/*
** Astrolog (Version 4.00) File: options.c
**
** IMPORTANT NOTICE: the graphics database and chart display routines
** used in this program are Copyright (C) 1991-1993 by Walter D. Pullen
** (cruiser1@stein.u.washington.edu). Permission is granted to freely
** use and distribute these routines provided one doesn't sell,
** restrict, or profit from them in any way. Modification is allowed
** provided these notices remain with any altered or edited versions of
** the program.
**
** The main planetary calculation routines used in this program have
** been Copyrighted and the core of this program is basically a
** conversion to C of the routines created by James Neely as listed in
** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
** available from Matrix Software. The copyright gives us permission to
** use the routines for personal use but not to sell them or profit from
** them in any way.
**
** The PostScript code within the core graphics routines are programmed
** and Copyright (C) 1992-1993 by Brian D. Willoughby
** (brianw@sounds.wa.com). Conditions are identical to those above.
**
** The extended accurate ephemeris databases and formulas are from the
** calculation routines in the program "Placalc" and are programmed and
** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
** (alois@azur.ch). The use of that source code is subject to
** regulations made by Astrodienst Zurich, and the code is not in the
** public domain. This copyright notice must not be changed or removed
** by any user of this program.
**
** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
** X Window graphics initially programmed 10/23-29/1991.
** PostScript graphics initially programmed 11/29-30/1992.
** Last code change made 12/31/1993.
*/

#include "astrolog.h"


/*
******************************************************************************
** Display Subroutines.
******************************************************************************
*/

/* This is a subprocedure of CreateGrid() and CreateGridRelation(). Given */
/* two planets, determine what aspect, if any, is present between them,   */
/* and save the aspect name and orb in the specified grid cell.           */

void GetAspect(planet1, planet2, ret1, ret2, i, j)
real *planet1, *planet2, *ret1, *ret2;
int i, j;
{
  int k;
  real l, m;

  grid->v[i][j] = grid->n[i][j] = 0;
  l = MinDistance(planet2[i], planet1[j]);
  for (k = aspects; k >= 1; k--) {
    m = l-aspectangle[k];
    if (dabs(m) < Orb(i, j, k)) {
      grid->n[i][j] = k;

      /* If -ga switch in effect, then change the sign of the orb to    */
      /* correspond to whether the aspect is applying or separating.    */
      /* To do this, we check the velocity vectors to see if the        */
      /* planets are moving toward, away, or are overtaking each other. */

      if (exdisplay & DASHga)
        m = SGN2(ret1[j]-ret2[i])*
          SGN2(MinDifference(planet2[i], planet1[j]))*SGN2(m)*dabs(m);
      grid->v[i][j] = (int) (m*60.0);
    }
  }
}


/* Set up the aspect/midpoint grid. Allocate memory for this array, if not */
/* already done. Allocation is only done once, first time this is called.  */

bool EnsureGrid()
{
  char string[STRING];

  if (grid != NULL)
    return TRUE;
  Allocate(grid, sizeof(gridstruct), gridstruct PTR);
  if (grid == NULL
#ifdef PC
    /* For PC's the grid better not cross a segment boundary. */
    || HIWORD(LOWORD(grid) + sizeof(gridstruct)) > 0
#endif
    ) {
    sprintf(string, "Not enough memory for grid (%d bytes).",
      sizeof(gridstruct));
    PrintError(string);
    return FALSE;
  }
  return TRUE;
}


/* Fill in the aspect grid based on the aspects taking place among the */
/* planets in the present chart. Also fill in the midpoint grid.       */

void CreateGrid(acc)
int acc;
{
  int i, j, k;
  real l;

  if (!EnsureGrid())
    return;
  for (j = 1; j <= total; j++) if (!ignore[j])
    for (i = 1; i <= total; i++) if (!ignore[i])

      /* The parameter 'acc' determine what half of the grid is filled in */
      /* with the aspects and what half is filled in with the midpoints.  */

      if (acc ? i > j : i < j)
        GetAspect(planet, planet, ret, ret, i, j);
      else if (acc ? i < j : i > j) {
        l = Mod(Midpoint(planet[i], planet[j])); k = (int)l;    /* Calculate */
        grid->n[i][j] = k/30+1;                                 /* midpoint. */
        grid->v[i][j] = (int)((l-(real)(k/30)*30.0)*60.0);
      } else {
        grid->n[i][j] = ZTOS(planet[j]);
        grid->v[i][j] = (int)(planet[j]-(real)(grid->n[i][j]-1)*30.0);
      }
}


/* This is similar to the previous function; however, this time fill in the */
/* grid based on the aspects (or midpoints if 'acc' set) taking place among */
/* the planets in two different charts, as in the -g -r0 combination.       */

void CreateGridRelation(acc)
int acc;
{
  int i, j, k;
  real l;

  if (!EnsureGrid())
    return;
  for (j = 1; j <= total; j++) if (!ignore[j])
    for (i = 1; i <= total; i++) if (!ignore[i])
      if (!acc)
        GetAspect(planet1, planet2, ret1, ret2, i, j);
      else {
        l = Mod(Midpoint(planet2[i], planet1[j])); k = (int)l;  /* Calculate */
        grid->n[i][j] = k/30+1;                                 /* midpoint. */
        grid->v[i][j] = (int)((l-(real)(k/30)*30.0)*60.0);
      }
}


/*
******************************************************************************
** Multiple Chart Display Subprograms.
******************************************************************************
*/

/* Print out an aspect (or midpoint if -g0 switch in effect) grid of a      */
/* relationship chart. This is similar to the ChartGrid() routine; however, */
/* here we have both axes labeled with the planets for the two charts in    */
/* question, instead of just a diagonal down the center for only one chart. */

void DisplayGridRelation()
{
  int i, j, k, tot = total, temp;

#ifdef INTERPRET
  if (interpret && !(exdisplay & DASHg0)) {
    InterpretGridRelation();
    return;
  }
#endif
  fprintf(S, " 2>");
  for (temp = 0, i = 1; i <= total; i++) if (!ignore[i]) {
    printc(BOXV);
    AnsiColor(objectansi[i]);
    fprintf(S, "%c%c%c", OBJNAM(i));
    AnsiColor(DEFAULT);
    temp++;
    if (column80 && temp >= 19) {
      tot = i;
      i = total;
    }
  }
  fprintf(S, "\n1  ");
  for (i = 1; i <= tot; i++) if (!ignore[i]) {
    printc(BOXV);
    AnsiColor(signansi(ZTOS(planet2[i])));
    fprintf(S, "%2d%c", (int)planet2[i] % 30, DEGR2);
    AnsiColor(DEFAULT);
  }
  fprintf(S, "\nV  ");
  for (i = 1; i <= tot; i++) if (!ignore[i]) {
    printc(BOXV);
    temp = ZTOS(planet2[i]);
    AnsiColor(signansi(temp));
    fprintf(S, "%c%c%c", SIGNAM(temp));
    AnsiColor(DEFAULT);
  }
  printl();
  for (j = 1; j <= total; j++) if (!ignore[j])
    for (k = 1; k <= 4; k++) {
      if (k < 2)
        PrintTab(BOXH, 3);
      else if (k == 2) {
        AnsiColor(objectansi[j]);
        fprintf(S, "%c%c%c", OBJNAM(j));
      } else {
        temp = ZTOS(planet1[j]);
        AnsiColor(signansi(temp));
        if (k == 3)
          fprintf(S, "%2d%c", (int)planet1[j] - (temp-1)*30, DEGR2);
        else
          fprintf(S, "%c%c%c", SIGNAM(temp));
      }
      if (k > 1)
        AnsiColor(DEFAULT);
      for (i = 1; i <= tot; i++) if (!ignore[i]) {
        printc(k < 2 ? BOXC : BOXV);
        temp = grid->n[i][j];
        if (k > 1) {
          if (i == j)
            AnsiColor(REVERSE);
          AnsiColor(exdisplay & DASHg0 ? signansi(temp) :
            aspectansi[temp]);
        }
        if (k < 2)
          PrintTab(BOXH, 3);
        else if (k == 2) {
          if (exdisplay & DASHg0)
            fprintf(S, "%c%c%c", SIGNAM(temp));
          else
            fprintf(S, "%s", temp ? aspectabbrev[temp] : "   ");
        } else if (k == 3) {
          if (exdisplay & DASHg0)
            fprintf(S, "%2d%c", grid->v[i][j]/60, DEGR2);
          else
            if (grid->n[i][j]) {
              if (grid->v[i][j] < 600)
                fprintf(S, "%c%2d", exdisplay & DASHga ?
                  (grid->v[i][j] < 0 ? 'a' : 's') :
                  (grid->v[i][j] < 0 ? '-' : '+'), abs(grid->v[i][j])/60);
              else
                fprintf(S, "%3d", abs(temp)/60);
            } else
              fprintf(S, "   ");
        } else {
          if (grid->n[i][j])
            fprintf(S, "%02d'", abs(grid->v[i][j])%60);
          else
            fprintf(S, "   ");
        }
        AnsiColor(DEFAULT);
      }
      printl();
    }
}


