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