]> granicus.if.org Git - graphviz/commitdiff
adding lib/patchwork - for Stephen
authorellson <devnull@localhost>
Thu, 10 Jul 2008 21:32:12 +0000 (21:32 +0000)
committerellson <devnull@localhost>
Thu, 10 Jul 2008 21:32:12 +0000 (21:32 +0000)
lib/patchwork/Makefile.am [new file with mode: 0644]
lib/patchwork/Makefile.old [new file with mode: 0644]
lib/patchwork/patchwork.c [new file with mode: 0644]
lib/patchwork/patchwork.h [new file with mode: 0644]
lib/patchwork/patchworkinit.c [new file with mode: 0644]

diff --git a/lib/patchwork/Makefile.am b/lib/patchwork/Makefile.am
new file mode 100644 (file)
index 0000000..c883cd8
--- /dev/null
@@ -0,0 +1,19 @@
+# $Id$ $Revision$
+## Process this file with automake to produce Makefile.in
+
+AM_CPPFLAGS = \
+        -I$(top_srcdir) \
+        -I$(top_srcdir)/lib/common \
+       -I$(top_srcdir)/lib/gvc \
+       -I$(top_srcdir)/lib/neatogen \
+       -I$(top_srcdir)/lib/pack \
+       -I$(top_srcdir)/lib/pathplan \
+       -I$(top_srcdir)/lib/graph \
+       -I$(top_srcdir)/lib/cdt
+
+noinst_HEADERS = patchwork.h
+noinst_LTLIBRARIES = libpatchwork_C.la
+
+libpatchwork_C_la_SOURCES = patchwork.c patchworkinit.c
+
+EXTRA_DIST = Makefile.old
diff --git a/lib/patchwork/Makefile.old b/lib/patchwork/Makefile.old
new file mode 100644 (file)
index 0000000..26d332b
--- /dev/null
@@ -0,0 +1,37 @@
+all:   libtwopigen.a
+ROOT=../..
+include $(ROOT)/Config.mk
+include $(ROOT)/makearch/$(ARCH)
+
+INCS = -I. -I$(ROOT) \
+       -I../common \
+       -I../neatogen \
+       -I../pack \
+       -I../gvc \
+       -I../pathplan \
+       -I../graph \
+       -I../cdt \
+       -I../gd
+
+DEFINES = -DHAVE_CONFIG_H
+
+OBJS = twopiinit.o circle.o 
+
+HFILES = circle.h 
+
+libtwopigen.a : $(OBJS)
+       $(RM) libtwopigen.a
+       $(AR) cr libtwopigen.a $(OBJS)
+       $(RANLIB) libtwopigen.a
+
+$(OBJS) : $(HFILES) ../common/types.h
+
+install: libtwopigen.a
+       $(MKPATH) $(LIBDIR)
+       $(INSTALL) libtwopigen.a $(LIBDIR)
+
+clean:
+       $(RM) *.o core
+
+distclean: clean
+       $(RM) *.a twopi lib*.so.*
diff --git a/lib/patchwork/patchwork.c b/lib/patchwork/patchwork.c
new file mode 100644 (file)
index 0000000..927947b
--- /dev/null
@@ -0,0 +1,207 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "render.h"
+
+typedef struct rect_t {pointf ll; pointf ur;} 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
+
+static treenode_t *newtreenode(treenode_t **first, treenode_t **prev)
+{
+       treenode_t *p;
+       p = malloc(sizeof(treenode_t));
+       p->leftchild = p->rightsib = 0;
+       p->area = 0.0;
+       if (!*first) *first = p;
+       if (*prev) (*prev)->rightsib = p;
+       *prev = p;
+       return p;
+}
+
+/* return list of treenodes */
+static treenode_t *treebuilder(Agraph_t *g)
+{
+       int                     i;
+       treenode_t      *first = 0;
+       treenode_t      *prev = 0;
+       treenode_t      *p;
+       Agraph_t        *subg;
+       Agnode_t        *n;
+
+       for (i = 1; i <= GD_n_cluster(g); i++) {
+               subg = GD_clust(g)[i];
+               if (agnnodes(subg) == 0) continue;
+               p = newtreenode(&first,&prev);
+               p->kind = AGRAPH;
+               p->u.subg = subg;
+               p->leftchild = treebuilder(subg);
+       }
+
+       for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
+               char *val;
+               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;
+       }
+       return first;
+}
+
+/* get recursive area requirements */
+static double sizeit(treenode_t *tree)
+{
+       treenode_t      *p;
+       double          mysize = 0.0;
+
+       if (tree->leftchild) {
+               for (p = tree->leftchild; p; p = p->rightsib) mysize += sizeit(p);
+               tree->area = mysize;
+       }
+       return tree->area;
+}
+
+/* normal layout */
+static void layouter(treenode_t *tree, int dir, rect_t r)
+{
+       double  delta;
+       pointf  ref;
+       rect_t  r0;
+       treenode_t      *p;
+
+       tree->r = r;
+       if (dir == BT) delta = (r.ur.y - r.ll.y) / tree->area;
+       else if (dir == LR) delta = (r.ur.x - r.ll.x) / tree->area;
+       else abort();
+       ref = r.ll;
+       for (p = tree->leftchild; p; p = p->rightsib) {
+               r0.ll = ref;
+               if (dir == BT) {
+                       r0.ur.x = r.ur.x;
+                       r0.ur.y = ref.y + p->area * delta;
+               }
+               else {
+                       r0.ur.x = ref.x + p->area * delta;
+                       r0.ur.y = r.ur.y;
+               }
+               layouter(p,(dir == BT? LR : BT),r0);
+               if (dir == BT) ref.y = r0.ur.y;
+               else ref.x = r0.ur.x;
+       }
+}
+
+/* squarified layout */
+static double aspect(rect_t r) { return (r.ur.y - r.ll.y)/(r.ur.x - r.ll.x); }
+
+static void sqlayouter(treenode_t *list, int dir, rect_t r, double total)
+{
+       double frac = list->area / total;
+       rect_t s = r;
+       if (dir == BT) s.ur.y = s.ll.y +  frac * (r.ur.y - r.ll.y);
+       else s.ur.x = s.ll.x + frac * (r.ur.x - r.ll.x);
+       list->r = s;
+
+       if (list->leftchild) {
+               if (aspect(r) > 1) sqlayouter(list->leftchild, BT, r, list->area);
+               else sqlayouter(list->leftchild, LR,r, list->area);
+       }
+
+       if (list->rightsib) {
+               total = total - list->area;
+               if (dir == BT) r.ll.y = s.ur.y;
+               else r.ll.x = s.ur.x;
+               if (aspect(r) > 1) sqlayouter(list->rightsib, BT, r, total);
+               else sqlayouter(list->rightsib, LR, r, total);
+       }
+}
+
+static void printer(treenode_t *tree)
+{
+       static int onetime = 1;
+       treenode_t      *p;
+
+       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());
+       }
+}
+
+static void walker(treenode_t *tree)
+{
+       treenode_t      *p;
+       Agnode_t        *n;
+       point           center;
+
+       switch(tree->kind) {
+               case AGRAPH:
+                       break;
+               case AGNODE:
+                       center.x = (tree->r.ur.x + tree->r.ll.x) / 2.0;
+                       center.y = (tree->r.ur.y + tree->r.ll.y) / 2.0;
+
+                       n = tree->u.n;
+                       ND_coord_i(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(n->graph));
+                       /*fprintf(stderr,"%s coord %d %d ht %d width %d\n",
+                               n->name, ND_coord_i(n).x, ND_coord_i(n).y, ND_ht_i(n),
+                               ND_rw_i(n)+ND_lw_i(n));*/
+                       break;
+               default: abort();
+       }
+       if (tree->leftchild)
+               for (p = tree->leftchild; p; p = p->rightsib) walker(p);
+}
+
+#ifdef PWDRIVER
+int main()
+{
+       static treenode_t       root;
+       rect_t r = {{0.0, 0.0}, {100.0, 100.0}};
+       Agraph_t *g;
+
+       aginit();
+       g = agread(stdin);
+       root.leftchild = treebuilder(g);
+       sizeit(&root);
+       /*layouter(&root,LR,r);*/
+       sqlayouter(&root,LR,r,root.area);
+       printer(&root);
+       return 0;
+}
+#endif
+
+void patchwork_layout(Agraph_t *g)
+{
+       static treenode_t       root;
+       rect_t r = {{0.0, 0.0}, {100.0, 100.0}};
+       patchwork_init_graph(g);
+       root.leftchild = treebuilder(g);
+       sizeit(&root);
+       sqlayouter(&root,LR,r,root.area);
+       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);
+}
diff --git a/lib/patchwork/patchwork.h b/lib/patchwork/patchwork.h
new file mode 100644 (file)
index 0000000..7e1948b
--- /dev/null
@@ -0,0 +1,52 @@
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#ifndef PATCHWORK_H
+#define PATCHWORK_H
+
+#include "render.h"
+#include "../fdpgen/fdp.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    typedef struct {
+       int nStepsToLeaf;
+       int subtreeSize;
+       int nChildren;
+       int nStepsToCenter;
+       node_t *parent;
+       double span;
+       double theta;
+    } rdata;
+
+#define RDATA(n) ((rdata*)((n)->u.alg))
+#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);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/lib/patchwork/patchworkinit.c b/lib/patchwork/patchworkinit.c
new file mode 100644 (file)
index 0000000..f4cdffc
--- /dev/null
@@ -0,0 +1,167 @@
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+
+#include    "patchwork.h"
+#include    "adjust.h"
+#include    "pack.h"
+#include    "neatoprocs.h"
+
+/* the following code shamelessly copied from lib/fdpgen/layout.c
+and should be extracted and made into a common function */
+
+#define CL_CHUNK 10
+
+typedef struct {
+    graph_t **cl;
+    int sz;
+    int cnt;
+} clist_t;
+
+static void initCList(clist_t * clist)
+{
+    clist->cl = 0;
+    clist->sz = 0;
+    clist->cnt = 0;
+}
+
+/* addCluster:
+ * Append a new cluster to the list.
+ * NOTE: cl[0] is empty. The clusters are in cl[1..cnt].
+ * Normally, we increase the array when cnt == sz.
+ * The test for cnt > sz is necessary for the first time.
+ */
+static void addCluster(clist_t * clist, graph_t * subg)
+{
+    clist->cnt++;
+    if (clist->cnt >= clist->sz) {
+       clist->sz += CL_CHUNK;
+       clist->cl = RALLOC(clist->sz, clist->cl, graph_t *);
+    }
+    clist->cl[clist->cnt] = subg;
+}
+
+/* mkClusters:
+ * Attach list of immediate child clusters.
+ * NB: By convention, the indexing starts at 1.
+ * If pclist is NULL, the graph is the root graph or a cluster
+ * If pclist is non-NULL, we are recursively scanning a non-cluster
+ * subgraph for cluster children.
+ */
+static void
+mkClusters (graph_t * g, clist_t* pclist, graph_t* parent)
+{
+    node_t*  mn;
+    edge_t*  me;
+    graph_t* mg;
+    graph_t* subg;
+    clist_t  list;
+    clist_t* clist;
+
+    if (pclist == NULL) {
+        clist = &list;
+        initCList(clist);
+    }
+    else
+        clist = pclist;
+    mg = g->meta_node->graph;
+    for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
+        mn = me->head;
+        subg = agusergraph(mn);
+        if (!strncmp(subg->name, "cluster", 7)) {
+#ifdef FDP_GEN
+            GD_alg(subg) = (void *) NEW(gdata); /* freed in cleanup_subgs */
+            GD_ndim(subg) = GD_ndim(parent);
+            LEVEL(subg) = LEVEL(parent) + 1;
+            GPARENT(subg) = parent;
+#endif
+            addCluster(clist, subg);
+            mkClusters(subg, NULL, subg);
+        }
+        else {
+            mkClusters(subg, clist, parent);
+        }
+    }
+    if (pclist == NULL) {
+        GD_n_cluster(g) = list.cnt;
+        if (list.cnt)
+            GD_clust(g) = RALLOC(list.cnt + 1, list.cl, graph_t*);
+    }
+}
+
+static void patchwork_init_node(node_t * n)
+{
+    agset(n,"shape","box");
+    common_init_node(n);
+    gv_nodesize(n, GD_flip(n->graph));
+    ND_pos(n) = ALLOC(GD_ndim(n->graph), 0, double);
+}
+
+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)
+{
+    node_t *n;
+    edge_t *e;
+    int i = 0;
+    rdata* alg = N_NEW(agnnodes(g), rdata);
+
+    GD_neato_nlist(g) = N_NEW(agnnodes(g) + 1, node_t *);
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+       ND_alg(n) = alg + i;
+       GD_neato_nlist(g)[i++] = n;
+       patchwork_init_node(n);
+    }
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+       for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
+           patchwork_init_edge(e);
+       }
+    }
+}
+
+void patchwork_init_graph(graph_t * g)
+{
+       agnodeattr(g,"shape","box");
+    setEdgeType (g, ET_LINE);
+    /* GD_ndim(g) = late_int(g,agfindattr(g,"dim"),2,2); */
+    Ndim = GD_ndim(g) = 2;     /* The algorithm only makes sense in 2D */
+       mkClusters(g, NULL, g);
+    patchwork_init_node_edge(g);
+}
+
+static void patchwork_cleanup_graph(graph_t * g)
+{
+    free(GD_neato_nlist(g));
+    if (g != g->root) memset(&(g->u), 0, sizeof(Agraphinfo_t));
+}
+
+void patchwork_cleanup(graph_t * g)
+{
+    node_t *n;
+    edge_t *e;
+
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+       for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
+           gv_cleanup_edge(e);
+       }
+       gv_cleanup_node(n);
+    }
+    patchwork_cleanup_graph(g);
+}