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