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