]> granicus.if.org Git - graphviz/commitdiff
Fix bug 643;
authorerg <devnull@localhost>
Mon, 14 Mar 2005 23:17:59 +0000 (23:17 +0000)
committererg <devnull@localhost>
Mon, 14 Mar 2005 23:17:59 +0000 (23:17 +0000)
remove unused code;
fix bug with flat edges where all labeled flat edges between two nodes
are given the same label position; also, do not generate label positions
on the previous rank flat edges between adjacent nodes.

lib/dotgen/flat.c
lib/dotgen/position.c

index 213a49b7783a697799005be99ef867983f8849cd..3a396fcde21bdb6dc51ffae688887fe2b63decd4 100644 (file)
@@ -129,7 +129,14 @@ static int flat_limits(graph_t * g, edge_t * e)
     return pos;
 }
 
-static void flat_node(edge_t * e)
+/* flat_node:
+ * Create virtual node representing edge label between
+ * actual ends of edge e. 
+ * This node is characterized by being virtual and having a non-NULL
+ * ND_alg pointing to e.
+ */
+static void 
+flat_node(edge_t * e)
 {
     int r, place, ypos, h2;
     graph_t *g;
@@ -145,10 +152,10 @@ static void flat_node(edge_t * e)
     place = flat_limits(g, e);
     /* grab ypos = LL.y of label box before make_vn_slot() */
     if ((n = GD_rank(g)[r - 1].v[0]))
-       ypos = ND_coord_i(n).y - GD_rank(g)[r - 1].ht2;
+       ypos = ND_coord_i(n).y - GD_rank(g)[r - 1].ht1;
     else {
        n = GD_rank(g)[r].v[0];
-       ypos = ND_coord_i(n).y + GD_rank(g)[r].ht1 + GD_ranksep(g);
+       ypos = ND_coord_i(n).y + GD_rank(g)[r].ht2 + GD_ranksep(g);
     }
     vn = make_vn_slot(g, r - 1, place);
     dimen = ED_label(e)->dimen;
@@ -175,6 +182,8 @@ static void flat_node(edge_t * e)
        GD_rank(g)[r - 1].ht1 = h2;
     if (GD_rank(g)[r - 1].ht2 < h2)
        GD_rank(g)[r - 1].ht2 = h2;
+    ND_alg(vn) = e;
+    ED_alg(e) = vn;
 }
 
 static void abomination(graph_t * g)
@@ -197,32 +206,120 @@ static void abomination(graph_t * g)
     GD_minrank(g)--;
 }
 
