#include "phylip.h"
#include "draw.h"

/* Version 3.696.
   Written by Joseph Felsenstein and Christopher A. Meacham.  Additional code
   written by Sean Lamont, Andrew Keefe, Hisashi Horino, Akiko Fuseki, Doug
   Buxton Michal Palczewski, and James McGill.

   Copyright (c) 1986-2014, Joseph Felsenstein
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
   POSSIBILITY OF SUCH DAMAGE.
*/

#ifdef MAC
char* about_message = 
  "Drawtree unrooted tree plotting program\r"
  "PHYLIP version 3.696.\r"
  "(c) Copyright 1986-2004 by Joseph Felsenstein.\r"  
  "Written by Joseph Felsenstein and Christopher A. Meacham.\r" 
  "Additional code written by Sean Lamont, Andrew Keefe, Hisashi Horino,\r"
  "Akiko Fuseki, Doug Buxton and Michal Palczewski.\r"
#endif

//#define JAVADEBUG

#define GAP             0.5
#define MAXITERATIONS   100
#define MINIMUMCHANGE   0.0001

/*When 2 Nodes are on top of each other, this is the max. 
  force that's allowed.*/
#ifdef INFINITY
#undef INFINITY
#endif
#define INFINITY        (double) 9999999999.0

typedef enum {fixed, radial, along, middle} labelorient;
FILE        *plotfile;
char        pltfilename[FNMLNGTH];
long        nextnode,  strpwide, strpdeep,
            strptop, strpbottom,  payge, numlines,hpresolution;
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, maxchange;
boolean     canbeplotted, dotmatrix, haslengths,
             uselengths, regular, rotate, empty, rescaled,
             notfirst, improve, nbody, firstscreens, labelavoid;
boolean     pictbold,pictitalic,pictshadow,pictoutline;
boolean javarun;

striptype stripe;
plottertype plotter, oldplotter;
growth grows;
labelorient labeldirec;
node *root, *where;
pointarray nodep;
pointarray treenode;
fonttype font;
enum {  yes, no } penchange, oldpenchange;
char ch,resopts;
char *progname;
long filesize;
long strpdiv;
double pagex,pagey,paperx,papery,hpmargin,vpmargin;
double *textlength, *firstlet;
double trweight;   /* starting here, needed to make sccs version happy */
boolean goteof;
node *grbg;
winactiontype winaction;

long maxNumOfIter;
struct stackElem
{
  /* This is actually equivalent to a reversed link list; pStackElemBack
     point toward the direction of the bottom of the stack */
  struct stackElem *pStackElemBack;
  node *pNode;
};
typedef struct stackElem stackElemType;


#ifndef OLDC
/* function prototypes */
void   initdrawtreenode(node **, node **, node *, long, long, long *,
        long *, initops, pointarray, pointarray, Char *, Char *, FILE *);
void   initialparms(void);
char   showparms(void);
void   getparms(char);
void   getwidth(node *);
void   plrtrans(node *, double, double, double);
void   coordtrav(node *, double *, double *);
double angleof(double , double );
void   polartrav(node *, double, double, double, double, double *,
        double *, double *, double *);
void   tilttrav(node *, double *, double *, double *, double *);
                
void   leftrightangle(node *, double, double);
void   improvtrav(node *);
void   force_1to1(node *, node *, double *, double *, double);
void   totalForceOnNode(node *, node *, double *, double *, double);
double dotProduct(double, double, double, double );
double capedAngle(double);
double angleBetVectors(double, double, double, double);
double signOfMoment(double, double, double, double);
double forcePerpendicularOnNode(node *, node *, double);
void   polarizeABranch(node *, double *, double *);

void   pushNodeToStack(stackElemType **, node *);
void   popNodeFromStack(stackElemType **, node **);
double medianOfDistance(node *, boolean);
void   leftRightLimits(node *, double *, double *);
void   branchLRHelper(node *, node *, double *, double *);
void   branchLeftRightAngles(node *, double *,  double *);
void   improveNodeAngle(node *, double);
void   improvtravn(node *);
void   coordimprov(double *, double *);
void   calculate(void);
void   rescale(void);
void   user_loop(void);
void setup_environment(int argc, Char *argv[]);
void polarize(node *p, double *xx, double *yy);
double vCounterClkwiseU(double Xu, double Yu, double Xv, double Yv);
void drawtree(char* intreename, char* plotfilename, char* plotfileopt, char* fontfilename,
              char* treegrows, int usebranchlengths, char* labeldirecstr, double labelangle,
              double treerotation, double treearc, char* iterationkind, int iterationcount,
              int regularizeangles, int avoidlabeloverlap, int branchrescale,
              double branchscaler, double relcharhgt, double xmarginratio, 
              double ymarginratio, int dofinalplot, char* finalplotkind);
/* function prototypes */
#endif


void initdrawtreenode(node **p, node **grbg, node *q, long len,
                long nodei, long *ntips, long *parens, initops whichinit,
                pointarray treenode, pointarray nodep, Char *str, Char *ch,
                FILE *intree)
{
  /* initializes a node */
  long i;
  boolean minusread;
  double valyew, divisor;

  switch (whichinit) {
  case bottom:
    gnu(grbg, p);
    (*p)->index = nodei;
    (*p)->tip = false;
    for (i=0;i<MAXNCH;i++)
      (*p)->nayme[i] = '\0';
    nodep[(*p)->index - 1] = (*p);
    break;
  case nonbottom:
    gnu(grbg, p);
    (*p)->index = nodei;
    break;
  case tip:
    (*ntips)++;
    gnu(grbg, p);
    nodep[(*ntips) - 1] = *p;
    setupnode(*p, *ntips);
    (*p)->tip        = true;
    (*p)->naymlength = len ;
    strncpy ((*p)->nayme, str, MAXNCH);
    break;
  case length:
    processlength(&valyew, &divisor, ch,
      &minusread, intree, parens);
    if (!minusread)
      (*p)->oldlen = valyew / divisor;
    else
      (*p)->oldlen = fabs(valyew/divisor);
    if ((*p)->oldlen < epsilon)
      (*p)->oldlen = epsilon;
    if ((*p)->back != NULL)
      (*p)->back->oldlen = (*p)->oldlen;
    break;
  case hsnolength:
    haslengths = false;
    break;
  default:        /* cases hslength,iter,treewt,unitrwt        */
    break;        /* should not occur                        */
  }
} /* initdrawtreenode */


void initialparms()
{
  /* initialize parameters */
  paperx = 20.6375;
  pagex  = 20.6375;
  papery = 26.9875;
  pagey  = 26.9875;
  strcpy(fontname,"Times-Roman");
  plotrparms(spp);
  grows = vertical;
  treeangle = pi / 2.0;
  ark = 2 * pi;
  improve = true;
  nbody = false;
  regular = false;
  rescaled = true;
  bscale = 1.0;
  labeldirec = middle;
  xmargin = 0.08 * xsize;
  ymargin = 0.08 * ysize;
  labelrotation = 0.0;
  charht = 0.3333;
  plotter = DEFPLOTTER;
  hpmargin = 0.02*pagex;
  vpmargin = 0.02*pagey;
  labelavoid = false;
  uselengths = haslengths;
}  /* initialparms */


