home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / Astro / astrolog / Source / options.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-12  |  56.2 KB  |  1,738 lines

  1. /*
  2. ** Astrolog (Version 4.10) File: options.c
  3. **
  4. ** IMPORTANT NOTICE: the graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1994 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 3/19/1994.
  36. */
  37.  
  38. #include "astrolog.h"
  39.  
  40.  
  41. /*
  42. ******************************************************************************
  43. ** Display Subroutines.
  44. ******************************************************************************
  45. */
  46.  
  47. /* This is a subprocedure of CreateGrid() and CreateGridRelation(). Given */
  48. /* two planets, determine what aspect, if any, is present between them,   */
  49. /* and save the aspect name and orb in the specified grid cell.           */
  50.  
  51. void GetAspect(planet1, planet2, ret1, ret2, i, j)
  52. real *planet1, *planet2, *ret1, *ret2;
  53. int i, j;
  54. {
  55.   int k;
  56.   real l, m;
  57.  
  58.   grid->v[i][j] = grid->n[i][j] = 0;
  59.   l = MinDistance(planet2[i], planet1[j]);
  60.   for (k = aspects; k >= 1; k--) {
  61.     m = l-aspectangle[k];
  62.     if (dabs(m) < Orb(i, j, k)) {
  63.       grid->n[i][j] = k;
  64.  
  65.       /* If -ga switch in effect, then change the sign of the orb to    */
  66.       /* correspond to whether the aspect is applying or separating.    */
  67.       /* To do this, we check the velocity vectors to see if the        */
  68.       /* planets are moving toward, away, or are overtaking each other. */
  69.  
  70.       if (exdisplay & DASHga)
  71.         m = SGN2(ret1[j]-ret2[i])*
  72.           SGN2(MinDifference(planet2[i], planet1[j]))*SGN2(m)*dabs(m);
  73.       grid->v[i][j] = (int) (m*60.0);
  74.     }
  75.   }
  76. }
  77.  
  78.  
  79. /* Set up the aspect/midpoint grid. Allocate memory for this array, if not */
  80. /* already done. Allocation is only done once, first time this is called.  */
  81.  
  82. bool EnsureGrid()
  83. {
  84.   char string[STRING];
  85.  
  86.   if (grid != NULL)
  87.     return TRUE;
  88.   Allocate(grid, sizeof(gridstruct), gridstruct PTR);
  89.   if (grid == NULL
  90. #ifdef PC
  91.     /* For PC's the grid better not cross a segment boundary. */
  92.     || HIWORD(LOWORD(grid) + sizeof(gridstruct)) > 0
  93. #endif
  94.     ) {
  95.     sprintf(string, "Not enough memory for grid (%d bytes).",
  96.       sizeof(gridstruct));
  97.     PrintError(string);
  98.     return FALSE;
  99.   }
  100.   return TRUE;
  101. }
  102.  
  103.  
  104. /* Fill in the aspect grid based on the aspects taking place among the */
  105. /* planets in the present chart. Also fill in the midpoint grid.       */
  106.  
  107. void CreateGrid(acc)
  108. int acc;
  109. {
  110.   int i, j, k;
  111.   real l;
  112.  
  113.   if (!EnsureGrid())
  114.     return;
  115.   for (j = 1; j <= total; j++) if (!ignore[j])
  116.     for (i = 1; i <= total; i++) if (!ignore[i])
  117.  
  118.       /* The parameter 'acc' determine what half of the grid is filled in */
  119.       /* with the aspects and what half is filled in with the midpoints.  */
  120.  
  121.       if (acc ? i > j : i < j)
  122.         GetAspect(planet, planet, ret, ret, i, j);
  123.       else if (acc ? i < j : i > j) {
  124.         l = Mod(Midpoint(planet[i], planet[j])); k = (int)l;    /* Calculate */
  125.         grid->n[i][j] = k/30+1;                                 /* midpoint. */
  126.         grid->v[i][j] = (int)((l-(real)(k/30)*30.0)*60.0);
  127.       } else {
  128.         grid->n[i][j] = ZTOS(planet[j]);
  129.         grid->v[i][j] = (int)(planet[j]-(real)(grid->n[i][j]-1)*30.0);
  130.       }
  131. }
  132.  
  133.  
  134. /* This is similar to the previous function; however, this time fill in the */
  135. /* grid based on the aspects (or midpoints if 'acc' set) taking place among */
  136. /* the planets in two different charts, as in the -g -r0 combination.       */
  137.  
  138. void CreateGridRelation(acc)
  139. int acc;
  140. {
  141.   int i, j, k;
  142.   real l;
  143.  
  144.   if (!EnsureGrid())
  145.     return;
  146.   for (j = 1; j <= total; j++) if (!ignore[j])
  147.     for (i = 1; i <= total; i++) if (!ignore[i])
  148.       if (!acc)
  149.         GetAspect(planet1, planet2, ret1, ret2, i, j);
  150.       else {
  151.         l = Mod(Midpoint(planet2[i], planet1[j])); k = (int)l;  /* Calculate */
  152.         grid->n[i][j] = k/30+1;                                 /* midpoint. */
  153.         grid->v[i][j] = (int)((l-(real)(k/30)*30.0)*60.0);
  154.       }
  155. }
  156.  
  157.  
  158. /*
  159. ******************************************************************************
  160. ** Multiple Chart Display Subprograms.
  161. ******************************************************************************
  162. */
  163.  
  164. /* Print out an aspect (or midpoint if -g0 switch in effect) grid of a      */
  165. /* relationship chart. This is similar to the ChartGrid() routine; however, */
  166. /* here we have both axes labeled with the planets for the two charts in    */
  167. /* question, instead of just a diagonal down the center for only one chart. */
  168.  
  169. void DisplayGridRelation()
  170. {
  171.   int i, j, k, tot = total, temp;
  172.  
  173. #ifdef INTERPRET
  174.   if (interpret && !(exdisplay & DASHg0)) {
  175.     InterpretGridRelation();
  176.     return;
  177.   }
  178. #endif
  179.   fprintf(S, " 2>");
  180.   for (temp = 0, i = 1; i <= total; i++) if (!ignore[i]) {
  181.     printc(BOXV);
  182.     AnsiColor(objectansi[i]);
  183.     fprintf(S, "%c%c%c", OBJNAM(i));
  184.     AnsiColor(DEFAULT);
  185.     temp++;
  186.     if (column80 && temp >= 19) {
  187.       tot = i;
  188.       i = total;
  189.     }
  190.   }
  191.   fprintf(S, "\n1  ");
  192.   for (i = 1; i <= tot; i++) if (!ignore[i]) {
  193.     printc(BOXV);
  194.     AnsiColor(signansi(ZTOS(planet2[i])));
  195.     fprintf(S, "%2d%c", (int)planet2[i] % 30, DEGR0);
  196.     AnsiColor(DEFAULT);
  197.   }
  198.   fprintf(S, "\nV  ");
  199.   for (i = 1; i <= tot; i++) if (!ignore[i]) {
  200.     printc(BOXV);
  201.     temp = ZTOS(planet2[i]);
  202.     AnsiColor(signansi(temp));
  203.     fprintf(S, "%c%c%c", SIGNAM(temp));
  204.     AnsiColor(DEFAULT);
  205.   }
  206.   printl();
  207.   for (j = 1; j <= total; j++) if (!ignore[j])
  208.     for (k = 1; k <= 4; k++) {
  209.       if (k < 2)
  210.         PrintTab(BOXH, 3);
  211.       else if (k == 2) {
  212.         AnsiColor(objectansi[j]);
  213.         fprintf(S, "%c%c%c", OBJNAM(j));
  214.       } else {
  215.         temp = ZTOS(planet1[j]);
  216.         AnsiColor(signansi(temp));
  217.         if (k == 3)
  218.           fprintf(S, "%2d%c", (int)planet1[j] - (temp-1)*30, DEGR0);
  219.         else
  220.           fprintf(S, "%c%c%c", SIGNAM(temp));
  221.       }
  222.       if (k > 1)
  223.         AnsiColor(DEFAULT);
  224.       for (i = 1; i <= tot; i++) if (!ignore[i]) {
  225.         printc(k < 2 ? BOXC : BOXV);
  226.         temp = grid->n[i][j];
  227.         if (k > 1) {
  228.           if (i == j)
  229.             AnsiColor(REVERSE);
  230.           AnsiColor(exdisplay & DASHg0 ? signansi(temp) :
  231.             aspectansi[temp]);
  232.         }
  233.         if (k < 2)
  234.           PrintTab(BOXH, 3);
  235.         else if (k == 2) {
  236.           if (exdisplay & DASHg0)
  237.             fprintf(S, "%c%c%c", SIGNAM(temp));
  238.           else
  239.             fprintf(S, "%s", temp ? aspectabbrev[temp] : "   ");
  240.         } else if (k == 3) {
  241.           if (exdisplay & DASHg0)
  242.             fprintf(S, "%2d%c", grid->v[i][j]/60, DEGR0);
  243.           else
  244.             if (grid->n[i][j]) {
  245.               if (grid->v[i][j] < 6000)
  246.                 fprintf(S, "%c%2d", exdisplay & DASHga ?
  247.                   (grid->v[i][j] < 0 ? 'a' : 's') :
  248.                   (grid->v[i][j] < 0 ? '-' : '+'), abs(grid->v[i][j])/60);
  249.               else
  250.                 fprintf(S, "%3d", abs(temp)/60);
  251.             } else
  252.               fprintf(S, "   ");
  253.         } else {
  254.           if (grid->n[i][j])
  255.             fprintf(S, "%02d'", abs(grid->v[i][j])%60);
  256.           else
  257.             fprintf(S, "   ");
  258.         }
  259.         AnsiColor(DEFAULT);
  260.       }
  261.       printl();
  262.     }
  263. }
  264.  
  265.  
  266. /* Display all aspects between objects in the relationship comparison chart, */
  267. /* one per line, in sorted order based on the total "power" of the aspects,  */
  268. /* as specified with the -r0 -m0 switch combination.                         */
  269.  
  270. void DisplayAspectRelation()
  271. {
  272.   int pcut = 30000, icut, jcut, phi, ihi, jhi, ahi, p, i, j, k, count = 0;
  273.   real ip, jp;
  274.  
  275.   loop {
  276.     phi = -1;
  277.  
  278.     /* Search for the next most powerful aspect in the aspect grid. */
  279.  
  280.     for (i = 1; i <= total; i++) if (!ignore[i])
  281.       for (j = 1; j <= total; j++) if (!ignore[j])
  282.         if (k = grid->n[i][j]) {
  283.           ip = i <= OBJECTS ? objectinf[i] : 2.5;
  284.           jp = j <= OBJECTS ? objectinf[j] : 2.5;
  285.           p = (int) (aspectinf[k]*(ip+jp)/2.0*
  286.             (1.0-dabs((real)(grid->v[i][j]))/60.0/aspectorb[k])*1000.0);
  287.           if ((p < pcut || (p == pcut && (i > icut ||
  288.             (i == icut && j > jcut)))) && p > phi) {
  289.             ihi = i; jhi = j; phi = p; ahi = k;
  290.           }
  291.         }
  292.     if (phi < 0)    /* Exit when no less powerful aspect found. */
  293.       break;
  294.     pcut = phi; icut = ihi; jcut = jhi;
  295.     count++;                               /* Display the current aspect.   */
  296. #ifdef INTERPRET
  297.     if (interpret) {                       /* Interpret it if -I in effect. */
  298.       InterpretAspectRelation(jhi, ihi);
  299.       continue;
  300.     }
  301. #endif
  302.     fprintf(S, "%3d: ", count);
  303.     PrintAspect(jhi, ZTOS(planet1[jhi]), (int)Sgn(ret1[jhi]), ahi,
  304.       ihi, ZTOS(planet2[ihi]), (int)Sgn(ret2[ihi]), 'A');
  305.     k = grid->v[ihi][jhi];
  306.     AnsiColor(k < 0 ? WHITE : LTGRAY);
  307.     fprintf(S, "- orb: %c%d,%02d'",
  308.       exdisplay & DASHga ? (k < 0 ? 'a' : 's') : (k < 0 ? '-' : '+'),
  309.       abs(k)/60, abs(k)%60);
  310.     AnsiColor(DKGREEN);
  311.     fprintf(S, " - power:%6.2f\n", (real) phi/1000.0);
  312.     AnsiColor(DEFAULT);
  313.   }
  314. }
  315.  
  316.  
  317. /* Display locations of all midpoints between objects in the relationship */
  318. /* comparison chart, one per line, in sorted zodiac order from zero Aries */
  319. /* onward, as specified with the -r0 -m switch combination.               */
  320.  
  321. void DisplayMidpointRelation()
  322. {
  323.   int mcut = -1, icut, jcut, mlo, ilo, jlo, m, i, j, count = 0;
  324.  
  325.   loop {
  326.     mlo = 21600;
  327.  
  328.     /* Search for the next closest midpoint farther down in the zodiac. */ 
  329.  
  330.     for (i = 1; i <= total; i++) if (!ignore[i])
  331.       for (j = 1; j <= total; j++) if (!ignore[j]) {
  332.         m = (grid->n[j][i]-1)*30*60 + grid->v[j][i];
  333.         if ((m > mcut || (m == mcut && (i > icut ||
  334.           (i == icut && j > jcut)))) && m < mlo) {
  335.           ilo = i; jlo = j; mlo = m;
  336.         }
  337.       }
  338.     if (mlo >= 21600)    /* Exit when no midpoint farther in zodiac found. */
  339.       break;
  340.     mcut = mlo; icut = ilo; jcut = jlo;
  341.     count++;                               /* Display the current midpoint. */
  342. #ifdef INTERPRET
  343.     if (interpret) {                       /* Interpret it if -I in effect. */
  344.       InterpretMidpointRelation(ilo, jlo);
  345.       continue;
  346.     }
  347. #endif
  348.     fprintf(S, "%4d: ", count);
  349.     PrintZodiac((real) mlo/60.0);
  350.     printc(' ');
  351.     PrintAspect(ilo, ZTOS(planet1[ilo]), (int)Sgn(ret1[ilo]), 0,
  352.       jlo, ZTOS(planet2[jlo]), (int)Sgn(ret2[jlo]), 'M');
  353.     AnsiColor(DEFAULT);
  354.     m = (int)(MinDistance(planet1[ilo], planet2[jlo])*60.0);
  355.     fprintf(S, "-%4d%c%02d' degree span.\n", m/60, DEGR1, m%60);
  356.   }
  357. }
  358.  
  359.  
  360. /* Calculate any of the various kinds of relationship charts. This involves */
  361. /* reading in and storing the planet and house positions for both charts,   */
  362. /* and then combining them in the main single chart in the proper manner.   */
  363. /* If the parameter 'var' is set, then we read the info for the two charts  */
  364. /* from files, otherwise use the info in preset "core" and "second" charts. */
  365.  
  366. void CastRelation(var)
  367. int var;
  368. {
  369.   int mon, day, yea, i;
  370.   real tim, zon, lon, lat, ratio, t1, t2, t;
  371.  
  372.   /* Read in and cast the first chart. */
  373.  
  374.   if (var)
  375.     InputData(filename);
  376.   mon = MM; day = DD; yea = YY; tim = TT; zon = ZZ; lon = OO; lat = AA;
  377.   if (var) {
  378.     SetTwin(MM, DD, YY, TT, ZZ, OO, AA);
  379.   } else {
  380.     SetCore(Mon2, Day2, Yea2, Tim2, Zon2, Lon2, Lat2);
  381.   }
  382.   t1 = CastChart(TRUE);
  383.   for (i = 1; i <= SIGNS; i++) {
  384.     house1[i] = house[i];
  385.     inhouse1[i] = inhouse[i];
  386.   }
  387.   for (i = 1; i <= total; i++) {
  388.     planet1[i] = planet[i];
  389.     planetalt1[i] = planetalt[i];
  390.     ret1[i] = ret[i];
  391.   }
  392.  
  393.   /* Read in the second chart. */
  394.  
  395.   if (var) {
  396.     InputData(filename2);
  397.     if (relation == DASHrp) {
  398.       progress = TRUE;
  399.       Jdp = (real)MdyToJulian(MM, DD, YY) + TT / 24.0;
  400.       SetCore(mon, day, yea, tim, zon, lon, lat);
  401.     }
  402.   } else {
  403.     SetCore(mon, day, yea, tim, zon, lon, lat);
  404.   }
  405.   SetMain(MM, DD, YY, TT, ZZ, OO, AA);
  406.   t2 = CastChart(TRUE);
  407.   for (i = 1; i <= SIGNS; i++) {
  408.     house2[i] = house[i];
  409.     inhouse2[i] = inhouse[i];
  410.   }
  411.   for (i = 1; i <= total; i++) {
  412.     planet2[i] = planet[i];
  413.     planetalt2[i] = planetalt[i];
  414.     ret2[i] = ret[i];
  415.   }
  416.  
  417.   /* Now combine the two charts based on what relation we are doing.   */
  418.   /* For the standard -r synastry chart, use the house cusps of chart1 */
  419.   /* and the planets positions of chart2.                              */
  420.  
  421.   ratio = (real)ratio1 / ((real)(ratio1 + ratio2));
  422.   if (relation <= DASHr)
  423.     for (i = 1; i <= SIGNS; i++)
  424.       house[i] = house1[i];
  425.  
  426.   /* For the -rc composite chart, take the midpoints of the planets/houses. */
  427.  
  428.   else if (relation == DASHrc) {
  429.     for (i = 1; i <= total; i++) {
  430.       planet[i] = RATIO(planet1[i], planet2[i], ratio);
  431.       if (dabs(planet2[i] - planet1[i]) > DEGHALF)
  432.         planet[i] = Mod(planet[i] + DEGREES*ratio);
  433.       planetalt[i] = RATIO(planetalt1[i], planetalt2[i], ratio);
  434.       ret[i] = RATIO(ret1[i], ret2[i], ratio);
  435.     }
  436.     for (i = 1; i <= SIGNS; i++) {
  437.       house[i] = RATIO(house1[i], house2[i], ratio);
  438.       if (dabs(house2[i] - house1[i]) > DEGHALF)
  439.         house[i] = Mod(house[i] + DEGREES*ratio);
  440.     }
  441.  
  442.     /* Make sure we don't have any 180 degree errors in house cusp    */
  443.     /* complement pairs, which may happen if the cusps are far apart. */
  444.  
  445.     for (i = 1; i <= SIGNS; i++)
  446.       if (MinDistance(house[_CAP], Mod(house[i]-STOZ(i+3))) > DEGQUAD)
  447.         house[i] = Mod(house[i]+DEGHALF);
  448.     if (dabs(DEGHALF - MinDistance(house[_ARI], planet[_ASC])) < SMALL)
  449.       planet[_ASC] = Mod(planet[_ASC]+DEGHALF);
  450.  
  451.   /* For the -rm time space midpoint chart, calculate the midpoint time and */
  452.   /* place between the two charts and then recast for the new chart info.   */
  453.  
  454.   } else if (relation == DASHrm) {
  455.     T = RATIO(t1, t2, ratio);
  456.     t = (T*36525.0)+ROUND; JD = floor(t)+2415020.0; TT = FRACT(t)*24.0;
  457.     ZZ = RATIO(DecToDeg(zon), DecToDeg(Zon), ratio); ZZ = DegToDec(ZZ);
  458.     TT = DecToDeg(TT)-DecToDeg(ZZ); TT = DegToDec(TT);
  459.     if (TT < 0.0) {
  460.       TT = DecToDeg(TT)+24.0; TT = DegToDec(TT); JD -= 1.0;
  461.     }
  462.     JulianToMdy(JD, &MM, &DD, &YY);
  463.     OO = RATIO(DecToDeg(lon), DecToDeg(Lon), ratio);
  464.     if (dabs(Lon-lon) > DEGHALF)
  465.       OO = Mod(OO+DEGREES*ratio);
  466.     OO = DegToDec(OO);
  467.     AA = RATIO(DecToDeg(lat), DecToDeg(Lat), ratio); AA = DegToDec(AA);
  468.     SetMain(MM, DD, YY, TT, ZZ, OO, AA);
  469.     CastChart(FALSE);
  470.  
  471.   /* There are a couple of non-astrological charts, which only require the */
  472.   /* number of days that have passed between the two charts to be done.    */
  473.  
  474.   } else
  475.     JD = dabs(t2-t1)*36525.0;
  476.   HousePlace();
  477. }
  478.  
  479.  
  480. /* Given two objects and an aspect between them, or an object and a sign  */
  481. /* that it's entering, print if this is a "major" event, such as a season */
  482. /* change or major lunar phase. This is called from the DisplayInDay      */
  483. /* searching and influence routines. Go an interpretation if need be too. */
  484.  
  485. void PrintInDay(source, aspect, dest)
  486. int source, aspect, dest;
  487. {
  488.   if (aspect == _SIG) {
  489.     if (source == _SUN) {
  490.       AnsiColor(WHITE);
  491.       if (dest == 1)
  492.         fprintf(S, " (Vernal Equinox)");     /* If the Sun changes sign, */
  493.       else if (dest == 4)                    /* then print out if this   */
  494.         fprintf(S, " (Summer Solstice)");    /* is a season change.      */
  495.       else if (dest == 7)
  496.         fprintf(S, " (Autumnal Equinox)");
  497.       else if (dest == 10)
  498.         fprintf(S, " (Winter Solstice)");
  499.     }
  500.   } else if (aspect > 0) {
  501.     if (source == _SUN && dest == _MOO) {
  502.       if (aspect <= _SQU)
  503.         AnsiColor(WHITE);
  504.       if (aspect == _CON)
  505.         fprintf(S, " (New Moon)");     /* Print out if the present */
  506.       else if (aspect == _OPP)         /* aspect is a New, Full,   */
  507.         fprintf(S, " (Full Moon)");    /* or Half Moon.            */
  508.       else if (aspect == _SQU)
  509.         fprintf(S, " (Half Moon)");
  510.     }
  511.   }
  512.   printl();
  513.  
  514. #ifdef INTERPRET
  515.   if (interpret)
  516.     InterpretInDay(source, aspect, dest);
  517. #endif
  518.   AnsiColor(DEFAULT);
  519. }
  520.  
  521.  
  522. /* Given two objects and an aspect (or one object, and an event such as a */
  523. /* sign or direction change) display the configuration in question. This  */
  524. /* is called by the many charts which list aspects among items, such as   */
  525. /* the -m0 aspect lists, -m midpoint lists, -d aspect in day search and   */
  526. /* influence charts, and -t transit search and influence charts.          */
  527.  
  528. void PrintAspect(obj1, sign1, ret1, asp, obj2, sign2, ret2, chart)
  529. int obj1, sign1, ret1, asp, obj2, sign2, ret2;
  530. char chart;
  531. {
  532.   int smart, a, s2;
  533.  
  534.   smart = smartcusp && IsCusp(obj2) && asp == _OPP;
  535.   a = smart ? _CON : asp;
  536.   s2 = smart ? sign1 : sign2;
  537.  
  538.   AnsiColor(objectansi[obj1]);
  539.   if (chart == 't' || chart == 'T')
  540.     fprintf(S, "trans ");
  541.   else if (chart == 'e' || chart == 'u' || chart == 'U')
  542.     fprintf(S, "progr ");
  543.   fprintf(S, "%7.7s", objectname[obj1]);
  544.   AnsiColor(signansi(sign1));
  545.   fprintf(S, " %c%c%c%c%c",
  546.     ret1 > 0 ? '(' : (ret1 < 0 ? '[' : '<'), SIGNAM(sign1),
  547.     ret1 > 0 ? ')' : (ret1 < 0 ? ']' : '>'));
  548.   AnsiColor(a > 0 ? aspectansi[a] : WHITE);
  549.   printc(' ');
  550.   if (a == _SIG)
  551.     fprintf(S, "-->");                       /* Print a sign change. */
  552.   else if (a == _DIR)
  553.     fprintf(S, "S/%c", obj2 ? 'R' : 'D');    /* Print a direction change. */
  554.   else if (a == 0)
  555.     fprintf(S, chart == 'm' ? "&" : "with");
  556.   else
  557.     fprintf(S, "%s", aspectabbrev[a]);       /* Print an aspect. */
  558.   printc(' ');
  559.   if (chart == 'A')
  560.     fprintf(S, "with ");
  561.   if (a == _SIG) {
  562.     AnsiColor(signansi(obj2));
  563.     fprintf(S, "%s", signname[obj2]);
  564.   } else if (a >= 0) {
  565.     AnsiColor(signansi(s2));
  566.     if (chart == 't' || chart == 'u' || chart == 'T' || chart == 'U')
  567.       fprintf(S, "natal ");
  568.     fprintf(S, "%c%c%c%c%c ",
  569.       ret2 > 0 ? '(' : (ret2 < 0 ? '[' : '<'), SIGNAM(s2),
  570.       ret2 > 0 ? ')' : (ret2 < 0 ? ']' : '>'));
  571.     AnsiColor(smart ? signansi((obj2-15) - (obj2 < 23)) : objectansi[obj2]);
  572.     if (smart) {
  573.       fprintf(S, "%dth cusp", (obj2-15) - (obj2 < 23));
  574.       if (obj2 < 23)
  575.         printc(' ');
  576.     } else
  577.       fprintf(S, "%.10s", objectname[obj2]);
  578.   }
  579.   if (chart == 'D' || chart == 'T' || chart == 'U' ||
  580.     chart == 'a' || chart == 'A' || chart == 'm' || chart == 'M')
  581.     PrintTab(' ', 10-StringLen(objectname[obj2]));
  582. }
  583.  
  584.  
  585. /* Search through a day, and print out the times of exact aspects among the  */
  586. /* planets during that day, as specified with the -d switch, as well as the  */
  587. /* times when a planet changes sign or direction. To do this, we cast charts */
  588. /* for the beginning and end of the day, or a part of a day, and do a linear */
  589. /* equation check to see if anything exciting happens during the interval.   */
  590. /* (This is probably the single most complicated procedure in the program.)  */
  591.  
  592. void DisplayInDaySearch(prog)
  593. int prog;
  594. {
  595.   int time[MAXINDAY], source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY],
  596.     sign1[MAXINDAY], sign2[MAXINDAY], D1, D2, occurcount, division, div,
  597.     year, i, j, k, l, s1, s2;
  598.   real divsiz, d1, d2, e1, e2, f1, f2, g;
  599.  
  600.   /* If parameter 'prog' is set, look for changes in a progressed chart. */
  601.  
  602.   year = (exdisplay & DASHdm) && (Mon2 == 0);
  603.   division = (year || prog) ? 1 : divisions;
  604.   divsiz = 24.0/ (real) division*60.0;
  605.  
  606.   /* If -dm in effect, then search through the whole month, day by day. */
  607.  
  608.   if (exdisplay & DASHdm) {
  609.     D1 = 1;
  610.     if (year) {
  611.       Mon2 = 1; D2 = DayInYear(prog ? Yea2 : Yea);
  612.     } else
  613.       D2 = DayInMonth(prog ? Mon2 : Mon, prog ? Yea2 : Yea);
  614.   } else
  615.     D1 = D2 = Day;
  616.  
  617.   /* Start searching the day or days in question for exciting stuff. */
  618.  
  619.   for (Day2 = D1; Day2 <= D2; Day2 = AddDay(Mon, Day2, Yea, 1)) {
  620.     occurcount = 0;
  621.  
  622.     /* Cast chart for beginning of day and store it for future use. */
  623.  
  624.     SetCore(year ? Mon2 : Mon, Day2, Yea, 0.0, Zon, Lon, Lat);
  625.     if (progress = prog) {
  626.       Jdp = (real)MdyToJulian(Mon2, DD, Yea2);
  627.       SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  628.     }
  629.     CastChart(TRUE);
  630.     for (i = 1; i <= SIGNS; i++) {
  631.       house2[i] = house[i];
  632.       inhouse2[i] = inhouse[i];
  633.     }
  634.     for (i = 1; i <= total; i++) {
  635.       planet2[i] = planet[i];
  636.       ret2[i] = ret[i];
  637.     }
  638.  
  639.     /* Now divide the day into segments and search each segment in turn. */
  640.     /* More segments is slower, but has slightly better time accuracy.   */
  641.  
  642.     for (div = 1; div <= division; div++) {
  643.  
  644.       /* Cast the chart for the ending time of the present segment. The   */
  645.       /* beginning time chart is copied from the previous end time chart. */
  646.  
  647.       SetCore(year ? Mon2 : Mon, Day2, Yea,
  648.         DegToDec(24.0*(real)div/(real)division), Zon, Lon, Lat);
  649.       if (prog) {
  650.         Jdp = (real)MdyToJulian(Mon2, DD+1, Yea2);
  651.         SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  652.       }
  653.       CastChart(TRUE);
  654.       for (i = 1; i <= SIGNS; i++) {
  655.         house1[i] = house2[i]; inhouse1[i] = inhouse2[i];
  656.         house2[i] = house[i];  inhouse2[i] = inhouse[i];
  657.       }
  658.       for (i = 1; i <= total; i++) {
  659.         planet1[i] = planet2[i]; ret1[i] = ret2[i];
  660.         planet2[i] = planet[i];  ret2[i] = ret[i];
  661.       }
  662.  
  663.       /* Now search through the present segment for anything exciting. */
  664.  
  665.       for (i = 1; i <= total; i++) if (!ignore[i] && (prog || IsThing(i))) {
  666.         s1 = ZTOS(planet1[i])-1;
  667.         s2 = ZTOS(planet2[i])-1;
  668.  
  669.         /* Does the current planet change into the next or previous sign? */
  670.  
  671.         if (!ignore[i] && s1 != s2 && !ignore[0]) {
  672.           source[occurcount] = i;
  673.           aspect[occurcount] = _SIG;
  674.           dest[occurcount] = s2+1;
  675.           time[occurcount] = (int) (MinDistance(planet1[i],
  676.             (real) (ret1[i] >= 0.0 ? s2 : s1) * 30.0) /
  677.             MinDistance(planet1[i], planet2[i])*divsiz) +
  678.             (int) ((real) (div-1)*divsiz);
  679.           sign1[occurcount] = sign2[occurcount] = s1+1;
  680.           occurcount++;
  681.         }
  682.  
  683.         /* Does the current planet go retrograde or direct? */
  684.  
  685.         if (!ignore[i] && (ret1[i] < 0.0) != (ret2[i] < 0.0) && !ignore2[0]) {
  686.           source[occurcount] = i;
  687.           aspect[occurcount] = _DIR;
  688.           dest[occurcount] = ret2[i] < 0.0;
  689.           time[occurcount] = (int) (dabs(ret1[i])/(dabs(ret1[i])+dabs(ret2[i]))
  690.             *divsiz) + (int) ((real) (div-1)*divsiz);
  691.           sign1[occurcount] = sign2[occurcount] = s1+1;
  692.           occurcount++;
  693.         }
  694.  
  695.         /* Now search for anything making an aspect to the current planet. */
  696.  
  697.         for (j = i+1; j <= total; j++) if (!ignore[j] && (prog || IsThing(j)))
  698.           for (k = 1; k <= aspects; k++) {
  699.             d1 = planet1[i]; d2 = planet2[i];
  700.             e1 = planet1[j]; e2 = planet2[j];
  701.             if (MinDistance(d1, d2) < MinDistance(e1, e2)) {
  702.               SwapReal(&d1, &e1);
  703.               SwapReal(&d2, &e2);
  704.             }
  705.  
  706.             /* We are searching each aspect in turn. Let's subtract the  */
  707.             /* size of the aspect from the angular difference, so we can */
  708.             /* then treat it like a conjunction.                         */
  709.  
  710.             if (MinDistance(e1, Mod(d1-aspectangle[k])) <
  711.                 MinDistance(e2, Mod(d2+aspectangle[k]))) {
  712.               e1 = Mod(e1+aspectangle[k]);
  713.               e2 = Mod(e2+aspectangle[k]);
  714.             } else {
  715.               e1 = Mod(e1-aspectangle[k]);
  716.               e2 = Mod(e2-aspectangle[k]);
  717.             }
  718.  
  719.             /* Check to see if the aspect actually occurs during our    */
  720.             /* segment, making sure we take into account if one or both */
  721.             /* planets are retrograde or if they cross the Aries point. */
  722.  
  723.             f1 = e1-d1;
  724.             if (dabs(f1) > DEGHALF)
  725.               f1 -= Sgn(f1)*DEGREES;
  726.             f2 = e2-d2;
  727.             if (dabs(f2) > DEGHALF)
  728.               f2 -= Sgn(f2)*DEGREES;
  729.             if (MinDistance(Midpoint(d1, d2), Midpoint(e1, e2)) < DEGQUAD &&
  730.               Sgn(f1) != Sgn(f2)) {
  731.               source[occurcount] = i;
  732.               aspect[occurcount] = k;
  733.               dest[occurcount] = j;
  734.  
  735.               /* Horray! The aspect occurs sometime during the interval.   */
  736.               /* Now we just have to solve an equation in two variables to */
  737.               /* find out where the "lines" cross, i.e. the aspect's time. */
  738.  
  739.               f1 = d2-d1;
  740.               if (dabs(f1) > DEGHALF)
  741.                 f1 -= Sgn(f1)*DEGREES;
  742.               f2 = e2-e1;
  743.               if (dabs(f2) > DEGHALF)
  744.                 f2 -= Sgn(f2)*DEGREES;
  745.               g = (dabs(d1-e1) > DEGHALF ?
  746.                 (d1-e1)-Sgn(d1-e1)*DEGREES : d1-e1)/(f2-f1);
  747.               time[occurcount] = (int) (g*divsiz) +
  748.                 (int) ((real) (div-1)*divsiz);
  749.               sign1[occurcount] = (int) (Mod(planet1[i]+
  750.                 Sgn(planet2[i]-planet1[i])*
  751.                 (dabs(planet2[i]-planet1[i]) > DEGHALF ? -1 : 1)*
  752.                 dabs(g)*MinDistance(planet1[i], planet2[i]))/30.0)+1;
  753.               sign2[occurcount] = (int) (Mod(planet1[j]+
  754.                 Sgn(planet2[j]-planet1[j])*
  755.                 (dabs(planet2[j]-planet1[j]) > DEGHALF ? -1 : 1)*
  756.                 dabs(g)*MinDistance(planet1[j], planet2[j]))/30.0)+1;
  757.               occurcount++;
  758.             }
  759.           }
  760.       }
  761.     }
  762.  
  763.     /* After all the aspects, etc, in the day have been located, sort   */
  764.     /* them by time at which they occur, so we can print them in order. */
  765.  
  766.     for (i = 1; i < occurcount; i++) {
  767.       j = i-1;
  768.       while (j >= 0 && time[j] > time[j+1]) {
  769.         SWAP(source[j], source[j+1]);
  770.         SWAP(aspect[j], aspect[j+1]);
  771.         SWAP(dest[j], dest[j+1]);
  772.         SWAP(time[j], time[j+1]);
  773.         SWAP(sign1[j], sign1[j+1]); SWAP(sign2[j], sign2[j+1]);
  774.         j--;
  775.       }
  776.     }
  777.  
  778.     /* Finally, loop through and display each aspect and when it occurs. */
  779.  
  780.     for (i = 0; i < occurcount; i++) {
  781.       s1 = time[i]/60;
  782.       s2 = time[i]-s1*60;
  783.       j = Day2;
  784.       if (year || prog) {
  785.         l = Mon2;
  786.         while (j > (k = DayInMonth(l, prog ? Yea2 : Yea))) {
  787.           j -= k;
  788.           l++;
  789.         }
  790.       }
  791.       SetSave(year || prog ? l : Mon, j, prog ? Yea2 : Yea,
  792.         DegToDec((real)time[i] / 60.0), Zon, Lon, Lat);
  793.       k = DayOfWeek(year || prog ? l : Mon, j, prog ? Yea2 : Yea);
  794.       AnsiColor(rainbowansi[k + 1]);
  795.       fprintf(S, "(%c%c%c) ", DAYNAM(k));
  796.       AnsiColor(DEFAULT);
  797.       fprintf(S, "%s %s ",
  798.         CharDate(year || prog ? l : Mon, j, prog ? Yea2 : Yea, FALSE),
  799.         CharTime(s1, s2));
  800.       PrintAspect(source[i], sign1[i],
  801.         (int)Sgn(ret1[source[i]])+(int)Sgn(ret2[source[i]]),
  802.         aspect[i], dest[i], sign2[i],
  803.         (int)Sgn(ret1[dest[i]])+(int)Sgn(ret2[dest[i]]), prog ? 'e' : 'd');
  804.       PrintInDay(source[i], aspect[i], dest[i]);
  805.     }
  806.   }
  807.  
  808.   /* Recompute original chart placements as we've overwritten them. */
  809.  
  810.   SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  811.   CastChart(TRUE);
  812. }
  813.  
  814.  
  815. /* Based on the given chart information, display all the aspects taking    */
  816. /* place in the chart, as specified with the -D switch. The aspects are    */
  817. /* printed in order of influence determined by treating them as happening  */
  818. /* outside among transiting planets, such that rare outer planet aspects   */
  819. /* are given more power than common ones among inner planets. (This is     */
  820. /* almost identical to the -m0 list, except the influences are different.) */
  821.  
  822. void DisplayInDayInfluence()
  823. {
  824.   int source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY];
  825.   real power[MAXINDAY];
  826.   int occurcount = 0, i, j, k, l, m;
  827.  
  828.   /* Go compute the aspects in the chart. */
  829.  
  830.   i = exdisplay;
  831.   exdisplay |= DASHga;    /* We always want applying vs. separating orbs. */
  832.   CreateGrid(FALSE);
  833.   exdisplay = i;
  834.  
  835.   /* Search through the grid and build up the list of aspects. */
  836.  
  837.   for (j = 2; j <= total; j++) {
  838.     if (ignore[j])
  839.       continue;
  840.     for (i = 1; i < j; i++) {
  841.       if (ignore[i] || (k = grid->n[i][j]) == 0 || occurcount >= MAXINDAY)
  842.         continue;
  843.       if (smartcusp && k > _OPP && IsCusp(j))
  844.         continue;
  845.       source[occurcount] = i; aspect[occurcount] = k; dest[occurcount] = j;
  846.       l = grid->v[i][j];
  847.       power[occurcount] =
  848.         ((i <= BASE ? transitinf[i] : 2.0)/4.0)*
  849.         ((j <= BASE ? transitinf[j] : 2.0)/4.0)*
  850.         aspectinf[k]*(1.0-(real)abs(l)/60.0/Orb(i, j, k));
  851.       occurcount++;
  852.     }
  853.   }
  854.  
  855.   /* Sort aspects by order of influence. */
  856.  
  857.   for (i = 1; i < occurcount; i++) {
  858.     j = i-1;
  859.     while (j >= 0 && power[j] < power[j+1]) {
  860.       SWAP(source[j], source[j+1]);
  861.       SWAP(aspect[j], aspect[j+1]);
  862.       SWAP(dest[j], dest[j+1]);
  863.       SwapReal(&power[j], &power[j+1]);
  864.       j--;
  865.     }
  866.   }
  867.  
  868.   /* Now display each aspect line. */
  869.  
  870.   for (i = 0; i < occurcount; i++) {
  871.     fprintf(S, "%3d: ", i+1);
  872.     j = source[i]; k = aspect[i]; l = dest[i];
  873.     PrintAspect(
  874.       j, ZTOS(planet[j]), (int)Sgn(ret[j]), k,
  875.       l, ZTOS(planet[l]), (int)Sgn(ret[l]), 'D');
  876.     m = grid->v[j][l];
  877.     AnsiColor(m < 0 ? WHITE : LTGRAY);
  878.     fprintf(S, "- %s%2d%c%02d'", m < 0 ? "app" : "sep",
  879.       abs(m)/60, DEGR1, abs(m)%60);
  880.     AnsiColor(DKGREEN);
  881.     fprintf(S, " - power:%6.2f", power[i]);
  882.     PrintInDay(j, k, l);
  883.   }
  884. }
  885.  
  886.  
  887. /* Search through a month, year, or years, and print out the times of exact */
  888. /* transits where planets in the time frame make aspect to the planets in   */
  889. /* some other chart, as specified with the -t switch. To do this, we cast   */
  890. /* charts for the start and end of each month, or within a month, and do an */
  891. /* equation check for aspects to the other base chart during the interval.  */
  892.  
  893. void DisplayTransitSearch(prog)
  894. int prog;
  895. {
  896.   real planet3[TOTAL+1], house3[SIGNS+1], ret3[TOTAL+1];
  897.   _int time[MAXINDAY];
  898.   int source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY], sign[MAXINDAY],
  899.     isret[MAXINDAY], M1, M2, Y1, Y2, occurcount, div, i, j, k, s1, s2, s3;
  900.   real divsiz, daysiz, d, e1, e2, f1, f2;
  901.  
  902.   for (i = 1; i <= SIGNS; i++)
  903.     house3[i] = house[i];
  904.   for (i = 1; i <= total; i++) {
  905.     planet3[i] = planet[i];
  906.     ret3[i] = ret[i];
  907.   }
  908.  
  909.   /* Hacks: Searching month number zero means to search the whole year     */
  910.   /* instead, month by month. Searching a negative month means to search   */
  911.   /* multiple years, with the span off the year stored in the "day" field. */
  912.  
  913.   Y1 = Y2 = Yea2;
  914.   M1 = M2 = Mon2;
  915.   if (Mon2 < 1) {
  916.     M1 = 1; M2 = 12;
  917.     if (Mon2 < 0) {
  918.       if (Day2 < 1) {
  919.         Y1 = Yea2 + Day2 + 1; Y2 = Yea2;
  920.       } else {
  921.         Y1 = Yea2; Y2 = Yea2 + Day2 - 1;
  922.       }
  923.     }
  924.   }
  925.  
  926.   /* Start searching the year or years in question for any transits. */
  927.  
  928.   for (Yea2 = Y1; Yea2 <= Y2; Yea2++)
  929.  
  930.   /* Start searching the month or months in question for any transits. */
  931.  
  932.   for (Mon2 = M1; Mon2 <= M2; Mon2++) {
  933.     daysiz = (real) DayInMonth(Mon2, Yea2)*24.0*60.0;
  934.     divsiz = daysiz/ (real) divisions;
  935.  
  936.     /* Cast chart for beginning of month and store it for future use. */
  937.  
  938.     SetCore(Mon2, 1, Yea2, 0.0, Zon2, Lon2, Lat2);
  939.     if (progress = prog) {
  940.       Jdp = (real)MdyToJulian(MM, DD, YY);
  941.       SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  942.     }
  943.     CastChart(TRUE);
  944.     for (i = 1; i <= SIGNS; i++)
  945.       house2[i] = house[i];
  946.     for (i = 1; i <= OBJECTS; i++) {
  947.       planet2[i] = planet[i];
  948.       ret2[i] = ret[i];
  949.     }
  950.  
  951.     /* Divide our month into segments and then search each segment in turn. */
  952.  
  953.     for (div = 1; div <= divisions; div++) {
  954.       occurcount = 0;
  955.  
  956.       /* Cast the chart for the ending time of the present segment, and */
  957.       /* copy the start time chart from the previous end time chart.    */
  958.  
  959.       d = 1.0 + (daysiz/24.0/60.0)*(real)div/(real)divisions;
  960.       SetCore(Mon2, (int)d, Yea2,
  961.         DegToDec(FRACT(d)*24.0), Zon2, Lon2, Lat2);
  962.       if (prog) {
  963.         Jdp = (real)MdyToJulian(MM, DD, YY);
  964.         SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  965.       }
  966.       CastChart(TRUE);
  967.       for (i = 1; i <= SIGNS; i++) {
  968.         house1[i] = house2[i]; house2[i] = house[i];
  969.       }
  970.       for (i = 1; i <= OBJECTS; i++) {
  971.         planet1[i] = planet2[i]; ret1[i] = ret2[i];
  972.         planet2[i] = planet[i];  ret2[i] = ret[i];
  973.       }
  974.  
  975.       /* Now search through the present segment for any transits. Note that */
  976.       /* stars can be transited, but they can't make transits themselves.   */
  977.  
  978.       for (i = 1; i <= total; i++) if (!ignore[i])
  979.         for (j = 1; j <= BASE; j++) if (!ignore2[j] && (prog || IsThing(j)))
  980.  
  981.           /* Between each pair of planets, check if they make any aspects. */
  982.  
  983.           for (k = 1; k <= aspects; k++) {
  984.             d = planet3[i]; e1 = planet1[j]; e2 = planet2[j];
  985.             if (MinDistance(e1, Mod(d-aspectangle[k])) <
  986.                 MinDistance(e2, Mod(d+aspectangle[k]))) {
  987.               e1 = Mod(e1+aspectangle[k]);
  988.               e2 = Mod(e2+aspectangle[k]);
  989.             } else {
  990.               e1 = Mod(e1-aspectangle[k]);
  991.               e2 = Mod(e2-aspectangle[k]);
  992.             }
  993.  
  994.             /* Check to see if the present aspect actually occurs during the */
  995.             /* segment, making sure we check any Aries point crossings.      */
  996.  
  997.             f1 = e1-d;
  998.             if (dabs(f1) > DEGHALF)
  999.               f1 -= Sgn(f1)*DEGREES;
  1000.             f2 = e2-d;
  1001.             if (dabs(f2) > DEGHALF)
  1002.               f2 -= Sgn(f2)*DEGREES;
  1003.             if (MinDistance(d, Midpoint(e1, e2)) < DEGQUAD &&
  1004.               Sgn(f1) != Sgn(f2) && occurcount < MAXINDAY) {
  1005.  
  1006.               /* Ok, we have found a transit. Now determine the time */
  1007.               /* and save this transit in our list to be printed.    */
  1008.  
  1009.               source[occurcount] = j;
  1010.               aspect[occurcount] = k;
  1011.               dest[occurcount] = i;
  1012.               time[occurcount] = (int) (dabs(f1)/(dabs(f1)+dabs(f2))*divsiz) +
  1013.                 (int) ((real) (div-1)*divsiz);
  1014.               sign[occurcount] = (int) (Mod(
  1015.                 MinDistance(planet1[j], Mod(d-aspectangle[k])) <
  1016.                 MinDistance(planet2[j], Mod(d+aspectangle[k])) ?
  1017.                 d-aspectangle[k] : d+aspectangle[k])/30.0)+1;
  1018.               isret[occurcount] = (int)Sgn(ret1[j]) + (int)Sgn(ret2[j]);
  1019.               occurcount++;
  1020.             }
  1021.           }
  1022.  
  1023.       /* After all transits located, sort them by time at which they occur. */
  1024.  
  1025.       for (i = 1; i < occurcount; i++) {
  1026.         j = i-1;
  1027.         while (j >= 0 && time[j] > time[j+1]) {
  1028.           SWAP(source[j], source[j+1]);
  1029.           SWAP(aspect[j], aspect[j+1]);
  1030.           SWAP(dest[j], dest[j+1]);
  1031.           SWAP(time[j], time[j+1]);
  1032.           SWAP(sign[j], sign[j+1]);
  1033.           SWAP(isret[j], isret[j+1]);
  1034.           j--;
  1035.         }
  1036.       }
  1037.  
  1038.       /* Now loop through list and display all the transits. */
  1039.  
  1040.       for (i = 0; i < occurcount; i++) {
  1041.         k = smartcusp && IsCusp(dest[i]);
  1042.         if (k && aspect[i] > _OPP)
  1043.           continue;
  1044.         else
  1045.           k = k && aspect[i] == _OPP;
  1046.         s1 = time[i]/24/60;
  1047.         s3 = time[i]-s1*24*60;
  1048.         s2 = s3/60;
  1049.         s3 = s3-s2*60;
  1050.         SetSave(Mon2, s1+1, Yea2,
  1051.           DegToDec((real)(time[i]-s1*24*60) / 60.0), Zon2, Lon2, Lat2);
  1052.         fprintf(S, "%s %s ",
  1053.           CharDate(Mon2, s1+1, Yea2, FALSE), CharTime(s2, s3));
  1054.         PrintAspect(source[i], sign[i], isret[i], aspect[i],
  1055.           dest[i], ZTOS(planet3[dest[i]]), (int)Sgn(ret3[dest[i]]),
  1056.           prog ? 'u' : 't');
  1057.  
  1058.         /* Check for a Solar, Lunar, or any other return. */
  1059.  
  1060.         if (aspect[i] == _CON && source[i] == dest[i]) {
  1061.           AnsiColor(WHITE);
  1062.           fprintf(S, " (%s Return)", source[i] == _SUN ? "Solar" :
  1063.             (source[i] == _MOO ? "Lunar" : objectname[source[i]]));
  1064.         }
  1065.         printl();
  1066. #ifdef INTERPRET
  1067.         if (interpret)
  1068.           InterpretTransit(source[i], aspect[i], dest[i]);
  1069. #endif
  1070.         AnsiColor(DEFAULT);
  1071.       }
  1072.     }
  1073.   }
  1074. }
  1075.  
  1076.  
  1077. /* Given an arbitrary day, determine what aspects are made between this */
  1078. /* transiting chart and the given natal chart, as specified with the -T */
  1079. /* switch, and display the transits in order sorted by influence.       */
  1080.  
  1081. void DisplayTransitInfluence(prog)
  1082. int prog;
  1083. {
  1084.   int source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY];
  1085.   real power[MAXINDAY];
  1086.   byte ignore3[TOTAL+1];
  1087.   int occurcount = 0, i, j, k, l, m;
  1088.  
  1089.   /* Cast the natal and transiting charts as with a relationship chart. */
  1090.  
  1091.   for (i = 1; i <= SIGNS; i++)
  1092.     house1[i] = house[i];
  1093.   for (i = 1; i <= total; i++) {
  1094.     planet1[i] = planet[i];
  1095.     ret1[i] = ret[i];
  1096.   }
  1097.   SetCore(Mon2, Day2, Yea2, Tim2, Zon2, Lon2, Lat2);
  1098.   if (progress = prog) {
  1099.     Jdp = (real)MdyToJulian(MM, DD, YY);
  1100.     MM = Mon; DD = Day; YY = Yea;
  1101.   }
  1102.   CastChart(TRUE);
  1103.   for (i = 1; i <= SIGNS; i++)
  1104.     house2[i] = house[i];
  1105.   for (i = 1; i <= total; i++) {
  1106.     planet2[i] = planet[i];
  1107.     ret2[i] = ret[i];
  1108.   }
  1109.  
  1110.   /* Do a relationship aspect grid to get the transits. We have to make and */
  1111.   /* restore three changes to get it right for this chart. (1) We make the  */
  1112.   /* natal planets have zero velocity so applying vs. separating is only a  */
  1113.   /* function of the transiter. (2) We force applying vs. separating orbs   */
  1114.   /* regardless if -ga or -ma is in effect or not. (3) Finally we tweak the */
  1115.   /* main restrictions to allow for transiting objects not restricted.      */
  1116.  
  1117.   for (i = 1; i <= total; i++) {
  1118.     ret[i] = ret1[i];
  1119.     ret1[i] = 0.0;
  1120.     ignore3[i] = ignore[i];
  1121.     ignore[i] = ignore[i] && ignore2[i];
  1122.   }
  1123.   i = exdisplay;
  1124.   exdisplay |= DASHga;
  1125.   CreateGridRelation(FALSE);
  1126.   exdisplay = i;
  1127.   for (i = 1; i <= total; i++) {
  1128.     ret1[i] = ret[i];
  1129.     ignore[i] = ignore3[i];
  1130.   }
  1131.  
  1132.   /* Loop through the grid, and build up a list of the valid transits. */
  1133.  
  1134.   for (i = 1; i <= BASE; i++) {
  1135.     if (ignore2[i] || !IsThing(i))
  1136.       continue;
  1137.     for (j = 1; j <= total; j++) {
  1138.       if (ignore[j] || (k = grid->n[i][j]) == 0 || occurcount >= MAXINDAY)
  1139.         continue;
  1140.       if (smartcusp && k > _OPP && IsCusp(j))
  1141.         continue;
  1142.       source[occurcount] = i; aspect[occurcount] = k; dest[occurcount] = j;
  1143.       l = grid->v[i][j];
  1144.       power[occurcount] = transitinf[i]*
  1145.         ((j <= BASE ? objectinf[j] : 2.0)/4.0)*aspectinf[k]*
  1146.         (1.0-(real)abs(l)/60.0/Orb(i, j, k));
  1147.       occurcount++;
  1148.     }
  1149.   }
  1150.  
  1151.   /* After all transits located, sort them by their total power. */
  1152.  
  1153.   for (i = 1; i < occurcount; i++) {
  1154.     j = i-1;
  1155.     while (j >= 0 && power[j] < power[j+1]) {
  1156.       SWAP(source[j], source[j+1]);
  1157.       SWAP(aspect[j], aspect[j+1]);
  1158.       SWAP(dest[j], dest[j+1]);
  1159.       SwapReal(&power[j], &power[j+1]);
  1160.       j--;
  1161.     }
  1162.   }
  1163.  
  1164.   /* Now loop through list and display each transit in effect at the time. */
  1165.  
  1166.   for (i = 0; i < occurcount; i++) {
  1167.     k = aspect[i];
  1168.     l = source[i];
  1169.     fprintf(S, "%3d: ", i+1);
  1170.     j = ZTOS(planet2[l]);
  1171.     PrintAspect(l, j, (int)Sgn(ret2[l]), k,
  1172.       dest[i], ZTOS(planet1[dest[i]]), (int)Sgn(ret1[dest[i]]),
  1173.       prog ? 'U' : 'T');
  1174.     m = grid->v[l][dest[i]];
  1175.     AnsiColor(m < 0 ? WHITE : LTGRAY);
  1176.     fprintf(S, "- %s%2d%c%02d'", m < 0 ? "app" : "sep",
  1177.       abs(m)/60, DEGR1, abs(m)%60);
  1178.     AnsiColor(DKGREEN);
  1179.     fprintf(S, " - power:%6.2f", power[i]);
  1180.     if (k == _CON && l == dest[i]) {       /* Print a small "R" for returns. */
  1181.       AnsiColor(WHITE);
  1182.       fprintf(S, " R");
  1183.     }
  1184.     printl();
  1185. #ifdef INTERPRET
  1186.     if (interpret)
  1187.       InterpretTransit(l, k, dest[i]);
  1188. #endif
  1189.     AnsiColor(DEFAULT);
  1190.   }
  1191. }
  1192.  
  1193.  
  1194. /* Given the zodiac location of a planet in the sky and its declination,   */
  1195. /* and a location on the Earth, compute the azimuth and altitude of where  */
  1196. /* on the local horizon sky the planet would appear to one at the given    */
  1197. /* location. A reference MC position at Greenwich is also needed for this. */
  1198.  
  1199. void EclToHorizon(azi, alt, planet, planetalt, lon, lat, mc)
  1200. real *azi, *alt, planet, planetalt, lon, lat, mc;
  1201. {
  1202.   real lonz, latz;
  1203.  
  1204.   lonz = DTOR(planet); latz = DTOR(planetalt);
  1205.   EclToEqu(&lonz, &latz);
  1206.   lonz = DTOR(Mod(RTOD(mc-lonz+lon)));
  1207.   lonz = DTOR(Mod(RTOD(lonz-lon+PI/2.0)));
  1208.   EquToLocal(&lonz, &latz, PI/2.0-lat);
  1209.   *azi = DEGREES-RTOD(lonz); *alt = RTOD(latz);
  1210. }
  1211.  
  1212.  
  1213. /* Display a list of planetary rising times relative to the local horizon */
  1214. /* for the day indicated in the chart information, as specified with the  */
  1215. /* -Zd switch. For the day, the time each planet rises (transits horizon  */
  1216. /* in East half of sky), sets (transits horizon in West), reaches its     */
  1217. /* zenith point (transits meridian in South half of sky), and nadirs      */
  1218. /* transits meridian in North), is displayed.                             */
  1219.  
  1220. void DisplayInDayHorizon()
  1221. {
  1222.   int source[MAXINDAY], type[MAXINDAY], time[MAXINDAY], sign[MAXINDAY],
  1223.     isret[MAXINDAY], occurcount, division, div, s1, s2, i, j;
  1224.   real planetalt1[TOTAL+1], planetalt2[TOTAL+1], azialt[MAXINDAY],
  1225.     lon, lat, mc1, mc2, azi1, alt1, azi2, alt2, d, k;
  1226.  
  1227.   lon = DTOR(Mod(Lon)); lat = DTOR(Lat);
  1228.   division = divisions * 4;
  1229.   occurcount = 0;
  1230.  
  1231.   SetCore(Mon, Day, Yea, 0.0, Zon, Lon, Lat);
  1232.   CastChart(TRUE);
  1233.   mc2 = DTOR(planet[_MC]); k = DTOR(planetalt[_MC]);
  1234.   EclToEqu(&mc2, &k);
  1235.   for (i = 1; i <= SIGNS; i++) {
  1236.     house2[i] = house[i];
  1237.     inhouse2[i] = inhouse[i];
  1238.   }
  1239.   for (i = 1; i <= total; i++) {
  1240.     planet2[i] = planet[i];
  1241.     planetalt2[i] = planetalt[i];
  1242.     ret2[i] = ret[i];
  1243.   }
  1244.  
  1245.   /* Loop thorough the day, dividing it into a certain number of segments. */
  1246.   /* For each segment we get the planet positions at its endpoints.        */
  1247.  
  1248.   for (div = 1; div <= division; div++) {
  1249.     SetCore(Mon, Day, Yea,
  1250.       DegToDec(24.0*(real)div/(real)division), Zon, Lon, Lat);
  1251.     CastChart(TRUE);
  1252.     mc1 = mc2;
  1253.     mc2 = DTOR(planet[_MC]); k = DTOR(planetalt[_MC]);
  1254.     EclToEqu(&mc2, &k);
  1255.     for (i = 1; i <= SIGNS; i++) {
  1256.       house1[i] = house2[i]; inhouse1[i] = inhouse2[i];
  1257.       house2[i] = house[i];  inhouse2[i] = inhouse[i];
  1258.     }
  1259.     for (i = 1; i <= total; i++) {
  1260.       planet1[i] = planet2[i]; planet2[i] = planet[i];
  1261.       planetalt1[i] = planetalt2[i]; planetalt2[i] = planetalt[i];
  1262.       ret1[i] = ret2[i]; ret2[i] = ret[i];
  1263.     }
  1264.  
  1265.     /* For our segment, check to see if each planet during it rises, sets, */
  1266.     /* reaches its zenith, or reaches its nadir.                           */
  1267.  
  1268.     for (i = 1; i <= total; i++) if (!ignore[i] && IsThing(i)) {
  1269.       EclToHorizon(&azi1, &alt1, planet1[i], planetalt1[i], lon, lat, mc1);
  1270.       EclToHorizon(&azi2, &alt2, planet2[i], planetalt2[i], lon, lat, mc2);
  1271.       j = 0;
  1272.       /* Check for transits to the horizon. */
  1273.       if ((alt1 > 0.0) != (alt2 > 0.0)) {
  1274.         d = dabs(alt1)/(dabs(alt1)+dabs(alt2));
  1275.         k = Mod(azi1 + d*MinDifference(azi1, azi2));
  1276.         j = 1 + 2*(MinDistance(k, DEGHALF) < DEGQUAD);
  1277.       /* Check for transits to the meridian. */
  1278.       } else if (Sgn(MinDifference(azi1, DEGQUAD)) !=
  1279.         Sgn(MinDifference(azi2, DEGQUAD))) {
  1280.         j = 2 + 2*(MinDistance(azi1, DEGQUAD) < DEGQUAD);
  1281.         d = dabs(azi1 - (j > 2 ? DEGQUAD : 270.0))/MinDistance(azi1, azi2);
  1282.         k = alt1 + d*(alt2-alt1);
  1283.       }
  1284.       if (j && occurcount < MAXINDAY) {
  1285.         source[occurcount] = i;
  1286.         type[occurcount] = j;
  1287.         time[occurcount] = (int)(24.0*((real)(div-1)+d)/(real)division*60.0);
  1288.         sign[occurcount] = (int)Mod(planet1[i] +
  1289.           d*MinDifference(planet1[i], planet2[i]))/30 + 1;
  1290.         isret[occurcount] = (int)Sgn(ret1[i]) + (int)Sgn(ret2[i]);
  1291.         azialt[occurcount] = k;
  1292.         SetSave(Mon, Day, Yea, DegToDec((real)time[occurcount] / 60.0),
  1293.           Zon, Lon, Lat);
  1294.         occurcount++;
  1295.       }
  1296.     }
  1297.   }
  1298.  
  1299.   /* Sort each event in order of time when it happens during the day. */
  1300.  
  1301.   for (i = 1; i < occurcount; i++) {
  1302.     j = i-1;
  1303.     while (j >= 0 && time[j] > time[j+1]) {
  1304.       SWAP(source[j], source[j+1]);
  1305.       SWAP(type[j], type[j+1]);
  1306.       SWAP(time[j], time[j+1]);
  1307.       SWAP(sign[j], sign[j+1]);
  1308.       SWAP(isret[j], isret[j+1]);
  1309.       SwapReal(&azialt[j], &azialt[j+1]);
  1310.       j--;
  1311.     }
  1312.   }
  1313.  
  1314.   /* Finally display the list showing each event and when it occurs. */
  1315.  
  1316.   for (i = 0; i < occurcount; i++) {
  1317.     SetSave(Mon, Day, Yea,
  1318.       DegToDec((real)time[i] / 60.0), Zon, Lon, Lat);
  1319.     j = DayOfWeek(Mon, Day, Yea);
  1320.     AnsiColor(rainbowansi[j + 1]);
  1321.     fprintf(S, "(%c%c%c) ", DAYNAM(j));
  1322.     AnsiColor(DEFAULT);
  1323.     s1 = time[i]/60;
  1324.     s2 = time[i]-s1*60;
  1325.     fprintf(S, "%s %s ", CharDate(Mon, Day, Yea, FALSE), CharTime(s1, s2));
  1326.     AnsiColor(objectansi[source[i]]);
  1327.     fprintf(S, "%7.7s ", objectname[source[i]]);
  1328.     AnsiColor(signansi(sign[i]));
  1329.     fprintf(S, "%c%c%c%c%c ",
  1330.       isret[i] > 0 ? '(' : (isret[i] < 0 ? '[' : '<'), SIGNAM(sign[i]),
  1331.       isret[i] > 0 ? ')' : (isret[i] < 0 ? ']' : '>'));
  1332.     AnsiColor(elemansi[type[i]-1]);
  1333.     if (type[i] == 1)
  1334.       fprintf(S, "rises  ");
  1335.     else if (type[i] == 2)
  1336.       fprintf(S, "zeniths");
  1337.     else if (type[i] == 3)
  1338.       fprintf(S, "sets   ");
  1339.     else
  1340.       fprintf(S, "nadirs ");
  1341.     AnsiColor(DEFAULT);
  1342.     fprintf(S, " at ");
  1343.     if (type[i] & 1) {
  1344.       j = (int) (FRACT(azialt[i])*60.0);
  1345.       fprintf(S, "%3d%c%02d'", (int) azialt[i], DEGR1, j);
  1346.  
  1347.       /* For rising and setting events, we'll also display a direction  */
  1348.       /* vector to make the 360 degree azimuth value thought of easier. */
  1349.  
  1350.       azi1 = cos(DTOR(azialt[i])); alt1 = sin(DTOR(azialt[i]));
  1351.       if (dabs(azi1) < dabs(alt1)) {
  1352.         azi2 = dabs(azi1 / alt1); alt2 = 1.0;
  1353.       } else {
  1354.         alt2 = dabs(alt1 / azi1); azi2 = 1.0;
  1355.       }
  1356.       fprintf(S, " (%.2f%c %.2f%c)",
  1357.         alt2, alt1 < 0.0 ? 's' : 'n', azi2, azi1 > 0.0 ? 'e' : 'w');
  1358.     } else
  1359.       PrintAltitude(azialt[i]);
  1360.     printl();
  1361.   }
  1362.  
  1363.   /* Recompute original chart placements as we've overwritten them. */
  1364.  
  1365.   SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  1366.   CastChart(TRUE);
  1367. }
  1368.  
  1369.  
  1370. /* Print out an ephemeris - the positions of the planets (at the time in the */
  1371. /* current chart) each day during a specified month, as done with the -E     */
  1372. /* switch. Display the ephemeris for the whole year if -Ey is in effect.     */
  1373.  
  1374. void DisplayEphemeris()
  1375. {
  1376.   int M0, M1, M2, daysiz, i, j, k, s, d, m;
  1377.  
  1378.   /* If -Ey is in effect, then loop through all months in the whole year. */
  1379.  
  1380.   if (exdisplay & DASHEy) {
  1381.     M1 = 1; M2 = 12;
  1382.   } else
  1383.     M1 = M2 = Mon;
  1384.  
  1385.   /* Loop through the month or months in question, printing each ephemeris. */
  1386.  
  1387.   for (M0 = M1; M0 <= M2; M0++) {
  1388.     daysiz = DayInMonth(M0, Yea);
  1389.     fprintf(S, eurodate ? "Dy/Mo/Yr" : "Mo/Dy/Yr");
  1390.     for (k = 0, j = 1; j <= total; j++) {
  1391.       if (!ignore[j] && IsThing(j)) {
  1392.         fprintf(S, "  %c%c%c%c ", OBJNAM(j), objectname[j][3] != 0 ?
  1393.           objectname[j][3] : ' ');
  1394.         k++;
  1395.         if (column80 && k >= 10)
  1396.           j = total;
  1397.       }
  1398.     }
  1399.     printl();
  1400.     for (i = 1; i <= daysiz; i = AddDay(M0, i, Yea, 1)) {
  1401.  
  1402.       /* Loop through each day in the month, casting a chart for that day. */
  1403.  
  1404.       SetCore(M0, i, Yea, Tim, Zon, Lon, Lat);
  1405.       CastChart(TRUE);
  1406.       fprintf(S, "%s ", CharDate(M0, i, Yea, -1));
  1407.       for (k = 0, j = 1; j <= total; j++)
  1408.         if (!ignore[j] && IsThing(j)) {
  1409.           AnsiColor(objectansi[j]);
  1410.           s = ZTOS(planet[j]);
  1411.           d = (int) planet[j] - (s-1)*30;
  1412.           m = (int) (FRACT(planet[j])*60.0);
  1413.           fprintf(S, "%2d%s%02d%c", d, signabbrev[s], m,
  1414.             ret[j] >= 0.0 ? ' ' : '.');
  1415.           k++;
  1416.           if (column80 && k >= 10)
  1417.             j = total;
  1418.         }
  1419.       printl();
  1420.       AnsiColor(DEFAULT);
  1421.     }
  1422.     if (M0 < M2)
  1423.       printl();
  1424.   }
  1425. }
  1426.  
  1427.  
  1428. /* Display a calendar for the given month in the chart, as specified with  */
  1429. /* with the -K switch. When color is on, the title is white, weekends are  */
  1430. /* highlighted in red, and the specific day in the chart is colored green. */
  1431.  
  1432. void DisplayCalendarMonth()
  1433. {
  1434.   int i, j, k;
  1435.  
  1436.   AnsiColor(WHITE);
  1437.   PrintTab(' ', 16-StringLen(monthname[Mon]) >> 1);
  1438.   fprintf(S, "%s%5d\n", monthname[Mon], Yea);
  1439.   for (i = 0; i < 7; i++)
  1440.     fprintf(S, "%c%c%c", dayname[i][0], dayname[i][1], i < 6 ? ' ' : '\n');
  1441.   j = DayOfWeek(Mon, 1, Yea);
  1442.   AnsiColor(DEFAULT);
  1443.   for (i = 0; i < j; i++) {
  1444.     if (i == 0)
  1445.       AnsiColor(RED);
  1446.     fprintf(S, "-- ");
  1447.     if (i == 0)
  1448.       AnsiColor(DEFAULT);
  1449.   }
  1450.   k = DayInMonth(Mon, Yea);
  1451.   for (i = 1; i <= k; i = AddDay(Mon, i, Yea, 1)) {
  1452.     if (i == (int)Day)
  1453.       AnsiColor(GREEN);
  1454.     else if (j == 0 || j == 6)
  1455.       AnsiColor(RED);
  1456.     fprintf(S, "%2d", i);
  1457.     if (j == 0 || j == 6 || i == Day)
  1458.       AnsiColor(DEFAULT);
  1459.     if (j < 6) {
  1460.       j++;
  1461.       printc(' ');
  1462.     } else {
  1463.       j = 0;
  1464.       printl();
  1465.     }
  1466.   }
  1467.   while (j > 0 && j < 7) {
  1468.     if (j == 6)
  1469.       AnsiColor(RED);
  1470.     j++;
  1471.     fprintf(S, "--%c", j < 7 ? ' ' : '\n');
  1472.   }
  1473.   AnsiColor(DEFAULT);
  1474. }
  1475.  
  1476.  
  1477. /* Display a calendar for the entire year given in the chart, as specified */
  1478. /* with the -Ky switch. This is just like twelve of the individual month   */
  1479. /* calendars above displayed together, with same color highlights and all. */
  1480.  
  1481. void DisplayCalendarYear()
  1482. {
  1483.   int r, w, c, m, d, dy, p[3], l[3], n[3];
  1484.  
  1485.   dy = DayOfWeek(1, 1, Yea);
  1486.   for (r = 0; r < 4; r++) {    /* Loop over one set of three months */
  1487.     AnsiColor(WHITE);
  1488.     for (c = 0; c < 3; c++) {
  1489.       m = r*3+c+1;
  1490.       PrintTab(' ', 16-StringLen(monthname[m]) >> 1);
  1491.       fprintf(S, "%s%5d", monthname[m], Yea);
  1492.       if (c < 2)
  1493.         PrintTab(' ', 20 + MONTHSPACE -
  1494.           (16-StringLen(monthname[m]) >> 1) - StringLen(monthname[m]) - 5);
  1495.     }
  1496.     printl();
  1497.     for (c = 0; c < 3; c++) {
  1498.       for (d = 0; d < 7; d++)
  1499.         fprintf(S, "%c%c%c", dayname[d][0], dayname[d][1],
  1500.           d < 6 || c < 2 ? ' ' : '\n');
  1501.       if (c < 2)
  1502.         PrintTab(' ', MONTHSPACE-1);
  1503.       m = r*3+c+1;
  1504.       p[c] = dy % 7;
  1505.       l[c] = DayInMonth(m, Yea);
  1506.       n[c] = 0;
  1507.       dy += DaysInMonth(m, Yea);
  1508.     }
  1509.     for (w = 0; w < 6; w++) {      /* Loop over one set of week rows */
  1510.       for (c = 0; c < 3; c++) {    /* Loop over one week in a month  */
  1511.         m = r*3+c+1;
  1512.         d = 0;
  1513.         if (w == 0)
  1514.           while (d < p[c]) {
  1515.             if (d == 0)
  1516.               AnsiColor(RED);
  1517.             fprintf(S, "-- ");
  1518.             if (d == 0)
  1519.               AnsiColor(DEFAULT);
  1520.             d++;
  1521.           }
  1522.         AnsiColor(DEFAULT);
  1523.         while (d < 7 && n[c] < l[c]) {
  1524.           n[c] = AddDay(m, n[c], Yea, 1);
  1525.           if (n[c] == Day && m == Mon)
  1526.             AnsiColor(GREEN);
  1527.           else if (d == 0 || d == 6)
  1528.             AnsiColor(RED);
  1529.           fprintf(S, "%2d%c", n[c], d < 6 || c < 2 ? ' ' : '\n');
  1530.           if (d == 0 || d == 6 || (n[c] == Day && m == Mon))
  1531.             AnsiColor(DEFAULT);
  1532.           d++;
  1533.         }
  1534.         while (d < 7) {
  1535.           if (d == 0 || d == 6)
  1536.             AnsiColor(RED);
  1537.           fprintf(S, "--%c", d < 6 || c < 2 ? ' ' : '\n');
  1538.           if (d == 0)
  1539.             AnsiColor(DEFAULT);
  1540.           d++;
  1541.         }
  1542.         if (c < 2)
  1543.           PrintTab(' ', MONTHSPACE-1);
  1544.       }
  1545.     }
  1546.     if (r < 3)
  1547.       printl();
  1548.   }
  1549.   AnsiColor(DEFAULT);
  1550. }
  1551.  
  1552.  
  1553. /* Display either a biorhythm chart or the time difference in various units */
  1554. /* between two charts, i.e. two types of relationship "charts" that aren't  */
  1555. /* related in any way to planetary positions, as specified by either the    */
  1556. /* -rb or -rd switches, respectively.                                       */
  1557.  
  1558. void DisplayRelation()
  1559. {
  1560. #ifdef BIORHYTHM
  1561.   int i, j;
  1562.   real k, l;
  1563. #endif
  1564.  
  1565.   /* If we are calculating the difference between two dates, then display */
  1566.   /* the value and return, as with the -rd switch.                        */
  1567.  
  1568.   if (relation == DASHrd) {
  1569.     fprintf(S, "Differences between the dates in the two charts:\n");
  1570.     AnsiColor(rainbowansi[1]); fprintf(S, "Years  : %.0f\n", JD/365.25);
  1571.     AnsiColor(rainbowansi[2]); fprintf(S, "Months : %.0f\n", JD/(365.25/12));
  1572.     AnsiColor(rainbowansi[3]); fprintf(S, "Weeks  : %.0f\n", JD/7.0);
  1573.     AnsiColor(rainbowansi[4]); fprintf(S, "Days   : %.0f\n", JD);
  1574.     AnsiColor(rainbowansi[5]); fprintf(S, "Hours  : %.0f\n", JD*24.0);
  1575.     AnsiColor(rainbowansi[6]); fprintf(S, "Minutes: %.0f\n", JD*24.0*60.0);
  1576.     AnsiColor(rainbowansi[7]); fprintf(S, "Seconds: %.0f\n", JD*24.0*3600.0);
  1577.     AnsiColor(DEFAULT);
  1578.     return;
  1579.   }
  1580.  
  1581. #ifdef BIORHYTHM
  1582.   /* If we are doing a biorhythm (-rb switch), then we'll calculate it for */
  1583.   /* someone born on the older date, at the time of the younger date. Loop */
  1584.   /* through the week preceeding and following the date in question.       */
  1585.  
  1586.   JD = floor(JD + ROUND);
  1587.   for (JD -= 7.0, i = -7; i <= 7; i++, JD += 1.0) {
  1588.     if (i == 0)
  1589.       AnsiColor(WHITE);
  1590.     else if (i == 1)
  1591.       AnsiColor(DEFAULT);
  1592.     fprintf(S, "T%c%d Day%c:",
  1593.       i < 0 ? '-' : '+', abs(i), abs(i) != 1 ? 's' : ' ');
  1594.     for (j = 1; j <= 3; j++) {
  1595.       printc(' ');
  1596.       switch (j) {
  1597.       case 1: k = _PHY; AnsiColor(RED);   fprintf(S, "Physical");     break;
  1598.       case 2: k = _EMO; AnsiColor(BLUE);  fprintf(S, "Emotional");    break;
  1599.       case 3: k = _INT; AnsiColor(GREEN); fprintf(S, "Intellectual"); break;
  1600.       }
  1601.       AnsiColor(i ? DEFAULT : WHITE);
  1602.  
  1603.       /* The biorhythm calculation is below. */
  1604.  
  1605.       l = Biorhythm(JD, k);
  1606.       fprintf(S, " at %c%3.0f%%", l < 0.0 ? '-' : '+', dabs(l));
  1607.  
  1608.       /* Print smiley face, medium face, or sad face based on current cycle. */
  1609.  
  1610.       AnsiColor(PURPLE);
  1611.       fprintf(S, " :%c", l > 50.0 ? ')' : (l < -50.0 ? '(' : '|'));
  1612.       AnsiColor(i ? DEFAULT : WHITE);
  1613.       if (j < 3)
  1614.         printc(',');
  1615.     }
  1616.     printl();
  1617.   }
  1618. #endif /* BIORHYTHM */
  1619. }
  1620.  
  1621.  
  1622. /* Another important procedure: Display any of the types of (text) charts    */
  1623. /* that the user specified they wanted, by calling the appropriate routines. */
  1624.  
  1625. void PrintChart(prog)
  1626. {
  1627.   if (todisplay == 0)          /* Assume the -v chart if user */
  1628.     todisplay |= DASHv;        /* didn't indicate anything.   */
  1629.   if (todisplay & DASHv) {
  1630.     if (relation < DASHrd)
  1631.       ChartLocation();
  1632.     else
  1633.  
  1634.       /* If the -rb or -rd relationship charts are in effect, then instead  */
  1635.       /* of doing the standard -v chart, print either of these chart types. */
  1636.  
  1637.       DisplayRelation();
  1638.     if (todisplay - (todisplay & DASHv*2-1))
  1639.       printl2();
  1640.   }
  1641.   if (todisplay & DASHw) {
  1642.     ChartWheel();
  1643.     if (todisplay - (todisplay & DASHw*2-1))
  1644.       printl2();
  1645.   }
  1646.   if (todisplay & DASHg) {
  1647.     if (relation > DASHr0) {
  1648.       CreateGrid(FALSE);
  1649.       ChartGrid();
  1650.       if (exdisplay & DASHg0) {    /* If -g0 switch in effect, then  */
  1651.         printl();                  /* display aspect configurations. */
  1652.         DisplayGrands();
  1653.       }
  1654.     } else {
  1655.  
  1656.       /* Do a relationship aspect grid between two charts if -r0 in effect. */
  1657.  
  1658.       CreateGridRelation((exdisplay & DASHg0) > 0);
  1659.       DisplayGridRelation();
  1660.     }
  1661.     if (todisplay - (todisplay & DASHg*2-1))
  1662.       printl2();
  1663.   }
  1664.   if (todisplay & DASHm) {
  1665.     if (!(todisplay & DASHg) || relation <= DASHr0)
  1666.       CreateGrid(FALSE);
  1667.     if (relation > DASHr0) {
  1668.       if (exdisplay & DASHm0)
  1669.         ChartAspect();
  1670.       else
  1671.         ChartMidpoint();
  1672.       if (todisplay - (todisplay & DASHm*2-1))
  1673.         printl2();
  1674.     } else {
  1675.       CreateGridRelation((exdisplay & DASHm0) == 0);
  1676.       if (exdisplay & DASHm0)
  1677.         DisplayAspectRelation();
  1678.       else
  1679.         DisplayMidpointRelation();
  1680.     }
  1681.   }
  1682.   if (todisplay & DASHZ) {
  1683.     if (exdisplay & DASHZd)
  1684.       DisplayInDayHorizon();
  1685.     else
  1686.       ChartHorizon();
  1687.     if (todisplay - (todisplay & DASHZ*2-1))
  1688.       printl2();
  1689.   }
  1690.   if (todisplay & DASHS) {
  1691.     ChartSpace();
  1692.     if (todisplay - (todisplay & DASHS*2-1))
  1693.       printl2();
  1694.   }
  1695.   if (todisplay & DASHj) {
  1696.     ChartInfluence();
  1697.     if (todisplay - (todisplay & DASHj*2-1))
  1698.       printl2();
  1699.   }
  1700.   if (todisplay & DASHL) {
  1701.     ChartAstroGraph();
  1702.     if (todisplay - (todisplay & DASHL*2-1))
  1703.       printl2();
  1704.   }
  1705.   if (todisplay & DASHK) {
  1706.     if (exdisplay & DASHKy)
  1707.       DisplayCalendarYear();
  1708.     else
  1709.       DisplayCalendarMonth();
  1710.     if (todisplay - (todisplay & DASHK*2-1))
  1711.       printl2();
  1712.   }
  1713.   if (todisplay & DASHd) {
  1714.     DisplayInDaySearch(prog);
  1715.     if (todisplay - (todisplay & DASHd*2-1))
  1716.       printl2();
  1717.   }
  1718.   if (todisplay & DASHD) {
  1719.     DisplayInDayInfluence();
  1720.     if (todisplay - (todisplay & DASHD*2-1))
  1721.       printl2();
  1722.   }
  1723.   if (todisplay & DASHE) {
  1724.     DisplayEphemeris();
  1725.     if (todisplay - (todisplay & DASHE*2-1))
  1726.       printl2();
  1727.   }
  1728.   if (todisplay & DASHt) {
  1729.     DisplayTransitSearch(prog);
  1730.     if (todisplay - (todisplay & DASHt*2-1))
  1731.       printl2();
  1732.   }
  1733.   if (todisplay & DASHT)
  1734.     DisplayTransitInfluence(prog);
  1735. }
  1736.  
  1737. /* options.c */
  1738.