Merge branch 'master' into Unittest_space_bool

This commit is contained in:
Jan Möbius
2020-11-16 13:13:33 +01:00
14 changed files with 1070 additions and 93 deletions

View File

@@ -451,32 +451,7 @@ _STLReader_::
check_stl_type(const std::string& _filename) const
{
// open file
std::ifstream ifs (_filename.c_str(), std::ifstream::binary);
if(!ifs.good())
{
omerr() << "could not open file" << _filename << std::endl;
return NONE;
}
//find first non whitespace character
std::string line = "";
std::size_t firstChar;
while(line.empty() && ifs.good())
{
std::getline(ifs,line);
firstChar = line.find_first_not_of("\t ");
}
//check for ascii keyword solid
if(strnicmp("solid",&line[firstChar],5) == 0)
{
return STLA;
}
ifs.close();
//if the file does not start with solid it is probably STLB
//check the file size to verify it.
// Check the file size if it matches the binary value given after the header.
//open the file
FILE* in = fopen(_filename.c_str(), "rb");
@@ -493,7 +468,6 @@ check_stl_type(const std::string& _filename) const
fread(dummy, 1, 80, in);
size_t nT = read_int(in, swapFlag);
// compute file size from nT
size_t binary_size = 84 + nT*50;
@@ -504,8 +478,8 @@ check_stl_type(const std::string& _filename) const
file_size += fread(dummy, 1, 100, in);
fclose(in);
// if sizes match -> it's STLB
return (binary_size == file_size ? STLB : NONE);
// if sizes match -> it's STLB otherwise STLA is assumed
return (binary_size == file_size ? STLB : STLA);
}

View File

