* graphics code generator
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
#include <ctype.h>
#include "render.h"
#include "agxbuf.h"
+#include "htmltable.h"
+#define P2RECT(p, pr, sx, sy) (pr[0].x = p.x - sx, pr[0].y = p.y - sy, pr[1].x = p.x + sx, pr[1].y = p.y + sy)
+#define FUZZ 3
#define EPSILON .0001
static char *defaultlinestyle[3] = { "solid\0", "setlinewidth\0001\0", 0 };
-int emitState;
+
+/* push empty graphic state for current object */
+static obj_state_t* push_obj_state(GVJ_t *job)
+{
+ obj_state_t *obj;
+
+ if (! (obj = zmalloc(sizeof(obj_state_t))))
+ agerr(AGERR, "no memory from zmalloc()\n");
+
+ obj->parent = job->obj;
+ job->obj = obj;
+
+ return obj;
+}
+
+/* pop graphic state of current object */
+static void pop_obj_state(GVJ_t *job)
+{
+ obj_state_t *obj = job->obj;
+
+ assert(obj);
+
+ if (obj->url) free(obj->url);
+ if (obj->tailurl) free(obj->tailurl);
+ if (obj->headurl) free(obj->headurl);
+ if (obj->tooltip) free(obj->tooltip);
+ if (obj->tailtooltip) free(obj->tailtooltip);
+ if (obj->headtooltip) free(obj->headtooltip);
+ if (obj->target) free(obj->target);
+ if (obj->tailtarget) free(obj->tailtarget);
+ if (obj->headtarget) free(obj->headtarget);
+ if (obj->url_map_p) free(obj->url_map_p);
+ if (obj->url_bsplinemap_p) free(obj->url_bsplinemap_p);
+ if (obj->url_bsplinemap_n) free(obj->url_bsplinemap_n);
+ if (obj->tailurl_map_p) free(obj->tailurl_map_p);
+ if (obj->headurl_map_p) free(obj->headurl_map_p);
+
+ job->obj = obj->parent;
+ free(obj);
+}
+
+static void doHTMLdata(htmldata_t * dp, point p, void *obj)
+{
+ char *url = NULL, *target = NULL, *title = NULL;
+ pointf p1, p2;
+ int havetitle = 0;
+
+ if ((url = dp->href) && url[0]) {
+ switch (agobjkind(obj)) {
+ case AGGRAPH:
+ url = strdup_and_subst_graph(url, (graph_t *) obj);
+ break;
+ case AGNODE:
+ url = strdup_and_subst_node(url, (node_t *) obj);
+ break;
+ case AGEDGE:
+ url = strdup_and_subst_edge(url, (edge_t *) obj);
+ break;
+ }
+ }
+ target = dp->target;
+ if ((title = dp->title) && title[0]) {
+ havetitle++;
+ switch (agobjkind(obj)) {
+ case AGGRAPH:
+ title = strdup_and_subst_graph(title, (graph_t *) obj);
+ break;
+ case AGNODE:
+ title = strdup_and_subst_node(title, (node_t *) obj);
+ break;
+ case AGEDGE:
+ title = strdup_and_subst_edge(title, (edge_t *) obj);
+ break;
+ }
+ }
+ if (url || title) {
+ p1.x = p.x + dp->box.LL.x;
+ p1.y = p.y + dp->box.LL.y;
+ p2.x = p.x + dp->box.UR.x;
+ p2.y = p.y + dp->box.UR.y;
+// FIXME
+// map_output_rect(p1, p2, url, target, "", title);
+ }
+ free(url);
+ free(title);
+}
+
+/* forward declaration */
+static void doHTMLcell(htmlcell_t * cp, point p, void *obj);
+
+static void doHTMLtbl(htmltbl_t * tbl, point p, void *obj)
+{
+ htmlcell_t **cells = tbl->u.n.cells;
+ htmlcell_t *cp;
+
+ while ((cp = *cells++))
+ doHTMLcell(cp, p, obj);
+ if (tbl->data.href)
+ doHTMLdata(&tbl->data, p, obj);
+}
+
+static void doHTMLcell(htmlcell_t * cp, point p, void *obj)
+{
+ if (cp->child.kind == HTML_TBL)
+ doHTMLtbl(cp->child.u.tbl, p, obj);
+ if (cp->data.href)
+ doHTMLdata(&cp->data, p, obj);
+}
+
+static void doHTMLlabel(htmllabel_t * lbl, point p, void *obj)
+{
+ if (lbl->kind == HTML_TBL) {
+ doHTMLtbl(lbl->u.tbl, p, obj);
+ }
+}
+
+/* isRect:
+ * isRect function returns true when polygon has
+ * regular rectangular shape. Rectangle is regular when
+ * it is not skewed and distorted and orientation is almost zero
+ */
+static bool isRect(polygon_t * p)
+{
+ return (p->sides == 4 && (ROUND(p->orientation) % 90) == 0
+ && p->distortion == 0.0 && p->skew == 0.0);
+}
+
+/*
+ * isFilled function returns 1 if filled style has been set for node 'n'
+ * otherwise returns 0. it accepts pointer to node_t as an argument
+ */
+static int ifFilled(node_t * n)
+{
+ char *style, *p, **pp;
+ int r = 0;
+ style = late_nnstring(n, N_style, "");
+ if (style[0]) {
+ pp = parse_style(style);
+ while ((p = *pp)) {
+ if (strcmp(p, "filled") == 0)
+ r = 1;
+ pp++;
+ }
+ }
+ return r;
+}
+
+/* pEllipse:
+ * pEllipse function returns 'np' points from the circumference
+ * of ellipse described by radii 'a' and 'b'.
+ * Assumes 'np' is greater than zero.
+ * 'np' should be at least 4 to sample polygon from ellipse
+ */
+static pointf *pEllipse(double a, double b, int np)
+{
+ double theta = 0.0;
+ double deltheta = 2 * M_PI / np;
+ int i;
+ pointf *ps;
+
+ ps = N_NEW(np, pointf);
+ for (i = 0; i < np; i++) {
+ ps[i].x = a * cos(theta);
+ ps[i].y = b * sin(theta);
+ theta += deltheta;
+ }
+ return ps;
+}
+
+#define HW 2.0 /* maximum distance away from line, in points */
+
+/* check_control_points:
+ * check_control_points function checks the size of quadrilateral
+ * formed by four control points
+ * returns 1 if four points are in line (or close to line)
+ * else return 0
+ */
+static int check_control_points(pointf *cp)
+{
+ double dis1 = ptToLine2 (cp[0], cp[3], cp[1]);
+ double dis2 = ptToLine2 (cp[0], cp[3], cp[2]);
+ if (dis1 < HW*HW && dis2 < HW*HW)
+ return 1;
+ else
+ return 0;
+}
+
+#ifdef DEBUG
+static void psmapOutput (point* ps, int n)
+{
+ int i;
+ fprintf (stdout, "newpath %d %d moveto\n", ps[0].x, ps[0].y);
+ for (i=1; i < n; i++)
+ fprintf (stdout, "%d %d lineto\n", ps[i].x, ps[i].y);
+ fprintf (stdout, "closepath stroke\n");
+}
+#endif
+
+typedef struct segitem_s {
+ pointf p;
+ struct segitem_s* next;
+} segitem_t;
+
+#define MARK_FIRST_SEG(L) ((L)->next = (segitem_t*)1)
+#define FIRST_SEG(L) ((L)->next == (segitem_t*)1)
+#define INIT_SEG(P,L) {(L)->next = 0; (L)->p = P;}
+
+static segitem_t* appendSeg (pointf p, segitem_t* lp)
+{
+ segitem_t* s = GNEW(segitem_t);
+ INIT_SEG (p, s);
+ lp->next = s;
+ return s;
+}
+
+/* map_bspline_poly:
+ * Output the polygon determined by the n points in p1, followed
+ * by the n points in p2 in reverse order. Assumes n <= 50.
+ */
+static void map_bspline_poly(pointf **pbs_p, int **pbs_n, int *pbs_poly_n, int n, pointf* p1, pointf* p2)
+{
+ int i = 0, nump = 0, last = 2*n-1;
+
+ for ( ; i < *pbs_poly_n; i++)
+ nump += (*pbs_n)[i];
+
+ (*pbs_poly_n)++;
+ *pbs_n = grealloc(*pbs_n, (*pbs_poly_n) * sizeof(int));
+ (*pbs_n)[i] = 2*n;
+ *pbs_p = grealloc(*pbs_p, (nump + 2*n) * sizeof(pointf));
+
+ for (i = 0; i < n; i++) {
+ (*pbs_p)[nump+i] = p1[i];
+ (*pbs_p)[nump+last-i] = p2[i];
+ }
+#ifdef DEBUG
+ psmapOutput (*pbs_p + nump, last+1);
+#endif
+}
+
+/* approx_bezier:
+ * Approximate Bezier by line segments. If the four points are
+ * almost colinear, as determined by check_control_points, we store
+ * the segment cp[0]-cp[3]. Otherwise we split the Bezier into 2 and recurse.
+ * Since 2 contiguous segments share an endpoint, we actually store
+ * the segments as a list of points.
+ * New points are appended to the list given by lp. The tail of the
+ * list is returned.
+ */
+static segitem_t* approx_bezier (pointf *cp, segitem_t* lp)
+{
+ pointf sub_curves[8];
+
+ if (check_control_points(cp)) {
+ if (FIRST_SEG (lp)) INIT_SEG (cp[0], lp);
+ lp = appendSeg (cp[3], lp);
+ }
+ else {
+ Bezier (cp, 3, 0.5, sub_curves, sub_curves+4);
+ lp = approx_bezier (sub_curves, lp);
+ lp = approx_bezier (sub_curves+4, lp);
+ }
+ return lp;
+}
+
+/* bisect:
+ * Return the angle of the bisector between the two rays
+ * pp-cp and cp-np. The bisector returned is always to the
+ * left of pp-cp-np.
+ */
+static double bisect (pointf pp, pointf cp, pointf np)
+{
+ double ang, theta, phi;
+ theta = atan2(np.y - cp.y,np.x - cp.x);
+ phi = atan2(pp.y - cp.y,pp.x - cp.x);
+ ang = theta - phi;
+ if (ang > 0) ang -= 2*M_PI;
+
+ return (phi + ang/2.0);
+}
+
+/* mkSegPts:
+ * Determine polygon points related to 2 segments prv-cur and cur-nxt.
+ * The points lie on the bisector of the 2 segments, passing through cur,
+ * and distance HW from cur. The points are stored in p1 and p2.
+ * If p1 is NULL, we use the normal to cur-nxt.
+ * If p2 is NULL, we use the normal to prv-cur.
+ * Assume at least one of prv or nxt is non-NULL.
+ */
+static void mkSegPts (segitem_t* prv, segitem_t* cur, segitem_t* nxt,
+ pointf* p1, pointf* p2)
+{
+ pointf cp, pp, np;
+ double theta, delx, dely;
+ pointf p;
+
+ cp = cur->p;
+ /* if prv or nxt are NULL, use the one given to create a collinear
+ * prv or nxt. This could be more efficiently done with special case code,
+ * but this way is more uniform.
+ */
+ if (prv) {
+ pp = prv->p;
+ if (nxt)
+ np = nxt->p;
+ else {
+ np.x = 2*cp.x - pp.x;
+ np.y = 2*cp.y - pp.y;
+ }
+ }
+ else {
+ np = nxt->p;
+ pp.x = 2*cp.x - np.x;
+ pp.y = 2*cp.y - np.y;
+ }
+ theta = bisect(pp,cp,np);
+ delx = HW*cos(theta);
+ dely = HW*sin(theta);
+ p.x = cp.x + delx;
+ p.y = cp.y + dely;
+ *p1 = p;
+ p.x = cp.x - delx;
+ p.y = cp.y - dely;
+ *p2 = p;
+}
+
+/* map_output_bspline:
+ * Construct and output a closed polygon approximating the input
+ * B-spline bp. We do this by first approximating bp by a sequence
+ * of line segments. We then use the sequence of segments to determine
+ * the polygon.
+ * In cmapx, polygons are limited to 100 points, so we output polygons
+ * in chunks of 100.
+ */
+static void map_output_bspline (pointf **pbs, int **pbs_n, int *pbs_poly_n, bezier* bp)
+{
+ segitem_t* segl = GNEW(segitem_t);
+ segitem_t* segp = segl;
+ segitem_t* segprev;
+ segitem_t* segnext;
+ int nc, j, k, cnt;
+ pointf pts[4];
+ pointf pt1[50], pt2[50];
+
+ MARK_FIRST_SEG(segl);
+ nc = (bp->size - 1)/3; /* nc is number of bezier curves */
+ for (j = 0; j < nc; j++) {
+ for (k = 0; k < 4; k++) {
+ pts[k].x = (double)bp->list[3*j + k].x;
+ pts[k].y = (double)bp->list[3*j + k].y;
+ }
+ segp = approx_bezier (pts, segp);
+ }
+
+ segp = segl;
+ segprev = 0;
+ cnt = 0;
+ while (segp) {
+ segnext = segp->next;
+ mkSegPts (segprev, segp, segnext, pt1+cnt, pt2+cnt);
+ cnt++;
+ if ((segnext == NULL) || (cnt == 50)) {
+ map_bspline_poly (pbs, pbs_n, pbs_poly_n, cnt, pt1, pt2);
+ pt1[0] = pt1[cnt-1];
+ pt2[0] = pt2[cnt-1];
+ cnt = 1;
+ }
+ segprev = segp;
+ segp = segnext;
+ }
+
+ /* free segl */
+ while (segl) {
+ segp = segl->next;
+ free (segl);
+ segl = segp;
+ }
+}
+
/* parse_layers:
* Split input string into tokens, with separators specified by
}
#endif
+static void emit_begin_node(GVJ_t * job, node_t * n)
+{
+ obj_state_t *obj;
+ int flags = job->flags;
+ textlabel_t *lab;
+ int sides, peripheries, i, j, filled = 0, rect = 0, shape, nump = 0;
+ polygon_t *poly = NULL;
+ pointf *vertices, ldimen, *p = NULL;
+ point coord;
+ char *s;
+
+ obj = push_obj_state(job);
+ obj->type = NODE_OBJTYPE;
+ obj->u.n = n;
+
+ obj->oldstate = job->gvc->emit_state;
+ job->gvc->emit_state = EMIT_NDRAW;
+
+ if (flags & GVRENDER_DOES_Z) {
+ obj->z = late_double(n, N_z, 0.0, -MAXFLOAT);
+ }
+ if ((flags & GVRENDER_DOES_LABELS) && ((lab = ND_label(n)))) {
+ if (lab->html)
+ doHTMLlabel(lab->u.html, lab->p, (void *) n);
+ obj->label = lab->text;
+ }
+ if ((flags & GVRENDER_DOES_MAPS)
+ && (((s = agget(n, "href")) && s[0]) || ((s = agget(n, "URL")) && s[0]))) {
+ obj->url = strdup_and_subst_node(s, n);
+ }
+ if (flags & GVRENDER_DOES_TOOLTIPS) {
+ if ((s = agget(n, "tooltip")) && s[0]) {
+ obj->tooltip = strdup_and_subst_node(s, n);
+ obj->explicit_tooltip = true;
+ }
+ else {
+ obj->tooltip = strdup(ND_label(n)->text);
+ }
+ }
+ if ((flags & GVRENDER_DOES_TARGETS) && ((s = agget(n, "target")) && s[0])) {
+ obj->target = strdup_and_subst_node(s, n);
+ }
+ if ((flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS))
+ && (obj->url || obj->explicit_tooltip)) {
+
+ /* checking shape of node */
+ shape = shapeOf(n);
+ /* node coordinate */
+ coord = ND_coord_i(n);
+ /* checking if filled style has been set for node */
+ filled = ifFilled(n);
+
+ if (shape == SH_POLY || shape == SH_POINT) {
+ poly = (polygon_t *) ND_shape_info(n);
+
+ /* checking if polygon is regular rectangle */
+ if (isRect(poly) && (poly->peripheries || filled))
+ rect = 1;
+ }
+
+ /* When node has polygon shape and requested output supports polygons
+ * we use a polygon to map the clickable region that is a:
+ * circle, ellipse, polygon with n side, or point.
+ * For regular rectangular shape we have use node's bounding box to map clickable region
+ */
+ if (poly && !rect && (flags & GVRENDER_DOES_MAP_POLYGON)) {
+
+ if (poly->sides < 3)
+ sides = 1;
+ else
+ sides = poly->sides;
+
+ if (poly->peripheries < 2)
+ peripheries = 1;
+ else
+ peripheries = poly->peripheries;
+
+ vertices = poly->vertices;
+
+ if ((s = agget(n, "samplepoints")))
+ nump = atoi(s);
+ /* We want at least 4 points. For server-side maps, at most 100
+ * points are allowed. To simplify things to fit with the 120 points
+ * used for skewed ellipses, we set the bound at 60.
+ */
+ if ((nump < 4) || (nump > 60))
+ nump = DFLT_SAMPLE;
+ /* use bounding box of text label for mapping
+ * when polygon has no peripheries and node is not filled
+ */
+ if (poly->peripheries == 0 && !filled) {
+ obj->url_map_shape = MAP_RECTANGLE;
+ nump = 2;
+ p = N_NEW(nump, pointf);
+ ldimen = ND_label(n)->dimen;
+ P2RECT(coord, p, ldimen.x / 2.0, ldimen.y / 2.0);
+ }
+ /* circle or ellipse */
+ else if (poly->sides < 3 && poly->skew == 0.0 && poly->distortion == 0.0) {
+ if (poly->regular) {
+ obj->url_map_shape = MAP_CIRCLE;
+ nump = 2; /* center of circle and top right corner of bb */
+ p = N_NEW(nump, pointf);
+ p[0].x = coord.x;
+ p[0].y = coord.y;
+ p[1].x = coord.x + vertices[peripheries - 1].x;
+ p[1].y = coord.y + vertices[peripheries - 1].y;
+ }
+ else { /* ellipse is treated as polygon */
+ obj->url_map_shape= MAP_POLYGON;
+ p = pEllipse((double)(vertices[peripheries - 1].x),
+ (double)(vertices[peripheries - 1].y), nump);
+ for (i = 0; i < nump; i++) {
+ p[i].x += coord.x;
+ p[i].y += coord.y;
+ }
+ }
+ }
+ /* all other polygonal shape */
+ else {
+ int offset = (peripheries - 1)*(poly->sides);
+ obj->url_map_shape = MAP_POLYGON;
+ /* distorted or skewed ellipses and circles are polygons with 120
+ * sides. For mapping we convert them into polygon with sample sides
+ */
+ if (poly->sides >= nump) {
+ int delta = poly->sides / nump;
+ p = N_NEW(nump, pointf);
+ for (i = 0, j = 0; j < nump; i += delta, j++) {
+ p[j].x = coord.x + vertices[i + offset].x;
+ p[j].y = coord.y + vertices[i + offset].y;
+ }
+ } else {
+ nump = sides;
+ p = N_NEW(nump, pointf);
+ for (i = 0; i < nump; i++) {
+ p[i].x = coord.x + vertices[i + offset].x;
+ p[i].y = coord.y + vertices[i + offset].y;
+ }
+ }
+ }
+ }
+ else {
+ /* we have to use the node's bounding box to map clickable region
+ * when requested output format is not capable of polygons.
+ */
+ obj->url_map_shape = MAP_RECTANGLE;
+ nump = 2;
+ p = N_NEW(nump, pointf);
+ p[0].x = coord.x - ND_lw_i(n);
+ p[0].y = coord.y - (ND_ht_i(n) / 2);
+ p[1].x = coord.x + ND_rw_i(n);
+ p[1].y = coord.y + (ND_ht_i(n) / 2);
+ }
+ if (! (flags & GVRENDER_DOES_TRANSFORM))
+ gvrender_ptf_A(job, p, p, nump);
+ obj->url_map_p = p;
+ obj->url_map_n = nump;
+ }
+
+#ifdef WITH_CODEGENS
+ Obj = NODE;
+#endif
+ gvrender_begin_node(job, n);
+ setColorScheme (agget (n, "colorscheme"));
+ gvrender_begin_context(job);
+}
+
+static void emit_end_node(GVJ_t * job)
+{
+ gvrender_end_context(job);
+ gvrender_end_node(job);
+#ifdef WITH_CODEGENS
+ Obj = NONE;
+#endif
+ job->gvc->emit_state = job->obj->oldstate;
+ pop_obj_state(job);
+}
+
static void emit_node(GVJ_t * job, node_t * n)
{
GVC_t *gvc = job->gvc;
char *s;
- int oldstate;
if (ND_shape(n) == NULL)
return;
- oldstate = gvc->emit_state;
- gvc->emit_state = EMIT_NDRAW;
if (node_in_layer(job, n->graph, n)
&& node_in_box(n, job->pageBoxClip)
&& (ND_state(n) != gvc->common.viewNum)) {
gvrender_comment(job, n->name);
-
s = late_string(n, N_comment, "");
if (s[0])
gvrender_comment(job, s);
- gvrender_begin_node(job, n);
- setColorScheme (agget (n, "colorscheme"));
- gvrender_begin_context(job);
+ emit_begin_node(job, n);
ND_shape(n)->fns->codefn(job, n);
ND_state(n) = gvc->common.viewNum;
- gvrender_end_context(job);
- gvrender_end_node(job);
+ emit_end_node(job);
}
- gvc->emit_state = oldstate;
}
/* calculate an offset vector, length d, perpendicular to line p,q */
bool saved = FALSE;
double scale, numc2;
char *p;
- int oldstate;
#define SEP 2.0
- oldstate = job->gvc->emit_state;
- job->gvc->emit_state = EMIT_EDRAW;
style = late_string(e, E_style, "");
/* We shortcircuit drawing an invisible edge because the arrowhead
* code resets the style to solid, and most of the code generators
if (saved)
gvrender_end_context(job);
- job->gvc->emit_state = oldstate;
}
static bool edge_in_box(edge_t *e, boxf b)
return FALSE;
}
+static void emit_begin_edge(GVJ_t * job, edge_t * e)
+{
+ obj_state_t *obj;
+ int flags = job->flags;
+ char *s;
+ textlabel_t *lab = NULL, *tlab = NULL, *hlab = NULL;
+ pointf *p = NULL, *pt = NULL, *ph = NULL, *pte = NULL, *phe = NULL, *pbs = NULL;
+ int i, nump, *pbs_n = NULL, pbs_poly_n = 0;
+ bezier bz;
+
+ obj = push_obj_state(job);
+ obj->type = EDGE_OBJTYPE;
+ obj->u.e = e;
+
+ obj->oldstate = job->gvc->emit_state;
+ job->gvc->emit_state = EMIT_EDRAW;
+
+ if (flags & GVRENDER_DOES_Z) {
+ obj->tail_z= late_double(e->tail, N_z, 0.0, -1000.0);
+ obj->head_z= late_double(e->head, N_z, 0.0, -MAXFLOAT);
+ }
+
+ if (flags & GVRENDER_DOES_LABELS) {
+ if ((lab = ED_label(e))) {
+ if (lab->html)
+ doHTMLlabel(lab->u.html, lab->p, (void *) e);
+ obj->label = lab->text;
+ }
+ obj->taillabel = obj->headlabel = obj->label;
+ if ((tlab = ED_tail_label(e))) {
+ if (tlab->html)
+ doHTMLlabel(tlab->u.html, tlab->p, (void *) e);
+ obj->taillabel = tlab->text;
+ }
+ if ((hlab = ED_head_label(e))) {
+ if (hlab->html)
+ doHTMLlabel(hlab->u.html, hlab->p, (void *) e);
+ obj->headlabel = hlab->text;
+ }
+ }
+
+ if (flags & GVRENDER_DOES_MAPS) {
+ if (((s = agget(e, "href")) && s[0]) || ((s = agget(e, "URL")) && s[0]))
+ obj->url = strdup_and_subst_edge(s, e);
+ if (((s = agget(e, "tailhref")) && s[0]) || ((s = agget(e, "tailURL")) && s[0]))
+ obj->tailurl = strdup_and_subst_edge(s, e);
+ else if (obj->url)
+ obj->tailurl = strdup(obj->url);
+ if (((s = agget(e, "headhref")) && s[0]) || ((s = agget(e, "headURL")) && s[0]))
+ obj->headurl = strdup_and_subst_edge(s, e);
+ else if (obj->url)
+ obj->headurl = strdup(obj->url);
+ }
+
+ if (flags & GVRENDER_DOES_TARGETS) {
+ if ((s = agget(e, "target")) && s[0])
+ obj->target = strdup_and_subst_edge(s, e);
+ if ((s = agget(e, "tailtarget")) && s[0])
+ obj->tailtarget = strdup_and_subst_edge(s, e);
+ else if (obj->target)
+ obj->tailtarget = strdup(obj->target);
+ if ((s = agget(e, "headtarget")) && s[0])
+ obj->headtarget = strdup_and_subst_edge(s, e);
+ else if (obj->target)
+ obj->headtarget = strdup(obj->target);
+ }
+
+ if (flags & GVRENDER_DOES_TOOLTIPS) {
+ if ((s = agget(e, "tooltip")) && s[0]) {
+ obj->tooltip = strdup_and_subst_edge(s, e);
+ obj->explicit_tooltip = true;
+ }
+ else if (obj->label)
+ obj->tooltip = strdup(obj->label);
+ if ((s = agget(e, "tailtooltip")) && s[0]) {
+ obj->tailtooltip = strdup_and_subst_edge(s, e);
+ obj->explicit_tailtooltip = true;
+ }
+ else if (obj->taillabel)
+ obj->tailtooltip = strdup(obj->taillabel);
+ if ((s = agget(e, "headtooltip")) && s[0]) {
+ obj->headtooltip = strdup_and_subst_edge(s, e);
+ obj->explicit_headtooltip = true;
+ }
+ else if (obj->headlabel)
+ obj->headtooltip = strdup(obj->headlabel);
+ }
+
+ if (flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) {
+ if (flags & (GVRENDER_DOES_MAP_RECTANGLE | GVRENDER_DOES_MAP_POLYGON)) {
+ if (flags & GVRENDER_DOES_MAP_RECTANGLE) {
+ obj->url_map_shape = MAP_RECTANGLE;
+ nump = 2;
+ }
+ else { /* GVRENDER_DOES_MAP_POLYGON */
+ obj->url_map_shape = MAP_POLYGON;
+ nump = 4;
+ }
+
+ if (lab && (obj->url || obj->tooltip)) {
+ obj->url_map_n = nump;
+ p = N_NEW(nump, pointf);
+ P2RECT(lab->p, p, lab->dimen.x / 2., lab->dimen.y / 2.);
+ }
+
+ if (tlab && (obj->tailurl || obj->tailtooltip)) {
+ obj->tailurl_map_n = nump;
+ pt = N_NEW(nump, pointf);
+ P2RECT(tlab->p, pt, tlab->dimen.x / 2., tlab->dimen.y / 2.);
+ }
+
+ if (hlab && (obj->headurl || obj->headtooltip)) {
+ obj->headurl_map_n = nump;
+ ph = N_NEW(nump, pointf);
+ P2RECT(hlab->p, ph, hlab->dimen.x / 2., hlab->dimen.y / 2.);
+ }
+
+ /* process intersecion with tail node */
+ if (ED_spl(e) && (obj->tailurl || obj->tailtooltip)) {
+ obj->tailendurl_map_n = nump;
+ pte = N_NEW(nump, pointf);
+ bz = ED_spl(e)->list[0];
+ if (bz.sflag) {
+ /* Arrow at start of splines */
+ P2RECT(bz.sp, pte, FUZZ, FUZZ);
+ } else {
+ /* No arrow at start of splines */
+ P2RECT(bz.list[0], pte, FUZZ, FUZZ);
+ }
+ }
+
+ /* process intersection with head node */
+ if (ED_spl(e) && (obj->headurl || obj->headtooltip)) {
+ obj->headendurl_map_n = nump;
+ phe = N_NEW(nump, pointf);
+ bz = ED_spl(e)->list[ED_spl(e)->size - 1];
+ if (bz.eflag) {
+ /* Arrow at end of splines */
+ P2RECT(bz.ep, phe, FUZZ, FUZZ);
+ } else {
+ /* No arrow at end of splines */
+ P2RECT(bz.list[bz.size - 1], phe, FUZZ, FUZZ);
+ }
+ }
+
+ if (ED_spl(e) && (obj->url || obj->tooltip) && (flags & GVRENDER_DOES_MAP_POLYGON)) {
+ int ns;
+ splines *spl;
+
+ spl = ED_spl(e);
+ ns = spl->size; /* number of splines */
+ for (i = 0; i < ns; i++)
+ map_output_bspline (&pbs, &pbs_n, &pbs_poly_n, spl->list+i);
+ obj->url_bsplinemap_poly_n = pbs_poly_n;
+ obj->url_bsplinemap_n = pbs_n;
+ }
+
+ if (! (flags & GVRENDER_DOES_TRANSFORM)) {
+ if (p) gvrender_ptf_A(job, p, p, 2);
+ if (pt) gvrender_ptf_A(job, pt, pt, 2);
+ if (ph) gvrender_ptf_A(job, ph, ph, 2);
+ if (pte) gvrender_ptf_A(job, pte, pte, 2);
+ if (phe) gvrender_ptf_A(job, phe, phe, 2);
+ if (pbs) {
+ for ( nump = 0, i = 0; i < pbs_poly_n; i++)
+ nump += pbs_n[i];
+ gvrender_ptf_A(job, pbs, pbs, nump);
+ }
+ }
+ if (! (flags & GVRENDER_DOES_MAP_RECTANGLE)) {
+ if (p) rect2poly(p);
+ if (pt) rect2poly(pt);
+ if (ph) rect2poly(ph);
+ if (pte) rect2poly(pte);
+ if (phe) rect2poly(phe);
+ }
+
+ }
+ obj->url_map_p = p;
+ obj->tailurl_map_p = pt;
+ obj->headurl_map_p = ph;
+ obj->tailendurl_map_p = pte;
+ obj->headendurl_map_p = phe;
+ obj->url_bsplinemap_p = pbs;
+ }
+
+#ifdef WITH_CODEGENS
+ Obj = EDGE;
+#endif
+ gvrender_begin_edge(job, e);
+}
+
+static void emit_end_edge(GVJ_t * job)
+{
+ gvrender_end_edge(job);
+#ifdef WITH_CODEGENS
+ Obj = NONE;
+#endif
+ job->gvc->emit_state = job->obj->oldstate;
+ pop_obj_state(job);
+}
+
static void emit_edge(GVJ_t * job, edge_t * e)
{
char *s;
- int oldstate;
if (! edge_in_box(e, job->pageBoxClip) || ! edge_in_layer(job, e->head->graph, e))
return;
- oldstate = job->gvc->emit_state;
- job->gvc->emit_state = EMIT_EDRAW;
s = malloc(strlen(e->tail->name) + 2 + strlen(e->head->name) + 1);
strcpy(s,e->tail->name);
if (AG_IS_DIRECTED(e->tail->graph))
if (s[0])
gvrender_comment(job, s);
- gvrender_begin_edge(job, e);
+ emit_begin_edge(job, e);
emit_edge_graphics (job, e);
- gvrender_end_edge(job);
- job->gvc->emit_state = oldstate;
+ emit_end_edge(job);
}
static void init_gvc(GVC_t * gvc, graph_t * g)
gvrender_end_page(job);
}
+static void emit_begin_graph(GVJ_t * job, graph_t * g)
+{
+ GVC_t *gvc = job->gvc;
+ int flags = job->flags;
+ obj_state_t *obj;
+ textlabel_t *lab;
+ char *s;
+
+ obj = push_obj_state(job);
+ obj->type = ROOTGRAPH_OBJTYPE;
+ obj->u.g = g;
+
+ obj->oldstate = job->gvc->emit_state;
+ job->gvc->emit_state = EMIT_GDRAW;
+
+ if ((flags & GVRENDER_DOES_LABELS) && ((lab = GD_label(g)))) {
+ if (lab->html)
+ doHTMLlabel(lab->u.html, lab->p, (void *) g);
+ obj->label = lab->text;
+ }
+ if ((flags & GVRENDER_DOES_MAPS)
+ && (((s = agget(g, "href")) && s[0])
+ || ((s = agget(g, "URL")) && s[0]))) {
+ obj->url = strdup_and_subst_graph(s, g);
+ }
+ if (flags & GVRENDER_DOES_TOOLTIPS) {
+ if ((s = agget(g, "tooltip")) && s[0]) {
+ obj->tooltip = strdup_and_subst_graph(s, g);
+ obj->explicit_tooltip = true;
+ }
+ else if (obj->url && obj->label) {
+ obj->tooltip = strdup(obj->label);
+ }
+ }
+ if ((flags & GVRENDER_DOES_TARGETS) && ((s = agget(g, "target")) && s[0])) {
+ obj->target = strdup_and_subst_graph(s, g);
+ }
+
+ /* init stack */
+ gvc->SP = 0;
+ job->style = &(gvc->styles[0]);
+ job->style->pen = PEN_SOLID;
+ job->style->fill = FILL_NONE;
+ job->style->penwidth = PENWIDTH_NORMAL;
+
+#ifdef WITH_CODEGENS
+ Obj = NONE;
+#endif
+ gvrender_begin_graph(job, g);
+}
+
+static void emit_end_graph(GVJ_t * job, graph_t * g)
+{
+ gvrender_end_graph(job);
+#ifdef WITH_CODEGENS
+ Obj = NONE;
+#endif
+ job->gvc->emit_state = job->obj->oldstate;
+ pop_obj_state(job);
+}
+
void emit_graph(GVJ_t * job, graph_t * g)
{
node_t *n;
s = late_string(g, agfindattr(g, "comment"), "");
gvrender_comment(job, s);
- gvrender_begin_graph(job, g);
+ emit_begin_graph(job, g);
+
if (flags & EMIT_COLORS)
emit_colors(job,g);
if (job->numLayers > 1)
gvrender_end_layer(job);
}
- gvrender_end_graph(job);
+ emit_end_graph(job, g);
}
/* support for stderr_once */
return pstyle;
}
+static void emit_begin_cluster(GVJ_t * job, Agraph_t * sg)
+{
+ obj_state_t *obj;
+ int flags = job->flags;
+ textlabel_t *lab;
+ char *s;
+ int nump = 0;
+ pointf *p = NULL;
+
+ obj = push_obj_state(job);
+ obj->type = CLUSTER_OBJTYPE;
+ obj->u.sg = sg;
+
+ obj->oldstate = job->gvc->emit_state;
+ job->gvc->emit_state = EMIT_CDRAW;
+
+ if ((flags & GVRENDER_DOES_LABELS) && ((lab = GD_label(sg)))) {
+ if (lab->html)
+ doHTMLlabel(lab->u.html, lab->p, (void *) sg);
+ obj->label = lab->text;
+ }
+ if ((flags & GVRENDER_DOES_MAPS)
+ && (((s = agget(sg, "href")) && s[0]) || ((s = agget(sg, "URL")) && s[0])))
+ obj->url = strdup_and_subst_graph(s, sg);
+
+ if ((flags & GVRENDER_DOES_TARGETS) && ((s = agget(sg, "target")) && s[0]))
+ obj->target = strdup_and_subst_graph(s, sg);
+
+ if (flags & GVRENDER_DOES_TOOLTIPS) {
+ if ((s = agget(sg, "tooltip")) && s[0]) {
+ obj->tooltip = strdup_and_subst_graph(s, sg);
+ obj->explicit_tooltip = true;
+ }
+ else if (obj->label) {
+ obj->tooltip = strdup(obj->label);
+ }
+ }
+
+ if (flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) {
+ if (flags & (GVRENDER_DOES_MAP_RECTANGLE | GVRENDER_DOES_MAP_POLYGON)) {
+ if (flags & GVRENDER_DOES_MAP_RECTANGLE) {
+ obj->url_map_shape = MAP_RECTANGLE;
+ nump = 2;
+ }
+ else {
+ obj->url_map_shape = MAP_POLYGON;
+ nump = 4;
+ }
+
+ p = N_NEW(nump, pointf);
+ P2PF(GD_bb(sg).LL, p[0]);
+ P2PF(GD_bb(sg).UR, p[1]);
+
+ if (! (flags & (GVRENDER_DOES_MAP_RECTANGLE)))
+ rect2poly(p);
+ }
+ obj->url_map_p = p;
+ obj->url_map_n = nump;
+ }
+
+#ifdef WITH_CODEGENS
+ Obj = CLST;
+#endif
+ gvrender_begin_cluster(job, sg);
+}
+
+static void emit_end_cluster(GVJ_t * job, Agraph_t * g)
+{
+ gvrender_end_cluster(job, g);
+#ifdef WITH_CODEGENS
+ Obj = NONE;
+#endif
+ job->gvc->emit_state = job->obj->oldstate;
+ pop_obj_state(job);
+}
+
void emit_clusters(GVJ_t * job, Agraph_t * g, int flags)
{
int c, istyle, filled;
char *color, *fillcolor, *pencolor, **style;
node_t *n;
edge_t *e;
- int oldstate;
- oldstate = job->gvc->emit_state;
- job->gvc->emit_state = EMIT_CDRAW;
for (c = 1; c <= GD_n_cluster(g); c++) {
sg = GD_clust(g)[c];
if (clust_in_layer(job, sg) == FALSE)
/* when mapping, detect events on clusters after sub_clusters */
if (flags & EMIT_CLUSTERS_LAST)
emit_clusters(job, sg, flags);
- gvrender_begin_cluster(job, sg);
+ emit_begin_cluster(job, sg);
setColorScheme (agget (sg, "colorscheme"));
gvrender_begin_context(job);
filled = FALSE;
}
}
gvrender_end_context(job);
- gvrender_end_cluster(job, g);
+ emit_end_cluster(job, g);
/* when drawing, lay down clusters before sub_clusters */
if (!(flags & EMIT_CLUSTERS_LAST))
emit_clusters(job, sg, flags);
}
- job->gvc->emit_state = oldstate;
}
static bool is_style_delim(int c)
init_job_viewport(job, g);
init_job_pagination(job, g);
- job->gvc->emit_state = EMIT_GDRAW;
gvrender_begin_job(job);
switch (job->output_lang) {
return -1;
}
+void rect2poly(pointf *p)
+{
+ p[3].x = p[2].x = p[1].x;
+ p[2].y = p[1].y;
+ p[3].y = p[0].y;
+ p[1].x = p[0].x;
+}
+
static pointf rotatepf(pointf p, int cwrot)
{
static double sina, cosa;
extern point cwrotatep(point p, int cwrot);
extern pointf cwrotatepf(pointf p, int cwrot);
+extern void rect2poly(pointf *p);
+
#ifdef __cplusplus
}
#endif
typedef enum {MAP_RECTANGLE, MAP_CIRCLE, MAP_POLYGON, } map_shape_t;
+ typedef enum {ROOTGRAPH_OBJTYPE, CLUSTER_OBJTYPE, NODE_OBJTYPE, EDGE_OBJTYPE} obj_type;
typedef struct obj_state_s obj_state_t;
struct obj_state_s {
obj_state_t *parent;
- graph_t *g; /* this object - only one of *g, *sg, *n, *e should be non-NULL */
- graph_t *sg;
- node_t *n;
- edge_t *e;
+ obj_type type;
+ union {
+ graph_t *g;
+ graph_t *sg;
+ node_t *n;
+ edge_t *e;
+ } u;
+
+ int oldstate; /* FIXME - used by one of those other state stacks */
double z, tail_z, head_z; /* z depths for 2.5D renderers such as vrml */
/* render */
+ extern pointf gvrender_ptf(GVJ_t *job, pointf p);
+ extern pointf* gvrender_ptf_A(GVJ_t *job, pointf *af, pointf *AF, int n);
+
extern void gvrender_begin_job(GVJ_t * job);
extern void gvrender_end_job(GVJ_t * job);
extern int gvrender_select(GVJ_t * job, char *lang);
#include "const.h"
#include "macros.h"
#include "gvplugin_render.h"
-#include "globals.h"
#include "graph.h"
#include "gvcint.h"
#include "colorprocs.h"
+#include "geom.h"
+#include "geomprocs.h"
#include "gvcproc.h"
-#include "htmltable.h"
-
-#include "render.h"
-
-#define FUZZ 3
-
-#define P2RECT(p, pr, sx, sy) (pr[0].x = p.x - sx, pr[0].y = p.y - sy, pr[1].x = p.x + sx, pr[1].y = p.y + sy)
extern int emit_once(char *str);
return features;
}
-static obj_state_t* push_obj_state(GVJ_t *job)
-{
- obj_state_t *obj;
-
- if (! (obj = zmalloc(sizeof(obj_state_t))))
- agerr(AGERR, "no memory from zmalloc()\n");
-
- obj->parent = job->obj;
- job->obj = obj;
-
- return obj;
-}
-
-static void pop_obj_state(GVJ_t *job)
-{
- obj_state_t *obj = job->obj;
-
- assert(obj);
-
- if (obj->url) free(obj->url);
- if (obj->tailurl) free(obj->tailurl);
- if (obj->headurl) free(obj->headurl);
- if (obj->tooltip) free(obj->tooltip);
- if (obj->tailtooltip) free(obj->tailtooltip);
- if (obj->headtooltip) free(obj->headtooltip);
- if (obj->target) free(obj->target);
- if (obj->tailtarget) free(obj->tailtarget);
- if (obj->headtarget) free(obj->headtarget);
- if (obj->url_map_p) free(obj->url_map_p);
- if (obj->url_bsplinemap_p) free(obj->url_bsplinemap_p);
- if (obj->url_bsplinemap_n) free(obj->url_bsplinemap_n);
- if (obj->tailurl_map_p) free(obj->tailurl_map_p);
- if (obj->headurl_map_p) free(obj->headurl_map_p);
-
- job->obj = obj->parent;
- free(obj);
-}
-
-static void doHTMLdata(htmldata_t * dp, point p, void *obj)
-{
- char *url = NULL, *target = NULL, *title = NULL;
- pointf p1, p2;
- int havetitle = 0;
-
- if ((url = dp->href) && url[0]) {
- switch (agobjkind(obj)) {
- case AGGRAPH:
- url = strdup_and_subst_graph(url, (graph_t *) obj);
- break;
- case AGNODE:
- url = strdup_and_subst_node(url, (node_t *) obj);
- break;
- case AGEDGE:
- url = strdup_and_subst_edge(url, (edge_t *) obj);
- break;
- }
- }
- target = dp->target;
- if ((title = dp->title) && title[0]) {
- havetitle++;
- switch (agobjkind(obj)) {
- case AGGRAPH:
- title = strdup_and_subst_graph(title, (graph_t *) obj);
- break;
- case AGNODE:
- title = strdup_and_subst_node(title, (node_t *) obj);
- break;
- case AGEDGE:
- title = strdup_and_subst_edge(title, (edge_t *) obj);
- break;
- }
- }
- if (url || title) {
- p1.x = p.x + dp->box.LL.x;
- p1.y = p.y + dp->box.LL.y;
- p2.x = p.x + dp->box.UR.x;
- p2.y = p.y + dp->box.UR.y;
-// FIXME
-// map_output_rect(p1, p2, url, target, "", title);
- }
- free(url);
- free(title);
-}
-
-/* forward declaration */
-static void doHTMLcell(htmlcell_t * cp, point p, void *obj);
-
-static void doHTMLtbl(htmltbl_t * tbl, point p, void *obj)
-{
- htmlcell_t **cells = tbl->u.n.cells;
- htmlcell_t *cp;
-
- while ((cp = *cells++))
- doHTMLcell(cp, p, obj);
- if (tbl->data.href)
- doHTMLdata(&tbl->data, p, obj);
-}
-
-static void doHTMLcell(htmlcell_t * cp, point p, void *obj)
-{
- if (cp->child.kind == HTML_TBL)
- doHTMLtbl(cp->child.u.tbl, p, obj);
- if (cp->data.href)
- doHTMLdata(&cp->data, p, obj);
-}
-
-static void doHTMLlabel(htmllabel_t * lbl, point p, void *obj)
-{
- if (lbl->kind == HTML_TBL) {
- doHTMLtbl(lbl->u.tbl, p, obj);
- }
-}
-
-/* isRect:
- * * isRect function returns true when polygon has
- * * regular rectangular shape. Rectangle is regular when
- * * it is not skewed and distorted and orientation is almost zero
- * */
void gvrender_begin_job(GVJ_t * job)
{
GVC_t *gvc = job->gvc;
#define BOLD 1
#define ITALIC 2
-static pointf gvrender_ptf(GVJ_t *job, pointf p)
+pointf gvrender_ptf(GVJ_t *job, pointf p)
{
pointf rv, translation = job->translation, scale = job->compscale;
/* transform an array of n points */
/* *AF and *af must be preallocated */
/* *AF can be the same as *af for inplace transforms */
-static pointf* gvrender_ptf_A(GVJ_t *job, pointf *af, pointf *AF, int n)
+pointf* gvrender_ptf_A(GVJ_t *job, pointf *af, pointf *AF, int n)
{
int i;
pointf translation = job->translation, scale = job->compscale;
return strcmp(*(char **) s1, *(char **) s2);
}
-static void rect2poly(pointf *p)
-{
- p[3].x = p[2].x = p[1].x;
- p[2].y = p[1].y;
- p[3].y = p[0].y;
- p[1].x = p[0].x;
-}
-
static void gvrender_resolve_color(gvrender_features_t * features,
char *name, gvcolor_t * color)
{
void gvrender_begin_graph(GVJ_t * job, graph_t * g)
{
GVC_t *gvc = job->gvc;
- int flags = job->flags;
- obj_state_t *obj;
gvrender_engine_t *gvre = job->render.engine;
- textlabel_t *lab;
char *s;
- obj = push_obj_state(job);
- obj->g = g;
- if ((flags & GVRENDER_DOES_LABELS) && ((lab = GD_label(g)))) {
- if (lab->html)
- doHTMLlabel(lab->u.html, lab->p, (void *) g);
- obj->label = lab->text;
- }
- if ((flags & GVRENDER_DOES_MAPS)
- && (((s = agget(g, "href")) && s[0])
- || ((s = agget(g, "URL")) && s[0]))) {
- obj->url = strdup_and_subst_graph(s, g);
- }
- if (flags & GVRENDER_DOES_TOOLTIPS) {
- if ((s = agget(g, "tooltip")) && s[0]) {
- obj->tooltip = strdup_and_subst_graph(s, g);
- obj->explicit_tooltip = true;
- }
- else if (obj->url && obj->label) {
- obj->tooltip = strdup(obj->label);
- }
- }
- if ((flags & GVRENDER_DOES_TARGETS) && ((s = agget(g, "target")) && s[0])) {
- obj->target = strdup_and_subst_graph(s, g);
- }
-
- /* init stack */
- gvc->SP = 0;
- job->style = &(gvc->styles[0]);
- job->style->pen = PEN_SOLID;
- job->style->fill = FILL_NONE;
- job->style->penwidth = PENWIDTH_NORMAL;
-
if (gvre) {
/* render specific init */
if (gvre->begin_graph)
cg->end_graph();
}
#endif
- pop_obj_state(job);
}
void gvrender_begin_page(GVJ_t * job)
void gvrender_begin_cluster(GVJ_t * job, graph_t * sg)
{
gvrender_engine_t *gvre = job->render.engine;
- obj_state_t *obj;
- textlabel_t *lab;
- char *s;
- int flags, nump = 0;
- pointf *p = NULL;
-
- flags = job->flags;
- obj = push_obj_state(job);
- obj->sg = sg;
- if ((flags & GVRENDER_DOES_LABELS) && ((lab = GD_label(sg)))) {
- if (lab->html)
- doHTMLlabel(lab->u.html, lab->p, (void *) sg);
- obj->label = lab->text;
- }
- if ((flags & GVRENDER_DOES_MAPS)
- && (((s = agget(sg, "href")) && s[0]) || ((s = agget(sg, "URL")) && s[0])))
- obj->url = strdup_and_subst_graph(s, sg);
-
- if ((flags & GVRENDER_DOES_TARGETS) && ((s = agget(sg, "target")) && s[0]))
- obj->target = strdup_and_subst_graph(s, sg);
-
- if (flags & GVRENDER_DOES_TOOLTIPS) {
- if ((s = agget(sg, "tooltip")) && s[0]) {
- obj->tooltip = strdup_and_subst_graph(s, sg);
- obj->explicit_tooltip = true;
- }
- else if (obj->label) {
- obj->tooltip = strdup(obj->label);
- }
- }
-
- if (flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) {
- if (flags & (GVRENDER_DOES_MAP_RECTANGLE | GVRENDER_DOES_MAP_POLYGON)) {
- if (flags & GVRENDER_DOES_MAP_RECTANGLE) {
- obj->url_map_shape = MAP_RECTANGLE;
- nump = 2;
- }
- else {
- obj->url_map_shape = MAP_POLYGON;
- nump = 4;
- }
-
- p = N_NEW(nump, pointf);
- P2PF(GD_bb(sg).LL, p[0]);
- P2PF(GD_bb(sg).UR, p[1]);
-
- if (! (flags & (GVRENDER_DOES_MAP_RECTANGLE)))
- rect2poly(p);
- }
- obj->url_map_p = p;
- obj->url_map_n = nump;
- }
+ obj_state_t *obj = job->obj;
if (gvre) {
if (gvre->begin_anchor && (obj->url || obj->explicit_tooltip))
else {
codegen_t *cg = job->codegen;
- Obj = CLST;
if (cg && cg->begin_anchor && (obj->url || obj->explicit_tooltip))
cg->begin_anchor(obj->url, obj->tooltip, obj->target);
if (cg && cg->begin_cluster)
if (cg && cg->end_anchor && (obj->url || obj->explicit_tooltip))
cg->end_anchor();
}
- Obj = NONE;
#endif
- pop_obj_state(job);
}
void gvrender_begin_nodes(GVJ_t * job)
#endif
}
-static bool isRect(polygon_t * p)
-{
- return (p->sides == 4 && (ROUND(p->orientation) % 90) == 0
- && p->distortion == 0.0 && p->skew == 0.0);
-}
-
-/*
- * isFilled function returns 1 if filled style has been set for node 'n'
- * otherwise returns 0. it accepts pointer to node_t as an argument
- */
-static int ifFilled(node_t * n)
-{
- char *style, *p, **pp;
- int r = 0;
- style = late_nnstring(n, N_style, "");
- if (style[0]) {
- pp = parse_style(style);
- while ((p = *pp)) {
- if (strcmp(p, "filled") == 0)
- r = 1;
- pp++;
- }
- }
- return r;
-}
-
-/* pEllipse:
- * pEllipse function returns 'np' points from the circumference
- * of ellipse described by radii 'a' and 'b'.
- * Assumes 'np' is greater than zero.
- * 'np' should be at least 4 to sample polygon from ellipse
- */
-static pointf *pEllipse(double a, double b, int np)
-{
- double theta = 0.0;
- double deltheta = 2 * M_PI / np;
- int i;
- pointf *ps;
-
- ps = N_NEW(np, pointf);
- for (i = 0; i < np; i++) {
- ps[i].x = a * cos(theta);
- ps[i].y = b * sin(theta);
- theta += deltheta;
- }
- return ps;
-}
-
-
void gvrender_begin_node(GVJ_t * job, node_t * n)
{
gvrender_engine_t *gvre = job->render.engine;
- obj_state_t *obj;
- textlabel_t *lab;
- int flags, sides, peripheries, i, j, filled = 0, rect = 0, shape, nump = 0;
- polygon_t *poly = NULL;
- pointf *vertices, ldimen, *p = NULL;
- point coord;
- char *s;
-
- flags = job->flags;
- obj = push_obj_state(job);
- obj->n = n;
-
- if (flags & GVRENDER_DOES_Z) {
- obj->z = late_double(n, N_z, 0.0, -MAXFLOAT);
- }
- if ((flags & GVRENDER_DOES_LABELS) && ((lab = ND_label(n)))) {
- if (lab->html)
- doHTMLlabel(lab->u.html, lab->p, (void *) n);
- obj->label = lab->text;
- }
- if ((flags & GVRENDER_DOES_MAPS)
- && (((s = agget(n, "href")) && s[0]) || ((s = agget(n, "URL")) && s[0]))) {
- obj->url = strdup_and_subst_node(s, n);
- }
- if (flags & GVRENDER_DOES_TOOLTIPS) {
- if ((s = agget(n, "tooltip")) && s[0]) {
- obj->tooltip = strdup_and_subst_node(s, n);
- obj->explicit_tooltip = true;
- }
- else {
- obj->tooltip = strdup(ND_label(n)->text);
- }
- }
- if ((flags & GVRENDER_DOES_TARGETS) && ((s = agget(n, "target")) && s[0])) {
- obj->target = strdup_and_subst_node(s, n);
- }
- if ((flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS))
- && (obj->url || obj->explicit_tooltip)) {
-
- /* checking shape of node */
- shape = shapeOf(n);
- /* node coordinate */
- coord = ND_coord_i(n);
- /* checking if filled style has been set for node */
- filled = ifFilled(n);
-
- if (shape == SH_POLY || shape == SH_POINT) {
- poly = (polygon_t *) ND_shape_info(n);
-
- /* checking if polygon is regular rectangle */
- if (isRect(poly) && (poly->peripheries || filled))
- rect = 1;
- }
-
- /* When node has polygon shape and requested output supports polygons
- * we use a polygon to map the clickable region that is a:
- * circle, ellipse, polygon with n side, or point.
- * For regular rectangular shape we have use node's bounding box to map clickable region
- */
- if (poly && !rect && (flags & GVRENDER_DOES_MAP_POLYGON)) {
-
- if (poly->sides < 3)
- sides = 1;
- else
- sides = poly->sides;
-
- if (poly->peripheries < 2)
- peripheries = 1;
- else
- peripheries = poly->peripheries;
-
- vertices = poly->vertices;
-
- if ((s = agget(n, "samplepoints")))
- nump = atoi(s);
- /* We want at least 4 points. For server-side maps, at most 100
- * points are allowed. To simplify things to fit with the 120 points
- * used for skewed ellipses, we set the bound at 60.
- */
- if ((nump < 4) || (nump > 60))
- nump = DFLT_SAMPLE;
- /* use bounding box of text label for mapping
- * when polygon has no peripheries and node is not filled
- */
- if (poly->peripheries == 0 && !filled) {
- obj->url_map_shape = MAP_RECTANGLE;
- nump = 2;
- p = N_NEW(nump, pointf);
- ldimen = ND_label(n)->dimen;
- P2RECT(coord, p, ldimen.x / 2.0, ldimen.y / 2.0);
- }
- /* circle or ellipse */
- else if (poly->sides < 3 && poly->skew == 0.0 && poly->distortion == 0.0) {
- if (poly->regular) {
- obj->url_map_shape = MAP_CIRCLE;
- nump = 2; /* center of circle and top right corner of bb */
- p = N_NEW(nump, pointf);
- p[0].x = coord.x;
- p[0].y = coord.y;
- p[1].x = coord.x + vertices[peripheries - 1].x;
- p[1].y = coord.y + vertices[peripheries - 1].y;
- }
- else { /* ellipse is treated as polygon */
- obj->url_map_shape= MAP_POLYGON;
- p = pEllipse((double)(vertices[peripheries - 1].x),
- (double)(vertices[peripheries - 1].y), nump);
- for (i = 0; i < nump; i++) {
- p[i].x += coord.x;
- p[i].y += coord.y;
- }
- }
- }
- /* all other polygonal shape */
- else {
- int offset = (peripheries - 1)*(poly->sides);
- obj->url_map_shape = MAP_POLYGON;
- /* distorted or skewed ellipses and circles are polygons with 120
- * sides. For mapping we convert them into polygon with sample sides
- */
- if (poly->sides >= nump) {
- int delta = poly->sides / nump;
- p = N_NEW(nump, pointf);
- for (i = 0, j = 0; j < nump; i += delta, j++) {
- p[j].x = coord.x + vertices[i + offset].x;
- p[j].y = coord.y + vertices[i + offset].y;
- }
- } else {
- nump = sides;
- p = N_NEW(nump, pointf);
- for (i = 0; i < nump; i++) {
- p[i].x = coord.x + vertices[i + offset].x;
- p[i].y = coord.y + vertices[i + offset].y;
- }
- }
- }
- }
- else {
- /* we have to use the node's bounding box to map clickable region
- * when requested output format is not capable of polygons.
- */
- obj->url_map_shape = MAP_RECTANGLE;
- nump = 2;
- p = N_NEW(nump, pointf);
- p[0].x = coord.x - ND_lw_i(n);
- p[0].y = coord.y - (ND_ht_i(n) / 2);
- p[1].x = coord.x + ND_rw_i(n);
- p[1].y = coord.y + (ND_ht_i(n) / 2);
- }
- if (! (flags & GVRENDER_DOES_TRANSFORM))
- gvrender_ptf_A(job, p, p, nump);
- obj->url_map_p = p;
- obj->url_map_n = nump;
- }
+ obj_state_t *obj = job->obj;
if (gvre) {
if (gvre->begin_anchor && (obj->url || obj->explicit_tooltip))
else {
codegen_t *cg = job->codegen;
- Obj = NODE;
if (cg && cg->begin_anchor && (obj->url || obj->explicit_tooltip))
cg->begin_anchor(obj->url, obj->tooltip, obj->target);
if (cg && cg->begin_node)
if (cg && cg->end_anchor && (obj->url || obj->explicit_tooltip))
cg->end_anchor();
}
- Obj = NONE;
-#endif
- pop_obj_state(job);
-}
-
-#define HW 2.0 /* maximum distance away from line, in points */
-
-/* check_control_points:
- * check_control_points function checks the size of quadrilateral
- * formed by four control points
- * returns 1 if four points are in line (or close to line)
- * else return 0
- */
-static int check_control_points(pointf *cp)
-{
- double dis1 = ptToLine2 (cp[0], cp[3], cp[1]);
- double dis2 = ptToLine2 (cp[0], cp[3], cp[2]);
- if (dis1 < HW*HW && dis2 < HW*HW)
- return 1;
- else
- return 0;
-}
-
-#ifdef DEBUG
-static void psmapOutput (point* ps, int n)
-{
- int i;
- fprintf (stdout, "newpath %d %d moveto\n", ps[0].x, ps[0].y);
- for (i=1; i < n; i++)
- fprintf (stdout, "%d %d lineto\n", ps[i].x, ps[i].y);
- fprintf (stdout, "closepath stroke\n");
-}
-#endif
-
-typedef struct segitem_s {
- pointf p;
- struct segitem_s* next;
-} segitem_t;
-
-#define MARK_FIRST_SEG(L) ((L)->next = (segitem_t*)1)
-#define FIRST_SEG(L) ((L)->next == (segitem_t*)1)
-#define INIT_SEG(P,L) {(L)->next = 0; (L)->p = P;}
-
-static segitem_t* appendSeg (pointf p, segitem_t* lp)
-{
- segitem_t* s = GNEW(segitem_t);
- INIT_SEG (p, s);
- lp->next = s;
- return s;
-}
-
-/* map_bspline_poly:
- * Output the polygon determined by the n points in p1, followed
- * by the n points in p2 in reverse order. Assumes n <= 50.
- */
-static void map_bspline_poly(pointf **pbs_p, int **pbs_n, int *pbs_poly_n, int n, pointf* p1, pointf* p2)
-{
- int i = 0, nump = 0, last = 2*n-1;
-
- for ( ; i < *pbs_poly_n; i++)
- nump += (*pbs_n)[i];
-
- (*pbs_poly_n)++;
- *pbs_n = grealloc(*pbs_n, (*pbs_poly_n) * sizeof(int));
- (*pbs_n)[i] = 2*n;
- *pbs_p = grealloc(*pbs_p, (nump + 2*n) * sizeof(pointf));
-
- for (i = 0; i < n; i++) {
- (*pbs_p)[nump+i] = p1[i];
- (*pbs_p)[nump+last-i] = p2[i];
- }
-#ifdef DEBUG
- psmapOutput (*pbs_p + nump, last+1);
#endif
}
-/* approx_bezier:
- * Approximate Bezier by line segments. If the four points are
- * almost colinear, as determined by check_control_points, we store
- * the segment cp[0]-cp[3]. Otherwise we split the Bezier into 2
- * and recurse.
- * Since 2 contiguous segments share an endpoint, we actually store
- * the segments as a list of points.
- * New points are appended to the list given by lp. The tail of the
- * list is returned.
- */
-static segitem_t* approx_bezier (pointf *cp, segitem_t* lp)
-{
- pointf sub_curves[8];
-
- if (check_control_points(cp)) {
- if (FIRST_SEG (lp)) INIT_SEG (cp[0], lp);
- lp = appendSeg (cp[3], lp);
- }
- else {
- Bezier (cp, 3, 0.5, sub_curves, sub_curves+4);
- lp = approx_bezier (sub_curves, lp);
- lp = approx_bezier (sub_curves+4, lp);
- }
- return lp;
-}
-
-/* bisect:
- * Return the angle of the bisector between the two rays
- * pp-cp and cp-np. The bisector returned is always to the
- * left of pp-cp-np.
- */
-static double bisect (pointf pp, pointf cp, pointf np)
-{
- double ang, theta, phi;
- theta = atan2(np.y - cp.y,np.x - cp.x);
- phi = atan2(pp.y - cp.y,pp.x - cp.x);
- ang = theta - phi;
- if (ang > 0) ang -= 2*M_PI;
-
- return (phi + ang/2.0);
-}
-
-/* mkSegPts:
- * Determine polygon points related to 2 segments prv-cur and cur-nxt.
- * The points lie on the bisector of the 2 segments, passing through cur,
- * and distance HW from cur. The points are stored in p1 and p2.
- * If p1 is NULL, we use the normal to cur-nxt.
- * If p2 is NULL, we use the normal to prv-cur.
- * Assume at least one of prv or nxt is non-NULL.
- */
-static void mkSegPts (segitem_t* prv, segitem_t* cur, segitem_t* nxt,
- pointf* p1, pointf* p2)
-{
- pointf cp, pp, np;
- double theta, delx, dely;
- pointf p;
-
- cp = cur->p;
- /* if prv or nxt are NULL, use the one given to create a collinear
- * prv or nxt. This could be more efficiently done with special case code,
- * but this way is more uniform.
- */
- if (prv) {
- pp = prv->p;
- if (nxt)
- np = nxt->p;
- else {
- np.x = 2*cp.x - pp.x;
- np.y = 2*cp.y - pp.y;
- }
- }
- else {
- np = nxt->p;
- pp.x = 2*cp.x - np.x;
- pp.y = 2*cp.y - np.y;
- }
- theta = bisect(pp,cp,np);
- delx = HW*cos(theta);
- dely = HW*sin(theta);
- p.x = cp.x + delx;
- p.y = cp.y + dely;
- *p1 = p;
- p.x = cp.x - delx;
- p.y = cp.y - dely;
- *p2 = p;
-}
-
-/* map_output_bspline:
- * Construct and output a closed polygon approximating the input
- * B-spline bp. We do this by first approximating bp by a sequence
- * of line segments. We then use the sequence of segments to determine
- * the polygon.
- * In cmapx, polygons are limited to 100 points, so we output polygons
- * in chunks of 100.
- */
-static void map_output_bspline (pointf **pbs, int **pbs_n, int *pbs_poly_n, bezier* bp)
-{
- segitem_t* segl = GNEW(segitem_t);
- segitem_t* segp = segl;
- segitem_t* segprev;
- segitem_t* segnext;
- int nc, j, k, cnt;
- pointf pts[4];
- pointf pt1[50], pt2[50];
-
- MARK_FIRST_SEG(segl);
- nc = (bp->size - 1)/3; /* nc is number of bezier curves */
- for (j = 0; j < nc; j++) {
- for (k = 0; k < 4; k++) {
- pts[k].x = (double)bp->list[3*j + k].x;
- pts[k].y = (double)bp->list[3*j + k].y;
- }
- segp = approx_bezier (pts, segp);
- }
-
- segp = segl;
- segprev = 0;
- cnt = 0;
- while (segp) {
- segnext = segp->next;
- mkSegPts (segprev, segp, segnext, pt1+cnt, pt2+cnt);
- cnt++;
- if ((segnext == NULL) || (cnt == 50)) {
- map_bspline_poly (pbs, pbs_n, pbs_poly_n, cnt, pt1, pt2);
- pt1[0] = pt1[cnt-1];
- pt2[0] = pt2[cnt-1];
- cnt = 1;
- }
- segprev = segp;
- segp = segnext;
- }
-
- /* free segl */
- while (segl) {
- segp = segl->next;
- free (segl);
- segl = segp;
- }
-}
-
void gvrender_begin_edge(GVJ_t * job, edge_t * e)
{
gvrender_engine_t *gvre = job->render.engine;
- obj_state_t *obj;
- char *s;
- textlabel_t *lab = NULL, *tlab = NULL, *hlab = NULL;
- pointf *p = NULL, *pt = NULL, *ph = NULL, *pte = NULL, *phe = NULL, *pbs = NULL;
- int flags, i, nump, *pbs_n = NULL, pbs_poly_n = 0;
- bezier bz;
-
- flags = job->flags;
- obj = push_obj_state(job);
- obj->e = e;
-
- if (flags & GVRENDER_DOES_Z) {
- obj->tail_z= late_double(e->tail, N_z, 0.0, -1000.0);
- obj->head_z= late_double(e->head, N_z, 0.0, -MAXFLOAT);
- }
-
- if (flags & GVRENDER_DOES_LABELS) {
- if ((lab = ED_label(e))) {
- if (lab->html)
- doHTMLlabel(lab->u.html, lab->p, (void *) e);
- obj->label = lab->text;
- }
- obj->taillabel = obj->headlabel = obj->label;
- if ((tlab = ED_tail_label(e))) {
- if (tlab->html)
- doHTMLlabel(tlab->u.html, tlab->p, (void *) e);
- obj->taillabel = tlab->text;
- }
- if ((hlab = ED_head_label(e))) {
- if (hlab->html)
- doHTMLlabel(hlab->u.html, hlab->p, (void *) e);
- obj->headlabel = hlab->text;
- }
- }
-
- if (flags & GVRENDER_DOES_MAPS) {
- if (((s = agget(e, "href")) && s[0]) || ((s = agget(e, "URL")) && s[0]))
- obj->url = strdup_and_subst_edge(s, e);
- if (((s = agget(e, "tailhref")) && s[0]) || ((s = agget(e, "tailURL")) && s[0]))
- obj->tailurl = strdup_and_subst_edge(s, e);
- else if (obj->url)
- obj->tailurl = strdup(obj->url);
- if (((s = agget(e, "headhref")) && s[0]) || ((s = agget(e, "headURL")) && s[0]))
- obj->headurl = strdup_and_subst_edge(s, e);
- else if (obj->url)
- obj->headurl = strdup(obj->url);
- }
-
- if (flags & GVRENDER_DOES_TARGETS) {
- if ((s = agget(e, "target")) && s[0])
- obj->target = strdup_and_subst_edge(s, e);
- if ((s = agget(e, "tailtarget")) && s[0])
- obj->tailtarget = strdup_and_subst_edge(s, e);
- else if (obj->target)
- obj->tailtarget = strdup(obj->target);
- if ((s = agget(e, "headtarget")) && s[0])
- obj->headtarget = strdup_and_subst_edge(s, e);
- else if (obj->target)
- obj->headtarget = strdup(obj->target);
- }
-
- if (flags & GVRENDER_DOES_TOOLTIPS) {
- if ((s = agget(e, "tooltip")) && s[0]) {
- obj->tooltip = strdup_and_subst_edge(s, e);
- obj->explicit_tooltip = true;
- }
- else if (obj->label)
- obj->tooltip = strdup(obj->label);
- if ((s = agget(e, "tailtooltip")) && s[0]) {
- obj->tailtooltip = strdup_and_subst_edge(s, e);
- obj->explicit_tailtooltip = true;
- }
- else if (obj->taillabel)
- obj->tailtooltip = strdup(obj->taillabel);
- if ((s = agget(e, "headtooltip")) && s[0]) {
- obj->headtooltip = strdup_and_subst_edge(s, e);
- obj->explicit_headtooltip = true;
- }
- else if (obj->headlabel)
- obj->headtooltip = strdup(obj->headlabel);
- }
-
- if (flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) {
- if (flags & (GVRENDER_DOES_MAP_RECTANGLE | GVRENDER_DOES_MAP_POLYGON)) {
- if (flags & GVRENDER_DOES_MAP_RECTANGLE) {
- obj->url_map_shape = MAP_RECTANGLE;
- nump = 2;
- }
- else { /* GVRENDER_DOES_MAP_POLYGON */
- obj->url_map_shape = MAP_POLYGON;
- nump = 4;
- }
-
- if (lab && (obj->url || obj->tooltip)) {
- obj->url_map_n = nump;
- p = N_NEW(nump, pointf);
- P2RECT(lab->p, p, lab->dimen.x / 2., lab->dimen.y / 2.);
- }
-
- if (tlab && (obj->tailurl || obj->tailtooltip)) {
- obj->tailurl_map_n = nump;
- pt = N_NEW(nump, pointf);
- P2RECT(tlab->p, pt, tlab->dimen.x / 2., tlab->dimen.y / 2.);
- }
-
- if (hlab && (obj->headurl || obj->headtooltip)) {
- obj->headurl_map_n = nump;
- ph = N_NEW(nump, pointf);
- P2RECT(hlab->p, ph, hlab->dimen.x / 2., hlab->dimen.y / 2.);
- }
-
- /* process intersecion with tail node */
- if (ED_spl(e) && (obj->tailurl || obj->tailtooltip)) {
- obj->tailendurl_map_n = nump;
- pte = N_NEW(nump, pointf);
- bz = ED_spl(e)->list[0];
- if (bz.sflag) {
- /* Arrow at start of splines */
- P2RECT(bz.sp, pte, FUZZ, FUZZ);
- } else {
- /* No arrow at start of splines */
- P2RECT(bz.list[0], pte, FUZZ, FUZZ);
- }
- }
-
- /* process intersection with head node */
- if (ED_spl(e) && (obj->headurl || obj->headtooltip)) {
- obj->headendurl_map_n = nump;
- phe = N_NEW(nump, pointf);
- bz = ED_spl(e)->list[ED_spl(e)->size - 1];
- if (bz.eflag) {
- /* Arrow at end of splines */
- P2RECT(bz.ep, phe, FUZZ, FUZZ);
- } else {
- /* No arrow at end of splines */
- P2RECT(bz.list[bz.size - 1], phe, FUZZ, FUZZ);
- }
- }
-
- if (ED_spl(e) && (obj->url || obj->tooltip) && (flags & GVRENDER_DOES_MAP_POLYGON)) {
- int ns;
- splines *spl;
-
- spl = ED_spl(e);
- ns = spl->size; /* number of splines */
- for (i = 0; i < ns; i++)
- map_output_bspline (&pbs, &pbs_n, &pbs_poly_n, spl->list+i);
- obj->url_bsplinemap_poly_n = pbs_poly_n;
- obj->url_bsplinemap_n = pbs_n;
- }
-
- if (! (flags & GVRENDER_DOES_TRANSFORM)) {
- if (p) gvrender_ptf_A(job, p, p, 2);
- if (pt) gvrender_ptf_A(job, pt, pt, 2);
- if (ph) gvrender_ptf_A(job, ph, ph, 2);
- if (pte) gvrender_ptf_A(job, pte, pte, 2);
- if (phe) gvrender_ptf_A(job, phe, phe, 2);
- if (pbs) {
- for ( nump = 0, i = 0; i < pbs_poly_n; i++)
- nump += pbs_n[i];
- gvrender_ptf_A(job, pbs, pbs, nump);
- }
- }
- if (! (flags & GVRENDER_DOES_MAP_RECTANGLE)) {
- if (p) rect2poly(p);
- if (pt) rect2poly(pt);
- if (ph) rect2poly(ph);
- if (pte) rect2poly(pte);
- if (phe) rect2poly(phe);
- }
-
- }
- obj->url_map_p = p;
- obj->tailurl_map_p = pt;
- obj->headurl_map_p = ph;
- obj->tailendurl_map_p = pte;
- obj->headendurl_map_p = phe;
- obj->url_bsplinemap_p = pbs;
- }
+ obj_state_t *obj = job->obj;
if (gvre) {
if (gvre->begin_anchor && (obj->url || obj->explicit_tooltip))
else {
codegen_t *cg = job->codegen;
- Obj = EDGE;
if (cg && cg->begin_anchor && (obj->url || obj->explicit_tooltip))
cg->begin_anchor(obj->url, obj->tooltip, obj->target);
if (cg && cg->begin_edge)
if (cg && cg->end_anchor && (obj->url || obj->explicit_tooltip))
cg->end_anchor();
}
- Obj = NONE;
#endif
- pop_obj_state(job);
}
void gvrender_begin_context(GVJ_t * job)
assert(us->name);
assert(us->f);
- n = job->obj->n;
+ n = job->obj->u.n;
assert(n);
fprintf(out, "Shape {\n");
figgen_printf(job, "# Generated by %s version %s (%s)\n",
job->common->info[0], job->common->info[1], job->common->info[2]);
figgen_printf(job, "# For: %s\n", job->common->user);
- figgen_printf(job, "# Title: %s\n", obj->g->name);
+ figgen_printf(job, "# Title: %s\n", obj->u.g->name);
figgen_printf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
figgen_fputs(job, "Portrait\n"); /* orientation */
figgen_fputs(job, "Center\n"); /* justification */
static void map_begin_page(GVJ_t * job)
{
obj_state_t *obj = job->obj;
- char *name = xml_string(obj->g->name);
+ char *name = xml_string(obj->u.g->name);
switch (job->render.id) {
case FORMAT_IMAP:
break;
case FORMAT_ISMAP:
if (obj->url && obj->url[0])
- fprintf(job->output_file, "default %s %s\n", obj->url, obj->g->name);
+ fprintf(job->output_file, "default %s %s\n", obj->url, obj->u.g->name);
break;
case FORMAT_CMAPX:
fprintf(job->output_file, "<map id=\"%s\" name=\"%s\">\n", name, name);
{
obj_state_t *obj = job->obj;
- fprintf(job->output_file, "%% %s\n", obj->sg->name);
+ fprintf(job->output_file, "%% %s\n", obj->u.sg->name);
map_output_shape(job, obj->url_map_shape, obj->url_map_p, obj->url_map_n,
obj->url, obj->tooltip, obj->target);
setupLatin1 = FALSE;
if (job->common->viewNum == 0) {
- fprintf(job->output_file, "%%%%Title: %s\n", obj->g->name);
+ fprintf(job->output_file, "%%%%Title: %s\n", obj->u.g->name);
fprintf(job->output_file, "%%%%Pages: (atend)\n");
if (job->common->show_boxes == NULL)
fprintf(job->output_file, "%%%%BoundingBox: (atend)\n");
cat_preamble(job, job->common->lib);
epsf_define(job->output_file);
}
- isLatin1 = (GD_charset(obj->g) == CHAR_LATIN1);
+ isLatin1 = (GD_charset(obj->u.g) == CHAR_LATIN1);
if (isLatin1 && !setupLatin1) {
fprintf(job->output_file, "setupLatin1\n"); /* as defined in ps header */
setupLatin1 = TRUE;
{
obj_state_t *obj = job->obj;
- fprintf(job->output_file, "%% %s\n", obj->sg->name);
+ fprintf(job->output_file, "%% %s\n", obj->u.sg->name);
if (obj->url && obj->url_map_p) {
fprintf(job->output_file, "[ /Rect [ %g %g %g %g ]\n",
char *objtype;
if (color) {
- if (job->obj->g)
- objtype = "graph";
- else if (job->obj->sg)
- objtype = "graph";
- else if (job->obj->n)
- objtype = "node";
- else if (job->obj->e)
- objtype = "edge";
- else
- objtype = "sethsb";
+ switch (job->obj->type) {
+ case ROOTGRAPH_OBJTYPE:
+ case CLUSTER_OBJTYPE:
+ objtype = "graph";
+ break;
+ case NODE_OBJTYPE:
+ objtype = "node";
+ break;
+ case EDGE_OBJTYPE:
+ objtype = "edge";
+ break;
+ default:
+ objtype = "sethsb";
+ break;
+ }
if ( last_color.u.HSVA[0] != color->u.HSVA[0]
|| last_color.u.HSVA[1] != color->u.HSVA[1]
|| last_color.u.HSVA[2] != color->u.HSVA[2]
|| last_color.u.HSVA[3] != color->u.HSVA[3]
- || (job->obj->g && (job->obj->g == job->obj->g->root))) {
+ || (job->obj->type == ROOTGRAPH_OBJTYPE)) {
fprintf(job->output_file, "%.3f %.3f %.3f %scolor\n",
color->u.HSVA[0], color->u.HSVA[1], color->u.HSVA[2], objtype);
last_color.u.HSVA[0] = color->u.HSVA[0];
obj_state_t *obj = job->obj;
svggen_fputs(job, "<!--");
- if (obj->g->name[0]) {
+ if (obj->u.g->name[0]) {
svggen_fputs(job, " Title: ");
- svggen_fputs(job, xml_string(obj->g->name));
+ svggen_fputs(job, xml_string(obj->u.g->name));
}
svggen_printf(job, " Pages: %d -->\n", job->pagesArraySize.x * job->pagesArraySize.y);
job->scale.x, job->scale.y, -job->rotation,
job->translation.x, -job->translation.y);
/* default style */
- if (obj->g->name[0]) {
+ if (obj->u.g->name[0]) {
svggen_fputs(job, "<title>");
- svggen_fputs(job, xml_string(obj->g->name));
+ svggen_fputs(job, xml_string(obj->u.g->name));
svggen_fputs(job, "</title>\n");
}
}
obj_state_t *obj = job->obj;
svggen_printf(job, "<g id=\"cluster%ld\" class=\"cluster\">",
- obj->sg->meta_node->id);
+ obj->u.sg->meta_node->id);
svggen_fputs(job, "<title>");
- svggen_fputs(job, xml_string(obj->sg->name));
+ svggen_fputs(job, xml_string(obj->u.sg->name));
svggen_fputs(job, "</title>\n");
}
{
obj_state_t *obj = job->obj;
- svggen_printf(job, "<g id=\"node%ld\" class=\"node\">", obj->n->id);
+ svggen_printf(job, "<g id=\"node%ld\" class=\"node\">", obj->u.n->id);
svggen_fputs(job, "<title>");
- svggen_fputs(job, xml_string(obj->n->name));
+ svggen_fputs(job, xml_string(obj->u.n->name));
svggen_fputs(job, "</title>\n");
}
obj_state_t *obj = job->obj;
char *edgeop;
- svggen_printf(job, "<g id=\"edge%ld\" class=\"edge\">", obj->e->id);
- if (obj->e->tail->graph->root->kind & AGFLAG_DIRECTED)
+ svggen_printf(job, "<g id=\"edge%ld\" class=\"edge\">", obj->u.e->id);
+ if (obj->u.e->tail->graph->root->kind & AGFLAG_DIRECTED)
edgeop = "->";
else
edgeop = "--";
svggen_fputs(job, "<title>");
- svggen_fputs(job, xml_string(obj->e->tail->name));
+ svggen_fputs(job, xml_string(obj->u.e->tail->name));
svggen_fputs(job, edgeop);
/* can't do this in single svggen_printf because
* xml_string's buffer gets reused. */
- svggen_fputs(job, xml_string(obj->e->head->name));
+ svggen_fputs(job, xml_string(obj->u.e->head->name));
svggen_fputs(job, "</title>\n");
}
{
FILE *out = job->output_file;
obj_state_t *obj = job->obj;
- node_t *n = obj->n;
+ node_t *n = obj->u.n;
double z = obj->z;
int width, height;
int transparent;
static void vrml_begin_edge(GVJ_t *job)
{
FILE *out = job->output_file;
- edge_t *e = job->obj->e;
+ obj_state_t *obj = job->obj;
+ edge_t *e = obj->u.e;
IsSegment = 0;
fprintf(out, "# edge %s -> %s\n", e->tail->name, e->head->name);
static void vrml_end_edge(GVJ_t *job)
{
if (IsSegment)
- finishSegment(job->output_file, job->obj->e);
+ finishSegment(job->output_file, job->obj->u.e);
fprintf(job->output_file, "] }\n");
}
int brect[8];
extern gdFontPtr gdFontSmall;
- if (! obj->n)
+ if (! obj->u.n)
return;
switch (para->just) {
break;
}
- mp = vrml_node_point(job, obj->n, p);
+ mp = vrml_node_point(job, obj->u.n, p);
err = gdImageStringFT(im, brect,
color_index(im, job->style->pencolor),
interpolate_zcoord(GVJ_t *job, pointf p1, pointf fst, double fstz, pointf snd, double sndz)
{
obj_state_t *obj = job->obj;
- edge_t *e = obj->e;
+ edge_t *e = obj->u.e;
double len, d, rv;
if (fstz == sndz)
FILE *out = job->output_file;
gvstyle_t *style = job->style;
obj_state_t *obj = job->obj;
- edge_t *e = obj->e;
+ edge_t *e = obj->u.e;
double fstz = obj->tail_z, sndz = obj->head_z;
pointf p1, V[4];
int i, j, step;
- assert(obj->e);
+ assert(e);
if (straight(A,n)) {
doSegment (job, A, ND_coord_i(e->tail),Fstz,ND_coord_i(e->head),Sndz);
FILE *out = job->output_file;
gvstyle_t *style = job->style;
obj_state_t *obj = job->obj;
- edge_t *e = obj->e;
+ edge_t *e = obj->u.e;
double rad, ht, y;
pointf p0; /* center of triangle base */
point tp,hp;
FILE *out = job->output_file;
gvstyle_t *style = job->style;
obj_state_t *obj = job->obj;
- graph_t *g = obj->g;
- node_t *n = obj->n;
- edge_t *e = obj->e;
+ node_t *n;
+ edge_t *e;
double z = obj->z;
pointf p, mp;
gdPoint *points;
gdImagePtr brush = NULL;
double theta;
- if (g) {
+ switch (obj->type) {
+ case ROOTGRAPH_OBJTYPE:
fprintf(out, " Background { skyColor %.3f %.3f %.3f }\n",
style->fillcolor.u.rgba[0] / 255.,
style->fillcolor.u.rgba[1] / 255.,
style->fillcolor.u.rgba[2] / 255.);
Saw_skycolor = TRUE;
- }
- else if (n) {
+ break;
+ case CLUSTER_OBJTYPE:
+ break;
+ case NODE_OBJTYPE:
+ n = obj->u.n;
pen = set_penstyle(job, im, brush);
-
points = N_GNEW(np, gdPoint);
for (i = 0; i < np; i++) {
mp = vrml_node_point(job, n, A[i]);
ND_coord_i(n).x, ND_coord_i(n).y, z + .01);
fprintf(out, " }\n");
fprintf(out, "}\n");
-
- }
- else if (e) {
+ break;
+ case EDGE_OBJTYPE:
+ e = obj->u.e;
if (np != 3) {
static int flag;
if (!flag) {
atan2((A[0].y + A[2].y) / 2.0 - A[1].y,
(A[0].x + A[2].x) / 2.0 - A[1].x) + PI / 2.0;
-
/* this is gruesome, but how else can we get z coord */
if (DIST2(p, ND_coord_i(e->tail)) < DIST2(p, ND_coord_i(e->head)))
z = obj->tail_z;
fprintf(out, " }\n");
fprintf(out, " ]\n");
fprintf(out, "}\n");
+ break;
}
}
FILE *out = job->output_file;
gvstyle_t *style = job->style;
obj_state_t *obj = job->obj;
- node_t *n = obj->n;
- edge_t *e = obj->e;
+ node_t *n;
+ edge_t *e;
double z = obj->z;
double rx, ry;
int dx, dy;
rx = A[1].x - A[0].x;
ry = A[1].y - A[0].y;
- if (n) {
+ switch (obj->type) {
+ case ROOTGRAPH_OBJTYPE:
+ case CLUSTER_OBJTYPE:
+ break;
+ case NODE_OBJTYPE:
+ n = obj->u.n;
P2PF(ND_coord_i(n), mp);
if (shapeOf(n) == SH_POINT) {
fprintf(out, " }\n");
fprintf(out, " ]\n");
fprintf(out, "}\n");
- }
- else if (e) {
+ break;
+ case EDGE_OBJTYPE:
+ e = obj->u.e;
/* this is gruesome, but how else can we get z coord */
if (DIST2(A[0], ND_coord_i(e->tail)) < DIST2(A[0], ND_coord_i(e->head)))
z = obj->tail_z;