diff --git a/src/ModelingData/TKBRep/BRep/BRep_Tool.cxx b/src/ModelingData/TKBRep/BRep/BRep_Tool.cxx index e512120d6b..bb1b1bfde7 100644 --- a/src/ModelingData/TKBRep/BRep/BRep_Tool.cxx +++ b/src/ModelingData/TKBRep/BRep/BRep_Tool.cxx @@ -65,6 +65,40 @@ // modified by NIZNHY-PKV Fri Oct 17 14:13:29 2008f static bool IsPlane(const occ::handle& 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& 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 aBasisCurve = theCurve; + for (occ::handle aTrim = occ::down_cast(aBasisCurve); + !aTrim.IsNull(); + aTrim = occ::down_cast(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 BRep_Tool::CurveOnPlane(const TopoDS_Edge& l = C3D->TransformedParameter(l, aTrsf); } + if (!isValidTrimRange(C3D, f, l)) + { + return nullPCurve; + } + + occ::handle aTrimmedCurve = new Geom_TrimmedCurve(C3D, f, l, true, false); + // Perform projection occ::handle 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 HS = new GeomAdaptor_Surface(GP); occ::handle HC = new GeomAdaptor_Curve(ProjOnPlane); diff --git a/src/ModelingData/TKBRep/GTests/BRep_Tool_Test.cxx b/src/ModelingData/TKBRep/GTests/BRep_Tool_Test.cxx index 7dcf182330..2b965096e4 100644 --- a/src/ModelingData/TKBRep/GTests/BRep_Tool_Test.cxx +++ b/src/ModelingData/TKBRep/GTests/BRep_Tool_Test.cxx @@ -11,15 +11,20 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. +#include #include #include #include +#include +#include #include #include +#include #include #include #include #include +#include #include #include #include @@ -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 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 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 aPlane = new Geom_Plane(gp::XOY()); + occ::handle 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 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 aPlane = new Geom_Plane(gp::XOY()); + occ::handle 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 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 aPlane = new Geom_Plane(gp::XOY()); + occ::handle 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 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 aPlane = new Geom_Plane(gp::XOY()); + occ::handle 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); +}