9#ifndef CDT_pDqrlveWIOrIWeUCkPqX
10#define CDT_pDqrlveWIOrIWeUCkPqX
13#include "portable_nth_element.hpp"
21CDT_ENSURE_PRECISE_MATH_FOR_CONSTRUCTIONS
26typedef std::deque<TriInd> TriDeque;
34const std::size_t nTargetVerts = 0;
40const float minDistToConstraintEdge(0);
46template <
typename T,
typename TNearPo
intLocator>
48 : m_nTargetVerts(detail::defaults::nTargetVerts)
49 , m_superGeomType(detail::defaults::superGeomType)
50 , m_vertexInsertionOrder(detail::defaults::vertexInsertionOrder)
51 , m_intersectingEdgesStrategy(detail::defaults::intersectingEdgesStrategy)
52 , m_minDistToConstraintEdge(detail::defaults::minDistToConstraintEdge)
53#ifdef CDT_ENABLE_CALLBACK_HANDLER
54 , m_callbackHandler(NULL)
58template <
typename T,
typename TNearPo
intLocator>
61 : m_nTargetVerts(detail::defaults::nTargetVerts)
62 , m_superGeomType(detail::defaults::superGeomType)
63 , m_vertexInsertionOrder(vertexInsertionOrder)
64 , m_intersectingEdgesStrategy(detail::defaults::intersectingEdgesStrategy)
65 , m_minDistToConstraintEdge(detail::defaults::minDistToConstraintEdge)
66#ifdef CDT_ENABLE_CALLBACK_HANDLER
67 , m_callbackHandler(NULL)
71template <
typename T,
typename TNearPo
intLocator>
75 const T minDistToConstraintEdge)
76 : m_nTargetVerts(detail::defaults::nTargetVerts)
77 , m_superGeomType(detail::defaults::superGeomType)
78 , m_vertexInsertionOrder(vertexInsertionOrder)
79 , m_intersectingEdgesStrategy(intersectingEdgesStrategy)
80 , m_minDistToConstraintEdge(minDistToConstraintEdge)
81#ifdef CDT_ENABLE_CALLBACK_HANDLER
82 , m_callbackHandler(NULL)
86template <
typename T,
typename TNearPo
intLocator>
89 const TNearPointLocator& nearPtLocator,
91 const T minDistToConstraintEdge)
92 : m_nearPtLocator(nearPtLocator)
93 , m_nTargetVerts(detail::defaults::nTargetVerts)
94 , m_superGeomType(detail::defaults::superGeomType)
95 , m_vertexInsertionOrder(vertexInsertionOrder)
96 , m_intersectingEdgesStrategy(intersectingEdgesStrategy)
97 , m_minDistToConstraintEdge(minDistToConstraintEdge)
98#ifdef CDT_ENABLE_CALLBACK_HANDLER
99 , m_callbackHandler(NULL)
103template <
typename T,
typename TNearPo
intLocator>
115 finalizeTriangulation(toErase);
118template <
typename T,
typename TNearPo
intLocator>
121 assert(m_vertTris[0] != noNeighbor);
122 const std::stack<TriInd> seed(std::deque<TriInd>(1, m_vertTris[0]));
123 const TriIndUSet toErase = growToBoundary(seed);
124 finalizeTriangulation(toErase);
127template <
typename T,
typename TNearPo
intLocator>
133 for(std::size_t iT = 0; iT !=
triangles.size(); ++iT)
135 if(triDepths[iT] % 2 == 0)
136 toErase.insert(
static_cast<TriInd>(iT));
138 finalizeTriangulation(toErase);
147template <
typename T,
typename TNearPo
intLocator>
151 if(removedTriangles.empty())
157 if(removedTriangles.count(iT))
159 triIndMap[iT] = iTnew;
170 for(NeighborsArr3::iterator n = nn.begin(); n != nn.end(); ++n)
172 if(removedTriangles.count(*n))
176 else if(*n != noNeighbor)
184template <
typename T,
typename TNearPo
intLocator>
190template <
typename T,
typename TNearPo
intLocator>
196template <
typename T,
typename TNearPo
intLocator>
197void Triangulation<T, TNearPointLocator>::finalizeTriangulation(
205 vertices.begin(), vertices.begin() + nSuperTriangleVertices);
209 typedef CDT::EdgeUSet::const_iterator It;
210 for(It e = fixedEdges.begin(); e != fixedEdges.end(); ++e)
214 fixedEdges = updatedFixedEdges;
217 unordered_map<Edge, BoundaryOverlapCount> updatedOverlapCount;
218 typedef unordered_map<Edge, BoundaryOverlapCount>::const_iterator
220 for(It it = overlapCount.begin(); it != overlapCount.end(); ++it)
222 updatedOverlapCount.insert(
226 overlapCount = updatedOverlapCount;
229 unordered_map<Edge, EdgeVec> updatedPieceToOriginals;
230 typedef unordered_map<Edge, EdgeVec>::const_iterator It;
231 for(It it = pieceToOriginals.begin(); it != pieceToOriginals.end();
235 for(EdgeVec::iterator eeIt = ee.begin(); eeIt != ee.end();
240 updatedPieceToOriginals.insert(
243 pieceToOriginals = updatedPieceToOriginals;
247 removeTriangles(removedTriangles);
251 for(TriangleVec::iterator t = triangles.begin(); t != triangles.end();
255 for(VerticesArr3::iterator v = vv.begin(); v != vv.end(); ++v)
257 *v -= nSuperTriangleVertices;
263template <
typename T,
typename TNearPo
intLocator>
266 m_nearPtLocator.initialize(
vertices);
267 m_nTargetVerts = verticesCount();
271template <
typename T,
typename TNearPo
intLocator>
272TriIndUSet Triangulation<T, TNearPointLocator>::growToBoundary(
273 std::stack<TriInd> seeds)
const
276 while(!seeds.empty())
278 const TriInd iT = seeds.top();
280 traversed.insert(iT);
285 if(fixedEdges.count(opEdge))
288 if(iN != noNeighbor && traversed.count(iN) == 0)
295template <
typename T,
typename TNearPo
intLocator>
296TriInd Triangulation<T, TNearPointLocator>::addTriangle(
const Triangle& t)
298 const TriInd iT = trianglesCount();
299 triangles.push_back(t);
303template <
typename T,
typename TNearPo
intLocator>
304TriInd Triangulation<T, TNearPointLocator>::addTriangle()
309template <
typename T,
typename TNearPo
intLocator>
310VertInd Triangulation<T, TNearPointLocator>::verticesCount()
const
312 return static_cast<VertInd>(vertices.size());
315template <
typename T,
typename TNearPo
intLocator>
316TriInd Triangulation<T, TNearPointLocator>::trianglesCount()
const
318 return static_cast<TriInd>(triangles.size());
321template <
typename T,
typename TNearPo
intLocator>
323 const std::vector<Edge>& edges)
328template <
typename T,
typename TNearPo
intLocator>
330 const std::vector<Edge>& edges)
335template <
typename T,
typename TNearPo
intLocator>
336void Triangulation<T, TNearPointLocator>::fixEdge(
const Edge& edge)
338 if(!fixedEdges.insert(edge).second)
340 ++overlapCount[edge];
348template <
typename T,
typename Allocator1>
349void insert_unique(std::vector<T, Allocator1>& to,
const T& elem)
351 if(std::find(to.begin(), to.end(), elem) == to.end())
358template <
typename T,
typename Allocator1,
typename Allocator2>
360 std::vector<T, Allocator1>& to,
361 const std::vector<T, Allocator2>& from)
363 typedef typename std::vector<T, Allocator2>::const_iterator Cit;
364 to.reserve(to.size() + from.size());
365 for(Cit cit = from.begin(); cit != from.end(); ++cit)
367 insert_unique(to, *cit);
373template <
typename T,
typename TNearPo
intLocator>
374void Triangulation<T, TNearPointLocator>::splitFixedEdge(
379 const Edge half1(edge.v1(), iSplitVert);
380 const Edge half2(iSplitVert, edge.v2());
382 fixedEdges.erase(edge);
386 typedef unordered_map<Edge, BoundaryOverlapCount>::const_iterator It;
387 const It overlapIt = overlapCount.find(edge);
388 if(overlapIt != overlapCount.end())
390 overlapCount[half1] += overlapIt->second;
391 overlapCount[half2] += overlapIt->second;
392 overlapCount.erase(overlapIt);
396 const unordered_map<Edge, EdgeVec>::const_iterator originalsIt =
397 pieceToOriginals.find(edge);
398 if(originalsIt != pieceToOriginals.end())
400 newOriginals = originalsIt->second;
401 pieceToOriginals.erase(originalsIt);
403 detail::insert_unique(pieceToOriginals[half1], newOriginals);
404 detail::insert_unique(pieceToOriginals[half2], newOriginals);
407template <
typename T,
typename TNearPo
intLocator>
408VertInd Triangulation<T, TNearPointLocator>::addSplitEdgeVertex(
414 const VertInd iSplitVert = verticesCount();
415 addNewVertex(splitVert, noNeighbor);
417#ifdef CDT_ENABLE_CALLBACK_HANDLER
418 if(m_callbackHandler)
420 m_callbackHandler->onAddVertexStart(
425 std::stack<TriInd> triStack = insertVertexOnEdge(iSplitVert, iT, iTopo);
426 tryAddVertexToLocator(iSplitVert);
427 ensureDelaunayByEdgeFlips(iSplitVert, triStack);
431template <
typename T,
typename TNearPo
intLocator>
432VertInd Triangulation<T, TNearPointLocator>::splitFixedEdgeAt(
438 const VertInd iSplitVert = addSplitEdgeVertex(splitVert, iT, iTopo);
439 splitFixedEdge(edge, iSplitVert);
443template <
typename T,
typename TNearPo
intLocator>
444bool Triangulation<T, TNearPointLocator>::isEdgeSplitVertexValid(
458 splitVert, vertices[tL.vertices[sL]], vertices[tL.vertices[
ccw(sL)]]);
459 if(side == PtLineLocation::OnLine)
461 return splitVert != vertices[iVL] && splitVert != vertices[iVR];
463 const Triangle& t = side == PtLineLocation::Left ? tL : triangles[iTopo];
470 const V2d<T>& from = vertices[t.vertices[s]];
471 const V2d<T>& to = vertices[t.vertices[
ccw(s)]];
472 const V2d<T>& apex = vertices[t.vertices[
cw(s)]];
473 return locatePointLine(splitVert, to, apex) != PtLineLocation::Right &&
477template <
typename T,
typename TNearPo
intLocator>
478Edge Triangulation<T, TNearPointLocator>::originalInputEdge(
const Edge& e)
const
481 pieceToOriginals.count(e) ? pieceToOriginals.at(e).front() : e;
483 VertInd(orig.v1() - m_nTargetVerts),
484 VertInd(orig.v2() - m_nTargetVerts));
487template <
typename T,
typename TNearPo
intLocator>
489Triangulation<T, TNearPointLocator>::triangleAt(
const TriInd iT)
const
491 if(iT >= triangles.size())
492 handleException(
Error(
494 ?
"Attempted reading no-neighbor sentinel value triangle"
495 :
"Triangle index " + CDT::to_string(iT) +
" out of range " +
496 CDT::to_string(triangles.size()),
497 CDT_SOURCE_LOCATION));
498 return triangles[iT];
501template <
typename T,
typename TNearPo
intLocator>
502void Triangulation<T, TNearPointLocator>::fixEdge(
504 const Edge& originalEdge)
507 if(edge != originalEdge)
508 detail::insert_unique(pieceToOriginals[edge], originalEdge);
515T lerp(
const T& a,
const T& b,
const T t)
517 return (T(1) - t) * a + t * b;
522V2d<T> intersectionPosition(
528 using namespace predicates::adaptive;
532 const T a_cd = orient2d(c.x, c.y, d.x, d.y, a.x, a.y);
533 const T b_cd = orient2d(c.x, c.y, d.x, d.y, b.x, b.y);
534 const T t_ab = a_cd / (a_cd - b_cd);
536 const T c_ab = orient2d(a.x, a.y, b.x, b.y, c.x, c.y);
537 const T d_ab = orient2d(a.x, a.y, b.x, b.y, d.x, d.y);
538 const T t_cd = c_ab / (c_ab - d_ab);
541 std::fabs(a.x - b.x) < std::fabs(c.x - d.x) ? lerp(a.x, b.x, t_ab)
542 : lerp(c.x, d.x, t_cd),
543 std::fabs(a.y - b.y) < std::fabs(c.y - d.y) ? lerp(a.y, b.y, t_ab)
544 : lerp(c.y, d.y, t_cd));
549template <
typename T,
typename TNearPo
intLocator>
550void Triangulation<T, TNearPointLocator>::insertEdgeIteration(
552 const Edge originalEdge,
554 std::vector<TriangulatePseudoPolygonTask>& tppIterations)
563 fixEdge(edge, originalEdge);
567 const V2d<T>& a = vertices[iA];
568 const V2d<T>& b = vertices[iB];
569 const T distanceTolerance =
570 m_minDistToConstraintEdge == T(0)
572 : m_minDistToConstraintEdge *
distance(a, b);
577 tie(iT, iVL, iVR) = intersectedTriangle(iA, a, b, distanceTolerance);
581 const Edge edgePart(iA, iVL);
582 fixEdge(edgePart, originalEdge);
583 remaining.push_back(
Edge(iVL, iB));
587 std::vector<TriInd> intersected(1, iT);
588 std::vector<VertInd> polyL, polyR;
591 polyL.push_back(iVL);
594 polyR.push_back(iVR);
595 unordered_map<Edge, TriInd> outerTris;
600 while(!t.containsVertex(iB))
603 const Triangle& tOpo = triangleAt(iTopo);
606 switch(m_intersectingEdgesStrategy)
609 if(fixedEdges.count(
Edge(iVL, iVR)))
611 originalInputEdge(originalEdge),
612 originalInputEdge(
Edge(iVL, iVR)),
613 CDT_SOURCE_LOCATION));
617 if(!fixedEdges.count(
Edge(iVL, iVR)))
620 const V2d<T> newV = detail::intersectionPosition(
621 vertices[iA], vertices[iB], vertices[iVL], vertices[iVR]);
622 if(!isEdgeSplitVertexValid(newV, iT, iTopo, iVL, iVR))
624 originalInputEdge(originalEdge),
625 originalInputEdge(
Edge(iVL, iVR)),
626 CDT_SOURCE_LOCATION));
628 splitFixedEdgeAt(
Edge(iVL, iVR), newV, iT, iTopo);
631 remaining.push_back(
Edge(iA, iNewVert));
632 remaining.push_back(
Edge(iNewVert, iB));
636 assert(!fixedEdges.count(
Edge(iVL, iVR)));
642 if(loc == PtLineLocation::Left)
644 const Edge e(polyL.back(), iVopo);
646 if(!outerTris.insert(std::make_pair(e, outer)).second)
647 outerTris.at(e) = noNeighbor;
648 polyL.push_back(iVopo);
652 else if(loc == PtLineLocation::Right)
654 const Edge e(polyR.back(), iVopo);
656 if(!outerTris.insert(std::make_pair(e, outer)).second)
657 outerTris.at(e) = noNeighbor;
658 polyR.push_back(iVopo);
665 intersected.push_back(iTopo);
674 assert(!intersected.empty());
677 if(m_vertTris[iA] == intersected.front())
678 pivotVertexTriangleCW(iA);
679 if(m_vertTris[iB] == intersected.back())
680 pivotVertexTriangleCW(iB);
683#ifdef CDT_ENABLE_CALLBACK_HANDLER
684 if(m_callbackHandler)
686 m_callbackHandler->onReTriangulatePolygon(intersected);
691 std::reverse(polyR.begin(), polyR.end());
696 assert(intersected.size() >= 2);
697 const TriInd iTL = intersected.back();
698 intersected.pop_back();
699 const TriInd iTR = intersected.back();
700 intersected.pop_back();
702 triangulatePseudoPolygon(
703 polyL, outerTris, iTL, iTR, intersected, tppIterations);
704 triangulatePseudoPolygon(
705 polyR, outerTris, iTR, iTL, intersected, tppIterations);
706 assert(intersected.empty());
712 const Edge edgePart(iA, iB);
713 fixEdge(edgePart, originalEdge);
714 remaining.push_back(
Edge(iB, edge.v2()));
719 fixEdge(edge, originalEdge);
723template <
typename T,
typename TNearPo
intLocator>
724void Triangulation<T, TNearPointLocator>::insertEdge(
726 const Edge originalEdge,
728 std::vector<TriangulatePseudoPolygonTask>& tppIterations)
730#ifdef CDT_ENABLE_CALLBACK_HANDLER
731 if(m_callbackHandler)
733 m_callbackHandler->onAddEdgeStart(edge);
739 remaining.push_back(edge);
740 while(!remaining.empty())
742 edge = remaining.back();
743 remaining.pop_back();
744 insertEdgeIteration(edge, originalEdge, remaining, tppIterations);
748template <
typename T,
typename TNearPo
intLocator>
749void Triangulation<T, TNearPointLocator>::conformToEdgeIteration(
752 BoundaryOverlapCount overlaps,
753 std::vector<ConformToEdgeTask>& remaining)
764 overlapCount[edge] = overlaps;
766 if(!originals.empty() && edge != originals.front())
768 detail::insert_unique(pieceToOriginals[edge], originals);
773 const V2d<T>& a = vertices[iA];
774 const V2d<T>& b = vertices[iB];
775 const T distanceTolerance =
776 m_minDistToConstraintEdge == T(0)
778 : m_minDistToConstraintEdge *
distance(a, b);
781 tie(iT, iVleft, iVright) = intersectedTriangle(iA, a, b, distanceTolerance);
785 const Edge edgePart(iA, iVleft);
788 overlapCount[edgePart] = overlaps;
789 detail::insert_unique(pieceToOriginals[edgePart], originals);
790#ifdef CDT_CXX11_IS_SUPPORTED
791 remaining.emplace_back(
Edge(iVleft, iB), originals, overlaps);
793 remaining.push_back(make_tuple(
Edge(iVleft, iB), originals, overlaps));
800 while(std::find(t.vertices.begin(), t.vertices.end(), iB) ==
804 const Triangle& tOpo = triangleAt(iTopo);
806 const V2d<T> vOpo = vertices[iVopo];
808 switch(m_intersectingEdgesStrategy)
811 if(fixedEdges.count(
Edge(iVleft, iVright)))
813 originalInputEdge(edge),
814 originalInputEdge(
Edge(iVleft, iVright)),
815 CDT_SOURCE_LOCATION));
819 if(!fixedEdges.count(
Edge(iVleft, iVright)))
822 const V2d<T> newV = detail::intersectionPosition(
827 if(!isEdgeSplitVertexValid(newV, iT, iTopo, iVleft, iVright))
829 originalInputEdge(edge),
830 originalInputEdge(
Edge(iVleft, iVright)),
831 CDT_SOURCE_LOCATION));
833 splitFixedEdgeAt(
Edge(iVleft, iVright), newV, iT, iTopo);
834#ifdef CDT_CXX11_IS_SUPPORTED
835 remaining.emplace_back(
Edge(iNewVert, iB), originals, overlaps);
836 remaining.emplace_back(
Edge(iA, iNewVert), originals, overlaps);
839 make_tuple(
Edge(iNewVert, iB), originals, overlaps));
841 make_tuple(
Edge(iA, iNewVert), originals, overlaps));
846 assert(!fixedEdges.count(
Edge(iVleft, iVright)));
855 if(loc == PtLineLocation::Left)
860 else if(loc == PtLineLocation::Right)
872#ifdef CDT_CXX11_IS_SUPPORTED
873 remaining.emplace_back(
Edge(iB, edge.v2()), originals, overlaps);
876 make_tuple(
Edge(iB, edge.v2()), originals, overlaps));
881 const VertInd iMid = verticesCount();
882 const V2d<T>& start = vertices[iA];
883 const V2d<T>& end = vertices[iB];
885 V2d<T>((start.x + end.x) / T(2), (start.y + end.y) / T(2)), noNeighbor);
887#ifdef CDT_ENABLE_CALLBACK_HANDLER
888 if(m_callbackHandler)
890 m_callbackHandler->onAddVertexStart(
895 const std::vector<Edge> flippedFixedEdges =
896 insertVertex_FlipFixedEdges(iMid);
898#ifdef CDT_CXX11_IS_SUPPORTED
899 remaining.emplace_back(
Edge(iMid, iB), originals, overlaps);
900 remaining.emplace_back(
Edge(iA, iMid), originals, overlaps);
902 remaining.push_back(make_tuple(
Edge(iMid, iB), originals, overlaps));
903 remaining.push_back(make_tuple(
Edge(iA, iMid), originals, overlaps));
908 for(std::vector<Edge>::const_iterator it = flippedFixedEdges.begin();
909 it != flippedFixedEdges.end();
912 const Edge& flippedFixedEdge = *it;
913 fixedEdges.erase(flippedFixedEdge);
915 BoundaryOverlapCount prevOverlaps = 0;
916 const unordered_map<Edge, BoundaryOverlapCount>::const_iterator
917 overlapsIt = overlapCount.find(flippedFixedEdge);
918 if(overlapsIt != overlapCount.end())
920 prevOverlaps = overlapsIt->second;
921 overlapCount.erase(overlapsIt);
924 EdgeVec prevOriginals(1, flippedFixedEdge);
925 const unordered_map<Edge, EdgeVec>::const_iterator originalsIt =
926 pieceToOriginals.find(flippedFixedEdge);
927 if(originalsIt != pieceToOriginals.end())
929 prevOriginals = originalsIt->second;
931#ifdef CDT_CXX11_IS_SUPPORTED
932 remaining.emplace_back(flippedFixedEdge, prevOriginals, prevOverlaps);
935 make_tuple(flippedFixedEdge, prevOriginals, prevOverlaps));
940template <
typename T,
typename TNearPo
intLocator>
941void Triangulation<T, TNearPointLocator>::conformToEdge(
944 BoundaryOverlapCount overlaps,
945 std::vector<ConformToEdgeTask>& remaining)
947#ifdef CDT_ENABLE_CALLBACK_HANDLER
948 if(m_callbackHandler)
950 m_callbackHandler->onAddEdgeStart(edge);
956#ifdef CDT_CXX11_IS_SUPPORTED
957 remaining.emplace_back(edge, originals, overlaps);
959 remaining.push_back(make_tuple(edge, originals, overlaps));
961 while(!remaining.empty())
963 tie(edge, originals, overlaps) = remaining.back();
964 remaining.pop_back();
965 conformToEdgeIteration(edge, originals, overlaps, remaining);
979template <
typename T,
typename TNearPo
intLocator>
980tuple<TriInd, VertInd, VertInd>
981Triangulation<T, TNearPointLocator>::intersectedTriangle(
985 const T orientationTolerance)
const
987 const TriInd startTri = m_vertTris[iA];
994 const T orientP2 =
orient2D(vertices[iP2], a, b);
996 if(locP2 == PtLineLocation::Right)
999 const T orientP1 =
orient2D(vertices[iP1], a, b);
1001 if(locP1 == PtLineLocation::OnLine)
1003 return make_tuple(noNeighbor, iP1, iP1);
1005 if(locP1 == PtLineLocation::Left)
1007 if(orientationTolerance)
1011 if(std::abs(orientP1) <= std::abs(orientP2))
1013 closestOrient = orientP1;
1018 closestOrient = orientP2;
1022 closestOrient, orientationTolerance) ==
1023 PtLineLocation::OnLine)
1025 return make_tuple(noNeighbor, iClosestP, iClosestP);
1028 return make_tuple(iT, iP1, iP2);
1031 iT = t.next(iA).first;
1032 }
while(iT != startTri);
1034 handleException(
Error(
1035 "Could not find vertex triangle intersected by an edge.",
1036 CDT_SOURCE_LOCATION));
1037 return make_tuple(noNeighbor, noVertex, noVertex);
1040template <
typename T,
typename TNearPo
intLocator>
1041void Triangulation<T, TNearPointLocator>::addSuperTriangle(
const Box2d<T>& box)
1043 m_nTargetVerts = nSuperTriangleVertices;
1047 (box.min.x + box.max.x) / T(2), (box.min.y + box.max.y) / T(2));
1048 const T w = box.max.x - box.min.x;
1049 const T h = box.max.y - box.min.y;
1050 T r = std::max(w, h);
1055 r = std::max(T(2) * r, T(1));
1061 while(center.y <= center.y - r)
1065 const T R = T(2) * r;
1066 const T cos_30_deg = T(0.8660254037844386);
1067 const T shiftX = R * cos_30_deg;
1068 const V2d<T> posV1(center.x - shiftX, center.y - r);
1069 const V2d<T> posV2(center.x + shiftX, center.y - r);
1070 const V2d<T> posV3(center.x, center.y + R);
1071 addNewVertex(posV1,
TriInd(0));
1072 addNewVertex(posV2,
TriInd(0));
1073 addNewVertex(posV3,
TriInd(0));
1075#ifdef CDT_ENABLE_CALLBACK_HANDLER
1076 if(m_callbackHandler)
1078 m_callbackHandler->onAddSuperTriangle();
1087 m_nearPtLocator.initialize(vertices);
1091template <
typename T,
typename TNearPo
intLocator>
1092void Triangulation<T, TNearPointLocator>::addNewVertex(
1096 vertices.push_back(pos);
1097 m_vertTris.push_back(iT);
1100template <
typename T,
typename TNearPo
intLocator>
1102Triangulation<T, TNearPointLocator>::insertVertex_FlipFixedEdges(
1105 std::vector<Edge> flippedFixedEdges;
1107 const V2d<T>& v1 = vertices[iV1];
1108 const VertInd startVertex = m_nearPtLocator.nearPoint(v1, vertices);
1109 array<TriInd, 2> trisAt = walkingSearchTrianglesAt(iV1, startVertex);
1110 std::stack<TriInd> triStack =
1111 trisAt[1] == noNeighbor ? insertVertexInsideTriangle(iV1, trisAt[0])
1112 : insertVertexOnEdge(iV1, trisAt[0], trisAt[1]);
1114 TriInd iTopo, n1, n2, n3, n4;
1116 while(!triStack.empty())
1118 const TriInd iT = triStack.top();
1121 edgeFlipInfo(iT, iV1, iTopo, iV2, iV3, iV4, n1, n2, n3, n4);
1122 if(iTopo != noNeighbor && isFlipNeeded(iV1, iV2, iV3, iV4))
1125 const Edge flippedEdge(iV2, iV4);
1126 if(!fixedEdges.empty() &&
1127 fixedEdges.find(flippedEdge) != fixedEdges.end())
1129 flippedFixedEdges.push_back(flippedEdge);
1132 flipEdge(iT, iTopo, iV1, iV2, iV3, iV4, n1, n2, n3, n4);
1134 triStack.push(iTopo);
1138 tryAddVertexToLocator(iV1);
1139 return flippedFixedEdges;
1142template <
typename T,
typename TNearPo
intLocator>
1143void Triangulation<T, TNearPointLocator>::insertVertex(
1144 const VertInd iVert,
1145 const VertInd walkStart)
1147#ifdef CDT_ENABLE_CALLBACK_HANDLER
1148 if(m_callbackHandler)
1150 m_callbackHandler->onAddVertexStart(iVert, AddVertexType::UserInput);
1154 const array<TriInd, 2> trisAt = walkingSearchTrianglesAt(iVert, walkStart);
1155 std::stack<TriInd> triStack =
1156 trisAt[1] == noNeighbor
1157 ? insertVertexInsideTriangle(iVert, trisAt[0])
1158 : insertVertexOnEdge(iVert, trisAt[0], trisAt[1], true);
1159 ensureDelaunayByEdgeFlips(iVert, triStack);
1162template <
typename T,
typename TNearPo
intLocator>
1163void Triangulation<T, TNearPointLocator>::insertVertex(
const VertInd iVert)
1165 const V2d<T>& v = vertices[iVert];
1166 const VertInd walkStart = m_nearPtLocator.nearPoint(v, vertices);
1167 insertVertex(iVert, walkStart);
1168 tryAddVertexToLocator(iVert);
1171template <
typename T,
typename TNearPo
intLocator>
1172void Triangulation<T, TNearPointLocator>::ensureDelaunayByEdgeFlips(
1174 std::stack<TriInd>& triStack)
1176 TriInd iTopo, n1, n2, n3, n4;
1178 while(!triStack.empty())
1180 const TriInd iT = triStack.top();
1183 edgeFlipInfo(iT, iV1, iTopo, iV2, iV3, iV4, n1, n2, n3, n4);
1184 if(iTopo != noNeighbor && isFlipNeeded(iV1, iV2, iV3, iV4))
1186 flipEdge(iT, iTopo, iV1, iV2, iV3, iV4, n1, n2, n3, n4);
1188 triStack.push(iTopo);
1206template <
typename T,
typename TNearPo
intLocator>
1207void Triangulation<T, TNearPointLocator>::edgeFlipInfo(
1224 const Triangle& t = triangles[iT];
1225 if(t.vertices[0] == iV1)
1227 iV2 = t.vertices[1];
1228 iV4 = t.vertices[2];
1229 n1 = t.neighbors[0];
1230 n3 = t.neighbors[2];
1231 iTopo = t.neighbors[1];
1233 else if(t.vertices[1] == iV1)
1235 iV2 = t.vertices[2];
1236 iV4 = t.vertices[0];
1237 n1 = t.neighbors[1];
1238 n3 = t.neighbors[0];
1239 iTopo = t.neighbors[2];
1243 iV2 = t.vertices[0];
1244 iV4 = t.vertices[1];
1245 n1 = t.neighbors[2];
1246 n3 = t.neighbors[1];
1247 iTopo = t.neighbors[0];
1249 if(iTopo == noNeighbor)
1251 const Triangle& tOpo = triangles[iTopo];
1252 if(tOpo.neighbors[0] == iT)
1254 iV3 = tOpo.vertices[2];
1255 n2 = tOpo.neighbors[1];
1256 n4 = tOpo.neighbors[2];
1258 else if(tOpo.neighbors[1] == iT)
1260 iV3 = tOpo.vertices[0];
1261 n2 = tOpo.neighbors[2];
1262 n4 = tOpo.neighbors[0];
1266 iV3 = tOpo.vertices[1];
1267 n2 = tOpo.neighbors[0];
1268 n4 = tOpo.neighbors[1];
1295template <
typename T,
typename TNearPo
intLocator>
1296bool Triangulation<T, TNearPointLocator>::isFlipNeeded(
1300 const VertInd iV4)
const
1302 if(fixedEdges.count(Edge(iV2, iV4)))
1304 const V2d<T>& v1 = vertices[iV1];
1305 const V2d<T>& v2 = vertices[iV2];
1306 const V2d<T>& v3 = vertices[iV3];
1307 const V2d<T>& v4 = vertices[iV4];
1308 if(m_superGeomType == SuperGeometryType::SuperTriangle)
1365template <
typename T,
typename TNearPo
intLocator>
1370#ifdef CDT_ENABLE_CALLBACK_HANDLER
1371 if(m_callbackHandler)
1373 m_callbackHandler->onFlipEdge(iT, iTopo);
1379 const array<TriInd, 3>& triNs = t.
neighbors;
1380 const array<TriInd, 3>& triOpoNs = tOpo.
neighbors;
1381 const array<VertInd, 3>& triVs = t.
vertices;
1382 const array<VertInd, 3>& triOpoVs = tOpo.
vertices;
1387 const TriInd n1 = triNs[i];
1390 const VertInd v3 = triOpoVs[i];
1392 const TriInd n4 = triOpoNs[i];
1398 changeNeighbor(n1, iT, iTopo);
1399 changeNeighbor(n4, iTopo, iT);
1405 setAdjacentTriangle(v4, iT);
1406 setAdjacentTriangle(v2, iTopo);
1426template <
typename T,
typename TNearPo
intLocator>
1439#ifdef CDT_ENABLE_CALLBACK_HANDLER
1440 if(m_callbackHandler)
1442 m_callbackHandler->onFlipEdge(iT, iTopo);
1450 changeNeighbor(n1, iT, iTopo);
1451 changeNeighbor(n4, iTopo, iT);
1457 setAdjacentTriangle(v4, iT);
1458 setAdjacentTriangle(v2, iTopo);
1478template <
typename T,
typename TNearPo
intLocator>
1480Triangulation<T, TNearPointLocator>::insertVertexInsideTriangle(
1484 const TriInd iNewT1 = addTriangle();
1485 const TriInd iNewT2 = addTriangle();
1487#ifdef CDT_ENABLE_CALLBACK_HANDLER
1488 if(m_callbackHandler)
1490 m_callbackHandler->onInsertVertexInsideTriangle(iT, iNewT1, iNewT2);
1494 Triangle& t = triangles[iT];
1495 const array<VertInd, 3> vv = t.vertices;
1496 const array<TriInd, 3> nn = t.neighbors;
1497 const VertInd v1 = vv[0], v2 = vv[1], v3 = vv[2];
1498 const TriInd n1 = nn[0], n2 = nn[1], n3 = nn[2];
1501 triangles[iNewT1] = Triangle(arr3(v2, v3, v), arr3(n2, iNewT2, iT));
1502 triangles[iNewT2] = Triangle(arr3(v3, v1, v), arr3(n3, iT, iNewT1));
1503 t = Triangle(arr3(v1, v2, v), arr3(n1, iNewT1, iNewT2));
1505 setAdjacentTriangle(v, iT);
1506 setAdjacentTriangle(v3, iNewT1);
1508 changeNeighbor(n2, iT, iNewT1);
1509 changeNeighbor(n3, iT, iNewT2);
1511 std::stack<TriInd> newTriangles;
1512 newTriangles.push(iT);
1513 newTriangles.push(iNewT1);
1514 newTriangles.push(iNewT2);
1515 return newTriangles;
1531template <
typename T,
typename TNearPo
intLocator>
1532std::stack<TriInd> Triangulation<T, TNearPointLocator>::insertVertexOnEdge(
1536 const bool doHandleFixedSplitEdge)
1538 const TriInd iTnew1 = addTriangle();
1539 const TriInd iTnew2 = addTriangle();
1541#ifdef CDT_ENABLE_CALLBACK_HANDLER
1542 if(m_callbackHandler)
1544 m_callbackHandler->onInsertVertexOnEdge(iT1, iT2, iTnew1, iTnew2);
1548 Triangle& t1 = triangles[iT1];
1549 Triangle& t2 = triangles[iT2];
1551 const VertInd v1 = t1.vertices[i];
1553 const TriInd n1 = t1.neighbors[i];
1554 const TriInd n4 = t1.neighbors[
cw(i)];
1556 const VertInd v3 = t2.vertices[i];
1558 const TriInd n3 = t2.neighbors[i];
1559 const TriInd n2 = t2.neighbors[
cw(i)];
1561 t1 = Triangle(
arr3(v, v1, v2),
arr3(iTnew1, n1, iT2));
1562 t2 = Triangle(
arr3(v, v2, v3),
arr3(iT1, n2, iTnew2));
1563 triangles[iTnew1] = Triangle(
arr3(v, v4, v1),
arr3(iTnew2, n4, iT1));
1564 triangles[iTnew2] = Triangle(
arr3(v, v3, v4),
arr3(iT2, n3, iTnew1));
1566 setAdjacentTriangle(v, iT1);
1567 setAdjacentTriangle(v4, iTnew1);
1569 changeNeighbor(n4, iT1, iTnew1);
1570 changeNeighbor(n3, iT2, iTnew2);
1572 if(doHandleFixedSplitEdge)
1574 const Edge sharedEdge(v2, v4);
1575 if(fixedEdges.count(sharedEdge))
1576 splitFixedEdge(sharedEdge, v);
1579 std::stack<TriInd> newTriangles;
1580 newTriangles.push(iT1);
1581 newTriangles.push(iTnew2);
1582 newTriangles.push(iT2);
1583 newTriangles.push(iTnew1);
1584 return newTriangles;
1587template <
typename T,
typename TNearPo
intLocator>
1589Triangulation<T, TNearPointLocator>::trianglesAt(
const V2d<T>& pos)
const
1591 array<TriInd, 2> out = {noNeighbor, noNeighbor};
1592 for(TriInd i =
TriInd(0); i <
TriInd(triangles.size()); ++i)
1594 const Triangle& t = triangles[i];
1595 const V2d<T>& v1 = vertices[t.vertices[0]];
1596 const V2d<T>& v2 = vertices[t.vertices[1]];
1597 const V2d<T>& v3 = vertices[t.vertices[2]];
1599 if(loc == PtTriLocation::Outside)
1607 Error(
"No triangle was found at position", CDT_SOURCE_LOCATION));
1611template <
typename T,
typename TNearPo
intLocator>
1612TriInd Triangulation<T, TNearPointLocator>::walkTriangles(
1613 const VertInd startVertex,
1614 const V2d<T>& pos)
const
1617 TriInd currTri = m_vertTris[startVertex];
1619 detail::SplitMix64RandGen prng;
1622 const Triangle& t = triangles[currTri];
1625 const Index offset(prng() % 3);
1626 for(Index i_(0); i_ <
Index(3); ++i_)
1628 const Index i((i_ + offset) % 3);
1629 const V2d<T>& vStart = vertices[t.vertices[i]];
1630 const V2d<T>& vEnd = vertices[t.vertices[
ccw(i)]];
1631 const PtLineLocation::Enum edgeCheck =
1633 const TriInd iN = t.neighbors[i];
1634 if(edgeCheck == PtLineLocation::Right && iN != noNeighbor)
1645template <
typename T,
typename TNearPo
intLocator>
1646array<TriInd, 2> Triangulation<T, TNearPointLocator>::walkingSearchTrianglesAt(
1648 const VertInd startVertex)
const
1650 const V2d<T> v = vertices[iV];
1651 array<TriInd, 2> out = {noNeighbor, noNeighbor};
1652 const TriInd iT = walkTriangles(startVertex, v);
1654 const Triangle& t = triangles[iT];
1655 const V2d<T>& v1 = vertices[t.vertices[0]];
1656 const V2d<T>& v2 = vertices[t.vertices[1]];
1657 const V2d<T>& v3 = vertices[t.vertices[2]];
1660 if(loc == PtTriLocation::Outside)
1663 Error(
"No triangle was found at position", CDT_SOURCE_LOCATION));
1665 if(loc == PtTriLocation::OnVertex)
1667 const VertInd iDupe = v1 == v ? t.vertices[0]
1668 : v2 == v ? t.vertices[1]
1670 handleException(DuplicateVertexError(
1672 VertInd(iDupe - m_nTargetVerts),
1673 CDT_SOURCE_LOCATION));
1682template <
typename T,
typename TNearPo
intLocator>
1683void Triangulation<T, TNearPointLocator>::changeNeighbor(
1685 const TriInd oldNeighbor,
1686 const TriInd newNeighbor)
1688 if(iT == noNeighbor)
1692 nn[0] == oldNeighbor || nn[1] == oldNeighbor || nn[2] == oldNeighbor);
1693 if(nn[0] == oldNeighbor)
1694 nn[0] = newNeighbor;
1695 else if(nn[1] == oldNeighbor)
1696 nn[1] = newNeighbor;
1698 nn[2] = newNeighbor;
1701template <
typename T,
typename TNearPo
intLocator>
1702void Triangulation<T, TNearPointLocator>::changeNeighbor(
1704 const VertInd iVedge1,
1705 const VertInd iVedge2,
1706 const TriInd newNeighbor)
1708 assert(iT != noNeighbor);
1709 Triangle& t = triangles[iT];
1710 t.neighbors[
edgeNeighborInd(t.vertices, iVedge1, iVedge2)] = newNeighbor;
1713template <
typename T,
typename TNearPo
intLocator>
1714void Triangulation<T, TNearPointLocator>::triangulatePseudoPolygon(
1715 const std::vector<VertInd>& poly,
1716 unordered_map<Edge, TriInd>& outerTris,
1719 std::vector<TriInd>& trianglesToReuse,
1720 std::vector<TriangulatePseudoPolygonTask>& iterations)
1722 assert(poly.size() > 2);
1725 iterations.push_back(make_tuple(
1727 static_cast<IndexSizeType
>(poly.size() - 1),
1731 while(!iterations.empty())
1733 triangulatePseudoPolygonIteration(
1734 poly, outerTris, trianglesToReuse, iterations);
1738template <
typename T,
typename TNearPo
intLocator>
1739void Triangulation<T, TNearPointLocator>::triangulatePseudoPolygonIteration(
1740 const std::vector<VertInd>& poly,
1741 unordered_map<Edge, TriInd>& outerTris,
1742 std::vector<TriInd>& trianglesToReuse,
1743 std::vector<TriangulatePseudoPolygonTask>& iterations)
1745 IndexSizeType iA, iB;
1748 assert(!iterations.empty());
1749 tie(iA, iB, iT, iParent, iInParent) = iterations.back();
1750 iterations.pop_back();
1751 assert(iB - iA > 1 && iT != noNeighbor && iParent != noNeighbor);
1752 Triangle& t = triangles[iT];
1754 const IndexSizeType iC = findDelaunayPoint(poly, iA, iB);
1766 assert(!trianglesToReuse.empty());
1767 const TriInd iNext = trianglesToReuse.back();
1768 trianglesToReuse.pop_back();
1769 iterations.push_back(make_tuple(iC, iB, iNext, iT,
Index(1)));
1773 const Edge outerEdge(b, c);
1774 const TriInd outerTri = outerTris.at(outerEdge);
1775 if(outerTri != noNeighbor)
1777 assert(outerTri != iT);
1778 t.neighbors[1] = outerTri;
1779 changeNeighbor(outerTri, c, b, iT);
1782 outerTris.at(outerEdge) = iT;
1787 assert(!trianglesToReuse.empty());
1788 const TriInd iNext = trianglesToReuse.back();
1789 trianglesToReuse.pop_back();
1790 iterations.push_back(make_tuple(iA, iC, iNext, iT,
Index(2)));
1794 const Edge outerEdge(c, a);
1795 const TriInd outerTri = outerTris.at(outerEdge);
1796 if(outerTri != noNeighbor)
1798 assert(outerTri != iT);
1799 t.neighbors[2] = outerTri;
1800 changeNeighbor(outerTri, c, a, iT);
1803 outerTris.at(outerEdge) = iT;
1808 triangles[iParent].neighbors[iInParent] = iT;
1809 t.neighbors[0] = iParent;
1810 t.vertices =
arr3(a, b, c);
1811 setAdjacentTriangle(c, iT);
1814template <
typename T,
typename TNearPo
intLocator>
1815IndexSizeType Triangulation<T, TNearPointLocator>::findDelaunayPoint(
1816 const std::vector<VertInd>& poly,
1817 const IndexSizeType iA,
1818 const IndexSizeType iB)
const
1820 assert(iB - iA > 1);
1821 const V2d<T>& a = vertices[poly[iA]];
1822 const V2d<T>& b = vertices[poly[iB]];
1823 IndexSizeType out = iA + 1;
1824 const V2d<T>* c = &vertices[poly[out]];
1825 for(IndexSizeType i = iA + 1; i < iB; ++i)
1827 const V2d<T>& v = vertices[poly[i]];
1834 assert(out > iA && out < iB);
1838template <
typename T,
typename TNearPo
intLocator>
1840 const std::vector<
V2d<T> >& newVertices)
1846template <
typename T,
typename TNearPo
intLocator>
1849 return m_vertTris.empty() && !
vertices.empty();
1852template <
typename T,
typename TNearPo
intLocator>
1853unordered_map<TriInd, LayerDepth>
1854Triangulation<T, TNearPointLocator>::peelLayer(
1855 std::stack<TriInd> seeds,
1857 std::vector<LayerDepth>& triDepths)
const
1859 unordered_map<TriInd, LayerDepth> behindBoundary;
1860 while(!seeds.empty())
1862 const TriInd iT = seeds.top();
1864 triDepths[iT] = std::min(triDepths[iT], layerDepth);
1865 behindBoundary.erase(iT);
1871 if(iN == noNeighbor || triDepths[iN] <= layerDepth)
1873 if(fixedEdges.count(opEdge))
1875 const unordered_map<Edge, LayerDepth>::const_iterator cit =
1876 overlapCount.find(opEdge);
1877 const LayerDepth triDepth = cit == overlapCount.end()
1879 : layerDepth + cit->second + 1;
1880 behindBoundary[iN] = triDepth;
1886 return behindBoundary;
1889template <
typename T,
typename TNearPo
intLocator>
1890std::vector<LayerDepth>
1893 std::vector<LayerDepth> triDepths(
1894 triangles.size(), std::numeric_limits<LayerDepth>::max());
1895 std::stack<TriInd> seeds(TriDeque(1, m_vertTris[0]));
1899 unordered_map<LayerDepth, TriIndUSet> seedsByDepth;
1902 const unordered_map<TriInd, LayerDepth>& newSeeds =
1903 peelLayer(seeds, layerDepth, triDepths);
1905 seedsByDepth.erase(layerDepth);
1906 typedef unordered_map<TriInd, LayerDepth>::const_iterator Iter;
1907 for(Iter it = newSeeds.begin(); it != newSeeds.end(); ++it)
1909 deepestSeedDepth = std::max(deepestSeedDepth, it->second);
1910 seedsByDepth[it->second].insert(it->first);
1912 const TriIndUSet& nextLayerSeeds = seedsByDepth[layerDepth + 1];
1913 seeds = std::stack<TriInd>(
1914 TriDeque(nextLayerSeeds.begin(), nextLayerSeeds.end()));
1916 }
while(!seeds.empty() || deepestSeedDepth > layerDepth);
1921#ifdef CDT_ENABLE_CALLBACK_HANDLER
1922template <
typename T,
typename TNearPo
intLocator>
1926 m_callbackHandler = callbackHandler;
1930template <
typename T,
typename TNearPo
intLocator>
1931void Triangulation<T, TNearPointLocator>::insertVertices_AsProvided(
1934 for(
VertInd iV = superGeomVertCount; iV < vertices.size(); ++iV)
1936#ifdef CDT_ENABLE_CALLBACK_HANDLER
1937 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
1946template <
typename T,
typename TNearPo
intLocator>
1947void Triangulation<T, TNearPointLocator>::insertVertices_Randomized(
1948 VertInd superGeomVertCount)
1950 std::size_t vertexCount = vertices.size() - superGeomVertCount;
1951 std::vector<VertInd> ii(vertexCount);
1952 detail::iota(ii.begin(), ii.end(), superGeomVertCount);
1953 detail::random_shuffle(ii.begin(), ii.end());
1954 for(std::vector<VertInd>::iterator it = ii.begin(); it != ii.end(); ++it)
1956#ifdef CDT_ENABLE_CALLBACK_HANDLER
1957 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
1970template <
typename T>
1971inline double log2_bc(T x)
1973#ifdef CDT_CXX11_IS_SUPPORTED
1974 return std::log2(x);
1976 static double log2_constant = std::log(2.0);
1977 return std::log(
static_cast<double>(x)) / log2_constant;
1987 const int filledLayerPow2 =
1988 static_cast<int>(std::floor(log2_bc(vertexCount)) - 1);
1989 const std::size_t nodesInFilledTree =
1990 static_cast<std::size_t
>(std::pow(2., filledLayerPow2 + 1) - 1);
1991 const std::size_t nodesInLastFilledLayer =
1992 static_cast<std::size_t
>(std::pow(2., filledLayerPow2));
1993 const std::size_t nodesInLastLayer = vertexCount - nodesInFilledTree;
1994 return nodesInLastLayer >= nodesInLastFilledLayer
1995 ? nodesInLastFilledLayer + nodesInLastLayer -
1996 nodesInLastFilledLayer
1997 : nodesInLastFilledLayer;
2000template <
typename T>
2001class FixedCapacityQueue
2004 FixedCapacityQueue(
const std::size_t capacity)
2006 , m_front(m_vec.begin())
2007 , m_back(m_vec.begin())
2014 const T& front()
const
2022 if(m_front == m_vec.end())
2023 m_front = m_vec.begin();
2026 void push(
const T& t)
2028 assert(m_size < m_vec.size());
2031 if(m_back == m_vec.end())
2032 m_back = m_vec.begin();
2035#ifdef CDT_CXX11_IS_SUPPORTED
2036 void push(
const T&& t)
2038 assert(m_size < m_vec.size());
2041 if(m_back == m_vec.end())
2042 m_back = m_vec.begin();
2047 std::vector<T> m_vec;
2048 typename std::vector<T>::iterator m_front;
2049 typename std::vector<T>::iterator m_back;
2053template <
typename T>
2056 const std::vector<V2d<T> >& m_vertices;
2059 less_than_x(
const std::vector<
V2d<T> >& vertices)
2060 : m_vertices(vertices)
2064 return m_vertices[a].x < m_vertices[b].x;
2068template <
typename T>
2071 const std::vector<V2d<T> >& m_vertices;
2074 less_than_y(
const std::vector<
V2d<T> >& vertices)
2075 : m_vertices(vertices)
2079 return m_vertices[a].y < m_vertices[b].y;
2085template <
typename T,
typename TNearPo
intLocator>
2086void Triangulation<T, TNearPointLocator>::insertVertices_KDTreeBFS(
2091 const VertInd vertexCount(verticesCount() - superGeomVertCount);
2094 std::vector<VertInd> ii(vertexCount);
2095 detail::iota(ii.begin(), ii.end(), superGeomVertCount);
2097 typedef std::vector<VertInd>::iterator It;
2100 queue.push(make_tuple(ii.begin(), ii.end(), box.
min, box.
max,
VertInd(0)));
2103 V2d<T> newBoxMin, newBoxMax;
2109 while(!queue.empty())
2111#ifdef CDT_ENABLE_CALLBACK_HANDLER
2112 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
2117 tie(first, last, box.
min, box.
max, parent) = queue.front();
2119 assert(first != last);
2121 const std::ptrdiff_t len = std::distance(first, last);
2124 insertVertex(*first, parent);
2127 const It midIt = first + len / 2;
2130 detail::portable_nth_element(first, midIt, last, cmpX);
2132 const T split = vertices[mid].x;
2133 newBoxMin.
x = split;
2134 newBoxMin.
y = box.
min.y;
2135 newBoxMax.
x = split;
2136 newBoxMax.
y = box.
max.y;
2140 detail::portable_nth_element(first, midIt, last, cmpY);
2142 const T split = vertices[mid].y;
2143 newBoxMin.
x = box.
min.x;
2144 newBoxMin.
y = split;
2145 newBoxMax.
x = box.
max.x;
2146 newBoxMax.
y = split;
2148 insertVertex(mid, parent);
2151 queue.push(make_tuple(first, midIt, box.
min, newBoxMax, mid));
2153 if(midIt + 1 != last)
2155 queue.push(make_tuple(midIt + 1, last, newBoxMin, box.
max, mid));
2160template <
typename T,
typename TNearPo
intLocator>
2161std::pair<TriInd, TriInd> Triangulation<T, TNearPointLocator>::edgeTriangles(
2163 const VertInd b)
const
2165 const TriInd triStart = m_vertTris[a];
2166 assert(triStart != noNeighbor);
2167 TriInd iT = triStart, iTNext = triStart;
2171 const Triangle& t = triangles[iT];
2172 tie(iTNext, iV) = t.
next(a);
2173 assert(iTNext != noNeighbor);
2176 return std::make_pair(iT, iTNext);
2179 }
while(iT != triStart);
2180 return std::make_pair(noNeighbor, noNeighbor);
2183template <
typename T,
typename TNearPo
intLocator>
2184bool Triangulation<T, TNearPointLocator>::hasEdge(
2186 const VertInd b)
const
2188 return edgeTriangles(a, b).first != invalidIndexSizeType;
2191template <
typename T,
typename TNearPo
intLocator>
2192void Triangulation<T, TNearPointLocator>::setAdjacentTriangle(
2196 assert(t != noNeighbor);
2199 triangles[t].vertices[0] == v || triangles[t].vertices[1] == v ||
2200 triangles[t].vertices[2] == v);
2203template <
typename T,
typename TNearPo
intLocator>
2204void Triangulation<T, TNearPointLocator>::pivotVertexTriangleCW(
const VertInd v)
2206 assert(m_vertTris[v] != noNeighbor);
2207 m_vertTris[v] = triangles[m_vertTris[v]].next(v).first;
2208 assert(m_vertTris[v] != noNeighbor);
2210 triangles[m_vertTris[v]].vertices[0] == v ||
2211 triangles[m_vertTris[v]].vertices[1] == v ||
2212 triangles[m_vertTris[v]].vertices[2] == v);
2215template <
typename T,
typename TNearPo
intLocator>
2216void Triangulation<T, TNearPointLocator>::tryAddVertexToLocator(
const VertInd v)
2218 if(!m_nearPtLocator.empty())
2219 m_nearPtLocator.addPoint(v, vertices);
2222template <
typename T,
typename TNearPo
intLocator>
2223void Triangulation<T, TNearPointLocator>::tryInitNearestPointLocator()
2225 if(!vertices.empty() && m_nearPtLocator.empty())
2227 m_nearPtLocator.initialize(vertices);
2233CDT_RESTORE_MATH_SETTINGS_FOR_CONSTRUCTIONS
void iota(ForwardIt first, ForwardIt last, T value)
backport from c++11
std::size_t maxQueueLengthBFSKDTree(const std::size_t vertexCount)
Since KD-tree bulk load builds a balanced tree the maximum length of a queue can be pre-calculated: i...
Interface for the callback handler that user can derive from and inject into the triangulation to mon...
Error thrown when intersecting constraint edges are detected, but triangulation is not configured to ...
Error thrown when resolving intersecting constraints fails: floating-point rounding places the comput...
void eraseOuterTriangles()
Erase triangles outside of constrained boundary using growing.
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< LayerDepth > calculateTriangleDepths() const
Calculate depth of each triangle in constraint triangulation.
bool isFinalized() const
Check if the triangulation was finalized with erase... method and super-triangle was removed.
void eraseOuterTrianglesAndHoles()
Erase triangles outside of constrained boundary and auto-detected holes.
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.
void eraseSuperTriangle()
Erase triangles adjacent to super triangle.
TriangleVec triangles
triangulation's triangles
Triangulation()
Default constructor.
void setCallbackHandler(ICallbackHandler *callbackHandler)
Set user-provided callback handler.
void initializedWithCustomSuperGeometry()
Call this method after directly setting custom super-geometry via vertices and triangles members.
unsigned short LayerDepth
Type used for storing layer depths for triangles.
void flipEdge(TriInd iT, TriInd iTopo)
Flip an edge between two triangle.
TriIndVec & VertTrisInternal()
Access internal vertex adjacent triangles.
void removeTriangles(const TriIndUSet &removedTriangles)
Remove triangles with specified indices.
Namespace containing triangulation functionality.
std::vector< Edge > EdgeVec
Vector of edges.
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY VertInd opposedVertex(const Triangle &tri, TriInd iTopo)
Given two triangles, return vertex of first triangle opposed to the second.
unordered_set< Edge > EdgeUSet
Hash table of edges.
VertInd edge_get_v2(const Edge &e)
Get edge second vertex.
std::vector< TriInd > TriIndVec
Vector of triangle indices.
CDT_INLINE_IF_HEADER_ONLY Index edgeNeighborInd(const VerticesArr3 &vv, VertInd iVedge1, VertInd iVedge2)
Index of triangle's neighbor opposed to an edge.
VertInd edge_get_v1(const Edge &e)
Get edge first vertex.
CDT_EXPORT PtLineLocation::Enum classifyOrientation(T orientation, T orientationTolerance=T(0))
Classify value of orient2d predicate.
array< TriInd, 3 > NeighborsArr3
array of three neighbors
CDT_EXPORT T distance(const V2d< T > &a, const V2d< T > &b)
Distance between two 2D points.
IndexSizeType VertInd
Vertex index.
CDT_EXPORT Index cw(Index i)
Advance vertex or neighbor index clockwise.
array< VertInd, 3 > VerticesArr3
array of three vertex indices
CDT_INLINE_IF_HEADER_ONLY bool touchesSuperTriangle(const Triangle &t)
Check if any of triangle's vertices belongs to a super-triangle.
array< T, 3 > arr3(const T &v0, const T &v1, const T &v2)
Needed for c++03 compatibility (no uniform initialization available)
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opoNbr(Index vertIndex)
Opposed neighbor index from vertex index.
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index vertexInd(const VerticesArr3 &vv, VertInd iV)
If triangle has a given vertex return vertex-index.
CDT_EXPORT T orient2D(const V2d< T > &p, const V2d< T > &v1, const V2d< T > &v2)
Orient p against line v1-v2 2D: robust geometric predicate.
CDT_EXPORT PtLineLocation::Enum locatePointLine(const V2d< T > &p, const V2d< T > &v1, const V2d< T > &v2, T orientationTolerance=T(0))
Check if point lies to the left of, to the right of, or on a line.
unordered_set< TriInd > TriIndUSet
Hash table of triangles.
CDT_EXPORT Index ccw(Index i)
Advance vertex or neighbor index counter-clockwise.
CDT_EXPORT Index edgeNeighbor(PtTriLocation::Enum location)
Neighbor index from a on-edge location.
unordered_map< TriInd, TriInd > TriIndUMap
Triangle hash map.
const T & getX_V2d(const V2d< T > &v)
X- coordinate getter for V2d.
unsigned char Index
Index in triangle.
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY TriInd opposedTriangle(const Triangle &tri, VertInd iVert)
Given triangle and a vertex find opposed triangle.
CDT_EXPORT bool isInCircumcircle(const V2d< T > &p, const V2d< T > &v1, const V2d< T > &v2, const V2d< T > &v3)
Test if point lies in a circumscribed circle of a triangle.
Edge RemapNoSuperTriangle(const Edge &e)
Remap removing super-triangle: subtract 3 from vertices.
CDT_EXPORT bool isOnEdge(PtTriLocation::Enum location)
Check if location is classified as on any of three edges.
IndexSizeType TriInd
Triangle index.
CDT_EXPORT PtTriLocation::Enum locatePointTriangle(const V2d< T > &p, const V2d< T > &v1, const V2d< T > &v2, const V2d< T > &v3)
Check if point a lies inside of, outside of, or on an edge of a triangle.
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opposedVertexInd(const NeighborsArr3 &nn, TriInd iTopo)
Index of triangle's vertex opposed to a triangle.
const T & getY_V2d(const V2d< T > &v)
Y-coordinate getter for V2d.
@ FixedEdgeMidpoint
During conforming triangulation edge mid-point is added.
@ FixedEdgesIntersection
Resolving fixed/constraint edges' intersection.
V2d< T > max
max box corner
V2d< T > min
min box corner
Edge connecting two vertices: vertex with smaller index is always first.
VertInd v1() const
V1 getter.
VertInd v2() const
V2 getter.
@ TryResolve
attempt to resolve constraint edge intersections
@ NotAllowed
constraint edge intersections are not allowed
@ DontCheck
No checks: slightly faster but less safe.
@ SuperTriangle
conventional super-triangle
@ Custom
user-specified custom geometry (e.g., grid)
Triangulation triangle (counter-clockwise winding)
VerticesArr3 vertices
triangle's three vertices
NeighborsArr3 neighbors
triangle's three neighbors
std::pair< TriInd, VertInd > next(const VertInd i) const
Next triangle adjacent to a vertex (clockwise)
@ Auto
Automatic insertion order optimized for better performance.