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
6 // This file is part of Open CASCADE Technology software library.
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.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
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
21 #define No_Standard_RangeError
22 #define No_Standard_OutOfRange
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>
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>
64 //#include <Geom2dConvert_BSplineCurveKnotSplitting.hxx>
65 static const Standard_Real PosTol = Precision::PConfusion() / 2;
67 static const Standard_Integer maxDerivOrder = 3;
68 static const Standard_Real MinStep = 1e-7;
70 static gp_Vec2d dummyDerivative; // used as empty value for unused derivatives in AdjustDerivative
72 // Recalculate derivatives in the singular point
73 // Returns true is the direction of derivatives is changed
74 static Standard_Boolean AdjustDerivative(const Handle(Adaptor2d_HCurve2d)& theAdaptor, Standard_Integer theMaxDerivative,
75 Standard_Real theU, gp_Vec2d& theD1, gp_Vec2d& theD2 = dummyDerivative,
76 gp_Vec2d& theD3 = dummyDerivative, gp_Vec2d& theD4 = dummyDerivative);
78 //=======================================================================
79 //function : LocalContinuity
80 //purpose : Computes the Continuity of a BSplineCurve
81 // between the parameters U1 and U2
82 // The continuity is C(d-m)
84 // m = max multiplicity of the Knots between U1 and U2
85 //=======================================================================
87 GeomAbs_Shape Geom2dAdaptor_Curve::LocalContinuity(const Standard_Real U1,
88 const Standard_Real U2)
91 Standard_NoSuchObject_Raise_if(myTypeCurve!=GeomAbs_BSplineCurve," ");
92 Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
93 Standard_Integer Nb = aBspl->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);
100 aBspl->Multiplicities(TM);
101 BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,U1,aBspl->IsPeriodic(),
102 1,Nb,Index1,newFirst);
103 BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,U2,aBspl->IsPeriodic(),
104 1,Nb,Index2,newLast);
105 if ( Abs(newFirst-TK(Index1+1))<Precision::PConfusion()) {
106 if (Index1 < Nb)Index1++;
108 if ( Abs(newLast-TK(Index2))<Precision::PConfusion())
110 Standard_Integer MultMax;
111 // attention aux courbes peridiques.
112 if ( (aBspl->IsPeriodic()) && (Index1 == Nb) )
115 if ( Index2 - Index1 <= 0) {
116 MultMax = 100; // CN entre 2 Noeuds consecutifs
119 MultMax = TM(Index1+1);
120 for(Standard_Integer i = Index1+1;i<=Index2;i++) {
121 if ( TM(i)>MultMax) MultMax=TM(i);
123 MultMax = aBspl->Degree() - MultMax;
128 else if ( MultMax == 1) {
131 else if ( MultMax == 2) {
134 else if ( MultMax == 3) {
143 //=======================================================================
144 //function : Geom2dAdaptor_Curve
146 //=======================================================================
148 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve()
149 : myTypeCurve(GeomAbs_OtherCurve),
155 //=======================================================================
156 //function : Geom2dAdaptor_Curve
158 //=======================================================================
160 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve(const Handle(Geom2d_Curve)& theCrv)
161 : myTypeCurve(GeomAbs_OtherCurve),
168 //=======================================================================
169 //function : Geom2dAdaptor_Curve
171 //=======================================================================
173 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve(const Handle(Geom2d_Curve)& theCrv,
174 const Standard_Real theUFirst,
175 const Standard_Real theULast)
176 : myTypeCurve(GeomAbs_OtherCurve),
180 Load(theCrv, theUFirst, theULast);
184 //=======================================================================
187 //=======================================================================
189 void Geom2dAdaptor_Curve::load(const Handle(Geom2d_Curve)& C,
190 const Standard_Real UFirst,
191 const Standard_Real ULast)
198 myCurveCache = Handle(BSplCLib_Cache)();
200 Handle(Standard_Type) TheType = C->DynamicType();
201 if ( TheType == STANDARD_TYPE(Geom2d_TrimmedCurve)) {
202 Load(Handle(Geom2d_TrimmedCurve)::DownCast (C)->BasisCurve(),
205 else if ( TheType == STANDARD_TYPE(Geom2d_Circle)) {
206 myTypeCurve = GeomAbs_Circle;
208 else if ( TheType ==STANDARD_TYPE(Geom2d_Line)) {
209 myTypeCurve = GeomAbs_Line;
211 else if ( TheType == STANDARD_TYPE(Geom2d_Ellipse)) {
212 myTypeCurve = GeomAbs_Ellipse;
214 else if ( TheType == STANDARD_TYPE(Geom2d_Parabola)) {
215 myTypeCurve = GeomAbs_Parabola;
217 else if ( TheType == STANDARD_TYPE(Geom2d_Hyperbola)) {
218 myTypeCurve = GeomAbs_Hyperbola;
220 else if ( TheType == STANDARD_TYPE(Geom2d_BezierCurve)) {
221 myTypeCurve = GeomAbs_BezierCurve;
222 // Create cache for Bezier
223 Handle(Geom2d_BezierCurve) aBezier = Handle(Geom2d_BezierCurve)::DownCast(myCurve);
224 Standard_Integer aDeg = aBezier->Degree();
225 TColStd_Array1OfReal aFlatKnots(BSplCLib::FlatBezierKnots(aDeg), 1, 2 * (aDeg + 1));
226 myCurveCache = new BSplCLib_Cache(aDeg, aBezier->IsPeriodic(), aFlatKnots,
227 aBezier->Poles(), aBezier->Weights());
229 else if ( TheType == STANDARD_TYPE(Geom2d_BSplineCurve)) {
230 myTypeCurve = GeomAbs_BSplineCurve;
231 // Create cache for B-spline
232 Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
233 myCurveCache = new BSplCLib_Cache(aBspl->Degree(), aBspl->IsPeriodic(),
234 aBspl->KnotSequence(), aBspl->Poles(), aBspl->Weights());
236 else if ( TheType == STANDARD_TYPE(Geom2d_OffsetCurve))
238 myTypeCurve = GeomAbs_OffsetCurve;
239 // Create nested adaptor for base curve
240 Handle(Geom2d_Curve) aBase = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->BasisCurve();
241 myOffsetBaseCurveAdaptor = new Geom2dAdaptor_HCurve(aBase);
244 myTypeCurve = GeomAbs_OtherCurve;
250 // -- Global methods - Apply to the whole curve.
253 //=======================================================================
254 //function : Continuity
256 //=======================================================================
258 GeomAbs_Shape Geom2dAdaptor_Curve::Continuity() const
260 if (myTypeCurve == GeomAbs_BSplineCurve) {
261 return LocalContinuity(myFirst, myLast);
263 else if (myTypeCurve == GeomAbs_OffsetCurve){
265 Handle(Geom2d_OffsetCurve)::DownCast (myCurve)->GetBasisCurveContinuity();
267 case GeomAbs_CN: return GeomAbs_CN;
268 case GeomAbs_C3: return GeomAbs_C2;
269 case GeomAbs_C2: return GeomAbs_C1;
270 case GeomAbs_C1: return GeomAbs_C0;
271 case GeomAbs_G1: return GeomAbs_G1;
272 case GeomAbs_G2: return GeomAbs_G2;
275 Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::Continuity");
279 else if (myTypeCurve == GeomAbs_OtherCurve) {
280 Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::Continuity");
290 //=======================================================================
291 //function : NbIntervals
293 //=======================================================================
295 Standard_Integer Geom2dAdaptor_Curve::NbIntervals(const GeomAbs_Shape S) const
297 Standard_Integer myNbIntervals = 1;
298 Standard_Integer NbSplit;
299 if (myTypeCurve == GeomAbs_BSplineCurve) {
300 Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
301 Standard_Integer FirstIndex = aBspl->FirstUKnotIndex();
302 Standard_Integer LastIndex = aBspl->LastUKnotIndex();
303 TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
304 if ( S > Continuity()) {
305 Standard_Integer Cont;
309 Standard_DomainError::Raise("Geom2dAdaptor_Curve::NbIntervals");
319 if ( S == GeomAbs_C1) Cont = 1;
320 else if ( S == GeomAbs_C2) Cont = 2;
321 else if ( S == GeomAbs_C3) Cont = 3;
322 else Cont = aBspl->Degree();
323 Standard_Integer Degree = aBspl->Degree();
324 Standard_Integer NbKnots = aBspl->NbKnots();
325 TColStd_Array1OfInteger Mults (1, NbKnots);
326 aBspl->Multiplicities (Mults);
328 Standard_Integer Index = FirstIndex;
329 Inter (NbSplit) = Index;
332 while (Index < LastIndex)
334 if (Degree - Mults (Index) < Cont)
336 Inter (NbSplit) = Index;
341 Inter (NbSplit) = Index;
343 Standard_Integer NbInt = NbSplit-1;
345 Standard_Integer Nb = aBspl->NbKnots();
346 Standard_Integer Index1 = 0;
347 Standard_Integer Index2 = 0;
348 Standard_Real newFirst, newLast;
349 TColStd_Array1OfReal TK(1,Nb);
350 TColStd_Array1OfInteger TM(1,Nb);
352 aBspl->Multiplicities(TM);
353 BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,myFirst,
355 1,Nb,Index1,newFirst);
356 BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,myLast,
358 1,Nb,Index2,newLast);
360 // On decale eventuellement les indices
361 // On utilise une "petite" tolerance, la resolution ne doit
362 // servir que pour les tres longue courbes....(PRO9248)
363 Standard_Real Eps = Min(Resolution(Precision::Confusion()),
364 Precision::PConfusion());
365 if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
366 if ( newLast-TK(Index2)> Eps) Index2++;
369 for ( Standard_Integer i=1; i<=NbInt; i++)
370 if (Inter(i)>Index1 && Inter(i)<Index2) myNbIntervals++;
376 else if (myTypeCurve == GeomAbs_OffsetCurve){
377 GeomAbs_Shape BaseS=GeomAbs_C0;
381 Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
383 case GeomAbs_C0: BaseS = GeomAbs_C1; break;
384 case GeomAbs_C1: BaseS = GeomAbs_C2; break;
385 case GeomAbs_C2: BaseS = GeomAbs_C3; break;
386 default: BaseS = GeomAbs_CN;
388 myNbIntervals = myOffsetBaseCurveAdaptor->NbIntervals(BaseS);
391 return myNbIntervals;
394 //=======================================================================
395 //function : Intervals
397 //=======================================================================
399 void Geom2dAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
400 const GeomAbs_Shape S ) const
402 Standard_Integer myNbIntervals = 1;
403 Standard_Integer NbSplit;
404 if (myTypeCurve == GeomAbs_BSplineCurve) {
405 Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
406 Standard_Integer FirstIndex = aBspl->FirstUKnotIndex();
407 Standard_Integer LastIndex = aBspl->LastUKnotIndex();
408 TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
409 if ( S > Continuity()) {
410 Standard_Integer Cont;
414 Standard_DomainError::Raise("Geom2dAdaptor_Curve::NbIntervals");
424 if ( S == GeomAbs_C1) Cont = 1;
425 else if ( S == GeomAbs_C2) Cont = 2;
426 else if ( S == GeomAbs_C3) Cont = 3;
427 else Cont = aBspl->Degree();
428 Standard_Integer Degree = aBspl->Degree();
429 Standard_Integer NbKnots = aBspl->NbKnots();
430 TColStd_Array1OfInteger Mults (1, NbKnots);
431 aBspl->Multiplicities (Mults);
433 Standard_Integer Index = FirstIndex;
434 Inter (NbSplit) = Index;
437 while (Index < LastIndex)
439 if (Degree - Mults (Index) < Cont)
441 Inter (NbSplit) = Index;
446 Inter (NbSplit) = Index;
447 Standard_Integer NbInt = NbSplit-1;
449 Standard_Integer Nb = aBspl->NbKnots();
450 Standard_Integer Index1 = 0;
451 Standard_Integer Index2 = 0;
452 Standard_Real newFirst, newLast;
453 TColStd_Array1OfReal TK(1,Nb);
454 TColStd_Array1OfInteger TM(1,Nb);
456 aBspl->Multiplicities(TM);
457 BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,myFirst,
459 1,Nb,Index1,newFirst);
460 BSplCLib::LocateParameter(aBspl->Degree(),TK,TM,myLast,
462 1,Nb,Index2,newLast);
465 // On decale eventuellement les indices
466 // On utilise une "petite" tolerance, la resolution ne doit
467 // servir que pour les tres longue courbes....(PRO9248)
468 Standard_Real Eps = Min(Resolution(Precision::Confusion()),
469 Precision::PConfusion());
470 if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
471 if ( newLast-TK(Index2)> Eps) Index2++;
475 for ( Standard_Integer i=1; i<=NbInt; i++) {
476 if (Inter(i) > Index1 && Inter(i)<Index2 ) {
478 Inter(myNbIntervals) = Inter(i);
481 Inter(myNbIntervals+1) = Index2;
483 Standard_Integer ii = T.Lower() - 1;
484 for (Standard_Integer I=1;I<=myNbIntervals+1;I++) {
485 T(ii + I) = TK(Inter(I));
492 else if (myTypeCurve == GeomAbs_OffsetCurve){
493 GeomAbs_Shape BaseS=GeomAbs_C0;
497 Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
499 case GeomAbs_C0: BaseS = GeomAbs_C1; break;
500 case GeomAbs_C1: BaseS = GeomAbs_C2; break;
501 case GeomAbs_C2: BaseS = GeomAbs_C3; break;
502 default: BaseS = GeomAbs_CN;
504 myNbIntervals = myOffsetBaseCurveAdaptor->NbIntervals(BaseS);
505 myOffsetBaseCurveAdaptor->Intervals(T, BaseS);
508 T( T.Lower() ) = myFirst;
509 T( T.Lower() + myNbIntervals ) = myLast;
512 //=======================================================================
515 //=======================================================================
517 Handle(Adaptor2d_HCurve2d) Geom2dAdaptor_Curve::Trim
518 (const Standard_Real First,
519 const Standard_Real Last,
520 // const Standard_Real Tol) const
521 const Standard_Real ) const
523 Handle(Geom2dAdaptor_HCurve) HE = new Geom2dAdaptor_HCurve(myCurve,First,Last);
528 //=======================================================================
529 //function : IsClosed
531 //=======================================================================
533 Standard_Boolean Geom2dAdaptor_Curve::IsClosed() const
535 if (!Precision::IsPositiveInfinite(myLast) &&
536 !Precision::IsNegativeInfinite(myFirst)) {
537 gp_Pnt2d Pd = Value(myFirst);
538 gp_Pnt2d Pf = Value(myLast);
539 return ( Pd.Distance(Pf) <= Precision::Confusion());
542 return Standard_False;
545 //=======================================================================
546 //function : IsPeriodic
548 //=======================================================================
550 Standard_Boolean Geom2dAdaptor_Curve::IsPeriodic() const
552 if (myCurve->IsPeriodic())
555 return Standard_False;
558 //=======================================================================
561 //=======================================================================
563 Standard_Real Geom2dAdaptor_Curve::Period() const
565 return myCurve->LastParameter() - myCurve->FirstParameter();
568 //=======================================================================
569 //function : RebuildCache
571 //=======================================================================
572 void Geom2dAdaptor_Curve::RebuildCache(const Standard_Real theParameter) const
574 if (myTypeCurve == GeomAbs_BezierCurve)
576 Handle(Geom2d_BezierCurve) aBezier = Handle(Geom2d_BezierCurve)::DownCast(myCurve);
577 Standard_Integer aDeg = aBezier->Degree();
578 TColStd_Array1OfReal aFlatKnots(BSplCLib::FlatBezierKnots(aDeg), 1, 2 * (aDeg + 1));
579 myCurveCache->BuildCache(theParameter, aDeg, aBezier->IsPeriodic(), aFlatKnots,
580 aBezier->Poles(), aBezier->Weights());
582 else if (myTypeCurve == GeomAbs_BSplineCurve)
584 Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
585 myCurveCache->BuildCache(theParameter, aBspl->Degree(),
586 aBspl->IsPeriodic(), aBspl->KnotSequence(),
587 aBspl->Poles(), aBspl->Weights());
591 //=======================================================================
594 //=======================================================================
596 gp_Pnt2d Geom2dAdaptor_Curve::Value(const Standard_Real U) const
598 if (myTypeCurve == GeomAbs_BSplineCurve)
599 return ValueBSpline(U);
600 else if (myTypeCurve == GeomAbs_OffsetCurve)
601 return ValueOffset(U);
602 else if (myTypeCurve == GeomAbs_BezierCurve)
605 myCurveCache->D0(U, aRes);
609 return myCurve->Value(U);
612 //=======================================================================
613 //function : ValueBSpline
614 //purpose : Computes the point of parameter U on the B-spline curve
615 //=======================================================================
616 gp_Pnt2d Geom2dAdaptor_Curve::ValueBSpline(const Standard_Real theU) const
618 if (theU == myFirst || theU == myLast)
620 Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
621 Standard_Integer Ideb = 0, Ifin = 0;
624 aBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
626 if (Ideb>=Ifin) Ifin = Ideb+1;
630 aBspl->LocateU(myLast, PosTol, Ideb, Ifin);
631 if (Ifin > aBspl->NbKnots()) Ifin = aBspl->NbKnots();
632 if (Ideb>=Ifin) Ideb = Ifin-1;
634 return aBspl->LocalValue(theU, Ideb, Ifin);
636 else if (!myCurveCache.IsNull()) // use cached B-spline data
638 if (!myCurveCache->IsCacheValid(theU))
641 myCurveCache->D0(theU, aRes);
644 return myCurve->Value(theU);
647 //=======================================================================
648 //function : ValueOffset
649 //purpose : Computes the point of parameter U on the offset curve
650 //=======================================================================
651 gp_Pnt2d Geom2dAdaptor_Curve::ValueOffset(const Standard_Real theU) const
655 myOffsetBaseCurveAdaptor->D1(theU, aP, aD1);
656 Standard_Boolean isDirectionChange = Standard_False;
657 const Standard_Real aTol = gp::Resolution();
658 if(aD1.SquareMagnitude() <= aTol)
659 isDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 1, theU, aD1);
661 Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
662 CSLib_Offset::D0(aP, aD1, anOffset, isDirectionChange, aP);
666 //=======================================================================
669 //=======================================================================
671 void Geom2dAdaptor_Curve::D0(const Standard_Real U, gp_Pnt2d& P) const
673 if (myTypeCurve == GeomAbs_BSplineCurve)
675 else if (myTypeCurve == GeomAbs_OffsetCurve)
677 else if (myTypeCurve == GeomAbs_BezierCurve) // use cached data
678 myCurveCache->D0(U, P);
683 //=======================================================================
684 //function : D0BSpline
685 //purpose : Computes the point of parameter theU on the B-spline curve
686 //=======================================================================
687 void Geom2dAdaptor_Curve::D0BSpline(const Standard_Real theU, gp_Pnt2d& theP) const
689 if (theU == myFirst || theU == myLast)
691 Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
692 Standard_Integer Ideb = 0, Ifin = 0;
693 if (theU == myFirst) {
694 aBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
696 if (Ideb>=Ifin) Ifin = Ideb+1;
698 if (theU == myLast) {
699 aBspl->LocateU(myLast, PosTol, Ideb, Ifin);
700 if (Ifin > aBspl->NbKnots()) Ifin = aBspl->NbKnots();
701 if (Ideb>=Ifin) Ideb = Ifin-1;
703 aBspl->LocalD0(theU, Ideb, Ifin, theP);
706 else if (!myCurveCache.IsNull()) // use cached B-spline data
708 if (!myCurveCache->IsCacheValid(theU))
710 myCurveCache->D0(theU, theP);
713 myCurve->D0(theU, theP);
716 //=======================================================================
717 //function : D0Offset
718 //purpose : Computes the point of parameter theU on the offset curve
719 //=======================================================================
720 void Geom2dAdaptor_Curve::D0Offset(const Standard_Real theU, gp_Pnt2d& theP) const
722 theP = ValueOffset(theU);
725 //=======================================================================
728 //=======================================================================
730 void Geom2dAdaptor_Curve::D1(const Standard_Real U,
731 gp_Pnt2d& P, gp_Vec2d& V) const
733 if (myTypeCurve == GeomAbs_BSplineCurve)
735 else if (myTypeCurve == GeomAbs_OffsetCurve)
737 else if (myTypeCurve == GeomAbs_BezierCurve) // use cached data
738 myCurveCache->D1(U, P, V);
740 myCurve->D1(U, P, V);
743 //=======================================================================
744 //function : D1BSpline
745 //purpose : Computes the point of parameter theU on the B-spline curve and its derivative
746 //=======================================================================
747 void Geom2dAdaptor_Curve::D1BSpline(const Standard_Real theU, gp_Pnt2d& theP, gp_Vec2d& theV) const
749 if (theU == myFirst || theU == myLast)
751 Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
752 Standard_Integer Ideb = 0, Ifin = 0;
753 if (theU == myFirst) {
754 aBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
756 if (Ideb>=Ifin) Ifin = Ideb+1;
758 if (theU == myLast) {
759 aBspl->LocateU(myLast, PosTol, Ideb, Ifin);
760 if (Ifin > aBspl->NbKnots()) Ifin = aBspl->NbKnots();
761 if (Ideb>=Ifin) Ideb = Ifin-1;
763 aBspl->LocalD1(theU, Ideb, Ifin, theP, theV);
766 else if (!myCurveCache.IsNull()) // use cached B-spline data
768 if (!myCurveCache->IsCacheValid(theU))
770 myCurveCache->D1(theU, theP, theV);
773 myCurve->D1(theU, theP, theV);
776 //=======================================================================
777 //function : D1Offset
778 //purpose : Computes the point of parameter theU on the offset curve and its derivative
779 //=======================================================================
780 void Geom2dAdaptor_Curve::D1Offset(const Standard_Real theU, gp_Pnt2d& theP, gp_Vec2d& theV) const
782 // P(u) = p(u) + Offset * Ndir / R
783 // with R = || p' ^ Z|| and Ndir = P' ^ Z
785 // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R))
788 myOffsetBaseCurveAdaptor->D2 (theU, theP, theV, V2);
790 Standard_Boolean IsDirectionChange = Standard_False;
791 if(theV.SquareMagnitude() <= gp::Resolution())
792 IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 2, theU, theV, V2);
794 Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
795 CSLib_Offset::D1(theP, theV, V2, anOffset, IsDirectionChange, theP, theV);
798 //=======================================================================
801 //=======================================================================
803 void Geom2dAdaptor_Curve::D2(const Standard_Real U,
804 gp_Pnt2d& P, gp_Vec2d& V1, gp_Vec2d& V2) const
806 if (myTypeCurve == GeomAbs_BSplineCurve)
807 D2BSpline(U, P, V1, V2);
808 else if (myTypeCurve == GeomAbs_OffsetCurve)
809 D2Offset(U, P, V1, V2);
810 else if (myTypeCurve == GeomAbs_BezierCurve) // use cached data
811 myCurveCache->D2(U, P, V1, V2);
813 myCurve->D2(U, P, V1, V2);
816 //=======================================================================
817 //function : D2BSpline
818 //purpose : Computes the point of parameter theU on the B-spline curve and its first and second derivatives
819 //=======================================================================
820 void Geom2dAdaptor_Curve::D2BSpline(const Standard_Real theU, gp_Pnt2d& theP,
821 gp_Vec2d& theV1, gp_Vec2d& theV2) const
823 if (theU == myFirst || theU == myLast)
825 Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
826 Standard_Integer Ideb = 0, Ifin = 0;
827 if (theU == myFirst) {
828 aBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
830 if (Ideb>=Ifin) Ifin = Ideb+1;
832 if (theU == myLast) {
833 aBspl->LocateU(myLast, PosTol, Ideb, Ifin);
834 if (Ifin > aBspl->NbKnots()) Ifin = aBspl->NbKnots();
835 if (Ideb>=Ifin) Ideb = Ifin-1;
837 aBspl->LocalD2(theU, Ideb, Ifin, theP, theV1, theV2);
840 else if (!myCurveCache.IsNull()) // use cached B-spline data
842 if (!myCurveCache->IsCacheValid(theU))
844 myCurveCache->D2(theU, theP, theV1, theV2);
847 myCurve->D2(theU, theP, theV1, theV2);
849 //=======================================================================
850 //function : D2Offset
851 //purpose : Computes the point of parameter theU on the offset curve and its first and second derivatives
852 //=======================================================================
853 void Geom2dAdaptor_Curve::D2Offset(const Standard_Real theU, gp_Pnt2d& theP,
854 gp_Vec2d& theV1, gp_Vec2d& theV2) const
856 // P(u) = p(u) + Offset * Ndir / R
857 // with R = || p' ^ Z|| and Ndir = P' ^ Z
859 // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R))
861 // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
862 // Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
865 myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, V3);
867 Standard_Boolean IsDirectionChange = Standard_False;
868 if(theV1.SquareMagnitude() <= gp::Resolution())
869 IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 3, theU, theV1, theV2, V3);
871 Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
872 CSLib_Offset::D2(theP, theV1, theV2, V3, anOffset, IsDirectionChange, theP, theV1, theV2);
875 //=======================================================================
878 //=======================================================================
880 void Geom2dAdaptor_Curve::D3(const Standard_Real U,
881 gp_Pnt2d& P, gp_Vec2d& V1,
882 gp_Vec2d& V2, gp_Vec2d& V3) const
884 if (myTypeCurve == GeomAbs_BSplineCurve)
885 D3BSpline(U, P, V1, V2, V3);
886 else if (myTypeCurve == GeomAbs_OffsetCurve)
887 D3Offset(U, P, V1, V2, V3);
888 else if (myTypeCurve == GeomAbs_BezierCurve) // use cached data
889 myCurveCache->D3(U, P, V1, V2, V3);
891 myCurve->D3(U, P, V1, V2, V3);
894 //=======================================================================
895 //function : D3BSpline
896 //purpose : Computes the point of parameter theU on the B-spline curve and its 1st - 3rd derivatives
897 //=======================================================================
898 void Geom2dAdaptor_Curve::D3BSpline(const Standard_Real theU, gp_Pnt2d& theP,
899 gp_Vec2d& theV1, gp_Vec2d& theV2, gp_Vec2d& theV3) const
901 if (theU == myFirst || theU == myLast)
903 Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
904 Standard_Integer Ideb = 0, Ifin = 0;
905 if (theU == myFirst) {
906 aBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
908 if (Ideb>=Ifin) Ifin = Ideb+1;
910 if (theU == myLast) {
911 aBspl->LocateU(myLast, PosTol, Ideb, Ifin);
912 if (Ifin > aBspl->NbKnots()) Ifin = aBspl->NbKnots();
913 if (Ideb>=Ifin) Ideb = Ifin-1;
915 aBspl->LocalD3(theU, Ideb, Ifin, theP, theV1, theV2, theV3);
918 else if (!myCurveCache.IsNull()) // use cached B-spline data
920 if (!myCurveCache->IsCacheValid(theU))
922 myCurveCache->D3(theU, theP, theV1, theV2, theV3);
925 myCurve->D3(theU, theP, theV1, theV2, theV3);
927 //=======================================================================
928 //function : D3Offset
929 //purpose : Computes the point of parameter theU on the offset curve and its 1st - 3rd derivatives
930 //=======================================================================
931 void Geom2dAdaptor_Curve::D3Offset(const Standard_Real theU, gp_Pnt2d& theP,
932 gp_Vec2d& theV1, gp_Vec2d& theV2, gp_Vec2d& theV3) const
934 // P(u) = p(u) + Offset * Ndir / R
935 // with R = || p' ^ Z|| and Ndir = P' ^ Z
937 // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R))
939 // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
940 // Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
942 //P"'(u) = p"'(u) + (Offset / R) * (D3Ndir - (3.0 * Dr/R**2 ) * D2Ndir -
943 // (3.0 * D2r / R2) * DNdir) + (3.0 * Dr * Dr / R4) * DNdir -
944 // (D3r/R2) * Ndir + (6.0 * Dr * Dr / R4) * Ndir +
945 // (6.0 * Dr * D2r / R4) * Ndir - (15.0 * Dr* Dr* Dr /R6) * Ndir
947 Standard_Boolean IsDirectionChange = Standard_False;
949 myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, theV3);
950 gp_Vec2d V4 = myOffsetBaseCurveAdaptor->DN (theU, 4);
952 if(theV1.SquareMagnitude() <= gp::Resolution())
953 IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 4, theU, theV1, theV2, theV3, V4);
955 Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
956 CSLib_Offset::D3(theP, theV1, theV2, theV3, V4, anOffset, IsDirectionChange,
957 theP, theV1, theV2, theV3);
960 //=======================================================================
963 //=======================================================================
965 gp_Vec2d Geom2dAdaptor_Curve::DN(const Standard_Real U,
966 const Standard_Integer N) const
968 if (myTypeCurve == GeomAbs_BSplineCurve)
969 return DNBSpline(U, N);
970 else if (myTypeCurve == GeomAbs_OffsetCurve)
971 return DNOffset(U, N);
973 return myCurve->DN(U, N);
976 gp_Vec2d Geom2dAdaptor_Curve::DNBSpline(const Standard_Real U,
977 const Standard_Integer N) const
979 if (U==myFirst || U==myLast)
981 Handle(Geom2d_BSplineCurve) aBspl = Handle(Geom2d_BSplineCurve)::DownCast(myCurve);
982 Standard_Integer Ideb = 0, Ifin = 0;
984 aBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
986 if (Ideb>=Ifin) Ifin = Ideb+1;
989 aBspl->LocateU(myLast, PosTol, Ideb, Ifin);
990 if (Ifin > aBspl->NbKnots()) Ifin = aBspl->NbKnots();
991 if (Ideb>=Ifin) Ideb = Ifin-1;
993 return aBspl->LocalDN( U, Ideb, Ifin, N);
996 return myCurve->DN( U, N);
999 gp_Vec2d Geom2dAdaptor_Curve::DNOffset(const Standard_Real U,
1000 const Standard_Integer N) const
1008 D1Offset(U, aPnt, aVN);
1011 D2Offset(U, aPnt, aVec, aVN);
1014 D3Offset(U, aPnt, aVec, aVec, aVN);
1017 aVN = myCurve->DN(U, N);
1022 //=======================================================================
1023 //function : Resolution
1025 //=======================================================================
1027 Standard_Real Geom2dAdaptor_Curve::Resolution(const Standard_Real Ruv) const {
1028 switch ( myTypeCurve) {
1031 case GeomAbs_Circle: {
1032 Standard_Real R = Handle(Geom2d_Circle)::DownCast (myCurve)->Circ2d().Radius();
1034 return 2*ASin(Ruv/(2*R));
1038 case GeomAbs_Ellipse: {
1039 return Ruv / Handle(Geom2d_Ellipse)::DownCast (myCurve)->MajorRadius();
1041 case GeomAbs_BezierCurve: {
1043 Handle(Geom2d_BezierCurve)::DownCast (myCurve)->Resolution(Ruv,res);
1046 case GeomAbs_BSplineCurve: {
1048 Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->Resolution(Ruv,res);
1052 return Precision::Parametric(Ruv);
1058 // -- The following methods must be called when GetType returned
1059 // -- the corresponding type.
1062 //=======================================================================
1065 //=======================================================================
1067 gp_Lin2d Geom2dAdaptor_Curve::Line() const
1069 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Line, "");
1070 return Handle(Geom2d_Line)::DownCast (myCurve)->Lin2d();
1073 //=======================================================================
1076 //=======================================================================
1078 gp_Circ2d Geom2dAdaptor_Curve::Circle() const
1080 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Circle, "");
1081 return Handle(Geom2d_Circle)::DownCast (myCurve)->Circ2d();
1084 //=======================================================================
1085 //function : Ellipse
1087 //=======================================================================
1089 gp_Elips2d Geom2dAdaptor_Curve::Ellipse() const
1091 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Ellipse, "");
1092 return Handle(Geom2d_Ellipse)::DownCast (myCurve)->Elips2d();
1095 //=======================================================================
1096 //function : Hyperbola
1098 //=======================================================================
1100 gp_Hypr2d Geom2dAdaptor_Curve::Hyperbola() const
1102 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Hyperbola, "");
1103 return Handle(Geom2d_Hyperbola)::DownCast (myCurve)->Hypr2d();
1106 //=======================================================================
1107 //function : Parabola
1109 //=======================================================================
1111 gp_Parab2d Geom2dAdaptor_Curve::Parabola() const
1113 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Parabola, "");
1114 return Handle(Geom2d_Parabola)::DownCast (myCurve)->Parab2d();
1117 //=======================================================================
1120 //=======================================================================
1122 Standard_Integer Geom2dAdaptor_Curve::Degree() const
1124 if (myTypeCurve == GeomAbs_BezierCurve)
1125 return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->Degree();
1126 else if (myTypeCurve == GeomAbs_BSplineCurve)
1127 return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->Degree();
1129 Standard_NoSuchObject::Raise();
1134 //=======================================================================
1135 //function : IsRational
1137 //=======================================================================
1139 Standard_Boolean Geom2dAdaptor_Curve::IsRational() const {
1140 switch( myTypeCurve) {
1141 case GeomAbs_BSplineCurve:
1142 return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->IsRational();
1143 case GeomAbs_BezierCurve:
1144 return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->IsRational();
1146 return Standard_False;
1150 //=======================================================================
1151 //function : NbPoles
1153 //=======================================================================
1155 Standard_Integer Geom2dAdaptor_Curve::NbPoles() const
1157 if (myTypeCurve == GeomAbs_BezierCurve)
1158 return Handle(Geom2d_BezierCurve)::DownCast (myCurve)->NbPoles();
1159 else if (myTypeCurve == GeomAbs_BSplineCurve)
1160 return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->NbPoles();
1162 Standard_NoSuchObject::Raise();
1167 //=======================================================================
1168 //function : NbKnots
1170 //=======================================================================
1172 Standard_Integer Geom2dAdaptor_Curve::NbKnots() const {
1173 if ( myTypeCurve != GeomAbs_BSplineCurve)
1174 Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::NbKnots");
1175 return Handle(Geom2d_BSplineCurve)::DownCast (myCurve)->NbKnots();
1179 //=======================================================================
1182 //=======================================================================
1184 Handle(Geom2d_BezierCurve) Geom2dAdaptor_Curve::Bezier() const
1186 return Handle(Geom2d_BezierCurve)::DownCast (myCurve);
1189 //=======================================================================
1190 //function : BSpline
1192 //=======================================================================
1194 Handle(Geom2d_BSplineCurve) Geom2dAdaptor_Curve::BSpline() const
1196 return Handle(Geom2d_BSplineCurve)::DownCast (myCurve);
1199 static Standard_Integer nbPoints(const Handle(Geom2d_Curve)& theCurve)
1202 Standard_Integer nbs = 10;
1204 if(theCurve->IsKind(STANDARD_TYPE( Geom2d_Line)) )
1206 else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BezierCurve)))
1208 nbs = 3 + Handle(Geom2d_BezierCurve)::DownCast (theCurve)->NbPoles();
1210 else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BSplineCurve))) {
1211 nbs = Handle(Geom2d_BSplineCurve)::DownCast (theCurve)->NbKnots();
1212 nbs*= Handle(Geom2d_BSplineCurve)::DownCast (theCurve)->Degree();
1213 if(nbs < 2.0) nbs=2;
1215 else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
1217 Handle(Geom2d_Curve) aCurve = Handle(Geom2d_OffsetCurve)::DownCast (theCurve)->BasisCurve();
1218 return Max(nbs, nbPoints(aCurve));
1221 else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
1223 Handle(Geom2d_Curve) aCurve = Handle(Geom2d_TrimmedCurve)::DownCast (theCurve)->BasisCurve();
1224 return Max(nbs, nbPoints(aCurve));
1232 Standard_Integer Geom2dAdaptor_Curve::NbSamples() const
1234 return nbPoints(myCurve);
1238 // ============= Auxiliary functions ===================
1239 Standard_Boolean AdjustDerivative(const Handle(Adaptor2d_HCurve2d)& theAdaptor, Standard_Integer theMaxDerivative,
1240 Standard_Real theU, gp_Vec2d& theD1, gp_Vec2d& theD2,
1241 gp_Vec2d& theD3, gp_Vec2d& theD4)
1243 static const Standard_Real aTol = gp::Resolution();
1245 Standard_Boolean IsDirectionChange = Standard_False;
1246 const Standard_Real anUinfium = theAdaptor->FirstParameter();
1247 const Standard_Real anUsupremum = theAdaptor->LastParameter();
1249 const Standard_Real DivisionFactor = 1.e-3;
1251 if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst()))
1254 du = anUsupremum - anUinfium;
1256 const Standard_Real aDelta = Max(du * DivisionFactor, MinStep);
1258 //Derivative is approximated by Taylor-series
1259 Standard_Integer anIndex = 1; //Derivative order
1264 V = theAdaptor->DN(theU, ++anIndex);
1266 while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder);
1270 if(theU-anUinfium < aDelta)
1276 theAdaptor->D0(Min(theU, u),P1);
1277 theAdaptor->D0(Max(theU, u),P2);
1279 gp_Vec2d V1(P1, P2);
1280 IsDirectionChange = V.Dot(V1) < 0.0;
1281 Standard_Real aSign = IsDirectionChange ? -1.0 : 1.0;
1284 gp_Vec2d* aDeriv[3] = {&theD2, &theD3, &theD4};
1285 for (Standard_Integer i = 1; i < theMaxDerivative; i++)
1286 *(aDeriv[i-1]) = theAdaptor->DN(theU, anIndex + i) * aSign;
1288 return IsDirectionChange;