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