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 bounadries
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))
189 BSplCLib::D0(aNewU,aSpanIndex,deg,periodic,POLES,
191 knots->Array1(), &mults->Array1(),
196 BSplCLib::D0(aNewU,aSpanIndex,deg,periodic,POLES,
197 BSplCLib::NoWeights(),
198 knots->Array1(), &mults->Array1(),
203 //=======================================================================
206 //=======================================================================
208 void Geom_BSplineCurve::D1 (const Standard_Real U,
212 Standard_Integer aSpanIndex = 0;
213 Standard_Real aNewU(U);
214 PeriodicNormalization(aNewU);
215 BSplCLib::LocateParameter(deg, knots->Array1(), &mults->Array1(), U, periodic, aSpanIndex, aNewU);
216 if (aNewU < knots->Value(aSpanIndex))
220 BSplCLib::D1(aNewU,aSpanIndex,deg,periodic,POLES,
222 knots->Array1(), &mults->Array1(),
227 BSplCLib::D1(aNewU,aSpanIndex,deg,periodic,POLES,
228 BSplCLib::NoWeights(),
229 knots->Array1(), &mults->Array1(),
234 //=======================================================================
237 //=======================================================================
239 void Geom_BSplineCurve::D2(const Standard_Real U,
244 Standard_Integer aSpanIndex = 0;
245 Standard_Real aNewU(U);
246 PeriodicNormalization(aNewU);
247 BSplCLib::LocateParameter(deg, knots->Array1(), &mults->Array1(), U, periodic, aSpanIndex, aNewU);
248 if (aNewU < knots->Value(aSpanIndex))
252 BSplCLib::D2(aNewU,aSpanIndex,deg,periodic,POLES,
254 knots->Array1(), &mults->Array1(),
259 BSplCLib::D2(aNewU,aSpanIndex,deg,periodic,POLES,
260 BSplCLib::NoWeights(),
261 knots->Array1(), &mults->Array1(),
266 //=======================================================================
269 //=======================================================================
271 void Geom_BSplineCurve::D3(const Standard_Real U,
277 Standard_Integer aSpanIndex = 0;
278 Standard_Real aNewU(U);
279 PeriodicNormalization(aNewU);
280 BSplCLib::LocateParameter(deg, knots->Array1(), &mults->Array1(), U, periodic, aSpanIndex, aNewU);
281 if (aNewU < knots->Value(aSpanIndex))
285 BSplCLib::D3(aNewU,aSpanIndex,deg,periodic,POLES,
287 knots->Array1(), &mults->Array1(),
292 BSplCLib::D3(aNewU,aSpanIndex,deg,periodic,POLES,
293 BSplCLib::NoWeights(),
294 knots->Array1(), &mults->Array1(),
299 //=======================================================================
302 //=======================================================================
304 gp_Vec Geom_BSplineCurve::DN(const Standard_Real U,
305 const Standard_Integer N) const
309 BSplCLib::DN(U,N,0,deg,periodic,POLES,
314 BSplCLib::DN(U,N,0,deg,periodic,POLES,
315 BSplCLib::NoWeights(),
321 //=======================================================================
322 //function : EndPoint
324 //=======================================================================
326 gp_Pnt Geom_BSplineCurve::EndPoint () const
328 if (mults->Value (knots->Upper ()) == deg + 1)
329 return poles->Value (poles->Upper());
331 return Value(LastParameter());
334 //=======================================================================
335 //function : FirstUKnotIndex
337 //=======================================================================
339 Standard_Integer Geom_BSplineCurve::FirstUKnotIndex () const
341 if (periodic) return 1;
342 else return BSplCLib::FirstUKnotIndex (deg, mults->Array1());
345 //=======================================================================
346 //function : FirstParameter
348 //=======================================================================
350 Standard_Real Geom_BSplineCurve::FirstParameter () const
352 return flatknots->Value (deg+1);
355 //=======================================================================
358 //=======================================================================
360 Standard_Real Geom_BSplineCurve::Knot (const Standard_Integer Index) const
362 Standard_OutOfRange_Raise_if
363 (Index < 1 || Index > knots->Length(), "Geom_BSplineCurve::Knot");
364 return knots->Value (Index);
367 //=======================================================================
368 //function : KnotDistribution
370 //=======================================================================
372 GeomAbs_BSplKnotDistribution Geom_BSplineCurve::KnotDistribution () const
377 //=======================================================================
380 //=======================================================================
382 void Geom_BSplineCurve::Knots (TColStd_Array1OfReal& K) const
384 Standard_DomainError_Raise_if (K.Lower() < knots->Lower() ||
385 K.Upper() > knots->Upper(),
386 "Geom_BSplineCurve::Knots");
387 for(Standard_Integer anIdx = K.Lower(); anIdx <= K.Upper(); anIdx++)
388 K(anIdx) = knots->Value(anIdx);
391 const TColStd_Array1OfReal& Geom_BSplineCurve::Knots() const
393 return knots->Array1();
396 //=======================================================================
397 //function : KnotSequence
399 //=======================================================================
401 void Geom_BSplineCurve::KnotSequence (TColStd_Array1OfReal& K) const
403 Standard_DomainError_Raise_if (K.Lower() < flatknots->Lower() ||
404 K.Upper() > flatknots->Upper(),
405 "Geom_BSplineCurve::KnotSequence");
406 for(Standard_Integer anIdx = K.Lower(); anIdx <= K.Upper(); anIdx++)
407 K(anIdx) = flatknots->Value(anIdx);
410 const TColStd_Array1OfReal& Geom_BSplineCurve::KnotSequence() const
412 return flatknots->Array1();
415 //=======================================================================
416 //function : LastUKnotIndex
418 //=======================================================================
420 Standard_Integer Geom_BSplineCurve::LastUKnotIndex() const
422 if (periodic) return knots->Length();
423 else return BSplCLib::LastUKnotIndex (deg, mults->Array1());
426 //=======================================================================
427 //function : LastParameter
429 //=======================================================================
431 Standard_Real Geom_BSplineCurve::LastParameter () const
433 return flatknots->Value (flatknots->Upper()-deg);
436 //=======================================================================
437 //function : LocalValue
439 //=======================================================================
441 gp_Pnt Geom_BSplineCurve::LocalValue
442 (const Standard_Real U,
443 const Standard_Integer FromK1,
444 const Standard_Integer ToK2) const
447 LocalD0(U,FromK1,ToK2,P);
451 //=======================================================================
454 //=======================================================================
456 void Geom_BSplineCurve::LocalD0
457 (const Standard_Real U,
458 const Standard_Integer FromK1,
459 const Standard_Integer ToK2,
462 Standard_DomainError_Raise_if (FromK1 == ToK2,
463 "Geom_BSplineCurve::LocalValue");
466 Standard_Integer index = 0;
467 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic,FromK1,ToK2, index,u);
468 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
470 BSplCLib::D0(u,index,deg,periodic,POLES,
475 BSplCLib::D0(u,index,deg,periodic,POLES,
476 BSplCLib::NoWeights(),
481 //=======================================================================
484 //=======================================================================
486 void Geom_BSplineCurve::LocalD1 (const Standard_Real U,
487 const Standard_Integer FromK1,
488 const Standard_Integer ToK2,
492 Standard_DomainError_Raise_if (FromK1 == ToK2,
493 "Geom_BSplineCurve::LocalD1");
496 Standard_Integer index = 0;
497 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
498 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
500 BSplCLib::D1(u,index,deg,periodic,POLES,
505 BSplCLib::D1(u,index,deg,periodic,POLES,
506 BSplCLib::NoWeights(),
511 //=======================================================================
514 //=======================================================================
516 void Geom_BSplineCurve::LocalD2
517 (const Standard_Real U,
518 const Standard_Integer FromK1,
519 const Standard_Integer ToK2,
524 Standard_DomainError_Raise_if (FromK1 == ToK2,
525 "Geom_BSplineCurve::LocalD2");
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);
532 BSplCLib::D2(u,index,deg,periodic,POLES,
534 FKNOTS,FMULTS,P,V1,V2);
537 BSplCLib::D2(u,index,deg,periodic,POLES,
538 BSplCLib::NoWeights(),
539 FKNOTS,FMULTS,P,V1,V2);
543 //=======================================================================
546 //=======================================================================
548 void Geom_BSplineCurve::LocalD3
549 (const Standard_Real U,
550 const Standard_Integer FromK1,
551 const Standard_Integer ToK2,
557 Standard_DomainError_Raise_if (FromK1 == ToK2,
558 "Geom_BSplineCurve::LocalD3");
561 Standard_Integer index = 0;
562 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
563 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
565 BSplCLib::D3(u,index,deg,periodic,POLES,
567 FKNOTS,FMULTS,P,V1,V2,V3);
570 BSplCLib::D3(u,index,deg,periodic,POLES,
571 BSplCLib::NoWeights(),
572 FKNOTS,FMULTS,P,V1,V2,V3);
576 //=======================================================================
579 //=======================================================================
581 gp_Vec Geom_BSplineCurve::LocalDN
582 (const Standard_Real U,
583 const Standard_Integer FromK1,
584 const Standard_Integer ToK2,
585 const Standard_Integer N ) const
587 Standard_DomainError_Raise_if (FromK1 == ToK2,
588 "Geom_BSplineCurve::LocalD3");
591 Standard_Integer index = 0;
592 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
593 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
597 BSplCLib::DN(u,N,index,deg,periodic,POLES,
602 BSplCLib::DN(u,N,index,deg,periodic,POLES,
603 BSplCLib::NoWeights(),
609 //=======================================================================
610 //function : Multiplicity
612 //=======================================================================
614 Standard_Integer Geom_BSplineCurve::Multiplicity
615 (const Standard_Integer Index) const
617 Standard_OutOfRange_Raise_if (Index < 1 || Index > mults->Length(),
618 "Geom_BSplineCurve::Multiplicity");
619 return mults->Value (Index);
622 //=======================================================================
623 //function : Multiplicities
625 //=======================================================================
627 void Geom_BSplineCurve::Multiplicities (TColStd_Array1OfInteger& M) const
629 Standard_DimensionError_Raise_if (M.Length() != mults->Length(),
630 "Geom_BSplineCurve::Multiplicities");
634 const TColStd_Array1OfInteger& Geom_BSplineCurve::Multiplicities() const
636 return mults->Array1();
639 //=======================================================================
642 //=======================================================================
644 Standard_Integer Geom_BSplineCurve::NbKnots () const
645 { return knots->Length(); }
647 //=======================================================================
650 //=======================================================================
652 Standard_Integer Geom_BSplineCurve::NbPoles () const
653 { return poles->Length(); }
655 //=======================================================================
658 //=======================================================================
660 const gp_Pnt& Geom_BSplineCurve::Pole (const Standard_Integer Index) const
662 Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
663 "Geom_BSplineCurve::Pole");
664 return poles->Value (Index);
667 //=======================================================================
670 //=======================================================================
672 void Geom_BSplineCurve::Poles (TColgp_Array1OfPnt& P) const
674 Standard_DimensionError_Raise_if (P.Length() != poles->Length(),
675 "Geom_BSplineCurve::Poles");
679 const TColgp_Array1OfPnt& Geom_BSplineCurve::Poles() const
681 return poles->Array1();
684 //=======================================================================
685 //function : StartPoint
687 //=======================================================================
689 gp_Pnt Geom_BSplineCurve::StartPoint () const
691 if (mults->Value (1) == deg + 1)
692 return poles->Value (1);
694 return Value(FirstParameter());
697 //=======================================================================
700 //=======================================================================
702 Standard_Real Geom_BSplineCurve::Weight
703 (const Standard_Integer Index) const
705 Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
706 "Geom_BSplineCurve::Weight");
708 return weights->Value (Index);
713 //=======================================================================
716 //=======================================================================
718 void Geom_BSplineCurve::Weights
719 (TColStd_Array1OfReal& W) const
721 Standard_DimensionError_Raise_if (W.Length() != poles->Length(),
722 "Geom_BSplineCurve::Weights");
724 W = weights->Array1();
728 for (i = W.Lower(); i <= W.Upper(); i++)
733 const TColStd_Array1OfReal* Geom_BSplineCurve::Weights() const
736 return &weights->Array1();
737 return BSplCLib::NoWeights();
740 //=======================================================================
741 //function : IsRational
743 //=======================================================================
745 Standard_Boolean Geom_BSplineCurve::IsRational () const
747 return !weights.IsNull();
750 //=======================================================================
751 //function : Transform
753 //=======================================================================
755 void Geom_BSplineCurve::Transform
758 TColgp_Array1OfPnt & CPoles = poles->ChangeArray1();
759 for (Standard_Integer I = 1; I <= CPoles.Length(); I++)
760 CPoles (I).Transform (T);
764 //=======================================================================
767 // pmn : 30/01/97 mise en conformite avec le cdl, lorsque U est un noeud
769 //=======================================================================
771 void Geom_BSplineCurve::LocateU
772 (const Standard_Real U,
773 const Standard_Real ParametricTolerance,
774 Standard_Integer& I1,
775 Standard_Integer& I2,
776 const Standard_Boolean WithKnotRepetition) const
778 Standard_Real NewU = U;
779 Handle(TColStd_HArray1OfReal) TheKnots;
780 if (WithKnotRepetition) TheKnots = flatknots;
781 else TheKnots = knots;
782 const TColStd_Array1OfReal & CKnots = TheKnots->Array1();
784 PeriodicNormalization(NewU); //Attention a la periode
786 Standard_Real UFirst = CKnots (1);
787 Standard_Real ULast = CKnots (CKnots.Length());
788 Standard_Real PParametricTolerance = Abs(ParametricTolerance);
789 if (Abs (NewU - UFirst) <= PParametricTolerance) { I1 = I2 = 1; }
790 else if (Abs (NewU - ULast) <= PParametricTolerance) {
791 I1 = I2 = CKnots.Length();
793 else if (NewU < UFirst) {
797 else if (NewU > ULast) {
798 I1 = CKnots.Length();
803 BSplCLib::Hunt (CKnots, NewU, I1);
804 I1 = Max (Min (I1, CKnots.Upper()), CKnots.Lower());
805 while (I1 + 1 <= CKnots.Upper()
806 && Abs (CKnots (I1 + 1) - NewU) <= PParametricTolerance)
810 if ( Abs( CKnots(I1) - NewU) <= PParametricTolerance) {
819 //=======================================================================
820 //function : Resolution
822 //=======================================================================
824 void Geom_BSplineCurve::Resolution(const Standard_Real Tolerance3D,
825 Standard_Real & UTolerance)
830 Standard_Integer NbKnots, NbPoles;
831 BSplCLib::PrepareUnperiodize( deg,
835 TColgp_Array1OfPnt new_poles(1,NbPoles) ;
836 TColStd_Array1OfReal new_weights(1,NbPoles) ;
837 for(ii = 1 ; ii <= NbPoles ; ii++) {
838 new_poles(ii) = poles->Array1()((ii-1) % poles->Length() + 1) ;
841 for(ii = 1 ; ii <= NbPoles ; ii++) {
842 new_weights(ii) = weights->Array1()((ii-1) % poles->Length() + 1) ;
844 BSplCLib::Resolution(new_poles,
853 BSplCLib::Resolution(new_poles,
854 BSplCLib::NoWeights(),
865 BSplCLib::Resolution(poles->Array1(),
874 BSplCLib::Resolution(poles->Array1(),
875 BSplCLib::NoWeights(),
885 UTolerance = Tolerance3D * maxderivinv;
888 //=======================================================================
891 //=======================================================================
893 Standard_Boolean Geom_BSplineCurve::IsEqual(const Handle(Geom_BSplineCurve)& theOther,
894 const Standard_Real thePreci) const
896 if( knots.IsNull() || poles.IsNull() || mults.IsNull() )
897 return Standard_False;
898 if( deg != theOther->Degree())
899 return Standard_False;
900 if( knots->Length() != theOther->NbKnots() ||
901 poles->Length() != theOther->NbPoles())
902 return Standard_False;
904 Standard_Integer i = 1;
905 for( i = 1 ; i <= poles->Length(); i++ )
907 const gp_Pnt& aPole1 = poles->Value(i);
908 const gp_Pnt& aPole2 =theOther->Pole(i);
909 if( fabs( aPole1.X() - aPole2.X() ) > thePreci ||
910 fabs( aPole1.Y() - aPole2.Y() ) > thePreci ||
911 fabs( aPole1.Z() - aPole2.Z() ) > thePreci )
912 return Standard_False;
915 for( ; i <= knots->Length(); i++ )
917 if( fabs(knots->Value(i) - theOther->Knot(i)) > Precision::Parametric(thePreci) )
918 return Standard_False;
921 for( i = 1 ; i <= mults->Length(); i++ )
923 if( mults->Value(i) != theOther->Multiplicity(i) )
924 return Standard_False;
927 if( rational != theOther->IsRational())
928 return Standard_False;
931 return Standard_True;
933 for( i = 1 ; i <= weights->Length(); i++ )
935 if( fabs( Standard_Real(weights->Value(i) - theOther->Weight(i))) > Epsilon(weights->Value(i)) )
936 return Standard_False;
938 return Standard_True;