swe4r 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,959 @@
1
+ /* SWISSEPH
2
+ $Header: /home/dieter/sweph/RCS/swemplan.c,v 1.74 2008/06/16 10:07:20 dieter Exp $
3
+ Moshier planet routines
4
+
5
+ modified for SWISSEPH by Dieter Koch
6
+
7
+ **************************************************************/
8
+ /* Copyright (C) 1997 - 2008 Astrodienst AG, Switzerland. All rights reserved.
9
+
10
+ License conditions
11
+ ------------------
12
+
13
+ This file is part of Swiss Ephemeris.
14
+
15
+ Swiss Ephemeris is distributed with NO WARRANTY OF ANY KIND. No author
16
+ or distributor accepts any responsibility for the consequences of using it,
17
+ or for whether it serves any particular purpose or works at all, unless he
18
+ or she says so in writing.
19
+
20
+ Swiss Ephemeris is made available by its authors under a dual licensing
21
+ system. The software developer, who uses any part of Swiss Ephemeris
22
+ in his or her software, must choose between one of the two license models,
23
+ which are
24
+ a) GNU public license version 2 or later
25
+ b) Swiss Ephemeris Professional License
26
+
27
+ The choice must be made before the software developer distributes software
28
+ containing parts of Swiss Ephemeris to others, and before any public
29
+ service using the developed software is activated.
30
+
31
+ If the developer choses the GNU GPL software license, he or she must fulfill
32
+ the conditions of that license, which includes the obligation to place his
33
+ or her whole software project under the GNU GPL or a compatible license.
34
+ See http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
35
+
36
+ If the developer choses the Swiss Ephemeris Professional license,
37
+ he must follow the instructions as found in http://www.astro.com/swisseph/
38
+ and purchase the Swiss Ephemeris Professional Edition from Astrodienst
39
+ and sign the corresponding license contract.
40
+
41
+ The License grants you the right to use, copy, modify and redistribute
42
+ Swiss Ephemeris, but only under certain conditions described in the License.
43
+ Among other things, the License requires that the copyright notices and
44
+ this notice be preserved on all copies.
45
+
46
+ Authors of the Swiss Ephemeris: Dieter Koch and Alois Treindl
47
+
48
+ The authors of Swiss Ephemeris have no control or influence over any of
49
+ the derived works, i.e. over software or services created by other
50
+ programmers which use Swiss Ephemeris functions.
51
+
52
+ The names of the authors or of the copyright holder (Astrodienst) must not
53
+ be used for promoting any software, product or service which uses or contains
54
+ the Swiss Ephemeris. This copyright notice is the ONLY place where the
55
+ names of the authors can legally appear, except in cases where they have
56
+ given special permission in writing.
57
+
58
+ The trademarks 'Swiss Ephemeris' and 'Swiss Ephemeris inside' may be used
59
+ for promoting such software, products or services.
60
+ */
61
+
62
+ #include <string.h>
63
+ #include "swephexp.h"
64
+ #include "sweph.h"
65
+ #include "swephlib.h"
66
+ #include "src/swemptab.c"
67
+
68
+ #define TIMESCALE 3652500.0
69
+
70
+ #define mods3600(x) ((x) - 1.296e6 * floor ((x)/1.296e6))
71
+
72
+ #define FICT_GEO 1
73
+ #define KGAUSS_GEO 0.0000298122353216 /* Earth only */
74
+ /* #define KGAUSS_GEO 0.00002999502129737 Earth + Moon */
75
+
76
+ static void embofs_mosh(double J, double *xemb);
77
+ static int check_t_terms(double t, char *sinp, double *doutp);
78
+
79
+ static int read_elements_file(int32 ipl, double tjd,
80
+ double *tjd0, double *tequ,
81
+ double *mano, double *sema, double *ecce,
82
+ double *parg, double *node, double *incl,
83
+ char *pname, int32 *fict_ifl, char *serr);
84
+
85
+ static int pnoint2msh[] = {2, 2, 0, 1, 3, 4, 5, 6, 7, 8, };
86
+
87
+
88
+ /* From Simon et al (1994) */
89
+ static double freqs[] =
90
+ {
91
+ /* Arc sec per 10000 Julian years. */
92
+ 53810162868.8982,
93
+ 21066413643.3548,
94
+ 12959774228.3429,
95
+ 6890507749.3988,
96
+ 1092566037.7991,
97
+ 439960985.5372,
98
+ 154248119.3933,
99
+ 78655032.0744,
100
+ 52272245.1795
101
+ };
102
+
103
+ static double phases[] =
104
+ {
105
+ /* Arc sec. */
106
+ 252.25090552 * 3600.,
107
+ 181.97980085 * 3600.,
108
+ 100.46645683 * 3600.,
109
+ 355.43299958 * 3600.,
110
+ 34.35151874 * 3600.,
111
+ 50.07744430 * 3600.,
112
+ 314.05500511 * 3600.,
113
+ 304.34866548 * 3600.,
114
+ 860492.1546,
115
+ };
116
+
117
+ static struct plantbl *planets[] =
118
+ {
119
+ &mer404,
120
+ &ven404,
121
+ &ear404,
122
+ &mar404,
123
+ &jup404,
124
+ &sat404,
125
+ &ura404,
126
+ &nep404,
127
+ &plu404
128
+ };
129
+
130
+ static double FAR ss[9][24];
131
+ static double FAR cc[9][24];
132
+
133
+ static void sscc (int k, double arg, int n);
134
+
135
+ int swi_moshplan2 (double J, int iplm, double *pobj)
136
+ {
137
+ int i, j, k, m, k1, ip, np, nt;
138
+ signed char FAR *p;
139
+ double FAR *pl, *pb, *pr;
140
+ double su, cu, sv, cv, T;
141
+ double t, sl, sb, sr;
142
+ struct plantbl *plan = planets[iplm];
143
+
144
+ T = (J - J2000) / TIMESCALE;
145
+ /* Calculate sin( i*MM ), etc. for needed multiple angles. */
146
+ for (i = 0; i < 9; i++)
147
+ {
148
+ if ((j = plan->max_harmonic[i]) > 0)
149
+ {
150
+ sr = (mods3600 (freqs[i] * T) + phases[i]) * STR;
151
+ sscc (i, sr, j);
152
+ }
153
+ }
154
+
155
+ /* Point to start of table of arguments. */
156
+ p = plan->arg_tbl;
157
+ /* Point to tabulated cosine and sine amplitudes. */
158
+ pl = plan->lon_tbl;
159
+ pb = plan->lat_tbl;
160
+ pr = plan->rad_tbl;
161
+ sl = 0.0;
162
+ sb = 0.0;
163
+ sr = 0.0;
164
+
165
+ for (;;)
166
+ {
167
+ /* argument of sine and cosine */
168
+ /* Number of periodic arguments. */
169
+ np = *p++;
170
+ if (np < 0)
171
+ break;
172
+ if (np == 0)
173
+ { /* It is a polynomial term. */
174
+ nt = *p++;
175
+ /* Longitude polynomial. */
176
+ cu = *pl++;
177
+ for (ip = 0; ip < nt; ip++)
178
+ {
179
+ cu = cu * T + *pl++;
180
+ }
181
+ sl += mods3600 (cu);
182
+ /* Latitude polynomial. */
183
+ cu = *pb++;
184
+ for (ip = 0; ip < nt; ip++)
185
+ {
186
+ cu = cu * T + *pb++;
187
+ }
188
+ sb += cu;
189
+ /* Radius polynomial. */
190
+ cu = *pr++;
191
+ for (ip = 0; ip < nt; ip++)
192
+ {
193
+ cu = cu * T + *pr++;
194
+ }
195
+ sr += cu;
196
+ continue;
197
+ }
198
+ k1 = 0;
199
+ cv = 0.0;
200
+ sv = 0.0;
201
+ for (ip = 0; ip < np; ip++)
202
+ {
203
+ /* What harmonic. */
204
+ j = *p++;
205
+ /* Which planet. */
206
+ m = *p++ - 1;
207
+ if (j)
208
+ {
209
+ k = j;
210
+ if (j < 0)
211
+ k = -k;
212
+ k -= 1;
213
+ su = ss[m][k]; /* sin(k*angle) */
214
+ if (j < 0)
215
+ su = -su;
216
+ cu = cc[m][k];
217
+ if (k1 == 0)
218
+ { /* set first angle */
219
+ sv = su;
220
+ cv = cu;
221
+ k1 = 1;
222
+ }
223
+ else
224
+ { /* combine angles */
225
+ t = su * cv + cu * sv;
226
+ cv = cu * cv - su * sv;
227
+ sv = t;
228
+ }
229
+ }
230
+ }
231
+ /* Highest power of T. */
232
+ nt = *p++;
233
+ /* Longitude. */
234
+ cu = *pl++;
235
+ su = *pl++;
236
+ for (ip = 0; ip < nt; ip++)
237
+ {
238
+ cu = cu * T + *pl++;
239
+ su = su * T + *pl++;
240
+ }
241
+ sl += cu * cv + su * sv;
242
+ /* Latitiude. */
243
+ cu = *pb++;
244
+ su = *pb++;
245
+ for (ip = 0; ip < nt; ip++)
246
+ {
247
+ cu = cu * T + *pb++;
248
+ su = su * T + *pb++;
249
+ }
250
+ sb += cu * cv + su * sv;
251
+ /* Radius. */
252
+ cu = *pr++;
253
+ su = *pr++;
254
+ for (ip = 0; ip < nt; ip++)
255
+ {
256
+ cu = cu * T + *pr++;
257
+ su = su * T + *pr++;
258
+ }
259
+ sr += cu * cv + su * sv;
260
+ }
261
+ pobj[0] = STR * sl;
262
+ pobj[1] = STR * sb;
263
+ pobj[2] = STR * plan->distance * sr + plan->distance;
264
+ return OK;
265
+ }
266
+
267
+ /* Moshier ephemeris.
268
+ * computes heliocentric cartesian equatorial coordinates of
269
+ * equinox 2000
270
+ * for earth and a planet
271
+ * tjd julian day
272
+ * ipli internal SWEPH planet number
273
+ * xp array of 6 doubles for planet's position and speed
274
+ * xe earth's
275
+ * serr error string
276
+ */
277
+ int swi_moshplan(double tjd, int ipli, AS_BOOL do_save, double *xpret, double *xeret, char *serr)
278
+ {
279
+ int i;
280
+ int do_earth = FALSE;
281
+ double dx[3], x2[3], xxe[6], xxp[6];
282
+ double *xp, *xe;
283
+ double dt;
284
+ char s[AS_MAXCH];
285
+ int iplm = pnoint2msh[ipli];
286
+ struct plan_data *pdp = &swed.pldat[ipli];
287
+ struct plan_data *pedp = &swed.pldat[SEI_EARTH];
288
+ double seps2000 = swed.oec2000.seps;
289
+ double ceps2000 = swed.oec2000.ceps;
290
+ if (do_save) {
291
+ xp = pdp->x;
292
+ xe = pedp->x;
293
+ } else {
294
+ xp = xxp;
295
+ xe = xxe;
296
+ }
297
+ if (do_save || ipli == SEI_EARTH || xeret != NULL)
298
+ do_earth = TRUE;
299
+ /* tjd beyond ephemeris limits, give some margin for spped at edge */
300
+ if (tjd < MOSHPLEPH_START - 0.3 || tjd > MOSHPLEPH_END + 0.3) {
301
+ if (serr != NULL) {
302
+ sprintf(s, "jd %f outside Moshier planet range %.2f .. %.2f ",
303
+ tjd, MOSHPLEPH_START, MOSHPLEPH_END);
304
+ if (strlen(serr) + strlen(s) < AS_MAXCH)
305
+ strcat(serr, s);
306
+ }
307
+ return(ERR);
308
+ }
309
+ /* earth, for geocentric position */
310
+ if (do_earth) {
311
+ if (tjd == pedp->teval
312
+ && pedp->iephe == SEFLG_MOSEPH) {
313
+ xe = pedp->x;
314
+ } else {
315
+ /* emb */
316
+ swi_moshplan2(tjd, pnoint2msh[SEI_EMB], xe); /* emb hel. ecl. 2000 polar */
317
+ swi_polcart(xe, xe); /* to cartesian */
318
+ swi_coortrf2(xe, xe, -seps2000, ceps2000);/* and equator 2000 */
319
+ embofs_mosh(tjd, xe); /* emb -> earth */
320
+ if (do_save) {
321
+ pedp->teval = tjd;
322
+ pedp->xflgs = -1;
323
+ pedp->iephe = SEFLG_MOSEPH;
324
+ }
325
+ /* one more position for speed. */
326
+ swi_moshplan2(tjd - PLAN_SPEED_INTV, pnoint2msh[SEI_EMB], x2);
327
+ swi_polcart(x2, x2);
328
+ swi_coortrf2(x2, x2, -seps2000, ceps2000);
329
+ embofs_mosh(tjd - PLAN_SPEED_INTV, x2);/**/
330
+ for (i = 0; i <= 2; i++)
331
+ dx[i] = (xe[i] - x2[i]) / PLAN_SPEED_INTV;
332
+ /* store speed */
333
+ for (i = 0; i <= 2; i++) {
334
+ xe[i+3] = dx[i];
335
+ }
336
+ }
337
+ if (xeret != NULL)
338
+ for (i = 0; i <= 5; i++)
339
+ xeret[i] = xe[i];
340
+ }
341
+ /* earth is the planet wanted */
342
+ if (ipli == SEI_EARTH) {
343
+ xp = xe;
344
+ } else {
345
+ /* other planet */
346
+ /* if planet has already been computed, return */
347
+ if (tjd == pdp->teval && pdp->iephe == SEFLG_MOSEPH) {
348
+ xp = pdp->x;
349
+ } else {
350
+ swi_moshplan2(tjd, iplm, xp);
351
+ swi_polcart(xp, xp);
352
+ swi_coortrf2(xp, xp, -seps2000, ceps2000);
353
+ if (do_save) {
354
+ pdp->teval = tjd;/**/
355
+ pdp->xflgs = -1;
356
+ pdp->iephe = SEFLG_MOSEPH;
357
+ }
358
+ /* one more position for speed.
359
+ * the following dt gives good speed for light-time correction
360
+ */
361
+ #if 0
362
+ for (i = 0; i <= 2; i++)
363
+ dx[i] = xp[i] - pedp->x[i];
364
+ dt = LIGHTTIME_AUNIT * sqrt(square_sum(dx));
365
+ #endif
366
+ dt = PLAN_SPEED_INTV;
367
+ swi_moshplan2(tjd - dt, iplm, x2);
368
+ swi_polcart(x2, x2);
369
+ swi_coortrf2(x2, x2, -seps2000, ceps2000);
370
+ for (i = 0; i <= 2; i++)
371
+ dx[i] = (xp[i] - x2[i]) / dt;
372
+ /* store speed */
373
+ for (i = 0; i <= 2; i++) {
374
+ xp[i+3] = dx[i];
375
+ }
376
+ }
377
+ if (xpret != NULL)
378
+ for (i = 0; i <= 5; i++)
379
+ xpret[i] = xp[i];
380
+ }
381
+ return(OK);
382
+ }
383
+
384
+
385
+ /* Prepare lookup table of sin and cos ( i*Lj )
386
+ * for required multiple angles
387
+ */
388
+ static void sscc (int k, double arg, int n)
389
+ {
390
+ double cu, su, cv, sv, s;
391
+ int i;
392
+
393
+ su = sin (arg);
394
+ cu = cos (arg);
395
+ ss[k][0] = su; /* sin(L) */
396
+ cc[k][0] = cu; /* cos(L) */
397
+ sv = 2.0 * su * cu;
398
+ cv = cu * cu - su * su;
399
+ ss[k][1] = sv; /* sin(2L) */
400
+ cc[k][1] = cv;
401
+ for (i = 2; i < n; i++)
402
+ {
403
+ s = su * cv + cu * sv;
404
+ cv = cu * cv - su * sv;
405
+ sv = s;
406
+ ss[k][i] = sv; /* sin( i+1 L ) */
407
+ cc[k][i] = cv;
408
+ }
409
+ }
410
+
411
+
412
+ /* Adjust position from Earth-Moon barycenter to Earth
413
+ *
414
+ * J = Julian day number
415
+ * xemb = rectangular equatorial coordinates of Earth
416
+ */
417
+ static void embofs_mosh(double tjd, double *xemb)
418
+ {
419
+ double T, M, a, L, B, p;
420
+ double smp, cmp, s2mp, c2mp, s2d, c2d, sf, cf;
421
+ double s2f, sx, cx, xyz[6];
422
+ double seps = swed.oec.seps;
423
+ double ceps = swed.oec.ceps;
424
+ int i;
425
+ /* Short series for position of the Moon
426
+ */
427
+ T = (tjd-J1900)/36525.0;
428
+ /* Mean anomaly of moon (MP) */
429
+ a = swe_degnorm(((1.44e-5*T + 0.009192)*T + 477198.8491)*T + 296.104608);
430
+ a *= DEGTORAD;
431
+ smp = sin(a);
432
+ cmp = cos(a);
433
+ s2mp = 2.0*smp*cmp; /* sin(2MP) */
434
+ c2mp = cmp*cmp - smp*smp; /* cos(2MP) */
435
+ /* Mean elongation of moon (D) */
436
+ a = swe_degnorm(((1.9e-6*T - 0.001436)*T + 445267.1142)*T + 350.737486);
437
+ a = 2.0 * DEGTORAD * a;
438
+ s2d = sin(a);
439
+ c2d = cos(a);
440
+ /* Mean distance of moon from its ascending node (F) */
441
+ a = swe_degnorm((( -3.e-7*T - 0.003211)*T + 483202.0251)*T + 11.250889);
442
+ a *= DEGTORAD;
443
+ sf = sin(a);
444
+ cf = cos(a);
445
+ s2f = 2.0*sf*cf; /* sin(2F) */
446
+ sx = s2d*cmp - c2d*smp; /* sin(2D - MP) */
447
+ cx = c2d*cmp + s2d*smp; /* cos(2D - MP) */
448
+ /* Mean longitude of moon (LP) */
449
+ L = ((1.9e-6*T - 0.001133)*T + 481267.8831)*T + 270.434164;
450
+ /* Mean anomaly of sun (M) */
451
+ M = swe_degnorm((( -3.3e-6*T - 1.50e-4)*T + 35999.0498)*T + 358.475833);
452
+ /* Ecliptic longitude of the moon */
453
+ L = L
454
+ + 6.288750*smp
455
+ + 1.274018*sx
456
+ + 0.658309*s2d
457
+ + 0.213616*s2mp
458
+ - 0.185596*sin( DEGTORAD * M )
459
+ - 0.114336*s2f;
460
+ /* Ecliptic latitude of the moon */
461
+ a = smp*cf;
462
+ sx = cmp*sf;
463
+ B = 5.128189*sf
464
+ + 0.280606*(a+sx) /* sin(MP+F) */
465
+ + 0.277693*(a-sx) /* sin(MP-F) */
466
+ + 0.173238*(s2d*cf - c2d*sf); /* sin(2D-F) */
467
+ B *= DEGTORAD;
468
+ /* Parallax of the moon */
469
+ p = 0.950724
470
+ +0.051818*cmp
471
+ +0.009531*cx
472
+ +0.007843*c2d
473
+ +0.002824*c2mp;
474
+ p *= DEGTORAD;
475
+ /* Elongation of Moon from Sun
476
+ */
477
+ L = swe_degnorm(L);
478
+ L *= DEGTORAD;
479
+ /* Distance in au */
480
+ a = 4.263523e-5/sin(p);
481
+ /* Convert to rectangular ecliptic coordinates */
482
+ xyz[0] = L;
483
+ xyz[1] = B;
484
+ xyz[2] = a;
485
+ swi_polcart(xyz, xyz);
486
+ /* Convert to equatorial */
487
+ swi_coortrf2(xyz, xyz, -seps, ceps);
488
+ /* Precess to equinox of J2000.0 */
489
+ swi_precess(xyz, tjd, J_TO_J2000);/**/
490
+ /* now emb -> earth */
491
+ for (i = 0; i <= 2; i++)
492
+ xemb[i] -= xyz[i] / (EARTH_MOON_MRAT + 1.0);
493
+ }
494
+
495
+ /* orbital elements of planets that are computed from osculating elements
496
+ * epoch
497
+ * equinox
498
+ * mean anomaly,
499
+ * semi axis,
500
+ * eccentricity,
501
+ * argument of perihelion,
502
+ * ascending node
503
+ * inclination
504
+ */
505
+ #define SE_NEELY /* use James Neely's revised elements
506
+ * of Uranian planets*/
507
+ static char *plan_fict_nam[SE_NFICT_ELEM] =
508
+ {"Cupido", "Hades", "Zeus", "Kronos",
509
+ "Apollon", "Admetos", "Vulkanus", "Poseidon",
510
+ "Isis-Transpluto", "Nibiru", "Harrington",
511
+ "Leverrier", "Adams",
512
+ "Lowell", "Pickering",};
513
+
514
+ char *swi_get_fict_name(int32 ipl, char *snam)
515
+ {
516
+ if (read_elements_file(ipl, 0, NULL, NULL,
517
+ NULL, NULL, NULL, NULL, NULL, NULL,
518
+ snam, NULL, NULL) == ERR)
519
+ strcpy(snam, "name not found");
520
+ return snam;
521
+ }
522
+
523
+ static double plan_oscu_elem[SE_NFICT_ELEM][8] = {
524
+ #ifdef SE_NEELY
525
+ {J1900, J1900, 163.7409, 40.99837, 0.00460, 171.4333, 129.8325, 1.0833},/* Cupido Neely */
526
+ {J1900, J1900, 27.6496, 50.66744, 0.00245, 148.1796, 161.3339, 1.0500},/* Hades Neely */
527
+ {J1900, J1900, 165.1232, 59.21436, 0.00120, 299.0440, 0.0000, 0.0000},/* Zeus Neely */
528
+ {J1900, J1900, 169.0193, 64.81960, 0.00305, 208.8801, 0.0000, 0.0000},/* Kronos Neely */
529
+ {J1900, J1900, 138.0533, 70.29949, 0.00000, 0.0000, 0.0000, 0.0000},/* Apollon Neely */
530
+ {J1900, J1900, 351.3350, 73.62765, 0.00000, 0.0000, 0.0000, 0.0000},/* Admetos Neely */
531
+ {J1900, J1900, 55.8983, 77.25568, 0.00000, 0.0000, 0.0000, 0.0000},/* Vulcanus Neely */
532
+ {J1900, J1900, 165.5163, 83.66907, 0.00000, 0.0000, 0.0000, 0.0000},/* Poseidon Neely */
533
+ #else
534
+ {J1900, J1900, 104.5959, 40.99837, 0, 0, 0, 0}, /* Cupido */
535
+ {J1900, J1900, 337.4517, 50.667443, 0, 0, 0, 0}, /* Hades */
536
+ {J1900, J1900, 104.0904, 59.214362, 0, 0, 0, 0}, /* Zeus */
537
+ {J1900, J1900, 17.7346, 64.816896, 0, 0, 0, 0}, /* Kronos */
538
+ {J1900, J1900, 138.0354, 70.361652, 0, 0, 0, 0}, /* Apollon */
539
+ {J1900, J1900, -8.678, 73.736476, 0, 0, 0, 0}, /* Admetos */
540
+ {J1900, J1900, 55.9826, 77.445895, 0, 0, 0, 0}, /* Vulkanus */
541
+ {J1900, J1900, 165.3595, 83.493733, 0, 0, 0, 0}, /* Poseidon */
542
+ #endif
543
+ /* Isis-Transpluto; elements from "Die Sterne" 3/1952, p. 70ff.
544
+ * Strubell does not give an equinox. 1945 is taken to best reproduce
545
+ * ASTRON ephemeris. (This is a strange choice, though.)
546
+ * The epoch is 1772.76. The year is understood to have 366 days.
547
+ * The fraction is counted from 1 Jan. 1772 */
548
+ {2368547.66, 2431456.5, 0.0, 77.775, 0.3, 0.7, 0, 0},
549
+ /* Nibiru, elements from Christian Woeltge, Hannover */
550
+ {1856113.380954, 1856113.380954, 0.0, 234.8921, 0.981092, 103.966, -44.567, 158.708},
551
+ /* Harrington, elements from Astronomical Journal 96(4), Oct. 1988 */
552
+ {2374696.5, J2000, 0.0, 101.2, 0.411, 208.5, 275.4, 32.4},
553
+ /* Leverrier's Neptune,
554
+ according to W.G. Hoyt, "Planets X and Pluto", Tucson 1980, p. 63 */
555
+ {2395662.5, 2395662.5, 34.05, 36.15, 0.10761, 284.75, 0, 0},
556
+ /* Adam's Neptune */
557
+ {2395662.5, 2395662.5, 24.28, 37.25, 0.12062, 299.11, 0, 0},
558
+ /* Lowell's Pluto */
559
+ {2425977.5, 2425977.5, 281, 43.0, 0.202, 204.9, 0, 0},
560
+ /* Pickering's Pluto */
561
+ {2425977.5, 2425977.5, 48.95, 55.1, 0.31, 280.1, 100, 15}, /**/
562
+ #if 0 /* Ceres JPL 1600, without perturbations from other minor planets,
563
+ * from following initial elements:
564
+ * 2450600.5 2000 0 1 164.7073602 73.0340746 80.5995101
565
+ * 10.5840296 0.07652422 0.0 2.770176095 */
566
+ {2305447.5, J2000, 0.5874558977449977e+02, 0.2766536058742327e+01,
567
+ 0.7870946565779195e-01, 0.5809199028919189e+02,
568
+ 0.8650119410725021e+02, 0.1066835622280712e+02},
569
+ /* Chiron, Bowell database 18-mar-1997 */
570
+ {2450500.5, J2000, 7.258191, 13.67387471, 0.38174778, 339.558345, 209.379239, 6.933360}, /**/
571
+ #endif
572
+ };
573
+
574
+ /* computes a planet from osculating elements *
575
+ * tjd julian day
576
+ * ipl body number
577
+ * ipli body number in planetary data structure
578
+ * iflag flags
579
+ */
580
+ int swi_osc_el_plan(double tjd, double *xp, int ipl, int ipli, double *xearth, double *xsun, char *serr)
581
+ {
582
+ double pqr[9], x[6];
583
+ double eps, K, fac, rho, cose, sine;
584
+ double alpha, beta, zeta, sigma, M2, Msgn, M_180_or_0;
585
+ double tjd0, tequ, mano, sema, ecce, parg, node, incl, dmot;
586
+ double cosnode, sinnode, cosincl, sinincl, cosparg, sinparg;
587
+ double M, E;
588
+ struct plan_data *pedp = &swed.pldat[SEI_EARTH];
589
+ struct plan_data *pdp = &swed.pldat[ipli];
590
+ int32 fict_ifl = 0;
591
+ int i;
592
+ /* orbital elements, either from file or, if file not found,
593
+ * from above built-in set
594
+ */
595
+ if (read_elements_file(ipl, tjd, &tjd0, &tequ,
596
+ &mano, &sema, &ecce, &parg, &node, &incl,
597
+ NULL, &fict_ifl, serr) == ERR)
598
+ return ERR;
599
+ dmot = 0.9856076686 * DEGTORAD / sema / sqrt(sema); /* daily motion */
600
+ if (fict_ifl & FICT_GEO)
601
+ dmot /= sqrt(SUN_EARTH_MRAT);
602
+ cosnode = cos(node);
603
+ sinnode = sin(node);
604
+ cosincl = cos(incl);
605
+ sinincl = sin(incl);
606
+ cosparg = cos(parg);
607
+ sinparg = sin(parg);
608
+ /* Gaussian vector */
609
+ pqr[0] = cosparg * cosnode - sinparg * cosincl * sinnode;
610
+ pqr[1] = -sinparg * cosnode - cosparg * cosincl * sinnode;
611
+ pqr[2] = sinincl * sinnode;
612
+ pqr[3] = cosparg * sinnode + sinparg * cosincl * cosnode;
613
+ pqr[4] = -sinparg * sinnode + cosparg * cosincl * cosnode;
614
+ pqr[5] = -sinincl * cosnode;
615
+ pqr[6] = sinparg * sinincl;
616
+ pqr[7] = cosparg * sinincl;
617
+ pqr[8] = cosincl;
618
+ /* Kepler problem */
619
+ E = M = swi_mod2PI(mano + (tjd - tjd0) * dmot); /* mean anomaly of date */
620
+ /* better E for very high eccentricity and small M */
621
+ if (ecce > 0.975) {
622
+ M2 = M * RADTODEG;
623
+ if (M2 > 150 && M2 < 210) {
624
+ M2 -= 180;
625
+ M_180_or_0 = 180;
626
+ } else
627
+ M_180_or_0 = 0;
628
+ if (M2 > 330)
629
+ M2 -= 360;
630
+ if (M2 < 0) {
631
+ M2 = -M2;
632
+ Msgn = -1;
633
+ } else
634
+ Msgn = 1;
635
+ if (M2 < 30) {
636
+ M2 *= DEGTORAD;
637
+ alpha = (1 - ecce) / (4 * ecce + 0.5);
638
+ beta = M2 / (8 * ecce + 1);
639
+ zeta = pow(beta + sqrt(beta * beta + alpha * alpha), 1/3);
640
+ sigma = zeta - alpha / 2;
641
+ sigma = sigma - 0.078 * sigma * sigma * sigma * sigma * sigma / (1 + ecce);
642
+ E = Msgn * (M2 + ecce * (3 * sigma - 4 * sigma * sigma * sigma))
643
+ + M_180_or_0;
644
+ }
645
+ }
646
+ E = swi_kepler(E, M, ecce);
647
+ /* position and speed, referred to orbital plane */
648
+ if (fict_ifl & FICT_GEO)
649
+ K = KGAUSS_GEO / sqrt(sema);
650
+ else
651
+ K = KGAUSS / sqrt(sema);
652
+ cose = cos(E);
653
+ sine = sin(E);
654
+ fac = sqrt((1 - ecce) * (1 + ecce));
655
+ rho = 1 - ecce * cose;
656
+ x[0] = sema * (cose - ecce);
657
+ x[1] = sema * fac * sine;
658
+ x[3] = -K * sine / rho;
659
+ x[4] = K * fac * cose / rho;
660
+ /* transformation to ecliptic */
661
+ xp[0] = pqr[0] * x[0] + pqr[1] * x[1];
662
+ xp[1] = pqr[3] * x[0] + pqr[4] * x[1];
663
+ xp[2] = pqr[6] * x[0] + pqr[7] * x[1];
664
+ xp[3] = pqr[0] * x[3] + pqr[1] * x[4];
665
+ xp[4] = pqr[3] * x[3] + pqr[4] * x[4];
666
+ xp[5] = pqr[6] * x[3] + pqr[7] * x[4];
667
+ /* transformation to equator */
668
+ eps = swi_epsiln(tequ);
669
+ swi_coortrf(xp, xp, -eps);
670
+ swi_coortrf(xp+3, xp+3, -eps);
671
+ /* precess to J2000 */
672
+ if (tequ != J2000) {
673
+ swi_precess(xp, tequ, J_TO_J2000);
674
+ swi_precess(xp+3, tequ, J_TO_J2000);
675
+ }
676
+ /* to solar system barycentre */
677
+ if (fict_ifl & FICT_GEO) {
678
+ for (i = 0; i <= 5; i++) {
679
+ xp[i] += xearth[i];
680
+ }
681
+ } else {
682
+ for (i = 0; i <= 5; i++) {
683
+ xp[i] += xsun[i];
684
+ }
685
+ }
686
+ if (pdp->x == xp) {
687
+ pdp->teval = tjd; /* for precession! */
688
+ pdp->iephe = pedp->iephe;
689
+ }
690
+ return OK;
691
+ }
692
+
693
+ #if 1
694
+ /* note: input parameter tjd is required for T terms in elements */
695
+ static int read_elements_file(int32 ipl, double tjd,
696
+ double *tjd0, double *tequ,
697
+ double *mano, double *sema, double *ecce,
698
+ double *parg, double *node, double *incl,
699
+ char *pname, int32 *fict_ifl, char *serr)
700
+ {
701
+ int i, iline, iplan, retc, ncpos;
702
+ FILE *fp = NULL;
703
+ char s[AS_MAXCH], *sp;
704
+ char *cpos[20], serri[AS_MAXCH];
705
+ AS_BOOL elem_found = FALSE;
706
+ double tt = 0;
707
+ /* -1, because file information is not saved, file is always closed */
708
+ if ((fp = swi_fopen(-1, SE_FICTFILE, swed.ephepath, serr)) == NULL) {
709
+ /* file does not exist, use built-in bodies */
710
+ if (ipl >= SE_NFICT_ELEM) {
711
+ if (serr != NULL)
712
+ sprintf(serr, "error no elements for fictitious body no %7.0f", (double) ipl);
713
+ return ERR;
714
+ }
715
+ if (tjd0 != NULL)
716
+ *tjd0 = plan_oscu_elem[ipl][0]; /* epoch */
717
+ if (tequ != NULL)
718
+ *tequ = plan_oscu_elem[ipl][1]; /* equinox */
719
+ if (mano != NULL)
720
+ *mano = plan_oscu_elem[ipl][2] * DEGTORAD; /* mean anomaly */
721
+ if (sema != NULL)
722
+ *sema = plan_oscu_elem[ipl][3]; /* semi-axis */
723
+ if (ecce != NULL)
724
+ *ecce = plan_oscu_elem[ipl][4]; /* eccentricity */
725
+ if (parg != NULL)
726
+ *parg = plan_oscu_elem[ipl][5] * DEGTORAD; /* arg. of peri. */
727
+ if (node != NULL)
728
+ *node = plan_oscu_elem[ipl][6] * DEGTORAD; /* asc. node */
729
+ if (incl != NULL)
730
+ *incl = plan_oscu_elem[ipl][7] * DEGTORAD; /* inclination */
731
+ if (pname != NULL)
732
+ strcpy(pname, plan_fict_nam[ipl]);
733
+ return OK;
734
+ }
735
+ /*
736
+ * find elements in file
737
+ */
738
+ iline = 0;
739
+ iplan = -1;
740
+ while (fgets(s, AS_MAXCH, fp) != NULL) {
741
+ iline++;
742
+ sp = s;
743
+ while(*sp == ' ' || *sp == '\t')
744
+ sp++;
745
+ swi_strcpy(s, sp);
746
+ if (*s == '#')
747
+ continue;
748
+ if (*s == '\r')
749
+ continue;
750
+ if (*s == '\n')
751
+ continue;
752
+ if (*s == '\0')
753
+ continue;
754
+ if ((sp = strchr(s, '#')) != NULL)
755
+ *sp = '\0';
756
+ ncpos = swi_cutstr(s, ",", cpos, 20);
757
+ sprintf(serri, "error in file %s, line %7.0f:",
758
+ SE_FICTFILE, (double) iline);
759
+ if (ncpos < 9) {
760
+ if (serr != NULL)
761
+ sprintf(serr, "%s nine elements required", serri);
762
+ return ERR;
763
+ }
764
+ iplan++;
765
+ if (iplan != ipl)
766
+ continue;
767
+ elem_found = TRUE;
768
+ /* epoch of elements */
769
+ if (tjd0 != NULL) {
770
+ sp = cpos[0];
771
+ for (i = 0; i < 5; i++)
772
+ sp[i] = tolower(sp[i]);
773
+ if (strncmp(sp, "j2000", 5) == OK)
774
+ *tjd0 = J2000;
775
+ else if (strncmp(sp, "b1950", 5) == OK)
776
+ *tjd0 = B1950;
777
+ else if (strncmp(sp, "j1900", 5) == OK)
778
+ *tjd0 = J1900;
779
+ else if (*sp == 'j' || *sp == 'b') {
780
+ if (serr != NULL)
781
+ sprintf(serr, "%s invalid epoch", serri);
782
+ goto return_err;
783
+ } else
784
+ *tjd0 = atof(sp);
785
+ tt = tjd - *tjd0;
786
+ }
787
+ /* equinox */
788
+ if (tequ != NULL) {
789
+ sp = cpos[1];
790
+ while(*sp == ' ' || *sp == '\t')
791
+ sp++;
792
+ for (i = 0; i < 5; i++)
793
+ sp[i] = tolower(sp[i]);
794
+ if (strncmp(sp, "j2000", 5) == OK)
795
+ *tequ = J2000;
796
+ else if (strncmp(sp, "b1950", 5) == OK)
797
+ *tequ = B1950;
798
+ else if (strncmp(sp, "j1900", 5) == OK)
799
+ *tequ = J1900;
800
+ else if (strncmp(sp, "jdate", 5) == OK)
801
+ *tequ = tjd;
802
+ else if (*sp == 'j' || *sp == 'b') {
803
+ if (serr != NULL)
804
+ sprintf(serr, "%s invalid equinox", serri);
805
+ goto return_err;
806
+ } else
807
+ *tequ = atof(sp);
808
+ }
809
+ /* mean anomaly t0 */
810
+ if (mano != NULL) {
811
+ retc = check_t_terms(tt, cpos[2], mano);
812
+ *mano = swe_degnorm(*mano);
813
+ if (retc == ERR) {
814
+ if (serr != NULL)
815
+ sprintf(serr, "%s mean anomaly value invalid", serri);
816
+ goto return_err;
817
+ }
818
+ /* if mean anomaly has t terms (which happens with fictitious
819
+ * planet Vulcan), we set
820
+ * epoch = tjd, so that no motion will be added anymore
821
+ * equinox = tjd */
822
+ if (retc == 1) {
823
+ *tjd0 = tjd;
824
+ }
825
+ *mano *= DEGTORAD;
826
+ }
827
+ /* semi-axis */
828
+ if (sema != NULL) {
829
+ retc = check_t_terms(tt, cpos[3], sema);
830
+ if (*sema <= 0 || retc == ERR) {
831
+ if (serr != NULL)
832
+ sprintf(serr, "%s semi-axis value invalid", serri);
833
+ goto return_err;
834
+ }
835
+ }
836
+ /* eccentricity */
837
+ if (ecce != NULL) {
838
+ retc = check_t_terms(tt, cpos[4], ecce);
839
+ if (*ecce >= 1 || *ecce < 0 || retc == ERR) {
840
+ if (serr != NULL)
841
+ sprintf(serr, "%s eccentricity invalid (no parabolic or hyperbolic orbits allowed)", serri);
842
+ goto return_err;
843
+ }
844
+ }
845
+ /* perihelion argument */
846
+ if (parg != NULL) {
847
+ retc = check_t_terms(tt, cpos[5], parg);
848
+ *parg = swe_degnorm(*parg);
849
+ if (retc == ERR) {
850
+ if (serr != NULL)
851
+ sprintf(serr, "%s perihelion argument value invalid", serri);
852
+ goto return_err;
853
+ }
854
+ *parg *= DEGTORAD;
855
+ }
856
+ /* node */
857
+ if (node != NULL) {
858
+ retc = check_t_terms(tt, cpos[6], node);
859
+ *node = swe_degnorm(*node);
860
+ if (retc == ERR) {
861
+ if (serr != NULL)
862
+ sprintf(serr, "%s node value invalid", serri);
863
+ goto return_err;
864
+ }
865
+ *node *= DEGTORAD;
866
+ }
867
+ /* inclination */
868
+ if (incl != NULL) {
869
+ retc = check_t_terms(tt, cpos[7], incl);
870
+ *incl = swe_degnorm(*incl);
871
+ if (retc == ERR) {
872
+ if (serr != NULL)
873
+ sprintf(serr, "%s inclination value invalid", serri);
874
+ goto return_err;
875
+ }
876
+ *incl *= DEGTORAD;
877
+ }
878
+ /* planet name */
879
+ if (pname != NULL) {
880
+ sp = cpos[8];
881
+ while(*sp == ' ' || *sp == '\t')
882
+ sp++;
883
+ swi_right_trim(sp);
884
+ strcpy(pname, sp);
885
+ }
886
+ /* geocentric */
887
+ if (fict_ifl != NULL && ncpos > 9) {
888
+ for (sp = cpos[9]; *sp != '\0'; sp++)
889
+ *sp = tolower(*sp);
890
+ if (strstr(cpos[9], "geo") != NULL)
891
+ *fict_ifl |= FICT_GEO;
892
+ }
893
+ break;
894
+ }
895
+ if (!elem_found) {
896
+ if (serr != NULL)
897
+ sprintf(serr, "%s elements for planet %7.0f not found", serri, (double) ipl);
898
+ goto return_err;
899
+ }
900
+ fclose(fp);
901
+ return OK;
902
+ return_err:
903
+ fclose(fp);
904
+ return ERR;
905
+ }
906
+ #endif
907
+
908
+ static int check_t_terms(double t, char *sinp, double *doutp)
909
+ {
910
+ int i, isgn = 1, z;
911
+ int retc = 0;
912
+ char *sp;
913
+ double tt[5], fac;
914
+ tt[0] = t / 36525;
915
+ tt[1] = tt[0];
916
+ tt[2] = tt[1] * tt[1];
917
+ tt[3] = tt[2] * tt[1];
918
+ tt[4] = tt[3] * tt[1];
919
+ if ((sp = strpbrk(sinp, "+-")) != NULL)
920
+ retc = 1; /* with additional terms */
921
+ sp = sinp;
922
+ *doutp = 0;
923
+ fac = 1;
924
+ z = 0;
925
+ while (1) {
926
+ while(*sp != '\0' && strchr(" \t", *sp) != NULL)
927
+ sp++;
928
+ if (strchr("+-", *sp) || *sp == '\0') {
929
+ if (z > 0)
930
+ *doutp += fac;
931
+ isgn = 1;
932
+ if (*sp == '-')
933
+ isgn = -1;
934
+ fac = 1 * isgn;
935
+ if (*sp == '\0')
936
+ return retc;
937
+ sp++;
938
+ } else {
939
+ while(*sp != '\0' && strchr("* \t", *sp) != NULL)
940
+ sp++;
941
+ if (*sp != '\0' && strchr("tT", *sp) != NULL) {
942
+ /* a T */
943
+ sp++;
944
+ if (*sp != '\0' && strchr("+-", *sp))
945
+ fac *= tt[0];
946
+ else if ((i = atoi(sp)) <= 4 && i >= 0)
947
+ fac *= tt[i];
948
+ } else {
949
+ /* a number */
950
+ if (atof(sp) != 0 || *sp == '0')
951
+ fac *= atof(sp);
952
+ }
953
+ while (*sp != '\0' && strchr("0123456789.", *sp))
954
+ sp++;
955
+ }
956
+ z++;
957
+ }
958
+ return retc; /* there have been additional terms */
959
+ }