This is formulas.c in view mode; [Download] [Up]
/* ** Astrolog (Version 4.10) File: formulas.c ** ** IMPORTANT NOTICE: the graphics database and chart display routines ** used in this program are Copyright (C) 1991-1994 by Walter D. Pullen ** (cruiser1@stein.u.washington.edu). Permission is granted to freely ** use and distribute these routines provided one doesn't sell, ** restrict, or profit from them in any way. Modification is allowed ** provided these notices remain with any altered or edited versions of ** the program. ** ** The main planetary calculation routines used in this program have ** been Copyrighted and the core of this program is basically a ** conversion to C of the routines created by James Neely as listed in ** Michael Erlewine's 'Manual of Computer Programming for Astrologers', ** available from Matrix Software. The copyright gives us permission to ** use the routines for personal use but not to sell them or profit from ** them in any way. ** ** The PostScript code within the core graphics routines are programmed ** and Copyright (C) 1992-1993 by Brian D. Willoughby ** (brianw@sounds.wa.com). Conditions are identical to those above. ** ** The extended accurate ephemeris databases and formulas are from the ** calculation routines in the program "Placalc" and are programmed and ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl ** (alois@azur.ch). The use of that source code is subject to ** regulations made by Astrodienst Zurich, and the code is not in the ** public domain. This copyright notice must not be changed or removed ** by any user of this program. ** ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991. ** X Window graphics initially programmed 10/23-29/1991. ** PostScript graphics initially programmed 11/29-30/1992. ** Last code change made 3/19/1994. */ #include "astrolog.h" real MC, Asc, Vtx, RA, OB, X, Y, A; real planet1[TOTAL+1], planet2[TOTAL+1], planetalt1[TOTAL+1], planetalt2[TOTAL+1], house1[SIGNS+1], house2[SIGNS+1], ret1[TOTAL+1], ret2[TOTAL+1]; real FAR *datapointer; /* ****************************************************************************** ** Specific Calculations. ****************************************************************************** */ #ifdef MATRIX /* Given a month, day, and year, convert it into a single Julian day value, */ /* i.e. the number of days passed since a fixed reference date. */ long MdyToJulian(mon, day, yea) int mon, day, yea; { #ifndef PLACALC long im, j; im = 12*((long)yea+4800)+(long)mon-3; j = (2*(im%12) + 7 + 365*im)/12; j += (long)day + im/48 - 32083; if (j > 2299171) /* Take care of dates in */ j += im/4800 - im/1200 + 38; /* Gregorian calendar. */ return j; #else int greg = TRUE; if (yea < G2JYEA || (yea == G2JYEA && (mon < G2JMON || (mon == G2JMON && day < 15)))) greg = FALSE; return (long)floor(julday(mon, day, yea, 12.0, greg)+ROUND); #endif } /* Take a Julian day value, and convert it back into the corresponding */ /* month, day, and year. */ void JulianToMdy(JD, mon, day, yea) real JD; int *mon, *day, *yea; { #ifndef PLACALC long L, N, IT, JT, K, IK; L = (long)floor(JD+ROUND)+68569L; N = Dvd(4L*L, 146097L); L -= Dvd(146097L*N + 3L, 4L); IT = Dvd(4000L*(L+1L), 1461001L); L -= Dvd(1461L*IT, 4L) - 31L; JT = Dvd(80L*L, 2447L); K = L-Dvd(2447L*JT, 80L); L = Dvd(JT, 11L); JT += 2L - 12L*L; IK = 100L*(N-49L) + IT + L; *mon = (int)JT; *day = (int)K; *yea = (int)IK; #else int greg = TRUE; double tim; if (JD < 2299171.0) /* October 15, 1582 */ greg = FALSE; revjul(JD, greg, mon, day, yea, &tim); #endif } /* This is a subprocedure of CastChart(). Once we have the chart parameters, */ /* calculate a few important things related to the date, i.e. the Greenwich */ /* time, the Julian day and fractional part of the day, the offset to the */ /* sidereal, and a couple of other things. */ real ProcessInput(var) int var; { real Off, Ln; TT = Sgn(TT)*floor(dabs(TT))+FRACT(dabs(TT))*100.0/60.0+DecToDeg(ZZ); OO = DecToDeg(OO); AA = MIN(AA, 89.9999); /* Make sure the chart isn't being cast */ AA = MAX(AA, -89.9999); /* on the precise north or south pole. */ AA = DTOR(DecToDeg(AA)); /* if parameter 'var' isn't set, then we can assume that the true time */ /* has already been determined (as in a -rm switch time midpoint chart). */ if (var) { JD = (real)MdyToJulian(MM, DD, YY); if (!progress || (operation & DASHp0) > 0) T = ((JD-2415020.0)+TT/24.0-0.5)/36525.0; else /* Determine actual time that a progressed chart is to be cast for. */ T = (((Jdp-JD)/progday+JD)-2415020.0+TT/24.0-0.5)/36525.0; } /* Compute angle that the ecliptic is inclined to the Celestial Equator */ OB = DTOR(23.452294-0.0130125*T); Ln = Mod((933060-6962911*T+7.5*T*T)/3600.0); /* Mean lunar node */ Off = (259205536.0*T+2013816.0)/3600.0; /* Mean Sun */ Off = 17.23*sin(DTOR(Ln))+1.27*sin(DTOR(Off))-(5025.64+1.11*T)*T; Off = (Off-84038.27)/3600.0; SD = ((operation & DASHs) ? Off : 0.0) + addfactor; return Off; } /* Convert polar to rectangular coordinates. */ void PolToRec(A, R, X, Y) real A, R, *X, *Y; { if (A == 0.0) A = SMALL; *X = R*cos(A); *Y = R*sin(A); } /* Convert rectangular to polar coordinates. */ void RecToPol(X, Y, A, R) real X, Y, *A, *R; { if (Y == 0.0) Y = SMALL; *R = sqrt(X*X+Y*Y); *A = Angle(X, Y); } /* Convert rectangular to spherical coordinates. */ real RecToSph(B, L, O) real B, L, O; { real R, Q, G; A = B; R = 1.0; PolToRec(A, R, &X, &Y); Q = Y; R = X; A = L; PolToRec(A, R, &X, &Y); G = X; X = Y; Y = Q; RecToPol(X, Y, &A, &R); A += O; PolToRec(A, R, &X, &Y); Q = ASIN(Y); Y = X; X = G; RecToPol(X, Y, &A, &R); if (A < 0.0) A += 2*PI; G = A; return G; } /* Do a coordinate transformation: Given a longitude and latitude value, */ /* return the new longitude and latitude values that the same location */ /* would have, were the equator tilted by a specified number of degrees. */ /* In other words, do a pole shift! This is used to convert among ecliptic, */ /* equatorial, and local coordinates, each of which have zero declination */ /* in different planes. In other words, take into account the Earth's axis. */ void CoorXform(azi, alt, tilt) real *azi, *alt, tilt; { real x, y, a1, l1; real sinalt, cosalt, sinazi, sintilt, costilt; sinalt = sin(*alt); cosalt = cos(*alt); sinazi = sin(*azi); sintilt = sin(tilt); costilt = cos(tilt); x = cosalt * sinazi * costilt; y = sinalt * sintilt; x -= y; a1 = cosalt; y = cosalt * cos(*azi); l1 = Angle(y, x); a1 = a1 * sinazi * sintilt + sinalt * costilt; a1 = ASIN(a1); *azi = l1; *alt = a1; } /* This is another subprocedure of CastChart(). Calculate a few variables */ /* corresponding to the chart parameters that are used later on. The */ /* astrological vertex (object number twenty) is also calculated here. */ void ComputeVariables() { real R, R2, B, L, O, G; RA = DTOR(Mod((6.6460656+2400.0513*T+2.58E-5*T*T+TT)*15.0-OO)); R2 = RA; O = -OB; B = AA; A = R2; R = 1.0; PolToRec(A, R, &X, &Y); X *= cos(O); RecToPol(X, Y, &A, &R); MC = Mod(SD+RTOD(A)); /* Midheaven */ L = R2; G = RecToSph(B, L, O); #if FALSE Asc = Mod(SD+Mod(G+PI/2.0)); /* Ascendant */ #endif L= R2+PI; B = PI/2.0-dabs(B); if (AA < 0.0) B = -B; G = RecToSph(B, L, O); Vtx = Mod(SD+RTOD(G+PI/2.0)); /* Vertex */ } #endif /* MATRIX */ /* ****************************************************************************** ** House Cusp Calculations. ****************************************************************************** */ /* This is a subprocedure of HousePlace(). Given a zodiac position, return */ /* which of the twelve houses it falls in. Remember that a special check */ /* has to be done for the house that spans 0 degrees Aries. */ int HousePlaceIn(point) real point; { int i = 0; point = Mod(point + 0.5/60.0/60.0); do { i++; } while (!(i >= SIGNS || (point >= house[i] && point < house[Mod12(i+1)]) || (house[i] > house[Mod12(i+1)] && (point >= house[i] || point < house[Mod12(i+1)])))); return i; } /* For each object in the chart, determine what house it belongs in. */ void HousePlace() { int i; for (i = 1; i <= total; i++) inhouse[i] = HousePlaceIn(planet[i]); } #ifdef MATRIX /* The following two functions calculate the midheaven and ascendant of */ /* the chart in question, based on time and location. They are also used */ /* in some of the house cusp calculation routines as a quick way to get */ /* the 10th and 1st house cusps. */ real CuspMidheaven() { real MC; MC = ATAN(tan(RA)/cos(OB)); if (MC < 0.0) MC += PI; if (RA > PI) MC += PI; return Mod(RTOD(MC)+SD); } real CuspAscendant() { real Asc; Asc = Angle(-sin(RA)*cos(OB)-tan(AA)*sin(OB), cos(RA)); return Mod(RTOD(Asc)+SD); } /* These are various different algorithms for calculating the house cusps: */ real CuspPlacidus(deg, FF, neg) real deg, FF; bool neg; { real LO, R1, R2, XS; int i; R1 = RA+DTOR(deg); if (neg) X = 1.0; else X = -1.0; for (i = 1; i <= 10; i++) { /* This formula works except at 0 latitude (AA == 0.0). */ XS = X*sin(R1)*tan(OB)*tan(AA == 0.0 ? 0.0001 : AA); XS = ACOS(XS); if (XS < 0.0) XS += PI; if (neg) R2 = RA+PI-(XS/FF); else R2 = RA+(XS/FF); R1 = R2; } LO = ATAN(tan(R1)/cos(OB)); if (LO < 0.0) LO += PI; if (sin(R1) < 0.0) LO += PI; return RTOD(LO); } void HousePlacidus() { int i; house[1] = Mod(Asc-SD); house[4] = Mod(MC+DEGHALF-SD); house[5] = CuspPlacidus(30.0, 3.0, FALSE) + DEGHALF; house[6] = CuspPlacidus(60.0, 1.5, FALSE) + DEGHALF; house[2] = CuspPlacidus(120.0, 1.5, TRUE); house[3] = CuspPlacidus(150.0, 3.0, TRUE); for (i = 1; i <= SIGNS; i++) { if (i <= 6) house[i] = Mod(house[i]+SD); else house[i] = Mod(house[i-6]+DEGHALF); } } void HouseKoch() { real A1, A2, A3, KN, D; int i; A1 = sin(RA)*tan(AA)*tan(OB); A1 = ASIN(A1); for (i = 1; i <= SIGNS; i++) { D = Mod(60.0+30.0*(real)i); A2 = D/DEGQUAD-1.0; KN = 1.0; if (D >= DEGHALF) { KN = -1.0; A2 = D/DEGQUAD-3.0; } A3 = DTOR(Mod(RTOD(RA)+D+A2*RTOD(A1))); X = Angle(cos(A3)*cos(OB)-KN*tan(AA)*sin(OB), sin(A3)); house[i] = Mod(RTOD(X)+SD); } } void HouseEqual() { int i; for (i = 1; i <= SIGNS; i++) house[i] = Mod(Asc-30.0+30.0*(real)i); } void HouseCampanus() { real KO, DN; int i; for (i = 1; i <= SIGNS; i++) { KO = DTOR(60.000001+30.0*(real)i); DN = ATAN(tan(KO)*cos(AA)); if (DN < 0.0) DN += PI; if (sin(KO) < 0.0) DN += PI; X = Angle(cos(RA+DN)*cos(OB)-sin(DN)*tan(AA)*sin(OB), sin(RA+DN)); house[i] = Mod(RTOD(X)+SD); } } void HouseMeridian() { real D; int i; for (i = 1; i <= SIGNS; i++) { D = DTOR(60.0+30.0*(real)i); X = Angle(cos(RA+D)*cos(OB), sin(RA+D)); house[i] = Mod(RTOD(X)+SD); } } void HouseRegiomontanus() { real D; int i; for (i = 1; i <= SIGNS; i++) { D = DTOR(60.0+30.0*(real)i); X = Angle(cos(RA+D)*cos(OB)-sin(D)*tan(AA)*sin(OB), sin(RA+D)); house[i] = Mod(RTOD(X)+SD); } } void HousePorphyry() { int i; X = Asc-MC; if (X < 0.0) X += DEGREES; Y = X/3.0; for (i = 1; i <= 2; i++) house[i+4] = Mod(DEGHALF+MC+i*Y); X = Mod(DEGHALF+MC)-Asc; if (X < 0.0) X += DEGREES; house[1]=Asc; Y = X/3.0; for (i = 1; i <= 3; i++) house[i+1] = Mod(Asc+i*Y); for (i = 1; i <= 6; i++) house[i+6] = Mod(house[i]+DEGHALF); } void HouseMorinus() { real D; int i; for (i = 1; i <= SIGNS; i++) { D = DTOR(60.0+30.0*(real)i); X = Angle(cos(RA+D), sin(RA+D)*cos(OB)); house[i] = Mod(RTOD(X)+SD); } } real CuspTopocentric(deg) real deg; { real OA, X, LO; OA = Mod(RA+DTOR(deg)); X = ATAN(tan(AA)/cos(OA)); LO = ATAN(cos(X)*tan(OA)/cos(X+OB)); if (LO < 0.0) LO += PI; if (sin(OA) < 0.0) LO += PI; return LO; } void HouseTopocentric() { real TL, P1, P2, LT; int i; modulus = 2.0*PI; house[4] = Mod(DTOR(MC+DEGHALF-SD)); TL = tan(AA); P1 = ATAN(TL/3.0); P2 = ATAN(TL/1.5); LT = AA; AA = P1; house[5] = CuspTopocentric(30.0) + PI; AA = P2; house[6] = CuspTopocentric(60.0) + PI; AA = LT; house[1] = CuspTopocentric(90.0); AA = P2; house[2] = CuspTopocentric(120.0); AA = P1; house[3] = CuspTopocentric(150.0); AA = LT; modulus = DEGREES; for (i = 1; i <= 6; i++) { house[i] = Mod(RTOD(house[i])+SD); house[i+6] = Mod(house[i]+DEGHALF); } } #endif /* MATRIX */ /* This house system is just like the Equal system except that we start */ /* our 12 equal segments from the Midheaven instead of the Ascendant. */ void HouseEqualMidheaven() { int i; for (i = 1; i <= SIGNS; i++) house[i] = Mod(MC-270.0+30.0*(real)(i-1)); } /* This is a new house system similar in philosophy to Porphyry houses. */ /* Instead of just trisecting the difference in each quadrant, we do a */ /* smooth sinusoidal distribution of the difference around all the cusps. */ void HousePorphyryNeo() { real delta; int i; delta = (MinDistance(MC, Asc) - DEGQUAD)/4.0; house[_LIB] = Mod(Asc+DEGHALF); house[_CAP] = MC; house[_AQU] = Mod(house[_CAP] + 30.0 + delta + SD); house[_PIS] = Mod(house[_AQU] + 30.0 + delta*2 + SD); house[_SAG] = Mod(house[_CAP] - 30.0 + delta + SD); house[_SCO] = Mod(house[_SAG] - 30.0 + delta*2 + SD); for (i = _ARI; i < _LIB; i++) house[i] = Mod(house[i+6]-DEGHALF); } /* In "null" houses, the cusps are always fixed to start at their */ /* corresponding sign, i.e. the 1st house is always at 0 degrees Aries, etc. */ void HouseNull() { int i; for (i = 1; i <= SIGNS; i++) house[i] = Mod(STOZ(i)+SD); } /* Calculate the house cusp positions, using the specified algorithm. */ void ComputeHouses(housesystem) int housesystem; { char string[STRING]; if (dabs(AA) > DTOR(DEGQUAD-TROPIC) && housesystem < 2) { sprintf(string, "The %s system of houses is not defined at extreme latitudes.", systemname[housesystem]); PrintError(string); Terminate(_FATAL); } switch (housesystem) { case 1: HouseKoch(); break; case 2: HouseEqual(); break; case 3: HouseCampanus(); break; case 4: HouseMeridian(); break; case 5: HouseRegiomontanus(); break; case 6: HousePorphyry(); break; case 7: HouseMorinus(); break; case 8: HouseTopocentric(); break; case 9: HouseEqualMidheaven(); break; case 10: HousePorphyryNeo(); break; case 11: HouseNull(); break; default: HousePlacidus(); } } #ifdef MATRIX /* ****************************************************************************** ** Planetary Position Calculations. ****************************************************************************** */ /* Read the next three values from the planet data stream, and return them */ /* combined as the coefficients of a quadratic equation in the chart time. */ real ReadThree() { real S0, S1, S2; S0 = ReadPlanetData(); S1 = ReadPlanetData(); S2 = ReadPlanetData(); return S0 = DTOR(S0+S1*T+S2*T*T); } /* Another coordinate transformation. This is used by the ComputePlanets() */ /* procedure to rotate rectangular coordinates by a certain amount. */ real RecToSph2(AP, AN, IN) real AP, AN, IN; { real R, D, G; RecToPol(X, Y, &A, &R); A += AP; PolToRec(A, R, &X, &Y); D = X; X = Y; Y = 0.0; RecToPol(X, Y, &A, &R); A += IN; PolToRec(A, R, &X, &Y); G = Y; Y = X; X = D; RecToPol(X, Y, &A, &R); A += AN; if (A < 0.0) A += 2.0*PI; PolToRec(A, R, &X, &Y); return G; } /* Calculate some harmonic delta error correction factors to add onto the */ /* coordinates of Jupiter through Pluto, for better accuracy. */ void ErrorCorrect(ind, x, y, z) int ind; real *x, *y, *z; { real U, V, W, S0, T0[4]; int IK, IJ, errorindex; errorindex = errorcount[ind]; for (IK = 1; IK <= 3; IK++) { if (ind == 6 && IK == 3) { T0[3] = 0.0; break; } if (IK == 3) errorindex--; S0 = ReadThree(); A = 0.0; for (IJ = 1; IJ <= errorindex; IJ++) { U = ReadPlanetData(); V = ReadPlanetData(); W = ReadPlanetData(); A = A+DTOR(U)*cos((V*T+W)*PI/DEGHALF); } T0[IK] = RTOD(S0+A); } *x += T0[2]; *y += T0[1]; *z += T0[3]; } /* Another subprocedure of the ComputePlanets() routine. Convert the final */ /* rectangular coordinates of a planet to zodiac position and declination. */ void ProcessPlanet(ind, aber) int ind; real aber; { real ang, rad; RecToPol(spacex[ind], spacey[ind], &ang, &rad); planet[ind] = Mod(RTOD(ang) /*+ NU*/ - aber + SD); RecToPol(rad, spacez[ind], &ang, &rad); if (centerplanet == _SUN && ind == _SUN) ang = 0.0; planetalt[ind] = RTOD(ang); } /* This is probably the heart of the whole program of Astrolog. Calculate */ /* the position of each body that orbits the Sun. A heliocentric chart is */ /* most natural; extra calculation is needed to have other central bodies. */ void ComputePlanets() { real helio[BASE+1], helioalt[BASE+1], helioret[BASE+1], heliox[BASE+1], helioy[BASE+1], helioz[BASE+1]; real aber = 0.0, AU, E, EA, E1, M, XW, YW, AP, AN, IN, G, XS, YS, ZS; int ind = 1, i; datapointer = planetdata; while (ind <= (operation & DASHu ? BASE : PLANETS+1)) { modulus = 2.0*PI; EA = M = Mod(ReadThree()); /* Calculate mean anomaly */ E = RTOD(ReadThree()); /* Calculate eccentricity */ for (i = 1; i <= 5; i++) EA = M+E*sin(EA); /* Solve Kepler's equation */ AU = ReadPlanetData(); /* Semi-major axis */ E1 = 0.01720209/(pow(AU, 1.5)* (1.0-E*cos(EA))); /* Begin velocity coordinates */ XW = -AU*E1*sin(EA); /* Perifocal coordinates */ YW = AU*E1*pow(1.0-E*E,0.5)*cos(EA); AP = ReadThree(); AN = ReadThree(); IN = ReadThree(); /* Calculate inclination */ X = XW; Y = YW; G = RecToSph2(AP, AN, IN); /* Rotate velocity coords */ heliox[ind] = X; helioy[ind] = Y; helioz[ind] = G; /* Helio ecliptic rectangtular */ modulus = DEGREES; X = AU*(cos(EA)-E); /* Perifocal coordinates for */ Y = AU*sin(EA)*pow(1.0-E*E,0.5); /* rectangular position coordinates */ G = RecToSph2(AP, AN, IN); /* Rotate for rectangular */ XS = X; YS = Y; ZS = G; /* position coordinates */ if (ind >= _JUP && ind <= _PLU) ErrorCorrect(ind, &XS, &YS, &ZS); ret[ind] = /* Helio daily motion */ (XS*helioy[ind]-YS*heliox[ind])/(XS*XS+YS*YS); spacex[ind] = XS; spacey[ind] = YS; spacez[ind] = ZS; ProcessPlanet(ind, 0.0); ind += (ind == 1 ? 2 : (ind != PLANETS+1 ? 1 : 10)); } spacex[0] = spacey[0] = spacez[0] = 0.0; if (!centerplanet) { if (exdisplay & DASHv0) for (i = 0; i <= BASE; i++) /* Use relative velocity */ ret[i] = DTOR(1.0); /* if -v0 is in effect */ return; } #endif /* MATRIX */ /* A second loop is needed for geocentric charts or central bodies other */ /* than the Sun. For example, we can't find the position of Mercury in */ /* relation to Pluto until we know the position of Pluto in relation to */ /* the Sun, and since Mercury is calculated first, another pass needed. */ ind = centerplanet; for (i = 0; i <= BASE; i++) { helio[i] = planet[i]; helioalt[i] = planetalt[i]; helioret[i] = ret[i]; if (i != _MOO && i != ind) { spacex[i] -= spacex[ind]; spacey[i] -= spacey[ind]; spacez[i] -= spacez[ind]; } } spacex[ind] = spacey[ind] = spacez[ind] = 0.0; SwapReal(&spacex[0], &spacex[ind]); SwapReal(&spacey[0], &spacey[ind]); /* Do some swapping - we want */ SwapReal(&spacez[0], &spacez[ind]); /* the central body to be in */ SwapReal(&spacex[1], &spacex[ind]); /* object position number zero. */ SwapReal(&spacey[1], &spacey[ind]); SwapReal(&spacez[1], &spacez[ind]); for (i = 1; i <= (operation & DASHu ? BASE : PLANETS+1); i += (i == 1 ? 2 : (i != PLANETS+1 ? 1 : 10))) { XS = spacex[i]; YS = spacey[i]; ZS = spacez[i]; if (ind != _SUN || i != _SUN) ret[i] = (XS*(helioy[i]-helioy[ind])-YS*(heliox[i]-heliox[ind]))/ (XS*XS+YS*YS); if (ind == _SUN) aber = 0.0057756*sqrt(XS*XS+YS*YS+ZS*ZS)*RTOD(ret[i]); /* Aberration */ ProcessPlanet(i, aber); if (exdisplay & DASHv0) /* Use relative velocity */ ret[i] = DTOR(ret[i]/helioret[i]); /* if -v0 is in effect */ } } #ifdef MATRIX /* ****************************************************************************** ** Lunar Position Calculations ****************************************************************************** */ /* Calculate the position and declination of the Moon, and the Moon's North */ /* Node. This has to be done separately from the other planets, because they */ /* all orbit the Sun, while the Moon orbits the Earth. */ void ComputeLunar(moonlo, moonla, nodelo, nodela) real *moonlo, *moonla, *nodelo, *nodela; { real LL, G, N, G1, D, L, ML, L1, MB, T1, M = 3600.0; LL = 973563.0+1732564379.0*T-4.0*T*T; /* Compute mean lunar longitude */ G = 1012395.0+6189.0*T; /* Sun's mean longitude of perigee */ N = 933060.0-6962911.0*T+7.5*T*T; /* Compute mean lunar node */ G1 = 1203586.0+14648523.0*T-37.0*T*T; /* Mean longitude of lunar perigee */ D = 1262655.0+1602961611.0*T-5.0*T*T; /* Mean elongation of Moon from Sun */ L = (LL-G1)/M; L1 = ((LL-D)-G)/M; /* Some auxiliary angles */ T1 = (LL-N)/M; D = D/M; Y = 2.0*D; /* Compute Moon's perturbations. */ ML = 22639.6*SIND(L)-4586.4*SIND(L-Y)+2369.9*SIND(Y)+769.0*SIND(2.0*L)- 669.0*SIND(L1)-411.6*SIND(2.0*T1)-212.0*SIND(2.0*L-Y)-206.0*SIND(L+L1-Y); ML += 192.0*SIND(L+Y)-165.0*SIND(L1-Y)+148.0*SIND(L-L1)-125.0*SIND(D)-110.0* SIND(L+L1)-55.0*SIND(2.0*T1-Y)-45.0*SIND(L+2.0*T1)+40.0*SIND(L-2.0*T1); *moonlo = G = Mod((LL+ML)/M+SD); /* Lunar longitude */ /* Compute lunar latitude. */ MB = 18461.5*SIND(T1)+1010.0*SIND(L+T1)-999.0*SIND(T1-L)-624.0*SIND(T1-Y)+ 199.0*SIND(T1+Y-L)-167.0*SIND(L+T1-Y); MB += 117.0*SIND(T1+Y)+62.0*SIND(2.0*L+T1)- 33.0*SIND(T1-Y-L)-32.0*SIND(T1-2.0*L)-30.0*SIND(L1+T1-Y); *moonla = MB = Sgn(MB)*((dabs(MB)/M)/DEGREES-floor((dabs(MB)/M)/DEGREES))*DEGREES; /* Compute position of the north node. One can compute the true North */ /* Node here if they like, but the Mean Node seems to be the one used */ /* in astrology, so that's the one Astrolog returns by default. */ #ifdef TRUENODE N = N+5392.0*SIND(2.0*T1-Y)-541.0*SIND(L1)-442.0*SIND(Y)+423.0*SIND(2.0*T1)- 291.0*SIND(2.0*L-2.0*T1); #endif *nodelo = Mod(N/M+SD); *nodela = 0.0; } #endif /* MATRIX */ /* ****************************************************************************** ** Star Position Calculations ****************************************************************************** */ /* This is used by the chart calculation routine to calculate the positions */ /* of the fixed stars. Since the stars don't move in the sky over time, */ /* getting their positions is mostly just reading info from an array and */ /* converting it to the correct reference frame. However, we have to add */ /* in the correct precession for the tropical zodiac, and sort the final */ /* index list based on what order the stars are supposed to be printed in. */ void ComputeStars(SD) real SD; { int i, j; real x, y, z; /* Read in star positions. */ for (i = 1; i <= STARS; i++) { x = stardata[i*6-6]; y = stardata[i*6-5]; z = stardata[i*6-4]; planet[BASE+i] = DTOR(x*DEGREES/24.0+y*15.0/60.0+z*0.25/60.0); x = stardata[i*6-3]; y = stardata[i*6-2]; z = stardata[i*6-1]; planetalt[BASE+i] = DTOR(x+y/60.0+z/60.0/60.0); EquToEcl(&planet[BASE+i], &planetalt[BASE+i]); /* Convert to */ planet[BASE+i] = Mod(RTOD(planet[BASE+i])+SD2000+SD); /* ecliptic. */ planetalt[BASE+i] = RTOD(planetalt[BASE+i]); starname[i] = i; } /* Sort the index list if -Uz, -Ul, -Un, or -Ub switch in effect. */ if (universe > 1) for (i = 2; i <= STARS; i++) { j = i-1; /* Compare star names for -Un switch. */ if (universe == 'n') while (j > 0 && StringCmp( objectname[BASE+starname[j]], objectname[BASE+starname[j+1]]) > 0) { SWAP(starname[j], starname[j+1]); j--; /* Compare star brightnesses for -Ub switch. */ } else if (universe == 'b') while (j > 0 && starbright[starname[j]] > starbright[starname[j+1]]) { SWAP(starname[j], starname[j+1]); j--; /* Compare star zodiac locations for -Uz switch. */ } else if (universe == 'z') while (j > 0 && planet[BASE+starname[j]] > planet[BASE+starname[j+1]]) { SWAP(starname[j], starname[j+1]); j--; /* Compare star declinations for -Ul switch. */ } else if (universe == 'l') while (j > 0 && planetalt[BASE+starname[j]] < planetalt[BASE+starname[j+1]]) { SWAP(starname[j], starname[j+1]); j--; } } } /* ****************************************************************************** ** Chart Calculation. ****************************************************************************** */ #ifdef PLACALC /* Compute the positions of the planets at a certain time using the Placalc */ /* accurate formulas and ephemeris. This will superseed the Matrix routine */ /* values and is only called with the -b switch is in effect. Not all */ /* objects or modes are available using this, but some additional values */ /* such as Moon and Node velocities not available without -b are. (This is */ /* the one place in Astrolog which calls the Placalc package functions.) */ void ComputePlacalc(t) real t; { int i; real r1, r2, r3, r4, r; /* We can compute the positions of Sun through Pluto, Chiron, and the */ /* North Node using Placalc. The other object must be done elsewhere. */ for (i = _SUN; i <= _NOD; i++) if (i <= _CHI || i >= _NOD) { if (PlacalcPlanet(i, t*36525.0+2415020.0, centerplanet != _SUN, &r1, &r2, &r3, &r4)) { /* Note that this can't compute charts with central planets other */ /* than the Sun or Earth or relative velocities in current state. */ planet[i] = Mod(r1 + SD); planetalt[i] = r2; ret[i] = DTOR(r3); /* Compute x,y,z coordinates from azimuth, altitude, and distance. */ spacez[i] = r4*SIND(planetalt[i]); r = r4*COSD(planetalt[i]); spacex[i] = r*COSD(planet[i]); spacey[i] = r*SIND(planet[i]); } } } #endif /* This is probably the main routine in all of Astrolog. It generates a */ /* chart, calculating the positions of all the celestial bodies and house */ /* cusps, based on the current chart information, and saves them for use */ /* by any of the display routines. */ real CastChart(var) int var; { int i, k; real housetemp[SIGNS+1], Off = 0.0, j; if (MM == -1) { /* Hack: If month is negative, then we know chart was read in through a */ /* -o0 position file, so the planet positions are already in the arrays. */ MC = planet[_MC]; Asc = planet[_ASC]; Vtx = planet[_VTX]; } else { Off = ProcessInput(var); ComputeVariables(); if (operation & DASHG) /* Check for -G geodetic chart. */ RA = DTOR(Mod(-OO)); MC = CuspMidheaven(); /* Calculate our Ascendant & Midheaven. */ Asc = CuspAscendant(); ComputeHouses(housesystem); /* Go calculate house cusps. */ for (i = 1; i <= total; i++) { planetalt[i] = 0.0; /* Assume on ecliptic unless we say so. */ ret[i] = 1.0; /* Assume direct until we say otherwise. */ } /* Go calculate planet, Moon, and North Node positions. */ ComputePlanets(); ComputeLunar(&planet[_MOO], &planetalt[_MOO], &planet[_NOD], &planetalt[_NOD]); ret[_NOD] = -1.0; /* Compute more accurate ephemeris positions for certain objects. */ #ifdef PLACALC if (placalc) ComputePlacalc(T); #endif /* Calculate position of Part of Fortune. */ j = planet[_MOO]-planet[_SUN]; j = dabs(j) < DEGQUAD ? j : j - Sgn(j)*DEGREES; planet[_FOR] = Mod(j+Asc); /* Fill in "planet" positions corresponding to house cusps. */ planet[_MC] = MC; planet[_ASC] = Asc; planet[_VTX] = Vtx; planet[C_LO] = house[11]; planet[C_LO+1] = house[12]; planet[C_LO+2] = house[2]; planet[C_LO+3] = house[3]; } /* Go calculate star positions if -U switch in effect. */ if (universe) ComputeStars(operation & DASHs ? 0.0 : -Off); /* Now, we may have to modify the base positions we calculated above based */ /* on what type of chart we are generating. */ if (operation & DASHp0) { /* Are we doing a -p0 solar arc chart? */ for (i = 1; i <= total; i++) planet[i] = Mod(planet[i] + (Jdp - JD) / progday); for (i = 1; i <= SIGNS; i++) house[i] = Mod(house[i] + (Jdp - JD) / progday); } if (multiplyfactor > 1) /* Are we doing a -x harmonic chart? */ for (i = 1; i <= total; i++) planet[i] = Mod(planet[i] * (real)multiplyfactor); if (onasc) { if (onasc > 0) /* Is -1 put on Ascendant in effect? */ j = planet[onasc]-Asc; else /* Or -2 put object on Midheaven switch? */ j = planet[-onasc]-MC; for (i = 1; i <= SIGNS; i++) /* If so, rotate the houses accordingly. */ house[i] = Mod(house[i]+j); } /* Check to see if we are -F forcing any objects to be particular values. */ for (i = 1; i <= total; i++) if (force[i] != 0.0) { planet[i] = force[i]-DEGREES; planetalt[i] = ret[i] = 0.0; } HousePlace(); /* Figure out what house everything falls in. */ /* If -f domal chart switch in effect, switch planet and house positions. */ if (operation & DASHf) { for (i = 1; i <= total; i++) { k = inhouse[i]; inhouse[i] = ZTOS(planet[i]); planet[i] = STOZ(k)+MinDistance(house[k], planet[i]) / MinDistance(house[k], house[Mod12(k+1)])*30.0; } for (i = 1; i <= SIGNS; i++) { k = HousePlaceIn(STOZ(i)); housetemp[i] = STOZ(k)+MinDistance(house[k], STOZ(i)) / MinDistance(house[k], house[Mod12(k+1)])*30.0; } for (i = 1; i <= SIGNS; i++) house[i] = housetemp[i]; } /* If -3 decan chart switch in effect, edit planet positions accordingly. */ if (operation & DASH3) for (i = 1; i <= total; i++) { k = ZTOS(planet[i]); j = planet[i] - STOZ(k); k = Mod12(k + 4*((int)floor(j/10.0))); j = (j - floor(j/10.0)*10.0)*3.0; planet[i] = STOZ(k)+j; HousePlace(); } return T; } /* formulas.c */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.