#include "drawgraphics.h"

/* Version 3.52c.  Copyright (c) 1986-1993 by Joseph Felsenstein and
  Christopher A. Meacham.  Additional code written by Hisashi Horino,
  Sean Lamont, Andrew Keefe, and Akiko Fuseki.
  Permission is granted to copy, distribute,
  and modify this program provided that (1) this copyright message is
  not removed and (2) no fee is charged for this program. */

#define maxnch          30
#define point           '.'
#define fontsize        3800
#define pi              3.141592653
#define epsilon         0.00001
#define xstart          10
#define ystart          35
#define gap             0.5
#define iterations      5

#ifdef MAC
#undef maxnodes
#define maxnodes 250
#endif

typedef enum {  fixed, radial, along} labelorient;
FILE *treefile, *plotfile;
char        pltfilename[100];
long        ntips, nextnode,  strpwide, strpdeep,
	    strptop, strpbottom,  payge, numlines;
double       xmargin, ymargin, topoflabels, rightoflabels, leftoflabels,
              bottomoflabels, ark, maxx, maxy, minx, miny, scale, xscale,
	      yscale, xoffset, yoffset, charht, xnow, ynow, xunitspercm,
	      yunitspercm, xsize, ysize, xcorner, ycorner,labelheight,
	      labelrotation, treeangle,  expand, bscale,enthusiasm;
boolean        canbeplotted, preview, previewing, dotmatrix,haslengths,
	       uselengths, regular, didreroot, rotate, empty, rescaled,
               notfirst, improve;
       double textlength[maxnodes], firstlet[maxnodes];
       striptype stripe;
       plottertype plotter, oldplotter, previewer;
       growth grows;
       labelorient labeldirec;
       node *root, *where;
      node *nodep[maxnodes];
       fonttype font;
       enum {  yes, no } penchange, oldpenchange;
char ch;
char fontname[64];
long filesize;
long strpdiv;

openfile(fp,filename,mode,application,perm)
FILE **fp;
char *filename;
char *mode;
char *application;
char *perm;
{
  FILE *of;
  char file[100];
  strcpy(file,filename);
  while (1){
    of = fopen(file,mode);
    if (of)
      break;
    else {
      switch (*mode){
      case 'r':
        printf("%s:  can't read %s\n",application,file);
        file[0]='\0';
        while (file[0] =='\0'){
          printf("Please enter a new filename>");
          gets(file);}
        break;
      case 'w':
        printf("%s: can't write %s\n",application,file);
        file[0] = '\0';
        while (file[0] =='\0'){
          printf("Please enter a new filename>");
          gets(file);}
        break;
      }
    }
  }
  *fp=of;
  if (perm != NULL)
    strcpy(perm,file);
}

void uppercase(ch)
Char *ch;
{
  /* make ch upper-case */
   *ch = (islower(*ch) ?  toupper(*ch) : (*ch));
}  /* uppercase */

/* Local variables for treeread: */

void getch(c)
Char *c;
{
  /* get next nonblank character */
  do {*c = getc(treefile);
  } while ((*c == ' ')||(*c == '\n')||(*c == '\t'));
}  /* getch */

void processlength(p)
node *p;
{
  long  digit, ordzero;
  double valyew, divisor;
  boolean pointread, minusread;

  ordzero = '0';
  pointread = false;
  minusread = false;
  valyew = 0.0;
  divisor = 1.0;
  getch(&ch);
  digit = ch - ordzero;
  while (((unsigned long)digit <= 9) || (ch == '.') || (ch == '.')){
        if (ch == '.')   pointread = true;
   else if (ch == '-')   minusread = true;
   else {
        valyew = valyew * 10.0 + digit;
        if (pointread)
          divisor *= 10.0;
      }
        getch(&ch);
        digit = ch - ordzero;
      }
 if (!minusread)
   p->oldlen = valyew / divisor;
 else
   p->oldlen = 0.0;
  /* processlength */
}

