From: astrolog@byron.u.washington.edu (Astrolog)
Newsgroups: alt.astrology
Subject: * Astrolog birthchart program version 2.30 [Part 05/12] charts.c
Summary: (Leo) Source file - extract and save to "charts.c"
Keywords: Astrolog 2.30
Date: 12 Sep 92 02:50:08 GMT
Organization: University of Washington

/*
** Astrolog (Version 2.30) File: charts.c
**
** IMPORTANT: The 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 our own purposes but not to sell them or profit
** from them in any way.
**
** IN ADDITION: the graphics database and chart display routines used in
** this program are Copyright (C) 1991-1992 by Walter D. Pullen. 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.
*/

#include "astrolog.h"

/* List of planet interpretations, as used in a couple of procedures. */

char *mindpart[] = {"",
  "spirit, ego, image of self, and sense of aliveness",
  "emotional nature, moods, feelings, and caring tendencies",
  "thoughts, intellect, and communicative activity",
  "creativity, tendencies for affection and calmness, and relationship needs",
  "will, energy, activity, and aggressive, assertive tendencies",
  "enthusiastic, faithful, wise, expansive, spontaneous nature",
  "part of mind that is disciplined, respectful, and solitary",
  "individuality, desires for change, and tendency to go against social norms",
  "intuitive, spiritual, compassionate, psychic nature",
  "destiny, and capacity to transform the self and the outer world",
  "ability to help, heal, and teach others, and where one has much experience",
  "tendency to direct energy to instinctive, creative, reproductive goals",
  "tendency to direct energy away from emotional and into mental pursuits",
  "tendency to give away individual power for the benefit of a relationship",
  "capacity to direct creative energy into personal or devotional goals",
  "karmic goals, and best direction of evolutionary growth",
  "place where opportunity and success can be found",
  "personality and outward appearance, as projected to the world",
  "view as seen in the eyes of others, reputation, and social standing",
  "karmic fate and method of reception of energies"};


/*
*******************************************************************************
** Display subprograms
*******************************************************************************
*/

/* This function is used by the interpretation routines to print out lines  */
/* of text with newlines inserted just before the end of screen is reached. */

fieldword(string)
char *string;
{
  static char line[STRING*2];
  static int cursor = 0;
  int i, j;

  /* Hack: Dump buffer if function called with a null string. */

  if (string[0] == 0) {
    line[cursor] = 0;
    printf("%s\n", line);
    cursor = 0;
    return;
  }
  if (cursor)
    line[cursor++] = ' ';
  for (i = 0; (line[cursor] = string[i]); i++, cursor++)
    ;

  /* When buffer overflows 80 columns, print out one line and start over. */

  while (cursor >= STRING-1) {
    for (i = STRING-1; line[i] != ' '; i--)
      ;
    line[i] = 0;
    printf("%s\n", line);
    line[0] = line[1] = ' ';
    for (j = 2; (line[j] = line[i+j-1]) != 0; j++)
      ;
    cursor -= (i-1);
  }
}


/* Print the interpretation of each planet in sign and house, as specified */
/* with the -vI switch. This is basically array accessing combining the    */
/* meanings of each planet, sign, and house, and a couple of other things. */

interpretlocation(general)
int general;
{
  static char *description[] = {"",
  "forceful, energetic, direct, courageous",
  "practical, often skeptical and stubborn",
  "inquisitive, witty, perceptive, adaptable",
  "introspective, emotional, protective",
  "proud, gregarious, dramatic, dignified",
  "analytical, critical, modest, helpful",
  "affectionate, tolerant, often indecisive, appreciates beauty",
  "penetrating, suspicious, introspective",
  "jovial, open minded, loves freedom",
  "industrious, practical, disciplined",
  "progressive, erratic, revolutionary, idealistic, humanitarian, inventive",
  "imaginative, other worldly, impressionable"};
  static char *desire[] = {"",
  "seeks adventure and challenge",
  "loves serenity and inner peace",
  "seeks out information",
  "wants inner and outer security",
  "desires self expression",
  "works toward perfection",
  "seeks balance, relationship, and calmness",
  "desires to transform and remove outer masks",
  "seeks meaning and new experience",
  "works for solitude and personal integrity",
  "desires individuality",
  "seeks transcendence of self"};
  static char *lifearea[] = {"",
  "establishment of personal identity",
  "self image, self worth, and material security",
  "communicating to and receiving from the environment",
  "imagination, fantasies, inner feelings, and domestic life",
  "finding joy, pleasure, and creative expression",
  "work and feeling talented and useful",
  "personal relationships and intimacy",
  "sex, death, the occult, and other hard to grasp topics",
  "changes, exploration, and the breaking of routine",
  "career, social stature, and destiny",
  "the future, life goals, and association with friends and groups",
  "things that disrupt or cause disassociation with the personality"};
  char string[STRING], c;
  int i, j;

  /* If parameter 'general' set, then, instead of an interpretation, just */
  /* print out what each sign, house, and planet means, as in -I0 switch. */

  if (general) {
    printf("Signs of the zodiac represent psychological characteristics.\n\n");
    for (i = 1; i <= SIGNS; i++) {
      sprintf(string, "%s is", signname[i]); fieldword(string);
      sprintf(string, "%s, and", description[i]); fieldword(string);
      sprintf(string, "%s.", desire[i]); fieldword(string);
      fieldword("");
    }
    printf("\nHouses represent different areas within one's life.\n\n");
    for (i = 1; i <= SIGNS; i++) {
      sprintf(string, "The %d%s House is the area of life dealing with",
	      i, post[i]); fieldword(string);
      sprintf(string, "%s.", lifearea[i]); fieldword(string);
      fieldword("");
    }
    printf("\nPlanets represent various parts of one's mind or self.\n\n");
    for (i = 1; i <= OBJECTS; i++) if (!ignore[i]) {
      sprintf(string, "%s%s%s%s represents one's",
	      i < 3 || i >= 16 ? "The " : "",
	      i == 16 ? "North " : (i == 17 ? "Part of " : ""), objectname[i],
	      i == 13 ? " Athena" : ""); fieldword(string);
      sprintf(string, "%s.", mindpart[i]); fieldword(string);
      fieldword("");
    }
    return;
  }

  /* If parameter 'general' not set, then print out interpretation. */

  putchar('\n');
  for (i = 1; i <= OBJECTS; i++) if (!ignore[i]) {
    j = (int) (planet[i]/30.0)+1; c = dignify(i, j);
    sprintf(string, "%s%s%s%s in %s", ret[i] < 0.0 ? "Retrograde " : "",
	    i == 16 ? "North " : (i == 17 ? "Part of " : ""), objectname[i],
	    i == 13 ? " Athena" : "", signname[j]);
    fieldword(string);
    sprintf(string, "and %d%s House:", inhouse[i], post[inhouse[i]]);
    fieldword(string);
    fieldword("This person's"); fieldword(mindpart[i]); fieldword("is");
    if (((int) planet[i]) % 30 < 10)
      fieldword("very");
    sprintf(string, "%s, and", description[j]); fieldword(string);
    sprintf(string, "%s.", desire[j]); fieldword(string);
    fieldword("Most often this manifests");
    if (ret[i] < 0.0 && i != 16)
      fieldword("in an independent, backward, introverted manner, and");
    fieldword("in the area of life dealing with");
    sprintf(string, "%s.", lifearea[inhouse[i]]); fieldword(string);

    /* Extra information if planet is in its ruling, falling, etc, sign. */

    if (c == 'R')
      fieldword("This is a major aspect of the person's psyche!");
    else if (c == 'F')
      fieldword("(This bit plays only a minor part in the person's psyche.)");
    else if (c == 'e')
      fieldword("It is easy for them to express this part of themself.");
    else if (c == 'd')
      fieldword("It is difficult for them to express this part of themself.");
    fieldword("");
  }
}