char showparms()
{
  long loopcount;
  char numtochange;
  Char ch,input[64];
  double treea;
  char    options[32];
  
  strcpy(options,"#YN0OPVBLRIDSMC");
  if (strcmp(fontname,"Hershey") !=0 && 
       (((plotter == pict || plotter == mac)  &&
       (((grows == vertical && labelrotation == 0.0) ||
            (grows == horizontal && labelrotation == 90.0))))))
       strcat(options,"Q");
  if  (plotter == lw || plotter == idraw || plotter == pict || plotter == mac)
           strcat(options,"F");
  if (!improve)
      strcat(options,"GA");
  if (!firstscreens)
    clearit();
  printf("\nUnrooted tree plotting program version %s\n", VERSION);
  putchar('\n');
  printf("Here are the settings: \n\n");
  printf(" 0  Screen type (IBM PC, ANSI)?  %s\n",
           ibmpc ? "IBM PC" : ansi  ? "ANSI"  : "(none)");
  printf(" P       Final plotting device: ");
  switch (plotter) {
    case lw:
      printf(" Postscript printer\n");
      break;
    case pcl:
      printf(" HP Laserjet compatible printer (%d DPI)\n", (int) hpresolution);
      break;
    case epson:
      printf(" Epson dot-matrix printer\n");
      break;
    case pcx:
      printf(" PCX file for PC Paintbrush drawing program (%s)\n",
             (resopts == 1) ? "EGA 640x350" : 
             (resopts == 2) ? "VGA 800x600" : "VGA 1024x768");
      break;
    case pict:
      printf(" Macintosh PICT file for drawing program\n");
      break;
    case idraw:
      printf(" Idraw drawing program\n");
      break;
    case fig:
      printf(" Xfig drawing program\n");
      break;
    case hp:
      printf(" HPGL graphics language for HP plotters\n");
      break;
    case bmp:
      printf(" MS-Windows Bitmap (%d by %d resolution)\n",
             (int)xsize,(int)ysize);
      break;
    case xbm:
      printf(" X Bitmap file format (%d by %d resolution)\n",
             (int)xsize,(int)ysize);
      break;
    case ibm:
      printf(" IBM PC graphics (CGA, EGA, or VGA)\n");
      break;
    case tek:
      printf(" Tektronix graphics screen\n");
      break;
   case decregis:
      printf(" DEC ReGIS graphics (VT240 or DECTerm)\n");
      break;
    case houston:
      printf(" Houston Instruments plotter\n");
      break;
    case toshiba:
      printf(" Toshiba 24-pin dot matrix printer\n");
      break;
    case citoh:
      printf(" Imagewriter or C.Itoh/TEC/NEC 9-pin dot matrix printer\n");
      break;
    case oki:
      printf(" old Okidata 9-pin dot matrix printer\n");
      break;
    case ray:
      printf(" Rayshade ray-tracing program file format\n");
      break;
    case pov:
      printf(" POV ray-tracing program file format\n");
      break;
    case vrml:
      printf(" VRML, Virtual Reality Markup Language\n");
  case mac:
  case gif:
  case other:
    break ;
  default:        /* case not handled        */
    break;
  }

  printf(" (Preview not available)\n");

  printf(" B          Use branch lengths:  ");
  if (haslengths)
    printf("%s\n",uselengths ? "Yes" : "No");
   else
    printf("(no branch lengths available)\n");
  printf(" L             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 if (labeldirec == middle)
    printf("  branch points to Middle of label\n");
  else
    printf("  Along branches\n");
  printf(" R            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);
  if (!improve) {
    printf(" A       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(" I     Iterate to improve tree:  ");
  if (improve) {
    if (nbody)
      printf("n-Body algorithm\n");
    else
      printf("Equal-Daylight algorithm\n");
  } else
    printf("No\n");
  if (improve)
    printf(" D  Try to avoid label overlap?  %s\n",
           (labelavoid? "Yes" : "No"));
  printf(" S      Scale of branch length:");
  if (rescaled)
    printf("  Automatically rescaled\n");
  else
    printf("  Fixed:%6.2f cm per unit branch length\n", bscale);
  if (!improve) {
    printf(" G       Regularize the angles:  %s\n",
           (regular ? "Yes" : "No"));
  }
  printf(" C   Relative character height:%8.4f\n", charht);
  if ((((plotter == pict || plotter == mac)  &&
       (((grows == vertical && labelrotation == 0.0) ||
       (grows == horizontal && labelrotation == 90.0))))))
    printf(" F                        Font:  %s\n Q" 
        "        Pict Font Attributes:  %s, %s, %s, %s\n",
   fontname, (pictbold   ? "Bold"   : "Medium"),
        (pictitalic ? "Italic" : "Regular"),
        (pictshadow ? "Shadowed": "Unshadowed"),
        (pictoutline ? "Outlined" : "Unoutlined"));
    else if (plotter == lw || plotter == idraw)  
    printf(" F                        Font:  %s\n",fontname);
  if (plotter == ray) {
    printf(" M          Horizontal margins:%6.2f pixels\n", xmargin);
    printf(" M            Vertical margins:%6.2f pixels\n", ymargin);
  } else {
    printf(" M          Horizontal margins:%6.2f cm\n", xmargin);
    printf(" M            Vertical margins:%6.2f cm\n", ymargin);
  }
  printf(" #           Page size submenu:  ");
  /* Add 0.5 to clear up truncation problems. */
  if (((int) ((pagex / paperx) + 0.5) == 1) && 
      ((int) ((pagey / papery) + 0.5) == 1))
    /* If we're only using one page per tree, */
    printf ("one page per tree\n") ;   
  else
    printf ("%.0f by %.0f pages per tree\n",
             (pagey-vpmargin) / (papery-vpmargin),
             (pagex-hpmargin) / (paperx-hpmargin)) ;
  loopcount = 0;
  for (;;) {
    printf("\n Y to accept these or type the letter for one to change\n");
#ifdef WIN32
    phyFillScreenColor();
#endif
    getstryng(input);
    uppercase(&input[0]);
    ch=input[0];
    if (strchr(options,ch))
      {
        numtochange = ch;
        break; 
      }
    printf(" That letter is not one of the menu choices.  Type\n");
    countup(&loopcount, 100);
  }
  return numtochange; 
}  /* showparms */


void getparms(char numtochange)
{
  /* get from user the relevant parameters for the plotter and diagram */
  long loopcount2;
  Char ch;
  boolean ok;
  char    options[32];
  char    line[32];
  char    input[100];
  int m, n;

  n = (int)((pagex-hpmargin-0.01)/(paperx-hpmargin)+1.0);
  m = (int)((pagey-vpmargin-0.01)/(papery-vpmargin)+1.0);
  strcpy(options,"YNOPVBLRIDSMC");
  if      ((((plotter == pict || plotter == mac)  &&
          (((grows == vertical && labelrotation == 0.0) ||
            (grows == horizontal && labelrotation == 90.0))))))
         strcat(options,"Q");
  if  (plotter == lw || plotter == idraw) 
           strcat(options,"F");
  if (!improve) {
      strcat(options,"GA");
  }
  if (numtochange == '*') {
    do {
      printf(" Type the number of one that you want to change:\n");
#ifdef WIN32
      phyFillScreenColor();
#endif
      getstryng(line);
      numtochange = line[0];
      } while (strchr(options,numtochange));
  }
  switch (numtochange) {

  case '0':
    initterminal(&ibmpc, &ansi);
    break;

  case 'P':
    getplotter();
    break;

  case '#':
    loopcount2 = 0;
    for (;;){
      clearit();
      printf("  Page Specifications Submenu\n\n");
      printf(" L   Output size in pages: %.0f down by %.0f across\n",
             (pagey / papery), (pagex / paperx));
      printf(" P   Physical paper size: %1.5f by %1.5f cm\n",paperx,papery);
      printf(" O   Overlap Region: %1.5f %1.5f cm\n",hpmargin,vpmargin);
      printf(" M   main menu\n");
#ifdef WIN32
      phyFillScreenColor();
#endif
      getstryng(input);
      ch = input[0];
      uppercase(&ch);
      switch (ch){
      case 'L':
        printf("Number of pages in height:\n");
#ifdef WIN32
        phyFillScreenColor();
#endif
        getstryng(input);
        m = atoi(input);
        printf("Number of pages in width:\n");
#ifdef WIN32
        phyFillScreenColor();
#endif
        getstryng(input);
        n = atoi(input);
        break;
      case 'P':
        printf("Paper Width (in cm):\n");
#ifdef WIN32
        phyFillScreenColor();
#endif
        getstryng(input);
        paperx = atof(input);
        printf("Paper Height (in cm):\n");
#ifdef WIN32
        phyFillScreenColor();
#endif
        getstryng(input);
        papery = atof(input);    
        break;
      case 'O':
        printf("Horizontal Overlap (in cm):");
#ifdef WIN32
        phyFillScreenColor();
#endif
        getstryng(input);
        hpmargin = atof(input);    
        printf("Vertical Overlap (in cm):");
#ifdef WIN32
        phyFillScreenColor();
#endif
        getstryng(input);
        vpmargin = atof(input);    
      case 'M':
        break;
      default:
        printf("Please enter L, P, O , or M.\n");
        break;
      }
      pagex = ((double)n * (paperx-hpmargin)+hpmargin);
      pagey = ((double)m * (papery-vpmargin)+vpmargin);
      if (ch == 'M')
        break;
      countup(&loopcount2, 20);
    }
    break;

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

  case 'L':
    printf("\nDo you want labels to be Fixed angle, Radial, Along,");
    printf(" or Middle?\n");
    loopcount2 = 0;
    do {
      printf(" Type F, R, A, or M\n");
#ifdef WIN32
      phyFillScreenColor();
#endif
      fflush(stdout);
      scanf("%c%*[^\n]", &ch);
      (void)getchar();
      if (ch == '\n')
        ch = ' ';
      uppercase(&ch);
      countup(&loopcount2, 10);
    } while (ch != 'F' && ch != 'R' && ch != 'A' && ch != 'M');
    switch (ch) {

    case 'A':
      labeldirec = along;
      break;

    case 'F':
      labeldirec = fixed;
      break;

    case 'R':
      labeldirec = radial;
      break;

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

  case 'R':
    printf("\n At what angle is the tree to be plotted?\n");
    loopcount2 = 0;
    do {
      printf(" Choose an angle in degrees from 360 to -360: \n");
#ifdef WIN32
      phyFillScreenColor();
#endif
      fflush(stdout);
      scanf("%lf%*[^\n]", &treeangle);
      (void)getchar();
      uppercase(&ch);
      countup(&loopcount2, 10);
    } while (treeangle < -360.0 && treeangle > 360.0);
    treeangle = treeangle * pi / 180;
    break;

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

  case 'I':
    if (nbody) {
      improve = false;
      nbody = false;
    } else {
      if (improve)
        nbody = true;
      else improve = true;
    }
    break;

  case 'D':
    labelavoid = !labelavoid;
    break;

  case 'S':
    rescaled = !rescaled;
    if (!rescaled) {
      printf("Centimeters per unit branch length?\n");
#ifdef WIN32
      phyFillScreenColor();
#endif
      fflush(stdout);
      scanf("%lf%*[^\n]", &bscale);
      (void)getchar();
    }
    break;

  case 'M':
    clearit();
    printf("\nThe tree will be drawn to fit in a rectangle which has \n");
    printf(" margins in the horizontal and vertical directions of:\n");
    if (plotter == ray) {
      printf(
       "%6.2f pixels (horizontal margin) and%6.2f pixels (vertical margin)\n",
               xmargin, ymargin);
      }
    else {
        printf("%6.2f cm (horizontal margin) and%6.2f cm (vertical margin)\n",
               xmargin, ymargin);
      }
    loopcount2 = 0;
    do {
      printf(" New value (in cm) of horizontal margin?\n");
#ifdef WIN32
      phyFillScreenColor();
#endif
      fflush(stdout);
      scanf("%lf%*[^\n]", &xmargin);
      (void)getchar();
      ok = ((unsigned)xmargin < xsize / 2.0);
      if (!ok)
        printf(" Impossible value.  Please retype it.\n");
      countup(&loopcount2, 10);
    } while (!ok);
    loopcount2 = 0;
    do {
      printf(" New value (in cm) of vertical margin?\n");
#ifdef WIN32
      phyFillScreenColor();
#endif
      fflush(stdout);
      scanf("%lf%*[^\n]", &ymargin);
      (void)getchar();
      ok = ((unsigned)ymargin < ysize / 2.0);
      if (!ok)
        printf(" Impossible value.  Please retype it.\n");
      countup(&loopcount2, 10);
    } while (!ok);
    break;

  case 'C':
    printf("New value of character height?\n");
#ifdef WIN32
    phyFillScreenColor();
#endif
    fflush(stdout);
    scanf("%lf%*[^\n]", &charht);
    (void)getchar();
    break;

  case 'F':
      printf("Enter font name or \"Hershey\" for default font\n");
#ifdef WIN32
      phyFillScreenColor();
#endif
      getstryng(fontname);
      break;

  case 'G':
      regular = !regular;
      break;

 case 'Q':
    clearit();
    loopcount2 = 0;
    do {
      printf("Italic? (Y/N)\n");  
#ifdef WIN32
      phyFillScreenColor();
#endif
      getstryng(input);
      input[0] = toupper(input[0]);
      countup(&loopcount2, 10);
    } while (input[0] != 'Y' && input[0] != 'N');
    pictitalic = (input[0] == 'Y');
    loopcount2 = 0;
    do {
      printf("Bold? (Y/N)\n");  
#ifdef WIN32
      phyFillScreenColor();
#endif
      getstryng(input);
      input[0] = toupper(input[0]);
      countup(&loopcount2, 10);
    } while (input[0] != 'Y' && input[0] != 'N');
    pictbold = (input[0] == 'Y');
    loopcount2 = 0;
    do {
      printf("Shadow? (Y/N)\n");  
#ifdef WIN32
      phyFillScreenColor();
#endif
      getstryng(input);
      input[0] = toupper(input[0]);
      countup(&loopcount2, 10);
    } while (input[0] != 'Y' && input[0] != 'N');
    pictshadow = (input[0] == 'Y');
    loopcount2 = 0;
    do {
      printf("Outline? (Y/N)\n");  
#ifdef WIN32
      phyFillScreenColor();
#endif
      getstryng(input);
      input[0] = toupper(input[0]);
      countup(&loopcount2, 10);
    } while (input[0] != 'Y' && input[0] != 'N');
    pictoutline = (input[0] == 'Y');
    break;
  }
}  /* getparms */


void getwidth(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 (((p != root) && (pp != qq)) || ((p == root) && (pp != p->next)));
  }
  p->depth = nd + p->length;
  p->width = nw;
}  /* getwidth */


void plrtrans(node *p, double theta, double lower, double 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;
  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 = fabs(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 (((p != root) && (pp != qq)) || ((p == root) && (pp != p->next)));
}  /* plrtrans */


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

  if (!p->tip) {
    pp = p->next;
    while (pp != p) {
      coordtrav(pp->back, xx, yy);
      pp = pp->next;
      if (p == root)
        coordtrav(p->back, xx, yy);
    }
  }
  (*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(double x, double 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;
  while (theta > 2 * pi)
    theta -= 2 * pi;
  while (theta < 0.0)
    theta += 2 * pi;
  return theta;
}  /* angleof */


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

  lookatit = true;
  if (!p->tip)
    lookatit = (p->next->next != p || p->index != root->index);
  if (lookatit) {
    x = nodep[p->index - 1]->xcoord;
    y = nodep[p->index - 1]->ycoord;
    if (p->tip) {
      if (labeldirec == fixed) {
        labangle = pi * labelrotation / 180.0;
        if (cos(p->oldtheta) < 0.0)
          labangle = labangle - pi;
      }
      if (labeldirec == radial)
        labangle = p->theta;
      else if (labeldirec == along)
        labangle = p->oldtheta;
      else if (labeldirec == middle)
        labangle = 0.0;
      xxx = x;
      yyy = y;
      if (labelavoid) {
        if  (labeldirec == middle) {
          xxx += GAP * labelheight * cos(p->oldtheta);
          yyy += GAP * labelheight * sin(p->oldtheta);
          xxx += labelheight * cos(labangle) * textlength[p->index - 1];
          if (textlength[p->index - 1] * sin(p->oldtheta) < 1.0)
            xxx += labelheight * cos(labangle) * textlength[p->index - 1];
          else
            xxx += 0.5 * labelheight * cos(labangle)
                     * textlength[p->index - 1];
          yyy += labelheight * sin(labangle) * textlength[p->index - 1];
        }
        else {
          xxx += GAP * labelheight * cos(p->oldtheta);
          yyy += GAP * labelheight * sin(p->oldtheta);
          xxx -= labelheight * cos(labangle) * 0.5 * firstlet[p->index - 1];
          yyy -= labelheight * sin(labangle) * 0.5 * firstlet[p->index - 1];
          xxx += labelheight * cos(labangle) * textlength[p->index - 1];
          yyy += labelheight * sin(labangle) * textlength[p->index - 1];
        }
      }
      if ((yyy - yy) * firstx - (xxx - xx) * firsty < 0.0) {
        if ((yyy - yy) * (*rightx) - (xxx - xx) * (*righty) < 0.0) {
          (*rightx) = xxx - xx;
          (*righty) = yyy - yy;
        }
      }
      if ((yyy - yy) * firstx - (xxx - xx) * firsty > 0.0) {
        if ((yyy - yy) * (*leftx) - (xxx - xx) * (*lefty) > 0.0) {
          (*leftx) = xxx - xx;
          (*lefty) = yyy - yy;
        }
      }
    }
    if ((y - yy) * firstx - (x - xx) * firsty < 0.0) {
      if ((y - yy) * (*rightx) - (x - xx) * (*righty) < 0.0) {
        (*rightx) = x - xx;
        (*righty) = y - yy;
      }
    }
    if ((y - yy) * firstx - (x - xx) * firsty > 0.0) {
      if ((y - yy) * (*leftx) - (x - xx) * (*lefty) > 0.0) {
        (*leftx) = x - xx;
        (*lefty) = y - yy;
      }
    }
  }
  if (p->tip)
    return;
  pp = p->next;
  while (pp != p) {
    if (pp != NULL)
      polartrav(pp->back,xx,yy,firstx,firsty,leftx,lefty,rightx,righty);
    pp = pp->next;
  }
}  /* polartrav */


void tilttrav(node *q, double *xx, double *yy, double *sinphi,
                double *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) + ((*yy) - y) * (*sinphi);
  pp->ycoord = (*yy) + (x - (*xx)) * (*sinphi) + (y - (*yy)) * (*cosphi);
  if (q->tip)
    return;
  pp = q->next;
  while (pp != q) {
    /*
    if (pp != root)
    */
    if (pp->back != NULL)
      tilttrav(pp->back,xx,yy,sinphi,cosphi);
    pp = pp->next;
  }
}  /* tilttrav */


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

  if (fabs(p->xcoord - (*xx)) > epsilon)
    p->oldtheta = atan((p->ycoord - (*yy)) / (p->xcoord - (*xx)));
  else if (p->ycoord - (*yy) > epsilon)
      p->oldtheta = pi / 2;
  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 leftrightangle(node *p, double xx, double yy)
{
  /* get leftmost and rightmost angle of subtree, put them in node p */
  double firstx, firsty, leftx, lefty, rightx, righty;
  double langle, rangle;

  firstx = nodep[p->back->index-1]->xcoord - xx;
  firsty = nodep[p->back->index-1]->ycoord - yy;
  leftx = firstx;
  lefty = firsty;
  rightx = firstx;
  righty = firsty;
  if (p->back != NULL)
    polartrav(p->back,xx,yy,firstx,firsty,&leftx,&lefty,&rightx,&righty);
  if ((fabs(leftx) < epsilon) && (fabs(lefty) < epsilon))
    langle = p->back->oldtheta;
  else
    langle = angleof(leftx, lefty);
  if ((fabs(rightx) < epsilon) && (fabs(righty) < epsilon))
    rangle = p->back->oldtheta;
  else
    rangle = angleof(rightx, righty);
  while (langle - rangle > 2*pi)
    langle -= 2 * pi;
  while (rangle > langle) {
    if (rangle > 2*pi)
      rangle -= 2 * pi;
    else
      langle += 2 * pi;
  }
  while (langle > 2*pi) {
    rangle -= 2 * pi;
    langle -= 2 * pi;
  }
  p->lefttheta = langle;
  p->righttheta = rangle;
} /* leftrightangle */


void improvtrav(node *p)
{
  /* traverse tree trying different tiltings at each node */
  double xx, yy, cosphi, sinphi;
  double langle, rangle, sumrot, olddiff;
  node *pp, *qq, *ppp;;

  if (p->tip)
    return;
  xx = p->xcoord;
  yy = p->ycoord;
  pp = p->next;
  do {
    leftrightangle(pp, xx, yy);
    pp = pp->next;
  } while ((pp != p->next));
  if (p == root) {
    pp = p->next;
    do {
      qq = pp;
      pp = pp->next;
    } while (pp != root);
    p->righttheta = qq->righttheta;
    p->lefttheta = p->next->lefttheta;
  }
  qq = p;
  pp = p->next;
  ppp = p->next->next;
  do {
    langle = qq->righttheta - pp->lefttheta;
    rangle = pp->righttheta - ppp->lefttheta; 
    while (langle > pi)
      langle -= 2*pi;
    while (langle < -pi)
      langle += 2*pi;
    while (rangle > pi)
      rangle -= 2*pi;
    while (rangle < -pi)
      rangle += 2*pi;
    olddiff = fabs(langle-rangle);
    sumrot = (langle - rangle) /2.0;
    if (sumrot > langle)
      sumrot = langle;
    if (sumrot < -rangle)
      sumrot = -rangle;
    cosphi = cos(sumrot);
    sinphi = sin(sumrot);
    if (p != root) {
      if (fabs(sumrot) > maxchange)
        maxchange = fabs(sumrot);
      pp->back->oldtheta += sumrot;
      tilttrav(pp->back,&xx,&yy,&sinphi,&cosphi);
      polarize(pp->back,&xx,&yy);
      leftrightangle(pp, xx, yy);
      langle = qq->righttheta - pp->lefttheta;
      rangle = pp->righttheta - ppp->lefttheta; 
      while (langle > pi)
        langle -= 2*pi;
      while (langle < -pi)
        langle += 2*pi;
      while (rangle > pi)
        rangle -= 2*pi;
      while (rangle < -pi)
        rangle += 2*pi;
      while ((fabs(langle-rangle) > olddiff) && (fabs(sumrot) > 0.01)) {
        sumrot = sumrot /2.0;
        cosphi = cos(-sumrot);
        sinphi = sin(-sumrot);
        pp->back->oldtheta -= sumrot;
        tilttrav(pp->back,&xx,&yy,&sinphi,&cosphi);
        polarize(pp->back,&xx,&yy);
        leftrightangle(pp, xx, yy);
        langle = qq->righttheta - pp->lefttheta;
        rangle = pp->righttheta - ppp->lefttheta; 
        if (langle > pi)
          langle -= 2*pi;
        if (langle < -pi)
          langle += 2*pi;
        if (rangle > pi)
          rangle -= 2*pi;
        if (rangle < -pi)
          rangle += 2*pi;
      }
    }
    qq = pp;
    pp = pp->next;
    ppp = ppp->next;
  } while (((p == root) && (pp != p->next)) || ((p != root) && (pp != p)));
  pp = p->next;
  do {
    improvtrav(pp->back);
    pp = pp->next;
  }
  while (((p == root) && (pp != p->next)) || ((p != root) && (pp != p)));
}  /* improvtrav */


void force_1to1(node *pFromSubNode, node *pToSubNode, double *pForce,
                double *pAngle, double medianDistance)
{
/* calculate force acting between 2 nodes and return the force in pForce. 
   Remember to pass the index subnodes to this function if needed. 
   Force should always be positive for repelling.  Angle changes to 
   indicate the direction of the force.  The value of INFINITY is the cap
   to the value of Force.  
   There might have problem (error msg.) if pFromSubNode and pToSubNode 
   are the same node or the coordinates are identical even with double 
   precision.  */
  double distanceX, distanceY, distance, norminalDistance;
  distanceX = pFromSubNode->xcoord - pToSubNode->xcoord;
  distanceY = pFromSubNode->ycoord - pToSubNode->ycoord;
  distance = sqrt( distanceX*distanceX + distanceY*distanceY );
  norminalDistance = distance/medianDistance;

  if (norminalDistance < epsilon)
  {
    *pForce = INFINITY;
  }
  else
  {

    *pForce = (double)1 / (norminalDistance * norminalDistance);

    if (*pForce > INFINITY) *pForce = INFINITY;
  }
  
  *pAngle = computeAngle(pFromSubNode->xcoord, pFromSubNode->ycoord,
                        pToSubNode->xcoord, pToSubNode->ycoord);

  return;
}  /* force_1to1 */


void totalForceOnNode(node *pPivotSubNode, node *pToSubNode,
                double *pTotalForce, double *pAngle, double medianDistance)
{
/* pToSubNode is where all the relevent nodes apply forces to.
   All branches are visited except the branch contains pToSubNode.
   pToSubNode must be one of the branch out of the current Node (= out of one
   of the subnode in the current subnodes set.)
   Most likely pPivotSubNode is not the index subNode!  In any case, only
   the leafs are consider in repelling force; so, no worry about index subNode.
   pTotalForce and pAngle must be set to 0 before calling this function for the
   first time, or the result will be invalid.  pPivotSubNode is named for 
   external interface.  When calling totalForceOnNode() recursively, 
   pPivotSubNode should be thought of as pFromSubNode.
 */
  node *pSubNode;
  double force, angle, forceX, forceY, prevForceX, prevForceY;

  pSubNode = pPivotSubNode;

  /* visit the rest of the branches of current node; the branch attaches to 
     the current subNode may be visited in the code down below. */
  while (pSubNode->next != NULL && pSubNode->next != pPivotSubNode)
  {
    pSubNode = pSubNode->next;
    if ( pSubNode->back != NULL && pSubNode->back != pToSubNode) 
      totalForceOnNode(pSubNode->back, pToSubNode, pTotalForce, pAngle, 
          medianDistance);
  }

  /* visit this branch; You need to visit it for the first time - at root only!
   *
   * Modified so that all nodes are visited and calculated forces, instead of 
   * just the leafs only. 
   * use pPivotSubNode instead of pSubNode here because pSubNode stop short
   *  just before pPivotSubNode (the entry node) */
  if ( pPivotSubNode == root && pPivotSubNode->back != NULL 
       && pPivotSubNode->back != pToSubNode) 
    totalForceOnNode(pPivotSubNode->back, pToSubNode, pTotalForce, pAngle, 
        medianDistance);

  /* Break down the previous sum of forces to components form */
  prevForceX = *pTotalForce * cos(*pAngle);
  prevForceY = *pTotalForce * sin(*pAngle);
  
  force_1to1(nodep[pPivotSubNode->index-1], pToSubNode, &force, &angle, 
      medianDistance);
  /* force between 2 nodes */
  forceX = force * cos(angle);
  forceY = force * sin(angle);

  /* Combined force */
  forceX = forceX + prevForceX;
  forceY = forceY + prevForceY;

  /* Write to output parameters */
  *pTotalForce = sqrt( forceX*forceX + forceY*forceY );
  
  *pAngle = computeAngle((double)0, (double)0, forceX, forceY);

  return;
}  /* totalForceOnNode */


double dotProduct(double Xu, double Yu, double Xv, double Yv)
{
  return Xu * Xv + Yu * Yv;
}  /* dotProduct */


double capedAngle(double angle)
{
/* Return the equivalent value of angle that is within
   0 to 2*pi */
  while (angle < 0 || angle >= 2*pi)
  {
    if(angle < 0)
    {
      angle = angle + 2*pi;
    }
    else if (angle >= 2*pi)
    {
      angle = angle - 2*pi;
    }
  }
  return angle;
}  /* capedAngle */


double angleBetVectors(double Xu, double Yu, double Xv, double Yv)
{
/* Calculate angle between 2 vectors; value returned is always between
   0 and pi.  
   Use vCounterClkwiseU() to get the relative position of the vectors.  */ 
  double dotProd, cosTheta, theta, lengthsProd;

  dotProd = dotProduct(Xu, Yu, Xv, Yv);
  lengthsProd = sqrt(Xu*Xu+Yu*Yu) * sqrt(Xv*Xv+Yv*Yv);

  if (lengthsProd < epsilon)
  {
    printf("ERROR: drawtree - division by zero in angleBetVectors()!\n");
    printf("Xu %f Yu %f Xv %f Yv %f\n", Xu, Yu, Xv, Yv);
    exxit(0);
  }
  cosTheta = dotProd / lengthsProd;

  if (cosTheta > 1) /* cosTheta will only be > 1 or < -1 due to rounding errors */
    theta = 0; /* cosTheta = 1 */
  else if (cosTheta < -1)
    theta = pi; /* cosTheta = -1 */
  else 
    theta = acos(cosTheta);

  return theta;
}  /* angleBetVectors */


double signOfMoment(double xReferenceVector, double yReferenceVector,
                double xForce, double yForce)
{
/* it return the sign of the moment caused by the force, applied
   to the tip of the refereceVector; the root of the refereceVector
   is the pivot. */
  double angleReference, angleForce, sign;

  angleReference = computeAngle((double)0, (double)0, xReferenceVector, 
                                yReferenceVector);
  angleForce = computeAngle((double)0, (double)0, xForce, yForce);
  angleForce = capedAngle(angleForce);
  angleReference = capedAngle(angleReference);

  /* reduce angleReference to 0 */
  angleForce = angleForce - angleReference;
  angleForce = capedAngle(angleForce);

  if (angleForce > 0 && angleForce < pi)
  {
    /* positive sign - force pointing toward the left of the reference 
       line/vector.  */
    sign = 1;
  }
  else
  {
    /* negative sign */
    sign = -1;
  }
  return sign;
}  /* signOfMoment */


double vCounterClkwiseU(double Xu, double Yu, double Xv, double Yv)
{
/* Return 1 if vector v is counter clockwise from u */
  /* signOfMoment() is doing just that! */
  return signOfMoment(Xu, Yu, Xv, Yv);
}  /* vCounterClkwiseU */


double forcePerpendicularOnNode(node *pPivotSubNode, node *pToSubNode,
                double medianDistance)
{
/* Read comment for totalForceOnNode */
/* It supposed to return a positive value to indicate that it has a positive 
   moment; and negative return value to indicate negative moment. 
   force perpendicular at norminal distance 1 is taken to be 1.  
   medianDistance is the median of Distances in this graph.  */
/*
                        / Force
                       /  
          |  ToNode   o  > alpha
          |              \  
   yDelta |               \     theta = pi/2 + alpha
          |                  beta = vector (or angle) from Pivot to ToNode
  Pivot   o-----------
             xDelta

  alpha = theta + beta
 */
  double totalForce, forceAngle, xDelta, yDelta;
  double alpha, theta, forcePerpendicular, sinForceAngle, cosForceAngle;

  totalForce = (double)0;
  forceAngle = (double)0;

  totalForceOnNode(pPivotSubNode, pToSubNode, &totalForce, &forceAngle, 
      medianDistance);

  xDelta = nodep[pToSubNode->index-1]->xcoord - 
    nodep[pPivotSubNode->index-1]->xcoord;
  yDelta = nodep[pToSubNode->index-1]->ycoord - 
    nodep[pPivotSubNode->index-1]->ycoord;

  /* Try to avoid the case where 2 nodes are on top of each other. */
  /*
  if (xDelta < 0) tempx = -xDelta;
  else tempx = xDelta;
  if (yDelta < 0) tempy = -yDelta;
  else tempy = yDelta;
  if (tempx < epsilon && tempy < epsilon)
  {
    return;
  }
  */

  sinForceAngle = sin(forceAngle);
  cosForceAngle = cos(forceAngle);
  theta = angleBetVectors(xDelta, yDelta, cosForceAngle, sinForceAngle);

  if (theta > pi/2)
  {
    alpha = theta - pi/2;
  }
  else
  {
    alpha = pi/2 - theta;
  }

  forcePerpendicular = totalForce * cos(alpha);

  if (forcePerpendicular < -epsilon)
  {
    printf("ERROR: drawtree - forcePerpendicular applied at an angle should" 
        " not be less than zero (in forcePerpendicularOnNode()). \n");
    printf("alpha = %f\n", alpha);
    exxit(1);
  }
  /* correct the sign of the moment */
  forcePerpendicular = signOfMoment(xDelta, yDelta, cosForceAngle, 
      sinForceAngle) 
    * forcePerpendicular;
  return forcePerpendicular;
}  /* forcePerpendicularOnNode */


void polarizeABranch(node *pStartingSubNode, double *xx, double *yy)
{
/* added - danieyek 990128 */
/* After calling tilttrav(), if you don't polarize all the nodes on the branch
   to convert the x-y coordinates to theta and radius, you won't get result on 
   the plot!  This function takes a subnode and branch out of all other subnode
   except the starting subnode (where the parent is), thus converting the x-y 
   to polar coordinates for the branch only.  xx and yy are purely "inherited"
   features of polarize().  They should have been passed as values not 
   addresses. */
  node *pSubNode;

  pSubNode = pStartingSubNode;

  /* convert the current node (note: not subnode) to polar coordinates. */
  polarize( nodep[pStartingSubNode->index - 1], xx, yy);

  /* visit the rest of the branches of current node */
  while (pSubNode->next != NULL && pSubNode->next != pStartingSubNode)
  {
    pSubNode = pSubNode->next;
    if ( pSubNode->tip != true )
      polarizeABranch(pSubNode->back, xx, yy);
  }
  return;
}  /* polarizeABranch */


void pushNodeToStack(stackElemType **ppStackTop, node *pNode)
{
/* added - danieyek 990204 */
/* pStackTop must be the current top element of the stack, where we add another
   element on top of it.  
   ppStackTop must be the location where we can find pStackTop.
   This function "returns" the revised top (element) of the stack through 
   the output parameter, ppStackTop. 
   The last element on the stack has the "back" (pStackElemBack) pointer
   set to NULL.  So, when the last element is poped, ppStackTop will be
   automatically set to NULL.  If popNodeFromStack() is called with 
   ppStackTop = NULL, we assume that it is the error caused by over popping
   the stack.
*/
  stackElemType *pStackElem;

  if (ppStackTop == NULL)
  {
    /* NULL can be stored in the location, but the location itself can't 
       be NULL! */
    printf("ERROR: drawtree - error using pushNodeToStack(); " 
        "ppStackTop is NULL.\n");
    exxit(1);
  }
  pStackElem = (stackElemType*)Malloc( sizeof(stackElemType) );
  pStackElem->pStackElemBack = *ppStackTop;
  /* push an element onto the stack */
  pStackElem->pNode = pNode;
  *ppStackTop = pStackElem;
  return;
}  /* pushNodeToStack */


void popNodeFromStack(stackElemType **ppStackTop, node **ppNode)
{
/* added - danieyek 990205 */
/* pStackTop must be the current top element of the stack, where we pop an
   element from the top of it.  
   ppStackTop must be the location where we can find pStackTop.
   This function "returns" the revised top (element) of the stack through 
   the output parameter, ppStackTop. 
   The last element on the stack has the "back" (pStackElemBack) pointer
   set to NULL.  So, when the last element is poped, ppStackTop will be
   automatically set to NULL.  If popNodeFromStack() is called with 
   ppStackTop = NULL, we assume that it is the error caused by over popping
   the stack.
*/
  stackElemType *pStackT;

  if (ppStackTop == NULL)
  {
    printf("ERROR: drawtree - a call to pop while the stack is empty.\n");
    exxit(1);
  }

  pStackT = *ppStackTop;
  *ppStackTop = pStackT->pStackElemBack;
  *ppNode  = pStackT->pNode;
  free(pStackT);

  return;
}  /* popNodeFromStack */


double medianOfDistance(node *pRootSubNode, boolean firstRecursiveCallP)
{
/* added - danieyek 990208 */
/* Find the median of the distance; used to compute the angle to rotate
   in proportion to the size of the graph and forces.
   It is assumed that pRootSubNode is also the pivot (during the first 
   call to this function) - the center, with
   respect to which node the distances are calculated.
   If there are only 3 element, element #2 is returned, ie. (2+1)/2.
   This function now finds the median of distances of all nodes, not only
   the leafs! 
*/
  node *pSubNode;
  double xDelta, yDelta, distance;
  long i, j;
  struct dblLinkNode
  {
    double value;
    /* Implement reverse Linked List */
    struct dblLinkNode *pBack;
  } *pLink, *pBackElem, *pMidElem, *pFrontElem, junkLink;
  /* must use static to retain values over calls */
  static node *pReferenceNode;
  static long count;
  static struct dblLinkNode *pFrontOfLinkedList;

  /* Remember the reference node so that it doesn't have to be passed 
     arround in the function parameter. */
  if (firstRecursiveCallP == true)
  {
    pReferenceNode = pRootSubNode;
    pFrontOfLinkedList = NULL;
    count = 0;
  }

  pSubNode = pRootSubNode;
  /* visit the rest of the branches of current node; the branch attaches to 
     the current subNode may be visited in the code further down below. */
  while (pSubNode->next != NULL && pSubNode->next != pRootSubNode)
  {
    pSubNode = pSubNode->next;
    if ( pSubNode->back != NULL) 
      medianOfDistance(pSubNode->back, false);
  }

  /* visit this branch; You need to visit it for the first time - at root 
     only! use pRootSubNode instead of pSubNode here because pSubNode stop 
     short just before pRootSubNode (the entry node) */
  if ( firstRecursiveCallP == true && pRootSubNode->back != NULL)
    medianOfDistance(pRootSubNode->back, false);

  /* Why only leafs count?  Modifying it!  */
  xDelta = nodep[pSubNode->index-1]->xcoord - 
    nodep[pReferenceNode->index-1]->xcoord;
  yDelta = nodep[pSubNode->index-1]->ycoord - 
    nodep[pReferenceNode->index-1]->ycoord;
  distance = sqrt( xDelta*xDelta + yDelta*yDelta );
  
  /* Similar to pushing onto the stack */
  pLink = (struct dblLinkNode*) Malloc( sizeof(struct dblLinkNode) );
  if (pLink == NULL)
  {
    printf("Fatal ERROR: drawtree - Insufficient Memory in" 
        " medianOfDistance()!\n");
    exxit(1);
  }
  pLink->value = distance;
  pLink->pBack = pFrontOfLinkedList;
  pFrontOfLinkedList = pLink;
  count = count + 1;

  if (firstRecursiveCallP == true) 
  {
    if (count == 0)
    {
      return (double)0;
    }
    else if (count == 1)
    {
      distance = pFrontOfLinkedList->value;
      free(pFrontOfLinkedList);
      return distance;
    }
    else if (count == 2)
    {
      distance = (pFrontOfLinkedList->value + 
          pFrontOfLinkedList->pBack->value)/(double)2;
      free(pFrontOfLinkedList->pBack);
      free(pFrontOfLinkedList);
      return distance;
    }
    else
    {
      junkLink.pBack = pFrontOfLinkedList;

      /* SORT first - use bubble sort; we start with at least 3 elements here. */
      /* We are matching backward when sorting the list and comparing MidElem and 
         BackElem along the path;  junkLink is there just to make a symmetric
         operation at the front end. */
      for (j = 0; j < count - 1; j++)
      {
            pFrontElem = &junkLink;
            pMidElem = junkLink.pBack;
            pBackElem = junkLink.pBack->pBack;
        for (i = j; i < count - 1; i++)
        {
          if(pMidElem->value < pBackElem->value)
          {
          /* Swap - carry the smaller value to the root of the linked list. */
            pMidElem->pBack = pBackElem->pBack;
            pBackElem->pBack = pMidElem;
            pFrontElem->pBack = pBackElem;
            /* Correct the order of pFrontElem, pMidElem, pBackElem and match 
               one step */
            pFrontElem = pBackElem;
            pBackElem = pMidElem->pBack;
          }
          else
          {
            pFrontElem = pMidElem;
            pMidElem = pBackElem;
            pBackElem = pBackElem->pBack;
          }
        }
        pFrontOfLinkedList = junkLink.pBack;
      }
      /* Sorted; now get the middle element. */
      for (i = 1; i < (count + 1)/(long) 2; i++)
      {
        /* Similar to Poping the stack */
              pLink = pFrontOfLinkedList;
        pFrontOfLinkedList = pLink->pBack;
        free(pLink);
      }

    /* Get the return value!! - only the last return value is the valid one. */
      distance = pFrontOfLinkedList->value;

      /* Continue from the same i value left off by the previous for loop!  */
      for (; i <= count; i++)
      {
        /* Similar to Poping the stack */
              pLink = pFrontOfLinkedList;
        pFrontOfLinkedList = pLink->pBack;
        free(pLink);
      }
    }
  }
  return distance;
}  /* medianOfDistance */


void leftRightLimits(node *pToSubNode, double *pLeftLimit, 
                double *pRightLimit)
/* As usual, pToSubNode->back is the angle 
   leftLimit is the max angle you can rotate on the left and 
   rightLimit vice versa.
   *pLeftLimit and *pRightLimit must be initialized to 0; without
   initialization, it would introduce bitter bugs into the program;
   they are initialized in this routine.
*/
{
  /* pPivotNode is nodep[pToSubNode->back->index-1], not pPivotSubNode
     which is just pToSubNode->back! */
  node *pLeftSubNode, *pRightSubNode, *pPivotNode, *pSubNode;
  double leftLimit, rightLimit, xToNodeVector, yToNodeVector, xLeftVector, 
    yLeftVector, xRightVector, yRightVector, lengthsProd;

  *pLeftLimit = 0;
  *pRightLimit = 0;
  /* Make an assumption first - guess "pToSubNode->back->next" is the right 
     and the opposite direction is the left! */
  /* It shouldn't be pivoted at a left, but just checking. */
  if (pToSubNode->back->tip == true)
  {
   /* Logically this should not happen.  But we actually can return pi 
      as the limit. */
    printf("ERROR: In leftRightLimits() - Pivoted at a leaf! Unable to " 
        "calculate left and right limit.\n");
    exxit(1);
  }
  else if (pToSubNode->back->next->next == pToSubNode->back)
  {
    *pLeftLimit = 0; /* don't pivot where there is no branching */
    *pRightLimit = 0;
    return;
  }
  /* Else, do this */
  pPivotNode = nodep[pToSubNode->back->index-1];

  /* 3 or more branches - the regular case. */
  /* First, initialize the pRightSubNode - non-repeative portion of the code */
  pRightSubNode = pToSubNode->back;
  pLeftSubNode = pToSubNode->back;
  xToNodeVector = nodep[pToSubNode->index-1]->xcoord - pPivotNode->xcoord;
  yToNodeVector = nodep[pToSubNode->index-1]->ycoord - pPivotNode->ycoord;

  /* If both x and y are 0, then the length must be 0; but this check is not
     enough yet, we need to check the product of length also. */
  if ( fabs(xToNodeVector) < epsilon && fabs(yToNodeVector) < epsilon )
  {
    /* If the branch to rotate is too short, don't rotate it. */
    *pLeftLimit = 0;
    *pRightLimit = 0;
    return;
  }


  while( nodep[pRightSubNode->index-1]->tip != true )
  {
    /* Repeative code */
    pRightSubNode = pRightSubNode->next->back;

    xRightVector = nodep[pRightSubNode->index-1]->xcoord - pPivotNode->xcoord;
    yRightVector = nodep[pRightSubNode->index-1]->ycoord - pPivotNode->ycoord;

    lengthsProd = sqrt(xToNodeVector*xToNodeVector+yToNodeVector*yToNodeVector)
      * sqrt(xRightVector*xRightVector+yRightVector*yRightVector);
    if ( lengthsProd < epsilon )
    {
      continue;
    }
    rightLimit = angleBetVectors(xToNodeVector, yToNodeVector, xRightVector, 
        yRightVector);

    if ( (*pRightLimit) < rightLimit) *pRightLimit = rightLimit;
  }

  while( nodep[pLeftSubNode->index-1]->tip != true )
  {
    /* First, let pSubNode be 1 subnode after rightSubNode. */
    pSubNode = pLeftSubNode->next->next;
    /* Then, loop until the last subNode before getting back to the pivot */
    while (pSubNode->next != pLeftSubNode)
    {
      pSubNode = pSubNode->next;
    }
    pLeftSubNode = pSubNode->back;
    
    xLeftVector = nodep[pLeftSubNode->index-1]->xcoord - pPivotNode->xcoord;
    yLeftVector = nodep[pLeftSubNode->index-1]->ycoord - pPivotNode->ycoord;

    lengthsProd = sqrt(xToNodeVector*xToNodeVector+yToNodeVector*yToNodeVector)
      * sqrt(xLeftVector*xLeftVector+yLeftVector*yLeftVector);
    if ( lengthsProd < epsilon )
    {
      continue;
    }
    leftLimit = angleBetVectors(xToNodeVector, yToNodeVector, xLeftVector, 
        yLeftVector);

    if ( (*pLeftLimit) < leftLimit) *pLeftLimit = leftLimit;
  }
  return;
}  /* leftRightLimits */


void branchLRHelper(node *pPivotSubNode, node *pCurSubNode,
                double *pBranchL, double *pBranchR)
{
/* added - danieyek 990226 */
/* Recursive helper function for branchLeftRightAngles(). 
   pPivotSubNode->back is the pToNode, to which node you apply the forces!
*/
/* Abandoned as it is similar to day-light algorithm; the first part is 
   done implementing but not tested, the second part yet to be 
   implemented if necessary. */
  double xCurNodeVector, yCurNodeVector, xPivotVector, yPivotVector;

  /* Base case : a leaf - return 0 & 0.  */
  if ( nodep[pCurSubNode->index-1]->tip == true )
  {
    xPivotVector = nodep[pPivotSubNode->back->index-1]->xcoord 
      - nodep[pPivotSubNode->index-1]->xcoord;
    yPivotVector = nodep[pPivotSubNode->back->index-1]->ycoord 
      - nodep[pPivotSubNode->index-1]->ycoord;
    xCurNodeVector = nodep[pCurSubNode->index-1]->xcoord 
      - nodep[pPivotSubNode->index-1]->xcoord;
    yCurNodeVector = nodep[pCurSubNode->index-1]->ycoord 
      - nodep[pPivotSubNode->index-1]->ycoord;

    if ( vCounterClkwiseU(xPivotVector, yPivotVector, xCurNodeVector, 
          yCurNodeVector) 
         == 1)
    {
      /* Relevant to Left Angle */
      *pBranchL = angleBetVectors(xPivotVector, yPivotVector, 
                                  xCurNodeVector, yCurNodeVector);
      *pBranchR = (double)0;
    }
    else
    {
      /* Relevant to Right Angle */
      *pBranchR = angleBetVectors(xPivotVector, yPivotVector,
                                  xCurNodeVector, yCurNodeVector);
      *pBranchL = (double)0;
    }
    return;
  }
  else
  {
    /* not a leaf */
  }
} /* branchLRHelper */


void improveNodeAngle(node *pToNode, double medianDistance)
{
  double forcePerpendicular, distance, 
    xDistance, yDistance, angleRotate, sinAngleRotate, cosAngleRotate, 
    norminalDistance, leftLimit, rightLimit, limitFactor;
  node *pPivot;

  /* Limit factor determinte how close the rotation can approach the 
     absolute limit before colliding with other branches */
  limitFactor = (double)4 / (double)5;
  pPivot = pToNode->back;

  xDistance = nodep[pPivot->index-1]->xcoord - nodep[pToNode->index-1]->xcoord;
  yDistance = nodep[pPivot->index-1]->ycoord - nodep[pToNode->index-1]->ycoord;
  distance = sqrt( xDistance*xDistance + yDistance*yDistance  );

  /* convert distance to absolute value and test if it is zero */
  if ( fabs(distance) < epsilon) 
  {
    angleRotate = (double)0;
  }
  else 
  {
    leftRightLimits(pToNode, &leftLimit, &rightLimit);
    norminalDistance = distance / medianDistance;
    forcePerpendicular = forcePerpendicularOnNode(pPivot, pToNode,
        medianDistance);
    angleRotate = forcePerpendicular / norminalDistance;
    /* Limiting the angle of rotation */
    if ( angleRotate > 0 && angleRotate > limitFactor * leftLimit)
    {
      /* Left */
      angleRotate = limitFactor * leftLimit;
    }
    else if ( -angleRotate > limitFactor * rightLimit )
    /* angleRotate < 0 && */ 
    {
      /* Right */
      angleRotate = - limitFactor * rightLimit;
    }
  }
  angleRotate = (double).1 * angleRotate;

  sinAngleRotate = sin(angleRotate);
  cosAngleRotate = cos(angleRotate);

  tilttrav(pToNode,  
           &(nodep[pPivot->index - 1]->xcoord), 
           &(nodep[pPivot->index - 1]->ycoord), 
           &sinAngleRotate, &cosAngleRotate);

  polarizeABranch(pToNode,
           &(nodep[pPivot->index - 1]->xcoord),
           &(nodep[pPivot->index - 1]->ycoord));
}  /* improveNodeAngle */


void improvtravn(node *pStartingSubNode)
{
/* improvtrav for n-body. */
/* POPStack is the stack that is currently being used (popped); 
   PUSHStack is the stack that is for the use of the next round 
   (is pushed now) */
  stackElemType *pPUSHStackTop, *pPOPStackTop, *pTempStack;
  node *pSubNode, *pBackStartNode, *pBackSubNode;
  double medianDistance;
  long noOfIteration;

  /* Stack starts with no element on it */
  pPUSHStackTop = NULL;
  pPOPStackTop = NULL;


  /* Get the median to relate force to angle proportionally. */
  medianDistance = medianOfDistance(root, true);

  /* Set max. number of iteration */
  for ( noOfIteration = (long)0; noOfIteration < maxNumOfIter; noOfIteration++) {

    /* First, push all subNodes in the root node onto the stack-to-be-used
       to kick up the process */
    pSubNode = pStartingSubNode;
    pushNodeToStack(&pPUSHStackTop, pSubNode);
    while(pSubNode->next != pStartingSubNode)
    {
      pSubNode = pSubNode->next;
      pushNodeToStack(&pPUSHStackTop, pSubNode);
    } 
  
    while (true)
    {
      /* Finishes with the current POPStack; swap the function of the stacks if 
               PUSHStack is not empty */
      if (pPUSHStackTop == NULL)
      {
              /* Exit infinity loop here if empty. */
              break;
      }
      else
      {
              /* swap */
              pTempStack = pPUSHStackTop;
              pPUSHStackTop = pPOPStackTop;
              pPOPStackTop = pTempStack;
      }
      
      while (pPOPStackTop != NULL)
      {
           /* We always push the pivot subNode onto the stack!  That's when we
            pop that pivot subNode, subNode.back is the node we apply the force
            to (ToNode). Also, when we pop a pivot subNode, always push all 
            pivot subNodes in the same ToNode onto the stack. */
              popNodeFromStack(&pPOPStackTop, &pSubNode);
      
              pBackStartNode = pSubNode->back;
              if (pBackStartNode->tip == true)
              {
                /* tip indicates if a node is a leaf */
                improveNodeAngle(pSubNode->back, medianDistance);
      
              }
              else
              {
                /* Push all subNodes in this pSubNode->back onto the
                 * stack-to-be-used, after poping a pivot subNode. If
                 * pSubNode->back is a leaf, no push on stack. */ 
                pBackSubNode = pBackStartNode;
                /* Do not push this pBackStartNode onto the stack!  Or the
                 * process will never stop. */
                while(pBackSubNode->next != pBackStartNode)
                {
                  pBackSubNode = pBackSubNode->next;
                  pushNodeToStack(&pPOPStackTop, pBackSubNode);
                } 
                /* improve the node even if it is not a leaf */
                improveNodeAngle(pSubNode->back, medianDistance);
              }
      }
    }
  }
} /* improvtravn */


void coordimprov(double *xx, double *yy)
{
  /* use angles calculation to improve node coordinate placement */
  long i;

  if (nbody)       /* n-body algorithm */
    improvtravn(root);
  else {          /* equal-daylight algorithm */
    i = 0;
    do {
      maxchange = 0.0;
      improvtrav(root);
      i++;
    } while ((i < MAXITERATIONS) && (maxchange > MINIMUMCHANGE));
  }
}  /* coordimprov */


void calculate()
{
  /* compute coordinates for tree */
  double xx, yy;
  long i;
  double nttot, fontheight, labangle=0, 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 = fabs(nodep[i]->oldlen);
  }

  getwidth(root);
  nttot = root->width;
  for (i = 0; i < nextnode; i++)
    nodep[i]->width = nodep[i]->width * spp / nttot;
  if (!improve)
    plrtrans(root, treeangle, treeangle - ark / 2.0, treeangle + ark / 2.0);
  else plrtrans(root, treeangle, treeangle - pi, treeangle + pi);
  maxx = 0.0;
  minx = 0.0;
  maxy = 0.0;
  miny = 0.0;
  coordtrav(root, &xx,&yy);
  fontheight = heighttext(font,fontname);
  if (labeldirec == fixed)
    labangle = pi * labelrotation / 180.0;
  textlength = (double*) Malloc(nextnode*sizeof(double));
  firstlet = (double*) Malloc(nextnode*sizeof(double));

  for (i = 0; i < nextnode; i++) {
    if (nodep[i]->tip) {
      textlength[i] = lengthtext(nodep[i]->nayme, nodep[i]->naymlength,
                                          fontname,font);
      textlength[i] /= fontheight;
      firstlet[i] = lengthtext(nodep[i]->nayme,1L,fontname,font)
                      / fontheight;
    }
  }
  if (spp > 1)
    labelheight = charht * (maxx - minx) / (spp - 1);
  else
    labelheight = charht * (maxx - minx);
  if (improve) {
    coordimprov(&xx,&yy);
    maxx = 0.0;
    minx = 0.0;
    maxy = 0.0;
    miny = 0.0;
    coordtrav(root, &xx,&yy);
  }
  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;
      else if (labeldirec == middle)
        labangle = 0.0;
      if (cos(labangle) < 0.0 && labeldirec != fixed)
        labangle -= pi;
      firstlet[i] = lengthtext(nodep[i]->nayme,1L,fontname,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 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(node *p, node *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;
  do {
    plottree(pp->back, p);
    pp = pp->next;
  } while (((p == root) && (pp != p->next)) || ((p != root) && (pp != p)));
}  /* plottree */


void plotlabels(char *fontname)
{
  long i;
  double compr, dx = 0, dy = 0, labangle, sino, coso, cosl, sinl,
         cosv, sinv, vec;
  boolean 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;
      else if (labeldirec == middle)
        labangle = 0.0;
      if (cos(labangle) < 0.0)
        labangle -= pi;
      sino = sin(nodep[i]->oldtheta);
      coso = cos(nodep[i]->oldtheta);
      cosl = cos(labangle);
      sinl = sin(labangle);
      right = ((coso*cosl+sino*sinl) > 0.0) || (labeldirec == middle);
      vec = sqrt(1.0+firstlet[i]*firstlet[i]);
      cosv = firstlet[i]/vec;
      sinv = 1.0/vec;
      if (labeldirec == middle) {
          if ((textlength[i]+1.0)*fabs(tan(nodep[i]->oldtheta)) > 2.0) {
            dx = -0.5 * textlength[i] * labelheight * expand;
            if (sino > 0.0) {
              dy = 0.5 * labelheight * expand;
              if (fabs(nodep[i]->oldtheta - pi/2.0) > 1000.0)
                dx += labelheight * expand / (2.0*tan(nodep[i]->oldtheta));
            } else {
              dy = -1.5 * labelheight * expand;
              if (fabs(nodep[i]->oldtheta - pi/2.0) > 1000.0)
                dx += labelheight * expand / (2.0*tan(nodep[i]->oldtheta));
            }
          }
          else {
            if (coso > 0.0) {
              dx = 0.5 * labelheight * expand;
              dy = (-0.5 + (0.5*textlength[i]+0.5)*tan(nodep[i]->oldtheta))
                    * labelheight * expand;
            }
            else {
              dx = -(textlength[i]+0.5) * labelheight * expand;
              dy = (-0.5 - (0.5*textlength[i]+0.5)*tan(nodep[i]->oldtheta))
                    * labelheight * expand;
            }
          }
      } else {
        if (right) {
          dx = labelheight * expand * coso;
          dy = labelheight * expand * sino;
          dx += labelheight * expand * 0.5 * vec * (-cosl*cosv+sinl*sinv);
          dy += labelheight * expand * 0.5 * vec * (-sinl*cosv-cosl*sinv);
        } else {
          dx = labelheight * expand * coso;
          dy = labelheight * expand * sino;
          dx += labelheight * expand * 0.5 * vec * (cosl*cosv+sinl*sinv);
          dy += labelheight * expand * 0.5 * vec * (sinl*cosv-cosl*sinv);
          dx -= textlength[i] * labelheight * expand * cosl;
          dy -= textlength[i] * labelheight * expand * sinl;
        }
      }
      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 */


void user_loop()
{
  /* loop to decide what to do */

  long loopcount;
  char input_char;

  while (!canbeplotted) {
    loopcount = 0;
    do {
      input_char=showparms();
      firstscreens = false;
      if ( input_char != 'Y')
        getparms(input_char);
      countup(&loopcount, 10);
    } while (input_char != 'Y');
    xscale = xunitspercm;
    yscale = yunitspercm;
    plotrparms(spp);
    numlines = dotmatrix
      ? ((long)floor(yunitspercm * ysize + 0.5) / strpdeep):1;
    calculate();
    rescale();
    canbeplotted = true;
 }
} /* user_loop */


void setup_environment(int argc, Char *argv[])
{
  /* Set up all kinds of fun stuff */
  node *q, *r;

  char *pChar;
  double i;
  boolean firsttree;
  treenode = NULL;
  
#ifdef TURBOC
  if ((registerbgidriver(EGAVGA_driver) <0) ||
      (registerbgidriver(Herc_driver) <0)   ||
      (registerbgidriver(CGA_driver) <0)){
    fprintf(stderr,"Graphics error: %s ",grapherrormsg(graphresult()));
    exxit(-1);}
#endif
 
 
  printf("DRAWTREE from PHYLIP version %s\n", VERSION);
  

  /* Open in binary: ftell() is broken for UNIX line-endings under WIN32 */
  openfile(&intree,INTREE,"input tree file", "rb",argv[0],NULL);
  printf("Reading tree ... \n");
  firsttree = true;
  allocate_nodep(&nodep, &intree, &spp);
  treeread (intree, &root, treenode, &goteof, &firsttree, nodep, &nextnode,
      &haslengths, &grbg, initdrawtreenode,true,-1);
  q = root;
  r = root;
  while (!(q->next == root))
    q = q->next;
  q->next = root->next;
  root = q;
  chuck(&grbg, r);
  nodep[spp] = q;
  where = root;
  rotate = true;
  printf("Tree has been read.\n");
  printf("Loading the font ... \n");
  loadfont(font,FONTFILE,argv[0]);
  printf("Font loaded.\n");
  ansi = ANSICRT;
  ibmpc = IBMCRT;
  firstscreens = true;
  initialparms();
  canbeplotted = false;
  if (argc > 1)
  {
    pChar = argv[1];
    for (i = 0; i < strlen(pChar); i++)
    {
      if ( ! isdigit(*pChar) ) 
      {
            /* set to default if the 2nd. parameter is not a number */
            maxNumOfIter = 50;
            return;
      }
      else if ( isspace(*pChar) )
      {
            printf("ERROR: Number of iteration should not contain space!\n");
            exxit(1);
      }
    }
    sscanf(argv[1], "%li", &maxNumOfIter);
  }
  else
  {
    /* 2nd. argument is not entered; use default. */
    maxNumOfIter = 50;
  }
  return;
}  /* setup_environment */

void drawtree(
    char*  intreename,
    char*  plotfilename,
    char*  plotfileopt,
    char*  fontfilename,
    char*  treegrows,
    int    usebranchlengths,
    char*  labeldirecstr,
    double labelangle,
    double treerotation,
    double treearc,
    char*  iterationkind,
    int    iterationcount,
    int    regularizeangles,
    int    avoidlabeloverlap,
    int    branchrescale,
    double branchscaler,
    double relcharhgt,
    double  xmarginratio,
    double  ymarginratio,
    int    dofinalplot,
    char*  finalplotkind)
{
    //printf("hello from DrawTree\n");    //JRMDebug
    //fflush(stdout);

    char *previewfilename = "JavaPreview.ps";
    
    // from init
    javarun   = true;
    ansi = ANSICRT;
    ibmpc = IBMCRT;
    
    firstscreens = false;
    canbeplotted = true;
    dotmatrix = false;

    boolean wasplotted = false;
    grbg = NULL;
    progname = "Drawtree";
    
    initialparms();
    
    // translate Java doubles and ints to Drawtree local variables
    labelrotation = labelangle;
    treeangle     = treerotation * pi / 180;
    ark           = treearc * pi / 180;
    bscale        = branchscaler;
    charht        = relcharhgt;
    maxNumOfIter  = iterationcount;
    xmargin = xmarginratio * paperx;
    ymargin = ymarginratio * papery;
      
    // translate Java boolean to Phylip boolean
    boolean doplot;
    if (dofinalplot != 0)
        doplot = true;
    else
        doplot = false;
    
    if (usebranchlengths != 0)
        uselengths = true;
    else
        uselengths = false;
    
    if (regularizeangles != 0)
        regular = true;
    else
        regular = false;
    
    if (avoidlabeloverlap != 0)
        labelavoid = true;
    else
        labelavoid = false;
    
    if (branchrescale != 0)
        rescaled = true;
    else
        rescaled = false;

    // label direction
    labeldirec = middle;
    if (!strcmp(labeldirecstr,"fixed"))
        labeldirec = fixed;
    if (!strcmp(labeldirecstr,"middle"))
        labeldirec = middle;
    if (!strcmp(labeldirecstr,"radial"))
        labeldirec = radial;
    if (!strcmp(labeldirecstr,"along"))
        labeldirec = along;
    
    // iterate to improve tree
    improve = false;
    nbody = false;
    if (!strcmp(iterationkind,"improve"))
    {
        improve = true;
    }
    if (!strcmp(iterationkind,"nbody"))
    {
        improve = true;
        nbody = true;
    }

  // tree growth direction
    grows = horizontal;
    if (!strcmp(treegrows,"vertical"))
        grows = vertical;

  // figure out plot type
    plotter = lw;
    strcpy(afmfile,"none");
    
    if(dofinalplot)
    {
        if (!strcmp(finalplotkind,"lw"))
        {
            plotter = lw;
        }
        
        /*
        // not currently available
        if(!strcmp(finalplotkind,"svg"))
        {
            plotter = svg;
        }
        */
        
        else if(!strcmp(finalplotkind,"hp"))
        {
            plotter = hp;
        }
        
        if(!strcmp(finalplotkind,"tek"))
        {
            plotter = tek;
        }
        
        if(!strcmp(finalplotkind,"ibm"))
        {
            plotter = ibm;
        }
        
        if(!strcmp(finalplotkind,"mac"))
        {
            plotter = mac;
        }
        
        if(!strcmp(finalplotkind,"houston"))
        {
            plotter = houston;
        }
        
        if(!strcmp(finalplotkind,"decregis"))
        {
            plotter = decregis;
        }
        
        if(!strcmp(finalplotkind,"epson"))
        {
            plotter = epson;
        }
        
        if(!strcmp(finalplotkind,"oki"))
        {
            plotter = oki;
        }
        
        if(!strcmp(finalplotkind,"fig"))
        {
            plotter = fig;
        }
        
        if(!strcmp(finalplotkind,"citoh"))
        {
            plotter = citoh;
        }
        
        if(!strcmp(finalplotkind,"toshiba"))
        {
            plotter = toshiba;
        }
        
        if(!strcmp(finalplotkind,"pcx"))
        {
            plotter = pcx;
        }
        
        if(!strcmp(finalplotkind,"pcl"))
        {
            plotter = pcl;
        }
        
        if(!strcmp(finalplotkind,"pict"))
        {
            plotter = pict;
        }
        
        if(!strcmp(finalplotkind,"ray"))
        {
            plotter = ray;
        }
        
        if(!strcmp(finalplotkind,"pov"))
        {
            plotter = pov;
        }
        
        if(!strcmp(finalplotkind,"xbm"))
        {
            plotter = xbm;
        }
        
        if(!strcmp(finalplotkind,"bmp"))
        {
            plotter = bmp;
        }
        
        if(!strcmp(finalplotkind,"gif"))
        {
            plotter = gif;
        }
        
        if(!strcmp(finalplotkind,"idraw"))
        {
            plotter = idraw;
        }
        
        if(!strcmp(finalplotkind,"vrml"))
        {
            plotter = vrml;
        }
        
        if(!strcmp(finalplotkind,"other"))
        {
            plotter = other;
        }
    }
    else
    {
        // preview
        plotter = lw;  // hardwired to ps
    }
    
    // choose the best Hershey approximation of the font 
    int fontid = figfontid(fontfilename);
    //printf("fontfilename: %s id: %i ", fontfilename, fontid);
    char* hersheyfontname = "font1";
    switch (fontid)
    {
        case 4:  //AvantGarde-Book
        case 8:  //Bookman-Light 
        case 16: //Helvetica
        case 20: //Helvetica-Narrow
            hersheyfontname = "font1"; // romans sans
        break;
        
        case 6:  //AvantGarde-Demi 
        case 10: //Bookman-Demi
        case 18: //Helvetica-Bold
        case 22: //Helvetica-Narrow-Bold
            hersheyfontname = "font2"; // romans sans bold
        break;
        
        case 0: //Times-Roman
        case 2: //Times-Bold
        case 12: //Courier
        case 14: //Courier-Bold
        case 24: //NewCenturySchlbk-Roman
        case 26: //NewCenturySchlbk-Bold
        case 28: //Palatino-Roman
        case 30: //Palatino-Bold
            hersheyfontname = "font3"; // romans serif
        break;
        
        case 1: //Times-Italic
        case 5: //AvantGarde-BookOblique
        case 9: //Bookman-LightItalic
        case 13: //Courier-Italic
        case 17: //Helvetica-Oblique
        case 21: //Helvetica-Narrow-Oblique
        case 25: //NewCenturySchlbk-Italic
        case 29: //Palatino-Italic
        case 33: //ZapfChancery-MediumItalic
            hersheyfontname = "font4"; // romans serif italic
        break;
        
        case 3: //Times-BoldItalic
        case 7: //AvantGarde-DemiOblique
        case 11: //Bookman-DemiItalic
        case 15: //Courier-BoldItalic
        case 19: //Helvetica-BoldOblique
        case 23: //Helvetica-Narrow-BoldOblique
        case 27: //NewCenturySchlbk-BoldItalic
        case 31: //Palatino-BoldItalic
            hersheyfontname = "font5"; // romans serif italic bold
        break;
        
        default:
        /*
        case 32: //Symbol
        case 34: //ZapfDingbats    
        */
            hersheyfontname = "font1"; // romans sans
        break;
            
    }
    //printf("hersheyfontname: %s\n", hersheyfontname);
    loadfont(font,hersheyfontname,progname);
    
    
 #ifdef JAVADEBUG    
    // dump translated parameters from Java to make sure they made it
    //JRMDebug
    printf("***Java input parameters***\n");
    printf("intreename: %s\n",intreename);
    printf("plotfilename: %s\n",plotfilename);
    printf("plotfileopt: %s\n",plotfileopt);
    printf("fontfilename: %s\n",fontfilename);
    printf("usebranchlengths:: %i\n",usebranchlengths);
    printf("labeldirecstr: %s\n",labeldirecstr);
    printf("labelangle: %f\n",labelangle);
    printf("treerotation: %f\n",treerotation);
    printf("treearc: %f\n",treearc);
    printf("iterationkind: %s\n",iterationkind);
    printf("iterationcount: %i\n",iterationcount);
    printf("regularizeangles: %i\n",regularizeangles);
    printf("avoidlabeloverlap: %i\n",avoidlabeloverlap);
    printf("branchrescale: %i\n",branchrescale);
    printf("branchscaler: %f\n",branchscaler);
    printf("relcharhgt: %f\n",relcharhgt);
    printf("dofinalplot: %i\n",dofinalplot);
    printf("previewfilename: %s\n",previewfilename);
    printf("finalplotkind: %s\n",finalplotkind);
    printf("doplot: %i\n",doplot);
    fflush(stdout);    
#endif   
    
    // read tree
    intree = fopen(intreename,"r"); 
    boolean firsttree = true;
    allocate_nodep(&nodep, &intree, &spp);
    plotrparms(spp); 
    treeread (intree, &root, treenode, &goteof, &firsttree, nodep, &nextnode, 
      &haslengths, &grbg, initdrawtreenode,true,-1);
    root->oldlen = 0.0;   //???
    // if there are no lengths, shut uselengths off 
    if (haslengths==0)
    {
        uselengths = false;
    }
    //printf("Tree has been read.\n"); 
    //printf("haslengths: %i\n",haslengths);
    //fflush(stdout);  
  
    // printer specific details to simulate interactive setup
    // mostly from getplotter with some from plotrparms
    // after treeread as some formats need some of the tree data
    dotmatrix = false;
    long stripedepth;
    switch (plotter) {    
        case lw:
           strcpy(fontname, fontfilename);
        break; 
        case hp:
            strcpy(fontname, "Hershey");
        break;  
        case tek:
            strcpy(fontname, "Hershey");
        break;  
        case ibm:
            strcpy(fontname, "Hershey");
        break;  
        case mac:
            strcpy(fontname, "Hershey");
        break;  
        case houston:
            strcpy(fontname, "Hershey");
        break; 
        case decregis:
            strcpy(fontname, "Hershey");
        break; 
        case epson:
            dotmatrix = true;
            strcpy(fontname, "Hershey");
            strpdiv = 1;
            stripedepth = allocstripe(stripe,(strpwide/8),((long)(yunitspercm * ysize)));
        break;
        case oki:
            dotmatrix = true;
            strcpy(fontname, "Hershey");
            strpdiv = 1;
            stripedepth = allocstripe(stripe,(strpwide/8),((long)(yunitspercm * ysize)));
        break;
        case fig:
             strcpy(fontname, fontfilename);
        break;
        case citoh:
            dotmatrix = true;
            strcpy(fontname, "Hershey");
            strpdiv = 1;
            stripedepth = allocstripe(stripe,(strpwide/8),((long)(yunitspercm * ysize)));
        break;
        case toshiba:
            dotmatrix = true;
            strcpy(fontname, "Hershey");
            strpdiv = 4;
            stripedepth = allocstripe(stripe,(strpwide/8),((long)(yunitspercm * ysize)));
        break;
        case pcx:
            dotmatrix = true;
            strcpy(fontname, "Hershey");
            // assume VGA 1024 x 768
            strpwide = 1024;
            yunitspercm = 768 / ysize;
            resopts = 3;
            strpdiv = 10;
            stripedepth = allocstripe(stripe,(strpwide/8),((long)(yunitspercm * ysize)));
        break; 
        case pcl:
            dotmatrix = true;
            strcpy(fontname, "Hershey");
            // assume 300 dpi
            hpresolution = 300;
            xunitspercm = 118.11023622;   /* 300 DPI = 118.1 DPC                    */
            yunitspercm = 118.11023622;
            strpwide = 2550;   /* 8.5 * 300 DPI                                     */
            strpdeep = DEFAULT_STRIPE_HEIGHT;     /* height of the strip            */
            strpdiv = DEFAULT_STRIPE_HEIGHT;      /* in this case == strpdeep       */
            stripedepth = allocstripe(stripe,(strpwide/8),((long)(yunitspercm * ysize)));
        break;  
        case pict:
            strcpy(fontname, fontfilename);
        break; 
        case ray:
            strcpy(fontname, "Hershey");
        break;
        case pov:
            strcpy(fontname, "Hershey");
        break;
        case xbm:
            dotmatrix = true;
            strcpy(fontname, "Hershey");
            // assume 1000 x 1000
            xunitspercm = 1.0;
            yunitspercm = 1.0;
            xsize = 1000;
            ysize = 1000;
            xmargin = 0.08 * xsize;
            ymargin = 0.08 * ysize;
            strpdeep = DEFAULT_STRIPE_HEIGHT;
            strpdiv = DEFAULT_STRIPE_HEIGHT;
            strpwide = (long)xsize;
            stripedepth = allocstripe(stripe,(strpwide/8),((long)(yunitspercm * ysize)));
        break;
        case bmp:
            dotmatrix = true;
            strcpy(fontname, "Hershey");
            // assume 1000 x 1000
            xunitspercm = 1.0;
            yunitspercm = 1.0;
            xsize = 1000;
            ysize = 1000;
            xmargin = 0.08 * xsize;
            ymargin = 0.08 * ysize;
            strpdeep = DEFAULT_STRIPE_HEIGHT;
            strpdiv = DEFAULT_STRIPE_HEIGHT;
            strpwide = (long)xsize;
            stripedepth = allocstripe(stripe,(strpwide/8),((long)(yunitspercm * ysize)));
           /*
            printf("***bmp setup done\n");
            printf("xsize: %f\n", xsize);
            printf("ysize: %f\n", ysize);
            printf("xmargin: %f\n",xmargin);
            printf("ymargin: %f\n",ymargin);
            printf("strpwide: %li, yunitspercm: %f, ysize: %f\n" ,strpwide, yunitspercm, ysize);
            fflush(stdout);
            */
        break;
        case gif:
            strcpy(fontname, fontfilename);
        break;
        case idraw:
            strcpy(fontname, "Times-Bold");
        break; 
        case vrml:
            strcpy(fontname, "Hershey");
            treecolor = 5;
            namecolor = 4;
            vrmlskycolornear = 6;
            vrmlskycolorfar = 6;
            vrmlgroundcolornear = 3;
            vrmlgroundcolorfar = 3;
        break;
        case other:
            strcpy(fontname, "Hershey");
        break;
    
        default:
        break;
    }
    
    numlines = dotmatrix ? ((long)floor(yunitspercm * ysize + 0.5) / strpdeep) :1;
    xscale = xunitspercm;
    yscale = yunitspercm;
    
#ifdef JAVADEBUG    
    printf("\n***internal parameters***\n");
    printf("fontname: %s\n", fontname);
    printf("plotter: %i\n",plotter);
    printf("paperx: %f\n",paperx);
    printf("papery: %f\n",papery);
    printf("hpmargin: %f\n",hpmargin);
    printf("vpmargin: %f\n",vpmargin);
    printf("pagex: %f\n",pagex);
    printf("pagey: %f\n",pagey);
    printf("xmargin: %f\n",xmargin);
    printf("ymargin: %f\n",ymargin);
    printf("rescaled: %i\n",rescaled);
    printf("firstscreens: %i\n",firstscreens);
    printf("canbeplotted: %i\n",canbeplotted);
    printf("labelrotation: %f\n",labelrotation);
    printf("treeangle: %f\n",treeangle);
    printf("maxNumOfIter: %li\n",maxNumOfIter);
    printf("ark: %f\n",ark);
    printf("bscale: %f\n",bscale);
    printf("charht: %f\n",charht);
    printf("uselengths: %i\n",uselengths);
    printf("regular: %i\n",regular);
    printf("rescaled: %i\n",rescaled);
    printf("labeldirec: %i\n",labeldirec);
    printf("improve: %i\n",improve);
    printf("nbody: %i\n",nbody);
    printf("grows: %i\n",grows);
    printf("dotmatrix: %i numlines: %li\n",dotmatrix, numlines);
    fflush(stdout);
#endif   
    
    // set up node link structure
    node *q, *r;
    q = root;
    r = root;
    while (!(q->next == root))
    q = q->next;
    q->next = root->next;
    root = q;
    chuck(&grbg, r);
    nodep[spp] = q;
    where = root;
    rotate = true;
    
    calculate();
    rescale();
    
    int lenname;
    if (doplot)
    {
        lenname = strlen(plotfilename);
    }
    else
    {
        lenname = strlen(previewfilename);
    }
    
    char* usefilename = (char*) malloc(lenname + 1);
    if (doplot)
    {
        strcpy(usefilename, plotfilename);
    }
    else
    {
        strcpy(usefilename, previewfilename);
    }
    
    // Open plot files in binary mode.
    plotfile = fopen(usefilename,plotfileopt);  
    initplotter(spp,fontname);
    numlines = dotmatrix ? ((long)floor(yunitspercm * ysize + 0.5)/strpdeep) : 1;
    
    if (!dofinalplot)
    {
        changepen(labelpen);
        makebox(fontname,&xoffset,&yoffset,&scale,spp);
        changepen(treepen);
    }
    drawit(fontname,&xoffset,&yoffset,numlines,root);
    finishplotter();
    fclose(plotfile);
    wasplotted = true;    
    fclose(intree);
    return;
}



int main(int argc, Char *argv[])
{
  long stripedepth;
  boolean wasplotted = false;
  javarun = false;
#ifdef MAC
  char filename1[FNMLNGTH];
  OSErr retcode;
  FInfo  fndrinfo;
#ifdef OSX_CARBON
  FSRef fileRef;
  FSSpec fileSpec;
#endif
#ifdef __MWERKS__
  SIOUXSetTitle("\pPHYLIP:  Drawtree");
#endif
  argv[0] = "Drawtree";
#endif
  init(argc,argv);
  
  progname = argv[0];
  grbg =  NULL;
  setup_environment(argc, argv);



  user_loop();
    
 #ifdef JAVADEBUG    
    //JRMDebug
    printf("\n***internal parameters***\n");
    printf("fontname: %s\n", fontname);
    printf("plotter: %i\n",plotter);
    printf("paperx: %f\n",paperx);
    printf("papery: %f\n",papery);
    printf("hpmargin: %f\n",hpmargin);
    printf("vpmargin: %f\n",vpmargin);
    printf("pagex: %f\n",pagex);
    printf("pagey: %f\n",pagey);
    printf("xmargin: %f\n",xmargin);
    printf("ymargin: %f\n",ymargin);
    printf("rescaled: %i\n",rescaled);
    printf("firstscreens: %i\n",firstscreens);
    printf("canbeplotted: %i\n",canbeplotted);
    printf("labelrotation: %f\n",labelrotation);
    printf("treeangle: %f\n",treeangle);
    printf("maxNumOfIter: %li\n",maxNumOfIter);
    printf("ark: %f\n",ark);
    printf("bscale: %f\n",bscale);
    printf("charht: %f\n",charht);
    printf("uselengths: %i\n",uselengths);
    printf("regular: %i\n",regular);
    printf("rescaled: %i\n",rescaled);
    printf("labeldirec: %i\n",labeldirec);
    printf("improve: %i\n",improve);
    printf("nbody: %i\n",nbody);
    printf("grows: %i\n",grows);
    printf("dotmatrix: %i\n",dotmatrix);
    fflush(stdout);
#endif
    
  if (dotmatrix) {
    stripedepth = allocstripe(stripe,(strpwide/8),
                              ((long)(yunitspercm * ysize)));
    strpdeep = stripedepth;
    strpdiv  = stripedepth;
  }

  if (!(winaction == quitnow)) {
    // Open plotfiles in binary mode 
    openfile(&plotfile, PLOTFILE, "plot file", "wb", argv[0], pltfilename);
    initplotter(spp,fontname);
    numlines = dotmatrix ? ((long)floor(yunitspercm * ysize + 0.5)/strpdeep) : 1;   
    if (plotter != ibm)
      printf("\nWriting plot file ...\n");
    drawit(fontname,&xoffset,&yoffset,numlines,root);
    finishplotter();
    wasplotted = true;
    FClose(plotfile);
    printf("\nPlot written to file \"%s\"\n", pltfilename);
  }

  FClose(intree);
  printf("\nDone.\n\n");
#ifdef MAC
  if (plotter == pict && wasplotted){
#ifdef OSX_CARBON
    FSPathMakeRef((unsigned char *)pltfilename, &fileRef, NULL);
    FSGetCatalogInfo(&fileRef, kFSCatInfoNone, NULL, NULL, &fileSpec, NULL);
    FSpGetFInfo(&fileSpec, &fndrinfo);
    fndrinfo.fdType='PICT';
    fndrinfo.fdCreator='MDRW';
    FSpSetFInfo(&fileSpec, &fndrinfo);
#else
    strcpy(filename1, pltfilename);
    retcode=GetFInfo(CtoPstr(filename1),0,&fndrinfo);
    fndrinfo.fdType='PICT';
    fndrinfo.fdCreator='MDRW';
    strcpy(filename1, pltfilename);
    retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);
#endif
  }
  if (plotter == lw && wasplotted){
#ifdef OSX_CARBON
    FSPathMakeRef((unsigned char *)pltfilename, &fileRef, NULL);
    FSGetCatalogInfo(&fileRef, kFSCatInfoNone, NULL, NULL, &fileSpec, NULL);
    FSpGetFInfo(&fileSpec, &fndrinfo);
    fndrinfo.fdType='TEXT';
    FSpSetFInfo(&fileSpec, &fndrinfo);
#else
    retcode=GetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);
    fndrinfo.fdType='TEXT';
    retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);
#endif
  }
#endif
#ifdef WIN32
  phyRestoreConsoleAttributes();
#endif
  exxit(0);
  return 1;
}
