source: tags/arb-6.0/GDE/PHYLIP/drawtree.c

Last change on this file was 2175, checked in by westram, 20 years ago

upgrade to PHYLIP 3.6

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 75.3 KB
Line 
1 
2#include "draw.h"
3
4/* Version 3.6.  Copyright (c) 1986-2002 by the University of Washington and
5  Written by Joseph Felsenstein and Christopher A. Meacham.  Additional code
6  written by Sean Lamont, Andrew Keefe, Hisashi Horino and Akiko Fuseki.
7  Permission is granted to copy, distribute,
8  and modify this program provided that (1) this copyright message is
9  not removed and (2) no fee is charged for this program. */
10
11#define GAP             0.5
12#define MAXITERATIONS   100
13#define MINIMUMCHANGE   0.0001
14
15/* added - danieyek 990129 */
16/* When 2 Nodes are on top of each other, this is the max. force that's allowed. */
17#ifdef INFINITY
18#undef INFINITY
19#endif
20#define INFINITY        (double) 9999999999.0
21
22#ifdef MAC
23#undef maxnodes
24#define maxnodes 500     /* debug should this be 250? for 68k Macs? */
25#endif
26
27typedef enum {fixed, radial, along, middle} labelorient;
28FILE        *plotfile;
29char        pltfilename[FNMLNGTH];
30long        nextnode,  strpwide, strpdeep,
31            strptop, strpbottom,  payge, numlines,hpresolution;
32double      xmargin, ymargin, topoflabels, rightoflabels, leftoflabels,
33             bottomoflabels, ark, maxx, maxy, minx, miny, scale, xscale,
34             yscale, xoffset, yoffset, charht, xnow, ynow, xunitspercm,
35             yunitspercm, xsize, ysize, xcorner, ycorner,labelheight,
36             labelrotation, treeangle, expand, bscale, maxchange;
37boolean     canbeplotted, preview, previewing, dotmatrix,haslengths,
38             uselengths, regular, rotate, empty, rescaled,
39             notfirst, improve, nbody, firstscreens, labelavoid;
40boolean     pictbold,pictitalic,pictshadow,pictoutline;
41
42double textlength[maxnodes], firstlet[maxnodes];
43striptype stripe;
44plottertype plotter, oldplotter, previewer;
45growth grows;
46labelorient labeldirec;
47node *root, *where;
48pointarray nodep;
49fonttype font;
50enum {  yes, no } penchange, oldpenchange;
51char ch,resopts;
52char *progname;
53long filesize;
54long strpdiv;
55double pagex,pagey,paperx,papery,hpmargin,vpmargin;
56double trweight;   /* starting here, needed to make sccs version happy */
57boolean goteof;
58node *grbg;
59winactiontype winaction;
60
61/* added - danieyek 990226 */
62long maxNumOfIter;
63
64/* added - danieyek 990203 */
65extern double pie;
66
67
68
69
70
71/* added - danieyek 990204 */
72struct stackElem
73{
74  /* This is actually equivalent to a reversed link list; pStackElemBack
75     point toward the direction of the bottom of the stack */
76  struct stackElem *pStackElemBack;
77  node *pNode;
78};
79typedef struct stackElem stackElemType;
80
81#ifdef X
82String res[]= {
83        "*.input: True",
84        "*.menubar.orientation: horizontal",
85        "*.menubar.borderWidth: 0",
86        "*.drawing_area.background: #CCFFFF",
87        "*.drawing_area.foreground: #000000",
88        "*.menubar.right: ChainLeft",
89        "*.menubar.bottom: ChainTop",
90        "*.menubar.top: ChainTop",
91        "*.menubar.left: ChainLeft",
92        "*.drawing_area.fromVert: menubar",
93        "*.drawing_area.top: ChainTop",
94        "*.drawing_area.bottom: ChainBottom",
95        "*.drawing_area.left: ChainLeft",
96        "*.drawing_area.right: ChainRight",
97        "*.dialog.label: Drawtree -- Unrooted tree plotting program\\n\\n\\nPHYLIP version 3.6. (c) Copyright 1993-2002 by The University of Washington.\\nWritten by Joseph Felsenstein, Andrew Keeffe, Akiko Fuseki, Sean Lamont\\nand Dan Fineman\\nPermission is granted to copy and use this program provided no fee is\\ncharged for it and provided that this copyright notice is not removed.",
98        NULL
99};
100#endif
101
102
103#ifndef OLDC
104/* function prototypes */
105void   initdrawtreenode(node **, node **, node *, long, long, long *,
106        long *, initops, pointarray, pointarray, Char *, Char *, FILE *);
107void   initialparms(void);
108char   showparms(void);
109void   getparms(char);
110void   getwidth(node *);
111void   plrtrans(node *, double, double, double);
112void   coordtrav(node *, double *, double *);
113double angleof(double , double );
114void   polartrav(node *, double, double, double, double, double *,
115        double *, double *, double *);
116void   tilttrav(node *, double *, double *, double *, double *);
117               
118void   leftrightangle(node *, double, double);
119void   improvtrav(node *);
120void   force_1to1(node *, node *, double *, double *, double);
121void   totalForceOnNode(node *, node *, double *, double *, double);
122double dotProduct(double, double, double, double );
123double capedAngle(double);
124double angleBetVectors(double, double, double, double);
125double signOfMoment(double, double, double, double);
126double forcePerpendicularOnNode(node *, node *, double);
127void   polarizeABranch(node *, double *, double *);
128
129void   pushNodeToStack(stackElemType **, node *);
130void   popNodeFromStack(stackElemType **, node **);
131double medianOfDistance(node *, boolean);
132void   leftRightLimits(node *, double *, double *);
133void   branchLRHelper(node *, node *, double *, double *);
134void   branchLeftRightAngles(node *, double *,  double *);
135void   improveNodeAngle(node *, double);
136void   improvtravn(node *);
137void   coordimprov(double *, double *);
138void   calculate(void);
139void   rescale(void);
140void   user_loop(void);
141void setup_environment(int argc, Char *argv[]);
142void polarize(node *p, double *xx, double *yy);
143double vCounterClkwiseU(double Xu, double Yu, double Xv, double Yv);
144/* function prototypes */
145#endif
146
147
148void initdrawtreenode(node **p, node **grbg, node *q, long len,
149                long nodei, long *ntips, long *parens, initops whichinit,
150                pointarray treenode, pointarray nodep, Char *str, Char *ch,
151                FILE *intree)
152{
153  /* initializes a node */
154  long i;
155  boolean minusread;
156  double valyew, divisor;
157
158  switch (whichinit) {
159  case bottom:
160    gnu(grbg, p);
161    (*p)->index = nodei;
162    (*p)->tip = false;
163    for (i=0;i<MAXNCH;i++)
164      (*p)->nayme[i] = '\0';
165    nodep[(*p)->index - 1] = (*p);
166    break;
167  case nonbottom:
168    gnu(grbg, p);
169    (*p)->index = nodei;
170    break;
171  case tip:
172    (*ntips)++;
173    gnu(grbg, p);
174    nodep[(*ntips) - 1] = *p;
175    setupnode(*p, *ntips);
176    (*p)->tip        = true;
177    (*p)->naymlength = len ;
178    strncpy ((*p)->nayme, str, MAXNCH);
179    break;
180  case length:
181    processlength(&valyew, &divisor, ch,
182      &minusread, intree, parens);
183    if (!minusread)
184      (*p)->oldlen = valyew / divisor;
185    else
186      (*p)->oldlen = 0.0;
187    if ((*p)->back != NULL)
188      (*p)->back->oldlen = (*p)->oldlen;
189    break;
190  case hsnolength:
191    haslengths = false;
192    break;
193  default:        /* cases hslength,iter,treewt,unitrwt        */
194    break;        /* should not occur                        */
195  }
196} /* initdrawtreenode */
197
198
199void initialparms()
200{
201  /* initialize parameters */
202  paperx = 20.6375;
203  pagex  = 20.6375;
204  papery = 26.9875;
205  pagey  = 26.9875;
206  strcpy(fontname,"Times-Roman");
207  plotrparms(spp);
208  grows = vertical;
209  treeangle = pi / 2.0;
210  ark = 2 * pi;
211  improve = true;
212  nbody = false;
213  regular = false;
214  rescaled = true;
215  bscale = 1.0;
216  labeldirec = middle;
217  xmargin = 0.08 * xsize;
218  ymargin = 0.08 * ysize;
219  labelrotation = 0.0;
220  charht = 0.3333;
221  preview = true; 
222  plotter = DEFPLOTTER;
223  previewer = DEFPREV;
224  hpmargin = 0.02*pagex;
225  vpmargin = 0.02*pagey;
226  labelavoid = false;
227  uselengths = haslengths;
228}  /* initialparms */
229
230
231char showparms()
232{
233  long loopcount;
234  char numtochange;
235  Char ch,input[64];
236  double treea;
237  char    options[32];
238 
239  strcpy(options,"#YN0OPVBLRAIDSMC");
240  if (strcmp(fontname,"Hershey") !=0 && 
241       (((plotter == pict || plotter == mac)  &&
242       (((grows == vertical && labelrotation == 0.0) ||
243            (grows == horizontal && labelrotation == 90.0))))))
244       strcat(options,"Q");
245  if  (plotter == lw || plotter == idraw || plotter == pict || plotter == mac)
246           strcat(options,"F");
247  if (!improve)
248      strcat(options,"G");
249  if (!firstscreens)
250    clearit();
251  printf("\nUnrooted tree plotting program version %s\n", VERSION);
252  putchar('\n');
253  printf("Here are the settings: \n\n");
254  printf(" 0  Screen type (IBM PC, ANSI)?  %s\n",
255           ibmpc ? "IBM PC" : ansi  ? "ANSI"  : "(none)");
256  printf(" P       Final plotting device: ");
257  switch (plotter) {
258    case lw:
259      printf(" Postscript printer\n");
260      break;
261    case pcl:
262      printf(" HP Laserjet compatible printer (%d DPI)\n", (int) hpresolution);
263      break;
264    case epson:
265      printf(" Epson dot-matrix printer\n");
266      break;
267    case pcx:
268      printf(" PCX file for PC Paintbrush drawing program (%s)\n",
269             (resopts == 1) ? "EGA 640x350" : 
270             (resopts == 2) ? "VGA 800x600" : "VGA 1024x768");
271      break;
272    case pict:
273      printf(" Macintosh PICT file for drawing program\n");
274      break;
275    case idraw:
276      printf(" Idraw drawing program\n");
277      break;
278    case fig:
279      printf(" Xfig drawing program\n");
280      break;
281    case hp:
282      printf(" HPGL graphics language for HP plotters\n");
283      break;
284    case bmp:
285      printf(" MS-Windows Bitmap (%d by %d resolution)\n",
286             (int)xsize,(int)ysize);
287      break;
288    case xbm:
289      printf(" X Bitmap file format (%d by %d resolution)\n",
290             (int)xsize,(int)ysize);
291      break;
292    case ibm:
293      printf(" IBM PC graphics (CGA, EGA, or VGA)\n");
294      break;
295    case tek:
296      printf(" Tektronix graphics screen\n");
297      break;
298   case decregis:
299      printf(" DEC ReGIS graphics (VT240 or DECTerm)\n");
300      break;
301    case houston:
302      printf(" Houston Instruments plotter\n");
303      break;
304    case toshiba:
305      printf(" Toshiba 24-pin dot matrix printer\n");
306      break;
307    case citoh:
308      printf(" Imagewriter or C.Itoh/TEC/NEC 9-pin dot matrix printer\n");
309      break;
310    case oki:
311      printf(" old Okidata 9-pin dot matrix printer\n");
312      break;
313    case ray:
314      printf(" Rayshade ray-tracing program file format\n");
315      break;
316    case pov:
317      printf(" POV ray-tracing program file format\n");
318      break;
319    case vrml:
320      printf(" VRML, Virtual Reality Markup Language\n");
321  case mac:
322  case gif:
323  case other:
324    break ;
325  default:        /* case xpreview not handled        */
326    break;
327  }
328  printf(" V           Previewing device: ");
329  if (!preview)
330    printf(" (none)\n");
331  else {
332    switch (previewer) {
333      case ibm:
334        printf(" IBM PC graphics (CGA, EGA, or VGA)\n");
335        break;
336      case xpreview:
337        printf(" X Windows display\n");
338        break;
339      case tek:
340        printf(" Tektronix graphics screen\n");
341        break;
342      case mac:
343        printf(" Macintosh graphics screen\n");
344        break;
345      case decregis:
346        printf(" DEC ReGIS graphics (VT240 or DECTerm)\n");
347        break;
348      case winpreview:
349        printf(" MS Windows display\n");
350        break;
351    case lw:
352    case hp:
353    case houston:
354    case epson:
355    case oki:
356    case fig:
357    case citoh:
358    case toshiba:
359    case pcx:
360    case pcl:
361    case pict:
362    case ray:
363    case pov:
364    case bmp:
365    case xbm:
366    case gif:
367    case idraw:
368    case other:
369      break ;
370    default:        /* case vrml not handled        */
371      break;
372    }
373  }
374  printf(" B          Use branch lengths:  ");
375  if (haslengths)
376    printf("%s\n",uselengths ? "Yes" : "No");
377   else
378    printf("(no branch lengths available)\n");
379  printf(" L             Angle of labels:");
380  if (labeldirec == fixed) {
381    printf("  Fixed angle of");
382    if (labelrotation >= 10.0)
383      printf("%6.1f", labelrotation);
384    else if (labelrotation <= -10.0)
385      printf("%7.1f", labelrotation);
386    else if (labelrotation < 0.0)
387      printf("%6.1f", labelrotation);
388    else
389      printf("%5.1f", labelrotation);
390    printf(" degrees\n");
391  } else if (labeldirec == radial)
392    printf("  Radial\n");
393  else if (labeldirec == middle)
394    printf("  branch points to Middle of label\n");
395  else
396    printf("  Along branches\n");
397  printf(" R            Rotation of tree:");
398  treea = treeangle * 180 / pi;
399  if (treea >= 100.0)
400    printf("%7.1f\n", treea);
401  else if (treea >= 10.0)
402    printf("%6.1f\n", treea);
403  else if (treea <= -100.0)
404    printf("%8.1f\n", treea);
405  else if (treea <= -10.0)
406    printf("%7.1f\n", treea);
407  else if (treea < 0.0)
408    printf("%6.1f\n", treea);
409  else
410    printf("%5.1f\n", treea);
411  printf(" A       Angle of arc for tree:");
412  treea = 180 * ark / pi;
413  if (treea >= 100.0)
414    printf("%7.1f\n", treea);
415  else if (treea >= 10.0)
416    printf("%6.1f\n", treea);
417  else if (treea <= -100.0)
418    printf("%8.1f\n", treea);
419  else if (treea <= -10.0)
420    printf("%7.1f\n", treea);
421  else if (treea < 0.0)
422    printf("%6.1f\n", treea);
423  else
424    printf("%5.1f\n", treea);
425  /*
426  printf(" I     Iterate to improve tree:  %s\n",
427         (improve ? "Yes" : "No"));
428   */
429  printf(" I     Iterate to improve tree:  ");
430  if (improve) {
431    if (nbody)
432      printf("n-Body algorithm\n");
433    else
434      printf("Equal-Daylight algorithm\n");
435  } else
436    printf("No\n");
437  if (improve)
438    printf(" D  Try to avoid label overlap?  %s\n",
439           (labelavoid? "Yes" : "No"));
440  printf(" S      Scale of branch length:");
441  if (rescaled)
442    printf("  Automatically rescaled\n");
443  else
444    printf("  Fixed:%6.2f cm per unit branch length\n", bscale);
445  if (!improve) {
446    printf(" G       Regularize the angles:  %s\n",
447           (regular ? "Yes" : "No"));
448  }
449  printf(" C   Relative character height:%8.4f\n", charht);
450  if ((((plotter == pict || plotter == mac)  &&
451       (((grows == vertical && labelrotation == 0.0) ||
452       (grows == horizontal && labelrotation == 90.0))))))
453    printf(" F                        Font:  %s\n Q        Pict Font Attributes:  %s, %s, %s, %s\n",
454   fontname, (pictbold   ? "Bold"   : "Medium"),
455        (pictitalic ? "Italic" : "Regular"),
456        (pictshadow ? "Shadowed": "Unshadowed"),
457        (pictoutline ? "Outlined" : "Unoutlined"));
458    else if (plotter == lw || plotter == idraw) 
459    printf(" F                        Font:  %s\n",fontname);
460  if (plotter == ray) {
461    printf(" M          Horizontal margins:%6.2f pixels\n", xmargin);
462    printf(" M            Vertical margins:%6.2f pixels\n", ymargin);
463  } else {
464    printf(" M          Horizontal margins:%6.2f cm\n", xmargin);
465    printf(" M            Vertical margins:%6.2f cm\n", ymargin);
466  }
467  printf(" #           Page size submenu:  ");
468  /* Add 0.5 to clear up truncation problems. */
469  if (((int) ((pagex / paperx) + 0.5) == 1) && 
470      ((int) ((pagey / papery) + 0.5) == 1))
471    /* If we're only using one page per tree, */
472    printf ("one page per tree\n") ;   
473  else
474    printf ("%.0f by %.0f pages per tree\n",
475             (pagey-vpmargin) / (papery-vpmargin),
476             (pagex-hpmargin) / (paperx-hpmargin)) ;
477  loopcount = 0;
478  for (;;) {
479    printf("\n Y to accept these or type the letter for one to change\n");
480#ifdef WIN32
481    phyFillScreenColor();
482#endif
483    getstryng(input);
484    uppercase(&input[0]);
485    ch=input[0];
486    if (strchr(options,ch))
487      {
488        numtochange = ch;
489        break; 
490      }
491    printf(" That letter is not one of the menu choices.  Type\n");
492    countup(&loopcount, 100);
493  }
494  return numtochange; 
495}  /* showparms */
496
497
498void getparms(char numtochange)
499{
500  /* get from user the relevant parameters for the plotter and diagram */
501  long loopcount, loopcount2;
502  Char ch;
503  boolean ok;
504  char    options[32];
505  char    line[32];
506  char    input[100];
507  int m, n;
508
509  n = (int)((pagex-hpmargin-0.01)/(paperx-hpmargin)+1.0);
510  m = (int)((pagey-vpmargin-0.01)/(papery-vpmargin)+1.0);
511  strcpy(options,"YNOPVBLRAIDSMC");
512  if      ((((plotter == pict || plotter == mac)  &&
513          (((grows == vertical && labelrotation == 0.0) ||
514            (grows == horizontal && labelrotation == 90.0))))))
515         strcat(options,"Q");
516  if  (plotter == lw || plotter == idraw) 
517           strcat(options,"F");
518  if (!improve)
519      strcat(options,"G");
520  if (numtochange == '*') {
521    do {
522      printf(" Type the number of one that you want to change:\n");
523#ifdef WIN32
524      phyFillScreenColor();
525#endif
526      getstryng(line);
527      numtochange = line[0];
528      } while (strchr(options,numtochange));
529  }
530  switch (numtochange) {
531
532  case '0':
533    initterminal(&ibmpc, &ansi);
534    break;
535
536  case 'P':
537    getplotter();
538    break;
539
540  case 'V':
541    getpreview();
542    break;
543
544  case '#':
545    loopcount2 = 0;
546    for (;;){
547      clearit();
548      printf("  Page Specifications Submenu\n\n");
549      printf(" L   Output size in pages: %.0f down by %.0f across\n",
550             (pagey / papery), (pagex / paperx));
551      printf(" P   Physical paper size: %1.5f by %1.5f cm\n",paperx,papery);
552      printf(" O   Overlap Region: %1.5f %1.5f cm\n",hpmargin,vpmargin);
553      printf(" M   main menu\n");
554#ifdef WIN32
555      phyFillScreenColor();
556#endif
557      getstryng(input);
558      ch = input[0];
559      uppercase(&ch);
560      switch (ch){
561      case 'L':
562        printf("Number of pages in height:\n");
563#ifdef WIN32
564        phyFillScreenColor();
565#endif
566        getstryng(input);
567        m = atoi(input);
568        printf("Number of pages in width:\n");
569#ifdef WIN32
570        phyFillScreenColor();
571#endif
572        getstryng(input);
573        n = atoi(input);
574        break;
575      case 'P':
576        printf("Paper Width (in cm):\n");
577#ifdef WIN32
578        phyFillScreenColor();
579#endif
580        getstryng(input);
581        paperx = atof(input);
582        printf("Paper Height (in cm):\n");
583#ifdef WIN32
584        phyFillScreenColor();
585#endif
586        getstryng(input);
587        papery = atof(input);   
588        break;
589      case 'O':
590        printf("Horizontal Overlap (in cm):");
591#ifdef WIN32
592        phyFillScreenColor();
593#endif
594        getstryng(input);
595        hpmargin = atof(input);   
596        printf("Vertical Overlap (in cm):");
597#ifdef WIN32
598        phyFillScreenColor();
599#endif
600        getstryng(input);
601        vpmargin = atof(input);   
602      case 'M':
603        break;
604      default:
605        printf("Please enter L, P, O , or M.\n");
606        break;
607      }
608      pagex = ((double)n * (paperx-hpmargin)+hpmargin);
609      pagey = ((double)m * (papery-vpmargin)+vpmargin);
610      if (ch == 'M')
611        break;
612      countup(&loopcount2, 20);
613    }
614    break;
615
616  case 'B':
617    if (haslengths)
618      uselengths = !uselengths;
619    else {
620      printf("Cannot use lengths since not all of them exist\n");
621      uselengths = false;
622    }
623    break;
624
625  case 'L':
626    printf("\nDo you want labels to be Fixed angle, Radial, Along,");
627    printf(" or Middle?\n");
628    loopcount2 = 0;
629    do {
630      printf(" Type F, R, A, or M\n");
631#ifdef WIN32
632      phyFillScreenColor();
633#endif
634      scanf("%c%*[^\n]", &ch);
635      (void)getchar();
636      if (ch == '\n')
637        ch = ' ';
638      uppercase(&ch);
639      countup(&loopcount2, 10);
640    } while (ch != 'F' && ch != 'R' && ch != 'A' && ch != 'M');
641    switch (ch) {
642
643    case 'A':
644      labeldirec = along;
645      break;
646
647    case 'F':
648      labeldirec = fixed;
649      break;
650
651    case 'R':
652      labeldirec = radial;
653      break;
654
655    case 'M':
656      labeldirec = middle;
657      break;
658    }
659    if (labeldirec == fixed) {
660      printf("Are the labels to be plotted vertically (90),\n");
661      printf(" horizontally (0), or downwards (-90) ?\n");
662      loopcount2 = 0;
663      do {
664        printf(" Choose an angle in degrees from 90 to -90: \n");
665#ifdef WIN32
666        phyFillScreenColor();
667#endif
668        scanf("%lf%*[^\n]", &labelrotation);
669        (void)getchar();
670        countup(&loopcount2, 10);
671      } while ((labelrotation < -90.0 || labelrotation > 90.0) &&
672               labelrotation != -99.0);
673    }
674    break;
675
676  case 'R':
677    printf("\n At what angle is the tree to be plotted?\n");
678    loopcount2 = 0;
679    do {
680      printf(" Choose an angle in degrees from 360 to -360: \n");
681#ifdef WIN32
682      phyFillScreenColor();
683#endif
684      scanf("%lf%*[^\n]", &treeangle);
685      (void)getchar();
686      uppercase(&ch);
687      countup(&loopcount2, 10);
688    } while (treeangle < -360.0 && treeangle > 360.0);
689    treeangle = treeangle * pi / 180;
690    break;
691
692  case 'A':
693    printf(" How many degrees (up to 360) of arc\n");
694    printf("  should the tree occupy? (Currently it is %5.1f)\n",
695           180 * ark / pi);
696    loopcount2 = 0;
697    do {
698      printf("Enter a number of degrees from 0 up to 360)\n");
699#ifdef WIN32
700      phyFillScreenColor();
701#endif
702      scanf("%lf%*[^\n]", &ark);
703      (void)getchar();
704      countup(&loopcount2, 10);
705    } while (ark <= 0.0 || ark > 360.0);
706    ark = ark * pi / 180;
707    break;
708
709  case 'I':
710    if (nbody) {
711      improve = false;
712      nbody = false;
713    } else {
714      if (improve)
715        nbody = true;
716      else improve = true;
717    }
718    break;
719
720  case 'D':
721    labelavoid = !labelavoid;
722    break;
723
724  case 'S':
725    rescaled = !rescaled;
726    if (!rescaled) {
727      printf("Centimeters per unit branch length?\n");
728#ifdef WIN32
729      phyFillScreenColor();
730#endif
731      scanf("%lf%*[^\n]", &bscale);
732      (void)getchar();
733    }
734    break;
735
736  case 'M':
737    clearit();
738    printf("\nThe tree will be drawn to fit in a rectangle which has \n");
739    printf(" margins in the horizontal and vertical directions of:\n");
740    if (plotter == ray) {
741      printf(
742       "%6.2f pixels (horizontal margin) and%6.2f pixels (vertical margin)\n",
743               xmargin, ymargin);
744      }
745    else {
746        printf("%6.2f cm (horizontal margin) and%6.2f cm (vertical margin)\n",
747               xmargin, ymargin);
748      }
749    loopcount2 = 0;
750    do {
751      printf(" New value (in cm) of horizontal margin?\n");
752#ifdef WIN32
753      phyFillScreenColor();
754#endif
755      scanf("%lf%*[^\n]", &xmargin);
756      (void)getchar();
757      ok = ((unsigned)xmargin < xsize / 2.0);
758      if (!ok)
759        printf(" Impossible value.  Please retype it.\n");
760      countup(&loopcount2, 10);
761    } while (!ok);
762    loopcount2 = 0;
763    do {
764      printf(" New value (in cm) of vertical margin?\n");
765#ifdef WIN32
766      phyFillScreenColor();
767#endif
768      scanf("%lf%*[^\n]", &ymargin);
769      (void)getchar();
770      ok = ((unsigned)ymargin < ysize / 2.0);
771      if (!ok)
772        printf(" Impossible value.  Please retype it.\n");
773      countup(&loopcount2, 10);
774    } while (!ok);
775    break;
776
777  case 'C':
778    printf("New value of character height?\n");
779#ifdef WIN32
780    phyFillScreenColor();
781#endif
782    scanf("%lf%*[^\n]", &charht);
783    (void)getchar();
784    break;
785
786  case 'F':
787      printf("Enter font name or \"Hershey\" for default font\n");
788#ifdef WIN32
789      phyFillScreenColor();
790#endif
791      getstryng(fontname);
792      break;
793
794  case 'G':
795      regular = !regular;
796      break;
797
798 case 'Q':
799    clearit();
800    loopcount2 = 0;
801    do {
802      printf("Italic? (Y/N)\n"); 
803#ifdef WIN32
804      phyFillScreenColor();
805#endif
806      getstryng(input);
807      input[0] = toupper(input[0]);
808      countup(&loopcount2, 10);
809    } while (input[0] != 'Y' && input[0] != 'N');
810    pictitalic = (input[0] == 'Y');
811    loopcount2 = 0;
812    do {
813      printf("Bold? (Y/N)\n"); 
814#ifdef WIN32
815      phyFillScreenColor();
816#endif
817      getstryng(input);
818      input[0] = toupper(input[0]);
819      countup(&loopcount2, 10);
820    } while (input[0] != 'Y' && input[0] != 'N');
821    pictbold = (input[0] == 'Y');
822    loopcount2 = 0;
823    do {
824      printf("Shadow? (Y/N)\n"); 
825#ifdef WIN32
826      phyFillScreenColor();
827#endif
828      getstryng(input);
829      input[0] = toupper(input[0]);
830      countup(&loopcount2, 10);
831    } while (input[0] != 'Y' && input[0] != 'N');
832    pictshadow = (input[0] == 'Y');
833    loopcount2 = 0;
834    do {
835      printf("Outline? (Y/N)\n"); 
836#ifdef WIN32
837      phyFillScreenColor();
838#endif
839      getstryng(input);
840      input[0] = toupper(input[0]);
841      countup(&loopcount2, 10);
842    } while (input[0] != 'Y' && input[0] != 'N');
843    pictoutline = (input[0] == 'Y');
844    break;
845
846    countup(&loopcount, 100);
847  }
848}  /* getparms */
849
850
851void getwidth(node *p)
852{
853  /* get width and depth beyond each node */
854  double nw, nd;
855  node *pp, *qq;
856
857  nd = 0.0;
858  if (p->tip)
859    nw = 1.0;
860  else {
861    nw = 0.0;
862    qq = p;
863    pp = p->next;
864    do {
865      getwidth(pp->back);
866      nw += pp->back->width;
867      if (pp->back->depth > nd)
868        nd = pp->back->depth;
869      pp = pp->next;
870    } while (((p != root) && (pp != qq)) || ((p == root) && (pp != p->next)));
871  }
872  p->depth = nd + p->length;
873  p->width = nw;
874}  /* getwidth */
875
876
877void plrtrans(node *p, double theta, double lower, double upper)
878{
879  /* polar coordinates of a node relative to start */
880  long num;
881  double nn, pr, ptheta, angle, angle2, subangle, len;
882  node *pp, *qq;
883
884  nn = p->width;
885  angle = theta;
886  subangle = (upper - lower) / nn;
887  qq = p;
888  pp = p->next;
889  if (p->tip)
890    return;
891  angle = upper;
892  do {
893    angle -= pp->back->width / 2.0 * subangle;
894    pr = p->r;
895    ptheta = p->theta;
896    if (regular) {
897      num = 1;
898      while (num * subangle < 2 * pi)
899        num *= 2;
900      if (angle >= 0.0)
901        angle2 = 2 * pi / num * (long)(num * angle / (2 * pi) + 0.5);
902      else
903        angle2 = 2 * pi / num * (long)(num * angle / (2 * pi) - 0.5);
904    } else
905      angle2 = angle;
906    if (uselengths)
907      len = fabs(pp->back->oldlen);
908    else
909      len = 1.0;
910    pp->back->r = sqrt(len * len + pr * pr + 2 * len * pr * cos(angle2 - ptheta));
911    if (fabs(pr * cos(ptheta) + len * cos(angle2)) > epsilon)
912      pp->back->theta = atan((pr * sin(ptheta) + len * sin(angle2)) /
913                             (pr * cos(ptheta) + len * cos(angle2)));
914    else if (pr * sin(ptheta) + len * sin(angle2) >= 0.0)
915      pp->back->theta = pi / 2;
916    else
917      pp->back->theta = 1.5 * pi;
918    if (pr * cos(ptheta) + len * cos(angle2) < -epsilon)
919      pp->back->theta += pi;
920    if (!pp->back->tip)
921      plrtrans(pp->back, pp->back->theta,
922                 angle - pp->back->width * subangle / 2.0,
923                 angle + pp->back->width * subangle / 2.0);
924    else
925      pp->back->oldtheta = angle2;
926    angle -= pp->back->width / 2.0 * subangle;
927    pp = pp->next;
928  } while (((p != root) && (pp != qq)) || ((p == root) && (pp != p->next)));
929}  /* plrtrans */
930
931
932void coordtrav(node *p, double *xx, double *yy)
933{
934  /* compute x and y coordinates */
935  node *pp;
936
937  if (!p->tip) {
938    pp = p->next;
939    while (pp != p) {
940           coordtrav(pp->back, xx, yy);
941           pp = pp->next;
942    if (p == root)
943           coordtrav(p->back, xx, yy);
944    }
945  }
946  (*xx) = p->r * cos(p->theta);
947  (*yy) = p->r * sin(p->theta);
948  if ((*xx) > maxx)
949    maxx = (*xx);
950  if ((*xx) < minx)
951    minx = (*xx);
952  if ((*yy) > maxy)
953    maxy = (*yy);
954  if ((*yy) < miny)
955    miny = (*yy);
956  p->xcoord = (*xx);
957  p->ycoord = (*yy);
958}  /* coordtrav */
959
960
961double angleof(double x, double y)
962{
963  /* compute the angle of a vector */
964  double theta;
965
966  if (fabs(x) > epsilon)
967    theta = atan(y / x);
968  else if (y >= 0.0)
969      theta = pi / 2;
970    else
971      theta = 1.5 * pi;
972  if (x < -epsilon)
973    theta = pi + theta;
974  while (theta > 2 * pi)
975    theta -= 2 * pi;
976  while (theta < 0.0)
977    theta += 2 * pi;
978  return theta;
979}  /* angleof */
980
981
982void polartrav(node *p, double xx, double yy, double firstx,
983                double firsty, double *leftx, double *lefty, double *rightx,
984                double *righty)
985{
986  /* go through subtree getting left and right vectors */
987  double x, y, xxx, yyy, labangle = 0;
988  boolean lookatit;
989  node *pp;
990
991  lookatit = true;
992  if (!p->tip)
993    lookatit = (p->next->next != p || p->index != root->index);
994  if (lookatit) {
995    x = nodep[p->index - 1]->xcoord;
996    y = nodep[p->index - 1]->ycoord;
997    if (p->tip) {
998      if (labeldirec == fixed) {
999        labangle = pi * labelrotation / 180.0;
1000        if (cos(p->oldtheta) < 0.0)
1001          labangle = labangle - pi;
1002      }
1003      if (labeldirec == radial)
1004        labangle = p->theta;
1005      else if (labeldirec == along)
1006        labangle = p->oldtheta;
1007      else if (labeldirec == middle)
1008        labangle = 0.0;
1009      xxx = x;
1010      yyy = y;
1011      if (labelavoid) {
1012        if  (labeldirec == middle) {
1013          xxx += GAP * labelheight * cos(p->oldtheta);
1014          yyy += GAP * labelheight * sin(p->oldtheta);
1015          xxx += labelheight * cos(labangle) * textlength[p->index - 1];
1016          if (textlength[p->index - 1] * sin(p->oldtheta) < 1.0)
1017            xxx += labelheight * cos(labangle) * textlength[p->index - 1];
1018          else
1019            xxx += 0.5 * labelheight * cos(labangle)
1020                     * textlength[p->index - 1];
1021          yyy += labelheight * sin(labangle) * textlength[p->index - 1];
1022        }
1023        else {
1024          xxx += GAP * labelheight * cos(p->oldtheta);
1025          yyy += GAP * labelheight * sin(p->oldtheta);
1026          xxx -= labelheight * cos(labangle) * 0.5 * firstlet[p->index - 1];
1027          yyy -= labelheight * sin(labangle) * 0.5 * firstlet[p->index - 1];
1028          xxx += labelheight * cos(labangle) * textlength[p->index - 1];
1029          yyy += labelheight * sin(labangle) * textlength[p->index - 1];
1030        }
1031      }
1032      if ((yyy - yy) * firstx - (xxx - xx) * firsty < 0.0) {
1033        if ((yyy - yy) * (*rightx) - (xxx - xx) * (*righty) < 0.0) {
1034          (*rightx) = xxx - xx;
1035          (*righty) = yyy - yy;
1036        }
1037      }
1038      if ((yyy - yy) * firstx - (xxx - xx) * firsty > 0.0) {
1039        if ((yyy - yy) * (*leftx) - (xxx - xx) * (*lefty) > 0.0) {
1040          (*leftx) = xxx - xx;
1041          (*lefty) = yyy - yy;
1042        }
1043      }
1044    }
1045    if ((y - yy) * firstx - (x - xx) * firsty < 0.0) {
1046      if ((y - yy) * (*rightx) - (x - xx) * (*righty) < 0.0) {
1047        (*rightx) = x - xx;
1048        (*righty) = y - yy;
1049      }
1050    }
1051    if ((y - yy) * firstx - (x - xx) * firsty > 0.0) {
1052      if ((y - yy) * (*leftx) - (x - xx) * (*lefty) > 0.0) {
1053        (*leftx) = x - xx;
1054        (*lefty) = y - yy;
1055      }
1056    }
1057  }
1058  if (p->tip)
1059    return;
1060  pp = p->next;
1061  while (pp != p) {
1062    if (pp != NULL)
1063      polartrav(pp->back,xx,yy,firstx,firsty,leftx,lefty,rightx,righty);
1064    pp = pp->next;
1065  }
1066}  /* polartrav */
1067
1068
1069void tilttrav(node *q, double *xx, double *yy, double *sinphi,
1070                double *cosphi)
1071{
1072  /* traverse to move successive nodes */
1073  double x, y;
1074  node *pp;
1075
1076  pp = nodep[q->index - 1];
1077  x = pp->xcoord;
1078  y = pp->ycoord;
1079  pp->xcoord = (*xx) + (x - (*xx)) * (*cosphi) + ((*yy) - y) * (*sinphi);
1080  pp->ycoord = (*yy) + (x - (*xx)) * (*sinphi) + (y - (*yy)) * (*cosphi);
1081  if (q->tip)
1082    return;
1083  pp = q->next;
1084  while (pp != q) {
1085    /*
1086    if (pp != root)
1087    */
1088    if (pp->back != NULL)
1089      tilttrav(pp->back,xx,yy,sinphi,cosphi);
1090    pp = pp->next;
1091  }
1092}  /* tilttrav */
1093
1094
1095void polarize(node *p, double *xx, double *yy)
1096{
1097  double TEMP, TEMP1;
1098
1099  if (fabs(p->xcoord - (*xx)) > epsilon)
1100    p->oldtheta = atan((p->ycoord - (*yy)) / (p->xcoord - (*xx)));
1101  else if (p->ycoord - (*yy) > epsilon)
1102      p->oldtheta = pi / 2;
1103  if (p->xcoord - (*xx) < -epsilon)
1104    p->oldtheta += pi;
1105  if (fabs(p->xcoord - root->xcoord) > epsilon)
1106    p->theta = atan((p->ycoord - root->ycoord) / (p->xcoord - root->xcoord));
1107  else if (p->ycoord - root->ycoord > 0.0)
1108      p->theta = pi / 2;
1109    else
1110      p->theta = 1.5 * pi;
1111  if (p->xcoord - root->xcoord < -epsilon)
1112    p->theta += pi;
1113  TEMP = p->xcoord - root->xcoord;
1114  TEMP1 = p->ycoord - root->ycoord;
1115  p->r = sqrt(TEMP * TEMP + TEMP1 * TEMP1);
1116}  /* polarize */
1117
1118
1119void leftrightangle(node *p, double xx, double yy)
1120{
1121  /* get leftmost and rightmost angle of subtree, put them in node p */
1122  double firstx, firsty, leftx, lefty, rightx, righty;
1123  double langle, rangle;
1124
1125  firstx = nodep[p->back->index-1]->xcoord - xx;
1126  firsty = nodep[p->back->index-1]->ycoord - yy;
1127  leftx = firstx;
1128  lefty = firsty;
1129  rightx = firstx;
1130  righty = firsty;
1131  if (p->back != NULL)
1132    polartrav(p->back,xx,yy,firstx,firsty,&leftx,&lefty,&rightx,&righty);
1133  if ((fabs(leftx) < epsilon) && (fabs(lefty) < epsilon))
1134    langle = p->back->oldtheta;
1135  else
1136    langle = angleof(leftx, lefty);
1137  if ((fabs(rightx) < epsilon) && (fabs(righty) < epsilon))
1138    rangle = p->back->oldtheta;
1139  else
1140    rangle = angleof(rightx, righty);
1141  while (langle - rangle > 2*pi)
1142    langle -= 2 * pi;
1143  while (rangle > langle)
1144    langle += 2 * pi;
1145  p->lefttheta = langle;
1146  p->righttheta = rangle;
1147} /* leftrightangle */
1148
1149
1150void improvtrav(node *p)
1151{
1152  /* traverse tree trying different tiltings at each node */
1153  double xx, yy, cosphi, sinphi;
1154  double langle, rangle, sumrot, olddiff;
1155  node *pp, *qq, *ppp;;
1156
1157  if (p->tip)
1158    return;
1159  xx = p->xcoord;
1160  yy = p->ycoord;
1161  pp = p->next;
1162  do {
1163    leftrightangle(pp, xx, yy);
1164    pp = pp->next;
1165  } while ((pp != p->next));
1166  if (p == root) {
1167    pp = p->next;
1168    do {
1169      qq = pp;
1170      pp = pp->next;
1171    } while (pp != root);                      /* debug ?? */
1172    p->righttheta = qq->righttheta;
1173    p->lefttheta = p->next->lefttheta;
1174  }
1175  qq = p;
1176  pp = p->next;
1177  ppp = p->next->next;
1178  do {
1179    langle = qq->righttheta - pp->lefttheta;
1180    rangle = pp->righttheta - ppp->lefttheta; 
1181    /*
1182    if (langle > pi)
1183      langle -= 2*pi;
1184    if (langle < -pi)
1185      langle += 2*pi;
1186    if (rangle > pi)
1187      rangle -= 2*pi;
1188    if (rangle < -pi)
1189      rangle += 2*pi;
1190      */
1191    while (langle > pi)
1192      langle -= 2*pi;
1193    while (langle < -pi)
1194      langle += 2*pi;
1195    while (rangle > pi)
1196      rangle -= 2*pi;
1197    while (rangle < -pi)
1198      rangle += 2*pi;
1199    olddiff = fabs(langle-rangle);
1200    sumrot = (langle - rangle) /2.0;
1201    if (sumrot > langle)
1202      sumrot = langle;
1203    if (sumrot < -rangle)
1204      sumrot = -rangle;
1205    cosphi = cos(sumrot);
1206    sinphi = sin(sumrot);
1207    /*
1208    if ((p != root) || ((p == root) && (root->next->next->next != root))) {
1209    */
1210    if (p != root) {
1211      if (fabs(sumrot) > maxchange)
1212        maxchange = fabs(sumrot);
1213      pp->back->oldtheta += sumrot;
1214      tilttrav(pp->back,&xx,&yy,&sinphi,&cosphi);
1215      polarize(pp->back,&xx,&yy);
1216      leftrightangle(pp, xx, yy);
1217      langle = qq->righttheta - pp->lefttheta;
1218      rangle = pp->righttheta - ppp->lefttheta; 
1219      /*
1220      if (langle > pi)
1221        langle -= 2*pi;
1222      if (langle < -pi)
1223        langle += 2*pi;
1224      if (rangle > pi)
1225        rangle -= 2*pi;
1226      if (rangle < -pi)
1227        rangle += 2*pi;
1228      */
1229      while (langle > pi)
1230        langle -= 2*pi;
1231      while (langle < -pi)
1232        langle += 2*pi;
1233      while (rangle > pi)
1234        rangle -= 2*pi;
1235      while (rangle < -pi)
1236        rangle += 2*pi;
1237      while ((fabs(langle-rangle) > olddiff) && (fabs(sumrot) > 0.01)) {
1238        sumrot = sumrot /2.0;
1239        cosphi = cos(-sumrot);
1240        sinphi = sin(-sumrot);
1241        pp->back->oldtheta -= sumrot;
1242        tilttrav(pp->back,&xx,&yy,&sinphi,&cosphi);
1243        polarize(pp->back,&xx,&yy);
1244        leftrightangle(pp, xx, yy);
1245        langle = qq->righttheta - pp->lefttheta;
1246        rangle = pp->righttheta - ppp->lefttheta; 
1247        if (langle > pi)
1248          langle -= 2*pi;
1249        if (langle < -pi)
1250          langle += 2*pi;
1251        if (rangle > pi)
1252          rangle -= 2*pi;
1253        if (rangle < -pi)
1254          rangle += 2*pi;
1255      }
1256    }
1257    qq = pp;
1258    pp = pp->next;
1259    ppp = ppp->next;
1260  } while (((p == root) && (pp != p->next)) || ((p != root) && (pp != p)));
1261  pp = p->next;
1262  do {
1263    improvtrav(pp->back);
1264    pp = pp->next;
1265  }
1266  while (((p == root) && (pp != p->next)) || ((p != root) && (pp != p)));
1267}  /* improvtrav */
1268
1269
1270void force_1to1(node *pFromSubNode, node *pToSubNode, double *pForce,
1271                double *pAngle, double medianDistance)
1272{
1273/* calculate force acting between 2 nodes and return the force in pForce.
1274   Remember to pass the index subnodes to this function if needed.
1275   Force should always be positive for repelling.  Angle changes to
1276   indicate the direction of the force.  The value of INFINITY is the cap
1277   to the value of Force. 
1278   There might have problem (error msg.) if pFromSubNode and pToSubNode
1279   are the same node or the coordinates are identical even with double
1280   precision.  */
1281  double distanceX, distanceY, distance, norminalDistance;
1282  distanceX = pFromSubNode->xcoord - pToSubNode->xcoord;
1283  distanceY = pFromSubNode->ycoord - pToSubNode->ycoord;
1284  distance = sqrt( distanceX*distanceX + distanceY*distanceY );
1285  norminalDistance = distance/medianDistance;
1286
1287  if (norminalDistance < epsilon)
1288  {
1289    *pForce = INFINITY;
1290  }
1291  else
1292  {
1293
1294    *pForce = (double)1 / (norminalDistance * norminalDistance);
1295
1296    if (*pForce > INFINITY) *pForce = INFINITY;
1297  }
1298 
1299  *pAngle = computeAngle(pFromSubNode->xcoord, pFromSubNode->ycoord,
1300                        pToSubNode->xcoord, pToSubNode->ycoord);
1301
1302  return;
1303}  /* force_1to1 */
1304
1305
1306void totalForceOnNode(node *pPivotSubNode, node *pToSubNode,
1307                double *pTotalForce, double *pAngle, double medianDistance)
1308{
1309/* pToSubNode is where all the relevent nodes apply forces to.
1310   All branches are visited except the branch contains pToSubNode.
1311   pToSubNode must be one of the branch out of the current Node (= out of one
1312   of the subnode in the current subnodes set.)
1313   Most likely pPivotSubNode is not the index subNode!  In any case, only
1314   the leafs are consider in repelling force; so, no worry about index subNode.
1315   pTotalForce and pAngle must be set to 0 before calling this function for the
1316   first time, or the result will be invalid.
1317   pPivotSubNode is named for external interface.  When calling totalForceOnNode()
1318   recursively, pPivotSubNode should be thought of as pFromSubNode.
1319 */
1320  node *pSubNode;
1321  double force, angle, forceX, forceY, prevForceX, prevForceY;
1322
1323  pSubNode = pPivotSubNode;
1324
1325  /* visit the rest of the branches of current node; the branch attaches to
1326     the current subNode may be visited in the code down below. */
1327  while (pSubNode->next != NULL && pSubNode->next != pPivotSubNode)
1328  {
1329    pSubNode = pSubNode->next;
1330    if ( pSubNode->back != NULL && pSubNode->back != pToSubNode) 
1331      totalForceOnNode(pSubNode->back, pToSubNode, pTotalForce, pAngle, medianDistance);
1332  }
1333
1334  /* visit this branch; You need to visit it for the first time - at root only! */
1335  /* Modified so that all nodes are visited and calculated forces, instead of just
1336     the leafs only. */
1337  /* use pPivotSubNode instead of pSubNode here because pSubNode stop short
1338     just before pPivotSubNode (the entry node) */
1339  if ( pPivotSubNode == root && pPivotSubNode->back != NULL 
1340       && pPivotSubNode->back != pToSubNode) 
1341    totalForceOnNode(pPivotSubNode->back, pToSubNode, pTotalForce, pAngle, medianDistance);
1342
1343  /* Break down the previous sum of forces to components form */
1344  prevForceX = *pTotalForce * cos(*pAngle);
1345  prevForceY = *pTotalForce * sin(*pAngle);
1346 
1347  force_1to1(nodep[pPivotSubNode->index-1], pToSubNode, &force, &angle, medianDistance);
1348  /* force between 2 nodes */
1349  forceX = force * cos(angle);
1350  forceY = force * sin(angle);
1351
1352  /* Combined force */
1353  forceX = forceX + prevForceX;
1354  forceY = forceY + prevForceY;
1355
1356  /* Write to output parameters */
1357  *pTotalForce = sqrt( forceX*forceX + forceY*forceY );
1358 
1359  *pAngle = computeAngle((double)0, (double)0, forceX, forceY);
1360
1361  return;
1362}  /* totalForceOnNode */
1363
1364
1365double dotProduct(double Xu, double Yu, double Xv, double Yv)
1366{
1367  return Xu * Xv + Yu * Yv;
1368}  /* dotProduct */
1369
1370
1371double capedAngle(double angle)
1372{
1373/* Return the equivalent value of angle that is within
1374   0 to 2*pie */
1375  while (angle < 0 || angle >= 2*pie)
1376  {
1377    if(angle < 0)
1378    {
1379      angle = angle + 2*pie;
1380    }
1381    else if (angle >= 2*pie)
1382    {
1383      angle = angle - 2*pie;
1384    }
1385  }
1386  return angle;
1387}  /* capedAngle */
1388
1389
1390double angleBetVectors(double Xu, double Yu, double Xv, double Yv)
1391{
1392/* Calculate angle between 2 vectors; use capedAngle() if needed to get
1393   the equivalent angle in positive value. - I guess it is never necessary.
1394   Use vCounterClkwiseU() to get the relative position of the vectors.
1395*/ 
1396  double dotProd, cosTheta, theta, lengthsProd;
1397/*double angleU, angleV, angleUToV;*/
1398
1399  dotProd = dotProduct(Xu, Yu, Xv, Yv);
1400  lengthsProd = sqrt(Xu*Xu+Yu*Yu) * sqrt(Xv*Xv+Yv*Yv);
1401
1402  if (lengthsProd < epsilon)
1403  {
1404    printf("ERROR: drawtree - division by zero in angleBetVectors()!\n");
1405    printf("Xu %f Yu %f Xv %f Yv %f\n", Xu, Yu, Xv, Yv);
1406    exxit(0);
1407  }
1408  cosTheta = dotProd / lengthsProd;
1409
1410  if (cosTheta > 1 || cosTheta < -1)
1411  {
1412    printf("ERROR: drawtree - acos of an invalid value in angleBetVectors()!\n");
1413    exxit(0);
1414  }
1415  theta = acos(cosTheta);
1416
1417  if (theta < 0)
1418  {
1419    printf("ERROR: theta not supposed to be negative in angleBetVectors()!\n");
1420    printf("theta = %f\n", theta);
1421    exxit(1);
1422  }
1423  return theta;
1424}  /* angleBetVectors */
1425
1426
1427double signOfMoment(double xReferenceVector, double yReferenceVector,
1428                double xForce, double yForce)
1429{
1430/* it return the sign of the moment caused by the force, applied
1431   to the tip of the refereceVector; the root of the refereceVector
1432   is the pivot. */
1433  double angleReference, angleForce, sign;
1434
1435  angleReference = computeAngle((double)0, (double)0, xReferenceVector, 
1436                                yReferenceVector);
1437  angleForce = computeAngle((double)0, (double)0, xForce, yForce);
1438  angleForce = capedAngle(angleForce);
1439  angleReference = capedAngle(angleReference);
1440
1441  /* reduce angleReference to 0 */
1442  angleForce = angleForce - angleReference;
1443  angleForce = capedAngle(angleForce);
1444  angleReference = 0;
1445
1446  if (angleForce > 0 && angleForce < pie)
1447  {
1448    /* positive sign - force pointing toward the left of the reference
1449       line/vector.  */
1450    sign = 1;
1451  }
1452  else
1453  {
1454    /* negative sign */
1455    sign = -1;
1456  }
1457  return sign;
1458}  /* signOfMoment */
1459
1460
1461double vCounterClkwiseU(double Xu, double Yu, double Xv, double Yv)
1462{
1463/* Return 1 if vector v is counter clockwise from u */
1464  /* signOfMoment() is doing just that! */
1465  return signOfMoment(Xu, Yu, Xv, Yv);
1466}  /* vCounterClkwiseU */
1467
1468
1469double forcePerpendicularOnNode(node *pPivotSubNode, node *pToSubNode,
1470                double medianDistance)
1471{
1472/* Read comment for totalForceOnNode */
1473/* It supposed to return a positive value to indicate that it has a positive
1474   moment; and negative return value to indicate negative moment.
1475   force perpendicular at norminal distance 1 is taken to be 1. 
1476   medianDistance is the median of Distances in this graph.  */
1477/*
1478                        / Force
1479                       / 
1480          |  ToNode   o  > alpha
1481          |              \ 
1482   yDelta |               \     theta = pie/2 + alpha
1483          |                  beta = vector (or angle) from Pivot to ToNode
1484  Pivot   o-----------
1485             xDelta
1486
1487  alpha = theta + beta
1488 */
1489  double totalForce, forceAngle, xDelta, yDelta, beta;
1490  double alpha, theta, forcePerpendicular, sinForceAngle, cosForceAngle;
1491
1492  totalForce = (double)0;
1493  forceAngle = (double)0;
1494
1495  totalForceOnNode(pPivotSubNode, pToSubNode, &totalForce, &forceAngle, medianDistance);
1496
1497  xDelta = nodep[pToSubNode->index-1]->xcoord - nodep[pPivotSubNode->index-1]->xcoord;
1498  yDelta = nodep[pToSubNode->index-1]->ycoord - nodep[pPivotSubNode->index-1]->ycoord;
1499
1500  /* Try to avoid the case where 2 nodes are on top of each other. */
1501  /*
1502  if (xDelta < 0) tempx = -xDelta;
1503  else tempx = xDelta;
1504  if (yDelta < 0) tempy = -yDelta;
1505  else tempy = yDelta;
1506  if (tempx < epsilon && tempy < epsilon)
1507  {
1508    return;
1509  }
1510  */
1511
1512  sinForceAngle = sin(forceAngle);
1513  cosForceAngle = cos(forceAngle);
1514  beta = computeAngle((double)0, (double)0, yDelta, -xDelta);
1515  theta = angleBetVectors(xDelta, yDelta, cosForceAngle, sinForceAngle);
1516
1517  if (theta > pie/2)
1518  {
1519    alpha = theta - pie/2;
1520  }
1521  else
1522  {
1523    alpha = pie/2 - theta;
1524  }
1525
1526  forcePerpendicular = totalForce * cos(alpha);
1527
1528  if (forcePerpendicular < -epsilon)
1529  {
1530    printf("ERROR: drawtree - forcePerpendicular applied at an angle should not be less than zero (in forcePerpendicularOnNode()). \n");
1531    printf("alpha = %f\n", alpha);
1532    exxit(1);
1533  }
1534  /* correct the sign of the moment */
1535  forcePerpendicular = signOfMoment(xDelta, yDelta, cosForceAngle, sinForceAngle) 
1536    * forcePerpendicular;
1537  return forcePerpendicular;
1538}  /* forcePerpendicularOnNode */
1539
1540
1541void polarizeABranch(node *pStartingSubNode, double *xx, double *yy)
1542{
1543/* added - danieyek 990128 */
1544/* After calling tilttrav(), if you don't polarize all the nodes on the branch
1545   to convert the x-y coordinates to theta and radius, you won't get result on
1546   the plot!  This function takes a subnode and branch out of all other subnode
1547   except the starting subnode (where the parent is), thus converting the x-y
1548   to polar coordinates for the branch only.  xx and yy are purely "inherited"
1549   features of polarize().  They should have been passed as values not addresses. */
1550  node *pSubNode;
1551
1552  pSubNode = pStartingSubNode;
1553
1554  /* convert the current node (note: not subnode) to polar coordinates. */
1555  polarize( nodep[pStartingSubNode->index - 1], xx, yy);
1556
1557  /* visit the rest of the branches of current node */
1558  while (pSubNode->next != NULL && pSubNode->next != pStartingSubNode)
1559  {
1560    pSubNode = pSubNode->next;
1561    if ( pSubNode->tip != true )
1562      polarizeABranch(pSubNode->back, xx, yy);
1563  }
1564  return;
1565}  /* polarizeABranch */
1566
1567
1568void pushNodeToStack(stackElemType **ppStackTop, node *pNode)
1569{
1570/* added - danieyek 990204 */
1571/* pStackTop must be the current top element of the stack, where we add another
1572   element on top of it. 
1573   ppStackTop must be the location where we can find pStackTop.
1574   This function "returns" the revised top (element) of the stack through
1575   the output parameter, ppStackTop.
1576   The last element on the stack has the "back" (pStackElemBack) pointer
1577   set to NULL.  So, when the last element is poped, ppStackTop will be
1578   automatically set to NULL.  If popNodeFromStack() is called with
1579   ppStackTop = NULL, we assume that it is the error caused by over popping
1580   the stack.
1581*/
1582  stackElemType *pStackElem;
1583
1584  if (ppStackTop == NULL)
1585  {
1586    /* NULL can be stored in the location, but the location itself can't
1587       be NULL! */
1588    printf("ERROR: drawtree - error using pushNodeToStack(); ppStackTop is NULL.\n");
1589    exxit(1);
1590  }
1591  pStackElem = (stackElemType*)Malloc( sizeof(stackElemType) );
1592  pStackElem->pStackElemBack = *ppStackTop;
1593  /* push an element onto the stack */
1594  pStackElem->pNode = pNode;
1595  *ppStackTop = pStackElem;
1596  return;
1597}  /* pushNodeToStack */
1598
1599
1600void popNodeFromStack(stackElemType **ppStackTop, node **ppNode)
1601{
1602/* added - danieyek 990205 */
1603/* pStackTop must be the current top element of the stack, where we pop an
1604   element from the top of it. 
1605   ppStackTop must be the location where we can find pStackTop.
1606   This function "returns" the revised top (element) of the stack through
1607   the output parameter, ppStackTop.
1608   The last element on the stack has the "back" (pStackElemBack) pointer
1609   set to NULL.  So, when the last element is poped, ppStackTop will be
1610   automatically set to NULL.  If popNodeFromStack() is called with
1611   ppStackTop = NULL, we assume that it is the error caused by over popping
1612   the stack.
1613*/
1614  stackElemType *pStackT;
1615
1616  if (ppStackTop == NULL)
1617  {
1618    printf("ERROR: drawtree - a call to pop while the stack is empty.\n");
1619    exxit(1);
1620  }
1621
1622  pStackT = *ppStackTop;
1623  *ppStackTop = pStackT->pStackElemBack;
1624  *ppNode  = pStackT->pNode;
1625  free(pStackT);
1626
1627  return;
1628}  /* popNodeFromStack */
1629
1630
1631double medianOfDistance(node *pRootSubNode, boolean firstRecursiveCallP)
1632{
1633/* added - danieyek 990208 */
1634/* Find the median of the distance; used to compute the angle to rotate
1635   in proportion to the size of the graph and forces.
1636   It is assumed that pRootSubNode is also the pivot (during the first
1637   call to this function) - the center, with
1638   respect to which node the distances are calculated.
1639   If there are only 3 element, element #2 is returned, ie. (2+1)/2.
1640   This function now finds the median of distances of all nodes, not only
1641   the leafs!
1642*/
1643  node *pSubNode;
1644  double xDelta, yDelta, distance;
1645  long i, j;
1646  struct dblLinkNode
1647  {
1648    double value;
1649    /* Implement reverse Linked List */
1650    struct dblLinkNode *pBack;
1651  } *pLink, *pBackElem, *pMidElem, *pFrontElem, junkLink;
1652  /* must use static to retain values over calls */
1653  static node *pReferenceNode;
1654  static long count;
1655  static struct dblLinkNode *pFrontOfLinkedList;
1656
1657  /* Remember the reference node so that it doesn't have to be passed
1658     arround in the function parameter. */
1659  if (firstRecursiveCallP == true)
1660  {
1661    pReferenceNode = pRootSubNode;
1662    pFrontOfLinkedList = NULL;
1663    count = 0;
1664  }
1665
1666  pSubNode = pRootSubNode;
1667  /* visit the rest of the branches of current node; the branch attaches to
1668     the current subNode may be visited in the code further down below. */
1669  while (pSubNode->next != NULL && pSubNode->next != pRootSubNode)
1670  {
1671    pSubNode = pSubNode->next;
1672    if ( pSubNode->back != NULL) 
1673      medianOfDistance(pSubNode->back, false);
1674  }
1675
1676  /* visit this branch; You need to visit it for the first time - at root only! */
1677  /* use pRootSubNode instead of pSubNode here because pSubNode stop short
1678     just before pRootSubNode (the entry node) */
1679  if ( firstRecursiveCallP == true && pRootSubNode->back != NULL)
1680    medianOfDistance(pRootSubNode->back, false);
1681
1682  /* Why only leafs count?  Modifying it!  */
1683  xDelta = nodep[pSubNode->index-1]->xcoord - nodep[pReferenceNode->index-1]->xcoord;
1684  yDelta = nodep[pSubNode->index-1]->ycoord - nodep[pReferenceNode->index-1]->ycoord;
1685  distance = sqrt( xDelta*xDelta + yDelta*yDelta );
1686 
1687  /* Similar to pushing onto the stack */
1688  pLink = (struct dblLinkNode*) Malloc( sizeof(struct dblLinkNode) );
1689  if (pLink == NULL)
1690  {
1691    printf("Fatal ERROR: drawtree - Insufficient Memory in medianOfDistance()!\n");
1692    exxit(1);
1693  }
1694  pLink->value = distance;
1695  pLink->pBack = pFrontOfLinkedList;
1696  pFrontOfLinkedList = pLink;
1697  count = count + 1;
1698
1699  if (firstRecursiveCallP == true) 
1700  {
1701    if (count == 0)
1702    {
1703      return (double)0;
1704    }
1705    else if (count == 1)
1706    {
1707      distance = pFrontOfLinkedList->value;
1708      free(pFrontOfLinkedList);
1709      return distance;
1710    }
1711    else if (count == 2)
1712    {
1713      distance = (pFrontOfLinkedList->value + pFrontOfLinkedList->pBack->value)/(double)2;
1714      free(pFrontOfLinkedList->pBack);
1715      free(pFrontOfLinkedList);
1716      return distance;
1717    }
1718    else
1719    {
1720      junkLink.pBack = pFrontOfLinkedList;
1721
1722      /* SORT first - use bubble sort; we start with at least 3 elements here. */
1723      /* We are matching backward when sorting the list and comparing MidElem and
1724         BackElem along the path;  junkLink is there just to make a symmetric
1725         operation at the front end. */
1726      for (j = 0; j < count - 1; j++)
1727      {
1728            pFrontElem = &junkLink;
1729            pMidElem = junkLink.pBack;
1730            pBackElem = junkLink.pBack->pBack;
1731        for (i = j; i < count - 1; i++)
1732        {
1733          if(pMidElem->value < pBackElem->value)
1734          {
1735            /* Swap - carry the smaller value to the root of the linked list. */
1736            pMidElem->pBack = pBackElem->pBack;
1737            pBackElem->pBack = pMidElem;
1738            pFrontElem->pBack = pBackElem;
1739            /* Correct the order of pFrontElem, pMidElem, pBackElem and match
1740               one step */
1741            pFrontElem = pBackElem;
1742            pBackElem = pMidElem->pBack;
1743          }
1744          else
1745          {
1746            pFrontElem = pMidElem;
1747            pMidElem = pBackElem;
1748            pBackElem = pBackElem->pBack;
1749          }
1750        }
1751        pFrontOfLinkedList = junkLink.pBack;
1752      }
1753      /* Sorted; now get the middle element. */
1754      for (i = 1; i < (count + 1)/(long) 2; i++)
1755      {
1756        /* Similar to Poping the stack */
1757              pLink = pFrontOfLinkedList;
1758        pFrontOfLinkedList = pLink->pBack;
1759        free(pLink);
1760      }
1761
1762      /* Get the return value!! - only the last return value is the valid one. */
1763      distance = pFrontOfLinkedList->value;
1764
1765      /* Continue from the same i value left off by the previous for loop!  */
1766      for (; i <= count; i++)
1767      {
1768        /* Similar to Poping the stack */
1769              pLink = pFrontOfLinkedList;
1770        pFrontOfLinkedList = pLink->pBack;
1771        free(pLink);
1772      }
1773    }
1774  }
1775  return distance;
1776}  /* medianOfDistance */
1777
1778
1779void leftRightLimits(node *pToSubNode, double *pLeftLimit, 
1780                double *pRightLimit)
1781/* As usual, pToSubNode->back is the angle
1782   leftLimit is the max angle you can rotate on the left and
1783   rightLimit vice versa.
1784   *pLeftLimit and *pRightLimit must be initialized to 0; without
1785   initialization, it would introduce bitter bugs into the program;
1786   they are initialized in this routine.
1787*/
1788{
1789  /* pPivotNode is nodep[pToSubNode->back->index-1], not pPivotSubNode
1790     which is just pToSubNode->back! */
1791  node *pLeftSubNode, *pRightSubNode, *pPivotNode, *pSubNode;
1792  double leftLimit, rightLimit, xToNodeVector, yToNodeVector, xLeftVector, 
1793    yLeftVector, xRightVector, yRightVector, lengthsProd;
1794
1795  *pLeftLimit = 0;
1796  *pRightLimit = 0;
1797  /* Make an assumption first - guess "pToSubNode->back->next" is the right
1798     and the opposite direction is the left! */
1799  /* It shouldn't be pivoted at a left, but just checking. */
1800  if (pToSubNode->back->tip == true)
1801  {
1802    /* Logically this should not happen.  But we actually can return pi as the limit. */
1803    printf("ERROR: In leftRightLimits() - Pivoted at a leaf! Unable to calculate left and right limit.\n");
1804    exxit(1);
1805  }
1806  else if (pToSubNode->back->next->next == pToSubNode->back)
1807  {
1808    printf("ERROR: leftRightLimits() - 2-branches-only case not handled!!");
1809    exxit(1);
1810  }
1811  /* Else, do this */
1812  pPivotNode = nodep[pToSubNode->back->index-1];
1813
1814  /* 3 or more branches - the regular case. */
1815  /* First, initialize the pRightSubNode - non-repeative portion of the code */
1816  pRightSubNode = pToSubNode->back;
1817  pLeftSubNode = pToSubNode->back;
1818  xToNodeVector = nodep[pToSubNode->index-1]->xcoord - pPivotNode->xcoord;
1819  yToNodeVector = nodep[pToSubNode->index-1]->ycoord - pPivotNode->ycoord;
1820
1821  /* If both x and y are 0, then the length must be 0; but this check is not
1822     enough yet, we need to check the product of length also. */
1823  if ( fabs(xToNodeVector) < epsilon && fabs(yToNodeVector) < epsilon )
1824  {
1825    /* If the branch to rotate is too short, don't rotate it. */
1826    *pLeftLimit = 0;
1827    *pRightLimit = 0;
1828    return;
1829  }
1830
1831
1832  while( nodep[pRightSubNode->index-1]->tip != true )
1833  {
1834    /* Repeative code */
1835    pRightSubNode = pRightSubNode->next->back;
1836
1837    xRightVector = nodep[pRightSubNode->index-1]->xcoord - pPivotNode->xcoord;
1838    yRightVector = nodep[pRightSubNode->index-1]->ycoord - pPivotNode->ycoord;
1839
1840    lengthsProd = sqrt(xToNodeVector*xToNodeVector+yToNodeVector*yToNodeVector) 
1841      * sqrt(xRightVector*xRightVector+yRightVector*yRightVector);
1842    if ( lengthsProd < epsilon )
1843    {
1844      continue;
1845    }
1846    rightLimit = angleBetVectors(xToNodeVector, yToNodeVector, xRightVector, yRightVector);
1847
1848    if ( (*pRightLimit) < rightLimit) *pRightLimit = rightLimit;
1849  }
1850
1851  while( nodep[pLeftSubNode->index-1]->tip != true )
1852  {
1853    /* First, let pSubNode be 1 subnode after rightSubNode. */
1854    pSubNode = pLeftSubNode->next->next;
1855    /* Then, loop until the last subNode before getting back to the pivot */
1856    while (pSubNode->next != pLeftSubNode)
1857    {
1858      pSubNode = pSubNode->next;
1859    }
1860    pLeftSubNode = pSubNode->back;
1861   
1862    xLeftVector = nodep[pLeftSubNode->index-1]->xcoord - pPivotNode->xcoord;
1863    yLeftVector = nodep[pLeftSubNode->index-1]->ycoord - pPivotNode->ycoord;
1864
1865    lengthsProd = sqrt(xToNodeVector*xToNodeVector+yToNodeVector*yToNodeVector) 
1866      * sqrt(xLeftVector*xLeftVector+yLeftVector*yLeftVector);
1867    if ( lengthsProd < epsilon )
1868    {
1869      continue;
1870    }
1871    leftLimit = angleBetVectors(xToNodeVector, yToNodeVector, xLeftVector, yLeftVector);
1872
1873    if ( (*pLeftLimit) < leftLimit) *pLeftLimit = leftLimit;
1874  }
1875  return;
1876}  /* leftRightLimits */
1877
1878
1879void branchLRHelper(node *pPivotSubNode, node *pCurSubNode,
1880                double *pBranchL, double *pBranchR)
1881{
1882/* added - danieyek 990226 */
1883/* Recursive helper function for branchLeftRightAngles().
1884   pPivotSubNode->back is the pToNode, to which node you apply the forces!
1885*/
1886/* Abandoned as it is similar to day-light algorithm; the first part is
1887   done implementing but not tested, the second part yet to be
1888   implemented if necessary. */
1889  double xCurNodeVector, yCurNodeVector, xPivotVector, yPivotVector;
1890
1891  /* Base case : a leaf - return 0 & 0.  */
1892  if ( nodep[pCurSubNode->index-1]->tip == true )
1893  {
1894    xPivotVector = nodep[pPivotSubNode->back->index-1]->xcoord
1895      - nodep[pPivotSubNode->index-1]->xcoord;
1896    yPivotVector = nodep[pPivotSubNode->back->index-1]->ycoord
1897      - nodep[pPivotSubNode->index-1]->ycoord;
1898    xCurNodeVector = nodep[pCurSubNode->index-1]->xcoord
1899      - nodep[pPivotSubNode->index-1]->xcoord;
1900    yCurNodeVector = nodep[pCurSubNode->index-1]->ycoord
1901      - nodep[pPivotSubNode->index-1]->ycoord;
1902
1903    if ( vCounterClkwiseU(xPivotVector, yPivotVector, xCurNodeVector, yCurNodeVector) 
1904         == 1)
1905    {
1906      /* Relevant to Left Angle */
1907      *pBranchL = angleBetVectors(xPivotVector, yPivotVector, 
1908                                  xCurNodeVector, yCurNodeVector);
1909      *pBranchR = (double)0;
1910    }
1911    else
1912    {
1913      /* Relevant to Right Angle */
1914      *pBranchR = angleBetVectors(xPivotVector, yPivotVector,
1915                                  xCurNodeVector, yCurNodeVector);
1916      *pBranchL = (double)0;
1917    }
1918    return;
1919  }
1920  else
1921  {
1922    /* not a leaf */
1923  }
1924} /* branchLRHelper */
1925
1926
1927void improveNodeAngle(node *pToNode, double medianDistance)
1928{
1929/* added - danieyek 990204 */
1930/* Assume calling pToNode->back will bring me to the Pivot!  */
1931  double forcePerpendicular, distance, 
1932    xDistance, yDistance, angleRotate, sinAngleRotate, cosAngleRotate, 
1933    norminalDistance, leftLimit, rightLimit, limitFactor;
1934  node *pPivot;
1935
1936  /* Limit factor determinte how close the rotation can approach the
1937     absolute limit before colliding with other branches */
1938  limitFactor = (double)4 / (double)5;
1939  pPivot = pToNode->back;
1940
1941  xDistance = nodep[pPivot->index-1]->xcoord - nodep[pToNode->index-1]->xcoord;
1942  yDistance = nodep[pPivot->index-1]->ycoord - nodep[pToNode->index-1]->ycoord;
1943  distance = sqrt( xDistance*xDistance + yDistance*yDistance  );
1944
1945  /* convert distance to absolute value and test if it is zero */
1946  if ( fabs(distance) < epsilon) 
1947  {
1948    forcePerpendicular = (double)0;
1949    angleRotate = (double)0;
1950  }
1951  else 
1952  {
1953    leftRightLimits(pToNode, &leftLimit, &rightLimit);
1954    norminalDistance = distance / medianDistance;
1955    forcePerpendicular = forcePerpendicularOnNode(pPivot, pToNode, medianDistance);
1956    angleRotate = forcePerpendicular / norminalDistance;
1957    /* Limiting the angle of rotation */
1958    if ( angleRotate > 0 && angleRotate > limitFactor * leftLimit)
1959    {
1960      /* Left */
1961      angleRotate = limitFactor * leftLimit;
1962    }
1963    else if ( -angleRotate > limitFactor * rightLimit )
1964    /* angleRotate < 0 && */ 
1965    {
1966      /* Right */
1967      angleRotate = - limitFactor * rightLimit;
1968    }
1969  }
1970  angleRotate = (double).1 * angleRotate;
1971
1972  sinAngleRotate = sin(angleRotate);
1973  cosAngleRotate = cos(angleRotate);
1974
1975  tilttrav(pToNode, 
1976           &(nodep[pPivot->index - 1]->xcoord), 
1977           &(nodep[pPivot->index - 1]->ycoord), 
1978           &sinAngleRotate, &cosAngleRotate);
1979
1980  polarizeABranch(pToNode,
1981           &(nodep[pPivot->index - 1]->xcoord),
1982           &(nodep[pPivot->index - 1]->ycoord));
1983}  /* improveNodeAngle */
1984
1985
1986void improvtravn(node *pStartingSubNode)
1987{
1988/* function modified - danieyek 990125 */
1989/* improvtrav for n-body. */
1990/* POPStack is the stack that is currently being used (popped);
1991   PUSHStack is the stack that is for the use of the next round
1992   (is pushed now) */
1993  stackElemType *pPUSHStackTop, *pPOPStackTop, *pTempStack;
1994  node *pSubNode, *pBackStartNode, *pBackSubNode;
1995  double sinphi, cosphi, phi, medianDistance;
1996  long noOfIteration;
1997
1998  /* Stack starts with no element on it */
1999  pPUSHStackTop = NULL;
2000  pPOPStackTop = NULL;
2001
2002phi = (double)1.0;
2003sinphi = sin(phi);
2004cosphi = cos(phi);
2005
2006  /* Get the median to relate force to angle proportionally. */
2007  medianDistance = medianOfDistance(root, true);
2008
2009  /* Set max. number of iteration */
2010  noOfIteration = (long)0;
2011  while( noOfIteration++ < maxNumOfIter)
2012  {
2013
2014    /* First, push all subNodes in the root node onto the stack-to-be-used to kick up
2015       the process */
2016    pSubNode = pStartingSubNode;
2017    pushNodeToStack(&pPUSHStackTop, pSubNode);
2018    while(pSubNode->next != pStartingSubNode)
2019    {
2020      pSubNode = pSubNode->next;
2021      pushNodeToStack(&pPUSHStackTop, pSubNode);
2022    } 
2023 
2024    while (true)
2025    {
2026      /* Finishes with the current POPStack; swap the function of the stacks if
2027               PUSHStack is not empty */
2028      if (pPUSHStackTop == NULL)
2029      {
2030              /* Exit infinity loop here if empty. */
2031              break;
2032      }
2033      else
2034      {
2035              /* swap */
2036              pTempStack = pPUSHStackTop;
2037              pPUSHStackTop = pPOPStackTop;
2038              pPOPStackTop = pTempStack;
2039      }
2040     
2041      while (pPOPStackTop != NULL)
2042      {
2043              /* We always push the pivot subNode onto the stack!  That's when we
2044                 pop that pivot subNode, subNode.back is the node we apply the force
2045                 to (ToNode). Also, when we pop a pivot subNode, always push all
2046                 pivot subNodes in the same ToNode onto the stack. */
2047              popNodeFromStack(&pPOPStackTop, &pSubNode);
2048     
2049              pBackStartNode = pSubNode->back;
2050              if (pBackStartNode->tip == true)
2051              {
2052                /* tip indicates if a node is a leaf */
2053                improveNodeAngle(pSubNode->back, medianDistance);
2054     
2055              }
2056              else
2057              {
2058                /* Push all subNodes in this pSubNode->back onto the stack-to-be-used,
2059                   after poping a pivot subNode. If pSubNode->back is a leaf, no
2060                   push on stack. */ 
2061                pBackSubNode = pBackStartNode;
2062                /* Do not push this pBackStartNode onto the stack!  Or the process will never
2063                   stop. */
2064                while(pBackSubNode->next != pBackStartNode)
2065                {
2066                  pBackSubNode = pBackSubNode->next;
2067                  pushNodeToStack(&pPOPStackTop, pBackSubNode);
2068                } 
2069                /* improve the node even if it is not a leaf */
2070                improveNodeAngle(pSubNode->back, medianDistance);
2071              }
2072      }
2073    }
2074  }
2075} /* improvtravn */
2076
2077
2078void coordimprov(double *xx, double *yy)
2079{
2080  /* use angles calculation to improve node coordinate placement */
2081  long i, its;
2082
2083  if (nbody) {      /* n-body algorithm */
2084
2085    /* modified - danieyek 990125 */
2086    /*
2087    its = 5; 
2088    */
2089    its = 1;
2090
2091    /* modified - danieyek 990125 */
2092    /* why its = 5 ??  - to be modified as equal-daylight below -
2093       introduce a condition to stop */
2094    /*
2095    for (i=1; i++; i<=its)
2096      improvtravn(root);
2097    */
2098
2099    for (i=1; i<=its; i++) improvtravn(root);
2100  } else {          /* equal-daylight algorithm */
2101    i = 0;
2102    do {
2103      maxchange = 0.0;
2104      improvtrav(root);
2105      i++;
2106    } while ((i < MAXITERATIONS) && (maxchange > MINIMUMCHANGE));
2107  }
2108}  /* coordimprov */
2109
2110
2111void calculate()
2112{
2113  /* compute coordinates for tree */
2114  double xx, yy;
2115  long i;
2116  double nttot, fontheight, labangle=0, top, bot, rig, lef;
2117
2118  for (i = 0; i < nextnode; i++)
2119    nodep[i]->width = 1.0;
2120  for (i = 0; i < nextnode; i++)
2121    nodep[i]->xcoord = 0.0;
2122  for (i = 0; i < nextnode; i++)
2123    nodep[i]->ycoord = 0.0;
2124  if (!uselengths) {
2125    for (i = 0; i < nextnode; i++)
2126      nodep[i]->length = 1.0;
2127  } else {
2128    for (i = 0; i < nextnode; i++)
2129      nodep[i]->length = fabs(nodep[i]->oldlen);
2130  }
2131  getwidth(root);
2132  nttot = root->width;
2133  for (i = 0; i < nextnode; i++)
2134    nodep[i]->width = nodep[i]->width * spp / nttot;
2135  plrtrans(root, treeangle, treeangle - ark / 2.0, treeangle + ark / 2.0);
2136  maxx = 0.0;
2137  minx = 0.0;
2138  maxy = 0.0;
2139  miny = 0.0;
2140  coordtrav(root, &xx,&yy);
2141  fontheight = heighttext(font,fontname);
2142  if (labeldirec == fixed)
2143    labangle = pi * labelrotation / 180.0;
2144  for (i = 0; i < nextnode; i++) {
2145    if (nodep[i]->tip) {
2146      textlength[i] = lengthtext(nodep[i]->nayme, nodep[i]->naymlength,
2147                                          fontname,font);
2148      textlength[i] /= fontheight;
2149      firstlet[i] = lengthtext(nodep[i]->nayme,1L,fontname,font)
2150                      / fontheight;
2151    }
2152  }
2153  if (spp > 1)
2154    labelheight = charht * (maxx - minx) / (spp - 1);
2155  else
2156    labelheight = charht * (maxx - minx);
2157  if (improve) {
2158    coordimprov(&xx,&yy);
2159    maxx = 0.0;
2160    minx = 0.0;
2161    maxy = 0.0;
2162    miny = 0.0;
2163    coordtrav(root, &xx,&yy);
2164  }
2165  topoflabels = 0.0;
2166  bottomoflabels = 0.0;
2167  rightoflabels = 0.0;
2168  leftoflabels = 0.0;
2169  for (i = 0; i < nextnode; i++) {
2170    if (nodep[i]->tip) {
2171      if (labeldirec == radial)
2172        labangle = nodep[i]->theta;
2173      else if (labeldirec == along)
2174        labangle = nodep[i]->oldtheta;
2175      else if (labeldirec == middle)
2176        labangle = 0.0;
2177      if (cos(labangle) < 0.0 && labeldirec != fixed)
2178        labangle -= pi;
2179      firstlet[i] = lengthtext(nodep[i]->nayme,1L,fontname,font)
2180                     / fontheight;
2181      top = (nodep[i]->ycoord - maxy) / labelheight + sin(nodep[i]->oldtheta);
2182      rig = (nodep[i]->xcoord - maxx) / labelheight + cos(nodep[i]->oldtheta);
2183      bot = (miny - nodep[i]->ycoord) / labelheight - sin(nodep[i]->oldtheta);
2184      lef = (minx - nodep[i]->xcoord) / labelheight - cos(nodep[i]->oldtheta);
2185      if (cos(labangle) * cos(nodep[i]->oldtheta) +
2186          sin(labangle) * sin(nodep[i]->oldtheta) > 0.0) {
2187        if (sin(labangle) > 0.0)
2188          top += sin(labangle) * textlength[i];
2189        top += sin(labangle - 1.25 * pi) * GAP * firstlet[i];
2190        if (sin(labangle) < 0.0)
2191          bot -= sin(labangle) * textlength[i];
2192        bot -= sin(labangle - 0.75 * pi) * GAP * firstlet[i];
2193        if (sin(labangle) > 0.0)
2194          rig += cos(labangle - 0.75 * pi) * GAP * firstlet[i];
2195        else
2196          rig += cos(labangle - 1.25 * pi) * GAP * firstlet[i];
2197        rig += cos(labangle) * textlength[i];
2198        if (sin(labangle) > 0.0)
2199          lef -= cos(labangle - 1.25 * pi) * GAP * firstlet[i];
2200        else
2201          lef -= cos(labangle - 0.75 * pi) * GAP * firstlet[i];
2202      } else {
2203        if (sin(labangle) < 0.0)
2204          top -= sin(labangle) * textlength[i];
2205        top += sin(labangle + 0.25 * pi) * GAP * firstlet[i];
2206        if (sin(labangle) > 0.0)
2207          bot += sin(labangle) * textlength[i];
2208        bot -= sin(labangle - 0.25 * pi) * GAP * firstlet[i];
2209        if (sin(labangle) > 0.0)
2210          rig += cos(labangle - 0.25 * pi) * GAP * firstlet[i];
2211        else
2212          rig += cos(labangle + 0.25 * pi) * GAP * firstlet[i];
2213        if (sin(labangle) < 0.0)
2214          rig += cos(labangle) * textlength[i];
2215        if (sin(labangle) > 0.0)
2216          lef -= cos(labangle + 0.25 * pi) * GAP * firstlet[i];
2217        else
2218          lef -= cos(labangle - 0.25 * pi) * GAP * firstlet[i];
2219        lef += cos(labangle) * textlength[i];
2220      }
2221      if (top > topoflabels)
2222        topoflabels = top;
2223      if (bot > bottomoflabels)
2224        bottomoflabels = bot;
2225      if (rig > rightoflabels)
2226        rightoflabels = rig;
2227      if (lef > leftoflabels)
2228        leftoflabels = lef;
2229    }
2230  }
2231  topoflabels *= labelheight;
2232  bottomoflabels *= labelheight;
2233  leftoflabels *= labelheight;
2234  rightoflabels *= labelheight;
2235}  /* calculate */
2236
2237
2238void rescale()
2239{
2240  /* compute coordinates of tree for plot or preview device */
2241  long i;
2242  double treeheight, treewidth, extrax, extray, temp;
2243
2244  treeheight = maxy - miny + topoflabels + bottomoflabels;
2245  treewidth = maxx - minx + rightoflabels + leftoflabels;
2246  if (grows == vertical) {
2247    if (!rescaled)
2248      expand = bscale;
2249    else {
2250      expand = (xsize - 2 * xmargin) / treewidth;
2251      if ((ysize - 2 * ymargin) / treeheight < expand)
2252        expand = (ysize - 2 * ymargin) / treeheight;
2253    }
2254    extrax = (xsize - 2 * xmargin - treewidth * expand) / 2.0;
2255    extray = (ysize - 2 * ymargin - treeheight * expand) / 2.0;
2256  } else {
2257    if (!rescaled)
2258      expand = bscale;
2259    else {
2260      expand = (ysize - 2 * ymargin) / treewidth;
2261      if ((xsize - 2 * xmargin) / treeheight < expand)
2262        expand = (xsize - 2 * xmargin) / treeheight;
2263    }
2264    extrax = (xsize - 2 * xmargin - treeheight * expand) / 2.0;
2265    extray = (ysize - 2 * ymargin - treewidth * expand) / 2.0;
2266  }
2267  for (i = 0; i < (nextnode); i++) {
2268    nodep[i]->xcoord = expand * (nodep[i]->xcoord - minx + leftoflabels);
2269    nodep[i]->ycoord = expand * (nodep[i]->ycoord - miny + bottomoflabels);
2270    if (grows == horizontal) {
2271      temp = nodep[i]->ycoord;
2272      nodep[i]->ycoord = expand * treewidth - nodep[i]->xcoord;
2273      nodep[i]->xcoord = temp;
2274    }
2275    nodep[i]->xcoord += xmargin + extrax;
2276    nodep[i]->ycoord += ymargin + extray;
2277  }
2278}  /* rescale */
2279
2280
2281void plottree(node *p, node *q)
2282{
2283  /* plot part or all of tree on the plotting device */
2284  double x1, y1, x2, y2;
2285  node *pp;
2286
2287  x2 = xscale * (xoffset + p->xcoord);
2288  y2 = yscale * (yoffset + p->ycoord);
2289  if (p != root) {
2290    x1 = xscale * (xoffset + q->xcoord);
2291    y1 = yscale * (yoffset + q->ycoord);
2292    plot(penup, x1, y1);
2293    plot(pendown, x2, y2);
2294  }
2295  if (p->tip)
2296    return;
2297  pp = p->next;
2298  do {
2299    plottree(pp->back, p);
2300    pp = pp->next;
2301  } while (((p == root) && (pp != p->next)) || ((p != root) && (pp != p)));
2302}  /* plottree */
2303
2304
2305void plotlabels(char *fontname)
2306{
2307  long i;
2308  double compr, dx = 0, dy = 0, labangle, sino, coso, cosl, sinl,
2309         cosv, sinv, vec;
2310  boolean left, right;
2311  node *lp;
2312
2313  compr = xunitspercm / yunitspercm;
2314  if (penchange == yes)
2315    changepen(labelpen);
2316  for (i = 0; i < (nextnode); i++) {
2317    if (nodep[i]->tip) {
2318      lp = nodep[i];
2319      labangle = labelrotation * pi / 180.0;
2320      if (labeldirec == radial)
2321        labangle = nodep[i]->theta;
2322      else if (labeldirec == along)
2323        labangle = nodep[i]->oldtheta;
2324      else if (labeldirec == middle)
2325        labangle = 0.0;
2326      if (cos(labangle) < 0.0)
2327        labangle -= pi;
2328      sino = sin(nodep[i]->oldtheta);
2329      coso = cos(nodep[i]->oldtheta);
2330      cosl = cos(labangle);
2331      sinl = sin(labangle);
2332      right = ((coso*cosl+sino*sinl) > 0.0) || (labeldirec == middle);
2333      left = !right;
2334      vec = sqrt(1.0+firstlet[i]*firstlet[i]);
2335      cosv = firstlet[i]/vec;
2336      sinv = 1.0/vec;
2337      if (labeldirec == middle) {
2338          if ((textlength[i]+1.0)*fabs(tan(nodep[i]->oldtheta)) > 2.0) {
2339            dx = -0.5 * textlength[i] * labelheight * expand;
2340            if (sino > 0.0) {
2341              dy = 0.5 * labelheight * expand;
2342              if (fabs(nodep[i]->oldtheta - pi/2.0) > 1000.0)
2343                dx += labelheight * expand / (2.0*tan(nodep[i]->oldtheta));
2344            } else {
2345              dy = -1.5 * labelheight * expand;
2346              if (fabs(nodep[i]->oldtheta - pi/2.0) > 1000.0)
2347                dx += labelheight * expand / (2.0*tan(nodep[i]->oldtheta));
2348            }
2349          }
2350          else {
2351            if (coso > 0.0) {
2352              dx = 0.5 * labelheight * expand;
2353              dy = (-0.5 + (0.5*textlength[i]+0.5)*tan(nodep[i]->oldtheta))
2354                    * labelheight * expand;
2355            }
2356            else {
2357              dx = -(textlength[i]+0.5) * labelheight * expand;
2358              dy = (-0.5 - (0.5*textlength[i]+0.5)*tan(nodep[i]->oldtheta))
2359                    * labelheight * expand;
2360            }
2361          }
2362      } else {
2363        if (right) {
2364          dx = labelheight * expand * coso;
2365          dy = labelheight * expand * sino;
2366          dx += labelheight * expand * 0.5 * vec * (-cosl*cosv+sinl*sinv);
2367          dy += labelheight * expand * 0.5 * vec * (-sinl*cosv-cosl*sinv);
2368        } else {
2369          dx = labelheight * expand * coso;
2370          dy = labelheight * expand * sino;
2371          dx += labelheight * expand * 0.5 * vec * (cosl*cosv+sinl*sinv);
2372          dy += labelheight * expand * 0.5 * vec * (sinl*cosv-cosl*sinv);
2373          dx -= textlength[i] * labelheight * expand * cosl;
2374          dy -= textlength[i] * labelheight * expand * sinl;
2375        }
2376      }
2377      plottext(lp->nayme, lp->naymlength,
2378               labelheight * expand * xscale / compr, compr,
2379               xscale * (lp->xcoord + dx + xoffset),
2380               yscale * (lp->ycoord + dy + yoffset), -180 * labangle / pi,
2381               font,fontname);
2382    }
2383  }
2384  if (penchange == yes)
2385    changepen(treepen);
2386}  /* plotlabels */
2387
2388
2389void user_loop()
2390{
2391  /* loop to make preview window and decide what to do with it */
2392
2393  long loopcount;
2394  char input_char;
2395
2396  while (!canbeplotted) {
2397    loopcount = 0;
2398    do {
2399      input_char=showparms();
2400      firstscreens = false;
2401      if ( input_char != 'Y')
2402        getparms(input_char);
2403      countup(&loopcount, 10);
2404    } while (input_char != 'Y');
2405    xscale = xunitspercm;
2406    yscale = yunitspercm;
2407    plotrparms(spp);
2408    numlines = dotmatrix
2409      ? ((long)floor(yunitspercm * ysize + 0.5) / strpdeep):1;
2410    calculate();
2411    rescale();
2412    canbeplotted = true;
2413    if (preview)
2414      canbeplotted=plotpreview(fontname,&xoffset,&yoffset,&scale,spp,root);
2415    else
2416      canbeplotted=plot_without_preview(fontname,&xoffset,&yoffset,
2417                                        &scale,spp,root);
2418     if ((previewer == winpreview || previewer == xpreview || previewer == mac) && (winaction == quitnow))
2419      canbeplotted = true;
2420 }
2421} /* user_loop */
2422
2423
2424void setup_environment(int argc, Char *argv[])
2425{
2426  /* Set up all kinds of fun stuff */
2427  node *q, *r;
2428
2429  char *pChar;
2430  double i;
2431  boolean firsttree;
2432  pointarray treenode = NULL;
2433
2434
2435#ifdef MAC
2436  OSErr retcode;
2437  FInfo  fndrinfo;
2438  macsetup("Drawtree","Preview");
2439#endif
2440#ifdef TURBOC
2441  if ((registerbgidriver(EGAVGA_driver) <0) ||
2442      (registerbgidriver(Herc_driver) <0)   ||
2443      (registerbgidriver(CGA_driver) <0)){
2444    fprintf(stderr,"Graphics error: %s ",grapherrormsg(graphresult()));
2445    exxit(-1);}
2446#endif
2447
2448
2449  printf("DRAWTREE from PHYLIP version %s\n", VERSION);
2450  openfile(&plotfile,PLOTFILE,"plot file", "w",argv[0],pltfilename);
2451  openfile(&intree,INTREE,"input tree file", "r",argv[0],NULL);
2452  printf("Reading tree ... \n");
2453  firsttree = true;
2454  allocate_nodep(&nodep, &intree, &spp);
2455  treeread (intree, &root, treenode, &goteof, &firsttree,
2456            nodep, &nextnode, &haslengths,
2457            &grbg, initdrawtreenode);
2458  q = root;
2459  r = root;
2460  while (!(q->next == root))
2461    q = q->next;
2462  q->next = root->next;
2463  root = q;
2464  chuck(&grbg, r);
2465  nodep[spp] = q;
2466  where = root;
2467  rotate = true;
2468  printf("Tree has been read.\n");
2469  printf("Loading the font ... \n");
2470  loadfont(font,argv[0]);
2471  printf("Font loaded.\n");
2472  previewing = false;
2473  ansi = ANSICRT;
2474  ibmpc = IBMCRT;
2475  firstscreens = true;
2476  initialparms();
2477  canbeplotted = false;
2478  if (argc > 1)
2479  {
2480    pChar = argv[1];
2481    for (i = 0; i < strlen(pChar); i++)
2482    {
2483      if ( ! isdigit(*pChar) ) 
2484      {
2485            /* set to default if the 2nd. parameter is not a number */
2486            maxNumOfIter = 50;
2487            return;
2488      }
2489      else if ( isspace(*pChar) )
2490      {
2491            printf("ERROR: Number of iteration should not contain space!\n");
2492            exxit(1);
2493      }
2494    }
2495    sscanf(argv[1], "%li", &maxNumOfIter);
2496  }
2497  else
2498  {
2499    /* 2nd. argument is not entered; use default. */
2500    maxNumOfIter = 50;
2501  }
2502  return;
2503}  /* setup_environment */
2504
2505
2506int main(int argc, Char *argv[])
2507{
2508  long stripedepth;
2509#ifdef MAC
2510  char filename1[FNMLNGTH];
2511  OSErr retcode;
2512  FInfo  fndrinfo;
2513 
2514  SIOUXSetTitle("\pPHYLIP:  Drawtree");
2515  argv[0] = "Drawtree";
2516#endif
2517#ifdef X
2518  nargc=argc;
2519  nargv=argv;
2520#endif
2521  init(argc,argv);
2522 
2523  progname = argv[0];
2524  grbg =  NULL;
2525  setup_environment(argc, argv);
2526
2527  user_loop();
2528 
2529  if (dotmatrix) {
2530    stripedepth = allocstripe(stripe,(strpwide/8),
2531                              ((long)(yunitspercm * ysize)));
2532    strpdeep = stripedepth;
2533    strpdiv  = stripedepth;
2534  }
2535
2536  if (!((previewer == winpreview || previewer == xpreview || previewer == mac) && (winaction == quitnow))) {
2537    previewing = false;
2538    initplotter(spp,fontname);
2539    numlines = dotmatrix ? ((long)floor(yunitspercm * ysize + 0.5)/strpdeep):1;   
2540    if (plotter != ibm)
2541      printf("\nWriting plot file ...\n");
2542    drawit(fontname,&xoffset,&yoffset,numlines,root);
2543    finishplotter();
2544  }
2545
2546  FClose(intree);
2547  FClose(plotfile);
2548  printf("\nPlot written to file \"%s\"\n\n", pltfilename);
2549  printf("Done.\n\n");
2550#ifdef MAC
2551  if (plotter == pict){
2552    strcpy(filename1, pltfilename);
2553    retcode=GetFInfo(CtoPstr(filename1),0,&fndrinfo);
2554    fndrinfo.fdType='PICT';
2555    fndrinfo.fdCreator='MDRW';
2556    strcpy(filename1, pltfilename);
2557    retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);}
2558  if (plotter == lw){
2559    retcode=GetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);
2560    fndrinfo.fdType='TEXT';
2561    retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);}
2562#endif
2563#ifdef WIN32
2564  phyRestoreConsoleAttributes();
2565#endif
2566  exxit(0);
2567  return 1;
2568}
Note: See TracBrowser for help on using the repository browser.