diff --git a/src/Mod/Part/App/BSplineCurvePyImp.cpp b/src/Mod/Part/App/BSplineCurvePyImp.cpp index 537a054e16..95955c22d9 100644 --- a/src/Mod/Part/App/BSplineCurvePyImp.cpp +++ b/src/Mod/Part/App/BSplineCurvePyImp.cpp @@ -828,8 +828,8 @@ PyObject* BSplineCurvePy::approximate(PyObject *args, PyObject *kwds) else c = GeomAbs_C2; - bool ok = this->getGeomBSplineCurvePtr()->approximate(tol3d, segMax, degMax, c); - return Py_BuildValue("O", (ok ? Py_True : Py_False)); + this->getGeomBSplineCurvePtr()->approximate(tol3d, segMax, degMax, c); + Py_Return; } // Approximate a list of points diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index 95c9c650d4..20519fe1ee 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -65,6 +65,7 @@ # include # include # include +# include # include # include # include @@ -1713,28 +1714,115 @@ void GeomBSplineCurve::increaseDegree(int degree) * \param maxSegments * \param maxDegree * \param continuity - * \return true if the approximation succeeded, false otherwise */ -bool GeomBSplineCurve::approximate(double tol3d, int maxSegments, int maxDegree, int continuity) +void GeomBSplineCurve::approximate(double tol3d, int maxSegments, int maxDegree, + GeomAbs_Shape continuity) { try { - GeomAbs_Shape cont = GeomAbs_C0; - if (continuity >= 0 && continuity <= 6) - cont = static_cast(continuity); - GeomAdaptor_Curve adapt(myCurve); Handle(GeomAdaptor_HCurve) hCurve = new GeomAdaptor_HCurve(adapt); - Approx_Curve3d approx(hCurve, tol3d, cont, maxSegments, maxDegree); - if (approx.IsDone() && approx.HasResult()) { + Approx_Curve3d approx(hCurve, tol3d, continuity, maxSegments, maxDegree); + if (approx.IsDone()) { this->setHandle(approx.Curve()); - return true; + } + else if (approx.HasResult()) { + throw Standard_Failure("Approximation of B-Spline succeeded but is outside of tolerance"); + } + else { + throw Standard_Failure("Approximation of B-Spline failed"); } } catch (Standard_Failure& e) { - THROWM(Base::CADKernelError,e.GetMessageString()) + THROWM(Base::CADKernelError, e.GetMessageString()) } +} - return false; +void GeomBSplineCurve::approximate(const std::vector& pnts, + int minDegree, int maxDegree, + GeomAbs_Shape continuity, double tol3d) +{ + try { + TColgp_Array1OfPnt coords(1, static_cast(pnts.size())); + Standard_Integer index = 1; + for (const auto& it : pnts) { + coords(index++) = gp_Pnt(it.x, it.y, it.z); + } + + GeomAPI_PointsToBSpline fit(coords, minDegree, maxDegree, continuity, tol3d); + const Handle(Geom_BSplineCurve)& spline = fit.Curve(); + if (!spline.IsNull()) { + setHandle(spline); + } + else { + throw Standard_Failure("Failed to approximate B-Spline"); + } + } + catch (Standard_Failure& e) { + THROWM(Base::CADKernelError, e.GetMessageString()) + } +} + +void GeomBSplineCurve::approximate(const std::vector& pnts, + Approx_ParametrizationType parType, + int minDegree, int maxDegree, + GeomAbs_Shape continuity, double tol3d) +{ + try { + TColgp_Array1OfPnt coords(1, static_cast(pnts.size())); + Standard_Integer index = 1; + for (const auto& it : pnts) { + coords(index++) = gp_Pnt(it.x, it.y, it.z); + } + + GeomAPI_PointsToBSpline fit(coords, parType, minDegree, maxDegree, continuity, tol3d); + const Handle(Geom_BSplineCurve)& spline = fit.Curve(); + if (!spline.IsNull()) { + setHandle(spline); + } + else { + throw Standard_Failure("Failed to approximate B-Spline"); + } + } + catch (Standard_Failure& e) { + THROWM(Base::CADKernelError, e.GetMessageString()) + } +} + +/*! + * \brief GeomBSplineCurve::approximate + * \param pnts Points to fit + * \param weight1 Weight of curve length as smoothing criterion + * \param weight2 Weight of curvature as smoothing criterion + * \param weight3 Weight of torsion as smoothing criterion + * \param minDegree Minimum degree + * \param maxDegree Maximum degree + * \param continuity Continuity of the spline + * \param tol3d Tolerance to the data points + */ +void GeomBSplineCurve::approximate(const std::vector& pnts, + double weight1, double weight2, double weight3, + int maxDegree, GeomAbs_Shape continuity, double tol3d) +{ + try { + TColgp_Array1OfPnt coords(1, static_cast(pnts.size())); + Standard_Integer index = 1; + for (const auto& it : pnts) { + coords(index++) = gp_Pnt(it.x, it.y, it.z); + } + + GeomAPI_PointsToBSpline fit(coords, weight1, weight2, weight3, + maxDegree, continuity, tol3d); + const Handle(Geom_BSplineCurve)& spline = fit.Curve(); + if (!spline.IsNull()) { + setHandle(spline); + } + else { + throw Standard_Failure("Failed to approximate B-Spline"); + } + } + catch (Standard_Failure& e) { + THROWM(Base::CADKernelError, e.GetMessageString()) + } } void GeomBSplineCurve::increaseMultiplicity(int index, int multiplicity) @@ -1742,11 +1830,10 @@ void GeomBSplineCurve::increaseMultiplicity(int index, int multiplicity) try { Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast(this->handle()); curve->IncreaseMultiplicity(index, multiplicity); - return; } catch (Standard_Failure& e) { THROWM(Base::CADKernelError,e.GetMessageString()) - } + } } void GeomBSplineCurve::insertKnot(double param, int multiplicity) diff --git a/src/Mod/Part/App/Geometry.h b/src/Mod/Part/App/Geometry.h index 183b5de2ba..2525281493 100644 --- a/src/Mod/Part/App/Geometry.h +++ b/src/Mod/Part/App/Geometry.h @@ -24,6 +24,7 @@ #define PART_GEOMETRY_H #include +#include #include #include #include @@ -339,7 +340,15 @@ public: std::list toBiArcs(double tolerance) const; void increaseDegree(int degree); - bool approximate(double tol3d, int maxSegments, int maxDegree, int continuity); + void approximate(double tol3d, int maxSegments, int maxDegree, GeomAbs_Shape continuity); + void approximate(const std::vector& pnts, int minDegree = 3, int maxDegree = 8, + GeomAbs_Shape continuity = GeomAbs_C2, double tol3d = 1.0e-3); + void approximate(const std::vector& pnts, Approx_ParametrizationType parType, + int minDegree = 3, int maxDegree = 8, + GeomAbs_Shape continuity = GeomAbs_C2, double tol3d = 1.0e-3); + void approximate(const std::vector& pnts, + double weight1, double weight2, double weight3, int maxDegree = 8, + GeomAbs_Shape continuity = GeomAbs_C2, double tol3d = 1.0e-3); void increaseMultiplicity(int index, int multiplicity); void insertKnot(double param, int multiplicity); @@ -353,7 +362,7 @@ public: void Save(Base::Writer &/*writer*/) const override; void Restore(Base::XMLReader &/*reader*/) override; // Base implementer ---------------------------- - PyObject *getPyObject(void) override; + PyObject *getPyObject() override; bool isSame(const Geometry &other, double tol, double atol) const override; diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 91a11612ef..2d1e1b7641 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -6508,9 +6508,7 @@ bool SketchObject::decreaseBSplineDegree(int GeoId, int degreedecrement /*= 1*/) int maxdegree = cdegree - degreedecrement; if (maxdegree == 0) return false; - bool ok = bspline->approximate(Precision::Confusion(), 20, maxdegree, 0); - if (!ok) - return false; + bspline->approximate(Precision::Confusion(), 20, maxdegree, GeomAbs_C0); } catch (const Base::Exception& e) { Base::Console().Error("%s\n", e.what());