From: erg Date: Tue, 15 Feb 2011 17:45:08 +0000 (+0000) Subject: Update patchwork code incorporating Yifan's treemap function. X-Git-Tag: LAST_LIBGRAPH~32^2~1033 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=05f9f7eb58b98c4de9af755aa35a449ee095f920;p=graphviz Update patchwork code incorporating Yifan's treemap function. --- diff --git a/lib/patchwork/Makefile.am b/lib/patchwork/Makefile.am index 3010b76f9..b936eda67 100644 --- a/lib/patchwork/Makefile.am +++ b/lib/patchwork/Makefile.am @@ -19,9 +19,9 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/lib/$(GRAPH) \ -I$(top_srcdir)/lib/cdt -noinst_HEADERS = patchwork.h +noinst_HEADERS = patchwork.h tree_map.h noinst_LTLIBRARIES = libpatchwork_C.la -libpatchwork_C_la_SOURCES = patchwork.c patchworkinit.c +libpatchwork_C_la_SOURCES = patchwork.c patchworkinit.c tree_map.c EXTRA_DIST = Makefile.old gvpatchwork.vcproj diff --git a/lib/patchwork/patchwork.c b/lib/patchwork/patchwork.c index 4cded4b09..ebcd0572b 100644 --- a/lib/patchwork/patchwork.c +++ b/lib/patchwork/patchwork.c @@ -1,262 +1,238 @@ +/* $Id$Revision: */ +/* vim:set shiftwidth=4 ts=8: */ + +/************************************************************************* + * Copyright (c) 2011 AT&T Intellectual Property + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: See CVS logs. Details at http://www.graphviz.org/ + *************************************************************************/ + #include #include #include +#include #include "render.h" -extern void patchwork_init_graph(graph_t * g); - -#ifndef HAVE_DRAND48 -extern double drand48(void); -#endif - -typedef boxf rect_t; - -typedef struct treenode_t { - double area; - rect_t r; - struct treenode_t *leftchild, *rightsib; - union {Agraph_t *subg; Agnode_t *n;} u; - int kind; -} treenode_t; - -#define BT 101 -#define LR 202 - -typedef struct rlist_s { - treenode_t *elt; - int n, extent; - double sum; -} rlist_t; - -static treenode_t *newtreenode(treenode_t **first, treenode_t **prev) -{ - treenode_t *p; - p = NEW(treenode_t); - if (!*first) *first = p; - if (*prev) (*prev)->rightsib = p; - *prev = p; - return p; -} - -/* return list of treenodes */ -static treenode_t *treebuilder(Agraph_t *g) +typedef struct treenode_t treenode_t; +struct treenode_t { + double area; + rectangle r; + treenode_t *leftchild, *rightsib; + union { + Agraph_t *subg; + Agnode_t *n; + } u; + int kind; + int n_children; +}; + +/* mkTreeNode: + */ +static treenode_t* mkTreeNode (Agnode_t* n, attrsym_t* ap) { - int i; - treenode_t *first = 0; - treenode_t *prev = 0; - treenode_t *p; - Agraph_t *subg; - Agnode_t *n; + treenode_t *p = NEW(treenode_t); - for (i = 1; i <= GD_n_cluster(g); i++) { - subg = GD_clust(g)[i]; - if (agnnodes(subg) == 0) continue; - p = newtreenode(&first,&prev); -#ifndef WITH_CGRAPH - p->kind = AGGRAPH; -#else - p->kind = AGRAPH; -#endif - p->u.subg = subg; - p->leftchild = treebuilder(subg); - } + p->area = late_double (n, ap, 1.0, 0); + if (p->area == 0) p->area = 1.0; + p->kind = AGNODE; + p->u.n = n; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - char *val; - if (SPARENT(n)) continue; - p = newtreenode(&first,&prev); - val = agget(n,"area"); - if (val) p->area = atof(val); - if (p->area <= 0.0) p->area = 1.0; - p->kind = AGNODE; - p->u.n = n; - SPARENT(n) = g; - } - return first; + return p; } -/* get recursive area requirements */ -static double sizeit(treenode_t *tree) +#define INSERT(cp) if(!first) first=cp; if(prev) prev->rightsib=cp; prev=cp; + +/* mkTree: + * Recursively build tree from graph + * Pre-condition: agnnodes(g) != 0 + */ +static treenode_t *mkTree (Agraph_t * g, attrsym_t* ap) { - treenode_t *p; - double mysize = 0.0; + treenode_t *p = NEW(treenode_t); + Agraph_t *subg; + Agnode_t *n; + treenode_t *cp; + treenode_t *first = 0; + treenode_t *prev = 0; + int i, n_children = 0; + double area = 0; + + p->kind = AGRAPH; + p->u.subg = g; + + for (i = 1; i <= GD_n_cluster(g); i++) { + subg = GD_clust(g)[i]; + if (agnnodes(subg) == 0) + continue; + cp = mkTree (subg, ap); + n_children++; + area += cp->area; + INSERT(cp); + } - if (tree->leftchild) { - for (p = tree->leftchild; p; p = p->rightsib) mysize += sizeit(p); - tree->area = mysize; - } - return tree->area; -} + for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + if (SPARENT(n)) + continue; + cp = mkTreeNode (n, ap); + n_children++; + area += cp->area; + INSERT(cp); + SPARENT(n) = g; + } -static rect_t mkrectangle(double x0, double y0, double x1, double y1) -{ - rect_t rv; - rv.LL.x = x0; rv.LL.y = y0; rv.UR.x = x1; rv.UR.y = y1; - return rv; -} + p->n_children = n_children; + p->area = area; + p->leftchild = first; -static double weight(treenode_t *tree, treenode_t *split) -{ - double rv = 0.0; - while (tree && (tree!=split)) {rv = rv + tree->area; tree = tree->rightsib;} - return rv; + return p; } -static void layout(treenode_t *tree, treenode_t *split, rect_t r) +static int nodecmp (treenode_t** p0, treenode_t** p1) { - double size, halfsize, w1, tmp, width, height; - rect_t r1,r2; - treenode_t *p; - - if (!tree) return; - if (!tree->rightsib || (tree->rightsib==split)) {tree->r = r; layout(tree->leftchild,0,r); return;} - size = weight(tree,split); - halfsize = size / 2.0; - w1 = 0; tmp = 0; - - for (p = tree; p && (p != split); p = p->rightsib) { - tmp = w1 + p->area; - if (abs(halfsize - tmp) > abs(halfsize- w1)) - break; - w1 = tmp; - } + double diff = (*p0)->area - (*p1)->area; - width = r.UR.x - r.LL.x; - height = r.UR.y - r.LL.y; - if (width > height) { - r1 = mkrectangle(r.LL.x,r.LL.y,r.LL.x + width * w1 / size, r.UR.y); - r2 = mkrectangle(r1.UR.x,r.LL.y,r.UR.x,r.UR.y); - } - else { - /* this was bottom to top - but we want top to bottom layout - r1 = mkrectangle(r.LL.x,r.LL.y,r.UR.x,r.LL.y + height * w1 / size); - r2 = mkrectangle(r.LL.x,r1.UR.y,r.UR.x,r.UR.y); - */ - r1 = mkrectangle(r.LL.x,r.UR.y - height * w1 / size,r.UR.x,r.UR.y); - r2 = mkrectangle(r.LL.x,r.LL.y,r.UR.x,r1.LL.y); - } - layout(tree,p,r1); - layout(p,split,r2); + if (diff < 0) return 1; + else if (diff > 0) return -1; + else return 0; } -static void printer(treenode_t *tree) +static void layoutTree(treenode_t * tree) { - static int onetime = 1; - treenode_t *p; + rectangle *recs; + treenode_t** nodes; + double* areas_sorted; + int i, nc; + treenode_t* cp; + + if (tree->kind == AGNODE) return; + + nc = tree->n_children; + nodes = N_NEW(nc, treenode_t*); + cp = tree->leftchild; + for (i = 0; i < nc; i++) { + nodes[i] = cp; + cp = cp->rightsib; + } - if (onetime) { fprintf(stderr,"%%!PS\n"); onetime=0;} - fprintf(stderr,"newpath %.3lf %.3lf moveto %.3lf %.3lf lineto %.3lf %.3lf lineto %.3lf %.3lf lineto closepath \n", - tree->r.LL.x,tree->r.LL.y, - tree->r.UR.x,tree->r.LL.y, - tree->r.UR.x,tree->r.UR.y, - tree->r.LL.x,tree->r.UR.y); - if (tree->leftchild) { - fprintf(stderr,"stroke \n"); - for (p = tree->leftchild; p; p = p->rightsib) printer(p); - } - else { - fprintf(stderr,"gsave %.3lf 1.0 1.0 sethsbcolor fill grestore stroke\n",drand48()); - } -} + qsort (nodes, nc, sizeof(treenode_t*), (qsort_cmpf)nodecmp); + areas_sorted = N_NEW(nc,double); + for (i = 0; i < nc; i++) { + areas_sorted[i] = nodes[i]->area; + } + recs = tree_map(nc, areas_sorted, tree->r); + if (Verbose) + fprintf (stderr, "rec %f %f %f %f\n", tree->r.x[0], tree->r.x[1], tree->r.size[0], tree->r.size[1]); + for (i = 0; i < nc; i++) { + nodes[i]->r = recs[i]; + if (Verbose) + fprintf (stderr, "%f - %f %f %f %f = %f (%f %f %f %f)\n", areas_sorted[i], + recs[i].x[0]-recs[i].size[0]*0.5, recs[i].x[1]-recs[i].size[1]*0.5, + recs[i].x[0]+recs[i].size[0]*0.5, recs[i].x[1]+recs[i].size[1]*0.5, recs[i].size[0]*recs[i].size[1], + recs[i].x[0], recs[i].x[1], recs[i].size[0], recs[i].size[1]); -static void finishNode (node_t* n) -{ - char* str = strdup_and_subst_obj(NODENAME_ESC, (void*)n); - ND_shape(n) = bind_shape("box", n); - ND_label(n) = make_label((void*)n, str, LT_NONE, - late_double(n, N_fontsize, DEFAULT_FONTSIZE, MIN_FONTSIZE), - late_nnstring(n, N_fontname, DEFAULT_FONTNAME), - late_nnstring(n, N_fontcolor, DEFAULT_COLOR)); - ND_shape(n)->fns->initfn(n); + } + free (nodes); + free (areas_sorted); + free (recs); + + cp = tree->leftchild; + for (i = 0; i < nc; i++) { + if (cp->kind == AGRAPH) + layoutTree (cp); + cp = cp->rightsib; + } } -static rect_t walker(treenode_t *tree) +static void finishNode(node_t * n) { - treenode_t *p; - Agnode_t *n; - pointf center; - rect_t r, rr; - - switch(tree->kind) { + char buf [40]; + if (N_fontsize) { #ifndef WITH_CGRAPH - case AGGRAPH: + char* str = agxget(n, N_fontsize->index); #else - case AGRAPH: + char* str = agxget(n, N_fontsize); #endif - break; - case AGNODE: - rr = tree->r; - center.x = (tree->r.UR.x + tree->r.LL.x) / 2.0; - center.y = (tree->r.UR.y + tree->r.LL.y) / 2.0; + if (*str == '\0') { + sprintf (buf, "%.03f", ND_ht(n)*0.7); +#ifndef WITH_CGRAPH + agxset(n, N_fontsize->index, buf); +#else /* WITH_CGRAPH */ + agxset(n, N_fontsize, buf); +#endif /* WITH_CGRAPH */ + } + } + common_init_node (n); +} - n = tree->u.n; - ND_coord(n) = center; - ND_height(n) = PS2INCH(tree->r.UR.y - tree->r.LL.y); - ND_width(n) = PS2INCH(tree->r.UR.x - tree->r.LL.x); - gv_nodesize(n,GD_flip(agraphof(n))); - finishNode (n); - /*fprintf(stderr,"%s coord %.5g %.5g ht %d width %d\n", - agnameof(n), ND_coord(n).x, ND_coord(n).y, ND_ht(n), - ND_rw(n)+ND_lw(n));*/ - break; - default: abort(); +static void walkTree(treenode_t * tree) +{ + treenode_t *p; + Agnode_t *n; + pointf center; + rectangle rr; + boxf r; + double x0, y0, wd, ht; + + if (tree->kind == AGRAPH) { + for (p = tree->leftchild; p; p = p->rightsib) + walkTree (p); + x0 = tree->r.x[0]; + y0 = tree->r.x[1]; + wd = tree->r.size[0]; + ht = tree->r.size[1]; + r.LL.x = x0 - wd/2.0; + r.LL.y = y0 - ht/2.0; + r.UR.x = r.LL.x + wd; + r.UR.y = r.LL.y + ht; + GD_bb(tree->u.subg) = r; } - if ((p = tree->leftchild)) { - rr = walker (p); - p = p->rightsib; - for (; p; p = p->rightsib) { - r = walker(p); - EXPANDBB(rr,r); - } - rr.LL.x -= 2./72.; - rr.LL.y -= 2./72.; - rr.UR.x += 2./72.; - rr.UR.y += 2./72.; - GD_bb(tree->u.subg) = rr; + else { + rr = tree->r; + center.x = rr.x[0]; + center.y = rr.x[1]; + + n = tree->u.n; + ND_coord(n) = center; + ND_width(n) = PS2INCH(rr.size[0]); + ND_height(n) = PS2INCH(rr.size[1]); + gv_nodesize(n, GD_flip(agraphof(n))); + finishNode(n); + if (Verbose) + fprintf(stderr,"%s coord %.5g %.5g ht %f width %f\n", + agnameof(n), ND_coord(n).x, ND_coord(n).y, ND_ht(n), ND_xsize(n)); } - return rr; } -#ifdef PWDRIVER -int main() +/* freeTree: + */ +static void freeTree (treenode_t* tp) { - static treenode_t root; - rect_t r = {{0.0, 0.0}, {100.0, 100.0}}; - Agraph_t *g; + treenode_t* cp = tp->leftchild; + int i, nc = tp->n_children; - aginit(); - g = agread(stdin); -#ifndef WITH_CGRAPH - root.kind = AGGRAPH; -#else - root.kind = AGRAPH; -#endif - root.leftchild = treebuilder(g); - sizeit(&root); - /*layouter(&root,LR,r);*/ - printer(&root); - return 0; + for (i = 0; i < nc; i++) { + freeTree (cp); + cp = cp->rightsib; + } + free (tp); } -#endif -void patchwork_layout(Agraph_t *g) +/* patchworkLayout: + */ +void patchworkLayout(Agraph_t * g) { - static treenode_t root; - rect_t r = {{0.0, 0.0}, {100.0, 100.0}}; - patchwork_init_graph(g); -#ifndef WITH_CGRAPH - root.kind = AGGRAPH; -#else - root.kind = AGRAPH; -#endif - root.leftchild = treebuilder(g); - root.u.subg = g; - sizeit(&root); - layout(&root,0,r); - /* printer(&root); */ - walker(&root); - /* compute_bb(g); */ - /* fprintf(stderr,"bb %d %d %d %d\n", */ - /* GD_bb(g).LL.x, GD_bb(g).LL.y, GD_bb(g).UR.x, GD_bb(g).UR.y); */ - dotneato_postprocess(g); + treenode_t* root; + attrsym_t * ap = agfindnodeattr(g, "size"); + double total; + + root = mkTree (g,ap); + total = root->area; + root->r = rectangle_new(0, 0, sqrt(total + 0.1), sqrt(total + 0.1)); + layoutTree(root); + walkTree(root); + freeTree (root); } diff --git a/lib/patchwork/patchwork.h b/lib/patchwork/patchwork.h index 6a66e76ba..ee3df7a97 100644 --- a/lib/patchwork/patchwork.h +++ b/lib/patchwork/patchwork.h @@ -1,3 +1,4 @@ +/* $Id$Revision: */ /* vim:set shiftwidth=4 ts=8: */ /************************************************************************* @@ -21,27 +22,15 @@ extern "C" { #endif typedef struct { - int nStepsToLeaf; - int subtreeSize; - int nChildren; - int nStepsToCenter; graph_t *parent; - double span; - double theta; } rdata; #define RDATA(n) ((rdata*)(ND_alg(n))) -#define SLEAF(n) (RDATA(n)->nStepsToLeaf) -#define STSIZE(n) (RDATA(n)->subtreeSize) -#define NCHILD(n) (RDATA(n)->nChildren) -#define SCENTER(n) (RDATA(n)->nStepsToCenter) #define SPARENT(n) (RDATA(n)->parent) -#define SPAN(n) (RDATA(n)->span) -#define THETA(n) (RDATA(n)->theta) -extern void patchwork_init_graph(graph_t * g); -extern void twopi_layout(Agraph_t * g); -extern void twopi_cleanup(Agraph_t * g); +extern void patchwork_layout(Agraph_t * g); +extern void patchwork_cleanup(Agraph_t * g); +extern void patchworkLayout(Agraph_t *g); #ifdef __cplusplus } diff --git a/lib/patchwork/patchworkinit.c b/lib/patchwork/patchworkinit.c index 443555f58..8dc29871b 100644 --- a/lib/patchwork/patchworkinit.c +++ b/lib/patchwork/patchworkinit.c @@ -1,3 +1,4 @@ +/* $Id$Revision: */ /* vim:set shiftwidth=4 ts=8: */ /************************************************************************* @@ -10,7 +11,6 @@ * Contributors: See CVS logs. Details at http://www.graphviz.org/ *************************************************************************/ - #include "patchwork.h" #include "adjust.h" #include "pack.h" @@ -108,16 +108,12 @@ mkClusters (graph_t * g, clist_t* pclist, graph_t* parent) static void patchwork_init_node(node_t * n) { agset(n,"shape","box"); - common_init_node_opt(n,FALSE); - /* gv_nodesize(n, GD_flip(agraphof(n))); */ - /* ND_pos(n) = ALLOC(GD_ndim(agraphof(n)), 0, double); */ + /* common_init_node_opt(n,FALSE); */ } static void patchwork_init_edge(edge_t * e) { /* common_init_edge(e); */ - - ED_factor(e) = late_double(e, E_weight, 1.0, 0.0); } static void patchwork_init_node_edge(graph_t * g) @@ -140,7 +136,7 @@ static void patchwork_init_node_edge(graph_t * g) } } -void patchwork_init_graph(graph_t * g) +static void patchwork_init_graph(graph_t * g) { #ifndef WITH_CGRAPH N_shape = agnodeattr(g, "shape", "box"); @@ -154,6 +150,21 @@ void patchwork_init_graph(graph_t * g) patchwork_init_node_edge(g); } +/* patchwork_layout: + * The current version makes no use of edges, neither for a notion of connectivity + * nor during drawing. + */ +void patchwork_layout(Agraph_t *g) +{ + if (agnnodes(g) == 0) return; + + patchwork_init_graph(g); + + patchworkLayout (g); + + dotneato_postprocess(g); +} + static void patchwork_cleanup_graph(graph_t * g) { free(GD_neato_nlist(g)); @@ -170,7 +181,10 @@ void patchwork_cleanup(graph_t * g) node_t *n; edge_t *e; - for (n = agfstnode(g); n; n = agnxtnode(g, n)) { + n = agfstnode(g); + if (!n) return; + free (ND_alg(n)); + for (; n; n = agnxtnode(g, n)) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { gv_cleanup_edge(e); } diff --git a/lib/patchwork/tree_map.c b/lib/patchwork/tree_map.c new file mode 100644 index 000000000..baa2073d2 --- /dev/null +++ b/lib/patchwork/tree_map.c @@ -0,0 +1,127 @@ +/* $Id$Revision: */ +/* vim:set shiftwidth=4 ts=8: */ + +/************************************************************************* + * Copyright (c) 2011 AT&T Intellectual Property + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: See CVS logs. Details at http://www.graphviz.org/ + *************************************************************************/ + +#include "render.h" +#include "tree_map.h" + +static void squarify(int n, real *area, rectangle *recs, int nadded, real maxarea, real minarea, real totalarea, + real asp, rectangle fillrec){ + /* add a list of area in fillrec using squarified treemap alg. + n: number of items to add + area: area of these items, Sum to 1 (?). + nadded: number of items already added + maxarea: maxarea of already added items + minarea: min areas of already added items + asp: current worst aspect ratio of the already added items so far + fillrec: the rectangle to be filled in. + */ + real w = MIN(fillrec.size[0], fillrec.size[1]); + int i; + + if (n <= 0) return; + + if (Verbose) { + fprintf(stderr, "trying to add to rect {%f +/- %f, %f +/- %f}\n",fillrec.x[0], fillrec.size[0], fillrec.x[1], fillrec.size[1]); + fprintf(stderr, "total added so far = %d\n", nadded); + } + + if (nadded == 0){ + nadded = 1; + maxarea = minarea = area[0]; + asp = MAX(area[0]/(w*w), (w*w)/area[0]); + totalarea = area[0]; + squarify(n, area, recs, nadded, maxarea, minarea, totalarea, asp, fillrec); + } else { + real newmaxarea, newminarea, s, h, maxw, minw, newasp, hh, ww, xx, yy; + if (nadded < n){ + newmaxarea = MAX(maxarea, area[nadded]); + newminarea = MIN(minarea, area[nadded]); + s = totalarea + area[nadded]; + h = s/w; + maxw = newmaxarea/h; + minw = newminarea/h; + newasp = MAX(h/minw, maxw/h);/* same as MAX{s^2/(w^2*newminarea), (w^2*newmaxarea)/(s^2)}*/ + } + if (nadded < n && newasp <= asp){/* aspectio improved, keep adding */ + squarify(n, area, recs, ++nadded, newmaxarea, newminarea, s, newasp, fillrec); + } else { + /* aspectio worsen if add another area, fixed the already added recs */ + if (Verbose) fprintf(stderr,"adding %d items, total area = %f, w = %f, area/w=%f\n",nadded, totalarea, w, totalarea/w); + if (w == fillrec.size[0]){/* tall rec. fix the items along x direction, left to right, at top*/ + hh = totalarea/w; + xx = fillrec.x[0] - fillrec.size[0]/2; + for (i = 0; i < nadded; i++){ + recs[i].size[1] = hh; + ww = area[i]/hh; + recs[i].size[0] = ww; + recs[i].x[1] = fillrec.x[1] + 0.5*(fillrec.size[1]) - hh/2; + recs[i].x[0] = xx + ww/2; + xx += ww; + } + fillrec.x[1] -= hh/2;/* the new empty space is below the filled space */ + fillrec.size[1] -= hh; + } else {/* short rec. fix along y top to bot, at left*/ + ww = totalarea/w; + yy = fillrec.x[1] + fillrec.size[1]/2; + for (i = 0; i < nadded; i++){ + recs[i].size[0] = ww; + hh = area[i]/ww; + recs[i].size[1] = hh; + recs[i].x[0] = fillrec.x[0] - 0.5*(fillrec.size[0]) + ww/2; + recs[i].x[1] = yy - hh/2; + yy -= hh; + } + fillrec.x[0] += ww/2;/* the new empty space is right of the filled space */ + fillrec.size[0] -= ww; + } + squarify(n - nadded, area + nadded, recs + nadded, 0, 0., 0., 0., 1., fillrec); + } + + } +} + +/* tree_map: + * Perform a squarified treemap layout on a single level. + * n - number of rectangles + * area - area of rectangles + * fillred - rectangle to be filled + * return array of rectangles + */ +rectangle* tree_map(int n, real *area, rectangle fillrec){ + /* fill a rectangle rec with n items, each item i has area[i] area. */ + rectangle *recs; + int i; + real total = 0, minarea = 1., maxarea = 0., asp = 1, totalarea = 0; + int nadded = 0; + + for (i = 0; i < n; i++) total += area[i]; + /* make sure there is enough area */ + if (total > fillrec.size[0] * fillrec.size[1] + 0.001) + return NULL; + + recs = N_NEW(n,rectangle); + squarify(n, area, recs, nadded, maxarea, minarea, totalarea, asp, fillrec); + return recs; +} + +/* rectangle_new: + * Create and initialize a new rectangle structure + */ +rectangle rectangle_new(real x, real y, real width, real height){ + rectangle r; + r.x[0] = x; + r.x[1] = y; + r.size[0] = width; + r.size[1] = height; + return r; +} diff --git a/lib/patchwork/tree_map.h b/lib/patchwork/tree_map.h new file mode 100644 index 000000000..12bc90416 --- /dev/null +++ b/lib/patchwork/tree_map.h @@ -0,0 +1,28 @@ +/* $Id$Revision: */ +/* vim:set shiftwidth=4 ts=8: */ + +/************************************************************************* + * Copyright (c) 2011 AT&T Intellectual Property + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: See CVS logs. Details at http://www.graphviz.org/ + *************************************************************************/ + +#ifndef TREE_MAP_H +#define TREE_MAP_H + +#include + +typedef struct rectangle_struct { + real x[2];/* center */ + real size[2]; /* total width/height*/ +} rectangle; + +extern rectangle* tree_map(int n, real *area, rectangle fillrec); + +extern rectangle rectangle_new(real x, real y, real width, real height); + +#endif