00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 #include "config.h"
00019 #endif
00020
00021 #include <stdarg.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <ctype.h>
00025
00026 #ifdef WIN32
00027 #include <io.h>
00028 #include "compat.h"
00029 #endif
00030
00031 #include "macros.h"
00032 #include "const.h"
00033
00034 #include "gvplugin_render.h"
00035 #include "graph.h"
00036 #include "agxbuf.h"
00037 #include "utils.h"
00038 #include "color.h"
00039
00040
00041 #define BEZIERSUBDIVISION 6
00042
00043 typedef enum { FORMAT_FIG, } format_type;
00044
00045 static int Depth;
00046
00047 static void figptarray(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 gvdevice_printf(job, " %d %d", p.x, p.y);
00055 }
00056 if (close) {
00057 PF2P(A[0],p);
00058 gvdevice_printf(job, " %d %d", p.x, p.y);
00059 }
00060 gvdevice_fputs(job, "\n");
00061 }
00062
00063 static char *fig_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 figColorResolve(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;
00110
00111 *new = 0;
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;
00120 mindist = dist;
00121 ct = c;
00122 }
00123 }
00124
00125 if (top++ == maxColors)
00126 return ct;
00127 red[c] = r;
00128 green[c] = g;
00129 blue[c] = b;
00130 *new = 1;
00131 return c;
00132 }
00133
00134
00135 static char *figcolor[] = {
00136 "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
00137 };
00138
00139 static void fig_resolve_color(GVJ_t *job, gvcolor_t * color)
00140 {
00141 int object_code = 0;
00142 int i, new;
00143
00144 switch (color->type) {
00145 case COLOR_STRING:
00146 for (i = 0; figcolor[i]; i++) {
00147 if (streq(figcolor[i], color->u.string)) {
00148 color->u.index = i;
00149 break;
00150 }
00151 }
00152 break;
00153 case RGBA_BYTE:
00154 i = 32 + figColorResolve(&new,
00155 color->u.rgba[0],
00156 color->u.rgba[1],
00157 color->u.rgba[2]);
00158 if (new)
00159 gvdevice_printf(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);
00168 }
00169
00170 color->type = COLOR_INDEX;
00171 }
00172
00173 static void fig_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 fig_comment(GVJ_t *job, char *str)
00193 {
00194 gvdevice_printf(job, "# %s\n", str);
00195 }
00196
00197 static void fig_begin_graph(GVJ_t * job)
00198 {
00199 obj_state_t *obj = job->obj;
00200
00201 gvdevice_fputs(job, "#FIG 3.2\n");
00202 gvdevice_printf(job, "# Generated by %s version %s (%s)\n",
00203 job->common->info[0], job->common->info[1], job->common->info[2]);
00204 gvdevice_printf(job, "# For: %s\n", job->common->user);
00205 gvdevice_printf(job, "# Title: %s\n", obj->u.g->name);
00206 gvdevice_printf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
00207 gvdevice_fputs(job, "Portrait\n");
00208 gvdevice_fputs(job, "Center\n");
00209 gvdevice_fputs(job, "Inches\n");
00210 gvdevice_fputs(job, "Letter\n");
00211 gvdevice_fputs(job, "100.00\n");
00212 gvdevice_fputs(job, "Single\n");
00213 gvdevice_fputs(job, "-2\n");
00214 gvdevice_fputs(job, "1200");
00215 gvdevice_fputs(job, " 2\n");
00216 }
00217
00218 static void fig_end_graph(GVJ_t * job)
00219 {
00220 gvdevice_fputs(job, "# end of FIG file\n");
00221 }
00222
00223 static void fig_begin_page(GVJ_t * job)
00224 {
00225 Depth = 2;
00226 }
00227
00228 static void fig_begin_node(GVJ_t * job)
00229 {
00230 Depth = 1;
00231 }
00232
00233 static void fig_end_node(GVJ_t * job)
00234 {
00235 Depth = 2;
00236 }
00237
00238 static void fig_begin_edge(GVJ_t * job)
00239 {
00240 Depth = 0;
00241 }
00242
00243 static void fig_end_edge(GVJ_t * job)
00244 {
00245 Depth = 2;
00246 }
00247
00248 static void fig_textpara(GVJ_t * job, pointf p, textpara_t * para)
00249 {
00250 obj_state_t *obj = job->obj;
00251
00252 int object_code = 4;
00253 int sub_type = 0;
00254 int color = obj->pencolor.u.index;
00255 int depth = Depth;
00256 int pen_style = 0;
00257 int font = -1;
00258 double font_size = para->fontsize * job->zoom;
00259 double angle = job->rotation ? (M_PI / 2.0) : 0.0;
00260 int font_flags = 6;
00261
00262
00263
00264
00265 double height = 0.0;
00266 double length = 0.0;
00267
00268 if (para->postscript_alias)
00269 font = para->postscript_alias->xfig_code;
00270
00271 switch (para->just) {
00272 case 'l':
00273 sub_type = 0;
00274 break;
00275 case 'r':
00276 sub_type = 2;
00277 break;
00278 default:
00279 case 'n':
00280 sub_type = 1;
00281 break;
00282 }
00283
00284 gvdevice_printf(job,
00285 "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
00286 object_code, sub_type, color, depth, pen_style, font,
00287 font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
00288 fig_string(para->str));
00289 }
00290
00291 static void fig_ellipse(GVJ_t * job, pointf * A, int filled)
00292 {
00293 obj_state_t *obj = job->obj;
00294
00295 int object_code = 1;
00296 int sub_type = 1;
00297 int line_style;
00298 int thickness = obj->penwidth;
00299 int pen_color = obj->pencolor.u.index;
00300 int fill_color = obj->fillcolor.u.index;
00301 int depth = Depth;
00302 int pen_style = 0;
00303 int area_fill = filled ? 20 : -1;
00304 double style_val;
00305 int direction = 0;
00306 double angle = 0.0;
00307 int center_x, center_y, radius_x, radius_y;
00308 int start_x, start_y, end_x, end_y;
00309
00310 fig_line_style(obj, &line_style, &style_val);
00311
00312 start_x = center_x = ROUND(A[0].x);
00313 start_y = center_y = ROUND(A[0].y);
00314 radius_x = ROUND(A[1].x - A[0].x);
00315 radius_y = ROUND(A[1].y - A[0].y);
00316 end_x = ROUND(A[1].x);
00317 end_y = ROUND(A[1].y);
00318
00319 gvdevice_printf(job,
00320 "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
00321 object_code, sub_type, line_style, thickness, pen_color,
00322 fill_color, depth, pen_style, area_fill, style_val, direction,
00323 angle, center_x, center_y, radius_x, radius_y, start_x,
00324 start_y, end_x, end_y);
00325 }
00326
00327 static void fig_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00328 int arrow_at_end, int filled)
00329 {
00330 obj_state_t *obj = job->obj;
00331
00332 int object_code = 3;
00333 int sub_type;
00334 int line_style;
00335 int thickness = obj->penwidth;
00336 int pen_color = obj->pencolor.u.index;
00337 int fill_color = obj->fillcolor.u.index;
00338 int depth = Depth;
00339 int pen_style = 0;
00340 int area_fill;
00341 double style_val;
00342 int cap_style = 0;
00343 int forward_arrow = 0;
00344 int backward_arrow = 0;
00345 int npoints = n;
00346 int i;
00347
00348 pointf pf, V[4];
00349 point p;
00350 int j, step;
00351 int count = 0;
00352 int size;
00353
00354 char *buffer;
00355 char *buf;
00356 buffer =
00357 malloc((npoints + 1) * (BEZIERSUBDIVISION +
00358 1) * 20 * sizeof(char));
00359 buf = buffer;
00360
00361 fig_line_style(obj, &line_style, &style_val);
00362
00363 if (filled) {
00364 sub_type = 5;
00365 area_fill = 20;
00366 fill_color = job->obj->fillcolor.u.index;
00367 }
00368 else {
00369 sub_type = 4;
00370 area_fill = -1;
00371 fill_color = 0;
00372 }
00373 V[3].x = A[0].x;
00374 V[3].y = A[0].y;
00375
00376 count++;
00377 PF2P(A[0], p);
00378 size = sprintf(buf, " %d %d", p.x, p.y);
00379 buf += size;
00380
00381 for (i = 0; i + 3 < n; i += 3) {
00382 V[0] = V[3];
00383 for (j = 1; j <= 3; j++) {
00384 V[j].x = A[i + j].x;
00385 V[j].y = A[i + j].y;
00386 }
00387 for (step = 1; step <= BEZIERSUBDIVISION; step++) {
00388 count++;
00389 pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
00390 PF2P(pf, p);
00391 size = sprintf(buf, " %d %d", p.x, p.y);
00392 buf += size;
00393 }
00394 }
00395
00396 gvdevice_printf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
00397 object_code,
00398 sub_type,
00399 line_style,
00400 thickness,
00401 pen_color,
00402 fill_color,
00403 depth,
00404 pen_style,
00405 area_fill,
00406 style_val, cap_style, forward_arrow, backward_arrow, count);
00407
00408 gvdevice_printf(job, " %s\n", buffer);
00409 free(buffer);
00410 for (i = 0; i < count; i++) {
00411 gvdevice_printf(job, " %d", i % (count - 1) ? 1 : 0);
00412 }
00413 gvdevice_fputs(job, "\n");
00414 }
00415
00416 static void fig_polygon(GVJ_t * job, pointf * A, int n, int filled)
00417 {
00418 obj_state_t *obj = job->obj;
00419
00420 int object_code = 2;
00421 int sub_type = 3;
00422 int line_style;
00423 int thickness = obj->penwidth;
00424 int pen_color = obj->pencolor.u.index;
00425 int fill_color = obj->fillcolor.u.index;
00426 int depth = Depth;
00427 int pen_style = 0;
00428 int area_fill = filled ? 20 : -1;
00429 double style_val;
00430 int join_style = 0;
00431 int cap_style = 0;
00432 int radius = 0;
00433 int forward_arrow = 0;
00434 int backward_arrow = 0;
00435 int npoints = n + 1;
00436
00437 fig_line_style(obj, &line_style, &style_val);
00438
00439 gvdevice_printf(job,
00440 "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
00441 object_code, sub_type, line_style, thickness, pen_color,
00442 fill_color, depth, pen_style, area_fill, style_val, join_style,
00443 cap_style, radius, forward_arrow, backward_arrow, npoints);
00444 figptarray(job, A, n, 1);
00445 }
00446
00447 static void fig_polyline(GVJ_t * job, pointf * A, int n)
00448 {
00449 obj_state_t *obj = job->obj;
00450
00451 int object_code = 2;
00452 int sub_type = 1;
00453 int line_style;
00454 int thickness = obj->penwidth;
00455 int pen_color = obj->pencolor.u.index;
00456 int fill_color = 0;
00457 int depth = Depth;
00458 int pen_style = 0;
00459 int area_fill = 0;
00460 double style_val;
00461 int join_style = 0;
00462 int cap_style = 0;
00463 int radius = 0;
00464 int forward_arrow = 0;
00465 int backward_arrow = 0;
00466 int npoints = n;
00467
00468 fig_line_style(obj, &line_style, &style_val);
00469
00470 gvdevice_printf(job,
00471 "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
00472 object_code, sub_type, line_style, thickness, pen_color,
00473 fill_color, depth, pen_style, area_fill, style_val, join_style,
00474 cap_style, radius, forward_arrow, backward_arrow, npoints);
00475 figptarray(job, A, n, 0);
00476 }
00477
00478 gvrender_engine_t fig_engine = {
00479 0,
00480 0,
00481 fig_begin_graph,
00482 fig_end_graph,
00483 0,
00484 0,
00485 fig_begin_page,
00486 0,
00487 0,
00488 0,
00489 0,
00490 0,
00491 0,
00492 0,
00493 fig_begin_node,
00494 fig_end_node,
00495 fig_begin_edge,
00496 fig_end_edge,
00497 0,
00498 0,
00499 fig_textpara,
00500 fig_resolve_color,
00501 fig_ellipse,
00502 fig_polygon,
00503 fig_bezier,
00504 fig_polyline,
00505 fig_comment,
00506 0,
00507 };
00508
00509
00510
00511 static char *fig_knowncolors[] = {
00512 "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
00513 };
00514
00515
00516 gvrender_features_t render_features_fig = {
00517 EMIT_COLORS
00518 | GVRENDER_Y_GOES_DOWN,
00519 4.,
00520 fig_knowncolors,
00521 sizeof(fig_knowncolors) / sizeof(char *),
00522 RGBA_BYTE,
00523 };
00524
00525 gvdevice_features_t device_features_fig = {
00526 EMIT_COLORS
00527 | GVRENDER_Y_GOES_DOWN,
00528 {0.,0.},
00529 {0.,0.},
00530 {1440.,1440.},
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540 };
00541
00542 gvplugin_installed_t gvrender_fig_types[] = {
00543 {FORMAT_FIG, "fig", 1, &fig_engine, &render_features_fig},
00544 {0, NULL, 0, NULL, NULL}
00545 };
00546
00547 gvplugin_installed_t gvdevice_fig_types[] = {
00548 {FORMAT_FIG, "fig:fig", 1, NULL, &device_features_fig},
00549 {0, NULL, 0, NULL, NULL}
00550 };