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