Commit 784b49ba authored by Philip Trettner's avatar Philip Trettner
Browse files

more docs, moved properties to top-level include, renamed old property struct to attribute_view

parent 1b75c483
......@@ -7,3 +7,5 @@
* `<vector>`
* ...
* `Mesh::copy` and `Mesh::create` now work on `pm::unique_ptr`
* `properties.hh` was renamed to `view.hh`
* `algorithms/properties.hh` was moved to `properties.hh`
......@@ -20,7 +20,7 @@ TODO
Extracting Edges as Segments
--------------------------
----------------------------
::
......
Properties
==========
Properties are the commonly used free functions found in ``<polymesh/properties.hh>``.
TODO
......@@ -40,6 +40,8 @@ Handles and Indices
.. doxygenstruct:: polymesh::halfedge_handle
:members:
.. _ranges-ref:
Ranges and Collections
----------------------
......
......@@ -2,13 +2,53 @@ Smart Ranges
============
Many collections found in ``polymesh::`` derive from :cpp:struct:`polymesh::smart_range\<this_t, ElementT>`.
Iterating over these collections yields elements of type ``ElementT``.
The ``smart_range`` base class provides many convenience functions that encourage a functional programming style.
See :ref:`ranges-ref` for all supported operations.
:cpp:struct:`polymesh::vertex_attribute\<T>`
Example: ::
:cpp:struct:`polymesh::vertex_attribute`
pm::Mesh m;
auto pos = m.vertices().make_attribute<tg::pos3>();
// ... load or create mesh
:cpp:struct:`polymesh::smart_range`
// get edge lengths as edge attribute
auto edge_lengths = m.edges().map([&](pm::edge_handle e) { return distance(pos[e.vertexA()], pos[e.vertexB()]); });
:cpp:struct:`smart_range`
// sum up all edge lengths
auto total_edge_length = edge_lengths.sum();
TODO
// NOTE: this sums over deleted edges as well if the mesh is not compact
// alternatively only over valid edges:
// (this works because edge_lengths is also a function (pm::edge_handle) -> float)
auto total_valid_edge_length = m.edges().sum(edge_lengths);
// compute avg vertex position per face
// (is only real center of gravity for triangles)
auto face_cog = m.faces().map([&](pm::face_handle f) { return f.vertices().avg(pos); });
// find vertex with maximum y coordinate
auto max_y_v = m.vertices().max_by([&](pm::vertex_handle v) { return pos[v].y; });
// iterate over all vertices with valence > 5
for (auto v : m.vertices().where([&](auto v) { return valence(v) > 5; })
pos[v] = ...;
// iterate over faces and unpack triangle vertices
POLYMESH_ASSERT(is_triangle_mesh(m));
for (auto f : m.faces())
{
// get the three vertices
auto [v0, v1, v2] = f.vertices().to_array<3>();
// get the three vertex positions
auto [p0, p1, p2] = f.vertices().to_array<3>(pos);
}
:doc:`properties` are designed to interact well with this functional style.
Notable ``smart_range`` collections in polymesh include:
* all :ref:`primitive-collection` (e.g. ``m.vertices()``)
* all :doc:`attributes` (e.g. ``pm::face_attribute<T>``)
* all handle circulators (e.g. ``f.edges()`` for :struct:`polymesh::face_handle` ``f``)
......@@ -25,7 +25,6 @@
#include "algorithms/normalize.hh"
#include "algorithms/operations.hh"
#include "algorithms/optimization.hh"
#include "algorithms/properties.hh"
#include "algorithms/sampling.hh"
#include "algorithms/smoothing.hh"
#include "algorithms/stats.hh"
......
#pragma once
#include <polymesh/Mesh.hh>
#include <polymesh/algorithms/properties.hh>
#include <polymesh/properties.hh>
#include <polymesh/detail/delaunay.hh>
namespace polymesh
......
......@@ -3,7 +3,7 @@
#include <queue>
#include <polymesh/Mesh.hh>
#include <polymesh/algorithms/properties.hh>
#include <polymesh/properties.hh>
namespace polymesh
{
......
This diff is collapsed.
......@@ -8,7 +8,7 @@
#include <polymesh/Mesh.hh>
#include <polymesh/assert.hh>
#include "properties.hh"
#include <polymesh/properties.hh>
namespace polymesh
{
......
......@@ -7,7 +7,7 @@
#include <polymesh/fields.hh>
#include "components.hh"
#include "properties.hh"
#include <polymesh/properties.hh>
namespace polymesh
{
......
......@@ -3,12 +3,12 @@
#include <cstddef>
#include <vector>
#include "attribute_base.hh"
#include "cursors.hh"
#include "detail/unique_array.hh"
#include "properties.hh"
#include "ranges.hh"
#include "tmp.hh"
#include <polymesh/attribute_base.hh>
#include <polymesh/cursors.hh>
#include <polymesh/detail/unique_array.hh>
#include <polymesh/ranges.hh>
#include <polymesh/tmp.hh>
#include <polymesh/view.hh>
namespace polymesh
{
......@@ -106,7 +106,7 @@ public:
void compute(FuncT&& f);
template <class FuncT>
auto view(FuncT&& f) const -> readonly_property<primitive_attribute<tag, AttrT> const&, FuncT>;
auto view(FuncT&& f) const -> attribute_view<primitive_attribute<tag, AttrT> const&, FuncT>;
#ifndef _MSC_VER // cannot overload this apparently
template <class FuncT>
void view(FuncT&& f) && = delete;
......
......@@ -439,9 +439,9 @@ void primitive_attribute<tag, AttrT>::compute(FuncT&& f)
template <class tag, class AttrT>
template <class FuncT>
auto primitive_attribute<tag, AttrT>::view(FuncT&& f) const -> readonly_property<primitive_attribute<tag, AttrT> const&, FuncT>
auto primitive_attribute<tag, AttrT>::view(FuncT&& f) const -> attribute_view<primitive_attribute<tag, AttrT> const&, FuncT>
{
return readonly_property<primitive_attribute<tag, AttrT> const&, FuncT>(*this, f);
return attribute_view<primitive_attribute<tag, AttrT> const&, FuncT>(*this, std::forward<FuncT>(f));
}
} // namespace polymesh
#pragma once
// Includes all polymesh features
// Includes most commonly used polymesh features
#include <polymesh/Mesh.hh>
#include <polymesh/algorithms/optimization.hh>
#include <polymesh/algorithms/properties.hh>
#include <polymesh/properties.hh>
#include <polymesh/formats.hh>
#include <polymesh/objects.hh>
This diff is collapsed.
#pragma once
#include <polymesh/primitives.hh>
#include <polymesh/tmp.hh>
namespace polymesh
{
template <class CollectionT, class FuncT>
struct attribute_view
{
attribute_view(CollectionT collection, FuncT func) : mCollection(collection), mFunc(std::move(func)) {}
using index_t = typename std::decay<CollectionT>::type::index_t;
using handle_t = typename std::decay<CollectionT>::type::handle_t;
using input_t = decltype(std::declval<CollectionT>()[index_t()]);
using output_t = typename tmp::decayed_result_type_of<FuncT, input_t>;
output_t operator[](handle_t h) const { return mFunc(mCollection(h)); }
output_t operator[](index_t h) const { return mFunc(mCollection(h)); }
output_t operator()(handle_t h) const { return mFunc(mCollection(h)); }
output_t operator()(index_t h) const { return mFunc(mCollection(h)); }
int size() const { return mCollection.size(); }
template <class F>
auto map(F&& f) const
{
auto f2 = [ff = std::forward<F>(f)](output_t const& v) { return ff(v); };
return attribute_view<CollectionT, decltype(f2)>(mCollection, std::move(f2));
}
private:
CollectionT mCollection;
FuncT mFunc;
};
}
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