home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume37 / astrolog / part06 < prev    next >
Encoding:
Text File  |  1993-05-18  |  54.9 KB  |  1,532 lines

  1. Newsgroups: comp.sources.misc
  2. From: astrolog@u.washington.edu (Astrolog)
  3. Subject: v37i075:  astrolog - Generation of astrology charts v3.05, Part06/12
  4. Message-ID: <1993May19.061845.12083@sparky.imd.sterling.com>
  5. X-Md4-Signature: 35ae020f82fd2cd902b829e41b0ead63
  6. Date: Wed, 19 May 1993 06:18:45 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: astrolog@u.washington.edu (Astrolog)
  10. Posting-number: Volume 37, Issue 75
  11. Archive-name: astrolog/part06
  12. Environment: UNIX, DOS, VMS
  13. Supersedes: astrolog: Volume 30, Issue 62-69
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 6 (of 12)."
  22. # Contents:  xcharts.c
  23. # Wrapped by pul@hardy on Sun May 16 22:23:17 1993
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'xcharts.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'xcharts.c'\"
  27. else
  28. echo shar: Extracting \"'xcharts.c'\" \(52928 characters\)
  29. sed "s/^X//" >'xcharts.c' <<'END_OF_FILE'
  30. X/*
  31. X** Astrolog (Version 3.05) File: xcharts.c
  32. X** Initially programmed 10/23-29/1991
  33. X**
  34. X** IMPORTANT: The planetary calculation routines used in this program
  35. X** have been Copyrighted and the core of this program is basically a
  36. X** conversion to C of the routines created by James Neely as listed in
  37. X** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  38. X** available from Matrix Software. The copyright gives us permission to
  39. X** use the routines for our own purposes but not to sell them or profit
  40. X** from them in any way.
  41. X**
  42. X** IMPORTANT: the graphics database and chart display routines used in
  43. X** this program are Copyright (C) 1991-1993 by Walter D. Pullen. Permission
  44. X** is granted to freely use and distribute these routines provided one
  45. X** doesn't sell, restrict, or profit from them in any way. Modification
  46. X** is allowed provided these notices remain with any altered or edited
  47. X** versions of the program.
  48. X*/
  49. X
  50. X#include "astrolog.h"
  51. X
  52. X#ifdef GRAPH
  53. X
  54. X/* Are particular coordinates on the chart? */
  55. X#define ISLEGAL(X, Y) \
  56. X  ((X) >= 0 && (X) < chartx && (Y) >= 0 && (Y) < chartx)
  57. X
  58. X/* draw a rectangle with thin sides. */
  59. X#define DrawEdge(X1, Y1, X2, Y2, O) \
  60. X  DrawBox(X1, Y1, X2, Y2, 1, 1, O)
  61. X
  62. X/* draw a border around the whole window. */
  63. X#define DrawBoxAll(XSIZ, YSIZ, O) \
  64. X  DrawBox(0, 0, chartx-1, charty-1, XSIZ, YSIZ, O)
  65. X
  66. Xreal symbol[TOTAL+1];
  67. Xcirclestruct PTR circ = NULL;
  68. X
  69. X
  70. X/*
  71. X*******************************************************************************
  72. X** Main subprograms
  73. X*******************************************************************************
  74. X*/
  75. X
  76. X/* Return whether the specified object should be displayed in the current  */
  77. X/* graphics chart type. For example, don't include the Moon in the solar   */
  78. X/* system charts, don't include house cusps in astro-graph, and so on.     */
  79. X
  80. Xint Proper(i)
  81. Xint i;
  82. X{
  83. X  int j;
  84. X
  85. X  if (modex == 'l')                            /* astro-graph charts */
  86. X    j = (i <= THINGS || i > C_HI);
  87. X  else if (modex == 'z' || modex == 'g')       /* horizon or zenith charts */
  88. X    j = (i < THINGS || i > C_HI);
  89. X  else if (modex == 's')                       /* solar system charts */
  90. X    j = (i != 2 && (i < THINGS || i > C_HI));
  91. X  else
  92. X    j = TRUE;
  93. X  return j && !ignore[i];                      /* check restriction status */
  94. X}
  95. X
  96. X
  97. X/* Adjust an array of zodiac positions so that no two positions are within   */
  98. X/* a certain orb of each other. This is used by the wheel drawing chart      */
  99. X/* routines in order to make sure that we don't draw any planet glyphs on    */
  100. X/* top of each other. We'll later draw the glyphs at the adjusted positions. */
  101. X
  102. Xvoid FillSymbolRing(symbol)
  103. Xreal *symbol;
  104. X{
  105. X  int i, j, k = 1, l, k1, k2;
  106. X  real orb = DEFORB*256.0/(real)charty*(real)SCALE, temp;
  107. X
  108. X  /* Keep adjusting as long as we can still make changes, or until we do 'n' */
  109. X  /* rounds. (With many objects, there just may not be enough room for all.) */
  110. X
  111. X  for (l = 0; k && l < divisions*4; l++) {
  112. X    k = 0;
  113. X    for (i = 1; i <= total; i++) if (Proper(i)) {
  114. X
  115. X      /* For each object, determine who is closest on either side. */
  116. X
  117. X      k1 = 1000; k2 = -1000;
  118. X      for (j = 1; j <= total; j++)
  119. X        if (Proper(j) && i != j) {
  120. X          temp = symbol[j]-symbol[i];
  121. X          if (dabs(temp) > 180.0)
  122. X            temp -= DEGREES*Sgn(temp);
  123. X          if (temp<k1 && temp>=0.0)
  124. X            k1 = temp;
  125. X          else if (temp>k2 && temp<=0.0)
  126. X            k2 = temp;
  127. X        }
  128. X
  129. X      /* If an object's too close on one side, then we move to the other. */
  130. X
  131. X      if (k2>-orb && k1>orb) {
  132. X        k = 1; symbol[i] = Mod(symbol[i]+orb*0.51+k2*0.49);
  133. X      } else if (k1<orb && k2<-orb) {
  134. X        k = 1; symbol[i] = Mod(symbol[i]-orb*0.51+k1*0.49);
  135. X
  136. X      /* If we are bracketed by close objects on both sides, then let's move */
  137. X      /* to the midpoint, so we are as far away as possible from either one. */
  138. X
  139. X      } else if (k2>-orb && k1<orb) {
  140. X        k = 1; symbol[i] = Mod(symbol[i]+(k1+k2)*0.5);
  141. X      }
  142. X    }
  143. X  }
  144. X}
  145. X
  146. X
  147. X/* Set up arrays with the sine and cosine values of each degree. This is   */
  148. X/* used by the wheel chart routines which draw lots of circles. Memory is  */
  149. X/* allocated for this array if not already done. The allocation and        */
  150. X/* initialization is only done once, the first time the routine is called. */
  151. X
  152. Xvoid InitCircle()
  153. X{
  154. X  int i;
  155. X
  156. X  if (circ != NULL)
  157. X    return;
  158. X  Allocate(circ, sizeof(circlestruct), circlestruct PTR);
  159. X  if (circ == NULL
  160. X#ifndef NOPC
  161. X    /* For PC's the array better not cross a segment boundary. */
  162. X    || HIWORD(LOWORD(circ) + sizeof(circlestruct)) > 0
  163. X#endif
  164. X    ) {
  165. X    fprintf(stderr, "%s: Out of memory for sine table.\n", appname);
  166. X    Terminate(1);
  167. X  }
  168. X  for (i = 0; i < 360; i++) {
  169. X    circ->x[i] = COSD((real) i);
  170. X    circ->y[i] = SIND((real) i);
  171. X  }
  172. X  circ->x[360] = circ->x[0]; circ->y[360] = circ->y[0];
  173. X}
  174. X
  175. X
  176. X/* Get a coordinate based on chart radius, a fraction, and (co)sin value. */
  177. X#define POINT(U, R, S) ((int) ((R)*(real)(U)*(S)+0.5))
  178. X
  179. X/* Determine (co)sin factor based on zodiac angle and chart orientation. */
  180. X#define PX(A) COSD(180.0-(A)+Asc)
  181. X#define PY(A) SIND(180.0-(A)+Asc)
  182. X
  183. X/* Draw a wheel chart, in which the 12 signs and houses are delineated, and  */
  184. X/* the planets are inserted in their proper places. This is the default      */
  185. X/* graphics chart to generate, as is done when the -v or -w (or no) switches */
  186. X/* are included with -X. Draw the aspects in the middle of chart, too.       */
  187. X
  188. Xvoid XChartWheel()
  189. X{
  190. X  int cx = chartx / 2, cy = charty / 2, unitx, unity, i, j, count = 0;
  191. X  real Asc, orb = DEFORB*256.0/(real)charty*(real)SCALE, temp;
  192. X
  193. X  DrawBoxAll(1, 1, hilite);
  194. X  unitx = cx; unity = cy;
  195. X  Asc = xeast ? planet[abs(xeast)]+90*(xeast < 0) : house[1];
  196. X  InitCircle();
  197. X
  198. X  /* Draw Ascendant/Descendant and Midheaven/Nadir lines across whole chart. */
  199. X
  200. X  DrawLine(cx+POINT(unitx, 0.99, PX(house[1])),
  201. X           cy+POINT(unity, 0.99, PY(house[1])),
  202. X           cx+POINT(unitx, 0.99, PX(house[7])),
  203. X           cy+POINT(unity, 0.99, PY(house[7])), hilite, !xcolor);
  204. X  DrawLine(cx+POINT(unitx, 0.99, PX(house[10])),
  205. X           cy+POINT(unity, 0.99, PY(house[10])),
  206. X           cx+POINT(unitx, 0.99, PX(house[4])),
  207. X           cy+POINT(unity, 0.99, PY(house[4])), hilite, !xcolor);
  208. X
  209. X  /* Draw small five or one degree increments around the zodiac sign ring. */
  210. X
  211. X  for (i = 0; i < 360; i += 5-xcolor*4) {
  212. X    temp = (real) i;
  213. X    DrawLine(cx+POINT(unitx, 0.80, PX(temp)), cy+POINT(unity, 0.80, PY(temp)),
  214. X      cx+POINT(unitx, 0.75, PX(temp)), cy+POINT(unity, 0.75, PY(temp)),
  215. X      i%5 ? gray : on, 0);
  216. X  }
  217. X
  218. X  /* Draw circles for the zodiac sign and house rings. */
  219. X
  220. X  for (i = 0; i < 360; i++) {
  221. X    DrawLine(cx+POINT(unitx, 0.95, circ->x[i]),
  222. X      cy+POINT(unity, 0.95, circ->y[i]), cx+POINT(unitx, 0.95, circ->x[i+1]),
  223. X      cy+POINT(unity, 0.95, circ->y[i+1]), on, 0);
  224. X    DrawLine(cx+POINT(unitx, 0.80, circ->x[i]),
  225. X      cy+POINT(unity, 0.80, circ->y[i]), cx+POINT(unitx, 0.80, circ->x[i+1]),
  226. X      cy+POINT(unity, 0.80, circ->y[i+1]), on, 0);
  227. X    DrawLine(cx+POINT(unitx, 0.75, circ->x[i]),
  228. X      cy+POINT(unity, 0.75, circ->y[i]), cx+POINT(unitx, 0.75, circ->x[i+1]),
  229. X      cy+POINT(unity, 0.75, circ->y[i+1]), on, 0);
  230. X    DrawLine(cx+POINT(unitx, 0.65, circ->x[i]),
  231. X      cy+POINT(unity, 0.65, circ->y[i]), cx+POINT(unitx, 0.65, circ->x[i+1]),
  232. X      cy+POINT(unity, 0.65, circ->y[i+1]), on, 0);
  233. X  }
  234. X
  235. X  /* Draw the glyphs for the signs and houses themselves. */
  236. X
  237. X  for (i = 1; i <= SIGNS; i++) {
  238. X    temp = (real) (i-1)*30.0;
  239. X    DrawLine(cx+POINT(unitx, 0.95, PX(temp)),       /* Draw lines separating */
  240. X      cy+POINT(unity, 0.95, PY(temp)),              /* each sign and house   */
  241. X      cx+POINT(unitx, 0.80, PX(temp)),              /* from each other.      */
  242. X      cy+POINT(unity, 0.80, PY(temp)), on, 0);
  243. X    DrawLine(cx+POINT(unitx, 0.75, PX(house[i])),
  244. X      cy+POINT(unity, 0.75, PY(house[i])),
  245. X      cx+POINT(unitx, 0.65, PX(house[i])),
  246. X      cy+POINT(unity, 0.65, PY(house[i])), on, 0);
  247. X    if (xcolor && i%3 != 1)                                    /* Lines from */
  248. X      DrawLine(cx, cy, cx+POINT(unitx, 0.65, PX(house[i])),    /* each house */
  249. X        cy+POINT(unity, 0.65, PY(house[i])), gray, 1);         /* to center. */
  250. X    temp += 15.0;
  251. X    DrawTurtle(signdraw[i], cx+POINT(unitx, 0.875, PX(temp)),
  252. X      cy+POINT(unity, 0.875, PY(temp)), elemcolor[(i-1)%4]);
  253. X    temp = Midpoint(house[i], house[Mod12(i+1)]);
  254. X    DrawTurtle(housedraw[i], cx+POINT(unitx, 0.70, PX(temp)),
  255. X      cy+POINT(unity, 0.70, PY(temp)), elemcolor[(i-1)%4]);
  256. X  }
  257. X  for (i = 1; i <= total; i++) {   /* Figure out where to put planet glyphs. */
  258. X    symbol[i] = planet[i];
  259. X  }
  260. X  FillSymbolRing(symbol);
  261. X
  262. X  /* For each planet, draw a small dot indicating where it is, and then */
  263. X  /* a line from that point to the planet's glyph.                      */
  264. X
  265. X  for (i = 1; i <= total; i++) if (Proper(i)) {
  266. X    temp = symbol[i];
  267. X    DrawLine(cx+POINT(unitx, 0.52, PX(planet[i])),
  268. X      cy+POINT(unity, 0.52, PY(planet[i])),
  269. X      cx+POINT(unitx, 0.56, PX(temp)),
  270. X      cy+POINT(unity, 0.56, PY(temp)),
  271. X      ret[i] < 0.0 ? gray : on, (ret[i] < 0.0 ? 1 : 0) - xcolor);
  272. X    DrawObject(i, cx+POINT(unitx, 0.60, PX(temp)),
  273. X      cy+POINT(unity, 0.60, PY(temp)));
  274. X    DrawPoint(cx+POINT(unitx, 0.50, PX(planet[i])),
  275. X      cy+POINT(unity, 0.50, PY(planet[i])), objectcolor[i]);
  276. X  }
  277. X  if (bonus)    /* Don't draw aspects in bonus mode. */
  278. X    return;
  279. X
  280. X  /* Draw lines connecting planets which have aspects between them. */
  281. X
  282. X  CreateGrid(FALSE);
  283. X  for (j = total; j >= 2; j--)
  284. X    for (i = j-1; i >= 1; i--)
  285. X      if (grid->n[i][j] && Proper(i) && Proper(j))
  286. X        DrawLine(cx+POINT(unitx, 0.48, PX(planet[i])),
  287. X          cy+POINT(unity, 0.48, PY(planet[i])),
  288. X          cx+POINT(unitx, 0.48, PX(planet[j])),
  289. X          cy+POINT(unity, 0.48, PY(planet[j])),
  290. X          aspectcolor[grid->n[i][j]], abs(grid->v[i][j]/60/2));
  291. X}
  292. X
  293. X
  294. X/* Draw another wheel chart; however, this time we have two rings of planets */
  295. X/* because we are doing a relationship chart between two sets of data. This  */
  296. X/* chart is obtained when the -r0 is combined with the -X switch.            */
  297. X
  298. Xvoid XChartWheelRelation()
  299. X{
  300. X  int cx = chartx / 2, cy = charty / 2, unitx, unity, i, j;
  301. X  real Asc, temp;
  302. X
  303. X  DrawBoxAll(1, 1, hilite);
  304. X  unitx = cx; unity = cy;
  305. X  Asc = xeast ? planet1[abs(xeast)]+90*(xeast < 0) : house1[1];
  306. X  InitCircle();
  307. X
  308. X  /* Draw the horizon and meridian lines across whole chart, and draw the */
  309. X  /* zodiac and house rings, exactly like before. We are drawing only the */
  310. X  /* houses of one of the two charts in the relationship, however.        */
  311. X
  312. X  DrawLine(cx+POINT(unitx, 0.99, PX(house1[1])),
  313. X           cy+POINT(unity, 0.99, PY(house1[1])),
  314. X           cx+POINT(unitx, 0.99, PX(house1[7])),
  315. X           cy+POINT(unity, 0.99, PY(house1[7])), hilite, !xcolor);
  316. X  DrawLine(cx+POINT(unitx, 0.99, PX(house1[10])),
  317. X           cy+POINT(unity, 0.99, PY(house1[10])),
  318. X           cx+POINT(unitx, 0.99, PX(house1[4])),
  319. X           cy+POINT(unity, 0.99, PY(house1[4])), hilite, !xcolor);
  320. X  for (i = 0; i < 360; i += 5-xcolor*4) {
  321. X    temp = (real) i;
  322. X    DrawLine(cx+POINT(unitx, 0.82, PX(temp)), cy+POINT(unity, 0.82, PY(temp)),
  323. X      cx+POINT(unitx, 0.78, PX(temp)), cy+POINT(unity, 0.78, PY(temp)),
  324. X      i%5 ? gray : on, 0);
  325. X  }
  326. X  for (i = 0; i < 360; i++) {
  327. X    DrawLine(cx+POINT(unitx, 0.95, circ->x[i]),
  328. X      cy+POINT(unity, 0.95, circ->y[i]), cx+POINT(unitx, 0.95, circ->x[i+1]),
  329. X      cy+POINT(unity, 0.95, circ->y[i+1]), on, 0);
  330. X    DrawLine(cx+POINT(unitx, 0.82, circ->x[i]),
  331. X      cy+POINT(unity, 0.82, circ->y[i]), cx+POINT(unitx, 0.82, circ->x[i+1]),
  332. X      cy+POINT(unity, 0.82, circ->y[i+1]), on, 0);
  333. X    DrawLine(cx+POINT(unitx, 0.78, circ->x[i]),
  334. X      cy+POINT(unity, 0.78, circ->y[i]), cx+POINT(unitx, 0.78, circ->x[i+1]),
  335. X      cy+POINT(unity, 0.78, circ->y[i+1]), on, 0);
  336. X    DrawLine(cx+POINT(unitx, 0.70, circ->x[i]),
  337. X      cy+POINT(unity, 0.70, circ->y[i]), cx+POINT(unitx, 0.70, circ->x[i+1]),
  338. X      cy+POINT(unity, 0.70, circ->y[i+1]), on, 0);
  339. X  }
  340. X  for (i = 1; i <= SIGNS; i++) {
  341. X    temp = (real) (i-1)*30.0;
  342. X    DrawLine(cx+POINT(unitx, 0.95, PX(temp)),
  343. X      cy+POINT(unity, 0.95, PY(temp)),
  344. X      cx+POINT(unitx, 0.82, PX(temp)),
  345. X      cy+POINT(unity, 0.82, PY(temp)), on, 0);
  346. X    DrawLine(cx+POINT(unitx, 0.78, PX(house1[i])),
  347. X      cy+POINT(unity, 0.78, PY(house1[i])),
  348. X      cx+POINT(unitx, 0.70, PX(house1[i])),
  349. X      cy+POINT(unity, 0.70, PY(house1[i])), on, 0);
  350. X    if (xcolor && i%3 != 1)
  351. X      DrawLine(cx, cy, cx+POINT(unitx, 0.70, PX(house1[i])),
  352. X        cy+POINT(unity, 0.70, PY(house1[i])), gray, 1);
  353. X    temp += 15.0;
  354. X    DrawTurtle(signdraw[i], cx+POINT(unitx, 0.885, PX(temp)),
  355. X      cy+POINT(unity, 0.885, PY(temp)), elemcolor[(i-1)%4]);
  356. X    temp = Midpoint(house1[i], house1[Mod12(i+1)]);
  357. X    DrawTurtle(housedraw[i], cx+POINT(unitx, 0.74, PX(temp)),
  358. X      cy+POINT(unity, 0.74, PY(temp)), elemcolor[(i-1)%4]);
  359. X  }
  360. X
  361. X  /* Draw the outer ring of planets (based on the planets in the chart     */
  362. X  /* which the houses do not reflect - the houses belong to the inner ring */
  363. X  /* below). Draw each glyph, a line from it to its actual position point  */
  364. X  /* in the outer ring, and then draw another line from this point to a    */
  365. X  /* another dot at the same position in the inner ring as well.           */
  366. X
  367. X  for (i = 1; i <= total; i++) {
  368. X    symbol[i] = planet2[i];
  369. X  }
  370. X  FillSymbolRing(symbol);
  371. X  for (i = 1; i <= total; i++) if (Proper(i)) {
  372. X    temp = symbol[i];
  373. X    DrawLine(cx+POINT(unitx, 0.58, PX(planet2[i])),
  374. X      cy+POINT(unity, 0.58, PY(planet2[i])),
  375. X      cx+POINT(unitx, 0.61, PX(temp)),
  376. X      cy+POINT(unity, 0.61, PY(temp)),
  377. X      ret2[i] < 0.0 ? gray : on, (ret2[i] < 0.0 ? 1 : 0) - xcolor);
  378. X    DrawObject(i, cx+POINT(unitx, 0.65, PX(temp)),
  379. X      cy+POINT(unity, 0.65, PY(temp)));
  380. X    DrawPoint(cx+POINT(unitx, 0.56, PX(planet2[i])),
  381. X      cy+POINT(unity, 0.56, PY(planet2[i])), objectcolor[i]);
  382. X    DrawPoint(cx+POINT(unitx, 0.43, PX(planet2[i])),
  383. X      cy+POINT(unity, 0.43, PY(planet2[i])), objectcolor[i]);
  384. X    DrawLine(cx+POINT(unitx, 0.45, PX(planet2[i])),
  385. X      cy+POINT(unity, 0.45, PY(planet2[i])),
  386. X      cx+POINT(unitx, 0.54, PX(planet2[i])),
  387. X      cy+POINT(unity, 0.54, PY(planet2[i])),
  388. X      ret2[i] < 0.0 ? gray : on, 2-xcolor);
  389. X  }
  390. X
  391. X  /* Now draw the inner ring of planets. If it weren't for the outer ring,  */
  392. X  /* this would be just like the standard non-relationship wheel chart with */
  393. X  /* only one set of planets. Again, draw glyph, and a line to true point.  */
  394. X
  395. X  for (i = 1; i <= total; i++) {
  396. X    symbol[i] = planet1[i];
  397. X  }
  398. X  FillSymbolRing(symbol);
  399. X  for (i = 1; i <= total; i++) if (Proper(i)) {
  400. X    temp = symbol[i];
  401. X    DrawLine(cx+POINT(unitx, 0.45, PX(planet1[i])),
  402. X      cy+POINT(unity, 0.45, PY(planet1[i])),
  403. X      cx+POINT(unitx, 0.48, PX(temp)),
  404. X      cy+POINT(unity, 0.48, PY(temp)),
  405. X      ret1[i] < 0.0 ? gray : on, (ret1[i] < 0.0 ? 1 : 0) - xcolor);
  406. X    DrawObject(i, cx+POINT(unitx, 0.52, PX(temp)),
  407. X      cy+POINT(unity, 0.52, PY(temp)));
  408. X    DrawPoint(cx+POINT(unitx, 0.43, PX(planet1[i])),
  409. X      cy+POINT(unity, 0.43, PY(planet1[i])), objectcolor[i]);
  410. X  }
  411. X  if (bonus)    /* Don't draw aspects in bonus mode. */
  412. X    return;
  413. X
  414. X  /* Draw lines connecting planets between the two charts that have aspects. */
  415. X
  416. X  CreateGridRelation(FALSE);
  417. X  for (j = total; j >= 1; j--)
  418. X    for (i = total; i >= 1; i--)
  419. X      if (grid->n[i][j] && Proper(i) && Proper(j))
  420. X        DrawLine(cx+POINT(unitx, 0.41, PX(planet1[j])),
  421. X          cy+POINT(unity, 0.41, PY(planet1[j])),
  422. X          cx+POINT(unitx, 0.41, PX(planet2[i])),
  423. X          cy+POINT(unity, 0.41, PY(planet2[i])),
  424. X          aspectcolor[grid->n[i][j]], abs(grid->v[i][j]/60/2));
  425. X}
  426. X
  427. X
  428. X/* Given longitude and latitude values on a globe, return the window        */
  429. X/* coordinates corresponding to them. In other words, project the globe     */
  430. X/* onto the view plane, and return where our coordinates got projected to,  */
  431. X/* as well as whether our location is hidden on the back side of the globe. */
  432. X
  433. Xint GlobeCalc(x1, y1, u, v, cx, cy, rx, ry, deg)
  434. Xreal x1, y1;
  435. Xint *u, *v, cx, cy, rx, ry, deg;
  436. X{
  437. X  real j;
  438. X
  439. X  /* Compute coordinates for a general globe invoked with -XG switch. */
  440. X
  441. X  if (modex == 'g') {
  442. X    x1 = Mod(x1+(real)deg);    /* Shift by current globe rotation value. */
  443. X    if (tilt != 0.0) {
  444. X      x1 = DTOR(x1); y1 = DTOR(90.0-y1);         /* Do another coordinate  */
  445. X      CoorXform(&x1, &y1, tilt / DEGTORAD);      /* shift if the globe's   */
  446. X      x1 = Mod(RTOD(x1)); y1 = 90.0-RTOD(y1);    /* equator is tilted any. */
  447. X    }
  448. X    *v = cy + (int) ((real)(ry+1)*-COSD(y1));
  449. X    *u = cx + (int) ((real)(rx+1)*-COSD(x1)*SIND(y1));
  450. X    return x1 > 180.0;
  451. X  }
  452. X
  453. X  /* Compute coordinates for a polar globe invoked with -XP switch. */
  454. X
  455. X  j = bonus ? 90.0+x1+deg : 270.0-x1-deg;
  456. X  *v = cy + (int) (SIND(y1)*(real)(ry+1)*SIND(j));
  457. X  *u = cx + (int) (SIND(y1)*(real)(rx+1)*COSD(j));
  458. X  return bonus ? y1 < 90.0 : y1 > 90.0;
  459. X}
  460. X
  461. X
  462. X/* Draw a globe in the window, based on the specified rotational and tilt  */
  463. X/* values. In addition, we may draw in each planet at its zenith position. */
  464. X
  465. Xvoid DrawGlobe(deg)
  466. Xint deg;
  467. X{
  468. X  char *nam, *loc, *lin, d;
  469. X  int X[TOTAL+1], Y[TOTAL+1], M[TOTAL+1], N[TOTAL+1],
  470. X    cx = chartx / 2, cy = charty / 2, rx, ry, lon, lat, unit = 12*SCALE,
  471. X    x, y, m, n, u, v, i, J, k, l;
  472. X  real planet1[TOTAL+1], planet2[TOTAL+1], x1, y1, j;
  473. X  color c;
  474. X
  475. X  rx = cx-1; ry = cy-1;
  476. X
  477. X  /* Loop through each coastline string, drawing visible parts on the globe. */
  478. X
  479. X  while (ReadWorldData(&nam, &loc, &lin)) {
  480. X    i = nam[0]-'0';
  481. X    c = (modex == 'g' && bonus) ? gray : (i ? rainbowcolor[i] : maincolor[6]);
  482. X
  483. X    /* Get starting longitude and latitude of current coastline piece. */
  484. X
  485. X    lon = (loc[0] == '+' ? 1 : -1)*
  486. X      ((loc[1]-'0')*100 + (loc[2]-'0')*10 + (loc[3]-'0'));
  487. X    lat = (loc[4] == '+' ? 1 : -1)*((loc[5]-'0')*10 + (loc[6]-'0'));
  488. X    x = 180-lon;
  489. X    y = 90-lat;
  490. X    GlobeCalc((real) x, (real) y, &m, &n, cx, cy, rx, ry, deg);
  491. X
  492. X    /* Go down the coastline piece, drawing each visible segment on globe. */
  493. X
  494. X    for (i = 0; d = lin[i]; i++) {
  495. X      if (d == 'L' || d == 'H' || d == 'G')
  496. X        x--;
  497. X      else if (d == 'R' || d == 'E' || d == 'F')
  498. X        x++;
  499. X      if (d == 'U' || d == 'H' || d == 'E')
  500. X        y--;
  501. X      else if (d == 'D' || d == 'G' || d == 'F')
  502. X        y++;
  503. X      if (x > 359)
  504. X        x = 0;
  505. X      else if (x < 0)
  506. X        x = 359;
  507. X      if (!GlobeCalc((real) x, (real) y, &u, &v, cx, cy, rx, ry, deg))
  508. X        DrawLine(m, n, u, v, c, 0);
  509. X      m = u; n = v;
  510. X    }
  511. X  }
  512. X
  513. X  /* Finally, draw the circular outline of the globe itself. */
  514. X
  515. X  m = cx+rx+1; n = cy;
  516. X  for (i = 0; i <= 360; i++) {
  517. X    u = cx+(rx+1)*COSD((real)i); v = cy+(ry+1)*SIND((real)i);
  518. X    u = MIN(u, cx+rx); v = MIN(v, cy+ry);
  519. X    DrawLine(m, n, u, v, on, 0); m = u; n = v;
  520. X  }
  521. X
  522. X  /* Now, only if we are in bonus chart mode, draw each planet at its */
  523. X  /* zenith location on the globe, assuming that location is visible. */
  524. X
  525. X  if (modex != 'g' || !bonus)
  526. X    return;
  527. X  j = Lon;
  528. X  if (j < 0.0)
  529. X    j += DEGREES;
  530. X  for (i = 1; i <= total; i++) {
  531. X    planet1[i] = DTOR(planet[i]);
  532. X    planet2[i] = DTOR(planetalt[i]);
  533. X    ecltoequ(&planet1[i], &planet2[i]);    /* Calculate zenith long. & lat. */
  534. X  }
  535. X  for (i = 1; i <= total; i++) if (Proper(i)) {
  536. X    x1 = planet1[18]-planet1[i];
  537. X    if (x1 < 0.0)
  538. X      x1 += 2.0*PI;
  539. X    if (x1 > PI)
  540. X      x1 -= 2.0*PI;
  541. X    x1 = Mod(180.0-j-RTOD(x1));
  542. X    y1 = 90.0-RTOD(planet2[i]);
  543. X    X[i] = GlobeCalc(x1, y1, &u, &v, cx, cy, rx, ry, deg) ? -1000 : u;
  544. X    Y[i] = v; M[i] = X[i]; N[i] = Y[i]+unit/2;
  545. X  }
  546. X
  547. X  /* Now that we have the coordinates of each object, figure out where to    */
  548. X  /* draw the glyphs. Again, we try not to draw glyphs on top of each other. */
  549. X
  550. X  for (i = 1; i <= total; i++) if (Proper(i)) {
  551. X    k = l = chartx+charty;
  552. X
  553. X    /* For each planet, we draw the glyph either right over or right under */
  554. X    /* the actual zenith location point. So, find out the closest distance */
  555. X    /* of any other planet assuming we place ours at both possibilities.   */
  556. X
  557. X    for (J = 1; J < i; J++) if (Proper(J)) {
  558. X      k = MIN(k, abs(M[i]-M[J])+abs(N[i]-N[J]));
  559. X      l = MIN(l, abs(M[i]-M[J])+abs(N[i]-unit-N[J]));
  560. X    }
  561. X
  562. X    /* Normally, we put the glyph right below the actual point. If however   */
  563. X    /* another planet is close enough to have their glyphs overlap, and the  */
  564. X    /* above location is better of, then we'll draw the glyph above instead. */
  565. X
  566. X    if (k < unit || l < unit)
  567. X      if (k < l)
  568. X        N[i] -= unit;
  569. X  }
  570. X  for (i = total; i >= 1; i--) if (X[i] >= 0 && Proper(i))      /* Draw the */
  571. X    DrawObject(i, M[i], N[i]);                                  /* glyphs.  */
  572. X  for (i = total; i >= 1; i--) if (X[i] >= 0 && Proper(i)) {
  573. X#ifdef WIN
  574. X    if (!xbitmap)
  575. X      Xcolor(objectcolor[i]);
  576. X#endif
  577. X    DrawSpot(X[i], Y[i], objectcolor[i]);
  578. X  }
  579. X}
  580. X
  581. X
  582. X/* Draw one "Ley line" on the world map, based coordinates given in terms of */
  583. X/* longitude and vertical fractional distance from the center of the earth.  */
  584. X
  585. Xvoid DrawLeyLine(l1, f1, l2, f2, o)
  586. Xreal l1, f1, l2, f2;
  587. Xbit o;
  588. X{
  589. X  l1 = Mod(l1); l2 = Mod(l2);
  590. X
  591. X  /* Convert vertical fractional distance to a corresponding coordinate. */
  592. X
  593. X  f1 = 90.0-ASIN(f1)/(PI/2.0)*90.0; f2 = 90.0-ASIN(f2)/(PI/2.0)*90.0;
  594. X  DrawWrap((int) (l1*(real)SCALE+0.5)+1,
  595. X           (int) (f1*(real)SCALE+0.5)+1,
  596. X           (int) (l2*(real)SCALE+0.5)+1,
  597. X           (int) (f2*(real)SCALE+0.5)+1, o);
  598. X}
  599. X
  600. X
  601. X/* Draw the main set of planetary Ley lines on the map of the world. This */
  602. X/* consists of drawing an icosahedron and then a dodecahedron lattice.    */
  603. X
  604. Xvoid DrawLeyLines(deg)
  605. Xint deg;
  606. X{
  607. X  color icosa, dodeca;
  608. X  real off = (real) deg, phi, h, h1, h2, r, i;
  609. X
  610. X  icosa = aspectcolor[10]; dodeca = aspectcolor[13];
  611. X  phi = (sqrt(5.0)+1.0)/2.0;                     /* Icosahedron constants. */
  612. X  h = 1.0/(phi*2.0-1.0);
  613. X  for (i = off; i < DEGREES+off; i += 72.0) {    /* Draw icosahedron edges. */
  614. X    DrawLeyLine(i, h, i+72.0, h, icosa);
  615. X    DrawLeyLine(i-36.0, -h, i+36.0, -h, icosa);
  616. X    DrawLeyLine(i, h, i, 1.0, icosa);
  617. X    DrawLeyLine(i+36.0, -h, i+36.0, -1.0, icosa);
  618. X    DrawLeyLine(i, h, i+36.0, -h, icosa);
  619. X    DrawLeyLine(i, h, i-36.0, -h, icosa);
  620. X  }
  621. X  r = 1.0/sqrt(3.0)/phi/cos(DTOR(54.0));         /* Dodecahedron constants. */
  622. X  h2 = sqrt(1.0-r*r); h1 = h2/(phi*2.0+1.0);
  623. X  for (i = off; i < DEGREES+off; i += 72.0) {    /* Draw docecahedron edges. */
  624. X    DrawLeyLine(i-36.0, h2, i+36.0, h2, dodeca);
  625. X    DrawLeyLine(i, -h2, i+72.0, -h2, dodeca);
  626. X    DrawLeyLine(i+36.0, h2, i+36.0, h1, dodeca);
  627. X    DrawLeyLine(i, -h2, i, -h1, dodeca);
  628. X    DrawLeyLine(i+36.0, h1, i+72.0, -h1, dodeca);
  629. X    DrawLeyLine(i+36.0, h1, i, -h1, dodeca);
  630. X  }
  631. X}
  632. X
  633. X
  634. X/* Draw a map of the world on the screen. This is similar to drawing the  */
  635. X/* globe, but is simplified because this is just a rectangular image, and */
  636. X/* the window coordinates are proportional to the longitude and latitude. */
  637. X
  638. Xvoid DrawWorld(deg)
  639. Xint deg;
  640. X{
  641. X  char *nam, *loc, *lin, d;
  642. X  int lon, lat, x, y, xold, yold, i;
  643. X  color c;
  644. X
  645. X  /* Loop through each coastline string, drawing it on the world map. */
  646. X
  647. X  while (ReadWorldData(&nam, &loc, &lin)) {
  648. X    i = nam[0]-'0';
  649. X    c = modex == 'l' ? on : (i ? rainbowcolor[i] : maincolor[6]);
  650. X
  651. X    /* Get starting longitude and latitude of current coastline piece. */
  652. X
  653. X    lon = (loc[0] == '+' ? 1 : -1)*
  654. X      ((loc[1]-'0')*100 + (loc[2]-'0')*10 + (loc[3]-'0'));
  655. X    lat = (loc[4] == '+' ? 1 : -1)*((loc[5]-'0')*10 + (loc[6]-'0'));
  656. X    xold = x = (int) Mod((real)(180-lon+deg));
  657. X    yold = y = 91-lat;
  658. X
  659. X    /* Go down the coastline piece, drawing each segment on world map. */
  660. X
  661. X    for (i = 0; d = lin[i]; i++) {
  662. X      if (d == 'L' || d == 'H' || d == 'G')
  663. X        x--;
  664. X      else if (d == 'R' || d == 'E' || d == 'F')
  665. X        x++;
  666. X      if (d == 'U' || d == 'H' || d == 'E')
  667. X        y--;
  668. X      else if (d == 'D' || d == 'G' || d == 'F')
  669. X        y++;
  670. X      if (x > 360) {
  671. X        x = 1;
  672. X        xold = 0;
  673. X      }
  674. X
  675. X      /* If we are doing a Mollewide map projection, then transform the */
  676. X      /* coordinates appropriately before drawing the segment.          */
  677. X
  678. X      if ((exdisplay & DASHXW0) > 0 && modex != 'l')
  679. X        DrawLine((180+(xold-180)*(int)sqrt((real)(32400-4*(yold-91)*(yold-91)
  680. X                 ))/180)*SCALE, yold*SCALE,
  681. X                 (180+(x-180)*(int)sqrt((real)(32400-4*(y-91)*(y-91)))/180)*
  682. X                 SCALE, y*SCALE, c, 0);
  683. X      else
  684. X        DrawLine(xold*SCALE, yold*SCALE, x*SCALE, y*SCALE, c, 0);
  685. X      if (x < 1)
  686. X        x = 360;
  687. X      xold = x; yold = y;
  688. X    }
  689. X  }
  690. X
  691. X  /* Again, if we are doing the non-rectangular Mollewide map projection, */
  692. X  /* draw the outline of the globe/map itself.                            */
  693. X
  694. X  if ((exdisplay & DASHXW0) > 0 && modex != 'l') {
  695. X    if (!bonus)
  696. X      for (xold = 0, y = -89; y <= 90; y++, xold = x)
  697. X        for (x = (int)(sqrt((real)(32400-4*y*y))+0.5), i = -1; i < 2; i += 2)
  698. X          DrawLine((180+i*xold)*SCALE, (90+y)*SCALE,
  699. X            (180+i*x)*SCALE, (91+y)*SCALE, on, 0);
  700. X  } else
  701. X    DrawBoxAll(1, 1, hilite);
  702. X}
  703. X
  704. X
  705. X/* Adjust an array of longitude positions so that no two are within a    */
  706. X/* certain orb of each other. This is used by the astro-graph routine to */
  707. X/* make sure we don't draw any planet glyphs marking the lines on top of */
  708. X/* each other. This is almost identical to the FillSymbolRing() routine  */
  709. X/* used by the wheel charts; however, there the glyphs are placed in a   */
  710. X/* continuous ring, while here we have the left and right screen edges.  */
  711. X/* Also, here we are placing two sets of planets at the same time.       */
  712. X
  713. Xvoid FillSymbolLine(symbol)
  714. Xreal *symbol;
  715. X{
  716. X  real orb = DEFORB*1.35*(real)SCALE, max = DEGREES*(real)SCALE, temp;
  717. X  int i, j, k = 1, l, k1, k2;
  718. X
  719. X  /* Keep adjusting as long as we can still make changes. */
  720. X
  721. X  for (l = 0; k && l < divisions*4; l++) {
  722. X    k = 0;
  723. X    for (i = 1; i <= TOTAL*2; i++)
  724. X      if (Proper((i+1)/2) && symbol[i] >= 0.0) {
  725. X
  726. X        /* For each object, determine who is closest to the left and right. */
  727. X
  728. X        k1 = max-symbol[i]; k2 = -symbol[i];
  729. X        for (j = 1; j <= THINGS*2; j++) {
  730. X          if (Proper((j+1)/2) && i != j) {
  731. X            temp = symbol[j]-symbol[i];
  732. X            if (temp<k1 && temp>=0.0)
  733. X              k1 = temp;
  734. X            else if (temp>k2 && temp<=0.0)
  735. X              k2 = temp;
  736. X          }
  737. X        }
  738. X
  739. X        /* If an object's too close on one side, then we move to the other. */
  740. X
  741. X        if (k2>-orb && k1>orb) {
  742. X          k = 1; symbol[i] = symbol[i]+orb*0.51+k2*0.49;
  743. X        } else if (k1<orb && k2<-orb) {
  744. X          k = 1; symbol[i] = symbol[i]-orb*0.51+k1*0.49;
  745. X        } else if (k2>-orb && k1<orb) {
  746. X          k = 1; symbol[i] = symbol[i]+(k1+k2)*0.5;
  747. X        }
  748. X      }
  749. X  }
  750. X}
  751. X
  752. X
  753. X/* Draw an astro-graph chart on a map of the world, i.e. the draw the     */
  754. X/* Ascendant, Descendant, Midheaven, and Nadir lines corresponding to the */
  755. X/* time in the chart. This chart is done when the -L switch is combined   */
  756. X/* with the -X switch.                                                    */
  757. X
  758. Xvoid XChartAstroGraph()
  759. X{
  760. X  real planet1[TOTAL+1], planet2[TOTAL+1],
  761. X    end1[TOTAL*2+1], end2[TOTAL*2+1],
  762. X    symbol1[TOTAL*2+1], symbol2[TOTAL*2+1],
  763. X    lon = Lon, longm, x, y, z, ad, oa, am, od, dm, lat;
  764. X  int unit = SCALE, lat1 = -60, lat2 = 75, y1, y2, xold1, xold2, i, j, k;
  765. X
  766. X  /* Erase top and bottom parts of map. We don't draw the astro-graph lines */
  767. X  /* above certain latitudes, and this gives us room for glyph labels, too. */
  768. X
  769. X  y1 = (91-lat1)*SCALE;
  770. X  y2 = (91-lat2)*SCALE;
  771. X  DrawBlock(1, 1, chartx-2, y2-1, off);
  772. X  DrawBlock(1, charty-2, chartx-2, y1+1, off);
  773. X  DrawLine(0, charty/2, chartx-2, charty/2, hilite, 4);    /* Draw equator. */
  774. X  DrawLine(1, y2, chartx-2, y2, on, 0);
  775. X  DrawLine(1, y1, chartx-2, y1, on, 0);
  776. X  for (i = 1; i <= total*2; i++)
  777. X    end1[i] = end2[i] = -1000.0;
  778. X
  779. X  /* Draw small hatches every 5 degrees along edges of world map. */
  780. X
  781. X  for (i = lat1; i <= lat2; i += 5) {
  782. X    j = (91-i)*SCALE;
  783. X    k = 2+(i%10 == 0)+2*(i%30 == 0);
  784. X    DrawLine(1, j, k, j, hilite, 0);
  785. X    DrawLine(chartx-2, j, chartx-1-k, j, hilite, 0);
  786. X  }
  787. X  for (i = -180; i < 180; i += 5) {
  788. X    j = (180-i)*SCALE;
  789. X    k = 2+(i%10 == 0)+2*(i%30 == 0)+(i%90 == 0);
  790. X    DrawLine(j, y2+1, j, y2+k, hilite, 0);
  791. X    DrawLine(j, y1-1, j, y1-k, hilite, 0);
  792. X  }
  793. X
  794. X  /* Calculate zenith locations of each planet. */
  795. X
  796. X  for (i = 1; i <= total; i++) {
  797. X    planet1[i] = DTOR(planet[i]);
  798. X    planet2[i] = DTOR(planetalt[i]);
  799. X    ecltoequ(&planet1[i], &planet2[i]);
  800. X  }
  801. X
  802. X  /* Draw the Midheaven lines and zenith location markings. */
  803. X
  804. X  if (lon < 0.0)
  805. X    lon += DEGREES;
  806. X  for (i = 1; i <= total; i++) if (Proper(i)) {
  807. X    x = DTOR(MC)-planet1[i];
  808. X    if (x < 0.0)
  809. X      x += 2.0*PI;
  810. X    if (x > PI)
  811. X      x -= 2.0*PI;
  812. X    z = lon+RTOD(x);
  813. X    if (z > 180.0)
  814. X      z -= DEGREES;
  815. X    j = (int) (Mod(180.0-z+degree)*(real)SCALE);
  816. X    DrawLine(j, y1+unit*4, j, y2-unit*1, elemcolor[1], 0);
  817. X    end2[i*2-1] = (real) j;
  818. X    y = RTOD(planet2[i]);
  819. X    k = (int) ((91.0-y)*(real)SCALE);
  820. X    DrawBlock(j-1, k-1, j+1, k+1, hilite);
  821. X    DrawBlock(j, k, j, k, off);
  822. X
  823. X    /* Draw Nadir lines assuming we aren't in bonus chart mode. */
  824. X
  825. X    if (!bonus) {
  826. X      j += 180*SCALE;
  827. X      if (j > chartx-2)
  828. X        j -= (chartx-2);
  829. X      end1[i*2-1] = (real) j;
  830. X      DrawLine(j, y1+unit*2, j, y2-unit*2, elemcolor[3], 0);
  831. X    }
  832. X  }
  833. X
  834. X  /* Now, normally, unless we are in bonus chart mode, we will go on to draw */
  835. X  /* the Ascendant and Descendant lines here.                                */
  836. X
  837. X  longm = DTOR(Mod(MC+lon));
  838. X  if (!bonus) for (i = 1; i <= total; i++) if (Proper(i)) {
  839. X    xold1 = xold2 = -1000;
  840. X    for (lat = (real) lat1; lat <= (real) lat2;
  841. X      lat += 1.0/(real)SCALE) {
  842. X
  843. X      /* First compute and draw the current segment of Ascendant line. */
  844. X
  845. X      j = (int) ((91.0-lat)*(real)SCALE);
  846. X      ad = tan(planet2[i])*tan(DTOR(lat));
  847. X      if (ad*ad > 1.0)
  848. X        ad = 1000.0;
  849. X      else {
  850. X        ad = ASIN(ad);
  851. X        oa = planet1[i]-ad;
  852. X        if (oa < 0.0)
  853. X          oa += 2.0*PI;
  854. X        am = oa-PI/2.0;
  855. X        if (am < 0.0)
  856. X          am += 2.0*PI;
  857. X        z = longm-am;
  858. X        if (z < 0.0)
  859. X          z += 2.0*PI;
  860. X        if (z > PI)
  861. X          z -= 2.0*PI;
  862. X        z = RTOD(z);
  863. X        k = (int) (Mod(180.0-z+degree)*(real)SCALE);
  864. X        DrawWrap(xold1, j+1, k, j, elemcolor[0]);
  865. X        if (lat == (real) lat1) {                            /* Line segment */
  866. X          DrawLine(k, y1, k, y1+unit*4, elemcolor[0], 0);    /* pointing to  */
  867. X          end2[i*2] = (real) k;                              /* Ascendant.   */
  868. X        }
  869. X        xold1 = k;
  870. X      }
  871. X
  872. X      /* The curving Ascendant and Descendant lines actually touch each at  */
  873. X      /* low latitudes. Sometimes when we start out, a particular planet's  */
  874. X      /* lines haven't appeared yet, i.e. we are scanning at a latitude     */
  875. X      /* where our planet's lines don't exist. If this is the case, then    */
  876. X      /* when they finally do start, draw a thin horizontal line connecting */
  877. X      /* the Ascendant and Descendant lines so they don't just start in     */
  878. X      /* space. Note that these connected lines aren't labeled with glyphs. */
  879. X
  880. X      if (ad == 1000.0) {
  881. X        if (xold1 >= 0) {
  882. X          DrawWrap(xold1, j+1, xold2, j+1, gray);
  883. X          lat = 90.0;
  884. X        }
  885. X      } else {
  886. X
  887. X      /* Then compute and draw corresponding segment of Descendant line. */
  888. X
  889. X        od = planet1[i]+ad;
  890. X        dm = od+PI/2.0;
  891. X        z = longm-dm;
  892. X        if (z < 0.0)
  893. X          z += 2.0*PI;
  894. X        if (z > PI)
  895. X          z -= 2.0*PI;
  896. X        z = RTOD(z);
  897. X        k = (int) (Mod(180.0-z+degree)*(real)SCALE);
  898. X        DrawWrap(xold2, j+1, k, j, elemcolor[2]);
  899. X        if (xold2 < 0)
  900. X          DrawWrap(xold1, j, k, j, gray);
  901. X        if (lat == (real) lat1)                              /* Line segment */
  902. X          DrawLine(k, y1, k, y1+unit*2, elemcolor[2], 0);    /* pointing to  */
  903. X        xold2 = k;                                           /* Descendant.  */
  904. X      }
  905. X    }
  906. X
  907. X    /* Draw segments pointing to top of Ascendant and Descendant lines. */
  908. X
  909. X    if (ad != 1000.0) {
  910. X      DrawLine(xold1, y2, xold1, y2-unit*1, elemcolor[0], 0);
  911. X      DrawLine(k, y2, k, y2-unit*2, elemcolor[2], 0);
  912. X      end1[i*2] = (real) k;
  913. X    }
  914. X  }
  915. X#ifdef WIN
  916. X  if (!xbitmap)
  917. X    Xcolor(maincolor[5]);
  918. X#endif
  919. X  DrawPoint((int)((180.0-Lon)*(real)SCALE), (int)((91-Lat)*(real)SCALE), on);
  920. X#ifdef WIN
  921. X  if (!xbitmap)
  922. X    Xcolor(on);
  923. X#endif
  924. X
  925. X  /* Determine where to draw the planet glyphs. We have four sets of each    */
  926. X  /* planet - each planet's glyph appearing in the chart up to four times -  */
  927. X  /* one for each type of line. The Midheaven and Ascendant lines are always */
  928. X  /* labeled at the bottom of the chart, while the Nadir and Midheaven lines */
  929. X  /* at the top. Therefore we need to place two sets of glyphs, twice.       */
  930. X
  931. X  for (i = 1; i <= total*2; i++) {
  932. X    symbol1[i] = end1[i];
  933. X    symbol2[i] = end2[i];
  934. X  }
  935. X  FillSymbolLine(symbol1);
  936. X  FillSymbolLine(symbol2);
  937. X
  938. X  /* Now actually draw the planet glyphs. */
  939. X
  940. X  for (i = 1; i <= total*2; i++) {
  941. X    j = (i+1)/2;
  942. X    if (Proper(j)) {
  943. X      if ((turtlex = (int) symbol1[i]) > 0) {
  944. X        DrawLine((int) end1[i], y2-unit*2, (int) symbol1[i], y2-unit*4,
  945. X          ret[j] < 0.0 ? gray : on, (ret[i] < 0.0 ? 1 : 0) - xcolor);
  946. X        DrawObject(j, turtlex, y2-unit*10);
  947. X      }
  948. X      if ((turtlex = (int) symbol2[i]) > 0) {
  949. X        DrawLine((int) end2[i], y1+unit*4, (int) symbol2[i], y1+unit*8,
  950. X          ret[j] < 0.0 ? gray : on, (ret[i] < 0.0 ? 1 : 0) - xcolor);
  951. X        DrawObject(j, turtlex, y1+unit*14);
  952. X        DrawTurtle(objectdraw[i & 1 ? 18 : 19], (int) symbol2[i],
  953. X          y1+unit*24, objectcolor[j]);
  954. X      }
  955. X    }
  956. X  }
  957. X}
  958. X
  959. X
  960. X/* Draw an aspect and midpoint grid in the window, with planets labeled down */
  961. X/* the diagonal. This chart is done when the -g switch is combined with the  */
  962. X/* -X switch. The chart is always 20 by 20 cells in size; therefore based on */
  963. X/* how the restrictions are set up, there may be blank columns and rows, or  */
  964. X/* else only the first 20 unrestricted objects will be included.             */
  965. X
  966. Xvoid XChartGrid()
  967. X{
  968. X  int unit, siz, x, y, i, j, k;
  969. X  color c;
  970. X
  971. X  unit = CELLSIZE*SCALE; siz = OBJECTS*unit;
  972. X  CreateGrid(bonus);
  973. X  
  974. X  /* Loop through each cell in each row and column of grid. */
  975. X
  976. X  for (y = 1, j = 0; y <= OBJECTS; y++) {
  977. X    do {
  978. X      j++;
  979. X    } while (ignore[j] && j <= total);
  980. X    DrawLine(0, y*unit, siz, y*unit, gray, !xcolor);
  981. X    DrawLine(y*unit, 0, y*unit, siz, gray, !xcolor);
  982. X    if (j <= total) for (x = 1, i = 0; x <= OBJECTS; x++) {
  983. X      do {
  984. X        i++;
  985. X      } while (ignore[i] && i <= total);
  986. X      if (i <= total) {
  987. X        turtlex = x*unit-unit/2;
  988. X        turtley = y*unit-unit/2 - (scale > 200 ? 5 : 0);
  989. X
  990. X        /* If this is an aspect cell, draw glyph of aspect in effect. */
  991. X
  992. X        if (bonus ? x > y : x < y)
  993. X          DrawTurtle(aspectdraw[grid->n[i][j]], turtlex,
  994. X            turtley, c = aspectcolor[grid->n[i][j]]);
  995. X
  996. X        /* If this is a midpoint cell, draw glyph of sign of midpoint. */
  997. X
  998. X        else if (bonus ? x < y : x > y)
  999. X          DrawTurtle(signdraw[grid->n[i][j]], turtlex,
  1000. X            turtley, c = elemcolor[(grid->n[i][j]-1)%4]);
  1001. X
  1002. X        /* For cells on main diagonal, draw glyph of planet. */
  1003. X
  1004. X        else {
  1005. X          DrawEdge((y-1)*unit, (y-1)*unit, y*unit, y*unit, hilite);
  1006. X          DrawObject(i, turtlex, turtley);
  1007. X        }
  1008. X
  1009. X        /* When the scale size is 300, we can print text in each cell: */
  1010. X
  1011. X        if (scale > 200 && label) {
  1012. X          k = abs(grid->v[i][j]);
  1013. X
  1014. X          /* For the aspect portion, print the orb in degrees and minutes. */
  1015. X
  1016. X          if (bonus ? x > y : x < y) {
  1017. X            if (grid->n[i][j])
  1018. X              sprintf(string, "%c%d %d%d'", k != grid->v[i][j] ? '-' : '+',
  1019. X                k/60, (k%60)/10, (k%60)%10);
  1020. X            else
  1021. X              sprintf(string, "");
  1022. X
  1023. X          /* For the midpoint portion, print the degrees and minutes. */
  1024. X
  1025. X          } else if (bonus ? x < y : x > y)
  1026. X            sprintf(string, "%d%d %d%d'",
  1027. X              (k/60)/10, (k/60)%10, (k%60)/10, (k%60)%10);
  1028. X
  1029. X          /* For the main diagonal, print degree and sign of each planet. */
  1030. X
  1031. X          else {
  1032. X            c = elemcolor[(grid->n[i][j]-1)%4];
  1033. X            sprintf(string, "%c%c%c %d%d", SIGNAM(grid->n[i][j]), k/10, k%10);
  1034. X          }
  1035. X          DrawText(string, x*unit-unit/2-FONTX*3, y*unit-3, c);
  1036. X        }
  1037. X      }
  1038. X    }
  1039. X  }
  1040. X  DrawBoxAll(1, 1, hilite);
  1041. X}
  1042. X
  1043. X
  1044. X/* Draw an aspect (or midpoint) grid in the window, between the planets in  */
  1045. X/* two different charts, with the planets labeled at the top and side. This */
  1046. X/* chart is done when the -g switch is combined with the -r0 and -X switch. */
  1047. X/* Like above, the chart always has a fixed number of cells.                */
  1048. X
  1049. Xvoid XChartGridRelation()
  1050. X{
  1051. X  int unit, siz, x, y, i, j, k, l;
  1052. X  color c;
  1053. X
  1054. X  unit = CELLSIZE*SCALE; siz = (OBJECTS+1)*unit;
  1055. X  CreateGridRelation(bonus != (exdisplay & DASHg0) > 0);
  1056. X  for (y = 0, j = -1; y <= OBJECTS; y++) {
  1057. X    do {
  1058. X      j++;
  1059. X    } while (ignore[j] && j <= total);
  1060. X    DrawLine(0, (y+1)*unit, siz, (y+1)*unit, gray, !xcolor);
  1061. X    DrawLine((y+1)*unit, 0, (y+1)*unit, siz, gray, !xcolor);
  1062. X    DrawEdge(0, y*unit, unit, (y+1)*unit, hilite);
  1063. X    DrawEdge(y*unit, 0, (y+1)*unit, unit, hilite);
  1064. X    if (j <= total) for (x = 0, i = -1; x <= OBJECTS; x++) {
  1065. X      do {
  1066. X        i++;
  1067. X      } while (ignore[i] && i <= total);
  1068. X
  1069. X      /* Again, we are looping through each cell in each row and column. */
  1070. X
  1071. X      if (i <= total) {
  1072. X        turtlex = x*unit+unit/2;
  1073. X        turtley = y*unit+unit/2 - (!xbitmap && scale > 200 ? 5 : 0);
  1074. X
  1075. X        /* If current cell is on top row or left hand column, draw glyph */
  1076. X        /* of planet owning the particular row or column in question.    */
  1077. X
  1078. X        if (y == 0 || x == 0) {
  1079. X          if (x+y > 0)
  1080. X            DrawObject(j == 0 ? i : j, turtlex, turtley);
  1081. X        } else {
  1082. X
  1083. X        /* Otherwise, draw glyph of aspect in effect, or glyph of */
  1084. X        /* sign of midpoint, between the two planets in question. */
  1085. X
  1086. X          if (bonus == (exdisplay & DASHg0) > 0)
  1087. X            DrawTurtle(aspectdraw[grid->n[i][j]], turtlex, turtley,
  1088. X              c = aspectcolor[grid->n[i][j]]);
  1089. X          else
  1090. X            DrawTurtle(signdraw[grid->n[i][j]], turtlex, turtley,
  1091. X              c = elemcolor[(grid->n[i][j]-1)%4]);
  1092. X        }
  1093. X
  1094. X        /* Again, when scale size is 300, print some text in current cell: */
  1095. X
  1096. X        if (scale > 200 && label) {
  1097. X
  1098. X          /* For top and left edges, print sign and degree of the planet. */
  1099. X
  1100. X          if (y == 0 || x == 0) {
  1101. X            if (x+y > 0) {
  1102. X              k = (int)((y == 0 ? planet2[i] : planet1[j])/30.0)+1;
  1103. X              l = (int)((y == 0 ? planet2[i] : planet1[j])-(real)(k-1)*30.0);
  1104. X              c = elemcolor[(k-1)%4];
  1105. X              sprintf(string, "%c%c%c %d%d", SIGNAM(k), l/10, l%10);
  1106. X
  1107. X              /* For extreme upper left corner, print some little arrows */
  1108. X              /* pointing out chart1's planets and chart2's planets.     */
  1109. X
  1110. X            } else {
  1111. X              c = hilite;
  1112. X              sprintf(string, "1v 2->");
  1113. X            }
  1114. X          } else {
  1115. X            k = abs(grid->v[i][j]);
  1116. X
  1117. X            /* For aspect cells, print the orb in degrees and minutes. */
  1118. X
  1119. X            if (bonus == (exdisplay & DASHg0) > 0)
  1120. X              if (grid->n[i][j])
  1121. X                sprintf(string, "%c%d %d%d'", k != grid->v[i][j] ? (exdisplay &
  1122. X                  DASHga ? 'a' : '-') : (exdisplay & DASHga ? 's' : '+'),
  1123. X                  k/60, (k%60)/10, (k%60)%10);
  1124. X              else
  1125. X                sprintf(string, "");
  1126. X
  1127. X            /* For midpoint cells, print degree and minute. */
  1128. X
  1129. X            else
  1130. X              sprintf(string, "%d%d %d%d'",
  1131. X                (k/60)/10, (k/60)%10, (k%60)/10, (k%60)%10);
  1132. X          }
  1133. X          DrawText(string, x*unit+unit/2-FONTX*3, (y+1)*unit-3, c);
  1134. X        }
  1135. X      }
  1136. X    }
  1137. X  }
  1138. X  DrawBoxAll(1, 1, hilite);
  1139. X}
  1140. X
  1141. X
  1142. X/* Draw the local horizon, and draw in the planets where they are at the */
  1143. X/* time in question, as done when the -Z is combined with the -X switch. */
  1144. X
  1145. Xvoid XChartHorizon()
  1146. X{
  1147. X  real lon, lat,
  1148. X    lonz[TOTAL+1], latz[TOTAL+1], azi[TOTAL+1], alt[TOTAL+1];
  1149. X  int x[TOTAL+1], y[TOTAL+1], m[TOTAL+1], n[TOTAL+1],
  1150. X    cx = chartx / 2, cy = charty / 2, unit = 12*SCALE,
  1151. X    x1, y1, x2, y2, xs, ys, i, j, k, l;
  1152. X
  1153. X  DrawBoxAll(1, 1, hilite);
  1154. X
  1155. X  /* Make a slightly smaller rectangle within the window to draw the planets */
  1156. X  /* in. Make segments on all four edges marking 5 degree increments.        */
  1157. X
  1158. X  x1 = y1 = unit/2; x2 = chartx-x1; y2 = charty-y1;
  1159. X  xs = x2-x1; ys = y2-y1;
  1160. X  for (i = 0; i < 180; i += 5) {
  1161. X    j = y1+(int)((real)i*(real)ys/180.0);
  1162. X    k = 2+(i%10 == 0)+2*(i%30 == 0);
  1163. X    DrawLine(x1+1, j, x1+1+k, j, hilite, 0);
  1164. X    DrawLine(x2-1, j, x2-1-k, j, hilite, 0);
  1165. X  }
  1166. X  for (i = 0; i < 360; i += 5) {
  1167. X    j = x1+(int)((real)i*(real)xs/DEGREES);
  1168. X    k = 2+(i%10 == 0)+2*(i%30 == 0);
  1169. X    DrawLine(j, y1+1, j, y1+1+k, hilite, 0);
  1170. X    DrawLine(j, y2-1, j, y2-1-k, hilite, 0);
  1171. X  }
  1172. X
  1173. X  /* Draw vertical lines dividing our rectangle into four areas. In our     */
  1174. X  /* local space chart, the middle line represents due south, the left line */
  1175. X  /* due east, the right line due west, and the edges due north. A fourth   */
  1176. X  /* horizontal line divides that which is above and below the horizon.     */
  1177. X
  1178. X  DrawLine(cx, y1, cx, y2, gray, 1);
  1179. X  DrawLine((cx+x1)/2, y1, (cx+x1)/2, y2, gray, 1);
  1180. X  DrawLine((cx+x2)/2, y1, (cx+x2)/2, y2, gray, 1);
  1181. X  DrawEdge(x1, y1, x2, y2, on);
  1182. X  DrawLine(x1, cy, x2, cy, on, 1);
  1183. X
  1184. X  /* Calculate the local horizon coordinates of each planet. First convert */
  1185. X  /* zodiac position and declination to zenith longitude and latitude.     */
  1186. X
  1187. X  lon = DTOR(Mod(Lon)); lat = DTOR(Lat);
  1188. X  for (i = 1; i <= total; i++) {
  1189. X    lonz[i] = DTOR(planet[i]); latz[i] = DTOR(planetalt[i]);
  1190. X    ecltoequ(&lonz[i], &latz[i]);
  1191. X  }
  1192. X  for (i = 1; i <= total; i++) if (Proper(i)) {
  1193. X    lonz[i] = DTOR(Mod(RTOD(lonz[18]-lonz[i]+PI/2.0)));
  1194. X    equtolocal(&lonz[i], &latz[i], PI/2.0-lat);
  1195. X    azi[i] = DEGREES-RTOD(lonz[i]); alt[i] = RTOD(latz[i]);
  1196. X    x[i] = x1+(int)((real)xs*(Mod(90.0-azi[i]))/DEGREES+0.5);
  1197. X    y[i] = y1+(int)((real)ys*(90.0-alt[i])/180.0+0.5);
  1198. X    m[i] = x[i]; n[i] = y[i]+unit/2;
  1199. X  }
  1200. X
  1201. X  /* As in the DrawGlobe() routine, we now determine where to draw the   */
  1202. X  /* glyphs in relation to the actual points, so that the glyphs aren't  */
  1203. X  /* drawn on top of each other if possible. Again, we assume that we'll */
  1204. X  /* put the glyph right under the point, unless there would be some     */
  1205. X  /* overlap and the above position is better off.                       */
  1206. X
  1207. X  for (i = 1; i <= total; i++) if (Proper(i)) {
  1208. X    k = l = chartx+charty;
  1209. X    for (j = 1; j < i; j++) if (Proper(j)) {
  1210. X      k = MIN(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  1211. X      l = MIN(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  1212. X    }
  1213. X    if (k < unit || l < unit)
  1214. X      if (k < l)
  1215. X        n[i] -= unit;
  1216. X  }
  1217. X  for (i = total; i >= 1; i--) if (Proper(i))    /* Draw planet's glyph. */
  1218. X    DrawObject(i, m[i], n[i]);
  1219. X  for (i = total; i >= 1; i--) if (Proper(i)) {
  1220. X#ifdef WIN
  1221. X    if (!xbitmap)
  1222. X      Xcolor(objectcolor[i]);
  1223. X#endif
  1224. X    if (!bonus || i > BASE)
  1225. X      DrawPoint(x[i], y[i], objectcolor[i]);    /* Draw small or large dot */
  1226. X    else                                        /* near glyph indicating   */
  1227. X      DrawSpot(x[i], y[i], objectcolor[i]);     /* exact local location.   */
  1228. X  }
  1229. X}
  1230. X
  1231. X
  1232. X/* Draw the local horizon, and draw in the planets where they are at the  */
  1233. X/* time in question. This chart is done when the -Z0 is combined with the */
  1234. X/* -X switch. This is an identical function to XChartHorizon(); however,  */
  1235. X/* that routine's chart is entered on the horizon and meridian. Here we   */
  1236. X/* center the chart around the center of the sky straight up from the     */
  1237. X/* local horizon, with the horizon itself being an encompassing circle.   */
  1238. X
  1239. Xvoid XChartHorizonSky()
  1240. X{
  1241. X  real lon, lat, rx, ry, s, a, sqr2,
  1242. X    lonz[TOTAL+1], latz[TOTAL+1], azi[TOTAL+1], alt[TOTAL+1];
  1243. X  int x[TOTAL+1], y[TOTAL+1], m[TOTAL+1], n[TOTAL+1],
  1244. X    cx = chartx / 2, cy = charty / 2, unit = 12*SCALE, i, j, k, l;
  1245. X
  1246. X  /* Draw a circle in window to indicate horizon line, lines dividing   */
  1247. X  /* the window into quadrants to indicate n/s and w/e meridians, and   */
  1248. X  /* segments on these lines and the edges marking 5 degree increments. */
  1249. X
  1250. X  InitCircle();
  1251. X  sqr2 = sqrt(2.0);
  1252. X  DrawLine(cx, 0, cx, charty-1, gray, 1);
  1253. X  DrawLine(0, cy, chartx-1, cy, gray, 1);
  1254. X  for (i = -125; i <= 125; i += 5) {
  1255. X    k = 2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0);
  1256. X    s = 1.0/(90.0*sqr2);
  1257. X    j = cy+(int)(s*cy*i);
  1258. X    DrawLine(cx-k, j, cx+k, j, hilite, 0);
  1259. X    j = cx+(int)(s*cx*i);
  1260. X    DrawLine(j, cy-k, j, cy+k, hilite, 0);
  1261. X  }
  1262. X  for (i = 5; i < 55; i += 5) {
  1263. X    k = 2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0);
  1264. X    s = 1.0/(180.0-90.0*sqr2);
  1265. X    j = (int)(s*cy*i);
  1266. X    DrawLine(0, j, k, j, hilite, 0);
  1267. X    DrawLine(0, charty-1-j, k, charty-1-j, hilite, 0);
  1268. X    DrawLine(chartx-1, j, chartx-1-k, j, hilite, 0);
  1269. X    DrawLine(chartx-1, charty-1-j, chartx-1-k, charty-1-j, hilite, 0);
  1270. X    j = (int)(s*cx*i);
  1271. X    DrawLine(j, 0, j, k, hilite, 0);
  1272. X    DrawLine(chartx-1-j, 0, chartx-1-j, k, hilite, 0);
  1273. X    DrawLine(j, charty-1, j, charty-1-k, hilite, 0);
  1274. X    DrawLine(chartx-1-j, charty-1, chartx-1-j, charty-1-k, hilite, 0);
  1275. X  }
  1276. X  rx = cx/sqr2; ry = cy/sqr2;
  1277. X  for (i = 0; i < 360; i++)
  1278. X    DrawLine(cx+(int)(rx*circ->x[i]), cy+(int)(ry*circ->y[i]),
  1279. X      cx+(int)(rx*circ->x[i+1]), cy+(int)(ry*circ->y[i+1]), on, 0);
  1280. X  for (i = 0; i < 360; i += 5) {
  1281. X    k = 2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0);
  1282. X    DrawLine(cx+(int)((rx-k)*circ->x[i]), cy+(int)((ry-k)*circ->y[i]),
  1283. X      cx+(int)((rx+k)*circ->x[i]), cy+(int)((ry+k)*circ->y[i]), on, 0);
  1284. X  }
  1285. X
  1286. X  /* Calculate the local horizon coordinates of each planet. First convert */
  1287. X  /* zodiac position and declination to zenith longitude and latitude.     */
  1288. X
  1289. X  lon = DTOR(Mod(Lon)); lat = DTOR(Lat);
  1290. X  for (i = 1; i <= total; i++) {
  1291. X    lonz[i] = DTOR(planet[i]); latz[i] = DTOR(planetalt[i]);
  1292. X    ecltoequ(&lonz[i], &latz[i]);
  1293. X  }
  1294. X  for (i = 1; i <= total; i++) if (Proper(i)) {
  1295. X    lonz[i] = DTOR(Mod(RTOD(lonz[18]-lonz[i]+PI/2.0)));
  1296. X    equtolocal(&lonz[i], &latz[i], PI/2.0-lat);
  1297. X    azi[i] = a = DEGREES-RTOD(lonz[i]); alt[i] = 90.0-RTOD(latz[i]);
  1298. X    s = alt[i]/90.0;
  1299. X    x[i] = cx+(int)(rx*s*COSD(180.0+azi[i])+0.5);
  1300. X    y[i] = cy+(int)(ry*s*SIND(180.0+azi[i])+0.5);
  1301. X    if (!ISLEGAL(x[i], y[i]))
  1302. X      x[i] = -1000;
  1303. X    m[i] = x[i]; n[i] = y[i]+unit/2;
  1304. X  }
  1305. X
  1306. X  /* As in the DrawGlobe() routine, we now determine where to draw the   */
  1307. X  /* glyphs in relation to the actual points, so that the glyphs aren't  */
  1308. X  /* drawn on top of each other if possible. Again, we assume that we'll */
  1309. X  /* put the glyph right under the point, unless there would be some     */
  1310. X  /* overlap and the above position is better off.                       */
  1311. X
  1312. X  for (i = 1; i <= total; i++) if (Proper(i)) {
  1313. X    k = l = chartx+charty;
  1314. X    for (j = 1; j < i; j++) if (Proper(j)) {
  1315. X      k = MIN(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  1316. X      l = MIN(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  1317. X    }
  1318. X    if (k < unit || l < unit)
  1319. X      if (k < l)
  1320. X        n[i] -= unit;
  1321. X  }
  1322. X  for (i = total; i >= 1; i--) if (m[i] >= 0 && Proper(i))    /* Draw glyph. */
  1323. X    DrawObject(i, m[i], n[i]);
  1324. X  for (i = total; i >= 1; i--) if (x[i] >= 0 && Proper(i)) {
  1325. X#ifdef WIN
  1326. X    if (!xbitmap)
  1327. X      Xcolor(objectcolor[i]);
  1328. X#endif
  1329. X    if (!bonus || i > BASE)
  1330. X      DrawPoint(x[i], y[i], objectcolor[i]);    /* Draw small or large dot */
  1331. X    else                                        /* near glyph indicating   */
  1332. X      DrawSpot(x[i], y[i], objectcolor[i]);     /* exact local location.   */
  1333. X  }
  1334. X  DrawBoxAll(1, 1, hilite);
  1335. X}
  1336. X
  1337. X
  1338. X/* Given an x and y coordinate, return the angle formed by the line from the */
  1339. X/* origin to this coordinate. This is just converting from rectangular to    */
  1340. X/* polar coordinates; however, we don't determine the radius here.           */
  1341. X
  1342. Xreal Angle(x, y)
  1343. Xreal x, y;
  1344. X{
  1345. X  real a;
  1346. X
  1347. X  a = atan(y/x);
  1348. X  if (a < 0.0)
  1349. X    a += PI;
  1350. X  if (y < 0.0)
  1351. X    a += PI;
  1352. X  return Mod(RTOD(a));
  1353. X}
  1354. X
  1355. X
  1356. X/* Draw a chart depicting an aerial view of the solar system in space, with */
  1357. X/* all the planets drawn around the Sun, and the specified central planet   */
  1358. X/* in the middle, as done when the -S is combined with the -X switch.       */
  1359. X
  1360. Xvoid XChartSpace()
  1361. X{
  1362. X  int x[TOTAL+1], y[TOTAL+1], m[TOTAL+1], n[TOTAL+1],
  1363. X    cx = chartx / 2, cy = charty / 2, unit = 12*SCALE, i, j, k, l;
  1364. X  real sx, sy, sz = 30.0, x1, y1, a;
  1365. X
  1366. X  /* Determine the scale of the window. For a scale size of 300, make    */
  1367. X  /* the window 6 AU in radius (enough for inner planets out to asteroid */
  1368. X  /* belt). For a scale of 200, make window 30 AU in radius (enough for  */
  1369. X  /* planets out to Neptune). For scale of 100, make it 90 AU in radius  */
  1370. X  /* (enough for all planets including the orbits of the uranians.)      */
  1371. X
  1372. X  if (scale < 200)
  1373. X    sz = 90.0;
  1374. X  else if (scale > 200)
  1375. X    sz = 6.0;
  1376. X  sx = (real)cx/sz; sy = (real)cy/sz;
  1377. X  for (i = 0; i <= BASE; i++) if (Proper(i)) {
  1378. X
  1379. X    /* Determine what glyph corresponds to our current planet. Normally the */
  1380. X    /* array indices are the same, however we have to do some swapping for  */
  1381. X    /* non-geocentric based charts where a planet gets replaced with Earth. */
  1382. X
  1383. X    if (centerplanet == 0)
  1384. X      j = i < 2 ? 1-i : i;
  1385. X    else if (centerplanet == 1)
  1386. X      j = i;
  1387. X    else
  1388. X      j = i == 0 ? centerplanet : (i == centerplanet ? 0 : i);
  1389. X    x1 = spacex[j]; y1 = spacey[j];
  1390. X    x[i] = cx-(int)(x1*sx); y[i] = cy+(int)(y1*sy);
  1391. X    m[i] = x[i]; n[i] = y[i]+unit/2;
  1392. X  }
  1393. X
  1394. X  /* As in the DrawGlobe() routine, we now determine where to draw the   */
  1395. X  /* glyphs in relation to the actual points, so that the glyphs aren't  */
  1396. X  /* drawn on top of each other if possible. Again, we assume that we'll */
  1397. X  /* put the glyph right under the point, unless there would be some     */
  1398. X  /* overlap and the above position is better off.                       */
  1399. X
  1400. X  for (i = 0; i <= BASE; i++) if (Proper(i)) {
  1401. X    k = l = chartx+charty;
  1402. X    for (j = 0; j < i; j++) if (Proper(j)) {
  1403. X      k = MIN(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  1404. X      l = MIN(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  1405. X    }
  1406. X    if (k < unit || l < unit)
  1407. X      if (k < l)
  1408. X        n[i] -= unit;
  1409. X  }
  1410. X
  1411. X  /* Draw the 12 sign boundaries from the center body to edges of screen. */
  1412. X
  1413. X  a = Mod(Angle(spacex[3], spacey[3])-planet[3]);
  1414. X  for (i = 0; i < SIGNS; i++) {
  1415. X    k = cx+2*(int)((real)cx*COSD((real)i*30.0+a));
  1416. X    l = cy+2*(int)((real)cy*SIND((real)i*30.0+a));
  1417. X    DrawClip(cx, cy, k, l, gray, 1);
  1418. X  }
  1419. X  for (i = BASE; i >= 0; i--) if (Proper(i) && ISLEGAL(m[i], n[i]))
  1420. X    DrawObject(i, m[i], n[i]);
  1421. X  for (i = BASE; i >= 0; i--) if (Proper(i) && ISLEGAL(x[i], y[i])) {
  1422. X#ifdef WIN
  1423. X    if (!xbitmap)
  1424. X      Xcolor(objectcolor[i]);
  1425. X#endif
  1426. X    if (!bonus || i > BASE)
  1427. X      DrawPoint(x[i], y[i], objectcolor[i]);    /* Draw small or large dot */
  1428. X    else                                        /* near glyph indicating   */
  1429. X      DrawSpot(x[i], y[i], objectcolor[i]);     /* exact local location.   */
  1430. X  }
  1431. X  DrawBoxAll(1, 1, hilite);
  1432. X}
  1433. X
  1434. X
  1435. X/* Create a chart in the window based on the current graphics chart mode. */
  1436. X/* This is the main dispatch routine for all of the program's graphics.   */
  1437. X
  1438. Xvoid XChart()
  1439. X{
  1440. X  int i, j, k;
  1441. X
  1442. X  if (xbitmap) {
  1443. X    if (chartx > BITMAPX)
  1444. X      chartx = BITMAPX;
  1445. X    if (charty > BITMAPY)
  1446. X      charty = BITMAPY;
  1447. X    DrawBlock(0, 0, chartx - 1, charty - 1, off);    /* Clear bitmap screen. */
  1448. X  }
  1449. X  switch (modex) {
  1450. X  case 'c':
  1451. X    if (relation != DASHr0)
  1452. X      XChartWheel();
  1453. X    else
  1454. X      XChartWheelRelation();
  1455. X    break;
  1456. X  case 'l':
  1457. X    DrawWorld(degree);     /* First draw map of world.           */
  1458. X    XChartAstroGraph();    /* Then draw astro-graph lines on it. */
  1459. X    break;
  1460. X  case 'a':
  1461. X    if (relation != DASHr0)
  1462. X      XChartGrid();
  1463. X    else
  1464. X      XChartGridRelation();
  1465. X    break;
  1466. X  case 'z':
  1467. X    if (exdisplay & DASHZ0)
  1468. X      XChartHorizonSky();
  1469. X    else
  1470. X      XChartHorizon();
  1471. X    break;
  1472. X  case 's':
  1473. X    XChartSpace();
  1474. X    break;
  1475. X  case 'w':
  1476. X    DrawWorld(degree);                          /* First draw map of world. */
  1477. X    if (bonus && (exdisplay & DASHXW0) == 0)    /* Then maybe Ley lines.    */
  1478. X      DrawLeyLines(degree);
  1479. X    break;
  1480. X  case 'p':
  1481. X  case 'g':
  1482. X    DrawGlobe(degree);
  1483. X    break;
  1484. X  }
  1485. X
  1486. X  /* Print text showing chart information at bottom of window. */
  1487. X
  1488. X  if (xtext && modex != 'w' && modex != 'p' && modex != 'g') {
  1489. X    if (Mon == -1)
  1490. X      sprintf(string, "(no time or space)");
  1491. X    else if (relation == DASHrc)
  1492. X      sprintf(string, "(composite)");
  1493. X    else {
  1494. X      i = (int) Mon; j = (int) (FRACT(Tim)*100.0+0.1);
  1495. X      k = ansi; ansi = FALSE;
  1496. X      sprintf(string, "%2.0f %c%c%c %.0f %2.0f:%d%d (%.2f GMT) %s",
  1497. X        Day, monthname[i][0], monthname[i][1], monthname[i][2], Yea,
  1498. X        floor(Tim), j/10, j%10, -Zon, StringLocation(Lon, Lat, 100.0));
  1499. X      ansi = k;
  1500. X    }
  1501. X    DrawText(string, (chartx-StringLen(string)*FONTX)/2, charty-3, hilite);
  1502. X  }
  1503. X}
  1504. X#endif
  1505. X
  1506. X/* xcharts.c */
  1507. END_OF_FILE
  1508. if test 52928 -ne `wc -c <'xcharts.c'`; then
  1509.     echo shar: \"'xcharts.c'\" unpacked with wrong size!
  1510. fi
  1511. # end of 'xcharts.c'
  1512. fi
  1513. echo shar: End of archive 6 \(of 12\).
  1514. cp /dev/null ark6isdone
  1515. MISSING=""
  1516. for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
  1517.     if test ! -f ark${I}isdone ; then
  1518.     MISSING="${MISSING} ${I}"
  1519.     fi
  1520. done
  1521. if test "${MISSING}" = "" ; then
  1522.     echo You have unpacked all 12 archives.
  1523.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1524. else
  1525.     echo You still need to unpack the following archives:
  1526.     echo "        " ${MISSING}
  1527. fi
  1528. ##  End of shell archive.
  1529. exit 0
  1530.  
  1531. exit 0 # Just in case...
  1532.