source: trunk/GDE/PHYLIP/drawtree.c

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