-// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+// Copyright (C) 2019-2023 CEA, EDF
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
#include <GeomAPI_XY.h>
#include <Geom2d_BSplineCurve.hxx>
+#include <Geom2dAPI_ProjectPointOnCurve.hxx>
+#include <GeomLib_Tool.hxx>
+#include <Precision.hxx>
#define MY_BSPLINE (*(implPtr<Handle_Geom2d_BSplineCurve>()))
+static Handle_Geom2d_BSplineCurve* newBSpline2d(
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const int theDegree,
+ const bool thePeriodic);
+
+
static Handle_Geom2d_BSplineCurve* newBSpline2d(
const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
const std::list<double>& theWeights,
const int theDegree,
const bool thePeriodic)
{
+ if (theKnots.empty() || theMults.empty())
+ return newBSpline2d(thePoles, theWeights, theDegree, thePeriodic);
+
+ int anAuxPole = 0;
+ if (thePeriodic && thePoles.front()->distance(thePoles.back()) < Precision::Confusion()) {
+ // additionally check the number of poles is greater than needed for th periodic B-spline
+ int aNbPoles = 0;
+ std::list<int>::const_iterator it = theMults.begin();
+ for (++it; it != theMults.end(); ++it)
+ aNbPoles += *it;
+ if ((int)thePoles.size() > aNbPoles)
+ anAuxPole = -1;
+ }
+
// collect arrays of poles, weights, knots and multiplicities
- TColgp_Array1OfPnt2d aPoles(1, (int)thePoles.size());
- TColStd_Array1OfReal aWeights(1, (int)theWeights.size());
+ TColgp_Array1OfPnt2d aPoles(1, (int)thePoles.size() + anAuxPole);
+ TColStd_Array1OfReal aWeights(1, (int)theWeights.size() + anAuxPole);
TColStd_Array1OfReal aKnots(1, (int)theKnots.size());
TColStd_Array1OfInteger aMults(1, (int)theMults.size());
int anIndex = 1;
for (std::list<GeomPnt2dPtr>::const_iterator aPIt = thePoles.begin();
- aPIt != thePoles.end(); ++aPIt, ++anIndex)
+ aPIt != thePoles.end() && anIndex <= aPoles.Upper(); ++aPIt, ++anIndex)
aPoles.SetValue(anIndex, gp_Pnt2d((*aPIt)->x(), (*aPIt)->y()));
anIndex = 1;
for (std::list<double>::const_iterator aWIt = theWeights.begin();
- aWIt != theWeights.end(); ++aWIt, ++anIndex)
+ aWIt != theWeights.end() && anIndex <= aWeights.Upper(); ++aWIt, ++anIndex)
aWeights.SetValue(anIndex, *aWIt);
anIndex = 1;
for (std::list<double>::const_iterator aKIt = theKnots.begin();
return new Handle_Geom2d_BSplineCurve(aCurve);
}
-static Handle_Geom2d_BSplineCurve* newBSpline2d(
+Handle_Geom2d_BSplineCurve* newBSpline2d(
const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
const std::list<double>& theWeights,
const int theDegree,
const bool thePeriodic)
{
+ std::list<std::shared_ptr<GeomAPI_Pnt2d> > aPoles = thePoles;
+ std::list<double> aWeights = theWeights;
+ int aMult = theDegree + 1;
int aNbKnots = (int)thePoles.size() - theDegree + 1;
+ if (thePeriodic) {
+ if (aPoles.front()->distance(aPoles.back()) < Precision::Confusion()) {
+ aPoles.pop_back();
+ aWeights.pop_back();
+ }
+ aMult = 1;
+ aNbKnots = (int)aPoles.size() + 1;
+ }
+
if (aNbKnots < 2)
return new Handle_Geom2d_BSplineCurve();
aKnots.push_back(aEndParam);
std::list<int> aMults(aNbKnots - 2, 1);
- aMults.push_front(theDegree + 1);
- aMults.push_back(theDegree + 1);
+ aMults.push_front(aMult);
+ aMults.push_back(aMult);
- return newBSpline2d(thePoles, theWeights, aKnots, aMults, theDegree, thePeriodic);
+ return newBSpline2d(aPoles, aWeights, aKnots, aMults, theDegree, thePeriodic);
}
static Handle_Geom2d_BSplineCurve* newBSpline2d(
return std::list<int>(aBSplMults.begin(), aBSplMults.end());
}
+const bool GeomAPI_BSpline2d::parameter(const std::shared_ptr<GeomAPI_Pnt2d> thePoint,
+ const double theTolerance,
+ double& theParameter) const
+{
+ const gp_Pnt2d& aPoint = thePoint->impl<gp_Pnt2d>();
+ bool isOk = GeomLib_Tool::Parameter(MY_BSPLINE, aPoint,
+ theTolerance, theParameter) == Standard_True;
+ if (!isOk) {
+ // Sometimes OCCT's Extrema algorithm cannot find the parameter on B-spline curve
+ // (usually, if the point is near the curve extremity).
+ // Workaround: compute distance to each boundary point
+ isOk = true;
+ double aDistPS = aPoint.Distance(MY_BSPLINE->Poles().First());
+ double aDistPE = aPoint.Distance(MY_BSPLINE->Poles().Last());
+ if (aDistPS < aDistPE && aDistPS < theTolerance)
+ theParameter = MY_BSPLINE->Knots().First();
+ else if (aDistPE < aDistPS && aDistPE < theTolerance)
+ theParameter = MY_BSPLINE->Knots().Last();
+ else
+ isOk = false;
+ }
+ return isOk;
+}
+
void GeomAPI_BSpline2d::D0(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
{
gp_Pnt2d aPnt;