rework property manager
This commit is contained in:
@@ -78,25 +78,15 @@ namespace OpenMesh {
|
|||||||
*/
|
*/
|
||||||
template<typename PROPTYPE, typename MeshT = int>
|
template<typename PROPTYPE, typename MeshT = int>
|
||||||
class PropertyManager {
|
class PropertyManager {
|
||||||
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
||||||
public:
|
|
||||||
PropertyManager(const PropertyManager&) = delete;
|
|
||||||
PropertyManager& operator=(const PropertyManager&) = delete;
|
|
||||||
#else
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* Noncopyable because there aren't no straightforward copy semantics.
|
|
||||||
*/
|
|
||||||
PropertyManager(const PropertyManager&);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Noncopyable because there aren't no straightforward copy semantics.
|
|
||||||
*/
|
|
||||||
PropertyManager& operator=(const PropertyManager&);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using Value = typename PROPTYPE::Value;
|
||||||
|
using value_type = typename PROPTYPE::value_type;
|
||||||
|
using Handle = typename PROPTYPE::Handle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated Use a constructor without \p existing and check existance with hasProperty() instead.
|
||||||
|
*
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* Throws an \p std::runtime_error if \p existing is true and
|
* Throws an \p std::runtime_error if \p existing is true and
|
||||||
@@ -110,22 +100,114 @@ class PropertyManager {
|
|||||||
* the instance merely acts as a convenience wrapper around an existing property with no
|
* the instance merely acts as a convenience wrapper around an existing property with no
|
||||||
* lifecycle management whatsoever.
|
* lifecycle management whatsoever.
|
||||||
*
|
*
|
||||||
* @see PropertyManager::createIfNotExists, makePropertyManagerFromNew,
|
* @see PropertyManager::getOrMakeProperty, PropertyManager::getProperty,
|
||||||
* makePropertyManagerFromExisting, makePropertyManagerFromExistingOrNew
|
* PropertyManager::makeTemporaryProperty
|
||||||
*/
|
*/
|
||||||
PropertyManager(PolyConnectivity& mesh, const char *propname, bool existing = false) : mesh_(&mesh), retain_(existing), name_(propname) {
|
OM_DEPRECATED("Use the constructor without parameter 'existing' instead. Check for existance with hasProperty")
|
||||||
|
PropertyManager(PolyConnectivity& mesh, const char *propname, bool existing) : mesh_(mesh), retain_(existing), name_(propname) {
|
||||||
if (existing) {
|
if (existing) {
|
||||||
if (!mesh_->get_property_handle(prop_, propname)) {
|
if (!mesh_.get_property_handle(prop_, propname)) {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Requested property handle \"" << propname << "\" does not exist.";
|
oss << "Requested property handle \"" << propname << "\" does not exist.";
|
||||||
throw std::runtime_error(oss.str());
|
throw std::runtime_error(oss.str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mesh_->add_property(prop_, propname);
|
mesh_.add_property(prop_, propname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyManager() : mesh_(0), retain_(false) {
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* Asks for a property with name propname and creates one if none exists. Lifetime is not managed.
|
||||||
|
*
|
||||||
|
* @param mesh The mesh on which to create the property.
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* Asks for a property with name propname and creates one if none exists. Lifetime is not managed.
|
||||||
|
* If the property is created it is initialized with \p initial_value
|
||||||
|
*
|
||||||
|
* @param mesh The mesh on which to create the property.
|
||||||
|
* @param initial_value
|
||||||
|
* @param propname The name of the property.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
set_range(mesh_.all_elements<Handle>(), intial_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* Create an anonymous property. Lifetime is managed.
|
||||||
|
*
|
||||||
|
* @param mesh The mesh on which to create the property.
|
||||||
|
*/
|
||||||
|
PropertyManager(PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") {
|
||||||
|
mesh_.add_property(prop_, name_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* Create an anonymous property. Lifetime is managed.
|
||||||
|
* If the property is created it is initialized with \p initial_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_);
|
||||||
|
set_range(mesh_.all_elements<Handle>(), intial_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* Create a wrapper around an existing property. Lifetime is not managed.
|
||||||
|
*
|
||||||
|
* @param mesh The mesh on which to create the property.
|
||||||
|
*/
|
||||||
|
PropertyManager(PolyConnectivity& mesh, PROPTYPE property_handle) : mesh_(mesh), prop_(property_handle), retain_(true), name_() {
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyManager() = delete;
|
||||||
|
|
||||||
|
PropertyManager(const PropertyManager& rhs)
|
||||||
|
:
|
||||||
|
mesh_(rhs.mesh_),
|
||||||
|
prop_(),
|
||||||
|
retain_(rhs.retain_),
|
||||||
|
name_(rhs.name_)
|
||||||
|
{
|
||||||
|
if (rhs.retain_) // named property -> create a property manager referring to the same
|
||||||
|
{
|
||||||
|
prop_ = rhs.prop_;
|
||||||
|
}
|
||||||
|
else // unnamed property -> create a property manager refering to a new property and copy the contents
|
||||||
|
{
|
||||||
|
mesh_.add_property(prop_, name_);
|
||||||
|
rhs.copy_to(rhs.mesh_.template all_elements<Handle>(), *this, mesh_.all_elements<Handle>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyManager& operator=(const PropertyManager& rhs)
|
||||||
|
{
|
||||||
|
if (&mesh_ == &rhs.mesh_ && prop_ == rhs.prop_)
|
||||||
|
; // nothing to do
|
||||||
|
else
|
||||||
|
rhs.copy_to(rhs.mesh_.template all_elements<Handle>(), *this, mesh_.all_elements<Handle>());
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~PropertyManager() {
|
~PropertyManager() {
|
||||||
@@ -177,21 +259,40 @@ class PropertyManager {
|
|||||||
/**
|
/**
|
||||||
* Move constructor. Transfers ownership (delete responsibility).
|
* Move constructor. Transfers ownership (delete responsibility).
|
||||||
*/
|
*/
|
||||||
PropertyManager(PropertyManager &&rhs) : mesh_(rhs.mesh_), prop_(rhs.prop_), retain_(rhs.retain_), name_(rhs.name_) {
|
PropertyManager(PropertyManager &&rhs)
|
||||||
rhs.retain_ = true;
|
:
|
||||||
|
mesh_(rhs.mesh_),
|
||||||
|
prop_(rhs.prop_),
|
||||||
|
retain_(rhs.retain_),
|
||||||
|
name_(rhs.name_)
|
||||||
|
{
|
||||||
|
if (!rhs.retain_)
|
||||||
|
rhs.prop_.invalidate(); // only invalidate unnamed properties
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move assignment. Transfers ownership (delete responsibility).
|
* Move assignment. Transfers ownership (delete responsibility).
|
||||||
*/
|
*/
|
||||||
PropertyManager &operator=(PropertyManager &&rhs) {
|
PropertyManager& operator=(PropertyManager&& rhs)
|
||||||
if (&rhs != this) {
|
{
|
||||||
deleteProperty();
|
if ((&mesh_ != &rhs.mesh_) || (prop_ != rhs.prop_))
|
||||||
mesh_ = rhs.mesh_;
|
{
|
||||||
prop_ = rhs.prop_;
|
if (rhs.retain_)
|
||||||
retain_ = rhs.retain_;
|
{
|
||||||
name_ = rhs.name_;
|
// retained properties cannot be invalidated. Copy instead
|
||||||
rhs.retain_ = true;
|
rhs.copy_to(rhs.mesh_.template all_elements<Handle>(), *this, mesh_.all_elements<Handle>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// switch the data stored in the properties
|
||||||
|
std::swap(mesh_.property(prop_).data_vector(), rhs.mesh_.property(rhs.prop_).data_vector());
|
||||||
|
// resize the property to the correct size
|
||||||
|
mesh_.property(prop_).resize(mesh_.n_elements<Handle>());
|
||||||
|
// remove the property from rhs
|
||||||
|
rhs.mesh_.remove_property(rhs.prop_);
|
||||||
|
// invalidate prop_
|
||||||
|
rhs.prop_.invalidate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -204,10 +305,7 @@ class PropertyManager {
|
|||||||
* @see makePropertyManagerFromExistingOrNew
|
* @see makePropertyManagerFromExistingOrNew
|
||||||
*/
|
*/
|
||||||
static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname) {
|
static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname) {
|
||||||
PROPTYPE dummy_prop;
|
return PropertyManager(mesh, propname);
|
||||||
PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname));
|
|
||||||
pm.retain();
|
|
||||||
return std::move(pm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -248,8 +346,8 @@ class PropertyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PropertyManager duplicate(const char *clone_name) {
|
PropertyManager duplicate(const char *clone_name) {
|
||||||
PropertyManager pm(*mesh_, clone_name, false);
|
PropertyManager pm(mesh_, clone_name, false);
|
||||||
pm.mesh_->property(pm.prop_) = mesh_->property(prop_);
|
pm.mesh_.property(pm.prop_) = mesh_.property(prop_);
|
||||||
return pm;
|
return pm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,21 +426,11 @@ class PropertyManager {
|
|||||||
|
|
||||||
Proxy duplicate(const char *clone_name) {
|
Proxy duplicate(const char *clone_name) {
|
||||||
PropertyManager pm(*mesh_, clone_name, false);
|
PropertyManager pm(*mesh_, clone_name, false);
|
||||||
pm.mesh_->property(pm.prop_) = mesh_->property(prop_);
|
pm.mesh_.property(pm.prop_) = mesh_.property(prop_);
|
||||||
return (Proxy)pm;
|
return (Proxy)pm;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Disable lifecycle management for this property.
|
|
||||||
*
|
|
||||||
* If this method is called, the encapsulated property will not be deleted
|
|
||||||
* upon destruction of the PropertyManager instance.
|
|
||||||
*/
|
|
||||||
inline void retain(bool doRetain = true) {
|
|
||||||
retain_ = doRetain;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access the value of the encapsulated mesh property.
|
* Access the value of the encapsulated mesh property.
|
||||||
*
|
*
|
||||||
@@ -356,7 +444,7 @@ class PropertyManager {
|
|||||||
* @note This method is only used for mesh properties.
|
* @note This method is only used for mesh properties.
|
||||||
*/
|
*/
|
||||||
typename PROPTYPE::reference& operator*() {
|
typename PROPTYPE::reference& operator*() {
|
||||||
return mesh_->mproperty(prop_)[0];
|
return mesh_.mproperty(prop_)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -372,7 +460,7 @@ class PropertyManager {
|
|||||||
* @note This method is only used for mesh properties.
|
* @note This method is only used for mesh properties.
|
||||||
*/
|
*/
|
||||||
typename PROPTYPE::const_reference& operator*() const {
|
typename PROPTYPE::const_reference& operator*() const {
|
||||||
return mesh_->mproperty(prop_)[0];
|
return mesh_.mproperty(prop_)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -384,7 +472,7 @@ class PropertyManager {
|
|||||||
*/
|
*/
|
||||||
template<typename HandleType>
|
template<typename HandleType>
|
||||||
inline typename PROPTYPE::reference operator[] (const HandleType &handle) {
|
inline typename PROPTYPE::reference operator[] (const HandleType &handle) {
|
||||||
return mesh_->property(prop_, handle);
|
return mesh_.property(prop_, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -396,7 +484,7 @@ class PropertyManager {
|
|||||||
*/
|
*/
|
||||||
template<typename HandleType>
|
template<typename HandleType>
|
||||||
inline typename PROPTYPE::const_reference operator[] (const HandleType &handle) const {
|
inline typename PROPTYPE::const_reference operator[] (const HandleType &handle) const {
|
||||||
return mesh_->property(prop_, handle);
|
return mesh_.property(prop_, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -502,12 +590,12 @@ class PropertyManager {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void deleteProperty() {
|
void deleteProperty() {
|
||||||
if (!retain_)
|
if (!retain_ && prop_.is_valid())
|
||||||
mesh_->remove_property(prop_);
|
mesh_.remove_property(prop_);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PolyConnectivity* mesh_;
|
PolyConnectivity& mesh_;
|
||||||
PROPTYPE prop_;
|
PROPTYPE prop_;
|
||||||
bool retain_;
|
bool retain_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
@@ -544,6 +632,27 @@ makeTemporaryProperty(PolyConnectivity &mesh, const char *propname = "") {
|
|||||||
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type>(mesh, propname, false);
|
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type>(mesh, propname, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///// shortcut or makeTemporaryrProperty<OpenMesh::VertexHandle, T, MeshT>
|
||||||
|
//template<typename T, typename MeshT>
|
||||||
|
//PropertyManager<typename HandleToPropHandle<OpenMesh::VertexHandle, T>::type, MeshT>
|
||||||
|
//makeTemporaryVertexProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty<OpenMesh::VertexHandle, T>(mesh, propname); }
|
||||||
|
|
||||||
|
///// shortcut or makeTemporaryrProperty<OpenMesh::HalfedgeHandle, T, MeshT>
|
||||||
|
//template<typename T, typename MeshT>
|
||||||
|
//PropertyManager<typename HandleToPropHandle<OpenMesh::HalfedgeHandle, T>::type, MeshT>
|
||||||
|
//makeTemporaryHalfedgeProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty<OpenMesh::HalfedgeHandle, T>(mesh, propname); }
|
||||||
|
|
||||||
|
///// shortcut or makeTemporaryrProperty<OpenMesh::EdgeHandle, T, MeshT>
|
||||||
|
//template<typename T, typename MeshT>
|
||||||
|
//PropertyManager<typename HandleToPropHandle<OpenMesh::EdgeHandle, T>::type, MeshT>
|
||||||
|
//makeTemporaryEdgeProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty<OpenMesh::EdgeHandle, T>(mesh, propname); }
|
||||||
|
|
||||||
|
///// shortcut or makeTemporaryrProperty<OpenMesh::FaceHandle, T, MeshT>
|
||||||
|
//template<typename T, typename MeshT>
|
||||||
|
//PropertyManager<typename HandleToPropHandle<OpenMesh::FaceHandle, T>::type, MeshT>
|
||||||
|
//makeTemporaryFaceProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty<OpenMesh::FaceHandle, T>(mesh, propname); }
|
||||||
|
|
||||||
|
|
||||||
/** @relates PropertyManager
|
/** @relates PropertyManager
|
||||||
*
|
*
|
||||||
* Obtains a handle to a named property.
|
* Obtains a handle to a named property.
|
||||||
@@ -701,14 +810,14 @@ PropertyManager<PROPTYPE> makePropertyManagerFromExistingOrNew(PolyConnectivity
|
|||||||
*
|
*
|
||||||
* Intended for creating or accessing persistent properties.
|
* Intended for creating or accessing persistent properties.
|
||||||
*/
|
*/
|
||||||
template<typename PROPTYPE, typename MeshT,
|
template<typename PROPTYPE,
|
||||||
typename ITERATOR_TYPE, typename PROP_VALUE>
|
typename ITERATOR_TYPE, typename PROP_VALUE>
|
||||||
OM_DEPRECATED("Use getOrMakeProperty instead.")
|
OM_DEPRECATED("Use getOrMakeProperty instead.")
|
||||||
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(
|
PropertyManager<PROPTYPE> makePropertyManagerFromExistingOrNew(
|
||||||
MeshT &mesh, const char *propname,
|
PolyConnectivity &mesh, const char *propname,
|
||||||
const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end,
|
const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end,
|
||||||
const PROP_VALUE &init_value) {
|
const PROP_VALUE &init_value) {
|
||||||
return PropertyManager<PROPTYPE, MeshT>::createIfNotExists(
|
return PropertyManager<PROPTYPE>::createIfNotExists(
|
||||||
mesh, propname, begin, end, init_value);
|
mesh, propname, begin, end, init_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,5 +843,29 @@ PropertyManager<PROPTYPE> makePropertyManagerFromExistingOrNew(
|
|||||||
mesh, propname, range.begin(), range.end(), init_value);
|
mesh, propname, range.begin(), range.end(), init_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @relates PropertyManager
|
||||||
|
* Returns a convenience wrapper around the points property of a mesh.
|
||||||
|
*/
|
||||||
|
template<typename MeshT>
|
||||||
|
PropertyManager<OpenMesh::VPropHandleT<typename MeshT::Point>>
|
||||||
|
getPointsProperty(MeshT &mesh) {
|
||||||
|
return PropertyManager<OpenMesh::VPropHandleT<typename MeshT::Point>>(mesh, mesh.points_property_handle());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using VProp = PropertyManager<OpenMesh::VPropHandleT<T>>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using HProp = PropertyManager<OpenMesh::HPropHandleT<T>>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using EProp = PropertyManager<OpenMesh::EPropHandleT<T>>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using FProp = PropertyManager<OpenMesh::FPropHandleT<T>>;
|
||||||
|
|
||||||
|
|
||||||
} /* namespace OpenMesh */
|
} /* namespace OpenMesh */
|
||||||
#endif /* PROPERTYMANAGER_HH_ */
|
#endif /* PROPERTYMANAGER_HH_ */
|
||||||
|
|||||||
@@ -230,4 +230,614 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
|
|||||||
ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
|
ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(OpenMeshPropertyManager, property_copy_construction) {
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
mesh_.add_vertex(Mesh::Point());
|
||||||
|
|
||||||
|
// unnamed
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_);
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
auto prop2 = prop1; // prop1 and prop2 should be two different properties with the same content
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13);
|
||||||
|
}
|
||||||
|
|
||||||
|
// named
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids");
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
auto prop2 = prop1; // prop1 and prop2 should refere to the same property
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13);
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OpenMeshPropertyManager, property_move_construction) {
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
mesh_.add_vertex(Mesh::Point());
|
||||||
|
|
||||||
|
// unnamed
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_);
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_FALSE(prop1.isValid()) << "prop1 should have been invalidated";
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13);
|
||||||
|
}
|
||||||
|
|
||||||
|
// named
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids");
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_TRUE(prop1.isValid()) << "named properties cannot be invalidated";
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "property is not valid anymore";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "did not copy property correctly";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0);
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) {
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
mesh_.add_vertex(Mesh::Point());
|
||||||
|
|
||||||
|
// unnamed to unnamed
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(3, mesh_);
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(0, mesh_);
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
}
|
||||||
|
|
||||||
|
// unnamed to named
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_);
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(0, mesh_, "ids");
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids");
|
||||||
|
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to unnamed
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(mesh_);
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to named (different names)
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(mesh_, "ids4");
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to named (same names)
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(mesh_, "ids5");
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(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";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 42);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
|
||||||
|
|
||||||
|
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
|
||||||
|
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(OpenMeshPropertyManager, property_moving_same_mesh) {
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
mesh_.add_vertex(Mesh::Point());
|
||||||
|
|
||||||
|
// unnamed to unnamed
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_);
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(mesh_);
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
}
|
||||||
|
|
||||||
|
// unnamed to named
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_);
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(mesh_, "ids");
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids");
|
||||||
|
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to unnamed
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(mesh_);
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to named (different names)
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(mesh_, "ids4");
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to named (same names)
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(mesh_, "ids5");
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
|
||||||
|
|
||||||
|
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
|
||||||
|
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) {
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
mesh_.add_vertex(Mesh::Point());
|
||||||
|
|
||||||
|
auto copy = mesh_;
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
copy.add_vertex(Mesh::Point());
|
||||||
|
|
||||||
|
// unnamed to unnamed
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(3, mesh_);
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(0, copy);
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(copy.n_vertices()-1)]) << "Property not correctly resized";
|
||||||
|
}
|
||||||
|
|
||||||
|
// unnamed to named
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_);
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(0, copy, "ids");
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
auto prop3 = OpenMesh::VProp<int>(copy, "ids");
|
||||||
|
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to unnamed
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(copy);
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to named (different names)
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(copy, "ids4");
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to named (same names)
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(copy, "ids5");
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(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";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 42);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
|
||||||
|
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
|
||||||
|
auto prop4 = OpenMesh::VProp<int>(copy, "ids5");
|
||||||
|
EXPECT_EQ(prop4[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) {
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
mesh_.add_vertex(Mesh::Point());
|
||||||
|
|
||||||
|
auto copy = mesh_;
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
copy.add_vertex(Mesh::Point());
|
||||||
|
|
||||||
|
// unnamed to unnamed
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_);
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(copy);
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(copy.n_vertices()-1)]) << "Property not correctly resized";
|
||||||
|
}
|
||||||
|
|
||||||
|
// unnamed to named
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_);
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(copy, "ids");
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
auto prop3 = OpenMesh::VProp<int>(copy, "ids");
|
||||||
|
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to unnamed
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(copy);
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to named (different names)
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(copy, "ids4");
|
||||||
|
prop2.set_range(mesh_.vertices(), 0);
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
}
|
||||||
|
|
||||||
|
// named to named (same names)
|
||||||
|
{
|
||||||
|
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
|
||||||
|
auto prop2 = OpenMesh::VProp<int>(copy, "ids5");
|
||||||
|
|
||||||
|
for (auto vh : mesh_.vertices())
|
||||||
|
prop1[vh] = vh.idx()*2-13;
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
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<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;
|
||||||
|
|
||||||
|
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
prop1.set_range(mesh_.vertices(), 42);
|
||||||
|
|
||||||
|
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
|
||||||
|
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
|
||||||
|
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
|
||||||
|
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
|
||||||
|
auto prop4 = OpenMesh::VProp<int>(copy, "ids5");
|
||||||
|
EXPECT_EQ(prop4[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user