1/* $Id$ $Revision$ */
2/* vim:set shiftwidth=4 ts=8: */
3
4/*************************************************************************
5 * Copyright (c) 2011 AT&T Intellectual Property
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors: See CVS logs. Details at http://www.graphviz.org/
12 *************************************************************************/
13
14
15/* dbg.c:
16 * Written by Emden R. Gansner
17 *
18 * Simple debugging infrastructure
19 */
20#ifdef DEBUG
21
22#define FDP_PRIVATE
23
24#include <dbg.h>
25#include <neatoprocs.h>
26#include <fdp.h>
27#include <math.h>
28
29static int indent = -1;
30
31void incInd()
32{
33 indent++;
34}
35
36void decInd()
37{
38 if (indent >= 0)
39 indent--;
40}
41
42void prIndent(void)
43{
44 int i;
45 for (i = 0; i < indent; i++)
46 fputs(" ", stderr);
47}
48
49void prEdge(edge_t *e,char *s)
50{
51 fprintf(stderr,"%s --", agnameof(agtail(e)));
52 fprintf(stderr,"%s%s", agnameof(aghead(e)),s);
53}
54
55static void dumpBB(graph_t * g)
56{
57 boxf bb;
58 boxf b;
59
60 bb = BB(g);
61 b = GD_bb(g);
62 prIndent();
63 fprintf(stderr, " LL (%f,%f) UR (%f,%f)\n", bb.LL.x, bb.LL.y,
64 bb.UR.x, bb.UR.y);
65 prIndent();
66 fprintf(stderr, " LL (%f,%f) UR (%f,%f)\n", b.LL.x, b.LL.y,
67 b.UR.x, b.UR.y);
68}
69
70static void dumpSG(graph_t * g)
71{
72 graph_t *subg;
73 int i;
74
75 if (GD_n_cluster(g) == 0)
76 return;
77 prIndent();
78 fprintf(stderr, " {\n");
79 for (i = 1; i <= GD_n_cluster(g); i++) {
80 subg = (GD_clust(g))[i];
81 prIndent();
82 fprintf(stderr, " subgraph %s : %d nodes\n", agnameof(subg),
83 agnnodes(subg));
84 dumpBB(subg);
85 incInd ();
86 dumpSG(subg);
87 decInd ();
88 }
89 prIndent();
90 fprintf(stderr, " }\n");
91}
92
93/* dumpE:
94 */
95void dumpE(graph_t * g, int derived)
96{
97 Agnode_t *n;
98 Agedge_t *e;
99 Agedge_t **ep;
100 Agedge_t *el;
101 int i;
102 int deg;
103
104 prIndent();
105 fprintf(stderr, "Graph %s : %d nodes %d edges\n", agnameof(g), agnnodes(g),
106 agnedges(g));
107 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
108 deg = 0;
109 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
110 deg++;
111 prIndent();
112 prEdge(e,"\n");
113 if (derived) {
114 for (i = 0, ep = (Agedge_t **) ED_to_virt(e);
115 i < ED_count(e); i++, ep++) {
116 el = *ep;
117 prIndent();
118 prEdge(el,"\n");
119 }
120 }
121 }
122 if (deg == 0) { /* no out edges */
123 if (!agfstin(g, n)) /* no in edges */
124 fprintf(stderr, " %s\n", agnameof(n));
125 }
126 }
127 if (!derived) {
128 bport_t *pp;
129 if ((pp = PORTS(g))) {
130 int sz = NPORTS(g);
131 fprintf(stderr, " %d ports\n", sz);
132 while (pp->e) {
133 fprintf(stderr, " %s : ", agnameof(pp->n));
134 prEdge(pp->e,"\n");
135 pp++;
136 }
137 }
138 }
139}
140
141/* dump:
142 */
143void dump(graph_t * g, int level, int doBB)
144{
145 node_t *n;
146 boxf bb;
147 double w, h;
148 pointf pos;
149
150 if (Verbose < level)
151 return;
152 prIndent();
153 fprintf(stderr, "Graph %s : %d nodes\n", agnameof(g), agnnodes(g));
154 dumpBB(g);
155 if (Verbose > level) {
156 incInd();
157 dumpSG(g);
158 decInd();
159 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
160 pos.x = ND_pos(n)[0];
161 pos.y = ND_pos(n)[1];
162 prIndent();
163 w = ND_width(n);
164 h = ND_height(n);
165 if (doBB) {
166 bb.LL.x = pos.x - w / 2.0;
167 bb.LL.y = pos.y - h / 2.0;
168 bb.UR.x = bb.LL.x + w;
169 bb.UR.y = bb.LL.y + h;
170 fprintf(stderr, "%s: (%f,%f) ((%f,%f) , (%f,%f))\n",
171 agnameof(n), pos.x, pos.y, bb.LL.x, bb.LL.y, bb.UR.x,
172 bb.UR.y);
173 } else {
174 fprintf(stderr, "%s: (%f,%f) (%f,%f) \n",
175 agnameof(n), pos.x, pos.y, w, h);
176 }
177 }
178 }
179}
180
181void dumpG(graph_t * g, char *fname, int expMode)
182{
183 FILE *fp;
184
185 fp = fopen(fname, "w");
186 if (!fp) {
187 fprintf(stderr, "Couldn not open %s \n", fname);
188 exit(1);
189 }
190 outputGraph(g, fp, expMode);
191 fclose(fp);
192}
193
194/* #define BOX */
195
196/* static char* pos_name = "pos"; */
197/* static char* lp_name = "lp"; */
198
199double Scale = 0.0;
200double ArrowScale = 1.0;
201
202#define ARROW_LENGTH 10
203#define ARROW_WIDTH 5
204/* #define DEGREES(rad) ((rad)/M_PI * 180.0) */
205
206static char *plog = "%!PS-Adobe-2.0\n\n\
207/Times-Roman findfont 14 scalefont setfont\n\
208/lLabel {\n\
209\tmoveto\n\
210\tgsave\n\
211\tshow\n\
212\tgrestore\n\
213} def\n\
214/inch {\n\
215\t72 mul\n\
216} def\n\
217/doBox {\n\
218\tnewpath\n\
219\tmoveto\n\
220\t/ht exch def\n\
221\t/wd exch def\n\
222\t0 ht rlineto\n\
223\twd 0 rlineto\n\
224\t0 0 ht sub rlineto\n\
225\tclosepath\n\
226\tgsave\n\
227\t\t.9 setgray\n\
228\t\tfill\n\
229\tgrestore\n\
230\tstroke\n\
231} def\n\
232/drawCircle {\n\
233\t/r exch def\n\
234\t/y exch def\n\
235\t/x exch def\n\
236\tnewpath\n\
237\tx y r 0 360 arc\n\
238\tstroke\n\
239} def\n\
240/fillCircle {\n\
241\t/r exch def\n\
242\t/y exch def\n\
243\t/x exch def\n\
244\tnewpath\n\
245\tx y r 0 360 arc\n\
246\tfill\n\
247} def\n";
248
249static char *elog = "showpage\n";
250
251/*
252static char* arrow = "/doArrow {\n\
253\t/arrowwidth exch def\n\
254\t/arrowlength exch def\n\
255\tgsave\n\
256\t\t3 1 roll\n\
257\t\ttranslate\n\
258\t\t\trotate\n\
259\t\t\tnewpath\n\
260\t\t\tarrowlength arrowwidth 2 div moveto\n\
261\t\t\t0 0 lineto\n\
262\t\t\tarrowlength arrowwidth -2 div lineto\n\
263\t\tclosepath fill\n\
264\t\tstroke\n\
265\tgrestore\n\
266} def\n";
267*/
268
269static double PSWidth = 550.0;
270static double PSHeight = 756.0;
271
272static void pswrite(Agraph_t * g, FILE * fp, int expMode)
273{
274 Agnode_t *n;
275 Agnode_t *h;
276 Agedge_t *e;
277 double minx, miny, maxx, maxy;
278 double scale, width, height;
279 int do_arrow;
280 int angle;
281 char *p;
282 double theta;
283 double arrow_w, arrow_l;
284 int portColor;
285
286 fprintf(fp, "%s", plog);
287
288/*
289 if (agisdirected (g) && DoArrow) {
290 do_arrow = 1;
291 fprintf(fp,arrow);
292 }
293 else
294*/
295 do_arrow = 0;
296
297 n = agfstnode(g);
298 minx = ND_pos(n)[0];
299 miny = ND_pos(n)[1];
300 maxx = ND_pos(n)[0];
301 maxy = ND_pos(n)[1];
302 n = agnxtnode(g, n);
303 for (; n; n = agnxtnode(g, n)) {
304 if (ND_pos(n)[0] < minx)
305 minx = ND_pos(n)[0];
306 if (ND_pos(n)[1] < miny)
307 miny = ND_pos(n)[1];
308 if (ND_pos(n)[0] > maxx)
309 maxx = ND_pos(n)[0];
310 if (ND_pos(n)[1] > maxy)
311 maxy = ND_pos(n)[1];
312 }
313
314 /* Convert to points
315 */
316 minx *= POINTS_PER_INCH;
317 miny *= POINTS_PER_INCH;
318 maxx *= POINTS_PER_INCH;
319 maxy *= POINTS_PER_INCH;
320
321 /* Check for rotation
322 */
323 if ((p = agget(g, "rotate")) && (*p != '\0')
324 && ((angle = atoi(p)) != 0)) {
325 fprintf(fp, "306 396 translate\n");
326 fprintf(fp, "%d rotate\n", angle);
327 fprintf(fp, "-306 -396 translate\n");
328 }
329
330 /* If user gives scale factor, use it.
331 * Else if figure too large for standard PS page, scale it to fit.
332 */
333 if (Scale > 0.0)
334 scale = Scale;
335 else {
336 width = maxx - minx + 20;
337 height = maxy - miny + 20;
338 if (width > PSWidth) {
339 if (height > PSHeight) {
340 scale =
341 (PSWidth / width <
342 PSHeight / height ? PSWidth / width : PSHeight /
343 height);
344 } else
345 scale = PSWidth / width;
346 } else if (height > PSHeight) {
347 scale = PSHeight / height;
348 } else
349 scale = 1.0;
350 }
351
352 fprintf(fp, "%f %f translate\n",
353 (PSWidth - scale * (minx + maxx)) / 2.0,
354 (PSHeight - scale * (miny + maxy)) / 2.0);
355 fprintf(fp, "%f %f scale\n", scale, scale);
356
357/*
358 if (Verbose)
359 fprintf (stderr, "Region (%f,%f) (%f,%f), scale %f\n",
360 minx, miny, maxx, maxy, scale);
361*/
362
363 if (do_arrow) {
364 arrow_w = ArrowScale * ARROW_WIDTH / scale;
365 arrow_l = ArrowScale * ARROW_LENGTH / scale;
366 }
367
368 fprintf(fp, "0.0 setlinewidth\n");
369#ifdef SHOW_GRID
370 if (UseGrid) {
371 int i;
372 fprintf(fp, "%f %f 5 fillCircle\n", 0.0, 0.0);
373 for (i = 0; i < maxx; i += CellW) {
374 fprintf(fp, "%f 0.0 moveto %f %f lineto stroke\n",
375 (float) i, (float) i, maxy);
376 }
377 for (i = 0; i < maxy; i += CellH) {
378 fprintf(fp, "0.0 %f moveto %f %f lineto stroke\n",
379 (float) i, maxx, (float) i);
380 }
381 }
382#endif
383 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
384 if (IS_PORT(n)) {
385 double r;
386 r = sqrt(ND_pos(n)[0] * ND_pos(n)[0] +
387 ND_pos(n)[1] * ND_pos(n)[1]);
388 fprintf(fp, "0 0 %f inch drawCircle\n", r);
389 break;
390 }
391 }
392
393 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
394 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
395 h = aghead(e);
396 fprintf(fp, "%f inch %f inch moveto %f inch %f inch lineto\n",
397 ND_pos(n)[0], ND_pos(n)[1], ND_pos(h)[0],
398 ND_pos(h)[1]);
399 fprintf(fp, "stroke\n");
400 if (do_arrow) {
401 theta =
402 atan2(ND_pos(n)[1] - ND_pos(h)[1],
403 ND_pos(n)[0] - ND_pos(h)[0]);
404 fprintf(fp, "%f %f %.2f %.2f %.2f doArrow\n",
405 ND_pos(h)[0], ND_pos(h)[1], DEGREES(theta),
406 arrow_l, arrow_w);
407 }
408
409 }
410 }
411
412#ifdef BOX
413 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
414 float wd, ht;
415
416 data = getData(n);
417 wd = data->wd;
418 ht = data->ht;
419 fprintf(fp, "%f %f %f %f doBox\n", wd, ht,
420 data->pos.x - (wd / 2), data->pos.y - (ht / 2));
421 }
422#else
423 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
424 fprintf(fp, "%% %s\n", agnameof(n));
425 if (expMode) {
426 double wd, ht;
427 double r;
428 wd = ND_width(n);
429 ht = ND_height(n);
430 r = sqrt((wd * wd / 4) + ht * ht / 4);
431 fprintf(fp, "%f inch %f inch %f inch %f inch doBox\n", wd, ht,
432 ND_pos(n)[0] - (wd / 2), ND_pos(n)[1] - (ht / 2));
433 fprintf(fp, "%f inch %f inch %f inch drawCircle\n",
434 ND_pos(n)[0], ND_pos(n)[1], r);
435 } else {
436 if (IS_PORT(n)) {
437 if (!portColor) {
438 fprintf(fp, "0.667 1.000 1.000 sethsbcolor\n");
439 portColor = 1;
440 }
441 } else {
442 if (portColor) {
443 fprintf(fp, "0.0 0.000 0.000 sethsbcolor\n");
444 portColor = 0;
445 }
446 }
447 }
448 fprintf(fp, "%f inch %f inch %f fillCircle\n", ND_pos(n)[0],
449 ND_pos(n)[1], 3 / scale);
450 }
451#endif
452
453 fprintf(fp, "0.667 1.000 1.000 sethsbcolor\n");
454 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
455 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
456 h = aghead(e);
457 fprintf(fp, "%f inch %f inch moveto %f inch %f inch lineto\n",
458 ND_pos(n)[0], ND_pos(n)[1], ND_pos(h)[0],
459 ND_pos(h)[1]);
460 fprintf(fp, "stroke\n");
461 if (do_arrow) {
462 theta =
463 atan2(ND_pos(n)[1] - ND_pos(h)[1],
464 ND_pos(n)[0] - ND_pos(h)[0]);
465 fprintf(fp, "%f %f %.2f %.2f %.2f doArrow\n",
466 ND_pos(h)[0], ND_pos(h)[1], DEGREES(theta),
467 arrow_l, arrow_w);
468 }
469
470 }
471 }
472
473 fprintf(fp, "%s", elog);
474}
475
476void outputGraph(Agraph_t * g, FILE * fp, int expMode)
477{
478 pswrite(g, fp, expMode);
479}
480
481#endif /* DEBUG */
482