/* ** Astrolog (Version 4.40) File: xcharts0.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 GRAPH /* ****************************************************************************** ** Subchart Graphics Routines. ****************************************************************************** */ /* Given a string, draw it on the screen using the given color. The */ /* position of the text is based the saved positions of where we drew the */ /* text the last time the routine was called, being either directly below */ /* in the same column or in the same row just to the right. This is used */ /* by the sidebar drawing routine to print a list of text on the chart. */ int DrawPrint(sz, m, n) char *sz; int m, n; { static int x0, x, y; if (sz == NULL) { /* Null string means just initialize position. */ x0 = x = m; y = n; return y; } if (y >= gs.yWin-1) /* Don't draw if we've scrolled off the chart bottom. */ return y; DrawColor(m); DrawSz(sz, x, y, dtLeft | dtBottom); /* If the second parameter is TRUE, we stay on the same line, otherwise */ /* when FALSE we go to the next line at the original column setting. */ if (n) x += CchSz(sz)*xFont*gi.nScaleT; else { x = x0; n = y; y += yFont*gi.nScaleT; } return y; } /* Print text showing the chart information and house and planet positions */ /* of a chart in a "sidebar" to the right of the chart in question. This */ /* is always done for the -v and -w graphic wheel charts unless the -v0 */ /* switch flag is also set, in which case none of the stuff here is done. */ void DrawInfo() { char sz[cchSzDef]; ET et; int i, y, a, s; #ifdef INTERPRET int tot, abo, lef; /* Hack: Just for fun, if interpretation is active (which normally has */ /* no effect whatsoever on graphics) we'll decorate the chart a little. */ if (us.fInterpret) { if (us.nScreenWidth & 1) { /* If screenwidth value is odd, draw a moire pattern in each corner. */ abo = gs.yWin/(us.nScreenWidth/10); lef = gs.xWin/(us.nScreenWidth/10); for (y = 0; y <= 1; y++) for (i = 0; i <= 1; i++) for (s = 0; s <= 1; s++) for (a = 1; a < (s ? lef : abo)*2; a++) { DrawColor(a & 1 ? gi.kiGray : gi.kiOff); DrawLine(i ? gs.xWin-1-lef : lef, y ? gs.yWin-1-abo : abo, s ? (i ? gs.xWin-1-a : a) : i*(gs.xWin-1), s ? y*(gs.yWin-1) : (y ? gs.yWin-1-a : a)); } } else { /* If screenwidth is even, draw spider web lines in each corner. */ DrawColor(gi.kiGray); tot = us.nScreenWidth*3/20; abo = gs.yWin/4; lef = gs.xWin/4; for (y = 0; y <= 1; y++) for (i = 0; i <= 1; i++) for (a = 1; a < tot; a++) DrawLine(i*(gs.xWin-1), y ? (gs.yWin-1-a*abo/tot) : a*abo/tot, i ? gs.xWin-1-lef+a*lef/tot : lef-a*lef/tot, y*(gs.yWin-1)); } } #endif if (!gs.fText || us.fVelocity) /* Don't draw sidebar if */ return; /* -v0 flag is set. */ a = us.fAnsi; us.fAnsi = -(!gs.fFont || (!gs.fMeta && !gs.fPS)); DrawColor(gi.kiLite); if (gs.fBorder) DrawLine(gs.xWin-1, 0, gs.xWin-1, gs.yWin-1); gs.xWin += xSideT; DrawPrint(NULL, gs.xWin-xSideT+xFontT-gi.nScaleT, yFont*7/5*gi.nScaleT); /* Print chart header and setting information. */ sprintf(sz, "%s %s", szAppName, szVersionCore); DrawPrint(sz, gi.kiOn, fFalse); if (*ciMain.nam) DrawPrint(ciMain.nam, gi.kiLite, fFalse); if (Mon == -1) sprintf(sz, "No time or space."); else if (us.nRel == rcComposite) sprintf(sz, "Composite chart."); else { sprintf(sz, "%c%c%c %s", chDay3(DayOfWeek(Mon, Day, Yea)), SzDate(Mon, Day, Yea, fTrue)); DrawPrint(sz, gi.kiLite, fFalse); DrawPrint(SzTim(Tim), gi.kiLite, fTrue); sprintf(sz, " (%cT %s GMT)", Dst != 0.0 ? 'D' : 'S', SzZone(Zon)); } DrawPrint(sz, gi.kiLite, fFalse); if (*ciMain.loc) DrawPrint(ciMain.loc, gi.kiLite, fFalse); DrawPrint(SzLocation(Lon, Lat), gi.kiLite, fFalse); sprintf(sz, "%s houses.", szSystem[us.nHouseSystem]); DrawPrint(sz, gi.kiLite, fFalse); sprintf(sz, "%s, %s.", us.fSiderial ? "Sidereal" : "Tropical", us.objCenter == 0 ? "Heliocentric" : (us.objCenter == 1 ? "Geocentric" : szObjName[us.objCenter])); DrawPrint(sz, gi.kiLite, fFalse); sprintf(sz, "Julian Day = %11.4f", JulianDayFromTime(T)); DrawPrint(sz, gi.kiLite, fFalse); /* Print house cusp positions. */ DrawPrint("", gi.kiLite, fFalse); for (i = 1; i <= cSign; i++) { sprintf(sz, "%2d%s house: ", i, szSuffix[i]); y = DrawPrint(sz, kSignB(i), fTrue); if (!is.fSeconds && (gs.nScale == 100 || !gs.fFont || !gi.fFile || gs.fBitmap) && y < gs.yWin-1) { s = gi.nScale; gi.nScale = gi.nScaleT; DrawSign(SFromZ(house[i]), gs.xWin-12*gi.nScaleT, y-(yFont/2-1)*gi.nScaleT); gi.nScale = s; } DrawPrint(SzZodiac(house[i]), kSignB(SFromZ(house[i])), fFalse); } /* Print planet positions. */ DrawPrint("", gi.kiLite, fFalse); for (i = 1; i <= oNorm; i++) if (!ignore[i] && !FCusp(i)) { sprintf(sz, is.fSeconds ? "%3.3s: " : "%4.4s: ", szObjName[i]); DrawPrint(sz, kObjB[i], fTrue); y = DrawPrint(SzZodiac(planet[i]), kSignB(SFromZ(planet[i])), fTrue); if (!is.fSeconds && i < starLo && (gs.nScale == 100 || !gs.fFont || !gi.fFile || gs.fBitmap) && y < gs.yWin-1) { s = gi.nScale; gi.nScale = gi.nScaleT; DrawObject(i, gs.xWin-12*gi.nScaleT, y-(yFont/2-1)*gi.nScaleT); gi.nScale = s; } sprintf(sz, "%c ", ret[i] < 0.0 ? chRet : ' '); s = FThing(i); DrawPrint(sz, gi.kiOn, s); if (s) { is.fSeconds = fFalse; DrawPrint(SzAltitude(planetalt[i]), gi.kiLite, fFalse); is.fSeconds = us.fSeconds; } } /* Print star positions. */ for (i = starLo; i <= starHi; i++) if (!ignore[i]) { s = oNorm+starname[i-oNorm]; sprintf(sz, is.fSeconds ? "%3.3s: " : "%4.4s: ", szObjName[s]); DrawPrint(sz, kObjB[s], fTrue); DrawPrint(SzZodiac(planet[s]), kSignB(SFromZ(planet[s])), fTrue); DrawPrint(" ", gi.kiOn, fTrue); DrawPrint(SzAltitude(planetalt[s]), gi.kiLite, fFalse); } /* Print element table information. */ DrawPrint("", gi.kiLite, fFalse); CreateElemTable(&et); sprintf(sz, "Fire: %d, Earth: %d,", et.coElem[eFir], et.coElem[eEar]); DrawPrint(sz, gi.kiLite, fFalse); sprintf(sz, "Air : %d, Water: %d", et.coElem[eAir], et.coElem[eWat]); DrawPrint(sz, gi.kiLite, fFalse); sprintf(sz, "Car: %d, Fix: %d, Mut: %d", et.coMode[0], et.coMode[1], et.coMode[2]); DrawPrint(sz, gi.kiLite, fFalse); sprintf(sz, "Yang: %d, Yin: %d", et.coYang, et.coYin); DrawPrint(sz, gi.kiLite, fFalse); sprintf(sz, "M: %d, N: %d, A: %d, D: %d", et.coMC, et.coIC, et.coAsc, et.coDes); DrawPrint(sz, gi.kiLite, fFalse); sprintf(sz, "Ang: %d, Suc: %d, Cad: %d", et.coModeH[0], et.coModeH[1], et.coModeH[2]); DrawPrint(sz, gi.kiLite, fFalse); sprintf(sz, "Learn: %d, Share: %d", et.coLearn, et.coShare); DrawPrint(sz, gi.kiLite, fFalse); us.fAnsi = a; } /* ****************************************************************************** ** Map Chart Routines. ****************************************************************************** */ /* Another stream reader, this one is used by the globe drawing routine: */ /* for the next body of land/water, return its name (and color), its */ /* longitude and latitude, and a vector description of its outline. */ bool FReadWorldData(nam, loc, lin) char FAR **nam, FAR **loc, FAR **lin; { static char FAR **psz = (char FAR **)szWorldData; int i; *loc = *psz++; *lin = *psz++; *nam = *psz++; if (*loc[0]) { if (gs.fPrintMap && gi.fFile) { i = **nam - '0'; AnsiColor(i ? kRainbowA[i] : kMainA[7]); PrintSz(*nam+1); PrintL(); } return fTrue; } psz = (char FAR **)szWorldData; /* Reset stream when no data left. */ return fFalse; } /* Given longitude and latitude values on a globe, return the window */ /* coordinates corresponding to them. In other words, project the globe */ /* onto the view plane, and return where our coordinates got projected to, */ /* as well as whether our location is hidden on the back side of the globe. */ bool FGlobeCalc(x1, y1, u, v, cx, cy, rx, ry, deg) real x1, y1; int *u, *v, cx, cy, rx, ry, deg; { real j, siny1; /* Compute coordinates for a general globe invoked with -XG switch. */ if (gi.nMode == gGlobe) { x1 = Mod(x1+(real)deg); /* Shift by current globe rotation value. */ if (gs.rTilt != 0.0) { /* Do another coordinate shift if the globe's equator is tilted any. */ x1 = RFromD(x1); y1 = RFromD(rDegQuad-y1); CoorXform(&x1, &y1, RFromD(gs.rTilt)); x1 = Mod(DFromR(x1)); y1 = rDegQuad-DFromR(y1); } *v = cy + (int)((real)ry*-RCosD(y1)-rRound); *u = cx + (int)((real)rx*-RCosD(x1)*RSinD(y1)-rRound); return x1 > rDegHalf; } /* Compute coordinates for a polar globe invoked with -XP switch. */ siny1 = RSinD(y1); j = gs.fAlt ? rDegQuad+x1+deg : 270.0-x1-deg; *v = cy + (int)(siny1*(real)ry*RSinD(j)-rRound); *u = cx + (int)(siny1*(real)rx*RCosD(j)-rRound); return gs.fAlt ? y1 < rDegQuad : y1 > rDegQuad; } /* Draw one "Ley line" on the world map, based coordinates given in terms of */ /* longitude and vertical fractional distance from the center of the earth. */ void DrawLeyLine(l1, f1, l2, f2) real l1, f1, l2, f2; { l1 = Mod(l1); l2 = Mod(l2); /* Convert vertical fractional distance to a corresponding coordinate. */ f1 = rDegQuad-RAsin(f1)/rPiHalf*rDegQuad; f2 = rDegQuad-RAsin(f2)/rPiHalf*rDegQuad; DrawWrap((int)(l1*(real)gi.nScale+rRound)+1, (int)(f1*(real)gi.nScale+rRound)+1, (int)(l2*(real)gi.nScale+rRound)+1, (int)(f2*(real)gi.nScale+rRound)+1, 1, gs.xWin-2); } /* Draw the main set of planetary Ley lines on the map of the world. This */ /* consists of drawing an icosahedron and then a dodecahedron lattice. */ void DrawLeyLines(deg) int deg; { real off = (real)deg, phi, h, h1, h2, r, i; phi = (RSqr(5.0)+1.0)/2.0; /* Icosahedron constants. */ h = 1.0/(phi*2.0-1.0); DrawColor(kMainB[6]); for (i = off; i < rDegMax+off; i += 72.0) { /* Draw icosahedron edges. */ DrawLeyLine(i, h, i+72.0, h); DrawLeyLine(i-36.0, -h, i+36.0, -h); DrawLeyLine(i, h, i, 1.0); DrawLeyLine(i+36.0, -h, i+36.0, -1.0); DrawLeyLine(i, h, i+36.0, -h); DrawLeyLine(i, h, i-36.0, -h); } r = 1.0/RSqr(3.0)/phi/RCos(RFromD(54.0)); /* Dodecahedron constants. */ h2 = RSqr(1.0-r*r); h1 = h2/(phi*2.0+1.0); DrawColor(kMainB[4]); for (i = off; i < rDegMax+off; i += 72.0) { /* Draw docecahedron edges. */ DrawLeyLine(i-36.0, h2, i+36.0, h2); DrawLeyLine(i, -h2, i+72.0, -h2); DrawLeyLine(i+36.0, h2, i+36.0, h1); DrawLeyLine(i, -h2, i, -h1); DrawLeyLine(i+36.0, h1, i+72.0, -h1); DrawLeyLine(i+36.0, h1, i, -h1); } } /* This major routine draws all of Astrolog's map charts. This means */ /* either the world map or the constellations, in either rectangular or */ /* globe hemisphere form. The rectangular chart may also be done in a */ /* Mollewide projection, for six total combinations. We shift the chart by */ /* specified rotational and tilt values, and may draw on the chart each */ /* planet at its zenith position on Earth or location in constellations. */ void DrawMap(fSky, fGlobe, deg) bool fSky, fGlobe; int deg; { char *nam, *loc, *lin, chCmd; int X[objMax], Y[objMax], M[objMax], N[objMax], cx = gs.xWin/2, cy = gs.yWin/2, rx, ry, lon, lat, unit = 12*gi.nScale, x, y, xold, yold, m, n, u, v, i, j, k, l, nScl = gi.nScale; bool fNext = fTrue, fCan; real planet1[objMax], planet2[objMax], x1, y1, rT; #ifdef CONSTEL char *pch; bool fBlank; int isz = 0, nC, xT, yT, xDelta, yDelta, xLo, xHi, yLo, yHi; #endif /* Set up some variables. */ rx = cx-1; ry = cy-1; if (fGlobe) fCan = (gs.rTilt == 0.0 && gi.nMode != gPolar); #ifdef CONSTEL /* Draw a dot grid for large rectangular constellation charts. */ if (fSky && !fGlobe && !gs.fMollewide && gi.nScale/gi.nScaleT > 2) for (yT = 5; yT < nDegHalf; yT += 5) for (xT = 5; xT <= nDegMax; xT += 5) { DrawColor(xT % 15 == 0 && yT % 10 == 0 ? gi.kiOn : gi.kiGray); x = xT+deg; if (x > nDegMax) x -= nDegMax; DrawPoint(x*nScl, yT*nScl); } #endif loop { /* Get the next chunk of data to process. Get the starting position, */ /* map it to the screen, and set the drawing color appropriately. */ if (fNext) { fNext = fFalse; /* For constellations, get data for the next constellation shape. */ if (fSky) { #ifdef CONSTEL isz++; if (isz > cCnstl) break; DrawColor(gs.fAlt && gi.nMode != gPolar && (gi.nMode != gWorldMap || !gs.fMollewide) ? kMainB[7] : kRainbowB[6]); pch = (char *)szDrawConstel[isz]; lon = nDegMax - (((pch[2]-'0')*10+(pch[3]-'0'))*15+(pch[4]-'0')*10+(pch[5]-'0')); lat = 90-((pch[6] == '-' ? -1 : 1)*((pch[7]-'0')*10+(pch[8]-'0'))); pch += 9; xLo = xHi = xT = xold = x = lon; yLo = yHi = yT = yold = y = lat; nC = 0; if (fGlobe) { FGlobeCalc((real)x, (real)y, &m, &n, cx, cy, rx, ry, deg); k = l = fTrue; } else { xold += deg; x += deg; } #else ; #endif /* For world maps, get data for the next coastline piece. */ } else { if (!FReadWorldData(&nam, &loc, &lin)) break; i = nam[0]-'0'; DrawColor((!fGlobe && gi.nMode == gAstroGraph) ? gi.kiOn : (gi.nMode == gGlobe && gs.fAlt) ? gi.kiGray : (i ? kRainbowB[i] : kMainB[7])); lon = (loc[0] == '+' ? 1 : -1)* ((loc[1]-'0')*100 + (loc[2]-'0')*10 + (loc[3]-'0')); lat = (loc[4] == '+' ? 1 : -1)*((loc[5]-'0')*10 + (loc[6]-'0')); if (fGlobe) { x = 180-lon; y = 90-lat; FGlobeCalc((real)x, (real)y, &m, &n, cx, cy, rx, ry, deg); k = l = fTrue; } else { xold = x = 181-lon+deg; yold = y = 91-lat; } } } /* Get the next unit from the string to draw on the screen as a line. */ if (fSky) { /* For constellations we have a cache of how long we should keep */ /* going in the previous direction, as say "u5" for up five should */ /* move our pointer up five times without advancing string pointer. */ #ifdef CONSTEL if (nC <= 0) { if (!(chCmd = *pch)) { fNext = fTrue; if (gs.fText) { /* If we've reached the end of current constellation, compute */ /* the center location in it based on lower and upper bounds */ /* we've maintained, and print the name of the constel there. */ xT = xLo + (xHi - xLo)*(szDrawConstel[isz][0]-'1')/8; yT = yLo + (yHi - yLo)*(szDrawConstel[isz][1]-'1')/8; if (xT < 0) xT += nDegMax; else if (xT > nDegMax) xT -= nDegMax; if (fGlobe) { if (FGlobeCalc((real)xT, (real)yT, &x, &y, cx, cy, rx, ry, deg)) continue; } else { xT += deg; if (xT > nDegMax) xT -= nDegMax; if (gs.fMollewide) x = 180*nScl + NMultDiv(xT-180, NMollewide(yT-91), 180L); else x = xT*nScl; y = yT*nScl; } DrawColor(gs.fAlt && gi.nMode != gPolar && (gi.nMode != gWorldMap || !gs.fMollewide) ? gi.kiGray : kMainB[5]); DrawSz(szCnstlAbbrev[isz], x, y, dtCent); } continue; } pch++; /* Get the next direction and distance from constellation string. */ if (fBlank = (chCmd == 'b')) chCmd = *pch++; xDelta = yDelta = 0; switch (chCmd) { case 'u': yDelta = -1; break; /* Up */ case 'd': yDelta = 1; break; /* Down */ case 'l': xDelta = -1; break; /* Left */ case 'r': xDelta = 1; break; /* Right */ case 'U': yDelta = -1; nC = (yT-1)%10+1; break; /* Up until */ case 'D': yDelta = 1; nC = 10-yT%10; break; /* Down until */ case 'L': xDelta = -1; nC = (xT+599)%15+1; break; /* Left until */ case 'R': xDelta = 1; nC = 15-(xT+600)%15; break; /* Right until */ default: PrintError("Bad draw."); /* Shouldn't happen. */ } if (chCmd >= 'a') nC = NFromPch(&pch); /* Figure out how far to draw. */ } nC--; xT += xDelta; x += xDelta; yT += yDelta; y += yDelta; if (fBlank) { xold = x; yold = y; /* We occasionally want to move the pointer */ l = fFalse; /* without drawing the line on the screen. */ continue; } if (xT < xLo) /* Maintain our bounding rectangle for this */ xLo = xT; /* constellation if we crossed over it any. */ else if (xT > xHi) xHi = xT; if (yT < yLo) yLo = yT; else if (yT > yHi) yHi = yT; #else ; #endif } else { /* Get the next unit from the much simpler world map strings. */ if (!(chCmd = *lin)) { fNext = fTrue; continue; } lin++; /* Each unit is exactly one character in the coastline string. */ if (chCmd == 'L' || chCmd == 'H' || chCmd == 'G') x--; else if (chCmd == 'R' || chCmd == 'E' || chCmd == 'F') x++; if (chCmd == 'U' || chCmd == 'H' || chCmd == 'E') y--; else if (chCmd == 'D' || chCmd == 'G' || chCmd == 'F') y++; } /* Transform map coordinates to screen coordinates and draw a line. */ while (x >= nDegMax) /* Take care of coordinate wrap around. */ x -= nDegMax; while (x < 0) x += nDegMax; if (abs(x-xold) > nDegHalf) xold = x; if (fGlobe) { /* For globes, we have to go do a complicated transformation, and not */ /* draw when we're hidden on the back side of the sphere. We're smart */ /* and try to only do the slow stuff when we know we'll be visible. */ if (fCan) { k = x+deg; if (k >= nDegMax) k -= nDegMax; k = (k <= 180); } if (k && !FGlobeCalc((real)x, (real)y, &u, &v, cx, cy, rx, ry, deg)) { if (l) DrawLine(m, n, u, v); m = u; n = v; l = fTrue; } else l = fFalse; } else { /* Rectangular maps are much simpler, with screen coordinates */ /* proportional to internal coords. For the Mollewide projection */ /* we have to apply a factor to the horizontal positioning though. */ if (gs.fMollewide && gi.nMode != gAstroGraph) DrawLine(180*nScl + NMultDiv(xold-180, NMollewide(yold-91), 180L), yold*nScl, 180*nScl + NMultDiv(x-180, NMollewide(y-91), 180L), y*nScl); else DrawLine(xold*nScl, yold*nScl, x*nScl, y*nScl); xold = x; yold = y; } } /* Draw the outline of the map, either a circle around globes or a */ /* Mollewide type ellipse for that type of rectangular chart. */ DrawColor(gi.kiOn); if (!fGlobe) { if (gs.fMollewide && gi.nMode != gAstroGraph) if (!gs.fAlt) for (xold = 0, y = -89; y <= 90; y++, xold = x) for (x = NMollewide(y), i = -1; i <= 1; i += 2) { DrawLine(180*nScl + i*xold - (i == 1), (90+y)*nScl, 180*nScl + i*x - (i == 1), (91+y)*nScl); } } else DrawEllipse(0, 0, gs.xWin-1, gs.yWin-1); /* Now, if we are in an appropriate bonus chart mode, draw each planet at */ /* its zenith or visible location on the globe or map, if not hidden. */ if (!gs.fAlt || (gi.nMode != gGlobe && (!fSky || gi.nMode != gWorldMap || gs.fMollewide))) return; rT = gs.fConstel ? rDegHalf - (fGlobe ? 0.0 : (real)deg) : Lon; if (rT < 0.0) rT += rDegMax; for (i = 1; i <= cObj; i++) { planet1[i] = RFromD(Tropical(planet[i])); planet2[i] = RFromD(planetalt[i]); EclToEqu(&planet1[i], &planet2[i]); /* Calculate zenith long. & lat. */ } /* Compute screen coordinates of each object, if it's even visible. */ for (i = 1; i <= cObj; i++) if (FProper(i)) { if (fSky) x1 = planet1[i]; else x1 = planet1[oMC]-planet1[i]; if (x1 < 0.0) x1 += 2.0*rPi; if (x1 > rPi) x1 -= 2.0*rPi; x1 = Mod(rDegHalf-rT-DFromR(x1)); y1 = rDegQuad-DFromR(planet2[i]); if (fGlobe) { X[i] = FGlobeCalc(x1, y1, &u, &v, cx, cy, rx, ry, deg) ? -1000 : u; Y[i] = v; } else { X[i] = (int)(x1 * (real)nScl); Y[i] = (int)(y1 * (real)nScl); } M[i] = X[i]; N[i] = Y[i]+unit/2; } /* Now that we have the coordinates of each object, figure out where to */ /* draw the glyphs. Again we try not to draw glyphs on top of each other. */ for (i = 1; i <= cObj; i++) if (FProper(i)) { k = l = gs.xWin+gs.yWin; /* For each planet, we draw the glyph either right over or right under */ /* the actual zenith location point. So, find out the closest distance */ /* of any other planet assuming we place ours at both possibilities. */ for (j = 1; j < i; j++) if (FProper(j)) { k = Min(k, abs(M[i]-M[j])+abs(N[i]-N[j])); l = Min(l, abs(M[i]-M[j])+abs(N[i]-unit-N[j])); } /* Normally, we put the glyph right below the actual point. If however */ /* another planet is close enough to have their glyphs overlap, and the */ /* above location is better, then we'll draw the glyph above instead. */ if (k < unit || l < unit) if (k < l) N[i] -= unit; } for (i = cObj; i >= 1; i--) if (X[i] >= 0 && FProper(i)) /* Draw the */ DrawObject(i, M[i], N[i]); /* glyphs. */ for (i = cObj; i >= 1; i--) if (X[i] >= 0 && FProper(i)) { DrawColor(kObjB[i]); DrawSpot(X[i], Y[i]); } } /* Create a chart in the window based on the current graphics chart mode. */ /* This is the main dispatch routine for all of the program's graphics. */ void DrawChartX() { char sz[cchSzDef]; int i; bool fT; gi.nScale = gs.nScale/100; if (gs.fBitmap || gs.fMeta) PrintNotice("Creating graphics chart in memory."); DrawClearScreen(); #ifdef CONSTEL fT = gs.fConstel; #else fT = fFalse; #endif switch (gi.nMode) { case gWheel: case gHouse: if (us.nRel > rcDual) XChartWheel(); else XChartWheelRelation(); break; case gGrid: if (us.nRel > rcDual) XChartGrid(); else XChartGridRelation(); break; case gHorizon: if (us.fPrimeVert) XChartHorizonSky(); else XChartHorizon(); break; case gOrbit: XChartOrbit(); break; case gDisposit: XChartDispositor(); break; case gAstroGraph: DrawMap(fFalse, fFalse, gs.nRot); /* First draw map of world. */ XChartAstroGraph(); /* Then draw astro-graph lines on it. */ break; case gCalendar: XChartCalendar(); break; case gEphemeris: XChartEphemeris(); break; case gWorldMap: DrawMap(fT, fFalse, gs.nRot); /* First draw map of world. */ if (!fT && gs.fAlt && !gs.fMollewide) /* Then maybe Ley lines. */ DrawLeyLines(gs.nRot); break; case gGlobe: case gPolar: DrawMap(fT, fTrue, gs.nRot); break; #ifdef BIORHYTHM case gBiorhythm: XChartBiorhythm(); break; #endif } /* Print text showing chart information at bottom of window. */ DrawColor(gi.kiLite); if (fDrawText) { if (Mon == -1) sprintf(sz, "(No time or space)"); else if (us.nRel == rcComposite) sprintf(sz, "(Composite)"); else { fT = us.fAnsi; us.fAnsi = -(!gs.fFont || (!gs.fMeta && !gs.fPS)); i = DayOfWeek(Mon, Day, Yea); sprintf(sz, "%c%c%c %s %s (%cT %s GMT) %s", chDay3(i), SzDate(Mon, Day, Yea, 2), SzTim(Tim), Dst != 0.0 ? 'D' : 'S', SzZone(Zon), SzLocation(Lon, Lat)); us.fAnsi = fT; } DrawSz(sz, gs.xWin/2, gs.yWin-3*gi.nScaleT, dtBottom | dtErase); } /* Draw a border around the chart if the mode is set and appropriate. */ if (fDrawBorder) DrawEdgeAll(); } #endif /* GRAPH */ /* xcharts0.c */