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