0022939: Make B-Spline internal cache thread-safe to be used in multy-threaded mode
[occt.git] / src / Geom / Geom_BSplineCurve_1.cxx
1 // Created on: 1991-07-05
2 // Created by: JCV
3 // Copyright (c) 1991-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
5 //
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
10 //
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 //
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
20
21
22
23 // 03-02-97 : pmn ->LocateU sur Periodic (PRO6963), 
24 //            bon appel a LocateParameter (PRO6973) et mise en conformite avec
25 //            le cdl de LocateU, lorsque U est un noeud (PRO6988)
26
27 #define No_Standard_OutOfRange
28 #define No_Standard_DimensionError
29
30 #include <Geom_BSplineCurve.jxx>
31 #include <BSplCLib.hxx>
32 #include <gp.hxx>
33
34 #include <Geom_UndefinedDerivative.hxx>
35 #include <Standard_DimensionError.hxx>
36 #include <Standard_OutOfRange.hxx>
37 #include <Standard_DomainError.hxx>
38 #include <Standard_RangeError.hxx>
39 #include <Standard_Mutex.hxx>
40
41 #define  POLES    (poles->Array1())
42 #define  KNOTS    (knots->Array1())
43 #define  FKNOTS   (flatknots->Array1())
44 #define  FMULTS   (BSplCLib::NoMults())
45
46 //=======================================================================
47 //function : IsCN
48 //purpose  : 
49 //=======================================================================
50
51 Standard_Boolean Geom_BSplineCurve::IsCN ( const Standard_Integer N) const
52 {
53   Standard_RangeError_Raise_if
54     (N < 0, "Geom_BSplineCurve::IsCN");
55
56   switch (smooth) {
57   case GeomAbs_CN : return Standard_True;
58   case GeomAbs_C0 : return N <= 0;
59   case GeomAbs_G1 : return N <= 0;
60   case GeomAbs_C1 : return N <= 1;
61   case GeomAbs_G2 : return N <= 1;
62   case GeomAbs_C2 : return N <= 2;
63   case GeomAbs_C3 : 
64     return N <= 3 ? Standard_True :
65            N <= deg - BSplCLib::MaxKnotMult (mults->Array1(), mults->Lower() + 1, mults->Upper() - 1);
66   default:
67     return Standard_False;
68   }
69 }
70
71 //=======================================================================
72 //function : IsClosed
73 //purpose  : 
74 //=======================================================================
75
76 Standard_Boolean Geom_BSplineCurve::IsClosed () const
77 //-- { return (StartPoint().Distance (EndPoint())) <= gp::Resolution (); }
78 { return (StartPoint().SquareDistance(EndPoint())) <= 1e-16; }
79
80 //=======================================================================
81 //function : IsPeriodic
82 //purpose  : 
83 //=======================================================================
84
85 Standard_Boolean Geom_BSplineCurve::IsPeriodic () const
86 { return periodic; }
87
88 //=======================================================================
89 //function : Continuity
90 //purpose  : 
91 //=======================================================================
92
93 GeomAbs_Shape Geom_BSplineCurve::Continuity () const
94 { return smooth; }
95
96 //=======================================================================
97 //function : Degree
98 //purpose  : 
99 //=======================================================================
100
101 Standard_Integer Geom_BSplineCurve::Degree () const
102 { return deg; }
103
104 //=======================================================================
105 //function : D0
106 //purpose  : 
107 //=======================================================================
108
109 void Geom_BSplineCurve::D0(const Standard_Real U, gp_Pnt& P) const 
110 {
111   Standard_Real NewU(U);
112   PeriodicNormalization(NewU);
113
114   Geom_BSplineCurve* MyCurve = (Geom_BSplineCurve *) this;
115   Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
116
117   if(!IsCacheValid(NewU)) 
118     MyCurve->ValidateCache(NewU);
119
120   if(rational)
121   {
122     BSplCLib::CacheD0(NewU,
123       deg,
124       parametercache,
125       spanlenghtcache,
126       cachepoles->Array1(),
127       cacheweights->Array1(),
128       P);
129   }
130   else
131   {
132     BSplCLib::CacheD0(NewU,
133       deg,
134       parametercache,
135       spanlenghtcache,
136       cachepoles->Array1(),
137       *((TColStd_Array1OfReal*) NULL),
138       P);
139   }
140 }
141
142 //=======================================================================
143 //function : D1
144 //purpose  : 
145 //=======================================================================
146
147 void Geom_BSplineCurve::D1 (const Standard_Real U,
148                                   gp_Pnt& P,
149                                   gp_Vec& V1) const
150 {
151   Standard_Real NewU(U);
152   PeriodicNormalization(NewU);
153
154   Geom_BSplineCurve* MyCurve = (Geom_BSplineCurve *) this;
155   Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
156
157   if(!IsCacheValid(NewU)) 
158     MyCurve->ValidateCache(NewU);
159
160   if(rational)
161   {
162     BSplCLib::CacheD1(NewU,
163       deg,
164       parametercache,
165       spanlenghtcache,
166       cachepoles->Array1(),
167       cacheweights->Array1(),
168       P,
169       V1);
170   }
171   else
172   {
173     BSplCLib::CacheD1(NewU,
174       deg,
175       parametercache,
176       spanlenghtcache,
177       cachepoles->Array1(),
178       *((TColStd_Array1OfReal*) NULL),
179       P,
180       V1);
181   }
182 }
183
184 //=======================================================================
185 //function : D2
186 //purpose  : 
187 //=======================================================================
188
189 void Geom_BSplineCurve::D2(const Standard_Real U,
190                            gp_Pnt& P,
191                            gp_Vec& V1,
192                            gp_Vec& V2) const
193 {
194   Standard_Real NewU(U);
195   PeriodicNormalization(NewU);
196
197   Geom_BSplineCurve* MyCurve = (Geom_BSplineCurve *) this;
198   Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
199
200   if(!IsCacheValid(NewU)) 
201     MyCurve->ValidateCache(NewU);
202
203   if(rational)
204   {
205     BSplCLib::CacheD2(NewU,
206                       deg,
207                       parametercache,
208                       spanlenghtcache,
209                       (cachepoles->Array1()),
210                       cacheweights->Array1(),
211                       P,
212                       V1,
213                       V2);
214   }
215   else {
216     BSplCLib::CacheD2(NewU,
217                       deg,
218                       parametercache,
219                       spanlenghtcache,
220                       (cachepoles->Array1()),
221                       *((TColStd_Array1OfReal*) NULL),
222                       P,
223                       V1,
224                       V2);
225   }
226 }
227
228 //=======================================================================
229 //function : D3
230 //purpose  : 
231 //=======================================================================
232
233 void Geom_BSplineCurve::D3(const Standard_Real U,
234                            gp_Pnt& P,
235                            gp_Vec& V1,
236                            gp_Vec& V2,
237                            gp_Vec& V3) const
238 {
239   
240   Standard_Real NewU(U);
241   PeriodicNormalization(NewU);
242
243   Geom_BSplineCurve* MyCurve = (Geom_BSplineCurve *) this;
244   Standard_Mutex::Sentry aSentry(MyCurve->myMutex);
245
246   if(!IsCacheValid(NewU)) 
247     MyCurve->ValidateCache(NewU);
248
249   if(rational)
250   {
251     BSplCLib::CacheD3(NewU,
252                       deg,
253                       parametercache,
254                       spanlenghtcache,
255                       (cachepoles->Array1()),
256                       cacheweights->Array1(),
257                       P,
258                       V1,
259                       V2,
260                       V3) ;
261   }
262   else
263   {
264     BSplCLib::CacheD3(NewU,
265                       deg,
266                       parametercache,
267                       spanlenghtcache,
268                       cachepoles->Array1(),
269                       *((TColStd_Array1OfReal*) NULL),
270                       P,
271                       V1,
272                       V2,
273                       V3) ;
274   }
275 }
276
277 //=======================================================================
278 //function : DN
279 //purpose  : 
280 //=======================================================================
281
282 gp_Vec Geom_BSplineCurve::DN  (const Standard_Real    U,
283                                const Standard_Integer N ) const
284 {
285   gp_Vec V;
286   if (rational) {
287     BSplCLib::DN(U,N,0,deg,periodic,POLES,
288                  weights->Array1(),
289                  FKNOTS,FMULTS,V);
290   }
291   else {
292     BSplCLib::DN(U,N,0,deg,periodic,POLES,
293                  *((TColStd_Array1OfReal*) NULL),
294                  FKNOTS,FMULTS,V);
295   }
296   return V;
297 }
298
299 //=======================================================================
300 //function : EndPoint
301 //purpose  : 
302 //=======================================================================
303
304 gp_Pnt Geom_BSplineCurve::EndPoint () const
305
306   if (mults->Value (knots->Upper ()) == deg + 1) 
307     return poles->Value (poles->Upper());
308   else
309     return Value(LastParameter());
310 }
311
312 //=======================================================================
313 //function : FirstUKnotIndex
314 //purpose  : 
315 //=======================================================================
316
317 Standard_Integer Geom_BSplineCurve::FirstUKnotIndex () const
318
319   if (periodic) return 1;
320   else return BSplCLib::FirstUKnotIndex (deg, mults->Array1()); 
321 }
322
323 //=======================================================================
324 //function : FirstParameter
325 //purpose  : 
326 //=======================================================================
327
328 Standard_Real Geom_BSplineCurve::FirstParameter () const
329 {
330   return flatknots->Value (deg+1); 
331 }
332
333 //=======================================================================
334 //function : Knot
335 //purpose  : 
336 //=======================================================================
337
338 Standard_Real Geom_BSplineCurve::Knot (const Standard_Integer Index) const
339 {
340   Standard_OutOfRange_Raise_if
341     (Index < 1 || Index > knots->Length(), "Geom_BSplineCurve::Knot");
342   return knots->Value (Index);
343 }
344
345 //=======================================================================
346 //function : KnotDistribution
347 //purpose  : 
348 //=======================================================================
349
350 GeomAbs_BSplKnotDistribution Geom_BSplineCurve::KnotDistribution () const
351
352   return knotSet; 
353 }
354
355 //=======================================================================
356 //function : Knots
357 //purpose  : 
358 //=======================================================================
359
360 void Geom_BSplineCurve::Knots (TColStd_Array1OfReal& K) const
361 {
362   Standard_DimensionError_Raise_if
363     (K.Length() != knots->Length(), "Geom_BSplineCurve::Knots");
364   K = knots->Array1();
365 }
366
367 //=======================================================================
368 //function : KnotSequence
369 //purpose  : 
370 //=======================================================================
371
372 void Geom_BSplineCurve::KnotSequence (TColStd_Array1OfReal& K) const
373 {
374   Standard_DimensionError_Raise_if
375     (K.Length() != flatknots->Length(), "Geom_BSplineCurve::KnotSequence");
376   K = flatknots->Array1();
377 }
378
379 //=======================================================================
380 //function : LastUKnotIndex
381 //purpose  : 
382 //=======================================================================
383
384 Standard_Integer Geom_BSplineCurve::LastUKnotIndex() const
385 {
386   if (periodic) return knots->Length();
387   else return BSplCLib::LastUKnotIndex (deg, mults->Array1()); 
388 }
389
390 //=======================================================================
391 //function : LastParameter
392 //purpose  : 
393 //=======================================================================
394
395 Standard_Real Geom_BSplineCurve::LastParameter () const
396 {
397   return flatknots->Value (flatknots->Upper()-deg); 
398 }
399
400 //=======================================================================
401 //function : LocalValue
402 //purpose  : 
403 //=======================================================================
404
405 gp_Pnt Geom_BSplineCurve::LocalValue
406   (const Standard_Real    U,
407    const Standard_Integer FromK1,
408    const Standard_Integer ToK2)   const
409 {
410   gp_Pnt P;
411   LocalD0(U,FromK1,ToK2,P);
412   return P;
413 }
414
415 //=======================================================================
416 //function : LocalD0
417 //purpose  : 
418 //=======================================================================
419
420 void  Geom_BSplineCurve::LocalD0
421   (const Standard_Real    U,
422    const Standard_Integer FromK1,
423    const Standard_Integer ToK2,
424    gp_Pnt& P)   const
425 {
426   Standard_DomainError_Raise_if (FromK1 == ToK2,
427                                  "Geom_BSplineCurve::LocalValue");
428
429   Standard_Real u = U;
430   Standard_Integer index = 0;
431   BSplCLib::LocateParameter(deg, FKNOTS, U, periodic,FromK1,ToK2, index,u);
432   index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
433   if (rational) {
434     BSplCLib::D0(u,index,deg,periodic,POLES,
435                  weights->Array1(),
436                  FKNOTS,FMULTS,P);
437   }
438   else {
439     BSplCLib::D0(u,index,deg,periodic,POLES,
440                  *((TColStd_Array1OfReal*) NULL),
441                  FKNOTS,FMULTS,P);
442   }
443 }
444
445 //=======================================================================
446 //function : LocalD1
447 //purpose  : 
448 //=======================================================================
449
450 void Geom_BSplineCurve::LocalD1 (const Standard_Real    U,
451                                  const Standard_Integer FromK1,
452                                  const Standard_Integer ToK2,
453                                  gp_Pnt&    P, 
454                                  gp_Vec&    V1)    const
455 {
456   Standard_DomainError_Raise_if (FromK1 == ToK2,
457                                  "Geom_BSplineCurve::LocalD1");
458   
459   Standard_Real u = U;
460   Standard_Integer index = 0;
461   BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
462   index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
463   if (rational) {
464     BSplCLib::D1(u,index,deg,periodic,POLES,
465                  weights->Array1(),
466                  FKNOTS,FMULTS,P,V1);
467   }
468   else {
469     BSplCLib::D1(u,index,deg,periodic,POLES,
470                  *((TColStd_Array1OfReal*) NULL),
471                  FKNOTS,FMULTS,P,V1);
472   }
473 }
474
475 //=======================================================================
476 //function : LocalD2
477 //purpose  : 
478 //=======================================================================
479
480 void Geom_BSplineCurve::LocalD2
481   (const Standard_Real    U,
482    const Standard_Integer FromK1,
483    const Standard_Integer ToK2, 
484    gp_Pnt&    P,
485    gp_Vec&    V1,
486    gp_Vec&    V2) const
487 {
488   Standard_DomainError_Raise_if (FromK1 == ToK2,
489                                  "Geom_BSplineCurve::LocalD2");
490   
491   Standard_Real u = U;
492   Standard_Integer index = 0;
493   BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
494   index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
495   if (rational) {
496     BSplCLib::D2(u,index,deg,periodic,POLES,
497                  weights->Array1(),
498                  FKNOTS,FMULTS,P,V1,V2);
499   }
500   else {
501     BSplCLib::D2(u,index,deg,periodic,POLES,
502                  *((TColStd_Array1OfReal*) NULL),
503                  FKNOTS,FMULTS,P,V1,V2);
504   }
505 }
506
507 //=======================================================================
508 //function : LocalD3
509 //purpose  : 
510 //=======================================================================
511
512 void Geom_BSplineCurve::LocalD3
513   (const Standard_Real    U,
514    const Standard_Integer FromK1,
515    const Standard_Integer ToK2, 
516    gp_Pnt&    P,
517    gp_Vec&    V1,
518    gp_Vec&    V2,
519    gp_Vec&    V3) const
520 {
521   Standard_DomainError_Raise_if (FromK1 == ToK2,
522                                  "Geom_BSplineCurve::LocalD3");
523   
524   Standard_Real u = U;
525   Standard_Integer index = 0;
526   BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
527   index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
528   if (rational) {
529     BSplCLib::D3(u,index,deg,periodic,POLES,
530                  weights->Array1(),
531                  FKNOTS,FMULTS,P,V1,V2,V3);
532   }
533   else {
534     BSplCLib::D3(u,index,deg,periodic,POLES,
535                  *((TColStd_Array1OfReal*) NULL),
536                  FKNOTS,FMULTS,P,V1,V2,V3);
537   }
538 }
539
540 //=======================================================================
541 //function : LocalDN
542 //purpose  : 
543 //=======================================================================
544
545 gp_Vec Geom_BSplineCurve::LocalDN
546   (const Standard_Real    U,
547    const Standard_Integer FromK1,
548    const Standard_Integer ToK2,
549    const Standard_Integer N      ) const
550 {
551   Standard_DomainError_Raise_if (FromK1 == ToK2,
552                                  "Geom_BSplineCurve::LocalD3");
553   
554   Standard_Real u = U;
555   Standard_Integer index = 0;
556   BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
557   index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
558   
559   gp_Vec V;
560   if (rational) {
561     BSplCLib::DN(u,N,index,deg,periodic,POLES,
562                  weights->Array1(),
563                  FKNOTS,FMULTS,V);
564   }
565   else {
566     BSplCLib::DN(u,N,index,deg,periodic,POLES,
567                  *((TColStd_Array1OfReal*) NULL),
568                  FKNOTS,FMULTS,V);
569   }
570   return V;
571 }
572
573 //=======================================================================
574 //function : Multiplicity
575 //purpose  : 
576 //=======================================================================
577
578 Standard_Integer Geom_BSplineCurve::Multiplicity 
579   (const Standard_Integer Index) const
580 {
581   Standard_OutOfRange_Raise_if (Index < 1 || Index > mults->Length(),
582                                 "Geom_BSplineCurve::Multiplicity");
583   return mults->Value (Index);
584 }
585
586 //=======================================================================
587 //function : Multiplicities
588 //purpose  : 
589 //=======================================================================
590
591 void Geom_BSplineCurve::Multiplicities (TColStd_Array1OfInteger& M) const
592 {
593   Standard_DimensionError_Raise_if (M.Length() != mults->Length(),
594                                     "Geom_BSplineCurve::Multiplicities");
595   M = mults->Array1();
596 }
597
598 //=======================================================================
599 //function : NbKnots
600 //purpose  : 
601 //=======================================================================
602
603 Standard_Integer Geom_BSplineCurve::NbKnots () const
604 { return knots->Length(); }
605
606 //=======================================================================
607 //function : NbPoles
608 //purpose  : 
609 //=======================================================================
610
611 Standard_Integer Geom_BSplineCurve::NbPoles () const
612 { return poles->Length(); }
613
614 //=======================================================================
615 //function : Pole
616 //purpose  : 
617 //=======================================================================
618
619 gp_Pnt Geom_BSplineCurve::Pole (const Standard_Integer Index) const
620 {
621   Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
622                                 "Geom_BSplineCurve::Pole");
623   return poles->Value (Index);      
624 }
625
626 //=======================================================================
627 //function : Poles
628 //purpose  : 
629 //=======================================================================
630
631 void Geom_BSplineCurve::Poles (TColgp_Array1OfPnt& P) const
632 {
633   Standard_DimensionError_Raise_if (P.Length() != poles->Length(),
634                                     "Geom_BSplineCurve::Poles");
635   P = poles->Array1();
636 }
637
638 //=======================================================================
639 //function : StartPoint
640 //purpose  : 
641 //=======================================================================
642
643 gp_Pnt Geom_BSplineCurve::StartPoint () const
644 {
645   if (mults->Value (1) == deg + 1)  
646     return poles->Value (1);
647   else 
648     return Value(FirstParameter());
649 }
650
651 //=======================================================================
652 //function : Weight
653 //purpose  : 
654 //=======================================================================
655
656 Standard_Real Geom_BSplineCurve::Weight
657   (const Standard_Integer Index) const
658 {
659   Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
660                                 "Geom_BSplineCurve::Weight");
661   if (IsRational())
662     return weights->Value (Index);
663   else
664     return 1.;
665 }
666
667 //=======================================================================
668 //function : Weights
669 //purpose  : 
670 //=======================================================================
671
672 void Geom_BSplineCurve::Weights
673   (TColStd_Array1OfReal& W) const
674 {
675   Standard_DimensionError_Raise_if (W.Length() != poles->Length(),
676                                     "Geom_BSplineCurve::Weights");
677   if (IsRational())
678     W = weights->Array1();
679   else {
680     Standard_Integer i;
681
682     for (i = W.Lower(); i <= W.Upper(); i++)
683       W(i) = 1.;
684   }
685 }
686
687 //=======================================================================
688 //function : IsRational
689 //purpose  : 
690 //=======================================================================
691
692 Standard_Boolean Geom_BSplineCurve::IsRational () const
693
694   return !weights.IsNull(); 
695
696
697 //=======================================================================
698 //function : Transform
699 //purpose  : 
700 //=======================================================================
701
702 void Geom_BSplineCurve::Transform
703   (const gp_Trsf& T)
704 {
705   TColgp_Array1OfPnt & CPoles = poles->ChangeArray1();
706   for (Standard_Integer I = 1; I <= CPoles.Length(); I++)  
707     CPoles (I).Transform (T);
708   InvalidateCache() ;
709   maxderivinvok = 0;
710 }
711
712 //=======================================================================
713 //function : LocateU
714 //purpose  : 
715 // pmn : 30/01/97 mise en conformite avec le cdl, lorsque U est un noeud
716 // (PRO6988)
717 //=======================================================================
718
719 void Geom_BSplineCurve::LocateU
720   (const Standard_Real    U, 
721    const Standard_Real    ParametricTolerance, 
722    Standard_Integer&      I1,
723    Standard_Integer&      I2,
724    const Standard_Boolean WithKnotRepetition) const
725 {
726   Standard_Real NewU = U;
727   Handle(TColStd_HArray1OfReal) TheKnots;
728   if (WithKnotRepetition)  TheKnots = flatknots;
729   else                     TheKnots = knots;
730   const TColStd_Array1OfReal & CKnots = TheKnots->Array1();
731
732   PeriodicNormalization(NewU); //Attention a la periode
733   
734   Standard_Real UFirst = CKnots (1);
735   Standard_Real ULast  = CKnots (CKnots.Length());
736   Standard_Real PParametricTolerance = Abs(ParametricTolerance);
737   if (Abs (NewU - UFirst) <= PParametricTolerance) { I1 = I2 = 1; }
738   else if (Abs (NewU - ULast) <= PParametricTolerance) { 
739     I1 = I2 = CKnots.Length();
740   }
741   else if (NewU < UFirst) {
742     I2 = 1;
743     I1 = 0;
744   }
745   else if (NewU > ULast) {
746     I1 = CKnots.Length();
747     I2 = I1 + 1;
748   }
749   else {
750     I1 = 1;
751     BSplCLib::Hunt (CKnots, NewU, I1);
752     while ( Abs( CKnots(I1+1) - NewU) <= PParametricTolerance) I1++;
753     if ( Abs( CKnots(I1) - NewU) <= PParametricTolerance) {
754       I2 = I1;
755     }
756     else {
757       I2 = I1 + 1;
758     }
759   }
760 }
761
762 //=======================================================================
763 //function : Resolution
764 //purpose  : 
765 //=======================================================================
766
767 void Geom_BSplineCurve::Resolution(const Standard_Real Tolerance3D,
768                                    Standard_Real &     UTolerance) 
769 {
770   Standard_Integer ii;  
771   if(!maxderivinvok){
772     if ( periodic) {
773       Standard_Integer NbKnots, NbPoles;
774       BSplCLib::PrepareUnperiodize( deg, 
775                                     mults->Array1(),
776                                     NbKnots,
777                                     NbPoles);
778       TColgp_Array1OfPnt    new_poles(1,NbPoles) ;
779       TColStd_Array1OfReal  new_weights(1,NbPoles) ;
780       for(ii = 1 ; ii <= NbPoles ; ii++) {
781         new_poles(ii) = poles->Array1()((ii-1) % poles->Length() + 1) ;
782       }
783       if (rational) {
784         for(ii = 1 ; ii <= NbPoles ; ii++) {
785           new_weights(ii) = weights->Array1()((ii-1) % poles->Length() + 1) ;
786         }
787         BSplCLib::Resolution(new_poles,
788                              new_weights,
789                              new_poles.Length(),
790                              flatknots->Array1(),
791                              deg,
792                              1.,
793                              maxderivinv) ;
794       }
795       else {
796         BSplCLib::Resolution(new_poles,
797                              *((TColStd_Array1OfReal*) NULL),
798                              new_poles.Length(),
799                              flatknots->Array1(),
800                              deg,
801                              1.,
802                              maxderivinv) ;
803       }
804       
805     }
806     else {
807       if (rational) {
808         BSplCLib::Resolution(poles->Array1(),
809                              weights->Array1(),
810                              poles->Length(),
811                              flatknots->Array1(),
812                              deg,
813                              1.,
814                              maxderivinv) ;
815       }
816       else {
817         BSplCLib::Resolution(poles->Array1(),
818                              *((TColStd_Array1OfReal*) NULL),
819                              poles->Length(),
820                              flatknots->Array1(),
821                              deg,
822                              1.,
823                              maxderivinv) ;
824       }
825     }
826     maxderivinvok = 1;
827   }
828   UTolerance = Tolerance3D * maxderivinv;
829 }