From: ellson Date: Thu, 27 Jan 2005 06:27:30 +0000 (+0000) Subject: cleaning up pagination code X-Git-Tag: LAST_LIBGRAPH~32^2~7990 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9dcec0d4c286f4a7c4ee4c9fa4b4652e8ba101ce;p=graphviz cleaning up pagination code --- diff --git a/lib/common/emit.c b/lib/common/emit.c index 7f8464528..f31bd1bd0 100644 --- a/lib/common/emit.c +++ b/lib/common/emit.c @@ -31,18 +31,12 @@ #define MAX_CODEGENS 100 +#define PAGINATIONBUG 1 + char *BaseLineStyle[3] = { "solid\0", "setlinewidth\0001\0", 0 }; int Obj; -static int Page; /* w.r.t. unrotated coords */ -static int Layer, Nlayers; -static char **LayerID; -static box PB; /* drawable region in device coords */ -static pointf GP; /* graph page size, in graph coords */ -static box CB; /* current page box, in graph coords */ -static point PFC; /* device page box for centering */ static double Deffontsize; static char *Deffontname; -static char *Layerdelims; static attrsym_t *G_peripheries; static point exch_xy(point p) @@ -65,70 +59,81 @@ static pointf exch_xyf(pointf p) /* parse_layers: * Split input string into tokens, with separators specified by - * the layersep attribute. Store the values in the LayerID array, + * the layersep attribute. Store the values in the gvc->layerIDs array, * starting at index 1, and return the count. * Free previously stored list. Note that there is no mechanism * to free the memory before exit. */ -static int parse_layers(graph_t * g, char *p) +static int parse_layers(GVC_t *gvc, graph_t * g, char *p) { int ntok; - char *pcopy; char *tok; int sz; - Layerdelims = agget(g, "layersep"); - if (!Layerdelims) - Layerdelims = DEFAULT_LAYERSEP; + gvc->layerDelims = agget(g, "layersep"); + if (!gvc->layerDelims) + gvc->layerDelims = DEFAULT_LAYERSEP; ntok = 0; sz = 0; - pcopy = strdup(p); + gvc->layers = strdup(p); - if (LayerID) - free(LayerID); - LayerID = 0; - for (tok = strtok(pcopy, Layerdelims); tok; - tok = strtok(NULL, Layerdelims)) { + for (tok = strtok(gvc->layers, gvc->layerDelims); tok; + tok = strtok(NULL, gvc->layerDelims)) { ntok++; if (ntok > sz) { sz += SMALLBUF; - LayerID = ALLOC(sz, LayerID, char *); + gvc->layerIDs = ALLOC(sz, gvc->layerIDs, char *); } - LayerID[ntok] = tok; + gvc->layerIDs[ntok] = tok; } if (ntok) { - LayerID = RALLOC(ntok + 2, LayerID, char *); /* shrink to minimum size */ - LayerID[0] = NULL; - LayerID[ntok + 1] = NULL; + gvc->layerIDs = RALLOC(ntok + 2, gvc->layerIDs, char *); /* shrink to minimum size */ + gvc->layerIDs[0] = NULL; + gvc->layerIDs[ntok + 1] = NULL; } return ntok; } -static void setup_layering(GVC_t * gvc, graph_t * g) +static void init_layering(GVC_t * gvc, graph_t * g) { char *str; + /* free layer strings and pointers from previous graph */ + if (gvc->layers) + free(gvc->layers); + if (gvc->layerIDs) + free(gvc->layerIDs); + if ((str = agget(g, "layers")) != 0) { if (gvrender_features(gvc) & GVRENDER_DOES_LAYERS) { - Nlayers = parse_layers(g, str); + gvc->numLayers = parse_layers(gvc, g, str); } else { agerr(AGWARN, "layers not supported in %s output\n", gvc->job->output_langname); - Nlayers = 0; + gvc->numLayers = 1; } } else { - LayerID = NULL; - Nlayers = 0; + gvc->layerIDs = NULL; + gvc->numLayers = 1; } } -static void reset_layering(GVC_t * gvc, graph_t * g) +static void firstlayer(GVC_t *gvc) +{ + gvc->layerNum = 1; +} + +static boolean validlayer(GVC_t *gvc) +{ + return (gvc->layerNum <= gvc->numLayers); +} + +static void nextlayer(GVC_t *gvc) { - Layer = Nlayers = 0; - LayerID = NULL; /* FIXME - poss leak of array of layer names? */ + gvc->layerNum++; } static point pagecode(GVC_t *gvc, char c) @@ -160,6 +165,7 @@ static void set_pagedir(GVC_t *gvc, graph_t * g) gvc->pagesArrayMajor.x = gvc->pagesArrayMajor.y = gvc->pagesArrayMinor.x = gvc->pagesArrayMinor.y = 0; + gvc->pagesArrayFirst.x = gvc->pagesArrayFirst.y = 0; str = agget(g, "pagedir"); if (str && str[0]) { gvc->pagesArrayMajor = pagecode(gvc, str[0]); @@ -167,44 +173,44 @@ static void set_pagedir(GVC_t *gvc, graph_t * g) } if ((abs(gvc->pagesArrayMajor.x + gvc->pagesArrayMinor.x) != 1) || (abs(gvc->pagesArrayMajor.y + gvc->pagesArrayMinor.y) != 1)) { - gvc->pagesArrayMajor.x = 0; - gvc->pagesArrayMajor.y = 1; - gvc->pagesArrayMinor.x = 1; - gvc->pagesArrayMinor.y = 0; - gvc->pagesArrayFirst.x = gvc->pagesArrayFirst.y = 0; + gvc->pagesArrayMajor = pagecode(gvc, 'B'); + gvc->pagesArrayMinor = pagecode(gvc, 'L'); if (str) agerr(AGWARN, "pagedir=%s ignored\n", str); } } -static void setup_pagination(GVC_t * gvc, graph_t * g) +static void init_job_pagination(GVC_t * gvc, graph_t * g) { - point PFCLM; /* page for centering less margins */ - point DS; /* device drawable region for a page of the graph */ + gvrender_job_t *job = gvc->job; + pointf PFCLM; /* page for centering less margins */ + pointf DS; /* device drawable region for a page of the graph */ /* determine pagination */ - PB.LL = GD_drawing(g)->margin; - if ((GD_drawing(g)->page.x > 0) && (GD_drawing(g)->page.y > 0)) { + job->pageBox.LL = job->margin; + if (gvc->graph_sets_page) { /* page was set by user */ point tp; - PFC = GD_drawing(g)->page; - PFCLM.x = PFC.x - 2 * PB.LL.x; - PFCLM.y = PFC.y - 2 * PB.LL.y; - GP.x = PFCLM.x; - GP.y = PFCLM.y; /* convert to double */ + job->pageBoxCentered = gvc->page; + PFCLM.x = job->pageBoxCentered.x - 2 * job->pageBox.LL.x; + PFCLM.y = job->pageBoxCentered.y - 2 * job->pageBox.LL.y; + gvc->pageSize.x = PFCLM.x; + gvc->pageSize.y = PFCLM.y; /* convert to double */ if (GD_drawing(g)->landscape) - GP = exch_xyf(GP); - GP.x = GP.x / gvc->job->zoom; - GP.y = GP.y / gvc->job->zoom; + gvc->pageSize = exch_xyf(gvc->pageSize); + gvc->pageSize.x /= gvc->job->zoom; + gvc->pageSize.y /= gvc->job->zoom; /* we don't want graph page to exceed its bounding box */ - GP.x = MIN(GP.x, GD_bb(g).UR.x); - GP.y = MIN(GP.y, GD_bb(g).UR.y); - gvc->pagesArraySize.x = (GP.x > 0) ? ceil(((double) GD_bb(g).UR.x) / GP.x) : 1; - gvc->pagesArraySize.y = (GP.y > 0) ? ceil(((double) GD_bb(g).UR.y) / GP.y) : 1; - gvc->pagesSize = gvc->pagesArraySize.x * gvc->pagesArraySize.y; + gvc->pageSize.x = MIN(gvc->pageSize.x, gvc->bb.UR.x); + gvc->pageSize.y = MIN(gvc->pageSize.y, gvc->bb.UR.y); + gvc->pagesArraySize.x = + (gvc->pageSize.x > 0) ? ceil((gvc->bb.UR.x) / gvc->pageSize.x) : 1; + gvc->pagesArraySize.y = + (gvc->pageSize.y > 0) ? ceil((gvc->bb.UR.y) / gvc->pageSize.y) : 1; + gvc->numPages = gvc->pagesArraySize.x * gvc->pagesArraySize.y; /* find the drawable size in device coords */ -#if 1 +#ifdef PAGINATIONBUG tp = GD_drawing(g)->size; #else tp.x = gvc->job->width; @@ -217,21 +223,21 @@ static void setup_pagination(GVC_t * gvc, graph_t * g) } else { /* page not set by user, assume default when centering, but allow infinite page for any other interpretation */ - GP.x = GD_bb(g).UR.x; - GP.y = GD_bb(g).UR.y; - PFC.x = DEFAULT_PAGEWD; - PFC.y = DEFAULT_PAGEHT; - PFCLM.x = PFC.x - 2 * PB.LL.x; - PFCLM.y = PFC.y - 2 * PB.LL.y; -#if 1 - DS = GD_drawing(g)->size; + gvc->pageSize.x = gvc->bb.UR.x; + gvc->pageSize.y = gvc->bb.UR.y; + job->pageBoxCentered.x = DEFAULT_PAGEWD; + job->pageBoxCentered.y = DEFAULT_PAGEHT; + PFCLM.x = job->pageBoxCentered.x - 2 * job->pageBox.LL.x; + PFCLM.y = job->pageBoxCentered.y - 2 * job->pageBox.LL.y; +#ifdef PAGINATIONBUG + P2PF(GD_drawing(g)->size, DS); #else DS.x = gvc->job->width; DS.y = gvc->job->height; #endif if (GD_drawing(g)->landscape) - DS = exch_xy(DS); - gvc->pagesArraySize.x = gvc->pagesArraySize.y = gvc->pagesSize = 1; + DS = exch_xyf(DS); + gvc->pagesArraySize.x = gvc->pagesArraySize.y = gvc->numPages = 1; } set_pagedir(gvc, g); @@ -243,23 +249,37 @@ static void setup_pagination(GVC_t * gvc, graph_t * g) extra.x = 0; if ((extra.y = PFCLM.y - DS.y) < 0) extra.y = 0; - PB.LL.x += extra.x / 2; - PB.LL.y += extra.y / 2; + job->pageBox.LL.x += extra.x / 2; + job->pageBox.LL.y += extra.y / 2; } - PB.UR = add_points(PB.LL, DS); + job->pageBox.UR = add_pointfs(job->pageBox.LL, DS); } -static void reset_pagination(GVC_t * gvc, graph_t * g) +static void firstpage(GVC_t *gvc) { - Page = 0; - gvc->pagesArrayFirst.x = gvc->pagesArrayFirst.y = 0; - gvc->pagesArrayMajor.x = gvc->pagesArrayMajor.y = 0; - gvc->pagesArrayMinor.x = gvc->pagesArrayMinor.y = 0; - gvc->pagesArraySize.x = gvc->pagesArraySize.y = gvc->pagesSize = 1; - PB.LL.x = PB.LL.y = PB.UR.x = PB.UR.y = 0; - GP.x = GP.y = 0; - CB.LL.x = CB.LL.y = CB.UR.x = CB.UR.y = 0; - PFC.x = PFC.y = 0; + gvc->pagesArrayElem = gvc->pagesArrayFirst; + gvc->pageNum = 1; +} + +static int validpage(GVC_t *gvc) +{ + return ((gvc->pagesArrayElem.x >= 0) + && (gvc->pagesArrayElem.x < gvc->pagesArraySize.x) + && (gvc->pagesArrayElem.y >= 0) + && (gvc->pagesArrayElem.y < gvc->pagesArraySize.y)); +} + +static void nextpage(GVC_t *gvc) +{ + gvc->pagesArrayElem = add_points(gvc->pagesArrayElem, gvc->pagesArrayMinor); + if (validpage(gvc) == FALSE) { + if (gvc->pagesArrayMajor.y) + gvc->pagesArrayElem.x = gvc->pagesArrayFirst.x; + else + gvc->pagesArrayElem.y = gvc->pagesArrayFirst.y; + gvc->pagesArrayElem = add_points(gvc->pagesArrayElem, gvc->pagesArrayMajor); + } + gvc->pageNum = gvc->pagesArrayElem.x + gvc->pagesArrayElem.y * gvc->pagesArraySize.x + 1; } static int write_edge_test(Agraph_t * g, Agedge_t * e) @@ -292,10 +312,6 @@ void emit_reset(GVC_t * gvc, graph_t * g) { Agnode_t *n; - reset_layering(gvc, g); - - reset_pagination(gvc, g); - /* reset state */ for (n = agfstnode(g); n; n = agnxtnode(g, n)) { ND_state(n) = 0; @@ -305,20 +321,22 @@ void emit_reset(GVC_t * gvc, graph_t * g) gvrender_reset(gvc); } -static void emit_background(GVC_t * gvc, point LL, point UR) +static void emit_background(GVC_t * gvc, boxf pageBox) { char *str; point A[4]; graph_t *g = gvc->g; + box PB; if (((str = agget(g, "bgcolor")) != 0) && str[0] && strcmp(str, "white") != 0 && strcmp(str, "transparent") != 0) { /* increment to cover int rounding errors */ - A[0].x = A[1].x = LL.x - GD_drawing(g)->margin.x - 1; - A[2].x = A[3].x = UR.x + GD_drawing(g)->margin.x + 1; - A[1].y = A[2].y = UR.y + GD_drawing(g)->margin.y + 1; - A[3].y = A[0].y = LL.y - GD_drawing(g)->margin.y - 1; + BF2B(pageBox, PB); + A[0].x = A[1].x = PB.LL.x - GD_drawing(g)->margin.x - 1; + A[2].x = A[3].x = PB.UR.x + GD_drawing(g)->margin.x + 1; + A[1].y = A[2].y = PB.UR.y + GD_drawing(g)->margin.y + 1; + A[3].y = A[0].y = PB.LL.y - GD_drawing(g)->margin.y - 1; gvrender_set_fillcolor(gvc, str); gvrender_set_pencolor(gvc, str); gvrender_polygon(gvc, A, 4, TRUE); /* filled */ @@ -333,45 +351,165 @@ static void emit_defaults(GVC_t * gvc) /* even if this makes you cringe, at least it's short */ -static void setup_page(GVC_t * gvc, point page) +static void setup_page(GVC_t * gvc) { point offset; int rot; graph_t *g = gvc->g; - Page++; - /* establish current box in graph coordinates */ - CB.LL.x = page.x * GP.x; - CB.LL.y = page.y * GP.y; - CB.UR.x = CB.LL.x + GP.x; - CB.UR.y = CB.LL.y + GP.y; + gvc->pageBox.LL.x = gvc->pagesArrayElem.x * gvc->pageSize.x; + gvc->pageBox.LL.y = gvc->pagesArrayElem.y * gvc->pageSize.y; + gvc->pageBox.UR.x = gvc->pageBox.LL.x + gvc->pageSize.x; + gvc->pageBox.UR.y = gvc->pageBox.LL.y + gvc->pageSize.y; /* establish offset to be applied, in graph coordinates */ if (GD_drawing(g)->landscape == FALSE) - offset = pointof(-CB.LL.x, -CB.LL.y); + offset = pointof(-gvc->pageBox.LL.x, -gvc->pageBox.LL.y); else { - offset.x = (page.y + 1) * GP.y; - offset.y = -page.x * GP.x; + offset.x = (gvc->pagesArrayElem.y + 1) * gvc->pageSize.y; + offset.y = -(gvc->pagesArrayElem.x) * gvc->pageSize.x; } rot = GD_drawing(g)->landscape ? 90 : 0; - gvrender_begin_page(gvc, page, gvc->job->zoom, rot, offset); - emit_background(gvc, CB.LL, CB.UR); + gvrender_begin_page(gvc, gvc->job->zoom, rot, offset); + emit_background(gvc, gvc->pageBox); emit_defaults(gvc); } -static int node_in_CB(GVC_t *gvc, node_t * n) +static boolean node_in_pageBox(GVC_t *gvc, node_t * n) { - box nb; + boxf nb; - if (gvc->pagesSize == 1) + if (gvc->numPages == 1) return TRUE; nb.LL.x = ND_coord_i(n).x - ND_lw_i(n); - nb.LL.y = ND_coord_i(n).y - ND_ht_i(n) / 2; + nb.LL.y = ND_coord_i(n).y - ND_ht_i(n) / 2.; nb.UR.x = ND_coord_i(n).x + ND_rw_i(n); - nb.UR.y = ND_coord_i(n).y + ND_ht_i(n) / 2; - return rect_overlap(CB, nb); + nb.UR.y = ND_coord_i(n).y + ND_ht_i(n) / 2.; + return boxf_overlap(gvc->pageBox, nb); +} + +static int is_natural_number(char *sstr) +{ + unsigned char *str = (unsigned char *) sstr; + while (*str) + if (NOT(isdigit(*str++))) + return FALSE; + return TRUE; +} + +static int layer_index(GVC_t *gvc, char *str, int all) +{ + int i; + + if (streq(str, "all")) + return all; + if (is_natural_number(str)) + return atoi(str); + if (gvc->layerIDs) + for (i = 1; i <= gvc->numLayers; i++) + if (streq(str, gvc->layerIDs[i])) + return i; + return -1; +} + +static int selectedlayer(GVC_t *gvc, char *spec) +{ + int n0, n1; + unsigned char buf[SMALLBUF]; + char *w0, *w1; + agxbuf xb; + int rval = FALSE; + + agxbinit(&xb, SMALLBUF, buf); + agxbput(&xb, spec); + w1 = w0 = strtok(agxbuse(&xb), gvc->layerDelims); + if (w0) + w1 = strtok(NULL, gvc->layerDelims); + switch ((w0 != NULL) + (w1 != NULL)) { + case 0: + rval = FALSE; + break; + case 1: + n0 = layer_index(gvc, w0, gvc->layerNum); + rval = (n0 == gvc->layerNum); + break; + case 2: + n0 = layer_index(gvc, w0, 0); + n1 = layer_index(gvc, w1, gvc->numLayers); + if ((n0 < 0) || (n1 < 0)) + rval = TRUE; + else if (n0 > n1) { + int t = n0; + n0 = n1; + n1 = t; + } + rval = BETWEEN(n0, gvc->layerNum, n1); + break; + } + agxbfree(&xb); + return rval; +} + +static int node_in_layer(GVC_t *gvc, graph_t * g, node_t * n) +{ + char *pn, *pe; + edge_t *e; + + if (gvc->numLayers <= 1) + return TRUE; + pn = late_string(n, N_layer, ""); + if (selectedlayer(gvc, pn)) + return TRUE; + if (pn[0]) + return FALSE; /* Only check edges if pn = "" */ + if ((e = agfstedge(g, n)) == NULL) + return TRUE; + for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { + pe = late_string(e, E_layer, ""); + if ((pe[0] == '\0') || selectedlayer(gvc, pe)) + return TRUE; + } + return FALSE; +} + +static int edge_in_layer(GVC_t *gvc, graph_t * g, edge_t * e) +{ + char *pe, *pn; + int cnt; + + if (gvc->numLayers <= 1) + return TRUE; + pe = late_string(e, E_layer, ""); + if (selectedlayer(gvc, pe)) + return TRUE; + if (pe[0]) + return FALSE; + for (cnt = 0; cnt < 2; cnt++) { + pn = late_string(cnt < 1 ? e->tail : e->head, N_layer, ""); + if ((pn[0] == '\0') || selectedlayer(gvc, pn)) + return TRUE; + } + return FALSE; +} + +static int clust_in_layer(GVC_t *gvc, graph_t * sg) +{ + char *pg; + node_t *n; + + if (gvc->numLayers <= 1) + return TRUE; + pg = late_string(sg, agfindattr(sg, "layer"), ""); + if (selectedlayer(gvc, pg)) + return TRUE; + if (pg[0]) + return FALSE; + for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) + if (node_in_layer(gvc, sg, n)) + return TRUE; + return FALSE; } static void emit_node(GVC_t * gvc, node_t * n) @@ -380,7 +518,7 @@ static void emit_node(GVC_t * gvc, node_t * n) if (ND_shape(n) == NULL) return; - if (node_in_layer(n->graph, n) && node_in_CB(gvc, n) && (ND_state(n) != Page)) { + if (node_in_layer(gvc, n->graph, n) && node_in_pageBox(gvc, n) && (ND_state(n) != gvc->pageNum)) { gvrender_begin_node(gvc, n); if (((s = agget(n, "href")) && s[0]) || ((s = agget(n, "URL")) && s[0])) { @@ -395,7 +533,7 @@ static void emit_node(GVC_t * gvc, node_t * n) } gvrender_begin_context(gvc); ND_shape(n)->fns->codefn(gvc, n); - ND_state(n) = Page; + ND_state(n) = gvc->pageNum; gvrender_end_context(gvc); if (url) { gvrender_end_anchor(gvc); @@ -472,15 +610,17 @@ void emit_attachment(GVC_t * gvc, textlabel_t * lp, splines * spl) gvrender_polyline(gvc, A, 3); } -static int edge_in_CB(GVC_t *gvc, edge_t * e) +static boolean edge_in_pageBox(GVC_t *gvc, edge_t * e) { int i, j, np; bezier bz; - point *p, pp, sz; - box b; + point *p; + pointf pp, pn; + double sx, sy; + boxf b; textlabel_t *lp; - if (gvc->pagesSize == 1) + if (gvc->numPages == 1) return TRUE; if (ED_spl(e) == NULL) return FALSE; @@ -488,21 +628,23 @@ static int edge_in_CB(GVC_t *gvc, edge_t * e) bz = ED_spl(e)->list[i]; np = bz.size; p = bz.list; - pp = p[0]; + P2PF(p[0],pp); for (j = 0; j < np; j++) { - if (rect_overlap(CB, mkbox(pp, p[j]))) + P2PF(p[j],pn); + if (boxf_overlap(gvc->pageBox, mkboxf(pp, pn))) return TRUE; - pp = p[j]; + pp = pn; } } if ((lp = ED_label(e)) == NULL) return FALSE; - PF2P(lp->dimen, sz); - b.LL.x = lp->p.x - sz.x / 2; - b.UR.x = lp->p.x + sz.x / 2; - b.LL.y = lp->p.y - sz.y / 2; - b.UR.y = lp->p.y + sz.y / 2; - return rect_overlap(CB, b); + sx = lp->dimen.x / 2.; + sy = lp->dimen.y / 2.; + b.LL.x = lp->p.x - sx; + b.UR.x = lp->p.x + sx; + b.LL.y = lp->p.y - sy; + b.UR.y = lp->p.y + sy; + return boxf_overlap(gvc->pageBox, b); } static void emit_edge(GVC_t * gvc, edge_t * e) @@ -524,8 +666,8 @@ static void emit_edge(GVC_t * gvc, edge_t * e) #define SEP 2.0 - if ((edge_in_CB(gvc, e) == FALSE) - || (edge_in_layer(e->head->graph, e) == FALSE)) + if ((edge_in_pageBox(gvc, e) == FALSE) + || (edge_in_layer(gvc, e->head->graph, e) == FALSE)) return; gvrender_begin_edge(gvc, e); @@ -699,6 +841,7 @@ static void emit_edge(GVC_t * gvc, edge_t * e) gvrender_end_edge(gvc); } +#ifdef PAGINATIONBUG static double setScale(graph_t * g) { double xscale, yscale, scale; @@ -711,6 +854,7 @@ static double setScale(graph_t * g) GD_drawing(g)->size.y = scale * GD_bb(g).UR.y; return scale; } +#endif /* emit_init @@ -723,7 +867,7 @@ void emit_init(GVC_t * gvc, graph_t * g) double X, Y, Z, x, y; point size = GD_drawing(g)->size; point UR = GD_bb(g).UR; -#if 1 +#ifdef PAGINATIONBUG double scale; #endif @@ -732,22 +876,27 @@ void emit_init(GVC_t * gvc, graph_t * g) /* determine final drawing size and scale to apply. */ /* N.B. size given by user is not rotated by landscape mode */ /* start with "natural" size of layout */ -#if 1 +#ifdef PAGINATIONBUG /* FIXME - this version still needed by psgen.c*/ scale = GD_drawing(g)->scale = 1.0; if (GD_drawing(g)->size.x > 0) { /* was given by user... */ if ((GD_drawing(g)->size.x < GD_bb(g).UR.x) /* drawing is too big... */ ||(GD_drawing(g)->size.y < GD_bb(g).UR.y)) { scale = setScale(g); - } else if (GD_drawing(g)->filled) { + } + else if (GD_drawing(g)->filled) { if ((GD_drawing(g)->size.x > GD_bb(g).UR.x) /* drawing is too small... */ &&(GD_drawing(g)->size.y > GD_bb(g).UR.y)) { - scale = setScale(g); + scale = setScale(g); } - } else + } + else { GD_drawing(g)->size = GD_bb(g).UR; - } else + } + } + else { GD_drawing(g)->size = GD_bb(g).UR; + } #endif Z = 1.0; @@ -772,9 +921,9 @@ void emit_init(GVC_t * gvc, graph_t * g) late_double(g->proto->n, N_fontsize, DEFAULT_FONTSIZE, MIN_FONTSIZE); - setup_layering(gvc, g); + init_layering(gvc, g); - setup_pagination(gvc, g); + init_job_pagination(gvc, g); gvrender_begin_job(gvc, Lib, X, Y, Z, x, y, GD_drawing(g)->dpi); } @@ -784,28 +933,36 @@ void emit_deinit(GVC_t * gvc) gvrender_end_job(gvc); } -static int validpage(GVC_t *gvc, point page) +static void init_job_margin(GVC_t *gvc) { - return ((page.x >= 0) && (page.x < gvc->pagesArraySize.x) - && (page.y >= 0) && (page.y < gvc->pagesArraySize.y)); -} - -static point pageincr(GVC_t *gvc, point page) -{ - page = add_points(page, gvc->pagesArrayMinor); - if (validpage(gvc, page) == FALSE) { - if (gvc->pagesArrayMajor.y) - page.x = gvc->pagesArrayFirst.x; - else - page.y = gvc->pagesArrayFirst.y; - page = add_points(page, gvc->pagesArrayMajor); + gvrender_job_t *job = gvc->job; + + if (gvc->graph_sets_margin) { + job->margin = gvc->margin; + } + else { + /* set default margins depending on format */ + switch (gvc->job->output_lang) { + case GVRENDER_PLUGIN: + job->margin.x = job->margin.y = job->render_features->default_margin; + break; + case POSTSCRIPT: case PDF: case HPGL: case PCL: case MIF: + case METAPOST: case FIG: case VTX: case ATTRIBUTED_DOT: + case PLAIN: case PLAIN_EXT: case QPDF: + job->margin.x = job->margin.y = DEFAULT_MARGIN; + break; + case CANONICAL_DOT: + job->margin.x = job->margin.y = 0; + break; + default: + job->margin.x = job->margin.y = DEFAULT_EMBED_MARGIN; + break; + } } - return page; } void emit_graph(GVC_t * gvc, graph_t * g, int flags) { - point curpage; graph_t *sg; node_t *n; edge_t *e; @@ -813,18 +970,11 @@ void emit_graph(GVC_t * gvc, graph_t * g, int flags) char *str, *colors; char *s, *url = NULL, *tooltip = NULL, *target = NULL; -/* FIXME - shouldn't need this again */ - setup_pagination(gvc, g); + init_job_margin(gvc); -#if 0 -/* FIXME - apparently zoom is not set yet */ - gvc->clip.UR.x = ROUND(gvc->focus.x + (gvc->width+1) / (gvc->zoom * 2.)); - gvc->clip.UR.y = ROUND(gvc->focus.y + (gvc->height+1) / (gvc->zoom * 2.)); - gvc->clip.LL.x = ROUND(gvc->focus.x - (gvc->width+1) / (gvc->zoom * 2.)); - gvc->clip.LL.y = ROUND(gvc->focus.y - (gvc->height+1) / (gvc->zoom * 2.)); -#endif + init_job_pagination(gvc, g); - gvrender_begin_graph(gvc, g, PB, PFC); + gvrender_begin_graph(gvc, g); if (flags & EMIT_COLORS) { gvrender_set_fillcolor(gvc, DEFAULT_FILL); if (((str = agget(g, "bgcolor")) != 0) && str[0]) @@ -866,14 +1016,12 @@ void emit_graph(GVC_t * gvc, graph_t * g, int flags) } } - Layer = 1; - do { - if (Nlayers > 0) - gvrender_begin_layer(gvc, LayerID[Layer], Layer, Nlayers); - for (curpage = gvc->pagesArrayFirst; validpage(gvc, curpage); - curpage = pageincr(gvc, curpage)) { + for (firstlayer(gvc); validlayer(gvc); nextlayer(gvc)) { + if (gvc->numLayers > 1) + gvrender_begin_layer(gvc); + for (firstpage(gvc); validpage(gvc); nextpage(gvc)) { + setup_page(gvc); Obj = NONE; - setup_page(gvc, curpage); if (((s = agget(g, "href")) && s[0]) || ((s = agget(g, "URL")) && s[0])) { url = strdup_and_subst_graph(s, g); @@ -975,16 +1123,15 @@ void emit_graph(GVC_t * gvc, graph_t * g, int flags) } gvrender_end_page(gvc); } - if (Nlayers > 0) + if (gvc->numLayers > 1) gvrender_end_layer(gvc); - Layer++; - } while (Layer <= Nlayers); + } gvrender_end_graph(gvc); } void emit_eof(GVC_t * gvc) { - if (Page > 0) { + if (gvc->pageNum > 0) { emit_deinit(gvc); emit_once_reset(); } @@ -1002,7 +1149,7 @@ void emit_clusters(GVC_t * gvc, Agraph_t * g, int flags) for (c = 1; c <= GD_n_cluster(g); c++) { sg = GD_clust(g)[c]; - if (clust_in_layer(sg) == FALSE) + if (clust_in_layer(gvc, sg) == FALSE) continue; /* when mapping, detect events on clusters after sub_clusters */ if (flags & EMIT_CLUSTERS_LAST) { @@ -1098,128 +1245,6 @@ void emit_clusters(GVC_t * gvc, Agraph_t * g, int flags) } } -int node_in_layer(graph_t * g, node_t * n) -{ - char *pn, *pe; - edge_t *e; - - if (Nlayers <= 0) - return TRUE; - pn = late_string(n, N_layer, ""); - if (selectedlayer(pn)) - return TRUE; - if (pn[0]) - return FALSE; /* Only check edges if pn = "" */ - if ((e = agfstedge(g, n)) == NULL) - return TRUE; - for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { - pe = late_string(e, E_layer, ""); - if ((pe[0] == '\0') || selectedlayer(pe)) - return TRUE; - } - return FALSE; -} - -int edge_in_layer(graph_t * g, edge_t * e) -{ - char *pe, *pn; - int cnt; - - if (Nlayers <= 0) - return TRUE; - pe = late_string(e, E_layer, ""); - if (selectedlayer(pe)) - return TRUE; - if (pe[0]) - return FALSE; - for (cnt = 0; cnt < 2; cnt++) { - pn = late_string(cnt < 1 ? e->tail : e->head, N_layer, ""); - if ((pn[0] == '\0') || selectedlayer(pn)) - return TRUE; - } - return FALSE; -} - -int clust_in_layer(graph_t * sg) -{ - char *pg; - node_t *n; - - if (Nlayers <= 0) - return TRUE; - pg = late_string(sg, agfindattr(sg, "layer"), ""); - if (selectedlayer(pg)) - return TRUE; - if (pg[0]) - return FALSE; - for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) - if (node_in_layer(sg, n)) - return TRUE; - return FALSE; -} - -int is_natural_number(char *sstr) -{ - unsigned char *str = (unsigned char *) sstr; - while (*str) - if (NOT(isdigit(*str++))) - return FALSE; - return TRUE; -} - -static int layer_index(char *str, int all) -{ - int i; - - if (streq(str, "all")) - return all; - if (is_natural_number(str)) - return atoi(str); - if (LayerID) - for (i = 1; i <= Nlayers; i++) - if (streq(str, LayerID[i])) - return i; - return -1; -} - -int selectedlayer(char *spec) -{ - int n0, n1; - unsigned char buf[SMALLBUF]; - char *w0, *w1; - agxbuf xb; - int rval = FALSE; - - agxbinit(&xb, SMALLBUF, buf); - agxbput(&xb, spec); - w1 = w0 = strtok(agxbuse(&xb), Layerdelims); - if (w0) - w1 = strtok(NULL, Layerdelims); - switch ((w0 != NULL) + (w1 != NULL)) { - case 0: - rval = FALSE; - break; - case 1: - n0 = layer_index(w0, Layer); - rval = (n0 == Layer); - break; - case 2: - n0 = layer_index(w0, 0); - n1 = layer_index(w1, Nlayers); - if ((n0 < 0) || (n1 < 0)) - rval = TRUE; - else if (n0 > n1) { - int t = n0; - n0 = n1; - n1 = t; - } - rval = BETWEEN(n0, Layer, n1); - break; - } - agxbfree(&xb); - return rval; -} - static int style_delim(int c) { switch (c) { diff --git a/lib/common/macros.h b/lib/common/macros.h index 7c7b263bc..039ff1cbc 100644 --- a/lib/common/macros.h +++ b/lib/common/macros.h @@ -108,6 +108,8 @@ #define P2PF(p, pf) (pf.x = p.x, pf.y = p.y) #define PF2P(pf, p) (p.x = ROUND (pf.x), p.y = ROUND (pf.y)) +#define B2BF(b, bf) (bf.LL.x = b.LL.x, bf.LL.y = b.LL.y, bf.UR.x = b.UR.x, bf.UR.y = b.UR.y) +#define BF2B(bf, b) (b.LL.x = ROUND (bf.LL.x), b.LL.y = ROUND (bf.LL.y), b.UR.x = ROUND (bf.UR.x), b.UR.y = ROUND (bf.UR.y)) #define XPAD(d) ((d).x += 4*GAP) #define YPAD(d) ((d).y += 2*GAP) diff --git a/lib/common/output.c b/lib/common/output.c index d248364a9..9d699bd6d 100644 --- a/lib/common/output.c +++ b/lib/common/output.c @@ -35,69 +35,33 @@ static void extend_attrs(GVC_t * gvc); #define Y(y) (y_invert ? (y_off - (y)) : (y)) #define YF(y) (y_invert ? (yf_off - (y)) : (y)) -void dotneato_set_margins(GVC_t * gvc, graph_t * g) +static void graph_sets_margin(GVC_t * gvc, graph_t * g) { double xf, yf; char *p; int i; /* margins */ + gvc->graph_sets_margin = FALSE; if ((p = agget(g, "margin"))) { - i = sscanf(p, "%lf,%lf", &xf, &yf); - if (i > 0) - GD_drawing(g)->margin.x = GD_drawing(g)->margin.y = POINTS(xf); - if (i > 1) - GD_drawing(g)->margin.y = POINTS(yf); - } else { - /* set default margins depending on format */ - switch (gvc->job->output_lang) { - case GVRENDER_PLUGIN: - GD_drawing(g)->margin.x = GD_drawing(g)->margin.y = - gvc->job->render_features->default_margin; - break; - case GIF: - case PNG: - case JPEG: - case WBMP: - case GD: - case memGD: - case GD2: - case ISMAP: - case IMAP: - case CMAP: - case CMAPX: - case VRML: - case DIA: - case SVG: - case SVGZ: - case QEPDF: - GD_drawing(g)->margin.x = GD_drawing(g)->margin.y = - DEFAULT_EMBED_MARGIN; - break; - case POSTSCRIPT: - case PDF: - case HPGL: - case PCL: - case MIF: - case METAPOST: - case FIG: - case VTX: - case ATTRIBUTED_DOT: - case PLAIN: - case PLAIN_EXT: - case QPDF: - GD_drawing(g)->margin.x = GD_drawing(g)->margin.y = - DEFAULT_MARGIN; - break; - case CANONICAL_DOT: - break; - default: - if (gvc->job->output_lang >= QBM_FIRST - && gvc->job->output_lang < QBM_LAST) - GD_drawing(g)->margin.x = GD_drawing(g)->margin.y = - DEFAULT_EMBED_MARGIN; - break; - } + i = sscanf(p, "%lf,%lf", &xf, &yf); + if (i > 0) { + gvc->margin.x = gvc->margin.y = xf * POINTS_PER_INCH; + if (i > 1) + gvc->margin.y = yf * POINTS_PER_INCH; + gvc->graph_sets_margin = TRUE; + } + } +} + +static void graph_sets_page(GVC_t * gvc, graph_t * g) +{ + gvc->graph_sets_page = FALSE; + P2PF(GD_drawing(g)->page, gvc->page); + P2PF(GD_bb(g).LL,gvc->bb.LL); + P2PF(GD_bb(g).UR,gvc->bb.UR); + if ((GD_drawing(g)->page.x > 0) && (GD_drawing(g)->page.y > 0)) { + gvc->graph_sets_page = TRUE; } } @@ -118,75 +82,75 @@ static int chkOrder(graph_t * g) return 0; } -void dotneato_write_one(GVC_t * gvc, graph_t * g) +static int lang_sets_flags(gvrender_job_t * job, graph_t * g) { - gvrender_job_t *job = gvc->job; int flags; - gvc->g = g; -#ifndef DISABLE_CODEGENS - Output_file = job->output_file; - Output_lang = job->output_lang; -#endif - dotneato_set_margins(gvc, g); - emit_init(gvc, g); - if (NOT(gvrender_features(gvc) & GVRENDER_DOES_MULTIGRAPH_OUTPUT_FILES) -#ifndef DISABLE_CODEGENS -/* FIXME - bad hack until feaures supported in codegens */ - && job->codegen != &PS_CodeGen -#ifdef QUARTZ_RENDER - && job->codegen != &QPDF_CodeGen && job->codegen != &QEPDF_CodeGen -#endif -#endif - ) - emit_reset(gvc, g); /* FIXME - split into emit_init & page reset */ - switch (gvc->job->output_lang) { + switch (job->output_lang) { case GVRENDER_PLUGIN: - flags = chkOrder(g); - flags |= job->render_features->flags; - gvemit_graph(gvc, g, flags); + flags = chkOrder(g) | job->render_features->flags; break; case POSTSCRIPT: - case PDF: - case HPGL: - case PCL: - case MIF: - case PIC_format: - case GIF: - case PNG: - case JPEG: - case WBMP: - case GD: - case memGD: - case GD2: - case VRML: - case METAPOST: - case SVG: - case SVGZ: - case QPDF: - case QEPDF: - emit_graph(gvc, g, chkOrder(g)); + flags = chkOrder(g) | GVRENDER_DOES_MULTIGRAPH_OUTPUT_FILES; break; - case ISMAP: - case IMAP: - case CMAP: - case CMAPX: + case ISMAP: case IMAP: case CMAP: case CMAPX: /* output in breadth first graph walk order, but * with nodes edges and nested clusters before * clusters */ - emit_graph(gvc, g, EMIT_CLUSTERS_LAST); + flags = EMIT_CLUSTERS_LAST; break; case FIG: /* output color definition objects first */ - emit_graph(gvc, g, EMIT_COLORS); + flags = EMIT_COLORS; break; case VTX: /* output sorted, i.e. all nodes then all edges */ - emit_graph(gvc, g, EMIT_SORTED); + flags = EMIT_SORTED; break; case DIA: /* output in preorder traversal of the graph */ - emit_graph(gvc, g, EMIT_PREORDER); + flags = EMIT_PREORDER; + break; + case EXTENDED_DOT: case ATTRIBUTED_DOT: case CANONICAL_DOT: + case PLAIN: case PLAIN_EXT: + flags = 0; + break; + default: + flags = chkOrder(g); + break; + } + return flags; +} + +void dotneato_write_one(GVC_t * gvc, graph_t * g) +{ + gvrender_job_t *job = gvc->job; + int flags; + + gvc->g = g; +#ifndef DISABLE_CODEGENS + Output_file = job->output_file; + Output_lang = job->output_lang; +#endif + + graph_sets_margin(gvc, g); + graph_sets_page(gvc, g); + flags = lang_sets_flags(job, g); + emit_init(gvc, g); + + if (! (flags & GVRENDER_DOES_MULTIGRAPH_OUTPUT_FILES)) + emit_reset(gvc, g); /* FIXME - split into emit_init & page reset */ + + switch (gvc->job->output_lang) { + case GVRENDER_PLUGIN: + gvemit_graph(gvc, g, flags); + break; + case POSTSCRIPT: case PDF: case HPGL: case PCL: case MIF: + case PIC_format: case GIF: case PNG: case JPEG: case WBMP: + case GD: case memGD: case GD2: case VRML: case METAPOST: + case SVG: case SVGZ: case QPDF: case QEPDF: case ISMAP: + case IMAP: case CMAP: case CMAPX: case FIG: case VTX: case DIA: + emit_graph(gvc, g, flags); break; case EXTENDED_DOT: attach_attrs(g); @@ -203,20 +167,18 @@ void dotneato_write_one(GVC_t * gvc, graph_t * g) agwrite(g, gvc->job->output_file); break; case PLAIN: - /* attach_attrs(g); */ write_plain(gvc, gvc->job->output_file); break; case PLAIN_EXT: - /* attach_attrs(g); */ write_plain_ext(gvc, gvc->job->output_file); break; default: if (gvc->job->output_lang >= QBM_FIRST && gvc->job->output_lang < QBM_LAST) - emit_graph(gvc, g, chkOrder(g)); + emit_graph(gvc, g, flags); break; - } + fflush(gvc->job->output_file); #if 0 emit_deinit(gvc); diff --git a/lib/common/renderprocs.h b/lib/common/renderprocs.h index 49c0ff9c7..a6677e682 100644 --- a/lib/common/renderprocs.h +++ b/lib/common/renderprocs.h @@ -25,6 +25,7 @@ extern "C" { extern void add_box(path *, box); extern point add_points(point, point); + extern pointf add_pointfs(pointf, pointf); extern void arrow_flags(Agedge_t * e, int *sflag, int *eflag); extern void arrow_gen(GVC_t * gvc, point p, point u, double scale, int flag); @@ -43,10 +44,11 @@ extern "C" { boolean left_inside); extern shape_desc *bind_shape(char *name, node_t *); extern box boxof(int, int, int, int); + extern boolean box_overlap(box, box); + extern boolean boxf_overlap(boxf, boxf); extern void cat_libfile(FILE *, char **, char **); extern void clip_and_install(edge_t *, edge_t *, point *, int, splineInfo *); - extern int clust_in_layer(Agraph_t *); extern char *canontoken(char *str); extern void colorxlate(char *str, color_t * color, color_type_t target_type); @@ -69,7 +71,6 @@ extern "C" { extern void dotneato_terminate(GVC_t * gvc); extern void dotneato_write(GVC_t * gvc, graph_t *g); extern void dotneato_write_one(GVC_t * gvc, graph_t *g); - extern int edge_in_layer(Agraph_t *, Agedge_t *); extern double elapsed_sec(void); extern void enqueue(queue *, Agnode_t *); extern void enqueue_neighbors(queue *, Agnode_t *, int); @@ -113,7 +114,6 @@ extern "C" { extern point image_size(graph_t * g, char *shapefile); extern void init_ugraph(graph_t * g); extern point invflip_pt(point p, int rankdir); - extern int is_natural_number(char *); extern boolean isPolygon(node_t *); extern int late_attr(void *, char *); extern int late_bool(void *, Agsym_t *, int); @@ -137,11 +137,11 @@ extern "C" { extern void map_edge(Agedge_t *); extern point map_point(point); extern box mkbox(point, point); + extern boxf mkboxf(pointf, pointf); extern point neato_closest(splines * spl, point p); extern bezier *new_spline(edge_t * e, int sz); extern queue *new_queue(int); extern Agraph_t *next_input_graph(void); - extern int node_in_layer(Agraph_t *, node_t *); extern void osize_label(textlabel_t *, int *, int *, int *, int *); extern char **parse_style(char *s); extern void place_graph_label(Agraph_t *); @@ -152,12 +152,10 @@ extern "C" { extern char *ps_string(char *s); extern void rank(graph_t * g, int balance, int maxiter); extern void rec_attach_bb(Agraph_t *); - extern int rect_overlap(box, box); extern void routesplinesinit(void); extern point *routesplines(path *, int *); extern void routesplinesterm(void); extern char *safefile(char *shapefilename); - extern int selectedlayer(char *); extern void setup_graph(GVC_t * gvc, graph_t * g); extern shape_kind shapeOf(node_t *); extern void shape_clip(node_t * n, point curve[4], edge_t * e); @@ -188,6 +186,7 @@ extern "C" { # define extern __EXPORT__ #endif extern point sub_points(point, point); + extern pointf sub_pointfs(pointf, pointf); extern void toggle(int); extern int test_toggle(); diff --git a/lib/common/types.h b/lib/common/types.h index bc25342a6..b039ffed6 100644 --- a/lib/common/types.h +++ b/lib/common/types.h @@ -41,10 +41,22 @@ extern "C" { typedef struct htmllabel_t htmllabel_t; + typedef struct point { + int x, y; + } point; + typedef struct pointf { double x, y; } pointf; + typedef struct box { + point LL, UR; + } box; + + typedef struct boxf { + pointf LL, UR; + } boxf; + typedef struct inside_t { pointf *p; double *r; @@ -52,14 +64,6 @@ extern "C" { edge_t *e; } inside_t; - typedef struct point { - int x, y; - } point; - - typedef struct box { - point LL, UR; - } box; - typedef struct port { /* internal edge endpoint specification */ point p; /* aiming point */ double theta; /* slope in radians */ diff --git a/lib/common/utils.c b/lib/common/utils.c index 553acc3e3..f9782d67a 100644 --- a/lib/common/utils.c +++ b/lib/common/utils.c @@ -293,6 +293,27 @@ box mkbox(point p0, point p1) return rv; } +boxf mkboxf(pointf p0, pointf p1) +{ + boxf rv; + + if (p0.x < p1.x) { + rv.LL.x = p0.x; + rv.UR.x = p1.x; + } else { + rv.LL.x = p1.x; + rv.UR.x = p0.x; + } + if (p0.y < p1.y) { + rv.LL.y = p0.y; + rv.UR.y = p1.y; + } else { + rv.LL.y = p1.y; + rv.UR.y = p0.y; + } + return rv; +} + point add_points(point p0, point p1) { p0.x += p1.x; @@ -307,6 +328,20 @@ point sub_points(point p0, point p1) return p0; } +pointf add_pointfs(pointf p0, pointf p1) +{ + p0.x += p1.x; + p0.y += p1.y; + return p0; +} + +pointf sub_pointfs(pointf p0, pointf p1) +{ + p0.x -= p1.x; + p0.y -= p1.y; + return p0; +} + /* from Glassner's Graphics Gems */ #define W_DEGREE 5 @@ -542,7 +577,15 @@ void cat_libfile(FILE * ofp, char **arglib, char **stdlib) } } -int rect_overlap(box b0, box b1) +boolean box_overlap(box b0, box b1) +{ + if ((b0.UR.x < b1.LL.x) || (b1.UR.x < b0.LL.x) + || (b0.UR.y < b1.LL.y) || (b1.UR.y < b0.LL.y)) + return FALSE; + return TRUE; +} + +boolean boxf_overlap(boxf b0, boxf b1) { if ((b0.UR.x < b1.LL.x) || (b1.UR.x < b0.LL.x) || (b0.UR.y < b1.LL.y) || (b1.UR.y < b0.LL.y)) diff --git a/lib/fdpgen/fdp.h b/lib/fdpgen/fdp.h index 6fe596334..8c6f57c67 100644 --- a/lib/fdpgen/fdp.h +++ b/lib/fdpgen/fdp.h @@ -27,10 +27,6 @@ typedef enum { #define NDIM 2 -typedef struct { - pointf LL, UR; -} boxf; - typedef struct bport_s { edge_t *e; node_t *n; diff --git a/lib/gvc/gvc.h b/lib/gvc/gvc.h index 96467ac9f..1f2186310 100644 --- a/lib/gvc/gvc.h +++ b/lib/gvc/gvc.h @@ -78,14 +78,11 @@ extern "C" { extern void gvrender_begin_job(GVC_t * gvc, char **lib, double X, double Y, double Z, double x, double y, int dpi); extern void gvrender_end_job(GVC_t * gvc); - extern void gvrender_begin_graph(GVC_t * gvc, graph_t * g, box bb, - point pb); + extern void gvrender_begin_graph(GVC_t * gvc, graph_t * g); extern void gvrender_end_graph(GVC_t * gvc); - extern void gvrender_begin_page(GVC_t * gvc, point page, double scale, - int rot, point offset); + extern void gvrender_begin_page(GVC_t * gvc, double scale, int rot, point offset); extern void gvrender_end_page(GVC_t * gvc); - extern void gvrender_begin_layer(GVC_t * gvc, char *layerName, int n, - int nLayers); + extern void gvrender_begin_layer(GVC_t * gvc); extern void gvrender_end_layer(GVC_t * gvc); extern void gvrender_begin_cluster(GVC_t * gvc, graph_t * sg); extern void gvrender_end_cluster(GVC_t * gvc); diff --git a/lib/gvc/gvcint.h b/lib/gvc/gvcint.h index 6c487b7e1..042382ecf 100644 --- a/lib/gvc/gvcint.h +++ b/lib/gvc/gvcint.h @@ -53,8 +53,8 @@ extern "C" { #define GVRENDER_X11_EVENTS (1<<10) typedef struct { + double default_margin; /* points */ int flags; - int default_margin; int default_dpi; char **knowncolors; int sz_knowncolors; @@ -86,26 +86,24 @@ extern "C" { graph_t *g; /* parent graph */ int flags; /* emit_graph flags */ + pointf margin; /* job-specific margin */ + boxf pageBox; /* drawable region in device coords */ + /* basically width*height - margins */ + pointf pageBoxCentered; /* device page box for centering */ + unsigned int width; /* width in pixels */ unsigned int height; /* height in pixels */ int dpi; /* resolution pixels-per-inch */ int rot; /* rotation */ double zoom; /* viewport zoom factor */ pointf focus; /* viewport focus in graph units */ -// pointf pointer; /* pointer position in graph units */ -// boxf clip; /* clip region in graph units */ - +#if 0 + pointf pointer; /* pointer position in graph units */ +#endif + boxf clip; /* clip region in graph units */ + point offset; pointf compscale; /* composite device scale incl: scale, zoom, dpi, y_goes_down */ - /* gvrender_begin_page */ - point pagesArrayElem; /* 2D coord of current page - 0,0 based */ - int pagesElem; /* 1D index of current page - 0 based */ - point offset; - - /* gvrender_begin_layer() */ - int layer; - int nLayers; - boolean fit_mode, needs_refresh, click, active, has_grown; void *window; /* display-specific data for gvrender plugin */ @@ -153,19 +151,32 @@ extern "C" { char **lib; + pointf margin, page; + boxf bb; + boolean graph_sets_margin, graph_sets_page; + /* pagination */ - point pagesArraySize; /* 2D size of page array */ - point pagesArrayFirst; /* 2D starting corner in */ - point pagesArrayMajor; /* 2D major increment */ - point pagesArrayMinor; /* 2D minor increment */ - int pagesSize; /* 1D size of page array */ + point pagesArraySize; /* 2D size of page array */ + point pagesArrayFirst; /* 2D starting corner in */ + point pagesArrayMajor; /* 2D major increment */ + point pagesArrayMinor; /* 2D minor increment */ + point pagesArrayElem; /* 2D coord of current page - 0,0 based */ + int numPages; /* number of pages */ + int pageNum; /* current page - 1 based */ + pointf pageSize; /* page size in graph coords */ + boxf pageBox; /* page box in graph coords */ + + /* layers */ + char *layerDelims; /* delimiters in layer names */ + char *layers; /* null delimited list of layer names */ + char **layerIDs; /* array of layer names */ + int numLayers; /* number of layers */ + int layerNum; /* current layer - 1 based*/ /* gvrender_begin_graph() */ graph_t *g; - box bb; /* graph bounding box (what units???) */ point pb; /* page size - including margins (inches) */ - point margin; /* page margins (inches) */ gvstyle_t styles[MAXNEST]; /* style stack - reused by each job */ int SP; diff --git a/lib/gvc/gvplugin_render.h b/lib/gvc/gvplugin_render.h index f92dd3e1a..41ae11506 100644 --- a/lib/gvc/gvplugin_render.h +++ b/lib/gvc/gvplugin_render.h @@ -29,9 +29,10 @@ extern "C" { void (*end_job) (gvrender_job_t * job); void (*begin_graph) (gvrender_job_t * job, char *graphname); void (*end_graph) (gvrender_job_t * job); - void (*begin_page) (gvrender_job_t * job, char *pagename); - void (*end_page) (gvrender_job_t * job); - void (*begin_layer) (gvrender_job_t * job, char *layername); + void (*begin_page) (gvrender_job_t * job, char *pagename, point pagesArrayElem, int pageNum, int numPages); + void (*end_page) (gvrender_job_t * job, point pagesArrayElem, int pageNum, int numPages); + void (*begin_layer) (gvrender_job_t * job, char *layername, + int layerNum, int numLayers); void (*end_layer) (gvrender_job_t * job); void (*begin_cluster) (gvrender_job_t * job, char *clustername, long id); void (*end_cluster) (gvrender_job_t * job); diff --git a/lib/gvc/gvrender.c b/lib/gvc/gvrender.c index 44f1bc798..4117e0458 100644 --- a/lib/gvc/gvrender.c +++ b/lib/gvc/gvrender.c @@ -153,7 +153,7 @@ void gvrender_begin_job(GVC_t * gvc, char **lib, double X, double Y, double Z, d else { codegen_t *cg = job->codegen; - if (cg && cg->begin_job && job->pagesElem == 0) + if (cg && cg->begin_job && gvc->pageNum == 1) cg->begin_job(gvc->job->output_file, gvc->g, lib, gvc->user, gvc->info, gvc->pagesArraySize); } @@ -233,22 +233,27 @@ static void gvrender_resolve_color(gvrender_features_t * features, } } -void gvrender_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb) +void gvrender_begin_graph(GVC_t * gvc, graph_t * g) { gvrender_job_t *job = gvc->job; gvrender_engine_t *gvre = job->render_engine; char *str; + double sx, sy; gvc->g = g; - gvc->bb = bb; - gvc->pb = pb; if (gvre) { job->compscale.x = job->zoom * job->dpi / POINTS_PER_INCH; - job->compscale.y = - job->compscale.x * + job->compscale.y = job->compscale.x * ((job->render_features->flags & GVRENDER_Y_GOES_DOWN) ? -1.0 : 1.0); + sx = job->width / (job->zoom * 2.); + sy = job->height / (job->zoom * 2.); + job->clip.UR.x = job->focus.x + sx; + job->clip.UR.y = job->focus.y + sy; + job->clip.LL.x = job->focus.x - sx; + job->clip.LL.y = job->focus.y - sy; + /* render specific init */ if (gvre->begin_graph) gvre->begin_graph(job, g->name); @@ -276,9 +281,14 @@ void gvrender_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb) #ifndef DISABLE_CODEGENS else { codegen_t *cg = job->codegen; + box bb; + point pb; + + PF2P(gvc->bb.LL,bb.LL); + PF2P(gvc->bb.UR,bb.UR); if (cg && cg->begin_graph) - cg->begin_graph(gvc, g, bb, pb); + cg->begin_graph(gvc, g, bb, gvc->pb); } #endif } @@ -298,30 +308,26 @@ void gvrender_end_graph(GVC_t * gvc) cg->end_graph(); } #endif - gvc->bb = b0; - gvc->pb = p0; } -void gvrender_begin_page(GVC_t * gvc, point page, double scale, int rot, - point offset) +void gvrender_begin_page(GVC_t * gvc, double scale, int rot, point offset) { gvrender_job_t *job = gvc->job; gvrender_engine_t *gvre = job->render_engine; - job->pagesArrayElem = page; - job->pagesElem = page.x + page.y * gvc->pagesArraySize.x + 1; - // gvc->scale = scale; job->rot = rot; // gvc->offset = offset; if (gvre && gvre->begin_page) - gvre->begin_page(job, gvc->g->name); + gvre->begin_page(job, gvc->g->name, + gvc->pagesArrayElem, gvc->pageNum, gvc->numPages); + #ifndef DISABLE_CODEGENS else { codegen_t *cg = job->codegen; if (cg && cg->begin_page) - cg->begin_page(gvc->g, page, scale, rot, offset); + cg->begin_page(gvc->g, gvc->pagesArrayElem, scale, rot, offset); } #endif } @@ -332,7 +338,7 @@ void gvrender_end_page(GVC_t * gvc) gvrender_engine_t *gvre = job->render_engine; if (gvre && gvre->end_page) - gvre->end_page(job); + gvre->end_page(job, gvc->pagesArrayElem, gvc->pageNum, gvc->numPages); #ifndef DISABLE_CODEGENS else { codegen_t *cg = job->codegen; @@ -343,22 +349,19 @@ void gvrender_end_page(GVC_t * gvc) #endif } -void gvrender_begin_layer(GVC_t * gvc, char *layername, int layer, - int nLayers) +void gvrender_begin_layer(GVC_t * gvc) { gvrender_job_t *job = gvc->job; gvrender_engine_t *gvre = job->render_engine; - job->layer = layer; - job->nLayers = nLayers; if (gvre && gvre->begin_layer) - gvre->begin_layer(job, layername); + gvre->begin_layer(job, gvc->layerIDs[gvc->layerNum], gvc->layerNum, gvc->numLayers); #ifndef DISABLE_CODEGENS else { codegen_t *cg = job->codegen; if (cg && cg->begin_layer) - cg->begin_layer(layername, layer, nLayers); + cg->begin_layer(gvc->layerIDs[gvc->layerNum], gvc->layerNum, gvc->numLayers); } #endif } @@ -378,8 +381,6 @@ void gvrender_end_layer(GVC_t * gvc) cg->end_layer(); } #endif - job->layer = 0; - job->nLayers = 0; } void gvrender_begin_cluster(GVC_t * gvc, graph_t * sg) diff --git a/lib/neatogen/constraint.c b/lib/neatogen/constraint.c index b7498a285..885aa6e08 100644 --- a/lib/neatogen/constraint.c +++ b/lib/neatogen/constraint.c @@ -443,10 +443,6 @@ void cAdjust(graph_t * g, int xy) free(nlist); } -typedef struct { - pointf LL; - pointf UR; -} boxf; typedef struct { pointf pos; /* position for sorting */ boxf bb;