]> granicus.if.org Git - graphviz/commitdiff
Fix bug 2129
authorerg <devnull@localhost>
Sun, 6 Feb 2011 00:19:45 +0000 (00:19 +0000)
committererg <devnull@localhost>
Sun, 6 Feb 2011 00:19:45 +0000 (00:19 +0000)
lib/common/render.h
lib/common/routespl.c
lib/dotgen/dotsplines.c

index 5b58adec0ea1153e4baf2891d28ef095fa1c177b..1283739c053e8f678f836eb42c77aa6122f55b74 100644 (file)
@@ -144,6 +144,7 @@ extern "C" {
     extern void routesplinesinit(void);
     extern pointf *routesplines(path *, int *);
     extern void routesplinesterm(void);
+    extern pointf* simpleSplineRoute (pointf, pointf, Ppoly_t, int*, int);
     extern pointf *routepolylines(path* pp, int* npoints);
     extern int selfRightSpace (edge_t* e);
     extern void setup_graph(GVC_t * gvc, graph_t * g);
index 4d310adfd0c40f0e18fbf6bf88b030ece3566b11..2da3bef58a3f95ac037fde8b1e80437781e99b63 100644 (file)
@@ -220,6 +220,62 @@ static int debugleveln(edge_t* realedge, int i)
 }
 #endif  /* DEBUG */
 
