@swisseph/node 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2936 @@
1
+ /* SWISSEPH
2
+
3
+ **************************************************************/
4
+ /* Copyright (C) 1997 - 2021 Astrodienst AG, Switzerland. All rights reserved.
5
+
6
+ License conditions
7
+ ------------------
8
+
9
+ This file is part of Swiss Ephemeris.
10
+
11
+ Swiss Ephemeris is distributed with NO WARRANTY OF ANY KIND. No author
12
+ or distributor accepts any responsibility for the consequences of using it,
13
+ or for whether it serves any particular purpose or works at all, unless he
14
+ or she says so in writing.
15
+
16
+ Swiss Ephemeris is made available by its authors under a dual licensing
17
+ system. The software developer, who uses any part of Swiss Ephemeris
18
+ in his or her software, must choose between one of the two license models,
19
+ which are
20
+ a) GNU Affero General Public License (AGPL)
21
+ b) Swiss Ephemeris Professional License
22
+
23
+ The choice must be made before the software developer distributes software
24
+ containing parts of Swiss Ephemeris to others, and before any public
25
+ service using the developed software is activated.
26
+
27
+ If the developer choses the AGPL software license, he or she must fulfill
28
+ the conditions of that license, which includes the obligation to place his
29
+ or her whole software project under the AGPL or a compatible license.
30
+ See https://www.gnu.org/licenses/agpl-3.0.html
31
+
32
+ If the developer choses the Swiss Ephemeris Professional license,
33
+ he must follow the instructions as found in http://www.astro.com/swisseph/
34
+ and purchase the Swiss Ephemeris Professional Edition from Astrodienst
35
+ and sign the corresponding license contract.
36
+
37
+ The License grants you the right to use, copy, modify and redistribute
38
+ Swiss Ephemeris, but only under certain conditions described in the License.
39
+ Among other things, the License requires that the copyright notices and
40
+ this notice be preserved on all copies.
41
+
42
+ Authors of the Swiss Ephemeris: Dieter Koch and Alois Treindl
43
+
44
+ The authors of Swiss Ephemeris have no control or influence over any of
45
+ the derived works, i.e. over software or services created by other
46
+ programmers which use Swiss Ephemeris functions.
47
+
48
+ The names of the authors or of the copyright holder (Astrodienst) must not
49
+ be used for promoting any software, product or service which uses or contains
50
+ the Swiss Ephemeris. This copyright notice is the ONLY place where the
51
+ names of the authors can legally appear, except in cases where they have
52
+ given special permission in writing.
53
+
54
+ The trademarks 'Swiss Ephemeris' and 'Swiss Ephemeris inside' may be used
55
+ for promoting such software, products or services.
56
+ */
57
+
58
+ static char *info = "\n\
59
+ Computes planetary phenomena\n\
60
+ for a given start date and a time range.\n\
61
+ Input can either be a date or an absolute julian day number.\n\
62
+ 0:00 (midnight).\n\
63
+ Precision of this program:\n\
64
+ Conjunctions: Deviations from Rosicrucian Ephemeris result from\n\
65
+ the fact that R.E. gives ephemeris time.\n\
66
+ Ingresses: ditto.\n\
67
+ Stations: ditto. The stations given by AA are different, they\n\
68
+ are in rectascension.\n\
69
+ Max. Elongations: AA gives date and hour. This program computes \n\
70
+ e.g. 20 Aug. 96, 3:28. AA has a rounded value of 4h.\n\
71
+ Transits: There is no venus transit in 20th cty.\n\
72
+ There was a transit of mercury in 1993. The ingress\n\
73
+ and egress times computed by this program agree\n\
74
+ exactly with AA93, p. A86.\n\
75
+ Visibility: elongation > 10 degrees, according to AA.\n\
76
+ gr. brillancy: Our times of greatest brillancy differ from the\n\
77
+ ones given by AA94 and AA96, p. A3, by several days.\n\
78
+ Probably an error of AA. The times on p. A3 are\n\
79
+ inconsistent with the magnitudes listed on p. A4.\n\
80
+ The maxima computed by this program are consistent\n\
81
+ with these magnitude tables.\n\
82
+ \n\
83
+ Command line options:\n\
84
+ \n\
85
+ example:\n\
86
+ swevents -p3 -bj2436723.5 -n1000 -s1 -ejpl \n\
87
+ for -p2 (mercury), use -s0.3 \n\
88
+ \n\
89
+ -mscreen output on screen\n\
90
+ -mps postscript [default: HP Laserjet]\n\
91
+ -cl do not print command line at bottom of 1st page\n\
92
+ -p planet to be computed.\n\
93
+ See the letter coding below.\n\
94
+ -nN output data for N consecutive days; if no -n option\n\
95
+ is given, the default is 1. If the option -n without a\n\
96
+ number is given, the default is 20.\n\
97
+ -sN timestep N days, default 1. This option is only meaningful\n\
98
+ when combined with option -n.\n\
99
+ -edirPATH change the directory of the ephemeris files \n\
100
+ -cycol.. number cycles per column\n\
101
+ -doall | -doingr etc : do just that\n\
102
+ -doing45 crossings over 15 tau, Leo, Sco, Aqu\n\
103
+ (are not included with doall)\n\
104
+ -noingr no ingresses\n\
105
+ -motab special format Moon ingres table\n\
106
+ -mojap special format Moon phases\n\
107
+ -bDATE use this begin date instead of asking; use -b1.1.1992 if\n\
108
+ the begin date string contains blanks; use format -bj2400000.5\n\
109
+ to express the date as absolute Julian day number.\n\
110
+ Note: the date format is day month year (European style).\n\
111
+ -eswe swiss ephemeris\n\
112
+ -ejpl jpl ephemeris (DE431), or with ephemeris file name\n\
113
+ -ejplde200.eph\n\
114
+ -emos moshier ephemeris\n\
115
+ -true true positions\n\
116
+ -noaberr no aberration\n\
117
+ -nodefl no gravitational light deflection\n\
118
+ -noprec no precession (i.e. J2000 positions)\n\
119
+ -nonut no nutation \n\
120
+ -dgap use gap within date\n\
121
+ -zlong use long sign names\n\
122
+ -znam3 use 3-letter sign names\n\
123
+ -monnum use month numbers instead of names\n\
124
+ -gmtoff X use X hours gmt offset (+ for east)\n\
125
+ -tzoneTIMEZONE output date and time in timezone (hours east)\n\
126
+ -transitstderr lists transits of Venus or Mercury as c style data to stderr \n\
127
+ -jd show also jd in output \n\
128
+ -ep use extended precision in output\n\
129
+ \n\
130
+ -? display this info\n\
131
+ \n\
132
+ Planet selection letters:\n\
133
+ 0 Sun (character zero)\n\
134
+ 1 Moon (character 1)\n\
135
+ 2 Mercury\n\
136
+ ....\n\
137
+ 9 Pluto\n\
138
+ 10 mean lunar node\n\
139
+ 11 true lunar node\n\
140
+ 12 mean lunar apogee\n\
141
+ 13 true lunar apogee\n\
142
+ 14 earth\n\
143
+ 15 chiron etc up to 22, see swephexp.h\n\
144
+ h00 .. h18 fictitious factors, see swephexp.h\n\
145
+ \n\
146
+ Date entry:\n\
147
+ In the interactive mode, when you are asked for a start date,\n\
148
+ you can enter data in one of the following formats:\n\
149
+ \n\
150
+ 1.2.1991 three integers separated by a nondigit character for\n\
151
+ day month year. Dates are interpreted as Gregorian\n\
152
+ after 4.10.1582 and as Julian Calender before.\n\
153
+ Time is always set to midnight.\n\
154
+ If the three letters jul are appended to the date,\n\
155
+ the Julian calendar is used even after 1582.\n\
156
+ If the four letters greg are appended to the date,\n\
157
+ the Gregorian calendar is used even before 1582.\n\
158
+ \n\
159
+ j2400123.67 the letter j followed by a real number, for\n\
160
+ the absolute Julian daynumber of the start date.\n\
161
+ Fraction .5 indicates midnight, fraction .0\n\
162
+ indicates noon, other times of the day can be\n\
163
+ chosen accordingly.\n\
164
+ \n\
165
+ <RETURN> repeat the last entry\n\
166
+ \n\
167
+ . stop the program\n\
168
+ \n\
169
+ +20 advance the date by 20 days\n\
170
+ \n\
171
+ -10 go back in time 10 days\n";
172
+ /**************************************************************/
173
+
174
+ #define PRINTMOD 0
175
+
176
+ #if PRINTMOD
177
+ # include "ourdef.h"
178
+ # include "astrolib.h"
179
+ # include "printmod.h"
180
+ #else
181
+ # define PMODEL_SCREEN 10
182
+ #endif
183
+ #include "swephexp.h"
184
+ #include "swephlib.h"
185
+ #include "sweph.h"
186
+ #include "swevents.h"
187
+ #include <time.h>
188
+
189
+ #define MAX_LINES 67
190
+ #define MAX_COLS 2
191
+ double xcol[4] = {20.0, 110.0};
192
+ double xcol4[4] = {12.0, 60, 108.0, 156.0};
193
+ double xdate = 25; /* position of date */
194
+ double xpos = 52; /* position of date */
195
+ double ytop = 24;
196
+ double line_space = 4;
197
+ double gmtoff = 0;
198
+ int pmodel;
199
+ int ncycol = 0;
200
+ int do_flag = 0;
201
+ int prev_yout = -999999;
202
+ int max_cols = MAX_COLS;
203
+
204
+ #define J2000 2451545.0 /* 2000 January 1.5 */
205
+ #define square_sum(x) (x[0]*x[0]+x[1]*x[1]+x[2]*x[2])
206
+ #define SEFLG_EPHMASK (SEFLG_JPLEPH|SEFLG_SWIEPH|SEFLG_MOSEPH)
207
+ #define SUN_RADIUS (959.63 / 3600 * DEGTORAD) /* Meeus germ. p 391 */
208
+ #define VENUS_RADIUS (8.34 / 3600 * DEGTORAD) /* AA96 E43 */
209
+ #define MERCURY_RADIUS (3.36 / 3600 * DEGTORAD) /* AA96 E43 */
210
+ #define MARS_RADIUS (4.68 / 3600 * DEGTORAD) /* AA96 E43 */
211
+ #define UNUSED(expr) do { (void)(expr); } while (0)
212
+
213
+ #define BIT_ROUND_NO 0
214
+ #define BIT_ROUND_SEC 1
215
+ #define BIT_ROUND_MIN 2
216
+ #define BIT_ZODIAC 4
217
+ #define BIT_LZEROES 8
218
+
219
+ #define STRLEN_OUT_TEXT 20
220
+
221
+ static char *zod_nam[] = {"AR", "TA", "GE", "CN", "LE", "VI",
222
+ "LI", "SC", "SA", "CP", "AQ", "PI"};
223
+ static char *zod_nam3[] = {"ARI", "TAU", "GEM", "CAN", "LEO", "VIR",
224
+ "LIB", "SCO", "SAG", "CAP", "AQU", "PIS"};
225
+ static char *zod_nam_long[] = {"aries", "taurus", "gemini",
226
+ "cancer", "leo", "virgo",
227
+ "libra", "scorpio", "sagittarius",
228
+ "capricorn", "aquarius", "pisces"};
229
+ static char *month_nam[] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
230
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
231
+
232
+
233
+ static char motab[13][31][10]; /* table for moon ingresses */
234
+
235
+ char *planet_name;
236
+ AS_BOOL ephemeris_time = FALSE;
237
+ AS_BOOL do_not_round = FALSE;
238
+ AS_BOOL do_motab = FALSE;
239
+ AS_BOOL do_mojap = FALSE;
240
+ AS_BOOL date_gap = FALSE;
241
+ AS_BOOL show_jd = FALSE;
242
+ AS_BOOL print_cl = TRUE;
243
+ AS_BOOL output_extra_prec = FALSE;
244
+ AS_BOOL get_data_of_day = FALSE;
245
+ AS_BOOL transits_to_stderr = FALSE;
246
+ double phase_mod = 90;
247
+ char **znam = zod_nam;
248
+ char *gap = " ";
249
+ char sdatefrom[AS_MAXCH], sdateto[AS_MAXCH], syear0[80];
250
+ char sdate[AS_MAXCH];
251
+ AS_BOOL gregflag = TRUE;
252
+ int ipl;
253
+ double tzone = 0;
254
+ int whicheph = SEFLG_JPLEPH;
255
+ char cmdline[4 * AS_MAXCH];
256
+ char *stit = "Planetary Phenomena";
257
+
258
+ #if MSDOS
259
+ # define EPHEPATH "C:\\C600\\SOURCE\\SWEPH\\"
260
+ #else
261
+ # define EPHEPATH "/home/ephe"
262
+ #endif
263
+
264
+ static char *dms(double x, int iflag);
265
+ static int find_zero(double y00, double y11, double y2, double dx,
266
+ double *dxret, double *dxret2);
267
+ static int find_maximum(double y00, double y11, double y2, double dx,
268
+ double *dxret, double *yret);
269
+ static void print_item(char *s, double t, double x, double elo, double mag);
270
+ static int print_motab();
271
+
272
+ // from old swevents.c
273
+ static char *hms(double x, int32 iflag);
274
+ static int32 get_next_voc(double tet0, int32 iflag, int32 vocmethod, VOC *pvoc, char *serr);
275
+ static int32 calc_all_crossings(
276
+ int32 iflag, /* swiss ephemeris flags */
277
+ int32 itype, /* type of calculation:
278
+ * 0 = mundane aspects,
279
+ * 1 = transits,
280
+ * 2 = ingresses */
281
+ double tjd0, /* start time */
282
+ double tjde, /* end time */
283
+ double tstep, /* time step width */
284
+ char *splan, /* moving planets' string */
285
+ char *sasp, /* aspects string */
286
+ int32 npos, /* with ityp=1, number of transit positions */
287
+ double *dpos, /* transit/ingress positions */
288
+ struct event *pev, /* struct for output */
289
+ char *serr /* error string */
290
+ );
291
+ static int32 calc_all_voc(int32 iflag, double te, double tend, char *serr);
292
+ static int32 extract_data_of_day(int32 do_flag, double te, double dtol, char *splan, char *sasp, EVENT *pev, char *serr);
293
+ static int letter_to_ipl(int letter);
294
+
295
+
296
+
297
+
298
+ #define DO_CONJ 1
299
+ #define DO_RISE 2
300
+ #define DO_ELONG 4
301
+ #define DO_RETRO 8
302
+ #define DO_BRILL 16
303
+ #define DO_APS 32
304
+ #define DO_NODE 64
305
+ #define DO_LAT 128
306
+ #define DO_INGR 256
307
+ #define DO_LPHASE 512
308
+ #define DO_INGR45 1024 // add ingresses over 45,135,215,305° (mid of fixed signs)
309
+ #define DO_ASPECTS 2048
310
+ #define DO_VOC 4096
311
+
312
+ #define DO_ALL (DO_CONJ|DO_RISE|DO_ELONG|DO_RETRO|DO_BRILL|DO_APS|DO_NODE|DO_LAT|DO_INGR)
313
+
314
+ AS_BOOL sign_change(double x0, double x1)
315
+ {
316
+ if (x0 < 0 && x1 >= 0) return TRUE;
317
+ if (x0 >= 0 && x1 < 0) return TRUE;
318
+ return FALSE;
319
+ }
320
+
321
+
322
+ int main(int argc, char *argv[])
323
+ {
324
+ AS_BOOL is_opposition;
325
+ char serr[256];
326
+ char spnam[256];
327
+ char sout[AS_MAXCH], s[AS_MAXCH], saves[AS_MAXCH];
328
+ char *sp, *spsave;
329
+ char *spno;
330
+ int i, j, k, n, izod;
331
+ int jmon, jday, jyear;
332
+ double elong_vis, magme[3];
333
+ double jut = 0.0;
334
+ int iplfrom = SE_VENUS;
335
+ int nstep = 0, istep;
336
+ double dx;
337
+ double x[6], xs[6], x0[6], x1[6], x2[6];
338
+ double xp[6], xp0[6], xp1[6] = {0}, xp2[6], xs0[6], xs1[6] = {0}, xs2[6];
339
+ double xel0[6], xel1[6] = {0}, xel2[6], xang0[6], xang1[6] = {0}, xang2[6], xma0[6], xma1[6] = {0}, xma2[6];
340
+ double xh0[6], xh1[6] = {0}, xh2[6];
341
+ double attr[20];
342
+ double xel, xma, sunrad;
343
+ double dt, dt1, dt2, elong, rphel;
344
+ char ephepath[AS_MAXCH] = EPHEPATH;
345
+ char fname[80] = "de431.eph";
346
+ char *begindate = NULL;
347
+ int iflag = SEFLG_RADIANS | SEFLG_SPEED; /* external flag: helio, geo... */
348
+ int nzer, iflgret;
349
+ /*double tjd = 2436723.589269907;*/
350
+ double tjd = 2436723.588888889;
351
+ double t, te, tend, t2, t3, tstep;
352
+ double delt;
353
+ struct tm *tim;
354
+ time_t tloc;
355
+ EVENT *pev0;
356
+ tstep = 1;
357
+ nstep = 300;
358
+ pmodel = PMODEL_SCREEN;
359
+ strcpy(ephepath, EPHEPATH);
360
+ time(&tloc);
361
+ tim = localtime (&tloc);
362
+ sprintf(sdate, "%d/%02d/%02d", 1900+tim->tm_year, tim->tm_mon, tim->tm_mday);
363
+ for (i = 1; i < argc; i++) {
364
+ if (strcmp(argv[i], "-doall") == 0) {
365
+ do_flag = DO_ALL;
366
+ } else if (strcmp(argv[i], "-noingr") == 0) {
367
+ do_flag &= ~DO_INGR;
368
+ } else if (strcmp(argv[i], "-doconj") == 0) {
369
+ do_flag |= DO_CONJ;
370
+ } else if (strcmp(argv[i], "-dobrill") == 0) {
371
+ do_flag |= DO_BRILL;
372
+ } else if (strcmp(argv[i], "-dorise") == 0) {
373
+ do_flag |= DO_RISE;
374
+ } else if (strcmp(argv[i], "-doelong") == 0) {
375
+ do_flag |= DO_ELONG;
376
+ } else if (strcmp(argv[i], "-doretro") == 0) {
377
+ do_flag |= DO_RETRO;
378
+ } else if (strcmp(argv[i], "-doaps") == 0) {
379
+ do_flag |= DO_APS;
380
+ } else if (strcmp(argv[i], "-dolphase") == 0) {
381
+ do_flag |= DO_LPHASE;
382
+ } else if (strcmp(argv[i], "-donode") == 0) {
383
+ do_flag |= DO_NODE;
384
+ } else if (strcmp(argv[i], "-doingr") == 0) {
385
+ do_flag |= DO_INGR;
386
+ } else if (strcmp(argv[i], "-doing45") == 0) {
387
+ do_flag |= DO_INGR45;
388
+ } else if (strcmp(argv[i], "-doasp") == 0) {
389
+ do_flag |= DO_ASPECTS;
390
+ } else if (strcmp(argv[i], "-dovoc") == 0) {
391
+ do_flag |= DO_VOC;
392
+ } else if (strcmp(argv[i], "-getday") == 0) {
393
+ get_data_of_day = TRUE;
394
+ } else if (strcmp(argv[i], "-et") == 0) {
395
+ ephemeris_time = TRUE;
396
+ } else if (strcmp(argv[i], "-jd") == 0) {
397
+ show_jd = TRUE;
398
+ } else if (strncmp(argv[i], "-cycol", 6) == 0) {
399
+ ncycol = atoi(argv[i] + 6);
400
+ } else if (strcmp(argv[i], "-ep") == 0) {
401
+ output_extra_prec = TRUE;
402
+ } else if (strncmp(argv[i], "-ejpl", 5) == 0) {
403
+ whicheph = SEFLG_JPLEPH;
404
+ if (*(argv[i]+5) != '\0')
405
+ strcpy(fname, argv[i]+5);
406
+ } else if (strcmp(argv[i], "-eswe") == 0) {
407
+ whicheph = SEFLG_SWIEPH;
408
+ } else if (strcmp(argv[i], "-emos") == 0) {
409
+ whicheph = SEFLG_MOSEPH;
410
+ } else if (strcmp(argv[i], "-zlong") == 0) {
411
+ znam = zod_nam_long;
412
+ } else if (strcmp(argv[i], "-znam3") == 0) {
413
+ znam = zod_nam3;
414
+ } else if (strcmp(argv[i], "-monnum") == 0) {
415
+ for (n = 1; n <= 12; n++) {
416
+ month_nam[n] = malloc(4);
417
+ sprintf(month_nam[n], "%3d", n);
418
+ }
419
+ } else if (strcmp(argv[i], "-?") == 0) {
420
+ printf(info);
421
+ #if PRINTMOD
422
+ } else if (strcmp(argv[i], "-mpdf") == 0) {
423
+ pmodel = PMODEL_PDF;
424
+ } else if (strcmp(argv[i], "-mps") == 0) {
425
+ pmodel = PMODEL_PS;
426
+ } else if (strcmp(argv[i], "-mscreen") == 0) {
427
+ pmodel = PMODEL_SCREEN;
428
+ #endif
429
+ } else if (strcmp(argv[i], "-j2000") == 0) {
430
+ iflag |= SEFLG_J2000;
431
+ } else if (strcmp(argv[i], "-icrs") == 0) {
432
+ iflag |= SEFLG_ICRS;
433
+ } else if (strcmp(argv[i], "-hel") == 0) {
434
+ iflag |= SEFLG_HELCTR;
435
+ } else if (strcmp(argv[i], "-bary") == 0) {
436
+ iflag |= SEFLG_BARYCTR;
437
+ } else if (strcmp(argv[i], "-true") == 0) {
438
+ iflag |= SEFLG_TRUEPOS;
439
+ } else if (strcmp(argv[i], "-noaberr") == 0) {
440
+ iflag |= SEFLG_NOABERR;
441
+ } else if (strcmp(argv[i], "-nodefl") == 0) {
442
+ iflag |= SEFLG_NOGDEFL;
443
+ } else if (strcmp(argv[i], "-nonut") == 0) {
444
+ iflag |= SEFLG_NONUT;
445
+ } else if (strcmp(argv[i], "-noprec") == 0) {
446
+ iflag |= SEFLG_J2000;
447
+ } else if (strcmp(argv[i], "-noround") == 0) {
448
+ do_not_round = TRUE;
449
+ } else if (strcmp(argv[i], "-dgap") == 0) {
450
+ date_gap = TRUE;
451
+ } else if (strcmp(argv[i], "-motab") == 0) {
452
+ do_motab = TRUE;
453
+ do_flag = DO_INGR;
454
+ stit = "Sign Ingresses";
455
+ } else if (strcmp(argv[i], "-mojap") == 0) {
456
+ do_mojap = TRUE;
457
+ do_flag = DO_LPHASE;
458
+ phase_mod = 90;
459
+ xpos -= xdate;
460
+ xdate = 0;
461
+ max_cols = 4;
462
+ memcpy(xcol, xcol4, sizeof(xcol));
463
+ stit = "Phases";
464
+ if (atoi(argv[i+1]) > 0) {
465
+ phase_mod = atoi(argv[i+1]);
466
+ i++;
467
+ }
468
+ } else if (strcmp(argv[i], "-gmtoff") == 0) {
469
+ i++;
470
+ gmtoff = atof(argv[i]);
471
+ } else if (strncmp(argv[i], "-p", 2) == 0) {
472
+ spno = argv[i]+2;
473
+ /* single factor */
474
+ if (*spno >= '0' && *spno <= '9' && atol(spno) < SE_NPLANETS) {
475
+ iplfrom = atol(spno);
476
+ /* ecliptic, nutation */
477
+ } else if ((ipl = atol(spno)) == -1) {
478
+ iplfrom = ipl;
479
+ } else if (*spno == 'h') {
480
+ iplfrom = atol(spno + 1) + SE_FICT_OFFSET;
481
+ if (iplfrom > SE_WALDEMATH) {
482
+ printf("illegal planet number %s\n", argv[i]);
483
+ exit(1);
484
+ }
485
+ } else {
486
+ printf("illegal planet number %s\n", argv[i]);
487
+ exit(1);
488
+ }
489
+ } else if (strncmp(argv[i], "-n", 2) == 0) {
490
+ nstep = atoi(argv[i]+2);
491
+ } else if (strncmp(argv[i], "-s", 2) == 0) {
492
+ tstep = atof(argv[i]+2);
493
+ } else if (strncmp(argv[i], "-b", 2) == 0) {
494
+ begindate = argv[i] + 2;
495
+ } else if (strcmp(argv[i], "-cl") == 0) {
496
+ print_cl = FALSE;
497
+ } else if (strncmp(argv[i], "-g", 2) == 0) {
498
+ gap = argv[i] + 2;
499
+ if (*gap == '\0') gap = "\t";
500
+ } else if (strncmp(argv[i], "-tzone", 6) == 0) {
501
+ tzone = atof(argv[i]+6);
502
+ } else if (strncmp(argv[i], "-transitstderr", 6) == 0) {
503
+ transits_to_stderr = TRUE;
504
+ } else {
505
+ printf("illegal option %s\n", argv[i]);
506
+ exit(1);
507
+ }
508
+ }
509
+ strcpy(cmdline, "Command: ");
510
+ for (i = 0; i < argc; i++) {
511
+ if (strlen(cmdline) + strlen(argv[i]) < sizeof(cmdline) - 2)
512
+ sprintf(cmdline + strlen(cmdline), "%s ", argv[i]);
513
+ }
514
+ #if PRINTMOD
515
+ if (pmodel != PMODEL_SCREEN) {
516
+ printmod_set_printer(pmodel, 0);
517
+ } else {
518
+ printf("%s\n\n", cmdline);
519
+ }
520
+ #else
521
+ printf("%s\n\n", cmdline);
522
+ #endif
523
+ swe_set_ephe_path(ephepath);
524
+ swe_set_jpl_file(fname);
525
+ iflag |= whicheph;
526
+ if (begindate == NULL) {
527
+ printf ("datum ?");
528
+ sp = fgets(s, AS_MAXCH, stdin);
529
+ } else {
530
+ sp = begindate;
531
+ begindate = "."; /* to exit afterwards */
532
+ }
533
+ spsave = sp;
534
+ if (*sp == '.') {
535
+ exit(1);
536
+ } else if (*sp == '\0') {
537
+ strcpy (s, saves);
538
+ } else {
539
+ strcpy (saves, s);
540
+ }
541
+ if (*sp == 'j') { /* it's a day number */
542
+ sscanf(sp+1,"%lf", &tjd);
543
+ if (tjd < 2299160.5)
544
+ gregflag = FALSE;
545
+ else
546
+ gregflag = TRUE;
547
+ if (strstr(sp, "jul") != NULL)
548
+ gregflag = FALSE;
549
+ else if (strstr(sp, "greg") != NULL)
550
+ gregflag = TRUE;
551
+ swe_revjul(tjd, gregflag, &jyear, &jmon, &jday, &jut);
552
+ } else if (*sp == '+') {
553
+ n = atoi(sp);
554
+ if (n == 0) n = 1;
555
+ tjd += n;
556
+ swe_revjul(tjd, gregflag, &jyear, &jmon, &jday, &jut);
557
+ } else if (*sp == '-') {
558
+ n = atoi(sp);
559
+ if (n == 0) n = -1;
560
+ tjd += n;
561
+ swe_revjul(tjd, gregflag, &jyear, &jmon, &jday, &jut);
562
+ } else {
563
+ if (sscanf (sp, "%d%*c%d%*c%d", &jday,&jmon,&jyear) < 1) exit(1);
564
+ if (jyear * 10000 + jmon * 100 + jday < 15821015)
565
+ gregflag = FALSE;
566
+ else
567
+ gregflag = TRUE;
568
+ if (strstr(sp, "jul") != NULL)
569
+ gregflag = FALSE;
570
+ else if (strstr(sp, "greg") != NULL)
571
+ gregflag = TRUE;
572
+ tjd = swe_julday(jyear,jmon,jday,jut,gregflag); /* PLACALC :
573
+ get jd for the
574
+ date you want */
575
+ }
576
+ sprintf(syear0, "%02d", jyear);
577
+ swe_revjul(tjd + tstep * nstep, gregflag, &jyear, &jmon, &jday, &jut);
578
+ sprintf(sdateto, "%02d", jyear);
579
+ for (t = tjd, istep = 0; istep <= nstep; t += tstep, istep++) {
580
+ if (t < 2299160.5)
581
+ gregflag = FALSE;
582
+ else
583
+ gregflag = TRUE;
584
+ if (strstr(spsave, "jul") != NULL)
585
+ gregflag = FALSE;
586
+ else if (strstr(spsave, "greg") != NULL)
587
+ gregflag = TRUE;
588
+ swe_revjul(t, gregflag, &jyear, &jmon, &jday, &jut);
589
+ if (!ephemeris_time) {
590
+ //delt = swe_deltat(t);
591
+ delt = swe_deltat_ex(t, whicheph, serr);
592
+ te = t + delt;
593
+ } else {
594
+ te = t;
595
+ }
596
+ ipl = iplfrom;
597
+ switch(ipl) {
598
+ case SE_SUN:
599
+ planet_name = "Sun";
600
+ break;
601
+ case SE_VENUS:
602
+ planet_name = "Venus";
603
+ break;
604
+ case SE_MERCURY:
605
+ planet_name = "Mercury";
606
+ break;
607
+ case SE_MARS:
608
+ planet_name = "Mars";
609
+ break;
610
+ case SE_JUPITER:
611
+ planet_name = "Jupiter";
612
+ break;
613
+ case SE_SATURN:
614
+ planet_name = "Saturn";
615
+ break;
616
+ case SE_URANUS:
617
+ planet_name = "Uranus";
618
+ break;
619
+ case SE_NEPTUNE:
620
+ planet_name = "Neptune";
621
+ break;
622
+ case SE_PLUTO:
623
+ planet_name = "Pluto";
624
+ break;
625
+ default:
626
+ swe_get_planet_name(ipl, spnam);
627
+ planet_name = spnam;
628
+ break;
629
+ }
630
+ // handle the three old swevents.c modes and exit
631
+ if (get_data_of_day) {
632
+ if ((pev0 = (EVENT *) calloc((size_t) NEVENTMAX, sizeof(EVENT))) == NULL) {
633
+ fprintf(stderr, "could not allocate structure for event data\n");
634
+ return ERR;
635
+ }
636
+ if (extract_data_of_day(do_flag, te, 1.6, SPLAN_ASPECTS, SASP_ASPECTS, pev0, serr) == ERR) {
637
+ fprintf(stderr, "%s\n", serr);
638
+ return ERR;
639
+ }
640
+ return OK;
641
+ }
642
+ /* moon void of course */
643
+ if (do_flag & DO_VOC) {
644
+ tend = te + nstep;
645
+ if (calc_all_voc(iflag, te, tend, serr) == ERR) {
646
+ fprintf(stderr, "%s\n", serr);
647
+ return ERR;
648
+ }
649
+ return OK;
650
+ }
651
+ /* mundane aspects */
652
+ if (do_flag & DO_ASPECTS) {
653
+ tend = te + nstep;
654
+ if ((pev0 = (EVENT *) calloc((size_t) NEVENTMAX, sizeof(EVENT))) == NULL) {
655
+ fprintf(stderr, "could not allocate structure for event data\n");
656
+ return ERR;
657
+ }
658
+ if (calc_all_crossings(iflag, CTYP_MASPECTS, te, tend, tstep, SPLAN_ASPECTS, SASP_ASPECTS, 0, NULL, pev0, serr) == ERR) {
659
+ fprintf(stderr, "%s\n", serr);
660
+ return ERR;
661
+ }
662
+ return OK;
663
+ }
664
+ /* we have always
665
+ * - three positions and speeds for venus
666
+ * - three positions and speeds for sun
667
+ * - three elongations of venus (with elongation speed)
668
+ * - three magnitudes
669
+ */
670
+ memcpy(xp0, xp1, 6 * sizeof(double)); /* planet */
671
+ memcpy(xp1, xp2, 6 * sizeof(double));
672
+ memcpy(xh0, xh1, 6 * sizeof(double)); /* heliocentric */
673
+ memcpy(xh1, xh2, 6 * sizeof(double)); /* heliocentric */
674
+ memcpy(xs0, xs1, 6 * sizeof(double)); /* sun */
675
+ memcpy(xs1, xs2, 6 * sizeof(double));
676
+ memcpy(xel0, xel1, 6 * sizeof(double)); /* elongation in longitude */
677
+ memcpy(xel1, xel2, 6 * sizeof(double));
678
+ memcpy(xang0, xang1, 6 * sizeof(double));/* ang. dist. from sun */
679
+ memcpy(xang1, xang2, 6 * sizeof(double));
680
+ memcpy(xma0, xma1, 6 * sizeof(double)); /* magnitude */
681
+ memcpy(xma1, xma2, 6 * sizeof(double));
682
+ iflgret = swe_calc(te, (int) ipl, iflag, xp2, serr);
683
+ if (iflgret < 0) {
684
+ fprintf(stderr, "return code %d, mesg: %s\n", iflgret, serr);
685
+ }
686
+ iflgret = swe_calc(te, SE_SUN, iflag, xs2, serr);
687
+ if (iflgret < 0) {
688
+ fprintf(stderr, "return code %d, mesg: %s\n", iflgret, serr);
689
+ }
690
+ iflgret = swe_calc(te, (int) ipl, iflag/*|SEFLG_HELCTR*/, xh2, serr);
691
+ if (iflgret < 0) {
692
+ fprintf(stderr, "return code %d, mesg: %s\n", iflgret, serr);
693
+ }
694
+ /* true heliocentric distance */
695
+ /* elongation of planet measured on ecliptic */
696
+ for (i = 0; i <= 5; i++)
697
+ xel2[i] = xp2[i] - xs2[i];
698
+ xel2[0] = swe_radnorm(xel2[0]);
699
+ if (xel2[0] > M_PI)
700
+ xel2[0] -= 2 * M_PI;
701
+ /* other values */
702
+ // cartesian coordinates of planet and sun
703
+ swi_polcart(xp2, x1);
704
+ swi_polcart(xs2, x2);
705
+ for (i = 0; i <= 2; i++)
706
+ x[i] = -x2[i] + x1[i];
707
+ /* 'apparent' hel. distance of planet*/
708
+ rphel = sqrt(square_sum(x));
709
+ // elongation of planet = angular distance of planet from sun
710
+ elong = acos((xs2[2] * xs2[2] + xp2[2] * xp2[2] - rphel * rphel) / 2.0 / xs2[2] / xp2[2]);
711
+ // this is equivalent to:
712
+ // elong = acos(swi_dot_prod_unit(x1, x2));
713
+ xang2[0] = elong;
714
+ if (rphel != 0 && ipl <= 4) {
715
+ if ((i = swe_pheno(te, ipl, iflag, attr, serr)) < 0) {
716
+ fprintf(stderr, "return code %d, mesg: %s\n", i, serr);
717
+ xma2[0] = 1;
718
+ } else {
719
+ xma2[0] = attr[4];
720
+ }
721
+ //fprintf(stderr, "mag1=%.7f\n", xma2[0]);
722
+ } else {
723
+ xma2[0] = 1;
724
+ }
725
+ if (istep >= 2) { /* now all of the arrays xp* and xs* are filled */
726
+ /* conjunctions with sun, in longitude */
727
+ if (do_flag & DO_LPHASE)
728
+ goto l_phase;
729
+ if (!(do_flag & DO_CONJ))
730
+ goto l_noconj;
731
+ if (sign_change(xel1[0] ,xel2[0])) {
732
+ double el0 = xel0[0], el1 = xel1[0], el2 = xel2[0];
733
+ if (el0 > M_PI / 2) el0 -= M_PI;
734
+ if (el0 < -M_PI / 2) el0 += M_PI;
735
+ if (el1 > M_PI / 2) el1 -= M_PI;
736
+ if (el1 < -M_PI / 2) el1 += M_PI;
737
+ if (el2 > M_PI / 2) el2 -= M_PI;
738
+ if (el2 < -M_PI / 2) el2 += M_PI;
739
+ nzer = find_zero(el0, el1, el2, tstep, &dt, &dt2);
740
+ if (nzer > 0) {
741
+ t2 = te + dt;
742
+ iflgret = swe_calc(t2, (int) ipl, iflag, x, serr);
743
+ iflgret = swe_calc(t2, SE_SUN, iflag, xs, serr);
744
+ is_opposition = 0;
745
+ if (ipl != SE_VENUS && ipl != SE_MERCURY) {
746
+ if (fabs(xel1[0]) > M_PI / 2) {
747
+ is_opposition = 1;
748
+ print_item("opposition", t2, x[0] * RADTODEG, x[1] * RADTODEG, HUGE);
749
+ } else
750
+ print_item("conjunction", t2, x[0] * RADTODEG, x[1] * RADTODEG, HUGE);
751
+ } else {
752
+ if (x[3] > 0)
753
+ print_item("superior conj", t2, x[0] * RADTODEG, x[1] * RADTODEG, HUGE);
754
+ else
755
+ print_item("inferior conj", t2, x[0] * RADTODEG, x[1] * RADTODEG, HUGE);
756
+ }
757
+ /* planet is behind solar disk or is transiting it */
758
+ for (j = 0, dt1 = tstep; j <= 5; j++, dt1 /= 3) {
759
+ for (k = 0; k <= 2; k++) {
760
+ switch(k) {
761
+ case 0:
762
+ t3 = t2 - dt1;
763
+ break;
764
+ case 1:
765
+ t3 = t2;
766
+ break;
767
+ case 2:
768
+ t3 = t2 + dt1;
769
+ break;
770
+ }
771
+ iflgret = swe_calc(t3, (int) ipl, iflag, xp, serr);
772
+ iflgret = swe_calc(t3, SE_SUN, iflag, xs, serr);
773
+ swi_polcart(xp, x1);
774
+ swi_polcart(xs, x2);
775
+ for (i = 0; i <= 2; i++)
776
+ x[i] = -x2[i] + x1[i];
777
+ rphel = sqrt(square_sum(x));
778
+ x0[k] = acos((xs[2] * xs[2] + xp[2] * xp[2] - rphel * rphel) /
779
+ 2.0 / xs[2] / xp[2]);
780
+ }
781
+ find_maximum(x0[0], x0[1], x0[2], dt1, &dt, &xel);
782
+ t2 = t2 + dt1 + dt;
783
+ }
784
+ iflgret = swe_calc(t2, (int) ipl, iflag, x, serr);
785
+ iflgret = swe_calc(t2, SE_SUN, iflag, xs, serr);
786
+ /* minimum elongation of planet */
787
+ if (is_opposition) {
788
+ /*print_item(" maximum elong", t2, x[0] * RADTODEG, xel*RADTODEG, HUGE)*/;
789
+ } else {
790
+ print_item(" minimum elong", t2, x[0] * RADTODEG, xel*RADTODEG, HUGE);
791
+ }
792
+ switch(ipl) {
793
+ case SE_VENUS:
794
+ sunrad = SUN_RADIUS / xs[2] + VENUS_RADIUS / x[2];
795
+ break;
796
+ case SE_MERCURY:
797
+ sunrad = SUN_RADIUS / xs[2] + MERCURY_RADIUS / x[2];
798
+ break;
799
+ case SE_MARS:
800
+ default:
801
+ sunrad = SUN_RADIUS / xs[2] + MARS_RADIUS / x[2];
802
+ break;
803
+ }
804
+ if (sunrad > fabs(xel)) {
805
+ if (x[3] > 0 || ipl > SE_VENUS) {
806
+ strcpy(sout, " behind sun begin");
807
+ } else {
808
+ strcpy(sout, " transit begin");
809
+ print_item(" transit middle", t2, x[0] * RADTODEG, xel*RADTODEG, HUGE);
810
+ }
811
+ dt = sqrt(sunrad * sunrad - xel * xel);
812
+ /*dt = acos(cos(sunrad) / cos(xel)); is not better */
813
+ dt /= sqrt((x[3]-xs[3]) * (x[3]-xs[3]) + (x[4]-xs[4]) * (x[4]-xs[4]));
814
+ iflgret = swe_calc(t2-dt, (int) ipl, iflag, x, serr);
815
+ print_item(sout, t2 - dt, x[0] * RADTODEG, HUGE, HUGE);
816
+ if (x[3] > 0 || ipl > SE_VENUS)
817
+ strcpy(sout, " behind sun end");
818
+ else
819
+ strcpy(sout, " transit end");
820
+ iflgret = swe_calc(t2+dt, (int) ipl, iflag, x, serr);
821
+ print_item(sout, t2 + dt, x[0] * RADTODEG, HUGE, HUGE);
822
+ }
823
+ }
824
+ }
825
+ l_noconj:;
826
+ if (!(do_flag & DO_BRILL))
827
+ goto l_nobrill;
828
+ /* greatest brillancy */
829
+ if (ipl <= SE_MARS
830
+ && xma0[0] > xma1[0]
831
+ && xma2[0] > xma1[0]
832
+ && xang1[0] > 10*DEGTORAD) {
833
+ find_maximum(xma0[0], xma1[0], xma2[0], tstep, &dt, &xma);
834
+ t2 = te + dt;
835
+ for (j = 0, dt1 = tstep; j <= 5; j++, dt1 /= 3) {
836
+ for (k = 0; k <= 2; k++) {
837
+ switch(k) {
838
+ case 0:
839
+ t3 = t2 - dt1;
840
+ break;
841
+ case 1:
842
+ t3 = t2;
843
+ break;
844
+ case 2:
845
+ t3 = t2 + dt1;
846
+ break;
847
+ }
848
+ //iflgret = swe_calc(t3, (int) ipl, iflag, xp, serr);
849
+ //iflgret = swe_calc(t3, SE_SUN, iflag, xs, serr);
850
+ //swi_polcart(xp, x1);
851
+ //swi_polcart(xs, x2);
852
+ //for (i = 0; i <= 2; i++)
853
+ // x[i] = -x2[i] + x1[i];
854
+ //rphel = sqrt(square_sum(x));
855
+ if ((i = swe_pheno(t3, ipl, iflag, attr, serr)) < 0) {
856
+ fprintf(stderr, "return code %d, mesg: %s\n", i, serr);
857
+ x0[k] = 1;
858
+ exit(0);
859
+ } else {
860
+ x0[k] = attr[4];
861
+ }
862
+ }
863
+ find_maximum(x0[0], x0[1], x0[2], dt1, &dt, &xma);
864
+ t2 = t2 + dt1 + dt;
865
+ }
866
+ iflgret = swe_calc(t2, (int) ipl, iflag, x, serr);
867
+ print_item("greatest brilliancy", t2, x[0] * RADTODEG, HUGE, xma);
868
+ }
869
+ l_nobrill:;
870
+ if (!(do_flag& DO_RISE) && !(do_flag & DO_ELONG))
871
+ goto l_noelong;
872
+ /* rise and set of morning and evening star
873
+ * This calculation is very simplistic. Exact dates are not possible
874
+ * because they depend on the geographic position of the observer.
875
+ */
876
+ *sout = '\0';
877
+ magme[0] = magme[1] = magme[2] = 0;
878
+ switch(ipl) {
879
+ case SE_MERCURY:
880
+ magme[0] = xma0[0];
881
+ magme[1] = xma1[0];
882
+ magme[2] = xma2[0];
883
+ case SE_VENUS:
884
+ case SE_JUPITER:
885
+ elong_vis = 10;
886
+ break;
887
+ case SE_MOON:
888
+ case SE_MARS:
889
+ case SE_SATURN:
890
+ elong_vis = 15;
891
+ break;
892
+ default:
893
+ elong_vis = 15;
894
+ break;
895
+ }
896
+ if (xang1[0] * RADTODEG > elong_vis + magme[1]
897
+ && xang2[0] * RADTODEG < elong_vis + magme[2]) {
898
+ if (xel1[0] > 0)
899
+ strcpy(sout, "evening set");
900
+ else
901
+ strcpy(sout, "morning set");
902
+ }
903
+ if (xang1[0] * RADTODEG < elong_vis + magme[1]
904
+ && xang2[0] * RADTODEG > elong_vis + magme[2]) {
905
+ if (xel1[0] > 0)
906
+ strcpy(sout, "evening rise");
907
+ else
908
+ strcpy(sout, "morning rise");
909
+ }
910
+ if (*sout != '\0') {
911
+ x[0] = xang0[0] - elong_vis * DEGTORAD;
912
+ x[1] = xang1[0] - elong_vis * DEGTORAD;
913
+ x[2] = xang2[0] - elong_vis * DEGTORAD;
914
+ // with Mercury, brightness is taken into account
915
+ // (this method from Expl. Suppl. of AA 1984, however
916
+ // magnitudes used are from Swisseph >= 2.07)
917
+ if (ipl == SE_MERCURY) {
918
+ x[0] -= magme[0] * DEGTORAD;
919
+ x[1] -= magme[1] * DEGTORAD;
920
+ x[2] -= magme[2] * DEGTORAD;
921
+ }
922
+ }
923
+ if (!(do_flag & DO_RISE))
924
+ goto l_norise;
925
+ if (*sout != '\0') {
926
+ double cos_elong, deg_elong, derr;
927
+ if ((nzer = find_zero(x[0], x[1], x[2], tstep, &dt, &dt2)) > 0) {
928
+ t2 = te + dt;
929
+ /* some test code to verify actual elongation at found date */
930
+ iflgret = swe_calc(t2, (int) ipl, iflag, x2, serr);
931
+ iflgret = swe_calc(t2, SE_SUN, iflag, x1, serr);
932
+ cos_elong = cos(x2[0]-x1[0]) * cos(x2[1]-x1[1]);
933
+ deg_elong = acos(cos_elong) * RADTODEG;
934
+ derr = fabs(deg_elong) - elong_vis;
935
+ if (ipl == SE_MERCURY) {
936
+ //double xx1[6], xx2[6], rh;
937
+ double ma;
938
+ //swi_polcart(x2, xx2);
939
+ //swi_polcart(x1, xx1);
940
+ //for (i = 0; i <= 2; i++)
941
+ // x[i] = -xx1[i] + xx2[i];
942
+ /* 'apparent' hel. distance of planet*/
943
+ //rh = sqrt(square_sum(x));
944
+ if ((i = swe_pheno(t2, ipl, iflag, attr, serr)) < 0) {
945
+ fprintf(stderr, "return code %d, mesg: %s\n", i, serr);
946
+ exit(0);
947
+ }
948
+ ma = attr[4];
949
+ derr -= ma;
950
+ }
951
+ if (fabs(derr) > 0.01)
952
+ fprintf(stderr, "warning elongation planet %d test deviation %.3f arcsec at t=%f\n", ipl, derr * 3600, t2);
953
+ /* end test code */
954
+ print_item(sout, t2, x2[0] * RADTODEG, HUGE, HUGE);
955
+ }
956
+ }
957
+ l_norise:;
958
+ if (!(do_flag & DO_ELONG) || ipl >= SE_MARS)
959
+ goto l_noelong;
960
+ /* maximum elongation */
961
+ if (fabs(xang0[0]) < fabs(xang1[0]) && fabs(xang2[0]) < fabs(xang1[0])) {
962
+ find_maximum(xang0[0], xang1[0], xang2[0], tstep, &dt, &xel);
963
+ t2 = te + dt;
964
+ for (j = 0, dt1 = tstep; j <= 5; j++, dt1 /= 3) {
965
+ for (k = 0; k <= 2; k++) {
966
+ switch(k) {
967
+ case 0:
968
+ t3 = t2 - dt1;
969
+ break;
970
+ case 1:
971
+ t3 = t2;
972
+ break;
973
+ case 2:
974
+ t3 = t2 + dt1;
975
+ break;
976
+ }
977
+ iflgret = swe_calc(t3, (int) ipl, iflag, xp, serr);
978
+ iflgret = swe_calc(t3, SE_SUN, iflag, xs, serr);
979
+ swi_polcart(xp, x1);
980
+ swi_polcart(xs, x2);
981
+ for (i = 0; i <= 2; i++)
982
+ x[i] = -x2[i] + x1[i];
983
+ rphel = sqrt(square_sum(x));
984
+ x0[k] = acos((xs[2] * xs[2] + xp[2] * xp[2] - rphel * rphel) /
985
+ 2.0 / xs[2] / xp[2]);
986
+ }
987
+ find_maximum(x0[0], x0[1], x0[2], dt1, &dt, &xel);
988
+ t2 = t2 + dt1 + dt;
989
+ }
990
+ iflgret = swe_calc(t2, (int) ipl, iflag, x, serr);
991
+ if (ipl > SE_VENUS)
992
+ strcpy(sout, "maximum elong.");
993
+ else if (xel1[0] > 0)
994
+ strcpy(sout, "evening max el");
995
+ else
996
+ strcpy(sout, "morning max el");
997
+ print_item(sout, t2, x[0] * RADTODEG, xel*RADTODEG, HUGE);
998
+ }
999
+ l_noelong:;
1000
+ if (!(do_flag & DO_RETRO))
1001
+ goto l_noretro;
1002
+ /* retrograde or direct, maximum position */
1003
+ if ((xp1[3] < 0 && xp2[3] >= 0) || (xp1[3] > 0 && xp2[3] <= 0)) {
1004
+ t2 = te - xp2[3] / ((xp2[3] - xp1[3]) / tstep);
1005
+ for (j = 0, dt1 = tstep; j <= 5; j++, dt1 /= 3) {
1006
+ for (k = 0; k <= 1; k++) {
1007
+ switch(k) {
1008
+ case 0:
1009
+ t3 = t2;
1010
+ break;
1011
+ case 1:
1012
+ t3 = t2 + dt1;
1013
+ break;
1014
+ }
1015
+ iflgret = swe_calc(t3, (int) ipl, iflag, xp, serr);
1016
+ x0[k] = xp[3];
1017
+ }
1018
+ t2 = t3 - x0[1] / ((x0[1] - x0[0]) / dt1);
1019
+ //fprintf(stderr, "tt=%.8f\n", t2);
1020
+ }
1021
+ iflgret = swe_calc(t2, (int) ipl, iflag, x, serr);
1022
+ if (xp2[3] < 0)
1023
+ strcpy(sout, "retrograde");
1024
+ else
1025
+ strcpy(sout, "direct");
1026
+ print_item(sout, t2, x[0] * RADTODEG, HUGE, HUGE);
1027
+ }
1028
+ l_noretro:;
1029
+ if (!(do_flag & DO_APS))
1030
+ goto l_noaps;
1031
+ /* apsides */
1032
+ if ((xh2[2] < xh1[2] && xh0[2] < xh1[2]) || (xh2[2] > xh1[2] && xh0[2] > xh1[2])) {
1033
+ x0[0] = xh0[2];
1034
+ x0[1] = xh1[2];
1035
+ x0[2] = xh2[2];
1036
+ find_maximum(x0[0], x0[1], x0[2], tstep, &dt, &xel);
1037
+ t2 = te + dt;
1038
+ for (j = 0, dt1 = tstep; j <= 4; j++, dt1 /= 3) {
1039
+ for (k = 0; k <= 2; k++) {
1040
+ switch(k) {
1041
+ case 0:
1042
+ t3 = t2 - dt1;
1043
+ break;
1044
+ case 1:
1045
+ t3 = t2;
1046
+ break;
1047
+ case 2:
1048
+ t3 = t2 + dt1;
1049
+ break;
1050
+ }
1051
+ iflgret = swe_calc(t3, (int) ipl, iflag/*|SEFLG_HELCTR*/, xp, serr);
1052
+ x0[k] = xp[2];
1053
+ }
1054
+ find_maximum(x0[0], x0[1], x0[2], dt1, &dt, &xel);
1055
+ t2 = t2 + dt1 + dt;
1056
+ }
1057
+ iflgret = swe_calc(t2, (int) ipl, iflag/*|SEFLG_HELCTR*/, x, serr);
1058
+ if (xh2[2] < xh1[2]) {
1059
+ if (iflag & SEFLG_HELCTR)
1060
+ strcpy(sout, "aphelion");
1061
+ else
1062
+ strcpy(sout, "max. Earth dist.");
1063
+ } else {
1064
+ if (iflag & SEFLG_HELCTR)
1065
+ strcpy(sout, "perihelion");
1066
+ else
1067
+ strcpy(sout, "min. Earth dist.");
1068
+ }
1069
+ print_item(sout, t2, x[0] * RADTODEG, HUGE, x[2]);
1070
+ }
1071
+ l_noaps:;
1072
+ if (!(do_flag & DO_NODE))
1073
+ goto l_nonode;
1074
+ if (sign_change(xh1[1] ,xh2[1])) { // latitude sign change?
1075
+ if ((nzer = find_zero(xh0[1], xh1[1], xh2[1], tstep, &dt, &dt2)) > 0) {
1076
+ t2 = te + dt;
1077
+ iflgret = swe_calc(t2, (int) ipl, iflag/*|SEFLG_HELCTR*/, x, serr);
1078
+ if (xh2[1] >= 0)
1079
+ strcpy(sout, "asc. node");
1080
+ else
1081
+ strcpy(sout, "desc. node");
1082
+ print_item(sout, t2, x[0] * RADTODEG, HUGE, HUGE);
1083
+ }
1084
+ }
1085
+ l_nonode:;
1086
+ /* sign ingresses */
1087
+ if (do_flag & DO_INGR) {
1088
+ double x0, x1, x2, xcross, d12, d01, x[6], tx, dx;
1089
+ int j;
1090
+ x2 = xp2[0] * RADTODEG; // at t
1091
+ x1 = xp1[0] * RADTODEG; // at t - tstep
1092
+ x0 = xp0[0] * RADTODEG; // at t - 2 * tstep
1093
+ // x2 is in [0..360[
1094
+ // normalize x1 and x0 so that there are no jumps
1095
+ d12 = swe_difdeg2n(x2, x1);
1096
+ x1 = x2 - d12;
1097
+ d01 = swe_difdeg2n(x1, x0);
1098
+ x0 = x1 - d01;
1099
+ for (i = 0; i <= 12; i++) { // we consider 13 sign cusps, 0..360
1100
+ // because x2 can be 359, x1 = 361, x0 = 363
1101
+ xcross = i * 30.0;
1102
+ // is xcross between x1 and x2?
1103
+ // or x2 critically near xcross
1104
+ if (sign_change((x1 - xcross), (x2 - xcross))
1105
+ || (fabs(x0-x1) + fabs(x1-x2) > fabs(x2 - xcross))) {
1106
+ nzer = find_zero(x0 - xcross, x1 - xcross, x2 - xcross, tstep, &dt1, &dt2);
1107
+ if (nzer == 1) {
1108
+ tx = te + dt1;
1109
+ for (j = 0; j < 3; j++) {
1110
+ iflgret = swe_calc(tx, (int) ipl, iflag, x, serr);
1111
+ x[0] *= RADTODEG; x[3] *= RADTODEG;
1112
+ dx = swe_degnorm(x[0] - xcross);
1113
+ if (dx > 180) dx -= 360;
1114
+ tx -= dx / x[3];
1115
+ }
1116
+ izod = i % 12;
1117
+ if (x2 <= xcross) {
1118
+ strcpy(sout, "ingress retro. ");
1119
+ izod = (izod + 11) % 12;
1120
+ } else {
1121
+ strcpy(sout, "ingress ");
1122
+ }
1123
+ print_item(sout, tx, izod, HUGE, HUGE);
1124
+ }
1125
+ if (nzer == 2) { // double crossed in 1 timestep
1126
+ fprintf(stderr, "warning double crossing in ingress, reduced accuracy: planet=%d, tjd1=%.8f, tjd2=%.8f\n", ipl, te + dt1, te + dt2);
1127
+ if (x2 > xcross) { // retro, then direct
1128
+ strcpy(sout, "ingress retro. ");
1129
+ izod = (i + 11) % 12;
1130
+ print_item(sout, te + dt1, izod, HUGE, HUGE);
1131
+ strcpy(sout, "ingress ");
1132
+ izod = i % 12;
1133
+ print_item(sout, te + dt2, izod, HUGE, HUGE);
1134
+ } else { // direct, then retro
1135
+ strcpy(sout, "ingress ");
1136
+ izod = i % 12;
1137
+ print_item(sout, te + dt1, izod, HUGE, HUGE);
1138
+ strcpy(sout, "ingress retro. ");
1139
+ izod = (i + 11) % 12;
1140
+ print_item(sout, te + dt2, izod, HUGE, HUGE);
1141
+ }
1142
+ }
1143
+ }
1144
+ }
1145
+ }
1146
+ /* 45° ingresses */
1147
+ if (do_flag & DO_INGR45) {
1148
+ double x0, x1, x2, xcross, d12, d01, tx, x[6];
1149
+ int j;
1150
+ x2 = xp2[0] * RADTODEG; // at t
1151
+ x1 = xp1[0] * RADTODEG; // at t - tstep
1152
+ x0 = xp0[0] * RADTODEG; // at t - 2 * tstep
1153
+ // x2 is in [0..360[
1154
+ // normalize x1 and x0 so that there are no jumps
1155
+ d12 = swe_difdeg2n(x2, x1);
1156
+ x1 = x2 - d12;
1157
+ d01 = swe_difdeg2n(x1, x0);
1158
+ x0 = x1 - d01;
1159
+ for (i = 0; i < 4; i++) {
1160
+ xcross = 45 + i * 90.0;
1161
+ // is xcross between x1 and x2?
1162
+ // or x2 critically near xcross
1163
+ if (sign_change((x1 - xcross), (x2 - xcross))
1164
+ || (fabs(x0-x1) + fabs(x1-x2) > fabs(x2 - xcross))) {
1165
+ nzer = find_zero(x0 - xcross, x1 - xcross, x2 - xcross, tstep, &dt1, &dt2);
1166
+ izod = xcross / 30;
1167
+ if (nzer == 1) {
1168
+ tx = te + dt1;
1169
+ for (j = 0; j < 3; j++) {
1170
+ iflgret = swe_calc(tx, (int) ipl, iflag, x, serr);
1171
+ x[0] *= RADTODEG; x[3] *= RADTODEG;
1172
+ dx = swe_degnorm(x[0] - xcross);
1173
+ if (dx > 180) dx -= 360;
1174
+ tx -= dx / x[3];
1175
+ }
1176
+ if (x2 <= xcross) {
1177
+ strcpy(sout, "ingr45 retro. ");
1178
+ } else {
1179
+ strcpy(sout, "ingr45 ");
1180
+ }
1181
+ print_item(sout, tx, izod, HUGE, HUGE);
1182
+ }
1183
+ if (nzer == 2) { // double crossed in 1 timestep
1184
+ if (x2 > xcross) { // retro, then direct
1185
+ strcpy(sout, "ingr45 retro. ");
1186
+ print_item(sout, te + dt1, izod, HUGE, HUGE);
1187
+ strcpy(sout, "ingr45 ");
1188
+ print_item(sout, te + dt2, izod, HUGE, HUGE);
1189
+ } else { // direct, then retro
1190
+ strcpy(sout, "ingr45 ");
1191
+ print_item(sout, te + dt1, izod, HUGE, HUGE);
1192
+ strcpy(sout, "ingr45 retro. ");
1193
+ print_item(sout, te + dt2, izod, HUGE, HUGE);
1194
+ }
1195
+ }
1196
+ }
1197
+ }
1198
+ }
1199
+ /* lunar phases */
1200
+ l_phase:
1201
+ if (do_flag & DO_LPHASE) {
1202
+ int new_phase;
1203
+ int old_phase;
1204
+ int nphases = swe_d2l(360 / phase_mod);
1205
+ int j;
1206
+ double d, dv, xm[6], xs[6];
1207
+ x2[0] = swe_degnorm((xp2[0] - xs2[0]) * RADTODEG);
1208
+ x1[0] = swe_degnorm((xp1[0] - xs1[0]) * RADTODEG);
1209
+ x0[0] = swe_degnorm((xp0[0] - xs0[0]) * RADTODEG);
1210
+ if (x0[0] > x1[0]) {
1211
+ x1[0] += 360;
1212
+ x2[0] += 360;
1213
+ }
1214
+ if (x1[0] > x2[0]) {
1215
+ x2[0] += 360;
1216
+ }
1217
+ /* is there a phase change within last tstep ? */
1218
+ new_phase = floor(x2[0] / phase_mod) + 1;
1219
+ old_phase = floor(x1[0] / phase_mod) + 1;
1220
+ if (old_phase != new_phase) {
1221
+ double lphase = HUGE;
1222
+ x0[0] = x0[0] / phase_mod - old_phase;
1223
+ x1[0] = x1[0] / phase_mod - old_phase;
1224
+ x2[0] = x2[0] / phase_mod - old_phase;
1225
+ if ((nzer = find_zero(x0[0], x1[0], x2[0], tstep, &dt1, &dt2)) > 0) {
1226
+ if (fabs(dt2) < fabs(dt1))
1227
+ t2 = te + dt2;
1228
+ else
1229
+ t2 = te + dt1;
1230
+ for (j = 0; j < 2; j++) {
1231
+ iflgret = swe_calc(t2, (int) SE_MOON, iflag, xm, serr);
1232
+ iflgret = swe_calc(t2, (int) SE_SUN, iflag, xs, serr);
1233
+ d = swe_radnorm(xm[0] - xs[0]) * RADTODEG;
1234
+ dx = swe_degnorm(d - (new_phase - 1) * 90);
1235
+ if (dx > 180) dx -= 360;
1236
+ dv = (xm[3] - xs[3]) * RADTODEG;
1237
+ t2 -= dx / dv;
1238
+ }
1239
+ while (new_phase > nphases) {
1240
+ new_phase -= nphases;
1241
+ }
1242
+ strcpy(sout, "phase ");
1243
+ if (pmodel == PMODEL_SCREEN) {
1244
+ iflgret = swe_calc(t2, (int) SE_MOON, iflag, xm, serr);
1245
+ lphase = xm[0] * RADTODEG;
1246
+ }
1247
+ print_item(sout, t2, new_phase, lphase, HUGE);
1248
+ }
1249
+ }
1250
+ }
1251
+ }
1252
+ if ((iflgret & whicheph) == 0) {
1253
+ sprintf(sout, "ephemeris %d", iflgret & SEFLG_EPHMASK);
1254
+ print_item(sout, HUGE, -1, HUGE, HUGE);
1255
+ }
1256
+ }
1257
+ /* close open files and free allocated space */
1258
+ if (do_motab && prev_yout != -999999)
1259
+ print_motab();
1260
+ #if PRINTMOD
1261
+ printmod_close_page();
1262
+ printmod_close_printer();
1263
+ #endif
1264
+ swe_close();
1265
+ return OK;
1266
+ }
1267
+
1268
+ static int print_motab()
1269
+ {
1270
+ int i, j;
1271
+ printf("%d\n", prev_yout);
1272
+ for (i = 1; i <= 12; i++)
1273
+ printf("\t%s", month_nam[i]);
1274
+ printf("\n");
1275
+ for (i = 0; i < 31; i++) {
1276
+ printf("%02d", i+1);
1277
+ for (j = 0; j < 12; j++)
1278
+ printf("\t%s", motab[j][i]);
1279
+ printf("\n");
1280
+ }
1281
+ printf("\n\n");
1282
+ memset(motab, 0, sizeof(motab));
1283
+ prev_yout = -999999;
1284
+ return OK;
1285
+ }
1286
+
1287
+ /*
1288
+ * a planetary phenomenon ist printed;
1289
+ * date time is alway printed (in UT)
1290
+ * ingresses: s is "ingress" or "ingress retro" , only date and 0/30 sign
1291
+ * ingr45: s is "ingr45" or "ingr45 retro" , only date and 15 [r] sign
1292
+ * phases: s is "phase" , only date and phase number
1293
+ * if delon or dmag are HUGE, they are not printed.
1294
+ */
1295
+ static void print_item(char *s, double teph, double dpos, double delon, double dmag)
1296
+ {
1297
+ static char smag[10], sout[AS_MAXCH], serr[AS_MAXCH];
1298
+ int mout, dout, yout, hour, min, sec, izod;
1299
+ int ing_deg = 0;
1300
+ double hout;
1301
+ double secfr;
1302
+ double jut;
1303
+ AS_BOOL is_ingress;
1304
+ AS_BOOL is_ingr45;
1305
+ AS_BOOL is_phase;
1306
+ AS_BOOL is_retro = FALSE;
1307
+ char sign_deg[30];
1308
+ static AS_BOOL cycle_has_started = FALSE;
1309
+ char *jul = "";
1310
+ jut = ing_deg * is_retro; // dummy to silence compiler;
1311
+ // static double teph_save = 0;
1312
+ teph += tzone/24;
1313
+ if (do_flag != DO_ALL) {
1314
+ cycle_has_started = TRUE;
1315
+ swe_revjul(teph, gregflag, &yout, &mout, &dout, &jut);
1316
+ sprintf(sdatefrom, "%d", yout);
1317
+ if (gregflag && yout < 1700)
1318
+ strcat(sdatefrom, "greg");
1319
+ }
1320
+ if (strncmp(s, "superior", 8) == 0
1321
+ || (ipl > SE_VENUS && strncmp(s, "conj", 4) == 0)) {
1322
+ if (!cycle_has_started) {
1323
+ swe_revjul(teph, gregflag, &yout, &mout, &dout, &jut);
1324
+ sprintf(sdatefrom, "%d", yout);
1325
+ if (gregflag && yout < 1700)
1326
+ strcat(sdatefrom, "greg");
1327
+ }
1328
+ cycle_has_started = TRUE;
1329
+ } else if (!cycle_has_started)
1330
+ return;
1331
+ is_ingress = (strncmp(s, "ingr", 4) == 0);
1332
+ is_ingr45 = (strncmp(s, "ingr45", 6) == 0);
1333
+ is_phase = (strncmp(s, "phas", 4) == 0);
1334
+ if (gregflag == FALSE) {
1335
+ jul = "j";
1336
+ }
1337
+ if (strstr(s, "ret") != NULL) {
1338
+ is_retro = TRUE;
1339
+ ing_deg = 30;
1340
+ strcpy(sign_deg, "30");
1341
+ if (is_ingr45) {
1342
+ ing_deg = 15;
1343
+ strcpy(sign_deg, "15 r");
1344
+ }
1345
+ } else {
1346
+ ing_deg = 0;
1347
+ strcpy(sign_deg, " 0");
1348
+ if (is_ingr45) {
1349
+ ing_deg = 15;
1350
+ strcpy(sign_deg, "15");
1351
+ }
1352
+ }
1353
+ /* compute UT and add 0.5 minutes for later rounding to minutes */
1354
+ if (transits_to_stderr && strstr(s, "transit") != NULL) {
1355
+ swe_revjul(teph, gregflag, &yout, &mout, &dout, &hout);
1356
+ if (strstr(s, "middle") != NULL) {
1357
+ fprintf(stderr, "/* %d %s %d %f */\n", yout, month_nam[mout], dout, hout);
1358
+ }
1359
+ fprintf(stderr, "%f,", teph);
1360
+ if (strstr(s, "end") != NULL) {
1361
+ fprintf(stderr, "\n");
1362
+ }
1363
+ }
1364
+ teph += gmtoff / 24;
1365
+ if (ephemeris_time)
1366
+ teph = teph;
1367
+ else
1368
+ teph = teph - swe_deltat_ex(teph, whicheph, serr);
1369
+ swe_revjul(teph, gregflag, &yout, &mout, &dout, &hout);
1370
+ swe_split_deg(hout, SE_SPLIT_DEG_ROUND_SEC, &hour, &min, &sec, &secfr, &izod);
1371
+ if (dmag != HUGE) {
1372
+ if (strstr(s, "brill") != NULL) {
1373
+ sprintf(smag, " %.1fm", dmag);
1374
+ } else {
1375
+ if (output_extra_prec)
1376
+ sprintf(smag, " %8.13f AU", dmag);
1377
+ else
1378
+ sprintf(smag, " %8.5f AU", dmag);
1379
+ }
1380
+ } else {
1381
+ *smag = '\0';
1382
+ }
1383
+ if (do_motab) {
1384
+ if (yout != prev_yout && prev_yout != -999999)
1385
+ print_motab();
1386
+ izod = (int) (dpos + 0.1);
1387
+ sprintf(sout, "%02d:%02d:%02d %s", hour, min, sec, znam[izod]);
1388
+ strcpy(motab[mout-1][dout-1], sout);
1389
+ prev_yout = yout;
1390
+ return;
1391
+ }
1392
+ if (is_ingress || is_phase)
1393
+ strcpy(s, " ");
1394
+ if (pmodel == PMODEL_SCREEN) {
1395
+ if (strncmp(s, "superior", 8) == 0)
1396
+ putchar('\n');
1397
+ else if (ipl > SE_VENUS && strncmp(s, "conj", 4) == 0)
1398
+ putchar('\n');
1399
+ printf("%-20s%s", s, gap);
1400
+ if (date_gap) {
1401
+ printf("%02d%s%s%s%2d%s%s%02d:%02d:%02d",
1402
+ yout, gap, month_nam[mout], gap, dout, jul, gap, hour, min, sec);
1403
+ } else {
1404
+ printf("%02d %s %2d %s %02d:%02d:%02d ",
1405
+ yout, month_nam[mout], dout, jul, hour, min, sec);
1406
+ }
1407
+ if (show_jd)
1408
+ printf("%sjd=%.8lf", gap, teph);
1409
+ printf("%s", gap);
1410
+ if (is_ingr45) {
1411
+ printf("%s", sign_deg);
1412
+ izod = (int) (dpos + 0.1);
1413
+ if (date_gap)
1414
+ printf("%s%s", gap, znam[izod]);
1415
+ else
1416
+ printf(" %s", znam[izod]);
1417
+ } else if (is_ingress) {
1418
+ printf("%s", sign_deg);
1419
+ izod = (int) (dpos + 0.1);
1420
+ if (date_gap)
1421
+ printf("%s%s", gap, znam[izod]);
1422
+ else
1423
+ printf(" %s", znam[izod]);
1424
+ } else if (is_phase) {
1425
+ izod = (int) (dpos + 0.1);
1426
+ switch(izod) {
1427
+ case 1:
1428
+ strcpy(sout, " New"); break;
1429
+ case 2:
1430
+ strcpy(sout, " h/wax"); break;
1431
+ case 3:
1432
+ strcpy(sout, " Full"); break;
1433
+ case 4:
1434
+ strcpy(sout, " h/wane"); break;
1435
+ }
1436
+ printf("%s%s%d", sout, gap, izod);
1437
+ if (delon != HUGE) {
1438
+ printf("%s", dms(delon, BIT_ZODIAC|BIT_ROUND_SEC));
1439
+ delon = HUGE;
1440
+ }
1441
+ } else {
1442
+ printf("%s", dms(dpos, BIT_ZODIAC|BIT_ROUND_SEC));
1443
+ }
1444
+ if (delon != HUGE) {
1445
+ printf("%s%s", gap, dms(delon, BIT_ROUND_SEC));
1446
+ }
1447
+ if (*smag)
1448
+ printf("%s%s", gap, smag); /**/
1449
+ printf("\n");
1450
+ }
1451
+ #if PRINTMOD
1452
+ else {
1453
+ CSEC cspos = dpos * DEG2CSEC;
1454
+ char cdtsgn, s2[AS_MAXCH];
1455
+ int dtmin, dthr, ncpt;
1456
+ int max_lines = MAX_LINES;
1457
+ static int line_count, page_count, col_count;
1458
+ static int icycol = 0;
1459
+ if (page_count == 0 && print_cl)
1460
+ max_lines -= 2; /* leave space for command line output */
1461
+ if (line_count > 0 && (strncmp(s, "superior", 8) == 0
1462
+ || (ipl > SE_VENUS && strncmp(s, "conj", 4) == 0))) {
1463
+ line_count++;
1464
+ if (ncycol > 0) {
1465
+ icycol++;
1466
+ if (icycol >= ncycol) {
1467
+ line_count = max_lines;
1468
+ icycol = 0;
1469
+ }
1470
+ }
1471
+ }
1472
+ if (line_count >= max_lines) {
1473
+ col_count++;
1474
+ line_count = 0;
1475
+ if (col_count == max_cols) {
1476
+ if (page_count == 0 && print_cl) {
1477
+ SetFont(FT_TIM_8);
1478
+ MoveToXYmm(xcol[0], ytop + (max_lines + 1) * line_space);
1479
+ Print(cmdline);
1480
+ }
1481
+ page_count++;
1482
+ printmod_close_page();
1483
+ col_count = 0;
1484
+ }
1485
+ }
1486
+ if (col_count == 0 && line_count == 0) {
1487
+ printmod_open_page(NULL);
1488
+ print_date_time(s2);
1489
+ if (ephemeris_time)
1490
+ sprintf(sout, "%s of %s from %s through %s (ET), Astrodienst AG %s, page %d", stit, planet_name, syear0, sdateto, s2, page_count + 1);
1491
+ else
1492
+ sprintf(sout, "%s of %s from %s through %s (UT), Astrodienst AG %s, page %d", stit, planet_name, syear0, sdateto, s2, page_count + 1);
1493
+ if (ephemeris_time)
1494
+ MoveToXYmm(xcol[col_count], ytop - 3 * line_space);
1495
+ else
1496
+ MoveToXYmm(xcol[col_count], ytop - 2 * line_space);
1497
+ SetFont(FT_TIM_10);
1498
+ Print(sout);
1499
+ if (ephemeris_time) {
1500
+ double delt;
1501
+ SetFont(FT_TIM_8);
1502
+ MoveToXYmm(xcol[col_count], ytop - 2 * line_space);
1503
+ //delt = swe_deltat(teph) * 86400;
1504
+ delt = swe_deltat_ex(teph, whicheph, serr) * 86400;
1505
+ dtmin = (fabs(delt) + 30) / 60; /* delta t in rounded minutes */
1506
+ dthr = dtmin / 60;
1507
+ if (delt < 0)
1508
+ cdtsgn = '+';
1509
+ else
1510
+ cdtsgn = '-';
1511
+ dtmin %= 60;
1512
+ sprintf(sout, "(UT = ET %c %dh%2dm)", cdtsgn, dthr, dtmin);
1513
+ Print(sout);
1514
+ }
1515
+ if (*sdatefrom == '-') {
1516
+ int yb = atoi(sdatefrom);
1517
+ SetFont(FT_TIM_8);
1518
+ MoveToXYmm(xcol[col_count], ytop - 1 * line_space);
1519
+ sprintf(sout, "Attention, astronomical year style is used: The year %d in astronomical counting style is the year %d BCE in historical counting style.", yb, abs(yb) + 1);
1520
+ Print(sout);
1521
+ }
1522
+ }
1523
+ MoveToXYmm(xcol[col_count], ytop + line_count * line_space);
1524
+ SetFont(FT_TIM_8);
1525
+ if (! is_ingress)
1526
+ Print(s);
1527
+ MoveToXmm(xcol[col_count] + xdate);
1528
+ sprintf(sout, "%02d ", yout);
1529
+ Print(sout);
1530
+ Print(month_nam[mout]);
1531
+ ncpt = TextWidth("May") - TextWidth(month_nam[mout]);
1532
+ RmoveXcp(ncpt);
1533
+ sprintf(sout, " %02d %s %02d:%02d", dout, jul, min / 60, min % 60);
1534
+ Print(sout);
1535
+ MoveToXmm(xcol[col_count] + xpos);
1536
+ if (is_ingr45) {
1537
+ if (ing_deg < 10)
1538
+ RmoveXcp(TextWidth("0"));
1539
+ sprintf(sout, "%d%s", ing_deg, ODEGREE_STRING);
1540
+ Print(sout);
1541
+ if (is_retro) {
1542
+ SetFont(FT_SYMBS);
1543
+ Print(symb_special(SYMB_RETRO));
1544
+ }
1545
+ SetFont(FT_SYMBS);
1546
+ Print(symb_sign((int) dpos));
1547
+ SetFont(FT_TIM_8);
1548
+ } else if (is_ingress) {
1549
+ if (ing_deg < 10)
1550
+ RmoveXcp(TextWidth("0"));
1551
+ sprintf(sout, "%d%s", ing_deg, ODEGREE_STRING);
1552
+ Print(sout);
1553
+ if (is_retro) {
1554
+ SetFont(FT_SYMBS);
1555
+ Print(symb_special(SYMB_RETRO));
1556
+ }
1557
+ SetFont(FT_SYMBS);
1558
+ Print(symb_sign((int) dpos));
1559
+ SetFont(FT_TIM_8);
1560
+ } else if (is_phase) {
1561
+ int iphase = dpos;
1562
+ if (phase_mod == 180) {
1563
+ if (iphase == 1)
1564
+ strcpy(sout, "new");
1565
+ else
1566
+ strcpy(sout, "full");
1567
+ } else if (phase_mod == 90) {
1568
+ switch(iphase) {
1569
+ case 1:
1570
+ strcpy(sout, " New"); break;
1571
+ case 2:
1572
+ strcpy(sout, ""); break;
1573
+ case 3:
1574
+ strcpy(sout, " Full"); break;
1575
+ case 4:
1576
+ strcpy(sout, ""); break;
1577
+ }
1578
+ SetFont(FT_SYMBN);
1579
+ Print(symb_special(SYMB_NEW_MOON + iphase - 1));
1580
+ SetFont(FT_TIM_8);
1581
+ } else {
1582
+ if (iphase == 1)
1583
+ strcpy(sout, "1 = new");
1584
+ else
1585
+ sprintf(sout, "%d", iphase);
1586
+ }
1587
+ Print(sout);
1588
+ } else {
1589
+ printmod_pds(cspos, FT_SYMBS, 0);
1590
+ }
1591
+ if (delon != HUGE) {
1592
+ Print(" ");
1593
+ printmod_pds(delon * DEG2CSEC, FT_SYMBS, PDS_NO_ZOD_SIGN);
1594
+ }
1595
+ Print(smag);
1596
+ PrintLn();
1597
+ line_count++;
1598
+ }
1599
+ # endif
1600
+ }
1601
+
1602
+ static char *dms(double x, int iflag)
1603
+ {
1604
+ int izod = 0;
1605
+ int k, kdeg, kmin, ksec;
1606
+ char *c = ODEGREE_STRING;
1607
+ char *sp;
1608
+ static char s[80], s2[80];
1609
+ int sgn;
1610
+ *s = *s2 = '\0';
1611
+ again_dms:
1612
+ if (iflag & SEFLG_EQUATORIAL)
1613
+ c = "h";
1614
+ if (x < 0) {
1615
+ x = -x;
1616
+ sgn = -1;
1617
+ } else {
1618
+ sgn = 1;
1619
+ }
1620
+ if (iflag & BIT_ZODIAC) {
1621
+ izod = (int) floor(x / 30);
1622
+ x = fmod(x, 30);
1623
+ kdeg = (long) x;
1624
+ sprintf(s, "%2d %s ", kdeg, znam[izod]);
1625
+ } else {
1626
+ kdeg = (long) x;
1627
+ sprintf(s, " %3d%s", kdeg, c);
1628
+ }
1629
+ x -= kdeg;
1630
+ x *= 60;
1631
+ if (iflag & BIT_ROUND_MIN)
1632
+ x += 0.5;
1633
+ kmin = (long) x;
1634
+ if (kmin == 60) {
1635
+ x = (kdeg + 1) * sgn;
1636
+ if (iflag & BIT_ZODIAC)
1637
+ x += izod * 30;
1638
+ goto again_dms;
1639
+ }
1640
+ strcpy(s2, s);
1641
+ if ((iflag & BIT_ZODIAC) && (iflag & BIT_ROUND_MIN))
1642
+ sprintf(s, "%s%2d", s2, kmin);
1643
+ else
1644
+ sprintf(s, "%s%2d'", s2, kmin);
1645
+ if (iflag & BIT_ROUND_MIN)
1646
+ goto return_dms;
1647
+ x -= kmin;
1648
+ x *= 60;
1649
+ if (iflag & BIT_ROUND_SEC)
1650
+ x += 0.5;
1651
+ ksec = (long) x;
1652
+ if (ksec == 60) {
1653
+ x = (kdeg + (kmin + 1) / 60.0 + 0.1 / 3600.0) * sgn;
1654
+ if (iflag & BIT_ZODIAC)
1655
+ x += izod * 30;
1656
+ goto again_dms;
1657
+ }
1658
+ strcpy(s2, s);
1659
+ sprintf(s, "%s%2d\"", s2, ksec);
1660
+ if (iflag & BIT_ROUND_SEC)
1661
+ goto return_dms;
1662
+ x -= ksec;
1663
+ k = (long) x * 10000;
1664
+ sprintf(s, "%s.%04d", s, k);
1665
+ return_dms:
1666
+ if (sgn < 0) {
1667
+ sp = strpbrk(s, "0123456789");
1668
+ *(sp-1) = '-';
1669
+ }
1670
+ if (iflag & BIT_LZEROES) {
1671
+ while ((sp = strchr(s+2, ' ')) != NULL) *sp = '0';
1672
+ }
1673
+ return(s);
1674
+ }
1675
+
1676
+ /* y00, y11, y2 are values for -2*dx, -dx, 0.
1677
+ * find zero points of parabola.
1678
+ * return: 0 if none
1679
+ * 1 if one zero in [-dx.. 0[
1680
+ * 1 if both zeros in [-dx.. 0[
1681
+ */
1682
+ static int find_zero(double y00, double y11, double y2, double dx,
1683
+ double *dxret, double *dxret2)
1684
+ {
1685
+ double a, b, c, x1, x2;
1686
+ c = y11;
1687
+ b = (y2 - y00) / 2.0;
1688
+ a = (y2 + y00) / 2.0 - c;
1689
+ if (b * b - 4 * a * c < 0)
1690
+ return 0;
1691
+ if (fabs(a) < 1e-100) return 0;
1692
+ x1 = (-b + sqrt(b * b - 4 * a * c)) / 2 / a;
1693
+ x2 = (-b - sqrt(b * b - 4 * a * c)) / 2 / a;
1694
+ // up to here the calcuation was made as if the x-values were -1, 0, 1.
1695
+ // This is why below they are shifted by -1
1696
+ if (x1 == x2) {
1697
+ *dxret = (x1 - 1) * dx;
1698
+ *dxret2 = (x1 - 1) * dx;
1699
+ return 1;
1700
+ }
1701
+ if (x1 >=0 && x1 < 1 && x2 >= 0 && x2 < 1) {
1702
+ if (x1 > x2) { // two zeroes, order return values
1703
+ *dxret = (x2 - 1) * dx;
1704
+ *dxret2 = (x1 - 1) * dx;
1705
+ } else {
1706
+ *dxret = (x1 - 1) * dx;
1707
+ *dxret2 = (x2 - 1) * dx;
1708
+ }
1709
+ return 2;
1710
+ }
1711
+ if (x1 >=0 && x1 < 1) {
1712
+ *dxret = (x1 - 1) * dx;
1713
+ *dxret2 = (x2 - 1) * dx; // set this value just in case, should not be used.
1714
+ return 1;
1715
+ }
1716
+ if (x2 >=0 && x2 < 1) {
1717
+ *dxret = (x2 - 1) * dx;
1718
+ *dxret2 = (x1 - 1) * dx;
1719
+ return 1;
1720
+ }
1721
+ return 0; // should not happen!
1722
+ }
1723
+
1724
+ static int find_maximum(double y00, double y11, double y2, double dx,
1725
+ double *dxret, double *yret)
1726
+ {
1727
+ double a, b, c, x, y;
1728
+ c = y11;
1729
+ b = (y2 - y00) / 2.0;
1730
+ a = (y2 + y00) / 2.0 - c;
1731
+ x = -b / 2 / a;
1732
+ y = (4 * a * c - b * b) / 4 / a;
1733
+ *dxret = (x - 1) * dx;
1734
+ *yret = y;
1735
+ return OK;
1736
+ }
1737
+
1738
+ // stuff from old swevents.c
1739
+ /*
1740
+ * aspect codes
1741
+ * 1: 0
1742
+ * 2: 180
1743
+ * 3: 90
1744
+ * 4: 120
1745
+ * 5: 60
1746
+ * 6: 30
1747
+ * 7: 150
1748
+ * 8: 72
1749
+ * 9: 144
1750
+ * A: 45
1751
+ * B: 135
1752
+ * C: 0 parallel
1753
+ * D: 0 anti-parallel
1754
+ * input:
1755
+ * sasp aspects string, e.g. "1234567"
1756
+ * output:
1757
+ * dasp aspect angles: 0, 180, 90, 270, 120, 240, 60, 300, 30, 330, 150, 210
1758
+ * saspi aspects string that defines the angles: 123344556677
1759
+ */
1760
+ static int32 get_aspect_angles(char *sasp, char *saspi, double *dasp, char *serr)
1761
+ {
1762
+ int nasp = 0;
1763
+ char *sp;
1764
+ *saspi = '\0';
1765
+ for (sp = sasp; *sp != '\0'; sp++) {
1766
+ switch (*sp) {
1767
+ case '1':
1768
+ dasp[nasp] = 0;
1769
+ strcat(saspi, "1");
1770
+ nasp++;
1771
+ break;
1772
+ case '2':
1773
+ dasp[nasp] = 180;
1774
+ strcat(saspi, "2");
1775
+ nasp++;
1776
+ break;
1777
+ case '3':
1778
+ dasp[nasp] = 90;
1779
+ nasp++;
1780
+ dasp[nasp] = 270;
1781
+ nasp++;
1782
+ strcat(saspi, "33");
1783
+ break;
1784
+ case '4':
1785
+ dasp[nasp] = 120;
1786
+ nasp++;
1787
+ dasp[nasp] = 240;
1788
+ nasp++;
1789
+ strcat(saspi, "44");
1790
+ break;
1791
+ case '5':
1792
+ dasp[nasp] = 60;
1793
+ nasp++;
1794
+ dasp[nasp] = 300;
1795
+ nasp++;
1796
+ strcat(saspi, "55");
1797
+ break;
1798
+ case '6':
1799
+ dasp[nasp] = 30;
1800
+ nasp++;
1801
+ dasp[nasp] = 330;
1802
+ nasp++;
1803
+ strcat(saspi, "66");
1804
+ break;
1805
+ case '7':
1806
+ dasp[nasp] = 150;
1807
+ nasp++;
1808
+ dasp[nasp] = 210;
1809
+ nasp++;
1810
+ strcat(saspi, "77");
1811
+ break;
1812
+ case '8':
1813
+ dasp[nasp] = 72;
1814
+ nasp++;
1815
+ dasp[nasp] = 288;
1816
+ nasp++;
1817
+ strcat(saspi, "88");
1818
+ break;
1819
+ case '9':
1820
+ dasp[nasp] = 144;
1821
+ nasp++;
1822
+ dasp[nasp] = 216;
1823
+ nasp++;
1824
+ strcat(saspi, "99");
1825
+ break;
1826
+ case 'A':
1827
+ dasp[nasp] = 45;
1828
+ nasp++;
1829
+ dasp[nasp] = 315;
1830
+ nasp++;
1831
+ strcat(saspi, "AA");
1832
+ break;
1833
+ case 'B':
1834
+ dasp[nasp] = 135;
1835
+ nasp++;
1836
+ dasp[nasp] = 225;
1837
+ nasp++;
1838
+ strcat(saspi, "BB");
1839
+ break;
1840
+ default:
1841
+ sprintf(serr, "aspects string %s is invalid", sasp);
1842
+ return ERR;
1843
+ break;
1844
+ }
1845
+ }
1846
+ return nasp;
1847
+ }
1848
+
1849
+ static int32 call_swe_calc(double tjd, int32 ipl, int32 iflag, char *star, double *x, char * serr)
1850
+ {
1851
+ if (ipl == -2)
1852
+ fprintf(stderr, "hallo %d %s\n", ipl, star);
1853
+ if (ipl == SE_FIXSTAR) {
1854
+ return swe_fixstar(star, tjd, iflag, x, serr);
1855
+ } else {
1856
+ return swe_calc(tjd, ipl, iflag, x, serr);
1857
+ }
1858
+ }
1859
+
1860
+ /*
1861
+ * Binary search of minimum orb with an almost-aspect
1862
+ * and of exact aspects that happen twice within step width
1863
+ */
1864
+ static int get_crossing_bin_search(double dt, double tt0, double dang, double xta1, double xta2, double xtb1, double xtb2, double *tret, int32 ipla, int32 iplb, char *stara, char *starb, int32 iflag, AS_BOOL is_transit, char *serr)
1865
+ {
1866
+ double d12, d1, d2, tt1, xa[6], xb[6];
1867
+ /*swe_revjul(tt0, 1, &jyear, &jmon, &jday, &jut);
1868
+ printf("%d%02d%02d %.2f: %c - %c %d\n", jyear, jmon, jday, jut, *spa, *spb, (int) dang);*/
1869
+ d1 = swe_degnorm(xta1 - xtb1 - dang);
1870
+ if (d1 > 180) d1 -= 360;
1871
+ d2 = swe_degnorm(xta2 - xtb2 - dang);
1872
+ if (d2 > 180) d2 -= 360;
1873
+ #if 0
1874
+ /* this is handled by calling function */
1875
+ if (ipla == SE_MOON || iplb == SE_MOON) {
1876
+ if (fabs(d1) > 20)
1877
+ continue;
1878
+ } else if (fabs(d1) > 5) {
1879
+ continue;
1880
+ }
1881
+ #endif
1882
+ while(dt > HUNDTHOFSEC) {
1883
+ dt /= 2.0;
1884
+ tt1 = tt0 + dt;
1885
+ if (call_swe_calc(tt1, ipla, iflag, stara, xa, serr) == ERR)
1886
+ return ERR;
1887
+ if (is_transit)
1888
+ xb[0] = xtb1;
1889
+ else
1890
+ if (call_swe_calc(tt1, iplb, iflag, starb, xb, serr) == ERR)
1891
+ return ERR;
1892
+ d12 = swe_degnorm(xa[0] - xb[0] - dang);
1893
+ if (d12 > 180) d12 -= 360;
1894
+ if (d1 * d12 < 0) {
1895
+ xta2 = xa[0];
1896
+ xtb2 = xb[0];
1897
+ } else {
1898
+ xta1 = xa[0];
1899
+ xtb1 = xb[0];
1900
+ tt0 += dt;
1901
+ }
1902
+ d1 = swe_degnorm(xta1 - xtb1 - dang);
1903
+ if (d1 > 180) d1 -= 360;
1904
+ d2 = swe_degnorm(xta2 - xtb2 - dang);
1905
+ if (d2 > 180) d2 -= 360;
1906
+ }
1907
+ *tret = tt0;
1908
+ return OK;
1909
+ }
1910
+
1911
+ /* Binary search of exact aspect
1912
+ * This function finds aspects if exactness occurs only once within step
1913
+ * width */
1914
+ static int get_near_crossing_bin_search(double dt, double tt0, double dang, double xta1, double xta2, double xtb1, double xtb2, double *tret, double *tret2, double *dorb, int32 ipla, int32 iplb, char *stara, char *starb, int32 iflag, char *serr)
1915
+ {
1916
+ double d12, d1, d2, tt1, xa[6], xb[6];
1917
+ *tret = 0;
1918
+ *tret2 = 0;
1919
+ *dorb = 0;
1920
+ /*swe_revjul(tt0, 1, &jyear, &jmon, &jday, &jut);
1921
+ printf("%d%02d%02d %.2f: %c - %c %d\n", jyear, jmon, jday, jut, *spa, *spb, (int) dang);*/
1922
+ d1 = swe_degnorm(xta1 - xtb1 - dang);
1923
+ if (d1 > 180) d1 -= 360;
1924
+ d2 = swe_degnorm(xta2 - xtb2 - dang);
1925
+ if (d2 > 180) d2 -= 360;
1926
+ while(dt > HUNDTHOFSEC) {
1927
+ dt /= 2.0;
1928
+ tt1 = tt0 + dt;
1929
+ if (call_swe_calc(tt1, ipla, iflag, stara, xa, serr) == ERR)
1930
+ return ERR;
1931
+ if (call_swe_calc(tt1, iplb, iflag, starb, xb, serr) == ERR)
1932
+ return ERR;
1933
+ d12 = swe_degnorm(xa[0] - xb[0] - dang);
1934
+ if (d12 > 180) d12 -= 360;
1935
+ if (d1 * d12 < 0 || d12 * d2 < 0) {
1936
+ if (get_crossing_bin_search(dt, tt0, dang, xta1, xa[0], xtb1, xb[0], tret, ipla, iplb, stara, starb, iflag, FALSE, serr) == ERR)
1937
+ return ERR;
1938
+ if (get_crossing_bin_search(dt, tt1, dang, xa[0], xta2, xb[0], xtb2, tret2, ipla, iplb, stara, starb, iflag, FALSE, serr) == ERR)
1939
+ return ERR;
1940
+ *dorb = 0;
1941
+ return OK;
1942
+ /*sprintf(serr, "crossing missed near t=%f, ipl1=%d, ipl2=%d, dang=%.0f\n", tt1, ipla, iplb, dang);
1943
+ return ERR;*/
1944
+ } else if (fabs(d2) > fabs(d1)) {
1945
+ xta2 = xa[0];
1946
+ xtb2 = xb[0];
1947
+ } else {
1948
+ xta1 = xa[0];
1949
+ xtb1 = xb[0];
1950
+ tt0 += dt;
1951
+ }
1952
+ d1 = swe_degnorm(xta1 - xtb1 - dang);
1953
+ if (d1 > 180) d1 -= 360;
1954
+ d2 = swe_degnorm(xta2 - xtb2 - dang);
1955
+ if (d2 > 180) d2 -= 360;
1956
+ }
1957
+ *tret = tt0;
1958
+ *dorb = d1;
1959
+ return OK;
1960
+ }
1961
+
1962
+ static void fill_pev_day(EVENT *pevd, double tjd, int ipla, int iplb, char *stara, char *starb, int iasp, int bpind, double dasp, double dang, double dorb, char *strg)
1963
+ {
1964
+ int jyear, jmon, jday;
1965
+ double jut;
1966
+ char s[AS_MAXCH];
1967
+ char spl1[30], spl2[30];
1968
+ swe_get_planet_name(ipla, spl1);
1969
+ swe_get_planet_name(iplb, spl2);
1970
+ if (ipla == SE_FIXSTAR)
1971
+ strcpy(spl1, stara);
1972
+ if (iplb == SE_FIXSTAR)
1973
+ strcpy(spl2, starb);
1974
+ spl1[3] = '\0';
1975
+ spl2[3] = '\0';
1976
+ pevd->ipla = ipla;
1977
+ pevd->iplb = iplb;
1978
+ strcpy(pevd->stnama, spl1);
1979
+ strcpy(pevd->stnamb, spl2);
1980
+ pevd->tjd = tjd;
1981
+ pevd->iasp = iasp;
1982
+ pevd->bpind = bpind;
1983
+ pevd->dasp = dasp;
1984
+ pevd->dang = dang;
1985
+ pevd->dorb = dorb;
1986
+ tjd -= swe_deltat(tjd); /* now we have UT */
1987
+ swe_revjul(tjd, 1, &jyear, &jmon, &jday, &jut);
1988
+ sprintf(s, "%d/%02d/%02d %s: %s - %s ang=%d", jyear, jmon, jday, hms(jut, BIT_LZEROES), spl1, spl2, (int) dang);
1989
+ if (fabs(dorb) > 0)
1990
+ sprintf(s + strlen(s), " orb=%.4f", dorb);
1991
+ if (strg != NULL && *strg != '\0')
1992
+ sprintf(s + strlen(s), " %s", strg);
1993
+ strcat(s, "\n");
1994
+ /* printf(s);*/
1995
+ }
1996
+
1997
+ static void test_print_date(double tjd, int ipla, int iplb, char *stara, char *starb, double dang, double dorb, char *strg)
1998
+ {
1999
+ int jyear, jmon, jday;
2000
+ double jut;
2001
+ char s[AS_MAXCH];
2002
+ char spl1[30], spl2[30];
2003
+ swe_get_planet_name(ipla, spl1);
2004
+ swe_get_planet_name(iplb, spl2);
2005
+ if (ipla == SE_FIXSTAR)
2006
+ strcpy(spl1, stara);
2007
+ if (iplb == SE_FIXSTAR)
2008
+ strcpy(spl2, starb);
2009
+ spl1[3] = '\0';
2010
+ spl2[3] = '\0';
2011
+ tjd -= swe_deltat(tjd); /* now we have UT */
2012
+ swe_revjul(tjd, 1, &jyear, &jmon, &jday, &jut);
2013
+ sprintf(s, "%d/%02d/%02d %s: %s - %s ang=%.0f", jyear, jmon, jday, hms(jut, BIT_LZEROES), spl1, spl2, dang);
2014
+ if (fabs(dorb) > 0)
2015
+ sprintf(s + strlen(s), " orb=%.4f", dorb);
2016
+ if (strg != NULL && *strg != '\0')
2017
+ sprintf(s + strlen(s), " %s", strg);
2018
+ strcat(s, "\n");
2019
+ printf(s);
2020
+ }
2021
+
2022
+ static char *forw_splan(char *sp)
2023
+ {
2024
+ char *sp2;
2025
+ /*fprintf(stderr, "vor=%s; ", sp);*/
2026
+ if (*sp == ',') {
2027
+ sp2 = strchr(sp, ']');
2028
+ if (sp2 == NULL)
2029
+ sp = sp + strlen(sp); /* end of string splan */
2030
+ else
2031
+ sp = sp2 + 1;
2032
+ } else {
2033
+ sp++;
2034
+ }
2035
+ /* fprintf(stderr, "nach=%s;\n", sp);*/
2036
+ return sp;
2037
+ }
2038
+
2039
+ /*
2040
+ * Function returns the ipl or name (if star) of the next object in
2041
+ * the planets string.
2042
+ * The planets string is formed as follows:
2043
+ * "0123456789mtAFD,f[Gal],f[Ald],a[136199],a[433]"
2044
+ * The characters before the comma are planet codes as we use them
2045
+ * in other software.
2046
+ * Asteroids are coded as follows ",a[mpc_number]".
2047
+ * Fixed stars are coded as follows ",f[star_name]".
2048
+ */
2049
+ static int32 letter_to_ipl_or_star(char *s, char *stnam)
2050
+ {
2051
+ char *sp, *sp2;
2052
+ int ipl = letter_to_ipl((int) *s);
2053
+ if (*s == ',') {
2054
+ sp = s + 1;
2055
+ /* fixed star */
2056
+ if (*sp == 'f') {
2057
+ sp += 2;
2058
+ sp2 = strchr(sp, ']');
2059
+ if (sp2 == NULL) { /* bracket at end of string missing */
2060
+ strcpy(stnam, sp);
2061
+ } else {
2062
+ strncpy(stnam, sp, sp2 - sp);
2063
+ stnam[sp2 - sp] = '\0';
2064
+ }
2065
+ ipl = SE_FIXSTAR;
2066
+ } else if (*sp == 'a') {
2067
+ sp += 2;
2068
+ ipl = atoi(sp) + SE_AST_OFFSET;
2069
+ }
2070
+ }
2071
+ return ipl;
2072
+ }
2073
+
2074
+ static int pev_compare(const EVENT *a1, const EVENT *a2)
2075
+ {
2076
+ if (a1->tjd > a2->tjd)
2077
+ return 1;
2078
+ if (a1->tjd < a2->tjd)
2079
+ return -1;
2080
+ return 0;
2081
+ }
2082
+
2083
+ #define SWEV_ASPORB 1
2084
+ #define NSTARS_MAX 30
2085
+ #define NMAXPL 50
2086
+ #define NEAR_CROSSING_ORB 1
2087
+ #define FOUTNAM "sweasp.dat"
2088
+ #define PATH_FOUTNAM "."
2089
+
2090
+ static int read_sweasp_dat(char *foutnam)
2091
+ {
2092
+ FILE *fpout;
2093
+ char serr[AS_MAXCH];
2094
+ int32 flen = 0, headerlen = 0;
2095
+ int32 i, nrec = 0, ipla, iplb, iasp;
2096
+ double tjd, dasp, tjd_pre, tjd_post;
2097
+ int jyear, jmon, jday;
2098
+ double jut, dorb, dur;
2099
+ char s[AS_MAXCH], *sp;
2100
+ char spl1[30], spl2[30];
2101
+ /* open aspects file */
2102
+ if ((fpout = fopen(foutnam, BFILE_R_ACCESS)) == NULL) {
2103
+ sprintf(serr, "could not open file %s", foutnam);
2104
+ return ERR;
2105
+ }
2106
+ while (fgets(s, AS_MAXCH, fpout) != NULL && (sp = strchr(s, '\n')) != NULL) {
2107
+ headerlen += strlen(s);
2108
+ if (strncmp(s, "####", 4) == 0)
2109
+ break;
2110
+ }
2111
+ if (fseek(fpout, 0L, SEEK_END) != 0) {
2112
+ sprintf(serr, "fseek failed (SEEK_END): %s", foutnam);
2113
+ return ERR;
2114
+ }
2115
+ flen = ftell(fpout) - headerlen;
2116
+ nrec = flen / 52;
2117
+ if (fseek(fpout, headerlen, SEEK_SET) != 0) {
2118
+ sprintf(serr, "fseek failed (SEEK_SET): %s", foutnam);
2119
+ return ERR;
2120
+ }
2121
+ dur = 0;
2122
+ for (i = 0; i < nrec; i++) {
2123
+ fread((void *) &tjd, sizeof(double), 1, fpout);
2124
+ fread((void *) &ipla, sizeof(int32), 1, fpout);
2125
+ fread((void *) &iplb, sizeof(int32), 1, fpout);
2126
+ fread((void *) &iasp, sizeof(int32), 1, fpout);
2127
+ fread((void *) &dasp, sizeof(double), 1, fpout);
2128
+ fread((void *) &dorb, sizeof(double), 1, fpout);
2129
+ fread((void *) &tjd_pre, sizeof(double), 1, fpout);
2130
+ fread((void *) &tjd_post, sizeof(double), 1, fpout);
2131
+ if ((0)) { /* test output find longest possible aspect duration */
2132
+ if (ipla <= 9 && tjd_pre > 0 && tjd_post > 0 && tjd_post - tjd_pre > dur) {
2133
+ dur = tjd_post - tjd_pre;
2134
+ fprintf(stderr, "dur = %f\n", dur);
2135
+ } else {
2136
+ continue;
2137
+ }
2138
+ }
2139
+ swe_get_planet_name(ipla, spl1);
2140
+ swe_get_planet_name(iplb, spl2);
2141
+ /* if (ipla == SE_FIXSTAR)
2142
+ strcpy(spl1, stara);
2143
+ if (iplb == SE_FIXSTAR)
2144
+ strcpy(spl2, starb);*/
2145
+ spl1[3] = '\0';
2146
+ spl2[3] = '\0';
2147
+ tjd -= swe_deltat(tjd); /* now we have UT */
2148
+ swe_revjul(tjd, 1, &jyear, &jmon, &jday, &jut);
2149
+ sprintf(s, "%d/%02d/%02d %s: %s - %s ang=%.0f, orb=%.4f, %.5f, %.5f, %.5f", jyear, jmon, jday, hms(jut, BIT_LZEROES), spl1, spl2, dasp, dorb, tjd, tjd_pre, tjd_post);
2150
+ strcat(s, "\n");
2151
+ fprintf(stderr, s);
2152
+ }
2153
+ fclose(fpout);
2154
+ return OK;
2155
+ }
2156
+
2157
+ /* Search for mundane aspects.
2158
+ * The algorithm finds
2159
+ * 1. exact aspects
2160
+ * 2. near aspects with orb < 3 before the planets separate again
2161
+ */
2162
+ int32 calc_mundane_aspects(int32 iflag, double tjd0, double tjde, double tstep,
2163
+ char *splan, char *sasp, EVENT *pev, char *serr)
2164
+ {
2165
+ int32 ipl, ipla, iplb, ipli, iplia, iplib, bpind;
2166
+ char *sp, *spa, *spb;
2167
+ char stnam[40], stnama[40], stnamb[40];
2168
+ double t, tt0, tret, tret2, dang = 0, dorb = 0;
2169
+ double x[6], x1[30], x2[30], x1d[30], x2d[30];
2170
+ double xa[6], xa1[30], xa2[30], xa1d[30], xa2d[30];
2171
+ double d1d, d2d;
2172
+ double xta1, xta2, xtb1, xtb2, dt, d1, d2;
2173
+ int32 retflag = 0;
2174
+ int32 jyear, jmon, jday;
2175
+ double jut;
2176
+ char saspi[30];
2177
+ double dasp[30];
2178
+ int iaspi;
2179
+ int nasp = get_aspect_angles(sasp, saspi, dasp, serr);
2180
+ int nev;
2181
+ EVENT events_day[500], *pevd = &(events_day[0]);
2182
+ struct aspdat aspdat[NMAXPL * NMAXPL], *pasp;
2183
+ char foutnam[AS_MAXCH];
2184
+ FILE *fpout = NULL;
2185
+ UNUSED(xa1);
2186
+ UNUSED(xa1d);
2187
+ sprintf(foutnam, "%s/%s", PATH_FOUTNAM, FOUTNAM);
2188
+ if ((fpout = fopen(foutnam, "w+")) == NULL) {
2189
+ sprintf(serr, "could not open file %s", foutnam);
2190
+ return ERR;
2191
+ }
2192
+ fprintf(fpout, "%s, mundane aspects\ncreation date: %s\n%s\n", FOUTNAM, sdate, cmdline);
2193
+ swe_revjul(tjd0, 1, &jyear, &jmon, &jday, &jut);
2194
+ fprintf(fpout, "start date: %d/%02d/%02d, ", jyear, jmon, jday);
2195
+ swe_revjul(tjde, 1, &jyear, &jmon, &jday, &jut);
2196
+ fprintf(fpout, "end date: %d/%02d/%02d\n", jyear, jmon, jday);
2197
+ fprintf(fpout, "planets: %s\n", splan);
2198
+ fprintf(fpout, "aspects: %s\n", sasp);
2199
+ fprintf(fpout, "orb: %.2f\n", (double) SWEV_ASPORB);
2200
+ fprintf(fpout, "aspects 90 and 270 are distinguished; the coding of aspects is therefore as follows:\n");
2201
+ fprintf(fpout, "aspcode: 0123456789...\n");
2202
+ fprintf(fpout, " = %s\n", saspi);
2203
+ fprintf(fpout, "data structure:\ndouble time of exactness (TT)\nint32 number of planet a\nint32 number of planet b\nint32 number of aspect\ndouble aspect angle\ndouble precision of aspect; 0 if exact\ndouble time of crossing of pre-orb\ndouble time of crossing of post-orb\n");
2204
+ fprintf(fpout, "Aspects between nodes and apsides have no pre-orb and post-orb.\nIf an aspect comes into orb but does not become exact, time of exactness is the moment of closest approach.\nIf an aspect has no preorb, there is another exactness before that. And if it has no postorb, there is another exactness after that.\n");
2205
+ fprintf(fpout, "######################\n");
2206
+ memset((void *) &(aspdat[0]), 0, NMAXPL * NMAXPL * sizeof(struct aspdat));
2207
+ /* *stnam = '\0';*/
2208
+ for (t = tjd0; t < tjde; t += tstep) {
2209
+ nev = 0;
2210
+ pevd = &(events_day[0]);
2211
+ for (sp = splan, ipli = 0; *sp != '\0'; sp = forw_splan(sp), ipli++) {
2212
+ ipl = letter_to_ipl_or_star(sp, stnam);
2213
+ if (t == tjd0) {
2214
+ if (call_swe_calc(t, ipl, iflag|SEFLG_SPEED, stnam, x, serr) == ERR)
2215
+ return ERR;
2216
+ if (call_swe_calc(t, ipl, iflag|SEFLG_SPEED|SEFLG_EQUATORIAL, stnam, xa, serr) == ERR)
2217
+ return ERR;
2218
+ x1[ipli] = x[0];
2219
+ x1d[ipli] = x[0] + tstep / 10.0 * x[3];
2220
+ /* declination */
2221
+ xa1[ipli] = xa[1];
2222
+ xa1d[ipli] = xa[1] + tstep / 10.0 * xa[4];
2223
+ } else {
2224
+ x1[ipli] = x2[ipli];
2225
+ x1d[ipli] = x2d[ipli];
2226
+ /* declination */
2227
+ xa1[ipli] = xa2[ipli];
2228
+ xa1d[ipli] = xa2d[ipli];
2229
+ }
2230
+ if (call_swe_calc(t + tstep, ipl, iflag|SEFLG_SPEED, stnam, x, serr) == ERR)
2231
+ return ERR;
2232
+ if (call_swe_calc(t + tstep, ipl, iflag|SEFLG_SPEED|SEFLG_EQUATORIAL, stnam, xa, serr) == ERR)
2233
+ return ERR;
2234
+ x2[ipli] = x[0];
2235
+ x2d[ipli] = x[0] + tstep / 10.0 * x[3];
2236
+ /* declination */
2237
+ xa2[ipli] = xa[1];
2238
+ xa2d[ipli] = xa[1] + tstep / 10.0 * xa[4];
2239
+ }
2240
+ /* for all planets a */
2241
+ for (spa = splan, iplia = 0; *spa != '\0'; spa = forw_splan(spa), iplia++) {
2242
+ ipla = letter_to_ipl_or_star(spa, stnama);
2243
+ /* fixed stars are not considered to transit over other bodies */
2244
+ if (ipla == SE_FIXSTAR) continue; /* ????? */
2245
+ /* for all planets b */
2246
+ for (spb = forw_splan(spa), iplib = iplia + 1; *spb != '\0'; spb = forw_splan(spb), iplib++) {
2247
+ iplb = letter_to_ipl_or_star(spb, stnamb);
2248
+ bpind = iplia * NMAXPL + iplib;
2249
+ /* for all aspects */
2250
+ for (iaspi = 0; iaspi < nasp; iaspi++) {
2251
+ int iorb, norb = 3;
2252
+ int orbfac;
2253
+ double dmaxorb;
2254
+ int iasp = (int) saspi[iaspi] - (int) '0';
2255
+ /* for pre-orb, exact, post-orb: */
2256
+ for (iorb = 0; iorb < norb; iorb++) {
2257
+ /* no pre- and post orbs for aspects between different kinds of
2258
+ * nodes and apsides */
2259
+ if (norb == 3 && iorb != 1) {
2260
+ if (strchr("mtABcg", *spa) != NULL && strchr("mtABcg", *spb) != NULL)
2261
+ continue;
2262
+ }
2263
+ orbfac = (iorb - 1); /* is -1, 0, 1 */
2264
+ if (norb == 1)
2265
+ orbfac = 0;
2266
+ dmaxorb = SWEV_ASPORB * orbfac;
2267
+ dang = swe_degnorm(dasp[iaspi] + dmaxorb);
2268
+ xta1 = x1[iplia];
2269
+ xta2 = x2[iplia];
2270
+ xtb1 = x1[iplib];
2271
+ xtb2 = x2[iplib];
2272
+ tt0 = t;
2273
+ dt = tstep;
2274
+ d1 = swe_degnorm(xta1 - xtb1 - dang);
2275
+ if (d1 > 180) d1 -= 360;
2276
+ d2 = swe_degnorm(xta2 - xtb2 - dang);
2277
+ if (d2 > 180) d2 -= 360;
2278
+ if (ipla == SE_MOON || iplb == SE_MOON) {
2279
+ if (fabs(d1) > 20)
2280
+ continue;
2281
+ } else if (fabs(d1) > NEAR_CROSSING_ORB + 3) {
2282
+ continue;
2283
+ }
2284
+ d1d = swe_degnorm(x1d[iplia] - x1d[iplib] - dang);
2285
+ if (d1d > 180) d1d -= 360;
2286
+ d2d = swe_degnorm(x2d[iplia] - x2d[iplib] - dang);
2287
+ if (d2d > 180) d2d -= 360;
2288
+ /*
2289
+ * crossing found
2290
+ * find t of exact aspect
2291
+ * if exactness happens twice within step width, the aspect is
2292
+ * lost
2293
+ */
2294
+ if (d1 * d2 < 0) {
2295
+ /*
2296
+ * step width 1 day: 1min20sec/100 yr (1 or 2 asp lost per cty)
2297
+ * step width 0.1 day: 1min55sec/100 years
2298
+ * step width 0.01 day: 9min32sec/100 years
2299
+ * (calculations with SEFLG_NONUT)
2300
+ * Still, we use 1-day step width. The lost aspects will
2301
+ * be found in the "else".
2302
+ */
2303
+ if ((retflag = get_crossing_bin_search(dt, tt0, dang, xta1, xta2, xtb1, xtb2, &tret, ipla, iplb, stnama, stnamb, iflag, FALSE, serr)) == ERR)
2304
+ return ERR;
2305
+ fill_pev_day(pevd + nev, tret, ipla, iplb, stnama, stnamb, iasp, bpind, dasp[iaspi], dang, 0, NULL);
2306
+ nev++;
2307
+ /*
2308
+ * - near crossing occurs (t of smallest orb is found)
2309
+ * - or exact aspect occurs twice within step width
2310
+ * (was lost by "if")
2311
+ */
2312
+ } else if (fabs(d1) < NEAR_CROSSING_ORB || fabs(d2) < NEAR_CROSSING_ORB) {
2313
+ /* printf("d1=%f, d1d=%f, d2=%f, d2d=%f\n", d1, d1d, d2, d2d);*/
2314
+ if (d1 > 0 && d2 > 0) {
2315
+ if (d1 > d2 && d2 > d2d) continue;
2316
+ if (d1 < d2 && d1 < d1d) continue;
2317
+ } else {
2318
+ if (d1 > d2 && d1 > d1d) continue;
2319
+ if (d1 < d2 && d2 < d2d) continue;
2320
+ }
2321
+ if ((retflag = get_near_crossing_bin_search(dt, tt0, dang, xta1, xta2, xtb1, xtb2, &tret, &tret2, &dorb, ipla, iplb, stnama, stnamb, iflag, serr)) == ERR)
2322
+ return ERR;
2323
+ if (retflag == -2)
2324
+ continue;
2325
+ if (fabs(dorb) > 0) {
2326
+ if (orbfac == 0) {
2327
+ fill_pev_day(pevd + nev, tret, ipla, iplb, stnama, stnamb, iasp, bpind, dasp[iaspi], dang, dorb, "*");
2328
+ nev++;
2329
+ }
2330
+ } else {
2331
+ fill_pev_day(pevd + nev, tret, ipla, iplb, stnama, stnamb, iasp, bpind, dasp[iaspi], dang, dorb, "x");
2332
+ nev++;
2333
+ if (tret2 != 0) {
2334
+ fill_pev_day(pevd + nev, tret2, ipla, iplb, stnama, stnamb, iasp, bpind, dasp[iaspi], dang, dorb, "x");
2335
+ nev++;
2336
+ }
2337
+ }
2338
+ }
2339
+ }
2340
+ }
2341
+ }
2342
+ }
2343
+ /* sort transits of current day (time step) */
2344
+ qsort((void *) &(events_day[0]), (size_t) nev, sizeof(EVENT),
2345
+ (int (*)(const void *, const void *))(pev_compare));
2346
+ for (pevd = &(events_day[0]); pevd - &(events_day[0]) < nev; pevd++) {
2347
+ test_print_date(pevd->tjd, pevd->ipla, pevd->iplb, pevd->stnama, pevd->stnamb, pevd->dang, pevd->dorb, "");
2348
+ pasp = &(aspdat[pevd->bpind]);
2349
+ /* new aspect between body pair: init structure */
2350
+ if (pasp->tjd == 0 && pasp->tjd_pre == 0)
2351
+ pasp->iasp = -1;
2352
+ if (pasp->iasp != pevd->iasp) {
2353
+ pasp->tjd = 0;
2354
+ pasp->tjd_pre = 0;
2355
+ pasp->iasp = pevd->iasp;
2356
+ }
2357
+ /* aspect is exact */
2358
+ if (pevd->dasp == pevd->dang) {
2359
+ /* if there was another exactness before this one, we delete tjd_pre */
2360
+ if (pasp->tjd != 0)
2361
+ pasp->tjd_pre = 0;
2362
+ pasp->tjd = pevd->tjd;
2363
+ /* write database */
2364
+ if (fseek(fpout, 0, SEEK_END) != 0) {
2365
+ strcpy(serr, "error in fseek (1)");
2366
+ return ERR;
2367
+ }
2368
+ fwrite((char *) &(pasp->tjd), sizeof(double), 1, fpout);
2369
+ fwrite((char *) &(pevd->ipla), sizeof(int32), 1, fpout);
2370
+ fwrite((char *) &(pevd->iplb), sizeof(int32), 1, fpout);
2371
+ fwrite((char *) &(pevd->iasp), sizeof(int32), 1, fpout);
2372
+ fwrite((char *) &(pevd->dasp), sizeof(double), 1, fpout);
2373
+ fwrite((char *) &(pevd->dorb), sizeof(double), 1, fpout);
2374
+ fwrite((char *) &(pasp->tjd_pre), sizeof(double), 1, fpout);
2375
+ pasp->fpos_tjd_post = ftell(fpout);
2376
+ fwrite((char *) &(pasp->tjd_post), sizeof(double), 1, fpout);
2377
+ /*fprintf(stderr, "%f: %d - %d ang=%.0f tpre=%f\n", pasp->tjd, pevd->ipla, pevd->iplb, pevd->dasp, pasp->tjd_pre);*/
2378
+ /* entering orb: save tjd_pre */
2379
+ } else if (pasp->tjd == 0) {
2380
+ pasp->tjd_pre = pevd->tjd;
2381
+ /* leaving orb */
2382
+ } else {
2383
+ /* write database: tjd_post */
2384
+ if (fseek(fpout, pasp->fpos_tjd_post, SEEK_SET) != 0) {
2385
+ strcpy(serr, "error in fseek (1)");
2386
+ return ERR;
2387
+ }
2388
+ fwrite((char *) &(pevd->tjd), sizeof(double), 1, fpout);
2389
+ /* after writing database, init aspdat */
2390
+ pasp->iasp = -1;
2391
+ pasp->tjd = 0;
2392
+ pasp->tjd_pre = 0;
2393
+ }
2394
+ }
2395
+ }
2396
+ fclose(fpout);
2397
+ read_sweasp_dat(foutnam);
2398
+ //if (get_crossings(iflag, t, tstep, ipl1, ipl2, x1, x2, sasp, pev, serr) == ERR)
2399
+ return OK;
2400
+ }
2401
+
2402
+ static int do_fread_double(FILE *fpout, char *foutnam, int32 fposbeg, double *tjdbeg, char *serr)
2403
+ {
2404
+ if (fseek(fpout, fposbeg, SEEK_SET) != 0) {
2405
+ sprintf(serr, "fseek failed (SEEK_SET): %s", foutnam);
2406
+ return ERR;
2407
+ }
2408
+ if (fread((void *) tjdbeg, sizeof(double), 1, fpout) <= 0) {
2409
+ sprintf(serr, "error while trying to read %s (1)", foutnam);
2410
+ return ERR;
2411
+ }
2412
+ return OK;
2413
+ }
2414
+
2415
+ static int do_fread_asp(FILE *fpout, int32 fpos1, double *tjd_ex, int *ipla, int *iplb, int *iasp, double *dasp, double *dorb, double *tjd_pre, double *tjd_post, char *serr)
2416
+ {
2417
+ if (fseek(fpout, fpos1, SEEK_SET) != 0) {
2418
+ sprintf(serr, "do_fread_asp(): fseek failed (SEEK_SET)");
2419
+ return ERR;
2420
+ }
2421
+ if (fread((void *) tjd_ex, sizeof(double), 1, fpout) <= 0) {
2422
+ sprintf(serr, "do_fread_asp(): error while trying to read");
2423
+ return ERR;
2424
+ }
2425
+ if (fread((void *) ipla, sizeof(int), 1, fpout) <= 0) {
2426
+ sprintf(serr, "do_fread_asp(): error while trying to read");
2427
+ return ERR;
2428
+ }
2429
+ if (fread((void *) iplb, sizeof(int), 1, fpout) <= 0) {
2430
+ sprintf(serr, "do_fread_asp(): error while trying to read");
2431
+ return ERR;
2432
+ }
2433
+ if (fread((void *) iasp, sizeof(int), 1, fpout) <= 0) {
2434
+ sprintf(serr, "do_fread_asp(): error while trying to read");
2435
+ return ERR;
2436
+ }
2437
+ if (fread((void *) dasp, sizeof(double), 1, fpout) <= 0) {
2438
+ sprintf(serr, "do_fread_asp(): error while trying to read");
2439
+ return ERR;
2440
+ }
2441
+ if (fread((void *) dorb, sizeof(double), 1, fpout) <= 0) {
2442
+ sprintf(serr, "do_fread_asp(): error while trying to read");
2443
+ return ERR;
2444
+ }
2445
+ if (fread((void *) tjd_pre, sizeof(double), 1, fpout) <= 0) {
2446
+ sprintf(serr, "do_fread_asp(): error while trying to read");
2447
+ return ERR;
2448
+ }
2449
+ if (fread((void *) tjd_post, sizeof(double), 1, fpout) <= 0) {
2450
+ sprintf(serr, "do_fread_asp(): error while trying to read");
2451
+ return ERR;
2452
+ }
2453
+ return OK;
2454
+ }
2455
+
2456
+ static int start_and_end_date_sweasp(FILE *fpout, char *foutnam, int32 fposbeg, int32 fposlast, double *tjdbeg, double *tjdend, char *serr)
2457
+ {
2458
+ if (do_fread_double(fpout, foutnam, fposbeg, tjdbeg, serr) == ERR)
2459
+ return ERR;
2460
+ if (do_fread_double(fpout, foutnam, fposlast, tjdend, serr) == ERR)
2461
+ return ERR;
2462
+ return OK;
2463
+ }
2464
+
2465
+ static int is_node_apsis(int ipl)
2466
+ {
2467
+ if (ipl == SE_MEAN_NODE || ipl == SE_TRUE_NODE
2468
+ || ipl == SE_MEAN_APOG || ipl == SE_OSCU_APOG
2469
+ || ipl == SE_INTP_APOG || ipl == SE_INTP_PERG)
2470
+ return 1;
2471
+ return 0;
2472
+ }
2473
+
2474
+ #define SWEASP_DAT_RECLEN 52
2475
+ #define PERIOD_PRE_POST 365 /* days */
2476
+ /* returns all aspects, that are within orb during the time (tjd +- dtol) */
2477
+ static int32 extract_data_of_day(int32 doflag, double tjd, double dtol, char *splan, char *sasp, EVENT *pev, char *serr)
2478
+ {
2479
+ int32 flen = 0, headerlen = 0, fposfirst = 0, fposlast = 0, nrecdif;
2480
+ int32 fpos0, fpos1, fpos2;
2481
+ int32 retc, nrec = 0, ipla, iplb, iasp;
2482
+ double dasp, dorb, dorb2, tjd_pre, tjd_post, tjd_ex, tjdstart;
2483
+ double tjd0, tjd1, tjd2;
2484
+ int ipla2, iplb2, iasp2;
2485
+ double tjd_pre2, tjd_post2, tjd_ex2;
2486
+ double tjdbeg, tjdend;
2487
+ char s[AS_MAXCH], *sp;
2488
+ FILE *fpout = NULL;
2489
+ char foutnam[AS_MAXCH];
2490
+ UNUSED(tjd2);
2491
+ /* open aspects file */
2492
+ sprintf(foutnam, "%s/%s", PATH_FOUTNAM, FOUTNAM);
2493
+ if ((fpout = fopen(foutnam, BFILE_R_ACCESS)) == NULL) {
2494
+ sprintf(serr, "could not open file %s", foutnam);
2495
+ return ERR;
2496
+ }
2497
+ /* read file header */
2498
+ while (fgets(s, AS_MAXCH, fpout) != NULL && (sp = strchr(s, '\n')) != NULL) {
2499
+ headerlen += strlen(s);
2500
+ if (strncmp(s, "####", 4) == 0)
2501
+ break;
2502
+ }
2503
+ /* start position of file */
2504
+ fposfirst = headerlen;
2505
+ /* end position of file */
2506
+ if (fseek(fpout, 0L, SEEK_END) != 0) {
2507
+ sprintf(serr, "fseek failed (SEEK_END): %s", foutnam);
2508
+ return ERR;
2509
+ }
2510
+ fposlast = ftell(fpout); /* pointer to end of file */
2511
+ flen = fposlast - headerlen;
2512
+ /* number of records in file */
2513
+ nrec = flen / SWEASP_DAT_RECLEN;
2514
+ fposlast = fposfirst + (nrec - 1) * SWEASP_DAT_RECLEN; /* pointer to last record in file */
2515
+ /* is search date in file range ? */
2516
+ if ((retc = start_and_end_date_sweasp(fpout, foutnam, fposfirst, fposlast, &tjdbeg, &tjdend, serr)) == ERR)
2517
+ goto end_extract;
2518
+ if (tjd <= tjdbeg || tjd >= tjdend) {
2519
+ sprintf(serr, "date %f is beyond range of file %s (%.0f - %.0f)", tjd, foutnam, tjdbeg, tjdend);
2520
+ return ERR;
2521
+ goto end_extract;
2522
+ }
2523
+ /* binary search for date in file */
2524
+ tjdstart = tjd - PERIOD_PRE_POST; /* we start our search a year before the date we want */
2525
+ if (tjdstart < tjdbeg)
2526
+ tjdstart = tjdbeg;
2527
+ nrecdif = (fposlast - fposfirst) / SWEASP_DAT_RECLEN;
2528
+ tjd0 = tjdbeg; tjd2 = tjdend; tjd1 = tjd0;
2529
+ fpos0 = fposfirst; fpos2 = fposlast;
2530
+ fpos1 = fpos0; // silence compiler
2531
+ while(fabs(tjdstart - tjd1) > 2) {
2532
+ fpos1 = fpos0 + (nrecdif / 2) * SWEASP_DAT_RECLEN;
2533
+ if ((retc = do_fread_double(fpout, foutnam, fpos1, &tjd1, serr)) == ERR) {
2534
+ goto end_extract;
2535
+ }
2536
+ if (tjdstart >= tjd1) {
2537
+ tjd0 = tjd1;
2538
+ fpos0 = fpos1;
2539
+ } else {
2540
+ tjd2 = tjd1;
2541
+ fpos2 = fpos1;
2542
+ }
2543
+ nrecdif = (fpos2 - fpos0) / SWEASP_DAT_RECLEN;
2544
+ }
2545
+ /*fprintf(stderr, "ts = %.0f, t0 = %.0f, t1 = %.0f, t2 = %.0f, d = %d\n", tjdstart, tjd0, tjd1, tjd2, nrecdif);*/
2546
+ /* now, from this date we start searching for aspects whose period covers
2547
+ * or overlaps with our date tjd +- dtol */
2548
+ if ((retc = do_fread_asp(fpout, fpos1, &tjd_ex, &ipla, &iplb, &iasp, &dasp, &dorb, &tjd_pre, &tjd_post, serr)) == ERR)
2549
+ goto end_extract;
2550
+ while(tjd_ex < tjd + PERIOD_PRE_POST) {
2551
+ /*if (ipla == 8 && iplb == 11) {
2552
+ fprintf(stderr, "hallo\n");
2553
+ }*/
2554
+ if (ipla <= SE_CHIRON && iplb <= SE_CHIRON && ipla >= 0 && iplb >= 0 && iasp < 8) {
2555
+ /* complete aspect with tjd_pre and tjd_post */
2556
+ if (tjd_pre > 0 && tjd_post > 0) {
2557
+ /* within time range */
2558
+ if (tjd_post >= tjd - dtol && tjd_pre <= tjd + dtol) {
2559
+ fprintf(stderr, "tjd_ex=%.1f, tjd_pre=%.1f, tjd_post=%.1f, %d, %d, %.0f %d\n", tjd_ex, tjd_pre, tjd_post, ipla, iplb, dasp, iasp);
2560
+ }
2561
+ /* aspect between nodes and aspides (no tjd_pre and tjd_post) */
2562
+ } else if (is_node_apsis(ipla) && is_node_apsis(iplb)) {
2563
+ /* exactness is within time range */
2564
+ if (tjd_ex >= tjd - dtol && tjd_ex <= tjd + dtol) {
2565
+ fprintf(stderr, "tjd_ex=%.1f, tjd_pre=%.1f, tjd_post=%.1f, %d, %d, %.0f %d\n", tjd_ex, tjd_pre, tjd_post, ipla, iplb, dasp, iasp);
2566
+ }
2567
+ /* aspect is in process already at the beginning of search period,
2568
+ * too far away from the required date range */
2569
+ } else if (tjd_pre == 0) {
2570
+ ;
2571
+ /* aspect begins after end of required date range */
2572
+ } else if (tjd + dtol < tjd_pre) {
2573
+ ;
2574
+ /* aspect with unknown end, possibly covering our required date range.
2575
+ * we search for its end */
2576
+ } else {
2577
+ AS_BOOL do_output = FALSE;
2578
+ if (tjd_ex > tjd - dtol) {
2579
+ do_output = TRUE;
2580
+ fprintf(stderr, "xxtjd_ex=%.1f, tjd_pre=%.1f, tjd_post=%.1f, %d, %d, %.0f %d\n", tjd_ex, tjd_pre, tjd_post, ipla, iplb, dasp, iasp);
2581
+ }
2582
+ fpos2 = fpos1;
2583
+ tjd_ex2 = tjd_ex;
2584
+ while(tjd_ex2 < tjd + PERIOD_PRE_POST && fpos2 < fposlast) {
2585
+ fpos2 += SWEASP_DAT_RECLEN;
2586
+ if ((retc = do_fread_asp(fpout, fpos2, &tjd_ex2, &ipla2, &iplb2, &iasp2, &dasp, &dorb2, &tjd_pre2, &tjd_post2, serr)) == ERR)
2587
+ goto end_extract;
2588
+ if (ipla == ipla2 && iplb == iplb2 && iasp == iasp2) {
2589
+ fprintf(stderr, "yytjd_ex=%.1f, tjd_pre=%.1f, tjd_post=%.1f, %d, %d, %.0f\n", tjd_ex2, tjd_pre2, tjd_post2, ipla2, iplb2, dasp);
2590
+ fprintf(stderr, "yytjd_ex=%.1f, tjd_pre=%.1f, tjd_post=%.1f, %d, %d, %.0f %d\n", tjd_ex2, tjd_pre2, tjd_post2, ipla2, iplb2, dasp, iasp);
2591
+ /* if previous phases had no exactness, but the current one has
2592
+ * or is exacter, take over its time of exactness */
2593
+ if (fabs(dorb2) < fabs(dorb)) {
2594
+ dorb = dorb2;
2595
+ tjd_ex = tjd_ex2;
2596
+ }
2597
+ /* if there are several exactnesses, select the one closest
2598
+ * to the required date */
2599
+ if (dorb2 == 0 && fabs(tjd_ex2 - tjd) < fabs(tjd_ex - tjd)) {
2600
+ tjd_ex = tjd_ex2;
2601
+ dorb = 0;
2602
+ }
2603
+ if (tjd_post2 > tjd - dtol) {
2604
+ do_output = TRUE;
2605
+ tjd_post = tjd_post2;
2606
+ }
2607
+ if (tjd_post2 > 0) /* there is no future exactness after that */
2608
+ break;
2609
+ }
2610
+ }
2611
+ if (do_output)
2612
+ fprintf(stderr, "xxtjd_ex=%.1f, tjd_pre=%.1f, tjd_post=%.1f, %d, %d, %.0f %d\n", tjd_ex, tjd_pre, tjd_post, ipla, iplb, dasp, iasp);
2613
+ }
2614
+
2615
+ }
2616
+ fpos1 += SWEASP_DAT_RECLEN;
2617
+ if ((retc = do_fread_asp(fpout, fpos1, &tjd_ex, &ipla, &iplb, &iasp, &dasp, &dorb, &tjd_pre, &tjd_post, serr)) == ERR)
2618
+ goto end_extract;
2619
+ }
2620
+ end_extract:
2621
+ fclose(fpout);
2622
+ if (retc == ERR)
2623
+ fprintf(stderr, serr);
2624
+ return retc;
2625
+ }
2626
+
2627
+ int32 calc_all_crossings(
2628
+ int32 iflag, /* swiss ephemeris flags */
2629
+ int32 itype, /* type of calculation:
2630
+ * 0 = mundane aspects,
2631
+ * 1 = transits,
2632
+ * 2 = ingresses */
2633
+ double tjd0, /* start time */
2634
+ double tjde, /* end time */
2635
+ double tstep, /* time step width */
2636
+ char *splan, /* moving planets' string */
2637
+ char *sasp, /* aspects string */
2638
+ int32 npos, /* with ityp=1, number of transit positions */
2639
+ double *dpos, /* transit/ingress positions */
2640
+ EVENT *pev, /* struct for output */
2641
+ char *serr /* error string */
2642
+ )
2643
+ {
2644
+ switch (itype) {
2645
+ case 0:
2646
+ if (tstep == 0)
2647
+ tstep = 1;
2648
+ if (calc_mundane_aspects(SEFLG_SWIEPH|SEFLG_NONUT, tjd0, tjde, tstep, splan, sasp, pev, serr) == ERR)
2649
+ return ERR;
2650
+ break;
2651
+ }
2652
+ return OK;
2653
+ }
2654
+
2655
+ static char get_casp(double dasp)
2656
+ {
2657
+ if (dasp == 0) return ((char) 1);
2658
+ if (dasp == 180) return ((char) 2);
2659
+ if (dasp == 90) return ((char) 3);
2660
+ if (dasp == 270) return ((char) 3);
2661
+ if (dasp == 120) return ((char) 4);
2662
+ if (dasp == 240) return ((char) 4);
2663
+ if (dasp == 60) return ((char) 5);
2664
+ if (dasp == 300) return ((char) 5);
2665
+ return ((char) 0);
2666
+ }
2667
+
2668
+ static int32 get_prev_lunasp(double t0, int32 ipl, int32 iflag, double *tret, double *dasp, int32 *isign, char *serr)
2669
+ {
2670
+ double xx[6], xm[6], dang, dx, t, mspeed;
2671
+ int nsign;
2672
+ if (swe_calc(t0, SE_MOON, iflag, xm, serr) == ERR)
2673
+ return ERR;
2674
+ if (swe_calc(t0, ipl, iflag, xx, serr) == ERR)
2675
+ return ERR;
2676
+ nsign = 0;
2677
+ dx = swe_degnorm(xm[0] - xx[0]);
2678
+ nsign = (int) (dx / 30);
2679
+ /* ignore semisextiles and inconjuncts */
2680
+ if (nsign == 1 || nsign == 5 || nsign == 7 || nsign == 11)
2681
+ nsign--;
2682
+ dang = nsign * 30;
2683
+ dx -= dang;
2684
+ /* lunar speed roughly */
2685
+ mspeed = xm[3] - xx[3];
2686
+ if (iflag & SEFLG_TOPOCTR)
2687
+ mspeed = 13 - xx[3];
2688
+ t = t0 - dx / mspeed;
2689
+ while (fabs(dx) > 1e-5) {
2690
+ if (swe_calc(t, SE_MOON, iflag, xm, serr) == ERR)
2691
+ return ERR;
2692
+ if (swe_calc(t, ipl, iflag, xx, serr) == ERR)
2693
+ return ERR;
2694
+ dx = swe_degnorm(xm[0] - xx[0] - dang);
2695
+ if (dx > 180)
2696
+ dx -= 360;
2697
+ t -= dx / mspeed;
2698
+ }
2699
+ *dasp = (double) ((int) (dang + 0.5));
2700
+ *tret = t;
2701
+ *isign = (int) (xm[0] / 30);
2702
+ return OK;
2703
+ }
2704
+
2705
+ static int32 get_sign_ingress_direct_body(double tet0, int32 ipl, int32 iflag, int32 backward, double *tret, int32 *isign, char *serr)
2706
+ {
2707
+ double xx[6], xingr, dx, mspeed, t;
2708
+ iflag |= SEFLG_SPEED;
2709
+ if (swe_calc(tet0, ipl, iflag, xx, serr) == ERR)
2710
+ return ERR;
2711
+ *isign = (int) (xx[0] / 30);
2712
+ /* if (!backward) {*/
2713
+ if (ipl != SE_MEAN_NODE)
2714
+ (*isign) ++;
2715
+ if (*isign == 12)
2716
+ *isign = 0;
2717
+ if (*isign == -1)
2718
+ * isign = 11;
2719
+ /* }*/
2720
+ xingr = *isign * 30;
2721
+ dx = swe_difdeg2n(xingr, xx[0]);
2722
+ t = tet0;
2723
+ /* body's speed roughly */
2724
+ mspeed = xx[3];
2725
+ if (ipl == SE_MOON && (iflag & SEFLG_TOPOCTR))
2726
+ mspeed = 13;
2727
+ while(fabs(dx) > 1e-6) {
2728
+ t += dx / mspeed;
2729
+ if (swe_calc(t, ipl, iflag, xx, serr) == ERR)
2730
+ return ERR;
2731
+ dx = swe_difdeg2n(xingr, xx[0]);
2732
+ }
2733
+ *tret = t;
2734
+ return OK;
2735
+ }
2736
+
2737
+ /*
2738
+ Lunar void-of-course phases
2739
+ ===========================
2740
+
2741
+ Definition:
2742
+ Last lunar aspect (COQTS) to a planet (0-9) before a lunar ingress.
2743
+
2744
+ Problem:
2745
+ It happens that a the moon does not form ANY aspects with planets while
2746
+ crossing a sign.
2747
+ The Rosicrucian Ephemeris lists the following case for March 1965:
2748
+ Last aspect Lunar ingress
2749
+ Day h m Day h m
2750
+ 4 1:35 4 18:45
2751
+ 4 1:35 7 1:50
2752
+
2753
+ Method 1 (-v1):
2754
+ A VOC phase can start before the last sign ingress, and it can last longer
2755
+ than a sign transit. There are less VOC phases than ingresses. The output
2756
+ contains a line per VOC phase, but not a line per ingress.
2757
+ For a given time t:
2758
+ - calculate the next lunar ingress (ti_next)
2759
+ - calculate the next lunar ingress after ti_next (ti_nextnext)
2760
+ - set tvoc_start = 0, tvoc_end = ti_nextnext
2761
+ - calculate the last aspect before tvoc_end (ta_last)
2762
+ as soon as an aspect later than ti_next is found,
2763
+ set tvoc_end = ti_next; break the search and repeat it
2764
+ - set tvoc_start = ta_last
2765
+
2766
+ Method 2 (-v2):
2767
+ A VOC phase can start before the last sign ingress, and it can last longer
2768
+ than a sign transit. But a line is printed for each ingress, and two
2769
+ ingresses can have the same start date for their VOC phases.
2770
+ (Output is as in Ros. Eph., e.g. for 4-mar-1965)
2771
+ - calculate the next lunar ingress (ti_next)
2772
+ - set tvoc_start = 0, tvoc_end = ti_next
2773
+ - calculate the last aspect before tvoc_end (ta_last)
2774
+ - set tvoc_start = ta_last
2775
+
2776
+ Method 3 (-v3, default):
2777
+ A VOC phase cannot start before the last sign ingress, i.e. a VOC phase
2778
+ can start at a sign ingress and end at the next sign ingress.
2779
+ the two VOC phases remain separate, a VOC phase may start at ingress
2780
+ - same procedure as solution 2
2781
+ but after that:
2782
+ - calculate previous lunar ingress (ti_prev)
2783
+ - if ta_last < ti_prev, then ta_last = ti_prev
2784
+ */
2785
+ static int32 get_next_voc(double tet0, int32 iflag, int32 vocmethod, VOC *pvoc, char *serr)
2786
+ {
2787
+ int32 retc;
2788
+ double tet_asp, daspi, tvoc_end, tingr_save;
2789
+ double tret[2], dasp;
2790
+ int32 ipl, ipllast;
2791
+ int32 isign, isigni, isign_save;
2792
+ int32 isign_ingr;
2793
+ if (vocmethod == 0) vocmethod = 3;
2794
+ /* next ingress */
2795
+ if ((retc = get_sign_ingress_direct_body(tet0, SE_MOON, iflag, 0, &(tret[1]), &isign, serr)) == ERR)
2796
+ return retc;
2797
+ isign_save = isign;
2798
+ tingr_save = tret[1];
2799
+ tvoc_end = tret[1];
2800
+ /* overnext ingress */
2801
+ if (vocmethod == 1 && (retc = get_sign_ingress_direct_body(tret[1] + 1, SE_MOON, iflag, 0, &tvoc_end, &isign, serr)) == ERR)
2802
+ return retc;
2803
+ isign_ingr = isign;
2804
+ /* find the last aspect with a planet within this time range */
2805
+ tret[0] = 0;
2806
+ repeat_loop:
2807
+ for (ipl = SE_SUN; ipl <= SE_PLUTO; ipl++) {
2808
+ if (ipl == SE_MOON)
2809
+ continue;
2810
+ if ((retc = get_prev_lunasp(tvoc_end, ipl, iflag, &tet_asp, &daspi, &isigni, serr)) == ERR)
2811
+ return retc;
2812
+ if (vocmethod == 1 && tet_asp > tret[1]) {
2813
+ tvoc_end = tret[1];
2814
+ isign_ingr--;
2815
+ if (isign_ingr < 0) isign_ingr = 11;
2816
+ goto repeat_loop;
2817
+ }
2818
+ if (tet_asp > tret[0]) {
2819
+ tret[0] = tet_asp;
2820
+ dasp = daspi;
2821
+ ipllast = ipl;
2822
+ isign = isigni;
2823
+ }
2824
+ }
2825
+ tret[1] = tvoc_end;
2826
+ if (vocmethod == 3) {
2827
+ double tingr_prev;
2828
+ /* get previous lunar ingress */
2829
+ if ((retc = get_sign_ingress_direct_body(tet0, SE_MOON, iflag, 1, &tingr_prev, &isign, serr)) == ERR)
2830
+ return retc;
2831
+ if (tret[0] < tingr_prev)
2832
+ tret[0] = tingr_prev;
2833
+ }
2834
+ pvoc->tvoc = tret[0];
2835
+ pvoc->tingr = tret[1];
2836
+ pvoc->casp = get_casp(dasp);
2837
+ pvoc->cpl = (char) ipllast;
2838
+ pvoc->isign_voc = isign;
2839
+ pvoc->isign_ingr = isign_ingr;
2840
+ if (isign_save == isign_ingr) {
2841
+ pvoc->tingr0 = 0;
2842
+ pvoc->isign_ingr0 = 0;
2843
+ } else {
2844
+ pvoc->tingr0 = tingr_save;
2845
+ pvoc->isign_ingr0 = isign_save;
2846
+ }
2847
+ return OK;
2848
+ }
2849
+
2850
+ static int32 calc_all_voc(int32 iflag, double te, double tend, char *serr)
2851
+ {
2852
+ double t, tnext;
2853
+ int jday, jmon, jyear, gregflag = SE_GREG_CAL;
2854
+ double jut;
2855
+ /* int32 ctyp = CTYP_VOC; */
2856
+ int32 retc;
2857
+ VOC dvoc;
2858
+ /* moon void of course */
2859
+ for (t = te; t < tend; t = tnext) {
2860
+ retc = get_next_voc(t, SEFLG_SPEED, 1, &dvoc, serr);
2861
+ if (retc == ERR) {
2862
+ printf("%s\n", serr);
2863
+ return ERR;
2864
+ }
2865
+ /* content of dvoc:
2866
+ * double tvoc; : time of begin of voc phase
2867
+ * double tingr; : time of ingress that ends voc phase
2868
+ * double tingr0; : time of first ingress, if there are two ingresses
2869
+ * during voc phase
2870
+ * char casp, cpl; : aspect and planet that marks begin of voc phase
2871
+ * int isign_voc; : sign in which moon begins voc phase
2872
+ * int isign_ingr; : sign of ingress that ends voc phase
2873
+ * int isign_ingr0;: sign of first ingress, if there are two ingresses
2874
+ * during voc phase
2875
+ */
2876
+ swe_revjul(dvoc.tvoc, gregflag, &jyear, &jmon, &jday, &jut);
2877
+ printf("VOCBEG: %d.%d.%d, %f, %d -> ", jday, jmon, jyear, jut, dvoc.isign_voc);
2878
+ swe_revjul(dvoc.tingr, gregflag, &jyear, &jmon, &jday, &jut);
2879
+ printf("VOCEND: %d.%d.%d, %f, %d \n", jday, jmon, jyear, jut, dvoc.isign_ingr);
2880
+ if (dvoc.tingr0 != 0) {
2881
+ swe_revjul(dvoc.tingr0, gregflag, &jyear, &jmon, &jday, &jut);
2882
+ printf(" -> VOCEND0: %d.%d.%d, %f, %d \n", jday, jmon, jyear, jut, dvoc.isign_ingr0);
2883
+ }
2884
+ tnext = dvoc.tingr + 0.1;
2885
+ }
2886
+ return OK;
2887
+ }
2888
+
2889
+ static int letter_to_ipl(int letter)
2890
+ {
2891
+ if (letter >= '0' && letter <= '9')
2892
+ return letter - '0' + SE_SUN;
2893
+ if (letter >= 'A' && letter <= 'I')
2894
+ return letter - 'A' + SE_MEAN_APOG;
2895
+ if (letter >= 'J' && letter <= 'Z')
2896
+ return letter - 'J' + SE_CUPIDO;
2897
+ switch (letter) {
2898
+ case 'm': return SE_MEAN_NODE;
2899
+ case 'c': return SE_INTP_APOG;
2900
+ case 'g': return SE_INTP_PERG;
2901
+ case 'n':
2902
+ case 'o': return SE_ECL_NUT;
2903
+ case 't': return SE_TRUE_NODE;
2904
+ case 'f': return SE_FIXSTAR;
2905
+ case 'w': return SE_WALDEMATH;
2906
+ case 'e': /* swetest: a line of labels */
2907
+ case 'q': /* swetest: delta t */
2908
+ case 's': /* swetest: an asteroid, with number given in -xs[number] */
2909
+ case 'z': /* swetest: a fictitious body, number given in -xz[number] */
2910
+ case 'd': /* swetest: default (main) factors 0123456789mtABC */
2911
+ case 'p': /* swetest: main factors ('d') plus main asteroids DEFGHI */
2912
+ case 'h': /* swetest: fictitious factors JKLMNOPQRSTUVWXYZw */
2913
+ case 'a': /* swetest: all factors, like 'p'+'h' */
2914
+ return -1;
2915
+ }
2916
+ return -2;
2917
+ }
2918
+
2919
+ static char *hms(double x, int32 iflag)
2920
+ {
2921
+ static char s[AS_MAXCH], s2[AS_MAXCH], *sp;
2922
+ char *c = ODEGREE_STRING;
2923
+ x += 0.5 / 36000.0; /* round to 0.1 sec */
2924
+ strcpy(s, dms(x, iflag));
2925
+ sp = strstr(s, c);
2926
+ if (sp != NULL) {
2927
+ *sp = ':';
2928
+ if (strlen(ODEGREE_STRING) > 1)
2929
+ strcpy(s2, sp + strlen(ODEGREE_STRING));
2930
+ strcpy(sp + 1, s2);
2931
+ *(sp + 3) = ':';
2932
+ *(sp + 8) = '\0';
2933
+ }
2934
+ return s;
2935
+ }
2936
+