add first version of smart ranges

This commit is contained in:
Max Lyon
2019-09-27 14:12:22 +02:00
parent 011a53e7ba
commit aa91a88f7b
3 changed files with 453 additions and 98 deletions

View File

@@ -45,6 +45,7 @@
#define OPENMESH_POLYCONNECTIVITY_HH #define OPENMESH_POLYCONNECTIVITY_HH
#include <OpenMesh/Core/Mesh/ArrayKernel.hh> #include <OpenMesh/Core/Mesh/ArrayKernel.hh>
#include <OpenMesh/Core/Mesh/SmartRange.hh>
namespace OpenMesh namespace OpenMesh
{ {
@@ -64,6 +65,42 @@ namespace Iterators
class GenericCirculatorT; class GenericCirculatorT;
} }
template <typename RangeTraitT>
class EntityRange;
template<
typename CONTAINER_T,
typename ITER_T,
ITER_T (CONTAINER_T::*begin_fn)() const,
ITER_T (CONTAINER_T::*end_fn)() const>
struct RangeTraitT
{
using CONTAINER_TYPE = CONTAINER_T;
using ITER_TYPE = ITER_T;
static ITER_TYPE begin(const CONTAINER_TYPE& _container) { return (_container.*begin_fn)(); }
static ITER_TYPE end(const CONTAINER_TYPE& _container) { return (_container.*end_fn)(); }
};
template<
typename CONTAINER_T,
typename ITER_T,
typename CENTER_ENTITY_T,
typename TO_ENTITY_T,
ITER_T (CONTAINER_T::*begin_fn)(CENTER_ENTITY_T) const,
ITER_T (CONTAINER_T::*end_fn)(CENTER_ENTITY_T) const>
struct CirculatorRangeTraitT
{
using CONTAINER_TYPE = CONTAINER_T;
using ITER_TYPE = ITER_T;
using CENTER_ENTITY_TYPE = CENTER_ENTITY_T;
using TO_ENTITYE_TYPE = TO_ENTITY_T;
static ITER_TYPE begin(const CONTAINER_TYPE& _container, CENTER_ENTITY_TYPE _ce) { return (_container.*begin_fn)(_ce); }
static ITER_TYPE end(const CONTAINER_TYPE& _container, CENTER_ENTITY_TYPE _ce) { return (_container.*end_fn)(_ce); }
};
/** \brief Connectivity Class for polygonal meshes /** \brief Connectivity Class for polygonal meshes
*/ */
class OPENMESHDLLEXPORT PolyConnectivity : public ArrayKernel class OPENMESHDLLEXPORT PolyConnectivity : public ArrayKernel
@@ -970,122 +1007,104 @@ public:
/** @name Range based iterators and circulators */ /** @name Range based iterators and circulators */
//@{ //@{
/// Generic class for vertex/halfedge/edge/face ranges. typedef EntityRange<RangeTraitT<
template<
typename CONTAINER_TYPE,
typename ITER_TYPE,
ITER_TYPE (CONTAINER_TYPE::*begin_fn)() const,
ITER_TYPE (CONTAINER_TYPE::*end_fn)() const>
class EntityRange {
public:
typedef ITER_TYPE iterator;
typedef ITER_TYPE const_iterator;
explicit EntityRange(CONTAINER_TYPE &container) : container_(container) {}
ITER_TYPE begin() const { return (container_.*begin_fn)(); }
ITER_TYPE end() const { return (container_.*end_fn)(); }
private:
CONTAINER_TYPE &container_;
};
typedef EntityRange<
const PolyConnectivity, const PolyConnectivity,
PolyConnectivity::ConstVertexIter, PolyConnectivity::ConstVertexIter,
&PolyConnectivity::vertices_begin, &PolyConnectivity::vertices_begin,
&PolyConnectivity::vertices_end> ConstVertexRange; &PolyConnectivity::vertices_end>> ConstVertexRange;
typedef EntityRange< typedef EntityRange<RangeTraitT<
const PolyConnectivity, const PolyConnectivity,
PolyConnectivity::ConstVertexIter, PolyConnectivity::ConstVertexIter,
&PolyConnectivity::vertices_sbegin, &PolyConnectivity::vertices_sbegin,
&PolyConnectivity::vertices_end> ConstVertexRangeSkipping; &PolyConnectivity::vertices_end>> ConstVertexRangeSkipping;
typedef EntityRange< typedef EntityRange<RangeTraitT<
const PolyConnectivity, const PolyConnectivity,
PolyConnectivity::ConstHalfedgeIter, PolyConnectivity::ConstHalfedgeIter,
&PolyConnectivity::halfedges_begin, &PolyConnectivity::halfedges_begin,
&PolyConnectivity::halfedges_end> ConstHalfedgeRange; &PolyConnectivity::halfedges_end>> ConstHalfedgeRange;
typedef EntityRange< typedef EntityRange<RangeTraitT<
const PolyConnectivity, const PolyConnectivity,
PolyConnectivity::ConstHalfedgeIter, PolyConnectivity::ConstHalfedgeIter,
&PolyConnectivity::halfedges_sbegin, &PolyConnectivity::halfedges_sbegin,
&PolyConnectivity::halfedges_end> ConstHalfedgeRangeSkipping; &PolyConnectivity::halfedges_end>> ConstHalfedgeRangeSkipping;
typedef EntityRange< typedef EntityRange<RangeTraitT<
const PolyConnectivity, const PolyConnectivity,
PolyConnectivity::ConstEdgeIter, PolyConnectivity::ConstEdgeIter,
&PolyConnectivity::edges_begin, &PolyConnectivity::edges_begin,
&PolyConnectivity::edges_end> ConstEdgeRange; &PolyConnectivity::edges_end>> ConstEdgeRange;
typedef EntityRange< typedef EntityRange<RangeTraitT<
const PolyConnectivity, const PolyConnectivity,
PolyConnectivity::ConstEdgeIter, PolyConnectivity::ConstEdgeIter,
&PolyConnectivity::edges_sbegin, &PolyConnectivity::edges_sbegin,
&PolyConnectivity::edges_end> ConstEdgeRangeSkipping; &PolyConnectivity::edges_end>> ConstEdgeRangeSkipping;
typedef EntityRange< typedef EntityRange<RangeTraitT<
const PolyConnectivity, const PolyConnectivity,
PolyConnectivity::ConstFaceIter, PolyConnectivity::ConstFaceIter,
&PolyConnectivity::faces_begin, &PolyConnectivity::faces_begin,
&PolyConnectivity::faces_end> ConstFaceRange; &PolyConnectivity::faces_end>> ConstFaceRange;
typedef EntityRange< typedef EntityRange<RangeTraitT<
const PolyConnectivity, const PolyConnectivity,
PolyConnectivity::ConstFaceIter, PolyConnectivity::ConstFaceIter,
&PolyConnectivity::faces_sbegin, &PolyConnectivity::faces_sbegin,
&PolyConnectivity::faces_end> ConstFaceRangeSkipping; &PolyConnectivity::faces_end>> ConstFaceRangeSkipping;
/** /**
* @return The vertices as a range object suitable * @return The vertices as a range object suitable
* for C++11 range based for loops. Will skip deleted vertices. * for C++11 range based for loops. Will skip deleted vertices.
*/ */
ConstVertexRangeSkipping vertices() const { return ConstVertexRangeSkipping(*this); } ConstVertexRangeSkipping vertices() const;
/** /**
* @return The vertices as a range object suitable * @return The vertices as a range object suitable
* for C++11 range based for loops. Will include deleted vertices. * for C++11 range based for loops. Will include deleted vertices.
*/ */
ConstVertexRange all_vertices() const { return ConstVertexRange(*this); } ConstVertexRange all_vertices() const;
/** /**
* @return The halfedges as a range object suitable * @return The halfedges as a range object suitable
* for C++11 range based for loops. Will skip deleted halfedges. * for C++11 range based for loops. Will skip deleted halfedges.
*/ */
ConstHalfedgeRangeSkipping halfedges() const { return ConstHalfedgeRangeSkipping(*this); } ConstHalfedgeRangeSkipping halfedges() const;
/** /**
* @return The halfedges as a range object suitable * @return The halfedges as a range object suitable
* for C++11 range based for loops. Will include deleted halfedges. * for C++11 range based for loops. Will include deleted halfedges.
*/ */
ConstHalfedgeRange all_halfedges() const { return ConstHalfedgeRange(*this); } ConstHalfedgeRange all_halfedges() const;
/** /**
* @return The edges as a range object suitable * @return The edges as a range object suitable
* for C++11 range based for loops. Will skip deleted edges. * for C++11 range based for loops. Will skip deleted edges.
*/ */
ConstEdgeRangeSkipping edges() const { return ConstEdgeRangeSkipping(*this); } ConstEdgeRangeSkipping edges() const;
/** /**
* @return The edges as a range object suitable * @return The edges as a range object suitable
* for C++11 range based for loops. Will include deleted edges. * for C++11 range based for loops. Will include deleted edges.
*/ */
ConstEdgeRange all_edges() const { return ConstEdgeRange(*this); } ConstEdgeRange all_edges() const;
/** /**
* @return The faces as a range object suitable * @return The faces as a range object suitable
* for C++11 range based for loops. Will skip deleted faces. * for C++11 range based for loops. Will skip deleted faces.
*/ */
ConstFaceRangeSkipping faces() const { return ConstFaceRangeSkipping(*this); } ConstFaceRangeSkipping faces() const;
/** /**
* @return The faces as a range object suitable * @return The faces as a range object suitable
* for C++11 range based for loops. Will include deleted faces. * for C++11 range based for loops. Will include deleted faces.
*/ */
ConstFaceRange all_faces() const { return ConstFaceRange(*this); } ConstFaceRange all_faces() const;
/// Generic class for iterator ranges. /// Generic class for iterator ranges.
template< template <typename CirculatorRangeTraitT>
typename CONTAINER_TYPE, class CirculatorRange : public SmartRangeT<CirculatorRange<CirculatorRangeTraitT>, typename CirculatorRangeTraitT::TO_ENTITYE_TYPE>{
typename ITER_TYPE,
typename CENTER_ENTITY_TYPE,
ITER_TYPE (CONTAINER_TYPE::*begin_fn)(CENTER_ENTITY_TYPE) const,
ITER_TYPE (CONTAINER_TYPE::*end_fn)(CENTER_ENTITY_TYPE) const>
class CirculatorRange {
public: public:
typedef typename CirculatorRangeTraitT::ITER_TYPE ITER_TYPE;
typedef typename CirculatorRangeTraitT::CENTER_ENTITY_TYPE CENTER_ENTITY_TYPE;
typedef typename CirculatorRangeTraitT::CONTAINER_TYPE CONTAINER_TYPE;
typedef ITER_TYPE iterator; typedef ITER_TYPE iterator;
typedef ITER_TYPE const_iterator; typedef ITER_TYPE const_iterator;
@@ -1093,139 +1112,132 @@ public:
const CONTAINER_TYPE &container, const CONTAINER_TYPE &container,
CENTER_ENTITY_TYPE center) : CENTER_ENTITY_TYPE center) :
container_(container), center_(center) {} container_(container), center_(center) {}
ITER_TYPE begin() const { return (container_.*begin_fn)(center_); } ITER_TYPE begin() const { return CirculatorRangeTraitT::begin(container_, center_); }
ITER_TYPE end() const { return (container_.*end_fn)(center_); } ITER_TYPE end() const { return CirculatorRangeTraitT::end(container_, center_); }
private: private:
const CONTAINER_TYPE &container_; const CONTAINER_TYPE &container_;
CENTER_ENTITY_TYPE center_; CENTER_ENTITY_TYPE center_;
}; };
typedef CirculatorRange<
typedef CirculatorRange<CirculatorRangeTraitT<
PolyConnectivity, PolyConnectivity,
ConstVertexVertexCWIter, ConstVertexVertexCWIter,
VertexHandle, VertexHandle,
VertexHandle,
&PolyConnectivity::cvv_cwbegin, &PolyConnectivity::cvv_cwbegin,
&PolyConnectivity::cvv_cwend> ConstVertexVertexRange; &PolyConnectivity::cvv_cwend>> ConstVertexVertexRange;
typedef CirculatorRange< typedef CirculatorRange<CirculatorRangeTraitT<
PolyConnectivity, PolyConnectivity,
ConstVertexIHalfedgeIter, ConstVertexIHalfedgeIter,
VertexHandle, VertexHandle,
HalfedgeHandle,
&PolyConnectivity::cvih_begin, &PolyConnectivity::cvih_begin,
&PolyConnectivity::cvih_end> ConstVertexIHalfedgeRange; &PolyConnectivity::cvih_end>> ConstVertexIHalfedgeRange;
typedef CirculatorRange< typedef CirculatorRange<CirculatorRangeTraitT<
PolyConnectivity, PolyConnectivity,
ConstVertexOHalfedgeIter, VertexHandle, ConstVertexOHalfedgeIter,
VertexHandle,
HalfedgeHandle,
&PolyConnectivity::cvoh_begin, &PolyConnectivity::cvoh_begin,
&PolyConnectivity::cvoh_end> ConstVertexOHalfedgeRange; &PolyConnectivity::cvoh_end>> ConstVertexOHalfedgeRange;
typedef CirculatorRange< typedef CirculatorRange<CirculatorRangeTraitT<
PolyConnectivity, PolyConnectivity,
ConstVertexEdgeIter, ConstVertexEdgeIter,
VertexHandle, VertexHandle,
EdgeHandle,
&PolyConnectivity::cve_begin, &PolyConnectivity::cve_begin,
&PolyConnectivity::cve_end> ConstVertexEdgeRange; &PolyConnectivity::cve_end>> ConstVertexEdgeRange;
typedef CirculatorRange< typedef CirculatorRange<CirculatorRangeTraitT<
PolyConnectivity, PolyConnectivity,
ConstVertexFaceIter, ConstVertexFaceIter,
VertexHandle, VertexHandle,
FaceHandle,
&PolyConnectivity::cvf_begin, &PolyConnectivity::cvf_begin,
&PolyConnectivity::cvf_end> ConstVertexFaceRange; &PolyConnectivity::cvf_end>> ConstVertexFaceRange;
typedef CirculatorRange< typedef CirculatorRange<CirculatorRangeTraitT<
PolyConnectivity, PolyConnectivity,
ConstFaceVertexIter, ConstFaceVertexIter,
FaceHandle, FaceHandle,
VertexHandle,
&PolyConnectivity::cfv_begin, &PolyConnectivity::cfv_begin,
&PolyConnectivity::cfv_end> ConstFaceVertexRange; &PolyConnectivity::cfv_end>> ConstFaceVertexRange;
typedef CirculatorRange< typedef CirculatorRange<CirculatorRangeTraitT<
PolyConnectivity, PolyConnectivity,
ConstFaceHalfedgeIter, ConstFaceHalfedgeIter,
FaceHandle, FaceHandle,
HalfedgeHandle,
&PolyConnectivity::cfh_begin, &PolyConnectivity::cfh_begin,
&PolyConnectivity::cfh_end> ConstFaceHalfedgeRange; &PolyConnectivity::cfh_end>> ConstFaceHalfedgeRange;
typedef CirculatorRange< typedef CirculatorRange<CirculatorRangeTraitT<
PolyConnectivity, PolyConnectivity,
ConstFaceEdgeIter, ConstFaceEdgeIter,
FaceHandle, FaceHandle,
EdgeHandle,
&PolyConnectivity::cfe_begin, &PolyConnectivity::cfe_begin,
&PolyConnectivity::cfe_end> ConstFaceEdgeRange; &PolyConnectivity::cfe_end>> ConstFaceEdgeRange;
typedef CirculatorRange< typedef CirculatorRange<CirculatorRangeTraitT<
PolyConnectivity, PolyConnectivity,
ConstFaceFaceIter, ConstFaceFaceIter,
FaceHandle, FaceHandle,
FaceHandle,
&PolyConnectivity::cff_begin, &PolyConnectivity::cff_begin,
&PolyConnectivity::cff_end> ConstFaceFaceRange; &PolyConnectivity::cff_end>> ConstFaceFaceRange;
/** /**
* @return The vertices adjacent to the specified vertex * @return The vertices adjacent to the specified vertex
* as a range object suitable for C++11 range based for loops. * as a range object suitable for C++11 range based for loops.
*/ */
ConstVertexVertexRange vv_range(VertexHandle _vh) const { ConstVertexVertexRange vv_range(VertexHandle _vh) const;
return ConstVertexVertexRange(*this, _vh);
}
/** /**
* @return The incoming halfedges incident to the specified vertex * @return The incoming halfedges incident to the specified vertex
* as a range object suitable for C++11 range based for loops. * as a range object suitable for C++11 range based for loops.
*/ */
ConstVertexIHalfedgeRange vih_range(VertexHandle _vh) const { ConstVertexIHalfedgeRange vih_range(VertexHandle _vh) const;
return ConstVertexIHalfedgeRange(*this, _vh);
}
/** /**
* @return The outgoing halfedges incident to the specified vertex * @return The outgoing halfedges incident to the specified vertex
* as a range object suitable for C++11 range based for loops. * as a range object suitable for C++11 range based for loops.
*/ */
ConstVertexOHalfedgeRange voh_range(VertexHandle _vh) const { ConstVertexOHalfedgeRange voh_range(VertexHandle _vh) const;
return ConstVertexOHalfedgeRange(*this, _vh);
}
/** /**
* @return The edges incident to the specified vertex * @return The edges incident to the specified vertex
* as a range object suitable for C++11 range based for loops. * as a range object suitable for C++11 range based for loops.
*/ */
ConstVertexEdgeRange ve_range(VertexHandle _vh) const { ConstVertexEdgeRange ve_range(VertexHandle _vh) const ;
return ConstVertexEdgeRange(*this, _vh);
}
/** /**
* @return The faces incident to the specified vertex * @return The faces incident to the specified vertex
* as a range object suitable for C++11 range based for loops. * as a range object suitable for C++11 range based for loops.
*/ */
ConstVertexFaceRange vf_range(VertexHandle _vh) const { ConstVertexFaceRange vf_range(VertexHandle _vh) const;
return ConstVertexFaceRange(*this, _vh);
}
/** /**
* @return The vertices incident to the specified face * @return The vertices incident to the specified face
* as a range object suitable for C++11 range based for loops. * as a range object suitable for C++11 range based for loops.
*/ */
ConstFaceVertexRange fv_range(FaceHandle _fh) const { ConstFaceVertexRange fv_range(FaceHandle _fh) const;
return ConstFaceVertexRange(*this, _fh);
}
/** /**
* @return The halfedges incident to the specified face * @return The halfedges incident to the specified face
* as a range object suitable for C++11 range based for loops. * as a range object suitable for C++11 range based for loops.
*/ */
ConstFaceHalfedgeRange fh_range(FaceHandle _fh) const { ConstFaceHalfedgeRange fh_range(FaceHandle _fh) const;
return ConstFaceHalfedgeRange(*this, _fh);
}
/** /**
* @return The edges incident to the specified face * @return The edges incident to the specified face
* as a range object suitable for C++11 range based for loops. * as a range object suitable for C++11 range based for loops.
*/ */
ConstFaceEdgeRange fe_range(FaceHandle _fh) const { ConstFaceEdgeRange fe_range(FaceHandle _fh) const;
return ConstFaceEdgeRange(*this, _fh);
}
/** /**
* @return The faces adjacent to the specified face * @return The faces adjacent to the specified face
* as a range object suitable for C++11 range based for loops. * as a range object suitable for C++11 range based for loops.
*/ */
ConstFaceFaceRange ff_range(FaceHandle _fh) const { ConstFaceFaceRange ff_range(FaceHandle _fh) const;
return ConstFaceFaceRange(*this, _fh);
}
//@} //@}
@@ -1487,11 +1499,74 @@ private: // Working storage for add_face()
}//namespace OpenMesh }//namespace OpenMesh
#include <OpenMesh/Core/Mesh/IteratorsT.hh> #include <OpenMesh/Core/Mesh/IteratorsT.hh>
#include <OpenMesh/Core/Mesh/CirculatorsT.hh> #include <OpenMesh/Core/Mesh/CirculatorsT.hh>
namespace OpenMesh { namespace OpenMesh {
/// Generic class for vertex/halfedge/edge/face ranges.
template <typename RangeTraitT>
class EntityRange : public SmartRangeT<EntityRange<RangeTraitT>, typename RangeTraitT::ITER_TYPE::value_handle> {
public:
typedef typename RangeTraitT::ITER_TYPE iterator;
typedef typename RangeTraitT::ITER_TYPE const_iterator;
explicit EntityRange(typename RangeTraitT::CONTAINER_TYPE &container) : container_(container) {}
typename RangeTraitT::ITER_TYPE begin() const { return RangeTraitT::begin(container_); }
typename RangeTraitT::ITER_TYPE end() const { return RangeTraitT::end(container_); }
private:
typename RangeTraitT::CONTAINER_TYPE &container_;
};
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); }
inline PolyConnectivity::ConstHalfedgeRange PolyConnectivity::all_halfedges() const { return ConstHalfedgeRange(*this); }
inline PolyConnectivity::ConstEdgeRangeSkipping PolyConnectivity::edges() const { return ConstEdgeRangeSkipping(*this); }
inline PolyConnectivity::ConstEdgeRange PolyConnectivity::all_edges() const { return ConstEdgeRange(*this); }
inline PolyConnectivity::ConstFaceRangeSkipping PolyConnectivity::faces() const { return ConstFaceRangeSkipping(*this); }
inline PolyConnectivity::ConstFaceRange PolyConnectivity::all_faces() const { return ConstFaceRange(*this); }
inline PolyConnectivity::ConstVertexVertexRange PolyConnectivity::vv_range(VertexHandle _vh) const {
return ConstVertexVertexRange(*this, _vh);
}
inline PolyConnectivity::ConstVertexIHalfedgeRange PolyConnectivity::vih_range(VertexHandle _vh) const {
return ConstVertexIHalfedgeRange(*this, _vh);
}
inline PolyConnectivity::ConstVertexOHalfedgeRange PolyConnectivity::voh_range(VertexHandle _vh) const {
return ConstVertexOHalfedgeRange(*this, _vh);
}
inline PolyConnectivity::ConstVertexEdgeRange PolyConnectivity::ve_range(VertexHandle _vh) const {
return ConstVertexEdgeRange(*this, _vh);
}
inline PolyConnectivity::ConstVertexFaceRange PolyConnectivity::vf_range(VertexHandle _vh) const {
return ConstVertexFaceRange(*this, _vh);
}
inline PolyConnectivity::ConstFaceVertexRange PolyConnectivity::fv_range(FaceHandle _fh) const {
return ConstFaceVertexRange(*this, _fh);
}
inline PolyConnectivity::ConstFaceHalfedgeRange PolyConnectivity::fh_range(FaceHandle _fh) const {
return ConstFaceHalfedgeRange(*this, _fh);
}
inline PolyConnectivity::ConstFaceEdgeRange PolyConnectivity::fe_range(FaceHandle _fh) const {
return ConstFaceEdgeRange(*this, _fh);
}
inline PolyConnectivity::ConstFaceFaceRange PolyConnectivity::ff_range(FaceHandle _fh) const {
return ConstFaceFaceRange(*this, _fh);
}
inline PolyConnectivity::VertexIter PolyConnectivity::vertices_begin() inline PolyConnectivity::VertexIter PolyConnectivity::vertices_begin()
{ return VertexIter(*this, VertexHandle(0)); } { return VertexIter(*this, VertexHandle(0)); }