/* Display all aspects between objects in the relationship comparison chart, */
/* one per line, in sorted order based on the total "power" of the aspects,  */
/* as specified with the -r0 -m0 switch combination.                         */

void DisplayAspectRelation()
{
  int pcut = 30000, icut, jcut, phi, ihi, jhi, ahi, p, i, j, k, count = 0;
  real ip, jp;

  loop {
    phi = -1;

    /* Search for the next most powerful aspect in the aspect grid. */

    for (i = 1; i <= total; i++) if (!ignore[i])
      for (j = 1; j <= total; j++) if (!ignore[j])
        if (k = grid->n[i][j]) {
          ip = i <= OBJECTS ? objectinf[i] : 2.5;
          jp = j <= OBJECTS ? objectinf[j] : 2.5;
          p = (int) (aspectinf[k]*(ip+jp)/2.0*
            (1.0-dabs((real)(grid->v[i][j]))/60.0/aspectorb[k])*1000.0);
          if ((p < pcut || (p == pcut && (i > icut ||
            (i == icut && j > jcut)))) && p > phi) {
            ihi = i; jhi = j; phi = p; ahi = k;
          }
        }
    if (phi < 0)    /* Exit when no less powerful aspect found. */
      break;
    pcut = phi; icut = ihi; jcut = jhi;
    count++;                               /* Display the current aspect.   */
#ifdef INTERPRET
    if (interpret) {                       /* Interpret it if -I in effect. */
      InterpretAspectRelation(jhi, ihi);
      continue;
    }
#endif
    fprintf(S, "%3d: ", count);
    PrintAspect(jhi, ZTOS(planet1[jhi]), (int)Sgn(ret1[jhi]), ahi,
      ihi, ZTOS(planet2[ihi]), (int)Sgn(ret2[ihi]), 'A');
    k = grid->v[ihi][jhi];
    AnsiColor(k < 0 ? WHITE : LTGRAY);
    fprintf(S, "- orb: %c%d,%02d'",
      exdisplay & DASHga ? (k < 0 ? 'a' : 's') : (k < 0 ? '-' : '+'),
      abs(k)/60, abs(k)%60);
    AnsiColor(DKGREEN);
    fprintf(S, " - power:%6.2f\n", (real) phi/1000.0);
    AnsiColor(DEFAULT);
  }
}


/* Display locations of all midpoints between objects in the relationship */
/* comparison chart, one per line, in sorted zodiac order from zero Aries */
/* onward, as specified with the -r0 -m switch combination.               */

void DisplayMidpointRelation()
{
  int mcut = -1, icut, jcut, mlo, ilo, jlo, m, i, j, count = 0;

  loop {
    mlo = 21600;

    /* Search for the next closest midpoint farther down in the zodiac. */ 

    for (i = 1; i <= total; i++) if (!ignore[i])
      for (j = 1; j <= total; j++) if (!ignore[j]) {
        m = (grid->n[j][i]-1)*30*60 + grid->v[j][i];
        if ((m > mcut || (m == mcut && (i > icut ||
          (i == icut && j > jcut)))) && m < mlo) {
          ilo = i; jlo = j; mlo = m;
        }
      }
    if (mlo >= 21600)    /* Exit when no midpoint farther in zodiac found. */
      break;
    mcut = mlo; icut = ilo; jcut = jlo;
    count++;                               /* Display the current midpoint. */
#ifdef INTERPRET
    if (interpret) {                       /* Interpret it if -I in effect. */
      InterpretMidpointRelation(ilo, jlo);
      continue;
    }
#endif
    fprintf(S, "%4d: ", count);
    PrintZodiac((real) mlo/60.0);
    printc(' ');
    PrintAspect(ilo, ZTOS(planet1[ilo]), (int)Sgn(ret1[ilo]), 0,
      jlo, ZTOS(planet2[jlo]), (int)Sgn(ret2[jlo]), 'M');
    AnsiColor(DEFAULT);
    fprintf(S, "-%4d degree span.\n",
      (int)MinDistance(planet1[ilo], planet2[jlo]));
  }
}


/* Calculate any of the various kinds of relationship charts. This involves */
/* reading in and storing the planet and house positions for both charts,   */
/* and then combining them in the main single chart in the proper manner.   */
/* If the parameter 'var' is set, then we read the info for the two charts  */
/* from files, otherwise use the info in preset "core" and "second" charts. */

void CastRelation(var)
int var;
{
  int mon, day, yea, i;
  real tim, zon, lon, lat, t1, t2, t;

  /* Read in and cast the first chart. */

  if (var)
    InputData(filename);
  mon = MM; day = DD; yea = YY; tim = TT; zon = ZZ; lon = OO; lat = AA;
  if (var) {
    SetTwin(MM, DD, YY, TT, ZZ, OO, AA);
  } else {
    SetCore(Mon2, Day2, Yea2, Tim2, Zon2, Lon2, Lat2);
  }
  t1 = CastChart(TRUE);
  for (i = 1; i <= SIGNS; i++) {
    house1[i] = house[i];
    inhouse1[i] = inhouse[i];
  }
  for (i = 1; i <= total; i++) {
    planet1[i] = planet[i];
    planetalt1[i] = planetalt[i];
    ret1[i] = ret[i];
  }

  /* Read in the second chart. */

  if (var) {
    InputData(filename2);
    if (relation == DASHrp) {
      progress = TRUE;
      Jdp = (real)MdyToJulian(MM, DD, YY) + TT / 24.0;
      SetCore(mon, day, yea, tim, zon, lon, lat);
    }
  } else {
    SetCore(mon, day, yea, tim, zon, lon, lat);
  }
  SetMain(MM, DD, YY, TT, ZZ, OO, AA);
  t2 = CastChart(TRUE);
  for (i = 1; i <= SIGNS; i++) {
    house2[i] = house[i];
    inhouse2[i] = inhouse[i];
  }
  for (i = 1; i <= total; i++) {
    planet2[i] = planet[i];
    planetalt2[i] = planetalt[i];
    ret2[i] = ret[i];
  }

  /* Now combine the two charts based on what relation we are doing.   */
  /* For the standard -r synastry chart, use the house cusps of chart1 */
  /* and the planets positions of chart2.                              */

  if (relation <= DASHr)
    for (i = 1; i <= SIGNS; i++)
      house[i] = house1[i];

  /* For the -rc composite chart, take the midpoints of the planets/houses. */

  else if (relation == DASHrc) {
    for (i = 1; i <= total; i++) {
      planet[i] = Midpoint(planet1[i], planet2[i]);
      planetalt[i] = (planetalt1[i]+planetalt2[i])/2.0;
      ret[i] = (ret1[i]+ret2[i])/2.0;
    }
    for (i = 1; i <= SIGNS; i++)
      house[i] = Midpoint(house1[i], house2[i]);

    /* Make sure we don't have any 180 degree errors in house cusp    */
    /* complement pairs, which may happen if the cusps are far apart. */

    for (i = 1; i <= SIGNS; i++)
      if (MinDistance(house[_CAP], Mod(house[i]-STOZ(i+3))) > DEGQUAD)
        house[i] = Mod(house[i]+DEGHALF);

  /* For the -rm time space midpoint chart, calculate the midpoint time and */
  /* place between the two charts and then recast for the new chart info.   */

  } else if (relation == DASHrm) {
    T = (t1+t2)/2.0;
    t = (T*36525.0)+ROUND; JD = floor(t)+2415020.0; TT = FRACT(t)*24.0;
    ZZ = (DecToDeg(zon)+DecToDeg(Zon))/2.0; ZZ = DegToDec(ZZ);
    TT = DecToDeg(TT)-DecToDeg(ZZ); TT = DegToDec(TT);
    if (TT < 0.0) {
      TT = DecToDeg(TT)+24.0; TT = DegToDec(TT); JD -= 1.0;
    }
    JulianToMdy(JD, &MM, &DD, &YY);
    OO = (DecToDeg(lon)+DecToDeg(Lon))/2.0;
    if (dabs(Lon-lon) > DEGHALF)
      OO = Mod(OO+DEGHALF);
    OO = DegToDec(OO);
    AA = (DecToDeg(lat)+DecToDeg(Lat))/2.0; AA = DegToDec(AA);
    SetMain(MM, DD, YY, TT, ZZ, OO, AA);
    CastChart(FALSE);

  /* There are a couple of non-astrological charts, which only require the */
  /* number of days that have passed between the two charts to be done.    */

  } else
    JD = dabs(t2-t1)*36525.0;
  HousePlace();
}