+
+
+/* simpleSplineRoute:
+ * Given a simple (ccw) polygon, route an edge from tp to hp.
+ */
+pointf*
+simpleSplineRoute (pointf tp, pointf hp, Ppoly_t poly, int* n_spl_pts,
+    int polyline)
+{
+    Ppolyline_t pl, spl;
+    Ppoint_t eps[2];
+    Pvector_t evs[2];
+    int i;
+
+    eps[0] = (Ppoint_t)tp;
+    eps[1] = (Ppoint_t)hp;
+    if (Pshortestpath(&poly, eps, &pl) == -1)
+        return NULL;
+
+    if (polyline)
+       make_polyline (pl, &spl);
+    else {
+       if (poly.pn > edgen) {
+           edges = ALLOC(poly.pn, edges, Pedge_t);
+           edgen = poly.pn;
+       }
+       for (i = 0; i < poly.pn; i++) {
+           edges[i].a = poly.ps[i];
+           edges[i].b = poly.ps[(i + 1) % poly.pn];
+       }
+#if 0
+       if (pp->start.constrained) {
+           evs[0].x = cos(pp->start.theta);
+           evs[0].y = sin(pp->start.theta);
+       } else
+#endif
+           evs[0].x = evs[0].y = 0;
+#if 0
+       if (pp->end.constrained) {
+           evs[1].x = -cos(pp->end.theta);
+           evs[1].y = -sin(pp->end.theta);
+       } else
+#endif
+           evs[1].x = evs[1].y = 0;
+       if (Proutespline(edges, poly.pn, pl, evs, &spl) == -1)
+            return NULL;
+    }
+
+    mkspacep(spl.pn);
+    for (i = 0; i < spl.pn; i++) {
+        ps[i] = spl.ps[i];
+    }
+    *n_spl_pts = spl.pn;
+    return ps;
+}
+
 /* routesplinesinit:
  * Data initialized once until matching call to routeplineterm
  * Allows recursive calls to dot
index 5f4855b510657e18308d47c267b4c080df9d086d..1520a4c577b22e1b7bdf17c379a8b2c7b13eb2bf 100644 (file)
@@ -826,6 +826,209 @@ transformf (pointf p, pointf del, int flip)
     return add_pointf(p, del);
 }
 
+/* edgelblcmpfn:
+ * lexicographically order edges by
+ *  - has label
+ *  - label is wider
+ *  - label is higher
+ */
+static int edgelblcmpfn(edge_t** ptr0, edge_t** ptr1)
+{
+    edge_t *e0, *e1;
+    pointf sz0, sz1;
+
+    e0 = (edge_t *) * ptr0;
+    e1 = (edge_t *) * ptr1;
+
+    if (ED_label(e0)) {
+       if (ED_label(e1)) {
+           sz0 = ED_label(e0)->dimen;
+           sz1 = ED_label(e1)->dimen;
+           if (sz0.x > sz1.x) return -1;
+           else if (sz0.x < sz1.x) return 1;
+           else if (sz0.y > sz1.y) return -1;
+           else if (sz0.y < sz1.y) return 1;
+           else return 0;
+       }
+       else
+           return -1;
+    }
+    else if (ED_label(e1)) {
+       return 1;
+    }
+    else
+       return 0;
+}
+
+#define LBL_SPACE  6  /* space between labels, in points */
+
+/* makeSimpleFlatLabels:
+ * This handles the second simplest case for flat edges between
+ * two adjacent nodes. We still invoke a dot on a rotated problem
+ * to handle edges with ports. This usually works, but fails for
+ * records because of their weird nature.
+ */
+static void
+makeSimpleFlatLabels (node_t* tn, node_t* hn, edge_t** edges, int ind, int cnt, int et, int n_lbls)
+{
+    pointf *ps;
+    Ppoly_t poly;
+    int pn;
+    edge_t* e = edges[ind];
+    pointf points[10], tp, hp;
+    int i, pointn;
+    double leftend, rightend, ctrx, ctry, miny, maxy;
+    double uminx, umaxx;
+    double lminx, lmaxx;
+
+    edge_t** earray = N_NEW(cnt, edge_t*);
+
+    for (i = 0; i < cnt; i++) {
+       earray[i] = edges[ind + i];
+    }
+
+    qsort (earray, cnt, sizeof(edge_t*), (qsort_cmpf) edgelblcmpfn);
+
+    tp = add_pointf(ND_coord(tn), ED_tail_port(e).p);
+    hp = add_pointf(ND_coord(hn), ED_head_port(e).p);
+
+    leftend = tp.x+ND_rw(tn);
+    rightend = hp.x-ND_lw(hn);
+    ctrx = (leftend + rightend)/2.0;
+    
+    /* do first edge */
+    pointn = 0;
+    points[pointn++] = tp;
+    points[pointn++] = tp;
+    points[pointn++] = hp;
+    points[pointn++] = hp;
+#ifndef WITH_CGRAPH
+    clip_and_install(e, e->head, points, pointn, &sinfo);
+#else /* WITH_CGRAPH */
+    clip_and_install(e, aghead(e), points, pointn, &sinfo);
+#endif /* WITH_CGRAPH */
+    ED_label(e)->pos.x = ctrx;
+    ED_label(e)->pos.y = tp.y + (ED_label(e)->dimen.y+LBL_SPACE)/2.0;
+    ED_label(e)->set = TRUE;
+
+    miny = tp.y + LBL_SPACE/2.0;
+    maxy = miny + ED_label(e)->dimen.y;
+    uminx = ctrx - (ED_label(e)->dimen.x)/2.0;
+    umaxx = ctrx + (ED_label(e)->dimen.x)/2.0;
+
+    for (i = 1; i < n_lbls; i++) {
+       e = edges[ind + i];
+       if (i%2) {  /* down */
+           if (i == 1) {
+               lminx = ctrx - (ED_label(e)->dimen.x)/2.0;
+               lmaxx = ctrx + (ED_label(e)->dimen.x)/2.0;
+           }
+           miny -= LBL_SPACE + ED_label(e)->dimen.y;
+           points[0] = tp;
+           points[1].x = tp.x;
+           points[1].y = miny - LBL_SPACE;
+           points[2].x = hp.x;
+           points[2].y = points[1].y;
+           points[3] = hp;
+           points[4].x = lmaxx;
+           points[4].y = hp.y;
+           points[5].x = lmaxx;
+           points[5].y = miny;
+           points[6].x = lminx;
+           points[6].y = miny;
+           points[7].x = lminx;
+           points[7].y = tp.y;
+           ctry = miny + (ED_label(e)->dimen.y)/2.0;
+       }
+       else {   /* up */
+           points[0] = tp;
+           points[1].x = uminx;
+           points[1].y = tp.y;
+           points[2].x = uminx;
+           points[2].y = maxy;
+           points[3].x = umaxx;
+           points[3].y = maxy;
+           points[4].x = umaxx;
+           points[4].y = hp.y;
+           points[5].x = hp.x;
+           points[5].y = hp.y;
+           points[6].x = hp.x;
+           points[6].y = maxy + LBL_SPACE;
+           points[7].x = tp.x;
+           points[7].y = maxy + LBL_SPACE;
+           ctry =  maxy + (ED_label(e)->dimen.y)/2.0 + LBL_SPACE;
+           maxy += ED_label(e)->dimen.y + LBL_SPACE;
+       }
+       poly.pn = 8;
+       poly.ps = (Ppoint_t*)points;
+       ps = simpleSplineRoute (tp, hp, poly, &pn, et == ET_PLINE);
+       if (pn == 0) return;
+       ED_label(e)->pos.x = ctrx;
+       ED_label(e)->pos.y = ctry;
+       ED_label(e)->set = TRUE;
+#ifndef WITH_CGRAPH
+       clip_and_install(e, e->head, ps, pn, &sinfo);
+#else /* WITH_CGRAPH */
+       clip_and_install(e, aghead(e), ps, pn, &sinfo);
+#endif /* WITH_CGRAPH */
+    }
+
+    /* edges with no labels */
+    for (; i < cnt; i++) {
+       e = edges[ind + i];
+       if (i%2) {  /* down */
+           if (i == 1) {
+               lminx = (2*leftend + rightend)/3.0;
+               lmaxx = (leftend + 2*rightend)/3.0;
+           }
+           miny -= LBL_SPACE;
+           points[0] = tp;
+           points[1].x = tp.x;
+           points[1].y = miny - LBL_SPACE;
+           points[2].x = hp.x;
+           points[2].y = points[1].y;
+           points[3] = hp;
+           points[4].x = lmaxx;
+           points[4].y = hp.y;
+           points[5].x = lmaxx;
+           points[5].y = miny;
+           points[6].x = lminx;
+           points[6].y = miny;
+           points[7].x = lminx;
+           points[7].y = tp.y;
+       }
+       else {   /* up */
+           points[0] = tp;
+           points[1].x = uminx;
+           points[1].y = tp.y;
+           points[2].x = uminx;
+           points[2].y = maxy;
+           points[3].x = umaxx;
+           points[3].y = maxy;
+           points[4].x = umaxx;
+           points[4].y = hp.y;
+           points[5].x = hp.x;
+           points[5].y = hp.y;
+           points[6].x = hp.x;
+           points[6].y = maxy + LBL_SPACE;
+           points[7].x = tp.x;
+           points[7].y = maxy + LBL_SPACE;
+           maxy += + LBL_SPACE;
+       }
+       poly.pn = 8;
+       poly.ps = (Ppoint_t*)points;
+       ps = simpleSplineRoute (tp, hp, poly, &pn, et == ET_PLINE);
+       if (pn == 0) return;
+#ifndef WITH_CGRAPH
+       clip_and_install(e, e->head, ps, pn, &sinfo);
+#else /* WITH_CGRAPH */
+       clip_and_install(e, aghead(e), ps, pn, &sinfo);
+#endif /* WITH_CGRAPH */
+    }
+   
+    free (earray);
+}
+
 /* makeSimpleFlat:
  */
 static void
@@ -875,6 +1078,7 @@ makeSimpleFlat (node_t* tn, node_t* hn, edge_t** edges, int ind, int cnt, int et
 /* make_flat_adj_edges:
  * In the simple case, with no labels or ports, this creates a simple
  * spindle of splines.
+ * If there are only labels, cobble something together.
  * Otherwise, we run dot recursively on the 2 nodes and the edges, 
  * essentially using rankdir=LR, to get the needed spline info.
  */
@@ -903,9 +1107,15 @@ make_flat_adj_edges(path* P, edge_t** edges, int ind, int cnt, edge_t* e0,
        if (ED_tail_port(e).defined || ED_head_port(e).defined) ports = 1;
     }
 
-    /* flat edges without ports and labels can go straight left to right */
-    if ((labels == 0) && (ports == 0)) {
-       makeSimpleFlat (tn, hn, edges, ind, cnt, et);
+    if (ports == 0) {
+       /* flat edges without ports and labels can go straight left to right */
+       if (labels == 0) {
+           makeSimpleFlat (tn, hn, edges, ind, cnt, et);
+       }
+       /* flat edges without ports but with labels take more work */
+       else {
+           makeSimpleFlatLabels (tn, hn, edges, ind, cnt, et, labels);
+       }
        return;
     }