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 // 03-02-97 : pmn ->LocateU sur Periodic (PRO6963),
18 // bon appel a LocateParameter (PRO6973) et mise en conformite avec
19 // le cdl de LocateU, lorsque U est un noeud (PRO6988)
21 #define No_Standard_OutOfRange
22 #define No_Standard_DimensionError
25 #include <BSplCLib.hxx>
26 #include <Geom_BSplineCurve.hxx>
27 #include <Geom_Geometry.hxx>
28 #include <Geom_UndefinedDerivative.hxx>
31 #include <gp_Trsf.hxx>
33 #include <Precision.hxx>
34 #include <Standard_ConstructionError.hxx>
35 #include <Standard_DimensionError.hxx>
36 #include <Standard_DomainError.hxx>
37 #include <Standard_NoSuchObject.hxx>
38 #include <Standard_OutOfRange.hxx>
39 #include <Standard_RangeError.hxx>
41 #define POLES (poles->Array1())
42 #define KNOTS (knots->Array1())
43 #define FKNOTS (flatknots->Array1())
44 #define FMULTS (BSplCLib::NoMults())
46 //=======================================================================
49 //=======================================================================
51 Standard_Boolean Geom_BSplineCurve::IsCN ( const Standard_Integer N) const
53 Standard_RangeError_Raise_if
54 (N < 0, "Geom_BSplineCurve::IsCN");
57 case GeomAbs_CN : return Standard_True;
58 case GeomAbs_C0 : return N <= 0;
59 case GeomAbs_G1 : return N <= 0;
60 case GeomAbs_C1 : return N <= 1;
61 case GeomAbs_G2 : return N <= 1;
62 case GeomAbs_C2 : return N <= 2;
64 return N <= 3 ? Standard_True :
65 N <= deg - BSplCLib::MaxKnotMult (mults->Array1(), mults->Lower() + 1, mults->Upper() - 1);
67 return Standard_False;
70 //=======================================================================
73 //=======================================================================
75 Standard_Boolean Geom_BSplineCurve::IsG1 ( const Standard_Real theTf,
76 const Standard_Real theTl,
77 const Standard_Real theAngTol) const
84 Standard_Integer start = FirstUKnotIndex()+1,
85 finish = LastUKnotIndex()-1;
86 Standard_Integer aDeg = Degree();
87 for(Standard_Integer aNKnot = start; aNKnot <= finish; aNKnot++)
89 const Standard_Real aTpar = Knot(aNKnot);
96 Standard_Integer mult = Multiplicity(aNKnot);
102 LocalD1(aTpar, aNKnot-1, aNKnot, aP1, aV1);
103 LocalD1(aTpar, aNKnot, aNKnot+1, aP2, aV2);
105 if((aV1.SquareMagnitude() <= gp::Resolution()) ||
106 aV2.SquareMagnitude() <= gp::Resolution())
108 return Standard_False;
111 if(Abs(aV1.Angle(aV2)) > theAngTol)
112 return Standard_False;
116 return Standard_True;
118 const Standard_Real aFirstParam = FirstParameter(),
119 aLastParam = LastParameter();
121 if( ((aFirstParam - theTf)*(theTl - aFirstParam) < 0.0) &&
122 ((aLastParam - theTf)*(theTl - aLastParam) < 0.0))
124 //Range [theTf, theTl] does not intersect curve bounadries
125 return Standard_True;
128 //Curve is closed or periodic and range [theTf, theTl]
129 //intersect curve boundary. Therefore, it is necessary to
130 //check if curve is smooth in its first and last point.
134 D1(Knot(FirstUKnotIndex()), aP, aV1);
135 D1(Knot(LastUKnotIndex()), aP, aV2);
137 if((aV1.SquareMagnitude() <= gp::Resolution()) ||
138 aV2.SquareMagnitude() <= gp::Resolution())
140 return Standard_False;
143 if(Abs(aV1.Angle(aV2)) > theAngTol)
144 return Standard_False;
146 return Standard_True;
149 //=======================================================================
150 //function : IsClosed
152 //=======================================================================
154 Standard_Boolean Geom_BSplineCurve::IsClosed () const
155 //-- { return (StartPoint().Distance (EndPoint())) <= gp::Resolution (); }
156 { return (StartPoint().SquareDistance(EndPoint())) <= 1e-16; }
158 //=======================================================================
159 //function : IsPeriodic
161 //=======================================================================
163 Standard_Boolean Geom_BSplineCurve::IsPeriodic () const
166 //=======================================================================
167 //function : Continuity
169 //=======================================================================
171 GeomAbs_Shape Geom_BSplineCurve::Continuity () const
174 //=======================================================================
177 //=======================================================================
179 Standard_Integer Geom_BSplineCurve::Degree () const
182 //=======================================================================
185 //=======================================================================
187 void Geom_BSplineCurve::D0(const Standard_Real U, gp_Pnt& P) const
189 Standard_Integer aSpanIndex = 0;
190 Standard_Real aNewU(U);
191 PeriodicNormalization(aNewU);
192 BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
193 if (aNewU < knots->Value(aSpanIndex))
197 BSplCLib::D0(aNewU,aSpanIndex,deg,periodic,POLES,
199 knots->Array1(), mults->Array1(),
204 BSplCLib::D0(aNewU,aSpanIndex,deg,periodic,POLES,
205 *((TColStd_Array1OfReal*) NULL),
206 knots->Array1(), mults->Array1(),
211 //=======================================================================
214 //=======================================================================
216 void Geom_BSplineCurve::D1 (const Standard_Real U,
220 Standard_Integer aSpanIndex = 0;
221 Standard_Real aNewU(U);
222 PeriodicNormalization(aNewU);
223 BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
224 if (aNewU < knots->Value(aSpanIndex))
228 BSplCLib::D1(aNewU,aSpanIndex,deg,periodic,POLES,
230 knots->Array1(), mults->Array1(),
235 BSplCLib::D1(aNewU,aSpanIndex,deg,periodic,POLES,
236 *((TColStd_Array1OfReal*) NULL),
237 knots->Array1(), mults->Array1(),
242 //=======================================================================
245 //=======================================================================
247 void Geom_BSplineCurve::D2(const Standard_Real U,
252 Standard_Integer aSpanIndex = 0;
253 Standard_Real aNewU(U);
254 PeriodicNormalization(aNewU);
255 BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
256 if (aNewU < knots->Value(aSpanIndex))
260 BSplCLib::D2(aNewU,aSpanIndex,deg,periodic,POLES,
262 knots->Array1(), mults->Array1(),
267 BSplCLib::D2(aNewU,aSpanIndex,deg,periodic,POLES,
268 *((TColStd_Array1OfReal*) NULL),
269 knots->Array1(), mults->Array1(),
274 //=======================================================================
277 //=======================================================================
279 void Geom_BSplineCurve::D3(const Standard_Real U,
285 Standard_Integer aSpanIndex = 0;
286 Standard_Real aNewU(U);
287 PeriodicNormalization(aNewU);
288 BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
289 if (aNewU < knots->Value(aSpanIndex))
293 BSplCLib::D3(aNewU,aSpanIndex,deg,periodic,POLES,
295 knots->Array1(), mults->Array1(),
300 BSplCLib::D3(aNewU,aSpanIndex,deg,periodic,POLES,
301 *((TColStd_Array1OfReal*) NULL),
302 knots->Array1(), mults->Array1(),
307 //=======================================================================
310 //=======================================================================
312 gp_Vec Geom_BSplineCurve::DN(const Standard_Real U,
313 const Standard_Integer N) const
317 BSplCLib::DN(U,N,0,deg,periodic,POLES,
322 BSplCLib::DN(U,N,0,deg,periodic,POLES,
323 *((TColStd_Array1OfReal*) NULL),
329 //=======================================================================
330 //function : EndPoint
332 //=======================================================================
334 gp_Pnt Geom_BSplineCurve::EndPoint () const
336 if (mults->Value (knots->Upper ()) == deg + 1)
337 return poles->Value (poles->Upper());
339 return Value(LastParameter());
342 //=======================================================================
343 //function : FirstUKnotIndex
345 //=======================================================================
347 Standard_Integer Geom_BSplineCurve::FirstUKnotIndex () const
349 if (periodic) return 1;
350 else return BSplCLib::FirstUKnotIndex (deg, mults->Array1());
353 //=======================================================================
354 //function : FirstParameter
356 //=======================================================================
358 Standard_Real Geom_BSplineCurve::FirstParameter () const
360 return flatknots->Value (deg+1);
363 //=======================================================================
366 //=======================================================================
368 Standard_Real Geom_BSplineCurve::Knot (const Standard_Integer Index) const
370 Standard_OutOfRange_Raise_if
371 (Index < 1 || Index > knots->Length(), "Geom_BSplineCurve::Knot");
372 return knots->Value (Index);
375 //=======================================================================
376 //function : KnotDistribution
378 //=======================================================================
380 GeomAbs_BSplKnotDistribution Geom_BSplineCurve::KnotDistribution () const
385 //=======================================================================
388 //=======================================================================
390 void Geom_BSplineCurve::Knots (TColStd_Array1OfReal& K) const
392 Standard_DimensionError_Raise_if
393 (K.Length() != knots->Length(), "Geom_BSplineCurve::Knots");
397 const TColStd_Array1OfReal& Geom_BSplineCurve::Knots() const
399 return knots->Array1();
402 //=======================================================================
403 //function : KnotSequence
405 //=======================================================================
407 void Geom_BSplineCurve::KnotSequence (TColStd_Array1OfReal& K) const
409 Standard_DimensionError_Raise_if
410 (K.Length() != flatknots->Length(), "Geom_BSplineCurve::KnotSequence");
411 K = flatknots->Array1();
414 const TColStd_Array1OfReal& Geom_BSplineCurve::KnotSequence() const
416 return flatknots->Array1();
419 //=======================================================================
420 //function : LastUKnotIndex
422 //=======================================================================
424 Standard_Integer Geom_BSplineCurve::LastUKnotIndex() const
426 if (periodic) return knots->Length();
427 else return BSplCLib::LastUKnotIndex (deg, mults->Array1());
430 //=======================================================================
431 //function : LastParameter
433 //=======================================================================
435 Standard_Real Geom_BSplineCurve::LastParameter () const
437 return flatknots->Value (flatknots->Upper()-deg);
440 //=======================================================================
441 //function : LocalValue
443 //=======================================================================
445 gp_Pnt Geom_BSplineCurve::LocalValue
446 (const Standard_Real U,
447 const Standard_Integer FromK1,
448 const Standard_Integer ToK2) const
451 LocalD0(U,FromK1,ToK2,P);
455 //=======================================================================
458 //=======================================================================
460 void Geom_BSplineCurve::LocalD0
461 (const Standard_Real U,
462 const Standard_Integer FromK1,
463 const Standard_Integer ToK2,
466 Standard_DomainError_Raise_if (FromK1 == ToK2,
467 "Geom_BSplineCurve::LocalValue");
470 Standard_Integer index = 0;
471 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic,FromK1,ToK2, index,u);
472 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
474 BSplCLib::D0(u,index,deg,periodic,POLES,
479 BSplCLib::D0(u,index,deg,periodic,POLES,
480 *((TColStd_Array1OfReal*) NULL),
485 //=======================================================================
488 //=======================================================================
490 void Geom_BSplineCurve::LocalD1 (const Standard_Real U,
491 const Standard_Integer FromK1,
492 const Standard_Integer ToK2,
496 Standard_DomainError_Raise_if (FromK1 == ToK2,
497 "Geom_BSplineCurve::LocalD1");
500 Standard_Integer index = 0;
501 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
502 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
504 BSplCLib::D1(u,index,deg,periodic,POLES,
509 BSplCLib::D1(u,index,deg,periodic,POLES,
510 *((TColStd_Array1OfReal*) NULL),
515 //=======================================================================
518 //=======================================================================
520 void Geom_BSplineCurve::LocalD2
521 (const Standard_Real U,
522 const Standard_Integer FromK1,
523 const Standard_Integer ToK2,
528 Standard_DomainError_Raise_if (FromK1 == ToK2,
529 "Geom_BSplineCurve::LocalD2");
532 Standard_Integer index = 0;
533 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
534 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
536 BSplCLib::D2(u,index,deg,periodic,POLES,
538 FKNOTS,FMULTS,P,V1,V2);
541 BSplCLib::D2(u,index,deg,periodic,POLES,
542 *((TColStd_Array1OfReal*) NULL),
543 FKNOTS,FMULTS,P,V1,V2);
547 //=======================================================================
550 //=======================================================================
552 void Geom_BSplineCurve::LocalD3
553 (const Standard_Real U,
554 const Standard_Integer FromK1,
555 const Standard_Integer ToK2,
561 Standard_DomainError_Raise_if (FromK1 == ToK2,
562 "Geom_BSplineCurve::LocalD3");
565 Standard_Integer index = 0;
566 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
567 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
569 BSplCLib::D3(u,index,deg,periodic,POLES,
571 FKNOTS,FMULTS,P,V1,V2,V3);
574 BSplCLib::D3(u,index,deg,periodic,POLES,
575 *((TColStd_Array1OfReal*) NULL),
576 FKNOTS,FMULTS,P,V1,V2,V3);
580 //=======================================================================
583 //=======================================================================
585 gp_Vec Geom_BSplineCurve::LocalDN
586 (const Standard_Real U,
587 const Standard_Integer FromK1,
588 const Standard_Integer ToK2,
589 const Standard_Integer N ) const
591 Standard_DomainError_Raise_if (FromK1 == ToK2,
592 "Geom_BSplineCurve::LocalD3");
595 Standard_Integer index = 0;
596 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
597 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
601 BSplCLib::DN(u,N,index,deg,periodic,POLES,
606 BSplCLib::DN(u,N,index,deg,periodic,POLES,
607 *((TColStd_Array1OfReal*) NULL),
613 //=======================================================================
614 //function : Multiplicity
616 //=======================================================================
618 Standard_Integer Geom_BSplineCurve::Multiplicity
619 (const Standard_Integer Index) const
621 Standard_OutOfRange_Raise_if (Index < 1 || Index > mults->Length(),
622 "Geom_BSplineCurve::Multiplicity");
623 return mults->Value (Index);
626 //=======================================================================
627 //function : Multiplicities
629 //=======================================================================
631 void Geom_BSplineCurve::Multiplicities (TColStd_Array1OfInteger& M) const
633 Standard_DimensionError_Raise_if (M.Length() != mults->Length(),
634 "Geom_BSplineCurve::Multiplicities");
638 const TColStd_Array1OfInteger& Geom_BSplineCurve::Multiplicities() const
640 return mults->Array1();
643 //=======================================================================
646 //=======================================================================
648 Standard_Integer Geom_BSplineCurve::NbKnots () const
649 { return knots->Length(); }
651 //=======================================================================
654 //=======================================================================
656 Standard_Integer Geom_BSplineCurve::NbPoles () const
657 { return poles->Length(); }
659 //=======================================================================
662 //=======================================================================
664 gp_Pnt Geom_BSplineCurve::Pole (const Standard_Integer Index) const
666 Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
667 "Geom_BSplineCurve::Pole");
668 return poles->Value (Index);
671 //=======================================================================
674 //=======================================================================
676 void Geom_BSplineCurve::Poles (TColgp_Array1OfPnt& P) const
678 Standard_DimensionError_Raise_if (P.Length() != poles->Length(),
679 "Geom_BSplineCurve::Poles");
683 const TColgp_Array1OfPnt& Geom_BSplineCurve::Poles() const
685 return poles->Array1();
688 //=======================================================================
689 //function : StartPoint
691 //=======================================================================
693 gp_Pnt Geom_BSplineCurve::StartPoint () const
695 if (mults->Value (1) == deg + 1)
696 return poles->Value (1);
698 return Value(FirstParameter());
701 //=======================================================================
704 //=======================================================================
706 Standard_Real Geom_BSplineCurve::Weight
707 (const Standard_Integer Index) const
709 Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
710 "Geom_BSplineCurve::Weight");
712 return weights->Value (Index);
717 //=======================================================================
720 //=======================================================================
722 void Geom_BSplineCurve::Weights
723 (TColStd_Array1OfReal& W) const
725 Standard_DimensionError_Raise_if (W.Length() != poles->Length(),
726 "Geom_BSplineCurve::Weights");
728 W = weights->Array1();
732 for (i = W.Lower(); i <= W.Upper(); i++)
737 const TColStd_Array1OfReal& Geom_BSplineCurve::Weights() const
740 return weights->Array1();
741 return BSplCLib::NoWeights();
744 //=======================================================================
745 //function : IsRational
747 //=======================================================================
749 Standard_Boolean Geom_BSplineCurve::IsRational () const
751 return !weights.IsNull();
754 //=======================================================================
755 //function : Transform
757 //=======================================================================
759 void Geom_BSplineCurve::Transform
762 TColgp_Array1OfPnt & CPoles = poles->ChangeArray1();
763 for (Standard_Integer I = 1; I <= CPoles.Length(); I++)
764 CPoles (I).Transform (T);
768 //=======================================================================
771 // pmn : 30/01/97 mise en conformite avec le cdl, lorsque U est un noeud
773 //=======================================================================
775 void Geom_BSplineCurve::LocateU
776 (const Standard_Real U,
777 const Standard_Real ParametricTolerance,
778 Standard_Integer& I1,
779 Standard_Integer& I2,
780 const Standard_Boolean WithKnotRepetition) const
782 Standard_Real NewU = U;
783 Handle(TColStd_HArray1OfReal) TheKnots;
784 if (WithKnotRepetition) TheKnots = flatknots;
785 else TheKnots = knots;
786 const TColStd_Array1OfReal & CKnots = TheKnots->Array1();
788 PeriodicNormalization(NewU); //Attention a la periode
790 Standard_Real UFirst = CKnots (1);
791 Standard_Real ULast = CKnots (CKnots.Length());
792 Standard_Real PParametricTolerance = Abs(ParametricTolerance);
793 if (Abs (NewU - UFirst) <= PParametricTolerance) { I1 = I2 = 1; }
794 else if (Abs (NewU - ULast) <= PParametricTolerance) {
795 I1 = I2 = CKnots.Length();
797 else if (NewU < UFirst) {
801 else if (NewU > ULast) {
802 I1 = CKnots.Length();
807 BSplCLib::Hunt (CKnots, NewU, I1);
808 while ( Abs( CKnots(I1+1) - NewU) <= PParametricTolerance) I1++;
809 if ( Abs( CKnots(I1) - NewU) <= PParametricTolerance) {
818 //=======================================================================
819 //function : Resolution
821 //=======================================================================
823 void Geom_BSplineCurve::Resolution(const Standard_Real Tolerance3D,
824 Standard_Real & UTolerance)
829 Standard_Integer NbKnots, NbPoles;
830 BSplCLib::PrepareUnperiodize( deg,
834 TColgp_Array1OfPnt new_poles(1,NbPoles) ;
835 TColStd_Array1OfReal new_weights(1,NbPoles) ;
836 for(ii = 1 ; ii <= NbPoles ; ii++) {
837 new_poles(ii) = poles->Array1()((ii-1) % poles->Length() + 1) ;
840 for(ii = 1 ; ii <= NbPoles ; ii++) {
841 new_weights(ii) = weights->Array1()((ii-1) % poles->Length() + 1) ;
843 BSplCLib::Resolution(new_poles,
852 BSplCLib::Resolution(new_poles,
853 *((TColStd_Array1OfReal*) NULL),
864 BSplCLib::Resolution(poles->Array1(),
873 BSplCLib::Resolution(poles->Array1(),
874 *((TColStd_Array1OfReal*) NULL),
884 UTolerance = Tolerance3D * maxderivinv;
887 //=======================================================================
890 //=======================================================================
892 Standard_Boolean Geom_BSplineCurve::IsEqual(const Handle(Geom_BSplineCurve)& theOther,
893 const Standard_Real thePreci) const
895 if( knots.IsNull() || poles.IsNull() || mults.IsNull() )
896 return Standard_False;
897 if( deg != theOther->Degree())
898 return Standard_False;
899 if( knots->Length() != theOther->NbKnots() ||
900 poles->Length() != theOther->NbPoles())
901 return Standard_False;
903 Standard_Integer i = 1;
904 for( i = 1 ; i <= poles->Length(); i++ )
906 const gp_Pnt& aPole1 = poles->Value(i);
907 const gp_Pnt& aPole2 =theOther->Pole(i);
908 if( fabs( aPole1.X() - aPole2.X() ) > thePreci ||
909 fabs( aPole1.Y() - aPole2.Y() ) > thePreci ||
910 fabs( aPole1.Z() - aPole2.Z() ) > thePreci )
911 return Standard_False;
914 for( ; i <= knots->Length(); i++ )
916 if( fabs(knots->Value(i) - theOther->Knot(i)) > Precision::Parametric(thePreci) )
917 return Standard_False;
920 for( i = 1 ; i <= mults->Length(); i++ )
922 if( mults->Value(i) != theOther->Multiplicity(i) )
923 return Standard_False;
926 if( rational != theOther->IsRational())
927 return Standard_False;
930 return Standard_True;
932 for( i = 1 ; i <= weights->Length(); i++ )
934 if( fabs( Standard_Real(weights->Value(i) - theOther->Weight(i))) > Epsilon(weights->Value(i)) )
935 return Standard_False;
937 return Standard_True;