/* Given two objects and an aspect between them, or an object and a sign  */
/* that it's entering, print if this is a "major" event, such as a season */
/* change or major lunar phase. This is called from the DisplayInDay      */
/* searching and influence routines. Go an interpretation if need be too. */

void PrintInDay(source, aspect, dest)
int source, aspect, dest;
{
  if (aspect == _SIG) {
    if (source == _SUN) {
      AnsiColor(WHITE);
      if (dest == 1)
        fprintf(S, " (Vernal Equinox)");     /* If the Sun changes sign, */
      else if (dest == 4)                    /* then print out if this   */
        fprintf(S, " (Summer Solstice)");    /* is a season change.      */
      else if (dest == 7)
        fprintf(S, " (Autumnal Equinox)");
      else if (dest == 10)
        fprintf(S, " (Winter Solstice)");
    }
  } else if (aspect > 0) {
    if (source == _SUN && dest == _MOO) {
      if (aspect <= _SQU)
        AnsiColor(WHITE);
      if (aspect == _CON)
        fprintf(S, " (New Moon)");     /* Print out if the present */
      else if (aspect == _OPP)         /* aspect is a New, Full,   */
        fprintf(S, " (Full Moon)");    /* or Half Moon.            */
      else if (aspect == _SQU)
        fprintf(S, " (Half Moon)");
    }
  }
  printl();

#ifdef INTERPRET
  if (interpret)
    InterpretInDay(source, aspect, dest);
#endif
  AnsiColor(DEFAULT);
}


/* Given two objects and an aspect (or one object, and an event such as a */
/* sign or direction change) display the configuration in question. This  */
/* is called by the many charts which list aspects among items, such as   */
/* the -m0 aspect lists, -m midpoint lists, -d aspect in day search and   */
/* influence charts, and -t transit search and influence charts.          */

void PrintAspect(obj1, sign1, ret1, asp, obj2, sign2, ret2, chart)
int obj1, sign1, ret1, asp, obj2, sign2, ret2;
char chart;
{
  int smart, a, s2;

  smart = smartcusp && IsCusp(obj2) && asp == _OPP;
  a = smart ? _CON : asp;
  s2 = smart ? sign1 : sign2;

  AnsiColor(objectansi[obj1]);
  if (chart == 't' || chart == 'T')
    fprintf(S, "trans ");
  else if (chart == 'e' || chart == 'u' || chart == 'U')
    fprintf(S, "progr ");
  fprintf(S, "%7.7s", objectname[obj1]);
  AnsiColor(signansi(sign1));
  fprintf(S, " %c%c%c%c%c",
    ret1 > 0 ? '(' : (ret1 < 0 ? '[' : '<'), SIGNAM(sign1),
    ret1 > 0 ? ')' : (ret1 < 0 ? ']' : '>'));
  AnsiColor(a > 0 ? aspectansi[a] : WHITE);
  printc(' ');
  if (a == _SIG)
    fprintf(S, "-->");                       /* Print a sign change. */
  else if (a == _DIR)
    fprintf(S, "S/%c", obj2 ? 'R' : 'D');    /* Print a direction change. */
  else if (a == 0)
    printf(chart == 'm' ? "&" : "with");
  else
    fprintf(S, "%s", aspectabbrev[a]);       /* Print an aspect. */
  printc(' ');
  if (chart == 'A')
    fprintf(S, "with ");
  if (a == _SIG) {
    AnsiColor(signansi(obj2));
    fprintf(S, "%s", signname[obj2]);
  } else if (a >= 0) {
    AnsiColor(signansi(s2));
    if (chart == 't' || chart == 'u' || chart == 'T' || chart == 'U')
      fprintf(S, "natal ");
    fprintf(S, "%c%c%c%c%c ",
      ret2 > 0 ? '(' : (ret2 < 0 ? '[' : '<'), SIGNAM(s2),
      ret2 > 0 ? ')' : (ret2 < 0 ? ']' : '>'));
    AnsiColor(smart ? signansi((obj2-15) - (obj2 < 23)) : objectansi[obj2]);
    if (smart) {
      fprintf(S, "%dth cusp", (obj2-15) - (obj2 < 23));
      if (obj2 < 23)
        printc(' ');
    } else
      fprintf(S, "%.10s", objectname[obj2]);
  }
  if (chart == 'D' || chart == 'T' || chart == 'U' ||
    chart == 'a' || chart == 'A' || chart == 'm' || chart == 'M')
    PrintTab(' ', 10-StringLen(objectname[obj2]));
}


/* Search through a day, and print out the times of exact aspects among the  */
/* planets during that day, as specified with the -d switch, as well as the  */
/* times when a planet changes sign or direction. To do this, we cast charts */
/* for the beginning and end of the day, or a part of a day, and do a linear */
/* equation check to see if anything exciting happens during the interval.   */
/* (This is probably the single most complicated procedure in the program.)  */