@@ -43,6 +43,8 @@
#error Do not include this directly, include instead PolyConnectivity.hh
#endif//OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE
#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
//== NAMESPACES ===============================================================
namespace OpenMesh {
@@ -73,8 +75,38 @@ private:
};
/// Base class for all smart handle types that contains status related methods
template <typename HandleType>
class SmartHandleStatusPredicates
{
public:
/// Returns true iff the handle is marked as feature
bool feature() const;
/// Returns true iff the handle is marked as selected
bool selected() const;
/// Returns true iff the handle is marked as tagged
bool tagged() const;
/// Returns true iff the handle is marked as tagged2
bool tagged2() const;
/// Returns true iff the handle is marked as locked
bool locked() const;
/// Returns true iff the handle is marked as hidden
bool hidden() const;
/// Returns true iff the handle is marked as deleted
bool deleted() const;
};
/// Base class for all smart handle types that contains status related methods
template <typename HandleType>
class SmartHandleBoundaryPredicate
{
public:
/// Returns true iff the handle is boundary
bool is_boundary() const;
};
/// Smart version of VertexHandle contains a pointer to the corresponding mesh and allows easier access to navigation methods
struct OPENMESHDLLEXPORT SmartVertexHandle : public SmartBaseHandle, VertexHandle
struct OPENMESHDLLEXPORT SmartVertexHandle : public SmartBaseHandle, VertexHandle, SmartHandleStatusPredicates<SmartVertexHandle>, SmartHandleBoundaryPredicate<SmartVertexHandle>
{
explicit SmartVertexHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), VertexHandle(_idx) {}
@@ -98,13 +130,11 @@ struct OPENMESHDLLEXPORT SmartVertexHandle : public SmartBaseHandle, VertexHandl
/// Returns valence of the vertex
uint valence() const;
/// Returns true iff the vertex is incident to a boundary halfedge
bool is_boundary() const;
/// Returns true iff (the mesh at) the vertex is two-manifold ?
bool is_manifold() const;
};
struct OPENMESHDLLEXPORT SmartHalfedgeHandle : public SmartBaseHandle, HalfedgeHandle
struct OPENMESHDLLEXPORT SmartHalfedgeHandle : public SmartBaseHandle, HalfedgeHandle, SmartHandleStatusPredicates<SmartHalfedgeHandle>, SmartHandleBoundaryPredicate<SmartHalfedgeHandle>
{
explicit SmartHalfedgeHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), HalfedgeHandle(_idx) {}
@@ -125,12 +155,9 @@ struct OPENMESHDLLEXPORT SmartHalfedgeHandle : public SmartBaseHandle, HalfedgeH
/// Returns a range of halfedges in the face of the halfedge (or along the boundary) (PolyConnectivity::hl_range())
PolyConnectivity::ConstHalfedgeLoopRange loop() const;
/// Returns true iff the halfedge is on the boundary (i.e. it has no corresponding face)
bool is_boundary() const;
};
struct OPENMESHDLLEXPORT SmartEdgeHandle : public SmartBaseHandle, EdgeHandle
struct OPENMESHDLLEXPORT SmartEdgeHandle : public SmartBaseHandle, EdgeHandle, SmartHandleStatusPredicates<SmartEdgeHandle>, SmartHandleBoundaryPredicate<SmartEdgeHandle>
{
explicit SmartEdgeHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), EdgeHandle(_idx) {}
@@ -150,12 +177,9 @@ struct OPENMESHDLLEXPORT SmartEdgeHandle : public SmartBaseHandle, EdgeHandle
SmartVertexHandle v0() const;
/// Shorthand for vertex(1)
SmartVertexHandle v1() const;
/// Returns true iff the edge lies on the boundary (i.e. one of the halfedges is boundary)
bool is_boundary() const;
};
struct OPENMESHDLLEXPORT SmartFaceHandle : public SmartBaseHandle, FaceHandle
struct OPENMESHDLLEXPORT SmartFaceHandle : public SmartBaseHandle, FaceHandle, SmartHandleStatusPredicates<SmartFaceHandle>, SmartHandleBoundaryPredicate<SmartFaceHandle>
{
explicit SmartFaceHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), FaceHandle(_idx) {}
@@ -173,8 +197,6 @@ struct OPENMESHDLLEXPORT SmartFaceHandle : public SmartBaseHandle, FaceHandle
/// Returns the valence of the face
uint valence() const;
/// Returns true iff the face lies at the boundary (i.e. one of the edges is boundary)
bool is_boundary() const;
};
@@ -207,6 +229,70 @@ template <> struct SmartHandle<EdgeHandle> { using type = SmartEdgeHandle;
template <> struct SmartHandle<FaceHandle> { using type = SmartFaceHandle; };
template <typename HandleType>
inline bool SmartHandleStatusPredicates<HandleType>::feature() const
{
const auto& handle = static_cast<const HandleType&>(*this);
assert(handle.mesh() != nullptr);
return handle.mesh()->status(handle).feature();
}
template <typename HandleType>
inline bool SmartHandleStatusPredicates<HandleType>::selected() const
{
const auto& handle = static_cast<const HandleType&>(*this);
assert(handle.mesh() != nullptr);
return handle.mesh()->status(handle).selected();
}
template <typename HandleType>
inline bool SmartHandleStatusPredicates<HandleType>::tagged() const
{
const auto& handle = static_cast<const HandleType&>(*this);
assert(handle.mesh() != nullptr);
return handle.mesh()->status(handle).tagged();
}
template <typename HandleType>
inline bool SmartHandleStatusPredicates<HandleType>::tagged2() const
{
const auto& handle = static_cast<const HandleType&>(*this);
assert(handle.mesh() != nullptr);
return handle.mesh()->status(handle).tagged2();
}
template <typename HandleType>
inline bool SmartHandleStatusPredicates<HandleType>::locked() const
{
const auto& handle = static_cast<const HandleType&>(*this);
assert(handle.mesh() != nullptr);
return handle.mesh()->status(handle).locked();
}
template <typename HandleType>
inline bool SmartHandleStatusPredicates<HandleType>::hidden() const
{
const auto& handle = static_cast<const HandleType&>(*this);
assert(handle.mesh() != nullptr);
return handle.mesh()->status(handle).hidden();
}
template <typename HandleType>
inline bool SmartHandleStatusPredicates<HandleType>::deleted() const
{
const auto& handle = static_cast<const HandleType&>(*this);
assert(handle.mesh() != nullptr);
return handle.mesh()->status(handle).deleted();
}
template <typename HandleType>
inline bool SmartHandleBoundaryPredicate<HandleType>::is_boundary() const
{
const auto& handle = static_cast<const HandleType&>(*this);
assert(handle.mesh() != nullptr);
return handle.mesh()->is_boundary(handle);
}
inline SmartHalfedgeHandle SmartVertexHandle::out() const
{
assert(mesh() != nullptr);
@@ -229,12 +315,6 @@ inline uint SmartVertexHandle::valence() const
return mesh()->valence(*this);
}
inline bool SmartVertexHandle::is_boundary() const
{
assert(mesh() != nullptr);
return mesh()->is_boundary(*this);
}
inline bool SmartVertexHandle::is_manifold() const
{
assert(mesh() != nullptr);
@@ -283,12 +363,6 @@ inline SmartFaceHandle SmartHalfedgeHandle::face() const
return make_smart(mesh()->face_handle(*this), mesh());
}
inline bool SmartHalfedgeHandle::is_boundary() const
{
assert(mesh() != nullptr);
return mesh()->is_boundary(*this);
}
inline SmartHalfedgeHandle SmartEdgeHandle::halfedge(unsigned int _i) const
{
assert(mesh() != nullptr);
@@ -330,12 +404,6 @@ inline SmartVertexHandle SmartEdgeHandle::v1() const
return v(1);
}
inline bool SmartEdgeHandle::is_boundary() const
{
assert(mesh() != nullptr);
return mesh()->is_boundary(*this);
}
inline SmartHalfedgeHandle SmartFaceHandle::halfedge() const
{
assert(mesh() != nullptr);
@@ -348,11 +416,6 @@ inline uint SmartFaceHandle::valence() const
return mesh()->valence(*this);
}
inline bool SmartFaceHandle::is_boundary() const
{
assert(mesh() != nullptr);
return mesh()->is_boundary(*this);
}
//=============================================================================
} // namespace OpenMesh
//=============================================================================

