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

Compare commits

...

2 Commits

Author SHA1 Message Date
dkulikov
40c01dedcf Fixed remark 2025-08-29 17:28:59 +01:00
dkulikov
d644a7b47f 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.
2025-08-29 17:23:16 +01:00
2 changed files with 87 additions and 27 deletions

View File

@@ -34,6 +34,7 @@
#include <algorithm> #include <algorithm>
#include <stack> #include <stack>
#include <vector>
const Standard_Real AngDeviation1Deg = M_PI / 180.; const Standard_Real AngDeviation1Deg = M_PI / 180.;
const Standard_Real AngDeviation90Deg = 90 * AngDeviation1Deg; 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.Add(thePnt2);
theBox.Enlarge(Precision); 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 } // anonymous namespace
//================================================================================================= //=================================================================================================
@@ -1339,17 +1400,28 @@ void BRepMesh_Delaun::cleanupPolygon(const IMeshData::SequenceOfInteger& thePoly
IMeshData::MapOfInteger aSurvivedLinks(anIgnoredEdges); IMeshData::MapOfInteger aSurvivedLinks(anIgnoredEdges);
Standard_Integer aPolyVertIt = 0; for (Standard_Integer aPolyVertIt = 0; aPolyVertIt < aPolyVertices.Length() - 1; ++aPolyVertIt)
Standard_Integer anUniqueVerticesNum = aPolyVertices.Length() - 1;
for (; aPolyVertIt < anUniqueVerticesNum; ++aPolyVertIt)
{ {
killTrianglesAroundVertex(aPolyVertices(aPolyVertIt), StackOfFrames aStackFames;
aPolyVertices, IMeshData::VectorOfInteger aStackData;
aPolyVerticesFindMap, for (int aCurrentVictim = aPolyVertices(aPolyVertIt); aCurrentVictim != -1;
thePolygon, aCurrentVictim = aStackFames.IsEmpty() ? -1 : aStackData(aStackFames.PopElement()))
thePolyBoxes, {
aSurvivedLinks, const int aPrevStackDataSize = aStackData.Length();
aLoopEdges); 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); IMeshData::MapOfIntegerInteger::Iterator aLoopEdgesIt(aLoopEdges);
@@ -1376,12 +1448,12 @@ void BRepMesh_Delaun::killTrianglesAroundVertex(
const IMeshData::SequenceOfInteger& thePolygon, const IMeshData::SequenceOfInteger& thePolygon,
const IMeshData::SequenceOfBndB2d& thePolyBoxes, const IMeshData::SequenceOfBndB2d& thePolyBoxes,
IMeshData::MapOfInteger& theSurvivedLinks, IMeshData::MapOfInteger& theSurvivedLinks,
IMeshData::MapOfIntegerInteger& theLoopEdges) IMeshData::MapOfIntegerInteger& theLoopEdges,
IMeshData::VectorOfInteger& theVictimNodes)
{ {
IMeshData::ListOfInteger::Iterator aNeighborsIt = myMeshData->LinksConnectedTo(theZombieNodeId); IMeshData::ListOfInteger::Iterator aNeighborsIt = myMeshData->LinksConnectedTo(theZombieNodeId);
// Try to infect neighbor nodes // Try to infect neighbor nodes
IMeshData::VectorOfInteger aVictimNodes;
for (; aNeighborsIt.More(); aNeighborsIt.Next()) for (; aNeighborsIt.More(); aNeighborsIt.Next())
{ {
const Standard_Integer& aNeighborLinkId = aNeighborsIt.Value(); const Standard_Integer& aNeighborLinkId = aNeighborsIt.Value();
@@ -1421,7 +1493,7 @@ void BRepMesh_Delaun::killTrianglesAroundVertex(
if (isVertexInsidePolygon(anOtherNode, thePolyVertices)) if (isVertexInsidePolygon(anOtherNode, thePolyVertices))
{ {
// Got you! // Got you!
aVictimNodes.Append(anOtherNode); theVictimNodes.Append(anOtherNode);
} }
else else
{ {
@@ -1444,19 +1516,6 @@ void BRepMesh_Delaun::killTrianglesAroundVertex(
theSurvivedLinks.Add(aNeighborLinkId); theSurvivedLinks.Add(aNeighborLinkId);
killLinkTriangles(aNeighborLinkId, theLoopEdges); 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::SequenceOfInteger& thePolygon,
const IMeshData::SequenceOfBndB2d& thePolyBoxes, const IMeshData::SequenceOfBndB2d& thePolyBoxes,
IMeshData::MapOfInteger& theSurvivedLinks, IMeshData::MapOfInteger& theSurvivedLinks,
IMeshData::MapOfIntegerInteger& theLoopEdges); IMeshData::MapOfIntegerInteger& theLoopEdges,
IMeshData::VectorOfInteger& theVictimNodes);
//! Checks is the given link crosses the polygon boundary. //! Checks is the given link crosses the polygon boundary.
//! If yes, kills its triangles and checks neighbor links on boundary intersection. Does nothing //! If yes, kills its triangles and checks neighbor links on boundary intersection. Does nothing