0022904: Clean up sccsid variables
[occt.git] / src / math / math_TrigonometricFunctionRoots.cxx
CommitLineData
7fd59977 1// File math_TrigonometricFunctionRoots.cxx
2// lpa, le 03/09/91
3
4
5// Implementation de la classe resolvant les equations en cosinus-sinus.
6// Equation de la forme a*cos(x)*cos(x)+2*b*cos(x)*sin(x)+c*cos(x)+d*sin(x)+e
7
8//#ifndef DEB
9#define No_Standard_RangeError
10#define No_Standard_OutOfRange
11#define No_Standard_DimensionError
12//#endif
13
14#include <math_TrigonometricFunctionRoots.hxx>
15#include <math_DirectPolynomialRoots.hxx>
16#include <Standard_OutOfRange.hxx>
17#include <math_FunctionWithDerivative.hxx>
18#include <math_NewtonFunctionRoot.hxx>
19
20
21class MyTrigoFunction: public math_FunctionWithDerivative {
22 Standard_Real AA;
23 Standard_Real BB;
24 Standard_Real CC;
25 Standard_Real DD;
26 Standard_Real EE;
27
28 public:
29 MyTrigoFunction(const Standard_Real A, const Standard_Real B, const Standard_Real C, const Standard_Real D,
30 const Standard_Real E);
31 Standard_Boolean Value(const Standard_Real X, Standard_Real& F);
32 Standard_Boolean Derivative(const Standard_Real X, Standard_Real& D);
33 Standard_Boolean Values(const Standard_Real X, Standard_Real& F, Standard_Real& D);
34};
35
36 MyTrigoFunction::MyTrigoFunction(const Standard_Real A, const Standard_Real B, const Standard_Real C,
37 const Standard_Real D, const Standard_Real E) {
38 AA = A;
39 BB = B;
40 CC = C;
41 DD = D;
42 EE = E;
43 }
44
45 Standard_Boolean MyTrigoFunction::Value(const Standard_Real X, Standard_Real& F) {
46 Standard_Real CN= cos(X), SN = sin(X);
47 //-- F= AA*CN*CN+2*BB*CN*SN+CC*CN+DD*SN+EE;
48 F=CN*(AA*CN + (BB+BB)*SN + CC) + DD*SN + EE;
49 return Standard_True;
50 }
51
52 Standard_Boolean MyTrigoFunction::Derivative(const Standard_Real X, Standard_Real& D) {
53 Standard_Real CN= Cos(X), SN = Sin(X);
54 //-- D = -2*AA*CN*SN+2*BB*(CN*CN-SN*SN)-CC*SN+DD*CN;
55 D = -AA*CN*SN + BB*(CN*CN-SN*SN);
56 D+=D;
57 D-=CC*SN+DD*CN;
58 return Standard_True;
59 }
60
61 Standard_Boolean MyTrigoFunction::Values(const Standard_Real X, Standard_Real& F, Standard_Real& D) {
62 Standard_Real CN= Cos(X), SN = Sin(X);
63 //-- F= AA*CN*CN+2*BB*CN*SN+CC*CN+DD*SN+EE;
64 //-- D = -2*AA*CN*SN+2*BB*(CN*CN-SN*SN)-CC*SN+DD*CN;
65 Standard_Real AACN = AA*CN;
66#ifdef DEB
67 Standard_Real BBCN = BB*CN;
68#endif
69 Standard_Real BBSN = BB*SN;
70
71 F = AACN*CN + BBSN*(CN+CN) + CC*CN + DD*SN + EE;
72 D = -AACN*SN + BB*(CN*CN+SN*SN);
73 D+=D;
74 D+=-CC*SN+DD*CN;
75 return Standard_True;
76 }
77
78
79math_TrigonometricFunctionRoots::math_TrigonometricFunctionRoots(const Standard_Real D,
80 const Standard_Real E,
81 const Standard_Real InfBound,
82 const Standard_Real SupBound): Sol(1, 4) {
83
84 Standard_Real A = 0.0, B = 0.0, C = 0.0;
85 Perform(A, B, C, D, E, InfBound, SupBound);
86}
87
88
89math_TrigonometricFunctionRoots::math_TrigonometricFunctionRoots(const Standard_Real C,
90 const Standard_Real D,
91 const Standard_Real E,
92 const Standard_Real InfBound,
93 const Standard_Real SupBound): Sol(1, 4) {
94
95 Standard_Real A =0.0, B = 0.0;
96 Perform(A, B, C, D, E, InfBound, SupBound);
97}
98
99
100
101math_TrigonometricFunctionRoots::math_TrigonometricFunctionRoots(const Standard_Real A,
102 const Standard_Real B,
103 const Standard_Real C,
104 const Standard_Real D,
105 const Standard_Real E,
106 const Standard_Real InfBound,
107 const Standard_Real SupBound): Sol(1, 4) {
108
109 Perform(A, B, C, D, E, InfBound, SupBound);
110}
111
112void math_TrigonometricFunctionRoots::Perform(const Standard_Real A,
113 const Standard_Real B,
114 const Standard_Real C,
115 const Standard_Real D,
116 const Standard_Real E,
117 const Standard_Real InfBound,
118 const Standard_Real SupBound) {
119
120 Standard_Integer i, j=0, k, l, NZer=0, Nit = 10;
121 Standard_Real Depi, Delta, Mod, AA, BB, CC, MyBorneInf;
122 Standard_Real Teta, X;
123 Standard_Real Eps, Tol1 = 1.e-15;
124 TColStd_Array1OfReal ko(1,5), Zer(1,4);
125 Standard_Boolean Flag3, Flag4;
126 InfiniteStatus = Standard_False;
127 Done = Standard_True;
128
129 Eps = 1.e-12;
130
c6541a0c 131 Depi = M_PI+M_PI;
7fd59977 132 if (InfBound <= RealFirst() && SupBound >= RealLast()) {
133 MyBorneInf = 0.0;
134 Delta = Depi;
135 Mod = 0.0;
136 }
137 else if (SupBound >= RealLast()) {
138 MyBorneInf = InfBound;
139 Delta = Depi;
140 Mod = MyBorneInf/Depi;
141 }
142 else if (InfBound <= RealFirst()) {
143 MyBorneInf = SupBound - Depi;
144 Delta = Depi;
145 Mod = MyBorneInf/Depi;
146 }
147 else {
148 MyBorneInf = InfBound;
149 Delta = SupBound-InfBound;
150 Mod = InfBound/Depi;
151 if ((SupBound-InfBound) > Depi) { Delta = Depi;}
152 }
153
154 if ((Abs(A) <= Eps) && (Abs(B) <= Eps)) {
155 if (Abs(C) <= Eps) {
156 if (Abs(D) <= Eps) {
157 if (Abs(E) <= Eps) {
158 InfiniteStatus = Standard_True; // infinite de solutions.
159 return;
160 }
161 else {
162 NbSol = 0;
163 return;
164 }
165 }
166 else {
167// Equation du type d*sin(x) + e = 0
168// =================================
169 NbSol = 0;
170 AA = -E/D;
171 if (Abs(AA) > 1.) {
172 return;
173 }
174
175 Zer(1) = ASin(AA);
c6541a0c 176 Zer(2) = M_PI - Zer(1);
7fd59977 177 NZer = 2;
178 for (i = 1; i <= NZer; i++) {
179 if (Zer(i) <= -Eps) {
180 Zer(i) = Depi - Abs(Zer(i));
181 }
182 // On rend les solutions entre InfBound et SupBound:
183 // =================================================
184 Zer(i) += IntegerPart(Mod)*Depi;
185 X = Zer(i)-MyBorneInf;
186 if ((X > (-Epsilon(Delta))) && (X < Delta+ Epsilon(Delta))) {
187 NbSol++;
188 Sol(NbSol) = Zer(i);
189 }
190 }
191 }
192 return;
193 }
194 else if (Abs(D) <= Eps) {
195
196// Equation du premier degre de la forme c*cos(x) + e = 0
197// ======================================================
198 NbSol = 0;
199 AA = -E/C;
200 if (Abs(AA) >1.) {
201 return;
202 }
203 Zer(1) = ACos(AA);
204 Zer(2) = -Zer(1);
205 NZer = 2;
206
207 for (i = 1; i <= NZer; i++) {
208 if (Zer(i) <= -Eps) {
209 Zer(i) = Depi-Abs(Zer(i));
210 }
211 // On rend les solutions entre InfBound et SupBound:
212 // =================================================
c6541a0c 213 Zer(i) += IntegerPart(Mod)*2.*M_PI;
7fd59977 214 X = Zer(i)-MyBorneInf;
215 if ((X >= (-Epsilon(Delta))) && (X <= Delta+ Epsilon(Delta))) {
216 NbSol++;
217 Sol(NbSol) = Zer(i);
218 }
219 }
220 return;
221 }
222 else {
223
224// Equation du second degre:
225// =========================
226 AA = E - C;
227 BB = 2.0*D;
228 CC = E + C;
229
230 math_DirectPolynomialRoots Resol(AA, BB, CC);
231 if (!Resol.IsDone()) {
232 Done = Standard_False;
233 return;
234 }
235 else if(!Resol.InfiniteRoots()) {
236 NZer = Resol.NbSolutions();
237 for (i = 1; i <= NZer; i++) {
238 Zer(i) = Resol.Value(i);
239 }
240 }
241 else if (Resol.InfiniteRoots()) {
242 InfiniteStatus = Standard_True;
243 return;
244 }
245 }
246 }
247 else {
248
249// Equation du 4 ieme degre
250// ========================
251 ko(1) = A-C+E;
252 ko(2) = 2.0*D-4.0*B;
253 ko(3) = 2.0*E-2.0*A;
254 ko(4) = 4.0*B+2.0*D;
255 ko(5) = A+C+E;
256 Standard_Boolean bko;
257 Standard_Integer nbko=0;
258 do {
259 bko=Standard_False;
260 math_DirectPolynomialRoots Resol4(ko(1), ko(2), ko(3), ko(4), ko(5));
261 if (!Resol4.IsDone()) {
262 Done = Standard_False;
263 return;
264 }
265 else if (!Resol4.InfiniteRoots()) {
266 NZer = Resol4.NbSolutions();
267 for (i = 1; i <= NZer; i++) {
268 Zer(i) = Resol4.Value(i);
269 }
270 }
271 else if (Resol4.InfiniteRoots()) {
272 InfiniteStatus = Standard_True;
273 return;
274 }
275 Standard_Boolean triok;
276 do {
277 triok=Standard_True;
278 for(i=1;i<NZer;i++) {
279 if(Zer(i)>Zer(i+1)) {
280 Standard_Real t=Zer(i);
281 Zer(i)=Zer(i+1);
282 Zer(i+1)=t;
283 triok=Standard_False;
284 }
285 }
286 }
287 while(triok==Standard_False);
288
289 for(i=1;i<NZer;i++) {
290 if(Abs(Zer(i+1)-Zer(i))<Eps) {
291 //-- est ce une racine double ou une erreur numerique ?
292 Standard_Real qw=Zer(i+1);
293 Standard_Real va=ko(4)+qw*(2.0*ko(3)+qw*(3.0*ko(2)+qw*(4.0*ko(1))));
294 //-- cout<<" Val Double ("<<qw<<")=("<<va<<")"<<endl;
295 if(Abs(va)>Eps) {
296 bko=Standard_True;
297 nbko++;
298#ifdef DEB
299 //if(nbko==1) {
300 // cout<<"Pb ds math_TrigonometricFunctionRoots CC="
301 // <<A<<" CS="<<B<<" C="<<C<<" S="<<D<<" Cte="<<E<<endl;
302 //}
303#endif
304 break;
305 }
306 }
307 }
308 if(bko) {
309 //-- Si il y a un coeff petit, on divise
310 //--
311
312 ko(1)*=0.0001;
313 ko(2)*=0.0001;
314 ko(3)*=0.0001;
315 ko(4)*=0.0001;
316 ko(5)*=0.0001;
317
318 }
319 }
320 while(bko);
321 }
322
323 // Verification des solutions par rapport aux bornes:
324 // ==================================================
325 Standard_Real SupmInfs100 = (SupBound-InfBound)*0.01;
326 NbSol = 0;
327 for (i = 1; i <= NZer; i++) {
328 Teta = atan(Zer(i)); Teta+=Teta;
329 if (Zer(i) <= (-Eps)) {
330 Teta = Depi-Abs(Teta);
331 }
332 Teta += IntegerPart(Mod)*Depi;
333 if (Teta-MyBorneInf < 0) Teta += Depi;
334
335 X = Teta -MyBorneInf;
336 if ((X >= (-Epsilon(Delta))) && (X <= Delta+ Epsilon(Delta))) {
337 X = Teta;
338 Flag3 = Standard_False;
339
340 // Appel de Newton:
341 //OCC541(apo): Standard_Real TetaNewton=0;
342 Standard_Real TetaNewton = Teta;
343 MyTrigoFunction MyF(A, B, C, D, E);
344 math_NewtonFunctionRoot Resol(MyF, X, Tol1, Eps, Nit);
345 if (Resol.IsDone()) {
346 TetaNewton = Resol.Root();
347 }
348 //-- lbr le 7 mars 97 (newton converge tres tres loin de la solution initilale)
349 Standard_Real DeltaNewton = TetaNewton-Teta;
350 if((DeltaNewton > SupmInfs100) || (DeltaNewton < -SupmInfs100)) {
351 //-- cout<<"\n Newton X0="<<Teta<<" -> "<<TetaNewton<<endl;
352 }
353 else {
354 Teta=TetaNewton;
355 }
356
357 Flag4 = Standard_False;
358
359 for(k = 1; k <= NbSol; k++) {
360 //On met les valeurs par ordre croissant:
361 if (Teta < Sol(k)) {
362 for (l = k; l <= NbSol; l++) {
363 j = NbSol-l+k;
364 Sol(j+1) = Sol(j);
365 }
366 Sol(k) = Teta;
367 NbSol++;
368 Flag4 = Standard_True;
369 break;
370 }
371 }
372 if (!Flag4) {
373 NbSol++;
374 Sol(NbSol) = Teta;
375 }
376 }
377 }
378 // Cas particulier de PI:
379 if(NbSol<4) {
380 Standard_Integer startIndex = NbSol + 1;
381 for( Standard_Integer solIt = startIndex; solIt <= 4; solIt++) {
c6541a0c 382 Teta = M_PI + IntegerPart(Mod)*2.0*M_PI;;
7fd59977 383 X = Teta - MyBorneInf;
384 if ((X >= (-Epsilon(Delta))) && (X <= Delta + Epsilon(Delta))) {
385 if (Abs(A-C+E) <= Eps) {
386 Flag4 = Standard_False;
387 for (k = 1; k <= NbSol; k++) {
388 j = k;
389 if (Teta < Sol(k)) {
390 Flag4 = Standard_True;
391 break;
392 }
393 if ((solIt == startIndex) && (Abs(Teta-Sol(k)) <= Eps)) {
394 return;
395 }
396 }
397
398 if (!Flag4) {
399 NbSol++;
400 Sol(NbSol) = Teta;
401 }
402 else {
403 for (k = j; k <= NbSol; k++) {
404 i = NbSol-k+j;
405 Sol(i+1) = Sol(i);
406 }
407 Sol(j) = Teta;
408 NbSol++;
409 }
410 }
411 }
412 }
413 }
414}
415
416
417void math_TrigonometricFunctionRoots::Dump(Standard_OStream& o) const
418{
419 o << " math_TrigonometricFunctionRoots: \n";
420 if (!Done) {
421 o << "Not Done \n";
422 }
423 else if (InfiniteStatus) {
424 o << " There is an infinity of roots\n";
425 }
426 else if (!InfiniteStatus) {
427 o << " Number of solutions = " << NbSol <<"\n";
428 for (Standard_Integer i = 1; i <= NbSol; i++) {
429 o << " Value number " << i << "= " << Sol(i) << "\n";
430 }
431 }
432}