28#define ARROW_LENGTH 10.
30#define NUMB_OF_ARROW_HEADS 4
33#define BITS_PER_ARROW 8
35#define BITS_PER_ARROW_TYPE 4
37#define ARR_TYPE_NONE (ARR_NONE)
38#define ARR_TYPE_NORM 1
39#define ARR_TYPE_CROW 2
42#define ARR_TYPE_DIAMOND 5
44#define ARR_TYPE_CURVE 7
49#define ARR_MOD_OPEN (1<<(BITS_PER_ARROW_TYPE+0))
50#define ARR_MOD_INV (1<<(BITS_PER_ARROW_TYPE+1))
51#define ARR_MOD_LEFT (1<<(BITS_PER_ARROW_TYPE+2))
52#define ARR_MOD_RIGHT (1<<(BITS_PER_ARROW_TYPE+3))
166 namelen = strlen(arrowname->name);
168 *flag |= arrowname->type;
185 }
while (next != rest);
205 agwarningf(
"Arrow type \"%s\" unknown - ignoring\n", next);
224 if (
streq(attr, arrowdir->dir)) {
225 *sflag = arrowdir->sflag;
226 *eflag = arrowdir->eflag;
237 if (arrowhead !=
NULL && ((attr =
agxget(e, arrowhead)))[0])
243 if (arrowtail !=
NULL && ((attr =
agxget(e, arrowtail)))[0])
264 if (arrowsize == 0) {
273 if (f == arrowtype->
type) {
286 return DIST2(p, inside_context->
a.
p[0]) <= inside_context->
a.
r[0];
290 size_t endp,
bezier *spl, uint32_t eflag) {
298 spl->
ep =
ps[endp + 3];
299 if (endp > startp &&
DIST2(
ps[endp],
ps[endp + 3]) < elen2) {
303 sp[2] =
ps[endp + 1];
304 sp[1] =
ps[endp + 2];
308 inside_context.
a.
p = &sp[0];
309 inside_context.
a.
r = &elen2;
314 ps[endp + 1] = sp[2];
315 ps[endp + 2] = sp[1];
316 ps[endp + 3] = sp[0];
321 size_t endp,
bezier *spl, uint32_t sflag) {
329 spl->
sp =
ps[startp];
330 if (endp > startp &&
DIST2(
ps[startp],
ps[startp + 3]) < slen2) {
333 sp[0] =
ps[startp + 3];
334 sp[1] =
ps[startp + 2];
335 sp[2] =
ps[startp + 1];
339 inside_context.
a.
p = &sp[3];
340 inside_context.
a.
r = &slen2;
345 ps[startp + 1] = sp[2];
346 ps[startp + 2] = sp[1];
347 ps[startp + 3] = sp[0];
361 bezier *spl, uint32_t sflag, uint32_t eflag) {
363 double d, tlen, hlen, maxd;
365 if (sflag && eflag && endp == startp) {
371 if (hlen + tlen >= d) {
396 ps[endp] =
ps[endp + 1] =
s;
397 ps[endp + 2] =
ps[endp + 3] = t;
398 spl->
sflag = sflag, spl->
sp = p;
399 spl->
eflag = eflag, spl->
ep = q;
413 if (p.
x < q.
x) r.
x = q.
x - hlen;
414 else r.
x = q.
x + hlen;
418 if (p.
y < q.
y) r.
y = q.
y - hlen;
419 else r.
y = q.
y + hlen;
422 ps[endp + 2] =
ps[endp + 3] = r;
437 if (p.
x < q.
x) r.
x = p.
x + tlen;
438 else r.
x = p.
x - tlen;
442 if (p.
y < q.
y) r.
y = p.
y + tlen;
443 else r.
y = p.
y - tlen;
445 ps[startp] =
ps[startp + 1] = r;
461 if ((base_left.
x == P.
x && base_left.
y == P.
y) ||
462 (base_right.
x == P.
x && base_right.
y == P.
y)) {
466 const triangle line_join_shape = {{P, P, P}};
467 return line_join_shape;
469 const pointf A[] = {base_left, P};
470 const double dxA =
A[1].
x -
A[0].x;
471 const double dyA =
A[1].y -
A[0].y;
472 const double hypotA = hypot(dxA, dyA);
473 const double cosAlpha = dxA / hypotA;
474 const double sinAlpha = dyA / hypotA;
475 const double alpha = dyA > 0 ? acos(cosAlpha) : -acos(cosAlpha);
480 const pointf B[] = {P, base_right};
481 const double dxB =
B[1].
x -
B[0].x;
482 const double dyB =
B[1].y -
B[0].y;
483 const double hypotB = hypot(dxB, dyB);
484 const double cosBeta = dxB / hypotB;
485 const double beta = dyB > 0 ? acos(cosBeta) : -acos(cosBeta);
488 const double beta_rev = beta -
M_PI;
490 assert(theta >= 0 && theta <=
M_PI &&
"theta out of range");
494 const double stroke_miterlimit = 4.0;
495 const double normalized_miter_length = 1.0 / sin(theta / 2.0);
497 const double sinBeta = dyB / hypotB;
498 const double sinBetaMinusPi = -sinBeta;
499 const double cosBetaMinusPi = -cosBeta;
503 if (normalized_miter_length > stroke_miterlimit) {
510 const pointf Pbevel = {(P1.
x + P2.
x) / 2, (P1.
y + P2.
y) / 2};
511 const triangle line_join_shape = {{Pbevel, P1, P2}};
513 return line_join_shape;
517 const double l =
penwidth / 2.0 / tan(theta / 2.0);
519 const pointf P3 = {P1.
x + l * cosAlpha,
520 P1.
y + l * sinAlpha};
521 const triangle line_join_shape = {{P3, P1, P2}};
523 return line_join_shape;
527 uint32_t flag,
pointf *a) {
535 v.
x = -u.
y * arrowwidth;
536 v.
y = u.
x * arrowwidth;
540 pointf delta_base = {0, 0};
542 const pointf origin = {0, 0};
548 const pointf normal_tip = {-u.
x, -u.
y};
552 pointf delta_tip = {0, 0};
554 if (u.
x != 0 || u.
y != 0) {
556 const double cosPhi = P.
x / hypot(P.
x, P.
y);
557 const double sinPhi = P.
y / hypot(P.
x, P.
y);
558 const double phi = P.
y > 0 ? acos(cosPhi) : -acos(cosPhi);
564 const double dx_P_P1 = P1.
x - P.
x;
565 const double dy_P_P1 = P1.
y - P.
y;
566 const double hypot_P_P1 = hypot(dx_P_P1, dy_P_P1);
567 const double cosAlpha = dx_P_P1 / hypot_P_P1;
568 const double alpha = dy_P_P1 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
569 const double gamma =
alpha - phi;
570 const double delta_tip_length = hypot_P_P1 * cos(gamma);
571 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
576 const double dx_P_P2 = P2.
x - P.
x;
577 const double dy_P_P2 = P2.
y - P.
y;
578 const double hypot_P_P2 = hypot(dx_P_P2, dy_P_P2);
579 const double cosAlpha = dx_P_P2 / hypot_P_P2;
580 const double alpha = dy_P_P2 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
581 const double gamma =
alpha - phi;
582 const double delta_tip_length = hypot_P_P2 * cos(gamma);
583 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
645 double arrowwidth, shaftwidth;
649 arrowwidth *=
penwidth / (4 * arrowsize);
653 shaftwidth = 0.05 * (
penwidth - 1) / arrowsize;
655 v.
x = -u.
y * arrowwidth;
656 v.
y = u.
x * arrowwidth;
657 w.
x = -u.
y * shaftwidth;
658 w.
y = u.
x * shaftwidth;
661 m.
x = p.
x + u.
x * 0.5;
662 m.
y = p.
y + u.
y * 0.5;
664 pointf delta_base = {0, 0};
666 const pointf origin = {0, 0};
672 const pointf normal_tip = u;
673 const pointf inv_tip = {-u.
x, -u.
y};
676 pointf delta_tip = {0, 0};
678 if (u.
x != 0 || u.
y != 0) {
680 const double cosPhi = P.
x / hypot(P.
x, P.
y);
681 const double sinPhi = P.
y / hypot(P.
x, P.
y);
682 const double phi = P.
y > 0 ? acos(cosPhi) : -acos(cosPhi);
688 const double dx_P_P2 = P2.
x - P.
x;
689 const double dy_P_P2 = P2.
y - P.
y;
690 const double hypot_P_P2 = hypot(dx_P_P2, dy_P_P2);
691 const double cosAlpha = dx_P_P2 / hypot_P_P2;
692 const double alpha = dy_P_P2 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
693 const double gamma =
alpha - phi;
694 const double delta_tip_length = hypot_P_P2 * cos(gamma);
695 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
700 const double dx_P_P1 = P1.
x - P.
x;
701 const double dy_P_P1 = P1.
y - P.
y;
702 const double hypot_P_P1 = hypot(dx_P_P1, dy_P_P1);
703 const double cosAlpha = dx_P_P1 / hypot_P_P1;
704 const double alpha = dy_P_P1 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
705 const double gamma =
alpha - phi;
706 const double delta_tip_length = hypot_P_P1 * cos(gamma);
707 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
722 const pointf toe_base_right = origin;
727 const double dx_P_P1 = P1.
x - toe_P.
x;
728 const double dy_P_P1 = P1.
y - toe_P.
y;
729 const double hypot_P_P1 = hypot(dx_P_P1, dy_P_P1);
730 const double cosAlpha = dx_P_P1 / hypot_P_P1;
731 const double alpha = dy_P_P1 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
732 const double gamma =
alpha - phi;
733 const double delta_tip_length = -hypot_P_P1 * cos(gamma);
734 delta_base = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
769 a[3].
x = p.
x + delta_base.
x;
770 a[3].
y = p.
y + delta_base.
y;
772 a[5].
x = p.
x + delta_base.
x;
773 a[5].
y = p.
y + delta_base.
y;
828 m.
x = p.
x + u.
x * 0.2;
829 m.
y = p.
y + u.
y * 0.2;
830 n.
x = p.
x + u.
x * 0.6;
831 n.
y = p.
y + u.
y * 0.6;
833 const double length = hypot(u.
x, u.
y);
834 const double polygon_extend_over_polyline =
penwidth / 2 - 0.2 * length;
835 if (length > 0 && polygon_extend_over_polyline > 0) {
841 const double cosPhi = P.
x / hypot(P.
x, P.
y);
842 const double sinPhi = P.
y / hypot(P.
x, P.
y);
843 const pointf delta = {polygon_extend_over_polyline * cosPhi, polygon_extend_over_polyline * sinPhi};
887 m.
x = p.
x + u.
x * 0.8;
888 m.
y = p.
y + u.
y * 0.8;
894 if (u.
x != 0 || u.
y != 0) {
897 const double cosPhi = P.
x / hypot(P.
x, P.
y);
898 const double sinPhi = P.
y / hypot(P.
x, P.
y);
937 uint32_t flag,
pointf *a) {
942 r.
x = p.
x + u.
x / 2.;
943 r.
y = p.
y + u.
y / 2.;
947 const pointf origin = {0, 0};
1005 r = hypot(u.
x, u.
y) / 2.;
1009 if (u.
x != 0 || u.
y != 0) {
1012 const double cosPhi = P.
x / hypot(P.
x, P.
y);
1013 const double sinPhi = P.
y / hypot(P.
x, P.
y);
1022 AF[0].
x = p.
x + u.
x / 2. - r;
1023 AF[0].
y = p.
y + u.
y / 2. - r;
1024 AF[1].
x = p.
x + u.
x / 2. + r;
1025 AF[1].
y = p.
y + u.
y / 2. + r;
1053 const double cosPhi = P.
x / hypot(P.
x, P.
y);
1054 const double sinPhi = P.
y / hypot(P.
x, P.
y);
1064 v.
x = -u.
y * arrowwidth;
1065 v.
y = u.
x * arrowwidth;
1070 AF[0].
x = p.
x + v.
x + w.
x;
1071 AF[0].
y = p.
y + v.
y + w.
y;
1073 AF[3].
x = p.
x - v.
x + w.
x;
1074 AF[3].
y = p.
y - v.
y + w.
y;
1077 AF[1].
x = p.
x + 0.95 * v.
x + w.
x + w.
x * 4.0 / 3.0;
1078 AF[1].
y = AF[0].
y + w.
y * 4.0 / 3.0;
1080 AF[2].
x = p.
x - 0.95 * v.
x + w.
x + w.
x * 4.0 / 3.0;
1081 AF[2].
y = AF[3].
y + w.
y * 4.0 / 3.0;
1084 AF[1].
x = p.
x + 0.95 * v.
x + w.
x - w.
x * 4.0 / 3.0;
1085 AF[1].
y = AF[0].
y - w.
y * 4.0 / 3.0;
1087 AF[2].
x = p.
x - 0.95 * v.
x + w.
x - w.
x * 4.0 / 3.0;
1088 AF[2].
y = AF[3].
y - w.
y * 4.0 / 3.0;
1107 if (f == arrowtype->
type) {
1108 u.
x *= arrowtype->
lenfact * arrowsize;
1109 u.
y *= arrowtype->
lenfact * arrowsize;
1110 p = arrowtype->
gen(job, p, u, arrowsize,
penwidth, flag);
1121 double ax,ay,bx,by,cx,cy,
dx,
dy;
1147 bb.
UR.
x = fmax(ax, fmax(bx, fmax(cx,
dx)));
1148 bb.
UR.
y = fmax(ay, fmax(by, fmax(cy,
dy)));
1149 bb.
LL.
x = fmin(ax, fmin(bx, fmin(cx,
dx)));
1150 bb.
LL.
y = fmin(ay, fmin(by, fmin(cy,
dy)));
1156 double arrowsize,
double penwidth, uint32_t flag) {
1211 const pointf base1 = a[1];
1212 const pointf base2 = a[3];
1214 const double full_length = q.
x;
1215 assert(full_length > 0 &&
"non-positive full length");
1216 const double nominal_length = fabs(base1.
x - tip.
x);
1217 const double nominal_base_width = base2.
y - base1.
y;
1218 assert(nominal_base_width > 0 &&
"non-positive nominal base width");
1220 const double full_base_width =
1221 nominal_base_width * full_length / nominal_length;
1222 assert(full_base_width > 0 &&
"non-positive full base width");
1226 const double overlap_at_base =
penwidth / 2;
1228 const double length_where_width_is_penwidth =
1229 full_length *
penwidth / full_base_width;
1230 const double overlap_at_tip = length_where_width_is_penwidth;
1248 const double nominal_length = lenfact * arrowsize *
ARROW_LENGTH;
1249 double length = nominal_length;
1253 const double polygon_extend_over_polyline_at_start =
penwidth / 2 - (1 - 0.6) * nominal_length;
1254 if (polygon_extend_over_polyline_at_start > 0) {
1255 length += polygon_extend_over_polyline_at_start;
1258 const double polygon_extend_over_polyline_at_end =
penwidth / 2 - 0.2 * nominal_length;
1259 if (polygon_extend_over_polyline_at_start > 0) {
1260 length += polygon_extend_over_polyline_at_end;
1290 const pointf base1 = a[3];
1291 const pointf base2 = a[1];
1293 const double full_length = q.
x / 2;
1294 assert(full_length > 0 &&
"non-positive full length");
1295 const double nominal_length = fabs(base1.
x - tip.
x);
1296 const double nominal_base_width = base2.
y - base1.
y;
1297 assert(nominal_base_width > 0 &&
"non-positive nominal base width");
1299 const double full_base_width =
1300 nominal_base_width * full_length / nominal_length;
1301 assert(full_base_width > 0 &&
"non-positive full base width");
1307 const double length_where_width_is_penwidth =
1308 full_length *
penwidth / full_base_width;
1309 const double overlap_at_tip = length_where_width_is_penwidth;
1311 const double overlap = overlap_at_tip;
1315 return 2 * full_length -
overlap;
1343 const pointf base1 = a[1];
1344 const pointf base2 = a[7];
1346 const pointf shaft1 = a[3];
1347 const double full_length = q.
x;
1348 assert(full_length > 0 &&
"non-positive full length");
1349 const double full_length_without_shaft = full_length - (base1.
x - shaft1.
x);
1350 assert(full_length_without_shaft > 0 &&
"non-positive full length without shaft");
1351 const double nominal_length = fabs(base1.
x - tip.
x);
1352 const double nominal_base_width = base2.
y - base1.
y;
1353 assert(nominal_base_width > 0 &&
"non-positive nominal base width");
1355 const double full_base_width =
1356 nominal_base_width * full_length_without_shaft / nominal_length;
1357 assert(full_base_width > 0 &&
"non-positive full base width");
1361 const double overlap_at_base =
penwidth / 2;
1363 const double length_where_width_is_penwidth =
1364 full_length_without_shaft *
penwidth / full_base_width;
1365 const double overlap_at_tip = length_where_width_is_penwidth;
static const arrowtype_t Arrowtypes[]
static pointf arrow_type_diamond(GVJ_t *job, pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag)
static triangle miter_shape(pointf base_left, pointf P, pointf base_right, double penwidth)
static double arrow_length_curve(double lenfact, double arrowsize, double penwidth, uint32_t flag)
static double arrow_length_tee(double lenfact, double arrowsize, double penwidth, uint32_t flag)
static double arrow_length(edge_t *e, uint32_t flag)
static double arrow_length_crow(double lenfact, double arrowsize, double penwidth, uint32_t flag)
static pointf arrow_gen_type(GVJ_t *job, pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag)
boxf arrow_bb(pointf p, pointf u, double arrowsize)
static double arrow_length_dot(double lenfact, double arrowsize, double penwidth, uint32_t flag)
size_t arrowStartClip(edge_t *e, pointf *ps, size_t startp, size_t endp, bezier *spl, uint32_t sflag)
size_t arrowEndClip(edge_t *e, pointf *ps, size_t startp, size_t endp, bezier *spl, uint32_t eflag)
static pointf arrow_type_diamond0(pointf p, pointf u, double penwidth, uint32_t flag, pointf *a)
static const arrowname_t Arrownames[]
static char * arrow_match_shape(char *name, uint32_t *flag)
static const arrowname_t Arrowmods[]
static pointf arrow_type_dot(GVJ_t *job, pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag)
static const arrowname_t Arrowsynonyms[]
void arrowOrthoClip(edge_t *e, pointf *ps, size_t startp, size_t endp, bezier *spl, uint32_t sflag, uint32_t eflag)
static double arrow_length_generic(double lenfact, double arrowsize, double penwidth, uint32_t flag)
static double arrow_length_diamond(double lenfact, double arrowsize, double penwidth, uint32_t flag)
static pointf arrow_type_box(GVJ_t *job, pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag)
static void arrow_match_name(char *name, uint32_t *flag)
static const size_t Arrowtypes_size
static bool inside(inside_t *inside_context, pointf p)
static char * arrow_match_name_frag(char *name, const arrowname_t *arrownames, uint32_t *flag)
void arrow_flags(Agedge_t *e, uint32_t *sflag, uint32_t *eflag)
#define NUMB_OF_ARROW_HEADS
static pointf arrow_type_normal0(pointf p, pointf u, double penwidth, uint32_t flag, pointf *a)
static const arrowdir_t Arrowdirs[]
static pointf arrow_type_gap(GVJ_t *job, pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag)
static pointf arrow_type_crow0(pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag, pointf *a)
#define BITS_PER_ARROW_TYPE
static pointf arrow_type_curve(GVJ_t *job, pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag)
static pointf arrow_type_tee(GVJ_t *job, pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag)
void arrow_gen(GVJ_t *job, emit_state_t emit_state, pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag)
static pointf arrow_type_crow(GVJ_t *job, pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag)
static double arrow_length_normal(double lenfact, double arrowsize, double penwidth, uint32_t flag)
static pointf arrow_type_normal(GVJ_t *job, pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag)
static double arrow_length_box(double lenfact, double arrowsize, double penwidth, uint32_t flag)
pointf Bezier(pointf *V, double t, pointf *Left, pointf *Right)
double late_double(void *obj, attrsym_t *attr, double defaultValue, double minimum)
static void gen(Excc_t *, Exnode_t *)
geometric functions (e.g. on points and boxes)
static pointf add_pointf(pointf p, pointf q)
static pointf sub_pointf(pointf p, pointf q)
static pointf scale(double c, pointf p)
static double len(glCompPoint p)
char * agxget(void *obj, Agsym_t *sym)
#define ED_conc_opp_flag(e)
#define agfindedgeattr(g, a)
#define agfindedge(g, t, h)
void agwarningf(const char *fmt,...)
int agisdirected(Agraph_t *g)
Agraph_t * agraphof(void *obj)
void gvrender_beziercurve(GVJ_t *job, pointf *AF, size_t n, int filled)
void gvrender_set_style(GVJ_t *job, char **s)
void gvrender_polyline(GVJ_t *job, pointf *AF, size_t n)
void gvrender_polygon(GVJ_t *job, pointf *af, size_t n, int filled)
void gvrender_ellipse(GVJ_t *job, pointf *AF, int filled)
void gvrender_set_penwidth(GVJ_t *job, double penwidth)
void bezier_clip(inside_t *inside_context, bool(*insidefn)(inside_t *inside_context, pointf p), pointf *sp, bool left_inside)
static double overlap(double i0, double i1, double j0, double j1)
static bool startswith(const char *s, const char *prefix)
does the string s begin with the string prefix?
static bool streq(const char *a, const char *b)
are a and b equal?
pointf(* gen)(GVJ_t *job, pointf p, pointf u, double arrowsize, double penwidth, uint32_t flag)
double(* len)(double lenfact, double arrowsize, double penwidth, uint32_t flag)
penwidth dependent length