/* Print the straight listing of planet and house positions and specified */
/* by the -v switch, along with the element table, etc.                   */

void chartlocation(general)
int general;
{
  int elemode[4][3], elem[4], mo[3], pos = 0, abo = 0, lef = 0, lea = 0;
  int count = 0, i, j, k;
  if (general) {                /* If parameter 'general' set, then ignore */
    interpretlocation(TRUE);    /* chart, and display general meanings of  */
    return;                     /* signs, houses, and planets.             */
  }
  for (i = 0; i < 4; i++)
    elem[i] = 0;
  for (j = 0; j < 3; j++)
    mo[j] = 0;
  for (i = 0; i < 4; i++)
    for (j = 0; j < 3; j++)
      elemode[i][j] = 0;

  /* Calculate number of objects in each element, mode, hemisphere, etc. */

  for (i = 1; i <= total; i++) if (!ignore[i]) {
    count++;
    j = (int) (planet[i]/30.0) + 1;
    elemode[(j-1)%4][(j-1)%3]++;
    elem[(j-1)%4]++; mo[(j-1)%3]++;
    pos += (j & 1);
    lea += (j <= 6);
    j = inhouse[i];
    abo += (j >= 7);
    lef += (j < 4 || j >= 10);
  }

  /* Print header showing time and date of the chart being displayed. */

  printf("Astrolog (%s) chart ", VERSION);
  if (Mon == -1)
    printf("(no time or space)\n");
  else if (relation == 2)
    printf("(composite)\n");
  else {
    i = (int) ((dabs(Tim)-floor(dabs(Tim)))*100.0+0.5);
    j = (int) ((dabs(Zon)-floor(dabs(Zon)))*100.0+0.5);
    printf("for %d %s %d %.0f:%d%d (%c%.0f:%d%d GMT) ",
	   (int) Day, monthname[(int) Mon], (int) Yea, floor(Tim), 
	   i/10, i%10, Zon > 0.0 ? '-' : '+', dabs(Zon), j/10, j%10);
    printf("%s\n", stringlocation(Lon, Lat, 100.0));
  }
  if (todisplay & DASHVI) {
    interpretlocation(FALSE);    /* Print interpretation if -vI in effect. */
    return;
  }
  printf("Body  Locat. Ret. Decl. Rul.      House  Rul. Veloc.    ");
  printf("%s Houses.\n\n", systemname[housesystem]);

  /* Ok, now print out each location of each object. */

  for (i = 1; i <= BASE; i++)
    if (i <= OBJECTS || (i > C_HI && !ignore[i])) {
    printf("%-4.4s: ", objectname[i]);
    printminute(planet[i]);
    printf(" %c ", ret[i] >= 0.0 ? ' ' : 'R');
    if (i <= THINGS || i > OBJECTS)
      printaltitude(planetalt[i]);
    else
      printf("_______");
    printf(" (%c)", dignify(i, (int) (planet[i]/30.0)+1));
    j = inhouse[i];
    printf(" [%2d%c%c house]", j, post[j][0], post[j][1]);
    printf(" [%c]", dignify(i, j));
    if (i != 2 && i < THINGS || i > C_HI)
      printf(" %c%5.3f", ret[i] < 0.0 ? '-' : '+', RTOD(dabs(ret[i])));
    else
      printf(" ______");
    if (i <= SIGNS) {
      printf("  -  House cusp %2d: ", i);
      printminute(house[i]);
    }

    /* For some lines, we have to append the element table information. */

    if (i == SIGNS+2)
      printf("     Car Fix Mut TOT");
    else if (i > SIGNS+2 && i < SIGNS+7) {
      j = i-(SIGNS+2)-1;
      printf("  %c%c%c%3d %3d %3d %3d",
	     element[j][0], element[j][1], element[j][2],
	     elemode[j][0], elemode[j][1], elemode[j][2], elem[j]);
    } else if (i == SIGNS+7)
      printf("  TOT %2d %3d %3d %3d", mo[0], mo[1], mo[2], count);
    else if (i == OBJECTS)
      printtab(' ', 23);
    else if (i >= U_LO)
      printf("  Uranian #%d", i-U_LO+1);
    switch (i-SIGNS-1) {
    case 1: printf("   +:%2d", pos);       break;
    case 2: printf("   -:%2d", count-pos); break;
    case 3: printf("   M:%2d", abo);       break;
    case 4: printf("   N:%2d", count-abo); break;
    case 5: printf("   A:%2d", lef);       break;
    case 6: printf("   D:%2d", count-lef); break;
    case 7: printf(   "<:%2d", lea);       break;
    }
    putchar('\n');
  }

  /* Do another loop to print out the stars in their specified order. */

  if (universe) for (i = S_LO; i <= S_HI; i++) if (!ignore[i]) {
    j = BASE+starname[i-BASE];
    printf("%.4s: ", objectname[j]);
    printminute(planet[j]);
    printf("   ");
    printaltitude(planetalt[j]);
    k = inhouse[j];
    printf("     [%2d%c%c house]", k, post[k][0], post[k][1]);
    printf("     ______  Star #%2d: %5.2f\n", i-BASE, starbright[j-BASE]);
  }
}


