]> granicus.if.org Git - graphviz/commitdiff
detect mouse in arrows (or to be accurate, arrow_bb)
authorellson <devnull@localhost>
Sat, 7 May 2005 18:06:39 +0000 (18:06 +0000)
committerellson <devnull@localhost>
Sat, 7 May 2005 18:06:39 +0000 (18:06 +0000)
lib/common/arrows.c
lib/common/emit.c
lib/common/macros.h
lib/common/renderprocs.h
lib/common/utils.c

index b8504b3eafb83d73a638a8674e2165584448e9d7..72d45a16ecbc3533238b355e9acff39f4b090af0 100644 (file)
@@ -510,7 +510,7 @@ static pointf arrow_gen_type(GVJ_t * job, pointf p, pointf u, int flag)
     return p;
 }
 
-boxf arrow_bb(GVJ_t * job, pointf p, pointf u, double scale, int flag)
+boxf arrow_bb(pointf p, pointf u, double scale, int flag)
 {
     double s;
     boxf bb;
index 0590420efd07d8ccfb46f184f8e39b0afe312582..eba0918bde01ad89ba9b571f64e5c3cd9222af5b 100644 (file)
@@ -1636,45 +1636,53 @@ static FILE *file_select(char *str)
     return rv;
 }
 
-static void init_bb_node(node_t *n)
-{
-    ND_bb(n).LL.x = ND_coord_i(n).x - ND_lw_i(n);
-    ND_bb(n).LL.y = ND_coord_i(n).y - ND_ht_i(n) / 2.;
-    ND_bb(n).UR.x = ND_coord_i(n).x + ND_rw_i(n);
-    ND_bb(n).UR.y = ND_coord_i(n).y + ND_ht_i(n) / 2.;
-}
-
-static box bezier_bb(bezier bz)
+static boxf bezier_bb(bezier bz)
 {
     int i;
+    point p;
     box bb;
+    boxf bbf;
 
     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);
+        p=bz.list[i];
+       EXPANDBP(bb,p);
     }
-    return bb;
+    B2BF(bb, bbf);
+    return bbf;
 }
 
 static void init_splines_bb(splines *spl)
 {
     int i;
-    box bb, b;
+    bezier bz;
+    boxf bb, b;
+    pointf p, u;
 
     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);
+    bz = spl->list[0];
+    bb = bezier_bb(bz);
+    for (i = 0; i < spl->size; i++) {
+        if (i > 0) {
+           bz = spl->list[i];
+            b = bezier_bb(bz);
+           EXPANDBB(bb, b);
+       }
+       if (bz.sflag) {
+           P2PF(bz.sp, p);
+           P2PF(bz.list[0], u);
+           b = arrow_bb(p, u, 1, bz.sflag);
+           EXPANDBB(bb, b);
+       }
+       if (bz.eflag) {
+           P2PF(bz.ep, p);
+           P2PF(bz.list[bz.size - 1], u);
+           b = arrow_bb(p, u, 1, bz.eflag);
+           EXPANDBB(bb, b);
+       }
     }
-    B2BF(bb,spl->bb);
+    spl->bb = bb;
 }
 
 static void init_bb_edge(edge_t *e)
@@ -1690,17 +1698,32 @@ static void init_bb_edge(edge_t *e)
 //        {}
 }
 
+static void init_bb_node(graph_t *g, node_t *n)
+{
+    edge_t *e;
+
+    ND_bb(n).LL.x = ND_coord_i(n).x - ND_lw_i(n);
+    ND_bb(n).LL.y = ND_coord_i(n).y - ND_ht_i(n) / 2.;
+    ND_bb(n).UR.x = ND_coord_i(n).x + ND_rw_i(n);
+    ND_bb(n).UR.y = ND_coord_i(n).y + ND_ht_i(n) / 2.;
+
+    for (e = agfstout(g, n); e; e = agnxtout(g, e))
+       init_bb_edge(e);
+
+    /* IDEA - could also save in the node the bb of the node and 
+    all of its outedges, then the scan time would be proportional
+    to just the number of nodes for many graphs.
+    Wouldn't work so well if the edges are sprawling all over the place
+    but it wouldn't add much to the cost to try before trying individual
+    nodes and edges. */
+}
+
 static void init_bb(graph_t *g)
 {
     node_t *n;
-    edge_t *e;
 
-    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
-       init_bb_node(n);
-        for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
-           init_bb_edge(e);
-       }
-    }
+    for (n = agfstnode(g); n; n = agnxtnode(g, n))
+       init_bb_node(g, n);
 }
 
 void emit_jobs (GVC_t * gvc, graph_t * g)
index 3e086935477d2fb01265ee7c4f7d370d3c811aea..59776c8aa1a1ee20fa13128affbe8c4ca1a78c9b 100644 (file)
 #undef BETWEEN
 #endif
 #define BETWEEN(a,b,c) (((a) <= (b)) && ((b) <= (c)))
+
+/* true if point p is inside box b */
 #define INSIDE(p,b)    (BETWEEN((b).LL.x,(p).x,(b).UR.x) && BETWEEN((b).LL.y,(p).y,(b).UR.y))
+/* true if boxes b0 and b1 overlap */
 #define OVERLAP(b0,b1) (((b0).UR.x >= (b1).LL.x) && ((b1).UR.x >= (b0).LL.x) && ((b0).UR.y >= (b1).LL.y) && ((b1).UR.y >= (b0).LL.y))
+/* true if box b0 completely contains b1*/
 #define CONTAINS(b0,b1)        (((b0).UR.x >= (b1).UR.x) && ((b0).UR.y >= (b1).UR.y) && ((b0).LL.x <= (b1).LL.x) && ((b0).LL.y <= (b1).LL.y))
 
+/* expand box b as needed to enclose point p */
+#define EXPANDBP(b, p) (b.LL.x = MIN(b.LL.x, p.x), b.LL.y = MIN(b.LL.y, p.y), b.UR.x = MAX(b.UR.x, p.x), b.UR.y = MAX(b.UR.y, p.y))
+/* expand box b0 as needed to enclose box b1 */
+#define EXPANDBB(b0, b1) (b0.LL.x = MIN(b0.LL.x, b1.LL.x), b0.LL.y = MIN(b0.LL.y, b1.LL.y), b0.UR.x = MAX(b0.UR.x, b1.UR.x), b0.UR.y = MAX(b0.UR.y, b1.UR.y))
+
 #define ROUND(f)        ((f>=0)?(int)(f + .5):(int)(f - .5))
 #define RADIANS(deg)   ((deg)/180.0 * PI)
 #define DEGREES(rad)   ((rad)/PI * 180.0)
index c7795678591c93e1b5e55bb27cf51f1fed56c8d0..b163f4b80eb6c3e474bbb708dd7c6889915024e9 100644 (file)
@@ -27,8 +27,7 @@ extern "C" {
     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 boxf arrow_bb(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);
index 070823528e523b790231abdf5d4d531d906e7104..57873dae580c051f6131a75d05efff1a34c38aa1 100644 (file)
@@ -666,6 +666,7 @@ boolean box_contains(box b0, box b1)
 {
     return CONTAINS(b0, b1);
 }
+
 boolean boxf_contains(boxf b0, boxf b1)
 {
     return CONTAINS(b0, b1);
@@ -1923,20 +1924,32 @@ boolean overlap_label(textlabel_t *lp, boxf b)
     return OVERLAP(b, bb);
 }
 
+static boolean overlap_arrow(pointf p, pointf u, double scale, int flag, boxf b)
+{
+    boxf bb;
+
+    bb = arrow_bb(p, u, scale, flag);
+    if (OVERLAP(b, bb)) {
+       /* FIXME - check inside arrow shape */
+       return TRUE;
+    }
+    return FALSE;
+}
+
 static boolean overlap_bezier(bezier bz, boxf b)
 {
     int i, j;
+    point pp;
     box bb;
     boxf bbf;
+    pointf p, u;
 
     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);
+           pp = bz.list[j];
+           EXPANDBP(bb, pp);
         }
         B2BF(bb, bbf);
         if (OVERLAP(b, bbf)) {
@@ -1944,6 +1957,20 @@ static boolean overlap_bezier(bezier bz, boxf b)
             return TRUE;
         }
     }
+
+    /* check arrows */
+    if (bz.sflag) {
+       P2PF(bz.sp, p);
+       P2PF(bz.list[0], u);
+       if (overlap_arrow(p, u, 1, bz.sflag, b))
+           return TRUE;
+    }
+    if (bz.eflag) {
+       P2PF(bz.ep, p);
+       P2PF(bz.list[bz.size - 1], u);
+       if (overlap_arrow(p, u, 1, bz.eflag, b))
+           return TRUE;
+    }
     return FALSE;
 }
 
@@ -1954,15 +1981,11 @@ boolean overlap_edge(edge_t *e, boxf b)
     textlabel_t *lp;
 
     spl = ED_spl(e);
-    if (spl && boxf_overlap(spl->bb, b)) {
+    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;