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