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