1 /* draw.c */
2
3 #include "../Tree.h"
4
5 #define MYDEBUG 1
6
7 /*--------------------------------------------------------------------*/
8 static void
9 findLocalCoords ( int n, double x[], double xloc[], double rscale,
10 double radius[], double xmin, double xmax ) ;
11 /*--------------------------------------------------------------------*/
12 /*
13 ------------------------------------------------------------
14 purpose -- to write an EPS file with a picture of a tree.
15 each node can have its own radius and label
16
17 filename -- name of the file to be written
18 xDV -- x coordinates
19 yDV -- y coordinates
20 rscale -- scaling factor for radius of nodes
21 radiusDV -- radius of nodes, if NULL then radius = 1
22 labelflag -- flag to specify whether labels are to be drawn
23 1 -- draw labels
24 otherwise -- do not draw labels
25 fontscale -- scaling factor for font
26 labelsIV -- IV object that contains the labels of the nodes.
27 if NULL then the node ids are used
28 bbox[] -- bounding box for figure
29 bbox[0] -- x_min
30 bbox[1] -- y_min
31 bbox[2] -- x_max
32 bbox[3] -- y_max
33 frame[] -- frame to hold tree
34 frame[0] -- x_min
35 frame[1] -- y_min
36 frame[2] -- x_max
37 frame[3] -- y_max
38 bounds[] -- bounds for local coordinates
39 if bounds is NULL then
40 the tree fills the frame. note, this is a nonlinear process
41 when the nodes have non-constant radii, and may not converge
42 when the maximum radius is large when compared to the frame.
43 if the process does not converge, a message is printed and
44 the program exits.
45 else
46 bounds[0] -- xi_min
47 bounds[1] -- eta_min
48 bounds[2] -- xi_max
49 bounds[3] -- eta_max
50 endif
51
52 recommendations,
53 bbox[] = { 0, 0, 500, 200 } for tall skinny trees
54 { 0, 0, 500, 500 } for wide trees
55 frame[0] = bbox[0] + 10
56 frame[1] = bbox[1] + 10
57 frame[2] = bbox[2] - 10
58 frame[3] = bbox[3] - 10
59
60 return value
61 1 -- normal return
62 -1 -- tree is NULL
63 -2 -- filename is NULL
64 -3 -- xDV is NULL
65 -4 -- yDV is NULL
66 -5 -- rscale is negative
67 -6 -- fontscale is negative
68 -7 -- bbox is NULL
69 -8 -- frame is NULL
70
71 created -- 99jan07, cca
72 ------------------------------------------------------------
73 */
74 int
Tree_drawToEPS(Tree * tree,char * filename,DV * xDV,DV * yDV,double rscale,DV * radiusDV,int labelflag,double fontscale,IV * labelsIV,double bbox[],double frame[],double bounds[])75 Tree_drawToEPS (
76 Tree *tree,
77 char *filename,
78 DV *xDV,
79 DV *yDV,
80 double rscale,
81 DV *radiusDV,
82 int labelflag,
83 double fontscale,
84 IV *labelsIV,
85 double bbox[],
86 double frame[],
87 double bounds[]
88 ) {
89 double etamax, etamin, ximax, ximin, xmax, xmin, xrmax, xrmin,
90 xscale, ymax, ymin, yrmax, yrmin, yscale ;
91 double *radius, *x, *xloc, *y, *yloc ;
92 FILE *fp ;
93 int count, J, K, n ;
94 int *fch, *par, *sib ;
95 /*
96 ---------------
97 check the input
98 ---------------
99 */
100 if ( tree == NULL ) {
101 fprintf(stderr, "\n error in Tree_drawToEPS()"
102 "\n tree is NULL\n") ;
103 return(-1) ;
104 }
105 if ( filename == NULL ) {
106 fprintf(stderr, "\n error in Tree_drawToEPS()"
107 "\n filename is NULL\n") ;
108 return(-2) ;
109 }
110 if ( xDV == NULL ) {
111 fprintf(stderr, "\n error in Tree_drawToEPS()"
112 "\n xDV is NULL\n") ;
113 return(-3) ;
114 }
115 if ( yDV == NULL ) {
116 fprintf(stderr, "\n error in Tree_drawToEPS()"
117 "\n yDV is NULL\n") ;
118 return(-4) ;
119 }
120 if ( rscale < 0.0 ) {
121 fprintf(stderr, "\n error in Tree_drawToEPS()"
122 "\n rscale is negative\n") ;
123 return(-5) ;
124 }
125 if ( fontscale < 0.0 ) {
126 fprintf(stderr, "\n error in Tree_drawToEPS()"
127 "\n fontscale is negative\n") ;
128 return(-6) ;
129 }
130 if ( bbox == NULL ) {
131 fprintf(stderr, "\n error in Tree_drawToEPS()"
132 "\n bbox is NULL\n") ;
133 return(-7) ;
134 }
135 if ( frame == NULL ) {
136 fprintf(stderr, "\n error in Tree_drawToEPS()"
137 "\n frame is NULL\n") ;
138 return(-8) ;
139 }
140 n = tree->n ;
141 par = tree->par ;
142 fch = tree->fch ;
143 sib = tree->sib ;
144 x = DV_entries(xDV) ;
145 y = DV_entries(yDV) ;
146 if ( radiusDV != NULL ) {
147 radius = DV_entries(radiusDV) ;
148 } else {
149 radius = NULL ;
150 }
151 #if MYDEBUG > 0
152 fprintf(stdout, "\n\n x") ;
153 DVfprintf(stdout, n, x) ;
154 fprintf(stdout, "\n\n y") ;
155 DVfprintf(stdout, n, y) ;
156 if ( radius != NULL ) {
157 fprintf(stdout, "\n\n radius") ;
158 DVfprintf(stdout, n, radius) ;
159 }
160 #endif
161 xloc = DVinit(n, 0.0) ;
162 yloc = DVinit(n, 0.0) ;
163 if ( bounds != NULL ) {
164 /*
165 ------------------------------------------
166 get the local coordinates w.r.t the bounds
167 ------------------------------------------
168 */
169 double etamax, etamin, ximax, ximin, xmax, xmin, xoff, xscale,
170 ymax, ymin, yoff, yscale ;
171 xmin = frame[0] ; xmax = frame[2] ;
172 ximin = bounds[0] ; ximax = bounds[2] ;
173 xoff = (xmin*ximax - xmax*ximin)/(ximax - ximin) ;
174 xscale = (xmax - xmin)/(ximax - ximin) ;
175 for ( J = 0 ; J < n ; J++ ) {
176 xloc[J] = xoff + xscale*x[J] ;
177 }
178 ymin = frame[1] ; ymax = frame[3] ;
179 etamin = bounds[1] ; etamax = bounds[3] ;
180 yoff = (ymin*etamax - ymax*etamin)/(etamax - etamin) ;
181 yscale = (ymax - ymin)/(etamax - etamin) ;
182 for ( J = 0 ; J < n ; J++ ) {
183 yloc[J] = yoff + yscale*y[J] ;
184 }
185 } else {
186 /*
187 -----------------------------------------
188 scale x[] and y[] to fit within the frame
189 -----------------------------------------
190 */
191 xmin = frame[0] ;
192 ymin = frame[1] ;
193 xmax = frame[2] ;
194 ymax = frame[3] ;
195 #if MYDEBUG > 0
196 fprintf(stdout, "\n\n xmin = %.3g, xmax = %.3g", xmin, xmax) ;
197 #endif
198 findLocalCoords(n, x, xloc, rscale, radius, xmin, xmax) ;
199 #if MYDEBUG > 0
200 fprintf(stdout, "\n\n ymin = %.3g, ymax = %.3g", ymin, ymax) ;
201 #endif
202 findLocalCoords(n, y, yloc, rscale, radius, ymin, ymax) ;
203 }
204 #if MYDEBUG > 0
205 fprintf(stdout, "\n\n xloc") ;
206 DVfprintf(stdout, n, xloc) ;
207 #endif
208 #if MYDEBUG > 0
209 fprintf(stdout, "\n\n yloc") ;
210 DVfprintf(stdout, n, yloc) ;
211 #endif
212 /*
213 -------------
214 open the file
215 -------------
216 */
217 if ( (fp = fopen(filename, "w")) == NULL ) {
218 fprintf(stderr, "\n unable to open file %s", filename) ;
219 exit(-1) ;
220 }
221 /*
222 ----------------------------
223 print the header information
224 ----------------------------
225 */
226 fprintf(fp,
227 "%%!PS-Adobe-2.0 EPSF-1.2"
228 "\n%%%%BoundingBox: %.3g %.3g %.3g %.3g",
229 bbox[0], bbox[1], bbox[2], bbox[3]) ;
230 fprintf(fp,
231 "\n /CSH {"
232 "\n %%"
233 "\n %% center show a string"
234 "\n %%"
235 "\n %% stack"
236 "\n %% string str"
237 "\n %%"
238 "\n dup stringwidth pop 2 div neg 0 rmoveto"
239 "\n show"
240 "\n } def") ;
241 fprintf(fp,
242 "\n /ML {"
243 "\n %%"
244 "\n %% moveto lineto"
245 "\n %%"
246 "\n %% stack"
247 "\n %% x0 y0 x1 y1"
248 "\n %%"
249 "\n moveto lineto"
250 "\n } def") ;
251 fprintf(fp,
252 "\n /FC {"
253 "\n %%"
254 "\n %% draw filled circle"
255 "\n %%"
256 "\n %% stack"
257 "\n %% x y r"
258 "\n %%"
259 "\n newpath 2 index 1 index add 2 index moveto 0 360 arc fill"
260 "\n } def") ;
261 fprintf(fp,
262 "\n /OC {"
263 "\n %%"
264 "\n %% draw open circle"
265 "\n %%"
266 "\n %% stack"
267 "\n %% x y r"
268 "\n %%"
269 "\n newpath 2 index 1 index add 2 index moveto 0 360 arc stroke"
270 "\n } def") ;
271 fprintf(fp, "\n /rscale %.3f def", rscale) ;
272 fprintf(fp, "\n /fontscale %.3f def", fontscale) ;
273 /*
274 --------------
275 draw the edges
276 --------------
277 */
278 fprintf(fp, "\n %.3g %.3g %.3g %.3g rectclip",
279 frame[0], frame[1], frame[2] - frame[0], frame[3] - frame[1]) ;
280 par = tree->par ;
281 count = 0 ;
282 for ( J = 0 ; J < n ; J++ ) {
283 if ( (K = par[J]) != -1 ) {
284 if ( count == 0 ) {
285 fprintf(fp, "\n newpath") ;
286 }
287 fprintf(fp, "\n %.3g %.3g %.3g %.3g ML",
288 xloc[J], yloc[J], xloc[K], yloc[K]) ;
289 count++ ;
290 if ( count == 100 ) {
291 fprintf(fp, "\n stroke") ;
292 count = 0 ;
293 }
294 }
295 }
296 if ( count > 0 ) {
297 fprintf(fp, "\n stroke") ;
298 }
299 /*
300 -------------------------
301 draw the nodes and labels
302 -------------------------
303 */
304 fprintf(fp, "\n\n gsave") ;
305 if ( labelflag == 1 ) {
306 fprintf(fp,
307 "\n /Helvetica-Bold findfont fontscale scalefont setfont") ;
308 }
309 if ( radius == NULL ) {
310 for ( J = 0 ; J < n ; J++ ) {
311 fprintf(fp, "\n 1.0 setgray") ;
312 fprintf(fp, " %.3g %.3g %.3g FC",
313 xloc[J], yloc[J], rscale) ;
314 fprintf(fp, "\n 0.0 setgray") ;
315 fprintf(fp, " %.3g %.3g %.3g OC",
316 xloc[J], yloc[J], rscale) ;
317 if ( labelflag == 1 ) {
318 fprintf(fp, "\n %.3g %.3g moveto ",
319 xloc[J], yloc[J] - 0.5*rscale) ;
320 if ( labelsIV != NULL ) {
321 fprintf(fp, " (%d) CSH", IV_entry(labelsIV, J)) ;
322 } else {
323 fprintf(fp, " (%d) CSH", J) ;
324 }
325 }
326 }
327 } else {
328 for ( J = 0 ; J < n ; J++ ) {
329 fprintf(fp, "\n 1.0 setgray") ;
330 fprintf(fp, " %.3g %.3g %.3g FC",
331 xloc[J], yloc[J], rscale*radius[J]) ;
332 fprintf(fp, "\n 0.0 setgray") ;
333 fprintf(fp, " %.3g %.3g %.3g OC",
334 xloc[J], yloc[J], rscale*radius[J]) ;
335 if ( labelflag == 1 ) {
336 fprintf(fp, "\n %.3g %.3g %.3g sub moveto ",
337 xloc[J], yloc[J], 0.25*fontscale) ;
338 if ( labelsIV != NULL ) {
339 fprintf(fp, " (%d) CSH", IV_entry(labelsIV, J)) ;
340 } else {
341 fprintf(fp, " (%d) CSH", J) ;
342 }
343 }
344 }
345 }
346 fprintf(fp, "\n\n grestore") ;
347 fprintf(fp, "\n %.3g %.3g %.3g %.3g rectstroke",
348 frame[0], frame[1], frame[2] - frame[0], frame[3] - frame[1]) ;
349 fprintf(fp, "\n\n showpage") ;
350
351 return(1) ; }
352
353 /*--------------------------------------------------------------------*/
354 static void
findLocalCoords(int n,double x[],double xloc[],double rscale,double radius[],double xmin,double xmax)355 findLocalCoords (
356 int n,
357 double x[],
358 double xloc[],
359 double rscale,
360 double radius[],
361 double xmin,
362 double xmax
363 ) {
364 int J, Jmax, Jmin ;
365 double b1, b2, locwidth, width, ximax, ximin,
366 xlocmax, xlocmin, xoff, xscale ;
367
368 width = xmax - xmin ;
369 ximin = DVmin(n, x, &J) ;
370 ximax = DVmax(n, x, &J) ;
371 #if MYDEBUG > 0
372 fprintf(stdout, "\n ximin %f, ximax %f", ximin, ximax) ;
373 #endif
374 if ( ximax == ximin ) {
375 DVfill(n, xloc, 0.5*(xmax+xmin)) ;
376 return ;
377 }
378 xscale = width/(ximax - ximin) ;
379 #if MYDEBUG > 0
380 fprintf(stdout, "\n initial xscale %f", xscale) ;
381 #endif
382 for ( J = 0 ; J < n ; J++ ) {
383 xloc[J] = xmin + xscale*(x[J] - ximin) ;
384 }
385 while ( 1 ) {
386 if ( radius == NULL ) {
387 xlocmin = xloc[0] - rscale ;
388 xlocmax = xloc[0] + rscale ;
389 Jmin = Jmax = 0 ;
390 for ( J = 0 ; J < n ; J++ ) {
391 if ( xlocmin > xloc[J] - rscale ) {
392 xlocmin = xloc[J] - rscale ;
393 Jmin = J ;
394 }
395 if ( xlocmax < xloc[J] + rscale ) {
396 xlocmax = xloc[J] + rscale ;
397 Jmax = J ;
398 }
399 }
400 } else {
401 xlocmin = xloc[0] - rscale*radius[0] ;
402 xlocmax = xloc[0] + rscale*radius[0] ;
403 Jmin = Jmax = 0 ;
404 for ( J = 0 ; J < n ; J++ ) {
405 if ( xlocmin > xloc[J] - rscale*radius[J] ) {
406 xlocmin = xloc[J] - rscale*radius[J] ;
407 Jmin = J ;
408 }
409 if ( xlocmax < xloc[J] + rscale*radius[J] ) {
410 xlocmax = xloc[J] + rscale*radius[J] ;
411 Jmax = J ;
412 }
413 }
414 }
415 #if MYDEBUG > 0
416 fprintf(stdout, "\n\n Jmin = %d, Jmax = %d", Jmin, Jmax) ;
417 fprintf(stdout, "\n xlocmin %f, xlocmax %f", xlocmin, xlocmax) ;
418 #endif
419 if ( Jmin == Jmax ) {
420 DVfill(n, xloc, (xmin + xmax)/2) ;
421 #if MYDEBUG > 0
422 fprintf(stdout, "\n leaving") ;
423 #endif
424 break ;
425 } else {
426 locwidth = xlocmax - xlocmin ;
427 #if MYDEBUG > 0
428 fprintf(stdout, "\n width %f, locwidth %f", width, locwidth) ;
429 #endif
430 if ( locwidth > 1.01*width || locwidth < 0.99*width ) {
431 if ( radius == NULL ) {
432 b1 = xmin + rscale ;
433 b2 = xmax - rscale ;
434 } else {
435 b1 = xmin + rscale*radius[Jmin] ;
436 b2 = xmax - rscale*radius[Jmax] ;
437 }
438 if ( b1 > b2 ) {
439 fprintf(stderr, "\n\n error in Tree_drawEPS()"
440 "\n nonlinear process is unable to converge"
441 "\n reduce radius scaling factor\n") ;
442 exit(-1) ;
443 }
444 #if MYDEBUG > 0
445 fprintf(stdout, "\n 1. x[%d] = %f, x[%d] = %f",
446 Jmin, x[Jmin], Jmax, x[Jmax]) ;
447 fprintf(stdout, "\n 1. b1 = %f, b2 = %f", b1, b2) ;
448 #endif
449 xscale = (b2 - b1)/(x[Jmax] - x[Jmin]) ;
450 xoff = -(b2*x[Jmin] - b1*x[Jmax])/(x[Jmax] - x[Jmin]) ;
451 #if MYDEBUG > 0
452 fprintf(stdout, "\n 1. xscale = %f, xoff = %f", xscale, xoff) ;
453 #endif
454 for ( J = 0 ; J < n ; J++ ) {
455 xloc[J] = xoff + xscale*x[J] ;
456 }
457 } else {
458 break ;
459 }
460 }
461 }
462 return ; }
463
464 /*--------------------------------------------------------------------*/
465