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

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


/*
    This software may only be used by you under license from AT&T Corp.
    ("AT&T").  A copy of AT&T's Source Code Agreement is available at
    AT&T's Internet website having the URL:
    <http://www.research.att.com/sw/tools/graphviz/license/source.html>
    If you received this software without first entering into a license
    with AT&T, you have an infringing copy of this software and cannot use
    it without violating AT&T's intellectual property rights.
*/
#pragma prototyped

#include                "render.h"
#include                "gd.h"


/* IMAP font modifiers */
#define REGULAR 0
#define BOLD            1
#define ITALIC          2

/* IMAP patterns */
#define P_SOLID         0
#define P_NONE  15
#define P_DOTTED 4                              /* i wasn't sure about this */
#define P_DASHED 11                             /* or this */

#define SCALE (GD_RESOLUTION/72.0)

/* IMAP bold line constant */
#define WIDTH_NORMAL 1
#define WIDTH_BOLD 3

/* static int        N_pages; */
/* static point    Pages; */
static double   ArgScale;
static double   Scale;
static int      Rot;
static int        onetime = TRUE;

typedef struct context_t {
	char                    color_ix, *fontfam, fontopt, font_was_set;
	char                    pen, fill, penwidth, style_was_set;
	double              fontsz;
} context_t;

#define MAXNEST 4
static context_t cstk[MAXNEST];
static int        SP;

void
map_output_rect (pointf p1, pointf p2, char *url, char *label, char *tooltip)
{
    pointf	pp1,pp2;
    double 	t;

    if (!(url && url[0])) return;

    /* apply scaling and translation if necessary */
    if (Output_lang == IMAP || Output_lang == ISMAP || Output_lang == CMAP) {
	pp1 = gdpt(p1);
	pp2 = gdpt(p2);
    } else {
	pp1 = p1;
	pp2 = p2;
    }

    /* fix up coordinate order */
    if (pp2.x < pp1.x) {
	t = pp2.x;
	pp2.x = pp1.x;
	pp1.x = t;
    }
    if (pp2.y < pp1.y) {
	t = pp2.y;
	pp2.y = pp1.y;
	pp1.y = t;
    }

    if (Output_lang == IMAP) {
	fprintf(Output_file,"rect %s %d,%d %d,%d\n",
	    url,
	    ROUND(pp1.x),ROUND(pp1.y),ROUND(pp2.x),ROUND(pp2.y));
    } else if (Output_lang == ISMAP) {
    	fprintf(Output_file,"rectangle (%d,%d) (%d,%d) %s %s\n",
	    ROUND(pp1.x),ROUND(pp1.y),ROUND(pp2.x),ROUND(pp2.y),
	    url,label);
    } else if (Output_lang == CMAP) {
	fprintf(Output_file,"<area shape=\"rect\" href=\"%s\"",
	    xml_string(url));
	if (tooltip && tooltip[0]) {
	    fprintf(Output_file," title=\"%s\"", xml_string(tooltip));
	}
	if (label && label[0]) {
	    fprintf(Output_file," alt=\"%s\"", xml_string(label));
	}
	fprintf(Output_file," coords=\"%d,%d,%d,%d\">\n",
	    ROUND(pp1.x),ROUND(pp1.y),ROUND(pp2.x),ROUND(pp2.y));
    } else if (Output_lang == POSTSCRIPT || Output_lang == PDF) {
        fprintf(Output_file,"[ /Rect [ %d %d %d %d ]\n"
		"  /Border [ 0 0 0 ]\n"
		"  /Action << /Subtype /URI /URI %s >>\n"
		"  /Subtype /Link\n"
		"/ANN pdfmark\n",
	    ROUND(pp1.x),ROUND(pp1.y),ROUND(pp2.x),ROUND(pp2.y),
	    ps_string(url));
    }
}

/* radius of mouse-sensitive region around a point */
#define FUZZ 3
void
map_output_fuzzy_point (pointf p, char *url, char *label, char *tooltip)
{
    pointf    p1, p2;

    p1.x = p.x - FUZZ;
    p1.y = p.y - FUZZ;
    p2.x = p.x + FUZZ;
    p2.y = p.y + FUZZ;

    map_output_rect(p1, p2, url, label, tooltip);
}

static  void
map_reset(void)
{
	onetime = TRUE;
}

