Modeling Data - Prevent exception in BRep_Tool::CurveOnPlane (#1402)

Validate the edge range against the effective curve basis before
constructing Geom_TrimmedCurve. Preserve valid periodic ranges and
return a null pcurve for inconsistent bounded ranges.
This commit is contained in:
Pasukhin Dmitry
2026-07-28 12:38:53 +01:00
committed by GitHub
parent 97c092347d
commit 6a7e068773
2 changed files with 145 additions and 4 deletions
+42 -4
View File
@@ -65,6 +65,40 @@
// modified by NIZNHY-PKV Fri Oct 17 14:13:29 2008f
static bool IsPlane(const occ::handle<Geom_Surface>& aS);
namespace
{
//=================================================================================================
//! Checks trim range against the effective basis curve.
//! @param[in] theCurve curve to check
//! @param[in] theFirst first trim parameter
//! @param[in] theLast last trim parameter
//! @return true if the trim range is valid
bool isValidTrimRange(const occ::handle<Geom_Curve>& theCurve,
const double theFirst,
const double theLast)
{
const double aTrimFirst = std::min(theFirst, theLast);
const double aTrimLast = std::max(theFirst, theLast);
if (!(aTrimFirst < aTrimLast))
{
return false;
}
// Unwrap nested trims.
occ::handle<Geom_Curve> aBasisCurve = theCurve;
for (occ::handle<Geom_TrimmedCurve> aTrim = occ::down_cast<Geom_TrimmedCurve>(aBasisCurve);
!aTrim.IsNull();
aTrim = occ::down_cast<Geom_TrimmedCurve>(aBasisCurve))
{
aBasisCurve = aTrim->BasisCurve();
}
return aBasisCurve->IsPeriodic()
|| (aBasisCurve->FirstParameter() - aTrimFirst <= Precision::PConfusion()
&& aTrimLast - aBasisCurve->LastParameter() <= Precision::PConfusion());
}
} // namespace
// modified by NIZNHY-PKV Fri Oct 17 14:13:33 2008t
//
//=================================================================================================
@@ -427,12 +461,16 @@ occ::handle<Geom2d_Curve> BRep_Tool::CurveOnPlane(const TopoDS_Edge&
l = C3D->TransformedParameter(l, aTrsf);
}
if (!isValidTrimRange(C3D, f, l))
{
return nullPCurve;
}
occ::handle<Geom_TrimmedCurve> aTrimmedCurve = new Geom_TrimmedCurve(C3D, f, l, true, false);
// Perform projection
occ::handle<Geom_Curve> ProjOnPlane =
GeomProjLib::ProjectOnPlane(new Geom_TrimmedCurve(C3D, f, l, true, false),
GP,
GP->Position().Direction(),
true);
GeomProjLib::ProjectOnPlane(aTrimmedCurve, GP, GP->Position().Direction(), true);
occ::handle<GeomAdaptor_Surface> HS = new GeomAdaptor_Surface(GP);
occ::handle<GeomAdaptor_Curve> HC = new GeomAdaptor_Curve(ProjOnPlane);
@@ -11,15 +11,20 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom_BezierCurve.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Plane.hxx>
#include <Geom_Surface.hxx>
#include <gp.hxx>
#include <gp_Ax2.hxx>
#include <gp_Pnt.hxx>
#include <NCollection_Array1.hxx>
#include <Precision.hxx>
#include <TopAbs_ShapeEnum.hxx>
#include <TopExp_Explorer.hxx>
@@ -158,3 +163,101 @@ TEST(BRep_Tool_Test, Degenerated)
const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current());
EXPECT_FALSE(BRep_Tool::Degenerated(anEdge)) << "Box edges should not be degenerated";
}
TEST(BRep_Tool_Test, CurveOnPlane_RejectsEdgeRangeOutsideBoundedCurve)
{
NCollection_Array1<gp_Pnt> aPoles(1, 3);
aPoles.SetValue(1, gp_Pnt(0.0, 0.0, 0.0));
aPoles.SetValue(2, gp_Pnt(0.5, 0.25, 0.0));
aPoles.SetValue(3, gp_Pnt(1.0, 0.0, 0.0));
occ::handle<Geom_BezierCurve> aCurve = new Geom_BezierCurve(aPoles);
BRepBuilderAPI_MakeEdge anEdgeMaker(aCurve);
ASSERT_TRUE(anEdgeMaker.IsDone());
const TopoDS_Edge& anEdge = anEdgeMaker.Edge();
constexpr double THE_EDGE_FIRST = -0.000002673149646;
constexpr double THE_EDGE_LAST = 0.999997326850354;
BRep_Builder().Range(anEdge, THE_EDGE_FIRST, THE_EDGE_LAST, true);
occ::handle<Geom_Plane> aPlane = new Geom_Plane(gp::XOY());
occ::handle<Geom2d_Curve> aPCurve;
double aFirst = 0.0;
double aLast = 0.0;
bool isStored = true;
EXPECT_NO_THROW(
aPCurve =
BRep_Tool::CurveOnSurface(anEdge, aPlane, TopLoc_Location(), aFirst, aLast, &isStored));
EXPECT_TRUE(aPCurve.IsNull());
EXPECT_FALSE(isStored);
EXPECT_DOUBLE_EQ(aFirst, THE_EDGE_FIRST);
EXPECT_DOUBLE_EQ(aLast, THE_EDGE_LAST);
}
TEST(BRep_Tool_Test, CurveOnPlane_ProjectsShiftedPeriodicRange)
{
occ::handle<Geom_Circle> aCircle = new Geom_Circle(gp_Ax2(gp::Origin(), gp::DZ()), 1.0);
BRepBuilderAPI_MakeEdge anEdgeMaker(aCircle);
ASSERT_TRUE(anEdgeMaker.IsDone());
const TopoDS_Edge& anEdge = anEdgeMaker.Edge();
const double aRangeFirst = aCircle->Period();
const double aRangeLast = 2.0 * aCircle->Period();
BRep_Builder().Range(anEdge, aRangeFirst, aRangeLast, true);
occ::handle<Geom_Plane> aPlane = new Geom_Plane(gp::XOY());
occ::handle<Geom2d_Curve> aPCurve;
double aFirst = 0.0;
double aLast = 0.0;
EXPECT_NO_THROW(aPCurve =
BRep_Tool::CurveOnPlane(anEdge, aPlane, TopLoc_Location(), aFirst, aLast));
EXPECT_FALSE(aPCurve.IsNull());
EXPECT_DOUBLE_EQ(aFirst, aRangeFirst);
EXPECT_DOUBLE_EQ(aLast, aRangeLast);
}
TEST(BRep_Tool_Test, CurveOnPlane_ProjectsPeriodicEdgeBuiltFromEqualParameters)
{
occ::handle<Geom_Circle> aCircle = new Geom_Circle(gp_Ax2(gp::Origin(), gp::DZ()), 1.0);
BRepBuilderAPI_MakeEdge anEdgeMaker(aCircle, 0.0, 0.0);
ASSERT_TRUE(anEdgeMaker.IsDone());
const TopoDS_Edge& anEdge = anEdgeMaker.Edge();
double aEdgeFirst = 0.0;
double aEdgeLast = 0.0;
BRep_Tool::Range(anEdge, aEdgeFirst, aEdgeLast);
EXPECT_NEAR(aEdgeLast - aEdgeFirst, aCircle->Period(), Precision::PConfusion());
occ::handle<Geom_Plane> aPlane = new Geom_Plane(gp::XOY());
occ::handle<Geom2d_Curve> aPCurve;
double aFirst = 0.0;
double aLast = 0.0;
EXPECT_NO_THROW(aPCurve =
BRep_Tool::CurveOnPlane(anEdge, aPlane, TopLoc_Location(), aFirst, aLast));
EXPECT_FALSE(aPCurve.IsNull());
EXPECT_DOUBLE_EQ(aFirst, aEdgeFirst);
EXPECT_DOUBLE_EQ(aLast, aEdgeLast);
}
TEST(BRep_Tool_Test, CurveOnPlane_RejectsEqualPeriodicRange)
{
occ::handle<Geom_Circle> aCircle = new Geom_Circle(gp_Ax2(gp::Origin(), gp::DZ()), 1.0);
BRepBuilderAPI_MakeEdge anEdgeMaker(aCircle);
ASSERT_TRUE(anEdgeMaker.IsDone());
const TopoDS_Edge& anEdge = anEdgeMaker.Edge();
BRep_Builder().Range(anEdge, 0.0, 0.0, true);
occ::handle<Geom_Plane> aPlane = new Geom_Plane(gp::XOY());
occ::handle<Geom2d_Curve> aPCurve;
double aFirst = 1.0;
double aLast = 1.0;
EXPECT_NO_THROW(aPCurve =
BRep_Tool::CurveOnPlane(anEdge, aPlane, TopLoc_Location(), aFirst, aLast));
EXPECT_TRUE(aPCurve.IsNull());
EXPECT_DOUBLE_EQ(aFirst, 0.0);
EXPECT_DOUBLE_EQ(aLast, 0.0);
}