From 6d51b91e2904f4d0bab6a9d32457670920589c33 Mon Sep 17 00:00:00 2001 From: artem-ogre Date: Fri, 26 Aug 2022 12:31:12 +0200 Subject: [PATCH] Fix wrong implementation of iterative conformToEdge converted from recursive Fix erroneous overlap counts of zero in conforming triangulation Adjust tests --- CDT/include/Triangulation.h | 26 ++-- CDT/include/Triangulation.hpp | 121 +++++++++++------- ...ges__conforming_randomized_resolve_all.txt | 4 +- 3 files changed, 84 insertions(+), 67 deletions(-) diff --git a/CDT/include/Triangulation.h b/CDT/include/Triangulation.h index 704e7a3d..16c80983 100644 --- a/CDT/include/Triangulation.h +++ b/CDT/include/Triangulation.h @@ -407,43 +407,36 @@ class CDT_EXPORT Triangulation * Conform Delaunay triangulation to a fixed edge by recursively inserting * mid point of the edge and then conforming to its halves * @param edge fixed edge to conform to - * @param originalEdges original edges that new edge is piece of + * @param originals original edges that new edge is piece of * @param overlaps count of overlapping boundaries at the edge. Only used * when re-introducing edge with overlaps > 0 * @param[in,out] remaining remaining edge parts to be conformed to - * @param[in,out] reintroduce fixed edges that got removed during conforming - * process and need to be reintroduced * @note in-out state (@param remaining @param reintroduce) is shared * between different runs for performance gains (reducing memory * allocations) */ void conformToEdge( Edge edge, - const EdgeVec& originalEdges, + EdgeVec originals, BoundaryOverlapCount overlaps, - EdgeVec& remaining, - std::vector& reintroduce); + std::vector& remaining); /** * Iteration of conform to fixed edge. * @param edge fixed edge to conform to - * @param originalEdges original edges that new edge is piece of + * @param originals original edges that new edge is piece of * @param overlaps count of overlapping boundaries at the edge. Only used * when re-introducing edge with overlaps > 0 - * @param[in,out] remaining remaining edge parts that need to be conformed - * to - * @param[in,out] reintroduce fixed edges that got removed during conforming - * process and need to be reintroduced + * @param[in,out] remaining remaining edge parts * @note in-out state (@param remaining @param reintroduce) is shared * between different runs for performance gains (reducing memory * allocations) */ void conformToEdgeIteration( Edge edge, - const EdgeVec& originalEdges, + const EdgeVec& originals, BoundaryOverlapCount overlaps, - EdgeVec& remaining, - std::vector& reintroduce); + std::vector& remaining); tuple intersectedTriangle( VertInd iA, @@ -670,15 +663,14 @@ void Triangulation::conformToEdges( "new edges is not possible"); } // state shared between different runs for performance gains - EdgeVec remaining; - std::vector reintroduce; + std::vector remaining; for(; first != last; ++first) { // +3 to account for super-triangle vertices const Edge e( VertInd(getStart(*first) + m_nTargetVerts), VertInd(getEnd(*first) + m_nTargetVerts)); - conformToEdge(e, EdgeVec(1, e), 0, remaining, reintroduce); + conformToEdge(e, EdgeVec(1, e), 0, remaining); } eraseDummies(); } diff --git a/CDT/include/Triangulation.hpp b/CDT/include/Triangulation.hpp index 357c02fc..ee99ec30 100644 --- a/CDT/include/Triangulation.hpp +++ b/CDT/include/Triangulation.hpp @@ -643,10 +643,9 @@ void Triangulation::insertEdge( template void Triangulation::conformToEdgeIteration( Edge edge, - const EdgeVec& originalEdges, + const EdgeVec& originals, BoundaryOverlapCount overlaps, - EdgeVec& remaining, - std::vector& reintroduce) + std::vector& remaining) { const VertInd iA = edge.v1(); VertInd iB = edge.v2(); @@ -660,9 +659,9 @@ void Triangulation::conformToEdgeIteration( { overlaps > 0 ? fixEdge(edge, overlaps) : fixEdge(edge); // avoid marking edge as a part of itself - if(!originalEdges.empty() && edge != originalEdges.front()) + if(!originals.empty() && edge != originals.front()) { - detail::insert_unique(pieceToOriginals[edge], originalEdges); + detail::insert_unique(pieceToOriginals[edge], originals); } return; } @@ -680,8 +679,12 @@ void Triangulation::conformToEdgeIteration( { const Edge edgePart(iA, iVleft); overlaps > 0 ? fixEdge(edgePart, overlaps) : fixEdge(edgePart); - detail::insert_unique(pieceToOriginals[edgePart], originalEdges); - remaining.push_back(Edge(iVleft, iB)); + detail::insert_unique(pieceToOriginals[edgePart], originals); +#ifdef CDT_CXX11_IS_SUPPORTED + remaining.emplace_back(Edge(iVleft, iB), originals, overlaps); +#else + remaining.push_back(make_tuple(Edge(iVleft, iB), originals, overlaps)); +#endif return; } @@ -706,13 +709,26 @@ void Triangulation::conformToEdgeIteration( const Edge splitEdge(iVleft, iVright); const Edge half1(iVleft, iNewVert); const Edge half2(iNewVert, iVright); - const BoundaryOverlapCount overlaps = overlapCount[splitEdge]; - // remove the edge that will be split + + const unordered_map::const_iterator + splitEdgeOverlapsIt = overlapCount.find(splitEdge); + const BoundaryOverlapCount splitEdgeOverlaps = + splitEdgeOverlapsIt != overlapCount.end() + ? splitEdgeOverlapsIt->second + : 0; + // remove the edge that will be split and add split edge's halves fixedEdges.erase(splitEdge); - overlapCount.erase(splitEdge); - // add split edge's halves - fixEdge(half1, overlaps); - fixEdge(half2, overlaps); + if(splitEdgeOverlaps > 0) + { + overlapCount.erase(splitEdgeOverlapsIt); + fixEdge(half1, splitEdgeOverlaps); + fixEdge(half2, splitEdgeOverlaps); + } + else + { + fixEdge(half1); + fixEdge(half2); + } // maintain piece-to-original mapping EdgeVec newOriginals(1, splitEdge); const unordered_map::const_iterator originalsIt = @@ -735,8 +751,15 @@ void Triangulation::conformToEdgeIteration( std::stack triStack = insertPointOnEdge(iNewVert, iT, iTopo); ensureDelaunayByEdgeFlips(newV, iNewVert, triStack); - remaining.push_back(Edge(iNewVert, iB)); - remaining.push_back(Edge(iA, iNewVert)); +#ifdef CDT_CXX11_IS_SUPPORTED + remaining.emplace_back(Edge(iNewVert, iB), originals, overlaps); + remaining.emplace_back(Edge(iA, iNewVert), originals, overlaps); +#else + remaining.push_back( + make_tuple(Edge(iNewVert, iB), originals, overlaps)); + remaining.push_back( + make_tuple(Edge(iA, iNewVert), originals, overlaps)); +#endif return; } @@ -762,7 +785,12 @@ void Triangulation::conformToEdgeIteration( // encountered one or more points on the edge: add remaining edge part if(iB != edge.v2()) { - remaining.push_back(Edge(iB, edge.v2())); +#ifdef CDT_CXX11_IS_SUPPORTED + remaining.emplace_back(Edge(iB, edge.v2()), originals, overlaps); +#else + remaining.push_back( + make_tuple(Edge(iB, edge.v2()), originals, overlaps)); +#endif } // add mid-point to triangulation @@ -775,8 +803,13 @@ void Triangulation::conformToEdgeIteration( const std::vector flippedFixedEdges = insertVertex_FlipFixedEdges(iMid); - remaining.push_back(Edge(iMid, iB)); - remaining.push_back(Edge(iA, iMid)); +#ifdef CDT_CXX11_IS_SUPPORTED + remaining.emplace_back(Edge(iMid, iB), originals, overlaps); + remaining.emplace_back(Edge(iA, iMid), originals, overlaps); +#else + remaining.push_back(make_tuple(Edge(iMid, iB), originals, overlaps)); + remaining.push_back(make_tuple(Edge(iA, iMid), originals, overlaps)); +#endif // re-introduce fixed edges that were flipped // and make sure overlap count is preserved @@ -784,59 +817,53 @@ void Triangulation::conformToEdgeIteration( it != flippedFixedEdges.end(); ++it) { - fixedEdges.erase(*it); + const Edge& flippedFixedEdge = *it; + fixedEdges.erase(flippedFixedEdge); BoundaryOverlapCount prevOverlaps = 0; const unordered_map::const_iterator - overlapsIt = overlapCount.find(*it); + overlapsIt = overlapCount.find(flippedFixedEdge); if(overlapsIt != overlapCount.end()) { prevOverlaps = overlapsIt->second; overlapCount.erase(overlapsIt); } // override overlapping boundaries count when re-inserting an edge - EdgeVec prevOriginals(1, *it); + EdgeVec prevOriginals(1, flippedFixedEdge); const unordered_map::const_iterator originalsIt = - pieceToOriginals.find(*it); + pieceToOriginals.find(flippedFixedEdge); if(originalsIt != pieceToOriginals.end()) { prevOriginals = originalsIt->second; } - reintroduce.push_back(make_tuple(*it, prevOriginals, prevOverlaps)); +#ifdef CDT_CXX11_IS_SUPPORTED + remaining.emplace_back(flippedFixedEdge, prevOriginals, prevOverlaps); +#else + remaining.push_back( + make_tuple(flippedFixedEdge, prevOriginals, prevOverlaps)); +#endif } } template void Triangulation::conformToEdge( Edge edge, - const EdgeVec& originalEdges, - const BoundaryOverlapCount overlaps, - EdgeVec& remaining, - std::vector& reintroduce) + EdgeVec originals, + BoundaryOverlapCount overlaps, + std::vector& remaining) { // use iteration over recursion to avoid stack overflows - reintroduce.clear(); remaining.clear(); - remaining.push_back(edge); - Edge reEdge(noNeighbor, noNeighbor); - EdgeVec reOriginals; - BoundaryOverlapCount reOverlaps; - while(!remaining.empty() || !reintroduce.empty()) +#ifdef CDT_CXX11_IS_SUPPORTED + remaining.emplace_back(edge, originals, overlaps); +#else + remaining.push_back(make_tuple(edge, originals, overlaps)); +#endif + while(!remaining.empty()) { - if(!reintroduce.empty()) - { - tie(reEdge, reOriginals, reOverlaps) = reintroduce.back(); - reintroduce.pop_back(); - conformToEdgeIteration( - reEdge, reOriginals, reOverlaps, remaining, reintroduce); - } - else - { - edge = remaining.back(); - remaining.pop_back(); - conformToEdgeIteration( - edge, originalEdges, overlaps, remaining, reintroduce); - } + tie(edge, originals, overlaps) = remaining.back(); + remaining.pop_back(); + conformToEdgeIteration(edge, originals, overlaps, remaining); } } diff --git a/CDT/tests/expected/crossing-edges__conforming_randomized_resolve_all.txt b/CDT/tests/expected/crossing-edges__conforming_randomized_resolve_all.txt index 4eb25bff..71ceac80 100644 --- a/CDT/tests/expected/crossing-edges__conforming_randomized_resolve_all.txt +++ b/CDT/tests/expected/crossing-edges__conforming_randomized_resolve_all.txt @@ -17,9 +17,7 @@ 5 7 6 7 -2 -3 7 0 -5 7 0 +0 4 3 7