]> granicus.if.org Git - graphviz/commitdiff
Add support for dynamic choice of compass points based on layout
authorerg <devnull@localhost>
Thu, 14 Aug 2008 18:47:32 +0000 (18:47 +0000)
committererg <devnull@localhost>
Thu, 14 Aug 2008 18:47:32 +0000 (18:47 +0000)
and external sides.

lib/Makefile.am
lib/common/render.h
lib/common/shapes.c
lib/common/types.h
lib/dotgen/Makefile.am
lib/dotgen/dotsplines.c
lib/gvc/Makefile.am
lib/neatogen/Makefile.am
lib/neatogen/neatosplines.c

index 6aaf34e53eaa56454e5e4d7aa4210e94cadd3afe..227056e1907a293bdc36e7e5424e002e6a41bb67 100644 (file)
@@ -3,6 +3,6 @@
 
 SUBDIRS = cdt graph agraph gd pathplan agutil sfio vmalloc ast vpsc \
        circogen dotgen fdpgen neatogen twopigen sparse sfdpgen \
-       patchwork common pack gvc ingraphs expr cgraph xdot topfish glcomp
+       patchwork common pack gvc ingraphs expr cgraph xdot topfish glcomp ortho
 
 EXTRA_DIST = Makefile.old
index ee865628eec8c1f63fb37bf9bebcbc6fa7cef25a..b320250d59853f202f898f634c0c41ca3b963473 100644 (file)
@@ -139,6 +139,7 @@ extern "C" {
     extern void pop_obj_state(GVJ_t *job);
     extern obj_state_t* push_obj_state(GVJ_t *job);
     extern int rank(graph_t * g, int balance, int maxiter);
+    extern void resolvePorts (edge_t* e);
     extern void round_corners(GVJ_t*, char*, char*, pointf*, int, int);
     extern void routesplinesinit(void);
     extern point *routesplines(path *, int *);
index aded3533fcd795948c61f62fb4f3b966e7ebfb23..c369f603081c94641ea38b95196a49963a338fc5 100644 (file)
@@ -1327,6 +1327,7 @@ compassPort(node_t* n, box* bp, port* pp, char* compass, int sides, inside_t* ic
     int rv = 0;
     double theta = 0.0;
     boolean constrain = FALSE;
+    boolean dyna = FALSE;
     int side = 0;
     boolean clip = TRUE;
     boolean defined;
@@ -1433,13 +1434,20 @@ compassPort(node_t* n, box* bp, port* pp, char* compass, int sides, inside_t* ic
                break;
            }
            break;
+       case '_':
+           dyna = TRUE;
+           side = sides;
+           break;
+       case 'c':
+           break;
        default:
            rv = 1;
            break;
        }
     }
     p = cwrotatep(p, 90*GD_rankdir(n->graph));
-    pp->side = invflip_side(side, GD_rankdir(n->graph));
+    if (dyna) pp->side = side;
+    else pp->side = invflip_side(side, GD_rankdir(n->graph));
     pp->bp = bp;
     pp->p = p;
     pp->theta = invflip_angle(theta, GD_rankdir(n->graph));
@@ -1454,6 +1462,7 @@ compassPort(node_t* n, box* bp, port* pp, char* compass, int sides, inside_t* ic
     pp->constrained = constrain;
     pp->defined = defined;
     pp->clip = clip;
+    pp->dyna = dyna;
     return rv;
 }
 
@@ -1466,6 +1475,8 @@ static port poly_port(node_t * n, char *portname, char *compass)
     if (portname[0] == '\0')
        return Center;
 
