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;
34 return EdgeQueue(EdgeQueue::container_type(edges.begin(), edges.end()));
38template <
typename TVec>
41 std::sort(v.begin(), v.end());
42 v.erase(std::unique(v.begin(), v.end()), v.end());
52const float minDistToConstraintEdge(0);
67template <
typename T,
typename TNearPo
intLocator>
69 : m_vertexInsertionOrder(detail::defaults::vertexInsertionOrder)
70 , m_intersectingEdgesStrategy(detail::defaults::intersectingEdgesStrategy)
71 , m_minDistToConstraintEdge(detail::defaults::minDistToConstraintEdge)
72#ifdef CDT_ENABLE_CALLBACK_HANDLER
73 , m_callbackHandler(NULL)
77template <
typename T,
typename TNearPo
intLocator>
80 : m_vertexInsertionOrder(vertexInsertionOrder)
81 , m_intersectingEdgesStrategy(detail::defaults::intersectingEdgesStrategy)
82 , m_minDistToConstraintEdge(detail::defaults::minDistToConstraintEdge)
83#ifdef CDT_ENABLE_CALLBACK_HANDLER
84 , m_callbackHandler(NULL)
88template <
typename T,
typename TNearPo
intLocator>
92 const T minDistToConstraintEdge)
93 : m_vertexInsertionOrder(vertexInsertionOrder)
94 , m_intersectingEdgesStrategy(intersectingEdgesStrategy)
95 , m_minDistToConstraintEdge(minDistToConstraintEdge)
96#ifdef CDT_ENABLE_CALLBACK_HANDLER
97 , m_callbackHandler(NULL)
101template <
typename T,
typename TNearPo
intLocator>
104 const TNearPointLocator& nearPtLocator,
106 const T minDistToConstraintEdge)
107 : m_nearPtLocator(nearPtLocator)
108 , m_vertexInsertionOrder(vertexInsertionOrder)
109 , m_intersectingEdgesStrategy(intersectingEdgesStrategy)
110 , m_minDistToConstraintEdge(minDistToConstraintEdge)
111#ifdef CDT_ENABLE_CALLBACK_HANDLER
112 , m_callbackHandler(NULL)
116template <
typename T,
typename TNearPo
intLocator>
119 finalizeTriangulation(collectSuperTriangle());
122template <
typename T,
typename TNearPo
intLocator>
128template <
typename T,
typename TNearPo
intLocator>
134template <
typename T,
typename TNearPo
intLocator>
150template <
typename T,
typename TNearPo
intLocator>
156 assert(m_vertTris[0] != noNeighbor);
157 const std::stack<TriInd> seed(std::deque<TriInd>(1, m_vertTris[0]));
158 return growToBoundary(seed);
161template <
typename T,
typename TNearPo
intLocator>
171 for(std::size_t iT = 0; iT !=
triangles.size(); ++iT)
173 if(triDepths[iT] % 2 == 0)
174 toErase.insert(
static_cast<TriInd>(iT));
186template <
typename T,
typename TNearPo
intLocator>
190 if(removedTriangles.empty())
196 if(removedTriangles.count(iT))
198 triIndMap[iT] = iTnew;
209 for(NeighborsArr3::iterator n = nn.begin(); n != nn.end(); ++n)
211 if(removedTriangles.count(*n))
215 else if(*n != noNeighbor)
223template <
typename T,
typename TNearPo
intLocator>
229template <
typename T,
typename TNearPo
intLocator>
235template <
typename T,
typename TNearPo
intLocator>
248 typedef CDT::EdgeUSet::const_iterator It;
256 unordered_map<Edge, BoundaryOverlapCount> updatedOverlapCount;
257 typedef unordered_map<Edge, BoundaryOverlapCount>::const_iterator It;
260 updatedOverlapCount.insert(
266 unordered_map<Edge, EdgeVec> updatedPieceToOriginals;
267 typedef unordered_map<Edge, EdgeVec>::const_iterator It;
272 for(EdgeVec::iterator eeIt = ee.begin(); eeIt != ee.end(); ++eeIt)
276 updatedPieceToOriginals.insert(
287 for(VerticesArr3::iterator v = vv.begin(); v != vv.end(); ++v)
289 *v -= nSuperTriVerts;
294template <
typename T,
typename TNearPo
intLocator>
295TriIndUSet Triangulation<T, TNearPointLocator>::growToBoundary(
296 std::stack<TriInd> seeds)
const
299 while(!seeds.empty())
301 const TriInd iT = seeds.top();
303 traversed.insert(iT);
308 if(fixedEdges.count(opEdge))
311 if(iN != noNeighbor && traversed.count(iN) == 0)
318template <
typename T,
typename TNearPo
intLocator>
319TriInd Triangulation<T, TNearPointLocator>::addTriangle(
const Triangle& t)
321 const TriInd iT = trianglesCount();
322 triangles.push_back(t);
326template <
typename T,
typename TNearPo
intLocator>
327TriInd Triangulation<T, TNearPointLocator>::addTriangle()
332template <
typename T,
typename TNearPo
intLocator>
333VertInd Triangulation<T, TNearPointLocator>::verticesCount()
const
335 return static_cast<VertInd>(vertices.size());
338template <
typename T,
typename TNearPo
intLocator>
339TriInd Triangulation<T, TNearPointLocator>::trianglesCount()
const
341 return static_cast<TriInd>(triangles.size());
344template <
typename T,
typename TNearPo
intLocator>
346 const std::vector<Edge>& edges)
351template <
typename T,
typename TNearPo
intLocator>
353 const std::vector<Edge>& edges)
358template <
typename T,
typename TNearPo
intLocator>
359void Triangulation<T, TNearPointLocator>::fixEdge(
const Edge& edge)
361 if(!fixedEdges.insert(edge).second)
363 ++overlapCount[edge];
371template <
typename T,
typename Allocator1>
372void insert_unique(std::vector<T, Allocator1>& to,
const T& elem)
374 if(std::find(to.begin(), to.end(), elem) == to.end())
381template <
typename T,
typename Allocator1,
typename Allocator2>
383 std::vector<T, Allocator1>& to,
384 const std::vector<T, Allocator2>& from)
386 typedef typename std::vector<T, Allocator2>::const_iterator Cit;
387 to.reserve(to.size() + from.size());
388 for(Cit cit = from.begin(); cit != from.end(); ++cit)
390 insert_unique(to, *cit);
396template <
typename T,
typename TNearPo
intLocator>
397void Triangulation<T, TNearPointLocator>::splitFixedEdge(
402 const Edge half1(edge.v1(), iSplitVert);
403 const Edge half2(iSplitVert, edge.v2());
405 fixedEdges.erase(edge);
409 typedef unordered_map<Edge, BoundaryOverlapCount>::const_iterator It;
410 const It overlapIt = overlapCount.find(edge);
411 if(overlapIt != overlapCount.end())
413 overlapCount[half1] += overlapIt->second;
414 overlapCount[half2] += overlapIt->second;
415 overlapCount.erase(overlapIt);
419 const unordered_map<Edge, EdgeVec>::const_iterator originalsIt =
420 pieceToOriginals.find(edge);
421 if(originalsIt != pieceToOriginals.end())
423 newOriginals = originalsIt->second;
424 pieceToOriginals.erase(originalsIt);
426 detail::insert_unique(pieceToOriginals[half1], newOriginals);
427 detail::insert_unique(pieceToOriginals[half2], newOriginals);
430template <
typename T,
typename TNearPo
intLocator>
431VertInd Triangulation<T, TNearPointLocator>::addSplitEdgeVertex(
439 const VertInd iSplitVert = verticesCount();
440 addNewVertex(splitVert, noNeighbor);
442#ifdef CDT_ENABLE_CALLBACK_HANDLER
443 if(m_callbackHandler)
445 m_callbackHandler->onAddVertexStart(iSplitVert, vertexType);
451 std::stack<TriInd> triStack = insertVertexOnEdge(iSplitVert, iT, iTopo);
453 splitFixedEdge(edge, iSplitVert);
454 tryAddVertexToLocator(iSplitVert);
455 ensureDelaunayByEdgeFlips(iSplitVert, triStack);
459template <
typename T,
typename TNearPo
intLocator>
467 if(!isEdgeSplitVertexValid(splitVert, iT, iTopo))
470 addSplitEdgeVertex(edge, splitVert, iT, iTopo, vertexType);
474template <
typename T,
typename TNearPo
intLocator>
475bool Triangulation<T, TNearPointLocator>::isEdgeSplitVertexValid(
483 const V2d<T>& v1 = vertices[t1.vertices[i]];
484 const V2d<T>& v2 = vertices[t1.vertices[
ccw(i)]];
485 const V2d<T>& v4 = vertices[t1.vertices[
cw(i)]];
486 const Triangle& t2 = triangles[iTopo];
495template <
typename T,
typename TNearPo
intLocator>
496Edge Triangulation<T, TNearPointLocator>::originalInputEdge(
const Edge& e)
const
499 pieceToOriginals.count(e) ? pieceToOriginals.at(e).front() : e;
501 VertInd(orig.v1() - nSuperTriVerts),
502 VertInd(orig.v2() - nSuperTriVerts));
505template <
typename T,
typename TNearPo
intLocator>
507Triangulation<T, TNearPointLocator>::triangleAt(
const TriInd iT)
const
509 if(iT >=
TriInd(triangles.size()))
510 handleException(
Error(
512 ?
"Attempted reading no-neighbor sentinel value triangle"
513 :
"Triangle index " + CDT::to_string(iT) +
" out of range " +
514 CDT::to_string(triangles.size()),
515 CDT_SOURCE_LOCATION));
516 return triangles[iT];
519template <
typename T,
typename TNearPo
intLocator>
520void Triangulation<T, TNearPointLocator>::fixEdge(
522 const Edge& originalEdge)
525 if(edge != originalEdge)
526 detail::insert_unique(pieceToOriginals[edge], originalEdge);
533T lerp(
const T& a,
const T& b,
const T t)
535 return (T(1) - t) * a + t * b;
542 const T ux = a.
x - apex.
x, uy = a.
y - apex.
y;
543 const T wx = b.
x - apex.
x, wy = b.
y - apex.
y;
544 const T dot = ux * wx + uy * wy;
551V2d<T> intersectionPosition(
559 const T a_cd = predicates::orient2d(c.
x, c.
y, d.
x, d.
y, a.
x, a.
y);
560 const T b_cd = predicates::orient2d(c.
x, c.
y, d.
x, d.
y, b.
x, b.
y);
561 const T t_ab = a_cd / (a_cd - b_cd);
563 const T c_ab = predicates::orient2d(a.
x, a.
y, b.
x, b.
y, c.
x, c.
y);
564 const T d_ab = predicates::orient2d(a.
x, a.
y, b.
x, b.
y, d.
x, d.
y);
565 const T t_cd = c_ab / (c_ab - d_ab);
568 std::fabs(a.
x - b.
x) < std::fabs(c.
x - d.
x) ? lerp(a.
x, b.
x, t_ab)
569 : lerp(c.
x, d.
x, t_cd),
570 std::fabs(a.
y - b.
y) < std::fabs(c.
y - d.
y) ? lerp(a.
y, b.
y, t_ab)
571 : lerp(c.
y, d.
y, t_cd));
576template <
typename T,
typename TNearPo
intLocator>
577void Triangulation<T, TNearPointLocator>::insertEdgeIteration(
579 const Edge originalEdge,
581 std::vector<TriangulatePseudoPolygonTask>& tppIterations)
588 const V2d<T>& a = vertices[iA];
589 const V2d<T>& b = vertices[iB];
590 const T distanceTolerance =
591 m_minDistToConstraintEdge == T(0)
593 : m_minDistToConstraintEdge *
distance(a, b);
597 const VertInd iV = opposedVertexOnEdge(edge, distanceTolerance);
600 remaining.push_back(
Edge(iV, iB));
601 remaining.push_back(
Edge(iA, iV));
604 fixEdge(edge, originalEdge);
611 tie(iT, iVL, iVR) = intersectedTriangle(iA, a, b, distanceTolerance);
615 remaining.push_back(
Edge(iVL, iB));
616 remaining.push_back(
Edge(iA, iVL));
620 std::vector<TriInd> intersected(1, iT);
621 std::vector<VertInd> polyL, polyR;
624 polyL.push_back(iVL);
627 polyR.push_back(iVR);
628 unordered_map<Edge, TriInd> outerTris;
633 while(!t.containsVertex(iB))
636 const Triangle& tOpo = triangleAt(iTopo);
639 switch(m_intersectingEdgesStrategy)
642 if(fixedEdges.count(
Edge(iVL, iVR)))
644 originalInputEdge(originalEdge),
645 originalInputEdge(
Edge(iVL, iVR)),
646 CDT_SOURCE_LOCATION));
650 if(!fixedEdges.count(
Edge(iVL, iVR)))
653 const V2d<T> newV = detail::intersectionPosition(
654 vertices[iA], vertices[iB], vertices[iVL], vertices[iVR]);
661 if(!splitVert.hasValue())
663 originalInputEdge(originalEdge),
664 originalInputEdge(
Edge(iVL, iVR)),
665 CDT_SOURCE_LOCATION));
666 const VertInd iNewVert = splitVert.value();
669 remaining.push_back(
Edge(iA, iNewVert));
670 remaining.push_back(
Edge(iNewVert, iB));
674 assert(!fixedEdges.count(
Edge(iVL, iVR)));
680 if(loc == PtLineLocation::Left)
682 const Edge e(polyL.back(), iVopo);
684 if(!outerTris.insert(std::make_pair(e, outer)).second)
685 outerTris.at(e) = noNeighbor;
686 polyL.push_back(iVopo);
690 else if(loc == PtLineLocation::Right)
692 const Edge e(polyR.back(), iVopo);
694 if(!outerTris.insert(std::make_pair(e, outer)).second)
695 outerTris.at(e) = noNeighbor;
696 polyR.push_back(iVopo);
703 intersected.push_back(iTopo);
712 assert(!intersected.empty());
715 if(m_vertTris[iA] == intersected.front())
716 pivotVertexTriangleCW(iA);
717 if(m_vertTris[iB] == intersected.back())
718 pivotVertexTriangleCW(iB);
721#ifdef CDT_ENABLE_CALLBACK_HANDLER
722 if(m_callbackHandler)
724 m_callbackHandler->onReTriangulatePolygon(intersected);
729 std::reverse(polyR.begin(), polyR.end());
734 assert(intersected.size() >= 2);
735 const TriInd iTL = intersected.back();
736 intersected.pop_back();
737 const TriInd iTR = intersected.back();
738 intersected.pop_back();
740 triangulatePseudoPolygon(
741 polyL, outerTris, iTL, iTR, intersected, tppIterations);
742 triangulatePseudoPolygon(
743 polyR, outerTris, iTR, iTL, intersected, tppIterations);
744 assert(intersected.empty());
750 const Edge edgePart(iA, iB);
751 fixEdge(edgePart, originalEdge);
752 remaining.push_back(
Edge(iB, edge.v2()));
757 fixEdge(edge, originalEdge);
761template <
typename T,
typename TNearPo
intLocator>
762void Triangulation<T, TNearPointLocator>::insertEdge(
764 const Edge originalEdge,
766 std::vector<TriangulatePseudoPolygonTask>& tppIterations)
768#ifdef CDT_ENABLE_CALLBACK_HANDLER
769 if(m_callbackHandler)
771 m_callbackHandler->onAddEdgeStart(edge);
777 remaining.push_back(edge);
778 while(!remaining.empty())
780 edge = remaining.back();
781 remaining.pop_back();
782 insertEdgeIteration(edge, originalEdge, remaining, tppIterations);
786template <
typename T,
typename TNearPo
intLocator>
787void Triangulation<T, TNearPointLocator>::conformToEdgeIteration(
790 BoundaryOverlapCount overlaps,
791 std::vector<ConformToEdgeTask>& remaining)
798 const V2d<T>& a = vertices[iA];
799 const V2d<T>& b = vertices[iB];
800 const T distanceTolerance =
801 m_minDistToConstraintEdge == T(0)
803 : m_minDistToConstraintEdge *
distance(a, b);
807 const VertInd iV = opposedVertexOnEdge(edge, distanceTolerance);
810#ifdef CDT_CXX11_IS_SUPPORTED
811 remaining.emplace_back(
Edge(iV, iB), originals, overlaps);
812 remaining.emplace_back(
Edge(iA, iV), originals, overlaps);
814 remaining.push_back(make_tuple(
Edge(iV, iB), originals, overlaps));
815 remaining.push_back(make_tuple(
Edge(iA, iV), originals, overlaps));
821 overlapCount[edge] = overlaps;
823 if(!originals.empty() && edge != originals.front())
825 detail::insert_unique(pieceToOriginals[edge], originals);
832 tie(iT, iVleft, iVright) = intersectedTriangle(iA, a, b, distanceTolerance);
836#ifdef CDT_CXX11_IS_SUPPORTED
837 remaining.emplace_back(
Edge(iVleft, iB), originals, overlaps);
838 remaining.emplace_back(
Edge(iA, iVleft), originals, overlaps);
840 remaining.push_back(make_tuple(
Edge(iVleft, iB), originals, overlaps));
841 remaining.push_back(make_tuple(
Edge(iA, iVleft), originals, overlaps));
848 while(std::find(t.vertices.begin(), t.vertices.end(), iB) ==
852 const Triangle& tOpo = triangleAt(iTopo);
854 const V2d<T> vOpo = vertices[iVopo];
856 switch(m_intersectingEdgesStrategy)
859 if(fixedEdges.count(
Edge(iVleft, iVright)))
861 originalInputEdge(edge),
862 originalInputEdge(
Edge(iVleft, iVright)),
863 CDT_SOURCE_LOCATION));
867 if(!fixedEdges.count(
Edge(iVleft, iVright)))
870 const V2d<T> newV = detail::intersectionPosition(
876 Edge(iVleft, iVright),
881 if(!splitVert.hasValue())
883 originalInputEdge(edge),
884 originalInputEdge(
Edge(iVleft, iVright)),
885 CDT_SOURCE_LOCATION));
886 const VertInd iNewVert = splitVert.value();
887#ifdef CDT_CXX11_IS_SUPPORTED
888 remaining.emplace_back(
Edge(iNewVert, iB), originals, overlaps);
889 remaining.emplace_back(
Edge(iA, iNewVert), originals, overlaps);
892 make_tuple(
Edge(iNewVert, iB), originals, overlaps));
894 make_tuple(
Edge(iA, iNewVert), originals, overlaps));
899 assert(!fixedEdges.count(
Edge(iVleft, iVright)));
908 if(loc == PtLineLocation::Left)
913 else if(loc == PtLineLocation::Right)
925#ifdef CDT_CXX11_IS_SUPPORTED
926 remaining.emplace_back(
Edge(iB, edge.v2()), originals, overlaps);
929 make_tuple(
Edge(iB, edge.v2()), originals, overlaps));
934 const VertInd iMid = verticesCount();
935 const V2d<T>& start = vertices[iA];
936 const V2d<T>& end = vertices[iB];
938 V2d<T>((start.x + end.x) / T(2), (start.y + end.y) / T(2)), noNeighbor);
940#ifdef CDT_ENABLE_CALLBACK_HANDLER
941 if(m_callbackHandler)
943 m_callbackHandler->onAddVertexStart(
948 const std::vector<Edge> flippedFixedEdges =
949 insertVertex_FlipFixedEdges(iMid);
951#ifdef CDT_CXX11_IS_SUPPORTED
952 remaining.emplace_back(
Edge(iMid, iB), originals, overlaps);
953 remaining.emplace_back(
Edge(iA, iMid), originals, overlaps);
955 remaining.push_back(make_tuple(
Edge(iMid, iB), originals, overlaps));
956 remaining.push_back(make_tuple(
Edge(iA, iMid), originals, overlaps));
961 for(std::vector<Edge>::const_iterator it = flippedFixedEdges.begin();
962 it != flippedFixedEdges.end();
965 const Edge& flippedFixedEdge = *it;
966 fixedEdges.erase(flippedFixedEdge);
968 BoundaryOverlapCount prevOverlaps = 0;
969 const unordered_map<Edge, BoundaryOverlapCount>::const_iterator
970 overlapsIt = overlapCount.find(flippedFixedEdge);
971 if(overlapsIt != overlapCount.end())
973 prevOverlaps = overlapsIt->second;
974 overlapCount.erase(overlapsIt);
977 EdgeVec prevOriginals(1, flippedFixedEdge);
978 const unordered_map<Edge, EdgeVec>::const_iterator originalsIt =
979 pieceToOriginals.find(flippedFixedEdge);
980 if(originalsIt != pieceToOriginals.end())
982 prevOriginals = originalsIt->second;
984#ifdef CDT_CXX11_IS_SUPPORTED
985 remaining.emplace_back(flippedFixedEdge, prevOriginals, prevOverlaps);
988 make_tuple(flippedFixedEdge, prevOriginals, prevOverlaps));
993template <
typename T,
typename TNearPo
intLocator>
994void Triangulation<T, TNearPointLocator>::conformToEdge(
997 BoundaryOverlapCount overlaps,
998 std::vector<ConformToEdgeTask>& remaining)
1000#ifdef CDT_ENABLE_CALLBACK_HANDLER
1001 if(m_callbackHandler)
1003 m_callbackHandler->onAddEdgeStart(edge);
1009#ifdef CDT_CXX11_IS_SUPPORTED
1010 remaining.emplace_back(edge, originals, overlaps);
1012 remaining.push_back(make_tuple(edge, originals, overlaps));
1014 while(!remaining.empty())
1016 tie(edge, originals, overlaps) = remaining.back();
1017 remaining.pop_back();
1018 conformToEdgeIteration(edge, originals, overlaps, remaining);
1032template <
typename T,
typename TNearPo
intLocator>
1033tuple<TriInd, VertInd, VertInd>
1034Triangulation<T, TNearPointLocator>::intersectedTriangle(
1038 const T orientationTolerance)
const
1040 const TriInd startTri = m_vertTris[iA];
1047 const T orientP2 =
orient2D(vertices[iP2], a, b);
1049 if(locP2 == PtLineLocation::Right)
1052 const T orientP1 =
orient2D(vertices[iP1], a, b);
1054 if(locP1 == PtLineLocation::OnLine)
1056 return make_tuple(noNeighbor, iP1, iP1);
1058 if(locP1 == PtLineLocation::Left)
1060 if(orientationTolerance)
1064 if(std::abs(orientP1) <= std::abs(orientP2))
1066 closestOrient = orientP1;
1071 closestOrient = orientP2;
1075 closestOrient, orientationTolerance) ==
1076 PtLineLocation::OnLine)
1078 return make_tuple(noNeighbor, iClosestP, iClosestP);
1081 return make_tuple(iT, iP1, iP2);
1084 iT = t.next(iA).first;
1085 }
while(iT != startTri);
1087 handleException(
Error(
1088 "Could not find vertex triangle intersected by an edge.",
1089 CDT_SOURCE_LOCATION));
1090 return make_tuple(noNeighbor, noVertex, noVertex);
1093template <
typename T,
typename TNearPo
intLocator>
1094void Triangulation<T, TNearPointLocator>::addSuperTriangle(
const Box2d<T>& box)
1097 (box.min.x + box.max.x) / T(2), (box.min.y + box.max.y) / T(2));
1098 const T w = box.max.x - box.min.x;
1099 const T h = box.max.y - box.min.y;
1100 T r = std::max(w, h);
1105 r = std::max(T(2) * r, T(1));
1111 while(center.y <= center.y - r)
1115 const T R = T(2) * r;
1116 const T cos_30_deg = T(0.8660254037844386);
1117 const T shiftX = R * cos_30_deg;
1118 const V2d<T> posV1(center.x - shiftX, center.y - r);
1119 const V2d<T> posV2(center.x + shiftX, center.y - r);
1120 const V2d<T> posV3(center.x, center.y + R);
1121 addNewVertex(posV1,
TriInd(0));
1122 addNewVertex(posV2,
TriInd(0));
1123 addNewVertex(posV3,
TriInd(0));
1125#ifdef CDT_ENABLE_CALLBACK_HANDLER
1126 if(m_callbackHandler)
1128 m_callbackHandler->onAddSuperTriangle();
1137 m_nearPtLocator.initialize(vertices);
1141template <
typename T,
typename TNearPo
intLocator>
1142void Triangulation<T, TNearPointLocator>::addNewVertex(
1146 vertices.push_back(pos);
1147 m_vertTris.push_back(iT);
1150template <
typename T,
typename TNearPo
intLocator>
1152Triangulation<T, TNearPointLocator>::insertVertex_FlipFixedEdges(
1155 std::vector<Edge> flippedFixedEdges;
1157 const V2d<T>& v1 = vertices[iV1];
1158 const VertInd startVertex = m_nearPtLocator.nearPoint(v1, vertices);
1159 array<TriInd, 2> trisAt = walkingSearchTrianglesAt(iV1, startVertex);
1160 std::stack<TriInd> triStack =
1161 trisAt[1] == noNeighbor ? insertVertexInsideTriangle(iV1, trisAt[0])
1162 : insertVertexOnEdge(iV1, trisAt[0], trisAt[1]);
1164 TriInd iTopo, n1, n2, n3, n4;
1166 while(!triStack.empty())
1168 const TriInd iT = triStack.top();
1171 edgeFlipInfo(iT, iV1, iTopo, iV2, iV3, iV4, n1, n2, n3, n4);
1172 if(iTopo != noNeighbor && isFlipNeeded(iV1, iV2, iV3, iV4, true))
1175 const Edge flippedEdge(iV2, iV4);
1176 if(!fixedEdges.empty() &&
1177 fixedEdges.find(flippedEdge) != fixedEdges.end())
1179 flippedFixedEdges.push_back(flippedEdge);
1182 flipEdge(iT, iTopo, iV1, iV2, iV3, iV4, n1, n2, n3, n4);
1184 triStack.push(iTopo);
1188 tryAddVertexToLocator(iV1);
1189 return flippedFixedEdges;
1192template <
typename T,
typename TNearPo
intLocator>
1193void Triangulation<T, TNearPointLocator>::insertVertex(
1194 const VertInd iVert,
1195 const VertInd walkStart)
1197#ifdef CDT_ENABLE_CALLBACK_HANDLER
1198 if(m_callbackHandler)
1200 m_callbackHandler->onAddVertexStart(iVert, AddVertexType::UserInput);
1204 const array<TriInd, 2> trisAt = walkingSearchTrianglesAt(iVert, walkStart);
1205 std::stack<TriInd> triStack =
1206 trisAt[1] == noNeighbor
1207 ? insertVertexInsideTriangle(iVert, trisAt[0])
1208 : insertVertexOnEdge(iVert, trisAt[0], trisAt[1], true);
1209 ensureDelaunayByEdgeFlips(iVert, triStack);
1212template <
typename T,
typename TNearPo
intLocator>
1213void Triangulation<T, TNearPointLocator>::insertVertex(
const VertInd iVert)
1215 const V2d<T>& v = vertices[iVert];
1216 const VertInd walkStart = m_nearPtLocator.nearPoint(v, vertices);
1217 insertVertex(iVert, walkStart);
1218 tryAddVertexToLocator(iVert);
1221template <
typename T,
typename TNearPo
intLocator>
1222void Triangulation<T, TNearPointLocator>::ensureDelaunayByEdgeFlips(
1224 std::stack<TriInd>& triStack)
1226 TriInd iTopo, n1, n2, n3, n4;
1228 while(!triStack.empty())
1230 const TriInd iT = triStack.top();
1233 edgeFlipInfo(iT, iV1, iTopo, iV2, iV3, iV4, n1, n2, n3, n4);
1234 if(iTopo != noNeighbor && isFlipNeeded(iV1, iV2, iV3, iV4))
1236 flipEdge(iT, iTopo, iV1, iV2, iV3, iV4, n1, n2, n3, n4);
1238 triStack.push(iTopo);
1256template <
typename T,
typename TNearPo
intLocator>
1257void Triangulation<T, TNearPointLocator>::edgeFlipInfo(
1274 const Triangle& t = triangles[iT];
1275 if(t.vertices[0] == iV1)
1277 iV2 = t.vertices[1];
1278 iV4 = t.vertices[2];
1279 n1 = t.neighbors[0];
1280 n3 = t.neighbors[2];
1281 iTopo = t.neighbors[1];
1283 else if(t.vertices[1] == iV1)
1285 iV2 = t.vertices[2];
1286 iV4 = t.vertices[0];
1287 n1 = t.neighbors[1];
1288 n3 = t.neighbors[0];
1289 iTopo = t.neighbors[2];
1293 iV2 = t.vertices[0];
1294 iV4 = t.vertices[1];
1295 n1 = t.neighbors[2];
1296 n3 = t.neighbors[1];
1297 iTopo = t.neighbors[0];
1299 if(iTopo == noNeighbor)
1301 const Triangle& tOpo = triangles[iTopo];
1302 if(tOpo.neighbors[0] == iT)
1304 iV3 = tOpo.vertices[2];
1305 n2 = tOpo.neighbors[1];
1306 n4 = tOpo.neighbors[2];
1308 else if(tOpo.neighbors[1] == iT)
1310 iV3 = tOpo.vertices[0];
1311 n2 = tOpo.neighbors[2];
1312 n4 = tOpo.neighbors[0];
1316 iV3 = tOpo.vertices[1];
1317 n2 = tOpo.neighbors[0];
1318 n4 = tOpo.neighbors[1];
1322template <
typename T,
typename TNearPo
intLocator>
1323bool Triangulation<T, TNearPointLocator>::isSameOriginalEdge(
1325 const Edge& e2)
const
1327 if(!fixedEdges.count(e1) || !fixedEdges.count(e2))
1329 typedef unordered_map<Edge, EdgeVec>::const_iterator It;
1330 const It it1 = pieceToOriginals.find(e1);
1331 const It it2 = pieceToOriginals.find(e2);
1332 return (it1 == pieceToOriginals.end() ? e1 : it1->second.front()) ==
1333 (it2 == pieceToOriginals.end() ? e2 : it2->second.front());
1359template <
typename T,
typename TNearPo
intLocator>
1360bool Triangulation<T, TNearPointLocator>::isFlipNeeded(
1365 const bool doFlipFixedEdges)
const
1367 if(!doFlipFixedEdges && fixedEdges.count(Edge(iV2, iV4)))
1370 if(!fixedEdges.empty() &&
1371 (isSameOriginalEdge(Edge(iV1, iV2), Edge(iV2, iV3)) ||
1372 isSameOriginalEdge(Edge(iV3, iV4), Edge(iV4, iV1))))
1374 const V2d<T>& v1 = vertices[iV1];
1375 const V2d<T>& v2 = vertices[iV2];
1376 const V2d<T>& v3 = vertices[iV3];
1377 const V2d<T>& v4 = vertices[iV4];
1382 if(iV1 < nSuperTriVerts)
1385 if(iV2 < nSuperTriVerts)
1387 if(iV4 < nSuperTriVerts)
1391 if(iV3 < nSuperTriVerts)
1394 if(iV2 < nSuperTriVerts)
1398 if(iV4 < nSuperTriVerts)
1405 if(iV2 < nSuperTriVerts)
1407 if(iV4 < nSuperTriVerts)
1428template <
typename T,
typename TNearPo
intLocator>
1433#ifdef CDT_ENABLE_CALLBACK_HANDLER
1434 if(m_callbackHandler)
1436 m_callbackHandler->onFlipEdge(iT, iTopo);
1442 const array<TriInd, 3>& triNs = t.
neighbors;
1443 const array<TriInd, 3>& triOpoNs = tOpo.
neighbors;
1444 const array<VertInd, 3>& triVs = t.
vertices;
1445 const array<VertInd, 3>& triOpoVs = tOpo.
vertices;
1450 const TriInd n1 = triNs[i];
1453 const VertInd v3 = triOpoVs[i];
1455 const TriInd n4 = triOpoNs[i];
1461 changeNeighbor(n1, iT, iTopo);
1462 changeNeighbor(n4, iTopo, iT);
1468 setAdjacentTriangle(v4, iT);
1469 setAdjacentTriangle(v2, iTopo);
1473template <
typename T,
typename TNearPo
intLocator>
1474bool Triangulation<T, TNearPointLocator>::isRefinementNeeded(
1477 const T refinementThreshold)
const
1482 switch(refinementCriterion)
1487 return area(a, b, c) > refinementThreshold;
1493template <
typename T,
typename TNearPo
intLocator>
1494bool Triangulation<T, TNearPointLocator>::isSmallestAngleFixed(
1495 const Triangle& tri)
const
1499 vertices[tri.vertices[
ccw(
Index(0))]],
1500 vertices[tri.vertices[
cw(
Index(0))]]);
1501 for(Index i(1); i <
Index(3); ++i)
1504 vertices[tri.vertices[
ccw(i)]], vertices[tri.vertices[
cw(i)]]);
1505 if(sqLen < shortestSqLen)
1507 shortestSqLen = sqLen;
1511 const VertInd apex = tri.vertices[iApex];
1512 return fixedEdges.count(Edge(apex, tri.vertices[
ccw(iApex)])) &&
1513 fixedEdges.count(Edge(apex, tri.vertices[
cw(iApex)]));
1516template <
typename T,
typename TNearPo
intLocator>
1517bool Triangulation<T, TNearPointLocator>::isEdgeEncroached(
1518 const Edge& edge)
const
1521 tie(iT, iTopo) = edgeTriangles(edge.v1(), edge.v2());
1522 assert(iT != noNeighbor && iTopo != noNeighbor);
1525 const V2d<T>& edgeStart = vertices[edge.v1()];
1526 const V2d<T>& edgeEnd = vertices[edge.v2()];
1527 return detail::isEncroachingOnEdge(vertices[v1], edgeStart, edgeEnd) ||
1528 detail::isEncroachingOnEdge(vertices[v2], edgeStart, edgeEnd);
1531template <
typename T,
typename TNearPo
intLocator>
1532bool Triangulation<T, TNearPointLocator>::isEdgeEncroachedBy(
1534 const V2d<T>& v)
const
1536 return detail::isEncroachingOnEdge(
1537 v, vertices[edge.v1()], vertices[edge.v2()]);
1540template <
typename T,
typename TNearPo
intLocator>
1548 typedef EdgeUSet::const_iterator Iter;
1551 const Edge edge = *it;
1552 if(isEdgeEncroached(edge))
1554 encroachedEdges.push_back(edge);
1559 std::sort(encroachedEdges.begin(), encroachedEdges.end());
1560 return encroachedEdges;
1563template <
typename T,
typename TNearPo
intLocator>
1566 const T refinementThreshold)
const
1575 if(isRefinementNeeded(t, refinementCriterion, refinementThreshold))
1576 unrefinedTriangles.push_back(iT);
1578 return unrefinedTriangles;
1581template <
typename T,
typename TNearPo
intLocator>
1582EdgeVec Triangulation<T, TNearPointLocator>::edgesEncroachedBy(
1596 std::stack<TriInd> toTraverse;
1597 toTraverse.push(iT);
1598 traversed.insert(iT);
1599 while(!toTraverse.empty())
1601 const Triangle& t = triangles[toTraverse.top()];
1606 if(fixedEdges.count(opEdge))
1609 if(isEdgeEncroachedBy(opEdge, v))
1610 detail::insert_unique(encroachedEdges, opEdge);
1613 const TriInd iN = t.
neighbors[opoNbr(i)];
1614 if(iN == noNeighbor || traversed.count(iN))
1616 const Triangle& n = triangles[iN];
1617 if(!isInCircumcircle(
1619 vertices[n.vertices[0]],
1620 vertices[n.vertices[1]],
1621 vertices[n.vertices[2]]))
1623 traversed.insert(iN);
1624 toTraverse.push(iN);
1627 return encroachedEdges;
1630template <
typename T,
typename TNearPo
intLocator>
1631TriIndVec Triangulation<T, TNearPointLocator>::resolveEncroachedEdges(
1632 EdgeQueue encroachedEdges,
1633 VertInd& remainingVertexBudget,
1634 const VertInd steinerVerticesOffset,
1635 const V2d<T>*
const circumcenterOrNull,
1636 const RefinementCriterion::Enum refinementCriterion,
1637 const T badTriangleThreshold,
1638 TriIndUSet*
const toEraseOrNull,
1639 const T minEdgeLength,
1640 Unrefined& unrefined)
1642 std::vector<TriInd> badTriangles;
1644 while(!encroachedEdges.empty() && remainingVertexBudget > 0)
1646 const Edge edge = encroachedEdges.front();
1647 encroachedEdges.pop();
1648 if(fixedEdges.find(edge) == fixedEdges.end())
1653 if(
distance(vertices[edge.v1()], vertices[edge.v2()]) <= minEdgeLength)
1655 ++unrefined.shortEdges;
1660 edge, steinerVerticesOffset, toEraseOrNull, unrefined);
1661 if(!splitVert.hasValue())
1663 const VertInd iSplitVert = splitVert.value();
1664 --remainingVertexBudget;
1666 const TriInd start = m_vertTris[iSplitVert];
1670 const Triangle& t = triangles[iT];
1671 const bool isMarkedForErasure =
1672 toEraseOrNull && toEraseOrNull->count(iT);
1673 if(circumcenterOrNull && !isMarkedForErasure &&
1675 isRefinementNeeded(t, refinementCriterion, badTriangleThreshold))
1677 badTriangles.push_back(iT);
1679 for(Index i(0); i <
Index(3); ++i)
1681 const Edge triEdge(t.vertices[i], t.vertices[
cw(i)]);
1682 if(fixedEdges.find(triEdge) == fixedEdges.end())
1684 if(isEdgeEncroached(triEdge))
1686 encroachedEdges.push(triEdge);
1689 iT = t.
next(iSplitVert).first;
1690 }
while(iT != start);
1692 return badTriangles;
1695template <
typename T,
typename TNearPo
intLocator>
1696OptionalVertInd Triangulation<T, TNearPointLocator>::splitEncroachedEdge(
1698 const VertInd steinerVerticesOffset,
1699 TriIndUSet*
const toEraseOrNull,
1700 Unrefined& unrefined)
1702 const V2d<T>& start = vertices[edge.v1()];
1703 const V2d<T>& end = vertices[edge.v2()];
1706 tie(iT, iTopo) = edgeTriangles(edge.v1(), edge.v2());
1707 assert(iT != noNeighbor && iTopo != noNeighbor);
1712 if(edge.v1() < steinerVerticesOffset &&
1713 edge.v2() >= steinerVerticesOffset &&
1714 hasAnotherFixedEdgeAtSmallAngle(edge.v1(), edge))
1718 const T len =
distance(start, end);
1719 const T d = len / T(2);
1721 T nearestPowerOfTwo = T(1);
1722 while(d > nearestPowerOfTwo)
1724 nearestPowerOfTwo *= T(2);
1726 while(d < T(0.75) * nearestPowerOfTwo)
1728 nearestPowerOfTwo *= T(0.5);
1730 split = nearestPowerOfTwo / len;
1733 const V2d<T> mid = V2d<T>(
1734 detail::lerp(start.x, end.x, split),
1735 detail::lerp(start.y, end.y, split));
1738 edge, mid, iT, iTopo, AddVertexType::RefinementEdgeSplit);
1739 if(!iMid.hasValue())
1741 ++unrefined.splitVertexInvalid;
1743 else if(toEraseOrNull)
1747 if(toEraseOrNull->count(iT))
1748 toEraseOrNull->insert(
TriInd(triangles.size() - 2));
1749 if(toEraseOrNull->count(iTopo))
1750 toEraseOrNull->insert(
TriInd(triangles.size() - 1));
1771template <
typename T,
typename TNearPo
intLocator>
1784#ifdef CDT_ENABLE_CALLBACK_HANDLER
1785 if(m_callbackHandler)
1787 m_callbackHandler->onFlipEdge(iT, iTopo);
1795 changeNeighbor(n1, iT, iTopo);
1796 changeNeighbor(n4, iTopo, iT);
1802 setAdjacentTriangle(v4, iT);
1803 setAdjacentTriangle(v2, iTopo);
1823template <
typename T,
typename TNearPo
intLocator>
1825Triangulation<T, TNearPointLocator>::insertVertexInsideTriangle(
1829 const TriInd iNewT1 = addTriangle();
1830 const TriInd iNewT2 = addTriangle();
1832#ifdef CDT_ENABLE_CALLBACK_HANDLER
1833 if(m_callbackHandler)
1835 m_callbackHandler->onInsertVertexInsideTriangle(iT, iNewT1, iNewT2);
1839 Triangle& t = triangles[iT];
1840 const array<VertInd, 3> vv = t.vertices;
1841 const array<TriInd, 3> nn = t.neighbors;
1842 const VertInd v1 = vv[0], v2 = vv[1], v3 = vv[2];
1843 const TriInd n1 = nn[0], n2 = nn[1], n3 = nn[2];
1846 triangles[iNewT1] = Triangle(arr3(v2, v3, v), arr3(n2, iNewT2, iT));
1847 triangles[iNewT2] = Triangle(arr3(v3, v1, v), arr3(n3, iT, iNewT1));
1848 t = Triangle(arr3(v1, v2, v), arr3(n1, iNewT1, iNewT2));
1850 setAdjacentTriangle(v, iT);
1851 setAdjacentTriangle(v3, iNewT1);
1853 changeNeighbor(n2, iT, iNewT1);
1854 changeNeighbor(n3, iT, iNewT2);
1856 std::stack<TriInd> newTriangles;
1857 newTriangles.push(iT);
1858 newTriangles.push(iNewT1);
1859 newTriangles.push(iNewT2);
1860 return newTriangles;
1876template <
typename T,
typename TNearPo
intLocator>
1877std::stack<TriInd> Triangulation<T, TNearPointLocator>::insertVertexOnEdge(
1881 const bool doHandleFixedSplitEdge)
1883 const TriInd iTnew1 = addTriangle();
1884 const TriInd iTnew2 = addTriangle();
1886#ifdef CDT_ENABLE_CALLBACK_HANDLER
1887 if(m_callbackHandler)
1889 m_callbackHandler->onInsertVertexOnEdge(iT1, iT2, iTnew1, iTnew2);
1893 Triangle& t1 = triangles[iT1];
1894 Triangle& t2 = triangles[iT2];
1896 const VertInd v1 = t1.vertices[i];
1898 const TriInd n1 = t1.neighbors[i];
1899 const TriInd n4 = t1.neighbors[
cw(i)];
1901 const VertInd v3 = t2.vertices[i];
1903 const TriInd n3 = t2.neighbors[i];
1904 const TriInd n2 = t2.neighbors[
cw(i)];
1906 t1 = Triangle(
arr3(v, v1, v2),
arr3(iTnew1, n1, iT2));
1907 t2 = Triangle(
arr3(v, v2, v3),
arr3(iT1, n2, iTnew2));
1908 triangles[iTnew1] = Triangle(
arr3(v, v4, v1),
arr3(iTnew2, n4, iT1));
1909 triangles[iTnew2] = Triangle(
arr3(v, v3, v4),
arr3(iT2, n3, iTnew1));
1911 setAdjacentTriangle(v, iT1);
1912 setAdjacentTriangle(v4, iTnew1);
1914 changeNeighbor(n4, iT1, iTnew1);
1915 changeNeighbor(n3, iT2, iTnew2);
1917 if(doHandleFixedSplitEdge)
1919 const Edge sharedEdge(v2, v4);
1920 if(fixedEdges.count(sharedEdge))
1921 splitFixedEdge(sharedEdge, v);
1924 std::stack<TriInd> newTriangles;
1925 newTriangles.push(iT1);
1926 newTriangles.push(iTnew2);
1927 newTriangles.push(iT2);
1928 newTriangles.push(iTnew1);
1929 return newTriangles;
1932template <
typename T,
typename TNearPo
intLocator>
1934Triangulation<T, TNearPointLocator>::trianglesAt(
const V2d<T>& pos)
const
1936 array<TriInd, 2> out = {noNeighbor, noNeighbor};
1937 for(TriInd i =
TriInd(0); i <
TriInd(triangles.size()); ++i)
1939 const Triangle& t = triangles[i];
1940 const V2d<T>& v1 = vertices[t.vertices[0]];
1941 const V2d<T>& v2 = vertices[t.vertices[1]];
1942 const V2d<T>& v3 = vertices[t.vertices[2]];
1944 if(loc == PtTriLocation::Outside)
1952 Error(
"No triangle was found at position", CDT_SOURCE_LOCATION));
1956template <
typename T,
typename TNearPo
intLocator>
1957OptionalTriInd Triangulation<T, TNearPointLocator>::walkTriangles(
1958 const VertInd startVertex,
1959 const V2d<T>& pos)
const
1962 TriInd currTri = m_vertTris[startVertex];
1964 bool isOutside =
false;
1965 detail::SplitMix64RandGen prng;
1968 const Triangle& t = triangles[currTri];
1972 const Index offset(prng() % 3);
1973 for(Index i_(0); i_ <
Index(3); ++i_)
1975 const Index i((i_ + offset) % 3);
1976 const V2d<T>& vStart = vertices[t.vertices[i]];
1977 const V2d<T>& vEnd = vertices[t.vertices[
ccw(i)]];
1978 const PtLineLocation::Enum edgeCheck =
1980 const TriInd iN = t.neighbors[i];
1981 if(edgeCheck == PtLineLocation::Right)
1983 if(iN != noNeighbor)
1998template <
typename T,
typename TNearPo
intLocator>
1999array<TriInd, 2> Triangulation<T, TNearPointLocator>::walkingSearchTrianglesAt(
2001 const VertInd startVertex)
const
2003 const V2d<T> v = vertices[iV];
2004 array<TriInd, 2> out = {noNeighbor, noNeighbor};
2006 if(!walkResult.hasValue())
2009 Error(
"No triangle was found at position", CDT_SOURCE_LOCATION));
2011 const TriInd iT = walkResult.value();
2013 const Triangle& t = triangles[iT];
2014 const V2d<T>& v1 = vertices[t.vertices[0]];
2015 const V2d<T>& v2 = vertices[t.vertices[1]];
2016 const V2d<T>& v3 = vertices[t.vertices[2]];
2019 if(loc == PtTriLocation::Outside)
2022 Error(
"No triangle was found at position", CDT_SOURCE_LOCATION));
2024 if(loc == PtTriLocation::OnVertex)
2026 const VertInd iDupe = v1 == v ? t.vertices[0]
2027 : v2 == v ? t.vertices[1]
2029 handleException(DuplicateVertexError(
2031 VertInd(iDupe - nSuperTriVerts),
2032 CDT_SOURCE_LOCATION));
2041template <
typename T,
typename TNearPo
intLocator>
2042void Triangulation<T, TNearPointLocator>::changeNeighbor(
2044 const TriInd oldNeighbor,
2045 const TriInd newNeighbor)
2047 if(iT == noNeighbor)
2051 nn[0] == oldNeighbor || nn[1] == oldNeighbor || nn[2] == oldNeighbor);
2052 if(nn[0] == oldNeighbor)
2053 nn[0] = newNeighbor;
2054 else if(nn[1] == oldNeighbor)
2055 nn[1] = newNeighbor;
2057 nn[2] = newNeighbor;
2060template <
typename T,
typename TNearPo
intLocator>
2061void Triangulation<T, TNearPointLocator>::changeNeighbor(
2063 const VertInd iVedge1,
2064 const VertInd iVedge2,
2065 const TriInd newNeighbor)
2067 assert(iT != noNeighbor);
2068 Triangle& t = triangles[iT];
2069 t.neighbors[
edgeNeighborInd(t.vertices, iVedge1, iVedge2)] = newNeighbor;
2072template <
typename T,
typename TNearPo
intLocator>
2073void Triangulation<T, TNearPointLocator>::triangulatePseudoPolygon(
2074 const std::vector<VertInd>& poly,
2075 unordered_map<Edge, TriInd>& outerTris,
2078 std::vector<TriInd>& trianglesToReuse,
2079 std::vector<TriangulatePseudoPolygonTask>& iterations)
2081 assert(poly.size() > 2);
2084 iterations.push_back(make_tuple(
2086 static_cast<IndexSizeType
>(poly.size() - 1),
2090 while(!iterations.empty())
2092 triangulatePseudoPolygonIteration(
2093 poly, outerTris, trianglesToReuse, iterations);
2097template <
typename T,
typename TNearPo
intLocator>
2098void Triangulation<T, TNearPointLocator>::triangulatePseudoPolygonIteration(
2099 const std::vector<VertInd>& poly,
2100 unordered_map<Edge, TriInd>& outerTris,
2101 std::vector<TriInd>& trianglesToReuse,
2102 std::vector<TriangulatePseudoPolygonTask>& iterations)
2104 IndexSizeType iA, iB;
2107 assert(!iterations.empty());
2108 tie(iA, iB, iT, iParent, iInParent) = iterations.back();
2109 iterations.pop_back();
2110 assert(iB - iA > 1 && iT != noNeighbor && iParent != noNeighbor);
2111 Triangle& t = triangles[iT];
2113 const IndexSizeType iC = findDelaunayPoint(poly, iA, iB);
2125 assert(!trianglesToReuse.empty());
2126 const TriInd iNext = trianglesToReuse.back();
2127 trianglesToReuse.pop_back();
2128 iterations.push_back(make_tuple(iC, iB, iNext, iT,
Index(1)));
2132 const Edge outerEdge(b, c);
2133 const TriInd outerTri = outerTris.at(outerEdge);
2134 if(outerTri != noNeighbor)
2136 assert(outerTri != iT);
2137 t.neighbors[1] = outerTri;
2138 changeNeighbor(outerTri, c, b, iT);
2141 outerTris.at(outerEdge) = iT;
2146 assert(!trianglesToReuse.empty());
2147 const TriInd iNext = trianglesToReuse.back();
2148 trianglesToReuse.pop_back();
2149 iterations.push_back(make_tuple(iA, iC, iNext, iT,
Index(2)));
2153 const Edge outerEdge(c, a);
2154 const TriInd outerTri = outerTris.at(outerEdge);
2155 if(outerTri != noNeighbor)
2157 assert(outerTri != iT);
2158 t.neighbors[2] = outerTri;
2159 changeNeighbor(outerTri, c, a, iT);
2162 outerTris.at(outerEdge) = iT;
2167 triangles[iParent].neighbors[iInParent] = iT;
2168 t.neighbors[0] = iParent;
2169 t.vertices =
arr3(a, b, c);
2170 setAdjacentTriangle(c, iT);
2173template <
typename T,
typename TNearPo
intLocator>
2174IndexSizeType Triangulation<T, TNearPointLocator>::findDelaunayPoint(
2175 const std::vector<VertInd>& poly,
2176 const IndexSizeType iA,
2177 const IndexSizeType iB)
const
2179 assert(iB - iA > 1);
2180 const V2d<T>& a = vertices[poly[iA]];
2181 const V2d<T>& b = vertices[poly[iB]];
2182 IndexSizeType out = iA + 1;
2183 const V2d<T>* c = &vertices[poly[out]];
2184 for(IndexSizeType i = iA + 1; i < iB; ++i)
2186 const V2d<T>& v = vertices[poly[i]];
2193 assert(out > iA && out < iB);
2197template <
typename T,
typename TNearPo
intLocator>
2199 const std::vector<
V2d<T> >& newVertices)
2205template <
typename T,
typename TNearPo
intLocator>
2208 return m_vertTris.empty() && !
vertices.empty();
2211template <
typename T,
typename TNearPo
intLocator>
2212unordered_map<TriInd, LayerDepth>
2213Triangulation<T, TNearPointLocator>::peelLayer(
2214 std::stack<TriInd> seeds,
2216 std::vector<LayerDepth>& triDepths)
const
2218 unordered_map<TriInd, LayerDepth> behindBoundary;
2219 while(!seeds.empty())
2221 const TriInd iT = seeds.top();
2223 triDepths[iT] = std::min(triDepths[iT], layerDepth);
2224 behindBoundary.erase(iT);
2230 if(iN == noNeighbor || triDepths[iN] <= layerDepth)
2232 if(fixedEdges.count(opEdge))
2234 const unordered_map<Edge, LayerDepth>::const_iterator cit =
2235 overlapCount.find(opEdge);
2236 const LayerDepth triDepth = cit == overlapCount.end()
2238 : layerDepth + cit->second + 1;
2239 behindBoundary[iN] = triDepth;
2245 return behindBoundary;
2248template <
typename T,
typename TNearPo
intLocator>
2249std::vector<LayerDepth>
2252 std::vector<LayerDepth> triDepths(
2253 triangles.size(), std::numeric_limits<LayerDepth>::max());
2254 std::stack<TriInd> seeds(TriDeque(1, m_vertTris[0]));
2258 unordered_map<LayerDepth, TriIndUSet> seedsByDepth;
2261 const unordered_map<TriInd, LayerDepth>& newSeeds =
2262 peelLayer(seeds, layerDepth, triDepths);
2264 seedsByDepth.erase(layerDepth);
2265 typedef unordered_map<TriInd, LayerDepth>::const_iterator Iter;
2266 for(Iter it = newSeeds.begin(); it != newSeeds.end(); ++it)
2268 deepestSeedDepth = std::max(deepestSeedDepth, it->second);
2269 seedsByDepth[it->second].insert(it->first);
2271 const TriIndUSet& nextLayerSeeds = seedsByDepth[layerDepth + 1];
2272 seeds = std::stack<TriInd>(
2273 TriDeque(nextLayerSeeds.begin(), nextLayerSeeds.end()));
2275 }
while(!seeds.empty() || deepestSeedDepth > layerDepth);
2280#ifdef CDT_ENABLE_CALLBACK_HANDLER
2281template <
typename T,
typename TNearPo
intLocator>
2285 m_callbackHandler = callbackHandler;
2289template <
typename T,
typename TNearPo
intLocator>
2290void Triangulation<T, TNearPointLocator>::insertVertices_AsProvided(
2293 for(
VertInd iV = superGeomVertCount; iV < vertices.size(); ++iV)
2295#ifdef CDT_ENABLE_CALLBACK_HANDLER
2296 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
2305template <
typename T,
typename TNearPo
intLocator>
2306void Triangulation<T, TNearPointLocator>::insertVertices_Randomized(
2307 VertInd superGeomVertCount)
2309 std::size_t vertexCount = vertices.size() - superGeomVertCount;
2310 std::vector<VertInd> ii(vertexCount);
2311 detail::iota(ii.begin(), ii.end(), superGeomVertCount);
2312 detail::random_shuffle(ii.begin(), ii.end());
2313 for(std::vector<VertInd>::iterator it = ii.begin(); it != ii.end(); ++it)
2315#ifdef CDT_ENABLE_CALLBACK_HANDLER
2316 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
2329template <
typename T>
2330inline double log2_bc(T x)
2332#ifdef CDT_CXX11_IS_SUPPORTED
2333 return std::log2(x);
2335 static double log2_constant = std::log(2.0);
2336 return std::log(
static_cast<double>(x)) / log2_constant;
2346 const int filledLayerPow2 =
2347 static_cast<int>(std::floor(log2_bc(vertexCount)) - 1);
2348 const std::size_t nodesInFilledTree =
2349 static_cast<std::size_t
>(std::pow(2., filledLayerPow2 + 1) - 1);
2350 const std::size_t nodesInLastFilledLayer =
2351 static_cast<std::size_t
>(std::pow(2., filledLayerPow2));
2352 const std::size_t nodesInLastLayer = vertexCount - nodesInFilledTree;
2353 return nodesInLastLayer >= nodesInLastFilledLayer
2354 ? nodesInLastFilledLayer + nodesInLastLayer -
2355 nodesInLastFilledLayer
2356 : nodesInLastFilledLayer;
2359template <
typename T>
2360class FixedCapacityQueue
2363 FixedCapacityQueue(
const std::size_t capacity)
2365 , m_front(m_vec.begin())
2366 , m_back(m_vec.begin())
2373 const T& front()
const
2381 if(m_front == m_vec.end())
2382 m_front = m_vec.begin();
2385 void push(
const T& t)
2387 assert(m_size < m_vec.size());
2390 if(m_back == m_vec.end())
2391 m_back = m_vec.begin();
2394#ifdef CDT_CXX11_IS_SUPPORTED
2395 void push(
const T&& t)
2397 assert(m_size < m_vec.size());
2400 if(m_back == m_vec.end())
2401 m_back = m_vec.begin();
2406 std::vector<T> m_vec;
2407 typename std::vector<T>::iterator m_front;
2408 typename std::vector<T>::iterator m_back;
2412template <
typename T>
2415 const std::vector<V2d<T> >& m_vertices;
2418 less_than_x(
const std::vector<
V2d<T> >& vertices)
2419 : m_vertices(vertices)
2423 return m_vertices[a].x < m_vertices[b].x;
2427template <
typename T>
2430 const std::vector<V2d<T> >& m_vertices;
2433 less_than_y(
const std::vector<
V2d<T> >& vertices)
2434 : m_vertices(vertices)
2438 return m_vertices[a].y < m_vertices[b].y;
2444template <
typename T,
typename TNearPo
intLocator>
2445void Triangulation<T, TNearPointLocator>::insertVertices_KDTreeBFS(
2450 const VertInd vertexCount(verticesCount() - superGeomVertCount);
2453 std::vector<VertInd> ii(vertexCount);
2454 detail::iota(ii.begin(), ii.end(), superGeomVertCount);
2456 typedef std::vector<VertInd>::iterator It;
2459 queue.push(make_tuple(ii.begin(), ii.end(), box.
min, box.
max,
VertInd(0)));
2462 V2d<T> newBoxMin, newBoxMax;
2468 while(!queue.empty())
2470#ifdef CDT_ENABLE_CALLBACK_HANDLER
2471 if(m_callbackHandler && m_callbackHandler->isAbortCalculation())
2476 tie(first, last, box.
min, box.
max, parent) = queue.front();
2478 assert(first != last);
2480 const std::ptrdiff_t len = std::distance(first, last);
2483 insertVertex(*first, parent);
2486 const It midIt = first + len / 2;
2489 detail::portable_nth_element(first, midIt, last, cmpX);
2491 const T split = vertices[mid].x;
2492 newBoxMin.
x = split;
2493 newBoxMin.
y = box.
min.y;
2494 newBoxMax.
x = split;
2495 newBoxMax.
y = box.
max.y;
2499 detail::portable_nth_element(first, midIt, last, cmpY);
2501 const T split = vertices[mid].y;
2502 newBoxMin.
x = box.
min.x;
2503 newBoxMin.
y = split;
2504 newBoxMax.
x = box.
max.x;
2505 newBoxMax.
y = split;
2507 insertVertex(mid, parent);
2510 queue.push(make_tuple(first, midIt, box.
min, newBoxMax, mid));
2512 if(midIt + 1 != last)
2514 queue.push(make_tuple(midIt + 1, last, newBoxMin, box.
max, mid));
2519template <
typename T,
typename TNearPo
intLocator>
2520std::pair<TriInd, TriInd> Triangulation<T, TNearPointLocator>::edgeTriangles(
2522 const VertInd b)
const
2524 const TriInd triStart = m_vertTris[a];
2525 assert(triStart != noNeighbor);
2526 TriInd iT = triStart, iTNext = triStart;
2530 const Triangle& t = triangles[iT];
2531 tie(iTNext, iV) = t.
next(a);
2532 assert(iTNext != noNeighbor);
2535 return std::make_pair(iT, iTNext);
2538 }
while(iT != triStart);
2539 return std::make_pair(noNeighbor, noNeighbor);
2542template <
typename T,
typename TNearPo
intLocator>
2543bool Triangulation<T, TNearPointLocator>::hasEdge(
2545 const VertInd b)
const
2547 return edgeTriangles(a, b).first != invalidIndexSizeType;
2550template <
typename T,
typename TNearPo
intLocator>
2551VertInd Triangulation<T, TNearPointLocator>::opposedVertexOnEdge(
2553 const T tolerance)
const
2555 if(fixedEdges.count(edge))
2557 const V2d<T>& a = vertices[edge.v1()];
2558 const V2d<T>& b = vertices[edge.v2()];
2559 const std::pair<TriInd, TriInd> tris = edgeTriangles(edge.v1(), edge.v2());
2563 for(
int i = 0; i < 2; ++i)
2565 const V2d<T>& v = vertices[opposed[i]];
2569 detail::isEncroachingOnEdge(v, a, b))
2578template <
typename T,
typename TNearPo
intLocator>
2579bool Triangulation<T, TNearPointLocator>::hasAnotherFixedEdgeAtSmallAngle(
2581 const Edge& excludeEdge)
const
2585 excludeEdge.v1() == v ? excludeEdge.v2() : excludeEdge.v1();
2586 const TriInd triStart = m_vertTris[v];
2587 assert(triStart != noNeighbor);
2591 const Triangle& t = triangles[iT];
2594 tie(iTNext, iV) = t.next(v);
2595 const Edge candidate(v, iV);
2596 if(candidate != excludeEdge && fixedEdges.count(candidate) &&
2597 detail::isAngleAtApexSmall(
2598 vertices[v], vertices[iVOther], vertices[iV]))
2603 }
while(iT != triStart);
2607template <
typename T,
typename TNearPo
intLocator>
2608void Triangulation<T, TNearPointLocator>::setAdjacentTriangle(
2612 assert(t != noNeighbor);
2615 triangles[t].vertices[0] == v || triangles[t].vertices[1] == v ||
2616 triangles[t].vertices[2] == v);
2619template <
typename T,
typename TNearPo
intLocator>
2620void Triangulation<T, TNearPointLocator>::pivotVertexTriangleCW(
const VertInd v)
2622 assert(m_vertTris[v] != noNeighbor);
2623 m_vertTris[v] = triangles[m_vertTris[v]].next(v).first;
2624 assert(m_vertTris[v] != noNeighbor);
2626 triangles[m_vertTris[v]].vertices[0] == v ||
2627 triangles[m_vertTris[v]].vertices[1] == v ||
2628 triangles[m_vertTris[v]].vertices[2] == v);
2631template <
typename T,
typename TNearPo
intLocator>
2632void Triangulation<T, TNearPointLocator>::tryAddVertexToLocator(
const VertInd v)
2634 if(!m_nearPtLocator.empty())
2635 m_nearPtLocator.addPoint(v, vertices);
2638template <
typename T,
typename TNearPo
intLocator>
2639void Triangulation<T, TNearPointLocator>::tryInitNearestPointLocator()
2641 if(!vertices.empty() && m_nearPtLocator.empty())
2643 m_nearPtLocator.initialize(vertices);
2647template <
typename T,
typename TNearPo
intLocator>
2649 const VertInd maxVerticesToInsert,
2651 const T refinementThreshold,
2653 const T minEdgeLength)
2658 tryInitNearestPointLocator();
2661 VertInd remainingVertexBudget = maxVerticesToInsert;
2665 resolveEncroachedEdges(
2667 remainingVertexBudget,
2668 steinerVerticesOffset,
2670 refinementCriterion,
2671 refinementThreshold,
2678 std::queue<std::pair<TriInd, VerticesArr3> > badTriangles;
2683 !(toEraseOrNull && toEraseOrNull->count(iT)) &&
2684 isRefinementNeeded(t, refinementCriterion, refinementThreshold))
2686 badTriangles.push(std::make_pair(iT, t.
vertices));
2690 while(!badTriangles.empty() && remainingVertexBudget > 0)
2692 const TriInd iT = badTriangles.front().first;
2696 if(toEraseOrNull && toEraseOrNull->count(iT))
2700 if(!isRefinementNeeded(t, refinementCriterion, refinementThreshold) ||
2702 isSmallestAngleFixed(t)))
2711 const T shortestEdge = std::min(
2713 if(shortestEdge <= minEdgeLength)
2721 m_nearPtLocator.nearPoint(circumcenterPos,
vertices),
2723 if(!triAtCircumcenter.hasValue())
2730 const VertInd budgetBeforeSplits = remainingVertexBudget;
2731 const EdgeVec encroachedEdges =
2732 edgesEncroachedBy(circumcenterPos, triAtCircumcenter.value());
2733 const TriIndVec badTris = resolveEncroachedEdges(
2735 remainingVertexBudget,
2736 steinerVerticesOffset,
2738 refinementCriterion,
2739 refinementThreshold,
2743 if(!remainingVertexBudget)
2748 if(remainingVertexBudget != budgetBeforeSplits || !badTris.empty())
2750 typedef TriIndVec::const_iterator It;
2751 for(It it = badTris.begin(); it != badTris.end(); ++it)
2759 if(!encroachedEdges.empty())
2762 const TriInd iCircumcenterTri = triAtCircumcenter.value();
2769 if(loc == PtTriLocation::OnVertex)
2775 const array<TriInd, 2> trisAt = {
2781 (toEraseOrNull->count(trisAt[0]) || toEraseOrNull->count(trisAt[1])))
2788 --remainingVertexBudget;
2790 addNewVertex(circumcenterPos, noNeighbor);
2791#ifdef CDT_ENABLE_CALLBACK_HANDLER
2792 if(m_callbackHandler)
2794 m_callbackHandler->onAddVertexStart(
2798 std::stack<TriInd> triStack =
2799 trisAt[1] == noNeighbor
2800 ? insertVertexInsideTriangle(iVert, trisAt[0])
2801 : insertVertexOnEdge(iVert, trisAt[0], trisAt[1],
true);
2802 ensureDelaunayByEdgeFlips(iVert, triStack);
2803 tryAddVertexToLocator(iVert);
2805 TriInd start = m_vertTris[iVert];
2810 if(!(toEraseOrNull && toEraseOrNull->count(currTri)) &&
2812 isRefinementNeeded(t, refinementCriterion, refinementThreshold))
2814 badTriangles.push(std::make_pair(currTri, t.
vertices));
2816 currTri = t.
next(iVert).first;
2817 }
while(currTri != start);
2828 (toEraseOrNull && toEraseOrNull->count(iT)))
2832 if(isRefinementNeeded(
2833 t, refinementCriterion, refinementThreshold) &&
2834 isSmallestAngleFixed(t))
2845CDT_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...
bool isAngleAtApexSmall(const V2d< T > &apex, const V2d< T > &a, const V2d< T > &b)
Whether the angle at apex between apex->a and apex->b is smaller than 60°
EdgeQueue toQueue(const EdgeVec &edges)
Turn a vector into a queue, preserving order.
void sortUnique(TVec &v)
Sort a vector and remove its duplicate elements.
Error thrown when triangulation modification is attempted after it was finalized.
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...
EdgeUSet fixedEdges
triangulation's constraints (fixed edges)
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.
TriIndUSet collectSuperTriangle() const
Collect triangles adjacent to super-triangle: same triangles that eraseSuperTriangle would remove.
bool isFinalized() const
Check if the triangulation was finalized with erase... method and super-triangle was removed.
TriIndUSet collectOuterTrianglesAndHoles() const
Collect triangles outside of constrained boundary and auto-detected holes: same triangles that eraseO...
TriIndVec findUnrefinedTriangles(RefinementCriterion::Enum refinementCriterion=RefinementCriterion::SmallestAngle, T refinementThreshold=degToRad(T(20))) const
Find triangles that don't fulfill the refinement criterion.
void finalizeTriangulation(const TriIndUSet &removedTriangles)
Remove super-triangle and triangles with specified indices.
void eraseOuterTrianglesAndHoles()
Erase triangles outside of constrained boundary and auto-detected holes.
V2dVec vertices
triangulation's vertices
TriIndUSet collectOuterTriangles() const
Collect triangles outside of constrained boundary: same triangles that eraseOuterTriangles would remo...
Unrefined refineTriangles(VertInd maxVerticesToInsert, RefinementCriterion::Enum refinementCriterion=RefinementCriterion::SmallestAngle, T refinementThreshold=degToRad(T(20)), TriIndUSet *toEraseOrNull=NULL, T minEdgeLength=T(1e-6))
Triangles refinement by splitting bad triangles.
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.
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
Triangulation()
Default constructor.
EdgeVec findEncroachedFixedEdges() const
Find all fixed edges encroached by their opposed vertices.
void setCallbackHandler(ICallbackHandler *callbackHandler)
Set user-provided callback handler.
unsigned short LayerDepth
Type used for storing layer depths for triangles.
OptionalIndex< VertInd > OptionalVertInd
Optional vertex index.
OptionalIndex< TriInd > OptionalTriInd
Optional triangle index.
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.
CDT_EXPORT T area(const V2d< T > &a, const V2d< T > &b, const V2d< T > &c)
Surface area of a triangle ABC.
std::vector< TriInd > TriIndVec
Vector of triangle indices.
CDT_EXPORT 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_EXPORT 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.
CDT_EXPORT T distanceSquared(const V2d< T > &a, const V2d< T > &b)
Squared distance between two 2D points.
unordered_set< TriInd > TriIndUSet
Hash table of triangles.
CDT_EXPORT Index ccw(Index i)
Advance vertex or neighbor index counter-clockwise.
CDT_EXPORT V2d< T > circumcenter(V2d< T > a, V2d< T > b, V2d< T > c)
Position of ABC triangle circumcenter.
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 T smallestAngle(const V2d< T > &a, const V2d< T > &b, const V2d< T > &c)
Smallest angle of triangle ABC in radians.
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.
std::queue< Edge > EdgeQueue
Queue of edges.
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.
@ RefinementCircumcenter
Refinement: circumcenter of a poor-quality triangle.
@ 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.
@ LargestArea
constraint maximum triangles area
@ SmallestAngle
constraint minimum triangles angle
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)
Counts of the refinements that Triangulation::refineTriangles was not able to perform.
std::size_t circumcenterOnVertex
triangles whose circumcenter coincides with an existing vertex
std::size_t sharpFixedCorner
triangles whose smallest angle is enclosed by two fixed edges: such an angle comes from the input and...
std::size_t splitVertexInvalid
fixed edges whose split vertex can not be placed: inserting it would break the triangulation's topolo...
std::size_t circumcenterOutside
triangles whose circumcenter is outside the triangulated area
std::size_t shortEdges
fixed edges that are shorter than the threshold
std::size_t shortEdgeTriangles
triangles whose shortest edge is shorter than the threshold
Unrefined()
Constructor: all the counts start at zero.
@ Auto
Automatic insertion order optimized for better performance.