Skip to content

Modeling Algorithms - use the adaptor's NbPoles() in BRepGProp_EdgeTool::IntegrationOrder#1382

Open
gsdali wants to merge 3 commits into
Open-Cascade-SAS:masterfrom
gsdali:fix/318-brepgprop-edgetool-nbpoles-curveonsurface
Open

Modeling Algorithms - use the adaptor's NbPoles() in BRepGProp_EdgeTool::IntegrationOrder#1382
gsdali wants to merge 3 commits into
Open-Cascade-SAS:masterfrom
gsdali:fix/318-brepgprop-edgetool-nbpoles-curveonsurface

Conversation

@gsdali

@gsdali gsdali commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Fixes #1381.

Problem

BRepGProp::LinearProperties() (and anything built on BRepGProp_Cinert) SIGSEGVs computing the
integration order for an edge whose only curve geometry is a Bezier- or BSpline-type
curve-on-surface (pcurve) — an edge with no 3D curve, the common case for a degenerate edge
BRepBuilderAPI_Sewing produces reconciling near-coincident vertices between two faces that don't
share an edge outright.

Root cause

IntegrationOrder branches on BAC.GetType(), which correctly reports the curve-on-surface
pcurve's type via GeomAdaptor_TransformedCurve::GetType()'s override:

return myConSurf.IsNull() ? myCurve.GetType() : myConSurf->GetType();

but then read the pole count via a completely different, non-virtual path — BAC.Curve().Curve(),
down-cast to Geom_BezierCurve/Geom_BSplineCurve. BAC.Curve() returns the base
GeomAdaptor_Curve sub-object, which holds the 3D-curve representation only: it is never Load()ed
when the edge has no 3D curve, so the handle is null, the down-cast returns null, and ->NbPoles()
dereferences it.

Fix

GeomAdaptor_TransformedCurve already has a correctly-dispatching NbPoles() override right next
to GetType() in the same header:

int NbPoles() const override
{
  return myConSurf.IsNull() ? myCurve.NbPoles() : myConSurf->NbPoles();
}

Calling BAC.NbPoles() instead of manually re-deriving the pole count from BAC.Curve() fixes the
crash and matches the accessor GetType() one line above it already uses — no cast, no null check
needed, and no behaviour change for an edge that does have a 3D curve (myConSurf.IsNull() there,
so NbPoles() resolves to the same myCurve.NbPoles() the removed code reached by hand).

Reproducer / test

Handle(Geom_Plane) plane = new Geom_Plane(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1));

TColgp_Array1OfPnt2d poles(1, 4);
poles.SetValue(1, gp_Pnt2d(0.0, 0.0));
poles.SetValue(2, gp_Pnt2d(0.1, 0.05));
poles.SetValue(3, gp_Pnt2d(0.2, -0.05));
poles.SetValue(4, gp_Pnt2d(0.3, 0.0));

TColStd_Array1OfReal knots(1, 2);
knots.SetValue(1, 0.0);
knots.SetValue(2, 1.0);

TColStd_Array1OfInteger mults(1, 2);
mults.SetValue(1, 4);
mults.SetValue(2, 4);

Handle(Geom2d_BSplineCurve) pcurve = new Geom2d_BSplineCurve(poles, knots, mults, 3);

BRep_Builder builder;
TopoDS_Edge edge;
builder.MakeEdge(edge);
builder.UpdateEdge(edge, pcurve, plane, TopLoc_Location(), Precision::Confusion());
builder.Range(edge, plane, TopLoc_Location(), pcurve->FirstParameter(), pcurve->LastParameter());
builder.Degenerated(edge, true);

GProp_GProps props;
BRepGProp::LinearProperties(edge, props);  // crashes on master

Added as BRepGPropTest.LinearProperties_DegenerateEdgeWithBSplinePCurveNoCrash in the existing
BRepGProp_Test.cxx.

gsdali added 2 commits July 19, 2026 22:54
…ol::IntegrationOrder

BRepGProp::LinearProperties crashes (uncatchable SIGSEGV) computing the
integration order for a Bezier- or BSpline-type edge that has no 3D curve,
only a curve-on-surface (pcurve) representation with that curve type -- the
common case for a degenerate edge produced by BRepBuilderAPI_Sewing when it
merges near-coincident vertices between two faces that don't share an edge
outright.

Root cause: IntegrationOrder branches on BAC.GetType() (a BRepAdaptor_Curve),
which correctly reports the curve-on-surface pcurve's type via
GeomAdaptor_TransformedCurve::GetType()'s override, but then reads the pole
count via a completely different, non-virtual path: BAC.Curve().Curve(),
down-cast to Geom_BezierCurve/Geom_BSplineCurve. BAC.Curve() returns the base
GeomAdaptor_Curve sub-object, which holds the 3D-curve representation only --
it is never Load()ed when the edge has no 3D curve, so the handle is null,
the down_cast returns null, and ->NbPoles() dereferences it.

GeomAdaptor_TransformedCurve already has a correctly-dispatching NbPoles()
override next to GetType() in the same header. Calling BAC.NbPoles() instead
fixes the crash and matches the accessor GetType() one line above it already
uses -- no cast, no null check needed, and no behaviour change for an edge
that does have a 3D curve.

Reported downstream and isolated at SecondMouseAU/OCCTSwift#318.
… curve-on-surface crash (Open-Cascade-SAS#318)

Regression test for the fix in the previous commit: a degenerate edge whose
sole geometric representation is a Bezier/BSpline-type curve-on-surface
pcurve (no 3D curve) used to SIGSEGV inside IntegrationOrder. Verifies
LinearProperties completes and returns a finite, non-negative length.
…TColStd aliases

TColgp_Array1OfPnt2d.hxx, TColStd_Array1OfInteger.hxx and TColStd_Array1OfReal.hxx
moved to src/Deprecated/NCollectionAliases in OCCT 8.0.0; that toolkit isn't on
TKTopAlgo's GTest include path, so CI failed with a missing-header error on all
platforms. Geom2d_BSplineCurve already takes NCollection_Array1<T> natively.
@dpasukhi
dpasukhi self-requested a review July 22, 2026 14:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

BRepGProp_EdgeTool::IntegrationOrder SIGSEGVs on a degenerate curve-on-surface (Bezier/BSpline) edge

1 participant