ad985722642619d006b798969e2d0fad72ea4403
[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, aFlatKnots, aBezier->Poles(), aBezier->Weights());
562   }
563   else if (myTypeCurve == GeomAbs_BSplineCurve)
564   {
565     // Create cache for B-spline
566     if (myCurveCache.IsNull())
567       myCurveCache = new BSplCLib_Cache (myBSplineCurve->Degree(), myBSplineCurve->IsPeriodic(),
568         myBSplineCurve->KnotSequence(), myBSplineCurve->Poles(), myBSplineCurve->Weights());
569     myCurveCache->BuildCache (theParameter, myBSplineCurve->KnotSequence(),
570                               myBSplineCurve->Poles(), myBSplineCurve->Weights());
571   }
572 }
573
574 //=======================================================================
575 //function : IsBoundary
576 //purpose  : 
577 //=======================================================================
578 Standard_Boolean Geom2dAdaptor_Curve::IsBoundary(const Standard_Real theU,
579                                                  Standard_Integer& theSpanStart,
580                                                  Standard_Integer& theSpanFinish) const
581 {
582   if (!myBSplineCurve.IsNull() && (theU == myFirst || theU == myLast))
583   {
584     if (theU == myFirst)
585     {
586       myBSplineCurve->LocateU(myFirst, PosTol, theSpanStart, theSpanFinish);
587       if (theSpanStart < 1)
588         theSpanStart = 1;
589       if (theSpanStart >= theSpanFinish)
590         theSpanFinish = theSpanStart + 1;
591     }
592     else if (theU == myLast)
593     {
594       myBSplineCurve->LocateU(myLast, PosTol, theSpanStart, theSpanFinish);
595       if (theSpanFinish > myBSplineCurve->NbKnots())
596         theSpanFinish = myBSplineCurve->NbKnots();
597       if (theSpanStart >= theSpanFinish)
598         theSpanStart = theSpanFinish - 1;
599     }
600     return Standard_True;
601   }
602   return Standard_False;
603 }
604
605 //=======================================================================
606 //function : Value
607 //purpose  : 
608 //=======================================================================
609
610 gp_Pnt2d Geom2dAdaptor_Curve::Value(const Standard_Real U) const 
611 {
612   gp_Pnt2d aRes;
613   D0(U, aRes);
614   return aRes;
615 }
616
617 //=======================================================================
618 //function : D0
619 //purpose  : 
620 //=======================================================================
621
622 void Geom2dAdaptor_Curve::D0(const Standard_Real U, gp_Pnt2d& P) const
623 {
624   switch (myTypeCurve)
625   {
626   case GeomAbs_BezierCurve:
627   case GeomAbs_BSplineCurve:
628   {
629     Standard_Integer aStart = 0, aFinish = 0;
630     if (IsBoundary(U, aStart, aFinish))
631     {
632       myBSplineCurve->LocalD0(U, aStart, aFinish, P);
633     }
634     else
635     {
636       // use cached data
637       if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U))
638         RebuildCache(U);
639       myCurveCache->D0(U, P);
640     }
641     break;
642   }
643
644   case GeomAbs_OffsetCurve:
645     myNestedEvaluator->D0(U, P);
646     break;
647
648   default:
649     myCurve->D0(U, P);
650   }
651 }
652
653 //=======================================================================
654 //function : D1
655 //purpose  : 
656 //=======================================================================
657
658 void Geom2dAdaptor_Curve::D1(const Standard_Real U, 
659                              gp_Pnt2d& P, gp_Vec2d& V) const 
660 {
661   switch (myTypeCurve)
662   {
663   case GeomAbs_BezierCurve:
664   case GeomAbs_BSplineCurve:
665   {
666     Standard_Integer aStart = 0, aFinish = 0;
667     if (IsBoundary(U, aStart, aFinish))
668     {
669       myBSplineCurve->LocalD1(U, aStart, aFinish, P, V);
670     }
671     else
672     {
673       // use cached data
674       if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U))
675         RebuildCache(U);
676       myCurveCache->D1(U, P, V);
677     }
678     break;
679   }
680
681   case GeomAbs_OffsetCurve:
682     myNestedEvaluator->D1(U, P, V);
683     break;
684
685   default:
686     myCurve->D1(U, P, V);
687   }
688 }
689
690 //=======================================================================
691 //function : D2
692 //purpose  : 
693 //=======================================================================
694
695 void Geom2dAdaptor_Curve::D2(const Standard_Real U, 
696                              gp_Pnt2d& P, gp_Vec2d& V1, gp_Vec2d& V2) const 
697 {
698   switch (myTypeCurve)
699   {
700   case GeomAbs_BezierCurve:
701   case GeomAbs_BSplineCurve:
702   {
703     Standard_Integer aStart = 0, aFinish = 0;
704     if (IsBoundary(U, aStart, aFinish))
705     {
706       myBSplineCurve->LocalD2(U, aStart, aFinish, P, V1, V2);
707     }
708     else
709     {
710       // use cached data
711       if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U))
712         RebuildCache(U);
713       myCurveCache->D2(U, P, V1, V2);
714     }
715     break;
716   }
717
718   case GeomAbs_OffsetCurve:
719     myNestedEvaluator->D2(U, P, V1, V2);
720     break;
721
722   default:
723     myCurve->D2(U, P, V1, V2);
724   }
725 }
726
727 //=======================================================================
728 //function : D3
729 //purpose  : 
730 //=======================================================================
731
732 void Geom2dAdaptor_Curve::D3(const Standard_Real U, 
733                              gp_Pnt2d& P,  gp_Vec2d& V1, 
734                              gp_Vec2d& V2, gp_Vec2d& V3) const 
735 {
736   switch (myTypeCurve)
737   {
738   case GeomAbs_BezierCurve:
739   case GeomAbs_BSplineCurve:
740   {
741     Standard_Integer aStart = 0, aFinish = 0;
742     if (IsBoundary(U, aStart, aFinish))
743     {
744       myBSplineCurve->LocalD3(U, aStart, aFinish, P, V1, V2, V3);
745     }
746     else
747     {
748       // use cached data
749       if (myCurveCache.IsNull() || !myCurveCache->IsCacheValid(U))
750         RebuildCache(U);
751       myCurveCache->D3(U, P, V1, V2, V3);
752     }
753     break;
754   }
755
756   case GeomAbs_OffsetCurve:
757     myNestedEvaluator->D3(U, P, V1, V2, V3);
758     break;
759
760   default:
761     myCurve->D3(U, P, V1, V2, V3);
762   }
763 }
764
765 //=======================================================================
766 //function : DN
767 //purpose  : 
768 //=======================================================================
769
770 gp_Vec2d Geom2dAdaptor_Curve::DN(const Standard_Real U, 
771                                  const Standard_Integer N) const 
772 {
773   switch (myTypeCurve)
774   {
775   case GeomAbs_BezierCurve:
776   case GeomAbs_BSplineCurve:
777   {
778     Standard_Integer aStart = 0, aFinish = 0;
779     if (IsBoundary(U, aStart, aFinish))
780     {
781       myBSplineCurve->LocalDN(U, aStart, aFinish, N);
782     }
783     else
784       return myCurve->DN(U, N);
785     break;
786   }
787
788   case GeomAbs_OffsetCurve:
789     return myNestedEvaluator->DN(U, N);
790     break;
791
792   default: // to eliminate gcc warning
793     break;
794   }
795   return myCurve->DN(U, N);
796 }
797
798 //=======================================================================
799 //function : Resolution
800 //purpose  : 
801 //=======================================================================
802
803 Standard_Real Geom2dAdaptor_Curve::Resolution(const Standard_Real Ruv) const {
804   switch ( myTypeCurve) {
805   case GeomAbs_Line :
806     return Ruv;
807   case GeomAbs_Circle: {
808     Standard_Real R = Handle(Geom2d_Circle)::DownCast (myCurve)->Circ2d().Radius();
809     if ( R > Ruv/2.)
810       return 2*ASin(Ruv/(2*R));
811     else
812       return 2*M_PI;
813   }
814   case GeomAbs_Ellipse: {
815     return Ruv / Handle(Geom2d_Ellipse)::DownCast (myCurve)->MajorRadius();
816   }
817   case GeomAbs_BezierCurve: {
818     Standard_Real res;
819     Handle(Geom2d_BezierCurve)::DownCast (myCurve)->Resolution(Ruv,res);
820     return res;
821   }
822   case GeomAbs_BSplineCurve: {
823     Standard_Real res;
824     Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->Resolution(Ruv,res);
825     return res;
826   }
827   default:
828     return Precision::Parametric(Ruv);
829   }  
830 }
831
832
833 //    --
834 //    --     The following methods must  be called when GetType returned
835 //    --     the corresponding type.
836 //    --     
837
838 //=======================================================================
839 //function : Line
840 //purpose  : 
841 //=======================================================================
842
843 gp_Lin2d Geom2dAdaptor_Curve::Line() const 
844 {
845   Standard_NoSuchObject_Raise_if (myTypeCurve != GeomAbs_Line,
846                                   "Geom2dAdaptor_Curve::Line() - curve is not a Line");
847   return Handle(Geom2d_Line)::DownCast (myCurve)->Lin2d();
848 }
849
850 //=======================================================================
851 //function : Circle
852 //purpose  : 
853 //=======================================================================
854
855 gp_Circ2d  Geom2dAdaptor_Curve::Circle() const 
856 {
857   Standard_NoSuchObject_Raise_if (myTypeCurve != GeomAbs_Circle,
858                                   "Geom2dAdaptor_Curve::Circle() - curve is not a Circle");
859   return Handle(Geom2d_Circle)::DownCast (myCurve)->Circ2d();
860 }
861
862 //=======================================================================
863 //function : Ellipse
864 //purpose  : 
865 //=======================================================================
866
867 gp_Elips2d Geom2dAdaptor_Curve::Ellipse() const 
868 {
869   Standard_NoSuchObject_Raise_if (myTypeCurve != GeomAbs_Ellipse,
870                                   "Geom2dAdaptor_Curve::Ellipse() - curve is not an Ellipse");
871   return Handle(Geom2d_Ellipse)::DownCast (myCurve)->Elips2d();
872 }
873
874 //=======================================================================
875 //function : Hyperbola
876 //purpose  : 
877 //=======================================================================
878
879 gp_Hypr2d Geom2dAdaptor_Curve::Hyperbola() const 
880 {
881   Standard_NoSuchObject_Raise_if (myTypeCurve != GeomAbs_Hyperbola,
882                                   "Geom2dAdaptor_Curve::Hyperbola() - curve is not a Hyperbola");
883   return Handle(Geom2d_Hyperbola)::DownCast (myCurve)->Hypr2d();
884 }
885
886 //=======================================================================
887 //function : Parabola
888 //purpose  : 
889 //=======================================================================
890
891 gp_Parab2d Geom2dAdaptor_Curve::Parabola() const 
892 {
893   Standard_NoSuchObject_Raise_if (myTypeCurve != GeomAbs_Parabola,
894                                   "Geom2dAdaptor_Curve::Parabola() - curve is not a Parabola");
895   return Handle(Geom2d_Parabola)::DownCast (myCurve)->Parab2d();
896 }
897
898 //=======================================================================
899 //function : Degree
900 //purpose  : 
901 //=======================================================================
902
903 Standard_Integer Geom2dAdaptor_Curve::Degree() const
904 {
905   if (myTypeCurve == GeomAbs_BezierCurve)
906     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->Degree();
907   else if (myTypeCurve == GeomAbs_BSplineCurve)
908     return myBSplineCurve->Degree();
909   else
910     throw Standard_NoSuchObject();
911 }
912
913 //=======================================================================
914 //function : IsRational
915 //purpose  : 
916 //=======================================================================
917
918 Standard_Boolean Geom2dAdaptor_Curve::IsRational() const {
919   switch( myTypeCurve) {
920   case GeomAbs_BSplineCurve:
921     return myBSplineCurve->IsRational();
922   case GeomAbs_BezierCurve:
923     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->IsRational();
924   default:
925     return Standard_False;
926   }
927 }
928
929 //=======================================================================
930 //function : NbPoles
931 //purpose  : 
932 //=======================================================================
933
934 Standard_Integer Geom2dAdaptor_Curve::NbPoles() const
935 {
936   if (myTypeCurve == GeomAbs_BezierCurve)
937     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->NbPoles();
938   else if (myTypeCurve == GeomAbs_BSplineCurve)
939     return myBSplineCurve->NbPoles();
940   else
941     throw Standard_NoSuchObject();
942 }
943
944 //=======================================================================
945 //function : NbKnots
946 //purpose  : 
947 //=======================================================================
948
949 Standard_Integer Geom2dAdaptor_Curve::NbKnots() const
950 {
951   if ( myTypeCurve != GeomAbs_BSplineCurve)
952     throw Standard_NoSuchObject("Geom2dAdaptor_Curve::NbKnots");
953   return myBSplineCurve->NbKnots();
954 }
955
956 //=======================================================================
957 //function : Bezier
958 //purpose  : 
959 //=======================================================================
960
961 Handle(Geom2d_BezierCurve) Geom2dAdaptor_Curve::Bezier() const 
962 {
963   return Handle(Geom2d_BezierCurve)::DownCast (myCurve);
964 }
965
966 //=======================================================================
967 //function : BSpline
968 //purpose  : 
969 //=======================================================================
970
971 Handle(Geom2d_BSplineCurve) Geom2dAdaptor_Curve::BSpline() const 
972 {
973   return myBSplineCurve;
974 }
975
976 static Standard_Integer nbPoints(const Handle(Geom2d_Curve)& theCurve) 
977 {
978  
979   Standard_Integer nbs = 20;
980   
981   if(theCurve->IsKind(STANDARD_TYPE( Geom2d_Line)) )
982     nbs = 2;
983   else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BezierCurve))) 
984   {
985     nbs = 3 + Handle(Geom2d_BezierCurve)::DownCast (theCurve)->NbPoles();
986   }
987   else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BSplineCurve))) { 
988     nbs =  Handle(Geom2d_BSplineCurve)::DownCast (theCurve)->NbKnots();
989     nbs*= Handle(Geom2d_BSplineCurve)::DownCast (theCurve)->Degree();
990     if(nbs < 2.0) nbs=2;
991   }
992   else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
993   {
994     Handle(Geom2d_Curve) aCurve = Handle(Geom2d_OffsetCurve)::DownCast (theCurve)->BasisCurve();
995     return Max(nbs, nbPoints(aCurve));
996   }
997
998   else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
999   {
1000     Handle(Geom2d_Curve) aCurve = Handle(Geom2d_TrimmedCurve)::DownCast (theCurve)->BasisCurve();
1001     return Max(nbs, nbPoints(aCurve));
1002   }
1003   if(nbs>300)
1004     nbs = 300;
1005   return nbs;
1006
1007 }
1008
1009 Standard_Integer Geom2dAdaptor_Curve::NbSamples() const
1010 {
1011   return  nbPoints(myCurve);
1012 }