0026914: [Regression 7.0alpha] Hang in surface approximation
[occt.git] / src / GeomAdaptor / GeomAdaptor_Curve.cxx
1 // Created on: 1993-04-29
2 // Created by: Bruno DUMORTIER
3 // Copyright (c) 1993-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 // 20/02/97 : PMN -> Positionement local sur BSpline (PRO6902)
18 // 10/07/97 : PMN -> Pas de calcul de resolution dans Nb(Intervals)(PRO9248)
19 // 20/10/97 : RBV -> traitement des offset curves
20
21 #define No_Standard_RangeError
22 #define No_Standard_OutOfRange
23
24
25 #include <Adaptor3d_HCurve.hxx>
26 #include <BSplCLib.hxx>
27 #include <BSplCLib_Cache.hxx>
28 #include <CSLib_Offset.hxx>
29 #include <Geom_BezierCurve.hxx>
30 #include <Geom_BSplineCurve.hxx>
31 #include <Geom_Circle.hxx>
32 #include <Geom_Curve.hxx>
33 #include <Geom_Ellipse.hxx>
34 #include <Geom_Hyperbola.hxx>
35 #include <Geom_Line.hxx>
36 #include <Geom_OffsetCurve.hxx>
37 #include <Geom_Parabola.hxx>
38 #include <Geom_TrimmedCurve.hxx>
39 #include <GeomAbs_Shape.hxx>
40 #include <GeomAdaptor_Curve.hxx>
41 #include <GeomAdaptor_HCurve.hxx>
42 #include <GeomAdaptor_Surface.hxx>
43 #include <gp_Circ.hxx>
44 #include <gp_Elips.hxx>
45 #include <gp_Hypr.hxx>
46 #include <gp_Lin.hxx>
47 #include <gp_Parab.hxx>
48 #include <gp_Pnt.hxx>
49 #include <gp_Vec.hxx>
50 #include <Precision.hxx>
51 #include <Standard_ConstructionError.hxx>
52 #include <Standard_DomainError.hxx>
53 #include <Standard_NoSuchObject.hxx>
54 #include <Standard_NotImplemented.hxx>
55 #include <Standard_NullObject.hxx>
56 #include <Standard_OutOfRange.hxx>
57 #include <TColgp_Array1OfPnt.hxx>
58 #include <TColStd_Array1OfInteger.hxx>
59 #include <TColStd_Array1OfReal.hxx>
60 #include <TColStd_HArray1OfInteger.hxx>
61
62 //#include <GeomConvert_BSplineCurveKnotSplitting.hxx>
63 #define myBspl Handle(Geom_BSplineCurve)::DownCast (myCurve)
64 #define PosTol Precision::PConfusion()/2
65
66 static const int maxDerivOrder = 3;
67 static const Standard_Real MinStep   = 1e-7;
68
69 static gp_Vec dummyDerivative; // used as empty value for unused derivatives in AdjustDerivative
70 // Recalculate derivatives in the singular point
71 // Returns true if the direction of derivatives is changed
72 static Standard_Boolean AdjustDerivative(
73     const Handle(Adaptor3d_HCurve)& theAdaptor, Standard_Integer theMaxDerivative, Standard_Real theU, gp_Vec& theD1,
74     gp_Vec& theD2 = dummyDerivative, gp_Vec& theD3 = dummyDerivative, gp_Vec& theD4 = dummyDerivative);
75
76
77 //=======================================================================
78 //function : LocalContinuity
79 //purpose  : Computes the Continuity of a BSplineCurve 
80 //           between the parameters U1 and U2
81 //           The continuity is C(d-m) 
82 //             with   d = degree, 
83 //                    m = max multiplicity of the Knots between U1 and U2
84 //=======================================================================
85
86 GeomAbs_Shape GeomAdaptor_Curve::LocalContinuity(const Standard_Real U1, 
87                                                  const Standard_Real U2) 
88      const 
89 {
90   Standard_NoSuchObject_Raise_if(myTypeCurve!=GeomAbs_BSplineCurve," ");
91   Standard_Integer Nb = myBspl->NbKnots();
92   Standard_Integer Index1 = 0;
93   Standard_Integer Index2 = 0;
94   Standard_Real newFirst, newLast;
95   TColStd_Array1OfReal    TK(1,Nb);
96   TColStd_Array1OfInteger TM(1,Nb);
97   myBspl->Knots(TK);
98   myBspl->Multiplicities(TM);
99   BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,U1,myBspl->IsPeriodic(),
100                             1,Nb,Index1,newFirst);
101   BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,U2,myBspl->IsPeriodic(),
102                             1,Nb,Index2,newLast);
103   if ( Abs(newFirst-TK(Index1+1))<Precision::PConfusion()) { 
104     if (Index1 < Nb) Index1++;
105   }
106   if ( Abs(newLast-TK(Index2))<Precision::PConfusion())
107     Index2--;
108   Standard_Integer MultMax;
109   // attention aux courbes peridiques.
110   if ( (myBspl->IsPeriodic()) && (Index1 == Nb) )
111     Index1 = 1;
112
113   if ( Index2 - Index1 <= 0) {
114     MultMax = 100;  // CN entre 2 Noeuds consecutifs
115   }
116   else {
117     MultMax = TM(Index1+1);
118     for(Standard_Integer i = Index1+1;i<=Index2;i++) {
119       if ( TM(i)>MultMax) MultMax=TM(i);
120     }
121     MultMax = myBspl->Degree() - MultMax;
122   }
123   if ( MultMax <= 0) {
124     return GeomAbs_C0;
125   }
126   else if ( MultMax == 1) {
127     return GeomAbs_C1;
128   } 
129   else if ( MultMax == 2) {
130     return GeomAbs_C2;
131   }
132   else if ( MultMax == 3) {
133     return GeomAbs_C3;
134   }
135   else { 
136     return GeomAbs_CN;
137   }
138 }
139
140
141 //=======================================================================
142 //function : Load
143 //purpose  : 
144 //=======================================================================
145
146 void GeomAdaptor_Curve::load(const Handle(Geom_Curve)& C,
147                              const Standard_Real UFirst,
148                              const Standard_Real ULast)
149 {
150   myFirst = UFirst;
151   myLast  = ULast;
152
153   if ( myCurve != C) {
154     myCurve = C;
155     
156     const Handle(Standard_Type)& TheType = C->DynamicType();
157     if ( TheType == STANDARD_TYPE(Geom_TrimmedCurve)) {
158       Load(Handle(Geom_TrimmedCurve)::DownCast (C)->BasisCurve(),UFirst,ULast);
159     }
160     else if ( TheType ==  STANDARD_TYPE(Geom_Circle)) {
161       myTypeCurve = GeomAbs_Circle;
162     }
163     else if ( TheType ==STANDARD_TYPE(Geom_Line)) {
164       myTypeCurve = GeomAbs_Line;
165     }
166     else if ( TheType == STANDARD_TYPE(Geom_Ellipse)) {
167       myTypeCurve = GeomAbs_Ellipse;
168     }
169     else if ( TheType == STANDARD_TYPE(Geom_Parabola)) {
170       myTypeCurve = GeomAbs_Parabola;
171     }
172     else if ( TheType == STANDARD_TYPE(Geom_Hyperbola)) {
173       myTypeCurve = GeomAbs_Hyperbola;
174     }
175     else if ( TheType == STANDARD_TYPE(Geom_BezierCurve)) {
176       myTypeCurve = GeomAbs_BezierCurve;
177     }
178     else if ( TheType == STANDARD_TYPE(Geom_BSplineCurve)) {
179       myTypeCurve = GeomAbs_BSplineCurve;
180       // Create cache for B-spline
181       myCurveCache = new BSplCLib_Cache(myBspl->Degree(), myBspl->IsPeriodic(), 
182         myBspl->KnotSequence(), myBspl->Poles(), myBspl->Weights());
183     }
184     else if ( TheType == STANDARD_TYPE(Geom_OffsetCurve)) {
185       myTypeCurve = GeomAbs_OffsetCurve;
186       // Create nested adaptor for base curve
187       Handle(Geom_Curve) aBase = Handle(Geom_OffsetCurve)::DownCast(myCurve)->BasisCurve();
188       myOffsetBaseCurveAdaptor = new GeomAdaptor_HCurve(aBase);
189     }
190     else {
191       myTypeCurve = GeomAbs_OtherCurve;
192     }
193   }
194 }  
195
196 //    --
197 //    --     Global methods - Apply to the whole curve.
198 //    --     
199
200 //=======================================================================
201 //function : Continuity
202 //purpose  : 
203 //=======================================================================
204
205 GeomAbs_Shape GeomAdaptor_Curve::Continuity() const 
206 {
207   if (myTypeCurve == GeomAbs_BSplineCurve)
208     return LocalContinuity(myFirst, myLast);
209
210   if (myTypeCurve == GeomAbs_OffsetCurve)
211   {
212     const GeomAbs_Shape S =
213       Handle(Geom_OffsetCurve)::DownCast (myCurve)->GetBasisCurveContinuity();
214     switch(S)
215     {
216       case GeomAbs_CN: return GeomAbs_CN;
217       case GeomAbs_C3: return GeomAbs_C2;
218       case GeomAbs_C2: return GeomAbs_C1;
219       case GeomAbs_C1: return GeomAbs_C0; 
220       case GeomAbs_G1: return GeomAbs_G1;
221       case GeomAbs_G2: return GeomAbs_G2;
222       default:
223         Standard_NoSuchObject::Raise("GeomAdaptor_Curve::Continuity");
224     }
225   }
226   else if (myTypeCurve == GeomAbs_OtherCurve) {
227     Standard_NoSuchObject::Raise("GeomAdaptor_Curve::Contunuity");
228   }
229
230   return GeomAbs_CN;
231 }
232
233 //=======================================================================
234 //function : NbIntervals
235 //purpose  : 
236 //=======================================================================
237
238 Standard_Integer GeomAdaptor_Curve::NbIntervals(const GeomAbs_Shape S) const
239 {
240   Standard_Integer myNbIntervals = 1;
241   Standard_Integer NbSplit;
242   if (myTypeCurve == GeomAbs_BSplineCurve) {
243     Standard_Integer FirstIndex = myBspl->FirstUKnotIndex();
244     Standard_Integer LastIndex  = myBspl->LastUKnotIndex();
245     TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
246     if ( S > Continuity()) {
247       Standard_Integer Cont;
248       switch ( S) {
249       case GeomAbs_G1:
250       case GeomAbs_G2:
251         Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
252         break;
253       case GeomAbs_C0:
254         myNbIntervals = 1;
255         break;
256       case GeomAbs_C1:
257       case GeomAbs_C2:
258       case GeomAbs_C3: 
259       case GeomAbs_CN: 
260         {
261           if      ( S == GeomAbs_C1) Cont = 1;
262           else if ( S == GeomAbs_C2) Cont = 2;
263           else if ( S == GeomAbs_C3) Cont = 3;
264           else                       Cont = myBspl->Degree();
265           Standard_Integer Degree = myBspl->Degree();
266           Standard_Integer NbKnots = myBspl->NbKnots();
267           TColStd_Array1OfInteger Mults (1, NbKnots);
268           myBspl->Multiplicities (Mults);
269           NbSplit = 1;
270           Standard_Integer Index   = FirstIndex;
271           Inter (NbSplit) = Index;
272           Index++;
273           NbSplit++;
274           while (Index < LastIndex) 
275             {
276               if (Degree - Mults (Index) < Cont) 
277                 {
278                   Inter (NbSplit) = Index;
279                   NbSplit++;
280                 }
281               Index++;
282             }
283           Inter (NbSplit) = Index;
284
285           Standard_Integer NbInt = NbSplit-1;
286           
287           Standard_Integer Nb = myBspl->NbKnots();
288           Standard_Integer Index1 = 0;
289           Standard_Integer Index2 = 0;
290           Standard_Real newFirst, newLast;
291           TColStd_Array1OfReal    TK(1,Nb);
292           TColStd_Array1OfInteger TM(1,Nb);
293           myBspl->Knots(TK);
294           myBspl->Multiplicities(TM);
295           BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myFirst,
296                                     myBspl->IsPeriodic(),
297                                     1,Nb,Index1,newFirst);
298           BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myLast,
299                                     myBspl->IsPeriodic(),
300                                     1,Nb,Index2,newLast);
301
302           // On decale eventuellement les indices  
303           // On utilise une "petite" tolerance, la resolution ne doit 
304           // servir que pour les tres longue courbes....(PRO9248)
305           Standard_Real Eps = Min(Resolution(Precision::Confusion()),
306                                   Precision::PConfusion()); 
307           if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
308           if ( newLast-TK(Index2)> Eps) Index2++;
309           
310           myNbIntervals = 1;
311           for ( Standard_Integer i=1; i<=NbInt; i++)
312             if (Inter(i)>Index1 && Inter(i)<Index2) myNbIntervals++;
313         }
314         break;
315       }
316     }
317   }
318   
319   else if (myTypeCurve == GeomAbs_OffsetCurve) {
320     GeomAbs_Shape BaseS=GeomAbs_C0;
321     switch(S){
322     case GeomAbs_G1:
323     case GeomAbs_G2:
324       Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
325       break;
326     case GeomAbs_C0: BaseS = GeomAbs_C1; break;
327     case GeomAbs_C1: BaseS = GeomAbs_C2; break;
328     case GeomAbs_C2: BaseS = GeomAbs_C3; break;
329     default: BaseS = GeomAbs_CN;
330     }
331     GeomAdaptor_Curve C
332       (Handle(Geom_OffsetCurve)::DownCast (myCurve)->BasisCurve());
333     // akm 05/04/02 (OCC278)  If our curve is trimmed we must recalculate 
334     //                    the number of intervals obtained from the basis to
335     //              vvv   reflect parameter bounds
336     Standard_Integer iNbBasisInt = C.NbIntervals(BaseS), iInt;
337     if (iNbBasisInt>1)
338     {
339       TColStd_Array1OfReal rdfInter(1,1+iNbBasisInt);
340       C.Intervals(rdfInter,BaseS);
341       for (iInt=1; iInt<=iNbBasisInt; iInt++)
342         if (rdfInter(iInt)>myFirst && rdfInter(iInt)<myLast)
343           myNbIntervals++;
344     }
345     // akm 05/04/02 ^^^
346   }
347   return myNbIntervals;
348 }
349
350 //=======================================================================
351 //function : Intervals
352 //purpose  : 
353 //=======================================================================
354
355 void GeomAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
356                                   const GeomAbs_Shape S   ) const
357 {
358   Standard_Integer myNbIntervals = 1;
359   Standard_Integer NbSplit;
360   Standard_Real FirstParam = myFirst, LastParam = myLast;
361
362   if (myTypeCurve == GeomAbs_BSplineCurve) 
363     {
364       Standard_Integer FirstIndex = myBspl->FirstUKnotIndex();
365       Standard_Integer LastIndex  = myBspl->LastUKnotIndex();
366       TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
367       
368       if ( S > Continuity()) {
369         Standard_Integer Cont;
370         switch ( S) {
371         case GeomAbs_G1:
372         case GeomAbs_G2:
373           Standard_DomainError::Raise("Geom2dAdaptor_Curve::NbIntervals");
374           break;
375         case GeomAbs_C0:
376           myNbIntervals = 1;
377           break;
378         case GeomAbs_C1:
379         case GeomAbs_C2:
380         case GeomAbs_C3: 
381         case GeomAbs_CN: 
382           {
383             if      ( S == GeomAbs_C1) Cont = 1;
384             else if ( S == GeomAbs_C2) Cont = 2;
385             else if ( S == GeomAbs_C3) Cont = 3;
386             else                       Cont = myBspl->Degree();
387             Standard_Integer Degree = myBspl->Degree();
388             Standard_Integer NbKnots = myBspl->NbKnots();
389             TColStd_Array1OfInteger Mults (1, NbKnots);
390             myBspl->Multiplicities (Mults);
391             NbSplit = 1;
392             Standard_Integer Index   = FirstIndex;
393             Inter (NbSplit) = Index;
394             Index++;
395             NbSplit++;
396             while (Index < LastIndex) 
397               {
398                 if (Degree - Mults (Index) < Cont) 
399                   {
400                     Inter (NbSplit) = Index;
401                     NbSplit++;
402                   }
403                 Index++;
404               }
405             Inter (NbSplit) = Index;
406             Standard_Integer NbInt = NbSplit-1;
407             //        GeomConvert_BSplineCurveKnotSplitting Convector(myBspl, Cont);
408             //        Standard_Integer NbInt = Convector.NbSplits()-1;
409             //        TColStd_Array1OfInteger Inter(1,NbInt+1);
410             //        Convector.Splitting( Inter);
411             
412             Standard_Integer Nb = myBspl->NbKnots();
413             Standard_Integer Index1 = 0;
414             Standard_Integer Index2 = 0;
415             Standard_Real newFirst, newLast;
416             TColStd_Array1OfReal    TK(1,Nb);
417             TColStd_Array1OfInteger TM(1,Nb);
418             myBspl->Knots(TK);
419             myBspl->Multiplicities(TM);
420             BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myFirst,
421                                       myBspl->IsPeriodic(),
422                                       1,Nb,Index1,newFirst);
423             BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myLast,
424                                       myBspl->IsPeriodic(),
425                                       1,Nb,Index2,newLast);
426             FirstParam = newFirst;
427             LastParam = newLast;
428             // On decale eventuellement les indices  
429             // On utilise une "petite" tolerance, la resolution ne doit 
430             // servir que pour les tres longue courbes....(PRO9248)
431             Standard_Real Eps = Min(Resolution(Precision::Confusion()),
432                                     Precision::PConfusion()); 
433             if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
434             if ( newLast-TK(Index2)> Eps) Index2++;
435             
436             Inter( 1) = Index1;
437             myNbIntervals = 1;
438             for ( Standard_Integer i=1; i<=NbInt; i++) {
439               if (Inter(i) > Index1 && Inter(i)<Index2 ) {
440                 myNbIntervals++;
441                 Inter(myNbIntervals) = Inter(i);
442               }
443             }
444             Inter(myNbIntervals+1) = Index2;
445             
446             for (Standard_Integer I=1;I<=myNbIntervals+1;I++) {
447               T(I) = TK(Inter(I));
448             }
449           }
450           break;
451         }
452       }
453     }
454
455   else if (myTypeCurve == GeomAbs_OffsetCurve){
456     GeomAbs_Shape BaseS=GeomAbs_C0;
457     switch(S){
458     case GeomAbs_G1:
459     case GeomAbs_G2:
460       Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
461       break;
462     case GeomAbs_C0: BaseS = GeomAbs_C1; break;
463     case GeomAbs_C1: BaseS = GeomAbs_C2; break;
464     case GeomAbs_C2: BaseS = GeomAbs_C3; break;
465     default: BaseS = GeomAbs_CN;
466     }
467     GeomAdaptor_Curve C
468       (Handle(Geom_OffsetCurve)::DownCast (myCurve)->BasisCurve());
469     // akm 05/04/02 (OCC278)  If our curve is trimmed we must recalculate 
470     //                    the array of intervals obtained from the basis to
471     //              vvv   reflect parameter bounds
472     Standard_Integer iNbBasisInt = C.NbIntervals(BaseS), iInt;
473     if (iNbBasisInt>1)
474     {
475       TColStd_Array1OfReal rdfInter(1,1+iNbBasisInt);
476       C.Intervals(rdfInter,BaseS);
477       for (iInt=1; iInt<=iNbBasisInt; iInt++)
478         if (rdfInter(iInt)>myFirst && rdfInter(iInt)<myLast)
479           T(++myNbIntervals)=rdfInter(iInt);
480     }
481     // old - myNbIntervals = C.NbIntervals(BaseS);
482     // old - C.Intervals(T, BaseS);
483     // akm 05/04/02 ^^^
484   }
485   
486   T( T.Lower() ) = FirstParam;
487   T( T.Lower() + myNbIntervals ) = LastParam;
488 }
489
490 //=======================================================================
491 //function : Trim
492 //purpose  : 
493 //=======================================================================
494
495 Handle(Adaptor3d_HCurve) GeomAdaptor_Curve::Trim(const Standard_Real First,
496                                                  const Standard_Real Last,
497                                                  const Standard_Real /*Tol*/) const
498 {
499   return Handle(GeomAdaptor_HCurve)(new GeomAdaptor_HCurve(myCurve,First,Last));
500 }
501
502
503 //=======================================================================
504 //function : IsClosed
505 //purpose  : 
506 //=======================================================================
507
508 Standard_Boolean GeomAdaptor_Curve::IsClosed() const
509 {
510   if (!Precision::IsPositiveInfinite(myLast) &&
511       !Precision::IsNegativeInfinite(myFirst))
512   {
513     const gp_Pnt Pd = Value(myFirst);
514     const gp_Pnt Pf = Value(myLast);
515     return (Pd.Distance(Pf) <= Precision::Confusion());
516   }
517   return Standard_False;
518 }
519
520 //=======================================================================
521 //function : IsPeriodic
522 //purpose  : 
523 //=======================================================================
524
525 Standard_Boolean GeomAdaptor_Curve::IsPeriodic() const 
526 {
527   return (myCurve->IsPeriodic()? IsClosed() : Standard_False);
528 }
529
530 //=======================================================================
531 //function : Period
532 //purpose  : 
533 //=======================================================================
534
535 Standard_Real GeomAdaptor_Curve::Period() const 
536 {
537   return myCurve->LastParameter() - myCurve->FirstParameter();
538 }
539
540 //=======================================================================
541 //function : RebuildCache
542 //purpose  : 
543 //=======================================================================
544 void GeomAdaptor_Curve::RebuildCache(const Standard_Real theParameter) const
545 {
546   myCurveCache->BuildCache(theParameter, myBspl->Degree(), 
547     myBspl->IsPeriodic(), myBspl->KnotSequence(), 
548     myBspl->Poles(), myBspl->Weights());
549 }
550
551 //=======================================================================
552 //function : Value
553 //purpose  : 
554 //=======================================================================
555
556 gp_Pnt GeomAdaptor_Curve::Value(const Standard_Real U) const
557 {
558   if (myTypeCurve == GeomAbs_BSplineCurve)
559     return ValueBSpline(U);
560   else if (myTypeCurve == GeomAbs_OffsetCurve)
561     return ValueOffset(U);
562   return myCurve->Value(U);
563 }
564
565 //=======================================================================
566 //function : ValueBSpline
567 //purpose  : 
568 //=======================================================================
569 gp_Pnt GeomAdaptor_Curve::ValueBSpline(const Standard_Real theU) const
570 {
571   if (theU == myFirst || theU == myLast)
572   {
573     Standard_Integer Ideb = 0, Ifin = 0;
574     if (theU == myFirst) {
575       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
576       if (Ideb<1) Ideb=1;
577       if (Ideb>=Ifin) Ifin = Ideb+1;
578     }
579     if (theU == myLast) {
580       myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
581       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
582       if (Ideb>=Ifin) Ideb = Ifin-1;
583     }
584     return myBspl->LocalValue(theU, Ideb, Ifin);
585   }
586   else if (!myCurveCache.IsNull()) // use cached B-spline data
587   {
588     if (!myCurveCache->IsCacheValid(theU))
589       RebuildCache(theU);
590     gp_Pnt aRes;
591     myCurveCache->D0(theU, aRes);
592     return aRes;
593   }
594   return myCurve->Value(theU);
595 }
596
597 //=======================================================================
598 //function : ValueOffset
599 //purpose  : 
600 //=======================================================================
601 gp_Pnt GeomAdaptor_Curve::ValueOffset(const Standard_Real theU) const
602 {
603   gp_Pnt aP;
604   gp_Vec aV;
605   myOffsetBaseCurveAdaptor->D1(theU, aP, aV);
606   Standard_Boolean IsDirectionChange = Standard_False;
607   if(aV.SquareMagnitude() <= gp::Resolution())
608     IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 1, theU, aV);
609
610   Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
611   Standard_Real anOffsetVal = anOffC->Offset();
612   const gp_Dir& anOffsetDir = anOffC->Direction();
613
614   CSLib_Offset::D0(aP, aV, anOffsetDir, anOffsetVal, IsDirectionChange, aP);
615   return aP;
616 }
617
618 //=======================================================================
619 //function : D0
620 //purpose  : 
621 //=======================================================================
622
623 void GeomAdaptor_Curve::D0(const Standard_Real U, gp_Pnt& P) const
624 {
625   if (myTypeCurve == GeomAbs_BSplineCurve)
626     D0BSpline(U, P);
627   else if (myTypeCurve == GeomAbs_OffsetCurve)
628     D0Offset(U, P);
629   else
630     myCurve->D0(U, P);
631 }
632
633 //=======================================================================
634 //function : D0BSpline
635 //purpose  : 
636 //=======================================================================
637 void GeomAdaptor_Curve::D0BSpline(const Standard_Real theU, gp_Pnt& theP) const
638 {
639   if (theU == myFirst || theU == myLast) 
640   {
641     Standard_Integer Ideb = 0, Ifin = 0;
642     if (theU == myFirst) {
643       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
644       if (Ideb<1) Ideb=1;
645       if (Ideb>=Ifin) Ifin = Ideb+1;
646     }
647     if (theU == myLast) {
648       myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
649       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
650       if (Ideb>=Ifin) Ideb = Ifin-1;
651     }
652     myBspl->LocalD0(theU, Ideb, Ifin, theP);
653     return;
654   }
655   else if (!myCurveCache.IsNull()) // use cached B-spline data
656   {
657     if (!myCurveCache->IsCacheValid(theU))
658       RebuildCache(theU);
659     myCurveCache->D0(theU, theP);
660     return;
661   }
662   myCurve->D0(theU, theP);
663 }
664
665 //=======================================================================
666 //function : D0Offset
667 //purpose  : 
668 //=======================================================================
669 void GeomAdaptor_Curve::D0Offset(const Standard_Real theU, gp_Pnt& theP) const
670 {
671   theP = ValueOffset(theU);
672 }
673
674 //=======================================================================
675 //function : D1
676 //purpose  : 
677 //=======================================================================
678
679 void GeomAdaptor_Curve::D1(const Standard_Real U, gp_Pnt& P, gp_Vec& V) const 
680 {
681   if (myTypeCurve == GeomAbs_BSplineCurve)
682     D1BSpline(U, P, V);
683   else if (myTypeCurve == GeomAbs_OffsetCurve)
684     D1Offset(U, P, V);
685   else
686     myCurve->D1(U, P, V);
687 }
688
689 //=======================================================================
690 //function : D1BSpline
691 //purpose  : 
692 //=======================================================================
693 void GeomAdaptor_Curve::D1BSpline(const Standard_Real theU, gp_Pnt& theP, gp_Vec& theV) const
694 {
695   if (theU == myFirst || theU == myLast) 
696   {
697     Standard_Integer Ideb = 0, Ifin = 0;
698     if (theU == myFirst) {
699       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
700       if (Ideb<1) Ideb=1;
701       if (Ideb>=Ifin) Ifin = Ideb+1;
702     }
703     if (theU == myLast) {
704       myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
705       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
706       if (Ideb>=Ifin) Ideb = Ifin-1;
707     }
708     myBspl->LocalD1(theU, Ideb, Ifin, theP, theV);
709     return;
710   }
711   else if (!myCurveCache.IsNull()) // use cached B-spline data
712   {
713     if (!myCurveCache->IsCacheValid(theU))
714       RebuildCache(theU);
715     myCurveCache->D1(theU, theP, theV);
716     return;
717   }
718   myCurve->D1(theU, theP, theV);
719 }
720
721 //=======================================================================
722 //function : D1Offset
723 //purpose  : 
724 //=======================================================================
725 void GeomAdaptor_Curve::D1Offset(const Standard_Real theU, gp_Pnt& theP, gp_Vec& theV) const
726 {
727   gp_Vec aV2;
728   myOffsetBaseCurveAdaptor->D2 (theU, theP, theV, aV2);
729
730   Standard_Boolean IsDirectionChange = Standard_False;
731   if(theV.SquareMagnitude() <= gp::Resolution())
732     IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 2, theU, theV, aV2);
733
734   Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
735   Standard_Real anOffsetVal = anOffC->Offset();
736   const gp_Dir& anOffsetDir = anOffC->Direction();
737   CSLib_Offset::D1(theP, theV, aV2, anOffsetDir, anOffsetVal, IsDirectionChange, theP, theV);
738 }
739
740
741 //=======================================================================
742 //function : D2
743 //purpose  : 
744 //=======================================================================
745
746 void GeomAdaptor_Curve::D2(const Standard_Real U, 
747                            gp_Pnt& P, gp_Vec& V1, gp_Vec& V2) const 
748 {
749   if (myTypeCurve == GeomAbs_BSplineCurve)
750     D2BSpline(U, P, V1, V2);
751   else if (myTypeCurve == GeomAbs_OffsetCurve)
752     D2Offset(U, P, V1, V2);
753   else
754     myCurve->D2(U, P, V1, V2);
755 }
756
757 //=======================================================================
758 //function : D2BSpline
759 //purpose  : 
760 //=======================================================================
761 void GeomAdaptor_Curve::D2BSpline(const Standard_Real theU, gp_Pnt& theP,
762                                   gp_Vec& theV1, gp_Vec& theV2) const
763 {
764   if (theU == myFirst || theU == myLast)
765   {
766     Standard_Integer Ideb = 0, Ifin = 0;
767     if (theU == myFirst) {
768       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
769       if (Ideb<1) Ideb=1;
770       if (Ideb>=Ifin) Ifin = Ideb+1;
771     }
772     if (theU == myLast) {
773       myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
774       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
775       if (Ideb>=Ifin) Ideb = Ifin-1;
776     }
777     myBspl->LocalD2(theU, Ideb, Ifin, theP, theV1, theV2);
778     return;
779   }
780   else if (!myCurveCache.IsNull()) // use cached B-spline data
781   {
782     if (!myCurveCache->IsCacheValid(theU))
783       RebuildCache(theU);
784     myCurveCache->D2(theU, theP, theV1, theV2);
785     return;
786   }
787   myCurve->D2(theU, theP, theV1, theV2);
788 }
789
790 //=======================================================================
791 //function : D2Offset
792 //purpose  : 
793 //=======================================================================
794 void GeomAdaptor_Curve::D2Offset(const Standard_Real theU, gp_Pnt& theP,
795                                   gp_Vec& theV1, gp_Vec& theV2) const
796 {
797   gp_Vec V3;
798   myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, V3);
799
800   Standard_Boolean IsDirectionChange = Standard_False;
801   if(theV1.SquareMagnitude() <= gp::Resolution())
802     IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 3, theU, theV1, theV2, V3);
803
804   Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
805   Standard_Real anOffsetVal = anOffC->Offset();
806   const gp_Dir& anOffsetDir = anOffC->Direction();
807   CSLib_Offset::D2(theP, theV1, theV2, V3, anOffsetDir, anOffsetVal, IsDirectionChange, theP, theV1, theV2);
808 }
809
810 //=======================================================================
811 //function : D3
812 //purpose  : 
813 //=======================================================================
814
815 void GeomAdaptor_Curve::D3(const Standard_Real U, 
816                            gp_Pnt& P, gp_Vec& V1, 
817                            gp_Vec& V2, gp_Vec& V3) const 
818 {
819   if (myTypeCurve == GeomAbs_BSplineCurve)
820     D3BSpline(U, P, V1, V2, V3);
821   else if (myTypeCurve == GeomAbs_OffsetCurve)
822     D3Offset(U, P, V1, V2, V3);
823   else
824     myCurve->D3(U, P, V1, V2, V3);
825 }
826
827 //=======================================================================
828 //function : D3BSpline
829 //purpose  : 
830 //=======================================================================
831 void GeomAdaptor_Curve::D3BSpline(const Standard_Real theU,
832                                   gp_Pnt& theP, gp_Vec& theV1,
833                                   gp_Vec& theV2, gp_Vec& theV3) const
834 {
835   if (theU == myFirst || theU == myLast)
836   {
837     Standard_Integer Ideb = 0, Ifin = 0;
838     if (theU == myFirst) {
839       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
840       if (Ideb<1) Ideb=1;
841       if (Ideb>=Ifin) Ifin = Ideb+1;
842     }
843     if (theU == myLast) {
844       myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
845       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
846       if (Ideb>=Ifin) Ideb = Ifin-1;
847     }
848     myBspl->LocalD3(theU, Ideb, Ifin, theP, theV1, theV2, theV3);
849     return;
850   }
851   else if (!myCurveCache.IsNull()) // use cached B-spline data
852   {
853     if (!myCurveCache->IsCacheValid(theU))
854       RebuildCache(theU);
855     myCurveCache->D3(theU, theP, theV1, theV2, theV3);
856     return;
857   }
858   myCurve->D3(theU, theP, theV1, theV2, theV3);
859 }
860
861 //=======================================================================
862 //function : D3Offset
863 //purpose  : 
864 //=======================================================================
865 void GeomAdaptor_Curve::D3Offset(const Standard_Real theU,
866                                  gp_Pnt& theP, gp_Vec& theV1,
867                                  gp_Vec& theV2, gp_Vec& theV3) const
868 {
869   myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, theV3);
870   gp_Vec V4 = myOffsetBaseCurveAdaptor->DN(theU, 4);
871
872   Standard_Boolean IsDirectionChange = Standard_False;
873   if(theV1.SquareMagnitude() <= gp::Resolution())
874     IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 4, theU, theV1, theV2, theV3, V4);
875
876   Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
877   Standard_Real anOffsetVal = anOffC->Offset();
878   const gp_Dir& anOffsetDir = anOffC->Direction();
879   CSLib_Offset::D3(theP, theV1, theV2, theV3, V4, anOffsetDir, anOffsetVal, IsDirectionChange,
880                    theP, theV1, theV2, theV3);
881 }
882
883 //=======================================================================
884 //function : DN
885 //purpose  : 
886 //=======================================================================
887
888 gp_Vec GeomAdaptor_Curve::DN(const Standard_Real    U, 
889                              const Standard_Integer N) const 
890 {
891   if (myTypeCurve == GeomAbs_BSplineCurve)
892     return DNBSpline(U, N);
893   else if (myTypeCurve == GeomAbs_OffsetCurve)
894     return DNOffset(U, N);
895
896   return myCurve->DN(U, N);
897 }
898
899 gp_Vec GeomAdaptor_Curve::DNBSpline(const Standard_Real    U,
900                                     const Standard_Integer N) const
901 {
902   if ((U==myFirst || U==myLast))
903   {
904     Standard_Integer Ideb = 0, Ifin = 0;
905     if (U==myFirst) {
906       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
907       if (Ideb<1) Ideb=1;
908       if (Ideb>=Ifin) Ifin = Ideb+1;
909     }
910     if (U==myLast) {
911       myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
912       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
913       if (Ideb>=Ifin) Ideb = Ifin-1;
914     } 
915     return myBspl->LocalDN( U, Ideb, Ifin, N);
916   }
917   return myCurve->DN( U, N);
918 }
919
920 gp_Vec GeomAdaptor_Curve::DNOffset(const Standard_Real    U,
921                                    const Standard_Integer N) const
922 {
923   gp_Pnt aPnt;
924   gp_Vec aVec, aVN;
925
926   switch (N)
927   {
928   case 1:
929     D1Offset(U, aPnt, aVN);
930     break;
931   case 2:
932     D2Offset(U, aPnt, aVec, aVN);
933     break;
934   case 3:
935     D3Offset(U, aPnt, aVec, aVec, aVN);
936     break;
937   default:
938     aVN = myCurve->DN(U, N);
939   }
940   return aVN;
941 }
942
943 //=======================================================================
944 //function : Resolution
945 //purpose  : 
946 //=======================================================================
947
948 Standard_Real GeomAdaptor_Curve::Resolution(const Standard_Real R3D) const
949 {
950   switch ( myTypeCurve) {
951   case GeomAbs_Line :
952     return R3D;
953   case GeomAbs_Circle: {
954     Standard_Real R = Handle(Geom_Circle)::DownCast (myCurve)->Circ().Radius();
955     if ( R > R3D/2. )
956       return 2*ASin(R3D/(2*R));
957     else
958       return 2*M_PI;
959   }
960   case GeomAbs_Ellipse: {
961     return R3D / Handle(Geom_Ellipse)::DownCast (myCurve)->MajorRadius();
962   }
963   case GeomAbs_BezierCurve: {
964     Standard_Real res;
965     Handle(Geom_BezierCurve)::DownCast (myCurve)->Resolution(R3D,res);
966     return res;
967   }
968   case GeomAbs_BSplineCurve: {
969     Standard_Real res;
970     Handle(Geom_BSplineCurve)::DownCast (myCurve)->Resolution(R3D,res);
971     return res;
972   }
973   default:
974     return Precision::Parametric(R3D);
975   }  
976 }
977
978
979 //    --
980 //    --     The following methods must  be called when GetType returned
981 //    --     the corresponding type.
982 //    --     
983
984 //=======================================================================
985 //function : Line
986 //purpose  : 
987 //=======================================================================
988
989 gp_Lin GeomAdaptor_Curve::Line() const 
990 {
991   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Line, "");
992   return Handle(Geom_Line)::DownCast (myCurve)->Lin();  
993 }
994
995 //=======================================================================
996 //function : Circle
997 //purpose  : 
998 //=======================================================================
999
1000 gp_Circ  GeomAdaptor_Curve::Circle() const 
1001 {
1002   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Circle, "");
1003   return Handle(Geom_Circle)::DownCast (myCurve)->Circ();
1004 }
1005
1006 //=======================================================================
1007 //function : Ellipse
1008 //purpose  : 
1009 //=======================================================================
1010
1011 gp_Elips GeomAdaptor_Curve::Ellipse() const 
1012 {
1013   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Ellipse, "");
1014   return Handle(Geom_Ellipse)::DownCast (myCurve)->Elips();
1015 }
1016
1017 //=======================================================================
1018 //function : Hyperbola
1019 //purpose  : 
1020 //=======================================================================
1021
1022 gp_Hypr GeomAdaptor_Curve::Hyperbola() const 
1023 {
1024   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Hyperbola, "");
1025   return Handle(Geom_Hyperbola)::DownCast (myCurve)->Hypr();  
1026 }
1027
1028 //=======================================================================
1029 //function : Parabola
1030 //purpose  : 
1031 //=======================================================================
1032
1033 gp_Parab GeomAdaptor_Curve::Parabola() const 
1034 {
1035   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Parabola, "");
1036   return Handle(Geom_Parabola)::DownCast (myCurve)->Parab();
1037 }
1038
1039 //=======================================================================
1040 //function : Degree
1041 //purpose  : 
1042 //=======================================================================
1043
1044 Standard_Integer GeomAdaptor_Curve::Degree() const
1045 {
1046   if (myTypeCurve == GeomAbs_BezierCurve)
1047     return Handle(Geom_BezierCurve)::DownCast (myCurve)->Degree();
1048   else if (myTypeCurve == GeomAbs_BSplineCurve)
1049     return Handle(Geom_BSplineCurve)::DownCast (myCurve)->Degree();
1050   else
1051     Standard_NoSuchObject::Raise();
1052   // portage WNT 
1053   return 0;
1054 }
1055
1056 //=======================================================================
1057 //function : IsRational
1058 //purpose  : 
1059 //=======================================================================
1060
1061 Standard_Boolean GeomAdaptor_Curve::IsRational() const {
1062   switch( myTypeCurve) {
1063   case GeomAbs_BSplineCurve:
1064     return Handle(Geom_BSplineCurve)::DownCast (myCurve)->IsRational();
1065   case GeomAbs_BezierCurve:
1066     return Handle(Geom_BezierCurve)::DownCast (myCurve)->IsRational();
1067   default:
1068     return Standard_False;
1069   }
1070 }
1071
1072 //=======================================================================
1073 //function : NbPoles
1074 //purpose  : 
1075 //=======================================================================
1076
1077 Standard_Integer GeomAdaptor_Curve::NbPoles() const
1078 {
1079   if (myTypeCurve == GeomAbs_BezierCurve)
1080     return Handle(Geom_BezierCurve)::DownCast (myCurve)->NbPoles();
1081   else if (myTypeCurve == GeomAbs_BSplineCurve)
1082     return Handle(Geom_BSplineCurve)::DownCast (myCurve)->NbPoles();
1083   else
1084     Standard_NoSuchObject::Raise();
1085   // portage WNT
1086   return 0;
1087 }
1088
1089 //=======================================================================
1090 //function : NbKnots
1091 //purpose  : 
1092 //=======================================================================
1093
1094 Standard_Integer GeomAdaptor_Curve::NbKnots() const
1095 {
1096   if ( myTypeCurve != GeomAbs_BSplineCurve)
1097     Standard_NoSuchObject::Raise("GeomAdaptor_Curve::NbKnots");
1098   return Handle(Geom_BSplineCurve)::DownCast (myCurve)->NbKnots();
1099 }
1100
1101 //=======================================================================
1102 //function : Bezier
1103 //purpose  : 
1104 //=======================================================================
1105
1106 Handle(Geom_BezierCurve) GeomAdaptor_Curve::Bezier() const 
1107 {
1108  if ( myTypeCurve != GeomAbs_BezierCurve)
1109     Standard_NoSuchObject::Raise("GeomAdaptor_Curve::Bezier");
1110   return Handle(Geom_BezierCurve)::DownCast (myCurve);
1111 }
1112
1113 //=======================================================================
1114 //function : BSpline
1115 //purpose  : 
1116 //=======================================================================
1117
1118 Handle(Geom_BSplineCurve) GeomAdaptor_Curve::BSpline() const 
1119 {
1120  if ( myTypeCurve != GeomAbs_BSplineCurve)
1121     Standard_NoSuchObject::Raise("GeomAdaptor_Curve::BSpline");
1122
1123   return Handle(Geom_BSplineCurve)::DownCast (myCurve);
1124 }
1125
1126
1127 // ============= Auxiliary functions ===================
1128 Standard_Boolean AdjustDerivative(const Handle(Adaptor3d_HCurve)& theAdaptor, Standard_Integer theMaxDerivative,
1129                                   Standard_Real theU, gp_Vec& theD1, gp_Vec& theD2,
1130                                   gp_Vec& theD3, gp_Vec& theD4)
1131 {
1132   static const Standard_Real aTol = gp::Resolution();
1133
1134   Standard_Boolean IsDirectionChange = Standard_False;
1135   const Standard_Real anUinfium   = theAdaptor->FirstParameter();
1136   const Standard_Real anUsupremum = theAdaptor->LastParameter();
1137
1138   const Standard_Real DivisionFactor = 1.e-3;
1139   Standard_Real du;
1140   if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
1141     du = 0.0;
1142   else
1143     du = anUsupremum - anUinfium;
1144
1145   const Standard_Real aDelta = Max(du * DivisionFactor, MinStep);
1146
1147   //Derivative is approximated by Taylor-series
1148   Standard_Integer anIndex = 1; //Derivative order
1149   gp_Vec V;
1150
1151   do
1152   {
1153     V =  theAdaptor->DN(theU, ++anIndex);
1154   }
1155   while((V.SquareMagnitude() <= aTol) && anIndex < maxDerivOrder);
1156
1157   Standard_Real u;
1158
1159   if(theU-anUinfium < aDelta)
1160     u = theU+aDelta;
1161   else
1162     u = theU-aDelta;
1163
1164   gp_Pnt P1, P2;
1165   theAdaptor->D0(Min(theU, u), P1);
1166   theAdaptor->D0(Max(theU, u), P2);
1167
1168   gp_Vec V1(P1, P2);
1169   IsDirectionChange = V.Dot(V1) < 0.0;
1170   Standard_Real aSign = IsDirectionChange ? -1.0 : 1.0;
1171
1172   theD1 = V * aSign;
1173   gp_Vec* aDeriv[3] = {&theD2, &theD3, &theD4};
1174   for (Standard_Integer i = 1; i < theMaxDerivative; i++)
1175     *(aDeriv[i-1]) = theAdaptor->DN(theU, anIndex + i) * aSign;
1176
1177   return IsDirectionChange;
1178 }