Commit 5c99f603 authored by Jan Möbius's avatar Jan Möbius

Merge branch 'SmartRanges' into 'master'

Smart ranges and reworked property manager

See merge request !233
parents 05349d51 8f672979
Pipeline #12785 passed with stages
in 181 minutes and 2 seconds
......@@ -32,7 +32,7 @@ echo "CPPCHECK Summary"
echo "=============================================================================="
echo -e "${NC}"
MAX_COUNT=26
MAX_COUNT=27
if [ $COUNT -gt $MAX_COUNT ]; then
echo -e ${WARNING}
......
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Core/Mesh/DefaultTriMesh.hh>
#include <OpenMesh/Core/Utils/PropertyManager.hh>
#include <iostream>
#include <vector>
using MyMesh = OpenMesh::TriMesh_ArrayKernelT<>;
using MyMesh = OpenMesh::TriMesh;
int main(int argc, char** argv)
{
......@@ -27,7 +27,7 @@ int main(int argc, char** argv)
{
// Add a vertex property storing the computed centers of gravity
auto cog = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, MyMesh::Point>(mesh);
auto cog = OpenMesh::VProp<MyMesh::Point>(mesh);
// Smooth the mesh several times
for (int i = 0; i < iterations; ++i) {
......
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/DefaultTriMesh.hh>
#include <OpenMesh/Core/Utils/PropertyManager.hh>
#include <iostream>
#include <vector>
using MyMesh = OpenMesh::TriMesh;
int main(int argc, char** argv)
{
// Read command line options
MyMesh mesh;
if (argc != 4) {
std::cerr << "Usage: " << argv[0] << " #iterations infile outfile" << std::endl;
return 1;
}
const int iterations = argv[1];
const std::string infile = argv[2];
const std::string outfile = argv[3];
// Read mesh file
if (!OpenMesh::IO::read_mesh(mesh, infile)) {
std::cerr << "Error: Cannot read mesh from " << infile << std::endl;
return 1;
}
{
// Add a vertex property storing the laplace vector
auto laplace = OpenMesh::VProp<MyMesh::Point>(mesh);
// Add a vertex property storing the laplace of the laplace
auto bi_laplace = OpenMesh::VProp<MyMesh::Point>(mesh);
// Get a propertymanager of the points property of the mesh to use as functor
auto points = OpenMesh::getPointsProperty(mesh);
// Smooth the mesh several times
for (int i = 0; i < iterations; ++i) {
// Iterate over all vertices to compute laplace vector
for (const auto& vh : mesh.vertices())
laplace(vh) = vh.vertices().avg(points) - points(vh);
// Iterate over all vertices to compte update vectors as the negative of the laplace of the laplace damped by 0.5
for (const auto& vh : mesh.vertices())
bi_laplace(vh) = (vh.vertices().avg(laplace) - laplace(vh));
// update points
for (const auto& vh : mesh.vertices())
points(vh) += -0.5 * bi_laplace(vh);
}
} // The laplace and update properties are removed is removed from the mesh at the end of this scope.
// Write mesh file
if (!OpenMesh::IO::read_mesh(mesh, outfile)) {
std::cerr << "Error: Cannot write mesh to " << outfile << std::endl;
return 1;
}
}
......@@ -8,11 +8,20 @@
<tr valign=top><td><b>8.1</b> (?/?/?)</td><td>
<b>Breaking Changes</b>
<ul>
<li>PropertyManager: PropertyManager only gives const access to the underlying mesh.</li>
</ul>
<b>Core</b>
<ul>
<li>Property System: Get rid of the OM_FORCE_STATIC_CAST defines. We use the type ids to check if the cast is valid or not. This will add more type safety. </li>
<li>Default Traits: Added DefaultTraitsDouble as a version of the default traits that uses double precision for positions and normals as well as float for colors. </li>
<li>Default Mesh Types: Added typdefs for a Triangle Mesh and a PolyMesh which use DefaultTraitsDouble and can be used as default mesh type be the user. </li>
<li>Template Programming Convenience: Added n_elements which returns the number of elements corresponding to the handle type given as template argument. Also added elements and all_elements methods returning ranges of the elements corresponding to the handle type given as template argument.</li>
<li>Smart Handles: Most userfacing functions returning handles should now return smart handles instead. Smart handles know their corresponding mesh and give convenient access to mesh navigation methods.
<li>Smart Ranges: OpenMesh ranges now provide a few methods that simplify a few calculations. See documentation for more details.
</ul>
......@@ -27,6 +36,7 @@
<ul>
<li>Change PropertyManager::operator* to access the property value for mesh properties</li>
<li>PropertyManager: add hasProperty function</li>
<li>PropertyManager rework: The behavior of the PropertyManager has been changed, hopefully making it more usable. See tutoial.
</ul>
<b>IO</b>
......
......@@ -82,6 +82,7 @@ repeatedly replacing each vertex' position by the center of gravity
\li \ref tutorial_02
\li \ref tutorial_03
\li \ref tutorial_04
\li \ref tutorial_11
\li \ref tutorial_05
\li \ref tutorial_06
\li \ref tutorial_07
......
......@@ -11,34 +11,33 @@ let %OpenMesh manage the data.
It would be even more helpful if we could attach such properties
dynamically to the mesh.
Custom properties can be conveniently created and attached to meshes with the following functions:
- makeTemporaryProperty() creates a property that is temporary to the current scope.
- getOrMakeProperty() is used for creating and accessing permanent named properties on a mesh.
- getProperty() is used for accessing an existing permanent named property on a mesh.
Custom properties can be conveniently created and attached to meshes by creating an object of type OpenMesh::PropertyManager. A PropertyManager manages the lifetime of the property and provides read / write access to its values.
All three functions take two template arguments:
- First, the type of the mesh element that the property is attached to (i.e. OpenMesh::VertexHandle, OpenMesh::HalfedgeHandle, OpenMesh::EdgeHandle, or OpenMesh::FaceHandle). <em>Mesh properties</em> (i.e. singleton properties that are attached to an entire mesh instead of individual elements) are accessed by passing \c void instead of a handle type.
- Second, the type of the property value that is attached to each element (e.g., \p int, \p double, etc.).
You can use the typedefs VProp, HProp, EProp, FProp, and MProp in order to create a PropertyManager attached to vertices, halfedge, edges, faces and the mesh respectively. Each of these takes as template argument the type of the property value that is attached to each element (e.g., \p int, \p double, etc.).
We differentiate between two kinds of properties. <em>Named</em> and <em>temporary</em> properties. Temporary properties are created by just providing the constructor with a mesh on which the property should be created. These properties will be removed as soon as the PropertyManager goes out of scope. If in addition to the mesh a property name is provided, a named property will be created which will stay alive even after the PropertyManager goes out of scope. If a PropertyManager is given a name of an already existing property, it will provide read and write access to the same property.
Finally, an optional first parameter can be given containing a value that will be used to initialize the property for all elements if the property is freshly created (i.e. always for temporary properties, and only the first time a specific name is used).
All three functions return a handle object (of type OpenMesh::PropertyManager) that manages the lifetime of the property and provides read / write access to its values.
Here are a few examples of how to create and access mesh properties:
\code
// Add a temporary mesh property that stores a double value for every vertex
auto temperature = OpenMesh::getOrMakeProperty<OpenMesh::VertexHandle, double>(mesh, "temperature");
auto temperature = OpenMesh::VProp<double>(mesh);
OpenMesh::VertexHandle vh = ...;
temperature[vh] = 1.0;
// The temperature property will be removed from the mesh when the handle reaches the end of the scope.
// Obtain an existing mesh property that stores a 2D vector for every halfedge
// (Beware: the next line might throw if the expected property doesn't exist.)
auto uv = OpenMesh::getProperty<OpenMesh::HalfedgeHandle, OpenMesh::Vec2d>(mesh, "uv");
// Obtain an existing property that stores a 2D vector for every halfedge
// (or create that property if it does not exist already) and initilize it with the Vector(1,1))
auto uv = OpenMesh::HProp<OpenMesh::Vec2d>(mesh, "uv", OpenMesh::Vec2d(1,1));
OpenMesh::VertexHandle heh = ...;
std::cout << temperature[heh][0] << " " << temperature[heh][1] << std::endl;
// Add a permanent mesh property containing a description string
auto desc = OpenMesh::getOrMakeProperty<void, std::string>(mesh, "desc");
// Obtain an existing mesh property (or create that property if it does not exist already)
// containing a description string
auto desc = OpenMesh::MProp<std::string>(mesh, "desc");
*desc = "This is a very nice mesh.";
\endcode
......@@ -50,7 +49,7 @@ In this example, we will store the \c cog value (see previous example) in a vert
To do so, we first add a (temporary) property of the desired element type (OpenMesh::VertexHandle) and value type (\c %MyMesh::Point) to the mesh:
\dontinclude 03-properties/smooth.cc
\skipline makeTemporaryProperty
\skipline VProp
Enough memory is allocated to hold as many values of \c %MyMesh::Point as there are vertices.
All insert and delete operations on the mesh are synchronized with the attached properties.
......@@ -75,30 +74,19 @@ Below is the complete source code:
## Property Lifetime
In the above example, we chose to use makeTemporaryProperty(). This causes the created property to automatically be removed from the mesh as soon as we leave the scope of the associated handle variable \c cog.
In the above example, we chose to use VProp without a name. This causes the created property to automatically be removed from the mesh as soon as we leave the scope of the associated handle variable \c cog.
If, instead, a property is desired to survive its local scope, it should be created with using getOrMakeProperty(). In that case, the property must be given a name that can later be used to retrieve the property. For example:
If, instead, a property is desired to survive its local scope, it should be created with a name. For example:
\code
auto face_area = OpenMesh::makeTemporaryProperty<OpenMesh::FaceHandle, double>(mesh, "face_area");
\endcode
At a later time, we can use the getProperty() function to obtain a handle to a property that was previously created by refering to its name:
\code
try {
auto face_area = OpenMesh::getProperty<OpenMesh::FaceHandle, double>(mesh, "face_area");
// Use the face_area property.
}
catch (const std::runtime_error& e) {
// Property not found. Handle the error here.
}
auto face_area = OpenMesh::FProp<double>(mesh, "face_area");
\endcode
Using hasProperty(), we can test whether a mesh has a certain property:
At a later time, we can access the same property by using the same name. If we want to make sure, that we access a property that has already been created earler, we can use hasProperty() to test whether a mesh has the desired property:
\code
if (OpenMesh::hasProperty<OpenMesh::EdgeHandle, bool>(mesh, "is_valley")) {
if (OpenMesh::hasProperty<OpenMesh::FaceHandle, double>(mesh, "face_area")) {
// Property exists. Do something with it.
auto valley = OpenMesh::getProperty<OpenMesh::EdgeHandle, bool>(mesh, "is_valley");
auto valley = OpenMesh::FProp<bool>(mesh, "face_area");
}
else {
// Property does not exist. Do something else.
......@@ -109,9 +97,9 @@ Using hasProperty(), we can test whether a mesh has a certain property:
## Low-Level Property API
The functions makeTemporaryProperty(), getOrMakeProperty(), and getProperty() are the convenient high-level interface for creating and accessing mesh properties.
The property managers VProp, HProp, EProp, FProp and MProp are the convenient high-level interface for creating and accessing mesh properties.
Beneath these convenience functions, there is also a low-level property interface where handle and property lifetime must be managed manually. This interface is accessed through a mesh's add_property(), remove_property(), and property() functions and several property handle classes (OpenMesh::VPropHandleT, OpenMesh::HPropHandleT, OpenMesh::EPropHandleT, OpenMesh::FPropHandleT, OpenMesh::MPropHandleT).
Beneath these convenience functions, there is also a low-level property interface where handle and property lifetime must be managed manually. This interface is accessed through a mesh's add_property(), get_property(), remove_property(), and property() functions and several property handle classes (OpenMesh::VPropHandleT, OpenMesh::HPropHandleT, OpenMesh::EPropHandleT, OpenMesh::FPropHandleT, OpenMesh::MPropHandleT).
---
......
/** \page tutorial_09 Using custom properties
/** \page tutorial_09 Using custom properties (old style)
This small code example shows how to attach andaccess additional properties on a mesh.
This small code example shows how to attach and access additional properties on a mesh.
<em>Note that this is an old style of using properties. Nowadays you should use the OpenMesh::PropertyManager instead.</em>
When you want to add an additional properties you have to attach it to a primitive of the
mesh. You can attach to verticies, halfedges, edges, faces or to the mesh itself. Use the
......
/** \page tutorial_11 Using Smart Handles
This examples shows:
- How to use Smart Handles and ranges to navigate on the mesh
- How to use Smart Ranges
So far we have used methods such as halfedge_handle(), next_halfedge_handle(), prev_halfedge_handle(), oppopsite_halfedge_handle(), face_handle(), to_vertex_handle(), and some others, to navigate on that mesh. These functions are defined on a mesh and require as input a handle to an element of the mesh, such as VertexHandle or HalfedgeHandle. In the following example we iterate over all vertices of a triangle mesh and for each vertex we create a list of the vertices that lie opposite of the edges in the ring around the vertex:
\code
// iterate over vertices of the mesh
for (auto vh : mesh.vertices())
{
std::vector<OpenMesh::VertexHandle> opposite_vertices;
// iterate over all outgoing halfedges
for (auto heh : mesh.voh_range(vh))
{
// navigate to the opposite vertex and store it in the vector
opposite_vertices.push_back(mesh.to_vertex_handle(mesh.next_halfedge_handle(mesh.opposite_halfedge_handle(mesh.next_halfedge_handle(heh)))));
}
}
\endcode
For a more concise way of navigating OpenMesh provides smart handles, OpenMesh::SmartVertexHandle, OpenMesh::SmartHalfedgeHandle, OpenMesh::SmartEdgeHandle, and OpenMesh::SmartFaceHandle. Smart handles are smart, because they know to which mesh they belong. This allows them to provide functions for navigating the mesh allowing us to write the above code much simpler:
\code
// iterate over vertices of the mesh
for (auto vh : mesh.vertices())
{
// iterate over all outgoing halfedges
std::vector<OpenMesh::VertexHandle> opposite_vertices;
for (auto heh : vh.outgoing_halfedges())
{
// navigate to the opposite vertex and store it in the vector
opposite_vertices.push_back(heh.next().opp().next().to());
}
}
\endcode
The ranges of OpenMesh that are returned by functions like voh_range() or outgoing_halfedges() all provide a few methods than can simplify some calculations (see OpenMesh::SmartRangeT). One example is the to_vector() method which convertes the range of elements into a vector containing the elements. All of these methods take a functor as argument (sometimes optional) which is called for each element of the range. With this, the above code can also be implemented like this:
\code
// iterate over vertices of the mesh
for (auto vh : mesh.vertices())
{
// create lambda that returns opposite vertex
auto opposite_vertex = [](OpenMesh::SmartHalfedgeHandle heh) { return heh.next().opp().next().to(); };
// create vector containing all opposite vertices
auto opposite_vertices = vh.outgoing_halfedges().to_vector(opposite_vertex);
}
\endcode
---
## Code Example
In this example, we will use bi-laplacian smoothing on a mesh. We store the \c laplace vector which is the vector pointing from a vertex to the center of gravity of its neighboring vertices in a vertex property.
\dontinclude 11-smart_handles/smooth.cc
\skipline laplace
\skipline laplace
To compute the center of gravity, i.e. the average position, we use the avg() method of the range of 1-ring vertices and pass in a PropertyManager acting as functor returning the corresponding point of a vertex.
\skipline points
\until avg(points)
Similarily we compute the update vector as the laplace of the freshly computed laplace vectors by simply exchanging the points property manager with the laplace property manager.
\skipline Iterate
\until bi_laplace
Finally, we apply the update after damping it by a factor of -0.5.
\skipline udpate points
\until bi_laplace
Below is the complete source code:
\include 11-smart_handles/smooth.cc
---
*/
......@@ -33,6 +33,7 @@ repeatedly replacing each vertex' position by the center of gravity
<li> \subpage tutorial_02
<li> \subpage tutorial_03
<li> \subpage tutorial_04
<li> \subpage tutorial_11
<li> \subpage tutorial_05
<li> \subpage tutorial_06
<li> \subpage tutorial_07
......
......@@ -169,6 +169,11 @@ class VectorT {
std::copy_n(it, DIM, values_.begin());
}
/// construct from an array
explicit VectorT(container&& _array) {
values_ = _array;
}
/// copy & cast constructor (explicit)
template<typename otherScalarType,
typename = typename std::enable_if<
......@@ -759,6 +764,21 @@ VectorT<Scalar, DIM>& minimize(VectorT<Scalar, DIM>& _v1, VectorT<Scalar, DIM>&
return _v1.minimize(_v2);
}
/// \relates OpenMesh::VectorT
/// non-member max
template<typename Scalar, int DIM>
VectorT<Scalar, DIM> max(const VectorT<Scalar, DIM>& _v1, const VectorT<Scalar, DIM>& _v2) {
return _v1.max(_v2);
}
/// \relates OpenMesh::VectorT
/// non-member min
template<typename Scalar, int DIM>
VectorT<Scalar, DIM> min(const VectorT<Scalar, DIM>& _v1, const VectorT<Scalar, DIM>& _v2) {
return _v1.min(_v2);
}
//== TYPEDEFS =================================================================
/** 1-byte signed vector */
......
......@@ -317,6 +317,22 @@ VectorT<Scalar, DIM>& minimize(VectorT<Scalar, DIM>& _v1, VectorT<Scalar, DIM>&
}
/// \relates OpenMesh::VectorT
/// non-member max
template<typename Scalar, int DIM>
VectorT<Scalar, DIM> max(VectorT<Scalar, DIM>& _v1, VectorT<Scalar, DIM>& _v2) {
return VectorT<Scalar, DIM>(_v1).maximize(_v2);
}
/// \relates OpenMesh::VectorT
/// non-member min
template<typename Scalar, int DIM>
VectorT<Scalar, DIM> min(VectorT<Scalar, DIM>& _v1, VectorT<Scalar, DIM>& _v2) {
return VectorT<Scalar, DIM>(_v1).minimize(_v2);
}
//== TYPEDEFS =================================================================
/** 1-byte signed vector */
......
......@@ -105,10 +105,26 @@ public:
FAttribs = MeshItems::FAttribs
};
typedef VPropHandleT<VertexData> DataVPropHandle;
typedef HPropHandleT<HalfedgeData> DataHPropHandle;
typedef EPropHandleT<EdgeData> DataEPropHandle;
typedef FPropHandleT<FaceData> DataFPropHandle;
typedef VPropHandleT<VertexData> DataVPropHandle;
typedef HPropHandleT<HalfedgeData> DataHPropHandle;
typedef EPropHandleT<EdgeData> DataEPropHandle;
typedef FPropHandleT<FaceData> DataFPropHandle;
typedef VPropHandleT<Point> PointsPropertyHandle;
typedef VPropHandleT<Normal> VertexNormalsPropertyHandle;
typedef VPropHandleT<Color> VertexColorsPropertyHandle;
typedef VPropHandleT<TexCoord1D> VertexTexCoords1DPropertyHandle;
typedef VPropHandleT<TexCoord2D> VertexTexCoords2DPropertyHandle;
typedef VPropHandleT<TexCoord3D> VertexTexCoords3DPropertyHandle;
typedef HPropHandleT<TexCoord1D> HalfedgeTexCoords1DPropertyHandle;
typedef HPropHandleT<TexCoord2D> HalfedgeTexCoords2DPropertyHandle;
typedef HPropHandleT<TexCoord3D> HalfedgeTexCoords3DPropertyHandle;
typedef EPropHandleT<Color> EdgeColorsPropertyHandle;
typedef HPropHandleT<Normal> HalfedgeNormalsPropertyHandle;
typedef HPropHandleT<Color> HalfedgeColorsPropertyHandle;
typedef FPropHandleT<Normal> FaceNormalsPropertyHandle;
typedef FPropHandleT<Color> FaceColorsPropertyHandle;
typedef FPropHandleT<TextureIndex> FaceTextureIndexPropertyHandle;
public:
......@@ -240,6 +256,9 @@ public:
void set_point(VertexHandle _vh, const Point& _p)
{ this->property(points_, _vh) = _p; }
const PointsPropertyHandle& points_property_handle() const
{ return points_; }
//------------------------------------------------------------ vertex normals
......@@ -592,24 +611,6 @@ public:
bool has_face_colors() const { return face_colors_.is_valid(); }
bool has_face_texture_index() const { return face_texture_index_.is_valid(); }
public:
typedef VPropHandleT<Point> PointsPropertyHandle;
typedef VPropHandleT<Normal> VertexNormalsPropertyHandle;
typedef VPropHandleT<Color> VertexColorsPropertyHandle;
typedef VPropHandleT<TexCoord1D> VertexTexCoords1DPropertyHandle;
typedef VPropHandleT<TexCoord2D> VertexTexCoords2DPropertyHandle;
typedef VPropHandleT<TexCoord3D> VertexTexCoords3DPropertyHandle;
typedef HPropHandleT<TexCoord1D> HalfedgeTexCoords1DPropertyHandle;
typedef HPropHandleT<TexCoord2D> HalfedgeTexCoords2DPropertyHandle;
typedef HPropHandleT<TexCoord3D> HalfedgeTexCoords3DPropertyHandle;
typedef EPropHandleT<Color> EdgeColorsPropertyHandle;
typedef HPropHandleT<Normal> HalfedgeNormalsPropertyHandle;
typedef HPropHandleT<Color> HalfedgeColorsPropertyHandle;
typedef FPropHandleT<Normal> FaceNormalsPropertyHandle;
typedef FPropHandleT<Color> FaceColorsPropertyHandle;
typedef FPropHandleT<TextureIndex> FaceTextureIndexPropertyHandle;
public:
//standard vertex properties
PointsPropertyHandle points_pph() const
......
......@@ -516,7 +516,7 @@ public:
// Copy all properties, if build in is true
// Otherwise, copy only properties without build in specifier
if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "v:" ) )
(*p_it)->copy(_vh_from.idx(), _vh_to.idx());
(*p_it)->copy(static_cast<size_t>(_vh_from.idx()), static_cast<size_t>(_vh_to.idx()));
}
}
......@@ -690,6 +690,9 @@ public: //----------------------------------------------------- element numbers
virtual size_t n_edges() const { return 0; }
virtual size_t n_faces() const { return 0; }
template <typename HandleT>
size_t n_elements() const;
protected: //------------------------------------------- synchronize properties
......@@ -814,6 +817,16 @@ private:
};
template <>
inline size_t BaseKernel::n_elements<VertexHandle>() const { return n_vertices(); }
template <>
inline size_t BaseKernel::n_elements<HalfedgeHandle>() const { return n_halfedges(); }
template <>
inline size_t BaseKernel::n_elements<EdgeHandle>() const { return n_edges(); }
template <>
inline size_t BaseKernel::n_elements<FaceHandle>() const { return n_faces(); }
//=============================================================================
} // namespace OpenMesh
//=============================================================================
......
......@@ -40,9 +40,8 @@
* ========================================================================= */
#pragma once
#ifndef OPENMESH_CIRCULATORS_HH
#define OPENMESH_CIRCULATORS_HH
//=============================================================================
//
// Vertex and Face circulators for PolyMesh/TriMesh
......@@ -54,6 +53,7 @@
//== INCLUDES =================================================================
#include <OpenMesh/Core/System/config.h>
#include <OpenMesh/Core/Mesh/SmartHandles.hh>
#include <cassert>
#include <cstddef>
#include <iterator>
......@@ -248,19 +248,25 @@ class GenericCirculatorBaseT {
int lap_counter_;
};
template<class Mesh, class CenterEntityHandle, class ValueHandle,
ValueHandle (GenericCirculatorBaseT<Mesh>::*Handle2Value)() const, bool CW = true >
class GenericCirculatorT : protected GenericCirculatorBaseT<Mesh> {
//template<class Mesh, class CenterEntityHandle, class ValueHandle,
// ValueHandle (GenericCirculatorBaseT<Mesh>::*Handle2Value)() const, bool CW = true >
template <typename GenericCirculatorT_TraitsT, bool CW = true>
class GenericCirculatorT : protected GenericCirculatorBaseT<typename GenericCirculatorT_TraitsT::Mesh> {
public:
using Mesh = typename GenericCirculatorT_TraitsT::Mesh;
using value_type = typename GenericCirculatorT_TraitsT::ValueHandle;
using CenterEntityHandle = typename GenericCirculatorT_TraitsT::CenterEntityHandle;
using smart_value_type = decltype(make_smart(std::declval<value_type>(), std::declval<Mesh>()));
typedef std::ptrdiff_t difference_type;
typedef ValueHandle value_type;
typedef const value_type& reference;
typedef const value_type* pointer;
typedef const smart_value_type* pointer;
typedef std::bidirectional_iterator_tag iterator_category;
typedef typename GenericCirculatorBaseT<Mesh>::mesh_ptr mesh_ptr;
typedef typename GenericCirculatorBaseT<Mesh>::mesh_ref mesh_ref;
typedef GenericCirculator_ValueHandleFnsT<Mesh, CenterEntityHandle, ValueHandle, CW> GenericCirculator_ValueHandleFns;
typedef GenericCirculator_ValueHandleFnsT<Mesh, CenterEntityHandle, value_type, CW> GenericCirculator_ValueHandleFns;
public:
GenericCirculatorT() {}
......@@ -276,8 +282,8 @@ class GenericCirculatorT : protected GenericCirculatorBaseT<Mesh> {
}
GenericCirculatorT(const GenericCirculatorT &rhs) : GenericCirculatorBaseT<Mesh>(rhs) {}
friend class GenericCirculatorT<Mesh,CenterEntityHandle,ValueHandle,Handle2Value,!CW>;
explicit GenericCirculatorT( const GenericCirculatorT<Mesh,CenterEntityHandle,ValueHandle,Handle2Value,!CW>& rhs )
friend class GenericCirculatorT<GenericCirculatorT_TraitsT,!CW>;
explicit GenericCirculatorT( const GenericCirculatorT<GenericCirculatorT_TraitsT,!CW>& rhs )
:GenericCirculatorBaseT<Mesh>(rhs){}
GenericCirculatorT& operator++() {
......@@ -308,16 +314,16 @@ class GenericCirculatorT : protected GenericCirculatorBaseT<Mesh> {
}
/// Standard dereferencing operator.
value_type operator*() const {
smart_value_type operator*() const {
// We can't use this due to a GCC6 compiler bug
const GenericCirculatorBaseT<Mesh>* self = this;
#ifndef NDEBUG
assert(this->heh_.is_valid());
value_type res = (self->*Handle2Value)();
value_type res = GenericCirculatorT_TraitsT::toHandle(this->mesh_, this->heh_);
assert(res.is_valid());
return res;
return make_smart(res, this->mesh_);
#else
return (self->*Handle2Value)();
return make_smart(GenericCirculatorT_TraitsT::toHandle(this->mesh_, this->heh_), this->mesh_);
#endif
}
......@@ -357,7 +363,7 @@ class GenericCirculatorT : protected GenericCirculatorBaseT<Mesh> {
}
private:
mutable value_type pointer_deref_value;
mutable smart_value_type pointer_deref_value;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
......@@ -420,19 +426,22 @@ class GenericCirculator_ValueHandleFnsT_DEPRECATED<Mesh, CenterEntityHandle, typ
}
};
template<class Mesh, class CenterEntityHandle, class ValueHandle,
ValueHandle (GenericCirculatorBaseT<Mesh>::*Handle2Value)() const>
class GenericCirculatorT_DEPRECATED : protected GenericCirculatorBaseT<Mesh> {
template <typename GenericCirculatorT_DEPRECATED_TraitsT>
class GenericCirculatorT_DEPRECATED : protected GenericCirculatorBaseT<typename GenericCirculatorT_DEPRECATED_TraitsT::Mesh> {
public:
using Mesh = typename GenericCirculatorT_DEPRECATED_TraitsT::Mesh;
using CenterEntityHandle = typename GenericCirculatorT_DEPRECATED_TraitsT::CenterEntityHandle;