Skip to content

Commit

Permalink
Fix wrong implementation of iterative conformToEdge converted from re…
Browse files Browse the repository at this point in the history
…cursive

Fix erroneous overlap counts of zero in conforming triangulation

Adjust tests
  • Loading branch information
artem-ogre committed Aug 26, 2022
1 parent 7a9d709 commit 6d51b91
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 67 deletions.
26 changes: 9 additions & 17 deletions CDT/include/Triangulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<ConformToEdgeTask>& reintroduce);
std::vector<ConformToEdgeTask>& 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<ConformToEdgeTask>& reintroduce);
std::vector<ConformToEdgeTask>& remaining);

tuple<TriInd, VertInd, VertInd> intersectedTriangle(
VertInd iA,
Expand Down Expand Up @@ -670,15 +663,14 @@ void Triangulation<T, TNearPointLocator>::conformToEdges(
"new edges is not possible");
}
// state shared between different runs for performance gains
EdgeVec remaining;
std::vector<ConformToEdgeTask> reintroduce;
std::vector<ConformToEdgeTask> 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();
}
Expand Down
121 changes: 74 additions & 47 deletions CDT/include/Triangulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,10 +643,9 @@ void Triangulation<T, TNearPointLocator>::insertEdge(
template <typename T, typename TNearPointLocator>
void Triangulation<T, TNearPointLocator>::conformToEdgeIteration(
Edge edge,
const EdgeVec& originalEdges,
const EdgeVec& originals,
BoundaryOverlapCount overlaps,
EdgeVec& remaining,
std::vector<ConformToEdgeTask>& reintroduce)
std::vector<ConformToEdgeTask>& remaining)
{
const VertInd iA = edge.v1();
VertInd iB = edge.v2();
Expand All @@ -660,9 +659,9 @@ void Triangulation<T, TNearPointLocator>::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;
}
Expand All @@ -680,8 +679,12 @@ void Triangulation<T, TNearPointLocator>::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;
}

Expand All @@ -706,13 +709,26 @@ void Triangulation<T, TNearPointLocator>::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<Edge, BoundaryOverlapCount>::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<Edge, EdgeVec>::const_iterator originalsIt =
Expand All @@ -735,8 +751,15 @@ void Triangulation<T, TNearPointLocator>::conformToEdgeIteration(
std::stack<TriInd> 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;
}

Expand All @@ -762,7 +785,12 @@ void Triangulation<T, TNearPointLocator>::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
Expand All @@ -775,68 +803,67 @@ void Triangulation<T, TNearPointLocator>::conformToEdgeIteration(
const std::vector<Edge> 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
for(std::vector<Edge>::const_iterator it = flippedFixedEdges.begin();
it != flippedFixedEdges.end();
++it)
{
fixedEdges.erase(*it);
const Edge& flippedFixedEdge = *it;
fixedEdges.erase(flippedFixedEdge);

BoundaryOverlapCount prevOverlaps = 0;
const unordered_map<Edge, BoundaryOverlapCount>::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<Edge, EdgeVec>::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 <typename T, typename TNearPointLocator>
void Triangulation<T, TNearPointLocator>::conformToEdge(
Edge edge,
const EdgeVec& originalEdges,
const BoundaryOverlapCount overlaps,
EdgeVec& remaining,
std::vector<ConformToEdgeTask>& reintroduce)
EdgeVec originals,
BoundaryOverlapCount overlaps,
std::vector<ConformToEdgeTask>& 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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
5 7
6 7

2
3 7 0
5 7 0
0

4
3 7
Expand Down

0 comments on commit 6d51b91

Please sign in to comment.