void DisplayInDaySearch(prog)
int prog;
{
  int time[MAXINDAY], source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY],
    sign1[MAXINDAY], sign2[MAXINDAY], D1, D2, occurcount, division, div,
    i, j, k, l, s1, s2;
  real divsiz, d1, d2, e1, e2, f1, f2, g;

  /* If parameter 'prog' is set, look for changes in a progressed chart. */

  division = prog ? 1 : divisions;
  divsiz = 24.0/ (real) division*60.0;

  /* If -dm in effect, then search through the whole month, day by day. */

  if (exdisplay & DASHdm) {
    D1 = 1;
    if (prog && Mon2 == 0) {
      Mon2 = 1; D2 = DayInYear(Yea2);
    } else
      D2 = DayInMonth(prog ? Mon2 : Mon, prog ? Yea2 : Yea);
  } else
    D1 = D2 = Day;

  /* Start searching the day or days in question for exciting stuff. */

  for (Day2 = D1; Day2 <= D2; Day2++) {
    occurcount = 0;

    /* Cast chart for beginning of day and store it for future use. */

    SetCore(Mon, Day2, Yea, 0.0, Zon, Lon, Lat);
    if (progress = prog) {
      Jdp = (real)MdyToJulian(Mon2, DD, Yea2);
      SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
    }
    CastChart(TRUE);
    for (i = 1; i <= SIGNS; i++) {
      house2[i] = house[i];
      inhouse2[i] = inhouse[i];
    }
    for (i = 1; i <= total; i++) {
      planet2[i] = planet[i];
      ret2[i] = ret[i];
    }

    /* Now divide the day into segments and search each segment in turn. */
    /* More segments is slower, but has slightly better time accuracy.   */

    for (div = 1; div <= division; div++) {

      /* Cast the chart for the ending time of the present segment. The   */
      /* beginning time chart is copied from the previous end time chart. */

      SetCore(Mon, Day2, Yea,
        DegToDec(24.0*(real)div/(real)division), Zon, Lon, Lat);
      if (prog) {
        Jdp = (real)MdyToJulian(Mon2, DD+1, Yea2);
        SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
      }
      CastChart(TRUE);
      for (i = 1; i <= SIGNS; i++) {
        house1[i] = house2[i]; inhouse1[i] = inhouse2[i];
        house2[i] = house[i];  inhouse2[i] = inhouse[i];
      }
      for (i = 1; i <= total; i++) {
        planet1[i] = planet2[i]; ret1[i] = ret2[i];
        planet2[i] = planet[i];  ret2[i] = ret[i];
      }

      /* Now search through the present segment for anything exciting. */

      for (i = 1; i <= total; i++) if (!ignore[i] && (prog || IsThing(i))) {
        s1 = ZTOS(planet1[i])-1;
        s2 = ZTOS(planet2[i])-1;

        /* Does the current planet change into the next or previous sign? */

        if (!ignore[i] && s1 != s2 && !ignore[0]) {
          source[occurcount] = i;
          aspect[occurcount] = _SIG;
          dest[occurcount] = s2+1;
          time[occurcount] = (int) (MinDistance(planet1[i],
            (real) (ret1[i] >= 0.0 ? s2 : s1) * 30.0) /
            MinDistance(planet1[i], planet2[i])*divsiz) +
            (int) ((real) (div-1)*divsiz);
          sign1[occurcount] = sign2[occurcount] = s1+1;
          occurcount++;
        }

        /* Does the current planet go retrograde or direct? */

        if (!ignore[i] && (ret1[i] < 0.0) != (ret2[i] < 0.0) && !ignore2[0]) {
          source[occurcount] = i;
          aspect[occurcount] = _DIR;
          dest[occurcount] = ret2[i] < 0.0;
          time[occurcount] = (int) (dabs(ret1[i])/(dabs(ret1[i])+dabs(ret2[i]))
            *divsiz) + (int) ((real) (div-1)*divsiz);
          sign1[occurcount] = sign2[occurcount] = s1+1;
          occurcount++;
        }

        /* Now search for anything making an aspect to the current planet. */

        for (j = i+1; j <= total; j++) if (!ignore[j] && (prog || IsThing(j)))
          for (k = 1; k <= aspects; k++) {
            d1 = planet1[i]; d2 = planet2[i];
            e1 = planet1[j]; e2 = planet2[j];
            if (MinDistance(d1, d2) < MinDistance(e1, e2)) {
              SwapReal(&d1, &e1);
              SwapReal(&d2, &e2);
            }

            /* We are searching each aspect in turn. Let's subtract the  */
            /* size of the aspect from the angular difference, so we can */
            /* then treat it like a conjunction.                         */

            if (MinDistance(e1, Mod(d1-aspectangle[k])) <
                MinDistance(e2, Mod(d2+aspectangle[k]))) {
              e1 = Mod(e1+aspectangle[k]);
              e2 = Mod(e2+aspectangle[k]);
            } else {
              e1 = Mod(e1-aspectangle[k]);
              e2 = Mod(e2-aspectangle[k]);
            }

            /* Check to see if the aspect actually occurs during our    */
            /* segment, making sure we take into account if one or both */
            /* planets are retrograde or if they cross the Aries point. */

            f1 = e1-d1;
            if (dabs(f1) > DEGHALF)
              f1 -= Sgn(f1)*DEGREES;
            f2 = e2-d2;
            if (dabs(f2) > DEGHALF)
              f2 -= Sgn(f2)*DEGREES;
            if (MinDistance(Midpoint(d1, d2), Midpoint(e1, e2)) < DEGQUAD &&
              Sgn(f1) != Sgn(f2)) {
              source[occurcount] = i;
              aspect[occurcount] = k;
              dest[occurcount] = j;

              /* Horray! The aspect occurs sometime during the interval.   */
              /* Now we just have to solve an equation in two variables to */
              /* find out where the "lines" cross, i.e. the aspect's time. */

              f1 = d2-d1;
              if (dabs(f1) > DEGHALF)
                f1 -= Sgn(f1)*DEGREES;
              f2 = e2-e1;
              if (dabs(f2) > DEGHALF)
                f2 -= Sgn(f2)*DEGREES;
              g = (dabs(d1-e1) > DEGHALF ?
                (d1-e1)-Sgn(d1-e1)*DEGREES : d1-e1)/(f2-f1);
              time[occurcount] = (int) (g*divsiz) +
                (int) ((real) (div-1)*divsiz);
              sign1[occurcount] = (int) (Mod(planet1[i]+
                Sgn(planet2[i]-planet1[i])*
                (dabs(planet2[i]-planet1[i]) > DEGHALF ? -1 : 1)*
                dabs(g)*MinDistance(planet1[i], planet2[i]))/30.0)+1;
              sign2[occurcount] = (int) (Mod(planet1[j]+
                Sgn(planet2[j]-planet1[j])*
                (dabs(planet2[j]-planet1[j]) > DEGHALF ? -1 : 1)*
                dabs(g)*MinDistance(planet1[j], planet2[j]))/30.0)+1;
              occurcount++;
            }
          }
      }
    }

    /* After all the aspects, etc, in the day have been located, sort   */
    /* them by time at which they occur, so we can print them in order. */

    for (i = 1; i < occurcount; i++) {
      j = i-1;
      while (j >= 0 && time[j] > time[j+1]) {
        SWAP(source[j], source[j+1]);
        SWAP(aspect[j], aspect[j+1]);
        SWAP(dest[j], dest[j+1]);
        SWAP(time[j], time[j+1]);
        SWAP(sign1[j], sign1[j+1]); SWAP(sign2[j], sign2[j+1]);
        j--;
      }
    }

    /* Finally, loop through and display each aspect and when it occurs. */

    for (i = 0; i < occurcount; i++) {
      s1 = time[i]/60;
      s2 = time[i]-s1*60;
      j = Day2;
      if (prog) {
        l = Mon2;
        while (j > (k = DayInMonth(l, Yea2))) {
          j -= k;
          l++;
        }
      }
      SetSave(prog ? l : Mon, j, prog ? Yea2 : Yea,
        DegToDec((real)time[i] / 60.0), Zon, Lon, Lat);
      k = DayOfWeek(prog ? l : Mon, j, prog ? Yea2 : Yea);
      AnsiColor(rainbowansi[k + 1]);
      fprintf(S, "(%c%c%c) ", DAYNAM(k));
      AnsiColor(DEFAULT);
      fprintf(S, "%s %s ",
        CharDate(prog ? l : Mon, j, prog ? Yea2 : Yea, FALSE),
        CharTime(s1, s2));
      PrintAspect(source[i], sign1[i],
        (int)Sgn(ret1[source[i]])+(int)Sgn(ret2[source[i]]),
        aspect[i], dest[i], sign2[i],
        (int)Sgn(ret1[dest[i]])+(int)Sgn(ret2[dest[i]]), prog ? 'e' : 'd');
      PrintInDay(source[i], aspect[i], dest[i]);
    }
  }
}


/* Based on the given chart information, display all the aspects taking    */
/* place in the chart, as specified with the -D switch. The aspects are    */
/* printed in order of influence determined by treating them as happening  */
/* outside among transiting planets, such that rare outer planet aspects   */
/* are given more power than common ones among inner planets. (This is     */
/* almost identical to the -m0 list, except the influences are different.) */

void DisplayInDayInfluence()
{
  int source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY];
  real power[MAXINDAY];
  int occurcount = 0, i, j, k, l, m;

  /* Go compute the aspects in the chart. */

  i = exdisplay;
  exdisplay |= DASHga;    /* We always want applying vs. separating orbs. */
  CreateGrid(FALSE);
  exdisplay = i;

  /* Search through the grid and build up the list of aspects. */

  for (j = 2; j <= total; j++) {
    if (ignore[j])
      continue;
    for (i = 1; i < j; i++) {
      if (ignore[i] || (k = grid->n[i][j]) == 0 || occurcount >= MAXINDAY)
        continue;
      if (smartcusp && k > _OPP && IsCusp(j))
        continue;
      source[occurcount] = i; aspect[occurcount] = k; dest[occurcount] = j;
      l = grid->v[i][j];
      power[occurcount] =
        ((i <= BASE ? transitinf[i] : 2.0)/4.0)*
        ((j <= BASE ? transitinf[j] : 2.0)/4.0)*
        aspectinf[k]*(1.0-(real)abs(l)/60.0/Orb(i, j, k));
      occurcount++;
    }
  }

  /* Sort aspects by order of influence. */

  for (i = 1; i < occurcount; i++) {
    j = i-1;
    while (j >= 0 && power[j] < power[j+1]) {
      SWAP(source[j], source[j+1]);
      SWAP(aspect[j], aspect[j+1]);
      SWAP(dest[j], dest[j+1]);
      SwapReal(&power[j], &power[j+1]);
      j--;
    }
  }

  /* Now display each aspect line. */

  for (i = 0; i < occurcount; i++) {
    fprintf(S, "%3d: ", i+1);
    j = source[i]; k = aspect[i]; l = dest[i];
    PrintAspect(
      j, ZTOS(planet[j]), (int)Sgn(ret[j]), k,
      l, ZTOS(planet[l]), (int)Sgn(ret[l]), 'D');
    m = grid->v[j][l];
    AnsiColor(m < 0 ? WHITE : LTGRAY);
    fprintf(S, "- %s%2d%c%02d'", m < 0 ? "app" : "sep",
      abs(m)/60, DEGR1, abs(m)%60);
    AnsiColor(DKGREEN);
    fprintf(S, " - power:%6.2f", power[i]);
    PrintInDay(j, k, l);
  }
}