static  void
init_imap(void)
{
	SP = 0;
	cstk[0].color_ix = 0;           /* IMAP color index 0-7 */
	cstk[0].fontfam = "Times";              /* font family name */
	cstk[0].fontopt = REGULAR;              /* modifier: REGULAR, BOLD or ITALIC */
	cstk[0].pen = P_SOLID;          /* pen pattern style, default is sold */
	cstk[0].fill = P_NONE;
	cstk[0].penwidth = WIDTH_NORMAL;
}

static  void map_font(context_t* cp) { }

static  void map_color(int i) { }

static  void map_style(context_t* cp) { }

static void
map_begin_job(FILE *ofp, graph_t *g, char **lib, char *user, char *info[], point pages)
{
	/* Pages = pages; */
	/* N_pages = pages.x * pages.y; */
	if (Output_lang == IMAP) {
		fprintf(Output_file,"base referer\n");
	} else if (Output_lang == ISMAP) {
/*		fprintf(Output_file,"base referer\n"); */
	} else if (Output_lang == CMAP) {
/*		fprintf(Output_file,"base referer\n"); */
	} else if (Output_lang == POSTSCRIPT || Output_lang == PDF) {
/*		fprintf(Output_file,"base referer\n"); */
	}
}

static void map_end_job(void) { }

static void
map_begin_graph(graph_t* g, box bb, point pb)
{
	gd_begin_graph(g, bb, pb);
	if (onetime) {
		init_imap();
		onetime = FALSE;
	}
}

static pointf	Default_p1,Default_p2;
static char *Default_URL, *Default_label;

static void
map_begin_page(graph_t *g, point page, double scale, int rot, point offset)
{
	char               *s;
	ArgScale = scale;
	Scale = scale * SCALE;
	Rot = rot;
	gd_begin_page(g, page, scale, rot, offset);

	Default_URL = NULL;
	if ((s = agget(g, "URL")) && strlen(s)) {
		if (Output_lang == IMAP) {
			fprintf(Output_file,"default %s\n",s);
		} else if (Output_lang == ISMAP) {
			fprintf(Output_file,"default %s %s\n",s,g->name);
		} else if (Output_lang == CMAP) {
			Default_URL = strdup_and_subst_graph(s,g);
			Default_label = g->name;
			Default_p1.x = GD_bb(g).LL.x;
			Default_p1.y = GD_bb(g).LL.y;
			Default_p2.x = GD_bb(g).UR.x;
			Default_p2.y = GD_bb(g).UR.y;
		}
	}

}

static void map_end_page(void) {
	if (Default_URL) {
		map_output_rect(Default_p1,Default_p2,Default_URL,Default_label,"");
		free(Default_URL);
	}
}

static void map_end_graph(void) { }

void
map_begin_cluster(graph_t* g)
{
	char	*s, *t="";
	pointf	p1,p2;

	if ((s = agget(g, "URL")) && strlen(s)) {
		if (GD_label(g) != NULL) t=GD_label(g)->text;
		p1.x = GD_bb(g).LL.x;
		p1.y = GD_bb(g).LL.y;
		p2.x = GD_bb(g).UR.x;
		p2.y = GD_bb(g).UR.y;
		s = strdup_and_subst_graph(s,g);
		map_output_rect(p1,p2,s,t,t);
		free(s);
	}
}

static void map_end_cluster(void) { }

static void map_begin_nodes(void) { }

static void map_end_nodes(void) { }

static void map_begin_edges(void) { }

static void map_end_edges(void) { }

void
map_begin_node(node_t* n)
{
	char	*url=NULL, *tooltip=NULL;
	char	*m_tooltip=NULL;
	pointf	p1,p2;

	if ((url = agget(n, "URL")) && url[0]) {
		p1.x = ND_coord_i(n).x - ND_lw_i(n);
		p1.y = ND_coord_i(n).y - (ND_ht_i(n)/2);
		p2.x = ND_coord_i(n).x + ND_rw_i(n);
		p2.y = ND_coord_i(n).y + (ND_ht_i(n)/2);
		url = strdup_and_subst_node(url,n);
		if ((tooltip = agget(n, "tooltip")) && tooltip[0]) {
			m_tooltip = tooltip = strdup_and_subst_node(tooltip,n);
		}
		else {
			tooltip = ND_label(n)->text;
		}
		map_output_rect(p1,p2,url,ND_label(n)->text,tooltip);
		if (m_tooltip) free(m_tooltip);
		free(url);
	}
}

static  void map_end_node(void) { }

