/******************************************************* $Header: /home/dieter/sweph/RCS/swehouse.c,v 1.74 2008/06/16 10:07:20 dieter Exp $ module swehouse.c house and (simple) aspect calculation ************************************************************/ /* Copyright (C) 1997 - 2008 Astrodienst AG, Switzerland. All rights reserved. License conditions ------------------ This file is part of Swiss Ephemeris. Swiss Ephemeris is distributed with NO WARRANTY OF ANY KIND. No author or distributor accepts any responsibility for the consequences of using it, or for whether it serves any particular purpose or works at all, unless he or she says so in writing. Swiss Ephemeris is made available by its authors under a dual licensing system. The software developer, who uses any part of Swiss Ephemeris in his or her software, must choose between one of the two license models, which are a) GNU public license version 2 or later b) Swiss Ephemeris Professional License The choice must be made before the software developer distributes software containing parts of Swiss Ephemeris to others, and before any public service using the developed software is activated. If the developer choses the GNU GPL software license, he or she must fulfill the conditions of that license, which includes the obligation to place his or her whole software project under the GNU GPL or a compatible license. See http://www.gnu.org/licenses/old-licenses/gpl-2.0.html If the developer choses the Swiss Ephemeris Professional license, he must follow the instructions as found in http://www.astro.com/swisseph/ and purchase the Swiss Ephemeris Professional Edition from Astrodienst and sign the corresponding license contract. The License grants you the right to use, copy, modify and redistribute Swiss Ephemeris, but only under certain conditions described in the License. Among other things, the License requires that the copyright notices and this notice be preserved on all copies. Authors of the Swiss Ephemeris: Dieter Koch and Alois Treindl The authors of Swiss Ephemeris have no control or influence over any of the derived works, i.e. over software or services created by other programmers which use Swiss Ephemeris functions. The names of the authors or of the copyright holder (Astrodienst) must not be used for promoting any software, product or service which uses or contains the Swiss Ephemeris. This copyright notice is the ONLY place where the names of the authors can legally appear, except in cases where they have given special permission in writing. The trademarks 'Swiss Ephemeris' and 'Swiss Ephemeris inside' may be used for promoting such software, products or services. */ #include "sweodef.h" #include "swephexp.h" #include "sweph.h" #include "swephlib.h" #include "swehouse.h" #include #define MILLIARCSEC (1.0 / 3600000.0) static double Asc1(double, double, double, double); static double Asc2(double, double, double, double); static int CalcH( double th, double fi, double ekl, char hsy, int iteration_count, struct houses *hsp ); static int sidereal_houses_ecl_t0(double tjde, double armc, double eps, double *nutlo, double lat, int hsys, double *cusp, double *ascmc); static int sidereal_houses_trad(double tjde, double armc, double eps, double nutl, double lat, int hsys, double *cusp, double *ascmc); static int sidereal_houses_ssypl(double tjde, double armc, double eps, double *nutlo, double lat, int hsys, double *cusp, double *ascmc); /* housasp.c * cusps are returned in double cusp[13], * or cusp[37] with house system 'G'. * cusp[1...12] houses 1 - 12 * additional points are returned in ascmc[10]. * ascmc[0] = ascendant * ascmc[1] = mc * ascmc[2] = armc * ascmc[3] = vertex * ascmc[4] = equasc * "equatorial ascendant" * * ascmc[5] = coasc1 * "co-ascendant" (W. Koch) * * ascmc[6] = coasc2 * "co-ascendant" (M. Munkasey) * * ascmc[7] = polasc * "polar ascendant" (M. Munkasey) * */ int FAR PASCAL_CONV swe_houses(double tjd_ut, double geolat, double geolon, int hsys, double *cusp, double *ascmc) { int i, retc = 0; double armc, eps, nutlo[2]; double tjde = tjd_ut + swe_deltat(tjd_ut); eps = swi_epsiln(tjde) * RADTODEG; swi_nutation(tjde, nutlo); for (i = 0; i < 2; i++) nutlo[i] *= RADTODEG; armc = swe_degnorm(swe_sidtime0(tjd_ut, eps + nutlo[1], nutlo[0]) * 15 + geolon); #ifdef TRACE swi_open_trace(NULL); if (swi_trace_count <= TRACE_COUNT_MAX) { if (swi_fp_trace_c != NULL) { fputs("\n/*SWE_HOUSES*/\n", swi_fp_trace_c); fprintf(swi_fp_trace_c, "#if 0\n"); fprintf(swi_fp_trace_c, " tjd = %.9f;", tjd_ut); fprintf(swi_fp_trace_c, " geolon = %.9f;", geolon); fprintf(swi_fp_trace_c, " geolat = %.9f;", geolat); fprintf(swi_fp_trace_c, " hsys = %d;\n", hsys); fprintf(swi_fp_trace_c, " retc = swe_houses(tjd, geolat, geolon, hsys, cusp, ascmc);\n"); fprintf(swi_fp_trace_c, " /* swe_houses calls swe_houses_armc as follows: */\n"); fprintf(swi_fp_trace_c, "#endif\n"); fflush(swi_fp_trace_c); } } #endif retc = swe_houses_armc(armc, geolat, eps + nutlo[1], hsys, cusp, ascmc); return retc; } /* housasp.c * cusps are returned in double cusp[13], * or cusp[37] with house system 'G'. * cusp[1...12] houses 1 - 12 * additional points are returned in ascmc[10]. * ascmc[0] = ascendant * ascmc[1] = mc * ascmc[2] = armc * ascmc[3] = vertex * ascmc[4] = equasc * "equatorial ascendant" * * ascmc[5] = coasc1 * "co-ascendant" (W. Koch) * * ascmc[6] = coasc2 * "co-ascendant" (M. Munkasey) * * ascmc[7] = polasc * "polar ascendant" (M. Munkasey) * */ int FAR PASCAL_CONV swe_houses_ex(double tjd_ut, int32 iflag, double geolat, double geolon, int hsys, double *cusp, double *ascmc) { int i, retc = 0; double armc, eps_mean, nutlo[2]; double tjde = tjd_ut + swe_deltat(tjd_ut); struct sid_data *sip = &swed.sidd; int ito; if (toupper(hsys) == 'G') ito = 36; else ito = 12; if ((iflag & SEFLG_SIDEREAL) && !swed.ayana_is_set) swe_set_sid_mode(SE_SIDM_FAGAN_BRADLEY, 0, 0); eps_mean = swi_epsiln(tjde) * RADTODEG; swi_nutation(tjde, nutlo); for (i = 0; i < 2; i++) nutlo[i] *= RADTODEG; #ifdef TRACE swi_open_trace(NULL); if (swi_trace_count <= TRACE_COUNT_MAX) { if (swi_fp_trace_c != NULL) { fputs("\n/*SWE_HOUSES_EX*/\n", swi_fp_trace_c); fprintf(swi_fp_trace_c, "#if 0\n"); fprintf(swi_fp_trace_c, " tjd = %.9f;", tjd_ut); fprintf(swi_fp_trace_c, " iflag = %d;\n", iflag); fprintf(swi_fp_trace_c, " geolon = %.9f;", geolon); fprintf(swi_fp_trace_c, " geolat = %.9f;", geolat); fprintf(swi_fp_trace_c, " hsys = %d;\n", hsys); fprintf(swi_fp_trace_c, " retc = swe_houses_ex(tjd, iflag, geolat, geolon, hsys, cusp, ascmc);\n"); fprintf(swi_fp_trace_c, " /* swe_houses calls swe_houses_armc as follows: */\n"); fprintf(swi_fp_trace_c, "#endif\n"); fflush(swi_fp_trace_c); } } #endif /*houses_to_sidereal(tjde, geolat, hsys, eps, cusp, ascmc, iflag);*/ armc = swe_degnorm(swe_sidtime0(tjd_ut, eps_mean + nutlo[1], nutlo[0]) * 15 + geolon); if (iflag & SEFLG_SIDEREAL) { if (sip->sid_mode & SE_SIDBIT_ECL_T0) retc = sidereal_houses_ecl_t0(tjde, armc, eps_mean + nutlo[1], nutlo, geolat, hsys, cusp, ascmc); else if (sip->sid_mode & SE_SIDBIT_SSY_PLANE) retc = sidereal_houses_ssypl(tjde, armc, eps_mean + nutlo[1], nutlo, geolat, hsys, cusp, ascmc); else retc = sidereal_houses_trad(tjde, armc, eps_mean + nutlo[1], nutlo[0], geolat, hsys, cusp, ascmc); } else { retc = swe_houses_armc(armc, geolat, eps_mean + nutlo[1], hsys, cusp, ascmc); } if (iflag & SEFLG_RADIANS) { for (i = 1; i <= ito; i++) cusp[i] *= DEGTORAD; for (i = 0; i < SE_NASCMC; i++) ascmc[i] *= DEGTORAD; } return retc; } /* * houses to sidereal * ------------------ * there are two methods: * a) the traditional one * houses are computed tropically, then nutation and the ayanamsa * are subtracted. * b) the projection on the ecliptic of t0 * The house computation is then as follows: * * Be t the birth date and t0 the epoch at which ayanamsa = 0. * 1. Compute the angle between the mean ecliptic at t0 and * the true equator at t. * The intersection point of these two circles we call the * "auxiliary vernal point", and the angle between them the * "auxiliary obliquity". * 2. Compute the distance of the auxiliary vernal point from the * vernal point at t. (this is a section on the equator) * 3. subtract this value from the armc of t = aux. armc. * 4. Compute the axes and houses for this aux. armc and aux. obliquity. * 5. Compute the distance between the auxiliary vernal point and the * vernal point at t0 (this is the ayanamsa at t, measured on the * ecliptic of t0) * 6. subtract this distance from all house cusps. * 7. subtract ayanamsa_t0 from all house cusps. */ static int sidereal_houses_ecl_t0(double tjde, double armc, double eps, double *nutlo, double lat, int hsys, double *cusp, double *ascmc) { int i, j, retc = OK; double x[6], xvpx[6], x2[6], epst0, xnorm[6]; double rxy, rxyz, c2, epsx, sgn, fac, dvpx, dvpxe; double armcx; struct sid_data *sip = &swed.sidd; int ito; if (toupper(hsys) == 'G') ito = 36; else ito = 12; /* epsilon at t0 */ epst0 = swi_epsiln(sip->t0); /* cartesian coordinates of an imaginary moving body on the * the mean ecliptic of t0; we take the vernal point: */ x[0] = x[4] = 1; x[1] = x[2] = x[3] = x[5] = 0; /* to equator */ swi_coortrf(x, x, -epst0); swi_coortrf(x+3, x+3, -epst0); /* to tjd_et */ swi_precess(x, sip->t0, J_TO_J2000); swi_precess(x, tjde, J2000_TO_J); swi_precess(x+3, sip->t0, J_TO_J2000); swi_precess(x+3, tjde, J2000_TO_J); /* to true equator of tjd_et */ swi_coortrf(x, x, (eps - nutlo[1]) * DEGTORAD); swi_coortrf(x+3, x+3, (eps - nutlo[1]) * DEGTORAD); swi_cartpol_sp(x, x); x[0] += nutlo[0] * DEGTORAD; swi_polcart_sp(x, x); swi_coortrf(x, x, -eps * DEGTORAD); swi_coortrf(x+3, x+3, -eps * DEGTORAD); /* now, we have the moving point precessed to tjd_et. * next, we compute the auxiliary epsilon: */ swi_cross_prod(x, x+3, xnorm); rxy = xnorm[0] * xnorm[0] + xnorm[1] * xnorm[1]; c2 = (rxy + xnorm[2] * xnorm[2]); rxyz = sqrt(c2); rxy = sqrt(rxy); epsx = asin(rxy / rxyz) * RADTODEG; /* 1a */ /* auxiliary vernal point */ if (fabs(x[5]) < 1e-15) x[5] = 1e-15; fac = x[2] / x[5]; sgn = x[5] / fabs(x[5]); for (j = 0; j <= 2; j++) xvpx[j] = (x[j] - fac * x[j+3]) * sgn; /* 1b */ /* distance of the auxiliary vernal point from * the zero point at tjd_et (a section on the equator): */ swi_cartpol(xvpx, x2); dvpx = x2[0] * RADTODEG; /* 2 */ /* auxiliary armc */ armcx = swe_degnorm(armc - dvpx); /* 3 */ /* compute axes and houses: */ retc = swe_houses_armc(armcx, lat, epsx, hsys, cusp, ascmc); /* 4 */ /* distance between auxiliary vernal point and * vernal point of t0 (a section on the sidereal plane) */ dvpxe = acos(swi_dot_prod_unit(x, xvpx)) * RADTODEG; /* 5 */ if (tjde < sip->t0) dvpxe = -dvpxe; for (i = 1; i <= ito; i++) /* 6, 7 */ cusp[i] = swe_degnorm(cusp[i] - dvpxe - sip->ayan_t0); for (i = 0; i <= SE_NASCMC; i++) ascmc[i] = swe_degnorm(ascmc[i] - dvpxe - sip->ayan_t0); return retc; } /* * Be t the birth date and t0 the epoch at which ayanamsa = 0. * 1. Compute the angle between the solar system rotation plane and * the true equator at t. * The intersection point of these two circles we call the * "auxiliary vernal point", and the angle between them the * "auxiliary obliquity". * 2. Compute the distance of the auxiliary vernal point from the * zero point at t. (this is a section on the equator) * 3. subtract this value from the armc of t = aux. armc. * 4. Compute the axes and houses for this aux. armc and aux. obliquity. * 5. Compute the distance between the auxiliary vernal point at t * and the zero point of the solar system plane J2000 * (a section measured on the solar system plane) * 6. subtract this distance from all house cusps. * 7. compute the ayanamsa of J2000 on the solar system plane, * referred to t0 * 8. subtract ayanamsa_t0 from all house cusps. * 9. subtract ayanamsa_2000 from all house cusps. */ static int sidereal_houses_ssypl(double tjde, double armc, double eps, double *nutlo, double lat, int hsys, double *cusp, double *ascmc) { int i, j, retc = OK; double x[6], x0[6], xvpx[6], x2[6], xnorm[6]; double rxy, rxyz, c2, epsx, eps2000, sgn, fac, dvpx, dvpxe, x00; double armcx; struct sid_data *sip = &swed.sidd; int ito; if (toupper(hsys) == 'G') ito = 36; else ito = 12; eps2000 = swi_epsiln(J2000); /* cartesian coordinates of the zero point on the * the solar system rotation plane */ x[0] = x[4] = 1; x[1] = x[2] = x[3] = x[5] = 0; /* to ecliptic 2000 */ swi_coortrf(x, x, -SSY_PLANE_INCL); swi_coortrf(x+3, x+3, -SSY_PLANE_INCL); swi_cartpol_sp(x, x); x[0] += SSY_PLANE_NODE_E2000; swi_polcart_sp(x, x); /* to equator 2000 */ swi_coortrf(x, x, -eps2000); swi_coortrf(x+3, x+3, -eps2000); /* to mean equator of t */ swi_precess(x, tjde, J2000_TO_J); swi_precess(x+3, tjde, J2000_TO_J); /* to true equator of t */ swi_coortrf(x, x, (eps - nutlo[1]) * DEGTORAD); swi_coortrf(x+3, x+3, (eps - nutlo[1]) * DEGTORAD); swi_cartpol_sp(x, x); x[0] += nutlo[0] * DEGTORAD; swi_polcart_sp(x, x); swi_coortrf(x, x, -eps * DEGTORAD); swi_coortrf(x+3, x+3, -eps * DEGTORAD); /* now, we have the moving point precessed to tjd_et. * next, we compute the auxiliary epsilon: */ swi_cross_prod(x, x+3, xnorm); rxy = xnorm[0] * xnorm[0] + xnorm[1] * xnorm[1]; c2 = (rxy + xnorm[2] * xnorm[2]); rxyz = sqrt(c2); rxy = sqrt(rxy); epsx = asin(rxy / rxyz) * RADTODEG; /* 1a */ /* auxiliary vernal point */ if (fabs(x[5]) < 1e-15) x[5] = 1e-15; fac = x[2] / x[5]; sgn = x[5] / fabs(x[5]); for (j = 0; j <= 2; j++) xvpx[j] = (x[j] - fac * x[j+3]) * sgn; /* 1b */ /* distance of the auxiliary vernal point from * mean vernal point at tjd_et (a section on the equator): */ swi_cartpol(xvpx, x2); dvpx = x2[0] * RADTODEG; /* 2 */ /* auxiliary armc */ armcx = swe_degnorm(armc - dvpx); /* 3 */ /* compute axes and houses: */ retc = swe_houses_armc(armcx, lat, epsx, hsys, cusp, ascmc); /* 4 */ /* distance between the auxiliary vernal point at t and * the sidereal zero point of 2000 at t * (a section on the sidereal plane). */ dvpxe = acos(swi_dot_prod_unit(x, xvpx)) * RADTODEG; /* 5 */ /* (always positive for dates after 5400 bc) */ dvpxe -= SSY_PLANE_NODE * RADTODEG; /* ayanamsa between t0 and J2000, measured on solar system plane: */ /* position of zero point of t0 */ x0[0] = 1; x0[1] = x0[2] = 0; /* zero point of t0 in J2000 system */ if (sip->t0 != J2000) swi_precess(x0, sip->t0, J_TO_J2000); /* zero point to ecliptic 2000 */ swi_coortrf(x0, x0, eps2000); /* to solar system plane */ swi_cartpol(x0, x0); x0[0] -= SSY_PLANE_NODE_E2000; swi_polcart(x0, x0); swi_coortrf(x0, x0, SSY_PLANE_INCL); swi_cartpol(x0, x0); x0[0] += SSY_PLANE_NODE; x00 = x0[0] * RADTODEG; /* 7 */ for (i = 1; i <= ito; i++) /* 6, 8, 9 */ cusp[i] = swe_degnorm(cusp[i] - dvpxe - sip->ayan_t0 - x00); for (i = 0; i <= SE_NASCMC; i++) ascmc[i] = swe_degnorm(ascmc[i] - dvpxe - sip->ayan_t0 - x00); return retc; } /* common simplified procedure */ static int sidereal_houses_trad(double tjde, double armc, double eps, double nutl, double lat, int hsys, double *cusp, double *ascmc) { int i, retc = OK; double ay; int ito; int ihs = toupper(hsys); int ihs2 = ihs; ay = swe_get_ayanamsa(tjde); if (ihs == 'G') ito = 36; else ito = 12; if (ihs == 'W') /* whole sign houses: treat as 'E' and fix later */ ihs2 = 'E'; retc = swe_houses_armc(armc, lat, eps, ihs2, cusp, ascmc); for (i = 1; i <= ito; i++) { cusp[i] = swe_degnorm(cusp[i] - ay - nutl); if (ihs == 'W') /* whole sign houses */ cusp[i] -= fmod(cusp[i], 30); } for (i = 0; i < SE_NASCMC; i++) { if (i == 2) /* armc */ continue; ascmc[i] = swe_degnorm(ascmc[i] - ay - nutl); } return retc; } /* * this function is required for very special computations * where no date is given for house calculation, * e.g. for composite charts or progressive charts. * cusps are returned in double cusp[13], * or cusp[37] with house system 'G'. * cusp[1...12] houses 1 - 12 * additional points are returned in ascmc[10]. * ascmc[0] = ascendant * ascmc[1] = mc * ascmc[2] = armc * ascmc[3] = vertex * ascmc[4] = equasc * "equatorial ascendant" * * ascmc[5] = coasc1 * "co-ascendant" (W. Koch) * * ascmc[6] = coasc2 * "co-ascendant" (M. Munkasey) * * ascmc[7] = polasc * "polar ascendant" (M. Munkasey) * */ int FAR PASCAL_CONV swe_houses_armc( double armc, double geolat, double eps, int hsys, double *cusp, double *ascmc) { struct houses h; int i, retc = 0; int ito; if (toupper(hsys) == 'G') ito = 36; else ito = 12; armc = swe_degnorm(armc); retc = CalcH(armc, geolat, eps, (char)hsys, 2, &h); cusp[0] = 0; for (i = 1; i <= ito; i++) { cusp[i] = h.cusp[i]; } ascmc[0] = h.ac; /* Asc */ ascmc[1] = h.mc; /* Mid */ ascmc[2] = armc; ascmc[3] = h.vertex; ascmc[4] = h.equasc; ascmc[5] = h.coasc1; /* "co-ascendant" (W. Koch) */ ascmc[6] = h.coasc2; /* "co-ascendant" (M. Munkasey) */ ascmc[7] = h.polasc; /* "polar ascendant" (M. Munkasey) */ for (i = SE_NASCMC; i < 10; i++) ascmc[i] = 0; #ifdef TRACE swi_open_trace(NULL); if (swi_trace_count <= TRACE_COUNT_MAX) { if (swi_fp_trace_c != NULL) { fputs("\n/*SWE_HOUSES_ARMC*/\n", swi_fp_trace_c); fprintf(swi_fp_trace_c, " armc = %.9f;", armc); fprintf(swi_fp_trace_c, " geolat = %.9f;", geolat); fprintf(swi_fp_trace_c, " eps = %.9f;", eps); fprintf(swi_fp_trace_c, " hsys = %d;\n", hsys); fprintf(swi_fp_trace_c, " retc = swe_houses_armc(armc, geolat, eps, hsys, cusp, ascmc);\n"); fputs(" printf(\"swe_houses_armc: %f\\t%f\\t%f\\t%c\\t\\n\", ", swi_fp_trace_c); fputs(" armc, geolat, eps, hsys);\n", swi_fp_trace_c); fputs(" printf(\"retc = %d\\n\", retc);\n", swi_fp_trace_c); fputs(" printf(\"cusp:\\n\");\n", swi_fp_trace_c); fputs(" for (i = 0; i < 12; i++)\n", swi_fp_trace_c); fputs(" printf(\" %d\\t%f\\n\", i, cusp[i]);\n", swi_fp_trace_c); fputs(" printf(\"ascmc:\\n\");\n", swi_fp_trace_c); fputs(" for (i = 0; i < 10; i++)\n", swi_fp_trace_c); fputs(" printf(\" %d\\t%f\\n\", i, ascmc[i]);\n", swi_fp_trace_c); fflush(swi_fp_trace_c); } if (swi_fp_trace_out != NULL) { fprintf(swi_fp_trace_out, "swe_houses_armc: %f\t%f\t%f\t%c\t\n", armc, geolat, eps, hsys); fprintf(swi_fp_trace_out, "retc = %d\n", retc); fputs("cusp:\n", swi_fp_trace_out); for (i = 0; i < 12; i++) fprintf(swi_fp_trace_out, " %d\t%f\n", i, cusp[i]); fputs("ascmc:\n", swi_fp_trace_out); for (i = 0; i < 10; i++) fprintf(swi_fp_trace_out, " %d\t%f\n", i, ascmc[i]); fflush(swi_fp_trace_out); } } #endif #if 0 /* for test of swe_house_pos(). * 1st house will be 0, second 30, etc. */ for (i = 1; i <=12; i++) { double x[6]; x[0] = cusp[i]; x[1] = 0; x[2] = 1; cusp[i] = (swe_house_pos(armc, geolat, eps, hsys, x, NULL) - 1) * 30; } #endif return retc; } static int CalcH( double th, double fi, double ekl, char hsy, int iteration_count, struct houses *hsp ) /* ********************************************************* * Arguments: th = sidereal time (angle 0..360 degrees * hsy = letter code for house system; * A equal * E equal * B Alcabitius * C Campanus * G 36 Gauquelin sectors * H horizon / azimut * K Koch * M Morinus * O Porphyry * P Placidus * R Regiomontanus * T Polich/Page ("topocentric") * V equal Vehlow * W equal, whole sign * X axial rotation system/ Meridian houses * U Krusinski-Pisa-Goelzer * fi = geographic latitude * ekl = obliquity of the ecliptic * iteration_count = number of iterations in * Placidus calculation; can be 1 or 2. * ********************************************************* * Koch and Placidus don't work in the polar circle. * We swap MC/IC so that MC is always before AC in the zodiac * We than divide the quadrants into 3 equal parts. * ********************************************************* * All angles are expressed in degrees. * Special trigonometric functions sind, cosd etc. are * implemented for arguments in degrees. ***********************************************************/ { double tane, tanfi, cosfi, tant, sina, cosa, th2; double a, c, f, fh1, fh2, xh1, xh2, rectasc, ad3, acmc, vemc; int i, ih, ih2, retc = OK; double sine, cose; double x[3], krHorizonLon; /* BK 14.02.2006 */ cose = cosd(ekl); sine = sind(ekl); tane = tand(ekl); /* north and south poles */ if (fabs(fabs(fi) - 90) < VERY_SMALL) { if (fi < 0) fi = -90 + VERY_SMALL; else fi = 90 - VERY_SMALL; } tanfi = tand(fi); /* mc */ if (fabs(th - 90) > VERY_SMALL && fabs(th - 270) > VERY_SMALL) { tant = tand(th); hsp->mc = atand(tant / cose); if (th > 90 && th <= 270) hsp->mc = swe_degnorm(hsp->mc + 180); } else { if (fabs(th - 90) <= VERY_SMALL) hsp->mc = 90; else hsp->mc = 270; } /* if */ hsp->mc = swe_degnorm(hsp->mc); /* ascendant */ hsp->ac = Asc1 (th + 90, fi, sine, cose); hsp->cusp[1] = hsp->ac; hsp->cusp[10] = hsp->mc; if (hsy > 95) hsy = (char) (hsy - 32);/* translate into capital letter */ switch (hsy) { case 'A': /* equal houses */ case 'E': /* * within polar circle we swap AC/DC if AC is on wrong side */ acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); hsp->cusp[1] = hsp->ac; } for (i = 2; i <=12; i++) hsp->cusp [i] = swe_degnorm(hsp->cusp [1] + (i-1) * 30); break; case 'C': /* Campanus houses and Horizon or Azimut system */ case 'H': if (hsy == 'H') { if (fi > 0) fi = 90 - fi; else fi = -90 - fi; /* equator */ if (fabs(fabs(fi) - 90) < VERY_SMALL) { if (fi < 0) fi = -90 + VERY_SMALL; else fi = 90 - VERY_SMALL; } th = swe_degnorm(th + 180); } fh1 = asind(sind (fi) / 2); fh2 = asind(sqrt (3.0) / 2 * sind(fi)); cosfi = cosd(fi); if (fabs(cosfi) == 0) { /* '==' should be save! */ if (fi > 0) xh1 = xh2 = 90; /* cosfi = VERY_SMALL; */ else xh1 = xh2 = 270; /* cosfi = -VERY_SMALL; */ } else { xh1 = atand(sqrt (3.0) / cosfi); xh2 = atand(1 / sqrt (3.0) / cosfi); } hsp->cusp [11] = Asc1 (th + 90 - xh1, fh1, sine, cose); hsp->cusp [12] = Asc1 (th + 90 - xh2, fh2, sine, cose); if (hsy == 'H') hsp->cusp [1] = Asc1 (th + 90, fi, sine, cose); hsp->cusp [2] = Asc1 (th + 90 + xh2, fh2, sine, cose); hsp->cusp [3] = Asc1 (th + 90 + xh1, fh1, sine, cose); /* within polar circle, when mc sinks below horizon and * ascendant changes to western hemisphere, all cusps * must be added 180 degrees. * houses will be in clockwise direction */ if (fabs(fi) >= 90 - ekl) { /* within polar circle */ acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); hsp->mc = swe_degnorm(hsp->mc + 180); for (i = 1; i <= 12; i++) hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180); } } if (hsy == 'H') { for (i = 1; i <= 3; i++) hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180); for (i = 11; i <= 12; i++) hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180); /* restore fi and th */ if (fi > 0) fi = 90 - fi; else fi = -90 - fi; th = swe_degnorm(th + 180); acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); } } break; case 'K': /* Koch houses */ if (fabs(fi) >= 90 - ekl) { /* within polar circle */ retc = ERR; goto porphyry; } sina = sind(hsp->mc) * sine / cosd(fi); if (sina > 1) sina = 1; if (sina < -1) sina = -1; cosa = sqrt(1 - sina * sina); /* always >> 0 */ c = atand(tanfi / cosa); ad3 = asind(sind(c) * sina) / 3.0; hsp->cusp [11] = Asc1 (th + 30 - 2 * ad3, fi, sine, cose); hsp->cusp [12] = Asc1 (th + 60 - ad3, fi, sine, cose); hsp->cusp [2] = Asc1 (th + 120 + ad3, fi, sine, cose); hsp->cusp [3] = Asc1 (th + 150 + 2 * ad3, fi, sine, cose); break; case 'O': /* Porphyry houses */ porphyry: /* * within polar circle we swap AC/DC if AC is on wrong side */ acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); hsp->cusp[1] = hsp->ac; acmc = swe_difdeg2n(hsp->ac, hsp->mc); } hsp->cusp [2] = swe_degnorm(hsp->ac + (180 - acmc) / 3); hsp->cusp [3] = swe_degnorm(hsp->ac + (180 - acmc) / 3 * 2); hsp->cusp [11] = swe_degnorm(hsp->mc + acmc / 3); hsp->cusp [12] = swe_degnorm(hsp->mc + acmc / 3 * 2); break; case 'R': /* Regiomontanus houses */ fh1 = atand (tanfi * 0.5); fh2 = atand (tanfi * cosd(30)); hsp->cusp [11] = Asc1 (30 + th, fh1, sine, cose); hsp->cusp [12] = Asc1 (60 + th, fh2, sine, cose); hsp->cusp [2] = Asc1 (120 + th, fh2, sine, cose); hsp->cusp [3] = Asc1 (150 + th, fh1, sine, cose); /* within polar circle, when mc sinks below horizon and * ascendant changes to western hemisphere, all cusps * must be added 180 degrees. * houses will be in clockwise direction */ if (fabs(fi) >= 90 - ekl) { /* within polar circle */ acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); hsp->mc = swe_degnorm(hsp->mc + 180); for (i = 1; i <= 12; i++) hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180); } } break; case 'T': /* 'topocentric' houses */ fh1 = atand (tanfi / 3.0); fh2 = atand (tanfi * 2.0 / 3.0); hsp->cusp [11] = Asc1 (30 + th, fh1, sine, cose); hsp->cusp [12] = Asc1 (60 + th, fh2, sine, cose); hsp->cusp [2] = Asc1 (120 + th, fh2, sine, cose); hsp->cusp [3] = Asc1 (150 + th, fh1, sine, cose); /* within polar circle, when mc sinks below horizon and * ascendant changes to western hemisphere, all cusps * must be added 180 degrees. * houses will be in clockwise direction */ if (fabs(fi) >= 90 - ekl) { /* within polar circle */ acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); hsp->mc = swe_degnorm(hsp->mc + 180); for (i = 1; i <= 12; i++) hsp->cusp[i] = swe_degnorm(hsp->cusp[i] + 180); } } break; case 'V': /* equal houses after Vehlow */ /* * within polar circle we swap AC/DC if AC is on wrong side */ acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); hsp->cusp[1] = hsp->ac; } hsp->cusp [1] = swe_degnorm(hsp->ac - 15); for (i = 2; i <=12; i++) hsp->cusp [i] = swe_degnorm(hsp->cusp [1] + (i-1) * 30); break; case 'W': /* equal, whole-sign houses */ /* * within polar circle we swap AC/DC if AC is on wrong side */ acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); hsp->cusp[1] = hsp->ac; } hsp->cusp [1] = hsp->ac - fmod(hsp->ac, 30); for (i = 2; i <=12; i++) hsp->cusp [i] = swe_degnorm(hsp->cusp [1] + (i-1) * 30); break; case 'X': { /* * Meridian or axial rotation system: * ecliptic points whose rectascensions * are armc + n * 30 */ int j; double a = th; for (i = 1; i <= 12; i++) { j = i + 10; if (j > 12) j -= 12; a = swe_degnorm(a + 30); if (fabs(a - 90) > VERY_SMALL && fabs(a - 270) > VERY_SMALL) { tant = tand(a); hsp->cusp[j] = atand(tant / cose); if (a > 90 && a <= 270) hsp->cusp[j] = swe_degnorm(hsp->cusp[j] + 180); } else { if (fabs(a - 90) <= VERY_SMALL) hsp->cusp[j] = 90; else hsp->cusp[j] = 270; } /* if */ hsp->cusp[j] = swe_degnorm(hsp->cusp[j]); } acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); } break; } case 'M': { /* * Morinus * points of the equator (armc + n * 30) are transformed * into the ecliptic coordinate system */ int j; double a = th; double x[3]; for (i = 1; i <= 12; i++) { j = i + 10; if (j > 12) j -= 12; a = swe_degnorm(a + 30); x[0] = a; x[1] = 0; swe_cotrans(x, x, ekl); hsp->cusp[j] = x[0]; } acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); } break; } case 'B': { /* Alcabitius */ /* created by Alois 17-sep-2000, followed example in Matrix electrical library. The code reproduces the example! See http://www.astro.com/cgi/adict.cgi query: alcabitius in the resuotl page, see program code example. I think the Alcabitius code in Walter Pullen's Astrolog 5.40 is wrong, because he remains in RA and forgets the transform to the ecliptic. */ double dek, r, sna, sda, sn3, sd3; #if FALSE if (fabs(fi) >= 90 - ekl) { /* within polar circle */ retc = ERR; goto porphyry; } #endif acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); hsp->cusp[1] = hsp->ac; acmc = swe_difdeg2n(hsp->ac, hsp->mc); } dek = asind(sind(hsp->ac) * sine); /* declination of Ascendant */ /* must treat the case fi == 90 or -90 */ r = -tanfi * tand(dek); /* must treat the case of abs(r) > 1; probably does not happen * because dek becomes smaller when fi is large, as ac is close to * zero Aries/Libra in that case. */ sda = acos(r) * RADTODEG; /* semidiurnal arc, measured on equator */ sna = 180 - sda; /* complement, seminocturnal arc */ sd3 = sda / 3; sn3 = sna / 3; rectasc = swe_degnorm(th + sd3); /* cusp 11 */ /* project rectasc onto eclipitic with pole height 0, i.e. along the declination circle */ hsp->cusp [11] = Asc1 (rectasc, 0, sine, cose); rectasc = swe_degnorm(th + 2 * sd3); /* cusp 12 */ hsp->cusp [12] = Asc1 (rectasc, 0, sine, cose); rectasc = swe_degnorm(th + 180 - 2 * sn3); /* cusp 2 */ hsp->cusp [2] = Asc1 (rectasc, 0, sine, cose); rectasc = swe_degnorm(th + 180 - sn3); /* cusp 3 */ hsp->cusp [3] = Asc1 (rectasc, 0, sine, cose); } break; case 'G': /* 36 Gauquelin sectors */ for (i = 1; i <= 36; i++) { hsp->cusp[i] = 0; } if (fabs(fi) >= 90 - ekl) { /* within polar circle */ retc = ERR; goto porphyry; } /*************** forth/second quarter ***************/ /* note: Gauquelin sectors are counted in clockwise direction */ a = asind(tand(fi) * tane); for (ih = 2; ih <= 9; ih++) { ih2 = 10 - ih; fh1 = atand(sind(a * ih2 / 9) / tane); rectasc = swe_degnorm((90 / 9) * ih2 + th); tant = tand(asind(sine * sind(Asc1 (rectasc, fh1, sine, cose)))); if (fabs(tant) < VERY_SMALL) { hsp->cusp[ih] = rectasc; } else { /* pole height */ f = atand(sind(asind(tanfi * tant) * ih2 / 9) /tant); hsp->cusp [ih] = Asc1 (rectasc, f, sine, cose); for (i = 1; i <= iteration_count; i++) { tant = tand(asind(sine * sind(hsp->cusp[ih]))); if (fabs(tant) < VERY_SMALL) { hsp->cusp[ih] = rectasc; break; } /* pole height */ f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant); hsp->cusp[ih] = Asc1 (rectasc, f, sine, cose); } } hsp->cusp[ih+18] = swe_degnorm(hsp->cusp[ih] + 180); } /*************** first/third quarter ***************/ for (ih = 29; ih <= 36; ih++) { ih2 = ih - 28; fh1 = atand(sind(a * ih2 / 9) / tane); rectasc = swe_degnorm(180 - ih2 * 90 / 9 + th); tant = tand(asind(sine * sind(Asc1 (rectasc, fh1, sine, cose)))); if (fabs(tant) < VERY_SMALL) { hsp->cusp[ih] = rectasc; } else { f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant); /* pole height */ hsp->cusp[ih] = Asc1 (rectasc, f, sine, cose); for (i = 1; i <= iteration_count; i++) { tant = tand(asind(sine * sind(hsp->cusp[ih]))); if (fabs(tant) < VERY_SMALL) { hsp->cusp[ih] = rectasc; break; } f = atand(sind(asind(tanfi * tant) * ih2 / 9) / tant); /* pole height */ hsp->cusp[ih] = Asc1 (rectasc, f, sine, cose); } } hsp->cusp[ih-18] = swe_degnorm(hsp->cusp[ih] + 180); } hsp->cusp[1] = hsp->ac; hsp->cusp[10] = hsp->mc; hsp->cusp[19] = swe_degnorm(hsp->ac + 180); hsp->cusp[28] = swe_degnorm(hsp->mc + 180); break; case 'U': /* Krusinski-Pisa */ /* * The following code was written by Bogdan Krusinski in 2006. * bogdan@astrologia.pl * * Definition: * "Krusinski - house system based on the great circle passing through * ascendant and zenith. This circle is divided into 12 equal parts * (1st cusp is ascendent, 10th cusp is zenith), then the resulting * points are projected onto the ecliptic through meridian circles. * The house cusps in space are half-circles perpendicular to the equator * and running from the north to the south celestial pole through the * resulting cusp points on the house circle. The points where they * cross the ecliptic mark the ecliptic house cusps." * * Description of the algorithm: * Transform into great circle running through Asc and zenit (where arc * between Asc and zenith is always 90 deg), and then return with * house cusps into ecliptic. Eg. solve trigonometrical triangle * with three transformations and two rotations starting from ecliptic. * House cusps in space are meridian circles. * * Notes: * 1. In this definition we assume MC on ecliptic as point where * half-meridian (from north to south pole) cuts ecliptic, * so MC may be below horizon in arctic regions. * 2. Houses could be calculated in all latitudes except the poles * themselves (-90,90) and points on arctic circle in cases where * ecliptic is equal to horizon and then ascendant is undefined. * But ascendant when 'horizon=ecliptic' could be deduced as limes * from both sides of that point and houses with that provision can * be computed also there. * * Starting values for calculations: * - Asc ecliptic longitude * - right ascension of MC (RAMC) * - geographic latitude. */ /* * within polar circle we swap AC/DC if AC is on wrong side */ acmc = swe_difdeg2n(hsp->ac, hsp->mc); if (acmc < 0) { hsp->ac = swe_degnorm(hsp->ac + 180); } /* A0. Start point - ecliptic coords of ascendant */ x[0] = hsp->ac; /* Asc longitude */ x[1] = 0.0; /* Asc declination */ x[2] = 1.0; /* Radius to test validity of subsequent transformations. */ swe_cotrans(x, x, -ekl); /* A1. Transform into equatorial coords */ x[0] = x[0] - (th-90); /* A2. Rotate */ swe_cotrans(x, x, -(90-fi)); /* A3. Transform into horizontal coords */ krHorizonLon = x[0]; /* ...save asc lon on horizon to get back later with house cusp */ x[0] = x[0] - x[0]; /* A4. Rotate */ swe_cotrans(x, x, -90); /* A5. Transform into this house system great circle (asc-zenith) */ /* As it is house circle now, simple add 30 deg increments... */ for(i = 0; i < 6; i++) { /* B0. Set 'n-th' house cusp. * Note that IC/MC are also calculated here to check * if really this is the asc-zenith great circle. */ x[0] = 30.0*i; x[1] = 0.0; swe_cotrans(x, x, 90); /* B1. Transform back into horizontal coords */ x[0] = x[0] + krHorizonLon; /* B2. Rotate back. */ swe_cotrans(x, x, 90-fi); /* B3. Transform back into equatorial coords */ x[0] = swe_degnorm(x[0] + (th-90)); /* B4. Rotate back -> RA of house cusp as result. */ /* B5. Where's this house cusp on ecliptic? */ /* ... so last but not least - get ecliptic longitude of house cusp: */ hsp->cusp[i+1] = atand(tand(x[0])/cosd(ekl)); if (x[0] > 90 && x[0] <= 270) hsp->cusp[i+1] = swe_degnorm(hsp->cusp[i+1] + 180); hsp->cusp[i+1] = swe_degnorm(hsp->cusp[i+1]); hsp->cusp[i+7] = swe_degnorm(hsp->cusp[i+1]+180); } break; default: /* Placidus houses */ #ifndef _WINDOWS if (hsy != 'P') fprintf (stderr, "swe_houses: make Placidus, unknown key %c\n", hsy); #endif if (fabs(fi) >= 90 - ekl) { /* within polar circle */ retc = ERR; goto porphyry; } a = asind(tand(fi) * tane); fh1 = atand(sind(a / 3) / tane); fh2 = atand(sind(a * 2 / 3) / tane); /* ************ house 11 ******************** */ rectasc = swe_degnorm(30 + th); tant = tand(asind(sine * sind(Asc1 (rectasc, fh1, sine, cose)))); if (fabs(tant) < VERY_SMALL) { hsp->cusp [11] = rectasc; } else { /* pole height */ f = atand(sind(asind(tanfi * tant) / 3) /tant); hsp->cusp [11] = Asc1 (rectasc, f, sine, cose); for (i = 1; i <= iteration_count; i++) { tant = tand(asind(sine * sind(hsp->cusp [11]))); if (fabs(tant) < VERY_SMALL) { hsp->cusp [11] = rectasc; break; } /* pole height */ f = atand(sind(asind(tanfi * tant) / 3) / tant); hsp->cusp [11] = Asc1 (rectasc, f, sine, cose); } } /* ************ house 12 ******************** */ rectasc = swe_degnorm(60 + th); tant = tand(asind(sine*sind(Asc1 (rectasc, fh2, sine, cose)))); if (fabs(tant) < VERY_SMALL) { hsp->cusp [12] = rectasc; } else { f = atand(sind(asind(tanfi * tant) / 1.5) / tant); /* pole height */ hsp->cusp [12] = Asc1 (rectasc, f, sine, cose); for (i = 1; i <= iteration_count; i++) { tant = tand(asind(sine * sind(hsp->cusp [12]))); if (fabs(tant) < VERY_SMALL) { hsp->cusp [12] = rectasc; break; } f = atand(sind(asind(tanfi * tant) / 1.5) / tant); /* pole height */ hsp->cusp [12] = Asc1 (rectasc, f, sine, cose); } } /* ************ house 2 ******************** */ rectasc = swe_degnorm(120 + th); tant = tand(asind(sine * sind(Asc1 (rectasc, fh2, sine, cose)))); if (fabs(tant) < VERY_SMALL) { hsp->cusp [2] = rectasc; } else { f = atand(sind(asind(tanfi * tant) / 1.5) / tant); /* pole height */ hsp->cusp [2] = Asc1 (rectasc, f, sine, cose); for (i = 1; i <= iteration_count; i++) { tant = tand(asind(sine * sind(hsp->cusp [2]))); if (fabs(tant) < VERY_SMALL) { hsp->cusp [2] = rectasc; break; } f = atand(sind(asind(tanfi * tant) / 1.5) / tant); /* pole height */ hsp->cusp [2] = Asc1 (rectasc, f, sine, cose); } } /* ************ house 3 ******************** */ rectasc = swe_degnorm(150 + th); tant = tand(asind(sine * sind(Asc1 (rectasc, fh1, sine, cose)))); if (fabs(tant) < VERY_SMALL) { hsp->cusp [3] = rectasc; } else { f = atand(sind(asind(tanfi * tant) / 3) / tant); /* pole height */ hsp->cusp [3] = Asc1(rectasc, f, sine, cose); for (i = 1; i <= iteration_count; i++) { tant = tand(asind(sine * sind(hsp->cusp [3]))); if (fabs(tant) < VERY_SMALL) { hsp->cusp [3] = rectasc; break; } f = atand(sind(asind(tanfi * tant) / 3) / tant); /* pole height */ hsp->cusp [3] = Asc1 (rectasc, f, sine, cose); } } break; } /* end switch */ if (hsy != 'G') { hsp->cusp [4] = swe_degnorm(hsp->cusp [10] + 180); hsp->cusp [5] = swe_degnorm(hsp->cusp [11] + 180); hsp->cusp [6] = swe_degnorm(hsp->cusp [12] + 180); hsp->cusp [7] = swe_degnorm(hsp->cusp [1] + 180); hsp->cusp [8] = swe_degnorm(hsp->cusp [2] + 180); hsp->cusp [9] = swe_degnorm(hsp->cusp [3] + 180); } /* vertex */ if (fi >= 0) f = 90 - fi; else f = -90 - fi; hsp->vertex = Asc1 (th - 90, f, sine, cose); /* with tropical latitudes, the vertex behaves strange, * in a similar way as the ascendant within the polar * circle. we keep it always on the western hemisphere.*/ if (fabs(fi) <= ekl) { vemc = swe_difdeg2n(hsp->vertex, hsp->mc); if (vemc > 0) hsp->vertex = swe_degnorm(hsp->vertex + 180); } /* * some strange points: */ /* equasc (equatorial ascendant) */ th2 = swe_degnorm(th + 90); if (fabs(th2 - 90) > VERY_SMALL && fabs(th2 - 270) > VERY_SMALL) { tant = tand(th2); hsp->equasc = atand(tant / cose); if (th2 > 90 && th2 <= 270) hsp->equasc = swe_degnorm(hsp->equasc + 180); } else { if (fabs(th2 - 90) <= VERY_SMALL) hsp->equasc = 90; else hsp->equasc = 270; } /* if */ hsp->equasc = swe_degnorm(hsp->equasc); /* "co-ascendant" W. Koch */ hsp->coasc1 = swe_degnorm(Asc1 (th - 90, fi, sine, cose) + 180); /* "co-ascendant" M. Munkasey */ if (fi >= 0) hsp->coasc2 = Asc1 (th + 90, 90 - fi, sine, cose); else /* southern hemisphere */ hsp->coasc2 = Asc1 (th + 90, -90 - fi, sine, cose); /* "polar ascendant" M. Munkasey */ hsp->polasc = Asc1 (th - 90, fi, sine, cose); return retc; } /* procedure houses */ /******************************/ static double Asc1 (double x1, double f, double sine, double cose) { int n; double ass; x1 = swe_degnorm(x1); n = (int) ((x1 / 90) + 1); if (n == 1) ass = ( Asc2 (x1, f, sine, cose)); else if (n == 2) ass = (180 - Asc2 (180 - x1, - f, sine, cose)); else if (n == 3) ass = (180 + Asc2 (x1 - 180, - f, sine, cose)); else ass = (360 - Asc2 (360- x1, f, sine, cose)); ass = swe_degnorm(ass); if (fabs(ass - 90) < VERY_SMALL) /* rounding, e.g.: if */ ass = 90; /* fi = 0 & st = 0, ac = 89.999... */ if (fabs(ass - 180) < VERY_SMALL) ass = 180; if (fabs(ass - 270) < VERY_SMALL) /* rounding, e.g.: if */ ass = 270; /* fi = 0 & st = 0, ac = 89.999... */ if (fabs(ass - 360) < VERY_SMALL) ass = 0; return ass; } /* Asc1 */ static double Asc2 (double x, double f, double sine, double cose) { double ass, sinx; ass = - tand(f) * sine + cose * cosd(x); if (fabs(ass) < VERY_SMALL) ass = 0; sinx = sind(x); if (fabs(sinx) < VERY_SMALL) sinx = 0; if (sinx == 0) { if (ass < 0) ass = -VERY_SMALL; else ass = VERY_SMALL; } else if (ass == 0) { if (sinx < 0) ass = -90; else ass = 90; } else { ass = atand(sinx / ass); } if (ass < 0) ass = 180 + ass; return (ass); } /* Asc2 */ /* Computes the house position of a planet or another point, * in degrees: 0 - 30 = 1st house, 30 - 60 = 2nd house, etc. * armc sidereal time in degrees * geolat geographic latitude * eps true ecliptic obliquity * hsys house system character * xpin array of 6 doubles: * only the first two of them are used: ecl. long., lat. * serr error message area * * House position is returned by function. * * IMPORTANT: This function should NOT be used for sidereal astrology. * If you cannot avoid doing so, please note: * - The input longitudes (xpin) MUST always be tropical, even if you * are a siderealist. * - Sidereal and tropical house positions are identical for most house * systems, if a traditional definition of the sidereal zodiac is used * (sid = trop - ayanamsa). * - The function does NOT provide correct positions for Whole Sign houses. * - The function does NOT provide correct positions, if you use a * non-traditional sidereal method (where the sidereal plane is not * identical to the ecliptic of date) with a house system whose definition * is dependent on the ecliptic, such as: * equal, Porphyry, Alcabitius, Koch, Krusinski (all others should work). * The Swiss Ephemeris currently does not handle these cases. */ double FAR PASCAL_CONV swe_house_pos( double armc, double geolat, double eps, int hsys, double *xpin, char *serr) { double xp[6], xeq[6], ra, de, mdd, mdn, sad, san; double hpos, sinad, ad, a, admc, adp, samc, demc, asc, mc, acmc, tant; double fh, ra0, tanfi, fac, dfac; double x[3], xasc[3], raep, raaz, oblaz, xtemp; /* BK 21.02.2006 */ double sine = sind(eps); double cose = cosd(eps); AS_BOOL is_above_hor = FALSE; AS_BOOL is_invalid = FALSE; AS_BOOL is_circumpolar = FALSE; if (serr != NULL) *serr = '\0'; hsys = toupper(hsys); xeq[0] = xpin[0]; xeq[1] = xpin[1]; xeq[2] = 1; swe_cotrans(xpin, xeq, -eps); ra = xeq[0]; de = xeq[1]; mdd = swe_degnorm(ra - armc); mdn = swe_degnorm(mdd + 180); if (mdd >= 180) mdd -= 360; if (mdn >= 180) mdn -= 360; /* xp[0] will contain the house position, a value between 0 and 360 */ switch(hsys) { case 'A': case 'E': case 'V': case 'W': asc = Asc1 (swe_degnorm(armc + 90), geolat, sine, cose); demc = atand(sind(armc) * tand(eps)); if (geolat >= 0 && 90 - geolat + demc < 0) asc = swe_degnorm(asc + 180); if (geolat < 0 && -90 - geolat + demc > 0) asc = swe_degnorm(asc + 180); xp[0] = swe_degnorm(xpin[0] - asc); if (hsys == 'V') xp[0] = swe_degnorm(xp[0] + 15); if (hsys == 'W') xp[0] = swe_degnorm(xp[0] + fmod(asc, 30)); /* to make sure that a call with a house cusp position returns * a value within the house, 0.001" is added */ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC); hpos = xp[0] / 30.0 + 1; break; case 'O': /* Porphyry */ case 'B': /* Alcabitius */ asc = Asc1 (swe_degnorm(armc + 90), geolat, sine, cose); demc = atand(sind(armc) * tand(eps)); /* mc */ if (fabs(armc - 90) > VERY_SMALL && fabs(armc - 270) > VERY_SMALL) { tant = tand(armc); mc = swe_degnorm(atand(tant / cose)); if (armc > 90 && armc <= 270) mc = swe_degnorm(mc + 180); } else { if (fabs(armc - 90) <= VERY_SMALL) mc = 90; else mc = 270; } /* while MC is always south, * Asc must always be in eastern hemisphere */ if (geolat >= 0 && 90 - geolat + demc < 0) { asc = swe_degnorm(asc + 180); } if (geolat < 0 && -90 - geolat + demc > 0) { asc = swe_degnorm(asc + 180); } if (hsys == 'O') { xp[0] = swe_degnorm(xpin[0] - asc); /* to make sure that a call with a house cusp position returns * a value within the house, 0.001" is added */ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC); if (xp[0] < 180) hpos = 1; else { hpos = 7; xp[0] -= 180; } acmc = swe_difdeg2n(asc, mc); if (xp[0] < 180 - acmc) hpos += xp[0] * 3 / (180 - acmc); else hpos += 3 + (xp[0] - 180 + acmc) * 3 / acmc; } else { /* Alcabitius */ double dek, r, sna, sda; dek = asind(sind(asc) * sine); /* declination of Ascendant */ /* must treat the case fi == 90 or -90 */ tanfi = tand(geolat); r = -tanfi * tand(dek); /* must treat the case of abs(r) > 1; probably does not happen * because dek becomes smaller when fi is large, as ac is close to * zero Aries/Libra in that case. */ sda = acos(r) * RADTODEG; /* semidiurnal arc, measured on equator */ sna = 180 - sda; /* complement, seminocturnal arc */ if (mdd > 0) { if (mdd < sda) hpos = mdd * 90 / sda; else hpos = 90 + (mdd - sda) * 90 / sna; } else { if (mdd > -sna) hpos = 360 + mdd * 90 / sna; else hpos = 270 + (mdd + sna) * 90 / sda; } hpos = swe_degnorm(hpos - 90) / 30.0 + 1.0; if (hpos >= 13.0) hpos -= 12; } break; case 'X': /* Merdidian or axial rotation system */ hpos = swe_degnorm(mdd - 90) / 30.0 + 1.0; break; case 'M': { /* Morinus */ double a = xpin[0]; if (fabs(a - 90) > VERY_SMALL && fabs(a - 270) > VERY_SMALL) { tant = tand(a); hpos = atand(tant / cose); if (a > 90 && a <= 270) hpos = swe_degnorm(hpos + 180); } else { if (fabs(a - 90) <= VERY_SMALL) hpos = 90; else hpos = 270; } /* if */ hpos = swe_degnorm(hpos - armc - 90); hpos = hpos / 30.0 + 1; } break; #if 0 /* old version of Koch method */ case 'K': demc = atand(sind(armc) * tand(eps)); /* if body is within circumpolar region, error */ if (90 - fabs(geolat) <= fabs(de)) { if (serr != NULL) strcpy(serr, "no Koch house position, because planet is circumpolar."); xp[0] = 0; hpos = 0; /* Error */ } else if (90 - fabs(geolat) <= fabs(demc)) { if (serr != NULL) strcpy(serr, "no Koch house position, because mc is circumpolar."); xp[0] = 0; hpos = 0; /* Error */ } else { admc = asind(tand(eps) * tand(geolat) * sind(armc)); adp = asind(tand(geolat) * tand(de)); samc = 90 + admc; if (mdd >= 0) { /* east */ xp[0] = swe_degnorm(((mdd - adp + admc) / samc - 1) * 90); } else { xp[0] = swe_degnorm(((mdd + 180 + adp + admc) / samc + 1) * 90); } /* to make sure that a call with a house cusp position returns * a value within the house, 0.001" is added */ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC); hpos = xp[0] / 30.0 + 1; } break; #endif /* version of Koch method: do calculations within circumpolar circle, * if possible; make sure house positions 4 - 9 only appear on western * hemisphere */ case 'K': demc = atand(sind(armc) * tand(eps)); is_invalid = FALSE; is_circumpolar = FALSE; /* object is within a circumpolar circle */ if (90 - geolat < de || -90 - geolat > de) { adp = 90; is_circumpolar = TRUE; } /* object is within a circumpolar circle, southern hemisphere */ else if (geolat - 90 > de || geolat + 90 < de) { adp = -90; is_circumpolar = TRUE; } /* object does rise and set */ else { adp = asind(tand(geolat) * tand(de)); } #if 0 if (fabs(adp) == 90) is_invalid = TRUE; /* omit this to use the above values */ #endif admc = tand(eps) * tand(geolat) * sind(armc); /* midheaven is circumpolar */ if (fabs(admc) > 1) { #if 0 is_invalid = TRUE; /* omit this line to use the below values */ #endif if (admc > 1) admc = 1; else admc = -1; is_circumpolar = TRUE; } admc = asind(admc); samc = 90 + admc; if (samc == 0) is_invalid = TRUE; if (fabs(samc) > 0) { if (mdd >= 0) { /* east */ dfac = (mdd - adp + admc) / samc; xp[0] = swe_degnorm((dfac - 1) * 90); xp[0] = swe_degnorm(xp[0] + MILLIARCSEC); /* eastern object has longer SA than midheaven */ if (dfac > 2 || dfac < 0) is_invalid = TRUE; /* if this is omitted, funny things happen */ } else { dfac = (mdd + 180 + adp + admc) / samc; xp[0] = swe_degnorm((dfac + 1) * 90); xp[0] = swe_degnorm(xp[0] + MILLIARCSEC); /* western object has longer SA than midheaven */ if (dfac > 2 || dfac < 0) is_invalid = TRUE; /* if this is omitted, funny things happen */ } } if (is_invalid) { xp[0] = 0; hpos = 0; if (serr != NULL) strcpy(serr, "Koch house position failed in circumpolar area"); break; } if (is_circumpolar) { if (serr != NULL) strcpy(serr, "Koch house position, doubtful result in circumpolar area"); } /* to make sure that a call with a house cusp position returns * a value within the house, 0.001" is added */ hpos = xp[0] / 30.0 + 1; break; case 'C': xeq[0] = swe_degnorm(mdd - 90); swe_cotrans(xeq, xp, -geolat); /* to make sure that a call with a house cusp position returns * a value within the house, 0.001" is added */ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC); hpos = xp[0] / 30.0 + 1; break; case 'U': /* Krusinski-Pisa-Goelzer */ /* Purpose: find point where planet's house circle (meridian) * cuts house plane, giving exact planet's house position. * Input data: ramc, geolat, asc. */ asc = Asc1 (swe_degnorm(armc + 90), geolat, sine, cose); demc = atand(sind(armc) * tand(eps)); /* while MC is always south, * Asc must always be in eastern hemisphere */ if (geolat >= 0 && 90 - geolat + demc < 0) { asc = swe_degnorm(asc + 180); } if (geolat < 0 && -90 - geolat + demc > 0) { asc = swe_degnorm(asc + 180); } /* * Descr: find the house plane 'asc-zenith' - where it intersects * with equator and at what angle, and then simple find arc * from asc on that plane to planet's meridian intersection * with this plane. */ /* I. find plane of 'asc-zenith' great circle relative to equator: * solve spherical triangle 'EP-asc-intersection of house circle with equator' */ /* Ia. Find intersection of house plane with equator: */ x[0] = asc; x[1] = 0.0; x[2] = 1.0; /* 1. Start with ascendent on ecliptic */ swe_cotrans(x, x, -eps); /* 2. Transform asc into equatorial coords */ raep = swe_degnorm(armc + 90); /* 3. RA of east point */ x[0] = swe_degnorm(raep - x[0]); /* 4. Rotation - found arc raas-raep */ swe_cotrans(x, x, -(90-geolat)); /* 5. Transform into horizontal coords - arc EP-asc on horizon */ xtemp = atand(tand(x[0])/cosd((90-geolat))); /* 6. Rotation from horizon on circle perpendicular to equator */ if (x[0] > 90 && x[0] <= 270) xtemp = swe_degnorm(xtemp + 180); x[0] = swe_degnorm(xtemp); raaz = swe_degnorm(raep - x[0]); /* result: RA of intersection 'asc-zenith' great circle with equator */ /* Ib. Find obliquity to equator of 'asc-zenith' house plane: */ x[0] = raaz; x[1] = 0.0; x[0] = swe_degnorm(raep - x[0]); /* 1. Rotate start point relative to EP */ swe_cotrans(x, x, -(90-geolat)); /* 2. Transform into horizontal coords */ x[1] = x[1] + 90; /* 3. Add 90 deg do decl - so get the point on house plane most distant from equ. */ swe_cotrans(x, x, 90-geolat); /* 4. Rotate back to equator */ oblaz = x[1]; /* 5. Obliquity of house plane to equator */ /* II. Next find asc and planet position on house plane, * so to find relative distance of planet from * coords beginning. */ /* IIa. Asc on house plane relative to intersection * of equator with 'asc-zenith' plane. */ xasc[0] = asc; xasc[1] = 0.0; xasc[2] = 1.0; swe_cotrans(xasc, xasc, -eps); xasc[0] = swe_degnorm(xasc[0] - raaz); xtemp = atand(tand(xasc[0])/cosd(oblaz)); if (xasc[0] > 90 && xasc[0] <= 270) xtemp = swe_degnorm(xtemp + 180); xasc[0] = swe_degnorm(xtemp); /* IIb. Planet on house plane relative to intersection * of equator with 'asc-zenith' plane */ xp[0] = swe_degnorm(xeq[0] - raaz); /* Rotate on equator */ xtemp = atand(tand(xp[0])/cosd(oblaz)); /* Find arc on house plane from equator */ if (xp[0] > 90 && xp[0] <= 270) xtemp = swe_degnorm(xtemp + 180); xp[0] = swe_degnorm(xtemp); xp[0] = swe_degnorm(xp[0]-xasc[0]); /* find arc between asc and planet, and get planet house position */ /* IIc. Distance from planet to house plane on declination circle: */ x[0] = xeq[0]; x[1] = xeq[1]; swe_cotrans(x, x, oblaz); xp[1] = xeq[1] - x[1]; /* How many degrees is the point on declination circle from house circle */ /* to make sure that a call with a house cusp position returns * a value within the house, 0.001" is added */ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC); hpos = xp[0] / 30.0 + 1; break; case 'H': xeq[0] = swe_degnorm(mdd - 90); swe_cotrans(xeq, xp, 90 - geolat); /* to make sure that a call with a house cusp position returns * a value within the house, 0.001" is added */ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC); hpos = xp[0] / 30.0 + 1; break; case 'R': if (fabs(mdd) < VERY_SMALL) xp[0] = 270; else if (180 - fabs(mdd) < VERY_SMALL) xp[0] = 90; else { if (90 - fabs(geolat) < VERY_SMALL) { if (geolat > 0) geolat = 90 - VERY_SMALL; else geolat = -90 + VERY_SMALL; } if (90 - fabs(de) < VERY_SMALL) { if (de > 0) de = 90 - VERY_SMALL; else de = -90 + VERY_SMALL; } a = tand(geolat) * tand(de) + cosd(mdd); xp[0] = swe_degnorm(atand(-a / sind(mdd))); if (mdd < 0) xp[0] += 180; xp[0] = swe_degnorm(xp[0]); /* to make sure that a call with a house cusp position returns * a value within the house, 0.001" is added */ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC); } hpos = xp[0] / 30.0 + 1; break; case 'T': mdd = swe_degnorm(mdd); if (de > 90 - VERY_SMALL) de = 90 - VERY_SMALL; if (de < -90 + VERY_SMALL) de = -90 + VERY_SMALL; sinad = tand(de) * tand(geolat); ad = asind(sinad); a = sinad + cosd(mdd); if (a >= 0) is_above_hor = TRUE; /* mirror everything below the horizon to the opposite point * above the horizon */ if (!is_above_hor) { ra = swe_degnorm(ra + 180); de = -de; mdd = swe_degnorm(mdd + 180); } /* mirror everything on western hemisphere to eastern hemisphere */ if (mdd > 180) { ra = swe_degnorm(armc - mdd); } /* binary search for "topocentric" position line of body */ tanfi = tand(geolat); fh = geolat; ra0 = swe_degnorm(armc + 90); xp[1] = 1; xeq[1] = de; fac = 2; while (fabs(xp[1]) > 0.000001) { if (xp[1] > 0) { fh = atand(tand(fh) - tanfi / fac); ra0 -= 90 / fac; } else { fh = atand(tand(fh) + tanfi / fac); ra0 += 90 / fac; } xeq[0] = swe_degnorm(ra - ra0); swe_cotrans(xeq, xp, 90 - fh); fac *= 2; } hpos = swe_degnorm(ra0 - armc); /* mirror back to west */ if (mdd > 180) hpos = swe_degnorm(-hpos); /* mirror back to below horizon */ if (!is_above_hor) hpos = swe_degnorm(hpos + 180); hpos = swe_degnorm(hpos - 90) / 30 + 1; break; case 'P': case 'G': default: /* circumpolar region */ if (90 - fabs(de) <= fabs(geolat)) { if (de * geolat < 0) xp[0] = swe_degnorm(90 + mdn / 2); else xp[0] = swe_degnorm(270 + mdd / 2); if (serr != NULL) strcpy(serr, "Otto Ludwig procedure within circumpolar regions."); } else { sinad = tand(de) * tand(geolat); ad = asind(sinad); a = sinad + cosd(mdd); if (a >= 0) is_above_hor = TRUE; sad = 90 + ad; san = 90 - ad; if (is_above_hor) xp[0] = (mdd / sad + 3) * 90; else xp[0] = (mdn / san + 1) * 90; /* to make sure that a call with a house cusp position returns * a value within the house, 0.001" is added */ xp[0] = swe_degnorm(xp[0] + MILLIARCSEC); } if (hsys == 'G') { xp[0] = 360 - xp[0]; /* Gauquelin sectors are in clockwise direction */ hpos = xp[0] / 10.0 + 1; } else { hpos = xp[0] / 30.0 + 1; } break; } return hpos; }