/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * @file * Utilities and helpers */ #ifndef CDT_obwOaxOTdAWcLNTlNnaq #define CDT_obwOaxOTdAWcLNTlNnaq #ifdef CDT_DONT_USE_BOOST_RTREE // CDT_DONT_USE_BOOST_RTREE was replaced with CDT_USE_BOOST typedef char CDT_DONT_USE_BOOST_RTREE__was__replaced__with__CDT_USE_BOOST[-1]; #endif // #define CDT_USE_STRONG_TYPING // strong type checks on indices // check if c++11 is supported #if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) #define CDT_CXX11_IS_SUPPORTED #elif !defined(__cplusplus) && !defined(_MSC_VER) typedef char couldnt_parse_cxx_standard[-1]; ///< Error: couldn't parse standard #endif // Functions defined outside the class need to be 'inline' // if CDT is configured to be used as header-only library: // single-definition rule is violated otherwise #ifdef CDT_USE_AS_COMPILED_LIBRARY #define CDT_INLINE_IF_HEADER_ONLY #include "cdt_export.h" // automatically generated by CMake #else /** * Macro for inlining non-template functions when in header-only mode to * avoid multiple declaration errors. */ #define CDT_INLINE_IF_HEADER_ONLY inline /// Export not needed in header-only mode #define CDT_EXPORT #endif #include #include #include #include #ifdef CDT_USE_BOOST #include #endif // use fall-backs for c++11 features #ifdef CDT_CXX11_IS_SUPPORTED #include #include #include #include #include #include namespace CDT { using std::array; using std::get; using std::make_tuple; using std::mt19937; using std::tie; using std::tuple; using std::unordered_map; using std::unordered_set; } // namespace CDT #else #include #include #include #include #include #include namespace CDT { using boost::array; using boost::get; using boost::make_tuple; using boost::tie; using boost::tuple; using boost::unordered_map; using boost::unordered_set; using boost::random::mt19937; } // namespace CDT #endif namespace CDT { /// 2D vector template struct CDT_EXPORT V2d { T x; ///< X-coordinate T y; ///< Y-coordinate /// Create vector from X and Y coordinates static V2d make(T x, T y); }; /// X- coordinate getter for V2d template const T& getX_V2d(const V2d& v) { return v.x; } /// Y-coordinate getter for V2d template const T& getY_V2d(const V2d& v) { return v.y; } /// If two 2D vectors are exactly equal template bool operator==(const CDT::V2d& lhs, const CDT::V2d& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } #ifdef CDT_USE_64_BIT_INDEX_TYPE typedef unsigned long long IndexSizeType; #else typedef unsigned int IndexSizeType; #endif #ifndef CDT_USE_STRONG_TYPING /// Index in triangle typedef unsigned char Index; /// Vertex index typedef IndexSizeType VertInd; /// Triangle index typedef IndexSizeType TriInd; #else /// Index in triangle BOOST_STRONG_TYPEDEF(unsigned char, Index); /// Vertex index BOOST_STRONG_TYPEDEF(IndexSizeType, VertInd); /// Triangle index BOOST_STRONG_TYPEDEF(IndexSizeType, TriInd); #endif /// Constant representing no valid neighbor for a triangle const static TriInd noNeighbor(std::numeric_limits::max()); /// Constant representing no valid vertex for a triangle const static VertInd noVertex(std::numeric_limits::max()); typedef std::vector TriIndVec; ///< Vector of triangle indices typedef array VerticesArr3; ///< array of three vertex indices typedef array NeighborsArr3; ///< array of three neighbors /// 2D bounding box template struct CDT_EXPORT Box2d { V2d min; ///< min box corner V2d max; ///< max box corner /// Envelop box around a point void envelopPoint(const V2d& p) { envelopPoint(p.x, p.y); } /// Envelop box around a point with given coordinates void envelopPoint(const T x, const T y) { min.x = std::min(x, min.x); max.x = std::max(x, max.x); min.y = std::min(y, min.y); max.y = std::max(y, max.y); } }; /// Bounding box of a collection of custom 2D points given coordinate getters template < typename T, typename TVertexIter, typename TGetVertexCoordX, typename TGetVertexCoordY> Box2d envelopBox( TVertexIter first, TVertexIter last, TGetVertexCoordX getX, TGetVertexCoordY getY) { const T max = std::numeric_limits::max(); Box2d box = {{max, max}, {-max, -max}}; for(; first != last; ++first) { box.envelopPoint(getX(*first), getY(*first)); } return box; } /// Bounding box of a collection of 2D points template CDT_EXPORT Box2d envelopBox(const std::vector >& vertices); /// Edge connecting two vertices: vertex with smaller index is always first /// \note: hash Edge is specialized at the bottom struct CDT_EXPORT Edge { /// Constructor Edge(VertInd iV1, VertInd iV2); /// Equals operator bool operator==(const Edge& other) const; /// Not-equals operator bool operator!=(const Edge& other) const; /// V1 getter VertInd v1() const; /// V2 getter VertInd v2() const; /// Edges' vertices const std::pair& verts() const; private: std::pair m_vertices; }; /// Get edge first vertex inline VertInd edge_get_v1(const Edge& e) { return e.v1(); } /// Get edge second vertex inline VertInd edge_get_v2(const Edge& e) { return e.v2(); } /// Get edge second vertex inline Edge edge_make(VertInd iV1, VertInd iV2) { return Edge(iV1, iV2); } typedef std::vector EdgeVec; ///< Vector of edges typedef unordered_set EdgeUSet; ///< Hash table of edges typedef unordered_set TriIndUSet; ///< Hash table of triangles typedef unordered_map TriIndUMap; ///< Triangle hash map #ifdef CDT_USE_BOOST /// Flat hash table of triangles typedef boost::container::flat_set TriIndFlatUSet; #endif /// Triangulation triangle (CCW winding) /* Counter-clockwise winding: v3 /\ n3/ \n2 /____\ v1 n1 v2 */ struct CDT_EXPORT Triangle { VerticesArr3 vertices; ///< triangle's three vertices NeighborsArr3 neighbors; ///< triangle's three neighbors /** * Factory method * @note needed for c++03 compatibility (no uniform initialization * available) */ static Triangle make(const array& vertices, const array& neighbors) { Triangle t = {vertices, neighbors}; return t; } }; typedef std::vector TriangleVec; ///< Vector of triangles /// Advance vertex or neighbor index counter-clockwise CDT_EXPORT Index ccw(Index i); /// Advance vertex or neighbor index clockwise CDT_EXPORT Index cw(Index i); /// Location of point on a triangle struct CDT_EXPORT PtTriLocation { /// Enum enum Enum { Inside, Outside, OnEdge1, OnEdge2, OnEdge3, }; }; /// Check if location is classified as on any of three edges CDT_EXPORT bool isOnEdge(PtTriLocation::Enum location); /// Neighbor index from a on-edge location /// \note Call only if located on the edge! CDT_EXPORT Index edgeNeighbor(PtTriLocation::Enum location); /// Relative location of point to a line struct CDT_EXPORT PtLineLocation { /// Enum enum Enum { Left, Right, OnLine, }; }; /// Orient p against line v1-v2 2D: robust geometric predicate template CDT_EXPORT T orient2D(const V2d& p, const V2d& v1, const V2d& v2); /// Check if point lies to the left of, to the right of, or on a line template CDT_EXPORT PtLineLocation::Enum locatePointLine( const V2d& p, const V2d& v1, const V2d& v2, T orientationTolerance = T(0)); /// Classify value of orient2d predicate template CDT_EXPORT PtLineLocation::Enum classifyOrientation(T orientation, T orientationTolerance = T(0)); /// Check if point a lies inside of, outside of, or on an edge of a triangle template CDT_EXPORT PtTriLocation::Enum locatePointTriangle( const V2d& p, const V2d& v1, const V2d& v2, const V2d& v3); /// Opposed neighbor index from vertex index CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opoNbr(Index vertIndex); /// Opposed vertex index from neighbor index CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opoVrt(Index neighborIndex); /// Index of triangle's neighbor opposed to a vertex CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opposedTriangleInd(const Triangle& tri, VertInd iVert); /// Index of triangle's neighbor opposed to an edge CDT_INLINE_IF_HEADER_ONLY Index opposedTriangleInd(const Triangle& tri, VertInd iVedge1, VertInd iVedge2); /// Index of triangle's vertex opposed to a triangle CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opposedVertexInd(const Triangle& tri, TriInd iTopo); /// If triangle has a given neighbor return neighbor-index, throw otherwise CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index neighborInd(const Triangle& tri, TriInd iTnbr); /// If triangle has a given vertex return vertex-index, throw otherwise CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index vertexInd(const Triangle& tri, VertInd iV); /// Given triangle and a vertex find opposed triangle CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY TriInd opposedTriangle(const Triangle& tri, VertInd iVert); /// Given two triangles, return vertex of first triangle opposed to the second CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY VertInd opposedVertex(const Triangle& tri, TriInd iTopo); /// Test if point lies in a circumscribed circle of a triangle template CDT_EXPORT bool isInCircumcircle( const V2d& p, const V2d& v1, const V2d& v2, const V2d& v3); /// Test if two vertices share at least one common triangle CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY bool verticesShareEdge(const TriIndVec& aTris, const TriIndVec& bTris); /// Distance between two 2D points template CDT_EXPORT T distance(const V2d& a, const V2d& b); /// Squared distance between two 2D points template CDT_EXPORT T distanceSquared(const V2d& a, const V2d& b); } // namespace CDT #ifndef CDT_USE_AS_COMPILED_LIBRARY #include "CDTUtils.hpp" #endif //***************************************************************************** // Specialize hash functions //***************************************************************************** #ifdef CDT_CXX11_IS_SUPPORTED namespace std #else namespace boost #endif { #ifdef CDT_USE_STRONG_TYPING /// Vertex index hasher template <> struct hash { /// Hash operator std::size_t operator()(const CDT::VertInd& vi) const { return std::hash()(vi.t); } }; /// Triangle index hasher template <> struct hash { /// Hash operator std::size_t operator()(const CDT::TriInd& vi) const { return std::hash()(vi.t); } }; #endif // CDT_USE_STRONG_TYPING /// Edge hasher template <> struct hash { /// Hash operator std::size_t operator()(const CDT::Edge& e) const { return hashEdge(e); } private: static void hashCombine(std::size_t& seed, const CDT::VertInd& key) { #ifdef CDT_CXX11_IS_SUPPORTED typedef std::hash Hasher; #else typedef boost::hash Hasher; #endif seed ^= Hasher()(key) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } static std::size_t hashEdge(const CDT::Edge& e) { const std::pair& vv = e.verts(); std::size_t seed1(0); hashCombine(seed1, vv.first); hashCombine(seed1, vv.second); std::size_t seed2(0); hashCombine(seed2, vv.second); hashCombine(seed2, vv.first); return std::min(seed1, seed2); } }; } // namespace std/boost #endif // header guard