Still need to tackle loops.
free(lp);
}
-static box *portToTbl(htmltbl_t *, char *); /* forward declaration */
+static htmldata_t* portToTbl(htmltbl_t *, char *); /* forward declaration */
-static box *portToCell(htmlcell_t * cp, char *id)
+static htmldata_t* portToCell(htmlcell_t * cp, char *id)
{
- box *rv;
+ htmldata_t* rv;
if (cp->data.port && (strcasecmp(cp->data.port, id) == 0))
- rv = &cp->data.box;
+ rv = &cp->data;
else if (cp->child.kind == HTML_TBL)
rv = portToTbl(cp->child.u.tbl, id);
else
* See if tp or any of its child cells has the given port id.
* If true, return corresponding box.
*/
-static box *portToTbl(htmltbl_t * tp, char *id)
+static htmldata_t*
+portToTbl(htmltbl_t* tp, char* id)
{
- box *rv;
- htmlcell_t **cells;
- htmlcell_t *cp;
+ htmldata_t* rv;
+ htmlcell_t** cells;
+ htmlcell_t* cp;
if (tp->data.port && (strcasecmp(tp->data.port, id) == 0))
- rv = &tp->data.box;
+ rv = &tp->data;
else {
rv = NULL;
cells = tp->u.n.cells;
* If successful, return pointer to port's box.
* Else return NULL.
*/
-box *html_port(node_t * n, char *pname)
+box *html_port(node_t * n, char *pname, int* sides)
{
- htmllabel_t *lbl = ND_label(n)->u.html;
+ htmldata_t* tp;
+ htmllabel_t* lbl = ND_label(n)->u.html;
+ box* rv = NULL;
if (lbl->kind == HTML_TEXT)
return NULL;
- return portToTbl(lbl->u.tbl, pname);
+ tp = portToTbl(lbl->u.tbl, pname);
+ if (tp) {
+ rv = &tp->box;
+ *sides = tp->sides;
+ }
+ return rv;
+
}
/* html_path:
closeGraphs(rowg, colg);
}
-static void pos_html_tbl(htmltbl_t *, box); /* forward declaration */
+static void pos_html_tbl(htmltbl_t *, box, int); /* forward declaration */
static void pos_html_img(htmlimg_t * cp, box pos)
{
cp->box = pos;
}
-static void pos_html_cell(htmlcell_t * cp, box pos)
+static void pos_html_cell(htmlcell_t * cp, box pos, int sides)
{
int delx, dely;
point oldsz;
}
}
cp->data.box = pos;
+ cp->data.sides = sides;
/* set up child's position */
cbox.LL.x = pos.LL.x + cp->data.border + cp->data.pad;
cbox.UR.y = pos.UR.y - cp->data.border - cp->data.pad;
if (cp->child.kind == HTML_TBL) {
- pos_html_tbl(cp->child.u.tbl, cbox);
+ pos_html_tbl(cp->child.u.tbl, cbox, sides);
} else if (cp->child.kind == HTML_IMAGE) {
pos_html_img(cp->child.u.img, cbox);
} else {
/* pos_html_tbl:
* Position table given its box, then calculate
- * the position of each cell.
+ * the position of each cell. In addition, set the sides
+ * attribute indicating which external sides of the node
+ * are accessible to the table.
*/
-static void pos_html_tbl(htmltbl_t * tbl, box pos)
+static void pos_html_tbl(htmltbl_t * tbl, box pos, int sides)
{
int x, y, delx, dely;
int i, plus, extra, oldsz;
}
while ((cp = *cells++)) {
+ int mask = 0;
+ if (sides) {
+ if (cp->col == 0) mask |= LEFT;
+ if (cp->row == 0) mask |= TOP;
+ if (cp->col + cp->cspan == tbl->cc) mask |= RIGHT;
+ if (cp->row + cp->rspan == tbl->rc) mask |= BOTTOM;
+ }
cbox.LL.x = tbl->widths[cp->col];
cbox.UR.x = tbl->widths[cp->col + cp->cspan] - tbl->data.space;
cbox.UR.y = tbl->heights[cp->row];
cbox.LL.y = tbl->heights[cp->row + cp->rspan] + tbl->data.space;
- pos_html_cell(cp, cbox);
+ pos_html_cell(cp, cbox, sides & mask);
}
+ tbl->data.sides = sides;
tbl->data.box = pos;
}
wd2 = (lbl->u.tbl->data.box.UR.x + 1) / 2;
ht2 = (lbl->u.tbl->data.box.UR.y + 1) / 2;
box = boxof(-wd2, -ht2, wd2, ht2);
- pos_html_tbl(lbl->u.tbl, box);
+ pos_html_tbl(lbl->u.tbl, box, BOTTOM | RIGHT | TOP | LEFT);
lp->dimen.x = box.UR.x - box.LL.x;
lp->dimen.y = box.UR.y - box.LL.y;
} else {
unsigned short width;
unsigned short height;
box box; /* its geometric placement in points */
+ unsigned char sides; /* set of sides exposed to field */
} htmldata_t;
#define HTML_UNSET 0
extern void free_html_data(htmldata_t *);
extern void free_html_text(htmltxt_t *);
- extern box *html_port(node_t * n, char *pname);
+ extern box *html_port(node_t * n, char *pname, int* sides);
extern int html_path(node_t * n, edge_t * e, int pt, box * rv, int *k);
extern int html_inside(node_t * n, pointf p, edge_t * e);
# define sincos(x,s,c) *s = sin(x); *c = cos(x)
#endif
-static port Center = { {0, 0}, -1, 0, 0, 0, 0 };
+static port Center = { {0, 0}, -1, 0, 0, 0, 1, 0, 0 };
#define ATTR_SET(a,n) ((a) && (*(agxget(n,a->index)) != '\0'))
#define DEF_POINT 0.05
node_t *n = inside_context->n;
P = flip_ptf(p, GD_rankdir(n->graph));
- for (f = e; ED_edge_type(f) != NORMAL; f = ED_to_orig(f));
- e = f;
+ if (e) {
+ for (f = e; ED_edge_type(f) != NORMAL; f = ED_to_orig(f));
+ e = f;
+ }
if ((n != lastn) || (e != laste)) {
- bp = GET_PORT_BOX(n, e);
+ if (e) bp = GET_PORT_BOX(n, e);
+ else bp = NULL;
if ((bp == NULL) && (n != datan)) {
datan = n;
return side;
}
+/* invflip_side:
+ */
+static int invflip_side (int side, int rankdir)
+{
+ switch (rankdir) {
+ case RANKDIR_TB:
+ break;
+ case RANKDIR_BT:
+ switch (side) {
+ case TOP:
+ side = BOTTOM;
+ break;
+ case BOTTOM:
+ side = TOP;
+ break;
+ default:
+ break;
+ }
+ break;
+ case RANKDIR_LR:
+ switch (side) {
+ case TOP:
+ side = RIGHT;
+ break;
+ case BOTTOM:
+ side = LEFT;
+ break;
+ case LEFT:
+ side = TOP;
+ break;
+ case RIGHT:
+ side = BOTTOM;
+ break;
+ }
+ break;
+ case RANKDIR_RL:
+ switch (side) {
+ case TOP:
+ side = RIGHT;
+ break;
+ case BOTTOM:
+ side = LEFT;
+ break;
+ case LEFT:
+ side = BOTTOM;
+ break;
+ case RIGHT:
+ side = TOP;
+ break;
+ }
+ break;
+ }
+ return side;
+}
+
+/* invflip_angle:
+ */
+static double invflip_angle (double angle, int rankdir)
+{
+ switch (rankdir) {
+ case RANKDIR_TB:
+ break;
+ case RANKDIR_BT:
+ angle *= -1;
+ break;
+ case RANKDIR_LR:
+ angle -= PI * 0.5;
+ break;
+ case RANKDIR_RL:
+ if (angle == PI)
+ angle = -0.5 * PI;
+ else if (angle == PI * 0.75)
+ angle = -0.25 * PI;
+ else if (angle == PI * 0.5)
+ angle = 0;
+ else if (angle == PI * 0.25)
+ angle = angle;
+ else if (angle == 0)
+ angle = PI * 0.5;
+ else if (angle == PI * -0.25)
+ angle = PI * 0.75;
+ else if (angle == PI * -0.5)
+ angle = PI;
+ else if (angle == PI * -0.75)
+ angle = angle;
+ break;
+ }
+ return angle;
+}
+
/* compassPort:
* Attach a compass point to a port pp, and fill in remaining fields.
* n is the corresponding node; bp is the bounding box of the port.
* compass is the compass point
* Return 1 if unrecognized compass point, in which case we
* use the center.
- * This function also finishes initialized the port structure,
+ * This function also finishes initializing the port structure,
* even if no compass point is involved.
+ * The sides value gives the set of sides shared by the port. This
+ * is used with a compass point to indicate if the port is exposed, to
+ * set the port's side value.
*/
-static int compassPort(node_t * n, box * bp, port * pp, char *compass)
+static int
+compassPort(node_t* n, box* bp, port* pp, char* compass, int sides)
{
box b;
point p, ctr;
int rv = 0;
double theta = 0.0;
int constrain = 0;
+ int side = 0;
+ int clip = TRUE;
if (bp) {
b = *bp;
int margin = 1; /* would like = 0, but spline router croaks */
switch (*compass++) {
case 'e':
- p.x = b.UR.x - margin;
+ p.x = b.UR.x + margin;
theta = 0.0;
constrain = 1;
+ clip = FALSE;
+ side = sides & RIGHT;
break;
case 's':
- p.y = b.LL.y + margin;
+ p.y = b.LL.y - margin;
constrain = 1;
+ clip = FALSE;
+ side = sides & BOTTOM;
switch (*compass) {
case '\0':
theta = -PI * 0.5;
default:
p.y = ctr.y;
constrain = 0;
+ clip = TRUE;
rv = 1;
break;
}
break;
case 'w':
- p.x = b.LL.x + margin;
+ p.x = b.LL.x - margin;
theta = PI;
constrain = 1;
+ clip = FALSE;
+ side = sides & LEFT;
break;
case 'n':
- p.y = b.UR.y - margin;
+ p.y = b.UR.y + margin;
constrain = 1;
+ clip = FALSE;
+ side = sides & TOP;
switch (*compass) {
case '\0':
theta = PI * 0.5;
default:
p.y = ctr.y;
constrain = 0;
+ clip = TRUE;
rv = 1;
break;
}
}
}
p = invflip_pt(p, GD_rankdir(n->graph));
+ pp->side = invflip_side(side, GD_rankdir(n->graph));
pp->bp = bp;
pp->p = p;
- pp->theta = theta;
- pp->order =
- (MC_SCALE * (ND_lw_i(n) + p.x)) / (ND_lw_i(n) + ND_rw_i(n));
+ pp->theta = invflip_angle(theta, GD_rankdir(n->graph));
+ if ((p.x == 0) && (p.y == 0))
+ pp->order = MC_SCALE/2;
+ else {
+ /* compute angle with 0 at north pole, increasing CCW */
+ double angle = atan2(p.y,p.x) + 1.5*PI;
+ if (angle >= 2*PI) angle -= 2*PI;
+ pp->order = (int)((MC_SCALE * angle) / 2*PI);
+ }
pp->constrained = constrain;
+ pp->defined = TRUE;
+ pp->clip = clip;
return rv;
}
{
port rv;
box *bp;
+ int sides; /* bitmap of which sides the port lies along */
if (portname[0] == '\0')
return Center;
+ sides = BOTTOM | RIGHT | TOP | LEFT;
if ((ND_label(n)->html)) {
- if ((bp = html_port(n, portname))) {
- if (compassPort(n, bp, &rv, compass)) {
+ if ((bp = html_port(n, portname, &sides))) {
+ if (compassPort(n, bp, &rv, compass, sides)) {
agerr(AGWARN,
"node %s, port %s, unrecognized compass point '%s' - ignored\n",
n->name, portname, compass);
}
- } else if (compassPort(n, NULL, &rv, portname)) {
+ } else if (compassPort(n, NULL, &rv, portname, sides)) {
unrecognized(n, portname);
}
- } else if (compassPort(n, NULL, &rv, portname)) {
+ } else if (compassPort(n, NULL, &rv, portname, sides)) {
unrecognized(n, portname);
}
static char *reclblp;
-static field_t *parse_reclbl(node_t * n, int LR, int flag, char *text)
+static field_t*
+parse_reclbl(node_t * n, int LR, int flag, char *text)
{
field_t *fp, *rv = NEW(field_t);
char *tsp, *psp, *hstsp, *hspsp, *sp;
}
}
-static void pos_reclbl(field_t * f, point ul)
+/* pos_reclbl:
+ * Assign position info for each field. Also, set
+ * the sides attribute, which indicates which sides of the
+ * record are accessible to the field.
+ */
+static void pos_reclbl(field_t * f, point ul, int sides)
{
- int i;
+ int i, last, mask;
+ f->sides = sides;
f->b.LL = pointof(ul.x, ul.y - f->size.y);
f->b.UR = pointof(ul.x + f->size.x, ul.y);
- for (i = 0; i < f->n_flds; i++) {
- pos_reclbl(f->fld[i], ul);
+ last = f->n_flds - 1;
+ for (i = 0; i <= last; i++) {
+ if (sides) {
+ if (f->LR) {
+ if (i == 0) {
+ if (i == last) mask = TOP | BOTTOM | RIGHT | LEFT;
+ else mask = TOP | BOTTOM | LEFT;
+ }
+ else if (i == last) mask = TOP | BOTTOM | RIGHT;
+ else mask = TOP | BOTTOM;
+ }
+ else {
+ if (i == 0) {
+ if (i == last) mask = TOP | BOTTOM | RIGHT | LEFT;
+ else mask = TOP | RIGHT | LEFT;
+ }
+ else if (i == last) mask = LEFT | BOTTOM | RIGHT;
+ else mask = LEFT | RIGHT;
+ }
+ }
+ else mask = 0;
+ pos_reclbl(f->fld[i], ul, sides & mask);
if (f->LR)
ul.x = ul.x + f->fld[i]->size.x;
else
point ul, sz;
int len;
char *textbuf; /* temp buffer for storing labels */
+ int sides = BOTTOM | RIGHT | TOP | LEFT;
reclblp = ND_label(n)->text;
len = strlen(reclblp);
textbuf = N_NEW(len + 1, char);
- if (!(info = parse_reclbl(n, NOT(GD_flip(n->graph)), TRUE, textbuf))) {
+ if (!(info = parse_reclbl(n,NOT(GD_flip(n->graph)), TRUE, textbuf))) {
agerr(AGERR, "bad label format %s\n", ND_label(n)->text);
reclblp = "\\N";
info = parse_reclbl(n, NOT(GD_flip(n->graph)), TRUE, textbuf);
}
resize_reclbl(info, sz, mapbool(late_string(n, N_nojustify, "false")));
ul = pointof(-sz.x / 2, sz.y / 2);
- pos_reclbl(info, ul);
+ pos_reclbl(info, ul, sides);
ND_width(n) = PS2INCH(info->size.x);
ND_height(n) = PS2INCH(info->size.y);
ND_shape_info(n) = (void *) info;
field_t *f;
field_t *subf;
port rv;
+ int sides; /* bitmap of which sides the port lies along */
if (portname[0] == '\0')
return Center;
+ sides = BOTTOM | RIGHT | TOP | LEFT;
f = (field_t *) ND_shape_info(n);
if ((subf = map_rec_port(f, portname))) {
- if (compassPort(n, &subf->b, &rv, compass)) {
+ if (compassPort(n, &subf->b, &rv, compass, subf->sides)) {
agerr(AGWARN,
"node %s, port %s, unrecognized compass point '%s' - ignored\n",
n->name, portname, compass);
}
- } else if (compassPort(n, &f->b, &rv, portname)) {
+ } else if (compassPort(n, &f->b, &rv, portname, sides)) {
unrecognized(n, portname);
}
/* convert point to node coordinate system */
p = flip_ptf(p, GD_rankdir(n->graph));
+
+ if (e == NULL) {
+ fld0 = (field_t *) ND_shape_info(n);
+ return INSIDE(p, fld0->b);
+ }
+
/* find real edge */
for (f = e; ED_edge_type(f) != NORMAL; f = ED_to_orig(f));
e = f;
#include <render.h>
-/* wantclip:
- * Return false if head/tail end of edge should not be clipped
- * to node.
- */
-static boolean wantclip(edge_t * e, node_t * n)
-{
- char *str;
- attrsym_t *sym = 0;
- boolean rv = TRUE;
-
- if (n == e->tail)
- sym = E_tailclip;
- if (n == e->head)
- sym = E_headclip;
- if (sym) { /* mapbool isn't a good fit, because we want "" to mean TRUE */
- str = agxget(e, sym->index);
- if (str && str[0])
- rv = mapbool(str);
- else
- rv = TRUE;
- }
- return rv;
-}
-
/* arrow_clip:
* Clip arrow to node boundary.
* The real work is done elsewhere. Here we get the real edge,
* fed back to shape_clip, it will again assume left_inside is true.
* To be safe, shape_clip0 should guarantee that the computed boundary
* point fails insidefn.
+ * The edge e is used to provide a port box. If NULL, the spline is
+ * clipped to the node shape.
*/
void shape_clip(node_t * n, point curve[4], edge_t * e)
{
}
/* spline may be interior to node */
- if (wantclip(orig, tn) && ND_shape(tn) && ND_shape(tn)->fns->insidefn) {
+ if(ED_tail_port(orig).clip && ND_shape(tn) && ND_shape(tn)->fns->insidefn) {
inside_context.n = tn;
inside_context.e = fe;
for (start = 0; start < pn - 4; start += 3) {
shape_clip0(&inside_context, tn, &ps[start], TRUE);
} else
start = 0;
- if (wantclip(orig, hn) && ND_shape(hn) && ND_shape(hn)->fns->insidefn) {
+ if(ED_head_port(orig).clip && ND_shape(hn) && ND_shape(hn)->fns->insidefn) {
inside_context.n = hn;
inside_context.e = le;
for (end = pn - 4; end > 0; end -= 3) {
newspl->size = end - start + 4;
}
-static double conc_slope(node_t * n)
+static double
+conc_slope(node_t* n)
{
double s_in, s_out, m_in, m_out;
int cnt_in, cnt_out;
void
beginpath(path * P, edge_t * e, int et, pathend_t * endp, boolean merge)
{
- int mask;
+ int side, mask;
node_t *n;
int (*pboxfn) (node_t * n, edge_t * e, int, box *, int *);
P->nbox = 0;
P->data = (void *) e;
endp->np = P->start.p;
+ if ((et == REGULAREDGE) && (ND_node_type(n) == NORMAL) && ((side = ED_tail_port(e).side))) {
+ edge_t* orig;
+ box b0, b = endp->nb;
+ switch (side) {
+ case LEFT:
+ b.UR.x = P->start.p.x;
+ b.LL.y = ND_coord_i(n).y - ND_ht_i(n)/2;
+ b.UR.y = P->start.p.y;
+ endp->boxes[0] = b;
+ endp->boxn = 1;
+ break;
+ case RIGHT:
+ b.LL.x = P->start.p.x;
+ b.LL.y = ND_coord_i(n).y - ND_ht_i(n)/2;
+ b.UR.y = P->start.p.y;
+ endp->boxes[0] = b;
+ endp->boxn = 1;
+ break;
+ case TOP:
+ if (ND_coord_i(e->head).x < 2*ND_coord_i(n).x - endp->np.x) {
+ b0.LL.x = b.LL.x - 1;
+ b0.LL.y = ND_coord_i(n).y + ND_ht_i(n)/2;
+ b0.UR.x = P->start.p.x;
+ b0.UR.y = b0.LL.y + GD_ranksep(n->graph)/2;
+ b.UR.x = ND_coord_i(n).x - ND_lw_i(n) - 2;
+ b.UR.y = b0.LL.y;
+ b.LL.y = ND_coord_i(n).y - ND_ht_i(n)/2;
+ b.LL.x -= 1;
+ endp->boxes[0] = b0;
+ endp->boxes[1] = b;
+ }
+ else {
+ b0.LL.x = P->start.p.x;
+ b0.LL.y = ND_coord_i(n).y + ND_ht_i(n)/2;
+ b0.UR.x = b.UR.x+1;
+ b0.UR.y = b0.LL.y + GD_ranksep(n->graph)/2;
+ b.LL.x = ND_coord_i(n).x + ND_rw_i(n) + 2;
+ b.UR.y = b0.LL.y;
+ b.LL.y = ND_coord_i(n).y - ND_ht_i(n)/2;
+ b.UR.x += 1;
+ endp->boxes[0] = b0;
+ endp->boxes[1] = b;
+ }
+ endp->boxn = 2;
+ break;
+ case BOTTOM:
+ b.UR.y = MAX(b.UR.y,P->start.p.y);
+ endp->boxes[0] = b;
+ endp->boxn = 1;
+ break;
+ }
+ for (orig = e; ED_edge_type(orig) != NORMAL; orig = ED_to_orig(orig));
+ ED_tail_port(orig).clip = FALSE;
+ endp->sidemask = side;
+ return;
+ }
/* FIXME: check that record_path returns a good path */
if (pboxfn
&& (mask = (*pboxfn) (n, e, 1, &endp->boxes[0], &endp->boxn)))
void endpath(path * P, edge_t * e, int et, pathend_t * endp, boolean merge)
{
- int mask;
+ int side, mask;
node_t *n;
int (*pboxfn) (node_t * n, edge_t * e, int, box *, int *);
P->end.constrained = FALSE;
}
endp->np = P->end.p;
+ if ((et == REGULAREDGE) && (ND_node_type(n) == NORMAL) && ((side = ED_head_port(e).side))) {
+ edge_t* orig;
+ box b0, b = endp->nb;
+ switch (side) {
+ case LEFT:
+ b.UR.x = P->end.p.x;
+ b.UR.y = ND_coord_i(n).y + ND_ht_i(n)/2;
+ b.LL.y = P->end.p.y;
+ endp->boxes[0] = b;
+ endp->boxn = 1;
+ break;
+ case RIGHT:
+ b.LL.x = P->end.p.x;
+ b.UR.y = ND_coord_i(n).y + ND_ht_i(n)/2;
+ b.LL.y = P->end.p.y;
+ endp->boxes[0] = b;
+ endp->boxn = 1;
+ break;
+ case BOTTOM:
+ if (ND_coord_i(e->tail).x < 2*ND_coord_i(n).x - endp->np.x) {
+ b0.LL.x = b.LL.x-1;
+ b0.UR.y = ND_coord_i(n).y - ND_ht_i(n)/2;
+ b0.UR.x = P->end.p.x;
+ b0.LL.y = b0.UR.y - GD_ranksep(n->graph)/2;
+ b.UR.x = ND_coord_i(n).x - ND_lw_i(n) - 2;
+ b.LL.y = b0.UR.y;
+ b.UR.y = ND_coord_i(n).y + ND_ht_i(n)/2;
+ b.LL.x -= 1;
+ endp->boxes[0] = b0;
+ endp->boxes[1] = b;
+ }
+ else {
+ b0.LL.x = P->end.p.x;
+ b0.UR.y = ND_coord_i(n).y - ND_ht_i(n)/2;
+ b0.UR.x = b.UR.x+1;
+ b0.LL.y = b0.UR.y - GD_ranksep(n->graph)/2;
+ b.LL.x = ND_coord_i(n).x + ND_rw_i(n) + 2;
+ b.LL.y = b0.UR.y;
+ b.UR.y = ND_coord_i(n).y + ND_ht_i(n)/2;
+ b.UR.x += 1;
+ endp->boxes[0] = b0;
+ endp->boxes[1] = b;
+ }
+ endp->boxn = 2;
+ break;
+ case TOP:
+ b.LL.y = MIN(b.LL.y,P->end.p.y);
+ endp->boxes[0] = b;
+ endp->boxn = 1;
+ break;
+ }
+ for (orig = e; ED_edge_type(orig) != NORMAL; orig = ED_to_orig(orig));
+ ED_head_port(orig).clip = FALSE;
+ endp->sidemask = side;
+ return;
+ }
if (pboxfn
&& (mask = (*pboxfn) (n, e, 2, &endp->boxes[0], &endp->boxn)))
endp->sidemask = mask;
} inside_t;
typedef struct port { /* internal edge endpoint specification */
- point p; /* aiming point */
+ point p; /* aiming point relative to node center */
double theta; /* slope in radians */
box *bp; /* if not null, points to bbox of
* rectangular area that is port target
boolean constrained; /* if true, constraints such as theta are set */
boolean clip; /* if true, clip end to node/port shape */
unsigned char order; /* for mincross */
+ unsigned char side; /* if port is on perimeter of node */
} port;
typedef struct {
} adjmatrix_t;
typedef struct rank_t {
- int n; /* number of nodes in this rank */
- node_t **v; /* ordered list of nodes in rank */
+ int n; /* number of nodes in this rank */
+ node_t **v; /* ordered list of nodes in rank */
int an; /* globally allocated number of nodes */
- node_t **av; /* allocated list of nodes in rank */
- int ht1, ht2; /* height below/above centerline */
+ node_t **av; /* allocated list of nodes in rank */
+ int ht1, ht2; /* height below/above centerline */
int pht1, pht2; /* as above, but only primitive nodes */
- boolean candidate; /* for transpose () */
+ boolean candidate; /* for transpose () */
boolean valid;
- int cache_nc; /* caches number of crossings */
+ int cache_nc; /* caches number of crossings */
adjmatrix_t *flat;
} rank_t;
int n_flds;
textlabel_t *lp; /* n_flds == 0 */
struct field_t **fld; /* n_flds > 0 */
- int LR; /* if box list is horizontal (left to right) */
char *id; /* user's identifier */
+ unsigned char LR; /* if box list is horizontal (left to right) */
+ unsigned char sides; /* sides of node exposed to field */
} field_t;
typedef struct hsbcolor_t {
static void make_flat_edge(path *, Agedge_t **, int, int);
static box makeflatend(box, int, int, box);
static void make_regular_edge(path *, Agedge_t **, int, int);
-static void makeregularend(box, int, int, box *);
+static box makeregularend(box, int, int);
static void make_self_edge(path *, Agedge_t **, int, int);
static box maximal_bbox(Agnode_t *, Agedge_t *, Agedge_t *);
static Agnode_t *neighbor(Agnode_t *, Agedge_t *, Agedge_t *, int);
LeftBound = MIN(LeftBound, (ND_coord_i(n).x - ND_lw_i(n)));
if (GD_rank(g)[i].n && (n = GD_rank(g)[i].v[GD_rank(g)[i].n - 1]))
RightBound = MAX(RightBound, (ND_coord_i(n).x + ND_rw_i(n)));
+ LeftBound -= MINW;
+ RightBound += MINW;
for (j = 0; j < GD_rank(g)[i].n; j++) {
n = GD_rank(g)[i].v[j];
g = e->tail->graph;
tn = e->tail;
hn = e->head;
- tend.nb = maximal_bbox(tn, NULL, e);
+ b = tend.nb = maximal_bbox(tn, NULL, e);
beginpath(P, e, REGULAREDGE, &tend, spline_merge(e->tail));
- makeregularend(tend.boxes[tend.boxn - 1], BOTTOM,
- ND_coord_i(tn).y - GD_rank(tn->graph)[ND_rank(tn)].ht1,
- &b);
+ b.UR.y = tend.boxes[tend.boxn - 1].UR.y;
+ b.LL.y = tend.boxes[tend.boxn - 1].LL.y;
+ b = makeregularend(b, BOTTOM,
+ ND_coord_i(tn).y - GD_rank(tn->graph)[ND_rank(tn)].ht1);
if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
tend.boxes[tend.boxn++] = b;
longedge = 0;
}
hend.nb = maximal_bbox(hn, e, ND_out(hn).list[0]);
endpath(P, e, REGULAREDGE, &hend, spline_merge(e->head));
- makeregularend(hend.boxes[hend.boxn - 1], TOP,
- ND_coord_i(hn).y +
- GD_rank(hn->graph)[ND_rank(hn)].ht2, &b);
+ b = makeregularend(hend.boxes[hend.boxn - 1], TOP,
+ ND_coord_i(hn).y + GD_rank(hn->graph)[ND_rank(hn)].ht2);
if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
hend.boxes[hend.boxn++] = b;
P->end.theta = PI / 2, P->end.constrained = TRUE;
boxn = 0;
tend.nb = maximal_bbox(tn, ND_in(tn).list[0], e);
beginpath(P, e, REGULAREDGE, &tend, spline_merge(e->tail));
- makeregularend(tend.boxes[tend.boxn - 1], BOTTOM,
- ND_coord_i(tn).y -
- GD_rank(tn->graph)[ND_rank(tn)].ht1, &b);
+ b = makeregularend(tend.boxes[tend.boxn - 1], BOTTOM,
+ ND_coord_i(tn).y - GD_rank(tn->graph)[ND_rank(tn)].ht1);
if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
tend.boxes[tend.boxn++] = b;
P->start.theta = -PI / 2, P->start.constrained = TRUE;
smode = FALSE;
}
boxes[boxn++] = rank_box(g, ND_rank(tn));
- hend.nb = maximal_bbox(hn, e, NULL);
+ b = hend.nb = maximal_bbox(hn, e, NULL);
endpath(P, hackflag ? &fwdedgeb : e, REGULAREDGE, &hend,
spline_merge(e->head));
- makeregularend(hend.boxes[hend.boxn - 1], TOP,
- ND_coord_i(hn).y + GD_rank(hn->graph)[ND_rank(hn)].ht2,
- &b);
+ b.UR.y = hend.boxes[hend.boxn - 1].UR.y;
+ b.LL.y = hend.boxes[hend.boxn - 1].LL.y;
+ b = makeregularend(b, TOP,
+ ND_coord_i(hn).y + GD_rank(hn->graph)[ND_rank(hn)].ht2);
if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
hend.boxes[hend.boxn++] = b;
completeregularpath(P, segfirst, e, &tend, &hend, boxes, boxn,
/* regular edges */
+#define DONT_WANT_ANY_ENDPOINT_PATH_REFINEMENT
#ifdef DONT_WANT_ANY_ENDPOINT_PATH_REFINEMENT
static void
completeregularpath(path * P, edge_t * first, edge_t * last,
}
#endif
-/* for now, regular edges always go from top to bottom */
-static void makeregularend(box b, int side, int y, box * bp)
+/* makeregularend:
+ * Add box to fill between node and interrank space. Needed because
+ * nodes in a given rank can differ in height.
+ * for now, regular edges always go from top to bottom
+ */
+static box makeregularend(box b, int side, int y)
{
+ box newb;
switch (side) {
case BOTTOM:
- *bp = boxof(b.LL.x, y, b.UR.x, b.LL.y);
+ newb = boxof(b.LL.x, y, b.UR.x, b.LL.y);
break;
case TOP:
- *bp = boxof(b.LL.x, b.UR.y, b.UR.x, y);
+ newb = boxof(b.LL.x, b.UR.y, b.UR.x, y);
break;
}
+ return newb;
}
#ifndef DONT_WANT_ANY_ENDPOINT_PATH_REFINEMENT
}
#endif
+/* adjustregularpath:
+ * make sure the path is wide enough.
+ * the % 2 was so that in rank boxes would only be grown if
+ * they were == 0 while inter-rank boxes could be stretched to a min
+ * width.
+ * The list of boxes has three parts: tail boxes, path boxes, and head
+ * boxes. (Note that because of back edges, the tail boxes might actually
+ * belong to the head node, and vice versa.) fb is the index of the
+ * first interrank path box and lb is the last interrank path box.
+ * If fb > lb, there are none.
+ *
+ * The second for loop was added by ek long ago, and apparently is intended
+ * to guarantee an overlap between adjacent boxes of at least MINW.
+ * It doesn't do this, and the ifdef'ed part has the potential of moving
+ * a box within a node for more complex paths.
+ */
static void adjustregularpath(path * P, int fb, int lb)
{
box *bp1, *bp2;
int i, x;
- for (i = 0; i < P->nbox; i++) {
+ for (i = fb-1; i < lb+1; i++) {
bp1 = &P->boxes[i];
if ((i - fb) % 2 == 0) {
if (bp1->LL.x >= bp1->UR.x) {
bp1->LL.x = bp2->UR.x - MINW;
if (bp1->UR.x - MINW < bp2->LL.x)
bp1->UR.x = bp2->LL.x + MINW;
- } else {
+ }
+#ifdef OLD
+ else {
if (bp1->LL.x + MINW > bp2->UR.x) {
x = (bp1->LL.x + bp2->UR.x) / 2;
bp1->LL.x = x - HALFMINW;
bp2->LL.x = x - HALFMINW;
}
}
+#endif
}
}
return rv;
}
-static box maximal_bbox(vn, ie, oe)
-node_t *vn;
-edge_t *ie, *oe;
+/* maximal_bbox:
+ * Return an initial bounding box to be used for building the
+ * beginning or ending of the path of boxes.
+ * Height reflects height of tallest node on rank.
+ */
+static box maximal_bbox(node_t* vn, edge_t* ie, edge_t* oe)
{
int nb, b;
graph_t *g = vn->graph, *left_cl, *right_cl;