void addelement(p, q)
node **p, *q;
{
  /* read in and add next part of tree, it will be node p
    and will be hooked to pointer q */
  node *pp;
  long n,indx;
  boolean notlast;

  nextnode++;
  *p = (node *)Malloc((long)sizeof(node));
  nodep[nextnode - 1] = *p;
  indx = nextnode;
  (*p)->index = indx;
  if (ch == '(') {
    (*p)->tip = false;
    pp = *p;
    notlast = true;
    while (notlast) {
      pp->next = (node *)Malloc((long)sizeof(node));
      pp->next->tip = false;
      nextnode++;
      nodep[nextnode - 1] = pp->next;
      pp->next->index = indx;
      pp = pp->next;
      getch(&ch);
      addelement(&pp->back, pp);
      if (ch == ')') {
	notlast = false;
	do {
	  getch(&ch);
	} while (ch != ':' && ch != ',' && ch != ')' && ch != '[' &&
		 ch != ';');
      }
    }
    pp->next = *p;
  } else {
    (*p)->tip = true;
    ntips++;
    n = 1;
    do {
      if (!ebcdic && (ch & 255) == 255)
	ch = '\'';
      if (!ebcdic && (ch & 255) > 175)
	ch -= 48;
      if (!ebcdic && (ch & (~127)) != 0)
	ch -= 64;
      if (ch == '_')
	ch = ' ';
      if (n < maxnch)
	(*p)->nayme[n - 1] = ch;
      if (eoln(treefile)) {
	fscanf(treefile, "%*[^\n]");
	(void)getc(treefile);
      }
      ch = getc(treefile);
      if (ch == '\n')
	ch = ' ';
      n++;
    } while (ch != ':' && ch != ',' && ch != ')');
    if (n > maxnch)
      n = maxnch + 1;
    (*p)->naymlength = n - 1;
  }
  if (ch == ':')
    processlength(*p);
  else
    haslengths = (haslengths && q == NULL);
  (*p)->back = q;
  if (haslengths && q != NULL)
    (*p)->back->oldlen = (*p)->oldlen;
  (*p)->r = 0.0;
  (*p)->theta = 0.0;
}  /* addelement */

void treeread()
{
  /* read a tree from the treefile and set up nodes and pointers */
  haslengths = true;
  ntips = 0;
  nextnode = 0;
  getch(&ch);
  addelement(&root, NULL);
  root->oldlen = 0.0;
  fscanf(treefile, "%*[^\n]");
  (void)getc(treefile);
  uselengths = haslengths;
  where = root;
  rotate = true;
}  /* treeread */

void initialparms()
{
  /* initialize parameters */

  getplotter();
  plotrparms();
  xmargin = 0.08 * xsize;
  ymargin = 0.08 * ysize;
  xscale = xunitspercm;
  yscale = yunitspercm;
  grows = vertical;
  treeangle = pi / 2.0;
  ark = 2 * pi;
  improve = true;
  regular = false;
  rescaled = true;
  bscale = 1.0;
  labeldirec = fixed;
  labelrotation = 0.0;
  charht = 0.3333;
  numlines = dotmatrix ? ((long)floor(yunitspercm * ysize + 0.5) / strpdeep):1;
  enthusiasm = 1.0/(double)ntips;
}  /* initialparms */


long showparms()
{
  long i;
  long numtochange;
  Char ch,input[64];
  double treea;

  putchar('\n');
  if (previewer == tek)
    printf("%c\f", escape);
  else {
    for (i = 1; i <= 24; i++)
      putchar('\n');
  }
  printf("Here are the settings: \n\n");
  printf(" (1)        Use branch lengths:  ");
  if (haslengths)
    printf("%s\n",uselengths ? "Yes" : "No");
   else
    printf("(no branch lengths available)\n");
  printf(" (2)           Angle of labels:");
  if (labeldirec == fixed) {
    printf("  Fixed angle of");
    if (labelrotation >= 10.0)
      printf("%6.1f", labelrotation);
    else if (labelrotation <= -10.0)
      printf("%7.1f", labelrotation);
    else if (labelrotation < 0.0)
      printf("%6.1f", labelrotation);
    else
      printf("%5.1f", labelrotation);
    printf(" degrees\n");
  } else if (labeldirec == radial)
    printf("  Radial\n");
  else
    printf("  Along branches\n");
  printf(" (3)          Rotation of tree:");
  treea = treeangle * 180 / pi;
  if (treea >= 100.0)
    printf("%7.1f\n", treea);
  else if (treea >= 10.0)
    printf("%6.1f\n", treea);
  else if (treea <= -100.0)
    printf("%8.1f\n", treea);
  else if (treea <= -10.0)
    printf("%7.1f\n", treea);
  else if (treea < 0.0)
    printf("%6.1f\n", treea);
  else
    printf("%5.1f\n", treea);
  printf(" (4)     Angle of arc for tree:");
  treea = 180 * ark / pi;
  if (treea >= 100.0)
    printf("%7.1f\n", treea);
  else if (treea >= 10.0)
    printf("%6.1f\n", treea);
  else if (treea <= -100.0)
    printf("%8.1f\n", treea);
  else if (treea <= -10.0)
    printf("%7.1f\n", treea);
  else if (treea < 0.0)
    printf("%6.1f\n", treea);
  else
    printf("%5.1f\n", treea);
  printf(" (5)   Iterate to improve tree:  %s\n",
	 (improve ? "Yes" : "No"));
  printf(" (6)    Scale of branch length:");
  if (rescaled)
    printf("  Automatically rescaled\n");
  else
    printf("  Fixed:%6.2f cm per unit branch length\n", bscale);
  didreroot = false;
  printf(" (7)        Horizontal margins:%6.2f cm\n", xmargin);
  printf(" (7)          Vertical margins:%6.2f cm\n", ymargin);
  printf(" (8) Relative character height:%8.4f\n", charht);
  if (!improve)
    printf(" (9)     Regularize the angles:  %s\n",(regular ? "Yes" : "No"));
  else
    printf(" (9)       Enthusiasm constant:%9.5f\n",enthusiasm);
  if (plotter == lw)
    printf(" (10)           Font          :  %s\n",fontname);

  printf("\n\n Do you want to accept these? (Yes or No)\n");
  for (;;) {
    printf(" Type Y or N or the number (1-%2ld) of the one to change: \n",
            (plotter == lw) ? 10L : 9L);
    gets(input);
    uppercase(&input[0]);
    ch=input[0];
    numtochange = atoi(input);
    if ((ch == 'Y' || ch == 'N') || (numtochange >= 1 && numtochange <=
       ((plotter == lw) ? 10 : 9)))
      break;
  }
  return (ch == 'Y') ? -1 : numtochange;
}  /* showparms */