void
map_begin_edge(edge_t* e)
{
    /* strings */
    char	*label=NULL, *taillabel=NULL, *headlabel=NULL;
    char	*url=NULL, *headurl=NULL, *tailurl=NULL;
    char	*tooltip=NULL, *tailtooltip=NULL, *headtooltip=NULL;

    /* malloc flags for strings */
    char	*m_url=NULL, *m_headurl=NULL, *m_tailurl=NULL;
    char	*m_tooltip=NULL, *m_tailtooltip=NULL, *m_headtooltip=NULL;

    textlabel_t	*lab=NULL, *tlab=NULL, *hlab=NULL;
    pointf	p,p1,p2;
    bezier	bz;

    /*  establish correct text for main edge label, URL, tooltip */
    if ((lab=ED_label(e))) {
	    label = lab->text;
    } else {
	    label = "";
    }
    if ((url = agget(e, "URL")) && url[0]) {
	m_url = url = strdup_and_subst_edge(url,e);
	if ((tooltip = agget(e, "tooltip")) && tooltip[0]) {
		m_tooltip = tooltip = strdup_and_subst_edge(tooltip,e);
	} else {
		tooltip = label;
	}	
    } else {
	tooltip = "";
    }

    /*  establish correct text for tail label, URL, tooltip */
    if ((tlab=ED_tail_label(e))) {
	taillabel = tlab->text;
    } else {
	taillabel=label;
    } 
    if ((tailurl = agget(e, "tailURL")) && tailurl[0]) {
	m_tailurl = tailurl = strdup_and_subst_edge(tailurl,e);
	if ((tailtooltip = agget(e, "tailtooltip")) && tailtooltip[0]) {
		m_tailtooltip = tailtooltip = strdup_and_subst_edge(tailtooltip,e);
	} else {
		tailtooltip = taillabel;
	}
    } else if (url) {
	tailurl = url;
	tailtooltip = tooltip;
    }

    /*  establish correct text for head label, URL, tooltip */
    if ((hlab=ED_head_label(e))) {
	headlabel = hlab->text;
    } else {
	headlabel = label;
    }
    if ((headurl = agget(e, "headURL")) && headurl[0]) {
	m_headurl = headurl = strdup_and_subst_edge(headurl,e);
	if ((headtooltip = agget(e, "headtooltip")) && headtooltip[0]) {
		m_headtooltip = headtooltip = strdup_and_subst_edge(headtooltip,e);
	} else {
		headtooltip = headlabel;
	}
    } else if (url) {
	headurl = url;
	headtooltip = tooltip;
    }

    /* strings are now set  - next we map the three labels */

    if (lab && url) {
	/* map a rectangle around the edge label */
	p1.x = lab->p.x - lab->dimen.x*64/2;
	p1.y = lab->p.y - lab->dimen.y*64/2;
	p2.x = lab->p.x + lab->dimen.x*64/2;
	p2.y = lab->p.y + lab->dimen.y*64/2;
	map_output_rect(p1,p2,url,label,tooltip);
    }

    if (tlab && (url || tailurl)) {
	/* map a rectangle around the edge taillabel */
	p1.x = tlab->p.x - tlab->dimen.x*64/2;
	p1.y = tlab->p.y - tlab->dimen.y*64/2;
	p2.x = tlab->p.x + tlab->dimen.x*64/2;
	p2.y = tlab->p.y + tlab->dimen.y*64/2;
    	map_output_rect(p1,p2,tailurl,taillabel,tailtooltip);
    }

    if (hlab && (url || headurl)) {
	/* map a rectangle around the edge headlabel */
	p1.x = hlab->p.x - hlab->dimen.x*64/2;
	p1.y = hlab->p.y - hlab->dimen.y*64/2;
	p2.x = hlab->p.x + hlab->dimen.x*64/2;
	p2.y = hlab->p.y + hlab->dimen.y*64/2;
	map_output_rect(p1,p2,headurl,headlabel,headtooltip);
    }

#if 0
# FIXME - what is this supposed to do?  Perhaps map spline control points?
    if (ED_spl(e) && url) {
	int i,j;

	for (i = 0; i < ED_spl(e)->size; i++) {
	    bz = ED_spl(e)->list[i];
	    for (j = 0; j < bz.size; j +=3) {
		if (((i == 0) && (j == 0))  /* origin */
		            ||  ((i == (ED_spl(e)->size -1)) && (j == (bz.size - 1)))) {
		    continue;
		}
		p.x = bz.list[j].x;
		p.y = bz.list[j].y;
		map_output_fuzzy_point(p, url, ED_label(e)->text);
	    }
	}
    }
#endif

    /* finally we map the two ends of the edge where they touch nodes */

    /* process intersecion with tail node */
    if (ED_spl(e) && (url || tailurl)) {
        bz = ED_spl(e)->list[0];
        if (bz.sflag) {
	    /* Arrow at start of splines */
	    p.x = bz.sp.x;
	    p.y = bz.sp.y;
        } else {
	    /* No arrow at start of splines */
	    p.x = bz.list[0].x;
	    p.y = bz.list[0].y;
	}
	map_output_fuzzy_point(p, tailurl, taillabel, tailtooltip);
    }

    /* process intersection with head node */
    if (ED_spl(e) && (url || headurl)) {
        bz = ED_spl(e)->list[ED_spl(e)->size-1];
        if (bz.eflag) {
	    /* Arrow at end of splines */
	    p.x = bz.ep.x;
	    p.y = bz.ep.y;
        } else {
	    /* No arrow at end of splines */
	    p.x = bz.list[bz.size-1].x;
	    p.y = bz.list[bz.size-1].y;
        }
	map_output_fuzzy_point(p, headurl, headlabel, headtooltip);
    }

    if (m_url) free(m_url);
    if (m_tailurl) free(m_tailurl);
    if (m_headurl) free(m_headurl);
    if (m_tooltip) free(m_tooltip);
    if (m_tailtooltip) free(m_tailtooltip);
    if (m_headtooltip) free(m_headtooltip);
}

