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
24 #include <Geom2dAdaptor_Curve.ixx>
25 #include <Geom2d_OffsetCurve.hxx>
26 #include <Geom2dAdaptor_HCurve.hxx>
27 #include <Adaptor2d_HCurve2d.hxx>
28 #include <BSplCLib.hxx>
29 #include <BSplCLib_Cache.hxx>
30 #include <GeomAbs_Shape.hxx>
31 #include <TColgp_Array1OfPnt2d.hxx>
32 #include <TColStd_Array1OfReal.hxx>
33 #include <TColStd_Array1OfInteger.hxx>
34 #include <TColStd_HArray1OfInteger.hxx>
35 #include <Precision.hxx>
37 #include <Geom2d_TrimmedCurve.hxx>
38 #include <Geom2d_Circle.hxx>
39 #include <Geom2d_Line.hxx>
40 #include <Geom2d_TrimmedCurve.hxx>
41 #include <Geom2d_BezierCurve.hxx>
42 #include <Geom2d_BSplineCurve.hxx>
43 #include <Geom2d_Ellipse.hxx>
44 #include <Geom2d_Parabola.hxx>
45 #include <Geom2d_Hyperbola.hxx>
46 #include <Geom2d_UndefinedValue.hxx>
47 #include <Geom2d_UndefinedDerivative.hxx>
48 #include <CSLib_Offset.hxx>
49 //#include <Geom2dConvert_BSplineCurveKnotSplitting.hxx>
51 #include <Standard_OutOfRange.hxx>
52 #include <Standard_NoSuchObject.hxx>
53 #include <Standard_NullObject.hxx>
54 #include <Standard_NotImplemented.hxx>
56 #define myBspl (*((Handle(Geom2d_BSplineCurve)*)&myCurve))
57 #define PosTol Precision::PConfusion()/2
59 static const int maxDerivOrder = 3;
60 static const Standard_Real MinStep = 1e-7;
62 static gp_Vec2d dummyDerivative; // used as empty value for unused derivatives in AdjustDerivative
64 // Recalculate derivatives in the singular point
65 // Returns true is the direction of derivatives is changed
66 static Standard_Boolean AdjustDerivative(const Handle(Adaptor2d_HCurve2d)& theAdaptor, Standard_Integer theMaxDerivative,
67 Standard_Real theU, gp_Vec2d& theD1, gp_Vec2d& theD2 = dummyDerivative,
68 gp_Vec2d& theD3 = dummyDerivative, gp_Vec2d& theD4 = dummyDerivative);
70 //=======================================================================
71 //function : LocalContinuity
72 //purpose : Computes the Continuity of a BSplineCurve
73 // between the parameters U1 and U2
74 // The continuity is C(d-m)
76 // m = max multiplicity of the Knots between U1 and U2
77 //=======================================================================
79 GeomAbs_Shape Geom2dAdaptor_Curve::LocalContinuity(const Standard_Real U1,
80 const Standard_Real U2)
83 Standard_NoSuchObject_Raise_if(myTypeCurve!=GeomAbs_BSplineCurve," ");
84 Standard_Integer Nb = myBspl->NbKnots();
85 Standard_Integer Index1 = 0;
86 Standard_Integer Index2 = 0;
87 Standard_Real newFirst, newLast;
88 TColStd_Array1OfReal TK(1,Nb);
89 TColStd_Array1OfInteger TM(1,Nb);
91 myBspl->Multiplicities(TM);
92 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,U1,myBspl->IsPeriodic(),
93 1,Nb,Index1,newFirst);
94 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,U2,myBspl->IsPeriodic(),
96 if ( Abs(newFirst-TK(Index1+1))<Precision::PConfusion()) {
97 if (Index1 < Nb)Index1++;
99 if ( Abs(newLast-TK(Index2))<Precision::PConfusion())
101 Standard_Integer MultMax;
102 // attention aux courbes peridiques.
103 if ( (myBspl->IsPeriodic()) && (Index1 == Nb) )
106 if ( Index2 - Index1 <= 0) {
107 MultMax = 100; // CN entre 2 Noeuds consecutifs
110 MultMax = TM(Index1+1);
111 for(Standard_Integer i = Index1+1;i<=Index2;i++) {
112 if ( TM(i)>MultMax) MultMax=TM(i);
114 MultMax = myBspl->Degree() - MultMax;
119 else if ( MultMax == 1) {
122 else if ( MultMax == 2) {
125 else if ( MultMax == 3) {
134 //=======================================================================
135 //function : Geom2dAdaptor_Curve
137 //=======================================================================
139 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve()
140 : myTypeCurve(GeomAbs_OtherCurve),
146 //=======================================================================
147 //function : Geom2dAdaptor_Curve
149 //=======================================================================
151 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve(const Handle(Geom2d_Curve)& theCrv)
152 : myTypeCurve(GeomAbs_OtherCurve),
159 //=======================================================================
160 //function : Geom2dAdaptor_Curve
162 //=======================================================================
164 Geom2dAdaptor_Curve::Geom2dAdaptor_Curve(const Handle(Geom2d_Curve)& theCrv,
165 const Standard_Real theUFirst,
166 const Standard_Real theULast)
167 : myTypeCurve(GeomAbs_OtherCurve),
171 Load(theCrv, theUFirst, theULast);
175 //=======================================================================
178 //=======================================================================
180 void Geom2dAdaptor_Curve::load(const Handle(Geom2d_Curve)& C,
181 const Standard_Real UFirst,
182 const Standard_Real ULast)
190 Handle(Standard_Type) TheType = C->DynamicType();
191 if ( TheType == STANDARD_TYPE(Geom2d_TrimmedCurve)) {
192 Load((*((Handle(Geom2d_TrimmedCurve)*)&C))->BasisCurve(),
195 else if ( TheType == STANDARD_TYPE(Geom2d_Circle)) {
196 myTypeCurve = GeomAbs_Circle;
198 else if ( TheType ==STANDARD_TYPE(Geom2d_Line)) {
199 myTypeCurve = GeomAbs_Line;
201 else if ( TheType == STANDARD_TYPE(Geom2d_Ellipse)) {
202 myTypeCurve = GeomAbs_Ellipse;
204 else if ( TheType == STANDARD_TYPE(Geom2d_Parabola)) {
205 myTypeCurve = GeomAbs_Parabola;
207 else if ( TheType == STANDARD_TYPE(Geom2d_Hyperbola)) {
208 myTypeCurve = GeomAbs_Hyperbola;
210 else if ( TheType == STANDARD_TYPE(Geom2d_BezierCurve)) {
211 myTypeCurve = GeomAbs_BezierCurve;
213 else if ( TheType == STANDARD_TYPE(Geom2d_BSplineCurve)) {
214 myTypeCurve = GeomAbs_BSplineCurve;
215 // Create cache for B-spline
216 myCurveCache = new BSplCLib_Cache(myBspl->Degree(), myBspl->IsPeriodic(),
217 myBspl->KnotSequence(), myBspl->Poles(), myBspl->Weights());
219 else if ( TheType == STANDARD_TYPE(Geom2d_OffsetCurve))
221 myTypeCurve = GeomAbs_OtherCurve;
222 // Create nested adaptor for base curve
223 Handle(Geom2d_Curve) aBase = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->BasisCurve();
224 myOffsetBaseCurveAdaptor = new Geom2dAdaptor_HCurve(aBase);
227 myTypeCurve = GeomAbs_OtherCurve;
233 // -- Global methods - Apply to the whole curve.
236 //=======================================================================
237 //function : Continuity
239 //=======================================================================
241 GeomAbs_Shape Geom2dAdaptor_Curve::Continuity() const
243 if (myTypeCurve == GeomAbs_BSplineCurve) {
244 return LocalContinuity(myFirst, myLast);
246 else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve)){
248 (*((Handle(Geom2d_OffsetCurve)*)&myCurve))->GetBasisCurveContinuity();
250 case GeomAbs_CN: return GeomAbs_CN;
251 case GeomAbs_C3: return GeomAbs_C2;
252 case GeomAbs_C2: return GeomAbs_C1;
253 case GeomAbs_C1: return GeomAbs_C0;
254 case GeomAbs_G1: return GeomAbs_G1;
255 case GeomAbs_G2: return GeomAbs_G2;
258 Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::Continuity");
262 else if (myTypeCurve == GeomAbs_OtherCurve) {
263 Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::Continuity");
273 //=======================================================================
274 //function : NbIntervals
276 //=======================================================================
278 Standard_Integer Geom2dAdaptor_Curve::NbIntervals(const GeomAbs_Shape S) const
280 Standard_Integer myNbIntervals = 1;
281 Standard_Integer NbSplit;
282 if (myTypeCurve == GeomAbs_BSplineCurve) {
283 Standard_Integer FirstIndex = myBspl->FirstUKnotIndex();
284 Standard_Integer LastIndex = myBspl->LastUKnotIndex();
285 TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
286 if ( S > Continuity()) {
287 Standard_Integer Cont;
291 Standard_DomainError::Raise("Geom2dAdaptor_Curve::NbIntervals");
301 if ( S == GeomAbs_C1) Cont = 1;
302 else if ( S == GeomAbs_C2) Cont = 2;
303 else if ( S == GeomAbs_C3) Cont = 3;
304 else Cont = myBspl->Degree();
305 Standard_Integer Degree = myBspl->Degree();
306 Standard_Integer NbKnots = myBspl->NbKnots();
307 TColStd_Array1OfInteger Mults (1, NbKnots);
308 myBspl->Multiplicities (Mults);
310 Standard_Integer Index = FirstIndex;
311 Inter (NbSplit) = Index;
314 while (Index < LastIndex)
316 if (Degree - Mults (Index) < Cont)
318 Inter (NbSplit) = Index;
323 Inter (NbSplit) = Index;
325 Standard_Integer NbInt = NbSplit-1;
327 Standard_Integer Nb = myBspl->NbKnots();
328 Standard_Integer Index1 = 0;
329 Standard_Integer Index2 = 0;
330 Standard_Real newFirst, newLast;
331 TColStd_Array1OfReal TK(1,Nb);
332 TColStd_Array1OfInteger TM(1,Nb);
334 myBspl->Multiplicities(TM);
335 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myFirst,
336 myBspl->IsPeriodic(),
337 1,Nb,Index1,newFirst);
338 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myLast,
339 myBspl->IsPeriodic(),
340 1,Nb,Index2,newLast);
342 // On decale eventuellement les indices
343 // On utilise une "petite" tolerance, la resolution ne doit
344 // servir que pour les tres longue courbes....(PRO9248)
345 Standard_Real Eps = Min(Resolution(Precision::Confusion()),
346 Precision::PConfusion());
347 if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
348 if ( newLast-TK(Index2)> Eps) Index2++;
351 for ( Standard_Integer i=1; i<=NbInt; i++)
352 if (Inter(i)>Index1 && Inter(i)<Index2) myNbIntervals++;
358 else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve)){
359 GeomAbs_Shape BaseS=GeomAbs_C0;
363 Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
365 case GeomAbs_C0: BaseS = GeomAbs_C1; break;
366 case GeomAbs_C1: BaseS = GeomAbs_C2; break;
367 case GeomAbs_C2: BaseS = GeomAbs_C3; break;
368 default: BaseS = GeomAbs_CN;
370 myNbIntervals = myOffsetBaseCurveAdaptor->NbIntervals(BaseS);
373 return myNbIntervals;
376 //=======================================================================
377 //function : Intervals
379 //=======================================================================
381 void Geom2dAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
382 const GeomAbs_Shape S ) const
384 Standard_Integer myNbIntervals = 1;
385 Standard_Integer NbSplit;
386 if (myTypeCurve == GeomAbs_BSplineCurve) {
387 Standard_Integer FirstIndex = myBspl->FirstUKnotIndex();
388 Standard_Integer LastIndex = myBspl->LastUKnotIndex();
389 TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
390 if ( S > Continuity()) {
391 Standard_Integer Cont;
395 Standard_DomainError::Raise("Geom2dAdaptor_Curve::NbIntervals");
405 if ( S == GeomAbs_C1) Cont = 1;
406 else if ( S == GeomAbs_C2) Cont = 2;
407 else if ( S == GeomAbs_C3) Cont = 3;
408 else Cont = myBspl->Degree();
409 Standard_Integer Degree = myBspl->Degree();
410 Standard_Integer NbKnots = myBspl->NbKnots();
411 TColStd_Array1OfInteger Mults (1, NbKnots);
412 myBspl->Multiplicities (Mults);
414 Standard_Integer Index = FirstIndex;
415 Inter (NbSplit) = Index;
418 while (Index < LastIndex)
420 if (Degree - Mults (Index) < Cont)
422 Inter (NbSplit) = Index;
427 Inter (NbSplit) = Index;
428 Standard_Integer NbInt = NbSplit-1;
430 Standard_Integer Nb = myBspl->NbKnots();
431 Standard_Integer Index1 = 0;
432 Standard_Integer Index2 = 0;
433 Standard_Real newFirst, newLast;
434 TColStd_Array1OfReal TK(1,Nb);
435 TColStd_Array1OfInteger TM(1,Nb);
437 myBspl->Multiplicities(TM);
438 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myFirst,
439 myBspl->IsPeriodic(),
440 1,Nb,Index1,newFirst);
441 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myLast,
442 myBspl->IsPeriodic(),
443 1,Nb,Index2,newLast);
446 // On decale eventuellement les indices
447 // On utilise une "petite" tolerance, la resolution ne doit
448 // servir que pour les tres longue courbes....(PRO9248)
449 Standard_Real Eps = Min(Resolution(Precision::Confusion()),
450 Precision::PConfusion());
451 if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
452 if ( newLast-TK(Index2)> Eps) Index2++;
456 for ( Standard_Integer i=1; i<=NbInt; i++) {
457 if (Inter(i) > Index1 && Inter(i)<Index2 ) {
459 Inter(myNbIntervals) = Inter(i);
462 Inter(myNbIntervals+1) = Index2;
464 Standard_Integer ii = T.Lower() - 1;
465 for (Standard_Integer I=1;I<=myNbIntervals+1;I++) {
466 T(ii + I) = TK(Inter(I));
473 else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve)){
474 GeomAbs_Shape BaseS=GeomAbs_C0;
478 Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
480 case GeomAbs_C0: BaseS = GeomAbs_C1; break;
481 case GeomAbs_C1: BaseS = GeomAbs_C2; break;
482 case GeomAbs_C2: BaseS = GeomAbs_C3; break;
483 default: BaseS = GeomAbs_CN;
485 myNbIntervals = myOffsetBaseCurveAdaptor->NbIntervals(BaseS);
486 myOffsetBaseCurveAdaptor->Intervals(T, BaseS);
489 T( T.Lower() ) = myFirst;
490 T( T.Lower() + myNbIntervals ) = myLast;
493 //=======================================================================
496 //=======================================================================
498 Handle(Adaptor2d_HCurve2d) Geom2dAdaptor_Curve::Trim
499 (const Standard_Real First,
500 const Standard_Real Last,
501 // const Standard_Real Tol) const
502 const Standard_Real ) const
504 Handle(Geom2dAdaptor_HCurve) HE = new Geom2dAdaptor_HCurve(myCurve,First,Last);
509 //=======================================================================
510 //function : IsClosed
512 //=======================================================================
514 Standard_Boolean Geom2dAdaptor_Curve::IsClosed() const
516 if (!Precision::IsPositiveInfinite(myLast) &&
517 !Precision::IsNegativeInfinite(myFirst)) {
518 gp_Pnt2d Pd = Value(myFirst);
519 gp_Pnt2d Pf = Value(myLast);
520 return ( Pd.Distance(Pf) <= Precision::Confusion());
523 return Standard_False;
526 //=======================================================================
527 //function : IsPeriodic
529 //=======================================================================
531 Standard_Boolean Geom2dAdaptor_Curve::IsPeriodic() const
533 if (myCurve->IsPeriodic())
536 return Standard_False;
539 //=======================================================================
542 //=======================================================================
544 Standard_Real Geom2dAdaptor_Curve::Period() const
546 return myCurve->LastParameter() - myCurve->FirstParameter();
549 //=======================================================================
550 //function : RebuildCache
552 //=======================================================================
553 void Geom2dAdaptor_Curve::RebuildCache(const Standard_Real theParameter) const
555 myCurveCache->BuildCache(theParameter, myBspl->Degree(),
556 myBspl->IsPeriodic(), myBspl->KnotSequence(),
557 myBspl->Poles(), myBspl->Weights());
560 //=======================================================================
563 //=======================================================================
565 gp_Pnt2d Geom2dAdaptor_Curve::Value(const Standard_Real U) const
567 if (myTypeCurve == GeomAbs_BSplineCurve)
568 return ValueBSpline(U);
569 else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
570 return ValueOffset(U);
572 return myCurve->Value(U);
575 //=======================================================================
576 //function : ValueBSpline
577 //purpose : Computes the point of parameter U on the B-spline curve
578 //=======================================================================
579 gp_Pnt2d Geom2dAdaptor_Curve::ValueBSpline(const Standard_Real theU) const
581 if (theU == myFirst || theU == myLast)
583 Standard_Integer Ideb = 0, Ifin = 0;
586 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
588 if (Ideb>=Ifin) Ifin = Ideb+1;
592 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
593 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
594 if (Ideb>=Ifin) Ideb = Ifin-1;
596 return myBspl->LocalValue(theU, Ideb, Ifin);
598 else if (!myCurveCache.IsNull()) // use cached B-spline data
600 if (!myCurveCache->IsCacheValid(theU))
603 myCurveCache->D0(theU, aRes);
606 return myCurve->Value(theU);
609 //=======================================================================
610 //function : ValueOffset
611 //purpose : Computes the point of parameter U on the offset curve
612 //=======================================================================
613 gp_Pnt2d Geom2dAdaptor_Curve::ValueOffset(const Standard_Real theU) const
617 myOffsetBaseCurveAdaptor->D1(theU, aP, aD1);
618 Standard_Boolean isDirectionChange = Standard_False;
619 const Standard_Real aTol = gp::Resolution();
620 if(aD1.SquareMagnitude() <= aTol)
621 isDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 1, theU, aD1);
623 Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
624 CSLib_Offset::D0(aP, aD1, anOffset, isDirectionChange, aP);
628 //=======================================================================
631 //=======================================================================
633 void Geom2dAdaptor_Curve::D0(const Standard_Real U, gp_Pnt2d& P) const
635 if (myTypeCurve == GeomAbs_BSplineCurve)
640 else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
649 //=======================================================================
650 //function : D0BSpline
651 //purpose : Computes the point of parameter theU on the B-spline curve
652 //=======================================================================
653 void Geom2dAdaptor_Curve::D0BSpline(const Standard_Real theU, gp_Pnt2d& theP) const
655 if (theU == myFirst || theU == myLast)
657 Standard_Integer Ideb = 0, Ifin = 0;
658 if (theU == myFirst) {
659 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
661 if (Ideb>=Ifin) Ifin = Ideb+1;
663 if (theU == myLast) {
664 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
665 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
666 if (Ideb>=Ifin) Ideb = Ifin-1;
668 myBspl->LocalD0(theU, Ideb, Ifin, theP);
671 else if (!myCurveCache.IsNull()) // use cached B-spline data
673 if (!myCurveCache->IsCacheValid(theU))
675 myCurveCache->D0(theU, theP);
678 myCurve->D0(theU, theP);
681 //=======================================================================
682 //function : D0Offset
683 //purpose : Computes the point of parameter theU on the offset curve
684 //=======================================================================
685 void Geom2dAdaptor_Curve::D0Offset(const Standard_Real theU, gp_Pnt2d& theP) const
687 theP = ValueOffset(theU);
690 //=======================================================================
693 //=======================================================================
695 void Geom2dAdaptor_Curve::D1(const Standard_Real U,
696 gp_Pnt2d& P, gp_Vec2d& V) const
698 if (myTypeCurve == GeomAbs_BSplineCurve)
703 else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
709 myCurve->D1(U, P, V);
712 //=======================================================================
713 //function : D1BSpline
714 //purpose : Computes the point of parameter theU on the B-spline curve and its derivative
715 //=======================================================================
716 void Geom2dAdaptor_Curve::D1BSpline(const Standard_Real theU, gp_Pnt2d& theP, gp_Vec2d& theV) const
718 if (theU == myFirst || theU == myLast)
720 Standard_Integer Ideb = 0, Ifin = 0;
721 if (theU == myFirst) {
722 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
724 if (Ideb>=Ifin) Ifin = Ideb+1;
726 if (theU == myLast) {
727 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
728 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
729 if (Ideb>=Ifin) Ideb = Ifin-1;
731 myBspl->LocalD1(theU, Ideb, Ifin, theP, theV);
734 else if (!myCurveCache.IsNull()) // use cached B-spline data
736 if (!myCurveCache->IsCacheValid(theU))
738 myCurveCache->D1(theU, theP, theV);
741 myCurve->D1(theU, theP, theV);
744 //=======================================================================
745 //function : D1Offset
746 //purpose : Computes the point of parameter theU on the offset curve and its derivative
747 //=======================================================================
748 void Geom2dAdaptor_Curve::D1Offset(const Standard_Real theU, gp_Pnt2d& theP, gp_Vec2d& theV) const
750 // P(u) = p(u) + Offset * Ndir / R
751 // with R = || p' ^ Z|| and Ndir = P' ^ Z
753 // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R))
756 myOffsetBaseCurveAdaptor->D2 (theU, theP, theV, V2);
758 Standard_Boolean IsDirectionChange = Standard_False;
759 if(theV.SquareMagnitude() <= gp::Resolution())
760 IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 2, theU, theV, V2);
762 Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
763 CSLib_Offset::D1(theP, theV, V2, anOffset, IsDirectionChange, theP, theV);
766 //=======================================================================
769 //=======================================================================
771 void Geom2dAdaptor_Curve::D2(const Standard_Real U,
772 gp_Pnt2d& P, gp_Vec2d& V1, gp_Vec2d& V2) const
774 if (myTypeCurve == GeomAbs_BSplineCurve)
776 D2BSpline(U, P, V1, V2);
779 else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
781 D2Offset(U, P, V1, V2);
785 myCurve->D2(U, P, V1, V2);
788 //=======================================================================
789 //function : D2BSpline
790 //purpose : Computes the point of parameter theU on the B-spline curve and its first and second derivatives
791 //=======================================================================
792 void Geom2dAdaptor_Curve::D2BSpline(const Standard_Real theU, gp_Pnt2d& theP,
793 gp_Vec2d& theV1, gp_Vec2d& theV2) const
795 if (theU == myFirst || theU == myLast)
797 Standard_Integer Ideb = 0, Ifin = 0;
798 if (theU == myFirst) {
799 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
801 if (Ideb>=Ifin) Ifin = Ideb+1;
803 if (theU == myLast) {
804 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
805 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
806 if (Ideb>=Ifin) Ideb = Ifin-1;
808 myBspl->LocalD2(theU, Ideb, Ifin, theP, theV1, theV2);
811 else if (!myCurveCache.IsNull()) // use cached B-spline data
813 if (!myCurveCache->IsCacheValid(theU))
815 myCurveCache->D2(theU, theP, theV1, theV2);
818 myCurve->D2(theU, theP, theV1, theV2);
820 //=======================================================================
821 //function : D2Offset
822 //purpose : Computes the point of parameter theU on the offset curve and its first and second derivatives
823 //=======================================================================
824 void Geom2dAdaptor_Curve::D2Offset(const Standard_Real theU, gp_Pnt2d& theP,
825 gp_Vec2d& theV1, gp_Vec2d& theV2) const
827 // P(u) = p(u) + Offset * Ndir / R
828 // with R = || p' ^ Z|| and Ndir = P' ^ Z
830 // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R))
832 // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
833 // Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
836 myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, V3);
838 Standard_Boolean IsDirectionChange = Standard_False;
839 if(theV1.SquareMagnitude() <= gp::Resolution())
840 IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 3, theU, theV1, theV2, V3);
842 Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
843 CSLib_Offset::D2(theP, theV1, theV2, V3, anOffset, IsDirectionChange, theP, theV1, theV2);
846 //=======================================================================
849 //=======================================================================
851 void Geom2dAdaptor_Curve::D3(const Standard_Real U,
852 gp_Pnt2d& P, gp_Vec2d& V1,
853 gp_Vec2d& V2, gp_Vec2d& V3) const
855 if (myTypeCurve == GeomAbs_BSplineCurve)
857 D3BSpline(U, P, V1, V2, V3);
860 else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
862 D3Offset(U, P, V1, V2, V3);
866 myCurve->D3(U, P, V1, V2, V3);
869 //=======================================================================
870 //function : D3BSpline
871 //purpose : Computes the point of parameter theU on the B-spline curve and its 1st - 3rd derivatives
872 //=======================================================================
873 void Geom2dAdaptor_Curve::D3BSpline(const Standard_Real theU, gp_Pnt2d& theP,
874 gp_Vec2d& theV1, gp_Vec2d& theV2, gp_Vec2d& theV3) const
876 if (theU == myFirst || theU == myLast)
878 Standard_Integer Ideb = 0, Ifin = 0;
879 if (theU == myFirst) {
880 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
882 if (Ideb>=Ifin) Ifin = Ideb+1;
884 if (theU == myLast) {
885 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
886 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
887 if (Ideb>=Ifin) Ideb = Ifin-1;
889 myBspl->LocalD3(theU, Ideb, Ifin, theP, theV1, theV2, theV3);
892 else if (!myCurveCache.IsNull()) // use cached B-spline data
894 if (!myCurveCache->IsCacheValid(theU))
896 myCurveCache->D3(theU, theP, theV1, theV2, theV3);
899 myCurve->D3(theU, theP, theV1, theV2, theV3);
901 //=======================================================================
902 //function : D3Offset
903 //purpose : Computes the point of parameter theU on the offset curve and its 1st - 3rd derivatives
904 //=======================================================================
905 void Geom2dAdaptor_Curve::D3Offset(const Standard_Real theU, gp_Pnt2d& theP,
906 gp_Vec2d& theV1, gp_Vec2d& theV2, gp_Vec2d& theV3) const
908 // P(u) = p(u) + Offset * Ndir / R
909 // with R = || p' ^ Z|| and Ndir = P' ^ Z
911 // P'(u) = p'(u) + (Offset / R**2) * (DNdir/DU * R - Ndir * (DR/R))
913 // P"(u) = p"(u) + (Offset / R) * (D2Ndir/DU - DNdir * (2.0 * Dr/ R**2) +
914 // Ndir * ( (3.0 * Dr**2 / R**4) - (D2r / R**2)))
916 //P"'(u) = p"'(u) + (Offset / R) * (D3Ndir - (3.0 * Dr/R**2 ) * D2Ndir -
917 // (3.0 * D2r / R2) * DNdir) + (3.0 * Dr * Dr / R4) * DNdir -
918 // (D3r/R2) * Ndir + (6.0 * Dr * Dr / R4) * Ndir +
919 // (6.0 * Dr * D2r / R4) * Ndir - (15.0 * Dr* Dr* Dr /R6) * Ndir
921 Standard_Boolean IsDirectionChange = Standard_False;
923 myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, theV3);
924 gp_Vec2d V4 = myOffsetBaseCurveAdaptor->DN (theU, 4);
926 if(theV1.SquareMagnitude() <= gp::Resolution())
927 IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 4, theU, theV1, theV2, theV3, V4);
929 Standard_Real anOffset = Handle(Geom2d_OffsetCurve)::DownCast(myCurve)->Offset();
930 CSLib_Offset::D3(theP, theV1, theV2, theV3, V4, anOffset, IsDirectionChange,
931 theP, theV1, theV2, theV3);
934 //=======================================================================
937 //=======================================================================
939 gp_Vec2d Geom2dAdaptor_Curve::DN(const Standard_Real U,
940 const Standard_Integer N) const
942 if (myTypeCurve == GeomAbs_BSplineCurve)
943 return DNBSpline(U, N);
944 else if (myCurve->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve))
945 return DNOffset(U, N);
947 return myCurve->DN(U, N);
950 gp_Vec2d Geom2dAdaptor_Curve::DNBSpline(const Standard_Real U,
951 const Standard_Integer N) const
953 if (U==myFirst || U==myLast)
955 Standard_Integer Ideb = 0, Ifin = 0;
957 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
959 if (Ideb>=Ifin) Ifin = Ideb+1;
962 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
963 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
964 if (Ideb>=Ifin) Ideb = Ifin-1;
966 return myBspl->LocalDN( U, Ideb, Ifin, N);
969 return myCurve->DN( U, N);
972 gp_Vec2d Geom2dAdaptor_Curve::DNOffset(const Standard_Real U,
973 const Standard_Integer N) const
981 D1Offset(U, aPnt, aVN);
984 D2Offset(U, aPnt, aVec, aVN);
987 D3Offset(U, aPnt, aVec, aVec, aVN);
990 aVN = myCurve->DN(U, N);
995 //=======================================================================
996 //function : Resolution
998 //=======================================================================
1000 Standard_Real Geom2dAdaptor_Curve::Resolution(const Standard_Real Ruv) const {
1001 switch ( myTypeCurve) {
1004 case GeomAbs_Circle: {
1005 Standard_Real R = (*((Handle(Geom2d_Circle)*)&myCurve))->Circ2d().Radius();
1007 return 2*ASin(Ruv/(2*R));
1011 case GeomAbs_Ellipse: {
1012 return Ruv / (*((Handle(Geom2d_Ellipse)*)&myCurve))->MajorRadius();
1014 case GeomAbs_BezierCurve: {
1016 (*((Handle(Geom2d_BezierCurve)*)&myCurve))->Resolution(Ruv,res);
1019 case GeomAbs_BSplineCurve: {
1021 (*((Handle(Geom2d_BSplineCurve)*)&myCurve))->Resolution(Ruv,res);
1025 return Precision::Parametric(Ruv);
1031 // -- The following methods must be called when GetType returned
1032 // -- the corresponding type.
1035 //=======================================================================
1038 //=======================================================================
1040 gp_Lin2d Geom2dAdaptor_Curve::Line() const
1042 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Line, "");
1043 return (*((Handle(Geom2d_Line)*)&myCurve))->Lin2d();
1046 //=======================================================================
1049 //=======================================================================
1051 gp_Circ2d Geom2dAdaptor_Curve::Circle() const
1053 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Circle, "");
1054 return (*((Handle(Geom2d_Circle)*)&myCurve))->Circ2d();
1057 //=======================================================================
1058 //function : Ellipse
1060 //=======================================================================
1062 gp_Elips2d Geom2dAdaptor_Curve::Ellipse() const
1064 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Ellipse, "");
1065 return (*((Handle(Geom2d_Ellipse)*)&myCurve))->Elips2d();
1068 //=======================================================================
1069 //function : Hyperbola
1071 //=======================================================================
1073 gp_Hypr2d Geom2dAdaptor_Curve::Hyperbola() const
1075 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Hyperbola, "");
1076 return (*((Handle(Geom2d_Hyperbola)*)&myCurve))->Hypr2d();
1079 //=======================================================================
1080 //function : Parabola
1082 //=======================================================================
1084 gp_Parab2d Geom2dAdaptor_Curve::Parabola() const
1086 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Parabola, "");
1087 return (*((Handle(Geom2d_Parabola)*)&myCurve))->Parab2d();
1090 //=======================================================================
1093 //=======================================================================
1095 Standard_Integer Geom2dAdaptor_Curve::Degree() const
1097 if (myTypeCurve == GeomAbs_BezierCurve)
1098 return (*((Handle(Geom2d_BezierCurve)*)&myCurve))->Degree();
1099 else if (myTypeCurve == GeomAbs_BSplineCurve)
1100 return (*((Handle(Geom2d_BSplineCurve)*)&myCurve))->Degree();
1102 Standard_NoSuchObject::Raise();
1107 //=======================================================================
1108 //function : IsRational
1110 //=======================================================================
1112 Standard_Boolean Geom2dAdaptor_Curve::IsRational() const {
1113 switch( myTypeCurve) {
1114 case GeomAbs_BSplineCurve:
1115 return (*((Handle(Geom2d_BSplineCurve)*)&myCurve))->IsRational();
1116 case GeomAbs_BezierCurve:
1117 return (*((Handle(Geom2d_BezierCurve)*)&myCurve))->IsRational();
1119 return Standard_False;
1123 //=======================================================================
1124 //function : NbPoles
1126 //=======================================================================
1128 Standard_Integer Geom2dAdaptor_Curve::NbPoles() const
1130 if (myTypeCurve == GeomAbs_BezierCurve)
1131 return (*((Handle(Geom2d_BezierCurve)*)&myCurve))->NbPoles();
1132 else if (myTypeCurve == GeomAbs_BSplineCurve)
1133 return (*((Handle(Geom2d_BSplineCurve)*)&myCurve))->NbPoles();
1135 Standard_NoSuchObject::Raise();
1140 //=======================================================================
1141 //function : NbKnots
1143 //=======================================================================
1145 Standard_Integer Geom2dAdaptor_Curve::NbKnots() const {
1146 if ( myTypeCurve != GeomAbs_BSplineCurve)
1147 Standard_NoSuchObject::Raise("Geom2dAdaptor_Curve::NbKnots");
1148 return (*((Handle(Geom2d_BSplineCurve)*)&myCurve))->NbKnots();
1152 //=======================================================================
1155 //=======================================================================
1157 Handle(Geom2d_BezierCurve) Geom2dAdaptor_Curve::Bezier() const
1159 return *((Handle(Geom2d_BezierCurve)*)&myCurve);
1162 //=======================================================================
1163 //function : BSpline
1165 //=======================================================================
1167 Handle(Geom2d_BSplineCurve) Geom2dAdaptor_Curve::BSpline() const
1169 return *((Handle(Geom2d_BSplineCurve)*)&myCurve);
1172 static Standard_Integer nbPoints(const Handle(Geom2d_Curve)& theCurve)
1175 Standard_Integer nbs = 10;
1177 if(theCurve->IsKind(STANDARD_TYPE( Geom2d_Line)) )
1179 else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BezierCurve)))
1181 nbs = 3 + (*((Handle(Geom2d_BezierCurve)*)&theCurve))->NbPoles();
1183 else if(theCurve->IsKind(STANDARD_TYPE( Geom2d_BSplineCurve))) {
1184 nbs = (*((Handle(Geom2d_BSplineCurve)*)&theCurve))->NbKnots();
1185 nbs*= (*((Handle(Geom2d_BSplineCurve)*)&theCurve))->Degree();
1186 if(nbs < 2.0) nbs=2;
1188 else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_OffsetCurve)))
1190 Handle(Geom2d_Curve) aCurve = (*((Handle(Geom2d_OffsetCurve)*)&theCurve))->BasisCurve();
1191 return Max(nbs, nbPoints(aCurve));
1194 else if (theCurve->IsKind(STANDARD_TYPE(Geom2d_TrimmedCurve)))
1196 Handle(Geom2d_Curve) aCurve = (*((Handle(Geom2d_TrimmedCurve)*)&theCurve))->BasisCurve();
1197 return Max(nbs, nbPoints(aCurve));
1205 Standard_Integer Geom2dAdaptor_Curve::NbSamples() const
1207 return nbPoints(myCurve);
1211 // ============= Auxiliary functions ===================
1212 Standard_Boolean AdjustDerivative(const Handle(Adaptor2d_HCurve2d)& theAdaptor, Standard_Integer theMaxDerivative,
1213 Standard_Real theU, gp_Vec2d& theD1, gp_Vec2d& theD2,
1214 gp_Vec2d& theD3, gp_Vec2d& theD4)
1216 static const Standard_Real aTol = gp::Resolution();
1218 Standard_Boolean IsDirectionChange = Standard_False;
1219 const Standard_Real anUinfium = theAdaptor->FirstParameter();
1220 const Standard_Real anUsupremum = theAdaptor->LastParameter();
1222 const Standard_Real DivisionFactor = 1.e-3;
1224 if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst()))
1227 du = anUsupremum - anUinfium;
1229 const Standard_Real aDelta = Max(du * DivisionFactor, MinStep);
1231 //Derivative is approximated by Taylor-series
1232 Standard_Integer anIndex = 1; //Derivative order
1237 V = theAdaptor->DN(theU, ++anIndex);
1239 while((V.Magnitude() <= aTol) && anIndex < maxDerivOrder);
1243 if(theU-anUinfium < aDelta)
1249 theAdaptor->D0(Min(theU, u),P1);
1250 theAdaptor->D0(Max(theU, u),P2);
1252 gp_Vec2d V1(P1, P2);
1253 IsDirectionChange = V.Dot(V1) < 0.0;
1254 Standard_Real aSign = IsDirectionChange ? -1.0 : 1.0;
1257 gp_Vec2d* aDeriv[3] = {&theD2, &theD3, &theD4};
1258 for (Standard_Integer i = 1; i < theMaxDerivative; i++)
1259 *(aDeriv[i-1]) = theAdaptor->DN(theU, anIndex + i) * aSign;
1261 return IsDirectionChange;