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