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 | |
---|