/* Print the interpretation of each aspect in the aspect grid, as specified */
/* with the -gI switch. Again, this is basically array accessing of the     */
/* meanings of the two planets in aspect and of the aspect itself.          */

interpretgrid(general)
int general;
{
  static char *interact[] = {"",
    "is %sconnected and fused together with",
    "%sopposes and creates tension with",
    "is %sin conflict with",
    "is %sin harmony with",
    "has %sopportunity for growth, exchange, and harmony in relation with",
    "is %sdifferent from",
    "%sgets new perspectives in relation with",
    "%screates internal friction with",
    "%screates internal agitation with",
    "%screatively relates externally with",
    "%screatively relates internally with"};

  /* Modifier array makes the interpretation stronger for narrower orbs. */

  static char *modifier[3][11] = {{"always ", "always ", "irreconcilably ",
    "always ", "much ", "completely ", "often ", "often ", "often ", "often ",
    "often "}, {"", "", "", "", "", "", "", "", "", "", ""}, {"somewhat ",
    "somewhat ", "somewhat ", "somewhat ", "some ", "somewhat ", "sometimes ",
    "sometimes ", "sometimes ", "sometimes ", "sometimes "}};
  static char *therefore[] = {"",
    "Both parts are prominent in their psyche", "Balance is needed",
    "Adaptation is required by both sides", "", "",
    "They can often relate in a discordant way", "", "", "", "", ""};
  char string[STRING];
  int i, j, k;

  /* Again, if parameter 'general' is set, then ignore chart and print */
  /* general meanings of each aspect as specified with the -I0 switch. */

  if (general) {
    printf("\nAspects are different relationships between planets.\n\n");
    for (i = 1; i <= 11; i++) {
      sprintf(string, "When planets are %s, one", aspectname[i]);
      fieldword(string); sprintf(string, interact[i], ""); fieldword(string);
      fieldword("another.");
      if (therefore[i][0]) {
	sprintf(string, "%s.", therefore[i]); fieldword(string);
      }
      fieldword("");
    }
    return;
  }

  /* If parameter 'general' not set, then actually do the interpretation. */

  creategrid(FALSE);
  for (i = 1; i < OBJECTS; i++) if (!ignore[i])
    for (j = i+1; j <= OBJECTS; j++) if (!ignore[j]) {
      k = gridname[i][j];
      if (k > 0 && k <= 11) {
	sprintf(string, "%s %s %s: This person's", objectname[i],
		aspectname[k], objectname[j]);
	fieldword(string); fieldword(mindpart[i]);
	sprintf(string, interact[k],
		modifier[MIN(abs(grid[i][j])/150, 2)][k-1]);
	fieldword(string); fieldword("their");
	sprintf(string, "%s.", mindpart[j]); fieldword(string);
	if (therefore[k][0]) {
	  sprintf(string, "%s.", therefore[k]); fieldword(string);
	}
	fieldword("");
      }
    }
}


/* Print out the aspect and midpoint grid for a chart, as specified with the */
/* -g switch. (Each grid row takes up 4 lines of text.)                      */

void chartgrid(general)
int general;
{
  int i, j, k, temp;
  if (general || (todisplay & DASHGI) > 0) {    /* If -gI or -I0 in effect, */
    interpretgrid(general);                     /* ignore chart and print   */
    return;                                     /* interpretation.          */
  }
  for (j = 1; j <= total; j++) if (!ignore[j])
    for (k = 1; k <= 4; k++) {
      for (i = 1; i <= total; i++) if (!ignore[i]) {
	if (i > 1 && j+k > 2)
	  putchar('|');
	if (k > 1) {

	  /* Print aspect rows. */

	  if (i < j) {
	    if (k == 2)
	      printf("%s", aspectabbrev[gridname[i][j]]);
	    else if (!gridname[i][j])
	      printf("   ");
	    else
	      if (k == 3) {
		if (grid[i][j] < 600)
		  printf("%c%2d", todisplay & DASHGA ?
			 (grid[i][j] < 0 ? 'a' : 's') :
			 (grid[i][j] < 0 ? '-' : '+'), abs(grid[i][j])/60);
		else
		  printf("%3d", abs(grid[i][j])/60);
	      } else {
		temp = abs(grid[i][j])%60;
		printf("%d%d'", temp/10, temp%10);
	      }

          /* Print midpoint rows. */

	  } else if (i > j) {
	    if (k == 2) {
	      temp = gridname[i][j];
	      printf("%c%c%c", SIGNAM(temp));
	    } else if (k == 3)
	      printf("%3d", grid[i][j]/60);
	    else {
	      temp = grid[i][j]%60;
	      printf("%d%d'", temp/10, temp%10);
	    }

	  /* Print the diagonal of object names. */

	  } else {
	    if (k == 2)
	      printf("%c%c%c", OBJNAM(j));
	    else if (k == 4) {
	      temp = (int)(planet[j]/30.0)+1;
	      printf("%c%c%c", SIGNAM(temp));
	    } else
	      printf("###");
	  }
	} else
	  if (j > 1)
	    printf("---");
      }
      if (j+k > 2)
	putchar('\n');
    }
}


