/* ** Astrolog (Version 4.40) File: matrix.c ** ** IMPORTANT NOTICE: The graphics database and chart display routines ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen ** (astara@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 1/29/1995. */ #include "astrolog.h" #ifdef MATRIX real MC, Asc, RA, OB; /* ****************************************************************************** ** Assorted Calculations. ****************************************************************************** */ /* 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 fGreg = fTrue; if (yea < yeaJ2G || (yea == yeaJ2G && (mon < monJ2G || (mon == monJ2G && day < 15)))) fGreg = fFalse; return (long)RFloor(julday(mon, day, yea, 12.0, fGreg)+rRound); #endif } /* Like above but return a fractional Julian time given the extra info. */ real MdytszToJulian(mon, day, yea, tim, dst, zon) int mon, day, yea; real tim, dst, zon; { return (real)MdyToJulian(mon, day, yea) + (DecToDeg(tim) + DecToDeg(zon) - DecToDeg(dst)) / 24.0; } /* 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)RFloor(JD+rRound)+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 double tim; revjul(JD, JD >= 2299171.0 /* October 15, 1582 */, 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(fDate) bool fDate; { real Off, Ln; TT = RSgn(TT)*RFloor(RAbs(TT))+RFract(RAbs(TT))*100.0/60.0 + (DecToDeg(ZZ) - DecToDeg(SS)); 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 = RFromD(DecToDeg(AA)); /* if parameter 'fDate' isn't set, then we can assume that the true time */ /* has already been determined (as in a -rm switch time midpoint chart). */ if (fDate) { is.JD = (real)MdyToJulian(MM, DD, YY); if (!us.fProgress || us.fSolarArc) T = (is.JD + TT/24.0 - 2415020.5) / 36525.0; else { /* Determine actual time that a progressed chart is to be cast for. */ T = ((is.JD + TT/24.0 + (is.JDp - (is.JD + TT/24.0)) / us.rProgDay) - 2415020.5) / 36525.0; } } /* Compute angle that the ecliptic is inclined to the Celestial Equator */ OB = RFromD(23.452294-0.0130125*T); Ln = Mod((933060L-6962911L*T+7.5*T*T)/3600.0); /* Mean lunar node */ Off = (259205536.0*T+2013816.0)/3600.0; /* Mean Sun */ Off = 17.23*RSin(RFromD(Ln))+1.27*RSin(RFromD(Off))-(5025.64+1.11*T)*T; Off = (Off-84038.27)/3600.0; is.rSid = (us.fSiderial ? Off : 0.0) + us.rZodiacOffset; return Off; } /* Convert polar to rectangular coordinates. */ void PolToRec(A, R, X, Y) real A, R, *X, *Y; { if (A == 0.0) A = rSmall; *X = R*RCos(A); *Y = R*RSin(A); } /* Convert rectangular to polar coordinates. */ void RecToPol(X, Y, A, R) real X, Y, *A, *R; { if (Y == 0.0) Y = rSmall; *R = RSqr(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, X, Y, A; 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 = RAsin(Y); Y = X; X = G; RecToPol(X, Y, &A, &R); if (A < 0.0) A += 2*rPi; G = A; return G; /* We only ever care about and return one of the coordinates. */ } /* 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 = RSin(*alt); cosalt = RCos(*alt); sinazi = RSin(*azi); sintilt = RSin(tilt); costilt = RCos(tilt); x = cosalt * sinazi * costilt; y = sinalt * sintilt; x -= y; a1 = cosalt; y = cosalt * RCos(*azi); l1 = Angle(y, x); a1 = a1 * sinazi * sintilt + sinalt * costilt; a1 = RAsin(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(vtx) real *vtx; { real R, R2, B, L, O, G, X, Y, A; RA = RFromD(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 *= RCos(O); RecToPol(X, Y, &A, &R); MC = Mod(is.rSid + DFromR(A)); /* Midheaven */ #if FALSE L = R2; G = RecToSph(B, L, O); Asc = Mod(is.rSid + Mod(G+rPiHalf)); /* Ascendant */ #endif L= R2+rPi; B = rPiHalf-RAbs(B); if (AA < 0.0) B = -B; G = RecToSph(B, L, O); *vtx = Mod(is.rSid + DFromR(G+rPiHalf)); /* Vertex */ } /* ****************************************************************************** ** House Cusp Calculations. ****************************************************************************** */ /* The following three functions calculate the Midheaven, Ascendant, and */ /* East Point of the chart in question, based on time and location. The */ /* first two are also used in some of the house cusp calculation routines */ /* as a quick way to get the 10th and 1st cusps. The East Point object is */ /* technically defined as the Ascendant's position at zero latitude. */ real CuspMidheaven() { real MC; MC = RAtn(RTan(RA)/RCos(OB)); if (MC < 0.0) MC += rPi; if (RA > rPi) MC += rPi; return Mod(DFromR(MC)+is.rSid); } real CuspAscendant() { real Asc; Asc = Angle(-RSin(RA)*RCos(OB)-RTan(AA)*RSin(OB), RCos(RA)); return Mod(DFromR(Asc)+is.rSid); } real CuspEastPoint() { real EP; EP = Angle(-RSin(RA)*RCos(OB), RCos(RA)); return Mod(DFromR(EP)+is.rSid); } /* These are various different algorithms for calculating the house cusps: */ real CuspPlacidus(deg, FF, fNeg) real deg, FF; bool fNeg; { real LO, R1, XS, X; int i; R1 = RA+RFromD(deg); X = fNeg ? 1.0 : -1.0; /* Looping 10 times is arbitrary, but it's what other programs do. */ for (i = 1; i <= 10; i++) { /* This formula works except at 0 latitude (AA == 0.0). */ XS = X*RSin(R1)*RTan(OB)*RTan(AA == 0.0 ? 0.0001 : AA); XS = RAcos(XS); if (XS < 0.0) XS += rPi; R1 = RA + (fNeg ? rPi-(XS/FF) : (XS/FF)); } LO = RAtn(RTan(R1)/RCos(OB)); if (LO < 0.0) LO += rPi; if (RSin(R1) < 0.0) LO += rPi; return DFromR(LO); } void HousePlacidus() { int i; house[1] = Mod(Asc-is.rSid); house[4] = Mod(MC+rDegHalf-is.rSid); house[5] = CuspPlacidus(30.0, 3.0, fFalse) + rDegHalf; house[6] = CuspPlacidus(60.0, 1.5, fFalse) + rDegHalf; house[2] = CuspPlacidus(120.0, 1.5, fTrue); house[3] = CuspPlacidus(150.0, 3.0, fTrue); for (i = 1; i <= cSign; i++) { if (i <= 6) house[i] = Mod(house[i]+is.rSid); else house[i] = Mod(house[i-6]+rDegHalf); } } void HouseKoch() { real A1, A2, A3, KN, D, X; int i; A1 = RSin(RA)*RTan(AA)*RTan(OB); A1 = RAsin(A1); for (i = 1; i <= cSign; i++) { D = Mod(60.0+30.0*(real)i); A2 = D/rDegQuad-1.0; KN = 1.0; if (D >= rDegHalf) { KN = -1.0; A2 = D/rDegQuad-3.0; } A3 = RFromD(Mod(DFromR(RA)+D+A2*DFromR(A1))); X = Angle(RCos(A3)*RCos(OB)-KN*RTan(AA)*RSin(OB), RSin(A3)); house[i] = Mod(DFromR(X)+is.rSid); } } void HouseEqual() { int i; for (i = 1; i <= cSign; i++) house[i] = Mod(Asc-30.0+30.0*(real)i); } void HouseCampanus() { real KO, DN, X; int i; for (i = 1; i <= cSign; i++) { KO = RFromD(60.000001+30.0*(real)i); DN = RAtn(RTan(KO)*RCos(AA)); if (DN < 0.0) DN += rPi; if (RSin(KO) < 0.0) DN += rPi; X = Angle(RCos(RA+DN)*RCos(OB)-RSin(DN)*RTan(AA)*RSin(OB), RSin(RA+DN)); house[i] = Mod(DFromR(X)+is.rSid); } } void HouseMeridian() { real D, X; int i; for (i = 1; i <= cSign; i++) { D = RFromD(60.0+30.0*(real)i); X = Angle(RCos(RA+D)*RCos(OB), RSin(RA+D)); house[i] = Mod(DFromR(X)+is.rSid); } } void HouseRegiomontanus() { real D, X; int i; for (i = 1; i <= cSign; i++) { D = RFromD(60.0+30.0*(real)i); X = Angle(RCos(RA+D)*RCos(OB)-RSin(D)*RTan(AA)*RSin(OB), RSin(RA+D)); house[i] = Mod(DFromR(X)+is.rSid); } } void HousePorphyry() { real X, Y; int i; X = Asc-MC; if (X < 0.0) X += rDegMax; Y = X/3.0; for (i = 1; i <= 2; i++) house[i+4] = Mod(rDegHalf+MC+i*Y); X = Mod(rDegHalf+MC)-Asc; if (X < 0.0) X += rDegMax; 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]+rDegHalf); } void HouseMorinus() { real D, X; int i; for (i = 1; i <= cSign; i++) { D = RFromD(60.0+30.0*(real)i); X = Angle(RCos(RA+D), RSin(RA+D)*RCos(OB)); house[i] = Mod(DFromR(X)+is.rSid); } } real CuspTopocentric(deg) real deg; { real OA, X, LO; OA = ModRad(RA+RFromD(deg)); X = RAtn(RTan(AA)/RCos(OA)); LO = RAtn(RCos(X)*RTan(OA)/RCos(X+OB)); if (LO < 0.0) LO += rPi; if (RSin(OA) < 0.0) LO += rPi; return LO; } void HouseTopocentric() { real TL, P1, P2, LT; int i; house[4] = ModRad(RFromD(MC+rDegHalf-is.rSid)); TL = RTan(AA); P1 = RAtn(TL/3.0); P2 = RAtn(TL/1.5); LT = AA; AA = P1; house[5] = CuspTopocentric(30.0) + rPi; AA = P2; house[6] = CuspTopocentric(60.0) + rPi; AA = LT; house[1] = CuspTopocentric(90.0); AA = P2; house[2] = CuspTopocentric(120.0); AA = P1; house[3] = CuspTopocentric(150.0); AA = LT; for (i = 1; i <= 6; i++) { house[i] = Mod(DFromR(house[i])+is.rSid); house[i+6] = Mod(house[i]+rDegHalf); } } /* ****************************************************************************** ** Planetary Position Calculations. ****************************************************************************** */ /* Given three values, return them combined as the coefficients of a */ /* quadratic equation as a function of the chart time. */ real ReadThree(r0, r1, r2) real r0, r1, r2; { return RFromD(r0 + r1*T + r2*T*T); } /* Another coordinate transformation. This is used by the ComputePlanets() */ /* procedure to rotate rectangular coordinates by a certain amount. */ void RecToSph2(AP, AN, IN, X, Y, G) real AP, AN, IN, *X, *Y, *G; { real R, D, A; 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*rPi; PolToRec(A, R, X, Y); } /* 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, A, S0, T0[4], FAR *pr; int IK, IJ, irError; irError = errorcount[ind-oJup]; pr = (lpreal)&errordata[erroroffset[ind-oJup]]; for (IK = 1; IK <= 3; IK++) { if (ind == oJup && IK == 3) { T0[3] = 0.0; break; } if (IK == 3) irError--; S0 = ReadThree(pr[0], pr[1], pr[2]); pr += 3; A = 0.0; for (IJ = 1; IJ <= irError; IJ++) { U = *pr++; V = *pr++; W = *pr++; A += RFromD(U)*RCos((V*T+W)*rPi/rDegHalf); } T0[IK] = DFromR(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(DFromR(ang) /*+ NU*/ - aber + is.rSid); RecToPol(rad, spacez[ind], &ang, &rad); if (us.objCenter == oSun && ind == oSun) ang = 0.0; ang = DFromR(ang); while (ang > rDegQuad) /* Ensure declination is from -90..+90 degrees. */ ang -= rDegHalf; while (ang < -rDegQuad) ang += rDegHalf; planetalt[ind] = 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[oNorm+1], helioalt[oNorm+1], helioret[oNorm+1], heliox[oNorm+1], helioy[oNorm+1], helioz[oNorm+1]; real aber = 0.0, AU, E, EA, E1, M, XW, YW, AP, AN, IN, X, Y, G, XS, YS, ZS; int ind = oSun, i; OE *poe; while (ind <= (us.fUranian ? oNorm : cPlanet)) { if (ignore[ind] && ind > oSun) goto LNextPlanet; poe = &rgoe[IoeFromObj(ind)]; EA = M = ModRad(ReadThree(poe->ma0, poe->ma1, poe->ma2)); E = DFromR(ReadThree(poe->ec0, poe->ec1, poe->ec2)); for (i = 1; i <= 5; i++) EA = M+E*RSin(EA); /* Solve Kepler's equation */ AU = poe->sma; /* Semi-major axis */ E1 = 0.01720209/(pow(AU, 1.5)* (1.0-E*RCos(EA))); /* Begin velocity coordinates */ XW = -AU*E1*RSin(EA); /* Perifocal coordinates */ YW = AU*E1*pow(1.0-E*E,0.5)*RCos(EA); AP = ReadThree(poe->ap0, poe->ap1, poe->ap2); AN = ReadThree(poe->an0, poe->an1, poe->an2); IN = ReadThree(poe->in0, poe->in1, poe->in2); /* Calculate inclination */ X = XW; Y = YW; RecToSph2(AP, AN, IN, &X, &Y, &G); /* Rotate velocity coords */ heliox[ind] = X; helioy[ind] = Y; helioz[ind] = G; /* Helio ecliptic rectangtular */ X = AU*(RCos(EA)-E); /* Perifocal coordinates for */ Y = AU*RSin(EA)*pow(1.0-E*E,0.5); /* rectangular position coordinates */ RecToSph2(AP, AN, IN, &X, &Y, &G); /* Rotate for rectangular */ XS = X; YS = Y; ZS = G; /* position coordinates */ if (FBetween(ind, oJup, oPlu)) 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); LNextPlanet: ind += (ind == oSun ? 2 : (ind != cPlanet ? 1 : uranLo-cPlanet)); } spacex[0] = spacey[0] = spacez[0] = 0.0; if (!us.objCenter) { if (us.fVelocity) for (i = 0; i <= oNorm; i++) /* Use relative velocity */ ret[i] = RFromD(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 = us.objCenter; for (i = 0; i <= oNorm; i++) { helio[i] = planet[i]; helioalt[i] = planetalt[i]; helioret[i] = ret[i]; if (i != oMoo && i != ind) { spacex[i] -= spacex[ind]; spacey[i] -= spacey[ind]; spacez[i] -= spacez[ind]; } } spacex[ind] = spacey[ind] = spacez[ind] = 0.0; SwapR(&spacex[0], &spacex[ind]); SwapR(&spacey[0], &spacey[ind]); /* Do some swapping - we want */ SwapR(&spacez[0], &spacez[ind]); /* the central body to be in */ SwapR(&spacex[1], &spacex[ind]); /* object position number zero. */ SwapR(&spacey[1], &spacey[ind]); SwapR(&spacez[1], &spacez[ind]); for (i = 1; i <= (us.fUranian ? oNorm : cPlanet); i += (i == 1 ? 2 : (i != cPlanet ? 1 : uranLo-cPlanet))) { if (ignore[i] && i > oSun) continue; XS = spacex[i]; YS = spacey[i]; ZS = spacez[i]; if (ind != oSun || i != oSun) ret[i] = (XS*(helioy[i]-helioy[ind])-YS*(heliox[i]-heliox[ind]))/ (XS*XS+YS*YS); if (ind == oSun) aber = 0.0057756*RSqr(XS*XS+YS*YS+ZS*ZS)*DFromR(ret[i]); /* Aberration */ ProcessPlanet(i, aber); if (us.fVelocity) /* Use relative velocity */ ret[i] = RFromD(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, Y, 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*RSinD(L) - 4586.4*RSinD(L-Y) + 2369.9*RSinD(Y) + 769.0*RSinD(2.0*L) - 669.0*RSinD(L1) - 411.6*RSinD(2.0*T1) - 212.0*RSinD(2.0*L-Y) - 206.0*RSinD(L+L1-Y); ML += 192.0*RSinD(L+Y) - 165.0*RSinD(L1-Y) + 148.0*RSinD(L-L1) - 125.0*RSinD(D) - 110.0*RSinD(L+L1) - 55.0*RSinD(2.0*T1-Y) - 45.0*RSinD(L+2.0*T1) + 40.0*RSinD(L-2.0*T1); *moonlo = G = Mod((LL+ML)/M+is.rSid); /* Lunar longitude */ /* Compute lunar latitude. */ MB = 18461.5*RSinD(T1) + 1010.0*RSinD(L+T1) - 999.0*RSinD(T1-L) - 624.0*RSinD(T1-Y) + 199.0*RSinD(T1+Y-L) - 167.0*RSinD(L+T1-Y); MB += 117.0*RSinD(T1+Y) + 62.0*RSinD(2.0*L+T1) - 33.0*RSinD(T1-Y-L) - 32.0*RSinD(T1-2.0*L) - 30.0*RSinD(L1+T1-Y); *moonla = MB = RSgn(MB)*((RAbs(MB)/M)/rDegMax-RFloor((RAbs(MB)/M)/rDegMax))*rDegMax; /* Compute position of the North Lunar Node, either True or Mean. */ if (us.fTrueNode) N = N+5392.0*RSinD(2.0*T1-Y)-541.0*RSinD(L1)-442.0*RSinD(Y)+ 423.0*RSinD(2.0*T1)-291.0*RSinD(2.0*L-2.0*T1); *nodelo = Mod(N/M+is.rSid); *nodela = 0.0; } #endif /* MATRIX */ /* matrix.c */