0026254: Inject GeomAbs_OffsetCurve into GeomAbs_CurveType enumeration
[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 <CSLib_Offset.hxx>
29 #include <Geom2d_BezierCurve.hxx>
30 #include <Geom2d_BSplineCurve.hxx>
31 #include <Geom2d_Circle.hxx>
32 #include <Geom2d_Curve.hxx>
33 #include <Geom2d_Ellipse.hxx>
34 #include <Geom2d_Hyperbola.hxx>
35 #include <Geom2d_Line.hxx>
36 #include <Geom2d_OffsetCurve.hxx>
37 #include <Geom2d_Parabola.hxx>
38 #include <Geom2d_TrimmedCurve.hxx>
39 #include <Geom2d_UndefinedDerivative.hxx>
40 #include <Geom2d_UndefinedValue.hxx>
41 #include <Geom2dAdaptor_Curve.hxx>
42 #include <Geom2dAdaptor_HCurve.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 #define myBspl Handle(Geom2d_BSplineCurve)::DownCast (myCurve)
66 #define PosTol Precision::PConfusion()/2
67
68 static const int maxDerivOrder = 3;
69 static const Standard_Real MinStep   = 1e-7;
70
71 static gp_Vec2d dummyDerivative; // used as empty value for unused derivatives in AdjustDerivative
72
73 // Recalculate derivatives in the singular point
74 // Returns true is the direction of derivatives is changed
75 static Standard_Boolean AdjustDerivative(const Handle(Adaptor2d_HCurve2d)& theAdaptor, Standard_Integer theMaxDerivative,
76                                          Standard_Real theU, gp_Vec2d& theD1, gp_Vec2d& theD2 = dummyDerivative,
77                                          gp_Vec2d& theD3 = dummyDerivative, gp_Vec2d& theD4 = dummyDerivative);
78
79 //=======================================================================
80 //function : LocalContinuity
81 //purpose  : Computes the Continuity of a BSplineCurve 
82 //           between the parameters U1 and U2
83 //           The continuity is C(d-m) 
84 //             with   d = degree, 
85 //                    m = max multiplicity of the Knots between U1 and U2
86 //=======================================================================
87
88 GeomAbs_Shape Geom2dAdaptor_Curve::LocalContinuity(const Standard_Real U1, 
89                                                    const Standard_Real U2) 
90      const {
91
92        Standard_NoSuchObject_Raise_if(myTypeCurve!=GeomAbs_BSplineCurve," ");
93        Standard_Integer Nb = myBspl->NbKnots();
94        Standard_Integer Index1 = 0;
95        Standard_Integer Index2 = 0;
96        Standard_Real newFirst, newLast;
97        TColStd_Array1OfReal    TK(1,Nb);
98        TColStd_Array1OfInteger TM(1,Nb);
99        myBspl->Knots(TK);
100        myBspl->Multiplicities(TM);
101        BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,U1,myBspl->IsPeriodic(),
102                                  1,Nb,Index1,newFirst);
103        BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,U2,myBspl->IsPeriodic(),
104                                  1,Nb,Index2,newLast);
105        if ( Abs(newFirst-TK(Index1+1))<Precision::PConfusion()) { 
106          if (Index1 < Nb)Index1++;
107        }
108        if ( Abs(newLast-TK(Index2))<Precision::PConfusion())
109          Index2--;
110        Standard_Integer MultMax;
111        // attention aux courbes peridiques.
112        if ( (myBspl->IsPeriodic()) && (Index1 == Nb) )
113          Index1 = 1;
114
115        if ( Index2 - Index1 <= 0) {
116          MultMax = 100;  // CN entre 2 Noeuds consecutifs
117        }
118        else {
119          MultMax = TM(Index1+1);
120          for(Standard_Integer i = Index1+1;i<=Index2;i++) {
121            if ( TM(i)>MultMax) MultMax=TM(i);
122          }
123          MultMax = myBspl->Degree() - MultMax;
124        }
125        if ( MultMax <= 0) {
126          return GeomAbs_C0;
127        }
128        else if ( MultMax == 1) {
129          return GeomAbs_C1;
130        } 
131        else if ( MultMax == 2) {
132          return GeomAbs_C2;
133        }
134        else if ( MultMax == 3) {
135          return GeomAbs_C3;
136        }
137        else { 
138          return GeomAbs_CN;
139        }
140      }
141
142
143 //=======================================================================
144 //function : Geom2dAdaptor_Curve
145 //purpose  : 
146 //=======================================================================
147
148 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve()
149 : myTypeCurve(GeomAbs_OtherCurve),
150   myFirst    (0.0),
151   myLast     (0.0)
152 {
153 }
154
155 //=======================================================================
156 //function : Geom2dAdaptor_Curve
157 //purpose  : 
158 //=======================================================================
159
160 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve(const Handle(Geom2d_Curve)& theCrv)
161 : myTypeCurve(GeomAbs_OtherCurve),
162   myFirst    (0.0),
163   myLast     (0.0)
164 {
165   Load(theCrv);
166 }
167
168 //=======================================================================
169 //function : Geom2dAdaptor_Curve
170 //purpose  : 
171 //=======================================================================
172
173 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve(const Handle(Geom2d_Curve)& theCrv,
174                                          const Standard_Real theUFirst,
175                                          const Standard_Real theULast)
176 : myTypeCurve(GeomAbs_OtherCurve),
177   myFirst    (theUFirst),
178   myLast     (theULast)
179 {
180   Load(theCrv, theUFirst, theULast);
181 }
182
183
184 //=======================================================================
185 //function : Load
186 //purpose  : 
187 //=======================================================================
188
189 void Geom2dAdaptor_Curve::load(const Handle(Geom2d_Curve)& C,
190                                                  const Standard_Real UFirst,
191                                                  const Standard_Real ULast) 
192 {
193   myFirst = UFirst;
194   myLast  = ULast;
195
196   if ( myCurve != C) {
197     myCurve = C;
198
199     Handle(Standard_Type) TheType = C->DynamicType();
200     if ( TheType == STANDARD_TYPE(Geom2d_TrimmedCurve)) {
201       Load(Handle(Geom2d_TrimmedCurve)::DownCast (C)->BasisCurve(),
202            UFirst,ULast);
203     }
204     else if ( TheType ==  STANDARD_TYPE(Geom2d_Circle)) {
205       myTypeCurve = GeomAbs_Circle;
206     }
207     else if ( TheType ==STANDARD_TYPE(Geom2d_Line)) {
208       myTypeCurve = GeomAbs_Line;
209     }
210     else if ( TheType == STANDARD_TYPE(Geom2d_Ellipse)) {
211       myTypeCurve = GeomAbs_Ellipse;
212     }
213     else if ( TheType == STANDARD_TYPE(Geom2d_Parabola)) {
214       myTypeCurve = GeomAbs_Parabola;
215     }
216     else if ( TheType == STANDARD_TYPE(Geom2d_Hyperbola)) {
217       myTypeCurve = GeomAbs_Hyperbola;
218     }
219     else if ( TheType == STANDARD_TYPE(Geom2d_BezierCurve)) {
220       myTypeCurve = GeomAbs_BezierCurve;
221     }
222     else if ( TheType == STANDARD_TYPE(Geom2d_BSplineCurve)) {
223       myTypeCurve = GeomAbs_BSplineCurve;
224       // Create cache for B-spline
225       myCurveCache = new BSplCLib_Cache(myBspl->Degree(), myBspl->IsPeriodic(), 
226         myBspl->KnotSequence(), myBspl->Poles(), myBspl->Weights());
227     }
228     else if ( TheType == STANDARD_TYPE(Geom2d_OffsetCurve))
229     {
230       myTypeCurve = GeomAbs_OffsetCurve;
231       // Create nested adaptor for base curve
232       Handle(Geom2d_Curve) aBase = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->BasisCurve();
233       myOffsetBaseCurveAdaptor = new Geom2dAdaptor_HCurve(aBase);
234     }
235     else {
236       myTypeCurve = GeomAbs_OtherCurve;
237     }
238   }
239 }
240
241 //    --
242 //    --     Global methods - Apply to the whole curve.
243 //    --     
244
245 //=======================================================================
246 //function : Continuity
247 //purpose  : 
248 //=======================================================================
249
250 GeomAbs_Shape Geom2dAdaptor_Curve::Continuity() const 
251 {
252   if (myTypeCurve == GeomAbs_BSplineCurve) {
253     return LocalContinuity(myFirst, myLast);
254   }
255   else if (myTypeCurve == GeomAbs_OffsetCurve){
256     GeomAbs_Shape S = 
257       Handle(Geom2d_OffsetCurve)::DownCast (myCurve)->GetBasisCurveContinuity(); 
258     switch(S){
259     case GeomAbs_CN: return GeomAbs_CN;
260     case GeomAbs_C3: return GeomAbs_C2;
261     case GeomAbs_C2: return GeomAbs_C1;
262     case GeomAbs_C1: return GeomAbs_C0;  
263     case GeomAbs_G1: return GeomAbs_G1;
264     case GeomAbs_G2: return GeomAbs_G2;
265
266     default:
267       Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::Continuity");
268     }
269   }
270
271   else if (myTypeCurve == GeomAbs_OtherCurve) {
272     Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::Continuity");
273   }
274   else {
275     return GeomAbs_CN;
276   }
277
278   // portage WNT
279   return GeomAbs_CN;
280 }
281
282 //=======================================================================
283 //function : NbIntervals
284 //purpose  : 
285 //=======================================================================
286
287 Standard_Integer Geom2dAdaptor_Curve::NbIntervals(const GeomAbs_Shape S) const
288 {
289   Standard_Integer myNbIntervals = 1;
290   Standard_Integer NbSplit;
291   if (myTypeCurve == GeomAbs_BSplineCurve) {
292     Standard_Integer FirstIndex = myBspl->FirstUKnotIndex();
293     Standard_Integer LastIndex  = myBspl->LastUKnotIndex();
294     TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
295     if ( S > Continuity()) {
296       Standard_Integer Cont;
297       switch ( S) {
298       case GeomAbs_G1:
299       case GeomAbs_G2:
300         Standard_DomainError::Raise("Geom2dAdaptor_Curve::NbIntervals");
301         break;
302       case GeomAbs_C0:
303         myNbIntervals = 1;
304         break;
305       case GeomAbs_C1:
306       case GeomAbs_C2:
307       case GeomAbs_C3: 
308       case GeomAbs_CN: 
309         {
310           if      ( S == GeomAbs_C1) Cont = 1;
311           else if ( S == GeomAbs_C2) Cont = 2;
312           else if ( S == GeomAbs_C3) Cont = 3;
313           else                       Cont = myBspl->Degree();
314           Standard_Integer Degree = myBspl->Degree();
315           Standard_Integer NbKnots = myBspl->NbKnots();
316           TColStd_Array1OfInteger Mults (1, NbKnots);
317           myBspl->Multiplicities (Mults);
318           NbSplit = 1;
319           Standard_Integer Index   = FirstIndex;
320           Inter (NbSplit) = Index;
321           Index++;
322           NbSplit++;
323           while (Index < LastIndex) 
324             {
325               if (Degree - Mults (Index) < Cont) 
326                 {
327                   Inter (NbSplit) = Index;
328                   NbSplit++;
329                 }
330               Index++;
331             }
332           Inter (NbSplit) = Index;
333
334           Standard_Integer NbInt = NbSplit-1;
335           
336           Standard_Integer Nb = myBspl->NbKnots();
337           Standard_Integer Index1 = 0;
338           Standard_Integer Index2 = 0;
339           Standard_Real newFirst, newLast;
340           TColStd_Array1OfReal    TK(1,Nb);
341           TColStd_Array1OfInteger TM(1,Nb);
342           myBspl->Knots(TK);
343           myBspl->Multiplicities(TM);
344           BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myFirst,
345                                     myBspl->IsPeriodic(),
346                                     1,Nb,Index1,newFirst);
347           BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myLast,
348                                     myBspl->IsPeriodic(),
349                                     1,Nb,Index2,newLast);
350
351           // On decale eventuellement les indices  
352           // On utilise une "petite" tolerance, la resolution ne doit 
353           // servir que pour les tres longue courbes....(PRO9248)
354           Standard_Real Eps = Min(Resolution(Precision::Confusion()),
355                                   Precision::PConfusion()); 
356           if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
357           if ( newLast-TK(Index2)> Eps) Index2++;
358           
359           myNbIntervals = 1;
360           for ( Standard_Integer i=1; i<=NbInt; i++)
361             if (Inter(i)>Index1 && Inter(i)<Index2) myNbIntervals++;
362         }
363         break;
364       }
365     }
366   }
367   else if (myTypeCurve == GeomAbs_OffsetCurve){
368     GeomAbs_Shape BaseS=GeomAbs_C0;
369     switch(S){
370     case GeomAbs_G1:
371     case GeomAbs_G2:
372       Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
373       break;
374     case GeomAbs_C0: BaseS = GeomAbs_C1; break;
375     case GeomAbs_C1: BaseS = GeomAbs_C2; break;
376     case GeomAbs_C2: BaseS = GeomAbs_C3; break;
377     default: BaseS = GeomAbs_CN;
378     }
379     myNbIntervals = myOffsetBaseCurveAdaptor->NbIntervals(BaseS);
380   }
381
382   return myNbIntervals;
383 }
384
385 //=======================================================================
386 //function : Intervals
387 //purpose  : 
388 //=======================================================================
389
390 void Geom2dAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
391                                     const GeomAbs_Shape S   ) const 
392 {
393   Standard_Integer myNbIntervals = 1;
394   Standard_Integer NbSplit;
395   if (myTypeCurve == GeomAbs_BSplineCurve) {
396     Standard_Integer FirstIndex = myBspl->FirstUKnotIndex();
397     Standard_Integer LastIndex  = myBspl->LastUKnotIndex();
398     TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
399     if ( S > Continuity()) {
400       Standard_Integer Cont;
401       switch ( S) {
402       case GeomAbs_G1:
403       case GeomAbs_G2:
404         Standard_DomainError::Raise("Geom2dAdaptor_Curve::NbIntervals");
405         break;
406       case GeomAbs_C0:
407         myNbIntervals = 1;
408         break;
409       case GeomAbs_C1:
410       case GeomAbs_C2:
411       case GeomAbs_C3: 
412       case GeomAbs_CN: 
413         {
414           if      ( S == GeomAbs_C1) Cont = 1;
415           else if ( S == GeomAbs_C2) Cont = 2;
416           else if ( S == GeomAbs_C3) Cont = 3;
417           else                       Cont = myBspl->Degree();
418           Standard_Integer Degree = myBspl->Degree();
419           Standard_Integer NbKnots = myBspl->NbKnots();
420           TColStd_Array1OfInteger Mults (1, NbKnots);
421           myBspl->Multiplicities (Mults);
422           NbSplit = 1;
423           Standard_Integer Index   = FirstIndex;
424           Inter (NbSplit) = Index;
425           Index++;
426           NbSplit++;
427           while (Index < LastIndex) 
428             {
429               if (Degree - Mults (Index) < Cont) 
430                 {
431                   Inter (NbSplit) = Index;
432                   NbSplit++;
433                 }
434               Index++;
435             }
436           Inter (NbSplit) = Index;
437           Standard_Integer NbInt = NbSplit-1;
438           
439           Standard_Integer Nb = myBspl->NbKnots();
440           Standard_Integer Index1 = 0;
441           Standard_Integer Index2 = 0;
442           Standard_Real newFirst, newLast;
443           TColStd_Array1OfReal    TK(1,Nb);
444           TColStd_Array1OfInteger TM(1,Nb);
445           myBspl->Knots(TK);
446           myBspl->Multiplicities(TM);
447           BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myFirst,
448                                     myBspl->IsPeriodic(),
449                                     1,Nb,Index1,newFirst);
450           BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myLast,
451                                     myBspl->IsPeriodic(),
452                                     1,Nb,Index2,newLast);
453
454
455           // On decale eventuellement les indices  
456           // On utilise une "petite" tolerance, la resolution ne doit 
457           // servir que pour les tres longue courbes....(PRO9248)
458           Standard_Real Eps = Min(Resolution(Precision::Confusion()),
459                                   Precision::PConfusion()); 
460           if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
461           if ( newLast-TK(Index2)> Eps) Index2++;
462           
463           Inter( 1) = Index1;
464           myNbIntervals = 1;
465           for ( Standard_Integer i=1; i<=NbInt; i++) {
466             if (Inter(i) > Index1 && Inter(i)<Index2 ) {
467               myNbIntervals++;
468               Inter(myNbIntervals) = Inter(i);
469             }
470           }
471           Inter(myNbIntervals+1) = Index2;
472           
473           Standard_Integer ii = T.Lower() - 1;
474           for (Standard_Integer I=1;I<=myNbIntervals+1;I++) {
475             T(ii + I) = TK(Inter(I));
476           }
477         }
478         break;
479       }
480     }
481   }
482   else if (myTypeCurve == GeomAbs_OffsetCurve){
483     GeomAbs_Shape BaseS=GeomAbs_C0;
484     switch(S){
485     case GeomAbs_G1:
486     case GeomAbs_G2:
487       Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
488       break;
489     case GeomAbs_C0: BaseS = GeomAbs_C1; break;
490     case GeomAbs_C1: BaseS = GeomAbs_C2; break;
491     case GeomAbs_C2: BaseS = GeomAbs_C3; break;
492     default: BaseS = GeomAbs_CN;
493     }
494     myNbIntervals = myOffsetBaseCurveAdaptor->NbIntervals(BaseS);
495     myOffsetBaseCurveAdaptor->Intervals(T, BaseS);
496   }
497
498   T( T.Lower() ) = myFirst;
499   T( T.Lower() + myNbIntervals ) = myLast;
500 }
501
502 //=======================================================================
503 //function : Trim
504 //purpose  : 
505 //=======================================================================
506
507 Handle(Adaptor2d_HCurve2d) Geom2dAdaptor_Curve::Trim
508 (const Standard_Real First,
509  const Standard_Real Last,
510 // const Standard_Real Tol) const 
511  const Standard_Real ) const 
512 {
513   Handle(Geom2dAdaptor_HCurve) HE = new Geom2dAdaptor_HCurve(myCurve,First,Last);
514   return HE;
515 }
516
517
518 //=======================================================================
519 //function : IsClosed
520 //purpose  : 
521 //=======================================================================
522
523 Standard_Boolean Geom2dAdaptor_Curve::IsClosed() const 
524 {
525   if (!Precision::IsPositiveInfinite(myLast) &&
526       !Precision::IsNegativeInfinite(myFirst)) {
527     gp_Pnt2d Pd = Value(myFirst);
528     gp_Pnt2d Pf = Value(myLast);
529     return ( Pd.Distance(Pf) <= Precision::Confusion());
530   }
531   else
532     return Standard_False;
533 }
534
535 //=======================================================================
536 //function : IsPeriodic
537 //purpose  : 
538 //=======================================================================
539
540 Standard_Boolean Geom2dAdaptor_Curve::IsPeriodic() const 
541 {
542   if (myCurve->IsPeriodic())
543     return IsClosed();
544   else
545     return Standard_False;
546 }
547
548 //=======================================================================
549 //function : Period
550 //purpose  : 
551 //=======================================================================
552
553 Standard_Real Geom2dAdaptor_Curve::Period() const 
554 {
555   return myCurve->LastParameter() - myCurve->FirstParameter();
556 }
557
558 //=======================================================================
559 //function : RebuildCache
560 //purpose  : 
561 //=======================================================================
562 void Geom2dAdaptor_Curve::RebuildCache(const Standard_Real theParameter) const
563 {
564   myCurveCache->BuildCache(theParameter, myBspl->Degree(), 
565     myBspl->IsPeriodic(), myBspl->KnotSequence(), 
566     myBspl->Poles(), myBspl->Weights());
567 }
568
569 //=======================================================================
570 //function : Value
571 //purpose  : 
572 //=======================================================================
573
574 gp_Pnt2d Geom2dAdaptor_Curve::Value(const Standard_Real U) const 
575 {
576   if (myTypeCurve == GeomAbs_BSplineCurve)
577     return ValueBSpline(U);
578   else if (myTypeCurve == GeomAbs_OffsetCurve)
579     return ValueOffset(U);
580
581   return myCurve->Value(U);
582 }
583
584 //=======================================================================
585 //function : ValueBSpline
586 //purpose  : Computes the point of parameter U on the B-spline curve
587 //=======================================================================
588 gp_Pnt2d Geom2dAdaptor_Curve::ValueBSpline(const Standard_Real theU) const
589 {
590   if (theU == myFirst || theU == myLast)
591   {
592     Standard_Integer Ideb = 0, Ifin = 0;
593     if (theU == myFirst)
594     {
595       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
596       if (Ideb<1) Ideb=1;
597       if (Ideb>=Ifin) Ifin = Ideb+1;
598     }
599     if (theU == myLast)
600     {
601       myBspl->LocateU(myLast,  PosTol, Ideb, Ifin);
602       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
603       if (Ideb>=Ifin) Ideb = Ifin-1;
604     }
605     return myBspl->LocalValue(theU, Ideb, Ifin);
606   }
607   else if (!myCurveCache.IsNull()) // use cached B-spline data
608   {
609     if (!myCurveCache->IsCacheValid(theU))
610       RebuildCache(theU);
611     gp_Pnt2d aRes;
612     myCurveCache->D0(theU, aRes);
613     return aRes;
614   }
615   return myCurve->Value(theU);
616 }
617
618 //=======================================================================
619 //function : ValueOffset
620 //purpose  : Computes the point of parameter U on the offset curve
621 //=======================================================================
622 gp_Pnt2d Geom2dAdaptor_Curve::ValueOffset(const Standard_Real theU) const
623 {
624   gp_Pnt2d aP;
625   gp_Vec2d aD1;
626   myOffsetBaseCurveAdaptor->D1(theU, aP, aD1);
627   Standard_Boolean isDirectionChange = Standard_False;
628   const Standard_Real aTol = gp::Resolution();
629   if(aD1.SquareMagnitude() <= aTol)
630     isDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 1, theU, aD1);
631
632   Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
633   CSLib_Offset::D0(aP, aD1, anOffset, isDirectionChange, aP);
634   return aP;
635 }
636
637 //=======================================================================
638 //function : D0
639 //purpose  : 
640 //=======================================================================
641
642 void Geom2dAdaptor_Curve::D0(const Standard_Real U, gp_Pnt2d& P) const
643 {
644   if (myTypeCurve == GeomAbs_BSplineCurve)
645   {
646     D0BSpline(U, P);
647     return;
648   }
649   else if (myTypeCurve == GeomAbs_OffsetCurve)
650   {
651     D0Offset(U, P);
652     return;
653   }
654
655   myCurve->D0(U, P);
656 }
657
658 //=======================================================================
659 //function : D0BSpline
660 //purpose  : Computes the point of parameter theU on the B-spline curve
661 //=======================================================================
662 void Geom2dAdaptor_Curve::D0BSpline(const Standard_Real theU, gp_Pnt2d& theP) const
663 {
664   if (theU == myFirst || theU == myLast)
665   {
666     Standard_Integer Ideb = 0, Ifin = 0;
667     if (theU == myFirst) {
668       myBspl->LocateU(myFirst,  PosTol, Ideb, Ifin);
669       if (Ideb<1) Ideb=1;
670       if (Ideb>=Ifin) Ifin = Ideb+1;
671     }
672     if (theU == myLast) {
673       myBspl->LocateU(myLast,  PosTol, Ideb, Ifin);
674       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
675       if (Ideb>=Ifin) Ideb = Ifin-1;
676     }
677     myBspl->LocalD0(theU, Ideb, Ifin, theP);
678     return;
679   }
680   else if (!myCurveCache.IsNull()) // use cached B-spline data
681   {
682     if (!myCurveCache->IsCacheValid(theU))
683       RebuildCache(theU);
684     myCurveCache->D0(theU, theP);
685     return;
686   }
687   myCurve->D0(theU, theP);
688 }
689
690 //=======================================================================
691 //function : D0Offset
692 //purpose  : Computes the point of parameter theU on the offset curve
693 //=======================================================================
694 void Geom2dAdaptor_Curve::D0Offset(const Standard_Real theU, gp_Pnt2d& theP) const
695 {
696   theP = ValueOffset(theU);
697 }
698
699 //=======================================================================
700 //function : D1
701 //purpose  : 
702 //=======================================================================
703
704 void Geom2dAdaptor_Curve::D1(const Standard_Real U, 
705                              gp_Pnt2d& P, gp_Vec2d& V) const 
706 {
707   if (myTypeCurve == GeomAbs_BSplineCurve)
708   {
709     D1BSpline(U, P, V);
710     return;
711   }
712   else if (myTypeCurve == GeomAbs_OffsetCurve)
713   {
714     D1Offset(U, P, V);
715     return;
716   }
717
718   myCurve->D1(U, P, V);
719 }
720
721 //=======================================================================
722 //function : D1BSpline
723 //purpose  : Computes the point of parameter theU on the B-spline curve and its derivative
724 //=======================================================================
725 void Geom2dAdaptor_Curve::D1BSpline(const Standard_Real theU, gp_Pnt2d& theP, gp_Vec2d& theV) const
726 {
727   if (theU == myFirst || theU == myLast)
728   {
729     Standard_Integer Ideb = 0, Ifin = 0;
730     if (theU == myFirst) {
731       myBspl->LocateU(myFirst,  PosTol, Ideb, Ifin);
732       if (Ideb<1) Ideb=1;
733       if (Ideb>=Ifin) Ifin = Ideb+1;
734     }
735     if (theU == myLast) {
736       myBspl->LocateU(myLast,  PosTol, Ideb, Ifin);
737       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
738       if (Ideb>=Ifin) Ideb = Ifin-1;
739     }
740     myBspl->LocalD1(theU, Ideb, Ifin, theP, theV); 
741     return;
742   }
743   else if (!myCurveCache.IsNull()) // use cached B-spline data
744   {
745     if (!myCurveCache->IsCacheValid(theU))
746       RebuildCache(theU);
747     myCurveCache->D1(theU, theP, theV);
748     return;
749   }
750   myCurve->D1(theU, theP, theV);
751 }
752
753 //=======================================================================
754 //function : D1Offset
755 //purpose  : Computes the point of parameter theU on the offset curve and its derivative
756 //=======================================================================
757 void Geom2dAdaptor_Curve::D1Offset(const Standard_Real theU, gp_Pnt2d& theP, gp_Vec2d& theV) const
758 {
759    // P(u) = p(u) + Offset * Ndir / R
760    // with R = || p' ^ Z|| and Ndir = P' ^ Z
761
762    // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
763
764   gp_Vec2d V2;
765   myOffsetBaseCurveAdaptor->D2 (theU, theP, theV, V2);
766
767   Standard_Boolean IsDirectionChange = Standard_False;
768   if(theV.SquareMagnitude() <= gp::Resolution())
769     IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 2, theU, theV, V2);
770
771   Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
772   CSLib_Offset::D1(theP, theV, V2, anOffset, IsDirectionChange, theP, theV);
773 }
774
775 //=======================================================================
776 //function : D2
777 //purpose  : 
778 //=======================================================================
779
780 void Geom2dAdaptor_Curve::D2(const Standard_Real U, 
781                              gp_Pnt2d& P, gp_Vec2d& V1, gp_Vec2d& V2) const 
782 {
783   if (myTypeCurve == GeomAbs_BSplineCurve)
784   {
785     D2BSpline(U, P, V1, V2);
786     return;
787   }
788   else if (myTypeCurve == GeomAbs_OffsetCurve)
789   {
790     D2Offset(U, P, V1, V2);
791     return;
792   }
793
794   myCurve->D2(U, P, V1, V2);
795 }
796
797 //=======================================================================
798 //function : D2BSpline
799 //purpose  : Computes the point of parameter theU on the B-spline curve and its first and second derivatives
800 //=======================================================================
801 void Geom2dAdaptor_Curve::D2BSpline(const Standard_Real theU, gp_Pnt2d& theP,
802                                     gp_Vec2d& theV1, gp_Vec2d& theV2) const
803 {
804   if (theU == myFirst || theU == myLast)
805   {
806     Standard_Integer Ideb = 0, Ifin = 0;
807     if (theU == myFirst) {
808       myBspl->LocateU(myFirst,  PosTol, Ideb, Ifin);
809       if (Ideb<1) Ideb=1;
810       if (Ideb>=Ifin) Ifin = Ideb+1;
811     }
812     if (theU == myLast) {
813       myBspl->LocateU(myLast,  PosTol, Ideb, Ifin);
814       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
815       if (Ideb>=Ifin) Ideb = Ifin-1;
816     }
817     myBspl->LocalD2(theU, Ideb, Ifin, theP, theV1, theV2);
818     return;
819   }
820   else if (!myCurveCache.IsNull()) // use cached B-spline data
821   {
822     if (!myCurveCache->IsCacheValid(theU))
823       RebuildCache(theU);
824     myCurveCache->D2(theU, theP, theV1, theV2);
825     return;
826   }
827   myCurve->D2(theU, theP, theV1, theV2);
828 }
829 //=======================================================================
830 //function : D2Offset
831 //purpose  : Computes the point of parameter theU on the offset curve and its first and second derivatives
832 //=======================================================================
833 void Geom2dAdaptor_Curve::D2Offset(const Standard_Real theU, gp_Pnt2d& theP,
834                                     gp_Vec2d& theV1, gp_Vec2d& theV2) const
835 {
836    // P(u) = p(u) + Offset * Ndir / R
837    // with R = || p' ^ Z|| and Ndir = P' ^ Z
838
839    // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
840
841    // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
842    //         Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
843
844   gp_Vec2d V3;
845   myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, V3);
846
847   Standard_Boolean IsDirectionChange = Standard_False;
848   if(theV1.SquareMagnitude() <= gp::Resolution())
849     IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 3, theU, theV1, theV2, V3);
850
851   Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
852   CSLib_Offset::D2(theP, theV1, theV2, V3, anOffset, IsDirectionChange, theP, theV1, theV2);
853 }
854
855 //=======================================================================
856 //function : D3
857 //purpose  : 
858 //=======================================================================
859
860 void Geom2dAdaptor_Curve::D3(const Standard_Real U, 
861                              gp_Pnt2d& P,  gp_Vec2d& V1, 
862                              gp_Vec2d& V2, gp_Vec2d& V3) const 
863 {
864   if (myTypeCurve == GeomAbs_BSplineCurve)
865   {
866     D3BSpline(U, P, V1, V2, V3);
867     return;
868   }
869   else if (myTypeCurve == GeomAbs_OffsetCurve)
870   {
871     D3Offset(U, P, V1, V2, V3);
872     return;
873   }
874
875   myCurve->D3(U, P, V1, V2, V3);
876 }
877
878 //=======================================================================
879 //function : D3BSpline
880 //purpose  : Computes the point of parameter theU on the B-spline curve and its 1st - 3rd derivatives
881 //=======================================================================
882 void Geom2dAdaptor_Curve::D3BSpline(const Standard_Real theU, gp_Pnt2d& theP,
883                                     gp_Vec2d& theV1, gp_Vec2d& theV2, gp_Vec2d& theV3) const
884 {
885   if (theU == myFirst || theU == myLast)
886   {
887     Standard_Integer Ideb = 0, Ifin = 0;
888     if (theU == myFirst) {
889       myBspl->LocateU(myFirst,  PosTol, Ideb, Ifin);
890       if (Ideb<1) Ideb=1;
891       if (Ideb>=Ifin) Ifin = Ideb+1;
892     }
893     if (theU == myLast) {
894       myBspl->LocateU(myLast,  PosTol, Ideb, Ifin);
895       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
896       if (Ideb>=Ifin) Ideb = Ifin-1;
897     }
898     myBspl->LocalD3(theU, Ideb, Ifin, theP, theV1, theV2, theV3);
899     return;
900   }
901   else if (!myCurveCache.IsNull()) // use cached B-spline data
902   {
903     if (!myCurveCache->IsCacheValid(theU))
904       RebuildCache(theU);
905     myCurveCache->D3(theU, theP, theV1, theV2, theV3);
906     return;
907   }
908   myCurve->D3(theU, theP, theV1, theV2, theV3);
909 }
910 //=======================================================================
911 //function : D3Offset
912 //purpose  : Computes the point of parameter theU on the offset curve and its 1st - 3rd derivatives
913 //=======================================================================
914 void Geom2dAdaptor_Curve::D3Offset(const Standard_Real theU, gp_Pnt2d& theP,
915                                     gp_Vec2d& theV1, gp_Vec2d& theV2, gp_Vec2d& theV3) const
916 {
917    // P(u) = p(u) + Offset * Ndir / R
918    // with R = || p' ^ Z|| and Ndir = P' ^ Z
919
920    // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R -  Ndir * (DR/R))
921
922    // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
923    //         Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
924
925    //P"'(u) = p"'(u) + (Offset / R) * (D3Ndir - (3.0 * Dr/R**2 ) * D2Ndir -
926    //         (3.0 * D2r / R2) * DNdir) + (3.0 * Dr * Dr / R4) * DNdir -
927    //         (D3r/R2) * Ndir + (6.0 * Dr * Dr / R4) * Ndir +
928    //         (6.0 * Dr * D2r / R4) * Ndir - (15.0 * Dr* Dr* Dr /R6) * Ndir
929
930   Standard_Boolean IsDirectionChange = Standard_False;
931
932   myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, theV3);
933   gp_Vec2d V4 = myOffsetBaseCurveAdaptor->DN (theU, 4);
934
935   if(theV1.SquareMagnitude() <= gp::Resolution())
936     IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 4, theU, theV1, theV2, theV3, V4);
937
938   Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
939   CSLib_Offset::D3(theP, theV1, theV2, theV3, V4, anOffset, IsDirectionChange,
940                    theP, theV1, theV2, theV3);
941 }
942
943 //=======================================================================
944 //function : DN
945 //purpose  : 
946 //=======================================================================
947
948 gp_Vec2d Geom2dAdaptor_Curve::DN(const Standard_Real U, 
949                                  const Standard_Integer N) const 
950 {
951   if (myTypeCurve == GeomAbs_BSplineCurve)
952     return DNBSpline(U, N);
953   else if (myTypeCurve == GeomAbs_OffsetCurve)
954     return DNOffset(U, N);
955
956   return myCurve->DN(U, N);
957 }
958
959 gp_Vec2d Geom2dAdaptor_Curve::DNBSpline(const Standard_Real U, 
960                                         const Standard_Integer N) const 
961 {
962   if (U==myFirst || U==myLast)
963   {
964     Standard_Integer Ideb = 0, Ifin = 0;
965     if (U==myFirst) {
966       myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
967       if (Ideb<1) Ideb=1;
968       if (Ideb>=Ifin) Ifin = Ideb+1;
969     }
970     if (U==myLast) {
971       myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
972       if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
973       if (Ideb>=Ifin) Ideb = Ifin-1;
974     } 
975     return myBspl->LocalDN( U, Ideb, Ifin, N);
976   }
977
978   return myCurve->DN( U, N);
979 }
980
981 gp_Vec2d Geom2dAdaptor_Curve::DNOffset(const Standard_Real    U,
982                                        const Standard_Integer N) const
983 {
984   gp_Pnt2d aPnt;
985   gp_Vec2d aVec, aVN;
986
987   switch (N)
988   {
989   case 1:
990     D1Offset(U, aPnt, aVN);
991     break;
992   case 2:
993     D2Offset(U, aPnt, aVec, aVN);
994     break;
995   case 3:
996     D3Offset(U, aPnt, aVec, aVec, aVN);
997     break;
998   default:
999     aVN = myCurve->DN(U, N);
1000   }
1001   return aVN;
1002 }
1003
1004 //=======================================================================
1005 //function : Resolution
1006 //purpose  : 
1007 //=======================================================================
1008
1009 Standard_Real Geom2dAdaptor_Curve::Resolution(const Standard_Real Ruv) const {
1010   switch ( myTypeCurve) {
1011   case GeomAbs_Line :
1012     return Ruv;
1013   case GeomAbs_Circle: {
1014     Standard_Real R = Handle(Geom2d_Circle)::DownCast (myCurve)->Circ2d().Radius();
1015     if ( R > Ruv/2.)
1016       return 2*ASin(Ruv/(2*R));
1017     else
1018       return 2*M_PI;
1019   }
1020   case GeomAbs_Ellipse: {
1021     return Ruv / Handle(Geom2d_Ellipse)::DownCast (myCurve)->MajorRadius();
1022   }
1023   case GeomAbs_BezierCurve: {
1024     Standard_Real res;
1025     Handle(Geom2d_BezierCurve)::DownCast (myCurve)->Resolution(Ruv,res);
1026     return res;
1027   }
1028   case GeomAbs_BSplineCurve: {
1029     Standard_Real res;
1030     Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->Resolution(Ruv,res);
1031     return res;
1032   }
1033   default:
1034     return Precision::Parametric(Ruv);
1035   }  
1036 }
1037
1038
1039 //    --
1040 //    --     The following methods must  be called when GetType returned
1041 //    --     the corresponding type.
1042 //    --     
1043
1044 //=======================================================================
1045 //function : Line
1046 //purpose  : 
1047 //=======================================================================
1048
1049 gp_Lin2d Geom2dAdaptor_Curve::Line() const 
1050 {
1051   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Line, "");
1052   return Handle(Geom2d_Line)::DownCast (myCurve)->Lin2d();
1053 }
1054
1055 //=======================================================================
1056 //function : Circle
1057 //purpose  : 
1058 //=======================================================================
1059
1060 gp_Circ2d  Geom2dAdaptor_Curve::Circle() const 
1061 {
1062   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Circle, "");
1063   return Handle(Geom2d_Circle)::DownCast (myCurve)->Circ2d();
1064 }
1065
1066 //=======================================================================
1067 //function : Ellipse
1068 //purpose  : 
1069 //=======================================================================
1070
1071 gp_Elips2d Geom2dAdaptor_Curve::Ellipse() const 
1072 {
1073   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Ellipse, "");
1074   return Handle(Geom2d_Ellipse)::DownCast (myCurve)->Elips2d();
1075 }
1076
1077 //=======================================================================
1078 //function : Hyperbola
1079 //purpose  : 
1080 //=======================================================================
1081
1082 gp_Hypr2d Geom2dAdaptor_Curve::Hyperbola() const 
1083 {
1084   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Hyperbola, "");
1085   return Handle(Geom2d_Hyperbola)::DownCast (myCurve)->Hypr2d();
1086 }
1087
1088 //=======================================================================
1089 //function : Parabola
1090 //purpose  : 
1091 //=======================================================================
1092
1093 gp_Parab2d Geom2dAdaptor_Curve::Parabola() const 
1094 {
1095   Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Parabola, "");
1096   return Handle(Geom2d_Parabola)::DownCast (myCurve)->Parab2d();
1097 }
1098
1099 //=======================================================================
1100 //function : Degree
1101 //purpose  : 
1102 //=======================================================================
1103
1104 Standard_Integer Geom2dAdaptor_Curve::Degree() const
1105 {
1106   if (myTypeCurve == GeomAbs_BezierCurve)
1107     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->Degree();
1108   else if (myTypeCurve == GeomAbs_BSplineCurve)
1109     return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->Degree();
1110   else
1111     Standard_NoSuchObject::Raise();
1112   // portage WNT 
1113   return 0;
1114 }
1115
1116 //=======================================================================
1117 //function : IsRational
1118 //purpose  : 
1119 //=======================================================================
1120
1121 Standard_Boolean Geom2dAdaptor_Curve::IsRational() const {
1122   switch( myTypeCurve) {
1123   case GeomAbs_BSplineCurve:
1124     return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->IsRational();
1125   case GeomAbs_BezierCurve:
1126     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->IsRational();
1127   default:
1128     return Standard_False;
1129   }
1130 }
1131
1132 //=======================================================================
1133 //function : NbPoles
1134 //purpose  : 
1135 //=======================================================================
1136
1137 Standard_Integer Geom2dAdaptor_Curve::NbPoles() const
1138 {
1139   if (myTypeCurve == GeomAbs_BezierCurve)
1140     return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->NbPoles();
1141   else if (myTypeCurve == GeomAbs_BSplineCurve)
1142     return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->NbPoles();
1143   else
1144     Standard_NoSuchObject::Raise();
1145   // portage WNT 
1146   return 0;
1147 }
1148
1149 //=======================================================================
1150 //function : NbKnots
1151 //purpose  : 
1152 //=======================================================================
1153
1154 Standard_Integer Geom2dAdaptor_Curve::NbKnots() const {
1155   if ( myTypeCurve != GeomAbs_BSplineCurve)
1156     Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::NbKnots");
1157   return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->NbKnots();
1158
1159 }
1160
1161 //=======================================================================
1162 //function : Bezier
1163 //purpose  : 
1164 //=======================================================================
1165
1166 Handle(Geom2d_BezierCurve) Geom2dAdaptor_Curve::Bezier() const 
1167 {
1168   return Handle(Geom2d_BezierCurve)::DownCast (myCurve);
1169 }
1170
1171 //=======================================================================
1172 //function : BSpline
1173 //purpose  : 
1174 //=======================================================================
1175
1176 Handle(Geom2d_BSplineCurve) Geom2dAdaptor_Curve::BSpline() const 
1177 {
1178   return Handle(Geom2d_BSplineCurve)::DownCast (myCurve);
1179 }
1180
1181 static Standard_Integer nbPoints(const Handle(Geom2d_Curve)& theCurve) 
1182 {
1183  
1184   Standard_Integer nbs = 10;
1185   
1186   if(theCurve->IsKind(STANDARD_TYPE( Geom2d_Line)) )
1187     nbs = 2;
1188   else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BezierCurve))) 
1189   {
1190     nbs = 3 + Handle(Geom2d_BezierCurve)::DownCast (theCurve)->NbPoles();
1191   }
1192   else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BSplineCurve))) { 
1193     nbs =  Handle(Geom2d_BSplineCurve)::DownCast (theCurve)->NbKnots();
1194     nbs*= Handle(Geom2d_BSplineCurve)::DownCast (theCurve)->Degree();
1195     if(nbs < 2.0) nbs=2;
1196   }
1197   else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
1198   {
1199     Handle(Geom2d_Curve) aCurve = Handle(Geom2d_OffsetCurve)::DownCast (theCurve)->BasisCurve();
1200     return Max(nbs, nbPoints(aCurve));
1201   }
1202
1203   else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
1204   {
1205     Handle(Geom2d_Curve) aCurve = Handle(Geom2d_TrimmedCurve)::DownCast (theCurve)->BasisCurve();
1206     return Max(nbs, nbPoints(aCurve));
1207   }
1208   if(nbs>300)
1209     nbs = 300;
1210   return nbs;
1211   
1212 }
1213
1214 Standard_Integer Geom2dAdaptor_Curve::NbSamples() const
1215 {
1216   return  nbPoints(myCurve);
1217 }
1218
1219
1220 // ============= Auxiliary functions ===================
1221 Standard_Boolean AdjustDerivative(const Handle(Adaptor2d_HCurve2d)& theAdaptor, Standard_Integer theMaxDerivative,
1222                                   Standard_Real theU, gp_Vec2d& theD1, gp_Vec2d& theD2,
1223                                   gp_Vec2d& theD3, gp_Vec2d& theD4)
1224 {
1225   static const Standard_Real aTol = gp::Resolution();
1226
1227   Standard_Boolean IsDirectionChange = Standard_False;
1228   const Standard_Real anUinfium   = theAdaptor->FirstParameter();
1229   const Standard_Real anUsupremum = theAdaptor->LastParameter();
1230
1231   const Standard_Real DivisionFactor = 1.e-3;
1232   Standard_Real du;
1233   if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst())) 
1234     du = 0.0;
1235   else
1236     du = anUsupremum - anUinfium;
1237
1238   const Standard_Real aDelta = Max(du * DivisionFactor, MinStep);
1239
1240   //Derivative is approximated by Taylor-series
1241   Standard_Integer anIndex = 1; //Derivative order
1242   gp_Vec2d V;
1243
1244   do
1245   {
1246     V =  theAdaptor->DN(theU, ++anIndex);
1247   }
1248   while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder);
1249
1250   Standard_Real u;
1251
1252   if(theU-anUinfium < aDelta)
1253     u = theU+aDelta;
1254   else
1255     u = theU-aDelta;
1256
1257   gp_Pnt2d P1, P2;
1258   theAdaptor->D0(Min(theU, u),P1);
1259   theAdaptor->D0(Max(theU, u),P2);
1260
1261   gp_Vec2d V1(P1, P2);
1262   IsDirectionChange = V.Dot(V1) < 0.0;
1263   Standard_Real aSign = IsDirectionChange ? -1.0 : 1.0;
1264
1265   theD1 = V * aSign;
1266   gp_Vec2d* aDeriv[3] = {&theD2, &theD3, &theD4};
1267   for (Standard_Integer i = 1; i < theMaxDerivative; i++)
1268     *(aDeriv[i-1]) = theAdaptor->DN(theU, anIndex + i) * aSign;
1269
1270   return IsDirectionChange;
1271 }