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 <Geom_BSplineCurve.hxx>
19 #include <Geom_Geometry.hxx>
20 #include <Geom_UndefinedDerivative.hxx>
23 #include <gp_Trsf.hxx>
25 #include <Precision.hxx>
26 #include <Standard_ConstructionError.hxx>
27 #include <Standard_DimensionError.hxx>
28 #include <Standard_DomainError.hxx>
29 #include <Standard_NoSuchObject.hxx>
30 #include <Standard_OutOfRange.hxx>
31 #include <Standard_RangeError.hxx>
33 #define POLES (poles->Array1())
34 #define KNOTS (knots->Array1())
35 #define FKNOTS (flatknots->Array1())
36 #define FMULTS (BSplCLib::NoMults())
38 //=======================================================================
41 //=======================================================================
43 Standard_Boolean Geom_BSplineCurve::IsCN ( const Standard_Integer N) const
45 Standard_RangeError_Raise_if
46 (N < 0, "Geom_BSplineCurve::IsCN");
49 case GeomAbs_CN : return Standard_True;
50 case GeomAbs_C0 : return N <= 0;
51 case GeomAbs_G1 : return N <= 0;
52 case GeomAbs_C1 : return N <= 1;
53 case GeomAbs_G2 : return N <= 1;
54 case GeomAbs_C2 : return N <= 2;
56 return N <= 3 ? Standard_True :
57 N <= deg - BSplCLib::MaxKnotMult (mults->Array1(), mults->Lower() + 1, mults->Upper() - 1);
59 return Standard_False;
62 //=======================================================================
65 //=======================================================================
67 Standard_Boolean Geom_BSplineCurve::IsG1 ( const Standard_Real theTf,
68 const Standard_Real theTl,
69 const Standard_Real theAngTol) const
76 Standard_Integer start = FirstUKnotIndex()+1,
77 finish = LastUKnotIndex()-1;
78 Standard_Integer aDeg = Degree();
79 for(Standard_Integer aNKnot = start; aNKnot <= finish; aNKnot++)
81 const Standard_Real aTpar = Knot(aNKnot);
88 Standard_Integer mult = Multiplicity(aNKnot);
94 LocalD1(aTpar, aNKnot-1, aNKnot, aP1, aV1);
95 LocalD1(aTpar, aNKnot, aNKnot+1, aP2, aV2);
97 if((aV1.SquareMagnitude() <= gp::Resolution()) ||
98 aV2.SquareMagnitude() <= gp::Resolution())
100 return Standard_False;
103 if(Abs(aV1.Angle(aV2)) > theAngTol)
104 return Standard_False;
108 return Standard_True;
110 const Standard_Real aFirstParam = FirstParameter(),
111 aLastParam = LastParameter();
113 if( ((aFirstParam - theTf)*(theTl - aFirstParam) < 0.0) &&
114 ((aLastParam - theTf)*(theTl - aLastParam) < 0.0))
116 //Range [theTf, theTl] does not intersect curve boundaries
117 return Standard_True;
120 //Curve is closed or periodic and range [theTf, theTl]
121 //intersect curve boundary. Therefore, it is necessary to
122 //check if curve is smooth in its first and last point.
126 D1(Knot(FirstUKnotIndex()), aP, aV1);
127 D1(Knot(LastUKnotIndex()), aP, aV2);
129 if((aV1.SquareMagnitude() <= gp::Resolution()) ||
130 aV2.SquareMagnitude() <= gp::Resolution())
132 return Standard_False;
135 if(Abs(aV1.Angle(aV2)) > theAngTol)
136 return Standard_False;
138 return Standard_True;
141 //=======================================================================
142 //function : IsClosed
144 //=======================================================================
146 Standard_Boolean Geom_BSplineCurve::IsClosed () const
147 //-- { return (StartPoint().Distance (EndPoint())) <= gp::Resolution (); }
148 { return (StartPoint().SquareDistance(EndPoint())) <= 1e-16; }
150 //=======================================================================
151 //function : IsPeriodic
153 //=======================================================================
155 Standard_Boolean Geom_BSplineCurve::IsPeriodic () const
158 //=======================================================================
159 //function : Continuity
161 //=======================================================================
163 GeomAbs_Shape Geom_BSplineCurve::Continuity () const
166 //=======================================================================
169 //=======================================================================
171 Standard_Integer Geom_BSplineCurve::Degree () const
174 //=======================================================================
177 //=======================================================================
179 void Geom_BSplineCurve::D0(const Standard_Real U, gp_Pnt& P) const
181 Standard_Integer aSpanIndex = 0;
182 Standard_Real aNewU(U);
183 PeriodicNormalization(aNewU);
184 BSplCLib::LocateParameter(deg, knots->Array1(), &mults->Array1(), U, periodic, aSpanIndex, aNewU);
185 if (aNewU < knots->Value(aSpanIndex))
188 BSplCLib::D0 (aNewU, aSpanIndex, deg, periodic, POLES,
189 rational ? &weights->Array1() : BSplCLib::NoWeights(),
190 knots->Array1(), &mults->Array1(),
194 //=======================================================================
197 //=======================================================================
199 void Geom_BSplineCurve::D1 (const Standard_Real U,
203 Standard_Integer aSpanIndex = 0;
204 Standard_Real aNewU(U);
205 PeriodicNormalization(aNewU);
206 BSplCLib::LocateParameter(deg, knots->Array1(), &mults->Array1(), U, periodic, aSpanIndex, aNewU);
207 if (aNewU < knots->Value(aSpanIndex))
210 BSplCLib::D1 (aNewU, aSpanIndex, deg, periodic, POLES,
211 rational ? &weights->Array1() : BSplCLib::NoWeights(),
212 knots->Array1(), &mults->Array1(),
216 //=======================================================================
219 //=======================================================================
221 void Geom_BSplineCurve::D2(const Standard_Real U,
226 Standard_Integer aSpanIndex = 0;
227 Standard_Real aNewU(U);
228 PeriodicNormalization(aNewU);
229 BSplCLib::LocateParameter(deg, knots->Array1(), &mults->Array1(), U, periodic, aSpanIndex, aNewU);
230 if (aNewU < knots->Value(aSpanIndex))
233 BSplCLib::D2 (aNewU, aSpanIndex, deg, periodic, POLES,
234 rational ? &weights->Array1() : BSplCLib::NoWeights(),
235 knots->Array1(), &mults->Array1(),
239 //=======================================================================
242 //=======================================================================
244 void Geom_BSplineCurve::D3(const Standard_Real U,
250 Standard_Integer aSpanIndex = 0;
251 Standard_Real aNewU(U);
252 PeriodicNormalization(aNewU);
253 BSplCLib::LocateParameter(deg, knots->Array1(), &mults->Array1(), U, periodic, aSpanIndex, aNewU);
254 if (aNewU < knots->Value(aSpanIndex))
257 BSplCLib::D3 (aNewU, aSpanIndex, deg, periodic, POLES,
258 rational ? &weights->Array1() : BSplCLib::NoWeights(),
259 knots->Array1(), &mults->Array1(),
263 //=======================================================================
266 //=======================================================================
268 gp_Vec Geom_BSplineCurve::DN(const Standard_Real U,
269 const Standard_Integer N) const
272 BSplCLib::DN (U, N, 0, deg, periodic, POLES,
273 rational ? &weights->Array1() : BSplCLib::NoWeights(),
278 //=======================================================================
279 //function : EndPoint
281 //=======================================================================
283 gp_Pnt Geom_BSplineCurve::EndPoint () const
285 if (mults->Value (knots->Upper ()) == deg + 1)
286 return poles->Value (poles->Upper());
288 return Value(LastParameter());
291 //=======================================================================
292 //function : FirstUKnotIndex
294 //=======================================================================
296 Standard_Integer Geom_BSplineCurve::FirstUKnotIndex () const
298 if (periodic) return 1;
299 else return BSplCLib::FirstUKnotIndex (deg, mults->Array1());
302 //=======================================================================
303 //function : FirstParameter
305 //=======================================================================
307 Standard_Real Geom_BSplineCurve::FirstParameter () const
309 return flatknots->Value (deg+1);
312 //=======================================================================
315 //=======================================================================
317 Standard_Real Geom_BSplineCurve::Knot (const Standard_Integer Index) const
319 Standard_OutOfRange_Raise_if
320 (Index < 1 || Index > knots->Length(), "Geom_BSplineCurve::Knot");
321 return knots->Value (Index);
324 //=======================================================================
325 //function : KnotDistribution
327 //=======================================================================
329 GeomAbs_BSplKnotDistribution Geom_BSplineCurve::KnotDistribution () const
334 //=======================================================================
337 //=======================================================================
339 void Geom_BSplineCurve::Knots (TColStd_Array1OfReal& K) const
341 Standard_DomainError_Raise_if (K.Lower() < knots->Lower() ||
342 K.Upper() > knots->Upper(),
343 "Geom_BSplineCurve::Knots");
344 for(Standard_Integer anIdx = K.Lower(); anIdx <= K.Upper(); anIdx++)
345 K(anIdx) = knots->Value(anIdx);
348 const TColStd_Array1OfReal& Geom_BSplineCurve::Knots() const
350 return knots->Array1();
353 //=======================================================================
354 //function : KnotSequence
356 //=======================================================================
358 void Geom_BSplineCurve::KnotSequence (TColStd_Array1OfReal& K) const
360 Standard_DomainError_Raise_if (K.Lower() < flatknots->Lower() ||
361 K.Upper() > flatknots->Upper(),
362 "Geom_BSplineCurve::KnotSequence");
363 for(Standard_Integer anIdx = K.Lower(); anIdx <= K.Upper(); anIdx++)
364 K(anIdx) = flatknots->Value(anIdx);
367 const TColStd_Array1OfReal& Geom_BSplineCurve::KnotSequence() const
369 return flatknots->Array1();
372 //=======================================================================
373 //function : LastUKnotIndex
375 //=======================================================================
377 Standard_Integer Geom_BSplineCurve::LastUKnotIndex() const
379 if (periodic) return knots->Length();
380 else return BSplCLib::LastUKnotIndex (deg, mults->Array1());
383 //=======================================================================
384 //function : LastParameter
386 //=======================================================================
388 Standard_Real Geom_BSplineCurve::LastParameter () const
390 return flatknots->Value (flatknots->Upper()-deg);
393 //=======================================================================
394 //function : LocalValue
396 //=======================================================================
398 gp_Pnt Geom_BSplineCurve::LocalValue
399 (const Standard_Real U,
400 const Standard_Integer FromK1,
401 const Standard_Integer ToK2) const
404 LocalD0(U,FromK1,ToK2,P);
408 //=======================================================================
411 //=======================================================================
413 void Geom_BSplineCurve::LocalD0
414 (const Standard_Real U,
415 const Standard_Integer FromK1,
416 const Standard_Integer ToK2,
419 Standard_DomainError_Raise_if (FromK1 == ToK2,
420 "Geom_BSplineCurve::LocalValue");
423 Standard_Integer index = 0;
424 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic,FromK1,ToK2, index,u);
425 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
426 BSplCLib::D0 (u, index, deg, periodic, POLES,
427 rational ? &weights->Array1() : BSplCLib::NoWeights(),
431 //=======================================================================
434 //=======================================================================
436 void Geom_BSplineCurve::LocalD1 (const Standard_Real U,
437 const Standard_Integer FromK1,
438 const Standard_Integer ToK2,
442 Standard_DomainError_Raise_if (FromK1 == ToK2,
443 "Geom_BSplineCurve::LocalD1");
446 Standard_Integer index = 0;
447 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
448 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
449 BSplCLib::D1 (u, index, deg, periodic, POLES,
450 rational ? &weights->Array1() : BSplCLib::NoWeights(),
454 //=======================================================================
457 //=======================================================================
459 void Geom_BSplineCurve::LocalD2
460 (const Standard_Real U,
461 const Standard_Integer FromK1,
462 const Standard_Integer ToK2,
467 Standard_DomainError_Raise_if (FromK1 == ToK2,
468 "Geom_BSplineCurve::LocalD2");
471 Standard_Integer index = 0;
472 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
473 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
474 BSplCLib::D2 (u, index, deg, periodic, POLES,
475 rational ? &weights->Array1() : BSplCLib::NoWeights(),
476 FKNOTS, FMULTS, P, V1, V2);
479 //=======================================================================
482 //=======================================================================
484 void Geom_BSplineCurve::LocalD3
485 (const Standard_Real U,
486 const Standard_Integer FromK1,
487 const Standard_Integer ToK2,
493 Standard_DomainError_Raise_if (FromK1 == ToK2,
494 "Geom_BSplineCurve::LocalD3");
497 Standard_Integer index = 0;
498 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
499 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
500 BSplCLib::D3 (u, index, deg, periodic, POLES,
501 rational ? &weights->Array1() : BSplCLib::NoWeights(),
502 FKNOTS, FMULTS, P, V1, V2, V3);
505 //=======================================================================
508 //=======================================================================
510 gp_Vec Geom_BSplineCurve::LocalDN
511 (const Standard_Real U,
512 const Standard_Integer FromK1,
513 const Standard_Integer ToK2,
514 const Standard_Integer N ) const
516 Standard_DomainError_Raise_if (FromK1 == ToK2,
517 "Geom_BSplineCurve::LocalD3");
520 Standard_Integer index = 0;
521 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
522 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
525 BSplCLib::DN (u, N, index, deg, periodic, POLES,
526 rational ? &weights->Array1() : BSplCLib::NoWeights(),
531 //=======================================================================
532 //function : Multiplicity
534 //=======================================================================
536 Standard_Integer Geom_BSplineCurve::Multiplicity
537 (const Standard_Integer Index) const
539 Standard_OutOfRange_Raise_if (Index < 1 || Index > mults->Length(),
540 "Geom_BSplineCurve::Multiplicity");
541 return mults->Value (Index);
544 //=======================================================================
545 //function : Multiplicities
547 //=======================================================================
549 void Geom_BSplineCurve::Multiplicities (TColStd_Array1OfInteger& M) const
551 Standard_DimensionError_Raise_if (M.Length() != mults->Length(),
552 "Geom_BSplineCurve::Multiplicities");
556 const TColStd_Array1OfInteger& Geom_BSplineCurve::Multiplicities() const
558 return mults->Array1();
561 //=======================================================================
564 //=======================================================================
566 Standard_Integer Geom_BSplineCurve::NbKnots () const
567 { return knots->Length(); }
569 //=======================================================================
572 //=======================================================================
574 Standard_Integer Geom_BSplineCurve::NbPoles () const
575 { return poles->Length(); }
577 //=======================================================================
580 //=======================================================================
582 const gp_Pnt& Geom_BSplineCurve::Pole (const Standard_Integer Index) const
584 Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
585 "Geom_BSplineCurve::Pole");
586 return poles->Value (Index);
589 //=======================================================================
592 //=======================================================================
594 void Geom_BSplineCurve::Poles (TColgp_Array1OfPnt& P) const
596 Standard_DimensionError_Raise_if (P.Length() != poles->Length(),
597 "Geom_BSplineCurve::Poles");
601 const TColgp_Array1OfPnt& Geom_BSplineCurve::Poles() const
603 return poles->Array1();
606 //=======================================================================
607 //function : StartPoint
609 //=======================================================================
611 gp_Pnt Geom_BSplineCurve::StartPoint () const
613 if (mults->Value (1) == deg + 1)
614 return poles->Value (1);
616 return Value(FirstParameter());
619 //=======================================================================
622 //=======================================================================
624 Standard_Real Geom_BSplineCurve::Weight
625 (const Standard_Integer Index) const
627 Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
628 "Geom_BSplineCurve::Weight");
630 return weights->Value (Index);
635 //=======================================================================
638 //=======================================================================
640 void Geom_BSplineCurve::Weights
641 (TColStd_Array1OfReal& W) const
643 Standard_DimensionError_Raise_if (W.Length() != poles->Length(),
644 "Geom_BSplineCurve::Weights");
646 W = weights->Array1();
650 for (i = W.Lower(); i <= W.Upper(); i++)
655 const TColStd_Array1OfReal* Geom_BSplineCurve::Weights() const
658 return &weights->Array1();
659 return BSplCLib::NoWeights();
662 //=======================================================================
663 //function : IsRational
665 //=======================================================================
667 Standard_Boolean Geom_BSplineCurve::IsRational () const
669 return !weights.IsNull();
672 //=======================================================================
673 //function : Transform
675 //=======================================================================
677 void Geom_BSplineCurve::Transform
680 TColgp_Array1OfPnt & CPoles = poles->ChangeArray1();
681 for (Standard_Integer I = 1; I <= CPoles.Length(); I++)
682 CPoles (I).Transform (T);
686 //=======================================================================
689 // pmn : 30/01/97 mise en conformite avec le cdl, lorsque U est un noeud
691 //=======================================================================
693 void Geom_BSplineCurve::LocateU
694 (const Standard_Real U,
695 const Standard_Real ParametricTolerance,
696 Standard_Integer& I1,
697 Standard_Integer& I2,
698 const Standard_Boolean WithKnotRepetition) const
700 Standard_Real NewU = U;
701 Handle(TColStd_HArray1OfReal) TheKnots;
702 if (WithKnotRepetition) TheKnots = flatknots;
703 else TheKnots = knots;
704 const TColStd_Array1OfReal & CKnots = TheKnots->Array1();
706 PeriodicNormalization(NewU); //Attention a la periode
708 Standard_Real UFirst = CKnots (1);
709 Standard_Real ULast = CKnots (CKnots.Length());
710 Standard_Real PParametricTolerance = Abs(ParametricTolerance);
711 if (Abs (NewU - UFirst) <= PParametricTolerance) { I1 = I2 = 1; }
712 else if (Abs (NewU - ULast) <= PParametricTolerance) {
713 I1 = I2 = CKnots.Length();
715 else if (NewU < UFirst) {
719 else if (NewU > ULast) {
720 I1 = CKnots.Length();
725 BSplCLib::Hunt (CKnots, NewU, I1);
726 I1 = Max (Min (I1, CKnots.Upper()), CKnots.Lower());
727 while (I1 + 1 <= CKnots.Upper()
728 && Abs (CKnots (I1 + 1) - NewU) <= PParametricTolerance)
732 if ( Abs( CKnots(I1) - NewU) <= PParametricTolerance) {
741 //=======================================================================
742 //function : Resolution
744 //=======================================================================
746 void Geom_BSplineCurve::Resolution (const Standard_Real Tolerance3D,
747 Standard_Real& UTolerance)
753 Standard_Integer NbKnots, NbPoles;
754 BSplCLib::PrepareUnperiodize (deg, mults->Array1(), NbKnots, NbPoles);
755 TColgp_Array1OfPnt new_poles (1, NbPoles);
756 TColStd_Array1OfReal new_weights(1, NbPoles);
757 for (Standard_Integer ii = 1; ii <= NbPoles; ii++)
759 new_poles(ii) = poles->Array1()((ii-1) % poles->Length() + 1);
763 for (Standard_Integer ii = 1; ii <= NbPoles; ii++)
765 new_weights(ii) = weights->Array1()((ii-1) % poles->Length() + 1);
768 BSplCLib::Resolution (new_poles,
769 rational ? &new_weights : BSplCLib::NoWeights(),
778 BSplCLib::Resolution (poles->Array1(),
779 rational ? &weights->Array1() : BSplCLib::NoWeights(),
788 UTolerance = Tolerance3D * maxderivinv;
791 //=======================================================================
794 //=======================================================================
796 Standard_Boolean Geom_BSplineCurve::IsEqual(const Handle(Geom_BSplineCurve)& theOther,
797 const Standard_Real thePreci) const
799 if( knots.IsNull() || poles.IsNull() || mults.IsNull() )
800 return Standard_False;
801 if( deg != theOther->Degree())
802 return Standard_False;
803 if( knots->Length() != theOther->NbKnots() ||
804 poles->Length() != theOther->NbPoles())
805 return Standard_False;
807 Standard_Integer i = 1;
808 for( i = 1 ; i <= poles->Length(); i++ )
810 const gp_Pnt& aPole1 = poles->Value(i);
811 const gp_Pnt& aPole2 =theOther->Pole(i);
812 if( fabs( aPole1.X() - aPole2.X() ) > thePreci ||
813 fabs( aPole1.Y() - aPole2.Y() ) > thePreci ||
814 fabs( aPole1.Z() - aPole2.Z() ) > thePreci )
815 return Standard_False;
818 for( ; i <= knots->Length(); i++ )
820 if( fabs(knots->Value(i) - theOther->Knot(i)) > Precision::Parametric(thePreci) )
821 return Standard_False;
824 for( i = 1 ; i <= mults->Length(); i++ )
826 if( mults->Value(i) != theOther->Multiplicity(i) )
827 return Standard_False;
830 if( rational != theOther->IsRational())
831 return Standard_False;
834 return Standard_True;
836 for( i = 1 ; i <= weights->Length(); i++ )
838 if( fabs( Standard_Real(weights->Value(i) - theOther->Weight(i))) > Epsilon(weights->Value(i)) )
839 return Standard_False;
841 return Standard_True;