/* This is a subprocedure of displaygrands(). Here we print out one aspect */
/* configuration found by the parent procedure.                            */

printgrand(nam, i1, i2, i3, i4)
char nam;
int i1, i2, i3, i4;
{
  switch (nam) {
  case '.': printf("Stellium   "); break;
  case 't': printf("Grand Trine"); break;
  case 's': printf("T-Square   "); break;
  case 'y': printf("Yod        "); break;
  case 'g': printf("Grand Cross"); break;
  case 'c': printf("Cradle     "); break;
  default: ;
  }
  printf(" %s ", nam == '.' || nam == 't' || nam == 'g' ? "with" : "from");
  printf("%c%c%c: ", OBJNAM(i1));
  printminute(planet[i1]);
  printf(" %s %c%c%c: ", nam == '.' || nam == 't' ? "and" : "to ", OBJNAM(i2));
  printminute(planet[i2]);
  printf(" %s %c%c%c: ", nam == 'g' || nam == 'c' ? "to " : "and", OBJNAM(i3));
  printminute(planet[i3]);
  if (nam == 'g' || nam == 'c') {
    printf(" to %c%c%c: ", OBJNAM(i4));
    printminute(planet[i4]);
  }
  printf("\n");
}


/* Scan the aspect grid of a chart and print out any major configurations, */
/* as specified with the -g0 switch.                                       */

void displaygrands()
{
  int count = 0, i, j, k, l;
  for (i = 1; i <= OBJECTS; i++) if (!ignore[i])
    for (j = 1; j <= OBJECTS; j++) if (j != i && !ignore[j])
      for (k = 1; k <= OBJECTS; k++) if (k != i && k != j && !ignore[k]) {

	/* Is there a Stellium among the current three planets? */

	if (i < j && j < k && gridname[i][j] == 1 &&
	    gridname[i][k] == 1 && gridname[j][k] == 1) {
	  count++;
	  printgrand('.', i, j, k, l);

	/* Is there a Grand Trine? */

	} else if (i < j && j < k && gridname[i][j] == 4 &&
	    gridname[i][k] == 4 && gridname[j][k] == 4) {
	  count++;
	  printgrand('t', i, j, k, l);

	/* Is there a T-Square? */

	} else if (j < k && gridname[j][k] == 2 &&
	    gridname[MIN(i, j)][MAX(i, j)] == 3 &&
	    gridname[MIN(i, k)][MAX(i, k)] == 3) {
	  count++;
	  printgrand('s', i, j, k, l);

	/* Is there a Yod? */

	} else if (j < k && gridname[j][k] == 5 &&
	    gridname[MIN(i, j)][MAX(i, j)] == 6 &&
	    gridname[MIN(i, k)][MAX(i, k)] == 6) {
	  count++;
	  printgrand('y', i, j, k, l);
	}
	for (l = 1; l <= OBJECTS; l++) if (!ignore[l]) {

	  /* Is there a Grand Cross among the current four planets? */

	  if (i < j && i < k && i < l && j < l && gridname[i][j] == 3 &&
	      gridname[MIN(j, k)][MAX(j, k)] == 3 &&
	      gridname[MIN(k, l)][MAX(k, l)] == 3 &&
	      gridname[i][l] == 3 && mindistance(planet[i], planet[k]) > 150.0
	      && mindistance(planet[j], planet[l]) > 150.0) {
	    count++;
	    printgrand('g', i, j, k, l);

	  /* Is there a Cradle? */

	  } else if (i < l && gridname[MIN(i, j)][MAX(i, j)] == 5 &&
	      gridname[MIN(j, k)][MAX(j, k)] == 5 &&
	      gridname[MIN(k, l)][MAX(k, l)] == 5 &&
	      mindistance(planet[i], planet[l]) > 150.0) {
	    count++;
	    printgrand('c', i, j, k, l);
	  }
	}
      }
  if (!count)
    printf("No major configurations in aspect grid.\n");
}


/* A simple procedure used throughout Astrolog: Print a particular character */
/* on the screen 'n' times.                                                  */

printtab(chr, count)
char chr;
int count;
{
  int i;
  for (i = 0; i < count; i++)
    putchar(chr);
}

byte wheel[SIGNS][WHEELROWS];    /* Array used by chartwheel(). */

/* This is a subprocedure of chartwheel(). Here we print out one line in a */
/* particular house cell (which may be blank).                             */

printwheelslot(house, row)
int house, row;
{
  int i;
  i = wheel[house-1][row];
  if (i) {
    printf(" %c%c%c ", OBJNAM(i));    /* Print planet and its position. */
    printminute(planet[i]);
    printf("%c ", ret[i] < 0.0 ? 'r' : ' ');
    printtab(' ', WHEELCOLS-14-1);
  } else
    printtab(' ', WHEELCOLS-1);       /* This particular line is blank. */
}


/* Display all the objects in a wheel format on the screen, as specified */
/* with the -w switch. The wheel is divided into the 12 houses and the   */
/* planets are placed accordingly.                                       */

