/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/dotgen/sameport.c

Go to the documentation of this file.
00001 /* $Id: sameport.c,v 1.7 2006/05/22 17:39:35 erg Exp $ $Revision: 1.7 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 
00018 /*  vladimir@cs.ualberta.ca,  9-Dec-1997
00019  *      merge edges with specified samehead/sametail onto the same port
00020  */
00021 
00022 #include        "dot.h"
00023 
00024 
00025 #define MAXSAME 5               /* max no of same{head,tail} groups on a node */
00026 
00027 typedef struct same_t {
00028     char *id;                   /* group id */
00029     elist l;                    /* edges in the group */
00030     int n_arr;                  /* number of edges with arrows */
00031     double arr_len;             /* arrow length of an edge in the group */
00032 } same_t;
00033 static int n_same;              /* number of same_t groups on current node */
00034 
00035 static void sameedge(same_t * same, node_t * n, edge_t * e, char *id);
00036 static void sameport(node_t * u, elist * l, double arr_len);
00037 
00038 void dot_sameports(graph_t * g)
00039 /* merge edge ports in G */
00040 {
00041     node_t *n;
00042     edge_t *e;
00043     char *id;
00044     same_t same[MAXSAME];
00045     int i;
00046 
00047     E_samehead = agfindattr(g->proto->e, "samehead");
00048     E_sametail = agfindattr(g->proto->e, "sametail");
00049     if (!(E_samehead || E_sametail))
00050         return;
00051     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00052         n_same = 0;
00053         for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
00054             if (e->head == n && E_samehead &&
00055                 (id = agxget(e, E_samehead->index))[0])
00056                 sameedge(same, n, e, id);
00057             else if (e->tail == n && E_sametail &&
00058                      (id = agxget(e, E_sametail->index))[0])
00059                 sameedge(same, n, e, id);
00060         }
00061         for (i = 0; i < n_same; i++) {
00062             if (same[i].l.size > 1)
00063                 sameport(n, &same[i].l, same[i].arr_len);
00064             free_list(same[i].l);
00065             /* I sure hope I don't need to free the char* id */
00066         }
00067     }
00068 }
00069 
00070 static void sameedge(same_t * same, node_t * n, edge_t * e, char *id)
00071 /* register E in the SAME structure of N under ID. Uses static int N_SAME */
00072 {
00073     int i, sflag, eflag, flag;
00074 
00075     for (i = 0; i < n_same; i++)
00076         if (streq(same[i].id, id)) {
00077             elist_append(e, same[i].l);
00078             goto set_arrow;
00079         }
00080     if (++n_same > MAXSAME) {
00081         agerr(AGERR, "too many same{head,tail} groups for node %s\n",
00082               n->name);
00083         return;
00084     }
00085     alloc_elist(1, same[i].l);
00086     elist_fastapp(e, same[i].l);
00087     same[i].id = id;
00088     same[i].n_arr = 0;
00089     same[i].arr_len = 0;
00090   set_arrow:
00091     arrow_flags(e, &sflag, &eflag);
00092     if ((flag = e->head == n ? eflag : sflag))
00093         same[i].arr_len =
00094             /* only consider arrows if there's exactly one arrow */
00095             (++same[i].n_arr == 1) ? arrow_length(e, flag) : 0;
00096 }
00097 
00098 static void sameport(node_t * u, elist * l, double arr_len)
00099 /* make all edges in L share the same port on U. The port is placed on the
00100    node boundary and the average angle between the edges. FIXME: this assumes
00101    naively that the edges are straight lines, which is wrong if they are long.
00102    In that case something like concentration could be done.
00103 
00104    An arr_port is also computed that's ARR_LEN away from the node boundary.
00105    It's used for edges that don't themselves have an arrow.
00106 */
00107 {
00108     node_t *v;
00109     edge_t *e, *f;
00110     int i;
00111     double x = 0, y = 0, x1, y1, x2, y2, r;
00112     port prt;
00113     int sflag, eflag;
00114 #ifdef OLD
00115     int ht;
00116     port arr_prt;
00117 #endif
00118 
00119     /* Compute the direction vector (x,y) of the average direction. We compute
00120        with direction vectors instead of angles because else we have to first
00121        bring the angles within PI of each other. av(a,b)!=av(a,b+2*PI) */
00122     for (i = 0; i < l->size; i++) {
00123         e = l->list[i];
00124         if (e->head == u)
00125             v = e->tail;
00126         else
00127             v = e->head;
00128         x1 = ND_coord_i(v).x - ND_coord_i(u).x;
00129         y1 = ND_coord_i(v).y - ND_coord_i(u).y;
00130         r = hypot(x1, y1);
00131         x += x1 / r;
00132         y += y1 / r;
00133     }
00134     r = hypot(x, y);
00135     x /= r;
00136     y /= r;
00137 
00138     /* (x1,y1),(x2,y2) is a segment that must cross the node boundary */
00139     x1 = ND_coord_i(u).x;
00140     y1 = ND_coord_i(u).y;       /* center of node */
00141     r = MAX(ND_lw_i(u) + ND_rw_i(u), ND_ht_i(u) + GD_ranksep(u->graph));        /* far away */
00142     x2 = x * r + ND_coord_i(u).x;
00143     y2 = y * r + ND_coord_i(u).y;
00144     {                           /* now move (x1,y1) to the node boundary */
00145         point curve[4];         /* bezier control points for a straight line */
00146         curve[0].x = ROUND(x1);
00147         curve[0].y = ROUND(y1);
00148         curve[1].x = ROUND((2 * x1 + x2) / 3);
00149         curve[1].y = ROUND((2 * y1 + y2) / 3);
00150         curve[2].x = ROUND((2 * x2 + x1) / 3);
00151         curve[2].y = ROUND((2 * y2 + y1) / 3);
00152         curve[3].x = ROUND(x2);
00153         curve[3].y = ROUND(y2);
00154 
00155         shape_clip(u, curve);
00156         x1 = curve[0].x - ND_coord_i(u).x;
00157         y1 = curve[0].y - ND_coord_i(u).y;
00158     }
00159 
00160     /* compute PORT on the boundary */
00161     prt.p.x = ROUND(x1);
00162     prt.p.y = ROUND(y1);
00163     prt.bp = 0;
00164     prt.order =
00165         (MC_SCALE * (ND_lw_i(u) + prt.p.x)) / (ND_lw_i(u) + ND_rw_i(u));
00166     prt.constrained = FALSE;
00167     prt.defined = TRUE;
00168     prt.clip = FALSE;
00169     prt.theta = 0;
00170     prt.side = 0;
00171 
00172 #ifdef OBSOLETE
00173 /* This is commented because a version of gcc cannot handle it otherwise.
00174 This code appears obsolete and wrong. First, we don't use arr_prt
00175 anymore, as we have previously ifdef'ed out the code below where it
00176 is used. In addition, it resets the rank height. But we've already
00177 positioned the nodes, so it can cause the new ht2, when added to a
00178 node's y coordinate to give a value in the middle of the rank above.
00179 This causes havoc when constructing box for spline routing.
00180 See bug 419.
00181 If we really want to make room for arrowheads, this should be done in
00182 the general case that the user sets a small ranksep, and requires repositioning
00183 nodes and maintaining equal separation when specified
00184 */
00185     /* compute ARR_PORT at a distance ARR_LEN away from the boundary */
00186     if ((arr_prt.defined = arr_len && TRUE)) {
00187         arr_prt.p.x = ROUND(x1 + x * arr_len);
00188         arr_prt.p.y = ROUND(y1 + y * arr_len);
00189         arr_prt.bp = 0;
00190         arr_prt.side = 0;
00191         arr_prt.constrained = FALSE;
00192         arr_prt.order =
00193             (MC_SCALE * (ND_lw_i(u) + arr_prt.p.x)) / (ND_lw_i(u) +
00194                                                        ND_rw_i(u));
00195         /* adjust ht so that splines.c uses feasible boxes.
00196            FIXME: I guess this adds an extra box for all edges in the rank */
00197         if (u == l->list[0]->head) {
00198             if (GD_rank(u->graph)[ND_rank(u)].ht2 <
00199                 (ht = ABS(arr_prt.p.y)))
00200                 GD_rank(u->graph)[ND_rank(u)].ht2 = ht;
00201         } else {
00202             if (GD_rank(u->graph)[ND_rank(u)].ht1 <
00203                 (ht = ABS(arr_prt.p.y)))
00204                 GD_rank(u->graph)[ND_rank(u)].ht1 = ht;
00205         }
00206     }
00207 #endif
00208 
00209     /* assign one of the ports to every edge */
00210     for (i = 0; i < l->size; i++) {
00211         e = l->list[i];
00212         arrow_flags(e, &sflag, &eflag);
00213 #ifndef OBSOLETE
00214         for (; e; e = ED_to_virt(e)) {  /* assign to all virt edges of e */
00215             for (f = e; f;
00216                  f = ED_edge_type(f) == VIRTUAL &&
00217                  ND_node_type(f->head) == VIRTUAL &&
00218                  ND_out(f->head).size == 1 ?
00219                  ND_out(f->head).list[0] : NULL) {
00220                 if (f->head == u)
00221                     ED_head_port(f) = prt;
00222                 if (f->tail == u)
00223                     ED_tail_port(f) = prt;
00224             }
00225             for (f = e; f;
00226                  f = ED_edge_type(f) == VIRTUAL &&
00227                  ND_node_type(f->tail) == VIRTUAL &&
00228                  ND_in(f->tail).size == 1 ?
00229                  ND_in(f->tail).list[0] : NULL) {
00230                 if (f->head == u)
00231                     ED_head_port(f) = prt;
00232                 if (f->tail == u)
00233                     ED_tail_port(f) = prt;
00234             }
00235         }
00236 #else
00237         for (; e; e = ED_to_virt(e)) {  /* assign to all virt edges of e */
00238             if (e->head == u)
00239                 ED_head_port(e) =
00240                     arr_port.defined && !eflag ? arr_prt : prt;
00241             if (e->tail == u)
00242                 ED_tail_port(e) =
00243                     arr_port.defined && !sflag ? arr_prt : prt;
00244         }
00245 #endif
00246     }
00247 
00248     ND_has_port(u) = TRUE;      /* kinda pointless, because mincross is already done */
00249 }

Generated on Mon Mar 31 19:03:26 2008 for Graphviz by  doxygen 1.5.1