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.
This commit is contained in:
gsdali
2026-07-28 04:32:39 +10:00
committed by GitHub
parent 37dd5686f2
commit ff24d69967
2 changed files with 57 additions and 12 deletions
@@ -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<Geom_Curve>& GC = GAC.Curve();
occ::handle<Geom_BezierCurve> GBZC(occ::down_cast<Geom_BezierCurve>(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<Geom_Curve>& GC = GAC.Curve();
occ::handle<Geom_BSplineCurve> GBSC(occ::down_cast<Geom_BSplineCurve>(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;
@@ -17,16 +17,21 @@
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRep_Builder.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_Plane.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
#include <GProp_GProps.hxx>
#include <GProp_PrincipalProps.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <Standard_Handle.hxx>
#include <TopExp_Explorer.hxx>
#include <TopLoc_Location.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
@@ -34,6 +39,8 @@
#include <gtest/gtest.h>
#include <cmath>
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<Geom_Plane> aPlane = new Geom_Plane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0));
NCollection_Array1<gp_Pnt2d> 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<double> aKnots(1, 2);
aKnots.SetValue(1, 0.0);
aKnots.SetValue(2, 1.0);
NCollection_Array1<int> aMults(1, 2);
aMults.SetValue(1, 4);
aMults.SetValue(2, 4);
occ::handle<Geom2d_BSplineCurve> 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);
}