This is xoptions.c in view mode; [Download] [Up]
/* ** Astrolog (Version 4.10) File: xoptions.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" #ifdef GRAPH /* ****************************************************************************** ** Chart Graphics Subroutines. ****************************************************************************** */ /* Return whether the specified object should be displayed in the current */ /* graphics chart type. For example, don't include the Moon in the solar */ /* system charts, don't include house cusps in astro-graph, and so on. */ bool Proper(i) int i; { bool j; if (modex == MODEL || modex == MODEE) /* Astro-graph or ephem charts */ j = IsThing(i); else if (modex == MODEZ || modex == MODEG) /* Horizon or zenith charts */ j = IsObject(i); else if (modex == MODES) /* Solar system charts */ j = IsObject(i) && (i != _MOO || (placalc && centerplanet < _MOO)); else j = TRUE; return j && !ignore[i]; /* Check restriction status */ } /* Set up arrays with the sine and cosine values of each degree. This is */ /* used by the wheel chart routines which draw lots of circles. Memory is */ /* allocated for this array if not already done. The allocation and */ /* initialization is only done once, the first time the routine is called. */ bool InitCircle() { char string[STRING]; int i; if (circ != NULL) return TRUE; Allocate(circ, sizeof(circlestruct), circlestruct PTR); if (circ == NULL #ifdef PC /* For PC's the array better not cross a segment boundary. */ || HIWORD(LOWORD(circ) + sizeof(circlestruct)) > 0 #endif ) { sprintf(string, "Not enough memory for sine table (%d bytes).", sizeof(circlestruct)); PrintError(string); return FALSE; } for (i = 0; i < DEGD; i++) { circ->x[i] = COSD((real) i); circ->y[i] = SIND((real) i); } circ->x[DEGD] = circ->x[0]; circ->y[DEGD] = circ->y[0]; return TRUE; } /* Adjust an array of zodiac positions so that no two positions are within */ /* a certain orb of each other. This is used by the wheel drawing chart */ /* routines in order to make sure that we don't draw any planet glyphs on */ /* top of each other. We'll later draw the glyphs at the adjusted positions. */ void FillSymbolRing(symbol) real *symbol; { real orb = DEFORB*256.0/(real)charty*(real)SCALE, k1, k2, temp; int i, j, k = 1, l; /* Keep adjusting as long as we can still make changes, or until we do 'n' */ /* rounds. (With many objects, there just may not be enough room for all.) */ for (l = 0; k && l < divisions*2; l++) { k = 0; for (i = 1; i <= total; i++) if (Proper(i)) { /* For each object, determine who is closest on either side. */ k1 = LARGE; k2 = -LARGE; for (j = 1; j <= total; j++) if (Proper(j) && i != j) { temp = symbol[j]-symbol[i]; if (dabs(temp) > DEGHALF) temp -= DEGREES*Sgn(temp); if (temp < k1 && temp >= 0.0) k1 = temp; else if (temp > k2 && temp <= 0.0) k2 = temp; } /* If an object's too close on one side, then we move to the other. */ if (k2 > -orb && k1 > orb) { k = 1; symbol[i] = Mod(symbol[i]+orb*0.51+k2*0.49); } else if (k1 < orb && k2 < -orb) { k = 1; symbol[i] = Mod(symbol[i]-orb*0.51+k1*0.49); /* If we are bracketed by close objects on both sides, then let's move */ /* to the midpoint, so we are as far away as possible from either one. */ } else if (k2 > -orb && k1 < orb) { k = 1; symbol[i] = Mod(symbol[i]+(k1+k2)*0.5); } } } } /* Adjust an array of longitude positions so that no two are within a */ /* certain orb of each other. This is used by the astro-graph routine to */ /* make sure we don't draw any planet glyphs marking the lines on top of */ /* each other. This is almost identical to the FillSymbolRing() routine */ /* used by the wheel charts; however, there the glyphs are placed in a */ /* continuous ring, while here we have the left and right screen edges. */ /* Also, here we are placing two sets of planets at the same time. */ void FillSymbolLine(symbol) real *symbol; { real orb = DEFORB*1.35*(real)SCALE, max = DEGREES, k1, k2, temp; int i, j, k = 1, l; if (modex != MODEE) max *= (real)SCALE; else orb *= DEGREES/(real)chartx; /* Keep adjusting as long as we can still make changes. */ for (l = 0; k && l < divisions*2; l++) { k = 0; for (i = 1; i <= total*2; i++) if (Proper((i+1)/2) && symbol[i] >= 0.0) { /* For each object, determine who is closest to the left and right. */ k1 = max-symbol[i]; k2 = -symbol[i]; for (j = 1; j <= total*2; j++) { if (Proper((j+1)/2) && i != j) { temp = symbol[j]-symbol[i]; if (temp < k1 && temp >= 0.0) k1 = temp; else if (temp > k2 && temp <= 0.0) k2 = temp; } } /* If an object's too close on one side, then we move to the other. */ if (k2 > -orb && k1 > orb) { k = 1; symbol[i] = symbol[i]+orb*0.51+k2*0.49; } else if (k1 < orb && k2 < -orb) { k = 1; symbol[i] = symbol[i]-orb*0.51+k1*0.49; } else if (k2 > -orb && k1 < orb) { k = 1; symbol[i] = symbol[i]+(k1+k2)*0.5; } } } } /* 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. */ int ReadWorldData(nam, loc, lin) char **nam, **loc, **lin; { static char FAR **datapointer = worlddata; *loc = *datapointer++; *lin = *datapointer++; *nam = *datapointer++; if (*loc[0]) { if ((exdisplay & DASHXP0) && xfile) fprintf(stdout, "%s\n", *nam+1); return TRUE; } datapointer = worlddata; /* Reset stream when no data left. */ return FALSE; } /* 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. */ int GlobeCalc(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 (modex == MODEG) { x1 = Mod(x1+(real)deg); /* Shift by current globe rotation value. */ if (tilt != 0.0) { x1 = DTOR(x1); y1 = DTOR(DEGQUAD-y1); /* Do another coordinate */ CoorXform(&x1, &y1, tilt / DEGRAD); /* shift if the globe's */ x1 = Mod(RTOD(x1)); y1 = DEGQUAD-RTOD(y1); /* equator is tilted any. */ } *v = cy + (int) ((real)ry*-COSD(y1)-ROUND); *u = cx + (int) ((real)rx*-COSD(x1)*SIND(y1)-ROUND); return x1 > DEGHALF; } /* Compute coordinates for a polar globe invoked with -XP switch. */ siny1 = SIND(y1); j = xbonus ? DEGQUAD+x1+deg : 270.0-x1-deg; *v = cy + (int) (siny1*(real)ry*SIND(j)-ROUND); *u = cx + (int) (siny1*(real)rx*COSD(j)-ROUND); return xbonus ? y1 < DEGQUAD : y1 > DEGQUAD; } /* Draw a globe in the window, based on the specified rotational and tilt */ /* values. In addition, we may draw in each planet at its zenith position. */ void DrawGlobe(deg) int deg; { char *nam, *loc, *lin, d; int X[TOTAL+1], Y[TOTAL+1], M[TOTAL+1], N[TOTAL+1], cx = chartx/2, cy = charty/2, rx, ry, lon, lat, unit = 12*SCALE, x, y, m, n, u, v, i, J, k, l, o; real planet1[TOTAL+1], planet2[TOTAL+1], x1, y1, j; colpal c; rx = cx-1; ry = cy-1; /* Loop through each coastline string, drawing visible parts on the globe. */ while (ReadWorldData(&nam, &loc, &lin)) { i = nam[0]-'0'; c = (modex == MODEG && xbonus) ? gray : (i ? rainbowcolor[i] : maincolor[6]); DrawColor(c); /* Get starting longitude and latitude of current coastline piece. */ 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')); x = 180-lon; y = 90-lat; GlobeCalc((real) x, (real) y, &m, &n, cx, cy, rx, ry, deg); /* Go down the coastline piece, drawing each visible segment on globe. */ o = (tilt == 0.0 && modex != MODEP); k = l = TRUE; while (d = *lin++) { if (d == 'L' || d == 'H' || d == 'G') x--; else if (d == 'R' || d == 'E' || d == 'F') x++; if (d == 'U' || d == 'H' || d == 'E') y--; else if (d == 'D' || d == 'G' || d == 'F') y++; if (x > 359) x = 0; else if (x < 0) x = 359; if (o) { k = x+deg; if (k > 359) k -= DEGD; k = (k <= 180); } if (k && !GlobeCalc((real) x, (real) y, &u, &v, cx, cy, rx, ry, deg)) { if (l) DrawLine(m, n, u, v); m = u; n = v; l = TRUE; } else l = FALSE; } } DrawColor(on); DrawEllipse(0, 0, chartx-1, charty-1); /* Now, only if we are in bonus chart mode, draw each planet at its */ /* zenith location on the globe, assuming that location is visible. */ if (modex != MODEG || !xbonus) return; j = Lon; if (j < 0.0) j += DEGREES; for (i = 1; i <= total; i++) { planet1[i] = DTOR(planet[i]); planet2[i] = DTOR(planetalt[i]); EclToEqu(&planet1[i], &planet2[i]); /* Calculate zenith long. & lat. */ } for (i = 1; i <= total; i++) if (Proper(i)) { x1 = planet1[_MC]-planet1[i]; if (x1 < 0.0) x1 += 2.0*PI; if (x1 > PI) x1 -= 2.0*PI; x1 = Mod(DEGHALF-j-RTOD(x1)); y1 = DEGQUAD-RTOD(planet2[i]); X[i] = GlobeCalc(x1, y1, &u, &v, cx, cy, rx, ry, deg) ? -1000 : u; Y[i] = v; 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 <= total; i++) if (Proper(i)) { k = l = chartx+charty; /* 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 (Proper(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 of, then we'll draw the glyph above instead. */ if (k < unit || l < unit) if (k < l) N[i] -= unit; } for (i = total; i >= 1; i--) if (X[i] >= 0 && Proper(i)) /* Draw the */ DrawObject(i, M[i], N[i]); /* glyphs. */ for (i = total; i >= 1; i--) if (X[i] >= 0 && Proper(i)) { DrawColor(objectcolor[i]); DrawSpot(X[i], Y[i]); } } /* 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 = DEGQUAD-ASIN(f1)/(PI/2.0)*DEGQUAD; f2 = DEGQUAD-ASIN(f2)/(PI/2.0)*DEGQUAD; DrawWrap((int) (l1*(real)SCALE+ROUND)+1, (int) (f1*(real)SCALE+ROUND)+1, (int) (l2*(real)SCALE+ROUND)+1, (int) (f2*(real)SCALE+ROUND)+1, 1, chartx-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 = (sqrt(5.0)+1.0)/2.0; /* Icosahedron constants. */ h = 1.0/(phi*2.0-1.0); DrawColor(aspectcolor[10]); for (i = off; i < DEGREES+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/sqrt(3.0)/phi/cos(DTOR(54.0)); /* Dodecahedron constants. */ h2 = sqrt(1.0-r*r); h1 = h2/(phi*2.0+1.0); DrawColor(aspectcolor[13]); for (i = off; i < DEGREES+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); } } /* Draw a map of the world on the screen. This is similar to drawing the */ /* globe, but is simplified because this is just a rectangular image, and */ /* the window coordinates are proportional to the longitude and latitude. */ void DrawWorld(deg) int deg; { char *nam, *loc, *lin, d; int lon, lat, x, y, xold, yold, i; colpal c; /* Loop through each coastline string, drawing it on the world map. */ while (ReadWorldData(&nam, &loc, &lin)) { i = nam[0]-'0'; c = modex == MODEL ? on : (i ? rainbowcolor[i] : maincolor[6]); /* Get starting longitude and latitude of current coastline piece. */ 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')); xold = x = (int) Mod((real)(181-lon+deg)); yold = y = 91-lat; /* Go down the coastline piece, drawing each segment on world map. */ for (i = 0; d = lin[i]; i++) { if (d == 'L' || d == 'H' || d == 'G') x--; else if (d == 'R' || d == 'E' || d == 'F') x++; if (d == 'U' || d == 'H' || d == 'E') y--; else if (d == 'D' || d == 'G' || d == 'F') y++; if (x > DEGD) { x = 1; xold = 0; } /* If we are doing a Mollewide map projection, then transform the */ /* coordinates appropriately before drawing the segment. */ DrawColor(c); if ((exdisplay & DASHXW0) > 0 && modex != MODEL) DrawLine((180+(xold-180)* (int)sqrt((real)(32400-4*(yold-91)*(yold-91)))/180)*SCALE, yold*SCALE, (180+(x-180)*(int)sqrt((real)(32400-4*(y-91)*(y-91)))/180)*SCALE, y*SCALE); else DrawLine(xold*SCALE, yold*SCALE, x*SCALE, y*SCALE); if (x < 1) x = DEGD; xold = x; yold = y; } } /* Again, if we are doing the non-rectangular Mollewide map projection, */ /* draw the outline of the globe/map itself. */ if ((exdisplay & DASHXW0) > 0 && modex != MODEL) { if (!xbonus) { DrawColor(on); for (xold = 0, y = -89; y <= 90; y++, xold = x) for (x = (int)(sqrt((real)(32400-4*y*y))+ROUND), i = -1; i < 2; i += 2) DrawLine((180+i*xold)*SCALE, (90+y)*SCALE, (180+i*x)*SCALE, (91+y)*SCALE); } } } /* Given a zodiac degree, adjust it if need be to account for the expanding */ /* and compacting of parts the zodiac that happen when we display a graphic */ /* wheel chart such that all the houses appear the same size. */ real XHousePlaceIn(deg) real deg; { int in; if (modex == MODEv) /* We only adjust for the -w -X combination. */ return deg; in = HousePlaceIn(deg); return Mod(STOZ(in)+MinDistance(house[in], deg)/ MinDistance(house[in], house[Mod12(in+1)])*30.0); } /* ****************************************************************************** ** Multiple Chart Graphics Subprograms. ****************************************************************************** */ /* Draw another wheel chart; however, this time we have two rings of planets */ /* because we are doing a relationship chart between two sets of data. This */ /* chart is obtained when the -r0 is combined with the -X switch. */ void XChartWheelRelation() { real xsign[SIGNS+1], xhouse1[SIGNS+1], xplanet1[TOTAL+1], xplanet2[TOTAL+1], symbol[TOTAL+1]; int cx, cy, i, j; real asc, unitx, unity, px, py, temp; /* Set up variables and temporarily automatically decrease the horizontal */ /* chart size to leave room for the sidebar if that mode is in effect. */ if (xtext && !(exdisplay & DASHv0)) chartx -= SIDET; cx = chartx/2 - 1; cy = charty/2 - 1; unitx = (real)cx; unity = (real)cy; asc = xeast ? planet1[abs(xeast)]+90*(xeast < 0) : house1[1]; InitCircle(); /* Fill out arrays with the degree of each object, cusp, and sign glyph. */ if (modex == MODEv) { for (i = 1; i <= SIGNS; i++) xhouse1[i] = PZ(house1[i]); } else { asc -= house1[1]; for (i = 1; i <= SIGNS; i++) xhouse1[i] = PZ(STOZ(i)); } for (i = 1; i <= SIGNS; i++) xsign[i] = PZ(XHousePlaceIn(STOZ(i))); for (i = 1; i <= total; i++) xplanet1[i] = PZ(XHousePlaceIn(planet1[i])); for (i = 1; i <= total; i++) xplanet2[i] = PZ(XHousePlaceIn(planet2[i])); /* Draw the horizon and meridian lines across whole chart, and draw the */ /* zodiac and house rings, exactly like before. We are drawing only the */ /* houses of one of the two charts in the relationship, however. */ DrawColor(hilite); DrawDash(cx+POINT(unitx, 0.99, PX(xhouse1[1])), cy+POINT(unity, 0.99, PY(xhouse1[1])), cx+POINT(unitx, 0.99, PX(xhouse1[7])), cy+POINT(unity, 0.99, PY(xhouse1[7])), !xcolor); DrawDash(cx+POINT(unitx, 0.99, PX(xhouse1[10])), cy+POINT(unity, 0.99, PY(xhouse1[10])), cx+POINT(unitx, 0.99, PX(xhouse1[4])), cy+POINT(unity, 0.99, PY(xhouse1[4])), !xcolor); for (i = 0; i < DEGD; i += 5-(xcolor || psfile || metafile)*4) { temp = PZ(XHousePlaceIn((real)i)); px = PX(temp); py = PY(temp); DrawColor(i%5 ? gray : on); DrawDash(cx+POINT(unitx, 0.78, px), cy+POINT(unity, 0.78, py), cx+POINT(unitx, 0.82, px), cy+POINT(unity, 0.82, py), ((psfile || metafile) && i%5)*2); } DrawColor(on); DrawCircle(cx, cy, (int)(unitx*0.95+ROUND), (int)(unity*0.95+ROUND)); DrawCircle(cx, cy, (int)(unitx*0.82+ROUND), (int)(unity*0.82+ROUND)); DrawCircle(cx, cy, (int)(unitx*0.78+ROUND), (int)(unity*0.78+ROUND)); DrawCircle(cx, cy, (int)(unitx*0.70+ROUND), (int)(unity*0.70+ROUND)); for (i = 1; i <= SIGNS; i++) { temp = xsign[i]; DrawColor(on); DrawLine(cx+POINT(unitx, 0.95, PX(temp)), cy+POINT(unity, 0.95, PY(temp)), cx+POINT(unitx, 0.82, PX(temp)), cy+POINT(unity, 0.82, PY(temp))); DrawLine(cx+POINT(unitx, 0.78, PX(xhouse1[i])), cy+POINT(unity, 0.78, PY(xhouse1[i])), cx+POINT(unitx, 0.70, PX(xhouse1[i])), cy+POINT(unity, 0.70, PY(xhouse1[i]))); if (xcolor && i%3 != 1) { DrawColor(gray); DrawDash(cx, cy, cx+POINT(unitx, 0.70, PX(xhouse1[i])), cy+POINT(unity, 0.70, PY(xhouse1[i])), 1); } temp = Midpoint(temp, xsign[Mod12(i+1)]); DrawColor(signcolor(i)); DrawSign(i, cx+POINT(unitx, 0.885, PX(temp)), cy+POINT(unity, 0.885, PY(temp))); temp = Midpoint(xhouse1[i], xhouse1[Mod12(i+1)]); DrawHouse(i, cx+POINT(unitx, 0.74, PX(temp)), cy+POINT(unity, 0.74, PY(temp))); } /* Draw the outer ring of planets (based on the planets in the chart */ /* which the houses do not reflect - the houses belong to the inner ring */ /* below). Draw each glyph, a line from it to its actual position point */ /* in the outer ring, and then draw another line from this point to a */ /* another dot at the same position in the inner ring as well. */ for (i = 1; i <= total; i++) symbol[i] = xplanet2[i]; FillSymbolRing(symbol); for (i = total; i >= 1; i--) if (Proper(i)) { if (xlabel) { temp = symbol[i]; DrawColor(ret2[i] < 0.0 ? gray : on); DrawDash(cx+POINT(unitx, 0.58, PX(xplanet2[i])), cy+POINT(unity, 0.58, PY(xplanet2[i])), cx+POINT(unitx, 0.61, PX(temp)), cy+POINT(unity, 0.61, PY(temp)), (ret2[i] < 0.0 ? 1 : 0) - xcolor); DrawObject(i, cx+POINT(unitx, 0.65, PX(temp)), cy+POINT(unity, 0.65, PY(temp))); } DrawColor(objectcolor[i]); DrawPoint(cx+POINT(unitx, 0.56, PX(xplanet2[i])), cy+POINT(unity, 0.56, PY(xplanet2[i]))); DrawPoint(cx+POINT(unitx, 0.43, PX(xplanet2[i])), cy+POINT(unity, 0.43, PY(xplanet2[i]))); DrawColor(ret2[i] < 0.0 ? gray : on); DrawDash(cx+POINT(unitx, 0.45, PX(xplanet2[i])), cy+POINT(unity, 0.45, PY(xplanet2[i])), cx+POINT(unitx, 0.54, PX(xplanet2[i])), cy+POINT(unity, 0.54, PY(xplanet2[i])), 2-xcolor); } /* Now draw the inner ring of planets. If it weren't for the outer ring, */ /* this would be just like the standard non-relationship wheel chart with */ /* only one set of planets. Again, draw glyph, and a line to true point. */ for (i = 1; i <= total; i++) { symbol[i] = xplanet1[i]; } FillSymbolRing(symbol); for (i = 1; i <= total; i++) if (Proper(i)) { if (xlabel) { temp = symbol[i]; DrawColor(ret1[i] < 0.0 ? gray : on); DrawDash(cx+POINT(unitx, 0.45, PX(xplanet1[i])), cy+POINT(unity, 0.45, PY(xplanet1[i])), cx+POINT(unitx, 0.48, PX(temp)), cy+POINT(unity, 0.48, PY(temp)), (ret1[i] < 0.0 ? 1 : 0) - xcolor); DrawObject(i, cx+POINT(unitx, 0.52, PX(temp)), cy+POINT(unity, 0.52, PY(temp))); } else DrawColor(objectcolor[i]); DrawPoint(cx+POINT(unitx, 0.43, PX(xplanet1[i])), cy+POINT(unity, 0.43, PY(xplanet1[i]))); } /* Draw lines connecting planets between the two charts that have aspects. */ if (!xbonus) { /* Don't draw aspects in bonus mode. */ CreateGridRelation(FALSE); for (j = total; j >= 1; j--) for (i = total; i >= 1; i--) if (grid->n[i][j] && Proper(i) && Proper(j)) { DrawColor(aspectcolor[grid->n[i][j]]); DrawDash(cx+POINT(unitx, 0.41, PX(xplanet1[j])), cy+POINT(unity, 0.41, PY(xplanet1[j])), cx+POINT(unitx, 0.41, PX(xplanet2[i])), cy+POINT(unity, 0.41, PY(xplanet2[i])), abs(grid->v[i][j]/60/2)); } } /* Go draw sidebar with chart information and positions if need be. */ DrawInfo(); } /* Draw an aspect (or midpoint) grid in the window, between the planets in */ /* two different charts, with the planets labeled at the top and side. This */ /* chart is done when the -g switch is combined with the -r0 and -X switch. */ /* Like above, the chart always has a (definable) fixed number of cells. */ void XChartGridRelation() { char string[STRING]; int unit, siz, x, y, i, j, k, l; colpal c; unit = CELLSIZE*SCALE; siz = (gridobjects+1)*unit; CreateGridRelation(xbonus != (exdisplay & DASHg0) > 0); for (y = 0, j = -1; y <= gridobjects; y++) { do { j++; } while (ignore[j] && j <= total); DrawColor(gray); DrawDash(0, (y+1)*unit, siz, (y+1)*unit, !xcolor); DrawDash((y+1)*unit, 0, (y+1)*unit, siz, !xcolor); DrawColor(hilite); DrawEdge(0, y*unit, unit, (y+1)*unit); DrawEdge(y*unit, 0, (y+1)*unit, unit); if (j <= total) for (x = 0, i = -1; x <= gridobjects; x++) { do { i++; } while (ignore[i] && i <= total); /* Again, we are looping through each cell in each row and column. */ if (i <= total) { turtlex = x*unit+unit/2; turtley = y*unit+unit/2 - (SCALE/scalet > 2 ? 5*scalet : 0); /* If current cell is on top row or left hand column, draw glyph */ /* of planet owning the particular row or column in question. */ if (y == 0 || x == 0) { if (x+y > 0) DrawObject(j == 0 ? i : j, turtlex, turtley); } else { /* Otherwise, draw glyph of aspect in effect, or glyph of */ /* sign of midpoint, between the two planets in question. */ if (xbonus == (exdisplay & DASHg0) > 0) { DrawColor(c = aspectcolor[grid->n[i][j]]); DrawAspect(grid->n[i][j], turtlex, turtley); } else { DrawColor(c = signcolor(grid->n[i][j])); DrawSign(grid->n[i][j], turtlex, turtley); } } /* Again, when scale size is 300+, print some text in current cell: */ if (SCALE/scalet > 2 && xlabel) { /* For top and left edges, print sign and degree of the planet. */ if (y == 0 || x == 0) { if (x+y > 0) { k = ZTOS(y == 0 ? planet2[i] : planet1[j]); l = (int)((y == 0 ? planet2[i] : planet1[j])-STOZ(k)); c = signcolor(k); sprintf(string, "%c%c%c %02d", SIGNAM(k), l); /* For extreme upper left corner, print some little arrows */ /* pointing out chart1's planets and chart2's planets. */ } else { c = hilite; sprintf(string, "1v 2->"); } } else { k = abs(grid->v[i][j]); /* For aspect cells, print the orb in degrees and minutes. */ if (xbonus == (exdisplay & DASHg0) > 0) if (grid->n[i][j]) sprintf(string, "%c%d %02d'", k != grid->v[i][j] ? (exdisplay & DASHga ? 'a' : '-') : (exdisplay & DASHga ? 's' : '+'), k/60, k%60); else sprintf(string, ""); /* For midpoint cells, print degree and minute. */ else sprintf(string, "%2d %02d'", k/60, k%60); } DrawColor(c); DrawText(string, x*unit+unit/2, (y+1)*unit-3*scalet, TRUE); } } } } } #ifdef BIORHYTHM /* Draw a graphic biorhythm chart on the screen, as is done when the -rb */ /* switch is combined with -X. This is technically a relationship chart in */ /* that biorhythm status is determined by a natal chart time at another */ /* later time. For the day in question, and for two weeks before and after, */ /* the Physical, Emotional, and Mental percentages are plotted. */ void XChartBiorhythm() { char string[6], *c; real jd, r, a; int x1, x2, xs, cx, y1, y2, ys, cy, i, j, k, x, y, x0, y0; k = FONTX*6*scalet; x1 = k; x2 = chartx-k; xs = x2-x1; cx = (x1+x2)/2; k = CELLSIZE; y1 = k; y2 = charty-k; ys = y2-y1; cy = (y1+y2)/2; /* Create a dotted day/percentage grid to graph on. */ DrawColor(gray); DrawDash(x1, cy, x2, cy, 1); DrawDash(cx, y1, cx, y2, 1); for (j = -BIODAYS+1; j <= BIODAYS-1; j++) { x = x1 + MULTDIV(xs, j+BIODAYS, BIODAYS*2); for (k = -90; k <= 90; k += 10) { y = y1 + MULTDIV(ys, 100+k, 200); DrawPoint(x, y); } } /* Now actually draw the three biorhythm curves. */ for (i = 1; i <= 3; i++) { jd = floor(JD + ROUND); switch (i) { case 1: r = _PHY; c = "PHYS"; DrawColor(elemcolor[_FIR]); break; case 2: r = _EMO; c = "EMOT"; DrawColor(elemcolor[_WAT]); break; case 3: r = _INT; c = "INTE"; DrawColor(elemcolor[_EAR]); break; } for (jd -= (real)BIODAYS, j = -BIODAYS; j <= BIODAYS; j++, jd += 1.0) { a = Biorhythm(jd, r); x = x1 + MULTDIV(xs, j+BIODAYS, BIODAYS*2); y = y1 + (int)((real)ys * (100.0-a) / 200.0); if (j > -BIODAYS) DrawLine(x0, y0, x, y); else DrawText(c, x1/2, y+2*scalet, FALSE); x0 = x; y0 = y; } } DrawColor(hilite); /* Label biorhythm percentages along right vertical axis. */ for (k = -100; k <= 100; k += 10) { sprintf(string, "%c%3d%%", k < 0 ? '-' : '+', abs(k)); y = y1 + MULTDIV(ys, 100-k, 200); DrawText(string, (x2+chartx)/2, y+2*scalet, FALSE); } /* Label days on top horizontal axis. */ for (j = -BIODAYS+2; j < BIODAYS; j += 2) { x = x1 + MULTDIV(xs, j+BIODAYS, BIODAYS*2); sprintf(string, "%c%d", j < 0 ? '-' : '+', abs(j)); DrawText(string, x, y1-2*scalet, TRUE); } DrawEdge(x1, y1, x2, y2); } #endif /* 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 XChart() { char string[STRING]; int i, j; DrawClearScreen(); switch (modex) { case MODEv: case MODEw: if (relation > DASHr0) XChartWheel(); else XChartWheelRelation(); break; case MODEL: DrawWorld(degree); /* First draw map of world. */ XChartAstroGraph(); /* Then draw astro-graph lines on it. */ break; case MODEg: if (relation > DASHr0) XChartGrid(); else XChartGridRelation(); break; case MODEZ: if (exdisplay & DASHZ0) XChartHorizonSky(); else XChartHorizon(); break; case MODES: XChartSpace(); break; case MODEE: XChartEphemeris(); break; case MODEW: DrawWorld(degree); /* First draw map of world. */ if (xbonus && (exdisplay & DASHXW0) == 0) /* Then maybe Ley lines. */ DrawLeyLines(degree); break; case MODEG: case MODEP: DrawGlobe(degree); break; #ifdef BIORHYTHM case MODEb: XChartBiorhythm(); break; #endif } /* Print text showing chart information at bottom of window. */ DrawColor(hilite); if (xtext && modex != MODEW && modex != MODEG && modex != MODEP && ((modex != MODEv && modex != MODEw) || (exdisplay & DASHv0) > 0)) { if (Mon == -1) sprintf(string, "(no time or space)"); else if (relation == DASHrc) sprintf(string, "(composite)"); else { i = (int) (FRACT(dabs(Tim))*100.0+ROUND/60.0); j = ansi; ansi = FALSE; sprintf(string, "%s %s (%s GMT) %s", CharDate(Mon, Day, Yea, 2), CharTime((int)floor(Tim), i), CharZone(Zon), CharLocation(Lon, Lat, 100.0)); ansi = j; } DrawText(string, chartx/2, charty-3*scalet, TRUE); } /* Draw a border around the chart if the mode is set and appropriate. */ if ((xborder || modex == MODEg) && modex != MODEG && modex != MODEP && (modex != MODEW || (exdisplay & DASHXW0) == 0)) DrawEdgeAll(); } #endif /* GRAPH */ /* xoptions.c */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.