OCC22529 FitALL works incorrectly for small flat shapes
[occt.git] / src / Extrema / Extrema_GLocateExtPC.gxx
1 // File:        Extrema_GLocateExtPC.gxx
2 // Created:     Tue Dec 14 16:38:29 1993
3 // Author:      Christophe MARION
4 //              <cma@zerox>
5 // 05-Jun-00 : hla : meme type de corr. que xab : dans la methode "Perform",
6 //             suppression du test mal a propos "myintuinf > myintusup" avec
7 //             "return" a la suite.
8 // 05-Sep-95 : xab : correction d'un probleme de determination d'intervalle
9 //             de recherche
10
11 #include Extrema_ELPC_hxx
12 #include ThePOnC_hxx
13 #include ThePoint_hxx
14 #include TheVector_hxx
15 #include <StdFail_NotDone.hxx>
16 #include <Standard_DomainError.hxx>
17 #include <GeomAbs_CurveType.hxx>
18 #include <Precision.hxx>
19 #include <TColStd_Array1OfReal.hxx>
20
21
22 //=======================================================================
23 //function : Extrema_GLocateExtPC
24 //purpose  : 
25 //=======================================================================
26
27 Extrema_GLocateExtPC::Extrema_GLocateExtPC() { }
28
29
30 //=======================================================================
31 //function : Extrema_GLocateExtPC
32 //purpose  : 
33 //=======================================================================
34
35 Extrema_GLocateExtPC::Extrema_GLocateExtPC (const ThePoint&     P,
36                                             const TheCurve&     C,
37                                             const Standard_Real U0,
38                                             const Standard_Real TolF)
39 {
40   Initialize(C, TheCurveTool::FirstParameter(C), TheCurveTool::LastParameter(C), TolF);
41   Perform(P, U0);
42 }
43
44 //=======================================================================
45 //function : Extrema_GLocateExtPC
46 //purpose  : 
47 //=======================================================================
48
49 Extrema_GLocateExtPC::Extrema_GLocateExtPC (const ThePoint&     P,
50                                             const TheCurve&     C,
51                                             const Standard_Real U0, 
52                                             const Standard_Real Umin,
53                                             const Standard_Real Usup,
54                                             const Standard_Real TolF)
55 {
56   Initialize(C, Umin, Usup, TolF);
57   Perform(P, U0);
58 }
59
60
61
62 //=======================================================================
63 //function : Initialize
64 //purpose  : 
65 //=======================================================================
66
67 void Extrema_GLocateExtPC::Initialize(const TheCurve&     C, 
68                                       const Standard_Real Umin,
69                                       const Standard_Real Usup,
70                                       const Standard_Real TolF)
71 {
72   myC = (Standard_Address)&C;
73   mytol = TolF;
74   myumin = Umin;
75   myusup = Usup;
76   type = TheCurveTool::GetType(C);
77   Standard_Real tolu = TheCurveTool::Resolution(C, Precision::Confusion());
78   if ((type == GeomAbs_BSplineCurve) || 
79       (type == GeomAbs_BezierCurve)  || 
80       (type == GeomAbs_OtherCurve)) {
81     myLocExtPC.Initialize(C, Umin, Usup, tolu);
82   }
83   else {
84     myExtremPC.Initialize(C, Umin, Usup, tolu);
85   }
86 }
87
88
89
90
91 //=======================================================================
92 //function : Perform
93 //purpose  : 
94 //=======================================================================
95
96 void Extrema_GLocateExtPC::Perform(const ThePoint&     P,
97                                    const Standard_Real U0)
98 {
99   Standard_Integer i, i1, i2, inter;
100 #ifdef DEB
101   Standard_Real Tol = TheCurveTool::Resolution(*((TheCurve*)myC), Precision::Confusion());
102 #else
103   TheCurveTool::Resolution(*((TheCurve*)myC), Precision::Confusion());
104 #endif
105   Standard_Real Par, valU, valU2 = RealLast(),
106   local_u0 ;
107   Standard_Real myintuinf=0, myintusup=0;
108   local_u0 = U0 ;
109   switch(type) {
110     case GeomAbs_OtherCurve:
111     case GeomAbs_BSplineCurve: {
112       // La recherche de l extremum est faite intervalle continu C2 par
113       // intervalle continu C2 de la courbe
114       Standard_Integer n = TheCurveTool::NbIntervals(*((TheCurve*)myC), GeomAbs_C2);
115       TColStd_Array1OfReal theInter(1, n+1);
116       TheCurveTool::Intervals(*((TheCurve*)myC), theInter, GeomAbs_C2);
117 //
118 //  be gentle with the caller 
119 //
120       if (local_u0 < myumin) {
121         local_u0 = myumin ; 
122       }
123       else if (local_u0 > myusup) {
124         local_u0  = myusup ;
125       }
126       // Recherche de l intervalle ou se trouve U0
127       Standard_Boolean found = Standard_False;
128       inter = 1;
129       while (!found && inter <= n) {
130         // Intervalle commun a l intervalle C2 courant de la courbe et a
131         // l intervalle total de recherche de l'extremum (hla : au cas ou
132         // myintuinf > myintusup, c est que les 2 intervalles ne s intersectent
133         // pas, mais il n'y avait aucune raison de sortir en "return")
134         myintuinf = Max(theInter(inter), myumin);
135         myintusup = Min(theInter(inter+1), myusup);
136         if ((local_u0 >= myintuinf) && (local_u0 < myintusup)) found = Standard_True;
137         inter++;
138       }
139
140       if( found ) inter--; //IFV 16.06.00 - inter is increased after found!
141
142       // Essai sur l intervalle trouve
143       myLocExtPC.Initialize((*((TheCurve*)myC)), myintuinf, 
144                             myintusup, mytol);
145       myLocExtPC.Perform(P, local_u0);
146       myDone = myLocExtPC.IsDone();
147       if (myDone) {
148         mypp = myLocExtPC.Point();
149         myismin = myLocExtPC.IsMin();
150         mydist2 = myLocExtPC.SquareDistance();
151       }
152       else {
153         Standard_Integer k = 1;
154         // Essai sur les intervalles alentours:
155         i1 = inter;
156         i2 = inter;
157         Standard_Real s1inf, s2inf, s1sup, s2sup;
158         ThePoint P1;
159         TheVector V1;
160         TheCurveTool::D1(*((TheCurve*)myC), myintuinf, P1, V1);
161         s2inf = (TheVector(P, P1)*V1);
162         TheCurveTool::D1(*((TheCurve*)myC), myintusup, P1, V1);
163         s1sup = (TheVector(P, P1)*V1);
164         
165
166         while (!myDone && (i2 > 0) && (i1 <= n)) {
167           i1 = inter + k;
168           i2 = inter - k;
169           if (i1 <= n) {
170             myintuinf = Max(theInter(i1), myumin);
171             myintusup = Min(theInter(i1+1), myusup);
172             if (myintuinf < myintusup) {
173               TheCurveTool::D1(*((TheCurve*)myC), myintuinf, P1, V1);
174               s2sup = (TheVector(P, P1)*V1);
175               if (s1sup*s2sup <= RealEpsilon()) {
176                 // extremum:
177                 myDone = Standard_True;
178                 mypp.SetValues(myintuinf, P1);
179                 myismin = (s1sup <= 0.0);
180                 mydist2 = P.SquareDistance(P1);
181                 break;
182               }
183               TheCurveTool::D1(*((TheCurve*)myC), myintusup, P1, V1);
184               s1sup = (TheVector(P, P1)*V1);
185               myLocExtPC.Initialize((*((TheCurve*)myC)), myintuinf, 
186                                     myintusup, mytol);
187               myLocExtPC.Perform(P, (myintuinf + myintusup)*0.5);
188               myDone = myLocExtPC.IsDone();
189               if (myDone) {
190                 mypp = myLocExtPC.Point();
191                 myismin = myLocExtPC.IsMin();
192                 mydist2 = myLocExtPC.SquareDistance();
193                 break;
194               }
195             }
196           }
197           if (i2 > 0) {
198             myintuinf = Max(theInter(i2), myumin);
199             myintusup = Min(theInter(i2+1), myusup);
200             if (myintuinf < myintusup) {
201               TheCurveTool::D1(*((TheCurve*)myC), myintusup, P1, V1);
202               s1inf = (TheVector(P, P1)*V1);
203               if (s1inf*s2inf <= RealEpsilon()) {
204                 // extremum:
205                 myDone = Standard_True;
206                 mypp.SetValues(myintusup, P1);
207                 myismin = (s1inf <= 0.0);
208                 mydist2 = P.SquareDistance(P1);
209                 break;
210               }
211               TheCurveTool::D1(*((TheCurve*)myC), myintuinf, P1, V1);
212               s2inf = (TheVector(P, P1)*V1);
213               myLocExtPC.Initialize((*((TheCurve*)myC)), myintuinf, 
214                                     myintusup, mytol);
215               myLocExtPC.Perform(P, (myintuinf+myintusup)*0.5 );
216               myDone = myLocExtPC.IsDone();
217               if (myDone) {
218                 mypp = myLocExtPC.Point();
219                 myismin = myLocExtPC.IsMin();
220                 mydist2 = myLocExtPC.SquareDistance();
221                 break;
222               }
223             }
224           }
225           k++;
226         }
227       }
228     }
229       break;
230     case GeomAbs_BezierCurve: {
231       myLocExtPC.Perform(P, U0);
232       myDone = myLocExtPC.IsDone();
233     }
234       break;
235     default:{
236       myExtremPC.Perform(P);
237       numberext = 0;
238       if (myExtremPC.IsDone()) {
239         for (i = 1; i <= myExtremPC.NbExt(); i++) {
240           Par = myExtremPC.Point(i).Parameter();
241           valU = Abs(Par - U0);
242           if (valU <= valU2) {
243             valU2 = valU;
244             numberext = i;
245             myDone = Standard_True;
246           }
247         }
248       }
249       if (numberext == 0) myDone = Standard_False;
250       break;
251     }
252   }
253 }
254
255
256
257
258 //=======================================================================
259 //function : IsDone
260 //purpose  : 
261 //=======================================================================
262
263 Standard_Boolean Extrema_GLocateExtPC::IsDone () const 
264 {
265   return myDone;
266 }
267
268
269 //=======================================================================
270 //function : Value
271 //purpose  : 
272 //=======================================================================
273
274 Standard_Real Extrema_GLocateExtPC::SquareDistance () const 
275 {
276   if (!myDone) { StdFail_NotDone::Raise(); }
277   Standard_Real d=0;
278   if ((type == GeomAbs_BezierCurve)) {
279     d =  myLocExtPC.SquareDistance();
280   }
281   else if(type == GeomAbs_BSplineCurve || type == GeomAbs_OtherCurve) {
282     d = mydist2;
283   }
284   else {
285     if (numberext != 0) {
286       d = myExtremPC.SquareDistance(numberext);
287     }
288   }
289   return d;
290 }
291
292
293 //=======================================================================
294 //function : IsMin
295 //purpose  : 
296 //=======================================================================
297
298 Standard_Boolean Extrema_GLocateExtPC::IsMin () const 
299 {
300   if (!myDone) { StdFail_NotDone::Raise(); }
301   Standard_Boolean b=0;
302   if ((type == GeomAbs_BezierCurve)) {
303     b = myLocExtPC.IsMin();
304   }
305   else if(type == GeomAbs_BSplineCurve || type == GeomAbs_OtherCurve) {
306     b = myismin;
307   }
308   else {
309     if (numberext != 0) {
310       b = myExtremPC.IsMin(numberext);
311     }
312   }
313   return b;
314 }
315
316
317 //=======================================================================
318 //function : Point
319 //purpose  : 
320 //=======================================================================
321
322 ThePOnC Extrema_GLocateExtPC::Point () const 
323 {
324   if (!myDone) { StdFail_NotDone::Raise(); }
325   ThePOnC P;
326   if (type == GeomAbs_BezierCurve) {
327     P = myLocExtPC.Point();
328   }
329   else if(type == GeomAbs_BSplineCurve || type == GeomAbs_OtherCurve) {
330     P =  mypp;
331   }
332   else {
333     if (numberext != 0) {
334       P = myExtremPC.Point(numberext);
335     }
336   }
337   return P;
338 }