/* ** Astrolog (Version 4.40) File: charts2.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" /* ****************************************************************************** ** Dual Chart Display Routines. ****************************************************************************** */ /* Print out an aspect (or midpoint if -g0 switch in effect) grid of a */ /* relationship chart. This is similar to the ChartGrid() routine; however, */ /* here we have both axes labeled with the planets for the two charts in */ /* question, instead of just a diagonal down the center for only one chart. */ void ChartGridRelation() { char sz[cchSzDef]; int i, j, k, tot = cObj, temp; #ifdef INTERPRET if (us.fInterpret && !us.fGridConfig) { InterpretGridRelation(); return; } #endif PrintSz(" 2>"); for (temp = 0, i = 1; i <= cObj; i++) if (!ignore[i]) { PrintCh(chV); AnsiColor(kObjA[i]); sprintf(sz, "%c%c%c", chObj3(i)); PrintSz(sz); AnsiColor(kDefault); temp++; } PrintSz("\n1 "); for (i = 1; i <= tot; i++) if (!ignore[i]) { PrintCh(chV); AnsiColor(kSignA(SFromZ(cp2.obj[i]))); sprintf(sz, "%2d%c", (int)cp2.obj[i] % 30, chDeg0); PrintSz(sz); AnsiColor(kDefault); } PrintSz("\nV "); for (i = 1; i <= tot; i++) if (!ignore[i]) { PrintCh(chV); temp = SFromZ(cp2.obj[i]); AnsiColor(kSignA(temp)); sprintf(sz, "%c%c%c", chSig3(temp)); PrintSz(sz); AnsiColor(kDefault); } PrintL(); for (j = 1; j <= cObj; j++) if (!ignore[j]) for (k = 1; k <= 4; k++) { if (k < 2) PrintTab(chH, 3); else if (k == 2) { AnsiColor(kObjA[j]); sprintf(sz, "%c%c%c", chObj3(j)); PrintSz(sz); } else { temp = SFromZ(cp1.obj[j]); AnsiColor(kSignA(temp)); if (k == 3) sprintf(sz, "%2d%c", (int)cp1.obj[j] - (temp-1)*30, chDeg0); else sprintf(sz, "%c%c%c", chSig3(temp)); PrintSz(sz); } if (k > 1) AnsiColor(kDefault); for (i = 1; i <= tot; i++) if (!ignore[i]) { PrintCh((char)(k < 2 ? chC : chV)); temp = grid->n[i][j]; if (k > 1) { if (i == j) AnsiColor(kReverse); AnsiColor(us.fGridConfig ? kSignA(temp) : kAspA[temp]); } if (k < 2) PrintTab(chH, 3); else if (k == 2) { if (us.fGridConfig) sprintf(sz, "%c%c%c", chSig3(temp)); else sprintf(sz, "%s", temp ? szAspectAbbrev[temp] : " "); PrintSz(sz); } else if (k == 3) { if (us.fGridConfig) { sprintf(sz, "%2d%c", grid->v[i][j]/60, chDeg0); PrintSz(sz); } else if (grid->n[i][j]) { if (grid->v[i][j] < 6000) sprintf(sz, "%c%2d", us.fAppSep ? (grid->v[i][j] < 0 ? 'a' : 's') : (grid->v[i][j] < 0 ? '-' : '+'), abs(grid->v[i][j])/60); else sprintf(sz, "%3d", abs(temp)/60); PrintSz(sz); } else PrintSz(" "); } else { if (grid->n[i][j]) { sprintf(sz, "%02d'", abs(grid->v[i][j])%60); PrintSz(sz); } else PrintSz(" "); } AnsiColor(kDefault); } PrintL(); } } /* Display all aspects between objects in the relationship comparison chart, */ /* one per line, in sorted order based on the total "power" of the aspects, */ /* as specified with the -r0 -a switch combination. */ void ChartAspectRelation() { char sz[cchSzDef]; int pcut = 30000, icut, jcut, phi, ihi, jhi, ahi, p, i, j, k, count = 0; real ip, jp; loop { phi = -1; /* Search for the next most powerful aspect in the aspect grid. */ for (i = 1; i <= cObj; i++) if (!ignore[i]) for (j = 1; j <= cObj; j++) if (!ignore[j]) if (k = grid->n[i][j]) { ip = i <= oNorm ? objectinf[i] : 2.5; jp = j <= oNorm ? objectinf[j] : 2.5; p = (int)(aspectinf[k]*(ip+jp)/2.0* (1.0-RAbs((real)(grid->v[i][j]))/60.0/aspectorb[k])*1000.0); if ((p < pcut || (p == pcut && (i > icut || (i == icut && j > jcut)))) && p > phi) { ihi = i; jhi = j; phi = p; ahi = k; } } if (phi < 0) /* Exit when no less powerful aspect found. */ break; pcut = phi; icut = ihi; jcut = jhi; count++; /* Display the current aspect. */ #ifdef INTERPRET if (us.fInterpret) { /* Interpret it if -I in effect. */ InterpretAspectRelation(jhi, ihi); continue; } #endif sprintf(sz, "%3d: ", count); PrintSz(sz); PrintAspect(jhi, SFromZ(cp1.obj[jhi]), (int)RSgn(cp1.dir[jhi]), ahi, ihi, SFromZ(cp2.obj[ihi]), (int)RSgn(cp2.dir[ihi]), 'A'); k = grid->v[ihi][jhi]; AnsiColor(k < 0 ? kWhite : kLtGray); sprintf(sz, "- orb: %c%d,%02d'", us.fAppSep ? (k < 0 ? 'a' : 's') : (k < 0 ? '-' : '+'), abs(k)/60, abs(k)%60); PrintSz(sz); AnsiColor(kDkGreen); sprintf(sz, " - power:%6.2f\n", (real)phi/1000.0); PrintSz(sz); AnsiColor(kDefault); } } /* Display locations of all midpoints between objects in the relationship */ /* comparison chart, one per line, in sorted zodiac order from zero Aries */ /* onward, as specified with the -r0 -m switch combination. */ void ChartMidpointRelation() { char sz[cchSzDef]; int mcut = -1, icut, jcut, mlo, ilo, jlo, m, i, j, count = 0; loop { mlo = 21600; /* Search for the next closest midpoint farther down in the zodiac. */ for (i = 1; i <= cObj; i++) if (!ignore[i]) for (j = 1; j <= cObj; j++) if (!ignore[j]) { m = (grid->n[j][i]-1)*30*60 + grid->v[j][i]; if ((m > mcut || (m == mcut && (i > icut || (i == icut && j > jcut)))) && m < mlo) { ilo = i; jlo = j; mlo = m; } } if (mlo >= 21600) /* Exit when no midpoint farther in zodiac found. */ break; mcut = mlo; icut = ilo; jcut = jlo; count++; /* Display the current midpoint. */ #ifdef INTERPRET if (us.fInterpret) { /* Interpret it if -I in effect. */ InterpretMidpointRelation(ilo, jlo); continue; } #endif sprintf(sz, "%4d: ", count); PrintSz(sz); PrintZodiac((real)mlo/60.0); PrintCh(' '); PrintAspect(ilo, SFromZ(cp1.obj[ilo]), (int)RSgn(cp1.dir[ilo]), 0, jlo, SFromZ(cp2.obj[jlo]), (int)RSgn(cp2.dir[jlo]), 'M'); AnsiColor(kDefault); m = (int)(MinDistance(cp1.obj[ilo], cp2.obj[jlo])*60.0); sprintf(sz, "-%4d%c%02d' degree span.\n", m/60, chDeg1, m%60); PrintSz(sz); } } /* Calculate any of the various kinds of relationship charts. This involves */ /* reading in and storing the planet and house positions for both charts, */ /* and then combining them in the main single chart in the proper manner. */ /* If the parameter 'fFile' is on, then we read the info for the two charts */ /* from files, otherwise use the info in preset "core" and "second" charts. */ void CastRelation(fFile) bool fFile; { byte ignoreT[objMax]; CI ciT; int i; real ratio, t1, t2, t; /* Read in and cast the first chart. */ if (fFile) FInputData(is.szFile); ciT = ciCore; if (fFile) ciTwin = ciCore; else ciCore = ciTwin; t1 = CastChart(fTrue); for (i = 1; i <= cSign; i++) { cp1.cusp[i] = house[i]; cp1.house[i] = inhouse[i]; } for (i = 1; i <= cObj; i++) { cp1.obj[i] = planet[i]; cp1.alt[i] = planetalt[i]; cp1.dir[i] = ret[i]; } /* Read in the second chart. */ if (fFile) { FInputData(is.szFile2); if (us.nRel == rcProgress) { us.fProgress = fTrue; is.JDp = MdytszToJulian(MM, DD, YY, TT, SS, ZZ); ciCore = ciT; } } else ciCore = ciT; ciMain = ciCore; if (us.nRel == rcTransit) for (i = 1; i <= cObj; i++) { ignoreT[i] = ignore[i]; ignore[i] = ignore[i] && ignore2[i]; } t2 = CastChart(fTrue); if (us.nRel == rcTransit) for (i = 1; i <= cObj; i++) ignore[i] = ignoreT[i]; for (i = 1; i <= cSign; i++) { cp2.cusp[i] = house[i]; cp2.house[i] = inhouse[i]; } for (i = 1; i <= cObj; i++) { cp2.obj[i] = planet[i]; cp2.alt[i] = planetalt[i]; cp2.dir[i] = ret[i]; } /* Now combine the two charts based on what relation we are doing. */ /* For the standard -r synastry chart, use the house cusps of chart1 */ /* and the planets positions of chart2. */ ratio = (real)us.nRatio1 / ((real)(us.nRatio1 + us.nRatio2)); if (us.nRel <= rcSynastry) for (i = 1; i <= cSign; i++) house[i] = cp1.cusp[i]; /* For the -rc composite chart, take the midpoints of the planets/houses. */ else if (us.nRel == rcComposite) { for (i = 1; i <= cObj; i++) { planet[i] = Ratio(cp1.obj[i], cp2.obj[i], ratio); if (RAbs(cp2.obj[i] - cp1.obj[i]) > rDegHalf) planet[i] = Mod(planet[i] + rDegMax*ratio); planetalt[i] = Ratio(cp1.alt[i], cp2.alt[i], ratio); ret[i] = Ratio(cp1.dir[i], cp2.dir[i], ratio); } for (i = 1; i <= cSign; i++) { house[i] = Ratio(cp1.cusp[i], cp2.cusp[i], ratio); if (RAbs(cp2.cusp[i] - cp1.cusp[i]) > rDegHalf) house[i] = Mod(house[i] + rDegMax*ratio); } /* Make sure we don't have any 180 degree errors in house cusp */ /* complement pairs, which may happen if the cusps are far apart. */ for (i = 1; i <= cSign; i++) if (MinDistance(house[sCap], Mod(house[i]-ZFromS(i+3))) > rDegQuad) house[i] = Mod(house[i]+rDegHalf); for (i = 1; i <= cSign; i++) if (RAbs(MinDistance(house[i], planet[oAsc - 1 + i])) > rDegQuad) planet[oAsc - 1 + i] = Mod(planet[oAsc - 1 + i]+rDegHalf); /* For the -rm time space midpoint chart, calculate the midpoint time and */ /* place between the two charts and then recast for the new chart info. */ } else if (us.nRel == rcMidpoint) { T = Ratio(t1, t2, ratio); t = (T*36525.0)+rRound; is.JD = RFloor(t)+2415020.0; TT = RFract(t)*24.0; ZZ = Ratio(DecToDeg(ciT.zon), DecToDeg(Zon), ratio); SS = Ratio(DecToDeg(ciT.dst), DecToDeg(Dst), ratio); TT -= ZZ; if (TT < 0.0) { TT += 24.0; is.JD -= 1.0; } JulianToMdy(is.JD, &MM, &DD, &YY); OO = Ratio(DecToDeg(ciT.lon), DecToDeg(Lon), ratio); if (RAbs(Lon-ciT.lon) > rDegHalf) OO = Mod(OO+rDegMax*ratio); AA = Ratio(DecToDeg(ciT.lat), DecToDeg(Lat), ratio); TT = DegToDec(TT); SS = DegToDec(SS); ZZ = DegToDec(ZZ); OO = DegToDec(OO); AA = DegToDec(AA); ciMain = ciCore; CastChart(fTrue); /* There are a couple of non-astrological charts, which only require the */ /* number of days that have passed between the two charts to be done. */ } else is.JD = RAbs(t2-t1)*36525.0; ComputeInHouses(); } /* ****************************************************************************** ** Other Chart Display Routines. ****************************************************************************** */ /* Given two objects and an aspect between them, or an object and a sign */ /* that it's entering, print if this is a "major" event, such as a season */ /* change or major lunar phase. This is called from the ChartInDay() */ /* searching and influence routines. Do an interpretation if need be too. */ void PrintInDay(source, aspect, dest) int source, aspect, dest; { if (aspect == aSig) { if (source == oSun) { AnsiColor(kWhite); if (dest == 1) PrintSz(" (Vernal Equinox)"); /* If the Sun changes sign, */ else if (dest == 4) /* then print out if this */ PrintSz(" (Summer Solstice)"); /* is a season change. */ else if (dest == 7) PrintSz(" (Autumnal Equinox)"); else if (dest == 10) PrintSz(" (Winter Solstice)"); } } else if (aspect > 0) { if (source == oSun && dest == oMoo) { if (aspect <= aSqu) AnsiColor(kWhite); if (aspect == aCon) PrintSz(" (New Moon)"); /* Print out if the present */ else if (aspect == aOpp) /* aspect is a New, Full, */ PrintSz(" (Full Moon)"); /* or Half Moon. */ else if (aspect == aSqu) PrintSz(" (Half Moon)"); } } PrintL(); #ifdef INTERPRET if (us.fInterpret) InterpretInDay(source, aspect, dest); #endif AnsiColor(kDefault); } /* Given two objects and an aspect (or one object, and an event such as a */ /* sign or direction change) display the configuration in question. This */ /* is called by the many charts which list aspects among items, such as */ /* the -a aspect lists, -m midpoint lists, -d aspect in day search and */ /* influence charts, and -t transit search and influence charts. */ void PrintAspect(obj1, sign1, ret1, asp, obj2, sign2, ret2, chart) int obj1, sign1, ret1, asp, obj2, sign2, ret2; char chart; { char sz[cchSzDef]; AnsiColor(kObjA[obj1]); if (chart == 't' || chart == 'T') PrintSz("trans "); else if (chart == 'e' || chart == 'u' || chart == 'U') PrintSz("progr "); sprintf(sz, "%7.7s", szObjName[obj1]); PrintSz(sz); AnsiColor(kSignA(sign1)); sprintf(sz, " %c%c%c%c%c", ret1 > 0 ? '(' : (ret1 < 0 ? '[' : '<'), chSig3(sign1), ret1 > 0 ? ')' : (ret1 < 0 ? ']' : '>')); PrintSz(sz); AnsiColor(asp > 0 ? kAspA[asp] : kWhite); PrintCh(' '); if (asp == aSig) sprintf(sz, "-->"); /* Print a sign change. */ else if (asp == aDir) sprintf(sz, "S/%c", obj2 ? chRet : 'D'); /* Print a direction change. */ else if (asp == 0) sprintf(sz, chart == 'm' ? "&" : "with"); else sprintf(sz, "%s", szAspectAbbrev[asp]); /* Print an aspect. */ PrintSz(sz); if (asp != aDir) PrintCh(' '); if (chart == 'A') PrintSz("with "); if (asp == aSig) { AnsiColor(kSignA(obj2)); sprintf(sz, "%s", szSignName[obj2]); PrintSz(sz); } else if (asp >= 0) { AnsiColor(kSignA(sign2)); if (chart == 't' || chart == 'u' || chart == 'T' || chart == 'U') PrintSz("natal "); sprintf(sz, "%c%c%c%c%c ", ret2 > 0 ? '(' : (ret2 < 0 ? '[' : '<'), chSig3(sign2), ret2 > 0 ? ')' : (ret2 < 0 ? ']' : '>')); PrintSz(sz); AnsiColor(kObjA[obj2]); sprintf(sz, "%.10s", szObjName[obj2]); PrintSz(sz); } if (chart == 'D' || chart == 'T' || chart == 'U' || chart == 'a' || chart == 'A' || chart == 'm' || chart == 'M') PrintTab(' ', 10-CchSz(szObjName[obj2])); } /* Based on the given chart information, display all the aspects taking */ /* place in the chart, as specified with the -D switch. The aspects are */ /* printed in order of influence determined by treating them as happening */ /* outside among transiting planets, such that rare outer planet aspects */ /* are given more power than common ones among inner planets. (This is */ /* almost identical to the -a list, except the influences are different.) */ void ChartInDayInfluence() { int source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY]; real power[MAXINDAY]; char sz[cchSzDef]; int occurcount = 0, i, j, k, l, m; /* Go compute the aspects in the chart. */ i = us.fAppSep; us.fAppSep = fTrue; /* We always want applying vs. separating orbs. */ FCreateGrid(fFalse); us.fAppSep = i; /* Search through the grid and build up the list of aspects. */ for (j = 2; j <= cObj; j++) { if (ignore[j]) continue; for (i = 1; i < j; i++) { if (ignore[i] || (k = grid->n[i][j]) == 0 || occurcount >= MAXINDAY) continue; source[occurcount] = i; aspect[occurcount] = k; dest[occurcount] = j; l = grid->v[i][j]; power[occurcount] = ((i <= oNorm ? transitinf[i] : 2.0)/4.0)* ((j <= oNorm ? transitinf[j] : 2.0)/4.0)* aspectinf[k]*(1.0-(real)abs(l)/60.0/GetOrb(i, j, k)); occurcount++; } } /* Sort aspects by order of influence. */ for (i = 1; i < occurcount; i++) { j = i-1; while (j >= 0 && power[j] < power[j+1]) { SwapN(source[j], source[j+1]); SwapN(aspect[j], aspect[j+1]); SwapN(dest[j], dest[j+1]); SwapR(&power[j], &power[j+1]); j--; } } /* Now display each aspect line. */ for (i = 0; i < occurcount; i++) { sprintf(sz, "%3d: ", i+1); PrintSz(sz); j = source[i]; k = aspect[i]; l = dest[i]; PrintAspect( j, SFromZ(planet[j]), (int)RSgn(ret[j]), k, l, SFromZ(planet[l]), (int)RSgn(ret[l]), 'D'); m = grid->v[j][l]; AnsiColor(m < 0 ? kWhite : kLtGray); sprintf(sz, "- %s%2d%c%02d'", m < 0 ? "app" : "sep", abs(m)/60, chDeg1, abs(m)%60); PrintSz(sz); AnsiColor(kDkGreen); sprintf(sz, " - power:%6.2f", power[i]); PrintSz(sz); PrintInDay(j, k, l); } } /* Given an arbitrary day, determine what aspects are made between this */ /* transiting chart and the given natal chart, as specified with the -T */ /* switch, and display the transits in order sorted by influence. */ void ChartTransitInfluence(fProg) bool fProg; { int source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY]; real power[MAXINDAY]; byte ignore3[objMax]; char sz[cchSzDef]; int occurcount = 0, i, j, k, l, m; /* Cast the natal and transiting charts as with a relationship chart. */ for (i = 1; i <= cSign; i++) cp1.cusp[i] = house[i]; for (i = 1; i <= cObj; i++) { cp1.obj[i] = planet[i]; cp1.dir[i] = ret[i]; } ciCore = ciTwin; if (us.fProgress = fProg) { is.JDp = MdytszToJulian(MM, DD, YY, TT, SS, ZZ); ciCore = ciMain; } CastChart(fTrue); for (i = 1; i <= cSign; i++) cp2.cusp[i] = house[i]; for (i = 1; i <= cObj; i++) { cp2.obj[i] = planet[i]; cp2.dir[i] = ret[i]; } /* Do a relationship aspect grid to get the transits. We have to make and */ /* restore three changes to get it right for this chart. (1) We make the */ /* natal planets have zero velocity so applying vs. separating is only a */ /* function of the transiter. (2) We force applying vs. separating orbs */ /* regardless if -ga or -ma is in effect or not. (3) Finally we tweak the */ /* main restrictions to allow for transiting objects not restricted. */ for (i = 1; i <= cObj; i++) { ret[i] = cp1.dir[i]; cp1.dir[i] = 0.0; ignore3[i] = ignore[i]; ignore[i] = ignore[i] && ignore2[i]; } i = us.fAppSep; us.fAppSep = fTrue; FCreateGridRelation(fFalse); us.fAppSep = i; for (i = 1; i <= cObj; i++) { cp1.dir[i] = ret[i]; ignore[i] = ignore3[i]; } /* Loop through the grid, and build up a list of the valid transits. */ for (i = 1; i <= oNorm; i++) { if (ignore2[i] || !FThing(i)) continue; for (j = 1; j <= cObj; j++) { if (ignore[j] || (k = grid->n[i][j]) == 0 || occurcount >= MAXINDAY) continue; source[occurcount] = i; aspect[occurcount] = k; dest[occurcount] = j; l = grid->v[i][j]; power[occurcount] = transitinf[i]* ((j <= oNorm ? objectinf[j] : 2.0)/4.0)*aspectinf[k]* (1.0-(real)abs(l)/60.0/GetOrb(i, j, k)); occurcount++; } } /* After all transits located, sort them by their total power. */ for (i = 1; i < occurcount; i++) { j = i-1; while (j >= 0 && power[j] < power[j+1]) { SwapN(source[j], source[j+1]); SwapN(aspect[j], aspect[j+1]); SwapN(dest[j], dest[j+1]); SwapR(&power[j], &power[j+1]); j--; } } /* Now loop through list and display each transit in effect at the time. */ for (i = 0; i < occurcount; i++) { k = aspect[i]; l = source[i]; sprintf(sz, "%3d: ", i+1); PrintSz(sz); j = SFromZ(cp2.obj[l]); PrintAspect(l, j, (int)RSgn(cp2.dir[l]), k, dest[i], SFromZ(cp1.obj[dest[i]]), (int)RSgn(cp1.dir[dest[i]]), (char)(fProg ? 'U' : 'T')); m = grid->v[l][dest[i]]; AnsiColor(m < 0 ? kWhite : kLtGray); sprintf(sz, "- %s%2d%c%02d'", m < 0 ? "app" : "sep", abs(m)/60, chDeg1, abs(m)%60); PrintSz(sz); AnsiColor(kDkGreen); sprintf(sz, " - power:%6.2f", power[i]); PrintSz(sz); if (k == aCon && l == dest[i]) { /* Print a small "R" for returns. */ AnsiColor(kWhite); PrintSz(" R"); } PrintL(); #ifdef INTERPRET if (us.fInterpret) InterpretTransit(l, k, dest[i]); #endif AnsiColor(kDefault); } } /* Given the zodiac location of a planet in the sky and its declination, */ /* and a location on the Earth, compute the azimuth and altitude of where */ /* on the local horizon sky the planet would appear to one at the given */ /* location. A reference MC position at Greenwich is also needed for this. */ void EclToHorizon(azi, alt, planet, planetalt, lon, lat, mc) real *azi, *alt, planet, planetalt, lon, lat, mc; { real lonz, latz; lonz = RFromD(planet); latz = RFromD(planetalt); EclToEqu(&lonz, &latz); lonz = RFromD(Mod(DFromR(mc-lonz+lon))); lonz = RFromD(Mod(DFromR(lonz-lon+rPiHalf))); EquToLocal(&lonz, &latz, rPiHalf-lat); *azi = rDegMax-DFromR(lonz); *alt = DFromR(latz); } /* Display a calendar for the given month in the chart, as specified with */ /* with the -K switch. When color is on, the title is white, weekends are */ /* highlighted in red, and the specific day in the chart is colored green. */ void ChartCalendarMonth() { char sz[cchSzDef]; int i, j, k; AnsiColor(kWhite); PrintTab(' ', 16-CchSz(szMonth[Mon]) >> 1); sprintf(sz, "%s%5d\n", szMonth[Mon], Yea); PrintSz(sz); for (i = 0; i < 7; i++) { sprintf(sz, "%c%c%c", szDay[i][0], szDay[i][1], i < 6 ? ' ' : '\n'); PrintSz(sz); } j = DayOfWeek(Mon, 1, Yea); AnsiColor(kDefault); for (i = 0; i < j; i++) { if (i == 0) AnsiColor(kRainbowA[1]); PrintSz("-- "); if (i == 0) AnsiColor(kDefault); } k = DayInMonth(Mon, Yea); for (i = 1; i <= k; i = AddDay(Mon, i, Yea, 1)) { if (i == (int)Day) AnsiColor(kRainbowA[4]); else if (j == 0 || j == 6) AnsiColor(kRainbowA[1]); sprintf(sz, "%2d", i); PrintSz(sz); if (j == 0 || j == 6 || i == Day) AnsiColor(kDefault); if (j < 6) { j++; PrintCh(' '); } else { j = 0; PrintL(); } } while (j > 0 && j < 7) { if (j == 6) AnsiColor(kRainbowA[1]); j++; sprintf(sz, "--%c", j < 7 ? ' ' : '\n'); PrintSz(sz); } AnsiColor(kDefault); } /* Display a calendar for the entire year given in the chart, as specified */ /* with the -Ky switch. This is just like twelve of the individual month */ /* calendars above displayed together, with same color highlights and all. */ void ChartCalendarYear() { char sz[cchSzDef]; int r, w, c, m, d, dy, p[3], l[3], n[3]; dy = DayOfWeek(1, 1, Yea); for (r = 0; r < 4; r++) { /* Loop over one set of three months */ AnsiColor(kWhite); for (c = 0; c < 3; c++) { m = r*3+c+1; PrintTab(' ', 16-CchSz(szMonth[m]) >> 1); sprintf(sz, "%s%5d", szMonth[m], Yea); PrintSz(sz); if (c < 2) PrintTab(' ', 20 + MONTHSPACE - (16-CchSz(szMonth[m]) >> 1) - CchSz(szMonth[m]) - 5); } PrintL(); for (c = 0; c < 3; c++) { for (d = 0; d < 7; d++) { sprintf(sz, "%c%c%c", szDay[d][0], szDay[d][1], d < 6 || c < 2 ? ' ' : '\n'); PrintSz(sz); } if (c < 2) PrintTab(' ', MONTHSPACE-1); m = r*3+c+1; p[c] = dy % 7; l[c] = DayInMonth(m, Yea); n[c] = 0; dy += DaysInMonth(m, Yea); } for (w = 0; w < 6; w++) { /* Loop over one set of week rows */ for (c = 0; c < 3; c++) { /* Loop over one week in a month */ m = r*3+c+1; d = 0; if (w == 0) while (d < p[c]) { if (d == 0) AnsiColor(kRainbowA[1]); PrintSz("-- "); if (d == 0) AnsiColor(kDefault); d++; } AnsiColor(kDefault); while (d < 7 && n[c] < l[c]) { n[c] = AddDay(m, n[c], Yea, 1); if (n[c] == Day && m == Mon) AnsiColor(kRainbowA[4]); else if (d == 0 || d == 6) AnsiColor(kRainbowA[1]); sprintf(sz, "%2d%c", n[c], d < 6 || c < 2 ? ' ' : '\n'); PrintSz(sz); if (d == 0 || d == 6 || (n[c] == Day && m == Mon)) AnsiColor(kDefault); d++; } while (d < 7) { if (d == 0 || d == 6) AnsiColor(kRainbowA[1]); sprintf(sz, "--%c", d < 6 || c < 2 ? ' ' : '\n'); PrintSz(sz); if (d == 0) AnsiColor(kDefault); d++; } if (c < 2) PrintTab(' ', MONTHSPACE-1); } } if (r < 3) PrintL(); } AnsiColor(kDefault); } /* Display either a biorhythm chart or the time difference in various units */ /* between two charts, i.e. two types of relationship "charts" that aren't */ /* related in any way to planetary positions, as specified by either the */ /* -rb or -rd switches, respectively. */ void DisplayRelation() { char sz[cchSzDef]; int i; #ifdef BIORHYTHM int j; real k, l; #endif /* If we are calculating the difference between two dates, then display */ /* the value and return, as with the -rd switch. */ if (us.nRel == rcDifference) { PrintSz("Differences between the dates in the two charts:\n"); for (i = 1; i <= 7; i++) { AnsiColor(kRainbowA[i]); switch (i) { case 1: sprintf(sz, "Years : %.0f", is.JD/365.25); break; case 2: sprintf(sz, "Months : %.0f", is.JD/(365.25/12)); break; case 3: sprintf(sz, "Weeks : %.0f", is.JD/7.0); break; case 4: sprintf(sz, "Days : %.0f", is.JD); break; case 5: sprintf(sz, "Hours : %.0f", is.JD*24.0); break; case 6: sprintf(sz, "Minutes: %.0f", is.JD*24.0*60.0); break; case 7: sprintf(sz, "Seconds: %.0f", is.JD*24.0*3600.0); break; } PrintSz(sz); PrintL(); } AnsiColor(kDefault); return; } #ifdef BIORHYTHM /* If we are doing a biorhythm (-rb switch), then we'll calculate it for */ /* someone born on the older date, at the time of the younger date. Loop */ /* through the week preceeding and following the date in question. */ is.JD = RFloor(is.JD + rRound); for (is.JD -= 7.0, i = -7; i <= 7; i++, is.JD += 1.0) { if (i == 0) AnsiColor(kWhite); else if (i == 1) AnsiColor(kDefault); sprintf(sz, "T%c%d Day%c:", i < 0 ? '-' : '+', abs(i), abs(i) != 1 ? 's' : ' '); PrintSz(sz); for (j = 1; j <= 3; j++) { PrintCh(' '); switch (j) { case 1: k = brPhy; AnsiColor(kRed); PrintSz("Physical"); break; case 2: k = brEmo; AnsiColor(kBlue); PrintSz("Emotional"); break; case 3: k = brInt; AnsiColor(kGreen); PrintSz("Intellectual"); break; } AnsiColor(i ? kDefault : kWhite); /* The biorhythm calculation is below. */ l = RBiorhythm(is.JD, k); sprintf(sz, " at %c%3.0f%%", l < 0.0 ? '-' : '+', RAbs(l)); PrintSz(sz); /* Print smiley face, medium face, or sad face based on current cycle. */ AnsiColor(kPurple); sprintf(sz, " :%c", l > 50.0 ? ')' : (l < -50.0 ? '(' : '|')); PrintSz(sz); AnsiColor(i ? kDefault : kWhite); if (j < 3) PrintCh(','); } PrintL(); } #endif /* BIORHYTHM */ } /* charts2.c */