1 // Created on: 1993-04-29
2 // Created by: Bruno DUMORTIER
3 // Copyright (c) 1993-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
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 : RBV -> traitement des offset curves
21 #define No_Standard_RangeError
22 #define No_Standard_OutOfRange
25 #include <Adaptor3d_HCurve.hxx>
26 #include <BSplCLib.hxx>
27 #include <BSplCLib_Cache.hxx>
28 #include <CSLib_Offset.hxx>
29 #include <Geom_BezierCurve.hxx>
30 #include <Geom_BSplineCurve.hxx>
31 #include <Geom_Circle.hxx>
32 #include <Geom_Curve.hxx>
33 #include <Geom_Ellipse.hxx>
34 #include <Geom_Hyperbola.hxx>
35 #include <Geom_Line.hxx>
36 #include <Geom_OffsetCurve.hxx>
37 #include <Geom_Parabola.hxx>
38 #include <Geom_TrimmedCurve.hxx>
39 #include <GeomAbs_Shape.hxx>
40 #include <GeomAdaptor_Curve.hxx>
41 #include <GeomAdaptor_HCurve.hxx>
42 #include <GeomAdaptor_Surface.hxx>
43 #include <gp_Circ.hxx>
44 #include <gp_Elips.hxx>
45 #include <gp_Hypr.hxx>
47 #include <gp_Parab.hxx>
50 #include <Precision.hxx>
51 #include <Standard_ConstructionError.hxx>
52 #include <Standard_DomainError.hxx>
53 #include <Standard_NoSuchObject.hxx>
54 #include <Standard_NotImplemented.hxx>
55 #include <Standard_NullObject.hxx>
56 #include <Standard_OutOfRange.hxx>
57 #include <TColgp_Array1OfPnt.hxx>
58 #include <TColStd_Array1OfInteger.hxx>
59 #include <TColStd_Array1OfReal.hxx>
60 #include <TColStd_HArray1OfInteger.hxx>
62 //#include <GeomConvert_BSplineCurveKnotSplitting.hxx>
63 #define myBspl Handle(Geom_BSplineCurve)::DownCast (myCurve)
64 #define PosTol Precision::PConfusion()/2
66 static const int maxDerivOrder = 3;
67 static const Standard_Real MinStep = 1e-7;
69 static gp_Vec dummyDerivative; // used as empty value for unused derivatives in AdjustDerivative
70 // Recalculate derivatives in the singular point
71 // Returns true if the direction of derivatives is changed
72 static Standard_Boolean AdjustDerivative(
73 const Handle(Adaptor3d_HCurve)& theAdaptor, Standard_Integer theMaxDerivative, Standard_Real theU, gp_Vec& theD1,
74 gp_Vec& theD2 = dummyDerivative, gp_Vec& theD3 = dummyDerivative, gp_Vec& theD4 = dummyDerivative);
77 //=======================================================================
78 //function : LocalContinuity
79 //purpose : Computes the Continuity of a BSplineCurve
80 // between the parameters U1 and U2
81 // The continuity is C(d-m)
83 // m = max multiplicity of the Knots between U1 and U2
84 //=======================================================================
86 GeomAbs_Shape GeomAdaptor_Curve::LocalContinuity(const Standard_Real U1,
87 const Standard_Real U2)
90 Standard_NoSuchObject_Raise_if(myTypeCurve!=GeomAbs_BSplineCurve," ");
91 Standard_Integer Nb = myBspl->NbKnots();
92 Standard_Integer Index1 = 0;
93 Standard_Integer Index2 = 0;
94 Standard_Real newFirst, newLast;
95 TColStd_Array1OfReal TK(1,Nb);
96 TColStd_Array1OfInteger TM(1,Nb);
98 myBspl->Multiplicities(TM);
99 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,U1,myBspl->IsPeriodic(),
100 1,Nb,Index1,newFirst);
101 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,U2,myBspl->IsPeriodic(),
102 1,Nb,Index2,newLast);
103 if ( Abs(newFirst-TK(Index1+1))<Precision::PConfusion()) {
104 if (Index1 < Nb) Index1++;
106 if ( Abs(newLast-TK(Index2))<Precision::PConfusion())
108 Standard_Integer MultMax;
109 // attention aux courbes peridiques.
110 if ( (myBspl->IsPeriodic()) && (Index1 == Nb) )
113 if ( Index2 - Index1 <= 0) {
114 MultMax = 100; // CN entre 2 Noeuds consecutifs
117 MultMax = TM(Index1+1);
118 for(Standard_Integer i = Index1+1;i<=Index2;i++) {
119 if ( TM(i)>MultMax) MultMax=TM(i);
121 MultMax = myBspl->Degree() - MultMax;
126 else if ( MultMax == 1) {
129 else if ( MultMax == 2) {
132 else if ( MultMax == 3) {
141 //=======================================================================
144 //=======================================================================
146 void GeomAdaptor_Curve::load(const Handle(Geom_Curve)& C,
147 const Standard_Real UFirst,
148 const Standard_Real ULast)
156 const Handle(Standard_Type)& TheType = C->DynamicType();
157 if ( TheType == STANDARD_TYPE(Geom_TrimmedCurve)) {
158 Load(Handle(Geom_TrimmedCurve)::DownCast (C)->BasisCurve(),UFirst,ULast);
160 else if ( TheType == STANDARD_TYPE(Geom_Circle)) {
161 myTypeCurve = GeomAbs_Circle;
163 else if ( TheType ==STANDARD_TYPE(Geom_Line)) {
164 myTypeCurve = GeomAbs_Line;
166 else if ( TheType == STANDARD_TYPE(Geom_Ellipse)) {
167 myTypeCurve = GeomAbs_Ellipse;
169 else if ( TheType == STANDARD_TYPE(Geom_Parabola)) {
170 myTypeCurve = GeomAbs_Parabola;
172 else if ( TheType == STANDARD_TYPE(Geom_Hyperbola)) {
173 myTypeCurve = GeomAbs_Hyperbola;
175 else if ( TheType == STANDARD_TYPE(Geom_BezierCurve)) {
176 myTypeCurve = GeomAbs_BezierCurve;
178 else if ( TheType == STANDARD_TYPE(Geom_BSplineCurve)) {
179 myTypeCurve = GeomAbs_BSplineCurve;
180 // Create cache for B-spline
181 myCurveCache = new BSplCLib_Cache(myBspl->Degree(), myBspl->IsPeriodic(),
182 myBspl->KnotSequence(), myBspl->Poles(), myBspl->Weights());
184 else if ( TheType == STANDARD_TYPE(Geom_OffsetCurve)) {
185 myTypeCurve = GeomAbs_OffsetCurve;
186 // Create nested adaptor for base curve
187 Handle(Geom_Curve) aBase = Handle(Geom_OffsetCurve)::DownCast(myCurve)->BasisCurve();
188 myOffsetBaseCurveAdaptor = new GeomAdaptor_HCurve(aBase);
191 myTypeCurve = GeomAbs_OtherCurve;
197 // -- Global methods - Apply to the whole curve.
200 //=======================================================================
201 //function : Continuity
203 //=======================================================================
205 GeomAbs_Shape GeomAdaptor_Curve::Continuity() const
207 if (myTypeCurve == GeomAbs_BSplineCurve)
208 return LocalContinuity(myFirst, myLast);
210 if (myTypeCurve == GeomAbs_OffsetCurve)
212 const GeomAbs_Shape S =
213 Handle(Geom_OffsetCurve)::DownCast (myCurve)->GetBasisCurveContinuity();
216 case GeomAbs_CN: return GeomAbs_CN;
217 case GeomAbs_C3: return GeomAbs_C2;
218 case GeomAbs_C2: return GeomAbs_C1;
219 case GeomAbs_C1: return GeomAbs_C0;
220 case GeomAbs_G1: return GeomAbs_G1;
221 case GeomAbs_G2: return GeomAbs_G2;
223 Standard_NoSuchObject::Raise("GeomAdaptor_Curve::Continuity");
226 else if (myTypeCurve == GeomAbs_OtherCurve) {
227 Standard_NoSuchObject::Raise("GeomAdaptor_Curve::Contunuity");
233 //=======================================================================
234 //function : NbIntervals
236 //=======================================================================
238 Standard_Integer GeomAdaptor_Curve::NbIntervals(const GeomAbs_Shape S) const
240 Standard_Integer myNbIntervals = 1;
241 Standard_Integer NbSplit;
242 if (myTypeCurve == GeomAbs_BSplineCurve) {
243 Standard_Integer FirstIndex = myBspl->FirstUKnotIndex();
244 Standard_Integer LastIndex = myBspl->LastUKnotIndex();
245 TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
246 if ( S > Continuity()) {
247 Standard_Integer Cont;
251 Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
261 if ( S == GeomAbs_C1) Cont = 1;
262 else if ( S == GeomAbs_C2) Cont = 2;
263 else if ( S == GeomAbs_C3) Cont = 3;
264 else Cont = myBspl->Degree();
265 Standard_Integer Degree = myBspl->Degree();
266 Standard_Integer NbKnots = myBspl->NbKnots();
267 TColStd_Array1OfInteger Mults (1, NbKnots);
268 myBspl->Multiplicities (Mults);
270 Standard_Integer Index = FirstIndex;
271 Inter (NbSplit) = Index;
274 while (Index < LastIndex)
276 if (Degree - Mults (Index) < Cont)
278 Inter (NbSplit) = Index;
283 Inter (NbSplit) = Index;
285 Standard_Integer NbInt = NbSplit-1;
287 Standard_Integer Nb = myBspl->NbKnots();
288 Standard_Integer Index1 = 0;
289 Standard_Integer Index2 = 0;
290 Standard_Real newFirst, newLast;
291 TColStd_Array1OfReal TK(1,Nb);
292 TColStd_Array1OfInteger TM(1,Nb);
294 myBspl->Multiplicities(TM);
295 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myFirst,
296 myBspl->IsPeriodic(),
297 1,Nb,Index1,newFirst);
298 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myLast,
299 myBspl->IsPeriodic(),
300 1,Nb,Index2,newLast);
302 // On decale eventuellement les indices
303 // On utilise une "petite" tolerance, la resolution ne doit
304 // servir que pour les tres longue courbes....(PRO9248)
305 Standard_Real Eps = Min(Resolution(Precision::Confusion()),
306 Precision::PConfusion());
307 if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
308 if ( newLast-TK(Index2)> Eps) Index2++;
311 for ( Standard_Integer i=1; i<=NbInt; i++)
312 if (Inter(i)>Index1 && Inter(i)<Index2) myNbIntervals++;
319 else if (myTypeCurve == GeomAbs_OffsetCurve) {
320 GeomAbs_Shape BaseS=GeomAbs_C0;
324 Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
326 case GeomAbs_C0: BaseS = GeomAbs_C1; break;
327 case GeomAbs_C1: BaseS = GeomAbs_C2; break;
328 case GeomAbs_C2: BaseS = GeomAbs_C3; break;
329 default: BaseS = GeomAbs_CN;
332 (Handle(Geom_OffsetCurve)::DownCast (myCurve)->BasisCurve());
333 // akm 05/04/02 (OCC278) If our curve is trimmed we must recalculate
334 // the number of intervals obtained from the basis to
335 // vvv reflect parameter bounds
336 Standard_Integer iNbBasisInt = C.NbIntervals(BaseS), iInt;
339 TColStd_Array1OfReal rdfInter(1,1+iNbBasisInt);
340 C.Intervals(rdfInter,BaseS);
341 for (iInt=1; iInt<=iNbBasisInt; iInt++)
342 if (rdfInter(iInt)>myFirst && rdfInter(iInt)<myLast)
347 return myNbIntervals;
350 //=======================================================================
351 //function : Intervals
353 //=======================================================================
355 void GeomAdaptor_Curve::Intervals(TColStd_Array1OfReal& T,
356 const GeomAbs_Shape S ) const
358 Standard_Integer myNbIntervals = 1;
359 Standard_Integer NbSplit;
360 Standard_Real FirstParam = myFirst, LastParam = myLast;
362 if (myTypeCurve == GeomAbs_BSplineCurve)
364 Standard_Integer FirstIndex = myBspl->FirstUKnotIndex();
365 Standard_Integer LastIndex = myBspl->LastUKnotIndex();
366 TColStd_Array1OfInteger Inter (1, LastIndex-FirstIndex+1);
368 if ( S > Continuity()) {
369 Standard_Integer Cont;
373 Standard_DomainError::Raise("Geom2dAdaptor_Curve::NbIntervals");
383 if ( S == GeomAbs_C1) Cont = 1;
384 else if ( S == GeomAbs_C2) Cont = 2;
385 else if ( S == GeomAbs_C3) Cont = 3;
386 else Cont = myBspl->Degree();
387 Standard_Integer Degree = myBspl->Degree();
388 Standard_Integer NbKnots = myBspl->NbKnots();
389 TColStd_Array1OfInteger Mults (1, NbKnots);
390 myBspl->Multiplicities (Mults);
392 Standard_Integer Index = FirstIndex;
393 Inter (NbSplit) = Index;
396 while (Index < LastIndex)
398 if (Degree - Mults (Index) < Cont)
400 Inter (NbSplit) = Index;
405 Inter (NbSplit) = Index;
406 Standard_Integer NbInt = NbSplit-1;
407 // GeomConvert_BSplineCurveKnotSplitting Convector(myBspl, Cont);
408 // Standard_Integer NbInt = Convector.NbSplits()-1;
409 // TColStd_Array1OfInteger Inter(1,NbInt+1);
410 // Convector.Splitting( Inter);
412 Standard_Integer Nb = myBspl->NbKnots();
413 Standard_Integer Index1 = 0;
414 Standard_Integer Index2 = 0;
415 Standard_Real newFirst, newLast;
416 TColStd_Array1OfReal TK(1,Nb);
417 TColStd_Array1OfInteger TM(1,Nb);
419 myBspl->Multiplicities(TM);
420 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myFirst,
421 myBspl->IsPeriodic(),
422 1,Nb,Index1,newFirst);
423 BSplCLib::LocateParameter(myBspl->Degree(),TK,TM,myLast,
424 myBspl->IsPeriodic(),
425 1,Nb,Index2,newLast);
426 FirstParam = newFirst;
428 // On decale eventuellement les indices
429 // On utilise une "petite" tolerance, la resolution ne doit
430 // servir que pour les tres longue courbes....(PRO9248)
431 Standard_Real Eps = Min(Resolution(Precision::Confusion()),
432 Precision::PConfusion());
433 if ( Abs(newFirst-TK(Index1+1))< Eps) Index1++;
434 if ( newLast-TK(Index2)> Eps) Index2++;
438 for ( Standard_Integer i=1; i<=NbInt; i++) {
439 if (Inter(i) > Index1 && Inter(i)<Index2 ) {
441 Inter(myNbIntervals) = Inter(i);
444 Inter(myNbIntervals+1) = Index2;
446 for (Standard_Integer I=1;I<=myNbIntervals+1;I++) {
455 else if (myTypeCurve == GeomAbs_OffsetCurve){
456 GeomAbs_Shape BaseS=GeomAbs_C0;
460 Standard_DomainError::Raise("GeomAdaptor_Curve::NbIntervals");
462 case GeomAbs_C0: BaseS = GeomAbs_C1; break;
463 case GeomAbs_C1: BaseS = GeomAbs_C2; break;
464 case GeomAbs_C2: BaseS = GeomAbs_C3; break;
465 default: BaseS = GeomAbs_CN;
468 (Handle(Geom_OffsetCurve)::DownCast (myCurve)->BasisCurve());
469 // akm 05/04/02 (OCC278) If our curve is trimmed we must recalculate
470 // the array of intervals obtained from the basis to
471 // vvv reflect parameter bounds
472 Standard_Integer iNbBasisInt = C.NbIntervals(BaseS), iInt;
475 TColStd_Array1OfReal rdfInter(1,1+iNbBasisInt);
476 C.Intervals(rdfInter,BaseS);
477 for (iInt=1; iInt<=iNbBasisInt; iInt++)
478 if (rdfInter(iInt)>myFirst && rdfInter(iInt)<myLast)
479 T(++myNbIntervals)=rdfInter(iInt);
481 // old - myNbIntervals = C.NbIntervals(BaseS);
482 // old - C.Intervals(T, BaseS);
486 T( T.Lower() ) = FirstParam;
487 T( T.Lower() + myNbIntervals ) = LastParam;
490 //=======================================================================
493 //=======================================================================
495 Handle(Adaptor3d_HCurve) GeomAdaptor_Curve::Trim(const Standard_Real First,
496 const Standard_Real Last,
497 const Standard_Real /*Tol*/) const
499 return Handle(GeomAdaptor_HCurve)(new GeomAdaptor_HCurve(myCurve,First,Last));
503 //=======================================================================
504 //function : IsClosed
506 //=======================================================================
508 Standard_Boolean GeomAdaptor_Curve::IsClosed() const
510 if (!Precision::IsPositiveInfinite(myLast) &&
511 !Precision::IsNegativeInfinite(myFirst))
513 const gp_Pnt Pd = Value(myFirst);
514 const gp_Pnt Pf = Value(myLast);
515 return (Pd.Distance(Pf) <= Precision::Confusion());
517 return Standard_False;
520 //=======================================================================
521 //function : IsPeriodic
523 //=======================================================================
525 Standard_Boolean GeomAdaptor_Curve::IsPeriodic() const
527 return (myCurve->IsPeriodic()? IsClosed() : Standard_False);
530 //=======================================================================
533 //=======================================================================
535 Standard_Real GeomAdaptor_Curve::Period() const
537 return myCurve->LastParameter() - myCurve->FirstParameter();
540 //=======================================================================
541 //function : RebuildCache
543 //=======================================================================
544 void GeomAdaptor_Curve::RebuildCache(const Standard_Real theParameter) const
546 myCurveCache->BuildCache(theParameter, myBspl->Degree(),
547 myBspl->IsPeriodic(), myBspl->KnotSequence(),
548 myBspl->Poles(), myBspl->Weights());
551 //=======================================================================
554 //=======================================================================
556 gp_Pnt GeomAdaptor_Curve::Value(const Standard_Real U) const
558 if (myTypeCurve == GeomAbs_BSplineCurve)
559 return ValueBSpline(U);
560 else if (myTypeCurve == GeomAbs_OffsetCurve)
561 return ValueOffset(U);
562 return myCurve->Value(U);
565 //=======================================================================
566 //function : ValueBSpline
568 //=======================================================================
569 gp_Pnt GeomAdaptor_Curve::ValueBSpline(const Standard_Real theU) const
571 if (theU == myFirst || theU == myLast)
573 Standard_Integer Ideb = 0, Ifin = 0;
574 if (theU == myFirst) {
575 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
577 if (Ideb>=Ifin) Ifin = Ideb+1;
579 if (theU == myLast) {
580 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
581 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
582 if (Ideb>=Ifin) Ideb = Ifin-1;
584 return myBspl->LocalValue(theU, Ideb, Ifin);
586 else if (!myCurveCache.IsNull()) // use cached B-spline data
588 if (!myCurveCache->IsCacheValid(theU))
591 myCurveCache->D0(theU, aRes);
594 return myCurve->Value(theU);
597 //=======================================================================
598 //function : ValueOffset
600 //=======================================================================
601 gp_Pnt GeomAdaptor_Curve::ValueOffset(const Standard_Real theU) const
605 myOffsetBaseCurveAdaptor->D1(theU, aP, aV);
606 Standard_Boolean IsDirectionChange = Standard_False;
607 if(aV.SquareMagnitude() <= gp::Resolution())
608 IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 1, theU, aV);
610 Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
611 Standard_Real anOffsetVal = anOffC->Offset();
612 const gp_Dir& anOffsetDir = anOffC->Direction();
614 CSLib_Offset::D0(aP, aV, anOffsetDir, anOffsetVal, IsDirectionChange, aP);
618 //=======================================================================
621 //=======================================================================
623 void GeomAdaptor_Curve::D0(const Standard_Real U, gp_Pnt& P) const
625 if (myTypeCurve == GeomAbs_BSplineCurve)
627 else if (myTypeCurve == GeomAbs_OffsetCurve)
633 //=======================================================================
634 //function : D0BSpline
636 //=======================================================================
637 void GeomAdaptor_Curve::D0BSpline(const Standard_Real theU, gp_Pnt& theP) const
639 if (theU == myFirst || theU == myLast)
641 Standard_Integer Ideb = 0, Ifin = 0;
642 if (theU == myFirst) {
643 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
645 if (Ideb>=Ifin) Ifin = Ideb+1;
647 if (theU == myLast) {
648 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
649 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
650 if (Ideb>=Ifin) Ideb = Ifin-1;
652 myBspl->LocalD0(theU, Ideb, Ifin, theP);
655 else if (!myCurveCache.IsNull()) // use cached B-spline data
657 if (!myCurveCache->IsCacheValid(theU))
659 myCurveCache->D0(theU, theP);
662 myCurve->D0(theU, theP);
665 //=======================================================================
666 //function : D0Offset
668 //=======================================================================
669 void GeomAdaptor_Curve::D0Offset(const Standard_Real theU, gp_Pnt& theP) const
671 theP = ValueOffset(theU);
674 //=======================================================================
677 //=======================================================================
679 void GeomAdaptor_Curve::D1(const Standard_Real U, gp_Pnt& P, gp_Vec& V) const
681 if (myTypeCurve == GeomAbs_BSplineCurve)
683 else if (myTypeCurve == GeomAbs_OffsetCurve)
686 myCurve->D1(U, P, V);
689 //=======================================================================
690 //function : D1BSpline
692 //=======================================================================
693 void GeomAdaptor_Curve::D1BSpline(const Standard_Real theU, gp_Pnt& theP, gp_Vec& theV) const
695 if (theU == myFirst || theU == myLast)
697 Standard_Integer Ideb = 0, Ifin = 0;
698 if (theU == myFirst) {
699 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
701 if (Ideb>=Ifin) Ifin = Ideb+1;
703 if (theU == myLast) {
704 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
705 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
706 if (Ideb>=Ifin) Ideb = Ifin-1;
708 myBspl->LocalD1(theU, Ideb, Ifin, theP, theV);
711 else if (!myCurveCache.IsNull()) // use cached B-spline data
713 if (!myCurveCache->IsCacheValid(theU))
715 myCurveCache->D1(theU, theP, theV);
718 myCurve->D1(theU, theP, theV);
721 //=======================================================================
722 //function : D1Offset
724 //=======================================================================
725 void GeomAdaptor_Curve::D1Offset(const Standard_Real theU, gp_Pnt& theP, gp_Vec& theV) const
728 myOffsetBaseCurveAdaptor->D2 (theU, theP, theV, aV2);
730 Standard_Boolean IsDirectionChange = Standard_False;
731 if(theV.SquareMagnitude() <= gp::Resolution())
732 IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 2, theU, theV, aV2);
734 Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
735 Standard_Real anOffsetVal = anOffC->Offset();
736 const gp_Dir& anOffsetDir = anOffC->Direction();
737 CSLib_Offset::D1(theP, theV, aV2, anOffsetDir, anOffsetVal, IsDirectionChange, theP, theV);
741 //=======================================================================
744 //=======================================================================
746 void GeomAdaptor_Curve::D2(const Standard_Real U,
747 gp_Pnt& P, gp_Vec& V1, gp_Vec& V2) const
749 if (myTypeCurve == GeomAbs_BSplineCurve)
750 D2BSpline(U, P, V1, V2);
751 else if (myTypeCurve == GeomAbs_OffsetCurve)
752 D2Offset(U, P, V1, V2);
754 myCurve->D2(U, P, V1, V2);
757 //=======================================================================
758 //function : D2BSpline
760 //=======================================================================
761 void GeomAdaptor_Curve::D2BSpline(const Standard_Real theU, gp_Pnt& theP,
762 gp_Vec& theV1, gp_Vec& theV2) const
764 if (theU == myFirst || theU == myLast)
766 Standard_Integer Ideb = 0, Ifin = 0;
767 if (theU == myFirst) {
768 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
770 if (Ideb>=Ifin) Ifin = Ideb+1;
772 if (theU == myLast) {
773 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
774 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
775 if (Ideb>=Ifin) Ideb = Ifin-1;
777 myBspl->LocalD2(theU, Ideb, Ifin, theP, theV1, theV2);
780 else if (!myCurveCache.IsNull()) // use cached B-spline data
782 if (!myCurveCache->IsCacheValid(theU))
784 myCurveCache->D2(theU, theP, theV1, theV2);
787 myCurve->D2(theU, theP, theV1, theV2);
790 //=======================================================================
791 //function : D2Offset
793 //=======================================================================
794 void GeomAdaptor_Curve::D2Offset(const Standard_Real theU, gp_Pnt& theP,
795 gp_Vec& theV1, gp_Vec& theV2) const
798 myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, V3);
800 Standard_Boolean IsDirectionChange = Standard_False;
801 if(theV1.SquareMagnitude() <= gp::Resolution())
802 IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 3, theU, theV1, theV2, V3);
804 Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
805 Standard_Real anOffsetVal = anOffC->Offset();
806 const gp_Dir& anOffsetDir = anOffC->Direction();
807 CSLib_Offset::D2(theP, theV1, theV2, V3, anOffsetDir, anOffsetVal, IsDirectionChange, theP, theV1, theV2);
810 //=======================================================================
813 //=======================================================================
815 void GeomAdaptor_Curve::D3(const Standard_Real U,
816 gp_Pnt& P, gp_Vec& V1,
817 gp_Vec& V2, gp_Vec& V3) const
819 if (myTypeCurve == GeomAbs_BSplineCurve)
820 D3BSpline(U, P, V1, V2, V3);
821 else if (myTypeCurve == GeomAbs_OffsetCurve)
822 D3Offset(U, P, V1, V2, V3);
824 myCurve->D3(U, P, V1, V2, V3);
827 //=======================================================================
828 //function : D3BSpline
830 //=======================================================================
831 void GeomAdaptor_Curve::D3BSpline(const Standard_Real theU,
832 gp_Pnt& theP, gp_Vec& theV1,
833 gp_Vec& theV2, gp_Vec& theV3) const
835 if (theU == myFirst || theU == myLast)
837 Standard_Integer Ideb = 0, Ifin = 0;
838 if (theU == myFirst) {
839 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
841 if (Ideb>=Ifin) Ifin = Ideb+1;
843 if (theU == myLast) {
844 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
845 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
846 if (Ideb>=Ifin) Ideb = Ifin-1;
848 myBspl->LocalD3(theU, Ideb, Ifin, theP, theV1, theV2, theV3);
851 else if (!myCurveCache.IsNull()) // use cached B-spline data
853 if (!myCurveCache->IsCacheValid(theU))
855 myCurveCache->D3(theU, theP, theV1, theV2, theV3);
858 myCurve->D3(theU, theP, theV1, theV2, theV3);
861 //=======================================================================
862 //function : D3Offset
864 //=======================================================================
865 void GeomAdaptor_Curve::D3Offset(const Standard_Real theU,
866 gp_Pnt& theP, gp_Vec& theV1,
867 gp_Vec& theV2, gp_Vec& theV3) const
869 myOffsetBaseCurveAdaptor->D3 (theU, theP, theV1, theV2, theV3);
870 gp_Vec V4 = myOffsetBaseCurveAdaptor->DN(theU, 4);
872 Standard_Boolean IsDirectionChange = Standard_False;
873 if(theV1.SquareMagnitude() <= gp::Resolution())
874 IsDirectionChange = AdjustDerivative(myOffsetBaseCurveAdaptor, 4, theU, theV1, theV2, theV3, V4);
876 Handle(Geom_OffsetCurve) anOffC = Handle(Geom_OffsetCurve)::DownCast(myCurve);
877 Standard_Real anOffsetVal = anOffC->Offset();
878 const gp_Dir& anOffsetDir = anOffC->Direction();
879 CSLib_Offset::D3(theP, theV1, theV2, theV3, V4, anOffsetDir, anOffsetVal, IsDirectionChange,
880 theP, theV1, theV2, theV3);
883 //=======================================================================
886 //=======================================================================
888 gp_Vec GeomAdaptor_Curve::DN(const Standard_Real U,
889 const Standard_Integer N) const
891 if (myTypeCurve == GeomAbs_BSplineCurve)
892 return DNBSpline(U, N);
893 else if (myTypeCurve == GeomAbs_OffsetCurve)
894 return DNOffset(U, N);
896 return myCurve->DN(U, N);
899 gp_Vec GeomAdaptor_Curve::DNBSpline(const Standard_Real U,
900 const Standard_Integer N) const
902 if ((U==myFirst || U==myLast))
904 Standard_Integer Ideb = 0, Ifin = 0;
906 myBspl->LocateU(myFirst, PosTol, Ideb, Ifin);
908 if (Ideb>=Ifin) Ifin = Ideb+1;
911 myBspl->LocateU(myLast, PosTol, Ideb, Ifin);
912 if (Ifin>myBspl->NbKnots()) Ifin = myBspl->NbKnots();
913 if (Ideb>=Ifin) Ideb = Ifin-1;
915 return myBspl->LocalDN( U, Ideb, Ifin, N);
917 return myCurve->DN( U, N);
920 gp_Vec GeomAdaptor_Curve::DNOffset(const Standard_Real U,
921 const Standard_Integer N) const
929 D1Offset(U, aPnt, aVN);
932 D2Offset(U, aPnt, aVec, aVN);
935 D3Offset(U, aPnt, aVec, aVec, aVN);
938 aVN = myCurve->DN(U, N);
943 //=======================================================================
944 //function : Resolution
946 //=======================================================================
948 Standard_Real GeomAdaptor_Curve::Resolution(const Standard_Real R3D) const
950 switch ( myTypeCurve) {
953 case GeomAbs_Circle: {
954 Standard_Real R = Handle(Geom_Circle)::DownCast (myCurve)->Circ().Radius();
956 return 2*ASin(R3D/(2*R));
960 case GeomAbs_Ellipse: {
961 return R3D / Handle(Geom_Ellipse)::DownCast (myCurve)->MajorRadius();
963 case GeomAbs_BezierCurve: {
965 Handle(Geom_BezierCurve)::DownCast (myCurve)->Resolution(R3D,res);
968 case GeomAbs_BSplineCurve: {
970 Handle(Geom_BSplineCurve)::DownCast (myCurve)->Resolution(R3D,res);
974 return Precision::Parametric(R3D);
980 // -- The following methods must be called when GetType returned
981 // -- the corresponding type.
984 //=======================================================================
987 //=======================================================================
989 gp_Lin GeomAdaptor_Curve::Line() const
991 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Line, "");
992 return Handle(Geom_Line)::DownCast (myCurve)->Lin();
995 //=======================================================================
998 //=======================================================================
1000 gp_Circ GeomAdaptor_Curve::Circle() const
1002 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Circle, "");
1003 return Handle(Geom_Circle)::DownCast (myCurve)->Circ();
1006 //=======================================================================
1007 //function : Ellipse
1009 //=======================================================================
1011 gp_Elips GeomAdaptor_Curve::Ellipse() const
1013 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Ellipse, "");
1014 return Handle(Geom_Ellipse)::DownCast (myCurve)->Elips();
1017 //=======================================================================
1018 //function : Hyperbola
1020 //=======================================================================
1022 gp_Hypr GeomAdaptor_Curve::Hyperbola() const
1024 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Hyperbola, "");
1025 return Handle(Geom_Hyperbola)::DownCast (myCurve)->Hypr();
1028 //=======================================================================
1029 //function : Parabola
1031 //=======================================================================
1033 gp_Parab GeomAdaptor_Curve::Parabola() const
1035 Standard_NoSuchObject_Raise_if(myTypeCurve != GeomAbs_Parabola, "");
1036 return Handle(Geom_Parabola)::DownCast (myCurve)->Parab();
1039 //=======================================================================
1042 //=======================================================================
1044 Standard_Integer GeomAdaptor_Curve::Degree() const
1046 if (myTypeCurve == GeomAbs_BezierCurve)
1047 return Handle(Geom_BezierCurve)::DownCast (myCurve)->Degree();
1048 else if (myTypeCurve == GeomAbs_BSplineCurve)
1049 return Handle(Geom_BSplineCurve)::DownCast (myCurve)->Degree();
1051 Standard_NoSuchObject::Raise();
1056 //=======================================================================
1057 //function : IsRational
1059 //=======================================================================
1061 Standard_Boolean GeomAdaptor_Curve::IsRational() const {
1062 switch( myTypeCurve) {
1063 case GeomAbs_BSplineCurve:
1064 return Handle(Geom_BSplineCurve)::DownCast (myCurve)->IsRational();
1065 case GeomAbs_BezierCurve:
1066 return Handle(Geom_BezierCurve)::DownCast (myCurve)->IsRational();
1068 return Standard_False;
1072 //=======================================================================
1073 //function : NbPoles
1075 //=======================================================================
1077 Standard_Integer GeomAdaptor_Curve::NbPoles() const
1079 if (myTypeCurve == GeomAbs_BezierCurve)
1080 return Handle(Geom_BezierCurve)::DownCast (myCurve)->NbPoles();
1081 else if (myTypeCurve == GeomAbs_BSplineCurve)
1082 return Handle(Geom_BSplineCurve)::DownCast (myCurve)->NbPoles();
1084 Standard_NoSuchObject::Raise();
1089 //=======================================================================
1090 //function : NbKnots
1092 //=======================================================================
1094 Standard_Integer GeomAdaptor_Curve::NbKnots() const
1096 if ( myTypeCurve != GeomAbs_BSplineCurve)
1097 Standard_NoSuchObject::Raise("GeomAdaptor_Curve::NbKnots");
1098 return Handle(Geom_BSplineCurve)::DownCast (myCurve)->NbKnots();
1101 //=======================================================================
1104 //=======================================================================
1106 Handle(Geom_BezierCurve) GeomAdaptor_Curve::Bezier() const
1108 if ( myTypeCurve != GeomAbs_BezierCurve)
1109 Standard_NoSuchObject::Raise("GeomAdaptor_Curve::Bezier");
1110 return Handle(Geom_BezierCurve)::DownCast (myCurve);
1113 //=======================================================================
1114 //function : BSpline
1116 //=======================================================================
1118 Handle(Geom_BSplineCurve) GeomAdaptor_Curve::BSpline() const
1120 if ( myTypeCurve != GeomAbs_BSplineCurve)
1121 Standard_NoSuchObject::Raise("GeomAdaptor_Curve::BSpline");
1123 return Handle(Geom_BSplineCurve)::DownCast (myCurve);
1127 // ============= Auxiliary functions ===================
1128 Standard_Boolean AdjustDerivative(const Handle(Adaptor3d_HCurve)& theAdaptor, Standard_Integer theMaxDerivative,
1129 Standard_Real theU, gp_Vec& theD1, gp_Vec& theD2,
1130 gp_Vec& theD3, gp_Vec& theD4)
1132 static const Standard_Real aTol = gp::Resolution();
1134 Standard_Boolean IsDirectionChange = Standard_False;
1135 const Standard_Real anUinfium = theAdaptor->FirstParameter();
1136 const Standard_Real anUsupremum = theAdaptor->LastParameter();
1138 const Standard_Real DivisionFactor = 1.e-3;
1140 if((anUsupremum >= RealLast()) || (anUinfium <= RealFirst()))
1143 du = anUsupremum - anUinfium;
1145 const Standard_Real aDelta = Max(du * DivisionFactor, MinStep);
1147 //Derivative is approximated by Taylor-series
1148 Standard_Integer anIndex = 1; //Derivative order
1153 V = theAdaptor->DN(theU, ++anIndex);
1155 while((V.SquareMagnitude() <= aTol) && anIndex < maxDerivOrder);
1159 if(theU-anUinfium < aDelta)
1165 theAdaptor->D0(Min(theU, u), P1);
1166 theAdaptor->D0(Max(theU, u), P2);
1169 IsDirectionChange = V.Dot(V1) < 0.0;
1170 Standard_Real aSign = IsDirectionChange ? -1.0 : 1.0;
1173 gp_Vec* aDeriv[3] = {&theD2, &theD3, &theD4};
1174 for (Standard_Integer i = 1; i < theMaxDerivative; i++)
1175 *(aDeriv[i-1]) = theAdaptor->DN(theU, anIndex + i) * aSign;
1177 return IsDirectionChange;