-int flat_edges(graph_t * g)
+/* flatAdjacent:
+ * Return true if tn and hn are adjacent. 
+ * Assume e is flat.
+ */
+static int
+flatAdjacent (edge_t* e)
+{
+    node_t* tn = e->tail;
+    node_t* hn = e->head;
+    int i, lo, hi;
+    node_t* n;
+    rank_t *rank;
+
+    if (ND_order(tn) < ND_order(hn)) {
+       lo = ND_order(tn);
+       hi = ND_order(hn);
+    }
+    else {
+       lo = ND_order(hn);
+       hi = ND_order(tn);
+    }
+    rank = &(GD_rank(tn->graph)[ND_rank(tn)]);
+    for (i = lo + 1; i < hi; i++) {
+       n = rank->v[i];
+       if ((ND_node_type(n) == VIRTUAL && ND_label(n)) || 
+             ND_node_type(n) == NORMAL)
+           break;
+    }
+    return (i == hi);
+}
+/* flat_edges:
+ * Process flat edges.
+ * First, mark flat edges as having adjacent endpoints or not.
+ *
+ * Second, if there are edge labels, nodes are placed on ranks 0,2,4,...
+ * If we have a labeled flat edge on rank 0, add a rank -1.
+ *
+ * Finally, create label information. Add a virtual label node in the 
+ * previous rank for each labeled, non-adjacent flat edge. If this is 
+ * done for any edge, return true, so that main code will reset y coords.
+ * For labeled adjacent flat edges, store label width in representative edge.
+ * FIX: We should take into account any extra height needed for the latter
+ * labels.
+ * 
+ * We leave equivalent flat edges in ND_other. Their ED_virt field should
+ * still point to the class representative.
+ */
+int 
+flat_edges(graph_t * g)
 {
     int i, j, reset = FALSE;
     node_t *n;
     edge_t *e;
+    int found = FALSE;
+
+    for (n = GD_nlist(g); n; n = ND_next(n)) {
+       if (!ND_flat_out(n).list) continue; 
+       for (j = 0; (e = ND_flat_out(n).list[j]); j++) {
+           if (flatAdjacent (e)) ED_adjacent(e) = 1;
+       }
+    }
 
     if ((GD_rank(g)[0].flat) || (GD_n_cluster(g) > 0)) {
        for (i = 0; (n = GD_rank(g)[0].v[i]); i++) {
            for (j = 0; (e = ND_flat_in(n).list[j]); j++) {
-               if (ED_label(e)) {
+               if ((ED_label(e)) && !ED_adjacent(e)) {
                    abomination(g);
+                   found = TRUE;
                    break;
                }
            }
-           if (e)
+           if (found)
                break;
        }
     }
 
     rec_save_vlists(g);
     for (n = GD_nlist(g); n; n = ND_next(n)) {
-       if (ND_flat_out(n).list)
+          /* if n is the tail of any flat edge, one will be in flat_out */
+       if (ND_flat_out(n).list) {
            for (i = 0; (e = ND_flat_out(n).list[i]); i++) {
-               reset = TRUE;
-               flat_node(e);
+               if (ED_label(e)) {
+                   if (ED_adjacent(e)) {
+                       if (GD_flip(g)) ED_dist(e) = ED_label(e)->dimen.y;
+                       else ED_dist(e) = ED_label(e)->dimen.x; 
+                   }
+                   else {
+                       reset = TRUE;
+                       flat_node(e);
+                   }
+               }
            }
+           for (j = 0; j < ND_other(n).size; j++) {
+               edge_t* le;
+               e = ND_other(n).list[j];
+               if (ND_rank(e->tail) != ND_rank(e->head)) continue;
+               le = e;
+               while (ED_to_virt(le)) le = ED_to_virt(le);
+               ED_adjacent(e) = ED_adjacent(le); 
+               if (ED_label(e)) {
+                   if (ED_adjacent(e)) {
+                       double lw;
+                       if (GD_flip(g)) lw = ED_label(e)->dimen.y;
+                       else lw = ED_label(e)->dimen.x; 
+                       ED_dist(le) = MAX(lw,ED_dist(le));
+                   }
+                   else {
+                       reset = TRUE;
+                       flat_node(e);
+                   }
+               }
+           }
+       }
     }
     if (reset)
        rec_reset_vlists(g);
index 1a12725aa9465018029582378b77a891b42f8265..749d8d2cb2f21430bb15fc3086c8dbb172593ee2 100644 (file)
@@ -57,6 +57,59 @@ dumpNS (graph_t * g)
 }
 #endif
 
+/* connectGraph:
+ * When source and/or sink nodes are defined, it is possible that
+ * after the auxiliary edges are added, the graph may still have 2 or
+ * 3 components. To fix this, we put trivial constraints connecting the
+ * first items of each rank.
+ */
+static void
+connectGraph (graph_t* g)
+{
+    int i, j, r, found;
+    node_t* tp;
+    node_t* hp;
+    node_t* sn;
+    edge_t* e;
+    rank_t* rp;
+
+    for (r = GD_minrank(g); r < GD_maxrank(g); r++) {
+       rp = GD_rank(g)+r;
+       found =FALSE;
+        tp = NULL;
+       for (i = 0; i < rp->n; i++) {
+           tp = rp->v[i];
+           if (ND_save_out(tp).list) {
+               for (j = 0; (e = ND_save_out(tp).list[j]); j++) {
+                   if ((ND_rank(e->head) > r) || (ND_rank(e->tail) > r)) {
+                       found = TRUE;
+                       break;
+                   }
+               }
+               if (found) break;
+           }
+           if (ND_save_in(tp).list) {
+               for (j = 0; (e = ND_save_in(tp).list[j]); j++) {
+                   if ((ND_rank(e->tail) > r) || (ND_rank(e->head) > r)) {
+                       found = TRUE;
+                       break;
+                   }
+               }
+               if (found) break;
+           }
+       }
+       if (found || !tp) continue;
+       tp = rp->v[0];
+       hp = (rp+1)->v[0];
+       assert (hp);
+       sn = virtual_node(g);
+       ND_node_type(sn) = SLACKNODE;
+       make_aux_edge(sn, tp, 0, 0);
+       make_aux_edge(sn, hp, 0, 0);
+       ND_rank(sn) = MIN(ND_rank(tp), ND_rank(hp));
+    }
+}
+
 void dot_position(graph_t * g)
 {
     if (GD_nlist(g) == NULL)
@@ -69,7 +122,10 @@ void dot_position(graph_t * g)
     if (flat_edges(g))
        set_ycoords(g);
     create_aux_edges(g);
-    rank(g, 2, nsiter2(g));    /* LR balance == 2 */
+    if (rank(g, 2, nsiter2(g))) { /* LR balance == 2 */
+       connectGraph (g);
+       assert(rank(g, 2, nsiter2(g)) == 0);
+    }
     set_xcoords(g);
     set_aspect(g);
     remove_aux_edges(g);       /* must come after set_aspect since we now
@@ -87,7 +143,6 @@ static int nsiter2(graph_t * g)
     return maxiter;
 }
 
-static int searchcnt;
 static int go(node_t * u, node_t * v)
 {
     int i;
@@ -104,8 +159,6 @@ static int go(node_t * u, node_t * v)
 
 static int canreach(node_t * u, node_t * v)
 {
-    if (++searchcnt == 0)
-       searchcnt = 1;
     return go(u, v);
 }
 
@@ -139,20 +192,33 @@ static void allocate_aux_edges(graph_t * g)
     }
 }
 
-static void make_LR_constraints(graph_t * g)
+/* make_LR_constraints:
+ */
+static void 
+make_LR_constraints(graph_t * g)
 {
     int i, j, k;
     int sw;                    /* self width */
     int m0, m1;
-    int width;
-    edge_t *e, *e0, *e1, *f, *ff;
+    int width, sep[2];
+    int nodesep;      /* separation between nodes on same rank */
+    edge_t *e, *e0, *e1, *ff;
     node_t *u, *v, *t0, *h0;
     rank_t *rank = GD_rank(g);
 
+    /* Use smaller separation on odd ranks if g has edge labels */
+    if (GD_has_labels(g) & EDGE_LABEL) {
+       sep[0] = GD_nodesep(g);
+       sep[1] = 5;
+    }
+    else {
+       sep[1] = sep[0] = GD_nodesep(g);
+    }
     /* make edges to constrain left-to-right ordering */
     for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
        int last;
        last = rank[i].v[0]->u.rank = 0;
+       nodesep = sep[i & 1];
        for (j = 0; j < rank[i].n; j++) {
            u = rank[i].v[j];
            ND_mval(u) = ND_rw_i(u);    /* keep it somewhere safe */
@@ -175,15 +241,36 @@ static void make_LR_constraints(graph_t * g)
            }
            v = rank[i].v[j + 1];
            if (v) {
-               width = ND_rw_i(u) + ND_lw_i(v) + GD_nodesep(g);
+               width = ND_rw_i(u) + ND_lw_i(v) + nodesep;
                e0 = make_aux_edge(u, v, width, 0);
                last = (ND_rank(v) = last + width);
            }
 
+           /* constraints from labels of flat edges on previous rank */
+           if ((e = (edge_t*)ND_alg(u))) {
+               e0 = ND_save_out(u).list[0];
+               e1 = ND_save_out(u).list[1];
+               if (ND_order(e0->head) > ND_order(e1->head)) {
+                   ff = e0;
+                   e0 = e1;
+                   e1 = ff;
+               }
+               m0 = (ED_minlen(e) * GD_nodesep(g)) / 2;
+               m1 = m0 + ND_rw_i(e0->head) + ND_lw_i(e0->tail);
+               /* these guards are needed because the flat edges
+                * work very poorly with cluster layout */
+               if (canreach(e0->tail, e0->head) == FALSE)
+                   make_aux_edge(e0->head, e0->tail, m1,
+                       ED_weight(e));
+               m1 = m0 + ND_rw_i(e1->tail) + ND_lw_i(e1->head);
+               if (canreach(e1->head, e1->tail) == FALSE)
+                   make_aux_edge(e1->tail, e1->head, m1,
+                       ED_weight(e));
+           }
+
            /* position flat edge endpoints */
            for (k = 0; k < ND_flat_out(u).size; k++) {
                e = ND_flat_out(u).list[k];
-               v = e->head;
                if (ND_order(e->tail) < ND_order(e->head)) {
                    t0 = e->tail;
                    h0 = e->head;
@@ -192,40 +279,26 @@ static void make_LR_constraints(graph_t * g)
                    h0 = e->tail;
                }
 
-               /* case 1: flat edge with a label */
-               if ((f = ED_to_virt(e))) {
-                   while (ED_to_virt(f))
-                       f = ED_to_virt(f);
-                   e0 = ND_save_out(f->tail).list[0];
-                   e1 = ND_save_out(f->tail).list[1];
-                   if (ND_order(e0->head) > ND_order(e1->head)) {
-                       ff = e0;
-                       e0 = e1;
-                       e1 = ff;
-                   }
-                   m0 = (ED_minlen(e) * GD_nodesep(g)) / 2;
-                   m1 = m0 + ND_rw_i(e0->head) + ND_lw_i(e0->tail);
-                   /* these guards are needed because the flat edges
-                      work very poorly with cluster layout */
-                   if (canreach(e0->tail, e0->head) == FALSE)
-                       make_aux_edge(e0->head, e0->tail, m1,
-                                     ED_weight(e));
-                   m1 = m0 + ND_rw_i(e1->tail) + ND_lw_i(e1->head);
-                   if (canreach(e1->head, e1->tail) == FALSE)
-                       make_aux_edge(e1->tail, e1->head, m1,
-                                     ED_weight(e));
-                   continue;
-               }
-
-               m0 = ED_minlen(e) * GD_nodesep(g) + ND_rw_i(t0) +
-                   ND_lw_i(h0);
+               width = ND_rw_i(t0) + ND_lw_i(h0);
+               m0 = ED_minlen(e) * GD_nodesep(g) + width;
 
-               if ((e0 = find_fast_edge(t0, h0)))
-                   /* case 2: flat edge between neighbors */
+               if ((e0 = find_fast_edge(t0, h0))) {
+                   /* flat edge between adjacent neighbors 
+                     * ED_dist contains the largest label width.
+                     */
+                   m0 = MAX(m0, width + GD_nodesep(g) + ROUND(ED_dist(e)));
                    ED_minlen(e0) = MAX(ED_minlen(e0), m0);
-               else
-                   /* case 3: flat edge between non-neighbors */
+               }
+               else if (!ED_label(e)) {
+                   /* unlabeled flat edge between non-neighbors 
+                    * ED_minlen(e) is max of ED_minlen of all equivalent 
+                     * edges.
+                     */
                    make_aux_edge(t0, h0, m0, ED_weight(e));
+               }
+               /* labeled flat edges between non-neighbors have already
+                 * been constrained by the label above. 
+                 */ 
            }
        }
     }
@@ -472,7 +545,11 @@ static void remove_aux_edges(graph_t * g)
     GD_nlist(g)->u.prev = NULL;
 }
 
-static void set_xcoords(graph_t * g)
+/* set_xcoords:
+ * Set x coords of nodes.
+ */
+static void 
+set_xcoords(graph_t * g)
 {
     int i, j;
     node_t *v;