void rerootit(p)
node *p;
{
  node *q;

  q = root;
  while (q->next != root)
    q = q->next;
  q->next = root->next;
  q = p;
  while (q->next != p)
    q = q->next;
  root->next = p;
  q->next = root;
}  /* rerootit */

void reroot()
{
  /* reroot the tree, traversing tree */
  where = root->next;
  if (!rotate)
    rotate = where->back->tip;
  if (rotate) {
    where = where->next;
    rotate = false;
  } else {
    where = where->back;
    rotate = true;
  }
  rerootit(where);
}  /* reroot */


void getparms(numtochange)
long numtochange;
{
  /* get from user the relevant parameters for the plotter and diagram */
  Char ch;
  boolean ok;

  if (numtochange == 0) {
    do {
      printf(" Type the number of one that you want to change (1-%2ld):\n",
              (plotter == lw) ? 10L : 9L);
      scanf("%ld%*[^\n]", &numtochange);
      (void)getchar();
    } while (numtochange < 1 || numtochange > ((plotter == lw) ? 10 : 9));
  }
  switch (numtochange) {

  case 1:
    if (haslengths)
      uselengths = !uselengths;
    else {
      printf("Cannot use lengths since not all of them exist\n");
      uselengths = false;
    }
    break;

  case 2:
    printf("\nDo you want labels to be Fixed angle, Radial,");
    printf(" or Along branches?\n");
    do {
      printf(" Type F, R, or A\n");
      scanf("%c%*[^\n]", &ch);
      (void)getchar();
      if (ch == '\n')
	ch = ' ';
      uppercase(&ch);
    } while (ch != 'F' && ch != 'R' && ch != 'A');
    switch (ch) {

    case 'A':
      labeldirec = along;
      break;

    case 'F':
      labeldirec = fixed;
      break;

    case 'R':
      labeldirec = radial;
      break;
    }
    if (labeldirec == fixed) {
      printf("Are the labels to be plotted vertically (90),\n");
      printf(" horizontally (0), or downwards (-90) ?\n");
      do {
	printf(" Choose an angle in degrees from 90 to -90: \n");
	scanf("%lf%*[^\n]", &labelrotation);
	(void)getchar();
      } while ((labelrotation < -90.0 || labelrotation > 90.0) &&
	       labelrotation != -99.0);
    }
    break;

  case 3:
    printf("\n At what angle is the tree to be plotted?\n");
    do {
      printf(" Choose an angle in degrees from 360 to -360: \n");
      scanf("%lf%*[^\n]", &treeangle);
      (void)getchar();
      uppercase(&ch);
    } while (treeangle < -360.0 && treeangle > 360.0);
    treeangle = treeangle * pi / 180;
    break;

  case 4:
    printf(" How many degrees (up to 360) of arc\n");
    printf("  should the tree occupy? (Currently it is %5.1f)\n",
	   180 * ark / pi);
    do {
      printf("Enter a number of degrees from 0 up to 360)\n");
      scanf("%lf%*[^\n]", &ark);
      (void)getchar();
    } while (ark <= 0.0 || ark > 360.0);
    ark = ark * pi / 180;
    break;

  case 5:
    improve = !improve;
    break;

  case 6:
    rescaled = !rescaled;
    if (!rescaled) {
      printf("Centimeters per unit branch length?\n");
      scanf("%lf%*[^\n]", &bscale);
      (void)getchar();
    }
    break;

  case 7:
    printf("\nThe tree will be drawn to fit in a rectangle which has \n");
    printf(" margins in the horizontal and vertical directions of:\n");
    printf("%6.2f cm (horizontal margin) and%6.2f cm (vertical margin)\n\n",
	   xmargin, ymargin);
    do {
      printf(" New value (in cm) of horizontal margin?\n");
      scanf("%lf%*[^\n]", &xmargin);
      (void)getchar();
      ok = ((unsigned)xmargin < xsize / 2.0);
      if (!ok)
	printf(" Impossible value.  Please retype it.\n");
    } while (!ok);
    do {
      printf(" New value (in cm) of vertical margin?\n");
      scanf("%lf%*[^\n]", &ymargin);
      (void)getchar();
      ok = ((unsigned)ymargin < ysize / 2.0);
      if (!ok)
	printf(" Impossible value.  Please retype it.\n");
    } while (!ok);
    break;

  case 8:
    printf("New value of character height?\n");
    scanf("%lf%*[^\n]", &charht);
    (void)getchar();
    break;
  case 9:
    if (improve) {
      do {
	printf("Enthusiasm constant? (must be between 0 and 1)\n");
	scanf("%lf%*[^\n]", &enthusiasm);
	getchar();
      } while (enthusiasm <= 0.0 || enthusiasm > 1.0);}
    else
      regular = !regular;
    break;
  case 10:
    printf("Enter font name or \"Hershey\" for default font\n");
    gets(fontname);
    break;
  }
}  /* getparms */


