0030754: Coding - the array of weights should begin with Lower, not the constant...
[occt.git] / src / Geom2d / Geom2d_BSplineCurve.cxx
CommitLineData
b311480e 1// Created on: 1993-03-25
2// Created by: JCV
3// Copyright (c) 1993-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 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
973c2be1 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.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
7fd59977 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
42cf5bc1 31
7fd59977 32#include <BSplCLib.hxx>
33#include <BSplCLib_KnotDistribution.hxx>
34#include <BSplCLib_MultDistribution.hxx>
42cf5bc1 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>
7b1c1b7c 42#include <Precision.hxx>
7fd59977 43#include <Standard_ConstructionError.hxx>
42cf5bc1 44#include <Standard_DimensionError.hxx>
45#include <Standard_DomainError.hxx>
46#include <Standard_NoSuchObject.hxx>
47#include <Standard_NotImplemented.hxx>
7fd59977 48#include <Standard_OutOfRange.hxx>
42cf5bc1 49#include <Standard_RangeError.hxx>
50#include <Standard_Type.hxx>
7fd59977 51
92efcf78 52IMPLEMENT_STANDARD_RTTIEXT(Geom2d_BSplineCurve,Geom2d_BoundedCurve)
53
7fd59977 54//=======================================================================
55//function : CheckCurveData
56//purpose : Internal use only
57//=======================================================================
7fd59977 58static 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()) {
1b827f04 66 throw Standard_ConstructionError("BSpline curve: invalid degree");
7fd59977 67 }
68
1b827f04
BB
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");
7fd59977 71
72 for (Standard_Integer I = CKnots.Lower(); I < CKnots.Upper(); I++) {
73 if (CKnots (I+1) - CKnots (I) <= Epsilon (Abs(CKnots (I)))) {
1b827f04 74 throw Standard_ConstructionError("BSpline curve: Knots interval values too close");
7fd59977 75 }
76 }
77
78 if (CPoles.Length() != BSplCLib::NbPoles(Degree,Periodic,CMults))
1b827f04 79 throw Standard_ConstructionError("BSpline curve: # Poles and degree mismatch");
7fd59977 80}
81
6b41f0f3 82//! Check rationality of an array of weights
83static Standard_Boolean Rational (const TColStd_Array1OfReal& theWeights)
7fd59977 84{
6b41f0f3 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 }
7fd59977 91 }
6b41f0f3 92 return Standard_False;
7fd59977 93}
94
95//=======================================================================
96//function : Copy
97//purpose :
98//=======================================================================
99
100Handle(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
122Geom2d_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
94f71cad 135 CheckCurveData(Poles,
136 Knots,
137 Mults,
138 Degree,
139 Periodic);
7fd59977 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();
7fd59977 153}
154
155//=======================================================================
156//function : Geom2d_BSplineCurve
157//purpose :
158//=======================================================================
159
160Geom2d_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
94f71cad 176 CheckCurveData(Poles,
177 Knots,
178 Mults,
179 Degree,
180 Periodic);
7fd59977 181
182 if (Weights.Length() != Poles.Length())
1b827f04 183 throw Standard_ConstructionError("Geom2d_BSplineCurve: Weights and Poles array size mismatch");
7fd59977 184
185 Standard_Integer i;
186 for (i = Weights.Lower(); i <= Weights.Upper(); i++) {
187 if (Weights(i) <= gp::Resolution()) {
9775fa61 188 throw Standard_ConstructionError("Geom2d_BSplineCurve: Weights values too small");
7fd59977 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;
7fd59977 199 if (rational) {
200 weights = new TColStd_HArray1OfReal(1,Weights.Length());
201 weights->ChangeArray1() = Weights;
7fd59977 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();
7fd59977 211}
212
213//=======================================================================
214//function : MaxDegree
215//purpose :
216//=======================================================================
217
218Standard_Integer Geom2d_BSplineCurve::MaxDegree ()
219{
220 return BSplCLib::MaxDegree();
221}
222
223//=======================================================================
224//function : IncreaseDegree
225//purpose :
226//=======================================================================
227
228void Geom2d_BSplineCurve::IncreaseDegree
229(const Standard_Integer Degree)
230{
231 if (Degree == deg) return;
232
233 if (Degree < deg || Degree > Geom2d_BSplineCurve::MaxDegree()) {
1b827f04 234 throw Standard_ConstructionError("BSpline curve: IncreaseDegree: bad degree value");
7fd59977 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()) {
7fd59977 257 nweights = new TColStd_HArray1OfReal(1,npoles->Upper());
7fd59977 258 }
7fd59977 259
aff73fd5 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());
7fd59977 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
279void 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
295void 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
314void 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
331void 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//=======================================================================
347void 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(),
0e14656b 357 Knots,&Mults,nbpoles,nbknots,Epsilon,Add))
9775fa61 358 throw Standard_ConstructionError("Geom2d_BSplineCurve::InsertKnots");
7fd59977 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
aff73fd5 371 Handle(TColStd_HArray1OfReal) nweights;
372 if (rational)
373 {
374 nweights = new TColStd_HArray1OfReal (1, nbpoles);
7fd59977 375 }
376
aff73fd5 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;
7fd59977 385 poles = npoles;
386 knots = nknots;
387 mults = nmults;
388 UpdateKnots();
7fd59977 389}
390
391//=======================================================================
392//function : RemoveKnot
393//purpose :
394//=======================================================================
395
396Standard_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) {
1b827f04 407 throw Standard_OutOfRange("BSpline curve: RemoveKnot: index out of range");
7fd59977 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
aff73fd5 426 Handle(TColStd_HArray1OfReal) nweights;
427 if (IsRational())
428 {
429 nweights = new TColStd_HArray1OfReal(1,npoles->Length());
7fd59977 430 }
aff73fd5 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;
7fd59977 440 }
aff73fd5 441
442 weights = nweights;
7fd59977 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
457void Geom2d_BSplineCurve::InsertPoleAfter
458(const Standard_Integer Index,
459 const gp_Pnt2d& P,
460 const Standard_Real Weight)
461{
1b827f04 462 if (Index < 0 || Index > poles->Length()) throw Standard_OutOfRange("BSpline curve: InsertPoleAfter: Index and #pole mismatch");
7fd59977 463
1b827f04 464 if (Weight <= gp::Resolution()) throw Standard_ConstructionError("BSpline curve: InsertPoleAfter: Weight too small");
7fd59977 465
466 if (knotSet == GeomAbs_NonUniform || knotSet == GeomAbs_PiecewiseBezier) {
1b827f04 467 throw Standard_ConstructionError("BSpline curve: InsertPoleAfter: bad knotSet type");
7fd59977 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
548void 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
561void Geom2d_BSplineCurve::RemovePole
562(const Standard_Integer Index)
563{
1b827f04 564 if (Index < 1 || Index > poles->Length()) throw Standard_OutOfRange("BSpline curve: RemovePole: Index and #pole mismatch");
7fd59977 565
1b827f04 566 if (poles->Length() <= 2) throw Standard_ConstructionError("BSpline curve: RemovePole: #pole is already minimum");
7fd59977 567
568 if (knotSet == GeomAbs_NonUniform || knotSet == GeomAbs_PiecewiseBezier)
1b827f04 569 throw Standard_ConstructionError("BSpline curve: RemovePole: bad knotSet type");
7fd59977 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
620void 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
640Standard_Real Geom2d_BSplineCurve::ReversedParameter( const Standard_Real U) const
641{
642 return (FirstParameter() + LastParameter() - U);
643}
644
645//=======================================================================
646//function : Segment
647//purpose :
648//=======================================================================
649void Geom2d_BSplineCurve::Segment(const Standard_Real aU1,
6fd9bdf2 650 const Standard_Real aU2,
651 const Standard_Real theTolerance)
7fd59977 652{
369a38aa 653 if (aU2 < aU1)
9775fa61 654 throw Standard_DomainError("Geom2d_BSplineCurve::Segment");
7fd59977 655 //
656 Standard_Real AbsUMax = Max(Abs(FirstParameter()),Abs(LastParameter()));
6fd9bdf2 657 Standard_Real Eps = Max (Epsilon(AbsUMax), theTolerance);
7fd59977 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;
369a38aa 694 if (DU - Period > Precision::PConfusion())
9775fa61 695 throw Standard_DomainError("Geom2d_BSplineCurve::Segment");
369a38aa 696 if (DU > Period)
7fd59977 697 DU = Period;
7fd59977 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
809void Geom2d_BSplineCurve::SetKnot
810(const Standard_Integer Index,
811 const Standard_Real K)
812{
1b827f04 813 if (Index < 1 || Index > knots->Length()) throw Standard_OutOfRange("BSpline curve: SetKnot: Index and #knots mismatch");
7fd59977 814 Standard_Real DK = Abs(Epsilon (K));
815 if (Index == 1) {
1b827f04 816 if (K >= knots->Value(2) - DK) throw Standard_ConstructionError("BSpline curve: SetKnot: K out of range");
7fd59977 817 }
818 else if (Index == knots->Length()) {
819 if (K <= knots->Value (knots->Length()-1) + DK) {
1b827f04 820 throw Standard_ConstructionError("BSpline curve: SetKnot: K out of range");
7fd59977 821 }
822 }
823 else {
824 if (K <= knots->Value(Index-1) + DK ||
825 K >= knots->Value(Index+1) - DK ) {
1b827f04 826 throw Standard_ConstructionError("BSpline curve: SetKnot: K out of range");
7fd59977 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
841void 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
855void 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
869void 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
911void Geom2d_BSplineCurve::SetOrigin(const Standard_Integer Index)
912{
369a38aa 913 if (!periodic)
9775fa61 914 throw Standard_NoSuchObject("Geom2d_BSplineCurve::SetOrigin");
7fd59977 915 Standard_Integer i,k;
916 Standard_Integer first = FirstUKnotIndex();
917 Standard_Integer last = LastUKnotIndex();
918
369a38aa 919 if ((Index < first) || (Index > last))
9775fa61 920 throw Standard_DomainError("Geom2d_BSplineCurve::SetOrigin");
7fd59977 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
999void 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;
7fd59977 1015 if (IsRational()) {
7fd59977 1016 nweights = new TColStd_HArray1OfReal(1,NbPoles);
7fd59977 1017 }
aff73fd5 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());
7fd59977 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
1039void Geom2d_BSplineCurve::SetPole
1040(const Standard_Integer Index,
1041 const gp_Pnt2d& P)
1042{
1b827f04 1043 if (Index < 1 || Index > poles->Length()) throw Standard_OutOfRange("BSpline curve: SetPole: index and #pole mismatch");
7fd59977 1044 poles->SetValue (Index, P);
1045 maxderivinvok = 0;
7fd59977 1046}
1047
1048//=======================================================================
1049//function : SetPole
1050//purpose :
1051//=======================================================================
1052
1053void 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
1067void Geom2d_BSplineCurve::SetWeight
1068(const Standard_Integer Index,
1069 const Standard_Real W)
1070{
1b827f04 1071 if (Index < 1 || Index > poles->Length()) throw Standard_OutOfRange("BSpline curve: SetWeight: Index and #pole mismatch");
7fd59977 1072
1b827f04 1073 if (W <= gp::Resolution ()) throw Standard_ConstructionError("BSpline curve: SetWeight: Weight too small");
7fd59977 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;
7fd59977 1095}
1096
1097//=======================================================================
1098//function : MovePoint
1099//purpose :
1100//=======================================================================
1101
1102void Geom2d_BSplineCurve::MovePoint(const Standard_Real U,
94f71cad 1103 const gp_Pnt2d& P,
1104 const Standard_Integer Index1,
1105 const Standard_Integer Index2,
1106 Standard_Integer& FirstModifiedPole,
1107 Standard_Integer& LastmodifiedPole)
7fd59977 1108{
1109 if (Index1 < 1 || Index1 > poles->Length() ||
1110 Index2 < 1 || Index2 > poles->Length() || Index1 > Index2) {
1b827f04 1111 throw Standard_OutOfRange("BSpline curve: MovePoint: Index and #pole mismatch");
7fd59977 1112 }
1113 TColgp_Array1OfPnt2d npoles(1, poles->Length());
1114 gp_Pnt2d P0;
1115 D0(U, P0);
1116 gp_Vec2d Displ(P0, P);
aff73fd5 1117
1118 BSplCLib::MovePoint (U, Displ, Index1, Index2, deg, poles->Array1(),
1119 rational ? &weights->Array1() : BSplCLib::NoWeights(), flatknots->Array1(),
1120 FirstModifiedPole, LastmodifiedPole, npoles);
7fd59977 1121 if (FirstModifiedPole) {
1122 poles->ChangeArray1() = npoles;
1123 maxderivinvok = 0;
7fd59977 1124 }
1125}
1126
1127//=======================================================================
1128//function : MovePointAndTangent
1129//purpose :
1130//=======================================================================
1131
1132void Geom2d_BSplineCurve::
1133MovePointAndTangent(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 }
aff73fd5 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);
7fd59977 1173 if (!ErrorStatus) {
1174 poles->ChangeArray1() = new_poles;
1175 maxderivinvok = 0;
7fd59977 1176 }
1177}
1178
1179//=======================================================================
1180//function : UpdateKnots
1181//purpose :
1182//=======================================================================
1183
1184void Geom2d_BSplineCurve::UpdateKnots()
1185{
1186
1187 rational = !weights.IsNull();
1188
1189 Standard_Integer MaxKnotMult = 0;
06be28a4 1190 BSplCLib::KnotAnalysis (deg,
7fd59977 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 }
7fd59977 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
1226void 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