mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-06-20 11:54:07 +03:00
Modeling - Infinite loop when Simplifying Fuse operation, CPU to 100% #557
Minor refactoring of RelocatePCurvesToNewUorigin(). RelocatePCurvesToNewUorigin() can no longer stuck in infinite loop if it found the edge that is not present in theVEmap. Test bug_gh544 is added to check the fix.
This commit is contained in:
parent
2398b87d36
commit
7ed396b0eb
@ -282,26 +282,40 @@ static Standard_Boolean TryMakeLine(const Handle(Geom2d_Curve)& thePCurve,
|
|||||||
return Standard_True;
|
return Standard_True;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RemoveEdgeFromMap(const TopoDS_Edge& theEdge,
|
// Removes the specified edge from the vertex to edge map.
|
||||||
TopTools_IndexedDataMapOfShapeListOfShape& theVEmap)
|
// @param theEdge The edge to remove.
|
||||||
|
// @param theVertexToEdges The map of vertices to edges.
|
||||||
|
// @return True if the edge was removed, false otherwise.
|
||||||
|
static bool RemoveEdgeFromMap(const TopoDS_Edge& theEdge,
|
||||||
|
TopTools_IndexedDataMapOfShapeListOfShape& theVertexToEdges)
|
||||||
{
|
{
|
||||||
TopoDS_Vertex VV[2];
|
bool anIsRemoved = false;
|
||||||
TopExp::Vertices(theEdge, VV[0], VV[1]);
|
TopoDS_Vertex aFirstVertex;
|
||||||
for (Standard_Integer i = 0; i < 2; i++)
|
TopoDS_Vertex aLastVertex;
|
||||||
|
TopExp::Vertices(theEdge, aFirstVertex, aLastVertex);
|
||||||
|
for (const auto& aVertex : {aFirstVertex, aLastVertex})
|
||||||
{
|
{
|
||||||
if (!theVEmap.Contains(VV[i]))
|
if (!theVertexToEdges.Contains(aVertex))
|
||||||
continue;
|
|
||||||
TopTools_ListOfShape& Elist = theVEmap.ChangeFromKey(VV[i]);
|
|
||||||
TopTools_ListIteratorOfListOfShape itl(Elist);
|
|
||||||
while (itl.More())
|
|
||||||
{
|
{
|
||||||
const TopoDS_Shape& anEdge = itl.Value();
|
continue;
|
||||||
|
}
|
||||||
|
TopTools_ListOfShape& aVertexEdges = theVertexToEdges.ChangeFromKey(aVertex);
|
||||||
|
TopTools_ListIteratorOfListOfShape anEdgesIter(aVertexEdges);
|
||||||
|
while (anEdgesIter.More())
|
||||||
|
{
|
||||||
|
const TopoDS_Shape& anEdge = anEdgesIter.Value();
|
||||||
if (anEdge.IsSame(theEdge))
|
if (anEdge.IsSame(theEdge))
|
||||||
Elist.Remove(itl);
|
{
|
||||||
|
anIsRemoved = true;
|
||||||
|
aVertexEdges.Remove(anEdgesIter);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
itl.Next();
|
{
|
||||||
|
anEdgesIter.Next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return anIsRemoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Standard_Real ComputeMinEdgeSize(const TopTools_SequenceOfShape& theEdges,
|
static Standard_Real ComputeMinEdgeSize(const TopTools_SequenceOfShape& theEdges,
|
||||||
@ -451,6 +465,32 @@ static Standard_Boolean FindCoordBounds(const TopTools_SequenceOfShape&
|
|||||||
return Standard_True;
|
return Standard_True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
// Returns the start and end points of the edge in parametric space of the face.
|
||||||
|
// The orientation of the edge is taken into account, so the start and end points
|
||||||
|
// will be swapped if the edge has a reversed orientation.
|
||||||
|
// @param theEdge The edge to get the points from.
|
||||||
|
// @param theRefFace The reference face to get the parametric points.
|
||||||
|
// @return A pair of points representing the start and end points of the edge in parametric space.
|
||||||
|
static std::pair<gp_Pnt2d, gp_Pnt2d> getCurveParams(const TopoDS_Edge& theEdge,
|
||||||
|
const TopoDS_Face& theRefFace)
|
||||||
|
{
|
||||||
|
BRepAdaptor_Curve2d aCurveAdaptor(theEdge, theRefFace);
|
||||||
|
Standard_Real aFirstParam = aCurveAdaptor.FirstParameter();
|
||||||
|
Standard_Real aLastParam = aCurveAdaptor.LastParameter();
|
||||||
|
if (theEdge.Orientation() != TopAbs_FORWARD)
|
||||||
|
{
|
||||||
|
std::swap(aFirstParam, aLastParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
const gp_Pnt2d aFirstPoint = aCurveAdaptor.Value(aFirstParam);
|
||||||
|
const gp_Pnt2d aLastPoint = aCurveAdaptor.Value(aLastParam);
|
||||||
|
return {aFirstPoint, aLastPoint};
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
static void RelocatePCurvesToNewUorigin(
|
static void RelocatePCurvesToNewUorigin(
|
||||||
const TopTools_SequenceOfShape& theEdges,
|
const TopTools_SequenceOfShape& theEdges,
|
||||||
const TopoDS_Shape& theFirstFace,
|
const TopoDS_Shape& theFirstFace,
|
||||||
@ -462,141 +502,129 @@ static void RelocatePCurvesToNewUorigin(
|
|||||||
NCollection_DataMap<TopoDS_Shape, Handle(Geom2d_Curve)>& theEdgeNewPCurve,
|
NCollection_DataMap<TopoDS_Shape, Handle(Geom2d_Curve)>& theEdgeNewPCurve,
|
||||||
TopTools_MapOfShape& theUsedEdges)
|
TopTools_MapOfShape& theUsedEdges)
|
||||||
{
|
{
|
||||||
TopTools_MapOfShape EdgesOfFirstFace;
|
TopTools_MapOfShape anEdgesOfFirstFace;
|
||||||
TopExp::MapShapes(theFirstFace, EdgesOfFirstFace);
|
TopExp::MapShapes(theFirstFace, anEdgesOfFirstFace);
|
||||||
|
|
||||||
for (;;) // walk by contours
|
for (;;) // walk by contours
|
||||||
{
|
{
|
||||||
// try to find the start edge that:
|
// try to find the start edge that:
|
||||||
// 1. belongs to outer edges of first face;
|
// 1. belongs to outer edges of first face;
|
||||||
// 2. has minimum U-coord of its start point
|
// 2. has minimum U-coord of its start point
|
||||||
TopoDS_Edge StartEdge;
|
TopoDS_Edge aStartEdge;
|
||||||
TopAbs_Orientation anOr = TopAbs_FORWARD;
|
TopAbs_Orientation anOrientation = TopAbs_FORWARD;
|
||||||
Standard_Real aCoordMin = RealLast();
|
Standard_Real aCoordMin = RealLast();
|
||||||
for (Standard_Integer ii = 1; ii <= theEdges.Length(); ii++)
|
for (Standard_Integer anEdgeIndex = 1; anEdgeIndex <= theEdges.Length(); ++anEdgeIndex)
|
||||||
{
|
{
|
||||||
const TopoDS_Edge& anEdge = TopoDS::Edge(theEdges(ii));
|
const TopoDS_Edge& anEdge = TopoDS::Edge(theEdges(anEdgeIndex));
|
||||||
if (theUsedEdges.Contains(anEdge))
|
if (theUsedEdges.Contains(anEdge))
|
||||||
continue;
|
|
||||||
if (EdgesOfFirstFace.Contains(anEdge))
|
|
||||||
{
|
{
|
||||||
if (StartEdge.IsNull())
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anEdgesOfFirstFace.Contains(anEdge))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aStartEdge.IsNull())
|
||||||
|
{
|
||||||
|
aStartEdge = anEdge;
|
||||||
|
const auto&& [aFirstPoint, aLastPoint] = getCurveParams(anEdge, theRefFace);
|
||||||
|
if (aFirstPoint.Coord(theIndCoord) < aLastPoint.Coord(theIndCoord))
|
||||||
{
|
{
|
||||||
StartEdge = anEdge;
|
aCoordMin = aFirstPoint.Coord(theIndCoord);
|
||||||
BRepAdaptor_Curve2d StartBAcurve(StartEdge, theRefFace);
|
anOrientation = TopAbs_FORWARD;
|
||||||
Standard_Real aFirstParam, aLastParam;
|
|
||||||
if (StartEdge.Orientation() == TopAbs_FORWARD)
|
|
||||||
{
|
|
||||||
aFirstParam = StartBAcurve.FirstParameter();
|
|
||||||
aLastParam = StartBAcurve.LastParameter();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aFirstParam = StartBAcurve.LastParameter();
|
|
||||||
aLastParam = StartBAcurve.FirstParameter();
|
|
||||||
}
|
|
||||||
gp_Pnt2d aFirstPoint = StartBAcurve.Value(aFirstParam);
|
|
||||||
gp_Pnt2d aLastPoint = StartBAcurve.Value(aLastParam);
|
|
||||||
if (aFirstPoint.Coord(theIndCoord) < aLastPoint.Coord(theIndCoord))
|
|
||||||
{
|
|
||||||
aCoordMin = aFirstPoint.Coord(theIndCoord);
|
|
||||||
anOr = TopAbs_FORWARD;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aCoordMin = aLastPoint.Coord(theIndCoord);
|
|
||||||
anOr = TopAbs_REVERSED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BRepAdaptor_Curve2d aBAcurve(anEdge, theRefFace);
|
aCoordMin = aLastPoint.Coord(theIndCoord);
|
||||||
Standard_Real aFirstParam, aLastParam;
|
anOrientation = TopAbs_REVERSED;
|
||||||
if (anEdge.Orientation() == TopAbs_FORWARD)
|
|
||||||
{
|
|
||||||
aFirstParam = aBAcurve.FirstParameter();
|
|
||||||
aLastParam = aBAcurve.LastParameter();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aFirstParam = aBAcurve.LastParameter();
|
|
||||||
aLastParam = aBAcurve.FirstParameter();
|
|
||||||
}
|
|
||||||
gp_Pnt2d aFirstPoint = aBAcurve.Value(aFirstParam);
|
|
||||||
gp_Pnt2d aLastPoint = aBAcurve.Value(aLastParam);
|
|
||||||
if (aFirstPoint.Coord(theIndCoord) < aCoordMin)
|
|
||||||
{
|
|
||||||
StartEdge = anEdge;
|
|
||||||
aCoordMin = aFirstPoint.Coord(theIndCoord);
|
|
||||||
anOr = TopAbs_FORWARD;
|
|
||||||
}
|
|
||||||
if (aLastPoint.Coord(theIndCoord) < aCoordMin)
|
|
||||||
{
|
|
||||||
StartEdge = anEdge;
|
|
||||||
aCoordMin = aLastPoint.Coord(theIndCoord);
|
|
||||||
anOr = TopAbs_REVERSED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // if (EdgesOfFirstFace.Contains(anEdge))
|
}
|
||||||
} // for (Standard_Integer ii = 1; ii <= edges.Length(); ii++)
|
else
|
||||||
|
{
|
||||||
if (StartEdge.IsNull()) // all contours are passed
|
const auto&& [aFirstPoint, aLastPoint] = getCurveParams(anEdge, theRefFace);
|
||||||
break;
|
if (aFirstPoint.Coord(theIndCoord) < aCoordMin)
|
||||||
|
{
|
||||||
TopoDS_Vertex StartVertex = (anOr == TopAbs_FORWARD)
|
aStartEdge = anEdge;
|
||||||
? TopExp::FirstVertex(StartEdge, Standard_True)
|
aCoordMin = aFirstPoint.Coord(theIndCoord);
|
||||||
: TopExp::LastVertex(StartEdge, Standard_True);
|
anOrientation = TopAbs_FORWARD;
|
||||||
TopoDS_Edge CurEdge = StartEdge;
|
}
|
||||||
Standard_Real fpar, lpar;
|
if (aLastPoint.Coord(theIndCoord) < aCoordMin)
|
||||||
Handle(Geom2d_Curve) CurPCurve = BRep_Tool::CurveOnSurface(CurEdge, theRefFace, fpar, lpar);
|
{
|
||||||
CurPCurve = new Geom2d_TrimmedCurve(CurPCurve, fpar, lpar);
|
aStartEdge = anEdge;
|
||||||
theEdgeNewPCurve.Bind(CurEdge, CurPCurve);
|
aCoordMin = aLastPoint.Coord(theIndCoord);
|
||||||
if (CurEdge.Orientation() == TopAbs_REVERSED)
|
anOrientation = TopAbs_REVERSED;
|
||||||
{
|
}
|
||||||
Standard_Real tmp = fpar;
|
}
|
||||||
fpar = lpar;
|
|
||||||
lpar = tmp;
|
|
||||||
}
|
}
|
||||||
Standard_Real CurParam = (anOr == TopAbs_FORWARD) ? lpar : fpar;
|
|
||||||
|
if (aStartEdge.IsNull()) // all contours are passed
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TopoDS_Edge aCurrentEdge = aStartEdge;
|
||||||
|
Standard_Real anEdgeStartParam, anEdgeEndParam;
|
||||||
|
Handle(Geom2d_Curve) CurPCurve =
|
||||||
|
BRep_Tool::CurveOnSurface(aCurrentEdge, theRefFace, anEdgeStartParam, anEdgeEndParam);
|
||||||
|
CurPCurve = new Geom2d_TrimmedCurve(CurPCurve, anEdgeStartParam, anEdgeEndParam);
|
||||||
|
theEdgeNewPCurve.Bind(aCurrentEdge, CurPCurve);
|
||||||
|
if (aCurrentEdge.Orientation() == TopAbs_REVERSED)
|
||||||
|
{
|
||||||
|
std::swap(anEdgeStartParam, anEdgeEndParam);
|
||||||
|
}
|
||||||
|
Standard_Real CurParam = (anOrientation == TopAbs_FORWARD) ? anEdgeEndParam : anEdgeStartParam;
|
||||||
gp_Pnt2d CurPoint = CurPCurve->Value(CurParam);
|
gp_Pnt2d CurPoint = CurPCurve->Value(CurParam);
|
||||||
|
|
||||||
for (;;) // collect pcurves of a contour
|
for (;;) // collect pcurves of a contour
|
||||||
{
|
{
|
||||||
RemoveEdgeFromMap(CurEdge, theVEmap);
|
if (!RemoveEdgeFromMap(aCurrentEdge, theVEmap))
|
||||||
theUsedEdges.Add(CurEdge);
|
{
|
||||||
TopoDS_Vertex CurVertex = (anOr == TopAbs_FORWARD)
|
break; // end of contour in 2d
|
||||||
? TopExp::LastVertex(CurEdge, Standard_True)
|
}
|
||||||
: TopExp::FirstVertex(CurEdge, Standard_True);
|
theUsedEdges.Add(aCurrentEdge);
|
||||||
|
TopoDS_Vertex CurVertex = (anOrientation == TopAbs_FORWARD)
|
||||||
|
? TopExp::LastVertex(aCurrentEdge, Standard_True)
|
||||||
|
: TopExp::FirstVertex(aCurrentEdge, Standard_True);
|
||||||
|
|
||||||
const TopTools_ListOfShape& Elist = theVEmap.FindFromKey(CurVertex);
|
const TopTools_ListOfShape& Elist = theVEmap.FindFromKey(CurVertex);
|
||||||
if (Elist.IsEmpty())
|
if (Elist.IsEmpty())
|
||||||
|
{
|
||||||
break; // end of contour in 3d
|
break; // end of contour in 3d
|
||||||
|
}
|
||||||
|
|
||||||
TopTools_ListIteratorOfListOfShape itl(Elist);
|
for (TopTools_ListIteratorOfListOfShape itl(Elist); itl.More(); itl.Next())
|
||||||
for (; itl.More(); itl.Next())
|
|
||||||
{
|
{
|
||||||
const TopoDS_Edge& anEdge = TopoDS::Edge(itl.Value());
|
const TopoDS_Edge& anEdge = TopoDS::Edge(itl.Value());
|
||||||
if (anEdge.IsSame(CurEdge))
|
if (anEdge.IsSame(aCurrentEdge))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
TopoDS_Vertex aFirstVertex = (anOr == TopAbs_FORWARD)
|
}
|
||||||
|
|
||||||
|
TopoDS_Vertex aFirstVertex = (anOrientation == TopAbs_FORWARD)
|
||||||
? TopExp::FirstVertex(anEdge, Standard_True)
|
? TopExp::FirstVertex(anEdge, Standard_True)
|
||||||
: TopExp::LastVertex(anEdge, Standard_True);
|
: TopExp::LastVertex(anEdge, Standard_True);
|
||||||
if (!aFirstVertex.IsSame(CurVertex)) // may be if CurVertex is deg.vertex
|
if (!aFirstVertex.IsSame(CurVertex)) // may be if CurVertex is deg.vertex
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface(anEdge, theRefFace, fpar, lpar);
|
Handle(Geom2d_Curve) aPCurve =
|
||||||
aPCurve = new Geom2d_TrimmedCurve(aPCurve, fpar, lpar);
|
BRep_Tool::CurveOnSurface(anEdge, theRefFace, anEdgeStartParam, anEdgeEndParam);
|
||||||
|
aPCurve = new Geom2d_TrimmedCurve(aPCurve, anEdgeStartParam, anEdgeEndParam);
|
||||||
if (anEdge.Orientation() == TopAbs_REVERSED)
|
if (anEdge.Orientation() == TopAbs_REVERSED)
|
||||||
{
|
{
|
||||||
Standard_Real tmp = fpar;
|
std::swap(anEdgeStartParam, anEdgeEndParam);
|
||||||
fpar = lpar;
|
|
||||||
lpar = tmp;
|
|
||||||
}
|
}
|
||||||
Standard_Real aParam = (anOr == TopAbs_FORWARD) ? fpar : lpar;
|
Standard_Real aParam =
|
||||||
|
(anOrientation == TopAbs_FORWARD) ? anEdgeStartParam : anEdgeEndParam;
|
||||||
gp_Pnt2d aPoint = aPCurve->Value(aParam);
|
gp_Pnt2d aPoint = aPCurve->Value(aParam);
|
||||||
Standard_Real anOffset = CurPoint.Coord(theIndCoord) - aPoint.Coord(theIndCoord);
|
Standard_Real anOffset = CurPoint.Coord(theIndCoord) - aPoint.Coord(theIndCoord);
|
||||||
if (!(Abs(anOffset) < theCoordTol || Abs(Abs(anOffset) - thePeriod) < theCoordTol))
|
if (!(Abs(anOffset) < theCoordTol || Abs(Abs(anOffset) - thePeriod) < theCoordTol))
|
||||||
|
{
|
||||||
continue; // may be if CurVertex is deg.vertex
|
continue; // may be if CurVertex is deg.vertex
|
||||||
|
}
|
||||||
|
|
||||||
if (Abs(anOffset) > thePeriod / 2)
|
if (Abs(anOffset) > thePeriod / 2)
|
||||||
{
|
{
|
||||||
@ -611,8 +639,8 @@ static void RelocatePCurvesToNewUorigin(
|
|||||||
aPCurve = aNewPCurve;
|
aPCurve = aNewPCurve;
|
||||||
}
|
}
|
||||||
theEdgeNewPCurve.Bind(anEdge, aPCurve);
|
theEdgeNewPCurve.Bind(anEdge, aPCurve);
|
||||||
CurEdge = anEdge;
|
aCurrentEdge = anEdge;
|
||||||
TopAbs_Orientation CurOr = TopAbs::Compose(anOr, CurEdge.Orientation());
|
TopAbs_Orientation CurOr = TopAbs::Compose(anOrientation, aCurrentEdge.Orientation());
|
||||||
CurParam = (CurOr == TopAbs_FORWARD) ? aPCurve->LastParameter() : aPCurve->FirstParameter();
|
CurParam = (CurOr == TopAbs_FORWARD) ? aPCurve->LastParameter() : aPCurve->FirstParameter();
|
||||||
CurPoint = aPCurve->Value(CurParam);
|
CurPoint = aPCurve->Value(CurParam);
|
||||||
break;
|
break;
|
||||||
|
29
tests/bugs/modalg_8/bug_gh544
Normal file
29
tests/bugs/modalg_8/bug_gh544
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# This test is to check the fix for issue #544
|
||||||
|
# We have to make sure that boolean operation doesn't stuck in infinite loop.
|
||||||
|
|
||||||
|
# Load the base solid
|
||||||
|
restore [locate_data_file bug_gh544.brep] body
|
||||||
|
# restore solid.brep body
|
||||||
|
|
||||||
|
# get all the wires
|
||||||
|
explode body W
|
||||||
|
|
||||||
|
# make it a face
|
||||||
|
mkplane f body_18
|
||||||
|
|
||||||
|
# prism it, z = 12
|
||||||
|
prism p f 0 0 12
|
||||||
|
|
||||||
|
# settings to fuse
|
||||||
|
bclearobjects
|
||||||
|
bcleartools
|
||||||
|
baddobjects p
|
||||||
|
baddtools body
|
||||||
|
bfillds
|
||||||
|
|
||||||
|
# set simplify to true
|
||||||
|
bsimplify -f 1
|
||||||
|
|
||||||
|
# If this doesn't stuck in infinite loop, behavior is correct.
|
||||||
|
# If it does, it will be killed by the timeout eventually.
|
||||||
|
bapibop res_simple 1
|
Loading…
x
Reference in New Issue
Block a user