0029807: [Regression to 7.0.0] Impossible to cut cone from prism
[occt.git] / src / IntAna / IntAna_Curve.cxx
1 // Created on: 1992-06-30
2 // Created by: Laurent BUCHARD
3 // Copyright (c) 1992-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
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.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #ifndef OCCT_DEBUG
18 #define No_Standard_RangeError
19 #define No_Standard_OutOfRange
20 #endif
21
22 //----------------------------------------------------------------------
23 //-- Differents constructeurs sont proposes qui correspondent aux
24 //-- polynomes en Z :  
25 //--    A(Sin(Theta),Cos(Theta)) Z**2 
26 //--  + B(Sin(Theta),Cos(Theta)) Z
27 //--  + C(Sin(Theta),Cos(Theta))
28 //--
29 //-- Une Courbe est definie sur un domaine 
30 //--
31 //-- Value retourne le point de parametre U(Theta),V(Theta)
32 //--       ou V est la solution du polynome A V**2 + B V + C
33 //--       (Selon les cas, on prend V+ ou V-)
34 //--
35 //-- D1u   calcule le vecteur tangent a la courbe 
36 //--       et retourne le booleen Standard_False si ce calcul ne peut
37 //--       pas etre mene a bien.  
38 //----------------------------------------------------------------------
39
40 #include <algorithm>
41
42 #include <ElSLib.hxx>
43 #include <gp_Cone.hxx>
44 #include <gp_Cylinder.hxx>
45 #include <gp_Pnt.hxx>
46 #include <gp_Vec.hxx>
47 #include <gp_XYZ.hxx>
48 #include <IntAna_Curve.hxx>
49 #include <math_DirectPolynomialRoots.hxx>
50 #include <Precision.hxx>
51 #include <Standard_DomainError.hxx>
52
53 //=======================================================================
54 //function : IntAna_Curve
55 //purpose  : 
56 //=======================================================================
57 IntAna_Curve::IntAna_Curve()
58 {
59   typequadric=GeomAbs_OtherSurface;
60   firstbounded=Standard_False;
61   lastbounded=Standard_False;
62 }
63 //=======================================================================
64 //function : SetConeQuadValues
65 //purpose  : Description de l intersection Cone Quadrique
66 //=======================================================================
67 void IntAna_Curve::SetConeQuadValues(const gp_Cone& Cone,
68                                      const Standard_Real Qxx,
69                                      const Standard_Real Qyy,
70                                      const Standard_Real Qzz,
71                                      const Standard_Real Qxy,
72                                      const Standard_Real Qxz,
73                                      const Standard_Real Qyz,
74                                      const Standard_Real Qx,
75                                      const Standard_Real Qy,
76                                      const Standard_Real Qz,
77                                      const Standard_Real Q1,
78                                      const Standard_Real TOL,
79                                      const Standard_Real DomInf,
80                                      const Standard_Real DomSup,
81                                      const Standard_Boolean twocurves,
82                                      const Standard_Boolean takezpositive)
83 {
84   
85   Ax3        = Cone.Position();
86   RCyl       = Cone.RefRadius();
87
88   Angle      = Cone.SemiAngle();
89   Standard_Real UnSurTgAngle = 1.0/(Tan(Cone.SemiAngle()));
90
91   typequadric= GeomAbs_Cone;
92   
93   TwoCurves     = twocurves;         //-- deux  Z pour un meme parametre 
94   TakeZPositive = takezpositive;     //-- Prendre sur la courbe le Z Positif
95                                      //--   ( -B + Sqrt()) et non (-B - Sqrt())
96   
97   
98   Z0Cte      = Q1;                   //-- Attention On a    Z?Cos Cos(t)
99   Z0Sin      = 0.0;                  //-- et Non          2 Z?Cos Cos(t) !!!
100   Z0Cos      = 0.0;                  //-- Ce pour tous les Parametres
101   Z0CosCos   = 0.0;                  //--  ie pas de Coefficient 2  
102   Z0SinSin   = 0.0;                  //--     devant les termes CS C S 
103   Z0CosSin   = 0.0;
104   
105   Z1Cte      = 2.0*(UnSurTgAngle)*Qz;
106   Z1Sin      = Qy+Qy;
107   Z1Cos      = Qx+Qx;
108   Z1CosCos   = 0.0;
109   Z1SinSin   = 0.0;
110   Z1CosSin   = 0.0;
111   
112   Z2Cte      = Qzz * UnSurTgAngle*UnSurTgAngle;
113   Z2Sin      = (UnSurTgAngle+UnSurTgAngle)*Qyz;
114   Z2Cos      = (UnSurTgAngle+UnSurTgAngle)*Qxz;
115   Z2CosCos   = Qxx;
116   Z2SinSin   = Qyy;
117   Z2CosSin   = Qxy;
118
119   Tolerance  = TOL;
120   DomainInf = DomInf;
121   DomainSup = DomSup;
122   
123   RestrictedInf = RestrictedSup = Standard_True;   //-- Le Domaine est Borne
124   firstbounded = lastbounded = Standard_False;
125
126   myFirstParameter = DomainInf;
127   myLastParameter = (TwoCurves) ? DomainSup + DomainSup - DomainInf :
128                                   DomainSup;
129 }
130
131 //=======================================================================
132 //function : SetCylinderQuadValues
133 //purpose  : Description de l intersection Cylindre Quadrique
134 //=======================================================================
135 void IntAna_Curve::SetCylinderQuadValues(const gp_Cylinder& Cyl,
136                                          const Standard_Real Qxx,
137                                          const Standard_Real Qyy,
138                                          const Standard_Real Qzz,
139                                          const Standard_Real Qxy,
140                                          const Standard_Real Qxz,
141                                          const Standard_Real Qyz,
142                                          const Standard_Real Qx,
143                                          const Standard_Real Qy,
144                                          const Standard_Real Qz,
145                                          const Standard_Real Q1,
146                                          const Standard_Real TOL,
147                                          const Standard_Real DomInf,
148                                          const Standard_Real DomSup,
149                                          const Standard_Boolean twocurves,
150                                          const Standard_Boolean takezpositive)
151 {
152   
153   Ax3        = Cyl.Position();
154   RCyl       = Cyl.Radius();
155   typequadric= GeomAbs_Cylinder;
156   
157   TwoCurves     = twocurves;         //-- deux  Z pour un meme parametre 
158   TakeZPositive = takezpositive;     //-- Prendre sur la courbe le Z Positif
159   Standard_Real RCylmul2 = RCyl+RCyl;         //--   ( -B + Sqrt()) 
160
161   Z0Cte      = Q1;
162   Z0Sin      = RCylmul2*Qy;
163   Z0Cos      = RCylmul2*Qx;
164   Z0CosCos   = Qxx*RCyl*RCyl;
165   Z0SinSin   = Qyy*RCyl*RCyl;
166   Z0CosSin   = RCyl*RCyl*Qxy;
167
168   Z1Cte      = Qz+Qz;
169   Z1Sin      = RCylmul2*Qyz;
170   Z1Cos      = RCylmul2*Qxz;
171   Z1CosCos   = 0.0;
172   Z1SinSin   = 0.0;
173   Z1CosSin   = 0.0;
174
175   Z2Cte      = Qzz;
176   Z2Sin      = 0.0;
177   Z2Cos      = 0.0;
178   Z2CosCos   = 0.0;
179   Z2SinSin   = 0.0;
180   Z2CosSin   = 0.0;
181
182   Tolerance  = TOL;
183   DomainInf = DomInf;
184   DomainSup = DomSup;
185   
186   RestrictedInf = RestrictedSup = Standard_True;
187   firstbounded = lastbounded = Standard_False;
188
189   myFirstParameter = DomainInf;
190   myLastParameter  = (TwoCurves) ? DomainSup + DomainSup - DomainInf :
191                                    DomainSup;
192 }
193
194 //=======================================================================
195 //function : IsOpen
196 //purpose  : 
197 //=======================================================================
198 Standard_Boolean IntAna_Curve::IsOpen() const
199 {
200   return(RestrictedInf && RestrictedSup);
201 }
202
203 //=======================================================================
204 //function : Domain
205 //purpose  : 
206 //=======================================================================
207 void IntAna_Curve::Domain(Standard_Real& theFirst,
208                           Standard_Real& theLast) const
209 {
210   if (RestrictedInf && RestrictedSup)
211   {
212     theFirst = myFirstParameter;
213     theLast = myLastParameter;
214   }
215   else
216   {
217     throw Standard_DomainError("IntAna_Curve::Domain");
218   }
219 }
220 //=======================================================================
221 //function : IsConstant
222 //purpose  : 
223 //=======================================================================
224 Standard_Boolean IntAna_Curve::IsConstant() const
225 {
226   //-- ???  Pas facile de decider a la seule vue des Param.
227   return(Standard_False);
228 }
229
230 //=======================================================================
231 //function : IsFirstOpen
232 //purpose  : 
233 //=======================================================================
234 Standard_Boolean IntAna_Curve::IsFirstOpen() const
235 {
236   return(firstbounded);
237 }
238
239 //=======================================================================
240 //function : IsLastOpen
241 //purpose  : 
242 //=======================================================================
243 Standard_Boolean IntAna_Curve::IsLastOpen() const
244 {
245   return(lastbounded);
246 }
247 //=======================================================================
248 //function : SetIsFirstOpen
249 //purpose  : 
250 //=======================================================================
251 void IntAna_Curve::SetIsFirstOpen(const Standard_Boolean Flag)
252 {
253   firstbounded = Flag;
254 }
255
256 //=======================================================================
257 //function : SetIsLastOpen
258 //purpose  : 
259 //=======================================================================
260 void IntAna_Curve::SetIsLastOpen(const Standard_Boolean Flag)
261 {
262   lastbounded = Flag;
263 }
264
265 //=======================================================================
266 //function : InternalUVValue
267 //purpose  : 
268 //=======================================================================
269 void IntAna_Curve::InternalUVValue(const Standard_Real theta,
270                                    Standard_Real& Param1,
271                                    Standard_Real& Param2,
272                                    Standard_Real& A,
273                                    Standard_Real& B,
274                                    Standard_Real& C,
275                                    Standard_Real& cost,
276                                    Standard_Real& sint,
277                                    Standard_Real& SigneSqrtDis) const
278 {
279   const Standard_Real aRelTolp = 1.0+Epsilon(1.0), aRelTolm = 1.0-Epsilon(1.0);
280   
281   // Infinitesimal step of increasing curve parameter. See comment below.
282   const Standard_Real aDT = 100.0*Epsilon(DomainSup + DomainSup - DomainInf);
283
284   Standard_Real Theta=theta;
285   Standard_Boolean SecondSolution=Standard_False; 
286
287   if ((Theta<DomainInf*aRelTolm) ||
288       ((Theta>DomainSup*aRelTolp) && (!TwoCurves)) ||
289       (Theta>(DomainSup + DomainSup - DomainInf)*aRelTolp))
290   {
291     SigneSqrtDis = 0.;
292     throw Standard_DomainError("IntAna_Curve::Domain");
293   }
294   
295   if (Abs(Theta - DomainSup) < aDT)
296   {
297     // Point of Null-discriminant.
298     Theta = DomainSup;
299   }
300   else if (Theta>DomainSup)
301   {
302     Theta = DomainSup + DomainSup - Theta;
303     SecondSolution=Standard_True; 
304   }
305
306   Param1=Theta;
307
308   if(!TwoCurves) { 
309     SecondSolution=TakeZPositive; 
310   }
311   //
312   cost = Cos(Theta);
313   sint = Sin(Theta);
314   const Standard_Real aSin2t = Sin(Theta + Theta);
315   const Standard_Real aCos2t = Cos(Theta + Theta);
316   
317   A=Z2Cte+sint*(Z2Sin+sint*Z2SinSin)+cost*(Z2Cos+cost*Z2CosCos)
318     + Z2CosSin*aSin2t;
319   
320   const Standard_Real aDA = cost*Z2Sin - sint*Z2Cos + 
321                             aSin2t*(Z2SinSin - Z2CosCos) + 
322                             aCos2t*(Z2CosSin * Z2CosSin);
323
324   B=Z1Cte+sint*(Z1Sin+sint*Z1SinSin)+cost*(Z1Cos+cost*Z1CosCos)
325     + Z1CosSin*aSin2t;
326
327   const Standard_Real aDB = Z1Sin*cost - Z1Cos*sint +
328                             aSin2t*(Z1SinSin - Z1CosCos) +
329                             aCos2t*(Z1CosSin + Z1CosSin);
330   
331   C=Z0Cte+sint*(Z0Sin+sint*Z0SinSin)+cost*(Z0Cos+cost*Z0CosCos)
332     + Z0CosSin*aSin2t;
333   
334   const Standard_Real aDC = Z0Sin*cost - Z0Cos*sint +
335                             aSin2t*(Z0SinSin - Z0CosCos) + 
336                             aCos2t*(Z0CosSin + Z0CosSin);
337
338   Standard_Real aDiscriminant = B*B-4.0*A*C;
339
340   // We consider that infinitesimal dt = aDT.
341   // Error of discriminant computation is equal to
342   // (d(Disc)/dt)*dt, where 1st derivative d(Disc)/dt = 2*B*aDB - 4*(A*aDC + C*aDA).
343
344   const Standard_Real aTolD = 2.0*aDT*Abs(B*aDB - 2.0*(A*aDC + C*aDA));
345   
346   if (aDiscriminant < aTolD)
347     aDiscriminant = 0.0;
348
349   if (Abs(A) <= Precision::PConfusion())
350   {
351     if (Abs(B) <= Precision::PConfusion())
352     {
353       Param2 = 0.0;
354     }
355     else
356     {
357       Param2 = -C / B;
358     }
359   }
360   else
361   {
362     SigneSqrtDis = (SecondSolution) ? Sqrt(aDiscriminant) : -Sqrt(aDiscriminant);
363     Param2 = (-B + SigneSqrtDis) / (A + A);
364   }
365 }
366
367 //=======================================================================
368 //function : Value
369 //purpose  : 
370 //=======================================================================
371 gp_Pnt IntAna_Curve::Value(const Standard_Real theta)
372 {
373   Standard_Real A, B, C, U, V, sint, cost, SigneSqrtDis;
374   //
375   A=0.0;  B=0.0;   C=0.0;
376   U=0.0;  V=0.0;  
377   sint=0.0;  cost=0.0;
378   SigneSqrtDis=0.0;
379   InternalUVValue(theta,U,V,A,B,C,cost,sint,SigneSqrtDis); 
380   //-- checked the parameter U and Raises Domain Error if Error
381   return(InternalValue(U,V));
382 }
383 //=======================================================================
384 //function : D1u
385 //purpose  : 
386 //=======================================================================
387 Standard_Boolean IntAna_Curve::D1u(const Standard_Real theta,
388                                    gp_Pnt& Pt,
389                                    gp_Vec& Vec)
390 {
391   //-- Pour detecter le cas ou le calcul est impossible 
392   Standard_Real A, B, C, U, V, sint, cost, SigneSqrtDis;
393   A=0.0;  B=0.0;   C=0.0;
394   U=0.0;  V=0.0;  
395   sint=0.0;  cost=0.0;
396   //
397   InternalUVValue(theta,U,V,A,B,C,cost,sint,SigneSqrtDis);
398   //
399   Pt = Value(theta);
400   if (Abs(A)<1.0e-7 || Abs(SigneSqrtDis)<1.0e-10) return(Standard_False);
401   
402   
403   //-- Approximation de la derivee (mieux que le calcul mathematique!)
404   Standard_Real dtheta = (DomainSup - DomainInf)*1.0e-6;
405   Standard_Real theta2 = theta+dtheta;
406   if ((theta2<DomainInf) || ((theta2>DomainSup) && (!TwoCurves))
407       || (theta2>(DomainSup + DomainSup - DomainInf + 1.0e-14)))
408   {
409     dtheta = -dtheta;
410     theta2 = theta+dtheta;
411   }
412   gp_Pnt P2 = Value(theta2);
413   dtheta = 1.0/dtheta;
414   Vec.SetCoord((P2.X()-Pt.X())*dtheta,
415                (P2.Y()-Pt.Y())*dtheta,
416                (P2.Z()-Pt.Z())*dtheta);
417   
418   return(Standard_True);
419 }  
420 //=======================================================================
421 //function : FindParameter
422 //purpose  : Projects P to the ALine. Returns the list of parameters as a results
423 //            of projection.
424 //           Sometimes aline can be self-intersected line (see bug #29807 where 
425 //            ALine goes through the cone apex).
426 //=======================================================================
427 void IntAna_Curve::FindParameter(const gp_Pnt& theP,
428                                  TColStd_ListOfReal& theParams) const
429 {
430   const Standard_Real aPIpPI = M_PI + M_PI,
431                       anEpsAng = 1.e-8,
432                       aSqTolPrecision=1.0e-8;
433   Standard_Real aTheta = 0.0;
434   //
435   switch (typequadric)
436   {
437     case GeomAbs_Cylinder:
438     {
439       Standard_Real aZ;
440       ElSLib::CylinderParameters(Ax3, RCyl, theP, aTheta, aZ);
441     }
442     break;
443
444     case GeomAbs_Cone:
445     {
446       Standard_Real aZ;
447       ElSLib::ConeParameters(Ax3, RCyl, Angle, theP, aTheta, aZ);
448     }
449     break;
450
451     default:
452       return;
453   }
454   //
455   if (!firstbounded && (DomainInf > aTheta) && ((DomainInf - aTheta) <= anEpsAng))
456   {
457     aTheta = DomainInf;
458   }
459   else if (!lastbounded && (aTheta > DomainSup) && ((aTheta - DomainSup) <= anEpsAng))
460   {
461     aTheta = DomainSup;
462   }
463   //
464   if (aTheta < DomainInf)
465   {
466     aTheta = aTheta + aPIpPI;
467   }
468   else if (aTheta > DomainSup)
469   {
470     aTheta = aTheta - aPIpPI;
471   }
472
473   const Standard_Integer aMaxPar = 5;
474   Standard_Real aParams[aMaxPar] = {DomainInf, DomainSup, aTheta,
475                                     (TwoCurves)? DomainSup + DomainSup - aTheta : RealLast(),
476                                     (TwoCurves) ? DomainSup + DomainSup - DomainInf : RealLast()};
477
478   std::sort(aParams, aParams + aMaxPar - 1);
479
480   for (Standard_Integer i = 0; i < aMaxPar; i++)
481   {
482     if (aParams[i] > myLastParameter)
483       break;
484     
485     if (aParams[i] < myFirstParameter)
486       continue;
487
488     if (i && (aParams[i] - aParams[i - 1]) < Precision::PConfusion())
489       continue;
490
491     Standard_Real U = 0.0, V= 0.0, 
492                   A = 0.0, B = 0.0, C = 0.0,
493                   sint = 0.0, cost = 0.0, SigneSqrtDis = 0.0;
494     InternalUVValue(aParams[i], U, V, A, B, C, 
495                     cost, sint, SigneSqrtDis);
496     const gp_Pnt aP(InternalValue(U, V));
497     if (aP.SquareDistance(theP) < aSqTolPrecision)
498     {
499       theParams.Append(aParams[i]);
500     }
501   }
502 }
503 //=======================================================================
504 //function : InternalValue
505 //purpose  : 
506 //=======================================================================
507 gp_Pnt IntAna_Curve::InternalValue(const Standard_Real U,
508                                    const Standard_Real _V) const
509 {
510   //-- cout<<" ["<<U<<","<<V<<"]";
511   Standard_Real V = _V;
512   if(V > 100000.0 )   {   V= 100000.0; }       
513   if(V < -100000.0 )  {   V=-100000.0; }      
514
515   switch(typequadric) {
516   case GeomAbs_Cone:
517     {
518       //------------------------------------------------
519       //-- Parametrage : X = V * Cos(U)              ---
520       //--               Y = V * Sin(U)              ---
521       //--               Z = (V-RCyl) / Tan(SemiAngle)--
522       //------------------------------------------------ 
523       //-- Angle Vaut Cone.SemiAngle()  
524       return(ElSLib::ConeValue(U,(V-RCyl)/Sin(Angle),Ax3,RCyl,Angle));
525     }
526     break;
527     
528   case GeomAbs_Cylinder:
529     return(ElSLib::CylinderValue(U,V,Ax3,RCyl)); 
530   case GeomAbs_Sphere:
531     return(ElSLib::SphereValue(U,V,Ax3,RCyl)); 
532   default:
533     return(gp_Pnt(0.0,0.0,0.0));
534   }
535 }
536
537 //
538 //=======================================================================
539 //function : SetDomain
540 //purpose  : 
541 //=======================================================================
542 void IntAna_Curve::SetDomain(const Standard_Real theFirst,
543                              const Standard_Real theLast)
544 {
545   if (theLast <= theFirst)
546   {
547     throw Standard_DomainError("IntAna_Curve::Domain");
548   }
549   //
550   myFirstParameter = theFirst;
551   myLastParameter = theLast;
552 }