View File

@@ -428,27 +428,10 @@ struct SmartRangeT
* @param f Functor that needs to be evaluated to true if the element should not be skipped.
*/
template <typename Functor>
auto filtered(Functor&& f) -> FilteredSmartRangeT<SmartRange, Handle, typename std::decay<Functor>::type>
auto filtered(Functor&& f) -> FilteredSmartRangeT<SmartRange, Handle, Functor>
{
auto range = static_cast<const RangeT*>(this);
auto b = (*range).begin();
auto e = (*range).end();
return FilteredSmartRangeT<SmartRange, Handle, typename std::decay<Functor>::type>(f, b, e);
}
/** @brief Only iterate over a subset of elements
*
* Returns a smart range which skips all elements that do not satisfy functor \p f
*
* @param f Functor that needs to be evaluated to true if the element should not be skipped.
*/
template <typename Functor>
auto filtered(Functor& f) -> FilteredSmartRangeT<SmartRange, Handle, const typename std::decay<Functor>::type&>
{
auto range = static_cast<const RangeT*>(this);
auto b = (*range).begin();
auto e = (*range).end();
return FilteredSmartRangeT<SmartRange, Handle, const typename std::decay<Functor>::type&>(f, b, e);
return FilteredSmartRangeT<SmartRange, Handle, Functor>(std::forward<Functor>(f), (*range).begin(), (*range).end());
}
};
@@ -488,11 +471,12 @@ struct FilteredSmartRangeT : public SmartRangeT<FilteredSmartRangeT<RangeT, Hand
return *this;
}
Functor f_;
Functor f_; // Should iterators always get a reference to filter stored in range?
// Should iterators stay valid after range goes out of scope?
BaseIterator end_;
};
FilteredSmartRangeT(Functor f, BaseIterator begin, BaseIterator end) : f_(f), begin_(begin), end_(end){}
FilteredSmartRangeT(Functor&& f, BaseIterator begin, BaseIterator end) : f_(std::forward<Functor>(f)), begin_(std::move(begin)), end_(std::move(end)){}
FilteredIterator begin() const { return FilteredIterator(f_, begin_, end_); }
FilteredIterator end() const { return FilteredIterator(f_, end_, end_); }

View File

