Commit bed5c608 authored by Philip Trettner's avatar Philip Trettner
Browse files

working on smart ranges

parent fec75cbb
......@@ -17,5 +17,6 @@ Best used with glm and glow.
* Switch primitives and valid_primitives, check if compact flag is inlined
* Test self-adjacent faces
* smart ranges: average, min, max, any, all, first, last ...
* smart ranges: filter, map
* mid-level topo API: edge-rotate-next/prev, edge-split, edge-collapse, halfedge-split, halfedge-collapse, vertex-collapse
* annotate property preservation for mid-level topo API
......@@ -15,8 +15,23 @@
// - face normal
// - vertex normal
// - curvature
// - topological properties
namespace polymesh
{
/// returns true if the vertex lies at a boundary
bool is_boundary(vertex_handle v);
/// returns true if the face lies at a boundary
bool is_boundary(face_handle v);
/// returns true if the edge lies at a boundary
bool is_boundary(edge_handle v);
/// returns true if the half-edge lies at a boundary (NOTE: a half-edge is boundary if it has no face)
bool is_boundary(halfedge_handle v);
/// returns true if the vertex has no neighbors
bool is_isolated(vertex_handle v);
/// returns true if the edge has no neighboring faces
bool is_isolated(edge_handle v);
/// returns the vertex valence (number of adjacent vertices)
int valence_of(vertex_handle v);
......@@ -38,10 +53,19 @@ Vec3 triangle_centroid(face_handle f, vertex_attribute<Vec3> const& position);
/// ======== IMPLEMENTATION ========
inline int valence_of(vertex_handle v)
{
return v.adjacent_vertices().size();
}
inline bool is_boundary(vertex_handle v) { return v.is_boundary(); }
inline bool is_boundary(face_handle v) { return v.is_boundary(); }
inline bool is_boundary(edge_handle v) { return v.is_boundary(); }
inline bool is_boundary(halfedge_handle v) { return v.is_boundary(); }
inline bool is_isolated(vertex_handle v) { return v.is_isolated(); }
inline bool is_isolated(edge_handle v) { return v.is_isolated(); }
inline int valence_of(vertex_handle v) { return v.adjacent_vertices().size(); }
template <class Vec3>
typename field_3d<Vec3>::Scalar triangle_area(face_handle f, vertex_attribute<Vec3> const& position)
......
......@@ -38,6 +38,11 @@ public:
AttrT& operator[](index_t v) { return mData[v.value]; }
AttrT const& operator[](index_t v) const { return mData[v.value]; }
AttrT& operator()(handle_t v) { return mData[v.idx.value]; }
AttrT const& operator()(handle_t v) const { return mData[v.idx.value]; }
AttrT& operator()(index_t v) { return mData[v.value]; }
AttrT const& operator()(index_t v) const { return mData[v.value]; }
AttrT* data() { return mData.data; }
AttrT const* data() const { return mData.data; }
int size() const;
......@@ -49,10 +54,10 @@ public:
/// returns a new attribute where the given function was applied to each entry
template <class FuncT>
auto map(FuncT f) const -> attribute<tmp::result_type_of<FuncT, AttrT>>;
auto map(FuncT&& f) const -> attribute<tmp::decayed_result_type_of<FuncT, AttrT>>;
/// applies to given function to each attribute entry
template <class FuncT>
void apply(FuncT f);
void apply(FuncT&& f);
// data
protected:
......@@ -167,56 +172,4 @@ primitive_attribute<tag, AttrT>& primitive_attribute<tag, AttrT>::operator=(prim
return *this;
}
/// ======== CURSOR IMPLEMENTATION ========
template <class tag>
template <class AttrT>
AttrT& primitive_index<tag>::operator[](attribute<AttrT>& attr) const
{
return attr[*this];
}
template <class tag>
template <class AttrT>
AttrT const& primitive_index<tag>::operator[](attribute<AttrT> const& attr) const
{
return attr[*this];
}
template <class tag>
template <class AttrT>
AttrT& primitive_index<tag>::operator[](attribute<AttrT>* attr) const
{
return (*attr)[*this];
}
template <class tag>
template <class AttrT>
AttrT const& primitive_index<tag>::operator[](attribute<AttrT> const* attr) const
{
return (*attr)[*this];
}
template <class tag>
template <class AttrT>
AttrT& primitive_handle<tag>::operator[](attribute<AttrT>& attr) const
{
return attr[idx];
}
template <class tag>
template <class AttrT>
AttrT const& primitive_handle<tag>::operator[](attribute<AttrT> const& attr) const
{
return attr[idx];
}
template <class tag>
template <class AttrT>
AttrT& primitive_handle<tag>::operator[](attribute<AttrT>* attr) const
{
return (*attr)[idx];
}
template <class tag>
template <class AttrT>
AttrT const& primitive_handle<tag>::operator[](attribute<AttrT> const* attr) const
{
return (*attr)[idx];
}
}
......@@ -3,6 +3,7 @@
#include <iostream>
#include "primitives.hh"
#include "tmp.hh"
namespace polymesh
{
......@@ -28,14 +29,11 @@ struct primitive_index
bool operator==(index_t const& rhs) const { return value == rhs.value; }
bool operator!=(index_t const& rhs) const { return value != rhs.value; }
template <class AttrT>
AttrT& operator[](attribute<AttrT>& prop) const;
template <class AttrT>
AttrT const& operator[](attribute<AttrT> const& prop) const;
template <class AttrT>
AttrT& operator[](attribute<AttrT>* prop) const;
template <class AttrT>
AttrT const& operator[](attribute<AttrT> const* prop) const;
/// indexes this primitive by a functor
/// also works for attributes
/// - e.g. v[position] or f[area]
template <class FuncT>
auto operator[](FuncT&& f) const -> tmp::result_type_of<FuncT, index_t>;
};
template <class tag>
......@@ -57,14 +55,11 @@ struct primitive_handle
bool operator==(handle_t const& rhs) const { return mesh == rhs.mesh && idx == rhs.idx; }
bool operator!=(handle_t const& rhs) const { return mesh != rhs.mesh || idx != rhs.idx; }
template <class AttrT>
AttrT& operator[](attribute<AttrT>& prop) const;
template <class AttrT>
AttrT const& operator[](attribute<AttrT> const& prop) const;
template <class AttrT>
AttrT& operator[](attribute<AttrT>* prop) const;
template <class AttrT>
AttrT const& operator[](attribute<AttrT> const* prop) const;
/// indexes this primitive by a functor
/// also works for attributes
/// - e.g. v[position] or f[area]
template <class FuncT>
auto operator[](FuncT&& f) const -> tmp::result_type_of<FuncT, handle_t>;
bool is_valid() const { return idx.is_valid(); } ///< valid idx (but could be deleted in some iterators)
bool is_invalid() const { return !idx.is_valid(); } ///< invalid idx
......
......@@ -160,9 +160,9 @@ void primitive_attribute<tag, AttrT>::clear()
template <class tag, class AttrT>
template <class FuncT>
auto primitive_attribute<tag, AttrT>::map(FuncT f) const -> attribute<tmp::result_type_of<FuncT, AttrT>>
auto primitive_attribute<tag, AttrT>::map(FuncT &&f) const -> attribute<tmp::decayed_result_type_of<FuncT, AttrT>>
{
auto attr = primitive<tag>::all_collection_of(*this->mMesh).template make_attribute<tmp::result_type_of<FuncT, AttrT>>();
auto attr = primitive<tag>::all_collection_of(*this->mMesh).template make_attribute<tmp::decayed_result_type_of<FuncT, AttrT>>();
auto s = size();
auto d_in = data();
auto d_out = attr.data();
......@@ -170,4 +170,14 @@ auto primitive_attribute<tag, AttrT>::map(FuncT f) const -> attribute<tmp::resul
d_out[i] = f(d_in[i]);
return attr; // copy elison
}
template <class tag, class AttrT>
template <class FuncT>
void primitive_attribute<tag, AttrT>::apply(FuncT &&f)
{
auto s = size();
auto d = data();
for (auto i = 0; i < s; ++i)
d[i] = f(d[i]);
}
}
......@@ -4,6 +4,20 @@
namespace polymesh
{
template <class tag>
template <class FuncT>
auto primitive_index<tag>::operator[](FuncT&& f) const -> tmp::result_type_of<FuncT, index_t>
{
return f(*static_cast<typename primitive<tag>::index const*>(this));
}
template <class tag>
template <class FuncT>
auto primitive_handle<tag>::operator[](FuncT&& f) const -> tmp::result_type_of<FuncT, handle_t>
{
return f(*static_cast<typename primitive<tag>::handle const*>(this));
}
inline bool vertex_handle::is_removed() const { return idx.is_valid() && !mesh->vertex(idx).is_valid(); }
inline bool face_handle::is_removed() const { return idx.is_valid() && !mesh->face(idx).is_valid(); }
inline bool edge_handle::is_removed() const { return idx.is_valid() && !mesh->halfedge(idx, 0).is_valid(); }
......@@ -13,7 +27,7 @@ inline bool vertex_handle::is_isolated() const { return mesh->vertex(idx).is_iso
inline bool vertex_handle::is_boundary() const
{
auto const &v = mesh->vertex(idx);
auto const& v = mesh->vertex(idx);
if (v.is_isolated())
return true;
return mesh->halfedge(v.outgoing_halfedge).is_free();
......
......@@ -4,6 +4,52 @@
namespace polymesh
{
template <class this_t, class tag>
typename smart_range<this_t, tag>::handle smart_range<this_t, tag>::first() const
{
for (auto h : static_cast<this_t const *>(this))
return h;
return handle::invalid();
}
template <class this_t, class tag>
typename smart_range<this_t, tag>::handle smart_range<this_t, tag>::last() const
{
handle result;
for (auto h : static_cast<this_t const *>(this))
result = h;
return result;
}
template <class this_t, class tag>
bool smart_range<this_t, tag>::any() const
{
for (auto h : static_cast<this_t const *>(this))
return true;
return false;
}
template <class this_t, class tag>
template <typename PredT>
bool smart_range<this_t, tag>::any(PredT&& p) const
{
for (auto h : static_cast<this_t const *>(this))
if (p(h))
return true;
return false;
}
template <class this_t, class tag>
int smart_range<this_t, tag>::count() const
{
auto cnt = 0;
for (auto h : static_cast<this_t const *>(this))
{
(void)h; // unused
++cnt;
}
return cnt;
}
template <class mesh_ptr, class tag, class iterator>
int smart_collection<mesh_ptr, tag, iterator>::size() const
{
......
......@@ -7,10 +7,57 @@
namespace polymesh
{
template<class this_t, class tag>
struct smart_range
{
template<class AttrT>
using attribute = typename primitive<tag>::template attribute<AttrT>;
using handle = typename primitive<tag>::handle;
/// returns the first element in this range
/// returns invalid on empty ranges
handle first() const;
/// returns the last element in this range
/// returns invalid on empty ranges
/// TODO: how to make this O(1)
handle last() const;
/// returns true if the range is non-empty
bool any() const;
/// returns true if any handle fulfils p(h)
template<typename PredT>
bool any(PredT&& p) const;
/// returns true if any attribute is true for this range
// bool any(attribute<bool> const& a) const;
/// returns true if all handles fulfil p(h)
template<typename PredT>
bool all(PredT&& p) const;
/// returns true if all attributes are true for this range
// bool all(attribute<bool> const& a) const;
/// returns the number of elements in this range
/// NOTE: this is an O(n) operation, prefer size() if available
/// TODO: maybe SFINAE to implement this via size() if available?
int count() const;
// TODO:
// - average
// - sum
// - min
// - max
// - minmax (return struct {min, max})
// - filter (or where?)
// - map
// - skip
// - only_valid
// - count
};
// ================= COLLECTION =================
template <class mesh_ptr, class tag, class iterator>
struct smart_collection
struct smart_collection : smart_range<smart_collection<mesh_ptr, tag, iterator>, tag>
{
template <typename AttrT>
using attribute = typename primitive<tag>::template attribute<AttrT>;
......@@ -184,20 +231,22 @@ struct valid_halfedge_const_collection : smart_collection<Mesh const*, halfedge_
// ================= RINGS =================
template <class this_t, class element_handle>
struct primitive_ring
template <class this_t, class tag>
struct primitive_ring : smart_range<this_t, tag>
{
using handle = typename primitive<tag>::handle;
face_handle face;
/// Number of elements
/// O(result) computation
int size() const;
/// Returns true if handle is contained in this ring
bool contains(element_handle v) const;
bool contains(handle v) const;
};
template <class element_handle, class circulator>
struct face_primitive_ring : primitive_ring<face_primitive_ring<element_handle, circulator>, element_handle>
template <class tag, class circulator>
struct face_primitive_ring : primitive_ring<face_primitive_ring<tag, circulator>, tag>
{
face_handle face;
face_primitive_ring(face_handle f) { face = f; }
......@@ -207,8 +256,8 @@ struct face_primitive_ring : primitive_ring<face_primitive_ring<element_handle,
circulator end() const { return {face.any_halfedge(), true}; }
};
template <class element_handle, class circulator>
struct vertex_primitive_ring : primitive_ring<vertex_primitive_ring<element_handle, circulator>, element_handle>
template <class tag, class circulator>
struct vertex_primitive_ring : primitive_ring<vertex_primitive_ring<tag, circulator>, tag>
{
vertex_handle vertex;
vertex_primitive_ring(vertex_handle v) { vertex = v; }
......@@ -219,57 +268,57 @@ struct vertex_primitive_ring : primitive_ring<vertex_primitive_ring<element_hand
};
/// all vertices belonging to a face
struct face_vertex_ring : face_primitive_ring<vertex_handle, face_vertex_circulator>
struct face_vertex_ring : face_primitive_ring<vertex_tag, face_vertex_circulator>
{
using face_primitive_ring<vertex_handle, face_vertex_circulator>::face_primitive_ring;
using face_primitive_ring<vertex_tag, face_vertex_circulator>::face_primitive_ring;
};
/// all halfedges belonging to a face
struct face_halfedge_ring : face_primitive_ring<halfedge_handle, face_halfedge_circulator>
struct face_halfedge_ring : face_primitive_ring<halfedge_tag, face_halfedge_circulator>
{
using face_primitive_ring<halfedge_handle, face_halfedge_circulator>::face_primitive_ring;
using face_primitive_ring<halfedge_tag, face_halfedge_circulator>::face_primitive_ring;
};
/// all edges belonging to a face
struct face_edge_ring : face_primitive_ring<edge_handle, face_edge_circulator>
struct face_edge_ring : face_primitive_ring<edge_tag, face_edge_circulator>
{
using face_primitive_ring<edge_handle, face_edge_circulator>::face_primitive_ring;
using face_primitive_ring<edge_tag, face_edge_circulator>::face_primitive_ring;
};
/// all adjacent faces belonging to a face
struct face_face_ring : face_primitive_ring<face_handle, face_face_circulator>
struct face_face_ring : face_primitive_ring<face_tag, face_face_circulator>
{
using face_primitive_ring<face_handle, face_face_circulator>::face_primitive_ring;
using face_primitive_ring<face_tag, face_face_circulator>::face_primitive_ring;
};
/// all outgoing half-edges from a vertex
struct vertex_halfedge_out_ring : vertex_primitive_ring<halfedge_handle, vertex_halfedge_out_circulator>
struct vertex_halfedge_out_ring : vertex_primitive_ring<halfedge_tag, vertex_halfedge_out_circulator>
{
using vertex_primitive_ring<halfedge_handle, vertex_halfedge_out_circulator>::vertex_primitive_ring;
using vertex_primitive_ring<halfedge_tag, vertex_halfedge_out_circulator>::vertex_primitive_ring;
};
/// all incoming half-edges from a vertex
struct vertex_halfedge_in_ring : vertex_primitive_ring<halfedge_handle, vertex_halfedge_in_circulator>
struct vertex_halfedge_in_ring : vertex_primitive_ring<halfedge_tag, vertex_halfedge_in_circulator>
{
using vertex_primitive_ring<halfedge_handle, vertex_halfedge_in_circulator>::vertex_primitive_ring;
using vertex_primitive_ring<halfedge_tag, vertex_halfedge_in_circulator>::vertex_primitive_ring;
};
/// all adjacent vertices of a vertex
struct vertex_vertex_ring : vertex_primitive_ring<vertex_handle, vertex_vertex_circulator>
struct vertex_vertex_ring : vertex_primitive_ring<vertex_tag, vertex_vertex_circulator>
{
using vertex_primitive_ring<vertex_handle, vertex_vertex_circulator>::vertex_primitive_ring;
using vertex_primitive_ring<vertex_tag, vertex_vertex_circulator>::vertex_primitive_ring;
};
/// all adjacent edges of a vertex
struct vertex_edge_ring : vertex_primitive_ring<edge_handle, vertex_edge_circulator>
struct vertex_edge_ring : vertex_primitive_ring<edge_tag, vertex_edge_circulator>
{
using vertex_primitive_ring<edge_handle, vertex_edge_circulator>::vertex_primitive_ring;
using vertex_primitive_ring<edge_tag, vertex_edge_circulator>::vertex_primitive_ring;
};
/// all adjacent faces of a vertex (INCLUDES invalid ones for boundaries)
struct vertex_face_ring : vertex_primitive_ring<face_handle, vertex_face_circulator>
struct vertex_face_ring : vertex_primitive_ring<face_tag, vertex_face_circulator>
{
using vertex_primitive_ring<face_handle, vertex_face_circulator>::vertex_primitive_ring;
using vertex_primitive_ring<face_tag, vertex_face_circulator>::vertex_primitive_ring;
};
......@@ -287,8 +336,8 @@ int primitive_ring<this_t, element_handle>::size() const
return cnt;
}
template <class this_t, class element_handle>
bool primitive_ring<this_t, element_handle>::contains(element_handle v) const
template <class this_t, class tag>
bool primitive_ring<this_t, tag>::contains(handle v) const
{
for (auto v2 : *static_cast<this_t const*>(this))
if (v == v2)
......
......@@ -8,11 +8,20 @@ namespace polymesh
namespace tmp
{
template <class FuncT, class ArgT>
struct result_of
struct decayed_result_of
{
using type = typename std::decay<decltype(std::declval<FuncT>()(std::declval<ArgT>()))>::type;
};
template <class FuncT, class ArgT>
using decayed_result_type_of = typename decayed_result_of<FuncT, ArgT>::type;
template <class FuncT, class ArgT>
struct result_of
{
using type = decltype(std::declval<FuncT>()(std::declval<ArgT>()));
};
template <class FuncT, class ArgT>
using result_type_of = typename result_of<FuncT, ArgT>::type;
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment