From: erg Date: Fri, 2 Jul 2010 15:00:49 +0000 (+0000) Subject: Move makePortLabels() and addEdgeLabels() from neatogen to common X-Git-Tag: LAST_LIBGRAPH~32^2~1289 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8785a9ea2dd12233c15852abc3afbb1eb1558603;p=graphviz Move makePortLabels() and addEdgeLabels() from neatogen to common --- diff --git a/lib/common/render.h b/lib/common/render.h index fdfefcbbc..34089c755 100644 --- a/lib/common/render.h +++ b/lib/common/render.h @@ -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); diff --git a/lib/common/splines.c b/lib/common/splines.c index df848b25e..b05fc53ab 100644 --- a/lib/common/splines.c +++ b/lib/common/splines.c @@ -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 */