1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-09-03 14:10:33 +03:00

Stack overflow when meshing(with tbb) shapes from attached step file #688

Fixed stack overflow by introducing StackOfFrames class that allows for iterative approach instead of recursive.
This commit is contained in:
dkulikov
2025-08-29 17:23:16 +01:00
parent 51abcfc61c
commit d644a7b47f
2 changed files with 88 additions and 27 deletions

View File

@@ -34,6 +34,7 @@
#include <algorithm>
#include <stack>
#include <vector>
const Standard_Real AngDeviation1Deg = M_PI / 180.;
const Standard_Real AngDeviation90Deg = 90 * AngDeviation1Deg;
@@ -79,6 +80,66 @@ void UpdateBndBox(const gp_XY& thePnt1, const gp_XY& thePnt2, Bnd_B2d& theBox)
theBox.Add(thePnt2);
theBox.Enlarge(Precision);
}
// Class representing a stack of frames. Each frame is a range of elements to be processed.
// The stack allows to process elements in depth-first order meaning that when new elements
// are added to the stack, they will be processed before the remaining elements of the
// current frame.
// Frames are processed in LIFO order while elements inside a frame are processed in FIFO order.
class StackOfFrames
{
private:
// A frame is a range of elements to be processed.
class Frame
{
public:
// Construct a frame for the given range of elements.
// Note that the range is [theFrameStart, theFrameEnd).
Frame(const int theFrameStart, const int theFrameEnd)
: CurrentElement(theFrameStart),
FrameEnd(theFrameEnd)
{
}
// Return the index of the current element and advance to the next one.
inline int Advance() { return CurrentElement++; }
// Check if all elements in the frame have been processed.
inline bool IsEmpty() const { return CurrentElement == FrameEnd; }
private:
int CurrentElement; // Index of the current element of the frame.
int FrameEnd; // Index of the last element + 1 of the frame.
};
public:
// Adds a new frame for the given range of elements.
// Note that the range is [theFrameStart, theFrameEnd).
inline void PushFrame(const int theFrameStart, const int theFrameEnd)
{
myFrames.emplace_back(theFrameStart, theFrameEnd);
}
// Returns the index of the current element of the top frame
// and advances to the next element. If all elements of the top
// frame have been processed, the frame is removed from the stack.
// Precondition: the stack is not empty.
inline int PopElement()
{
Frame& aFrame = myFrames.back();
const int anElem = aFrame.Advance();
if (aFrame.IsEmpty())
myFrames.pop_back();
return anElem;
}
// Check if the stack is empty.
inline bool IsEmpty() const { return myFrames.empty(); }
private:
std::vector<Frame, NCollection_Allocator<Frame>> myFrames; // Container of frames.
};
} // anonymous namespace
//=================================================================================================
@@ -1339,17 +1400,28 @@ void BRepMesh_Delaun::cleanupPolygon(const IMeshData::SequenceOfInteger& thePoly
IMeshData::MapOfInteger aSurvivedLinks(anIgnoredEdges);
Standard_Integer aPolyVertIt = 0;
Standard_Integer anUniqueVerticesNum = aPolyVertices.Length() - 1;
for (; aPolyVertIt < anUniqueVerticesNum; ++aPolyVertIt)
for (Standard_Integer aPolyVertIt = 0; aPolyVertIt < aPolyVertices.Length() - 1; ++aPolyVertIt)
{
killTrianglesAroundVertex(aPolyVertices(aPolyVertIt),
aPolyVertices,
aPolyVerticesFindMap,
thePolygon,
thePolyBoxes,
aSurvivedLinks,
aLoopEdges);
StackOfFrames aStackFames;
IMeshData::VectorOfInteger aStackData;
for (int aCurrentVictim = aPolyVertices(aPolyVertIt); aCurrentVictim != -1;
aCurrentVictim = aStackFames.IsEmpty() ? -1 : aStackData(aStackFames.PopElement()))
{
const int aPrevStackDataSize = aStackData.Length();
killTrianglesAroundVertex(aCurrentVictim,
aPolyVertices,
aPolyVerticesFindMap,
thePolygon,
thePolyBoxes,
aSurvivedLinks,
aLoopEdges,
aStackData);
const int aNewStackDataSize = aStackData.Length();
if (aNewStackDataSize > aPrevStackDataSize)
{
aStackFames.PushFrame(aPrevStackDataSize, aNewStackDataSize);
}
}
}
IMeshData::MapOfIntegerInteger::Iterator aLoopEdgesIt(aLoopEdges);
@@ -1376,12 +1448,13 @@ void BRepMesh_Delaun::killTrianglesAroundVertex(
const IMeshData::SequenceOfInteger& thePolygon,
const IMeshData::SequenceOfBndB2d& thePolyBoxes,
IMeshData::MapOfInteger& theSurvivedLinks,
IMeshData::MapOfIntegerInteger& theLoopEdges)
IMeshData::MapOfIntegerInteger& theLoopEdges,
IMeshData::VectorOfInteger& theVictimNodes)
{
IMeshData::ListOfInteger::Iterator aNeighborsIt = myMeshData->LinksConnectedTo(theZombieNodeId);
// Try to infect neighbor nodes
IMeshData::VectorOfInteger aVictimNodes;
// std::list<Standard_Integer> aVictimNodes;
for (; aNeighborsIt.More(); aNeighborsIt.Next())
{
const Standard_Integer& aNeighborLinkId = aNeighborsIt.Value();
@@ -1421,7 +1494,7 @@ void BRepMesh_Delaun::killTrianglesAroundVertex(
if (isVertexInsidePolygon(anOtherNode, thePolyVertices))
{
// Got you!
aVictimNodes.Append(anOtherNode);
theVictimNodes.Append(anOtherNode);
}
else
{
@@ -1444,19 +1517,6 @@ void BRepMesh_Delaun::killTrianglesAroundVertex(
theSurvivedLinks.Add(aNeighborLinkId);
killLinkTriangles(aNeighborLinkId, theLoopEdges);
}
// Go and do your job!
IMeshData::VectorOfInteger::Iterator aVictimIt(aVictimNodes);
for (; aVictimIt.More(); aVictimIt.Next())
{
killTrianglesAroundVertex(aVictimIt.Value(),
thePolyVertices,
thePolyVerticesFindMap,
thePolygon,
thePolyBoxes,
theSurvivedLinks,
theLoopEdges);
}
}
//=======================================================================

View File

@@ -302,7 +302,8 @@ private:
const IMeshData::SequenceOfInteger& thePolygon,
const IMeshData::SequenceOfBndB2d& thePolyBoxes,
IMeshData::MapOfInteger& theSurvivedLinks,
IMeshData::MapOfIntegerInteger& theLoopEdges);
IMeshData::MapOfIntegerInteger& theLoopEdges,
IMeshData::VectorOfInteger& theVictimNodes);
//! Checks is the given link crosses the polygon boundary.
//! If yes, kills its triangles and checks neighbor links on boundary intersection. Does nothing