Commit aa91a88f authored by Max Lyon's avatar Max Lyon
Browse files

add first version of smart ranges

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