Local void getwidth(p)
node *p;
{
  /* get width and depth beyond each node */
  double nw, nd;
  node *pp, *qq;

  nd = 0.0;
  if (p->tip)
    nw = 1.0;
  else {
    nw = 0.0;
    qq = p;
    pp = p->next;
    do {
      getwidth(pp->back);
      nw += pp->back->width;
      if (pp->back->depth > nd)
	nd = pp->back->depth;
      pp = pp->next;
    } while (pp != qq);
  }
  p->depth = nd + p->length;
  p->width = nw;
}  /* getwidth */

void plrtrans(p, theta, lower, upper)
node *p;
double theta, lower, upper;
{
  /* polar coordinates of a node relative to start */
  long num;
  double nn, pr, ptheta, angle, angle2, subangle, len;
  node *pp, *qq;

  nn = p->width;
  angle = theta;
  subangle = (upper - lower) / nn;
  qq = p;
  pp = p->next;
  if (p->tip)
    return;
  angle = upper;
  do {
    angle -= pp->back->width / 2.0 * subangle;
    pr = p->r;
    ptheta = p->theta;
    if (regular) {
      num = 1;
      while (num * subangle < 2 * pi)
	num *= 2;
      if (angle >= 0.0)
	angle2 = 2 * pi / num * (long)(num * angle / (2 * pi) + 0.5);
      else
	angle2 = 2 * pi / num * (long)(num * angle / (2 * pi) - 0.5);
    } else
      angle2 = angle;
    if (uselengths)
      len = pp->back->oldlen;
    else
      len = 1.0;
    pp->back->r = sqrt(len * len + pr * pr + 2 * len * pr * cos(angle2 - ptheta));
    if (fabs(pr * cos(ptheta) + len * cos(angle2)) > epsilon)
      pp->back->theta = atan((pr * sin(ptheta) + len * sin(angle2)) /
			     (pr * cos(ptheta) + len * cos(angle2)));
    else if (pr * sin(ptheta) + len * sin(angle2) >= 0.0)
      pp->back->theta = pi / 2;
    else
      pp->back->theta = 1.5 * pi;
    if (pr * cos(ptheta) + len * cos(angle2) < -epsilon)
      pp->back->theta += pi;
    if (!pp->back->tip)
      plrtrans(pp->back, pp->back->theta,
		 angle - pp->back->width * subangle / 2.0,
		 angle + pp->back->width * subangle / 2.0);
    else
      pp->back->oldtheta = angle2;
    angle -= pp->back->width / 2.0 * subangle;
    pp = pp->next;
  } while (pp != qq);
}  /* plrtrans */

void coordtrav(p, xx, yy)
node *p;
double *xx, *yy;
{
  /* compute x and y coordinates */
  long i;
  node *pp;

  if (!p->tip) {
    pp = p->next;
    while (pp != p) {
      coordtrav(pp->back, xx,yy);
      pp = pp->next;
    }
  }
  if (p->tip) {
    i = 1;
    while (nodep[i - 1] != p)
      i++;
    textlength[i - 1] = (double)lengthtext(p->nayme, p->naymlength, font);
  }
  (*xx) = p->r * cos(p->theta);
  (*yy) = p->r * sin(p->theta);
  if ((*xx) > maxx)
    maxx = (*xx);
  if ((*xx) < minx)
    minx = (*xx);
  if ((*yy) > maxy)
    maxy = (*yy);
  if ((*yy) < miny)
    miny = (*yy);
  p->xcoord = (*xx);
  p->ycoord = (*yy);
}  /* coordtrav */


