CDT  1.4.1
C++ library for constrained Delaunay triangulation
Loading...
Searching...
No Matches
Triangulation.h
Go to the documentation of this file.
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
10#ifndef CDT_vW1vZ0lO8rS4gY4uI4fB
11#define CDT_vW1vZ0lO8rS4gY4uI4fB
12
13#include "CDTUtils.h"
14#include "LocatorKDTree.h"
15
16#include <algorithm>
17#include <cstdlib>
18#include <iterator>
19#include <stack>
20#include <stdexcept>
21#include <string>
22#include <utility>
23#include <vector>
24
26namespace CDT
27{
28
31
56
70
91
97typedef unsigned short LayerDepth;
98typedef LayerDepth BoundaryOverlapCount;
99
104{
105public:
106 SourceLocation(const std::string& file, const std::string& func, int line)
107 : m_file(file)
108 , m_func(func)
109 , m_line(line)
110 {}
111 const std::string& file() const
112 {
113 return m_file;
114 }
115 const std::string& func() const
116 {
117 return m_func;
118 }
119 int line() const
120 {
121 return m_line;
122 }
123
124private:
125 std::string m_file;
126 std::string m_func;
127 int m_line;
128};
129
131#define CDT_SOURCE_LOCATION \
132 SourceLocation(std::string(__FILE__), std::string(__func__), __LINE__)
133
138class Error : public std::runtime_error
139{
140public:
142 Error(const std::string& description, const SourceLocation& srcLoc)
143 : std::runtime_error(
144 description + "\nin '" + srcLoc.func() + "' at " + srcLoc.file() +
145 ":" + std::to_string(srcLoc.line()))
146 , m_description(description)
147 , m_srcLoc(srcLoc)
148 {}
150 const std::string& description() const
151 {
152 return m_description;
153 }
156 {
157 return m_srcLoc;
158 }
159
160private:
161 std::string m_description;
162 SourceLocation m_srcLoc;
163};
164
169class FinalizedError : public Error
170{
171public:
172 FinalizedError(const SourceLocation& srcLoc)
173 : Error(
174 "Triangulation was finalized with 'erase...' method. Further "
175 "modification is not possible.",
176 srcLoc)
177 {}
178};
179
184{
185public:
187 const VertInd v1,
188 const VertInd v2,
189 const SourceLocation& srcLoc)
190 : Error(
191 "Duplicate vertex detected: #" + std::to_string(v1) +
192 " is a duplicate of #" + std::to_string(v2),
193 srcLoc)
194 , m_v1(v1)
195 , m_v2(v2)
196 {}
197 VertInd v1() const
198 {
199 return m_v1;
200 }
201 VertInd v2() const
202 {
203 return m_v2;
204 }
205
206private:
207 VertInd m_v1, m_v2;
208};
209
215{
216public:
218 const Edge& e1,
219 const Edge& e2,
220 const SourceLocation& srcLoc)
221 : Error(
222 "Intersecting constraint edges detected: (" +
223 std::to_string(e1.v1()) + ", " + std::to_string(e1.v2()) +
224 ") intersects (" + std::to_string(e2.v1()) + ", " +
225 std::to_string(e2.v2()) + ")",
226 srcLoc)
227 , m_e1(e1)
228 , m_e2(e2)
229 {}
230 const Edge& e1() const
231 {
232 return m_e1;
233 }
234 const Edge& e2() const
235 {
236 return m_e2;
237 }
238
239private:
240 Edge m_e1, m_e2;
241};
242
248
257template <typename T, typename TNearPointLocator = LocatorKDTree<T> >
259{
260public:
261 typedef std::vector<V2d<T> > V2dVec;
265
273 unordered_map<Edge, BoundaryOverlapCount> overlapCount;
274
280 unordered_map<Edge, EdgeVec> pieceToOriginals;
281
282 /*____ API _____*/
289 explicit Triangulation(VertexInsertionOrder::Enum vertexInsertionOrder);
300 VertexInsertionOrder::Enum vertexInsertionOrder,
301 IntersectingConstraintEdges::Enum intersectingEdgesStrategy,
302 T minDistToConstraintEdge);
315 VertexInsertionOrder::Enum vertexInsertionOrder,
316 const TNearPointLocator& nearPtLocator,
317 IntersectingConstraintEdges::Enum intersectingEdgesStrategy,
318 T minDistToConstraintEdge);
331 template <
332 typename TVertexIter,
333 typename TGetVertexCoordX,
334 typename TGetVertexCoordY>
335 void insertVertices(
336 TVertexIter first,
337 TVertexIter last,
338 TGetVertexCoordX getX,
339 TGetVertexCoordY getY);
344 void insertVertices(const std::vector<V2d<T> >& vertices);
374 template <
375 typename TEdgeIter,
376 typename TGetEdgeVertexStart,
377 typename TGetEdgeVertexEnd>
378 void insertEdges(
379 TEdgeIter first,
380 TEdgeIter last,
381 TGetEdgeVertexStart getStart,
382 TGetEdgeVertexEnd getEnd);
403 void insertEdges(const std::vector<Edge>& edges);
433 template <
434 typename TEdgeIter,
435 typename TGetEdgeVertexStart,
436 typename TGetEdgeVertexEnd>
437 void conformToEdges(
438 TEdgeIter first,
439 TEdgeIter last,
440 TGetEdgeVertexStart getStart,
441 TGetEdgeVertexEnd getEnd);
462 void conformToEdges(const std::vector<Edge>& edges);
468 void eraseSuperTriangle();
470 void eraseOuterTriangles();
477 void eraseOuterTrianglesAndHoles();
482 void initializedWithCustomSuperGeometry();
483
489 bool isFinalized() const;
490
504 std::vector<LayerDepth> calculateTriangleDepths() const;
505
512
520 void flipEdge(TriInd iT, TriInd iTopo);
521
522 void flipEdge(
523 TriInd iT,
524 TriInd iTopo,
525 VertInd v1,
526 VertInd v2,
527 VertInd v3,
528 VertInd v4,
529 TriInd n1,
530 TriInd n2,
531 TriInd n3,
532 TriInd n4);
533
539 void removeTriangles(const TriIndUSet& removedTriangles);
540
542 TriIndVec& VertTrisInternal();
544 const TriIndVec& VertTrisInternal() const;
546
547private:
548 /*____ Detail __*/
549 void addSuperTriangle(const Box2d<T>& box);
550 void addNewVertex(const V2d<T>& pos, TriInd iT);
551 void insertVertex(VertInd iVert);
552 void insertVertex(VertInd iVert, VertInd walkStart);
553 void ensureDelaunayByEdgeFlips(VertInd iV1, std::stack<TriInd>& triStack);
555 std::vector<Edge> insertVertex_FlipFixedEdges(VertInd iV1);
556
558 typedef tuple<IndexSizeType, IndexSizeType, TriInd, TriInd, Index>
559 TriangulatePseudoPolygonTask;
560
573 void insertEdge(
574 Edge edge,
575 Edge originalEdge,
576 EdgeVec& remaining,
577 std::vector<TriangulatePseudoPolygonTask>& tppIterations);
578
591 void insertEdgeIteration(
592 Edge edge,
593 Edge originalEdge,
594 EdgeVec& remaining,
595 std::vector<TriangulatePseudoPolygonTask>& tppIterations);
596
598 typedef tuple<Edge, EdgeVec, BoundaryOverlapCount> ConformToEdgeTask;
599
612 void conformToEdge(
613 Edge edge,
614 EdgeVec originals,
615 BoundaryOverlapCount overlaps,
616 std::vector<ConformToEdgeTask>& remaining);
617
629 void conformToEdgeIteration(
630 Edge edge,
631 const EdgeVec& originals,
632 BoundaryOverlapCount overlaps,
633 std::vector<ConformToEdgeTask>& remaining);
634
635 tuple<TriInd, VertInd, VertInd> intersectedTriangle(
636 VertInd iA,
637 const V2d<T>& a,
638 const V2d<T>& b,
639 T orientationTolerance = T(0)) const;
641 std::stack<TriInd> insertVertexInsideTriangle(VertInd v, TriInd iT);
643 std::stack<TriInd> insertVertexOnEdge(VertInd v, TriInd iT1, TriInd iT2);
644 array<TriInd, 2> trianglesAt(const V2d<T>& pos) const;
645 array<TriInd, 2>
646 walkingSearchTrianglesAt(VertInd iV, VertInd startVertex) const;
647 TriInd walkTriangles(VertInd startVertex, const V2d<T>& pos) const;
650 void edgeFlipInfo(
651 TriInd iT,
652 VertInd iV1,
653 TriInd& iTopo,
654 VertInd& iV2,
655 VertInd& iV3,
656 VertInd& iV4,
657 TriInd& n1,
658 TriInd& n2,
659 TriInd& n3,
660 TriInd& n4);
661 bool isFlipNeeded(VertInd iV1, VertInd iV2, VertInd iV3, VertInd iV4) const;
662 void changeNeighbor(TriInd iT, TriInd oldNeighbor, TriInd newNeighbor);
663 void changeNeighbor(
664 TriInd iT,
665 VertInd iVedge1,
666 VertInd iVedge2,
667 TriInd newNeighbor);
668 void triangulatePseudoPolygon(
669 const std::vector<VertInd>& poly,
670 unordered_map<Edge, TriInd>& outerTris,
671 TriInd iT,
672 TriInd iN,
673 std::vector<TriangulatePseudoPolygonTask>& iterations);
674 void triangulatePseudoPolygonIteration(
675 const std::vector<VertInd>& poly,
676 unordered_map<Edge, TriInd>& outerTris,
677 std::vector<TriangulatePseudoPolygonTask>& iterations);
678 IndexSizeType findDelaunayPoint(
679 const std::vector<VertInd>& poly,
680 IndexSizeType iA,
681 IndexSizeType iB) const;
682 TriInd addTriangle(const Triangle& t); // note: invalidates iterators!
683 TriInd addTriangle(); // note: invalidates triangle iterators!
689 void finalizeTriangulation(const TriIndUSet& removedTriangles);
690 TriIndUSet growToBoundary(std::stack<TriInd> seeds) const;
691 void fixEdge(const Edge& edge);
692 void fixEdge(const Edge& edge, const Edge& originalEdge);
698 void splitFixedEdge(const Edge& edge, const VertInd iSplitVert);
707 VertInd addSplitEdgeVertex(
708 const V2d<T>& splitVert,
709 const TriInd iT,
710 const TriInd iTopo);
720 VertInd splitFixedEdgeAt(
721 const Edge& edge,
722 const V2d<T>& splitVert,
723 const TriInd iT,
724 const TriInd iTopo);
731 void makeDummy(TriInd iT);
737 void eraseDummies();
753 unordered_map<TriInd, LayerDepth> peelLayer(
754 std::stack<TriInd> seeds,
755 LayerDepth layerDepth,
756 std::vector<LayerDepth>& triDepths) const;
757
758 void insertVertices_AsProvided(VertInd superGeomVertCount);
759 void insertVertices_Randomized(VertInd superGeomVertCount);
760 void insertVertices_KDTreeBFS(
761 VertInd superGeomVertCount,
762 V2d<T> boxMin,
763 V2d<T> boxMax);
764 std::pair<TriInd, TriInd> edgeTriangles(VertInd a, VertInd b) const;
765 bool hasEdge(VertInd a, VertInd b) const;
766 void setAdjacentTriangle(const VertInd v, const TriInd t);
767 void pivotVertexTriangleCW(VertInd v);
769 void tryAddVertexToLocator(const VertInd v);
772 void tryInitNearestPointLocator();
773
774 std::vector<TriInd> m_dummyTris;
775 TNearPointLocator m_nearPtLocator;
776 IndexSizeType m_nTargetVerts;
777 SuperGeometryType::Enum m_superGeomType;
778 VertexInsertionOrder::Enum m_vertexInsertionOrder;
779 IntersectingConstraintEdges::Enum m_intersectingEdgesStrategy;
780 T m_minDistToConstraintEdge;
781 TriIndVec m_vertTris;
782};
783
786
787namespace detail
788{
789
792{
793 typedef unsigned long long uint64;
794 uint64 m_state;
795 explicit SplitMix64RandGen(uint64 state)
796 : m_state(state)
797 {}
798 explicit SplitMix64RandGen()
799 : m_state(0)
800 {}
801 uint64 operator()()
802 {
803 uint64 z = (m_state += 0x9e3779b97f4a7c15);
804 z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
805 z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
806 return z ^ (z >> 31);
807 }
808};
809
810template <class RandomIt>
811void random_shuffle(RandomIt first, RandomIt last)
812{
814 typename std::iterator_traits<RandomIt>::difference_type i, n;
815 n = last - first;
816 for(i = n - 1; i > 0; --i)
817 {
818 std::swap(first[i], first[prng() % (i + 1)]);
819 }
820}
821
822// backport from c++11
823template <class ForwardIt, class T>
824void iota(ForwardIt first, ForwardIt last, T value)
825{
826 while(first != last)
827 {
828 *first++ = value;
829 ++value;
830 }
831}
832
833} // namespace detail
834
835//-----------------------
836// Triangulation methods
837//-----------------------
838template <typename T, typename TNearPointLocator>
839template <
840 typename TVertexIter,
841 typename TGetVertexCoordX,
842 typename TGetVertexCoordY>
844 const TVertexIter first,
845 const TVertexIter last,
846 TGetVertexCoordX getX,
847 TGetVertexCoordY getY)
848{
849 if(isFinalized())
851
852 const bool isFirstTime = vertices.empty();
853 const T max = std::numeric_limits<T>::max();
854 Box2d<T> box = {{max, max}, {-max, -max}};
855 if(vertices.empty()) // called first time
856 {
857 box = envelopBox<T>(first, last, getX, getY);
858 addSuperTriangle(box);
859 }
860 tryInitNearestPointLocator();
861
862 const VertInd nExistingVerts = static_cast<VertInd>(vertices.size());
863 const VertInd nVerts =
864 static_cast<VertInd>(nExistingVerts + std::distance(first, last));
865 // optimization, try to pre-allocate tris
866 triangles.reserve(triangles.size() + 2 * nVerts);
867 vertices.reserve(nVerts);
868 m_vertTris.reserve(nVerts);
869 for(TVertexIter it = first; it != last; ++it)
870 addNewVertex(V2d<T>::make(getX(*it), getY(*it)), noNeighbor);
871
872 switch(m_vertexInsertionOrder)
873 {
875 insertVertices_AsProvided(nExistingVerts);
876 break;
878 isFirstTime ? insertVertices_KDTreeBFS(nExistingVerts, box.min, box.max)
879 : insertVertices_Randomized(nExistingVerts);
880 break;
881 }
882}
883
884template <typename T, typename TNearPointLocator>
885template <
886 typename TEdgeIter,
887 typename TGetEdgeVertexStart,
888 typename TGetEdgeVertexEnd>
890 TEdgeIter first,
891 const TEdgeIter last,
892 TGetEdgeVertexStart getStart,
893 TGetEdgeVertexEnd getEnd)
894{
895 if(isFinalized())
897
898 std::vector<TriangulatePseudoPolygonTask> tppIterations;
899 EdgeVec remaining;
900 for(; first != last; ++first)
901 {
902 // +3 to account for super-triangle vertices
903 const Edge edge(
904 VertInd(getStart(*first) + m_nTargetVerts),
905 VertInd(getEnd(*first) + m_nTargetVerts));
906 insertEdge(edge, edge, remaining, tppIterations);
907 }
908 eraseDummies();
909}
910
911template <typename T, typename TNearPointLocator>
912template <
913 typename TEdgeIter,
914 typename TGetEdgeVertexStart,
915 typename TGetEdgeVertexEnd>
917 TEdgeIter first,
918 const TEdgeIter last,
919 TGetEdgeVertexStart getStart,
920 TGetEdgeVertexEnd getEnd)
921{
922 if(isFinalized())
924
925 tryInitNearestPointLocator();
926 // state shared between different runs for performance gains
927 std::vector<ConformToEdgeTask> remaining;
928 for(; first != last; ++first)
929 {
930 // +3 to account for super-triangle vertices
931 const Edge e(
932 VertInd(getStart(*first) + m_nTargetVerts),
933 VertInd(getEnd(*first) + m_nTargetVerts));
934 conformToEdge(e, EdgeVec(1, e), 0, remaining);
935 }
936 eraseDummies();
937}
938
939} // namespace CDT
940
941#ifndef CDT_USE_AS_COMPILED_LIBRARY
942#include "Triangulation.hpp"
943#endif
944
945#endif // header-guard
Utilities and helpers.
#define CDT_EXPORT
Export not needed in header-only mode.
Definition CDTUtils.h:40
Adapter between for KDTree and CDT.
Triangulation class - implementation.
Error thrown when duplicate vertex is detected during vertex insertion.
Base class for errors.
const SourceLocation & sourceLocation() const
Get source location from where the error was thrown.
Error(const std::string &description, const SourceLocation &srcLoc)
Constructor.
const std::string & description() const
Get error description.
Error thrown when triangulation modification is attempted after it was finalized.
Error thrown when intersecting constraint edges are detected, but triangulation is not configured to ...
Contains source location info: file, function, line.
Data structure representing a 2D constrained Delaunay triangulation.
EdgeUSet fixedEdges
triangulation's constraints (fixed edges)
void conformToEdges(TEdgeIter first, TEdgeIter last, TGetEdgeVertexStart getStart, TGetEdgeVertexEnd getEnd)
Insert constraint edges into triangulation for Conforming Delaunay Triangulation (for example see fig...
std::vector< V2d< T > > V2dVec
Vertices vector.
V2dVec vertices
triangulation's vertices
void insertEdges(TEdgeIter first, TEdgeIter last, TGetEdgeVertexStart getStart, TGetEdgeVertexEnd getEnd)
Insert constraint edges into triangulation for Constrained Delaunay Triangulation (for example see fi...
void insertVertices(TVertexIter first, TVertexIter last, TGetVertexCoordX getX, TGetVertexCoordY getY)
Insert custom point-types specified by iterator range and X/Y-getters.
unordered_map< Edge, EdgeVec > pieceToOriginals
Stores list of original edges represented by a given fixed edge.
unordered_map< Edge, BoundaryOverlapCount > overlapCount
Stores count of overlapping boundaries for a fixed edge.
TriangleVec triangles
triangulation's triangles
unsigned short LayerDepth
Type used for storing layer depths for triangles.
Definition CDT.h:40
#define CDT_SOURCE_LOCATION
Macro for getting source location.
Namespace containing triangulation functionality.
std::vector< Edge > EdgeVec
Vector of edges.
Definition CDTUtils.h:245
unordered_set< Edge > EdgeUSet
Hash table of edges.
Definition CDTUtils.h:246
std::vector< TriInd > TriIndVec
Vector of triangle indices.
Definition CDTUtils.h:155
Box2d< T > envelopBox(TVertexIter first, TVertexIter last, TGetVertexCoordX getX, TGetVertexCoordY getY)
Bounding box of a collection of custom 2D points given coordinate getters.
Definition CDTUtils.h:187
IndexSizeType VertInd
Vertex index.
Definition CDTUtils.h:142
unordered_set< TriInd > TriIndUSet
Hash table of triangles.
Definition CDTUtils.h:247
IndexSizeType TriInd
Triangle index.
Definition CDTUtils.h:144
std::vector< Triangle > TriangleVec
Vector of triangles.
Definition CDTUtils.h:308
2D bounding box
Definition CDTUtils.h:162
V2d< T > max
max box corner
Definition CDTUtils.h:164
V2d< T > min
min box corner
Definition CDTUtils.h:163
Edge connecting two vertices: vertex with smaller index is always first.
Definition CDTUtils.h:209
VertInd v2() const
V2 getter.
Definition CDTUtils.hpp:62
VertInd v1() const
V1 getter.
Definition CDTUtils.hpp:57
Enum of strategies for treating intersecting constraint edges.
@ TryResolve
attempt to resolve constraint edge intersections
@ NotAllowed
constraint edge intersections are not allowed
@ DontCheck
No checks: slightly faster but less safe.
Enum of what type of geometry used to embed triangulation into.
Enum
The Enum itself.
@ SuperTriangle
conventional super-triangle
@ Custom
user-specified custom geometry (e.g., grid)
Triangulation triangle (counter-clockwise winding)
Definition CDTUtils.h:259
2D vector
Definition CDTUtils.h:96
Enum of strategies specifying order in which a range of vertices is inserted.
@ AsProvided
insert vertices in same order they are provided
@ Auto
Automatic insertion order optimized for better performance.
SplitMix64 pseudo-random number generator.