void chartwheel()
{
  static char *dayname[]
    = {"Sunday", "Monday", "Tuesday", "Wednesday",
	 "Thursday", "Friday", "Saturday"};
  int i, j, k, l, count = 0;
  for (i = 0; i < SIGNS; i++)
    for (j = 0; j < WHEELROWS; j++)    /* Clear out array from the */
      wheel[i][j] = 0;                 /* last time we used it.    */

  /* This section of code places each object in the wheel house array. */

  for (i = 1; i <= total && count < 26; i++) {
    if (!ignore[i] && (i < 18 || i == 20 || i > C_HI))

      /* Try to put object in its proper house. If no room, */
      /* then overflow over to the succeeding house.        */

      for (j = inhouse[i]-1; j < SIGNS; j = j < SIGNS ? (j+1)%SIGNS : j) {

	/* Now try to find the proper place in the house to put the object. */
	/* This is in sorted order, although a check is made for 0 Aries.   */

	l = house[j+1] > house[mod12(j+2)];
	for (k = 0; k < WHEELROWS && wheel[j][k] > 0 &&
	     (planet[i] >= planet[wheel[j][k]] ||
	      (l && planet[i] < 180.0 && planet[wheel[j][k]] > 180.0)) &&
	     !(l && planet[i] > 180.0 && planet[wheel[j][k]] < 180.0); k++)
	  ;
	count++;

	/* Actually insert object in proper place. */

	if (wheel[j][k] <= 0) {
	  wheel[j][k] = i;
	  j = SIGNS;
	} else if (k < WHEELROWS && wheel[j][WHEELROWS-1] <= 0) {
	  for (l = WHEELROWS-1; l > k; l--)
	    wheel[j][l] = wheel[j][l-1];
	  wheel[j][k] = i;
	  j = SIGNS;
	}
      }
  }

  /* Now, if this is really the -w switch and not -w0, then reverse the */
  /* order of objects in western houses for more intuitive reading.     */

  if (!(todisplay & DASHW0))
    for (i = 3; i < 9; i++)
      for (j = 0; j < WHEELROWS/2; j++) {
	k = WHEELROWS-1-j;
	l = wheel[i][j]; wheel[i][j] = wheel[i][k]; wheel[i][k] = l;
      }

  /* Here we actually print the wheel and the objects in it. */

  putchar('+'); printtab('-', WHEELCOLS-8); printf("<11>");
  printminute(house[11]); printtab('-', WHEELCOLS-11); printf("<10>");
  printminute(house[10]); printtab('-', WHEELCOLS-10); printf("<9>");
  printminute(house[9]); printtab('-', WHEELCOLS-4); printf("+\n");
  for (i = 0; i < WHEELROWS; i++) {
    for (j = 11; j >= 8; j--) {
      putchar('|'); printwheelslot(j, i);
    }
    printf("|\n");
  }
  printf("<12>"); printminute(house[12]); printtab('-', WHEELCOLS-11);
  putchar('|'); printtab('-', WHEELCOLS*2-1); putchar('|');
  printtab('-', WHEELCOLS-10); printminute(house[8]); printf("<8>\n");
  for (i = 0; i < WHEELROWS; i++) {
    putchar('|'); printwheelslot(12, i); putchar('|');

    /* For some rows, we have to insert the chart header information. */

    if (i) {
      printtab(' ', WHEELCOLS-11);
      if (i == 1)
	printf("Astrolog (%s) chart", VERSION);
      else if (i == 2) {
	j = (int) Mon;
	k = ((int) mdytojulian(Mon, Day, Yea) + 1) % 7;
	printf("%c%c%c %2d %c%c%c ",
	       dayname[k][0], dayname[k][1], dayname[k][2], (int) Day,
	       monthname[j][0], monthname[j][1], monthname[j][2]);
	k = (int) ((dabs(Tim)-floor(dabs(Tim)))*100.0+0.5);
	printf("%4d %2.0f:%d%d", (int) Yea, floor(Tim), k/10, k%10);
      } else {
	printf("%c%d%d:", Zon > 0.0 ? '-' : '+',
	       (int)dabs(Zon)/10, (int)dabs(Zon)%10);
	j = (int) ((dabs(Zon)-floor(dabs(Zon)))*100.0+0.5);
	printf("%d%d %s", j/10, j%10, stringlocation(Lon, Lat, 100.0));
      }
      printtab(' ', WHEELCOLS-11);

    } else
      printtab(' ', WHEELCOLS*2-1);
    putchar('|'); printwheelslot(7, i); printf("|\n");
  }
  printf("<1>"); printminute(house[1]); printtab('-', WHEELCOLS-10);
  putchar('|'); printtab(' ', WHEELCOLS-11);
  printf("%s", systemname[housesystem]);
  printtab(' ', 14-stringlen(systemname[housesystem]));
  printf("Houses."); printtab(' ', WHEELCOLS-11); putchar('|');
  printtab('-', WHEELCOLS-10); printminute(house[7]); printf("<7>\n");
  for (i = 0; i < WHEELROWS; i++) {
    putchar('|'); printwheelslot(1, i); putchar('|');
    printtab(' ', WHEELCOLS*2-1); putchar('|'); printwheelslot(6, i);
    printf("|\n");
  }
  printf("<2>"); printminute(house[2]); printtab('-', WHEELCOLS-10);
  putchar('|'); printtab('-', WHEELCOLS*2-1); putchar('|');
  printtab('-', WHEELCOLS-10); printminute(house[6]); printf("<6>\n");
  for (i = 0; i < WHEELROWS; i++) {
    for (j = 2; j <= 5; j++) {
      putchar('|'); printwheelslot(j, i);
    }
    printf("|\n");
  }
  printf("+"); printtab('-', WHEELCOLS-4); printminute(house[3]);
  printf("<3>"); printtab('-', WHEELCOLS-10); printminute(house[4]);
  printf("<4>"); printtab('-', WHEELCOLS-10); printminute(house[5]);
  printf("<5>"); printtab('-', WHEELCOLS-7); printf("+\n");
}


/* Display locations of the objects on the screen with respect to the local */
/* horizon, as specified with the -Z switch.                                */

