/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/common/arrows.c

Go to the documentation of this file.
00001 /* $Id: arrows.c,v 1.27 2008/02/29 22:00:16 ellson Exp $ $Revision: 1.27 $ */
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 #include "render.h"
00019 
00020 #define EPSILON .0001
00021 
00022 /* standard arrow length in points */
00023 #define ARROW_LENGTH 10.
00024 
00025 /* arrow types */
00026 #define ARR_TYPE_NONE     (ARR_NONE)
00027 #define ARR_TYPE_NORM     1
00028 #define ARR_TYPE_CROW     2
00029 #define ARR_TYPE_TEE      3
00030 #define ARR_TYPE_BOX      4
00031 #define ARR_TYPE_DIAMOND  5
00032 #define ARR_TYPE_DOT      6
00033 
00034 /* arrow mods */
00035 #define ARR_MOD_OPEN      (1<<8)
00036 #define ARR_MOD_INV       (1<<9)
00037 #define ARR_MOD_LEFT      (1<<10)
00038 #define ARR_MOD_RIGHT     (1<<11)
00039 
00040 typedef struct arrowdir_t {
00041     char *dir;
00042     int sflag;
00043     int eflag;
00044 } arrowdir_t;
00045 
00046 static arrowdir_t Arrowdirs[] = {
00047     {"forward", ARR_TYPE_NONE, ARR_TYPE_NORM},
00048     {"back", ARR_TYPE_NORM, ARR_TYPE_NONE},
00049     {"both", ARR_TYPE_NORM, ARR_TYPE_NORM},
00050     {"none", ARR_TYPE_NONE, ARR_TYPE_NONE},
00051     {(char *) 0, ARR_TYPE_NONE, ARR_TYPE_NONE}
00052 };
00053 
00054 typedef struct arrowname_t {
00055     char *name;
00056     int type;
00057 } arrowname_t;
00058 
00059 static arrowname_t Arrowsynonyms[] = {
00060     /* synonyms for deprecated arrow names - included for backward compatibility */
00061     /*  evaluated before primary names else "invempty" would give different results */
00062     {"invempty", (ARR_TYPE_NORM | ARR_MOD_INV | ARR_MOD_OPEN)}, /* oinv     */
00063     {(char *) 0, (ARR_TYPE_NONE)}
00064 };
00065 
00066 static arrowname_t Arrowmods[] = {
00067     {"o", ARR_MOD_OPEN},
00068     {"r", ARR_MOD_RIGHT},
00069     {"l", ARR_MOD_LEFT},
00070     /* deprecated alternates for backward compat */
00071     {"e", ARR_MOD_OPEN},        /* o  - needed for "ediamond" */
00072     {"half", ARR_MOD_LEFT},     /* l  - needed for "halfopen" */
00073     {(char *) 0, ARR_TYPE_NONE}
00074 };
00075 
00076 static arrowname_t Arrownames[] = {
00077     {"normal", ARR_TYPE_NORM},
00078     {"crow", ARR_TYPE_CROW},
00079     {"tee", ARR_TYPE_TEE},
00080     {"box", ARR_TYPE_BOX},
00081     {"diamond", ARR_TYPE_DIAMOND},
00082     {"dot", ARR_TYPE_DOT},
00083     {"none", ARR_TYPE_NONE},
00084     /* ARR_MOD_INV is used only here to define two additional shapes
00085        since not all types can use it */
00086     {"inv", (ARR_TYPE_NORM | ARR_MOD_INV)},
00087     {"vee", (ARR_TYPE_CROW | ARR_MOD_INV)},
00088     /* WARNING ugly kludge to deal with "o" v "open" conflict */
00089     /* Define "open" as just "pen" since "o" already taken as ARR_MOD_OPEN */
00090     /* Note that ARR_MOD_OPEN has no meaning for ARR_TYPE_CROW shape */
00091     {"pen", (ARR_TYPE_CROW | ARR_MOD_INV)},
00092     /* WARNING ugly kludge to deal with "e" v "empty" conflict */
00093     /* Define "empty" as just "mpty" since "e" already taken as ARR_MOD_OPEN */
00094     /* Note that ARR_MOD_OPEN has expected meaning for ARR_TYPE_NORM shape */
00095     {"mpty", ARR_TYPE_NORM},
00096     {(char *) 0, ARR_TYPE_NONE}
00097 };
00098 
00099 typedef struct arrowtype_t {
00100     int type;
00101     double lenfact;             /* ratio of length of this arrow type to standard arrow */
00102     void (*gen) (GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag); /* generator function for type */
00103 } arrowtype_t;
00104 
00105 /* forward declaration of functions used in Arrowtypes[] */
00106 static void arrow_type_normal(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00107 static void arrow_type_crow(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00108 static void arrow_type_tee(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00109 static void arrow_type_box(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00110 static void arrow_type_diamond(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00111 static void arrow_type_dot(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
00112 
00113 static arrowtype_t Arrowtypes[] = {
00114     {ARR_TYPE_NORM, 1.0, arrow_type_normal},
00115     {ARR_TYPE_CROW, 1.0, arrow_type_crow},
00116     {ARR_TYPE_TEE, 0.5, arrow_type_tee},
00117     {ARR_TYPE_BOX, 1.0, arrow_type_box},
00118     {ARR_TYPE_DIAMOND, 1.2, arrow_type_diamond},
00119     {ARR_TYPE_DOT, 0.8, arrow_type_dot},
00120     {ARR_TYPE_NONE, 0.0, NULL}
00121 };
00122 
00123 static char *arrow_match_name_frag(char *name, arrowname_t * arrownames,
00124                                    int *flag)
00125 {
00126     arrowname_t *arrowname;
00127     int namelen = 0;
00128     char *rest = name;
00129 
00130     for (arrowname = arrownames; arrowname->name; arrowname++) {
00131         namelen = strlen(arrowname->name);
00132         if (strncmp(name, arrowname->name, namelen) == 0) {
00133             *flag |= arrowname->type;
00134             rest += namelen;
00135             break;
00136         }
00137     }
00138     return rest;
00139 }
00140 
00141 static char *arrow_match_shape(char *name, int *flag)
00142 {
00143     char *next, *rest;
00144     int f = ARR_TYPE_NONE;
00145 
00146     rest = arrow_match_name_frag(name, Arrowsynonyms, &f);
00147     if (rest == name) {
00148         do {
00149             next = rest;
00150             rest = arrow_match_name_frag(next, Arrowmods, &f);
00151         } while (next != rest);
00152         rest = arrow_match_name_frag(rest, Arrownames, &f);
00153     }
00154     if (f && !(f & ((1 << 8) - 1)))
00155         f |= ARR_TYPE_NORM;
00156     *flag |= f;
00157     return rest;
00158 }
00159 
00160 static void arrow_match_name(char *name, int *flag)
00161 {
00162     char *rest;
00163     int f1 = ARR_TYPE_NONE, f2 = ARR_TYPE_NONE;
00164 
00165     rest = arrow_match_shape(name, &f1);
00166     rest = arrow_match_shape(rest, &f2);
00167     *flag = f1 | (f2 << 16);
00168 }
00169 
00170 void arrow_flags(Agedge_t * e, int *sflag, int *eflag)
00171 {
00172     char *attr;
00173     arrowdir_t *arrowdir;
00174 
00175     *sflag = ARR_TYPE_NONE;
00176     *eflag =
00177         AG_IS_DIRECTED(e->tail->graph) ? ARR_TYPE_NORM : ARR_TYPE_NONE;
00178     if (E_dir && ((attr = agxget(e, E_dir->index)))[0]) {
00179         for (arrowdir = Arrowdirs; arrowdir->dir; arrowdir++) {
00180             if (streq(attr, arrowdir->dir)) {
00181                 *sflag = arrowdir->sflag;
00182                 *eflag = arrowdir->eflag;
00183                 break;
00184             }
00185         }
00186     }
00187     if (E_arrowhead && ((attr = agxget(e, E_arrowhead->index)))[0])
00188         arrow_match_name(attr, eflag);
00189     if (E_arrowtail && ((attr = agxget(e, E_arrowtail->index)))[0])
00190         arrow_match_name(attr, sflag);
00191     if (ED_conc_opp_flag(e)) {
00192         edge_t *f;
00193         int s0, e0;
00194         /* pick up arrowhead of opposing edge */
00195         f = agfindedge(e->tail->graph, e->head, e->tail);
00196         arrow_flags(f, &s0, &e0);
00197         *eflag = *eflag | s0;
00198         *sflag = *sflag | e0;
00199     }
00200 }
00201 
00202 double arrow_length(edge_t * e, int flag)
00203 {
00204     arrowtype_t *arrowtype;
00205     double lenfact = 0.0;
00206     int f;
00207 
00208     /* we don't simply index with flag because arrowtypes are not necessarily sorted */
00209     f = flag & ((1 << 8) - 1);
00210     for (arrowtype = Arrowtypes; arrowtype->gen; arrowtype++) {
00211         if (f == arrowtype->type) {
00212             lenfact += arrowtype->lenfact;
00213             break;
00214         }
00215     }
00216     f = (flag >> 16) & ((1 << 8) - 1);
00217     for (arrowtype = Arrowtypes; arrowtype->gen; arrowtype++) {
00218         if (f == arrowtype->type) {
00219             lenfact += arrowtype->lenfact;
00220             break;
00221         }
00222     }
00223     /* The original was missing the factor E_arrowsz, but I believe it
00224        should be here for correct arrow clipping */
00225     return ARROW_LENGTH * lenfact * late_double(e, E_arrowsz, 1.0, 0.0);
00226 }
00227 
00228 /* inside function for calls to bezier_clip */
00229 static boolean inside(inside_t * inside_context, pointf p)
00230 {
00231     return DIST2(p, inside_context->a.p[0]) <= inside_context->a.r[0];
00232 }
00233 
00234 int arrowEndClip(edge_t* e, point * ps, int startp,
00235                  int endp, bezier * spl, int eflag)
00236 {
00237     inside_t inside_context;
00238     pointf sp[4];
00239     double elen, elen2;
00240 
00241     elen = arrow_length(e, eflag);
00242     elen2 = elen * elen;
00243     spl->eflag = eflag, spl->ep = ps[endp + 3];
00244     if (endp > startp && DIST2(ps[endp], ps[endp + 3]) < elen2) {
00245         endp -= 3;
00246     }
00247     P2PF(ps[endp], sp[3]);
00248     P2PF(ps[endp + 1], sp[2]);
00249     P2PF(ps[endp + 2], sp[1]);
00250     P2PF(spl->ep, sp[0]);       /* ensure endpoint starts inside */
00251 
00252     inside_context.a.p = &sp[0];
00253     inside_context.a.r = &elen2;
00254     bezier_clip(&inside_context, inside, sp, TRUE);
00255 
00256     PF2P(sp[3], ps[endp]);
00257     PF2P(sp[2], ps[endp + 1]);
00258     PF2P(sp[1], ps[endp + 2]);
00259     PF2P(sp[0], ps[endp + 3]);
00260     return endp;
00261 }
00262 
00263 int arrowStartClip(edge_t* e, point * ps, int startp,
00264                    int endp, bezier * spl, int sflag)
00265 {
00266     inside_t inside_context;
00267     pointf sp[4];
00268     double slen, slen2;
00269 
00270     slen = arrow_length(e, sflag);
00271     slen2 = slen * slen;
00272     spl->sflag = sflag, spl->sp = ps[startp];
00273     if (endp > startp && DIST2(ps[startp], ps[startp + 3]) < slen2) {
00274         startp += 3;
00275     }
00276     P2PF(ps[startp + 3], sp[0]);
00277     P2PF(ps[startp + 2], sp[1]);
00278     P2PF(ps[startp + 1], sp[2]);
00279     P2PF(spl->sp, sp[3]);       /* ensure endpoint starts inside */
00280 
00281     inside_context.a.p = &sp[3];
00282     inside_context.a.r = &slen2;
00283     bezier_clip(&inside_context, inside, sp, FALSE);
00284 
00285     PF2P(sp[3], ps[startp]);
00286     PF2P(sp[2], ps[startp + 1]);
00287     PF2P(sp[1], ps[startp + 2]);
00288     PF2P(sp[0], ps[startp + 3]);
00289     return startp;
00290 }
00291 
00292 static void arrow_type_normal(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00293 {
00294     pointf q, v, a[5];
00295     double arrowwidth;
00296 
00297     arrowwidth = 0.35;
00298     if (penwidth > 4)
00299         arrowwidth *= penwidth / 4;
00300 
00301     v.x = -u.y * arrowwidth;
00302     v.y = u.x * arrowwidth;
00303     q.x = p.x + u.x;
00304     q.y = p.y + u.y;
00305     if (flag & ARR_MOD_INV) {
00306         a[0] = a[4] = p;
00307         a[1].x = p.x - v.x;
00308         a[1].y = p.y - v.y;
00309         a[2] = q;
00310         a[3].x = p.x + v.x;
00311         a[3].y = p.y + v.y;
00312     } else {
00313         a[0] = a[4] = q;
00314         a[1].x = q.x - v.x;
00315         a[1].y = q.y - v.y;
00316         a[2] = p;
00317         a[3].x = q.x + v.x;
00318         a[3].y = q.y + v.y;
00319     }
00320     if (flag & ARR_MOD_LEFT)
00321         gvrender_polygon(job, a, 3, !(flag & ARR_MOD_OPEN));
00322     else if (flag & ARR_MOD_RIGHT)
00323         gvrender_polygon(job, &a[2], 3, !(flag & ARR_MOD_OPEN));
00324     else
00325         gvrender_polygon(job, &a[1], 3, !(flag & ARR_MOD_OPEN));
00326 }
00327 
00328 static void arrow_type_crow(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00329 {
00330     pointf m, q, v, w, a[9];
00331     double arrowwidth, shaftwidth;
00332 
00333     arrowwidth = 0.45;
00334     if (penwidth > (4 * arrowsize) && (flag & ARR_MOD_INV))
00335         arrowwidth *= penwidth / (4 * arrowsize);
00336 
00337     shaftwidth = 0;
00338     if (penwidth > 1 && (flag & ARR_MOD_INV))
00339         shaftwidth = 0.05 * (penwidth - 1) / arrowsize;   /* arrowsize to cancel the arrowsize term already in u */
00340 
00341     v.x = -u.y * arrowwidth;
00342     v.y = u.x * arrowwidth;
00343     w.x = -u.y * shaftwidth;
00344     w.y = u.x * shaftwidth;
00345     q.x = p.x + u.x;
00346     q.y = p.y + u.y;
00347     m.x = p.x + u.x * 0.5;
00348     m.y = p.y + u.y * 0.5;
00349     if (flag & ARR_MOD_INV) {  /* vee */
00350         a[0] = a[8] = p;
00351         a[1].x = q.x - v.x;
00352         a[1].y = q.y - v.y;
00353         a[2].x = m.x - w.x;
00354         a[2].y = m.y - w.y;
00355         a[3].x = q.x - w.x;
00356         a[3].y = q.y - w.y;
00357         a[4] = q;
00358         a[5].x = q.x + w.x;
00359         a[5].y = q.y + w.y;
00360         a[6].x = m.x + w.x;
00361         a[6].y = m.y + w.y;
00362         a[7].x = q.x + v.x;
00363         a[7].y = q.y + v.y;
00364     } else {                     /* crow */
00365         a[0] = a[8] = q;
00366         a[1].x = p.x - v.x;
00367         a[1].y = p.y - v.y;
00368         a[2].x = m.x - w.x;
00369         a[2].y = m.y - w.y;
00370         a[3].x = p.x;
00371         a[3].y = p.y;
00372         a[4] = p;
00373         a[5].x = p.x;
00374         a[5].y = p.y;
00375         a[6].x = m.x + w.x;
00376         a[6].y = m.y + w.y;
00377         a[7].x = p.x + v.x;
00378         a[7].y = p.y + v.y;
00379     }
00380     if (flag & ARR_MOD_LEFT)
00381         gvrender_polygon(job, a, 6, 1);
00382     else if (flag & ARR_MOD_RIGHT)
00383         gvrender_polygon(job, &a[3], 6, 1);
00384     else
00385         gvrender_polygon(job, a, 9, 1);
00386 }
00387 
00388 static void arrow_type_tee(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00389 {
00390     pointf m, n, q, v, a[4];
00391 
00392     v.x = -u.y;
00393     v.y = u.x;
00394     q.x = p.x + u.x;
00395     q.y = p.y + u.y;
00396     m.x = p.x + u.x * 0.2;
00397     m.y = p.y + u.y * 0.2;
00398     n.x = p.x + u.x * 0.6;
00399     n.y = p.y + u.y * 0.6;
00400     a[0].x = m.x + v.x;
00401     a[0].y = m.y + v.y;
00402     a[1].x = m.x - v.x;
00403     a[1].y = m.y - v.y;
00404     a[2].x = n.x - v.x;
00405     a[2].y = n.y - v.y;
00406     a[3].x = n.x + v.x;
00407     a[3].y = n.y + v.y;
00408     if (flag & ARR_MOD_LEFT) {
00409         a[0] = m;
00410         a[3] = n;
00411     } else if (flag & ARR_MOD_RIGHT) {
00412         a[1] = m;
00413         a[2] = n;
00414     }
00415     gvrender_polygon(job, a, 4, 1);
00416     a[0] = p;
00417     a[1] = q;
00418     gvrender_polyline(job, a, 2);
00419 }
00420 
00421 static void arrow_type_box(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00422 {
00423     pointf m, q, v, a[4];
00424 
00425     v.x = -u.y * 0.4;
00426     v.y = u.x * 0.4;
00427     m.x = p.x + u.x * 0.8;
00428     m.y = p.y + u.y * 0.8;
00429     q.x = p.x + u.x;
00430     q.y = p.y + u.y;
00431     a[0].x = p.x + v.x;
00432     a[0].y = p.y + v.y;
00433     a[1].x = p.x - v.x;
00434     a[1].y = p.y - v.y;
00435     a[2].x = m.x - v.x;
00436     a[2].y = m.y - v.y;
00437     a[3].x = m.x + v.x;
00438     a[3].y = m.y + v.y;
00439     if (flag & ARR_MOD_LEFT) {
00440         a[0] = p;
00441         a[3] = m;
00442     } else if (flag & ARR_MOD_RIGHT) {
00443         a[1] = p;
00444         a[2] = m;
00445     }
00446     gvrender_polygon(job, a, 4, !(flag & ARR_MOD_OPEN));
00447     a[0] = m;
00448     a[1] = q;
00449     gvrender_polyline(job, a, 2);
00450 }
00451 
00452 static void arrow_type_diamond(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00453 {
00454     pointf q, r, v, a[5];
00455 
00456     v.x = -u.y / 3.;
00457     v.y = u.x / 3.;
00458     r.x = p.x + u.x / 2.;
00459     r.y = p.y + u.y / 2.;
00460     q.x = p.x + u.x;
00461     q.y = p.y + u.y;
00462     a[0] = a[4] = q;
00463     a[1].x = r.x + v.x;
00464     a[1].y = r.y + v.y;
00465     a[2] = p;
00466     a[3].x = r.x - v.x;
00467     a[3].y = r.y - v.y;
00468     if (flag & ARR_MOD_LEFT)
00469         gvrender_polygon(job, &a[2], 3, !(flag & ARR_MOD_OPEN));
00470     else if (flag & ARR_MOD_RIGHT)
00471         gvrender_polygon(job, a, 3, !(flag & ARR_MOD_OPEN));
00472     else
00473         gvrender_polygon(job, a, 4, !(flag & ARR_MOD_OPEN));
00474 }
00475 
00476 static void arrow_type_dot(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00477 {
00478     double r;
00479     pointf AF[2];
00480 
00481     r = sqrt(u.x * u.x + u.y * u.y) / 2.;
00482     AF[0].x = p.x + u.x / 2. - r;
00483     AF[0].y = p.y + u.y / 2. - r;
00484     AF[1].x = p.x + u.x / 2. + r;
00485     AF[1].y = p.y + u.y / 2. + r;
00486     gvrender_ellipse(job, AF, 2, !(flag & ARR_MOD_OPEN));
00487 }
00488 
00489 static pointf arrow_gen_type(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00490 {
00491     int f;
00492     arrowtype_t *arrowtype;
00493 
00494     f = flag & ((1 << 8) - 1);
00495     for (arrowtype = Arrowtypes; arrowtype->type; arrowtype++) {
00496         if (f == arrowtype->type) {
00497             u.x *= arrowtype->lenfact * arrowsize;
00498             u.y *= arrowtype->lenfact * arrowsize;
00499             (arrowtype->gen) (job, p, u, arrowsize, penwidth, flag);
00500             p.x = p.x + u.x;
00501             p.y = p.y + u.y;
00502             break;
00503         }
00504     }
00505     return p;
00506 }
00507 
00508 boxf arrow_bb(pointf p, pointf u, double arrowsize, int flag)
00509 {
00510     double s;
00511     boxf bb;
00512     double ax,ay,bx,by,cx,cy,dx,dy;
00513     double ux2, uy2;
00514 
00515     /* generate arrowhead vector */
00516     u.x -= p.x;
00517     u.y -= p.y;
00518     /* the EPSILONs are to keep this stable as length of u approaches 0.0 */
00519     s = ARROW_LENGTH * arrowsize / (sqrt(u.x * u.x + u.y * u.y) + EPSILON);
00520     u.x += (u.x >= 0.0) ? EPSILON : -EPSILON;
00521     u.y += (u.y >= 0.0) ? EPSILON : -EPSILON;
00522     u.x *= s;
00523     u.y *= s;
00524 
00525     /* compute all 4 corners of rotated arrowhead bounding box */
00526     ux2 = u.x / 2.;
00527     uy2 = u.y / 2.;
00528     ax = p.x - uy2;
00529     ay = p.y - ux2;
00530     bx = p.x + uy2;
00531     by = p.y + ux2;
00532     cx = ax + u.x;
00533     cy = ay + u.y;
00534     dx = bx + u.x;
00535     dy = by + u.y;
00536 
00537     /* compute a right bb */
00538     bb.UR.x = MAX(ax, MAX(bx, MAX(cx, dx)));
00539     bb.UR.y = MAX(ay, MAX(by, MAX(cy, dy)));
00540     bb.LL.x = MIN(ax, MIN(bx, MIN(cx, dx)));
00541     bb.LL.y = MIN(ay, MIN(by, MIN(cy, dy)));
00542  
00543     return bb;
00544 }
00545 
00546 void arrow_newgen(GVJ_t * job, emit_state_t emit_state, pointf p, pointf u, double arrowsize, double penwidth, int flag)
00547 {
00548     obj_state_t *obj = job->obj;
00549     double s;
00550     int f;
00551     emit_state_t old_emit_state;
00552 
00553     old_emit_state = obj->emit_state;
00554     obj->emit_state = emit_state;
00555 
00556     /* Dotted and dashed styles on the arrowhead are ugly (dds) */
00557     /* linewidth needs to be reset */
00558     gvrender_begin_context(job);
00559     gvrender_set_style(job, job->gvc->defaultlinestyle);
00560 
00561     /* generate arrowhead vector */
00562     u.x -= p.x;
00563     u.y -= p.y;
00564     /* the EPSILONs are to keep this stable as length of u approaches 0.0 */
00565     s = ARROW_LENGTH / (sqrt(u.x * u.x + u.y * u.y) + EPSILON);
00566     u.x += (u.x >= 0.0) ? EPSILON : -EPSILON;
00567     u.y += (u.y >= 0.0) ? EPSILON : -EPSILON;
00568     u.x *= s;
00569     u.y *= s;
00570 
00571     /* arrow head closest to node */
00572     f = flag & ((1 << 16) - 1);
00573     p = arrow_gen_type(job, p, u, arrowsize, penwidth, f);
00574 
00575     /* arrow head furthest from node */
00576     /*   start where first one ended */
00577     f = (flag >> 16) & ((1 << 16) - 1);
00578     arrow_gen_type(job, p, u, arrowsize, penwidth, f);
00579 
00580     gvrender_end_context(job);
00581 
00582     obj->emit_state = old_emit_state;
00583 }
00584 
00585 /* FIXME emit.c and output.c require wrapper for int point coords */
00586 void arrow_gen(GVJ_t * job, emit_state_t emit_state, point p, point u, double arrowsize, double penwidth, int flag)
00587 {
00588     pointf P, U;
00589 
00590     P2PF(p, P);
00591     P2PF(u, U);
00592     arrow_newgen(job, emit_state, P, U, arrowsize, penwidth, flag);
00593 }

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