/* Search through a month, and print out the times of exact transits where   */
/* planets in the time frame make aspect to the planets in some other chart, */
/* as specified with the -t switch. To do this, we cast charts for the start */
/* and end of the month, or part of the month, and do an equation check for  */
/* aspects to the other base chart during the interval.                      */

void DisplayTransitSearch(prog)
int prog;
{
  real planet3[TOTAL+1], house3[SIGNS+1], ret3[TOTAL+1];
  uint time[MAXINDAY];
  int source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY], sign[MAXINDAY],
    isret[MAXINDAY], M1, M2, occurcount, div, i, j, k, s1, s2, s3;
  real divsiz, daysiz, d, e1, e2, f1, f2;

  for (i = 1; i <= SIGNS; i++)
    house3[i] = house[i];
  for (i = 1; i <= total; i++) {
    planet3[i] = planet[i];
    ret3[i] = ret[i];
  }
  if (Mon2 == 0) {      /* Searching month number zero means to search */
    M1 = 1; M2 = 12;    /* the whole year instead, month by month.     */
  } else
    M1 = M2 = Mon2;

  /* Start searching the month or months in question for any transits. */

  for (Mon2 = M1; Mon2 <= M2; Mon2++) {
    daysiz = (real) DayInMonth(Mon2, Yea2)*24.0*60.0;
    divsiz = daysiz/ (real) divisions;

    /* Cast chart for beginning of month and store it for future use. */

    SetCore(Mon2, 1, Yea2, 0.0, Zon2, Lon2, Lat2);
    if (progress = prog) {
      Jdp = (real)MdyToJulian(MM, DD, YY);
      SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
    }
    CastChart(TRUE);
    for (i = 1; i <= SIGNS; i++)
      house2[i] = house[i];
    for (i = 1; i <= OBJECTS; i++) {
      planet2[i] = planet[i];
      ret2[i] = ret[i];
    }

    /* Divide our month into segments and then search each segment in turn. */

    for (div = 1; div <= divisions; div++) {
      occurcount = 0;

      /* Cast the chart for the ending time of the present segment, and */
      /* copy the start time chart from the previous end time chart.    */

      d = 1.0 + (daysiz/24.0/60.0)*(real)div/(real)divisions;
      SetCore(Mon2, (int)d, Yea2,
        DegToDec(FRACT(d)*24.0), Zon2, Lon2, Lat2);
      if (prog) {
        Jdp = (real)MdyToJulian(MM, DD, YY);
        SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
      }
      CastChart(TRUE);
      for (i = 1; i <= SIGNS; i++) {
        house1[i] = house2[i]; house2[i] = house[i];
      }
      for (i = 1; i <= OBJECTS; i++) {
        planet1[i] = planet2[i]; ret1[i] = ret2[i];
        planet2[i] = planet[i];  ret2[i] = ret[i];
      }

      /* Now search through the present segment for any transits. Note that */
      /* stars can be transited, but they can't make transits themselves.   */

      for (i = 1; i <= total; i++) if (!ignore[i])
        for (j = 1; j <= BASE; j++) if (!ignore2[j] && (prog || IsThing(j)))

          /* Between each pair of planets, check if they make any aspects. */

          for (k = 1; k <= aspects; k++) {
            d = planet3[i]; e1 = planet1[j]; e2 = planet2[j];
            if (MinDistance(e1, Mod(d-aspectangle[k])) <
                MinDistance(e2, Mod(d+aspectangle[k]))) {
              e1 = Mod(e1+aspectangle[k]);
              e2 = Mod(e2+aspectangle[k]);
            } else {
              e1 = Mod(e1-aspectangle[k]);
              e2 = Mod(e2-aspectangle[k]);
            }

            /* Check to see if the present aspect actually occurs during the */
            /* segment, making sure we check any Aries point crossings.      */

            f1 = e1-d;
            if (dabs(f1) > DEGHALF)
              f1 -= Sgn(f1)*DEGREES;
            f2 = e2-d;
            if (dabs(f2) > DEGHALF)
              f2 -= Sgn(f2)*DEGREES;
            if (MinDistance(d, Midpoint(e1, e2)) < DEGQUAD &&
              Sgn(f1) != Sgn(f2) && occurcount < MAXINDAY) {

              /* Ok, we have found a transit. Now determine the time */
              /* and save this transit in our list to be printed.    */

              source[occurcount] = j;
              aspect[occurcount] = k;
              dest[occurcount] = i;
              time[occurcount] = (int) (dabs(f1)/(dabs(f1)+dabs(f2))*divsiz) +
                (int) ((real) (div-1)*divsiz);
              sign[occurcount] = (int) (Mod(
                MinDistance(planet1[j], Mod(d-aspectangle[k])) <
                MinDistance(planet2[j], Mod(d+aspectangle[k])) ?
                d-aspectangle[k] : d+aspectangle[k])/30.0)+1;
              isret[occurcount] = (int)Sgn(ret1[j]) + (int)Sgn(ret2[j]);
              occurcount++;
            }
          }

      /* After all transits located, sort them by time at which they occur. */

      for (i = 1; i < occurcount; i++) {
        j = i-1;
        while (j >= 0 && time[j] > time[j+1]) {
          SWAP(source[j], source[j+1]);
          SWAP(aspect[j], aspect[j+1]);
          SWAP(dest[j], dest[j+1]);
          SWAP(time[j], time[j+1]);
          SWAP(sign[j], sign[j+1]);
          SWAP(isret[j], isret[j+1]);
          j--;
        }
      }

      /* Now loop through list and display all the transits. */

      for (i = 0; i < occurcount; i++) {
        k = smartcusp && IsCusp(dest[i]);
        if (k && aspect[i] > _OPP)
          continue;
        else
          k = k && aspect[i] == _OPP;
        s1 = time[i]/24/60;
        s3 = time[i]-s1*24*60;
        s2 = s3/60;
        s3 = s3-s2*60;
        SetSave(Mon2, s1+1, Yea2,
          DegToDec((real)(time[i]-s1*24*60) / 60.0), Zon2, Lon2, Lat2);
        fprintf(S, "%s %s ",
          CharDate(Mon2, s1+1, Yea2, FALSE), CharTime(s2, s3));
        PrintAspect(source[i], sign[i], isret[i], aspect[i],
          dest[i], ZTOS(planet3[dest[i]]), (int)Sgn(ret3[dest[i]]),
          prog ? 'u' : 't');

        /* Check for a Solar, Lunar, or any other return. */

        if (aspect[i] == _CON && source[i] == dest[i]) {
          AnsiColor(WHITE);
          fprintf(S, " (%s Return)", source[i] == _SUN ? "Solar" :
            (source[i] == _MOO ? "Lunar" : objectname[source[i]]));
        }
        printl();
#ifdef INTERPRET
        if (interpret)
          InterpretTransit(source[i], aspect[i], dest[i]);
#endif
        AnsiColor(DEFAULT);
      }
    }
  }
}


/* Given an arbitrary day, determine what aspects are made between this */
/* transiting chart and the given natal chart, as specified with the -T */
/* switch, and display the transits in order sorted by influence.       */

