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