Bug in Geom_BSplineCurve?

I created non-rational BSpline curve
m_geomBSpline = new Geom_BSplineCurve(Poles, Knots, Mults, degree);
and then added a weight
m_geomBSpline->SetWeight(2,0.5);

After that I received an error in
BSplCLib::BuildCache
in code
for (ii = 1 ; ii CacheWeights(ii) = dc.poles[LocalIndex] * LocalValue ;
LocalIndex += Dimension_gen + 1;
LocalValue *= SpanDomain / (Standard_Real) ii ;
}
CacheWeights is a Null handler.

I searched the difference between Geom_BSplineCurve constructors with and without Weights. In the last case you create cacheweights:
if (rational) {
weights = new TColStd_HArray1OfReal(1,Weights.Length());
weights->ChangeArray1() = Weights;
cacheweights = new TColStd_HArray1OfReal(1,Degree + 1);
}
May be you must do so when you set a weight? But in SetWeight function we see only
if (rat && !IsRational()) {
weights = new TColStd_HArray1OfReal(1,poles->Length());
weights->Init(1.);
}
When I used constructor with weight=0.999 there was no error.

Sergey Slyadnev's picture

Hello Vladimir,

This really looks like a bug, so could you please report an issue in official BT? Your suggestion seems to fix the case.

In the meanwhile the workaround can be using rational form of B-curve from the very beginning. E.g:

  // Prepare poles for B-spline curve
  gp_Pnt Q1( 10.0, 0.0, -5.0 );
  gp_Pnt Q2( 0.00, 0.0,  0.0 );
  gp_Pnt Q3( 0.00, 0.0,  2.0 );
  gp_Pnt Q4(-5.00, 0.0,  5.0 );
  TColgp_Array1OfPnt Poles(1, 4);
  Poles(1) = Q1;
  Poles(2) = Q2;
  Poles(3) = Q3;
  Poles(4) = Q4;

  // Degree
  const Standard_Integer degree = 2;

  // Knots with their multiplicities
  TColStd_Array1OfReal Knots(1, 3);
  TColStd_Array1OfInteger Mults(1, 3);
  Mults.SetValue(1, 3);
  Mults.SetValue(2, 1);
  Mults.SetValue(3, 3);
  Knots.SetValue(1, 0.0);
  Knots.SetValue(2, 0.5);
  Knots.SetValue(3, 1.0);

  // Weights: notice that all are equal to 1
  TColStd_Array1OfReal Weights(1, 4);
  Weights(1) = 1.0;
  Weights(2) = 1.0;
  Weights(3) = 1.0;
  Weights(4) = 1.0;

  // Notice 'Standard_False' at the end
  Handle(Geom_BSplineCurve)
    curve = new Geom_BSplineCurve(Poles, Weights, Knots, Mults,
                                  degree, Standard_False, Standard_False);

  // Now it works
  curve->SetWeight(2, 10.0);

As you can see, all weights are initially unit. Therefore, if you do not pass Standard_False as the last argument to Geom_BSplineCurve constructor, it will recognize it as non-rational and you will experience the mentioned bug. However, if you pass Standard_True, this "smart check" will not occur and SetWeight() invocation will succeed.

Vladimir Karpov's picture

Thank you for attracting my attention to the last parameter.