0026838: Using GeomEvaluators for calculation of values of curves
[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) 
79      const {
80
81        Standard_NoSuchObject_Raise_if(myTypeCurve!=GeomAbs_BSplineCurve," ");
82        Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
83        Standard_Integer Nb = aBspl->NbKnots();
84        Standard_Integer Index1 = 0;
85        Standard_Integer Index2 = 0;
86        Standard_Real newFirst, newLast;
87        TColStd_Array1OfReal    TK(1,Nb);
88        TColStd_Array1OfInteger TM(1,Nb);
89        aBspl->Knots(TK);
90        aBspl->Multiplicities(TM);
91        BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,U1,aBspl->IsPeriodic(),
92                                  1,Nb,Index1,newFirst);
93        BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,U2,aBspl->IsPeriodic(),
94                                  1,Nb,Index2,newLast);
95        if ( Abs(newFirst-TK(Index1+1))<Precision::PConfusion()) { 
96          if (Index1 < Nb)Index1++;
97        }
98        if ( Abs(newLast-TK(Index2))<Precision::PConfusion())
99          Index2--;
100        Standard_Integer MultMax;
101        // attention aux courbes peridiques.
102        if ( (aBspl->IsPeriodic()) && (Index1 == Nb) )
103          Index1 = 1;
104
105        if ( Index2 - Index1 <= 0) {
106          MultMax = 100;  // CN entre 2 Noeuds consecutifs
107        }
108        else {
109          MultMax = TM(Index1+1);
110          for(Standard_Integer i = Index1+1;i<=Index2;i++) {
111            if ( TM(i)>MultMax) MultMax=TM(i);
112          }
113          MultMax = aBspl->Degree() - MultMax;
114        }
115        if ( MultMax <= 0) {
116          return GeomAbs_C0;
117        }
118        else if ( MultMax == 1) {
119          return GeomAbs_C1;
120        } 
121        else if ( MultMax == 2) {
122          return GeomAbs_C2;
123        }
124        else if ( MultMax == 3) {
125          return GeomAbs_C3;
126        }
127        else { 
128          return GeomAbs_CN;
129        }
130      }
131
132
133 //=======================================================================
134 //function : Geom2dAdaptor_Curve
135 //purpose  : 
136 //=======================================================================
137
138 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve()
139 : myTypeCurve(GeomAbs_OtherCurve),
140   myFirst    (0.0),
141   myLast     (0.0)
142 {
143 }
144
145 //=======================================================================
146 //function : Geom2dAdaptor_Curve
147 //purpose  : 
148 //=======================================================================
149
150 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve(const Handle(Geom2d_Curve)& theCrv)
151 : myTypeCurve(GeomAbs_OtherCurve),
152   myFirst    (0.0),
153   myLast     (0.0)
154 {
155   Load(theCrv);
156 }
157
158 //=======================================================================
159 //function : Geom2dAdaptor_Curve
160 //purpose  : 
161 //=======================================================================
162
163 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve(const Handle(Geom2d_Curve)& theCrv,
164                                          const Standard_Real theUFirst,
165                                          const Standard_Real theULast)
166 : myTypeCurve(GeomAbs_OtherCurve),
167   myFirst    (theUFirst),
168   myLast     (theULast)
169 {
170   Load(theCrv, theUFirst, theULast);
171 }
172
173
174 //=======================================================================
175 //function : Load
176 //purpose  : 
177 //=======================================================================
178
179 void Geom2dAdaptor_Curve::load(const Handle(Geom2d_Curve)& C,
180                                                  const Standard_Real UFirst,
181                                                  const Standard_Real ULast) 
182 {
183   myFirst = UFirst;
184   myLast  = ULast;
185
186   if ( myCurve != C) {
187     myCurve = C;
188     myCurveCache = Handle(BSplCLib_Cache)();
189     myNestedEvaluator = Handle(Geom2dEvaluator_Curve)();
190
191     Handle(Standard_Type) TheType = C->DynamicType();
192     if ( TheType == STANDARD_TYPE(Geom2d_TrimmedCurve)) {
193       Load(Handle(Geom2d_TrimmedCurve)::DownCast (C)->BasisCurve(),
194            UFirst,ULast);
195     }
196     else if ( TheType ==  STANDARD_TYPE(Geom2d_Circle)) {
197       myTypeCurve = GeomAbs_Circle;
198     }
199     else if ( TheType ==STANDARD_TYPE(Geom2d_Line)) {
200       myTypeCurve = GeomAbs_Line;
201     }
202     else if ( TheType == STANDARD_TYPE(Geom2d_Ellipse)) {
203       myTypeCurve = GeomAbs_Ellipse;
204     }
205     else if ( TheType == STANDARD_TYPE(Geom2d_Parabola)) {
206       myTypeCurve = GeomAbs_Parabola;
207     }
208     else if ( TheType == STANDARD_TYPE(Geom2d_Hyperbola)) {
209       myTypeCurve = GeomAbs_Hyperbola;
210     }
211     else if ( TheType == STANDARD_TYPE(Geom2d_BezierCurve)) {
212       myTypeCurve = GeomAbs_BezierCurve;
213       // Create cache for Bezier
214       Handle(Geom2d_BezierCurve) aBezier = Handle(Geom2d_BezierCurve)::DownCast(myCurve);
215       Standard_Integer aDeg = aBezier->Degree();
216       TColStd_Array1OfReal aFlatKnots(BSplCLib::FlatBezierKnots(aDeg), 1, 2 * (aDeg + 1));
217       myCurveCache = new BSplCLib_Cache(aDeg, aBezier->IsPeriodic(), aFlatKnots,
218           aBezier->Poles(), aBezier->Weights());
219     }
220     else if ( TheType == STANDARD_TYPE(Geom2d_BSplineCurve)) {
221       myTypeCurve = GeomAbs_BSplineCurve;
222       // Create cache for B-spline
223       Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
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     Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
294     Standard_Integer FirstIndex = aBspl->FirstUKnotIndex();
295     Standard_Integer LastIndex  = aBspl->LastUKnotIndex();
296     TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
297     if ( S > Continuity()) {
298       Standard_Integer Cont;
299       switch ( S) {
300       case GeomAbs_G1:
301       case GeomAbs_G2:
302         Standard_DomainError::Raise("Geom2dAdaptor_Curve::NbIntervals");
303         break;
304       case GeomAbs_C0:
305         myNbIntervals = 1;
306         break;
307       case GeomAbs_C1:
308       case GeomAbs_C2:
309       case GeomAbs_C3: 
310       case GeomAbs_CN: 
311         {
312           if      ( S == GeomAbs_C1) Cont = 1;
313           else if ( S == GeomAbs_C2) Cont = 2;
314           else if ( S == GeomAbs_C3) Cont = 3;
315           else                       Cont = aBspl->Degree();
316           Standard_Integer Degree = aBspl->Degree();
317           Standard_Integer NbKnots = aBspl->NbKnots();
318           TColStd_Array1OfInteger Mults (1, NbKnots);
319           aBspl->Multiplicities (Mults);
320           NbSplit = 1;
321           Standard_Integer Index   = FirstIndex;
322           Inter (NbSplit) = Index;
323           Index++;
324           NbSplit++;
325           while (Index < LastIndex) 
326             {
327               if (Degree - Mults (Index) < Cont) 
328                 {
329                   Inter (NbSplit) = Index;
330                   NbSplit++;
331                 }
332               Index++;
333             }
334           Inter (NbSplit) = Index;
335
336           Standard_Integer NbInt = NbSplit-1;
337           
338           Standard_Integer Nb = aBspl->NbKnots();
339           Standard_Integer Index1 = 0;
340           Standard_Integer Index2 = 0;
341           Standard_Real newFirst, newLast;
342           TColStd_Array1OfReal    TK(1,Nb);
343           TColStd_Array1OfInteger TM(1,Nb);
344           aBspl->Knots(TK);
345           aBspl->Multiplicities(TM);
346           BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,myFirst,
347                                     aBspl->IsPeriodic(),
348                                     1,Nb,Index1,newFirst);
349           BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,myLast,
350                                     aBspl->IsPeriodic(),
351                                     1,Nb,Index2,newLast);
352
353           // On decale eventuellement les indices  
354           // On utilise une "petite" tolerance, la resolution ne doit 
355           // servir que pour les tres longue courbes....(PRO9248)
356           Standard_Real Eps = Min(Resolution(Precision::Confusion()),
357                                   Precision::PConfusion()); 
358           if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
359           if ( newLast-TK(Index2)> Eps) Index2++;
360           
361           myNbIntervals = 1;
362           for ( Standard_Integer i=1; i<=NbInt; i++)
363             if (Inter(i)>Index1 && Inter(i)<Index2) myNbIntervals++;
364         }
365         break;
366       }
367     }
368   }
369   else if (myTypeCurve == GeomAbs_OffsetCurve){
370     GeomAbs_Shape BaseS=GeomAbs_C0;
371     switch(S){
372     case GeomAbs_G1:
373     case GeomAbs_G2:
374       Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
375       break;
376     case GeomAbs_C0: BaseS = GeomAbs_C1; break;
377     case GeomAbs_C1: BaseS = GeomAbs_C2; break;
378     case GeomAbs_C2: BaseS = GeomAbs_C3; break;
379     default: BaseS = GeomAbs_CN;
380     }
381     Geom2dAdaptor_Curve anAdaptor( Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->BasisCurve() );
382     myNbIntervals = anAdaptor.NbIntervals(BaseS);
383   }
384
385   return myNbIntervals;
386 }
387
388 //=======================================================================
389 //function : Intervals
390 //purpose  : 
391 //=======================================================================
392
393 void Geom2dAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
394                                     const GeomAbs_Shape S   ) const 
395 {
396   Standard_Integer myNbIntervals = 1;
397   Standard_Integer NbSplit;
398   if (myTypeCurve == GeomAbs_BSplineCurve) {
399     Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
400     Standard_Integer FirstIndex = aBspl->FirstUKnotIndex();
401     Standard_Integer LastIndex  = aBspl->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 = aBspl->Degree();
422           Standard_Integer Degree = aBspl->Degree();
423           Standard_Integer NbKnots = aBspl->NbKnots();
424           TColStd_Array1OfInteger Mults (1, NbKnots);
425           aBspl->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 = aBspl->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           aBspl->Knots(TK);
450           aBspl->Multiplicities(TM);
451           BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,myFirst,
452                                     aBspl->IsPeriodic(),
453                                     1,Nb,Index1,newFirst);
454           BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,myLast,
455                                     aBspl->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     Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
581     myCurveCache->BuildCache(theParameter, aBspl->Degree(),
582       aBspl->IsPeriodic(), aBspl->KnotSequence(),
583       aBspl->Poles(), aBspl->Weights());
584   }
585 }
586
587 //=======================================================================
588 //function : IsBoundary
589 //purpose  : 
590 //=======================================================================
591 Standard_Boolean Geom2dAdaptor_Curve::IsBoundary(const Standard_Real theU,
592                                                  Standard_Integer& theSpanStart,
593                                                  Standard_Integer& theSpanFinish) const
594 {
595   Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
596   if (!aBspl.IsNull() && (theU == myFirst || theU == myLast))
597   {
598     if (theU == myFirst)
599     {
600       aBspl->LocateU(myFirst, PosTol, theSpanStart, theSpanFinish);
601       if (theSpanStart < 1)
602         theSpanStart = 1;
603       if (theSpanStart >= theSpanFinish)
604         theSpanFinish = theSpanStart + 1;
605     }
606     else if (theU == myLast)
607     {
608       aBspl->LocateU(myLast, PosTol, theSpanStart, theSpanFinish);
609       if (theSpanFinish > aBspl->NbKnots())
610         theSpanFinish = aBspl->NbKnots();
611       if (theSpanStart >= theSpanFinish)
612         theSpanStart = theSpanFinish - 1;
613     }
614     return Standard_True;
615   }
616   return Standard_False;
617 }
618
619 //=======================================================================
620 //function : Value
621 //purpose  : 
622 //=======================================================================
623
624 gp_Pnt2d Geom2dAdaptor_Curve::Value(const Standard_Real U) const 
625 {
626   gp_Pnt2d aRes;
627   D0(U, aRes);
628   return aRes;
629 }
630
631 //=======================================================================
632 //function : D0
633 //purpose  : 
634 //=======================================================================
635
636 void Geom2dAdaptor_Curve::D0(const Standard_Real U, gp_Pnt2d& P) const
637 {
638   switch (myTypeCurve)
639   {
640   case GeomAbs_BezierCurve:
641   case GeomAbs_BSplineCurve:
642   {
643     Standard_Integer aStart = 0, aFinish = 0;
644     if (IsBoundary(U, aStart, aFinish))
645     {
646       Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
647       aBspl->LocalD0(U, aStart, aFinish, P);
648     }
649     else if (!myCurveCache.IsNull()) // use cached data
650     {
651       if (!myCurveCache->IsCacheValid(U))
652         RebuildCache(U);
653       myCurveCache->D0(U, P);
654     }
655     else
656       myCurve->D0(U, P);
657     break;
658   }
659
660   case GeomAbs_OffsetCurve:
661     myNestedEvaluator->D0(U, P);
662     break;
663
664   default:
665     myCurve->D0(U, P);
666   }
667 }
668
669 //=======================================================================
670 //function : D1
671 //purpose  : 
672 //=======================================================================
673
674 void Geom2dAdaptor_Curve::D1(const Standard_Real U, 
675                              gp_Pnt2d& P, gp_Vec2d& V) const 
676 {
677   switch (myTypeCurve)
678   {
679   case GeomAbs_BezierCurve:
680   case GeomAbs_BSplineCurve:
681   {
682     Standard_Integer aStart = 0, aFinish = 0;
683     if (IsBoundary(U, aStart, aFinish))
684     {
685       Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
686       aBspl->LocalD1(U, aStart, aFinish, P, V);
687     }
688     else if (!myCurveCache.IsNull()) // use cached data
689     {
690       if (!myCurveCache->IsCacheValid(U))
691         RebuildCache(U);
692       myCurveCache->D1(U, P, V);
693     }
694     else
695       myCurve->D1(U, P, V);
696     break;
697   }
698
699   case GeomAbs_OffsetCurve:
700     myNestedEvaluator->D1(U, P, V);
701     break;
702
703   default:
704     myCurve->D1(U, P, V);
705   }
706 }
707
708 //=======================================================================
709 //function : D2
710 //purpose  : 
711 //=======================================================================
712
713 void Geom2dAdaptor_Curve::D2(const Standard_Real U, 
714                              gp_Pnt2d& P, gp_Vec2d& V1, gp_Vec2d& V2) const 
715 {
716   switch (myTypeCurve)
717   {
718   case GeomAbs_BezierCurve:
719   case GeomAbs_BSplineCurve:
720   {
721     Standard_Integer aStart = 0, aFinish = 0;
722     if (IsBoundary(U, aStart, aFinish))
723     {
724       Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
725       aBspl->LocalD2(U, aStart, aFinish, P, V1, V2);
726     }
727     else if (!myCurveCache.IsNull()) // use cached data
728     {
729       if (!myCurveCache->IsCacheValid(U))
730         RebuildCache(U);
731       myCurveCache->D2(U, P, V1, V2);
732     }
733     else
734       myCurve->D2(U, P, V1, V2);
735     break;
736   }
737
738   case GeomAbs_OffsetCurve:
739     myNestedEvaluator->D2(U, P, V1, V2);
740     break;
741
742   default:
743     myCurve->D2(U, P, V1, V2);
744   }
745 }
746
747 //=======================================================================
748 //function : D3
749 //purpose  : 
750 //=======================================================================
751
752 void Geom2dAdaptor_Curve::D3(const Standard_Real U, 
753                              gp_Pnt2d& P,  gp_Vec2d& V1, 
754                              gp_Vec2d& V2, gp_Vec2d& V3) const 
755 {
756   switch (myTypeCurve)
757   {
758   case GeomAbs_BezierCurve:
759   case GeomAbs_BSplineCurve:
760   {
761     Standard_Integer aStart = 0, aFinish = 0;
762     if (IsBoundary(U, aStart, aFinish))
763     {
764       Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
765       aBspl->LocalD3(U, aStart, aFinish, P, V1, V2, V3);
766     }
767     else if (!myCurveCache.IsNull()) // use cached data
768     {
769       if (!myCurveCache->IsCacheValid(U))
770         RebuildCache(U);
771       myCurveCache->D3(U, P, V1, V2, V3);
772     }
773     else
774       myCurve->D3(U, P, V1, V2, V3);
775     break;
776   }
777
778   case GeomAbs_OffsetCurve:
779     myNestedEvaluator->D3(U, P, V1, V2, V3);
780     break;
781
782   default:
783     myCurve->D3(U, P, V1, V2, V3);
784   }
785 }
786
787 //=======================================================================
788 //function : DN
789 //purpose  : 
790 //=======================================================================
791
792 gp_Vec2d Geom2dAdaptor_Curve::DN(const Standard_Real U, 
793                                  const Standard_Integer N) const 
794 {
795   switch (myTypeCurve)
796   {
797   case GeomAbs_BezierCurve:
798   case GeomAbs_BSplineCurve:
799   {
800     Standard_Integer aStart = 0, aFinish = 0;
801     if (IsBoundary(U, aStart, aFinish))
802     {
803       Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
804       return aBspl->LocalDN(U, aStart, aFinish, N);
805     }
806     else
807       return myCurve->DN(U, N);
808     break;
809   }
810
811   case GeomAbs_OffsetCurve:
812     return myNestedEvaluator->DN(U, N);
813     break;
814
815   default: // to eliminate gcc warning
816     break;
817   }
818   return myCurve->DN(U, N);
819 }
820
821 //=======================================================================
822 //function : Resolution
823 //purpose  : 
824 //=======================================================================
825
826 Standard_Real Geom2dAdaptor_Curve::Resolution(const Standard_Real Ruv) const {
827   switch ( myTypeCurve) {
828   case GeomAbs_Line :
829     return Ruv;
830   case GeomAbs_Circle: {
831     Standard_Real R = Handle(Geom2d_Circle)::DownCast (myCurve)->Circ2d().Radius();
832     if ( R > Ruv/2.)
833       return 2*ASin(Ruv/(2*R));
834     else
835       return 2*M_PI;
836   }
837   case GeomAbs_Ellipse: {
838     return Ruv / Handle(Geom2d_Ellipse)::DownCast (myCurve)->MajorRadius();
839   }
840   case GeomAbs_BezierCurve: {
841     Standard_Real res;
842     Handle(Geom2d_BezierCurve)::DownCast (myCurve)->Resolution(Ruv,res);
843     return res;
844   }
845   case GeomAbs_BSplineCurve: {
846     Standard_Real res;
847     Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->Resolution(Ruv,res);
848     return res;
849   }
850   default:
851     return Precision::Parametric(Ruv);
852   }  
853 }
854
855
856 //    --
857 //    --     The following methods must  be called when GetType returned
858 //    --     the corresponding type.
859 //    --     
860
861 //=======================================================================
862 //function : Line
863 //purpose  : 
864 //=======================================================================
865
866 gp_Lin2d Geom2dAdaptor_Curve::Line() const 
867 {
868   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Line, "");
869   return Handle(Geom2d_Line)::DownCast (myCurve)->Lin2d();
870 }
871
872 //=======================================================================
873 //function : Circle
874 //purpose  : 
875 //=======================================================================
876
877 gp_Circ2d  Geom2dAdaptor_Curve::Circle() const 
878 {
879   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Circle, "");
880   return Handle(Geom2d_Circle)::DownCast (myCurve)->Circ2d();
881 }
882
883 //=======================================================================
884 //function : Ellipse
885 //purpose  : 
886 //=======================================================================
887
888 gp_Elips2d Geom2dAdaptor_Curve::Ellipse() const 
889 {
890   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Ellipse, "");
891   return Handle(Geom2d_Ellipse)::DownCast (myCurve)->Elips2d();
892 }
893
894 //=======================================================================
895 //function : Hyperbola
896 //purpose  : 
897 //=======================================================================
898
899 gp_Hypr2d Geom2dAdaptor_Curve::Hyperbola() const 
900 {
901   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Hyperbola, "");
902   return Handle(Geom2d_Hyperbola)::DownCast (myCurve)->Hypr2d();
903 }
904
905 //=======================================================================
906 //function : Parabola
907 //purpose  : 
908 //=======================================================================
909
910 gp_Parab2d Geom2dAdaptor_Curve::Parabola() const 
911 {
912   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Parabola, "");
913   return Handle(Geom2d_Parabola)::DownCast (myCurve)->Parab2d();
914 }
915
916 //=======================================================================
917 //function : Degree
918 //purpose  : 
919 //=======================================================================
920
921 Standard_Integer Geom2dAdaptor_Curve::Degree() const
922 {
923   if (myTypeCurve == GeomAbs_BezierCurve)
924     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->Degree();
925   else if (myTypeCurve == GeomAbs_BSplineCurve)
926     return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->Degree();
927   else
928     Standard_NoSuchObject::Raise();
929   // portage WNT 
930   return 0;
931 }
932
933 //=======================================================================
934 //function : IsRational
935 //purpose  : 
936 //=======================================================================
937
938 Standard_Boolean Geom2dAdaptor_Curve::IsRational() const {
939   switch( myTypeCurve) {
940   case GeomAbs_BSplineCurve:
941     return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->IsRational();
942   case GeomAbs_BezierCurve:
943     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->IsRational();
944   default:
945     return Standard_False;
946   }
947 }
948
949 //=======================================================================
950 //function : NbPoles
951 //purpose  : 
952 //=======================================================================
953
954 Standard_Integer Geom2dAdaptor_Curve::NbPoles() const
955 {
956   if (myTypeCurve == GeomAbs_BezierCurve)
957     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->NbPoles();
958   else if (myTypeCurve == GeomAbs_BSplineCurve)
959     return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->NbPoles();
960   else
961     Standard_NoSuchObject::Raise();
962   // portage WNT 
963   return 0;
964 }
965
966 //=======================================================================
967 //function : NbKnots
968 //purpose  : 
969 //=======================================================================
970
971 Standard_Integer Geom2dAdaptor_Curve::NbKnots() const {
972   if ( myTypeCurve != GeomAbs_BSplineCurve)
973     Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::NbKnots");
974   return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->NbKnots();
975
976 }
977
978 //=======================================================================
979 //function : Bezier
980 //purpose  : 
981 //=======================================================================
982
983 Handle(Geom2d_BezierCurve) Geom2dAdaptor_Curve::Bezier() const 
984 {
985   return Handle(Geom2d_BezierCurve)::DownCast (myCurve);
986 }
987
988 //=======================================================================
989 //function : BSpline
990 //purpose  : 
991 //=======================================================================
992
993 Handle(Geom2d_BSplineCurve) Geom2dAdaptor_Curve::BSpline() const 
994 {
995   return Handle(Geom2d_BSplineCurve)::DownCast (myCurve);
996 }
997
998 static Standard_Integer nbPoints(const Handle(Geom2d_Curve)& theCurve) 
999 {
1000  
1001   Standard_Integer nbs = 10;
1002   
1003   if(theCurve->IsKind(STANDARD_TYPE( Geom2d_Line)) )
1004     nbs = 2;
1005   else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BezierCurve))) 
1006   {
1007     nbs = 3 + Handle(Geom2d_BezierCurve)::DownCast (theCurve)->NbPoles();
1008   }
1009   else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BSplineCurve))) { 
1010     nbs =  Handle(Geom2d_BSplineCurve)::DownCast (theCurve)->NbKnots();
1011     nbs*= Handle(Geom2d_BSplineCurve)::DownCast (theCurve)->Degree();
1012     if(nbs < 2.0) nbs=2;
1013   }
1014   else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
1015   {
1016     Handle(Geom2d_Curve) aCurve = Handle(Geom2d_OffsetCurve)::DownCast (theCurve)->BasisCurve();
1017     return Max(nbs, nbPoints(aCurve));
1018   }
1019
1020   else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
1021   {
1022     Handle(Geom2d_Curve) aCurve = Handle(Geom2d_TrimmedCurve)::DownCast (theCurve)->BasisCurve();
1023     return Max(nbs, nbPoints(aCurve));
1024   }
1025   if(nbs>300)
1026     nbs = 300;
1027   return nbs;
1028   
1029 }
1030
1031 Standard_Integer Geom2dAdaptor_Curve::NbSamples() const
1032 {
1033   return  nbPoints(myCurve);
1034 }