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 #include <Extrema_ExtElC.hxx>
18 #include <Extrema_ExtElC2d.hxx>
19 #include <Extrema_ExtPElC.hxx>
20 #include <Extrema_POnCurv.hxx>
24 #include <gp_Circ.hxx>
25 #include <gp_Circ2d.hxx>
27 #include <gp_Elips.hxx>
28 #include <gp_Hypr.hxx>
30 #include <gp_Lin2d.hxx>
31 #include <gp_Parab.hxx>
34 #include <IntAna_QuadQuadGeo.hxx>
35 #include <IntAna2d_AnaIntersection.hxx>
36 #include <math_DirectPolynomialRoots.hxx>
37 #include <math_TrigonometricFunctionRoots.hxx>
38 #include <Precision.hxx>
39 #include <Standard_OutOfRange.hxx>
40 #include <StdFail_NotDone.hxx>
44 void RefineDir(gp_Dir& aDir);
46 //=======================================================================
47 //class : ExtremaExtElC_TrigonometricRoots
49 //== Classe Interne (Donne des racines classees d un polynome trigo)
50 //== Code duplique avec IntAna_IntQuadQuad.cxx (lbr le 26 mars 98)
51 //== Solution fiable aux problemes de coefficients proches de 0
52 //== avec essai de rattrapage si coeff<1.e-10 (jct le 27 avril 98)
53 //=======================================================================
54 class ExtremaExtElC_TrigonometricRoots {
56 Standard_Real Roots[4];
57 Standard_Boolean done;
58 Standard_Integer NbRoots;
59 Standard_Boolean infinite_roots;
61 ExtremaExtElC_TrigonometricRoots(const Standard_Real CC,
62 const Standard_Real SC,
63 const Standard_Real C,
64 const Standard_Real S,
65 const Standard_Real Cte,
66 const Standard_Real Binf,
67 const Standard_Real Bsup);
69 Standard_Boolean IsDone() {
73 Standard_Boolean IsARoot(Standard_Real u) {
74 Standard_Real PIpPI, aEps;
78 for(Standard_Integer i=0 ; i<NbRoots; i++) {
79 if(Abs(u - Roots[i])<=aEps) {
80 return Standard_True ;
82 if(Abs(u - Roots[i]-PIpPI)<=aEps) {
86 return Standard_False;
89 Standard_Integer NbSolutions() {
91 throw StdFail_NotDone();
96 Standard_Boolean InfiniteRoots() {
98 throw StdFail_NotDone();
100 return infinite_roots;
103 Standard_Real Value(const Standard_Integer& n) {
104 if((!done)||(n>NbRoots)) {
105 throw StdFail_NotDone();
110 //=======================================================================
111 //function : ExtremaExtElC_TrigonometricRoots
113 //=======================================================================
114 ExtremaExtElC_TrigonometricRoots::
115 ExtremaExtElC_TrigonometricRoots(const Standard_Real CC,
116 const Standard_Real SC,
117 const Standard_Real C,
118 const Standard_Real S,
119 const Standard_Real Cte,
120 const Standard_Real Binf,
121 const Standard_Real Bsup)
123 Standard_Integer i, nbessai;
124 Standard_Real cc ,sc, c, s, cte;
133 while (nbessai<=2 && !done) {
134 //-- F= AA*CN*CN+2*BB*CN*SN+CC*CN+DD*SN+EE;
135 math_TrigonometricFunctionRoots MTFR(cc,sc,c,s,cte,Binf,Bsup);
139 if(MTFR.InfiniteRoots()) {
140 infinite_roots=Standard_True;
143 Standard_Boolean Triee;
144 Standard_Integer j, SvNbRoots;
145 Standard_Real aTwoPI, aMaxCoef, aPrecision;
148 NbRoots=MTFR.NbSolutions();
149 for(i=0;i<NbRoots;++i) {
150 Roots[i]=MTFR.Value(i+1);
152 Roots[i]=Roots[i]+aTwoPI;
154 if(Roots[i]>aTwoPI) {
155 Roots[i]=Roots[i]-aTwoPI;
159 //-- La recherche directe donne n importe quoi.
160 aMaxCoef = Max(CC,SC);
161 aMaxCoef = Max(aMaxCoef,C);
162 aMaxCoef = Max(aMaxCoef,S);
163 aMaxCoef = Max(aMaxCoef,Cte);
164 aPrecision = Max(1.e-8, 1.e-12*aMaxCoef);
167 for(i=0; i<SvNbRoots; ++i) {
169 Standard_Real co=cos(Roots[i]);
170 Standard_Real si=sin(Roots[i]);
171 y=co*(CC*co + (SC+SC)*si + C) + S*si + Cte;
172 // modified by OCC Tue Oct 3 18:43:00 2006
173 if(Abs(y)>aPrecision) {
183 for(i=1, j=0; i<SvNbRoots; ++i, ++j) {
184 if(Roots[i]<Roots[j]) {
185 Triee=Standard_False;
194 infinite_roots=Standard_False;
195 if(NbRoots==0) { //--!!!!! Detect case Pol = Cte ( 1e-50 ) !!!!
196 if((Abs(CC) + Abs(SC) + Abs(C) + Abs(S)) < 1e-10) {
197 if(Abs(Cte) < 1e-10) {
198 infinite_roots=Standard_True;
203 } // if(MTFR.IsDone()) {
205 // try to set very small coefficients to ZERO
223 } // while (nbessai<=2 && !done) {
226 //=======================================================================
227 //function : Extrema_ExtElC
229 //=======================================================================
230 Extrema_ExtElC::Extrema_ExtElC ()
232 myDone = Standard_False;
233 myIsPar = Standard_False;
236 for (Standard_Integer i = 0; i < 6; i++)
238 mySqDist[i] = RealLast();
241 //=======================================================================
242 //function : Extrema_ExtElC
244 //=======================================================================
245 Extrema_ExtElC::Extrema_ExtElC (const gp_Lin& theC1,
249 // Find min distance between 2 straight lines.
252 // Let D1 and D2, be 2 directions of straight lines C1 and C2.
253 // 2 cases are considered:
254 // 1- if Angle(D1,D2) < AngTol, straight lines are parallel.
255 // The distance is the distance between a point of C1 and the straight line C2.
256 // 2- if Angle(D1,D2) > AngTol:
257 // Let P1=C1(u1) and P2=C2(u2).
258 // Then we must find u1 and u2 such as the distance P1P2 is minimal.
259 // Target function is:
260 // F(u1, u2) = ((L1x+D1x*u1)-(L2x+D2x*u2))^2 +
261 // ((L1y+D1y*u1)-(L2y+D2y*u2))^2 +
262 // ((L1z+D1z*u1)-(L2z+D2z*u2))^2 --> min,
263 // where L1 and L2 are lines locations, D1 and D2 are lines directions.
264 // Let simplify the function F
266 // F(u1, u2) = (D1x*u1-D2x*u2-Lx)^2 + (D1y*u1-D2y*u2-Ly)^2 + (D1z*u1-D2z*u2-Lz)^2,
267 // where L is a vector L1L2.
269 // In point of minimum, the condition
273 // must be satisfied.
275 // dF/du1 = 2*D1x*(D1x*u1-D2x*u2-Lx) +
276 // 2*D1y*(D1y*u1-D2y*u2-Ly) +
277 // 2*D1z*(D1z*u1-D2z*u2-Lz) =
278 // = 2*((D1^2)*u1-(D1.D2)*u2-L.D1) =
279 // = 2*(u1-(D1.D2)*u2-L.D1)
280 // dF/du2 = -2*D2x*(D1x*u1-D2x*u2-Lx) -
281 // 2*D2y*(D1y*u1-D2y*u2-Ly) -
282 // 2*D2z*(D1z*u1-D2z*u2-Lz)=
283 // = -2*((D2.D1)*u1-(D2^2)*u2-(D2.L)) =
284 // = -2*((D2.D1)*u1-u2-(D2.L))
286 // Consequently, we have two-equation system with two variables:
288 // {u1 - (D1.D2)*u2 = L.D1
289 // {(D1.D2)*u1 - u2 = L.D2
291 // This system has one solution if (D1.D2)^2 != 1
292 // (if straight lines are not parallel).
294 myDone = Standard_False;
296 myIsPar = Standard_False;
298 const gp_Dir &aD1 = theC1.Position().Direction(),
299 &aD2 = theC2.Position().Direction();
300 const Standard_Real aCosA = aD1.Dot(aD2);
301 const Standard_Real aSqSinA = 1.0 - aCosA * aCosA;
302 Standard_Real aU1 = 0.0, aU2 = 0.0;
303 if (aSqSinA < gp::Resolution() || aD1.IsParallel(aD2, Precision::Angular()))
305 myIsPar = Standard_True;
309 const gp_XYZ aL1L2 = theC2.Location().XYZ() - theC1.Location().XYZ();
310 const Standard_Real aD1L = aD1.XYZ().Dot(aL1L2),
311 aD2L = aD2.XYZ().Dot(aL1L2);
312 aU1 = (aD1L - aCosA * aD2L) / aSqSinA;
313 aU2 = (aCosA * aD1L - aD2L) / aSqSinA;
315 myIsPar = Precision::IsInfinite(aU1) || Precision::IsInfinite(aU2);
320 mySqDist[0] = theC2.SquareDistance(theC1.Location());
322 myDone = Standard_True;
326 // Here myIsPar == Standard_False;
328 const gp_Pnt aP1(ElCLib::Value(aU1, theC1)),
329 aP2(ElCLib::Value(aU2, theC2));
330 mySqDist[myNbExt] = aP1.SquareDistance(aP2);
331 myPoint[myNbExt][0] = Extrema_POnCurv(aU1, aP1);
332 myPoint[myNbExt][1] = Extrema_POnCurv(aU2, aP2);
334 myDone = Standard_True;
337 //=======================================================================
338 //function : PlanarLineCircleExtrema
340 //=======================================================================
341 Standard_Boolean Extrema_ExtElC::PlanarLineCircleExtrema(const gp_Lin& theLin,
342 const gp_Circ& theCirc)
344 const gp_Dir &aDirC = theCirc.Axis().Direction(),
345 &aDirL = theLin.Direction();
347 if (Abs(aDirC.Dot(aDirL)) > Precision::Angular())
348 return Standard_False;
350 //The line is in the circle-plane completely
351 //(or parallel to the circle-plane).
352 //Therefore, we are looking for extremas and
353 //intersections in 2D-space.
355 const gp_XYZ &aCLoc = theCirc.Location().XYZ();
356 const gp_XYZ &aDCx = theCirc.Position().XDirection().XYZ(),
357 &aDCy = theCirc.Position().YDirection().XYZ();
359 const gp_XYZ &aLLoc = theLin.Location().XYZ();
360 const gp_XYZ &aLDir = theLin.Direction().XYZ();
362 const gp_XYZ aVecCL(aLLoc - aCLoc);
364 //Center of 2D-circle
365 const gp_Pnt2d aPC(0.0, 0.0);
367 gp_Ax22d aCircAxis(aPC, gp_Dir2d(1.0, 0.0), gp_Dir2d(0.0, 1.0));
368 gp_Circ2d aCirc2d(aCircAxis, theCirc.Radius());
370 gp_Pnt2d aPL(aVecCL.Dot(aDCx), aVecCL.Dot(aDCy));
371 gp_Dir2d aDL(aLDir.Dot(aDCx), aLDir.Dot(aDCy));
372 gp_Lin2d aLin2d(aPL, aDL);
375 Extrema_ExtElC2d anExt2d(aLin2d, aCirc2d, Precision::Confusion());
377 IntAna2d_AnaIntersection anInters(aLin2d, aCirc2d);
379 myDone = anExt2d.IsDone() || anInters.IsDone();
382 return Standard_True;
384 const Standard_Integer aNbExtr = anExt2d.NbExt();
385 const Standard_Integer aNbSol = anInters.NbPoints();
387 const Standard_Integer aNbSum = aNbExtr + aNbSol;
388 for (Standard_Integer anExtrID = 1; anExtrID <= aNbSum; anExtrID++)
390 const Standard_Integer aDelta = anExtrID - aNbExtr;
392 Standard_Real aLinPar = 0.0, aCircPar = 0.0;
396 Extrema_POnCurv2d aPLin2d, aPCirc2d;
397 anExt2d.Points(anExtrID, aPLin2d, aPCirc2d);
398 aLinPar = aPLin2d.Parameter();
399 aCircPar = aPCirc2d.Parameter();
403 aLinPar = anInters.Point(aDelta).ParamOnFirst();
404 aCircPar = anInters.Point(aDelta).ParamOnSecond();
407 const gp_Pnt aPOnL(ElCLib::LineValue(aLinPar, theLin.Position())),
408 aPOnC(ElCLib::CircleValue(aCircPar,
409 theCirc.Position(), theCirc.Radius()));
411 mySqDist[myNbExt] = aPOnL.SquareDistance(aPOnC);
412 myPoint[myNbExt][0].SetValues(aLinPar, aPOnL);
413 myPoint[myNbExt][1].SetValues(aCircPar, aPOnC);
417 return Standard_True;
420 //=======================================================================
421 //function : Extrema_ExtElC
423 // Find extreme distances between straight line C1 and circle C2.
426 // Let P1=C1(u1) and P2=C2(u2) be two solution points
427 // D the direction of straight line C1
428 // T tangent at point P2;
429 // Then, ( P1P2.D = 0. (1)
431 // Let O1 and O2 be the origins of C1 and C2;
432 // Then, (1) <=> (O1P2-u1*D).D = 0. as O1P1 = u1*D
433 // <=> u1 = O1P2.D as D.D = 1.
434 // (2) <=> P1O2.T = 0. as O2P2.T = 0.
435 // <=> ((P2O1.D)D+O1O2).T = 0. as P1O1 = -u1*D = (P2O1.D)D
436 // <=> (((P2O2+O2O1).D)D+O1O2).T = 0.
437 // <=> ((P2O2.D)(D.T)+((O2O1.D)D-O2O1).T = 0.
438 // We are in the reference of the circle; let:
439 // Cos = Cos(u2) and Sin = Sin(u2),
440 // P2 (R*Cos,R*Sin,0.),
441 // T (-R*Sin,R*Cos,0.),
443 // V (Vx,Vy,Vz) = (O2O1.D)D-O2O1;
444 // Then, the equation by Cos and Sin is as follows:
445 // -(2*R*R*Dx*Dy) * Cos**2 + A1
446 // R*R*(Dx**2-Dy**2) * Cos*Sin + 2* A2
450 //Use the algorithm math_TrigonometricFunctionRoots to solve this equation.
451 //=======================================================================
452 Extrema_ExtElC::Extrema_ExtElC (const gp_Lin& C1,
456 Standard_Real Dx,Dy,Dz,aRO2O1, aTolRO2O1;
457 Standard_Real R, A1, A2, A3, A4, A5, aTol;
458 gp_Dir x2, y2, z2, D, D1;
460 myIsPar = Standard_False;
461 myDone = Standard_False;
464 if (PlanarLineCircleExtrema(C1, C2))
469 // Calculate T1 in the reference of the circle ...
472 x2 = C2.XAxis().Direction();
473 y2 = C2.YAxis().Direction();
474 z2 = C2.Axis().Direction();
479 D.SetCoord(Dx, Dy, Dz);
483 // Calcul de V dans le repere du cercle:
484 gp_Pnt O1 = C1.Location();
485 gp_Pnt O2 = C2.Location();
488 aTolRO2O1=gp::Resolution();
489 aRO2O1=O2O1.Magnitude();
490 if (aRO2O1 > aTolRO2O1) {
493 O2O1.Multiply(1./aRO2O1);
494 aDO2O1.SetCoord(O2O1.Dot(x2), O2O1.Dot(y2), O2O1.Dot(z2));
496 O2O1.SetXYZ(aRO2O1*aDO2O1.XYZ());
499 O2O1.SetCoord(O2O1.Dot(x2), O2O1.Dot(y2), O2O1.Dot(z2));
502 gp_XYZ Vxyz = (D.XYZ()*(O2O1.Dot(D)))-O2O1.XYZ();
504 //modified by NIZNHY-PKV Tue Mar 20 10:36:38 2012
509 A2 = R*R*(Dx*Dx-Dy*Dy)/2.;
516 if(fabs(A5) <= aTol) {
519 if(fabs(A1) <= aTol) {
522 if(fabs(A2) <= aTol) {
525 if(fabs(A3) <= aTol) {
528 if(fabs(A4) <= aTol) {
534 // Calculate the coefficients of the equation by Cos and Sin ...
539 A2 = 0.5*R*(Dx*Dx-Dy*Dy);// /2.;
543 if (A1>=-aTol && A1<=aTol) {
546 if (A2>=-aTol && A2<=aTol) {
549 if (A3>=-aTol && A3<=aTol) {
552 if (A4>=-aTol && A4<=aTol) {
555 if (A5>=-aTol && A5<=aTol) {
558 //modified by NIZNHY-PKV Tue Mar 20 10:36:40 2012t
560 ExtremaExtElC_TrigonometricRoots Sol(A1, A2, A3, A4, A5, 0., M_PI+M_PI);
564 if (Sol.InfiniteRoots()) {
565 myIsPar = Standard_True;
568 myDone = Standard_True;
571 // Storage of solutions ...
572 Standard_Integer NoSol, NbSol;
576 NbSol = Sol.NbSolutions();
577 for (NoSol=1; NoSol<=NbSol; ++NoSol) {
578 U2 = Sol.Value(NoSol);
579 P2 = ElCLib::Value(U2,C2);
580 U1 = (gp_Vec(O1,P2)).Dot(D1);
581 P1 = ElCLib::Value(U1,C1);
582 mySqDist[myNbExt] = P1.SquareDistance(P2);
583 //modified by NIZNHY-PKV Wed Mar 21 08:11:33 2012f
584 //myPoint[myNbExt][0] = Extrema_POnCurv(U1,P1);
585 //myPoint[myNbExt][1] = Extrema_POnCurv(U2,P2);
586 myPoint[myNbExt][0].SetValues(U1,P1);
587 myPoint[myNbExt][1].SetValues(U2,P2);
588 //modified by NIZNHY-PKV Wed Mar 21 08:11:36 2012t
591 myDone = Standard_True;
593 //=======================================================================
594 //function : Extrema_ExtElC
596 //=======================================================================
597 Extrema_ExtElC::Extrema_ExtElC (const gp_Lin& C1,
600 /*-----------------------------------------------------------------------------
602 Find extreme distances between straight line C1 and ellipse C2.
605 Let P1=C1(u1) and P2=C2(u2) two solution points
606 D the direction of straight line C1
607 T the tangent to point P2;
608 Then, ( P1P2.D = 0. (1)
610 Let O1 and O2 be the origins of C1 and C2;
611 Then, (1) <=> (O1P2-u1*D).D = 0. as O1P1 = u1*D
612 <=> u1 = O1P2.D as D.D = 1.
613 (2) <=> P1O2.T = 0. as O2P2.T = 0.
614 <=> ((P2O1.D)D+O1O2).T = 0. as P1O1 = -u1*D = (P2O1.D)D
615 <=> (((P2O2+O2O1).D)D+O1O2).T = 0.
616 <=> ((P2O2.D)(D.T)+((O2O1.D)D-O2O1).T = 0.
617 We are in the reference of the ellipse; let:
618 Cos = Cos(u2) and Sin = Sin(u2),
619 P2 (MajR*Cos,MinR*Sin,0.),
620 T (-MajR*Sin,MinR*Cos,0.),
622 V (Vx,Vy,Vz) = (O2O1.D)D-O2O1;
623 Then, get the following equation by Cos and Sin:
624 -(2*MajR*MinR*Dx*Dy) * Cos**2 +
625 (MajR*MajR*Dx**2-MinR*MinR*Dy**2) * Cos*Sin +
629 Use algorithm math_TrigonometricFunctionRoots to solve this equation.
630 -----------------------------------------------------------------------------*/
631 myIsPar = Standard_False;
632 myDone = Standard_False;
635 // Calculate T1 the reference of the ellipse ...
636 gp_Dir D = C1.Direction();
639 x2 = C2.XAxis().Direction();
640 y2 = C2.YAxis().Direction();
641 z2 = C2.Axis().Direction();
642 Standard_Real Dx = D.Dot(x2);
643 Standard_Real Dy = D.Dot(y2);
644 Standard_Real Dz = D.Dot(z2);
645 D.SetCoord(Dx,Dy,Dz);
648 gp_Pnt O1 = C1.Location();
649 gp_Pnt O2 = C2.Location();
651 O2O1.SetCoord(O2O1.Dot(x2), O2O1.Dot(y2), O2O1.Dot(z2));
652 gp_XYZ Vxyz = (D.XYZ()*(O2O1.Dot(D)))-O2O1.XYZ();
654 // Calculate the coefficients of the equation by Cos and Sin ...
655 Standard_Real MajR = C2.MajorRadius();
656 Standard_Real MinR = C2.MinorRadius();
657 Standard_Real A5 = MajR*MinR*Dx*Dy;
658 Standard_Real A1 = -2.*A5;
659 Standard_Real R2 = MajR*MajR;
660 Standard_Real r2 = MinR*MinR;
661 Standard_Real A2 =(R2*Dx*Dx -r2*Dy*Dy -R2 +r2)/2.0;
662 Standard_Real A3 = MinR*Vxyz.Y();
663 Standard_Real A4 = -MajR*Vxyz.X();
665 Standard_Real aEps=1.e-12;
667 if(fabs(A5) <= aEps) A5 = 0.;
668 if(fabs(A1) <= aEps) A1 = 0.;
669 if(fabs(A2) <= aEps) A2 = 0.;
670 if(fabs(A3) <= aEps) A3 = 0.;
671 if(fabs(A4) <= aEps) A4 = 0.;
673 ExtremaExtElC_TrigonometricRoots Sol(A1,A2,A3,A4,A5,0.,M_PI+M_PI);
674 if (!Sol.IsDone()) { return; }
676 if (Sol.InfiniteRoots()) {
677 myIsPar = Standard_True;
678 gp_Pnt aP = ElCLib::EllipseValue(0., C2.Position(), C2.MajorRadius(), C2.MinorRadius());
679 mySqDist[0] = C1.SquareDistance(aP);
681 myDone = Standard_True;
685 // Storage of solutions ...
688 Standard_Integer NbSol = Sol.NbSolutions();
689 for (Standard_Integer NoSol = 1; NoSol <= NbSol; NoSol++) {
690 U2 = Sol.Value(NoSol);
691 P2 = ElCLib::Value(U2,C2);
692 U1 = (gp_Vec(O1,P2)).Dot(D1);
693 P1 = ElCLib::Value(U1,C1);
694 mySqDist[myNbExt] = P1.SquareDistance(P2);
695 myPoint[myNbExt][0] = Extrema_POnCurv(U1,P1);
696 myPoint[myNbExt][1] = Extrema_POnCurv(U2,P2);
699 myDone = Standard_True;
702 //=======================================================================
703 //function : Extrema_ExtElC
705 //=======================================================================
706 Extrema_ExtElC::Extrema_ExtElC (const gp_Lin& C1,
709 /*-----------------------------------------------------------------------------
711 Find extrema between straight line C1 and hyperbola C2.
714 Let P1=C1(u1) and P2=C2(u2) be two solution points
715 D the direction of straight line C1
716 T the tangent at point P2;
717 Then, ( P1P2.D = 0. (1)
719 Let O1 and O2 be the origins of C1 and C2;
720 Then, (1) <=> (O1P2-u1*D).D = 0. as O1P1 = u1*D
721 <=> u1 = O1P2.D as D.D = 1.
722 (2) <=> (P1O2 + O2P2).T= 0.
723 <=> ((P2O1.D)D+O1O2 + O2P2).T = 0. as P1O1 = -u1*D = (P2O1.D)D
724 <=> (((P2O2+O2O1).D)D+O1O2 + O2P2).T = 0.
725 <=> (P2O2.D)(D.T)+((O2O1.D)D-O2O1).T + O2P2.T= 0.
726 We are in the reference of the hyperbola; let:
727 by writing P (R* Chu, r* Shu, 0.0)
728 and Chu = (v**2 + 1)/(2*v) ,
729 Shu = (V**2 - 1)/(2*v)
733 V (Vx,Vy,Vz) = (O2O1.D)D-O2O1;
735 Then we obtain the following equation by v:
736 (-2*R*r*Dx*Dy - R*R*Dx*Dx-r*r*Dy*Dy + R*R + r*r) * v**4 +
737 (2*R*Vx + 2*r*Vy) * v**3 +
738 (-2*R*Vx + 2*r*Vy) * v +
739 (-2*R*r*Dx*Dy - (R*R*Dx*Dx-r*r*Dy*Dy + R*R + r*r)) = 0
742 Use the algorithm math_DirectPolynomialRoots to solve this equation.
743 -----------------------------------------------------------------------------*/
744 myIsPar = Standard_False;
745 myDone = Standard_False;
748 // Calculate T1 in the reference of the hyperbola...
749 gp_Dir D = C1.Direction();
752 x2 = C2.XAxis().Direction();
753 y2 = C2.YAxis().Direction();
754 z2 = C2.Axis().Direction();
755 Standard_Real Dx = D.Dot(x2);
756 Standard_Real Dy = D.Dot(y2);
757 Standard_Real Dz = D.Dot(z2);
758 D.SetCoord(Dx,Dy,Dz);
761 gp_Pnt O1 = C1.Location();
762 gp_Pnt O2 = C2.Location();
764 O2O1.SetCoord(O2O1.Dot(x2), O2O1.Dot(y2), O2O1.Dot(z2));
765 gp_XYZ Vxyz = (D.XYZ()*(O2O1.Dot(D)))-O2O1.XYZ();
766 Standard_Real Vx = Vxyz.X();
767 Standard_Real Vy = Vxyz.Y();
769 // Calculate coefficients of the equation by v
770 Standard_Real R = C2.MajorRadius();
771 Standard_Real r = C2.MinorRadius();
772 Standard_Real a = -2*R*r*Dx*Dy;
773 Standard_Real b = -R*R*Dx*Dx - r*r*Dy*Dy + R*R + r*r;
774 Standard_Real A1 = a + b;
775 Standard_Real A2 = 2*R*Vx + 2*r*Vy;
776 Standard_Real A4 = -2*R*Vx + 2*r*Vy;
777 Standard_Real A5 = a - b;
779 math_DirectPolynomialRoots Sol(A1,A2,0.0,A4, A5);
780 if (!Sol.IsDone()) { return; }
782 // Store solutions ...
784 Standard_Real U1,U2, v;
785 Standard_Integer NbSol = Sol.NbSolutions();
786 for (Standard_Integer NoSol = 1; NoSol <= NbSol; NoSol++) {
787 v = Sol.Value(NoSol);
790 P2 = ElCLib::Value(U2,C2);
791 U1 = (gp_Vec(O1,P2)).Dot(D1);
792 P1 = ElCLib::Value(U1,C1);
793 mySqDist[myNbExt] = P1.SquareDistance(P2);
794 myPoint[myNbExt][0] = Extrema_POnCurv(U1,P1);
795 myPoint[myNbExt][1] = Extrema_POnCurv(U2,P2);
799 myDone = Standard_True;
801 //=======================================================================
802 //function : Extrema_ExtElC
804 //=======================================================================
805 Extrema_ExtElC::Extrema_ExtElC (const gp_Lin& C1,
808 /*-----------------------------------------------------------------------------
810 Find extreme distances between straight line C1 and parabole C2.
813 Let P1=C1(u1) and P2=C2(u2) be two solution points
814 D the direction of straight line C1
815 T the tangent to point P2;
816 Then, ( P1P2.D = 0. (1)
818 Let O1 and O2 be the origins of C1 and C2;
819 Then, (1) <=> (O1P2-u1*D).D = 0. as O1P1 = u1*D
820 <=> u1 = O1P2.D as D.D = 1.
821 (2) <=> (P1O2 + O2P2).T= 0.
822 <=> ((P2O1.D)D+O1O2 + O2P2).T = 0. as P1O1 = -u1*D = (P2O1.D)D
823 <=> (((P2O2+O2O1).D)D+O1O2 + O2P2).T = 0.
824 <=> (P2O2.D)(D.T)+((O2O1.D)D-O2O1).T + O2P2.T = 0.
825 We are in the reference of the parabola; let:
829 V (Vx,Vy,Vz) = (O2O1.D)D-O2O1;
831 Then, get the following equation by y:
832 ((1-Dx*Dx)/(2*p*p)) * y*y*y + A1
833 (-3*Dx*Dy/(2*p)) * y*y + A2
834 (1-Dy*Dy + Vx/p) * y + A3
837 Use the algorithm math_DirectPolynomialRoots to solve this equation.
838 -----------------------------------------------------------------------------*/
839 myIsPar = Standard_False;
840 myDone = Standard_False;
843 // Calculate T1 in the reference of the parabola...
844 gp_Dir D = C1.Direction();
847 x2 = C2.XAxis().Direction();
848 y2 = C2.YAxis().Direction();
849 z2 = C2.Axis().Direction();
850 Standard_Real Dx = D.Dot(x2);
851 Standard_Real Dy = D.Dot(y2);
852 Standard_Real Dz = D.Dot(z2);
853 D.SetCoord(Dx,Dy,Dz);
856 gp_Pnt O1 = C1.Location();
857 gp_Pnt O2 = C2.Location();
859 O2O1.SetCoord(O2O1.Dot(x2), O2O1.Dot(y2), O2O1.Dot(z2));
860 gp_XYZ Vxyz = (D.XYZ()*(O2O1.Dot(D)))-O2O1.XYZ();
862 // Calculate coefficients of the equation by y
863 Standard_Real P = C2.Parameter();
864 Standard_Real A1 = (1-Dx*Dx)/(2.0*P*P);
865 Standard_Real A2 = (-3.0*Dx*Dy/(2.0*P));
866 Standard_Real A3 = (1 - Dy*Dy + Vxyz.X()/P);
867 Standard_Real A4 = Vxyz.Y();
869 math_DirectPolynomialRoots Sol(A1,A2,A3,A4);
870 if (!Sol.IsDone()) { return; }
872 // Storage of solutions ...
875 Standard_Integer NbSol = Sol.NbSolutions();
876 for (Standard_Integer NoSol = 1; NoSol <= NbSol; NoSol++) {
877 U2 = Sol.Value(NoSol);
878 P2 = ElCLib::Value(U2,C2);
879 U1 = (gp_Vec(O1,P2)).Dot(D1);
880 P1 = ElCLib::Value(U1,C1);
881 mySqDist[myNbExt] = P1.SquareDistance(P2);
882 myPoint[myNbExt][0] = Extrema_POnCurv(U1,P1);
883 myPoint[myNbExt][1] = Extrema_POnCurv(U2,P2);
886 myDone = Standard_True;
888 //=======================================================================
889 //function : Extrema_ExtElC
891 //=======================================================================
892 Extrema_ExtElC::Extrema_ExtElC (const gp_Circ& C1,
895 Standard_Boolean bIsSamePlane, bIsSameAxe;
896 Standard_Real aTolD, aTolD2, aTolA, aD2, aDC2;
900 myIsPar = Standard_False;
901 myDone = Standard_False;
904 aTolA=Precision::Angular();
905 aTolD=Precision::Confusion();
909 aDc1=C1.Axis().Direction();
912 aDc2=C2.Axis().Direction();
913 gp_Pln aPlc1(aPc1, aDc1);
915 aD2=aPlc1.SquareDistance(aPc2);
916 bIsSamePlane=aDc1.IsParallel(aDc2, aTolA) && aD2<aTolD2;
921 // Here, both circles are in the same plane.
924 aDC2=aPc1.SquareDistance(aPc2);
925 bIsSameAxe=aDC2<aTolD2;
929 myIsPar = Standard_True;
931 myDone = Standard_True;
932 const Standard_Real aDR = C1.Radius() - C2.Radius();
933 mySqDist[0] = aDR*aDR;
937 Standard_Boolean bIn, bOut;
938 Standard_Integer j1, j2;
939 Standard_Real aR1, aR2, aD12, aT11, aT12, aT21, aT22;
941 gp_Pnt aP11, aP12, aP21, aP22;
943 myDone = Standard_True;
960 aR1 = aC1.Radius(); // max radius
961 aR2 = aC2.Radius(); // min radius
963 aPc1 = aC1.Location();
964 aPc2 = aC2.Location();
966 aD12 = aPc1.Distance(aPc2);
967 gp_Vec aVec12(aPc1, aPc2);
968 gp_Dir aDir12(aVec12);
970 // 1. Four common solutions
973 aP11.SetXYZ(aPc1.XYZ() - aR1*aDir12.XYZ());
974 aP12.SetXYZ(aPc1.XYZ() + aR1*aDir12.XYZ());
975 aP21.SetXYZ(aPc2.XYZ() - aR2*aDir12.XYZ());
976 aP22.SetXYZ(aPc2.XYZ() + aR2*aDir12.XYZ());
978 aT11 = ElCLib::Parameter(aC1, aP11);
979 aT12 = ElCLib::Parameter(aC1, aP12);
980 aT21 = ElCLib::Parameter(aC2, aP21);
981 aT22 = ElCLib::Parameter(aC2, aP22);
984 myPoint[0][j1].SetValues(aT11, aP11);
985 myPoint[0][j2].SetValues(aT21, aP21);
986 mySqDist[0] = aP11.SquareDistance(aP21);
988 myPoint[1][j1].SetValues(aT11, aP11);
989 myPoint[1][j2].SetValues(aT22, aP22);
990 mySqDist[1] = aP11.SquareDistance(aP22);
993 myPoint[2][j1].SetValues(aT12, aP12);
994 myPoint[2][j2].SetValues(aT21, aP21);
995 mySqDist[2] = aP12.SquareDistance(aP21);
998 myPoint[3][j1].SetValues(aT12, aP12);
999 myPoint[3][j2].SetValues(aT22, aP22);
1000 mySqDist[3] = aP12.SquareDistance(aP22);
1002 // 2. Check for intersections
1003 bOut = aD12 > (aR1 + aR2 + aTolD);
1004 bIn = aD12 < (aR1 - aR2 - aTolD);
1007 Standard_Boolean bNbExt6;
1008 Standard_Real aAlpha, aBeta, aT[2], aVal, aDist2;
1009 gp_Pnt aPt, aPL1, aPL2;
1012 aAlpha = 0.5*(aR1*aR1 - aR2*aR2 + aD12*aD12) / aD12;
1013 aVal = aR1*aR1 - aAlpha*aAlpha;
1015 {// see pkv/900/L4 for details
1019 //aBeta=Sqrt(aR1*aR1-aAlpha*aAlpha);
1021 aPt.SetXYZ(aPc1.XYZ() + aAlpha*aDir12.XYZ());
1024 aPL1.SetXYZ(aPt.XYZ() + aBeta*aDLt.XYZ());
1025 aPL2.SetXYZ(aPt.XYZ() - aBeta*aDLt.XYZ());
1027 aDist2 = aPL1.SquareDistance(aPL2);
1028 bNbExt6 = aDist2 > aTolD2;
1030 myNbExt = 5;// just in case. see pkv/900/L4 for details
1031 aT[j1] = ElCLib::Parameter(aC1, aPL1);
1032 aT[j2] = ElCLib::Parameter(aC2, aPL1);
1033 myPoint[4][j1].SetValues(aT[j1], aPL1);
1034 myPoint[4][j2].SetValues(aT[j2], aPL1);
1040 aT[j1] = ElCLib::Parameter(aC1, aPL2);
1041 aT[j2] = ElCLib::Parameter(aC2, aPL2);
1042 myPoint[5][j1].SetValues(aT[j1], aPL2);
1043 myPoint[5][j2].SetValues(aT[j2], aPL2);
1047 }// if (!bOut || !bIn) {
1050 //=======================================================================
1053 //=======================================================================
1054 Standard_Boolean Extrema_ExtElC::IsDone () const {
1057 //=======================================================================
1058 //function : IsParallel
1060 //=======================================================================
1061 Standard_Boolean Extrema_ExtElC::IsParallel () const
1064 throw StdFail_NotDone();
1068 //=======================================================================
1071 //=======================================================================
1072 Standard_Integer Extrema_ExtElC::NbExt () const
1076 throw StdFail_NotDone();
1080 //=======================================================================
1081 //function : SquareDistance
1083 //=======================================================================
1084 Standard_Real Extrema_ExtElC::SquareDistance (const Standard_Integer N) const
1086 if (N < 1 || N > NbExt())
1088 throw Standard_OutOfRange();
1091 return mySqDist[N - 1];
1093 //=======================================================================
1096 //=======================================================================
1097 void Extrema_ExtElC::Points (const Standard_Integer N,
1098 Extrema_POnCurv& P1,
1099 Extrema_POnCurv& P2) const
1101 if (N < 1 || N > NbExt())
1103 throw Standard_OutOfRange();
1106 P1 = myPoint[N-1][0];
1107 P2 = myPoint[N-1][1];
1111 //=======================================================================
1112 //function : RefineDir
1114 //=======================================================================
1115 void RefineDir(gp_Dir& aDir)
1117 Standard_Integer i, j, k, iK;
1118 Standard_Real aCx[3], aEps, aX1, aX2, aOne;
1122 aDir.Coord(aCx[0], aCx[1], aCx[2]);
1124 for (i=0; i<iK; ++i) {
1125 aOne=(aCx[i]>0.) ? 1. : -1.;
1129 if (aCx[i]>aX1 && aCx[i]<aX2) {
1135 aDir.SetCoord(aCx[0], aCx[1], aCx[2]);