and external sides.
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
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 *);
int rv = 0;
double theta = 0.0;
boolean constrain = FALSE;
+ boolean dyna = FALSE;
int side = 0;
boolean clip = TRUE;
boolean defined;
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));
pp->constrained = constrain;
pp->defined = defined;
pp->clip = clip;
+ pp->dyna = dyna;
return rv;
}
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)) {
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)) {
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));
+}
+
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,
-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
}
}
+ 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
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.
-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 \
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))
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 */
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 */
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)) {