double angleof(x, y)
double x, y;
{
  /* compute the angle of a vector */
  double theta;

  if (fabs(x) > epsilon)
    theta = atan(y / x);
  else if (y >= 0.0)
    theta = pi / 2;
  else
    theta = 1.5 * pi;
  if (x < -epsilon)
    theta = pi + theta;
  if (theta > 2 * pi)
    theta -= 2 * pi;
  return theta;
}  /* angleof */

void polartrav(p,xx,yy,leftx,lefty,rightx,righty)
node    *p;
double  *xx,*yy,*leftx,*lefty,*rightx,*righty;
{
  /* go through subtree getting left and right vectors */
  double x, y;
  boolean lookatit;
  node *pp;

  lookatit = true;
  if (!p->tip)
    lookatit = (p->next->next->next != p || p->index != root->index);
  if (lookatit) {
    x = nodep[p->index - 1]->xcoord;
    y = nodep[p->index - 1]->ycoord;
    if ((y - (*yy)) * (*rightx) - (x - (*xx)) * (*righty) < 0.0) {
      (*rightx) = x - (*xx);
      (*righty) = y - (*yy);
    }
    if ((y - (*yy)) * (*leftx) - (x - (*xx)) * (*lefty) > 0.0 &&
	!(notfirst && fabs((*rightx) - x + (*xx)) +
	  fabs((*righty) - y + (*yy)) < epsilon)) {
      (*leftx) = x - (*xx);
      (*lefty) = y - (*yy);
      notfirst = true;
    }
  }
  if (p->tip)
    return;
  pp = p->next;
  while (pp != p) {
    if (pp != root)
      polartrav(pp->back,xx,yy,leftx,lefty,rightx,righty);
    pp = pp->next;
  }
}  /* polartrav */

void tilttrav(q,xx,yy,sinphi,cosphi)
node *q;
double *xx,*yy,*sinphi,*cosphi;
{
  /* traverse to move successive nodes */
  double x, y;
  node *pp;

  pp = nodep[q->index - 1];
  x = pp->xcoord;
  y = pp->ycoord;
  pp->xcoord = (*xx) + (x - (*xx)) * (*cosphi) + (y - (*yy)) * (*sinphi);
  pp->ycoord = (*yy) + ((*xx) - x) * (*sinphi) + (y - (*yy)) * (*cosphi);
  if (q->tip)
    return;
  pp = q->next;
  while (pp != q) {
    if (pp != root)
      tilttrav(pp->back,xx,yy,sinphi,cosphi);
    pp = pp->next;
  }
}  /* tilttrav */

void polarize(p,xx,yy)
node *p;
double *xx,*yy;
{
  double TEMP, TEMP1;

  if (fabs(p->xcoord - (*xx)) > epsilon)
    p->oldtheta = atan((p->ycoord - (*yy)) / (p->xcoord - (*xx)));
  else if (p->ycoord - (*yy) >= 0.0)
    p->oldtheta = pi / 2;
  else
    p->oldtheta = 1.5 * pi;
  if (p->xcoord - (*xx) < -epsilon)
    p->oldtheta += pi;
  if (fabs(p->xcoord - root->xcoord) > epsilon)
    p->theta = atan((p->ycoord - root->ycoord) / (p->xcoord - root->xcoord));
  else if (p->ycoord - root->ycoord >= 0.0)
    p->theta = pi / 2;
  else
    p->theta = 1.5 * pi;
  if (p->xcoord - root->xcoord < -epsilon)
    p->theta += pi;
  TEMP = p->xcoord - root->xcoord;
  TEMP1 = p->ycoord - root->ycoord;
  p->r = sqrt(TEMP * TEMP + TEMP1 * TEMP1);
}  /* polarize */

void improvtrav(p)
node *p;
{
  /* traverse tree trying different tiltings at each node */
  double xx, yy, leftx, lefty, rightx, righty, cosphi, sinphi;
  long n;
  double usedangle, langle, rangle, freeangle, meanangle, sumrot;
  node *pp, *qq;

  if (p->tip)
    return;
  xx = p->xcoord;
  yy = p->ycoord;
  if (p != root) {
    n = 0;
    usedangle = 0.0;
    pp = p->next;
    do {
      leftx = pp->back->xcoord - xx;
      lefty = pp->back->ycoord - yy;
      rightx = leftx;
      righty = lefty;
      notfirst = false;
      if (!pp->back->tip)
	polartrav(pp->back, &xx,&yy,&leftx,&lefty,&rightx,&righty);
      n++;
      langle = angleof(leftx, lefty);
      rangle = angleof(rightx, righty);
      if (rangle > langle)
	langle += 2 * pi;
      pp->lefttheta = langle;
      pp->righttheta = rangle;
      usedangle += langle - rangle;
      pp = pp->next;
    } while (pp != p->next);
    freeangle = 2 * pi - usedangle;
    meanangle = freeangle / n;
    sumrot = 0.0;
    qq = p;
    pp = p->next;
    while (pp != p) {
      langle = qq->righttheta;
      rangle = pp->lefttheta;
      if (rangle > langle)
	langle += 2 * pi;
      sumrot += enthusiasm * (meanangle - langle + rangle);
      cosphi = cos(sumrot);
      sinphi = sin(sumrot);
      if (pp != root)
	tilttrav(pp->back, &xx,&yy,&sinphi,&cosphi);
      qq = pp;
      pp = pp->next;
    }
  }
  pp = p->next;
  while (pp != p) {
    if (pp != root)
      polarize(pp->back, &xx,&yy);
    pp = pp->next;
  }
  pp = p->next;
  while (pp != p) {
    if (pp != root)
      improvtrav(pp->back);
    pp = pp->next;
  }
}  /* improvtrav */

