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

working on functional style ranges

parent acadd249
......@@ -16,7 +16,9 @@ Best used with glm and glow.
* Debug: insert is_removed assertions into handle access
* 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
* vector, set, map -> range
* range -> vector, set, map
* weighted avg
\ No newline at end of file
......@@ -4,10 +4,26 @@
namespace polymesh
{
namespace detail
{
template <class T>
T helper_min(T const &a, T const &b)
{
using namespace std;
return min(a, b);
}
template <class T>
T helper_max(T const &a, T const &b)
{
using namespace std;
return max(a, b);
}
}
template <class this_t, class ElementT>
ElementT smart_range<this_t, ElementT>::first() const
{
for (auto h : static_cast<this_t const *>(this))
for (auto h : *static_cast<this_t const *>(this))
return h;
return {};
}
......@@ -15,7 +31,7 @@ template <class this_t, class ElementT>
ElementT smart_range<this_t, ElementT>::last() const
{
ElementT result;
for (auto h : static_cast<this_t const *>(this))
for (auto h : *static_cast<this_t const *>(this))
result = h;
return result;
}
......@@ -23,7 +39,7 @@ ElementT smart_range<this_t, ElementT>::last() const
template <class this_t, class ElementT>
bool smart_range<this_t, ElementT>::any() const
{
for (auto h : static_cast<this_t const *>(this))
for (auto h : *static_cast<this_t const *>(this))
return true;
return false;
}
......@@ -32,7 +48,7 @@ template <class this_t, class ElementT>
template <class PredT>
bool smart_range<this_t, ElementT>::any(PredT &&p) const
{
for (auto h : static_cast<this_t const *>(this))
for (auto h : *static_cast<this_t const *>(this))
if (p(h))
return true;
return false;
......@@ -42,7 +58,7 @@ template <class this_t, class ElementT>
template <class PredT>
bool smart_range<this_t, ElementT>::all(PredT &&p) const
{
for (auto h : static_cast<this_t const *>(this))
for (auto h : *static_cast<this_t const *>(this))
if (!p(h))
return false;
return true;
......@@ -52,7 +68,7 @@ template <class this_t, class ElementT>
int smart_range<this_t, ElementT>::count() const
{
auto cnt = 0;
for (auto h : static_cast<this_t const *>(this))
for (auto h : *static_cast<this_t const *>(this))
{
(void)h; // unused
++cnt;
......@@ -60,6 +76,92 @@ int smart_range<this_t, ElementT>::count() const
return cnt;
}
template <class this_t, class ElementT>
template <class FuncT>
auto smart_range<this_t, ElementT>::min(FuncT &&f) const -> tmp::decayed_result_type_of<FuncT, ElementT>
{
auto it_begin = static_cast<this_t const *>(this)->begin();
auto it_end = static_cast<this_t const *>(this)->end();
assert(it_begin != it_end && "requires non-empty range");
auto v = f(*it_begin);
++it_begin;
while (it_begin != it_end)
v = detail::helper_min(v, f(*it_begin));
return v;
}
template <class this_t, class ElementT>
template <class FuncT>
auto smart_range<this_t, ElementT>::max(FuncT &&f) const -> tmp::decayed_result_type_of<FuncT, ElementT>
{
auto it_begin = static_cast<this_t const *>(this)->begin();
auto it_end = static_cast<this_t const *>(this)->end();
assert(it_begin != it_end && "requires non-empty range");
auto v = f(*it_begin);
++it_begin;
while (it_begin != it_end)
v = detail::helper_max(v, f(*it_begin));
return v;
}
template <class this_t, class ElementT>
template <class FuncT>
auto smart_range<this_t, ElementT>::sum(FuncT &&f) const -> tmp::decayed_result_type_of<FuncT, ElementT>
{
auto it_begin = static_cast<this_t const *>(this)->begin();
auto it_end = static_cast<this_t const *>(this)->end();
assert(it_begin != it_end && "requires non-empty range");
auto s = f(*it_begin);
++it_begin;
while (it_begin != it_end)
s = s + f(*it_begin);
return s;
}
template <class this_t, class ElementT>
template <class FuncT>
auto smart_range<this_t, ElementT>::avg(FuncT &&f) const -> tmp::decayed_result_type_of<FuncT, ElementT>
{
auto it_begin = static_cast<this_t const *>(this)->begin();
auto it_end = static_cast<this_t const *>(this)->end();
assert(it_begin != it_end && "requires non-empty range");
auto s = f(*it_begin);
auto cnt = 1;
++it_begin;
while (it_begin != it_end)
{
s = s + f(*it_begin);
++cnt;
}
return s / cnt;
}
template <class this_t, class ElementT>
template <class FuncT>
auto smart_range<this_t, ElementT>::aabb(FuncT &&f) const -> polymesh::aabb<typename tmp::decayed_result_of<FuncT, ElementT>::type>
{
auto it_begin = static_cast<this_t const *>(this)->begin();
auto it_end = static_cast<this_t const *>(this)->end();
assert(it_begin != it_end && "requires non-empty range");
auto v = f(*it_begin);
polymesh::aabb<typename tmp::decayed_result_of<FuncT, ElementT>::type> r = { v, v };
++it_begin;
while (it_begin != it_end)
{
auto vv = f(*it_begin);
r.min = detail::helper_min(r.min, vv);
r.max = detail::helper_max(r.max, vv);
}
return r;
}
template <class this_t, class ElementT>
template <class FuncT>
auto smart_range<this_t, ElementT>::minmax(FuncT &&f) const -> polymesh::aabb<typename tmp::decayed_result_of<FuncT, ElementT>::type>
{
return aabb(f);
}
template <class mesh_ptr, class tag, class iterator>
int smart_collection<mesh_ptr, tag, iterator>::size() const
{
......
......@@ -27,11 +27,11 @@ struct smart_range
/// returns true if the range is non-empty
bool any() const;
/// returns true if any handle fulfils p(h)
/// returns true if any value fulfils p(v)
/// also works for boolean attributes
template <class PredT>
bool any(PredT&& p) const;
/// returns true if all handles fulfil p(h)
/// returns true if all values fulfil p(v)
/// also works for boolean attributes
template <class PredT>
bool all(PredT&& p) const;
......@@ -41,15 +41,37 @@ struct smart_range
/// TODO: maybe SFINAE to implement this via size() if available?
int count() const;
// template<class T>
// T min() const;
// TODO:
// - average
// - sum
// - min
// - max
// - minmax (return struct {min, max})
/// calculates min(f(e)) over all elements
/// undefined behavior if range is empty
/// works for std::min and everything reachable by ADL (calls min(_, _))
template <class FuncT>
auto min(FuncT&& f) const -> tmp::decayed_result_type_of<FuncT, ElementT>;
/// calculates max(f(e)) over all elements
/// undefined behavior if range is empty
/// works for std::max and everything reachable by ADL (calls max(_, _))
template <class FuncT>
auto max(FuncT&& f) const -> tmp::decayed_result_type_of<FuncT, ElementT>;
/// calculates the sum of f(e) over all elements
/// undefined behavior if range is empty
/// requires operator+ for the elements
template <class FuncT>
auto sum(FuncT&& f) const -> tmp::decayed_result_type_of<FuncT, ElementT>;
/// calculates the avg of f(e) over all elements
/// undefined behavior if range is empty
/// requires operator+ for the elements as well as operator/(ElementT, int)
template <class FuncT>
auto avg(FuncT&& f) const -> tmp::decayed_result_type_of<FuncT, ElementT>;
/// calculates the aabb (min and max) of f(e) over all elements
/// undefined behavior if range is empty
/// works for std::min/max and everything reachable by ADL (calls min/max(_, _))
template <class FuncT>
auto aabb(FuncT&& f) const -> polymesh::aabb<tmp::decayed_result_type_of<FuncT, ElementT>>;
/// same as aabb(...)
template <class FuncT>
auto minmax(FuncT&& f) const -> polymesh::aabb<tmp::decayed_result_type_of<FuncT, ElementT>>;
// TODO: (requires new ranges)
// - filter (or where?)
// - map
// - skip
......
Markdown is supported
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