Merge branch 'rename_property_manager_factories' into 'master'
rename PropertyManager factory functions See merge request OpenMesh/OpenMesh!193
This commit is contained in:
@@ -1,74 +1,57 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
// --------------------
|
|
||||||
#include <OpenMesh/Core/IO/MeshIO.hh>
|
#include <OpenMesh/Core/IO/MeshIO.hh>
|
||||||
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
|
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
|
||||||
|
#include <OpenMesh/Core/Utils/PropertyManager.hh>
|
||||||
|
|
||||||
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using MyMesh = OpenMesh::TriMesh_ArrayKernelT<>;
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
MyMesh mesh;
|
// Read command line options
|
||||||
|
MyMesh mesh;
|
||||||
|
if (argc != 4) {
|
||||||
// check command line options
|
std::cerr << "Usage: " << argv[0] << " #iterations infile outfile" << std::endl;
|
||||||
if (argc != 4)
|
return 1;
|
||||||
{
|
|
||||||
std::cerr << "Usage: " << argv[0] << " #iterations infile outfile\n";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// read mesh from stdin
|
|
||||||
if ( ! OpenMesh::IO::read_mesh(mesh, argv[2]) )
|
|
||||||
{
|
|
||||||
std::cerr << "Error: Cannot read mesh from " << argv[2] << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// this vertex property stores the computed centers of gravity
|
|
||||||
OpenMesh::VPropHandleT<MyMesh::Point> cogs;
|
|
||||||
mesh.add_property(cogs);
|
|
||||||
|
|
||||||
// smoothing mesh argv[1] times
|
|
||||||
MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
|
|
||||||
MyMesh::VertexVertexIter vv_it;
|
|
||||||
MyMesh::Point cog;
|
|
||||||
MyMesh::Scalar valence;
|
|
||||||
unsigned int i, N(atoi(argv[1]));
|
|
||||||
|
|
||||||
|
|
||||||
for (i=0; i < N; ++i)
|
|
||||||
{
|
|
||||||
for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
|
|
||||||
{
|
|
||||||
mesh.property(cogs,*v_it).vectorize(0.0f);
|
|
||||||
valence = 0.0;
|
|
||||||
|
|
||||||
for (vv_it=mesh.vv_iter( *v_it ); vv_it; ++vv_it)
|
|
||||||
{
|
|
||||||
mesh.property(cogs,*v_it) += mesh.point( *vv_it );
|
|
||||||
++valence;
|
|
||||||
}
|
|
||||||
mesh.property(cogs,*v_it) /= valence;
|
|
||||||
}
|
}
|
||||||
|
const int iterations = argv[1];
|
||||||
|
const std::string infile = argv[2];
|
||||||
|
const std::string outfile = argv[3];
|
||||||
|
|
||||||
for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it)
|
// Read mesh file
|
||||||
if ( !mesh.is_boundary( *v_it ) )
|
if (!OpenMesh::IO::read_mesh(mesh, infile)) {
|
||||||
mesh.set_point( *v_it, mesh.property(cogs,*v_it) );
|
std::cerr << "Error: Cannot read mesh from " << infile << std::endl;
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Add a vertex property storing the computed centers of gravity
|
||||||
|
auto cog = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, MyMesh::Point>(mesh);
|
||||||
|
|
||||||
// write mesh to stdout
|
// Smooth the mesh several times
|
||||||
if ( ! OpenMesh::IO::write_mesh(mesh, argv[3]) )
|
for (int i = 0; i < iterations; ++i) {
|
||||||
{
|
// Iterate over all vertices to compute centers of gravity
|
||||||
std::cerr << "Error: cannot write mesh to " << argv[3] << std::endl;
|
for (const auto& vh : mesh.vertices()) {
|
||||||
return 1;
|
cog[vh] = {0,0,0};
|
||||||
}
|
int valence = 0;
|
||||||
|
// Iterate over all 1-ring vertices around vh
|
||||||
return 0;
|
for (const auto& vvh : mesh.vv_range(vh)) {
|
||||||
|
cog[vh] += mesh.point(vvh);
|
||||||
|
++valence;
|
||||||
|
}
|
||||||
|
cog[vh] /= valence;
|
||||||
|
}
|
||||||
|
// Move all vertices to the previously computed positions
|
||||||
|
for (const auto& vh : mesh.vertices()) {
|
||||||
|
mesh.point(vh) = cog[vh];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // The cog vertex property 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/** \page tutorial_03 Using (custom) properties
|
/** \page tutorial_03 Using (custom) properties
|
||||||
|
|
||||||
This examples shows:
|
This examples shows:
|
||||||
- How to add and remove custom properties,
|
- How to add and remove custom properties
|
||||||
- How to get and set the value of a custom property
|
- How to get and set the value of a custom property
|
||||||
|
|
||||||
In the last example we computed the barycenter of each vertex'
|
In the last example we computed the barycenter of each vertex'
|
||||||
@@ -11,44 +11,69 @@ let %OpenMesh manage the data.
|
|||||||
It would be even more helpful if we could attach such properties
|
It would be even more helpful if we could attach such properties
|
||||||
dynamically to the mesh.
|
dynamically to the mesh.
|
||||||
|
|
||||||
%OpenMesh provides dynamic properties, which can be attached to each
|
Custom properties can be conveniently created and attached to meshes with the following functions:
|
||||||
mesh entity (vertex, face, edge, halfedge, and the mesh itself). We
|
- makeTemporaryProperty() creates a property that is temporary to the current scope.
|
||||||
distinguish between custom and standard properties. A custom property
|
- getOrMakeProperty() is used for creating and accessing permanent named properties on a mesh.
|
||||||
is any user-defined property and is accessed via the member function
|
- getProperty() is used for accessing an existing permanent named property on a mesh.
|
||||||
\c property(..) via a handle and an entity handle
|
|
||||||
(e.g. VertexHandle). Whereas the standard properties are accessed via
|
|
||||||
special member functions, e.g. the vertex position is accessed with \c
|
|
||||||
point(..) and a vertex handle.
|
|
||||||
|
|
||||||
In this example we will store the \c cog-value (see previous example)
|
All three functions take two template arguments:
|
||||||
in an additional vertex property instead of keeping it in a separate
|
- First, the type of the mesh element that the property is attached to (i.e. OpenMesh::VertexHandle, OpenMesh::HalfedgeHandle, OpenMesh::EdgeHandle, or OpenMesh::FaceHandle).
|
||||||
array. To do so we define first a so-called property handle with the desired
|
- Second, the type of the property value that is attached to each element (e.g., \p int, \p double, etc.).
|
||||||
type (\c MyMesh::Point) and register the handle at the mesh:
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
In this example, we will store the \c cog value (see previous example) in a vertex property instead of keeping it in a separate array.
|
||||||
|
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
|
\dontinclude 03-properties/smooth.cc
|
||||||
\skipline vertex property stores
|
\skipline makeTemporaryProperty
|
||||||
\until mesh.add
|
|
||||||
|
|
||||||
<br>The \c mesh allocates enough memory to hold as many elements of type
|
Enough memory is allocated to hold as many values of \c %MyMesh::Point as there are vertices.
|
||||||
\c MyMesh::Point as number of vertices exist, and of course the mesh
|
All insert and delete operations on the mesh are synchronized with the attached properties.
|
||||||
synchronizes all insert and delete operations on the vertices with the
|
|
||||||
vertex properties.
|
|
||||||
|
|
||||||
Once the wanted property is registered we can use the property to
|
Once the property is created, we can use it to compute the centers of the neighborhood of each vertex:
|
||||||
calculate the barycenter of the neighborhood of each vertex \c v_it
|
|
||||||
|
|
||||||
\dontinclude 03-properties/smooth.cc
|
\skipline mesh.vertices
|
||||||
\skipline vv_it=
|
\until cog[vv] /= valence
|
||||||
\until }
|
\until }
|
||||||
\until mesh.prop
|
|
||||||
|
|
||||||
<br>and finally set the new position for each vertex \c v_it
|
Finally, we set the new position for each vertex:
|
||||||
|
|
||||||
\dontinclude 03-properties/smooth.cc
|
\skipline mesh.vertices
|
||||||
\skipline mesh.set_point
|
\until mesh.point
|
||||||
|
\until }
|
||||||
|
|
||||||
<br>Below is the complete source code:
|
---
|
||||||
|
|
||||||
|
Since we chose to use makeTemporaryProperty(), the created property is automatically 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:
|
||||||
|
|
||||||
|
\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.
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The functions makeTemporaryProperty(), getOrMakeProperty(), and getProperty() 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).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Below is the complete source code:
|
||||||
|
|
||||||
\include 03-properties/smooth.cc
|
\include 03-properties/smooth.cc
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
40
src/OpenMesh/Core/Utils/HandleToPropHandle.hh
Normal file
40
src/OpenMesh/Core/Utils/HandleToPropHandle.hh
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef HANDLETOPROPHANDLE_HH_
|
||||||
|
#define HANDLETOPROPHANDLE_HH_
|
||||||
|
|
||||||
|
#include <OpenMesh/Core/Mesh/Handles.hh>
|
||||||
|
#include <OpenMesh/Core/Utils/Property.hh>
|
||||||
|
|
||||||
|
namespace OpenMesh {
|
||||||
|
|
||||||
|
template<typename ElementT, typename T>
|
||||||
|
struct HandleToPropHandle {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct HandleToPropHandle<OpenMesh::VertexHandle, T> {
|
||||||
|
using type = OpenMesh::VPropHandleT<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct HandleToPropHandle<OpenMesh::HalfedgeHandle, T> {
|
||||||
|
using type = OpenMesh::HPropHandleT<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct HandleToPropHandle<OpenMesh::EdgeHandle, T> {
|
||||||
|
using type = OpenMesh::EPropHandleT<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct HandleToPropHandle<OpenMesh::FaceHandle, T> {
|
||||||
|
using type = OpenMesh::FPropHandleT<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct HandleToPropHandle<void, T> {
|
||||||
|
using type = OpenMesh::MPropHandleT<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace OpenMesh
|
||||||
|
|
||||||
|
#endif // HANDLETOPROPHANDLE_HH_
|
||||||
@@ -49,6 +49,8 @@
|
|||||||
#ifndef PROPERTYMANAGER_HH_
|
#ifndef PROPERTYMANAGER_HH_
|
||||||
#define PROPERTYMANAGER_HH_
|
#define PROPERTYMANAGER_HH_
|
||||||
|
|
||||||
|
#include <OpenMesh/Core/System/config.h>
|
||||||
|
#include <OpenMesh/Core/Utils/HandleToPropHandle.hh>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -60,35 +62,23 @@ namespace OpenMesh {
|
|||||||
* It also defines convenience operators to access the encapsulated
|
* It also defines convenience operators to access the encapsulated
|
||||||
* property's value.
|
* property's value.
|
||||||
*
|
*
|
||||||
* For C++11, it is recommended to use the factory functions
|
* It is recommended to use the factory functions
|
||||||
* makePropertyManagerFromNew, makePropertyManagerFromExisting,
|
* makeTemporaryProperty(), getProperty(), and getOrMakeProperty()
|
||||||
* makePropertyManagerFromExistingOrNew to construct a PropertyManager, e.g.
|
* to construct a PropertyManager, e.g.
|
||||||
*
|
*
|
||||||
* \code
|
* \code
|
||||||
* TriMesh mesh;
|
* {
|
||||||
* auto visited = makePropertyManagerFromNew<VPropHandleT<bool>>(mesh, "visited.plugin-example.i8.informatik.rwth-aachen.de");
|
* TriMesh mesh;
|
||||||
|
* auto visited = makeTemporaryProperty<VertexHandle, bool>(mesh);
|
||||||
*
|
*
|
||||||
* for (auto vh : mesh.vertices()) {
|
* for (auto vh : mesh.vertices()) {
|
||||||
* if (!visited[vh]) {
|
* if (!visited[vh]) {
|
||||||
* visitComponent(mesh, vh, visited);
|
* visitComponent(mesh, vh, visited);
|
||||||
|
* }
|
||||||
* }
|
* }
|
||||||
|
* // The property is automatically removed at the end of the scope
|
||||||
* }
|
* }
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
|
||||||
* For C++98, it is usually more convenient to use the constructor explicitly,
|
|
||||||
* i.e.
|
|
||||||
*
|
|
||||||
* \code
|
|
||||||
* TriMesh mesh;
|
|
||||||
* PropertyManager<VPropHandleT<bool>, TriMesh> visited(mesh, "visited.plugin-example.i8.informatik.rwth-aachen.de");
|
|
||||||
*
|
|
||||||
* for (TriMesh::VertexIter vh_it = mesh.begin(); ... ; ...) {
|
|
||||||
* if (!visited[*vh_it]) {
|
|
||||||
* visitComponent(mesh, *vh_it, visited);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* \endcode
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
template<typename PROPTYPE, typename MeshT>
|
template<typename PROPTYPE, typename MeshT>
|
||||||
class PropertyManager {
|
class PropertyManager {
|
||||||
@@ -493,19 +483,127 @@ class PropertyManager {
|
|||||||
std::string name_;
|
std::string name_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \relates PropertyManager
|
/** @relates PropertyManager
|
||||||
|
*
|
||||||
|
* Creates a new property whose lifetime is limited to the current scope.
|
||||||
|
*
|
||||||
|
* Used for temporary properties. Shadows any existing properties of
|
||||||
|
* matching name and type.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
* PolyMesh m;
|
||||||
|
* {
|
||||||
|
* auto is_quad = makeTemporaryProperty<FaceHandle, bool>(m);
|
||||||
|
* for (auto& fh : m.faces()) {
|
||||||
|
* is_quad[fh] = (m.valence(fh) == 4);
|
||||||
|
* }
|
||||||
|
* // The property is automatically removed from the mesh at the end of the scope.
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @param mesh The mesh on which the property is created
|
||||||
|
* @param propname (optional) The name of the created property
|
||||||
|
* @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc.
|
||||||
|
* @tparam T Value type of the created property, e.g., \p double, \p int, etc.
|
||||||
|
* @tparam MeshT Type of the mesh. Can often be inferred from \p mesh
|
||||||
|
* @returns A PropertyManager handling the lifecycle of the property
|
||||||
|
*/
|
||||||
|
template<typename ElementT, typename T, typename MeshT>
|
||||||
|
PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT>
|
||||||
|
makeTemporaryProperty(MeshT &mesh, const char *propname = "") {
|
||||||
|
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT>(mesh, propname, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @relates PropertyManager
|
||||||
|
*
|
||||||
|
* Obtains a handle to a named property.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
* PolyMesh m;
|
||||||
|
* {
|
||||||
|
* try {
|
||||||
|
* auto is_quad = getProperty<FaceHandle, bool>(m, "is_quad");
|
||||||
|
* // Use is_quad here.
|
||||||
|
* }
|
||||||
|
* catch (const std::runtime_error& e) {
|
||||||
|
* // There is no is_quad face property on the mesh.
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @pre Property with the name \p propname of matching type exists.
|
||||||
|
* @throws std::runtime_error if no property with the name \p propname of
|
||||||
|
* matching type exists.
|
||||||
|
* @param mesh The mesh on which the property is created
|
||||||
|
* @param propname The name of the created property
|
||||||
|
* @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc.
|
||||||
|
* @tparam T Value type of the created property, e.g., \p double, \p int, etc.
|
||||||
|
* @tparam MeshT Type of the mesh. Can often be inferred from \p mesh
|
||||||
|
* @returns A PropertyManager wrapping the property
|
||||||
|
*/
|
||||||
|
template<typename ElementT, typename T, typename MeshT>
|
||||||
|
PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT>
|
||||||
|
getProperty(MeshT &mesh, const char *propname) {
|
||||||
|
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT>(mesh, propname, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @relates PropertyManager
|
||||||
|
*
|
||||||
|
* Obtains a handle to a named property if it exists or creates a new one otherwise.
|
||||||
|
*
|
||||||
|
* Used for creating or accessing permanent properties.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
* PolyMesh m;
|
||||||
|
* {
|
||||||
|
* auto is_quad = getOrMakeProperty<FaceHandle, bool>(m, "is_quad");
|
||||||
|
* for (auto& fh : m.faces()) {
|
||||||
|
* is_quad[fh] = (m.valence(fh) == 4);
|
||||||
|
* }
|
||||||
|
* // The property remains on the mesh after the end of the scope.
|
||||||
|
* }
|
||||||
|
* {
|
||||||
|
* // Retrieve the property from the previous scope.
|
||||||
|
* auto is_quad = getOrMakeProperty<FaceHandle, bool>(m, "is_quad");
|
||||||
|
* // Use is_quad here.
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @param mesh The mesh on which the property is created
|
||||||
|
* @param propname The name of the created property
|
||||||
|
* @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc.
|
||||||
|
* @tparam T Value type of the created property, e.g., \p double, \p int, etc.
|
||||||
|
* @tparam MeshT Type of the mesh. Can often be inferred from \p mesh
|
||||||
|
* @returns A PropertyManager wrapping the property
|
||||||
|
*/
|
||||||
|
template<typename ElementT, typename T, typename MeshT>
|
||||||
|
PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT>
|
||||||
|
getOrMakeProperty(MeshT &mesh, const char *propname) {
|
||||||
|
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT>::createIfNotExists(mesh, propname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @relates PropertyManager
|
||||||
|
* @deprecated Use makeTemporaryProperty() instead.
|
||||||
|
*
|
||||||
* Creates a new property whose lifecycle is managed by the returned
|
* Creates a new property whose lifecycle is managed by the returned
|
||||||
* PropertyManager.
|
* PropertyManager.
|
||||||
*
|
*
|
||||||
* Intended for temporary properties. Shadows any existsing properties of
|
* Intended for temporary properties. Shadows any existing properties of
|
||||||
* matching name and type.
|
* matching name and type.
|
||||||
*/
|
*/
|
||||||
template<typename PROPTYPE, typename MeshT>
|
template<typename PROPTYPE, typename MeshT>
|
||||||
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromNew(MeshT &mesh, const char *propname) {
|
OM_DEPRECATED("Use makeTemporaryProperty instead.")
|
||||||
|
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromNew(MeshT &mesh, const char *propname)
|
||||||
|
{
|
||||||
return PropertyManager<PROPTYPE, MeshT>(mesh, propname, false);
|
return PropertyManager<PROPTYPE, MeshT>(mesh, propname, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \relates PropertyManager
|
/** \relates PropertyManager
|
||||||
|
* @deprecated Use getProperty() instead.
|
||||||
|
*
|
||||||
* Creates a non-owning wrapper for an existing mesh property (no lifecycle
|
* Creates a non-owning wrapper for an existing mesh property (no lifecycle
|
||||||
* management).
|
* management).
|
||||||
*
|
*
|
||||||
@@ -516,22 +614,28 @@ PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromNew(MeshT &mesh, const c
|
|||||||
* matching type exists.
|
* matching type exists.
|
||||||
*/
|
*/
|
||||||
template<typename PROPTYPE, typename MeshT>
|
template<typename PROPTYPE, typename MeshT>
|
||||||
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExisting(MeshT &mesh, const char *propname) {
|
OM_DEPRECATED("Use getProperty instead.")
|
||||||
|
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExisting(MeshT &mesh, const char *propname)
|
||||||
|
{
|
||||||
return PropertyManager<PROPTYPE, MeshT>(mesh, propname, true);
|
return PropertyManager<PROPTYPE, MeshT>(mesh, propname, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \relates PropertyManager
|
/** @relates PropertyManager
|
||||||
|
* @deprecated Use getOrMakeProperty() instead.
|
||||||
|
*
|
||||||
* Creates a non-owning wrapper for a mesh property (no lifecycle management).
|
* Creates a non-owning wrapper for a mesh property (no lifecycle management).
|
||||||
* If the given property does not exist, it is created.
|
* If the given property does not exist, it is created.
|
||||||
*
|
*
|
||||||
* Intended for creating or accessing persistent properties.
|
* Intended for creating or accessing persistent properties.
|
||||||
*/
|
*/
|
||||||
template<typename PROPTYPE, typename MeshT>
|
template<typename PROPTYPE, typename MeshT>
|
||||||
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(MeshT &mesh, const char *propname) {
|
OM_DEPRECATED("Use getOrMakeProperty instead.")
|
||||||
|
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(MeshT &mesh, const char *propname)
|
||||||
|
{
|
||||||
return PropertyManager<PROPTYPE, MeshT>::createIfNotExists(mesh, propname);
|
return PropertyManager<PROPTYPE, MeshT>::createIfNotExists(mesh, propname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \relates PropertyManager
|
/** @relates PropertyManager
|
||||||
* Like the two parameter version of makePropertyManagerFromExistingOrNew()
|
* Like the two parameter version of makePropertyManagerFromExistingOrNew()
|
||||||
* except it initializes the property with the specified value over the
|
* except it initializes the property with the specified value over the
|
||||||
* specified range if it needs to be created. If the property already exists,
|
* specified range if it needs to be created. If the property already exists,
|
||||||
@@ -552,7 +656,7 @@ PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(
|
|||||||
mesh, propname, begin, end, init_value);
|
mesh, propname, begin, end, init_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \relates PropertyManager
|
/** @relates PropertyManager
|
||||||
* Like the two parameter version of makePropertyManagerFromExistingOrNew()
|
* Like the two parameter version of makePropertyManagerFromExistingOrNew()
|
||||||
* except it initializes the property with the specified value over the
|
* except it initializes the property with the specified value over the
|
||||||
* specified range if it needs to be created. If the property already exists,
|
* specified range if it needs to be created. If the property already exists,
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
|
|||||||
ASSERT_TRUE(pm_f_bool[*f_it]);
|
ASSERT_TRUE(pm_f_bool[*f_it]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
||||||
/*
|
/*
|
||||||
* Same thing again, this time with C++11 ranges.
|
* Same thing again, this time with C++11 ranges.
|
||||||
*/
|
*/
|
||||||
@@ -129,15 +128,13 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
|
|||||||
f_it != f_end; ++f_it)
|
f_it != f_end; ++f_it)
|
||||||
ASSERT_TRUE(pm_f_bool[*f_it]);
|
ASSERT_TRUE(pm_f_bool[*f_it]);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ====================================================================
|
* ====================================================================
|
||||||
* C++11 Specific Tests
|
* Factory Functions
|
||||||
* ====================================================================
|
* ====================================================================
|
||||||
*/
|
*/
|
||||||
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
||||||
|
|
||||||
template<typename PropHandle, typename Mesh>
|
template<typename PropHandle, typename Mesh>
|
||||||
bool has_property(const Mesh& _mesh, const std::string& _name) {
|
bool has_property(const Mesh& _mesh, const std::string& _name) {
|
||||||
@@ -154,7 +151,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_temp_property) {
|
|||||||
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name));
|
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name));
|
||||||
|
|
||||||
{
|
{
|
||||||
auto vprop = OpenMesh::makePropertyManagerFromNew<handle_type>(mesh_, prop_name);
|
auto vprop = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
|
||||||
static_cast<void>(vprop); // Unused variable
|
static_cast<void>(vprop); // Unused variable
|
||||||
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
|
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
|
||||||
}
|
}
|
||||||
@@ -172,13 +169,13 @@ TEST_F(OpenMeshPropertyManager, cpp11_temp_property_shadowing) {
|
|||||||
using handle_type = OpenMesh::VPropHandleT<int>;
|
using handle_type = OpenMesh::VPropHandleT<int>;
|
||||||
const auto prop_name = "pm_v_test_property";
|
const auto prop_name = "pm_v_test_property";
|
||||||
|
|
||||||
auto outer_prop = OpenMesh::makePropertyManagerFromNew<handle_type>(mesh_, prop_name);
|
auto outer_prop = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
|
||||||
outer_prop[vh] = 100;
|
outer_prop[vh] = 100;
|
||||||
ASSERT_EQ(100, outer_prop[vh]);
|
ASSERT_EQ(100, outer_prop[vh]);
|
||||||
|
|
||||||
{
|
{
|
||||||
// inner_prop uses same type and name as outer_prop
|
// inner_prop uses same type and name as outer_prop
|
||||||
auto inner_prop = OpenMesh::makePropertyManagerFromNew<handle_type>(mesh_, prop_name);
|
auto inner_prop = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
|
||||||
inner_prop[vh] = 200;
|
inner_prop[vh] = 200;
|
||||||
ASSERT_EQ(200, inner_prop[vh]);
|
ASSERT_EQ(200, inner_prop[vh]);
|
||||||
// End of scope: inner_prop is removed from mesh_
|
// End of scope: inner_prop is removed from mesh_
|
||||||
@@ -205,7 +202,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
|
|||||||
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name));
|
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name));
|
||||||
|
|
||||||
{
|
{
|
||||||
auto prop = OpenMesh::makePropertyManagerFromExistingOrNew<handle_type>(mesh_, prop_name);
|
auto prop = OpenMesh::getOrMakeProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
|
||||||
prop[vh] = 100;
|
prop[vh] = 100;
|
||||||
// End of scope, property persists
|
// End of scope, property persists
|
||||||
}
|
}
|
||||||
@@ -214,7 +211,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Since a property of the same name and type already exists, this refers to the existing property.
|
// Since a property of the same name and type already exists, this refers to the existing property.
|
||||||
auto prop = OpenMesh::makePropertyManagerFromExistingOrNew<handle_type>(mesh_, prop_name);
|
auto prop = OpenMesh::getOrMakeProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
|
||||||
ASSERT_EQ(100, prop[vh]);
|
ASSERT_EQ(100, prop[vh]);
|
||||||
prop[vh] = 200;
|
prop[vh] = 200;
|
||||||
// End of scope, property persists
|
// End of scope, property persists
|
||||||
@@ -224,7 +221,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Acquire non-owning handle to the property, knowing it exists
|
// Acquire non-owning handle to the property, knowing it exists
|
||||||
auto prop = OpenMesh::makePropertyManagerFromExisting<handle_type>(mesh_, prop_name);
|
auto prop = OpenMesh::getProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
|
||||||
ASSERT_EQ(200, prop[vh]);
|
ASSERT_EQ(200, prop[vh]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,12 +229,13 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Attempt to acquire non-owning handle for a non-existing property
|
// Attempt to acquire non-owning handle for a non-existing property
|
||||||
ASSERT_THROW(OpenMesh::makePropertyManagerFromExisting<handle_type>(mesh_, "wrong_property_name"), std::runtime_error);
|
auto code_that_throws = [&](){
|
||||||
|
OpenMesh::getProperty<OpenMesh::VertexHandle, int>(mesh_, "wrong_prop_name");
|
||||||
|
};
|
||||||
|
ASSERT_THROW(code_that_throws(), std::runtime_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
|
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#include <OpenMesh/Core/Utils/PropertyManager.hh>
|
||||||
#include <Unittests/unittests_common.hh>
|
#include <Unittests/unittests_common.hh>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -448,36 +449,31 @@ TEST_F(OpenMeshTutorials, using_custom_properties) {
|
|||||||
bool ok = OpenMesh::IO::read_mesh(mesh, "output.off");
|
bool ok = OpenMesh::IO::read_mesh(mesh, "output.off");
|
||||||
EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'";
|
EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'";
|
||||||
|
|
||||||
// this vertex property stores the computed centers of gravity
|
const int iterations = 100;
|
||||||
OpenMesh::VPropHandleT<MyMesh::Point> cogs;
|
|
||||||
mesh.add_property(cogs);
|
|
||||||
|
|
||||||
// smoothing mesh N times
|
|
||||||
MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
|
|
||||||
MyMesh::VertexVertexIter vv_it;
|
|
||||||
MyMesh::Point cog;
|
|
||||||
MyMesh::Scalar valence;
|
|
||||||
unsigned int i, N(100);
|
|
||||||
|
|
||||||
for (i=0; i < N; ++i)
|
|
||||||
{
|
{
|
||||||
for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
|
// Add a vertex property storing the computed centers of gravity
|
||||||
{
|
auto cog = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, MyMesh::Point>(mesh);
|
||||||
mesh.property(cogs,*v_it).vectorize(0.0f);
|
|
||||||
valence = 0.0;
|
|
||||||
|
|
||||||
for (vv_it = mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it)
|
// Smooth the mesh several times
|
||||||
{
|
for (int i = 0; i < iterations; ++i) {
|
||||||
mesh.property(cogs,*v_it) += mesh.point( *vv_it );
|
// Iterate over all vertices to compute centers of gravity
|
||||||
++valence;
|
for (const auto& vh : mesh.vertices()) {
|
||||||
|
cog[vh] = {0,0,0};
|
||||||
|
int valence = 0;
|
||||||
|
// Iterate over all 1-ring vertices around vh
|
||||||
|
for (const auto& vvh : mesh.vv_range(vh)) {
|
||||||
|
cog[vh] += mesh.point(vvh);
|
||||||
|
++valence;
|
||||||
|
}
|
||||||
|
cog[vh] /= valence;
|
||||||
|
}
|
||||||
|
// Move all vertices to the previously computed positions
|
||||||
|
for (const auto& vh : mesh.vertices()) {
|
||||||
|
mesh.point(vh) = cog[vh];
|
||||||
}
|
}
|
||||||
mesh.property(cogs,*v_it) /= valence;
|
|
||||||
}
|
}
|
||||||
|
} // The cog vertex property is removed from the mesh at the end of this scope
|
||||||
for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
|
|
||||||
if ( !mesh.is_boundary( *v_it ) )
|
|
||||||
mesh.set_point( *v_it, mesh.property(cogs,*v_it) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// write mesh
|
// write mesh
|
||||||
ok = OpenMesh::IO::write_mesh(mesh, "smoothed_custom_properties_output.off");
|
ok = OpenMesh::IO::write_mesh(mesh, "smoothed_custom_properties_output.off");
|
||||||
|
|||||||
Reference in New Issue
Block a user