void coordimprov(xx,yy)
double *xx,*yy;
{
  /* use angles calculation to improve node coordinate placement */
  long i;
  for (i = 1; i <= iterations; i++)
    improvtrav(root);
}  /* coordimprov */


void calculate()
{
  /* compute coordinates for tree */
  double xx, yy;
  long i;
  double nttot, fontheight, labangle, top, bot, rig, lef;

  for (i = 0; i < nextnode; i++)
    nodep[i]->width = 1.0;
  for (i = 0; i < nextnode; i++)
    nodep[i]->xcoord = 0.0;
  for (i = 0; i < nextnode; i++)
    nodep[i]->ycoord = 0.0;
  if (!uselengths) {
    for (i = 0; i < nextnode; i++)
      nodep[i]->length = 1.0;
  } else {
    for (i = 0; i < nextnode; i++)
      nodep[i]->length = nodep[i]->oldlen;
  }
  getwidth(root);
  nttot = root->width;
  for (i = 0; i < nextnode; i++)
    nodep[i]->width = nodep[i]->width * ntips / nttot;
  plrtrans(root, treeangle, treeangle - ark / 2.0, treeangle + ark / 2.0);
  maxx = 0.0;
  minx = 0.0;
  maxy = 0.0;
  miny = 0.0;
  coordtrav(root, &xx,&yy);
  if (improve) {
    coordimprov(&xx,&yy);
    coordtrav(root, &xx,&yy);
  }
  fontheight = font[2];
  if (labeldirec == fixed)
    labangle = pi * labelrotation / 180.0;
  for (i = 0; i < nextnode; i++) {
    if (nodep[i]->tip)
      textlength[i] /= fontheight;
  }
  if (ntips > 1)
    labelheight = charht * (maxx - minx) / (ntips - 1);
  else
    labelheight = charht * (maxx - minx);
  topoflabels = 0.0;
  bottomoflabels = 0.0;
  rightoflabels = 0.0;
  leftoflabels = 0.0;
  for (i = 0; i < nextnode; i++) {
    if (nodep[i]->tip) {
      if (labeldirec == radial)
	labangle = nodep[i]->theta;
      else if (labeldirec == along)
	labangle = nodep[i]->oldtheta;
      if (cos(labangle) < 0.0 && labeldirec != fixed)
	labangle -= pi;
      firstlet[i] = (double)lengthtext(nodep[i]->nayme,1L,font)/ fontheight;
      top = (nodep[i]->ycoord - maxy) / labelheight + sin(nodep[i]->oldtheta);
      rig = (nodep[i]->xcoord - maxx) / labelheight + cos(nodep[i]->oldtheta);
      bot = (miny - nodep[i]->ycoord) / labelheight - sin(nodep[i]->oldtheta);
      lef = (minx - nodep[i]->xcoord) / labelheight - cos(nodep[i]->oldtheta);
      if (cos(labangle) * cos(nodep[i]->oldtheta) +
	  sin(labangle) * sin(nodep[i]->oldtheta) > 0.0) {
	if (sin(labangle) > 0.0)
	  top += sin(labangle) * textlength[i];
	top += sin(labangle - 1.25 * pi) * gap * firstlet[i];
	if (sin(labangle) < 0.0)
	  bot -= sin(labangle) * textlength[i];
	bot -= sin(labangle - 0.75 * pi) * gap * firstlet[i];
	if (sin(labangle) > 0.0)
	  rig += cos(labangle - 0.75 * pi) * gap * firstlet[i];
	else
	  rig += cos(labangle - 1.25 * pi) * gap * firstlet[i];
	rig += cos(labangle) * textlength[i];
	if (sin(labangle) > 0.0)
	  lef -= cos(labangle - 1.25 * pi) * gap * firstlet[i];
	else
	  lef -= cos(labangle - 0.75 * pi) * gap * firstlet[i];
      } else {
	if (sin(labangle) < 0.0)
	  top -= sin(labangle) * textlength[i];
	top += sin(labangle + 0.25 * pi) * gap * firstlet[i];
	if (sin(labangle) > 0.0)
	  bot += sin(labangle) * textlength[i];
	bot -= sin(labangle - 0.25 * pi) * gap * firstlet[i];
	if (sin(labangle) > 0.0)
	  rig += cos(labangle - 0.25 * pi) * gap * firstlet[i];
	else
	  rig += cos(labangle + 0.25 * pi) * gap * firstlet[i];
	if (sin(labangle) < 0.0)
	  rig += cos(labangle) * textlength[i];
	if (sin(labangle) > 0.0)
	  lef -= cos(labangle + 0.25 * pi) * gap * firstlet[i];
	else
	  lef -= cos(labangle - 0.25 * pi) * gap * firstlet[i];
	lef += cos(labangle) * textlength[i];
      }
      if (top > topoflabels)
	topoflabels = top;
      if (bot > bottomoflabels)
	bottomoflabels = bot;
      if (rig > rightoflabels)
	rightoflabels = rig;
      if (lef > leftoflabels)
	leftoflabels = lef;
    }
  }
  topoflabels *= labelheight;
  bottomoflabels *= labelheight;
  leftoflabels *= labelheight;
  rightoflabels *= labelheight;
}  /* calculate */


