| 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, and modify this |
|---|
| 7 | program provided that (1) this copyright message is not removed |
|---|
| 8 | and (2) no fee is charged for this program. */ |
|---|
| 9 | |
|---|
| 10 | FILE *treefile, *plotfile; |
|---|
| 11 | char pltfilename[100]; |
|---|
| 12 | long ntips, nextnode, strpwide, strpdeep,strpdiv, |
|---|
| 13 | strptop, strpbottom, payge, numlines; |
|---|
| 14 | boolean preview, previewing, dotmatrix, |
|---|
| 15 | haslengths, uselengths, empty, rescaled; |
|---|
| 16 | double xmargin, ymargin, topoflabels, rightoflabels, leftoflabels, |
|---|
| 17 | tipspacing,maxheight, scale, xscale, yscale, xoffset, yoffset, |
|---|
| 18 | nodespace, stemlength, treedepth, xnow, ynow, xunitspercm, yunitspercm, |
|---|
| 19 | xsize, ysize, xcorner, ycorner, labelheight,labelrotation,expand, rooty, |
|---|
| 20 | bscale; |
|---|
| 21 | striptype stripe; |
|---|
| 22 | plottertype plotter, oldplotter, previewer; |
|---|
| 23 | growth grows; |
|---|
| 24 | treestyle style; |
|---|
| 25 | node *root; |
|---|
| 26 | node *nodep[maxnodes]; |
|---|
| 27 | fonttype font; |
|---|
| 28 | long filesize; |
|---|
| 29 | Char ch; |
|---|
| 30 | char fontname[64]; |
|---|
| 31 | |
|---|
| 32 | enum { yes, no} penchange,oldpenchange; |
|---|
| 33 | static enum { weighted, intermediate, centered, inner, vshaped} nodeposition; |
|---|
| 34 | |
|---|
| 35 | |
|---|
| 36 | openfile(fp,filename,mode,application,perm) |
|---|
| 37 | FILE **fp; |
|---|
| 38 | char *filename; |
|---|
| 39 | char *mode; |
|---|
| 40 | char *application; |
|---|
| 41 | char *perm; |
|---|
| 42 | { |
|---|
| 43 | FILE *of; |
|---|
| 44 | char file[100]; |
|---|
| 45 | strcpy(file,filename); |
|---|
| 46 | while (1){ |
|---|
| 47 | of = fopen(file,mode); |
|---|
| 48 | if (of) |
|---|
| 49 | break; |
|---|
| 50 | else { |
|---|
| 51 | switch (*mode){ |
|---|
| 52 | case 'r': |
|---|
| 53 | printf("%s: can't read %s\n",application,file); |
|---|
| 54 | file[0] = '\0'; |
|---|
| 55 | while (file[0] =='\0'){ |
|---|
| 56 | printf("Please enter a new filename>"); |
|---|
| 57 | gets(file);} |
|---|
| 58 | break; |
|---|
| 59 | case 'w': |
|---|
| 60 | printf("%s: can't write %s\n",application,file); |
|---|
| 61 | file[0] = '\0'; |
|---|
| 62 | while (file[0] =='\0'){ |
|---|
| 63 | printf("Please enter a new filename>"); |
|---|
| 64 | gets(file);} |
|---|
| 65 | break; |
|---|
| 66 | } |
|---|
| 67 | } |
|---|
| 68 | } |
|---|
| 69 | *fp=of; |
|---|
| 70 | if (perm != NULL) |
|---|
| 71 | strcpy(perm,file); |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | void uppercase(ch) |
|---|
| 75 | Char *ch; |
|---|
| 76 | { /* make ch upper-case */ |
|---|
| 77 | *ch = (islower(*ch) ? toupper(*ch) : (*ch)); |
|---|
| 78 | } /* uppercase */ |
|---|
| 79 | |
|---|
| 80 | void getch(c) |
|---|
| 81 | Char *c; |
|---|
| 82 | { /* get next nonblank character */ |
|---|
| 83 | do { |
|---|
| 84 | *c=getc(treefile); } |
|---|
| 85 | while ((*c == ' ')||(*c == '\n')||(*c == '\t')); |
|---|
| 86 | } /* getch */ |
|---|
| 87 | |
|---|
| 88 | Void processlength(p) |
|---|
| 89 | node *p; |
|---|
| 90 | { |
|---|
| 91 | long digit, ordzero; |
|---|
| 92 | double valyew, divisor; |
|---|
| 93 | boolean pointread, minusread; |
|---|
| 94 | |
|---|
| 95 | ordzero = '0'; |
|---|
| 96 | pointread = false; |
|---|
| 97 | minusread = false; |
|---|
| 98 | valyew = 0.0; |
|---|
| 99 | divisor = 1.0; |
|---|
| 100 | getch(&ch); |
|---|
| 101 | digit = ch - ordzero; |
|---|
| 102 | while (((unsigned long)digit <= 9) | (ch == '.') || (ch == '-')){ |
|---|
| 103 | if (ch == '.') pointread = true; |
|---|
| 104 | else if (ch == '-') minusread = true; |
|---|
| 105 | else { |
|---|
| 106 | valyew = valyew * 10.0 + digit; |
|---|
| 107 | if (pointread) |
|---|
| 108 | divisor *= 10.0; |
|---|
| 109 | } |
|---|
| 110 | getch(&ch); |
|---|
| 111 | digit = ch - ordzero; |
|---|
| 112 | } |
|---|
| 113 | if (!minusread) |
|---|
| 114 | p->oldlen = valyew / divisor; |
|---|
| 115 | else |
|---|
| 116 | p->oldlen = 0.0; |
|---|
| 117 | /* processlength */ |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | void addelement(p, q) |
|---|
| 121 | node **p, *q; |
|---|
| 122 | { |
|---|
| 123 | /* read in and add next part of tree, it will be node p |
|---|
| 124 | and will be hooked to pointer q */ |
|---|
| 125 | node *pfirst; |
|---|
| 126 | long n; |
|---|
| 127 | boolean notlast; |
|---|
| 128 | |
|---|
| 129 | nextnode++; |
|---|
| 130 | *p = (node *)Malloc((long)sizeof(node)); |
|---|
| 131 | nodep[nextnode - 1] = *p; |
|---|
| 132 | if (ch == '(') { |
|---|
| 133 | (*p)->tip = false; |
|---|
| 134 | (*p)->tipsabove = 0; |
|---|
| 135 | pfirst = *p; |
|---|
| 136 | notlast = true; |
|---|
| 137 | while (notlast) { |
|---|
| 138 | (*p)->next = (node *)Malloc((long)sizeof(node)); |
|---|
| 139 | *p = (*p)->next; |
|---|
| 140 | (*p)->tip = false; |
|---|
| 141 | getch(&ch); |
|---|
| 142 | addelement(&(*p)->back, *p); |
|---|
| 143 | pfirst->tipsabove += (*p)->back->tipsabove; |
|---|
| 144 | if (ch == ')') { |
|---|
| 145 | notlast = false; |
|---|
| 146 | do { |
|---|
| 147 | getch(&ch); |
|---|
| 148 | } while (ch != ':' && ch != ',' && ch != ')' && ch != '[' && ch != ';'); |
|---|
| 149 | } |
|---|
| 150 | } |
|---|
| 151 | (*p)->next = pfirst; |
|---|
| 152 | *p = pfirst; |
|---|
| 153 | } else { |
|---|
| 154 | (*p)->tip = true; |
|---|
| 155 | (*p)->tipsabove = 1; |
|---|
| 156 | ntips++; |
|---|
| 157 | n = 1; |
|---|
| 158 | do { |
|---|
| 159 | if (ch == '_') |
|---|
| 160 | ch = ' '; |
|---|
| 161 | if (!ebcdic && (ch & 255) == 255) |
|---|
| 162 | ch = '\''; |
|---|
| 163 | if (!ebcdic && (ch & 255) > 175) |
|---|
| 164 | ch -= 48; |
|---|
| 165 | if (!ebcdic && (ch & (~127)) != 0) |
|---|
| 166 | ch -= 64; |
|---|
| 167 | if (n < maxnch) |
|---|
| 168 | (*p)->nayme[n - 1] = ch; |
|---|
| 169 | if (eoln(treefile)) { |
|---|
| 170 | fscanf(treefile, "%*[^\n]"); |
|---|
| 171 | getc(treefile); |
|---|
| 172 | } |
|---|
| 173 | ch = getc(treefile); |
|---|
| 174 | n++; |
|---|
| 175 | } while (ch != ':' && ch != ',' && ch != ')'); |
|---|
| 176 | if (n > maxnch) |
|---|
| 177 | n = maxnch + 1; |
|---|
| 178 | (*p)->naymlength = n - 1; |
|---|
| 179 | } |
|---|
| 180 | if (ch == ':') |
|---|
| 181 | processlength(*p); |
|---|
| 182 | else |
|---|
| 183 | haslengths = (haslengths && q == NULL); |
|---|
| 184 | (*p)->back = q; |
|---|
| 185 | } /* addelement */ |
|---|
| 186 | |
|---|
| 187 | |
|---|
| 188 | void treeread() |
|---|
| 189 | { |
|---|
| 190 | /* read a tree from the treefile and set up nodes and pointers */ |
|---|
| 191 | haslengths = true; |
|---|
| 192 | ntips = 0; |
|---|
| 193 | nextnode = 0; |
|---|
| 194 | getch(&ch); |
|---|
| 195 | addelement(&root, NULL); |
|---|
| 196 | fscanf(treefile, "%*[^\n]"); |
|---|
| 197 | getc(treefile); |
|---|
| 198 | uselengths = haslengths; |
|---|
| 199 | } /* treeread */ |
|---|
| 200 | |
|---|
| 201 | |
|---|
| 202 | |
|---|
| 203 | void initialparms() |
|---|
| 204 | { |
|---|
| 205 | /* initialize parameters */ |
|---|
| 206 | getplotter(); |
|---|
| 207 | plotrparms(); |
|---|
| 208 | if (dotmatrix) |
|---|
| 209 | numlines = (long)floor(yunitspercm * ysize + 0.5) / strpdeep; |
|---|
| 210 | xmargin = 0.08 * xsize; |
|---|
| 211 | ymargin = 0.08 * ysize; |
|---|
| 212 | xscale = xunitspercm; |
|---|
| 213 | yscale = yunitspercm; |
|---|
| 214 | style = cladogram; |
|---|
| 215 | grows = vertical; |
|---|
| 216 | labelrotation = 45.0; |
|---|
| 217 | nodespace = 3.0; |
|---|
| 218 | stemlength = 0.05; |
|---|
| 219 | treedepth = 0.5 / 0.95; |
|---|
| 220 | rescaled = true; |
|---|
| 221 | bscale = 1.0; |
|---|
| 222 | if (uselengths) |
|---|
| 223 | nodeposition = intermediate; |
|---|
| 224 | else |
|---|
| 225 | nodeposition = vshaped; |
|---|
| 226 | } /* initialparms */ |
|---|
| 227 | |
|---|
| 228 | |
|---|
| 229 | long showparms() |
|---|
| 230 | { |
|---|
| 231 | long i; |
|---|
| 232 | long numtochange; |
|---|
| 233 | char input[32]; |
|---|
| 234 | Char ch, ch2,trash; |
|---|
| 235 | |
|---|
| 236 | putchar('\n'); |
|---|
| 237 | if (previewer == tek) |
|---|
| 238 | printf("%c\f", escape); |
|---|
| 239 | else { |
|---|
| 240 | for (i = 1; i <= 24; i++) |
|---|
| 241 | putchar('\n'); |
|---|
| 242 | } |
|---|
| 243 | printf("Here are the settings: \n\n"); |
|---|
| 244 | printf(" (1) Tree grows: "); |
|---|
| 245 | printf((grows == vertical) ? "Vertically\n" : "Horizontally\n"); |
|---|
| 246 | printf(" (2) Style of tree: %s\n", |
|---|
| 247 | (style == cladogram) ? "Cladogram" : |
|---|
| 248 | (style == phenogram) ? "Phenogram" : |
|---|
| 249 | (style == curvogram) ? "Curvogram" : |
|---|
| 250 | (style == eurogram) ? "Eurogram" : "Swoopogram"); |
|---|
| 251 | |
|---|
| 252 | |
|---|
| 253 | printf(" (3) Use branch lengths: "); |
|---|
| 254 | if (haslengths) { |
|---|
| 255 | if (uselengths) |
|---|
| 256 | printf("Yes\n"); |
|---|
| 257 | else |
|---|
| 258 | printf("No\n"); |
|---|
| 259 | } else |
|---|
| 260 | printf("(no branch lengths available)\n"); |
|---|
| 261 | printf(" (4) Angle of labels:"); |
|---|
| 262 | if (labelrotation < 10.0) |
|---|
| 263 | printf("%5.1f\n", labelrotation); |
|---|
| 264 | else |
|---|
| 265 | printf("%6.1f\n", labelrotation); |
|---|
| 266 | if (plotter == ray) { |
|---|
| 267 | printf(" (5) Horizontal margins:%6.2f pixels\n", xmargin); |
|---|
| 268 | printf(" (5) Vertical margins:%6.2f pixels\n", ymargin); |
|---|
| 269 | } else { |
|---|
| 270 | printf(" (5) Horizontal margins:%6.2f cm\n", xmargin); |
|---|
| 271 | printf(" (5) Vertical margins:%6.2f cm\n", ymargin); |
|---|
| 272 | } |
|---|
| 273 | printf(" (6) Scale of branch length:"); |
|---|
| 274 | if (rescaled) |
|---|
| 275 | printf(" Automatically rescaled\n"); |
|---|
| 276 | else |
|---|
| 277 | printf(" Fixed:%6.2f cm per unit branch length\n", bscale); |
|---|
| 278 | printf(" (7) Depth/Breadth of tree:%6.2f\n", treedepth); |
|---|
| 279 | printf(" (8) Stem-length/tree-depth:%6.2f\n", stemlength); |
|---|
| 280 | printf(" (9) Character ht / tip space:%8.4f\n", 1.0 / nodespace); |
|---|
| 281 | printf("(10) Ancestral nodes: %s\n", |
|---|
| 282 | (nodeposition == weighted) ? "Weighted" : |
|---|
| 283 | (nodeposition == intermediate) ? "Intermediate" : |
|---|
| 284 | (nodeposition == centered) ? "Centered" : |
|---|
| 285 | (nodeposition == inner) ? "Inner" : |
|---|
| 286 | "So tree is V-shaped"); |
|---|
| 287 | if (plotter == lw) |
|---|
| 288 | printf("(11) Font : %s\n",fontname); |
|---|
| 289 | |
|---|
| 290 | printf("\n Do you want to accept these? (Yes or No)\n"); |
|---|
| 291 | for (;;) { |
|---|
| 292 | printf(" Type Y or N or the number (1-%2ld) of the one to change:\n", |
|---|
| 293 | ((plotter == lw) ? 11L : 10L)); |
|---|
| 294 | gets(input); |
|---|
| 295 | uppercase(&input[0]); |
|---|
| 296 | numtochange = atoi(input); |
|---|
| 297 | ch = input[0]; |
|---|
| 298 | if ((ch == 'Y' || ch == 'N') || (numtochange >= 1 && numtochange <= 11)) |
|---|
| 299 | break; |
|---|
| 300 | } |
|---|
| 301 | return (ch == 'Y') ? -1 : numtochange; |
|---|
| 302 | } /* showparms */ |
|---|
| 303 | |
|---|
| 304 | |
|---|
| 305 | void getparms(numtochange) |
|---|
| 306 | long numtochange; |
|---|
| 307 | { |
|---|
| 308 | /* get from user the relevant parameters for the plotter and diagram */ |
|---|
| 309 | Char ch,trash; |
|---|
| 310 | boolean ok; |
|---|
| 311 | |
|---|
| 312 | if (numtochange == 0) { |
|---|
| 313 | do { |
|---|
| 314 | printf(" Type the number of one that you want to change (1-%2ld):\n", |
|---|
| 315 | ((plotter == lw) ? 11L : 10L)); |
|---|
| 316 | scanf("%hd%*[^\n]", &numtochange); |
|---|
| 317 | trash=getchar(); |
|---|
| 318 | } while (numtochange < 1 || numtochange > ((plotter == lw) ? 11 : 10)); |
|---|
| 319 | } |
|---|
| 320 | switch (numtochange) { |
|---|
| 321 | |
|---|
| 322 | case 1: |
|---|
| 323 | if (grows == vertical) |
|---|
| 324 | grows = horizontal; |
|---|
| 325 | else |
|---|
| 326 | grows = vertical; |
|---|
| 327 | break; |
|---|
| 328 | |
|---|
| 329 | case 2: |
|---|
| 330 | printf("\nWhat style tree is this to be:\n"); |
|---|
| 331 | printf(" Cladogram, Phenogram, curVogram, Eurogram,"); |
|---|
| 332 | printf(" or Swoopogram\n"); |
|---|
| 333 | printf(" (C, P, V, E, or S)\n"); |
|---|
| 334 | do { |
|---|
| 335 | printf(" Choose one: \n"); |
|---|
| 336 | scanf("%c%*[^\n]", &ch); |
|---|
| 337 | trash=getchar(); |
|---|
| 338 | uppercase(&ch); |
|---|
| 339 | } while (ch != 'C' && ch != 'P' && ch != 'V' && ch != 'E' && ch != 'S'); |
|---|
| 340 | switch (ch) { |
|---|
| 341 | |
|---|
| 342 | case 'C': |
|---|
| 343 | style = cladogram; |
|---|
| 344 | break; |
|---|
| 345 | |
|---|
| 346 | case 'P': |
|---|
| 347 | style = phenogram; |
|---|
| 348 | break; |
|---|
| 349 | |
|---|
| 350 | case 'E': |
|---|
| 351 | style = eurogram; |
|---|
| 352 | break; |
|---|
| 353 | |
|---|
| 354 | case 'S': |
|---|
| 355 | style = swoopogram; |
|---|
| 356 | break; |
|---|
| 357 | |
|---|
| 358 | case 'V': |
|---|
| 359 | style = curvogram; |
|---|
| 360 | break; |
|---|
| 361 | } |
|---|
| 362 | break; |
|---|
| 363 | |
|---|
| 364 | case 3: |
|---|
| 365 | if (haslengths) { |
|---|
| 366 | uselengths = !uselengths; |
|---|
| 367 | if (!uselengths) |
|---|
| 368 | nodeposition = vshaped; |
|---|
| 369 | else |
|---|
| 370 | nodeposition = intermediate; |
|---|
| 371 | } else { |
|---|
| 372 | printf("Cannot use lengths since not all of them exist\n"); |
|---|
| 373 | uselengths = false; |
|---|
| 374 | } |
|---|
| 375 | break; |
|---|
| 376 | |
|---|
| 377 | case 4: |
|---|
| 378 | printf("\n(Considering the tree as if it \"grew\" vertically:)\n"); |
|---|
| 379 | printf("Are the labels to be plotted vertically (90),\n"); |
|---|
| 380 | printf(" horizontally (0), or at a 45-degree angle?\n"); |
|---|
| 381 | do { |
|---|
| 382 | printf(" Choose an angle in degrees from 90 to 0:\n"); |
|---|
| 383 | scanf("%lf%*[^\n]", &labelrotation); |
|---|
| 384 | trash=getchar(); |
|---|
| 385 | uppercase(&ch); |
|---|
| 386 | } while (labelrotation < 0.0 && labelrotation > 90.0); |
|---|
| 387 | break; |
|---|
| 388 | |
|---|
| 389 | case 5: |
|---|
| 390 | printf("\nThe tree will be drawn to fit in a rectangle which has \n"); |
|---|
| 391 | printf(" margins in the horizontal and vertical directions of:\n"); |
|---|
| 392 | if (plotter == ray) |
|---|
| 393 | printf("%6.2f pixels (horizontal margin) and%6.2f pixels (vertical margin)\n", |
|---|
| 394 | xmargin, ymargin); |
|---|
| 395 | else |
|---|
| 396 | printf("%6.2f cm (horizontal margin) and%6.2f cm (vertical margin)\n", |
|---|
| 397 | xmargin, ymargin); |
|---|
| 398 | putchar('\n'); |
|---|
| 399 | do { |
|---|
| 400 | if (plotter == ray) |
|---|
| 401 | printf(" New value (in pixels) of horizontal margin?\n"); |
|---|
| 402 | else |
|---|
| 403 | printf(" New value (in cm) of horizontal margin?\n"); |
|---|
| 404 | scanf("%lf%*[^\n]", &xmargin); |
|---|
| 405 | trash=getchar(); |
|---|
| 406 | ok = ((unsigned)xmargin < xsize / 2.0); |
|---|
| 407 | if (!ok) |
|---|
| 408 | printf(" Impossible value. Please retype it.\n"); |
|---|
| 409 | } while (!ok); |
|---|
| 410 | do { |
|---|
| 411 | if (plotter == ray) |
|---|
| 412 | printf(" New value (in pixels) of vertical margin?\n"); |
|---|
| 413 | else |
|---|
| 414 | printf(" New value (in cm) of vertical margin?\n"); |
|---|
| 415 | scanf("%lf%*[^\n]", &ymargin); |
|---|
| 416 | trash=getchar(); |
|---|
| 417 | ok = ((unsigned)ymargin < ysize / 2.0); |
|---|
| 418 | if (!ok) |
|---|
| 419 | printf(" Impossible value. Please retype it.\n"); |
|---|
| 420 | } while (!ok); |
|---|
| 421 | break; |
|---|
| 422 | |
|---|
| 423 | case 6: |
|---|
| 424 | rescaled = !rescaled; |
|---|
| 425 | if (!rescaled) { |
|---|
| 426 | printf("Centimeters per unit branch length?\n"); |
|---|
| 427 | scanf("%lf%*[^\n]", &bscale); |
|---|
| 428 | trash=getchar(); |
|---|
| 429 | } |
|---|
| 430 | break; |
|---|
| 431 | |
|---|
| 432 | case 7: |
|---|
| 433 | printf("New value of depth of tree as fraction of its breadth?\n"); |
|---|
| 434 | scanf("%lf%*[^\n]", &treedepth); |
|---|
| 435 | trash=getchar(); |
|---|
| 436 | break; |
|---|
| 437 | |
|---|
| 438 | case 8: |
|---|
| 439 | do { |
|---|
| 440 | printf("New value of stem length as fraction of tree depth?\n"); |
|---|
| 441 | scanf("%lf%*[^\n]", &stemlength); |
|---|
| 442 | trash=getchar(); |
|---|
| 443 | } while ((unsigned)stemlength >= 0.9); |
|---|
| 444 | break; |
|---|
| 445 | |
|---|
| 446 | case 9: |
|---|
| 447 | printf("New value of character height as fraction of tip spacing?\n"); |
|---|
| 448 | scanf("%lf%*[^\n]", &nodespace); |
|---|
| 449 | trash=getchar(); |
|---|
| 450 | nodespace = 1.0 / nodespace; |
|---|
| 451 | break; |
|---|
| 452 | |
|---|
| 453 | case 10: |
|---|
| 454 | printf("Should interior node positions:\n"); |
|---|
| 455 | printf(" be Intermediate between their immediate descendants,\n"); |
|---|
| 456 | printf(" Weighted average of tip positions\n"); |
|---|
| 457 | printf(" Centered among their ultimate descendants\n"); |
|---|
| 458 | printf(" iNnermost of immediate descendants\n"); |
|---|
| 459 | printf(" or so that tree is V-shaped\n"); |
|---|
| 460 | do { |
|---|
| 461 | printf(" (type I, W, C, N or V):\n"); |
|---|
| 462 | scanf("%c%*[^\n]", &ch); |
|---|
| 463 | trash=getchar(); |
|---|
| 464 | uppercase(&ch); |
|---|
| 465 | } while (ch != 'I' && ch != 'W' && ch != 'C' && ch != 'N' && ch != 'V'); |
|---|
| 466 | switch (ch) { |
|---|
| 467 | |
|---|
| 468 | case 'W': |
|---|
| 469 | nodeposition = weighted; |
|---|
| 470 | break; |
|---|
| 471 | |
|---|
| 472 | case 'I': |
|---|
| 473 | nodeposition = intermediate; |
|---|
| 474 | break; |
|---|
| 475 | |
|---|
| 476 | case 'C': |
|---|
| 477 | nodeposition = centered; |
|---|
| 478 | break; |
|---|
| 479 | |
|---|
| 480 | case 'N': |
|---|
| 481 | nodeposition = inner; |
|---|
| 482 | break; |
|---|
| 483 | |
|---|
| 484 | case 'V': |
|---|
| 485 | nodeposition = vshaped; |
|---|
| 486 | break; |
|---|
| 487 | } |
|---|
| 488 | break; |
|---|
| 489 | case 11: |
|---|
| 490 | printf("Enter font name or \"Hershey\" for the default font\n"); |
|---|
| 491 | gets(fontname); |
|---|
| 492 | break; |
|---|
| 493 | } |
|---|
| 494 | } /* getparms */ |
|---|
| 495 | |
|---|
| 496 | |
|---|
| 497 | |
|---|
| 498 | void calctraverse(p, lengthsum,tipx) |
|---|
| 499 | node *p; |
|---|
| 500 | double lengthsum; |
|---|
| 501 | double *tipx; |
|---|
| 502 | { |
|---|
| 503 | /* traverse to establish initial node coordinates */ |
|---|
| 504 | double x1, y1, x2, y2, x3, w1, w2, sumwx, sumw, nodeheight, rr; |
|---|
| 505 | node *pp, *plast; |
|---|
| 506 | |
|---|
| 507 | if (p == root) |
|---|
| 508 | nodeheight = 0.0; |
|---|
| 509 | else if (uselengths) |
|---|
| 510 | nodeheight = lengthsum + p->oldlen; |
|---|
| 511 | else |
|---|
| 512 | nodeheight = 1.0; |
|---|
| 513 | if (nodeheight > maxheight) |
|---|
| 514 | maxheight = nodeheight; |
|---|
| 515 | if (p->tip) { |
|---|
| 516 | p->xcoord = *tipx; |
|---|
| 517 | if (uselengths) |
|---|
| 518 | p->ycoord = nodeheight; |
|---|
| 519 | else |
|---|
| 520 | p->ycoord = 1.0; |
|---|
| 521 | *tipx += tipspacing; |
|---|
| 522 | return; |
|---|
| 523 | } |
|---|
| 524 | sumwx = 0.0; |
|---|
| 525 | sumw = 0.0; |
|---|
| 526 | pp = p->next; |
|---|
| 527 | x3 = 0.0; |
|---|
| 528 | do { |
|---|
| 529 | calctraverse(pp->back, nodeheight,tipx); |
|---|
| 530 | sumw += pp->back->tipsabove; |
|---|
| 531 | sumwx += pp->back->tipsabove * pp->back->xcoord; |
|---|
| 532 | if (fabs(pp->back->xcoord - 0.5) < fabs(x3 - 0.5)) |
|---|
| 533 | x3 = pp->back->xcoord; |
|---|
| 534 | plast = pp; |
|---|
| 535 | pp = pp->next; |
|---|
| 536 | } while (pp != p); |
|---|
| 537 | x1 = p->next->back->xcoord; |
|---|
| 538 | x2 = plast->back->xcoord; |
|---|
| 539 | y1 = p->next->back->ycoord; |
|---|
| 540 | y2 = plast->back->ycoord; |
|---|
| 541 | rr = 2 * (1.0 - stemlength) * treedepth * maxheight; |
|---|
| 542 | switch (nodeposition) { |
|---|
| 543 | |
|---|
| 544 | case weighted: |
|---|
| 545 | w1 = y1 - nodeheight; |
|---|
| 546 | w2 = y2 - nodeheight; |
|---|
| 547 | if (w1 + w2 <= 0.0) |
|---|
| 548 | p->xcoord = (x1 + x2) / 2.0; |
|---|
| 549 | else |
|---|
| 550 | p->xcoord = (w2 * x1 + w1 * x2) / (w1 + w2); |
|---|
| 551 | break; |
|---|
| 552 | |
|---|
| 553 | case intermediate: |
|---|
| 554 | p->xcoord = (x1 + x2) / 2.0; |
|---|
| 555 | break; |
|---|
| 556 | |
|---|
| 557 | case centered: |
|---|
| 558 | p->xcoord = sumwx / sumw; |
|---|
| 559 | break; |
|---|
| 560 | |
|---|
| 561 | case inner: |
|---|
| 562 | p->xcoord = x3; |
|---|
| 563 | break; |
|---|
| 564 | |
|---|
| 565 | case vshaped: |
|---|
| 566 | p->xcoord = (x1 + x2 + (y1 - y2) / rr) / 2.0; |
|---|
| 567 | break; |
|---|
| 568 | } |
|---|
| 569 | if (uselengths) { |
|---|
| 570 | p->ycoord = nodeheight; |
|---|
| 571 | return; |
|---|
| 572 | } |
|---|
| 573 | if (nodeposition != inner) { |
|---|
| 574 | p->ycoord = (y1 + y2 - sqrt((y1 + y2) * (y1 + y2) - 4 * (y1 * y2 - |
|---|
| 575 | rr * rr * (x2 - p->xcoord) * (p->xcoord - x1)))) / 2.0; |
|---|
| 576 | |
|---|
| 577 | return; |
|---|
| 578 | } |
|---|
| 579 | if (fabs(x1 - 0.5) > fabs(x2 - 0.5)) { |
|---|
| 580 | p->ycoord = y1 + x1 - x2; |
|---|
| 581 | w1 = y2 - p->ycoord; |
|---|
| 582 | } else { |
|---|
| 583 | p->ycoord = y2 + x1 - x2; |
|---|
| 584 | w1 = y1 - p->ycoord; |
|---|
| 585 | } |
|---|
| 586 | if (w1 < epsilon) |
|---|
| 587 | p->ycoord -= fabs(x1 - x2); |
|---|
| 588 | } /* calctraverse */ |
|---|
| 589 | |
|---|
| 590 | |
|---|
| 591 | void calculate() |
|---|
| 592 | { |
|---|
| 593 | /* compute coordinates for tree */ |
|---|
| 594 | double tipx; |
|---|
| 595 | double sum, maxtextlength, textlength, firstlet, fontheight, angle; |
|---|
| 596 | long i; |
|---|
| 597 | for (i = 0; i < nextnode; i++) |
|---|
| 598 | nodep[i]->xcoord = 0.0; |
|---|
| 599 | for (i = 0; i < nextnode; i++) |
|---|
| 600 | nodep[i]->ycoord = 0.0; |
|---|
| 601 | maxheight = 0.0; |
|---|
| 602 | maxtextlength = 0.0; |
|---|
| 603 | if (nodep[0]->naymlength > 0) |
|---|
| 604 | firstlet = lengthtext(nodep[0]->nayme, 1L,font); |
|---|
| 605 | else |
|---|
| 606 | firstlet = 0.0; |
|---|
| 607 | sum = 0.0; |
|---|
| 608 | tipx = 0.0; |
|---|
| 609 | for (i = 0; i < nextnode; i++) { |
|---|
| 610 | if (nodep[i]->tip) { |
|---|
| 611 | textlength = lengthtext(nodep[i]->nayme, nodep[i]->naymlength,font); |
|---|
| 612 | if (textlength > maxtextlength) |
|---|
| 613 | maxtextlength = textlength; |
|---|
| 614 | } |
|---|
| 615 | } |
|---|
| 616 | fontheight = font[2]; |
|---|
| 617 | angle = pi * labelrotation / 180.0; |
|---|
| 618 | maxtextlength /= fontheight; |
|---|
| 619 | textlength /= fontheight; |
|---|
| 620 | firstlet /= fontheight; |
|---|
| 621 | if (ntips > 1) |
|---|
| 622 | labelheight = 1.0 / (nodespace * (ntips - 1)); |
|---|
| 623 | else |
|---|
| 624 | labelheight = 1.0 / nodespace; |
|---|
| 625 | if (angle < pi / 6.0) |
|---|
| 626 | tipspacing = (nodespace + cos(angle) * (maxtextlength - 0.5)) * labelheight; |
|---|
| 627 | else if (ntips > 1) |
|---|
| 628 | tipspacing = 1.0 / (ntips - 1.0); |
|---|
| 629 | else |
|---|
| 630 | tipspacing = 1.0; |
|---|
| 631 | topoflabels = labelheight * |
|---|
| 632 | (1.0 + sin(angle) * (maxtextlength - 0.5) + cos(angle) * 0.5); |
|---|
| 633 | rightoflabels = labelheight * |
|---|
| 634 | (cos(angle) * (textlength - 0.5) + sin(angle) * 0.5); |
|---|
| 635 | leftoflabels = labelheight * (cos(angle) * firstlet * 0.5 + sin(angle) * 0.5); |
|---|
| 636 | calctraverse(root, sum, &tipx); |
|---|
| 637 | rooty = root->ycoord; |
|---|
| 638 | for (i = 0; i < nextnode; i++) { |
|---|
| 639 | if (rescaled) { |
|---|
| 640 | nodep[i]->xcoord *= 1.0 - stemlength; |
|---|
| 641 | nodep[i]->ycoord = stemlength * treedepth + (1.0 - stemlength) * |
|---|
| 642 | treedepth * (nodep[i]->ycoord - rooty) / (maxheight - rooty); |
|---|
| 643 | } else { |
|---|
| 644 | nodep[i]->xcoord = nodep[i]->xcoord * (maxheight - rooty) / treedepth; |
|---|
| 645 | nodep[i]->ycoord = stemlength / (1 - stemlength) * (maxheight - rooty) + |
|---|
| 646 | nodep[i]->ycoord; |
|---|
| 647 | } |
|---|
| 648 | } |
|---|
| 649 | rooty = 0.0; |
|---|
| 650 | } /* calculate */ |
|---|
| 651 | |
|---|
| 652 | |
|---|
| 653 | void rescale() |
|---|
| 654 | { |
|---|
| 655 | /* compute coordinates of tree for plot or preview device */ |
|---|
| 656 | long i; |
|---|
| 657 | double treeheight, treewidth, extrax, extray, temp; |
|---|
| 658 | |
|---|
| 659 | treeheight = 0.0; |
|---|
| 660 | for (i = 0; i < nextnode; i++) { |
|---|
| 661 | if (nodep[i]->ycoord > treeheight) |
|---|
| 662 | treeheight = nodep[i]->ycoord; |
|---|
| 663 | } |
|---|
| 664 | treewidth = (ntips - 1) * tipspacing + rightoflabels + leftoflabels; |
|---|
| 665 | if (rescaled) { |
|---|
| 666 | leftoflabels *= 1.0 - stemlength; |
|---|
| 667 | rightoflabels *= 1.0 - stemlength; |
|---|
| 668 | treewidth *= 1.0 - stemlength; |
|---|
| 669 | } else { |
|---|
| 670 | if (uselengths) { |
|---|
| 671 | labelheight = labelheight * (maxheight - rooty) / treedepth; |
|---|
| 672 | topoflabels = topoflabels * (maxheight - rooty) / treedepth; |
|---|
| 673 | leftoflabels = leftoflabels * (maxheight - rooty) / treedepth; |
|---|
| 674 | rightoflabels = rightoflabels * (maxheight - rooty) / treedepth; |
|---|
| 675 | treewidth = treewidth * (maxheight - rooty) / treedepth; |
|---|
| 676 | } |
|---|
| 677 | } |
|---|
| 678 | treeheight += topoflabels; |
|---|
| 679 | if (grows == vertical) { |
|---|
| 680 | if (!rescaled) |
|---|
| 681 | expand = bscale; |
|---|
| 682 | else { |
|---|
| 683 | expand = (xsize - 2 * xmargin) / treewidth; |
|---|
| 684 | if ((ysize - 2 * ymargin) / treeheight < expand) |
|---|
| 685 | expand = (ysize - 2 * ymargin) / treeheight; |
|---|
| 686 | } |
|---|
| 687 | extrax = (xsize - 2 * xmargin - treewidth * expand) / 2.0; |
|---|
| 688 | extray = (ysize - 2 * ymargin - treeheight * expand) / 2.0; |
|---|
| 689 | } else { |
|---|
| 690 | if (!rescaled) |
|---|
| 691 | expand = bscale; |
|---|
| 692 | else { |
|---|
| 693 | expand = (ysize - 2 * ymargin) / treewidth; |
|---|
| 694 | if ((xsize - 2 * xmargin) / treeheight < expand) |
|---|
| 695 | expand = (xsize - 2 * xmargin) / treeheight; |
|---|
| 696 | } |
|---|
| 697 | extrax = (xsize - 2 * xmargin - treeheight * expand) / 2.0; |
|---|
| 698 | extray = (ysize - 2 * ymargin - treewidth * expand) / 2.0; |
|---|
| 699 | } |
|---|
| 700 | for (i = 0; i < nextnode; i++) { |
|---|
| 701 | nodep[i]->xcoord = expand * (nodep[i]->xcoord + leftoflabels); |
|---|
| 702 | nodep[i]->ycoord = expand * (nodep[i]->ycoord - rooty); |
|---|
| 703 | if (grows == horizontal) { |
|---|
| 704 | temp = nodep[i]->ycoord; |
|---|
| 705 | nodep[i]->ycoord = expand * treewidth - nodep[i]->xcoord; |
|---|
| 706 | nodep[i]->xcoord = temp; |
|---|
| 707 | } |
|---|
| 708 | nodep[i]->xcoord += xmargin + extrax; |
|---|
| 709 | nodep[i]->ycoord += ymargin + extray; |
|---|
| 710 | } |
|---|
| 711 | if (grows == vertical) |
|---|
| 712 | rooty = ymargin + extray; |
|---|
| 713 | else |
|---|
| 714 | rooty = xmargin + extrax; |
|---|
| 715 | } /* rescale */ |
|---|
| 716 | |
|---|
| 717 | |
|---|
| 718 | |
|---|
| 719 | void plottree(p, q) |
|---|
| 720 | node *p, *q; |
|---|
| 721 | { |
|---|
| 722 | /* plot part or all of tree on the plotting device */ |
|---|
| 723 | long i; |
|---|
| 724 | double x1, y1, x2, y2, x3, y3, f, g, h, fract, minny, miny; |
|---|
| 725 | node *pp; |
|---|
| 726 | |
|---|
| 727 | x2 = xscale * (xoffset + p->xcoord); |
|---|
| 728 | y2 = yscale * (yoffset + p->ycoord); |
|---|
| 729 | if (p != root) { |
|---|
| 730 | x1 = xscale * (xoffset + q->xcoord); |
|---|
| 731 | y1 = yscale * (yoffset + q->ycoord); |
|---|
| 732 | plot(penup, x1, y1); |
|---|
| 733 | switch (style) { |
|---|
| 734 | |
|---|
| 735 | case cladogram: |
|---|
| 736 | plot(pendown, x2, y2); |
|---|
| 737 | break; |
|---|
| 738 | |
|---|
| 739 | case phenogram: |
|---|
| 740 | if (grows == vertical) |
|---|
| 741 | plot(pendown, x2, y1); |
|---|
| 742 | else |
|---|
| 743 | plot(pendown, x1, y2); |
|---|
| 744 | plot(pendown, x2, y2); |
|---|
| 745 | break; |
|---|
| 746 | |
|---|
| 747 | case curvogram: |
|---|
| 748 | for (i = 1; i <= segments; i++) { |
|---|
| 749 | f = (double)i / segments; |
|---|
| 750 | g = (double)i / segments; |
|---|
| 751 | h = 1.0 - sqrt(1.0 - g * g); |
|---|
| 752 | if (grows == vertical) { |
|---|
| 753 | x3 = x1 * (1.0 - f) + x2 * f; |
|---|
| 754 | y3 = y1 + (y2 - y1) * h; |
|---|
| 755 | } else { |
|---|
| 756 | x3 = x1 + (x2 - x1) * h; |
|---|
| 757 | y3 = y1 * (1.0 - f) + y2 * f; |
|---|
| 758 | } |
|---|
| 759 | plot(pendown, x3, y3); |
|---|
| 760 | } |
|---|
| 761 | break; |
|---|
| 762 | |
|---|
| 763 | case eurogram: |
|---|
| 764 | if (grows == vertical) |
|---|
| 765 | plot(pendown, x2, (2 * y1 + y2) / 3); |
|---|
| 766 | else |
|---|
| 767 | plot(pendown, (2 * x1 + x2) / 3, y2); |
|---|
| 768 | plot(pendown, x2, y2); |
|---|
| 769 | break; |
|---|
| 770 | |
|---|
| 771 | case swoopogram: |
|---|
| 772 | if ((grows == vertical && fabs(y1 - y2) >= epsilon) || |
|---|
| 773 | (grows == horizontal && fabs(x1 - x2) >= epsilon)) { |
|---|
| 774 | if (grows == vertical) |
|---|
| 775 | miny = p->ycoord; |
|---|
| 776 | else |
|---|
| 777 | miny = p->xcoord; |
|---|
| 778 | pp = q->next; |
|---|
| 779 | while (pp != q) { |
|---|
| 780 | if (grows == vertical) |
|---|
| 781 | minny = pp->back->ycoord; |
|---|
| 782 | else |
|---|
| 783 | minny = pp->back->xcoord; |
|---|
| 784 | if (minny < miny) |
|---|
| 785 | miny = minny; |
|---|
| 786 | pp = pp->next; |
|---|
| 787 | } |
|---|
| 788 | if (grows == vertical) |
|---|
| 789 | miny = yscale * (yoffset + miny); |
|---|
| 790 | else |
|---|
| 791 | miny = xscale * (xoffset + miny); |
|---|
| 792 | if (grows == vertical) |
|---|
| 793 | fract = 0.3333 * (miny - y1) / (y2 - y1); |
|---|
| 794 | else |
|---|
| 795 | fract = 0.3333 * (miny - x1) / (x2 - x1); |
|---|
| 796 | for (i = 1; i <= segments; i++) { |
|---|
| 797 | f = (double)i / segments; |
|---|
| 798 | if (f < fract) |
|---|
| 799 | g = f / fract; |
|---|
| 800 | else |
|---|
| 801 | g = (f - fract) / (1.0 - fract); |
|---|
| 802 | if (f < fract) |
|---|
| 803 | h = fract * sqrt(1.0 - (1.0 - g) * (1.0 - g)); |
|---|
| 804 | else |
|---|
| 805 | h = fract + (1.0 - fract) * (1.000001 - sqrt(1.000001 - g * g)); |
|---|
| 806 | if (grows == vertical) { |
|---|
| 807 | x3 = x1 * (1.0 - f) + x2 * f; |
|---|
| 808 | y3 = y1 + (y2 - y1) * h; |
|---|
| 809 | } else { |
|---|
| 810 | x3 = x1 + (x2 - x1) * h; |
|---|
| 811 | y3 = y1 * (1.0 - f) + y2 * f; |
|---|
| 812 | } |
|---|
| 813 | plot(pendown, x3, y3); |
|---|
| 814 | } |
|---|
| 815 | } |
|---|
| 816 | break; |
|---|
| 817 | } |
|---|
| 818 | } else { |
|---|
| 819 | if (grows == vertical) { |
|---|
| 820 | x1 = xscale * (xoffset + p->xcoord); |
|---|
| 821 | y1 = yscale * (yoffset + rooty); |
|---|
| 822 | } else { |
|---|
| 823 | x1 = xscale * (xoffset + rooty); |
|---|
| 824 | y1 = yscale * (yoffset + p->ycoord); |
|---|
| 825 | } |
|---|
| 826 | plot(penup, x1, y1); |
|---|
| 827 | plot(pendown, x2, y2); |
|---|
| 828 | } |
|---|
| 829 | if (p->tip) |
|---|
| 830 | return; |
|---|
| 831 | pp = p->next; |
|---|
| 832 | while (pp != p) { |
|---|
| 833 | plottree(pp->back, p); |
|---|
| 834 | pp = pp->next; |
|---|
| 835 | } |
|---|
| 836 | } /* plottree */ |
|---|
| 837 | |
|---|
| 838 | |
|---|
| 839 | |
|---|
| 840 | void plotlabels(fontname) |
|---|
| 841 | char *fontname; |
|---|
| 842 | { |
|---|
| 843 | long i; |
|---|
| 844 | double compr, dx, dy, angle; |
|---|
| 845 | node *lp; |
|---|
| 846 | |
|---|
| 847 | compr = xunitspercm / yunitspercm; |
|---|
| 848 | if (penchange == yes) |
|---|
| 849 | changepen(labelpen); |
|---|
| 850 | angle = labelrotation * pi / 180.0; |
|---|
| 851 | for (i = 0; i < (nextnode); i++) { |
|---|
| 852 | if (nodep[i]->tip) { |
|---|
| 853 | lp = nodep[i]; |
|---|
| 854 | dx = labelheight * expand * -0.70710 * cos(angle + pi / 4.0); |
|---|
| 855 | dy = labelheight * expand * (1.0 - 0.70710 * sin(angle + pi / 4.0)); |
|---|
| 856 | if (grows == vertical) |
|---|
| 857 | plottext(lp->nayme, lp->naymlength, |
|---|
| 858 | labelheight * expand * xscale / compr, compr, |
|---|
| 859 | xscale * (lp->xcoord + dx + xoffset), |
|---|
| 860 | yscale * (lp->ycoord + dy + yoffset), |
|---|
| 861 | -labelrotation, font,fontname); |
|---|
| 862 | else |
|---|
| 863 | plottext(lp->nayme, lp->naymlength, labelheight * expand * yscale, |
|---|
| 864 | compr, xscale * (lp->xcoord + dy + xoffset), |
|---|
| 865 | yscale * (lp->ycoord - dx + yoffset), 90.0 - labelrotation, |
|---|
| 866 | font,fontname); |
|---|
| 867 | } |
|---|
| 868 | } |
|---|
| 869 | if (penchange == yes) |
|---|
| 870 | changepen(treepen); |
|---|
| 871 | } /* plotlabels */ |
|---|
| 872 | |
|---|
| 873 | |
|---|
| 874 | |
|---|
| 875 | main(argc, argv) |
|---|
| 876 | long argc; |
|---|
| 877 | Char *argv[]; |
|---|
| 878 | { |
|---|
| 879 | long i,n,stripedepth; |
|---|
| 880 | boolean canbeplotted; |
|---|
| 881 | |
|---|
| 882 | #ifdef MAC |
|---|
| 883 | OSErr retcode; |
|---|
| 884 | FInfo fndrinfo; |
|---|
| 885 | macsetup("Drawgram","Preview"); |
|---|
| 886 | #endif |
|---|
| 887 | #ifdef TURBOC |
|---|
| 888 | if ((registerbgidriver(EGAVGA_driver) <0) || |
|---|
| 889 | (registerbgidriver(Herc_driver) <0) || |
|---|
| 890 | (registerbgidriver(CGA_driver) <0)){ |
|---|
| 891 | printf("Graphics error: %s ",grapherrormsg(graphresult())); |
|---|
| 892 | exit(-1);} |
|---|
| 893 | #endif |
|---|
| 894 | strcpy(fontname,"Hershey"); |
|---|
| 895 | |
|---|
| 896 | openfile(&plotfile,PLOTFILE,"w",argv[0],pltfilename); |
|---|
| 897 | openfile(&treefile,TREEFILE,"r",argv[0],NULL); |
|---|
| 898 | |
|---|
| 899 | printf("DRAWGRAM from PHYLIP version %s\n",VERSION); |
|---|
| 900 | printf("Reading tree ... \n"); |
|---|
| 901 | treeread(); |
|---|
| 902 | |
|---|
| 903 | printf("Tree has been read.\nLoading the font .... \n"); |
|---|
| 904 | loadfont(font,argv[0]); |
|---|
| 905 | printf("Font loaded.\n"); |
|---|
| 906 | previewing = false; |
|---|
| 907 | initialparms(); |
|---|
| 908 | canbeplotted = false; |
|---|
| 909 | while (!canbeplotted) { |
|---|
| 910 | do { |
|---|
| 911 | n=showparms(); |
|---|
| 912 | if (n != -1) |
|---|
| 913 | getparms(n); |
|---|
| 914 | } while (n != -1); |
|---|
| 915 | calculate(); |
|---|
| 916 | rescale(); |
|---|
| 917 | canbeplotted = true; |
|---|
| 918 | if (preview) |
|---|
| 919 | canbeplotted=plotpreview(fontname,&xoffset,&yoffset,&scale,ntips,root); |
|---|
| 920 | } |
|---|
| 921 | if (dotmatrix) { |
|---|
| 922 | stripedepth = allocstripe(stripe,(strpwide/8), |
|---|
| 923 | ((long)(yunitspercm * ysize))); |
|---|
| 924 | strpdeep = stripedepth; |
|---|
| 925 | strpdiv = stripedepth; |
|---|
| 926 | } |
|---|
| 927 | previewing = false; |
|---|
| 928 | initplotter(ntips,fontname); |
|---|
| 929 | numlines = dotmatrix ? ((long)floor(yunitspercm * ysize + 0.5)/strpdeep) : 1; |
|---|
| 930 | if (plotter != ibmpc) |
|---|
| 931 | printf("Writing plot file ...\n"); |
|---|
| 932 | drawit(fontname,&xoffset,&yoffset,numlines,root); |
|---|
| 933 | finishplotter(); |
|---|
| 934 | FClose(plotfile); |
|---|
| 935 | FClose(treefile); |
|---|
| 936 | printf("Finished.\nEnd of run.\n"); |
|---|
| 937 | #ifdef MAC |
|---|
| 938 | if (plotter == pict){ |
|---|
| 939 | retcode=GetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo); |
|---|
| 940 | fndrinfo.fdType='PICT'; |
|---|
| 941 | fndrinfo.fdCreator='MDRW'; |
|---|
| 942 | retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);} |
|---|
| 943 | if (plotter == lw){ |
|---|
| 944 | retcode=GetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo); |
|---|
| 945 | fndrinfo.fdType='TEXT'; |
|---|
| 946 | retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);} |
|---|
| 947 | #endif |
|---|
| 948 | exit(0); |
|---|
| 949 | } |
|---|
| 950 | |
|---|
| 951 | |
|---|
| 952 | |
|---|
| 953 | int eof(f) |
|---|
| 954 | FILE *f; |
|---|
| 955 | { |
|---|
| 956 | register long ch; |
|---|
| 957 | |
|---|
| 958 | if (feof(f)) |
|---|
| 959 | return 1; |
|---|
| 960 | if (f == stdin) |
|---|
| 961 | return 0; |
|---|
| 962 | ch = getc(f); |
|---|
| 963 | if (ch == EOF) |
|---|
| 964 | return 1; |
|---|
| 965 | ungetc(ch, f); |
|---|
| 966 | return 0; |
|---|
| 967 | } |
|---|
| 968 | |
|---|
| 969 | |
|---|
| 970 | int eoln(f) |
|---|
| 971 | FILE *f; |
|---|
| 972 | { |
|---|
| 973 | register long ch; |
|---|
| 974 | |
|---|
| 975 | ch = getc(f); |
|---|
| 976 | if (ch == EOF) |
|---|
| 977 | return 1; |
|---|
| 978 | ungetc(ch, f); |
|---|
| 979 | return (ch == '\n'); |
|---|
| 980 | } |
|---|
| 981 | |
|---|
| 982 | void memerror() |
|---|
| 983 | { |
|---|
| 984 | printf("Error allocating memory\n"); |
|---|
| 985 | exit(-1); |
|---|
| 986 | } |
|---|
| 987 | |
|---|
| 988 | MALLOCRETURN *mymalloc(x) |
|---|
| 989 | long x; |
|---|
| 990 | { |
|---|
| 991 | MALLOCRETURN *mem; |
|---|
| 992 | mem = (MALLOCRETURN *)malloc((size_t)x); |
|---|
| 993 | if (!mem) |
|---|
| 994 | memerror(); |
|---|
| 995 | else |
|---|
| 996 | return (MALLOCRETURN *)mem; |
|---|
| 997 | |
|---|
| 998 | } |
|---|
| 999 | |
|---|