Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/graphviz/dotneato/common/figgen.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


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

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].