void rescale()
{
  /* compute coordinates of tree for plot or preview device */
  long i;
  double treeheight, treewidth, extrax, extray, temp;

  treeheight = maxy - miny + topoflabels + bottomoflabels;
  treewidth = maxx - minx + rightoflabels + leftoflabels;
  if (grows == vertical) {
    if (!rescaled)
      expand = bscale;
    else {
      expand = (xsize - 2 * xmargin) / treewidth;
      if ((ysize - 2 * ymargin) / treeheight < expand)
	expand = (ysize - 2 * ymargin) / treeheight;
    }
    extrax = (xsize - 2 * xmargin - treewidth * expand) / 2.0;
    extray = (ysize - 2 * ymargin - treeheight * expand) / 2.0;
  } else {
    if (!rescaled)
      expand = bscale;
    else {
      expand = (ysize - 2 * ymargin) / treewidth;
      if ((xsize - 2 * xmargin) / treeheight < expand)
	expand = (xsize - 2 * xmargin) / treeheight;
    }
    extrax = (xsize - 2 * xmargin - treeheight * expand) / 2.0;
    extray = (ysize - 2 * ymargin - treewidth * expand) / 2.0;
  }
  for (i = 0; i < (nextnode); i++) {
    nodep[i]->xcoord = expand * (nodep[i]->xcoord - minx + leftoflabels);
    nodep[i]->ycoord = expand * (nodep[i]->ycoord - miny + bottomoflabels);
    if (grows == horizontal) {
      temp = nodep[i]->ycoord;
      nodep[i]->ycoord = expand * treewidth - nodep[i]->xcoord;
      nodep[i]->xcoord = temp;
    }
    nodep[i]->xcoord += xmargin + extrax;
    nodep[i]->ycoord += ymargin + extray;
  }
}  /* rescale */

void plottree(p, q)
node *p, *q;
{
  /* plot part or all of tree on the plotting device */
  double x1, y1, x2, y2;
  node *pp;

  x2 = xscale * (xoffset + p->xcoord);
  y2 = yscale * (yoffset + p->ycoord);
  if (p != root) {
    x1 = xscale * (xoffset + q->xcoord);
    y1 = yscale * (yoffset + q->ycoord);
    plot(penup, x1, y1);
    plot(pendown, x2, y2);
  }
  if (p->tip)
    return;
  pp = p->next;
  while (pp != p) {
    plottree(pp->back, p);
    pp = pp->next;
  }
}  /* plottree */


void plotlabels(fontname)
char *fontname;
{
  long i;
  double compr, dx, dy, labangle;
  boolean left, right;
  node *lp;

  compr = xunitspercm / yunitspercm;
  if (penchange == yes)
    changepen(labelpen);
  for (i = 0; i < (nextnode); i++) {
    if (nodep[i]->tip) {
      lp = nodep[i];
      labangle = labelrotation * pi / 180.0;
      if (labeldirec == radial)
	labangle = nodep[i]->theta;
      else if (labeldirec == along)
	labangle = nodep[i]->oldtheta;
      if (cos(labangle) < 0.0)
	labangle -= pi;
      right = (cos(labangle) * cos(nodep[i]->oldtheta) +
	       sin(labangle) * sin(nodep[i]->oldtheta) > 0.0);
      left = !right;
      dx = labelheight * expand * cos(nodep[i]->oldtheta);
      dy = labelheight * expand * sin(nodep[i]->oldtheta);
      if (right) {
	dx += labelheight * expand * 0.5 * firstlet[i] * cos(labangle - 0.75 * pi);
	dy += labelheight * expand * 0.5 * firstlet[i] * sin(labangle - 0.75 * pi);
      }
      if (left) {
	dx += labelheight * expand * 0.5 * firstlet[i] * cos(labangle - 0.25 * pi);
	dy += labelheight * expand * 0.5 * firstlet[i] * sin(labangle - 0.25 * pi);
	dx -= textlength[i] * labelheight * expand * cos(labangle);
	dy -= textlength[i] * labelheight * expand * sin(labangle);
      }
	
      plottext(lp->nayme, lp->naymlength,
	       labelheight * expand * xscale / compr, compr,
	       xscale * (lp->xcoord + dx + xoffset),
	       yscale * (lp->ycoord + dy + yoffset), -180 * labangle / pi,
	       font,fontname);
    }
  }
  if (penchange == yes)
    changepen(treepen);
}  /* plotlabels */