+    if (compass == NULL)
+       compass = "_";
     sides = BOTTOM | RIGHT | TOP | LEFT; 
     if ((ND_label(n)->html) && (bp = html_port(n, portname, &sides))) {
        if (compassPort(n, bp, &rv, compass, sides, NULL)) {
@@ -2214,6 +2225,8 @@ static port record_port(node_t * n, char *portname, char *compass)
     if (portname[0] == '\0')
        return Center;
     sides = BOTTOM | RIGHT | TOP | LEFT; 
+    if (compass == NULL)
+       compass = "_";
     f = (field_t *) ND_shape_info(n);
     if ((subf = map_rec_port(f, portname))) {
        if (compassPort(n, &subf->b, &rv, compass, subf->sides, NULL)) {
@@ -2467,3 +2480,109 @@ static void epsf_gencode(GVJ_t * job, node_t * n)
         gvrender_end_anchor(job);
     }
 }
+
+static char* side_port[] = {"s", "e", "n", "w"};
+
+static point
+cvtPt (point p, int rankdir)
+{
+    point q;
+
+    switch (rankdir) {
+    case RANKDIR_TB :
+       q = p;
+       break;
+    case RANKDIR_BT :
+       q.x = p.x;
+       q.y = -p.y;
+       break;
+    case RANKDIR_LR :
+       q.y = p.x;
+       q.x = -p.y;
+       break;
+    case RANKDIR_RL :
+       q.y = p.x;
+       q.x = p.y;
+       break;
+    }
+    return q;
+}
+
+static char* closestSide (node_t*  n, node_t* other, port* oldport)
+{
+    box b;
+    int rkd = GD_rankdir(n->graph->root);
+    point p, pt = cvtPt (ND_coord_i(n), rkd);
+    point opt = cvtPt (ND_coord_i(other), rkd);
+    int sides = oldport->side;
+    char* rv = NULL;
+    int i, d, mind;
+
+    if (sides == 0) return rv;  /* use center */
+
+    if (oldport->bp) {
+       b = *oldport->bp;
+    } else {
+       if (GD_flip(n->graph)) {
+           b.UR.x = ND_ht_i(n) / 2;
+           b.LL.x = -b.UR.x;
+           b.UR.y = ND_lw_i(n);
+           b.LL.y = -b.UR.y;
+       } else {
+           b.UR.y = ND_ht_i(n) / 2;
+           b.LL.y = -b.UR.y;
+           b.UR.x = ND_lw_i(n);
+           b.LL.x = -b.UR.x;
+       }
+    }
+    
+    for (i = 0; i < 4; i++) {
+       if ((sides & (1<<i)) == 0) continue;
+       switch (i) {
+       case 0 :
+           p.y = b.LL.y;
+           p.x = (b.LL.x + b.UR.x)/2;
+           break;
+       case 1 :
+           p.x = b.UR.x;
+           p.y = (b.LL.y + b.UR.y)/2;
+           break;
+       case 2 :
+           p.y = b.UR.y;
+           p.x = (b.LL.x + b.UR.x)/2;
+           break;
+       case 3 :
+           p.x = b.LL.x;
+           p.y = (b.LL.y + b.UR.y)/2;
+           break;
+       }
+       p.x  += pt.x;
+       p.y  += pt.y;
+       d = DIST2(p, opt);
+       if (!rv || (d < mind)) {
+           mind = d;
+           rv = side_port[i];
+       }
+    }
+    return rv;
+}
+
+static port resolvePort(node_t*  n, node_t* other, port* oldport)
+{
+    port rv;
+    char* compass = closestSide (n, other, oldport);  
+
+    compassPort(n, oldport->bp, &rv, compass, oldport->side, NULL);
+
+    return rv;
+}
+
+void
+resolvePorts (edge_t* e)
+{
+    if (ED_tail_port(e).dyna) 
+       ED_tail_port(e) = resolvePort(e->tail, e->head, &ED_tail_port(e));
+    if (ED_head_port(e).dyna) 
+       ED_head_port(e) = resolvePort(e->head, e->tail, &ED_head_port(e));
+}
+
index 3c5dc2023d1298a40b2691f31baec829d5be14f7..a031ad75166208a9bed69abeaec3c63e80faaf2d 100644 (file)
@@ -78,6 +78,7 @@ extern "C" {
        boolean defined;        /* if true, edge has port info at this end */
        boolean constrained;    /* if true, constraints such as theta are set */
        boolean clip;           /* if true, clip end to node/port shape */
+       boolean dyna;           /* if true, assign compass point dynamically */
        unsigned char order;    /* for mincross */
        unsigned char side;     /* if port is on perimeter of node, this
                                  * contains the bitwise OR of the sides (TOP,
index 09c85ddfb5586cabc7983e6a810886e3c82c89d7..e7030285ece45e3812d155690f9dd0dbd4be6260 100644 (file)
@@ -5,6 +5,7 @@ AM_CPPFLAGS = \
        -I$(top_srcdir) \
         -I$(top_srcdir)/lib/common \
         -I$(top_srcdir)/lib/gvc \
+        -I$(top_srcdir)/lib/ortho \
        -I$(top_srcdir)/lib/graph \
        -I$(top_srcdir)/lib/cdt \
        -I$(top_srcdir)/lib/pathplan
index 22e0af7f0f0f91dd76ff869a5dc5ea7af01b31eb..172a2084ef725ff3da95cc16f235e76524f7b078 100644 (file)
@@ -322,6 +322,9 @@ static void _dot_splines(graph_t * g, int normalize)
        }
     }
 
+    for (i = 0; i < n_edges; i++)
+       resolvePorts (edges[i]);
+
     /* Sort so that equivalent edges are contiguous. 
      * Equivalence should basically mean that 2 edges have the
      * same set {(tailnode,tailport),(headnode,headport)}, or
index eca6736dee4c00c72760727d8b1d45164cf1c2f7..45ce849ca86748fafd4e13bfd9f8f762ba95542a 100644 (file)
@@ -44,6 +44,7 @@ libgvc_C_la_SOURCES = gvrender.c gvlayout.c gvdevice.c gvloadimage.c \
        gvcontext.c gvjobs.c gvevent.c gvplugin.c gvconfig.c \
        gvtextlayout.c gvusershape.c gvc.c
 libgvc_C_la_LIBADD = $(top_builddir)/lib/common/libcommon_C.la \
+       $(top_builddir)/lib/ortho/libortho_C.la \
        $(top_builddir)/lib/pack/libpack_C.la
 
 #For use with plugins.
index b04b4bf5e5d96ff22b3b206534d828bbcaed5430..027859bb1bd618f1648e6d5135c1d30799cd64ef 100644 (file)
@@ -6,6 +6,7 @@ AM_CPPFLAGS = \
         -I$(top_srcdir)/lib/common \
         -I$(top_srcdir)/lib/gvc \
         -I$(top_srcdir)/lib/pack \
+        -I$(top_srcdir)/lib/ortho \
         -I$(top_srcdir)/lib/pathplan \
         -I$(top_srcdir)/lib/graph \
         -I$(top_srcdir)/lib/sfdpgen \
index 527640999abc96d8bc4815baedc46d2aafbcfae1..ea45a1a0eb80246f30b116c22ca0f0636666b274 100644 (file)
@@ -28,6 +28,9 @@
 extern double drand48(void);
 #endif
 
+#ifdef ORTHO
+#include <ortho.h>
+#endif
 
 #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))
@@ -786,9 +789,6 @@ static int _spline_edges(graph_t * g, expand_t* pmargin, int edgetype)
     vconfig_t *vconfig = 0;
     path *P = NULL;
     int useEdges = (Nop > 1);
-#ifdef ORTHO
-    extern void orthoEdges (Agraph_t* g, int useLbls, splineInfo* sinfo);
-#endif
     router_t* rtr = 0;
 
     /* build configuration */
@@ -1946,9 +1946,6 @@ static int _spline_edges(graph_t * g, expand_t* pmargin, int edgetype)
     vconfig_t *vconfig = 0;
     path *P = NULL;
     int useEdges = (Nop > 1);
-#ifdef ORTHO
-    extern void orthoEdges (Agraph_t* g, int useLbls, splineInfo* sinfo);
-#endif
     router_t* rtr = 0;
 
     /* build configuration */
@@ -2091,6 +2088,12 @@ splineEdges(graph_t * g, int (*edgefn) (graph_t *, expand_t*, int),
 
     margin = esepFactor (g);
 
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+       for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
+           resolvePorts (e);
+       }
+    }
+
     /* find equivalent edges */
     map = dtopen(&edgeItemDisc, Dtoset);
     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {