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