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;
233 if (arrowhead !=
NULL && ((attr =
agxget(e, arrowhead)))[0])
238 if (arrowtail !=
NULL && ((attr =
agxget(e, arrowtail)))[0])
259 if (arrowsize == 0) {
268 if (f == arrowtype->
type) {
281 return DIST2(p, inside_context->
a.
p[0]) <= inside_context->
a.
r[0];
285 size_t endp,
bezier *spl, uint32_t eflag) {
293 spl->
ep =
ps[endp + 3];
294 if (endp > startp &&
DIST2(
ps[endp],
ps[endp + 3]) < elen2) {
298 sp[2] =
ps[endp + 1];
299 sp[1] =
ps[endp + 2];
303 inside_context.
a.
p = &sp[0];
304 inside_context.
a.
r = &elen2;
309 ps[endp + 1] = sp[2];
310 ps[endp + 2] = sp[1];
311 ps[endp + 3] = sp[0];
316 size_t endp,
bezier *spl, uint32_t sflag) {
324 spl->
sp =
ps[startp];
325 if (endp > startp &&
DIST2(
ps[startp],
ps[startp + 3]) < slen2) {
328 sp[0] =
ps[startp + 3];
329 sp[1] =
ps[startp + 2];
330 sp[2] =
ps[startp + 1];
334 inside_context.
a.
p = &sp[3];
335 inside_context.
a.
r = &slen2;
340 ps[startp + 1] = sp[2];
341 ps[startp + 2] = sp[1];
342 ps[startp + 3] = sp[0];
356 bezier *spl, uint32_t sflag, uint32_t eflag) {
358 double d, tlen, hlen, maxd;
360 if (sflag && eflag && endp == startp) {
366 if (hlen + tlen >= d) {
391 ps[endp] =
ps[endp + 1] =
s;
392 ps[endp + 2] =
ps[endp + 3] = t;
393 spl->
sflag = sflag, spl->
sp = p;
394 spl->
eflag = eflag, spl->
ep = q;
408 if (p.
x < q.
x) r.
x = q.
x - hlen;
409 else r.
x = q.
x + hlen;
413 if (p.
y < q.
y) r.
y = q.
y - hlen;
414 else r.
y = q.
y + hlen;
417 ps[endp + 2] =
ps[endp + 3] = r;
432 if (p.
x < q.
x) r.
x = p.
x + tlen;
433 else r.
x = p.
x - tlen;
437 if (p.
y < q.
y) r.
y = p.
y + tlen;
438 else r.
y = p.
y - tlen;
440 ps[startp] =
ps[startp + 1] = r;
456 if ((base_left.
x == P.
x && base_left.
y == P.
y) ||
457 (base_right.
x == P.
x && base_right.
y == P.
y)) {
461 const triangle line_join_shape = {{P, P, P}};
462 return line_join_shape;
464 const pointf A[] = {base_left, P};
465 const double dxA =
A[1].
x -
A[0].x;
466 const double dyA =
A[1].y -
A[0].y;
467 const double hypotA = hypot(dxA, dyA);
468 const double cosAlpha = dxA / hypotA;
469 const double sinAlpha = dyA / hypotA;
470 const double alpha = dyA > 0 ? acos(cosAlpha) : -acos(cosAlpha);
475 const pointf B[] = {P, base_right};
476 const double dxB =
B[1].
x -
B[0].x;
477 const double dyB =
B[1].y -
B[0].y;
478 const double hypotB = hypot(dxB, dyB);
479 const double cosBeta = dxB / hypotB;
480 const double beta = dyB > 0 ? acos(cosBeta) : -acos(cosBeta);
483 const double beta_rev = beta -
M_PI;
485 assert(theta >= 0 && theta <=
M_PI &&
"theta out of range");
489 const double stroke_miterlimit = 4.0;
490 const double normalized_miter_length = 1.0 / sin(theta / 2.0);
492 const double sinBeta = dyB / hypotB;
493 const double sinBetaMinusPi = -sinBeta;
494 const double cosBetaMinusPi = -cosBeta;
498 if (normalized_miter_length > stroke_miterlimit) {
505 const pointf Pbevel = {(P1.
x + P2.
x) / 2, (P1.
y + P2.
y) / 2};
506 const triangle line_join_shape = {{Pbevel, P1, P2}};
508 return line_join_shape;
512 const double l =
penwidth / 2.0 / tan(theta / 2.0);
514 const pointf P3 = {P1.
x + l * cosAlpha,
515 P1.
y + l * sinAlpha};
516 const triangle line_join_shape = {{P3, P1, P2}};
518 return line_join_shape;
522 uint32_t flag,
pointf *a) {
530 v.
x = -u.
y * arrowwidth;
531 v.
y = u.
x * arrowwidth;
535 pointf delta_base = {0, 0};
537 const pointf origin = {0, 0};
543 const pointf normal_tip = {-u.
x, -u.
y};
547 pointf delta_tip = {0, 0};
549 if (u.
x != 0 || u.
y != 0) {
551 const double cosPhi = P.
x / hypot(P.
x, P.
y);
552 const double sinPhi = P.
y / hypot(P.
x, P.
y);
553 const double phi = P.
y > 0 ? acos(cosPhi) : -acos(cosPhi);
559 const double dx_P_P1 = P1.
x - P.
x;
560 const double dy_P_P1 = P1.
y - P.
y;
561 const double hypot_P_P1 = hypot(dx_P_P1, dy_P_P1);
562 const double cosAlpha = dx_P_P1 / hypot_P_P1;
563 const double alpha = dy_P_P1 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
564 const double gamma =
alpha - phi;
565 const double delta_tip_length = hypot_P_P1 * cos(gamma);
566 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
571 const double dx_P_P2 = P2.
x - P.
x;
572 const double dy_P_P2 = P2.
y - P.
y;
573 const double hypot_P_P2 = hypot(dx_P_P2, dy_P_P2);
574 const double cosAlpha = dx_P_P2 / hypot_P_P2;
575 const double alpha = dy_P_P2 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
576 const double gamma =
alpha - phi;
577 const double delta_tip_length = hypot_P_P2 * cos(gamma);
578 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
640 double arrowwidth, shaftwidth;
644 arrowwidth *=
penwidth / (4 * arrowsize);
648 shaftwidth = 0.05 * (
penwidth - 1) / arrowsize;
650 v.
x = -u.
y * arrowwidth;
651 v.
y = u.
x * arrowwidth;
652 w.
x = -u.
y * shaftwidth;
653 w.
y = u.
x * shaftwidth;
656 m.
x = p.
x + u.
x * 0.5;
657 m.
y = p.
y + u.
y * 0.5;
659 pointf delta_base = {0, 0};
661 const pointf origin = {0, 0};
667 const pointf normal_tip = u;
668 const pointf inv_tip = {-u.
x, -u.
y};
671 pointf delta_tip = {0, 0};
673 if (u.
x != 0 || u.
y != 0) {
675 const double cosPhi = P.
x / hypot(P.
x, P.
y);
676 const double sinPhi = P.
y / hypot(P.
x, P.
y);
677 const double phi = P.
y > 0 ? acos(cosPhi) : -acos(cosPhi);
683 const double dx_P_P2 = P2.
x - P.
x;
684 const double dy_P_P2 = P2.
y - P.
y;
685 const double hypot_P_P2 = hypot(dx_P_P2, dy_P_P2);
686 const double cosAlpha = dx_P_P2 / hypot_P_P2;
687 const double alpha = dy_P_P2 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
688 const double gamma =
alpha - phi;
689 const double delta_tip_length = hypot_P_P2 * cos(gamma);
690 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
695 const double dx_P_P1 = P1.
x - P.
x;
696 const double dy_P_P1 = P1.
y - P.
y;
697 const double hypot_P_P1 = hypot(dx_P_P1, dy_P_P1);
698 const double cosAlpha = dx_P_P1 / hypot_P_P1;
699 const double alpha = dy_P_P1 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
700 const double gamma =
alpha - phi;
701 const double delta_tip_length = hypot_P_P1 * cos(gamma);
702 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
717 const pointf toe_base_right = origin;
722 const double dx_P_P1 = P1.
x - toe_P.
x;
723 const double dy_P_P1 = P1.
y - toe_P.
y;
724 const double hypot_P_P1 = hypot(dx_P_P1, dy_P_P1);
725 const double cosAlpha = dx_P_P1 / hypot_P_P1;
726 const double alpha = dy_P_P1 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
727 const double gamma =
alpha - phi;
728 const double delta_tip_length = -hypot_P_P1 * cos(gamma);
729 delta_base = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
764 a[3].
x = p.
x + delta_base.
x;
765 a[3].
y = p.
y + delta_base.
y;
767 a[5].
x = p.
x + delta_base.
x;
768 a[5].
y = p.
y + delta_base.
y;
823 m.
x = p.
x + u.
x * 0.2;
824 m.
y = p.
y + u.
y * 0.2;
825 n.
x = p.
x + u.
x * 0.6;
826 n.
y = p.
y + u.
y * 0.6;
828 const double length = hypot(u.
x, u.
y);
829 const double polygon_extend_over_polyline =
penwidth / 2 - 0.2 * length;
830 if (length > 0 && polygon_extend_over_polyline > 0) {
836 const double cosPhi = P.
x / hypot(P.
x, P.
y);
837 const double sinPhi = P.
y / hypot(P.
x, P.
y);
838 const pointf delta = {polygon_extend_over_polyline * cosPhi, polygon_extend_over_polyline * sinPhi};
882 m.
x = p.
x + u.
x * 0.8;
883 m.
y = p.
y + u.
y * 0.8;
889 if (u.
x != 0 || u.
y != 0) {
892 const double cosPhi = P.
x / hypot(P.
x, P.
y);
893 const double sinPhi = P.
y / hypot(P.
x, P.
y);
932 uint32_t flag,
pointf *a) {
937 r.
x = p.
x + u.
x / 2.;
938 r.
y = p.
y + u.
y / 2.;
942 const pointf origin = {0, 0};
1000 r = hypot(u.
x, u.
y) / 2.;
1004 if (u.
x != 0 || u.
y != 0) {
1007 const double cosPhi = P.
x / hypot(P.
x, P.
y);
1008 const double sinPhi = P.
y / hypot(P.
x, P.
y);
1017 AF[0].
x = p.
x + u.
x / 2. - r;
1018 AF[0].
y = p.
y + u.
y / 2. - r;
1019 AF[1].
x = p.
x + u.
x / 2. + r;
1020 AF[1].
y = p.
y + u.
y / 2. + r;
1048 const double cosPhi = P.
x / hypot(P.
x, P.
y);
1049 const double sinPhi = P.
y / hypot(P.
x, P.
y);
1059 v.
x = -u.
y * arrowwidth;
1060 v.
y = u.
x * arrowwidth;
1065 AF[0].
x = p.
x + v.
x + w.
x;
1066 AF[0].
y = p.
y + v.
y + w.
y;
1068 AF[3].
x = p.
x - v.
x + w.
x;
1069 AF[3].
y = p.
y - v.
y + w.
y;
1072 AF[1].
x = p.
x + 0.95 * v.
x + w.
x + w.
x * 4.0 / 3.0;
1073 AF[1].
y = AF[0].
y + w.
y * 4.0 / 3.0;
1075 AF[2].
x = p.
x - 0.95 * v.
x + w.
x + w.
x * 4.0 / 3.0;
1076 AF[2].
y = AF[3].
y + w.
y * 4.0 / 3.0;
1079 AF[1].
x = p.
x + 0.95 * v.
x + w.
x - w.
x * 4.0 / 3.0;
1080 AF[1].
y = AF[0].
y - w.
y * 4.0 / 3.0;
1082 AF[2].
x = p.
x - 0.95 * v.
x + w.
x - w.
x * 4.0 / 3.0;
1083 AF[2].
y = AF[3].
y - w.
y * 4.0 / 3.0;
1102 if (f == arrowtype->
type) {
1103 u.
x *= arrowtype->
lenfact * arrowsize;
1104 u.
y *= arrowtype->
lenfact * arrowsize;
1105 p = arrowtype->
gen(job, p, u, arrowsize,
penwidth, flag);
1116 double ax,ay,bx,by,cx,cy,
dx,
dy;
1142 bb.
UR.
x = fmax(ax, fmax(bx, fmax(cx,
dx)));
1143 bb.
UR.
y = fmax(ay, fmax(by, fmax(cy,
dy)));
1144 bb.
LL.
x = fmin(ax, fmin(bx, fmin(cx,
dx)));
1145 bb.
LL.
y = fmin(ay, fmin(by, fmin(cy,
dy)));
1151 double arrowsize,
double penwidth, uint32_t flag) {
1206 const pointf base1 = a[1];
1207 const pointf base2 = a[3];
1209 const double full_length = q.
x;
1210 assert(full_length > 0 &&
"non-positive full length");
1211 const double nominal_length = fabs(base1.
x - tip.
x);
1212 const double nominal_base_width = base2.
y - base1.
y;
1213 assert(nominal_base_width > 0 &&
"non-positive nominal base width");
1215 const double full_base_width =
1216 nominal_base_width * full_length / nominal_length;
1217 assert(full_base_width > 0 &&
"non-positive full base width");
1221 const double overlap_at_base =
penwidth / 2;
1223 const double length_where_width_is_penwidth =
1224 full_length *
penwidth / full_base_width;
1225 const double overlap_at_tip = length_where_width_is_penwidth;
1243 const double nominal_length = lenfact * arrowsize *
ARROW_LENGTH;
1244 double length = nominal_length;
1248 const double polygon_extend_over_polyline_at_start =
penwidth / 2 - (1 - 0.6) * nominal_length;
1249 if (polygon_extend_over_polyline_at_start > 0) {
1250 length += polygon_extend_over_polyline_at_start;
1253 const double polygon_extend_over_polyline_at_end =
penwidth / 2 - 0.2 * nominal_length;
1254 if (polygon_extend_over_polyline_at_start > 0) {
1255 length += polygon_extend_over_polyline_at_end;
1285 const pointf base1 = a[3];
1286 const pointf base2 = a[1];
1288 const double full_length = q.
x / 2;
1289 assert(full_length > 0 &&
"non-positive full length");
1290 const double nominal_length = fabs(base1.
x - tip.
x);
1291 const double nominal_base_width = base2.
y - base1.
y;
1292 assert(nominal_base_width > 0 &&
"non-positive nominal base width");
1294 const double full_base_width =
1295 nominal_base_width * full_length / nominal_length;
1296 assert(full_base_width > 0 &&
"non-positive full base width");
1302 const double length_where_width_is_penwidth =
1303 full_length *
penwidth / full_base_width;
1304 const double overlap_at_tip = length_where_width_is_penwidth;
1306 const double overlap = overlap_at_tip;
1310 return 2 * full_length -
overlap;
1338 const pointf base1 = a[1];
1339 const pointf base2 = a[7];
1341 const pointf shaft1 = a[3];
1342 const double full_length = q.
x;
1343 assert(full_length > 0 &&
"non-positive full length");
1344 const double full_length_without_shaft = full_length - (base1.
x - shaft1.
x);
1345 assert(full_length_without_shaft > 0 &&
"non-positive full length without shaft");
1346 const double nominal_length = fabs(base1.
x - tip.
x);
1347 const double nominal_base_width = base2.
y - base1.
y;
1348 assert(nominal_base_width > 0 &&
"non-positive nominal base width");
1350 const double full_base_width =
1351 nominal_base_width * full_length_without_shaft / nominal_length;
1352 assert(full_base_width > 0 &&
"non-positive full base width");
1356 const double overlap_at_base =
penwidth / 2;
1358 const double length_where_width_is_penwidth =
1359 full_length_without_shaft *
penwidth / full_base_width;
1360 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