7fd59977 |
1 | // File: Extrema_ExtPRevS.cxx |
2 | // Created: Tue Sep 21 15:50:01 1999 |
3 | // Author: Edward AGAPOV |
4 | // <eap@strelox.nnov.matra-dtv.fr> |
5 | |
6 | |
7 | #include <Extrema_ExtPRevS.ixx> |
8 | #include <Adaptor3d_HCurve.hxx> |
9 | #include <Extrema_ExtPElC.hxx> |
10 | #include <Extrema_GenExtPS.hxx> |
11 | #include <Extrema_POnCurv.hxx> |
12 | #include <Extrema_POnSurf.hxx> |
13 | #include <gp_Ax1.hxx> |
14 | #include <gp_Ax2.hxx> |
15 | #include <gp_Lin.hxx> |
16 | #include <gp_Pln.hxx> |
17 | #include <gp_Pnt.hxx> |
18 | #include <gp_Trsf.hxx> |
19 | #include <gp_Vec.hxx> |
20 | #include <Precision.hxx> |
21 | #include <ElCLib.hxx> |
22 | |
23 | static gp_Ax2 GetPosition (const Adaptor3d_SurfaceOfRevolution& S)//const Handle(Adaptor_HCurve)& C) |
24 | { |
25 | Handle(Adaptor3d_HCurve) C = S.BasisCurve(); |
26 | |
27 | switch (C->GetType()) { |
28 | |
29 | case GeomAbs_Line: { |
30 | gp_Lin L = C->Line(); |
31 | gp_Dir N = S.AxeOfRevolution().Direction(); |
32 | if (N.IsParallel(L.Direction(), Precision::Angular())) { |
33 | gp_Vec OO (L.Location(), S.AxeOfRevolution().Location()); |
34 | if (OO.Magnitude() <= gp::Resolution()) { |
35 | OO = gp_Vec(L.Location(), ElCLib::Value(100,L)); |
36 | if (N.IsParallel(OO, Precision::Angular())) |
37 | return gp_Ax2(); // Line and axe of revolution coinside |
38 | } |
39 | N ^= OO; |
40 | } |
41 | else { |
42 | N ^= L.Direction(); |
43 | } |
44 | return gp_Ax2 (L.Location(), N, L.Direction()); |
45 | } |
46 | case GeomAbs_Circle: |
47 | return C->Circle().Position(); |
48 | case GeomAbs_Ellipse: |
49 | return C->Ellipse().Position(); |
50 | case GeomAbs_Hyperbola: |
51 | return C->Hyperbola().Position(); |
52 | case GeomAbs_Parabola: |
53 | return C->Parabola().Position(); |
54 | default: |
55 | return gp_Ax2(); |
56 | } |
57 | } |
58 | |
59 | //======================================================================= |
60 | //function : HasSingularity |
61 | //purpose : |
62 | //======================================================================= |
63 | |
64 | static Standard_Boolean HasSingularity(const Adaptor3d_SurfaceOfRevolution& S) |
65 | { |
66 | |
67 | const Handle(Adaptor3d_HCurve) C = S.BasisCurve(); |
68 | gp_Dir N = S.AxeOfRevolution().Direction(); |
69 | gp_Pnt P = S.AxeOfRevolution().Location(); |
70 | |
71 | gp_Lin L(P, N); |
72 | |
73 | P = C->Value(C->FirstParameter()); |
74 | |
75 | if(L.SquareDistance(P) < Precision::Confusion() * Precision::Confusion()) return Standard_True; |
76 | |
77 | P = C->Value(C->LastParameter()); |
78 | |
79 | if(L.SquareDistance(P) < Precision::Confusion() * Precision::Confusion()) return Standard_True; |
80 | |
81 | return Standard_False; |
82 | } |
83 | |
84 | //============================================================================= |
85 | |
86 | static void PerformExtPElC (Extrema_ExtPElC& E, |
87 | const gp_Pnt& P, |
88 | const Handle(Adaptor3d_HCurve)& C, |
89 | const Standard_Real Tol) |
90 | { |
91 | switch (C->GetType()) { |
92 | case GeomAbs_Hyperbola: |
93 | E.Perform(P, C->Hyperbola(), Tol, -Precision::Infinite(),Precision::Infinite()); |
94 | return; |
95 | case GeomAbs_Line: |
96 | E.Perform(P, C->Line(), Tol, -Precision::Infinite(),Precision::Infinite()); |
97 | return; |
98 | case GeomAbs_Circle: |
99 | E.Perform(P, C->Circle(), Tol, 0.0, 2.0 * PI); |
100 | return; |
101 | case GeomAbs_Ellipse: |
102 | E.Perform(P, C->Ellipse(), Tol, 0.0, 2.0 * PI); |
103 | return; |
104 | case GeomAbs_Parabola: |
105 | E.Perform(P, C->Parabola(), Tol, -Precision::Infinite(),Precision::Infinite()); |
106 | return; |
107 | #ifndef DEB |
108 | default: |
109 | return ; |
110 | #endif |
111 | } |
112 | } |
113 | |
114 | //======================================================================= |
115 | //function : IsCaseAnalyticallyComputable |
116 | //purpose : |
117 | //======================================================================= |
118 | |
119 | static Standard_Boolean IsCaseAnalyticallyComputable |
120 | (const GeomAbs_CurveType& theType, |
121 | const gp_Ax2& theCurvePos, |
122 | const gp_Ax1& AxeOfRevolution) |
123 | { |
124 | // check type |
125 | switch (theType) { |
126 | case GeomAbs_Line: |
127 | case GeomAbs_Circle: |
128 | case GeomAbs_Ellipse: |
129 | case GeomAbs_Hyperbola: |
130 | case GeomAbs_Parabola: |
131 | break; |
132 | default: |
133 | return Standard_False; |
134 | } |
135 | // the axe of revolution must be in the plane of the curve. |
136 | gp_Pln pl(theCurvePos.Location(), theCurvePos.Direction()); |
137 | gp_Pnt p1 = AxeOfRevolution.Location(); |
138 | Standard_Real dist = 100., dist2 = dist * dist; |
139 | Standard_Real aThreshold = Precision::Angular() * Precision::Angular() * dist2; |
140 | gp_Pnt p2 = AxeOfRevolution.Location().XYZ() + dist * AxeOfRevolution.Direction().XYZ(); |
141 | |
142 | if((pl.SquareDistance(p1) < aThreshold) && |
143 | (pl.SquareDistance(p2) < aThreshold)) |
144 | return Standard_True; |
145 | return Standard_False; |
146 | // gp_Vec V (AxeOfRevolution.Location(),theCurvePos.Location()); |
147 | // if (Abs( V * theCurvePos.Direction()) <= gp::Resolution()) |
148 | // return Standard_True; |
149 | // else |
150 | // return Standard_False; |
151 | } |
152 | |
153 | //======================================================================= |
154 | //function : IsOriginalPnt |
155 | //purpose : |
156 | //======================================================================= |
157 | |
158 | static Standard_Boolean IsOriginalPnt (const gp_Pnt& P, |
159 | const Extrema_POnSurf* Points, |
160 | const Standard_Integer NbPoints) |
161 | { |
162 | for (Standard_Integer i=1; i<=NbPoints; i++) { |
163 | if (Points[i].Value().IsEqual(P, Precision::Confusion())) { |
164 | return Standard_False; |
165 | } |
166 | } |
167 | return Standard_True; |
168 | } |
169 | //======================================================================= |
170 | //function : IsExtremum |
171 | //purpose : |
172 | //======================================================================= |
173 | |
174 | static Standard_Boolean IsExtremum (const Standard_Real U, const Standard_Real V, |
175 | const gp_Pnt& P, const Adaptor3d_SurfacePtr& S, |
176 | gp_Pnt& E, Standard_Real& Dist2, |
177 | const Standard_Boolean IsVSup, |
178 | const Standard_Boolean IsMin) |
179 | { |
180 | E = S->Value(U,V); |
181 | Dist2 = P.SquareDistance(E); |
182 | if (IsMin) |
183 | return (Dist2 < P.SquareDistance(S->Value(U+1,V)) && |
184 | Dist2 < P.SquareDistance(S->Value(U-1,V)) && |
185 | Dist2 < P.SquareDistance(S->Value(U, IsVSup ? V-1 : V+1))); |
186 | else |
187 | return (Dist2 > P.SquareDistance(S->Value(U+1,V)) && |
188 | Dist2 > P.SquareDistance(S->Value(U-1,V)) && |
189 | Dist2 > P.SquareDistance(S->Value(U, IsVSup ? V-1 : V+1))); |
190 | } |
191 | //======================================================================= |
192 | //function : Extrema_ExtPRevS |
193 | //purpose : |
194 | //======================================================================= |
195 | |
196 | Extrema_ExtPRevS::Extrema_ExtPRevS() |
197 | { |
198 | myS=NULL; |
199 | myDone = Standard_False; |
200 | } |
201 | //======================================================================= |
202 | //function : Extrema_ExtPRevS |
203 | //purpose : |
204 | //======================================================================= |
205 | |
206 | Extrema_ExtPRevS::Extrema_ExtPRevS(const gp_Pnt& P, |
207 | const Adaptor3d_SurfaceOfRevolution& S, |
208 | const Standard_Real Umin, |
209 | const Standard_Real Usup, |
210 | const Standard_Real Vmin, |
211 | const Standard_Real Vsup, |
212 | const Standard_Real TolU, |
213 | const Standard_Real TolV) |
214 | { |
215 | myS=NULL; |
216 | Initialize (S, |
217 | Umin, Usup, Vmin, Vsup, |
218 | TolU, TolV); |
219 | Perform(P); |
220 | } |
221 | //======================================================================= |
222 | //function : Extrema_ExtPRevS |
223 | //purpose : |
224 | //======================================================================= |
225 | |
226 | Extrema_ExtPRevS::Extrema_ExtPRevS(const gp_Pnt& P, |
227 | const Adaptor3d_SurfaceOfRevolution& S, |
228 | const Standard_Real TolU, |
229 | const Standard_Real TolV) |
230 | { |
231 | myS=NULL; |
232 | Initialize (S, |
233 | S.FirstUParameter(), S.LastUParameter(), |
234 | S.FirstVParameter(), S.LastVParameter(), |
235 | TolU, TolV); |
236 | Perform(P); |
237 | } |
238 | //======================================================================= |
239 | //function : Initialize |
240 | //purpose : |
241 | //======================================================================= |
242 | |
243 | void Extrema_ExtPRevS::Initialize(const Adaptor3d_SurfaceOfRevolution& S, |
244 | const Standard_Real Umin, |
245 | const Standard_Real Usup, |
246 | const Standard_Real Vmin, |
247 | const Standard_Real Vsup, |
248 | const Standard_Real TolU, |
249 | const Standard_Real TolV) |
250 | { |
251 | myvinf=Vmin; |
252 | myvsup=Vsup; |
253 | mytolv=TolV; |
254 | |
255 | Handle(Adaptor3d_HCurve) anACurve = S.BasisCurve(); |
256 | if (!myS || myS != (Adaptor3d_SurfacePtr)&S) { |
257 | myS = Adaptor3d_SurfacePtr(&S); |
258 | myPosition = GetPosition(S); |
259 | myIsAnalyticallyComputable = |
260 | IsCaseAnalyticallyComputable (anACurve->GetType(),myPosition,S.AxeOfRevolution()); |
261 | } |
262 | if (!myIsAnalyticallyComputable) { |
263 | |
264 | Standard_Integer nbu = 32, nbv = 32; |
265 | |
266 | if(HasSingularity(S)) {nbv = 100;} |
267 | |
268 | myExtPS.Initialize(S, nbu, nbv, |
269 | Umin, Usup, Vmin, Vsup, |
270 | TolU, TolV); |
271 | } |
272 | } |
273 | //======================================================================= |
274 | //function : Perform |
275 | //purpose : |
276 | //======================================================================= |
277 | |
278 | void Extrema_ExtPRevS::Perform(const gp_Pnt& P) |
279 | { |
280 | myDone = Standard_False; |
281 | myNbExt = 0; |
282 | |
283 | if (!myIsAnalyticallyComputable) { |
284 | |
285 | myExtPS.Perform(P); |
286 | myDone = myExtPS.IsDone(); |
287 | myNbExt = myExtPS.NbExt(); |
288 | return; |
289 | } |
290 | |
291 | Handle(Adaptor3d_HCurve) anACurve = myS->BasisCurve(); |
292 | |
293 | gp_Ax1 Ax = myS->AxeOfRevolution(); |
294 | gp_Vec Dir = Ax.Direction(), Z = myPosition.Direction(); |
295 | gp_Pnt O = Ax.Location(); |
296 | |
297 | Standard_Real OPdir = gp_Vec(O,P).Dot(Dir); |
298 | gp_Pnt Pp = P.Translated(Dir.Multiplied(-OPdir)); |
299 | if (O.IsEqual(Pp,Precision::Confusion())) // P is on the AxeOfRevolution |
300 | return; |
301 | |
302 | Standard_Real U,V; |
303 | gp_Pnt P1, Ppp; |
304 | Standard_Real OPpz = gp_Vec(O,Pp).Dot(Z); |
305 | if (Abs(OPpz) <= gp::Resolution()) { |
306 | Ppp = Pp; |
307 | U = 0; |
308 | } |
309 | else { |
310 | Ppp = Pp.Translated(Z.Multiplied(-OPpz)); |
311 | if (O.IsEqual(Ppp,Precision::Confusion())) |
312 | U = PI/2; |
313 | else { |
314 | U = gp_Vec(O,Ppp).AngleWithRef(gp_Vec(O,Pp),Dir); |
315 | } |
316 | } |
317 | |
318 | gp_Vec OPpp (O,Ppp), OPq (O, myS->Value(PI/2,0)); |
319 | if (U != PI/2) { |
320 | if (Abs(OPq.Magnitude()) <= gp::Resolution()) |
321 | OPq = gp_Vec(O, myS->Value(PI/2,anACurve->LastParameter()/10)); |
322 | if (OPpp.AngleWithRef(OPq,Dir) < 0) |
323 | U += PI; |
324 | } |
325 | |
326 | gp_Trsf T; |
327 | T.SetRotation(Ax, -U); |
328 | P1 = P.Transformed(T); |
329 | |
330 | gp_Pnt E; |
331 | Standard_Real Dist2; |
332 | Standard_Integer i; |
333 | |
334 | Extrema_ExtPElC anExt; |
335 | PerformExtPElC(anExt, P1, anACurve, mytolv); |
336 | |
337 | if (anExt.IsDone()) { |
338 | myDone = Standard_True; |
339 | for (i=1; i<=anExt.NbExt(); i++) { |
340 | Extrema_POnCurv POC=anExt.Point(i); |
341 | V = POC.Parameter(); |
342 | if (V > myvsup) { |
343 | // if ( !IsExtremum (U, V = myvsup, P, myS, E, Dist2, |
344 | // Standard_True, anExt.IsMin(i))) continue; |
345 | Standard_Real newV = myvsup; |
346 | |
347 | if((anACurve->GetType() == GeomAbs_Circle) || |
348 | (anACurve->GetType() == GeomAbs_Ellipse)) { |
349 | newV = ElCLib::InPeriod(V, myvinf, myvinf + 2. * PI); |
350 | |
351 | if (newV > myvsup) { |
352 | newV = myvsup; |
353 | } |
354 | } |
355 | V = newV; |
356 | |
357 | if ( !IsExtremum (U, V, P, myS, E, Dist2, |
358 | Standard_True, anExt.IsMin(i))) { |
359 | continue; |
360 | } |
361 | } else if (V < myvinf) { |
362 | // if ( !IsExtremum (U, V = myvinf, P, myS, E, Dist2, |
363 | // Standard_False, anExt.IsMin(i))) continue; |
364 | |
365 | Standard_Real newV = myvinf; |
366 | |
367 | if((anACurve->GetType() == GeomAbs_Circle) || |
368 | (anACurve->GetType() == GeomAbs_Ellipse)) { |
369 | newV = ElCLib::InPeriod(V, myvsup - 2. * PI, myvsup); |
370 | |
371 | if(newV < myvinf) |
372 | newV = myvinf; |
373 | } |
374 | V = newV; |
375 | |
376 | if ( !IsExtremum (U, V, P, myS, E, Dist2, |
377 | Standard_False, anExt.IsMin(i))) continue; |
378 | } else { |
379 | E = myS->Value(U,V); |
380 | Dist2 = P.SquareDistance(E); |
381 | } |
382 | if (IsOriginalPnt(E, myPoint, myNbExt)) { |
383 | myPoint[++myNbExt] = Extrema_POnSurf(U,V,E); |
384 | mySqDist[myNbExt] = Dist2; |
385 | } |
386 | } |
387 | } |
388 | T.SetRotation(Ax, PI); |
389 | P1.Transform(T); |
390 | |
391 | PerformExtPElC(anExt, P1, anACurve, mytolv); |
392 | if (anExt.IsDone()) { |
393 | myDone = Standard_True; |
394 | |
395 | U += PI; |
396 | |
397 | for (i=1; i<=anExt.NbExt(); i++) { |
398 | Extrema_POnCurv POC=anExt.Point(i); |
399 | V = POC.Parameter(); |
400 | if (V > myvsup) { |
401 | // if ( !IsExtremum (U, V = myvsup, P, myS, E, Dist2, |
402 | // Standard_True, anExt.IsMin(i))) continue; |
403 | |
404 | Standard_Real newV = myvsup; |
405 | |
406 | if((anACurve->GetType() == GeomAbs_Circle) || |
407 | (anACurve->GetType() == GeomAbs_Ellipse)) { |
408 | newV = ElCLib::InPeriod(V, myvinf, myvinf + 2. * PI); |
409 | |
410 | if (newV > myvsup) { |
411 | newV = myvsup; |
412 | } |
413 | } |
414 | V = newV; |
415 | |
416 | if ( !IsExtremum (U, V, P, myS, E, Dist2, |
417 | Standard_True, anExt.IsMin(i))) continue; |
418 | } else if (V < myvinf) { |
419 | // if ( !IsExtremum (U, V = myvinf, P, myS, E, Dist2, |
420 | // Standard_False, anExt.IsMin(i))) continue; |
421 | Standard_Real newV = myvinf; |
422 | |
423 | if((anACurve->GetType() == GeomAbs_Circle) || |
424 | (anACurve->GetType() == GeomAbs_Ellipse)) { |
425 | newV = ElCLib::InPeriod(V, myvsup - 2. * PI, myvsup); |
426 | |
427 | if(newV < myvinf) |
428 | newV = myvinf; |
429 | } |
430 | V = newV; |
431 | |
432 | if ( !IsExtremum (U, V, P, myS, E, Dist2, |
433 | Standard_False, anExt.IsMin(i))) continue; |
434 | } else { |
435 | E = myS->Value(U,V); |
436 | Dist2 = P.SquareDistance(E); |
437 | } |
438 | if (IsOriginalPnt(E, myPoint, myNbExt)) { |
439 | myPoint[++myNbExt] = Extrema_POnSurf(U,V,E); |
440 | mySqDist[myNbExt] = Dist2; |
441 | |
442 | } |
443 | } |
444 | } |
445 | } |
446 | |
447 | |
448 | //======================================================================= |
449 | //function : IsDone |
450 | //purpose : |
451 | //======================================================================= |
452 | |
453 | Standard_Boolean Extrema_ExtPRevS::IsDone() const |
454 | { |
455 | return myDone; |
456 | } |
457 | |
458 | |
459 | //======================================================================= |
460 | //function : NbExt |
461 | //purpose : |
462 | //======================================================================= |
463 | |
464 | Standard_Integer Extrema_ExtPRevS::NbExt() const |
465 | { |
466 | if (!IsDone()) { StdFail_NotDone::Raise(); } |
467 | return myNbExt; |
468 | } |
469 | |
470 | |
471 | //======================================================================= |
472 | //function : Value |
473 | //purpose : |
474 | //======================================================================= |
475 | |
476 | Standard_Real Extrema_ExtPRevS::SquareDistance(const Standard_Integer N) const |
477 | { |
478 | if (!IsDone()) { StdFail_NotDone::Raise(); } |
479 | if ((N < 1) || (N > myNbExt)) { Standard_OutOfRange::Raise(); } |
480 | if (myIsAnalyticallyComputable) |
481 | return mySqDist[N]; |
482 | else |
483 | return myExtPS.SquareDistance(N); |
484 | } |
485 | //======================================================================= |
486 | //function : Point |
487 | //purpose : |
488 | //======================================================================= |
489 | |
490 | Extrema_POnSurf Extrema_ExtPRevS::Point(const Standard_Integer N) const |
491 | { |
492 | if (!IsDone()) { StdFail_NotDone::Raise(); } |
493 | if ((N < 1) || (N > myNbExt)) { Standard_OutOfRange::Raise(); } |
494 | if (myIsAnalyticallyComputable) |
495 | return myPoint[N]; |
496 | else |
497 | return myExtPS.Point(N); |
498 | } |
499 | |
500 | |