void charthorizon()
{
  double lon, lat, sx, sy, vx, vy,
    lonz[TOTAL+1], latz[TOTAL+1], azi[TOTAL+1], alt[TOTAL+1];
  int i, j, k;
  lon = DTOR(mod(Lon)); lat = DTOR(Lat);

  /* First find zenith location on Earth of each object. */

  for (i = 1; i <= total; i++) {
    lonz[i] = DTOR(planet[i]); latz[i] = DTOR(planetalt[i]);
    ecltoequ(&lonz[i], &latz[i]);
  }

  /* Then, convert this to local horizon altitude and azimuth. */

  for (i = 1; i <= total; i++) if (i != 18) {
    lonz[i] = DTOR(mod(RTOD(lonz[18]-lonz[i]+lon)));
    lonz[i] = DTOR(mod(RTOD(lonz[i]-lon+PI/2.0)));
    equtolocal(&lonz[i], &latz[i], PI/2.0-lat);
    azi[i] = DEGREES-RTOD(lonz[i]); alt[i] = RTOD(latz[i]);
  }

  /* Now, actually print the location of each object. */

  printf("Body Altitude Azimuth  Azi. Vector   %s Vector    Moon Vector\n\n",
	 centerplanet ? " Sun" : " Earth");
  for (k = 1; k <= total; k++) {
    i = k <= BASE ? k : BASE+starname[k-BASE];
    if (!ignore[i] && (i <= THINGS || i > C_HI)) {
      printf("%-4.4s: ", objectname[i]);
      printaltitude(alt[i]);

      /* Determine directional vector based on azimuth. */

      j = (int) ((azi[i]-floor(azi[i]))*60.0);
      printf(" %3d %d%d'", (int) azi[i], j/10, j%10);
      sx = cos(DTOR(azi[i])); sy = sin(DTOR(azi[i]));
      if (dabs(sx) < dabs(sy)) {
	vx = dabs(sx / sy); vy = 1.0;
      } else {
	vy = dabs(sy / sx); vx = 1.0;
      }
      printf(" (%.2f%c %.2f%c)",
	     vy, sy < 0.0 ? 's' : 'n', vx, sx > 0.0 ? 'e' : 'w');

      /* Determine distance vector of current object from Sun and Moon. */

      vx = azi[1]-azi[i]; vy = azi[2]-azi[i];
      printf(" [%6.1f%6.1f] [%6.1f%6.1f]",
        dabs(vx) < 180.0 ? vx : sgn(vx)*(DEGREES-dabs(vx)), alt[1]-alt[i],
	dabs(vy) < 180.0 ? vy : sgn(vy)*(DEGREES-dabs(vy)), alt[2]-alt[i]);
      if (i >= U_LO) {
	if (i <= U_HI)
	  printf("  Uranian #%d", i-U_LO+1);
	else
	  printf("  Star #%2d", i-S_LO+1);
      }
      putchar('\n');
    }
  }
}


/* Display x,y,z locations of each body (in AU) with respect to the Sun */
/* (or whatever the specified center planet is), as in the -S switch.   */
/* These values were already determined when calculating the planet     */
/* positions themselves, so this procedure is basically just a loop.    */

void chartspace()
{
  double x, y, z;
  int i;
  printf("Body     Angle    X axis    Y axis    Z axis    Length\n");
  for (i = 0; i <= BASE; i++)
    if (!ignore[i] && i != 2 && (i < THINGS || i > C_HI)) {
      printf("%c%c%c%c: ", OBJNAM(i),
	     objectname[i][3] ? objectname[i][3] : ' ');
      x = spacex[i]; y = spacey[i]; z = spacez[i];
      printf("[%7.2f] [%7.2f] [%7.3f] [%7.3f] [%7.3f]",
	     planet[i], x, y, z, sqrt(x*x+y*y+z*z));
      if (i >= U_LO) {
	if (i <= U_HI)
	  printf("  Uranian #%d", i-U_LO+1);
	else
	  printf("  Star #%2d", i-S_LO+1);
      }
      printf("\n");
    }
}


/* Influence information used by chartinfluence() follows. The influence of */
/* a planet in its ruling or exalting sign or house is tacked onto the last */
/* two positions of the object and house influence array, respectively.     */

  /* The inherent strength of each planet - */
double objectinf[] = {0, 30, 25, 10, 10, 10, 10, 10, 10, 10, 10,
		      5, 5, 5, 5, 5, 5, 5, 15, 20, 5,
		      20, 10};

  /* The inherent strength of each house - */
double houseinf[]  = {0, 20, 0, 0, 10, 0, 0, 5, 0, 0, 15, 0, 0,
		      15, 5};

  /* The inherent strength in each aspect - */
double aspectinf[] = {0.0, 1.0, 0.8, 0.8, 0.6, 0.6, 0.4, 0.4, 0.2, 0.2,
		      0.2, 0.2, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1};

  /* This little array is the reverse of the ruler arrays in data.c: */
  /* Here, given a sign, return what planet rules it.                */
int rules[SIGNS+1] = {0, 5, 4, 3, 2, 1, 3, 4, 10, 6, 7, 8, 9};


/* This is a subprocedure of chartinfluence(). Based on the values in the */
/* array parameter 'value', store numbers in array 'rank' reflecting the  */
/* relative order, e.g. value[x] 2nd greatest array value -> rank[x] = 2. */

sortrank(value, rank)
double *value;
int *rank;
{
  int h, i, j, k;
  value[0] = -1.0;
  for (i = 1; i <= THINGS; i++)
    rank[i] = -1;
  for (h = 1, i = 0; h <= THINGS; h++) if (!ignore[h]) {
    i++;
    k = 0;
    for (j = 1; j <= THINGS; j++) if (!ignore[j])
      if (value[j] > value[k] && rank[j] < 0)
	k = j;

        /* 'k' is the current position of the 'i'th place planet. */

    rank[k] = i;
  }
}


/* Print out a list of power values and relative rankings, based on the */
/* placements of the planets, and their aspects in the aspect grid, as  */
/* specified with the -I "find influences" switch.                      */

