swe4r 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1727 @@
1
+
2
+ /*******************************************************
3
+ $Header: /home/dieter/sweph/RCS/swehouse.c,v 1.74 2008/06/16 10:07:20 dieter Exp $
4
+ module swehouse.c
5
+ house and (simple) aspect calculation
6
+
7
+ ************************************************************/
8
+ /* Copyright (C) 1997 - 2008 Astrodienst AG, Switzerland. All rights reserved.
9
+
10
+ License conditions
11
+ ------------------
12
+
13
+ This file is part of Swiss Ephemeris.
14
+
15
+ Swiss Ephemeris is distributed with NO WARRANTY OF ANY KIND. No author
16
+ or distributor accepts any responsibility for the consequences of using it,
17
+ or for whether it serves any particular purpose or works at all, unless he
18
+ or she says so in writing.
19
+
20
+ Swiss Ephemeris is made available by its authors under a dual licensing
21
+ system. The software developer, who uses any part of Swiss Ephemeris
22
+ in his or her software, must choose between one of the two license models,
23
+ which are
24
+ a) GNU public license version 2 or later
25
+ b) Swiss Ephemeris Professional License
26
+
27
+ The choice must be made before the software developer distributes software
28
+ containing parts of Swiss Ephemeris to others, and before any public
29
+ service using the developed software is activated.
30
+
31
+ If the developer choses the GNU GPL software license, he or she must fulfill
32
+ the conditions of that license, which includes the obligation to place his
33
+ or her whole software project under the GNU GPL or a compatible license.
34
+ See http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
35
+
36
+ If the developer choses the Swiss Ephemeris Professional license,
37
+ he must follow the instructions as found in http://www.astro.com/swisseph/
38
+ and purchase the Swiss Ephemeris Professional Edition from Astrodienst
39
+ and sign the corresponding license contract.
40
+
41
+ The License grants you the right to use, copy, modify and redistribute
42
+ Swiss Ephemeris, but only under certain conditions described in the License.
43
+ Among other things, the License requires that the copyright notices and
44
+ this notice be preserved on all copies.
45
+
46
+ Authors of the Swiss Ephemeris: Dieter Koch and Alois Treindl
47
+
48
+ The authors of Swiss Ephemeris have no control or influence over any of
49
+ the derived works, i.e. over software or services created by other
50
+ programmers which use Swiss Ephemeris functions.
51
+
52
+ The names of the authors or of the copyright holder (Astrodienst) must not
53
+ be used for promoting any software, product or service which uses or contains
54
+ the Swiss Ephemeris. This copyright notice is the ONLY place where the
55
+ names of the authors can legally appear, except in cases where they have
56
+ given special permission in writing.
57
+
58
+ The trademarks 'Swiss Ephemeris' and 'Swiss Ephemeris inside' may be used
59
+ for promoting such software, products or services.
60
+ */
61
+
62
+ #include "sweodef.h"
63
+ #include "swephexp.h"
64
+ #include "sweph.h"
65
+ #include "swephlib.h"
66
+ #include "swehouse.h"
67
+ #include <string.h>
68
+
69
+ #define MILLIARCSEC (1.0 / 3600000.0)
70
+
71
+ static double Asc1(double, double, double, double);
72
+ static double Asc2(double, double, double, double);
73
+ static int CalcH(
74
+ double th, double fi, double ekl, char hsy,
75
+ int iteration_count, struct houses *hsp );
76
+ static int sidereal_houses_ecl_t0(double tjde,
77
+ double armc,
78
+ double eps,
79
+ double *nutlo,
80
+ double lat,
81
+ int hsys,
82
+ double *cusp,
83
+ double *ascmc);
84
+ static int sidereal_houses_trad(double tjde,
85
+ double armc,
86
+ double eps,
87
+ double nutl,
88
+ double lat,
89
+ int hsys,
90
+ double *cusp,
91
+ double *ascmc);
92
+ static int sidereal_houses_ssypl(double tjde,
93
+ double armc,
94
+ double eps,
95
+ double *nutlo,
96
+ double lat,
97
+ int hsys,
98
+ double *cusp,
99
+ double *ascmc);
100
+
101
+ /* housasp.c
102
+ * cusps are returned in double cusp[13],
103
+ * or cusp[37] with house system 'G'.
104
+ * cusp[1...12] houses 1 - 12
105
+ * additional points are returned in ascmc[10].
106
+ * ascmc[0] = ascendant
107
+ * ascmc[1] = mc
108
+ * ascmc[2] = armc
109
+ * ascmc[3] = vertex
110
+ * ascmc[4] = equasc * "equatorial ascendant" *
111
+ * ascmc[5] = coasc1 * "co-ascendant" (W. Koch) *
112
+ * ascmc[6] = coasc2 * "co-ascendant" (M. Munkasey) *
113
+ * ascmc[7] = polasc * "polar ascendant" (M. Munkasey) *
114
+ */
115
+ int FAR PASCAL_CONV swe_houses(double tjd_ut,
116
+ double geolat,
117
+ double geolon,
118
+ int hsys,
119
+ double *cusp,
120
+ double *ascmc)
121
+ {
122
+ int i, retc = 0;
123
+ double armc, eps, nutlo[2];
124
+ double tjde = tjd_ut + swe_deltat(tjd_ut);
125
+ eps = swi_epsiln(tjde) * RADTODEG;
126
+ swi_nutation(tjde, nutlo);
127
+ for (i = 0; i < 2; i++)
128
+ nutlo[i] *= RADTODEG;
129
+ armc = swe_degnorm(swe_sidtime0(tjd_ut, eps + nutlo[1], nutlo[0]) * 15 + geolon);
130
+ #ifdef TRACE
131
+ swi_open_trace(NULL);
132
+ if (swi_trace_count <= TRACE_COUNT_MAX) {
133
+ if (swi_fp_trace_c != NULL) {
134
+ fputs("\n/*SWE_HOUSES*/\n", swi_fp_trace_c);
135
+ fprintf(swi_fp_trace_c, "#if 0\n");
136
+ fprintf(swi_fp_trace_c, " tjd = %.9f;", tjd_ut);
137
+ fprintf(swi_fp_trace_c, " geolon = %.9f;", geolon);
138
+ fprintf(swi_fp_trace_c, " geolat = %.9f;", geolat);
139
+ fprintf(swi_fp_trace_c, " hsys = %d;\n", hsys);
140
+ fprintf(swi_fp_trace_c, " retc = swe_houses(tjd, geolat, geolon, hsys, cusp, ascmc);\n");
141
+ fprintf(swi_fp_trace_c, " /* swe_houses calls swe_houses_armc as follows: */\n");
142
+ fprintf(swi_fp_trace_c, "#endif\n");
143
+ fflush(swi_fp_trace_c);
144
+ }
145
+ }
146
+ #endif
147
+ retc = swe_houses_armc(armc, geolat, eps + nutlo[1], hsys, cusp, ascmc);
148
+ return retc;
149
+ }
150
+
151
+ /* housasp.c
152
+ * cusps are returned in double cusp[13],
153
+ * or cusp[37] with house system 'G'.
154
+ * cusp[1...12] houses 1 - 12
155
+ * additional points are returned in ascmc[10].
156
+ * ascmc[0] = ascendant
157
+ * ascmc[1] = mc
158
+ * ascmc[2] = armc
159
+ * ascmc[3] = vertex
160
+ * ascmc[4] = equasc * "equatorial ascendant" *
161
+ * ascmc[5] = coasc1 * "co-ascendant" (W. Koch) *
162
+ * ascmc[6] = coasc2 * "co-ascendant" (M. Munkasey) *
163
+ * ascmc[7] = polasc * "polar ascendant" (M. Munkasey) *
164
+ */
165
+ int FAR PASCAL_CONV swe_houses_ex(double tjd_ut,
166
+ int32 iflag,
167
+ double geolat,
168
+ double geolon,
169
+ int hsys,
170
+ double *cusp,
171
+ double *ascmc)
172
+ {
173
+ int i, retc = 0;
174
+ double armc, eps_mean, nutlo[2];
175
+ double tjde = tjd_ut + swe_deltat(tjd_ut);
176
+ struct sid_data *sip = &swed.sidd;
177
+ int ito;
178
+ if (toupper(hsys) == 'G')
179
+ ito = 36;
180
+ else
181
+ ito = 12;
182
+ if ((iflag & SEFLG_SIDEREAL) && !swed.ayana_is_set)
183
+ swe_set_sid_mode(SE_SIDM_FAGAN_BRADLEY, 0, 0);
184
+ eps_mean = swi_epsiln(tjde) * RADTODEG;
185
+ swi_nutation(tjde, nutlo);
186
+ for (i = 0; i < 2; i++)
187
+ nutlo[i] *= RADTODEG;
188
+ #ifdef TRACE
189
+ swi_open_trace(NULL);
190
+ if (swi_trace_count <= TRACE_COUNT_MAX) {
191
+ if (swi_fp_trace_c != NULL) {
192
+ fputs("\n/*SWE_HOUSES_EX*/\n", swi_fp_trace_c);
193
+ fprintf(swi_fp_trace_c, "#if 0\n");
194
+ fprintf(swi_fp_trace_c, " tjd = %.9f;", tjd_ut);
195
+ fprintf(swi_fp_trace_c, " iflag = %d;\n", iflag);
196
+ fprintf(swi_fp_trace_c, " geolon = %.9f;", geolon);
197
+ fprintf(swi_fp_trace_c, " geolat = %.9f;", geolat);
198
+ fprintf(swi_fp_trace_c, " hsys = %d;\n", hsys);
199
+ fprintf(swi_fp_trace_c, " retc = swe_houses_ex(tjd, iflag, geolat, geolon, hsys, cusp, ascmc);\n");
200
+ fprintf(swi_fp_trace_c, " /* swe_houses calls swe_houses_armc as follows: */\n");
201
+ fprintf(swi_fp_trace_c, "#endif\n");
202
+ fflush(swi_fp_trace_c);
203
+ }
204
+ }
205
+ #endif
206
+ /*houses_to_sidereal(tjde, geolat, hsys, eps, cusp, ascmc, iflag);*/
207
+ armc = swe_degnorm(swe_sidtime0(tjd_ut, eps_mean + nutlo[1], nutlo[0]) * 15 + geolon);
208
+ if (iflag & SEFLG_SIDEREAL) {
209
+ if (sip->sid_mode & SE_SIDBIT_ECL_T0)
210
+ retc = sidereal_houses_ecl_t0(tjde, armc, eps_mean + nutlo[1], nutlo, geolat, hsys, cusp, ascmc);
211
+ else if (sip->sid_mode & SE_SIDBIT_SSY_PLANE)
212
+ retc = sidereal_houses_ssypl(tjde, armc, eps_mean + nutlo[1], nutlo, geolat, hsys, cusp, ascmc);
213
+ else
214
+ retc = sidereal_houses_trad(tjde, armc, eps_mean + nutlo[1], nutlo[0], geolat, hsys, cusp, ascmc);
215
+ } else {
216
+ retc = swe_houses_armc(armc, geolat, eps_mean + nutlo[1], hsys, cusp, ascmc);
217
+ }
218
+ if (iflag & SEFLG_RADIANS) {
219
+ for (i = 1; i <= ito; i++)
220
+ cusp[i] *= DEGTORAD;
221
+ for (i = 0; i < SE_NASCMC; i++)
222
+ ascmc[i] *= DEGTORAD;
223
+ }
224
+ return retc;
225
+ }
226
+
227
+ /*
228
+ * houses to sidereal
229
+ * ------------------
230
+ * there are two methods:
231
+ * a) the traditional one
232
+ * houses are computed tropically, then nutation and the ayanamsa
233
+ * are subtracted.
234
+ * b) the projection on the ecliptic of t0
235
+ * The house computation is then as follows:
236
+ *
237
+ * Be t the birth date and t0 the epoch at which ayanamsa = 0.
238
+ * 1. Compute the angle between the mean ecliptic at t0 and
239
+ * the true equator at t.
240
+ * The intersection point of these two circles we call the
241
+ * "auxiliary vernal point", and the angle between them the
242
+ * "auxiliary obliquity".
243
+ * 2. Compute the distance of the auxiliary vernal point from the
244
+ * vernal point at t. (this is a section on the equator)
245
+ * 3. subtract this value from the armc of t = aux. armc.
246
+ * 4. Compute the axes and houses for this aux. armc and aux. obliquity.
247
+ * 5. Compute the distance between the auxiliary vernal point and the
248
+ * vernal point at t0 (this is the ayanamsa at t, measured on the
249
+ * ecliptic of t0)
250
+ * 6. subtract this distance from all house cusps.
251
+ * 7. subtract ayanamsa_t0 from all house cusps.
252
+ */
253
+ static int sidereal_houses_ecl_t0(double tjde,
254
+ double armc,
255
+ double eps,
256
+ double *nutlo,
257
+ double lat,
258
+ int hsys,
259
+ double *cusp,
260
+ double *ascmc)
261
+ {
262
+ int i, j, retc = OK;
263
+ double x[6], xvpx[6], x2[6], epst0, xnorm[6];
264
+ double rxy, rxyz, c2, epsx, sgn, fac, dvpx, dvpxe;
265
+ double armcx;
266
+ struct sid_data *sip = &swed.sidd;
267
+ int ito;
268
+ if (toupper(hsys) == 'G')
269
+ ito = 36;
270
+ else
271
+ ito = 12;
272
+ /* epsilon at t0 */
273
+ epst0 = swi_epsiln(sip->t0);
274
+ /* cartesian coordinates of an imaginary moving body on the
275
+ * the mean ecliptic of t0; we take the vernal point: */
276
+ x[0] = x[4] = 1;
277
+ x[1] = x[2] = x[3] = x[5] = 0;
278
+ /* to equator */
279
+ swi_coortrf(x, x, -epst0);
280
+ swi_coortrf(x+3, x+3, -epst0);
281
+ /* to tjd_et */
282
+ swi_precess(x, sip->t0, J_TO_J2000);
283
+ swi_precess(x, tjde, J2000_TO_J);
284
+ swi_precess(x+3, sip->t0, J_TO_J2000);
285
+ swi_precess(x+3, tjde, J2000_TO_J);
286
+ /* to true equator of tjd_et */
287
+ swi_coortrf(x, x, (eps - nutlo[1]) * DEGTORAD);
288
+ swi_coortrf(x+3, x+3, (eps - nutlo[1]) * DEGTORAD);
289
+ swi_cartpol_sp(x, x);
290
+ x[0] += nutlo[0] * DEGTORAD;
291
+ swi_polcart_sp(x, x);
292
+ swi_coortrf(x, x, -eps * DEGTORAD);
293
+ swi_coortrf(x+3, x+3, -eps * DEGTORAD);
294
+ /* now, we have the moving point precessed to tjd_et.
295
+ * next, we compute the auxiliary epsilon: */
296
+ swi_cross_prod(x, x+3, xnorm);
297
+ rxy = xnorm[0] * xnorm[0] + xnorm[1] * xnorm[1];
298
+ c2 = (rxy + xnorm[2] * xnorm[2]);
299
+ rxyz = sqrt(c2);
300
+ rxy = sqrt(rxy);
301
+ epsx = asin(rxy / rxyz) * RADTODEG; /* 1a */
302
+ /* auxiliary vernal point */
303
+ if (fabs(x[5]) < 1e-15)
304
+ x[5] = 1e-15;
305
+ fac = x[2] / x[5];
306
+ sgn = x[5] / fabs(x[5]);
307
+ for (j = 0; j <= 2; j++)
308
+ xvpx[j] = (x[j] - fac * x[j+3]) * sgn; /* 1b */
309
+ /* distance of the auxiliary vernal point from
310
+ * the zero point at tjd_et (a section on the equator): */
311
+ swi_cartpol(xvpx, x2);
312
+ dvpx = x2[0] * RADTODEG; /* 2 */
313
+ /* auxiliary armc */
314
+ armcx = swe_degnorm(armc - dvpx); /* 3 */
315
+ /* compute axes and houses: */
316
+ retc = swe_houses_armc(armcx, lat, epsx, hsys, cusp, ascmc); /* 4 */
317
+ /* distance between auxiliary vernal point and
318
+ * vernal point of t0 (a section on the sidereal plane) */
319
+ dvpxe = acos(swi_dot_prod_unit(x, xvpx)) * RADTODEG; /* 5 */
320
+ if (tjde < sip->t0)
321
+ dvpxe = -dvpxe;
322
+ for (i = 1; i <= ito; i++) /* 6, 7 */
323
+ cusp[i] = swe_degnorm(cusp[i] - dvpxe - sip->ayan_t0);
324
+ for (i = 0; i <= SE_NASCMC; i++)
325
+ ascmc[i] = swe_degnorm(ascmc[i] - dvpxe - sip->ayan_t0);
326
+ return retc;
327
+ }
328
+
329
+ /*
330
+ * Be t the birth date and t0 the epoch at which ayanamsa = 0.
331
+ * 1. Compute the angle between the solar system rotation plane and
332
+ * the true equator at t.
333
+ * The intersection point of these two circles we call the
334
+ * "auxiliary vernal point", and the angle between them the
335
+ * "auxiliary obliquity".
336
+ * 2. Compute the distance of the auxiliary vernal point from the
337
+ * zero point at t. (this is a section on the equator)
338
+ * 3. subtract this value from the armc of t = aux. armc.
339
+ * 4. Compute the axes and houses for this aux. armc and aux. obliquity.
340
+ * 5. Compute the distance between the auxiliary vernal point at t
341
+ * and the zero point of the solar system plane J2000
342
+ * (a section measured on the solar system plane)
343
+ * 6. subtract this distance from all house cusps.
344
+ * 7. compute the ayanamsa of J2000 on the solar system plane,
345
+ * referred to t0
346
+ * 8. subtract ayanamsa_t0 from all house cusps.
347
+ * 9. subtract ayanamsa_2000 from all house cusps.
348
+ */
349
+ static int sidereal_houses_ssypl(double tjde,
350
+ double armc,
351
+ double eps,
352
+ double *nutlo,
353
+ double lat,
354
+ int hsys,
355
+ double *cusp,
356
+ double *ascmc)
357
+ {
358
+ int i, j, retc = OK;
359
+ double x[6], x0[6], xvpx[6], x2[6], epst0, xnorm[6];
360
+ double rxy, rxyz, c2, epsx, eps2000, sgn, fac, dvpx, dvpxe, x00;
361
+ double armcx;
362
+ struct sid_data *sip = &swed.sidd;
363
+ int ito;
364
+ if (toupper(hsys) == 'G')
365
+ ito = 36;
366
+ else
367
+ ito = 12;
368
+ /* epsilon at t0 */
369
+ epst0 = swi_epsiln(sip->t0);
370
+ eps2000 = swi_epsiln(J2000);
371
+ /* cartesian coordinates of the zero point on the
372
+ * the solar system rotation plane */
373
+ x[0] = x[4] = 1;
374
+ x[1] = x[2] = x[3] = x[5] = 0;
375
+ /* to ecliptic 2000 */
376
+ swi_coortrf(x, x, -SSY_PLANE_INCL);
377
+ swi_coortrf(x+3, x+3, -SSY_PLANE_INCL);
378
+ swi_cartpol_sp(x, x);
379
+ x[0] += SSY_PLANE_NODE_E2000;
380
+ swi_polcart_sp(x, x);
381
+ /* to equator 2000 */
382
+ swi_coortrf(x, x, -eps2000);
383
+ swi_coortrf(x+3, x+3, -eps2000);
384
+ /* to mean equator of t */
385
+ swi_precess(x, tjde, J2000_TO_J);
386
+ swi_precess(x+3, tjde, J2000_TO_J);
387
+ /* to true equator of t */
388
+ swi_coortrf(x, x, (eps - nutlo[1]) * DEGTORAD);
389
+ swi_coortrf(x+3, x+3, (eps - nutlo[1]) * DEGTORAD);
390
+ swi_cartpol_sp(x, x);
391
+ x[0] += nutlo[0] * DEGTORAD;
392
+ swi_polcart_sp(x, x);
393
+ swi_coortrf(x, x, -eps * DEGTORAD);
394
+ swi_coortrf(x+3, x+3, -eps * DEGTORAD);
395
+ /* now, we have the moving point precessed to tjd_et.
396
+ * next, we compute the auxiliary epsilon: */
397
+ swi_cross_prod(x, x+3, xnorm);
398
+ rxy = xnorm[0] * xnorm[0] + xnorm[1] * xnorm[1];
399
+ c2 = (rxy + xnorm[2] * xnorm[2]);
400
+ rxyz = sqrt(c2);
401
+ rxy = sqrt(rxy);
402
+ epsx = asin(rxy / rxyz) * RADTODEG; /* 1a */
403
+ /* auxiliary vernal point */
404
+ if (fabs(x[5]) < 1e-15)
405
+ x[5] = 1e-15;
406
+ fac = x[2] / x[5];
407
+ sgn = x[5] / fabs(x[5]);
408
+ for (j = 0; j <= 2; j++)
409
+ xvpx[j] = (x[j] - fac * x[j+3]) * sgn; /* 1b */
410
+ /* distance of the auxiliary vernal point from
411
+ * mean vernal point at tjd_et (a section on the equator): */
412
+ swi_cartpol(xvpx, x2);
413
+ dvpx = x2[0] * RADTODEG; /* 2 */
414
+ /* auxiliary armc */
415
+ armcx = swe_degnorm(armc - dvpx); /* 3 */
416
+ /* compute axes and houses: */
417
+ retc = swe_houses_armc(armcx, lat, epsx, hsys, cusp, ascmc); /* 4 */
418
+ /* distance between the auxiliary vernal point at t and
419
+ * the sidereal zero point of 2000 at t
420
+ * (a section on the sidereal plane).
421
+ */
422
+ dvpxe = acos(swi_dot_prod_unit(x, xvpx)) * RADTODEG; /* 5 */
423
+ /* (always positive for dates after 5400 bc) */
424
+ dvpxe -= SSY_PLANE_NODE * RADTODEG;
425
+ /* ayanamsa between t0 and J2000, measured on solar system plane: */
426
+ /* position of zero point of t0 */
427
+ x0[0] = 1;
428
+ x0[1] = x0[2] = 0;
429
+ /* zero point of t0 in J2000 system */
430
+ if (sip->t0 != J2000)
431
+ swi_precess(x0, sip->t0, J_TO_J2000);
432
+ /* zero point to ecliptic 2000 */
433
+ swi_coortrf(x0, x0, eps2000);
434
+ /* to solar system plane */
435
+ swi_cartpol(x0, x0);
436
+ x0[0] -= SSY_PLANE_NODE_E2000;
437
+ swi_polcart(x0, x0);
438
+ swi_coortrf(x0, x0, SSY_PLANE_INCL);
439
+ swi_cartpol(x0, x0);
440
+ x0[0] += SSY_PLANE_NODE;
441
+ x00 = x0[0] * RADTODEG; /* 7 */
442
+ for (i = 1; i <= ito; i++) /* 6, 8, 9 */
443
+ cusp[i] = swe_degnorm(cusp[i] - dvpxe - sip->ayan_t0 - x00);
444
+ for (i = 0; i <= SE_NASCMC; i++)
445
+ ascmc[i] = swe_degnorm(ascmc[i] - dvpxe - sip->ayan_t0 - x00);
446
+ return retc;
447
+ }
448
+
449
+ /* common simplified procedure */
450
+ static int sidereal_houses_trad(double tjde,
451
+ double armc,
452
+ double eps,
453
+ double nutl,
454
+ double lat,
455
+ int hsys,
456
+ double *cusp,
457
+ double *ascmc)
458
+ {
459
+ int i, retc = OK;
460
+ double ay;
461
+ int ito;
462
+ int ihs = toupper(hsys);
463
+ int ihs2 = ihs;
464
+ ay = swe_get_ayanamsa(tjde);
465
+ if (ihs == 'G')
466
+ ito = 36;
467
+ else
468
+ ito = 12;
469
+ if (ihs == 'W') /* whole sign houses: treat as 'E' and fix later */
470
+ ihs2 = 'E';
471
+ retc = swe_houses_armc(armc, lat, eps, ihs2, cusp, ascmc);
472
+ for (i = 1; i <= ito; i++) {
473
+ cusp[i] = swe_degnorm(cusp[i] - ay - nutl);
474
+ if (ihs == 'W') /* whole sign houses */
475
+ cusp[i] -= fmod(cusp[i], 30);
476
+ }
477
+ for (i = 0; i < SE_NASCMC; i++) {
478
+ if (i == 2) /* armc */
479
+ continue;
480
+ ascmc[i] = swe_degnorm(ascmc[i] - ay - nutl);
481
+ }
482
+ return retc;
483
+ }
484
+
485
+ /*
486
+ * this function is required for very special computations
487
+ * where no date is given for house calculation,
488
+ * e.g. for composite charts or progressive charts.
489
+ * cusps are returned in double cusp[13],
490
+ * or cusp[37] with house system 'G'.
491
+ * cusp[1...12] houses 1 - 12
492
+ * additional points are returned in ascmc[10].
493
+ * ascmc[0] = ascendant
494
+ * ascmc[1] = mc
495
+ * ascmc[2] = armc
496
+ * ascmc[3] = vertex
497
+ * ascmc[4] = equasc * "equatorial ascendant" *
498
+ * ascmc[5] = coasc1 * "co-ascendant" (W. Koch) *
499
+ * ascmc[6] = coasc2 * "co-ascendant" (M. Munkasey) *
500
+ * ascmc[7] = polasc * "polar ascendant" (M. Munkasey) *
501
+ */
502
+ int FAR PASCAL_CONV swe_houses_armc(
503
+ double armc,
504
+ double geolat,
505
+ double eps,
506
+ int hsys,
507
+ double *cusp,
508
+ double *ascmc)
509
+ {
510
+ struct houses h;
511
+ int i, retc = 0;
512
+ int ito;
513
+ if (toupper(hsys) == 'G')
514
+ ito = 36;
515
+ else
516
+ ito = 12;
517
+ armc = swe_degnorm(armc);
518
+ retc = CalcH(armc,
519
+ geolat,
520
+ eps,
521
+ (char)hsys, 2, &h);
522
+ cusp[0] = 0;
523
+ for (i = 1; i <= ito; i++) {
524
+ cusp[i] = h.cusp[i];
525
+ }
526
+ ascmc[0] = h.ac; /* Asc */
527
+ ascmc[1] = h.mc; /* Mid */
528
+ ascmc[2] = armc;
529
+ ascmc[3] = h.vertex;
530
+ ascmc[4] = h.equasc;
531
+ ascmc[5] = h.coasc1; /* "co-ascendant" (W. Koch) */
532
+ ascmc[6] = h.coasc2; /* "co-ascendant" (M. Munkasey) */
533
+ ascmc[7] = h.polasc; /* "polar ascendant" (M. Munkasey) */
534
+ for (i = SE_NASCMC; i < 10; i++)
535
+ ascmc[i] = 0;
536
+ #ifdef TRACE
537
+ swi_open_trace(NULL);
538
+ if (swi_trace_count <= TRACE_COUNT_MAX) {
539
+ if (swi_fp_trace_c != NULL) {
540
+ fputs("\n/*SWE_HOUSES_ARMC*/\n", swi_fp_trace_c);
541
+ fprintf(swi_fp_trace_c, " armc = %.9f;", armc);
542
+ fprintf(swi_fp_trace_c, " geolat = %.9f;", geolat);
543
+ fprintf(swi_fp_trace_c, " eps = %.9f;", eps);
544
+ fprintf(swi_fp_trace_c, " hsys = %d;\n", hsys);
545
+ fprintf(swi_fp_trace_c, " retc = swe_houses_armc(armc, geolat, eps, hsys, cusp, ascmc);\n");
546
+ fputs(" printf(\"swe_houses_armc: %f\\t%f\\t%f\\t%c\\t\\n\", ", swi_fp_trace_c);
547
+ fputs(" armc, geolat, eps, hsys);\n", swi_fp_trace_c);
548
+ fputs(" printf(\"retc = %d\\n\", retc);\n", swi_fp_trace_c);
549
+ fputs(" printf(\"cusp:\\n\");\n", swi_fp_trace_c);
550
+ fputs(" for (i = 0; i < 12; i++)\n", swi_fp_trace_c);
551
+ fputs(" printf(\" %d\\t%f\\n\", i, cusp[i]);\n", swi_fp_trace_c);
552
+ fputs(" printf(\"ascmc:\\n\");\n", swi_fp_trace_c);
553
+ fputs(" for (i = 0; i < 10; i++)\n", swi_fp_trace_c);
554
+ fputs(" printf(\" %d\\t%f\\n\", i, ascmc[i]);\n", swi_fp_trace_c);
555
+ fflush(swi_fp_trace_c);
556
+ }
557
+ if (swi_fp_trace_out != NULL) {
558
+ fprintf(swi_fp_trace_out, "swe_houses_armc: %f\t%f\t%f\t%c\t\n", armc, geolat, eps, hsys);
559
+ fprintf(swi_fp_trace_out, "retc = %d\n", retc);
560
+ fputs("cusp:\n", swi_fp_trace_out);
561
+ for (i = 0; i < 12; i++)
562
+ fprintf(swi_fp_trace_out, " %d\t%f\n", i, cusp[i]);
563
+ fputs("ascmc:\n", swi_fp_trace_out);
564
+ for (i = 0; i < 10; i++)
565
+ fprintf(swi_fp_trace_out, " %d\t%f\n", i, ascmc[i]);
566
+ fflush(swi_fp_trace_out);
567
+ }
568
+ }
569
+ #endif
570
+ #if 0
571
+ /* for test of swe_house_pos().
572
+ * 1st house will be 0, second 30, etc. */
573
+ for (i = 1; i <=12; i++) {
574
+ double x[6];
575
+ x[0] = cusp[i]; x[1] = 0; x[2] = 1;
576
+ cusp[i] = (swe_house_pos(armc, geolat, eps, hsys, x, NULL) - 1) * 30;
577
+ }
578
+ #endif
579
+ return retc;
580
+ }
581
+
582
+ static int CalcH(
583
+ double th, double fi, double ekl, char hsy,
584
+ int iteration_count, struct houses *hsp )
585
+ /* *********************************************************
586
+ * Arguments: th = sidereal time (angle 0..360 degrees
587
+ * hsy = letter code for house system;
588
+ * A equal
589
+ * E equal
590
+ * B Alcabitius
591
+ * C Campanus
592
+ * H horizon / azimut
593
+ * K Koch
594
+ * O Porphyry
595
+ * P Placidus
596
+ * R Regiomontanus
597
+ * V equal Vehlow
598
+ * W equal, whole sign
599
+ * X axial rotation system/ Meridian houses
600
+ * G 36 Gauquelin sectors
601
+ * U Krusinski-Pisa
602
+ * fi = geographic latitude
603
+ * ekl = obliquity of the ecliptic
604
+ * iteration_count = number of iterations in
605
+ * Placidus calculation; can be 1 or 2.
606
+ * *********************************************************
607
+ * Koch and Placidus don't work in the polar circle.
608
+ * We swap MC/IC so that MC is always before AC in the zodiac
609
+ * We than divide the quadrants into 3 equal parts.
610
+ * *********************************************************
611
+ * All angles are expressed in degrees.
612
+ * Special trigonometric functions sind, cosd etc. are
613
+ * implemented for arguments in degrees.
614
+ ***********************************************************/
615
+ {
616
+ double tane, tanfi, cosfi, tant, sina, cosa, th2;
617
+ double a, c, f, fh1, fh2, xh1, xh2, rectasc, ad3, acmc, vemc;
618
+ int i, ih, ih2, retc = OK;
619
+ double sine, cose;
620
+ double x[3], krHorizonLon; /* BK 14.02.2006 */
621
+ cose = cosd(ekl);
622
+ sine = sind(ekl);
623
+ tane = tand(ekl);
624
+ /* north and south poles */
625
+ if (fabs(fabs(fi) - 90) < VERY_SMALL) {
626
+ if (fi < 0)
627
+ fi = -90 + VERY_SMALL;
628
+ else
629
+ fi = 90 - VERY_SMALL;
630
+ }
631
+ tanfi = tand(fi);
632
+ /* mc */
633
+ if (fabs(th - 90) > VERY_SMALL
634
+ && fabs(th - 270) > VERY_SMALL) {
635
+ tant = tand(th);
636
+ hsp->mc = atand(tant / cose);
637
+ if (th > 90 && th <= 270)
638
+ hsp->mc = swe_degnorm(hsp->mc + 180);
639
+ } else {
640
+ if (fabs(th - 90) <= VERY_SMALL)
641
+ hsp->mc = 90;
642
+ else
643
+ hsp->mc = 270;
644
+ } /* if */
645
+ hsp->mc = swe_degnorm(hsp->mc);
646
+ /* ascendant */
647
+ hsp->ac = Asc1 (th + 90, fi, sine, cose);
648
+ hsp->cusp[1] = hsp->ac;
649
+ hsp->cusp[10] = hsp->mc;
650
+ if (hsy > 95) hsy = (char) (hsy - 32);/* translate into capital letter */
651
+ switch (hsy) {
652
+ case 'A': /* equal houses */
653
+ case 'E':
654
+ /*
655
+ * within polar circle we swap AC/DC if AC is on wrong side
656
+ */
657
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
658
+ if (acmc < 0) {
659
+ hsp->ac = swe_degnorm(hsp->ac + 180);
660
+ hsp->cusp[1] = hsp->ac;
661
+ }
662
+ for (i = 2; i <=12; i++)
663
+ hsp->cusp [i] = swe_degnorm(hsp->cusp [1] + (i-1) * 30);
664
+ break;
665
+ case 'C': /* Campanus houses and Horizon or Azimut system */
666
+ case 'H':
667
+ if (hsy == 'H') {
668
+ if (fi > 0)
669
+ fi = 90 - fi;
670
+ else
671
+ fi = -90 - fi;
672
+ /* equator */
673
+ if (fabs(fabs(fi) - 90) < VERY_SMALL) {
674
+ if (fi < 0)
675
+ fi = -90 + VERY_SMALL;
676
+ else
677
+ fi = 90 - VERY_SMALL;
678
+ }
679
+ th = swe_degnorm(th + 180);
680
+ }
681
+ fh1 = asind(sind (fi) / 2);
682
+ fh2 = asind(sqrt (3.0) / 2 * sind(fi));
683
+ cosfi = cosd(fi);
684
+ if (fabs(cosfi) == 0) { /* '==' should be save! */
685
+ if (fi > 0)
686
+ xh1 = xh2 = 90; /* cosfi = VERY_SMALL; */
687
+ else
688
+ xh1 = xh2 = 270; /* cosfi = -VERY_SMALL; */
689
+ } else {
690
+ xh1 = atand(sqrt (3.0) / cosfi);
691
+ xh2 = atand(1 / sqrt (3.0) / cosfi);
692
+ }
693
+ hsp->cusp [11] = Asc1 (th + 90 - xh1, fh1, sine, cose);
694
+ hsp->cusp [12] = Asc1 (th + 90 - xh2, fh2, sine, cose);
695
+ if (hsy == 'H')
696
+ hsp->cusp [1] = Asc1 (th + 90, fi, sine, cose);
697
+ hsp->cusp [2] = Asc1 (th + 90 + xh2, fh2, sine, cose);
698
+ hsp->cusp [3] = Asc1 (th + 90 + xh1, fh1, sine, cose);
699
+ /* within polar circle, when mc sinks below horizon and
700
+ * ascendant changes to western hemisphere, all cusps
701
+ * must be added 180 degrees.
702
+ * houses will be in clockwise direction */
703
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
704
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
705
+ if (acmc < 0) {
706
+ hsp->ac = swe_degnorm(hsp->ac + 180);
707
+ hsp->mc = swe_degnorm(hsp->mc + 180);
708
+ for (i = 1; i <= 12; i++)
709
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
710
+ }
711
+ }
712
+ if (hsy == 'H') {
713
+ for (i = 1; i <= 3; i++)
714
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
715
+ for (i = 11; i <= 12; i++)
716
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
717
+ /* restore fi and th */
718
+ if (fi > 0)
719
+ fi = 90 - fi;
720
+ else
721
+ fi = -90 - fi;
722
+ th = swe_degnorm(th + 180);
723
+ }
724
+ break;
725
+ case 'K': /* Koch houses */
726
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
727
+ retc = ERR;
728
+ goto porphyry;
729
+ }
730
+ sina = sind(hsp->mc) * sine / cosd(fi);
731
+ if (sina > 1) sina = 1;
732
+ if (sina < -1) sina = -1;
733
+ cosa = sqrt(1 - sina * sina); /* always >> 0 */
734
+ c = atand(tanfi / cosa);
735
+ ad3 = asind(sind(c) * sina) / 3.0;
736
+ hsp->cusp [11] = Asc1 (th + 30 - 2 * ad3, fi, sine, cose);
737
+ hsp->cusp [12] = Asc1 (th + 60 - ad3, fi, sine, cose);
738
+ hsp->cusp [2] = Asc1 (th + 120 + ad3, fi, sine, cose);
739
+ hsp->cusp [3] = Asc1 (th + 150 + 2 * ad3, fi, sine, cose);
740
+ break;
741
+ case 'O': /* Porphyry houses */
742
+ porphyry:
743
+ /*
744
+ * within polar circle we swap AC/DC if AC is on wrong side
745
+ */
746
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
747
+ if (acmc < 0) {
748
+ hsp->ac = swe_degnorm(hsp->ac + 180);
749
+ hsp->cusp[1] = hsp->ac;
750
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
751
+ }
752
+ hsp->cusp [2] = swe_degnorm(hsp->ac + (180 - acmc) / 3);
753
+ hsp->cusp [3] = swe_degnorm(hsp->ac + (180 - acmc) / 3 * 2);
754
+ hsp->cusp [11] = swe_degnorm(hsp->mc + acmc / 3);
755
+ hsp->cusp [12] = swe_degnorm(hsp->mc + acmc / 3 * 2);
756
+ break;
757
+ case 'R': /* Regiomontanus houses */
758
+ fh1 = atand (tanfi * 0.5);
759
+ fh2 = atand (tanfi * cosd(30));
760
+ hsp->cusp [11] = Asc1 (30 + th, fh1, sine, cose);
761
+ hsp->cusp [12] = Asc1 (60 + th, fh2, sine, cose);
762
+ hsp->cusp [2] = Asc1 (120 + th, fh2, sine, cose);
763
+ hsp->cusp [3] = Asc1 (150 + th, fh1, sine, cose);
764
+ /* within polar circle, when mc sinks below horizon and
765
+ * ascendant changes to western hemisphere, all cusps
766
+ * must be added 180 degrees.
767
+ * houses will be in clockwise direction */
768
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
769
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
770
+ if (acmc < 0) {
771
+ hsp->ac = swe_degnorm(hsp->ac + 180);
772
+ hsp->mc = swe_degnorm(hsp->mc + 180);
773
+ for (i = 1; i <= 12; i++)
774
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
775
+ }
776
+ }
777
+ break;
778
+ case 'T': /* 'topocentric' houses */
779
+ fh1 = atand (tanfi / 3.0);
780
+ fh2 = atand (tanfi * 2.0 / 3.0);
781
+ hsp->cusp [11] = Asc1 (30 + th, fh1, sine, cose);
782
+ hsp->cusp [12] = Asc1 (60 + th, fh2, sine, cose);
783
+ hsp->cusp [2] = Asc1 (120 + th, fh2, sine, cose);
784
+ hsp->cusp [3] = Asc1 (150 + th, fh1, sine, cose);
785
+ /* within polar circle, when mc sinks below horizon and
786
+ * ascendant changes to western hemisphere, all cusps
787
+ * must be added 180 degrees.
788
+ * houses will be in clockwise direction */
789
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
790
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
791
+ if (acmc < 0) {
792
+ hsp->ac = swe_degnorm(hsp->ac + 180);
793
+ hsp->mc = swe_degnorm(hsp->mc + 180);
794
+ for (i = 1; i <= 12; i++)
795
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
796
+ }
797
+ }
798
+ break;
799
+ case 'V': /* equal houses after Vehlow */
800
+ /*
801
+ * within polar circle we swap AC/DC if AC is on wrong side
802
+ */
803
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
804
+ if (acmc < 0) {
805
+ hsp->ac = swe_degnorm(hsp->ac + 180);
806
+ hsp->cusp[1] = hsp->ac;
807
+ }
808
+ hsp->cusp [1] = swe_degnorm(hsp->ac - 15);
809
+ for (i = 2; i <=12; i++)
810
+ hsp->cusp [i] = swe_degnorm(hsp->cusp [1] + (i-1) * 30);
811
+ break;
812
+ case 'W': /* equal, whole-sign houses */
813
+ /*
814
+ * within polar circle we swap AC/DC if AC is on wrong side
815
+ */
816
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
817
+ if (acmc < 0) {
818
+ hsp->ac = swe_degnorm(hsp->ac + 180);
819
+ hsp->cusp[1] = hsp->ac;
820
+ }
821
+ hsp->cusp [1] = hsp->ac - fmod(hsp->ac, 30);
822
+ for (i = 2; i <=12; i++)
823
+ hsp->cusp [i] = swe_degnorm(hsp->cusp [1] + (i-1) * 30);
824
+ break;
825
+ case 'X': {
826
+ /*
827
+ * Meridian or axial rotation system:
828
+ * ecliptic points whose rectascensions
829
+ * are armc + n * 30
830
+ */
831
+ int j;
832
+ double a = th;
833
+ for (i = 1; i <= 12; i++) {
834
+ j = i + 10;
835
+ if (j > 12) j -= 12;
836
+ a = swe_degnorm(a + 30);
837
+ if (fabs(a - 90) > VERY_SMALL
838
+ && fabs(a - 270) > VERY_SMALL) {
839
+ tant = tand(a);
840
+ hsp->cusp[j] = atand(tant / cose);
841
+ if (a > 90 && a <= 270)
842
+ hsp->cusp[j] = swe_degnorm(hsp->cusp[j] + 180);
843
+ } else {
844
+ if (fabs(a - 90) <= VERY_SMALL)
845
+ hsp->cusp[j] = 90;
846
+ else
847
+ hsp->cusp[j] = 270;
848
+ } /* if */
849
+ hsp->cusp[j] = swe_degnorm(hsp->cusp[j]);
850
+ }
851
+ break; }
852
+ case 'M': {
853
+ /*
854
+ * Morinus
855
+ * points of the equator (armc + n * 30) are transformed
856
+ * into the ecliptic coordinate system
857
+ */
858
+ int j;
859
+ double a = th;
860
+ double x[3];
861
+ for (i = 1; i <= 12; i++) {
862
+ j = i + 10;
863
+ if (j > 12) j -= 12;
864
+ a = swe_degnorm(a + 30);
865
+ x[0] = a;
866
+ x[1] = 0;
867
+ swe_cotrans(x, x, ekl);
868
+ hsp->cusp[j] = x[0];
869
+ }
870
+ break; }
871
+ case 'B': { /* Alcabitius */
872
+ /* created by Alois 17-sep-2000, followed example in Matrix
873
+ electrical library. The code reproduces the example!
874
+ See http://www.astro.com/cgi/adict.cgi query: alcabitius
875
+ in the resuotl page, see program code example.
876
+ I think the Alcabitius code in Walter Pullen's Astrolog 5.40
877
+ is wrong, because he remains in RA and forgets the transform to
878
+ the ecliptic. */
879
+ double dek, r, sna, sda, sn3, sd3;
880
+ #if FALSE
881
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
882
+ retc = ERR;
883
+ goto porphyry;
884
+ }
885
+ #endif
886
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
887
+ if (acmc < 0) {
888
+ hsp->ac = swe_degnorm(hsp->ac + 180);
889
+ hsp->cusp[1] = hsp->ac;
890
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
891
+ }
892
+ dek = asind(sind(hsp->ac) * sine); /* declination of Ascendant */
893
+ /* must treat the case fi == 90 or -90 */
894
+ r = -tanfi * tand(dek);
895
+ /* must treat the case of abs(r) > 1; probably does not happen
896
+ * because dek becomes smaller when fi is large, as ac is close to
897
+ * zero Aries/Libra in that case.
898
+ */
899
+ sda = acos(r) * RADTODEG; /* semidiurnal arc, measured on equator */
900
+ sna = 180 - sda; /* complement, seminocturnal arc */
901
+ sd3 = sda / 3;
902
+ sn3 = sna / 3;
903
+ rectasc = swe_degnorm(th + sd3); /* cusp 11 */
904
+ /* project rectasc onto eclipitic with pole height 0, i.e. along the
905
+ declination circle */
906
+ hsp->cusp [11] = Asc1 (rectasc, 0, sine, cose);
907
+ rectasc = swe_degnorm(th + 2 * sd3); /* cusp 12 */
908
+ hsp->cusp [12] = Asc1 (rectasc, 0, sine, cose);
909
+ rectasc = swe_degnorm(th + 180 - 2 * sn3); /* cusp 2 */
910
+ hsp->cusp [2] = Asc1 (rectasc, 0, sine, cose);
911
+ rectasc = swe_degnorm(th + 180 - sn3); /* cusp 3 */
912
+ hsp->cusp [3] = Asc1 (rectasc, 0, sine, cose);
913
+ }
914
+ break;
915
+ case 'G': /* 36 Gauquelin sectors */
916
+ for (i = 1; i <= 36; i++) {
917
+ hsp->cusp[i] = 0;
918
+ }
919
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
920
+ retc = ERR;
921
+ goto porphyry;
922
+ }
923
+ /*************** forth/second quarter ***************/
924
+ /* note: Gauquelin sectors are counted in clockwise direction */
925
+ a = asind(tand(fi) * tane);
926
+ for (ih = 2; ih <= 9; ih++) {
927
+ ih2 = 10 - ih;
928
+ fh1 = atand(sind(a * ih2 / 9) / tane);
929
+ rectasc = swe_degnorm((90 / 9) * ih2 + th);
930
+ tant = tand(asind(sine * sind(Asc1 (rectasc, fh1, sine, cose))));
931
+ if (fabs(tant) < VERY_SMALL) {
932
+ hsp->cusp[ih] = rectasc;
933
+ } else {
934
+ /* pole height */
935
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) /tant);
936
+ hsp->cusp [ih] = Asc1 (rectasc, f, sine, cose);
937
+ for (i = 1; i <= iteration_count; i++) {
938
+ tant = tand(asind(sine * sind(hsp->cusp[ih])));
939
+ if (fabs(tant) < VERY_SMALL) {
940
+ hsp->cusp[ih] = rectasc;
941
+ break;
942
+ }
943
+ /* pole height */
944
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant);
945
+ hsp->cusp[ih] = Asc1 (rectasc, f, sine, cose);
946
+ }
947
+ }
948
+ hsp->cusp[ih+18] = swe_degnorm(hsp->cusp[ih] + 180);
949
+ }
950
+ /*************** first/third quarter ***************/
951
+ for (ih = 29; ih <= 36; ih++) {
952
+ ih2 = ih - 28;
953
+ fh1 = atand(sind(a * ih2 / 9) / tane);
954
+ rectasc = swe_degnorm(180 - ih2 * 90 / 9 + th);
955
+ tant = tand(asind(sine * sind(Asc1 (rectasc, fh1, sine, cose))));
956
+ if (fabs(tant) < VERY_SMALL) {
957
+ hsp->cusp[ih] = rectasc;
958
+ } else {
959
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant);
960
+ /* pole height */
961
+ hsp->cusp[ih] = Asc1 (rectasc, f, sine, cose);
962
+ for (i = 1; i <= iteration_count; i++) {
963
+ tant = tand(asind(sine * sind(hsp->cusp[ih])));
964
+ if (fabs(tant) < VERY_SMALL) {
965
+ hsp->cusp[ih] = rectasc;
966
+ break;
967
+ }
968
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant);
969
+ /* pole height */
970
+ hsp->cusp[ih] = Asc1 (rectasc, f, sine, cose);
971
+ }
972
+ }
973
+ hsp->cusp[ih-18] = swe_degnorm(hsp->cusp[ih] + 180);
974
+ }
975
+ hsp->cusp[1] = hsp->ac;
976
+ hsp->cusp[10] = hsp->mc;
977
+ hsp->cusp[19] = swe_degnorm(hsp->ac + 180);
978
+ hsp->cusp[28] = swe_degnorm(hsp->mc + 180);
979
+ break;
980
+ case 'U': /* Krusinski-Pisa */
981
+ /*
982
+ * The following code was written by Bogdan Krusinski in 2006.
983
+ * bogdan@astrologia.pl
984
+ *
985
+ * Definition:
986
+ * "Krusinski - house system based on the great circle passing through
987
+ * ascendant and zenith. This circle is divided into 12 equal parts
988
+ * (1st cusp is ascendent, 10th cusp is zenith), then the resulting
989
+ * points are projected onto the ecliptic through meridian circles.
990
+ * The house cusps in space are half-circles perpendicular to the equator
991
+ * and running from the north to the south celestial pole through the
992
+ * resulting cusp points on the house circle. The points where they
993
+ * cross the ecliptic mark the ecliptic house cusps."
994
+ *
995
+ * Description of the algorithm:
996
+ * Transform into great circle running through Asc and zenit (where arc
997
+ * between Asc and zenith is always 90 deg), and then return with
998
+ * house cusps into ecliptic. Eg. solve trigonometrical triangle
999
+ * with three transformations and two rotations starting from ecliptic.
1000
+ * House cusps in space are meridian circles.
1001
+ *
1002
+ * Notes:
1003
+ * 1. In this definition we assume MC on ecliptic as point where
1004
+ * half-meridian (from north to south pole) cuts ecliptic,
1005
+ * so MC may be below horizon in arctic regions.
1006
+ * 2. Houses could be calculated in all latitudes except the poles
1007
+ * themselves (-90,90) and points on arctic circle in cases where
1008
+ * ecliptic is equal to horizon and then ascendant is undefined.
1009
+ * But ascendant when 'horizon=ecliptic' could be deduced as limes
1010
+ * from both sides of that point and houses with that provision can
1011
+ * be computed also there.
1012
+ *
1013
+ * Starting values for calculations:
1014
+ * - Asc ecliptic longitude
1015
+ * - right ascension of MC (RAMC)
1016
+ * - geographic latitude.
1017
+ */
1018
+ /*
1019
+ * within polar circle we swap AC/DC if AC is on wrong side
1020
+ */
1021
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1022
+ if (acmc < 0) {
1023
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1024
+ }
1025
+ /* A0. Start point - ecliptic coords of ascendant */
1026
+ x[0] = hsp->ac; /* Asc longitude */
1027
+ x[1] = 0.0; /* Asc declination */
1028
+ x[2] = 1.0; /* Radius to test validity of subsequent transformations. */
1029
+ swe_cotrans(x, x, -ekl); /* A1. Transform into equatorial coords */
1030
+ x[0] = x[0] - (th-90); /* A2. Rotate */
1031
+ swe_cotrans(x, x, -(90-fi)); /* A3. Transform into horizontal coords */
1032
+ krHorizonLon = x[0]; /* ...save asc lon on horizon to get back later with house cusp */
1033
+ x[0] = x[0] - x[0]; /* A4. Rotate */
1034
+ swe_cotrans(x, x, -90); /* A5. Transform into this house system great circle (asc-zenith) */
1035
+ /* As it is house circle now, simple add 30 deg increments... */
1036
+ for(i = 0; i < 6; i++) {
1037
+ /* B0. Set 'n-th' house cusp.
1038
+ * Note that IC/MC are also calculated here to check
1039
+ * if really this is the asc-zenith great circle. */
1040
+ x[0] = 30.0*i;
1041
+ x[1] = 0.0;
1042
+ swe_cotrans(x, x, 90); /* B1. Transform back into horizontal coords */
1043
+ x[0] = x[0] + krHorizonLon; /* B2. Rotate back. */
1044
+ swe_cotrans(x, x, 90-fi); /* B3. Transform back into equatorial coords */
1045
+ x[0] = swe_degnorm(x[0] + (th-90)); /* B4. Rotate back -> RA of house cusp as result. */
1046
+ /* B5. Where's this house cusp on ecliptic? */
1047
+ /* ... so last but not least - get ecliptic longitude of house cusp: */
1048
+ hsp->cusp[i+1] = atand(tand(x[0])/cosd(ekl));
1049
+ if (x[0] > 90 && x[0] <= 270)
1050
+ hsp->cusp[i+1] = swe_degnorm(hsp->cusp[i+1] + 180);
1051
+ hsp->cusp[i+1] = swe_degnorm(hsp->cusp[i+1]);
1052
+ hsp->cusp[i+7] = swe_degnorm(hsp->cusp[i+1]+180);
1053
+ }
1054
+ break;
1055
+ default: /* Placidus houses */
1056
+ #ifndef _WINDOWS
1057
+ if (hsy != 'P')
1058
+ fprintf (stderr, "swe_houses: make Placidus, unknown key %c\n", hsy);
1059
+ #endif
1060
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
1061
+ retc = ERR;
1062
+ goto porphyry;
1063
+ }
1064
+ a = asind(tand(fi) * tane);
1065
+ fh1 = atand(sind(a / 3) / tane);
1066
+ fh2 = atand(sind(a * 2 / 3) / tane);
1067
+ /* ************ house 11 ******************** */
1068
+ rectasc = swe_degnorm(30 + th);
1069
+ tant = tand(asind(sine * sind(Asc1 (rectasc, fh1, sine, cose))));
1070
+ if (fabs(tant) < VERY_SMALL) {
1071
+ hsp->cusp [11] = rectasc;
1072
+ } else {
1073
+ /* pole height */
1074
+ f = atand(sind(asind(tanfi * tant) / 3) /tant);
1075
+ hsp->cusp [11] = Asc1 (rectasc, f, sine, cose);
1076
+ for (i = 1; i <= iteration_count; i++) {
1077
+ tant = tand(asind(sine * sind(hsp->cusp [11])));
1078
+ if (fabs(tant) < VERY_SMALL) {
1079
+ hsp->cusp [11] = rectasc;
1080
+ break;
1081
+ }
1082
+ /* pole height */
1083
+ f = atand(sind(asind(tanfi * tant) / 3) / tant);
1084
+ hsp->cusp [11] = Asc1 (rectasc, f, sine, cose);
1085
+ }
1086
+ }
1087
+ /* ************ house 12 ******************** */
1088
+ rectasc = swe_degnorm(60 + th);
1089
+ tant = tand(asind(sine*sind(Asc1 (rectasc, fh2, sine, cose))));
1090
+ if (fabs(tant) < VERY_SMALL) {
1091
+ hsp->cusp [12] = rectasc;
1092
+ } else {
1093
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1094
+ /* pole height */
1095
+ hsp->cusp [12] = Asc1 (rectasc, f, sine, cose);
1096
+ for (i = 1; i <= iteration_count; i++) {
1097
+ tant = tand(asind(sine * sind(hsp->cusp [12])));
1098
+ if (fabs(tant) < VERY_SMALL) {
1099
+ hsp->cusp [12] = rectasc;
1100
+ break;
1101
+ }
1102
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1103
+ /* pole height */
1104
+ hsp->cusp [12] = Asc1 (rectasc, f, sine, cose);
1105
+ }
1106
+ }
1107
+ /* ************ house 2 ******************** */
1108
+ rectasc = swe_degnorm(120 + th);
1109
+ tant = tand(asind(sine * sind(Asc1 (rectasc, fh2, sine, cose))));
1110
+ if (fabs(tant) < VERY_SMALL) {
1111
+ hsp->cusp [2] = rectasc;
1112
+ } else {
1113
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1114
+ /* pole height */
1115
+ hsp->cusp [2] = Asc1 (rectasc, f, sine, cose);
1116
+ for (i = 1; i <= iteration_count; i++) {
1117
+ tant = tand(asind(sine * sind(hsp->cusp [2])));
1118
+ if (fabs(tant) < VERY_SMALL) {
1119
+ hsp->cusp [2] = rectasc;
1120
+ break;
1121
+ }
1122
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1123
+ /* pole height */
1124
+ hsp->cusp [2] = Asc1 (rectasc, f, sine, cose);
1125
+ }
1126
+ }
1127
+ /* ************ house 3 ******************** */
1128
+ rectasc = swe_degnorm(150 + th);
1129
+ tant = tand(asind(sine * sind(Asc1 (rectasc, fh1, sine, cose))));
1130
+ if (fabs(tant) < VERY_SMALL) {
1131
+ hsp->cusp [3] = rectasc;
1132
+ } else {
1133
+ f = atand(sind(asind(tanfi * tant) / 3) / tant);
1134
+ /* pole height */
1135
+ hsp->cusp [3] = Asc1(rectasc, f, sine, cose);
1136
+ for (i = 1; i <= iteration_count; i++) {
1137
+ tant = tand(asind(sine * sind(hsp->cusp [3])));
1138
+ if (fabs(tant) < VERY_SMALL) {
1139
+ hsp->cusp [3] = rectasc;
1140
+ break;
1141
+ }
1142
+ f = atand(sind(asind(tanfi * tant) / 3) / tant);
1143
+ /* pole height */
1144
+ hsp->cusp [3] = Asc1 (rectasc, f, sine, cose);
1145
+ }
1146
+ }
1147
+ break;
1148
+ } /* end switch */
1149
+ if (hsy != 'G') {
1150
+ hsp->cusp [4] = swe_degnorm(hsp->cusp [10] + 180);
1151
+ hsp->cusp [5] = swe_degnorm(hsp->cusp [11] + 180);
1152
+ hsp->cusp [6] = swe_degnorm(hsp->cusp [12] + 180);
1153
+ hsp->cusp [7] = swe_degnorm(hsp->cusp [1] + 180);
1154
+ hsp->cusp [8] = swe_degnorm(hsp->cusp [2] + 180);
1155
+ hsp->cusp [9] = swe_degnorm(hsp->cusp [3] + 180);
1156
+ }
1157
+ /* vertex */
1158
+ if (fi >= 0)
1159
+ f = 90 - fi;
1160
+ else
1161
+ f = -90 - fi;
1162
+ hsp->vertex = Asc1 (th - 90, f, sine, cose);
1163
+ /* with tropical latitudes, the vertex behaves strange,
1164
+ * in a similar way as the ascendant within the polar
1165
+ * circle. we keep it always on the western hemisphere.*/
1166
+ if (fabs(fi) <= ekl) {
1167
+ vemc = swe_difdeg2n(hsp->vertex, hsp->mc);
1168
+ if (vemc > 0)
1169
+ hsp->vertex = swe_degnorm(hsp->vertex + 180);
1170
+ }
1171
+ /*
1172
+ * some strange points:
1173
+ */
1174
+ /* equasc (equatorial ascendant) */
1175
+ th2 = swe_degnorm(th + 90);
1176
+ if (fabs(th2 - 90) > VERY_SMALL
1177
+ && fabs(th2 - 270) > VERY_SMALL) {
1178
+ tant = tand(th2);
1179
+ hsp->equasc = atand(tant / cose);
1180
+ if (th2 > 90 && th2 <= 270)
1181
+ hsp->equasc = swe_degnorm(hsp->equasc + 180);
1182
+ } else {
1183
+ if (fabs(th2 - 90) <= VERY_SMALL)
1184
+ hsp->equasc = 90;
1185
+ else
1186
+ hsp->equasc = 270;
1187
+ } /* if */
1188
+ hsp->equasc = swe_degnorm(hsp->equasc);
1189
+ /* "co-ascendant" W. Koch */
1190
+ hsp->coasc1 = swe_degnorm(Asc1 (th - 90, fi, sine, cose) + 180);
1191
+ /* "co-ascendant" M. Munkasey */
1192
+ if (fi >= 0)
1193
+ hsp->coasc2 = Asc1 (th + 90, 90 - fi, sine, cose);
1194
+ else /* southern hemisphere */
1195
+ hsp->coasc2 = Asc1 (th + 90, -90 - fi, sine, cose);
1196
+ /* "polar ascendant" M. Munkasey */
1197
+ hsp->polasc = Asc1 (th - 90, fi, sine, cose);
1198
+ return retc;
1199
+ } /* procedure houses */
1200
+
1201
+ /******************************/
1202
+ static double Asc1 (double x1, double f, double sine, double cose)
1203
+ {
1204
+ int n;
1205
+ double ass;
1206
+ x1 = swe_degnorm(x1);
1207
+ n = (int) ((x1 / 90) + 1);
1208
+ if (n == 1)
1209
+ ass = ( Asc2 (x1, f, sine, cose));
1210
+ else if (n == 2)
1211
+ ass = (180 - Asc2 (180 - x1, - f, sine, cose));
1212
+ else if (n == 3)
1213
+ ass = (180 + Asc2 (x1 - 180, - f, sine, cose));
1214
+ else
1215
+ ass = (360 - Asc2 (360- x1, f, sine, cose));
1216
+ ass = swe_degnorm(ass);
1217
+ if (fabs(ass - 90) < VERY_SMALL) /* rounding, e.g.: if */
1218
+ ass = 90; /* fi = 0 & st = 0, ac = 89.999... */
1219
+ if (fabs(ass - 180) < VERY_SMALL)
1220
+ ass = 180;
1221
+ if (fabs(ass - 270) < VERY_SMALL) /* rounding, e.g.: if */
1222
+ ass = 270; /* fi = 0 & st = 0, ac = 89.999... */
1223
+ if (fabs(ass - 360) < VERY_SMALL)
1224
+ ass = 0;
1225
+ return ass;
1226
+ } /* Asc1 */
1227
+
1228
+ static double Asc2 (double x, double f, double sine, double cose)
1229
+ {
1230
+ double ass, sinx;
1231
+ ass = - tand(f) * sine + cose * cosd(x);
1232
+ if (fabs(ass) < VERY_SMALL)
1233
+ ass = 0;
1234
+ sinx = sind(x);
1235
+ if (fabs(sinx) < VERY_SMALL)
1236
+ sinx = 0;
1237
+ if (sinx == 0) {
1238
+ if (ass < 0)
1239
+ ass = -VERY_SMALL;
1240
+ else
1241
+ ass = VERY_SMALL;
1242
+ } else if (ass == 0) {
1243
+ if (sinx < 0)
1244
+ ass = -90;
1245
+ else
1246
+ ass = 90;
1247
+ } else {
1248
+ ass = atand(sinx / ass);
1249
+ }
1250
+ if (ass < 0)
1251
+ ass = 180 + ass;
1252
+ return (ass);
1253
+ } /* Asc2 */
1254
+
1255
+
1256
+ /* Computes the house position of a planet or another point,
1257
+ * in degrees: 0 - 30 = 1st house, 30 - 60 = 2nd house, etc.
1258
+ * armc sidereal time in degrees
1259
+ * geolat geographic latitude
1260
+ * eps true ecliptic obliquity
1261
+ * hsys house system character
1262
+ * xpin array of 6 doubles:
1263
+ * only the first two of them are used: ecl. long., lat.
1264
+ * serr error message area
1265
+ *
1266
+ * House position is returned by function.
1267
+ *
1268
+ * IMPORTANT: This function should NOT be used for sidereal astrology.
1269
+ * If you cannot avoid doing so, please note:
1270
+ * - The input longitudes (xpin) MUST always be tropical, even if you
1271
+ * are a siderealist.
1272
+ * - Sidereal and tropical house positions are identical for most house
1273
+ * systems, if a traditional definition of the sidereal zodiac is used
1274
+ * (sid = trop - ayanamsa).
1275
+ * - The function does NOT provide correct positions for Whole Sign houses.
1276
+ * - The function does NOT provide correct positions, if you use a
1277
+ * non-traditional sidereal method (where the sidereal plane is not
1278
+ * identical to the ecliptic of date) with a house system whose definition
1279
+ * is dependent on the ecliptic, such as:
1280
+ * equal, Porphyry, Alcabitius, Koch, Krusinski (all others should work).
1281
+ * The Swiss Ephemeris currently does not handle these cases.
1282
+ */
1283
+ double FAR PASCAL_CONV swe_house_pos(
1284
+ double armc, double geolat, double eps, int hsys, double *xpin, char *serr)
1285
+ {
1286
+ double xp[6], xeq[6], ra, de, mdd, mdn, sad, san;
1287
+ double hpos, sinad, ad, a, admc, adp, samc, demc, asc, mc, acmc, tant;
1288
+ double fh, ra0, tanfi, fac, dfac;
1289
+ double x[3], xasc[3], raep, raaz, oblaz, xtemp; /* BK 21.02.2006 */
1290
+ double sine = sind(eps);
1291
+ double cose = cosd(eps);
1292
+ AS_BOOL is_above_hor = FALSE;
1293
+ AS_BOOL is_invalid = FALSE;
1294
+ AS_BOOL is_circumpolar = FALSE;
1295
+ if (serr != NULL)
1296
+ *serr = '\0';
1297
+ hsys = toupper(hsys);
1298
+ xeq[0] = xpin[0];
1299
+ xeq[1] = xpin[1];
1300
+ xeq[2] = 1;
1301
+ swe_cotrans(xpin, xeq, -eps);
1302
+ ra = xeq[0];
1303
+ de = xeq[1];
1304
+ mdd = swe_degnorm(ra - armc);
1305
+ mdn = swe_degnorm(mdd + 180);
1306
+ if (mdd >= 180)
1307
+ mdd -= 360;
1308
+ if (mdn >= 180)
1309
+ mdn -= 360;
1310
+ /* xp[0] will contain the house position, a value between 0 and 360 */
1311
+ switch(hsys) {
1312
+ case 'A':
1313
+ case 'E':
1314
+ case 'V':
1315
+ case 'W':
1316
+ asc = Asc1 (swe_degnorm(armc + 90), geolat, sine, cose);
1317
+ demc = atand(sind(armc) * tand(eps));
1318
+ if (geolat >= 0 && 90 - geolat + demc < 0)
1319
+ asc = swe_degnorm(asc + 180);
1320
+ if (geolat < 0 && -90 - geolat + demc > 0)
1321
+ asc = swe_degnorm(asc + 180);
1322
+ xp[0] = swe_degnorm(xpin[0] - asc);
1323
+ if (hsys == 'V')
1324
+ xp[0] = swe_degnorm(xp[0] + 15);
1325
+ if (hsys == 'W')
1326
+ xp[0] = swe_degnorm(xp[0] + fmod(asc, 30));
1327
+ /* to make sure that a call with a house cusp position returns
1328
+ * a value within the house, 0.001" is added */
1329
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
1330
+ hpos = xp[0] / 30.0 + 1;
1331
+ break;
1332
+ case 'O': /* Porphyry */
1333
+ case 'B': /* Alcabitius */
1334
+ asc = Asc1 (swe_degnorm(armc + 90), geolat, sine, cose);
1335
+ demc = atand(sind(armc) * tand(eps));
1336
+ /* mc */
1337
+ if (fabs(armc - 90) > VERY_SMALL
1338
+ && fabs(armc - 270) > VERY_SMALL) {
1339
+ tant = tand(armc);
1340
+ mc = swe_degnorm(atand(tant / cose));
1341
+ if (armc > 90 && armc <= 270)
1342
+ mc = swe_degnorm(mc + 180);
1343
+ } else {
1344
+ if (fabs(armc - 90) <= VERY_SMALL)
1345
+ mc = 90;
1346
+ else
1347
+ mc = 270;
1348
+ }
1349
+ /* while MC is always south,
1350
+ * Asc must always be in eastern hemisphere */
1351
+ if (geolat >= 0 && 90 - geolat + demc < 0) {
1352
+ asc = swe_degnorm(asc + 180);
1353
+ }
1354
+ if (geolat < 0 && -90 - geolat + demc > 0) {
1355
+ asc = swe_degnorm(asc + 180);
1356
+ }
1357
+ if (hsys == 'O') {
1358
+ xp[0] = swe_degnorm(xpin[0] - asc);
1359
+ /* to make sure that a call with a house cusp position returns
1360
+ * a value within the house, 0.001" is added */
1361
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
1362
+ if (xp[0] < 180)
1363
+ hpos = 1;
1364
+ else {
1365
+ hpos = 7;
1366
+ xp[0] -= 180;
1367
+ }
1368
+ acmc = swe_difdeg2n(asc, mc);
1369
+ if (xp[0] < 180 - acmc)
1370
+ hpos += xp[0] * 3 / (180 - acmc);
1371
+ else
1372
+ hpos += 3 + (xp[0] - 180 + acmc) * 3 / acmc;
1373
+ } else { /* Alcabitius */
1374
+ double dek, r, sna, sda;
1375
+ dek = asind(sind(asc) * sine); /* declination of Ascendant */
1376
+ /* must treat the case fi == 90 or -90 */
1377
+ tanfi = tand(geolat);
1378
+ r = -tanfi * tand(dek);
1379
+ /* must treat the case of abs(r) > 1; probably does not happen
1380
+ * because dek becomes smaller when fi is large, as ac is close to
1381
+ * zero Aries/Libra in that case.
1382
+ */
1383
+ sda = acos(r) * RADTODEG; /* semidiurnal arc, measured on equator */
1384
+ sna = 180 - sda; /* complement, seminocturnal arc */
1385
+ if (mdd > 0) {
1386
+ if (mdd < sda)
1387
+ hpos = mdd * 90 / sda;
1388
+ else
1389
+ hpos = 90 + (mdd - sda) * 90 / sna;
1390
+ } else {
1391
+ if (mdd > -sna)
1392
+ hpos = 360 + mdd * 90 / sna;
1393
+ else
1394
+ hpos = 270 + (mdd + sna) * 90 / sda;
1395
+ }
1396
+ hpos = swe_degnorm(hpos - 90) / 30.0 + 1.0;
1397
+ if (hpos >= 13.0) hpos -= 12;
1398
+ }
1399
+ break;
1400
+ case 'X': /* Merdidian or axial rotation system */
1401
+ hpos = swe_degnorm(mdd - 90) / 30.0 + 1.0;
1402
+ break;
1403
+ case 'M': { /* Morinus */
1404
+ double a = xpin[0];
1405
+ if (fabs(a - 90) > VERY_SMALL
1406
+ && fabs(a - 270) > VERY_SMALL) {
1407
+ tant = tand(a);
1408
+ hpos = atand(tant / cose);
1409
+ if (a > 90 && a <= 270)
1410
+ hpos = swe_degnorm(hpos + 180);
1411
+ } else {
1412
+ if (fabs(a - 90) <= VERY_SMALL)
1413
+ hpos = 90;
1414
+ else
1415
+ hpos = 270;
1416
+ } /* if */
1417
+ hpos = swe_degnorm(hpos - armc - 90);
1418
+ hpos = hpos / 30.0 + 1;
1419
+ }
1420
+ break;
1421
+ #if 0
1422
+ /* old version of Koch method */
1423
+ case 'K':
1424
+ demc = atand(sind(armc) * tand(eps));
1425
+ /* if body is within circumpolar region, error */
1426
+ if (90 - fabs(geolat) <= fabs(de)) {
1427
+ if (serr != NULL)
1428
+ strcpy(serr, "no Koch house position, because planet is circumpolar.");
1429
+ xp[0] = 0;
1430
+ hpos = 0; /* Error */
1431
+ } else if (90 - fabs(geolat) <= fabs(demc)) {
1432
+ if (serr != NULL)
1433
+ strcpy(serr, "no Koch house position, because mc is circumpolar.");
1434
+ xp[0] = 0;
1435
+ hpos = 0; /* Error */
1436
+ } else {
1437
+ admc = asind(tand(eps) * tand(geolat) * sind(armc));
1438
+ adp = asind(tand(geolat) * tand(de));
1439
+ samc = 90 + admc;
1440
+ if (mdd >= 0) { /* east */
1441
+ xp[0] = swe_degnorm(((mdd - adp + admc) / samc - 1) * 90);
1442
+ } else {
1443
+ xp[0] = swe_degnorm(((mdd + 180 + adp + admc) / samc + 1) * 90);
1444
+ }
1445
+ /* to make sure that a call with a house cusp position returns
1446
+ * a value within the house, 0.001" is added */
1447
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
1448
+ hpos = xp[0] / 30.0 + 1;
1449
+ }
1450
+ break;
1451
+ #endif
1452
+ /* version of Koch method: do calculations within circumpolar circle,
1453
+ * if possible; make sure house positions 4 - 9 only appear on western
1454
+ * hemisphere */
1455
+ case 'K':
1456
+ demc = atand(sind(armc) * tand(eps));
1457
+ is_invalid = FALSE;
1458
+ is_circumpolar = FALSE;
1459
+ /* object is within a circumpolar circle */
1460
+ if (90 - geolat < de || -90 - geolat > de) {
1461
+ adp = 90;
1462
+ is_circumpolar = TRUE;
1463
+ }
1464
+ /* object is within a circumpolar circle, southern hemisphere */
1465
+ else if (geolat - 90 > de || geolat + 90 < de) {
1466
+ adp = -90;
1467
+ is_circumpolar = TRUE;
1468
+ }
1469
+ /* object does rise and set */
1470
+ else {
1471
+ adp = asind(tand(geolat) * tand(de));
1472
+ }
1473
+ #if 0
1474
+ if (fabs(adp) == 90)
1475
+ is_invalid = TRUE; /* omit this to use the above values */
1476
+ #endif
1477
+ admc = tand(eps) * tand(geolat) * sind(armc);
1478
+ /* midheaven is circumpolar */
1479
+ if (fabs(admc) > 1) {
1480
+ #if 0
1481
+ is_invalid = TRUE; /* omit this line to use the below values */
1482
+ #endif
1483
+ if (admc > 1)
1484
+ admc = 1;
1485
+ else
1486
+ admc = -1;
1487
+ is_circumpolar = TRUE;
1488
+ }
1489
+ admc = asind(admc);
1490
+ samc = 90 + admc;
1491
+ if (samc == 0)
1492
+ is_invalid = TRUE;
1493
+ if (fabs(samc) > 0) {
1494
+ if (mdd >= 0) { /* east */
1495
+ dfac = (mdd - adp + admc) / samc;
1496
+ xp[0] = swe_degnorm((dfac - 1) * 90);
1497
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
1498
+ /* eastern object has longer SA than midheaven */
1499
+ if (dfac > 2 || dfac < 0)
1500
+ is_invalid = TRUE; /* if this is omitted, funny things happen */
1501
+ } else {
1502
+ dfac = (mdd + 180 + adp + admc) / samc;
1503
+ xp[0] = swe_degnorm((dfac + 1) * 90);
1504
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
1505
+ /* western object has longer SA than midheaven */
1506
+ if (dfac > 2 || dfac < 0)
1507
+ is_invalid = TRUE; /* if this is omitted, funny things happen */
1508
+ }
1509
+ }
1510
+ if (is_invalid) {
1511
+ xp[0] = 0;
1512
+ hpos = 0;
1513
+ if (serr != NULL)
1514
+ strcpy(serr, "Koch house position failed in circumpolar area");
1515
+ break;
1516
+ }
1517
+ if (is_circumpolar) {
1518
+ if (serr != NULL)
1519
+ strcpy(serr, "Koch house position, doubtful result in circumpolar area");
1520
+ }
1521
+ /* to make sure that a call with a house cusp position returns
1522
+ * a value within the house, 0.001" is added */
1523
+ hpos = xp[0] / 30.0 + 1;
1524
+ break;
1525
+ case 'C':
1526
+ xeq[0] = swe_degnorm(mdd - 90);
1527
+ swe_cotrans(xeq, xp, -geolat);
1528
+ /* to make sure that a call with a house cusp position returns
1529
+ * a value within the house, 0.001" is added */
1530
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
1531
+ hpos = xp[0] / 30.0 + 1;
1532
+ break;
1533
+ case 'U': /* Krusinski-Pisa */
1534
+ /* Purpose: find point where planet's house circle (meridian)
1535
+ * cuts house plane, giving exact planet's house position.
1536
+ * Input data: ramc, geolat, asc.
1537
+ */
1538
+ asc = Asc1 (swe_degnorm(armc + 90), geolat, sine, cose);
1539
+ demc = atand(sind(armc) * tand(eps));
1540
+ /* while MC is always south,
1541
+ * Asc must always be in eastern hemisphere */
1542
+ if (geolat >= 0 && 90 - geolat + demc < 0) {
1543
+ asc = swe_degnorm(asc + 180);
1544
+ }
1545
+ if (geolat < 0 && -90 - geolat + demc > 0) {
1546
+ asc = swe_degnorm(asc + 180);
1547
+ }
1548
+ /*
1549
+ * Descr: find the house plane 'asc-zenith' - where it intersects
1550
+ * with equator and at what angle, and then simple find arc
1551
+ * from asc on that plane to planet's meridian intersection
1552
+ * with this plane.
1553
+ */
1554
+ /* I. find plane of 'asc-zenith' great circle relative to equator:
1555
+ * solve spherical triangle 'EP-asc-intersection of house circle with equator' */
1556
+ /* Ia. Find intersection of house plane with equator: */
1557
+ x[0] = asc; x[1] = 0.0; x[2] = 1.0; /* 1. Start with ascendent on ecliptic */
1558
+ swe_cotrans(x, x, -eps); /* 2. Transform asc into equatorial coords */
1559
+ raep = swe_degnorm(armc + 90); /* 3. RA of east point */
1560
+ x[0] = swe_degnorm(raep - x[0]); /* 4. Rotation - found arc raas-raep */
1561
+ swe_cotrans(x, x, -(90-geolat)); /* 5. Transform into horizontal coords - arc EP-asc on horizon */
1562
+ xtemp = atand(tand(x[0])/cosd((90-geolat))); /* 6. Rotation from horizon on circle perpendicular to equator */
1563
+ if (x[0] > 90 && x[0] <= 270)
1564
+ xtemp = swe_degnorm(xtemp + 180);
1565
+ x[0] = swe_degnorm(xtemp);
1566
+ raaz = swe_degnorm(raep - x[0]); /* result: RA of intersection 'asc-zenith' great circle with equator */
1567
+ /* Ib. Find obliquity to equator of 'asc-zenith' house plane: */
1568
+ x[0] = raaz; x[1] = 0.0;
1569
+ x[0] = swe_degnorm(raep - x[0]); /* 1. Rotate start point relative to EP */
1570
+ swe_cotrans(x, x, -(90-geolat)); /* 2. Transform into horizontal coords */
1571
+ x[1] = x[1] + 90; /* 3. Add 90 deg do decl - so get the point on house plane most distant from equ. */
1572
+ swe_cotrans(x, x, 90-geolat); /* 4. Rotate back to equator */
1573
+ oblaz = x[1]; /* 5. Obliquity of house plane to equator */
1574
+ /* II. Next find asc and planet position on house plane,
1575
+ * so to find relative distance of planet from
1576
+ * coords beginning. */
1577
+ /* IIa. Asc on house plane relative to intersection
1578
+ * of equator with 'asc-zenith' plane. */
1579
+ xasc[0] = asc; xasc[1] = 0.0; xasc[2] = 1.0;
1580
+ swe_cotrans(xasc, xasc, -eps);
1581
+ xasc[0] = swe_degnorm(xasc[0] - raaz);
1582
+ xtemp = atand(tand(xasc[0])/cosd(oblaz));
1583
+ if (xasc[0] > 90 && xasc[0] <= 270)
1584
+ xtemp = swe_degnorm(xtemp + 180);
1585
+ xasc[0] = swe_degnorm(xtemp);
1586
+ /* IIb. Planet on house plane relative to intersection
1587
+ * of equator with 'asc-zenith' plane */
1588
+ xp[0] = swe_degnorm(xeq[0] - raaz); /* Rotate on equator */
1589
+ xtemp = atand(tand(xp[0])/cosd(oblaz)); /* Find arc on house plane from equator */
1590
+ if (xp[0] > 90 && xp[0] <= 270)
1591
+ xtemp = swe_degnorm(xtemp + 180);
1592
+ xp[0] = swe_degnorm(xtemp);
1593
+ xp[0] = swe_degnorm(xp[0]-xasc[0]); /* find arc between asc and planet, and get planet house position */
1594
+ /* IIc. Distance from planet to house plane on declination circle: */
1595
+ x[0] = xeq[0];
1596
+ x[1] = xeq[1];
1597
+ swe_cotrans(x, x, oblaz);
1598
+ xp[1] = xeq[1] - x[1]; /* How many degrees is the point on declination circle from house circle */
1599
+ /* to make sure that a call with a house cusp position returns
1600
+ * a value within the house, 0.001" is added */
1601
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
1602
+ hpos = xp[0] / 30.0 + 1;
1603
+ break;
1604
+ case 'H':
1605
+ xeq[0] = swe_degnorm(mdd - 90);
1606
+ swe_cotrans(xeq, xp, 90 - geolat);
1607
+ /* to make sure that a call with a house cusp position returns
1608
+ * a value within the house, 0.001" is added */
1609
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
1610
+ hpos = xp[0] / 30.0 + 1;
1611
+ break;
1612
+ case 'R':
1613
+ if (fabs(mdd) < VERY_SMALL)
1614
+ xp[0] = 270;
1615
+ else if (180 - fabs(mdd) < VERY_SMALL)
1616
+ xp[0] = 90;
1617
+ else {
1618
+ if (90 - fabs(geolat) < VERY_SMALL) {
1619
+ if (geolat > 0)
1620
+ geolat = 90 - VERY_SMALL;
1621
+ else
1622
+ geolat = -90 + VERY_SMALL;
1623
+ }
1624
+ if (90 - fabs(de) < VERY_SMALL) {
1625
+ if (de > 0)
1626
+ de = 90 - VERY_SMALL;
1627
+ else
1628
+ de = -90 + VERY_SMALL;
1629
+ }
1630
+ a = tand(geolat) * tand(de) + cosd(mdd);
1631
+ xp[0] = swe_degnorm(atand(-a / sind(mdd)));
1632
+ if (mdd < 0)
1633
+ xp[0] += 180;
1634
+ xp[0] = swe_degnorm(xp[0]);
1635
+ /* to make sure that a call with a house cusp position returns
1636
+ * a value within the house, 0.001" is added */
1637
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
1638
+ }
1639
+ hpos = xp[0] / 30.0 + 1;
1640
+ break;
1641
+ case 'T':
1642
+ mdd = swe_degnorm(mdd);
1643
+ if (de > 90 - VERY_SMALL)
1644
+ de = 90 - VERY_SMALL;
1645
+ if (de < -90 + VERY_SMALL)
1646
+ de = -90 + VERY_SMALL;
1647
+ sinad = tand(de) * tand(geolat);
1648
+ ad = asind(sinad);
1649
+ a = sinad + cosd(mdd);
1650
+ if (a >= 0)
1651
+ is_above_hor = TRUE;
1652
+ /* mirror everything below the horizon to the opposite point
1653
+ * above the horizon */
1654
+ if (!is_above_hor) {
1655
+ ra = swe_degnorm(ra + 180);
1656
+ de = -de;
1657
+ mdd = swe_degnorm(mdd + 180);
1658
+ }
1659
+ /* mirror everything on western hemisphere to eastern hemisphere */
1660
+ if (mdd > 180) {
1661
+ ra = swe_degnorm(armc - mdd);
1662
+ }
1663
+ /* binary search for "topocentric" position line of body */
1664
+ tanfi = tand(geolat);
1665
+ fh = geolat;
1666
+ ra0 = swe_degnorm(armc + 90);
1667
+ xp[1] = 1;
1668
+ xeq[1] = de;
1669
+ fac = 2;
1670
+ while (fabs(xp[1]) > 0.000001) {
1671
+ if (xp[1] > 0) {
1672
+ fh = atand(tand(fh) - tanfi / fac);
1673
+ ra0 -= 90 / fac;
1674
+ } else {
1675
+ fh = atand(tand(fh) + tanfi / fac);
1676
+ ra0 += 90 / fac;
1677
+ }
1678
+ xeq[0] = swe_degnorm(ra - ra0);
1679
+ swe_cotrans(xeq, xp, 90 - fh);
1680
+ fac *= 2;
1681
+ }
1682
+ hpos = swe_degnorm(ra0 - armc);
1683
+ /* mirror back to west */
1684
+ if (mdd > 180)
1685
+ hpos = swe_degnorm(-hpos);
1686
+ /* mirror back to below horizon */
1687
+ if (!is_above_hor)
1688
+ hpos = swe_degnorm(hpos + 180);
1689
+ hpos = swe_degnorm(hpos - 90) / 30 + 1;
1690
+ break;
1691
+ case 'P':
1692
+ case 'G':
1693
+ default:
1694
+ /* circumpolar region */
1695
+ if (90 - fabs(de) <= fabs(geolat)) {
1696
+ if (de * geolat < 0)
1697
+ xp[0] = swe_degnorm(90 + mdn / 2);
1698
+ else
1699
+ xp[0] = swe_degnorm(270 + mdd / 2);
1700
+ if (serr != NULL)
1701
+ strcpy(serr, "Otto Ludwig procedure within circumpolar regions.");
1702
+ } else {
1703
+ sinad = tand(de) * tand(geolat);
1704
+ ad = asind(sinad);
1705
+ a = sinad + cosd(mdd);
1706
+ if (a >= 0)
1707
+ is_above_hor = TRUE;
1708
+ sad = 90 + ad;
1709
+ san = 90 - ad;
1710
+ if (is_above_hor)
1711
+ xp[0] = (mdd / sad + 3) * 90;
1712
+ else
1713
+ xp[0] = (mdn / san + 1) * 90;
1714
+ /* to make sure that a call with a house cusp position returns
1715
+ * a value within the house, 0.001" is added */
1716
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
1717
+ }
1718
+ if (hsys == 'G') {
1719
+ xp[0] = 360 - xp[0]; /* Gauquelin sectors are in clockwise direction */
1720
+ hpos = xp[0] / 10.0 + 1;
1721
+ } else {
1722
+ hpos = xp[0] / 30.0 + 1;
1723
+ }
1724
+ break;
1725
+ }
1726
+ return hpos;
1727
+ }