#ifdef CHILDAPP
void RealMain(int argc, char** argv)
#else
main(argc, argv)
     int argc;
     Char *argv[];
#endif

{
  long i,n,stripedepth;
  char filename1[100];
#if defined(MAC) || defined(__MWERKS__)
  OSErr retcode;
  FInfo  fndrinfo;
#ifdef MAC
  macsetup("Drawtree","Preview");
#endif
#endif
#ifdef TURBOC
  if ((registerbgidriver(EGAVGA_driver) <0) ||
      (registerbgidriver(Herc_driver) <0)   ||
      (registerbgidriver(CGA_driver) <0)){
    fprintf(stderr,"Graphics error: %s ",grapherrormsg(graphresult()));
    exit(-1);}
#endif
  strcpy(fontname,"Hershey");

  openfile(&plotfile,PLOTFILE,"w",argv[0],pltfilename);
  openfile(&treefile,TREEFILE,"r",argv[0],NULL);

  printf("DRAWTREE from PHYLIP version %s\n",VERSION);
  printf("Reading tree ... \n");
  treeread();
  printf("Tree has been read.\n");
  printf("Loading the font ... \n");
  loadfont(font,argv[0]);
  printf("Font loaded.\n");
  previewing = false;
  initialparms();

  canbeplotted = false;
  while (!canbeplotted) {
    do {
      n=showparms();
      if ( n != -1)
	getparms(n);
    } while (n != -1);
    calculate();
    rescale();
    canbeplotted = true;
    if (preview)
      canbeplotted=plotpreview(fontname,&xoffset,&yoffset,&scale,ntips,root);
  }
  if (dotmatrix) {
     stripedepth = allocstripe(stripe,(strpwide/8),
			    ((long)(yunitspercm * ysize)));
     strpdeep = stripedepth;
     strpdiv  = stripedepth;
     }
  previewing = false;
  initplotter(ntips,fontname);
  numlines = dotmatrix ? ((long)floor(yunitspercm * ysize + 0.5)/strpdeep):1;   if (plotter != ibmpc)
    printf("Writing plot file ...\n");
  drawit(fontname,&xoffset,&yoffset,numlines,root);
  finishplotter();
  printf("Finished.\n");
  FClose(treefile);
  FClose(plotfile);
  printf("End of run.\n");

#ifdef MAC
  if (plotter == pict){
    strcpy(filename1,pltfilename);
    retcode=GetFInfo(CtoPstr(filename1),0,&fndrinfo);
    fndrinfo.fdType='PICT';
    fndrinfo.fdCreator='MDRW';
    strcpy(filename1,pltfilename);
    retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);}
  if (plotter == lw){
    retcode=GetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);
    fndrinfo.fdType='TEXT';
    retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);}
#endif
#if defined(__MWERKS__)
if (plotter == pict){
  strcpy(filename1,pltfilename);
  retcode= getfinfo( pltfilename,0,&fndrinfo);
  fndrinfo.fdType='PICT';
  fndrinfo.fdCreator='MDRW';
  retcode=setfinfo( pltfilename,0,&fndrinfo);
  }
if (plotter == lw){
  retcode=getfinfo( pltfilename,0,&fndrinfo);
  fndrinfo.fdType='TEXT';
  retcode=setfinfo( pltfilename,0,&fndrinfo);
  }
#endif
  exit(0);
}

int eof(f)
FILE *f;
{
    register long ch;

    if (feof(f))
        return 1;
    if (f == stdin)
        return 0;
    ch = getc(f);
    if (ch == EOF)
        return 1;
    ungetc(ch, f);
    return 0;
}


int eoln(f)
FILE *f;
{
    register long ch;

    ch = getc(f);
    if (ch == EOF)
        return 1;
    ungetc(ch, f);
    return (ch == '\n');
}


void memerror()
{
printf("Error allocating memory\n");
exit(-1);
}

MALLOCRETURN *mymalloc(x)
long x;
{
MALLOCRETURN *mem;
mem = (MALLOCRETURN *)malloc(x);
if (!mem)
  memerror();
else
  return (MALLOCRETURN *)mem;
}
