Modeling Data, Algorithms - Always-populated weights, direct array access migration, Hermit bug fix (#1058)

Introduce always-populated weight arrays in BSpline/Bezier curve and surface
classes using non-owning views over a static unit-weights buffer. Migrate
~100 callers across the codebase from deprecated copy-out APIs to direct
const-reference array access. Fix a long-standing typo bug in Hermit.cxx.

Infrastructure (BSplCLib, BSplSLib):
- Add BSplCLib::UnitWeights(n) returning a non-owning NCollection_Array1
  view over a compile-time-initialized static array of 2049 ones; falls
  back to heap allocation for larger sizes.
- Add BSplCLib::MaxUnitWeightsSize() (constexpr 2049) and
  BSplCLib::UnitWeightsData() exposing the raw pointer for BSplSLib.
- Add BSplSLib::UnitWeights(nU, nV) returning a non-owning
  NCollection_Array2 view when nU*nV <= 2049, heap-allocated otherwise.

Always-populated myWeights (Geom/Geom2d curve and surface classes):
- myWeights is now always sized to match poles count.
  Non-rational: non-owning view via UnitWeights (zero allocation).
  Rational: owning array with actual weight values.
- Add WeightsArray() returning const NCollection_Array1<double>& (curves)
  or const NCollection_Array2<double>& (surfaces) that is always valid.
- Update all constructors, copy constructors, and restructuring operations
  (IncreaseDegree, InsertKnots, RemoveKnot, Segment, SetPeriodic,
  SetOrigin, SetNotPeriodic, ExchangeUV, etc.) to maintain the invariant.
- SetWeight: copies non-owning view to owned array before mutation when
  transitioning to rational; assigns UnitWeights when becoming non-rational.
- Remove myRational derivation from myWeights.Size() in updateKnots();
  rationality is now tracked explicitly via the myRational flag only.
- Fix Geom2d_BSplineCurve::InsertPoleAfter missing myRational update
  after inserting a weighted pole.
- Fix Geom_BSplineCurve::DumpJson stale myWeights.Size() > 0 guard
  (changed to myRational, matching all other classes).

Caller migration to direct array access (~100 files):
- Replace deprecated copy-out pattern (allocate temp + call Foo(temp))
  with const-reference access for Poles(), Knots(), Multiplicities(),
  UKnots(), VKnots(), UMultiplicities(), VMultiplicities(),
  KnotSequence(), UKnotSequence(), VKnotSequence().
- Replace Weights() null-pointer patterns with WeightsArray() const-ref
  or *Weights() dereference where null check is still appropriate.
- Affected modules: GeomConvert, Geom2dConvert, GeomLib, GeomFill,
  ProjLib, ShapeUpgrade, ShapeCustom, ShapeConstruct, ShapeAnalysis,
  ShapeAlgo, BRepLib, BRepGProp, HLRBRep, ChFi3d, ChFiKPart, BlendFunc,
  FairCurve, IntTools, TopOpeBRepTool, TopOpeBRepBuild, LocOpe,
  BRepOffset, Adaptor3d, GeomAdaptor, Geom2dAdaptor, BndLib, Extrema,
  DrawTrSurf, GeometryTest, GeomliteTest, SWDRAW, QABugs,
  GeomToIGES, IGESToBRep, GeomToStep, StdPrs.

Bug fix in Hermit.cxx (PolyTest, both 3D and 2D overloads):
- Fix typo: "Pole0 < 3" changed to "Pole0 < Pole3" — was comparing
  a double variable against the integer literal 3 instead of the
  variable Pole3 holding the endpoint weight value.
- Fix logic: "if (boucle == 1)" changed to "else if (boucle == 1)"
  to make the boucle==1 and boucle==2 branches mutually exclusive.
- Add explanatory comments on BSplCLib::D1 calls that intentionally
  pass weight values as scalar "poles" to evaluate the weight function.

NCollection_PackedMapAlgo migration (TDataStd, QABugs):
- Replace deprecated member functions (IsSubset, Subtraction, Subtract,
  Unite, Intersect, IsEqual) with NCollection_PackedMapAlgo free functions.

GTests:
- New BSplCLib_Test.cxx: 5 tests for UnitWeights API.
- New BSplSLib_Test.cxx: 5 tests for surface UnitWeights API.
- New Hermit_Test.cxx: 11 tests for Hermit::Solution (3D/2D) and
  Hermit::Solutionbis covering uniform, distinct, high-ratio, reversed,
  symmetric weights and positive-poles invariant.
- Add WeightsArray tests to Geom_BSplineCurve_Test, Geom_BezierCurve_Test,
  Geom_BSplineSurface_Test, Geom_BezierSurface_Test (2 tests each)
  verifying const-ref return, non-owning for non-rational, owning for
  rational.
This commit is contained in:
Pasukhin Dmitry
2026-02-10 18:41:34 +00:00
committed by GitHub
parent 8949fd25f9
commit 964a2c75df
125 changed files with 2024 additions and 1678 deletions
@@ -345,9 +345,13 @@ void BRepGProp_Face::UKnots(NCollection_Array1<double>& Knots) const
Knots(3) = M_PI * 4.0 / 3.0;
Knots(4) = M_PI * 6.0 / 3.0;
break;
case GeomAbs_BSplineSurface:
(*((occ::handle<Geom_BSplineSurface>*)&((mySurface.Surface()).Surface())))->UKnots(Knots);
break;
case GeomAbs_BSplineSurface: {
const NCollection_Array1<double>& aSrcKnots =
(*((occ::handle<Geom_BSplineSurface>*)&((mySurface.Surface()).Surface())))->UKnots();
for (int i = Knots.Lower(); i <= Knots.Upper(); i++)
Knots(i) = aSrcKnots(i);
}
break;
default:
Knots(1) = mySurface.FirstUParameter();
Knots(2) = mySurface.LastUParameter();
@@ -378,9 +382,13 @@ void BRepGProp_Face::VKnots(NCollection_Array1<double>& Knots) const
Knots(3) = M_PI * 4.0 / 3.0;
Knots(4) = M_PI * 6.0 / 3.0;
break;
case GeomAbs_BSplineSurface:
(*((occ::handle<Geom_BSplineSurface>*)&((mySurface.Surface()).Surface())))->VKnots(Knots);
break;
case GeomAbs_BSplineSurface: {
const NCollection_Array1<double>& aSrcKnots =
(*((occ::handle<Geom_BSplineSurface>*)&((mySurface.Surface()).Surface())))->VKnots();
for (int i = Knots.Lower(); i <= Knots.Upper(); i++)
Knots(i) = aSrcKnots(i);
}
break;
default:
Knots(1) = mySurface.FirstUParameter();
Knots(2) = mySurface.LastUParameter();
@@ -493,9 +501,13 @@ void BRepGProp_Face::LKnots(NCollection_Array1<double>& Knots) const
Knots(1) = myCurve.FirstParameter();
Knots(2) = myCurve.LastParameter();
break;
case GeomAbs_BSplineCurve:
(*((occ::handle<Geom2d_BSplineCurve>*)&(myCurve.Curve())))->Knots(Knots);
break;
case GeomAbs_BSplineCurve: {
const NCollection_Array1<double>& aSrcKnots =
(*((occ::handle<Geom2d_BSplineCurve>*)&(myCurve.Curve())))->Knots();
for (int i = Knots.Lower(); i <= Knots.Upper(); i++)
Knots(i) = aSrcKnots(i);
}
break;
default:
Knots(1) = myCurve.FirstParameter();
Knots(2) = myCurve.LastParameter();
@@ -606,13 +618,10 @@ static void GetCurveKnots(const double theMin,
if (isSBSpline)
{
occ::handle<Geom2d_BSplineCurve> aCrv;
int aNbKnots;
occ::handle<NCollection_HArray1<double>> aCrvKnots;
aCrv = occ::down_cast<Geom2d_BSplineCurve>(theCurve.Curve());
aNbKnots = aCrv->NbKnots();
aCrvKnots = new NCollection_HArray1<double>(1, aNbKnots);
aCrv->Knots(aCrvKnots->ChangeArray1());
aCrvKnots = new NCollection_HArray1<double>(aCrv->Knots());
GetRealKnots(theMin, theMax, aCrvKnots, theKnots);
}
else
@@ -649,7 +658,6 @@ void BRepGProp_Face::GetUKnots(const double theUMin
{
// Using span decomposition for BSpline.
occ::handle<NCollection_HArray1<double>> aKnots;
int aNbKnots;
if (isSBSpline)
{
@@ -658,9 +666,7 @@ void BRepGProp_Face::GetUKnots(const double theUMin
occ::handle<Geom_BSplineSurface> aBSplSurf;
aBSplSurf = occ::down_cast<Geom_BSplineSurface>(aSurf);
aNbKnots = aBSplSurf->NbUKnots();
aKnots = new NCollection_HArray1<double>(1, aNbKnots);
aBSplSurf->UKnots(aKnots->ChangeArray1());
aKnots = new NCollection_HArray1<double>(aBSplSurf->UKnots());
}
else
{
@@ -672,9 +678,7 @@ void BRepGProp_Face::GetUKnots(const double theUMin
aCurve.Load(occ::down_cast<Geom_SurfaceOfLinearExtrusion>(aSurf)->BasisCurve());
aBSplCurve = aCurve.BSpline();
aNbKnots = aBSplCurve->NbKnots();
aKnots = new NCollection_HArray1<double>(1, aNbKnots);
aBSplCurve->Knots(aKnots->ChangeArray1());
aKnots = new NCollection_HArray1<double>(aBSplCurve->Knots());
}
// Compute number of knots inside theUMin and theUMax.
@@ -701,16 +705,13 @@ void BRepGProp_Face::GetTKnots(const double theTMin
{
// Using span decomposition for BSpline.
occ::handle<NCollection_HArray1<double>> aSurfKnots;
int aNbKnots;
// Get V knots of BSpline surface.
occ::handle<Geom_Surface> aSurf = mySurface.Surface().Surface();
occ::handle<Geom_BSplineSurface> aBSplSurf;
aBSplSurf = occ::down_cast<Geom_BSplineSurface>(aSurf);
aNbKnots = aBSplSurf->NbVKnots();
aSurfKnots = new NCollection_HArray1<double>(1, aNbKnots);
aBSplSurf->VKnots(aSurfKnots->ChangeArray1());
aSurfKnots = new NCollection_HArray1<double>(aBSplSurf->VKnots());
// occ::handle<NCollection_HArray1<double>> aCurveKnots;
@@ -1348,8 +1348,7 @@ TopoDS_Edge BRepLib::SameParameter(const TopoDS_Edge& theEdge,
|| std::abs(OriginPoint.Y() - NewOriginPoint.Y()) > Precision::PConfusion())
{
NCollection_Array1<double> Knotbs2d(1, bs2d->NbKnots());
bs2d->Knots(Knotbs2d);
NCollection_Array1<double> Knotbs2d(bs2d->Knots());
for (int Index = 1; Index <= bs2d->NbKnots(); Index++)
{
@@ -1375,11 +1374,10 @@ TopoDS_Edge BRepLib::SameParameter(const TopoDS_Edge& theEdge,
double Tol2dbail = std::min(UResbail, VResbail);
bs2d->D0(bs2d->FirstParameter(), OriginPoint);
int nbp = bs2d->NbPoles();
NCollection_Array1<gp_Pnt2d> poles(1, nbp);
bs2d->Poles(poles);
gp_Pnt2d p = poles(1), p1;
double d = Precision::Infinite();
int nbp = bs2d->NbPoles();
const NCollection_Array1<gp_Pnt2d>& poles = bs2d->Poles();
gp_Pnt2d p = poles(1), p1;
double d = Precision::Infinite();
for (int ip = 2; ip <= nbp; ip++)
{
p1 = poles(ip);
@@ -1400,8 +1398,7 @@ TopoDS_Edge BRepLib::SameParameter(const TopoDS_Edge& theEdge,
|| std::abs(OriginPoint.Y() - NewOriginPoint.Y()) > Precision::PConfusion())
{
NCollection_Array1<double> Knotbs2d(1, bs2d->NbKnots());
bs2d->Knots(Knotbs2d);
const NCollection_Array1<double>& Knotbs2d = bs2d->Knots();
for (int Index = 1; Index <= bs2d->NbKnots(); Index++)
{
@@ -1431,9 +1428,7 @@ TopoDS_Edge BRepLib::SameParameter(const TopoDS_Edge& theEdge,
{
if (repar)
{
int NbKnots = bs2d->NbKnots();
NCollection_Array1<double> Knots(1, NbKnots);
bs2d->Knots(Knots);
NCollection_Array1<double> Knots(bs2d->Knots());
// BSplCLib::Reparametrize(f3d,l3d,Knots);
BSplCLib::Reparametrize(fC0, lC0, Knots);
bs2d->SetKnots(Knots);
@@ -1463,13 +1458,12 @@ TopoDS_Edge BRepLib::SameParameter(const TopoDS_Edge& theEdge,
if (cont > GeomAbs_C0 && error > std::max(1.e-3, theTolerance))
{
int NbKnots = bs2d->NbKnots();
NCollection_Array1<double> Knots(1, NbKnots);
bs2d->Knots(Knots);
double critratio = 10.;
double dtprev = Knots(2) - Knots(1), dtratio = 1.;
double dtmin = dtprev;
double dtcur;
int NbKnots = bs2d->NbKnots();
const NCollection_Array1<double>& Knots = bs2d->Knots();
double critratio = 10.;
double dtprev = Knots(2) - Knots(1), dtratio = 1.;
double dtmin = dtprev;
double dtcur;
for (int j = 2; j < NbKnots; j++)
{
dtcur = Knots(j + 1) - Knots(j);
@@ -1522,9 +1516,7 @@ TopoDS_Edge BRepLib::SameParameter(const TopoDS_Edge& theEdge,
if (std::abs(bs2d->FirstParameter() - fC0) > TolSameRange
|| std::abs(bs2d->LastParameter() - lC0) > TolSameRange)
{
int NbKnots = bs2d->NbKnots();
NCollection_Array1<double> Knots(1, NbKnots);
bs2d->Knots(Knots);
NCollection_Array1<double> Knots(bs2d->Knots());
// BSplCLib::Reparametrize(f3d,l3d,Knots);
BSplCLib::Reparametrize(fC0, lC0, Knots);
bs2d->SetKnots(Knots);
@@ -76,12 +76,9 @@ static void BCSmoothing(occ::handle<Geom_BSplineCurve>& theC,
{
int aNbKnots = theC->NbKnots();
NCollection_Array1<int> aMults(1, aNbKnots);
NCollection_Array1<double> aKnots(1, aNbKnots);
theC->Multiplicities(aMults);
theC->Knots(aKnots);
int i, m = theC->Degree();
NCollection_Array1<int> aMults(theC->Multiplicities());
NCollection_Array1<double> aKnots(theC->Knots());
int i, m = theC->Degree();
m = m - theCont;
if (m < 1)
@@ -912,9 +909,8 @@ bool BRepLib_FuseEdges::SameSupport(const TopoDS_Edge& E1, const TopoDS_Edge& E2
return false;
}
NCollection_Array1<gp_Pnt> P1(1, nbpoles), P2(1, nbpoles);
B1->Poles(P1);
B2->Poles(P2);
const NCollection_Array1<gp_Pnt>& P1 = B1->Poles();
const NCollection_Array1<gp_Pnt>& P2 = B2->Poles();
double tol3d = BRep_Tool::Tolerance(E1);
for (int p = 1; p <= nbpoles; p++)
@@ -925,13 +921,11 @@ bool BRepLib_FuseEdges::SameSupport(const TopoDS_Edge& E1, const TopoDS_Edge& E2
}
}
NCollection_Array1<double> K1(1, nbknots), K2(1, nbknots);
B1->Knots(K1);
B2->Knots(K2);
const NCollection_Array1<double>& K1 = B1->Knots();
const NCollection_Array1<double>& K2 = B2->Knots();
NCollection_Array1<int> M1(1, nbknots), M2(1, nbknots);
B1->Multiplicities(M1);
B2->Multiplicities(M2);
const NCollection_Array1<int>& M1 = B1->Multiplicities();
const NCollection_Array1<int>& M2 = B2->Multiplicities();
for (int k = 1; k <= nbknots; k++)
{
@@ -962,9 +956,8 @@ bool BRepLib_FuseEdges::SameSupport(const TopoDS_Edge& E1, const TopoDS_Edge& E2
if (B1->IsRational())
{
NCollection_Array1<double> W1(1, nbpoles), W2(1, nbpoles);
B1->Weights(W1);
B2->Weights(W2);
const NCollection_Array1<double>& W1 = B1->WeightsArray();
const NCollection_Array1<double>& W2 = B2->WeightsArray();
for (int w = 1; w <= nbpoles; w++)
{
@@ -995,9 +988,8 @@ bool BRepLib_FuseEdges::SameSupport(const TopoDS_Edge& E1, const TopoDS_Edge& E2
return false;
}
NCollection_Array1<gp_Pnt> P1(1, nbpoles), P2(1, nbpoles);
B1->Poles(P1);
B2->Poles(P2);
const NCollection_Array1<gp_Pnt>& P1 = B1->Poles();
const NCollection_Array1<gp_Pnt>& P2 = B2->Poles();
for (int p = 1; p <= nbpoles; p++)
{
@@ -1024,9 +1016,8 @@ bool BRepLib_FuseEdges::SameSupport(const TopoDS_Edge& E1, const TopoDS_Edge& E2
if (B1->IsRational())
{
NCollection_Array1<double> W1(1, nbpoles), W2(1, nbpoles);
B1->Weights(W1);
B2->Weights(W2);
const NCollection_Array1<double>& W1 = B1->WeightsArray();
const NCollection_Array1<double>& W2 = B2->WeightsArray();
for (int w = 1; w <= nbpoles; w++)
{
@@ -1147,8 +1138,7 @@ bool BRepLib_FuseEdges::UpdatePCurve(const TopoDS_Edge& theOl
|| std::abs(last - el) > Precision::PConfusion())
{
occ::handle<Geom2d_BSplineCurve> bc = occ::down_cast<Geom2d_BSplineCurve>(Curv2d);
NCollection_Array1<double> Knots(1, bc->NbKnots());
bc->Knots(Knots);
NCollection_Array1<double> Knots(bc->Knots());
BSplCLib::Reparametrize(ef, el, Knots);
bc->SetKnots(Knots);
}
@@ -465,11 +465,10 @@ void BRepTopAdaptor_TopolTool::ComputeSamplePoints()
{
if (typS == GeomAbs_BSplineSurface)
{
const occ::handle<Geom_BSplineSurface>& Bspl = myS->BSpline();
int nbup = Bspl->NbUPoles();
int nbvp = Bspl->NbVPoles();
NCollection_Array2<gp_Pnt> array2(1, nbup, 1, nbvp);
Bspl->Poles(array2);
const occ::handle<Geom_BSplineSurface>& Bspl = myS->BSpline();
int nbup = Bspl->NbUPoles();
int nbvp = Bspl->NbVPoles();
const NCollection_Array2<gp_Pnt>& array2 = Bspl->Poles();
Analyse(array2, nbup, nbvp, myNbSamplesU, myNbSamplesV);
nbsu = myNbSamplesU;
nbsv = myNbSamplesV;
@@ -477,11 +476,10 @@ void BRepTopAdaptor_TopolTool::ComputeSamplePoints()
}
else if (typS == GeomAbs_BezierSurface)
{
const occ::handle<Geom_BezierSurface>& Bez = myS->Bezier();
int nbup = Bez->NbUPoles();
int nbvp = Bez->NbVPoles();
NCollection_Array2<gp_Pnt> array2(1, nbup, 1, nbvp);
Bez->Poles(array2);
const occ::handle<Geom_BezierSurface>& Bez = myS->Bezier();
int nbup = Bez->NbUPoles();
int nbvp = Bez->NbVPoles();
const NCollection_Array2<gp_Pnt>& array2 = Bez->Poles();
Analyse(array2, nbup, nbvp, myNbSamplesU, myNbSamplesV);
nbsu = myNbSamplesU;
nbsv = myNbSamplesV;