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