| 1 | #include "drawgraphics.h" |
|---|
| 2 | |
|---|
| 3 | /* Version 3.52c. Copyright (c) 1986-1993 by Joseph Felsenstein and |
|---|
| 4 | Christopher A. Meacham. Additional code written by Hisashi Horino, |
|---|
| 5 | Sean Lamont, Andrew Keefe, and Akiko Fuseki. |
|---|
| 6 | Permission is granted to copy, distribute, |
|---|
| 7 | and modify this program provided that (1) this copyright message is |
|---|
| 8 | not removed and (2) no fee is charged for this program. */ |
|---|
| 9 | |
|---|
| 10 | #define maxnch 30 |
|---|
| 11 | #define point '.' |
|---|
| 12 | #define fontsize 3800 |
|---|
| 13 | #define pi 3.141592653 |
|---|
| 14 | #define epsilon 0.00001 |
|---|
| 15 | #define xstart 10 |
|---|
| 16 | #define ystart 35 |
|---|
| 17 | #define gap 0.5 |
|---|
| 18 | #define iterations 5 |
|---|
| 19 | |
|---|
| 20 | #ifdef MAC |
|---|
| 21 | #undef maxnodes |
|---|
| 22 | #define maxnodes 250 |
|---|
| 23 | #endif |
|---|
| 24 | |
|---|
| 25 | typedef enum { fixed, radial, along} labelorient; |
|---|
| 26 | FILE *treefile, *plotfile; |
|---|
| 27 | char pltfilename[100]; |
|---|
| 28 | long ntips, nextnode, strpwide, strpdeep, |
|---|
| 29 | strptop, strpbottom, payge, numlines; |
|---|
| 30 | double xmargin, ymargin, topoflabels, rightoflabels, leftoflabels, |
|---|
| 31 | bottomoflabels, ark, maxx, maxy, minx, miny, scale, xscale, |
|---|
| 32 | yscale, xoffset, yoffset, charht, xnow, ynow, xunitspercm, |
|---|
| 33 | yunitspercm, xsize, ysize, xcorner, ycorner,labelheight, |
|---|
| 34 | labelrotation, treeangle, expand, bscale,enthusiasm; |
|---|
| 35 | boolean canbeplotted, preview, previewing, dotmatrix,haslengths, |
|---|
| 36 | uselengths, regular, didreroot, rotate, empty, rescaled, |
|---|
| 37 | notfirst, improve; |
|---|
| 38 | double textlength[maxnodes], firstlet[maxnodes]; |
|---|
| 39 | striptype stripe; |
|---|
| 40 | plottertype plotter, oldplotter, previewer; |
|---|
| 41 | growth grows; |
|---|
| 42 | labelorient labeldirec; |
|---|
| 43 | node *root, *where; |
|---|
| 44 | node *nodep[maxnodes]; |
|---|
| 45 | fonttype font; |
|---|
| 46 | enum { yes, no } penchange, oldpenchange; |
|---|
| 47 | char ch; |
|---|
| 48 | char fontname[64]; |
|---|
| 49 | long filesize; |
|---|
| 50 | long strpdiv; |
|---|
| 51 | |
|---|
| 52 | openfile(fp,filename,mode,application,perm) |
|---|
| 53 | FILE **fp; |
|---|
| 54 | char *filename; |
|---|
| 55 | char *mode; |
|---|
| 56 | char *application; |
|---|
| 57 | char *perm; |
|---|
| 58 | { |
|---|
| 59 | FILE *of; |
|---|
| 60 | char file[100]; |
|---|
| 61 | strcpy(file,filename); |
|---|
| 62 | while (1){ |
|---|
| 63 | of = fopen(file,mode); |
|---|
| 64 | if (of) |
|---|
| 65 | break; |
|---|
| 66 | else { |
|---|
| 67 | switch (*mode){ |
|---|
| 68 | case 'r': |
|---|
| 69 | printf("%s: can't read %s\n",application,file); |
|---|
| 70 | file[0]='\0'; |
|---|
| 71 | while (file[0] =='\0'){ |
|---|
| 72 | printf("Please enter a new filename>"); |
|---|
| 73 | gets(file);} |
|---|
| 74 | break; |
|---|
| 75 | case 'w': |
|---|
| 76 | printf("%s: can't write %s\n",application,file); |
|---|
| 77 | file[0] = '\0'; |
|---|
| 78 | while (file[0] =='\0'){ |
|---|
| 79 | printf("Please enter a new filename>"); |
|---|
| 80 | gets(file);} |
|---|
| 81 | break; |
|---|
| 82 | } |
|---|
| 83 | } |
|---|
| 84 | } |
|---|
| 85 | *fp=of; |
|---|
| 86 | if (perm != NULL) |
|---|
| 87 | strcpy(perm,file); |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | void uppercase(ch) |
|---|
| 91 | Char *ch; |
|---|
| 92 | { |
|---|
| 93 | /* make ch upper-case */ |
|---|
| 94 | *ch = (islower(*ch) ? toupper(*ch) : (*ch)); |
|---|
| 95 | } /* uppercase */ |
|---|
| 96 | |
|---|
| 97 | /* Local variables for treeread: */ |
|---|
| 98 | |
|---|
| 99 | void getch(c) |
|---|
| 100 | Char *c; |
|---|
| 101 | { |
|---|
| 102 | /* get next nonblank character */ |
|---|
| 103 | do {*c = getc(treefile); |
|---|
| 104 | } while ((*c == ' ')||(*c == '\n')||(*c == '\t')); |
|---|
| 105 | } /* getch */ |
|---|
| 106 | |
|---|
| 107 | void processlength(p) |
|---|
| 108 | node *p; |
|---|
| 109 | { |
|---|
| 110 | long digit, ordzero; |
|---|
| 111 | double valyew, divisor; |
|---|
| 112 | boolean pointread, minusread; |
|---|
| 113 | |
|---|
| 114 | ordzero = '0'; |
|---|
| 115 | pointread = false; |
|---|
| 116 | minusread = false; |
|---|
| 117 | valyew = 0.0; |
|---|
| 118 | divisor = 1.0; |
|---|
| 119 | getch(&ch); |
|---|
| 120 | digit = ch - ordzero; |
|---|
| 121 | while (((unsigned long)digit <= 9) || (ch == '.') || (ch == '.')){ |
|---|
| 122 | if (ch == '.') pointread = true; |
|---|
| 123 | else if (ch == '-') minusread = true; |
|---|
| 124 | else { |
|---|
| 125 | valyew = valyew * 10.0 + digit; |
|---|
| 126 | if (pointread) |
|---|
| 127 | divisor *= 10.0; |
|---|
| 128 | } |
|---|
| 129 | getch(&ch); |
|---|
| 130 | digit = ch - ordzero; |
|---|
| 131 | } |
|---|
| 132 | if (!minusread) |
|---|
| 133 | p->oldlen = valyew / divisor; |
|---|
| 134 | else |
|---|
| 135 | p->oldlen = 0.0; |
|---|
| 136 | /* processlength */ |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | void addelement(p, q) |
|---|
| 140 | node **p, *q; |
|---|
| 141 | { |
|---|
| 142 | /* read in and add next part of tree, it will be node p |
|---|
| 143 | and will be hooked to pointer q */ |
|---|
| 144 | node *pp; |
|---|
| 145 | long n,indx; |
|---|
| 146 | boolean notlast; |
|---|
| 147 | |
|---|
| 148 | nextnode++; |
|---|
| 149 | *p = (node *)Malloc((long)sizeof(node)); |
|---|
| 150 | nodep[nextnode - 1] = *p; |
|---|
| 151 | indx = nextnode; |
|---|
| 152 | (*p)->index = indx; |
|---|
| 153 | if (ch == '(') { |
|---|
| 154 | (*p)->tip = false; |
|---|
| 155 | pp = *p; |
|---|
| 156 | notlast = true; |
|---|
| 157 | while (notlast) { |
|---|
| 158 | pp->next = (node *)Malloc((long)sizeof(node)); |
|---|
| 159 | pp->next->tip = false; |
|---|
| 160 | nextnode++; |
|---|
| 161 | nodep[nextnode - 1] = pp->next; |
|---|
| 162 | pp->next->index = indx; |
|---|
| 163 | pp = pp->next; |
|---|
| 164 | getch(&ch); |
|---|
| 165 | addelement(&pp->back, pp); |
|---|
| 166 | if (ch == ')') { |
|---|
| 167 | notlast = false; |
|---|
| 168 | do { |
|---|
| 169 | getch(&ch); |
|---|
| 170 | } while (ch != ':' && ch != ',' && ch != ')' && ch != '[' && |
|---|
| 171 | ch != ';'); |
|---|
| 172 | } |
|---|
| 173 | } |
|---|
| 174 | pp->next = *p; |
|---|
| 175 | } else { |
|---|
| 176 | (*p)->tip = true; |
|---|
| 177 | ntips++; |
|---|
| 178 | n = 1; |
|---|
| 179 | do { |
|---|
| 180 | if (!ebcdic && (ch & 255) == 255) |
|---|
| 181 | ch = '\''; |
|---|
| 182 | if (!ebcdic && (ch & 255) > 175) |
|---|
| 183 | ch -= 48; |
|---|
| 184 | if (!ebcdic && (ch & (~127)) != 0) |
|---|
| 185 | ch -= 64; |
|---|
| 186 | if (ch == '_') |
|---|
| 187 | ch = ' '; |
|---|
| 188 | if (n < maxnch) |
|---|
| 189 | (*p)->nayme[n - 1] = ch; |
|---|
| 190 | if (eoln(treefile)) { |
|---|
| 191 | fscanf(treefile, "%*[^\n]"); |
|---|
| 192 | (void)getc(treefile); |
|---|
| 193 | } |
|---|
| 194 | ch = getc(treefile); |
|---|
| 195 | if (ch == '\n') |
|---|
| 196 | ch = ' '; |
|---|
| 197 | n++; |
|---|
| 198 | } while (ch != ':' && ch != ',' && ch != ')'); |
|---|
| 199 | if (n > maxnch) |
|---|
| 200 | n = maxnch + 1; |
|---|
| 201 | (*p)->naymlength = n - 1; |
|---|
| 202 | } |
|---|
| 203 | if (ch == ':') |
|---|
| 204 | processlength(*p); |
|---|
| 205 | else |
|---|
| 206 | haslengths = (haslengths && q == NULL); |
|---|
| 207 | (*p)->back = q; |
|---|
| 208 | if (haslengths && q != NULL) |
|---|
| 209 | (*p)->back->oldlen = (*p)->oldlen; |
|---|
| 210 | (*p)->r = 0.0; |
|---|
| 211 | (*p)->theta = 0.0; |
|---|
| 212 | } /* addelement */ |
|---|
| 213 | |
|---|
| 214 | void treeread() |
|---|
| 215 | { |
|---|
| 216 | /* read a tree from the treefile and set up nodes and pointers */ |
|---|
| 217 | haslengths = true; |
|---|
| 218 | ntips = 0; |
|---|
| 219 | nextnode = 0; |
|---|
| 220 | getch(&ch); |
|---|
| 221 | addelement(&root, NULL); |
|---|
| 222 | root->oldlen = 0.0; |
|---|
| 223 | fscanf(treefile, "%*[^\n]"); |
|---|
| 224 | (void)getc(treefile); |
|---|
| 225 | uselengths = haslengths; |
|---|
| 226 | where = root; |
|---|
| 227 | rotate = true; |
|---|
| 228 | } /* treeread */ |
|---|
| 229 | |
|---|
| 230 | void initialparms() |
|---|
| 231 | { |
|---|
| 232 | /* initialize parameters */ |
|---|
| 233 | |
|---|
| 234 | getplotter(); |
|---|
| 235 | plotrparms(); |
|---|
| 236 | xmargin = 0.08 * xsize; |
|---|
| 237 | ymargin = 0.08 * ysize; |
|---|
| 238 | xscale = xunitspercm; |
|---|
| 239 | yscale = yunitspercm; |
|---|
| 240 | grows = vertical; |
|---|
| 241 | treeangle = pi / 2.0; |
|---|
| 242 | ark = 2 * pi; |
|---|
| 243 | improve = true; |
|---|
| 244 | regular = false; |
|---|
| 245 | rescaled = true; |
|---|
| 246 | bscale = 1.0; |
|---|
| 247 | labeldirec = fixed; |
|---|
| 248 | labelrotation = 0.0; |
|---|
| 249 | charht = 0.3333; |
|---|
| 250 | numlines = dotmatrix ? ((long)floor(yunitspercm * ysize + 0.5) / strpdeep):1; |
|---|
| 251 | enthusiasm = 1.0/(double)ntips; |
|---|
| 252 | } /* initialparms */ |
|---|
| 253 | |
|---|
| 254 | |
|---|
| 255 | long showparms() |
|---|
| 256 | { |
|---|
| 257 | long i; |
|---|
| 258 | long numtochange; |
|---|
| 259 | Char ch,input[64]; |
|---|
| 260 | double treea; |
|---|
| 261 | |
|---|
| 262 | putchar('\n'); |
|---|
| 263 | if (previewer == tek) |
|---|
| 264 | printf("%c\f", escape); |
|---|
| 265 | else { |
|---|
| 266 | for (i = 1; i <= 24; i++) |
|---|
| 267 | putchar('\n'); |
|---|
| 268 | } |
|---|
| 269 | printf("Here are the settings: \n\n"); |
|---|
| 270 | printf(" (1) Use branch lengths: "); |
|---|
| 271 | if (haslengths) |
|---|
| 272 | printf("%s\n",uselengths ? "Yes" : "No"); |
|---|
| 273 | else |
|---|
| 274 | printf("(no branch lengths available)\n"); |
|---|
| 275 | printf(" (2) Angle of labels:"); |
|---|
| 276 | if (labeldirec == fixed) { |
|---|
| 277 | printf(" Fixed angle of"); |
|---|
| 278 | if (labelrotation >= 10.0) |
|---|
| 279 | printf("%6.1f", labelrotation); |
|---|
| 280 | else if (labelrotation <= -10.0) |
|---|
| 281 | printf("%7.1f", labelrotation); |
|---|
| 282 | else if (labelrotation < 0.0) |
|---|
| 283 | printf("%6.1f", labelrotation); |
|---|
| 284 | else |
|---|
| 285 | printf("%5.1f", labelrotation); |
|---|
| 286 | printf(" degrees\n"); |
|---|
| 287 | } else if (labeldirec == radial) |
|---|
| 288 | printf(" Radial\n"); |
|---|
| 289 | else |
|---|
| 290 | printf(" Along branches\n"); |
|---|
| 291 | printf(" (3) Rotation of tree:"); |
|---|
| 292 | treea = treeangle * 180 / pi; |
|---|
| 293 | if (treea >= 100.0) |
|---|
| 294 | printf("%7.1f\n", treea); |
|---|
| 295 | else if (treea >= 10.0) |
|---|
| 296 | printf("%6.1f\n", treea); |
|---|
| 297 | else if (treea <= -100.0) |
|---|
| 298 | printf("%8.1f\n", treea); |
|---|
| 299 | else if (treea <= -10.0) |
|---|
| 300 | printf("%7.1f\n", treea); |
|---|
| 301 | else if (treea < 0.0) |
|---|
| 302 | printf("%6.1f\n", treea); |
|---|
| 303 | else |
|---|
| 304 | printf("%5.1f\n", treea); |
|---|
| 305 | printf(" (4) Angle of arc for tree:"); |
|---|
| 306 | treea = 180 * ark / pi; |
|---|
| 307 | if (treea >= 100.0) |
|---|
| 308 | printf("%7.1f\n", treea); |
|---|
| 309 | else if (treea >= 10.0) |
|---|
| 310 | printf("%6.1f\n", treea); |
|---|
| 311 | else if (treea <= -100.0) |
|---|
| 312 | printf("%8.1f\n", treea); |
|---|
| 313 | else if (treea <= -10.0) |
|---|
| 314 | printf("%7.1f\n", treea); |
|---|
| 315 | else if (treea < 0.0) |
|---|
| 316 | printf("%6.1f\n", treea); |
|---|
| 317 | else |
|---|
| 318 | printf("%5.1f\n", treea); |
|---|
| 319 | printf(" (5) Iterate to improve tree: %s\n", |
|---|
| 320 | (improve ? "Yes" : "No")); |
|---|
| 321 | printf(" (6) Scale of branch length:"); |
|---|
| 322 | if (rescaled) |
|---|
| 323 | printf(" Automatically rescaled\n"); |
|---|
| 324 | else |
|---|
| 325 | printf(" Fixed:%6.2f cm per unit branch length\n", bscale); |
|---|
| 326 | didreroot = false; |
|---|
| 327 | printf(" (7) Horizontal margins:%6.2f cm\n", xmargin); |
|---|
| 328 | printf(" (7) Vertical margins:%6.2f cm\n", ymargin); |
|---|
| 329 | printf(" (8) Relative character height:%8.4f\n", charht); |
|---|
| 330 | if (!improve) |
|---|
| 331 | printf(" (9) Regularize the angles: %s\n",(regular ? "Yes" : "No")); |
|---|
| 332 | else |
|---|
| 333 | printf(" (9) Enthusiasm constant:%9.5f\n",enthusiasm); |
|---|
| 334 | if (plotter == lw) |
|---|
| 335 | printf(" (10) Font : %s\n",fontname); |
|---|
| 336 | |
|---|
| 337 | printf("\n\n Do you want to accept these? (Yes or No)\n"); |
|---|
| 338 | for (;;) { |
|---|
| 339 | printf(" Type Y or N or the number (1-%2ld) of the one to change: \n", |
|---|
| 340 | (plotter == lw) ? 10L : 9L); |
|---|
| 341 | gets(input); |
|---|
| 342 | uppercase(&input[0]); |
|---|
| 343 | ch=input[0]; |
|---|
| 344 | numtochange = atoi(input); |
|---|
| 345 | if ((ch == 'Y' || ch == 'N') || (numtochange >= 1 && numtochange <= |
|---|
| 346 | ((plotter == lw) ? 10 : 9))) |
|---|
| 347 | break; |
|---|
| 348 | } |
|---|
| 349 | return (ch == 'Y') ? -1 : numtochange; |
|---|
| 350 | } /* showparms */ |
|---|
| 351 | |
|---|
| 352 | void rerootit(p) |
|---|
| 353 | node *p; |
|---|
| 354 | { |
|---|
| 355 | node *q; |
|---|
| 356 | |
|---|
| 357 | q = root; |
|---|
| 358 | while (q->next != root) |
|---|
| 359 | q = q->next; |
|---|
| 360 | q->next = root->next; |
|---|
| 361 | q = p; |
|---|
| 362 | while (q->next != p) |
|---|
| 363 | q = q->next; |
|---|
| 364 | root->next = p; |
|---|
| 365 | q->next = root; |
|---|
| 366 | } /* rerootit */ |
|---|
| 367 | |
|---|
| 368 | void reroot() |
|---|
| 369 | { |
|---|
| 370 | /* reroot the tree, traversing tree */ |
|---|
| 371 | where = root->next; |
|---|
| 372 | if (!rotate) |
|---|
| 373 | rotate = where->back->tip; |
|---|
| 374 | if (rotate) { |
|---|
| 375 | where = where->next; |
|---|
| 376 | rotate = false; |
|---|
| 377 | } else { |
|---|
| 378 | where = where->back; |
|---|
| 379 | rotate = true; |
|---|
| 380 | } |
|---|
| 381 | rerootit(where); |
|---|
| 382 | } /* reroot */ |
|---|
| 383 | |
|---|
| 384 | |
|---|
| 385 | void getparms(numtochange) |
|---|
| 386 | long numtochange; |
|---|
| 387 | { |
|---|
| 388 | /* get from user the relevant parameters for the plotter and diagram */ |
|---|
| 389 | Char ch; |
|---|
| 390 | boolean ok; |
|---|
| 391 | |
|---|
| 392 | if (numtochange == 0) { |
|---|
| 393 | do { |
|---|
| 394 | printf(" Type the number of one that you want to change (1-%2ld):\n", |
|---|
| 395 | (plotter == lw) ? 10L : 9L); |
|---|
| 396 | scanf("%ld%*[^\n]", &numtochange); |
|---|
| 397 | (void)getchar(); |
|---|
| 398 | } while (numtochange < 1 || numtochange > ((plotter == lw) ? 10 : 9)); |
|---|
| 399 | } |
|---|
| 400 | switch (numtochange) { |
|---|
| 401 | |
|---|
| 402 | case 1: |
|---|
| 403 | if (haslengths) |
|---|
| 404 | uselengths = !uselengths; |
|---|
| 405 | else { |
|---|
| 406 | printf("Cannot use lengths since not all of them exist\n"); |
|---|
| 407 | uselengths = false; |
|---|
| 408 | } |
|---|
| 409 | break; |
|---|
| 410 | |
|---|
| 411 | case 2: |
|---|
| 412 | printf("\nDo you want labels to be Fixed angle, Radial,"); |
|---|
| 413 | printf(" or Along branches?\n"); |
|---|
| 414 | do { |
|---|
| 415 | printf(" Type F, R, or A\n"); |
|---|
| 416 | scanf("%c%*[^\n]", &ch); |
|---|
| 417 | (void)getchar(); |
|---|
| 418 | if (ch == '\n') |
|---|
| 419 | ch = ' '; |
|---|
| 420 | uppercase(&ch); |
|---|
| 421 | } while (ch != 'F' && ch != 'R' && ch != 'A'); |
|---|
| 422 | switch (ch) { |
|---|
| 423 | |
|---|
| 424 | case 'A': |
|---|
| 425 | labeldirec = along; |
|---|
| 426 | break; |
|---|
| 427 | |
|---|
| 428 | case 'F': |
|---|
| 429 | labeldirec = fixed; |
|---|
| 430 | break; |
|---|
| 431 | |
|---|
| 432 | case 'R': |
|---|
| 433 | labeldirec = radial; |
|---|
| 434 | break; |
|---|
| 435 | } |
|---|
| 436 | if (labeldirec == fixed) { |
|---|
| 437 | printf("Are the labels to be plotted vertically (90),\n"); |
|---|
| 438 | printf(" horizontally (0), or downwards (-90) ?\n"); |
|---|
| 439 | do { |
|---|
| 440 | printf(" Choose an angle in degrees from 90 to -90: \n"); |
|---|
| 441 | scanf("%lf%*[^\n]", &labelrotation); |
|---|
| 442 | (void)getchar(); |
|---|
| 443 | } while ((labelrotation < -90.0 || labelrotation > 90.0) && |
|---|
| 444 | labelrotation != -99.0); |
|---|
| 445 | } |
|---|
| 446 | break; |
|---|
| 447 | |
|---|
| 448 | case 3: |
|---|
| 449 | printf("\n At what angle is the tree to be plotted?\n"); |
|---|
| 450 | do { |
|---|
| 451 | printf(" Choose an angle in degrees from 360 to -360: \n"); |
|---|
| 452 | scanf("%lf%*[^\n]", &treeangle); |
|---|
| 453 | (void)getchar(); |
|---|
| 454 | uppercase(&ch); |
|---|
| 455 | } while (treeangle < -360.0 && treeangle > 360.0); |
|---|
| 456 | treeangle = treeangle * pi / 180; |
|---|
| 457 | break; |
|---|
| 458 | |
|---|
| 459 | case 4: |
|---|
| 460 | printf(" How many degrees (up to 360) of arc\n"); |
|---|
| 461 | printf(" should the tree occupy? (Currently it is %5.1f)\n", |
|---|
| 462 | 180 * ark / pi); |
|---|
| 463 | do { |
|---|
| 464 | printf("Enter a number of degrees from 0 up to 360)\n"); |
|---|
| 465 | scanf("%lf%*[^\n]", &ark); |
|---|
| 466 | (void)getchar(); |
|---|
| 467 | } while (ark <= 0.0 || ark > 360.0); |
|---|
| 468 | ark = ark * pi / 180; |
|---|
| 469 | break; |
|---|
| 470 | |
|---|
| 471 | case 5: |
|---|
| 472 | improve = !improve; |
|---|
| 473 | break; |
|---|
| 474 | |
|---|
| 475 | case 6: |
|---|
| 476 | rescaled = !rescaled; |
|---|
| 477 | if (!rescaled) { |
|---|
| 478 | printf("Centimeters per unit branch length?\n"); |
|---|
| 479 | scanf("%lf%*[^\n]", &bscale); |
|---|
| 480 | (void)getchar(); |
|---|
| 481 | } |
|---|
| 482 | break; |
|---|
| 483 | |
|---|
| 484 | case 7: |
|---|
| 485 | printf("\nThe tree will be drawn to fit in a rectangle which has \n"); |
|---|
| 486 | printf(" margins in the horizontal and vertical directions of:\n"); |
|---|
| 487 | printf("%6.2f cm (horizontal margin) and%6.2f cm (vertical margin)\n\n", |
|---|
| 488 | xmargin, ymargin); |
|---|
| 489 | do { |
|---|
| 490 | printf(" New value (in cm) of horizontal margin?\n"); |
|---|
| 491 | scanf("%lf%*[^\n]", &xmargin); |
|---|
| 492 | (void)getchar(); |
|---|
| 493 | ok = ((unsigned)xmargin < xsize / 2.0); |
|---|
| 494 | if (!ok) |
|---|
| 495 | printf(" Impossible value. Please retype it.\n"); |
|---|
| 496 | } while (!ok); |
|---|
| 497 | do { |
|---|
| 498 | printf(" New value (in cm) of vertical margin?\n"); |
|---|
| 499 | scanf("%lf%*[^\n]", &ymargin); |
|---|
| 500 | (void)getchar(); |
|---|
| 501 | ok = ((unsigned)ymargin < ysize / 2.0); |
|---|
| 502 | if (!ok) |
|---|
| 503 | printf(" Impossible value. Please retype it.\n"); |
|---|
| 504 | } while (!ok); |
|---|
| 505 | break; |
|---|
| 506 | |
|---|
| 507 | case 8: |
|---|
| 508 | printf("New value of character height?\n"); |
|---|
| 509 | scanf("%lf%*[^\n]", &charht); |
|---|
| 510 | (void)getchar(); |
|---|
| 511 | break; |
|---|
| 512 | case 9: |
|---|
| 513 | if (improve) { |
|---|
| 514 | do { |
|---|
| 515 | printf("Enthusiasm constant? (must be between 0 and 1)\n"); |
|---|
| 516 | scanf("%lf%*[^\n]", &enthusiasm); |
|---|
| 517 | getchar(); |
|---|
| 518 | } while (enthusiasm <= 0.0 || enthusiasm > 1.0);} |
|---|
| 519 | else |
|---|
| 520 | regular = !regular; |
|---|
| 521 | break; |
|---|
| 522 | case 10: |
|---|
| 523 | printf("Enter font name or \"Hershey\" for default font\n"); |
|---|
| 524 | gets(fontname); |
|---|
| 525 | break; |
|---|
| 526 | } |
|---|
| 527 | } /* getparms */ |
|---|
| 528 | |
|---|
| 529 | |
|---|
| 530 | Local void getwidth(p) |
|---|
| 531 | node *p; |
|---|
| 532 | { |
|---|
| 533 | /* get width and depth beyond each node */ |
|---|
| 534 | double nw, nd; |
|---|
| 535 | node *pp, *qq; |
|---|
| 536 | |
|---|
| 537 | nd = 0.0; |
|---|
| 538 | if (p->tip) |
|---|
| 539 | nw = 1.0; |
|---|
| 540 | else { |
|---|
| 541 | nw = 0.0; |
|---|
| 542 | qq = p; |
|---|
| 543 | pp = p->next; |
|---|
| 544 | do { |
|---|
| 545 | getwidth(pp->back); |
|---|
| 546 | nw += pp->back->width; |
|---|
| 547 | if (pp->back->depth > nd) |
|---|
| 548 | nd = pp->back->depth; |
|---|
| 549 | pp = pp->next; |
|---|
| 550 | } while (pp != qq); |
|---|
| 551 | } |
|---|
| 552 | p->depth = nd + p->length; |
|---|
| 553 | p->width = nw; |
|---|
| 554 | } /* getwidth */ |
|---|
| 555 | |
|---|
| 556 | void plrtrans(p, theta, lower, upper) |
|---|
| 557 | node *p; |
|---|
| 558 | double theta, lower, upper; |
|---|
| 559 | { |
|---|
| 560 | /* polar coordinates of a node relative to start */ |
|---|
| 561 | long num; |
|---|
| 562 | double nn, pr, ptheta, angle, angle2, subangle, len; |
|---|
| 563 | node *pp, *qq; |
|---|
| 564 | |
|---|
| 565 | nn = p->width; |
|---|
| 566 | angle = theta; |
|---|
| 567 | subangle = (upper - lower) / nn; |
|---|
| 568 | qq = p; |
|---|
| 569 | pp = p->next; |
|---|
| 570 | if (p->tip) |
|---|
| 571 | return; |
|---|
| 572 | angle = upper; |
|---|
| 573 | do { |
|---|
| 574 | angle -= pp->back->width / 2.0 * subangle; |
|---|
| 575 | pr = p->r; |
|---|
| 576 | ptheta = p->theta; |
|---|
| 577 | if (regular) { |
|---|
| 578 | num = 1; |
|---|
| 579 | while (num * subangle < 2 * pi) |
|---|
| 580 | num *= 2; |
|---|
| 581 | if (angle >= 0.0) |
|---|
| 582 | angle2 = 2 * pi / num * (long)(num * angle / (2 * pi) + 0.5); |
|---|
| 583 | else |
|---|
| 584 | angle2 = 2 * pi / num * (long)(num * angle / (2 * pi) - 0.5); |
|---|
| 585 | } else |
|---|
| 586 | angle2 = angle; |
|---|
| 587 | if (uselengths) |
|---|
| 588 | len = pp->back->oldlen; |
|---|
| 589 | else |
|---|
| 590 | len = 1.0; |
|---|
| 591 | pp->back->r = sqrt(len * len + pr * pr + 2 * len * pr * cos(angle2 - ptheta)); |
|---|
| 592 | if (fabs(pr * cos(ptheta) + len * cos(angle2)) > epsilon) |
|---|
| 593 | pp->back->theta = atan((pr * sin(ptheta) + len * sin(angle2)) / |
|---|
| 594 | (pr * cos(ptheta) + len * cos(angle2))); |
|---|
| 595 | else if (pr * sin(ptheta) + len * sin(angle2) >= 0.0) |
|---|
| 596 | pp->back->theta = pi / 2; |
|---|
| 597 | else |
|---|
| 598 | pp->back->theta = 1.5 * pi; |
|---|
| 599 | if (pr * cos(ptheta) + len * cos(angle2) < -epsilon) |
|---|
| 600 | pp->back->theta += pi; |
|---|
| 601 | if (!pp->back->tip) |
|---|
| 602 | plrtrans(pp->back, pp->back->theta, |
|---|
| 603 | angle - pp->back->width * subangle / 2.0, |
|---|
| 604 | angle + pp->back->width * subangle / 2.0); |
|---|
| 605 | else |
|---|
| 606 | pp->back->oldtheta = angle2; |
|---|
| 607 | angle -= pp->back->width / 2.0 * subangle; |
|---|
| 608 | pp = pp->next; |
|---|
| 609 | } while (pp != qq); |
|---|
| 610 | } /* plrtrans */ |
|---|
| 611 | |
|---|
| 612 | void coordtrav(p, xx, yy) |
|---|
| 613 | node *p; |
|---|
| 614 | double *xx, *yy; |
|---|
| 615 | { |
|---|
| 616 | /* compute x and y coordinates */ |
|---|
| 617 | long i; |
|---|
| 618 | node *pp; |
|---|
| 619 | |
|---|
| 620 | if (!p->tip) { |
|---|
| 621 | pp = p->next; |
|---|
| 622 | while (pp != p) { |
|---|
| 623 | coordtrav(pp->back, xx,yy); |
|---|
| 624 | pp = pp->next; |
|---|
| 625 | } |
|---|
| 626 | } |
|---|
| 627 | if (p->tip) { |
|---|
| 628 | i = 1; |
|---|
| 629 | while (nodep[i - 1] != p) |
|---|
| 630 | i++; |
|---|
| 631 | textlength[i - 1] = (double)lengthtext(p->nayme, p->naymlength, font); |
|---|
| 632 | } |
|---|
| 633 | (*xx) = p->r * cos(p->theta); |
|---|
| 634 | (*yy) = p->r * sin(p->theta); |
|---|
| 635 | if ((*xx) > maxx) |
|---|
| 636 | maxx = (*xx); |
|---|
| 637 | if ((*xx) < minx) |
|---|
| 638 | minx = (*xx); |
|---|
| 639 | if ((*yy) > maxy) |
|---|
| 640 | maxy = (*yy); |
|---|
| 641 | if ((*yy) < miny) |
|---|
| 642 | miny = (*yy); |
|---|
| 643 | p->xcoord = (*xx); |
|---|
| 644 | p->ycoord = (*yy); |
|---|
| 645 | } /* coordtrav */ |
|---|
| 646 | |
|---|
| 647 | |
|---|
| 648 | double angleof(x, y) |
|---|
| 649 | double x, y; |
|---|
| 650 | { |
|---|
| 651 | /* compute the angle of a vector */ |
|---|
| 652 | double theta; |
|---|
| 653 | |
|---|
| 654 | if (fabs(x) > epsilon) |
|---|
| 655 | theta = atan(y / x); |
|---|
| 656 | else if (y >= 0.0) |
|---|
| 657 | theta = pi / 2; |
|---|
| 658 | else |
|---|
| 659 | theta = 1.5 * pi; |
|---|
| 660 | if (x < -epsilon) |
|---|
| 661 | theta = pi + theta; |
|---|
| 662 | if (theta > 2 * pi) |
|---|
| 663 | theta -= 2 * pi; |
|---|
| 664 | return theta; |
|---|
| 665 | } /* angleof */ |
|---|
| 666 | |
|---|
| 667 | void polartrav(p,xx,yy,leftx,lefty,rightx,righty) |
|---|
| 668 | node *p; |
|---|
| 669 | double *xx,*yy,*leftx,*lefty,*rightx,*righty; |
|---|
| 670 | { |
|---|
| 671 | /* go through subtree getting left and right vectors */ |
|---|
| 672 | double x, y; |
|---|
| 673 | boolean lookatit; |
|---|
| 674 | node *pp; |
|---|
| 675 | |
|---|
| 676 | lookatit = true; |
|---|
| 677 | if (!p->tip) |
|---|
| 678 | lookatit = (p->next->next->next != p || p->index != root->index); |
|---|
| 679 | if (lookatit) { |
|---|
| 680 | x = nodep[p->index - 1]->xcoord; |
|---|
| 681 | y = nodep[p->index - 1]->ycoord; |
|---|
| 682 | if ((y - (*yy)) * (*rightx) - (x - (*xx)) * (*righty) < 0.0) { |
|---|
| 683 | (*rightx) = x - (*xx); |
|---|
| 684 | (*righty) = y - (*yy); |
|---|
| 685 | } |
|---|
| 686 | if ((y - (*yy)) * (*leftx) - (x - (*xx)) * (*lefty) > 0.0 && |
|---|
| 687 | !(notfirst && fabs((*rightx) - x + (*xx)) + |
|---|
| 688 | fabs((*righty) - y + (*yy)) < epsilon)) { |
|---|
| 689 | (*leftx) = x - (*xx); |
|---|
| 690 | (*lefty) = y - (*yy); |
|---|
| 691 | notfirst = true; |
|---|
| 692 | } |
|---|
| 693 | } |
|---|
| 694 | if (p->tip) |
|---|
| 695 | return; |
|---|
| 696 | pp = p->next; |
|---|
| 697 | while (pp != p) { |
|---|
| 698 | if (pp != root) |
|---|
| 699 | polartrav(pp->back,xx,yy,leftx,lefty,rightx,righty); |
|---|
| 700 | pp = pp->next; |
|---|
| 701 | } |
|---|
| 702 | } /* polartrav */ |
|---|
| 703 | |
|---|
| 704 | void tilttrav(q,xx,yy,sinphi,cosphi) |
|---|
| 705 | node *q; |
|---|
| 706 | double *xx,*yy,*sinphi,*cosphi; |
|---|
| 707 | { |
|---|
| 708 | /* traverse to move successive nodes */ |
|---|
| 709 | double x, y; |
|---|
| 710 | node *pp; |
|---|
| 711 | |
|---|
| 712 | pp = nodep[q->index - 1]; |
|---|
| 713 | x = pp->xcoord; |
|---|
| 714 | y = pp->ycoord; |
|---|
| 715 | pp->xcoord = (*xx) + (x - (*xx)) * (*cosphi) + (y - (*yy)) * (*sinphi); |
|---|
| 716 | pp->ycoord = (*yy) + ((*xx) - x) * (*sinphi) + (y - (*yy)) * (*cosphi); |
|---|
| 717 | if (q->tip) |
|---|
| 718 | return; |
|---|
| 719 | pp = q->next; |
|---|
| 720 | while (pp != q) { |
|---|
| 721 | if (pp != root) |
|---|
| 722 | tilttrav(pp->back,xx,yy,sinphi,cosphi); |
|---|
| 723 | pp = pp->next; |
|---|
| 724 | } |
|---|
| 725 | } /* tilttrav */ |
|---|
| 726 | |
|---|
| 727 | void polarize(p,xx,yy) |
|---|
| 728 | node *p; |
|---|
| 729 | double *xx,*yy; |
|---|
| 730 | { |
|---|
| 731 | double TEMP, TEMP1; |
|---|
| 732 | |
|---|
| 733 | if (fabs(p->xcoord - (*xx)) > epsilon) |
|---|
| 734 | p->oldtheta = atan((p->ycoord - (*yy)) / (p->xcoord - (*xx))); |
|---|
| 735 | else if (p->ycoord - (*yy) >= 0.0) |
|---|
| 736 | p->oldtheta = pi / 2; |
|---|
| 737 | else |
|---|
| 738 | p->oldtheta = 1.5 * pi; |
|---|
| 739 | if (p->xcoord - (*xx) < -epsilon) |
|---|
| 740 | p->oldtheta += pi; |
|---|
| 741 | if (fabs(p->xcoord - root->xcoord) > epsilon) |
|---|
| 742 | p->theta = atan((p->ycoord - root->ycoord) / (p->xcoord - root->xcoord)); |
|---|
| 743 | else if (p->ycoord - root->ycoord >= 0.0) |
|---|
| 744 | p->theta = pi / 2; |
|---|
| 745 | else |
|---|
| 746 | p->theta = 1.5 * pi; |
|---|
| 747 | if (p->xcoord - root->xcoord < -epsilon) |
|---|
| 748 | p->theta += pi; |
|---|
| 749 | TEMP = p->xcoord - root->xcoord; |
|---|
| 750 | TEMP1 = p->ycoord - root->ycoord; |
|---|
| 751 | p->r = sqrt(TEMP * TEMP + TEMP1 * TEMP1); |
|---|
| 752 | } /* polarize */ |
|---|
| 753 | |
|---|
| 754 | void improvtrav(p) |
|---|
| 755 | node *p; |
|---|
| 756 | { |
|---|
| 757 | /* traverse tree trying different tiltings at each node */ |
|---|
| 758 | double xx, yy, leftx, lefty, rightx, righty, cosphi, sinphi; |
|---|
| 759 | long n; |
|---|
| 760 | double usedangle, langle, rangle, freeangle, meanangle, sumrot; |
|---|
| 761 | node *pp, *qq; |
|---|
| 762 | |
|---|
| 763 | if (p->tip) |
|---|
| 764 | return; |
|---|
| 765 | xx = p->xcoord; |
|---|
| 766 | yy = p->ycoord; |
|---|
| 767 | if (p != root) { |
|---|
| 768 | n = 0; |
|---|
| 769 | usedangle = 0.0; |
|---|
| 770 | pp = p->next; |
|---|
| 771 | do { |
|---|
| 772 | leftx = pp->back->xcoord - xx; |
|---|
| 773 | lefty = pp->back->ycoord - yy; |
|---|
| 774 | rightx = leftx; |
|---|
| 775 | righty = lefty; |
|---|
| 776 | notfirst = false; |
|---|
| 777 | if (!pp->back->tip) |
|---|
| 778 | polartrav(pp->back, &xx,&yy,&leftx,&lefty,&rightx,&righty); |
|---|
| 779 | n++; |
|---|
| 780 | langle = angleof(leftx, lefty); |
|---|
| 781 | rangle = angleof(rightx, righty); |
|---|
| 782 | if (rangle > langle) |
|---|
| 783 | langle += 2 * pi; |
|---|
| 784 | pp->lefttheta = langle; |
|---|
| 785 | pp->righttheta = rangle; |
|---|
| 786 | usedangle += langle - rangle; |
|---|
| 787 | pp = pp->next; |
|---|
| 788 | } while (pp != p->next); |
|---|
| 789 | freeangle = 2 * pi - usedangle; |
|---|
| 790 | meanangle = freeangle / n; |
|---|
| 791 | sumrot = 0.0; |
|---|
| 792 | qq = p; |
|---|
| 793 | pp = p->next; |
|---|
| 794 | while (pp != p) { |
|---|
| 795 | langle = qq->righttheta; |
|---|
| 796 | rangle = pp->lefttheta; |
|---|
| 797 | if (rangle > langle) |
|---|
| 798 | langle += 2 * pi; |
|---|
| 799 | sumrot += enthusiasm * (meanangle - langle + rangle); |
|---|
| 800 | cosphi = cos(sumrot); |
|---|
| 801 | sinphi = sin(sumrot); |
|---|
| 802 | if (pp != root) |
|---|
| 803 | tilttrav(pp->back, &xx,&yy,&sinphi,&cosphi); |
|---|
| 804 | qq = pp; |
|---|
| 805 | pp = pp->next; |
|---|
| 806 | } |
|---|
| 807 | } |
|---|
| 808 | pp = p->next; |
|---|
| 809 | while (pp != p) { |
|---|
| 810 | if (pp != root) |
|---|
| 811 | polarize(pp->back, &xx,&yy); |
|---|
| 812 | pp = pp->next; |
|---|
| 813 | } |
|---|
| 814 | pp = p->next; |
|---|
| 815 | while (pp != p) { |
|---|
| 816 | if (pp != root) |
|---|
| 817 | improvtrav(pp->back); |
|---|
| 818 | pp = pp->next; |
|---|
| 819 | } |
|---|
| 820 | } /* improvtrav */ |
|---|
| 821 | |
|---|
| 822 | void coordimprov(xx,yy) |
|---|
| 823 | double *xx,*yy; |
|---|
| 824 | { |
|---|
| 825 | /* use angles calculation to improve node coordinate placement */ |
|---|
| 826 | long i; |
|---|
| 827 | for (i = 1; i <= iterations; i++) |
|---|
| 828 | improvtrav(root); |
|---|
| 829 | } /* coordimprov */ |
|---|
| 830 | |
|---|
| 831 | |
|---|
| 832 | void calculate() |
|---|
| 833 | { |
|---|
| 834 | /* compute coordinates for tree */ |
|---|
| 835 | double xx, yy; |
|---|
| 836 | long i; |
|---|
| 837 | double nttot, fontheight, labangle, top, bot, rig, lef; |
|---|
| 838 | |
|---|
| 839 | for (i = 0; i < nextnode; i++) |
|---|
| 840 | nodep[i]->width = 1.0; |
|---|
| 841 | for (i = 0; i < nextnode; i++) |
|---|
| 842 | nodep[i]->xcoord = 0.0; |
|---|
| 843 | for (i = 0; i < nextnode; i++) |
|---|
| 844 | nodep[i]->ycoord = 0.0; |
|---|
| 845 | if (!uselengths) { |
|---|
| 846 | for (i = 0; i < nextnode; i++) |
|---|
| 847 | nodep[i]->length = 1.0; |
|---|
| 848 | } else { |
|---|
| 849 | for (i = 0; i < nextnode; i++) |
|---|
| 850 | nodep[i]->length = nodep[i]->oldlen; |
|---|
| 851 | } |
|---|
| 852 | getwidth(root); |
|---|
| 853 | nttot = root->width; |
|---|
| 854 | for (i = 0; i < nextnode; i++) |
|---|
| 855 | nodep[i]->width = nodep[i]->width * ntips / nttot; |
|---|
| 856 | plrtrans(root, treeangle, treeangle - ark / 2.0, treeangle + ark / 2.0); |
|---|
| 857 | maxx = 0.0; |
|---|
| 858 | minx = 0.0; |
|---|
| 859 | maxy = 0.0; |
|---|
| 860 | miny = 0.0; |
|---|
| 861 | coordtrav(root, &xx,&yy); |
|---|
| 862 | if (improve) { |
|---|
| 863 | coordimprov(&xx,&yy); |
|---|
| 864 | coordtrav(root, &xx,&yy); |
|---|
| 865 | } |
|---|
| 866 | fontheight = font[2]; |
|---|
| 867 | if (labeldirec == fixed) |
|---|
| 868 | labangle = pi * labelrotation / 180.0; |
|---|
| 869 | for (i = 0; i < nextnode; i++) { |
|---|
| 870 | if (nodep[i]->tip) |
|---|
| 871 | textlength[i] /= fontheight; |
|---|
| 872 | } |
|---|
| 873 | if (ntips > 1) |
|---|
| 874 | labelheight = charht * (maxx - minx) / (ntips - 1); |
|---|
| 875 | else |
|---|
| 876 | labelheight = charht * (maxx - minx); |
|---|
| 877 | topoflabels = 0.0; |
|---|
| 878 | bottomoflabels = 0.0; |
|---|
| 879 | rightoflabels = 0.0; |
|---|
| 880 | leftoflabels = 0.0; |
|---|
| 881 | for (i = 0; i < nextnode; i++) { |
|---|
| 882 | if (nodep[i]->tip) { |
|---|
| 883 | if (labeldirec == radial) |
|---|
| 884 | labangle = nodep[i]->theta; |
|---|
| 885 | else if (labeldirec == along) |
|---|
| 886 | labangle = nodep[i]->oldtheta; |
|---|
| 887 | if (cos(labangle) < 0.0 && labeldirec != fixed) |
|---|
| 888 | labangle -= pi; |
|---|
| 889 | firstlet[i] = (double)lengthtext(nodep[i]->nayme,1L,font)/ fontheight; |
|---|
| 890 | top = (nodep[i]->ycoord - maxy) / labelheight + sin(nodep[i]->oldtheta); |
|---|
| 891 | rig = (nodep[i]->xcoord - maxx) / labelheight + cos(nodep[i]->oldtheta); |
|---|
| 892 | bot = (miny - nodep[i]->ycoord) / labelheight - sin(nodep[i]->oldtheta); |
|---|
| 893 | lef = (minx - nodep[i]->xcoord) / labelheight - cos(nodep[i]->oldtheta); |
|---|
| 894 | if (cos(labangle) * cos(nodep[i]->oldtheta) + |
|---|
| 895 | sin(labangle) * sin(nodep[i]->oldtheta) > 0.0) { |
|---|
| 896 | if (sin(labangle) > 0.0) |
|---|
| 897 | top += sin(labangle) * textlength[i]; |
|---|
| 898 | top += sin(labangle - 1.25 * pi) * gap * firstlet[i]; |
|---|
| 899 | if (sin(labangle) < 0.0) |
|---|
| 900 | bot -= sin(labangle) * textlength[i]; |
|---|
| 901 | bot -= sin(labangle - 0.75 * pi) * gap * firstlet[i]; |
|---|
| 902 | if (sin(labangle) > 0.0) |
|---|
| 903 | rig += cos(labangle - 0.75 * pi) * gap * firstlet[i]; |
|---|
| 904 | else |
|---|
| 905 | rig += cos(labangle - 1.25 * pi) * gap * firstlet[i]; |
|---|
| 906 | rig += cos(labangle) * textlength[i]; |
|---|
| 907 | if (sin(labangle) > 0.0) |
|---|
| 908 | lef -= cos(labangle - 1.25 * pi) * gap * firstlet[i]; |
|---|
| 909 | else |
|---|
| 910 | lef -= cos(labangle - 0.75 * pi) * gap * firstlet[i]; |
|---|
| 911 | } else { |
|---|
| 912 | if (sin(labangle) < 0.0) |
|---|
| 913 | top -= sin(labangle) * textlength[i]; |
|---|
| 914 | top += sin(labangle + 0.25 * pi) * gap * firstlet[i]; |
|---|
| 915 | if (sin(labangle) > 0.0) |
|---|
| 916 | bot += sin(labangle) * textlength[i]; |
|---|
| 917 | bot -= sin(labangle - 0.25 * pi) * gap * firstlet[i]; |
|---|
| 918 | if (sin(labangle) > 0.0) |
|---|
| 919 | rig += cos(labangle - 0.25 * pi) * gap * firstlet[i]; |
|---|
| 920 | else |
|---|
| 921 | rig += cos(labangle + 0.25 * pi) * gap * firstlet[i]; |
|---|
| 922 | if (sin(labangle) < 0.0) |
|---|
| 923 | rig += cos(labangle) * textlength[i]; |
|---|
| 924 | if (sin(labangle) > 0.0) |
|---|
| 925 | lef -= cos(labangle + 0.25 * pi) * gap * firstlet[i]; |
|---|
| 926 | else |
|---|
| 927 | lef -= cos(labangle - 0.25 * pi) * gap * firstlet[i]; |
|---|
| 928 | lef += cos(labangle) * textlength[i]; |
|---|
| 929 | } |
|---|
| 930 | if (top > topoflabels) |
|---|
| 931 | topoflabels = top; |
|---|
| 932 | if (bot > bottomoflabels) |
|---|
| 933 | bottomoflabels = bot; |
|---|
| 934 | if (rig > rightoflabels) |
|---|
| 935 | rightoflabels = rig; |
|---|
| 936 | if (lef > leftoflabels) |
|---|
| 937 | leftoflabels = lef; |
|---|
| 938 | } |
|---|
| 939 | } |
|---|
| 940 | topoflabels *= labelheight; |
|---|
| 941 | bottomoflabels *= labelheight; |
|---|
| 942 | leftoflabels *= labelheight; |
|---|
| 943 | rightoflabels *= labelheight; |
|---|
| 944 | } /* calculate */ |
|---|
| 945 | |
|---|
| 946 | |
|---|
| 947 | void rescale() |
|---|
| 948 | { |
|---|
| 949 | /* compute coordinates of tree for plot or preview device */ |
|---|
| 950 | long i; |
|---|
| 951 | double treeheight, treewidth, extrax, extray, temp; |
|---|
| 952 | |
|---|
| 953 | treeheight = maxy - miny + topoflabels + bottomoflabels; |
|---|
| 954 | treewidth = maxx - minx + rightoflabels + leftoflabels; |
|---|
| 955 | if (grows == vertical) { |
|---|
| 956 | if (!rescaled) |
|---|
| 957 | expand = bscale; |
|---|
| 958 | else { |
|---|
| 959 | expand = (xsize - 2 * xmargin) / treewidth; |
|---|
| 960 | if ((ysize - 2 * ymargin) / treeheight < expand) |
|---|
| 961 | expand = (ysize - 2 * ymargin) / treeheight; |
|---|
| 962 | } |
|---|
| 963 | extrax = (xsize - 2 * xmargin - treewidth * expand) / 2.0; |
|---|
| 964 | extray = (ysize - 2 * ymargin - treeheight * expand) / 2.0; |
|---|
| 965 | } else { |
|---|
| 966 | if (!rescaled) |
|---|
| 967 | expand = bscale; |
|---|
| 968 | else { |
|---|
| 969 | expand = (ysize - 2 * ymargin) / treewidth; |
|---|
| 970 | if ((xsize - 2 * xmargin) / treeheight < expand) |
|---|
| 971 | expand = (xsize - 2 * xmargin) / treeheight; |
|---|
| 972 | } |
|---|
| 973 | extrax = (xsize - 2 * xmargin - treeheight * expand) / 2.0; |
|---|
| 974 | extray = (ysize - 2 * ymargin - treewidth * expand) / 2.0; |
|---|
| 975 | } |
|---|
| 976 | for (i = 0; i < (nextnode); i++) { |
|---|
| 977 | nodep[i]->xcoord = expand * (nodep[i]->xcoord - minx + leftoflabels); |
|---|
| 978 | nodep[i]->ycoord = expand * (nodep[i]->ycoord - miny + bottomoflabels); |
|---|
| 979 | if (grows == horizontal) { |
|---|
| 980 | temp = nodep[i]->ycoord; |
|---|
| 981 | nodep[i]->ycoord = expand * treewidth - nodep[i]->xcoord; |
|---|
| 982 | nodep[i]->xcoord = temp; |
|---|
| 983 | } |
|---|
| 984 | nodep[i]->xcoord += xmargin + extrax; |
|---|
| 985 | nodep[i]->ycoord += ymargin + extray; |
|---|
| 986 | } |
|---|
| 987 | } /* rescale */ |
|---|
| 988 | |
|---|
| 989 | void plottree(p, q) |
|---|
| 990 | node *p, *q; |
|---|
| 991 | { |
|---|
| 992 | /* plot part or all of tree on the plotting device */ |
|---|
| 993 | double x1, y1, x2, y2; |
|---|
| 994 | node *pp; |
|---|
| 995 | |
|---|
| 996 | x2 = xscale * (xoffset + p->xcoord); |
|---|
| 997 | y2 = yscale * (yoffset + p->ycoord); |
|---|
| 998 | if (p != root) { |
|---|
| 999 | x1 = xscale * (xoffset + q->xcoord); |
|---|
| 1000 | y1 = yscale * (yoffset + q->ycoord); |
|---|
| 1001 | plot(penup, x1, y1); |
|---|
| 1002 | plot(pendown, x2, y2); |
|---|
| 1003 | } |
|---|
| 1004 | if (p->tip) |
|---|
| 1005 | return; |
|---|
| 1006 | pp = p->next; |
|---|
| 1007 | while (pp != p) { |
|---|
| 1008 | plottree(pp->back, p); |
|---|
| 1009 | pp = pp->next; |
|---|
| 1010 | } |
|---|
| 1011 | } /* plottree */ |
|---|
| 1012 | |
|---|
| 1013 | |
|---|
| 1014 | void plotlabels(fontname) |
|---|
| 1015 | char *fontname; |
|---|
| 1016 | { |
|---|
| 1017 | long i; |
|---|
| 1018 | double compr, dx, dy, labangle; |
|---|
| 1019 | boolean left, right; |
|---|
| 1020 | node *lp; |
|---|
| 1021 | |
|---|
| 1022 | compr = xunitspercm / yunitspercm; |
|---|
| 1023 | if (penchange == yes) |
|---|
| 1024 | changepen(labelpen); |
|---|
| 1025 | for (i = 0; i < (nextnode); i++) { |
|---|
| 1026 | if (nodep[i]->tip) { |
|---|
| 1027 | lp = nodep[i]; |
|---|
| 1028 | labangle = labelrotation * pi / 180.0; |
|---|
| 1029 | if (labeldirec == radial) |
|---|
| 1030 | labangle = nodep[i]->theta; |
|---|
| 1031 | else if (labeldirec == along) |
|---|
| 1032 | labangle = nodep[i]->oldtheta; |
|---|
| 1033 | if (cos(labangle) < 0.0) |
|---|
| 1034 | labangle -= pi; |
|---|
| 1035 | right = (cos(labangle) * cos(nodep[i]->oldtheta) + |
|---|
| 1036 | sin(labangle) * sin(nodep[i]->oldtheta) > 0.0); |
|---|
| 1037 | left = !right; |
|---|
| 1038 | dx = labelheight * expand * cos(nodep[i]->oldtheta); |
|---|
| 1039 | dy = labelheight * expand * sin(nodep[i]->oldtheta); |
|---|
| 1040 | if (right) { |
|---|
| 1041 | dx += labelheight * expand * 0.5 * firstlet[i] * cos(labangle - 0.75 * pi); |
|---|
| 1042 | dy += labelheight * expand * 0.5 * firstlet[i] * sin(labangle - 0.75 * pi); |
|---|
| 1043 | } |
|---|
| 1044 | if (left) { |
|---|
| 1045 | dx += labelheight * expand * 0.5 * firstlet[i] * cos(labangle - 0.25 * pi); |
|---|
| 1046 | dy += labelheight * expand * 0.5 * firstlet[i] * sin(labangle - 0.25 * pi); |
|---|
| 1047 | dx -= textlength[i] * labelheight * expand * cos(labangle); |
|---|
| 1048 | dy -= textlength[i] * labelheight * expand * sin(labangle); |
|---|
| 1049 | } |
|---|
| 1050 | |
|---|
| 1051 | plottext(lp->nayme, lp->naymlength, |
|---|
| 1052 | labelheight * expand * xscale / compr, compr, |
|---|
| 1053 | xscale * (lp->xcoord + dx + xoffset), |
|---|
| 1054 | yscale * (lp->ycoord + dy + yoffset), -180 * labangle / pi, |
|---|
| 1055 | font,fontname); |
|---|
| 1056 | } |
|---|
| 1057 | } |
|---|
| 1058 | if (penchange == yes) |
|---|
| 1059 | changepen(treepen); |
|---|
| 1060 | } /* plotlabels */ |
|---|
| 1061 | |
|---|
| 1062 | |
|---|
| 1063 | |
|---|
| 1064 | main(argc, argv) |
|---|
| 1065 | int argc; |
|---|
| 1066 | Char *argv[]; |
|---|
| 1067 | { |
|---|
| 1068 | long i,n,stripedepth; |
|---|
| 1069 | char filename1[100]; |
|---|
| 1070 | #ifdef MAC |
|---|
| 1071 | OSErr retcode; |
|---|
| 1072 | FInfo fndrinfo; |
|---|
| 1073 | macsetup("Drawtree","Preview"); |
|---|
| 1074 | #endif |
|---|
| 1075 | #ifdef TURBOC |
|---|
| 1076 | if ((registerbgidriver(EGAVGA_driver) <0) || |
|---|
| 1077 | (registerbgidriver(Herc_driver) <0) || |
|---|
| 1078 | (registerbgidriver(CGA_driver) <0)){ |
|---|
| 1079 | fprintf(stderr,"Graphics error: %s ",grapherrormsg(graphresult())); |
|---|
| 1080 | exit(-1);} |
|---|
| 1081 | #endif |
|---|
| 1082 | strcpy(fontname,"Hershey"); |
|---|
| 1083 | |
|---|
| 1084 | openfile(&plotfile,PLOTFILE,"w",argv[0],pltfilename); |
|---|
| 1085 | openfile(&treefile,TREEFILE,"r",argv[0],NULL); |
|---|
| 1086 | |
|---|
| 1087 | printf("DRAWTREE from PHYLIP version %s\n",VERSION); |
|---|
| 1088 | printf("Reading tree ... \n"); |
|---|
| 1089 | treeread(); |
|---|
| 1090 | printf("Tree has been read.\n"); |
|---|
| 1091 | printf("Loading the font ... \n"); |
|---|
| 1092 | loadfont(font,argv[0]); |
|---|
| 1093 | printf("Font loaded.\n"); |
|---|
| 1094 | previewing = false; |
|---|
| 1095 | initialparms(); |
|---|
| 1096 | |
|---|
| 1097 | canbeplotted = false; |
|---|
| 1098 | while (!canbeplotted) { |
|---|
| 1099 | do { |
|---|
| 1100 | n=showparms(); |
|---|
| 1101 | if ( n != -1) |
|---|
| 1102 | getparms(n); |
|---|
| 1103 | } while (n != -1); |
|---|
| 1104 | calculate(); |
|---|
| 1105 | rescale(); |
|---|
| 1106 | canbeplotted = true; |
|---|
| 1107 | if (preview) |
|---|
| 1108 | canbeplotted=plotpreview(fontname,&xoffset,&yoffset,&scale,ntips,root); |
|---|
| 1109 | } |
|---|
| 1110 | if (dotmatrix) { |
|---|
| 1111 | stripedepth = allocstripe(stripe,(strpwide/8), |
|---|
| 1112 | ((long)(yunitspercm * ysize))); |
|---|
| 1113 | strpdeep = stripedepth; |
|---|
| 1114 | strpdiv = stripedepth; |
|---|
| 1115 | } |
|---|
| 1116 | previewing = false; |
|---|
| 1117 | initplotter(ntips,fontname); |
|---|
| 1118 | numlines = dotmatrix ? ((long)floor(yunitspercm * ysize + 0.5)/strpdeep):1; if (plotter != ibmpc) |
|---|
| 1119 | printf("Writing plot file ...\n"); |
|---|
| 1120 | drawit(fontname,&xoffset,&yoffset,numlines,root); |
|---|
| 1121 | finishplotter(); |
|---|
| 1122 | printf("Finished.\n"); |
|---|
| 1123 | FClose(treefile); |
|---|
| 1124 | FClose(plotfile); |
|---|
| 1125 | printf("End of run.\n"); |
|---|
| 1126 | #ifdef MAC |
|---|
| 1127 | if (plotter == pict){ |
|---|
| 1128 | strcpy(filename1,pltfilename); |
|---|
| 1129 | retcode=GetFInfo(CtoPstr(filename1),0,&fndrinfo); |
|---|
| 1130 | fndrinfo.fdType='PICT'; |
|---|
| 1131 | fndrinfo.fdCreator='MDRW'; |
|---|
| 1132 | strcpy(filename1,pltfilename); |
|---|
| 1133 | retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);} |
|---|
| 1134 | if (plotter == lw){ |
|---|
| 1135 | retcode=GetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo); |
|---|
| 1136 | fndrinfo.fdType='TEXT'; |
|---|
| 1137 | retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);} |
|---|
| 1138 | #endif |
|---|
| 1139 | exit(0); |
|---|
| 1140 | } |
|---|
| 1141 | |
|---|
| 1142 | int eof(f) |
|---|
| 1143 | FILE *f; |
|---|
| 1144 | { |
|---|
| 1145 | register long ch; |
|---|
| 1146 | |
|---|
| 1147 | if (feof(f)) |
|---|
| 1148 | return 1; |
|---|
| 1149 | if (f == stdin) |
|---|
| 1150 | return 0; |
|---|
| 1151 | ch = getc(f); |
|---|
| 1152 | if (ch == EOF) |
|---|
| 1153 | return 1; |
|---|
| 1154 | ungetc(ch, f); |
|---|
| 1155 | return 0; |
|---|
| 1156 | } |
|---|
| 1157 | |
|---|
| 1158 | |
|---|
| 1159 | int eoln(f) |
|---|
| 1160 | FILE *f; |
|---|
| 1161 | { |
|---|
| 1162 | register long ch; |
|---|
| 1163 | |
|---|
| 1164 | ch = getc(f); |
|---|
| 1165 | if (ch == EOF) |
|---|
| 1166 | return 1; |
|---|
| 1167 | ungetc(ch, f); |
|---|
| 1168 | return (ch == '\n'); |
|---|
| 1169 | } |
|---|
| 1170 | |
|---|
| 1171 | |
|---|
| 1172 | void memerror() |
|---|
| 1173 | { |
|---|
| 1174 | printf("Error allocating memory\n"); |
|---|
| 1175 | exit(-1); |
|---|
| 1176 | } |
|---|
| 1177 | |
|---|
| 1178 | MALLOCRETURN *mymalloc(x) |
|---|
| 1179 | long x; |
|---|
| 1180 | { |
|---|
| 1181 | MALLOCRETURN *mem; |
|---|
| 1182 | mem = (MALLOCRETURN *)malloc(x); |
|---|
| 1183 | if (!mem) |
|---|
| 1184 | memerror(); |
|---|
| 1185 | else |
|---|
| 1186 | return (MALLOCRETURN *)mem; |
|---|
| 1187 | } |
|---|