1 // Created on: 1991-07-05
3 // Copyright (c) 1991-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 #include <BSplCLib.hxx>
18 #include <Geom2d_BSplineCurve.hxx>
19 #include <Geom2d_UndefinedDerivative.hxx>
21 #include <gp_Pnt2d.hxx>
22 #include <gp_Trsf2d.hxx>
23 #include <gp_Vec2d.hxx>
24 #include <Precision.hxx>
25 #include <Standard_DimensionError.hxx>
26 #include <Standard_DomainError.hxx>
27 #include <Standard_OutOfRange.hxx>
28 #include <Standard_RangeError.hxx>
30 #define POLES (poles->Array1())
31 #define KNOTS (knots->Array1())
32 #define FKNOTS (flatknots->Array1())
33 #define FMULTS (BSplCLib::NoMults())
35 //=======================================================================
38 //=======================================================================
40 Standard_Boolean Geom2d_BSplineCurve::IsCN ( const Standard_Integer N) const
42 Standard_RangeError_Raise_if
43 (N < 0, "Geom2d_BSplineCurve::IsCN");
46 case GeomAbs_CN : return Standard_True;
47 case GeomAbs_C0 : return N <= 0;
48 case GeomAbs_G1 : return N <= 0;
49 case GeomAbs_C1 : return N <= 1;
50 case GeomAbs_G2 : return N <= 1;
51 case GeomAbs_C2 : return N <= 2;
53 return N <= 3 ? Standard_True :
54 N <= deg - BSplCLib::MaxKnotMult (mults->Array1(), mults->Lower() + 1, mults->Upper() - 1);
56 return Standard_False;
59 //=======================================================================
62 //=======================================================================
64 Standard_Boolean Geom2d_BSplineCurve::IsG1 ( const Standard_Real theTf,
65 const Standard_Real theTl,
66 const Standard_Real theAngTol) const
74 Standard_Integer start = FirstUKnotIndex()+1,
75 finish = LastUKnotIndex()-1;
76 Standard_Integer aDeg = Degree();
77 for(Standard_Integer aNKnot = start; aNKnot <= finish; aNKnot++)
79 const Standard_Real aTpar = Knot(aNKnot);
86 Standard_Integer mult = Multiplicity(aNKnot);
92 LocalD1(aTpar, aNKnot-1, aNKnot, aP1, aV1);
93 LocalD1(aTpar, aNKnot, aNKnot+1, aP2, aV2);
95 if((aV1.SquareMagnitude() <= gp::Resolution()) ||
96 aV2.SquareMagnitude() <= gp::Resolution())
98 return Standard_False;
101 if(Abs(aV1.Angle(aV2)) > theAngTol)
102 return Standard_False;
106 return Standard_True;
108 const Standard_Real aFirstParam = FirstParameter(),
109 aLastParam = LastParameter();
111 if( ((aFirstParam - theTf)*(theTl - aFirstParam) < 0.0) &&
112 ((aLastParam - theTf)*(theTl - aLastParam) < 0.0))
114 //Range [theTf, theTl] does not intersect curve boundaries
115 return Standard_True;
118 //Curve is closed or periodic and range [theTf, theTl]
119 //intersect curve boundary. Therefore, it is necessary to
120 //check if curve is smooth in its first and last point.
124 D1(Knot(FirstUKnotIndex()), aP, aV1);
125 D1(Knot(LastUKnotIndex()), aP, aV2);
127 if((aV1.SquareMagnitude() <= gp::Resolution()) ||
128 aV2.SquareMagnitude() <= gp::Resolution())
130 return Standard_False;
133 if(Abs(aV1.Angle(aV2)) > theAngTol)
134 return Standard_False;
137 return Standard_True;
141 //=======================================================================
142 //function : IsClosed
144 //=======================================================================
146 Standard_Boolean Geom2d_BSplineCurve::IsClosed () const
147 { return (StartPoint().Distance (EndPoint())) <= gp::Resolution (); }
151 //=======================================================================
152 //function : IsPeriodic
154 //=======================================================================
156 Standard_Boolean Geom2d_BSplineCurve::IsPeriodic () const
159 //=======================================================================
160 //function : Continuity
162 //=======================================================================
164 GeomAbs_Shape Geom2d_BSplineCurve::Continuity () const
167 //=======================================================================
170 //=======================================================================
172 Standard_Integer Geom2d_BSplineCurve::Degree () const
176 //=======================================================================
179 //=======================================================================
181 void Geom2d_BSplineCurve::D0(const Standard_Real U,
184 Standard_Integer aSpanIndex = 0;
185 Standard_Real aNewU(U);
186 PeriodicNormalization(aNewU);
187 BSplCLib::LocateParameter(deg, knots->Array1(), &mults->Array1(), U, periodic, aSpanIndex, aNewU);
188 if (aNewU < knots->Value(aSpanIndex))
191 BSplCLib::D0 (aNewU, aSpanIndex, deg, periodic, POLES,
192 rational ? &weights->Array1() : BSplCLib::NoWeights(),
193 knots->Array1(), &mults->Array1(),
198 //=======================================================================
201 //=======================================================================
203 void Geom2d_BSplineCurve::D1(const Standard_Real U,
207 Standard_Integer aSpanIndex = 0;
208 Standard_Real aNewU(U);
209 PeriodicNormalization(aNewU);
210 BSplCLib::LocateParameter(deg, knots->Array1(), &mults->Array1(), U, periodic, aSpanIndex, aNewU);
211 if (aNewU < knots->Value(aSpanIndex))
214 BSplCLib::D1 (aNewU, aSpanIndex, deg, periodic, POLES,
215 rational ? &weights->Array1() : BSplCLib::NoWeights(),
216 knots->Array1(), &mults->Array1(),
220 //=======================================================================
223 //=======================================================================
225 void Geom2d_BSplineCurve::D2(const Standard_Real U,
230 Standard_Integer aSpanIndex = 0;
231 Standard_Real aNewU(U);
232 PeriodicNormalization(aNewU);
233 BSplCLib::LocateParameter(deg, knots->Array1(), &mults->Array1(), U, periodic, aSpanIndex, aNewU);
234 if (aNewU < knots->Value(aSpanIndex))
237 BSplCLib::D2 (aNewU, aSpanIndex, deg, periodic, POLES,
238 rational ? &weights->Array1() : BSplCLib::NoWeights(),
239 knots->Array1(), &mults->Array1(),
243 //=======================================================================
246 //=======================================================================
248 void Geom2d_BSplineCurve::D3(const Standard_Real U,
254 Standard_Integer aSpanIndex = 0;
255 Standard_Real aNewU(U);
256 PeriodicNormalization(aNewU);
257 BSplCLib::LocateParameter(deg, knots->Array1(), &mults->Array1(), U, periodic, aSpanIndex, aNewU);
258 if (aNewU < knots->Value(aSpanIndex))
261 BSplCLib::D3 (aNewU, aSpanIndex, deg, periodic, POLES,
262 rational ? &weights->Array1() : BSplCLib::NoWeights(),
263 knots->Array1(), &mults->Array1(),
267 //=======================================================================
270 //=======================================================================
272 gp_Vec2d Geom2d_BSplineCurve::DN(const Standard_Real U,
273 const Standard_Integer N) const
276 BSplCLib::DN (U, N, 0, deg, periodic, POLES,
277 rational ? &weights->Array1() : BSplCLib::NoWeights(),
282 //=======================================================================
283 //function : EndPoint
285 //=======================================================================
287 gp_Pnt2d Geom2d_BSplineCurve::EndPoint () const
289 if (mults->Value (knots->Upper ()) == deg + 1)
290 return poles->Value (poles->Upper());
292 return Value(LastParameter());
295 //=======================================================================
296 //function : FirstUKnotIndex
298 //=======================================================================
300 Standard_Integer Geom2d_BSplineCurve::FirstUKnotIndex () const
302 if (periodic) return 1;
303 else return BSplCLib::FirstUKnotIndex (deg, mults->Array1());
306 //=======================================================================
307 //function : FirstParameter
309 //=======================================================================
311 Standard_Real Geom2d_BSplineCurve::FirstParameter () const
313 return flatknots->Value (deg+1);
316 //=======================================================================
319 //=======================================================================
321 Standard_Real Geom2d_BSplineCurve::Knot (const Standard_Integer Index) const
323 Standard_OutOfRange_Raise_if
324 (Index < 1 || Index > knots->Length(), "Geom2d_BSplineCurve::Knot");
325 return knots->Value (Index);
328 //=======================================================================
329 //function : KnotDistribution
331 //=======================================================================
333 GeomAbs_BSplKnotDistribution Geom2d_BSplineCurve::KnotDistribution () const
338 //=======================================================================
341 //=======================================================================
343 void Geom2d_BSplineCurve::Knots (TColStd_Array1OfReal& K) const
345 Standard_DomainError_Raise_if (K.Lower() < knots->Lower() ||
346 K.Upper() > knots->Upper(),
347 "Geom2d_BSplineCurve::Knots");
348 for(Standard_Integer anIdx = K.Lower(); anIdx <= K.Upper(); anIdx++)
349 K(anIdx) = knots->Value(anIdx);
352 const TColStd_Array1OfReal& Geom2d_BSplineCurve::Knots() const
354 return knots->Array1();
357 //=======================================================================
358 //function : KnotSequence
360 //=======================================================================
362 void Geom2d_BSplineCurve::KnotSequence (TColStd_Array1OfReal& K) const
364 Standard_DomainError_Raise_if (K.Lower() < flatknots->Lower() ||
365 K.Upper() > flatknots->Upper(),
366 "Geom2d_BSplineCurve::KnotSequence");
367 for(Standard_Integer anIdx = K.Lower(); anIdx <= K.Upper(); anIdx++)
368 K(anIdx) = flatknots->Value(anIdx);
371 const TColStd_Array1OfReal& Geom2d_BSplineCurve::KnotSequence() const
373 return flatknots->Array1();
376 //=======================================================================
377 //function : LastUKnotIndex
379 //=======================================================================
381 Standard_Integer Geom2d_BSplineCurve::LastUKnotIndex() const
383 if (periodic) return knots->Length();
384 else return BSplCLib::LastUKnotIndex (deg, mults->Array1());
387 //=======================================================================
388 //function : LastParameter
390 //=======================================================================
392 Standard_Real Geom2d_BSplineCurve::LastParameter () const
394 return flatknots->Value (flatknots->Upper()-deg);
397 //=======================================================================
398 //function : LocalValue
400 //=======================================================================
402 gp_Pnt2d Geom2d_BSplineCurve::LocalValue
403 (const Standard_Real U,
404 const Standard_Integer FromK1,
405 const Standard_Integer ToK2) const
408 LocalD0(U,FromK1,ToK2,P);
412 //=======================================================================
415 //=======================================================================
417 void Geom2d_BSplineCurve::LocalD0
418 (const Standard_Real U,
419 const Standard_Integer FromK1,
420 const Standard_Integer ToK2,
423 Standard_DomainError_Raise_if (FromK1 == ToK2,
424 "Geom2d_BSplineCurve::LocalValue");
427 Standard_Integer index = 0;
428 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic,FromK1,ToK2, index,u);
429 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
431 BSplCLib::D0 (u, index, deg, periodic, POLES,
432 rational ? &weights->Array1() : BSplCLib::NoWeights(),
436 //=======================================================================
439 //=======================================================================
441 void Geom2d_BSplineCurve::LocalD1 (const Standard_Real U,
442 const Standard_Integer FromK1,
443 const Standard_Integer ToK2,
447 Standard_DomainError_Raise_if (FromK1 == ToK2,
448 "Geom2d_BSplineCurve::LocalD1");
451 Standard_Integer index = 0;
452 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
453 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
455 BSplCLib::D1 (u, index, deg, periodic, POLES,
456 rational ? &weights->Array1() : BSplCLib::NoWeights(),
457 FKNOTS, FMULTS, P, V1);
460 //=======================================================================
463 //=======================================================================
465 void Geom2d_BSplineCurve::LocalD2
466 (const Standard_Real U,
467 const Standard_Integer FromK1,
468 const Standard_Integer ToK2,
473 Standard_DomainError_Raise_if (FromK1 == ToK2,
474 "Geom2d_BSplineCurve::LocalD2");
477 Standard_Integer index = 0;
478 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
479 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
481 BSplCLib::D2 (u, index, deg, periodic, POLES,
482 rational ? &weights->Array1() : BSplCLib::NoWeights(),
483 FKNOTS, FMULTS, P, V1, V2);
486 //=======================================================================
489 //=======================================================================
491 void Geom2d_BSplineCurve::LocalD3
492 (const Standard_Real U,
493 const Standard_Integer FromK1,
494 const Standard_Integer ToK2,
500 Standard_DomainError_Raise_if (FromK1 == ToK2,
501 "Geom2d_BSplineCurve::LocalD3");
504 Standard_Integer index = 0;
505 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
506 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
508 BSplCLib::D3 (u, index, deg, periodic, POLES,
509 rational ? &weights->Array1() : BSplCLib::NoWeights(),
510 FKNOTS, FMULTS, P, V1, V2, V3);
513 //=======================================================================
516 //=======================================================================
518 gp_Vec2d Geom2d_BSplineCurve::LocalDN
519 (const Standard_Real U,
520 const Standard_Integer FromK1,
521 const Standard_Integer ToK2,
522 const Standard_Integer N ) const
524 Standard_DomainError_Raise_if (FromK1 == ToK2,
525 "Geom2d_BSplineCurve::LocalD3");
528 Standard_Integer index = 0;
529 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
530 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
533 BSplCLib::DN (u, N, index, deg, periodic, POLES,
534 rational ? &weights->Array1() : BSplCLib::NoWeights(),
539 //=======================================================================
540 //function : Multiplicity
542 //=======================================================================
544 Standard_Integer Geom2d_BSplineCurve::Multiplicity
545 (const Standard_Integer Index) const
547 Standard_OutOfRange_Raise_if (Index < 1 || Index > mults->Length(),
548 "Geom2d_BSplineCurve::Multiplicity");
549 return mults->Value (Index);
552 //=======================================================================
553 //function : Multiplicities
555 //=======================================================================
557 void Geom2d_BSplineCurve::Multiplicities (TColStd_Array1OfInteger& M) const
559 Standard_DimensionError_Raise_if (M.Length() != mults->Length(),
560 "Geom2d_BSplineCurve::Multiplicities");
564 const TColStd_Array1OfInteger& Geom2d_BSplineCurve::Multiplicities() const
566 return mults->Array1();
569 //=======================================================================
572 //=======================================================================
574 Standard_Integer Geom2d_BSplineCurve::NbKnots () const
575 { return knots->Length(); }
577 //=======================================================================
580 //=======================================================================
582 Standard_Integer Geom2d_BSplineCurve::NbPoles () const
583 { return poles->Length(); }
585 //=======================================================================
588 //=======================================================================
590 const gp_Pnt2d& Geom2d_BSplineCurve::Pole (const Standard_Integer Index) const
592 Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
593 "Geom2d_BSplineCurve::Pole");
594 return poles->Value (Index);
597 //=======================================================================
600 //=======================================================================
602 void Geom2d_BSplineCurve::Poles (TColgp_Array1OfPnt2d& P) const
604 Standard_DimensionError_Raise_if (P.Length() != poles->Length(),
605 "Geom2d_BSplineCurve::Poles");
609 const TColgp_Array1OfPnt2d& Geom2d_BSplineCurve::Poles() const
611 return poles->Array1();
614 //=======================================================================
615 //function : StartPoint
617 //=======================================================================
619 gp_Pnt2d Geom2d_BSplineCurve::StartPoint () const
621 if (mults->Value (1) == deg + 1)
622 return poles->Value (1);
624 return Value(FirstParameter());
627 //=======================================================================
630 //=======================================================================
632 Standard_Real Geom2d_BSplineCurve::Weight
633 (const Standard_Integer Index) const
635 Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
636 "Geom2d_BSplineCurve::Weight");
638 return weights->Value (Index);
643 //=======================================================================
646 //=======================================================================
648 void Geom2d_BSplineCurve::Weights
649 (TColStd_Array1OfReal& W) const
651 Standard_DimensionError_Raise_if (W.Length() != poles->Length(),
652 "Geom2d_BSplineCurve::Weights");
654 W = weights->Array1();
657 for (i = W.Lower(); i <= W.Upper(); i++)
662 const TColStd_Array1OfReal* Geom2d_BSplineCurve::Weights() const
665 return &weights->Array1();
666 return BSplCLib::NoWeights();
669 //=======================================================================
670 //function : IsRational
672 //=======================================================================
674 Standard_Boolean Geom2d_BSplineCurve::IsRational () const
676 return !weights.IsNull();
679 //=======================================================================
680 //function : Transform
682 //=======================================================================
684 void Geom2d_BSplineCurve::Transform
687 TColgp_Array1OfPnt2d & CPoles = poles->ChangeArray1();
688 for (Standard_Integer I = 1; I <= CPoles.Length(); I++)
689 CPoles (I).Transform (T);
691 // maxderivinvok = 0;
694 //=======================================================================
697 //=======================================================================
699 void Geom2d_BSplineCurve::LocateU
700 (const Standard_Real U,
701 const Standard_Real ParametricTolerance,
702 Standard_Integer& I1,
703 Standard_Integer& I2,
704 const Standard_Boolean WithKnotRepetition) const
706 Standard_Real NewU = U;
707 Handle(TColStd_HArray1OfReal) TheKnots;
708 if (WithKnotRepetition) TheKnots = flatknots;
709 else TheKnots = knots;
711 const TColStd_Array1OfReal & CKnots = TheKnots->Array1();
713 PeriodicNormalization(NewU); //Attention a la periode
714 Standard_Real UFirst = CKnots (1);
715 Standard_Real ULast = CKnots (CKnots.Length());
716 Standard_Real PParametricTolerance = Abs(ParametricTolerance);
717 if (Abs (NewU - UFirst) <= PParametricTolerance) { I1 = I2 = 1; }
718 else if (Abs (NewU - ULast) <= PParametricTolerance) {
719 I1 = I2 = CKnots.Length();
721 else if (NewU < UFirst) {
725 else if (NewU > ULast) {
726 I1 = CKnots.Length();
731 BSplCLib::Hunt (CKnots, NewU, I1);
732 I1 = Max (Min (I1, CKnots.Upper()), CKnots.Lower());
733 while (I1 + 1 <= CKnots.Upper()
734 && Abs (CKnots (I1 + 1) - NewU) <= PParametricTolerance)
738 if ( Abs( CKnots(I1) - NewU) <= PParametricTolerance) {
747 //=======================================================================
748 //function : Resolution
750 //=======================================================================
752 void Geom2d_BSplineCurve::Resolution (const Standard_Real ToleranceUV,
753 Standard_Real& UTolerance)
759 Standard_Integer NbKnots, NbPoles;
760 BSplCLib::PrepareUnperiodize (deg, mults->Array1(), NbKnots, NbPoles);
761 TColgp_Array1OfPnt2d new_poles (1, NbPoles);
762 TColStd_Array1OfReal new_weights (1, NbPoles);
763 for (Standard_Integer ii = 1; ii <= NbPoles ; ii++)
765 new_poles (ii) = poles->Array1()(((ii-1) % poles->Length()) + 1);
769 for (Standard_Integer ii = 1; ii <= NbPoles; ii++)
771 new_weights (ii) = weights->Array1()(((ii-1) % poles->Length()) + 1);
774 BSplCLib::Resolution (new_poles,
775 rational ? &new_weights : BSplCLib::NoWeights(),
784 BSplCLib::Resolution (poles->Array1(),
785 rational ? &weights->Array1() : BSplCLib::NoWeights(),
794 UTolerance = ToleranceUV * maxderivinv;