0028724: Extrema between circle and plane cannot be found
[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 <Geom_BezierCurve.hxx>
29 #include <Geom_BSplineCurve.hxx>
30 #include <Geom_Circle.hxx>
31 #include <Geom_Curve.hxx>
32 #include <Geom_Ellipse.hxx>
33 #include <Geom_Hyperbola.hxx>
34 #include <Geom_Line.hxx>
35 #include <Geom_OffsetCurve.hxx>
36 #include <Geom_Parabola.hxx>
37 #include <Geom_TrimmedCurve.hxx>
38 #include <GeomAbs_Shape.hxx>
39 #include <GeomAdaptor_Curve.hxx>
40 #include <GeomAdaptor_HCurve.hxx>
41 #include <GeomAdaptor_Surface.hxx>
42 #include <GeomEvaluator_OffsetCurve.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 static const Standard_Real PosTol = Precision::PConfusion() / 2;
64
65
66 //=======================================================================
67 //function : LocalContinuity
68 //purpose  : Computes the Continuity of a BSplineCurve 
69 //           between the parameters U1 and U2
70 //           The continuity is C(d-m) 
71 //             with   d = degree, 
72 //                    m = max multiplicity of the Knots between U1 and U2
73 //=======================================================================
74
75 GeomAbs_Shape GeomAdaptor_Curve::LocalContinuity(const Standard_Real U1, 
76                                                  const Standard_Real U2) 
77      const 
78 {
79   Standard_NoSuchObject_Raise_if(myTypeCurve!=GeomAbs_BSplineCurve," ");
80   Standard_Integer Nb = myBSplineCurve->NbKnots();
81   Standard_Integer Index1 = 0;
82   Standard_Integer Index2 = 0;
83   Standard_Real newFirst, newLast;
84   const TColStd_Array1OfReal& TK = myBSplineCurve->Knots();
85   const TColStd_Array1OfInteger& TM = myBSplineCurve->Multiplicities();
86   BSplCLib::LocateParameter(myBSplineCurve->Degree(),TK,TM,U1,myBSplineCurve->IsPeriodic(),
87                             1,Nb,Index1,newFirst);
88   BSplCLib::LocateParameter(myBSplineCurve->Degree(),TK,TM,U2,myBSplineCurve->IsPeriodic(),
89                             1,Nb,Index2,newLast);
90   if ( Abs(newFirst-TK(Index1+1))<Precision::PConfusion()) { 
91     if (Index1 < Nb) Index1++;
92   }
93   if ( Abs(newLast-TK(Index2))<Precision::PConfusion())
94     Index2--;
95   Standard_Integer MultMax;
96   // attention aux courbes peridiques.
97   if ( (myBSplineCurve->IsPeriodic()) && (Index1 == Nb) )
98     Index1 = 1;
99
100   if ( Index2 - Index1 <= 0) {
101     MultMax = 100;  // CN entre 2 Noeuds consecutifs
102   }
103   else {
104     MultMax = TM(Index1+1);
105     for(Standard_Integer i = Index1+1;i<=Index2;i++) {
106       if ( TM(i)>MultMax) MultMax=TM(i);
107     }
108     MultMax = myBSplineCurve->Degree() - MultMax;
109   }
110   if ( MultMax <= 0) {
111     return GeomAbs_C0;
112   }
113   else if ( MultMax == 1) {
114     return GeomAbs_C1;
115   } 
116   else if ( MultMax == 2) {
117     return GeomAbs_C2;
118   }
119   else if ( MultMax == 3) {
120     return GeomAbs_C3;
121   }
122   else { 
123     return GeomAbs_CN;
124   }
125 }
126
127
128 //=======================================================================
129 //function : Load
130 //purpose  : 
131 //=======================================================================
132
133 void GeomAdaptor_Curve::load(const Handle(Geom_Curve)& C,
134                              const Standard_Real UFirst,
135                              const Standard_Real ULast)
136 {
137   myFirst = UFirst;
138   myLast  = ULast;
139   myCurveCache.Nullify();
140
141   if ( myCurve != C) {
142     myCurve = C;
143     myNestedEvaluator.Nullify();
144     myBSplineCurve.Nullify();
145     
146     const Handle(Standard_Type)& TheType = C->DynamicType();
147     if ( TheType == STANDARD_TYPE(Geom_TrimmedCurve)) {
148       Load(Handle(Geom_TrimmedCurve)::DownCast (C)->BasisCurve(),UFirst,ULast);
149     }
150     else if ( TheType ==  STANDARD_TYPE(Geom_Circle)) {
151       myTypeCurve = GeomAbs_Circle;
152     }
153     else if ( TheType ==STANDARD_TYPE(Geom_Line)) {
154       myTypeCurve = GeomAbs_Line;
155     }
156     else if ( TheType == STANDARD_TYPE(Geom_Ellipse)) {
157       myTypeCurve = GeomAbs_Ellipse;
158     }
159     else if ( TheType == STANDARD_TYPE(Geom_Parabola)) {
160       myTypeCurve = GeomAbs_Parabola;
161     }
162     else if ( TheType == STANDARD_TYPE(Geom_Hyperbola)) {
163       myTypeCurve = GeomAbs_Hyperbola;
164     }
165     else if ( TheType == STANDARD_TYPE(Geom_BezierCurve)) {
166       myTypeCurve = GeomAbs_BezierCurve;
167     }
168     else if ( TheType == STANDARD_TYPE(Geom_BSplineCurve)) {
169       myTypeCurve = GeomAbs_BSplineCurve;
170       myBSplineCurve = Handle(Geom_BSplineCurve)::DownCast(myCurve);
171     }
172     else if ( TheType == STANDARD_TYPE(Geom_OffsetCurve)) {
173       myTypeCurve = GeomAbs_OffsetCurve;
174       Handle(Geom_OffsetCurve) anOffsetCurve = Handle(Geom_OffsetCurve)::DownCast(myCurve);
175       // Create nested adaptor for base curve
176       Handle(Geom_Curve) aBaseCurve = anOffsetCurve->BasisCurve();
177       Handle(GeomAdaptor_HCurve) aBaseAdaptor = new GeomAdaptor_HCurve(aBaseCurve);
178       myNestedEvaluator = new GeomEvaluator_OffsetCurve(
179           aBaseAdaptor, anOffsetCurve->Offset(), anOffsetCurve->Direction());
180     }
181     else {
182       myTypeCurve = GeomAbs_OtherCurve;
183     }
184   }
185 }
186
187 //    --
188 //    --     Global methods - Apply to the whole curve.
189 //    --     
190
191 //=======================================================================
192 //function : Continuity
193 //purpose  : 
194 //=======================================================================
195
196 GeomAbs_Shape GeomAdaptor_Curve::Continuity() const 
197 {
198   if (myTypeCurve == GeomAbs_BSplineCurve)
199     return LocalContinuity(myFirst, myLast);
200
201   if (myTypeCurve == GeomAbs_OffsetCurve)
202   {
203     const GeomAbs_Shape S =
204       Handle(Geom_OffsetCurve)::DownCast (myCurve)->GetBasisCurveContinuity();
205     switch(S)
206     {
207       case GeomAbs_CN: return GeomAbs_CN;
208       case GeomAbs_C3: return GeomAbs_C2;
209       case GeomAbs_C2: return GeomAbs_C1;
210       case GeomAbs_C1: return GeomAbs_C0; 
211       case GeomAbs_G1: return GeomAbs_G1;
212       case GeomAbs_G2: return GeomAbs_G2;
213       default:
214         throw Standard_NoSuchObject("GeomAdaptor_Curve::Continuity");
215     }
216   }
217   else if (myTypeCurve == GeomAbs_OtherCurve) {
218     throw Standard_NoSuchObject("GeomAdaptor_Curve::Contunuity");
219   }
220
221   return GeomAbs_CN;
222 }
223
224 //=======================================================================
225 //function : NbIntervals
226 //purpose  : 
227 //=======================================================================
228
229 Standard_Integer GeomAdaptor_Curve::NbIntervals(const GeomAbs_Shape S) const
230 {
231   Standard_Integer myNbIntervals = 1;
232   Standard_Integer NbSplit;
233   if (myTypeCurve == GeomAbs_BSplineCurve) {
234     Standard_Integer FirstIndex = myBSplineCurve->FirstUKnotIndex();
235     Standard_Integer LastIndex  = myBSplineCurve->LastUKnotIndex();
236     TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
237     if ( S > Continuity()) {
238       Standard_Integer Cont;
239       switch ( S) {
240       case GeomAbs_G1:
241       case GeomAbs_G2:
242         throw Standard_DomainError("GeomAdaptor_Curve::NbIntervals");
243         break;
244       case GeomAbs_C0:
245         myNbIntervals = 1;
246         break;
247       case GeomAbs_C1:
248       case GeomAbs_C2:
249       case GeomAbs_C3: 
250       case GeomAbs_CN: 
251         {
252           if      ( S == GeomAbs_C1) Cont = 1;
253           else if ( S == GeomAbs_C2) Cont = 2;
254           else if ( S == GeomAbs_C3) Cont = 3;
255           else                       Cont = myBSplineCurve->Degree();
256           Standard_Integer Degree = myBSplineCurve->Degree();
257           Standard_Integer NbKnots = myBSplineCurve->NbKnots();
258           TColStd_Array1OfInteger Mults (1, NbKnots);
259           myBSplineCurve->Multiplicities (Mults);
260           NbSplit = 1;
261           Standard_Integer Index   = FirstIndex;
262           Inter (NbSplit) = Index;
263           Index++;
264           NbSplit++;
265           while (Index < LastIndex) 
266             {
267               if (Degree - Mults (Index) < Cont) 
268                 {
269                   Inter (NbSplit) = Index;
270                   NbSplit++;
271                 }
272               Index++;
273             }
274           Inter (NbSplit) = Index;
275
276           Standard_Integer NbInt = NbSplit-1;
277           
278           Standard_Integer Nb = myBSplineCurve->NbKnots();
279           Standard_Integer Index1 = 0;
280           Standard_Integer Index2 = 0;
281           Standard_Real newFirst, newLast;
282           const TColStd_Array1OfReal& TK = myBSplineCurve->Knots();
283           const TColStd_Array1OfInteger& TM = myBSplineCurve->Multiplicities();
284           BSplCLib::LocateParameter(myBSplineCurve->Degree(),TK,TM,myFirst,
285                                     myBSplineCurve->IsPeriodic(),
286                                     1,Nb,Index1,newFirst);
287           BSplCLib::LocateParameter(myBSplineCurve->Degree(),TK,TM,myLast,
288                                     myBSplineCurve->IsPeriodic(),
289                                     1,Nb,Index2,newLast);
290
291           // On decale eventuellement les indices  
292           // On utilise une "petite" tolerance, la resolution ne doit 
293           // servir que pour les tres longue courbes....(PRO9248)
294           Standard_Real Eps = Min(Resolution(Precision::Confusion()),
295                                   Precision::PConfusion()); 
296           if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
297           if ( newLast-TK(Index2)> Eps) Index2++;
298           
299           myNbIntervals = 1;
300           for ( Standard_Integer i=1; i<=NbInt; i++)
301             if (Inter(i)>Index1 && Inter(i)<Index2) myNbIntervals++;
302         }
303         break;
304       }
305     }
306   }
307   
308   else if (myTypeCurve == GeomAbs_OffsetCurve) {
309     GeomAbs_Shape BaseS=GeomAbs_C0;
310     switch(S){
311     case GeomAbs_G1:
312     case GeomAbs_G2:
313       throw Standard_DomainError("GeomAdaptor_Curve::NbIntervals");
314       break;
315     case GeomAbs_C0: BaseS = GeomAbs_C1; break;
316     case GeomAbs_C1: BaseS = GeomAbs_C2; break;
317     case GeomAbs_C2: BaseS = GeomAbs_C3; break;
318     default: BaseS = GeomAbs_CN;
319     }
320     GeomAdaptor_Curve C
321       (Handle(Geom_OffsetCurve)::DownCast (myCurve)->BasisCurve());
322     // akm 05/04/02 (OCC278)  If our curve is trimmed we must recalculate 
323     //                    the number of intervals obtained from the basis to
324     //              vvv   reflect parameter bounds
325     Standard_Integer iNbBasisInt = C.NbIntervals(BaseS), iInt;
326     if (iNbBasisInt>1)
327     {
328       TColStd_Array1OfReal rdfInter(1,1+iNbBasisInt);
329       C.Intervals(rdfInter,BaseS);
330       for (iInt=1; iInt<=iNbBasisInt; iInt++)
331         if (rdfInter(iInt)>myFirst && rdfInter(iInt)<myLast)
332           myNbIntervals++;
333     }
334     // akm 05/04/02 ^^^
335   }
336   return myNbIntervals;
337 }
338
339 //=======================================================================
340 //function : Intervals
341 //purpose  : 
342 //=======================================================================
343
344 void GeomAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
345                                   const GeomAbs_Shape S   ) const
346 {
347   Standard_Integer myNbIntervals = 1;
348   Standard_Integer NbSplit;
349   Standard_Real FirstParam = myFirst, LastParam = myLast;
350
351   if (myTypeCurve == GeomAbs_BSplineCurve) 
352     {
353       Standard_Integer FirstIndex = myBSplineCurve->FirstUKnotIndex();
354       Standard_Integer LastIndex  = myBSplineCurve->LastUKnotIndex();
355       TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
356       
357       if ( S > Continuity()) {
358         Standard_Integer Cont;
359         switch ( S) {
360         case GeomAbs_G1:
361         case GeomAbs_G2:
362           throw Standard_DomainError("Geom2dAdaptor_Curve::NbIntervals");
363           break;
364         case GeomAbs_C0:
365           myNbIntervals = 1;
366           break;
367         case GeomAbs_C1:
368         case GeomAbs_C2:
369         case GeomAbs_C3: 
370         case GeomAbs_CN: 
371           {
372             if      ( S == GeomAbs_C1) Cont = 1;
373             else if ( S == GeomAbs_C2) Cont = 2;
374             else if ( S == GeomAbs_C3) Cont = 3;
375             else                       Cont = myBSplineCurve->Degree();
376             Standard_Integer Degree = myBSplineCurve->Degree();
377             Standard_Integer NbKnots = myBSplineCurve->NbKnots();
378             TColStd_Array1OfInteger Mults (1, NbKnots);
379             myBSplineCurve->Multiplicities (Mults);
380             NbSplit = 1;
381             Standard_Integer Index   = FirstIndex;
382             Inter (NbSplit) = Index;
383             Index++;
384             NbSplit++;
385             while (Index < LastIndex) 
386               {
387                 if (Degree - Mults (Index) < Cont) 
388                   {
389                     Inter (NbSplit) = Index;
390                     NbSplit++;
391                   }
392                 Index++;
393               }
394             Inter (NbSplit) = Index;
395             Standard_Integer NbInt = NbSplit-1;
396             //        GeomConvert_BSplineCurveKnotSplitting Convector(myBspl, Cont);
397             //        Standard_Integer NbInt = Convector.NbSplits()-1;
398             //        TColStd_Array1OfInteger Inter(1,NbInt+1);
399             //        Convector.Splitting( Inter);
400             
401             Standard_Integer Nb = myBSplineCurve->NbKnots();
402             Standard_Integer Index1 = 0;
403             Standard_Integer Index2 = 0;
404             Standard_Real newFirst, newLast;
405             const TColStd_Array1OfReal& TK = myBSplineCurve->Knots();
406             const TColStd_Array1OfInteger& TM = myBSplineCurve->Multiplicities();
407             BSplCLib::LocateParameter(myBSplineCurve->Degree(),TK,TM,myFirst,
408                                       myBSplineCurve->IsPeriodic(),
409                                       1,Nb,Index1,newFirst);
410             BSplCLib::LocateParameter(myBSplineCurve->Degree(),TK,TM,myLast,
411                                       myBSplineCurve->IsPeriodic(),
412                                       1,Nb,Index2,newLast);
413             FirstParam = newFirst;
414             LastParam = newLast;
415             // On decale eventuellement les indices  
416             // On utilise une "petite" tolerance, la resolution ne doit 
417             // servir que pour les tres longue courbes....(PRO9248)
418             Standard_Real Eps = Min(Resolution(Precision::Confusion()),
419                                     Precision::PConfusion()); 
420             if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
421             if ( newLast-TK(Index2)> Eps) Index2++;
422             
423             Inter( 1) = Index1;
424             myNbIntervals = 1;
425             for ( Standard_Integer i=1; i<=NbInt; i++) {
426               if (Inter(i) > Index1 && Inter(i)<Index2 ) {
427                 myNbIntervals++;
428                 Inter(myNbIntervals) = Inter(i);
429               }
430             }
431             Inter(myNbIntervals+1) = Index2;
432             
433             for (Standard_Integer I=1;I<=myNbIntervals+1;I++) {
434               T(I) = TK(Inter(I));
435             }
436           }
437           break;
438         }
439       }
440     }
441
442   else if (myTypeCurve == GeomAbs_OffsetCurve){
443     GeomAbs_Shape BaseS=GeomAbs_C0;
444     switch(S){
445     case GeomAbs_G1:
446     case GeomAbs_G2:
447       throw Standard_DomainError("GeomAdaptor_Curve::NbIntervals");
448       break;
449     case GeomAbs_C0: BaseS = GeomAbs_C1; break;
450     case GeomAbs_C1: BaseS = GeomAbs_C2; break;
451     case GeomAbs_C2: BaseS = GeomAbs_C3; break;
452     default: BaseS = GeomAbs_CN;
453     }
454     GeomAdaptor_Curve C
455       (Handle(Geom_OffsetCurve)::DownCast (myCurve)->BasisCurve());
456     // akm 05/04/02 (OCC278)  If our curve is trimmed we must recalculate 
457     //                    the array of intervals obtained from the basis to
458     //              vvv   reflect parameter bounds
459     Standard_Integer iNbBasisInt = C.NbIntervals(BaseS), iInt;
460     if (iNbBasisInt>1)
461     {
462       TColStd_Array1OfReal rdfInter(1,1+iNbBasisInt);
463       C.Intervals(rdfInter,BaseS);
464       for (iInt=1; iInt<=iNbBasisInt; iInt++)
465         if (rdfInter(iInt)>myFirst && rdfInter(iInt)<myLast)
466           T(++myNbIntervals)=rdfInter(iInt);
467     }
468     // old - myNbIntervals = C.NbIntervals(BaseS);
469     // old - C.Intervals(T, BaseS);
470     // akm 05/04/02 ^^^
471   }
472   
473   T( T.Lower() ) = FirstParam;
474   T( T.Lower() + myNbIntervals ) = LastParam;
475 }
476
477 //=======================================================================
478 //function : Trim
479 //purpose  : 
480 //=======================================================================
481
482 Handle(Adaptor3d_HCurve) GeomAdaptor_Curve::Trim(const Standard_Real First,
483                                                  const Standard_Real Last,
484                                                  const Standard_Real /*Tol*/) const
485 {
486   return Handle(GeomAdaptor_HCurve)(new GeomAdaptor_HCurve(myCurve,First,Last));
487 }
488
489
490 //=======================================================================
491 //function : IsClosed
492 //purpose  : 
493 //=======================================================================
494
495 Standard_Boolean GeomAdaptor_Curve::IsClosed() const
496 {
497   if (!Precision::IsPositiveInfinite(myLast) &&
498       !Precision::IsNegativeInfinite(myFirst))
499   {
500     const gp_Pnt Pd = Value(myFirst);
501     const gp_Pnt Pf = Value(myLast);
502     return (Pd.Distance(Pf) <= Precision::Confusion());
503   }
504   return Standard_False;
505 }
506
507 //=======================================================================
508 //function : IsPeriodic
509 //purpose  : 
510 //=======================================================================
511
512 Standard_Boolean GeomAdaptor_Curve::IsPeriodic() const 
513 {
514   return myCurve->IsPeriodic();
515 }
516
517 //=======================================================================
518 //function : Period
519 //purpose  : 
520 //=======================================================================
521
522 Standard_Real GeomAdaptor_Curve::Period() const 
523 {
524   return myCurve->LastParameter() - myCurve->FirstParameter();
525 }
526
527 //=======================================================================
528 //function : RebuildCache
529 //purpose  : 
530 //=======================================================================
531 void GeomAdaptor_Curve::RebuildCache(const Standard_Real theParameter) const
532 {
533   if (myTypeCurve == GeomAbs_BezierCurve)
534   {
535     // Create cache for Bezier
536     Handle(Geom_BezierCurve) aBezier = Handle(Geom_BezierCurve)::DownCast(myCurve);
537     Standard_Integer aDeg = aBezier->Degree();
538     TColStd_Array1OfReal aFlatKnots(BSplCLib::FlatBezierKnots(aDeg), 1, 2 * (aDeg + 1));
539     if (myCurveCache.IsNull())
540       myCurveCache = new BSplCLib_Cache(aDeg, aBezier->IsPeriodic(), aFlatKnots,
541         aBezier->Poles(), aBezier->Weights());
542     myCurveCache->BuildCache(theParameter, aDeg, aBezier->IsPeriodic(), aFlatKnots,
543         aBezier->Poles(), aBezier->Weights());
544 }
545   else if (myTypeCurve == GeomAbs_BSplineCurve)
546 {
547     // Create cache for B-spline
548     if (myCurveCache.IsNull())
549       myCurveCache = new BSplCLib_Cache(myBSplineCurve->Degree(), myBSplineCurve->IsPeriodic(),
550         myBSplineCurve->KnotSequence(), myBSplineCurve->Poles(), myBSplineCurve->Weights());
551     myCurveCache->BuildCache(theParameter, myBSplineCurve->Degree(),
552         myBSplineCurve->IsPeriodic(), myBSplineCurve->KnotSequence(),
553         myBSplineCurve->Poles(), myBSplineCurve->Weights());
554 }
555 }
556
557 //=======================================================================
558 //function : IsBoundary
559 //purpose  : 
560 //=======================================================================
561 Standard_Boolean GeomAdaptor_Curve::IsBoundary(const Standard_Real theU,
562                                                Standard_Integer& theSpanStart,
563                                                Standard_Integer& theSpanFinish) const
564 {
565   if (!myBSplineCurve.IsNull() && (theU == myFirst || theU == myLast))
566   {
567     if (theU == myFirst)
568     {
569       myBSplineCurve->LocateU(myFirst, PosTol, theSpanStart, theSpanFinish);
570       if (theSpanStart < 1)
571         theSpanStart = 1;
572       if (theSpanStart >= theSpanFinish)
573         theSpanFinish = theSpanStart + 1;
574     }
575     else if (theU == myLast)
576     {
577       myBSplineCurve->LocateU(myLast, PosTol, theSpanStart, theSpanFinish);
578       if (theSpanFinish > myBSplineCurve->NbKnots())
579         theSpanFinish = myBSplineCurve->NbKnots();
580       if (theSpanStart >= theSpanFinish)
581         theSpanStart = theSpanFinish - 1;
582     }
583     return Standard_True;
584   }
585   return Standard_False;
586   }
587
588 //=======================================================================
589 //function : Value
590 //purpose  : 
591 //=======================================================================
592
593 gp_Pnt GeomAdaptor_Curve::Value(const Standard_Real U) const
594 {
595   gp_Pnt aValue;
596   D0(U, aValue);
597   return aValue;
598 }
599
600 //=======================================================================
601 //function : D0
602 //purpose  : 
603 //=======================================================================
604
605 void GeomAdaptor_Curve::D0(const Standard_Real U, gp_Pnt& P) const
606 {
607   switch (myTypeCurve)
608 {
609   case GeomAbs_BezierCurve:
610   case GeomAbs_BSplineCurve:
611   {
612     Standard_Integer aStart = 0, aFinish = 0;
613     if (IsBoundary(U, aStart, aFinish))
614     {
615       myBSplineCurve->LocalD0(U, aStart, aFinish, P);
616     }
617     else
618   {
619       // use cached data
620       if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U))
621         RebuildCache(U);
622       myCurveCache->D0(U, P);
623   }
624     break;
625 }
626
627   case GeomAbs_OffsetCurve:
628     myNestedEvaluator->D0(U, P);
629     break;
630
631   default:
632     myCurve->D0(U, P);
633 }
634 }
635
636 //=======================================================================
637 //function : D1
638 //purpose  : 
639 //=======================================================================
640
641 void GeomAdaptor_Curve::D1(const Standard_Real U, gp_Pnt& P, gp_Vec& V) const 
642 {
643   switch (myTypeCurve)
644 {
645   case GeomAbs_BezierCurve:
646   case GeomAbs_BSplineCurve:
647   {
648     Standard_Integer aStart = 0, aFinish = 0;
649     if (IsBoundary(U, aStart, aFinish))
650     {
651       myBSplineCurve->LocalD1(U, aStart, aFinish, P, V);
652     }
653     else
654   {
655       // use cached data
656       if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U))
657         RebuildCache(U);
658       myCurveCache->D1(U, P, V);
659   }
660     break;
661 }
662
663   case GeomAbs_OffsetCurve:
664     myNestedEvaluator->D1(U, P, V);
665     break;
666
667   default:
668     myCurve->D1(U, P, V);
669 }
670 }
671
672 //=======================================================================
673 //function : D2
674 //purpose  : 
675 //=======================================================================
676
677 void GeomAdaptor_Curve::D2(const Standard_Real U, 
678                            gp_Pnt& P, gp_Vec& V1, gp_Vec& V2) const 
679 {
680   switch (myTypeCurve)
681 {
682   case GeomAbs_BezierCurve:
683   case GeomAbs_BSplineCurve:
684   {
685     Standard_Integer aStart = 0, aFinish = 0;
686     if (IsBoundary(U, aStart, aFinish))
687     {
688       myBSplineCurve->LocalD2(U, aStart, aFinish, P, V1, V2);
689     }
690     else
691   {
692       // use cached data
693       if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U))
694         RebuildCache(U);
695       myCurveCache->D2(U, P, V1, V2);
696   }
697     break;
698 }
699
700   case GeomAbs_OffsetCurve:
701     myNestedEvaluator->D2(U, P, V1, V2);
702     break;
703
704   default:
705     myCurve->D2(U, P, V1, V2);
706 }
707 }
708
709 //=======================================================================
710 //function : D3
711 //purpose  : 
712 //=======================================================================
713
714 void GeomAdaptor_Curve::D3(const Standard_Real U, 
715                            gp_Pnt& P, gp_Vec& V1, 
716                            gp_Vec& V2, gp_Vec& V3) const 
717 {
718   switch (myTypeCurve)
719 {
720   case GeomAbs_BezierCurve:
721   case GeomAbs_BSplineCurve:
722   {
723     Standard_Integer aStart = 0, aFinish = 0;
724     if (IsBoundary(U, aStart, aFinish))
725     {
726       myBSplineCurve->LocalD3(U, aStart, aFinish, P, V1, V2, V3);
727     }
728     else
729   {
730       // use cached data
731       if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U))
732         RebuildCache(U);
733       myCurveCache->D3(U, P, V1, V2, V3);
734   }
735     break;
736 }
737
738   case GeomAbs_OffsetCurve:
739     myNestedEvaluator->D3(U, P, V1, V2, V3);
740     break;
741
742   default:
743     myCurve->D3(U, P, V1, V2, V3);
744 }
745 }
746
747 //=======================================================================
748 //function : DN
749 //purpose  : 
750 //=======================================================================
751
752 gp_Vec GeomAdaptor_Curve::DN(const Standard_Real    U, 
753                              const Standard_Integer N) const 
754 {
755   switch (myTypeCurve)
756 {
757   case GeomAbs_BezierCurve:
758   case GeomAbs_BSplineCurve:
759   {
760     Standard_Integer aStart = 0, aFinish = 0;
761     if (IsBoundary(U, aStart, aFinish))
762     {
763       return myBSplineCurve->LocalDN(U, aStart, aFinish, N);
764     }
765     else
766   return myCurve->DN( U, N);
767     break;
768 }
769
770   case GeomAbs_OffsetCurve:
771     return myNestedEvaluator->DN(U, N);
772     break;
773
774   default: // to eliminate gcc warning
775     break;
776   }
777   return myCurve->DN(U, N);
778 }
779
780 //=======================================================================
781 //function : Resolution
782 //purpose  : 
783 //=======================================================================
784
785 Standard_Real GeomAdaptor_Curve::Resolution(const Standard_Real R3D) const
786 {
787   switch ( myTypeCurve) {
788   case GeomAbs_Line :
789     return R3D;
790   case GeomAbs_Circle: {
791     Standard_Real R = Handle(Geom_Circle)::DownCast (myCurve)->Circ().Radius();
792     if ( R > R3D/2. )
793       return 2*ASin(R3D/(2*R));
794     else
795       return 2*M_PI;
796   }
797   case GeomAbs_Ellipse: {
798     return R3D / Handle(Geom_Ellipse)::DownCast (myCurve)->MajorRadius();
799   }
800   case GeomAbs_BezierCurve: {
801     Standard_Real res;
802     Handle(Geom_BezierCurve)::DownCast (myCurve)->Resolution(R3D,res);
803     return res;
804   }
805   case GeomAbs_BSplineCurve: {
806     Standard_Real res;
807     myBSplineCurve->Resolution(R3D,res);
808     return res;
809   }
810   default:
811     return Precision::Parametric(R3D);
812   }  
813 }
814
815
816 //    --
817 //    --     The following methods must  be called when GetType returned
818 //    --     the corresponding type.
819 //    --     
820
821 //=======================================================================
822 //function : Line
823 //purpose  : 
824 //=======================================================================
825
826 gp_Lin GeomAdaptor_Curve::Line() const 
827 {
828   Standard_NoSuchObject_Raise_if (myTypeCurve != GeomAbs_Line,
829                                   "GeomAdaptor_Curve::Line() - curve is not a Line");
830   return Handle(Geom_Line)::DownCast (myCurve)->Lin();  
831 }
832
833 //=======================================================================
834 //function : Circle
835 //purpose  : 
836 //=======================================================================
837
838 gp_Circ  GeomAdaptor_Curve::Circle() const 
839 {
840   Standard_NoSuchObject_Raise_if (myTypeCurve != GeomAbs_Circle,
841                                   "GeomAdaptor_Curve::Circle() - curve is not a Circle");
842   return Handle(Geom_Circle)::DownCast (myCurve)->Circ();
843 }
844
845 //=======================================================================
846 //function : Ellipse
847 //purpose  : 
848 //=======================================================================
849
850 gp_Elips GeomAdaptor_Curve::Ellipse() const 
851 {
852   Standard_NoSuchObject_Raise_if (myTypeCurve != GeomAbs_Ellipse,
853                                   "GeomAdaptor_Curve::Ellipse() - curve is not an Ellipse");
854   return Handle(Geom_Ellipse)::DownCast (myCurve)->Elips();
855 }
856
857 //=======================================================================
858 //function : Hyperbola
859 //purpose  : 
860 //=======================================================================
861
862 gp_Hypr GeomAdaptor_Curve::Hyperbola() const 
863 {
864   Standard_NoSuchObject_Raise_if (myTypeCurve != GeomAbs_Hyperbola,
865                                   "GeomAdaptor_Curve::Hyperbola() - curve is not a Hyperbola");
866   return Handle(Geom_Hyperbola)::DownCast (myCurve)->Hypr();  
867 }
868
869 //=======================================================================
870 //function : Parabola
871 //purpose  : 
872 //=======================================================================
873
874 gp_Parab GeomAdaptor_Curve::Parabola() const 
875 {
876   Standard_NoSuchObject_Raise_if (myTypeCurve != GeomAbs_Parabola,
877                                   "GeomAdaptor_Curve::Parabola() - curve is not a Parabola");
878   return Handle(Geom_Parabola)::DownCast (myCurve)->Parab();
879 }
880
881 //=======================================================================
882 //function : Degree
883 //purpose  : 
884 //=======================================================================
885
886 Standard_Integer GeomAdaptor_Curve::Degree() const
887 {
888   if (myTypeCurve == GeomAbs_BezierCurve)
889     return Handle(Geom_BezierCurve)::DownCast (myCurve)->Degree();
890   else if (myTypeCurve == GeomAbs_BSplineCurve)
891     return myBSplineCurve->Degree();
892   else
893     throw Standard_NoSuchObject();
894 }
895
896 //=======================================================================
897 //function : IsRational
898 //purpose  : 
899 //=======================================================================
900
901 Standard_Boolean GeomAdaptor_Curve::IsRational() const {
902   switch( myTypeCurve) {
903   case GeomAbs_BSplineCurve:
904     return myBSplineCurve->IsRational();
905   case GeomAbs_BezierCurve:
906     return Handle(Geom_BezierCurve)::DownCast (myCurve)->IsRational();
907   default:
908     return Standard_False;
909   }
910 }
911
912 //=======================================================================
913 //function : NbPoles
914 //purpose  : 
915 //=======================================================================
916
917 Standard_Integer GeomAdaptor_Curve::NbPoles() const
918 {
919   if (myTypeCurve == GeomAbs_BezierCurve)
920     return Handle(Geom_BezierCurve)::DownCast (myCurve)->NbPoles();
921   else if (myTypeCurve == GeomAbs_BSplineCurve)
922     return myBSplineCurve->NbPoles();
923   else
924     throw Standard_NoSuchObject();
925 }
926
927 //=======================================================================
928 //function : NbKnots
929 //purpose  : 
930 //=======================================================================
931
932 Standard_Integer GeomAdaptor_Curve::NbKnots() const
933 {
934   if ( myTypeCurve != GeomAbs_BSplineCurve)
935     throw Standard_NoSuchObject("GeomAdaptor_Curve::NbKnots");
936   return myBSplineCurve->NbKnots();
937 }
938
939 //=======================================================================
940 //function : Bezier
941 //purpose  : 
942 //=======================================================================
943
944 Handle(Geom_BezierCurve) GeomAdaptor_Curve::Bezier() const 
945 {
946  if ( myTypeCurve != GeomAbs_BezierCurve)
947     throw Standard_NoSuchObject("GeomAdaptor_Curve::Bezier");
948   return Handle(Geom_BezierCurve)::DownCast (myCurve);
949 }
950
951 //=======================================================================
952 //function : BSpline
953 //purpose  : 
954 //=======================================================================
955
956 Handle(Geom_BSplineCurve) GeomAdaptor_Curve::BSpline() const 
957 {
958  if ( myTypeCurve != GeomAbs_BSplineCurve)
959     throw Standard_NoSuchObject("GeomAdaptor_Curve::BSpline");
960
961   return myBSplineCurve;
962 }
963
964 //=======================================================================
965 //function : BasisCurve
966 //purpose  : 
967 //=======================================================================
968
969 Handle(Geom_OffsetCurve) GeomAdaptor_Curve::OffsetCurve() const
970 {
971   if ( myTypeCurve != GeomAbs_OffsetCurve)
972     throw Standard_NoSuchObject("GeomAdaptor_Curve::OffsetCurve");
973   return Handle(Geom_OffsetCurve)::DownCast(myCurve);
974 }