home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Guide / c-cplusplus-interactive-guide.iso / c_ref / csource1 / ast40dos / charts.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-04  |  34.4 KB  |  1,035 lines

  1. /*
  2. ** Astrolog (Version 4.00) File: charts.c
  3. **
  4. ** IMPORTANT NOTICE: the graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1993 by Walter D. Pullen
  6. ** (cruiser1@stein.u.washington.edu). Permission is granted to freely
  7. ** use and distribute these routines provided one doesn't sell,
  8. ** restrict, or profit from them in any way. Modification is allowed
  9. ** provided these notices remain with any altered or edited versions of
  10. ** the program.
  11. **
  12. ** The main planetary calculation routines used in this program have
  13. ** been Copyrighted and the core of this program is basically a
  14. ** conversion to C of the routines created by James Neely as listed in
  15. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  16. ** available from Matrix Software. The copyright gives us permission to
  17. ** use the routines for personal use but not to sell them or profit from
  18. ** them in any way.
  19. **
  20. ** The PostScript code within the core graphics routines are programmed
  21. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  22. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  23. **
  24. ** The extended accurate ephemeris databases and formulas are from the
  25. ** calculation routines in the program "Placalc" and are programmed and
  26. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  27. ** (alois@azur.ch). The use of that source code is subject to
  28. ** regulations made by Astrodienst Zurich, and the code is not in the
  29. ** public domain. This copyright notice must not be changed or removed
  30. ** by any user of this program.
  31. **
  32. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  33. ** X Window graphics initially programmed 10/23-29/1991.
  34. ** PostScript graphics initially programmed 11/29-30/1992.
  35. ** Last code change made 12/31/1993.
  36. */
  37.  
  38. #include "astrolog.h"
  39.  
  40.  
  41. /*
  42. ******************************************************************************
  43. ** Single Chart Display Subprograms.
  44. ******************************************************************************
  45. */
  46.  
  47. /* Fill out tables based on the number of unrestricted planets in signs by  */
  48. /* element, signs by mode, as well as other values such as the number of    */
  49. /* objects in yang vs. yin signs, in various house hemispheres (north/south */
  50. /* and east/west), and the number in first six signs vs. second six signs.  */
  51. /* This is used by the -v chart listing and the sidebar in graphics charts. */
  52.  
  53. void CreateElemTable(elemode, elem, mo, tot, pos, abo, lef, lea)
  54. int elemode[4][3], *elem, *mo, *tot, *pos, *abo, *lef, *lea;
  55. {
  56.   int i, j;
  57.  
  58.   *tot = *pos = *abo = *lef = *lea = 0;    /* Initialize arrays     */
  59.   for (i = 0; i < 4; i++)                  /* and variables to zero */
  60.     elem[i] = 0;
  61.   for (j = 0; j < 3; j++)
  62.     mo[j] = 0;
  63.   for (i = 0; i < 4; i++)
  64.     for (j = 0; j < 3; j++)
  65.       elemode[i][j] = 0;
  66.  
  67.   /* Calculate number of objects in each element, mode, hemisphere, etc. */
  68.  
  69.   for (i = 1; i <= total; i++) if (!ignore[i]) {
  70.     (*tot)++;
  71.     j = ZTOS(planet[i]);
  72.     elemode[(j-1)&3][(j-1)%3]++;
  73.     elem[(j-1)&3]++; mo[(j-1)%3]++;
  74.     *pos += (j & 1);
  75.     *lea += (j < _LIB);
  76.     j = inhouse[i];
  77.     *abo += (j >= _LIB);
  78.     *lef += (j < _CAN || j >= _CAP);
  79.   }
  80. }
  81.  
  82.  
  83. /* Print the straight listing of planet and house positions and specified */
  84. /* by the -v switch, along with the element table, etc.                   */
  85.  
  86. void ChartLocation()
  87. {
  88.   int elemode[4][3], elem[4], mo[3], pos, abo, lef, lea;
  89.   int count, i, j, k;
  90.  
  91.   CreateElemTable(elemode, elem, mo, &count, &pos, &abo, &lef, &lea);
  92.  
  93.   /* Print header showing time and date of the chart being displayed. */
  94.  
  95.   AnsiColor(WHITE);
  96.   fprintf(S, "%s %s chart ", appname, VERSION);
  97.   if (Mon == -1)
  98.     fprintf(S, "(no time or space)\n");
  99.   else if (relation == DASHrc)
  100.     fprintf(S, "(composite)\n");
  101.   else {
  102.     i = (int) (FRACT(dabs(Tim))*100.0+ROUND);
  103.     j = (int) (FRACT(dabs(Zon))*100.0+ROUND);
  104.     fprintf(S, "for %s %s",
  105.       CharDate(Mon, Day, Yea, TRUE), CharTime((int)Tim, i));
  106.     fprintf(S, " (%c%.0f:%02d GMT) ",
  107.       Zon > 0.0 ? '-' : '+', dabs(Zon), j);
  108.     fprintf(S, "%s\n", CharLocation(Lon, Lat, 100.0));
  109.   }
  110.  
  111. #ifdef INTERPRET
  112.   if (interpret) {            /* Print an interpretation if -I in effect. */
  113.     if (relation == DASHr)
  114.       InterpretSynastry();    /* Print synastry interpretaion for -r -I.  */
  115.     else
  116.       InterpretLocation();    /* Do normal interpretation for just -v -I. */
  117.     return;
  118.   }
  119. #endif
  120.   AnsiColor(DEFAULT);
  121.   fprintf(S, "Body  Locat. Ret. Decl. Rul.      House  Rul. Veloc.    ");
  122.   fprintf(S, "%s Houses.\n\n", systemname[housesystem]);
  123.  
  124.   /* Ok, now print out each location of each object. */
  125.  
  126.   for (i = 1, j = 1; i <= BASE; i++, j++) {
  127.     if (i > OBJECTS && (i <= C_HI || ignore[i]))
  128.       continue;
  129.     while (i <= OBJECTS && j <= OBJECTS && ignore[j])
  130.       j++;
  131.     if (i <= OBJECTS && j > OBJECTS)
  132.       PrintTab(' ', 51);
  133.     else {
  134.       if (i > OBJECTS)
  135.         j = i;
  136.       AnsiColor(objectansi[j]);
  137.       fprintf(S, "%-4.4s: ", objectname[j]);
  138.       PrintZodiac(planet[j]);
  139.       fprintf(S, " %c ", ret[j] >= 0.0 ? ' ' : 'R');
  140.       if (j <= THINGS || j > OBJECTS)
  141.         PrintAltitude(planetalt[i]);
  142.       else
  143.         fprintf(S, "_______");
  144.       fprintf(S, " (%c)", Dignify(j, ZTOS(planet[i])));
  145.       k = inhouse[j];
  146.       AnsiColor(signansi(k));
  147.       fprintf(S, " [%2d%c%c house]", k, post[k][0], post[k][1]);
  148.       AnsiColor(DEFAULT);
  149.       fprintf(S, " [%c] ", Dignify(j, k));
  150.       if ((j != _MOO || placalc) && (IsObject(j) || (j == _NOD && placalc)))
  151.         fprintf(S, RTOD(dabs(ret[j])) < 10.0 ? "%c%5.3f" : "%c%5.2f",
  152.           ret[i] < 0.0 ? '-' : '+', RTOD(dabs(ret[j])));
  153.       else
  154.         fprintf(S, "______");
  155.     }
  156.  
  157.     /* For some lines, we have to append the house cusp positions. */
  158.  
  159.     if (i <= SIGNS) {
  160.       fprintf(S, "  -  ");
  161.       AnsiColor(signansi(i));
  162.       fprintf(S, "House cusp %2d: ", i);
  163.       PrintZodiac(house[i]);
  164.     }
  165.  
  166.     /* For some lines, we have to append the element table information. */
  167.  
  168.     if (i == SIGNS+2)
  169.       fprintf(S, "     Car Fix Mut TOT");
  170.     else if (i > SIGNS+2 && i < SIGNS+7) {
  171.       k = i-(SIGNS+2)-1;
  172.       AnsiColor(elemansi[k]);
  173.       fprintf(S, "  %c%c%c%3d %3d %3d %3d",
  174.         element[k][0], element[k][1], element[k][2],
  175.         elemode[k][0], elemode[k][1], elemode[k][2], elem[k]);
  176.       AnsiColor(DEFAULT);
  177.     } else if (i == SIGNS+7)
  178.       fprintf(S, "  TOT %2d %3d %3d %3d", mo[0], mo[1], mo[2], count);
  179.     else if (i == OBJECTS)
  180.       PrintTab(' ', 23);
  181.     else if (i >= U_LO)
  182.       fprintf(S, "  Uranian #%d", i-U_LO+1);
  183.     switch (i-SIGNS-1) {
  184.     case 1: fprintf(S, "   +:%2d", pos);       break;
  185.     case 2: fprintf(S, "   -:%2d", count-pos); break;
  186.     case 3: fprintf(S, "   M:%2d", abo);       break;
  187.     case 4: fprintf(S, "   N:%2d", count-abo); break;
  188.     case 5: fprintf(S, "   A:%2d", lef);       break;
  189.     case 6: fprintf(S, "   D:%2d", count-lef); break;
  190.     case 7: fprintf(S,    "<:%2d", lea);       break;
  191.     }
  192.     printl();
  193.   }
  194.  
  195.   /* Do another loop to print out the stars in their specified order. */
  196.  
  197.   if (universe) for (i = S_LO; i <= S_HI; i++) if (!ignore[i]) {
  198.     j = BASE+starname[i-BASE];
  199.     AnsiColor(objectansi[j]);
  200.     fprintf(S, "%.4s: ", objectname[j]);
  201.     PrintZodiac(planet[j]);
  202.     fprintf(S, "   ");
  203.     PrintAltitude(planetalt[j]);
  204.     k = inhouse[j];
  205.     AnsiColor(signansi(k));
  206.     fprintf(S, "     [%2d%c%c house]", k, post[k][0], post[k][1]);
  207.     AnsiColor(DEFAULT);
  208.     fprintf(S, "     ______  Star #%2d: %5.2f\n", i-BASE, starbright[j-BASE]);
  209.   }
  210. }
  211.  
  212.  
  213. /* Print out the aspect and midpoint grid for a chart, as specified with the */
  214. /* -g switch. (Each grid row takes up 4 lines of text.)                      */
  215.  
  216. void ChartGrid()
  217. {
  218.   int x, y, r, x1, y1, temp;
  219.  
  220. #ifdef INTERPRET
  221.   if (interpret) {    /* Print interpretation instead if -I in effect. */
  222.     InterpretGrid();
  223.     return;
  224.   }
  225. #endif
  226.  
  227.   for (y1 = 0, y = 1; y <= total; y++) if (!ignore[y])
  228.     for (r = 1; r <= 4; r++) {
  229.       for (x1 = 0, x = 1; x <= total; x++) if (!ignore[x]) {
  230.         if (y1 > 0 && x1 > 0 && y+r > 2)
  231.           printc(r > 1 ? BOXV : BOXC);
  232.         if (r > 1) {
  233.           temp = grid->n[x][y];
  234.  
  235.           /* Print aspect rows. */
  236.  
  237.           if (x < y) {
  238.             if (temp);
  239.               AnsiColor(aspectansi[temp]);
  240.             if (r == 2)
  241.               fprintf(S, "%s", temp ? aspectabbrev[temp] : "   ");
  242.             else if (!temp)
  243.               fprintf(S, "   ");
  244.             else {
  245.               if (r == 3) {
  246.                 if (grid->v[x][y] < 600)
  247.                   fprintf(S, "%c%2d", exdisplay & DASHga ?
  248.                     (grid->v[x][y] < 0 ? 'a' : 's') :
  249.                     (grid->v[x][y] < 0 ? '-' : '+'), abs(grid->v[x][y])/60);
  250.                 else
  251.                   fprintf(S, "%3d", abs(grid->v[x][y])/60);
  252.               } else
  253.                 fprintf(S, "%02d'", abs(grid->v[x][y])%60);
  254.             }
  255.  
  256.           /* Print midpoint rows. */
  257.  
  258.           } else if (x > y) {
  259.             AnsiColor(signansi(temp));
  260.             if (r == 2) {
  261.               temp = grid->n[x][y];
  262.               fprintf(S, "%c%c%c", SIGNAM(temp));
  263.             } else if (r == 3) {
  264.               fprintf(S, "%2d%c", grid->v[x][y]/60, DEGR2);
  265.             } else
  266.               fprintf(S, "%02d'", grid->v[x][y]%60);
  267.  
  268.           /* Print the diagonal of object names. */
  269.  
  270.           } else {
  271.             AnsiColor(REVERSE);
  272.             if (r == 2) {
  273.               AnsiColor(objectansi[y]);
  274.               fprintf(S, "%c%c%c", OBJNAM(y));
  275.             } else {
  276.               temp = ZTOS(planet[y]);
  277.               AnsiColor(signansi(temp));
  278.               if (r == 3)
  279.                 fprintf(S, "%2d%c", (int)planet[y] - (temp-1)*30, DEGR2);
  280.               else
  281.                 fprintf(S, "%c%c%c", SIGNAM(temp));
  282.             }
  283.           }
  284.           AnsiColor(DEFAULT);
  285.         } else
  286.           if (y1 > 0)
  287.             PrintTab(BOXH, 3);
  288.         x1++;
  289.         if (column80 && x1 >= 20)
  290.           x = total;
  291.       }
  292.       if (y+r > 2)
  293.         printl();
  294.       y1++;
  295.     }
  296. }
  297.  
  298.  
  299. /* This is a subprocedure of DisplayGrands(). Here we print out one aspect */
  300. /* configuration found by the parent procedure.                            */
  301.  
  302. void PrintGrand(nam, i1, i2, i3, i4)
  303. char nam;
  304. int i1, i2, i3, i4;
  305. {
  306.   switch (nam) {
  307.   case '.': AnsiColor(aspectansi[_CON]); fprintf(S, "Stellium   "); break;
  308.   case 't': AnsiColor(aspectansi[_TRI]); fprintf(S, "Grand Trine"); break;
  309.   case 's': AnsiColor(aspectansi[_OPP]); fprintf(S, "T-Square   "); break;
  310.   case 'y': AnsiColor(aspectansi[_INC]); fprintf(S, "Yod        "); break;
  311.   case 'g': AnsiColor(aspectansi[_SQU]); fprintf(S, "Grand Cross"); break;
  312.   case 'c': AnsiColor(aspectansi[_SEX]); fprintf(S, "Cradle     "); break;
  313.   default: ;
  314.   }
  315.   AnsiColor(DEFAULT);
  316.   fprintf(S, " %s ", nam == '.' || nam == 't' || nam == 'g' ? "with" : "from");
  317.   AnsiColor(objectansi[i1]);
  318.   fprintf(S, "%c%c%c: ", OBJNAM(i1));
  319.   PrintZodiac(planet[i1]);
  320.   fprintf(S, " %s ", nam == '.' || nam == 't' ? "and" : "to ");
  321.   AnsiColor(objectansi[i2]);
  322.   fprintf(S, "%c%c%c: ", OBJNAM(i2));
  323.   PrintZodiac(planet[i2]);
  324.   fprintf(S, " %s ", nam == 'g' || nam == 'c' ? "to " : "and");
  325.   AnsiColor(objectansi[i3]);
  326.   fprintf(S, "%c%c%c: ", OBJNAM(i3));
  327.   PrintZodiac(planet[i3]);
  328.   if (nam == 'g' || nam == 'c') {
  329.     fprintf(S, " to ");
  330.     AnsiColor(objectansi[i4]);
  331.     fprintf(S, "%c%c%c: ", OBJNAM(i4));
  332.     PrintZodiac(planet[i4]);
  333.   }
  334.   printl();
  335. }
  336.  
  337.  
  338. /* Scan the aspect grid of a chart and print out any major configurations, */
  339. /* as specified with the -g0 switch.                                       */
  340.  
  341. void DisplayGrands()
  342. {
  343.   int count = 0, i, j, k, l;
  344.  
  345.   for (i = 1; i <= total; i++) if (!ignore[i])
  346.     for (j = 1; j <= total; j++) if (j != i && !ignore[j])
  347.       for (k = 1; k <= total; k++) if (k != i && k != j && !ignore[k]) {
  348.  
  349.         /* Is there a Stellium among the current three planets? */
  350.  
  351.         if (i < j && j < k && grid->n[i][j] == _CON &&
  352.             grid->n[i][k] == _CON && grid->n[j][k] == _CON) {
  353.           count++;
  354.           PrintGrand('.', i, j, k, l);
  355.  
  356.         /* Is there a Grand Trine? */
  357.  
  358.         } else if (i < j && j < k && grid->n[i][j] == _TRI &&
  359.             grid->n[i][k] == _TRI && grid->n[j][k] == _TRI) {
  360.           count++;
  361.           PrintGrand('t', i, j, k, l);
  362.  
  363.         /* Is there a T-Square? */
  364.  
  365.         } else if (j < k && grid->n[j][k] == _OPP &&
  366.             grid->n[MIN(i, j)][MAX(i, j)] == _SQU &&
  367.             grid->n[MIN(i, k)][MAX(i, k)] == _SQU) {
  368.           count++;
  369.           PrintGrand('s', i, j, k, l);
  370.  
  371.         /* Is there a Yod? */
  372.  
  373.         } else if (j < k && grid->n[j][k] == _SEX &&
  374.             grid->n[MIN(i, j)][MAX(i, j)] == _INC &&
  375.             grid->n[MIN(i, k)][MAX(i, k)] == _INC) {
  376.           count++;
  377.           PrintGrand('y', i, j, k, l);
  378.         }
  379.         for (l = 1; l <= total; l++) if (!ignore[l]) {
  380.  
  381.           /* Is there a Grand Cross among the current four planets? */
  382.  
  383.           if (i < j && i < k && i < l && j < l && grid->n[i][j] == _SQU &&
  384.               grid->n[MIN(j, k)][MAX(j, k)] == _SQU &&
  385.               grid->n[MIN(k, l)][MAX(k, l)] == _SQU &&
  386.               grid->n[i][l] == _SQU &&
  387.               MinDistance(planet[i], planet[k]) > 150.0 &&
  388.               MinDistance(planet[j], planet[l]) > 150.0) {
  389.             count++;
  390.             PrintGrand('g', i, j, k, l);
  391.  
  392.           /* Is there a Cradle? */
  393.  
  394.           } else if (i < l && grid->n[MIN(i, j)][MAX(i, j)] == _SEX &&
  395.               grid->n[MIN(j, k)][MAX(j, k)] == _SEX &&
  396.               grid->n[MIN(k, l)][MAX(k, l)] == _SEX &&
  397.               MinDistance(planet[i], planet[l]) > 150.0) {
  398.             count++;
  399.             PrintGrand('c', i, j, k, l);
  400.           }
  401.         }
  402.       }
  403.   if (!count)
  404.     fprintf(S, "No major configurations in aspect grid.\n");
  405. }
  406.  
  407.  
  408. /* This is subprocedure of ChartWheel(). Here we print out the location */
  409. /* of a particular house cusp as well as what house cusp number it is.  */
  410.  
  411. void PrintHouse(i, left)
  412. int i, left;
  413. {
  414.   if (!left)
  415.     PrintZodiac(house[i]);
  416.   AnsiColor(signansi(i));
  417.   fprintf(S, "<%d>", i);
  418.   if (left)
  419.     PrintZodiac(house[i]);
  420.   else
  421.     AnsiColor(DEFAULT);
  422. }
  423.  
  424.  
  425. /* Another subprocedure of ChartWheel(). Here we print out one line in a */
  426. /* particular house cell (which may be blank).                           */
  427.  
  428. void PrintWheelSlot(obj, wheelcols)
  429. int obj, wheelcols;
  430. {
  431.   if (obj) {
  432.     AnsiColor(objectansi[obj]);
  433.     fprintf(S, " %c%c%c ", OBJNAM(obj));  /* Print planet and its position. */
  434.     PrintZodiac(planet[obj]);
  435.     fprintf(S, "%c ", ret[obj] < 0.0 ? 'r' : ' ');
  436.     PrintTab(' ', WHEELCOLS-14-1);
  437.   } else
  438.     PrintTab(' ', wheelcols-1);       /* This particular line is blank. */
  439. }
  440.  
  441.  
  442. /* Display all the objects in a wheel format on the screen, as specified */
  443. /* with the -w switch. The wheel is divided into the 12 houses and the   */
  444. /* planets are placed accordingly.                                       */
  445.  
  446. void ChartWheel()
  447. {
  448.   byte wheel[SIGNS][WHEELROWS];
  449.   int wheelcols, count = 0, i, j, k, l;
  450.  
  451.   /* If the seconds (-b0) flag is set, we'll print all planet and house    */
  452.   /* locations to the nearest zodiac second instead of just to the minute. */
  453.  
  454.   seconds = -seconds;
  455.   wheelcols = WHEELCOLS + (seconds < 0)*4;
  456.  
  457.   for (i = 0; i < SIGNS; i++)
  458.     for (j = 0; j < wheelrows; j++)    /* Clear out array from the */
  459.       wheel[i][j] = 0;                 /* last time we used it.    */
  460.  
  461.   /* This section of code places each object in the wheel house array. */
  462.  
  463.   for (i = 1; i <= total && count < wheelrows*12; i++) {
  464.     if (ignore[i] || !(i < _MC || i == OBJECTS || i > C_HI))
  465.       continue;
  466.  
  467.     /* Try to put object in its proper house. If no room, */
  468.     /* then overflow over to the succeeding house.        */
  469.  
  470.     for (j = inhouse[i]-1; j < SIGNS; j = j < SIGNS ? (j+1)%SIGNS : j) {
  471.  
  472.       /* Now try to find the proper place in the house to put the object. */
  473.       /* This is in sorted order, although a check is made for 0 Aries.   */
  474.  
  475.       if (wheel[j][wheelrows-1] > 0)
  476.         continue;
  477.       l = house[j+1] > house[Mod12(j+2)];
  478.       for (k = 0; wheel[j][k] > 0 &&
  479.            (planet[i] >= planet[wheel[j][k]] ||
  480.             (l && planet[i] < DEGHALF && planet[wheel[j][k]] > DEGHALF)) &&
  481.            !(l && planet[i] > DEGHALF && planet[wheel[j][k]] < DEGHALF); k++)
  482.         ;
  483.  
  484.       /* Actually insert object in proper place. */
  485.  
  486.       if (wheel[j][k] <= 0)
  487.         wheel[j][k] = i;
  488.       else {
  489.         for (l = wheelrows-1; l > k; l--)
  490.           wheel[j][l] = wheel[j][l-1];
  491.         wheel[j][k] = i;
  492.       }
  493.       count++;
  494.       j = SIGNS;
  495.     }
  496.   }
  497.  
  498.   /* Now, if this is really the -w switch and not -w0, then reverse the */
  499.   /* order of objects in western houses for more intuitive reading.     */
  500.  
  501.   if (!(exdisplay & DASHw0))
  502.     for (i = 3; i < 9; i++)
  503.       for (j = 0; j < wheelrows/2; j++) {
  504.         k = wheelrows-1-j;
  505.         l = wheel[i][j]; wheel[i][j] = wheel[i][k]; wheel[i][k] = l;
  506.       }
  507.  
  508.   /* Here we actually print the wheel and the objects in it. */
  509.  
  510.   printc(BOXNW); PrintTab(BOXH, WHEELCOLS-8); PrintHouse(11, TRUE);
  511.   PrintTab(BOXH, WHEELCOLS-11); PrintHouse(10, TRUE);
  512.   PrintTab(BOXH, WHEELCOLS-10); PrintHouse(9, TRUE);
  513.   PrintTab(BOXH, wheelcols-4); fprintf(S, "%c\n", BOXNE);
  514.   for (i = 0; i < wheelrows; i++) {
  515.     for (j = 10; j >= 7; j--) {
  516.       printc(BOXV); PrintWheelSlot(wheel[j][i], wheelcols);
  517.     }
  518.     fprintf(S, "%c\n", BOXV);
  519.   }
  520.   PrintHouse(12, TRUE); PrintTab(BOXH, WHEELCOLS-11);
  521.   printc(BOXC); PrintTab(BOXH, wheelcols-1); printc(BOXJN);
  522.   PrintTab(BOXH, wheelcols-1); printc(BOXC); PrintTab(BOXH, WHEELCOLS-10);
  523.   PrintHouse(8, FALSE); printl();
  524.   for (i = 0; i < wheelrows; i++) {
  525.     printc(BOXV); PrintWheelSlot(wheel[11][i], wheelcols); printc(BOXV);
  526.  
  527.     /* For some rows, we have to insert the chart header information. */
  528.  
  529.     if (i) {
  530.       PrintTab(' ', wheelcols-11-(i == 2 && !eurotime));
  531.       if (i == 1)
  532.         fprintf(S, "%s (%s) chart", appname, VERSION);
  533.       else if (i == 2) {
  534.         j = DayOfWeek(Mon, Day, Yea);
  535.         k = (int) (FRACT(dabs(Tim))*100.0+ROUND);
  536.         fprintf(S, "%c%c%c %s %s", DAYNAM(j), CharDate(Mon, Day, Yea, 2),
  537.           CharTime((int)floor(Tim), k));
  538.       } else if (i == 3) {
  539.         fprintf(S, "%c%02d:", Zon > 0.0 ? '-' : '+', (int)dabs(Zon));
  540.         j = (int) (FRACT(dabs(Zon))*100.0+ROUND);
  541.         fprintf(S, "%02d %s", j, CharLocation(Lon, Lat, 100.0));
  542.       } else
  543.         PrintTab(' ', 21);
  544.       PrintTab(' ', wheelcols-11-(i == 2 && !eurotime));
  545.  
  546.     } else
  547.       PrintTab(' ', wheelcols*2-1);
  548.     printc(BOXV); PrintWheelSlot(wheel[6][i], wheelcols);
  549.     fprintf(S, "%c\n", BOXV);
  550.   }
  551.   PrintHouse(1, TRUE); PrintTab(BOXH, WHEELCOLS-10);
  552.   printc(BOXJW); PrintTab(' ', wheelcols-11);
  553.   fprintf(S, "%s", systemname[housesystem]);
  554.   PrintTab(' ', 14-StringLen(systemname[housesystem]));
  555.   fprintf(S, "Houses."); PrintTab(' ', wheelcols-11); printc(BOXJE);
  556.   PrintTab(BOXH, WHEELCOLS-10); PrintHouse(7, FALSE); printl();
  557.   for (i = 0; i < wheelrows; i++) {
  558.     printc(BOXV); PrintWheelSlot(wheel[0][i], wheelcols); printc(BOXV);
  559.     if (i == 0) {
  560.       PrintTab(' ', wheelcols-12);
  561.       fprintf(S, "Julian Day = %9.2f", JulianDayFromTime(T));
  562.       PrintTab(' ', wheelcols-12);
  563.     } else
  564.       PrintTab(' ', wheelcols*2-1);
  565.     printc(BOXV); PrintWheelSlot(wheel[5][i], wheelcols);
  566.     fprintf(S, "%c\n", BOXV);
  567.   }
  568.   PrintHouse(2, TRUE); PrintTab(BOXH, WHEELCOLS-10);
  569.   printc(BOXC); PrintTab(BOXH, wheelcols-1); printc(BOXJS);
  570.   PrintTab(BOXH, wheelcols-1); printc(BOXC);
  571.   PrintTab(BOXH, WHEELCOLS-10); PrintHouse(6, FALSE); printl();
  572.   for (i = 0; i < wheelrows; i++) {
  573.     for (j = 1; j <= 4; j++) {
  574.       printc(BOXV); PrintWheelSlot(wheel[j][i], wheelcols);
  575.     }
  576.     fprintf(S, "%c\n", BOXV);
  577.   }
  578.   printc(BOXSW); PrintTab(BOXH, wheelcols-4); PrintHouse(3, FALSE);
  579.   PrintTab(BOXH, WHEELCOLS-10); PrintHouse(4, FALSE);
  580.   PrintTab(BOXH, WHEELCOLS-10); PrintHouse(5, FALSE);
  581.   PrintTab(BOXH, WHEELCOLS-7); fprintf(S, "%c\n", BOXSE);
  582.   seconds = -seconds;
  583. }
  584.  
  585.  
  586. /* Display all aspects between objects in the chart, one per line, in       */
  587. /* sorted order based on the total "power" of the aspect, as specified with */
  588. /* the -m0 switch. The same influences used for -I charts are used here.    */
  589.  
  590. void ChartAspect()
  591. {
  592.   int pcut = 30000, icut, jcut, phi, ihi, jhi, ahi, p, i, j, k, count = 0;
  593.   real ip, jp;
  594.  
  595.   loop {
  596.     phi = -1;
  597.  
  598.     /* Search for the next most powerful aspect in the aspect grid. */
  599.  
  600.     for (i = 2; i <= total; i++) if (!ignore[i])
  601.       for (j = 1; j < i; j++) if (!ignore[j])
  602.         if (k = grid->n[j][i]) {
  603.           ip = i <= OBJECTS ? objectinf[i] : 2.5;
  604.           jp = j <= OBJECTS ? objectinf[j] : 2.5;
  605.           p = (int) (aspectinf[k]*(ip+jp)/2.0*
  606.             (1.0-dabs((real)(grid->v[j][i]))/60.0/aspectorb[k])*1000.0);
  607.           if ((p < pcut || (p == pcut && (i > icut ||
  608.             (i == icut && j > jcut)))) && p > phi) {
  609.             ihi = i; jhi = j; phi = p; ahi = k;
  610.           }
  611.         }
  612.     if (phi < 0)    /* Exit when no less powerful aspect found. */
  613.       break;
  614.     pcut = phi; icut = ihi; jcut = jhi;
  615.     count++;                               /* Display the current aspect.   */
  616. #ifdef INTERPRET
  617.     if (interpret) {                       /* Interpret it if -I in effect. */
  618.       InterpretAspect(jhi, ihi);
  619.       continue;
  620.     }
  621. #endif
  622.     fprintf(S, "%3d: ", count);
  623.     PrintAspect(jhi, ZTOS(planet[jhi]), (int)Sgn(ret[jhi]), ahi,
  624.       ihi, ZTOS(planet[ihi]), (int)Sgn(ret[ihi]), 'a');
  625.     k = grid->v[jhi][ihi];
  626.     AnsiColor(k < 0 ? WHITE : LTGRAY);
  627.     fprintf(S, " - orb: %c%d%c%02d'",
  628.       exdisplay & DASHga ? (k < 0 ? 'a' : 's') : (k < 0 ? '-' : '+'),
  629.       abs(k)/60, DEGR1, abs(k)%60);
  630.     AnsiColor(DKGREEN);
  631.     fprintf(S, " - power:%6.2f\n", (real) phi/1000.0);
  632.     AnsiColor(DEFAULT);
  633.   }
  634. }
  635.  
  636.  
  637. /* Display locations of all midpoints between objects in the chart, */
  638. /* one per line, in sorted zodiac order from zero Aries onward, as  */
  639. /* specified with the -m switch.                                    */
  640.  
  641. void ChartMidpoint()
  642. {
  643.   int mcut = -1, icut, jcut, mlo, ilo, jlo, m, i, j, count = 0;
  644.  
  645.   loop {
  646.     mlo = 21600;
  647.  
  648.     /* Search for the next closest midpoint farther down in the zodiac. */ 
  649.  
  650.     for (i = 1; i < total; i++) if (!ignore[i])
  651.       for (j = i+1; j <= total; j++) if (!ignore[j]) {
  652.         m = (grid->n[j][i]-1)*30*60 + grid->v[j][i];
  653.         if ((m > mcut || (m == mcut && (i > icut ||
  654.           (i == icut && j > jcut)))) && m < mlo) {
  655.           ilo = i; jlo = j; mlo = m;
  656.         }
  657.       }
  658.     if (mlo >= 21600)    /* Exit when no midpoint farther in zodiac found. */
  659.       break;
  660.     mcut = mlo; icut = ilo; jcut = jlo;
  661.     count++;                               /* Display the current midpoint. */
  662. #ifdef INTERPRET
  663.     if (interpret) {                       /* Interpret it if -I in effect. */
  664.       InterpretMidpoint(ilo, jlo);
  665.       continue;
  666.     }
  667. #endif
  668.     fprintf(S, "%4d: ", count);
  669.     PrintZodiac((real) mlo/60.0);
  670.     printc(' ');
  671.     PrintAspect(ilo, ZTOS(planet[ilo]), (int)Sgn(ret[ilo]), 0,
  672.       jlo, ZTOS(planet[jlo]), (int)Sgn(ret[jlo]), 'm');
  673.     AnsiColor(DEFAULT);
  674.     fprintf(S, "-%4d degree span.\n",
  675.       (int) MinDistance(planet[ilo], planet[jlo]));
  676.   }
  677. }
  678.  
  679.  
  680. /* Display locations of the objects on the screen with respect to the local */
  681. /* horizon, as specified with the -Z switch.                                */
  682.  
  683. void ChartHorizon()
  684. {
  685.   real lon, lat, sx, sy, vx, vy,
  686.     lonz[TOTAL+1], latz[TOTAL+1], azi[TOTAL+1], alt[TOTAL+1];
  687.   int i, j, k, tot;
  688.  
  689.   lon = DTOR(Mod(Lon)); lat = DTOR(Lat);
  690.   tot = universe ? total : BASE;
  691.  
  692.   /* First find zenith location on Earth of each object. */
  693.  
  694.   for (i = 1; i <= tot; i++) {
  695.     lonz[i] = DTOR(planet[i]); latz[i] = DTOR(planetalt[i]);
  696.     EclToEqu(&lonz[i], &latz[i]);
  697.   }
  698.  
  699.   /* Then, convert this to local horizon altitude and azimuth. */
  700.  
  701.   for (i = 1; i <= tot; i++) if (i != _MC) {
  702.     lonz[i] = DTOR(Mod(RTOD(lonz[_MC]-lonz[i]+lon)));
  703.     lonz[i] = DTOR(Mod(RTOD(lonz[i]-lon+PI/2.0)));
  704.     EquToLocal(&lonz[i], &latz[i], PI/2.0-lat);
  705.     azi[i] = DEGREES-RTOD(lonz[i]); alt[i] = RTOD(latz[i]);
  706.   }
  707.  
  708.   /* Now, actually print the location of each object. */
  709.  
  710.   fprintf(S,
  711.     "Body Altitude Azimuth  Azi. Vector   %s Vector    Moon Vector\n\n",
  712.     centerplanet ? " Sun" : " Earth");
  713.   for (k = 1; k <= tot; k++) {
  714.     i = k <= BASE ? k : BASE+starname[k-BASE];
  715.     if (ignore[i] || !IsThing(i))
  716.       continue;
  717.     AnsiColor(objectansi[i]);
  718.     fprintf(S, "%-4.4s: ", objectname[i]);
  719.     PrintAltitude(alt[i]);
  720.  
  721.     /* Determine directional vector based on azimuth. */
  722.  
  723.     j = (int) (FRACT(azi[i])*60.0);
  724.     fprintf(S, " %3d%c%02d'", (int) azi[i], DEGR1, j);
  725.     sx = cos(DTOR(azi[i])); sy = sin(DTOR(azi[i]));
  726.     if (dabs(sx) < dabs(sy)) {
  727.       vx = dabs(sx / sy); vy = 1.0;
  728.     } else {
  729.       vy = dabs(sy / sx); vx = 1.0;
  730.     }
  731.     fprintf(S, " (%.2f%c %.2f%c)",
  732.       vy, sy < 0.0 ? 's' : 'n', vx, sx > 0.0 ? 'e' : 'w');
  733.  
  734.     /* Determine distance vector of current object from Sun and Moon. */
  735.  
  736.     vx = azi[1]-azi[i]; vy = azi[2]-azi[i];
  737.     fprintf(S, " [%6.1f%6.1f] [%6.1f%6.1f]",
  738.       dabs(vx) < DEGHALF ? vx : Sgn(vx)*(DEGREES-dabs(vx)), alt[1]-alt[i],
  739.       dabs(vy) < DEGHALF ? vy : Sgn(vy)*(DEGREES-dabs(vy)), alt[2]-alt[i]);
  740.     if (i >= U_LO) {
  741.       if (i <= U_HI)
  742.         fprintf(S, "  Uranian #%d", i-U_LO+1);
  743.       else
  744.         fprintf(S, "  Star #%2d", i-S_LO+1);
  745.     }
  746.     printl();
  747.   }
  748.   AnsiColor(DEFAULT);
  749. }
  750.  
  751.  
  752. /* Display x,y,z locations of each body (in AU) with respect to the Sun */
  753. /* (or whatever the specified center planet is), as in the -S switch.   */
  754. /* These values were already determined when calculating the planet     */
  755. /* positions themselves, so this procedure is basically just a loop.    */
  756.  
  757. void ChartSpace()
  758. {
  759.   real x, y, z;
  760.   int i;
  761.  
  762.   fprintf(S, "Body     Angle    X axis    Y axis    Z axis    Length\n");
  763.   for (i = 0; i <= BASE; i++) {
  764.     if (ignore[i] || i == 2 || !IsObject(i))
  765.       continue;
  766.     AnsiColor(objectansi[i]);
  767.     fprintf(S, "%c%c%c%c: ", OBJNAM(i),
  768.       objectname[i][3] ? objectname[i][3] : ' ');
  769.     x = spacex[i]; y = spacey[i]; z = spacez[i];
  770.     fprintf(S, "[%7.2f] [%7.2f] [%7.3f] [%7.3f] [%7.3f]",
  771.       planet[i], x, y, z, sqrt(x*x+y*y+z*z));
  772.     if (i >= U_LO) {
  773.       if (i <= U_HI)
  774.         fprintf(S, "  Uranian #%d", i-U_LO+1);
  775.       else
  776.         fprintf(S, "  Star #%2d", i-S_LO+1);
  777.     }
  778.     printl();
  779.   }
  780.   AnsiColor(DEFAULT);
  781. }
  782.  
  783.  
  784. /* Print the locations of the astro-graph lines on the Earth as specified */
  785. /* with the -L switch. This includes Midheaven and Nadir lines, zenith    */
  786. /* positions, and locations of Ascendant and Descendant lines.            */
  787.  
  788. void ChartAstroGraph()
  789. {
  790.   crosstruct PTR c;
  791.   real planet1[TOTAL+1], planet2[TOTAL+1], mc[TOTAL+1], ic[TOTAL+1],
  792.     as[TOTAL+1], ds[TOTAL+1], as1[TOTAL+1], ds1[TOTAL+1],
  793.     lo = Lon, longm, w, x, y, z, ad, oa, am, od, dm;
  794.   int occurcount = 0, tot = total, i, j, k, l, m, n;
  795.  
  796.   if (exdisplay & DASHL0)
  797.     {
  798.     Allocate(c, sizeof(crosstruct), crosstruct PTR);
  799.     if (c == NULL
  800. #ifdef PC
  801.       /* For PC's the array better not cross a segment boundary. */
  802.       || HIWORD(LOWORD(c) + sizeof(crosstruct)) > 0
  803. #endif
  804.       ) {
  805.       PrintError("Not enough memory for crossing table.");
  806.       return;
  807.     }
  808.   }
  809.  
  810. #ifdef MATRIX
  811.   for (i = 1; i <= total; i++) {
  812.     planet1[i] = DTOR(planet[i]);
  813.     planet2[i] = DTOR(planetalt[i]);      /* Calculate zenith location on */
  814.     EclToEqu(&planet1[i], &planet2[i]);   /* Earth of each object.        */
  815.   }
  816.  
  817.   /* Print header. */
  818.  
  819.   fprintf(S, "Object :");
  820.   for (j = 0, i = 1; i <= total; i++)
  821.     if (!ignore[i] && IsThing(i)) {
  822.       AnsiColor(objectansi[i]);
  823.       fprintf(S, " %c%c%c", OBJNAM(i));
  824.       j++;
  825.       if (column80 && j >= 17) {
  826.         tot = i;
  827.         i = total;
  828.       }
  829.     }
  830.   AnsiColor(DEFAULT);
  831.   fprintf(S, "\n------ :");
  832.   for (i = 1; i <= tot; i++)
  833.     if (!ignore[i] && IsThing(i))
  834.       fprintf(S, " ###");
  835.  
  836.   /* Print the longitude locations of the Midheaven lines. */
  837.  
  838.   fprintf(S, "\nMidheav: ");
  839.   if (lo < 0.0)
  840.     lo += DEGREES;
  841.   for (i = 1; i <= tot; i++)
  842.     if (!ignore[i] && IsThing(i)) {
  843.     AnsiColor(objectansi[i]);
  844.     x = DTOR(MC)-planet1[i];
  845.     if (x < 0.0)
  846.       x += 2.0*PI;
  847.     if (x > PI)
  848.       x -= 2.0*PI;
  849.     z = lo+RTOD(x);
  850.     if (z > DEGHALF)
  851.       z -= DEGREES;
  852.     mc[i] = z;
  853.     fprintf(S, "%3.0f%c", dabs(z), z < 0.0 ? 'e' : 'w');
  854.   }
  855.   AnsiColor(DEFAULT);
  856.  
  857.   /* The Nadir lines are just always 180 degrees away from the Midheaven. */
  858.  
  859.   fprintf(S, "\nNadir  : ");
  860.   for (i = 1; i <= tot; i++)
  861.     if (!ignore[i] && IsThing(i)) {
  862.     AnsiColor(objectansi[i]);
  863.     z = mc[i] + DEGHALF;
  864.     if (z > DEGHALF)
  865.       z -= DEGREES;
  866.     ic[i] = z;
  867.     fprintf(S, "%3.0f%c", dabs(z), z < 0.0 ? 'e' : 'w');
  868.   }
  869.   AnsiColor(DEFAULT);
  870.  
  871.   /* Print the Zenith latitude locations. */
  872.  
  873.   fprintf(S, "\nZenith : ");
  874.   for (i = 1; i <= tot; i++)
  875.     if (!ignore[i] && IsThing(i)) {
  876.       AnsiColor(objectansi[i]);
  877.       y = RTOD(planet2[i]);
  878.       fprintf(S, "%3.0f%c", dabs(y), y < 0.0 ? 's' : 'n');
  879.       as[i] = ds[i] = as1[i] = ds1[i] = LARGE;
  880.     }
  881.   printl2();
  882.  
  883.   /* Now print the locations of Ascendant and Descendant lines. Since these */
  884.   /* are curvy, we loop through the latitudes, and for each object at each  */
  885.   /* latitude, print the longitude location of the line in question.        */
  886.  
  887.   longm = DTOR(Mod(MC+lo));
  888.   for (j = 80; j >= -80; j -= graphstep) {
  889.     AnsiColor(DEFAULT); 
  890.     fprintf(S, "Asc@%2d%c: ", j >= 0 ? j : -j, j < 0 ? 's' : 'n');
  891.     for (i = 1; i <= tot; i++)
  892.       if (!ignore[i] && IsThing(i)) {
  893.       AnsiColor(objectansi[i]);
  894.       ad = tan(planet2[i])*tan(DTOR(j));
  895.       if (ad*ad > 1.0) {
  896.         fprintf(S, " -- ");
  897.         as1[i] = ds1[i] = ret2[i] = LARGE;
  898.       } else {
  899.         ad = ASIN(ad);
  900.         oa = planet1[i]-ad;
  901.         if (oa < 0.0)
  902.           oa += 2.0*PI;
  903.         am = oa-PI/2.0;
  904.         if (am < 0.0)
  905.           am += 2.0*PI;
  906.         z = longm-am;
  907.         if (z < 0.0)
  908.           z += 2.0*PI;
  909.         if (z > PI)
  910.           z -= 2.0*PI;
  911.         as1[i] = as[i];
  912.         as[i] = z = RTOD(z);
  913.         ret2[i] = ad;
  914.         fprintf(S, "%3.0f%c", dabs(z), z < 0.0 ? 'e' : 'w');
  915.       }
  916.     }
  917.  
  918.     /* Again, the Descendant position is related to the Ascendant's,  */
  919.     /* being a mirror image, so it can be calculated somewhat easier. */
  920.  
  921.     AnsiColor(DEFAULT);
  922.     fprintf(S, "\nDsc@%2d%c: ", j >= 0 ? j : -j, j < 0 ? 's' : 'n');
  923.     for (i = 1; i <= tot; i++)
  924.       if (!ignore[i] && IsThing(i)) {
  925.       AnsiColor(objectansi[i]);
  926.       ad = ret2[i];
  927.       if (ad == LARGE)
  928.         fprintf(S, " -- ");
  929.       else {
  930.         od = planet1[i]+ad;
  931.         dm = od+PI/2.0;
  932.         z = longm-dm;
  933.         if (z < 0.0)
  934.           z += 2.0*PI;
  935.         if (z > PI)
  936.           z -= 2.0*PI;
  937.         ds1[i] = ds[i];
  938.         ds[i] = z = RTOD(z);
  939.         fprintf(S, "%3.0f%c", dabs(z), z < 0.0 ? 'e' : 'w');
  940.       }
  941.     }
  942.     printl();
  943. #endif /* MATRIX */
  944.  
  945.     /* Now, if the -L0 switch is in effect, then take these line positions, */
  946.     /* which we saved in an array above as we were printing them, and       */
  947.     /* calculate and print the latitude crossings.                          */
  948.  
  949.     if (exdisplay & DASHL0)
  950.       for (l = 1; l <= total; l++) if (!ignore[l] && IsThing(l))
  951.         for (k = 1; k <= total; k++) {
  952.           if (ignore[k] || !IsThing(k))
  953.             continue;
  954.           for (n = 0; n <= 1; n++) {
  955.             x = n ? ds1[l] : as1[l];
  956.             y = n ? ds[l] : as[l];
  957.             for (m = 0; m <= 1; m++) {
  958.  
  959.             /* Check if Ascendant/Descendant cross Midheaven/Nadir. */
  960.  
  961.             z = m ? ic[k] : mc[k];
  962.             if (occurcount < MAXCROSS &&
  963.               dabs(x-y) < DEGHALF && Sgn(z-x) != Sgn(z-y)) {
  964.               c->obj1[occurcount] = n ? -l : l;
  965.               c->obj2[occurcount] = m ? -k : k;
  966.               c->lat[occurcount] = (real)j+5.0*dabs(z-y)/dabs(x-y);
  967.               c->lon[occurcount] = z;
  968.               occurcount++;
  969.             }
  970.  
  971.             /* Check if Ascendant/Descendant cross another Asc/Des. */
  972.  
  973.             w = m ? ds1[k] : as1[k];
  974.             z = m ? ds[k] : as[k];
  975.             if (occurcount < MAXCROSS && k > l &&
  976.                 dabs(x-y)+dabs(w-z) < DEGHALF && Sgn(w-x) != Sgn(z-y)) {
  977.               c->obj1[occurcount] = n ? -l : l;
  978.               c->obj2[occurcount] = 100+(m ? -k : k);
  979.               c->lat[occurcount] = (real)j+5.0*
  980.                 dabs(y-z)/(dabs(x-w)+dabs(y-z));
  981.               c->lon[occurcount] = MIN(x, y)+dabs(x-y)*
  982.                 dabs(y-z)/(dabs(x-w)+dabs(y-z));
  983.               occurcount++;
  984.             }
  985.           }
  986.         }
  987.     }
  988.   }
  989.   if ((exdisplay & DASHL0) == 0)
  990.     return;
  991.   printl();
  992.  
  993.   /* Now, print out all the latitude crossings we found.  */
  994.   /* First, we sort them in order of decreasing latitude. */
  995.  
  996.   for (i = 1; i < occurcount; i++) {
  997.     j = i-1;
  998.     while (j >= 0 && c->lat[j] < c->lat[j+1]) {
  999.       SWAP(c->obj1[j], c->obj1[j+1]); SWAP(c->obj2[j], c->obj2[j+1]);
  1000.       SwapReal(&c->lat[j], &c->lat[j+1]); SwapReal(&c->lon[j], &c->lon[j+1]);
  1001.       j--;
  1002.     }
  1003.   }
  1004.   for (i = 1; i < occurcount; i++) {
  1005.     j = abs(c->obj1[i]);
  1006.     AnsiColor(objectansi[j]);
  1007.     fprintf(S, "%c%c%c ", OBJNAM(j));
  1008.     AnsiColor(elemansi[c->obj1[i] > 0 ? 0 : 2]);
  1009.     fprintf(S, "%s ", c->obj1[i] > 0 ? "Ascendant " : "Descendant");
  1010.     AnsiColor(WHITE);
  1011.     fprintf(S, "crosses ");
  1012.     j = abs(c->obj2[i] - (c->obj2[i] < 50 ? 0 : 100));
  1013.     AnsiColor(objectansi[j]);
  1014.     fprintf(S, "%c%c%c ", OBJNAM(j));
  1015.     AnsiColor(elemansi[c->obj2[i] < 50 ?
  1016.       (c->obj2[i] > 0 ? 1 : 3) : (c->obj2[i] > 100 ? 0 : 2)]);
  1017.     fprintf(S, "%s ", c->obj2[i] < 50 ? (c->obj2[i] > 0 ? "Midheaven " :
  1018.       "Nadir     ") : (c->obj2[i] > 100 ? "Ascendant " : "Descendant"));
  1019.     j = (int) (FRACT(dabs(c->lon[i]))*60.0);
  1020.     AnsiColor(DEFAULT);
  1021.     fprintf(S, "at %3d%c%02d'%c, ", (int) dabs(c->lon[i]), DEGR2,
  1022.       j, c->lon[i] < 0.0 ? 'E' : 'W');
  1023.     j = (int) (FRACT(dabs(c->lat[i]))*60.0);
  1024.     fprintf(S, "%2d%c%02d'%c\n", (int) dabs(c->lat[i]), DEGR2,
  1025.       j, c->lat[i] < 0.0 ? 'S' : 'N');
  1026.   }
  1027.   Deallocate(c);
  1028.   if (!occurcount) {
  1029.     AnsiColor(DEFAULT);
  1030.     fprintf(S, "No latitude crossings.\n");
  1031.   }
  1032. }
  1033.  
  1034. /* charts.c */
  1035.