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