Merge branch 'master' into Unittest_space_bool
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
//=============================================================================
|
||||
|
||||
@@ -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_); }
|
||||
|
||||
|
||||
293
src/OpenMesh/Core/Utils/Predicates.hh
Normal file
293
src/OpenMesh/Core/Utils/Predicates.hh
Normal 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
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user