void DisplayTransitInfluence(prog)
int prog;
{
  int source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY];
  real power[MAXINDAY];
  byte ignore3[TOTAL+1];
  int occurcount = 0, i, j, k, l, m;

  /* Cast the natal and transiting charts as with a relationship chart. */

  for (i = 1; i <= SIGNS; i++)
    house1[i] = house[i];
  for (i = 1; i <= total; i++) {
    planet1[i] = planet[i];
    ret1[i] = ret[i];
  }
  SetCore(Mon2, Day2, Yea2, Tim2, Zon2, Lon2, Lat2);
  if (progress = prog) {
    Jdp = (real)MdyToJulian(MM, DD, YY);
    MM = Mon; DD = Day; YY = Yea;
  }
  CastChart(TRUE);
  for (i = 1; i <= SIGNS; i++)
    house2[i] = house[i];
  for (i = 1; i <= total; i++) {
    planet2[i] = planet[i];
    ret2[i] = ret[i];
  }

  /* Do a relationship aspect grid to get the transits. We have to make and */
  /* restore three changes to get it right for this chart. (1) We make the  */
  /* natal planets have zero velocity so applying vs. separating is only a  */
  /* function of the transiter. (2) We force applying vs. separating orbs   */
  /* regardless if -ga or -ma is in effect or not. (3) Finally we tweak the */
  /* main restrictions to allow for transiting objects not restricted.      */

  for (i = 1; i <= total; i++) {
    ret[i] = ret1[i];
    ret1[i] = 0.0;
    ignore3[i] = ignore[i];
    ignore[i] = ignore[i] && ignore2[i];
  }
  i = exdisplay;
  exdisplay |= DASHga;
  CreateGridRelation(FALSE);
  exdisplay = i;
  for (i = 1; i <= total; i++) {
    ret1[i] = ret[i];
    ignore[i] = ignore3[i];
  }

  /* Loop through the grid, and build up a list of the valid transits. */

  for (i = 1; i <= BASE; i++) {
    if (ignore2[i] || !IsThing(i))
      continue;
    for (j = 1; j <= total; j++) {
      if (ignore[j] || (k = grid->n[i][j]) == 0 || occurcount >= MAXINDAY)
        continue;
      if (smartcusp && k > _OPP && IsCusp(j))
        continue;
      source[occurcount] = i; aspect[occurcount] = k; dest[occurcount] = j;
      l = grid->v[i][j];
      power[occurcount] = transitinf[i]*
        ((j <= BASE ? objectinf[j] : 2.0)/4.0)*aspectinf[k]*
        (1.0-(real)abs(l)/60.0/Orb(i, j, k));
      occurcount++;
    }
  }

  /* After all transits located, sort them by their total power. */

  for (i = 1; i < occurcount; i++) {
    j = i-1;
    while (j >= 0 && power[j] < power[j+1]) {
      SWAP(source[j], source[j+1]);
      SWAP(aspect[j], aspect[j+1]);
      SWAP(dest[j], dest[j+1]);
      SwapReal(&power[j], &power[j+1]);
      j--;
    }
  }

  /* Now loop through list and display each transit in effect at the time. */

  for (i = 0; i < occurcount; i++) {
    k = aspect[i];
    l = source[i];
    fprintf(S, "%3d: ", i+1);
    j = ZTOS(planet2[l]);
    PrintAspect(l, j, (int)Sgn(ret2[l]), k,
      dest[i], ZTOS(planet1[dest[i]]), (int)Sgn(ret1[dest[i]]),
      prog ? 'U' : 'T');
    m = grid->v[l][dest[i]];
    AnsiColor(m < 0 ? WHITE : LTGRAY);
    fprintf(S, "- %s%2d%c%02d'", m < 0 ? "app" : "sep",
      abs(m)/60, DEGR1, abs(m)%60);
    AnsiColor(DKGREEN);
    fprintf(S, " - power:%6.2f", power[i]);
    if (k == _CON && l == dest[i]) {       /* Print a small "R" for returns. */
      AnsiColor(WHITE);
      fprintf(S, " R");
    }
    printl();
#ifdef INTERPRET
    if (interpret)
      InterpretTransit(l, k, dest[i]);
#endif
    AnsiColor(DEFAULT);
  }
}


/* Given the zodiac location of a planet in the sky and its declination,   */
/* and a location on the Earth, compute the azimuth and altitude of where  */
/* on the local horizon sky the planet would appear to one at the given    */
/* location. A reference MC position at Greenwich is also needed for this. */

void EclToHorizon(azi, alt, planet, planetalt, lon, lat, mc)
real *azi, *alt, planet, planetalt, lon, lat, mc;
{
  real lonz, latz;

  lonz = DTOR(planet); latz = DTOR(planetalt);
  EclToEqu(&lonz, &latz);
  lonz = DTOR(Mod(RTOD(mc-lonz+lon)));
  lonz = DTOR(Mod(RTOD(lonz-lon+PI/2.0)));
  EquToLocal(&lonz, &latz, PI/2.0-lat);
  *azi = DEGREES-RTOD(lonz); *alt = RTOD(latz);
}


/* Display a list of planetary rising times relative to the local horizon */
/* for the day indicated in the chart information, as specified with the  */
/* -Zd switch. For the day, the time each planet rises (transits horizon  */
/* in East half of sky), sets (transits horizon in West), reaches its     */
/* zenith point (transits meridian in South half of sky), and nadirs      */
/* transits meridian in North), is displayed.                             */

