0026949: Geom(2d)Adaptor_Curve/Surface should not do down casts in evaluation
[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
184   if ( myCurve != C) {
185     myCurve = C;
186     myCurveCache.Nullify();
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       // Create cache for Bezier
213       Handle(Geom2d_BezierCurve) aBezier = Handle(Geom2d_BezierCurve)::DownCast(myCurve);
214       Standard_Integer aDeg = aBezier->Degree();
215       TColStd_Array1OfReal aFlatKnots(BSplCLib::FlatBezierKnots(aDeg), 1, 2 * (aDeg + 1));
216       myCurveCache = new BSplCLib_Cache(aDeg, aBezier->IsPeriodic(), aFlatKnots,
217           aBezier->Poles(), aBezier->Weights());
218     }
219     else if ( TheType == STANDARD_TYPE(Geom2d_BSplineCurve)) {
220       myTypeCurve = GeomAbs_BSplineCurve;
221       // Create cache for B-spline
222       Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
223       myBSplineCurve = aBspl;
224       myCurveCache = new BSplCLib_Cache(aBspl->Degree(), aBspl->IsPeriodic(),
225           aBspl->KnotSequence(), aBspl->Poles(), aBspl->Weights());
226     }
227     else if ( TheType == STANDARD_TYPE(Geom2d_OffsetCurve))
228     {
229       myTypeCurve = GeomAbs_OffsetCurve;
230       Handle(Geom2d_OffsetCurve) anOffsetCurve = Handle(Geom2d_OffsetCurve)::DownCast(myCurve);
231       // Create nested adaptor for base curve
232       Handle(Geom2d_Curve) aBaseCurve = anOffsetCurve->BasisCurve();
233       Handle(Geom2dAdaptor_HCurve) aBaseAdaptor = new Geom2dAdaptor_HCurve(aBaseCurve);
234       myNestedEvaluator = new Geom2dEvaluator_OffsetCurve(aBaseAdaptor, anOffsetCurve->Offset());
235     }
236     else {
237       myTypeCurve = GeomAbs_OtherCurve;
238     }
239   }
240 }
241
242 //    --
243 //    --     Global methods - Apply to the whole curve.
244 //    --     
245
246 //=======================================================================
247 //function : Continuity
248 //purpose  : 
249 //=======================================================================
250
251 GeomAbs_Shape Geom2dAdaptor_Curve::Continuity() const 
252 {
253   if (myTypeCurve == GeomAbs_BSplineCurve) {
254     return LocalContinuity(myFirst, myLast);
255   }
256   else if (myTypeCurve == GeomAbs_OffsetCurve){
257     GeomAbs_Shape S = 
258       Handle(Geom2d_OffsetCurve)::DownCast (myCurve)->GetBasisCurveContinuity(); 
259     switch(S){
260     case GeomAbs_CN: return GeomAbs_CN;
261     case GeomAbs_C3: return GeomAbs_C2;
262     case GeomAbs_C2: return GeomAbs_C1;
263     case GeomAbs_C1: return GeomAbs_C0;  
264     case GeomAbs_G1: return GeomAbs_G1;
265     case GeomAbs_G2: return GeomAbs_G2;
266
267     default:
268       Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::Continuity");
269     }
270   }
271
272   else if (myTypeCurve == GeomAbs_OtherCurve) {
273     Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::Continuity");
274   }
275   else {
276     return GeomAbs_CN;
277   }
278
279   // portage WNT
280   return GeomAbs_CN;
281 }
282
283 //=======================================================================
284 //function : NbIntervals
285 //purpose  : 
286 //=======================================================================
287
288 Standard_Integer Geom2dAdaptor_Curve::NbIntervals(const GeomAbs_Shape S) const
289 {
290   Standard_Integer myNbIntervals = 1;
291   Standard_Integer NbSplit;
292   if (myTypeCurve == GeomAbs_BSplineCurve) {
293     Standard_Integer FirstIndex = myBSplineCurve->FirstUKnotIndex();
294     Standard_Integer LastIndex  = myBSplineCurve->LastUKnotIndex();
295     TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
296     if ( S > Continuity()) {
297       Standard_Integer Cont;
298       switch ( S) {
299       case GeomAbs_G1:
300       case GeomAbs_G2:
301         Standard_DomainError::Raise("Geom2dAdaptor_Curve::NbIntervals");
302         break;
303       case GeomAbs_C0:
304         myNbIntervals = 1;
305         break;
306       case GeomAbs_C1:
307       case GeomAbs_C2:
308       case GeomAbs_C3: 
309       case GeomAbs_CN: 
310         {
311           if      ( S == GeomAbs_C1) Cont = 1;
312           else if ( S == GeomAbs_C2) Cont = 2;
313           else if ( S == GeomAbs_C3) Cont = 3;
314           else                       Cont = myBSplineCurve->Degree();
315           Standard_Integer Degree = myBSplineCurve->Degree();
316           Standard_Integer NbKnots = myBSplineCurve->NbKnots();
317           TColStd_Array1OfInteger Mults (1, NbKnots);
318           myBSplineCurve->Multiplicities (Mults);
319           NbSplit = 1;
320           Standard_Integer Index   = FirstIndex;
321           Inter (NbSplit) = Index;
322           Index++;
323           NbSplit++;
324           while (Index < LastIndex) 
325             {
326               if (Degree - Mults (Index) < Cont) 
327                 {
328                   Inter (NbSplit) = Index;
329                   NbSplit++;
330                 }
331               Index++;
332             }
333           Inter (NbSplit) = Index;
334
335           Standard_Integer NbInt = NbSplit-1;
336           
337           Standard_Integer Nb = myBSplineCurve->NbKnots();
338           Standard_Integer Index1 = 0;
339           Standard_Integer Index2 = 0;
340           Standard_Real newFirst, newLast;
341           TColStd_Array1OfReal    TK(1,Nb);
342           TColStd_Array1OfInteger TM(1,Nb);
343           myBSplineCurve->Knots(TK);
344           myBSplineCurve->Multiplicities(TM);
345           BSplCLib::LocateParameter(myBSplineCurve->Degree(),TK,TM,myFirst,
346                                     myBSplineCurve->IsPeriodic(),
347                                     1,Nb,Index1,newFirst);
348           BSplCLib::LocateParameter(myBSplineCurve->Degree(),TK,TM,myLast,
349                                     myBSplineCurve->IsPeriodic(),
350                                     1,Nb,Index2,newLast);
351
352           // On decale eventuellement les indices  
353           // On utilise une "petite" tolerance, la resolution ne doit 
354           // servir que pour les tres longue courbes....(PRO9248)
355           Standard_Real Eps = Min(Resolution(Precision::Confusion()),
356                                   Precision::PConfusion()); 
357           if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
358           if ( newLast-TK(Index2)> Eps) Index2++;
359           
360           myNbIntervals = 1;
361           for ( Standard_Integer i=1; i<=NbInt; i++)
362             if (Inter(i)>Index1 && Inter(i)<Index2) myNbIntervals++;
363         }
364         break;
365       }
366     }
367   }
368   else if (myTypeCurve == GeomAbs_OffsetCurve){
369     GeomAbs_Shape BaseS=GeomAbs_C0;
370     switch(S){
371     case GeomAbs_G1:
372     case GeomAbs_G2:
373       Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
374       break;
375     case GeomAbs_C0: BaseS = GeomAbs_C1; break;
376     case GeomAbs_C1: BaseS = GeomAbs_C2; break;
377     case GeomAbs_C2: BaseS = GeomAbs_C3; break;
378     default: BaseS = GeomAbs_CN;
379     }
380     Geom2dAdaptor_Curve anAdaptor( Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->BasisCurve() );
381     myNbIntervals = anAdaptor.NbIntervals(BaseS);
382   }
383
384   return myNbIntervals;
385 }
386
387 //=======================================================================
388 //function : Intervals
389 //purpose  : 
390 //=======================================================================
391
392 void Geom2dAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
393                                     const GeomAbs_Shape S   ) const 
394 {
395   Standard_Integer myNbIntervals = 1;
396   Standard_Integer NbSplit;
397   if (myTypeCurve == GeomAbs_BSplineCurve) {
398     Standard_Integer FirstIndex = myBSplineCurve->FirstUKnotIndex();
399     Standard_Integer LastIndex  = myBSplineCurve->LastUKnotIndex();
400     TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
401     if ( S > Continuity()) {
402       Standard_Integer Cont;
403       switch ( S) {
404       case GeomAbs_G1:
405       case GeomAbs_G2:
406         Standard_DomainError::Raise("Geom2dAdaptor_Curve::NbIntervals");
407         break;
408       case GeomAbs_C0:
409         myNbIntervals = 1;
410         break;
411       case GeomAbs_C1:
412       case GeomAbs_C2:
413       case GeomAbs_C3: 
414       case GeomAbs_CN: 
415         {
416           if      ( S == GeomAbs_C1) Cont = 1;
417           else if ( S == GeomAbs_C2) Cont = 2;
418           else if ( S == GeomAbs_C3) Cont = 3;
419           else                       Cont = myBSplineCurve->Degree();
420           Standard_Integer Degree = myBSplineCurve->Degree();
421           Standard_Integer NbKnots = myBSplineCurve->NbKnots();
422           TColStd_Array1OfInteger Mults (1, NbKnots);
423           myBSplineCurve->Multiplicities (Mults);
424           NbSplit = 1;
425           Standard_Integer Index   = FirstIndex;
426           Inter (NbSplit) = Index;
427           Index++;
428           NbSplit++;
429           while (Index < LastIndex) 
430             {
431               if (Degree - Mults (Index) < Cont) 
432                 {
433                   Inter (NbSplit) = Index;
434                   NbSplit++;
435                 }
436               Index++;
437             }
438           Inter (NbSplit) = Index;
439           Standard_Integer NbInt = NbSplit-1;
440           
441           Standard_Integer Nb = myBSplineCurve->NbKnots();
442           Standard_Integer Index1 = 0;
443           Standard_Integer Index2 = 0;
444           Standard_Real newFirst, newLast;
445           TColStd_Array1OfReal    TK(1,Nb);
446           TColStd_Array1OfInteger TM(1,Nb);
447           myBSplineCurve->Knots(TK);
448           myBSplineCurve->Multiplicities(TM);
449           BSplCLib::LocateParameter(myBSplineCurve->Degree(),TK,TM,myFirst,
450                                     myBSplineCurve->IsPeriodic(),
451                                     1,Nb,Index1,newFirst);
452           BSplCLib::LocateParameter(myBSplineCurve->Degree(),TK,TM,myLast,
453                                     myBSplineCurve->IsPeriodic(),
454                                     1,Nb,Index2,newLast);
455
456
457           // On decale eventuellement les indices  
458           // On utilise une "petite" tolerance, la resolution ne doit 
459           // servir que pour les tres longue courbes....(PRO9248)
460           Standard_Real Eps = Min(Resolution(Precision::Confusion()),
461                                   Precision::PConfusion()); 
462           if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
463           if ( newLast-TK(Index2)> Eps) Index2++;
464           
465           Inter( 1) = Index1;
466           myNbIntervals = 1;
467           for ( Standard_Integer i=1; i<=NbInt; i++) {
468             if (Inter(i) > Index1 && Inter(i)<Index2 ) {
469               myNbIntervals++;
470               Inter(myNbIntervals) = Inter(i);
471             }
472           }
473           Inter(myNbIntervals+1) = Index2;
474           
475           Standard_Integer ii = T.Lower() - 1;
476           for (Standard_Integer I=1;I<=myNbIntervals+1;I++) {
477             T(ii + I) = TK(Inter(I));
478           }
479         }
480         break;
481       }
482     }
483   }
484   else if (myTypeCurve == GeomAbs_OffsetCurve){
485     GeomAbs_Shape BaseS=GeomAbs_C0;
486     switch(S){
487     case GeomAbs_G1:
488     case GeomAbs_G2:
489       Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
490       break;
491     case GeomAbs_C0: BaseS = GeomAbs_C1; break;
492     case GeomAbs_C1: BaseS = GeomAbs_C2; break;
493     case GeomAbs_C2: BaseS = GeomAbs_C3; break;
494     default: BaseS = GeomAbs_CN;
495     }
496
497     Geom2dAdaptor_Curve anAdaptor( Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->BasisCurve() );
498     myNbIntervals = anAdaptor.NbIntervals(BaseS);
499     anAdaptor.Intervals(T, BaseS);
500   }
501
502   T( T.Lower() ) = myFirst;
503   T( T.Lower() + myNbIntervals ) = myLast;
504 }
505
506 //=======================================================================
507 //function : Trim
508 //purpose  : 
509 //=======================================================================
510
511 Handle(Adaptor2d_HCurve2d) Geom2dAdaptor_Curve::Trim
512 (const Standard_Real First,
513  const Standard_Real Last,
514 // const Standard_Real Tol) const 
515  const Standard_Real ) const 
516 {
517   Handle(Geom2dAdaptor_HCurve) HE = new Geom2dAdaptor_HCurve(myCurve,First,Last);
518   return HE;
519 }
520
521
522 //=======================================================================
523 //function : IsClosed
524 //purpose  : 
525 //=======================================================================
526
527 Standard_Boolean Geom2dAdaptor_Curve::IsClosed() const 
528 {
529   if (!Precision::IsPositiveInfinite(myLast) &&
530       !Precision::IsNegativeInfinite(myFirst)) {
531     gp_Pnt2d Pd = Value(myFirst);
532     gp_Pnt2d Pf = Value(myLast);
533     return ( Pd.Distance(Pf) <= Precision::Confusion());
534   }
535   else
536     return Standard_False;
537 }
538
539 //=======================================================================
540 //function : IsPeriodic
541 //purpose  : 
542 //=======================================================================
543
544 Standard_Boolean Geom2dAdaptor_Curve::IsPeriodic() const 
545 {
546   if (myCurve->IsPeriodic())
547     return IsClosed();
548   else
549     return Standard_False;
550 }
551
552 //=======================================================================
553 //function : Period
554 //purpose  : 
555 //=======================================================================
556
557 Standard_Real Geom2dAdaptor_Curve::Period() const 
558 {
559   return myCurve->LastParameter() - myCurve->FirstParameter();
560 }
561
562 //=======================================================================
563 //function : RebuildCache
564 //purpose  : 
565 //=======================================================================
566 void Geom2dAdaptor_Curve::RebuildCache(const Standard_Real theParameter) const
567 {
568   if (myTypeCurve == GeomAbs_BezierCurve)
569   {
570     Handle(Geom2d_BezierCurve) aBezier = Handle(Geom2d_BezierCurve)::DownCast(myCurve);
571     Standard_Integer aDeg = aBezier->Degree();
572     TColStd_Array1OfReal aFlatKnots(BSplCLib::FlatBezierKnots(aDeg), 1, 2 * (aDeg + 1));
573     myCurveCache->BuildCache(theParameter, aDeg, aBezier->IsPeriodic(), aFlatKnots,
574       aBezier->Poles(), aBezier->Weights());
575   }
576   else if (myTypeCurve == GeomAbs_BSplineCurve)
577   {
578     myCurveCache->BuildCache(theParameter, myBSplineCurve->Degree(),
579       myBSplineCurve->IsPeriodic(), myBSplineCurve->KnotSequence(),
580       myBSplineCurve->Poles(), myBSplineCurve->Weights());
581   }
582 }
583
584 //=======================================================================
585 //function : IsBoundary
586 //purpose  : 
587 //=======================================================================
588 Standard_Boolean Geom2dAdaptor_Curve::IsBoundary(const Standard_Real theU,
589                                                  Standard_Integer& theSpanStart,
590                                                  Standard_Integer& theSpanFinish) const
591 {
592   if (!myBSplineCurve.IsNull() && (theU == myFirst || theU == myLast))
593   {
594     if (theU == myFirst)
595     {
596       myBSplineCurve->LocateU(myFirst, PosTol, theSpanStart, theSpanFinish);
597       if (theSpanStart < 1)
598         theSpanStart = 1;
599       if (theSpanStart >= theSpanFinish)
600         theSpanFinish = theSpanStart + 1;
601     }
602     else if (theU == myLast)
603     {
604       myBSplineCurve->LocateU(myLast, PosTol, theSpanStart, theSpanFinish);
605       if (theSpanFinish > myBSplineCurve->NbKnots())
606         theSpanFinish = myBSplineCurve->NbKnots();
607       if (theSpanStart >= theSpanFinish)
608         theSpanStart = theSpanFinish - 1;
609     }
610     return Standard_True;
611   }
612   return Standard_False;
613 }
614
615 //=======================================================================
616 //function : Value
617 //purpose  : 
618 //=======================================================================
619
620 gp_Pnt2d Geom2dAdaptor_Curve::Value(const Standard_Real U) const 
621 {
622   gp_Pnt2d aRes;
623   D0(U, aRes);
624   return aRes;
625 }
626
627 //=======================================================================
628 //function : D0
629 //purpose  : 
630 //=======================================================================
631
632 void Geom2dAdaptor_Curve::D0(const Standard_Real U, gp_Pnt2d& P) const
633 {
634   switch (myTypeCurve)
635   {
636   case GeomAbs_BezierCurve:
637   case GeomAbs_BSplineCurve:
638   {
639     Standard_Integer aStart = 0, aFinish = 0;
640     if (IsBoundary(U, aStart, aFinish))
641     {
642       myBSplineCurve->LocalD0(U, aStart, aFinish, P);
643     }
644     else if (!myCurveCache.IsNull()) // use cached data
645     {
646       if (!myCurveCache->IsCacheValid(U))
647         RebuildCache(U);
648       myCurveCache->D0(U, P);
649     }
650     else
651       myCurve->D0(U, P);
652     break;
653   }
654
655   case GeomAbs_OffsetCurve:
656     myNestedEvaluator->D0(U, P);
657     break;
658
659   default:
660     myCurve->D0(U, P);
661   }
662 }
663
664 //=======================================================================
665 //function : D1
666 //purpose  : 
667 //=======================================================================
668
669 void Geom2dAdaptor_Curve::D1(const Standard_Real U, 
670                              gp_Pnt2d& P, gp_Vec2d& V) const 
671 {
672   switch (myTypeCurve)
673   {
674   case GeomAbs_BezierCurve:
675   case GeomAbs_BSplineCurve:
676   {
677     Standard_Integer aStart = 0, aFinish = 0;
678     if (IsBoundary(U, aStart, aFinish))
679     {
680       myBSplineCurve->LocalD1(U, aStart, aFinish, P, V);
681     }
682     else if (!myCurveCache.IsNull()) // use cached data
683     {
684       if (!myCurveCache->IsCacheValid(U))
685         RebuildCache(U);
686       myCurveCache->D1(U, P, V);
687     }
688     else
689       myCurve->D1(U, P, V);
690     break;
691   }
692
693   case GeomAbs_OffsetCurve:
694     myNestedEvaluator->D1(U, P, V);
695     break;
696
697   default:
698     myCurve->D1(U, P, V);
699   }
700 }
701
702 //=======================================================================
703 //function : D2
704 //purpose  : 
705 //=======================================================================
706
707 void Geom2dAdaptor_Curve::D2(const Standard_Real U, 
708                              gp_Pnt2d& P, gp_Vec2d& V1, gp_Vec2d& V2) const 
709 {
710   switch (myTypeCurve)
711   {
712   case GeomAbs_BezierCurve:
713   case GeomAbs_BSplineCurve:
714   {
715     Standard_Integer aStart = 0, aFinish = 0;
716     if (IsBoundary(U, aStart, aFinish))
717     {
718       myBSplineCurve->LocalD2(U, aStart, aFinish, P, V1, V2);
719     }
720     else if (!myCurveCache.IsNull()) // use cached data
721     {
722       if (!myCurveCache->IsCacheValid(U))
723         RebuildCache(U);
724       myCurveCache->D2(U, P, V1, V2);
725     }
726     else
727       myCurve->D2(U, P, V1, V2);
728     break;
729   }
730
731   case GeomAbs_OffsetCurve:
732     myNestedEvaluator->D2(U, P, V1, V2);
733     break;
734
735   default:
736     myCurve->D2(U, P, V1, V2);
737   }
738 }
739
740 //=======================================================================
741 //function : D3
742 //purpose  : 
743 //=======================================================================
744
745 void Geom2dAdaptor_Curve::D3(const Standard_Real U, 
746                              gp_Pnt2d& P,  gp_Vec2d& V1, 
747                              gp_Vec2d& V2, gp_Vec2d& V3) const 
748 {
749   switch (myTypeCurve)
750   {
751   case GeomAbs_BezierCurve:
752   case GeomAbs_BSplineCurve:
753   {
754     Standard_Integer aStart = 0, aFinish = 0;
755     if (IsBoundary(U, aStart, aFinish))
756     {
757       myBSplineCurve->LocalD3(U, aStart, aFinish, P, V1, V2, V3);
758     }
759     else if (!myCurveCache.IsNull()) // use cached data
760     {
761       if (!myCurveCache->IsCacheValid(U))
762         RebuildCache(U);
763       myCurveCache->D3(U, P, V1, V2, V3);
764     }
765     else
766       myCurve->D3(U, P, V1, V2, V3);
767     break;
768   }
769
770   case GeomAbs_OffsetCurve:
771     myNestedEvaluator->D3(U, P, V1, V2, V3);
772     break;
773
774   default:
775     myCurve->D3(U, P, V1, V2, V3);
776   }
777 }
778
779 //=======================================================================
780 //function : DN
781 //purpose  : 
782 //=======================================================================
783
784 gp_Vec2d Geom2dAdaptor_Curve::DN(const Standard_Real U, 
785                                  const Standard_Integer N) const 
786 {
787   switch (myTypeCurve)
788   {
789   case GeomAbs_BezierCurve:
790   case GeomAbs_BSplineCurve:
791   {
792     Standard_Integer aStart = 0, aFinish = 0;
793     if (IsBoundary(U, aStart, aFinish))
794     {
795       myBSplineCurve->LocalDN(U, aStart, aFinish, N);
796     }
797     else
798       return myCurve->DN(U, N);
799     break;
800   }
801
802   case GeomAbs_OffsetCurve:
803     return myNestedEvaluator->DN(U, N);
804     break;
805
806   default: // to eliminate gcc warning
807     break;
808   }
809   return myCurve->DN(U, N);
810 }
811
812 //=======================================================================
813 //function : Resolution
814 //purpose  : 
815 //=======================================================================
816
817 Standard_Real Geom2dAdaptor_Curve::Resolution(const Standard_Real Ruv) const {
818   switch ( myTypeCurve) {
819   case GeomAbs_Line :
820     return Ruv;
821   case GeomAbs_Circle: {
822     Standard_Real R = Handle(Geom2d_Circle)::DownCast (myCurve)->Circ2d().Radius();
823     if ( R > Ruv/2.)
824       return 2*ASin(Ruv/(2*R));
825     else
826       return 2*M_PI;
827   }
828   case GeomAbs_Ellipse: {
829     return Ruv / Handle(Geom2d_Ellipse)::DownCast (myCurve)->MajorRadius();
830   }
831   case GeomAbs_BezierCurve: {
832     Standard_Real res;
833     Handle(Geom2d_BezierCurve)::DownCast (myCurve)->Resolution(Ruv,res);
834     return res;
835   }
836   case GeomAbs_BSplineCurve: {
837     Standard_Real res;
838     Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->Resolution(Ruv,res);
839     return res;
840   }
841   default:
842     return Precision::Parametric(Ruv);
843   }  
844 }
845
846
847 //    --
848 //    --     The following methods must  be called when GetType returned
849 //    --     the corresponding type.
850 //    --     
851
852 //=======================================================================
853 //function : Line
854 //purpose  : 
855 //=======================================================================
856
857 gp_Lin2d Geom2dAdaptor_Curve::Line() const 
858 {
859   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Line, "");
860   return Handle(Geom2d_Line)::DownCast (myCurve)->Lin2d();
861 }
862
863 //=======================================================================
864 //function : Circle
865 //purpose  : 
866 //=======================================================================
867
868 gp_Circ2d  Geom2dAdaptor_Curve::Circle() const 
869 {
870   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Circle, "");
871   return Handle(Geom2d_Circle)::DownCast (myCurve)->Circ2d();
872 }
873
874 //=======================================================================
875 //function : Ellipse
876 //purpose  : 
877 //=======================================================================
878
879 gp_Elips2d Geom2dAdaptor_Curve::Ellipse() const 
880 {
881   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Ellipse, "");
882   return Handle(Geom2d_Ellipse)::DownCast (myCurve)->Elips2d();
883 }
884
885 //=======================================================================
886 //function : Hyperbola
887 //purpose  : 
888 //=======================================================================
889
890 gp_Hypr2d Geom2dAdaptor_Curve::Hyperbola() const 
891 {
892   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Hyperbola, "");
893   return Handle(Geom2d_Hyperbola)::DownCast (myCurve)->Hypr2d();
894 }
895
896 //=======================================================================
897 //function : Parabola
898 //purpose  : 
899 //=======================================================================
900
901 gp_Parab2d Geom2dAdaptor_Curve::Parabola() const 
902 {
903   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Parabola, "");
904   return Handle(Geom2d_Parabola)::DownCast (myCurve)->Parab2d();
905 }
906
907 //=======================================================================
908 //function : Degree
909 //purpose  : 
910 //=======================================================================
911
912 Standard_Integer Geom2dAdaptor_Curve::Degree() const
913 {
914   if (myTypeCurve == GeomAbs_BezierCurve)
915     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->Degree();
916   else if (myTypeCurve == GeomAbs_BSplineCurve)
917     return myBSplineCurve->Degree();
918   else
919     Standard_NoSuchObject::Raise();
920   // portage WNT 
921   return 0;
922 }
923
924 //=======================================================================
925 //function : IsRational
926 //purpose  : 
927 //=======================================================================
928
929 Standard_Boolean Geom2dAdaptor_Curve::IsRational() const {
930   switch( myTypeCurve) {
931   case GeomAbs_BSplineCurve:
932     return myBSplineCurve->IsRational();
933   case GeomAbs_BezierCurve:
934     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->IsRational();
935   default:
936     return Standard_False;
937   }
938 }
939
940 //=======================================================================
941 //function : NbPoles
942 //purpose  : 
943 //=======================================================================
944
945 Standard_Integer Geom2dAdaptor_Curve::NbPoles() const
946 {
947   if (myTypeCurve == GeomAbs_BezierCurve)
948     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->NbPoles();
949   else if (myTypeCurve == GeomAbs_BSplineCurve)
950     return myBSplineCurve->NbPoles();
951   else
952     Standard_NoSuchObject::Raise();
953   // portage WNT 
954   return 0;
955 }
956
957 //=======================================================================
958 //function : NbKnots
959 //purpose  : 
960 //=======================================================================
961
962 Standard_Integer Geom2dAdaptor_Curve::NbKnots() const
963 {
964   if ( myTypeCurve != GeomAbs_BSplineCurve)
965     Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::NbKnots");
966   return myBSplineCurve->NbKnots();
967 }
968
969 //=======================================================================
970 //function : Bezier
971 //purpose  : 
972 //=======================================================================
973
974 Handle(Geom2d_BezierCurve) Geom2dAdaptor_Curve::Bezier() const 
975 {
976   return Handle(Geom2d_BezierCurve)::DownCast (myCurve);
977 }
978
979 //=======================================================================
980 //function : BSpline
981 //purpose  : 
982 //=======================================================================
983
984 Handle(Geom2d_BSplineCurve) Geom2dAdaptor_Curve::BSpline() const 
985 {
986   return myBSplineCurve;
987 }
988
989 static Standard_Integer nbPoints(const Handle(Geom2d_Curve)& theCurve) 
990 {
991  
992   Standard_Integer nbs = 10;
993   
994   if(theCurve->IsKind(STANDARD_TYPE( Geom2d_Line)) )
995     nbs = 2;
996   else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BezierCurve))) 
997   {
998     nbs = 3 + Handle(Geom2d_BezierCurve)::DownCast (theCurve)->NbPoles();
999   }
1000   else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BSplineCurve))) { 
1001     nbs =  Handle(Geom2d_BSplineCurve)::DownCast (theCurve)->NbKnots();
1002     nbs*= Handle(Geom2d_BSplineCurve)::DownCast (theCurve)->Degree();
1003     if(nbs < 2.0) nbs=2;
1004   }
1005   else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
1006   {
1007     Handle(Geom2d_Curve) aCurve = Handle(Geom2d_OffsetCurve)::DownCast (theCurve)->BasisCurve();
1008     return Max(nbs, nbPoints(aCurve));
1009   }
1010
1011   else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
1012   {
1013     Handle(Geom2d_Curve) aCurve = Handle(Geom2d_TrimmedCurve)::DownCast (theCurve)->BasisCurve();
1014     return Max(nbs, nbPoints(aCurve));
1015   }
1016   if(nbs>300)
1017     nbs = 300;
1018   return nbs;
1019
1020 }
1021
1022 Standard_Integer Geom2dAdaptor_Curve::NbSamples() const
1023 {
1024   return  nbPoints(myCurve);
1025 }