View File

@@ -0,0 +1,84 @@
/* ========================================================================= *
* *
* 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. *
* *
* ========================================================================= */
#pragma once
#include <utility>
//== NAMESPACES ===============================================================
namespace OpenMesh {
//== FORWARD DECLARATION ======================================================
//== CLASS DEFINITION =========================================================
/// Base class for all smart range types
template <typename RangeT, typename HandleT>
struct SmartRangeT
{
// TODO: Someone with better c++ knowledge may improve the code below.
template <typename Functor>
auto sum(Functor f) -> decltype (f(std::declval<HandleT>())+f(std::declval<HandleT>()))
{
auto range = static_cast<const RangeT*>(this);
auto begin = range->begin();
auto end = range->end();
assert(begin != end);
decltype (f(*begin) + f(*begin)) sum = f(*begin);
auto it = begin;
++it;
for (; it != end; ++it)
sum += f(*it);
return sum;
}
};
//=============================================================================
} // namespace OpenMesh
//=============================================================================
//=============================================================================

View File

@@ -0,0 +1,196 @@
#include <gtest/gtest.h>
#include <Unittests/unittests_common.hh>
#include <OpenMesh/Core/Mesh/SmartHandles.hh>
#include <iostream>
#include <chrono>
namespace {
class OpenMeshSmartRanges : public OpenMeshBase {
protected:
// This function is called before each test is run
virtual void SetUp() {
mesh_.clear();
// Add some vertices
Mesh::VertexHandle vhandle[8];
vhandle[0] = mesh_.add_vertex(Mesh::Point(-1, -1, 1));
vhandle[1] = mesh_.add_vertex(Mesh::Point( 1, -1, 1));
vhandle[2] = mesh_.add_vertex(Mesh::Point( 1, 1, 1));
vhandle[3] = mesh_.add_vertex(Mesh::Point(-1, 1, 1));
vhandle[4] = mesh_.add_vertex(Mesh::Point(-1, -1, -1));
vhandle[5] = mesh_.add_vertex(Mesh::Point( 1, -1, -1));
vhandle[6] = mesh_.add_vertex(Mesh::Point( 1, 1, -1));
vhandle[7] = mesh_.add_vertex(Mesh::Point(-1, 1, -1));
// Add six faces to form a cube
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[6]);
face_vhandles.push_back(vhandle[5]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[5]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[5]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[6]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
// Test setup:
//
//
// 3 ======== 2
// / /|
// / / | z
// 0 ======== 1 | |
// | | | | y
// | 7 | 6 | /
// | | / | /
// | |/ |/
// 4 ======== 5 -------> x
//
// Check setup
EXPECT_EQ(18u, mesh_.n_edges() ) << "Wrong number of Edges";
EXPECT_EQ(36u, mesh_.n_halfedges() ) << "Wrong number of HalfEdges";
EXPECT_EQ(8u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(12u, mesh_.n_faces() ) << "Wrong number of faces";
}
// This function is called after all tests are through
virtual void TearDown() {
// Do some final stuff with the member data here...
mesh_.clear();
}
// Member already defined in OpenMeshBase
//Mesh mesh_;
};
/*
* ====================================================================
* Define tests below
* ====================================================================
*/
template <typename HandleT>
struct F
{
int operator()(HandleT ) { return 1; }
};
/* Test if smart ranges work
*/
TEST_F(OpenMeshSmartRanges, Sum)
{
auto one = [](OpenMesh::VertexHandle ) { return 1; };
EXPECT_EQ(mesh_.vertices().sum(one), mesh_.n_vertices());
EXPECT_EQ(mesh_.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.n_vertices());
EXPECT_EQ(mesh_.halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.n_halfedges());
EXPECT_EQ(mesh_.edges().sum(F<OpenMesh::EdgeHandle>()), mesh_.n_edges());
EXPECT_EQ(mesh_.faces().sum(F<OpenMesh::FaceHandle>()), mesh_.n_faces());
for (auto vh : mesh_.vertices())
EXPECT_EQ(vh.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.valence(vh));
for (auto vh : mesh_.vertices())
EXPECT_EQ(vh.faces().sum(F<OpenMesh::FaceHandle>()), mesh_.valence(vh));
for (auto vh : mesh_.vertices())
EXPECT_EQ(vh.outgoing_halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(vh));
for (auto vh : mesh_.vertices())
EXPECT_EQ(vh.incoming_halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(vh));
for (auto fh : mesh_.faces())
EXPECT_EQ(fh.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.valence(fh));
for (auto fh : mesh_.faces())
EXPECT_EQ(fh.halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(fh));
for (auto fh : mesh_.faces())
EXPECT_EQ(fh.edges().sum(F<OpenMesh::EdgeHandle>()), mesh_.valence(fh));
for (auto fh : mesh_.faces())
EXPECT_EQ(fh.faces().sum(F<OpenMesh::FaceHandle>()), 3);
}
}