0024200: Wrong result obtained by Exterma Curve/Curve
[occt.git] / src / Extrema / Extrema_ExtPElS.cxx
CommitLineData
b311480e 1// Copyright (c) 1995-1999 Matra Datavision
2// Copyright (c) 1999-2012 OPEN CASCADE SAS
3//
4// The content of this file is subject to the Open CASCADE Technology Public
5// License Version 6.5 (the "License"). You may not use the content of this file
6// except in compliance with the License. Please obtain a copy of the License
7// at http://www.opencascade.org and read it completely before using this file.
8//
9// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11//
12// The Original Code and all software distributed under the License is
13// distributed on an "AS IS" basis, without warranty of any kind, and the
14// Initial Developer hereby disclaims all such warranties, including without
15// limitation, any warranties of merchantability, fitness for a particular
16// purpose or non-infringement. Please see the License for the specific terms
17// and conditions governing the rights and limitations under the License.
18
19
7fd59977 20#include <Extrema_ExtPElS.ixx>
21#include <StdFail_NotDone.hxx>
22#include <Standard_OutOfRange.hxx>
23#include <Standard_NotImplemented.hxx>
24#include <ElSLib.hxx>
7c4e9501 25static const Standard_Real ExtPElS_MyEps = Epsilon(2. * M_PI);
7fd59977 26//=============================================================================
27
28Extrema_ExtPElS::Extrema_ExtPElS () { myDone = Standard_False; }
29//=============================================================================
30
31Extrema_ExtPElS::Extrema_ExtPElS (const gp_Pnt& P,
32 const gp_Cylinder& S,
33 const Standard_Real Tol)
34{
35
36 Perform(P, S, Tol);
37}
38/*-----------------------------------------------------------------------------
0d969553
Y
39Function:
40Find 2 extreme distances between point P and cylinder S.
7fd59977 41
0d969553
Y
42Method:
43 Let Pp be the projection of P in plane XOY of the cylinder;
44 2 cases are considered:
7fd59977 45 1- distance(Pp,O) < Tol:
0d969553 46 There are infinite solutions; IsDone() = Standard_False.
7fd59977 47 2- distance(Pp,O) > Tol:
0d969553 48 let V = OP.OZ,
c6541a0c
D
49 U1 = angle(OX,OPp) with 0 < U1 < 2.*M_PI
50 U2 = U1 + M_PI with 0 < U2 < 2.*M_PI;
0d969553
Y
51 then (U1,V) corresponds to the min distance.
52 and (U2,V) corresponds to the max distance.
7fd59977 53-----------------------------------------------------------------------------*/
54
55void Extrema_ExtPElS::Perform(const gp_Pnt& P,
56 const gp_Cylinder& S,
57 const Standard_Real Tol)
58{
59 myDone = Standard_False;
60 myNbExt = 0;
61
0d969553 62// Projection of point P in plane XOY of the cylinder ...
7fd59977 63 gp_Ax3 Pos = S.Position();
64 gp_Pnt O = Pos.Location();
65 gp_Vec OZ (Pos.Direction());
66 Standard_Real V = gp_Vec(O,P).Dot(OZ);
67 gp_Pnt Pp = P.Translated(OZ.Multiplied(-V));
68
0d969553 69// Calculation of extrema
7fd59977 70 gp_Vec OPp (O,Pp);
71 if (OPp.Magnitude() < Tol) { return; }
72 gp_Vec myZ = Pos.XDirection()^Pos.YDirection();
c6541a0c 73 Standard_Real U1 = gp_Vec(Pos.XDirection()).AngleWithRef(OPp,myZ); //-M_PI<U1<M_PI
7c4e9501 74 if (U1 > -ExtPElS_MyEps && U1 < ExtPElS_MyEps) { U1 = 0.; }
c6541a0c
D
75 Standard_Real U2 = U1 + M_PI;
76 if (U1 < 0.) { U1 += 2. * M_PI; }
7fd59977 77
78 gp_Pnt Ps;
79 Ps = ElSLib::Value(U1,V,S);
80 mySqDist[0] = Ps.SquareDistance(P);
81 myPoint[0] = Extrema_POnSurf(U1,V,Ps);
82 Ps = ElSLib::Value(U2,V,S);
83 mySqDist[1] = Ps.SquareDistance(P);
84 myPoint[1] = Extrema_POnSurf(U2,V,Ps);
85
86 myNbExt = 2;
87 myDone = Standard_True;
88}
89//=============================================================================
90
91Extrema_ExtPElS::Extrema_ExtPElS (const gp_Pnt& P,
92 const gp_Cone& S,
93 const Standard_Real Tol)
94{
95 Perform(P, S, Tol);
96}
97/*-----------------------------------------------------------------------------
0d969553
Y
98Function:
99 Find 2 extreme distances between point P and cone S.
7fd59977 100
0d969553
Y
101Method:
102 Let M the top of the cone.
103 2 cases are considered:
7fd59977 104 1- distance(P,M) < Tol:
0d969553 105 there is a minimum in M.
7fd59977 106 2- distance(P,M) > Tol:
0d969553
Y
107 Let Pp the projection of P in the plane XOY of the cone;
108 2 cases are considered:
7fd59977 109 1- distance(Pp,O) < Tol:
0d969553 110 There is an infinite number of solutions; IsDone() = Standard_False.
7fd59977 111 2- distance(Pp,O) > Tol:
0d969553
Y
112 There exist 2 extrema:
113 Let Vm = value of v for point M,
114 Vp = value of v for point P,
115 U1 = angle(OX,OPp) if Vp > Vm )
c6541a0c
D
116 -angle(OX,OPp) otherwise ) with 0. < U1 < 2*M_PI,
117 U2 = U1 + M_PI with 0. < U2 < 2*M_PI;
0d969553
Y
118 We are in plane PpOZ.
119 Let A the angle of the cone,
c6541a0c 120 B = angle(MP,MO) with 0. < B < M_PI,
7fd59977 121 L = longueur(MP),
122 V1 = (L * cos(B-A)) + Vm,
123 V2 = (L * cos(B+A)) + Vm;
0d969553 124 then (U1,V1) and (U2,V2) correspond to min distances.
7fd59977 125-----------------------------------------------------------------------------*/
126
127void Extrema_ExtPElS::Perform(const gp_Pnt& P,
128 const gp_Cone& S,
129 const Standard_Real Tol)
130{
131 myDone = Standard_False;
132 myNbExt = 0;
133
134 gp_Pnt M = S.Apex();
135 gp_Ax3 Pos = S.Position();
136 gp_Pnt O = Pos.Location();
137 Standard_Real A = S.SemiAngle();
138 gp_Vec OZ (Pos.Direction());
139 gp_Vec myZ = Pos.XDirection()^Pos.YDirection();
140 gp_Vec MP (M,P);
141
142 Standard_Real L2 = MP.SquareMagnitude();
143 Standard_Real Vm = -(S.RefRadius() / Sin(A));
7fd59977 144
0d969553 145// Case when P is mixed with S ...
7fd59977 146 if (L2 < Tol * Tol) {
147 mySqDist[0] = L2;
148 myPoint[0] = Extrema_POnSurf(0.,Vm,M);
149 myNbExt = 1;
150 myDone = Standard_True;
151 return;
152 }
153 gp_Vec DirZ;
154 if (M.SquareDistance(O)<Tol * Tol)
155 { DirZ=OZ;
156 if( A<0) DirZ.Multiplied(-1.);
157 }
158 else
159 DirZ=gp_Vec(M,O);
0d969553 160// Projection of P in the reference plane of the cone ...
7fd59977 161 Standard_Real Zp = gp_Vec(O, P).Dot(OZ);
162
163 gp_Pnt Pp = P.Translated(OZ.Multiplied(-Zp));
164 gp_Vec OPp(O, Pp);
165 if (OPp.SquareMagnitude() < Tol * Tol) return;
166 Standard_Real B, U1, V1, U2, V2;
167 Standard_Boolean Same = DirZ.Dot(MP) >= 0.0;
c6541a0c 168 U1 = gp_Vec(Pos.XDirection()).AngleWithRef(OPp,myZ); //-M_PI<U1<M_PI
7c4e9501 169 if (U1 > -ExtPElS_MyEps && U1 < ExtPElS_MyEps) { U1 = 0.; }
7fd59977 170 B = MP.Angle(DirZ);
c6541a0c
D
171 if (!Same) { U1 += M_PI; }
172 U2 = U1 + M_PI;
173 if (U1 < 0.) { U1 += 2. * M_PI; }
174 if (U2 > 2.*M_PI) { U2 -= 2. * M_PI; }
7fd59977 175 B = MP.Angle(DirZ);
176 A = Abs(A);
177 Standard_Real L = sqrt(L2);
178 if (!Same) {
c6541a0c 179 B = M_PI-B;
7fd59977 180 V1 = -L*cos(B-A);
181 V2 = -L*cos(B+A);
182 }
183 else {
184 V1 = L * cos(B-A);
185 V2 = L * cos(B+A);
186 }
187 Standard_Real Sense = OZ.Dot(gp_Dir(DirZ));
188 V1 *= Sense; V2 *= Sense;
189 V1 += Vm; V2 += Vm;
190
191 gp_Pnt Ps;
192 Ps = ElSLib::Value(U1,V1,S);
193 mySqDist[0] = Ps.SquareDistance(P);
194 myPoint[0] = Extrema_POnSurf(U1,V1,Ps);
195 Ps = ElSLib::Value(U2,V2,S);
196 mySqDist[1] = Ps.SquareDistance(P);
197 myPoint[1] = Extrema_POnSurf(U2,V2,Ps);
198
199 myNbExt = 2;
200 myDone = Standard_True;
201}
202//=============================================================================
203
204Extrema_ExtPElS::Extrema_ExtPElS (const gp_Pnt& P,
205 const gp_Sphere& S,
206 const Standard_Real Tol)
207{
208 Perform(P, S, Tol);
209}
210/*-----------------------------------------------------------------------------
0d969553
Y
211Function:
212 Find 2 extreme distances between point P and sphere S.
7fd59977 213
0d969553
Y
214Method:
215 Let O be the origin of the sphere.
216 2 cases are considered:
7fd59977 217 1- distance(P,O) < Tol:
0d969553 218 There is an infinite number of solutions; IsDone() = Standard_False
7fd59977 219 2- distance(P,O) > Tol:
0d969553
Y
220 Let Pp be the projection of point P in the plane XOY of the sphere;
221 2 cases are considered:
7fd59977 222 1- distance(Pp,O) < Tol:
c6541a0c 223 2 solutions are: (0,-M_PI/2.) and (0.,M_PI/2.)
7fd59977 224 2- distance(Pp,O) > Tol:
c6541a0c
D
225 Let U1 = angle(OX,OPp) with 0. < U1 < 2.*M_PI,
226 U2 = U1 + M_PI avec 0. < U2 < 2*M_PI,
227 V1 = angle(OPp,OP) with -M_PI/2. < V1 < M_PI/2. ,
0d969553
Y
228 then (U1, V1) corresponds to the min distance
229 and (U2,-V1) corresponds to the max distance.
7fd59977 230-----------------------------------------------------------------------------*/
231
232void Extrema_ExtPElS::Perform(const gp_Pnt& P,
233 const gp_Sphere& S,
234 const Standard_Real Tol)
235{
236 myDone = Standard_False;
237 myNbExt = 0;
238
239 gp_Ax3 Pos = S.Position();
240 gp_Vec OP (Pos.Location(),P);
241
0d969553 242// Case when P is mixed with O ...
7fd59977 243 if (OP.SquareMagnitude() < Tol * Tol) { return; }
244
0d969553 245// Projection if P in plane XOY of the sphere ...
7fd59977 246 gp_Pnt O = Pos.Location();
247 gp_Vec OZ (Pos.Direction());
248 Standard_Real Zp = OP.Dot(OZ);
249 gp_Pnt Pp = P.Translated(OZ.Multiplied(-Zp));
250
0d969553 251// Calculation of extrema ...
7fd59977 252 gp_Vec OPp (O,Pp);
253 Standard_Real U1, U2, V;
254 if (OPp.SquareMagnitude() < Tol * Tol) {
255 U1 = 0.;
256 U2 = 0.;
c6541a0c
D
257 if (Zp < 0.) { V = -M_PI / 2.; }
258 else { V = M_PI / 2.; }
7fd59977 259 }
260 else {
261 gp_Vec myZ = Pos.XDirection()^Pos.YDirection();
262 U1 = gp_Vec(Pos.XDirection()).AngleWithRef(OPp,myZ);
7c4e9501 263 if (U1 > -ExtPElS_MyEps && U1 < ExtPElS_MyEps) { U1 = 0.; }
c6541a0c
D
264 U2 = U1 + M_PI;
265 if (U1 < 0.) { U1 += 2. * M_PI; }
7fd59977 266 V = OP.Angle(OPp);
267 if (Zp < 0.) { V = -V; }
268 }
269
270 gp_Pnt Ps;
271 Ps = ElSLib::Value(U1,V,S);
272 mySqDist[0] = Ps.SquareDistance(P);
273 myPoint[0] = Extrema_POnSurf(U1,V,Ps);
274 Ps = ElSLib::Value(U2,-V,S);
275 mySqDist[1] = Ps.SquareDistance(P);
276 myPoint[1] = Extrema_POnSurf(U2,-V,Ps);
277
278 myNbExt = 2;
279 myDone = Standard_True;
280}
281//=============================================================================
282
283Extrema_ExtPElS::Extrema_ExtPElS (const gp_Pnt& P,
284 const gp_Torus& S,
285 const Standard_Real Tol)
286{
287 Perform(P, S, Tol);
288}
289/*-----------------------------------------------------------------------------
0d969553
Y
290Function:
291 Find 2 extreme distances between point P and torus S.
7fd59977 292
0d969553
Y
293 Method:
294 Let Pp be the projection of point P in plane XOY of the torus;
295 2 cases are consideres:
7fd59977 296 1- distance(Pp,O) < Tol:
0d969553 297 There is an infinite number of solutions; IsDone() = Standard_False.
7fd59977 298 2- distance(Pp,O) > Tol:
0d969553 299 One is located in plane PpOZ;
c6541a0c
D
300 Let V1 = angle(OX,OPp) with 0. < V1 < 2.*M_PI,
301 V2 = V1 + M_PI with 0. < V2 < 2.*M_PI,
0d969553
Y
302 O1 and O2 centers of circles (O1 on coord. posit.)
303 U1 = angle(OPp,O1P),
304 U2 = angle(OPp,PO2);
305 then (U1,V1) corresponds to the min distance
306 and (U2,V2) corresponds to the max distance.
7fd59977 307-----------------------------------------------------------------------------*/
308void Extrema_ExtPElS::Perform(const gp_Pnt& P,
309 const gp_Torus& S,
310 const Standard_Real Tol)
311{
312 myDone = Standard_False;
313 myNbExt = 0;
314
0d969553 315// Projection of P in plane XOY ...
7fd59977 316 gp_Ax3 Pos = S.Position();
317 gp_Pnt O = Pos.Location();
318 gp_Vec OZ (Pos.Direction());
319 gp_Pnt Pp = P.Translated(OZ.Multiplied(-(gp_Vec(O,P).Dot(Pos.Direction()))));
320
0d969553 321// Calculation of extrema ...
7fd59977 322 gp_Vec OPp (O,Pp);
323 Standard_Real R2 = OPp.SquareMagnitude();
324 if (R2 < Tol * Tol) { return; }
325
326 gp_Vec myZ = Pos.XDirection()^Pos.YDirection();
327 Standard_Real U1 = gp_Vec(Pos.XDirection()).AngleWithRef(OPp,myZ);
7c4e9501 328 if (U1 > -ExtPElS_MyEps && U1 < ExtPElS_MyEps) { U1 = 0.; }
c6541a0c
D
329 Standard_Real U2 = U1 + M_PI;
330 if (U1 < 0.) { U1 += 2. * M_PI; }
7fd59977 331 Standard_Real R = sqrt(R2);
332 gp_Vec OO1 = OPp.Divided(R).Multiplied(S.MajorRadius());
333 gp_Vec OO2 = OO1.Multiplied(-1.);
334 gp_Pnt O1 = O.Translated(OO1);
335 gp_Pnt O2 = O.Translated(OO2);
336
337 if(O1.SquareDistance(P) < Tol) { return; }
338 if(O2.SquareDistance(P) < Tol) { return; }
339
340 Standard_Real V1 = OO1.AngleWithRef(gp_Vec(O1,P),OO1.Crossed(OZ));
7c4e9501 341 if (V1 > -ExtPElS_MyEps && V1 < ExtPElS_MyEps) { V1 = 0.; }
7fd59977 342 Standard_Real V2 = OO2.AngleWithRef(gp_Vec(P,O2),OO2.Crossed(OZ));
7c4e9501 343 if (V2 > -ExtPElS_MyEps && V2 < ExtPElS_MyEps) { V2 = 0.; }
344
c6541a0c
D
345 if (V1 < 0.) { V1 += 2. * M_PI; }
346 if (V2 < 0.) { V2 += 2. * M_PI; }
7fd59977 347
348 gp_Pnt Ps;
349 Ps = ElSLib::Value(U1,V1,S);
350 mySqDist[0] = Ps.SquareDistance(P);
351 myPoint[0] = Extrema_POnSurf(U1,V1,Ps);
352
c6541a0c 353 Ps = ElSLib::Value(U1,V1+M_PI,S);
7fd59977 354 mySqDist[1] = Ps.SquareDistance(P);
c6541a0c 355 myPoint[1] = Extrema_POnSurf(U1,V1+M_PI,Ps);
7fd59977 356
357 Ps = ElSLib::Value(U2,V2,S);
358 mySqDist[2] = Ps.SquareDistance(P);
359 myPoint[2] = Extrema_POnSurf(U2,V2,Ps);
360
c6541a0c 361 Ps = ElSLib::Value(U2,V2+M_PI,S);
7fd59977 362 mySqDist[3] = Ps.SquareDistance(P);
c6541a0c 363 myPoint[3] = Extrema_POnSurf(U2,V2+M_PI,Ps);
7fd59977 364
365 myNbExt = 4;
366 myDone = Standard_True;
367}
368
369
370Extrema_ExtPElS::Extrema_ExtPElS (const gp_Pnt& P,
371 const gp_Pln& S,
372 const Standard_Real Tol)
373{
374 Perform(P, S, Tol);
375}
376
377void Extrema_ExtPElS::Perform (const gp_Pnt& P,
378 const gp_Pln& S,
379// const Standard_Real Tol)
380 const Standard_Real )
381{
382 myDone = Standard_False;
383 myNbExt = 0;
384
0d969553 385// Projection of point P in plane XOY of the cylinder ...
7fd59977 386 gp_Pnt O = S.Location();
387 gp_Vec OZ (S.Axis().Direction());
388 Standard_Real U, V = gp_Vec(O,P).Dot(OZ);
389 gp_Pnt Pp = P.Translated(OZ.Multiplied(-V));
390
391 ElSLib::Parameters(S, P, U, V);
392 mySqDist[0] = Pp.SquareDistance(P);
393 myPoint[0] = Extrema_POnSurf(U,V,Pp);
394 myNbExt = 1;
395 myDone = Standard_True;
396}
397
398
399//=============================================================================
400
401Standard_Boolean Extrema_ExtPElS::IsDone () const { return myDone; }
402//=============================================================================
403
404Standard_Integer Extrema_ExtPElS::NbExt () const
405{
406 if (!IsDone()) { StdFail_NotDone::Raise(); }
407 return myNbExt;
408}
409//=============================================================================
410
411Standard_Real Extrema_ExtPElS::SquareDistance (const Standard_Integer N) const
412{
413 if (!IsDone()) { StdFail_NotDone::Raise(); }
414 if ((N < 1) || (N > myNbExt)) { Standard_OutOfRange::Raise(); }
415 return mySqDist[N-1];
416}
417//=============================================================================
418
5d99f2c8 419const Extrema_POnSurf& Extrema_ExtPElS::Point (const Standard_Integer N) const
7fd59977 420{
421 if (!IsDone()) { StdFail_NotDone::Raise(); }
422 if ((N < 1) || (N > myNbExt)) { Standard_OutOfRange::Raise(); }
423 return myPoint[N-1];
424}
425//=============================================================================