@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,3140 @@
1
+
2
+ /*******************************************************
3
+ module swehouse.c
4
+ house and (simple) aspect calculation
5
+
6
+ ************************************************************/
7
+ /* Copyright (C) 1997 - 2021 Astrodienst AG, Switzerland. All rights reserved.
8
+
9
+ License conditions
10
+ ------------------
11
+
12
+ This file is part of Swiss Ephemeris.
13
+
14
+ Swiss Ephemeris is distributed with NO WARRANTY OF ANY KIND. No author
15
+ or distributor accepts any responsibility for the consequences of using it,
16
+ or for whether it serves any particular purpose or works at all, unless he
17
+ or she says so in writing.
18
+
19
+ Swiss Ephemeris is made available by its authors under a dual licensing
20
+ system. The software developer, who uses any part of Swiss Ephemeris
21
+ in his or her software, must choose between one of the two license models,
22
+ which are
23
+ a) GNU Affero General Public License (AGPL)
24
+ b) Swiss Ephemeris Professional License
25
+
26
+ The choice must be made before the software developer distributes software
27
+ containing parts of Swiss Ephemeris to others, and before any public
28
+ service using the developed software is activated.
29
+
30
+ If the developer choses the AGPL software license, he or she must fulfill
31
+ the conditions of that license, which includes the obligation to place his
32
+ or her whole software project under the AGPL or a compatible license.
33
+ See https://www.gnu.org/licenses/agpl-3.0.html
34
+
35
+ If the developer choses the Swiss Ephemeris Professional license,
36
+ he must follow the instructions as found in http://www.astro.com/swisseph/
37
+ and purchase the Swiss Ephemeris Professional Edition from Astrodienst
38
+ and sign the corresponding license contract.
39
+
40
+ The License grants you the right to use, copy, modify and redistribute
41
+ Swiss Ephemeris, but only under certain conditions described in the License.
42
+ Among other things, the License requires that the copyright notices and
43
+ this notice be preserved on all copies.
44
+
45
+ Authors of the Swiss Ephemeris: Dieter Koch and Alois Treindl
46
+
47
+ The authors of Swiss Ephemeris have no control or influence over any of
48
+ the derived works, i.e. over software or services created by other
49
+ programmers which use Swiss Ephemeris functions.
50
+
51
+ The names of the authors or of the copyright holder (Astrodienst) must not
52
+ be used for promoting any software, product or service which uses or contains
53
+ the Swiss Ephemeris. This copyright notice is the ONLY place where the
54
+ names of the authors can legally appear, except in cases where they have
55
+ given special permission in writing.
56
+
57
+ The trademarks 'Swiss Ephemeris' and 'Swiss Ephemeris inside' may be used
58
+ for promoting such software, products or services.
59
+ */
60
+
61
+ //#include "sweodef.h"
62
+ #include "swephexp.h"
63
+ #include "sweph.h"
64
+ #include "swephlib.h"
65
+ #include "swehouse.h"
66
+ #include <string.h>
67
+
68
+ #define MILLIARCSEC (1.0 / 3600000.0)
69
+ #define SOLAR_YEAR 365.24219893
70
+ #define ARMCS ((SOLAR_YEAR+1) / SOLAR_YEAR * 360)
71
+
72
+ static double Asc1(double, double, double, double);
73
+ static double AscDash(double, double, double, double);
74
+ static double Asc2(double, double, double, double);
75
+ static int CalcH(double th, double fi, double ekl, char hsy, 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
+ double *cusp_speed,
85
+ double *ascmc_speed,
86
+ char *serr);
87
+ static int sidereal_houses_trad(double tjde,
88
+ int32 iflag,
89
+ double armc,
90
+ double eps,
91
+ double nutl,
92
+ double lat,
93
+ int hsys,
94
+ double *cusp,
95
+ double *ascmc,
96
+ double *cusp_speed,
97
+ double *ascmc_speed,
98
+ char *serr);
99
+ static int sidereal_houses_ssypl(double tjde,
100
+ double armc,
101
+ double eps,
102
+ double *nutlo,
103
+ double lat,
104
+ int hsys,
105
+ double *cusp,
106
+ double *ascmc,
107
+ double *cusp_speed,
108
+ double *ascmc_speed,
109
+ char *serr);
110
+ static int sunshine_solution_makransky(double ramc, double lat, double ecl, struct houses *hsp);
111
+ static int sunshine_solution_treindl(double ramc, double lat, double ecl, struct houses *hsp);
112
+ #if 0
113
+ static void test_Asc1();
114
+ #endif
115
+
116
+ /* housasp.c
117
+ * cusps are returned in double cusp[13],
118
+ * or cusp[37] with house system 'G'.
119
+ * cusp[1...12] houses 1 - 12
120
+ * additional points are returned in ascmc[10].
121
+ * ascmc[0] = ascendant
122
+ * ascmc[1] = mc
123
+ * ascmc[2] = armc
124
+ * ascmc[3] = vertex
125
+ * ascmc[4] = equasc * "equatorial ascendant" *
126
+ * ascmc[5] = coasc1 * "co-ascendant" (W. Koch) *
127
+ * ascmc[6] = coasc2 * "co-ascendant" (M. Munkasey) *
128
+ * ascmc[7] = polasc * "polar ascendant" (M. Munkasey) *
129
+ */
130
+ int CALL_CONV swe_houses(double tjd_ut,
131
+ double geolat,
132
+ double geolon,
133
+ int hsys,
134
+ double *cusp,
135
+ double *ascmc)
136
+ {
137
+ int i, retc = 0;
138
+ double armc, eps, nutlo[2];
139
+ double tjde = tjd_ut + swe_deltat_ex(tjd_ut, -1, NULL);
140
+ eps = swi_epsiln(tjde, 0) * RADTODEG;
141
+ swi_nutation(tjde, 0, nutlo);
142
+ for (i = 0; i < 2; i++)
143
+ nutlo[i] *= RADTODEG;
144
+ armc = swe_degnorm(swe_sidtime0(tjd_ut, eps + nutlo[1], nutlo[0]) * 15 + geolon);
145
+ if (toupper(hsys) == 'I') { // compute sun declination for sunshine houses
146
+ int flags = SEFLG_SPEED| SEFLG_EQUATORIAL;
147
+ double xp[6];
148
+ int result = swe_calc_ut(tjd_ut, SE_SUN, flags, xp, NULL);
149
+ if (result < 0) {
150
+ // in case of failure, Porphyry houses
151
+ result = swe_houses_armc_ex2(armc, geolat, eps + nutlo[1], 'O', cusp, ascmc, NULL, NULL, NULL);
152
+ return ERR;
153
+ }
154
+ ascmc[9] = xp[1]; // declination in ascmc[9];
155
+ }
156
+ #ifdef TRACE
157
+ swi_open_trace(NULL);
158
+ if (swi_trace_count <= TRACE_COUNT_MAX) {
159
+ if (swi_fp_trace_c != NULL) {
160
+ fputs("\n/*SWE_HOUSES*/\n", swi_fp_trace_c);
161
+ fprintf(swi_fp_trace_c, "#if 0\n");
162
+ fprintf(swi_fp_trace_c, " tjd = %.9f;", tjd_ut);
163
+ fprintf(swi_fp_trace_c, " geolon = %.9f;", geolon);
164
+ fprintf(swi_fp_trace_c, " geolat = %.9f;", geolat);
165
+ fprintf(swi_fp_trace_c, " hsys = %d;\n", hsys);
166
+ fprintf(swi_fp_trace_c, " retc = swe_houses(tjd, geolat, geolon, hsys, cusp, ascmc);\n");
167
+ fprintf(swi_fp_trace_c, " /* swe_houses calls swe_houses_armc as follows: */\n");
168
+ fprintf(swi_fp_trace_c, "#endif\n");
169
+ fflush(swi_fp_trace_c);
170
+ }
171
+ }
172
+ #endif
173
+ retc = swe_houses_armc_ex2(armc, geolat, eps + nutlo[1], hsys, cusp, ascmc, NULL, NULL, NULL);
174
+ return retc;
175
+ }
176
+
177
+ // For explanation see function swe_houses_ex2() below.
178
+ int CALL_CONV swe_houses_ex(double tjd_ut,
179
+ int32 iflag,
180
+ double geolat,
181
+ double geolon,
182
+ int hsys,
183
+ double *cusp,
184
+ double *ascmc)
185
+ {
186
+ return swe_houses_ex2(tjd_ut, iflag, geolat, geolon, hsys, cusp, ascmc, NULL, NULL, NULL);
187
+ }
188
+
189
+ /*
190
+ * Function returns OK or ERR.
191
+ * cusps are returned in double cusp[13],
192
+ * or cusp[37] with house system 'G'.
193
+ * cusp[1...12] houses 1 - 12
194
+ * ascmc[0...10] additional points:
195
+ * ascmc[0] = ascendant
196
+ * ascmc[1] = mc
197
+ * ascmc[2] = armc
198
+ * ascmc[3] = vertex
199
+ * ascmc[4] = equasc * "equatorial ascendant" *
200
+ * ascmc[5] = coasc1 * "co-ascendant" (W. Koch) *
201
+ * ascmc[6] = coasc2 * "co-ascendant" (M. Munkasey) *
202
+ * ascmc[7] = polasc * "polar ascendant" (M. Munkasey) *
203
+ * cusp_speed[1...12] speeds (daily motions) of the cusps.
204
+ * ascmc_speed[0...10] speeds (daily motions) of the additional points.
205
+ * serr error message or warning
206
+ */
207
+ int CALL_CONV swe_houses_ex2(double tjd_ut,
208
+ int32 iflag,
209
+ double geolat,
210
+ double geolon,
211
+ int hsys,
212
+ double *cusp,
213
+ double *ascmc,
214
+ double *cusp_speed,
215
+ double *ascmc_speed,
216
+ char *serr)
217
+ {
218
+ int i, retc = 0;
219
+ double armc, eps_mean, nutlo[2];
220
+ double tjde = tjd_ut + swe_deltat_ex(tjd_ut, iflag, NULL);
221
+ struct sid_data *sip = &swed.sidd;
222
+ double xp[6];
223
+ int retc_makr = 0;
224
+ int ito;
225
+ if (toupper(hsys) == 'G')
226
+ ito = 36;
227
+ else
228
+ ito = 12;
229
+ if ((iflag & SEFLG_SIDEREAL) && !swed.ayana_is_set)
230
+ swe_set_sid_mode(SE_SIDM_FAGAN_BRADLEY, 0, 0);
231
+ eps_mean = swi_epsiln(tjde, 0) * RADTODEG;
232
+ swi_nutation(tjde, 0, nutlo);
233
+ for (i = 0; i < 2; i++)
234
+ nutlo[i] *= RADTODEG;
235
+ if (iflag & SEFLG_NONUT) {
236
+ for (i = 0; i < 2; i++)
237
+ nutlo[i] = 0;
238
+ }
239
+ #ifdef TRACE
240
+ swi_open_trace(NULL);
241
+ if (swi_trace_count <= TRACE_COUNT_MAX) {
242
+ if (swi_fp_trace_c != NULL) {
243
+ fputs("\n/*SWE_HOUSES_EX*/\n", swi_fp_trace_c);
244
+ fprintf(swi_fp_trace_c, "#if 0\n");
245
+ fprintf(swi_fp_trace_c, " tjd = %.9f;", tjd_ut);
246
+ fprintf(swi_fp_trace_c, " iflag = %d;\n", iflag);
247
+ fprintf(swi_fp_trace_c, " geolon = %.9f;", geolon);
248
+ fprintf(swi_fp_trace_c, " geolat = %.9f;", geolat);
249
+ fprintf(swi_fp_trace_c, " hsys = %d;\n", hsys);
250
+ fprintf(swi_fp_trace_c, " retc = swe_houses_ex(tjd, iflag, geolat, geolon, hsys, cusp, ascmc);\n");
251
+ fprintf(swi_fp_trace_c, " /* swe_houses calls swe_houses_armc as follows: */\n");
252
+ fprintf(swi_fp_trace_c, "#endif\n");
253
+ fflush(swi_fp_trace_c);
254
+ }
255
+ }
256
+ #endif
257
+ /*houses_to_sidereal(tjde, geolat, hsys, eps, cusp, ascmc, iflag);*/
258
+ armc = swe_degnorm(swe_sidtime0(tjd_ut, eps_mean + nutlo[1], nutlo[0]) * 15 + geolon);
259
+ //fprintf(stderr, "armc=%f, iflag=%d\n", armc, iflag);
260
+ if (toupper(hsys) == 'I') { // compute sun declination for sunshine houses
261
+ int flags = SEFLG_SPEED| SEFLG_EQUATORIAL;
262
+ retc_makr = swe_calc_ut(tjd_ut, SE_SUN, flags, xp, NULL);
263
+ if (retc_makr < 0) {
264
+ // in case of failure, provide Porphyry houses
265
+ hsys = (int) 'O';
266
+ }
267
+ ascmc[9] = xp[1]; // declination in ascmc[9];
268
+ }
269
+ if (iflag & SEFLG_SIDEREAL) {
270
+ if (sip->sid_mode & SE_SIDBIT_ECL_T0)
271
+ retc = sidereal_houses_ecl_t0(tjde, armc, eps_mean + nutlo[1], nutlo, geolat, hsys, cusp, ascmc, cusp_speed, ascmc_speed, serr);
272
+ else if (sip->sid_mode & SE_SIDBIT_SSY_PLANE)
273
+ retc = sidereal_houses_ssypl(tjde, armc, eps_mean + nutlo[1], nutlo, geolat, hsys, cusp, ascmc, cusp_speed, ascmc_speed, serr);
274
+ else
275
+ retc = sidereal_houses_trad(tjde, iflag, armc, eps_mean + nutlo[1], nutlo[0], geolat, hsys, cusp, ascmc, cusp_speed, ascmc_speed, serr);
276
+ } else {
277
+ retc = swe_houses_armc_ex2(armc, geolat, eps_mean + nutlo[1], hsys, cusp, ascmc, cusp_speed, ascmc_speed, serr);
278
+ if (toupper(hsys) == 'I')
279
+ ascmc[9] = xp[1]; // declination in ascmc[9];
280
+ }
281
+ if (iflag & SEFLG_RADIANS) {
282
+ for (i = 1; i <= ito; i++)
283
+ cusp[i] *= DEGTORAD;
284
+ for (i = 0; i < SE_NASCMC; i++)
285
+ ascmc[i] *= DEGTORAD;
286
+ }
287
+ if (retc_makr < 0)
288
+ return retc_makr;
289
+ return retc;
290
+ }
291
+
292
+ /*
293
+ * houses to sidereal
294
+ * ------------------
295
+ * there are two methods:
296
+ * a) the traditional one
297
+ * houses are computed tropically, then nutation and the ayanamsa
298
+ * are subtracted.
299
+ * b) the projection on the ecliptic of t0
300
+ * The house computation is then as follows:
301
+ *
302
+ * Be t the birth date and t0 the epoch at which ayanamsa = 0.
303
+ * 1. Compute the angle between the mean ecliptic at t0 and
304
+ * the true equator at t.
305
+ * The intersection point of these two circles we call the
306
+ * "auxiliary vernal point", and the angle between them the
307
+ * "auxiliary obliquity".
308
+ * 2. Compute the distance of the auxiliary vernal point from the
309
+ * vernal point at t. (this is a section on the equator)
310
+ * 3. subtract this value from the armc of t = aux. armc.
311
+ * 4. Compute the axes and houses for this aux. armc and aux. obliquity.
312
+ * 5. Compute the distance between the auxiliary vernal point and the
313
+ * vernal point at t0 (this is the ayanamsa at t, measured on the
314
+ * ecliptic of t0)
315
+ * 6. subtract this distance from all house cusps.
316
+ * 7. subtract ayanamsa_t0 from all house cusps.
317
+ */
318
+ static int sidereal_houses_ecl_t0(double tjde,
319
+ double armc,
320
+ double eps,
321
+ double *nutlo,
322
+ double lat,
323
+ int hsys,
324
+ double *cusp,
325
+ double *ascmc,
326
+ double *cusp_speed,
327
+ double *ascmc_speed,
328
+ char *serr)
329
+ {
330
+ int i, j, retc = OK;
331
+ double x[6], xvpx[6], x2[6], epst0, xnorm[6];
332
+ double rxy, rxyz, c2, epsx, sgn, fac, dvpx, dvpxe;
333
+ double armcx;
334
+ struct sid_data *sip = &swed.sidd;
335
+ int ito;
336
+ if (toupper(hsys) == 'G')
337
+ ito = 36;
338
+ else
339
+ ito = 12;
340
+ /* epsilon at t0 */
341
+ epst0 = swi_epsiln(sip->t0, 0);
342
+ /* cartesian coordinates of an imaginary moving body on the
343
+ * the mean ecliptic of t0; we take the vernal point: */
344
+ x[0] = x[4] = 1;
345
+ x[1] = x[2] = x[3] = x[5] = 0;
346
+ /* to equator */
347
+ swi_coortrf(x, x, -epst0);
348
+ swi_coortrf(x+3, x+3, -epst0);
349
+ /* to tjd_et */
350
+ swi_precess(x, sip->t0, 0, J_TO_J2000);
351
+ swi_precess(x, tjde, 0, J2000_TO_J);
352
+ swi_precess(x+3, sip->t0, 0, J_TO_J2000);
353
+ swi_precess(x+3, tjde, 0, J2000_TO_J);
354
+ /* to true equator of tjd_et */
355
+ swi_coortrf(x, x, (eps - nutlo[1]) * DEGTORAD);
356
+ swi_coortrf(x+3, x+3, (eps - nutlo[1]) * DEGTORAD);
357
+ swi_cartpol_sp(x, x);
358
+ x[0] += nutlo[0] * DEGTORAD;
359
+ swi_polcart_sp(x, x);
360
+ swi_coortrf(x, x, -eps * DEGTORAD);
361
+ swi_coortrf(x+3, x+3, -eps * DEGTORAD);
362
+ /* now, we have the moving point precessed to tjd_et.
363
+ * next, we compute the auxiliary epsilon: */
364
+ swi_cross_prod(x, x+3, xnorm);
365
+ rxy = xnorm[0] * xnorm[0] + xnorm[1] * xnorm[1];
366
+ c2 = (rxy + xnorm[2] * xnorm[2]);
367
+ rxyz = sqrt(c2);
368
+ rxy = sqrt(rxy);
369
+ epsx = asin(rxy / rxyz) * RADTODEG; /* 1a */
370
+ /* auxiliary vernal point */
371
+ if (fabs(x[5]) < 1e-15)
372
+ x[5] = 1e-15;
373
+ fac = x[2] / x[5];
374
+ sgn = x[5] / fabs(x[5]);
375
+ for (j = 0; j <= 2; j++)
376
+ xvpx[j] = (x[j] - fac * x[j+3]) * sgn; /* 1b */
377
+ /* distance of the auxiliary vernal point from
378
+ * the zero point at tjd_et (a section on the equator): */
379
+ swi_cartpol(xvpx, x2);
380
+ dvpx = x2[0] * RADTODEG; /* 2 */
381
+ /* auxiliary armc */
382
+ armcx = swe_degnorm(armc - dvpx); /* 3 */
383
+ /* compute axes and houses: */
384
+ retc = swe_houses_armc_ex2(armcx, lat, epsx, hsys, cusp, ascmc, cusp_speed, ascmc_speed, serr); /* 4 */
385
+ /* distance between auxiliary vernal point and
386
+ * vernal point of t0 (a section on the sidereal plane) */
387
+ dvpxe = acos(swi_dot_prod_unit(x, xvpx)) * RADTODEG; /* 5 */
388
+ if (tjde < sip->t0)
389
+ dvpxe = -dvpxe;
390
+ for (i = 1; i <= ito; i++) /* 6, 7 */
391
+ cusp[i] = swe_degnorm(cusp[i] - dvpxe - sip->ayan_t0);
392
+ for (i = 0; i <= SE_NASCMC; i++) {
393
+ if (i == 2) /* armc */
394
+ continue;
395
+ ascmc[i] = swe_degnorm(ascmc[i] - dvpxe - sip->ayan_t0);
396
+ }
397
+ if (hsys == 'N') { /* 1 = 0° Aries */
398
+ for (i = 1; i <= ito; i++) {
399
+ cusp[i] = (i - 1) * 30;
400
+ }
401
+ }
402
+ return retc;
403
+ }
404
+
405
+ /*
406
+ * Be t the birth date and t0 the epoch at which ayanamsa = 0.
407
+ * 1. Compute the angle between the solar system rotation plane and
408
+ * the true equator at t.
409
+ * The intersection point of these two circles we call the
410
+ * "auxiliary vernal point", and the angle between them the
411
+ * "auxiliary obliquity".
412
+ * 2. Compute the distance of the auxiliary vernal point from the
413
+ * zero point at t. (this is a section on the equator)
414
+ * 3. subtract this value from the armc of t = aux. armc.
415
+ * 4. Compute the axes and houses for this aux. armc and aux. obliquity.
416
+ * 5. Compute the distance between the auxiliary vernal point at t
417
+ * and the zero point of the solar system plane J2000
418
+ * (a section measured on the solar system plane)
419
+ * 6. subtract this distance from all house cusps.
420
+ * 7. compute the ayanamsa of J2000 on the solar system plane,
421
+ * referred to t0
422
+ * 8. subtract ayanamsa_t0 from all house cusps.
423
+ * 9. subtract ayanamsa_2000 from all house cusps.
424
+ */
425
+ static int sidereal_houses_ssypl(double tjde,
426
+ double armc,
427
+ double eps,
428
+ double *nutlo,
429
+ double lat,
430
+ int hsys,
431
+ double *cusp,
432
+ double *ascmc,
433
+ double *cusp_speed,
434
+ double *ascmc_speed,
435
+ char *serr)
436
+ {
437
+ int i, j, retc = OK;
438
+ double x[6], x0[6], xvpx[6], x2[6], xnorm[6];
439
+ double rxy, rxyz, c2, epsx, eps2000, sgn, fac, dvpx, dvpxe, x00;
440
+ double armcx;
441
+ struct sid_data *sip = &swed.sidd;
442
+ int ito;
443
+ if (toupper(hsys) == 'G')
444
+ ito = 36;
445
+ else
446
+ ito = 12;
447
+ eps2000 = swi_epsiln(J2000, 0);
448
+ /* cartesian coordinates of the zero point on the
449
+ * the solar system rotation plane */
450
+ x[0] = x[4] = 1;
451
+ x[1] = x[2] = x[3] = x[5] = 0;
452
+ /* to ecliptic 2000 */
453
+ swi_coortrf(x, x, -SSY_PLANE_INCL);
454
+ swi_coortrf(x+3, x+3, -SSY_PLANE_INCL);
455
+ swi_cartpol_sp(x, x);
456
+ x[0] += SSY_PLANE_NODE_E2000;
457
+ swi_polcart_sp(x, x);
458
+ /* to equator 2000 */
459
+ swi_coortrf(x, x, -eps2000);
460
+ swi_coortrf(x+3, x+3, -eps2000);
461
+ /* to mean equator of t */
462
+ swi_precess(x, tjde, 0, J2000_TO_J);
463
+ swi_precess(x+3, tjde, 0, J2000_TO_J);
464
+ /* to true equator of t */
465
+ swi_coortrf(x, x, (eps - nutlo[1]) * DEGTORAD);
466
+ swi_coortrf(x+3, x+3, (eps - nutlo[1]) * DEGTORAD);
467
+ swi_cartpol_sp(x, x);
468
+ x[0] += nutlo[0] * DEGTORAD;
469
+ swi_polcart_sp(x, x);
470
+ swi_coortrf(x, x, -eps * DEGTORAD);
471
+ swi_coortrf(x+3, x+3, -eps * DEGTORAD);
472
+ /* now, we have the moving point precessed to tjd_et.
473
+ * next, we compute the auxiliary epsilon: */
474
+ swi_cross_prod(x, x+3, xnorm);
475
+ rxy = xnorm[0] * xnorm[0] + xnorm[1] * xnorm[1];
476
+ c2 = (rxy + xnorm[2] * xnorm[2]);
477
+ rxyz = sqrt(c2);
478
+ rxy = sqrt(rxy);
479
+ epsx = asin(rxy / rxyz) * RADTODEG; /* 1a */
480
+ /* auxiliary vernal point */
481
+ if (fabs(x[5]) < 1e-15)
482
+ x[5] = 1e-15;
483
+ fac = x[2] / x[5];
484
+ sgn = x[5] / fabs(x[5]);
485
+ for (j = 0; j <= 2; j++)
486
+ xvpx[j] = (x[j] - fac * x[j+3]) * sgn; /* 1b */
487
+ /* distance of the auxiliary vernal point from
488
+ * mean vernal point at tjd_et (a section on the equator): */
489
+ swi_cartpol(xvpx, x2);
490
+ dvpx = x2[0] * RADTODEG; /* 2 */
491
+ /* auxiliary armc */
492
+ armcx = swe_degnorm(armc - dvpx); /* 3 */
493
+ /* compute axes and houses: */
494
+ retc = swe_houses_armc_ex2(armcx, lat, epsx, hsys, cusp, ascmc, cusp_speed, ascmc_speed, serr); /* 4 */
495
+ /* distance between the auxiliary vernal point at t and
496
+ * the sidereal zero point of 2000 at t
497
+ * (a section on the sidereal plane).
498
+ */
499
+ dvpxe = acos(swi_dot_prod_unit(x, xvpx)) * RADTODEG; /* 5 */
500
+ /* (always positive for dates after 5400 bc) */
501
+ dvpxe -= SSY_PLANE_NODE * RADTODEG;
502
+ /* ayanamsa between t0 and J2000, measured on solar system plane: */
503
+ /* position of zero point of t0 */
504
+ x0[0] = 1;
505
+ x0[1] = x0[2] = 0;
506
+ /* zero point of t0 in J2000 system */
507
+ if (sip->t0 != J2000)
508
+ swi_precess(x0, sip->t0, 0, J_TO_J2000);
509
+ /* zero point to ecliptic 2000 */
510
+ swi_coortrf(x0, x0, eps2000);
511
+ /* to solar system plane */
512
+ swi_cartpol(x0, x0);
513
+ x0[0] -= SSY_PLANE_NODE_E2000;
514
+ swi_polcart(x0, x0);
515
+ swi_coortrf(x0, x0, SSY_PLANE_INCL);
516
+ swi_cartpol(x0, x0);
517
+ x0[0] += SSY_PLANE_NODE;
518
+ x00 = x0[0] * RADTODEG; /* 7 */
519
+ for (i = 1; i <= ito; i++) /* 6, 8, 9 */
520
+ cusp[i] = swe_degnorm(cusp[i] - dvpxe - sip->ayan_t0 - x00);
521
+ for (i = 0; i <= SE_NASCMC; i++) {
522
+ if (i == 2) /* armc */
523
+ continue;
524
+ ascmc[i] = swe_degnorm(ascmc[i] - dvpxe - sip->ayan_t0 - x00);
525
+ }
526
+ if (hsys == 'N') { /* 1 = 0° Aries */
527
+ for (i = 1; i <= ito; i++) {
528
+ cusp[i] = (i - 1) * 30;
529
+ }
530
+ }
531
+ return retc;
532
+ }
533
+
534
+ /* common simplified procedure */
535
+ static int sidereal_houses_trad(double tjde,
536
+ int32 iflag,
537
+ double armc,
538
+ double eps,
539
+ double nutl,
540
+ double lat,
541
+ int hsys,
542
+ double *cusp,
543
+ double *ascmc,
544
+ double *cusp_speed,
545
+ double *ascmc_speed,
546
+ char *serr)
547
+ {
548
+ int i, retc = OK;
549
+ double ay;
550
+ int ito;
551
+ int ihs = toupper(hsys);
552
+ int ihs2 = ihs;
553
+ // ay = swe_get_ayanamsa(tjde);
554
+ //fprintf(stderr, "ay=%f\n", ay);
555
+ retc = swe_get_ayanamsa_ex(tjde, iflag, &ay, NULL);
556
+ //fprintf(stderr, "ay=%f\n", ay);
557
+ //fprintf(stderr, "nutl=%f\n", nutl);
558
+ if (ihs == 'G')
559
+ ito = 36;
560
+ else
561
+ ito = 12;
562
+ if (ihs == 'W') /* whole sign houses: treat as 'E' and fix later */
563
+ ihs2 = 'E';
564
+ //fprintf(stderr, "armc=%f\n", armc);
565
+ //if (hsys == 'P') fprintf(stderr, "ay=%f, t=%f %c", ay, tjde, (char) hsys);
566
+ retc = swe_houses_armc_ex2(armc, lat, eps, ihs2, cusp, ascmc, cusp_speed, ascmc_speed, serr);
567
+ //if (hsys == 'P') fprintf(stderr, " h1=%f", cusp[1]);
568
+ for (i = 1; i <= ito; i++) {
569
+ //cusp[i] = swe_degnorm(cusp[i] - ay - nutl);
570
+ cusp[i] = swe_degnorm(cusp[i] - ay);
571
+ if (ihs == 'W') /* whole sign houses */
572
+ cusp[i] -= fmod(cusp[i], 30);
573
+ }
574
+ if (ihs == 'N') { /* 1 = 0° Aries */
575
+ for (i = 1; i <= ito; i++) {
576
+ cusp[i] = (i - 1) * 30;
577
+ }
578
+ }
579
+ for (i = 0; i < SE_NASCMC; i++) {
580
+ if (i == 2) /* armc */
581
+ continue;
582
+ //ascmc[i] = swe_degnorm(ascmc[i] - ay - nutl);
583
+ ascmc[i] = swe_degnorm(ascmc[i] - ay);
584
+ }
585
+ //if (hsys == 'P') fprintf(stderr, " => %f\n", cusp[1]);
586
+ return retc;
587
+ }
588
+
589
+ // For explanation see function swe_houses_armc_ex2() below.
590
+ int CALL_CONV swe_houses_armc(
591
+ double armc,
592
+ double geolat,
593
+ double eps,
594
+ int hsys,
595
+ double *cusp,
596
+ double *ascmc)
597
+ {
598
+ return swe_houses_armc_ex2(armc, geolat, eps, hsys, cusp, ascmc, NULL, NULL, NULL);
599
+ }
600
+
601
+ /*
602
+ * Function returns OK or ERR.
603
+ * this function is required for very special computations
604
+ * where no date is given for house calculation,
605
+ * e.g. for composite charts or progressive charts.
606
+ * cusps are returned in double cusp[13],
607
+ * or cusp[37] with house system 'G'.
608
+ * cusp[1...12] houses 1 - 12
609
+ * ascmc[0...10] additional points:
610
+ * ascmc[0] = ascendant
611
+ * ascmc[1] = mc
612
+ * ascmc[2] = armc
613
+ * ascmc[3] = vertex
614
+ * ascmc[4] = equasc * "equatorial ascendant" *
615
+ * ascmc[5] = coasc1 * "co-ascendant" (W. Koch) *
616
+ * ascmc[6] = coasc2 * "co-ascendant" (M. Munkasey) *
617
+ * ascmc[7] = polasc * "polar ascendant" (M. Munkasey) *
618
+ * cusp_speed[1...12] speeds (daily motions) of the cusps.
619
+ * ascmc_speed[0...10] speeds (daily motions) of the additional points.
620
+ * serr error message or warning
621
+ */
622
+ int CALL_CONV swe_houses_armc_ex2(
623
+ double armc,
624
+ double geolat,
625
+ double eps,
626
+ int hsys,
627
+ double *cusp,
628
+ double *ascmc,
629
+ double *cusp_speed,
630
+ double *ascmc_speed,
631
+ char *serr)
632
+ {
633
+ struct houses h, hm1, hp1;
634
+ int i, retc = 0, rm1, rp1;
635
+ int ito;
636
+ static double saved_sundec = 99;
637
+ if (toupper(hsys) == 'G')
638
+ ito = 36;
639
+ else
640
+ ito = 12;
641
+ armc = swe_degnorm(armc);
642
+ h.do_speed = FALSE;
643
+ h.do_hspeed = FALSE;
644
+ if (ascmc_speed != NULL || cusp_speed != NULL)
645
+ h.do_speed = TRUE; // is needed if cusp_speed wanted
646
+ if (cusp_speed != NULL)
647
+ h.do_hspeed = TRUE;
648
+ if (toupper(hsys) == 'I') { // declination for sunshine houses
649
+ if (ascmc[9] == 99) {
650
+ h.sundec = 0;
651
+ if (saved_sundec != 99) h.sundec = saved_sundec;
652
+ } else {
653
+ h.sundec = ascmc[9];
654
+ saved_sundec = h.sundec;
655
+ }
656
+ if (h.sundec < -24 || h.sundec > 24) {
657
+ sprintf(serr, "House system I (Sunshine) needs valid Sun declination in ascmc[9]");
658
+ return ERR;
659
+ }
660
+ }
661
+ retc = CalcH(armc, geolat, eps, (char)hsys, &h);
662
+ cusp[0] = 0;
663
+ if (h.do_hspeed) cusp_speed[0] = 0;
664
+ // on failure, we only have 12 Porphyry cusps
665
+ if (retc < 0) {
666
+ ito = 12;
667
+ if (serr != NULL) strcpy(serr, h.serr);
668
+ }
669
+ for (i = 1; i <= ito; i++) {
670
+ cusp[i] = h.cusp[i];
671
+ if (h.do_hspeed) cusp_speed[i] = h.cusp_speed[i];
672
+ }
673
+ ascmc[0] = h.ac; /* Asc */
674
+ ascmc[1] = h.mc; /* Mid */
675
+ ascmc[2] = armc;
676
+ ascmc[3] = h.vertex;
677
+ ascmc[4] = h.equasc;
678
+ ascmc[5] = h.coasc1; /* "co-ascendant" (W. Koch) */
679
+ ascmc[6] = h.coasc2; /* "co-ascendant" (M. Munkasey) */
680
+ ascmc[7] = h.polasc; /* "polar ascendant" (M. Munkasey) */
681
+ for (i = SE_NASCMC; i < 10; i++)
682
+ ascmc[i] = 0;
683
+ if (toupper(hsys) == 'I') // declination for sunshine houses
684
+ ascmc[9] = h.sundec ;
685
+ if (h.do_speed && ascmc_speed != NULL) {
686
+ ascmc_speed[0] = h.ac_speed; /* Asc */
687
+ ascmc_speed[1] = h.mc_speed; /* Mid */
688
+ ascmc_speed[2] = h.armc_speed;
689
+ ascmc_speed[3] = h.vertex_speed;
690
+ ascmc_speed[4] = h.equasc_speed;
691
+ ascmc_speed[5] = h.coasc1_speed; /* "co-ascendant" (W. Koch) */
692
+ ascmc_speed[6] = h.coasc2_speed; /* "co-ascendant" (M. Munkasey) */
693
+ ascmc_speed[7] = h.polasc_speed; /* "polar ascendant" (M. Munkasey) */
694
+ for (i = SE_NASCMC; i < 10; i++)
695
+ ascmc_speed[i] = 0;
696
+ }
697
+ if (h.do_interpol) { // must compute cusp_speed via interpolation
698
+ double dt = 1.0 / 86400;
699
+ double darmc = dt * ARMCS;
700
+ hm1.do_speed = FALSE;
701
+ hm1.do_hspeed = FALSE;
702
+ hp1.do_speed = FALSE;
703
+ hp1.do_hspeed = FALSE;
704
+ if (toupper(hsys) == 'I') {
705
+ hm1.sundec = h.sundec;
706
+ hp1.sundec = h.sundec;
707
+ }
708
+ rm1 = CalcH(armc - darmc, geolat, eps, (char)hsys, &hm1);
709
+ rp1 = CalcH(armc + darmc, geolat, eps, (char)hsys, &hp1);
710
+ if (rp1 >= 0 && rm1 >=0) {
711
+ if (fabs(swe_difdeg2n(hp1.ac, h.ac)) > 90) {
712
+ hp1 = h; // use only upper interval
713
+ dt = dt / 2;
714
+ } else if (fabs(swe_difdeg2n(hm1.ac, h.ac)) > 90) {
715
+ hm1 = h; // use only lower interval
716
+ dt = dt / 2;
717
+ }
718
+ for (i = 1; i <= 12; i++) {
719
+ double dx = swe_difdeg2n(hp1.cusp[i], hm1.cusp[i]);
720
+ cusp_speed[i] = dx / 2 / dt ;
721
+ }
722
+ }
723
+ }
724
+ #ifdef TRACE
725
+ swi_open_trace(NULL);
726
+ if (swi_trace_count <= TRACE_COUNT_MAX) {
727
+ if (swi_fp_trace_c != NULL) {
728
+ fputs("\n/*SWE_HOUSES_ARMC_EX2*/\n", swi_fp_trace_c);
729
+ fprintf(swi_fp_trace_c, " armc = %.9f;", armc);
730
+ fprintf(swi_fp_trace_c, " geolat = %.9f;", geolat);
731
+ fprintf(swi_fp_trace_c, " eps = %.9f;", eps);
732
+ fprintf(swi_fp_trace_c, " hsys = %d;\n", hsys);
733
+ fprintf(swi_fp_trace_c, " retc = swe_houses_armc_ex2(armc, geolat, eps, hsys, cusp, ascmc, cusp_speed, ascmc_speed, serr);\n");
734
+ fputs(" printf(\"swe_houses_armc_ex2: %f\\t%f\\t%f\\t%c\\t\\n\", ", swi_fp_trace_c);
735
+ fputs(" armc, geolat, eps, hsys);\n", swi_fp_trace_c);
736
+ fputs(" printf(\"retc = %d\\n\", retc);\n", swi_fp_trace_c);
737
+ fputs(" printf(\"cusp:\\n\");\n", swi_fp_trace_c);
738
+ fputs(" for (i = 1; i <= 12; i++)\n", swi_fp_trace_c);
739
+ fputs(" printf(\" %d\\t%f\\n\", i, cusp[i]);\n", swi_fp_trace_c);
740
+ fputs(" printf(\"ascmc:\\n\");\n", swi_fp_trace_c);
741
+ fputs(" for (i = 0; i < 10; i++)\n", swi_fp_trace_c);
742
+ fputs(" printf(\" %d\\t%f\\n\", i, ascmc[i]);\n", swi_fp_trace_c);
743
+ fputs(" printf(\"cusp_speed:\\n\");\n", swi_fp_trace_c);
744
+ fputs(" for (i = 1; i <= 12; i++)\n", swi_fp_trace_c);
745
+ fputs(" printf(\" %d\\t%f\\n\", i, cusp_speed[i]);\n", swi_fp_trace_c);
746
+ fputs(" printf(\"ascmc_speed:\\n\");\n", swi_fp_trace_c);
747
+ fputs(" for (i = 0; i < 10; i++)\n", swi_fp_trace_c);
748
+ fputs(" printf(\" %d\\t%f\\n\", i, ascmc_speed[i]);\n", swi_fp_trace_c);
749
+ fflush(swi_fp_trace_c);
750
+ }
751
+ if (swi_fp_trace_out != NULL) {
752
+ fprintf(swi_fp_trace_out, "swe_houses_armc_ex2: %f\t%f\t%f\t%c\t\n", armc, geolat, eps, hsys);
753
+ fprintf(swi_fp_trace_out, "retc = %d\n", retc);
754
+ fputs("cusp:\n", swi_fp_trace_out);
755
+ for (i = 1; i <= 12; i++)
756
+ fprintf(swi_fp_trace_out, " %d\t%f\n", i, cusp[i]);
757
+ fputs("ascmc:\n", swi_fp_trace_out);
758
+ for (i = 0; i < 10; i++)
759
+ fprintf(swi_fp_trace_out, " %d\t%f\n", i, ascmc[i]);
760
+ fflush(swi_fp_trace_out);
761
+ }
762
+ }
763
+ #endif
764
+ #if 0
765
+ /* for test of swe_house_pos().
766
+ * 1st house will be 0, second 30, etc. */
767
+ for (i = 1; i <=12; i++) {
768
+ double x[6];
769
+ x[0] = cusp[i]; x[1] = 0; x[2] = 1;
770
+ cusp[i] = (swe_house_pos(armc, geolat, eps, hsys, x, NULL) - 1) * 30;
771
+ }
772
+ #endif
773
+ return retc;
774
+ }
775
+
776
+ /* for APC houses */
777
+ /* n number of house
778
+ * ph geographic latitude
779
+ * e ecliptic obliquity
780
+ * az armc
781
+ */
782
+ static double apc_sector(int n, double ph, double e, double az)
783
+ {
784
+ int k, is_below_hor = 0;
785
+ double kv, a, dasc, dret;
786
+ /* kv: ascensional difference of the ascendant */
787
+ /* dasc: declination of the ascendant */
788
+ if (fabs(ph * RADTODEG) > 90 - VERY_SMALL) {
789
+ kv = 0;
790
+ dasc = 0;
791
+ } else {
792
+ kv = atan(tan(ph) * tan(e) * cos(az)/(1 + tan(ph) * tan(e) * sin(az)));
793
+ if (fabs(ph * RADTODEG) < VERY_SMALL) {
794
+ dasc = (90 - VERY_SMALL) * DEGTORAD;
795
+ if (ph < 0)
796
+ dasc = -dasc;
797
+ } else {
798
+ dasc = atan(sin(kv) / tan(ph));
799
+ }
800
+ }
801
+ /* note, at polar circles, when the mc sinks below the horizon,
802
+ * kv and dasc change sign in the above formulae.
803
+ * this is what we need, because the ascendand jumps by 180 deg */
804
+ /* printf("%f, %f\n", kv*RADTODEG, dasc*RADTODEG); */
805
+ if (n < 8) {
806
+ is_below_hor = 1; /* 1 and 7 are included here */
807
+ k = n - 1;
808
+ } else {
809
+ k = n - 13;
810
+ }
811
+ /* az + PI/2 + kv = armc + 90 + asc. diff. = right ascension of ascendant
812
+ * PI/2 +- kv = semi-diurnal or seminocturnal arc of ascendant
813
+ * a = right ascension of house cusp on apc circle (ascendant-parallel
814
+ * circle), with declination dasc */
815
+ if (is_below_hor) {
816
+ a = kv + az + PI/2 + k * (PI/2 - kv) / 3;
817
+ } else {
818
+ a = kv + az + PI/2 + k * (PI/2 + kv) / 3;
819
+ }
820
+ a = swe_radnorm(a);
821
+ dret = atan2(tan(dasc) * tan(ph) * sin(az) + sin(a),
822
+ cos(e) * (tan(dasc) * tan(ph) * cos(az) + cos(a)) + sin(e) * tan(ph) * sin(az - a));
823
+ dret = swe_degnorm(dret * RADTODEG);
824
+ return dret;
825
+ }
826
+
827
+ const char *CALL_CONV swe_house_name(int hsys)
828
+ {
829
+ int h = hsys;
830
+ if (h != 'i') h = toupper(h);
831
+ switch (h) {
832
+ case 'A': return "equal";
833
+ case 'B': return "Alcabitius";
834
+ case 'C': return "Campanus";
835
+ case 'D': return "equal (MC)";
836
+ case 'E': return "equal";
837
+ case 'F': return "Carter poli-equ.";
838
+ case 'G': return "Gauquelin sectors";
839
+ case 'H': return "horizon/azimut";
840
+ case 'I': return "Sunshine";
841
+ case 'i': return "Sunshine/alt.";
842
+ case 'J': return "Savard-A";
843
+ case 'K': return "Koch";
844
+ case 'L': return "Pullen SD";
845
+ case 'M': return "Morinus";
846
+ case 'N': return "equal/1=Aries";
847
+ case 'O': return "Porphyry";
848
+ case 'Q': return "Pullen SR";
849
+ case 'R': return "Regiomontanus";
850
+ case 'S': return "Sripati";
851
+ case 'T': return "Polich/Page";
852
+ case 'U': return "Krusinski-Pisa-Goelzer";
853
+ case 'V': return "equal/Vehlow";
854
+ case 'W': return "equal/ whole sign";
855
+ case 'X': return "axial rotation system/Meridian houses";
856
+ case 'Y': return "APC houses";
857
+ default: return "Placidus";
858
+ }
859
+ }
860
+
861
+ // How to deal with Sunshine houses if the southern crossing point of Equator
862
+ // and Ecliptic is under the horizon:
863
+ // We follow the proposal by Dieter Koch, who wants to keep it in analogy with
864
+ // Regiomontanus, where we keep the MC above the horizon, by switching it to the north.
865
+ // This results in an clockwise sequence of house cusps in the chart.
866
+ //
867
+ // One can argue that the MC should be kept south, even when it is under the horizon.
868
+ // This would keep the sequence of houses in the chart counterclockwise as usual.
869
+ // To achieve it, the offsets on the diurnal arcs must be inverted.
870
+ #define SUNSHINE_KEEP_MC_SOUTH 0 // must be 0 or 1
871
+
872
+ double swi_armc_to_mc(double armc, double eps)
873
+ {
874
+ double tant, mc;
875
+ if (fabs(armc - 90) > VERY_SMALL
876
+ && fabs(armc - 270) > VERY_SMALL) {
877
+ tant = tand(armc);
878
+ mc = atand(tant / cosd(eps));
879
+ if (armc > 90 && armc <= 270)
880
+ mc = swe_degnorm(mc + 180);
881
+ } else {
882
+ if (fabs(armc - 90) <= VERY_SMALL)
883
+ mc = 90;
884
+ else
885
+ mc = 270;
886
+ } /* if */
887
+ return mc;
888
+ }
889
+
890
+ //#define DEBUG_PLAC_ITER 1
891
+ #define VERY_SMALL_PLAC_ITER (1.0 / 360000.0 )
892
+ static int CalcH(
893
+ double th, double fi, double ekl, char hsy, struct houses *hsp)
894
+ /* *********************************************************
895
+ * Arguments: th = sidereal time (angle 0..360 degrees
896
+ * hsy = letter code for house system;
897
+ * A equal
898
+ * E equal
899
+ * B Alcabitius
900
+ * C Campanus
901
+ * D equal (MC)
902
+ * F Carter "Poli-Equatorial"
903
+ * G 36 Gauquelin sectors
904
+ * H horizon / azimut
905
+ * I Sunshine solution Treindl
906
+ * i Sunshine solution Makransky
907
+ * J Savard-A
908
+ * K Koch
909
+ * L Pullen SD "sinusoidal delta", ex Neo-Porphyry
910
+ * M Morinus
911
+ * N equal/1=Aries
912
+ * O Porphyry
913
+ * P Placidus
914
+ * Q Pullen SR "sinusoidal ratio"
915
+ * R Regiomontanus
916
+ * S Sripati
917
+ * T Polich/Page ("topocentric")
918
+ * U Krusinski-Pisa-Goelzer
919
+ * V equal Vehlow
920
+ * W equal, whole sign
921
+ * X axial rotation system/ Meridian houses
922
+ * Y APC houses
923
+ * fi = geographic latitude
924
+ * ekl = obliquity of the ecliptic
925
+ * *********************************************************
926
+ * Koch and Placidus don't work in the polar circle.
927
+ * We swap MC/IC so that MC is always before AC in the zodiac
928
+ * We then divide the quadrants into 3 equal parts, ie apply Porphyry.
929
+ * *********************************************************
930
+ * All angles are expressed in degrees.
931
+ * Special trigonometric functions sind, cosd etc. are
932
+ * implemented for arguments in degrees.
933
+ ***********************************************************/
934
+ {
935
+ double tane, tanfi, cosfi, sinfi, tant, sina, cosa, th2;
936
+ double a, c, f, fh1, fh2, xh1, xh2, xs1, xs2, rectasc, ad3, acmc, vemc;
937
+ int i, ih, ih2, retc = OK;
938
+ double sine, cose;
939
+ double x[3], krHorizonLon; /* BK 14.02.2006 */
940
+ int niter_max = 100; // maximum iterations allowed with Placidus
941
+ double cuspsv;
942
+ *hsp->serr = '\0';
943
+ hsp->do_interpol = 0;
944
+ cose = cosd(ekl);
945
+ sine = sind(ekl);
946
+ tane = tand(ekl);
947
+ /* north and south poles */
948
+ if (fabs(fabs(fi) - 90) < VERY_SMALL) {
949
+ if (fi < 0)
950
+ fi = -90 + VERY_SMALL;
951
+ else
952
+ fi = 90 - VERY_SMALL;
953
+ }
954
+ tanfi = tand(fi);
955
+ /* mc */
956
+ if (fabs(th - 90) > VERY_SMALL
957
+ && fabs(th - 270) > VERY_SMALL) {
958
+ tant = tand(th);
959
+ hsp->mc = atand(tant / cose);
960
+ if (th > 90 && th <= 270)
961
+ hsp->mc = swe_degnorm(hsp->mc + 180);
962
+ } else {
963
+ if (fabs(th - 90) <= VERY_SMALL)
964
+ hsp->mc = 90;
965
+ else
966
+ hsp->mc = 270;
967
+ } /* if */
968
+ hsp->mc = swe_degnorm(hsp->mc);
969
+ if (hsp->do_speed) hsp->mc_speed = AscDash(th, 0, sine, cose);
970
+ /* ascendant */
971
+ hsp->ac = Asc1(th + 90, fi, sine, cose);
972
+ if (hsp->do_speed)
973
+ hsp->ac_speed = AscDash(th + 90, fi, sine, cose);
974
+ if (hsp->do_hspeed) {
975
+ for (i = 0; i <= 12; i++)
976
+ hsp->cusp_speed[i] = 0;
977
+ }
978
+ hsp->armc_speed = ARMCS;
979
+ // these cusp[1] and cusp[10] values may be changed further down for some house systems
980
+ hsp->cusp[1] = hsp->ac;
981
+ hsp->cusp[10] = hsp->mc;
982
+ if (hsp->do_hspeed) {
983
+ hsp->cusp_speed[1] = hsp->ac_speed;
984
+ hsp->cusp_speed[10] = hsp->mc_speed;
985
+ }
986
+ /* we respect smaller case letter for i, otherwise they are deprecated */
987
+ if (hsy > 95 && hsy != 'i') {
988
+ sprintf(hsp->serr, "use of lower case letters like %c for house systems is deprecated", hsy);
989
+ hsy = (char) (hsy - 32);/* translate into capital letter */
990
+ }
991
+ switch (hsy) {
992
+ case 'A': /* equal houses */
993
+ case 'E':
994
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
995
+ if (acmc < 0) {
996
+ /* within polar circle we swap AC/DC if AC is on wrong side */
997
+ hsp->ac = swe_degnorm(hsp->ac + 180);
998
+ hsp->cusp[1] = hsp->ac;
999
+ }
1000
+ for (i = 2; i <=12; i++) {
1001
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[1] + (i-1) * 30);
1002
+ }
1003
+ if (hsp->do_hspeed) {
1004
+ for (i = 1; i <=12; i++) {
1005
+ hsp->cusp_speed[i] = hsp->ac_speed;
1006
+ }
1007
+ }
1008
+ break;
1009
+ case 'D': /* equal, begin at MC */
1010
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1011
+ if (acmc < 0) {
1012
+ /* within polar circle we swap AC/DC if AC is on wrong side */
1013
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1014
+ }
1015
+ hsp->cusp[10] = hsp->mc;
1016
+ for (i = 11; i <= 12; i++)
1017
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[10] + (i-10) * 30);
1018
+ for (i = 1; i <= 9; i++)
1019
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[10] + (i + 2) * 30);
1020
+ if (hsp->do_hspeed) {
1021
+ for (i = 1; i <=12; i++) {
1022
+ hsp->cusp_speed[i] = hsp->mc_speed;
1023
+ }
1024
+ }
1025
+ break;
1026
+ case 'C': // Campanus houses:
1027
+ // Prime vertical is divided into 3 parts of 30° each, great circles from
1028
+ // north point to south point go through these points and intersect ecliptic.
1029
+ // pole height = shortest distance of plane from North pole,
1030
+ // measured along declination circle.
1031
+ // NP = North Pole, N = north point, P11 = house 11 point in prime vertical
1032
+ // triangle NP - N - P11 , angle 30 at N, side fi between NP and N
1033
+ // sin fh1 = sin fi * sin 30°,
1034
+ fh1 = asind(sind (fi) / 2);
1035
+ // triangle NP - N - P12 , angle 60 at N, side fi between NP and N
1036
+ // sin fh2 = sin fi * sin 60°,
1037
+ fh2 = asind(sqrt (3.0) / 2 * sind(fi));
1038
+ cosfi = cosd(fi);
1039
+ if (fabs(cosfi) == 0) { /* '==' should be save! */
1040
+ if (fi > 0)
1041
+ xh1 = xh2 = 90; /* cosfi = VERY_SMALL; */
1042
+ else
1043
+ xh1 = xh2 = 270; /* cosfi = -VERY_SMALL; */
1044
+ } else {
1045
+ // triangle formed by equator, prime vertical, great circle
1046
+ // through P11, S and N
1047
+ // with right angle between prime vertical and great circle
1048
+ // side length xh1 on equ, 60 on prime vertical, angle fi between
1049
+ // tan xh1 = tan 60 / cos fi = √3 / cos fi
1050
+ xh1 = atand(sqrt (3.0) / cosfi);
1051
+ // side length xh2 on equ, 30° on prime vertical, angle fi between
1052
+ // tan xh2 = tan 30 / cos fi = 1/√3 / cos fi
1053
+ xh2 = atand(1 / sqrt (3.0) / cosfi);
1054
+ }
1055
+ hsp->cusp[11] = Asc1(th + 90 - xh1, fh1, sine, cose);
1056
+ hsp->cusp[12] = Asc1(th + 90 - xh2, fh2, sine, cose);
1057
+ hsp->cusp[2] = Asc1(th + 90 + xh2, fh2, sine, cose);
1058
+ hsp->cusp[3] = Asc1(th + 90 + xh1, fh1, sine, cose);
1059
+ if (hsp->do_hspeed) {
1060
+ hsp->cusp_speed[11] = AscDash(th + 90 - xh1, fh1, sine, cose);
1061
+ hsp->cusp_speed[12] = AscDash(th + 90 - xh2, fh2, sine, cose);
1062
+ hsp->cusp_speed[2] = AscDash(th + 90 + xh2, fh2, sine, cose);
1063
+ hsp->cusp_speed[3] = AscDash(th + 90 + xh1, fh1, sine, cose);
1064
+ }
1065
+ /* within polar circle, when mc sinks below horizon and
1066
+ * ascendant changes to western hemisphere, all cusps
1067
+ * must be added 180 degrees.
1068
+ * houses will be in clockwise direction */
1069
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
1070
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1071
+ if (acmc < 0) {
1072
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1073
+ hsp->mc = swe_degnorm(hsp->mc + 180);
1074
+ for (i = 1; i <= 12; i++) {
1075
+ if (i >= 4 && i < 10) continue;
1076
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
1077
+ }
1078
+ }
1079
+ }
1080
+ break;
1081
+ case 'H': /* Horizon or Azimut system, similar to Campanus calulation */
1082
+ if (fi > 0)
1083
+ fi = 90 - fi;
1084
+ else
1085
+ fi = -90 - fi;
1086
+ /* equator */
1087
+ if (fabs(fabs(fi) - 90) < VERY_SMALL) {
1088
+ if (fi < 0)
1089
+ fi = -90 + VERY_SMALL;
1090
+ else
1091
+ fi = 90 - VERY_SMALL;
1092
+ }
1093
+ th = swe_degnorm(th + 180);
1094
+ fh1 = asind(sind (fi) / 2);
1095
+ fh2 = asind(sqrt (3.0) / 2 * sind(fi));
1096
+ cosfi = cosd(fi);
1097
+ if (fabs(cosfi) == 0) { /* '==' should be save! */
1098
+ if (fi > 0)
1099
+ xh1 = xh2 = 90; /* cosfi = VERY_SMALL; */
1100
+ else
1101
+ xh1 = xh2 = 270; /* cosfi = -VERY_SMALL; */
1102
+ } else {
1103
+ // triangle formed by equator, prime vertical, declination circle,
1104
+ // with right angle between equator and declination circle:
1105
+ // side length xh1 on equ, 60 on prime vertical, angle fi between
1106
+ // tan xh1 = tan 60 / cos fi = √3 / cos fi
1107
+ xh1 = atand(sqrt (3.0) / cosfi);
1108
+ // side length xh2 on equ, 30° on prime vertical, angle fi between
1109
+ // tan xh2 = tan 30 / cos fi = 1/√3 / cos fi
1110
+ xh2 = atand(1 / sqrt (3.0) / cosfi);
1111
+ }
1112
+ hsp->cusp[11] = Asc1(th + 90 - xh1, fh1, sine, cose);
1113
+ hsp->cusp[12] = Asc1(th + 90 - xh2, fh2, sine, cose);
1114
+ hsp->cusp[1] = Asc1(th + 90, fi, sine, cose);
1115
+ hsp->cusp[2] = Asc1(th + 90 + xh2, fh2, sine, cose);
1116
+ hsp->cusp[3] = Asc1(th + 90 + xh1, fh1, sine, cose);
1117
+ if (hsp->do_hspeed) {
1118
+ hsp->cusp_speed[11] = AscDash(th + 90 - xh1, fh1, sine, cose);
1119
+ hsp->cusp_speed[12] = AscDash(th + 90 - xh2, fh2, sine, cose);
1120
+ hsp->cusp_speed[1] = AscDash(th + 90, fi, sine, cose);
1121
+ hsp->cusp_speed[2] = AscDash(th + 90 + xh2, fh2, sine, cose);
1122
+ hsp->cusp_speed[3] = AscDash(th + 90 + xh1, fh1, sine, cose);
1123
+ }
1124
+ /* within polar circle, when mc sinks below horizon and
1125
+ * ascendant changes to western hemisphere, all cusps
1126
+ * must be added 180 degrees.
1127
+ * houses will be in clockwise direction */
1128
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
1129
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1130
+ if (acmc < 0) {
1131
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1132
+ hsp->mc = swe_degnorm(hsp->mc + 180);
1133
+ for (i = 1; i <= 12; i++) {
1134
+ if (i >= 4 && i < 10) continue;
1135
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
1136
+ }
1137
+ }
1138
+ }
1139
+ for (i = 1; i <= 3; i++)
1140
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
1141
+ for (i = 11; i <= 12; i++)
1142
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
1143
+ /* restore fi and th */
1144
+ if (fi > 0)
1145
+ fi = 90 - fi;
1146
+ else
1147
+ fi = -90 - fi;
1148
+ th = swe_degnorm(th + 180);
1149
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1150
+ if (acmc < 0) {
1151
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1152
+ }
1153
+ break;
1154
+ case 'I': /* Sunshine houses, solution Treindl */
1155
+ case 'i': /* Sunshine houses, solution Makranski */
1156
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1157
+ if (acmc < 0) {
1158
+ /* we shift axes */
1159
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1160
+ hsp->cusp[1] = hsp->ac;
1161
+ if (! SUNSHINE_KEEP_MC_SOUTH && hsy == 'I') {
1162
+ hsp->mc = swe_degnorm(hsp->mc + 180);
1163
+ hsp->cusp[10] = hsp->mc;
1164
+ }
1165
+ }
1166
+ hsp->cusp[4] = swe_degnorm(hsp->cusp[10] + 180);
1167
+ hsp->cusp[7] = swe_degnorm(hsp->cusp[1] + 180);
1168
+ if (hsy == 'I') {
1169
+ retc = sunshine_solution_treindl(th, fi, ekl, hsp);
1170
+ } else {
1171
+ retc = sunshine_solution_makransky(th, fi, ekl, hsp);
1172
+ }
1173
+ if (retc == ERR) { // only Makransky version does this
1174
+ strcpy(hsp->serr, "within polar circle, switched to Porphyry");
1175
+ hsy = 'O';
1176
+ goto porphyry;
1177
+ }
1178
+ hsp->do_interpol = hsp->do_hspeed;
1179
+ break;
1180
+ case 'J': /* Savard's supposed Albategnius houses */
1181
+ // house 11: latitude circle at 2/3 fi intersects prime meridian at p11.
1182
+ // house 12: latitude circle at fi / 3 intersects prime meridian at p12.
1183
+ // triangle X-p12-E formed by equator, prime vertical, declination circle,
1184
+ // side length xs1 or xs2 on prime vertical, 2/3 fi or fi/3 on declination circle,
1185
+ // angle fi between prime vertical and equator at E, right angle between equator
1186
+ // and declination circle.
1187
+ // sin b = sin B sin c, with b = 1/3 or 2/3 fi, B = fi
1188
+ sinfi = sind(fi);
1189
+ cosfi = cosd(fi);
1190
+ if (fabs(fi) < VERY_SMALL) {
1191
+ xs2 = 1 / 3.0;
1192
+ xs1 = 2 / 3.0;
1193
+ } else {
1194
+ xs2 = sind(fi / 3) / sinfi;
1195
+ xs1 = sind(2 * fi / 3) / sinfi;
1196
+ }
1197
+ xs2 = asind(xs2);
1198
+ xs1 = asind(xs1);
1199
+ // now consider triangle great circle through h11, equ, prime vertical, with
1200
+ // right angle between prime vertical and great circle
1201
+ // side length xh1 on equ, xs1 on prime vertical, angle fi between
1202
+ // tan xh1 = tan xs1 / cos fi
1203
+ if (cosfi == 0) {
1204
+ if (fi > 0)
1205
+ xh1 = xh2 = 90;
1206
+ else
1207
+ xh1 = xh2 = 270;
1208
+ } else {
1209
+ xh1 = atand(tand(xs1) / cosfi);
1210
+ xh2 = atand(tand(xs2) / cosfi);
1211
+ }
1212
+ // Pole height:
1213
+ // great circle S - p11 - N has angle 90 - xs1 on North or South point,
1214
+ // north point to south point go through these points and intersect ecliptic.
1215
+ // pole height = shortest distance of plane from North pole,
1216
+ // measured along declination circle.
1217
+ // NP = North Pole, N = north point, H11 = house 11 point in prime vertical
1218
+ // triangle NP - N - h11 , angle xs1 at N, side fi between NP and N
1219
+ // sin fh1 = sin fi * sin (90 - xs1),
1220
+ fh1 = asind(sind (fi) * sind(90 - xs1));
1221
+ fh2 = asind(sind (fi) * sind(90 - xs2));
1222
+ hsp->cusp[12] = Asc1(th + 90 - xh2, fh2, sine, cose);
1223
+ hsp->cusp[11] = Asc1(th + 90 - xh1, fh1, sine, cose);
1224
+ hsp->cusp[2] = Asc1(th + 90 + xh2, fh2, sine, cose);
1225
+ hsp->cusp[3] = Asc1(th + 90 + xh1, fh1, sine, cose);
1226
+ if (hsp->do_hspeed) {
1227
+ hsp->cusp_speed[11] = AscDash(th + 90 - xh1, fh1, sine, cose);
1228
+ hsp->cusp_speed[12] = AscDash(th + 90 - xh2, fh2, sine, cose);
1229
+ hsp->cusp_speed[3] = AscDash(th + 90 + xh1, fh1, sine, cose);
1230
+ hsp->cusp_speed[2] = AscDash(th + 90 + xh2, fh2, sine, cose);
1231
+ }
1232
+ /* within polar circle, when mc sinks below horizon and
1233
+ * ascendant changes to western hemisphere, all cusps
1234
+ * must be added 180 degrees.
1235
+ * houses will be in clockwise direction */
1236
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
1237
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1238
+ if (acmc < 0) {
1239
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1240
+ hsp->mc = swe_degnorm(hsp->mc + 180);
1241
+ for (i = 1; i <= 12; i++) {
1242
+ if (i >= 4 && i < 10) continue;
1243
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
1244
+ }
1245
+ }
1246
+ }
1247
+ break;
1248
+ case 'K': /* Koch houses */
1249
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
1250
+ retc = ERR;
1251
+ strcpy(hsp->serr, "within polar circle, switched to Porphyry");
1252
+ goto porphyry;
1253
+ }
1254
+ sina = sind(hsp->mc) * sine / cosd(fi);
1255
+ if (sina > 1) sina = 1;
1256
+ if (sina < -1) sina = -1;
1257
+ cosa = sqrt(1 - sina * sina); /* always >> 0 */
1258
+ c = atand(tanfi / cosa);
1259
+ ad3 = asind(sind(c) * sina) / 3.0;
1260
+ hsp->cusp[11] = Asc1(th + 30 - 2 * ad3, fi, sine, cose);
1261
+ hsp->cusp[12] = Asc1(th + 60 - ad3, fi, sine, cose);
1262
+ hsp->cusp[2] = Asc1(th + 120 + ad3, fi, sine, cose);
1263
+ hsp->cusp[3] = Asc1(th + 150 + 2 * ad3, fi, sine, cose);
1264
+ if (hsp->do_hspeed) {
1265
+ hsp->cusp_speed[11] = AscDash(th + 30 - 2 * ad3, fi, sine, cose);
1266
+ hsp->cusp_speed[12] = AscDash(th + 60 - ad3, fi, sine, cose);
1267
+ hsp->cusp_speed[2] = AscDash(th + 120 + ad3, fi, sine, cose);
1268
+ hsp->cusp_speed[3] = AscDash(th + 150 + 2 * ad3, fi, sine, cose);
1269
+ }
1270
+ break;
1271
+ case 'L': /* Pullen SD sinusoidal delta, ex Neo-Porphyry */
1272
+ {
1273
+ double d, q1;
1274
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1275
+ if (acmc < 0) {
1276
+ /* within polar circle we swap AC/DC if AC is on wrong side */
1277
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1278
+ hsp->cusp[1] = hsp->ac;
1279
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1280
+ }
1281
+ q1 = 180 - acmc;
1282
+ d = (acmc - 90) / 4.0;
1283
+ if (acmc <= 30) { // is quadrant <= 30, house 11 = zero width.
1284
+ hsp->cusp[11] = hsp->cusp[12] = swe_degnorm(hsp->mc + acmc / 2);
1285
+ } else {
1286
+ hsp->cusp[11] = swe_degnorm(hsp->mc + 30 + d);
1287
+ hsp->cusp[12] = swe_degnorm(hsp->mc + 60 + 3 * d);
1288
+ }
1289
+ d = (q1 - 90) / 4.0;
1290
+ if (q1 <= 30) { // is quadrant <= 30, house 2 = zero width.
1291
+ hsp->cusp[2] = hsp->cusp[3] = swe_degnorm(hsp->ac + q1 / 2);
1292
+ } else {
1293
+ hsp->cusp[2] = swe_degnorm(hsp->ac + 30 + d);
1294
+ hsp->cusp[3] = swe_degnorm(hsp->ac + 60 + 3 * d);
1295
+ }
1296
+ }
1297
+ hsp->do_interpol = hsp->do_hspeed;
1298
+ break;
1299
+ case 'N': /* whole signs, begin at 0° Aries */
1300
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1301
+ if (acmc < 0) {
1302
+ /* within polar circle we swap AC/DC if AC is on wrong side */
1303
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1304
+ }
1305
+ for (i = 1; i <= 12; i++)
1306
+ hsp->cusp[i] = (i - 1) * 30.0;
1307
+ break;
1308
+ case 'O': /* Porphyry houses */
1309
+ porphyry:
1310
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1311
+ if (acmc < 0) {
1312
+ /* within polar circle we swap AC/DC if AC is on wrong side */
1313
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1314
+ hsp->cusp[1] = hsp->ac;
1315
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1316
+ }
1317
+ hsp->cusp[1] = hsp->ac; // may have been destroyed if defaulting from Gauquelin
1318
+ hsp->cusp[10] = hsp->mc; // dito
1319
+ hsp->cusp[2] = swe_degnorm(hsp->ac + (180 - acmc) / 3);
1320
+ hsp->cusp[3] = swe_degnorm(hsp->ac + (180 - acmc) / 3 * 2);
1321
+ hsp->cusp[11] = swe_degnorm(hsp->mc + acmc / 3);
1322
+ hsp->cusp[12] = swe_degnorm(hsp->mc + acmc / 3 * 2);
1323
+ if (hsp->do_hspeed) {
1324
+ double q1_speed = hsp->ac_speed - hsp->mc_speed; // rate of growth of quadrant 1
1325
+ // double q4_speed = hsp->mc_speed - hsp->ac_speed; // rate of growth of quadrant 4
1326
+ hsp->cusp_speed[1] = hsp->ac_speed; // may have been destroyed if defaulting from Gauquelin
1327
+ hsp->cusp_speed[10] = hsp->mc_speed; // dito
1328
+ hsp->cusp_speed[2] = hsp->ac_speed - q1_speed / 3;
1329
+ hsp->cusp_speed[3] = hsp->ac_speed - q1_speed / 3 * 2;
1330
+ hsp->cusp_speed[11] = hsp->ac_speed + q1_speed / 3;
1331
+ hsp->cusp_speed[12] = hsp->ac_speed + q1_speed / 3 * 2;
1332
+ }
1333
+ break;
1334
+ case 'Q': /* Pullen sinusoidal ratio */
1335
+ {
1336
+ double q, c, csq, ccr, cqx, two23, third, r, r1, r2, x, xr, xr3, xr4;
1337
+ third = 1.0 / 3.0;
1338
+ two23 = pow(2.0 * 2.0, third); // 2^(2/3)
1339
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1340
+ if (acmc < 0) {
1341
+ /* within polar circle we swap AC/DC if AC is on wrong side */
1342
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1343
+ hsp->cusp[1] = hsp->ac;
1344
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1345
+ }
1346
+ q = acmc;
1347
+ if (q > 90) q = 180 - q;
1348
+ if (q < 1e-30) { // degenerate case of quadrant = zer0
1349
+ // r = INFINITY;
1350
+ x = xr = xr3 = 0;
1351
+ xr4 = 180;
1352
+ } else {
1353
+ c = (180 - q) / q;
1354
+ csq = c * c;
1355
+ ccr = pow(csq - c, third); // cuberoot(c^2 -c)
1356
+ cqx = sqrt(two23 * ccr + 1.0); // sqrt{2^(2/3)*cuberoot(c^2-c) + 1}
1357
+ r1 = 0.5 * cqx;
1358
+ r2 = 0.5 * sqrt(-2*(1-2*c) / cqx - two23 * ccr + 2);
1359
+ r = r1 + r2 - 0.5;
1360
+ x = q / (2 * r + 1);
1361
+ xr = r * x;
1362
+ xr3 = xr * r * r;
1363
+ xr4 = xr3 * r;
1364
+ }
1365
+ if (acmc > 90) {
1366
+ hsp->cusp[11] = swe_degnorm(hsp->mc + xr3); // house 10 and 12 size xr^3
1367
+ hsp->cusp[12] = swe_degnorm(hsp->cusp[11] + xr4); // house 11 size xr^4
1368
+ hsp->cusp[2] = swe_degnorm(hsp->ac + xr); // house 1 and 3 size xr
1369
+ hsp->cusp[3] = swe_degnorm(hsp->cusp[2] + x); // house 2 size x
1370
+ } else {
1371
+ hsp->cusp[11] = swe_degnorm(hsp->mc + xr); // house 10 and 12 size xr
1372
+ hsp->cusp[12] = swe_degnorm(hsp->cusp[11] + x); // house 11 size x
1373
+ hsp->cusp[2] = swe_degnorm(hsp->ac + xr3); // house 1 and 3 size xr^3
1374
+ hsp->cusp[3] = swe_degnorm(hsp->cusp[2] + xr4); // house 2 size xr^4
1375
+ }
1376
+ }
1377
+ hsp->do_interpol = hsp->do_hspeed;
1378
+ break;
1379
+ case 'R': /* Regiomontanus houses */
1380
+ fh1 = atand (tanfi * 0.5);
1381
+ fh2 = atand (tanfi * cosd(30));
1382
+ hsp->cusp[11] = Asc1(30 + th, fh1, sine, cose);
1383
+ hsp->cusp[12] = Asc1(60 + th, fh2, sine, cose);
1384
+ hsp->cusp[2] = Asc1(120 + th, fh2, sine, cose);
1385
+ hsp->cusp[3] = Asc1(150 + th, fh1, sine, cose);
1386
+ if (hsp->do_hspeed) {
1387
+ hsp->cusp_speed[11] = AscDash(30 + th, fh1, sine, cose);
1388
+ hsp->cusp_speed[12] = AscDash(60 + th, fh2, sine, cose);
1389
+ hsp->cusp_speed[2] = AscDash(120 + th, fh2, sine, cose);
1390
+ hsp->cusp_speed[3] = AscDash(150 + th, fh1, sine, cose);
1391
+ }
1392
+ /* within polar circle, when mc sinks below horizon and
1393
+ * ascendant changes to western hemisphere, all cusps
1394
+ * must be added 180 degrees.
1395
+ * houses will be in clockwise direction */
1396
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
1397
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1398
+ if (acmc < 0) {
1399
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1400
+ hsp->mc = swe_degnorm(hsp->mc + 180);
1401
+ for (i = 1; i <= 12; i++) {
1402
+ if (i >= 4 && i < 10) continue;
1403
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
1404
+ }
1405
+ }
1406
+ }
1407
+ break;
1408
+ case 'S': /* Sripati houses */
1409
+ /* uses Porphyry sectors, but then takes middle of sectors as cusps */
1410
+ {
1411
+ double s1, s4, q1;
1412
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc); // size of 4th quadrant
1413
+ if (acmc < 0) {
1414
+ /* within polar circle we swap AC/DC if AC is on wrong side */
1415
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1416
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1417
+ }
1418
+ q1 = 180 - acmc; // size of 1st quadrant
1419
+ s1 = q1 / 3.0;
1420
+ s4 = acmc / 3.0;
1421
+ hsp->cusp[1] = swe_degnorm(hsp->ac - s4 * 0.5);
1422
+ hsp->cusp[2] = swe_degnorm(hsp->ac + s1 * 0.5);
1423
+ hsp->cusp[3] = swe_degnorm(hsp->ac + s1 * 1.5);
1424
+ hsp->cusp[10] = swe_degnorm(hsp->mc - s1 * 0.5);
1425
+ hsp->cusp[11] = swe_degnorm(hsp->mc + s4 * 0.5);
1426
+ hsp->cusp[12] = swe_degnorm(hsp->mc + s4 * 1.5);
1427
+ }
1428
+ hsp->do_interpol = hsp->do_hspeed;
1429
+ break;
1430
+ case 'T': /* 'topocentric' houses */
1431
+ fh1 = atand (tanfi / 3.0);
1432
+ fh2 = atand (tanfi * 2.0 / 3.0);
1433
+ hsp->cusp[11] = Asc1(30 + th, fh1, sine, cose);
1434
+ hsp->cusp[12] = Asc1(60 + th, fh2, sine, cose);
1435
+ hsp->cusp[2] = Asc1(120 + th, fh2, sine, cose);
1436
+ hsp->cusp[3] = Asc1(150 + th, fh1, sine, cose);
1437
+ if (hsp->do_hspeed) {
1438
+ hsp->cusp_speed[11] = AscDash(30 + th, fh1, sine, cose);
1439
+ hsp->cusp_speed[12] = AscDash(60 + th, fh2, sine, cose);
1440
+ hsp->cusp_speed[2] = AscDash(120 + th, fh2, sine, cose);
1441
+ hsp->cusp_speed[3] = AscDash(150 + th, fh1, sine, cose);
1442
+ }
1443
+ /* within polar circle, when mc sinks below horizon and
1444
+ * ascendant changes to western hemisphere, all cusps
1445
+ * must be added 180 degrees.
1446
+ * houses will be in clockwise direction */
1447
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
1448
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1449
+ if (acmc < 0) {
1450
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1451
+ hsp->mc = swe_degnorm(hsp->mc + 180);
1452
+ for (i = 1; i <= 12; i++)
1453
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
1454
+ }
1455
+ }
1456
+ break;
1457
+ case 'V': /* equal houses after Vehlow */
1458
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1459
+ if (acmc < 0) {
1460
+ /* within polar circle we swap AC/DC if AC is on wrong side */
1461
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1462
+ }
1463
+ hsp->cusp[1] = swe_degnorm(hsp->ac - 15);
1464
+ for (i = 2; i <=12; i++)
1465
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[1] + (i-1) * 30);
1466
+ if (hsp->do_hspeed) {
1467
+ for (i = 1; i <=12; i++) {
1468
+ hsp->cusp_speed[i] = hsp->ac_speed;
1469
+ }
1470
+ }
1471
+ break;
1472
+ case 'W': /* equal, whole-sign houses */
1473
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1474
+ if (acmc < 0) {
1475
+ /* within polar circle we swap AC/DC if AC is on wrong side */
1476
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1477
+ hsp->cusp[1] = hsp->ac;
1478
+ }
1479
+ hsp->cusp[1] = hsp->ac - fmod(hsp->ac, 30);
1480
+ for (i = 2; i <=12; i++)
1481
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[1] + (i-1) * 30);
1482
+ break;
1483
+ case 'X': {
1484
+ /*
1485
+ * Meridian or axial rotation system:
1486
+ * ecliptic points whose rectascensions
1487
+ * are armc + n * 30
1488
+ */
1489
+ int j;
1490
+ double a = th;
1491
+ for (i = 1; i <= 12; i++) {
1492
+ j = i + 10;
1493
+ if (j > 12) j -= 12;
1494
+ a = swe_degnorm(a + 30);
1495
+ if (fabs(a - 90) > VERY_SMALL
1496
+ && fabs(a - 270) > VERY_SMALL) {
1497
+ tant = tand(a);
1498
+ hsp->cusp[j] = atand(tant / cose);
1499
+ if (a > 90 && a <= 270)
1500
+ hsp->cusp[j] = swe_degnorm(hsp->cusp[j] + 180);
1501
+ } else {
1502
+ if (fabs(a - 90) <= VERY_SMALL)
1503
+ hsp->cusp[j] = 90;
1504
+ else
1505
+ hsp->cusp[j] = 270;
1506
+ } /* if */
1507
+ hsp->cusp[j] = swe_degnorm(hsp->cusp[j]);
1508
+ }
1509
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1510
+ if (acmc < 0) {
1511
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1512
+ }
1513
+ hsp->do_interpol = hsp->do_hspeed;
1514
+ break; }
1515
+ case 'M': {
1516
+ /*
1517
+ * Morinus
1518
+ * points of the equator (armc + n * 30) are transformed
1519
+ * into the ecliptic coordinate system
1520
+ */
1521
+ int j;
1522
+ double a = th;
1523
+ double x[3];
1524
+ for (i = 1; i <= 12; i++) {
1525
+ j = i + 10;
1526
+ if (j > 12) j -= 12;
1527
+ a = swe_degnorm(a + 30);
1528
+ x[0] = a;
1529
+ x[1] = 0;
1530
+ swe_cotrans(x, x, ekl);
1531
+ hsp->cusp[j] = x[0];
1532
+ }
1533
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1534
+ if (acmc < 0) {
1535
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1536
+ }
1537
+ hsp->do_interpol = hsp->do_hspeed;
1538
+ break; }
1539
+ case 'F': {
1540
+ /*
1541
+ * Carter poli-equatorial
1542
+ * Rectascension a of ascendant is the starting point.
1543
+ * house cusps nh on the ecliptic are the points where
1544
+ * great circles through points of the equator (a + (nh -1) * 30)
1545
+ * and the poles intersect it.
1546
+ */
1547
+ double a, ra;
1548
+ double x[3];
1549
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1550
+ if (acmc < 0) {
1551
+ /* within polar circle we swap AC/DC if AC is on wrong side */
1552
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1553
+ hsp->cusp[1] = hsp->ac;
1554
+ }
1555
+ x[0] = hsp->ac;
1556
+ x[1] = 0;
1557
+ swe_cotrans(x, x, -ekl);
1558
+ a = x[0]; /* rectascension of ascendant */
1559
+ for (i = 2; i <= 12; i++) {
1560
+ if (i <= 3 || i >= 10) {
1561
+ ra = swe_degnorm(a + (i - 1) * 30);
1562
+ if (fabs(ra - 90) > VERY_SMALL
1563
+ && fabs(ra - 270) > VERY_SMALL) {
1564
+ tant = tand(ra);
1565
+ hsp->cusp[i] = atand(tant / cose);
1566
+ if (ra > 90 && ra <= 270)
1567
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
1568
+ } else {
1569
+ if (fabs(ra - 90) <= VERY_SMALL)
1570
+ hsp->cusp[i] = 90;
1571
+ else
1572
+ hsp->cusp[i] = 270;
1573
+ } /* if */
1574
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i]);
1575
+ }
1576
+ }
1577
+ hsp->do_interpol = hsp->do_hspeed;
1578
+ break; }
1579
+ case 'B': { /* Alcabitius */
1580
+ // created by Alois 17-sep-2000, followed example in Matrix
1581
+ // electrical library. The code reproduces the example!
1582
+ // This corresponds to Munkasey 'The Alcibitius Semiarc House System'
1583
+ // as described in his Astrological House Formulae'
1584
+ double dek, r, sna, sda, sn3, sd3;
1585
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1586
+ if (acmc < 0) {
1587
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1588
+ hsp->cusp[1] = hsp->ac;
1589
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1590
+ }
1591
+ dek = asind(sind(hsp->ac) * sine); /* declination of Ascendant */
1592
+ // triangle horizon - decl circle - equator, right angle between equ and
1593
+ // decl circle, angle 90 - fi between horizon and equator A, decl = a
1594
+ // tan a = sin b tan A, sin b = tan decl * cot (90-fi) = tan decl * tan fi
1595
+ // We want semidiurnal circle 90 + b; cos (90 + b) = - sin b = r = -tan decl * tan fi
1596
+ // sda = arccos r
1597
+ // case fi == 90 or -90 is dealt with at entry into function
1598
+ r = -tanfi * tand(dek);
1599
+ // must treat the case of abs(r) > 1; happens very rarely
1600
+ // because dek becomes smaller when fi is large, as ac is close to
1601
+ // zero Aries/Libra in that case.
1602
+ if (r > 1) r = 1;
1603
+ if (r < -1) r = -1;
1604
+ sda = acosd(r); // semidiurnal arc, measured on equator
1605
+ sna = 180 - sda; // complement, seminocturnal arc
1606
+ sd3 = sda / 3;
1607
+ sn3 = sna / 3;
1608
+ rectasc = swe_degnorm(th + sd3); /* cusp 11 */
1609
+ // project rectasc onto eclipitic with pole height 0, i.e. along the
1610
+ // declination circle
1611
+ hsp->cusp[11] = Asc1(rectasc, 0, sine, cose);
1612
+ rectasc = swe_degnorm(th + 2 * sd3); /* cusp 12 */
1613
+ hsp->cusp[12] = Asc1(rectasc, 0, sine, cose);
1614
+ rectasc = swe_degnorm(th + 180 - 2 * sn3); /* cusp 2 */
1615
+ hsp->cusp[2] = Asc1(rectasc, 0, sine, cose);
1616
+ rectasc = swe_degnorm(th + 180 - sn3); /* cusp 3 */
1617
+ hsp->cusp[3] = Asc1(rectasc, 0, sine, cose);
1618
+ }
1619
+ hsp->do_interpol = hsp->do_hspeed;
1620
+ break;
1621
+ case 'G': /* 36 Gauquelin sectors */
1622
+ for (i = 1; i <= 36; i++) {
1623
+ hsp->cusp[i] = 0;
1624
+ hsp->cusp_speed[i] = 0;
1625
+ }
1626
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
1627
+ retc = ERR;
1628
+ strcpy(hsp->serr, "within polar circle, switched to Porphyry");
1629
+ hsy = (int) 'O';
1630
+ goto porphyry;
1631
+ }
1632
+ /*************** forth/second quarter ***************/
1633
+ /* note: Gauquelin sectors are counted in clockwise direction */
1634
+ a = asind(tand(fi) * tane);
1635
+ for (ih = 2; ih <= 9; ih++) {
1636
+ ih2 = 10 - ih;
1637
+ fh1 = atand(sind(a * ih2 / 9) / tane);
1638
+ rectasc = swe_degnorm((90 / 9) * ih2 + th);
1639
+ tant = tand(asind(sine * sind(Asc1(rectasc, fh1, sine, cose))));
1640
+ if (fabs(tant) < VERY_SMALL) {
1641
+ hsp->cusp[ih] = rectasc;
1642
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1643
+ } else {
1644
+ /* pole height */
1645
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) /tant);
1646
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1647
+ cuspsv = 0;
1648
+ for (i = 1; i <= niter_max; i++) {
1649
+ tant = tand(asind(sine * sind(hsp->cusp[ih])));
1650
+ if (fabs(tant) < VERY_SMALL) {
1651
+ hsp->cusp[ih] = rectasc;
1652
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1653
+ break;
1654
+ }
1655
+ /* pole height */
1656
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant);
1657
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1658
+ if (i > 1 && fabs(swe_difdeg2n(hsp->cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
1659
+ break;
1660
+ cuspsv = hsp->cusp[ih];
1661
+ }
1662
+ #ifdef DEBUG_PLAC_ITER
1663
+ fprintf(stderr, "h=%d, niter=%d\n", ih, i);
1664
+ #endif
1665
+ if (i >= niter_max) {
1666
+ retc = ERR;
1667
+ hsy = (int) 'O';
1668
+ strcpy(hsp->serr, "very close to polar circle, switched to Porphyry");
1669
+ goto porphyry;
1670
+ }
1671
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = AscDash(rectasc, f, sine, cose);
1672
+ }
1673
+ hsp->cusp[ih+18] = swe_degnorm(hsp->cusp[ih] + 180);
1674
+ if (hsp->do_hspeed) hsp->cusp_speed[ih + 18] = hsp->cusp_speed[ih];
1675
+ }
1676
+ /*************** first/third quarter ***************/
1677
+ for (ih = 29; ih <= 36; ih++) {
1678
+ ih2 = ih - 28;
1679
+ fh1 = atand(sind(a * ih2 / 9) / tane);
1680
+ rectasc = swe_degnorm(180 - ih2 * 90 / 9 + th);
1681
+ tant = tand(asind(sine * sind(Asc1(rectasc, fh1, sine, cose))));
1682
+ if (fabs(tant) < VERY_SMALL) {
1683
+ hsp->cusp[ih] = rectasc;
1684
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1685
+ } else {
1686
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant);
1687
+ /* pole height */
1688
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1689
+ cuspsv = 0;
1690
+ for (i = 1; i <= niter_max; i++) {
1691
+ tant = tand(asind(sine * sind(hsp->cusp[ih])));
1692
+ if (fabs(tant) < VERY_SMALL) {
1693
+ hsp->cusp[ih] = rectasc;
1694
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1695
+ break;
1696
+ }
1697
+ f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant);
1698
+ /* pole height */
1699
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1700
+ if (i > 1 && fabs(swe_difdeg2n(hsp->cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
1701
+ break;
1702
+ cuspsv = hsp->cusp[ih];
1703
+ }
1704
+ #ifdef DEBUG_PLAC_ITER
1705
+ fprintf(stderr, "h=%d, niter=%d\n", ih, i);
1706
+ #endif
1707
+ if (i >= niter_max) {
1708
+ retc = ERR;
1709
+ hsy = (int) 'O';
1710
+ strcpy(hsp->serr, "very close to polar circle, switched to Porphyry");
1711
+ goto porphyry;
1712
+ }
1713
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = AscDash(rectasc, f, sine, cose);
1714
+ }
1715
+ hsp->cusp[ih-18] = swe_degnorm(hsp->cusp[ih] + 180);
1716
+ if (hsp->do_hspeed) hsp->cusp_speed[ih - 18] = hsp->cusp_speed[ih];
1717
+ }
1718
+ hsp->cusp[1] = hsp->ac;
1719
+ hsp->cusp[10] = hsp->mc;
1720
+ hsp->cusp[19] = swe_degnorm(hsp->ac + 180);
1721
+ hsp->cusp[28] = swe_degnorm(hsp->mc + 180);
1722
+ if (hsp->do_hspeed) {
1723
+ hsp->cusp_speed[1] = hsp->ac_speed;
1724
+ hsp->cusp_speed[10] = hsp->mc_speed;
1725
+ hsp->cusp_speed[19] = hsp->ac_speed;
1726
+ hsp->cusp_speed[28] = hsp->mc_speed;
1727
+ }
1728
+ break;
1729
+ case 'U': /* Krusinski-Pisa */
1730
+ /*
1731
+ * The following code was written by Bogdan Krusinski in 2006.
1732
+ * bogdan@astrologia.pl
1733
+ *
1734
+ * Definition:
1735
+ * "Krusinski - house system based on the great circle passing through
1736
+ * ascendant and zenith. This circle is divided into 12 equal parts
1737
+ * (1st cusp is ascendent, 10th cusp is zenith), then the resulting
1738
+ * points are projected onto the ecliptic through meridian circles.
1739
+ * The house cusps in space are half-circles perpendicular to the equator
1740
+ * and running from the north to the south celestial pole through the
1741
+ * resulting cusp points on the house circle. The points where they
1742
+ * cross the ecliptic mark the ecliptic house cusps."
1743
+ *
1744
+ * Description of the algorithm:
1745
+ * Transform into great circle running through Asc and zenit (where arc
1746
+ * between Asc and zenith is always 90 deg), and then return with
1747
+ * house cusps into ecliptic. Eg. solve trigonometrical triangle
1748
+ * with three transformations and two rotations starting from ecliptic.
1749
+ * House cusps in space are meridian circles.
1750
+ *
1751
+ * Notes:
1752
+ * 1. In this definition we assume MC on ecliptic as point where
1753
+ * half-meridian (from north to south pole) cuts ecliptic,
1754
+ * so MC may be below horizon in arctic regions.
1755
+ * 2. Houses could be calculated in all latitudes except the poles
1756
+ * themselves (-90,90) and points on arctic circle in cases where
1757
+ * ecliptic is equal to horizon and then ascendant is undefined.
1758
+ * But ascendant when 'horizon=ecliptic' could be deduced as limes
1759
+ * from both sides of that point and houses with that provision can
1760
+ * be computed also there.
1761
+ *
1762
+ * Starting values for calculations:
1763
+ * - Asc ecliptic longitude
1764
+ * - right ascension of MC (RAMC)
1765
+ * - geographic latitude.
1766
+ */
1767
+ /*
1768
+ * within polar circle we swap AC/DC if AC is on wrong side
1769
+ */
1770
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1771
+ if (acmc < 0) {
1772
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1773
+ }
1774
+ /* A0. Start point - ecliptic coords of ascendant */
1775
+ x[0] = hsp->ac; /* Asc longitude */
1776
+ x[1] = 0.0; /* Asc declination */
1777
+ x[2] = 1.0; /* Radius to test validity of subsequent transformations. */
1778
+ swe_cotrans(x, x, -ekl); /* A1. Transform into equatorial coords */
1779
+ x[0] = x[0] - (th-90); /* A2. Rotate */
1780
+ swe_cotrans(x, x, -(90-fi)); /* A3. Transform into horizontal coords */
1781
+ krHorizonLon = x[0]; /* ...save asc lon on horizon to get back later with house cusp */
1782
+ x[0] = x[0] - x[0]; /* A4. Rotate */
1783
+ swe_cotrans(x, x, -90); /* A5. Transform into this house system great circle (asc-zenith) */
1784
+ /* As it is house circle now, simple add 30 deg increments... */
1785
+ for(i = 0; i < 6; i++) {
1786
+ /* B0. Set 'n-th' house cusp.
1787
+ * Note that IC/MC are also calculated here to check
1788
+ * if really this is the asc-zenith great circle. */
1789
+ x[0] = 30.0*i;
1790
+ x[1] = 0.0;
1791
+ swe_cotrans(x, x, 90); /* B1. Transform back into horizontal coords */
1792
+ x[0] = x[0] + krHorizonLon; /* B2. Rotate back. */
1793
+ swe_cotrans(x, x, 90-fi); /* B3. Transform back into equatorial coords */
1794
+ x[0] = swe_degnorm(x[0] + (th-90)); /* B4. Rotate back -> RA of house cusp as result. */
1795
+ /* B5. Where's this house cusp on ecliptic? */
1796
+ /* ... so last but not least - get ecliptic longitude of house cusp: */
1797
+ hsp->cusp[i+1] = atand(tand(x[0])/cosd(ekl));
1798
+ if (x[0] > 90 && x[0] <= 270)
1799
+ hsp->cusp[i+1] = swe_degnorm(hsp->cusp[i+1] + 180);
1800
+ hsp->cusp[i+1] = swe_degnorm(hsp->cusp[i+1]);
1801
+ hsp->cusp[i+7] = swe_degnorm(hsp->cusp[i+1]+180);
1802
+ }
1803
+ break;
1804
+ case 'Y': /* APC houses */
1805
+ for (i = 1; i <= 12; i++) {
1806
+ hsp->cusp[i] = apc_sector(i, fi * DEGTORAD, ekl * DEGTORAD, th * DEGTORAD);
1807
+ }
1808
+ //hsp->ac = hsp->cusp[1];
1809
+ //hsp->mc = hsp->cusp[10];
1810
+ /* note the MC provided by apc_sector() near latitude 90 is not accurate */
1811
+ hsp->cusp[10] = hsp->mc;
1812
+ hsp->cusp[4] = swe_degnorm(hsp->mc + 180);
1813
+ /* within polar circle, when mc sinks below horizon and
1814
+ * ascendant changes to western hemisphere, all cusps
1815
+ * must be added 180 degrees.
1816
+ * houses will be in clockwise direction */
1817
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
1818
+ acmc = swe_difdeg2n(hsp->ac, hsp->mc);
1819
+ if (acmc < 0) {
1820
+ hsp->ac = swe_degnorm(hsp->ac + 180);
1821
+ hsp->mc = swe_degnorm(hsp->mc + 180);
1822
+ for (i = 1; i <= 12; i++)
1823
+ hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180);
1824
+ }
1825
+ }
1826
+ hsp->do_interpol = hsp->do_hspeed;
1827
+ break;
1828
+ default: /* Placidus houses */
1829
+ if (fabs(fi) >= 90 - ekl) { /* within polar circle */
1830
+ retc = ERR;
1831
+ strcpy(hsp->serr, "within polar circle, switched to Porphyry");
1832
+ goto porphyry;
1833
+ }
1834
+ a = asind(tand(fi) * tane);
1835
+ fh1 = atand(sind(a / 3) / tane);
1836
+ fh2 = atand(sind(a * 2 / 3) / tane);
1837
+ /* ************ house 11 ******************** */
1838
+ rectasc = swe_degnorm(30 + th);
1839
+ tant = tand(asind(sine * sind(Asc1(rectasc, fh1, sine, cose))));
1840
+ ih = 11;
1841
+ if (fabs(tant) < VERY_SMALL) {
1842
+ hsp->cusp[ih] = rectasc;
1843
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1844
+ } else {
1845
+ /* pole height */
1846
+ f = atand(sind(asind(tanfi * tant) / 3) /tant);
1847
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1848
+ cuspsv = 0;
1849
+ for (i = 1; i <= niter_max; i++) {
1850
+ tant = tand(asind(sine * sind(hsp->cusp[ih])));
1851
+ if (fabs(tant) < VERY_SMALL) {
1852
+ hsp->cusp[ih] = rectasc;
1853
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1854
+ break;
1855
+ }
1856
+ /* pole height */
1857
+ f = atand(sind(asind(tanfi * tant) / 3) / tant);
1858
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1859
+ if (i > 1 && fabs(swe_difdeg2n(hsp->cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
1860
+ break;
1861
+ cuspsv = hsp->cusp[ih];
1862
+ }
1863
+ if (i >= niter_max) {
1864
+ retc = ERR;
1865
+ strcpy(hsp->serr, "very close to polar circle, switched to Porphyry");
1866
+ goto porphyry;
1867
+ }
1868
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = AscDash(rectasc, f, sine, cose);
1869
+ #ifdef DEBUG_PLAC_ITER
1870
+ fprintf(stderr, "h=%d, niter=%d\n", ih, i);
1871
+ #endif
1872
+ }
1873
+ /* ************ house 12 ******************** */
1874
+ rectasc = swe_degnorm(60 + th);
1875
+ tant = tand(asind(sine*sind(Asc1(rectasc, fh2, sine, cose))));
1876
+ ih = 12;
1877
+ if (fabs(tant) < VERY_SMALL) {
1878
+ hsp->cusp[ih] = rectasc;
1879
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1880
+ } else {
1881
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1882
+ /* pole height */
1883
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1884
+ cuspsv = 0;
1885
+ for (i = 1; i <= niter_max; i++) {
1886
+ tant = tand(asind(sine * sind(hsp->cusp[ih])));
1887
+ if (fabs(tant) < VERY_SMALL) {
1888
+ hsp->cusp[ih] = rectasc;
1889
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1890
+ break;
1891
+ }
1892
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1893
+ /* pole height */
1894
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1895
+ if (i > 1 && fabs(swe_difdeg2n(hsp->cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
1896
+ break;
1897
+ cuspsv = hsp->cusp[ih];
1898
+ }
1899
+ if (i >= niter_max) {
1900
+ retc = ERR;
1901
+ strcpy(hsp->serr, "very close to polar circle, switched to Porphyry");
1902
+ goto porphyry;
1903
+ }
1904
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = AscDash(rectasc, f, sine, cose);
1905
+ #ifdef DEBUG_PLAC_ITER
1906
+ fprintf(stderr, "h=%d, niter=%d\n", ih, i);
1907
+ #endif
1908
+ }
1909
+ /* ************ house 2 ******************** */
1910
+ rectasc = swe_degnorm(120 + th);
1911
+ tant = tand(asind(sine * sind(Asc1(rectasc, fh2, sine, cose))));
1912
+ ih = 2;
1913
+ if (fabs(tant) < VERY_SMALL) {
1914
+ hsp->cusp[ih] = rectasc;
1915
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1916
+ } else {
1917
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1918
+ /* pole height */
1919
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1920
+ cuspsv = 0;
1921
+ for (i = 1; i <= niter_max; i++) {
1922
+ tant = tand(asind(sine * sind(hsp->cusp[ih])));
1923
+ if (fabs(tant) < VERY_SMALL) {
1924
+ hsp->cusp[ih] = rectasc;
1925
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1926
+ break;
1927
+ }
1928
+ f = atand(sind(asind(tanfi * tant) / 1.5) / tant);
1929
+ /* pole height */
1930
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1931
+ if (i > 1 && fabs(swe_difdeg2n(hsp->cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
1932
+ break;
1933
+ cuspsv = hsp->cusp[ih];
1934
+ }
1935
+ if (i >= niter_max) {
1936
+ retc = ERR;
1937
+ strcpy(hsp->serr, "very close to polar circle, switched to Porphyry");
1938
+ goto porphyry;
1939
+ }
1940
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = AscDash(rectasc, f, sine, cose);
1941
+ #ifdef DEBUG_PLAC_ITER
1942
+ fprintf(stderr, "h=%d, niter=%d\n", ih, i);
1943
+ #endif
1944
+ }
1945
+ /* ************ house 3 ******************** */
1946
+ rectasc = swe_degnorm(150 + th);
1947
+ tant = tand(asind(sine * sind(Asc1(rectasc, fh1, sine, cose))));
1948
+ ih = 3;
1949
+ if (fabs(tant) < VERY_SMALL) {
1950
+ hsp->cusp[ih] = rectasc;
1951
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1952
+ } else {
1953
+ f = atand(sind(asind(tanfi * tant) / 3) / tant);
1954
+ /* pole height */
1955
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1956
+ cuspsv = 0;
1957
+ for (i = 1; i <= niter_max; i++) {
1958
+ tant = tand(asind(sine * sind(hsp->cusp[ih])));
1959
+ if (fabs(tant) < VERY_SMALL) {
1960
+ hsp->cusp[ih] = rectasc;
1961
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = hsp->armc_speed;
1962
+ break;
1963
+ }
1964
+ f = atand(sind(asind(tanfi * tant) / 3) / tant);
1965
+ /* pole height */
1966
+ hsp->cusp[ih] = Asc1(rectasc, f, sine, cose);
1967
+ if (i > 1 && fabs(swe_difdeg2n(hsp->cusp[ih], cuspsv)) < VERY_SMALL_PLAC_ITER)
1968
+ break;
1969
+ cuspsv = hsp->cusp[ih];
1970
+ }
1971
+ if (i >= niter_max) {
1972
+ retc = ERR;
1973
+ strcpy(hsp->serr, "very close to polar circle, switched to Porphyry");
1974
+ goto porphyry;
1975
+ }
1976
+ if (hsp->do_hspeed) hsp->cusp_speed[ih] = AscDash(rectasc, f, sine, cose);
1977
+ #ifdef DEBUG_PLAC_ITER
1978
+ fprintf(stderr, "h=%d, niter=%d\n", ih, i);
1979
+ #endif
1980
+ }
1981
+ break;
1982
+ } /* end switch */
1983
+ if (hsy != 'G' && hsy != 'Y' && toupper(hsy) != 'I' ) {
1984
+ hsp->cusp[4] = swe_degnorm(hsp->cusp[10] + 180);
1985
+ hsp->cusp[5] = swe_degnorm(hsp->cusp[11] + 180);
1986
+ hsp->cusp[6] = swe_degnorm(hsp->cusp[12] + 180);
1987
+ hsp->cusp[7] = swe_degnorm(hsp->cusp[1] + 180);
1988
+ hsp->cusp[8] = swe_degnorm(hsp->cusp[2] + 180);
1989
+ hsp->cusp[9] = swe_degnorm(hsp->cusp[3] + 180);
1990
+ if (hsp->do_hspeed && ! hsp->do_interpol) {
1991
+ hsp->cusp_speed[4] = hsp->cusp_speed[10];
1992
+ hsp->cusp_speed[5] = hsp->cusp_speed[11];
1993
+ hsp->cusp_speed[6] = hsp->cusp_speed[12];
1994
+ hsp->cusp_speed[7] = hsp->cusp_speed[1];
1995
+ hsp->cusp_speed[8] = hsp->cusp_speed[2];
1996
+ hsp->cusp_speed[9] = hsp->cusp_speed[3];
1997
+ }
1998
+ }
1999
+ /* vertex */
2000
+ if (fi >= 0)
2001
+ f = 90 - fi;
2002
+ else
2003
+ f = -90 - fi;
2004
+ hsp->vertex = Asc1(th - 90, f, sine, cose);
2005
+ if (hsp->do_speed) hsp->vertex_speed = AscDash(th - 90, f, sine, cose);
2006
+ /* with tropical latitudes, the vertex behaves strange,
2007
+ * in a similar way as the ascendant within the polar
2008
+ * circle. we keep it always on the western hemisphere.*/
2009
+ if (fabs(fi) <= ekl) {
2010
+ vemc = swe_difdeg2n(hsp->vertex, hsp->mc);
2011
+ if (vemc > 0)
2012
+ hsp->vertex = swe_degnorm(hsp->vertex + 180);
2013
+ }
2014
+ /*
2015
+ * some strange points:
2016
+ */
2017
+ /* equasc (equatorial ascendant) */
2018
+ th2 = swe_degnorm(th + 90);
2019
+ if (fabs(th2 - 90) > VERY_SMALL
2020
+ && fabs(th2 - 270) > VERY_SMALL) {
2021
+ tant = tand(th2);
2022
+ hsp->equasc = atand(tant / cose);
2023
+ if (th2 > 90 && th2 <= 270)
2024
+ hsp->equasc = swe_degnorm(hsp->equasc + 180);
2025
+ } else {
2026
+ if (fabs(th2 - 90) <= VERY_SMALL)
2027
+ hsp->equasc = 90;
2028
+ else
2029
+ hsp->equasc = 270;
2030
+ } /* if */
2031
+ hsp->equasc = swe_degnorm(hsp->equasc);
2032
+ if (hsp->do_speed) hsp->equasc_speed = AscDash(th + 90, 0, sine, cose);
2033
+ /* "co-ascendant" W. Koch */
2034
+ hsp->coasc1 = swe_degnorm(Asc1(th - 90, fi, sine, cose) + 180);
2035
+ if (hsp->do_speed) hsp->coasc1_speed = AscDash(th - 90, fi, sine, cose);
2036
+ /* "co-ascendant" M. Munkasey */
2037
+ if (fi >= 0) {
2038
+ hsp->coasc2 = Asc1(th + 90, 90 - fi, sine, cose);
2039
+ if (hsp->do_speed) hsp->coasc2_speed = AscDash(th + 90, 90 - fi, sine, cose);
2040
+ } else { /* southern hemisphere */
2041
+ hsp->coasc2 = Asc1(th + 90, -90 - fi, sine, cose);
2042
+ if (hsp->do_speed) hsp->coasc2_speed = AscDash(th + 90, -90 - fi, sine, cose);
2043
+ }
2044
+ /* "polar ascendant" M. Munkasey */
2045
+ hsp->polasc = Asc1(th - 90, fi, sine, cose);
2046
+ if (hsp->do_speed) hsp->polasc_speed = AscDash(th - 90, fi, sine, cose);
2047
+ return retc;
2048
+ } /* procedure houses */
2049
+
2050
+ /*****
2051
+ * oblique triangle formed by: great circle with pole height f, ecliptic and equator,
2052
+ * x = intersection equator - great circle.
2053
+ * return crossing of ecliptic with great circle.
2054
+ * Prepare quadrants before doing the work in Asc2.
2055
+ */
2056
+ static double Asc1(double x1, double f, double sine, double cose)
2057
+ {
2058
+ int n;
2059
+ double ass;
2060
+ x1 = swe_degnorm(x1);
2061
+ n = (int) ((x1 / 90) + 1); // n is quadrant 1..4
2062
+ if (fabs(90 - f) < VERY_SMALL) { // near north pole
2063
+ return 180;
2064
+ }
2065
+ if (fabs(90 + f) < VERY_SMALL) { // near south pole
2066
+ return 0;
2067
+ }
2068
+ if (n == 1)
2069
+ ass = ( Asc2(x1, f, sine, cose));
2070
+ else if (n == 2)
2071
+ ass = (180 - Asc2(180 - x1, - f, sine, cose));
2072
+ else if (n == 3)
2073
+ ass = (180 + Asc2(x1 - 180, - f, sine, cose));
2074
+ else
2075
+ ass = (360 - Asc2(360- x1, f, sine, cose));
2076
+ ass = swe_degnorm(ass);
2077
+ if (fabs(ass - 90) < VERY_SMALL) /* rounding, e.g.: if */
2078
+ ass = 90; /* fi = 0 & st = 0, ac = 89.999... */
2079
+ if (fabs(ass - 180) < VERY_SMALL)
2080
+ ass = 180;
2081
+ if (fabs(ass - 270) < VERY_SMALL) /* rounding, e.g.: if */
2082
+ ass = 270; /* fi = 0 & st = 0, ac = 89.999... */
2083
+ if (fabs(ass - 360) < VERY_SMALL)
2084
+ ass = 0;
2085
+ return ass;
2086
+ } /* Asc1 */
2087
+
2088
+
2089
+ /*
2090
+ * x in range 0..90
2091
+ * f in range -90 .. +90
2092
+ * sine, cose around e=23°
2093
+ * oblique triangle formed by: great circle with pole height f, ecliptic and equator,
2094
+ * x = intersection equator - great circle.
2095
+ * return crossing of ecliptic with great circle.
2096
+ */
2097
+ static double Asc2(double x, double f, double sine, double cose)
2098
+ {
2099
+ double ass, sinx;
2100
+ // from https://en.wikipedia.org/wiki/Spherical_trigonometry CT5
2101
+ // cot c sin a = cot C sin B + cos a cos B, with B = ecl, a = x, C = 90 +f
2102
+ // cot 90 + f = - tan f
2103
+ ass = - tand(f) * sine + cose * cosd(x);
2104
+ if (fabs(ass) < VERY_SMALL)
2105
+ ass = 0;
2106
+ sinx = sind(x);
2107
+ if (fabs(sinx) < VERY_SMALL)
2108
+ sinx = 0;
2109
+ if (sinx == 0) {
2110
+ if (ass < 0)
2111
+ ass = -VERY_SMALL;
2112
+ else
2113
+ ass = VERY_SMALL;
2114
+ } else if (ass == 0) {
2115
+ if (sinx < 0)
2116
+ ass = -90;
2117
+ else
2118
+ ass = 90;
2119
+ } else {
2120
+ // resolve ass = sin x cot c; cot c = ass / sini x; tan c = sin x / ass
2121
+ ass = atand(sinx / ass);
2122
+ }
2123
+ if (ass < 0)
2124
+ ass = 180 + ass;
2125
+ return (ass);
2126
+ } /* Asc2 */
2127
+
2128
+ // derivative of Asc1, computes speed
2129
+ // code contributed by Graham Dawson
2130
+ static double AscDash(double x, double f, double sine, double cose)
2131
+ {
2132
+ double cosx = cosd(x);
2133
+ double sinx = sind(x);
2134
+ double sinx2 = sinx * sinx;
2135
+ double c = cose * cosx - tand(f) * sine;
2136
+ double d = sinx2 + c * c;
2137
+ double dudt;
2138
+ if (d > VERY_SMALL) {
2139
+ dudt = (cosx * c + cose * sinx2) / d;
2140
+ } else {
2141
+ dudt = 0.0; // When we are on axis of ecliptic
2142
+ }
2143
+ return dudt * ARMCS; // 360.985647366;
2144
+ }
2145
+
2146
+ static double armc_to_mc(double armc, double eps)
2147
+ {
2148
+ double cose = cosd(eps);
2149
+ double mc, tant;
2150
+ if (fabs(armc - 90) > VERY_SMALL
2151
+ && fabs(armc - 270) > VERY_SMALL) {
2152
+ tant = tand(armc);
2153
+ mc = swe_degnorm(atand(tant / cose));
2154
+ if (armc > 90 && armc <= 270)
2155
+ mc = swe_degnorm(mc + 180);
2156
+ } else {
2157
+ if (fabs(armc - 90) <= VERY_SMALL)
2158
+ mc = 90;
2159
+ else
2160
+ mc = 270;
2161
+ }
2162
+ return mc;
2163
+ }
2164
+
2165
+ /* if ascendant is on western half of horizon, add 180° */
2166
+ static double fix_asc_polar(double asc, double armc, double eps, double geolat)
2167
+ {
2168
+ double demc = atand(sind(armc) * tand(eps));
2169
+ if (geolat >= 0 && 90 - geolat + demc < 0)
2170
+ asc = swe_degnorm(asc + 180);
2171
+ if (geolat < 0 && -90 - geolat + demc > 0)
2172
+ asc = swe_degnorm(asc + 180);
2173
+ return asc;
2174
+ }
2175
+
2176
+ /* Computes the house position of a planet or another point,
2177
+ * in degrees: 0 - 30 = 1st house, 30 - 60 = 2nd house, etc.
2178
+ * armc sidereal time in degrees
2179
+ * geolat geographic latitude
2180
+ * eps true ecliptic obliquity
2181
+ * hsys house system character
2182
+ * xpin array of 6 doubles:
2183
+ * only the first two of them are used: ecl. long., lat.
2184
+ * serr error message area
2185
+ *
2186
+ * House position is returned by function.
2187
+ * Currently, geometrically correct house positions are provided
2188
+ * for the following house methods:
2189
+ * A/E Equal, V Vehlow, W Whole Signs, D Equal/MC, N Equal/Zodiac,
2190
+ * O Porphyry, B Alcabitius, X Meridian, F Carter, M Morinus,
2191
+ * P Placidus, K Koch, C Campanus, R Regiomontanus, U Krusinski,
2192
+ * T Topocentric, H Horizon, G Gauquelin.
2193
+ *
2194
+ * A simplified house position (distance_from_cusp / house_size)
2195
+ * is currently provided for the following house methods:
2196
+ * Y APC houses, L Pullen SD, Q Pullen SR, I Sunshine, S Sripati.
2197
+ *
2198
+ * IMPORTANT: This function should NOT be used for sidereal astrology.
2199
+ * If you cannot avoid doing so, please note:
2200
+ * - The input longitudes (xpin) MUST always be tropical, even if you
2201
+ * are a siderealist.
2202
+ * - Sidereal and tropical house positions are identical for most house
2203
+ * systems, if a traditional definition of the sidereal zodiac is used
2204
+ * (sid = trop - ayanamsa).
2205
+ * - The function does NOT provide correct positions for Whole Sign houses.
2206
+ * - The function does NOT provide correct positions, if you use a
2207
+ * non-traditional sidereal method (where the sidereal plane is not
2208
+ * identical to the ecliptic of date) with a house system whose definition
2209
+ * is dependent on the ecliptic, such as:
2210
+ * equal, Porphyry, Alcabitius, Koch, Krusinski (all others should work).
2211
+ * The Swiss Ephemeris currently does not handle these cases.
2212
+ */
2213
+ double CALL_CONV swe_house_pos(
2214
+ double armc, double geolat, double eps, int hsys, double *xpin, char *serr)
2215
+ {
2216
+ double xp[6], xeq[6], ra, de, mdd, mdn, sad, san;
2217
+ double hpos, sinad, ad, a, admc, adp, samc, asc, mc, acmc, tant;
2218
+ //double demc;
2219
+ double fh, ra0, tanfi, sinfi, fac, dfac, tanx;
2220
+ double x[3], xasc[3], xs1, xs2, raep, raaz, oblaz, xtemp; /* BK 21.02.2006 */
2221
+ double hcusp[37], ascmc[10];
2222
+ double sine = sind(eps);
2223
+ double cose = cosd(eps);
2224
+ double c1, c2, d, hsize;
2225
+ int i, j, nloop;
2226
+ double dsun = 0, darmc, harmc, y, sinpsi, sa;
2227
+ AS_BOOL is_western_half = FALSE;
2228
+ hsys = toupper(hsys);
2229
+ if (1) {
2230
+ /* input is a house cusp: no calculation is required */
2231
+ ascmc[9] = 99;// dirty hack. Sunshine house system needs sun declination
2232
+ // which we do not know. If it sees ascmc[9] == 99, it uses
2233
+ // the one is saved from last call. can lead to bugs, but can
2234
+ // also solve many problems.
2235
+ if (swe_houses_armc_ex2(armc, geolat, eps, hsys, hcusp, ascmc, NULL, NULL, serr) == ERR) {
2236
+ if (serr != NULL)
2237
+ sprintf(serr, "swe_house_pos(): failed for system %c", hsys);
2238
+ } else {
2239
+ hpos = 0;
2240
+ for (i = 1; i <= 12; i++) {
2241
+ if (fabs(swe_difdeg2n(xpin[0], hcusp[i])) < MILLIARCSEC && xpin[1] == 0) {
2242
+ hpos = (double) i;
2243
+ }
2244
+ }
2245
+ for (i = 1; i <= 12; i += 3) {
2246
+ if (fabs(swe_difdeg2n(xpin[0], hcusp[i])) < MILLIARCSEC && xpin[1] == 0) {
2247
+ xp[0] = (double) i;
2248
+ }
2249
+ }
2250
+ if (hpos > 0)
2251
+ return hpos;
2252
+ // for Sunshine houses: declination of Sun
2253
+ if (hsys == 'I')
2254
+ dsun = ascmc[9];
2255
+ // for APC houses: declination of ascendant into dsun
2256
+ if (hsys == 'Y') {
2257
+ xeq[0] = ascmc[0];
2258
+ xeq[1] = 0;
2259
+ xeq[2] = 1;
2260
+ swe_cotrans(xeq, xeq, -eps);
2261
+ dsun = xeq[1];
2262
+ }
2263
+ }
2264
+ }
2265
+ AS_BOOL is_above_hor = FALSE;
2266
+ AS_BOOL is_invalid = FALSE;
2267
+ AS_BOOL is_circumpolar = FALSE;
2268
+ if (serr != NULL)
2269
+ *serr = '\0';
2270
+ xeq[0] = xpin[0];
2271
+ xeq[1] = xpin[1];
2272
+ xeq[2] = 1;
2273
+ swe_cotrans(xeq, xeq, -eps);
2274
+ ra = xeq[0];
2275
+ de = xeq[1];
2276
+ mdd = swe_degnorm(ra - armc);
2277
+ mdn = swe_degnorm(mdd + 180);
2278
+ if (mdd >= 180)
2279
+ mdd -= 360;
2280
+ if (mdn >= 180)
2281
+ mdn -= 360;
2282
+ /* xp[0] will contain the house position, a value between 0 and 360 */
2283
+ switch(hsys) {
2284
+ case 'N': // equal (1=Aries)
2285
+ xp[0] = xpin[0];
2286
+ hpos = xp[0] / 30.0 + 1;
2287
+ break;
2288
+ case 'A': // equal
2289
+ case 'E': // equal
2290
+ case 'D': // equal (MC)
2291
+ case 'V': // Vehlow
2292
+ case 'W': // whole signs
2293
+ asc = Asc1(swe_degnorm(armc + 90), geolat, sine, cose);
2294
+ mc = armc_to_mc(armc, eps);
2295
+ asc = fix_asc_polar(asc, armc, eps, geolat);
2296
+ xp[0] = swe_degnorm(xpin[0] - asc);
2297
+ if (hsys == 'V')
2298
+ xp[0] = swe_degnorm(xp[0] + 15);
2299
+ if (hsys == 'W')
2300
+ xp[0] = swe_degnorm(xp[0] + fmod(asc, 30));
2301
+ if (hsys == 'D')
2302
+ xp[0] = swe_degnorm(xpin[0] - mc - 90);
2303
+ /* to make sure that a call with a house cusp position returns
2304
+ * a value within the house, 0.001" is added */
2305
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
2306
+ hpos = xp[0] / 30.0 + 1;
2307
+ break;
2308
+ case 'O': /* Porphyry */
2309
+ case 'B': /* Alcabitius */
2310
+ case 'S': /* Sripati */
2311
+ asc = Asc1(swe_degnorm(armc + 90), geolat, sine, cose);
2312
+ /* mc */
2313
+ mc = armc_to_mc(armc, eps);
2314
+ /* while MC is always south,
2315
+ * Asc must always be in eastern hemisphere */
2316
+ asc = fix_asc_polar(asc, armc, eps, geolat);
2317
+ if (hsys == 'O' || hsys == 'S') {
2318
+ xp[0] = swe_degnorm(xpin[0] - asc);
2319
+ /* to make sure that a call with a house cusp position returns
2320
+ * a value within the house, 0.001" is added */
2321
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
2322
+ if (xp[0] < 180)
2323
+ hpos = 1;
2324
+ else {
2325
+ hpos = 7;
2326
+ xp[0] -= 180;
2327
+ }
2328
+ acmc = swe_difdeg2n(asc, mc);
2329
+ if (xp[0] < 180 - acmc)
2330
+ hpos += xp[0] * 3 / (180 - acmc);
2331
+ else
2332
+ hpos += 3 + (xp[0] - 180 + acmc) * 3 / acmc;
2333
+ if (hsys == 'S') {
2334
+ hpos += 0.5;
2335
+ if (hpos > 12) hpos = 1;
2336
+ }
2337
+ } else { /* Alcabitius */
2338
+ double dek, r, sna, sda;
2339
+ dek = asind(sind(asc) * sine); /* declination of Ascendant */
2340
+ /* must treat the case fi == 90 or -90 */
2341
+ tanfi = tand(geolat);
2342
+ r = -tanfi * tand(dek);
2343
+ /* must treat the case of abs(r) > 1; probably does not happen
2344
+ * because dek becomes smaller when fi is large, as ac is close to
2345
+ * zero Aries/Libra in that case.
2346
+ */
2347
+ sda = acos(r) * RADTODEG; /* semidiurnal arc, measured on equator */
2348
+ sna = 180 - sda; /* complement, seminocturnal arc */
2349
+ if (mdd > 0) {
2350
+ if (mdd < sda)
2351
+ hpos = mdd * 90 / sda;
2352
+ else
2353
+ hpos = 90 + (mdd - sda) * 90 / sna;
2354
+ } else {
2355
+ if (mdd > -sna)
2356
+ hpos = 360 + mdd * 90 / sna;
2357
+ else
2358
+ hpos = 270 + (mdd + sna) * 90 / sda;
2359
+ }
2360
+ hpos = swe_degnorm(hpos - 90) / 30.0 + 1.0;
2361
+ if (hpos >= 13.0) hpos -= 12;
2362
+ }
2363
+ break;
2364
+ case 'X': /* Meridian or axial rotation system */
2365
+ hpos = swe_degnorm(mdd - 90) / 30.0 + 1.0;
2366
+ break;
2367
+ case 'F': /* Carter poli-equatorial */
2368
+ x[0] = Asc1(swe_degnorm(armc + 90), geolat, sine, cose);
2369
+ x[0] = fix_asc_polar(x[0], armc, eps, geolat);
2370
+ x[1] = 0;
2371
+ swe_cotrans(x, x, -eps);
2372
+ hpos = swe_degnorm(ra - x[0]) / 30.0 + 1;
2373
+ break;
2374
+ case 'M': { /* Morinus */
2375
+ double a = xpin[0];
2376
+ if (fabs(a - 90) > VERY_SMALL
2377
+ && fabs(a - 270) > VERY_SMALL) {
2378
+ tant = tand(a);
2379
+ hpos = atand(tant / cose);
2380
+ if (a > 90 && a <= 270)
2381
+ hpos = swe_degnorm(hpos + 180);
2382
+ } else {
2383
+ if (fabs(a - 90) <= VERY_SMALL)
2384
+ hpos = 90;
2385
+ else
2386
+ hpos = 270;
2387
+ } /* if */
2388
+ hpos = swe_degnorm(hpos - armc - 90);
2389
+ hpos = hpos / 30.0 + 1;
2390
+ }
2391
+ break;
2392
+ /* version of Koch method: do calculations within circumpolar circle,
2393
+ * if possible; make sure house positions 4 - 9 only appear on western
2394
+ * hemisphere */
2395
+ case 'K': // Koch
2396
+ //demc = atand(sind(armc) * tand(eps));
2397
+ is_invalid = FALSE;
2398
+ is_circumpolar = FALSE;
2399
+ /* object is within a circumpolar circle */
2400
+ if (90 - geolat < de || -90 - geolat > de) {
2401
+ adp = 90;
2402
+ is_circumpolar = TRUE;
2403
+ }
2404
+ /* object is within a circumpolar circle, southern hemisphere */
2405
+ else if (geolat - 90 > de || geolat + 90 < de) {
2406
+ adp = -90;
2407
+ is_circumpolar = TRUE;
2408
+ }
2409
+ /* object does rise and set */
2410
+ else {
2411
+ adp = asind(tand(geolat) * tand(de));
2412
+ }
2413
+ admc = tand(eps) * tand(geolat) * sind(armc);
2414
+ /* midheaven is circumpolar */
2415
+ if (fabs(admc) > 1) {
2416
+ if (admc > 1)
2417
+ admc = 1;
2418
+ else
2419
+ admc = -1;
2420
+ is_circumpolar = TRUE;
2421
+ }
2422
+ admc = asind(admc);
2423
+ samc = 90 + admc;
2424
+ if (samc == 0)
2425
+ is_invalid = TRUE;
2426
+ if (fabs(samc) > 0) {
2427
+ if (mdd >= 0) { /* east */
2428
+ dfac = (mdd - adp + admc) / samc;
2429
+ xp[0] = swe_degnorm((dfac - 1) * 90);
2430
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
2431
+ /* eastern object has longer SA than midheaven */
2432
+ if (dfac > 2 || dfac < 0)
2433
+ is_invalid = TRUE; /* if this is omitted, funny things happen */
2434
+ } else {
2435
+ dfac = (mdd + 180 + adp + admc) / samc;
2436
+ xp[0] = swe_degnorm((dfac + 1) * 90);
2437
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
2438
+ /* western object has longer SA than midheaven */
2439
+ if (dfac > 2 || dfac < 0)
2440
+ is_invalid = TRUE; /* if this is omitted, funny things happen */
2441
+ }
2442
+ }
2443
+ if (is_invalid) {
2444
+ xp[0] = 0;
2445
+ hpos = 0;
2446
+ if (serr != NULL)
2447
+ strcpy(serr, "Koch house position failed in circumpolar area");
2448
+ break;
2449
+ }
2450
+ if (is_circumpolar) {
2451
+ if (serr != NULL)
2452
+ strcpy(serr, "Koch house position, doubtful result in circumpolar area");
2453
+ }
2454
+ /* to make sure that a call with a house cusp position returns
2455
+ * a value within the house, 0.001" is added */
2456
+ hpos = xp[0] / 30.0 + 1;
2457
+ break;
2458
+ case 'C': // Campanus
2459
+ xeq[0] = swe_degnorm(mdd - 90);
2460
+ // we measure on equator from east point towards IC.
2461
+ // transformation to prime vertical, with these coordinate references
2462
+ // EP = 0, nadir = 90, WP = 180, Zenith = 270
2463
+ swe_cotrans(xeq, xp, -geolat);
2464
+ /* to make sure that a call with a house cusp position returns
2465
+ * a value within the house, 0.001" is added */
2466
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
2467
+ hpos = xp[0] / 30.0 + 1;
2468
+ break;
2469
+ case 'J': // Savard-A
2470
+ sinfi = sind(geolat);
2471
+ if (fabs(geolat) < VERY_SMALL) {
2472
+ xs2 = 1 / 3.0;
2473
+ xs1 = 2 / 3.0;
2474
+ } else {
2475
+ xs2 = sind(geolat / 3) / sinfi;
2476
+ xs1 = sind(2 * geolat / 3) / sinfi;
2477
+ }
2478
+ xs2 = asind(xs2);
2479
+ xs1 = asind(xs1);
2480
+ // xs1 and xs2 always in >= 0 < 90
2481
+ // house borders on prime vertical are, measured from EP downwards
2482
+ // h1 = 0, h4 = 90, h7 = 180, h10 = 270
2483
+ // h2 = xs2, h3 = xs1, h12 = 360 - xs2, h11 = 360 - xs1
2484
+ // h5 = h11 - 180, h6 = h12 - 180, h8 = h2 + 180, h9 = h3 + 180
2485
+ hcusp[1] = 0;
2486
+ hcusp[2] = xs2;
2487
+ hcusp[3] = xs1;
2488
+ hcusp[4] = 90;
2489
+ hcusp[5] = 180 - xs1;
2490
+ hcusp[6] = 180 - xs2;
2491
+ hcusp[7] = 180;
2492
+ hcusp[8] = 180 + xs2;
2493
+ hcusp[9] = 180 + xs1;
2494
+ hcusp[10] = 270;
2495
+ hcusp[11] = 360 - xs1;
2496
+ hcusp[12] = 360 - xs2;
2497
+ xeq[0] = swe_degnorm(mdd - 90);
2498
+ swe_cotrans(xeq, xp, -geolat);
2499
+ a = xp[0];
2500
+ if (swe_difdeg2n(hcusp[6], hcusp[1]) > 0) {
2501
+ d = swe_degnorm(a - hcusp[1]);
2502
+ for (i = 1; i <= 12; i++) {
2503
+ j = i + 1;
2504
+ if (j > 12)
2505
+ c2 = 360;
2506
+ else
2507
+ c2 = swe_degnorm(hcusp[j] - hcusp[1]);
2508
+ if (d < c2) break;
2509
+ }
2510
+ c1 = swe_degnorm(hcusp[i] - hcusp[1]);
2511
+ } else { // houses retrograde
2512
+ d = swe_degnorm(hcusp[1] - a);
2513
+ for (i = 1; i <= 12; i++) {
2514
+ j = i + 1;
2515
+ if (j > 12)
2516
+ c2 = 360;
2517
+ else
2518
+ c2 = swe_degnorm(hcusp[1] - hcusp[j]);
2519
+ if (d < c2) break;
2520
+ }
2521
+ c1 = swe_degnorm(hcusp[1] - hcusp[i]);
2522
+ }
2523
+ hsize = c2 - c1;
2524
+ if (hsize == 0) {
2525
+ hpos = i;
2526
+ } else {
2527
+ hpos = i + (d - c1) / hsize;
2528
+ }
2529
+ break;
2530
+ case 'U': /* Krusinski-Pisa-Goelzer */
2531
+ if (fabs(geolat) < VERY_SMALL) { /* code below does not like geolat 0 */
2532
+ geolat = (geolat >= 0) ? VERY_SMALL : -VERY_SMALL;
2533
+ }
2534
+ /* Purpose: find point where planet's house circle (meridian)
2535
+ * cuts house plane, giving exact planet's house position.
2536
+ * Input data: ramc, geolat, asc.
2537
+ */
2538
+ asc = Asc1(swe_degnorm(armc + 90), geolat, sine, cose);
2539
+ /* while MC is always south,
2540
+ * Asc must always be in eastern hemisphere */
2541
+ asc = fix_asc_polar(asc, armc, eps, geolat);
2542
+ /*
2543
+ * Descr: find the house plane 'asc-zenith' - where it intersects
2544
+ * with equator and at what angle, and then simple find arc
2545
+ * from asc on that plane to planet's meridian intersection
2546
+ * with this plane.
2547
+ */
2548
+ /* I. find plane of 'asc-zenith' great circle relative to equator:
2549
+ * solve spherical triangle 'EP-asc-intersection of house circle with equator' */
2550
+ /* Ia. Find intersection of house plane with equator: */
2551
+ x[0] = asc; x[1] = 0.0; x[2] = 1.0; /* 1. Start with ascendent on ecliptic */
2552
+ swe_cotrans(x, x, -eps); /* 2. Transform asc into equatorial coords */
2553
+ raep = swe_degnorm(armc + 90); /* 3. RA of east point */
2554
+ x[0] = swe_degnorm(raep - x[0]); /* 4. Rotation - found arc raas-raep */
2555
+ swe_cotrans(x, x, -(90-geolat)); /* 5. Transform into horizontal coords - arc EP-asc on horizon */
2556
+ tanx = tand(x[0]);
2557
+ if (geolat == 0) {
2558
+ xtemp = (tanx >= 0) ? 90 : -90;
2559
+ } else {
2560
+ xtemp = atand(tanx/cosd((90-geolat))); /* 6. Rotation from horizon on circle perpendicular to equator */
2561
+ }
2562
+ if (x[0] > 90 && x[0] <= 270)
2563
+ xtemp = swe_degnorm(xtemp + 180);
2564
+ x[0] = swe_degnorm(xtemp);
2565
+ raaz = swe_degnorm(raep - x[0]); /* result: RA of intersection 'asc-zenith' great circle with equator */
2566
+ /* Ib. Find obliquity to equator of 'asc-zenith' house plane: */
2567
+ x[0] = raaz; x[1] = 0.0;
2568
+ x[0] = swe_degnorm(raep - x[0]); /* 1. Rotate start point relative to EP */
2569
+ swe_cotrans(x, x, -(90-geolat)); /* 2. Transform into horizontal coords */
2570
+ x[1] = x[1] + 90; /* 3. Add 90 deg do decl - so get the point on house plane most distant from equ. */
2571
+ swe_cotrans(x, x, 90-geolat); /* 4. Rotate back to equator */
2572
+ oblaz = x[1]; /* 5. Obliquity of house plane to equator */
2573
+ /* II. Next find asc and planet position on house plane,
2574
+ * so to find relative distance of planet from
2575
+ * coords beginning. */
2576
+ /* IIa. Asc on house plane relative to intersection
2577
+ * of equator with 'asc-zenith' plane. */
2578
+ xasc[0] = asc; xasc[1] = 0.0; xasc[2] = 1.0;
2579
+ swe_cotrans(xasc, xasc, -eps);
2580
+ xasc[0] = swe_degnorm(xasc[0] - raaz);
2581
+ xtemp = atand(tand(xasc[0])/cosd(oblaz));
2582
+ if (xasc[0] > 90 && xasc[0] <= 270)
2583
+ xtemp = swe_degnorm(xtemp + 180);
2584
+ xasc[0] = swe_degnorm(xtemp);
2585
+ /* IIb. Planet on house plane relative to intersection
2586
+ * of equator with 'asc-zenith' plane */
2587
+ xp[0] = swe_degnorm(xeq[0] - raaz); /* Rotate on equator */
2588
+ xtemp = atand(tand(xp[0])/cosd(oblaz)); /* Find arc on house plane from equator */
2589
+ if (xp[0] > 90 && xp[0] <= 270)
2590
+ xtemp = swe_degnorm(xtemp + 180);
2591
+ xp[0] = swe_degnorm(xtemp);
2592
+ xp[0] = swe_degnorm(xp[0]-xasc[0]); /* find arc between asc and planet, and get planet house position */
2593
+ /* IIc. Distance from planet to house plane on declination circle: */
2594
+ x[0] = xeq[0];
2595
+ x[1] = xeq[1];
2596
+ swe_cotrans(x, x, oblaz);
2597
+ xp[1] = xeq[1] - x[1]; /* How many degrees is the point on declination circle from house circle */
2598
+ /* to make sure that a call with a house cusp position returns
2599
+ * a value within the house, 0.001" is added */
2600
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
2601
+ hpos = xp[0] / 30.0 + 1;
2602
+ break;
2603
+ case 'H': // horizon / azimuth
2604
+ xeq[0] = swe_degnorm(mdd - 90);
2605
+ swe_cotrans(xeq, xp, 90 - geolat);
2606
+ /* to make sure that a call with a house cusp position returns
2607
+ * a value within the house, 0.001" is added */
2608
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
2609
+ hpos = xp[0] / 30.0 + 1;
2610
+ break;
2611
+ case 'R': // Regiomontanus
2612
+ if (fabs(mdd) < VERY_SMALL)
2613
+ xp[0] = 270;
2614
+ else if (180 - fabs(mdd) < VERY_SMALL)
2615
+ xp[0] = 90;
2616
+ else {
2617
+ if (90 - fabs(geolat) < VERY_SMALL) {
2618
+ if (geolat > 0)
2619
+ geolat = 90 - VERY_SMALL;
2620
+ else
2621
+ geolat = -90 + VERY_SMALL;
2622
+ }
2623
+ if (90 - fabs(de) < VERY_SMALL) {
2624
+ if (de > 0)
2625
+ de = 90 - VERY_SMALL;
2626
+ else
2627
+ de = -90 + VERY_SMALL;
2628
+ }
2629
+ a = tand(geolat) * tand(de) + cosd(mdd);
2630
+ xp[0] = swe_degnorm(atand(-a / sind(mdd)));
2631
+ if (mdd < 0)
2632
+ xp[0] += 180;
2633
+ xp[0] = swe_degnorm(xp[0]);
2634
+ /* to make sure that a call with a house cusp position returns
2635
+ * a value within the house, 0.001" is added */
2636
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
2637
+ }
2638
+ hpos = xp[0] / 30.0 + 1;
2639
+ break;
2640
+ /* with Sunshine and APC houses, the method is the same,
2641
+ * except that Sunshine users dsun = (declination of Sun),
2642
+ * whereas APC uses dsun = (declination of ascendant).
2643
+ * The Sunshine method has more problems within the polar
2644
+ * circles, if the Sun is circumpolar. The ascendant is never
2645
+ * circumpolar except if it coincides with the MC or the IC.
2646
+ */
2647
+ case 'I': case 'i': // sunshine houses (Makransky)
2648
+ case 'Y': // APC houses (Knegt)
2649
+ if (geolat > 90 - MILLIARCSEC)
2650
+ geolat = 90 - MILLIARCSEC;
2651
+ if (geolat < -90 + MILLIARCSEC)
2652
+ geolat = -90 + MILLIARCSEC;
2653
+ //fprintf(stdout, "in=%f, mdd=%f\n", xpin[0], mdd);
2654
+ if (90 - fabs(de) < VERY_SMALL) {
2655
+ if (de > 0)
2656
+ de = 90 - VERY_SMALL;
2657
+ else
2658
+ de = -90 + VERY_SMALL;
2659
+ }
2660
+ a = tand(geolat) * tand(de) + cosd(mdd);
2661
+ xp[0] = swe_degnorm(atand(-a / sind(mdd)));
2662
+ if (mdd < 0)
2663
+ xp[0] += 180;
2664
+ xp[0] = swe_degnorm(xp[0]); // house position with hsys = 'R'
2665
+ /* is object above horizon? */
2666
+ sinad = tand(de) * tand(geolat);
2667
+ a = sinad + cosd(mdd);
2668
+ if (a >= 0)
2669
+ is_above_hor = TRUE;
2670
+ /* height of armc above horizon */
2671
+ harmc = 90 - geolat;
2672
+ if (geolat < 0)
2673
+ harmc = 90 + geolat;
2674
+ /* meridian distance of crossing of house position line with equator */
2675
+ darmc = swe_degnorm(xp[0] - 270);
2676
+ if (darmc > 180) {
2677
+ is_western_half = TRUE;
2678
+ darmc = (360 - darmc);
2679
+ }
2680
+ /* semi-diurnal arc of sun */
2681
+ sinad = tand(dsun) * tand(geolat);
2682
+ if (sinad >= 1)
2683
+ ad = 90;
2684
+ //ad = 90 - VERY_SMALL;
2685
+ else if (sinad <= -1)
2686
+ ad = -90;
2687
+ //ad = -(90 - VERY_SMALL);
2688
+ else
2689
+ ad = asind(sinad);
2690
+ sad = 90 + ad;
2691
+ san = 90 - ad;
2692
+ //fprintf(stdout, "in=%f, above=%d, sad=%f, san=%f, sinad=%f\n", xpin[0], (int) is_above_hor, sad, san, sinad);
2693
+ /* circumpolar sun has diurnal arc = 0 and object is above the horizon:
2694
+ * house position = 10 (270°) */
2695
+ if (sad == 0 && is_above_hor) {
2696
+ xp[0] = 270;
2697
+ /* circumpolar sun has nocturnal arc = 0 and object is below the horizon:
2698
+ * house position = 4 (90°) */
2699
+ } else if (san == 0 && !is_above_hor) {
2700
+ xp[0] = 90;
2701
+ /* otherwise we can calculate the house position */
2702
+ } else {
2703
+ sa = sad;
2704
+ if (!is_above_hor) {
2705
+ dsun = -dsun;
2706
+ sa = san;
2707
+ darmc = 180 - darmc;
2708
+ is_western_half = !is_western_half;
2709
+ }
2710
+ /* length of position line between south point and equator */
2711
+ a = acosd(cosd(harmc) * cosd(darmc));
2712
+ if (a < VERY_SMALL)
2713
+ a = VERY_SMALL;
2714
+ /* sine of angle between position line and equator */
2715
+ sinpsi = sind(harmc) / sind(a);
2716
+ if (sinpsi > 1) sinpsi = 1;
2717
+ if (sinpsi < -1) sinpsi = -1;
2718
+ /* meridian distance of crossing of house position line with solar diurnal arc */
2719
+ y = sind(dsun) / sinpsi;
2720
+ if (y > 1)
2721
+ y = 90 - VERY_SMALL;
2722
+ else if (y < -1)
2723
+ y = - (90 - VERY_SMALL);
2724
+ else
2725
+ y = asind(y);
2726
+ d = acosd(cosd(y) / cosd(dsun));
2727
+ if (dsun < 0) d = -d;
2728
+ if (geolat < 0) d = -d;
2729
+ darmc += d;
2730
+ if (is_western_half)
2731
+ xp[0] = 270 - (darmc / sa) * 90;
2732
+ else
2733
+ xp[0] = 270 + (darmc / sa) * 90;
2734
+ if (!is_above_hor)
2735
+ xp[0] = swe_degnorm(xp[0] + 180);
2736
+ }
2737
+ /* to make sure that a call with a house cusp position returns
2738
+ * a value within the house, 0.001" is added */
2739
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
2740
+ hpos = xp[0] / 30.0 + 1;
2741
+ break;
2742
+ case 'T': // Polich-Page ("topocentric")
2743
+ fh = geolat;
2744
+ if (fh > 89.999)
2745
+ fh = 89.999;
2746
+ if (fh < -89.999)
2747
+ fh = -89.999;
2748
+ mdd = swe_degnorm(mdd);
2749
+ if (de > 90 - VERY_SMALL)
2750
+ de = 90 - VERY_SMALL;
2751
+ if (de < -90 + VERY_SMALL)
2752
+ de = -90 + VERY_SMALL;
2753
+ sinad = tand(de) * tand(fh);
2754
+ if (sinad > 1.0) sinad = 1.0;
2755
+ if (sinad < -1.0) sinad = -1.0;
2756
+ a = sinad + cosd(mdd);
2757
+ if (a >= 0)
2758
+ is_above_hor = TRUE;
2759
+ /* mirror everything below the horizon to the opposite point
2760
+ * above the horizon */
2761
+ if (!is_above_hor) {
2762
+ ra = swe_degnorm(ra + 180);
2763
+ de = -de;
2764
+ mdd = swe_degnorm(mdd + 180);
2765
+ }
2766
+ /* mirror everything on western hemisphere to eastern hemisphere */
2767
+ if (mdd > 180) {
2768
+ ra = swe_degnorm(armc - mdd);
2769
+ }
2770
+ /* binary search for "topocentric" position line of body */
2771
+ tanfi = tand(fh);
2772
+ ra0 = swe_degnorm(armc + 90);
2773
+ xp[1] = 1;
2774
+ xeq[1] = de;
2775
+ fac = 2;
2776
+ nloop = 0;
2777
+ while (fabs(xp[1]) > 0.000001 && nloop < 1000) {
2778
+ if (xp[1] > 0) {
2779
+ fh = atand(tand(fh) - tanfi / fac);
2780
+ ra0 -= 90 / fac;
2781
+ } else {
2782
+ fh = atand(tand(fh) + tanfi / fac);
2783
+ ra0 += 90 / fac;
2784
+ }
2785
+ xeq[0] = swe_degnorm(ra - ra0);
2786
+ swe_cotrans(xeq, xp, 90 - fh);
2787
+ fac *= 2;
2788
+ nloop++;
2789
+ }
2790
+ hpos = swe_degnorm(ra0 - armc);
2791
+ /* mirror back to west */
2792
+ if (mdd > 180)
2793
+ hpos = swe_degnorm(-hpos);
2794
+ /* mirror back to below horizon */
2795
+ if (!is_above_hor)
2796
+ hpos = swe_degnorm(hpos + 180);
2797
+ hpos = swe_degnorm(hpos - 90) / 30 + 1;
2798
+ break;
2799
+ case 'P': // Placidus
2800
+ case 'G': // Gauquelin
2801
+ /* circumpolar region */
2802
+ if (90 - fabs(de) <= fabs(geolat)) {
2803
+ if (de * geolat < 0)
2804
+ xp[0] = swe_degnorm(90 + mdn / 2);
2805
+ else
2806
+ xp[0] = swe_degnorm(270 + mdd / 2);
2807
+ if (serr != NULL)
2808
+ strcpy(serr, "Otto Ludwig procedure within circumpolar regions.");
2809
+ } else {
2810
+ sinad = tand(de) * tand(geolat);
2811
+ ad = asind(sinad);
2812
+ a = sinad + cosd(mdd);
2813
+ if (a >= 0)
2814
+ is_above_hor = TRUE;
2815
+ sad = 90 + ad;
2816
+ san = 90 - ad;
2817
+ if (is_above_hor)
2818
+ xp[0] = (mdd / sad + 3) * 90;
2819
+ else
2820
+ xp[0] = (mdn / san + 1) * 90;
2821
+ /* to make sure that a call with a house cusp position returns
2822
+ * a value within the house, 0.001" is added */
2823
+ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC);
2824
+ }
2825
+ if (hsys == 'G') {
2826
+ xp[0] = 360 - xp[0]; /* Gauquelin sectors are in clockwise direction */
2827
+ hpos = xp[0] / 10.0 + 1;
2828
+ } else {
2829
+ hpos = xp[0] / 30.0 + 1;
2830
+ }
2831
+ break;
2832
+ default:
2833
+ hpos = 0;
2834
+ if (swe_houses_armc_ex2(armc, geolat, eps, hsys, hcusp, ascmc, NULL, NULL, serr) == ERR) {
2835
+ if (serr != NULL)
2836
+ sprintf(serr, "swe_house_pos(): failed for system %c", hsys);
2837
+ break;
2838
+ }
2839
+ if (swe_difdeg2n(hcusp[6], hcusp[1]) > 0) {
2840
+ d = swe_degnorm(xpin[0] - hcusp[1]);
2841
+ for (i = 1; i <= 12; i++) {
2842
+ j = i + 1;
2843
+ if (j > 12)
2844
+ c2 = 360;
2845
+ else
2846
+ c2 = swe_degnorm(hcusp[j] - hcusp[1]);
2847
+ if (d < c2) break;
2848
+ }
2849
+ c1 = swe_degnorm(hcusp[i] - hcusp[1]);
2850
+ } else { // houses retrograde
2851
+ d = swe_degnorm(hcusp[1] - xpin[0]);
2852
+ for (i = 1; i <= 12; i++) {
2853
+ j = i + 1;
2854
+ if (j > 12)
2855
+ c2 = 360;
2856
+ else
2857
+ c2 = swe_degnorm(hcusp[1] - hcusp[j]);
2858
+ if (d < c2) break;
2859
+ }
2860
+ c1 = swe_degnorm(hcusp[1] - hcusp[i]);
2861
+ }
2862
+ hsize = c2 - c1;
2863
+ if (hsize == 0) {
2864
+ hpos = i;
2865
+ } else {
2866
+ hpos = i + (d - c1) / hsize;
2867
+ }
2868
+ if (serr != NULL)
2869
+ sprintf(serr, "swe_house_pos(): using simplified algorithm for system %c\n", hsys);
2870
+ break;
2871
+ }
2872
+ return hpos;
2873
+ }
2874
+
2875
+ static int sunshine_init(double lat, double dec, double xh[])
2876
+ {
2877
+ double ad, nsa, dsa, arg;
2878
+ // ascensional difference: sin ad = tan dec tan lat
2879
+ // or near +- 90 if Sun circumpolar
2880
+ arg = tand(dec) * tand(lat);
2881
+ if (arg >= 1) {
2882
+ ad = 90 - VERY_SMALL;
2883
+ } else if (arg <= -1) {
2884
+ ad = -90 + VERY_SMALL;
2885
+ } else {
2886
+ ad = asind(arg);
2887
+ }
2888
+ nsa = 90 - ad;
2889
+ dsa = 90 + ad;
2890
+ xh[2] = -2 * nsa / 3;
2891
+ xh[3] = -1 * nsa / 3;
2892
+ xh[5] = 1 * nsa / 3;
2893
+ xh[6] = 2 * nsa / 3;
2894
+ xh[8] = -2 * dsa / 3;
2895
+ xh[9] = -1 * dsa / 3;
2896
+ xh[11] = 1 * dsa / 3;
2897
+ xh[12] = 2 * dsa / 3;
2898
+ if (fabs(arg) >= 1)
2899
+ return ERR;
2900
+ return OK;
2901
+ }
2902
+
2903
+ static int sunshine_solution_makransky(double ramc, double lat, double ecl, struct houses *hsp)
2904
+ {
2905
+ double xh[13];
2906
+ double md;
2907
+ double zd; // zenith distance of house circle, along prime vertical
2908
+ double pole, q, w, a, b, c, f, cu, r = 0, rah;
2909
+ double sinlat, coslat, tanlat, tandec, sinecl;
2910
+ double dec = hsp->sundec;
2911
+ sinlat = sind(lat);
2912
+ coslat = cosd(lat);
2913
+ tanlat = tand(lat);
2914
+ tandec = tand(dec);
2915
+ sinecl = sind(ecl);
2916
+ int ih;
2917
+ // if (90 - fabs(lat) <= ecl) {
2918
+ // strcpy(hsp->serr, "Sunshine in polar circle not allowed");
2919
+ // return ERR;
2920
+ // }
2921
+ if (sunshine_init(lat, dec, xh) == ERR)
2922
+ return ERR;
2923
+ for (ih = 1; ih <= 12; ih++) {
2924
+ double z = 0;
2925
+ if ((ih - 1) % 3 == 0) continue; // skip 1,4,7,10
2926
+ md = fabs(xh[ih]);
2927
+ if (ih <= 6)
2928
+ rah = swe_degnorm(ramc + 180 + xh[ih]);
2929
+ else
2930
+ rah = swe_degnorm(ramc + xh[ih]);
2931
+ if (lat < 0) { // Makransky deals with southern latitude this way
2932
+ rah = swe_degnorm(180 + rah);
2933
+ }
2934
+ // HP is the house point on the semidiurnal arc
2935
+ // CP = intersection house meridian with prime vertical
2936
+ // MP = intersection house meridian with equator
2937
+ // XP = intersection house circle with prime meridian
2938
+ if (md == 90) {
2939
+ // CP = east point (or west point),
2940
+ // HP is on meridian east point - north pole
2941
+ // use triangle CP - HP - XP with long side dec
2942
+ // and angle 90 - lat.
2943
+ // use tan b = cos alph tan c = sin lat tan dec
2944
+ zd = 90.0 - atand(sinlat * tandec);
2945
+ } else {
2946
+ if (md < 90) {
2947
+ // triangle 1) CP, Zenith, north pole: side 90-lat, angle md at
2948
+ // north pole.
2949
+ // tan a = cos lat * tan md
2950
+ // a is distance of CP from zenith on prime vertical
2951
+ a = atand(coslat * tand(md));
2952
+ } else {
2953
+ // triangle 1) MP - east point - CP : side b = 90-md, angle lat
2954
+ // at east point
2955
+ // tan c = tan md / cos lat
2956
+ // a is distance of CP from zenith on prime vertical
2957
+ a = atand(tand(md - 90) / coslat); // lat = 90 not allowed
2958
+ }
2959
+ // triangle 2) CP, MP, east point: side 90 - md, angle lat
2960
+ // tan b = tan lat * cos md
2961
+ // b is distance of CP from equator
2962
+ b = atand(tanlat * cosd(md));
2963
+ // c is distance of HP house point from CP, along its meridian.
2964
+ if (ih <= 6)
2965
+ c = b + dec;
2966
+ else
2967
+ c = b - dec;
2968
+ // triangle 3) HP - CP - XP, side c, angle from triangle 1)
2969
+ // tan f = sin lat * sin md * tan c;
2970
+ // f is the distance from CP to XP
2971
+ f = atand(sinlat * sind(md) * tand(c));
2972
+ // a + f give zd, the zenith distance
2973
+ // of house circle measured on prime vertical.
2974
+ zd = a + f;
2975
+ }
2976
+ pole = asind(sind(zd) * sinlat);
2977
+ q = asind(tandec * tand(pole));
2978
+ if (ih <= 3 || ih >= 11)
2979
+ w = swe_degnorm(rah - q);
2980
+ else
2981
+ w = swe_degnorm(rah + q);
2982
+ if (w == 90) {
2983
+ r = atand(sind(ecl) * tand(pole));
2984
+ if (ih <= 3 || ih >= 11)
2985
+ cu = 90 + r;
2986
+ else
2987
+ cu = 90 - r;
2988
+ } else if (w == 270) {
2989
+ r = atand(sinecl * tand(pole));
2990
+ if (ih <= 3 || ih >= 11)
2991
+ cu = 270 - r;
2992
+ else
2993
+ cu = 270 + r;
2994
+ } else {
2995
+ double m;
2996
+ m = atand(fabs(tand(pole) / cosd(w)));
2997
+ if (ih <= 3 || ih >= 11) {
2998
+ if (w > 90 && w < 270)
2999
+ z = m - ecl;
3000
+ else
3001
+ z = m + ecl;
3002
+ } else {
3003
+ if (w > 90 && w < 270)
3004
+ z = m + ecl;
3005
+ else
3006
+ z = m - ecl;
3007
+ }
3008
+ if (z == 90) {
3009
+ if (w < 180)
3010
+ cu = 90;
3011
+ else
3012
+ cu = 270;
3013
+ } else {
3014
+ // r is between 0 and 90
3015
+ r = atand(fabs(cosd(m) * tand(w) / cosd(z)));
3016
+ if (w < 90)
3017
+ cu = r;
3018
+ else if (w > 90 && w < 180)
3019
+ cu = 180 - r;
3020
+ else if (w > 180 && w < 270)
3021
+ cu = 180 + r;
3022
+ else
3023
+ cu = 360 - r;
3024
+ }
3025
+ if (z > 90) {
3026
+ // i am not sure if I understood the remark 'value will fall away from cancer..
3027
+ // on page 146 correctly.
3028
+ if (w < 90)
3029
+ cu = 180 - r;
3030
+ else if (w > 90 && w < 180)
3031
+ cu = + r;
3032
+ else if (w > 180 && w < 270)
3033
+ cu = 360 - r;
3034
+ else
3035
+ cu = 180 + r;
3036
+ }
3037
+ if (lat < 0) // Makransky deals with southern latitude this way
3038
+ cu = swe_degnorm(cu + 180);
3039
+ }
3040
+ hsp->cusp[ih] = cu;
3041
+ }
3042
+ return OK;
3043
+ }
3044
+
3045
+ static int sunshine_solution_treindl(double ramc, double lat, double ecl, struct houses *hsp)
3046
+ {
3047
+ double xh[13];
3048
+ double mcdec, sinlat, coslat, cosdec, tandec, sinecl, cosecl;
3049
+ double xhs, pole, a, cosa, alph, alpha2, c, cosc, b, sinzd, zd, rax, hc;
3050
+ int ih, retval = OK;
3051
+ AS_BOOL mc_under_horizon;
3052
+ double dec = hsp->sundec;
3053
+ // if (90 - fabs(lat) <= ecl) {
3054
+ // strcpy(hsp->serr, "Sunshine in polar circle not allowed");
3055
+ // return ERR;
3056
+ // }
3057
+ sinlat = sind(lat);
3058
+ coslat = cosd(lat);
3059
+ cosdec = cosd(dec);
3060
+ tandec = tand(dec);
3061
+ sinecl = sind(ecl);
3062
+ cosecl = cosd(ecl);
3063
+ sunshine_init(lat, dec, xh);
3064
+ // find out if MC under horizon
3065
+ mcdec = atand(sind(ramc) * tand(ecl));
3066
+ mc_under_horizon = fabs(lat - mcdec) > 90;
3067
+ if (mc_under_horizon && SUNSHINE_KEEP_MC_SOUTH) {
3068
+ // we have switched ac/mc, invert offsets on diurnal arcs
3069
+ for (ih = 2; ih <= 12; ih++) {
3070
+ xh[ih] = -xh[ih];
3071
+ }
3072
+ }
3073
+ //if (sunshine_init(lat, dec, xh) == ERR)
3074
+ // return ERR;
3075
+ // HP is the house point on the semidiurnal arc
3076
+ // CP = intersection house meridian with prime vertical
3077
+ // MP = intersection house meridian with equator
3078
+ // XP = intersection house circle with prime vertical
3079
+ // EP = intersection house circle with equator
3080
+ // MP0 = intersection semiarc with meridian
3081
+ for (ih = 1; ih <= 12; ih++) {
3082
+ if ((ih - 1) % 3 == 0) continue; // skip 1,4,7,10
3083
+ xhs = 2 * asind(cosdec * sind(xh[ih] / 2)); // x' great-circle length of x
3084
+ // compute triangle north pole - mp0 -hp
3085
+ // we have two sides 90 - dec, base xhs, ange at pole x
3086
+ // derive from cosine rule
3087
+ cosa = tandec * tand(xhs / 2);
3088
+ alph = acosd(cosa);
3089
+ // compute triangle south point - mp0 - hp
3090
+ // we have: side x', side b = 90 - lat + dec, angle alpha2 between the sides.
3091
+ // we want: angle zd at south point.
3092
+ // we compute first the other side with Seitencosinus-Satz
3093
+ // cos c = cos x' cos b + sin x' sin b cos alpha2
3094
+ // for nocturnal side: use alpha, side b = 90 - lat - dec;
3095
+ // zd will be angle at north point.
3096
+ if (ih > 7) {
3097
+ // complementary angle
3098
+ alpha2 = 180 - alph;
3099
+ b = 90 - lat + dec;
3100
+ } else { // nocturnal side
3101
+ alpha2 = alph;
3102
+ b = 90 - lat - dec;
3103
+ }
3104
+ // b can be zero, xhs can 90, c can get small.
3105
+ cosc = cosd(xhs) * cosd(b) + sind(xhs) * sind(b) * cosd(alpha2);
3106
+ c = acosd(cosc);
3107
+ // now Sinussatz
3108
+ if (c < 1e-6) {
3109
+ sprintf(hsp->serr, "Sunshine house %d c=%le very small", ih, c);
3110
+ retval = ERR;
3111
+ }
3112
+ sinzd = sind(xhs) * sind(alpha2) / sind(c);
3113
+ zd = asind(sinzd);
3114
+ // compute intersection house circle with equator, point rax
3115
+ // day side triangle south point - meridian point - EP
3116
+ // night side: triangle north point
3117
+ // sides: 90 - lat, angle zd
3118
+ rax = atand(coslat * tand(zd));
3119
+ // compute pole height (distance of house circle pole from equator
3120
+ // with triangle at west point
3121
+ pole = asind(sinzd * sinlat);
3122
+ if (ih <= 6) {
3123
+ pole = -pole;
3124
+ a = swe_degnorm(rax + ramc + 180);
3125
+ } else {
3126
+ a = swe_degnorm(ramc + rax);
3127
+ }
3128
+ // with pole and a = rectascension of equator intersection, we use Asc1()
3129
+ // like with many other house systems, to intersect house circle with eclitpic
3130
+ hc = Asc1(a, pole, sinecl, cosecl);
3131
+ hsp->cusp[ih] = hc;
3132
+ }
3133
+ if (mc_under_horizon && ! SUNSHINE_KEEP_MC_SOUTH) {
3134
+ for (ih = 2; ih <= 12; ih++) {
3135
+ if ((ih - 1) % 3 == 0) continue; // skip 1,4,7,10
3136
+ hsp->cusp[ih] = swe_degnorm(hsp->cusp[ih] + 180);
3137
+ }
3138
+ }
3139
+ return retval;
3140
+ }