void chartinfluence()
{
  double power[OBJECTS+1], power1[OBJECTS+1], power2[OBJECTS+1],
    total, total1, total2, x;
  int rank[OBJECTS+1], rank1[OBJECTS+1], rank2[OBJECTS+1], i, j, k, l;
  char c;
  for (i = 1; i <= OBJECTS; i++) {
    power1[i] = power2[i] = 0.0;
  }
  total = total1 = total2 = 0.0;

  /* First, for each object, find its power based on its placement alone. */

  for (i = 1; i <= THINGS; i++) {
    j = (int) (planet[i]/30.0)+1;
    power1[i] += objectinf[i];            /* Influence of planet itself. */
    power1[i] += houseinf[inhouse[i]];    /* Influence of house it's in. */
    c = dignify(i, j);
    switch (c) {
    case 'R': x = objectinf[21]; break;    /* Planets in signs they rule or  */
    case 'e': x = objectinf[22]; break;    /* are exalted in have influence. */
    default:  x =  0.0;
    }
    power1[i] += x;
    c = dignify(i, inhouse[i]);
    switch (c) {
    case 'R': x = houseinf[13]; break;   /* Planet in house corresponding to */
    case 'e': x = houseinf[14]; break;   /* signs it rules has influence.    */
    default:  x =  0.0;
    }
    power1[i] += x;
    if (i != rules[j])                         /* The planet ruling the sign */
      power1[rules[j]] += objectinf[i]/2.0;    /* and the house that the     */
    if (i != (j = rules[inhouse[i]]))          /* current planet is in, gets */
      power1[j] += objectinf[i]/2.0;           /* extra influence.           */
  }
  for (i = 1; i <= SIGNS; i++) {        /* Various planets get influence */
    j = (int)(house[i]/30.0)+1;         /* if house cusps fall in signs  */
    power1[rules[j]] += houseinf[i];    /* they rule.                    */
  }

  /* Second, for each object, find its power based on aspects it makes. */

  creategrid(FALSE);
  for (j = 1; j <= OBJECTS; j++) if (!ignore[j])
    for (i = 1; i <= OBJECTS; i++) if (!ignore[i] && i != j) {
      k = gridname[MIN(i, j)][MAX(i, j)];
      if (k) {
	l = grid[MIN(i, j)][MAX(i, j)];
	power2[j] += aspectinf[k]*objectinf[i]*
	  (1.0-dabs((double)l)/60.0/aspectorb[k]);
      }
    }

  /* Calculate total power of each planet. */

  for (i = 1; i <= THINGS; i++) if (!ignore[i]) {
    power[i] = power1[i]+power2[i]; total1 += power1[i]; total2 += power2[i];
  }
  total = total1+total2;

  /* Finally, determine ranks of the arrays, then print everything out. */

  sortrank(power1, rank1); sortrank(power2, rank2); sortrank(power, rank);
  printf("Name:    Position     Aspects     Total       Percent\n");
  for (i = 1; i <= THINGS; i++) if (!ignore[i]) {
    printf("%c%c%c%c: ", OBJNAM(i),
	   objectname[i][3] ? objectname[i][3] : ' ');
    printf("%6.1f (%2d) +%6.1f (%2d) =%7.1f (%2d) /%6.1f%%\n",
	   power1[i], rank1[i], power2[i], rank2[i],
	   power[i], rank[i], power[i]/total*100.0);
  }
  printf("Tot : %6.1f      +%6.1f      =%7.1f      / 100.0%%\n",
	 total1, total2, total);
}


/* Print the locations of the astro-graph lines on the Earth as specified */
/* with the -L switch. This includes Midheaven and Nadir lines, zenith    */
/* positions, and locations of Ascendant and Descendant lines.            */