void DisplayInDayHorizon()
{
  int source[MAXINDAY], type[MAXINDAY], time[MAXINDAY], sign[MAXINDAY],
    isret[MAXINDAY], occurcount, division, div, s1, s2, i, j;
  real planetalt1[TOTAL+1], planetalt2[TOTAL+1], azialt[MAXINDAY],
    divsiz, lon, lat, mc1, mc2, azi1, alt1, azi2, alt2, d, k;

  lon = DTOR(Mod(Lon)); lat = DTOR(Lat);
  division = divisions * 4;
  divsiz = 24.0/ (real) division*60.0;
  occurcount = 0;

  SetCore(Mon, Day, Yea, 0.0, Zon, Lon, Lat);
  CastChart(TRUE);
  mc2 = DTOR(planet[_MC]); k = DTOR(planetalt[_MC]);
  EclToEqu(&mc2, &k);
  for (i = 1; i <= SIGNS; i++) {
    house2[i] = house[i];
    inhouse2[i] = inhouse[i];
  }
  for (i = 1; i <= total; i++) {
    planet2[i] = planet[i];
    planetalt2[i] = planetalt[i];
    ret2[i] = ret[i];
  }

  /* Loop thorough the day, dividing it into a certain number of segments. */
  /* For each segment we get the planet positions at its endpoints.        */

  for (div = 1; div <= division; div++) {
    SetCore(Mon, Day, Yea,
      DegToDec(24.0*(real)div/(real)division), Zon, Lon, Lat);
    CastChart(TRUE);
    mc1 = mc2;
    mc2 = DTOR(planet[_MC]); k = DTOR(planetalt[_MC]);
    EclToEqu(&mc2, &k);
    for (i = 1; i <= SIGNS; i++) {
      house1[i] = house2[i]; inhouse1[i] = inhouse2[i];
      house2[i] = house[i];  inhouse2[i] = inhouse[i];
    }
    for (i = 1; i <= total; i++) {
      planet1[i] = planet2[i]; planet2[i] = planet[i];
      planetalt1[i] = planetalt2[i]; planetalt2[i] = planetalt[i];
      ret1[i] = ret2[i]; ret2[i] = ret[i];
    }

    /* For our segment, check to see if each planet during it rises, sets, */
    /* reaches its zenith, or reaches its nadir.                           */

    for (i = 1; i <= total; i++) if (!ignore[i] && IsThing(i)) {
      EclToHorizon(&azi1, &alt1, planet1[i], planetalt1[i], lon, lat, mc1);
      EclToHorizon(&azi2, &alt2, planet2[i], planetalt2[i], lon, lat, mc2);
      j = 0;
      /* Check for transits to the horizon. */
      if ((alt1 > 0.0) != (alt2 > 0.0)) {
        d = dabs(alt1)/(dabs(alt1)+dabs(alt2));
        k = Mod(azi1 + d*MinDifference(azi1, azi2));
        j = 1 + 2*(MinDistance(k, DEGHALF) < DEGQUAD);
      /* Check for transits to the meridian. */
      } else if (Sgn(MinDifference(azi1, DEGQUAD)) !=
        Sgn(MinDifference(azi2, DEGQUAD))) {
        j = 2 + 2*(MinDistance(azi1, DEGQUAD) < DEGQUAD);
        d = dabs(azi1 - (j > 2 ? DEGQUAD : 270.0))/MinDistance(azi1, azi2);
        k = alt1 + d*(alt2-alt1);
      }
      if (j && occurcount < MAXINDAY) {
        source[occurcount] = i;
        type[occurcount] = j;
        time[occurcount] = (int)(24.0*((real)(div-1)+d)/(real)division*60.0);
        sign[occurcount] = (int)Mod(planet1[i] +
          d*MinDifference(planet1[i], planet2[i]))/30 + 1;
        isret[occurcount] = (int)Sgn(ret1[i]) + (int)Sgn(ret2[i]);
        azialt[occurcount] = k;
        SetSave(Mon, Day, Yea, DegToDec((real)time[occurcount] / 60.0),
          Zon, Lon, Lat);
        occurcount++;
      }
    }
  }

  /* Sort each event in order of time when it happens during the day. */

  for (i = 1; i < occurcount; i++) {
    j = i-1;
    while (j >= 0 && time[j] > time[j+1]) {
      SWAP(source[j], source[j+1]);
      SWAP(type[j], type[j+1]);
      SWAP(time[j], time[j+1]);
      SWAP(sign[j], sign[j+1]);
      SWAP(isret[j], isret[j+1]);
      SwapReal(&azialt[j], &azialt[j+1]);
      j--;
    }
  }

  /* Finally display the list showing each event and when it occurs. */

  for (i = 0; i < occurcount; i++) {
    SetSave(Mon, Day, Yea,
      DegToDec((real)time[i] / 60.0), Zon, Lon, Lat);
    j = DayOfWeek(Mon, Day, Yea);
    AnsiColor(rainbowansi[j + 1]);
    fprintf(S, "(%c%c%c) ", DAYNAM(j));
    AnsiColor(DEFAULT);
    s1 = time[i]/60;
    s2 = time[i]-s1*60;
    fprintf(S, "%s %s ", CharDate(Mon, Day, Yea, FALSE), CharTime(s1, s2));
    AnsiColor(objectansi[source[i]]);
    fprintf(S, "%7.7s ", objectname[source[i]]);
    AnsiColor(signansi(sign[i]));
    fprintf(S, "%c%c%c%c%c ",
      isret[i] > 0 ? '(' : (isret[i] < 0 ? '[' : '<'), SIGNAM(sign[i]),
      isret[i] > 0 ? ')' : (isret[i] < 0 ? ']' : '>'));
    AnsiColor(elemansi[type[i]-1]);
    if (type[i] == 1)
      fprintf(S, "rises  ");
    else if (type[i] == 2)
      fprintf(S, "zeniths");
    else if (type[i] == 3)
      fprintf(S, "sets   ");
    else
      fprintf(S, "nadirs ");
    AnsiColor(DEFAULT);
    fprintf(S, " at ");
    if (type[i] & 1) {
      j = (int) (FRACT(azialt[i])*60.0);
      fprintf(S, "%3d%c%02d'", (int) azialt[i], DEGR1, j);

      /* For rising and setting events, we'll also display a direction  */
      /* vector to make the 360 degree azimuth value thought of easier. */

      azi1 = cos(DTOR(azialt[i])); alt1 = sin(DTOR(azialt[i]));
      if (dabs(azi1) < dabs(alt1)) {
        azi2 = dabs(azi1 / alt1); alt2 = 1.0;
      } else {
        alt2 = dabs(alt1 / azi1); azi2 = 1.0;
      }
      fprintf(S, " (%.2f%c %.2f%c)",
        alt2, alt1 < 0.0 ? 's' : 'n', azi2, azi1 > 0.0 ? 'e' : 'w');
    } else
      PrintAltitude(azialt[i]);
    printl();
  }
}


/* Print out an ephemeris - the positions of the planets (at the time in the */
/* current chart) each day during a specified month, as done with the -E     */
/* switch. Display the ephemeris for the whole year if -Ey is in effect.     */

void DisplayEphemeris()
{
  int M0, M1, M2, daysiz, i, j, k, s, d, m;

  /* If -Ey is in effect, then loop through all months in the whole year. */

  if (exdisplay & DASHEy) {
    M1 = 1; M2 = 12;
  } else
    M1 = M2 = Mon;

  /* Loop through the month or months in question, printing each ephemeris. */

  for (M0 = M1; M0 <= M2; M0++) {
    daysiz = DayInMonth(M0, Yea);
    printf(eurodate ? "Dy/Mo/Yr" : "Mo/Dy/Yr");
    for (k = 0, j = 1; j <= total; j++) {
      if (!ignore[j] && IsThing(j)) {
        fprintf(S, "  %c%c%c%c ", OBJNAM(j), objectname[j][3] != 0 ?
          objectname[j][3] : ' ');
        k++;
        if (column80 && k >= 10)
          j = total;
      }
    }
    printl();
    for (i = 1; i <= daysiz; i++) {

      /* Loop through each day in the month, casting a chart for that day. */

      SetCore(M0, i, Yea, Tim, Zon, Lon, Lat);
      CastChart(TRUE);
      fprintf(S, "%s ", CharDate(M0, i, Yea, -1));
      for (k = 0, j = 1; j <= total; j++)
        if (!ignore[j] && IsThing(j)) {
          AnsiColor(objectansi[j]);
          s = ZTOS(planet[j]);
          d = (int) planet[j] - (s-1)*30;
          m = (int) (FRACT(planet[j])*60.0);
          fprintf(S, "%2d%s%02d%c", d, signabbrev[s], m,
            ret[j] >= 0.0 ? ' ' : '.');
          k++;
          if (column80 && k >= 10)
            j = total;
        }
      printl();
      AnsiColor(DEFAULT);
    }
    if (M0 < M2)
      printl();
  }
}


/* Display a calendar for the given month in the chart, as specified with  */
/* with the -K switch. When color is on, the title is white, weekends are  */
/* highlighted in red, and the specific day in the chart is colored green. */

void DisplayCalendarMonth()
{
  int i, j, k;

  AnsiColor(WHITE);
  PrintTab(' ', 16-StringLen(monthname[Mon]) >> 1);
  fprintf(S, "%s%5d\n", monthname[Mon], Yea);
  for (i = 0; i < 7; i++)
    fprintf(S, "%c%c%c", dayname[i][0], dayname[i][1], i < 6 ? ' ' : '\n');
  j = DayOfWeek(Mon, 1, Yea);
  AnsiColor(DEFAULT);
  for (i = 0; i < j; i++) {
    if (i == 0)
      AnsiColor(RED);
    fprintf(S, "-- ");
    if (i == 0)
      AnsiColor(DEFAULT);
  }
  k = DayInMonth(Mon, Yea);
  for (i = 1; i <= k; i++) {
    if (i == (int)Day)
      AnsiColor(GREEN);
    else if (j == 0 || j == 6)
      AnsiColor(RED);
    fprintf(S, "%2d", i);
    if (j == 0 || j == 6 || i == Day)
      AnsiColor(DEFAULT);
    if (j < 6) {
      j++;
      printc(' ');
    } else {
      j = 0;
      printl();
    }
  }
  while (j > 0 && j < 7) {
    if (j == 6)
      AnsiColor(RED);
    j++;
    fprintf(S, "--%c", j < 7 ? ' ' : '\n');
  }
  AnsiColor(DEFAULT);
}


/* Display a calendar for the entire year given in the chart, as specified */
/* with the -Ky switch. This is just like twelve of the individual month   */
/* calendars above displayed together, with same color highlights and all. */

