#pragma prototyped /* * Copyright (c) AT&T Corp. 1994-1999 * This code is licensed by AT&T Corp. For the * terms and conditions of the license, see * http://www.research.att.com/orgs/ssr/book/reuse */ /* I don't think this driver was ever finished or debugged. --S. North */ #include "render.h" #include "utils.h" /* FIG font modifiers */ #define REGULAR 0 #define BOLD 1 #define ITALIC 2 /* FIG patterns */ #define P_SOLID 0 #define P_NONE 15 #define P_DOTTED 2 #define P_DASHED 1 /* FIG bold line constant */ #define WIDTH_NORMAL 1 #define WIDTH_BOLD 3 static int N_pages; /* static point Pages; */ static double Scale; static int Rot; static box PB; static int onetime = TRUE; typedef struct context_t { unsigned char pencolor_ix,fillcolor_ix; char *fontfam,fontopt,font_was_set; char line_style,fill,penwidth,style_was_set; double fontsz,style_val; } context_t; #define MAXNEST 4 static context_t cstk[MAXNEST]; static int SP; static int figColorResolve(int *new, int r, int g, int b) { #define maxColors 256 static int top=0; static short red[maxColors],green[maxColors],blue[maxColors]; int c; int ct = -1; long rd, gd, bd, dist; long mindist = 3 * 255 * 255; /* init to max poss dist */ *new = 0; /* in case it is not a new color */ for (c = 0; c < top; c++) { rd = (long) (red[c] - r); gd = (long) (green[c] - g); bd = (long) (blue[c] - b); dist = rd * rd + gd * gd + bd * bd; if (dist < mindist) { if (dist == 0) return c; /* Return exact match color */ mindist = dist; ct = c; } } /* no exact match. We now know closest, but first try to allocate exact */ if (top++ == maxColors) return ct; /* Return closest available color */ red[c] = r; green[c] = g; blue[c] = b; *new = 1; /* flag new color */ return c; /* Return newly allocated color */ } static void fig_reset(void) { onetime = TRUE; } static void init_fig(void) { SP = 0; cstk[0].pencolor_ix = 0; /* FIG pencolor index */ cstk[0].fillcolor_ix = 0; /* FIG fillcolor index */ cstk[0].fontfam = DEFAULT_FONTNAME; /* font family name */ cstk[0].fontopt = REGULAR; /* modifier: REGULAR, BOLD or ITALIC */ cstk[0].line_style = P_SOLID; /* pen pattern style, default is solid */ cstk[0].style_val = 0.0; /* style_val, used for dashed style */ cstk[0].fill = P_NONE; cstk[0].penwidth = WIDTH_NORMAL; } static point figpt(point p) { point rv; if (Rot == 0) { rv.x = Scale * p.x; rv.y = Scale * ( 2 * PB.UR.y - p.y ); } else { rv.x = Scale * ( 2 * PB.UR.x - p.y ); rv.y = Scale * p.x; } return rv; } static double figfontsz(double size) { return Scale * size * 72.0 / 1200.0; } static void figptarray(point* A, int n, int close) { int i; point p; for (i = 0; i < n; i++) { p.x = A[i].x; p.y = A[i].y; p = figpt(p); fprintf(Output_file," %d %d",p.x,p.y); } if (close) { p.x = A[0].x; p.y = A[0].y; p = figpt(p); fprintf(Output_file," %d %d",p.x,p.y); } fprintf(Output_file,"\n"); } static void fig_font(context_t* cp) { } static void fig_style(context_t* cp) { } static void fig_comment(void* obj, attrsym_t* sym) { char *str; str = late_string(obj,sym,""); if (str[0]) fprintf(Output_file,"# %s\n",str); } static void fig_begin_job(FILE *ofp, graph_t *g, char **lib, char *user, char *info[], point pages) { /* Pages = pages; */ N_pages = pages.x * pages.y; fprintf(Output_file,"#FIG 3.2\n"); fprintf(Output_file,"Portrait\n"); fprintf(Output_file,"Center\n"); fprintf(Output_file,"Metric\n"); fprintf(Output_file,"A4\n"); fprintf(Output_file,"100.00\n"); fprintf(Output_file,"Single\n"); fprintf(Output_file,"-2\n"); fprintf(Output_file,"1200 2\n"); fprintf(Output_file,"# Generated by %s version %s (%s)\n", info[0],info[1],info[2]); fprintf(Output_file,"# For: %s\n",user); fprintf(Output_file,"# Title: %s\n",g->name); fprintf(Output_file,"# Pages: %d\n",N_pages); } static void fig_end_job(void) { fprintf(Output_file,"# end of FIG file\n"); } static void fig_begin_graph(graph_t* g, box bb, point pb) { PB = bb; if (onetime) { #if 0 fprintf(stderr,"LL %d %d UR %d %d\n", PB.LL.x,PB.LL.y,PB.UR.x, PB.UR.y); #endif init_fig(); fig_comment(g,agfindattr(g,"comment")); onetime = FALSE; } } static void fig_end_graph(void) { } static void fig_begin_page(graph_t *g, point page, double scale, int rot, point offset) { /* int page_number; */ /* point sz; */ Scale = scale * 1200.0 / 72.0; Rot = rot; /* page_number = page.x + page.y * Pages.x + 1; sz = sub_points(PB.UR,PB.LL); */ } static void fig_end_page(void) { } static void fig_begin_cluster(graph_t* g) { } static void fig_end_cluster (void) { } static void fig_begin_nodes(void) { } static void fig_end_nodes(void) { } static void fig_begin_edges(void) { } static void fig_end_edges(void) { } static void fig_begin_node(node_t* n) { fprintf(Output_file,"# %s\n",n->name); fig_comment(n,N_comment); } static void fig_end_node (void) { } static void fig_begin_edge (edge_t* e) { fprintf(Output_file,"# %s -> %s\n",e->tail->name,e->head->name); fig_comment(e,E_comment); } static void fig_end_edge (void) { } static void fig_begin_context(void) { assert(SP + 1 < MAXNEST); cstk[SP+1] = cstk[SP]; SP++; } static void fig_end_context(void) { int psp = SP - 1; assert(SP > 0); if (cstk[SP].font_was_set) fig_font(&(cstk[psp])); if (cstk[SP].style_was_set) fig_style(&(cstk[psp])); /*free(cstk[psp].fontfam);*/ SP = psp; } static void fig_set_font(char* name, double size) { char *p,*q; context_t *cp; cp = &(cstk[SP]); cp->font_was_set = TRUE; cp->fontsz = size; p = strdup(name); if ((q = strchr(p,'-'))) { *q++ = 0; if (strcasecmp(q,"italic") == 0) cp->fontopt = ITALIC; else if (strcasecmp(q,"bold") == 0) cp->fontopt = BOLD; } cp->fontfam = p; fig_font(&cstk[SP]); } static void fig_color(int i, int r, int g, int b) { int object_code=0; /* always 0 for color */ fprintf(Output_file,"%d %d #%02x%02x%02x\n", object_code, i, r, g, b); } static unsigned char fig_resolve_color(char* name) { unsigned char i; int new; char *tok; color_t color; static char *figcolor[]= {"black","blue","green","cyan", "red","magenta","yellow","white",(char *)NULL}; tok = canontoken(name); for (i = 0; figcolor[i]; i++) { if (streq(figcolor[i],tok)) return i; } colorxlate(name,&color,RGBA_BYTE); i = 32 + figColorResolve(&new,color.u.rgba[0],color.u.rgba[1],color.u.rgba[2]); if (new) fig_color(i,color.u.rgba[0],color.u.rgba[1],color.u.rgba[2]); return i; } static void fig_set_pencolor(char* name) { cstk[SP].pencolor_ix = fig_resolve_color(name); } static void fig_set_fillcolor(char* name) { cstk[SP].fillcolor_ix = fig_resolve_color(name); } static void fig_set_style(char** s) { char *line; context_t *cp; cp = &(cstk[SP]); while ((line = *s++)) { if (streq(line,"solid")) { cp->line_style = P_SOLID; cp->style_val = 0.0; } else if (streq(line,"dashed")) { cp->line_style = P_DASHED; cp->style_val = 4.0; } else if (streq(line,"dotted")) { cp->line_style = P_DOTTED; cp->style_val = 3.0; } else if (streq(line,"invis")) cp->line_style = P_NONE; else if (streq(line,"bold")) cp->penwidth = WIDTH_BOLD; else if (streq(line,"filled")) cp->fill = P_SOLID; else if (streq(line,"unfilled")) cp->fill = P_NONE; else { agerr(AGWARN, "fig_set_style: unsupported style %s - ignoring\n", line); } cp->style_was_set = TRUE; } if (cp->style_was_set) fig_style(cp); } static char * fig_string(char *s) { static char *buf = NULL; static int bufsize = 0; int pos = 0; char *p, esc; if (!buf) { bufsize = 64; buf = N_GNEW(bufsize,char); } p = buf; while (*s) { if (pos > (bufsize-8)) { bufsize *= 2; buf = grealloc(buf,bufsize); p = buf + pos; } esc = 0; switch (*s) { case '\t': esc = 't'; break; case '>': case '\'': case '`': case '\\': esc = *s; break; } if (esc) { *p++ = '\\'; *p++ = esc; pos += 2; } else { *p++ = *s; pos++; } s++; } *p = '\0'; return buf; } static void fig_textline(point p, textline_t *line) { int object_code=4; /* always 4 for text */ int sub_type=0; /* text justification */ int color=cstk[SP].pencolor_ix; int depth=0; int pen_style=0; /* not used */ int font=0; double font_size = figfontsz(cstk[SP].fontsz); double angle=Rot?(PI/2.0):0.0; int font_flags=0; double height = 0.0; double length = 0.0; point mp; switch (line->just) { case 'l': sub_type = 0; break; case 'r': sub_type = 2; break; default: case 'n': sub_type = 1; break; } mp.x = p.x; mp.y = p.y; mp = figpt(mp); fprintf(Output_file,"%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n", object_code, sub_type, color, depth, pen_style, font, font_size, angle, font_flags, height, length, mp.x, mp.y, fig_string(line->str)); } static void fig_bezier(point* A, int n, int arrow_at_start, int arrow_at_end) { int object_code=3; /* always 3 for spline */ int sub_type=4; /* always 2 for opened interpolated spline */ int line_style=cstk[SP].line_style; /* solid, dotted, dashed */ int thickness=cstk[SP].penwidth; int pen_color=cstk[SP].pencolor_ix; int fill_color=0; int depth=0; int pen_style=0; /* not used */ int area_fill=-1; double style_val=cstk[SP].style_val; int cap_style=0; int forward_arrow=0; int backward_arrow=0; int npoints=n; int i; fprintf(Output_file,"%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n", object_code, sub_type, line_style, thickness, pen_color, fill_color, depth, pen_style, area_fill, style_val, cap_style, forward_arrow, backward_arrow, npoints); figptarray(A,n,0); /* open shape */ for (i = 0; i < n; i++) fprintf(Output_file," %d", i%(n-1)?1:-1); /* -1 on first and last */ fprintf(Output_file,"\n"); } static void fig_polygon(point *A, int n, int filled) { int object_code=2; /* always 2 for polyline */ int sub_type=3; /* always 3 for polygon */ int line_style=cstk[SP].line_style; /* solid, dotted, dashed */ int thickness=cstk[SP].penwidth; int pen_color=cstk[SP].pencolor_ix; int fill_color=cstk[SP].fillcolor_ix; int depth=0; int pen_style=0; /* not used */ int area_fill=filled ? 20 : -1; double style_val=cstk[SP].style_val; int join_style=0; int cap_style=0; int radius=0; int forward_arrow=0; int backward_arrow=0; int npoints=n+1; fprintf(Output_file,"%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n", object_code, sub_type, line_style, thickness, pen_color, fill_color, depth, pen_style, area_fill, style_val, join_style, cap_style, radius, forward_arrow, backward_arrow, npoints); figptarray(A,n,1); /* closed shape */ } static void fig_ellipse(point p, int rx, int ry, int filled) { int object_code=1; /* always 1 for ellipse */ int sub_type=1; /* ellipse defined by radii */ int line_style=cstk[SP].line_style; /* solid, dotted, dashed */ int thickness=cstk[SP].penwidth; int pen_color=cstk[SP].pencolor_ix; int fill_color=cstk[SP].fillcolor_ix; int depth=0; int pen_style=0; /* not used */ int area_fill=filled ? 20 : -1; double style_val=cstk[SP].style_val; int direction=0; double angle=0.0; int center_x, center_y, radius_x, radius_y; int start_x, start_y, end_x, end_y; #if 0 fprintf (stderr, "p %d %d\n", p.x, p.y); #endif if (Rot == 0) { start_x = center_x = Scale * p.x; /* FIXME - why do I need 2 * ??? */ start_y = center_y = Scale * (2 * PB.UR.y - p.y); radius_x = Scale * rx; radius_y = Scale * ry; } else { start_x = center_x = Scale * (2 * PB.UR.x - p.y); start_y = center_y = Scale * p.x; radius_x = Scale * ry; radius_y = Scale * rx; } end_x = start_x + radius_x; end_y = start_y + radius_y; fprintf(Output_file,"%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n", object_code, sub_type, line_style, thickness, pen_color, fill_color, depth, pen_style, area_fill, style_val, direction, angle, center_x, center_y, radius_x, radius_y, start_x, start_y, end_x, end_y); } static void fig_polyline(point* A, int n) { int object_code=2; /* always 2 for polyline */ int sub_type=1; /* always 1 for polyline */ int line_style=cstk[SP].line_style; /* solid, dotted, dashed */ int thickness=cstk[SP].penwidth; int pen_color=cstk[SP].pencolor_ix; int fill_color=0; int depth=0; int pen_style=0; /* not used */ int area_fill=0; double style_val=cstk[SP].style_val; int join_style=0; int cap_style=0; int radius=0; int forward_arrow=0; int backward_arrow=0; int npoints=n; fprintf(Output_file,"%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n", object_code, sub_type, line_style, thickness, pen_color, fill_color, depth, pen_style, area_fill, style_val, join_style, cap_style, radius, forward_arrow, backward_arrow, npoints); figptarray(A,n,0); /* open shape */ } static void fig_user_shape(char *name, point *A, int n, int filled) { static boolean onetime = TRUE; if (onetime) { agerr(AGERR, "custom shapes not available with this driver\n"); onetime = FALSE; } } codegen_t FIG_CodeGen = { fig_reset, fig_begin_job, fig_end_job, fig_begin_graph, fig_end_graph, fig_begin_page, fig_end_page, fig_begin_cluster, fig_end_cluster, fig_begin_nodes, fig_end_nodes, fig_begin_edges, fig_end_edges, fig_begin_node, fig_end_node, fig_begin_edge, fig_end_edge, fig_begin_context, fig_end_context, fig_set_font, fig_textline, fig_set_pencolor, fig_set_fillcolor, fig_set_style, fig_ellipse, fig_polygon, fig_bezier, fig_polyline, 0 /* fig_arrowhead */, fig_user_shape, 0 /* fig_comment */, 0 /* fig_textsize */ };