void chartastrograph()
{
  double planet1[TOTAL+1], planet2[TOTAL+1], lat[MAXCROSS], lon[MAXCROSS],
    mc[TOTAL+1], ic[TOTAL+1], as[TOTAL+1], ds[TOTAL+1], as1[TOTAL+1],
    ds1[TOTAL+1], lo = Lon, longm, w, x, y, z, ad, oa, am, od, dm;
  int obj1[MAXCROSS], obj2[MAXCROSS], occurcount = 0, i, j, k, l, m, n;
  for (i = 1; i <= TOTAL; i++) {
    planet1[i] = DTOR(planet[i]);
    planet2[i] = DTOR(planetalt[i]);      /* Calculate zenith location on */
    ecltoequ(&planet1[i], &planet2[i]);   /* Earth of each object.        */
  }

  /* Print header. */

  printf("Object :");
  for (i = 1; i <= total; i++)
    if (!ignore[i] && (i <= THINGS || i > C_HI))
      printf(" %c%c%c", OBJNAM(i));
  printf("\n------ :");
  for (i = 1; i <= total; i++)
    if (!ignore[i] && (i <= THINGS || i > C_HI))
      printf(" ###");

  /* Print the longitude locations of the Midheaven lines. */

  printf("\nMidheav: ");
  if (lo < 0.0)
    lo += DEGREES;
  for (i = 1; i <= total; i++)
    if (!ignore[i] && (i <= THINGS || i > C_HI)) {
    x = DTOR(MC)-planet1[i];
    if (x < 0.0)
      x += 2.0*PI;
    if (x > PI)
      x -= 2.0*PI;
    z = lo+RTOD(x);
    if (z > 180.0)
      z -= DEGREES;
    mc[i] = z;
    printf("%3.0f%c", dabs(z), z < 0.0 ? 'e' : 'w');
  }

  /* The Nadir lines are just always 180 degrees away from the Midheaven. */

  printf("\nNadir  : ");
  for (i = 1; i <= total; i++)
    if (!ignore[i] && (i <= THINGS || i > C_HI)) {
    z = mc[i] + 180.0;
    if (z > 180.0)
      z -= DEGREES;
    ic[i] = z;
    printf("%3.0f%c", dabs(z), z < 0.0 ? 'e' : 'w');
  }

  /* Print the Zenith latitude locations. */

  printf("\nZenith : ");
  for (i = 1; i <= total; i++)
    if (!ignore[i] && (i <= THINGS || i > C_HI)) {
      y = RTOD(planet2[i]);
      printf("%3.0f%c", dabs(y), y < 0.0 ? 's' : 'n');
      as[i] = ds[i] = as1[i] = ds1[i] = 1000.0;
    }
  printf("\n\n");

  /* Now print the locations of Ascendant and Descendant lines. Since these */
  /* are curvy, we loop through the latitudes, and for each object at each  */
  /* latitude, print the longitude location of the line in question.        */

  longm = DTOR(mod(MC+lo));
  for (j = 80; j >= -80; j -= graphstep) {
    printf("Asc@%2d%c: ", j >= 0 ? j : -j, j < 0 ? 's' : 'n');
    for (i = 1; i <= total; i++)
      if (!ignore[i] && (i <= THINGS || i > C_HI)) {
      ad = tan(planet2[i])*tan(DTOR(j));
      if (ad*ad > 1.0) {
	printf(" -- ");
	as1[i] = ds1[i] = ret2[i] = 1000.0;
      } else {
	ad = ASIN(ad);
	oa = planet1[i]-ad;
	if (oa < 0.0)
	  oa += 2.0*PI;
	am = oa-PI/2.0;
	if (am < 0.0)
	  am += 2.0*PI;
	z = longm-am;
	if (z < 0.0)
	  z += 2.0*PI;
	if (z > PI)
	  z -= 2.0*PI;
	as1[i] = as[i];
 	as[i] = z = RTOD(z);
	ret2[i] = ad;
	printf("%3.0f%c", dabs(z), z < 0.0 ? 'e' : 'w');
      }
    }

    /* Again, the Descendant position is related to the Ascendant's,  */
    /* being a mirror image, so it can be calculated somewhat easier. */

    printf("\nDsc@%2d%c: ", j >= 0 ? j : -j, j < 0 ? 's' : 'n');
    for (i = 1; i <= total; i++)
      if (!ignore[i] && (i <= THINGS || i > C_HI)) {
      ad = ret2[i];
      if (ad == 1000.0)
	printf(" -- ");
      else {
	od = planet1[i]+ad;
	dm = od+PI/2.0;
	z = longm-dm;
	if (z < 0.0)
	  z += 2.0*PI;
	if (z > PI)
	  z -= 2.0*PI;
	ds1[i] = ds[i];
	ds[i] = z = RTOD(z);
	printf("%3.0f%c", dabs(z), z < 0.0 ? 'e' : 'w');
      }
    }
    putchar('\n');

    /* Now, if the -L0 switch is in effect, then take these line positions, */
    /* which we saved in an array above as we were printing them, and       */
    /* calculate and print the latitude crossings.                          */

    if (todisplay & DASHL0)
      for (l = 1; l <= total; l++)
	if (!ignore[l] && (l <= THINGS || l > C_HI))
	for (k = 1; k <= total; k++)
	  if (!ignore[k] && (k <= THINGS || k > C_HI))
	  for (n = 0; n <= 1; n++) {
	    x = n ? ds1[l] : as1[l];
	    y = n ? ds[l] : as[l];
	    for (m = 0; m <= 1; m++) {

	      /* Check if Ascendant/Descendant cross Midheaven/Nadir. */

	      z = m ? ic[k] : mc[k];
	      if (occurcount < MAXCROSS &&
		  dabs(x-y) < 180.0 && sgn(z-x) != sgn(z-y)) {
		obj1[occurcount] = n ? -l : l;
		obj2[occurcount] = m ? -k : k;
		lat[occurcount] = (double)j+5.0*dabs(z-y)/dabs(x-y);
		lon[occurcount] = z;
		occurcount++;
	      }

	      /* Check if Ascendant/Descendant cross another Asc/Des. */

	      w = m ? ds1[k] : as1[k];
	      z = m ? ds[k] : as[k];
	      if (occurcount < MAXCROSS && k > l &&
		  dabs(x-y)+dabs(w-z) < 180.0 && sgn(w-x) != sgn(z-y)) {
		obj1[occurcount] = n ? -l : l;
		obj2[occurcount] = 100+(m ? -k : k);
		lat[occurcount] = (double)j+5.0*
		  dabs(y-z)/(dabs(x-w)+dabs(y-z));
		lon[occurcount] = MIN(x, y)+dabs(x-y)*
		  dabs(y-z)/(dabs(x-w)+dabs(y-z));
		occurcount++;
	      }
	    }
	  }
  }
  if ((todisplay & DASHL0) == 0)
    return;
  putchar('\n');

  /* Now, print out all the latitude crossings we found.  */
  /* First, we sort them in order of decreasing latitude. */

  for (i = 1; i < occurcount; i++) {
    j = i-1;
    while (j >= 0 && lat[j] < lat[j+1]) {
      swapint(&obj1[j], &obj1[j+1]); swapint(&obj2[j], &obj2[j+1]);
      swapdoub(&lat[j], &lat[j+1]); swapdoub(&lon[j], &lon[j+1]);
      j--;
    }
  }
  for (i = 1; i < occurcount; i++) {
    j = abs(obj1[i]);
    printf("%c%c%c %s crosses ", OBJNAM(j),
	   obj1[i] > 0 ? "Ascendant " : "Descendant");
    j = abs(obj2[i] - (obj2[i] < 50 ? 0 : 100));
    printf("%c%c%c %s at ", OBJNAM(j),
	   obj2[i] < 50 ? (obj2[i] > 0 ? "Midheaven " :
	   "Nadir     ") : (obj2[i] > 100 ? "Ascendant " : "Descendant"));
    j = (int) ((dabs(lon[i])-floor(dabs(lon[i])))*60.0);
    printf("%3d %d%d'%c, ", (int) dabs(lon[i]),
	   j/10, j%10, lon[i] < 0.0 ? 'E' : 'W');
    j = (int) ((dabs(lat[i])-floor(dabs(lat[i])))*60.0);
    printf("%2d %d%d'%c\n", (int) dabs(lat[i]),
	   j/10, j%10, lat[i] < 0.0 ? 'S' : 'N');
  }
  if (!occurcount)
    printf("No latitude crossings.\n");
}

/**/