OCC22610 The algorithm GeomAPI_ProjectPointOnSurf produces wrong results
[occt.git] / src / Extrema / Extrema_ExtPExtS.cxx
1 // File:        Extrema_ExtPExtS.cdl
2 // Created:     Thu Sep 16 16:53:38 1999
3 // Author:      Edward AGAPOV
4 //              <eap@strelox.nnov.matra-dtv.fr>
5 // Copyright:    Matra Datavision 1999
6
7 #include <Standard_NotImplemented.hxx>
8 #include <Standard_OutOfRange.hxx>
9 #include <StdFail_NotDone.hxx>
10 #include <Adaptor3d_HCurve.hxx>
11 #include <ElCLib.hxx>
12 #include <Extrema_ExtPElC.hxx>
13 #include <Extrema_ExtPExtS.hxx>
14 #include <Extrema_POnCurv.hxx>
15 #include <Extrema_POnSurf.hxx>
16 #include <Precision.hxx>
17 #include <gp.hxx>
18 #include <gp_Ax2.hxx>
19 #include <gp_Dir.hxx>
20 #include <gp_Lin.hxx>
21 #include <gp_Pln.hxx>
22 #include <gp_Pnt.hxx>
23 #include <gp_Vec.hxx>
24 #include <math_FunctionSetRoot.hxx>
25 #include <math_Vector.hxx>
26 #include <Adaptor3d_SurfaceOfLinearExtrusion.hxx>
27
28 static gp_Ax2 GetPosition (const Handle(Adaptor3d_HCurve)& C);
29      
30 static void PerformExtPElC (Extrema_ExtPElC& E,
31                             const gp_Pnt& P,
32                             const Handle(Adaptor3d_HCurve)& C,
33                             const Standard_Real Tol);
34      
35 static Standard_Boolean
36   IsCaseAnalyticallyComputable (const GeomAbs_CurveType& theType,
37                                 const gp_Ax2& theCurvePos,
38                                 const gp_Dir& theSurfaceDirection) ;
39
40 static gp_Pnt GetValue(const Standard_Real U,
41                        const Handle(Adaptor3d_HCurve)& C);
42 //=======================================================================
43 //function : Project
44 //purpose  : Returns the projection of a point <Point> on a plane 
45 //           <ThePlane>  along a direction <TheDir>.
46 //=======================================================================
47 static gp_Pnt ProjectPnt(const gp_Ax2& ThePlane,
48                          const gp_Dir& TheDir,
49                          const gp_Pnt& Point) 
50 {
51   gp_Vec PO(Point,ThePlane.Location());
52   Standard_Real Alpha = PO * gp_Vec(ThePlane.Direction());
53   Alpha /= TheDir * ThePlane.Direction();
54   gp_Pnt P;
55   P.SetXYZ(Point.XYZ() + Alpha * TheDir.XYZ());
56   return P;
57 }
58
59 //=======================================================================
60 //function : IsOriginalPnt
61 //purpose  : 
62 //=======================================================================
63
64 static Standard_Boolean IsOriginalPnt (const gp_Pnt& P,
65                                        const Extrema_POnSurf* Points,
66                                        const Standard_Integer NbPoints)
67 {
68   for (Standard_Integer i=1; i<=NbPoints; i++) {
69     if (Points[i-1].Value().IsEqual(P, Precision::Confusion())) {
70       return Standard_False;
71     }
72   }
73   return Standard_True;
74 }
75
76 //=======================================================================
77 //function : MakePreciser
78 //purpose  : 
79 //=======================================================================
80
81 void Extrema_ExtPExtS::MakePreciser (Standard_Real& U,
82                                      const gp_Pnt& P,
83                                      const Standard_Boolean isMin,
84                                      const gp_Ax2& OrtogSection) const
85 {
86   if (U>myusup) {
87     U = myusup;
88   } else if (U<myuinf) {
89     U = myuinf;
90   } else {
91     
92     Standard_Real step = (myusup - myuinf) / 30, D2e, D2next ,D2prev;
93     gp_Pnt
94       Pe = ProjectPnt (OrtogSection, myDirection, GetValue(U,myC)),
95       Pprev = ProjectPnt (OrtogSection, myDirection, GetValue(U-step, myC)),
96       Pnext = ProjectPnt (OrtogSection, myDirection, GetValue(U+step, myC));
97     D2e = P.SquareDistance(Pe),
98     D2next = P.SquareDistance(Pnext),
99     D2prev = P.SquareDistance(Pprev);
100     Standard_Boolean notFound;
101     if (isMin) 
102       notFound =  (D2e > D2prev || D2e > D2next);
103     else 
104       notFound = (D2e < D2prev || D2e < D2next);
105     
106     if (notFound && (D2e < D2next && isMin)) {
107       step = -step;
108       D2next = D2prev;
109       Pnext = Pprev;
110     }
111     while (notFound) {
112       U = U + step;
113       if (U > myusup) {
114         U = myusup;
115         break;
116       }
117       if (U < myuinf) {
118         U = myuinf;
119         break;
120       }
121       D2e = D2next;
122       Pe = Pnext;
123       Pnext = ProjectPnt (OrtogSection, myDirection, GetValue(U+step, myC));
124       D2next = P.SquareDistance(Pnext);
125       if (isMin) 
126         notFound = D2e > D2next;
127       else 
128         notFound = D2e < D2next;
129     }
130   }
131 }
132 //=============================================================================
133
134 Extrema_ExtPExtS::Extrema_ExtPExtS ()
135 {
136   myDone = Standard_False;
137 }
138
139 //=============================================================================
140
141 Extrema_ExtPExtS::Extrema_ExtPExtS (const gp_Pnt&       P, 
142                                     const Adaptor3d_SurfaceOfLinearExtrusion&  S,
143                                     const Standard_Real    Umin,
144                                     const Standard_Real    Usup,
145                                     const Standard_Real    Vmin,
146                                     const Standard_Real    Vsup,
147                                     const Standard_Real    TolU, 
148                                     const Standard_Real    TolV) 
149 {
150   Initialize (S,
151               Umin, Usup, Vmin, Vsup,
152               TolU, TolV);
153   Perform(P);
154 }
155 //=============================================================================
156
157 Extrema_ExtPExtS::Extrema_ExtPExtS (const gp_Pnt&       P, 
158                                     const Adaptor3d_SurfaceOfLinearExtrusion&  S,
159                                     const Standard_Real    TolU, 
160                                     const Standard_Real    TolV)
161 {
162   Initialize (S,
163               S.FirstUParameter(), S.LastUParameter(),
164               S.FirstVParameter(), S.LastVParameter(),
165               TolU, TolV);
166   Perform(P);
167 }
168 //=======================================================================
169 //function : Initialize
170 //purpose  : 
171 //=======================================================================
172
173 void Extrema_ExtPExtS::Initialize(const Adaptor3d_SurfaceOfLinearExtrusion& S,
174                                   const Standard_Real Uinf,
175                                   const Standard_Real Usup,
176                                   const Standard_Real Vinf,
177                                   const Standard_Real Vsup,
178                                   const Standard_Real TolU,
179                                   const Standard_Real TolV)
180 {
181   myuinf=Uinf;
182   myusup=Usup;
183   mytolu=TolU;
184   
185   myvinf=Vinf;
186   myvsup=Vsup;
187   mytolv=TolV;
188   
189   Handle(Adaptor3d_HCurve) anACurve = S.BasisCurve();
190
191   myF.Initialize(S);
192   myC = anACurve;
193   myPosition = GetPosition(myC);
194   myDirection = S.Direction();
195   myIsAnalyticallyComputable = //Standard_False;
196     IsCaseAnalyticallyComputable (myC->GetType(),myPosition,myDirection);
197   
198   if (!myIsAnalyticallyComputable)
199     
200     myExtPS.Initialize(S, 32, 32,
201                        Uinf, Usup, Vinf, Vsup,
202                        TolU, TolV);
203 }
204
205
206 //=======================================================================
207 //function : Perform
208 //purpose  : 
209 //=======================================================================
210
211 void Extrema_ExtPExtS::Perform (const gp_Pnt& P)
212 {
213   myDone = Standard_False;
214   myNbExt = 0;
215   
216   if (!myIsAnalyticallyComputable) {
217     myExtPS.Perform(P);
218     myDone = myExtPS.IsDone();
219 //  modified by NIZHNY-EAP Wed Nov 17 12:59:08 1999 ___BEGIN___
220     myNbExt = myExtPS.NbExt();
221 //  modified by NIZHNY-EAP Wed Nov 17 12:59:09 1999 ___END___
222     return;
223   }
224   
225   gp_Pnt Pe, Pp = ProjectPnt(myPosition,myDirection,P);
226   Extrema_ExtPElC anExt;
227   PerformExtPElC(anExt, Pp, myC, mytolu);
228   if (!anExt.IsDone()) return;
229   
230   gp_Ax2 anOrtogSection (P, myDirection);
231   Standard_Real U,V;
232   Standard_Boolean
233     isMin,
234     isSimpleCase =
235       myDirection.IsParallel(myPosition.Direction(),Precision::Angular());
236   Standard_Integer i, aNbExt = anExt.NbExt();
237   math_Vector UV(1,2), Tol(1,2), UVinf(1,2), UVsup(1,2);
238   Tol(1) = mytolu;   Tol(2) = mytolv;
239   UVinf(1) = myuinf; UVinf(2) = myvinf;
240   UVsup(1) = myusup; UVsup(2) = myvsup;
241   
242   
243   for (i=1; i<=aNbExt; i++) {
244     Extrema_POnCurv POC=anExt.Point(i);
245     U = POC.Parameter();
246     //// modified by jgv, 23.12.2008 for OCC17194 ////
247     if (myC->IsPeriodic())
248       {
249         Standard_Real U2 = U;
250         ElCLib::AdjustPeriodic(myuinf, myuinf + 2.*PI, Precision::PConfusion(), U, U2);
251       }
252     //////////////////////////////////////////////////
253     gp_Pnt E = POC.Value();
254     Pe = ProjectPnt(anOrtogSection, myDirection, E);
255     
256     if (isSimpleCase) {
257       V = gp_Vec(E,Pe) * gp_Vec(myDirection);
258       // modified by NIZHNY-MKK  Thu Sep 18 14:46:14 2003.BEGIN
259       //       myPoint[++myNbExt] = Extrema_POnSurf(U, V, Pe);
260       //       myValue[myNbExt] = anExt.Value(i);
261       myPoint[myNbExt] = Extrema_POnSurf(U, V, Pe);
262       mySqDist[myNbExt] = anExt.SquareDistance(i);
263       myNbExt++;
264       // modified by NIZHNY-MKK  Thu Sep 18 14:46:18 2003.END
265     }
266     else {
267       myF.SetPoint(P);
268       isMin = anExt.IsMin(i);//( Pp.Distance(GetValue(U+10,myC)) > anExt.Value(i) );
269       
270       MakePreciser(U, P, isMin, anOrtogSection);
271       E = GetValue(U, myC);
272       Pe = ProjectPnt (anOrtogSection, myDirection, E),
273       V = gp_Vec(E,Pe) * gp_Vec(myDirection);
274       UV(1) = U;         UV(2) = V;
275       math_FunctionSetRoot aFSR (myF,UV,Tol,UVinf,UVsup);
276 //      for (Standard_Integer k=1 ; k <= myF.NbExt(); 
277       Standard_Integer k;
278       for ( k=1 ; k <= myF.NbExt(); k++) {
279         if (IsOriginalPnt(myF.Point(k).Value(), myPoint, myNbExt)) {
280           // modified by NIZHNY-MKK  Thu Sep 18 14:46:41 2003.BEGIN
281           //      myPoint[++myNbExt] = myF.Point(k);
282           //      myValue[myNbExt] = myF.Value(k);
283           myPoint[myNbExt] = myF.Point(k);
284           mySqDist[myNbExt] = myF.SquareDistance(k);
285           myNbExt++;
286           // modified by NIZHNY-MKK  Thu Sep 18 14:46:43 2003.END
287         }
288       }
289       // try symmetric point
290       U *= -1;
291       MakePreciser(U, P, isMin, anOrtogSection);
292       E = GetValue(U, myC);
293       Pe = ProjectPnt (anOrtogSection, myDirection, E),
294       V = gp_Vec(E,Pe) * gp_Vec(myDirection); 
295       UV(1) = U; UV(2) = V;
296       
297       aFSR.Perform (myF,UV,UVinf,UVsup);
298       
299       for (k=1 ; k <= myF.NbExt(); k++) {
300         if (IsOriginalPnt(myF.Point(k).Value(), myPoint, myNbExt)) {
301           // modified by NIZHNY-MKK  Thu Sep 18 14:46:59 2003.BEGIN
302           //      myPoint[++myNbExt] = myF.Point(k);
303           //      myValue[myNbExt] = myF.Value(k);
304           myPoint[myNbExt] = myF.Point(k);
305           mySqDist[myNbExt] = myF.SquareDistance(k);
306           myNbExt++;
307           // modified by NIZHNY-MKK  Thu Sep 18 14:47:04 2003.END
308         }
309       }
310     }
311   }
312   myDone = Standard_True;
313   return;
314 }
315
316 //=============================================================================
317
318 Standard_Boolean Extrema_ExtPExtS::IsDone () const { return myDone; }
319 //=============================================================================
320
321 Standard_Integer Extrema_ExtPExtS::NbExt () const
322 {
323   if (!IsDone()) { StdFail_NotDone::Raise(); }
324   if (myIsAnalyticallyComputable)
325     return myNbExt;
326   else
327     return myExtPS.NbExt();
328 }
329 //=============================================================================
330
331 Standard_Real Extrema_ExtPExtS::SquareDistance (const Standard_Integer N) const
332 {
333   if (!IsDone()) { StdFail_NotDone::Raise(); }
334   if ((N < 1) || (N > myNbExt)) { Standard_OutOfRange::Raise(); }
335   if (myIsAnalyticallyComputable)
336     // modified by NIZHNY-MKK  Thu Sep 18 14:48:39 2003.BEGIN
337     //     return myValue[N];
338     return mySqDist[N-1];
339   // modified by NIZHNY-MKK  Thu Sep 18 14:48:42 2003.END
340   else
341     return myExtPS.SquareDistance(N);
342 }
343 //=============================================================================
344
345 Extrema_POnSurf Extrema_ExtPExtS::Point (const Standard_Integer N) const
346 {
347   if (!IsDone()) { StdFail_NotDone::Raise(); }
348   if ((N < 1) || (N > myNbExt)) { Standard_OutOfRange::Raise(); }
349   if (myIsAnalyticallyComputable) {
350     // modified by NIZHNY-MKK  Thu Sep 18 14:47:40 2003.BEGIN
351     //     return myPoint[N];
352     return myPoint[N-1];
353   }
354   // modified by NIZHNY-MKK  Thu Sep 18 14:47:43 2003.END
355   else
356     return myExtPS.Point(N);
357 }
358 //=============================================================================
359
360
361 static gp_Ax2 GetPosition (const Handle(Adaptor3d_HCurve)& C)
362 {
363   switch (C->GetType()) {
364   case GeomAbs_Line: {
365     gp_Lin L = C->Line();
366     gp_Pln Pln = gp_Pln(L.Location(), L.Direction());
367     //:abv 30.05.02: OCC  - use constructor instead of Set...s() to avoid exception
368     gp_Ax2 Pos ( Pln.Location(), Pln.Position().Direction(), Pln.Position().XDirection() );
369 //     Pos.SetAxis(Pln.XAxis());
370 //     Pos.SetXDirection(Pln.YAxis().Direction());
371 //     Pos.SetYDirection(Pln.Position().Direction());
372     return Pos;
373   }
374   case GeomAbs_Circle:
375     return  C->Circle().Position();
376   case GeomAbs_Ellipse:
377     return  C->Ellipse().Position();
378   case GeomAbs_Hyperbola:
379     return  C->Hyperbola().Position();
380   case GeomAbs_Parabola:
381     return  C->Parabola().Position();
382   default: 
383     return gp_Ax2 ();
384   }
385 }
386 //=============================================================================
387
388 static void PerformExtPElC (Extrema_ExtPElC& E,
389                             const gp_Pnt& P,
390                             const Handle(Adaptor3d_HCurve)& C,
391                             const Standard_Real Tol)
392 {
393   switch (C->GetType()) {
394   case GeomAbs_Hyperbola:
395     E.Perform(P, C->Hyperbola(), Tol, -Precision::Infinite(),Precision::Infinite());
396     return;
397   case GeomAbs_Line:
398     E.Perform(P, C->Line(), Tol, -Precision::Infinite(),Precision::Infinite());
399     return;
400   case GeomAbs_Circle:
401     E.Perform(P, C->Circle(), Tol, 0.0, 2.0 * PI);
402     return;
403   case GeomAbs_Ellipse:
404     E.Perform(P, C->Ellipse(), Tol, 0.0, 2.0 * PI);
405     return;
406   case GeomAbs_Parabola:
407     E.Perform(P, C->Parabola(), Tol, -Precision::Infinite(),Precision::Infinite());
408     return;
409 #ifndef DEB
410   default:
411     return;
412 #endif
413   }
414 }
415
416 //=======================================================================
417 //function : IsCaseAnalyticallyComputable
418 //purpose  : 
419 //=======================================================================
420
421 static Standard_Boolean IsCaseAnalyticallyComputable
422   (const GeomAbs_CurveType& theType,
423    const gp_Ax2& theCurvePos,
424    const gp_Dir& theSurfaceDirection) 
425 {
426   // check type
427   switch (theType) {
428   case GeomAbs_Line:
429   case GeomAbs_Circle:
430   case GeomAbs_Ellipse:
431   case GeomAbs_Hyperbola:
432   case GeomAbs_Parabola:
433     break;
434   default:
435     return  Standard_False;
436   }
437   // check if it is a plane
438   if (Abs(theCurvePos.Direction() * theSurfaceDirection) <= gp::Resolution())
439     return Standard_False;
440   else
441     return Standard_True;
442 }
443 //=======================================================================
444 //function : GetValue
445 //purpose  : 
446 //=======================================================================
447
448 static gp_Pnt GetValue(const Standard_Real U,
449                        const Handle(Adaptor3d_HCurve)& C)
450 {
451   switch (C->GetType()) {
452   case GeomAbs_Line:
453     return ElCLib::Value(U, C->Line());
454   case GeomAbs_Circle:
455     return ElCLib::Value(U, C->Circle());
456   case GeomAbs_Ellipse:
457     return ElCLib::Value(U, C->Ellipse());
458   case GeomAbs_Hyperbola:
459     return ElCLib::Value(U, C->Hyperbola());
460   case GeomAbs_Parabola:
461     return ElCLib::Value(U, C->Parabola());
462   default:
463     return gp_Pnt();
464   }
465 }
466 //=======================================================================
467 //function : GetU
468 //purpose  : 
469 //=======================================================================
470 //#ifdef DEB
471 //static Standard_Real GetU(const gp_Vec& vec,
472 //                        const gp_Pnt& P,
473 //                        const Handle(Adaptor3d_HCurve)& C)
474 //{
475 //  switch (C->GetType()) {
476 //  case GeomAbs_Line:
477 //    return ElCLib::Parameter(C->Line().Translated(vec), P);
478 //  case GeomAbs_Circle:
479 //    return ElCLib::Parameter(C->Circle().Translated(vec), P);
480 //  case GeomAbs_Ellipse:
481 //    return ElCLib::Parameter(C->Ellipse().Translated(vec), P);
482 //  case GeomAbs_Hyperbola:
483 //    return ElCLib::Parameter(C->Hyperbola().Translated(vec), P);
484 //  case GeomAbs_Parabola:
485 //    return ElCLib::Parameter(C->Parabola().Translated(vec), P);
486 //  default:
487 //    return 0;
488 //  }
489 //}
490 //#endif