Merge branch 'PropertyManagerRefactoring' into SmartRanges
# Conflicts: # src/OpenMesh/Core/Mesh/PolyConnectivity.hh
This commit is contained in:
@@ -105,10 +105,26 @@ public:
|
||||
FAttribs = MeshItems::FAttribs
|
||||
};
|
||||
|
||||
typedef VPropHandleT<VertexData> DataVPropHandle;
|
||||
typedef HPropHandleT<HalfedgeData> DataHPropHandle;
|
||||
typedef EPropHandleT<EdgeData> DataEPropHandle;
|
||||
typedef FPropHandleT<FaceData> DataFPropHandle;
|
||||
typedef VPropHandleT<VertexData> DataVPropHandle;
|
||||
typedef HPropHandleT<HalfedgeData> DataHPropHandle;
|
||||
typedef EPropHandleT<EdgeData> DataEPropHandle;
|
||||
typedef FPropHandleT<FaceData> DataFPropHandle;
|
||||
|
||||
typedef VPropHandleT<Point> PointsPropertyHandle;
|
||||
typedef VPropHandleT<Normal> VertexNormalsPropertyHandle;
|
||||
typedef VPropHandleT<Color> VertexColorsPropertyHandle;
|
||||
typedef VPropHandleT<TexCoord1D> VertexTexCoords1DPropertyHandle;
|
||||
typedef VPropHandleT<TexCoord2D> VertexTexCoords2DPropertyHandle;
|
||||
typedef VPropHandleT<TexCoord3D> VertexTexCoords3DPropertyHandle;
|
||||
typedef HPropHandleT<TexCoord1D> HalfedgeTexCoords1DPropertyHandle;
|
||||
typedef HPropHandleT<TexCoord2D> HalfedgeTexCoords2DPropertyHandle;
|
||||
typedef HPropHandleT<TexCoord3D> HalfedgeTexCoords3DPropertyHandle;
|
||||
typedef EPropHandleT<Color> EdgeColorsPropertyHandle;
|
||||
typedef HPropHandleT<Normal> HalfedgeNormalsPropertyHandle;
|
||||
typedef HPropHandleT<Color> HalfedgeColorsPropertyHandle;
|
||||
typedef FPropHandleT<Normal> FaceNormalsPropertyHandle;
|
||||
typedef FPropHandleT<Color> FaceColorsPropertyHandle;
|
||||
typedef FPropHandleT<TextureIndex> FaceTextureIndexPropertyHandle;
|
||||
|
||||
public:
|
||||
|
||||
@@ -240,6 +256,9 @@ public:
|
||||
void set_point(VertexHandle _vh, const Point& _p)
|
||||
{ this->property(points_, _vh) = _p; }
|
||||
|
||||
PointsPropertyHandle& points_property_handle()
|
||||
{ return points_; }
|
||||
|
||||
|
||||
//------------------------------------------------------------ vertex normals
|
||||
|
||||
@@ -592,24 +611,6 @@ public:
|
||||
bool has_face_colors() const { return face_colors_.is_valid(); }
|
||||
bool has_face_texture_index() const { return face_texture_index_.is_valid(); }
|
||||
|
||||
public:
|
||||
|
||||
typedef VPropHandleT<Point> PointsPropertyHandle;
|
||||
typedef VPropHandleT<Normal> VertexNormalsPropertyHandle;
|
||||
typedef VPropHandleT<Color> VertexColorsPropertyHandle;
|
||||
typedef VPropHandleT<TexCoord1D> VertexTexCoords1DPropertyHandle;
|
||||
typedef VPropHandleT<TexCoord2D> VertexTexCoords2DPropertyHandle;
|
||||
typedef VPropHandleT<TexCoord3D> VertexTexCoords3DPropertyHandle;
|
||||
typedef HPropHandleT<TexCoord1D> HalfedgeTexCoords1DPropertyHandle;
|
||||
typedef HPropHandleT<TexCoord2D> HalfedgeTexCoords2DPropertyHandle;
|
||||
typedef HPropHandleT<TexCoord3D> HalfedgeTexCoords3DPropertyHandle;
|
||||
typedef EPropHandleT<Color> EdgeColorsPropertyHandle;
|
||||
typedef HPropHandleT<Normal> HalfedgeNormalsPropertyHandle;
|
||||
typedef HPropHandleT<Color> HalfedgeColorsPropertyHandle;
|
||||
typedef FPropHandleT<Normal> FaceNormalsPropertyHandle;
|
||||
typedef FPropHandleT<Color> FaceColorsPropertyHandle;
|
||||
typedef FPropHandleT<TextureIndex> FaceTextureIndexPropertyHandle;
|
||||
|
||||
public:
|
||||
//standard vertex properties
|
||||
PointsPropertyHandle points_pph() const
|
||||
|
||||
@@ -516,7 +516,7 @@ public:
|
||||
// Copy all properties, if build in is true
|
||||
// Otherwise, copy only properties without build in specifier
|
||||
if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "v:" ) )
|
||||
(*p_it)->copy(_vh_from.idx(), _vh_to.idx());
|
||||
(*p_it)->copy(static_cast<size_t>(_vh_from.idx()), static_cast<size_t>(_vh_to.idx()));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -690,6 +690,9 @@ public: //----------------------------------------------------- element numbers
|
||||
virtual size_t n_edges() const { return 0; }
|
||||
virtual size_t n_faces() const { return 0; }
|
||||
|
||||
template <typename HandleT>
|
||||
size_t n_elements() const;
|
||||
|
||||
|
||||
protected: //------------------------------------------- synchronize properties
|
||||
|
||||
@@ -814,6 +817,16 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
inline size_t BaseKernel::n_elements<VertexHandle>() const { return n_vertices(); }
|
||||
template <>
|
||||
inline size_t BaseKernel::n_elements<HalfedgeHandle>() const { return n_halfedges(); }
|
||||
template <>
|
||||
inline size_t BaseKernel::n_elements<EdgeHandle>() const { return n_edges(); }
|
||||
template <>
|
||||
inline size_t BaseKernel::n_elements<FaceHandle>() const { return n_faces(); }
|
||||
|
||||
|
||||
//=============================================================================
|
||||
} // namespace OpenMesh
|
||||
//=============================================================================
|
||||
|
||||
66
src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh
Normal file
66
src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh
Normal file
@@ -0,0 +1,66 @@
|
||||
/* ========================================================================= *
|
||||
* *
|
||||
* OpenMesh *
|
||||
* Copyright (c) 2001-2019, RWTH-Aachen University *
|
||||
* Department of Computer Graphics and Multimedia *
|
||||
* All rights reserved. *
|
||||
* www.openmesh.org *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* This file is part of OpenMesh. *
|
||||
*---------------------------------------------------------------------------*
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* 1. Redistributions of source code must retain the above copyright notice, *
|
||||
* this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* 2. Redistributions in binary form must reproduce the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer in the *
|
||||
* documentation and/or other materials provided with the distribution. *
|
||||
* *
|
||||
* 3. Neither the name of the copyright holder nor the names of its *
|
||||
* contributors may be used to endorse or promote products derived from *
|
||||
* this software without specific prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
* *
|
||||
* ========================================================================= */
|
||||
|
||||
|
||||
#ifndef OPENMESH_DEFAULTPOLYMESH_HH
|
||||
#define OPENMESH_DEFAULTPOLYMESH_HH
|
||||
|
||||
|
||||
//== INCLUDES =================================================================
|
||||
|
||||
#include <OpenMesh/Core/Mesh/Traits.hh>
|
||||
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>
|
||||
|
||||
//== NAMESPACES ===============================================================
|
||||
|
||||
namespace OpenMesh {
|
||||
|
||||
//== TYPEDEFS =================================================================
|
||||
|
||||
typedef PolyMesh_ArrayKernelT<DefaultTraitsDouble> PolyMesh;
|
||||
|
||||
//=============================================================================
|
||||
} // namespace OpenMesh
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
#endif // OPENMESH_DEFAULTPOLYMESH_HH defined
|
||||
//=============================================================================
|
||||
66
src/OpenMesh/Core/Mesh/DefaultTriMesh.hh
Normal file
66
src/OpenMesh/Core/Mesh/DefaultTriMesh.hh
Normal file
@@ -0,0 +1,66 @@
|
||||
/* ========================================================================= *
|
||||
* *
|
||||
* OpenMesh *
|
||||
* Copyright (c) 2001-2019, RWTH-Aachen University *
|
||||
* Department of Computer Graphics and Multimedia *
|
||||
* All rights reserved. *
|
||||
* www.openmesh.org *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* This file is part of OpenMesh. *
|
||||
*---------------------------------------------------------------------------*
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* 1. Redistributions of source code must retain the above copyright notice, *
|
||||
* this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* 2. Redistributions in binary form must reproduce the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer in the *
|
||||
* documentation and/or other materials provided with the distribution. *
|
||||
* *
|
||||
* 3. Neither the name of the copyright holder nor the names of its *
|
||||
* contributors may be used to endorse or promote products derived from *
|
||||
* this software without specific prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
* *
|
||||
* ========================================================================= */
|
||||
|
||||
|
||||
#ifndef OPENMESH_DEFAULTTRIMESH_HH
|
||||
#define OPENMESH_DEFAULTTRIMESH_HH
|
||||
|
||||
|
||||
//== INCLUDES =================================================================
|
||||
|
||||
#include <OpenMesh/Core/Mesh/Traits.hh>
|
||||
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
|
||||
|
||||
//== NAMESPACES ===============================================================
|
||||
|
||||
namespace OpenMesh {
|
||||
|
||||
//== TYPEDEFS =================================================================
|
||||
|
||||
typedef TriMesh_ArrayKernelT<DefaultTraitsDouble> TriMesh;
|
||||
|
||||
//=============================================================================
|
||||
} // namespace OpenMesh
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
#endif // OPENMESH_DEFAULTTRIMESH_HH defined
|
||||
//=============================================================================
|
||||
@@ -1099,6 +1099,9 @@ public:
|
||||
&PolyConnectivity::faces_end>> ConstFaceRangeSkipping;
|
||||
|
||||
|
||||
template <typename HandleType>
|
||||
struct ElementRange;
|
||||
|
||||
/**
|
||||
* @return The vertices as a range object suitable
|
||||
* for C++11 range based for loops. Will skip deleted vertices.
|
||||
@@ -1147,12 +1150,26 @@ public:
|
||||
*/
|
||||
ConstFaceRange all_faces() const;
|
||||
|
||||
/**
|
||||
* @return The elements corresponding to the template type as a range object suitable
|
||||
* for C++11 range based for loops. Will skip deleted faces.
|
||||
*/
|
||||
template <typename HandleType>
|
||||
typename ElementRange<HandleType>::RangeSkipping elements() const;
|
||||
|
||||
/**
|
||||
* @return The elements corresponding to the template type as a range object suitable
|
||||
* for C++11 range based for loops. Will include deleted faces.
|
||||
*/
|
||||
template <typename HandleType>
|
||||
typename ElementRange<HandleType>::Range all_elements() const;
|
||||
|
||||
|
||||
typedef CirculatorRange<CirculatorRangeTraitT<
|
||||
PolyConnectivity,
|
||||
ConstVertexVertexCWIter,
|
||||
VertexHandle,
|
||||
VertexHandle,
|
||||
VertexHandle,
|
||||
VertexHandle,
|
||||
&PolyConnectivity::cvv_cwbegin,
|
||||
&PolyConnectivity::cvv_cwend>> ConstVertexVertexRange;
|
||||
typedef CirculatorRange<CirculatorRangeTraitT<
|
||||
@@ -1524,6 +1541,34 @@ private: // Working storage for add_face()
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PolyConnectivity::ElementRange<VertexHandle>
|
||||
{
|
||||
using Range = ConstVertexRange;
|
||||
using RangeSkipping = ConstVertexRangeSkipping;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PolyConnectivity::ElementRange<HalfedgeHandle>
|
||||
{
|
||||
using Range = ConstHalfedgeRange;
|
||||
using RangeSkipping = ConstHalfedgeRangeSkipping;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PolyConnectivity::ElementRange<EdgeHandle>
|
||||
{
|
||||
using Range = ConstEdgeRange;
|
||||
using RangeSkipping = ConstEdgeRangeSkipping;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PolyConnectivity::ElementRange<FaceHandle>
|
||||
{
|
||||
using Range = ConstFaceRange;
|
||||
using RangeSkipping = ConstFaceRangeSkipping;
|
||||
};
|
||||
|
||||
}//namespace OpenMesh
|
||||
|
||||
|
||||
@@ -1569,6 +1614,7 @@ class EntityRange : public SmartRangeT<EntityRange<RangeTraitT>, typename RangeT
|
||||
typename RangeTraitT::CONTAINER_TYPE &container_;
|
||||
};
|
||||
|
||||
|
||||
/// Generic class for iterator ranges.
|
||||
template <typename CirculatorRangeTraitT>
|
||||
//class CirculatorRange : public SmartRangeT<CirculatorRange<CirculatorRangeTraitT>, decltype (make_smart(std::declval<typename CirculatorRangeTraitT::TO_ENTITYE_TYPE>(), std::declval<PolyConnectivity>()))>{
|
||||
@@ -1592,7 +1638,6 @@ class CirculatorRange : public SmartRangeT<CirculatorRange<CirculatorRangeTraitT
|
||||
CENTER_ENTITY_TYPE center_;
|
||||
};
|
||||
|
||||
|
||||
inline PolyConnectivity::ConstVertexRangeSkipping PolyConnectivity::vertices() const { return ConstVertexRangeSkipping(*this); }
|
||||
inline PolyConnectivity::ConstVertexRange PolyConnectivity::all_vertices() const { return ConstVertexRange(*this); }
|
||||
inline PolyConnectivity::ConstHalfedgeRangeSkipping PolyConnectivity::halfedges() const { return ConstHalfedgeRangeSkipping(*this); }
|
||||
@@ -1602,6 +1647,15 @@ inline PolyConnectivity::ConstEdgeRange PolyConnectivity::all_edges(
|
||||
inline PolyConnectivity::ConstFaceRangeSkipping PolyConnectivity::faces() const { return ConstFaceRangeSkipping(*this); }
|
||||
inline PolyConnectivity::ConstFaceRange PolyConnectivity::all_faces() const { return ConstFaceRange(*this); }
|
||||
|
||||
template <> inline PolyConnectivity::ConstVertexRangeSkipping PolyConnectivity::elements<VertexHandle>() const { return vertices(); }
|
||||
template <> inline PolyConnectivity::ConstVertexRange PolyConnectivity::all_elements<VertexHandle>() const { return all_vertices(); }
|
||||
template <> inline PolyConnectivity::ConstHalfedgeRangeSkipping PolyConnectivity::elements<HalfedgeHandle>() const { return halfedges(); }
|
||||
template <> inline PolyConnectivity::ConstHalfedgeRange PolyConnectivity::all_elements<HalfedgeHandle>() const { return all_halfedges(); }
|
||||
template <> inline PolyConnectivity::ConstEdgeRangeSkipping PolyConnectivity::elements<EdgeHandle>() const { return edges(); }
|
||||
template <> inline PolyConnectivity::ConstEdgeRange PolyConnectivity::all_elements<EdgeHandle>() const { return all_edges(); }
|
||||
template <> inline PolyConnectivity::ConstFaceRangeSkipping PolyConnectivity::elements<FaceHandle>() const { return faces(); }
|
||||
template <> inline PolyConnectivity::ConstFaceRange PolyConnectivity::all_elements<FaceHandle>() const { return all_faces(); }
|
||||
|
||||
inline PolyConnectivity::ConstVertexVertexRange PolyConnectivity::vv_range(VertexHandle _vh) const {
|
||||
return ConstVertexVertexRange(*this, _vh);
|
||||
}
|
||||
|
||||
@@ -152,6 +152,24 @@ struct DefaultTraits
|
||||
FaceAttributes(0);
|
||||
};
|
||||
|
||||
/** \class DefaultTraitsDouble Traits.hh <OpenMesh/Mesh/Traits.hh>
|
||||
|
||||
Version of Default Traits that uses double precision for points and
|
||||
normals as well as floating point vectors for colors
|
||||
|
||||
\see The Mesh docu section on \ref mesh_type.
|
||||
\see Traits.hh for a list of macros for traits classes.
|
||||
*/
|
||||
struct DefaultTraitsDouble : public DefaultTraits
|
||||
{
|
||||
/// Use double precision points
|
||||
typedef OpenMesh::Vec3d Point;
|
||||
/// Use double precision Normals
|
||||
typedef OpenMesh::Vec3d Normal;
|
||||
/// Use RGBA Color
|
||||
typedef OpenMesh::Vec4f Color;
|
||||
};
|
||||
|
||||
|
||||
//== CLASS DEFINITION =========================================================
|
||||
|
||||
|
||||
@@ -485,6 +485,7 @@ struct VPropHandleT : public BasePropHandleT<T>
|
||||
{
|
||||
typedef T Value;
|
||||
typedef T value_type;
|
||||
typedef VertexHandle Handle;
|
||||
|
||||
explicit VPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {}
|
||||
explicit VPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {}
|
||||
@@ -499,6 +500,7 @@ struct HPropHandleT : public BasePropHandleT<T>
|
||||
{
|
||||
typedef T Value;
|
||||
typedef T value_type;
|
||||
typedef HalfedgeHandle Handle;
|
||||
|
||||
explicit HPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {}
|
||||
explicit HPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {}
|
||||
@@ -513,6 +515,7 @@ struct EPropHandleT : public BasePropHandleT<T>
|
||||
{
|
||||
typedef T Value;
|
||||
typedef T value_type;
|
||||
typedef EdgeHandle Handle;
|
||||
|
||||
explicit EPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {}
|
||||
explicit EPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {}
|
||||
@@ -527,6 +530,7 @@ struct FPropHandleT : public BasePropHandleT<T>
|
||||
{
|
||||
typedef T Value;
|
||||
typedef T value_type;
|
||||
typedef FaceHandle Handle;
|
||||
|
||||
explicit FPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {}
|
||||
explicit FPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {}
|
||||
@@ -541,11 +545,39 @@ struct MPropHandleT : public BasePropHandleT<T>
|
||||
{
|
||||
typedef T Value;
|
||||
typedef T value_type;
|
||||
typedef void Handle;
|
||||
|
||||
explicit MPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {}
|
||||
explicit MPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {}
|
||||
};
|
||||
|
||||
template <typename HandleT>
|
||||
struct PropHandle;
|
||||
|
||||
template <>
|
||||
struct PropHandle<VertexHandle> {
|
||||
template <typename T>
|
||||
using type = VPropHandleT<T>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PropHandle<HalfedgeHandle> {
|
||||
template <typename T>
|
||||
using type = HPropHandleT<T>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PropHandle<EdgeHandle> {
|
||||
template <typename T>
|
||||
using type = EPropHandleT<T>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PropHandle<FaceHandle> {
|
||||
template <typename T>
|
||||
using type = FPropHandleT<T>;
|
||||
};
|
||||
|
||||
} // namespace OpenMesh
|
||||
//=============================================================================
|
||||
#endif // OPENMESH_PROPERTY_HH defined
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
#include <OpenMesh/Core/System/config.h>
|
||||
#include <OpenMesh/Core/Utils/HandleToPropHandle.hh>
|
||||
#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@@ -59,6 +60,8 @@ namespace OpenMesh {
|
||||
* makeTemporaryProperty(), getProperty(), and getOrMakeProperty()
|
||||
* to construct a PropertyManager, e.g.
|
||||
*
|
||||
* Note that the second template parameter is depcretated.
|
||||
*
|
||||
* \code
|
||||
* {
|
||||
* TriMesh mesh;
|
||||
@@ -73,27 +76,54 @@ namespace OpenMesh {
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
template<typename PROPTYPE, typename MeshT>
|
||||
template<typename PROPTYPE, typename MeshT = int>
|
||||
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
|
||||
using Value = typename PROPTYPE::Value;
|
||||
using value_type = typename PROPTYPE::value_type;
|
||||
using Handle = typename PROPTYPE::Handle;
|
||||
using Self = PropertyManager<PROPTYPE, MeshT>;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Noncopyable because there aren't no straightforward copy semantics.
|
||||
*/
|
||||
PropertyManager(const PropertyManager&);
|
||||
// Mesh properties (MPropHandleT<...>) are stored differently than the other properties.
|
||||
// This class implements different behavior when copying or swapping data from one
|
||||
// property manager to a another one.
|
||||
template <typename PropertyManager2, typename PropHandleT>
|
||||
struct StorageT;
|
||||
|
||||
/**
|
||||
* Noncopyable because there aren't no straightforward copy semantics.
|
||||
*/
|
||||
PropertyManager& operator=(const PropertyManager&);
|
||||
#endif
|
||||
// specialization for Mesh Properties
|
||||
template <typename PropertyManager2>
|
||||
struct StorageT<PropertyManager2, MPropHandleT<Value>> {
|
||||
static void copy(const PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
|
||||
*to = *from;
|
||||
}
|
||||
static void swap(PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
|
||||
std::swap(*to, *from);
|
||||
}
|
||||
};
|
||||
|
||||
// definition for other Mesh Properties
|
||||
template <typename PropertyManager2, typename PropHandleT>
|
||||
struct StorageT {
|
||||
static void copy(const PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
|
||||
from.copy_to(from.mesh_.template all_elements<Handle>(), to, to.mesh_.template all_elements<Handle>());
|
||||
}
|
||||
static void swap(PropertyManager<PROPTYPE, MeshT>& lhs, PropertyManager2& rhs) {
|
||||
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<Handle>());
|
||||
rhs.mesh_.property(rhs.prop_).resize(rhs.mesh_.template n_elements<Handle>());
|
||||
}
|
||||
};
|
||||
|
||||
using Storage = StorageT<Self, PROPTYPE>;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @deprecated Use a constructor without \p existing and check existance with hasProperty() instead.
|
||||
*
|
||||
* Constructor.
|
||||
*
|
||||
* Throws an \p std::runtime_error if \p existing is true and
|
||||
@@ -107,22 +137,114 @@ class PropertyManager {
|
||||
* the instance merely acts as a convenience wrapper around an existing property with no
|
||||
* lifecycle management whatsoever.
|
||||
*
|
||||
* @see PropertyManager::createIfNotExists, makePropertyManagerFromNew,
|
||||
* makePropertyManagerFromExisting, makePropertyManagerFromExistingOrNew
|
||||
* @see PropertyManager::getOrMakeProperty, PropertyManager::getProperty,
|
||||
* PropertyManager::makeTemporaryProperty
|
||||
*/
|
||||
PropertyManager(MeshT &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") // 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 (!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);
|
||||
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.
|
||||
*
|
||||
* @param initial_value If the proeprty is newly created, it will be initialized with intial_value.
|
||||
* If the property already existed, nothing is changes.
|
||||
* @param mesh The mesh on which to create the property.
|
||||
* @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.
|
||||
*
|
||||
* @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_);
|
||||
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_);
|
||||
Storage::copy(rhs, *this);
|
||||
}
|
||||
}
|
||||
|
||||
PropertyManager& operator=(const PropertyManager& rhs)
|
||||
{
|
||||
if (&mesh_ == &rhs.mesh_ && prop_ == rhs.prop_)
|
||||
; // nothing to do
|
||||
else
|
||||
Storage::copy(rhs, *this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~PropertyManager() {
|
||||
@@ -130,49 +252,75 @@ class PropertyManager {
|
||||
}
|
||||
|
||||
void swap(PropertyManager &rhs) {
|
||||
std::swap(mesh_, rhs.mesh_);
|
||||
std::swap(prop_, rhs.prop_);
|
||||
std::swap(retain_, rhs.retain_);
|
||||
std::swap(name_, rhs.name_);
|
||||
// swap the data stored in the properties
|
||||
Storage::swap(rhs, *this);
|
||||
}
|
||||
|
||||
static bool propertyExists(MeshT &mesh, const char *propname) {
|
||||
static bool propertyExists(PolyConnectivity &mesh, const char *propname) {
|
||||
PROPTYPE dummy;
|
||||
return mesh.get_property_handle(dummy, propname);
|
||||
}
|
||||
|
||||
bool isValid() const { return mesh_ != 0; }
|
||||
bool isValid() const { return prop_.is_valid(); }
|
||||
operator bool() const { return isValid(); }
|
||||
|
||||
const PROPTYPE &getRawProperty() const { return prop_; }
|
||||
|
||||
const std::string &getName() const { return name_; }
|
||||
|
||||
MeshT &getMesh() const { return *mesh_; }
|
||||
/**
|
||||
* Get the mesh corresponding to the property.
|
||||
*
|
||||
* If you use PropertyManager without second template parameter (recommended)
|
||||
* you need to specify the actual mesh type when using this function, e.g.:
|
||||
* \code
|
||||
* {
|
||||
* TriMesh mesh;
|
||||
* auto visited = VProp<bool>(mesh);
|
||||
* TriMesh& mesh_ref = visited.getMesh<TriMesh>();
|
||||
* }
|
||||
*
|
||||
*/
|
||||
template <typename MeshType >
|
||||
MeshType& getMesh() const { return dynamic_cast<MeshType&>(mesh_); }
|
||||
|
||||
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
/// Only for pre C++11 compatibility.
|
||||
|
||||
typedef PropertyManager<PROPTYPE, MeshT> Proxy;
|
||||
MeshT& getMesh() const { return dynamic_cast<MeshT&>(mesh_); }
|
||||
|
||||
/**
|
||||
* Move constructor. Transfers ownership (delete responsibility).
|
||||
*/
|
||||
PropertyManager(PropertyManager &&rhs) : mesh_(rhs.mesh_), prop_(rhs.prop_), retain_(rhs.retain_), name_(rhs.name_) {
|
||||
rhs.retain_ = true;
|
||||
PropertyManager(PropertyManager &&rhs)
|
||||
:
|
||||
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).
|
||||
*/
|
||||
PropertyManager &operator=(PropertyManager &&rhs) {
|
||||
if (&rhs != this) {
|
||||
deleteProperty();
|
||||
mesh_ = rhs.mesh_;
|
||||
prop_ = rhs.prop_;
|
||||
retain_ = rhs.retain_;
|
||||
name_ = rhs.name_;
|
||||
rhs.retain_ = true;
|
||||
PropertyManager& operator=(PropertyManager&& rhs)
|
||||
{
|
||||
if ((&mesh_ != &rhs.mesh_) || (prop_ != rhs.prop_))
|
||||
{
|
||||
if (rhs.retain_)
|
||||
{
|
||||
// retained properties cannot be invalidated. Copy instead
|
||||
Storage::copy(rhs, *this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// swap the data stored in the properties
|
||||
Storage::swap(rhs, *this);
|
||||
// remove the property from rhs
|
||||
rhs.mesh_.remove_property(rhs.prop_);
|
||||
// invalidate prop_
|
||||
rhs.prop_.invalidate();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -184,11 +332,8 @@ class PropertyManager {
|
||||
*
|
||||
* @see makePropertyManagerFromExistingOrNew
|
||||
*/
|
||||
static PropertyManager createIfNotExists(MeshT &mesh, const char *propname) {
|
||||
PROPTYPE dummy_prop;
|
||||
PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname));
|
||||
pm.retain();
|
||||
return std::move(pm);
|
||||
static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname) {
|
||||
return PropertyManager(mesh, propname);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,7 +346,7 @@ class PropertyManager {
|
||||
* @see makePropertyManagerFromExistingOrNew
|
||||
*/
|
||||
template<typename PROP_VALUE, typename ITERATOR_TYPE>
|
||||
static PropertyManager createIfNotExists(MeshT &mesh, const char *propname,
|
||||
static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname,
|
||||
const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end,
|
||||
const PROP_VALUE &init_value) {
|
||||
const bool exists = propertyExists(mesh, propname);
|
||||
@@ -222,15 +367,15 @@ class PropertyManager {
|
||||
* @see makePropertyManagerFromExistingOrNew
|
||||
*/
|
||||
template<typename PROP_VALUE, typename ITERATOR_RANGE>
|
||||
static PropertyManager createIfNotExists(MeshT &mesh, const char *propname,
|
||||
static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname,
|
||||
const ITERATOR_RANGE &range, const PROP_VALUE &init_value) {
|
||||
return createIfNotExists(
|
||||
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_);
|
||||
PropertyManager pm(mesh_, clone_name, false);
|
||||
pm.mesh_.property(pm.prop_) = mesh_.property(prop_);
|
||||
return pm;
|
||||
}
|
||||
|
||||
@@ -241,89 +386,6 @@ class PropertyManager {
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
#else
|
||||
class Proxy {
|
||||
private:
|
||||
Proxy(MeshT *mesh_, PROPTYPE prop_, bool retain_, const std::string &name_) :
|
||||
mesh_(mesh_), prop_(prop_), retain_(retain_), name_(name_) {}
|
||||
MeshT *mesh_;
|
||||
PROPTYPE prop_;
|
||||
bool retain_;
|
||||
std::string name_;
|
||||
|
||||
friend class PropertyManager;
|
||||
};
|
||||
|
||||
operator Proxy() {
|
||||
Proxy p(mesh_, prop_, retain_, name_);
|
||||
mesh_ = 0;
|
||||
retain_ = true;
|
||||
return p;
|
||||
}
|
||||
|
||||
Proxy move() {
|
||||
return (Proxy)*this;
|
||||
}
|
||||
|
||||
PropertyManager(Proxy p) : mesh_(p.mesh_), prop_(p.prop_), retain_(p.retain_), name_(p.name_) {}
|
||||
|
||||
PropertyManager &operator=(Proxy p) {
|
||||
PropertyManager(p).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a property manager for the supplied property and mesh.
|
||||
* If the property doesn't exist, it is created. In any case,
|
||||
* lifecycle management is disabled.
|
||||
*
|
||||
* @see makePropertyManagerFromExistingOrNew
|
||||
*/
|
||||
static Proxy createIfNotExists(MeshT &mesh, const char *propname) {
|
||||
PROPTYPE dummy_prop;
|
||||
PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname));
|
||||
pm.retain();
|
||||
return (Proxy)pm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like createIfNotExists() with two parameters except, if the property
|
||||
* doesn't exist, it is initialized with the supplied value over
|
||||
* the supplied range after creation. If the property already exists,
|
||||
* this method has the exact same effect as the two parameter version.
|
||||
* Lifecycle management is disabled in any case.
|
||||
*
|
||||
* @see makePropertyManagerFromExistingOrNew
|
||||
*/
|
||||
template<typename PROP_VALUE, typename ITERATOR_TYPE>
|
||||
static Proxy createIfNotExists(MeshT &mesh, const char *propname,
|
||||
const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end,
|
||||
const PROP_VALUE &init_value) {
|
||||
const bool exists = propertyExists(mesh, propname);
|
||||
PropertyManager pm(mesh, propname, exists);
|
||||
pm.retain();
|
||||
if (!exists)
|
||||
pm.set_range(begin, end, init_value);
|
||||
return (Proxy)pm;
|
||||
}
|
||||
|
||||
Proxy duplicate(const char *clone_name) {
|
||||
PropertyManager pm(*mesh_, clone_name, false);
|
||||
pm.mesh_->property(pm.prop_) = mesh_->property(prop_);
|
||||
return (Proxy)pm;
|
||||
}
|
||||
#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.
|
||||
*
|
||||
@@ -337,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];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,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];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,7 +427,7 @@ class PropertyManager {
|
||||
*/
|
||||
template<typename HandleType>
|
||||
inline typename PROPTYPE::reference operator[] (const HandleType &handle) {
|
||||
return mesh_->property(prop_, handle);
|
||||
return mesh_.property(prop_, handle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -377,7 +439,7 @@ class PropertyManager {
|
||||
*/
|
||||
template<typename HandleType>
|
||||
inline typename PROPTYPE::const_reference operator[] (const HandleType &handle) const {
|
||||
return mesh_->property(prop_, handle);
|
||||
return mesh_.property(prop_, handle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -389,7 +451,7 @@ class PropertyManager {
|
||||
*/
|
||||
template<typename HandleType>
|
||||
inline typename PROPTYPE::reference operator() (const HandleType &handle) {
|
||||
return mesh_->property(prop_, handle);
|
||||
return mesh_.property(prop_, handle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,7 +463,7 @@ class PropertyManager {
|
||||
*/
|
||||
template<typename HandleType>
|
||||
inline typename PROPTYPE::const_reference operator() (const HandleType &handle) const {
|
||||
return mesh_->property(prop_, handle);
|
||||
return mesh_.property(prop_, handle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -410,7 +472,7 @@ class PropertyManager {
|
||||
* Examples:
|
||||
* \code
|
||||
* MeshT mesh;
|
||||
* PropertyManager<VPropHandleT<double>, MeshT> distance(
|
||||
* PropertyManager<VPropHandleT<double>> distance(
|
||||
* mesh, "distance.plugin-example.i8.informatik.rwth-aachen.de");
|
||||
* distance.set_range(
|
||||
* mesh.vertices_begin(), mesh.vertices_end(),
|
||||
@@ -458,9 +520,9 @@ class PropertyManager {
|
||||
* Will be used with dst_propmanager. Used to double check the bounds.
|
||||
*/
|
||||
template<typename HandleTypeIterator, typename PROPTYPE_2,
|
||||
typename MeshT_2, typename HandleTypeIterator_2>
|
||||
typename HandleTypeIterator_2>
|
||||
void copy_to(HandleTypeIterator begin, HandleTypeIterator end,
|
||||
PropertyManager<PROPTYPE_2, MeshT_2> &dst_propmanager,
|
||||
PropertyManager<PROPTYPE_2> &dst_propmanager,
|
||||
HandleTypeIterator_2 dst_begin, HandleTypeIterator_2 dst_end) const {
|
||||
|
||||
for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) {
|
||||
@@ -469,14 +531,15 @@ class PropertyManager {
|
||||
}
|
||||
|
||||
template<typename RangeType, typename PROPTYPE_2,
|
||||
typename MeshT_2, typename RangeType_2>
|
||||
typename RangeType_2>
|
||||
void copy_to(const RangeType &range,
|
||||
PropertyManager<PROPTYPE_2, MeshT_2> &dst_propmanager,
|
||||
PropertyManager<PROPTYPE_2> &dst_propmanager,
|
||||
const RangeType_2 &dst_range) const {
|
||||
copy_to(range.begin(), range.end(), dst_propmanager,
|
||||
dst_range.begin(), dst_range.end());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy the values of a property from a source range to
|
||||
* a target range. The source range must not be smaller than the
|
||||
@@ -491,15 +554,15 @@ class PropertyManager {
|
||||
* @param dst_mesh Destination mesh on which to copy.
|
||||
* @param dst_range Destination range.
|
||||
*/
|
||||
template<typename RangeType, typename MeshT_2, typename RangeType_2>
|
||||
template<typename RangeType, typename RangeType_2>
|
||||
static void copy(const char *prop_name,
|
||||
MeshT &src_mesh, const RangeType &src_range,
|
||||
MeshT_2 &dst_mesh, const RangeType_2 &dst_range) {
|
||||
PolyConnectivity &src_mesh, const RangeType &src_range,
|
||||
PolyConnectivity &dst_mesh, const RangeType_2 &dst_range) {
|
||||
|
||||
typedef OpenMesh::PropertyManager<PROPTYPE, MeshT> DstPM;
|
||||
typedef OpenMesh::PropertyManager<PROPTYPE> DstPM;
|
||||
DstPM dst(DstPM::createIfNotExists(dst_mesh, prop_name));
|
||||
|
||||
typedef OpenMesh::PropertyManager<PROPTYPE, MeshT_2> SrcPM;
|
||||
typedef OpenMesh::PropertyManager<PROPTYPE> SrcPM;
|
||||
SrcPM src(src_mesh, prop_name, true);
|
||||
|
||||
src.copy_to(src_range, dst, dst_range);
|
||||
@@ -507,18 +570,20 @@ class PropertyManager {
|
||||
|
||||
private:
|
||||
void deleteProperty() {
|
||||
if (!retain_)
|
||||
mesh_->remove_property(prop_);
|
||||
if (!retain_ && prop_.is_valid())
|
||||
mesh_.remove_property(prop_);
|
||||
}
|
||||
|
||||
private:
|
||||
MeshT *mesh_;
|
||||
PolyConnectivity& mesh_;
|
||||
PROPTYPE prop_;
|
||||
bool retain_;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
/** @relates PropertyManager
|
||||
*
|
||||
* @deprecated Temporary properties should not have a name.
|
||||
*
|
||||
* Creates a new property whose lifetime is limited to the current scope.
|
||||
*
|
||||
@@ -541,13 +606,72 @@ class PropertyManager {
|
||||
* @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);
|
||||
template<typename ElementT, typename T>
|
||||
PropertyManager<typename HandleToPropHandle<ElementT, T>::type>
|
||||
OM_DEPRECATED("Named temporary properties are deprecated. Either create a temporary without name or a non-temporary with name")
|
||||
makeTemporaryProperty(PolyConnectivity &mesh, const char *propname) {
|
||||
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type>(mesh, propname, false);
|
||||
}
|
||||
|
||||
/** @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
|
||||
* @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.
|
||||
* @returns A PropertyManager handling the lifecycle of the property
|
||||
*/
|
||||
template<typename ElementT, typename T>
|
||||
PropertyManager<typename HandleToPropHandle<ElementT, T>::type>
|
||||
makeTemporaryProperty(PolyConnectivity &mesh) {
|
||||
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type>(mesh);
|
||||
}
|
||||
|
||||
|
||||
/** @relates PropertyManager
|
||||
*
|
||||
* Tests whether a property with the given element type, value type, and name is
|
||||
* present on the given mesh.
|
||||
*
|
||||
* * Example:
|
||||
* @code
|
||||
* PolyMesh m;
|
||||
* if (hasProperty<FaceHandle, bool>(m, "is_quad")) {
|
||||
* // We now know the property exists: getProperty won't throw.
|
||||
* auto is_quad = getProperty<FaceHandle, bool>(m, "is_quad");
|
||||
* // Use is_quad here.
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @param mesh The mesh in question
|
||||
* @param propname The property name of the expected property
|
||||
* @tparam ElementT Element type of the expected property, e.g. VertexHandle, HalfedgeHandle, etc.
|
||||
* @tparam T Value type of the expected property, e.g., \p double, \p int, etc.
|
||||
* @tparam MeshT Type of the mesh. Can often be inferred from \p mesh
|
||||
*/
|
||||
template<typename ElementT, typename T>
|
||||
bool
|
||||
hasProperty(const PolyConnectivity &mesh, const char *propname) {
|
||||
typename HandleToPropHandle<ElementT, T>::type ph;
|
||||
return mesh.get_property_handle(ph, propname);
|
||||
}
|
||||
|
||||
/** @relates PropertyManager
|
||||
@@ -575,13 +699,18 @@ makeTemporaryProperty(MeshT &mesh, const char *propname = "") {
|
||||
* @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);
|
||||
template<typename ElementT, typename T>
|
||||
PropertyManager<typename HandleToPropHandle<ElementT, T>::type>
|
||||
getProperty(PolyConnectivity &mesh, const char *propname) {
|
||||
if (!hasProperty<ElementT, T>(mesh, propname))
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Requested property handle \"" << propname << "\" does not exist.";
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type>(mesh, propname);
|
||||
}
|
||||
|
||||
/** @relates PropertyManager
|
||||
@@ -611,41 +740,12 @@ getProperty(MeshT &mesh, const char *propname) {
|
||||
* @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
|
||||
*
|
||||
* Tests whether a property with the given element type, value type, and name is
|
||||
* present on the given mesh.
|
||||
*
|
||||
* * Example:
|
||||
* @code
|
||||
* PolyMesh m;
|
||||
* if (hasProperty<FaceHandle, bool>(m, "is_quad")) {
|
||||
* // We now know the property exists: getProperty won't throw.
|
||||
* auto is_quad = getProperty<FaceHandle, bool>(m, "is_quad");
|
||||
* // Use is_quad here.
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @param mesh The mesh in question
|
||||
* @param propname The property name of the expected property
|
||||
* @tparam ElementT Element type of the expected property, e.g. VertexHandle, HalfedgeHandle, etc.
|
||||
* @tparam T Value type of the expected property, e.g., \p double, \p int, etc.
|
||||
* @tparam MeshT Type of the mesh. Can often be inferred from \p mesh
|
||||
*/
|
||||
template<typename ElementT, typename T, typename MeshT>
|
||||
bool
|
||||
hasProperty(const MeshT &mesh, const char *propname) {
|
||||
typename HandleToPropHandle<ElementT, T>::type ph;
|
||||
return mesh.get_property_handle(ph, propname);
|
||||
template<typename ElementT, typename T>
|
||||
PropertyManager<typename HandleToPropHandle<ElementT, T>::type>
|
||||
getOrMakeProperty(PolyConnectivity &mesh, const char *propname) {
|
||||
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type>::createIfNotExists(mesh, propname);
|
||||
}
|
||||
|
||||
/** @relates PropertyManager
|
||||
@@ -657,11 +757,11 @@ hasProperty(const MeshT &mesh, const char *propname) {
|
||||
* Intended for temporary properties. Shadows any existing properties of
|
||||
* matching name and type.
|
||||
*/
|
||||
template<typename PROPTYPE, typename MeshT>
|
||||
template<typename PROPTYPE>
|
||||
OM_DEPRECATED("Use makeTemporaryProperty instead.")
|
||||
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromNew(MeshT &mesh, const char *propname)
|
||||
PropertyManager<PROPTYPE> makePropertyManagerFromNew(PolyConnectivity &mesh, const char *propname)
|
||||
{
|
||||
return PropertyManager<PROPTYPE, MeshT>(mesh, propname, false);
|
||||
return PropertyManager<PROPTYPE>(mesh, propname, false);
|
||||
}
|
||||
|
||||
/** \relates PropertyManager
|
||||
@@ -676,11 +776,11 @@ PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromNew(MeshT &mesh, const c
|
||||
* @throws std::runtime_error if no property with the name \p propname of
|
||||
* matching type exists.
|
||||
*/
|
||||
template<typename PROPTYPE, typename MeshT>
|
||||
template<typename PROPTYPE>
|
||||
OM_DEPRECATED("Use getProperty instead.")
|
||||
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExisting(MeshT &mesh, const char *propname)
|
||||
PropertyManager<PROPTYPE> makePropertyManagerFromExisting(PolyConnectivity &mesh, const char *propname)
|
||||
{
|
||||
return PropertyManager<PROPTYPE, MeshT>(mesh, propname, true);
|
||||
return PropertyManager<PROPTYPE>(mesh, propname, true);
|
||||
}
|
||||
|
||||
/** @relates PropertyManager
|
||||
@@ -691,11 +791,11 @@ PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExisting(MeshT &mesh, co
|
||||
*
|
||||
* Intended for creating or accessing persistent properties.
|
||||
*/
|
||||
template<typename PROPTYPE, typename MeshT>
|
||||
template<typename PROPTYPE>
|
||||
OM_DEPRECATED("Use getOrMakeProperty instead.")
|
||||
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(MeshT &mesh, const char *propname)
|
||||
PropertyManager<PROPTYPE> makePropertyManagerFromExistingOrNew(PolyConnectivity &mesh, const char *propname)
|
||||
{
|
||||
return PropertyManager<PROPTYPE, MeshT>::createIfNotExists(mesh, propname);
|
||||
return PropertyManager<PROPTYPE>::createIfNotExists(mesh, propname);
|
||||
}
|
||||
|
||||
/** @relates PropertyManager
|
||||
@@ -709,14 +809,14 @@ PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(MeshT &mes
|
||||
*
|
||||
* Intended for creating or accessing persistent properties.
|
||||
*/
|
||||
template<typename PROPTYPE, typename MeshT,
|
||||
template<typename PROPTYPE,
|
||||
typename ITERATOR_TYPE, typename PROP_VALUE>
|
||||
OM_DEPRECATED("Use getOrMakeProperty instead.")
|
||||
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(
|
||||
MeshT &mesh, const char *propname,
|
||||
PropertyManager<PROPTYPE> makePropertyManagerFromExistingOrNew(
|
||||
PolyConnectivity &mesh, const char *propname,
|
||||
const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end,
|
||||
const PROP_VALUE &init_value) {
|
||||
return PropertyManager<PROPTYPE, MeshT>::createIfNotExists(
|
||||
return PropertyManager<PROPTYPE>::createIfNotExists(
|
||||
mesh, propname, begin, end, init_value);
|
||||
}
|
||||
|
||||
@@ -731,16 +831,45 @@ PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(
|
||||
*
|
||||
* Intended for creating or accessing persistent properties.
|
||||
*/
|
||||
template<typename PROPTYPE, typename MeshT,
|
||||
template<typename PROPTYPE,
|
||||
typename ITERATOR_RANGE, typename PROP_VALUE>
|
||||
OM_DEPRECATED("Use getOrMakeProperty instead.")
|
||||
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(
|
||||
MeshT &mesh, const char *propname,
|
||||
PropertyManager<PROPTYPE> makePropertyManagerFromExistingOrNew(
|
||||
PolyConnectivity &mesh, const char *propname,
|
||||
const ITERATOR_RANGE &range,
|
||||
const PROP_VALUE &init_value) {
|
||||
return makePropertyManagerFromExistingOrNew<PROPTYPE, MeshT>(
|
||||
return makePropertyManagerFromExistingOrNew<PROPTYPE>(
|
||||
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 HandleT, typename T>
|
||||
using Prop = PropertyManager<typename PropHandle<HandleT>::template type<T>>;
|
||||
|
||||
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>>;
|
||||
|
||||
template <typename T>
|
||||
using MProp = PropertyManager<OpenMesh::MPropHandleT<T>>;
|
||||
|
||||
|
||||
} /* namespace OpenMesh */
|
||||
#endif /* PROPERTYMANAGER_HH_ */
|
||||
|
||||
@@ -51,8 +51,8 @@ protected: // SubdividerT interface
|
||||
_m.request_edge_status();
|
||||
_m.request_vertex_status();
|
||||
_m.request_face_status();
|
||||
PropertyManager<EPropHandleT<typename mesh_t::VertexHandle>, mesh_t> edge_midpoint(_m, "edge_midpoint");
|
||||
PropertyManager<VPropHandleT<bool>, mesh_t> is_original_vertex(_m, "is_original_vertex");
|
||||
PropertyManager<EPropHandleT<typename mesh_t::VertexHandle>> edge_midpoint(_m, "edge_midpoint");
|
||||
PropertyManager<VPropHandleT<bool>> is_original_vertex(_m, "is_original_vertex");
|
||||
|
||||
for (size_t iteration = 0; iteration < _n; ++iteration) {
|
||||
is_original_vertex.set_range(_m.vertices_begin(), _m.vertices_end(), true);
|
||||
|
||||
@@ -41,20 +41,25 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
|
||||
# Create unittest executable
|
||||
acg_add_executable(unittests ${UNITTEST_SRC})
|
||||
acg_add_executable(unittests_customvec ${UNITTEST_SRC})
|
||||
acg_add_executable(unittests_doublevec ${UNITTEST_SRC})
|
||||
target_compile_definitions(unittests_customvec PRIVATE TEST_CUSTOM_TRAITS)
|
||||
target_compile_definitions(unittests_doublevec PRIVATE TEST_DOUBLE_TRAITS)
|
||||
|
||||
# For the unittest we don't want the install rpath as set by acg_add_executable
|
||||
set_target_properties ( unittests PROPERTIES BUILD_WITH_INSTALL_RPATH 0 )
|
||||
set_target_properties ( unittests PROPERTIES BUILD_WITH_INSTALL_RPATH 0 )
|
||||
set_target_properties ( unittests_customvec PROPERTIES BUILD_WITH_INSTALL_RPATH 0 )
|
||||
set_target_properties ( unittests_doublevec PROPERTIES BUILD_WITH_INSTALL_RPATH 0 )
|
||||
|
||||
# Set output directory to ${BINARY_DIR}/Unittests
|
||||
set (OUTPUT_DIR "${CMAKE_BINARY_DIR}/Unittests")
|
||||
set_target_properties(unittests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
|
||||
set_target_properties(unittests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
|
||||
set_target_properties(unittests_customvec PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
|
||||
set_target_properties(unittests_doublevec PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
|
||||
foreach(CONFIG ${CMAKE_CONFIGURATION_TYPES})
|
||||
string(TOUPPER ${CONFIG} UPCONFIG)
|
||||
set_target_properties(unittests PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR})
|
||||
set_target_properties(unittests_customvec PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR})
|
||||
set_target_properties(unittests_doublevec PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR})
|
||||
endforeach()
|
||||
|
||||
|
||||
@@ -62,6 +67,7 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
|
||||
# Link against all necessary libraries
|
||||
target_link_libraries(unittests OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread)
|
||||
target_link_libraries(unittests_customvec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread)
|
||||
target_link_libraries(unittests_doublevec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread)
|
||||
|
||||
|
||||
|
||||
@@ -71,8 +77,9 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
|
||||
add_definitions( -DOPENMESHDLL )
|
||||
|
||||
endif()
|
||||
target_link_libraries(unittests OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
|
||||
target_link_libraries(unittests OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
|
||||
target_link_libraries(unittests_customvec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
|
||||
target_link_libraries(unittests_doublevec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
|
||||
endif()
|
||||
|
||||
|
||||
@@ -81,10 +88,12 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
|
||||
# Set compiler flags
|
||||
set_target_properties(unittests PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long")
|
||||
set_target_properties(unittests_customvec PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long")
|
||||
set_target_properties(unittests_doublevec PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long")
|
||||
else()
|
||||
# Set compiler flags
|
||||
set_target_properties(unittests PROPERTIES COMPILE_FLAGS "" )
|
||||
set_target_properties(unittests_customvec PROPERTIES COMPILE_FLAGS "" )
|
||||
set_target_properties(unittests_doublevec PROPERTIES COMPILE_FLAGS "" )
|
||||
endif()
|
||||
|
||||
if ( OPENMESH_BUILD_SHARED )
|
||||
@@ -103,14 +112,21 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
|
||||
"$<TARGET_FILE:${TAR}>"
|
||||
"${CMAKE_BINARY_DIR}/Unittests/$<TARGET_FILE_NAME:${TAR}>"
|
||||
COMMENT "Copying OpenMesh targets to unittests directory")
|
||||
add_custom_command(TARGET unittests_doublevec POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy
|
||||
"$<TARGET_FILE:${TAR}>"
|
||||
"${CMAKE_BINARY_DIR}/Unittests/$<TARGET_FILE_NAME:${TAR}>"
|
||||
COMMENT "Copying OpenMesh targets to unittests directory")
|
||||
endforeach(TAR)
|
||||
endif()
|
||||
|
||||
acg_copy_after_build(unittests ${CMAKE_CURRENT_SOURCE_DIR}/TestFiles ${CMAKE_BINARY_DIR}/Unittests/)
|
||||
acg_copy_after_build(unittests_customvec ${CMAKE_CURRENT_SOURCE_DIR}/TestFiles ${CMAKE_BINARY_DIR}/Unittests/)
|
||||
acg_copy_after_build(unittests_doublevec ${CMAKE_CURRENT_SOURCE_DIR}/TestFiles ${CMAKE_BINARY_DIR}/Unittests/)
|
||||
|
||||
add_test(NAME AllTestsIn_OpenMesh_tests WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/Unittests" COMMAND "${CMAKE_BINARY_DIR}/Unittests/unittests")
|
||||
add_test(NAME AllTestsIn_OpenMesh_tests_with_minimal_vector WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/Unittests" COMMAND "${CMAKE_BINARY_DIR}/Unittests/unittests_customvec")
|
||||
add_test(NAME AllTestsIn_OpenMesh_tests_with_double_vector WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/Unittests" COMMAND "${CMAKE_BINARY_DIR}/Unittests/unittests_doublevec")
|
||||
|
||||
else(GTEST_FOUND)
|
||||
message(STATUS "Google testing framework was not found, unittests disabled.")
|
||||
|
||||
@@ -62,7 +62,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
|
||||
|
||||
{
|
||||
OpenMesh::PropertyManager<
|
||||
OpenMesh::VPropHandleT<bool>, Mesh> pm_v_bool(mesh_, "pm_v_bool");
|
||||
OpenMesh::VPropHandleT<bool>> pm_v_bool(mesh_, "pm_v_bool");
|
||||
pm_v_bool.set_range(mesh_.vertices_begin(), mesh_.vertices_end(), false);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
ASSERT_FALSE(pm_v_bool[vhandle[i]]);
|
||||
@@ -71,7 +71,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
|
||||
ASSERT_TRUE(pm_v_bool[vhandle[i]]);
|
||||
|
||||
OpenMesh::PropertyManager<
|
||||
OpenMesh::EPropHandleT<bool>, Mesh> pm_e_bool(mesh_, "pm_e_bool");
|
||||
OpenMesh::EPropHandleT<bool>> pm_e_bool(mesh_, "pm_e_bool");
|
||||
pm_e_bool.set_range(mesh_.edges_begin(), mesh_.edges_end(), false);
|
||||
for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end();
|
||||
e_it != f_end; ++e_it)
|
||||
@@ -82,7 +82,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
|
||||
ASSERT_TRUE(pm_e_bool[*e_it]);
|
||||
|
||||
OpenMesh::PropertyManager<
|
||||
OpenMesh::FPropHandleT<bool>, Mesh> pm_f_bool(mesh_, "pm_f_bool");
|
||||
OpenMesh::FPropHandleT<bool>> pm_f_bool(mesh_, "pm_f_bool");
|
||||
pm_f_bool.set_range(mesh_.faces_begin(), mesh_.faces_end(), false);
|
||||
for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end();
|
||||
f_it != f_end; ++f_it)
|
||||
@@ -98,7 +98,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
|
||||
*/
|
||||
{
|
||||
OpenMesh::PropertyManager<
|
||||
OpenMesh::VPropHandleT<bool>, Mesh> pm_v_bool(mesh_, "pm_v_bool2");
|
||||
OpenMesh::VPropHandleT<bool>> pm_v_bool(mesh_, "pm_v_bool2");
|
||||
pm_v_bool.set_range(mesh_.vertices(), false);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
ASSERT_FALSE(pm_v_bool[vhandle[i]]);
|
||||
@@ -107,7 +107,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
|
||||
ASSERT_TRUE(pm_v_bool[vhandle[i]]);
|
||||
|
||||
OpenMesh::PropertyManager<
|
||||
OpenMesh::EPropHandleT<bool>, Mesh> pm_e_bool(mesh_, "pm_e_bool2");
|
||||
OpenMesh::EPropHandleT<bool>> pm_e_bool(mesh_, "pm_e_bool2");
|
||||
pm_e_bool.set_range(mesh_.edges(), false);
|
||||
for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end();
|
||||
e_it != f_end; ++e_it)
|
||||
@@ -118,7 +118,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
|
||||
ASSERT_TRUE(pm_e_bool[*e_it]);
|
||||
|
||||
OpenMesh::PropertyManager<
|
||||
OpenMesh::FPropHandleT<bool>, Mesh> pm_f_bool(mesh_, "pm_f_bool2");
|
||||
OpenMesh::FPropHandleT<bool>> pm_f_bool(mesh_, "pm_f_bool2");
|
||||
pm_f_bool.set_range(mesh_.faces(), false);
|
||||
for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end();
|
||||
f_it != f_end; ++f_it)
|
||||
@@ -130,62 +130,6 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ====================================================================
|
||||
* Factory Functions
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
template<typename PropHandle, typename Mesh>
|
||||
bool has_property(const Mesh& _mesh, const std::string& _name) {
|
||||
auto dummy_handle = PropHandle{};
|
||||
return _mesh.get_property_handle(dummy_handle, _name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Temporary property
|
||||
*/
|
||||
TEST_F(OpenMeshPropertyManager, cpp11_temp_property) {
|
||||
using handle_type = OpenMesh::VPropHandleT<int>;
|
||||
const auto prop_name = "pm_v_test_property";
|
||||
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name));
|
||||
|
||||
{
|
||||
auto vprop = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
|
||||
static_cast<void>(vprop); // Unused variable
|
||||
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
|
||||
}
|
||||
|
||||
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name));
|
||||
}
|
||||
|
||||
/*
|
||||
* Two temporary properties on a mesh using the same name and type. The second
|
||||
* (inner) one shadows the first (outer) one instead of aliasing.
|
||||
*/
|
||||
TEST_F(OpenMeshPropertyManager, cpp11_temp_property_shadowing) {
|
||||
auto vh = mesh_.add_vertex({0,0,0}); // Dummy vertex to attach properties to
|
||||
|
||||
using handle_type = OpenMesh::VPropHandleT<int>;
|
||||
const auto prop_name = "pm_v_test_property";
|
||||
|
||||
auto outer_prop = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
|
||||
outer_prop[vh] = 100;
|
||||
ASSERT_EQ(100, outer_prop[vh]);
|
||||
|
||||
{
|
||||
// inner_prop uses same type and name as outer_prop
|
||||
auto inner_prop = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
|
||||
inner_prop[vh] = 200;
|
||||
ASSERT_EQ(200, inner_prop[vh]);
|
||||
// End of scope: inner_prop is removed from mesh_
|
||||
}
|
||||
|
||||
// Ensure outer_prop still exists and its data has not been overwritten by inner_prop
|
||||
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
|
||||
ASSERT_EQ(100, outer_prop[vh]);
|
||||
}
|
||||
|
||||
/*
|
||||
* In sequence:
|
||||
* - add a persistent property to a mesh
|
||||
@@ -196,10 +140,9 @@ TEST_F(OpenMeshPropertyManager, cpp11_temp_property_shadowing) {
|
||||
TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
|
||||
auto vh = mesh_.add_vertex({0,0,0}); // Dummy vertex to attach properties to
|
||||
|
||||
using handle_type = OpenMesh::VPropHandleT<int>;
|
||||
const auto prop_name = "pm_v_test_property";
|
||||
|
||||
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name));
|
||||
ASSERT_FALSE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
|
||||
|
||||
{
|
||||
auto prop = OpenMesh::getOrMakeProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
|
||||
@@ -207,7 +150,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
|
||||
// End of scope, property persists
|
||||
}
|
||||
|
||||
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
|
||||
ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
|
||||
|
||||
{
|
||||
// Since a property of the same name and type already exists, this refers to the existing property.
|
||||
@@ -217,7 +160,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
|
||||
// End of scope, property persists
|
||||
}
|
||||
|
||||
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
|
||||
ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
|
||||
|
||||
{
|
||||
// Acquire non-owning handle to the property, knowing it exists
|
||||
@@ -225,7 +168,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
|
||||
ASSERT_EQ(200, prop[vh]);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
|
||||
ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
|
||||
|
||||
{
|
||||
// Attempt to acquire non-owning handle for a non-existing property
|
||||
@@ -235,7 +178,630 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
|
||||
ASSERT_THROW(code_that_throws(), std::runtime_error);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(has_property<handle_type>(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";
|
||||
}
|
||||
|
||||
{
|
||||
auto prop1 = OpenMesh::MProp<int>(mesh_);
|
||||
*prop1 = 43;
|
||||
auto prop2 = prop1;
|
||||
|
||||
prop2 = prop1;
|
||||
|
||||
prop2 = std::move(prop1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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(static_cast<int>(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(static_cast<int>(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");
|
||||
|
||||
auto prop6 = OpenMesh::Prop<OpenMesh::VertexHandle, int>(mesh_);
|
||||
prop6 = prop1;
|
||||
|
||||
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