void DisplayCalendarYear()
{
  int r, w, c, m, d, dy, p[3], l[3], n[3];

  dy = DayOfWeek(1, 1, Yea);
  for (r = 0; r < 4; r++) {    /* Loop over one set of three months */
    AnsiColor(WHITE);
    for (c = 0; c < 3; c++) {
      m = r*3+c+1;
      PrintTab(' ', 16-StringLen(monthname[m]) >> 1);
      fprintf(S, "%s%5d", monthname[m], Yea);
      if (c < 2)
        PrintTab(' ', 20 + MONTHSPACE -
          (16-StringLen(monthname[m]) >> 1) - StringLen(monthname[m]) - 5);
    }
    printl();
    for (c = 0; c < 3; c++) {
      for (d = 0; d < 7; d++)
        fprintf(S, "%c%c%c", dayname[d][0], dayname[d][1],
          d < 6 || c < 2 ? ' ' : '\n');
      if (c < 2)
        PrintTab(' ', MONTHSPACE-1);
      m = r*3+c+1;
      p[c] = dy % 7;
      l[c] = DayInMonth(m, Yea);
      n[c] = 0;
      dy += l[c];
    }
    for (w = 0; w < 6; w++) {      /* Loop over one set of week rows */
      for (c = 0; c < 3; c++) {    /* Loop over one week in a month  */
        m = r*3+c+1;
        d = 0;
        if (w == 0)
          while (d < p[c]) {
            if (d == 0)
              AnsiColor(RED);
            fprintf(S, "-- ");
            if (d == 0)
              AnsiColor(DEFAULT);
            d++;
          }
        AnsiColor(DEFAULT);
        while (d < 7 && n[c] < l[c]) {
          n[c]++;
          if (n[c] == Day && m == Mon)
            AnsiColor(GREEN);
          else if (d == 0 || d == 6)
            AnsiColor(RED);
          fprintf(S, "%2d%c", n[c], d < 6 || c < 2 ? ' ' : '\n');
          if (d == 0 || d == 6 || (n[c] == Day && m == Mon))
            AnsiColor(DEFAULT);
          d++;
        }
        while (d < 7) {
          if (d == 0 || d == 6)
            AnsiColor(RED);
          fprintf(S, "--%c", d < 6 || c < 2 ? ' ' : '\n');
          if (d == 0)
            AnsiColor(DEFAULT);
          d++;
        }
        if (c < 2)
          PrintTab(' ', MONTHSPACE-1);
      }
    }
    if (r < 3)
      printl();
  }
  AnsiColor(DEFAULT);
}


/* Display either a biorhythm chart or the time difference in various units */
/* between two charts, i.e. two types of relationship "charts" that aren't  */
/* related in any way to planetary positions, as specified by either the    */
/* -rb or -rd switches, respectively.                                       */

void DisplayRelation()
{
#ifdef BIORHYTHM
  int i, j;
  real k, l;
#endif

  /* If we are calculating the difference between two dates, then display */
  /* the value and return, as with the -rd switch.                        */

  if (relation == DASHrd) {
    fprintf(S, "Differences between the dates in the two charts:\n");
    AnsiColor(rainbowansi[1]); fprintf(S, "Years  : %.0f\n", JD/365.25);
    AnsiColor(rainbowansi[2]); fprintf(S, "Months : %.0f\n", JD/(365.25/12));
    AnsiColor(rainbowansi[3]); fprintf(S, "Weeks  : %.0f\n", JD/7.0);
    AnsiColor(rainbowansi[4]); fprintf(S, "Days   : %.0f\n", JD);
    AnsiColor(rainbowansi[5]); fprintf(S, "Hours  : %.0f\n", JD*24.0);
    AnsiColor(rainbowansi[6]); fprintf(S, "Minutes: %.0f\n", JD*24.0*60.0);
    AnsiColor(rainbowansi[7]); fprintf(S, "Seconds: %.0f\n", JD*24.0*3600.0);
    AnsiColor(DEFAULT);
    return;
  }

#ifdef BIORHYTHM
  /* If we are doing a biorhythm (-rb switch), then we'll calculate it for */
  /* someone born on the older date, at the time of the younger date. Loop */
  /* through the week preceeding and following the date in question.       */

  JD = floor(JD + ROUND);
  for (JD -= 7.0, i = -7; i <= 7; i++, JD += 1.0) {
    if (i == 0)
      AnsiColor(WHITE);
    else if (i == 1)
      AnsiColor(DEFAULT);
    fprintf(S, "T%c%d Day%c:",
      i < 0 ? '-' : '+', abs(i), abs(i) != 1 ? 's' : ' ');
    for (j = 1; j <= 3; j++) {
      printc(' ');
      switch (j) {
      case 1: k = _PHY; AnsiColor(RED);   fprintf(S, "Physical");     break;
      case 2: k = _EMO; AnsiColor(BLUE);  fprintf(S, "Emotional");    break;
      case 3: k = _INT; AnsiColor(GREEN); fprintf(S, "Intellectual"); break;
      }
      AnsiColor(i ? DEFAULT : WHITE);

      /* The biorhythm calculation is below. */

      l = Biorhythm(JD, k);
      fprintf(S, " at %c%3.0f%%", l < 0.0 ? '-' : '+', dabs(l));

      /* Print smiley face, medium face, or sad face based on current cycle. */

      AnsiColor(PURPLE);
      fprintf(S, " :%c", l > 50.0 ? ')' : (l < -50.0 ? '(' : '|'));
      AnsiColor(i ? DEFAULT : WHITE);
      if (j < 3)
        printc(',');
    }
    printl();
  }
#endif /* BIORHYTHM */
}


/* Another important procedure: Display any of the types of (text) charts    */
/* that the user specified they wanted, by calling the appropriate routines. */

void PrintChart(prog)
{
  if (todisplay == 0)          /* Assume the -v chart if user */
    todisplay |= DASHv;        /* didn't indicate anything.   */
  if (todisplay & DASHv) {
    if (relation < DASHrd)
      ChartLocation();
    else

      /* If the -rb or -rd relationship charts are in effect, then instead  */
      /* of doing the standard -v chart, print either of these chart types. */

      DisplayRelation();
    if (todisplay - (todisplay & DASHv*2-1))
      printl2();
  }
  if (todisplay & DASHw) {
    ChartWheel();
    if (todisplay - (todisplay & DASHw*2-1))
      printl2();
  }
  if (todisplay & DASHg) {
    if (relation > DASHr0) {
      CreateGrid(FALSE);
      ChartGrid();
      if (exdisplay & DASHg0) {    /* If -g0 switch in effect, then  */
        printl();                  /* display aspect configurations. */
        DisplayGrands();
      }
    } else {

      /* Do a relationship aspect grid between two charts if -r0 in effect. */

      CreateGridRelation((exdisplay & DASHg0) > 0);
      DisplayGridRelation();
    }
    if (todisplay - (todisplay & DASHg*2-1))
      printl2();
  }
  if (todisplay & DASHm) {
    if (!(todisplay & DASHg) || relation <= DASHr0)
      CreateGrid(FALSE);
    if (relation > DASHr0) {
      if (exdisplay & DASHm0)
        ChartAspect();
      else
        ChartMidpoint();
      if (todisplay - (todisplay & DASHm*2-1))
        printl2();
    } else {
      CreateGridRelation((exdisplay & DASHm0) == 0);
      if (exdisplay & DASHm0)
        DisplayAspectRelation();
      else
        DisplayMidpointRelation();
    }
  }
  if (todisplay & DASHZ) {
    if (exdisplay & DASHZd)
      DisplayInDayHorizon();
    else
      ChartHorizon();
    if (todisplay - (todisplay & DASHZ*2-1))
      printl2();
  }
  if (todisplay & DASHS) {
    ChartSpace();
    if (todisplay - (todisplay & DASHS*2-1))
      printl2();
  }
  if (todisplay & DASHj) {
    ChartInfluence();
    if (todisplay - (todisplay & DASHj*2-1))
      printl2();
  }
  if (todisplay & DASHL) {
    ChartAstroGraph();
    if (todisplay - (todisplay & DASHL*2-1))
      printl2();
  }
  if (todisplay & DASHK) {
    if (exdisplay & DASHKy)
      DisplayCalendarYear();
    else
      DisplayCalendarMonth();
    if (todisplay - (todisplay & DASHK*2-1))
      printl2();
  }
  if (todisplay & DASHd) {
    DisplayInDaySearch(prog);
    if (todisplay - (todisplay & DASHd*2-1))
      printl2();
  }
  if (todisplay & DASHD) {
    DisplayInDayInfluence();
    if (todisplay - (todisplay & DASHD*2-1))
      printl2();
  }
  if (todisplay & DASHE) {
    DisplayEphemeris();
    if (todisplay - (todisplay & DASHE*2-1))
      printl2();
  }
  if (todisplay & DASHt) {
    DisplayTransitSearch(prog);
    if (todisplay - (todisplay & DASHt*2-1))
      printl2();
  }
  if (todisplay & DASHT)
    DisplayTransitInfluence(prog);
}

/* options.c */
