/* 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 * Public API */ #ifndef CDT_lNrmUayWQaIR5fxnsg9B #define CDT_lNrmUayWQaIR5fxnsg9B #include "CDTUtils.h" #include "Triangulation.h" #include "remove_at.hpp" #include #include #include #include #include #include #include /// Namespace containing triangulation functionality namespace CDT { /** @defgroup API Public API * Contains API for constrained and conforming Delaunay triangulations */ /// @{ /** * Type used for storing layer depths for triangles * @note LayerDepth should support 60K+ layers, which could be to much or * too little for some use cases. Feel free to re-define this typedef. */ typedef unsigned short LayerDepth; typedef LayerDepth BoundaryOverlapCount; /// Triangles by vertex index typedef std::vector VerticesTriangles; /** @defgroup helpers Helpers * Helpers for working with CDT::Triangulation. */ /// @{ /** * Calculate triangles adjacent to vertices (triangles by vertex index) * @param triangles triangulation * @param verticesSize total number of vertices to pre-allocate the output * @return triangles by vertex index */ CDT_EXPORT VerticesTriangles calculateTrianglesByVertex(const TriangleVec& triangles, VertInd verticesSize); /** * Information about removed duplicated vertices. * * Contains mapping information and removed duplicates indices. * @note vertices {0,1,2,3,4} where 0 and 3 are the same will produce mapping * {0,1,2,0,3} (to new vertices {0,1,2,3}) and duplicates {3} */ struct CDT_EXPORT DuplicatesInfo { std::vector mapping; ///< vertex index mapping std::vector duplicates; ///< duplicates' indices }; /** * Find duplicates in given custom point-type range * @note duplicates are points with exactly same X and Y coordinates * @tparam TVertexIter iterator that dereferences to custom point type * @tparam TGetVertexCoordX function object getting x coordinate from vertex. * Getter signature: const TVertexIter::value_type& -> T * @tparam TGetVertexCoordY function object getting y coordinate from vertex. * Getter signature: const TVertexIter::value_type& -> T * @param first beginning of the range of vertices * @param last end of the range of vertices * @param getX getter of X-coordinate * @param getY getter of Y-coordinate * @returns information about vertex duplicates */ template < typename T, typename TVertexIter, typename TGetVertexCoordX, typename TGetVertexCoordY> DuplicatesInfo FindDuplicates( TVertexIter first, TVertexIter last, TGetVertexCoordX getX, TGetVertexCoordY getY); /** * Remove duplicates in-place from vector of custom points * @tparam TVertex vertex type * @tparam TAllocator allocator used by input vector of vertices * @param vertices vertices to remove duplicates from * @param duplicates information about duplicates */ template void RemoveDuplicates( std::vector& vertices, const std::vector& duplicates); /** * Remove duplicated points in-place * * @tparam T type of vertex coordinates (e.g., float, double) * @param[in, out] vertices collection of vertices to remove duplicates from * @returns information about duplicated vertices that were removed. */ template CDT_EXPORT DuplicatesInfo RemoveDuplicates(std::vector >& vertices); /** * Remap vertex indices in edges (in-place) using given vertex-index mapping. * @tparam TEdgeIter iterator that dereferences to custom edge type * @tparam TGetEdgeVertexStart function object getting start vertex index * from an edge. * Getter signature: const TEdgeIter::value_type& -> CDT::VertInd * @tparam TGetEdgeVertexEnd function object getting end vertex index from * an edge. Getter signature: const TEdgeIter::value_type& -> CDT::VertInd * @tparam TMakeEdgeFromStartAndEnd function object that makes new edge from * start and end vertices * @param first beginning of the range of edges * @param last end of the range of edges * @param mapping vertex-index mapping * @param getStart getter of edge start vertex index * @param getEnd getter of edge end vertex index * @param makeEdge factory for making edge from vetices */ template < typename TEdgeIter, typename TGetEdgeVertexStart, typename TGetEdgeVertexEnd, typename TMakeEdgeFromStartAndEnd> CDT_EXPORT void RemapEdges( TEdgeIter first, TEdgeIter last, const std::vector& mapping, TGetEdgeVertexStart getStart, TGetEdgeVertexEnd getEnd, TMakeEdgeFromStartAndEnd makeEdge); /** * Remap vertex indices in edges (in-place) using given vertex-index mapping. * * @note Mapping can be a result of RemoveDuplicates function * @param[in,out] edges collection of edges to remap * @param mapping vertex-index mapping */ CDT_EXPORT void RemapEdges(std::vector& edges, const std::vector& mapping); /** * Find point duplicates, remove them from vector (in-place) and remap edges * (in-place) * @note Same as a chained call of CDT::FindDuplicates, CDT::RemoveDuplicates, * and CDT::RemapEdges * @tparam T type of vertex coordinates (e.g., float, double) * @tparam TVertex type of vertex * @tparam TGetVertexCoordX function object getting x coordinate from vertex. * Getter signature: const TVertexIter::value_type& -> T * @tparam TGetVertexCoordY function object getting y coordinate from vertex. * Getter signature: const TVertexIter::value_type& -> T * @tparam TEdgeIter iterator that dereferences to custom edge type * @tparam TGetEdgeVertexStart function object getting start vertex index * from an edge. * Getter signature: const TEdgeIter::value_type& -> CDT::VertInd * @tparam TGetEdgeVertexEnd function object getting end vertex index from * an edge. Getter signature: const TEdgeIter::value_type& -> CDT::VertInd * @tparam TMakeEdgeFromStartAndEnd function object that makes new edge from * start and end vertices * @param[in, out] vertices vertices to remove duplicates from * @param[in, out] edges collection of edges connecting vertices * @param getX getter of X-coordinate * @param getY getter of Y-coordinate * @param edgesFirst beginning of the range of edges * @param edgesLast end of the range of edges * @param getStart getter of edge start vertex index * @param getEnd getter of edge end vertex index * @param makeEdge factory for making edge from vetices * @returns information about vertex duplicates */ template < typename T, typename TVertex, typename TGetVertexCoordX, typename TGetVertexCoordY, typename TVertexAllocator, typename TEdgeIter, typename TGetEdgeVertexStart, typename TGetEdgeVertexEnd, typename TMakeEdgeFromStartAndEnd> DuplicatesInfo RemoveDuplicatesAndRemapEdges( std::vector& vertices, TGetVertexCoordX getX, TGetVertexCoordY getY, TEdgeIter edgesFirst, TEdgeIter edgesLast, TGetEdgeVertexStart getStart, TGetEdgeVertexEnd getEnd, TMakeEdgeFromStartAndEnd makeEdge); /** * Same as a chained call of CDT::RemoveDuplicates + CDT::RemapEdges * * @tparam T type of vertex coordinates (e.g., float, double) * @param[in, out] vertices collection of vertices to remove duplicates from * @param[in,out] edges collection of edges to remap */ template CDT_EXPORT DuplicatesInfo RemoveDuplicatesAndRemapEdges( std::vector >& vertices, std::vector& edges); /** * Extract all edges of triangles * * @param triangles triangles used to extract edges * @return an unordered set of all edges of triangulation */ CDT_EXPORT EdgeUSet extractEdgesFromTriangles(const TriangleVec& triangles); /*! * Converts piece->original_edges mapping to original_edge->pieces * @param pieceToOriginals maps pieces to original edges * @return mapping of original edges to pieces */ CDT_EXPORT unordered_map EdgeToPiecesMapping(const unordered_map& pieceToOriginals); /*! * Convert edge-to-pieces mapping into edge-to-split-vertices mapping * @tparam T type of vertex coordinates (e.g., float, double) * @param edgeToPieces edge-to-pieces mapping * @param vertices vertex buffer * @return mapping of edge-to-split-points. * Split points are sorted from edge's start (v1) to end (v2) */ template CDT_EXPORT unordered_map > EdgeToSplitVertices( const unordered_map& edgeToPieces, const std::vector >& vertices); /// @} /// @} } // namespace CDT //***************************************************************************** // Implementations of template functionlity //***************************************************************************** // hash for CDT::V2d #ifdef CDT_CXX11_IS_SUPPORTED namespace std #else namespace boost #endif { template struct hash > { size_t operator()(const CDT::V2d& xy) const { #ifdef CDT_CXX11_IS_SUPPORTED typedef std::hash Hasher; #else typedef boost::hash Hasher; #endif return Hasher()(xy.x) ^ Hasher()(xy.y); } }; } // namespace std namespace CDT { //----- // API //----- template < typename T, typename TVertexIter, typename TGetVertexCoordX, typename TGetVertexCoordY> DuplicatesInfo FindDuplicates( TVertexIter first, TVertexIter last, TGetVertexCoordX getX, TGetVertexCoordY getY) { typedef unordered_map, std::size_t> PosToIndex; PosToIndex uniqueVerts; const std::size_t verticesSize = std::distance(first, last); DuplicatesInfo di = { std::vector(verticesSize), std::vector()}; for(std::size_t iIn = 0, iOut = iIn; iIn < verticesSize; ++iIn, ++first) { typename PosToIndex::const_iterator it; bool isUnique; tie(it, isUnique) = uniqueVerts.insert( std::make_pair(V2d::make(getX(*first), getY(*first)), iOut)); if(isUnique) { di.mapping[iIn] = iOut++; continue; } di.mapping[iIn] = it->second; // found a duplicate di.duplicates.push_back(iIn); } return di; } template void RemoveDuplicates( std::vector& vertices, const std::vector& duplicates) { vertices.erase( remove_at( vertices.begin(), vertices.end(), duplicates.begin(), duplicates.end()), vertices.end()); } template < typename TEdgeIter, typename TGetEdgeVertexStart, typename TGetEdgeVertexEnd, typename TMakeEdgeFromStartAndEnd> void RemapEdges( TEdgeIter first, const TEdgeIter last, const std::vector& mapping, TGetEdgeVertexStart getStart, TGetEdgeVertexEnd getEnd, TMakeEdgeFromStartAndEnd makeEdge) { for(; first != last; ++first) { *first = makeEdge( static_cast(mapping[getStart(*first)]), static_cast(mapping[getEnd(*first)])); } } template < typename T, typename TVertex, typename TGetVertexCoordX, typename TGetVertexCoordY, typename TVertexAllocator, typename TEdgeIter, typename TGetEdgeVertexStart, typename TGetEdgeVertexEnd, typename TMakeEdgeFromStartAndEnd> DuplicatesInfo RemoveDuplicatesAndRemapEdges( std::vector& vertices, TGetVertexCoordX getX, TGetVertexCoordY getY, const TEdgeIter edgesFirst, const TEdgeIter edgesLast, TGetEdgeVertexStart getStart, TGetEdgeVertexEnd getEnd, TMakeEdgeFromStartAndEnd makeEdge) { const DuplicatesInfo di = FindDuplicates(vertices.begin(), vertices.end(), getX, getY); RemoveDuplicates(vertices, di.duplicates); RemapEdges(edgesFirst, edgesLast, di.mapping, getStart, getEnd, makeEdge); return di; } template unordered_map > EdgeToSplitVertices( const unordered_map& edgeToPieces, const std::vector >& vertices) { typedef std::pair VertCoordPair; struct ComparePred { bool operator()(const VertCoordPair& a, const VertCoordPair& b) const { return a.second < b.second; } } comparePred; unordered_map > edgeToSplitVerts; typedef unordered_map::const_iterator It; for(It it = edgeToPieces.begin(); it != edgeToPieces.end(); ++it) { const Edge& e = it->first; const T dX = vertices[e.v2()].x - vertices[e.v1()].x; const T dY = vertices[e.v2()].y - vertices[e.v1()].y; const bool isX = std::abs(dX) >= std::abs(dY); // X-coord longer const bool isAscending = isX ? dX >= 0 : dY >= 0; // Longer coordinate ascends const EdgeVec& pieces = it->second; std::vector splitVerts; // size is: 2[ends] + (pieces - 1)[split vertices] = pieces + 1 splitVerts.reserve(pieces.size() + 1); typedef EdgeVec::const_iterator EIt; for(EIt it = pieces.begin(); it != pieces.end(); ++it) { const array vv = {it->v1(), it->v2()}; typedef array::const_iterator VIt; for(VIt v = vv.begin(); v != vv.end(); ++v) { const T c = isX ? vertices[*v].x : vertices[*v].y; splitVerts.push_back(std::make_pair(*v, isAscending ? c : -c)); } } // sort by longest coordinate std::sort(splitVerts.begin(), splitVerts.end(), comparePred); // remove duplicates splitVerts.erase( std::unique(splitVerts.begin(), splitVerts.end()), splitVerts.end()); assert(splitVerts.size() > 2); // 2 end points with split vertices std::pair > val = std::make_pair(e, std::vector()); val.second.reserve(splitVerts.size()); typedef typename std::vector::const_iterator SEIt; for(SEIt it = splitVerts.begin() + 1; it != splitVerts.end() - 1; ++it) { val.second.push_back(it->first); } edgeToSplitVerts.insert(val); } return edgeToSplitVerts; } } // namespace CDT #ifndef CDT_USE_AS_COMPILED_LIBRARY #include "CDT.hpp" #endif #endif // header-guard