From 24a14c65557fd1103bc6220b61a90f8e4abc9496 Mon Sep 17 00:00:00 2001 From: Dmitrii Kulikov <164657232+AtheneNoctuaPt@users.noreply.github.com> Date: Tue, 7 Oct 2025 20:15:37 +0100 Subject: [PATCH 01/17] Modeling - Segfault on chamfer or fillet approaching ellipse (#738) Fixed nullptr dereference --- src/ChFi3d/ChFi3d_Builder_C1.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ChFi3d/ChFi3d_Builder_C1.cxx b/src/ChFi3d/ChFi3d_Builder_C1.cxx index 73d2af02108..90d1a1ab99a 100644 --- a/src/ChFi3d/ChFi3d_Builder_C1.cxx +++ b/src/ChFi3d/ChFi3d_Builder_C1.cxx @@ -2637,6 +2637,10 @@ void ChFi3d_Builder::PerformIntersectionAtEnd(const Standard_Integer Index) cfacemoins1->D0(paredge2, pfac2); cface->D0(paredge2, pint); } + else if (C2dint1.IsNull() || C2dint2.IsNull()) + { + throw Standard_ConstructionError("Failed to get p-curve of edge"); + } else { C2dint1->D0(paredge2, pfac2); From fcd70cfda56a7236aeb59722e028e1402ab5f064 Mon Sep 17 00:00:00 2001 From: Dmitrii Kulikov <164657232+AtheneNoctuaPt@users.noreply.github.com> Date: Thu, 9 Oct 2025 18:37:51 +0100 Subject: [PATCH 02/17] Modeling - Crash in BRepOffsetAPI_MakePipeShell (#740) Performed a basic refactoring of BRepFill_SectionPlacement::Perform() and fixed a crash. --- src/BRepFill/BRepFill_SectionPlacement.cxx | 346 +++++++-------------- 1 file changed, 117 insertions(+), 229 deletions(-) diff --git a/src/BRepFill/BRepFill_SectionPlacement.cxx b/src/BRepFill/BRepFill_SectionPlacement.cxx index 6fd418faf55..c9d59500698 100644 --- a/src/BRepFill/BRepFill_SectionPlacement.cxx +++ b/src/BRepFill/BRepFill_SectionPlacement.cxx @@ -40,10 +40,6 @@ #include #include -#ifdef OCCT_DEBUG -static Standard_Boolean myDebug = Standard_False; -#endif - static Standard_Real SearchParam(const Handle(BRepFill_LocationLaw)& Law, const Standard_Integer Ind, const TopoDS_Vertex& TheV) @@ -91,282 +87,174 @@ void BRepFill_SectionPlacement::Perform(const Standard_Boolean WithContact, const Standard_Boolean WithCorrection, const TopoDS_Shape& Vertex) { - TopoDS_Vertex TheV; - TheV = TopoDS::Vertex(Vertex); - Standard_Integer ii; - Standard_Integer Ind1 = 0, Ind2 = 0; - Standard_Boolean Bof, isVertex = Standard_False; - Standard_Real First = 0., Last = 0.; - TopExp_Explorer Ex; - TopoDS_Edge E; - TopoDS_Vertex V; - Handle(Geom_Curve) C; - Handle(Geom_TrimmedCurve) TC; + Standard_Real anEdgeStartParam = 0.; + Standard_Real anEdgeEndParam = 0.; + Handle(Geom_Curve) aCurve; - // modified by NIZHNY-OCC629 Thu Jul 24 14:11:45 2003 - Standard_Boolean isFound = Standard_False; - Ex.Init(mySection, TopAbs_EDGE); - for (; Ex.More(); Ex.Next()) + // Here we are simply looking for the first valid curve in the section. + TopExp_Explorer anEdgeExplorer(mySection, TopAbs_EDGE); + for (; anEdgeExplorer.More(); anEdgeExplorer.Next()) { - E = TopoDS::Edge(Ex.Current()); - // avoid null, degenerated edges - if (E.IsNull() || BRep_Tool::Degenerated(E)) + const TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExplorer.Current()); + if (anEdge.IsNull() || BRep_Tool::Degenerated(anEdge)) continue; - C = BRep_Tool::Curve(E, First, Last); - if (C.IsNull()) + + aCurve = BRep_Tool::Curve(anEdge, anEdgeStartParam, anEdgeEndParam); + if (aCurve.IsNull()) continue; - isFound = Standard_True; + break; } - if (!isFound) - isVertex = Standard_True; + + Handle(Geom_Geometry) aSection; + if (aCurve.IsNull()) + { + // No edge found : the section is a vertex + TopExp_Explorer aVertexExplorer(mySection, TopAbs_VERTEX); + const TopoDS_Vertex aFirstVertex = TopoDS::Vertex(aVertexExplorer.Current()); + const gp_Pnt aPoint = BRep_Tool::Pnt(aFirstVertex); + aSection = new Geom_CartesianPoint(aPoint); + } else { - TC = new (Geom_TrimmedCurve)(C, First, Last); - Ex.Next(); + Handle(Geom_TrimmedCurve) aTrimmedCurve = + new Geom_TrimmedCurve(aCurve, anEdgeStartParam, anEdgeEndParam); + anEdgeExplorer.Next(); - if (Ex.More()) + if (anEdgeExplorer.More()) { - Standard_Real tolrac, epsV; - constexpr Standard_Real tol = Precision::Confusion(); - GeomConvert_CompCurveToBSplineCurve Conv(TC); - for (; Ex.More(); Ex.Next()) + constexpr Standard_Real aPrecisionTolerance = Precision::Confusion(); + GeomConvert_CompCurveToBSplineCurve aBSplineConverter(aTrimmedCurve); + for (; anEdgeExplorer.More(); anEdgeExplorer.Next()) { - E = TopoDS::Edge(Ex.Current()); + TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExplorer.Current()); // avoid null, degenerated edges - if (E.IsNull() || BRep_Tool::Degenerated(E)) + if (anEdge.IsNull() || BRep_Tool::Degenerated(anEdge)) continue; - TopoDS_Vertex VFirst, VLast; - TopExp::Vertices(E, VFirst, VLast); - epsV = Max(BRep_Tool::Tolerance(VFirst), BRep_Tool::Tolerance(VLast)); - C = BRep_Tool::Curve(E, First, Last); - if (C.IsNull()) + + aCurve = BRep_Tool::Curve(anEdge, anEdgeStartParam, anEdgeEndParam); + if (aCurve.IsNull()) continue; - TC = new (Geom_TrimmedCurve)(C, First, Last); - tolrac = Min(tol, epsV); - Bof = Conv.Add(TC, tolrac); - if (!Bof) + + TopoDS_Vertex aFirstVertex; + TopoDS_Vertex aLastVertex; + TopExp::Vertices(anEdge, aFirstVertex, aLastVertex); + const Standard_Real aVertexTolerance = + Max(BRep_Tool::Tolerance(aFirstVertex), BRep_Tool::Tolerance(aLastVertex)); + + aTrimmedCurve = new Geom_TrimmedCurve(aCurve, anEdgeStartParam, anEdgeEndParam); + if (!aBSplineConverter.Add(aTrimmedCurve, Min(aPrecisionTolerance, aVertexTolerance))) { - tolrac = Max(tol, epsV); - Bof = Conv.Add(TC, tolrac); + aBSplineConverter.Add(aTrimmedCurve, Max(aPrecisionTolerance, aVertexTolerance)); } } - C = Conv.BSplineCurve(); + aCurve = aBSplineConverter.BSplineCurve(); } else - C = TC; // On garde l'unique courbe - } - - // modified by NIZHNY-629 Fri Jul 25 11:10:27 2003 b - - // // punctual section - // Ex.Init(mySection, TopAbs_EDGE); - // Standard_Boolean isPonctual = Standard_False; - // if (Ex.More()) { - // E = TopoDS::Edge(Ex.Current()); - // isPonctual = BRep_Tool::Degenerated(E); - // } - - // Ex.Init(mySection, TopAbs_EDGE); - // if (Ex.More()&&!isPonctual) { - // E = TopoDS::Edge(Ex.Current()); - // C = BRep_Tool::Curve(E, First, Last); - // TC = new (Geom_TrimmedCurve)(C, First, Last); - // Ex.Next(); - // if (Ex.More()) { // On essai d'avoir un echantillon representatif - // Standard_Real tolrac, epsV, tol = Precision::Confusion(); - // GeomConvert_CompCurveToBSplineCurve Conv(TC); - // for (; Ex.More(); Ex.Next()) { - // E = TopoDS::Edge(Ex.Current()); - // TopoDS_Vertex VFirst, VLast; - // TopExp::Vertices(E,VFirst, VLast); - // epsV = Max(BRep_Tool::Tolerance(VFirst), BRep_Tool::Tolerance(VLast)); - // C = BRep_Tool::Curve(E, First, Last); - // TC = new (Geom_TrimmedCurve)(C, First, Last); - // tolrac = Min(tol,epsV); - // Bof = Conv.Add(TC, tolrac); - // if (!Bof) { - // tolrac = Max(tol,epsV); - // Bof = Conv.Add(TC, tolrac); - // } - // } - // C = Conv.BSplineCurve(); - // } - // else C = TC; // On garde l'unique courbe - // } - // else { - // // Localisation par distance Shape/Shape - // Standard_Real Tpos; - // BRepExtrema_DistShapeShape Ext(mySection, myLaw->Wire()); - - // if (! Ext.IsDone()) - // throw Standard_ConstructionError("Distance Vertex/Spine"); - - // if (Ext.SupportTypeShape2(1) == BRepExtrema_IsOnEdge) { - // TopoDS_Shape sbis = Ext.SupportOnShape2(1); - // E = TopoDS::Edge(sbis); - // Ext.ParOnEdgeS2(1, Tpos); - // } - // else { - // TopoDS_Vertex Vf, Vl,V; - // TopoDS_Shape sbis = Ext.SupportOnShape2(1); - // V = TopoDS::Vertex(sbis); - // for (ii=1, Ind1=0 ; ii<=myLaw->NbLaw(); ii++) { - // E = myLaw->Edge(ii); - // TopExp::Vertices(E, Vf, Vl); - // if ((V.IsSame(Vf)) || (V.IsSame(Vl))) { - // if (Ind1 == 0) Ind1 = ii; - // else Ind2 = ii; - // } - // } - - // // On invente une section - // gp_Dir D(0, 0, 1); - // gp_Pnt Origine, PV; - // Origine = BRep_Tool::Pnt(V); - // Standard_Real length; - - // if (Ext.SupportTypeShape1(1) == BRepExtrema_IsVertex) { - // TopoDS_Shape aLocalShape = Ext.SupportOnShape1(1); - // PV = BRep_Tool::Pnt(TopoDS::Vertex(aLocalShape)); - // // PV = BRep_Tool::Pnt(TopoDS::Vertex(Ext.SupportOnShape1(1))); - // } - // else { - // PV = BRep_Tool::Pnt(TopoDS::Vertex(mySection)); - // } - // length = Origine.Distance(PV); - // if (length > Precision::Confusion()) { - // gp_Vec theVec(Origine, PV); - // D.SetXYZ(theVec.XYZ()); - // } - // else length = 10*Precision::Confusion(); - // Handle(Geom_Line) CL = new (Geom_Line) (Origine, D); - // TC = new (Geom_TrimmedCurve)(CL, 0., length); - // C = TC; - // isVertex = Standard_True; - // } - // } - - // // Recherche du Vertex de positionnement - // if (!TheV.IsNull()) { - // Standard_Integer NbV = myLaw->NbLaw()+1; - // for (ii=1, Ind1=0; ii<=NbV && (!Ind1); ii++) - // if (TheV.IsSame(myLaw->Vertex(ii))) Ind1 = ii; - - // if (Ind1 != 0) { - // Ind2 =0; - // isVertex = Standard_True; - // if (Ind1==1) { - // if (myLaw->IsClosed()) Ind2 = NbV-1; - // } - // else { - // Ind1--; - // if (Ind1 < NbV-1) - // Ind2 = Ind1+1; - // } - // } - // else { - // TheV.Nullify(); // On oublie cette option... - // } - // } - - // modified by NIZHNY-629 Fri Jul 25 11:11:06 2003 e + { + aCurve = aTrimmedCurve; + } - // Construction - Handle(Geom_Geometry) theSection = C; - if (isVertex) - { - Ex.Init(mySection, TopAbs_VERTEX); - TopoDS_Vertex theVertex = TopoDS::Vertex(Ex.Current()); - gp_Pnt thePoint = BRep_Tool::Pnt(theVertex); - theSection = new Geom_CartesianPoint(thePoint); + aSection = aCurve; } - GeomFill_SectionPlacement Place(myLaw->Law(1), theSection); + GeomFill_SectionPlacement aSectionPlacement(myLaw->Law(1), aSection); + Handle(BRepAdaptor_CompCurve) aWireAdaptor = new BRepAdaptor_CompCurve(myLaw->Wire()); + aSectionPlacement.Perform(aWireAdaptor, Precision::Confusion()); + const Standard_Real aSectionParam = aSectionPlacement.ParameterOnPath(); + constexpr Standard_Real aParamConfusion = Precision::PConfusion(); + + Standard_Integer aLawIndex1 = 0; + Standard_Integer aLawIndex2 = 0; // In the general case : Localisation via concatenation of the spine - TColStd_Array1OfReal SuperKnot(1, myLaw->NbLaw() + 1); - for (ii = 1; ii <= myLaw->NbLaw(); ii++) + Standard_Boolean anIsIntervalFound = Standard_False; + for (int aLawIndex = 1; aLawIndex <= myLaw->NbLaw() && !anIsIntervalFound; ++aLawIndex) { - SuperKnot(ii + 1) = ii; - } - SuperKnot(1) = 0; - - Handle(BRepAdaptor_CompCurve) adpPath = new (BRepAdaptor_CompCurve)(myLaw->Wire()); + const Standard_Real aCurrKnotParam = aLawIndex - 1; + const Standard_Real aNextKnotParam = aLawIndex; - Place.Perform(adpPath, Precision::Confusion()); - - Standard_Real theParam = Place.ParameterOnPath(); - constexpr Standard_Real eps = Precision::PConfusion(); + // Check if the section parameter is in the interval [aCurrKnotParam, aNextKnotParam] + anIsIntervalFound = (aCurrKnotParam - aParamConfusion <= aSectionParam) + && (aNextKnotParam + aParamConfusion >= aSectionParam); + if (!anIsIntervalFound) + { + continue; + } -#ifdef OCCT_DEBUG - if (myDebug) - { - gp_Pnt P_Path; - P_Path = adpPath->Value(theParam); - std::cout << "Point on Path" << P_Path.X() << ", " << P_Path.Y() << ", " << P_Path.Z() << ", " - << std::endl; + aLawIndex1 = aLawIndex; + if ((Abs(aSectionParam - aCurrKnotParam) < aParamConfusion) && (aLawIndex > 1)) + { + aLawIndex2 = aLawIndex - 1; + } + else if ((Abs(aSectionParam - aNextKnotParam) < aParamConfusion) + && (aLawIndex < myLaw->NbLaw())) + { + aLawIndex2 = aLawIndex + 1; + } } -#endif - for (ii = 1, Bof = Standard_True; ii <= myLaw->NbLaw() && Bof; ii++) + if (!anIsIntervalFound) { - Bof = !((SuperKnot(ii) - eps <= theParam) && (SuperKnot(ii + 1) + eps >= theParam)); - if (!Bof) - { - Ind1 = ii; - if ((Abs(theParam - SuperKnot(ii)) < eps) && (ii > 1)) - Ind2 = ii - 1; - else if ((Abs(theParam - SuperKnot(ii + 1)) < eps) && (ii < myLaw->NbLaw())) - Ind2 = ii + 1; - } + throw Standard_ConstructionError("Interval is not found"); } - if (Bof) - throw Standard_ConstructionError("Interval non trouve !!"); // Search of the by vertex - if (!TheV.IsNull()) - for (Ind1 = 1; Ind1 <= myLaw->NbLaw(); Ind1++) + bool anIsVertexOnLaw = false; + TopoDS_Vertex aVertex = TopoDS::Vertex(Vertex); + if (!aVertex.IsNull()) + { + for (int aCurrentLawIndex = 1; aCurrentLawIndex <= myLaw->NbLaw(); ++aCurrentLawIndex) { - TopoDS_Edge anEdge = myLaw->Edge(Ind1); + TopoDS_Edge anEdge = myLaw->Edge(aCurrentLawIndex); TopoDS_Vertex V1, V2; TopExp::Vertices(anEdge, V1, V2); - if (V1.IsSame(TheV) || V2.IsSame(TheV)) + if (V1.IsSame(aVertex) || V2.IsSame(aVertex)) + { + anIsVertexOnLaw = true; + aLawIndex1 = aCurrentLawIndex; + aLawIndex2 = 0; break; + } } + } //////////////////// // Positioning on the localized edge (or 2 Edges) - Standard_Real Angle; - Place.SetLocation(myLaw->Law(Ind1)); - if (TheV.IsNull()) - Place.Perform(Precision::Confusion()); + + aSectionPlacement.SetLocation(myLaw->Law(aLawIndex1)); + if (!anIsVertexOnLaw) + { + aSectionPlacement.Perform(Precision::Confusion()); + } else { - Place.Perform(SearchParam(myLaw, Ind1, TheV), Precision::Confusion()); + aSectionPlacement.Perform(SearchParam(myLaw, aLawIndex1, aVertex), Precision::Confusion()); } - myTrsf = Place.Transformation(WithContact, WithCorrection); - myIndex = Ind1; - myParam = Place.ParameterOnPath(); - Angle = Place.Angle(); + myTrsf = aSectionPlacement.Transformation(WithContact, WithCorrection); + myIndex = aLawIndex1; + myParam = aSectionPlacement.ParameterOnPath(); + Standard_Real Angle = aSectionPlacement.Angle(); - if (Ind2) + if (aLawIndex2) { - Place.SetLocation(myLaw->Law(Ind2)); - if (TheV.IsNull()) - Place.Perform(Precision::Confusion()); + aSectionPlacement.SetLocation(myLaw->Law(aLawIndex2)); + if (!anIsVertexOnLaw) + { + aSectionPlacement.Perform(Precision::Confusion()); + } else { - if (Ind1 == Ind2) - TheV.Reverse(); - Place.Perform(SearchParam(myLaw, Ind2, TheV), Precision::Confusion()); + if (aLawIndex1 == aLawIndex2) + aVertex.Reverse(); + aSectionPlacement.Perform(SearchParam(myLaw, aLawIndex2, aVertex), Precision::Confusion()); } - if (Place.Angle() > Angle) + if (aSectionPlacement.Angle() > Angle) { - myTrsf = Place.Transformation(WithContact, WithCorrection); - myIndex = Ind2; - myParam = Place.ParameterOnPath(); + myTrsf = aSectionPlacement.Transformation(WithContact, WithCorrection); + myIndex = aLawIndex2; + myParam = aSectionPlacement.ParameterOnPath(); } } } From 7c248e5e9041b274dcc8a2918421b303b2d7161c Mon Sep 17 00:00:00 2001 From: Dmitrii Kulikov <164657232+AtheneNoctuaPt@users.noreply.github.com> Date: Thu, 16 Oct 2025 08:54:40 +0100 Subject: [PATCH 03/17] Modelling - Crash in BRepFilletAPI_MakeChamfer (#743) - Refactored helper functions with clearer naming and improved parameter handling - Added null safety checks to prevent crashes when edge lookup fails in face topology - Removed debug code and simplified variable declarations for better maintainability --- src/ChFi3d/ChFi3d_Builder_2.cxx | 494 ++++++++++++-------------------- 1 file changed, 176 insertions(+), 318 deletions(-) diff --git a/src/ChFi3d/ChFi3d_Builder_2.cxx b/src/ChFi3d/ChFi3d_Builder_2.cxx index 5e7ad10bab1..d80d6bb2023 100644 --- a/src/ChFi3d/ChFi3d_Builder_2.cxx +++ b/src/ChFi3d/ChFi3d_Builder_2.cxx @@ -71,16 +71,18 @@ #include #include -#ifdef OCCT_DEBUG - #ifdef DRAW - #include - #endif - #include -extern Standard_Real t_perfsetofkpart, t_perfsetofkgen, t_makextremities, t_performsurf, t_startsol; -extern Standard_Boolean ChFi3d_GettraceCHRON(); -extern void ChFi3d_InitChron(OSD_Chronometer& ch); -extern void ChFi3d_ResultChron(OSD_Chronometer& ch, Standard_Real& time); -#endif +namespace +{ + +// Simple wrapper over BRep_Tool::CurveOnSurface to get the 2d curve of an edge on a face +// without caring about the first and last parameters of the curve. +static inline Handle(Geom2d_Curve) getCurveOnSurface(const TopoDS_Edge& theEdge, + const TopoDS_Face& theFace) +{ + double aFirstParam = 0.; + double aLastParam = 0.; + return BRep_Tool::CurveOnSurface(theEdge, theFace, aFirstParam, aLastParam); +} //=================================================================== // Definition by a plane @@ -173,22 +175,24 @@ static void ChFi3d_CoupeParPlan(const ChFiDS_CommonPoint& compoint1, //================================================================================================= -static Standard_Boolean SortieTangente(const ChFiDS_CommonPoint& CP, - const TopoDS_Face& /*F*/, - const Handle(ChFiDS_SurfData)& /*SD*/, - const Standard_Integer /*OnS*/, - const Standard_Real TolAngular) +static Standard_Boolean isTangentToArc(const ChFiDS_CommonPoint& aCommonPoint, + const Standard_Real anAngularTolerance) { - if (!CP.HasVector()) + if (!aCommonPoint.HasVector()) + { return Standard_False; - gp_Pnt P; - gp_Vec Darc, Dsurf; - Handle(Geom_Curve) C; - Standard_Real Uf, Ul; - C = BRep_Tool::Curve(CP.Arc(), Uf, Ul); - C->D1(CP.ParameterOnArc(), P, Darc); - Dsurf = CP.Vector(); - return Dsurf.IsParallel(Darc, TolAngular); + } + + Standard_Real aDummyParam1, aDummyParam2; // Not used. + const Handle(Geom_Curve) anArcCurve = + BRep_Tool::Curve(aCommonPoint.Arc(), aDummyParam1, aDummyParam2); + + gp_Pnt aDummyPoint; // Not used. + gp_Vec anArcTangent; // Tangent to the arc at the common point. + anArcCurve->D1(aCommonPoint.ParameterOnArc(), aDummyPoint, anArcTangent); + + const gp_Vec aCommonPointVector = aCommonPoint.Vector(); + return aCommonPointVector.IsParallel(anArcTangent, anAngularTolerance); } //================================================================================================= @@ -204,7 +208,7 @@ static Standard_Boolean BonVoisin(const gp_Pnt& Point, const Standard_Real tol3d) { Standard_Boolean bonvoisin = 1; - Standard_Real winter, Uf, Ul; + Standard_Real winter; gp_Pnt papp = HS->Value(XDep, YDep); Standard_Real dist = RealLast(); Handle(BRepAdaptor_Curve) hc = new BRepAdaptor_Curve(); @@ -255,13 +259,13 @@ static Standard_Boolean BonVoisin(const gp_Pnt& Point, if (newe.IsSame(Ex2.Current())) { newe = TopoDS::Edge(Ex2.Current()); - PC = BRep_Tool::CurveOnSurface(newe, fff, Uf, Ul); + PC = getCurveOnSurface(newe, fff); break; } } } else - PC = BRep_Tool::CurveOnSurface(newe, ff, Uf, Ul); + PC = getCurveOnSurface(newe, ff); PC->Value(winter).Coord(XDep, YDep); if (issame) { @@ -279,7 +283,7 @@ static Standard_Boolean BonVoisin(const gp_Pnt& Point, { newe.Orientation(TopAbs_REVERSED); } - PC = BRep_Tool::CurveOnSurface(newe, fff, Uf, Ul); + PC = getCurveOnSurface(newe, fff); PC->Value(winter).Coord(XDep, YDep); } break; @@ -372,7 +376,7 @@ static void TgtKP(const Handle(ChFiDS_SurfData)& CD, // purpose : Checks if a vector belongs to a Face //======================================================================= -Standard_Boolean IsInput(const gp_Vec& Vec, const TopoDS_Vertex& Ve, const TopoDS_Face& Fa) +static Standard_Boolean IsInput(const gp_Vec& Vec, const TopoDS_Vertex& Ve, const TopoDS_Face& Fa) { TopExp_Explorer FaceExp(Fa, TopAbs_WIRE); BRepTools_WireExplorer WireExp; @@ -447,10 +451,10 @@ Standard_Boolean IsInput(const gp_Vec& Vec, const TopoDS_Vertex& Ve, const TopoD // purpose : Find a neighbor G1 by an edge //======================================================================= -Standard_Boolean IsG1(const ChFiDS_Map& TheMap, - const TopoDS_Edge& E, - const TopoDS_Face& FRef, - TopoDS_Face& FVoi) +static Standard_Boolean IsG1(const ChFiDS_Map& TheMap, + const TopoDS_Edge& E, + const TopoDS_Face& FRef, + TopoDS_Face& FVoi) { TopTools_ListIteratorOfListOfShape It; // Find a neighbor of E different from FRef (general case). @@ -573,14 +577,12 @@ static void ChangeTransition(const ChFiDS_CommonPoint& Precedan const Handle(TopOpeBRepDS_HDataStructure)& DS) { Standard_Boolean tochange = Standard_True; - Standard_Real f, l; - const TopoDS_Face& F = TopoDS::Face(DS->Shape(FaceIndex)); - const TopoDS_Edge& Arc = Precedant.Arc(); + const TopoDS_Face& F = TopoDS::Face(DS->Shape(FaceIndex)); + const TopoDS_Edge& Arc = Precedant.Arc(); Handle(Geom2d_Curve) PCurve1, PCurve2; - PCurve1 = BRep_Tool::CurveOnSurface(Arc, F, f, l); + PCurve1 = getCurveOnSurface(Arc, F); TopoDS_Shape aLocalShape = Arc.Reversed(); - PCurve2 = BRep_Tool::CurveOnSurface(TopoDS::Edge(aLocalShape), F, f, l); - // PCurve2 = BRep_Tool::CurveOnSurface(TopoDS::Edge(Arc.Reversed()), F, f, l); + PCurve2 = getCurveOnSurface(TopoDS::Edge(aLocalShape), F); if (PCurve1 != PCurve2) { // This is a cutting edge, it is necessary to make a small Geometric test @@ -597,6 +599,7 @@ static void ChangeTransition(const ChFiDS_CommonPoint& Precedan Precedant.ParameterOnArc(), TopAbs::Reverse(Precedant.TransitionOnArc())); } +} // namespace //======================================================================= // function : CallPerformSurf @@ -635,9 +638,6 @@ void ChFi3d_Builder::CallPerformSurf(Handle(ChFiDS_Stripe)& Stripe, Handle(BRepAdaptor_Surface)& Surf1, Handle(BRepAdaptor_Surface)& Surf2) { -#ifdef OCCT_DEBUG - OSD_Chronometer ch1; -#endif Handle(BRepAdaptor_Surface) HSon1, HSon2; HSon1 = HS1; HSon2 = HS2; @@ -684,11 +684,6 @@ void ChFi3d_Builder::CallPerformSurf(Handle(ChFiDS_Stripe)& Stripe, } else { - -#ifdef OCCT_DEBUG - ChFi3d_InitChron(ch1); // initial perform for PerformSurf -#endif - isdone = PerformSurf(SeqSD, HGuide, Spine, @@ -710,9 +705,6 @@ void ChFi3d_Builder::CallPerformSurf(Handle(ChFiDS_Stripe)& Stripe, Soldep, intf, intl); -#ifdef OCCT_DEBUG - ChFi3d_ResultChron(ch1, t_performsurf); // result perf for PerformSurf -#endif } // Case of error @@ -771,11 +763,6 @@ void ChFi3d_Builder::CallPerformSurf(Handle(ChFiDS_Stripe)& Stripe, } else { - -#ifdef OCCT_DEBUG - ChFi3d_InitChron(ch1); // init perf for PerformSurf -#endif - isdone = PerformSurf(SeqSD, HGuide, Spine, @@ -797,9 +784,6 @@ void ChFi3d_Builder::CallPerformSurf(Handle(ChFiDS_Stripe)& Stripe, Soldep, intf, intl); -#ifdef OCCT_DEBUG - ChFi3d_ResultChron(ch1, t_performsurf); // result perf for PerformSurf -#endif } } } @@ -942,13 +926,13 @@ void ChFi3d_Builder::StartSol(const Handle(ChFiDS_Stripe)& Stripe, ChFi3d::NextSide(Or1, Or2, Stripe->OrientationOnFace1(), Stripe->OrientationOnFace2(), RC); } - Standard_Real woned, Uf, Ul, ResU, ResV; + Standard_Real woned, ResU, ResV; Spine->Parameter(iedge, w, woned, Standard_True); cured.Orientation(TopAbs_FORWARD); TopoDS_Face f1forward = f1, f2forward = f2; f1forward.Orientation(TopAbs_FORWARD); f2forward.Orientation(TopAbs_FORWARD); - PC = BRep_Tool::CurveOnSurface(cured, f1forward, Uf, Ul); + PC = getCurveOnSurface(cured, f1forward); I1->Initialize((const Handle(Adaptor3d_Surface)&)HS1); PC->D1(woned, P1, derive); // There are points on the border, and internal points are found @@ -976,7 +960,7 @@ void ChFi3d_Builder::StartSol(const Handle(ChFiDS_Stripe)& Stripe, } if (f1.IsSame(f2)) cured.Orientation(TopAbs_REVERSED); - PC = BRep_Tool::CurveOnSurface(cured, f2forward, Uf, Ul); + PC = getCurveOnSurface(cured, f2forward); P2 = PC->Value(woned); const Handle(Adaptor3d_Surface)& HSon2 = HS2; // to avoid ambiguity I2->Initialize(HSon2); @@ -1013,14 +997,14 @@ void ChFi3d_Builder::StartSol(const Handle(ChFiDS_Stripe)& Stripe, Or2 = f2.Orientation(); Choix = ChFi3d::NextSide(Or1, Or2, Stripe->OrientationOnFace1(), Stripe->OrientationOnFace2(), RC); - Standard_Real woned, Uf, Ul; + Standard_Real woned; Spine->Parameter(iedge, w, woned, Standard_True); TopoDS_Face f1forward = f1, f2forward = f2; f1forward.Orientation(TopAbs_FORWARD); f2forward.Orientation(TopAbs_FORWARD); - PC = BRep_Tool::CurveOnSurface(cured, f1forward, Uf, Ul); + PC = getCurveOnSurface(cured, f1forward); P1 = PC->Value(woned); - PC = BRep_Tool::CurveOnSurface(cured, f2forward, Uf, Ul); + PC = getCurveOnSurface(cured, f2forward); P2 = PC->Value(woned); const Handle(Adaptor3d_Surface)& HSon1 = HS1; // to avoid ambiguity const Handle(Adaptor3d_Surface)& HSon2 = HS2; // to avoid ambiguity @@ -1159,72 +1143,66 @@ Standard_Boolean ChFi3d_Builder::StartSol( const Standard_Boolean decroch, const TopoDS_Vertex& Vref) const { - RecRst = RecS = RecP = c1obstacle = 0; - TopOpeBRepDS_DataStructure& DStr = myDS->ChangeDS(); - TopoDS_Face Fv, Fref; - // gp_Pnt2d pp1,pp2; - Handle(Geom2d_Curve) pc; - Standard_Real Uf, Ul; - - TopoDS_Face F = TopoDS::Face(DStr.Shape(SD->Index(ons))); - if (!HSref.IsNull()) - Fref = HSref->Face(); - const ChFiDS_CommonPoint& CP = SD->Vertex(isfirst, ons); + RecP = false; + RecS = false; + RecRst = false; + c1obstacle = false; + TopoDS_Face Fv; + Handle(Geom2d_Curve) aPCurve; + + const TopOpeBRepDS_DataStructure& DStr = myDS->ChangeDS(); + TopoDS_Face Fref = !HSref.IsNull() ? HSref->Face() : TopoDS_Face(); + TopoDS_Face F = TopoDS::Face(DStr.Shape(SD->Index(ons))); + + const ChFiDS_CommonPoint& aCommonPoint = SD->Vertex(isfirst, ons); HSBis.Nullify(); - if (CP.IsOnArc()) + if (aCommonPoint.IsOnArc()) { - Standard_Integer notons; - if (ons == 1) - notons = 2; - else - notons = 1; - const ChFiDS_CommonPoint& CPbis = SD->Vertex(isfirst, notons); + const Standard_Integer notons = ons == 1 ? 2 : 1; + const ChFiDS_CommonPoint& CPbis = SD->Vertex(isfirst, notons); if (CPbis.IsOnArc()) { // It is checked if it is not the extension zone - // In case CP is not at the end of surfdata and it is not necessary to take it into account - // except for separate cases (ie pointus) ... - // ts and tns were earlier CP.Parameter() and CPbis.Parameter, but sometimes they had no - // values. - Standard_Real ts = SD->Interference(ons).Parameter(isfirst), - tns = SD->Interference(notons).Parameter(isfirst); - Standard_Boolean isExtend; + // In case aCommonPoint is not at the end of surfdata and it is not necessary to take it into + // account except for separate cases (ie pointus) ... ts and tns were earlier + // aCommonPoint.Parameter() and CPbis.Parameter, but sometimes they had no values. + const Standard_Real ts = SD->Interference(ons).Parameter(isfirst); + const Standard_Real tns = SD->Interference(notons).Parameter(isfirst); // Arbitrary test (to precise) - if (isfirst) - isExtend = (ts - tns > 100 * tolesp); - else - isExtend = (tns - ts > 100 * tolesp); - if (isExtend && !CP.Point().IsEqual(CPbis.Point(), 0)) + const Standard_Boolean isExtend = + isfirst ? (ts - tns > 100 * tolesp) : (tns - ts > 100 * tolesp); + if (isExtend && !aCommonPoint.Point().IsEqual(CPbis.Point(), 0)) { // the state is preserved and False is returned (extension by the expected plane). HS->Initialize(F); - pc = SD->Interference(ons).PCurveOnFace(); + aPCurve = SD->Interference(ons).PCurveOnFace(); // The 2nd point is given by its trace on the support surface - RecS = Standard_False; - pons = pc->Value(tns); - return Standard_False; + RecS = false; + pons = aPCurve->Value(tns); + return false; } } } - if (CP.IsVertex() && !HC.IsNull() && !decroch) + if (aCommonPoint.IsVertex() && !HC.IsNull() && !decroch) { // The edge is changed, the parameter is updated and // eventually the support face and(or) the reference face. - TopoDS_Vertex VCP = CP.Vertex(); - TopoDS_Edge EHC = HC->Edge(); + const TopoDS_Vertex VCP = aCommonPoint.Vertex(); + const TopoDS_Edge EHC = HC->Edge(); // One starts by searching in Fref another edge referencing VCP. - TopExp_Explorer ex1, ex2; - TopoDS_Edge newedge, edgereg; - TopoDS_Face bidface = Fref, facereg; + TopoDS_Edge newedge; + TopoDS_Edge edgereg; + TopoDS_Face facereg; + TopoDS_Face bidface = Fref; bidface.Orientation(TopAbs_FORWARD); - for (ex1.Init(bidface, TopAbs_EDGE); ex1.More(); ex1.Next()) + for (TopExp_Explorer ex1(bidface, TopAbs_EDGE); ex1.More(); ex1.Next()) { const TopoDS_Edge& cured = TopoDS::Edge(ex1.Current()); - Standard_Boolean found = 0; + Standard_Boolean found = false; if (!cured.IsSame(EHC)) { - for (ex2.Init(cured, TopAbs_VERTEX); ex2.More() && !found; ex2.Next()) + for (TopExp_Explorer ex2(cured, TopAbs_VERTEX); ex2.More() && !found; ex2.Next()) { if (ex2.Current().IsSame(VCP)) { @@ -1234,7 +1212,9 @@ Standard_Boolean ChFi3d_Builder::StartSol( facereg = Fv; } else - found = 1; + { + found = true; + } } } } @@ -1252,19 +1232,14 @@ Standard_Boolean ChFi3d_Builder::StartSol( if (V1.IsSame(V2)) { newedge = EHC; - Standard_Real w1 = BRep_Tool::Parameter(V1, EHC); - Standard_Real w2 = BRep_Tool::Parameter(V2, EHC); + const Standard_Real w1 = BRep_Tool::Parameter(V1, EHC); + const Standard_Real w2 = BRep_Tool::Parameter(V2, EHC); const ChFiDS_FaceInterference& fi = SD->Interference(ons); const Handle(Geom2d_Curve)& pcf = fi.PCurveOnFace(); - Standard_Real ww = fi.Parameter(isfirst); - - gp_Pnt2d pww; - if (!pcf.IsNull()) - pww = pcf->Value(ww); - else - pww = SD->Get2dPoints(isfirst, ons); - gp_Pnt2d p1 = HC->Value(w1); - gp_Pnt2d p2 = HC->Value(w2); + const Standard_Real ww = fi.Parameter(isfirst); + const gp_Pnt2d pww = pcf.IsNull() ? SD->Get2dPoints(isfirst, ons) : pcf->Value(ww); + const gp_Pnt2d p1 = HC->Value(w1); + const gp_Pnt2d p2 = HC->Value(w2); if (p1.Distance(pww) > p2.Distance(pww)) { @@ -1276,20 +1251,21 @@ Standard_Boolean ChFi3d_Builder::StartSol( W = w2; pons = p2; } - RecP = c1obstacle = 1; - return 1; + RecP = true; + c1obstacle = true; + return true; } else if (!edgereg.IsNull()) { // the reference edge and face are changed. Fref = facereg; HSref->Initialize(Fref); - for (ex1.Init(facereg, TopAbs_EDGE); ex1.More() && newedge.IsNull(); ex1.Next()) + for (TopExp_Explorer ex1(facereg, TopAbs_EDGE); ex1.More() && newedge.IsNull(); ex1.Next()) { const TopoDS_Edge& cured = TopoDS::Edge(ex1.Current()); if (!cured.IsSame(edgereg)) { - for (ex2.Init(cured, TopAbs_VERTEX); ex2.More(); ex2.Next()) + for (TopExp_Explorer ex2(cured, TopAbs_VERTEX); ex2.More(); ex2.Next()) { if (ex2.Current().IsSame(VCP)) { @@ -1324,8 +1300,7 @@ Standard_Boolean ChFi3d_Builder::StartSol( HCref->Initialize(newedge, Fref); TopoDS_Face newface = Fv; newface.Orientation(TopAbs_FORWARD); - TopExp_Explorer ex; - for (ex.Init(newface, TopAbs_EDGE); ex.More(); ex.Next()) + for (TopExp_Explorer ex(newface, TopAbs_EDGE); ex.More(); ex.Next()) { if (ex.Current().IsSame(newedge)) { @@ -1336,99 +1311,106 @@ Standard_Boolean ChFi3d_Builder::StartSol( HC->Initialize(newedge, Fv); pons = HC->Value(W); } - RecP = c1obstacle = 1; - return 1; + RecP = true; + c1obstacle = true; + return true; } // End of Case Vertex && Obstacle - - else if (CP.IsOnArc() && !HC.IsNull() && !decroch) + else if (aCommonPoint.IsOnArc() && !HC.IsNull() && !decroch) { // Nothing is changed, the parameter is only updated. - W = CP.ParameterOnArc(); - c1obstacle = 1; - return 1; + W = aCommonPoint.ParameterOnArc(); + c1obstacle = true; + return true; } HC.Nullify(); - if (CP.IsOnArc()) + if (aCommonPoint.IsOnArc()) { - const TopoDS_Edge& E = CP.Arc(); + const TopoDS_Edge& anArcEdge = aCommonPoint.Arc(); + + // Lambda to avoid code duplication. + // Sets HS, W, aPCurve and pons to default return values. + auto prepareDefaultReturn = [&]() { + HS->Initialize(F); + W = aCommonPoint.ParameterOnArc(); + aPCurve = getCurveOnSurface(anArcEdge, F); + pons = aPCurve->Value(W); + }; + if (decroch) { HS->Initialize(Fref); - W = CP.ParameterOnArc(); - pc = BRep_Tool::CurveOnSurface(E, Fref, Uf, Ul); - pons = pc->Value(W); - RecS = 1; - return 1; + W = aCommonPoint.ParameterOnArc(); + aPCurve = getCurveOnSurface(anArcEdge, Fref); + pons = aPCurve->Value(W); + RecS = true; + return true; } - if (SearchFace(Spine, CP, F, Fv)) + + if (SearchFace(Spine, aCommonPoint, F, Fv)) { HS->Initialize(Fv); - RecS = 1; - if (CP.IsVertex()) + RecS = true; + if (aCommonPoint.IsVertex()) { // One goes directly by the Vertex - Standard_Integer Nb; - TopoDS_Face aux; // And it is checked that there are no other candidates - Nb = SearchFaceOnV(CP, F, myVEMap, myEFMap, Fv, aux); + TopoDS_Face aux; + const Standard_Integer Nb = SearchFaceOnV(aCommonPoint, F, myVEMap, myEFMap, Fv, aux); - pons = BRep_Tool::Parameters(CP.Vertex(), Fv); + pons = BRep_Tool::Parameters(aCommonPoint.Vertex(), Fv); HS->Initialize(Fv); if (Nb >= 2) { - HSBis = new (BRepAdaptor_Surface)(aux); - PBis = BRep_Tool::Parameters(CP.Vertex(), aux); + HSBis = new BRepAdaptor_Surface(aux); + PBis = BRep_Tool::Parameters(aCommonPoint.Vertex(), aux); } - return 1; + return true; } // otherwise one passes by the arc... if (!Fv.IsSame(F)) { Fv.Orientation(TopAbs_FORWARD); - TopoDS_Edge newedge; - TopExp_Explorer ex; - for (ex.Init(Fv, TopAbs_EDGE); ex.More(); ex.Next()) + TopoDS_Edge newedge; + for (TopExp_Explorer ex(Fv, TopAbs_EDGE); ex.More(); ex.Next()) { - if (ex.Current().IsSame(E)) + if (ex.Current().IsSame(anArcEdge)) { newedge = TopoDS::Edge(ex.Current()); break; } } - // gp_Vec Varc, VSurf; // In cas of Tangent output, the current face becomes the support face - if (SortieTangente(CP, F, SD, ons, 0.1)) + if (isTangentToArc(aCommonPoint, 0.1)) { - pc = BRep_Tool::CurveOnSurface(CP.Arc(), F, Uf, Ul); - HSBis = new (BRepAdaptor_Surface)(F); - PBis = pc->Value(CP.ParameterOnArc()); + aPCurve = getCurveOnSurface(aCommonPoint.Arc(), F); + HSBis = new BRepAdaptor_Surface(F); + PBis = aPCurve->Value(aCommonPoint.ParameterOnArc()); } - pc = BRep_Tool::CurveOnSurface(newedge, Fv, Uf, Ul); + aPCurve = getCurveOnSurface(newedge, Fv); } else { - TopoDS_Edge newedge = E; + TopoDS_Edge newedge = anArcEdge; newedge.Reverse(); Fv.Orientation(TopAbs_FORWARD); - pc = BRep_Tool::CurveOnSurface(newedge, Fv, Uf, Ul); + aPCurve = getCurveOnSurface(newedge, Fv); } - pons = pc->Value(CP.ParameterOnArc()); - return 1; + pons = aPCurve->Value(aCommonPoint.ParameterOnArc()); + return true; } else if (!Fv.IsNull()) { - c1obstacle = 1; + c1obstacle = true; if (!Vref.IsNull()) { - TopExp_Explorer ex; - for (ex.Init(E, TopAbs_VERTEX); ex.More(); ex.Next()) + for (TopExp_Explorer ex(anArcEdge, TopAbs_VERTEX); ex.More(); ex.Next()) { if (ex.Current().IsSame(Vref)) { - c1obstacle = 0; + c1obstacle = false; break; } } @@ -1437,45 +1419,48 @@ Standard_Boolean ChFi3d_Builder::StartSol( { HS->Initialize(Fv); HSref->Initialize(F); - W = CP.ParameterOnArc(); + W = aCommonPoint.ParameterOnArc(); HC = new BRepAdaptor_Curve2d(); TopoDS_Edge newedge; TopoDS_Face newface = Fv; newface.Orientation(TopAbs_FORWARD); - TopExp_Explorer ex; - for (ex.Init(newface, TopAbs_EDGE); ex.More(); ex.Next()) + for (TopExp_Explorer ex(newface, TopAbs_EDGE); ex.More(); ex.Next()) { - if (ex.Current().IsSame(E)) + if (ex.Current().IsSame(anArcEdge)) { newedge = TopoDS::Edge(ex.Current()); break; } } - HC->Initialize(newedge, Fv); - pons = HC->Value(W); - HCref->Initialize(E, F); - if (CP.IsVertex()) - RecP = 1; + + if (!newedge.IsNull()) + { + HC->Initialize(newedge, Fv); + pons = HC->Value(W); + HCref->Initialize(anArcEdge, F); + if (aCommonPoint.IsVertex()) + RecP = true; + else + RecRst = true; + return true; + } else - RecRst = 1; - return 1; + { + prepareDefaultReturn(); + return false; + } } else { - HS->Initialize(F); - W = CP.ParameterOnArc(); - pc = BRep_Tool::CurveOnSurface(E, F, Uf, Ul); - pons = pc->Value(W); - return Standard_False; + prepareDefaultReturn(); + return false; } } else - { // there is no neighbor face, the state is preserved and False is returned. - HS->Initialize(F); - W = CP.ParameterOnArc(); - pc = BRep_Tool::CurveOnSurface(E, F, Uf, Ul); - pons = pc->Value(W); - return Standard_False; + { + // there is no neighbor face, the state is preserved and False is returned. + prepareDefaultReturn(); + return false; } } else @@ -1487,7 +1472,7 @@ Standard_Boolean ChFi3d_Builder::StartSol( else pons = FI.PCurveOnFace()->Value(FI.Parameter(isfirst)); } - return Standard_True; + return true; } //================================================================================================= @@ -1505,9 +1490,6 @@ Standard_Boolean ChFi3d_Builder::SearchFace(const Handle(ChFiDS_Spine)& Spine, if (Pc.IsVertex()) { // attention it is necessary to analyze all faces that turn around of the vertex -#ifdef OCCT_DEBUG - std::cout << "Commonpoint on vertex, the process hangs up" << std::endl; -#endif if (Pc.HasVector()) { // General processing TopoDS_Face Fbis; @@ -1560,9 +1542,6 @@ Standard_Boolean ChFi3d_Builder::SearchFace(const Handle(ChFiDS_Spine)& Spine, if (Spine.IsNull()) { // La Spine peut etre nulle (ThreeCorner) -#ifdef OCCT_DEBUG - std::cout << "FindFace sur vertex avec spine nulle! QUEZAKO ?" << std::endl; -#endif return Standard_False; } @@ -2012,9 +1991,6 @@ static void ChFi3d_Purge(Handle(ChFiDS_Stripe)& Stripe, Standard_Integer opp = 3 - ons; if (!SD->Vertex(isfirst, opp).IsOnArc() || SD->TwistOnS1() || SD->TwistOnS2()) { -#ifdef OCCT_DEBUG - std::cout << "ChFi3d_Purge : No output on extension." << std::endl; -#endif ChFiDS_SequenceOfSurfData& Seq = Stripe->ChangeSetOfSurfData()->ChangeSequence(); if (isfirst) Seq.Remove(1); @@ -2132,15 +2108,6 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& Handle(BRepTopAdaptor_TopolTool)& It2, const Standard_Boolean Simul) { -#ifdef OCCT_DEBUG - OSD_Chronometer ch1; -#endif - - // Temporary - // gp_Pnt ptgui; - // gp_Vec d1gui; - //( HGuide->Curve() ).D1(HGuide->FirstParameter(),ptgui,d1gui); - ChFiDS_ElSpine& Guide = *HGuide; Handle(ChFiDS_ElSpine) OffsetHGuide; @@ -2218,16 +2185,8 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& // sinon solution approchee. Inside = Standard_True; -#ifdef OCCT_DEBUG - ChFi3d_InitChron(ch1); // init perf for StartSol -#endif - StartSol(Stripe, HGuide, HS1, HS2, It1, It2, pp1, pp2, First); -#ifdef OCCT_DEBUG - ChFi3d_ResultChron(ch1, t_startsol); // result perf for StartSol -#endif - Last = wf; if (Guide.IsPeriodic()) { @@ -2263,10 +2222,6 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& Last = Guide.FirstParameter(); } -#ifdef OCCT_DEBUG - ChFi3d_InitChron(ch1); // init perf for startsol -#endif - Ok1 = StartSol(Spine, HS1, pp1, @@ -2306,10 +2261,6 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& HC1.Nullify(); HC2.Nullify(); -#ifdef OCCT_DEBUG - ChFi3d_ResultChron(ch1, t_startsol); // result perf for startsol -#endif - if (Ok1 == 1 && Ok2 == 1) { if (forward) @@ -2395,11 +2346,6 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& Vref = Spine->LastVertex(); if (!ref.IsNull()) { - -#ifdef OCCT_DEBUG - ChFi3d_InitChron(ch1); // init perf for StartSol -#endif - Ok1 = StartSol(Spine, HS1, pp1, @@ -2436,10 +2382,6 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& pp4, decroch2, Vref); - -#ifdef OCCT_DEBUG - ChFi3d_ResultChron(ch1, t_startsol); // result perf for StartSol -#endif } // No more connected faces. Construction of the tangent plane to continue the path @@ -2537,9 +2479,6 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& } else { -#ifdef OCCT_DEBUG - ChFi3d_InitChron(ch1); // init perf for PerformSurf -#endif PerformSurf(SeqSD, HGuide, Spine, @@ -2571,9 +2510,6 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& RecP2, RecRst2, SoldepCC); -#ifdef OCCT_DEBUG - ChFi3d_ResultChron(ch1, t_performsurf); // result perf for PerformSurf -#endif } SD->ChangeIndexOfS1(DStr.AddShape(HS1->Face())); SD->ChangeIndexOfS2(DStr.AddShape(HS2->Face())); @@ -2623,9 +2559,6 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& } else { -#ifdef OCCT_DEBUG - ChFi3d_InitChron(ch1); // init perf for PerformSurf -#endif PerformSurf(SeqSD, HGuide, Spine, @@ -2651,9 +2584,6 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& RecS2, RecRst1, SoldepCS); -#ifdef OCCT_DEBUG - ChFi3d_ResultChron(ch1, t_performsurf); // result perf for PerformSurf -#endif } SD->ChangeIndexOfS1(DStr.AddShape(HS1->Face())); SD->ChangeIndexOfS2(DStr.AddShape(HS2->Face())); @@ -2700,9 +2630,6 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& } else { -#ifdef OCCT_DEBUG - ChFi3d_InitChron(ch1); // init perf for PerformSurf -#endif PerformSurf(SeqSD, HGuide, Spine, @@ -2728,9 +2655,6 @@ void ChFi3d_Builder::PerformSetOfSurfOnElSpine(const Handle(ChFiDS_ElSpine)& RecS1, RecRst2, SoldepCS); -#ifdef OCCT_DEBUG - ChFi3d_ResultChron(ch1, t_performsurf); // result perf for PerformSurf -#endif } SD->ChangeIndexOfS1(DStr.AddShape(HS1->Face())); SD->ChangeIndexOfS2(DStr.AddShape(HS2->Face())); @@ -2976,15 +2900,9 @@ void ChFi3d_Builder::PerformSetOfKPart(Handle(ChFiDS_Stripe)& Stripe, const Stan if (!ChFiKPart_ComputeData::Compute(DStr, SD, HS1, HS2, Or1, Or2, Spine, iedge)) { -#ifdef OCCT_DEBUG - std::cout << "failed calculation KPart" << std::endl; -#endif } else if (!SplitKPart(SD, LSD, Spine, iedge, HS1, It1, HS2, It2, intf, intl)) { -#ifdef OCCT_DEBUG - std::cout << "failed calculation KPart" << std::endl; -#endif LSD.Clear(); } else @@ -3161,17 +3079,7 @@ void ChFi3d_Builder::PerformSetOfKPart(Handle(ChFiDS_Stripe)& Stripe, const Stan ChFiDS_ListIteratorOfListOfHElSpine ILES(ll); for (; ILES.More(); ILES.Next()) { -#ifdef OCCT_DEBUG - if (ChFi3d_GettraceCHRON()) - elspine.Start(); -#endif ChFi3d_PerformElSpine(ILES.ChangeValue(), Spine, myConti, tolesp); -#ifdef OCCT_DEBUG - if (ChFi3d_GettraceCHRON()) - { - elspine.Stop(); - } -#endif } if (Spine->Mode() == ChFiDS_ConstThroatWithPenetrationChamfer) { @@ -3207,17 +3115,7 @@ void ChFi3d_Builder::PerformSetOfKGen(Handle(ChFiDS_Stripe)& Stripe, const Stand ChFiDS_ListIteratorOfListOfHElSpine ILES(ll); for (; ILES.More(); ILES.Next()) { -#ifdef OCCT_DEBUG - if (ChFi3d_GettraceCHRON()) - { - chemine.Start(); - } -#endif PerformSetOfSurfOnElSpine(ILES.Value(), Stripe, It1, It2, Simul); -#ifdef OCCT_DEBUG - if (ChFi3d_GettraceCHRON()) - chemine.Stop(); -#endif } if (!Simul) { @@ -3492,13 +3390,6 @@ void ChFi3d_Builder::PerformSetOfKGen(Handle(ChFiDS_Stripe)& Stripe, const Stand ChFi3d_ReparamPcurv(0., 1., PC1); ChFi3d_ReparamPcurv(0., 1., PC2); Handle(Geom_Surface) newsurf = fil.Surface(); -#ifdef OCCT_DEBUG - #ifdef DRAW - // POP for NT - char* pops = "newsurf"; - DrawTrSurf::Set(pops, newsurf); - #endif -#endif if (pointuon1) { newsurf->VReverse(); // we return to direction 1 from 2; @@ -3654,9 +3545,6 @@ void ChFi3d_Builder::PerformSetOfKGen(Handle(ChFiDS_Stripe)& Stripe, const Stand else if (IF < IL) { TColStd_Array1OfReal wv(IF, IL - 1); -#ifdef OCCT_DEBUG - std::cout << "length of the trajectory : " << (WL - WF) << std::endl; -#endif for (i = IF; i < IL; i++) { Standard_Integer iloc = i; @@ -3665,24 +3553,13 @@ void ChFi3d_Builder::PerformSetOfKGen(Handle(ChFiDS_Stripe)& Stripe, const Stand Standard_Real wi = Spine->LastParameter(iloc); if (periodic) wi = ElCLib::InPeriod(wi, WF, WF + period); - gp_Pnt pv = Spine->Value(wi); -#ifdef OCCT_DEBUG - gp_Pnt pelsapp = curhels->Value(wi); - Standard_Real distinit = pv.Distance(pelsapp); - std::cout << "distance psp/papp : " << distinit << std::endl; -#endif + gp_Pnt pv = Spine->Value(wi); Extrema_LocateExtPC ext(pv, *curhels, wi, 1.e-8); wv(i) = wi; if (ext.IsDone()) { wv(i) = ext.Point().Parameter(); } - else - { -#ifdef OCCT_DEBUG - std::cout << "fail of projection vertex ElSpine!!!" << std::endl; -#endif - } } for (i = 1; i <= len; i++) { @@ -3730,33 +3607,14 @@ void ChFi3d_Builder::PerformSetOfSurf(Handle(ChFiDS_Stripe)& Stripe, const Stand { TopOpeBRepDS_DataStructure& DStr = myDS->ChangeDS(); -#ifdef OCCT_DEBUG - OSD_Chronometer ch; - ChFi3d_InitChron(ch); // init perf for PerformSetOfKPart -#endif - const Handle(ChFiDS_Spine)& sp = Stripe->Spine(); Standard_Integer SI = ChFi3d_SolidIndex(sp, DStr, myESoMap, myEShMap); Stripe->SetSolidIndex(SI); if (!sp->SplitDone()) PerformSetOfKPart(Stripe, Simul); -#ifdef OCCT_DEBUG - ChFi3d_ResultChron(ch, t_perfsetofkpart); // result perf PerformSetOfKPart( - ChFi3d_InitChron(ch); // init perf for PerformSetOfKGen -#endif - PerformSetOfKGen(Stripe, Simul); -#ifdef OCCT_DEBUG - ChFi3d_ResultChron(ch, t_perfsetofkgen); // result perf PerformSetOfKGen - ChFi3d_InitChron(ch); // init perf for ChFi3d_MakeExtremities -#endif - if (!Simul) ChFi3d_MakeExtremities(Stripe, DStr, myEFMap, tolapp3d, tol2d); - -#ifdef OCCT_DEBUG - ChFi3d_ResultChron(ch, t_makextremities); // result perf t_makextremities -#endif } From a624ea564afba5a8f67599b228cb0f955e6840aa Mon Sep 17 00:00:00 2001 From: Pasukhin Dmitry Date: Fri, 24 Oct 2025 09:11:48 +0100 Subject: [PATCH 04/17] Application Framework - Early-return null NamedShape when TNaming_UsedShapes is missing (#760) Check Acces.Root().FindAttribute(...) result in TNaming_Tool::NamedShape and return an empty Handle if the TNaming_UsedShapes attribute is not found to avoid using an uninitialized map. --- src/TNaming/TNaming_NamedShape.cxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/TNaming/TNaming_NamedShape.cxx b/src/TNaming/TNaming_NamedShape.cxx index cb9b35283db..684fe907c81 100644 --- a/src/TNaming/TNaming_NamedShape.cxx +++ b/src/TNaming/TNaming_NamedShape.cxx @@ -1429,9 +1429,12 @@ TDF_Label TNaming_Tool::Label(const Handle(TNaming_UsedShapes)& Shapes, Handle(TNaming_NamedShape) TNaming_Tool::NamedShape(const TopoDS_Shape& S, const TDF_Label& Acces) { - Handle(TNaming_UsedShapes) US; - Acces.Root().FindAttribute(TNaming_UsedShapes::GetID(), US); Handle(TNaming_NamedShape) NS; + Handle(TNaming_UsedShapes) US; + if (!Acces.Root().FindAttribute(TNaming_UsedShapes::GetID(), US)) + { + return NS; + } if (!TNaming_Tool::HasLabel(US, S)) { From 92d725117f36e5468cf3b4320aa8fbccf232e145 Mon Sep 17 00:00:00 2001 From: Kirill Gavrilov Date: Mon, 24 Nov 2025 23:02:34 +0000 Subject: [PATCH 05/17] Visualization - Improve detection of full cylinder/cone parameters #830 Parametric space of TopoDS_Face and ElSLib::ConeVIso() are now used for calculating parameters. Scale factor is pre-applied. --- src/StdSelect/StdSelect_BRepSelectionTool.cxx | 246 +++++++++--------- 1 file changed, 122 insertions(+), 124 deletions(-) diff --git a/src/StdSelect/StdSelect_BRepSelectionTool.cxx b/src/StdSelect/StdSelect_BRepSelectionTool.cxx index 0e449205510..1a1b05fe07f 100644 --- a/src/StdSelect/StdSelect_BRepSelectionTool.cxx +++ b/src/StdSelect/StdSelect_BRepSelectionTool.cxx @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -58,51 +59,40 @@ #include #include #include +#include #include +#include #include #include -#include - #define BVH_PRIMITIVE_LIMIT 800000 namespace { -//======================================================================= -// function : getCylinderCircles -// purpose : Extracts up to two circular edges from a hollow cylinder face -//======================================================================= -std::array getCylinderCircles(const TopoDS_Face& theHollowCylinder, - Standard_Size& theNumCircles) +// Check if face represents a full cylinder or cone surface +// (single wire with 4 edges: 2 seam edges and 2 circular edges) +static Standard_Boolean isCylinderOrCone(const TopoDS_Face& theFace) { - std::array aCircles; // Array to store up to two circles - theNumCircles = 0; // Initialize the number of circles found - Standard_Integer aLinesNb = 0; // Counter for the number of edges processed + if (theFace.NbChildren() != 1) + return false; + + const TopoDS_Iterator aWireIt(theFace); + const TopoDS_Shape& aWire = aWireIt.Value(); + if (aWire.ShapeType() != TopAbs_WIRE || aWire.NbChildren() != 4) + return false; - for (TopExp_Explorer anEdgeExp(theHollowCylinder, TopAbs_EDGE); anEdgeExp.More(); - anEdgeExp.Next()) + int aNbSeams = 0, aNbCirles = 0; + for (TopoDS_Iterator anEdgeIt(aWire); anEdgeIt.More(); anEdgeIt.Next()) { - const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeExp.Current()); - BRepAdaptor_Curve anAdaptor(anEdge); - aLinesNb++; + const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeIt.Value()); + if (BRep_Tool::IsClosed(anEdge, theFace)) + ++aNbSeams; - if (anAdaptor.GetType() == GeomAbs_Circle && BRep_Tool::IsClosed(anEdge)) - { - theNumCircles++; - aCircles[theNumCircles - 1] = anAdaptor.Circle(); - } - else if (anAdaptor.GetType() != GeomAbs_Line || aLinesNb > 4) - { - theNumCircles = 0; - return std::array(); - } - if (theNumCircles == 2) - { - break; - } + BRepAdaptor_Curve anAdaptor(anEdge); + if (anAdaptor.GetType() == GeomAbs_Circle) + ++aNbCirles; } - - return aCircles; + return aNbSeams == 2 && aNbCirles == 2; } } // namespace @@ -653,119 +643,127 @@ Standard_Boolean StdSelect_BRepSelectionTool::GetSensitiveForFace( const Standard_Real theMaxParam, const Standard_Boolean theInteriorFlag) { - TopLoc_Location aLoc; - if (Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(theFace, aLoc)) + TopLoc_Location aLocSurf; + const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(theFace, aLocSurf); + if (Handle(Geom_SphericalSurface) aGeomSphere = Handle(Geom_SphericalSurface)::DownCast(aSurf)) { - TopLoc_Location aLocSurf; - const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(theFace, aLocSurf); - if (Handle(Geom_SphericalSurface) aGeomSphere = Handle(Geom_SphericalSurface)::DownCast(aSurf)) + bool isFullSphere = theFace.NbChildren() == 0; + if (theFace.NbChildren() == 1) { - bool isFullSphere = theFace.NbChildren() == 0; - if (theFace.NbChildren() == 1) + const TopoDS_Iterator aWireIter(theFace); + const TopoDS_Wire& aWire = TopoDS::Wire(aWireIter.Value()); + if (aWire.NbChildren() == 4) { - const TopoDS_Iterator aWireIter(theFace); - const TopoDS_Wire& aWire = TopoDS::Wire(aWireIter.Value()); - if (aWire.NbChildren() == 4) + Standard_Integer aNbSeamEdges = 0, aNbDegenEdges = 0; + for (TopoDS_Iterator anEdgeIter(aWire); anEdgeIter.More(); anEdgeIter.Next()) { - Standard_Integer aNbSeamEdges = 0, aNbDegenEdges = 0; - for (TopoDS_Iterator anEdgeIter(aWire); anEdgeIter.More(); anEdgeIter.Next()) - { - const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeIter.Value()); - aNbSeamEdges += BRep_Tool::IsClosed(anEdge, theFace); - aNbDegenEdges += BRep_Tool::Degenerated(anEdge); - } - isFullSphere = aNbSeamEdges == 2 && aNbDegenEdges == 2; + const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeIter.Value()); + aNbSeamEdges += BRep_Tool::IsClosed(anEdge, theFace); + aNbDegenEdges += BRep_Tool::Degenerated(anEdge); } - } - if (isFullSphere) - { - gp_Sphere aSphere = BRepAdaptor_Surface(theFace).Sphere(); - Handle(Select3D_SensitiveSphere) aSensSphere = - new Select3D_SensitiveSphere(theOwner, - aSphere.Position().Axis().Location(), - aSphere.Radius()); - theSensitiveList.Append(aSensSphere); - return Standard_True; + isFullSphere = aNbSeamEdges == 2 && aNbDegenEdges == 2; } } - else if (Handle(Geom_ConicalSurface) aGeomCone = Handle(Geom_ConicalSurface)::DownCast(aSurf)) + if (isFullSphere) { - Standard_Size aNumCircles; - const std::array aCircles = getCylinderCircles(theFace, aNumCircles); - - if (aNumCircles > 0 && aNumCircles < 3) - { - const gp_Cone aCone = BRepAdaptor_Surface(theFace).Cone(); - - gp_Trsf aTrsf; - Standard_Real aRad1, aRad2, aHeight; - if (aNumCircles == 1) - { - aRad1 = 0.0; - aRad2 = aCircles[0].Radius(); - aHeight = aRad2 * Tan(aCone.SemiAngle()); - aTrsf.SetTransformation(aCone.Position(), gp::XOY()); - } - else - { - aRad1 = aCircles[0].Radius(); - aRad2 = aCircles[1].Radius(); - aHeight = aCircles[0].Location().Distance(aCircles[1].Location()); - - const gp_Pnt aPos = aCircles[0].Location(); - const gp_Dir aDirection(aCircles[1].Location().XYZ() - aPos.XYZ()); - - aTrsf.SetTransformation(gp_Ax3(aPos, aDirection), gp::XOY()); - } + gp_Sphere aSphere = BRepAdaptor_Surface(theFace).Sphere(); + Handle(Select3D_SensitiveSphere) aSensSphere = + new Select3D_SensitiveSphere(theOwner, + aSphere.Position().Axis().Location(), + aSphere.Radius()); + theSensitiveList.Append(aSensSphere); + return Standard_True; + } + } + else if (Handle(Geom_ConicalSurface) aGeomCone = Handle(Geom_ConicalSurface)::DownCast(aSurf)) + { + if (isCylinderOrCone(theFace)) + { + double aURange[2] = {}, aVRange[2] = {}; + BRepTools::UVBounds(theFace, aURange[0], aURange[1], aVRange[0], aVRange[1]); + + const gp_Circ aCirc1 = ElSLib::ConeVIso(aGeomCone->Position(), + aGeomCone->RefRadius(), + aGeomCone->SemiAngle(), + aVRange[0]); + const gp_Circ aCirc2 = ElSLib::ConeVIso(aGeomCone->Position(), + aGeomCone->RefRadius(), + aGeomCone->SemiAngle(), + aVRange[1]); + const double aHeight = aCirc1.Location().Distance(aCirc2.Location()); + + gp_Ax3 aPos = aGeomCone->Position(); + aPos.SetLocation(aCirc1.Location()); + gp_Trsf aLocTrsf; + aLocTrsf.SetTransformation(aPos, gp::XOY()); + + gp_Trsf aTrsf = aLocSurf * aLocTrsf; + const double aScale = aTrsf.ScaleFactor(); + aTrsf.SetScaleFactor(1.0); - Handle(Select3D_SensitiveCylinder) aSensSCyl = - new Select3D_SensitiveCylinder(theOwner, aRad1, aRad2, aHeight, aTrsf, true); - theSensitiveList.Append(aSensSCyl); - return Standard_True; - } + Handle(Select3D_SensitiveCylinder) aSensSCyl = + new Select3D_SensitiveCylinder(theOwner, + aCirc1.Radius() * aScale, + aCirc2.Radius() * aScale, + aHeight * aScale, + aTrsf, + true); + theSensitiveList.Append(aSensSCyl); + return Standard_True; } - else if (Handle(Geom_CylindricalSurface) aGeomCyl = - Handle(Geom_CylindricalSurface)::DownCast(aSurf)) + } + else if (Handle(Geom_CylindricalSurface) aGeomCyl = + Handle(Geom_CylindricalSurface)::DownCast(aSurf)) + { + if (isCylinderOrCone(theFace)) { - Standard_Size aNumCircles; - const std::array aCircles = getCylinderCircles(theFace, aNumCircles); + double aURange[2] = {}, aVRange[2] = {}; + BRepTools::UVBounds(theFace, aURange[0], aURange[1], aVRange[0], aVRange[1]); - if (aNumCircles == 2) - { - const gp_Cylinder aCyl = BRepAdaptor_Surface(theFace).Cylinder(); + const double aRad = aGeomCyl->Radius(); + const double aHeight = aVRange[1] - aVRange[0]; - const Standard_Real aRad = aCyl.Radius(); - const gp_Pnt aPos = aCircles[0].Location(); - const gp_Dir aDirection(aCircles[1].Location().XYZ() - aPos.XYZ()); - const Standard_Real aHeight = aPos.Distance(aCircles[1].Location()); + gp_Ax3 aPos = aGeomCyl->Position(); + aPos.SetLocation(aGeomCyl->Location().XYZ() + aPos.Direction().XYZ() * aVRange[0]); + gp_Trsf aLocTrsf; + aLocTrsf.SetTransformation(aPos, gp::XOY()); - gp_Trsf aTrsf; - aTrsf.SetTransformation(gp_Ax3(aPos, aDirection), gp::XOY()); + gp_Trsf aTrsf = aLocSurf * aLocTrsf; + const double aScale = aTrsf.ScaleFactor(); + aTrsf.SetScaleFactor(1.0); - Handle(Select3D_SensitiveCylinder) aSensSCyl = - new Select3D_SensitiveCylinder(theOwner, aRad, aRad, aHeight, aTrsf, true); - theSensitiveList.Append(aSensSCyl); - return Standard_True; - } + Handle(Select3D_SensitiveCylinder) aSensSCyl = + new Select3D_SensitiveCylinder(theOwner, + aRad * aScale, + aRad * aScale, + aHeight * aScale, + aTrsf, + true); + theSensitiveList.Append(aSensSCyl); + return Standard_True; } - else if (Handle(Geom_Plane) aGeomPlane = Handle(Geom_Plane)::DownCast(aSurf)) + } + else if (Handle(Geom_Plane) aGeomPlane = Handle(Geom_Plane)::DownCast(aSurf)) + { + TopTools_IndexedMapOfShape aSubfacesMap; + TopExp::MapShapes(theFace, TopAbs_EDGE, aSubfacesMap); + if (aSubfacesMap.Extent() == 1) { - TopTools_IndexedMapOfShape aSubfacesMap; - TopExp::MapShapes(theFace, TopAbs_EDGE, aSubfacesMap); - if (aSubfacesMap.Extent() == 1) + const TopoDS_Edge& anEdge = TopoDS::Edge(aSubfacesMap.FindKey(1)); + BRepAdaptor_Curve anAdaptor(anEdge); + if (anAdaptor.GetType() == GeomAbs_Circle && BRep_Tool::IsClosed(anEdge)) { - const TopoDS_Edge& anEdge = TopoDS::Edge(aSubfacesMap.FindKey(1)); - BRepAdaptor_Curve anAdaptor(anEdge); - if (anAdaptor.GetType() == GeomAbs_Circle && BRep_Tool::IsClosed(anEdge)) - { - Handle(Select3D_SensitiveCircle) aSensSCyl = - new Select3D_SensitiveCircle(theOwner, anAdaptor.Circle(), theInteriorFlag); - theSensitiveList.Append(aSensSCyl); - return Standard_True; - } + Handle(Select3D_SensitiveCircle) aSensSCyl = + new Select3D_SensitiveCircle(theOwner, anAdaptor.Circle(), theInteriorFlag); + theSensitiveList.Append(aSensSCyl); + return Standard_True; } } + } + TopLoc_Location aLoc; + if (Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(theFace, aLoc)) + { Handle(Select3D_SensitiveTriangulation) STG = new Select3D_SensitiveTriangulation(theOwner, aTriangulation, aLoc, theInteriorFlag); theSensitiveList.Append(STG); From 64ee2b1c65c79a2843ef56ebd2a1edb8bb4e61a0 Mon Sep 17 00:00:00 2001 From: Dmitrii Kulikov <164657232+AtheneNoctuaPt@users.noreply.github.com> Date: Thu, 27 Nov 2025 13:38:35 +0000 Subject: [PATCH 06/17] Modeling - BRepFilletAPI_MakeFillet::Add hangs on adding edge (#859) - Refactored the `ReorderFaces` function to iterate through all edges at a vertex instead of assuming only two edges exist - Replaced manual face swapping with `std::swap` for cleaner code - Removed debug output statements and unused debug declarations --- src/ChFi3d/ChFi3d_Builder_1.cxx | 70 +++++++++++++-------------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/src/ChFi3d/ChFi3d_Builder_1.cxx b/src/ChFi3d/ChFi3d_Builder_1.cxx index 01b2bf0250b..ca92eef12d5 100644 --- a/src/ChFi3d/ChFi3d_Builder_1.cxx +++ b/src/ChFi3d/ChFi3d_Builder_1.cxx @@ -61,10 +61,6 @@ #include #include -#ifdef OCCT_DEBUG -extern Standard_Boolean ChFi3d_GetcontextFORCEBLEND(); -#endif - static void ReorderFaces(TopoDS_Face& theF1, TopoDS_Face& theF2, const TopoDS_Face& theFirstFace, @@ -73,53 +69,49 @@ static void ReorderFaces(TopoDS_Face& theF1, const ChFiDS_Map& theEFmap) { if (theF1.IsSame(theFirstFace)) + { return; + } else if (theF2.IsSame(theFirstFace)) { - TopoDS_Face TmpFace = theF1; - theF1 = theF2; - theF2 = TmpFace; + std::swap(theF1, theF2); return; } // Loop until find or - Standard_Boolean ToExchange = Standard_False; - TopoDS_Edge PrevEdge = thePrevEdge, CurEdge; - TopoDS_Face PrevFace = theFirstFace, CurFace; + TopoDS_Edge PrevEdge = thePrevEdge; + TopoDS_Edge CurEdge; + TopoDS_Face PrevFace = theFirstFace; + TopoDS_Face CurFace; for (;;) { - TopTools_IndexedDataMapOfShapeListOfShape VEmap; - TopExp::MapShapesAndAncestors(PrevFace, TopAbs_VERTEX, TopAbs_EDGE, VEmap); - const TopTools_ListOfShape& Elist = VEmap.FindFromKey(theCommonVertex); - if (PrevEdge.IsSame(Elist.First())) - CurEdge = TopoDS::Edge(Elist.Last()); - else - CurEdge = TopoDS::Edge(Elist.First()); - - const TopTools_ListOfShape& Flist = theEFmap.FindFromKey(CurEdge); - if (PrevFace.IsSame(Flist.First())) - CurFace = TopoDS::Face(Flist.Last()); - else - CurFace = TopoDS::Face(Flist.First()); - - if (CurFace.IsSame(theF1)) - break; - else if (CurFace.IsSame(theF2)) + TopTools_IndexedDataMapOfShapeListOfShape aVertexEdgeMap; + TopExp::MapShapesAndAncestors(PrevFace, TopAbs_VERTEX, TopAbs_EDGE, aVertexEdgeMap); + for (const auto& anEdge : aVertexEdgeMap.FindFromKey(theCommonVertex)) { - ToExchange = Standard_True; - break; + if (anEdge.IsSame(PrevEdge)) + { + continue; + } + + CurEdge = TopoDS::Edge(anEdge); + const TopTools_ListOfShape& Flist = theEFmap.FindFromKey(CurEdge); + CurFace = PrevFace.IsSame(TopoDS::Face(Flist.First())) ? TopoDS::Face(Flist.Last()) + : TopoDS::Face(Flist.First()); + if (CurFace.IsSame(theF1)) + { + return; + } + else if (CurFace.IsSame(theF2)) + { + std::swap(theF1, theF2); + return; + } } PrevEdge = CurEdge; PrevFace = CurFace; } - - if (ToExchange) - { - TopoDS_Face TmpFace = theF1; - theF1 = theF2; - theF2 = TmpFace; - } } static void ConcatCurves(TColGeom_SequenceOfCurve& theCurves, @@ -787,9 +779,6 @@ void ChFi3d_Builder::PerformExtremity(const Handle(ChFiDS_Spine)& Spine) if (nbf > 3) { Spine->SetFirstStatus(ChFiDS_BreakPoint); -#ifdef OCCT_DEBUG - std::cout << "top has : " << nbf << " faces." << std::endl; -#endif } nbf = 0, jf = 0; for (It.Initialize(myVFMap(Spine->LastVertex())); It.More(); It.Next()) @@ -809,9 +798,6 @@ void ChFi3d_Builder::PerformExtremity(const Handle(ChFiDS_Spine)& Spine) if (nbf > 3) { Spine->SetLastStatus(ChFiDS_BreakPoint); -#ifdef OCCT_DEBUG - std::cout << "top has : " << nbf << " faces." << std::endl; -#endif } } } From b26323673dae098140d4aff5128f1a49db91a9ee Mon Sep 17 00:00:00 2001 From: Dmitrii Kulikov <164657232+AtheneNoctuaPt@users.noreply.github.com> Date: Sat, 29 Nov 2025 16:25:18 +0000 Subject: [PATCH 07/17] Modelling - Boolean fuse segfaults on loft (#860) - Added null checks for 2D curve handles to prevent dereferencing null geometry - Refactored `ProcessDE()` to use modern C++ idioms (auto, structured bindings, range-based iteration patterns) - Simplified `FindPaveBlocks()` using a lambda function to reduce code duplication --- src/BOPAlgo/BOPAlgo_PaveFiller_8.cxx | 180 +++++++++++--------------- src/BOPTools/BOPTools_AlgoTools_1.cxx | 13 +- 2 files changed, 86 insertions(+), 107 deletions(-) diff --git a/src/BOPAlgo/BOPAlgo_PaveFiller_8.cxx b/src/BOPAlgo/BOPAlgo_PaveFiller_8.cxx index 1d8584e4e34..051ec3e7ffd 100644 --- a/src/BOPAlgo/BOPAlgo_PaveFiller_8.cxx +++ b/src/BOPAlgo/BOPAlgo_PaveFiller_8.cxx @@ -53,133 +53,102 @@ static Standard_Boolean AddSplitPoint(const Handle(BOPDS_PaveBlock)& thePBD, void BOPAlgo_PaveFiller::ProcessDE(const Message_ProgressRange& theRange) { Message_ProgressScope aPSOuter(theRange, NULL, 1); - - Standard_Integer nF, aNb, nE, nV, nVSD, aNbPB; - Handle(NCollection_BaseAllocator) aAllocator; - Handle(BOPDS_PaveBlock) aPBD; - TColStd_ListIteratorOfListOfInteger aItLI; // // 1. Find degenerated edges //-----------------------------------------------------scope f // - aAllocator = NCollection_BaseAllocator::CommonBaseAllocator(); - BOPDS_ListOfPaveBlock aLPBOut(aAllocator); - // - aNb = myDS->NbSourceShapes(); - for (nE = 0; nE < aNb; ++nE) + + for (int anEdgeIndex = 0; anEdgeIndex < myDS->NbSourceShapes(); ++anEdgeIndex) { - const BOPDS_ShapeInfo& aSIE = myDS->ShapeInfo(nE); - if (aSIE.ShapeType() == TopAbs_EDGE) + const BOPDS_ShapeInfo& anEdgeInfo = myDS->ShapeInfo(anEdgeIndex); + if (anEdgeInfo.ShapeType() != TopAbs_EDGE) + { + continue; + } + + if (int nF = 0; anEdgeInfo.HasFlag(nF)) { - if (aSIE.HasFlag(nF)) + const BOPDS_ShapeInfo& aSIF = myDS->ShapeInfo(nF); + int nV = anEdgeInfo.SubShapes().First(); + if (int nVSD = 0; myDS->HasShapeSD(nV, nVSD)) { - const BOPDS_ShapeInfo& aSIF = myDS->ShapeInfo(nF); - nV = aSIE.SubShapes().First(); - if (myDS->HasShapeSD(nV, nVSD)) - { - nV = nVSD; - } - // nV,nE,nF - // - if (aSIF.ShapeType() == TopAbs_FACE) + nV = nVSD; + } + + if (aSIF.ShapeType() == TopAbs_FACE) + { + // 1. Find PaveBlocks that go through nV for nF + BOPDS_ListOfPaveBlock aLPBOut(NCollection_BaseAllocator::CommonBaseAllocator()); + FindPaveBlocks(nV, nF, aLPBOut); + if (!aLPBOut.IsEmpty()) { - // 1. Find PaveBlocks that go through nV for nF - FindPaveBlocks(nV, nF, aLPBOut); - aNbPB = aLPBOut.Extent(); - if (aNbPB) - { - // - // 2. - BOPDS_ListOfPaveBlock& aLPBD = myDS->ChangePaveBlocks(nE); - Standard_ASSERT_VOID(!aLPBD.IsEmpty(), "ListOfPaveBlock is unexpectedly empty"); - if (aLPBD.IsEmpty()) - continue; - aPBD = aLPBD.First(); - // - FillPaves(nV, nE, nF, aLPBOut, aPBD); - // - myDS->UpdatePaveBlock(aPBD); - } // - MakeSplitEdge(nE, nF); + // 2. + BOPDS_ListOfPaveBlock& aLPBD = myDS->ChangePaveBlocks(anEdgeIndex); + Standard_ASSERT_VOID(!aLPBD.IsEmpty(), "ListOfPaveBlock is unexpectedly empty"); + if (aLPBD.IsEmpty()) + continue; + Handle(BOPDS_PaveBlock) aPBD = aLPBD.First(); // - aLPBOut.Clear(); - } - if (aSIF.ShapeType() == TopAbs_EDGE) - { - Standard_Real aTol = 1.e-7; - Standard_Integer nEn; - BRep_Builder BB; - const TopoDS_Edge& aDE = (*(TopoDS_Edge*)(&myDS->Shape(nE))); - const TopoDS_Vertex& aVn = (*(TopoDS_Vertex*)(&myDS->Shape(nV))); + FillPaves(nV, anEdgeIndex, nF, aLPBOut, aPBD); // - TopoDS_Edge aE = aDE; - aE.EmptyCopy(); - BB.Add(aE, aVn); - BB.Degenerated(aE, Standard_True); - BB.UpdateEdge(aE, aTol); - BOPDS_ShapeInfo aSI; - aSI.SetShapeType(TopAbs_EDGE); - aSI.SetShape(aE); - nEn = myDS->Append(aSI); - BOPDS_ListOfPaveBlock& aLPBD = myDS->ChangePaveBlocks(nE); - aPBD = aLPBD.First(); - aPBD->SetEdge(nEn); + myDS->UpdatePaveBlock(aPBD); } + // + MakeSplitEdge(anEdgeIndex, nF); } - if (UserBreak(aPSOuter)) + if (aSIF.ShapeType() == TopAbs_EDGE) { - return; + const TopoDS_Edge& aDE = (*(TopoDS_Edge*)(&myDS->Shape(anEdgeIndex))); + const TopoDS_Vertex& aVn = (*(TopoDS_Vertex*)(&myDS->Shape(nV))); + // + TopoDS_Edge aE = aDE; + aE.EmptyCopy(); + BRep_Builder BB; + BB.Add(aE, aVn); + BB.Degenerated(aE, Standard_True); + BB.UpdateEdge(aE, Precision::Confusion()); + BOPDS_ShapeInfo aSI; + aSI.SetShapeType(TopAbs_EDGE); + aSI.SetShape(aE); + const int nEn = myDS->Append(aSI); + BOPDS_ListOfPaveBlock& aLPBD = myDS->ChangePaveBlocks(anEdgeIndex); + Handle(BOPDS_PaveBlock) aPBD = aLPBD.First(); + aPBD->SetEdge(nEn); } } + + if (UserBreak(aPSOuter)) + { + return; + } } } //================================================================================================= -void BOPAlgo_PaveFiller::FindPaveBlocks(const Standard_Integer nV, - const Standard_Integer nF, - BOPDS_ListOfPaveBlock& aLPBOut) +void BOPAlgo_PaveFiller::FindPaveBlocks(const Standard_Integer thePaveIndex, + const Standard_Integer theFaceInfoIndex, + BOPDS_ListOfPaveBlock& theFoundBlocks) { - Standard_Integer i, aNbPBOn, aNbPBIn, aNbPBSc, nV1, nV2; - // - const BOPDS_FaceInfo& aFI = myDS->ChangeFaceInfo(nF); - // In - const BOPDS_IndexedMapOfPaveBlock& aMPBIn = aFI.PaveBlocksIn(); - aNbPBIn = aMPBIn.Extent(); - for (i = 1; i <= aNbPBIn; ++i) - { - const Handle(BOPDS_PaveBlock)& aPB = aMPBIn(i); - aPB->Indices(nV1, nV2); - if (nV == nV1 || nV == nV2) - { - aLPBOut.Append(aPB); - } - } - // On - const BOPDS_IndexedMapOfPaveBlock& aMPBOn = aFI.PaveBlocksOn(); - aNbPBOn = aMPBOn.Extent(); - for (i = 1; i <= aNbPBOn; ++i) - { - const Handle(BOPDS_PaveBlock)& aPB = aMPBOn(i); - aPB->Indices(nV1, nV2); - if (nV == nV1 || nV == nV2) - { - aLPBOut.Append(aPB); - } - } - // Sections - const BOPDS_IndexedMapOfPaveBlock& aMPBSc = aFI.PaveBlocksSc(); - aNbPBSc = aMPBSc.Extent(); - for (i = 1; i <= aNbPBSc; ++i) - { - const Handle(BOPDS_PaveBlock)& aPB = aMPBSc(i); - aPB->Indices(nV1, nV2); - if (nV == nV1 || nV == nV2) + auto processPaveBlocks = [thePaveIndex, + &theFoundBlocks](const BOPDS_IndexedMapOfPaveBlock& thePaveBlocksMap) { + for (int aBlockIndex = 1; aBlockIndex <= thePaveBlocksMap.Size(); ++aBlockIndex) { - aLPBOut.Append(aPB); + const Handle(BOPDS_PaveBlock)& aPaveBlock = thePaveBlocksMap(aBlockIndex); + int nV1, nV2; + aPaveBlock->Indices(nV1, nV2); + if (thePaveIndex == nV1 || thePaveIndex == nV2) + { + theFoundBlocks.Append(aPaveBlock); + } } - } + }; + + const BOPDS_FaceInfo& aFaceInfo = myDS->ChangeFaceInfo(theFaceInfoIndex); + processPaveBlocks(aFaceInfo.PaveBlocksIn()); + processPaveBlocks(aFaceInfo.PaveBlocksOn()); + processPaveBlocks(aFaceInfo.PaveBlocksSc()); } //================================================================================================= @@ -279,6 +248,11 @@ void BOPAlgo_PaveFiller::FillPaves(const Standard_Integer nVD, // Get 2D curve Standard_Real aTD1, aTD2; Handle(Geom2d_Curve) aC2DDE = BRep_Tool::CurveOnSurface(aDE, aDF, aTD1, aTD2); + if (aC2DDE.IsNull()) + { + return; + } + // Get direction of the curve Standard_Boolean bUDir = Abs(aC2DDE->Value(aTD1).Y() - aC2DDE->Value(aTD2).Y()) < Precision::PConfusion(); diff --git a/src/BOPTools/BOPTools_AlgoTools_1.cxx b/src/BOPTools/BOPTools_AlgoTools_1.cxx index b773937a1dd..8d4a3092a80 100644 --- a/src/BOPTools/BOPTools_AlgoTools_1.cxx +++ b/src/BOPTools/BOPTools_AlgoTools_1.cxx @@ -678,10 +678,15 @@ void CorrectWires(const TopoDS_Face& aFx, const TopTools_IndexedMapOfShape& aMap aIt.Initialize(aLE); for (; aIt.More(); aIt.Next()) { - const TopoDS_Edge& aE = *(TopoDS_Edge*)(&aIt.Value()); - const Handle(Geom2d_Curve)& aC2D = BRep_Tool::CurveOnSurface(aE, aF, aT1, aT2); - Standard_Real aT = BRep_Tool::Parameter(aV, aE); - Standard_Boolean isClosed = Standard_False; + const TopoDS_Edge& aE = *(TopoDS_Edge*)(&aIt.Value()); + const Handle(Geom2d_Curve)& aC2D = BRep_Tool::CurveOnSurface(aE, aF, aT1, aT2); + if (aC2D.IsNull()) + { + continue; + } + + Standard_Real aT = BRep_Tool::Parameter(aV, aE); + Standard_Boolean isClosed = Standard_False; { TopoDS_Vertex aV1, aV2; TopExp::Vertices(aE, aV1, aV2); From f2a1716c844cb49f3a783dd1250217fc4c5cb9a9 Mon Sep 17 00:00:00 2001 From: Dmitrii Kulikov <164657232+AtheneNoctuaPt@users.noreply.github.com> Date: Thu, 4 Dec 2025 19:02:29 +0000 Subject: [PATCH 08/17] Modeling - BRepBuilderAPI_GTransform face stretch crash (#875) - Modified parameter validation to allow curves where `theUFirst > theULast` within `Precision::Confusion()` tolerance - Updated documentation to reflect the new tolerance-based validation - Added comprehensive test suites for both 2D and 3D curve adaptors --- src/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx | 5 +++-- src/GeomAdaptor/GeomAdaptor_Curve.hxx | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx b/src/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx index 0ac96d8b2a1..7bbc94bf1b3 100644 --- a/src/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx +++ b/src/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -71,7 +72,7 @@ public: load(theCurve, theCurve->FirstParameter(), theCurve->LastParameter()); } - //! Standard_ConstructionError is raised if theUFirst>theULast + //! Standard_ConstructionError is raised if theUFirst > theULast + Precision::PConfusion() void Load(const Handle(Geom2d_Curve)& theCurve, const Standard_Real theUFirst, const Standard_Real theULast) @@ -80,7 +81,7 @@ public: { throw Standard_NullObject(); } - if (theUFirst > theULast) + if (theUFirst > theULast + Precision::Confusion()) { throw Standard_ConstructionError(); } diff --git a/src/GeomAdaptor/GeomAdaptor_Curve.hxx b/src/GeomAdaptor/GeomAdaptor_Curve.hxx index fc217b612c3..88d576c2d81 100644 --- a/src/GeomAdaptor/GeomAdaptor_Curve.hxx +++ b/src/GeomAdaptor/GeomAdaptor_Curve.hxx @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -47,7 +48,7 @@ public: GeomAdaptor_Curve(const Handle(Geom_Curve)& theCurve) { Load(theCurve); } - //! Standard_ConstructionError is raised if theUFirst>theULast + //! Standard_ConstructionError is raised if theUFirst > theULast + Precision::PConfusion() GeomAdaptor_Curve(const Handle(Geom_Curve)& theCurve, const Standard_Real theUFirst, const Standard_Real theULast) @@ -70,7 +71,7 @@ public: load(theCurve, theCurve->FirstParameter(), theCurve->LastParameter()); } - //! Standard_ConstructionError is raised if theUFirst>theULast + //! Standard_ConstructionError is raised if theUFirst > theULast + Precision::PConfusion() void Load(const Handle(Geom_Curve)& theCurve, const Standard_Real theUFirst, const Standard_Real theULast) @@ -79,7 +80,7 @@ public: { throw Standard_NullObject(); } - if (theUFirst > theULast) + if (theUFirst > theULast + Precision::Confusion()) { throw Standard_ConstructionError(); } From 0eb60a540451ed72993400feccbd8ba0621a432b Mon Sep 17 00:00:00 2001 From: Dmitrii Kulikov <164657232+AtheneNoctuaPt@users.noreply.github.com> Date: Thu, 4 Dec 2025 19:03:00 +0000 Subject: [PATCH 09/17] Modelling - ShapeUpgrade_UnifySameDomain crash (#876) - Added null safety checks for `BRepAdaptor_Curve2d::Curve()` before evaluating curve parameters - Modernized variable declarations with `const` qualifiers - Replaced conditional assignment with `std::min` for cleaner code --- .../ShapeUpgrade_UnifySameDomain.cxx | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/ShapeUpgrade/ShapeUpgrade_UnifySameDomain.cxx b/src/ShapeUpgrade/ShapeUpgrade_UnifySameDomain.cxx index ed1c55d1f5a..a43cbfb727c 100644 --- a/src/ShapeUpgrade/ShapeUpgrade_UnifySameDomain.cxx +++ b/src/ShapeUpgrade/ShapeUpgrade_UnifySameDomain.cxx @@ -332,9 +332,14 @@ static Standard_Real ComputeMinEdgeSize(const TopTools_SequenceOfShape& theEdges TopoDS_Vertex V1, V2; TopExp::Vertices(anEdge, V1, V2); BRepAdaptor_Curve2d BAcurve2d(anEdge, theRefFace); - gp_Pnt2d FirstP2d = BAcurve2d.Value(BAcurve2d.FirstParameter()); - gp_Pnt2d LastP2d = BAcurve2d.Value(BAcurve2d.LastParameter()); - Standard_Real aSqDist; + if (BAcurve2d.Curve().IsNull()) + { + continue; + } + + const gp_Pnt2d FirstP2d = BAcurve2d.Value(BAcurve2d.FirstParameter()); + const gp_Pnt2d LastP2d = BAcurve2d.Value(BAcurve2d.LastParameter()); + Standard_Real aSqDist; if (V1.IsSame(V2) && !BRep_Tool::Degenerated(anEdge)) { gp_Pnt2d MidP2d = @@ -342,9 +347,11 @@ static Standard_Real ComputeMinEdgeSize(const TopTools_SequenceOfShape& theEdges aSqDist = FirstP2d.SquareDistance(MidP2d); } else + { aSqDist = FirstP2d.SquareDistance(LastP2d); - if (aSqDist < MinSize) - MinSize = aSqDist; + } + + MinSize = std::min(MinSize, aSqDist); } MinSize = Sqrt(MinSize); return MinSize; @@ -3568,8 +3575,13 @@ void ShapeUpgrade_UnifySameDomain::IntUnifyFaces( { const TopoDS_Edge& anEdge = TopoDS::Edge(edges(ii)); BRepAdaptor_Curve2d aBAcurve(anEdge, F_RefFace); - gp_Pnt2d aFirstPoint = aBAcurve.Value(aBAcurve.FirstParameter()); - gp_Pnt2d aLastPoint = aBAcurve.Value(aBAcurve.LastParameter()); + if (aBAcurve.Curve().IsNull()) + { + continue; + } + + gp_Pnt2d aFirstPoint = aBAcurve.Value(aBAcurve.FirstParameter()); + gp_Pnt2d aLastPoint = aBAcurve.Value(aBAcurve.LastParameter()); if (aFirstPoint.X() < FaceUmin) FaceUmin = aFirstPoint.X(); @@ -3604,6 +3616,11 @@ void ShapeUpgrade_UnifySameDomain::IntUnifyFaces( Standard_Real fpar, lpar; Handle(Geom2d_Curve) StartPCurve = BRep_Tool::CurveOnSurface(StartEdge, F_RefFace, fpar, lpar); + if (StartPCurve.IsNull()) + { + edges.Remove(istart); + continue; + } TopoDS_Vertex StartVertex, CurVertex; TopExp::Vertices(StartEdge, StartVertex, CurVertex, Standard_True); // with orientation Standard_Real StartParam, CurParam; From fe019d4cd65007aaba7b85a199fdea380374c410 Mon Sep 17 00:00:00 2001 From: Pasukhin Dmitry Date: Sun, 30 Nov 2025 10:29:46 +0000 Subject: [PATCH 10/17] Modeling - Memory consumption in BOPAlgo_PaveFiller_6.cxx (#864) - Introduced a separate temporary allocator (`aTmpAllocator`) for per-iteration collections - Reorganized collection declarations to distinguish between temporary (per-iteration) and persistent (cross-iteration) data structures - Added allocator reset logic at the start of each iteration to reclaim memory --- src/BOPAlgo/BOPAlgo_PaveFiller_6.cxx | 45 ++++++++++++++++++---------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/BOPAlgo/BOPAlgo_PaveFiller_6.cxx b/src/BOPAlgo/BOPAlgo_PaveFiller_6.cxx index 99022a51682..aba6a88dd08 100644 --- a/src/BOPAlgo/BOPAlgo_PaveFiller_6.cxx +++ b/src/BOPAlgo/BOPAlgo_PaveFiller_6.cxx @@ -664,31 +664,38 @@ void BOPAlgo_PaveFiller::MakeBlocks(const Message_ProgressRange& theRange) return; } // - Standard_Boolean bExist, bValid2D; - Standard_Integer i, nF1, nF2, aNbC, aNbP, j; - Standard_Integer nV1, nV2; - Standard_Real aT1, aT2; - Handle(NCollection_BaseAllocator) aAllocator = new NCollection_IncAllocator; + Standard_Boolean bExist, bValid2D; + Standard_Integer i, nF1, nF2, aNbC, aNbP, j; + Standard_Integer nV1, nV2; + Standard_Real aT1, aT2; + Handle(NCollection_BaseAllocator) aAllocator = new NCollection_IncAllocator; + // Temporary allocator for per-iteration collections that are cleared each iteration. + // Using separate allocator allows to reclaim memory via Reset(false) at the start + // of each iteration, preventing memory accumulation in the main loop. + Handle(NCollection_IncAllocator) aTmpAllocator = new NCollection_IncAllocator; BOPDS_ListIteratorOfListOfPaveBlock aItLPB; TopoDS_Edge aES; Handle(BOPDS_PaveBlock) aPBOut; // //-----------------------------------------------------scope f // - TColStd_ListOfInteger aLSE(aAllocator), aLBV(aAllocator); - TColStd_MapOfInteger aMVOnIn(100, aAllocator), aMVCommon(100, aAllocator), - aMVStick(100, aAllocator), aMVEF(100, aAllocator), aMI(100, aAllocator), - aMVBounds(100, aAllocator); - BOPDS_IndexedMapOfPaveBlock aMPBOnIn(100, aAllocator); - BOPDS_MapOfPaveBlock aMPBAdd(100, aAllocator), aMPBCommon; + // Per-iteration collections (use temporary allocator, reset each iteration) + TColStd_ListOfInteger aLSE(aTmpAllocator), aLBV(aTmpAllocator); + TColStd_MapOfInteger aMVOnIn(100, aTmpAllocator), aMVCommon(100, aTmpAllocator), + aMVStick(100, aTmpAllocator), aMVEF(100, aTmpAllocator), aMVBounds(100, aTmpAllocator); + BOPDS_IndexedMapOfPaveBlock aMPBOnIn(100, aTmpAllocator); + BOPDS_MapOfPaveBlock aMPBCommon; + TColStd_DataMapOfIntegerReal aMVTol(100, aTmpAllocator); + TColStd_DataMapOfIntegerListOfInteger aDMBV(100, aTmpAllocator); + // Cross-iteration collections (use main allocator, persist through entire loop) + TColStd_MapOfInteger aMI(100, aAllocator); + BOPDS_MapOfPaveBlock aMPBAdd(100, aAllocator); BOPDS_ListOfPaveBlock aLPB(aAllocator); BOPDS_IndexedDataMapOfShapeCoupleOfPaveBlocks aMSCPB(100, aAllocator); TopTools_DataMapOfShapeInteger aMVI(100, aAllocator); BOPDS_DataMapOfPaveBlockListOfPaveBlock aDMExEdges(100, aAllocator); - TColStd_DataMapOfIntegerReal aMVTol(100, aAllocator); TColStd_DataMapOfIntegerInteger aDMNewSD(100, aAllocator); TColStd_DataMapOfIntegerListOfInteger aDMVLV; - TColStd_DataMapOfIntegerListOfInteger aDMBV(100, aAllocator); TColStd_DataMapIteratorOfDataMapOfIntegerReal aItMV; BOPDS_IndexedMapOfPaveBlock aMicroPB(100, aAllocator); TopTools_IndexedMapOfShape aVertsOnRejectedPB; @@ -731,6 +738,10 @@ void BOPAlgo_PaveFiller::MakeBlocks(const Message_ProgressRange& theRange) BOPDS_FaceInfo& aFI1 = myDS->ChangeFaceInfo(nF1); BOPDS_FaceInfo& aFI2 = myDS->ChangeFaceInfo(nF2); // + // Reset temporary allocator to reclaim memory from previous iteration. + // This prevents memory accumulation when processing many Face-Face pairs. + // All per-iteration collections must be cleared after Reset to invalidate old pointers. + aTmpAllocator->Reset(false); aMVOnIn.Clear(); aMVCommon.Clear(); aMPBOnIn.Clear(); @@ -738,9 +749,13 @@ void BOPAlgo_PaveFiller::MakeBlocks(const Message_ProgressRange& theRange) aDMBV.Clear(); aMVTol.Clear(); aLSE.Clear(); + aLBV.Clear(); + aMVStick.Clear(); + aMVEF.Clear(); + aMVBounds.Clear(); // myDS->SubShapesOnIn(nF1, nF2, aMVOnIn, aMVCommon, aMPBOnIn, aMPBCommon); - myDS->SharedEdges(nF1, nF2, aLSE, aAllocator); + myDS->SharedEdges(nF1, nF2, aLSE, aTmpAllocator); // // 1. Treat Points for (j = 0; j < aNbP; ++j) @@ -763,8 +778,6 @@ void BOPAlgo_PaveFiller::MakeBlocks(const Message_ProgressRange& theRange) } // // 2. Treat Curves - aMVStick.Clear(); - aMVEF.Clear(); GetStickVertices(nF1, nF2, aMVStick, aMVEF, aMI); // for (j = 0; j < aNbC; ++j) From d0ac6b9f51d33a7adb9771372b59653f916a69c3 Mon Sep 17 00:00:00 2001 From: Dmitrii Kulikov <164657232+AtheneNoctuaPt@users.noreply.github.com> Date: Wed, 24 Sep 2025 16:47:24 +0100 Subject: [PATCH 11/17] Data Exchange - Hang in STEPCAFControl_Reader (#733) Constructor of BRepTopAdaptor_FClass2d is updated to guarantee processing of curves with large parameters values with small difference between them. --- .../BRepTopAdaptor_FClass2d.cxx | 222 +++++------------- 1 file changed, 65 insertions(+), 157 deletions(-) diff --git a/src/BRepTopAdaptor/BRepTopAdaptor_FClass2d.cxx b/src/BRepTopAdaptor/BRepTopAdaptor_FClass2d.cxx index 8dffe1e312d..26a8e7866ca 100644 --- a/src/BRepTopAdaptor/BRepTopAdaptor_FClass2d.cxx +++ b/src/BRepTopAdaptor/BRepTopAdaptor_FClass2d.cxx @@ -14,8 +14,6 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. -#define AFFICHAGE 0 - #define No_Standard_OutOfRange #include @@ -46,38 +44,46 @@ #include #endif -#ifdef OCCT_DEBUG - #define LBRCOMPT 0 -#else - #define LBRCOMPT 0 -#endif - -#if LBRCOMPT -class StatistiquesFClass2d +namespace { -public: - long unsigned NbConstrShape; - long unsigned NbPerformInfinitePoint; - long unsigned NbPerform; - long unsigned NbTestOnRestriction; - long unsigned NbDestroy; +// Increments @p theValue by @p theIncrement towards @p theDirection, ensuring that the result is +// different from @p theValue. For large values of theValue with small theIncrement the result of +// theValue + theIncrement can be equal to theValue due to the limited resolution of double +// precision. This function guarantees to return the next representable value in the direction of +// theDirection in such cases. +inline double safeIncrement(const double theValue, + const double theDirection, + const double theIncrement) +{ + const double aNextValue = theValue + theIncrement; + return aNextValue == theValue ? std::nextafter(theValue, theDirection) : aNextValue; +} -public: - StatistiquesFClass2d() { NbConstrShape = NbPerform = NbPerformInfinitePoint = NbDestroy = 0; } +//================================================================================================== - ~StatistiquesFClass2d() +// Checks whether the curve is degenerated between theStartParam and theEndParam. +// The check is performed by sampling the curve at several points and measuring the distance to the +// start point. If all sampled points are closer than Precision::Confusion() to the start point, the +// curve is considered degenerated. +bool isDegenerated(const BRepAdaptor_Curve& theCurve, + const double theStartParam, + const double theEndParam) +{ + const double aParametricStep = (theEndParam - theStartParam) * 0.1; + const gp_Pnt aStartPoint = theCurve.Value(theStartParam); + for (double aCurrParam = theStartParam; aCurrParam < theEndParam; + aCurrParam = safeIncrement(aCurrParam, theEndParam, aParametricStep)) { - printf("\n--- Statistiques BRepTopAdaptor:\n"); - printf("\nConstructeur(Shape) : %10lu", NbConstrShape); - printf("\nPerformInfinitePoint: %10lu", NbPerformInfinitePoint); - printf("\nTestOnRestriction : %10lu", NbTestOnRestriction); - printf("\nPerform(pnt2d) : %10lu", NbPerform); - printf("\nDestroy : %10lu", NbDestroy); + const gp_Pnt aCurrentPoint = theCurve.Value(aCurrParam); + if (aStartPoint.SquareDistance(aCurrentPoint) > Precision::Confusion()) + { + return false; + } } -}; -static StatistiquesFClass2d STAT; -#endif + return true; +} +} // namespace BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, const Standard_Real TolUV) @@ -88,11 +94,6 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, U2(0.0), V2(0.0) { - -#if LBRCOMPT - STAT.NbConstrShape++; -#endif - //-- dead end on surfaces defined on more than one period Face.Orientation(TopAbs_FORWARD); @@ -101,18 +102,16 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, TopoDS_Edge edge; TopAbs_Orientation Or; - Standard_Real u, du, Tole = 0.0, Tol = 0.0; BRepTools_WireExplorer WireExplorer; - TopExp_Explorer FaceExplorer; Umin = Vmin = 0.0; // RealLast(); Umax = Vmax = -Umin; - Standard_Integer aNbE = 0; - Standard_Real eps = 1.e-10; - Standard_Integer BadWire = 0; - for (FaceExplorer.Init(Face, TopAbs_WIRE); (FaceExplorer.More() && BadWire == 0); - FaceExplorer.Next()) + Standard_Integer aNbE = 0; + constexpr Standard_Real eps = 1.e-10; + bool anIsBadWire = false; + for (TopExp_Explorer aFaceExplorer(Face, TopAbs_WIRE); (aFaceExplorer.More() && !anIsBadWire); + aFaceExplorer.Next()) { Standard_Integer nbpnts = 0; TColgp_SequenceOfPnt2d SeqPnt2d; @@ -123,17 +122,16 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, Standard_Integer NbEdges = 0; TopExp_Explorer Explorer; - for (Explorer.Init(FaceExplorer.Current(), TopAbs_EDGE); Explorer.More(); Explorer.Next()) + for (Explorer.Init(aFaceExplorer.Current(), TopAbs_EDGE); Explorer.More(); Explorer.Next()) NbEdges++; aNbE = NbEdges; gp_Pnt Ancienpnt3d(0, 0, 0); Standard_Boolean Ancienpnt3dinitialise = Standard_False; - for (WireExplorer.Init(TopoDS::Wire(FaceExplorer.Current()), Face); WireExplorer.More(); + for (WireExplorer.Init(TopoDS::Wire(aFaceExplorer.Current()), Face); WireExplorer.More(); WireExplorer.Next()) { - NbEdges--; edge = WireExplorer.Current(); Or = edge.Orientation(); @@ -142,71 +140,44 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, Standard_Real pfbid, plbid; if (BRep_Tool::CurveOnSurface(edge, Face, pfbid, plbid).IsNull()) return; - BRepAdaptor_Curve2d C(edge, Face); - //-- ---------------------------------------- + if (Abs(plbid - pfbid) < 1.e-9) + continue; + Standard_Boolean degenerated = Standard_False; if (BRep_Tool::Degenerated(edge)) + { degenerated = Standard_True; + } if (BRep_Tool::IsClosed(edge, Face)) + { degenerated = Standard_True; + } TopoDS_Vertex Va, Vb; TopExp::Vertices(edge, Va, Vb); - Standard_Real TolVertex1 = 0., TolVertex = 0.; - if (Va.IsNull()) - degenerated = Standard_True; - else - TolVertex1 = BRep_Tool::Tolerance(Va); - if (Vb.IsNull()) + if (Va.IsNull() || Vb.IsNull()) + { degenerated = Standard_True; - else - TolVertex = BRep_Tool::Tolerance(Vb); - if (TolVertex < TolVertex1) - TolVertex = TolVertex1; - BRepAdaptor_Curve C3d; - - if (Abs(plbid - pfbid) < 1.e-9) - continue; + } - // if(degenerated==Standard_False) - // C3d.Initialize(edge,Face); + const BRepAdaptor_Curve2d aCurveAdaptor2D(edge, Face); + const BRepAdaptor_Curve aCurveAdaptor3D(edge, Face); //-- Check cases when it was forgotten to code degenerated : PRO17410 (janv 99) if (degenerated == Standard_False) { - C3d.Initialize(edge, Face); - du = (plbid - pfbid) * 0.1; - u = pfbid + du; - gp_Pnt P3da = C3d.Value(u); - degenerated = Standard_True; - u += du; - do - { - - gp_Pnt P3db = C3d.Value(u); - // if(P3da.SquareDistance(P3db)) { degenerated=Standard_False; break; } - if (P3da.SquareDistance(P3db) > Precision::Confusion()) - { - degenerated = Standard_False; - break; - } - u += du; - } while (u < plbid); + degenerated = isDegenerated(aCurveAdaptor3D, pfbid, plbid); } //-- ---------------------------------------- - Tole = BRep_Tool::Tolerance(edge); - if (Tole > Tol) - Tol = Tole; - // Standard_Integer nbs = 1 + Geom2dInt_Geom2dCurveTool::NbSamples(C); - Standard_Integer nbs = Geom2dInt_Geom2dCurveTool::NbSamples(C); + Standard_Integer nbs = Geom2dInt_Geom2dCurveTool::NbSamples(aCurveAdaptor2D); //-- Attention to rational bsplines of degree 3. (ends of circles among others) if (nbs > 2) nbs *= 4; - du = (plbid - pfbid) / (Standard_Real)(nbs - 1); - + Standard_Real du = (plbid - pfbid) / (Standard_Real)(nbs - 1); + Standard_Real u = 0.0; if (Or == TopAbs_FORWARD) u = pfbid; else @@ -220,24 +191,12 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, //-- and the last point registered in SeqPnt2d //-- Try to remote the first point of the current edge //-- from the last saved point -#ifdef OCCT_DEBUG - gp_Pnt2d Pnt2dDebutEdgeCourant = C.Value(u); - (void)Pnt2dDebutEdgeCourant; -#endif - - // Standard_Real Baillement2dU=0; - // Standard_Real Baillement2dV=0; -#if AFFICHAGE - if (nbpnts > 1) - printf("\nTolVertex %g ", TolVertex); -#endif - if (firstpoint == 2) u += du; Standard_Integer Avant = nbpnts; for (Standard_Integer e = firstpoint; e <= nbs; e++) { - gp_Pnt2d P2d = C.Value(u); + gp_Pnt2d P2d = aCurveAdaptor2D.Value(u); if (P2d.X() < Umin) Umin = P2d.X(); if (P2d.X() > Umax) @@ -251,14 +210,14 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, gp_Pnt P3d; if (degenerated == Standard_False) { - P3d = C3d.Value(u); + P3d = aCurveAdaptor3D.Value(u); if (nbpnts > 1 && Ancienpnt3dinitialise) dist3dptcourant_ancienpnt = P3d.Distance(Ancienpnt3d); } Standard_Boolean IsRealCurve3d = Standard_True; // patch if (dist3dptcourant_ancienpnt < Precision::Confusion()) { - gp_Pnt MidP3d = C3d.Value(u - du / 2.); + gp_Pnt MidP3d = aCurveAdaptor3D.Value(u - du / 2.); if (P3d.Distance(MidP3d) < Precision::Confusion()) IsRealCurve3d = Standard_False; } @@ -272,13 +231,7 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, nbpnts++; SeqPnt2d.Append(P2d); } -#if AFFICHAGE - else - { - static int mm = 0; - printf("\npoint p%d %g %g %g", ++mm, P3d.X(), P3d.Y(), P3d.Z()); - } -#endif + u += du; Standard_Integer ii = nbpnts; //-- printf("\n nbpnts:%4d u=%7.5g FlecheU=%7.5g FlecheV=%7.5g ii=%3d Avant=%3d @@ -308,21 +261,12 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, if (NbEdges) { //-- on compte ++ with a normal explorer and with the Wire Explorer - /* - #ifdef OCCT_DEBUG - - std::cout << std::endl; - std::cout << "*** BRepTopAdaptor_Fclass2d ** Wire Probablement FAUX **" << std::endl; - std::cout << "*** WireExplorer does not find all edges " << std::endl; - std::cout << "*** Connect old classifier" << std::endl; - #endif - */ TColgp_Array1OfPnt2d PClass(1, 2); //// modified by jgv, 28.04.2009 //// PClass.Init(gp_Pnt2d(0., 0.)); ///////////////////////////////////// TabClass.Append((void*)new CSLib_Class2d(PClass, FlecheU, FlecheV, Umin, Vmin, Umax, Vmax)); - BadWire = 1; + anIsBadWire = true; TabOrien.Append(-1); } else if (WireIsNotEmpty) @@ -378,7 +322,7 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, SeqPnt2d.Clear(); FlecheU = 0.0; FlecheV = 0.0; - for (WireExplorer.Init(TopoDS::Wire(FaceExplorer.Current()), Face); WireExplorer.More(); + for (WireExplorer.Init(TopoDS::Wire(aFaceExplorer.Current()), Face); WireExplorer.More(); WireExplorer.Next()) { edge = WireExplorer.Current(); @@ -462,31 +406,11 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, FlecheU = Toluv; if (FlecheV < Toluv) FlecheV = Toluv; - //-- std::cout<<" U:"<-2)||(angle>10)||(angle<-10)) - // { - // BadWire=1; - // TabOrien.Append(-1); - // #ifdef OCCT_DEBUG - // std::cout << std::endl; - // std::cout << "*** BRepTopAdaptor_Fclass2d ** Wire Probably FALSE **" << - // std::endl; std::cout << "*** Total rotation angle of the wire : " << angle << - // std::endl; std::cout << "*** Connect the old classifier" << std::endl; - // #endif - // } - // else TabOrien.Append(((angle>0.0)? 1 : 0)); } // if(nbpoints>3 else { -#ifdef OCCT_DEBUG - std::cout << std::endl; - std::cout << "*** BRepTopAdaptor_Fclass2d ** Wire Probably FALSE **" << std::endl; - std::cout << "*** The sample wire contains less than 3 points" << std::endl; - std::cout << "*** Connect the old classifier" << std::endl; -#endif - BadWire = 1; + anIsBadWire = true; TabOrien.Append(-1); TColgp_Array1OfPnt2d xPClass(1, 2); xPClass(1) = SeqPnt2d(1); @@ -502,7 +426,7 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, if (nbtabclass > 0) { //-- If an error was detected on a wire: set all TabOrien to -1 - if (BadWire) + if (anIsBadWire) TabOrien(1) = -1; if (surf->GetType() == GeomAbs_Cone || surf->GetType() == GeomAbs_Cylinder @@ -538,10 +462,6 @@ BRepTopAdaptor_FClass2d::BRepTopAdaptor_FClass2d(const TopoDS_Face& aFace, TopAbs_State BRepTopAdaptor_FClass2d::PerformInfinitePoint() const { -#if LBRCOMPT - STAT.NbPerformInfinitePoint++; -#endif - if (Umax == -RealLast() || Vmax == -RealLast() || Umin == RealLast() || Vmin == RealLast()) { return (TopAbs_IN); @@ -553,10 +473,6 @@ TopAbs_State BRepTopAdaptor_FClass2d::PerformInfinitePoint() const TopAbs_State BRepTopAdaptor_FClass2d::Perform(const gp_Pnt2d& _Puv, const Standard_Boolean RecadreOnPeriodic) const { -#if LBRCOMPT - STAT.NbPerform++; -#endif - Standard_Integer dedans; Standard_Integer nbtabclass = TabClass.Length(); @@ -698,10 +614,6 @@ TopAbs_State BRepTopAdaptor_FClass2d::TestOnRestriction( const Standard_Real Tol, const Standard_Boolean RecadreOnPeriodic) const { -#if LBRCOMPT - STAT.NbConstrShape++; -#endif - Standard_Integer dedans; Standard_Integer nbtabclass = TabClass.Length(); @@ -836,10 +748,6 @@ TopAbs_State BRepTopAdaptor_FClass2d::TestOnRestriction( void BRepTopAdaptor_FClass2d::Destroy() { -#if LBRCOMPT - STAT.NbDestroy++; -#endif - Standard_Integer nbtabclass = TabClass.Length(); for (Standard_Integer d = 1; d <= nbtabclass; d++) { From 12a63a7cb4f5ac305b4cc8a0374b553ebd52bb0c Mon Sep 17 00:00:00 2001 From: Pasukhin Dmitry Date: Sat, 11 Oct 2025 12:19:50 +0100 Subject: [PATCH 12/17] Shape Healing - Optimize FixFaceOrientation (#584) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor shell construction algorithm for improved performance: - Add GetConnectedFaceGroups function using DFS to identify topologically connected face groups before shell construction - Replace O(nˆ3) iterations with pre-built connectivity maps (FaceEdgesMap, EdgeFacesMap) using STL unordered_map with custom allocators for O(1) lookup. - Process only the largest connected component first, significantly reducing time complexity for large face sets --- src/ShapeFix/ShapeFix_Shell.cxx | 480 ++++++++++++++++++++++++++------ 1 file changed, 398 insertions(+), 82 deletions(-) diff --git a/src/ShapeFix/ShapeFix_Shell.cxx b/src/ShapeFix/ShapeFix_Shell.cxx index 67a4fd798e1..ef05ee8131a 100644 --- a/src/ShapeFix/ShapeFix_Shell.cxx +++ b/src/ShapeFix/ShapeFix_Shell.cxx @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -48,8 +52,35 @@ #include #include +#include +#include +#include +#include + IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Shell, ShapeFix_Root) +namespace +{ +// Type aliases for unordered maps with custom allocators +using FaceEdgesAllocator = + NCollection_Allocator>>; +using FaceEdgesMap = std::unordered_map, + TopTools_ShapeMapHasher, + TopTools_ShapeMapHasher, + FaceEdgesAllocator>; +using EdgeFacesAllocator = + NCollection_Allocator>>; +using EdgeFacesMap = std::unordered_map, + TopTools_ShapeMapHasher, + TopTools_ShapeMapHasher, + EdgeFacesAllocator>; + +// Default increment for dynamic array of faces per edge +constexpr Standard_Integer DEFAULT_EDGE_FACES_INCREMENT = 5; +} // namespace + //================================================================================================= ShapeFix_Shell::ShapeFix_Shell() @@ -168,137 +199,404 @@ static Standard_Boolean GetFreeEdges(const TopoDS_Shape& aShape, TopTools_MapOfS return !MapEdges.IsEmpty(); } -//======================================================================= -// function : GetShells -// purpose : If mode isMultiConnex = Standard_True gets max possible shell for -// exception of multiconnexity parts. -// Else if this mode is equal to Standard_False maximum possible -// shell will be created without taking account of multiconnexity. -// In this function map face - shell and sequence of mebius faces is formed. -//======================================================================= -static Standard_Boolean GetShells(TopTools_SequenceOfShape& Lface, - const TopTools_MapOfShape& aMapMultiConnectEdges, - TopTools_SequenceOfShape& aSeqShells, - TopTools_DataMapOfShapeShape& aMapFaceShells, - TopTools_SequenceOfShape& ErrFaces) +/// Groups connected faces into separate sequences using existing connectivity data. +/// Uses depth-first search to find connected components through shared edges. +/// Each face appears in exactly one group, ensuring no duplicates across groups. +/// Groups are sorted by size with the largest group first. +/// @param theFaceEdges Map from faces to their constituent edges +/// @param theEdgeFaces Map from edges to faces that contain them +/// @return List of face sequences, each representing one connected component +static NCollection_List GetConnectedFaceGroups( + const FaceEdgesMap& theFaceEdges, + const EdgeFacesMap& theEdgeFaces) { - Standard_Boolean done = Standard_False; - if (!Lface.Length()) + NCollection_List aConnectedGroups; + + if (theFaceEdges.empty()) + { + return aConnectedGroups; + } + + TopTools_MapOfShape aVisitedFaces(static_cast(theFaceEdges.size())); + + for (auto aFaceIter = theFaceEdges.begin(); aFaceIter != theFaceEdges.end(); ++aFaceIter) + { + const TopoDS_Face& aStartFace = aFaceIter->first; + + if (aVisitedFaces.Contains(aStartFace)) + { + continue; + } + + // Start new connected group + TopTools_SequenceOfShape aConnectedGroup; + + // DFS traversal using STL stack with NCollection_Allocator + using StackAllocator = NCollection_Allocator; + std::stack> aStack; + aStack.push(aStartFace); + aVisitedFaces.Add(aStartFace); + + while (!aStack.empty()) + { + const TopoDS_Face aCurrentFace = aStack.top(); + aStack.pop(); + aConnectedGroup.Append(aCurrentFace); + + // Find connected faces through shared edges + auto aFaceEdgesIter = theFaceEdges.find(aCurrentFace); + if (aFaceEdgesIter != theFaceEdges.end()) + { + const NCollection_Array1& aFaceEdgesArray = aFaceEdgesIter->second; + + for (Standard_Integer anEdgeIdx = aFaceEdgesArray.Lower(); + anEdgeIdx <= aFaceEdgesArray.Upper(); + ++anEdgeIdx) + { + const TopoDS_Edge& anEdge = aFaceEdgesArray.Value(anEdgeIdx); + + auto anEdgeFacesIter = theEdgeFaces.find(anEdge); + if (anEdgeFacesIter != theEdgeFaces.end()) + { + const NCollection_DynamicArray& aConnectedFaces = anEdgeFacesIter->second; + + for (Standard_Integer aFaceIdx = 0; aFaceIdx < aConnectedFaces.Length(); ++aFaceIdx) + { + const TopoDS_Face& aNeighborFace = aConnectedFaces.Value(aFaceIdx); + + if (!aVisitedFaces.Contains(aNeighborFace)) + { + aVisitedFaces.Add(aNeighborFace); + aStack.push(aNeighborFace); + } + } + } + } + } + } + + // Insert in sorted order (largest groups first) + Standard_Boolean anIsInserted = Standard_False; + + for (NCollection_List::Iterator anIter(aConnectedGroups); + anIter.More(); + anIter.Next()) + { + if (aConnectedGroup.Length() > anIter.Value().Length()) + { + aConnectedGroups.InsertBefore(aConnectedGroup, anIter); + anIsInserted = Standard_True; + break; + } + } + + if (!anIsInserted) + { + aConnectedGroups.Append(aConnectedGroup); + } + } + + return aConnectedGroups; +} + +/// Creates shells from connected face groups using connectivity analysis. +/// Processes only the largest connected group for shell construction, improving efficiency +/// by focusing on faces that are actually topologically connected. +/// @param theLfaces Input sequence of faces to process; returns unprocessed faces +/// @param theMapMultiConnectEdges Map of edges shared by more than 2 faces (multiconnectivity mode) +/// @param theSeqShells Output sequence of created shells +/// @param theMapFaceShells Output map linking faces to their containing shells +/// @param theErrFaces Output sequence of faces that could not be processed (e.g., Mobius-like) +/// @return Standard_True if shell construction was successful, Standard_False otherwise +static Standard_Boolean GetShells(TopTools_SequenceOfShape& theLfaces, + const TopTools_MapOfShape& theMapMultiConnectEdges, + TopTools_SequenceOfShape& theSeqShells, + TopTools_DataMapOfShapeShape& theMapFaceShells, + TopTools_SequenceOfShape& theErrFaces) +{ + Standard_Boolean aDone = Standard_False; + if (!theLfaces.Length()) + { return Standard_False; - TopoDS_Shell nshell; - TopTools_MapOfShape dire, reve; - BRep_Builder B; + } + TopoDS_Shell nshell; + BRep_Builder B; B.MakeShell(nshell); - Standard_Boolean isMultiConnex = !aMapMultiConnectEdges.IsEmpty(); - Standard_Integer i = 1, j = 1; + Standard_Boolean anIsMultiConnex = !theMapMultiConnectEdges.IsEmpty(); + Standard_Integer aFaceIdx = 1, aFacesInShellCount = 1; TopTools_SequenceOfShape aSeqUnconnectFaces; - for (; i <= Lface.Length(); i++) + + // Using STL containers because number of faces or edges can be too high + // to keep them on flat basket OCCT map + using EdgeMapAllocator = + NCollection_Allocator>>; + using EdgeOrientedMap = std::unordered_map, + TopTools_ShapeMapHasher, + TopTools_ShapeMapHasher, + EdgeMapAllocator>; + using TempProcessedEdges = + NCollection_DataMap, TopTools_ShapeMapHasher>; + + FaceEdgesMap aFaceEdges; + aFaceEdges.reserve(theLfaces.Length()); + size_t aNumberOfEdges = 0; + NCollection_DynamicArray aTempEdges; + for (TopTools_SequenceOfShape::Iterator anFaceIter(theLfaces); anFaceIter.More(); + anFaceIter.Next()) + { + aTempEdges.Clear(); + TopoDS_Face aFace = TopoDS::Face(anFaceIter.Value()); + for (TopExp_Explorer anEdgeExp(aFace, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) + { + aTempEdges.Append(TopoDS::Edge(anEdgeExp.Current())); + aNumberOfEdges++; + } + NCollection_Array1 aFaceEdgesArray(1, static_cast(aTempEdges.Length())); + for (Standard_Integer idx = 0; idx < aTempEdges.Length(); ++idx) + { + aFaceEdgesArray.SetValue(idx + 1, aTempEdges.Value(idx)); + } + aFaceEdges[aFace] = std::move(aFaceEdgesArray); + } + + EdgeFacesMap aEdgeFaces; + aEdgeFaces.reserve(aNumberOfEdges); + + for (const auto& aFaceEdgesPair : aFaceEdges) + { + const TopoDS_Face& aFace = aFaceEdgesPair.first; + const NCollection_Array1& aFaceEdgesArray = aFaceEdgesPair.second; + + for (Standard_Integer anEdgeInd = aFaceEdgesArray.Lower(); anEdgeInd <= aFaceEdgesArray.Upper(); + ++anEdgeInd) + { + const TopoDS_Edge& anEdge = aFaceEdgesArray.Value(anEdgeInd); + + auto& aFacesArray = aEdgeFaces[anEdge]; + + // Check if face already exists in the array + Standard_Boolean aFaceExists = Standard_False; + for (Standard_Integer aFaceCheckIdx = 0; aFaceCheckIdx < aFacesArray.Length(); + ++aFaceCheckIdx) + { + if (aFacesArray.Value(aFaceCheckIdx).IsSame(aFace)) + { + aFaceExists = Standard_True; + break; + } + } + + if (aFacesArray.IsEmpty()) + { + aFacesArray.SetIncrement(DEFAULT_EDGE_FACES_INCREMENT); + } + + if (!aFaceExists) + { + aFacesArray.Append(aFace); + } + } + } + + // Get connected groups of faces using existing connectivity data + NCollection_List aConnectedGroups = + GetConnectedFaceGroups(aFaceEdges, aEdgeFaces); + + // Process only the largest connected group for shell construction + if (aConnectedGroups.IsEmpty()) { - TopTools_MapOfShape dtemp, rtemp; - Standard_Integer nbbe = 0, nbe = 0; - TopoDS_Face F1 = TopoDS::Face(Lface.Value(i)); - for (TopExp_Explorer expe(F1, TopAbs_EDGE); expe.More(); expe.Next()) + return Standard_False; + } + + // Some assumption that each edge can be in two orientations + aNumberOfEdges = static_cast((aNumberOfEdges / 2) + 1); + + EdgeOrientedMap aProcessedEdges; + aProcessedEdges.reserve(aNumberOfEdges); + + TopTools_SequenceOfShape aProcessingFaces = std::move(aConnectedGroups.First()); + + TempProcessedEdges aTempProcessedEdges(static_cast(aNumberOfEdges)); + for (; aFaceIdx <= aProcessingFaces.Length(); aFaceIdx++) + { + aTempProcessedEdges.Clear(); + + Standard_Integer aBadOrientationCount = 0, aGoodOrientationCount = 0; + TopoDS_Face F1 = TopoDS::Face(aProcessingFaces.Value(aFaceIdx)); + // Get edges of the face + const NCollection_Array1& aFaceEdgesArray = aFaceEdges[F1]; + + for (Standard_Integer anEdgeInd = aFaceEdgesArray.Lower(); anEdgeInd <= aFaceEdgesArray.Upper(); + ++anEdgeInd) { - TopoDS_Edge edge = TopoDS::Edge(expe.Current()); + const TopoDS_Edge& edge = aFaceEdgesArray.Value(anEdgeInd); // if multiconnexity mode is equal to Standard_True faces contains // the same multiconnexity edges are not added to one shell. - if (isMultiConnex && aMapMultiConnectEdges.Contains(edge)) + if (anIsMultiConnex && theMapMultiConnectEdges.Contains(edge)) continue; - if ((edge.Orientation() == TopAbs_FORWARD && dire.Contains(edge)) - || (edge.Orientation() == TopAbs_REVERSED && reve.Contains(edge))) - nbbe++; - else if ((edge.Orientation() == TopAbs_FORWARD && reve.Contains(edge)) - || (edge.Orientation() == TopAbs_REVERSED && dire.Contains(edge))) - nbe++; - - if (dire.Contains(edge)) - dire.Remove(edge); - else if (reve.Contains(edge)) - reve.Remove(edge); - else + auto aProcessedEdgeIt = aProcessedEdges.find(edge); + + if (aProcessedEdgeIt == aProcessedEdges.end()) + { + std::pair* aTempProcessedEdgeIt = aTempProcessedEdges.ChangeSeek(edge); + if (!aTempProcessedEdgeIt) + { + std::pair anEdgeOrientationPair{(edge.Orientation() == TopAbs_FORWARD), + (edge.Orientation() == TopAbs_REVERSED)}; + + aTempProcessedEdges.Bind(edge, anEdgeOrientationPair); + } + else + { + aTempProcessedEdgeIt->first = + aTempProcessedEdgeIt->first || (edge.Orientation() == TopAbs_FORWARD); + aTempProcessedEdgeIt->second = + aTempProcessedEdgeIt->second || (edge.Orientation() == TopAbs_REVERSED); + } + continue; + } + + auto& aPair = aProcessedEdgeIt->second; + + const bool isDirect = aPair.first; + const bool isReversed = aPair.second; + + if ((edge.Orientation() == TopAbs_FORWARD && isDirect) + || (edge.Orientation() == TopAbs_REVERSED && isReversed)) + { + aBadOrientationCount++; + } + else if ((edge.Orientation() == TopAbs_FORWARD && isReversed) + || (edge.Orientation() == TopAbs_REVERSED && isDirect)) { - if (edge.Orientation() == TopAbs_FORWARD) - dtemp.Add(edge); - if (edge.Orientation() == TopAbs_REVERSED) - rtemp.Add(edge); + aGoodOrientationCount++; + } + + if (isDirect) + { + aPair.first = false; + } + else if (isReversed) + { + aPair.second = false; + } + + if (!aPair.first && !aPair.second) + { + // if edge is processed in this face it is removed from map of processed edges + aProcessedEdges.erase(aProcessedEdgeIt); } } - if (!nbbe && !nbe && dtemp.IsEmpty() && rtemp.IsEmpty()) + + if (!aBadOrientationCount && !aGoodOrientationCount && aTempProcessedEdges.IsEmpty()) continue; // if face can not be added to shell it added to sequence of error faces. - if (nbe != 0 && nbbe != 0) + if (aGoodOrientationCount != 0 && aBadOrientationCount != 0) { - ErrFaces.Append(F1); - Lface.Remove(i); - j++; + theErrFaces.Append(F1); + aProcessingFaces.Remove(aFaceIdx); + aFacesInShellCount++; continue; } // Addition of face to shell. In the dependance of orientation faces in the shell // added face can be reversed. - if ((nbe != 0 || nbbe != 0) || j == 1) + if ((aGoodOrientationCount != 0 || aBadOrientationCount != 0) || aFacesInShellCount == 1) { - if (nbbe != 0) + if (aBadOrientationCount != 0) { F1.Reverse(); - for (TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next()) - reve.Add(ite.Key()); - for (TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next()) - dire.Add(ite1.Key()); - done = Standard_True; + + for (TempProcessedEdges::Iterator aTempEdgeIter(aTempProcessedEdges); aTempEdgeIter.More(); + aTempEdgeIter.Next()) + { + const TopoDS_Edge& edge = aTempEdgeIter.Key(); + const auto& anEdgeOrientationPair = aTempEdgeIter.Value(); + + std::pair aRevertedPair{!anEdgeOrientationPair.first, + !anEdgeOrientationPair.second}; + + auto aProcessedEdgeIt = aProcessedEdges.find(edge); + if (aProcessedEdgeIt == aProcessedEdges.end()) + { + aProcessedEdges.emplace(edge, aRevertedPair); + } + else + { + auto& aPair = aProcessedEdgeIt->second; + aPair = aRevertedPair; + } + } + aDone = Standard_True; } else { - for (TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next()) - dire.Add(ite.Key()); - for (TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next()) - reve.Add(ite1.Key()); + for (TempProcessedEdges::Iterator aTempEdgeIter(aTempProcessedEdges); aTempEdgeIter.More(); + aTempEdgeIter.Next()) + { + const TopoDS_Edge& edge = aTempEdgeIter.Key(); + const auto& anEdgeOrientationPair = aTempEdgeIter.Value(); + + auto aProcessedEdgeIt = aProcessedEdges.find(edge); + if (aProcessedEdgeIt == aProcessedEdges.end()) + { + aProcessedEdges.emplace(edge, anEdgeOrientationPair); + } + else + { + auto& aPair = aProcessedEdgeIt->second; + aPair.first = anEdgeOrientationPair.first; + aPair.second = anEdgeOrientationPair.second; + } + } } - j++; + aFacesInShellCount++; B.Add(nshell, F1); - aMapFaceShells.Bind(F1, nshell); - Lface.Remove(i); + theMapFaceShells.Bind(F1, nshell); + aProcessingFaces.Remove(aFaceIdx); // check if closed shell is obtained in multi connex mode and add to sequence of // shells and new shell begin to construct. // (check is n*2) - if (isMultiConnex && BRep_Tool::IsClosed(nshell)) + if (anIsMultiConnex && BRep_Tool::IsClosed(nshell)) { nshell.Closed(Standard_True); - aSeqShells.Append(nshell); + theSeqShells.Append(nshell); TopoDS_Shell nshellnext; B.MakeShell(nshellnext); - nshell = nshellnext; - j = 1; + nshell = nshellnext; + aFacesInShellCount = 1; } - i = 0; + aFaceIdx = 0; } // if shell contains of one face. This face is added to sequence of faces. // This shell is removed. - if (Lface.Length() && i == Lface.Length() && j <= 2) + if (aProcessingFaces.Length() && aFaceIdx == aProcessingFaces.Length() + && aFacesInShellCount <= 2) { TopoDS_Iterator aItf(nshell, Standard_False); if (aItf.More()) { aSeqUnconnectFaces.Append(aItf.Value()); - aMapFaceShells.UnBind(aItf.Value()); + theMapFaceShells.UnBind(aItf.Value()); } TopoDS_Shell nshellnext; B.MakeShell(nshellnext); - nshell = nshellnext; - i = 0; - j = 1; + nshell = nshellnext; + aFaceIdx = 0; + aFacesInShellCount = 1; } } Standard_Boolean isContains = Standard_False; - for (Standard_Integer k = 1; k <= aSeqShells.Length() && !isContains; k++) - isContains = nshell.IsSame(aSeqShells.Value(k)); + for (Standard_Integer k = 1; k <= theSeqShells.Length() && !isContains; k++) + isContains = nshell.IsSame(theSeqShells.Value(k)); if (!isContains) { Standard_Integer numFace = 0; @@ -311,25 +609,43 @@ static Standard_Boolean GetShells(TopTools_SequenceOfShape& Lface, if (numFace > 1) { // close all closed shells in no multi connex mode - if (!isMultiConnex) + if (!anIsMultiConnex) nshell.Closed(BRep_Tool::IsClosed(nshell)); - aSeqShells.Append(nshell); + theSeqShells.Append(nshell); } else if (numFace == 1) { - if (aMapFaceShells.IsBound(aFace)) - aMapFaceShells.UnBind(aFace); - Lface.Append(aFace); + if (theMapFaceShells.IsBound(aFace)) + theMapFaceShells.UnBind(aFace); + aProcessingFaces.Append(aFace); } } - // Sequence of faces Lface contains faces which can not be added to obtained shells. + // Add all unprocessed connected groups (second group and after) to unconnected faces + Standard_Integer aGroupIndex = 1; + for (NCollection_List::Iterator aGroupIter(aConnectedGroups); + aGroupIter.More(); + aGroupIter.Next(), ++aGroupIndex) + { + if (aGroupIndex == 1) + continue; // Skip first group (already processed) + + const TopTools_SequenceOfShape& aUnprocessedGroup = aGroupIter.Value(); + for (Standard_Integer aFaceIdx = 1; aFaceIdx <= aUnprocessedGroup.Length(); ++aFaceIdx) + { + aSeqUnconnectFaces.Append(aUnprocessedGroup.Value(aFaceIdx)); + } + } + + theLfaces = std::move(aProcessingFaces); + + // Add unconnected faces from the largest group that couldn't be added to shells for (Standard_Integer j1 = 1; j1 <= aSeqUnconnectFaces.Length(); j1++) { - Lface.Append(aSeqUnconnectFaces); + theLfaces.Append(aSeqUnconnectFaces.Value(j1)); } - return done; + return aDone; } //======================================================================= From 481ea96dcd8658ac214a30ffcf5c505d64e2ff04 Mon Sep 17 00:00:00 2001 From: Pasukhin Dmitry Date: Tue, 21 Oct 2025 11:14:33 +0100 Subject: [PATCH 13/17] Shape Healing - Regression after #584 (#753) Fixed issue with unstable shape order after fixing. Fixed reference data which was changed --- src/ShapeFix/ShapeFix_Shell.cxx | 57 ++++++++++----------------------- tests/bugs/mesh/bug25044_59 | 2 +- tests/bugs/mesh/bug25044_60 | 2 +- tests/bugs/mesh/bug25628 | 2 +- tests/de/step_2/S1 | 5 +-- tests/heal/wire_tails_real/A5 | 2 +- 6 files changed, 24 insertions(+), 46 deletions(-) diff --git a/src/ShapeFix/ShapeFix_Shell.cxx b/src/ShapeFix/ShapeFix_Shell.cxx index ef05ee8131a..5e8357678c8 100644 --- a/src/ShapeFix/ShapeFix_Shell.cxx +++ b/src/ShapeFix/ShapeFix_Shell.cxx @@ -62,13 +62,7 @@ IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Shell, ShapeFix_Root) namespace { // Type aliases for unordered maps with custom allocators -using FaceEdgesAllocator = - NCollection_Allocator>>; -using FaceEdgesMap = std::unordered_map, - TopTools_ShapeMapHasher, - TopTools_ShapeMapHasher, - FaceEdgesAllocator>; +using FaceEdgesMap = NCollection_IndexedDataMap>; using EdgeFacesAllocator = NCollection_Allocator>>; using EdgeFacesMap = std::unordered_map GetConnectedFaceGroups( { NCollection_List aConnectedGroups; - if (theFaceEdges.empty()) + if (theFaceEdges.IsEmpty()) { return aConnectedGroups; } - TopTools_MapOfShape aVisitedFaces(static_cast(theFaceEdges.size())); + TopTools_MapOfShape aVisitedFaces(static_cast(theFaceEdges.Size())); for (auto aFaceIter = theFaceEdges.begin(); aFaceIter != theFaceEdges.end(); ++aFaceIter) { - const TopoDS_Face& aStartFace = aFaceIter->first; + const TopoDS_Face& aStartFace = aFaceIter.ChangeIterator().Key(); if (aVisitedFaces.Contains(aStartFace)) { @@ -244,10 +238,10 @@ static NCollection_List GetConnectedFaceGroups( aConnectedGroup.Append(aCurrentFace); // Find connected faces through shared edges - auto aFaceEdgesIter = theFaceEdges.find(aCurrentFace); - if (aFaceEdgesIter != theFaceEdges.end()) + auto aFaceEdgesIter = theFaceEdges.Seek(aCurrentFace); + if (aFaceEdgesIter) { - const NCollection_Array1& aFaceEdgesArray = aFaceEdgesIter->second; + const NCollection_Array1& aFaceEdgesArray = *aFaceEdgesIter; for (Standard_Integer anEdgeIdx = aFaceEdgesArray.Lower(); anEdgeIdx <= aFaceEdgesArray.Upper(); @@ -275,25 +269,7 @@ static NCollection_List GetConnectedFaceGroups( } } - // Insert in sorted order (largest groups first) - Standard_Boolean anIsInserted = Standard_False; - - for (NCollection_List::Iterator anIter(aConnectedGroups); - anIter.More(); - anIter.Next()) - { - if (aConnectedGroup.Length() > anIter.Value().Length()) - { - aConnectedGroups.InsertBefore(aConnectedGroup, anIter); - anIsInserted = Standard_True; - break; - } - } - - if (!anIsInserted) - { - aConnectedGroups.Append(aConnectedGroup); - } + aConnectedGroups.Append(aConnectedGroup); } return aConnectedGroups; @@ -339,7 +315,7 @@ static Standard_Boolean GetShells(TopTools_SequenceOfShape& theLfaces, NCollection_DataMap, TopTools_ShapeMapHasher>; FaceEdgesMap aFaceEdges; - aFaceEdges.reserve(theLfaces.Length()); + aFaceEdges.ReSize(theLfaces.Length()); size_t aNumberOfEdges = 0; NCollection_DynamicArray aTempEdges; for (TopTools_SequenceOfShape::Iterator anFaceIter(theLfaces); anFaceIter.More(); @@ -357,16 +333,16 @@ static Standard_Boolean GetShells(TopTools_SequenceOfShape& theLfaces, { aFaceEdgesArray.SetValue(idx + 1, aTempEdges.Value(idx)); } - aFaceEdges[aFace] = std::move(aFaceEdgesArray); + aFaceEdges.Add(aFace, std::move(aFaceEdgesArray)); } EdgeFacesMap aEdgeFaces; aEdgeFaces.reserve(aNumberOfEdges); - for (const auto& aFaceEdgesPair : aFaceEdges) + for (Standard_Integer aFaceInd = 1; aFaceInd <= aFaceEdges.Size(); ++aFaceInd) { - const TopoDS_Face& aFace = aFaceEdgesPair.first; - const NCollection_Array1& aFaceEdgesArray = aFaceEdgesPair.second; + const TopoDS_Face& aFace = aFaceEdges.FindKey(aFaceInd); + const NCollection_Array1& aFaceEdgesArray = aFaceEdges.FindFromIndex(aFaceInd); for (Standard_Integer anEdgeInd = aFaceEdgesArray.Lower(); anEdgeInd <= aFaceEdgesArray.Upper(); ++anEdgeInd) @@ -425,7 +401,7 @@ static Standard_Boolean GetShells(TopTools_SequenceOfShape& theLfaces, Standard_Integer aBadOrientationCount = 0, aGoodOrientationCount = 0; TopoDS_Face F1 = TopoDS::Face(aProcessingFaces.Value(aFaceIdx)); // Get edges of the face - const NCollection_Array1& aFaceEdgesArray = aFaceEdges[F1]; + const NCollection_Array1& aFaceEdgesArray = aFaceEdges.FindFromKey(F1); for (Standard_Integer anEdgeInd = aFaceEdgesArray.Lower(); anEdgeInd <= aFaceEdgesArray.Upper(); ++anEdgeInd) @@ -631,9 +607,10 @@ static Standard_Boolean GetShells(TopTools_SequenceOfShape& theLfaces, continue; // Skip first group (already processed) const TopTools_SequenceOfShape& aUnprocessedGroup = aGroupIter.Value(); - for (Standard_Integer aFaceIdx = 1; aFaceIdx <= aUnprocessedGroup.Length(); ++aFaceIdx) + for (Standard_Integer anUnprocFaceIdx = 1; anUnprocFaceIdx <= aUnprocessedGroup.Length(); + ++anUnprocFaceIdx) { - aSeqUnconnectFaces.Append(aUnprocessedGroup.Value(aFaceIdx)); + aSeqUnconnectFaces.Append(aUnprocessedGroup.Value(anUnprocFaceIdx)); } } diff --git a/tests/bugs/mesh/bug25044_59 b/tests/bugs/mesh/bug25044_59 index c7a258093a8..a682378001b 100644 --- a/tests/bugs/mesh/bug25044_59 +++ b/tests/bugs/mesh/bug25044_59 @@ -1,4 +1,4 @@ -puts "TODO 25044 ALL: Not connected mesh inside face 147" +puts "TODO 25044 ALL: Not connected mesh inside face 137" puts "=======" puts "0025588: BRepMesh_ShapeTool::FindUV check for 2d points to be the same is inconsistent with ShapeAnalysis_Wire::CheckLacking" diff --git a/tests/bugs/mesh/bug25044_60 b/tests/bugs/mesh/bug25044_60 index 6c892505875..9fabc51021d 100644 --- a/tests/bugs/mesh/bug25044_60 +++ b/tests/bugs/mesh/bug25044_60 @@ -4,7 +4,7 @@ puts "=======" puts "" puts "TODO OCC25588 All: Not connected mesh inside face 893" -puts "TODO OCC25588 All: Not connected mesh inside face 1094" +puts "TODO OCC25588 All: Not connected mesh inside face 1097" pload XDE diff --git a/tests/bugs/mesh/bug25628 b/tests/bugs/mesh/bug25628 index 2dac4f54b19..90e3d561111 100644 --- a/tests/bugs/mesh/bug25628 +++ b/tests/bugs/mesh/bug25628 @@ -20,7 +20,7 @@ if { [llength $log] != 0 } { puts "Mesh is OK" } -checktrinfo a_36 -tri 37 -nod 39 +checktrinfo a_36 -tri 4551 -nod 2302 vinit vdisplay a_36 diff --git a/tests/de/step_2/S1 b/tests/de/step_2/S1 index 0e45c77abe1..dd4aa60f85d 100755 --- a/tests/de/step_2/S1 +++ b/tests/de/step_2/S1 @@ -1,6 +1,7 @@ # !!!! This file is generated automatically, do not edit manually! See end script puts "TODO CR23096 ALL: TPSTAT : Faulty" puts "TODO CR23096 ALL: TOLERANCE : Faulty" +puts "TODO CR23096 ALL: CHECKSHAPE : Faulty" set filename trj12_ttmouse-pe-214.stp @@ -8,10 +9,10 @@ set filename trj12_ttmouse-pe-214.stp set ref_data { DATA : Faulties = 0 ( 0 ) Warnings = 0 ( 0 ) Summary = 0 ( 0 ) TPSTAT : Faulties = 0 ( 0 ) Warnings = 40 ( 18 ) Summary = 40 ( 18 ) -CHECKSHAPE : Wires = 48 ( 48 ) Faces = 48 ( 48 ) Shells = 0 ( 0 ) Solids = 0 ( 0 ) +CHECKSHAPE : Wires = 48 ( 48 ) Faces = 40 ( 48 ) Shells = 8 ( 0 ) Solids = 8 ( 0 ) NBSHAPES : Solid = 15 ( 16 ) Shell = 17 ( 17 ) Face = 366 ( 366 ) STATSHAPE : Solid = 71 ( 79 ) Shell = 87 ( 87 ) Face = 2732 ( 2732 ) FreeWire = 0 ( 0 ) -TOLERANCE : MaxTol = 116.4921053 ( 5.033069571 ) AvgTol = 0.562451842 ( 0.06578172668 ) +TOLERANCE : MaxTol = 116.4921053 ( 5.033069571 ) AvgTol = 1.066335101 ( 0.06578172668 ) LABELS : N0Labels = 10 ( 10 ) N1Labels = 32 ( 32 ) N2Labels = 0 ( 0 ) TotalLabels = 42 ( 42 ) NameLabels = 22 ( 22 ) ColorLabels = 22 ( 22 ) LayerLabels = 0 ( 0 ) PROPS : Centroid = 0 ( 0 ) Volume = 0 ( 0 ) Area = 0 ( 0 ) NCOLORS : NColors = 6 ( 6 ) diff --git a/tests/heal/wire_tails_real/A5 b/tests/heal/wire_tails_real/A5 index 8cbda82dc60..54ac8da2c62 100644 --- a/tests/heal/wire_tails_real/A5 +++ b/tests/heal/wire_tails_real/A5 @@ -4,5 +4,5 @@ stepread [locate_data_file bug26261_ca07771-040x.stp] s * renamevar s_1 s fixshape r s -maxtaila 1 -maxtailw 1e-3 -checknbshapes r -vertex 25952 -edge 42001 -wire 16519 -face 16205 -shell 51 -solid 1 -compsolid 0 -compound 2 +checknbshapes r -vertex 25951 -edge 42000 -wire 16519 -face 16205 -shell 51 -solid 1 -compsolid 0 -compound 2 checkprops r -l 127197.46264592493 From 855c15b23bff0d61104b21a709e8ff7a019ce592 Mon Sep 17 00:00:00 2001 From: Pasukhin Dmitry Date: Mon, 27 Oct 2025 21:27:16 +0000 Subject: [PATCH 14/17] Shape Healing - Regression after #584 (#769) Second iteration of fixing regressions. Fixed issue with loops and incorrect shell created. #584 affected some tests which were not updated on time. Now all test cases are passed. --- src/ShapeFix/ShapeFix_Shell.cxx | 20 +++++++++++++++++++- tests/de/step_1/ZK4 | 4 ++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/ShapeFix/ShapeFix_Shell.cxx b/src/ShapeFix/ShapeFix_Shell.cxx index 5e8357678c8..6f7fc208d2d 100644 --- a/src/ShapeFix/ShapeFix_Shell.cxx +++ b/src/ShapeFix/ShapeFix_Shell.cxx @@ -269,7 +269,25 @@ static NCollection_List GetConnectedFaceGroups( } } - aConnectedGroups.Append(aConnectedGroup); + // Insert in sorted order (largest groups first) + Standard_Boolean anIsInserted = Standard_False; + + for (NCollection_List::Iterator anIter(aConnectedGroups); + anIter.More(); + anIter.Next()) + { + if (aConnectedGroup.Length() > anIter.Value().Length()) + { + aConnectedGroups.InsertBefore(aConnectedGroup, anIter); + anIsInserted = Standard_True; + break; + } + } + + if (!anIsInserted) + { + aConnectedGroups.Append(aConnectedGroup); + } } return aConnectedGroups; diff --git a/tests/de/step_1/ZK4 b/tests/de/step_1/ZK4 index 71822db15cb..9062ddfc1f9 100644 --- a/tests/de/step_1/ZK4 +++ b/tests/de/step_1/ZK4 @@ -5,8 +5,8 @@ set ref_data { DATA : Faulties = 0 ( 0 ) Warnings = 0 ( 0 ) Summary = 0 ( 0 ) TPSTAT : Faulties = 0 ( 0 ) Warnings = 0 ( 1 ) Summary = 0 ( 1 ) CHECKSHAPE : Wires = 0 ( 0 ) Faces = 0 ( 0 ) Shells = 0 ( 0 ) Solids = 0 ( 0 ) -NBSHAPES : Solid = 0 ( 0 ) Shell = 4 ( 4 ) Face = 13 ( 13 ) -STATSHAPE : Solid = 0 ( 0 ) Shell = 4 ( 4 ) Face = 13 ( 13 ) FreeWire = 0 ( 0 ) +NBSHAPES : Solid = 0 ( 0 ) Shell = 12 ( 12 ) Face = 13 ( 13 ) +STATSHAPE : Solid = 0 ( 0 ) Shell = 12 ( 12 ) Face = 13 ( 13 ) FreeWire = 0 ( 0 ) TOLERANCE : MaxTol = 0.004158901543 ( 0.004158901545 ) AvgTol = 0.001029524988 ( 0.001123851801 ) LABELS : N0Labels = 1 ( 1 ) N1Labels = 0 ( 0 ) N2Labels = 0 ( 0 ) TotalLabels = 1 ( 1 ) NameLabels = 1 ( 1 ) ColorLabels = 0 ( 0 ) LayerLabels = 0 ( 0 ) PROPS : Centroid = 0 ( 0 ) Volume = 0 ( 0 ) Area = 0 ( 0 ) From bba56332396ad25dd97013f1b05ce2d1e1cbc173 Mon Sep 17 00:00:00 2001 From: dpasukhi Date: Fri, 5 Dec 2025 23:08:25 +0000 Subject: [PATCH 15/17] Coding - Bump version to 7.9.3 --- adm/cmake/version.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adm/cmake/version.cmake b/adm/cmake/version.cmake index 13114d854fb..32d7b3d208d 100644 --- a/adm/cmake/version.cmake +++ b/adm/cmake/version.cmake @@ -18,4 +18,4 @@ set (OCC_VERSION_MAJOR 7 ) set (OCC_VERSION_MINOR 9 ) -set (OCC_VERSION_MAINTENANCE 2 ) +set (OCC_VERSION_MAINTENANCE 3 ) From 9ea6beb120893048b45b38146e0940dc1ea7c7cb Mon Sep 17 00:00:00 2001 From: dpasukhi Date: Sat, 25 Oct 2025 20:58:19 +0100 Subject: [PATCH 16/17] Testing - Add build-windows-packages workflow Add .github/workflows/build-windows-packages.yml to build and package OCCT on Windows. Workflow downloads 3rd-party archives, builds Release/Debug variants with and without PCH, applies GitHub attestation to DLLs, and uploads individual and combined artifacts. --- .github/workflows/build-windows-packages.yml | 321 +++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 .github/workflows/build-windows-packages.yml diff --git a/.github/workflows/build-windows-packages.yml b/.github/workflows/build-windows-packages.yml new file mode 100644 index 00000000000..5efe5b54bbc --- /dev/null +++ b/.github/workflows/build-windows-packages.yml @@ -0,0 +1,321 @@ +# This workflow builds OCCT Windows packages using prepared 3rd-party archives. +# It creates various package configurations (Release/Debug, with/without PCH) and signs DLLs. +# The workflow is designed to build each package variant on separate machines for optimal isolation. + +name: Build Windows Packages + +on: + pull_request: + branches: + - '**' + push: + branches: + - 'master' + +permissions: + contents: read + id-token: write + attestations: write + +env: + OCCT_VERSION: '7.9.2' + THIRDPARTY_URL: 'https://github.com/Open-Cascade-SAS/OCCT/releases/download/V7_9_0_beta1/3rdparty-vc14-64.zip' + +jobs: + # Build 3rd-party package + package-thirdparty: + name: Package 3rd-party VC++ 2022 64-bit + runs-on: windows-2022 + + steps: + - name: Download 3rd-party dependencies + run: | + Invoke-WebRequest -Uri $env:THIRDPARTY_URL -OutFile 3rdparty-vc14-64.zip + shell: pwsh + + - name: Upload 3rd-party package + uses: actions/upload-artifact@v4.4.3 + with: + name: 3rdparty-vc14-64 + path: 3rdparty-vc14-64.zip + retention-days: 30 + + # Build OCCT without PCH (Release + Debug) + build-no-pch: + name: Build OCCT without PCH (Release + Debug) + runs-on: windows-2022 + + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.1 + + - name: Download and extract 3rd-party dependencies + run: | + Invoke-WebRequest -Uri $env:THIRDPARTY_URL -OutFile 3rdparty-vc14-64.zip + Expand-Archive -Path 3rdparty-vc14-64.zip -DestinationPath . + Remove-Item 3rdparty-vc14-64.zip + shell: pwsh + + - name: Configure OCCT + run: | + mkdir build + cd build + cmake -T host=x64 ` + -D BUILD_USE_PCH=OFF ` + -D BUILD_GTEST=OFF ` + -D BUILD_Inspector=ON ` + -D BUILD_INCLUDE_SYMLINK=ON ` + -D BUILD_CPP_STANDARD=C++17 ` + -D USE_DRACO=ON ` + -D USE_FREETYPE=ON ` + -D USE_RAPIDJSON=ON ` + -D USE_MMGR_TYPE=JEMALLOC ` + -D USE_TBB=ON ` + -D USE_VTK=ON ` + -D USE_TK=ON ` + -D USE_OPENVR=ON ` + -D USE_OPENGL=ON ` + -D USE_GLES2=ON ` + -D USE_FREEIMAGE=ON ` + -D USE_FFMPEG=ON ` + -D USE_D3D=ON ` + -D BUILD_OPT_PROFILE=Production ` + -D BUILD_MODULE_Draw=ON ` + -D BUILD_MODULE_ApplicationFramework=ON ` + -D BUILD_MODULE_DataExchange=ON ` + -D BUILD_MODULE_FoundationClasses=ON ` + -D BUILD_MODULE_ModelingAlgorithms=ON ` + -D BUILD_MODULE_ModelingData=ON ` + -D BUILD_MODULE_Visualization=ON ` + -D 3RDPARTY_DIR=${{ github.workspace }}/3rdparty-vc14-64 ` + -D INSTALL_DIR=${{ github.workspace }}/occt-vc14-64 .. + shell: pwsh + + - name: Build and Install OCCT Release + run: | + cd build + cmake --build . --target install --config Release + shell: pwsh + + - name: Fix env.bat THIRDPARTY_DIR path + run: | + $envBatPath = "${{ github.workspace }}/occt-vc14-64/env.bat" + if (Test-Path $envBatPath) { + $content = Get-Content $envBatPath -Raw + $content = $content -replace 'THIRDPARTY_DIR=.*3rdparty-vc14-64"', 'THIRDPARTY_DIR=..\3rdparty-vc14-64"' + Set-Content -Path $envBatPath -Value $content -NoNewline + Write-Host "Updated env.bat with relative THIRDPARTY_DIR path" + } + shell: pwsh + + - name: Sign Release DLLs with GitHub attestation + uses: actions/attest-build-provenance@v1 + with: + subject-path: '${{ github.workspace }}/occt-vc14-64/**/*.dll' + + - name: Create OCCT Release package + run: | + $version = $env:OCCT_VERSION + $folderName = "opencascade-$version-vc14-64" + Copy-Item occt-vc14-64 $folderName -Recurse + Compress-Archive -Path $folderName -DestinationPath "$folderName.zip" + Remove-Item $folderName -Recurse -Force + shell: pwsh + + - name: Upload OCCT Release package + uses: actions/upload-artifact@v4.4.3 + with: + name: opencascade-release-no-pch + path: opencascade-${{ env.OCCT_VERSION }}-vc14-64.zip + retention-days: 30 + + - name: Create combined package (Release + 3rd-party) + run: | + Compress-Archive -Path 3rdparty-vc14-64,occt-vc14-64 -DestinationPath occt-vc14-64-combined.zip + shell: pwsh + + - name: Upload combined Release package + uses: actions/upload-artifact@v4.4.3 + with: + name: occt-combined-release-no-pch + path: occt-vc14-64-combined.zip + retention-days: 30 + + - name: Build and Install OCCT Debug (keeping Release files) + run: | + cd build + cmake --build . --target install --config Debug + shell: pwsh + + - name: Sign Debug DLLs with GitHub attestation + uses: actions/attest-build-provenance@v1 + with: + subject-path: '${{ github.workspace }}/occt-vc14-64/**/*.dll' + + - name: Create OCCT Release+Debug package + run: | + $version = $env:OCCT_VERSION + $folderName = "opencascade-$version-vc14-64" + Copy-Item occt-vc14-64 $folderName -Recurse + Compress-Archive -Path $folderName -DestinationPath "opencascade-$version-vc14-64-with-debug.zip" + Remove-Item $folderName -Recurse -Force + shell: pwsh + + - name: Upload OCCT Release+Debug package + uses: actions/upload-artifact@v4.4.3 + with: + name: opencascade-with-debug-no-pch + path: opencascade-${{ env.OCCT_VERSION }}-vc14-64-with-debug.zip + retention-days: 30 + + - name: Create combined package (Release+Debug + 3rd-party) + run: | + Compress-Archive -Path 3rdparty-vc14-64,occt-vc14-64 -DestinationPath occt-vc14-64-combined.zip -Force + shell: pwsh + + - name: Upload combined Release+Debug package + uses: actions/upload-artifact@v4.4.3 + with: + name: occt-combined-with-debug-no-pch + path: occt-vc14-64-combined.zip + retention-days: 30 + + # Build OCCT with PCH (Release + Debug) + build-pch: + name: Build OCCT with PCH (Release + Debug) + runs-on: windows-2022 + + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.1 + + - name: Download and extract 3rd-party dependencies + run: | + Invoke-WebRequest -Uri $env:THIRDPARTY_URL -OutFile 3rdparty-vc14-64.zip + Expand-Archive -Path 3rdparty-vc14-64.zip -DestinationPath . + Remove-Item 3rdparty-vc14-64.zip + shell: pwsh + + - name: Configure OCCT + run: | + mkdir build + cd build + cmake -T host=x64 ` + -D BUILD_USE_PCH=ON ` + -D BUILD_GTEST=OFF ` + -D BUILD_Inspector=ON ` + -D BUILD_INCLUDE_SYMLINK=ON ` + -D BUILD_CPP_STANDARD=C++17 ` + -D USE_DRACO=ON ` + -D USE_FREETYPE=ON ` + -D USE_RAPIDJSON=ON ` + -D USE_MMGR_TYPE=JEMALLOC ` + -D USE_TBB=ON ` + -D USE_VTK=ON ` + -D USE_TK=ON ` + -D USE_OPENVR=ON ` + -D USE_OPENGL=ON ` + -D USE_GLES2=ON ` + -D USE_FREEIMAGE=ON ` + -D USE_FFMPEG=ON ` + -D USE_D3D=ON ` + -D BUILD_OPT_PROFILE=Production ` + -D BUILD_MODULE_Draw=ON ` + -D BUILD_MODULE_ApplicationFramework=ON ` + -D BUILD_MODULE_DataExchange=ON ` + -D BUILD_MODULE_FoundationClasses=ON ` + -D BUILD_MODULE_ModelingAlgorithms=ON ` + -D BUILD_MODULE_ModelingData=ON ` + -D BUILD_MODULE_Visualization=ON ` + -D 3RDPARTY_DIR=${{ github.workspace }}/3rdparty-vc14-64 ` + -D INSTALL_DIR=${{ github.workspace }}/occt-vc14-64 .. + shell: pwsh + + - name: Build and Install OCCT Release + run: | + cd build + cmake --build . --target install --config Release + shell: pwsh + + - name: Fix env.bat THIRDPARTY_DIR path + run: | + $envBatPath = "${{ github.workspace }}/occt-vc14-64/env.bat" + if (Test-Path $envBatPath) { + $content = Get-Content $envBatPath -Raw + $content = $content -replace 'THIRDPARTY_DIR=.*3rdparty-vc14-64"', 'THIRDPARTY_DIR=..\3rdparty-vc14-64"' + Set-Content -Path $envBatPath -Value $content -NoNewline + Write-Host "Updated env.bat with relative THIRDPARTY_DIR path" + } + shell: pwsh + + - name: Sign Release DLLs with GitHub attestation + uses: actions/attest-build-provenance@v1 + with: + subject-path: '${{ github.workspace }}/occt-vc14-64/**/*.dll' + + - name: Create OCCT Release PCH package + run: | + $version = $env:OCCT_VERSION + $folderName = "opencascade-$version-vc14-64" + Copy-Item occt-vc14-64 $folderName -Recurse + Compress-Archive -Path $folderName -DestinationPath "opencascade-$version-vc14-64-pch.zip" + Remove-Item $folderName -Recurse -Force + shell: pwsh + + - name: Upload OCCT Release PCH package + uses: actions/upload-artifact@v4.4.3 + with: + name: opencascade-release-pch + path: opencascade-${{ env.OCCT_VERSION }}-vc14-64-pch.zip + retention-days: 30 + + - name: Create combined PCH package (Release + 3rd-party) + run: | + Compress-Archive -Path 3rdparty-vc14-64,occt-vc14-64 -DestinationPath occt-vc14-64-combined.zip + shell: pwsh + + - name: Upload combined Release PCH package + uses: actions/upload-artifact@v4.4.3 + with: + name: occt-combined-release-pch + path: occt-vc14-64-combined.zip + retention-days: 30 + + - name: Build and Install OCCT Debug (keeping Release files) + run: | + cd build + cmake --build . --target install --config Debug + shell: pwsh + + - name: Sign Debug DLLs with GitHub attestation + uses: actions/attest-build-provenance@v1 + with: + subject-path: '${{ github.workspace }}/occt-vc14-64/**/*.dll' + + - name: Create OCCT Release+Debug PCH package + run: | + $version = $env:OCCT_VERSION + $folderName = "opencascade-$version-vc14-64" + Copy-Item occt-vc14-64 $folderName -Recurse + Compress-Archive -Path $folderName -DestinationPath "opencascade-$version-vc14-64-pch-with-debug.zip" + Remove-Item $folderName -Recurse -Force + shell: pwsh + + - name: Upload OCCT Release+Debug PCH package + uses: actions/upload-artifact@v4.4.3 + with: + name: opencascade-with-debug-pch + path: opencascade-${{ env.OCCT_VERSION }}-vc14-64-pch-with-debug.zip + retention-days: 30 + + - name: Create combined PCH package (Release+Debug + 3rd-party) + run: | + Compress-Archive -Path 3rdparty-vc14-64,occt-vc14-64 -DestinationPath occt-vc14-64-combined.zip -Force + shell: pwsh + + - name: Upload combined Release+Debug PCH package + uses: actions/upload-artifact@v4.4.3 + with: + name: occt-combined-with-debug-pch + path: occt-vc14-64-combined.zip + retention-days: 30 From a016080bf6738d6aeae020badee4e888ad1540a5 Mon Sep 17 00:00:00 2001 From: dpasukhi Date: Fri, 5 Dec 2025 23:13:07 +0000 Subject: [PATCH 17/17] Testing - Update build-windows-packages workflow for OCCT version 7.9.3 - Bump OCCT version from 7.9.2 to 7.9.3. - Refactor file handling in the workflow to use Rename-Item instead of Copy-Item for better clarity and efficiency. - Update artifact paths to include the new version in the filenames. - Fix env.bat THIRDPARTY_DIR path for Debug builds to use a relative path. --- .github/workflows/build-windows-packages.yml | 96 ++++++++++++-------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/.github/workflows/build-windows-packages.yml b/.github/workflows/build-windows-packages.yml index 5efe5b54bbc..71f69a8ae25 100644 --- a/.github/workflows/build-windows-packages.yml +++ b/.github/workflows/build-windows-packages.yml @@ -1,5 +1,5 @@ # This workflow builds OCCT Windows packages using prepared 3rd-party archives. -# It creates various package configurations (Release/Debug, with/without PCH) and signs DLLs. +# It creates various package configurations (Release/Debug, with/without PCH). # The workflow is designed to build each package variant on separate machines for optimal isolation. name: Build Windows Packages @@ -14,11 +14,9 @@ on: permissions: contents: read - id-token: write - attestations: write env: - OCCT_VERSION: '7.9.2' + OCCT_VERSION: '7.9.3' THIRDPARTY_URL: 'https://github.com/Open-Cascade-SAS/OCCT/releases/download/V7_9_0_beta1/3rdparty-vc14-64.zip' jobs: @@ -108,18 +106,13 @@ jobs: } shell: pwsh - - name: Sign Release DLLs with GitHub attestation - uses: actions/attest-build-provenance@v1 - with: - subject-path: '${{ github.workspace }}/occt-vc14-64/**/*.dll' - - name: Create OCCT Release package run: | $version = $env:OCCT_VERSION $folderName = "opencascade-$version-vc14-64" - Copy-Item occt-vc14-64 $folderName -Recurse + Rename-Item occt-vc14-64 $folderName Compress-Archive -Path $folderName -DestinationPath "$folderName.zip" - Remove-Item $folderName -Recurse -Force + Rename-Item $folderName occt-vc14-64 shell: pwsh - name: Upload OCCT Release package @@ -131,14 +124,19 @@ jobs: - name: Create combined package (Release + 3rd-party) run: | - Compress-Archive -Path 3rdparty-vc14-64,occt-vc14-64 -DestinationPath occt-vc14-64-combined.zip + $version = $env:OCCT_VERSION + $folderName = "opencascade-$version-vc14-64" + $thirdpartyName = "3rdparty-vc14-64" + Rename-Item occt-vc14-64 $folderName + Compress-Archive -Path $thirdpartyName,$folderName -DestinationPath "$folderName-combined.zip" + Rename-Item $folderName occt-vc14-64 shell: pwsh - name: Upload combined Release package uses: actions/upload-artifact@v4.4.3 with: name: occt-combined-release-no-pch - path: occt-vc14-64-combined.zip + path: opencascade-${{ env.OCCT_VERSION }}-vc14-64-combined.zip retention-days: 30 - name: Build and Install OCCT Debug (keeping Release files) @@ -147,18 +145,24 @@ jobs: cmake --build . --target install --config Debug shell: pwsh - - name: Sign Debug DLLs with GitHub attestation - uses: actions/attest-build-provenance@v1 - with: - subject-path: '${{ github.workspace }}/occt-vc14-64/**/*.dll' + - name: Fix env.bat THIRDPARTY_DIR path for Debug + run: | + $envBatPath = "${{ github.workspace }}/occt-vc14-64/env.bat" + if (Test-Path $envBatPath) { + $content = Get-Content $envBatPath -Raw + $content = $content -replace 'THIRDPARTY_DIR=.*3rdparty-vc14-64"', 'THIRDPARTY_DIR=..\3rdparty-vc14-64"' + Set-Content -Path $envBatPath -Value $content -NoNewline + Write-Host "Updated env.bat with relative THIRDPARTY_DIR path" + } + shell: pwsh - name: Create OCCT Release+Debug package run: | $version = $env:OCCT_VERSION $folderName = "opencascade-$version-vc14-64" - Copy-Item occt-vc14-64 $folderName -Recurse + Rename-Item occt-vc14-64 $folderName Compress-Archive -Path $folderName -DestinationPath "opencascade-$version-vc14-64-with-debug.zip" - Remove-Item $folderName -Recurse -Force + Rename-Item $folderName occt-vc14-64 shell: pwsh - name: Upload OCCT Release+Debug package @@ -170,14 +174,19 @@ jobs: - name: Create combined package (Release+Debug + 3rd-party) run: | - Compress-Archive -Path 3rdparty-vc14-64,occt-vc14-64 -DestinationPath occt-vc14-64-combined.zip -Force + $version = $env:OCCT_VERSION + $folderName = "opencascade-$version-vc14-64" + $thirdpartyName = "3rdparty-vc14-64" + Rename-Item occt-vc14-64 $folderName + Compress-Archive -Path $thirdpartyName,$folderName -DestinationPath "$folderName-with-debug-combined.zip" + Rename-Item $folderName occt-vc14-64 shell: pwsh - name: Upload combined Release+Debug package uses: actions/upload-artifact@v4.4.3 with: name: occt-combined-with-debug-no-pch - path: occt-vc14-64-combined.zip + path: opencascade-${{ env.OCCT_VERSION }}-vc14-64-with-debug-combined.zip retention-days: 30 # Build OCCT with PCH (Release + Debug) @@ -248,18 +257,13 @@ jobs: } shell: pwsh - - name: Sign Release DLLs with GitHub attestation - uses: actions/attest-build-provenance@v1 - with: - subject-path: '${{ github.workspace }}/occt-vc14-64/**/*.dll' - - name: Create OCCT Release PCH package run: | $version = $env:OCCT_VERSION $folderName = "opencascade-$version-vc14-64" - Copy-Item occt-vc14-64 $folderName -Recurse + Rename-Item occt-vc14-64 $folderName Compress-Archive -Path $folderName -DestinationPath "opencascade-$version-vc14-64-pch.zip" - Remove-Item $folderName -Recurse -Force + Rename-Item $folderName occt-vc14-64 shell: pwsh - name: Upload OCCT Release PCH package @@ -271,14 +275,19 @@ jobs: - name: Create combined PCH package (Release + 3rd-party) run: | - Compress-Archive -Path 3rdparty-vc14-64,occt-vc14-64 -DestinationPath occt-vc14-64-combined.zip + $version = $env:OCCT_VERSION + $folderName = "opencascade-$version-vc14-64" + $thirdpartyName = "3rdparty-vc14-64" + Rename-Item occt-vc14-64 $folderName + Compress-Archive -Path $thirdpartyName,$folderName -DestinationPath "$folderName-pch-combined.zip" + Rename-Item $folderName occt-vc14-64 shell: pwsh - name: Upload combined Release PCH package uses: actions/upload-artifact@v4.4.3 with: name: occt-combined-release-pch - path: occt-vc14-64-combined.zip + path: opencascade-${{ env.OCCT_VERSION }}-vc14-64-pch-combined.zip retention-days: 30 - name: Build and Install OCCT Debug (keeping Release files) @@ -287,18 +296,24 @@ jobs: cmake --build . --target install --config Debug shell: pwsh - - name: Sign Debug DLLs with GitHub attestation - uses: actions/attest-build-provenance@v1 - with: - subject-path: '${{ github.workspace }}/occt-vc14-64/**/*.dll' + - name: Fix env.bat THIRDPARTY_DIR path for Debug + run: | + $envBatPath = "${{ github.workspace }}/occt-vc14-64/env.bat" + if (Test-Path $envBatPath) { + $content = Get-Content $envBatPath -Raw + $content = $content -replace 'THIRDPARTY_DIR=.*3rdparty-vc14-64"', 'THIRDPARTY_DIR=..\3rdparty-vc14-64"' + Set-Content -Path $envBatPath -Value $content -NoNewline + Write-Host "Updated env.bat with relative THIRDPARTY_DIR path" + } + shell: pwsh - name: Create OCCT Release+Debug PCH package run: | $version = $env:OCCT_VERSION $folderName = "opencascade-$version-vc14-64" - Copy-Item occt-vc14-64 $folderName -Recurse + Rename-Item occt-vc14-64 $folderName Compress-Archive -Path $folderName -DestinationPath "opencascade-$version-vc14-64-pch-with-debug.zip" - Remove-Item $folderName -Recurse -Force + Rename-Item $folderName occt-vc14-64 shell: pwsh - name: Upload OCCT Release+Debug PCH package @@ -310,12 +325,17 @@ jobs: - name: Create combined PCH package (Release+Debug + 3rd-party) run: | - Compress-Archive -Path 3rdparty-vc14-64,occt-vc14-64 -DestinationPath occt-vc14-64-combined.zip -Force + $version = $env:OCCT_VERSION + $folderName = "opencascade-$version-vc14-64" + $thirdpartyName = "3rdparty-vc14-64" + Rename-Item occt-vc14-64 $folderName + Compress-Archive -Path $thirdpartyName,$folderName -DestinationPath "$folderName-pch-with-debug-combined.zip" + Rename-Item $folderName occt-vc14-64 shell: pwsh - name: Upload combined Release+Debug PCH package uses: actions/upload-artifact@v4.4.3 with: name: occt-combined-with-debug-pch - path: occt-vc14-64-combined.zip + path: opencascade-${{ env.OCCT_VERSION }}-vc14-64-pch-with-debug-combined.zip retention-days: 30