From ff24d699673cc0c35d2c6cd2b01263540f1e1dc1 Mon Sep 17 00:00:00 2001 From: gsdali <51393997+gsdali@users.noreply.github.com> Date: Tue, 28 Jul 2026 04:32:39 +1000 Subject: [PATCH] Modeling Algorithms - use the adaptor's NbPoles() in BRepGProp_EdgeTool::IntegrationOrder (#1382) Use BRepAdaptor_Curve::NbPoles() when selecting the integration order for Bezier and BSpline curves. This keeps the pole count consistent with the curve representation reported by GetType() and avoids dereferencing a null 3D curve for edges represented only by a curve on surface. --- .../BRepGProp/BRepGProp_EdgeTool.cxx | 16 ++---- .../TKTopAlgo/GTests/BRepGProp_Test.cxx | 53 +++++++++++++++++++ 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/ModelingAlgorithms/TKTopAlgo/BRepGProp/BRepGProp_EdgeTool.cxx b/src/ModelingAlgorithms/TKTopAlgo/BRepGProp/BRepGProp_EdgeTool.cxx index b75902b195..c20d1f7ff9 100644 --- a/src/ModelingAlgorithms/TKTopAlgo/BRepGProp/BRepGProp_EdgeTool.cxx +++ b/src/ModelingAlgorithms/TKTopAlgo/BRepGProp/BRepGProp_EdgeTool.cxx @@ -42,19 +42,11 @@ int BRepGProp_EdgeTool::IntegrationOrder(const BRepAdaptor_Curve& BAC) case GeomAbs_Parabola: return 5; - case GeomAbs_BezierCurve: { - const GeomAdaptor_Curve& GAC = BAC.Curve(); - const occ::handle& GC = GAC.Curve(); - occ::handle GBZC(occ::down_cast(GC)); - int n = 2 * (GBZC->NbPoles()) - 1; - return n; - } - break; + case GeomAbs_BezierCurve: case GeomAbs_BSplineCurve: { - const GeomAdaptor_Curve& GAC = BAC.Curve(); - const occ::handle& GC = GAC.Curve(); - occ::handle GBSC(occ::down_cast(GC)); - int n = 2 * (GBSC->NbPoles()) - 1; + // Use the adaptor's own NbPoles(), which handles the curve-on-surface case; + // Curve() is null there and down-casting it segfaults. + int n = 2 * BAC.NbPoles() - 1; return n; } break; diff --git a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx index bbe175b7d9..189b286dd9 100644 --- a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx +++ b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx @@ -17,16 +17,21 @@ #include #include #include +#include #include +#include #include +#include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -34,6 +39,8 @@ #include +#include + TEST(BRepGPropTest, LinearProperties_EdgeLength) { gp_Pnt aP1(0.0, 0.0, 0.0); @@ -195,3 +202,49 @@ TEST(BRepGPropTest, OCC8797_BSplineLengthConsistencyAbscissaVsLinearProperties) // Both methods must agree within 0.1 % EXPECT_NEAR(aLengthAbscissa, aLengthGProp, aLengthGProp * 1e-3); } + +// Regression: a degenerate edge whose ONLY representation is a Bezier/BSpline-type +// curve-on-surface pcurve (no 3D curve) used to SIGSEGV inside +// BRepGProp_EdgeTool::IntegrationOrder, which read the pole count via BAC.Curve().Curve() +// (null when there is no 3D curve) instead of the adaptor's own NbPoles(). This is the +// shape BRepBuilderAPI_Sewing produces reconciling near-coincident vertices between two +// faces that do not share an edge outright. +TEST(BRepGPropTest, LinearProperties_DegenerateEdgeWithBSplinePCurveNoCrash) +{ + occ::handle aPlane = new Geom_Plane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + + NCollection_Array1 aPoles(1, 4); + aPoles.SetValue(1, gp_Pnt2d(0.0, 0.0)); + aPoles.SetValue(2, gp_Pnt2d(0.1, 0.05)); + aPoles.SetValue(3, gp_Pnt2d(0.2, -0.05)); + aPoles.SetValue(4, gp_Pnt2d(0.3, 0.0)); + + NCollection_Array1 aKnots(1, 2); + aKnots.SetValue(1, 0.0); + aKnots.SetValue(2, 1.0); + + NCollection_Array1 aMults(1, 2); + aMults.SetValue(1, 4); + aMults.SetValue(2, 4); + + occ::handle aPCurve = new Geom2d_BSplineCurve(aPoles, aKnots, aMults, 3); + + BRep_Builder aBuilder; + TopoDS_Edge anEdge; + aBuilder.MakeEdge(anEdge); + aBuilder.UpdateEdge(anEdge, aPCurve, aPlane, TopLoc_Location(), Precision::Confusion()); + aBuilder.Range(anEdge, + aPlane, + TopLoc_Location(), + aPCurve->FirstParameter(), + aPCurve->LastParameter()); + aBuilder.Degenerated(anEdge, true); + + GProp_GProps aProps; + BRepGProp::LinearProperties(anEdge, aProps); + + // Reaching this point at all is the regression check: IntegrationOrder used to SIGSEGV + // before returning. + EXPECT_TRUE(std::isfinite(aProps.Mass())); + EXPECT_GE(aProps.Mass(), 0.0); +}