Graphviz  2.41.20171026.1811
vtxgen.c
Go to the documentation of this file.
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 /*
16  * vtxgen.c generates graph diagrams in the format for
17  * Confluents's Visual Thought
18  */
19 
20 /*
21  * If this time code is a pain to port, then just comment out the
22  * next line. It only provides an optional information field
23  * in the (header...) block
24  */
25 #define SUPPORT_WRITEDATE
26 
27 #include "render.h"
28 #ifdef SUPPORT_WRITEDATE
29 #include <time.h>
30 #endif
31 
32 
33 /* VTX font modifiers */
34 #define REGULAR 0
35 #define BOLD 1
36 #define ITALIC 2
37 #define UNDERSORE 4
38 #define STRIKE 8
39 
40 /* VTX patterns */
41 #define P_NONE 0
42 #define P_SOLID 1
43 #define P_DOTTED 2
44 #define P_DASHED 3
45 
46 /* VTX bold line constant */
47 #define WIDTH_NORMAL 1
48 #define WIDTH_BOLD 3
49 
50 /* VTX shape mappings */
51 typedef struct shapemap_s {
52  char *shape;
53  char *vtxshape;
54 } shapemap_t;
55 
56 static shapemap_t shapemap[] = {
57  {"box", "\"Rectangle\""},
58  {"ellipse", "\"Ellipse\""},
59  {"circle", "\"Ellipse\""},
60  {"triangle", "\"Triangle\""},
61  {"diamond", "\"Diamond\""},
62  {"trapezium", "\"Trapezoid\""},
63  {"parallelogram", "\"Parallelogram\""},
64  {"hexagon", "\"Hexagon\""},
65  {NULL, "\"Ellipse\""} /* default */
66 };
67 
68 
69 static point Pages;
70 static double Scale;
71 static int Rot;
72 /* static box PB; */
73 static int onetime = TRUE;
74 
75 typedef struct context_t {
79  double fontsz;
80 } context_t;
81 
82 #define MAXNEST 4
83 static context_t cstk[MAXNEST];
84 static int SP;
85 
86 static void vtx_reset(void)
87 {
88  onetime = TRUE;
89 }
90 
91 
92 static void init_vtx(void)
93 {
94  SP = 0;
95  cstk[0].color_r = cstk[0].color_g = cstk[0].color_b = 0;
96  cstk[0].fontfam = "Times"; /* font family name */
97  cstk[0].fontopt = REGULAR; /* modifier: REGULAR, BOLD or ITALIC */
98  cstk[0].pen = P_SOLID; /* pen pattern style, default is solid */
99  cstk[0].fill = P_NONE;
100  cstk[0].penwidth = WIDTH_NORMAL;
101 }
102 
103 static pointf vtx_pt(pointf p)
104 {
105  pointf rv;
106 
107  if (Rot == 0) {
108  rv.x = p.x;
109  rv.y = p.y;
110  } else {
111  rv.x = p.y;
112  rv.y = p.x;
113  }
114  return rv;
115 }
116 
117 static void vtx_ptarray(point * A, int n)
118 {
119  int i;
120  pointf p;
121 
122  fprintf(Output_file, " (points\n");
123  for (i = 0; i < n; i++) {
124  p.x = (double) A[i].x;
125  p.y = (double) A[i].y;
126  p = vtx_pt(p);
127  fprintf(Output_file, " (%g %g)\n", p.x, p.y);
128  }
129  fprintf(Output_file, " )\n");
130 }
131 
132 static void vtx_bzptarray(point * A, int start, int end)
133 {
134  pointf p;
135  int qx = 0, qy = 0;
136  int i, j, incr = (start > end) ? -1 : 1;
137 
138  fprintf(Output_file, " (points\n");
139  for (i = start, j = 1; i != end; i += incr, j++) {
140  switch (j % 3) {
141  case 0:
142  p.x = (double) A[i].x;
143  p.y = (double) A[i].y;
144  p = vtx_pt(p);
145  fprintf(Output_file, " (%g %g)\n", p.x, p.y);
146  break;
147  case 1:
148 #if 1
149  qx = A[i].x;
150  qy = A[i].y;
151 #else
152  p.x = (double) A[i].x;
153  p.y = (double) A[i].y;
154  p = vtx_pt(p);
155  fprintf(Output_file, " (%g %g)\n", p.x, p.y);
156 #endif
157  break;
158  case 2:
159 #if 1
160  /* undo EK's strange coding of straight segments */
161  if (A[i].x == qx && A[i].y == qy) {
162  if ((A[i - 2].x == qx && A[i - 2].y == qy)
163  || (A[i + 1].x == qx && A[i + 1].y == qy)) {
164  p.x = (A[i + 1].x + A[i - 2].x) / 2.0;
165  p.y = (A[i + 1].y + A[i - 2].y) / 2.0;
166  } else {
167  p.x = (double) qx;
168  p.y = (double) qy;
169  }
170  } else {
171  p.x = (A[i].x + qx) / 2.0;
172  p.y = (A[i].y + qy) / 2.0;
173  }
174 #else
175  p.x = (double) A[i].x;
176  p.y = (double) A[i].y;
177 #endif
178  p = vtx_pt(p);
179  fprintf(Output_file, " (%g %g)\n", p.x, p.y);
180  break;
181  }
182  }
183  fprintf(Output_file, " )\n");
184 }
185 
186 static void vtx_font(context_t * cp)
187 {
188 /* FIX
189  char *fw,*fa;
190 
191  fw = fa = "Regular";
192  switch (cp->fontopt) {
193  case BOLD: fw = "Bold"; break;
194  case ITALIC: fa = "Italic"; break;
195  }
196 */
197 }
198 
199 static void vtx_comment(char *str)
200 {
201  fprintf(Output_file, "; %s\n", str);
202 }
203 
204 static void
205 vtx_begin_job(FILE * ofp, graph_t * g, const char **lib, char *info[], point pages)
206 {
207  char *date = "";
208 #ifdef SUPPORT_WRITEDATE
209  time_t when;
210  struct tm *tm;
211  size_t date_length = 200;
212 
213  time(&when);
214  tm = localtime(&when);
215  date = N_GNEW(date_length, char);
216  strftime(date, date_length, "%a %b %e %H:%M:%S %Z %Y", tm);
217 #endif
218 
219  Pages = pages;
220  /* N_pages = pages.x * pages.y; */
221 
222  fprintf(Output_file, "; Visual Thought 1.0\n"
223  "\n"
224  "(header\n"
225  " (program \"%s\")\n"
226  " (version \"%s\")\n"
227  " (buildDate \"%s\")\n"
228  " (writeDate \"%s\")\n"
229  " (documentPath \"\")\n"
230  ")\n" "\n", info[0], info[1], info[2], date);
231 
232  free(date);
233 }
234 
235 static void vtx_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb)
236 {
237  /* PB = bb; */
238  if (onetime) {
239  init_vtx();
240  onetime = FALSE;
241  }
242 }
243 
244 static void
245 vtx_begin_page(graph_t * g, point page, double scale, int rot,
246  point offset)
247 {
248  int page_number;
249  /* point sz; */
250 
251  Scale = scale;
252  Rot = rot;
253  page_number = page.x + page.y * Pages.x + 1;
254  /* sz = sub_points(PB.UR,PB.LL); */
255 
256  fprintf(Output_file, "(document\n"
257  " (palette F)\n"
258  " (layout\n"
259  " (page \"Letter\")\n"
260  " (units \"Inches\")\n"
261  " (orientation \"portrait\")\n"
262  " (numberOfPages %d %d)\n"
263  " (scale %g)\n"
264  " (margins 18 18 18 18)\n"
265  " )\n"
266  ")\n"
267  "\n"
268  "(views\n"
269  " (view\n"
270  " (location 269 49)\n"
271  " (size 632 723)\n"
272  " (zoom %g)\n"
273  " (documentLocation 0 119)\n"
274  " (gridSnap T)\n"
275  " (gridVisibility F)\n"
276  " (gridSpacing 9)\n"
277  " (pageBreaks T)\n"
278  " (toolVisibility T)\n"
279  " (rulerVisibility T)\n"
280  " )\n"
281  ")\n"
282  "\n", page_number, Pages.x * Pages.y, scale * 100, scale);
283 }
284 
285 static void vtx_begin_nodes(void)
286 {
287  fprintf(Output_file, "(shapes\n");
288 }
289 
290 static void vtx_end_nodes(void)
291 {
292  fprintf(Output_file, ")\n" "\n");
293 }
294 
295 static void vtx_begin_edges(void)
296 {
297  fprintf(Output_file, "(connections\n");
298 }
299 
300 static void vtx_end_edges(void)
301 {
302  fprintf(Output_file, ")\n" "\n" "(groups\n" ")\n");
303 }
304 
305 static void vtx_begin_node(node_t * n)
306 {
307  shapemap_t *p;
308 
309  for (p = shapemap; p->shape; p++) {
310  if (streq(ND_shape(n)->name, p->shape)) {
311  break;
312  }
313  }
314  fprintf(Output_file, " (shape\n"
315  " (id %ld)\n"
316  " (layer %ld)\n"
317  " (type %s)\n", AGID(n) + 1, AGID(n), p->vtxshape);
318 }
319 
320 static void vtx_end_node(void)
321 {
322  fprintf(Output_file, " )\n");
323 }
324 
325 static void vtx_begin_edge(edge_t * e)
326 {
327  fprintf(Output_file, " (connection\n"
328  " (id %ld)\n"
329  " (layer %ld)\n"
330  " (rotation 0)\n"
331  " (textRotation 0)\n"
332  " (locked F)\n"
333  " (start %ld)\n"
334  " (end %ld)\n",
335  AGID(e) + 1, AGID(e), AGID(agtail(e)) + 1, AGID(aghead(e)) + 1);
336 }
337 
338 static void vtx_end_edge(void)
339 {
340  fprintf(Output_file, " )\n");
341 }
342 
343 static void vtx_begin_context(void)
344 {
345  assert(SP + 1 < MAXNEST);
346  cstk[SP + 1] = cstk[SP];
347  SP++;
348 }
349 
350 static void vtx_end_context(void)
351 {
352  int psp = SP - 1;
353 
354  assert(SP > 0);
355  SP = psp;
356 }
357 
358 static void vtx_set_font(char *name, double size)
359 {
360  char *p, *q;
361  context_t *cp;
362 
363  cp = &(cstk[SP]);
364  cp->font_was_set = TRUE;
365  cp->fontsz = size;
366  p = strdup(name);
367  if ((q = strchr(p, '-'))) {
368  *q++ = 0;
369  if (strcasecmp(q, "italic") == 0)
370  cp->fontopt = ITALIC;
371  else if (strcasecmp(q, "bold") == 0)
372  cp->fontopt = BOLD;
373  }
374  cp->fontfam = p;
375  vtx_font(&cstk[SP]);
376 }
377 
378 static void vtx_style(void)
379 {
380  context_t *cp;
381 
382  cp = &(cstk[SP]);
383  fprintf(Output_file, " (style\n"
384  " (filled %s)\n"
385  " (fillColor %d %d %d)\n"
386  " (stroked T)\n"
387  " (strokeColor %d %d %d)\n"
388  " (lineWidth %d)\n"
389  " (shadowed F)\n"
390  " (shadowColor 39321 39321 39321)\n"
391  " )\n",
392  cp->fill ? "T" : "F",
393  cp->color_r, cp->color_g, cp->color_b,
394  cp->color_r, cp->color_g, cp->color_b, cp->penwidth);
395 }
396 
397 static void vtx_node_style(void)
398 {
399  fprintf(Output_file, " (rotation 0)\n" " (locked F)\n");
400  vtx_style();
401  fprintf(Output_file, " (flipHorizontal F)\n"
402  " (flipVertical F)\n");
403 }
404 
405 static void vtx_set_color(char *name)
406 {
407  gvcolor_t color;
408  context_t *cp;
409 
410  cp = &(cstk[SP]);
411  colorxlate(name, &color, RGBA_WORD);
412  cp->color_r = color.u.rrggbbaa[0];
413  cp->color_g = color.u.rrggbbaa[1];
414  cp->color_b = color.u.rrggbbaa[2];
415 }
416 
417 static void vtx_set_style(char **s)
418 {
419  char *line;
420  context_t *cp;
421 
422  cp = &(cstk[SP]);
423  while ((line = *s++)) {
424  if (streq(line, "solid"))
425  cp->pen = P_SOLID;
426  else if (streq(line, "dashed"))
427  cp->pen = P_DASHED;
428  else if (streq(line, "dotted"))
429  cp->pen = P_DOTTED;
430  else if (streq(line, "invis"))
431  cp->pen = P_NONE;
432  else if (streq(line, "bold"))
433  cp->penwidth = WIDTH_BOLD;
434  else if (streq(line, "filled"))
435  cp->fill = P_SOLID;
436  else if (streq(line, "unfilled"))
437  cp->fill = P_NONE;
438  else {
439  agerr(AGERR,
440  "vtx_set_style: unsupported style %s - ignoring\n",
441  line);
442  }
443  cp->style_was_set = TRUE;
444  }
445 }
446 
447 static char *vtx_string(char *s)
448 {
449  static char *buf = NULL;
450  static int bufsize = 0;
451  int pos = 0;
452  char *p, esc;
453 
454  if (!buf) {
455  bufsize = 64;
456  buf = N_GNEW(bufsize, char);
457  }
458 
459  p = buf;
460  while (*s) {
461  if (pos > (bufsize - 8)) {
462  bufsize *= 2;
463  buf = grealloc(buf, bufsize);
464  p = buf + pos;
465  }
466  esc = 0;
467  switch (*s) {
468  case '\t':
469  esc = 't';
470  break;
471  case '{':
472  case '}':
473  case '\\':
474  esc = *s;
475  break;
476  }
477  if (esc) {
478  *p++ = '\\';
479  *p++ = esc;
480  pos += 2;
481  } else {
482  *p++ = *s;
483  pos++;
484  }
485  s++;
486  }
487  *p = '\0';
488  return buf;
489 }
490 
491 static void vtx_textpara(point p, textpara_t * para)
492 {
493  pointf mp;
494  double fontsz = Scale * cstk[SP].fontsz;
495 
496  if (cstk[SP].pen == P_NONE) {
497  /* its invisible, don't draw */
498  return;
499  }
500 
501  mp.x = (double) p.x;
502  mp.y = (double) (p.y - fontsz / 2 + 2);
503  mp = vtx_pt(mp);
504  if (Obj == EDGE) {
505  fprintf(Output_file, " (showText T)\n"
506  " (textDistancePercentage 0.5)\n"
507  " (textWidth 72)\n"
508  " (textOffset 0)\n"
509  " (rtfText{\\rtf1\\ansi\\deff0\n"
510  "{\\fonttbl{\\f0\\fnil helvetica medium;}}\n"
511  "{\\colortbl\\red0\\green0\\blue0;}\n"
512  "\\cf0\\plain\\pard {\\fs%d %s}})\n",
513  (int) ((fontsz * 2) - 8), vtx_string(para->str));
514  } else {
515  fprintf(Output_file, " (showText T)\n"
516  " (textVerticalAlignment \"left\")\n"
517  " (rtfText{\\rtf1\\ansi\\deff0\n"
518  "{\\fonttbl{\\f0\\fnil helvetica medium;}}\n"
519  "{\\colortbl\\red0\\green0\\blue0;}\n"
520  "\\cf0\\plain\\pard {\\fs%d %s}})\n",
521  (int) ((fontsz * 2) - 8), vtx_string(para->str));
522  }
523 }
524 
525 static void vtx_bezier(point * A, int n, int arrow_at_start,
526  int arrow_at_end, int filled)
527 {
528  if (arrow_at_start) {
529  vtx_bzptarray(A, n - 2, 0);
530  fprintf(Output_file, " (curved T)\n");
531  vtx_style();
532  fprintf(Output_file, " (drawStartArrowhead %s)\n"
533  " (drawEndArrowhead %s)\n"
534  " (startArrowhead \"StandardArrow\")\n"
535  " (endArrowhead \"StandardArrow\")\n",
536  arrow_at_end ? "T" : "F", arrow_at_start ? "T" : "F");
537  } else {
538  vtx_bzptarray(A, 1, n - 1);
539  fprintf(Output_file, " (curved T)\n");
540  vtx_style();
541  fprintf(Output_file, " (drawStartArrowhead %s)\n"
542  " (drawEndArrowhead %s)\n"
543  " (startArrowhead \"StandardArrow\")\n"
544  " (endArrowhead \"StandardArrow\")\n",
545  arrow_at_start ? "T" : "F", arrow_at_end ? "T" : "F");
546  }
547 }
548 
549 static void vtx_polygon(point * A, int n, int filled)
550 {
551  int i;
552  pointf mp, max, min;
553 
554  mp.x = 0;
555  mp.y = 0;
556  max.x = min.x = (double) A[0].x;
557  max.y = min.y = (double) A[0].y;
558  for (i = 0; i < n; i++) {
559  mp.x += (double) A[i].x;
560  mp.y += (double) A[i].y;
561  max.x = MAX(max.x, (double) A[i].x);
562  max.y = MAX(max.y, (double) A[i].y);
563  min.x = MIN(min.x, (double) A[i].x);
564  min.y = MIN(min.y, (double) A[i].y);
565  }
566  mp.x /= n;
567  mp.y /= n;
568  mp = vtx_pt(mp);
569  max = vtx_pt(max);
570  min = vtx_pt(min);
571  fprintf(Output_file, " (location %g %g)\n"
572  " (size %g %g)\n",
573  mp.x, mp.y, max.x - min.x, max.y - min.y);
574  vtx_node_style();
575 }
576 
577 static void vtx_ellipse(point p, int rx, int ry, int filled)
578 {
579  pointf mp;
580 
581  mp.x = (double) p.x;
582  mp.y = (double) p.y;
583  mp = vtx_pt(mp);
584  fprintf(Output_file, " (location %g %g)\n"
585  " (size %g %g)\n",
586  mp.x, mp.y, (double) (rx + rx), (double) (ry + ry));
587  vtx_node_style();
588 }
589 
590 static void vtx_polyline(point * A, int n)
591 {
592  vtx_ptarray(A, n);
593  fprintf(Output_file, " (curved F)\n");
594  vtx_style();
595 }
596 
597 static void vtx_usershape(usershape_t *us, boxf b, point *A, int n, boolean filled)
598 {
599 /* FIXME */
600  int i;
601  pointf mp, max, min;
602 
603  mp.x = 0;
604  mp.y = 0;
605  max.x = min.x = (double) A[0].x;
606  max.y = min.y = (double) A[0].y;
607  for (i = 0; i < n; i++) {
608  mp.x += (double) A[i].x;
609  mp.y += (double) A[i].y;
610  max.x = MAX(max.x, (double) A[i].x);
611  max.y = MAX(max.y, (double) A[i].y);
612  min.x = MIN(min.x, (double) A[i].x);
613  min.y = MIN(min.y, (double) A[i].y);
614  }
615  mp.x /= n;
616  mp.y /= n;
617  mp = vtx_pt(mp);
618  max = vtx_pt(max);
619  min = vtx_pt(min);
620  fprintf(Output_file, " (location %g %g)\n"
621  " (size %g %g)\n",
622  mp.x, mp.y, max.x - min.x, max.y - min.y);
623  vtx_node_style();
624 }
625 
626 codegen_t VTX_CodeGen = {
627  vtx_reset,
628  vtx_begin_job, 0, /* vtx_end_job */
629  vtx_begin_graph, 0, /* vtx_end_graph */
630  vtx_begin_page, 0, /* vtx_end_page */
631  0, /* vtx_begin_layer */ 0, /* vtx_end_layer */
632  0, /* vtx_begin_cluster */ 0, /* vtx_end_cluster */
633  vtx_begin_nodes, vtx_end_nodes,
634  vtx_begin_edges, vtx_end_edges,
635  vtx_begin_node, vtx_end_node,
636  vtx_begin_edge, vtx_end_edge,
637  vtx_begin_context, vtx_end_context,
638  0, /* vtx_begin_anchor */ 0, /* vtx_end_anchor */
639  vtx_set_font, vtx_textpara,
640  vtx_set_color, vtx_set_color, vtx_set_style,
641  vtx_ellipse, vtx_polygon,
642  vtx_bezier, vtx_polyline,
643  1, /* bezier_has_arrows */
644  vtx_comment,
645  vtx_usershape
646 };
#define MAX(a, b)
Definition: agerror.c:17
Definition: cgraph.h:388
union color_s::@10 u
void * grealloc(void *ptr, size_t size)
Definition: memory.c:54
#define MIN(a, b)
Definition: arith.h:35
#define AGID(obj)
Definition: cgraph.h:114
#define EDGE
Definition: const.h:129
char fill
Definition: diagen.c:73
#define P_SOLID
Definition: vtxgen.c:42
#define assert(x)
Definition: cghdr.h:47
Definition: geom.h:28
#define WIDTH_BOLD
Definition: vtxgen.c:48
char * fontfam
Definition: diagen.c:72
int color_g
Definition: vtxgen.c:76
Definition: color.h:34
char pen
Definition: diagen.c:73
int agerr(agerrlevel_t level, const char *fmt,...)
Definition: agerror.c:141
#define BOLD
Definition: vtxgen.c:35
int color_r
Definition: vtxgen.c:76
int x
Definition: geom.h:26
CGRAPH_API Agnode_t * agtail(Agedge_t *e)
Definition: edge.c:525
#define MAXNEST
Definition: vtxgen.c:82
struct context_t context_t
#define P_DASHED
Definition: vtxgen.c:44
double fontsz
Definition: diagen.c:74
int rrggbbaa[4]
Definition: color.h:40
#define ITALIC
Definition: vtxgen.c:36
CGRAPH_API Agnode_t * aghead(Agedge_t *e)
Definition: edge.c:533
#define max(x, y)
Definition: stress.c:794
#define ND_shape(n)
Definition: types.h:534
#define REGULAR
Definition: vtxgen.c:34
double y
Definition: geom.h:28
Definition: gvcint.h:70
struct shapemap_s shapemap_t
char style_was_set
Definition: diagen.c:73
char * vtxshape
Definition: vtxgen.c:53
int color_b
Definition: vtxgen.c:76
Definition: grammar.c:79
char fontopt
Definition: diagen.c:72
char font_was_set
Definition: diagen.c:72
if(aagss+aagstacksize-1<=aagssp)
Definition: grammar.c:1332
int colorxlate(char *str, gvcolor_t *color, color_type_t target_type)
Definition: colxlate.c:254
#define NULL
Definition: logic.h:39
Definition: geom.h:26
double x
Definition: geom.h:28
#define streq(s, t)
Definition: cghdr.h:52
GVC_t * gvc
Definition: htmlparse.c:87
char penwidth
Definition: diagen.c:73
int strcasecmp(const char *s1, const char *s2)
Definition: strcasecmp.c:21
#define WIDTH_NORMAL
Definition: vtxgen.c:47
codegen_t VTX_CodeGen
Definition: vtxgen.c:626
agxbuf * str
Definition: htmlparse.c:85
char * shape
Definition: vtxgen.c:52
int y
Definition: geom.h:26
#define P_NONE
Definition: vtxgen.c:41
#define P_DOTTED
Definition: vtxgen.c:43
Definition: geom.h:35
#define N_GNEW(n, t)
Definition: agxbuf.c:20
#define FALSE
Definition: cgraph.h:35
Definition: geom.h:33
#define TRUE
Definition: cgraph.h:38