1 // Copyright (c) 1995-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
17 #define No_Standard_OutOfRange
20 #include <BSplCLib.hxx>
21 #include <Convert_ConicToBSplineCurve.hxx>
22 #include <Convert_CosAndSinEvalFunction.hxx>
23 #include <Convert_PolynomialCosAndSin.hxx>
24 #include <gp_Pnt2d.hxx>
26 #include <Standard_ConstructionError.hxx>
27 #include <Standard_OutOfRange.hxx>
28 #include <TColgp_Array1OfPnt.hxx>
29 #include <TColgp_Array1OfPnt2d.hxx>
30 #include <TColgp_HArray1OfPnt2d.hxx>
31 #include <TColStd_Array1OfInteger.hxx>
32 #include <TColStd_Array1OfReal.hxx>
33 #include <TColStd_HArray1OfInteger.hxx>
34 #include <TColStd_HArray1OfReal.hxx>
36 //=======================================================================
37 //function : Convert_ConicToBSplineCurve
39 //=======================================================================
40 Convert_ConicToBSplineCurve::Convert_ConicToBSplineCurve
41 (const Standard_Integer NbPoles,
42 const Standard_Integer NbKnots,
43 const Standard_Integer Degree )
44 : degree (Degree) , nbPoles (NbPoles) , nbKnots (NbKnots)
48 poles = new TColgp_HArray1OfPnt2d (1, NbPoles) ;
50 weights = new TColStd_HArray1OfReal (1, NbPoles) ;
53 knots = new TColStd_HArray1OfReal (1, NbKnots) ;
54 mults = new TColStd_HArray1OfInteger(1,NbKnots) ;
59 //=======================================================================
62 //=======================================================================
64 Standard_Integer Convert_ConicToBSplineCurve::Degree () const
69 //=======================================================================
72 //=======================================================================
74 Standard_Integer Convert_ConicToBSplineCurve::NbPoles () const
79 //=======================================================================
82 //=======================================================================
84 Standard_Integer Convert_ConicToBSplineCurve::NbKnots () const
89 //=======================================================================
90 //function : IsPeriodic
92 //=======================================================================
94 Standard_Boolean Convert_ConicToBSplineCurve::IsPeriodic() const
99 //=======================================================================
102 //=======================================================================
104 gp_Pnt2d Convert_ConicToBSplineCurve::Pole
105 (const Standard_Integer Index) const
107 if (Index < 1 || Index > nbPoles)
108 throw Standard_OutOfRange(" ");
109 return poles->Value (Index);
113 //=======================================================================
116 //=======================================================================
118 Standard_Real Convert_ConicToBSplineCurve::Weight
119 (const Standard_Integer Index) const
121 if (Index < 1 || Index > nbPoles)
122 throw Standard_OutOfRange(" ");
123 return weights->Value (Index);
127 //=======================================================================
130 //=======================================================================
132 Standard_Real Convert_ConicToBSplineCurve::Knot
133 (const Standard_Integer Index) const
135 if (Index < 1 || Index > nbKnots)
136 throw Standard_OutOfRange(" ");
137 return knots->Value (Index);
141 //=======================================================================
142 //function : Multiplicity
144 //=======================================================================
146 Standard_Integer Convert_ConicToBSplineCurve::Multiplicity
147 (const Standard_Integer Index) const
149 if (Index < 1 || Index > nbKnots)
150 throw Standard_OutOfRange(" ");
151 return mults->Value (Index);
153 //=======================================================================
154 //function : CosAndSinRationalC1
155 //purpose : evaluates U(t) and V(t) such that
158 // cos (theta(t)) = ----------
164 // sin (theta(t)) = ----------
168 // such that the derivative at the domain bounds of U + V is 0.0e0
169 // with is helpful when having to make a C1 BSpline by merging two BSpline together
170 //=======================================================================
172 void CosAndSinRationalC1(Standard_Real Parameter,
173 const Standard_Integer EvalDegree,
174 const TColgp_Array1OfPnt2d& EvalPoles,
175 const TColStd_Array1OfReal& EvalKnots,
176 const TColStd_Array1OfInteger* EvalMults,
177 Standard_Real Result[2])
180 BSplCLib::D0(Parameter,
185 BSplCLib::NoWeights(),
189 Result[0] = a_point.Coord(1) ;
190 Result[1] = a_point.Coord(2) ;
194 //=======================================================================
195 //function : CosAndSinQuasiAngular
196 //purpose : evaluates U(t) and V(t) such that
199 // cos (theta(t)) = ----------
205 // sin (theta(t)) = ----------
208 //=======================================================================
210 void CosAndSinQuasiAngular(Standard_Real Parameter,
211 const Standard_Integer EvalDegree,
212 const TColgp_Array1OfPnt2d& EvalPoles,
213 // const TColStd_Array1OfReal& EvalKnots,
214 const TColStd_Array1OfReal& ,
215 // const TColStd_Array1OfInteger& EvalMults,
216 const TColStd_Array1OfInteger* ,
217 Standard_Real Result[2])
223 coeff = (Standard_Real *) &EvalPoles(EvalPoles.Lower()) ;
225 // rational_function_coeff represent a rational approximation
226 // of U ---> cotan( PI * U /2) between [0 1]
227 // rational_function_coeff[i][0] is the denominator
228 // rational_function_coeff[i][1] is the numerator
230 param = Parameter * 0.5e0 ;
231 PLib::NoDerivativeEvalPolynomial (param,
239 //=======================================================================
240 //function : function that build the Bspline Representation of
241 // an algorithmic description of the function cos and sin
243 //=======================================================================
244 void AlgorithmicCosAndSin(Standard_Integer Degree,
245 const TColStd_Array1OfReal& FlatKnots,
246 const Standard_Integer EvalDegree,
247 const TColgp_Array1OfPnt2d& EvalPoles,
248 const TColStd_Array1OfReal& EvalKnots,
249 const TColStd_Array1OfInteger* EvalMults,
250 Convert_CosAndSinEvalFunction Evaluator,
251 TColStd_Array1OfReal& CosNumerator,
252 TColStd_Array1OfReal& SinNumerator,
253 TColStd_Array1OfReal& Denominator)
255 Standard_Integer order,
260 Standard_Real result[2],
264 num_poles = FlatKnots.Length() - order ;
266 if (num_poles != CosNumerator.Length() ||
267 num_poles != SinNumerator.Length() ||
268 num_poles != Denominator.Length() ) {
269 throw Standard_ConstructionError();
271 TColStd_Array1OfReal parameters(1,num_poles) ;
272 TColgp_Array1OfPnt poles_array(1,num_poles) ;
273 TColStd_Array1OfInteger contact_order_array(1,num_poles) ;
274 BSplCLib::BuildSchoenbergPoints(Degree,
277 for (ii = parameters.Lower() ; ii <= parameters.Upper() ; ii++) {
278 Evaluator(parameters(ii),
284 contact_order_array(ii) = 0 ;
286 poles_array(ii).SetCoord(1,
287 (result[1]*result[1] - result[0]*result[0]));
288 poles_array(ii).SetCoord(2,
289 2.0e0 * result[1]* result[0]) ;
290 poles_array(ii).SetCoord(3,
291 result[1]*result[1] + result[0] * result[0]) ;
293 BSplCLib::Interpolate(Degree,
298 pivot_index_problem) ;
299 for (ii = 1 ; ii <= num_poles ; ii++) {
300 inverse = 1.0e0 / poles_array(ii).Coord(3) ;
301 CosNumerator(ii) = poles_array(ii).Coord(1) * inverse ;
302 SinNumerator(ii) = poles_array(ii).Coord(2) * inverse ;
303 Denominator(ii) = poles_array(ii).Coord(3) ;
307 //=======================================================================
308 //function : BuildCosAndSin
310 //=======================================================================
312 void Convert_ConicToBSplineCurve::BuildCosAndSin(
313 const Convert_ParameterisationType Parameterisation,
314 const Standard_Real UFirst,
315 const Standard_Real ULast,
316 Handle(TColStd_HArray1OfReal)& CosNumeratorPtr,
317 Handle(TColStd_HArray1OfReal)& SinNumeratorPtr,
318 Handle(TColStd_HArray1OfReal)& DenominatorPtr,
319 Standard_Integer& Degree,
320 Handle(TColStd_HArray1OfReal)& KnotsPtr,
321 Handle(TColStd_HArray1OfInteger)& MultsPtr) const
323 Standard_Real delta = ULast - UFirst,
339 Standard_Integer num_poles = 0,
351 Convert_CosAndSinEvalFunction *EvaluatorPtr=NULL ;
356 switch (Parameterisation) {
357 case Convert_TgtThetaOver2:
359 (Standard_Integer)IntegerPart( 1.2 * delta / M_PI) + 1;
363 case Convert_TgtThetaOver2_1:
365 if (delta > 0.9999 * M_PI) {
366 throw Standard_ConstructionError() ;
370 case Convert_TgtThetaOver2_2:
372 if (delta > 1.9999 * M_PI) {
373 throw Standard_ConstructionError() ;
378 case Convert_TgtThetaOver2_3:
382 case Convert_TgtThetaOver2_4:
386 case Convert_QuasiAngular:
393 case Convert_RationalC1:
400 case Convert_Polynomial:
409 if (tgt_theta_flag) {
410 alpha = delta / ( 2.0e0 * num_spans) ;
412 num_poles = 2 * num_spans + 1;
416 new TColStd_HArray1OfReal(1,num_poles) ;
418 new TColStd_HArray1OfReal(1,num_poles) ;
420 new TColStd_HArray1OfReal(1,num_poles) ;
422 new TColStd_HArray1OfReal(1,num_spans+1) ;
424 new TColStd_HArray1OfInteger(1,num_spans+1) ;
425 if (tgt_theta_flag) {
428 CosNumeratorPtr->SetValue(1,Cos(UFirst)) ;
429 SinNumeratorPtr->SetValue(1,Sin(UFirst)) ;
430 DenominatorPtr ->SetValue(1,1.0e0) ;
431 KnotsPtr->SetValue(1,param) ;
432 MultsPtr->SetValue(1,Degree + 1) ;
433 direct = Cos(alpha) ;
434 inverse = 1.0e0 / direct ;
435 for (ii = 1 ; ii <= num_spans ; ii++ ) {
436 CosNumeratorPtr->SetValue(2 * ii, inverse * Cos(param + alpha)) ;
437 SinNumeratorPtr->SetValue(2 * ii, inverse * Sin(param + alpha)) ;
438 DenominatorPtr->SetValue(2 * ii, direct) ;
439 CosNumeratorPtr->SetValue(2 * ii + 1, Cos(param + 2 * alpha)) ;
440 SinNumeratorPtr->SetValue(2 * ii + 1, Sin(param + 2 * alpha)) ;
441 DenominatorPtr->SetValue(2 * ii + 1, 1.0e0) ;
442 KnotsPtr->SetValue(ii + 1, param + 2 * alpha) ;
443 MultsPtr->SetValue(ii + 1, 2) ;
446 MultsPtr->SetValue(num_spans + 1, Degree + 1) ;
448 else if (Parameterisation != Convert_Polynomial) {
449 alpha = ULast - UFirst ;
451 beta = ULast + UFirst ;
453 cos_beta = Cos(beta) ;
454 sin_beta = Sin(beta) ;
455 num_flat_knots = num_poles + order ;
459 TColStd_Array1OfReal flat_knots(1, num_flat_knots) ;
462 TColgp_Array1OfPnt2d temp_poles(1,num_temp_poles) ;
463 TColStd_Array1OfReal temp_knots(1,num_temp_knots) ;
464 TColStd_Array1OfInteger temp_mults(1,num_temp_knots) ;
466 for (ii = 1 ; ii <= order ; ii++) {
467 flat_knots(ii) = -alpha ;
468 flat_knots(ii + num_poles) = alpha ;
470 KnotsPtr->SetValue(1,UFirst) ;
471 KnotsPtr->SetValue(num_knots, ULast) ;
472 MultsPtr->SetValue(1,order) ;
473 MultsPtr->SetValue(num_knots,order) ;
475 switch (Parameterisation) {
476 case Convert_QuasiAngular:
478 // we code here in temp_poles(xx).Coord(1) the following function V(t)
479 // and in temp_poles(xx).Coord(2) the function U(t)
485 // c = --- + b = q_param
489 // gamma + ------ - tang gamma
491 // b =------------------------------ = p_param
493 // gamma (tang gamma - gamma)
495 // with gamma = alpha / 2
499 alpha_2 = alpha * 0.5e0 ;
500 p_param = - 1.0e0 / (alpha_2 * alpha_2) ;
502 if (alpha_2 < M_PI * 0.5e0)
504 if (alpha_2 < 1.0e-7)
506 // Fixed degenerate case, when obtain 0 / 0 uncertainty.
507 // According to Taylor approximation:
508 // b (gamma) = -6.0 / 15.0 + o(gamma^2)
509 p_param = -6.0 / 15.0;
513 tan_alpha_2 = Tan(alpha_2) ;
514 value1 = 3.0e0 * (tan_alpha_2 - alpha_2) ;
515 value1 = alpha_2 / value1 ;
519 q_param = (1.0e0 / 3.0e0) + p_param ;
523 temp_poles(1).SetCoord(1,0.0e0);
524 temp_poles(2).SetCoord(1,1.0e0);
525 temp_poles(3).SetCoord(1,0.0e0) ;
526 temp_poles(4).SetCoord(1,q_param) ;
528 temp_poles(1).SetCoord(2, 1.0e0) ;
529 temp_poles(2).SetCoord(2, 0.0e0) ;
530 temp_poles(3).SetCoord(2, p_param) ;
531 temp_poles(4).SetCoord(2, 0.0e0);
532 EvaluatorPtr = &CosAndSinQuasiAngular ;
534 case Convert_RationalC1:
535 for (ii = order + 1 ; ii <= num_poles ; ii++) {
536 flat_knots(ii) = 0.0e0 ;
538 KnotsPtr->SetValue(2,UFirst + alpha) ;
539 MultsPtr->SetValue(2,Degree -1) ;
541 alpha_2 = alpha * 0.5e0 ;
542 alpha_4 = alpha * 0.25e0 ;
543 tan_alpha_2 = Tan(alpha_2) ;
545 for (ii = 1 ; ii <= 2 ; ii++) {
546 temp_poles(1+ ii).SetCoord(2,1.0e0 + alpha_4 * tan_alpha_2) ;
547 temp_poles(jj).SetCoord(2,1.e0) ;
550 temp_poles(1).SetCoord(1,-tan_alpha_2) ;
551 temp_poles(2).SetCoord(1,alpha_4 - tan_alpha_2) ;
552 temp_poles(3).SetCoord(1,-alpha_4 + tan_alpha_2) ;
553 temp_poles(4).SetCoord(1,tan_alpha_2) ;
554 temp_knots(1) = -alpha ;
555 temp_knots(2) = 0.0e0 ;
556 temp_knots(3) = alpha ;
557 temp_mults(1) = temp_degree + 1;
559 temp_mults(3) = temp_degree + 1;
561 EvaluatorPtr = &CosAndSinRationalC1 ;
566 AlgorithmicCosAndSin(Degree,
573 CosNumeratorPtr->ChangeArray1(),
574 SinNumeratorPtr->ChangeArray1(),
575 DenominatorPtr->ChangeArray1()) ;
577 for (ii = 1 ; ii <= num_poles ; ii++) {
578 value1 = cos_beta * CosNumeratorPtr->Value(ii) -
579 sin_beta * SinNumeratorPtr->Value(ii) ;
580 value2 = sin_beta * CosNumeratorPtr->Value(ii) +
581 cos_beta * SinNumeratorPtr->Value(ii) ;
582 CosNumeratorPtr->SetValue(ii,value1) ;
583 SinNumeratorPtr->SetValue(ii,value2) ;
586 else { // Convert_Polynomial
588 KnotsPtr->SetValue(1, 0.) ;
589 KnotsPtr->SetValue(num_knots, 1.);
590 MultsPtr->SetValue(1, num_poles);
591 MultsPtr->SetValue(num_knots, num_poles);
593 BuildPolynomialCosAndSin(UFirst,ULast,num_poles,
594 CosNumeratorPtr,SinNumeratorPtr,DenominatorPtr);
599 //=======================================================================
600 //function : BuildCosAndSin
602 //=======================================================================
604 void Convert_ConicToBSplineCurve::BuildCosAndSin(
605 const Convert_ParameterisationType Parameterisation,
606 Handle(TColStd_HArray1OfReal)& CosNumeratorPtr,
607 Handle(TColStd_HArray1OfReal)& SinNumeratorPtr,
608 Handle(TColStd_HArray1OfReal)& DenominatorPtr,
609 Standard_Integer& Degree,
610 Handle(TColStd_HArray1OfReal)& KnotsPtr,
611 Handle(TColStd_HArray1OfInteger)& MultsPtr) const
613 Standard_Real half_pi,
635 if (Parameterisation != Convert_TgtThetaOver2 &&
636 Parameterisation != Convert_RationalC1) {
637 throw Standard_ConstructionError() ;
639 Handle(TColStd_HArray1OfReal) temp_cos_ptr,
641 temp_denominator_ptr,
643 Handle(TColStd_HArray1OfInteger) temp_mults_ptr;
644 if (Parameterisation == Convert_TgtThetaOver2) {
645 BuildCosAndSin(Convert_TgtThetaOver2_3,
650 temp_denominator_ptr,
655 new TColStd_HArray1OfReal(1,temp_cos_ptr->Length() -1) ;
657 new TColStd_HArray1OfReal(1,temp_cos_ptr->Length() -1) ;
659 new TColStd_HArray1OfReal(1,temp_cos_ptr->Length() -1) ;
660 for (ii = temp_cos_ptr->Lower() ; ii <= temp_cos_ptr->Upper()-1 ; ii++) {
661 CosNumeratorPtr->SetValue(ii,temp_cos_ptr->Value(ii)) ;
662 SinNumeratorPtr->SetValue(ii,temp_sin_ptr->Value(ii)) ;
663 DenominatorPtr->SetValue(ii,temp_denominator_ptr->Value(ii)) ;
665 for (ii = MultsPtr->Lower() ; ii <= MultsPtr->Upper() ; ii++) {
666 MultsPtr->SetValue(ii, Degree) ;
669 else if (Parameterisation == Convert_RationalC1)
671 first_param = 0.0e0 ;
673 BuildCosAndSin(Convert_RationalC1,
678 temp_denominator_ptr,
687 num_flat_knots = (Degree -1) * num_knots + 2 * 2 ;
688 num_poles = num_flat_knots - order ;
689 num_periodic_poles = num_poles - 2 ;
690 TColStd_Array1OfReal flat_knots(1,num_flat_knots) ;
692 new TColStd_HArray1OfReal(1,num_periodic_poles) ;
694 new TColStd_HArray1OfReal(1,num_periodic_poles) ;
696 new TColStd_HArray1OfReal(1,num_periodic_poles) ;
698 half_pi = M_PI * 0.5e0 ;
700 for (jj = 1 ; jj <= 2 ; jj++) {
701 flat_knots(index) = - half_pi ;
704 for (ii = 1 ; ii <= num_knots ; ii++) {
705 for (jj = 1 ; jj <= Degree -1 ; jj++) {
706 flat_knots(index) = (ii-1) * half_pi ;
712 for (jj = 1 ; jj <= 2 ; jj++) {
713 flat_knots(index) = 2 * M_PI + half_pi ;
717 new TColStd_HArray1OfReal(1,num_knots) ;
719 new TColStd_HArray1OfInteger(1,num_knots) ;
720 for ( ii = 1 ; ii <= num_knots ; ii++) {
721 KnotsPtr->SetValue(ii, (ii-1) * half_pi) ;
722 MultsPtr->SetValue(ii, Degree-1) ;
726 TColStd_Array1OfReal parameters(1,num_poles) ;
727 TColgp_Array1OfPnt poles_array(1,num_poles) ;
728 TColStd_Array1OfInteger contact_order_array(1,num_poles) ;
729 BSplCLib::BuildSchoenbergPoints(Degree,
733 for (ii = parameters.Lower() ; ii <= parameters.Upper() ; ii++) {
734 param = parameters(ii) ;
743 temp_cos_ptr->Array1(),
744 &temp_denominator_ptr->Array1(),
745 temp_knots_ptr->Array1(),
746 &temp_mults_ptr->Array1(),
753 temp_sin_ptr->Array1(),
754 &temp_denominator_ptr->Array1(),
755 temp_knots_ptr->Array1(),
756 &temp_mults_ptr->Array1(),
762 temp_denominator_ptr->Array1(),
763 BSplCLib::NoWeights(),
764 temp_knots_ptr->Array1(),
765 &temp_mults_ptr->Array1(),
767 contact_order_array(ii) = 0 ;
769 poles_array(ii).SetCoord(1,
770 value1 * value3 * inverse) ;
771 poles_array(ii).SetCoord(2,
772 value2 * value3 * inverse) ;
773 poles_array(ii).SetCoord(3,
776 BSplCLib::Interpolate(Degree,
781 pivot_index_problem) ;
782 for (ii = 1 ; ii <= num_periodic_poles ; ii++) {
783 inverse = 1.0e0 / poles_array(ii).Coord(3) ;
784 CosNumeratorPtr->ChangeArray1()(ii) = poles_array(ii).Coord(1) * inverse ;
785 SinNumeratorPtr->ChangeArray1()(ii) = poles_array(ii).Coord(2) * inverse ;
786 DenominatorPtr->ChangeArray1()(ii) = poles_array(ii).Coord(3) ;