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.
15 // Modified by skv - Thu Jul 7 14:37:05 2005 OCC9134
19 #include <Extrema_ExtElC.hxx>
20 #include <Extrema_ExtElCS.hxx>
21 #include <Extrema_ExtPElC.hxx>
22 #include <Extrema_ExtPElS.hxx>
23 #include <Extrema_POnCurv.hxx>
24 #include <Extrema_POnSurf.hxx>
25 #include <gp_Circ.hxx>
26 #include <gp_Cone.hxx>
27 #include <gp_Cylinder.hxx>
28 #include <gp_Hypr.hxx>
31 #include <gp_Sphere.hxx>
32 #include <gp_Torus.hxx>
34 #include <IntAna_IntConicQuad.hxx>
35 #include <IntAna_Quadric.hxx>
36 #include <Precision.hxx>
37 #include <Standard_NotImplemented.hxx>
38 #include <Standard_OutOfRange.hxx>
39 #include <StdFail_InfiniteSolutions.hxx>
40 #include <StdFail_NotDone.hxx>
42 Extrema_ExtElCS::Extrema_ExtElCS()
44 myDone = Standard_False;
45 myIsPar = Standard_False;
49 Extrema_ExtElCS::Extrema_ExtElCS(const gp_Lin& C,
57 void Extrema_ExtElCS::Perform(const gp_Lin& C,
60 myDone = Standard_True;
61 myIsPar = Standard_False;
63 if (C.Direction().IsNormal(S.Axis().Direction(),
64 Precision::Angular())) {
65 mySqDist = new TColStd_HArray1OfReal(1, 1);
66 mySqDist->SetValue(1, S.SquareDistance(C));
67 myIsPar = Standard_True;
76 Extrema_ExtElCS::Extrema_ExtElCS(const gp_Lin& C,
84 void Extrema_ExtElCS::Perform(const gp_Lin& C,
87 myDone = Standard_False;
89 myIsPar = Standard_False;
91 gp_Ax3 Pos = S.Position();
92 gp_Pnt Origin = Pos.Location();
93 gp_Pnt LineOrig = C.Location();
95 Standard_Real radius = S.Radius();
96 Extrema_ExtElC Extrem(gp_Lin(Pos.Axis()), C, Precision::Angular());
97 if (Extrem.IsParallel()) {
98 // Line direction is similar to cylinder axis of rotation.
99 mySqDist = new TColStd_HArray1OfReal(1, 1);
100 myPoint1 = new Extrema_HArray1OfPOnCurv(1, 1);
101 myPoint2 = new Extrema_HArray1OfPOnSurf(1, 1);
102 Standard_Real aDist = sqrt(Extrem.SquareDistance(1)) - radius;
103 mySqDist->SetValue(1, aDist * aDist);
104 Standard_Real u, v, w;
105 gp_Vec aVec(LineOrig, Origin);
106 gp_Vec aDirVec(C.Direction());
108 gp_Pnt LinPoint = LineOrig.Translated(w * aDirVec);
109 Extrema_POnCurv PonC(w, LinPoint);
110 myPoint1->SetValue(1, PonC);
112 gp_Vec OrigToLine(Origin, LinPoint);
113 if (OrigToLine.Magnitude() <= gp::Resolution())
117 CylPoint = ElSLib::Value(u, v, S);
121 OrigToLine.Normalize();
122 CylPoint = Origin.Translated(radius * OrigToLine);
123 ElSLib::CylinderParameters(Pos, radius, CylPoint, u, v);
125 Extrema_POnSurf PonS(u, v, CylPoint);
126 myPoint2->SetValue(1, PonS);
127 myDone = Standard_True;
128 myIsPar = Standard_True;
131 Standard_Integer i, aStartIdx = 0;
133 Extrema_POnCurv myPOnC1, myPOnC2;
134 Extrem.Points(1, myPOnC1, myPOnC2);
135 gp_Pnt PonAxis = myPOnC1.Value();
136 gp_Pnt PC = myPOnC2.Value();
138 // line intersects the cylinder
139 if (radius - PonAxis.Distance(PC) > Precision::PConfusion())
141 IntAna_Quadric theQuadric(S);
142 IntAna_IntConicQuad Inters(C, theQuadric);
145 myNbExt = Inters.NbPoints();
149 // Not more than 2 additional points from perpendiculars.
150 mySqDist = new TColStd_HArray1OfReal(1, myNbExt + 2);
151 myPoint1 = new Extrema_HArray1OfPOnCurv(1, myNbExt + 2);
152 myPoint2 = new Extrema_HArray1OfPOnSurf(1, myNbExt + 2);
153 Standard_Real u, v, w;
154 for (i = 1; i <= myNbExt; i++)
156 mySqDist->SetValue(i, 0.);
157 gp_Pnt P_int = Inters.Point(i);
158 w = Inters.ParamOnConic(i);
159 Extrema_POnCurv PonC(w, P_int);
160 myPoint1->SetValue(i, PonC);
161 ElSLib::CylinderParameters(Pos, radius, P_int, u, v);
162 Extrema_POnSurf PonS(u, v, P_int);
163 myPoint2->SetValue(i, PonS);
169 // line is tangent or outside of the cylinder
170 Extrema_ExtPElS ExPS(PC, S, Precision::Confusion());
175 myNbExt = ExPS.NbExt();
176 mySqDist = new TColStd_HArray1OfReal(1, myNbExt);
177 myPoint1 = new Extrema_HArray1OfPOnCurv(1, myNbExt);
178 myPoint2 = new Extrema_HArray1OfPOnSurf(1, myNbExt);
181 myNbExt += ExPS.NbExt();
183 for (i = aStartIdx + 1; i <= myNbExt; i++) {
184 myPoint1->SetValue(i, myPOnC2);
185 myPoint2->SetValue(i, ExPS.Point(i - aStartIdx));
186 mySqDist->SetValue(i,(myPOnC2.Value()).SquareDistance(ExPS.Point(i - aStartIdx).Value()));
189 myDone = Standard_True;
196 Extrema_ExtElCS::Extrema_ExtElCS(const gp_Lin& C,
202 //void Extrema_ExtElCS::Perform(const gp_Lin& C,
204 void Extrema_ExtElCS::Perform(const gp_Lin& ,
207 throw Standard_NotImplemented();
213 Extrema_ExtElCS::Extrema_ExtElCS(const gp_Lin& C,
221 void Extrema_ExtElCS::Perform(const gp_Lin& C,
224 // In case of intersection - return four points:
225 // 2 intersection points and 2 perpendicular.
226 // No intersection - only min and max.
228 myDone = Standard_False;
230 myIsPar = Standard_False;
231 Standard_Integer aStartIdx = 0;
233 gp_Pnt aCenter = S.Location();
235 Extrema_ExtPElC Extrem(aCenter, C, Precision::Angular(), RealFirst(), RealLast());
238 if (Extrem.IsDone() &&
241 Extrema_POnCurv myPOnC1 = Extrem.Point(1);
242 if (myPOnC1.Value().Distance(aCenter) <= S.Radius())
244 IntAna_IntConicQuad aLinSphere(C, S);
245 if (aLinSphere.IsDone())
247 myNbExt = aLinSphere.NbPoints();
249 // Not more than 2 additional points from perpendiculars.
250 mySqDist = new TColStd_HArray1OfReal(1, myNbExt + 2);
251 myPoint1 = new Extrema_HArray1OfPOnCurv(1, myNbExt + 2);
252 myPoint2 = new Extrema_HArray1OfPOnSurf(1, myNbExt + 2);
254 for (i = 1; i <= myNbExt; i++)
256 Extrema_POnCurv aCPnt(aLinSphere.ParamOnConic(i), aLinSphere.Point(i));
259 ElSLib::Parameters(S, aLinSphere.Point(i), u, v);
260 Extrema_POnSurf aSPnt(u, v, aLinSphere.Point(i));
262 myPoint1->SetValue(i, aCPnt);
263 myPoint2->SetValue(i, aSPnt);
264 mySqDist->SetValue(i,(aCPnt.Value()).SquareDistance(aSPnt.Value()));
269 Extrema_ExtPElS ExPS(myPOnC1.Value(), S, Precision::Confusion());
274 myNbExt = ExPS.NbExt();
275 mySqDist = new TColStd_HArray1OfReal(1, myNbExt);
276 myPoint1 = new Extrema_HArray1OfPOnCurv(1, myNbExt);
277 myPoint2 = new Extrema_HArray1OfPOnSurf(1, myNbExt);
280 myNbExt += ExPS.NbExt();
282 for (i = aStartIdx + 1; i <= myNbExt; i++)
284 myPoint1->SetValue(i, myPOnC1);
285 myPoint2->SetValue(i, ExPS.Point(i - aStartIdx));
286 mySqDist->SetValue(i,(myPOnC1.Value()).SquareDistance(ExPS.Point(i - aStartIdx).Value()));
290 myDone = Standard_True;
294 Extrema_ExtElCS::Extrema_ExtElCS(const gp_Lin& C,
300 //void Extrema_ExtElCS::Perform(const gp_Lin& C,
301 // const gp_Torus& S)
302 void Extrema_ExtElCS::Perform(const gp_Lin& ,
305 throw Standard_NotImplemented();
312 Extrema_ExtElCS::Extrema_ExtElCS(const gp_Circ& C,
320 void Extrema_ExtElCS::Perform(const gp_Circ& C,
323 myDone = Standard_True;
324 myIsPar = Standard_False;
326 gp_Ax2 Pos = C.Position();
327 gp_Dir NCirc = Pos.Direction();
328 gp_Dir NPln = S.Axis().Direction();
330 if (NCirc.IsParallel(NPln, Precision::Angular())) {
332 mySqDist = new TColStd_HArray1OfReal(1, 1);
333 mySqDist->SetValue(1, S.SquareDistance(C.Location()));
334 myIsPar = Standard_True;
339 gp_Dir ExtLine = NCirc ^ NPln;
340 ExtLine = ExtLine ^ NCirc;
342 gp_Dir XDir = Pos.XDirection();
344 T[0] = XDir.AngleWithRef(ExtLine, NCirc);
354 IntAna_IntConicQuad anInter(C, S,
355 Precision::Angular(),
356 Precision::Confusion());
359 if(anInter.NbPoints() > 1)
361 myNbExt += anInter.NbPoints();
365 myPoint1 = new Extrema_HArray1OfPOnCurv(1, myNbExt);
366 mySqDist = new TColStd_HArray1OfReal(1, myNbExt);
367 myPoint2 = new Extrema_HArray1OfPOnSurf(1, myNbExt);
372 Extrema_POnCurv POnC;
373 Extrema_POnSurf POnS;
374 for(i = 0; i < 2; ++i)
376 PC = ElCLib::CircleValue(T[i], C.Position(), C.Radius());
377 POnC.SetValues(T[i], PC);
378 myPoint1->SetValue(i+1, POnC);
379 ElSLib::PlaneParameters(S.Position(), PC, U, V);
380 PP = ElSLib::PlaneValue(U, V, S.Position());
381 POnS.SetParameters(U, V, PP);
382 myPoint2->SetValue(i+1, POnS);
383 mySqDist->SetValue(i+1, PC.SquareDistance(PP));
388 //Add intersection points
389 for(i = 1; i <= anInter.NbPoints(); ++i)
391 Standard_Real t = anInter.ParamOnConic(i);
392 PC = ElCLib::CircleValue(t, C.Position(), C.Radius());
393 POnC.SetValues(t, PC);
394 myPoint1->SetValue(i+2, POnC);
395 ElSLib::PlaneParameters(S.Position(), PC, U, V);
396 PP = ElSLib::PlaneValue(U, V, S.Position());
397 POnS.SetParameters(U, V, PP);
398 myPoint2->SetValue(i+2, POnS);
399 mySqDist->SetValue(i+2, PC.SquareDistance(PP));
408 Extrema_ExtElCS::Extrema_ExtElCS(const gp_Circ& C,
409 const gp_Cylinder& S)
416 // Modified by skv - Thu Jul 7 14:37:05 2005 OCC9134 Begin
417 // Implementation of the method.
418 void Extrema_ExtElCS::Perform(const gp_Circ& C,
419 const gp_Cylinder& S)
421 myDone = Standard_False;
422 myIsPar = Standard_False;
425 // Get an axis line of the cylinder.
426 gp_Lin anAxis(S.Axis());
428 // Compute extrema between the circle and the line.
429 Extrema_ExtElC anExtC(anAxis, C, 0.);
431 if (anExtC.IsDone()) {
432 if (anExtC.IsParallel()) {
433 myIsPar = Standard_True;
434 mySqDist = new TColStd_HArray1OfReal(1, 1);
435 Standard_Real aDist = sqrt (anExtC.SquareDistance(1)) - S.Radius();
436 mySqDist->SetValue(1, aDist * aDist);
438 Standard_Integer aNbExt = anExtC.NbExt();
440 Standard_Integer aCurI = 1;
441 Standard_Real aTolConf = Precision::Confusion();
442 Standard_Real aCylRad = S.Radius();
444 // Check whether two objects have intersection points
445 IntAna_Quadric aCylQuad(S);
446 IntAna_IntConicQuad aCircCylInter(C, aCylQuad);
447 Standard_Integer aNbInter = 0;
448 if (aCircCylInter.IsDone())
449 aNbInter = aCircCylInter.NbPoints();
451 // Compute the extremas.
452 myNbExt = 2*aNbExt + aNbInter;
453 mySqDist = new TColStd_HArray1OfReal(1, myNbExt);
454 myPoint1 = new Extrema_HArray1OfPOnCurv(1, myNbExt);
455 myPoint2 = new Extrema_HArray1OfPOnSurf(1, myNbExt);
457 for (i = 1; i <= aNbExt; i++) {
458 Extrema_POnCurv aPOnAxis;
459 Extrema_POnCurv aPOnCirc;
460 Standard_Real aSqDist = anExtC.SquareDistance(i);
461 Standard_Real aDist = sqrt (aSqDist);
463 anExtC.Points(i, aPOnAxis, aPOnCirc);
465 if (aSqDist <= (aTolConf * aTolConf)) {
470 gp_Dir aDir(aPOnAxis.Value().XYZ().Subtracted(aPOnCirc.Value().XYZ()));
471 Standard_Real aShift[2] = { aDist + aCylRad, aDist - aCylRad };
474 for (j = 0; j < 2; j++) {
478 aVec.Multiply(aShift[j]);
479 aPntOnCyl = aPOnCirc.Value().Translated(aVec);
484 ElSLib::Parameters(S, aPntOnCyl, aU, aV);
486 Extrema_POnSurf aPOnSurf(aU, aV, aPntOnCyl);
488 myPoint1->SetValue(aCurI, aPOnCirc);
489 myPoint2->SetValue(aCurI, aPOnSurf);
490 mySqDist->SetValue(aCurI++, aShift[j] * aShift[j]);
494 // Adding intersection points to the list of extremas
495 for (i=1; i<=aNbInter; i++)
500 gp_Pnt aInterPnt = aCircCylInter.Point(i);
502 aU = ElCLib::Parameter(C, aInterPnt);
503 Extrema_POnCurv aPOnCirc(aU, aInterPnt);
505 ElSLib::Parameters(S, aInterPnt, aU, aV);
506 Extrema_POnSurf aPOnCyl(aU, aV, aInterPnt);
507 myPoint1->SetValue(aCurI, aPOnCirc);
508 myPoint2->SetValue(aCurI, aPOnCyl);
509 mySqDist->SetValue(aCurI++, 0.0);
513 myDone = Standard_True;
516 // Modified by skv - Thu Jul 7 14:37:05 2005 OCC9134 End
520 Extrema_ExtElCS::Extrema_ExtElCS(const gp_Circ& C,
526 //void Extrema_ExtElCS::Perform(const gp_Circ& C,
528 void Extrema_ExtElCS::Perform(const gp_Circ& ,
531 throw Standard_NotImplemented();
537 Extrema_ExtElCS::Extrema_ExtElCS(const gp_Circ& C,
543 //void Extrema_ExtElCS::Perform(const gp_Circ& C,
544 // const gp_Sphere& S)
545 void Extrema_ExtElCS::Perform(const gp_Circ& ,
548 throw Standard_NotImplemented();
552 Extrema_ExtElCS::Extrema_ExtElCS(const gp_Circ& C,
558 //void Extrema_ExtElCS::Perform(const gp_Circ& C,
559 // const gp_Torus& S)
560 void Extrema_ExtElCS::Perform(const gp_Circ& ,
563 throw Standard_NotImplemented();
567 Extrema_ExtElCS::Extrema_ExtElCS(const gp_Hypr& C,
575 void Extrema_ExtElCS::Perform(const gp_Hypr& C,
578 myDone = Standard_True;
579 myIsPar = Standard_False;
581 gp_Ax2 Pos = C.Position();
582 gp_Dir NHypr = Pos.Direction();
583 gp_Dir NPln = S.Axis().Direction();
585 if (NHypr.IsParallel(NPln, Precision::Angular())) {
587 mySqDist = new TColStd_HArray1OfReal(1, 1);
588 mySqDist->SetValue(1, S.SquareDistance(C.Location()));
589 myIsPar = Standard_True;
594 gp_Dir XDir = Pos.XDirection();
595 gp_Dir YDir = Pos.YDirection();
597 Standard_Real A = C.MinorRadius()*(NPln.Dot(YDir));
598 Standard_Real B = C.MajorRadius()*(NPln.Dot(XDir));
600 if(Abs(B) > Abs(A)) {
601 Standard_Real T = -0.5 * Log((A+B)/(B-A));
602 gp_Pnt Ph = ElCLib::HyperbolaValue(T, Pos, C.MajorRadius(), C.MinorRadius());
603 Extrema_POnCurv PC(T, Ph);
604 myPoint1 = new Extrema_HArray1OfPOnCurv(1,1);
605 myPoint1->SetValue(1, PC);
607 mySqDist = new TColStd_HArray1OfReal(1, 1);
608 mySqDist->SetValue(1, S.SquareDistance(Ph));
611 ElSLib::PlaneParameters(S.Position(), Ph, U, V);
612 gp_Pnt Pp = ElSLib::PlaneValue(U, V, S.Position());
613 Extrema_POnSurf PS(U, V, Pp);
614 myPoint2 = new Extrema_HArray1OfPOnSurf(1,1);
615 myPoint2->SetValue(1, PS);
628 Standard_Boolean Extrema_ExtElCS::IsDone() const
634 Standard_Integer Extrema_ExtElCS::NbExt() const
636 if (myIsPar) throw StdFail_InfiniteSolutions();
640 Standard_Real Extrema_ExtElCS::SquareDistance(const Standard_Integer N) const
642 if (myIsPar && N != 1) throw StdFail_InfiniteSolutions();
643 return mySqDist->Value(N);
647 void Extrema_ExtElCS::Points(const Standard_Integer N,
649 Extrema_POnSurf& P2) const
651 if (myIsPar) throw StdFail_InfiniteSolutions();
652 P1 = myPoint1->Value(N);
653 P2 = myPoint2->Value(N);
657 Standard_Boolean Extrema_ExtElCS::IsParallel() const