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
24 #include <Geom_BSplineCurve.jxx>
25 #include <BSplCLib.hxx>
28 #include <Geom_UndefinedDerivative.hxx>
29 #include <Standard_DimensionError.hxx>
30 #include <Standard_OutOfRange.hxx>
31 #include <Standard_DomainError.hxx>
32 #include <Standard_RangeError.hxx>
33 #include <Precision.hxx>
35 #define POLES (poles->Array1())
36 #define KNOTS (knots->Array1())
37 #define FKNOTS (flatknots->Array1())
38 #define FMULTS (BSplCLib::NoMults())
40 //=======================================================================
43 //=======================================================================
45 Standard_Boolean Geom_BSplineCurve::IsCN ( const Standard_Integer N) const
47 Standard_RangeError_Raise_if
48 (N < 0, "Geom_BSplineCurve::IsCN");
51 case GeomAbs_CN : return Standard_True;
52 case GeomAbs_C0 : return N <= 0;
53 case GeomAbs_G1 : return N <= 0;
54 case GeomAbs_C1 : return N <= 1;
55 case GeomAbs_G2 : return N <= 1;
56 case GeomAbs_C2 : return N <= 2;
58 return N <= 3 ? Standard_True :
59 N <= deg - BSplCLib::MaxKnotMult (mults->Array1(), mults->Lower() + 1, mults->Upper() - 1);
61 return Standard_False;
64 //=======================================================================
67 //=======================================================================
69 Standard_Boolean Geom_BSplineCurve::IsG1 ( const Standard_Real theTf,
70 const Standard_Real theTl,
71 const Standard_Real theAngTol) const
78 Standard_Integer start = FirstUKnotIndex()+1,
79 finish = LastUKnotIndex()-1;
80 Standard_Integer aDeg = Degree();
81 for(Standard_Integer aNKnot = start; aNKnot <= finish; aNKnot++)
83 const Standard_Real aTpar = Knot(aNKnot);
90 Standard_Integer mult = Multiplicity(aNKnot);
96 LocalD1(aTpar, aNKnot-1, aNKnot, aP1, aV1);
97 LocalD1(aTpar, aNKnot, aNKnot+1, aP2, aV2);
99 if((aV1.SquareMagnitude() <= gp::Resolution()) ||
100 aV2.SquareMagnitude() <= gp::Resolution())
102 return Standard_False;
105 if(Abs(aV1.Angle(aV2)) > theAngTol)
106 return Standard_False;
110 return Standard_True;
112 const Standard_Real aFirstParam = FirstParameter(),
113 aLastParam = LastParameter();
115 if( ((aFirstParam - theTf)*(theTl - aFirstParam) < 0.0) &&
116 ((aLastParam - theTf)*(theTl - aLastParam) < 0.0))
118 //Range [theTf, theTl] does not intersect curve bounadries
119 return Standard_True;
122 //Curve is closed or periodic and range [theTf, theTl]
123 //intersect curve boundary. Therefore, it is necessary to
124 //check if curve is smooth in its first and last point.
128 D1(Knot(FirstUKnotIndex()), aP, aV1);
129 D1(Knot(LastUKnotIndex()), aP, aV2);
131 if((aV1.SquareMagnitude() <= gp::Resolution()) ||
132 aV2.SquareMagnitude() <= gp::Resolution())
134 return Standard_False;
137 if(Abs(aV1.Angle(aV2)) > theAngTol)
138 return Standard_False;
140 return Standard_True;
143 //=======================================================================
144 //function : IsClosed
146 //=======================================================================
148 Standard_Boolean Geom_BSplineCurve::IsClosed () const
149 //-- { return (StartPoint().Distance (EndPoint())) <= gp::Resolution (); }
150 { return (StartPoint().SquareDistance(EndPoint())) <= 1e-16; }
152 //=======================================================================
153 //function : IsPeriodic
155 //=======================================================================
157 Standard_Boolean Geom_BSplineCurve::IsPeriodic () const
160 //=======================================================================
161 //function : Continuity
163 //=======================================================================
165 GeomAbs_Shape Geom_BSplineCurve::Continuity () const
168 //=======================================================================
171 //=======================================================================
173 Standard_Integer Geom_BSplineCurve::Degree () const
176 //=======================================================================
179 //=======================================================================
181 void Geom_BSplineCurve::D0(const Standard_Real U, gp_Pnt& P) const
183 Standard_Integer aSpanIndex = 0;
184 Standard_Real aNewU(U);
185 PeriodicNormalization(aNewU);
186 BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
187 if (aNewU < knots->Value(aSpanIndex))
191 BSplCLib::D0(aNewU,aSpanIndex,deg,periodic,POLES,
193 knots->Array1(), mults->Array1(),
198 BSplCLib::D0(aNewU,aSpanIndex,deg,periodic,POLES,
199 *((TColStd_Array1OfReal*) NULL),
200 knots->Array1(), mults->Array1(),
205 //=======================================================================
208 //=======================================================================
210 void Geom_BSplineCurve::D1 (const Standard_Real U,
214 Standard_Integer aSpanIndex = 0;
215 Standard_Real aNewU(U);
216 PeriodicNormalization(aNewU);
217 BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
218 if (aNewU < knots->Value(aSpanIndex))
222 BSplCLib::D1(aNewU,aSpanIndex,deg,periodic,POLES,
224 knots->Array1(), mults->Array1(),
229 BSplCLib::D1(aNewU,aSpanIndex,deg,periodic,POLES,
230 *((TColStd_Array1OfReal*) NULL),
231 knots->Array1(), mults->Array1(),
236 //=======================================================================
239 //=======================================================================
241 void Geom_BSplineCurve::D2(const Standard_Real U,
246 Standard_Integer aSpanIndex = 0;
247 Standard_Real aNewU(U);
248 PeriodicNormalization(aNewU);
249 BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
250 if (aNewU < knots->Value(aSpanIndex))
254 BSplCLib::D2(aNewU,aSpanIndex,deg,periodic,POLES,
256 knots->Array1(), mults->Array1(),
261 BSplCLib::D2(aNewU,aSpanIndex,deg,periodic,POLES,
262 *((TColStd_Array1OfReal*) NULL),
263 knots->Array1(), mults->Array1(),
268 //=======================================================================
271 //=======================================================================
273 void Geom_BSplineCurve::D3(const Standard_Real U,
279 Standard_Integer aSpanIndex = 0;
280 Standard_Real aNewU(U);
281 PeriodicNormalization(aNewU);
282 BSplCLib::LocateParameter(deg, knots->Array1(), mults->Array1(), U, periodic, aSpanIndex, aNewU);
283 if (aNewU < knots->Value(aSpanIndex))
287 BSplCLib::D3(aNewU,aSpanIndex,deg,periodic,POLES,
289 knots->Array1(), mults->Array1(),
294 BSplCLib::D3(aNewU,aSpanIndex,deg,periodic,POLES,
295 *((TColStd_Array1OfReal*) NULL),
296 knots->Array1(), mults->Array1(),
301 //=======================================================================
304 //=======================================================================
306 gp_Vec Geom_BSplineCurve::DN(const Standard_Real U,
307 const Standard_Integer N) const
311 BSplCLib::DN(U,N,0,deg,periodic,POLES,
316 BSplCLib::DN(U,N,0,deg,periodic,POLES,
317 *((TColStd_Array1OfReal*) NULL),
323 //=======================================================================
324 //function : EndPoint
326 //=======================================================================
328 gp_Pnt Geom_BSplineCurve::EndPoint () const
330 if (mults->Value (knots->Upper ()) == deg + 1)
331 return poles->Value (poles->Upper());
333 return Value(LastParameter());
336 //=======================================================================
337 //function : FirstUKnotIndex
339 //=======================================================================
341 Standard_Integer Geom_BSplineCurve::FirstUKnotIndex () const
343 if (periodic) return 1;
344 else return BSplCLib::FirstUKnotIndex (deg, mults->Array1());
347 //=======================================================================
348 //function : FirstParameter
350 //=======================================================================
352 Standard_Real Geom_BSplineCurve::FirstParameter () const
354 return flatknots->Value (deg+1);
357 //=======================================================================
360 //=======================================================================
362 Standard_Real Geom_BSplineCurve::Knot (const Standard_Integer Index) const
364 Standard_OutOfRange_Raise_if
365 (Index < 1 || Index > knots->Length(), "Geom_BSplineCurve::Knot");
366 return knots->Value (Index);
369 //=======================================================================
370 //function : KnotDistribution
372 //=======================================================================
374 GeomAbs_BSplKnotDistribution Geom_BSplineCurve::KnotDistribution () const
379 //=======================================================================
382 //=======================================================================
384 void Geom_BSplineCurve::Knots (TColStd_Array1OfReal& K) const
386 Standard_DimensionError_Raise_if
387 (K.Length() != knots->Length(), "Geom_BSplineCurve::Knots");
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_DimensionError_Raise_if
404 (K.Length() != flatknots->Length(), "Geom_BSplineCurve::KnotSequence");
405 K = flatknots->Array1();
408 const TColStd_Array1OfReal& Geom_BSplineCurve::KnotSequence() const
410 return flatknots->Array1();
413 //=======================================================================
414 //function : LastUKnotIndex
416 //=======================================================================
418 Standard_Integer Geom_BSplineCurve::LastUKnotIndex() const
420 if (periodic) return knots->Length();
421 else return BSplCLib::LastUKnotIndex (deg, mults->Array1());
424 //=======================================================================
425 //function : LastParameter
427 //=======================================================================
429 Standard_Real Geom_BSplineCurve::LastParameter () const
431 return flatknots->Value (flatknots->Upper()-deg);
434 //=======================================================================
435 //function : LocalValue
437 //=======================================================================
439 gp_Pnt Geom_BSplineCurve::LocalValue
440 (const Standard_Real U,
441 const Standard_Integer FromK1,
442 const Standard_Integer ToK2) const
445 LocalD0(U,FromK1,ToK2,P);
449 //=======================================================================
452 //=======================================================================
454 void Geom_BSplineCurve::LocalD0
455 (const Standard_Real U,
456 const Standard_Integer FromK1,
457 const Standard_Integer ToK2,
460 Standard_DomainError_Raise_if (FromK1 == ToK2,
461 "Geom_BSplineCurve::LocalValue");
464 Standard_Integer index = 0;
465 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic,FromK1,ToK2, index,u);
466 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
468 BSplCLib::D0(u,index,deg,periodic,POLES,
473 BSplCLib::D0(u,index,deg,periodic,POLES,
474 *((TColStd_Array1OfReal*) NULL),
479 //=======================================================================
482 //=======================================================================
484 void Geom_BSplineCurve::LocalD1 (const Standard_Real U,
485 const Standard_Integer FromK1,
486 const Standard_Integer ToK2,
490 Standard_DomainError_Raise_if (FromK1 == ToK2,
491 "Geom_BSplineCurve::LocalD1");
494 Standard_Integer index = 0;
495 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
496 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
498 BSplCLib::D1(u,index,deg,periodic,POLES,
503 BSplCLib::D1(u,index,deg,periodic,POLES,
504 *((TColStd_Array1OfReal*) NULL),
509 //=======================================================================
512 //=======================================================================
514 void Geom_BSplineCurve::LocalD2
515 (const Standard_Real U,
516 const Standard_Integer FromK1,
517 const Standard_Integer ToK2,
522 Standard_DomainError_Raise_if (FromK1 == ToK2,
523 "Geom_BSplineCurve::LocalD2");
526 Standard_Integer index = 0;
527 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
528 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
530 BSplCLib::D2(u,index,deg,periodic,POLES,
532 FKNOTS,FMULTS,P,V1,V2);
535 BSplCLib::D2(u,index,deg,periodic,POLES,
536 *((TColStd_Array1OfReal*) NULL),
537 FKNOTS,FMULTS,P,V1,V2);
541 //=======================================================================
544 //=======================================================================
546 void Geom_BSplineCurve::LocalD3
547 (const Standard_Real U,
548 const Standard_Integer FromK1,
549 const Standard_Integer ToK2,
555 Standard_DomainError_Raise_if (FromK1 == ToK2,
556 "Geom_BSplineCurve::LocalD3");
559 Standard_Integer index = 0;
560 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
561 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
563 BSplCLib::D3(u,index,deg,periodic,POLES,
565 FKNOTS,FMULTS,P,V1,V2,V3);
568 BSplCLib::D3(u,index,deg,periodic,POLES,
569 *((TColStd_Array1OfReal*) NULL),
570 FKNOTS,FMULTS,P,V1,V2,V3);
574 //=======================================================================
577 //=======================================================================
579 gp_Vec Geom_BSplineCurve::LocalDN
580 (const Standard_Real U,
581 const Standard_Integer FromK1,
582 const Standard_Integer ToK2,
583 const Standard_Integer N ) const
585 Standard_DomainError_Raise_if (FromK1 == ToK2,
586 "Geom_BSplineCurve::LocalD3");
589 Standard_Integer index = 0;
590 BSplCLib::LocateParameter(deg, FKNOTS, U, periodic, FromK1,ToK2, index, u);
591 index = BSplCLib::FlatIndex(deg,index,mults->Array1(),periodic);
595 BSplCLib::DN(u,N,index,deg,periodic,POLES,
600 BSplCLib::DN(u,N,index,deg,periodic,POLES,
601 *((TColStd_Array1OfReal*) NULL),
607 //=======================================================================
608 //function : Multiplicity
610 //=======================================================================
612 Standard_Integer Geom_BSplineCurve::Multiplicity
613 (const Standard_Integer Index) const
615 Standard_OutOfRange_Raise_if (Index < 1 || Index > mults->Length(),
616 "Geom_BSplineCurve::Multiplicity");
617 return mults->Value (Index);
620 //=======================================================================
621 //function : Multiplicities
623 //=======================================================================
625 void Geom_BSplineCurve::Multiplicities (TColStd_Array1OfInteger& M) const
627 Standard_DimensionError_Raise_if (M.Length() != mults->Length(),
628 "Geom_BSplineCurve::Multiplicities");
632 const TColStd_Array1OfInteger& Geom_BSplineCurve::Multiplicities() const
634 return mults->Array1();
637 //=======================================================================
640 //=======================================================================
642 Standard_Integer Geom_BSplineCurve::NbKnots () const
643 { return knots->Length(); }
645 //=======================================================================
648 //=======================================================================
650 Standard_Integer Geom_BSplineCurve::NbPoles () const
651 { return poles->Length(); }
653 //=======================================================================
656 //=======================================================================
658 gp_Pnt Geom_BSplineCurve::Pole (const Standard_Integer Index) const
660 Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
661 "Geom_BSplineCurve::Pole");
662 return poles->Value (Index);
665 //=======================================================================
668 //=======================================================================
670 void Geom_BSplineCurve::Poles (TColgp_Array1OfPnt& P) const
672 Standard_DimensionError_Raise_if (P.Length() != poles->Length(),
673 "Geom_BSplineCurve::Poles");
677 const TColgp_Array1OfPnt& Geom_BSplineCurve::Poles() const
679 return poles->Array1();
682 //=======================================================================
683 //function : StartPoint
685 //=======================================================================
687 gp_Pnt Geom_BSplineCurve::StartPoint () const
689 if (mults->Value (1) == deg + 1)
690 return poles->Value (1);
692 return Value(FirstParameter());
695 //=======================================================================
698 //=======================================================================
700 Standard_Real Geom_BSplineCurve::Weight
701 (const Standard_Integer Index) const
703 Standard_OutOfRange_Raise_if (Index < 1 || Index > poles->Length(),
704 "Geom_BSplineCurve::Weight");
706 return weights->Value (Index);
711 //=======================================================================
714 //=======================================================================
716 void Geom_BSplineCurve::Weights
717 (TColStd_Array1OfReal& W) const
719 Standard_DimensionError_Raise_if (W.Length() != poles->Length(),
720 "Geom_BSplineCurve::Weights");
722 W = weights->Array1();
726 for (i = W.Lower(); i <= W.Upper(); i++)
731 const TColStd_Array1OfReal& Geom_BSplineCurve::Weights() const
734 return weights->Array1();
735 return BSplCLib::NoWeights();
738 //=======================================================================
739 //function : IsRational
741 //=======================================================================
743 Standard_Boolean Geom_BSplineCurve::IsRational () const
745 return !weights.IsNull();
748 //=======================================================================
749 //function : Transform
751 //=======================================================================
753 void Geom_BSplineCurve::Transform
756 TColgp_Array1OfPnt & CPoles = poles->ChangeArray1();
757 for (Standard_Integer I = 1; I <= CPoles.Length(); I++)
758 CPoles (I).Transform (T);
762 //=======================================================================
765 // pmn : 30/01/97 mise en conformite avec le cdl, lorsque U est un noeud
767 //=======================================================================
769 void Geom_BSplineCurve::LocateU
770 (const Standard_Real U,
771 const Standard_Real ParametricTolerance,
772 Standard_Integer& I1,
773 Standard_Integer& I2,
774 const Standard_Boolean WithKnotRepetition) const
776 Standard_Real NewU = U;
777 Handle(TColStd_HArray1OfReal) TheKnots;
778 if (WithKnotRepetition) TheKnots = flatknots;
779 else TheKnots = knots;
780 const TColStd_Array1OfReal & CKnots = TheKnots->Array1();
782 PeriodicNormalization(NewU); //Attention a la periode
784 Standard_Real UFirst = CKnots (1);
785 Standard_Real ULast = CKnots (CKnots.Length());
786 Standard_Real PParametricTolerance = Abs(ParametricTolerance);
787 if (Abs (NewU - UFirst) <= PParametricTolerance) { I1 = I2 = 1; }
788 else if (Abs (NewU - ULast) <= PParametricTolerance) {
789 I1 = I2 = CKnots.Length();
791 else if (NewU < UFirst) {
795 else if (NewU > ULast) {
796 I1 = CKnots.Length();
801 BSplCLib::Hunt (CKnots, NewU, I1);
802 while ( Abs( CKnots(I1+1) - NewU) <= PParametricTolerance) I1++;
803 if ( Abs( CKnots(I1) - NewU) <= PParametricTolerance) {
812 //=======================================================================
813 //function : Resolution
815 //=======================================================================
817 void Geom_BSplineCurve::Resolution(const Standard_Real Tolerance3D,
818 Standard_Real & UTolerance)
823 Standard_Integer NbKnots, NbPoles;
824 BSplCLib::PrepareUnperiodize( deg,
828 TColgp_Array1OfPnt new_poles(1,NbPoles) ;
829 TColStd_Array1OfReal new_weights(1,NbPoles) ;
830 for(ii = 1 ; ii <= NbPoles ; ii++) {
831 new_poles(ii) = poles->Array1()((ii-1) % poles->Length() + 1) ;
834 for(ii = 1 ; ii <= NbPoles ; ii++) {
835 new_weights(ii) = weights->Array1()((ii-1) % poles->Length() + 1) ;
837 BSplCLib::Resolution(new_poles,
846 BSplCLib::Resolution(new_poles,
847 *((TColStd_Array1OfReal*) NULL),
858 BSplCLib::Resolution(poles->Array1(),
867 BSplCLib::Resolution(poles->Array1(),
868 *((TColStd_Array1OfReal*) NULL),
878 UTolerance = Tolerance3D * maxderivinv;
881 //=======================================================================
884 //=======================================================================
886 Standard_Boolean Geom_BSplineCurve::IsEqual(const Handle(Geom_BSplineCurve)& theOther,
887 const Standard_Real thePreci) const
889 if( knots.IsNull() || poles.IsNull() || mults.IsNull() )
890 return Standard_False;
891 if( deg != theOther->Degree())
892 return Standard_False;
893 if( knots->Length() != theOther->NbKnots() ||
894 poles->Length() != theOther->NbPoles())
895 return Standard_False;
897 Standard_Integer i = 1;
898 for( i = 1 ; i <= poles->Length(); i++ )
900 const gp_Pnt& aPole1 = poles->Value(i);
901 const gp_Pnt& aPole2 =theOther->Pole(i);
902 if( fabs( aPole1.X() - aPole2.X() ) > thePreci ||
903 fabs( aPole1.Y() - aPole2.Y() ) > thePreci ||
904 fabs( aPole1.Z() - aPole2.Z() ) > thePreci )
905 return Standard_False;
908 for( ; i <= knots->Length(); i++ )
910 if( fabs(knots->Value(i) - theOther->Knot(i)) > Precision::Parametric(thePreci) )
911 return Standard_False;
914 for( i = 1 ; i <= mults->Length(); i++ )
916 if( mults->Value(i) != theOther->Multiplicity(i) )
917 return Standard_False;
920 if( rational != theOther->IsRational())
921 return Standard_False;
924 return Standard_True;
926 for( i = 1 ; i <= weights->Length(); i++ )
928 if( fabs( Standard_Real(weights->Value(i) - theOther->Weight(i))) > Epsilon(weights->Value(i)) )
929 return Standard_False;
931 return Standard_True;