static  void map_end_edge(void) { }

static  void
map_begin_context(void)
{
	assert(SP + 1 < MAXNEST);
	cstk[SP + 1] = cstk[SP];
	SP++;
}

static  void
map_end_context(void)
{
	int                      c, psp = SP - 1;
	assert(SP > 0);
	if (cstk[SP].color_ix != (c = cstk[psp].color_ix))
		map_color(c);
	if (cstk[SP].font_was_set)
		map_font(&(cstk[psp]));
	if (cstk[SP].style_was_set)
		map_style(&(cstk[psp]));
	/* free(cstk[psp].fontfam); */
	SP = psp;
}

static  void
map_set_font(char* name, double size) { }

static  void
map_set_color(char* name) { }

static  void
map_set_style(char** s) { }

static  void
map_textline(point p, textline_t *line) { }

static  void
map_bezier(point* A, int n, int arrow_at_start, int arrow_at_end) { }

static  void
map_polygon(point *A, int n, int filled) { }

static  void
map_ellipse(point p, int rx, int ry, int filled) { }

static  void
map_polyline(point* A, int n) { }

static  void
map_user_shape(char *name, point *A,int  n, int filled) { }

codegen_t       IMAP_CodeGen = {
	map_reset,
	map_begin_job, map_end_job,
	map_begin_graph, map_end_graph,
	map_begin_page, map_end_page,
	map_begin_cluster, map_end_cluster,
	map_begin_nodes, map_end_nodes,
	map_begin_edges, map_end_edges,
	map_begin_node, map_end_node,
	map_begin_edge, map_end_edge,
	map_begin_context, map_end_context,
	map_set_font, map_textline,
	map_set_color, map_set_color, map_set_style,
	map_ellipse, map_polygon,
	map_bezier, map_polyline,
	0 /* map_arrowhead */, map_user_shape,
	0 /* map_comment */, gd_textsize
};

codegen_t          ISMAP_CodeGen = {
        map_reset,
        map_begin_job, map_end_job,
        map_begin_graph, map_end_graph,
        map_begin_page, map_end_page,
        map_begin_cluster, map_end_cluster,
        map_begin_nodes, map_end_nodes,
        map_begin_edges, map_end_edges,
        map_begin_node, map_end_node,
        map_begin_edge, map_end_edge,
        map_begin_context, map_end_context,
        map_set_font, map_textline,
        map_set_color, map_set_color, map_set_style,
        map_ellipse, map_polygon,
        map_bezier, map_polyline,
        0 /* map_arrowhead */, map_user_shape,
        0 /* map_comment */, gd_textsize
};

codegen_t       CMAP_CodeGen = {
	map_reset,
	map_begin_job, map_end_job,
	map_begin_graph, map_end_graph,
	map_begin_page, map_end_page,
	map_begin_cluster, map_end_cluster,
	map_begin_nodes, map_end_nodes,
	map_begin_edges, map_end_edges,
	map_begin_node, map_end_node,
	map_begin_edge, map_end_edge,
	map_begin_context, map_end_context,
	map_set_font, map_textline,
	map_set_color, map_set_color, map_set_style,
	map_ellipse, map_polygon,
	map_bezier, map_polyline,
	0 /* map_arrowhead */, map_user_shape,
	0 /* map_comment */, gd_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 webmaster@9p.io.