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_ExtPElS.hxx>
18 #include <Extrema_POnSurf.hxx>
19 #include <gp_Cone.hxx>
20 #include <gp_Cylinder.hxx>
23 #include <gp_Sphere.hxx>
24 #include <gp_Torus.hxx>
25 #include <Standard_NotImplemented.hxx>
26 #include <Standard_OutOfRange.hxx>
27 #include <StdFail_NotDone.hxx>
29 static const Standard_Real ExtPElS_MyEps = Epsilon(2. * M_PI);
30 //=============================================================================
32 Extrema_ExtPElS::Extrema_ExtPElS () { myDone = Standard_False; }
33 //=============================================================================
35 Extrema_ExtPElS::Extrema_ExtPElS (const gp_Pnt& P,
37 const Standard_Real Tol)
42 /*-----------------------------------------------------------------------------
44 Find 2 extreme distances between point P and cylinder S.
47 Let Pp be the projection of P in plane XOY of the cylinder;
48 2 cases are considered:
49 1- distance(Pp,O) < Tol:
50 There are infinite solutions; IsDone() = Standard_False.
51 2- distance(Pp,O) > Tol:
53 U1 = angle(OX,OPp) with 0 < U1 < 2.*M_PI
54 U2 = U1 + M_PI with 0 < U2 < 2.*M_PI;
55 then (U1,V) corresponds to the min distance.
56 and (U2,V) corresponds to the max distance.
57 -----------------------------------------------------------------------------*/
59 void Extrema_ExtPElS::Perform(const gp_Pnt& P,
61 const Standard_Real Tol)
63 myDone = Standard_False;
66 // Projection of point P in plane XOY of the cylinder ...
67 gp_Ax3 Pos = S.Position();
68 gp_Pnt O = Pos.Location();
69 gp_Vec OZ (Pos.Direction());
70 Standard_Real V = gp_Vec(O,P).Dot(OZ);
71 gp_Pnt Pp = P.Translated(OZ.Multiplied(-V));
73 // Calculation of extrema
75 if (OPp.Magnitude() < Tol) { return; }
76 gp_Vec myZ = Pos.XDirection()^Pos.YDirection();
77 Standard_Real U1 = gp_Vec(Pos.XDirection()).AngleWithRef(OPp,myZ); //-M_PI<U1<M_PI
78 if (U1 > -ExtPElS_MyEps && U1 < ExtPElS_MyEps) { U1 = 0.; }
79 Standard_Real U2 = U1 + M_PI;
80 if (U1 < 0.) { U1 += 2. * M_PI; }
83 Ps = ElSLib::Value(U1,V,S);
84 mySqDist[0] = Ps.SquareDistance(P);
85 myPoint[0] = Extrema_POnSurf(U1,V,Ps);
86 Ps = ElSLib::Value(U2,V,S);
87 mySqDist[1] = Ps.SquareDistance(P);
88 myPoint[1] = Extrema_POnSurf(U2,V,Ps);
91 myDone = Standard_True;
93 //=============================================================================
95 Extrema_ExtPElS::Extrema_ExtPElS (const gp_Pnt& P,
97 const Standard_Real Tol)
101 /*-----------------------------------------------------------------------------
103 Find 2 extreme distances between point P and cone S.
106 Let M the top of the cone.
107 2 cases are considered:
108 1- distance(P,M) < Tol:
109 there is a minimum in M.
110 2- distance(P,M) > Tol:
111 Let Pp the projection of P in the plane XOY of the cone;
112 2 cases are considered:
113 1- distance(Pp,O) < Tol:
114 There is an infinite number of solutions; IsDone() = Standard_False.
115 2- distance(Pp,O) > Tol:
116 There exist 2 extrema:
117 Let Vm = value of v for point M,
118 Vp = value of v for point P,
119 U1 = angle(OX,OPp) if Vp > Vm )
120 -angle(OX,OPp) otherwise ) with 0. < U1 < 2*M_PI,
121 U2 = U1 + M_PI with 0. < U2 < 2*M_PI;
122 We are in plane PpOZ.
123 Let A the angle of the cone,
124 B = angle(MP,MO) with 0. < B < M_PI,
126 V1 = (L * cos(B-A)) + Vm,
127 V2 = (L * cos(B+A)) + Vm;
128 then (U1,V1) and (U2,V2) correspond to min distances.
129 -----------------------------------------------------------------------------*/
131 void Extrema_ExtPElS::Perform(const gp_Pnt& P,
133 const Standard_Real Tol)
135 myDone = Standard_False;
139 gp_Ax3 Pos = S.Position();
140 gp_Pnt O = Pos.Location();
141 Standard_Real A = S.SemiAngle();
142 gp_Vec OZ (Pos.Direction());
143 gp_Vec myZ = Pos.XDirection()^Pos.YDirection();
146 Standard_Real L2 = MP.SquareMagnitude();
147 Standard_Real Vm = -(S.RefRadius() / Sin(A));
149 // Case when P is mixed with S ...
150 if (L2 < Tol * Tol) {
152 myPoint[0] = Extrema_POnSurf(0.,Vm,M);
154 myDone = Standard_True;
158 if (M.SquareDistance(O)<Tol * Tol)
160 if( A<0) DirZ.Multiplied(-1.);
164 // Projection of P in the reference plane of the cone ...
165 Standard_Real Zp = gp_Vec(O, P).Dot(OZ);
167 gp_Pnt Pp = P.Translated(OZ.Multiplied(-Zp));
169 if (OPp.SquareMagnitude() < Tol * Tol) return;
170 Standard_Real B, U1, V1, U2, V2;
171 Standard_Boolean Same = DirZ.Dot(MP) >= 0.0;
172 U1 = gp_Vec(Pos.XDirection()).AngleWithRef(OPp,myZ); //-M_PI<U1<M_PI
173 if (U1 > -ExtPElS_MyEps && U1 < ExtPElS_MyEps) { U1 = 0.; }
175 if (!Same) { U1 += M_PI; }
177 if (U1 < 0.) { U1 += 2. * M_PI; }
178 if (U2 > 2.*M_PI) { U2 -= 2. * M_PI; }
181 Standard_Real L = sqrt(L2);
191 Standard_Real Sense = OZ.Dot(gp_Dir(DirZ));
192 V1 *= Sense; V2 *= Sense;
196 Ps = ElSLib::Value(U1,V1,S);
197 mySqDist[0] = Ps.SquareDistance(P);
198 myPoint[0] = Extrema_POnSurf(U1,V1,Ps);
199 Ps = ElSLib::Value(U2,V2,S);
200 mySqDist[1] = Ps.SquareDistance(P);
201 myPoint[1] = Extrema_POnSurf(U2,V2,Ps);
204 myDone = Standard_True;
206 //=============================================================================
208 Extrema_ExtPElS::Extrema_ExtPElS (const gp_Pnt& P,
210 const Standard_Real Tol)
214 /*-----------------------------------------------------------------------------
216 Find 2 extreme distances between point P and sphere S.
219 Let O be the origin of the sphere.
220 2 cases are considered:
221 1- distance(P,O) < Tol:
222 There is an infinite number of solutions; IsDone() = Standard_False
223 2- distance(P,O) > Tol:
224 Let Pp be the projection of point P in the plane XOY of the sphere;
225 2 cases are considered:
226 1- distance(Pp,O) < Tol:
227 2 solutions are: (0,-M_PI/2.) and (0.,M_PI/2.)
228 2- distance(Pp,O) > Tol:
229 Let U1 = angle(OX,OPp) with 0. < U1 < 2.*M_PI,
230 U2 = U1 + M_PI avec 0. < U2 < 2*M_PI,
231 V1 = angle(OPp,OP) with -M_PI/2. < V1 < M_PI/2. ,
232 then (U1, V1) corresponds to the min distance
233 and (U2,-V1) corresponds to the max distance.
234 -----------------------------------------------------------------------------*/
236 void Extrema_ExtPElS::Perform(const gp_Pnt& P,
238 const Standard_Real Tol)
240 myDone = Standard_False;
243 gp_Ax3 Pos = S.Position();
244 gp_Vec OP (Pos.Location(),P);
246 // Case when P is mixed with O ...
247 if (OP.SquareMagnitude() < Tol * Tol) { return; }
249 // Projection if P in plane XOY of the sphere ...
250 gp_Pnt O = Pos.Location();
251 gp_Vec OZ (Pos.Direction());
252 Standard_Real Zp = OP.Dot(OZ);
253 gp_Pnt Pp = P.Translated(OZ.Multiplied(-Zp));
255 // Calculation of extrema ...
257 Standard_Real U1, U2, V;
258 if (OPp.SquareMagnitude() < Tol * Tol) {
261 if (Zp < 0.) { V = -M_PI / 2.; }
262 else { V = M_PI / 2.; }
265 gp_Vec myZ = Pos.XDirection()^Pos.YDirection();
266 U1 = gp_Vec(Pos.XDirection()).AngleWithRef(OPp,myZ);
267 if (U1 > -ExtPElS_MyEps && U1 < ExtPElS_MyEps) { U1 = 0.; }
269 if (U1 < 0.) { U1 += 2. * M_PI; }
271 if (Zp < 0.) { V = -V; }
275 Ps = ElSLib::Value(U1,V,S);
276 mySqDist[0] = Ps.SquareDistance(P);
277 myPoint[0] = Extrema_POnSurf(U1,V,Ps);
278 Ps = ElSLib::Value(U2,-V,S);
279 mySqDist[1] = Ps.SquareDistance(P);
280 myPoint[1] = Extrema_POnSurf(U2,-V,Ps);
283 myDone = Standard_True;
285 //=============================================================================
287 Extrema_ExtPElS::Extrema_ExtPElS (const gp_Pnt& P,
289 const Standard_Real Tol)
293 /*-----------------------------------------------------------------------------
295 Find 2 extreme distances between point P and torus S.
298 Let Pp be the projection of point P in plane XOY of the torus;
299 2 cases are consideres:
300 1- distance(Pp,O) < Tol:
301 There is an infinite number of solutions; IsDone() = Standard_False.
302 2- distance(Pp,O) > Tol:
303 One is located in plane PpOZ;
304 Let V1 = angle(OX,OPp) with 0. < V1 < 2.*M_PI,
305 V2 = V1 + M_PI with 0. < V2 < 2.*M_PI,
306 O1 and O2 centers of circles (O1 on coord. posit.)
309 then (U1,V1) corresponds to the min distance
310 and (U2,V2) corresponds to the max distance.
311 -----------------------------------------------------------------------------*/
312 void Extrema_ExtPElS::Perform(const gp_Pnt& P,
314 const Standard_Real Tol)
316 const Standard_Real tol2 = Tol*Tol;
317 myDone = Standard_False;
320 // Projection of P in plane XOY ...
321 gp_Ax3 Pos = S.Position();
322 gp_Pnt O = Pos.Location();
323 gp_Vec OZ (Pos.Direction());
324 gp_Pnt Pp = P.Translated(OZ.Multiplied(-(gp_Vec(O,P).Dot(Pos.Direction()))));
326 // Calculation of extrema ...
328 Standard_Real R2 = OPp.SquareMagnitude();
329 if (R2 < tol2) { return; }
331 gp_Vec myZ = Pos.XDirection()^Pos.YDirection();
332 Standard_Real U1 = gp_Vec(Pos.XDirection()).AngleWithRef(OPp,myZ);
333 if (U1 > -ExtPElS_MyEps && U1 < ExtPElS_MyEps) { U1 = 0.; }
334 Standard_Real U2 = U1 + M_PI;
335 if (U1 < 0.) { U1 += 2. * M_PI; }
336 Standard_Real R = sqrt(R2);
337 gp_Vec OO1 = OPp.Divided(R).Multiplied(S.MajorRadius());
338 gp_Vec OO2 = OO1.Multiplied(-1.);
339 gp_Pnt O1 = O.Translated(OO1);
340 gp_Pnt O2 = O.Translated(OO2);
342 if(O1.SquareDistance(P) < tol2) { return; }
343 if(O2.SquareDistance(P) < tol2) { return; }
345 Standard_Real V1 = OPp.AngleWithRef(gp_Vec(O1,P),OPp.Crossed(OZ));
346 if (V1 > -ExtPElS_MyEps && V1 < ExtPElS_MyEps) { V1 = 0.; }
348 Standard_Real V2 = OPp.AngleWithRef(gp_Vec(P,O2),OPp.Crossed(OZ));
349 if (V2 > -ExtPElS_MyEps && V2 < ExtPElS_MyEps) { V2 = 0.; }
351 if (V1 < 0.) { V1 += 2. * M_PI; }
352 if (V2 < 0.) { V2 += 2. * M_PI; }
355 Ps = ElSLib::Value(U1,V1,S);
356 mySqDist[0] = Ps.SquareDistance(P);
357 myPoint[0] = Extrema_POnSurf(U1,V1,Ps);
359 Ps = ElSLib::Value(U1,V1+M_PI,S);
360 mySqDist[1] = Ps.SquareDistance(P);
361 myPoint[1] = Extrema_POnSurf(U1,V1+M_PI,Ps);
363 Ps = ElSLib::Value(U2,V2,S);
364 mySqDist[2] = Ps.SquareDistance(P);
365 myPoint[2] = Extrema_POnSurf(U2,V2,Ps);
367 Ps = ElSLib::Value(U2,V2+M_PI,S);
368 mySqDist[3] = Ps.SquareDistance(P);
369 myPoint[3] = Extrema_POnSurf(U2,V2+M_PI,Ps);
372 myDone = Standard_True;
376 Extrema_ExtPElS::Extrema_ExtPElS (const gp_Pnt& P,
378 const Standard_Real Tol)
383 void Extrema_ExtPElS::Perform (const gp_Pnt& P,
385 // const Standard_Real Tol)
386 const Standard_Real )
388 myDone = Standard_False;
391 // Projection of point P in plane XOY of the cylinder ...
392 gp_Pnt O = S.Location();
393 gp_Vec OZ (S.Axis().Direction());
394 Standard_Real U, V = gp_Vec(O,P).Dot(OZ);
395 gp_Pnt Pp = P.Translated(OZ.Multiplied(-V));
397 ElSLib::Parameters(S, P, U, V);
398 mySqDist[0] = Pp.SquareDistance(P);
399 myPoint[0] = Extrema_POnSurf(U,V,Pp);
401 myDone = Standard_True;
405 //=============================================================================
407 Standard_Boolean Extrema_ExtPElS::IsDone () const { return myDone; }
408 //=============================================================================
410 Standard_Integer Extrema_ExtPElS::NbExt () const
412 if (!IsDone()) { throw StdFail_NotDone(); }
415 //=============================================================================
417 Standard_Real Extrema_ExtPElS::SquareDistance (const Standard_Integer N) const
419 if (!IsDone()) { throw StdFail_NotDone(); }
420 if ((N < 1) || (N > myNbExt)) { throw Standard_OutOfRange(); }
421 return mySqDist[N-1];
423 //=============================================================================
425 const Extrema_POnSurf& Extrema_ExtPElS::Point (const Standard_Integer N) const
427 if (!IsDone()) { throw StdFail_NotDone(); }
428 if ((N < 1) || (N > myNbExt)) { throw Standard_OutOfRange(); }
431 //=============================================================================