swe4r 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/swe4r/swecl.c ADDED
@@ -0,0 +1,4948 @@
1
+ /* SWISSEPH
2
+ $Header: /home/dieter/sweph/RCS/swecl.c,v 1.75 2008/08/26 07:23:27 dieter Exp $
3
+
4
+ Ephemeris computations
5
+ Author: 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 "swejpl.h"
63
+ #include "swephexp.h"
64
+ #include "sweph.h"
65
+ #include "swephlib.h"
66
+
67
+ #define SEFLG_EPHMASK (SEFLG_JPLEPH|SEFLG_SWIEPH|SEFLG_MOSEPH)
68
+ static int find_maximum(double y00, double y11, double y2, double dx,
69
+ double *dxret, double *yret);
70
+ static int find_zero(double y00, double y11, double y2, double dx,
71
+ double *dxret, double *dxret2);
72
+ static double calc_dip(double geoalt, double atpress, double attemp, double lapse_rate);
73
+ static double calc_astronomical_refr(double geoalt,double atpress, double attemp);
74
+ static double const_lapse_rate = SE_LAPSE_RATE; /* for refraction */
75
+
76
+ #if 0
77
+ #define DSUN (1391978489.9 / AUNIT) /* this value is consistent with
78
+ * 959.63 arcsec at AU distance (Astr. Alm.) */
79
+ #else
80
+ #define DSUN (1392000000.0 / AUNIT)
81
+ #endif
82
+ #define DMOON (3476300.0 / AUNIT)
83
+ #define DEARTH (6378140.0 * 2 / AUNIT)
84
+ #define RSUN (DSUN / 2)
85
+ #define RMOON (DMOON / 2)
86
+ #define REARTH (DEARTH / 2)
87
+ /*#define SEI_OCC_FAST (16 * 1024L)*/
88
+ static int32 eclipse_where( double tjd_ut, int32 ipl, char *starname, int32 ifl, double *geopos,
89
+ double *dcore, char *serr);
90
+ static int32 eclipse_how( double tjd_ut, int32 ipl, char *starname, int32 ifl,
91
+ double geolon, double geolat, double geohgt,
92
+ double *attr, char *serr);
93
+ static int32 eclipse_when_loc(double tjd_start, int32 ifl, double *geopos,
94
+ double *tret, double *attr, AS_BOOL backward, char *serr);
95
+ static int32 occult_when_loc(double tjd_start, int32 ipl, char *starname, int32 ifl,
96
+ double *geopos, double *tret, double *attr, AS_BOOL backward, char *serr);
97
+ static int32 lun_eclipse_how(double tjd_ut, int32 ifl, double *attr,
98
+ double *dcore, char *serr);
99
+ static int32 calc_mer_trans(
100
+ double tjd_ut, int32 ipl, int32 epheflag, int32 rsmi,
101
+ double *geopos,
102
+ char *starname,
103
+ double *tret,
104
+ char *serr);
105
+ static int32 calc_planet_star(double tjd_et, int32 ipl, char *starname, int32 iflag, double *x, char *serr);
106
+
107
+ struct saros_data {int series_no; double tstart;};
108
+
109
+ #define SAROS_CYCLE 6585.3213
110
+ #define NSAROS_SOLAR 181
111
+ struct saros_data saros_data_solar[NSAROS_SOLAR] = {
112
+ {0, 641886.5}, /* 23 May -2955 */
113
+ {1, 672214.5}, /* 04 Jun -2872 */
114
+ {2, 676200.5}, /* 04 May -2861 */
115
+ {3, 693357.5}, /* 24 Apr -2814 */
116
+ {4, 723685.5}, /* 06 May -2731 */
117
+ {5, 727671.5}, /* 04 Apr -2720 */
118
+ {6, 744829.5}, /* 27 Mar -2673 */
119
+ {7, 775157.5}, /* 08 Apr -2590 */
120
+ {8, 779143.5}, /* 07 Mar -2579 */
121
+ {9, 783131.5}, /* 06 Feb -2568 */
122
+ {10, 820044.5}, /* 28 Feb -2467 */
123
+ {11, 810859.5}, /* 06 Jan -2492 */
124
+ {12, 748993.5}, /* 20 Aug -2662 */
125
+ {13, 792492.5}, /* 23 Sep -2543 */
126
+ {14, 789892.5}, /* 11 Aug -2550 */
127
+ {15, 787294.5}, /* 01 Jul -2557 */
128
+ {16, 824207.5}, /* 23 Jul -2456 */
129
+ {17, 834779.5}, /* 03 Jul -2427 */
130
+ {18, 838766.5}, /* 02 Jun -2416 */
131
+ {19, 869094.5}, /* 15 Jun -2333 */
132
+ {20, 886251.5}, /* 05 Jun -2286 */
133
+ {21, 890238.5}, /* 05 May -2275 */
134
+ {22, 927151.5}, /* 28 May -2174 */
135
+ {23, 937722.5}, /* 07 May -2145 */
136
+ {24, 941709.5}, /* 06 Apr -2134 */
137
+ {25, 978623.5}, /* 30 Apr -2033 */
138
+ {26, 989194.5}, /* 08 Apr -2004 */
139
+ {27, 993181.5}, /* 09 Mar -1993 */
140
+ {28, 1023510.5}, /* 22 Mar -1910 */
141
+ {29, 1034081.5}, /* 01 Mar -1881 */
142
+ {30, 972214.5}, /* 12 Oct -2051 */
143
+ {31, 1061811.5}, /* 31 Jan -1805 */
144
+ {32, 1006529.5}, /* 24 Sep -1957 */
145
+ {33, 997345.5}, /* 02 Aug -1982 */
146
+ {34, 1021088.5}, /* 04 Aug -1917 */
147
+ {35, 1038245.5}, /* 25 Jul -1870 */
148
+ {36, 1042231.5}, /* 23 Jun -1859 */
149
+ {37, 1065974.5}, /* 25 Jun -1794 */
150
+ {38, 1089716.5}, /* 26 Jun -1729 */
151
+ {39, 1093703.5}, /* 26 May -1718 */
152
+ {40, 1117446.5}, /* 28 May -1653 */
153
+ {41, 1141188.5}, /* 28 May -1588 */
154
+ {42, 1145175.5}, /* 28 Apr -1577 */
155
+ {43, 1168918.5}, /* 29 Apr -1512 */
156
+ {44, 1192660.5}, /* 30 Apr -1447 */
157
+ {45, 1196647.5}, /* 30 Mar -1436 */
158
+ {46, 1220390.5}, /* 01 Apr -1371 */
159
+ {47, 1244132.5}, /* 02 Apr -1306 */
160
+ {48, 1234948.5}, /* 08 Feb -1331 */
161
+ {49, 1265277.5}, /* 22 Feb -1248 */
162
+ {50, 1282433.5}, /* 11 Feb -1201 */
163
+ {51, 1207395.5}, /* 02 Sep -1407 */
164
+ {52, 1217968.5}, /* 14 Aug -1378 */
165
+ {53, 1254881.5}, /* 06 Sep -1277 */
166
+ {54, 1252282.5}, /* 25 Jul -1284 */
167
+ {55, 1262855.5}, /* 06 Jul -1255 */
168
+ {56, 1293182.5}, /* 17 Jul -1172 */
169
+ {57, 1297169.5}, /* 17 Jun -1161 */
170
+ {58, 1314326.5}, /* 07 Jun -1114 */
171
+ {59, 1344654.5}, /* 19 Jun -1031 */
172
+ {60, 1348640.5}, /* 18 May -1020 */
173
+ {61, 1365798.5}, /* 10 May -0973 */
174
+ {62, 1396126.5}, /* 22 May -0890 */
175
+ {63, 1400112.5}, /* 20 Apr -0879 */
176
+ {64, 1417270.5}, /* 11 Apr -0832 */
177
+ {65, 1447598.5}, /* 24 Apr -0749 */
178
+ {66, 1444999.5}, /* 12 Mar -0756 */
179
+ {67, 1462157.5}, /* 04 Mar -0709 */
180
+ {68, 1492485.5}, /* 16 Mar -0626 */
181
+ {69, 1456959.5}, /* 09 Dec -0724 */
182
+ {70, 1421434.5}, /* 05 Sep -0821 */
183
+ {71, 1471518.5}, /* 19 Oct -0684 */
184
+ {72, 1455748.5}, /* 16 Aug -0727 */
185
+ {73, 1466320.5}, /* 27 Jul -0698 */
186
+ {74, 1496648.5}, /* 08 Aug -0615 */
187
+ {75, 1500634.5}, /* 07 Jul -0604 */
188
+ {76, 1511207.5}, /* 18 Jun -0575 */
189
+ {77, 1548120.5}, /* 11 Jul -0474 */
190
+ {78, 1552106.5}, /* 09 Jun -0463 */
191
+ {79, 1562679.5}, /* 21 May -0434 */
192
+ {80, 1599592.5}, /* 13 Jun -0333 */
193
+ {81, 1603578.5}, /* 12 May -0322 */
194
+ {82, 1614150.5}, /* 22 Apr -0293 */
195
+ {83, 1644479.5}, /* 05 May -0210 */
196
+ {84, 1655050.5}, /* 14 Apr -0181 */
197
+ {85, 1659037.5}, /* 14 Mar -0170 */
198
+ {86, 1695950.5}, /* 06 Apr -0069 */
199
+ {87, 1693351.5}, /* 23 Feb -0076 */
200
+ {88, 1631484.5}, /* 06 Oct -0246 */
201
+ {89, 1727666.5}, /* 04 Feb 0018 */
202
+ {90, 1672384.5}, /* 28 Sep -0134 */
203
+ {91, 1663200.5}, /* 06 Aug -0159 */
204
+ {92, 1693529.5}, /* 19 Aug -0076 */
205
+ {93, 1710685.5}, /* 09 Aug -0029 */
206
+ {94, 1714672.5}, /* 09 Jul -0018 */
207
+ {95, 1738415.5}, /* 11 Jul 0047 */
208
+ {96, 1755572.5}, /* 01 Jul 0094 */
209
+ {97, 1766144.5}, /* 11 Jun 0123 */
210
+ {98, 1789887.5}, /* 12 Jun 0188 */
211
+ {99, 1807044.5}, /* 03 Jun 0235 */
212
+ {100, 1817616.5}, /* 13 May 0264 */
213
+ {101, 1841359.5}, /* 15 May 0329 */
214
+ {102, 1858516.5}, /* 05 May 0376 */
215
+ {103, 1862502.5}, /* 04 Apr 0387 */
216
+ {104, 1892831.5}, /* 17 Apr 0470 */
217
+ {105, 1903402.5}, /* 27 Mar 0499 */
218
+ {106, 1887633.5}, /* 23 Jan 0456 */
219
+ {107, 1924547.5}, /* 15 Feb 0557 */
220
+ {108, 1921948.5}, /* 04 Jan 0550 */
221
+ {109, 1873251.5}, /* 07 Sep 0416 */
222
+ {110, 1890409.5}, /* 30 Aug 0463 */
223
+ {111, 1914151.5}, /* 30 Aug 0528 */
224
+ {112, 1918138.5}, /* 31 Jul 0539 */
225
+ {113, 1935296.5}, /* 22 Jul 0586 */
226
+ {114, 1959038.5}, /* 23 Jul 0651 */
227
+ {115, 1963024.5}, /* 21 Jun 0662 */
228
+ {116, 1986767.5}, /* 23 Jun 0727 */
229
+ {117, 2010510.5}, /* 24 Jun 0792 */
230
+ {118, 2014496.5}, /* 24 May 0803 */
231
+ {119, 2031654.5}, /* 15 May 0850 */
232
+ {120, 2061982.5}, /* 27 May 0933 */
233
+ {121, 2065968.5}, /* 25 Apr 0944 */
234
+ {122, 2083126.5}, /* 17 Apr 0991 */
235
+ {123, 2113454.5}, /* 29 Apr 1074 */
236
+ {124, 2104269.5}, /* 06 Mar 1049 */
237
+ {125, 2108256.5}, /* 04 Feb 1060 */
238
+ {126, 2151755.5}, /* 10 Mar 1179 */
239
+ {127, 2083302.5}, /* 10 Oct 0991 */
240
+ {128, 2080704.5}, /* 29 Aug 0984 */
241
+ {129, 2124203.5}, /* 03 Oct 1103 */
242
+ {130, 2121603.5}, /* 20 Aug 1096 */
243
+ {131, 2132176.5}, /* 01 Aug 1125 */
244
+ {132, 2162504.5}, /* 13 Aug 1208 */
245
+ {133, 2166490.5}, /* 13 Jul 1219 */
246
+ {134, 2177062.5}, /* 22 Jun 1248 */
247
+ {135, 2207390.5}, /* 05 Jul 1331 */
248
+ {136, 2217962.5}, /* 14 Jun 1360 */
249
+ {137, 2228534.5}, /* 25 May 1389 */
250
+ {138, 2258862.5}, /* 06 Jun 1472 */
251
+ {139, 2269434.5}, /* 17 May 1501 */
252
+ {140, 2273421.5}, /* 16 Apr 1512 */
253
+ {141, 2310334.5}, /* 19 May 1613 */
254
+ {142, 2314320.5}, /* 17 Apr 1624 */
255
+ {143, 2311722.5}, /* 07 Mar 1617 */
256
+ {144, 2355221.5}, /* 11 Apr 1736 */
257
+ {145, 2319695.5}, /* 04 Jan 1639 */
258
+ {146, 2284169.5}, /* 19 Sep 1541 */
259
+ {147, 2314498.5}, /* 12 Oct 1624 */
260
+ {148, 2325069.5}, /* 21 Sep 1653 */
261
+ {149, 2329056.5}, /* 21 Aug 1664 */
262
+ {150, 2352799.5}, /* 24 Aug 1729 */
263
+ {151, 2369956.5}, /* 14 Aug 1776 */
264
+ {152, 2380528.5}, /* 26 Jul 1805 */
265
+ {153, 2404271.5}, /* 28 Jul 1870 */
266
+ {154, 2421428.5}, /* 19 Jul 1917 */
267
+ {155, 2425414.5}, /* 17 Jun 1928 */
268
+ {156, 2455743.5}, /* 01 Jul 2011 */
269
+ {157, 2472900.5}, /* 21 Jun 2058 */
270
+ {158, 2476886.5}, /* 20 May 2069 */
271
+ {159, 2500629.5}, /* 23 May 2134 */
272
+ {160, 2517786.5}, /* 13 May 2181 */
273
+ {161, 2515187.5}, /* 01 Apr 2174 */
274
+ {162, 2545516.5}, /* 15 Apr 2257 */
275
+ {163, 2556087.5}, /* 25 Mar 2286 */
276
+ {164, 2487635.5}, /* 24 Oct 2098 */
277
+ {165, 2504793.5}, /* 16 Oct 2145 */
278
+ {166, 2535121.5}, /* 29 Oct 2228 */
279
+ {167, 2525936.5}, /* 06 Sep 2203 */
280
+ {168, 2543094.5}, /* 28 Aug 2250 */
281
+ {169, 2573422.5}, /* 10 Sep 2333 */
282
+ {170, 2577408.5}, /* 09 Aug 2344 */
283
+ {171, 2594566.5}, /* 01 Aug 2391 */
284
+ {172, 2624894.5}, /* 13 Aug 2474 */
285
+ {173, 2628880.5}, /* 12 Jul 2485 */
286
+ {174, 2646038.5}, /* 04 Jul 2532 */
287
+ {175, 2669780.5}, /* 05 Jul 2597 */
288
+ {176, 2673766.5}, /* 04 Jun 2608 */
289
+ {177, 2690924.5}, /* 27 May 2655 */
290
+ {178, 2721252.5}, /* 09 Jun 2738 */
291
+ {179, 2718653.5}, /* 28 Apr 2731 */
292
+ {180, 2729226.5}, /* 08 Apr 2760 */
293
+ };
294
+
295
+ #define NSAROS_LUNAR 180
296
+ struct saros_data saros_data_lunar[NSAROS_LUNAR] = {
297
+ {1, 782437.5}, /* 14 Mar -2570 */
298
+ {2, 799593.5}, /* 03 Mar -2523 */
299
+ {3, 783824.5}, /* 30 Dec -2567 */
300
+ {4, 754884.5}, /* 06 Oct -2646 */
301
+ {5, 824724.5}, /* 22 Dec -2455 */
302
+ {6, 762857.5}, /* 04 Aug -2624 */
303
+ {7, 773430.5}, /* 16 Jul -2595 */
304
+ {8, 810343.5}, /* 08 Aug -2494 */
305
+ {9, 807743.5}, /* 26 Jun -2501 */
306
+ {10, 824901.5}, /* 17 Jun -2454 */
307
+ {11, 855229.5}, /* 29 Jun -2371 */
308
+ {12, 859215.5}, /* 28 May -2360 */
309
+ {13, 876373.5}, /* 20 May -2313 */
310
+ {14, 906701.5}, /* 01 Jun -2230 */
311
+ {15, 910687.5}, /* 30 Apr -2219 */
312
+ {16, 927845.5}, /* 21 Apr -2172 */
313
+ {17, 958173.5}, /* 04 May -2089 */
314
+ {18, 962159.5}, /* 02 Apr -2078 */
315
+ {19, 979317.5}, /* 24 Mar -2031 */
316
+ {20, 1009645.5}, /* 05 Apr -1948 */
317
+ {21, 1007046.5}, /* 22 Feb -1955 */
318
+ {22, 1017618.5}, /* 02 Feb -1926 */
319
+ {23, 1054531.5}, /* 25 Feb -1825 */
320
+ {24, 979493.5}, /* 16 Sep -2031 */
321
+ {25, 976895.5}, /* 06 Aug -2038 */
322
+ {26, 1020394.5}, /* 09 Sep -1919 */
323
+ {27, 1017794.5}, /* 28 Jul -1926 */
324
+ {28, 1028367.5}, /* 09 Jul -1897 */
325
+ {29, 1058695.5}, /* 21 Jul -1814 */
326
+ {30, 1062681.5}, /* 19 Jun -1803 */
327
+ {31, 1073253.5}, /* 30 May -1774 */
328
+ {32, 1110167.5}, /* 23 Jun -1673 */
329
+ {33, 1114153.5}, /* 22 May -1662 */
330
+ {34, 1131311.5}, /* 13 May -1615 */
331
+ {35, 1161639.5}, /* 25 May -1532 */
332
+ {36, 1165625.5}, /* 24 Apr -1521 */
333
+ {37, 1176197.5}, /* 03 Apr -1492 */
334
+ {38, 1213111.5}, /* 27 Apr -1391 */
335
+ {39, 1217097.5}, /* 26 Mar -1380 */
336
+ {40, 1221084.5}, /* 24 Feb -1369 */
337
+ {41, 1257997.5}, /* 18 Mar -1268 */
338
+ {42, 1255398.5}, /* 04 Feb -1275 */
339
+ {43, 1186946.5}, /* 07 Sep -1463 */
340
+ {44, 1283128.5}, /* 06 Jan -1199 */
341
+ {45, 1227845.5}, /* 29 Aug -1351 */
342
+ {46, 1225247.5}, /* 19 Jul -1358 */
343
+ {47, 1255575.5}, /* 31 Jul -1275 */
344
+ {48, 1272732.5}, /* 21 Jul -1228 */
345
+ {49, 1276719.5}, /* 21 Jun -1217 */
346
+ {50, 1307047.5}, /* 03 Jul -1134 */
347
+ {51, 1317619.5}, /* 13 Jun -1105 */
348
+ {52, 1328191.5}, /* 23 May -1076 */
349
+ {53, 1358519.5}, /* 05 Jun -0993 */
350
+ {54, 1375676.5}, /* 26 May -0946 */
351
+ {55, 1379663.5}, /* 25 Apr -0935 */
352
+ {56, 1409991.5}, /* 07 May -0852 */
353
+ {57, 1420562.5}, /* 16 Apr -0823 */
354
+ {58, 1424549.5}, /* 16 Mar -0812 */
355
+ {59, 1461463.5}, /* 09 Apr -0711 */
356
+ {60, 1465449.5}, /* 08 Mar -0700 */
357
+ {61, 1436509.5}, /* 13 Dec -0780 */
358
+ {62, 1493179.5}, /* 08 Feb -0624 */
359
+ {63, 1457653.5}, /* 03 Nov -0722 */
360
+ {64, 1435298.5}, /* 20 Aug -0783 */
361
+ {65, 1452456.5}, /* 11 Aug -0736 */
362
+ {66, 1476198.5}, /* 12 Aug -0671 */
363
+ {67, 1480184.5}, /* 11 Jul -0660 */
364
+ {68, 1503928.5}, /* 14 Jul -0595 */
365
+ {69, 1527670.5}, /* 15 Jul -0530 */
366
+ {70, 1531656.5}, /* 13 Jun -0519 */
367
+ {71, 1548814.5}, /* 04 Jun -0472 */
368
+ {72, 1579142.5}, /* 17 Jun -0389 */
369
+ {73, 1583128.5}, /* 16 May -0378 */
370
+ {74, 1600286.5}, /* 07 May -0331 */
371
+ {75, 1624028.5}, /* 08 May -0266 */
372
+ {76, 1628015.5}, /* 07 Apr -0255 */
373
+ {77, 1651758.5}, /* 09 Apr -0190 */
374
+ {78, 1675500.5}, /* 10 Apr -0125 */
375
+ {79, 1672901.5}, /* 27 Feb -0132 */
376
+ {80, 1683474.5}, /* 07 Feb -0103 */
377
+ {81, 1713801.5}, /* 19 Feb -0020 */
378
+ {82, 1645349.5}, /* 21 Sep -0208 */
379
+ {83, 1649336.5}, /* 22 Aug -0197 */
380
+ {84, 1686249.5}, /* 13 Sep -0096 */
381
+ {85, 1683650.5}, /* 02 Aug -0103 */
382
+ {86, 1694222.5}, /* 13 Jul -0074 */
383
+ {87, 1731136.5}, /* 06 Aug 0027 */
384
+ {88, 1735122.5}, /* 05 Jul 0038 */
385
+ {89, 1745694.5}, /* 15 Jun 0067 */
386
+ {90, 1776022.5}, /* 27 Jun 0150 */
387
+ {91, 1786594.5}, /* 07 Jun 0179 */
388
+ {92, 1797166.5}, /* 17 May 0208 */
389
+ {93, 1827494.5}, /* 30 May 0291 */
390
+ {94, 1838066.5}, /* 09 May 0320 */
391
+ {95, 1848638.5}, /* 19 Apr 0349 */
392
+ {96, 1878966.5}, /* 01 May 0432 */
393
+ {97, 1882952.5}, /* 31 Mar 0443 */
394
+ {98, 1880354.5}, /* 18 Feb 0436 */
395
+ {99, 1923853.5}, /* 24 Mar 0555 */
396
+ {100, 1881741.5}, /* 06 Dec 0439 */
397
+ {101, 1852801.5}, /* 11 Sep 0360 */
398
+ {102, 1889715.5}, /* 05 Oct 0461 */
399
+ {103, 1893701.5}, /* 03 Sep 0472 */
400
+ {104, 1897688.5}, /* 04 Aug 0483 */
401
+ {105, 1928016.5}, /* 16 Aug 0566 */
402
+ {106, 1938588.5}, /* 27 Jul 0595 */
403
+ {107, 1942575.5}, /* 26 Jun 0606 */
404
+ {108, 1972903.5}, /* 08 Jul 0689 */
405
+ {109, 1990059.5}, /* 27 Jun 0736 */
406
+ {110, 1994046.5}, /* 28 May 0747 */
407
+ {111, 2024375.5}, /* 10 Jun 0830 */
408
+ {112, 2034946.5}, /* 20 May 0859 */
409
+ {113, 2045518.5}, /* 29 Apr 0888 */
410
+ {114, 2075847.5}, /* 13 May 0971 */
411
+ {115, 2086418.5}, /* 21 Apr 1000 */
412
+ {116, 2083820.5}, /* 11 Mar 0993 */
413
+ {117, 2120733.5}, /* 03 Apr 1094 */
414
+ {118, 2124719.5}, /* 02 Mar 1105 */
415
+ {119, 2062852.5}, /* 14 Oct 0935 */
416
+ {120, 2086596.5}, /* 16 Oct 1000 */
417
+ {121, 2103752.5}, /* 06 Oct 1047 */
418
+ {122, 2094568.5}, /* 14 Aug 1022 */
419
+ {123, 2118311.5}, /* 16 Aug 1087 */
420
+ {124, 2142054.5}, /* 17 Aug 1152 */
421
+ {125, 2146040.5}, /* 17 Jul 1163 */
422
+ {126, 2169783.5}, /* 18 Jul 1228 */
423
+ {127, 2186940.5}, /* 09 Jul 1275 */
424
+ {128, 2197512.5}, /* 18 Jun 1304 */
425
+ {129, 2214670.5}, /* 10 Jun 1351 */
426
+ {130, 2238412.5}, /* 10 Jun 1416 */
427
+ {131, 2242398.5}, /* 10 May 1427 */
428
+ {132, 2266142.5}, /* 12 May 1492 */
429
+ {133, 2289884.5}, /* 13 May 1557 */
430
+ {134, 2287285.5}, /* 01 Apr 1550 */
431
+ {135, 2311028.5}, /* 13 Apr 1615 */
432
+ {136, 2334770.5}, /* 13 Apr 1680 */
433
+ {137, 2292659.5}, /* 17 Dec 1564 */
434
+ {138, 2276890.5}, /* 15 Oct 1521 */
435
+ {139, 2326974.5}, /* 09 Dec 1658 */
436
+ {140, 2304619.5}, /* 25 Sep 1597 */
437
+ {141, 2308606.5}, /* 25 Aug 1608 */
438
+ {142, 2345520.5}, /* 19 Sep 1709 */
439
+ {143, 2349506.5}, /* 18 Aug 1720 */
440
+ {144, 2360078.5}, /* 29 Jul 1749 */
441
+ {145, 2390406.5}, /* 11 Aug 1832 */
442
+ {146, 2394392.5}, /* 11 Jul 1843 */
443
+ {147, 2411550.5}, /* 02 Jul 1890 */
444
+ {148, 2441878.5}, /* 15 Jul 1973 */
445
+ {149, 2445864.5}, /* 13 Jun 1984 */
446
+ {150, 2456437.5}, /* 25 May 2013 */
447
+ {151, 2486765.5}, /* 06 Jun 2096 */
448
+ {152, 2490751.5}, /* 07 May 2107 */
449
+ {153, 2501323.5}, /* 16 Apr 2136 */
450
+ {154, 2538236.5}, /* 10 May 2237 */
451
+ {155, 2529052.5}, /* 18 Mar 2212 */
452
+ {156, 2473771.5}, /* 08 Nov 2060 */
453
+ {157, 2563367.5}, /* 01 Mar 2306 */
454
+ {158, 2508085.5}, /* 21 Oct 2154 */
455
+ {159, 2505486.5}, /* 09 Sep 2147 */
456
+ {160, 2542400.5}, /* 03 Oct 2248 */
457
+ {161, 2546386.5}, /* 02 Sep 2259 */
458
+ {162, 2556958.5}, /* 12 Aug 2288 */
459
+ {163, 2587287.5}, /* 27 Aug 2371 */
460
+ {164, 2597858.5}, /* 05 Aug 2400 */
461
+ {165, 2601845.5}, /* 06 Jul 2411 */
462
+ {166, 2632173.5}, /* 18 Jul 2494 */
463
+ {167, 2649330.5}, /* 09 Jul 2541 */
464
+ {168, 2653317.5}, /* 08 Jun 2552 */
465
+ {169, 2683645.5}, /* 22 Jun 2635 */
466
+ {170, 2694217.5}, /* 01 Jun 2664 */
467
+ {171, 2698203.5}, /* 01 May 2675 */
468
+ {172, 2728532.5}, /* 15 May 2758 */
469
+ {173, 2739103.5}, /* 24 Apr 2787 */
470
+ {174, 2683822.5}, /* 16 Dec 2635 */
471
+ {175, 2740492.5}, /* 11 Feb 2791 */
472
+ {176, 2724722.5}, /* 09 Dec 2747 */
473
+ {177, 2708952.5}, /* 05 Oct 2704 */
474
+ {178, 2732695.5}, /* 07 Oct 2769 */
475
+ {179, 2749852.5}, /* 27 Sep 2816 */
476
+ {180, 2753839.5}, /* 28 Aug 2827 */
477
+ };
478
+
479
+ /* Computes geographic location and type of solar eclipse
480
+ * for a given tjd
481
+ * iflag: to indicate ephemeris to be used
482
+ * (SEFLG_JPLEPH, SEFLG_SWIEPH, SEFLG_MOSEPH)
483
+ *
484
+ * Algorithms for the central line is taken from Montenbruck, pp. 179ff.,
485
+ * with the exception, that we consider refraction for the maxima of
486
+ * partial and noncentral eclipses.
487
+ * Geographical positions are referred to sea level / the mean ellipsoid.
488
+ *
489
+ * Errors:
490
+ * - from uncertainty of JPL-ephemerides (0.01 arcsec):
491
+ * about 40 meters
492
+ * - from displacement of shadow points by atmospheric refraction:
493
+ * a few meters
494
+ * - from deviation of the geoid from the ellipsoid
495
+ * a few meters
496
+ * - from polar motion
497
+ * a few meters
498
+ * For geographical locations that are interesting for observation,
499
+ * the error is always < 100 m.
500
+ * However, if the sun is close to the horizon,
501
+ * all of these errors can grow up to a km or more.
502
+ *
503
+ * Function returns:
504
+ * -1 (ERR) on error (e.g. if swe_calc() for sun or moon fails)
505
+ * 0 if there is no solar eclipse at tjd
506
+ * SE_ECL_TOTAL
507
+ * SE_ECL_ANNULAR
508
+ * SE_ECL_TOTAL | SE_ECL_CENTRAL
509
+ * SE_ECL_TOTAL | SE_ECL_NONCENTRAL
510
+ * SE_ECL_ANNULAR | SE_ECL_CENTRAL
511
+ * SE_ECL_ANNULAR | SE_ECL_NONCENTRAL
512
+ * SE_ECL_PARTIAL
513
+ *
514
+ * geopos[0]: geographic longitude of central line
515
+ * geopos[1]: geographic latitude of central line
516
+ *
517
+ * not implemented so far:
518
+ *
519
+ * geopos[2]: geographic longitude of northern limit of umbra
520
+ * geopos[3]: geographic latitude of northern limit of umbra
521
+ * geopos[4]: geographic longitude of southern limit of umbra
522
+ * geopos[5]: geographic latitude of southern limit of umbra
523
+ * geopos[6]: geographic longitude of northern limit of penumbra
524
+ * geopos[7]: geographic latitude of northern limit of penumbra
525
+ * geopos[8]: geographic longitude of southern limit of penumbra
526
+ * geopos[9]: geographic latitude of southern limit of penumbra
527
+ *
528
+ * Attention: "northern" and "southern" limits of umbra do not
529
+ * necessarily correspond to the northernmost or southernmost
530
+ * geographic position, where the total, annular, or partial
531
+ * phase is visible at a given time.
532
+ * Imagine a situation in northern summer, when the sun illuminates
533
+ * the northern polar circle. The southernmost point of the core
534
+ * shadow may then touch the north pole, and therefore the
535
+ * northernmost point will be more in the south.
536
+ * Note also that with annular eclipses, the northern edge is
537
+ * usually geographically the southern one. With annular-total
538
+ * ones, the two lines cross, usually twice. The maximum is always
539
+ * total in such cases.
540
+ *
541
+ * attr[0] fraction of solar diameter covered by moon (magnitude)
542
+ * attr[1] ratio of lunar diameter to solar one
543
+ * attr[2] fraction of solar disc covered by moon (obscuration)
544
+ * attr[3] diameter of core shadow in km
545
+ * attr[4] azimuth of sun at tjd
546
+ * attr[5] true altitude of sun above horizon at tjd
547
+ * attr[6] apparent altitude of sun above horizon at tjd
548
+ * attr[7] angular distance of moon from sun in degrees
549
+ * declare as attr[20] at least !
550
+ */
551
+ int32 FAR PASCAL_CONV swe_sol_eclipse_where(
552
+ double tjd_ut,
553
+ int32 ifl,
554
+ double *geopos,
555
+ double *attr,
556
+ char *serr)
557
+ {
558
+ int32 retflag, retflag2;
559
+ double dcore[10];
560
+ ifl &= SEFLG_EPHMASK;
561
+ if ((retflag = eclipse_where(tjd_ut, SE_SUN, NULL, ifl, geopos, dcore, serr)) < 0)
562
+ return retflag;
563
+ if ((retflag2 = eclipse_how(tjd_ut, SE_SUN, NULL, ifl, geopos[0], geopos[1], 0, attr, serr)) == ERR)
564
+ return retflag2;
565
+ attr[3] = dcore[0];
566
+ return retflag;
567
+ }
568
+
569
+ int32 FAR PASCAL_CONV swe_lun_occult_where(
570
+ double tjd_ut,
571
+ int32 ipl,
572
+ char *starname,
573
+ int32 ifl,
574
+ double *geopos,
575
+ double *attr,
576
+ char *serr)
577
+ {
578
+ int32 retflag, retflag2;
579
+ double dcore[10];
580
+ ifl &= SEFLG_EPHMASK;
581
+ /* function calls for Pluto with asteroid number 134340
582
+ * are treated as calls for Pluto as main body SE_PLUTO */
583
+ if (ipl == SE_AST_OFFSET + 134340)
584
+ ipl = SE_PLUTO;
585
+ if ((retflag = eclipse_where(tjd_ut, ipl, starname, ifl, geopos, dcore, serr)) < 0)
586
+ return retflag;
587
+ if ((retflag2 = eclipse_how(tjd_ut, ipl, starname, ifl, geopos[0], geopos[1], 0, attr, serr)) == ERR)
588
+ return retflag2;
589
+ attr[3] = dcore[0];
590
+ return retflag;
591
+ }
592
+
593
+ /* Used by several swe_sol_eclipse_ functions.
594
+ * Like swe_sol_eclipse_where(), but instead of attr[0], it returns:
595
+ *
596
+ * dcore[0]: core shadow width in km
597
+ * dcore[2]: distance of shadow axis from geocenter r0
598
+ * dcore[3]: diameter of core shadow on fundamental plane d0
599
+ * dcore[4]: diameter of half-shadow on fundamental plane D0
600
+ */
601
+ static int32 eclipse_where( double tjd_ut, int32 ipl, char *starname, int32 ifl, double *geopos, double *dcore,
602
+ char *serr)
603
+ {
604
+ int i;
605
+ int32 retc = 0, niter = 0;
606
+ double e[6], et[6], erm[6], rm[6], rs[6], rmt[6], rst[6], xs[6], xst[6];
607
+ double xssv[16], x[6];
608
+ double lm[6], ls[6], lx[6];
609
+ double dsm, dsmt, d0, D0, s0, r0, d, s, dm;
610
+ double de = 6378140.0 / AUNIT;
611
+ double earthobl = 1 - EARTH_OBLATENESS;
612
+ double deltat, tjd, sidt;
613
+ double drad;
614
+ double sinf1, sinf2, cosf1, cosf2;
615
+ int32 iflag, iflag2;
616
+ /* double ecce = sqrt(2 * EARTH_OBLATENESS - EARTH_OBLATENESS * EARTH_OBLATENESS); */
617
+ AS_BOOL no_eclipse = FALSE;
618
+ struct epsilon *oe = &swed.oec;
619
+ for (i = 0; i < 10; i++)
620
+ dcore[i] = 0;
621
+ /* nutation need not be in lunar and solar positions,
622
+ * if mean sidereal time will be used */
623
+ iflag = SEFLG_SPEED | SEFLG_EQUATORIAL | ifl;
624
+ iflag2 = iflag | SEFLG_RADIANS;
625
+ iflag = iflag | SEFLG_XYZ;
626
+ deltat = swe_deltat(tjd_ut);
627
+ tjd = tjd_ut + deltat;
628
+ /* moon in cartesian coordinates */
629
+ if ((retc = swe_calc(tjd, SE_MOON, iflag, rm, serr)) == ERR)
630
+ return retc;
631
+ /* moon in polar coordinates */
632
+ if ((retc = swe_calc(tjd, SE_MOON, iflag2, lm, serr)) == ERR)
633
+ return retc;
634
+ /* sun in cartesian coordinates */
635
+ if ((retc = calc_planet_star(tjd, ipl, starname, iflag, rs, serr)) == ERR)
636
+ return retc;
637
+ /* sun in polar coordinates */
638
+ if ((retc = calc_planet_star(tjd, ipl, starname, iflag2, ls, serr)) == ERR)
639
+ return retc;
640
+ /* save sun position */
641
+ for (i = 0; i <= 2; i++)
642
+ rst[i] = rs[i];
643
+ /* save moon position */
644
+ for (i = 0; i <= 2; i++)
645
+ rmt[i] = rm[i];
646
+ if (iflag & SEFLG_NONUT)
647
+ sidt = swe_sidtime0(tjd_ut, oe->eps * RADTODEG, 0) * 15 * DEGTORAD;
648
+ else
649
+ sidt = swe_sidtime(tjd_ut) * 15 * DEGTORAD;
650
+ /*
651
+ * radius of planet disk in AU
652
+ */
653
+ if (starname != NULL && *starname != '\0')
654
+ drad = 0;
655
+ else if (ipl < NDIAM)
656
+ drad = pla_diam[ipl] / 2 / AUNIT;
657
+ else if (ipl > SE_AST_OFFSET)
658
+ drad = swed.ast_diam / 2 * 1000 / AUNIT; /* km -> m -> AU */
659
+ else
660
+ drad = 0;
661
+ iter_where:
662
+ for (i = 0; i <= 2; i++) {
663
+ rs[i] = rst[i];
664
+ rm[i] = rmt[i];
665
+ }
666
+ /* Account for oblateness of earth:
667
+ * Instead of flattening the earth, we apply the
668
+ * correction to the z coordinate of the moon and
669
+ * the sun. This makes the calculation easier.
670
+ */
671
+ for (i = 0; i <= 2; i++)
672
+ lx[i] = lm[i];
673
+ swi_polcart(lx, rm);
674
+ rm[2] /= earthobl;
675
+ /* distance of moon from geocenter */
676
+ dm = sqrt(square_sum(rm));
677
+ /* Account for oblateness of earth */
678
+ for (i = 0; i <= 2; i++)
679
+ lx[i] = ls[i];
680
+ swi_polcart(lx, rs);
681
+ rs[2] /= earthobl;
682
+ /* sun - moon vector */
683
+ for (i = 0; i <= 2; i++) {
684
+ e[i] = (rm[i] - rs[i]);
685
+ et[i] = (rmt[i] - rst[i]);
686
+ }
687
+ /* distance sun - moon */
688
+ dsm = sqrt(square_sum(e));
689
+ dsmt = sqrt(square_sum(et));
690
+ /* sun - moon unit vector */
691
+ for (i = 0; i <= 2; i++) {
692
+ e[i] /= dsm;
693
+ et[i] /= dsmt;
694
+ erm[i] = rm[i] / dm;
695
+ }
696
+ sinf1 = ((drad - RMOON) / dsm);
697
+ cosf1 = sqrt(1 - sinf1 * sinf1);
698
+ sinf2 = ((drad + RMOON) / dsm);
699
+ cosf2 = sqrt(1 - sinf2 * sinf2);
700
+ /* distance of moon from fundamental plane */
701
+ s0 = -dot_prod(rm, e);
702
+ /* distance of shadow axis from geocenter */
703
+ r0 = sqrt(dm * dm - s0 * s0);
704
+ /* diameter of core shadow on fundamental plane */
705
+ d0 = (s0 / dsm * (drad * 2 - DMOON) - DMOON) / cosf1;
706
+ /* diameter of half-shadow on fundamental plane */
707
+ D0 = (s0 / dsm * (drad * 2 + DMOON) + DMOON) / cosf2;
708
+ dcore[2] = r0;
709
+ dcore[3] = d0;
710
+ dcore[4] = D0;
711
+ dcore[5] = cosf1;
712
+ dcore[6] = cosf2;
713
+ for (i = 2; i < 5; i++)
714
+ dcore[i] *= AUNIT / 1000.0;
715
+ /**************************
716
+ * central (total or annular) phase
717
+ **************************/
718
+ retc = 0;
719
+ if (de * cosf1 >= r0) {
720
+ retc |= SE_ECL_CENTRAL;
721
+ } else if (r0 <= de * cosf1 + fabs(d0) / 2) {
722
+ retc |= SE_ECL_NONCENTRAL;
723
+ } else if (r0 <= de * cosf2 + D0 / 2) {
724
+ retc |= (SE_ECL_PARTIAL | SE_ECL_NONCENTRAL);
725
+ } else {
726
+ if (serr != NULL)
727
+ sprintf(serr, "no solar eclipse at tjd = %f", tjd);
728
+ for (i = 0; i < 10; i++)
729
+ geopos[i] = 0;
730
+ *dcore = 0;
731
+ retc = 0;
732
+ d = 0;
733
+ no_eclipse = TRUE;
734
+ /*return retc;*/
735
+ }
736
+ /* distance of shadow point from fundamental plane */
737
+ d = s0 * s0 + de * de - dm * dm;
738
+ if (d > 0)
739
+ d = sqrt(d);
740
+ else
741
+ d = 0;
742
+ /* distance of moon from shadow point on earth */
743
+ s = s0 - d;
744
+ /* next: geographic position of eclipse center.
745
+ * if shadow axis does not touch the earth,
746
+ * place on earth with maximum occultation is computed.
747
+ */
748
+ #if 0 /* the following stuff is meaningless for observations */
749
+ /*
750
+ * account for refraction at horizon
751
+ */
752
+ if (d == 0) {
753
+ double ds, a, b;
754
+ /* distance of sun from geocenter */
755
+ ds = sqrt(square_sum(rs));
756
+ a = PI - acos(swi_dot_prod_unit(e, erm));
757
+ /* refraction at horizon + sun radius = about 0.83 degrees */
758
+ b = 34.4556 / 60.0 * DEGTORAD + asin(drad / ds);
759
+ # if 0
760
+ /* at edge of umbra and penumbra
761
+ * light rays are not parallel to shadow axis.
762
+ * for a short time close to contact of umbra and
763
+ * penumbra, an angle < 0.27 degrees would have
764
+ * to be subtracted from b;
765
+ */
766
+ if (retc & SE_ECL_PARTIAL) {
767
+ d = d0;
768
+ sinf = sinf1;
769
+ } else {
770
+ d = D0;
771
+ sinf = sinf2;
772
+ }
773
+ c = (r0 - de) / d * 2 * sinf;
774
+ if (c > sinf1) {
775
+ b -= .....;
776
+ }
777
+ printf("%f %f %f", a * RADTODEG, b * RADTODEG, s);
778
+ printf(" %f\n", s);
779
+ # else
780
+ if (retc & SE_ECL_PARTIAL)
781
+ b -= asin(sinf2); /* maximum! */
782
+ else
783
+ b -= asin(sinf1);
784
+ # endif
785
+ s += tan(b) * cos(PI / 2 - a) * dm;
786
+ }
787
+ #endif
788
+ /* geographic position of eclipse center (maximum) */
789
+ for (i = 0; i <= 2; i++)
790
+ xs[i] = rm[i] + s * e[i];
791
+ /* we need geographic position with correct z, as well */
792
+ for (i = 0; i <= 2; i++)
793
+ xst[i] = xs[i];
794
+ xst[2] *= earthobl;
795
+ swi_cartpol(xst, xst);
796
+ if (niter <= 0) {
797
+ double cosfi = cos(xst[1]);
798
+ double sinfi = sin(xst[1]);
799
+ double eobl = EARTH_OBLATENESS;
800
+ double cc= 1 / sqrt(cosfi * cosfi + (1-eobl) * (1-eobl) * sinfi * sinfi);
801
+ double ss= (1-eobl) * (1-eobl) * cc;
802
+ earthobl = ss;
803
+ niter++;
804
+ goto iter_where;
805
+ }
806
+ swi_polcart(xst, xst);
807
+ /* to longitude and latitude */
808
+ swi_cartpol(xs, xs);
809
+ /* measure from sidereal time at greenwich */
810
+ xs[0] -= sidt;
811
+ xs[0] *= RADTODEG;
812
+ xs[1] *= RADTODEG;
813
+ xs[0] = swe_degnorm(xs[0]);
814
+ /* west is negative */
815
+ if (xs[0] > 180)
816
+ xs[0] -= 360;
817
+ xssv[0] = xs[0];
818
+ xssv[1] = xs[1];
819
+ geopos[0] = xs[0];
820
+ geopos[1] = xs[1];
821
+ /* diameter of core shadow:
822
+ * first, distance moon - place of eclipse on earth */
823
+ for (i = 0; i <= 2; i++)
824
+ x[i] = rmt[i] - xst[i];
825
+ s = sqrt(square_sum(x));
826
+ /* diameter of core shadow at place of maximum eclipse */
827
+ *dcore = (s / dsmt * ( drad * 2 - DMOON) - DMOON) * cosf1;
828
+ *dcore *= AUNIT / 1000.0;
829
+ /* diameter of penumbra at place of maximum eclipse */
830
+ dcore[1] = (s / dsmt * ( drad * 2 + DMOON) + DMOON) * cosf2;
831
+ dcore[1] *= AUNIT / 1000.0;
832
+ if (!(retc & SE_ECL_PARTIAL) && !no_eclipse) {
833
+ if (*dcore > 0) {
834
+ /*printf("annular\n");*/
835
+ retc |= SE_ECL_ANNULAR;
836
+ } else {
837
+ /*printf("total\n");*/
838
+ retc |= SE_ECL_TOTAL;
839
+ }
840
+ }
841
+ return retc;
842
+ }
843
+
844
+ static int32 calc_planet_star(double tjd_et, int32 ipl, char *starname, int32 iflag, double *x, char *serr)
845
+ {
846
+ int i;
847
+ int retc = OK;
848
+ if (starname == NULL || *starname == '\0') {
849
+ retc = swe_calc(tjd_et, ipl, iflag, x, serr);
850
+ } else {
851
+ if ((retc = swe_fixstar(starname, tjd_et, iflag, x, serr)) == OK) {
852
+ /* fixstars have the standard distance 1.
853
+ * in the occultation routines, this might lead to errors
854
+ * if interpreted as AU distance. To avoid this, we make it very high.
855
+ */
856
+ if (iflag & SEFLG_XYZ) {
857
+ for (i = 0; i < 3; i++)
858
+ x[i] *= 100000000;
859
+ } else {
860
+ x[2] *= 100000000;
861
+ }
862
+ }
863
+ }
864
+ return retc;
865
+ }
866
+
867
+ /* Computes attributes of a solar eclipse for given tjd, geo. longitude,
868
+ * geo. latitude, and geo. height.
869
+ *
870
+ * retflag SE_ECL_TOTAL or SE_ECL_ANNULAR or SE_ECL_PARTIAL
871
+ * SE_ECL_NONCENTRAL
872
+ * if 0, no eclipse is visible at geogr. position.
873
+ *
874
+ * attr[0] fraction of solar diameter covered by moon
875
+ * attr[1] ratio of lunar diameter to solar one
876
+ * attr[2] fraction of solar disc covered by moon (obscuration)
877
+ * attr[3] diameter of core shadow in km
878
+ * attr[4] azimuth of sun at tjd
879
+ * attr[5] true altitude of sun above horizon at tjd
880
+ * attr[6] apparent altitude of sun above horizon at tjd
881
+ * attr[7] elongation of moon in degrees
882
+ * attr[8] magnitude (= attr[0] or attr[1] depending on eclipse type)
883
+ * attr[9] saros series number
884
+ * attr[10] saros series member number
885
+ * declare as attr[20] at least !
886
+ *
887
+ */
888
+ int32 FAR PASCAL_CONV swe_sol_eclipse_how(
889
+ double tjd_ut,
890
+ int32 ifl,
891
+ double *geopos,
892
+ double *attr,
893
+ char *serr)
894
+ {
895
+ int32 retflag, retflag2;
896
+ double dcore[10];
897
+ double geopos2[20];
898
+ ifl &= SEFLG_EPHMASK;
899
+ if ((retflag = eclipse_how(tjd_ut, SE_SUN, NULL, ifl, geopos[0], geopos[1], geopos[2], attr, serr)) == ERR)
900
+ return retflag;
901
+ if ((retflag2 = eclipse_where(tjd_ut, SE_SUN, NULL, ifl, geopos2, dcore, serr)) == ERR)
902
+ return retflag2;
903
+ if (retflag)
904
+ retflag |= (retflag2 & (SE_ECL_CENTRAL | SE_ECL_NONCENTRAL));
905
+ attr[3] = dcore[0];
906
+ return retflag;
907
+ }
908
+
909
+ static int32 eclipse_how( double tjd_ut, int32 ipl, char *starname, int32 ifl,
910
+ double geolon, double geolat, double geohgt,
911
+ double *attr, char *serr)
912
+ {
913
+ int i, j, k;
914
+ int32 retc = 0;
915
+ double te, d;
916
+ double xs[6], xm[6], ls[6], lm[6], x1[6], x2[6];
917
+ double rmoon, rsun, rsplusrm, rsminusrm;
918
+ double dctr;
919
+ double drad;
920
+ int32 iflag = SEFLG_EQUATORIAL | SEFLG_TOPOCTR | ifl;
921
+ int32 iflagcart = iflag | SEFLG_XYZ;
922
+ double mdd, eps, sidt, armc, xh[6], hmin_appr;
923
+ double lsun, lmoon, lctr, lsunleft, a, b, sc1, sc2;
924
+ for (i = 0; i < 10; i++)
925
+ attr[i] = 0;
926
+ te = tjd_ut + swe_deltat(tjd_ut);
927
+ swe_set_topo(geolon, geolat, geohgt);
928
+ if (calc_planet_star(te, ipl, starname, iflag, ls, serr) == ERR)
929
+ return ERR;
930
+ if (swe_calc(te, SE_MOON, iflag, lm, serr) == ERR)
931
+ return ERR;
932
+ if (calc_planet_star(te, ipl, starname, iflagcart, xs, serr) == ERR)
933
+ return ERR;
934
+ if (swe_calc(te, SE_MOON, iflagcart, xm, serr) == ERR)
935
+ return ERR;
936
+ /*
937
+ * radius of planet disk in AU
938
+ */
939
+ if (starname != NULL && *starname != '\0')
940
+ drad = 0;
941
+ else if (ipl < NDIAM)
942
+ drad = pla_diam[ipl] / 2 / AUNIT;
943
+ else if (ipl > SE_AST_OFFSET)
944
+ drad = swed.ast_diam / 2 * 1000 / AUNIT; /* km -> m -> AU */
945
+ else
946
+ drad = 0;
947
+ /*
948
+ * azimuth and altitude of sun or planet
949
+ */
950
+ eps = swi_epsiln(te);
951
+ if (iflag & SEFLG_NONUT)
952
+ sidt = swe_sidtime0(tjd_ut, eps * RADTODEG, 0) * 15;
953
+ else
954
+ sidt = swe_sidtime(tjd_ut) * 15;
955
+ armc = sidt + geolon;
956
+ mdd = swe_degnorm(ls[0] - armc);
957
+ xh[0] = swe_degnorm(mdd - 90);
958
+ xh[1] = ls[1];
959
+ xh[2] = ls[2];
960
+ swe_cotrans(xh, xh, 90 - geolat); /* azimuth from east, counterclock */
961
+ /* eclipse description */
962
+ rmoon = asin(RMOON / lm[2]) * RADTODEG;
963
+ rsun = asin(drad / ls[2]) * RADTODEG;
964
+ rsplusrm = rsun + rmoon;
965
+ rsminusrm = rsun - rmoon;
966
+ for (i = 0; i < 3; i++) {
967
+ x1[i] = xs[i] / ls[2];
968
+ x2[i] = xm[i] / lm[2];
969
+ }
970
+ dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
971
+ /*
972
+ * phase
973
+ */
974
+ if (dctr < rsminusrm)
975
+ retc = SE_ECL_ANNULAR;
976
+ else if (dctr < fabs(rsminusrm))
977
+ retc = SE_ECL_TOTAL;
978
+ else if (dctr < rsplusrm)
979
+ retc = SE_ECL_PARTIAL;
980
+ else {
981
+ retc = 0;
982
+ if (serr != NULL)
983
+ sprintf(serr, "no solar eclipse at tjd = %f", tjd_ut);
984
+ }
985
+ /*
986
+ * percentage of eclipse
987
+ */
988
+ #if 0
989
+ attr[0] = (rsplusrm - dctr) / rsun / 2 * 100;
990
+ #else
991
+ /*
992
+ * eclipse magnitude:
993
+ * fraction of solar diameter covered by moon
994
+ */
995
+ lsun = asin(rsun / 2 * DEGTORAD) * 2;
996
+ #if 0
997
+ lmoon = asin(rmoon / 2 * DEGTORAD) * 2;
998
+ lctr = asin(dctr / 2 * DEGTORAD) * 2;
999
+ #endif
1000
+ lsunleft = (-dctr + rsun + rmoon);
1001
+ if (lsun > 0) {
1002
+ attr[0] = lsunleft / rsun / 2;
1003
+ } else {
1004
+ attr[0] = 100;
1005
+ }
1006
+ /*
1007
+ * ratio of diameter of moon to that of sun
1008
+ */
1009
+ if (rsun > 0)
1010
+ attr[1] = rmoon / rsun;
1011
+ else
1012
+ attr[1] = 0;
1013
+ /*
1014
+ * obscuration:
1015
+ * fraction of solar disc obscured by moon
1016
+ */
1017
+ lsun = rsun;
1018
+ lmoon = rmoon;
1019
+ lctr = dctr;
1020
+ if (retc == 0 || lsun == 0)
1021
+ attr[2] = 100;
1022
+ else if (retc == SE_ECL_TOTAL || retc == SE_ECL_ANNULAR)
1023
+ attr[2] = lmoon * lmoon / lsun / lsun;
1024
+ else {
1025
+ a = 2 * lctr * lmoon;
1026
+ b = 2 * lctr * lsun;
1027
+ if (a < 1e-9) {
1028
+ attr[2] = lmoon * lmoon / lsun / lsun;
1029
+ } else {
1030
+ a = (lctr * lctr + lmoon * lmoon - lsun * lsun) / a;
1031
+ if (a > 1) a = 1;
1032
+ if (a < -1) a = -1;
1033
+ b = (lctr * lctr + lsun * lsun - lmoon * lmoon) / b;
1034
+ if (b > 1) b = 1;
1035
+ if (b < -1) b = -1;
1036
+ a = acos(a);
1037
+ b = acos(b);
1038
+ sc1 = a * lmoon * lmoon / 2;
1039
+ sc2 = b * lsun * lsun / 2;
1040
+ sc1 -= (cos(a) * sin(a)) * lmoon * lmoon / 2;
1041
+ sc2 -= (cos(b) * sin(b)) * lsun * lsun / 2;
1042
+ attr[2] = (sc1 + sc2) * 2 / PI / lsun / lsun;
1043
+ }
1044
+ }
1045
+ #endif
1046
+ attr[7] = dctr;
1047
+ /* approximate minimum height for visibility, considering
1048
+ * refraction and dip
1049
+ * 34.4556': refraction at horizon, from Bennets formulae
1050
+ * 1.75' / sqrt(geohgt): dip of horizon
1051
+ * 0.37' / sqrt(geohgt): refraction between horizon and observer */
1052
+ hmin_appr = -(34.4556 + (1.75 + 0.37) * sqrt(geohgt)) / 60;
1053
+ if (xh[1] + rsun + fabs(hmin_appr) >= 0 && retc)
1054
+ retc |= SE_ECL_VISIBLE; /* eclipse visible */
1055
+ attr[4] = swe_degnorm(90 - xh[0]); /* azimuth, from north, clockwise */
1056
+ attr[5] = xh[1]; /* height */
1057
+ if (ipl == SE_SUN && (starname == NULL || *starname == '\0')) {
1058
+ /* magnitude of solar eclipse */
1059
+ attr[8] = attr[0]; /* fraction of diameter occulted */
1060
+ if (retc & (SE_ECL_TOTAL | SE_ECL_ANNULAR))
1061
+ attr[8] = attr[1]; /* ration between diameters of sun and moon */
1062
+ /* saros series and member */
1063
+ for (i = 0; i < NSAROS_SOLAR; i++) {
1064
+ d = (tjd_ut - saros_data_solar[i].tstart) / SAROS_CYCLE;
1065
+ if (d < 0) continue;
1066
+ j = (int) d;
1067
+ if ((d - j) * SAROS_CYCLE < 2) {
1068
+ attr[9] = (double) saros_data_solar[i].series_no;
1069
+ attr[10] = (double) j + 1;
1070
+ break;
1071
+ }
1072
+ k = j + 1;
1073
+ if ((k - d) * SAROS_CYCLE < 2) {
1074
+ attr[9] = (double) saros_data_solar[i].series_no;
1075
+ attr[10] = (double) k + 1;
1076
+ break;
1077
+ }
1078
+ }
1079
+ if (i == NSAROS_SOLAR) {
1080
+ attr[9] = attr[10] = -99999999;
1081
+ }
1082
+ }
1083
+ return retc;
1084
+ }
1085
+
1086
+ /* When is the next solar eclipse anywhere on earth?
1087
+ *
1088
+ * input parameters:
1089
+ *
1090
+ * tjd_start start time for search (UT)
1091
+ * ifl ephemeris to be used (SEFLG_SWIEPH, etc.)
1092
+ * ifltype eclipse type to be searched (SE_ECL_TOTAL, etc.)
1093
+ * 0, if any type of eclipse is wanted
1094
+ *
1095
+ * return values:
1096
+ *
1097
+ * retflag SE_ECL_TOTAL or SE_ECL_ANNULAR or SE_ECL_PARTIAL
1098
+ * or SE_ECL_ANNULAR_TOTAL
1099
+ * SE_ECL_CENTRAL
1100
+ * SE_ECL_NONCENTRAL
1101
+ *
1102
+ * tret[0] time of maximum eclipse
1103
+ * tret[1] time, when eclipse takes place at local apparent noon
1104
+ * tret[2] time of eclipse begin
1105
+ * tret[3] time of eclipse end
1106
+ * tret[4] time of totality begin
1107
+ * tret[5] time of totality end
1108
+ * tret[6] time of center line begin
1109
+ * tret[7] time of center line end
1110
+ * tret[8] time when annular-total eclipse becomes total
1111
+ * not implemented so far
1112
+ * tret[9] time when annular-total eclipse becomes annular again
1113
+ * not implemented so far
1114
+ * declare as tret[10] at least!
1115
+ *
1116
+ */
1117
+ int32 FAR PASCAL_CONV swe_sol_eclipse_when_glob(double tjd_start, int32 ifl, int32 ifltype,
1118
+ double *tret, int32 backward, char *serr)
1119
+ {
1120
+ int i, j, k, m, n, o, i1 = 0, i2 = 0;
1121
+ int32 retflag = 0, retflag2 = 0;
1122
+ double de = 6378.140, a;
1123
+ double t, tt, tjd, tjds, dt, dtint, dta, dtb;
1124
+ double T, T2, T3, T4, K, M, Mm;
1125
+ double E, Ff;
1126
+ double xs[6], xm[6], ls[6], lm[6];
1127
+ double rmoon, rsun, dcore[10];
1128
+ double dc[3], dctr;
1129
+ double twohr = 2.0 / 24.0;
1130
+ double tenmin = 10.0 / 24.0 / 60.0;
1131
+ double dt1, dt2;
1132
+ double geopos[20], attr[20];
1133
+ double dtstart, dtdiv;
1134
+ double xa[6], xb[6];
1135
+ int direction = 1;
1136
+ AS_BOOL dont_times = FALSE;
1137
+ int32 iflag, iflagcart;
1138
+ ifl &= SEFLG_EPHMASK;
1139
+ iflag = SEFLG_EQUATORIAL | ifl;
1140
+ iflagcart = iflag | SEFLG_XYZ;
1141
+ if (ifltype == (SE_ECL_PARTIAL | SE_ECL_CENTRAL)) {
1142
+ if (serr != NULL)
1143
+ strcpy(serr, "central partial eclipses do not exist");
1144
+ return ERR;
1145
+ }
1146
+ if (ifltype == 0)
1147
+ ifltype = SE_ECL_TOTAL | SE_ECL_ANNULAR | SE_ECL_PARTIAL
1148
+ | SE_ECL_ANNULAR_TOTAL | SE_ECL_NONCENTRAL | SE_ECL_CENTRAL;
1149
+ if (backward)
1150
+ direction = -1;
1151
+ K = (int) ((tjd_start - J2000) / 365.2425 * 12.3685);
1152
+ K -= direction;
1153
+ next_try:
1154
+ retflag = 0;
1155
+ dont_times = FALSE;
1156
+ for (i = 0; i <= 9; i++)
1157
+ tret[i] = 0;
1158
+ T = K / 1236.85;
1159
+ T2 = T * T; T3 = T2 * T; T4 = T3 * T;
1160
+ Ff = swe_degnorm(160.7108 + 390.67050274 * K
1161
+ - 0.0016341 * T2
1162
+ - 0.00000227 * T3
1163
+ + 0.000000011 * T4);
1164
+ if (Ff > 180)
1165
+ Ff -= 180;
1166
+ if (Ff > 21 && Ff < 159) { /* no eclipse possible */
1167
+ K += direction;
1168
+ goto next_try;
1169
+ }
1170
+ /* approximate time of geocentric maximum eclipse
1171
+ * formula from Meeus, German, p. 381 */
1172
+ tjd = 2451550.09765 + 29.530588853 * K
1173
+ + 0.0001337 * T2
1174
+ - 0.000000150 * T3
1175
+ + 0.00000000073 * T4;
1176
+ M = swe_degnorm(2.5534 + 29.10535669 * K
1177
+ - 0.0000218 * T2
1178
+ - 0.00000011 * T3);
1179
+ Mm = swe_degnorm(201.5643 + 385.81693528 * K
1180
+ + 0.1017438 * T2
1181
+ + 0.00001239 * T3
1182
+ + 0.000000058 * T4);
1183
+ E = 1 - 0.002516 * T - 0.0000074 * T2;
1184
+ M *= DEGTORAD;
1185
+ Mm *= DEGTORAD;
1186
+ tjd = tjd - 0.4075 * sin(Mm)
1187
+ + 0.1721 * E * sin(M);
1188
+ /*
1189
+ * time of maximum eclipse (if eclipse) =
1190
+ * minimum geocentric angle between sun and moon edges.
1191
+ * After this time has been determined, check
1192
+ * whether or not an eclipse is taking place with
1193
+ * the functions eclipse_where() and _how().
1194
+ */
1195
+ dtstart = 1;
1196
+ if (tjd < 2000000)
1197
+ dtstart = 5;
1198
+ dtdiv = 4;
1199
+ for (dt = dtstart;
1200
+ dt > 0.0001;
1201
+ dt /= dtdiv) {
1202
+ for (i = 0, t = tjd - dt; i <= 2; i++, t += dt) {
1203
+ if (swe_calc(t, SE_SUN, iflag, ls, serr) == ERR)
1204
+ return ERR;
1205
+ if (swe_calc(t, SE_MOON, iflag, lm, serr) == ERR)
1206
+ return ERR;
1207
+ if (swe_calc(t, SE_SUN, iflagcart, xs, serr) == ERR)
1208
+ return ERR;
1209
+ if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
1210
+ return ERR;
1211
+ for (m = 0; m < 3; m++) {
1212
+ xa[m] = xs[m] / ls[2];
1213
+ xb[m] = xm[m] / lm[2];
1214
+ }
1215
+ dc[i] = acos(swi_dot_prod_unit(xa, xb)) * RADTODEG;
1216
+ rmoon = asin(RMOON / lm[2]) * RADTODEG;
1217
+ rsun = asin(RSUN / ls[2]) * RADTODEG;
1218
+ dc[i] -= (rmoon + rsun);
1219
+ }
1220
+ find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dctr);
1221
+ tjd += dtint + dt;
1222
+ }
1223
+ tjds = tjd = tjd - swe_deltat(tjd);
1224
+ if ((retflag = eclipse_where(tjd, SE_SUN, NULL, ifl, geopos, dcore, serr)) == ERR)
1225
+ return retflag;
1226
+ retflag2 = retflag;
1227
+ /* in extreme cases _where() returns no eclipse, where there is
1228
+ * actually a very small one, therefore call _how() with the
1229
+ * coordinates returned by _where(): */
1230
+ if ((retflag2 = eclipse_how(tjd, SE_SUN, NULL, ifl, geopos[0], geopos[1], 0, attr, serr)) == ERR)
1231
+ return retflag2;
1232
+ if (retflag2 == 0) {
1233
+ K += direction;
1234
+ goto next_try;
1235
+ }
1236
+ tret[0] = tjd;
1237
+ if ((backward && tret[0] >= tjd_start - 0.0001)
1238
+ || (!backward && tret[0] <= tjd_start + 0.0001)) {
1239
+ K += direction;
1240
+ goto next_try;
1241
+ }
1242
+ /*
1243
+ * eclipse type, SE_ECL_TOTAL, _ANNULAR, etc.
1244
+ * SE_ECL_ANNULAR_TOTAL will be discovered later
1245
+ */
1246
+ if ((retflag = eclipse_where(tjd, SE_SUN, NULL, ifl, geopos, dcore, serr)) == ERR)
1247
+ return retflag;
1248
+ if (retflag == 0) { /* can happen with extremely small percentage */
1249
+ retflag = SE_ECL_PARTIAL | SE_ECL_NONCENTRAL;
1250
+ tret[4] = tret[5] = tjd; /* fix this ???? */
1251
+ dont_times = TRUE;
1252
+ }
1253
+ /*
1254
+ * check whether or not eclipse type found is wanted
1255
+ */
1256
+ /* non central eclipse is wanted: */
1257
+ if (!(ifltype & SE_ECL_NONCENTRAL) && (retflag & SE_ECL_NONCENTRAL)) {
1258
+ K += direction;
1259
+ goto next_try;
1260
+ }
1261
+ /* central eclipse is wanted: */
1262
+ if (!(ifltype & SE_ECL_CENTRAL) && (retflag & SE_ECL_CENTRAL)) {
1263
+ K += direction;
1264
+ goto next_try;
1265
+ }
1266
+ /* non annular eclipse is wanted: */
1267
+ if (!(ifltype & SE_ECL_ANNULAR) && (retflag & SE_ECL_ANNULAR)) {
1268
+ K += direction;
1269
+ goto next_try;
1270
+ }
1271
+ /* non partial eclipse is wanted: */
1272
+ if (!(ifltype & SE_ECL_PARTIAL) && (retflag & SE_ECL_PARTIAL)) {
1273
+ K += direction;
1274
+ goto next_try;
1275
+ }
1276
+ /* annular-total eclipse will be discovered later */
1277
+ if (!(ifltype & (SE_ECL_TOTAL | SE_ECL_ANNULAR_TOTAL)) && (retflag & SE_ECL_TOTAL)) {
1278
+ K += direction;
1279
+ goto next_try;
1280
+ }
1281
+ if (dont_times)
1282
+ goto end_search_global;
1283
+ /*
1284
+ * n = 0: times of eclipse begin and end
1285
+ * n = 1: times of totality begin and end
1286
+ * n = 2: times of center line begin and end
1287
+ */
1288
+ if (retflag & SE_ECL_PARTIAL)
1289
+ o = 0;
1290
+ else if (retflag & SE_ECL_NONCENTRAL)
1291
+ o = 1;
1292
+ else
1293
+ o = 2;
1294
+ dta = twohr;
1295
+ dtb = tenmin / 3.0;
1296
+ for (n = 0; n <= o; n++) {
1297
+ if (n == 0) {
1298
+ /*dc[1] = dcore[3] / 2 + de - dcore[1];*/
1299
+ i1 = 2; i2 = 3;
1300
+ } else if (n == 1) {
1301
+ if (retflag & SE_ECL_PARTIAL)
1302
+ continue;
1303
+ i1 = 4; i2 = 5;
1304
+ } else if (n == 2) {
1305
+ if (retflag & SE_ECL_NONCENTRAL)
1306
+ continue;
1307
+ i1 = 6; i2 = 7;
1308
+ }
1309
+ for (i = 0, t = tjd - dta; i <= 2; i += 1, t += dta) {
1310
+ if ((retflag2 = eclipse_where(t, SE_SUN, NULL, ifl, geopos, dcore, serr)) == ERR)
1311
+ return retflag2;
1312
+ if (n == 0)
1313
+ dc[i] = dcore[4] / 2 + de / dcore[5] - dcore[2];
1314
+ else if (n == 1)
1315
+ dc[i] = fabs(dcore[3]) / 2 + de / dcore[6] - dcore[2];
1316
+ else if (n == 2)
1317
+ dc[i] = de / dcore[6] - dcore[2];
1318
+ }
1319
+ find_zero(dc[0], dc[1], dc[2], dta, &dt1, &dt2);
1320
+ tret[i1] = tjd + dt1 + dta;
1321
+ tret[i2] = tjd + dt2 + dta;
1322
+ for (m = 0, dt = dtb; m < 3; m++, dt /= 3) {
1323
+ for (j = i1; j <= i2; j += (i2 - i1)) {
1324
+ for (i = 0, t = tret[j] - dt; i < 2; i++, t += dt) {
1325
+ if ((retflag2 = eclipse_where(t, SE_SUN, NULL, ifl, geopos, dcore, serr)) == ERR)
1326
+ return retflag2;
1327
+ if (n == 0)
1328
+ dc[i] = dcore[4] / 2 + de / dcore[5] - dcore[2];
1329
+ else if (n == 1)
1330
+ dc[i] = fabs(dcore[3]) / 2 + de / dcore[6] - dcore[2];
1331
+ else if (n == 2)
1332
+ dc[i] = de / dcore[6] - dcore[2];
1333
+ }
1334
+ dt1 = dc[1] / ((dc[1] - dc[0]) / dt);
1335
+ tret[j] -= dt1;
1336
+ }
1337
+ }
1338
+ }
1339
+ /*
1340
+ * annular-total eclipses
1341
+ */
1342
+ if (retflag & SE_ECL_TOTAL) {
1343
+ if ((retflag2 = eclipse_where(tret[0], SE_SUN, NULL, ifl, geopos, dcore, serr)) == ERR)
1344
+ return retflag2;
1345
+ dc[0] = *dcore;
1346
+ if ((retflag2 = eclipse_where(tret[4], SE_SUN, NULL, ifl, geopos, dcore, serr)) == ERR)
1347
+ return retflag2;
1348
+ dc[1] = *dcore;
1349
+ if ((retflag2 = eclipse_where(tret[5], SE_SUN, NULL, ifl, geopos, dcore, serr)) == ERR)
1350
+ return retflag2;
1351
+ dc[2] = *dcore;
1352
+ /* the maximum is always total, and there is either one or
1353
+ * to times before and after, when the core shadow becomes
1354
+ * zero and totality changes into annularity or vice versa.
1355
+ */
1356
+ if (dc[0] * dc[1] < 0 || dc[0] * dc[2] < 0) {
1357
+ retflag |= SE_ECL_ANNULAR_TOTAL;
1358
+ retflag &= ~SE_ECL_TOTAL;
1359
+ }
1360
+ }
1361
+ /* if eclipse is given but not wanted: */
1362
+ if (!(ifltype & SE_ECL_TOTAL) && (retflag & SE_ECL_TOTAL)) {
1363
+ K += direction;
1364
+ goto next_try;
1365
+ }
1366
+ /* if annular_total eclipse is given but not wanted: */
1367
+ if (!(ifltype & SE_ECL_ANNULAR_TOTAL) && (retflag & SE_ECL_ANNULAR_TOTAL)) {
1368
+ K += direction;
1369
+ goto next_try;
1370
+ }
1371
+ /*
1372
+ * time of maximum eclipse at local apparent noon
1373
+ */
1374
+ /* first, find out, if there is a solar transit
1375
+ * between begin and end of eclipse */
1376
+ k = 2;
1377
+ for (i = 0; i < 2; i++) {
1378
+ j = i + k;
1379
+ tt = tret[j] + swe_deltat(tret[j]);
1380
+ if (swe_calc(tt, SE_SUN, iflag, ls, serr) == ERR)
1381
+ return ERR;
1382
+ if (swe_calc(tt, SE_MOON, iflag, lm, serr) == ERR)
1383
+ return ERR;
1384
+ dc[i] = swe_degnorm(ls[0] - lm[0]);
1385
+ if (dc[i] > 180)
1386
+ dc[i] -= 360;
1387
+ }
1388
+ if (dc[0] * dc[1] >= 0) /* no transit */
1389
+ tret[1] = 0;
1390
+ else {
1391
+ tjd = tjds;
1392
+ dt = 0.1;
1393
+ dt1 = (tret[3] - tret[2]) / 2.0;
1394
+ if (dt1 < dt)
1395
+ dt = dt1 / 2.0;
1396
+ for (j = 0;
1397
+ dt > 0.01;
1398
+ j++, dt /= 3) {
1399
+ for (i = 0, t = tjd; i <= 1; i++, t -= dt) {
1400
+ tt = t + swe_deltat(t);
1401
+ if (swe_calc(tt, SE_SUN, iflag, ls, serr) == ERR)
1402
+ return ERR;
1403
+ if (swe_calc(tt, SE_MOON, iflag, lm, serr) == ERR)
1404
+ return ERR;
1405
+ dc[i] = swe_degnorm(ls[0] - lm[0]);
1406
+ if (dc[i] > 180)
1407
+ dc[i] -= 360;
1408
+ if (dc[i] > 180)
1409
+ dc[i] -= 360;
1410
+ }
1411
+ a = (dc[1] - dc[0]) / dt;
1412
+ if (a < 1e-10)
1413
+ break;
1414
+ dt1 = dc[0] / a;
1415
+ tjd += dt1;
1416
+ }
1417
+ tret[1] = tjd;
1418
+ }
1419
+ end_search_global:
1420
+ return retflag;
1421
+ /*
1422
+ * the time of maximum occultation is practically identical
1423
+ * with the time of maximum core shadow diameter.
1424
+ *
1425
+ * the time, when duration of totality is maximal,
1426
+ * is not an interesting computation either. Near the maximum
1427
+ * occulation, the time of totality can be the same by
1428
+ * a second for hundreds of kilometers (for 10 minutes
1429
+ * or more).
1430
+ *
1431
+ * for annular eclipses the maximum duration is close to the
1432
+ * beginning and the end of the center lines, where is also
1433
+ * the minimum of core shadow diameter.
1434
+ */
1435
+ }
1436
+
1437
+ /* When is the next lunar occultation anywhere on earth?
1438
+ * This function also finds solar eclipses, but is less efficient
1439
+ * than swe_sol_eclipse_when_glob().
1440
+ *
1441
+ * input parameters:
1442
+ *
1443
+ * tjd_start start time for search (UT)
1444
+ * ipl planet number of occulted body
1445
+ * starname name of occulted star. Must be NULL or "", if a planetary
1446
+ * occultation is to be calculated. For the use of this
1447
+ * field, also see swe_fixstar().
1448
+ * ifl ephemeris to be used (SEFLG_SWIEPH, etc.)
1449
+ * ephemeris flag.
1450
+ *
1451
+ * ifltype eclipse type to be searched (SE_ECL_TOTAL, etc.)
1452
+ * 0, if any type of eclipse is wanted
1453
+ * this functionality also works with occultations
1454
+ *
1455
+ * backward if 1, causes search backward in time
1456
+ *
1457
+ * If you want to have only one conjunction
1458
+ * of the moon with the body tested, add the following flag:
1459
+ * backward |= SE_ECL_ONE_TRY. If this flag is not set,
1460
+ * the function will search for an occultation until it
1461
+ * finds one. For bodies with ecliptical latitudes > 5,
1462
+ * the function may search successlessly until it reaches
1463
+ * the end of the ephemeris.
1464
+ * (Note: we do not add SE_ECL_ONE_TRY to ifl, because
1465
+ * ifl may contain SEFLG_TOPOCTR (=SE_ECL_ONE_TRY) from
1466
+ * the parameter iflag of swe_calc() etc. Although the
1467
+ * topocentric flag is irrelevant here, it might cause
1468
+ * confusion.)
1469
+ *
1470
+ * return values:
1471
+ *
1472
+ * retflag SE_ECL_TOTAL or SE_ECL_ANNULAR or SE_ECL_PARTIAL
1473
+ * or SE_ECL_ANNULAR_TOTAL
1474
+ * SE_ECL_CENTRAL
1475
+ * SE_ECL_NONCENTRAL
1476
+ *
1477
+ * tret[0] time of maximum eclipse
1478
+ * tret[1] time, when eclipse takes place at local apparent noon
1479
+ * tret[2] time of eclipse begin
1480
+ * tret[3] time of eclipse end
1481
+ * tret[4] time of totality begin
1482
+ * tret[5] time of totality end
1483
+ * tret[6] time of center line begin
1484
+ * tret[7] time of center line end
1485
+ * tret[8] time when annular-total eclipse becomes total
1486
+ * not implemented so far
1487
+ * tret[9] time when annular-total eclipse becomes annular again
1488
+ * not implemented so far
1489
+ * declare as tret[10] at least!
1490
+ *
1491
+ */
1492
+ int32 FAR PASCAL_CONV swe_lun_occult_when_glob(
1493
+ double tjd_start, int32 ipl, char *starname, int32 ifl, int32 ifltype,
1494
+ double *tret, int32 backward, char *serr)
1495
+ {
1496
+ int i, j, k, m, n, o, i1, i2;
1497
+ int32 retflag = 0, retflag2 = 0;
1498
+ double de = 6378.140, a;
1499
+ double t, tt, tjd = 0, tjds, dt, dtint, dta, dtb;
1500
+ double drad;
1501
+ double xs[6], xm[6], ls[6], lm[6];
1502
+ double rmoon, rsun, dcore[10];
1503
+ double dc[20], dctr;
1504
+ double twohr = 2.0 / 24.0;
1505
+ double tenmin = 10.0 / 24.0 / 60.0;
1506
+ double dt1, dt2, dadd = 10, dadd2 = 6;
1507
+ int nstartpos = 10;
1508
+ double geopos[20];
1509
+ double dtstart, dtdiv;
1510
+ int direction = 1;
1511
+ char s[AS_MAXCH];
1512
+ int32 iflag, iflagcart;
1513
+ AS_BOOL dont_times = FALSE;
1514
+ int32 one_try = backward & SE_ECL_ONE_TRY;
1515
+ /*if (backward & SEI_OCC_FAST)
1516
+ dont_times = TRUE; */
1517
+ /* function calls for Pluto with asteroid number 134340
1518
+ * are treated as calls for Pluto as main body SE_PLUTO */
1519
+ if (ipl == SE_AST_OFFSET + 134340)
1520
+ ipl = SE_PLUTO;
1521
+ ifl &= SEFLG_EPHMASK;
1522
+ iflag = SEFLG_EQUATORIAL | ifl;
1523
+ iflagcart = iflag | SEFLG_XYZ;
1524
+ backward &= 1L;
1525
+ /*
1526
+ * initializations
1527
+ */
1528
+ if (ifltype == (SE_ECL_PARTIAL | SE_ECL_CENTRAL)) {
1529
+ if (serr != NULL)
1530
+ strcpy(serr, "central partial eclipses do not exist");
1531
+ return ERR;
1532
+ }
1533
+ if (ifltype == 0)
1534
+ ifltype = SE_ECL_TOTAL | SE_ECL_ANNULAR | SE_ECL_PARTIAL
1535
+ | SE_ECL_ANNULAR_TOTAL | SE_ECL_NONCENTRAL | SE_ECL_CENTRAL;
1536
+ retflag = 0;
1537
+ for (i = 0; i <= 9; i++)
1538
+ tret[i] = 0;
1539
+ if (backward)
1540
+ direction = -1;
1541
+ t = tjd_start - direction * 0.001;
1542
+ next_try:
1543
+ for (i = 0; i < nstartpos; i++, t += direction * dadd2) {
1544
+ if (calc_planet_star(t, ipl, starname, iflagcart, xs, serr) == ERR)
1545
+ return ERR;
1546
+ if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
1547
+ return ERR;
1548
+ dc[i] = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
1549
+ if (i > 1 && dc[i] > dc[i-1] && dc[i-2] > dc[i-1]) {
1550
+ tjd = t - direction * dadd2;
1551
+ break;
1552
+ } else if (i == nstartpos-1) {
1553
+ /*for (j = 0; j < nstartpos; j++)
1554
+ printf("%f ", dc[j]);*/
1555
+ if (serr != NULL) {
1556
+ if (starname != NULL && *starname != '\0')
1557
+ strcpy(s, starname);
1558
+ else
1559
+ swe_get_planet_name(ipl , s);
1560
+ sprintf(serr, "error in swe_lun_occult_when_glob(): conjunction of moon with planet %s not found\n", s);
1561
+ }
1562
+ return ERR;
1563
+ }
1564
+ }
1565
+ /*
1566
+ * radius of planet disk in AU
1567
+ */
1568
+ if (starname != NULL && *starname != '\0')
1569
+ drad = 0;
1570
+ else if (ipl < NDIAM)
1571
+ drad = pla_diam[ipl] / 2 / AUNIT;
1572
+ else if (ipl > SE_AST_OFFSET)
1573
+ drad = swed.ast_diam / 2 * 1000 / AUNIT; /* km -> m -> AU */
1574
+ else
1575
+ drad = 0;
1576
+ /*
1577
+ * time of maximum eclipse (if eclipse) =
1578
+ * minimum geocentric angle between sun and moon edges.
1579
+ * After this time has been determined, check
1580
+ * whether or not an eclipse is taking place with
1581
+ * the functions eclipse_where() and _how().
1582
+ */
1583
+ dtstart = dadd2; /* originally 1 */
1584
+ dtdiv = 3;
1585
+ for (dt = dtstart;
1586
+ dt > 0.0001;
1587
+ dt /= dtdiv) {
1588
+ for (i = 0, t = tjd - dt; i <= 2; i++, t += dt) {
1589
+ if (calc_planet_star(t, ipl, starname, iflag, ls, serr) == ERR)
1590
+ return ERR;
1591
+ if (swe_calc(t, SE_MOON, iflag, lm, serr) == ERR)
1592
+ return ERR;
1593
+ if (calc_planet_star(t, ipl, starname, iflagcart, xs, serr) == ERR)
1594
+ return ERR;
1595
+ if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
1596
+ return ERR;
1597
+ dc[i] = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
1598
+ rmoon = asin(RMOON / lm[2]) * RADTODEG;
1599
+ rsun = asin(drad / ls[2]) * RADTODEG;
1600
+ dc[i] -= (rmoon + rsun);
1601
+ }
1602
+ find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dctr);
1603
+ tjd += dtint + dt;
1604
+ }
1605
+ tjd -= swe_deltat(tjd);
1606
+ tjds = tjd;
1607
+ if ((retflag = eclipse_where(tjd, ipl, starname, ifl, geopos, dcore, serr)) == ERR)
1608
+ return retflag;
1609
+ retflag2 = retflag;
1610
+ /* in extreme cases _where() returns no eclipse, where there is
1611
+ * actually a very small one, therefore call _how() with the
1612
+ * coordinates returned by _where(): */
1613
+ /* if ((retflag2 = eclipse_how(tjd, ipl, starname, ifl, geopos[0], geopos[1], 0, attr, serr)) == ERR)
1614
+ return retflag2; */
1615
+ if (retflag2 == 0) {
1616
+ /* only one try! */
1617
+ if (one_try) {
1618
+ tret[0] = tjd;
1619
+ return 0;
1620
+ }
1621
+ t= tjd + direction * dadd;
1622
+ goto next_try;
1623
+ }
1624
+ tret[0] = tjd;
1625
+ if ((backward && tret[0] >= tjd_start - 0.0001)
1626
+ || (!backward && tret[0] <= tjd_start + 0.0001)) {
1627
+ t= tjd + direction * dadd;
1628
+ goto next_try;
1629
+ }
1630
+ /*
1631
+ * eclipse type, SE_ECL_TOTAL, _ANNULAR, etc.
1632
+ * SE_ECL_ANNULAR_TOTAL will be discovered later
1633
+ */
1634
+ if ((retflag = eclipse_where(tjd, ipl, starname, ifl, geopos, dcore, serr)) == ERR)
1635
+ return retflag;
1636
+ if (retflag == 0) { /* can happen with extremely small percentage */
1637
+ retflag = SE_ECL_PARTIAL | SE_ECL_NONCENTRAL;
1638
+ tret[4] = tret[5] = tjd; /* fix this ???? */
1639
+ dont_times = TRUE;
1640
+ }
1641
+ /*
1642
+ * check whether or not eclipse type found is wanted
1643
+ */
1644
+ /* non central eclipse is wanted: */
1645
+ if (!(ifltype & SE_ECL_NONCENTRAL) && (retflag & SE_ECL_NONCENTRAL)) {
1646
+ t= tjd + direction * dadd;
1647
+ goto next_try;
1648
+ }
1649
+ /* central eclipse is wanted: */
1650
+ if (!(ifltype & SE_ECL_CENTRAL) && (retflag & SE_ECL_CENTRAL)) {
1651
+ t= tjd + direction * dadd;
1652
+ goto next_try;
1653
+ }
1654
+ /* non annular eclipse is wanted: */
1655
+ if (!(ifltype & SE_ECL_ANNULAR) && (retflag & SE_ECL_ANNULAR)) {
1656
+ t= tjd + direction * dadd;
1657
+ goto next_try;
1658
+ }
1659
+ /* non partial eclipse is wanted: */
1660
+ if (!(ifltype & SE_ECL_PARTIAL) && (retflag & SE_ECL_PARTIAL)) {
1661
+ t= tjd + direction * dadd;
1662
+ goto next_try;
1663
+ }
1664
+ /* annular-total eclipse will be discovered later */
1665
+ if (!(ifltype & (SE_ECL_TOTAL | SE_ECL_ANNULAR_TOTAL)) && (retflag & SE_ECL_TOTAL)) {
1666
+ t= tjd + direction * dadd;
1667
+ goto next_try;
1668
+ }
1669
+ if (dont_times)
1670
+ goto end_search_global;
1671
+ /*
1672
+ * n = 0: times of eclipse begin and end
1673
+ * n = 1: times of totality begin and end
1674
+ * n = 2: times of center line begin and end
1675
+ */
1676
+ if (retflag & SE_ECL_PARTIAL)
1677
+ o = 0;
1678
+ else if (retflag & SE_ECL_NONCENTRAL)
1679
+ o = 1;
1680
+ else
1681
+ o = 2;
1682
+ dta = twohr;
1683
+ dtb = tenmin;
1684
+ for (n = 0; n <= o; n++) {
1685
+ if (n == 0) {
1686
+ /*dc[1] = dcore[3] / 2 + de - dcore[1];*/
1687
+ i1 = 2; i2 = 3;
1688
+ } else if (n == 1) {
1689
+ if (retflag & SE_ECL_PARTIAL)
1690
+ continue;
1691
+ i1 = 4; i2 = 5;
1692
+ } else if (n == 2) {
1693
+ if (retflag & SE_ECL_NONCENTRAL)
1694
+ continue;
1695
+ i1 = 6; i2 = 7;
1696
+ }
1697
+ for (i = 0, t = tjd - dta; i <= 2; i += 1, t += dta) {
1698
+ if ((retflag2 = eclipse_where(t, ipl, starname, ifl, geopos, dcore, serr)) == ERR)
1699
+ return retflag2;
1700
+ if (n == 0)
1701
+ dc[i] = dcore[4] / 2 + de / dcore[5] - dcore[2];
1702
+ else if (n == 1)
1703
+ dc[i] = fabs(dcore[3]) / 2 + de / dcore[6] - dcore[2];
1704
+ else if (n == 2)
1705
+ dc[i] = de / dcore[6] - dcore[2];
1706
+ }
1707
+ find_zero(dc[0], dc[1], dc[2], dta, &dt1, &dt2);
1708
+ tret[i1] = tjd + dt1 + dta;
1709
+ tret[i2] = tjd + dt2 + dta;
1710
+ for (m = 0, dt = dtb; m < 3; m++, dt /= 3) {
1711
+ for (j = i1; j <= i2; j += (i2 - i1)) {
1712
+ for (i = 0, t = tret[j] - dt; i < 2; i++, t += dt) {
1713
+ if ((retflag2 = eclipse_where(t, ipl, starname, ifl, geopos, dcore, serr)) == ERR)
1714
+ return retflag2;
1715
+ if (n == 0)
1716
+ dc[i] = dcore[4] / 2 + de / dcore[5] - dcore[2];
1717
+ else if (n == 1)
1718
+ dc[i] = fabs(dcore[3]) / 2 + de / dcore[6] - dcore[2];
1719
+ else if (n == 2)
1720
+ dc[i] = de / dcore[6] - dcore[2];
1721
+ }
1722
+ dt1 = dc[1] / ((dc[1] - dc[0]) / dt);
1723
+ tret[j] -= dt1;
1724
+ }
1725
+ }
1726
+ }
1727
+ /*
1728
+ * annular-total eclipses
1729
+ */
1730
+ if (retflag & SE_ECL_TOTAL) {
1731
+ if ((retflag2 = eclipse_where(tret[0], ipl, starname, ifl, geopos, dcore, serr)) == ERR)
1732
+ return retflag2;
1733
+ dc[0] = *dcore;
1734
+ if ((retflag2 = eclipse_where(tret[4], ipl, starname, ifl, geopos, dcore, serr)) == ERR)
1735
+ return retflag2;
1736
+ dc[1] = *dcore;
1737
+ if ((retflag2 = eclipse_where(tret[5], ipl, starname, ifl, geopos, dcore, serr)) == ERR)
1738
+ return retflag2;
1739
+ dc[2] = *dcore;
1740
+ /* the maximum is always total, and there is either one or
1741
+ * to times before and after, when the core shadow becomes
1742
+ * zero and totality changes into annularity or vice versa.
1743
+ */
1744
+ if (dc[0] * dc[1] < 0 || dc[0] * dc[2] < 0) {
1745
+ retflag |= SE_ECL_ANNULAR_TOTAL;
1746
+ retflag &= ~SE_ECL_TOTAL;
1747
+ }
1748
+ }
1749
+ /* if eclipse is given but not wanted: */
1750
+ if (!(ifltype & SE_ECL_TOTAL) && (retflag & SE_ECL_TOTAL)) {
1751
+ t= tjd + direction * dadd;
1752
+ goto next_try;
1753
+ }
1754
+ /* if annular_total eclipse is given but not wanted: */
1755
+ if (!(ifltype & SE_ECL_ANNULAR_TOTAL) && (retflag & SE_ECL_ANNULAR_TOTAL)) {
1756
+ t= tjd + direction * dadd;
1757
+ goto next_try;
1758
+ }
1759
+ /*
1760
+ * time of maximum eclipse at local apparent noon
1761
+ */
1762
+ /* first, find out, if there is a solar transit
1763
+ * between begin and end of eclipse */
1764
+ k = 2;
1765
+ for (i = 0; i < 2; i++) {
1766
+ j = i + k;
1767
+ tt = tret[j] + swe_deltat(tret[j]);
1768
+ if (calc_planet_star(tt, ipl, starname, iflag, ls, serr) == ERR)
1769
+ return ERR;
1770
+ if (swe_calc(tt, SE_MOON, iflag, lm, serr) == ERR)
1771
+ return ERR;
1772
+ dc[i] = swe_degnorm(ls[0] - lm[0]);
1773
+ if (dc[i] > 180)
1774
+ dc[i] -= 360;
1775
+ }
1776
+ if (dc[0] * dc[1] >= 0) /* no transit */
1777
+ tret[1] = 0;
1778
+ else {
1779
+ tjd = tjds;
1780
+ dt = 0.1;
1781
+ dt1 = (tret[3] - tret[2]) / 2.0;
1782
+ if (dt1 < dt)
1783
+ dt = dt1 / 2.0;
1784
+ for (j = 0;
1785
+ dt > 0.01;
1786
+ j++, dt /= 3) {
1787
+ for (i = 0, t = tjd; i <= 1; i++, t -= dt) {
1788
+ tt = t + swe_deltat(t);
1789
+ if (calc_planet_star(tt, ipl, starname, iflag, ls, serr) == ERR)
1790
+ return ERR;
1791
+ if (swe_calc(tt, SE_MOON, iflag, lm, serr) == ERR)
1792
+ return ERR;
1793
+ dc[i] = swe_degnorm(ls[0] - lm[0]);
1794
+ if (dc[i] > 180)
1795
+ dc[i] -= 360;
1796
+ if (dc[i] > 180)
1797
+ dc[i] -= 360;
1798
+ }
1799
+ a = (dc[1] - dc[0]) / dt;
1800
+ if (a < 1e-10)
1801
+ break;
1802
+ dt1 = dc[0] / a;
1803
+ tjd += dt1;
1804
+ }
1805
+ tret[1] = tjd;
1806
+ }
1807
+ end_search_global:
1808
+ return retflag;
1809
+ /*
1810
+ * the time of maximum occultation is practically identical
1811
+ * with the time of maximum core shadow diameter.
1812
+ *
1813
+ * the time, when duration of totality is maximal,
1814
+ * is not an interesting computation either. Near the maximum
1815
+ * occulation, the time of totality can be the same by
1816
+ * a second for hundreds of kilometers (for 10 minutes
1817
+ * or more).
1818
+ *
1819
+ * for annular eclipses the maximum duration is close to the
1820
+ * beginning and the end of the center lines, where is also
1821
+ * the minimum of core shadow diameter.
1822
+ */
1823
+ }
1824
+
1825
+ /* When is the next solar eclipse at a given geographical position?
1826
+ * Note the uncertainty of Delta T for the remote past and for
1827
+ * the future.
1828
+ *
1829
+ * retflag SE_ECL_TOTAL or SE_ECL_ANNULAR or SE_ECL_PARTIAL
1830
+ * SE_ECL_VISIBLE,
1831
+ * SE_ECL_MAX_VISIBLE,
1832
+ * SE_ECL_1ST_VISIBLE, SE_ECL_2ND_VISIBLE
1833
+ * SE_ECL_3ST_VISIBLE, SE_ECL_4ND_VISIBLE
1834
+ *
1835
+ * tret[0] time of maximum eclipse
1836
+ * tret[1] time of first contact
1837
+ * tret[2] time of second contact
1838
+ * tret[3] time of third contact
1839
+ * tret[4] time of forth contact
1840
+ * tret[5] time of sun rise between first and forth contact
1841
+ (not implemented so far)
1842
+ * tret[6] time of sun set beween first and forth contact
1843
+ (not implemented so far)
1844
+ *
1845
+ * attr[0] fraction of solar diameter covered by moon (magnitude)
1846
+ * attr[1] ratio of lunar diameter to solar one
1847
+ * attr[2] fraction of solar disc covered by moon (obscuration)
1848
+ * attr[3] diameter of core shadow in km
1849
+ * attr[4] azimuth of sun at tjd
1850
+ * attr[5] true altitude of sun above horizon at tjd
1851
+ * attr[6] apparent altitude of sun above horizon at tjd
1852
+ * attr[7] elongation of moon in degrees
1853
+ * declare as attr[20] at least !
1854
+ */
1855
+ int32 FAR PASCAL_CONV swe_sol_eclipse_when_loc(double tjd_start, int32 ifl,
1856
+ double *geopos, double *tret, double *attr, int32 backward, char *serr)
1857
+ {
1858
+ int32 retflag = 0, retflag2 = 0;
1859
+ double geopos2[20], dcore[10];
1860
+ ifl &= SEFLG_EPHMASK;
1861
+ if ((retflag = eclipse_when_loc(tjd_start, ifl, geopos, tret, attr, backward, serr)) <= 0)
1862
+ return retflag;
1863
+ /*
1864
+ * diameter of core shadow
1865
+ */
1866
+ if ((retflag2 = eclipse_where(tret[0], SE_SUN, NULL, ifl, geopos2, dcore, serr)) == ERR)
1867
+ return retflag2;
1868
+ retflag |= (retflag2 & SE_ECL_NONCENTRAL);
1869
+ attr[3] = dcore[0];
1870
+ return retflag;
1871
+ }
1872
+
1873
+ /* Same declaration as swe_sol_eclipse_when_loc().
1874
+ * In addition:
1875
+ * int32 ipl planet number of occulted body
1876
+ * char* starname name of occulted star. Must be NULL or "", if a planetary
1877
+ * occultation is to be calculated. For the use of this
1878
+ * field, also see swe_fixstar().
1879
+ * int32 ifl ephemeris flag. If you want to have only one conjunction
1880
+ * of the moon with the body tested, add the following flag:
1881
+ * backward |= SE_ECL_ONE_TRY. If this flag is not set,
1882
+ * the function will search for an occultation until it
1883
+ * finds one. For bodies with ecliptical latitudes > 5,
1884
+ * the function may search unsuccessfully until it reaches
1885
+ * the end of the ephemeris.
1886
+ */
1887
+ int32 FAR PASCAL_CONV swe_lun_occult_when_loc(double tjd_start, int32 ipl, char *starname, int32 ifl,
1888
+ double *geopos, double *tret, double *attr, int32 backward, char *serr)
1889
+ {
1890
+ int32 retflag = 0, retflag2 = 0;
1891
+ double geopos2[20], dcore[10];
1892
+ /* function calls for Pluto with asteroid number 134340
1893
+ * are treated as calls for Pluto as main body SE_PLUTO */
1894
+ if (ipl == SE_AST_OFFSET + 134340)
1895
+ ipl = SE_PLUTO;
1896
+ ifl &= SEFLG_EPHMASK;
1897
+ if ((retflag = occult_when_loc(tjd_start, ipl, starname, ifl, geopos, tret, attr, backward, serr)) <= 0)
1898
+ return retflag;
1899
+ /*
1900
+ * diameter of core shadow
1901
+ */
1902
+ if ((retflag2 = eclipse_where(tret[0], ipl, starname, ifl, geopos2, dcore, serr)) == ERR)
1903
+ return retflag2;
1904
+ retflag |= (retflag2 & SE_ECL_NONCENTRAL);
1905
+ attr[3] = dcore[0];
1906
+ return retflag;
1907
+ }
1908
+
1909
+ static int32 eclipse_when_loc(double tjd_start, int32 ifl, double *geopos, double *tret, double *attr, int32 backward, char *serr)
1910
+ {
1911
+ int i, j, k, m;
1912
+ int32 retflag = 0;
1913
+ double t, tjd, dt, dtint, K, T, T2, T3, T4, F, M, Mm;
1914
+ double E, Ff, A1, Om;
1915
+ double xs[6], xm[6], ls[6], lm[6], x1[6], x2[6], dm, ds;
1916
+ double rmoon, rsun, rsplusrm, rsminusrm;
1917
+ double dc[3], dctr, dctrmin;
1918
+ double twomin = 2.0 / 24.0 / 60.0;
1919
+ double tensec = 10.0 / 24.0 / 60.0 / 60.0;
1920
+ double twohr = 2.0 / 24.0;
1921
+ double tenmin = 10.0 / 24.0 / 60.0;
1922
+ double dt1, dt2, dtdiv, dtstart;
1923
+ int32 iflag = SEFLG_EQUATORIAL | SEFLG_TOPOCTR | ifl;
1924
+ int32 iflagcart = iflag | SEFLG_XYZ;
1925
+ swe_set_topo(geopos[0], geopos[1], geopos[2]);
1926
+ K = (int) ((tjd_start - J2000) / 365.2425 * 12.3685);
1927
+ if (backward)
1928
+ K++;
1929
+ else
1930
+ K--;
1931
+ next_try:
1932
+ T = K / 1236.85;
1933
+ T2 = T * T; T3 = T2 * T; T4 = T3 * T;
1934
+ Ff = F = swe_degnorm(160.7108 + 390.67050274 * K
1935
+ - 0.0016341 * T2
1936
+ - 0.00000227 * T3
1937
+ + 0.000000011 * T4);
1938
+ if (Ff > 180)
1939
+ Ff -= 180;
1940
+ if (Ff > 21 && Ff < 159) { /* no eclipse possible */
1941
+ if (backward)
1942
+ K--;
1943
+ else
1944
+ K++;
1945
+ goto next_try;
1946
+ }
1947
+ /* approximate time of geocentric maximum eclipse.
1948
+ * formula from Meeus, German, p. 381 */
1949
+ tjd = 2451550.09765 + 29.530588853 * K
1950
+ + 0.0001337 * T2
1951
+ - 0.000000150 * T3
1952
+ + 0.00000000073 * T4;
1953
+ M = swe_degnorm(2.5534 + 29.10535669 * K
1954
+ - 0.0000218 * T2
1955
+ - 0.00000011 * T3);
1956
+ Mm = swe_degnorm(201.5643 + 385.81693528 * K
1957
+ + 0.1017438 * T2
1958
+ + 0.00001239 * T3
1959
+ + 0.000000058 * T4);
1960
+ Om = swe_degnorm(124.7746 - 1.56375580 * K
1961
+ + 0.0020691 * T2
1962
+ + 0.00000215 * T3);
1963
+ E = 1 - 0.002516 * T - 0.0000074 * T2;
1964
+ A1 = swe_degnorm(299.77 + 0.107408 * K - 0.009173 * T2);
1965
+ M *= DEGTORAD;
1966
+ Mm *= DEGTORAD;
1967
+ F *= DEGTORAD;
1968
+ Om *= DEGTORAD;
1969
+ A1 *= DEGTORAD;
1970
+ tjd = tjd - 0.4075 * sin(Mm)
1971
+ + 0.1721 * E * sin(M);
1972
+ swe_set_topo(geopos[0], geopos[1], geopos[2]);
1973
+ dtdiv = 2;
1974
+ dtstart = 0.5;
1975
+ if (tjd < 1900000) /* because above formula is not good (delta t?) */
1976
+ dtstart = 2;
1977
+ for (dt = dtstart;
1978
+ dt > 0.00001;
1979
+ dt /= dtdiv) {
1980
+ if (dt < 0.1)
1981
+ dtdiv = 3;
1982
+ for (i = 0, t = tjd - dt; i <= 2; i++, t += dt) {
1983
+ /* this takes some time, but is necessary to avoid
1984
+ * missing an eclipse */
1985
+ if (swe_calc(t, SE_SUN, iflagcart, xs, serr) == ERR)
1986
+ return ERR;
1987
+ if (swe_calc(t, SE_SUN, iflag, ls, serr) == ERR)
1988
+ return ERR;
1989
+ if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
1990
+ return ERR;
1991
+ if (swe_calc(t, SE_MOON, iflag, lm, serr) == ERR)
1992
+ return ERR;
1993
+ dm = sqrt(square_sum(xm));
1994
+ ds = sqrt(square_sum(xs));
1995
+ for (k = 0; k < 3; k++) {
1996
+ x1[k] = xs[k] / ds /*ls[2]*/;
1997
+ x2[k] = xm[k] / dm /*lm[2]*/;
1998
+ }
1999
+ dc[i] = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
2000
+ }
2001
+ find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dctr);
2002
+ tjd += dtint + dt;
2003
+ }
2004
+ if (swe_calc(tjd, SE_SUN, iflagcart, xs, serr) == ERR)
2005
+ return ERR;
2006
+ if (swe_calc(tjd, SE_SUN, iflag, ls, serr) == ERR)
2007
+ return ERR;
2008
+ if (swe_calc(tjd, SE_MOON, iflagcart, xm, serr) == ERR)
2009
+ return ERR;
2010
+ if (swe_calc(tjd, SE_MOON, iflag, lm, serr) == ERR)
2011
+ return ERR;
2012
+ dctr = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
2013
+ rmoon = asin(RMOON / lm[2]) * RADTODEG;
2014
+ rsun = asin(RSUN / ls[2]) * RADTODEG;
2015
+ rsplusrm = rsun + rmoon;
2016
+ rsminusrm = rsun - rmoon;
2017
+ if (dctr > rsplusrm) {
2018
+ if (backward)
2019
+ K--;
2020
+ else
2021
+ K++;
2022
+ goto next_try;
2023
+ }
2024
+ tret[0] = tjd - swe_deltat(tjd);
2025
+ if ((backward && tret[0] >= tjd_start - 0.0001)
2026
+ || (!backward && tret[0] <= tjd_start + 0.0001)) {
2027
+ if (backward)
2028
+ K--;
2029
+ else
2030
+ K++;
2031
+ goto next_try;
2032
+ }
2033
+ if (dctr < rsminusrm)
2034
+ retflag = SE_ECL_ANNULAR;
2035
+ else if (dctr < fabs(rsminusrm))
2036
+ retflag = SE_ECL_TOTAL;
2037
+ else if (dctr <= rsplusrm)
2038
+ retflag = SE_ECL_PARTIAL;
2039
+ dctrmin = dctr;
2040
+ /* contacts 2 and 3 */
2041
+ if (dctr > fabs(rsminusrm)) /* partial, no 2nd and 3rd contact */
2042
+ tret[2] = tret[3] = 0;
2043
+ else {
2044
+ dc[1] = fabs(rsminusrm) - dctrmin;
2045
+ for (i = 0, t = tjd - twomin; i <= 2; i += 2, t = tjd + twomin) {
2046
+ if (swe_calc(t, SE_SUN, iflagcart, xs, serr) == ERR)
2047
+ return ERR;
2048
+ if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
2049
+ return ERR;
2050
+ dm = sqrt(square_sum(xm));
2051
+ ds = sqrt(square_sum(xs));
2052
+ rmoon = asin(RMOON / dm) * RADTODEG;
2053
+ rsun = asin(RSUN / ds) * RADTODEG;
2054
+ rsminusrm = rsun - rmoon;
2055
+ for (k = 0; k < 3; k++) {
2056
+ x1[k] = xs[k] / ds /*ls[2]*/;
2057
+ x2[k] = xm[k] / dm /*lm[2]*/;
2058
+ }
2059
+ dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
2060
+ dc[i] = fabs(rsminusrm) - dctr;
2061
+ }
2062
+ find_zero(dc[0], dc[1], dc[2], twomin, &dt1, &dt2);
2063
+ tret[2] = tjd + dt1 + twomin;
2064
+ tret[3] = tjd + dt2 + twomin;
2065
+ for (m = 0, dt = tensec; m < 2; m++, dt /= 10) {
2066
+ for (j = 2; j <= 3; j++) {
2067
+ if (swe_calc(tret[j], SE_SUN, iflagcart | SEFLG_SPEED, xs, serr) == ERR)
2068
+ return ERR;
2069
+ if (swe_calc(tret[j], SE_MOON, iflagcart | SEFLG_SPEED, xm, serr) == ERR)
2070
+ return ERR;
2071
+ for (i = 0; i < 2; i++) {
2072
+ if (i == 1) {
2073
+ for(k = 0; k < 3; k++) {
2074
+ xs[k] -= xs[k+3] * dt;
2075
+ xm[k] -= xm[k+3] * dt;
2076
+ }
2077
+ }
2078
+ dm = sqrt(square_sum(xm));
2079
+ ds = sqrt(square_sum(xs));
2080
+ rmoon = asin(RMOON / dm) * RADTODEG;
2081
+ rsun = asin(RSUN / ds) * RADTODEG;
2082
+ rsminusrm = rsun - rmoon;
2083
+ for (k = 0; k < 3; k++) {
2084
+ x1[k] = xs[k] / ds /*ls[2]*/;
2085
+ x2[k] = xm[k] / dm /*lm[2]*/;
2086
+ }
2087
+ dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
2088
+ dc[i] = fabs(rsminusrm) - dctr;
2089
+ }
2090
+ dt1 = -dc[0] / ((dc[0] - dc[1]) / dt);
2091
+ tret[j] += dt1;
2092
+ }
2093
+ }
2094
+ tret[2] -= swe_deltat(tret[2]);
2095
+ tret[3] -= swe_deltat(tret[3]);
2096
+ }
2097
+ /* contacts 1 and 4 */
2098
+ dc[1] = rsplusrm - dctrmin;
2099
+ for (i = 0, t = tjd - twohr; i <= 2; i += 2, t = tjd + twohr) {
2100
+ if (swe_calc(t, SE_SUN, iflagcart, xs, serr) == ERR)
2101
+ return ERR;
2102
+ if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
2103
+ return ERR;
2104
+ dm = sqrt(square_sum(xm));
2105
+ ds = sqrt(square_sum(xs));
2106
+ rmoon = asin(RMOON / dm) * RADTODEG;
2107
+ rsun = asin(RSUN / ds) * RADTODEG;
2108
+ rsplusrm = rsun + rmoon;
2109
+ for (k = 0; k < 3; k++) {
2110
+ x1[k] = xs[k] / ds /*ls[2]*/;
2111
+ x2[k] = xm[k] / dm /*lm[2]*/;
2112
+ }
2113
+ dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
2114
+ dc[i] = rsplusrm - dctr;
2115
+ }
2116
+ find_zero(dc[0], dc[1], dc[2], twohr, &dt1, &dt2);
2117
+ tret[1] = tjd + dt1 + twohr;
2118
+ tret[4] = tjd + dt2 + twohr;
2119
+ for (m = 0, dt = tenmin; m < 3; m++, dt /= 10) {
2120
+ for (j = 1; j <= 4; j += 3) {
2121
+ if (swe_calc(tret[j], SE_SUN, iflagcart | SEFLG_SPEED, xs, serr) == ERR)
2122
+ return ERR;
2123
+ if (swe_calc(tret[j], SE_MOON, iflagcart | SEFLG_SPEED, xm, serr) == ERR)
2124
+ return ERR;
2125
+ for (i = 0; i < 2; i++) {
2126
+ if (i == 1) {
2127
+ for(k = 0; k < 3; k++) {
2128
+ xs[k] -= xs[k+3] * dt;
2129
+ xm[k] -= xm[k+3] * dt;
2130
+ }
2131
+ }
2132
+ dm = sqrt(square_sum(xm));
2133
+ ds = sqrt(square_sum(xs));
2134
+ rmoon = asin(RMOON / dm) * RADTODEG;
2135
+ rsun = asin(RSUN / ds) * RADTODEG;
2136
+ rsplusrm = rsun + rmoon;
2137
+ for (k = 0; k < 3; k++) {
2138
+ x1[k] = xs[k] / ds /*ls[2]*/;
2139
+ x2[k] = xm[k] / dm /*lm[2]*/;
2140
+ }
2141
+ dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
2142
+ dc[i] = fabs(rsplusrm) - dctr;
2143
+ }
2144
+ dt1 = -dc[0] / ((dc[0] - dc[1]) / dt);
2145
+ tret[j] += dt1;
2146
+ }
2147
+ }
2148
+ tret[1] -= swe_deltat(tret[1]);
2149
+ tret[4] -= swe_deltat(tret[4]);
2150
+ /*
2151
+ * visibility of eclipse phases
2152
+ */
2153
+ for (i = 4; i >= 0; i--) { /* attr for i = 0 must be kept !!! */
2154
+ if (tret[i] == 0)
2155
+ continue;
2156
+ if (eclipse_how(tret[i], SE_SUN, NULL, ifl, geopos[0], geopos[1], geopos[2],
2157
+ attr, serr) == ERR)
2158
+ return ERR;
2159
+ /*if (retflag2 & SE_ECL_VISIBLE) { could be wrong for 1st/4th contact */
2160
+ if (attr[5] > 0) { /* this is save, sun above horizon */
2161
+ retflag |= SE_ECL_VISIBLE;
2162
+ switch(i) {
2163
+ case 0: retflag |= SE_ECL_MAX_VISIBLE; break;
2164
+ case 1: retflag |= SE_ECL_1ST_VISIBLE; break;
2165
+ case 2: retflag |= SE_ECL_2ND_VISIBLE; break;
2166
+ case 3: retflag |= SE_ECL_3RD_VISIBLE; break;
2167
+ case 4: retflag |= SE_ECL_4TH_VISIBLE; break;
2168
+ default: break;
2169
+ }
2170
+ }
2171
+ }
2172
+ #if 1
2173
+ if (!(retflag & SE_ECL_VISIBLE)) {
2174
+ if (backward)
2175
+ K--;
2176
+ else
2177
+ K++;
2178
+ goto next_try;
2179
+ }
2180
+ #endif
2181
+ return retflag;
2182
+ }
2183
+
2184
+ static int32 occult_when_loc(
2185
+ double tjd_start, int32 ipl, char *starname,
2186
+ int32 ifl, double *geopos, double *tret, double *attr,
2187
+ int32 backward, char *serr)
2188
+ {
2189
+ int i, j, k, m;
2190
+ int32 retflag = 0;
2191
+ double t, tjd, dt, dtint;
2192
+ double xs[6], xm[6], ls[6], lm[6], x1[6], x2[6], dm, ds;
2193
+ double rmoon, rsun, rsplusrm, rsminusrm;
2194
+ double dc[20], dctr, dctrmin;
2195
+ double twomin = 2.0 / 24.0 / 60.0;
2196
+ double tensec = 10.0 / 24.0 / 60.0 / 60.0;
2197
+ double twohr = 2.0 / 24.0;
2198
+ double tenmin = 10.0 / 24.0 / 60.0;
2199
+ double dt1, dt2, dtdiv, dtstart;
2200
+ double dadd2 = 6;
2201
+ int nstartpos = 10;
2202
+ double drad;
2203
+ int32 iflag = SEFLG_TOPOCTR | ifl;
2204
+ int32 iflaggeo = iflag & ~SEFLG_TOPOCTR;
2205
+ int32 iflagcart = iflag | SEFLG_XYZ;
2206
+ int32 iflagcartgeo = iflaggeo | SEFLG_XYZ;
2207
+ int direction = 1;
2208
+ int32 one_try = backward & SE_ECL_ONE_TRY;
2209
+ AS_BOOL stop_after_this = FALSE;
2210
+ backward &= 1L;
2211
+ retflag = 0;
2212
+ for (i = 0; i <= 9; i++)
2213
+ tret[i] = 0;
2214
+ if (backward)
2215
+ direction = -1;
2216
+ t = tjd_start - direction * 0.1;
2217
+ tjd = tjd_start;
2218
+ next_try:
2219
+ for (i = 0; i < nstartpos; i++, t += direction * dadd2) {
2220
+ if (calc_planet_star(t, ipl, starname, iflagcartgeo, xs, serr) == ERR)
2221
+ return ERR;
2222
+ if (swe_calc(t, SE_MOON, iflagcartgeo, xm, serr) == ERR)
2223
+ return ERR;
2224
+ dc[i] = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
2225
+ if (i > 1 && dc[i] > dc[i-1] && dc[i-2] > dc[i-1]) {
2226
+ tjd = t - direction*dadd2;
2227
+ break;
2228
+ } else if (i == nstartpos-1) {
2229
+ for (j = 0; j < nstartpos; j++)
2230
+ printf("%f ", dc[j]);
2231
+ printf("swe_lun_occult_when_loc(): problem planet\n");
2232
+ return ERR;
2233
+ }
2234
+ }
2235
+ /*
2236
+ * radius of planet disk in AU
2237
+ */
2238
+ if (starname != NULL && *starname != '\0')
2239
+ drad = 0;
2240
+ else if (ipl < NDIAM)
2241
+ drad = pla_diam[ipl] / 2 / AUNIT;
2242
+ else if (ipl > SE_AST_OFFSET)
2243
+ drad = swed.ast_diam / 2 * 1000 / AUNIT; /* km -> m -> AU */
2244
+ else
2245
+ drad = 0;
2246
+ /* now find out, if there is an occultation at our geogr. location */
2247
+ dtdiv = 3;
2248
+ dtstart = dadd2; /* formerly 0.2 */
2249
+ for (dt = dtstart;
2250
+ dt > 0.00001;
2251
+ dt /= dtdiv) {
2252
+ if (dt < 0.01)
2253
+ dtdiv = 3;
2254
+ for (i = 0, t = tjd - dt; i <= 2; i++, t += dt) {
2255
+ /* this takes some time, but is necessary to avoid
2256
+ * missing an eclipse */
2257
+ if (calc_planet_star(t, ipl, starname, iflagcart, xs, serr) == ERR)
2258
+ return ERR;
2259
+ if (calc_planet_star(t, ipl, starname, iflag, ls, serr) == ERR)
2260
+ return ERR;
2261
+ if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
2262
+ return ERR;
2263
+ if (swe_calc(t, SE_MOON, iflag, lm, serr) == ERR)
2264
+ return ERR;
2265
+ if (dt < 1 && fabs(ls[1] - lm[1]) > 2) {
2266
+ if (one_try) {
2267
+ stop_after_this = TRUE;
2268
+ } else {
2269
+ t = tjd + direction * 2;
2270
+ goto next_try;
2271
+ }
2272
+ }
2273
+ dc[i] = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
2274
+ rmoon = asin(RMOON / lm[2]) * RADTODEG;
2275
+ rsun = asin(drad / ls[2]) * RADTODEG;
2276
+ dc[i] -= (rmoon + rsun);
2277
+ }
2278
+ find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dctr);
2279
+ tjd += dtint + dt;
2280
+ }
2281
+ if (stop_after_this) { /* has one_try = TRUE */
2282
+ tret[0] = tjd;
2283
+ return 0;
2284
+ }
2285
+ if (calc_planet_star(tjd, ipl, starname, iflagcart, xs, serr) == ERR)
2286
+ return ERR;
2287
+ if (calc_planet_star(tjd, ipl, starname, iflag, ls, serr) == ERR)
2288
+ return ERR;
2289
+ if (swe_calc(tjd, SE_MOON, iflagcart, xm, serr) == ERR)
2290
+ return ERR;
2291
+ if (swe_calc(tjd, SE_MOON, iflag, lm, serr) == ERR)
2292
+ return ERR;
2293
+ dctr = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
2294
+ rmoon = asin(RMOON / lm[2]) * RADTODEG;
2295
+ rsun = asin(drad / ls[2]) * RADTODEG;
2296
+ rsplusrm = rsun + rmoon;
2297
+ rsminusrm = rsun - rmoon;
2298
+ if (dctr > rsplusrm) {
2299
+ if (one_try) {
2300
+ tret[0] = tjd;
2301
+ return 0;
2302
+ }
2303
+ t = tjd + direction;
2304
+ goto next_try;
2305
+ }
2306
+ tret[0] = tjd - swe_deltat(tjd);
2307
+ if ((backward && tret[0] >= tjd_start - 0.0001)
2308
+ || (!backward && tret[0] <= tjd_start + 0.0001)) {
2309
+ t = tjd + direction;
2310
+ goto next_try;
2311
+ }
2312
+ if (dctr < rsminusrm)
2313
+ retflag = SE_ECL_ANNULAR;
2314
+ else if (dctr < fabs(rsminusrm))
2315
+ retflag = SE_ECL_TOTAL;
2316
+ else if (dctr <= rsplusrm)
2317
+ retflag = SE_ECL_PARTIAL;
2318
+ dctrmin = dctr;
2319
+ /* contacts 2 and 3 */
2320
+ if (dctr > fabs(rsminusrm)) /* partial, no 2nd and 3rd contact */
2321
+ tret[2] = tret[3] = 0;
2322
+ else {
2323
+ dc[1] = fabs(rsminusrm) - dctrmin;
2324
+ for (i = 0, t = tjd - twomin; i <= 2; i += 2, t = tjd + twomin) {
2325
+ if (calc_planet_star(t, ipl, starname, iflagcart, xs, serr) == ERR)
2326
+ return ERR;
2327
+ if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
2328
+ return ERR;
2329
+ dm = sqrt(square_sum(xm));
2330
+ ds = sqrt(square_sum(xs));
2331
+ rmoon = asin(RMOON / dm) * RADTODEG;
2332
+ rsun = asin(drad / ds) * RADTODEG;
2333
+ rsminusrm = rsun - rmoon;
2334
+ for (k = 0; k < 3; k++) {
2335
+ x1[k] = xs[k] / ds /*ls[2]*/;
2336
+ x2[k] = xm[k] / dm /*lm[2]*/;
2337
+ }
2338
+ dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
2339
+ dc[i] = fabs(rsminusrm) - dctr;
2340
+ }
2341
+ find_zero(dc[0], dc[1], dc[2], twomin, &dt1, &dt2);
2342
+ tret[2] = tjd + dt1 + twomin;
2343
+ tret[3] = tjd + dt2 + twomin;
2344
+ for (m = 0, dt = tensec; m < 2; m++, dt /= 10) {
2345
+ for (j = 2; j <= 3; j++) {
2346
+ if (calc_planet_star(tret[j], ipl, starname, iflagcart | SEFLG_SPEED, xs, serr) == ERR)
2347
+ return ERR;
2348
+ if (swe_calc(tret[j], SE_MOON, iflagcart | SEFLG_SPEED, xm, serr) == ERR)
2349
+ return ERR;
2350
+ for (i = 0; i < 2; i++) {
2351
+ if (i == 1) {
2352
+ for(k = 0; k < 3; k++) {
2353
+ xs[k] -= xs[k+3] * dt;
2354
+ xm[k] -= xm[k+3] * dt;
2355
+ }
2356
+ }
2357
+ dm = sqrt(square_sum(xm));
2358
+ ds = sqrt(square_sum(xs));
2359
+ rmoon = asin(RMOON / dm) * RADTODEG;
2360
+ rsun = asin(drad / ds) * RADTODEG;
2361
+ rsminusrm = rsun - rmoon;
2362
+ for (k = 0; k < 3; k++) {
2363
+ x1[k] = xs[k] / ds /*ls[2]*/;
2364
+ x2[k] = xm[k] / dm /*lm[2]*/;
2365
+ }
2366
+ dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
2367
+ dc[i] = fabs(rsminusrm) - dctr;
2368
+ }
2369
+ dt1 = -dc[0] / ((dc[0] - dc[1]) / dt);
2370
+ tret[j] += dt1;
2371
+ }
2372
+ }
2373
+ tret[2] -= swe_deltat(tret[2]);
2374
+ tret[3] -= swe_deltat(tret[3]);
2375
+ }
2376
+ /* contacts 1 and 4 */
2377
+ dc[1] = rsplusrm - dctrmin;
2378
+ for (i = 0, t = tjd - twohr; i <= 2; i += 2, t = tjd + twohr) {
2379
+ if (calc_planet_star(t, ipl, starname, iflagcart, xs, serr) == ERR)
2380
+ return ERR;
2381
+ if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
2382
+ return ERR;
2383
+ dm = sqrt(square_sum(xm));
2384
+ ds = sqrt(square_sum(xs));
2385
+ rmoon = asin(RMOON / dm) * RADTODEG;
2386
+ rsun = asin(drad / ds) * RADTODEG;
2387
+ rsplusrm = rsun + rmoon;
2388
+ for (k = 0; k < 3; k++) {
2389
+ x1[k] = xs[k] / ds /*ls[2]*/;
2390
+ x2[k] = xm[k] / dm /*lm[2]*/;
2391
+ }
2392
+ dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
2393
+ dc[i] = rsplusrm - dctr;
2394
+ }
2395
+ find_zero(dc[0], dc[1], dc[2], twohr, &dt1, &dt2);
2396
+ tret[1] = tjd + dt1 + twohr;
2397
+ tret[4] = tjd + dt2 + twohr;
2398
+ for (m = 0, dt = tenmin; m < 3; m++, dt /= 10) {
2399
+ for (j = 1; j <= 4; j += 3) {
2400
+ if (calc_planet_star(tret[j], ipl, starname, iflagcart | SEFLG_SPEED, xs, serr) == ERR)
2401
+ return ERR;
2402
+ if (swe_calc(tret[j], SE_MOON, iflagcart | SEFLG_SPEED, xm, serr) == ERR)
2403
+ return ERR;
2404
+ for (i = 0; i < 2; i++) {
2405
+ if (i == 1) {
2406
+ for(k = 0; k < 3; k++) {
2407
+ xs[k] -= xs[k+3] * dt;
2408
+ xm[k] -= xm[k+3] * dt;
2409
+ }
2410
+ }
2411
+ dm = sqrt(square_sum(xm));
2412
+ ds = sqrt(square_sum(xs));
2413
+ rmoon = asin(RMOON / dm) * RADTODEG;
2414
+ rsun = asin(drad / ds) * RADTODEG;
2415
+ rsplusrm = rsun + rmoon;
2416
+ for (k = 0; k < 3; k++) {
2417
+ x1[k] = xs[k] / ds /*ls[2]*/;
2418
+ x2[k] = xm[k] / dm /*lm[2]*/;
2419
+ }
2420
+ dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
2421
+ dc[i] = fabs(rsplusrm) - dctr;
2422
+ }
2423
+ dt1 = -dc[0] / ((dc[0] - dc[1]) / dt);
2424
+ tret[j] += dt1;
2425
+ }
2426
+ }
2427
+ tret[1] -= swe_deltat(tret[1]);
2428
+ tret[4] -= swe_deltat(tret[4]);
2429
+ /*
2430
+ * visibility of eclipse phases
2431
+ */
2432
+ for (i = 4; i >= 0; i--) { /* attr for i = 0 must be kept !!! */
2433
+ if (tret[i] == 0)
2434
+ continue;
2435
+ if (eclipse_how(tret[i], ipl, starname, ifl, geopos[0], geopos[1], geopos[2],
2436
+ attr, serr) == ERR)
2437
+ return ERR;
2438
+ /*if (retflag2 & SE_ECL_VISIBLE) { could be wrong for 1st/4th contact */
2439
+ if (attr[5] > 0) { /* this is save, sun above horizon */
2440
+ retflag |= SE_ECL_VISIBLE;
2441
+ switch(i) {
2442
+ case 0: retflag |= SE_ECL_MAX_VISIBLE; break;
2443
+ case 1: retflag |= SE_ECL_1ST_VISIBLE; break;
2444
+ case 2: retflag |= SE_ECL_2ND_VISIBLE; break;
2445
+ case 3: retflag |= SE_ECL_3RD_VISIBLE; break;
2446
+ case 4: retflag |= SE_ECL_4TH_VISIBLE; break;
2447
+ default: break;
2448
+ }
2449
+ }
2450
+ }
2451
+ #if 1
2452
+ if (!(retflag & SE_ECL_VISIBLE)) {
2453
+ t = tjd + direction;
2454
+ goto next_try;
2455
+ }
2456
+ #endif
2457
+ return retflag;
2458
+ }
2459
+
2460
+ /*
2461
+ * swe_azalt()
2462
+ * Computes azimut and height, from either ecliptic or
2463
+ * equatorial coordinates
2464
+ *
2465
+ * input:
2466
+ * tjd_ut
2467
+ * iflag either SE_ECL2HOR or SE_EQU2HOR
2468
+ * geopos[3] geograph. longitude, latitude, height above sea
2469
+ * atpress atmospheric pressure at geopos in millibars (hPa)
2470
+ * attemp atmospheric temperature in degrees C
2471
+ * xin[2] input coordinates polar, in degrees
2472
+ *
2473
+ * Horizontal coordinates are returned in
2474
+ * xaz[3] xaz[0] = azimuth
2475
+ * xaz[1] = true altitude
2476
+ * xaz[2] = apparent altitude
2477
+ *
2478
+ * If atpress is not given (= 0), the programm assumes 1013.25 mbar;
2479
+ * if a non-zero height above sea is given, atpress is estimated.
2480
+ * geohgt height of observer above sea (optional)
2481
+ */
2482
+ void FAR PASCAL_CONV swe_azalt(
2483
+ double tjd_ut,
2484
+ int32 calc_flag,
2485
+ double *geopos,
2486
+ double atpress,
2487
+ double attemp,
2488
+ double *xin,
2489
+ double *xaz)
2490
+ {
2491
+ int i;
2492
+ double x[6], xra[3];
2493
+ double armc = swe_degnorm(swe_sidtime(tjd_ut) * 15 + geopos[0]);
2494
+ double mdd, eps_true, tjd_et;
2495
+ for (i = 0; i < 2; i++)
2496
+ xra[i] = xin[i];
2497
+ xra[2] = 1;
2498
+ if (calc_flag == SE_ECL2HOR) {
2499
+ tjd_et = tjd_ut + swe_deltat(tjd_ut);
2500
+ swe_calc(tjd_et, SE_ECL_NUT, 0, x, NULL);
2501
+ eps_true = x[0];
2502
+ swe_cotrans(xra, xra, -eps_true);
2503
+ }
2504
+ mdd = swe_degnorm(xra[0] - armc);
2505
+ x[0] = swe_degnorm(mdd - 90);
2506
+ x[1] = xra[1];
2507
+ x[2] = 1;
2508
+ /* azimuth from east, counterclock */
2509
+ swe_cotrans(x, x, 90 - geopos[1]);
2510
+ /* azimuth from south to west */
2511
+ x[0] = swe_degnorm(x[0] + 90);
2512
+ xaz[0] = 360 - x[0];
2513
+ xaz[1] = x[1]; /* true height */
2514
+ if (atpress == 0) {
2515
+ /* estimate atmospheric pressure */
2516
+ atpress = 1013.25 * pow(1 - 0.0065 * geopos[2] / 288, 5.255);
2517
+ }
2518
+ xaz[2] = swe_refrac_extended(x[1], geopos[2], atpress, attemp, const_lapse_rate, SE_TRUE_TO_APP, NULL);
2519
+ /* xaz[2] = swe_refrac_extended(xaz[2], geopos[2], atpress, attemp, const_lapse_rate, SE_APP_TO_TRUE, NULL);*/
2520
+ }
2521
+
2522
+ /*
2523
+ * swe_azalt_rev()
2524
+ * computes either ecliptical or equatorial coordinates from
2525
+ * azimuth and true altitude in degrees.
2526
+ * For conversion between true and apparent altitude, there is
2527
+ * the function swe_refrac().
2528
+ *
2529
+ * input:
2530
+ * tjd_ut
2531
+ * iflag either SE_HOR2ECL or SE_HOR2EQU
2532
+ * xin[2] azimut and true altitude, in degrees
2533
+ */
2534
+ void FAR PASCAL_CONV swe_azalt_rev(
2535
+ double tjd_ut,
2536
+ int32 calc_flag,
2537
+ double *geopos,
2538
+ double *xin,
2539
+ double *xout)
2540
+ {
2541
+ int i;
2542
+ double x[6], xaz[3];
2543
+ double geolon = geopos[0];
2544
+ double geolat = geopos[1];
2545
+ double armc = swe_degnorm(swe_sidtime(tjd_ut) * 15 + geolon);
2546
+ double eps_true, tjd_et, dang;
2547
+ for (i = 0; i < 2; i++)
2548
+ xaz[i] = xin[i];
2549
+ xaz[2] = 1;
2550
+ /* azimuth is from south, clockwise.
2551
+ * we need it from east, counterclock */
2552
+ xaz[0] = 360 - xaz[0];
2553
+ xaz[0] = swe_degnorm(xaz[0] - 90);
2554
+ /* equatorial positions */
2555
+ dang = geolat - 90;
2556
+ swe_cotrans(xaz, xaz, dang);
2557
+ xaz[0] = swe_degnorm(xaz[0] + armc + 90);
2558
+ xout[0] = xaz[0];
2559
+ xout[1] = xaz[1];
2560
+ /* ecliptic positions */
2561
+ if (calc_flag == SE_HOR2ECL) {
2562
+ tjd_et = tjd_ut + swe_deltat(tjd_ut);
2563
+ swe_calc(tjd_et, SE_ECL_NUT, 0, x, NULL);
2564
+ eps_true = x[0];
2565
+ swe_cotrans(xaz, x, eps_true);
2566
+ xout[0] = x[0];
2567
+ xout[1] = x[1];
2568
+ }
2569
+ }
2570
+
2571
+ /* swe_refrac()
2572
+ * Transforms apparent to true altitude and vice-versa.
2573
+ * These formulae do not handle the case when the
2574
+ * sun is visible below the geometrical horizon
2575
+ * (from a mountain top or an air plane)
2576
+ * input:
2577
+ * double inalt; * altitude of object in degrees *
2578
+ * double atpress; * millibars (hectopascal) *
2579
+ * double attemp; * degrees C *
2580
+ * int32 calc_flag; * either SE_CALC_APP_TO_TRUE or
2581
+ * * SE_CALC_TRUE_TO_APP
2582
+ */
2583
+ double FAR PASCAL_CONV swe_refrac(double inalt, double atpress, double attemp, int32 calc_flag)
2584
+ {
2585
+ double a, refr;
2586
+ double pt_factor = atpress / 1010.0 * 283.0 / (273.0 + attemp);
2587
+ double trualt, appalt;
2588
+ #if 0
2589
+ /*
2590
+ * -- S. L. Moshier */
2591
+ double y, yy0, D0, N, D, P, Q;
2592
+ int i;
2593
+ if (calc_flag == SE_TRUE_TO_APP) {
2594
+ trualt = inalt;
2595
+ if( (trualt < -2.0) || (trualt >= 90.0) )
2596
+ return(trualt);
2597
+ /* For high altitude angle, AA page B61
2598
+ * Accuracy "usually about 0.1' ".
2599
+ */
2600
+ if( trualt > 15.0 ) {
2601
+ D = 0.00452*atpress/((273.0+attemp)*tan( DEGTORAD*trualt ));
2602
+ return(trualt + D);
2603
+ }
2604
+ /* Formula for low altitude is from the Almanac for Computers.
2605
+ * It gives the correction for observed altitude, so has
2606
+ * to be inverted numerically to get the observed from the true.
2607
+ * Accuracy about 0.2' for -20C < T < +40C and 970mb < P < 1050mb.
2608
+ */
2609
+ /* Start iteration assuming correction = 0
2610
+ */
2611
+ y = trualt;
2612
+ D = 0.0;
2613
+ /* Invert Almanac for Computers formula numerically
2614
+ */
2615
+ P = (atpress - 80.0)/930.0;
2616
+ Q = 4.8e-3 * (attemp - 10.0);
2617
+ yy0 = y;
2618
+ D0 = D;
2619
+ for( i=0; i<4; i++ ) {
2620
+ N = y + (7.31/(y+4.4));
2621
+ N = 1.0/tan(DEGTORAD*N);
2622
+ D = N*P/(60.0 + Q * (N + 39.0));
2623
+ N = y - yy0;
2624
+ yy0 = D - D0 - N; /* denominator of derivative */
2625
+ if( (N != 0.0) && (yy0 != 0.0) )
2626
+ /* Newton iteration with numerically estimated derivative */
2627
+ N = y - N*(trualt + D - y)/yy0;
2628
+ else
2629
+ /* Can't do it on first pass */
2630
+ N = trualt + D;
2631
+ yy0 = y;
2632
+ D0 = D;
2633
+ y = N;
2634
+ }
2635
+ return( trualt + D );
2636
+ } else {
2637
+ #else
2638
+ /* another algorithm, from Meeus, German, p. 114ff.
2639
+ */
2640
+ if (calc_flag == SE_TRUE_TO_APP) {
2641
+ trualt = inalt;
2642
+ if (trualt > 15) {
2643
+ a = tan((90 - trualt) * DEGTORAD);
2644
+ refr = (58.276 * a - 0.0824 * a * a * a);
2645
+ refr *= pt_factor / 3600.0;
2646
+ } else if (trualt > -5) {
2647
+ /* the following tan is not defined for a value
2648
+ * of trualt near -5.00158 and 89.89158 */
2649
+ a = trualt + 10.3 / (trualt + 5.11);
2650
+ if (a + 1e-10 >= 90)
2651
+ refr = 0;
2652
+ else
2653
+ refr = 1.02 / tan(a * DEGTORAD);
2654
+ refr *= pt_factor / 60.0;
2655
+ } else
2656
+ refr = 0;
2657
+ appalt = trualt;
2658
+ if (appalt + refr > 0)
2659
+ appalt += refr;
2660
+ return appalt;
2661
+ } else {
2662
+ #endif
2663
+ /* apparent to true */
2664
+ appalt = inalt;
2665
+ /* the following tan is not defined for a value
2666
+ * of inalt near -4.3285 and 89.9225 */
2667
+ a = appalt + 7.31 / (appalt + 4.4);
2668
+ if (a + 1e-10 >= 90)
2669
+ refr = 0;
2670
+ else {
2671
+ refr = 1.00 / tan(a * DEGTORAD);
2672
+ refr -= 0.06 * sin(14.7 * refr + 13);
2673
+ }
2674
+ refr *= pt_factor / 60.0;
2675
+ trualt = appalt;
2676
+ if (appalt - refr > 0)
2677
+ trualt = appalt - refr;
2678
+ return trualt;
2679
+ }
2680
+ }
2681
+
2682
+ void FAR PASCAL_CONV swe_set_lapse_rate(double lapse_rate)
2683
+ {
2684
+ const_lapse_rate = lapse_rate;
2685
+ }
2686
+
2687
+ /* swe_refrac_extended()
2688
+ *
2689
+ * This function was created thanks to and with consultation with the
2690
+ * archaeoastronomer Victor Reijs.
2691
+ * It is more correct and more skilled than the old function swe_refrac():
2692
+ * - it allows correct calculation of refraction for altitudes above sea > 0,
2693
+ * where the ideal horizon and planets that are visible may have a
2694
+ * negative height. (for swe_refrac(), negative apparent heights do not
2695
+ * exist!)
2696
+ * - it allows to manipulate the refraction constant
2697
+ *
2698
+ * Transforms apparent to true altitude and vice-versa.
2699
+ * input:
2700
+ * double inalt; * altitude of object above geometric horizon in degrees*
2701
+ * * geometric horizon = plane perpendicular to gravity *
2702
+ * double geoalt; * altitude of observer above sea level in meters *
2703
+ * double atpress; * millibars (hectopascal) *
2704
+ * double lapse_rate; * (dT/dh) [deg K/m]
2705
+ * double attemp; * degrees C *
2706
+ * int32 calc_flag; * either SE_CALC_APP_TO_TRUE or
2707
+ * * SE_CALC_TRUE_TO_APP
2708
+ *
2709
+ * function returns:
2710
+ * case 1, conversion from true altitude to apparent altitude
2711
+ * - apparent altitude, if body appears above is observable above ideal horizon
2712
+ * - true altitude (the input value), otherwise
2713
+ * "ideal horizon" is the horizon as seen above an ideal sphere (as seen
2714
+ * from a plane over the ocean with a clear sky)
2715
+ * case 2, conversion from apparent altitude to true altitude
2716
+ * - the true altitude resulting from the input apparent altitude, if this value
2717
+ * is a plausible apparent altitude, i.e. if it is a position above the ideal
2718
+ * horizon
2719
+ * - the input altitude otherwise
2720
+ *
2721
+ * in addition the array dret[] is given the following values
2722
+ * - dret[0] true altitude, if possible; otherwise input value
2723
+ * - dret[1] apparent altitude, if possible; otherwise input value
2724
+ * - dret[2] refraction
2725
+ * - dret[3] dip of the horizon
2726
+ *
2727
+ * The body is above the horizon if the dret[0] != dret[1]
2728
+ */
2729
+ double FAR PASCAL_CONV swe_refrac_extended(double inalt, double geoalt, double atpress, double attemp, double lapse_rate, int32 calc_flag, double *dret)
2730
+ {
2731
+ double refr;
2732
+ double trualt;
2733
+ double dip = calc_dip(geoalt, atpress, attemp, lapse_rate);
2734
+ double D, D0, N, y, yy0;
2735
+ int i;
2736
+ /* make sure that inalt <=90 */
2737
+ if( (inalt>90) )
2738
+ inalt=180-inalt;
2739
+ if (calc_flag == SE_TRUE_TO_APP) {
2740
+ if (inalt < -10) {
2741
+ if (dret != NULL) {
2742
+ dret[0]=inalt;
2743
+ dret[1]=inalt;
2744
+ dret[2]=0;
2745
+ dret[3]=dip;
2746
+ }
2747
+ return inalt;
2748
+ }
2749
+ /* by iteration */
2750
+ y = inalt;
2751
+ D = 0.0;
2752
+ yy0 = 0;
2753
+ D0 = D;
2754
+ for(i=0; i<5; i++) {
2755
+ D = calc_astronomical_refr(y,atpress,attemp);
2756
+ N = y - yy0;
2757
+ yy0 = D - D0 - N; /* denominator of derivative */
2758
+ if (N != 0.0 && yy0 != 0.0) /* sic !!! code by Moshier */
2759
+ N = y - N*(inalt + D - y)/yy0; /* Newton iteration with numerically estimated derivative */
2760
+ else /* Can't do it on first pass */
2761
+ N = inalt + D;
2762
+ yy0 = y;
2763
+ D0 = D;
2764
+ y = N;
2765
+ }
2766
+ refr = D;
2767
+ if( (inalt + refr < dip) ) {
2768
+ if (dret != NULL) {
2769
+ dret[0]=inalt;
2770
+ dret[1]=inalt;
2771
+ dret[2]=0;
2772
+ dret[3]=dip;
2773
+ }
2774
+ return inalt;
2775
+ }
2776
+ if (dret != NULL) {
2777
+ dret[0]=inalt;
2778
+ dret[1]=inalt+refr;
2779
+ dret[2]=refr;
2780
+ dret[3]=dip;
2781
+ }
2782
+ return inalt+refr;
2783
+ } else {
2784
+ refr = calc_astronomical_refr(inalt,atpress,attemp);
2785
+ trualt=inalt-refr;
2786
+ if (dret != NULL) {
2787
+ if (inalt > dip) {
2788
+ dret[0]=trualt;
2789
+ dret[1]=inalt;
2790
+ dret[2]=refr;
2791
+ dret[3]=dip;
2792
+ } else {
2793
+ dret[0]=inalt;
2794
+ dret[1]=inalt;
2795
+ dret[2]=0;
2796
+ dret[3]=dip;
2797
+ }
2798
+ }
2799
+ if (trualt > dip)
2800
+ return trualt;
2801
+ else
2802
+ return inalt;
2803
+ }
2804
+ }
2805
+
2806
+ /* calculate the astronomical refraction
2807
+ * input parameters:
2808
+ * double inalt * apparent altitude of object
2809
+ * double atpress * atmospheric pressure millibars (hectopascal) *
2810
+ * double attemp * atmospheric temperature degrees C *
2811
+ * returns double r in degrees
2812
+ */
2813
+ static double calc_astronomical_refr(double inalt,double atpress, double attemp)
2814
+ {
2815
+ #if 0
2816
+ /* formula based on G.G. Bennett, The calculation of astronomical refraction in marine navigation,
2817
+ * Journal of Inst. Navigation, No. 35, page 255-259, 1982,
2818
+ * page 257 for refraction formula: formula H
2819
+ * and page 259 for atmospheric compensation
2820
+ */
2821
+ double refractaccent = 1/tan(DEGTORAD*(inalt + 7.31/(inalt+4.4)));
2822
+ double r = (refractaccent - 0.06 * sin(DEGTORAD*(14.7*refractaccent +13)));
2823
+ r = ((atpress - 80) / 930 / (1 + 0.00008 * (r + 39) * (attemp - 10)) * r)/60;
2824
+ return r;
2825
+ #else
2826
+ /* Formula by Sinclair, see article mentioned above, p. 256. Better for
2827
+ * apparent altitudes < 0; */
2828
+ double r;
2829
+ if (inalt > 17.904104638432) { /* for continuous function, instead of '>15' */
2830
+ r = 0.97 / tan(inalt * DEGTORAD);
2831
+ } else {
2832
+ r = (34.46 + 4.23 * inalt + 0.004 * inalt * inalt) / (1 + 0.505 * inalt + 0.0845 * inalt * inalt);
2833
+ }
2834
+ r = ((atpress - 80) / 930 / (1 + 0.00008 * (r + 39) * (attemp - 10)) * r) / 60.0;
2835
+ return r;
2836
+ #endif
2837
+ }
2838
+
2839
+ /* calculate dip of the horizon
2840
+ * input parameters:
2841
+ * double geoalt * altitude of observer above sea level in meters *
2842
+ * double atpress * atmospheric pressure millibars (hectopascal) *
2843
+ * double attemp * atmospheric temperature degrees C *
2844
+ * double lapse_rate * (dT/dh) [deg K/m]
2845
+ * returns dip in degrees
2846
+ */
2847
+ static double calc_dip(double geoalt, double atpress, double attemp, double lapse_rate)
2848
+ {
2849
+ /* below formula is based on A. Thom, Megalithic lunar observations, 1973 (page 32).
2850
+ * conversion to metric has been done by
2851
+ * V. Reijs, 2000, http://www.iol.ie/~geniet/eng/refract.htm
2852
+ */
2853
+ double krefr = (0.0342 + lapse_rate) / (0.154 * 0.0238);
2854
+ double d = 1-1.8480*krefr*atpress/(273.16+attemp)/(273.16+attemp);
2855
+ /* return -0.03203*sqrt(geoalt)*sqrt(d); */
2856
+ /* double a = acos(1/(1+geoalt/EARTH_RADIUS));*/
2857
+ return -180.0/PI * acos(1 / (1 + geoalt / EARTH_RADIUS)) * sqrt(d);
2858
+ }
2859
+
2860
+
2861
+ /* Computes attributes of a lunar eclipse for given tjd and geopos
2862
+ *
2863
+ * retflag SE_ECL_TOTAL or SE_ECL_PARTIAL
2864
+ * SE_ECL_PENUMBRAL
2865
+ * if 0, there is no eclipse
2866
+ *
2867
+ * attr[0] umbral magnitude at tjd
2868
+ * attr[1] penumbral magnitude
2869
+ #if 0 not implemented so far
2870
+ * attr[4] azimuth of moon at tjd
2871
+ * attr[5] true altitude of moon above horizon at tjd
2872
+ * attr[6] apparent altitude of moon above horizon at tjd
2873
+ #endif
2874
+ * attr[7] distance of moon from opposition in degrees
2875
+ * attr[8] umbral magnitude at tjd (= attr[0])
2876
+ * attr[9] saros series number
2877
+ * attr[10] saros series member number
2878
+ * declare as attr[20] at least !
2879
+ *
2880
+ */
2881
+ int32 FAR PASCAL_CONV swe_lun_eclipse_how(
2882
+ double tjd_ut,
2883
+ int32 ifl,
2884
+ double *geopos,
2885
+ double *attr,
2886
+ char *serr)
2887
+ {
2888
+ double dcore[10];
2889
+ /* attention: geopos[] is not used so far; may be NULL */
2890
+ if (geopos != NULL)
2891
+ geopos[0] = geopos[0]; /* to shut up mint */
2892
+ ifl = ifl & ~SEFLG_TOPOCTR;
2893
+ return lun_eclipse_how(tjd_ut, ifl, attr, dcore, serr);
2894
+ }
2895
+
2896
+ /*
2897
+ * attr[]: see swe_lun_eclipse_how()
2898
+ *
2899
+ * dcore[0]: distance of shadow axis from geocenter r0
2900
+ * dcore[1]: diameter of core shadow on fundamental plane d0
2901
+ * dcore[2]: diameter of half-shadow on fundamental plane D0
2902
+ */
2903
+ static int32 lun_eclipse_how(
2904
+ double tjd_ut,
2905
+ int32 ifl,
2906
+ double *attr,
2907
+ double *dcore,
2908
+ char *serr)
2909
+ {
2910
+ int i, j, k;
2911
+ int32 retc = 0;
2912
+ double e[6], rm[6], rs[6];
2913
+ double dsm, d0, D0, s0, r0, ds, dm;
2914
+ double dctr, x1[6], x2[6];
2915
+ double f1, f2;
2916
+ double deltat, tjd, d;
2917
+ double cosf1, cosf2;
2918
+ int32 iflag;
2919
+ for (i = 0; i < 10; i++)
2920
+ dcore[i] = 0;
2921
+ for (i = 0; i < 20; i++)
2922
+ attr[i] = 0;
2923
+ /* nutation need not be in lunar and solar positions,
2924
+ * if mean sidereal time will be used */
2925
+ iflag = SEFLG_SPEED | SEFLG_EQUATORIAL | ifl;
2926
+ iflag = iflag | SEFLG_XYZ;
2927
+ deltat = swe_deltat(tjd_ut);
2928
+ tjd = tjd_ut + deltat;
2929
+ /* moon in cartesian coordinates */
2930
+ if (swe_calc(tjd, SE_MOON, iflag, rm, serr) == ERR)
2931
+ return ERR;
2932
+ /* distance of moon from geocenter */
2933
+ dm = sqrt(square_sum(rm));
2934
+ /* sun in cartesian coordinates */
2935
+ if (swe_calc(tjd, SE_SUN, iflag, rs, serr) == ERR)
2936
+ return ERR;
2937
+ /* distance of sun from geocenter */
2938
+ ds = sqrt(square_sum(rs));
2939
+ for (i = 0; i < 3; i++) {
2940
+ x1[i] = rs[i] / ds;
2941
+ x2[i] = rm[i] / dm;
2942
+ }
2943
+ dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
2944
+ /* selenocentric sun */
2945
+ for (i = 0; i <= 2; i++)
2946
+ rs[i] -= rm[i];
2947
+ /* selenocentric earth */
2948
+ for (i = 0; i <= 2; i++)
2949
+ rm[i] = -rm[i];
2950
+ /* sun - earth vector */
2951
+ for (i = 0; i <= 2; i++)
2952
+ e[i] = (rm[i] - rs[i]);
2953
+ /* distance sun - earth */
2954
+ dsm = sqrt(square_sum(e));
2955
+ /* sun - earth unit vector */
2956
+ for (i = 0; i <= 2; i++)
2957
+ e[i] /= dsm;
2958
+ f1 = ((RSUN - REARTH) / dsm);
2959
+ cosf1 = sqrt(1 - f1 * f1);
2960
+ f2 = ((RSUN + REARTH) / dsm);
2961
+ cosf2 = sqrt(1 - f2 * f2);
2962
+ /* distance of earth from fundamental plane */
2963
+ s0 = -dot_prod(rm, e);
2964
+ /* distance of shadow axis from selenocenter */
2965
+ r0 = sqrt(dm * dm - s0 * s0);
2966
+ /* diameter of core shadow on fundamental plane */
2967
+ d0 = fabs(s0 / dsm * (DSUN - DEARTH) - DEARTH) * (1 + 1.0 / 50) / cosf1;
2968
+ /* one 50th is added for effect of atmosphere, AA98, L4 */
2969
+ /* diameter of half-shadow on fundamental plane */
2970
+ D0 = (s0 / dsm * (DSUN + DEARTH) + DEARTH) * (1 + 1.0 / 50) / cosf2;
2971
+ d0 /= cosf1;
2972
+ D0 /= cosf2;
2973
+ dcore[0] = r0;
2974
+ dcore[1] = d0;
2975
+ dcore[2] = D0;
2976
+ dcore[3] = cosf1;
2977
+ dcore[4] = cosf2;
2978
+ /**************************
2979
+ * phase and umbral magnitude
2980
+ **************************/
2981
+ retc = 0;
2982
+ if (d0 / 2 >= r0 + RMOON / cosf1) {
2983
+ retc = SE_ECL_TOTAL;
2984
+ attr[0] = (d0 / 2 - r0 + RMOON) / DMOON;
2985
+ } else if (d0 / 2 >= r0 - RMOON / cosf1) {
2986
+ retc = SE_ECL_PARTIAL;
2987
+ attr[0] = (d0 / 2 - r0 + RMOON) / DMOON;
2988
+ } else if (D0 / 2 >= r0 - RMOON / cosf2) {
2989
+ retc = SE_ECL_PENUMBRAL;
2990
+ attr[0] = 0;
2991
+ } else {
2992
+ if (serr != NULL)
2993
+ sprintf(serr, "no lunar eclipse at tjd = %f", tjd);
2994
+ }
2995
+ attr[8] = attr[0];
2996
+ /**************************
2997
+ * penumbral magnitude
2998
+ **************************/
2999
+ attr[1] = (D0 / 2 - r0 + RMOON) / DMOON;
3000
+ if (retc != 0)
3001
+ attr[7] = 180 - fabs(dctr);
3002
+ /* saros series and member */
3003
+ for (i = 0; i < NSAROS_LUNAR; i++) {
3004
+ d = (tjd_ut - saros_data_lunar[i].tstart) / SAROS_CYCLE;
3005
+ if (d < 0) continue;
3006
+ j = (int) d;
3007
+ if ((d - j) * SAROS_CYCLE < 2) {
3008
+ attr[9] = (double) saros_data_lunar[i].series_no;
3009
+ attr[10] = (double) j + 1;
3010
+ break;
3011
+ }
3012
+ k = j + 1;
3013
+ if ((k - d) * SAROS_CYCLE < 2) {
3014
+ attr[9] = (double) saros_data_lunar[i].series_no;
3015
+ attr[10] = (double) k + 1;
3016
+ break;
3017
+ }
3018
+ }
3019
+ if (i == NSAROS_LUNAR) {
3020
+ attr[9] = attr[10] = -99999999;
3021
+ }
3022
+ return retc;
3023
+ }
3024
+
3025
+ /* When is the next lunar eclipse?
3026
+ *
3027
+ * retflag SE_ECL_TOTAL or SE_ECL_PENUMBRAL or SE_ECL_PARTIAL
3028
+ *
3029
+ * tret[0] time of maximum eclipse
3030
+ * tret[1]
3031
+ * tret[2] time of partial phase begin (indices consistent with solar eclipses)
3032
+ * tret[3] time of partial phase end
3033
+ * tret[4] time of totality begin
3034
+ * tret[5] time of totality end
3035
+ * tret[6] time of penumbral phase begin
3036
+ * tret[7] time of penumbral phase end
3037
+ */
3038
+ int32 FAR PASCAL_CONV swe_lun_eclipse_when(double tjd_start, int32 ifl, int32 ifltype,
3039
+ double *tret, int32 backward, char *serr)
3040
+ {
3041
+ int i, j, m, n, o, i1 = 0, i2 = 0;
3042
+ int32 retflag = 0, retflag2 = 0;
3043
+ double t, tjd, dt, dtint, dta, dtb;
3044
+ double T, T2, T3, T4, K, F, M, Mm;
3045
+ double E, Ff, F1, A1, Om;
3046
+ double xs[6], xm[6], dm, ds;
3047
+ double rsun, rearth, dcore[10];
3048
+ double dc[3], dctr;
3049
+ double twohr = 2.0 / 24.0;
3050
+ double tenmin = 10.0 / 24.0 / 60.0;
3051
+ double dt1, dt2;
3052
+ double kk;
3053
+ double attr[20];
3054
+ double dtstart, dtdiv;
3055
+ double xa[6], xb[6];
3056
+ int direction = 1;
3057
+ int32 iflag;
3058
+ int32 iflagcart;
3059
+ ifl &= SEFLG_EPHMASK;
3060
+ iflag = SEFLG_EQUATORIAL | ifl;
3061
+ iflagcart = iflag | SEFLG_XYZ;
3062
+ if (ifltype == 0)
3063
+ ifltype = SE_ECL_TOTAL | SE_ECL_PENUMBRAL | SE_ECL_PARTIAL;
3064
+ if (backward)
3065
+ direction = -1;
3066
+ K = (int) ((tjd_start - J2000) / 365.2425 * 12.3685);
3067
+ K -= direction;
3068
+ next_try:
3069
+ retflag = 0;
3070
+ for (i = 0; i <= 9; i++)
3071
+ tret[i] = 0;
3072
+ kk = K + 0.5;
3073
+ T = kk / 1236.85;
3074
+ T2 = T * T; T3 = T2 * T; T4 = T3 * T;
3075
+ Ff = F = swe_degnorm(160.7108 + 390.67050274 * kk
3076
+ - 0.0016341 * T2
3077
+ - 0.00000227 * T3
3078
+ + 0.000000011 * T4);
3079
+ if (Ff > 180)
3080
+ Ff -= 180;
3081
+ if (Ff > 21 && Ff < 159) { /* no eclipse possible */
3082
+ K += direction;
3083
+ goto next_try;
3084
+ }
3085
+ /* approximate time of geocentric maximum eclipse
3086
+ * formula from Meeus, German, p. 381 */
3087
+ tjd = 2451550.09765 + 29.530588853 * kk
3088
+ + 0.0001337 * T2
3089
+ - 0.000000150 * T3
3090
+ + 0.00000000073 * T4;
3091
+ M = swe_degnorm(2.5534 + 29.10535669 * kk
3092
+ - 0.0000218 * T2
3093
+ - 0.00000011 * T3);
3094
+ Mm = swe_degnorm(201.5643 + 385.81693528 * kk
3095
+ + 0.1017438 * T2
3096
+ + 0.00001239 * T3
3097
+ + 0.000000058 * T4);
3098
+ Om = swe_degnorm(124.7746 - 1.56375580 * kk
3099
+ + 0.0020691 * T2
3100
+ + 0.00000215 * T3);
3101
+ E = 1 - 0.002516 * T - 0.0000074 * T2;
3102
+ A1 = swe_degnorm(299.77 + 0.107408 * kk - 0.009173 * T2);
3103
+ M *= DEGTORAD;
3104
+ Mm *= DEGTORAD;
3105
+ F *= DEGTORAD;
3106
+ Om *= DEGTORAD;
3107
+ F1 = F - 0.02665 * sin(Om) * DEGTORAD;
3108
+ A1 *= DEGTORAD;
3109
+ tjd = tjd - 0.4075 * sin(Mm)
3110
+ + 0.1721 * E * sin(M)
3111
+ + 0.0161 * sin(2 * Mm)
3112
+ - 0.0097 * sin(2 * F1)
3113
+ + 0.0073 * E * sin(Mm - M)
3114
+ - 0.0050 * E * sin(Mm + M)
3115
+ - 0.0023 * sin(Mm - 2 * F1)
3116
+ + 0.0021 * E * sin(2 * M)
3117
+ + 0.0012 * sin(Mm + 2 * F1)
3118
+ + 0.0006 * E * sin(2 * Mm + M)
3119
+ - 0.0004 * sin(3 * Mm)
3120
+ - 0.0003 * E * sin(M + 2 * F1)
3121
+ + 0.0003 * sin(A1)
3122
+ - 0.0002 * E * sin(M - 2 * F1)
3123
+ - 0.0002 * E * sin(2 * Mm - M)
3124
+ - 0.0002 * sin(Om);
3125
+ /*
3126
+ * precise computation:
3127
+ * time of maximum eclipse (if eclipse) =
3128
+ * minimum selenocentric angle between sun and earth edges.
3129
+ * After this time has been determined, check
3130
+ * whether or not an eclipse is taking place with
3131
+ * the function lun_eclipse_how().
3132
+ */
3133
+ dtstart = 0.1;
3134
+ if (tjd < 2000000)
3135
+ dtstart = 5;
3136
+ dtdiv = 4;
3137
+ for (j = 0, dt = dtstart;
3138
+ dt > 0.001;
3139
+ j++, dt /= dtdiv) {
3140
+ for (i = 0, t = tjd - dt; i <= 2; i++, t += dt) {
3141
+ if (swe_calc(t, SE_SUN, iflagcart, xs, serr) == ERR)
3142
+ return ERR;
3143
+ if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
3144
+ return ERR;
3145
+ for (m = 0; m < 3; m++) {
3146
+ xs[m] -= xm[m]; /* selenocentric sun */
3147
+ xm[m] = -xm[m]; /* selenocentric earth */
3148
+ }
3149
+ ds = sqrt(square_sum(xs));
3150
+ dm = sqrt(square_sum(xm));
3151
+ for (m = 0; m < 3; m++) {
3152
+ xa[m] = xs[m] / ds;
3153
+ xb[m] = xm[m] / dm;
3154
+ }
3155
+ dc[i] = acos(swi_dot_prod_unit(xa, xb)) * RADTODEG;
3156
+ rearth = asin(REARTH / dm) * RADTODEG;
3157
+ rsun = asin(RSUN / ds) * RADTODEG;
3158
+ dc[i] -= (rearth + rsun);
3159
+ }
3160
+ find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dctr);
3161
+ tjd += dtint + dt;
3162
+ }
3163
+ tjd = tjd - swe_deltat(tjd);
3164
+ if ((retflag = swe_lun_eclipse_how(tjd, ifl, NULL, attr, serr)) == ERR)
3165
+ return retflag;
3166
+ if (retflag == 0) {
3167
+ K += direction;
3168
+ goto next_try;
3169
+ }
3170
+ tret[0] = tjd;
3171
+ if ((backward && tret[0] >= tjd_start - 0.0001)
3172
+ || (!backward && tret[0] <= tjd_start + 0.0001)) {
3173
+ K += direction;
3174
+ goto next_try;
3175
+ }
3176
+ /*
3177
+ * check whether or not eclipse type found is wanted
3178
+ */
3179
+ /* non penumbral eclipse is wanted: */
3180
+ if (!(ifltype & SE_ECL_PENUMBRAL) && (retflag & SE_ECL_PENUMBRAL)) {
3181
+ K += direction;
3182
+ goto next_try;
3183
+ }
3184
+ /* non partial eclipse is wanted: */
3185
+ if (!(ifltype & SE_ECL_PARTIAL) && (retflag & SE_ECL_PARTIAL)) {
3186
+ K += direction;
3187
+ goto next_try;
3188
+ }
3189
+ /* annular-total eclipse will be discovered later */
3190
+ if (!(ifltype & (SE_ECL_TOTAL)) && (retflag & SE_ECL_TOTAL)) {
3191
+ K += direction;
3192
+ goto next_try;
3193
+ }
3194
+ /*
3195
+ * n = 0: times of eclipse begin and end
3196
+ * n = 1: times of totality begin and end
3197
+ * n = 2: times of center line begin and end
3198
+ */
3199
+ if (retflag & SE_ECL_PENUMBRAL)
3200
+ o = 0;
3201
+ else if (retflag & SE_ECL_PARTIAL)
3202
+ o = 1;
3203
+ else
3204
+ o = 2;
3205
+ dta = twohr;
3206
+ dtb = tenmin;
3207
+ for (n = 0; n <= o; n++) {
3208
+ if (n == 0) {
3209
+ i1 = 6; i2 = 7;
3210
+ } else if (n == 1) {
3211
+ i1 = 2; i2 = 3;
3212
+ } else if (n == 2) {
3213
+ i1 = 4; i2 = 5;
3214
+ }
3215
+ #if 1
3216
+ for (i = 0, t = tjd - dta; i <= 2; i += 1, t += dta) {
3217
+ if ((retflag2 = lun_eclipse_how(t, ifl, attr, dcore, serr)) == ERR)
3218
+ return retflag2;
3219
+ if (n == 0)
3220
+ dc[i] = dcore[2] / 2 + RMOON / dcore[4] - dcore[0];
3221
+ else if (n == 1)
3222
+ dc[i] = dcore[1] / 2 + RMOON / dcore[3] - dcore[0];
3223
+ else if (n == 2)
3224
+ dc[i] = dcore[1] / 2 - RMOON / dcore[3] - dcore[0];
3225
+ }
3226
+ find_zero(dc[0], dc[1], dc[2], dta, &dt1, &dt2);
3227
+ dtb = (dt1 + dta) / 2;
3228
+ tret[i1] = tjd + dt1 + dta;
3229
+ tret[i2] = tjd + dt2 + dta;
3230
+ #else
3231
+ tret[i1] = tjd - dtb;
3232
+ tret[i2] = tjd + dtb;
3233
+ #endif
3234
+ for (m = 0, dt = dtb / 2; m < 3; m++, dt /= 2) {
3235
+ for (j = i1; j <= i2; j += (i2 - i1)) {
3236
+ for (i = 0, t = tret[j] - dt; i < 2; i++, t += dt) {
3237
+ if ((retflag2 = lun_eclipse_how(t, ifl, attr, dcore, serr)) == ERR)
3238
+ return retflag2;
3239
+ if (n == 0)
3240
+ dc[i] = dcore[2] / 2 + RMOON / dcore[4] - dcore[0];
3241
+ else if (n == 1)
3242
+ dc[i] = dcore[1] / 2 + RMOON / dcore[3] - dcore[0];
3243
+ else if (n == 2)
3244
+ dc[i] = dcore[1] / 2 - RMOON / dcore[3] - dcore[0];
3245
+ }
3246
+ dt1 = dc[1] / ((dc[1] - dc[0]) / dt);
3247
+ tret[j] -= dt1;
3248
+ }
3249
+ }
3250
+ }
3251
+ return retflag;
3252
+ }
3253
+
3254
+ /*
3255
+ * function calculates planetary phenomena
3256
+ *
3257
+ * attr[0] = phase angle (earth-planet-sun)
3258
+ * attr[1] = phase (illumined fraction of disc)
3259
+ * attr[2] = elongation of planet
3260
+ * attr[3] = apparent diameter of disc
3261
+ * attr[4] = apparent magnitude
3262
+ * attr[5] = geocentric horizontal parallax (Moon)
3263
+ * declare as attr[20] at least !
3264
+ *
3265
+ * Note: the lunar magnitude is quite a complicated thing,
3266
+ * but our algorithm is very simple.
3267
+ * The phase of the moon, its distance from the earth and
3268
+ * the sun is considered, but no other factors.
3269
+ *
3270
+ */
3271
+ #define EULER 2.718281828459
3272
+ #define NMAG_ELEM (SE_VESTA + 1)
3273
+ static double mag_elem[NMAG_ELEM][4] = {
3274
+ /* DTV-Atlas Astronomie, p. 32 */
3275
+ {-26.86, 0, 0, 0},
3276
+ {-12.55, 0, 0, 0},
3277
+ /* IAU 1986 */
3278
+ {-0.42, 3.80, -2.73, 2.00},
3279
+ {-4.40, 0.09, 2.39, -0.65},
3280
+ {- 1.52, 1.60, 0, 0}, /* Mars */
3281
+ {- 9.40, 0.5, 0, 0}, /* Jupiter */
3282
+ {- 8.88, -2.60, 1.25, 0.044}, /* Saturn */
3283
+ {- 7.19, 0.0, 0, 0}, /* Uranus */
3284
+ {- 6.87, 0.0, 0, 0}, /* Neptune */
3285
+ {- 1.00, 0.0, 0, 0}, /* Pluto */
3286
+ {99, 0, 0, 0}, /* nodes and apogees */
3287
+ {99, 0, 0, 0},
3288
+ {99, 0, 0, 0},
3289
+ {99, 0, 0, 0},
3290
+ {99, 0, 0, 0}, /* Earth */
3291
+ /* from Bowell data base */
3292
+ {6.5, 0.15, 0, 0}, /* Chiron */
3293
+ {7.0, 0.15, 0, 0}, /* Pholus */
3294
+ {3.34, 0.12, 0, 0}, /* Ceres */
3295
+ {4.13, 0.11, 0, 0}, /* Pallas */
3296
+ {5.33, 0.32, 0, 0}, /* Juno */
3297
+ {3.20, 0.32, 0, 0}, /* Vesta */
3298
+ };
3299
+ int32 FAR PASCAL_CONV swe_pheno(double tjd, int32 ipl, int32 iflag, double *attr, char *serr)
3300
+ {
3301
+ int i;
3302
+ double xx[6], xx2[6], xxs[6], lbr[6], lbr2[6], dt = 0, dd;
3303
+ double fac;
3304
+ double T, in, om, sinB, u1, u2, du;
3305
+ double ph1, ph2, me[2];
3306
+ int32 iflagp, epheflag;
3307
+ /* function calls for Pluto with asteroid number 134340
3308
+ * are treated as calls for Pluto as main body SE_PLUTO */
3309
+ if (ipl == SE_AST_OFFSET + 134340)
3310
+ ipl = SE_PLUTO;
3311
+ for (i = 0; i < 20; i++)
3312
+ attr[i] = 0;
3313
+ /* Ceres - Vesta must be SE_CERES etc., not 10001 etc. */
3314
+ if (ipl > SE_AST_OFFSET && ipl <= SE_AST_OFFSET + 4)
3315
+ ipl = ipl - SE_AST_OFFSET - 1 + SE_CERES;
3316
+ iflag = iflag & (SEFLG_EPHMASK |
3317
+ SEFLG_TRUEPOS |
3318
+ SEFLG_J2000 |
3319
+ SEFLG_NONUT |
3320
+ SEFLG_NOGDEFL |
3321
+ SEFLG_NOABERR |
3322
+ SEFLG_TOPOCTR);
3323
+ iflagp = iflag & (SEFLG_EPHMASK |
3324
+ SEFLG_TRUEPOS |
3325
+ SEFLG_J2000 |
3326
+ SEFLG_NONUT |
3327
+ SEFLG_NOABERR);
3328
+ iflagp |= SEFLG_HELCTR;
3329
+ epheflag = iflag & SEFLG_EPHMASK;
3330
+ /*
3331
+ * geocentric planet
3332
+ */
3333
+ if (swe_calc(tjd, (int) ipl, iflag | SEFLG_XYZ, xx, serr) == ERR)
3334
+ /* int cast can be removed when swe_calc() gets int32 ipl definition */
3335
+ return ERR;
3336
+ if (swe_calc(tjd, (int) ipl, iflag, lbr, serr) == ERR)
3337
+ /* int cast can be removed when swe_calc() gets int32 ipl definition */
3338
+ return ERR;
3339
+ /* if moon, we need sun as well, for magnitude */
3340
+ if (ipl == SE_MOON)
3341
+ if (swe_calc(tjd, SE_SUN, iflag | SEFLG_XYZ, xxs, serr) == ERR)
3342
+ return ERR;
3343
+ if (ipl != SE_SUN && ipl != SE_EARTH &&
3344
+ ipl != SE_MEAN_NODE && ipl != SE_TRUE_NODE &&
3345
+ ipl != SE_MEAN_APOG && ipl != SE_OSCU_APOG) {
3346
+ /*
3347
+ * light time planet - earth
3348
+ */
3349
+ dt = lbr[2] * AUNIT / CLIGHT / 86400.0;
3350
+ if (iflag & SEFLG_TRUEPOS)
3351
+ dt = 0;
3352
+ /*
3353
+ * heliocentric planet at tjd - dt
3354
+ */
3355
+ if (swe_calc(tjd - dt, (int) ipl, iflagp | SEFLG_XYZ, xx2, serr) == ERR)
3356
+ /* int cast can be removed when swe_calc() gets int32 ipl definition */
3357
+ return ERR;
3358
+ if (swe_calc(tjd - dt, (int) ipl, iflagp, lbr2, serr) == ERR)
3359
+ /* int cast can be removed when swe_calc() gets int32 ipl definition */
3360
+ return ERR;
3361
+ /*
3362
+ * phase angle
3363
+ */
3364
+ attr[0] = acos(swi_dot_prod_unit(xx, xx2)) * RADTODEG;
3365
+ /*
3366
+ * phase
3367
+ */
3368
+ attr[1] = (1 + cos(attr[0] * DEGTORAD)) / 2;
3369
+ }
3370
+ /*
3371
+ * apparent diameter of disk
3372
+ */
3373
+ if (ipl < NDIAM)
3374
+ dd = pla_diam[ipl];
3375
+ else if (ipl > SE_AST_OFFSET)
3376
+ dd = swed.ast_diam * 1000; /* km -> m */
3377
+ else
3378
+ dd = 0;
3379
+ if (lbr[2] < dd / 2 / AUNIT)
3380
+ attr[3] = 180; /* assume position on surface of earth */
3381
+ else
3382
+ attr[3] = asin(dd / 2 / AUNIT / lbr[2]) * 2 * RADTODEG;
3383
+ /*
3384
+ * apparent magnitude
3385
+ */
3386
+ if (ipl > SE_AST_OFFSET || (ipl < NMAG_ELEM && mag_elem[ipl][0] < 99)) {
3387
+ if (ipl == SE_SUN) {
3388
+ /* ratio apparent diameter : average diameter */
3389
+ fac = attr[3] / (asin(pla_diam[SE_SUN] / 2.0 / AUNIT) * 2 * RADTODEG);
3390
+ fac *= fac;
3391
+ attr[4] = mag_elem[ipl][0] - 2.5 * log10(fac);
3392
+ } else if (ipl == SE_MOON) {
3393
+ /* formula according to Allen, C.W., 1976, Astrophysical Quantities */
3394
+ /*attr[4] = -21.62 + 5 * log10(384410497.8 / EARTH_RADIUS) / log10(10) + 0.026 * fabs(attr[0]) + 0.000000004 * pow(attr[0], 4);*/
3395
+ attr[4] = -21.62 + 5 * log10(lbr[2] * AUNIT / EARTH_RADIUS) / log10(10) + 0.026 * fabs(attr[0]) + 0.000000004 * pow(attr[0], 4);
3396
+ #if 0
3397
+ /* ratio apparent diameter : average diameter */
3398
+ fac = attr[3] / (asin(pla_diam[SE_MOON] / 2.0 / 384400000.0) * 2 * RADTODEG);
3399
+ /* distance sun - moon */
3400
+ for (i = 0; i < 3; i++)
3401
+ xxs[i] -= xx[i];
3402
+ dsm = sqrt(square_sum(xxs));
3403
+ /* account for phase and distance of moon: */
3404
+ fac *= fac * attr[1];
3405
+ /* account for distance of sun from moon: */
3406
+ fac *= dsm * dsm;
3407
+ attr[4] = mag_elem[ipl][0] - 2.5 * log10(fac);
3408
+ #endif
3409
+ /*printf("1 = %f, 2 = %f\n", mag, mag2);*/
3410
+ } else if (ipl == SE_SATURN) {
3411
+ /* rings are considered according to Meeus, German, p. 329ff. */
3412
+ T = (tjd - dt - J2000) / 36525.0;
3413
+ in = (28.075216 - 0.012998 * T + 0.000004 * T * T) * DEGTORAD;
3414
+ om = (169.508470 + 1.394681 * T + 0.000412 * T * T) * DEGTORAD;
3415
+ sinB = fabs(sin(in) * cos(lbr[1] * DEGTORAD)
3416
+ * sin(lbr[0] * DEGTORAD - om)
3417
+ - cos(in) * sin(lbr[1] * DEGTORAD));
3418
+ u1 = atan2(sin(in) * tan(lbr2[1] * DEGTORAD)
3419
+ + cos(in) * sin(lbr2[0] * DEGTORAD - om),
3420
+ cos(lbr2[0] * DEGTORAD - om)) * RADTODEG;
3421
+ u2 = atan2(sin(in) * tan(lbr[1] * DEGTORAD)
3422
+ + cos(in) * sin(lbr[0] * DEGTORAD - om),
3423
+ cos(lbr[0] * DEGTORAD - om)) * RADTODEG;
3424
+ du = swe_degnorm(u1 - u2);
3425
+ if (du > 10)
3426
+ du = 360 - du;
3427
+ attr[4] = 5 * log10(lbr2[2] * lbr[2])
3428
+ + mag_elem[ipl][1] * sinB
3429
+ + mag_elem[ipl][2] * sinB * sinB
3430
+ + mag_elem[ipl][3] * du
3431
+ + mag_elem[ipl][0];
3432
+ } else if (ipl < SE_CHIRON) {
3433
+ attr[4] = 5 * log10(lbr2[2] * lbr[2])
3434
+ + mag_elem[ipl][1] * attr[0] /100.0
3435
+ + mag_elem[ipl][2] * attr[0] * attr[0] / 10000.0
3436
+ + mag_elem[ipl][3] * attr[0] * attr[0] * attr[0] / 1000000.0
3437
+ + mag_elem[ipl][0];
3438
+ } else if (ipl < NMAG_ELEM || ipl > SE_AST_OFFSET) { /* asteroids */
3439
+ ph1 = pow(EULER, -3.33 * pow(tan(attr[0] * DEGTORAD / 2), 0.63));
3440
+ ph2 = pow(EULER, -1.87 * pow(tan(attr[0] * DEGTORAD / 2), 1.22));
3441
+ if (ipl < NMAG_ELEM) { /* main asteroids */
3442
+ me[0] = mag_elem[ipl][0];
3443
+ me[1] = mag_elem[ipl][1];
3444
+ } else if (ipl == SE_AST_OFFSET + 1566) {
3445
+ /* Icarus has elements from JPL database */
3446
+ me[0] = 16.9;
3447
+ me[1] = 0.15;
3448
+ } else { /* other asteroids */
3449
+ me[0] = swed.ast_H;
3450
+ me[1] = swed.ast_G;
3451
+ }
3452
+ attr[4] = 5 * log10(lbr2[2] * lbr[2])
3453
+ + me[0]
3454
+ - 2.5 * log10((1 - me[1]) * ph1 + me[1] * ph2);
3455
+ } else { /* ficticious bodies */
3456
+ attr[4] = 0;
3457
+ }
3458
+ }
3459
+ if (ipl != SE_SUN && ipl != SE_EARTH) {
3460
+ /*
3461
+ * elongation of planet
3462
+ */
3463
+ if (swe_calc(tjd, SE_SUN, iflag | SEFLG_XYZ, xx2, serr) == ERR)
3464
+ return ERR;
3465
+ if (swe_calc(tjd, SE_SUN, iflag, lbr2, serr) == ERR)
3466
+ return ERR;
3467
+ attr[2] = acos(swi_dot_prod_unit(xx, xx2)) * RADTODEG;
3468
+ }
3469
+ /* horizontal parallax */
3470
+ if (ipl == SE_MOON) {
3471
+ double sinhp, xm[6];
3472
+ /* geocentric horizontal parallax */
3473
+ /* Expl.Suppl. to the AA 1984, p.400 */
3474
+ if (swe_calc(tjd, (int) ipl, epheflag|SEFLG_TRUEPOS|SEFLG_EQUATORIAL|SEFLG_RADIANS, xm, serr) == ERR)
3475
+ /* int cast can be removed when swe_calc() gets int32 ipl definition */
3476
+ return ERR;
3477
+ sinhp = EARTH_RADIUS / xm[2] / AUNIT;
3478
+ attr[5] = asin(sinhp) / DEGTORAD;
3479
+ /* topocentric horizontal parallax */
3480
+ if (iflag & SEFLG_TOPOCTR) {
3481
+ if (swe_calc(tjd, (int) ipl, epheflag|SEFLG_XYZ|SEFLG_TOPOCTR, xm, serr) == ERR)
3482
+ return ERR;
3483
+ if (swe_calc(tjd, (int) ipl, epheflag|SEFLG_XYZ, xx, serr) == ERR)
3484
+ return ERR;
3485
+ attr[5] = acos(swi_dot_prod_unit(xm, xx)) / DEGTORAD;
3486
+ #if 0
3487
+ {
3488
+ /* Expl. Suppl. to the Astronomical Almanac 1984, p. 400;
3489
+ * Does not take into account
3490
+ * - the topocentric distance of the moon
3491
+ * - the distance of the observer from the geocenter
3492
+ */
3493
+ double tsid, h, e, f = EARTH_OBLATENESS;
3494
+ double cosz, sinz, phi;
3495
+ /* local apparent sidereal time */
3496
+ tsid = swe_sidtime(tjd - swe_deltat(tjd)) * 15 + swed.topd.geolon;
3497
+ /* local hour angle of the moon */
3498
+ h = swe_degnorm(tsid - xm[0] / DEGTORAD);
3499
+ /* geocentric latitude of the observer */
3500
+ e = sqrt(f * (2 - f));
3501
+ phi = atan((1 - e * e) * tan(swed.topd.geolat * DEGTORAD));
3502
+ /* sine of geocentric zenith angle of moon */
3503
+ cosz = sin(xm[1]) * sin(phi) + cos(xm[1]) * cos(phi) * cos(h * DEGTORAD);
3504
+ sinz = sqrt(1 - cosz * cosz);
3505
+ attr[5] = asin(sinz * sinhp / (1 - sinz * sinhp)) / DEGTORAD;
3506
+ }
3507
+ #endif
3508
+ }
3509
+ }
3510
+ return OK;
3511
+ }
3512
+
3513
+ int32 FAR PASCAL_CONV swe_pheno_ut(double tjd_ut, int32 ipl, int32 iflag, double *attr, char *serr)
3514
+ {
3515
+ return swe_pheno(tjd_ut + swe_deltat(tjd_ut), ipl, iflag, attr, serr);
3516
+ }
3517
+
3518
+ static int find_maximum(double y00, double y11, double y2, double dx,
3519
+ double *dxret, double *yret)
3520
+ {
3521
+ double a, b, c, x, y;
3522
+ c = y11;
3523
+ b = (y2 - y00) / 2.0;
3524
+ a = (y2 + y00) / 2.0 - c;
3525
+ x = -b / 2 / a;
3526
+ y = (4 * a * c - b * b) / 4 / a;
3527
+ *dxret = (x - 1) * dx;
3528
+ if (yret != NULL)
3529
+ *yret = y;
3530
+ return OK;
3531
+ }
3532
+
3533
+ static int find_zero(double y00, double y11, double y2, double dx,
3534
+ double *dxret, double *dxret2)
3535
+ {
3536
+ double a, b, c, x1, x2;
3537
+ c = y11;
3538
+ b = (y2 - y00) / 2.0;
3539
+ a = (y2 + y00) / 2.0 - c;
3540
+ if (b * b - 4 * a * c < 0)
3541
+ return ERR;
3542
+ x1 = (-b + sqrt(b * b - 4 * a * c)) / 2 / a;
3543
+ x2 = (-b - sqrt(b * b - 4 * a * c)) / 2 / a;
3544
+ *dxret = (x1 - 1) * dx;
3545
+ *dxret2 = (x2 - 1) * dx;
3546
+ return OK;
3547
+ }
3548
+
3549
+ double rdi_twilight(int32 rsmi)
3550
+ {
3551
+ double rdi = 0;
3552
+ if (rsmi & SE_BIT_CIVIL_TWILIGHT)
3553
+ rdi = 6;
3554
+ if (rsmi & SE_BIT_NAUTIC_TWILIGHT)
3555
+ rdi = 12;
3556
+ if (rsmi & SE_BIT_ASTRO_TWILIGHT)
3557
+ rdi = 18;
3558
+ return rdi;
3559
+ }
3560
+
3561
+ /* rise, set, and meridian transits of sun, moon, planets, and stars
3562
+ *
3563
+ * tjd_ut universal time from when on search ought to start
3564
+ * ipl planet number, neglected, if starname is given
3565
+ * starname pointer to string. if a planet, not a star, is
3566
+ * wanted, starname must be NULL or ""
3567
+ * epheflag used for ephemeris only
3568
+ * rsmi SE_CALC_RISE, SE_CALC_SET, SE_CALC_MTRANSIT, SE_CALC_ITRANSIT
3569
+ * | SE_BIT_DISC_CENTER for rises of disc center of body
3570
+ * | SE_BIT_DISC_BOTTOM for rises of disc bottom of body
3571
+ * | SE_BIT_NO_REFRACTION to neglect refraction
3572
+ * | SE_BIT_FIXED_DISC_SIZE neglect the effect of distance on disc size
3573
+ * geopos array of doubles for geogr. long., lat. and height above sea
3574
+ * atpress atmospheric pressure
3575
+ * attemp atmospheric temperature
3576
+ *
3577
+ * return variables:
3578
+ * tret time of rise, set, meridian transits
3579
+ * serr[256] error string
3580
+ * function return value -2 means that the body does not rise or set */
3581
+ #define SEFLG_EPHMASK (SEFLG_JPLEPH|SEFLG_SWIEPH|SEFLG_MOSEPH)
3582
+ int32 FAR PASCAL_CONV swe_rise_trans(
3583
+ double tjd_ut, int32 ipl, char *starname,
3584
+ int32 epheflag, int32 rsmi,
3585
+ double *geopos,
3586
+ double atpress, double attemp,
3587
+ double *tret,
3588
+ char *serr)
3589
+ {
3590
+ int i, j, k, ii, calc_culm, nculm = -1;
3591
+ double tjd_et = tjd_ut + swe_deltat(tjd_ut);
3592
+ double xc[6], xh[20][6], ah[6], aha;
3593
+ double tculm[4], tcu, tc[20], h[20], t2[6], dc[6], dtint, dx, rdi, dd = 0;
3594
+ int32 iflag = epheflag;
3595
+ int jmax = 14;
3596
+ double t, te, tt, dt, twohrs = 1.0 / 12.0;
3597
+ double curdist;
3598
+ AS_BOOL do_calc_twilight = 0;
3599
+ AS_BOOL do_fixstar = (starname != NULL && *starname != '\0');
3600
+ /* function calls for Pluto with asteroid number 134340
3601
+ * are treated as calls for Pluto as main body SE_PLUTO */
3602
+ if (ipl == SE_AST_OFFSET + 134340)
3603
+ ipl = SE_PLUTO;
3604
+ xh[0][0] = 0; /* to shut up mint */
3605
+ iflag &= SEFLG_EPHMASK;
3606
+ *tret = 0;
3607
+ iflag |= (SEFLG_EQUATORIAL | SEFLG_TOPOCTR);
3608
+ swe_set_topo(geopos[0], geopos[1], geopos[2]);
3609
+ if (rsmi & (SE_CALC_MTRANSIT | SE_CALC_ITRANSIT))
3610
+ return calc_mer_trans(tjd_ut, ipl, epheflag, rsmi,
3611
+ geopos, starname, tret, serr);
3612
+ if (!(rsmi & (SE_CALC_RISE | SE_CALC_SET)))
3613
+ rsmi |= SE_CALC_RISE;
3614
+ if (ipl == SE_SUN && (rsmi & (SE_BIT_CIVIL_TWILIGHT|SE_BIT_NAUTIC_TWILIGHT|SE_BIT_ASTRO_TWILIGHT))) {
3615
+ rsmi |= (SE_BIT_NO_REFRACTION | SE_BIT_DISC_CENTER);
3616
+ do_calc_twilight = 1;
3617
+ }
3618
+ /* find culmination points within 28 hours from t0 - twohrs.
3619
+ * culminations are required in case there are maxima or minima
3620
+ * in height slightly above or below the horizon.
3621
+ * we do not use meridian transits, because in polar regions
3622
+ * the culmination points may considerably deviate from
3623
+ * transits. also, there are cases where the moon rises in the
3624
+ * western half of the sky for a short time.
3625
+ */
3626
+ if (do_fixstar) {
3627
+ if (swe_fixstar(starname, tjd_et, iflag, xc, serr) == ERR)
3628
+ return ERR;
3629
+ }
3630
+ for (ii = 0, t = tjd_ut - twohrs; ii <= jmax; ii++, t += twohrs) {
3631
+ tc[ii] = t;
3632
+ if (!do_fixstar) {
3633
+ te = t + swe_deltat(t);
3634
+ if (swe_calc(te, ipl, iflag, xc, serr) == ERR)
3635
+ return ERR;
3636
+ }
3637
+ /* diameter of object in km */
3638
+ if (ii == 0) {
3639
+ if (do_fixstar)
3640
+ dd = 0;
3641
+ else if (rsmi & SE_BIT_DISC_CENTER)
3642
+ dd = 0;
3643
+ else if (ipl < NDIAM)
3644
+ dd = pla_diam[ipl];
3645
+ else if (ipl > SE_AST_OFFSET)
3646
+ dd = swed.ast_diam * 1000; /* km -> m */
3647
+ else
3648
+ dd = 0;
3649
+ }
3650
+ curdist = xc[2];
3651
+ if ( rsmi & SE_BIT_FIXED_DISC_SIZE )
3652
+ {
3653
+ if ( ipl == SE_SUN )
3654
+ {
3655
+ curdist = 1.0;
3656
+ }
3657
+ else if ( ipl == SE_MOON )
3658
+ {
3659
+ curdist = 0.00257;
3660
+ }
3661
+ }
3662
+ /* apparent radius of disc */
3663
+ rdi = asin( dd / 2 / AUNIT / curdist ) * RADTODEG;
3664
+ /* twilight calculation: */
3665
+ if (do_calc_twilight)
3666
+ rdi = rdi_twilight(rsmi);
3667
+ /* true height of center of body */
3668
+ swe_azalt(t, SE_EQU2HOR, geopos, atpress, attemp, xc, xh[ii]);
3669
+ if ( rsmi & SE_BIT_DISC_BOTTOM )
3670
+ {
3671
+ /* true height of bottom point of body */
3672
+ xh[ii][1] -= rdi;
3673
+ }
3674
+ else
3675
+ {
3676
+ /* true height of uppermost point of body */
3677
+ xh[ii][1] += rdi;
3678
+ }
3679
+ /* apparent height of uppermost point of body */
3680
+ if (rsmi & SE_BIT_NO_REFRACTION) {
3681
+ h[ii] = xh[ii][1];
3682
+ } else {
3683
+ swe_azalt_rev(t, SE_HOR2EQU, geopos, xh[ii], xc);
3684
+ swe_azalt(t, SE_EQU2HOR, geopos, atpress, attemp, xc, xh[ii]);
3685
+ h[ii] = xh[ii][2];
3686
+ }
3687
+ calc_culm = 0;
3688
+ if (ii > 1) {
3689
+ dc[0] = xh[ii-2][1];
3690
+ dc[1] = xh[ii-1][1];
3691
+ dc[2] = xh[ii][1];
3692
+ if (dc[1] > dc[0] && dc[1] > dc[2])
3693
+ calc_culm = 1;
3694
+ if (dc[1] < dc[0] && dc[1] < dc[2])
3695
+ calc_culm = 2;
3696
+ }
3697
+ if (calc_culm) {
3698
+ dt = twohrs;
3699
+ tcu = t - dt;
3700
+ find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dx);
3701
+ tcu += dtint + dt;
3702
+ dt /= 3;
3703
+ for (; dt > 0.0001; dt /= 3) {
3704
+ for (i = 0, tt = tcu - dt; i < 3; tt += dt, i++) {
3705
+ te = tt + swe_deltat(tt);
3706
+ if (!do_fixstar)
3707
+ if (swe_calc(te, ipl, iflag, xc, serr) == ERR)
3708
+ return ERR;
3709
+ swe_azalt(tt, SE_EQU2HOR, geopos, atpress, attemp, xc, ah);
3710
+ dc[i] = ah[1];
3711
+ }
3712
+ find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dx);
3713
+ tcu += dtint + dt;
3714
+ }
3715
+ nculm++;
3716
+ tculm[nculm] = tcu;
3717
+ }
3718
+ }
3719
+ /* note: there can be a rise or set on the poles, even if
3720
+ * there is no culmination. So, we must not leave here
3721
+ * in any case. */
3722
+ /* insert culminations into array of heights */
3723
+ for (i = 0; i <= nculm; i++) {
3724
+ for (j = 1; j <= jmax; j++) {
3725
+ if (tculm[i] < tc[j]) {
3726
+ for (k = jmax; k >= j; k--) {
3727
+ tc[k+1] = tc[k];
3728
+ h[k+1] = h[k];
3729
+ }
3730
+ tc[j] = tculm[i];
3731
+ if (!do_fixstar) {
3732
+ te = tc[j] + swe_deltat(tc[j]);
3733
+ if (swe_calc(te, ipl, iflag, xc, serr) == ERR)
3734
+ return ERR;
3735
+ }
3736
+ curdist = xc[2];
3737
+ if ( rsmi & SE_BIT_FIXED_DISC_SIZE )
3738
+ {
3739
+ if ( ipl == SE_SUN )
3740
+ {
3741
+ curdist = 1.0;
3742
+ }
3743
+ else if ( ipl == SE_MOON )
3744
+ {
3745
+ curdist = 0.00257;
3746
+ }
3747
+ }
3748
+ /* apparent radius of disc */
3749
+ rdi = asin( dd / 2 / AUNIT / curdist ) * RADTODEG;
3750
+ /* twilight calculation: */
3751
+ if (do_calc_twilight)
3752
+ rdi = rdi_twilight(rsmi);
3753
+ /* true height of center of body */
3754
+ swe_azalt(tc[j], SE_EQU2HOR, geopos, atpress, attemp, xc, ah);
3755
+ if ( rsmi & SE_BIT_DISC_BOTTOM )
3756
+ {
3757
+ /* true height of bottom point of body */
3758
+ ah[1] -= rdi;
3759
+ }
3760
+ else
3761
+ {
3762
+ /* true height of uppermost point of body */
3763
+ ah[1] += rdi;
3764
+ }
3765
+ /* apparent height of uppermost point of body */
3766
+ if (rsmi & SE_BIT_NO_REFRACTION) {
3767
+ h[j] = ah[1];
3768
+ } else {
3769
+ swe_azalt_rev(tc[j], SE_HOR2EQU, geopos, ah, xc);
3770
+ swe_azalt(tc[j], SE_EQU2HOR, geopos, atpress, attemp, xc, ah);
3771
+ h[j] = ah[2];
3772
+ }
3773
+ jmax++;
3774
+ break;
3775
+ }
3776
+ }
3777
+ }
3778
+ *tret = 0;
3779
+ /* find points with zero height.
3780
+ * binary search */
3781
+ for (ii = 1; ii <= jmax; ii++) {
3782
+ if (h[ii-1] * h[ii] >= 0)
3783
+ continue;
3784
+ if (h[ii-1] < h[ii] && !(rsmi & SE_CALC_RISE))
3785
+ continue;
3786
+ if (h[ii-1] > h[ii] && !(rsmi & SE_CALC_SET))
3787
+ continue;
3788
+ dc[0] = h[ii-1];
3789
+ dc[1] = h[ii];
3790
+ t2[0] = tc[ii-1];
3791
+ t2[1] = tc[ii];
3792
+ for (i = 0; i < 20; i++) {
3793
+ t = (t2[0] + t2[1]) / 2;
3794
+ if (!do_fixstar) {
3795
+ te = t + swe_deltat(t);
3796
+ if (swe_calc(te, ipl, iflag, xc, serr) == ERR)
3797
+ return ERR;
3798
+ }
3799
+ curdist = xc[2];
3800
+ if ( rsmi & SE_BIT_FIXED_DISC_SIZE )
3801
+ {
3802
+ if ( ipl == SE_SUN )
3803
+ {
3804
+ curdist = 1.0;
3805
+ }
3806
+ else if ( ipl == SE_MOON )
3807
+ {
3808
+ curdist = 0.00257;
3809
+ }
3810
+ }
3811
+ /* apparent radius of disc */
3812
+ rdi = asin( dd / 2 / AUNIT / curdist ) * RADTODEG;
3813
+ /* twilight calculation: */
3814
+ if (do_calc_twilight)
3815
+ rdi = rdi_twilight(rsmi);
3816
+ /* true height of center of body */
3817
+ swe_azalt(t, SE_EQU2HOR, geopos, atpress, attemp, xc, ah);
3818
+ if ( rsmi & SE_BIT_DISC_BOTTOM )
3819
+ {
3820
+ /* true height of bottom point of body */
3821
+ ah[1] -= rdi;
3822
+ }
3823
+ else
3824
+ {
3825
+ /* true height of uppermost point of body */
3826
+ ah[1] += rdi;
3827
+ }
3828
+ /* apparent height of uppermost point of body */
3829
+ if (rsmi & SE_BIT_NO_REFRACTION) {
3830
+ aha = ah[1];
3831
+ } else {
3832
+ swe_azalt_rev(t, SE_HOR2EQU, geopos, ah, xc);
3833
+ swe_azalt(t, SE_EQU2HOR, geopos, atpress, attemp, xc, ah);
3834
+ aha = ah[2];
3835
+ }
3836
+ if (aha * dc[0] <= 0) {
3837
+ dc[1] = aha;
3838
+ t2[1] = t;
3839
+ } else {
3840
+ dc[0] = aha;
3841
+ t2[0] = t;
3842
+ }
3843
+ }
3844
+ if (t > tjd_ut) {
3845
+ *tret = t;
3846
+ return OK;
3847
+ }
3848
+ }
3849
+ if (serr)
3850
+ sprintf(serr, "rise or set not found for planet %d", ipl);
3851
+ return -2; /* no t of rise or set found */
3852
+ }
3853
+
3854
+ static int32 calc_mer_trans(
3855
+ double tjd_ut, int32 ipl, int32 epheflag, int32 rsmi,
3856
+ double *geopos,
3857
+ char *starname,
3858
+ double *tret,
3859
+ char *serr)
3860
+ {
3861
+ int i;
3862
+ double tjd_et = tjd_ut + swe_deltat(tjd_ut);
3863
+ double armc, armc0, arxc, x0[6], x[6], t, te;
3864
+ double mdd;
3865
+ int32 iflag = epheflag;
3866
+ AS_BOOL do_fixstar = (starname != NULL && *starname != '\0');
3867
+ iflag &= SEFLG_EPHMASK;
3868
+ *tret = 0;
3869
+ iflag |= (SEFLG_EQUATORIAL | SEFLG_TOPOCTR);
3870
+ armc0 = swe_sidtime(tjd_ut) + geopos[0] / 15;
3871
+ if (armc0 >= 24)
3872
+ armc0 -= 24;
3873
+ if (armc0 < 0)
3874
+ armc0 += 24;
3875
+ armc0 *= 15;
3876
+ if (do_fixstar) {
3877
+ if (swe_fixstar(starname, tjd_et, iflag, x0, serr) == ERR)
3878
+ return ERR;
3879
+ } else {
3880
+ if (swe_calc(tjd_et, ipl, iflag, x0, serr) == ERR)
3881
+ return ERR;
3882
+ }
3883
+ /*
3884
+ * meridian transits
3885
+ */
3886
+ x[0] = x0[0];
3887
+ x[1] = x0[1];
3888
+ t = tjd_ut;
3889
+ arxc = armc0;
3890
+ if (rsmi & SE_CALC_ITRANSIT)
3891
+ arxc = swe_degnorm(arxc + 180);
3892
+ for (i = 0; i < 4; i++) {
3893
+ mdd = swe_degnorm(x[0] - arxc);
3894
+ if (i > 0 && mdd > 180)
3895
+ mdd -= 360;
3896
+ t += mdd / 361;
3897
+ armc = swe_sidtime(t) + geopos[0] / 15;
3898
+ if (armc >= 24)
3899
+ armc -= 24;
3900
+ if (armc < 0)
3901
+ armc += 24;
3902
+ armc *= 15;
3903
+ arxc = armc;
3904
+ if (rsmi & SE_CALC_ITRANSIT)
3905
+ arxc = swe_degnorm(arxc + 180);
3906
+ if (!do_fixstar) {
3907
+ te = t + swe_deltat(t);
3908
+ if (swe_calc(te, ipl, iflag, x, serr) == ERR)
3909
+ return ERR;
3910
+ }
3911
+ }
3912
+ *tret = t;
3913
+ return OK;
3914
+ }
3915
+
3916
+ /*
3917
+ Nodes and apsides of planets and moon
3918
+
3919
+ Planetary nodes can be defined in three different ways:
3920
+ a) They can be understood as a direction or as an axis
3921
+ defined by the intersection line of two orbital planes.
3922
+ E.g., the nodes of Mars are defined by the intersection
3923
+ line of Mars' orbital plane with the ecliptic (= the
3924
+ Earths orbit heliocentrically or the solar orbit
3925
+ geocentrically). However, as Michael Erlewine points
3926
+ out in his elaborate web page on this topic
3927
+ (http://thenewage.com/resources/articles/interface.html),
3928
+ planetary nodes can be defined for any couple of
3929
+ planets. E.g. there is also an intersection line for the
3930
+ two orbital planes of Mars and Saturn.
3931
+ Because such lines are, in principle, infinite, the
3932
+ heliocentric and the geocentric positions of the
3933
+ planetary nodes will be the same. There are astrologers
3934
+ that use such heliocentric planetary nodes in geocentric
3935
+ charts.
3936
+ The ascending and the descending node will, in this
3937
+ case, be in precise opposition.
3938
+
3939
+ b) The planetary nodes can also be understood in a
3940
+ different way, not as an axis, but as the two points on a
3941
+ planetary orbit that are located precisely on the
3942
+ intersection line of the two planes.
3943
+ This second definition makes no difference for the moon or
3944
+ for heliocentric positions of planets, but it does so for
3945
+ geocentric positions. There are two possibilities for
3946
+ geocentric planetary nodes based on this definition.
3947
+ 1) The common solution is that the points on the
3948
+ planets orbit are transformed to the geocenter. The
3949
+ two points will not be in opposition anymore, or
3950
+ they will only roughly be so with the outer planets. The
3951
+ advantage of these nodes is that when a planet is in
3952
+ conjunction with its node, then its ecliptic latitude
3953
+ will be zero. This is not true when a planet is in
3954
+ geocentric conjunction with its heliocentric node.
3955
+ (And neither is it always true for the inner planets,
3956
+ i.e. Mercury and Venus.)
3957
+ 2) The second possibility that nobody seems to have
3958
+ thought of so far: One may compute the points of
3959
+ the earth's orbit that lie exactly on another planet's
3960
+ orbital plane and transform it to the geocenter. The two
3961
+ points will always be in an approximate square.
3962
+
3963
+ c) Third, the planetary nodes could be defined as the
3964
+ intersection points of the plane defined by their
3965
+ momentary geocentric position and motion with the
3966
+ plane of the ecliptic. Such points would move very fast
3967
+ around the planetary stations. Here again, as in b)1),
3968
+ the planet would cross the ecliptic and its ecliptic
3969
+ latitude would be 0 exactly when it were in
3970
+ conjunction with one of its nodes.
3971
+
3972
+ The Swiss Ephemeris supports the solutions a) and b) 1).
3973
+
3974
+ Possible definitions for apsides
3975
+
3976
+ a) The planetary apsides can be defined as the perihelion and
3977
+ aphelion points on a planetary orbit. For a
3978
+ geocentric chart, these points could be transformed
3979
+ from the heliocenter to the geocenter.
3980
+ b) However, one might consider these points as
3981
+ astrologically relevant axes rather than as points on a
3982
+ planetary orbit. Again, this would allow heliocentric
3983
+ positions in a geocentric chart.
3984
+
3985
+ Note: For the "Dark Moon" or "Lilith", which I usually
3986
+ define as the lunar apogee, some astrologers give a
3987
+ different definition. They understand it as the second focal
3988
+ point of the moon's orbital ellipse. This definition does not
3989
+ make a difference for geocentric positions, because the
3990
+ apogee and the second focus are in exactly the same geocentric
3991
+ direction. However, it makes a difference with topocentric
3992
+ positions, because the two points do not have same distance.
3993
+ Analogous "black planets" have been proposed: they would be the
3994
+ second focal points of the planets' orbital ellipses. The
3995
+ heliocentric positions of these "black planets" are identical
3996
+ with the heliocentric positions of the aphelia, but geocentric
3997
+ positions are not identical, because the focal points are
3998
+ much closer to the sun than the aphelia.
3999
+
4000
+ The Swiss Ephemeris allows to compute the "black planets" as well.
4001
+
4002
+ Mean positions
4003
+
4004
+ Mean nodes and apsides can be computed for the Moon, the
4005
+ Earth and the planets Mercury - Neptune. They are taken
4006
+ from the planetary theory VSOP87. Mean points can not be
4007
+ calculated for Pluto and the asteroids, because there is no
4008
+ planetary theory for them.
4009
+
4010
+ Osculating nodes and apsides
4011
+
4012
+ Nodes and apsides can also be derived from the osculating
4013
+ orbital elements of a body, the paramaters that define an
4014
+ ideal unperturbed elliptic (two-body) orbit.
4015
+ For astrology, note that this is a simplification and
4016
+ idealization.
4017
+ Problem with Neptune: Neptune's orbit around the sun does not
4018
+ have much in common with an ellipse. There are often two
4019
+ perihelia and two aphelia within one revolution. As a result,
4020
+ there is a wild oscillation of the osculating perihelion (and
4021
+ aphelion).
4022
+ In actuality, Neptune's orbit is not heliocentric orbit at all.
4023
+ The twofold perihelia and aphelia are an effect of the motion of
4024
+ the sun about the solar system barycenter. This motion is
4025
+ much faster than the motion of Neptune, and Neptune
4026
+ cannot react on such fast displacements of the Sun. As a
4027
+ result, Neptune seems to move around the barycenter (or a
4028
+ mean sun) rather than around the true sun. In fact,
4029
+ Neptune's orbit around the barycenter is therefore closer to
4030
+ an ellipse than the his orbit around the sun. The same
4031
+ statement is also true for Saturn, Uranus and Pluto, but not
4032
+ for Jupiter and the inner planets.
4033
+
4034
+ This fundamental problem about osculating ellipses of
4035
+ planetary orbits does of course not only affect the apsides
4036
+ but also the nodes.
4037
+
4038
+ Two solutions can be thought of for this problem:
4039
+ 1) The one would be to interpolate between actual
4040
+ passages of the planets through their nodes and
4041
+ apsides. However, this works only well with Mercury.
4042
+ With all other planets, the supporting points are too far
4043
+ apart as to make an accurate interpolation possible.
4044
+ This solution is not implemented, here.
4045
+ 2) The other solution is to compute the apsides of the
4046
+ orbit around the barycenter rather than around the sun.
4047
+ This procedure makes sense for planets beyond Jupiter,
4048
+ it comes closer to the mean apsides and nodes for
4049
+ planets that have such points defined. For all other
4050
+ transsaturnian planets and asteroids, this solution yields
4051
+ a kind of "mean" nodes and apsides. On the other hand,
4052
+ the barycentric ellipse does not make any sense for
4053
+ inner planets and Jupiter.
4054
+
4055
+ The Swiss Ephemeris supports solution 2) for planets and
4056
+ asteroids beyond Jupiter.
4057
+
4058
+ Anyway, neither the heliocentric nor the barycentric ellipse
4059
+ is a perfect representation of the nature of a planetary orbit,
4060
+ and it will not yield the degree of precision that today's
4061
+ astrology is used to.
4062
+ The best choice of method will probably be:
4063
+ - For Mercury - Neptune: mean nodes and apsides
4064
+ - For asteroids that belong to the inner asteroid belt:
4065
+ osculating nodes/apsides from a heliocentric ellipse
4066
+ - For Pluto and outer asteroids: osculating nodes/apsides
4067
+ from a barycentric ellipse
4068
+
4069
+ The Moon is a special case: A "lunar true node" makes
4070
+ more sense, because it can be defined without the idea of an
4071
+ ellipse, e.g. as the intersection axis of the momentary lunar
4072
+ orbital plane with the ecliptic. Or it can be said that the
4073
+ momentary motion of the moon points to one of the two
4074
+ ecliptic points that are called the "true nodes". So, these
4075
+ points make sense. With planetary nodes, the situation is
4076
+ somewhat different, at least if we make a difference
4077
+ between heliocentric and geocentric positions. If so, the
4078
+ planetary nodes are points on a heliocentric orbital ellipse,
4079
+ which are transformed to the geocenter. An ellipse is
4080
+ required here, because a solar distance is required. In
4081
+ contrast to the planetary nodes, the lunar node does not
4082
+ require a distance, therefore manages without the idea of an
4083
+ ellipse and does not share its weaknesses.
4084
+ On the other hand, the lunar apsides DO require the idea of
4085
+ an ellipse. And because the lunar ellipse is actually
4086
+ extremely distorted, even more than any other celestial
4087
+ ellipse, the "true Lilith" (apogee), for which printed
4088
+ ephemerides are available, does not make any sense at all.
4089
+ (See the chapter on the lunar node and apogee.)
4090
+
4091
+ Special case: the Earth
4092
+
4093
+ The Earth is another special case. Instead of the motion of
4094
+ the Earth herself, the heliocentric motion of the Earth-
4095
+ Moon-Barycenter (EMB) is used to determine the
4096
+ osculating perihelion.
4097
+ There is no node of the earth orbit itself. However, there is
4098
+ an axis around which the earth's orbital plane slowly rotates
4099
+ due to planetary precession. The position points of this axis
4100
+ are not calculated by the Swiss Ephemeris.
4101
+
4102
+ Special case: the Sun
4103
+
4104
+ In addition to the Earth (EMB) apsides, the function
4105
+ computes so-to-say "apsides" of the sun, i.e. points on the
4106
+ orbit of the Sun where it is closest to and where it is farthest
4107
+ from the Earth. These points form an opposition and are
4108
+ used by some astrologers, e.g. by the Dutch astrologer
4109
+ George Bode or the Swiss astrologer Liduina Schmed. The
4110
+ perigee, located at about 13 Capricorn, is called the
4111
+ "Black Sun", the other one, in Cancer, the "Diamond".
4112
+ So, for a complete set of apsides, one ought to calculate
4113
+ them for the Sun and the Earth and all other planets.
4114
+
4115
+ The modes of the Swiss Ephemeris function
4116
+ swe_nod_aps()
4117
+
4118
+ The function swe_nod_aps() can be run in the following
4119
+ modes:
4120
+ 1) Mean positions are given for nodes and apsides of Sun,
4121
+ Moon, Earth, and the up to Neptune. Osculating
4122
+ positions are given with Pluto and all asteroids. This is
4123
+ the default mode.
4124
+ 2) Osculating positions are returned for nodes and apsides
4125
+ of all planets.
4126
+ 3) Same as 2), but for planets and asteroids beyond
4127
+ Jupiter, a barycentric ellipse is used.
4128
+ 4) Same as 1), but for Pluto and asteroids beyond Jupiter,
4129
+ a barycentric ellipse is used.
4130
+
4131
+ In all of these modes, the second focal point of the ellipse
4132
+ can be computed instead of the aphelion.
4133
+ Like the planetary function swe_calc(), swe_nod_aps() is
4134
+ able to return geocentric, topocentric, heliocentric, or
4135
+ barycentric position.
4136
+ *
4137
+ * tjd_ut julian day, ephemeris time
4138
+ * ipl planet number
4139
+ * iflag as usual, SEFLG_HELCTR, etc.
4140
+ * xnasc an array of 6 doubles: ascending node
4141
+ * xndsc an array of 6 doubles: ascending node
4142
+ * xperi an array of 6 doubles: perihelion
4143
+ * xaphe an array of 6 doubles: aphelion
4144
+ * method see below
4145
+ * serr error message
4146
+ *
4147
+ * method can have the following values:
4148
+ * - 0 or SE_NODBIT_MEAN. MEAN positions are given for
4149
+ * nodes and apsides of Sun, Moon, Earth, and the
4150
+ * planets up to Neptune. Osculating positions are
4151
+ * given with Pluto and all asteroids.
4152
+ * - SE_NODBIT_OSCU. Osculating positions are given
4153
+ * for all nodes and apsides.
4154
+ * - SE_NODBIT_OSCU_BAR. Osculating nodes and apsides
4155
+ * are computed from barycentric ellipses, for planets
4156
+ * beyond Jupiter, but from heliocentric ones for
4157
+ * ones for Jupiter and inner planets.
4158
+ * - SE_NODBIT_MEAN and SE_NODBIT_OSCU_BAR can be combined.
4159
+ * The program behaves the same way as with simple
4160
+ * SE_NODBIT_MEAN, but uses barycentric ellipses for
4161
+ * planets beyond Neptune and asteroids beyond Jupiter.
4162
+ * - SE_NODBIT_FOCAL can be combined with any of the other
4163
+ * bits. The second focal points of the ellipses will
4164
+ * be returned instead of the aphelia.
4165
+ */
4166
+ /* mean elements for Mercury - Neptune from VSOP87 (mean equinox of date) */
4167
+ static double el_node[8][4] =
4168
+ {{ 48.330893, 1.1861890, 0.00017587, 0.000000211,}, /* Mercury */
4169
+ { 76.679920, 0.9011190, 0.00040665, -0.000000080,}, /* Venus */
4170
+ { 0 , 0 , 0 , 0 ,}, /* Earth */
4171
+ { 49.558093, 0.7720923, 0.00001605, 0.000002325,}, /* Mars */
4172
+ {100.464441, 1.0209550, 0.00040117, 0.000000569,}, /* Jupiter */
4173
+ {113.665524, 0.8770970, -0.00012067, -0.000002380,}, /* Saturn */
4174
+ { 74.005947, 0.5211258, 0.00133982, 0.000018516,}, /* Uranus */
4175
+ {131.784057, 1.1022057, 0.00026006, -0.000000636,}, /* Neptune */
4176
+ };
4177
+ static double el_peri[8][4] =
4178
+ {{ 77.456119, 1.5564775, 0.00029589, 0.000000056,}, /* Mercury */
4179
+ {131.563707, 1.4022188, -0.00107337, -0.000005315,}, /* Venus */
4180
+ {102.937348, 1.7195269, 0.00045962, 0.000000499,}, /* Earth */
4181
+ {336.060234, 1.8410331, 0.00013515, 0.000000318,}, /* Mars */
4182
+ { 14.331309, 1.6126668, 0.00103127, -0.000004569,}, /* Jupiter */
4183
+ { 93.056787, 1.9637694, 0.00083757, 0.000004899,}, /* Saturn */
4184
+ {173.005159, 1.4863784, 0.00021450, 0.000000433,}, /* Uranus */
4185
+ { 48.123691, 1.4262677, 0.00037918, -0.000000003,}, /* Neptune */
4186
+ };
4187
+ static double el_incl[8][4] =
4188
+ {{ 7.004986, 0.0018215, -0.00001809, 0.000000053,}, /* Mercury */
4189
+ { 3.394662, 0.0010037, -0.00000088, -0.000000007,}, /* Venus */
4190
+ { 0, 0, 0, 0 ,}, /* Earth */
4191
+ { 1.849726, -0.0006010, 0.00001276, -0.000000006,}, /* Mars */
4192
+ { 1.303270, -0.0054966, 0.00000465, -0.000000004,}, /* Jupiter */
4193
+ { 2.488878, -0.0037363, -0.00001516, 0.000000089,}, /* Saturn */
4194
+ { 0.773196, 0.0007744, 0.00003749, -0.000000092,}, /* Uranus */
4195
+ { 1.769952, -0.0093082, -0.00000708, 0.000000028,}, /* Neptune */
4196
+ };
4197
+ static double el_ecce[8][4] =
4198
+ {{ 0.20563175, 0.000020406, -0.0000000284, -0.00000000017,}, /* Mercury */
4199
+ { 0.00677188, -0.000047766, 0.0000000975, 0.00000000044,}, /* Venus */
4200
+ { 0.01670862, -0.000042037, -0.0000001236, 0.00000000004,}, /* Earth */
4201
+ { 0.09340062, 0.000090483, -0.0000000806, -0.00000000035,}, /* Mars */
4202
+ { 0.04849485, 0.000163244, -0.0000004719, -0.00000000197,}, /* Jupiter */
4203
+ { 0.05550862, -0.000346818, -0.0000006456, 0.00000000338,}, /* Saturn */
4204
+ { 0.04629590, -0.000027337, 0.0000000790, 0.00000000025,}, /* Uranus */
4205
+ { 0.00898809, 0.000006408, -0.0000000008, -0.00000000005,}, /* Neptune */
4206
+ };
4207
+ static double el_sema[8][4] =
4208
+ {{ 0.387098310, 0.0, 0.0, 0.0,}, /* Mercury */
4209
+ { 0.723329820, 0.0, 0.0, 0.0,}, /* Venus */
4210
+ { 1.000001018, 0.0, 0.0, 0.0,}, /* Earth */
4211
+ { 1.523679342, 0.0, 0.0, 0.0,}, /* Mars */
4212
+ { 5.202603191, 0.0000001913, 0.0, 0.0,}, /* Jupiter */
4213
+ { 9.554909596, 0.0000021389, 0.0, 0.0,}, /* Saturn */
4214
+ { 19.218446062, -0.0000000372, 0.00000000098, 0.0,}, /* Uranus */
4215
+ { 30.110386869, -0.0000001663, 0.00000000069, 0.0,}, /* Neptune */
4216
+ };
4217
+ /* Ratios of mass of Sun to masses of the planets */
4218
+ static double plmass[9] = {
4219
+ 6023600, /* Mercury */
4220
+ 408523.5, /* Venus */
4221
+ 328900.5, /* Earth and Moon */
4222
+ 3098710, /* Mars */
4223
+ 1047.350, /* Jupiter */
4224
+ 3498.0, /* Saturn */
4225
+ 22960, /* Uranus */
4226
+ 19314, /* Neptune */
4227
+ 130000000, /* Pluto */
4228
+ };
4229
+ static int ipl_to_elem[15] = {2, 0, 0, 1, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 2,};
4230
+ int32 FAR PASCAL_CONV swe_nod_aps(double tjd_et, int32 ipl, int32 iflag,
4231
+ int32 method,
4232
+ double *xnasc, double *xndsc,
4233
+ double *xperi, double *xaphe,
4234
+ char *serr)
4235
+ {
4236
+ int ij, i, j;
4237
+ int32 iplx;
4238
+ int32 ipli;
4239
+ int istart, iend;
4240
+ int32 iflJ2000;
4241
+ double plm;
4242
+ double t = (tjd_et - J2000) / 36525, dt;
4243
+ double x[6], xx[24], *xp, xobs[6], x2000[6];
4244
+ double xpos[3][6], xnorm[6];
4245
+ double xposm[6];
4246
+ double xn[3][6], xs[3][6];
4247
+ double xq[3][6], xa[3][6];
4248
+ double xobs2[6], x2[6];
4249
+ double *xna, *xnd, *xpe, *xap;
4250
+ double incl, sema, ecce, parg, ea, vincl, vsema, vecce, pargx, eax;
4251
+ struct plan_data *pedp = &swed.pldat[SEI_EARTH];
4252
+ struct plan_data *psbdp = &swed.pldat[SEI_SUNBARY];
4253
+ struct plan_data pldat;
4254
+ double *xsun = psbdp->x;
4255
+ double *xear = pedp->x;
4256
+ double *ep;
4257
+ double Gmsm, dzmin;
4258
+ double rxy, rxyz, fac, sgn;
4259
+ double sinnode, cosnode, sinincl, cosincl, sinu, cosu, sinE, cosE, cosE2;
4260
+ double uu, ny, ny2, c2, v2, pp, ro, ro2, rn, rn2;
4261
+ struct epsilon *oe;
4262
+ AS_BOOL is_true_nodaps = FALSE;
4263
+ AS_BOOL do_aberr = !(iflag & (SEFLG_TRUEPOS | SEFLG_NOABERR));
4264
+ AS_BOOL do_defl = !(iflag & SEFLG_TRUEPOS) && !(iflag & SEFLG_NOGDEFL);
4265
+ AS_BOOL do_focal_point = method & SE_NODBIT_FOPOINT;
4266
+ AS_BOOL ellipse_is_bary = FALSE;
4267
+ int32 iflg0;
4268
+ /* function calls for Pluto with asteroid number 134340
4269
+ * are treated as calls for Pluto as main body SE_PLUTO */
4270
+ if (ipl == SE_AST_OFFSET + 134340)
4271
+ ipl = SE_PLUTO;
4272
+ xna = xx;
4273
+ xnd = xx+6;
4274
+ xpe = xx+12;
4275
+ xap = xx+18;
4276
+ xpos[0][0] = 0; /* to shut up mint */
4277
+ /* to get control over the save area: */
4278
+ swi_force_app_pos_etc();
4279
+ method %= SE_NODBIT_FOPOINT;
4280
+ ipli = ipl;
4281
+ if (ipl == SE_SUN)
4282
+ ipli = SE_EARTH;
4283
+ if (ipl == SE_MOON) {
4284
+ do_defl = FALSE;
4285
+ if (!(iflag & SEFLG_HELCTR))
4286
+ do_aberr = FALSE;
4287
+ }
4288
+ iflg0 = (iflag & (SEFLG_EPHMASK|SEFLG_NONUT)) | SEFLG_SPEED | SEFLG_TRUEPOS;
4289
+ if (ipli != SE_MOON)
4290
+ iflg0 |= SEFLG_HELCTR;
4291
+ if (ipl == SE_MEAN_NODE || ipl == SE_TRUE_NODE ||
4292
+ ipl == SE_MEAN_APOG || ipl == SE_OSCU_APOG ||
4293
+ ipl < 0 ||
4294
+ (ipl >= SE_NPLANETS && ipl <= SE_AST_OFFSET)) {
4295
+ /*(ipl >= SE_FICT_OFFSET && ipl - SE_FICT_OFFSET < SE_NFICT_ELEM)) */
4296
+ if (serr != NULL)
4297
+ sprintf(serr, "nodes/apsides for planet %5.0f are not implemented", (double) ipl);
4298
+ if (xnasc != NULL)
4299
+ for (i = 0; i <= 5; i++)
4300
+ xnasc[i] = 0;
4301
+ if (xndsc != NULL)
4302
+ for (i = 0; i <= 5; i++)
4303
+ xndsc[i] = 0;
4304
+ if (xaphe != NULL)
4305
+ for (i = 0; i <= 5; i++)
4306
+ xaphe[i] = 0;
4307
+ if (xperi != NULL)
4308
+ for (i = 0; i <= 5; i++)
4309
+ xperi[i] = 0;
4310
+ return ERR;
4311
+ }
4312
+ for (i = 0; i < 24; i++)
4313
+ xx[i] = 0;
4314
+ /***************************************
4315
+ * mean nodes and apsides
4316
+ ***************************************/
4317
+ /* mean points only for Sun - Neptune */
4318
+ if ((method == 0 || (method & SE_NODBIT_MEAN)) &&
4319
+ ((ipl >= SE_SUN && ipl <= SE_NEPTUNE) || ipl == SE_EARTH)) {
4320
+ if (ipl == SE_MOON) {
4321
+ swi_mean_lunar_elements(tjd_et, &xna[0], &xna[3], &xpe[0], &xpe[3]);
4322
+ incl = MOON_MEAN_INCL;
4323
+ vincl = 0;
4324
+ ecce = MOON_MEAN_ECC;
4325
+ vecce = 0;
4326
+ sema = MOON_MEAN_DIST / AUNIT;
4327
+ vsema = 0;
4328
+ } else {
4329
+ iplx = ipl_to_elem[ipl];
4330
+ ep = el_incl[iplx];
4331
+ incl = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t;
4332
+ vincl = ep[1] / 36525;
4333
+ ep = el_sema[iplx];
4334
+ sema = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t;
4335
+ vsema = ep[1] / 36525;
4336
+ ep = el_ecce[iplx];
4337
+ ecce = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t;
4338
+ vecce = ep[1] / 36525;
4339
+ ep = el_node[iplx];
4340
+ /* ascending node */
4341
+ xna[0] = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t;
4342
+ xna[3] = ep[1] / 36525;
4343
+ /* perihelion */
4344
+ ep = el_peri[iplx];
4345
+ xpe[0] = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t;
4346
+ xpe[3] = ep[1] / 36525;
4347
+ }
4348
+ /* descending node */
4349
+ xnd[0] = swe_degnorm(xna[0] + 180);
4350
+ xnd[3] = xna[3];
4351
+ /* angular distance of perihelion from node */
4352
+ parg = xpe[0] = swe_degnorm(xpe[0] - xna[0]);
4353
+ pargx = xpe[3] = swe_degnorm(xpe[0] + xpe[3] - xna[3]);
4354
+ /* transform from orbital plane to mean ecliptic of date */
4355
+ swe_cotrans(xpe, xpe, -incl);
4356
+ /* xpe+3 is aux. position, not speed!!! */
4357
+ swe_cotrans(xpe+3, xpe+3, -incl-vincl);
4358
+ /* add node again */
4359
+ xpe[0] = swe_degnorm(xpe[0] + xna[0]);
4360
+ /* xpe+3 is aux. position, not speed!!! */
4361
+ xpe[3] = swe_degnorm(xpe[3] + xna[0] + xna[3]);
4362
+ /* speed */
4363
+ xpe[3] = swe_degnorm(xpe[3] - xpe[0]);
4364
+ /* heliocentric distance of perihelion and aphelion */
4365
+ xpe[2] = sema * (1 - ecce);
4366
+ xpe[5] = (sema + vsema) * (1 - ecce - vecce) - xpe[2];
4367
+ /* aphelion */
4368
+ xap[0] = swe_degnorm(xpe[0] + 180);
4369
+ xap[1] = -xpe[1];
4370
+ xap[3] = xpe[3];
4371
+ xap[4] = -xpe[4];
4372
+ if (do_focal_point) {
4373
+ xap[2] = sema * ecce * 2;
4374
+ xap[5] = (sema + vsema) * (ecce + vecce) * 2 - xap[2];
4375
+ } else {
4376
+ xap[2] = sema * (1 + ecce);
4377
+ xap[5] = (sema + vsema) * (1 + ecce + vecce) - xap[2];
4378
+ }
4379
+ /* heliocentric distance of nodes */
4380
+ ea = atan(tan(-parg * DEGTORAD / 2) * sqrt((1-ecce)/(1+ecce))) * 2;
4381
+ eax = atan(tan(-pargx * DEGTORAD / 2) * sqrt((1-ecce-vecce)/(1+ecce+vecce))) * 2;
4382
+ xna[2] = sema * (cos(ea) - ecce) / cos(parg * DEGTORAD);
4383
+ xna[5] = (sema+vsema) * (cos(eax) - ecce - vecce) / cos(pargx * DEGTORAD);
4384
+ xna[5] -= xna[2];
4385
+ ea = atan(tan((180 - parg) * DEGTORAD / 2) * sqrt((1-ecce)/(1+ecce))) * 2;
4386
+ eax = atan(tan((180 - pargx) * DEGTORAD / 2) * sqrt((1-ecce-vecce)/(1+ecce+vecce))) * 2;
4387
+ xnd[2] = sema * (cos(ea) - ecce) / cos((180 - parg) * DEGTORAD);
4388
+ xnd[5] = (sema+vsema) * (cos(eax) - ecce - vecce) / cos((180 - pargx) * DEGTORAD);
4389
+ xnd[5] -= xnd[2];
4390
+ /* no light-time correction because speed is extremely small */
4391
+ for (i = 0, xp = xx; i < 4; i++, xp += 6) {
4392
+ /* to cartesian coordinates */
4393
+ xp[0] *= DEGTORAD;
4394
+ xp[1] *= DEGTORAD;
4395
+ xp[3] *= DEGTORAD;
4396
+ xp[4] *= DEGTORAD;
4397
+ swi_polcart_sp(xp, xp);
4398
+ }
4399
+ /***************************************
4400
+ * "true" or osculating nodes and apsides
4401
+ ***************************************/
4402
+ } else {
4403
+ /* first, we need a heliocentric distance of the planet */
4404
+ if (swe_calc(tjd_et, ipli, iflg0, x, serr) == ERR)
4405
+ return ERR;
4406
+ iflJ2000 = (iflag & SEFLG_EPHMASK)|SEFLG_J2000|SEFLG_EQUATORIAL|SEFLG_XYZ|SEFLG_TRUEPOS|SEFLG_NONUT|SEFLG_SPEED;
4407
+ ellipse_is_bary = FALSE;
4408
+ if (ipli != SE_MOON) {
4409
+ if ((method & SE_NODBIT_OSCU_BAR) && x[2] > 6) {
4410
+ iflJ2000 |= SEFLG_BARYCTR; /* only planets beyond Jupiter */
4411
+ ellipse_is_bary = TRUE;
4412
+ } else {
4413
+ iflJ2000 |= SEFLG_HELCTR;
4414
+ }
4415
+ }
4416
+ /* we need three positions and three speeds
4417
+ * for three nodes/apsides. from the three node positions,
4418
+ * the speed of the node will be computed. */
4419
+ if (ipli == SE_MOON) {
4420
+ dt = NODE_CALC_INTV;
4421
+ dzmin = 1e-15;
4422
+ Gmsm = GEOGCONST * (1 + 1 / EARTH_MOON_MRAT) /AUNIT/AUNIT/AUNIT*86400.0*86400.0;
4423
+ } else {
4424
+ if ((ipli >= SE_MERCURY && ipli <= SE_PLUTO) || ipli == SE_EARTH)
4425
+ plm = 1 / plmass[ipl_to_elem[ipl]];
4426
+ else
4427
+ plm = 0;
4428
+ dt = NODE_CALC_INTV * 10 * x[2];
4429
+ dzmin = 1e-15 * dt / NODE_CALC_INTV;
4430
+ Gmsm = HELGRAVCONST * (1 + plm) /AUNIT/AUNIT/AUNIT*86400.0*86400.0;
4431
+ }
4432
+ if (iflag & SEFLG_SPEED) {
4433
+ istart = 0;
4434
+ iend = 2;
4435
+ } else {
4436
+ istart = iend = 0;
4437
+ dt = 0;
4438
+ }
4439
+ for (i = istart, t = tjd_et - dt; i <= iend; i++, t += dt) {
4440
+ if (istart == iend)
4441
+ t = tjd_et;
4442
+ if (swe_calc(t, ipli, iflJ2000, xpos[i], serr) == ERR)
4443
+ return ERR;
4444
+ /* the EMB is used instead of the earth */
4445
+ if (ipli == SE_EARTH) {
4446
+ if (swe_calc(t, SE_MOON, iflJ2000 & ~(SEFLG_BARYCTR|SEFLG_HELCTR), xposm, serr) == ERR)
4447
+ return ERR;
4448
+ for (j = 0; j <= 2; j++)
4449
+ xpos[i][j] += xposm[j] / (EARTH_MOON_MRAT + 1.0);
4450
+ }
4451
+ swi_plan_for_osc_elem(iflg0, t, xpos[i]);
4452
+ }
4453
+ for (i = istart; i <= iend; i++) {
4454
+ if (fabs(xpos[i][5]) < dzmin)
4455
+ xpos[i][5] = dzmin;
4456
+ fac = xpos[i][2] / xpos[i][5];
4457
+ sgn = xpos[i][5] / fabs(xpos[i][5]);
4458
+ for (j = 0; j <= 2; j++) {
4459
+ xn[i][j] = (xpos[i][j] - fac * xpos[i][j+3]) * sgn;
4460
+ xs[i][j] = -xn[i][j];
4461
+ }
4462
+ }
4463
+ for (i = istart; i <= iend; i++) {
4464
+ /* node */
4465
+ rxy = sqrt(xn[i][0] * xn[i][0] + xn[i][1] * xn[i][1]);
4466
+ cosnode = xn[i][0] / rxy;
4467
+ sinnode = xn[i][1] / rxy;
4468
+ /* inclination */
4469
+ swi_cross_prod(xpos[i], xpos[i]+3, xnorm);
4470
+ rxy = xnorm[0] * xnorm[0] + xnorm[1] * xnorm[1];
4471
+ c2 = (rxy + xnorm[2] * xnorm[2]);
4472
+ rxyz = sqrt(c2);
4473
+ rxy = sqrt(rxy);
4474
+ sinincl = rxy / rxyz;
4475
+ cosincl = sqrt(1 - sinincl * sinincl);
4476
+ if (xnorm[2] < 0) cosincl = -cosincl; /* retrograde asteroid, e.g. 20461 Dioretsa */
4477
+ /* argument of latitude */
4478
+ cosu = xpos[i][0] * cosnode + xpos[i][1] * sinnode;
4479
+ sinu = xpos[i][2] / sinincl;
4480
+ uu = atan2(sinu, cosu);
4481
+ /* semi-axis */
4482
+ rxyz = sqrt(square_sum(xpos[i]));
4483
+ v2 = square_sum((xpos[i]+3));
4484
+ sema = 1 / (2 / rxyz - v2 / Gmsm);
4485
+ /* eccentricity */
4486
+ pp = c2 / Gmsm;
4487
+ ecce = sqrt(1 - pp / sema);
4488
+ /* eccentric anomaly */
4489
+ cosE = 1 / ecce * (1 - rxyz / sema);
4490
+ sinE = 1 / ecce / sqrt(sema * Gmsm) * dot_prod(xpos[i], (xpos[i]+3));
4491
+ /* true anomaly */
4492
+ ny = 2 * atan(sqrt((1+ecce)/(1-ecce)) * sinE / (1 + cosE));
4493
+ /* distance of perihelion from ascending node */
4494
+ xq[i][0] = swi_mod2PI(uu - ny);
4495
+ xq[i][1] = 0; /* latitude */
4496
+ xq[i][2] = sema * (1 - ecce); /* distance of perihelion */
4497
+ /* transformation to ecliptic coordinates */
4498
+ swi_polcart(xq[i], xq[i]);
4499
+ swi_coortrf2(xq[i], xq[i], -sinincl, cosincl);
4500
+ swi_cartpol(xq[i], xq[i]);
4501
+ /* adding node, we get perihelion in ecl. coord. */
4502
+ xq[i][0] += atan2(sinnode, cosnode);
4503
+ xa[i][0] = swi_mod2PI(xq[i][0] + PI);
4504
+ xa[i][1] = -xq[i][1];
4505
+ if (do_focal_point) {
4506
+ xa[i][2] = sema * ecce * 2; /* distance of aphelion */
4507
+ } else {
4508
+ xa[i][2] = sema * (1 + ecce); /* distance of aphelion */
4509
+ }
4510
+ swi_polcart(xq[i], xq[i]);
4511
+ swi_polcart(xa[i], xa[i]);
4512
+ /* new distance of node from orbital ellipse:
4513
+ * true anomaly of node: */
4514
+ ny = swi_mod2PI(ny - uu);
4515
+ ny2 = swi_mod2PI(ny + PI);
4516
+ /* eccentric anomaly */
4517
+ cosE = cos(2 * atan(tan(ny / 2) / sqrt((1+ecce) / (1-ecce))));
4518
+ cosE2 = cos(2 * atan(tan(ny2 / 2) / sqrt((1+ecce) / (1-ecce))));
4519
+ /* new distance */
4520
+ rn = sema * (1 - ecce * cosE);
4521
+ rn2 = sema * (1 - ecce * cosE2);
4522
+ /* old node distance */
4523
+ ro = sqrt(square_sum(xn[i]));
4524
+ ro2 = sqrt(square_sum(xs[i]));
4525
+ /* correct length of position vector */
4526
+ for (j = 0; j <= 2; j++) {
4527
+ xn[i][j] *= rn / ro;
4528
+ xs[i][j] *= rn2 / ro2;
4529
+ }
4530
+ }
4531
+ for (i = 0; i <= 2; i++) {
4532
+ if (iflag & SEFLG_SPEED) {
4533
+ xpe[i] = xq[1][i];
4534
+ xpe[i+3] = (xq[2][i] - xq[0][i]) / dt / 2;
4535
+ xap[i] = xa[1][i];
4536
+ xap[i+3] = (xa[2][i] - xa[0][i]) / dt / 2;
4537
+ xna[i] = xn[1][i];
4538
+ xna[i+3] = (xn[2][i] - xn[0][i]) / dt / 2;
4539
+ xnd[i] = xs[1][i];
4540
+ xnd[i+3] = (xs[2][i] - xs[0][i]) / dt / 2;
4541
+ } else {
4542
+ xpe[i] = xq[0][i];
4543
+ xpe[i+3] = 0;
4544
+ xap[i] = xa[0][i];
4545
+ xap[i+3] = 0;
4546
+ xna[i] = xn[0][i];
4547
+ xna[i+3] = 0;
4548
+ xnd[i] = xs[0][i];
4549
+ xnd[i+3] = 0;
4550
+ }
4551
+ }
4552
+ is_true_nodaps = TRUE;
4553
+ }
4554
+ /* to set the variables required in the save area,
4555
+ * i.e. ecliptic, nutation, barycentric sun, earth
4556
+ * we compute the planet */
4557
+ if (ipli == SE_MOON && (iflag & (SEFLG_HELCTR | SEFLG_BARYCTR))) {
4558
+ swi_force_app_pos_etc();
4559
+ if (swe_calc(tjd_et, SE_SUN, iflg0, x, serr) == ERR)
4560
+ return ERR;
4561
+ } else {
4562
+ if (swe_calc(tjd_et, ipli, iflg0 | (iflag & SEFLG_TOPOCTR), x, serr) == ERR)
4563
+ return ERR;
4564
+ }
4565
+ /***********************
4566
+ * position of observer
4567
+ ***********************/
4568
+ if (iflag & SEFLG_TOPOCTR) {
4569
+ /* geocentric position of observer */
4570
+ if (swi_get_observer(tjd_et, iflag, FALSE, xobs, serr) != OK)
4571
+ return ERR;
4572
+ /*for (i = 0; i <= 5; i++)
4573
+ xobs[i] = swed.topd.xobs[i];*/
4574
+ } else {
4575
+ for (i = 0; i <= 5; i++)
4576
+ xobs[i] = 0;
4577
+ }
4578
+ if (iflag & (SEFLG_HELCTR | SEFLG_BARYCTR)) {
4579
+ if ((iflag & SEFLG_HELCTR) && !(iflag & SEFLG_MOSEPH))
4580
+ for (i = 0; i <= 5; i++)
4581
+ xobs[i] = xsun[i];
4582
+ } else if (ipl == SE_SUN && !(iflag & SEFLG_MOSEPH)) {
4583
+ for (i = 0; i <= 5; i++)
4584
+ xobs[i] = xsun[i];
4585
+ } else {
4586
+ /* barycentric position of observer */
4587
+ for (i = 0; i <= 5; i++)
4588
+ xobs[i] += xear[i];
4589
+ }
4590
+ /* ecliptic obliqity */
4591
+ if (iflag & SEFLG_J2000)
4592
+ oe = &swed.oec2000;
4593
+ else
4594
+ oe = &swed.oec;
4595
+ /*************************************************
4596
+ * conversions shared by mean and osculating points
4597
+ *************************************************/
4598
+ for (ij = 0, xp = xx; ij < 4; ij++, xp += 6) {
4599
+ /* no nodes for earth */
4600
+ if (ipli == SE_EARTH && ij <= 1) {
4601
+ for (i = 0; i <= 5; i++)
4602
+ xp[i] = 0;
4603
+ continue;
4604
+ }
4605
+ /*********************
4606
+ * to equator
4607
+ *********************/
4608
+ if (is_true_nodaps && !(iflag & SEFLG_NONUT)) {
4609
+ swi_coortrf2(xp, xp, -swed.nut.snut, swed.nut.cnut);
4610
+ if (iflag & SEFLG_SPEED)
4611
+ swi_coortrf2(xp+3, xp+3, -swed.nut.snut, swed.nut.cnut);
4612
+ }
4613
+ swi_coortrf2(xp, xp, -oe->seps, oe->ceps);
4614
+ swi_coortrf2(xp+3, xp+3, -oe->seps, oe->ceps);
4615
+ if (is_true_nodaps) {
4616
+ /****************************
4617
+ * to mean ecliptic of date
4618
+ ****************************/
4619
+ if (!(iflag & SEFLG_NONUT))
4620
+ swi_nutate(xp, iflag, TRUE);
4621
+ }
4622
+ /*********************
4623
+ * to J2000
4624
+ *********************/
4625
+ swi_precess(xp, tjd_et, J_TO_J2000);
4626
+ if (iflag & SEFLG_SPEED)
4627
+ swi_precess_speed(xp, tjd_et, J_TO_J2000);
4628
+ /*********************
4629
+ * to barycenter
4630
+ *********************/
4631
+ if (ipli == SE_MOON) {
4632
+ for (i = 0; i <= 5; i++)
4633
+ xp[i] += xear[i];
4634
+ } else {
4635
+ if (!(iflag & SEFLG_MOSEPH) && !ellipse_is_bary)
4636
+ for (j = 0; j <= 5; j++)
4637
+ xp[j] += xsun[j];
4638
+ }
4639
+ /*********************
4640
+ * to correct center
4641
+ *********************/
4642
+ for (j = 0; j <= 5; j++)
4643
+ xp[j] -= xobs[j];
4644
+ /* geocentric perigee/apogee of sun */
4645
+ if (ipl == SE_SUN && !(iflag & (SEFLG_HELCTR | SEFLG_BARYCTR)))
4646
+ for (j = 0; j <= 5; j++)
4647
+ xp[j] = -xp[j];
4648
+ /*********************
4649
+ * light deflection
4650
+ *********************/
4651
+ dt = sqrt(square_sum(xp)) * AUNIT / CLIGHT / 86400.0;
4652
+ if (do_defl)
4653
+ swi_deflect_light(xp, dt, iflag);
4654
+ /*********************
4655
+ * aberration
4656
+ *********************/
4657
+ if (do_aberr) {
4658
+ swi_aberr_light(xp, xobs, iflag);
4659
+ /*
4660
+ * Apparent speed is also influenced by
4661
+ * the difference of speed of the earth between t and t-dt.
4662
+ * Neglecting this would result in an error of several 0.1"
4663
+ */
4664
+ if (iflag & SEFLG_SPEED) {
4665
+ /* get barycentric sun and earth for t-dt into save area */
4666
+ if (swe_calc(tjd_et - dt, ipli, iflg0 | (iflag & SEFLG_TOPOCTR), x2, serr) == ERR)
4667
+ return ERR;
4668
+ if (iflag & SEFLG_TOPOCTR) {
4669
+ /* geocentric position of observer */
4670
+ /* if (swi_get_observer(tjd_et - dt, iflag, FALSE, xobs, serr) != OK)
4671
+ return ERR;*/
4672
+ for (i = 0; i <= 5; i++)
4673
+ xobs2[i] = swed.topd.xobs[i];
4674
+ } else {
4675
+ for (i = 0; i <= 5; i++)
4676
+ xobs2[i] = 0;
4677
+ }
4678
+ if (iflag & (SEFLG_HELCTR | SEFLG_BARYCTR)) {
4679
+ if ((iflag & SEFLG_HELCTR) && !(iflag & SEFLG_MOSEPH))
4680
+ for (i = 0; i <= 5; i++)
4681
+ xobs2[i] = xsun[i];
4682
+ } else if (ipl == SE_SUN && !(iflag & SEFLG_MOSEPH)) {
4683
+ for (i = 0; i <= 5; i++)
4684
+ xobs2[i] = xsun[i];
4685
+ } else {
4686
+ /* barycentric position of observer */
4687
+ for (i = 0; i <= 5; i++)
4688
+ xobs2[i] += xear[i];
4689
+ }
4690
+ for (i = 3; i <= 5; i++)
4691
+ xp[i] += xobs[i] - xobs2[i];
4692
+ /* The above call of swe_calc() has destroyed the
4693
+ * parts of the save area
4694
+ * (i.e. bary sun, earth nutation matrix!).
4695
+ * to restore it:
4696
+ */
4697
+ if (swe_calc(tjd_et, SE_SUN, iflg0 | (iflag & SEFLG_TOPOCTR), x2, serr) == ERR)
4698
+ return ERR;
4699
+ }
4700
+ }
4701
+ /*********************
4702
+ * precession
4703
+ *********************/
4704
+ /* save J2000 coordinates; required for sidereal positions */
4705
+ for (j = 0; j <= 5; j++)
4706
+ x2000[j] = xp[j];
4707
+ if (!(iflag & SEFLG_J2000)) {
4708
+ swi_precess(xp, tjd_et, J2000_TO_J);
4709
+ if (iflag & SEFLG_SPEED)
4710
+ swi_precess_speed(xp, tjd_et, J2000_TO_J);
4711
+ }
4712
+ /*********************
4713
+ * nutation
4714
+ *********************/
4715
+ if (!(iflag & SEFLG_NONUT))
4716
+ swi_nutate(xp, iflag, FALSE);
4717
+ /* now we have equatorial cartesian coordinates; keep them */
4718
+ for (j = 0; j <= 5; j++)
4719
+ pldat.xreturn[18+j] = xp[j];
4720
+ /************************************************
4721
+ * transformation to ecliptic. *
4722
+ * with sidereal calc. this will be overwritten *
4723
+ * afterwards. *
4724
+ ************************************************/
4725
+ swi_coortrf2(xp, xp, oe->seps, oe->ceps);
4726
+ if (iflag & SEFLG_SPEED)
4727
+ swi_coortrf2(xp+3, xp+3, oe->seps, oe->ceps);
4728
+ if (!(iflag & SEFLG_NONUT)) {
4729
+ swi_coortrf2(xp, xp, swed.nut.snut, swed.nut.cnut);
4730
+ if (iflag & SEFLG_SPEED)
4731
+ swi_coortrf2(xp+3, xp+3, swed.nut.snut, swed.nut.cnut);
4732
+ }
4733
+ /* now we have ecliptic cartesian coordinates */
4734
+ for (j = 0; j <= 5; j++)
4735
+ pldat.xreturn[6+j] = xp[j];
4736
+ /************************************
4737
+ * sidereal positions *
4738
+ ************************************/
4739
+ if (iflag & SEFLG_SIDEREAL) {
4740
+ /* project onto ecliptic t0 */
4741
+ if (swed.sidd.sid_mode & SE_SIDBIT_ECL_T0) {
4742
+ if (swi_trop_ra2sid_lon(x2000, pldat.xreturn+6, pldat.xreturn+18, iflag, serr) != OK)
4743
+ return ERR;
4744
+ /* project onto solar system equator */
4745
+ } else if (swed.sidd.sid_mode & SE_SIDBIT_SSY_PLANE) {
4746
+ if (swi_trop_ra2sid_lon_sosy(x2000, pldat.xreturn+6, pldat.xreturn+18, iflag, serr) != OK)
4747
+ return ERR;
4748
+ } else {
4749
+ /* traditional algorithm */
4750
+ swi_cartpol_sp(pldat.xreturn+6, pldat.xreturn);
4751
+ pldat.xreturn[0] -= swe_get_ayanamsa(tjd_et) * DEGTORAD;
4752
+ swi_polcart_sp(pldat.xreturn, pldat.xreturn+6);
4753
+ }
4754
+ }
4755
+ if ((iflag & SEFLG_XYZ) && (iflag & SEFLG_EQUATORIAL)) {
4756
+ for (j = 0; j <= 5; j++)
4757
+ xp[j] = pldat.xreturn[18+j];
4758
+ continue;
4759
+ }
4760
+ if (iflag & SEFLG_XYZ) {
4761
+ for (j = 0; j <= 5; j++)
4762
+ xp[j] = pldat.xreturn[6+j];
4763
+ continue;
4764
+ }
4765
+ /************************************************
4766
+ * transformation to polar coordinates *
4767
+ ************************************************/
4768
+ swi_cartpol_sp(pldat.xreturn+18, pldat.xreturn+12);
4769
+ swi_cartpol_sp(pldat.xreturn+6, pldat.xreturn);
4770
+ /**********************
4771
+ * radians to degrees *
4772
+ **********************/
4773
+ for (j = 0; j < 2; j++) {
4774
+ pldat.xreturn[j] *= RADTODEG; /* ecliptic */
4775
+ pldat.xreturn[j+3] *= RADTODEG;
4776
+ pldat.xreturn[j+12] *= RADTODEG; /* equator */
4777
+ pldat.xreturn[j+15] *= RADTODEG;
4778
+ }
4779
+ if (iflag & SEFLG_EQUATORIAL) {
4780
+ for (j = 0; j <= 5; j++)
4781
+ xp[j] = pldat.xreturn[12+j];
4782
+ continue;
4783
+ } else {
4784
+ for (j = 0; j <= 5; j++)
4785
+ xp[j] = pldat.xreturn[j];
4786
+ continue;
4787
+ }
4788
+ }
4789
+ for (i = 0; i <= 5; i++) {
4790
+ if (i > 2 && !(iflag & SEFLG_SPEED))
4791
+ xna[i] = xnd[i] = xpe[i] = xap[i] = 0;
4792
+ if (xnasc != NULL)
4793
+ xnasc[i] = xna[i];
4794
+ if (xndsc != NULL)
4795
+ xndsc[i] = xnd[i];
4796
+ if (xperi != NULL)
4797
+ xperi[i] = xpe[i];
4798
+ if (xaphe != NULL)
4799
+ xaphe[i] = xap[i];
4800
+ }
4801
+ return OK;
4802
+ }
4803
+
4804
+ int32 FAR PASCAL_CONV swe_nod_aps_ut(double tjd_ut, int32 ipl, int32 iflag,
4805
+ int32 method,
4806
+ double *xnasc, double *xndsc,
4807
+ double *xperi, double *xaphe,
4808
+ char *serr) {
4809
+ return swe_nod_aps(tjd_ut + swe_deltat(tjd_ut),
4810
+ ipl, iflag, method, xnasc, xndsc, xperi, xaphe,
4811
+ serr);
4812
+ }
4813
+
4814
+ /* function finds the gauquelin sector position of a planet or fixed star
4815
+ *
4816
+ * if starname != NULL then a star is computed.
4817
+ * iflag: use the flags SE_SWIEPH, SE_JPLEPH, SE_MOSEPH, SEFLG_TOPOCTR.
4818
+ *
4819
+ * imeth defines method:
4820
+ * imeth = 0 use Placidus house position
4821
+ * imeth = 1 use Placidus house posiition (with planetary lat = 0)
4822
+ * imeth = 2 use rise and set of body's disc center
4823
+ * imeth = 3 use rise and set of body's disc center with refraction
4824
+ * rise and set are defined as appearance and disappearance of disc center
4825
+ *
4826
+ * geopos is an array of 3 doubles for geo. longitude, geo. latitude, elevation.
4827
+ * atpress and attemp are only needed for imeth = 3. If imeth = 3,
4828
+ * If imeth=3 and atpress not given (= 0), the programm assumes 1013.25 mbar;
4829
+ * if a non-zero height above sea is given in geopos, atpress is estimated.
4830
+ * dgsect is return area (pointer to a double)
4831
+ * serr is pointer to error string, may be NULL
4832
+ */
4833
+ int32 FAR PASCAL_CONV swe_gauquelin_sector(double t_ut, int32 ipl, char *starname, int32 iflag, int32 imeth, double *geopos, double atpress, double attemp, double *dgsect, char *serr)
4834
+ {
4835
+ AS_BOOL rise_found = TRUE;
4836
+ AS_BOOL set_found = TRUE;
4837
+ int32 retval;
4838
+ double tret[3];
4839
+ double t_et, t;
4840
+ double x0[6];
4841
+ double eps, nutlo[2], armc;
4842
+ int32 epheflag = iflag & SEFLG_EPHMASK;
4843
+ AS_BOOL do_fixstar = (starname != NULL && *starname != '\0');
4844
+ int32 risemeth = 0;
4845
+ AS_BOOL above_horizon = FALSE;
4846
+ if (imeth < 0 || imeth > 5) {
4847
+ if (serr)
4848
+ sprintf(serr, "invalid method: %d", imeth);
4849
+ return ERR;
4850
+ }
4851
+ /* function calls for Pluto with asteroid number 134340
4852
+ * are treated as calls for Pluto as main body SE_PLUTO */
4853
+ if (ipl == SE_AST_OFFSET + 134340)
4854
+ ipl = SE_PLUTO;
4855
+ /*
4856
+ * geometrically from ecl. longitude and latitude
4857
+ */
4858
+ if (imeth == 0 || imeth == 1) {
4859
+ t_et = t_ut + swe_deltat(t_ut);
4860
+ eps = swi_epsiln(t_et) * RADTODEG;
4861
+ swi_nutation(t_et, nutlo);
4862
+ nutlo[0] *= RADTODEG;
4863
+ nutlo[1] *= RADTODEG;
4864
+ armc = swe_degnorm(swe_sidtime0(t_ut, eps + nutlo[1], nutlo[0]) * 15 + geopos[0]);
4865
+ if (do_fixstar) {
4866
+ if (swe_fixstar(starname, t_et, iflag, x0, serr) == ERR)
4867
+ return ERR;
4868
+ } else {
4869
+ if (swe_calc(t_et, ipl, iflag, x0, serr) == ERR)
4870
+ return ERR;
4871
+ }
4872
+ if (imeth == 1)
4873
+ x0[1] = 0;
4874
+ *dgsect = swe_house_pos(armc, geopos[1], eps + nutlo[1], 'G', x0, NULL);
4875
+ return OK;
4876
+ }
4877
+ /*
4878
+ * from rise and set times
4879
+ */
4880
+ if (imeth == 2 || imeth == 4)
4881
+ risemeth |= SE_BIT_NO_REFRACTION;
4882
+ if (imeth == 2 || imeth == 3)
4883
+ risemeth |= SE_BIT_DISC_CENTER;
4884
+ /* find the next rising time of the planet or star */
4885
+ retval = swe_rise_trans(t_ut, ipl, starname, epheflag, SE_CALC_RISE|risemeth, geopos, atpress, attemp, &(tret[0]), serr);
4886
+ if (retval == ERR) {
4887
+ return ERR;
4888
+ } else if (retval == -2) {
4889
+ /* actually, we could return ERR here. However, we
4890
+ * keep this variable, in case we implement an algorithm
4891
+ * for Gauquelin sector positions of circumpolar bodies.
4892
+ * As with the Ludwig Otto procedure with Placidus, one
4893
+ * could replace missing rises or sets by meridian transits,
4894
+ * although there are cases where even this is not possible.
4895
+ * Sometimes a body both appears and disappears on the western
4896
+ * part of the horizon. Using true culminations rather than meridan
4897
+ * transits would not help in any case either, because there are
4898
+ * cases where a body does not have a culmination within days,
4899
+ * e.g. the sun near the poles.
4900
+ */
4901
+ rise_found = FALSE;
4902
+ }
4903
+ /* find the next setting time of the planet or star */
4904
+ retval = swe_rise_trans(t_ut, ipl, starname, epheflag, SE_CALC_SET|risemeth, geopos, atpress, attemp, &(tret[1]), serr);
4905
+ if (retval == ERR) {
4906
+ return ERR;
4907
+ } else if (retval == -2) {
4908
+ set_found = FALSE;
4909
+ }
4910
+ if (tret[0] < tret[1] && rise_found == TRUE) {
4911
+ above_horizon = FALSE;
4912
+ /* find last set */
4913
+ t = t_ut - 1.2;
4914
+ if (set_found) t = tret[1] - 1.2;
4915
+ set_found = TRUE;
4916
+ retval = swe_rise_trans(t, ipl, starname, epheflag, SE_CALC_SET|risemeth, geopos, atpress, attemp, &(tret[1]), serr);
4917
+ if (retval == ERR) {
4918
+ return ERR;
4919
+ } else if (retval == -2) {
4920
+ set_found = FALSE;
4921
+ }
4922
+ } else if (tret[0] >= tret[1] && set_found == TRUE) {
4923
+ above_horizon = TRUE;
4924
+ /* find last rise */
4925
+ t = t_ut - 1.2;
4926
+ if (rise_found) t = tret[0] - 1.2;
4927
+ rise_found = TRUE;
4928
+ retval = swe_rise_trans(t, ipl, starname, epheflag, SE_CALC_RISE|risemeth, geopos, atpress, attemp, &(tret[0]), serr);
4929
+ if (retval == ERR) {
4930
+ return ERR;
4931
+ } else if (retval == -2) {
4932
+ rise_found = FALSE;
4933
+ }
4934
+ }
4935
+ if (rise_found && set_found) {
4936
+ if (above_horizon) {
4937
+ *dgsect = (t_ut - tret[0]) / (tret[1] - tret[0]) * 18 + 1;
4938
+ } else {
4939
+ *dgsect = (t_ut - tret[1]) / (tret[0] - tret[1]) * 18 + 19;
4940
+ }
4941
+ return OK;
4942
+ } else {
4943
+ *dgsect = 0;
4944
+ if (serr)
4945
+ sprintf(serr, "rise or set not found for planet %d", ipl);
4946
+ return ERR;
4947
+ }
4948
+ }