From c4e7125c97f3d19b81739f82f9bd36578f025a04 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 5 Nov 2019 15:30:05 +0100 Subject: [PATCH] allow adding temporary properties on const meshes --- src/OpenMesh/Core/Utils/PropertyManager.hh | 130 ++++++++++++++------- src/Unittests/unittests_propertymanager.cc | 109 +++++++++++++---- 2 files changed, 173 insertions(+), 66 deletions(-) diff --git a/src/OpenMesh/Core/Utils/PropertyManager.hh b/src/OpenMesh/Core/Utils/PropertyManager.hh index 207746ae..82db190d 100644 --- a/src/OpenMesh/Core/Utils/PropertyManager.hh +++ b/src/OpenMesh/Core/Utils/PropertyManager.hh @@ -101,6 +101,12 @@ class PropertyManager { static void swap(PropertyManager& from, PropertyManager2& to) { std::swap(*to, *from); } + static const Value& access_property_const(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle&) { + return mesh.property(prop_handle); + } + static Value& access_property(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle&) { + return mesh.property(prop_handle); + } }; // definition for other Mesh Properties @@ -110,10 +116,16 @@ class PropertyManager { from.copy_to(from.mesh_.template all_elements(), to, to.mesh_.template all_elements()); } static void swap(PropertyManager& lhs, PropertyManager2& rhs) { - std::swap(lhs.mesh_.property(lhs.prop_).data_vector(), rhs.mesh_.property(rhs.prop_).data_vector()); + std::swap(lhs.mesh().property(lhs.prop_).data_vector(), rhs.mesh().property(rhs.prop_).data_vector()); // resize the property to the correct size - lhs.mesh_.property(lhs.prop_).resize(lhs.mesh_.template n_elements()); - rhs.mesh_.property(rhs.prop_).resize(rhs.mesh_.template n_elements()); + lhs.mesh().property(lhs.prop_).resize(lhs.mesh().template n_elements()); + rhs.mesh().property(rhs.prop_).resize(rhs.mesh().template n_elements()); + } + static const Value& access_property_const(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle& handle) { + return mesh.property(prop_handle, handle); + } + static Value& access_property(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle& handle) { + return mesh.property(prop_handle, handle); } }; @@ -143,13 +155,13 @@ class PropertyManager { OM_DEPRECATED("Use the constructor without parameter 'existing' instead. Check for existance with hasProperty") // As long as this overload exists, initial value must be first parameter due to ambiguity for properties of type bool PropertyManager(PolyConnectivity& mesh, const char *propname, bool existing) : mesh_(mesh), retain_(existing), name_(propname) { if (existing) { - if (!mesh_.get_property_handle(prop_, propname)) { + if (!PropertyManager::mesh().get_property_handle(prop_, propname)) { std::ostringstream oss; oss << "Requested property handle \"" << propname << "\" does not exist."; throw std::runtime_error(oss.str()); } } else { - mesh_.add_property(prop_, propname); + PropertyManager::mesh().add_property(prop_, propname); } } @@ -162,8 +174,8 @@ class PropertyManager { * @param propname The name of the property. */ PropertyManager(PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) { - if (!mesh_.get_property_handle(prop_, propname)) { - mesh_.add_property(prop_, propname); + if (!PropertyManager::mesh().get_property_handle(prop_, propname)) { + PropertyManager::mesh().add_property(prop_, propname); } } @@ -179,7 +191,7 @@ class PropertyManager { */ PropertyManager(const Value& intial_value, PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) { if (!mesh_.get_property_handle(prop_, propname)) { - mesh_.add_property(prop_, propname); + PropertyManager::mesh().add_property(prop_, propname); set_range(mesh_.all_elements(), intial_value); } } @@ -191,8 +203,8 @@ class PropertyManager { * * @param mesh The mesh on which to create the property. */ - PropertyManager(PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { - mesh_.add_property(prop_, name_); + PropertyManager(const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { + PropertyManager::mesh().add_property(prop_, name_); } /** @@ -203,8 +215,8 @@ class PropertyManager { * @param initial_value The property will be initialized with intial_value. * @param mesh The mesh on which to create the property. */ - PropertyManager(const Value& intial_value, PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { - mesh_.add_property(prop_, name_); + PropertyManager(const Value& intial_value, const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { + PropertyManager::mesh().add_property(prop_, name_); set_range(mesh_.all_elements(), intial_value); } @@ -233,7 +245,7 @@ class PropertyManager { } else // unnamed property -> create a property manager refering to a new property and copy the contents { - mesh_.add_property(prop_, name_); + PropertyManager::mesh().add_property(prop_, name_); Storage::copy(rhs, *this); } } @@ -282,9 +294,9 @@ class PropertyManager { * */ template - MeshType& getMesh() const { return dynamic_cast(mesh_); } + const MeshType& getMesh() const { return dynamic_cast(mesh_); } - MeshT& getMesh() const { return dynamic_cast(mesh_); } + const MeshT& getMesh() const { return dynamic_cast(mesh_); } /** * Move constructor. Transfers ownership (delete responsibility). @@ -317,7 +329,7 @@ class PropertyManager { // swap the data stored in the properties Storage::swap(rhs, *this); // remove the property from rhs - rhs.mesh_.remove_property(rhs.prop_); + rhs.mesh().remove_property(rhs.prop_); // invalidate prop_ rhs.prop_.invalidate(); } @@ -373,18 +385,6 @@ class PropertyManager { mesh, propname, range.begin(), range.end(), init_value); } - PropertyManager duplicate(const char *clone_name) { - PropertyManager pm(mesh_, clone_name, false); - pm.mesh_.property(pm.prop_) = mesh_.property(prop_); - return pm; - } - - /** - * Included for backwards compatibility with non-C++11 version. - */ - PropertyManager move() { - return std::move(*this); - } /** * Access the value of the encapsulated mesh property. @@ -399,7 +399,7 @@ class PropertyManager { * @note This method is only used for mesh properties. */ typename PROPTYPE::reference& operator*() { - return mesh_.mproperty(prop_)[0]; + return mesh().mproperty(prop_)[0]; } /** @@ -415,7 +415,7 @@ class PropertyManager { * @note This method is only used for mesh properties. */ typename PROPTYPE::const_reference& operator*() const { - return mesh_.mproperty(prop_)[0]; + return mesh().mproperty(prop_)[0]; } /** @@ -425,9 +425,8 @@ class PropertyManager { * * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) */ - template - inline typename PROPTYPE::reference operator[] (const HandleType &handle) { - return mesh_.property(prop_, handle); + inline typename PROPTYPE::reference operator[] (Handle handle) { + return mesh().property(prop_, handle); } /** @@ -437,9 +436,8 @@ class PropertyManager { * * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) */ - template - inline typename PROPTYPE::const_reference operator[] (const HandleType &handle) const { - return mesh_.property(prop_, handle); + inline typename PROPTYPE::const_reference operator[] (const Handle& handle) const { + return mesh().property(prop_, handle); } /** @@ -449,9 +447,9 @@ class PropertyManager { * * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) */ - template - inline typename PROPTYPE::reference operator() (const HandleType &handle) { - return mesh_.property(prop_, handle); + inline typename PROPTYPE::reference operator() (const Handle& handle = Handle()) { +// return mesh().property(prop_, handle); + return Storage::access_property(mesh(), prop_, handle); } /** @@ -461,9 +459,9 @@ class PropertyManager { * * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) */ - template - inline typename PROPTYPE::const_reference operator() (const HandleType &handle) const { - return mesh_.property(prop_, handle); + inline typename PROPTYPE::const_reference operator() (const Handle& handle = Handle()) const { +// return mesh().property(prop_, handle); + return Storage::access_property_const(mesh(), prop_, handle); } /** @@ -571,16 +569,50 @@ class PropertyManager { private: void deleteProperty() { if (!retain_ && prop_.is_valid()) - mesh_.remove_property(prop_); + mesh().remove_property(prop_); + } + + PolyConnectivity& mesh() const + { + return const_cast(mesh_); } private: - PolyConnectivity& mesh_; + const PolyConnectivity& mesh_; PROPTYPE prop_; bool retain_; std::string name_; }; +template +class ConstPropertyViewer +{ +public: + using Value = typename PropertyT::Value; + using value_type = typename PropertyT::value_type; + using Handle = typename PropertyT::Handle; + + ConstPropertyViewer(const PolyConnectivity& mesh, PropertyT property_handle) + : + mesh_(mesh), + prop_(property_handle) + {} + + inline const typename PropertyT::const_reference operator() (const Handle& handle) + { + return mesh_.property(prop_, handle); + } + + inline const typename PropertyT::const_reference operator[] (const Handle& handle) + { + return mesh_.property(prop_, handle); + } + +private: + const PolyConnectivity& mesh_; + PropertyT prop_; +}; + /** @relates PropertyManager * * @deprecated Temporary properties should not have a name. @@ -852,6 +884,16 @@ getPointsProperty(MeshT &mesh) { return PropertyManager>(mesh, mesh.points_property_handle()); } +/** @relates PropertyManager + * Returns a convenience wrapper around the points property of a mesh that only allows const access. + */ +template +ConstPropertyViewer> +getPointsProperty(const MeshT &mesh) { + using PropType = OpenMesh::VPropHandleT; + return ConstPropertyViewer(mesh, mesh.points_property_handle()); +} + template using Prop = PropertyManager::template type>; diff --git a/src/Unittests/unittests_propertymanager.cc b/src/Unittests/unittests_propertymanager.cc index ea7e82f7..5ae91071 100644 --- a/src/Unittests/unittests_propertymanager.cc +++ b/src/Unittests/unittests_propertymanager.cc @@ -4,6 +4,13 @@ #include +//#define ENABLE_PROPERTY_TIMING_OUTPUT +#ifdef ENABLE_PROPERTY_TIMING_OUTPUT +#define TIMING_OUTPUT(X) X +#else +#define TIMING_OUTPUT(X) +#endif + namespace { class OpenMeshPropertyManager : public OpenMeshBase { @@ -228,7 +235,7 @@ TEST_F(OpenMeshPropertyManager, property_move_construction) { auto t_start = std::chrono::high_resolution_clock::now(); auto prop2 = std::move(prop1); auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "move constructing property from temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "move constructing property from temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_FALSE(prop1.isValid()) << "prop1 should have been invalidated"; @@ -244,7 +251,7 @@ TEST_F(OpenMeshPropertyManager, property_move_construction) { auto t_start = std::chrono::high_resolution_clock::now(); auto prop2 = std::move(prop1); // prop1 and prop2 should refere to the same property auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "move constructing from named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "move constructing from named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_TRUE(prop1.isValid()) << "named properties cannot be invalidated"; @@ -279,7 +286,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = prop1; auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "copying property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "copying property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed"; @@ -303,7 +310,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = prop1; auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "copying property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "copying property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed"; @@ -328,7 +335,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = prop1; auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "copying property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "copying property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) prop1.set_range(mesh_.vertices(), 0); @@ -351,7 +358,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = prop1; auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "copying property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "copying property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) prop1.set_range(mesh_.vertices(), 0); @@ -372,7 +379,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = prop1; // this should be a no op auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "copying property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "copying property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; @@ -417,7 +424,7 @@ TEST_F(OpenMeshPropertyManager, property_moving_same_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = std::move(prop1); // this should be cheap auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "moving property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "moving property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving"; @@ -439,7 +446,7 @@ TEST_F(OpenMeshPropertyManager, property_moving_same_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = std::move(prop1); auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "moving property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "moving property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving"; @@ -462,7 +469,7 @@ TEST_F(OpenMeshPropertyManager, property_moving_same_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "moving property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "moving property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; @@ -487,7 +494,7 @@ TEST_F(OpenMeshPropertyManager, property_moving_same_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "moving property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "moving property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; @@ -510,7 +517,7 @@ TEST_F(OpenMeshPropertyManager, property_moving_same_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = std::move(prop1); // this should be a no op auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "moving property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "moving property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; @@ -553,7 +560,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = prop1; auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "copying property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "copying property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed"; @@ -578,7 +585,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = prop1; auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "copying property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "copying property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed"; @@ -603,7 +610,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = prop1; auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "copying property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "copying property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) prop1.set_range(mesh_.vertices(), 0); @@ -626,7 +633,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = prop1; auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "copying property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "copying property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) prop1.set_range(mesh_.vertices(), 0); @@ -646,7 +653,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = prop1; // this should be a no op auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "copying property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "copying property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; @@ -687,7 +694,7 @@ TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = std::move(prop1); // this should be cheap auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "moving property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "moving property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving"; @@ -710,7 +717,7 @@ TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = std::move(prop1); auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "moving property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "moving property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving"; @@ -733,7 +740,7 @@ TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "moving property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "moving property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; @@ -758,7 +765,7 @@ TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "moving property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "moving property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; @@ -783,7 +790,7 @@ TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) { auto t_start = std::chrono::high_resolution_clock::now(); prop2 = std::move(prop1); // should copy auto t_end = std::chrono::high_resolution_clock::now(); - std::cout << "moving property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + TIMING_OUTPUT(std::cout << "moving property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; @@ -803,5 +810,63 @@ TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) { } +TEST_F(OpenMeshPropertyManager, temporary_property_on_const_mesh) { + + const auto& const_ref = mesh_; + + auto cog = OpenMesh::FProp(const_ref); + auto points = OpenMesh::getPointsProperty(const_ref); + + for (auto fh : const_ref.faces()) + cog(fh) = fh.vertices().avg(points); + + auto cog_copy = cog; + + for (auto fh : const_ref.faces()) + { + EXPECT_NE(&cog(fh), &cog_copy(fh)) << "Both properties point to the same memory"; + EXPECT_EQ(cog(fh), cog_copy(fh)) << "Property not copied correctly"; + } + + auto description = OpenMesh::MProp(const_ref); + description() = "Cool Const Mesh"; + + std::cout << description(OpenMesh::MeshHandle(33)) << std::endl; + +} + + +OpenMesh::VProp get_id_prop(const OpenMesh::PolyConnectivity& mesh) +{ + auto t_start = std::chrono::high_resolution_clock::now(); + + auto id_prop = OpenMesh::VProp(mesh); + for (auto vh : mesh.vertices()) + id_prop(vh) = vh.idx(); + + auto t_end = std::chrono::high_resolution_clock::now(); + TIMING_OUTPUT(std::cout << "Time spend in function: " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) + + return id_prop; +} + +TEST_F(OpenMeshPropertyManager, return_property_from_function) { + + for (int i = 0; i < 1000000; ++i) + mesh_.add_vertex(Mesh::Point()); + + auto t_start = std::chrono::high_resolution_clock::now(); + auto id_p = get_id_prop(mesh_); + auto t_end = std::chrono::high_resolution_clock::now(); + TIMING_OUTPUT(std::cout << "Time spend around function " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl;) + + for (auto vh : mesh_.vertices()) + { + EXPECT_EQ(id_p(vh), vh.idx()) << "Property not returned correctly" << std::endl; + } + +} + + }