0022939: Make B-Spline internal cache thread-safe to be used in multy-threaded mode
[occt.git] / src / Geom / Geom_BSplineCurve.cxx
1 // Created on: 1993-03-09
2 // Created by: JCV
3 // Copyright (c) 1993-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
5 //
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
10 //
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 //
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
20
21
22 //Avril 1991 : constructeurs + methodes de lecture.
23 //Mai 1991   : revue des specifs + debut de realisation des classes tool =>
24 //             implementation des methodes Set et calcul du point courant.
25 //Juillet 1991 : voir egalement File Geom_BSplineCurve_1.cxx
26 //Juin    1992 : mise a plat des valeurs nodales - amelioration des
27 //               performances sur calcul du point courant
28
29 //RLE Aug 1993  Remove Swaps, Remove typedefs, Update BSplCLib
30 //              debug periodic, IncreaseDegree
31 // 21-Mar-95 : xab implemented cache
32 // 14-Mar-96 : xab implemented MovePointAndTangent 
33 // 13-Oct-96 : pmn Bug dans SetPeriodic (PRO6088) et Segment (PRO6250)
34
35 #define No_Standard_OutOfRange
36
37 #include <Geom_BSplineCurve.ixx>
38 #include <gp.hxx>
39 #include <ElCLib.hxx>
40 #include <BSplCLib.hxx>
41 #include <BSplCLib_KnotDistribution.hxx>
42 #include <BSplCLib_MultDistribution.hxx>
43 #include <Standard_NotImplemented.hxx>
44 #include <Standard_ConstructionError.hxx>
45 #include <Standard_OutOfRange.hxx>
46 #include <Standard_Real.hxx>
47
48 //=======================================================================
49 //function : CheckCurveData
50 //purpose  : Internal use only
51 //=======================================================================
52
53 static void CheckCurveData
54 (const TColgp_Array1OfPnt&         CPoles,
55  const TColStd_Array1OfReal&       CKnots,
56  const TColStd_Array1OfInteger&    CMults,
57  const Standard_Integer            Degree,
58  const Standard_Boolean            Periodic)
59 {
60   if (Degree < 1 || Degree > Geom_BSplineCurve::MaxDegree()) {
61     Standard_ConstructionError::Raise();  
62   }
63   
64   if (CPoles.Length() < 2)                Standard_ConstructionError::Raise();
65   if (CKnots.Length() != CMults.Length()) Standard_ConstructionError::Raise();
66   
67   for (Standard_Integer I = CKnots.Lower(); I < CKnots.Upper(); I++) {
68     if (CKnots (I+1) - CKnots (I) <= Epsilon (Abs(CKnots (I)))) {
69       Standard_ConstructionError::Raise();
70     }
71   }
72   
73   if (CPoles.Length() != BSplCLib::NbPoles(Degree,Periodic,CMults))
74     Standard_ConstructionError::Raise();
75 }
76
77 //=======================================================================
78 //function : KnotAnalysis
79 //purpose  : Internal use only
80 //=======================================================================
81
82 static void KnotAnalysis
83 (const Standard_Integer           Degree,
84  const Standard_Boolean           Periodic,
85  const TColStd_Array1OfReal&      CKnots,
86  const TColStd_Array1OfInteger&   CMults,
87  GeomAbs_BSplKnotDistribution&    KnotForm,
88  Standard_Integer&                MaxKnotMult)
89 {
90   KnotForm = GeomAbs_NonUniform;
91
92   BSplCLib_KnotDistribution KSet = 
93     BSplCLib::KnotForm (CKnots, 1, CKnots.Length());
94   
95
96   if (KSet == BSplCLib_Uniform) {
97     BSplCLib_MultDistribution MSet =
98       BSplCLib::MultForm (CMults, 1, CMults.Length());
99     switch (MSet) {
100     case BSplCLib_NonConstant   :       
101       break;
102     case BSplCLib_Constant      : 
103       if (CKnots.Length() == 2) {
104         KnotForm = GeomAbs_PiecewiseBezier;
105       }
106       else {
107         if (CMults (1) == 1)  KnotForm = GeomAbs_Uniform;   
108       }
109       break;
110     case BSplCLib_QuasiConstant :   
111       if (CMults (1) == Degree + 1) {
112         Standard_Real M = CMults (2);
113         if (M == Degree )   KnotForm = GeomAbs_PiecewiseBezier;
114         else if  (M == 1)   KnotForm = GeomAbs_QuasiUniform;
115       }
116       break;
117     }
118   }
119
120   Standard_Integer FirstKM = 
121     Periodic ? CKnots.Lower() :  BSplCLib::FirstUKnotIndex (Degree,CMults);
122   Standard_Integer LastKM = 
123     Periodic ? CKnots.Upper() :  BSplCLib::LastUKnotIndex (Degree,CMults);
124   MaxKnotMult = 0;
125   if (LastKM - FirstKM != 1) {
126     Standard_Integer Multi;
127     for (Standard_Integer i = FirstKM + 1; i < LastKM; i++) {
128       Multi = CMults (i);
129       MaxKnotMult = Max (MaxKnotMult, Multi);
130     }
131   }
132 }
133
134 //=======================================================================
135 //function : Rational
136 //purpose  : check rationality of an array of weights
137 //=======================================================================
138
139 static Standard_Boolean Rational(const TColStd_Array1OfReal& W)
140 {
141   Standard_Integer i, n = W.Length();
142   Standard_Boolean rat = Standard_False;
143   for (i = 1; i < n; i++) {
144     rat =  Abs(W(i) - W(i+1)) > gp::Resolution();
145     if (rat) break;
146   }
147   return rat;
148 }
149
150 //=======================================================================
151 //function : Copy
152 //purpose  : 
153 //=======================================================================
154
155 Handle(Geom_Geometry) Geom_BSplineCurve::Copy() const
156 {
157   Handle(Geom_BSplineCurve) C;
158   if (IsRational()) 
159     C = new Geom_BSplineCurve(poles->Array1(),
160                               weights->Array1(),
161                               knots->Array1(),
162                               mults->Array1(),
163                               deg,periodic);
164   else
165     C = new Geom_BSplineCurve(poles->Array1(),
166                               knots->Array1(),
167                               mults->Array1(),
168                               deg,periodic);
169   return C;
170 }
171
172 //=======================================================================
173 //function : Geom_BSplineCurve
174 //purpose  : 
175 //=======================================================================
176
177 Geom_BSplineCurve::Geom_BSplineCurve
178 (const TColgp_Array1OfPnt&       Poles,
179  const TColStd_Array1OfReal&     Knots,
180  const TColStd_Array1OfInteger&  Mults,
181  const Standard_Integer          Degree,
182  const Standard_Boolean          Periodic) :
183  rational(Standard_False),
184  periodic(Periodic),
185  deg(Degree),
186  maxderivinvok(Standard_False)
187 {
188   // check
189   
190   CheckCurveData (Poles,
191                   Knots,
192                   Mults,
193                   Degree,
194                   Periodic);
195
196
197   // copy arrays
198
199   poles =  new TColgp_HArray1OfPnt(1,Poles.Length());
200   poles->ChangeArray1() = Poles;
201   
202
203   knots = new TColStd_HArray1OfReal(1,Knots.Length());
204   knots->ChangeArray1() = Knots;
205
206   mults = new TColStd_HArray1OfInteger(1,Mults.Length());
207   mults->ChangeArray1() = Mults;
208
209   UpdateKnots();
210   cachepoles = new TColgp_HArray1OfPnt(1,Degree + 1);
211   parametercache = 0.0e0 ;
212   spanlenghtcache = 0.0e0 ;
213   spanindexcache = 0 ;
214
215 }
216
217 //=======================================================================
218 //function : Geom_BSplineCurve
219 //purpose  : 
220 //=======================================================================
221
222 Geom_BSplineCurve::Geom_BSplineCurve
223 (const TColgp_Array1OfPnt&      Poles,
224  const TColStd_Array1OfReal&    Weights,
225  const TColStd_Array1OfReal&    Knots,
226  const TColStd_Array1OfInteger& Mults,
227  const Standard_Integer         Degree,
228  const Standard_Boolean         Periodic,
229  const Standard_Boolean         CheckRational)  :
230  rational(Standard_True),
231  periodic(Periodic),
232  deg(Degree),
233  maxderivinvok(Standard_False)
234
235 {
236
237   // check
238   
239   CheckCurveData (Poles,
240                   Knots,
241                   Mults,
242                   Degree,
243                   Periodic);
244
245   if (Weights.Length() != Poles.Length())
246     Standard_ConstructionError::Raise("Geom_BSplineCurve");
247
248   Standard_Integer i;
249   for (i = Weights.Lower(); i <= Weights.Upper(); i++) {
250     if (Weights(i) <= gp::Resolution())  
251       Standard_ConstructionError::Raise("Geom_BSplineCurve");
252   }
253   
254   // check really rational
255   if (CheckRational)
256     rational = Rational(Weights);
257   
258   // copy arrays
259   
260   poles =  new TColgp_HArray1OfPnt(1,Poles.Length());
261   poles->ChangeArray1() = Poles;
262   cachepoles = new TColgp_HArray1OfPnt(1,Degree + 1);
263   if (rational) {
264     weights =  new TColStd_HArray1OfReal(1,Weights.Length());
265     weights->ChangeArray1() = Weights;
266     cacheweights  = new TColStd_HArray1OfReal(1,Degree + 1);
267   }
268
269   knots = new TColStd_HArray1OfReal(1,Knots.Length());
270   knots->ChangeArray1() = Knots;
271
272   mults = new TColStd_HArray1OfInteger(1,Mults.Length());
273   mults->ChangeArray1() = Mults;
274
275   UpdateKnots();
276   parametercache = 0.0e0 ;
277   spanlenghtcache = 0.0e0 ;
278   spanindexcache = 0 ;
279 }
280
281 //=======================================================================
282 //function : MaxDegree
283 //purpose  : 
284 //=======================================================================
285
286 Standard_Integer Geom_BSplineCurve::MaxDegree () 
287
288   return BSplCLib::MaxDegree(); 
289 }
290
291 //=======================================================================
292 //function : IncreaseDegree
293 //purpose  : 
294 //=======================================================================
295
296 void Geom_BSplineCurve::IncreaseDegree  (const Standard_Integer Degree)
297 {
298   if (Degree == deg) return;
299   
300   if (Degree < deg || Degree > Geom_BSplineCurve::MaxDegree()) {
301     Standard_ConstructionError::Raise();
302   }
303   Standard_Integer FromK1 = FirstUKnotIndex ();
304   Standard_Integer ToK2   = LastUKnotIndex  ();
305   
306   Standard_Integer Step   = Degree - deg;
307   
308   Handle(TColgp_HArray1OfPnt) npoles = new
309     TColgp_HArray1OfPnt(1,poles->Length() + Step * (ToK2-FromK1));
310
311   Standard_Integer nbknots = BSplCLib::IncreaseDegreeCountKnots
312     (deg,Degree,periodic,mults->Array1());
313
314   Handle(TColStd_HArray1OfReal) nknots = 
315     new TColStd_HArray1OfReal(1,nbknots);
316
317   Handle(TColStd_HArray1OfInteger) nmults = 
318     new TColStd_HArray1OfInteger(1,nbknots);
319
320   Handle(TColStd_HArray1OfReal) nweights;
321   
322   if (IsRational()) {
323     
324     nweights = new TColStd_HArray1OfReal(1,npoles->Upper());
325     
326     BSplCLib::IncreaseDegree
327       (deg,Degree, periodic,
328        poles->Array1(),weights->Array1(),
329        knots->Array1(),mults->Array1(),
330        npoles->ChangeArray1(),nweights->ChangeArray1(),
331        nknots->ChangeArray1(),nmults->ChangeArray1());
332   }
333   else {
334     BSplCLib::IncreaseDegree
335       (deg,Degree, periodic,
336        poles->Array1(),BSplCLib::NoWeights(),
337        knots->Array1(),mults->Array1(),
338        npoles->ChangeArray1(),
339        *((TColStd_Array1OfReal*) NULL),
340        nknots->ChangeArray1(),nmults->ChangeArray1());
341   }
342
343   deg     = Degree;
344   poles   = npoles;
345   weights = nweights;
346   knots   = nknots;
347   mults   = nmults;
348   UpdateKnots();
349   
350 }
351
352 //=======================================================================
353 //function : IncreaseMultiplicity
354 //purpose  : 
355 //=======================================================================
356
357 void Geom_BSplineCurve::IncreaseMultiplicity  (const Standard_Integer Index,
358                                                const Standard_Integer M)
359 {
360   TColStd_Array1OfReal k(1,1);
361   k(1) = knots->Value(Index);
362   TColStd_Array1OfInteger m(1,1);
363   m(1) = M - mults->Value(Index);
364   InsertKnots(k,m,Epsilon(1.),Standard_True);
365 }
366
367 //=======================================================================
368 //function : IncreaseMultiplicity
369 //purpose  : 
370 //=======================================================================
371
372 void Geom_BSplineCurve::IncreaseMultiplicity  (const Standard_Integer I1,
373                                                const Standard_Integer I2,
374                                                const Standard_Integer M)
375 {
376   Handle(TColStd_HArray1OfReal)  tk = knots;
377   TColStd_Array1OfReal k((knots->Array1())(I1),I1,I2);
378   TColStd_Array1OfInteger m(I1,I2);
379   Standard_Integer i;
380   for (i = I1; i <= I2; i++)
381     m(i) = M - mults->Value(i);
382   InsertKnots(k,m,Epsilon(1.),Standard_True);
383 }
384
385 //=======================================================================
386 //function : IncrementMultiplicity
387 //purpose  : 
388 //=======================================================================
389
390 void Geom_BSplineCurve::IncrementMultiplicity
391 (const Standard_Integer I1,
392  const Standard_Integer I2,
393  const Standard_Integer Step)
394 {
395   Handle(TColStd_HArray1OfReal) tk = knots;
396   TColStd_Array1OfReal    k((knots->Array1())(I1),I1,I2);
397   TColStd_Array1OfInteger m(I1,I2) ;
398   m.Init(Step);
399   InsertKnots(k,m,Epsilon(1.),Standard_True);
400 }
401
402 //=======================================================================
403 //function : InsertKnot
404 //purpose  : 
405 //=======================================================================
406
407 void Geom_BSplineCurve::InsertKnot
408 (const Standard_Real U, 
409  const Standard_Integer M, 
410  const Standard_Real ParametricTolerance,
411  const Standard_Boolean Add)
412 {
413   TColStd_Array1OfReal k(1,1);
414   k(1) = U;
415   TColStd_Array1OfInteger m(1,1);
416   m(1) = M;
417   InsertKnots(k,m,ParametricTolerance,Add);
418 }
419
420 //=======================================================================
421 //function : InsertKnots
422 //purpose  : 
423 //=======================================================================
424
425 void  Geom_BSplineCurve::InsertKnots(const TColStd_Array1OfReal& Knots, 
426                                      const TColStd_Array1OfInteger& Mults,
427                                      const Standard_Real Epsilon,
428                                      const Standard_Boolean Add)
429 {
430   // Check and compute new sizes
431   Standard_Integer nbpoles,nbknots;
432
433   if (!BSplCLib::PrepareInsertKnots(deg,periodic,
434                                     knots->Array1(),mults->Array1(),
435                                     Knots,Mults,nbpoles,nbknots,Epsilon,Add))
436     Standard_ConstructionError::Raise("Geom_BSplineCurve::InsertKnots");
437
438   if (nbpoles == poles->Length()) return;
439
440   Handle(TColgp_HArray1OfPnt)      npoles = new TColgp_HArray1OfPnt(1,nbpoles);
441   Handle(TColStd_HArray1OfReal)    nknots = knots;
442   Handle(TColStd_HArray1OfInteger) nmults = mults;
443
444   if (nbknots != knots->Length()) {
445     nknots = new TColStd_HArray1OfReal(1,nbknots);
446     nmults = new TColStd_HArray1OfInteger(1,nbknots);
447   }
448
449   if (rational) {
450     Handle(TColStd_HArray1OfReal) nweights = 
451       new TColStd_HArray1OfReal(1,nbpoles);
452     BSplCLib::InsertKnots(deg,periodic,
453                           poles->Array1(), weights->Array1(),
454                           knots->Array1(), mults->Array1(),
455                           Knots, Mults,
456                           npoles->ChangeArray1(), nweights->ChangeArray1(),
457                           nknots->ChangeArray1(), nmults->ChangeArray1(),
458                           Epsilon, Add);
459     weights = nweights;
460   }
461   else {
462     BSplCLib::InsertKnots(deg,periodic,
463                           poles->Array1(), BSplCLib::NoWeights(),
464                           knots->Array1(), mults->Array1(),
465                           Knots, Mults,
466                           npoles->ChangeArray1(),
467                           *((TColStd_Array1OfReal*) NULL),
468                           nknots->ChangeArray1(), nmults->ChangeArray1(),
469                           Epsilon, Add);
470   }
471
472   poles = npoles;
473   knots = nknots;
474   mults = nmults;
475   UpdateKnots();
476
477 }
478
479 //=======================================================================
480 //function : RemoveKnot
481 //purpose  : 
482 //=======================================================================
483
484 Standard_Boolean  Geom_BSplineCurve::RemoveKnot(const Standard_Integer Index,
485                                                 const Standard_Integer M, 
486                                                 const Standard_Real Tolerance)
487 {
488   if (M < 0) return Standard_True;
489
490   Standard_Integer I1  = FirstUKnotIndex ();
491   Standard_Integer I2  = LastUKnotIndex  ();
492
493   if ( !periodic && (Index <= I1 || Index >= I2) ) {
494     Standard_OutOfRange::Raise();
495   }
496   else if ( periodic  && (Index < I1 || Index > I2)) {
497     Standard_OutOfRange::Raise();
498   }
499   
500   const TColgp_Array1OfPnt   & oldpoles   = poles->Array1();
501
502   Standard_Integer step = mults->Value(Index) - M;
503   if (step <= 0) return Standard_True;
504
505   Handle(TColgp_HArray1OfPnt) npoles =
506     new TColgp_HArray1OfPnt(1,oldpoles.Length()-step);
507
508   Handle(TColStd_HArray1OfReal)    nknots  = knots;
509   Handle(TColStd_HArray1OfInteger) nmults  = mults;
510
511   if (M == 0) {
512     nknots = new TColStd_HArray1OfReal(1,knots->Length()-1);
513     nmults = new TColStd_HArray1OfInteger(1,knots->Length()-1);
514   }
515
516   if (IsRational()) {
517     Handle(TColStd_HArray1OfReal) nweights = 
518       new TColStd_HArray1OfReal(1,npoles->Length());
519     if (!BSplCLib::RemoveKnot
520         (Index, M, deg, periodic,
521          poles->Array1(),weights->Array1(), 
522          knots->Array1(),mults->Array1(),
523          npoles->ChangeArray1(), nweights->ChangeArray1(),
524          nknots->ChangeArray1(),nmults->ChangeArray1(),
525          Tolerance))
526       return Standard_False;
527     weights = nweights;
528   }
529   else {
530     if (!BSplCLib::RemoveKnot
531         (Index, M, deg, periodic,
532          poles->Array1(), BSplCLib::NoWeights(),
533          knots->Array1(),mults->Array1(),
534          npoles->ChangeArray1(),
535          *((TColStd_Array1OfReal*) NULL),
536          nknots->ChangeArray1(),nmults->ChangeArray1(),
537          Tolerance))
538       return Standard_False;
539   }
540   
541   poles = npoles;
542   knots = nknots;
543   mults = nmults;
544
545   UpdateKnots();
546   maxderivinvok = 0;
547   return Standard_True;
548 }
549
550 //=======================================================================
551 //function : Reverse
552 //purpose  : 
553 //=======================================================================
554
555 void Geom_BSplineCurve::Reverse ()
556
557   BSplCLib::Reverse(knots->ChangeArray1());
558   BSplCLib::Reverse(mults->ChangeArray1());
559   Standard_Integer last;
560   if (periodic)
561     last = flatknots->Upper() - deg - 1;
562   else
563     last = poles->Upper();
564   BSplCLib::Reverse(poles->ChangeArray1(),last);
565   if (rational)
566     BSplCLib::Reverse(weights->ChangeArray1(),last);
567   UpdateKnots();
568 }
569
570 //=======================================================================
571 //function : ReversedParameter
572 //purpose  : 
573 //=======================================================================
574
575 Standard_Real Geom_BSplineCurve::ReversedParameter
576 (const Standard_Real U) const
577 {
578   return (FirstParameter() + LastParameter() - U);
579 }
580
581 //=======================================================================
582 //function : Segment
583 //purpose  : 
584 //=======================================================================
585
586 void Geom_BSplineCurve::Segment(const Standard_Real U1,
587                                 const Standard_Real U2)
588 {
589   Standard_DomainError_Raise_if ( U2 < U1,
590                                  "Geom_BSplineCurve::Segment");
591   
592   Standard_Real NewU1, NewU2;
593   Standard_Real U,DU=0,aDDU=0;
594   Standard_Integer index;
595   Standard_Boolean wasPeriodic = periodic;
596
597   TColStd_Array1OfReal    Knots(1,2);
598   TColStd_Array1OfInteger Mults(1,2);
599
600   // define param ditance to keep (eap, Apr 18 2002, occ311)
601   if (periodic) {
602     Standard_Real Period = LastParameter() - FirstParameter();
603     DU = U2 - U1;
604     while (DU > Period)
605       DU -= Period;
606     if (DU <= Epsilon(Period))
607       DU = Period;
608     aDDU = DU;
609   }
610
611   index = 0;
612   BSplCLib::LocateParameter(deg,knots->Array1(),mults->Array1(),
613                             U1,periodic,knots->Lower(),knots->Upper(),
614                             index,NewU1);
615   index = 0;
616   BSplCLib::LocateParameter(deg,knots->Array1(),mults->Array1(),
617                             U2,periodic,knots->Lower(),knots->Upper(),
618                             index,NewU2);
619
620   //-- DBB
621   Standard_Real aNu2 = NewU2;
622   //-- DBB
623
624
625   Knots( 1) = Min( NewU1, NewU2);
626   Knots( 2) = Max( NewU1, NewU2);
627   Mults( 1) = Mults( 2) = deg;
628
629   Standard_Real AbsUMax = Max(Abs(NewU1),Abs(NewU2));
630
631 //  Modified by Sergey KHROMOV - Fri Apr 11 12:15:40 2003 Begin
632   AbsUMax = Max(AbsUMax, Max(Abs(FirstParameter()),Abs(LastParameter())));
633 //  Modified by Sergey KHROMOV - Fri Apr 11 12:15:40 2003 End
634
635   Standard_Real Eps = 100. * Epsilon(AbsUMax);
636
637   InsertKnots( Knots, Mults, Eps);
638
639   if (periodic) { // set the origine at NewU1
640     index = 0;
641     BSplCLib::LocateParameter(deg,knots->Array1(),mults->Array1(),
642                               U1,periodic,knots->Lower(),knots->Upper(),
643                               index,U);
644     // Test si l'insertion est Ok et decalage sinon. 
645     if ( Abs(knots->Value(index+1)-U) <= Eps) // <= pour etre homogene a InsertKnots
646       index++;
647     SetOrigin(index);
648     SetNotPeriodic();
649     NewU2 = NewU1 + DU;
650   }
651
652   // compute index1 and index2 to set the new knots and mults 
653   Standard_Integer index1 = 0, index2 = 0;
654   Standard_Integer FromU1 = knots->Lower();
655   Standard_Integer ToU2   = knots->Upper();
656   BSplCLib::LocateParameter(deg,knots->Array1(),mults->Array1(),
657                             NewU1,periodic,FromU1,ToU2,index1,U);
658   if ( Abs(knots->Value(index1+1)-U) <= Eps)
659     index1++;
660
661   BSplCLib::LocateParameter(deg,knots->Array1(),mults->Array1(),
662                             NewU2,periodic,FromU1,ToU2,index2,U);
663   if ( Abs(knots->Value(index2+1)-U) <= Eps)
664     index2++;
665   
666   Standard_Integer nbknots = index2 - index1 + 1;
667
668   Handle(TColStd_HArray1OfReal) 
669     nknots = new TColStd_HArray1OfReal(1,nbknots);
670   Handle(TColStd_HArray1OfInteger) 
671     nmults = new TColStd_HArray1OfInteger(1,nbknots);
672
673   // to restore changed U1
674   if (DU > 0) // if was periodic
675     DU = NewU1 - U1;
676   
677   Standard_Integer i , k = 1;
678   for ( i = index1; i<= index2; i++) {
679     nknots->SetValue(k, knots->Value(i) - DU);
680     nmults->SetValue(k, mults->Value(i));
681     k++;
682   }
683   nmults->SetValue(      1, deg + 1);
684   nmults->SetValue(nbknots, deg + 1);
685
686
687   // compute index1 and index2 to set the new poles and weights
688   Standard_Integer pindex1 
689     = BSplCLib::PoleIndex(deg,index1,periodic,mults->Array1());
690   Standard_Integer pindex2 
691     = BSplCLib::PoleIndex(deg,index2,periodic,mults->Array1());
692
693   pindex1++;
694   pindex2 = Min( pindex2+1, poles->Length());
695
696   Standard_Integer nbpoles  = pindex2 - pindex1 + 1;
697
698   Handle(TColStd_HArray1OfReal) 
699     nweights = new TColStd_HArray1OfReal(1,nbpoles);
700   Handle(TColgp_HArray1OfPnt)
701     npoles = new TColgp_HArray1OfPnt(1,nbpoles);
702
703   k = 1;
704   if ( rational) {
705     nweights = new TColStd_HArray1OfReal( 1, nbpoles);
706     for ( i = pindex1; i <= pindex2; i++) {
707       npoles->SetValue(k, poles->Value(i));
708       nweights->SetValue(k, weights->Value(i));
709       k++;
710     }
711   }
712   else {
713     for ( i = pindex1; i <= pindex2; i++) {
714       npoles->SetValue(k, poles->Value(i));
715       k++;
716     }
717   }
718
719   //-- DBB
720   if( wasPeriodic ) {
721     nknots->ChangeValue(nknots->Lower()) = U1;
722     if( aNu2 < U2 ) {
723       nknots->ChangeValue(nknots->Upper()) = U1 + aDDU;
724     }
725   }
726   //-- DBB
727
728   knots = nknots;
729   mults = nmults;
730   poles = npoles;
731   if ( rational) 
732     weights = nweights;
733
734   maxderivinvok = 0;
735   UpdateKnots();
736 }
737
738 //=======================================================================
739 //function : SetKnot
740 //purpose  : 
741 //=======================================================================
742
743 void Geom_BSplineCurve::SetKnot
744 (const Standard_Integer Index,
745  const Standard_Real K)
746 {
747   if (Index < 1 || Index > knots->Length())     Standard_OutOfRange::Raise();
748   Standard_Real DK = Abs(Epsilon (K));
749   if (Index == 1) { 
750     if (K >= knots->Value(2) - DK) Standard_ConstructionError::Raise();
751   }
752   else if (Index == knots->Length()) {
753     if (K <= knots->Value (knots->Length()-1) + DK)  {
754       Standard_ConstructionError::Raise();
755     }
756   }
757   else {
758     if (K <= knots->Value(Index-1) + DK ||
759         K >= knots->Value(Index+1) - DK ) {
760       Standard_ConstructionError::Raise();
761     }
762   }
763   if (K != knots->Value (Index)) {
764     knots->SetValue (Index, K);
765     maxderivinvok = 0;
766     UpdateKnots();
767   }
768 }
769
770 //=======================================================================
771 //function : SetKnots
772 //purpose  : 
773 //=======================================================================
774
775 void Geom_BSplineCurve::SetKnots
776 (const TColStd_Array1OfReal& K)
777 {
778   CheckCurveData(poles->Array1(),K,mults->Array1(),deg,periodic);
779   knots->ChangeArray1() = K;
780   maxderivinvok = 0;
781   UpdateKnots();
782 }
783
784 //=======================================================================
785 //function : SetKnot
786 //purpose  : 
787 //=======================================================================
788
789 void Geom_BSplineCurve::SetKnot
790 (const Standard_Integer Index,
791  const Standard_Real K,
792  const Standard_Integer M)
793 {
794   IncreaseMultiplicity (Index, M);
795   SetKnot (Index, K);
796 }
797
798 //=======================================================================
799 //function : SetPeriodic
800 //purpose  : 
801 //=======================================================================
802
803 void Geom_BSplineCurve::SetPeriodic ()
804 {
805   Standard_Integer first = FirstUKnotIndex();
806   Standard_Integer last  = LastUKnotIndex();
807
808   Handle(TColStd_HArray1OfReal) tk = knots;
809   TColStd_Array1OfReal    cknots((knots->Array1())(first),first,last);
810   knots = new TColStd_HArray1OfReal(1,cknots.Length());
811   knots->ChangeArray1() = cknots;
812
813   Handle(TColStd_HArray1OfInteger) tm = mults;
814   TColStd_Array1OfInteger cmults((mults->Array1())(first),first,last);
815   cmults(first) = cmults(last) = Min(deg, Max( cmults(first), cmults(last)));
816   mults = new TColStd_HArray1OfInteger(1,cmults.Length());
817   mults->ChangeArray1() = cmults;
818
819   // compute new number of poles;
820   Standard_Integer nbp = BSplCLib::NbPoles(deg,Standard_True,cmults);
821   
822   Handle(TColgp_HArray1OfPnt) tp = poles;
823   TColgp_Array1OfPnt cpoles((poles->Array1())(1),1,nbp);
824   poles = new TColgp_HArray1OfPnt(1,nbp);
825   poles->ChangeArray1() = cpoles;
826   
827   if (rational) {
828     Handle(TColStd_HArray1OfReal) tw = weights;
829     TColStd_Array1OfReal cweights((weights->Array1())(1),1,nbp);
830     weights = new TColStd_HArray1OfReal(1,nbp);
831     weights->ChangeArray1() = cweights;
832   }
833
834   periodic = Standard_True;
835   
836   maxderivinvok = 0;
837   UpdateKnots();
838 }
839
840 //=======================================================================
841 //function : SetOrigin
842 //purpose  : 
843 //=======================================================================
844
845 void Geom_BSplineCurve::SetOrigin(const Standard_Integer Index)
846 {
847   Standard_NoSuchObject_Raise_if( !periodic,
848                                  "Geom_BSplineCurve::SetOrigin");
849   Standard_Integer i,k;
850   Standard_Integer first = FirstUKnotIndex();
851   Standard_Integer last  = LastUKnotIndex();
852
853   Standard_DomainError_Raise_if( (Index < first) || (Index > last),
854                                 "Geom_BSplineCurve::SetOrigine");
855
856   Standard_Integer nbknots = knots->Length();
857   Standard_Integer nbpoles = poles->Length();
858
859   Handle(TColStd_HArray1OfReal) nknots = 
860     new TColStd_HArray1OfReal(1,nbknots);
861   TColStd_Array1OfReal& newknots = nknots->ChangeArray1();
862
863   Handle(TColStd_HArray1OfInteger) nmults =
864     new TColStd_HArray1OfInteger(1,nbknots);
865   TColStd_Array1OfInteger& newmults = nmults->ChangeArray1();
866
867   // set the knots and mults
868   Standard_Real period = knots->Value(last) - knots->Value(first);
869   k = 1;
870   for ( i = Index; i <= last ; i++) {
871     newknots(k) = knots->Value(i);
872     newmults(k) = mults->Value(i);
873     k++;
874   }
875   for ( i = first+1; i <= Index; i++) {
876     newknots(k) = knots->Value(i) + period;
877     newmults(k) = mults->Value(i);
878     k++;
879   }
880
881   Standard_Integer index = 1;
882   for (i = first+1; i <= Index; i++) 
883     index += mults->Value(i);
884
885   // set the poles and weights
886   Handle(TColgp_HArray1OfPnt) npoles =
887     new TColgp_HArray1OfPnt(1,nbpoles);
888   Handle(TColStd_HArray1OfReal) nweights =
889     new TColStd_HArray1OfReal(1,nbpoles);
890   TColgp_Array1OfPnt   & newpoles   = npoles->ChangeArray1();
891   TColStd_Array1OfReal & newweights = nweights->ChangeArray1();
892   first = poles->Lower();
893   last  = poles->Upper();
894   if ( rational) {
895     k = 1;
896     for ( i = index; i <= last; i++) {
897       newpoles(k)   = poles->Value(i);
898       newweights(k) = weights->Value(i);
899       k++;
900     }
901     for ( i = first; i < index; i++) {
902       newpoles(k)   = poles->Value(i);
903       newweights(k) = weights->Value(i);
904       k++;
905     }
906   }
907   else {
908     k = 1;
909     for ( i = index; i <= last; i++) {
910       newpoles(k) = poles->Value(i);
911       k++;
912     }
913     for ( i = first; i < index; i++) {
914       newpoles(k) = poles->Value(i);
915       k++;
916     }
917   }
918
919   poles = npoles;
920   knots = nknots;
921   mults = nmults;
922   if (rational) 
923     weights = nweights;
924   maxderivinvok = 0;
925   UpdateKnots();
926 }
927
928 //=======================================================================
929 //function : SetOrigin
930 //purpose  : 
931 //=======================================================================
932
933 void Geom_BSplineCurve::SetOrigin(const Standard_Real U,
934                                   const Standard_Real Tol)
935 {
936   Standard_NoSuchObject_Raise_if( !periodic,
937                                  "Geom_BSplineCurve::SetOrigin");
938   //U est il dans la period.
939   Standard_Real uf = FirstParameter(), ul = LastParameter();
940   Standard_Real u = U, period = ul - uf;
941   while (Tol < (uf-u)) u += period;
942   while (Tol > (ul-u)) u -= period;
943
944   if(Abs(U-u)>Tol) { //On reparametre la courbe
945     Standard_Real delta = U-u;
946     uf += delta;
947     ul += delta;
948     TColStd_Array1OfReal& kn = knots->ChangeArray1();
949     Standard_Integer fk = kn.Lower(), lk = kn.Upper();
950     for(Standard_Integer i = fk; i <= lk; i++){
951       kn.ChangeValue(i) += delta;
952     }
953     UpdateKnots();
954   }
955   if(Abs(U-uf)<Tol) return;
956   
957   TColStd_Array1OfReal& kn = knots->ChangeArray1();
958   Standard_Integer fk = kn.Lower(), lk = kn.Upper(),ik=0;
959   Standard_Real delta = RealLast();
960   for(Standard_Integer i = fk; i<= lk; i++){
961     Standard_Real dki = kn.Value(i)-U;
962     if(Abs(dki)<Abs(delta)){
963       ik = i;
964       delta = dki;
965     }
966   }
967   if(Abs(delta)>Tol){
968     InsertKnot(U);
969     if(delta < 0.) ik++;
970   }
971   SetOrigin(ik);
972 }
973
974 //=======================================================================
975 //function : SetNotPeriodic
976 //purpose  : 
977 //=======================================================================
978
979 void Geom_BSplineCurve::SetNotPeriodic () 
980
981   if ( periodic) {
982     Standard_Integer NbKnots, NbPoles;
983     BSplCLib::PrepareUnperiodize( deg, mults->Array1(),NbKnots,NbPoles);
984     
985     Handle(TColgp_HArray1OfPnt) npoles 
986       = new TColgp_HArray1OfPnt(1,NbPoles);
987     
988     Handle(TColStd_HArray1OfReal) nknots 
989       = new TColStd_HArray1OfReal(1,NbKnots);
990     
991     Handle(TColStd_HArray1OfInteger) nmults
992       = new TColStd_HArray1OfInteger(1,NbKnots);
993     
994     Handle(TColStd_HArray1OfReal) nweights;
995     
996     if (IsRational()) {
997       
998       nweights = new TColStd_HArray1OfReal(1,NbPoles);
999       
1000       BSplCLib::Unperiodize
1001         (deg,mults->Array1(),knots->Array1(),poles->Array1(),
1002          weights->Array1(),nmults->ChangeArray1(),
1003          nknots->ChangeArray1(),npoles->ChangeArray1(),
1004          nweights->ChangeArray1());
1005       
1006     }
1007     else {
1008       
1009       BSplCLib::Unperiodize
1010         (deg,mults->Array1(),knots->Array1(),poles->Array1(),
1011          BSplCLib::NoWeights(),nmults->ChangeArray1(),
1012          nknots->ChangeArray1(),npoles->ChangeArray1(),
1013          *((TColStd_Array1OfReal*) NULL));
1014       
1015     }
1016     poles   = npoles;
1017     weights = nweights;
1018     mults   = nmults;
1019     knots   = nknots;
1020     periodic = Standard_False;
1021     
1022     maxderivinvok = 0;
1023     UpdateKnots();
1024   }
1025 }
1026
1027 //=======================================================================
1028 //function : SetPole
1029 //purpose  : 
1030 //=======================================================================
1031
1032 void Geom_BSplineCurve::SetPole
1033 (const Standard_Integer Index,
1034  const gp_Pnt& P)
1035 {
1036   if (Index < 1 || Index > poles->Length()) Standard_OutOfRange::Raise();
1037   poles->SetValue (Index, P);
1038   maxderivinvok = 0;
1039   InvalidateCache() ;
1040 }
1041
1042 //=======================================================================
1043 //function : SetPole
1044 //purpose  : 
1045 //=======================================================================
1046
1047 void Geom_BSplineCurve::SetPole
1048 (const Standard_Integer Index,
1049  const gp_Pnt& P,
1050  const Standard_Real W)
1051 {
1052   SetPole(Index,P);
1053   SetWeight(Index,W);
1054 }
1055
1056 //=======================================================================
1057 //function : SetWeight
1058 //purpose  : 
1059 //=======================================================================
1060
1061 void Geom_BSplineCurve::SetWeight
1062 (const Standard_Integer Index,
1063  const Standard_Real W)
1064 {
1065   if (Index < 1 || Index > poles->Length())   Standard_OutOfRange::Raise();
1066
1067   if (W <= gp::Resolution ())     Standard_ConstructionError::Raise();
1068
1069
1070   Standard_Boolean rat = IsRational() || (Abs(W - 1.) > gp::Resolution());
1071
1072   if ( rat) {
1073     if (rat && !IsRational()) {
1074       weights = new TColStd_HArray1OfReal(1,poles->Length());
1075       weights->Init(1.);
1076     }
1077     
1078     weights->SetValue (Index, W);
1079     
1080     if (IsRational()) {
1081       rat = Rational(weights->Array1());
1082       if (!rat) weights.Nullify();
1083     }
1084     
1085     rational = !weights.IsNull();
1086   }
1087   maxderivinvok = 0;
1088   InvalidateCache() ;
1089 }
1090
1091 //=======================================================================
1092 //function : MovePoint
1093 //purpose  : 
1094 //=======================================================================
1095
1096 void Geom_BSplineCurve::MovePoint(const Standard_Real U,
1097                                   const gp_Pnt& P,
1098                                   const Standard_Integer Index1,
1099                                   const Standard_Integer Index2,
1100                                   Standard_Integer& FirstModifiedPole,
1101                                   Standard_Integer& LastmodifiedPole)
1102 {
1103   if (Index1 < 1 || Index1 > poles->Length() || 
1104       Index2 < 1 || Index2 > poles->Length() || Index1 > Index2) {
1105     Standard_OutOfRange::Raise();
1106   }
1107   TColgp_Array1OfPnt npoles(1, poles->Length());
1108   gp_Pnt P0;
1109   D0(U, P0);
1110   gp_Vec Displ(P0, P);
1111   BSplCLib::MovePoint(U, Displ, Index1, Index2, deg, rational, poles->Array1(), 
1112                       weights->Array1(), flatknots->Array1(), 
1113                       FirstModifiedPole, LastmodifiedPole, npoles);
1114   if (FirstModifiedPole) {
1115     poles->ChangeArray1() = npoles;
1116     maxderivinvok = 0;
1117     InvalidateCache() ;
1118   }
1119 }
1120
1121 //=======================================================================
1122 //function : MovePointAndTangent
1123 //purpose  : 
1124 //=======================================================================
1125
1126 void Geom_BSplineCurve::
1127 MovePointAndTangent(const Standard_Real U,
1128                     const gp_Pnt&       P,
1129                     const gp_Vec&       Tangent,
1130                     const Standard_Real    Tolerance,
1131                     const Standard_Integer StartingCondition,
1132                     const Standard_Integer EndingCondition,
1133                     Standard_Integer&      ErrorStatus) 
1134 {
1135   Standard_Integer ii ;
1136   if (IsPeriodic()) {
1137     //
1138     // for the time being do not deal with periodic curves
1139     //
1140     SetNotPeriodic() ;
1141   }
1142   TColgp_Array1OfPnt new_poles(1, poles->Length());
1143   gp_Pnt P0;
1144
1145
1146   gp_Vec delta_derivative;
1147   D1(U, P0,
1148      delta_derivative) ;
1149   gp_Vec delta(P0, P);
1150   for (ii = 1 ; ii <= 3 ; ii++) {
1151     delta_derivative.SetCoord(ii, 
1152                               Tangent.Coord(ii)- delta_derivative.Coord(ii)) ;
1153   }
1154   BSplCLib::MovePointAndTangent(U,
1155                                 delta,
1156                                 delta_derivative,
1157                                 Tolerance,
1158                                 deg,
1159                                 rational,
1160                                 StartingCondition,
1161                                 EndingCondition,
1162                                 poles->Array1(), 
1163                                 weights->Array1(), 
1164                                 flatknots->Array1(), 
1165                                 new_poles,
1166                                 ErrorStatus) ;
1167   if (!ErrorStatus) {
1168     poles->ChangeArray1() = new_poles;
1169     maxderivinvok = 0;
1170     InvalidateCache() ;
1171   }
1172 }
1173
1174 //=======================================================================
1175 //function : UpdateKnots
1176 //purpose  : 
1177 //=======================================================================
1178
1179 void Geom_BSplineCurve::UpdateKnots()
1180 {
1181   rational = !weights.IsNull();
1182
1183   Standard_Integer MaxKnotMult = 0;
1184   KnotAnalysis (deg, 
1185                 periodic,
1186                 knots->Array1(), 
1187                 mults->Array1(), 
1188                 knotSet, MaxKnotMult);
1189   
1190   if (knotSet == GeomAbs_Uniform && !periodic)  {
1191     flatknots = knots;
1192   }
1193   else {
1194     flatknots = new TColStd_HArray1OfReal 
1195       (1, BSplCLib::KnotSequenceLength(mults->Array1(),deg,periodic));
1196
1197     BSplCLib::KnotSequence (knots->Array1(), 
1198                             mults->Array1(),
1199                             deg,periodic,
1200                             flatknots->ChangeArray1());
1201   }
1202   
1203   if (MaxKnotMult == 0)  smooth = GeomAbs_CN;
1204   else {
1205     switch (deg - MaxKnotMult) {
1206     case 0 :   smooth = GeomAbs_C0;   break;
1207     case 1 :   smooth = GeomAbs_C1;   break;
1208     case 2 :   smooth = GeomAbs_C2;   break;
1209     case 3 :   smooth = GeomAbs_C3;   break;
1210       default :  smooth = GeomAbs_C3;   break;
1211     }
1212   }
1213   InvalidateCache() ;
1214 }
1215
1216 //=======================================================================
1217 //function : Invalidate the Cache
1218 //purpose  : as the name says
1219 //=======================================================================
1220
1221 void Geom_BSplineCurve::InvalidateCache() 
1222 {
1223   validcache = 0 ;
1224 }
1225
1226 //=======================================================================
1227 //function : check if the Cache is valid
1228 //purpose  : as the name says
1229 //=======================================================================
1230
1231 Standard_Boolean Geom_BSplineCurve::IsCacheValid
1232 (const Standard_Real  U)  const 
1233 {
1234   //Roman Lygin 26.12.08, performance improvements
1235   //1. avoided using NewParameter = (U - parametercache) / spanlenghtcache
1236   //to check against [0, 1), as division is CPU consuming
1237   //2. minimized use of if, as branching is also CPU consuming
1238   Standard_Real aDelta = U - parametercache;
1239
1240   return ( validcache &&
1241       (aDelta >= 0.0e0) &&
1242       ((aDelta < spanlenghtcache) || (spanindexcache == flatknots->Upper() - deg)) );
1243 }
1244
1245 //=======================================================================
1246 //function : Normalizes the parameters if the curve is periodic
1247 //purpose  : that is compute the cache so that it is valid
1248 //=======================================================================
1249
1250 void Geom_BSplineCurve::PeriodicNormalization(Standard_Real&  Parameter) const 
1251 {
1252   Standard_Real Period ;
1253
1254   if (periodic) {
1255     Period = flatknots->Value(flatknots->Upper() - deg) - flatknots->Value (deg + 1) ;
1256     while (Parameter > flatknots->Value(flatknots->Upper()-deg)) {
1257       Parameter -= Period ;
1258     }
1259     while (Parameter < flatknots->Value((deg + 1))) {
1260       Parameter +=  Period ;
1261     }
1262   }
1263 }
1264
1265 //=======================================================================
1266 //function : Validate the Cache
1267 //purpose  : that is compute the cache so that it is valid
1268 //=======================================================================
1269
1270 void Geom_BSplineCurve::ValidateCache(const Standard_Real  Parameter) 
1271 {
1272   Standard_Real NewParameter ;
1273   Standard_Integer LocalIndex = 0 ;
1274   //
1275   // check if the degree did not change
1276   //
1277   if (cachepoles->Upper() < deg + 1) {
1278     cachepoles = new TColgp_HArray1OfPnt(1,deg + 1);
1279     if (rational) {
1280       cacheweights  = new TColStd_HArray1OfReal(1,deg + 1);
1281     }
1282   }
1283   BSplCLib::LocateParameter(deg,
1284                             (flatknots->Array1()),
1285                             (BSplCLib::NoMults()),
1286                             Parameter,
1287                             periodic,
1288                             LocalIndex,
1289                             NewParameter);
1290   spanindexcache = LocalIndex ;
1291   if (Parameter == flatknots->Value(LocalIndex + 1)) {
1292     
1293     LocalIndex += 1 ;
1294     parametercache = flatknots->Value(LocalIndex) ;
1295     if (LocalIndex == flatknots->Upper() - deg) {
1296       //
1297       // for the last span if the parameter is outside of 
1298       // the domain of the curve than use the last knot
1299       // and normalize with the last span Still set the
1300       // spanindexcache to flatknots->Upper() - deg so that
1301       // the IsCacheValid will know for sure we are extending
1302       // the Bspline 
1303       //
1304       
1305       spanlenghtcache = flatknots->Value(LocalIndex - 1) - parametercache ;
1306     }
1307     else {
1308       spanlenghtcache = flatknots->Value(LocalIndex + 1) - parametercache ;
1309     }
1310   }
1311   else {
1312     parametercache = flatknots->Value(LocalIndex) ;
1313     spanlenghtcache = flatknots->Value(LocalIndex + 1) - parametercache ;
1314   }
1315   
1316   if  (rational) {
1317     BSplCLib::BuildCache(parametercache,
1318                          spanlenghtcache,
1319                          periodic,
1320                          deg,
1321                          (flatknots->Array1()),
1322                          poles->Array1(),
1323                          weights->Array1(),
1324                          cachepoles->ChangeArray1(),
1325                          cacheweights->ChangeArray1()) ;
1326   }
1327   else {
1328     BSplCLib::BuildCache(parametercache,
1329                          spanlenghtcache,
1330                          periodic,
1331                          deg,
1332                          (flatknots->Array1()),
1333                          poles->Array1(),
1334                          *((TColStd_Array1OfReal*) NULL),
1335                          cachepoles->ChangeArray1(),
1336                          *((TColStd_Array1OfReal*) NULL)) ;
1337   }
1338   validcache = 1 ;
1339 }
1340