]> granicus.if.org Git - graphviz/commitdiff
Move makePortLabels() and addEdgeLabels() from neatogen to common
authorerg <devnull@localhost>
Fri, 2 Jul 2010 15:00:49 +0000 (15:00 +0000)
committererg <devnull@localhost>
Fri, 2 Jul 2010 15:00:49 +0000 (15:00 +0000)
lib/common/render.h
lib/common/splines.c

index fdfefcbbcb61baa74cb1d7163dee8a4c31e30450..34089c7558cd22683df21681962ff26c51e4da5e 100644 (file)
@@ -135,6 +135,8 @@ extern "C" {
     extern char **parse_style(char *s);
     extern void place_graph_label(Agraph_t *);
     extern void place_portlabel(edge_t * e, boolean head_p);
+    extern void makePortLabels(edge_t * e);
+    extern void addEdgeLabels(graph_t* g, edge_t * e, pointf rp, pointf rq);
     extern void pop_obj_state(GVJ_t *job);
     extern obj_state_t* push_obj_state(GVJ_t *job);
     extern int rank(graph_t * g, int balance, int maxiter);
index df848b25e49008c4a1a26f8e01ca55965daa0478..b05fc53abe03aff0134b3ef8ee04cb09b3173b41 100644 (file)
@@ -1114,6 +1114,159 @@ makeSelfEdge(path * P, edge_t * edges[], int ind, int cnt, double sizex,
     else assert(0);
 }
 
+/* makePortLabels:
+ * Add head and tail labels if necessary and update bounding box.
+ */
+void makePortLabels(edge_t * e)
+{
+    if (ED_head_label(e) && !ED_head_label(e)->set) {
+       place_portlabel(e, TRUE);
+       updateBB(agraphof(agtail(e)), ED_head_label(e));
+    }
+    if (ED_tail_label(e) && !ED_tail_label(e)->set) {
+       place_portlabel(e, FALSE);
+       updateBB(agraphof(agtail(e)), ED_tail_label(e));
+    }
+}
+
+/* endPoints:
+ * Extract the actual end points of the spline, where
+ * they touch the node.
+ */
+static void endPoints(splines * spl, pointf * p, pointf * q)
+{
+    bezier bz;
+
+    bz = spl->list[0];
+    if (bz.sflag) {
+       *p = bz.sp;
+    }
+    else {
+       *p = bz.list[0];
+    }
+    bz = spl->list[spl->size - 1];
+    if (bz.eflag) {
+       *q = bz.ep;
+    }
+    else {
+       *q = bz.list[bz.size - 1];
+    }
+}
+
+/* polylineMidpoint;
+ * Find midpoint of polyline.
+ * pp and pq are set to the endpoints of the line segment containing it.
+ */
+static pointf
+polylineMidpoint (splines* spl, pointf* pp, pointf* pq)
+{
+    bezier bz;
+    int i, j, k;
+    double d, dist = 0;
+    pointf pf, qf, mf;
+
+    for (i = 0; i < spl->size; i++) {
+       bz = spl->list[i];
+       for (j = 0, k=3; k < bz.size; j+=3,k+=3) {
+           pf = bz.list[j];
+           qf = bz.list[k];
+           dist += DIST(pf, qf);
+       }
+    }
+    dist /= 2;
+    for (i = 0; i < spl->size; i++) {
+       bz = spl->list[i];
+       for (j = 0, k=3; k < bz.size; j+=3,k+=3) {
+           pf = bz.list[j];
+           qf = bz.list[k];
+           d = DIST(pf,qf);
+           if (d >= dist) {
+               *pp = pf;
+               *pq = qf;
+               mf.x = ((qf.x*dist) + (pf.x*(d-dist)))/d; 
+               mf.y = ((qf.y*dist) + (pf.y*(d-dist)))/d; 
+               return mf;
+           }
+           else
+               dist -= d;
+       }
+    }
+    assert (FALSE);   /* should never get here */
+    return mf;
+}
+
+#define LEFTOF(a,b,c) (((a.y - b.y)*(c.x - b.x) - (c.y - b.y)*(a.x - b.x)) > 0)
+#define MAXLABELWD  (POINTS_PER_INCH/2.0)
+
+/* addEdgeLabels:
+ * rp and rq are the port points of the tail and head node.
+ * Adds label, headlabel and taillabel.
+ * The use of 2 and 4 in computing ld.x and ld.y are fudge factors, to
+ * introduce a bit of spacing.
+ * Updates bounding box.
+ * We try to use the actual endpoints of the spline, as they may differ
+ * significantly from rp and rq, but if the spline is degenerate (e.g.,
+ * the nodes overlap), we use rp and rq.
+ */
+void addEdgeLabels(graph_t* g, edge_t * e, pointf rp, pointf rq)
+{
+    int et = EDGE_TYPE (g);
+    pointf p, q;
+    pointf d;                  /* midpoint of segment p-q */
+    point ld;
+    point del;
+    pointf spf;
+    double f, ht, wd, dist2;
+    int leftOf;
+
+    if (ED_label(e) && !ED_label(e)->set) {
+       endPoints(ED_spl(e), &p, &q);
+        if (APPROXEQPT(p, q, MILLIPOINT)) { /* degenerate spline */
+           p = rp;
+           q = rq;
+           spf = p;
+       }
+       else if (et == ET_SPLINE) {
+           d.x = (q.x + p.x) / 2.;
+           d.y = (p.y + q.y) / 2.;
+           spf = dotneato_closest(ED_spl(e), d);
+       }
+       else {   /* ET_PLINE, ET_ORTHO or ET_LINE */
+           spf = polylineMidpoint (ED_spl(e), &p, &q);
+       }
+       del.x = q.x - p.x;
+       del.y = q.y - p.y;
+       dist2 = del.x*del.x + del.y*del.y;
+       ht = (ED_label(e)->dimen.y + 2)/2.0;
+       if (dist2) {
+           wd = (MIN(ED_label(e)->dimen.x + 2, MAXLABELWD))/2.0;
+           leftOf = LEFTOF(p, q, spf);
+           if ((leftOf && (del.y >= 0)) || (!leftOf && (del.y < 0))) {
+               if (del.x*del.y >= 0)
+                   ht *= -1;
+           }
+           else {
+               wd *= -1;
+               if (del.x*del.y < 0)
+                   ht *= -1;
+           }
+           f = (del.y*wd - del.x*ht)/dist2;
+           ld.x = -f*del.y;
+           ld.y = f*del.x;
+       }
+       else {    /* end points the same */
+           ld.x = 0;
+           ld.y = -ht;
+       }
+
+       ED_label(e)->pos.x = spf.x + ld.x;
+       ED_label(e)->pos.y = spf.y + ld.y;
+       ED_label(e)->set = TRUE;
+       updateBB(agraphof(agtail(e)), ED_label(e));
+    }
+    makePortLabels(e);
+}
+
 /* vladimir */
 void place_portlabel(edge_t * e, boolean head_p)
 /* place the {head,tail}label (depending on HEAD_P) of edge E */