and use for both mouse_in_node/edge and node/edge_in_clip_region.
return p;
}
+boxf arrow_bb(GVJ_t * job, pointf p, pointf u, double scale, int flag)
+{
+ double s;
+ boxf bb;
+ double ax,ay,bx,by,cx,cy,dx,dy;
+ double ux2, uy2;
+
+ /* generate arrowhead vector */
+ u.x -= p.x;
+ u.y -= p.y;
+ /* the EPSILONs are to keep this stable as length of u approaches 0.0 */
+ s = ARROW_LENGTH * scale / (sqrt(u.x * u.x + u.y * u.y) + EPSILON);
+ u.x += (u.x >= 0.0) ? EPSILON : -EPSILON;
+ u.y += (u.y >= 0.0) ? EPSILON : -EPSILON;
+ u.x *= s;
+ u.y *= s;
+
+ /* compute all 4 corners of rotated arrowhead bounding box */
+ ux2 = u.x / 2.;
+ uy2 = u.y / 2.;
+ ax = p.x - uy2;
+ ay = p.y - ux2;
+ bx = p.x + uy2;
+ by = p.y + ux2;
+ cx = ax + u.x;
+ cy = ay + u.y;
+ dx = bx + u.x;
+ dy = by + u.y;
+
+ /* compute a right bb */
+ bb.UR.x = MAX(ax, MAX(bx, MAX(cx, dx)));
+ bb.UR.y = MAX(ay, MAX(by, MAX(cy, dy)));
+ bb.LL.x = MIN(ax, MIN(bx, MIN(cx, dx)));
+ bb.LL.y = MIN(ay, MIN(by, MIN(cy, dy)));
+
+ return bb;
+}
+
void arrow_newgen(GVJ_t * job, pointf p, pointf u, double scale, int flag)
{
double s;
emit_defaults(job);
}
-static boolean node_in_view(GVJ_t *job, node_t * n)
-{
- return boxf_overlap(job->pageBoxClip, ND_bb(n));
-}
-
static boolean is_natural_number(char *sstr)
{
unsigned char *str = (unsigned char *) sstr;
return;
if (node_in_layer(job, n->graph, n)
- && node_in_view(job, n)
+ && overlap_node(n, job->pageBoxClip)
&& (ND_state(n) != gvc->viewNum)) {
gvrender_comment(job, n->name);
gvrender_polyline(job, A, 3);
}
-static boolean edge_in_view(GVJ_t *job, edge_t * e)
-{
- int i, j, np;
- bezier bz;
- point *p;
- pointf pp, pn;
- double sx, sy;
- boxf b;
- textlabel_t *lp;
- splines *spl;
-
- spl = ED_spl(e);
- if (spl == NULL)
- return FALSE;
- if (! boxf_overlap(job->pageBoxClip, spl->bb))
- return FALSE;
- for (i = 0; i < spl->size; i++) {
- bz = spl->list[i];
- np = bz.size;
- p = bz.list;
- P2PF(p[0],pp);
- for (j = 0; j < np; j++) {
- P2PF(p[j],pn);
- b = mkboxf(pp, pn);
- if (boxf_overlap(job->pageBoxClip, b))
- return TRUE;
- pp = pn;
- }
- }
- if ((lp = ED_label(e)) == NULL)
- return FALSE;
- sx = lp->dimen.x / 2.;
- sy = lp->dimen.y / 2.;
- b.LL.x = lp->p.x - sx;
- b.UR.x = lp->p.x + sx;
- b.LL.y = lp->p.y - sy;
- b.UR.y = lp->p.y + sy;
- return boxf_overlap(job->pageBoxClip, b);
-}
-
void emit_edge_graphics(GVJ_t * job, edge_t * e)
{
int i, j, cnum, numc = 0;
char *s, *url = NULL, *label = NULL, *tooltip = NULL, *target = NULL;
textlabel_t *lab = NULL;
- if (! edge_in_view(job, e) || ! edge_in_layer(job, e->head->graph, e))
- return;
+ if (! overlap_edge(e, job->pageBoxClip)
+ || ! edge_in_layer(job, e->head->graph, e))
+ return;
s = malloc(strlen(e->tail->name) + 2 + strlen(e->head->name) + 1);
strcpy(s,e->tail->name);
ND_bb(n).UR.y = ND_coord_i(n).y + ND_ht_i(n) / 2.;
}
-static void init_bb_spl(splines *spl)
+static box bezier_bb(bezier bz)
{
- int i, j;
- bezier bz;
+ int i;
box bb;
- boxf bbf;
-
- for (i = 0; i < spl->size; i++) {
- bz = spl->list[i];
- bb.UR = bb.LL = bz.list[0];
- for (j = 1; j < bz.size; j++) {
- bb.LL.x = MIN(bb.LL.x, bz.list[j].x);
- bb.LL.y = MIN(bb.LL.y, bz.list[j].y);
- bb.UR.x = MAX(bb.UR.x, bz.list[j].x);
- bb.UR.y = MAX(bb.UR.y, bz.list[j].y);
- }
- B2BF(bb, bbf);
- if (i == 0)
- spl->bb = bbf;
- else {
- spl->bb.LL.x = MIN(spl->bb.LL.x, bbf.LL.x);
- spl->bb.LL.y = MIN(spl->bb.LL.y, bbf.LL.y);
- spl->bb.UR.x = MAX(spl->bb.UR.x, bbf.UR.x);
- spl->bb.UR.y = MAX(spl->bb.UR.y, bbf.UR.y);
- }
+
+ assert(bz.size > 0);
+ bb.LL = bb.UR = bz.list[0];
+ for (i = 1; i < bz.size; i++) {
+ bb.LL.x = MIN(bb.LL.x, bz.list[i].x);
+ bb.LL.y = MIN(bb.LL.y, bz.list[i].y);
+ bb.UR.x = MAX(bb.UR.x, bz.list[i].x);
+ bb.UR.y = MAX(bb.UR.y, bz.list[i].y);
+ }
+ return bb;
+}
+
+static void init_splines_bb(splines *spl)
+{
+ int i;
+ box bb, b;
+
+ assert(spl->size > 0);
+ bb = bezier_bb(spl->list[0]);
+ for (i = 1; i < spl->size; i++) {
+ b = bezier_bb(spl->list[0]);
+ bb.LL.x = MIN(bb.LL.x, b.LL.x);
+ bb.LL.y = MIN(bb.LL.y, b.LL.y);
+ bb.UR.x = MAX(bb.UR.x, b.UR.x);
+ bb.UR.y = MAX(bb.UR.y, b.UR.y);
}
+ B2BF(bb,spl->bb);
+}
+
+static void init_bb_edge(edge_t *e)
+{
+ splines *spl;
+
+ spl = ED_spl(e);
+ if (spl)
+ init_splines_bb(spl);
+
+// lp = ED_label(e);
+// if (lp)
+// {}
}
static void init_bb(graph_t *g)
{
node_t *n;
edge_t *e;
- splines *spl;
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
init_bb_node(n);
for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
- spl = ED_spl(e);
- if (spl)
- init_bb_spl(spl);
+ init_bb_edge(e);
}
}
}
extern point add_points(point, point);
extern pointf add_pointfs(pointf, pointf);
extern void arrow_flags(Agedge_t * e, int *sflag, int *eflag);
+ extern boxf arrow_bb(GVJ_t * job, pointf p, pointf u, double scale,
+ int flag);
extern void arrow_gen(GVJ_t * job, point p, point u, double scale,
int flag);
extern double arrow_length(edge_t * e, int flag);
extern nodequeue *new_queue(int);
extern Agraph_t *next_input_graph(void);
extern void osize_label(textlabel_t *, int *, int *, int *, int *);
+ extern boolean overlap_edge(edge_t *e, boxf b);
+ extern boolean overlap_node(node_t *n, boxf b);
extern char **parse_style(char *s);
extern void place_graph_label(Agraph_t *);
extern void place_portlabel(edge_t * e, boolean head_p);
return ns;
}
+boolean overlap_node(node_t *n, boxf b)
+{
+ boxf bb;
+// inside_t ictxt;
+
+ bb = ND_bb(n);
+ if (! OVERLAP(b, bb))
+ return FALSE;
+
+// ictxt.s.n = n;
+// ictxt.s.bp = NULL;
+
+// return ND_shape(n)->fns->insidefn(&ictxt, p);
+ return TRUE;
+}
+
+static boolean overlap_label(textlabel_t *lp, boxf b)
+{
+ double sx, sy;
+ boxf bb;
+
+ sx = lp->dimen.x / 2.;
+ sy = lp->dimen.y / 2.;
+ bb.LL.x = lp->p.x - sx;
+ bb.UR.x = lp->p.x + sx;
+ bb.LL.y = lp->p.y - sy;
+ bb.UR.y = lp->p.y + sy;
+ return OVERLAP(b, bb);
+}
+
+static boolean overlap_bezier(bezier bz, boxf b)
+{
+ int i, j;
+ box bb;
+ boxf bbf;
+
+ for (i = 0; i < bz.size -1; i += 3) {
+ /* compute a bb for the bezier segment */
+ bb.LL = bb.UR = bz.list[i];
+ for (j = i+1; j < i+4; j++) {
+ bb.LL.x = MIN(bb.LL.x,bz.list[j].x);
+ bb.LL.y = MIN(bb.LL.y,bz.list[j].y);
+ bb.UR.x = MAX(bb.UR.x,bz.list[j].x);
+ bb.UR.y = MAX(bb.UR.y,bz.list[j].y);
+ }
+ B2BF(bb, bbf);
+ if (OVERLAP(b, bbf)) {
+ /* FIXME - check if really close enough to actual curve */
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+boolean overlap_edge(edge_t *e, boxf b)
+{
+ int i;
+ splines *spl;
+ textlabel_t *lp;
+
+ spl = ED_spl(e);
+ if (spl && boxf_overlap(spl->bb, b)) {
+ for (i = 0; i < spl->size; i++)
+ if (overlap_bezier(spl->list[i], b))
+ return TRUE;
+
+// if (inside_arrow(e))
+// return TRUE;
+ }
+
+ lp = ED_label(e);
+ if (lp && overlap_label(lp, b))
+ return TRUE;
+
+ return FALSE;
+}
+
+
emit_graph(job, job->g);
}
-static boolean inside_node(node_t *n, boxf b)
-{
- boxf bb;
-// inside_t ictxt;
-
- bb = ND_bb(n);
- if (! OVERLAP(b, bb))
- return FALSE;
-
-// ictxt.s.n = n;
-// ictxt.s.bp = NULL;
-
-// return ND_shape(n)->fns->insidefn(&ictxt, p);
- return TRUE;
-}
-
-static boolean inside_label(edge_t *e, boxf b)
-{
- textlabel_t *lp;
- double sx, sy;
- boxf bb;
-
- lp = ED_label(e);
- if (lp == NULL)
- return FALSE;
- sx = lp->dimen.x / 2.;
- sy = lp->dimen.y / 2.;
- bb.LL.x = lp->p.x - sx;
- bb.UR.x = lp->p.x + sx;
- bb.LL.y = lp->p.y - sy;
- bb.UR.y = lp->p.y + sy;
- return OVERLAP(b, bb);
-}
-
-static boolean inside_spline(edge_t *e, boxf b)
-{
- int i, j, k;
- bezier bz;
- box bb;
- boxf bbf;
- splines *spl;
-
- spl = ED_spl(e);
- if (spl == NULL)
- return FALSE;
-
- bbf = spl->bb;
- if (! OVERLAP(b, bbf))
- return FALSE;
-
- for (i = 0; i < spl->size; i++) {
- bz = spl->list[i];
- for (j = 0; j < bz.size -1; j += 3) {
- /* compute a bb for the bezier segment */
- bb.LL = bb.UR = bz.list[j];
- for (k = j+1; k < j+4; k++) {
- bb.LL.x = MIN(bb.LL.x,bz.list[k].x);
- bb.LL.y = MIN(bb.LL.y,bz.list[k].y);
- bb.UR.x = MAX(bb.UR.x,bz.list[k].x);
- bb.UR.y = MAX(bb.UR.y,bz.list[k].y);
- }
- B2BF(bb, bbf);
- if (OVERLAP(b, bbf)) {
- /* FIXME - check if really close enough to actual curve */
- return TRUE;
- }
- }
- }
- return FALSE;
-}
-
-static boolean inside_edge(edge_t *e, boxf b)
-{
- if (inside_spline(e, b))
- return TRUE;
-// FIXME
-// if (inside_arrow(e))
-// return TRUE;
-
- return inside_label(e, b);
-}
-
/* recursively find innermost cluster containing the point */
static graph_t *gvevent_find_cluster(graph_t *g, boxf b)
{
/* edges might overlap nodes, so search them first */
for (n = agfstnode(g); n; n = agnxtnode(g, n))
for (e = agfstout(g, n); e; e = agnxtout(g, e))
- if (inside_edge(e, b))
+ if (overlap_edge(e, b))
return (void *)e;
/* search graph backwards to get topmost node, in case of overlap */
for (n = aglstnode(g); n; n = agprvnode(g, n))
- if (inside_node(n, b))
+ if (overlap_node(n, b))
return (void *)n;
/* search for innermost cluster */
sg = gvevent_find_cluster(g, b);