#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 */
};
|