@@ -0,0 +1,293 @@
/* ========================================================================= *
* *
* OpenMesh *
* Copyright (c) 2001-2020, 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 <OpenMesh/Core/Mesh/PolyConnectivity.hh>
#include <OpenMesh/Core/Utils/PropertyManager.hh>
#include <utility>
#include <array>
#include <vector>
#include <set>
#include <type_traits>
//== NAMESPACES ===============================================================
namespace OpenMesh {
namespace Predicates {
//== FORWARD DECLARATION ======================================================
//== CLASS DEFINITION =========================================================
template <typename PredicateT>
struct PredicateBase
{
};
template <typename PredicateT>
struct Predicate : public PredicateBase<Predicate<PredicateT>>
{
Predicate(PredicateT _p)
:
p_(_p)
{}
template <typename T>
bool operator()(const T& _t) const { return p_(_t); }
PredicateT p_;
};
template <typename PredicateT>
Predicate<const PredicateT&> make_predicate(PredicateT& _p) { return { _p }; }
template <typename PredicateT>
Predicate<PredicateT> make_predicate(PredicateT&& _p) { return { _p }; }
template <typename Predicate1T, typename Predicate2T>
struct Disjunction : public PredicateBase<Disjunction<Predicate1T, Predicate2T>>
{
Disjunction(Predicate1T _p1, Predicate2T _p2)
:
p1_(_p1),
p2_(_p2)
{}
template <typename T>
bool operator()(const T& _t) const { return p1_( _t) || p2_( _t); }
Predicate1T p1_;
Predicate2T p2_;
};
template <typename Predicate1T, typename Predicate2T>
struct Conjunction : public PredicateBase<Conjunction<Predicate1T, Predicate2T>>
{
Conjunction(Predicate1T _p1, Predicate2T _p2)
:
p1_(_p1),
p2_(_p2)
{}
template <typename T>
bool operator()(const T& _t) const { return p1_( _t) && p2_( _t); }
Predicate1T p1_;
Predicate2T p2_;
};
template <typename PredicateT>
struct Negation : public PredicateBase<Negation<PredicateT>>
{
Negation(const PredicateT& _p1)
:
p1_(_p1)
{}
template <typename T>
bool operator()(const T& _t) const { return !p1_( _t); }
PredicateT p1_;
};
template <typename P1, typename P2>
Disjunction<const P1&, const P2&> operator||(PredicateBase<P1>& p1, PredicateBase<P2>& p2)
{
return Disjunction<const P1&, const P2&>(static_cast<const P1&>(p1), static_cast<const P2&>(p2));
}
template <typename P1, typename P2>
Disjunction<const P1&, P2> operator||(PredicateBase<P1>& p1, PredicateBase<P2>&& p2)
{
return Disjunction<const P1&, P2>(static_cast<const P1&>(p1), static_cast<P2&&>(p2));
}
template <typename P1, typename P2>
Disjunction<P1, const P2&> operator||(PredicateBase<P1>&& p1, PredicateBase<P2>& p2)
{
return Disjunction<P1, const P2&>(static_cast<P1&&>(p1), static_cast<const P2&>(p2));
}
template <typename P1, typename P2>
Disjunction<P1, P2> operator||(PredicateBase<P1>&& p1, PredicateBase<P2>&& p2)
{
return Disjunction<P1, P2>(static_cast<P1&&>(p1), static_cast<P2&&>(p2));
}
template <typename P1, typename P2>
Conjunction<const P1&, const P2&> operator&&(PredicateBase<P1>& p1, PredicateBase<P2>& p2)
{
return Conjunction<const P1&, const P2&>(static_cast<const P1&>(p1), static_cast<const P2&>(p2));
}
template <typename P1, typename P2>
Conjunction<const P1&, P2> operator&&(PredicateBase<P1>& p1, PredicateBase<P2>&& p2)
{
return Conjunction<const P1&, P2>(static_cast<const P1&>(p1), static_cast<P2&&>(p2));
}
template <typename P1, typename P2>
Conjunction<P1, const P2&> operator&&(PredicateBase<P1>&& p1, PredicateBase<P2>& p2)
{
return Conjunction<P1, const P2&>(static_cast<P1>(p1), static_cast<const P2&>(p2));
}
template <typename P1, typename P2>
Conjunction<P1, P2> operator&&(PredicateBase<P1>&& p1, PredicateBase<P2>&& p2)
{
return Conjunction<P1, P2>(static_cast<P1&&>(p1), static_cast<P2&&>(p2));
}
template <typename P>
Negation<const P&> operator!(PredicateBase<P>& p)
{
return Negation<const P&>(static_cast<const P&>(p));
}
template <typename P>
Negation<P> operator!(PredicateBase<P>&& p)
{
return Negation<P>(static_cast<P&&>(p));
}
struct Feature : public PredicateBase<Feature>
{
template <typename HandleType>
bool operator()(const SmartHandleStatusPredicates<HandleType>& _h) const { return _h.feature(); }
};
struct Selected : public PredicateBase<Selected>
{
template <typename HandleType>
bool operator()(const SmartHandleStatusPredicates<HandleType>& _h) const { return _h.selected(); }
};
struct Tagged : public PredicateBase<Tagged>
{
template <typename HandleType>
bool operator()(const SmartHandleStatusPredicates<HandleType>& _h) const { return _h.tagged(); }
};
struct Tagged2 : public PredicateBase<Tagged2>
{
template <typename HandleType>
bool operator()(const SmartHandleStatusPredicates<HandleType>& _h) const { return _h.tagged2(); }
};
struct Locked : public PredicateBase<Locked>
{
template <typename HandleType>
bool operator()(const SmartHandleStatusPredicates<HandleType>& _h) const { return _h.locked(); }
};
struct Hidden : public PredicateBase<Hidden>
{
template <typename HandleType>
bool operator()(const SmartHandleStatusPredicates<HandleType>& _h) const { return _h.hidden(); }
};
struct Deleted : public PredicateBase<Deleted>
{
template <typename HandleType>
bool operator()(const SmartHandleStatusPredicates<HandleType>& _h) const { return _h.deleted(); }
};
struct Boundary : public PredicateBase<Boundary>
{
template <typename HandleType>
bool operator()(const SmartHandleBoundaryPredicate<HandleType>& _h) const { return _h.is_boundary(); }
};
template <int inner_reg, int boundary_reg>
struct Regular: public PredicateBase<Regular<inner_reg, boundary_reg>>
{
bool operator()(const SmartVertexHandle& _vh) const { return _vh.valence() == (_vh.is_boundary() ? boundary_reg : inner_reg); }
};
using RegularQuad = Regular<4,3>;
using RegularTri = Regular<6,4>;
/// Wrapper object to hold an object and a member function pointer,
/// and provides operator() to call that member function for that object with one argument
template <typename T, typename MF>
struct MemberFunctionWrapper
{
T t_; // Objects whose member function we want to call
MF mf_; // pointer to member function
MemberFunctionWrapper(T _t, MF _mf)
:
t_(_t),
mf_(_mf)
{}
template <typename O>
auto operator()(const O& _o) -> decltype ((t_.*mf_)(_o))
{
return (t_.*mf_)(_o);
}
};
/// Helper to create a MemberFunctionWrapper without explicitely naming the types
template <typename T, typename MF>
MemberFunctionWrapper<T,MF> make_member_function_wrapper(T&& _t, MF _mf)
{
return MemberFunctionWrapper<T,MF>(std::forward<T>(_t), _mf);
}
/// Convenience macro to create a MemberFunctionWrapper for *this object
#define OM_MFW(member_function) OpenMesh::Predicates::make_member_function_wrapper(*this, &std::decay<decltype(*this)>::type::member_function)
//=============================================================================
} // namespace Predicates
} // namespace OpenMesh
//=============================================================================
//=============================================================================

View File

@@ -85,14 +85,17 @@ class PropertyManager {
private:
// 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.
// This class implements different behavior when initializing a property or when
// copying or swapping data from one property manager to a another one.
template <typename PropertyManager2, typename PropHandleT>
struct StorageT;
// specialization for Mesh Properties
template <typename PropertyManager2>
struct StorageT<PropertyManager2, MPropHandleT<Value>> {
static void initialize(PropertyManager<PROPTYPE, MeshT>& pm, const Value& initial_value ) {
pm() = initial_value;
}
static void copy(const PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
*to = *from;
}
@@ -110,6 +113,9 @@ class PropertyManager {
// definition for other Mesh Properties
template <typename PropertyManager2, typename PropHandleT>
struct StorageT {
static void initialize(PropertyManager<PROPTYPE, MeshT>& pm, const Value& initial_value ) {
pm.set_range(pm.mesh_.template all_elements<Handle>(), initial_value);
}
static void copy(const PropertyManager& from, PropertyManager2& to) {
from.copy_to(from.mesh_.template all_elements<Handle>(), to, to.mesh_.template all_elements<Handle>());
}
@@ -190,7 +196,7 @@ class PropertyManager {
PropertyManager(const Value& initial_value, PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) {
if (!mesh_.get_property_handle(prop_, propname)) {
PropertyManager::mesh().add_property(prop_, propname);
set_range(mesh_.all_elements<Handle>(), initial_value);
Storage::initialize(*this, initial_value);
}
}
@@ -215,7 +221,7 @@ class PropertyManager {
*/
PropertyManager(const Value& initial_value, const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") {
PropertyManager::mesh().add_property(prop_, name_);
set_range(mesh_.all_elements<Handle>(), initial_value);
Storage::initialize(*this, initial_value);
}
/**

View File

@@ -870,5 +870,12 @@ TEST_F(OpenMeshPropertyManager, return_property_from_function) {
}
TEST_F(OpenMeshPropertyManager, mesh_property_initialization) {
OpenMesh::MProp<int> mesh_id(13, mesh_);
ASSERT_EQ(mesh_id(), 13);
}
}

View File

@@ -560,6 +560,60 @@ TEST(OpenMeshSmartHandlesNoFixture, SplitTriMesh)
}
template <typename MeshT, typename RangeT>
void test_status_fields(MeshT& _mesh, const RangeT& _range)
{
for (auto el : _range)
_mesh.status(el).set_selected(el.idx() % 3 == 0);
for (auto el : _range)
EXPECT_EQ(_mesh.status(el).selected(), el.selected());
for (auto el : _range)
_mesh.status(el).set_feature(el.idx() % 3 == 0);
for (auto el : _range)
EXPECT_EQ(_mesh.status(el).feature(), el.feature());
for (auto el : _range)
_mesh.status(el).set_tagged(el.idx() % 3 == 0);
for (auto el : _range)
EXPECT_EQ(_mesh.status(el).tagged(), el.tagged());
for (auto el : _range)
_mesh.status(el).set_tagged2(el.idx() % 3 == 0);
for (auto el : _range)
EXPECT_EQ(_mesh.status(el).tagged2(), el.tagged2());
for (auto el : _range)
_mesh.status(el).set_hidden(el.idx() % 3 == 0);
for (auto el : _range)
EXPECT_EQ(_mesh.status(el).hidden(), el.hidden());
for (auto el : _range)
_mesh.status(el).set_locked(el.idx() % 3 == 0);
for (auto el : _range)
EXPECT_EQ(_mesh.status(el).locked(), el.locked());
for (auto el : _range)
_mesh.status(el).set_deleted(el.idx() % 3 == 0);
for (auto el : _range)
EXPECT_EQ(_mesh.status(el).deleted(), el.deleted());
}
TEST_F(OpenMeshSmartHandles, StatusAccess)
{
ASSERT_TRUE(mesh_.n_vertices() > 0) << "Mesh is empty";
mesh_.request_vertex_status();
mesh_.request_halfedge_status();
mesh_.request_edge_status();
mesh_.request_face_status();
test_status_fields(mesh_, mesh_.all_vertices());
test_status_fields(mesh_, mesh_.all_edges());
test_status_fields(mesh_, mesh_.all_halfedges());
test_status_fields(mesh_, mesh_.all_faces());
}

View File

@@ -3,6 +3,7 @@
#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
#include <OpenMesh/Core/Utils/PropertyManager.hh>
#include <OpenMesh/Core/Utils/Predicates.hh>
#include <iostream>
#include <chrono>
@@ -258,7 +259,7 @@ TEST_F(OpenMeshSmartRanges, BoundingBox)
// Thus we convert here.
OpenMesh::VProp<OpenMesh::Vec3f> myPos(mesh_);
for (auto vh : mesh_.vertices())
for (size_t i = 0; i < 3; ++i)
for (int i = 0; i < 3; ++i)
myPos(vh)[i] = mesh_.point(vh)[i];
auto bb_min = mesh_.vertices().min(myPos);
@@ -421,4 +422,493 @@ TEST_F(OpenMeshSmartRanges, WeightedAvg)
}
template <typename HandleT>
void test_range_predicates(Mesh& _mesh)
{
using namespace OpenMesh::Predicates;
auto get_random_set = [&](int n)
{
auto max = _mesh.n_elements<HandleT>();
std::vector<HandleT> set;
set.push_back(HandleT(0));
for (int i = 0; i < n; ++i)
set.push_back(HandleT(rand() % max));
std::sort(set.begin(), set.end());
set.erase(std::unique(set.begin(), set.end()), set.end());
return set;
};
// Feature
{
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_feature(false);
auto set = get_random_set(4);
for (auto el : set)
_mesh.status(el).set_feature(true);
auto set2 = _mesh.elements<HandleT>().filtered(Feature()).to_vector();
EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_feature(false);
}
// Selected
{
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
auto set = get_random_set(4);
for (auto el : set)
_mesh.status(el).set_selected(true);
auto set2 = _mesh.elements<HandleT>().filtered(Selected()).to_vector();
EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
}
// Tagged
{
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged(false);
auto set = get_random_set(4);
for (auto el : set)
_mesh.status(el).set_tagged(true);
auto set2 = _mesh.elements<HandleT>().filtered(Tagged()).to_vector();
EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged(false);
}
// Tagged2
{
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged2(false);
auto set = get_random_set(4);
for (auto el : set)
_mesh.status(el).set_tagged2(true);
auto set2 = _mesh.elements<HandleT>().filtered(Tagged2()).to_vector();
EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged2(false);
}
// Locked
{
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_locked(false);
auto set = get_random_set(4);
for (auto el : set)
_mesh.status(el).set_locked(true);
auto set2 = _mesh.elements<HandleT>().filtered(Locked()).to_vector();
EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_locked(false);
}
// Hidden
{
for (auto el : _mesh.all_elements<HandleT>())
_mesh.status(el).set_hidden(false);
auto set = get_random_set(4);
for (auto el : set)
_mesh.status(el).set_hidden(true);
auto set2 = _mesh.all_elements<HandleT>().filtered(Hidden()).to_vector();
EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
for (auto el : _mesh.all_elements<HandleT>())
_mesh.status(el).set_hidden(false);
}
// Deleted
{
for (auto el : _mesh.all_elements<HandleT>())
_mesh.status(el).set_deleted(false);
auto set = get_random_set(4);
for (auto el : set)
_mesh.status(el).set_deleted(true);
auto set2 = _mesh.all_elements<HandleT>().filtered(Deleted()).to_vector();
EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
for (auto el : _mesh.all_elements<HandleT>())
_mesh.status(el).set_deleted(false);
}
// Custom property
{
OpenMesh::PropertyManager<typename OpenMesh::PropHandle<HandleT>::template type<bool>> prop(false, _mesh);
auto set = get_random_set(4);
for (auto el : set)
prop[el] = true;
auto set2 = _mesh.elements<HandleT>().filtered(prop).to_vector();
EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
}
// boundary
{
for (auto el : _mesh.elements<HandleT>().filtered(Boundary()))
EXPECT_TRUE(el.is_boundary());
int n_boundary1 = 0.0;
for (auto el : _mesh.elements<HandleT>())
if (el.is_boundary())
n_boundary1 += 1;
int n_boundary2 = _mesh.elements<HandleT>().count_if(Boundary());
EXPECT_EQ(n_boundary1, n_boundary2);
}
}
template <typename HandleT>
void test_range_predicate_combinations(Mesh& _mesh)
{
using namespace OpenMesh::Predicates;
auto n_elements = _mesh.n_elements<HandleT>();
auto get_random_set = [&](int n)
{
std::vector<HandleT> set;
for (int i = 0; i < n; ++i)
set.push_back(HandleT(rand() % n_elements));
std::sort(set.begin(), set.end());
set.erase(std::unique(set.begin(), set.end()), set.end());
return set;
};
// negation
{
auto set = get_random_set(4);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : set)
_mesh.status(el).set_selected(true);
auto true_set = _mesh.elements<HandleT>().filtered(Selected()).to_vector();
auto false_set = _mesh.elements<HandleT>().filtered(!Selected()).to_vector();
std::vector<HandleT> intersection;
std::set_intersection(true_set.begin(), true_set.end(), false_set.begin(), false_set.end(), std::back_inserter(intersection));
EXPECT_TRUE(intersection.empty());
EXPECT_EQ(true_set.size() + false_set.size(), n_elements);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
}
// conjunction
{
auto set1 = get_random_set(4);
auto set2 = get_random_set(4);
// make sure there is some overlap
{
auto set3 = get_random_set(3);
set1.insert(set1.end(), set3.begin(), set3.end());
set2.insert(set2.end(), set3.begin(), set3.end());
std::sort(set1.begin(), set1.end());
std::sort(set2.begin(), set2.end());
set1.erase(std::unique(set1.begin(), set1.end()), set1.end());
set2.erase(std::unique(set2.begin(), set2.end()), set2.end());
}
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged(false);
for (auto el : set1)
_mesh.status(el).set_selected(true);
for (auto el : set2)
_mesh.status(el).set_tagged(true);
auto set = _mesh.elements<HandleT>().filtered(Selected() && Tagged()).to_vector();
std::vector<HandleT> intersection;
std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(intersection));
EXPECT_EQ(intersection.size(), set.size());
for (size_t i = 0; i < std::min(intersection.size(), set.size()); ++i)
EXPECT_EQ(intersection[i], set[i]) << "Sets differ at position " << i;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged(false);
}
// Disjunction
{
auto set1 = get_random_set(4);
auto set2 = get_random_set(4);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged(false);
for (auto el : set1)
_mesh.status(el).set_selected(true);
for (auto el : set2)
_mesh.status(el).set_tagged(true);
auto set = _mesh.elements<HandleT>().filtered(Selected() || Tagged()).to_vector();
std::vector<HandleT> union_set;
std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set));
EXPECT_EQ(union_set.size(), set.size());
for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i)
EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged(false);
}
}
template <typename HandleT>
bool test_func(HandleT _h)
{
return _h.idx() % 3 == 0;
}
template <typename HandleT>
void test_make_predicate(Mesh& _mesh)
{
using namespace OpenMesh::Predicates;
auto n_elements = _mesh.n_elements<HandleT>();
auto get_random_set = [&](int n)
{
std::vector<HandleT> set;
for (int i = 0; i < n; ++i)
set.push_back(HandleT(rand() % n_elements));
std::sort(set.begin(), set.end());
set.erase(std::unique(set.begin(), set.end()), set.end());
return set;
};
// custom property
{
OpenMesh::PropertyManager<typename OpenMesh::PropHandle<HandleT>::template type<bool>> prop(false, _mesh);
auto set1 = get_random_set(4);
auto set2 = get_random_set(4);
for (auto el : set1)
prop[el] = true;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : set2)
_mesh.status(el).set_selected(true);
auto set = _mesh.elements<HandleT>().filtered(Selected() || make_predicate(prop)).to_vector();
std::vector<HandleT> union_set;
std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set));
EXPECT_EQ(union_set.size(), set.size());
for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i)
EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged(false);
}
// lambda
{
OpenMesh::PropertyManager<typename OpenMesh::PropHandle<HandleT>::template type<bool>> prop(false, _mesh);
auto set1 = get_random_set(4);
auto set2 = get_random_set(4);
for (auto el : set1)
prop[el] = true;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : set2)
_mesh.status(el).set_selected(true);
auto test = [&](HandleT h) { return prop(h); };
auto set = _mesh.elements<HandleT>().filtered(Selected() || make_predicate(test)).to_vector();
std::vector<HandleT> union_set;
std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set));
EXPECT_EQ(union_set.size(), set.size());
for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i)
EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged(false);
}
// r value lambda
{
OpenMesh::PropertyManager<typename OpenMesh::PropHandle<HandleT>::template type<bool>> prop(false, _mesh);
auto set1 = get_random_set(4);
auto set2 = get_random_set(4);
for (auto el : set1)
prop[el] = true;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : set2)
_mesh.status(el).set_selected(true);
auto set = _mesh.elements<HandleT>().filtered(Selected() || make_predicate([&](HandleT h) { return prop(h); })).to_vector();
std::vector<HandleT> union_set;
std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set));
EXPECT_EQ(union_set.size(), set.size());
for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i)
EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged(false);
}
// function pointer
{
auto set1 = _mesh.elements<HandleT>().filtered([&](const HandleT& h) { return test_func(h); }).to_vector();
auto set2 = get_random_set(4);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : set2)
_mesh.status(el).set_selected(true);
auto set = _mesh.elements<HandleT>().filtered(Selected() || make_predicate(test_func<HandleT>)).to_vector();
std::vector<HandleT> union_set;
std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set));
EXPECT_EQ(union_set.size(), set.size());
for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i)
EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i;
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_selected(false);
for (auto el : _mesh.elements<HandleT>())
_mesh.status(el).set_tagged(false);
}
}
TEST_F(OpenMeshSmartRanges, Predicate)
{
using namespace OpenMesh;
mesh_.request_vertex_status();
mesh_.request_halfedge_status();
mesh_.request_edge_status();
mesh_.request_face_status();
mesh_.delete_face(FaceHandle(0)); // ensure there is a boundary
mesh_.garbage_collection();
test_range_predicates<VertexHandle>(mesh_);
test_range_predicates<HalfedgeHandle>(mesh_);
test_range_predicates<EdgeHandle>(mesh_);
test_range_predicates<FaceHandle>(mesh_);
test_range_predicate_combinations<VertexHandle>(mesh_);
test_range_predicate_combinations<HalfedgeHandle>(mesh_);
test_range_predicate_combinations<EdgeHandle>(mesh_);
test_range_predicate_combinations<FaceHandle>(mesh_);
test_make_predicate<VertexHandle>(mesh_);
test_make_predicate<HalfedgeHandle>(mesh_);
test_make_predicate<EdgeHandle>(mesh_);
test_make_predicate<FaceHandle>(mesh_);
}
struct MemberFunctionWrapperTestStruct
{
MemberFunctionWrapperTestStruct(int _i)
:
i_(_i)
{
}
int get_i(const OpenMesh::SmartEdgeHandle& /*_eh*/) const
{
return i_;
}
bool id_divisible_by_2(const OpenMesh::SmartEdgeHandle& _eh) const
{
return _eh.idx() % 2 == 0;
}
int valence_times_i(const OpenMesh::SmartVertexHandle& vh)
{
return vh.edges().sum(OM_MFW(get_i));
}
int i_;
};
TEST_F(OpenMeshSmartRanges, MemberFunctionFunctor)
{
using namespace OpenMesh::Predicates;
EXPECT_TRUE(mesh_.n_vertices() > 0) << "Mesh has no vertices";
EXPECT_TRUE(mesh_.n_edges() > 0) << "Mesh has no edges";
int factor = 3;
MemberFunctionWrapperTestStruct test_object(factor);
// Test using a MemberFunctionWrapper as Functor
EXPECT_EQ(mesh_.n_edges() / 2, mesh_.edges().count_if(make_member_function_wrapper(test_object, &MemberFunctionWrapperTestStruct::id_divisible_by_2)));
// Test using a MemberFunctionWrapper as Functor that is created using the convenience macro from inside the struct
for (auto vh : mesh_.vertices())
EXPECT_EQ(test_object.valence_times_i(vh), vh.valence() * factor);
factor = 4;
test_object.i_ = factor;
for (auto vh : mesh_.vertices())
{
EXPECT_EQ(test_object.valence_times_i(vh), vh.valence() * factor);
}
}
}