Graphviz  2.41.20171026.1811
gvrender_core_mp.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 /* FIXME - incomplete replacement for codegen */
15 
16 #include "config.h"
17 
18 #include <stdarg.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <ctype.h>
22 
23 #ifdef _WIN32
24 #include <io.h>
25 #include "compat.h"
26 #endif
27 
28 #include "macros.h"
29 #include "const.h"
30 
31 #include "gvplugin_render.h"
32 #include "gvplugin_device.h"
33 #include "gvio.h"
34 #include "agxbuf.h"
35 #include "utils.h"
36 #include "color.h"
37 
38 /* Number of points to split splines into */
39 #define BEZIERSUBDIVISION 6
40 
41 typedef enum { FORMAT_MP, } format_type;
42 
43 static int Depth;
44 
45 static void mpptarray(GVJ_t *job, pointf * A, int n, int close)
46 {
47  int i;
48  point p;
49 
50  for (i = 0; i < n; i++) {
51  PF2P(A[i],p);
52  gvprintf(job, " %d %d", p.x, p.y);
53  }
54  if (close) {
55  PF2P(A[0],p);
56  gvprintf(job, " %d %d", p.x, p.y);
57  }
58  gvputs(job, "\n");
59 }
60 
61 static char *mp_string(char *s)
62 {
63  static char *buf = NULL;
64  static int bufsize = 0;
65  int pos = 0;
66  char *p;
67  unsigned char c;
68 
69  if (!buf) {
70  bufsize = 64;
71  buf = malloc(bufsize * sizeof(char));
72  }
73 
74  p = buf;
75  while ((c = *s++)) {
76  if (pos > (bufsize - 8)) {
77  bufsize *= 2;
78  buf = realloc(buf, bufsize * sizeof(char));
79  p = buf + pos;
80  }
81  if (isascii(c)) {
82  if (c == '\\') {
83  *p++ = '\\';
84  pos++;
85  }
86  *p++ = c;
87  pos++;
88  } else {
89  *p++ = '\\';
90  sprintf(p, "%03o", c);
91  p += 3;
92  pos += 4;
93  }
94  }
95  *p = '\0';
96  return buf;
97 }
98 
99 static int mpColorResolve(int *new, int r, int g, int b)
100 {
101 #define maxColors 256
102  static int top = 0;
103  static short red[maxColors], green[maxColors], blue[maxColors];
104  int c;
105  int ct = -1;
106  long rd, gd, bd, dist;
107  long mindist = 3 * 255 * 255; /* init to max poss dist */
108 
109  *new = 0; /* in case it is not a new color */
110  for (c = 0; c < top; c++) {
111  rd = (long) (red[c] - r);
112  gd = (long) (green[c] - g);
113  bd = (long) (blue[c] - b);
114  dist = rd * rd + gd * gd + bd * bd;
115  if (dist < mindist) {
116  if (dist == 0)
117  return c; /* Return exact match color */
118  mindist = dist;
119  ct = c;
120  }
121  }
122  /* no exact match. We now know closest, but first try to allocate exact */
123  if (top++ == maxColors)
124  return ct; /* Return closest available color */
125  red[c] = r;
126  green[c] = g;
127  blue[c] = b;
128  *new = 1; /* flag new color */
129  return c; /* Return newly allocated color */
130 }
131 
132 /* this table is in xfig color index order */
133 static char *mpcolor[] = {
134  "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
135 };
136 
137 static void mp_resolve_color(GVJ_t *job, gvcolor_t * color)
138 {
139  int object_code = 0; /* always 0 for color */
140  int i, new;
141 
142  switch (color->type) {
143  case COLOR_STRING:
144  for (i = 0; mpcolor[i]; i++) {
145  if (streq(mpcolor[i], color->u.string)) {
146  color->u.index = i;
147  break;
148  }
149  }
150  break;
151  case RGBA_BYTE:
152  i = 32 + mpColorResolve(&new,
153  color->u.rgba[0],
154  color->u.rgba[1],
155  color->u.rgba[2]);
156  if (new)
157  gvprintf(job, "%d %d #%02x%02x%02x\n",
158  object_code, i,
159  color->u.rgba[0],
160  color->u.rgba[1],
161  color->u.rgba[2]);
162  color->u.index = i;
163  break;
164  case HSVA_DOUBLE: /* TODO: implement color conversion */
165  color->u.index = 0;
166  break;
167  default:
168  assert(0); /* internal error */
169  }
170 
171  color->type = COLOR_INDEX;
172 }
173 
174 static void mp_line_style(obj_state_t *obj, int *line_style, double *style_val)
175 {
176  switch (obj->pen) {
177  case PEN_DASHED:
178  *line_style = 1;
179  *style_val = 10.;
180  break;
181  case PEN_DOTTED:
182  *line_style = 2;
183  *style_val = 10.;
184  break;
185  case PEN_SOLID:
186  default:
187  *line_style = 0;
188  *style_val = 0.;
189  break;
190  }
191 }
192 
193 static void mp_comment(GVJ_t *job, char *str)
194 {
195  gvprintf(job, "# %s\n", str);
196 }
197 
198 static void mp_begin_graph(GVJ_t * job)
199 {
200  obj_state_t *obj = job->obj;
201 
202  gvputs(job, "#FIG 3.2\n");
203  gvprintf(job, "# Generated by %s version %s (%s)\n",
204  job->common->info[0], job->common->info[1], job->common->info[2]);
205  gvprintf(job, "# Title: %s\n", agnameof(obj->u.g));
206  gvprintf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
207  gvputs(job, "Portrait\n"); /* orientation */
208  gvputs(job, "Center\n"); /* justification */
209  gvputs(job, "Inches\n"); /* units */
210  gvputs(job, "Letter\n"); /* papersize */
211  gvputs(job, "100.00\n"); /* magnification % */
212  gvputs(job, "Single\n"); /* multiple-page */
213  gvputs(job, "-2\n"); /* transparent color (none) */
214  gvputs(job, "1200"); /* resolution */
215  gvputs(job, " 2\n"); /* coordinate system (upper left) */
216 }
217 
218 static void mp_end_graph(GVJ_t * job)
219 {
220  gvputs(job, "# end of FIG file\n");
221 }
222 
223 static void mp_begin_page(GVJ_t * job)
224 {
225  Depth = 2;
226 }
227 
228 static void mp_begin_node(GVJ_t * job)
229 {
230  Depth = 1;
231 }
232 
233 static void mp_end_node(GVJ_t * job)
234 {
235  Depth = 2;
236 }
237 
238 static void mp_begin_edge(GVJ_t * job)
239 {
240  Depth = 0;
241 }
242 
243 static void mp_end_edge(GVJ_t * job)
244 {
245  Depth = 2;
246 }
247 
248 static void mp_textspan(GVJ_t * job, pointf p, textspan_t * span)
249 {
250  obj_state_t *obj = job->obj;
251 
252  int object_code = 4; /* always 4 for text */
253  int sub_type = 0; /* text justification */
254  int color = obj->pencolor.u.index;
255  int depth = Depth;
256  int pen_style = 0; /* not used */
257  int font = -1; /* init to xfig's default font */
258  double font_size = span->font->size * job->zoom;
259  double angle = job->rotation ? (M_PI / 2.0) : 0.0;
260  int font_flags = 4; /* PostScript font */
261  double height = 0.0;
262  double length = 0.0;
263 
264  if (span->font->postscript_alias) /* if it is a standard postscript font */
265  font = span->font->postscript_alias->xfig_code;
266 
267  switch (span->just) {
268  case 'l':
269  sub_type = 0;
270  break;
271  case 'r':
272  sub_type = 2;
273  break;
274  default:
275  case 'n':
276  sub_type = 1;
277  break;
278  }
279 
280  gvprintf(job,
281  "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
282  object_code, sub_type, color, depth, pen_style, font,
283  font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
284  mp_string(span->str));
285 }
286 
287 static void mp_ellipse(GVJ_t * job, pointf * A, int filled)
288 {
289  obj_state_t *obj = job->obj;
290 
291  int object_code = 1; /* always 1 for ellipse */
292  int sub_type = 1; /* ellipse defined by radii */
293  int line_style; /* solid, dotted, dashed */
294  int thickness = obj->penwidth;
295  int pen_color = obj->pencolor.u.index;
296  int fill_color = obj->fillcolor.u.index;
297  int depth = Depth;
298  int pen_style = 0; /* not used */
299  int area_fill = filled ? 20 : -1;
300  double style_val;
301  int direction = 0;
302  double angle = 0.0;
303  int center_x, center_y, radius_x, radius_y;
304  int start_x, start_y, end_x, end_y;
305 
306  mp_line_style(obj, &line_style, &style_val);
307 
308  start_x = center_x = ROUND(A[0].x);
309  start_y = center_y = ROUND(A[0].y);
310  radius_x = ROUND(A[1].x - A[0].x);
311  radius_y = ROUND(A[1].y - A[0].y);
312  end_x = ROUND(A[1].x);
313  end_y = ROUND(A[1].y);
314 
315  gvprintf(job,
316  "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
317  object_code, sub_type, line_style, thickness, pen_color,
318  fill_color, depth, pen_style, area_fill, style_val, direction,
319  angle, center_x, center_y, radius_x, radius_y, start_x,
320  start_y, end_x, end_y);
321 }
322 
323 static void mp_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
324  int arrow_at_end, int filled)
325 {
326  obj_state_t *obj = job->obj;
327 
328  int object_code = 3; /* always 3 for spline */
329  int sub_type;
330  int line_style; /* solid, dotted, dashed */
331  int thickness = obj->penwidth;
332  int pen_color = obj->pencolor.u.index;
333  int fill_color = obj->fillcolor.u.index;
334  int depth = Depth;
335  int pen_style = 0; /* not used */
336  int area_fill;
337  double style_val;
338  int cap_style = 0;
339  int forward_arrow = 0;
340  int backward_arrow = 0;
341  int npoints = n;
342  int i;
343 
344  pointf pf, V[4];
345  point p;
346  int j, step;
347  int count = 0;
348  int size;
349 
350  char *buffer;
351  char *buf;
352  buffer =
353  malloc((npoints + 1) * (BEZIERSUBDIVISION +
354  1) * 20 * sizeof(char));
355  buf = buffer;
356 
357  mp_line_style(obj, &line_style, &style_val);
358 
359  if (filled) {
360  sub_type = 5; /* closed X-spline */
361  area_fill = 20; /* fully saturated color */
362  fill_color = job->obj->fillcolor.u.index;
363  }
364  else {
365  sub_type = 4; /* opened X-spline */
366  area_fill = -1;
367  fill_color = 0;
368  }
369  V[3].x = A[0].x;
370  V[3].y = A[0].y;
371  /* Write first point in line */
372  count++;
373  PF2P(A[0], p);
374  size = sprintf(buf, " %d %d", p.x, p.y);
375  buf += size;
376  /* write subsequent points */
377  for (i = 0; i + 3 < n; i += 3) {
378  V[0] = V[3];
379  for (j = 1; j <= 3; j++) {
380  V[j].x = A[i + j].x;
381  V[j].y = A[i + j].y;
382  }
383  for (step = 1; step <= BEZIERSUBDIVISION; step++) {
384  count++;
385  pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
386  PF2P(pf, p);
387  size = sprintf(buf, " %d %d", p.x, p.y);
388  buf += size;
389  }
390  }
391 
392  gvprintf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
393  object_code,
394  sub_type,
395  line_style,
396  thickness,
397  pen_color,
398  fill_color,
399  depth,
400  pen_style,
401  area_fill,
402  style_val, cap_style, forward_arrow, backward_arrow, count);
403 
404  gvprintf(job, " %s\n", buffer); /* print points */
405  free(buffer);
406  for (i = 0; i < count; i++) {
407  gvprintf(job, " %d", i % (count - 1) ? 1 : 0); /* -1 on all */
408  }
409  gvputs(job, "\n");
410 }
411 
412 static void mp_polygon(GVJ_t * job, pointf * A, int n, int filled)
413 {
414  obj_state_t *obj = job->obj;
415 
416  int object_code = 2; /* always 2 for polyline */
417  int sub_type = 3; /* always 3 for polygon */
418  int line_style; /* solid, dotted, dashed */
419  int thickness = obj->penwidth;
420  int pen_color = obj->pencolor.u.index;
421  int fill_color = obj->fillcolor.u.index;
422  int depth = Depth;
423  int pen_style = 0; /* not used */
424  int area_fill = filled ? 20 : -1;
425  double style_val;
426  int join_style = 0;
427  int cap_style = 0;
428  int radius = 0;
429  int forward_arrow = 0;
430  int backward_arrow = 0;
431  int npoints = n + 1;
432 
433  mp_line_style(obj, &line_style, &style_val);
434 
435  gvprintf(job,
436  "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
437  object_code, sub_type, line_style, thickness, pen_color,
438  fill_color, depth, pen_style, area_fill, style_val, join_style,
439  cap_style, radius, forward_arrow, backward_arrow, npoints);
440  mpptarray(job, A, n, 1); /* closed shape */
441 }
442 
443 static void mp_polyline(GVJ_t * job, pointf * A, int n)
444 {
445  obj_state_t *obj = job->obj;
446 
447  int object_code = 2; /* always 2 for polyline */
448  int sub_type = 1; /* always 1 for polyline */
449  int line_style; /* solid, dotted, dashed */
450  int thickness = obj->penwidth;
451  int pen_color = obj->pencolor.u.index;
452  int fill_color = 0;
453  int depth = Depth;
454  int pen_style = 0; /* not used */
455  int area_fill = 0;
456  double style_val;
457  int join_style = 0;
458  int cap_style = 0;
459  int radius = 0;
460  int forward_arrow = 0;
461  int backward_arrow = 0;
462  int npoints = n;
463 
464  mp_line_style(obj, &line_style, &style_val);
465 
466  gvprintf(job,
467  "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
468  object_code, sub_type, line_style, thickness, pen_color,
469  fill_color, depth, pen_style, area_fill, style_val, join_style,
470  cap_style, radius, forward_arrow, backward_arrow, npoints);
471  mpptarray(job, A, n, 0); /* open shape */
472 }
473 
475  0, /* mp_begin_job */
476  0, /* mp_end_job */
477  mp_begin_graph,
478  mp_end_graph,
479  0, /* mp_begin_layer */
480  0, /* mp_end_layer */
481  mp_begin_page,
482  0, /* mp_end_page */
483  0, /* mp_begin_cluster */
484  0, /* mp_end_cluster */
485  0, /* mp_begin_nodes */
486  0, /* mp_end_nodes */
487  0, /* mp_begin_edges */
488  0, /* mp_end_edges */
489  mp_begin_node,
490  mp_end_node,
491  mp_begin_edge,
492  mp_end_edge,
493  0, /* mp_begin_anchor */
494  0, /* mp_end_anchor */
495  0, /* mp_begin_label */
496  0, /* mp_end_label */
497  mp_textspan,
498  mp_resolve_color,
499  mp_ellipse,
500  mp_polygon,
501  mp_bezier,
502  mp_polyline,
503  mp_comment,
504  0, /* mp_library_shape */
505 };
506 
507 static gvrender_features_t render_features_mp = {
508  0, /* flags */
509  4., /* default pad - graph units */
510  NULL, /* knowncolors */
511  0, /* sizeof knowncolors */
512  HSVA_DOUBLE, /* color_type */
513 };
514 
515 static gvdevice_features_t device_features_mp = {
516  0, /* flags */
517  {0.,0.}, /* default margin - points */
518  {0.,0.}, /* default page width, height - points */
519  {72.,72.}, /* default dpi */
520 };
521 
523  {FORMAT_MP, "mp", -1, &mp_engine, &render_features_mp},
524  {0, NULL, 0, NULL, NULL}
525 };
526 
528  {FORMAT_MP, "mp:mp", -1, NULL, &device_features_mp},
529  {0, NULL, 0, NULL, NULL}
530 };
531 
#define maxColors
int rotation
Definition: gvcjob.h:328
union color_s::@10 u
pen_type pen
Definition: gvcjob.h:206
int index
Definition: color.h:42
double size
Definition: textspan.h:52
point pagesArraySize
Definition: gvcjob.h:313
#define ROUND(f)
Definition: arith.h:84
#define assert(x)
Definition: cghdr.h:47
Definition: geom.h:28
#define PF2P(pf, p)
Definition: geom.h:72
Definition: color.h:34
gvcolor_t pencolor
Definition: gvcjob.h:203
Definition: gvcjob.h:271
int x
Definition: geom.h:26
gvplugin_installed_t gvdevice_mp_types[]
obj_state_t * obj
Definition: gvcjob.h:278
int gvputs(GVJ_t *job, const char *s)
Definition: gvdevice.c:270
gvplugin_installed_t gvrender_mp_types[]
char * str
Definition: textspan.h:59
color_type_t type
Definition: color.h:44
double y
Definition: geom.h:28
CGRAPH_API char * agnameof(void *)
Definition: id.c:143
char * string
Definition: color.h:41
GVCOMMON_t * common
Definition: gvcjob.h:276
char ** info
Definition: gvcommon.h:22
#define BEZIERSUBDIVISION
PostscriptAlias * postscript_alias
Definition: textspan.h:51
Definition: grammar.c:79
graph_t * g
Definition: gvcjob.h:195
format_type
pointf Bezier(pointf *V, int degree, double t, pointf *Left, pointf *Right)
Definition: utils.c:221
#define NULL
Definition: logic.h:39
Definition: geom.h:26
double x
Definition: geom.h:28
#define streq(s, t)
Definition: cghdr.h:52
#define top(sp)
Definition: stack.h:35
char just
Definition: textspan.h:65
union obj_state_s::@23 u
gvrender_engine_t mp_engine
void(* pf)(char *, void *)
Definition: xdot.c:501
#define M_PI
Definition: arith.h:77
agxbuf * str
Definition: htmlparse.c:85
gvcolor_t fillcolor
Definition: gvcjob.h:203
double dist(Site *s, Site *t)
Definition: site.c:41
double penwidth
Definition: gvcjob.h:208
int y
Definition: geom.h:26
unsigned char rgba[4]
Definition: color.h:38
double zoom
Definition: gvcjob.h:327
void gvprintf(GVJ_t *job, const char *format,...)
Definition: gvdevice.c:389
textfont_t * font
Definition: textspan.h:60