|
Graphviz
2.29.20120524.0446
|
00001 /* $Id$ $Revision$ */ 00002 /* vim:set shiftwidth=4 ts=8: */ 00003 00004 /************************************************************************* 00005 * Copyright (c) 2011 AT&T Intellectual Property 00006 * All rights reserved. This program and the accompanying materials 00007 * are made available under the terms of the Eclipse Public License v1.0 00008 * which accompanies this distribution, and is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * 00011 * Contributors: See CVS logs. Details at http://www.graphviz.org/ 00012 *************************************************************************/ 00013 00014 /* FIXME - incomplete replacement for codegen */ 00015 00016 #ifdef HAVE_CONFIG_H 00017 #include "config.h" 00018 #endif 00019 00020 #include <stdarg.h> 00021 #include <stdlib.h> 00022 #include <string.h> 00023 #include <ctype.h> 00024 00025 #ifdef WIN32 00026 #include <io.h> 00027 #include "compat.h" 00028 #endif 00029 00030 #include "macros.h" 00031 #include "const.h" 00032 00033 #include "gvdevice.h" 00034 #include "gvplugin_render.h" 00035 #include "gvplugin_device.h" 00036 #include "agxbuf.h" 00037 #include "utils.h" 00038 #include "color.h" 00039 00040 /* Number of points to split splines into */ 00041 #define BEZIERSUBDIVISION 6 00042 00043 typedef enum { FORMAT_HPGL, } format_type; 00044 00045 static int Depth; 00046 00047 static void hpglptarray(GVJ_t *job, pointf * A, int n, int close) 00048 { 00049 int i; 00050 point p; 00051 00052 for (i = 0; i < n; i++) { 00053 PF2P(A[i],p); 00054 gvprintf(job, " %d %d", p.x, p.y); 00055 } 00056 if (close) { 00057 PF2P(A[0],p); 00058 gvprintf(job, " %d %d", p.x, p.y); 00059 } 00060 gvputs(job, "\n"); 00061 } 00062 00063 static char *hpgl_string(char *s) 00064 { 00065 static char *buf = NULL; 00066 static int bufsize = 0; 00067 int pos = 0; 00068 char *p; 00069 unsigned char c; 00070 00071 if (!buf) { 00072 bufsize = 64; 00073 buf = malloc(bufsize * sizeof(char)); 00074 } 00075 00076 p = buf; 00077 while ((c = *s++)) { 00078 if (pos > (bufsize - 8)) { 00079 bufsize *= 2; 00080 buf = realloc(buf, bufsize * sizeof(char)); 00081 p = buf + pos; 00082 } 00083 if (isascii(c)) { 00084 if (c == '\\') { 00085 *p++ = '\\'; 00086 pos++; 00087 } 00088 *p++ = c; 00089 pos++; 00090 } else { 00091 *p++ = '\\'; 00092 sprintf(p, "%03o", c); 00093 p += 3; 00094 pos += 4; 00095 } 00096 } 00097 *p = '\0'; 00098 return buf; 00099 } 00100 00101 static int hpglColorResolve(int *new, int r, int g, int b) 00102 { 00103 #define maxColors 256 00104 static int top = 0; 00105 static short red[maxColors], green[maxColors], blue[maxColors]; 00106 int c; 00107 int ct = -1; 00108 long rd, gd, bd, dist; 00109 long mindist = 3 * 255 * 255; /* init to max poss dist */ 00110 00111 *new = 0; /* in case it is not a new color */ 00112 for (c = 0; c < top; c++) { 00113 rd = (long) (red[c] - r); 00114 gd = (long) (green[c] - g); 00115 bd = (long) (blue[c] - b); 00116 dist = rd * rd + gd * gd + bd * bd; 00117 if (dist < mindist) { 00118 if (dist == 0) 00119 return c; /* Return exact match color */ 00120 mindist = dist; 00121 ct = c; 00122 } 00123 } 00124 /* no exact match. We now know closest, but first try to allocate exact */ 00125 if (top++ == maxColors) 00126 return ct; /* Return closest available color */ 00127 red[c] = r; 00128 green[c] = g; 00129 blue[c] = b; 00130 *new = 1; /* flag new color */ 00131 return c; /* Return newly allocated color */ 00132 } 00133 00134 /* this table is in xfig color index order */ 00135 static char *hpglcolor[] = { 00136 "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL 00137 }; 00138 00139 static void hpgl_resolve_color(GVJ_t *job, gvcolor_t * color) 00140 { 00141 int object_code = 0; /* always 0 for color */ 00142 int i, new; 00143 00144 switch (color->type) { 00145 case COLOR_STRING: 00146 for (i = 0; hpglcolor[i]; i++) { 00147 if (streq(hpglcolor[i], color->u.string)) { 00148 color->u.index = i; 00149 break; 00150 } 00151 } 00152 break; 00153 case RGBA_BYTE: 00154 i = 32 + hpglColorResolve(&new, 00155 color->u.rgba[0], 00156 color->u.rgba[1], 00157 color->u.rgba[2]); 00158 if (new) 00159 gvprintf(job, "%d %d #%02x%02x%02x\n", 00160 object_code, i, 00161 color->u.rgba[0], 00162 color->u.rgba[1], 00163 color->u.rgba[2]); 00164 color->u.index = i; 00165 break; 00166 default: 00167 assert(0); /* internal error */ 00168 } 00169 00170 color->type = COLOR_INDEX; 00171 } 00172 00173 static void hpgl_line_style(obj_state_t *obj, int *line_style, double *style_val) 00174 { 00175 switch (obj->pen) { 00176 case PEN_DASHED: 00177 *line_style = 1; 00178 *style_val = 10.; 00179 break; 00180 case PEN_DOTTED: 00181 *line_style = 2; 00182 *style_val = 10.; 00183 break; 00184 case PEN_SOLID: 00185 default: 00186 *line_style = 0; 00187 *style_val = 0.; 00188 break; 00189 } 00190 } 00191 00192 static void hpgl_comment(GVJ_t *job, char *str) 00193 { 00194 gvprintf(job, "# %s\n", str); 00195 } 00196 00197 static void hpgl_begin_graph(GVJ_t * job) 00198 { 00199 obj_state_t *obj = job->obj; 00200 00201 gvputs(job, "#FIG 3.2\n"); 00202 gvprintf(job, "# Generated by %s version %s (%s)\n", 00203 job->common->info[0], job->common->info[1], job->common->info[2]); 00204 gvprintf(job, "# Title: %s\n", obj->u.g->name); 00205 gvprintf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y); 00206 gvputs(job, "Portrait\n"); /* orientation */ 00207 gvputs(job, "Center\n"); /* justification */ 00208 gvputs(job, "Inches\n"); /* units */ 00209 gvputs(job, "Letter\n"); /* papersize */ 00210 gvputs(job, "100.00\n"); /* magnification % */ 00211 gvputs(job, "Single\n"); /* multiple-page */ 00212 gvputs(job, "-2\n"); /* transparent color (none) */ 00213 gvputs(job, "1200"); /* resolution */ 00214 gvputs(job, " 2\n"); /* coordinate system (upper left) */ 00215 } 00216 00217 static void hpgl_end_graph(GVJ_t * job) 00218 { 00219 gvputs(job, "# end of FIG file\n"); 00220 } 00221 00222 static void hpgl_begin_page(GVJ_t * job) 00223 { 00224 Depth = 2; 00225 } 00226 00227 static void hpgl_begin_node(GVJ_t * job) 00228 { 00229 Depth = 1; 00230 } 00231 00232 static void hpgl_end_node(GVJ_t * job) 00233 { 00234 Depth = 2; 00235 } 00236 00237 static void hpgl_begin_edge(GVJ_t * job) 00238 { 00239 Depth = 0; 00240 } 00241 00242 static void hpgl_end_edge(GVJ_t * job) 00243 { 00244 Depth = 2; 00245 } 00246 00247 static void hpgl_textpara(GVJ_t * job, pointf p, textpara_t * para) 00248 { 00249 obj_state_t *obj = job->obj; 00250 00251 int object_code = 4; /* always 4 for text */ 00252 int sub_type = 0; /* text justification */ 00253 int color = obj->pencolor.u.index; 00254 int depth = Depth; 00255 int pen_style = 0; /* not used */ 00256 int font = -1; /* init to xfig's default font */ 00257 double font_size = para->fontsize * job->zoom; 00258 double angle = job->rotation ? (M_PI / 2.0) : 0.0; 00259 int font_flags = 4; /* PostScript font */ 00260 double height = 0.0; 00261 double length = 0.0; 00262 00263 if (para->postscript_alias) /* if it is a standard postscript font */ 00264 font = para->postscript_alias->xfig_code; 00265 00266 switch (para->just) { 00267 case 'l': 00268 sub_type = 0; 00269 break; 00270 case 'r': 00271 sub_type = 2; 00272 break; 00273 default: 00274 case 'n': 00275 sub_type = 1; 00276 break; 00277 } 00278 00279 gvprintf(job, 00280 "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n", 00281 object_code, sub_type, color, depth, pen_style, font, 00282 font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y), 00283 hpgl_string(para->str)); 00284 } 00285 00286 static void hpgl_ellipse(GVJ_t * job, pointf * A, int filled) 00287 { 00288 obj_state_t *obj = job->obj; 00289 00290 int object_code = 1; /* always 1 for ellipse */ 00291 int sub_type = 1; /* ellipse defined by radii */ 00292 int line_style; /* solid, dotted, dashed */ 00293 int thickness = obj->penwidth; 00294 int pen_color = obj->pencolor.u.index; 00295 int fill_color = obj->fillcolor.u.index; 00296 int depth = Depth; 00297 int pen_style = 0; /* not used */ 00298 int area_fill = filled ? 20 : -1; 00299 double style_val; 00300 int direction = 0; 00301 double angle = 0.0; 00302 int center_x, center_y, radius_x, radius_y; 00303 int start_x, start_y, end_x, end_y; 00304 00305 hpgl_line_style(obj, &line_style, &style_val); 00306 00307 start_x = center_x = ROUND(A[0].x); 00308 start_y = center_y = ROUND(A[0].y); 00309 radius_x = ROUND(A[1].x - A[0].x); 00310 radius_y = ROUND(A[1].y - A[0].y); 00311 end_x = ROUND(A[1].x); 00312 end_y = ROUND(A[1].y); 00313 00314 gvprintf(job, 00315 "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n", 00316 object_code, sub_type, line_style, thickness, pen_color, 00317 fill_color, depth, pen_style, area_fill, style_val, direction, 00318 angle, center_x, center_y, radius_x, radius_y, start_x, 00319 start_y, end_x, end_y); 00320 } 00321 00322 static void hpgl_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start, 00323 int arrow_at_end, int filled) 00324 { 00325 obj_state_t *obj = job->obj; 00326 00327 int object_code = 3; /* always 3 for spline */ 00328 int sub_type; 00329 int line_style; /* solid, dotted, dashed */ 00330 int thickness = obj->penwidth; 00331 int pen_color = obj->pencolor.u.index; 00332 int fill_color = obj->fillcolor.u.index; 00333 int depth = Depth; 00334 int pen_style = 0; /* not used */ 00335 int area_fill; 00336 double style_val; 00337 int cap_style = 0; 00338 int forward_arrow = 0; 00339 int backward_arrow = 0; 00340 int npoints = n; 00341 int i; 00342 00343 pointf pf, V[4]; 00344 point p; 00345 int j, step; 00346 int count = 0; 00347 int size; 00348 00349 char *buffer; 00350 char *buf; 00351 buffer = 00352 malloc((npoints + 1) * (BEZIERSUBDIVISION + 00353 1) * 20 * sizeof(char)); 00354 buf = buffer; 00355 00356 hpgl_line_style(obj, &line_style, &style_val); 00357 00358 if (filled) { 00359 sub_type = 5; /* closed X-spline */ 00360 area_fill = 20; /* fully saturated color */ 00361 fill_color = job->obj->fillcolor.u.index; 00362 } 00363 else { 00364 sub_type = 4; /* opened X-spline */ 00365 area_fill = -1; 00366 fill_color = 0; 00367 } 00368 V[3].x = A[0].x; 00369 V[3].y = A[0].y; 00370 /* Write first point in line */ 00371 count++; 00372 PF2P(A[0], p); 00373 size = sprintf(buf, " %d %d", p.x, p.y); 00374 buf += size; 00375 /* write subsequent points */ 00376 for (i = 0; i + 3 < n; i += 3) { 00377 V[0] = V[3]; 00378 for (j = 1; j <= 3; j++) { 00379 V[j].x = A[i + j].x; 00380 V[j].y = A[i + j].y; 00381 } 00382 for (step = 1; step <= BEZIERSUBDIVISION; step++) { 00383 count++; 00384 pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL); 00385 PF2P(pf, p); 00386 size = sprintf(buf, " %d %d", p.x, p.y); 00387 buf += size; 00388 } 00389 } 00390 00391 gvprintf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n", 00392 object_code, 00393 sub_type, 00394 line_style, 00395 thickness, 00396 pen_color, 00397 fill_color, 00398 depth, 00399 pen_style, 00400 area_fill, 00401 style_val, cap_style, forward_arrow, backward_arrow, count); 00402 00403 gvprintf(job, " %s\n", buffer); /* print points */ 00404 free(buffer); 00405 for (i = 0; i < count; i++) { 00406 gvprintf(job, " %d", i % (count - 1) ? 1 : 0); /* -1 on all */ 00407 } 00408 gvputs(job, "\n"); 00409 } 00410 00411 static void hpgl_polygon(GVJ_t * job, pointf * A, int n, int filled) 00412 { 00413 obj_state_t *obj = job->obj; 00414 00415 int object_code = 2; /* always 2 for polyline */ 00416 int sub_type = 3; /* always 3 for polygon */ 00417 int line_style; /* solid, dotted, dashed */ 00418 int thickness = obj->penwidth; 00419 int pen_color = obj->pencolor.u.index; 00420 int fill_color = obj->fillcolor.u.index; 00421 int depth = Depth; 00422 int pen_style = 0; /* not used */ 00423 int area_fill = filled ? 20 : -1; 00424 double style_val; 00425 int join_style = 0; 00426 int cap_style = 0; 00427 int radius = 0; 00428 int forward_arrow = 0; 00429 int backward_arrow = 0; 00430 int npoints = n + 1; 00431 00432 hpgl_line_style(obj, &line_style, &style_val); 00433 00434 gvprintf(job, 00435 "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n", 00436 object_code, sub_type, line_style, thickness, pen_color, 00437 fill_color, depth, pen_style, area_fill, style_val, join_style, 00438 cap_style, radius, forward_arrow, backward_arrow, npoints); 00439 hpglptarray(job, A, n, 1); /* closed shape */ 00440 } 00441 00442 static void hpgl_polyline(GVJ_t * job, pointf * A, int n) 00443 { 00444 obj_state_t *obj = job->obj; 00445 00446 int object_code = 2; /* always 2 for polyline */ 00447 int sub_type = 1; /* always 1 for polyline */ 00448 int line_style; /* solid, dotted, dashed */ 00449 int thickness = obj->penwidth; 00450 int pen_color = obj->pencolor.u.index; 00451 int fill_color = 0; 00452 int depth = Depth; 00453 int pen_style = 0; /* not used */ 00454 int area_fill = 0; 00455 double style_val; 00456 int join_style = 0; 00457 int cap_style = 0; 00458 int radius = 0; 00459 int forward_arrow = 0; 00460 int backward_arrow = 0; 00461 int npoints = n; 00462 00463 hpgl_line_style(obj, &line_style, &style_val); 00464 00465 gvprintf(job, 00466 "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n", 00467 object_code, sub_type, line_style, thickness, pen_color, 00468 fill_color, depth, pen_style, area_fill, style_val, join_style, 00469 cap_style, radius, forward_arrow, backward_arrow, npoints); 00470 hpglptarray(job, A, n, 0); /* open shape */ 00471 } 00472 00473 gvrender_engine_t hpgl_engine = { 00474 0, /* hpgl_begin_job */ 00475 0, /* hpgl_end_job */ 00476 hpgl_begin_graph, 00477 hpgl_end_graph, 00478 0, /* hpgl_begin_layer */ 00479 0, /* hpgl_end_layer */ 00480 hpgl_begin_page, 00481 0, /* hpgl_end_page */ 00482 0, /* hpgl_begin_cluster */ 00483 0, /* hpgl_end_cluster */ 00484 0, /* hpgl_begin_nodes */ 00485 0, /* hpgl_end_nodes */ 00486 0, /* hpgl_begin_edges */ 00487 0, /* hpgl_end_edges */ 00488 hpgl_begin_node, 00489 hpgl_end_node, 00490 hpgl_begin_edge, 00491 hpgl_end_edge, 00492 0, /* hpgl_begin_anchor */ 00493 0, /* hpgl_end_anchor */ 00494 0, /* hpgl_begin_label */ 00495 0, /* hpgl_end_label */ 00496 hpgl_textpara, 00497 hpgl_resolve_color, 00498 hpgl_ellipse, 00499 hpgl_polygon, 00500 hpgl_bezier, 00501 hpgl_polyline, 00502 hpgl_comment, 00503 0, /* hpgl_library_shape */ 00504 }; 00505 00506 static gvrender_features_t render_features_hpgl = { 00507 0, /* flags */ 00508 4., /* default pad - graph units */ 00509 NULL, /* knowncolors */ 00510 0, /* sizeof knowncolors */ 00511 HSVA_DOUBLE, /* color_type */ 00512 }; 00513 00514 static gvdevice_features_t device_features_hpgl = { 00515 0, /* flags */ 00516 {0.,0.}, /* default margin - points */ 00517 {0.,0.}, /* default page width, height - points */ 00518 {72.,72.}, /* default dpi */ 00519 }; 00520 00521 gvplugin_installed_t gvrender_hpgl_types[] = { 00522 {FORMAT_HPGL, "hpgl", -1, &hpgl_engine, &render_features_hpgl}, 00523 {0, NULL, 0, NULL, NULL} 00524 }; 00525 00526 gvplugin_installed_t gvdevice_hpgl_types[] = { 00527 {FORMAT_HPGL, "hpgl:hpgl", -1, NULL, &device_features_hpgl}, 00528 {0, NULL, 0, NULL, NULL} 00529 };
1.7.5