29#define ARROW_LENGTH 10.
31#define NUMB_OF_ARROW_HEADS 4
34#define BITS_PER_ARROW 8
36#define BITS_PER_ARROW_TYPE 4
38#define ARR_TYPE_NONE (ARR_NONE)
39#define ARR_TYPE_NORM 1
40#define ARR_TYPE_CROW 2
43#define ARR_TYPE_DIAMOND 5
45#define ARR_TYPE_CURVE 7
50#define ARR_MOD_OPEN (1<<(BITS_PER_ARROW_TYPE+0))
51#define ARR_MOD_INV (1<<(BITS_PER_ARROW_TYPE+1))
52#define ARR_MOD_LEFT (1<<(BITS_PER_ARROW_TYPE+2))
53#define ARR_MOD_RIGHT (1<<(BITS_PER_ARROW_TYPE+3))
167 namelen = strlen(arrowname->name);
169 *flag |= arrowname->type;
186 }
while (next != rest);
206 agwarningf(
"Arrow type \"%s\" unknown - ignoring\n", next);
225 if (
streq(attr, arrowdir->dir)) {
226 *sflag = arrowdir->sflag;
227 *eflag = arrowdir->eflag;
234 if (arrowhead !=
NULL && ((attr =
agxget(e, arrowhead)))[0])
239 if (arrowtail !=
NULL && ((attr =
agxget(e, arrowtail)))[0])
260 if (arrowsize == 0) {
269 if (f == arrowtype->
type) {
282 return DIST2(p, inside_context->
a.
p[0]) <= inside_context->
a.
r[0];
286 size_t endp,
bezier *spl, uint32_t eflag) {
294 spl->
ep =
ps[endp + 3];
295 if (endp > startp &&
DIST2(
ps[endp],
ps[endp + 3]) < elen2) {
299 sp[2] =
ps[endp + 1];
300 sp[1] =
ps[endp + 2];
304 inside_context.
a.
p = &sp[0];
305 inside_context.
a.
r = &elen2;
310 ps[endp + 1] = sp[2];
311 ps[endp + 2] = sp[1];
312 ps[endp + 3] = sp[0];
317 size_t endp,
bezier *spl, uint32_t sflag) {
325 spl->
sp =
ps[startp];
326 if (endp > startp &&
DIST2(
ps[startp],
ps[startp + 3]) < slen2) {
329 sp[0] =
ps[startp + 3];
330 sp[1] =
ps[startp + 2];
331 sp[2] =
ps[startp + 1];
335 inside_context.
a.
p = &sp[3];
336 inside_context.
a.
r = &slen2;
341 ps[startp + 1] = sp[2];
342 ps[startp + 2] = sp[1];
343 ps[startp + 3] = sp[0];
357 bezier *spl, uint32_t sflag, uint32_t eflag) {
359 double d, tlen, hlen, maxd;
361 if (sflag && eflag && endp == startp) {
367 if (hlen + tlen >= d) {
392 ps[endp] =
ps[endp + 1] =
s;
393 ps[endp + 2] =
ps[endp + 3] = t;
394 spl->
sflag = sflag, spl->
sp = p;
395 spl->
eflag = eflag, spl->
ep = q;
409 if (p.
x < q.
x) r.
x = q.
x - hlen;
410 else r.
x = q.
x + hlen;
414 if (p.
y < q.
y) r.
y = q.
y - hlen;
415 else r.
y = q.
y + hlen;
418 ps[endp + 2] =
ps[endp + 3] = r;
433 if (p.
x < q.
x) r.
x = p.
x + tlen;
434 else r.
x = p.
x - tlen;
438 if (p.
y < q.
y) r.
y = p.
y + tlen;
439 else r.
y = p.
y - tlen;
441 ps[startp] =
ps[startp + 1] = r;
457 if ((base_left.
x == P.
x && base_left.
y == P.
y) ||
458 (base_right.
x == P.
x && base_right.
y == P.
y)) {
462 const triangle line_join_shape = {{P, P, P}};
463 return line_join_shape;
465 const pointf A[] = {base_left, P};
466 const double dxA =
A[1].
x -
A[0].x;
467 const double dyA =
A[1].y -
A[0].y;
468 const double hypotA = hypot(dxA, dyA);
469 const double cosAlpha = dxA / hypotA;
470 const double sinAlpha = dyA / hypotA;
471 const double alpha = dyA > 0 ? acos(cosAlpha) : -acos(cosAlpha);
476 const pointf B[] = {P, base_right};
477 const double dxB =
B[1].
x -
B[0].x;
478 const double dyB =
B[1].y -
B[0].y;
479 const double hypotB = hypot(dxB, dyB);
480 const double cosBeta = dxB / hypotB;
481 const double beta = dyB > 0 ? acos(cosBeta) : -acos(cosBeta);
484 const double beta_rev = beta -
M_PI;
486 assert(theta >= 0 && theta <=
M_PI &&
"theta out of range");
490 const double stroke_miterlimit = 4.0;
491 const double normalized_miter_length = 1.0 / sin(theta / 2.0);
493 const double sinBeta = dyB / hypotB;
494 const double sinBetaMinusPi = -sinBeta;
495 const double cosBetaMinusPi = -cosBeta;
499 if (normalized_miter_length > stroke_miterlimit) {
506 const pointf Pbevel = {(P1.
x + P2.
x) / 2, (P1.
y + P2.
y) / 2};
507 const triangle line_join_shape = {{Pbevel, P1, P2}};
509 return line_join_shape;
513 const double l =
penwidth / 2.0 / tan(theta / 2.0);
515 const pointf P3 = {P1.
x + l * cosAlpha,
516 P1.
y + l * sinAlpha};
517 const triangle line_join_shape = {{P3, P1, P2}};
519 return line_join_shape;
523 uint32_t flag,
pointf *a) {
531 v.
x = -u.
y * arrowwidth;
532 v.
y = u.
x * arrowwidth;
536 pointf delta_base = {0, 0};
538 const pointf origin = {0, 0};
544 const pointf normal_tip = {-u.
x, -u.
y};
548 pointf delta_tip = {0, 0};
550 if (u.
x != 0 || u.
y != 0) {
552 const double cosPhi = P.
x / hypot(P.
x, P.
y);
553 const double sinPhi = P.
y / hypot(P.
x, P.
y);
554 const double phi = P.
y > 0 ? acos(cosPhi) : -acos(cosPhi);
560 const double dx_P_P1 = P1.
x - P.
x;
561 const double dy_P_P1 = P1.
y - P.
y;
562 const double hypot_P_P1 = hypot(dx_P_P1, dy_P_P1);
563 const double cosAlpha = dx_P_P1 / hypot_P_P1;
564 const double alpha = dy_P_P1 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
565 const double gamma =
alpha - phi;
566 const double delta_tip_length = hypot_P_P1 * cos(gamma);
567 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
572 const double dx_P_P2 = P2.
x - P.
x;
573 const double dy_P_P2 = P2.
y - P.
y;
574 const double hypot_P_P2 = hypot(dx_P_P2, dy_P_P2);
575 const double cosAlpha = dx_P_P2 / hypot_P_P2;
576 const double alpha = dy_P_P2 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
577 const double gamma =
alpha - phi;
578 const double delta_tip_length = hypot_P_P2 * cos(gamma);
579 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
641 double arrowwidth, shaftwidth;
645 arrowwidth *=
penwidth / (4 * arrowsize);
649 shaftwidth = 0.05 * (
penwidth - 1) / arrowsize;
651 v.
x = -u.
y * arrowwidth;
652 v.
y = u.
x * arrowwidth;
653 w.
x = -u.
y * shaftwidth;
654 w.
y = u.
x * shaftwidth;
657 m.
x = p.
x + u.
x * 0.5;
658 m.
y = p.
y + u.
y * 0.5;
660 pointf delta_base = {0, 0};
662 const pointf origin = {0, 0};
668 const pointf normal_tip = u;
669 const pointf inv_tip = {-u.
x, -u.
y};
672 pointf delta_tip = {0, 0};
674 if (u.
x != 0 || u.
y != 0) {
676 const double cosPhi = P.
x / hypot(P.
x, P.
y);
677 const double sinPhi = P.
y / hypot(P.
x, P.
y);
678 const double phi = P.
y > 0 ? acos(cosPhi) : -acos(cosPhi);
684 const double dx_P_P2 = P2.
x - P.
x;
685 const double dy_P_P2 = P2.
y - P.
y;
686 const double hypot_P_P2 = hypot(dx_P_P2, dy_P_P2);
687 const double cosAlpha = dx_P_P2 / hypot_P_P2;
688 const double alpha = dy_P_P2 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
689 const double gamma =
alpha - phi;
690 const double delta_tip_length = hypot_P_P2 * cos(gamma);
691 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
696 const double dx_P_P1 = P1.
x - P.
x;
697 const double dy_P_P1 = P1.
y - P.
y;
698 const double hypot_P_P1 = hypot(dx_P_P1, dy_P_P1);
699 const double cosAlpha = dx_P_P1 / hypot_P_P1;
700 const double alpha = dy_P_P1 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
701 const double gamma =
alpha - phi;
702 const double delta_tip_length = hypot_P_P1 * cos(gamma);
703 delta_tip = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
718 const pointf toe_base_right = origin;
723 const double dx_P_P1 = P1.
x - toe_P.
x;
724 const double dy_P_P1 = P1.
y - toe_P.
y;
725 const double hypot_P_P1 = hypot(dx_P_P1, dy_P_P1);
726 const double cosAlpha = dx_P_P1 / hypot_P_P1;
727 const double alpha = dy_P_P1 > 0 ? acos(cosAlpha) : -acos(cosAlpha);
728 const double gamma =
alpha - phi;
729 const double delta_tip_length = -hypot_P_P1 * cos(gamma);
730 delta_base = (
pointf){delta_tip_length * cosPhi, delta_tip_length * sinPhi};
765 a[3].
x = p.
x + delta_base.
x;
766 a[3].
y = p.
y + delta_base.
y;
768 a[5].
x = p.
x + delta_base.
x;
769 a[5].
y = p.
y + delta_base.
y;
824 m.
x = p.
x + u.
x * 0.2;
825 m.
y = p.
y + u.
y * 0.2;
826 n.
x = p.
x + u.
x * 0.6;
827 n.
y = p.
y + u.
y * 0.6;
829 const double length = hypot(u.
x, u.
y);
830 const double polygon_extend_over_polyline =
penwidth / 2 - 0.2 *
length;
831 if (
length > 0 && polygon_extend_over_polyline > 0) {
837 const double cosPhi = P.
x / hypot(P.
x, P.
y);
838 const double sinPhi = P.
y / hypot(P.
x, P.
y);
839 const pointf delta = {polygon_extend_over_polyline * cosPhi, polygon_extend_over_polyline * sinPhi};
883 m.
x = p.
x + u.
x * 0.8;
884 m.
y = p.
y + u.
y * 0.8;
890 if (u.
x != 0 || u.
y != 0) {
893 const double cosPhi = P.
x / hypot(P.
x, P.
y);
894 const double sinPhi = P.
y / hypot(P.
x, P.
y);
933 uint32_t flag,
pointf *a) {
938 r.
x = p.
x + u.
x / 2.;
939 r.
y = p.
y + u.
y / 2.;
943 const pointf origin = {0, 0};
1001 r = hypot(u.
x, u.
y) / 2.;
1005 if (u.
x != 0 || u.
y != 0) {
1008 const double cosPhi = P.
x / hypot(P.
x, P.
y);
1009 const double sinPhi = P.
y / hypot(P.
x, P.
y);
1018 AF[0].
x = p.
x + u.
x / 2. - r;
1019 AF[0].
y = p.
y + u.
y / 2. - r;
1020 AF[1].
x = p.
x + u.
x / 2. + r;
1021 AF[1].
y = p.
y + u.
y / 2. + r;
1049 const double cosPhi = P.
x / hypot(P.
x, P.
y);
1050 const double sinPhi = P.
y / hypot(P.
x, P.
y);
1060 v.
x = -u.
y * arrowwidth;
1061 v.
y = u.
x * arrowwidth;
1066 AF[0].
x = p.
x + v.
x + w.
x;
1067 AF[0].
y = p.
y + v.
y + w.
y;
1069 AF[3].
x = p.
x - v.
x + w.
x;
1070 AF[3].
y = p.
y - v.
y + w.
y;
1073 AF[1].
x = p.
x + 0.95 * v.
x + w.
x + w.
x * 4.0 / 3.0;
1074 AF[1].
y = AF[0].
y + w.
y * 4.0 / 3.0;
1076 AF[2].
x = p.
x - 0.95 * v.
x + w.
x + w.
x * 4.0 / 3.0;
1077 AF[2].
y = AF[3].
y + w.
y * 4.0 / 3.0;
1080 AF[1].
x = p.
x + 0.95 * v.
x + w.
x - w.
x * 4.0 / 3.0;
1081 AF[1].
y = AF[0].
y - w.
y * 4.0 / 3.0;
1083 AF[2].
x = p.
x - 0.95 * v.
x + w.
x - w.
x * 4.0 / 3.0;
1084 AF[2].
y = AF[3].
y - w.
y * 4.0 / 3.0;
1103 if (f == arrowtype->
type) {
1104 u.
x *= arrowtype->
lenfact * arrowsize;
1105 u.
y *= arrowtype->
lenfact * arrowsize;
1106 p = arrowtype->
gen(job, p, u, arrowsize,
penwidth, flag);
1117 double ax,ay,bx,by,cx,cy,
dx,
dy;
1143 bb.
UR.
x = fmax(ax, fmax(bx, fmax(cx,
dx)));
1144 bb.
UR.
y = fmax(ay, fmax(by, fmax(cy,
dy)));
1145 bb.
LL.
x = fmin(ax, fmin(bx, fmin(cx,
dx)));
1146 bb.
LL.
y = fmin(ay, fmin(by, fmin(cy,
dy)));
1152 double arrowsize,
double penwidth, uint32_t flag) {
1207 const pointf base1 = a[1];
1208 const pointf base2 = a[3];
1210 const double full_length = q.
x;
1211 assert(full_length > 0 &&
"non-positive full length");
1212 const double nominal_length = fabs(base1.
x - tip.
x);
1213 const double nominal_base_width = base2.
y - base1.
y;
1214 assert(nominal_base_width > 0 &&
"non-positive nominal base width");
1216 const double full_base_width =
1217 nominal_base_width * full_length / nominal_length;
1218 assert(full_base_width > 0 &&
"non-positive full base width");
1222 const double overlap_at_base =
penwidth / 2;
1224 const double length_where_width_is_penwidth =
1225 full_length *
penwidth / full_base_width;
1226 const double overlap_at_tip = length_where_width_is_penwidth;
1244 const double nominal_length = lenfact * arrowsize *
ARROW_LENGTH;
1245 double length = nominal_length;
1249 const double polygon_extend_over_polyline_at_start =
penwidth / 2 - (1 - 0.6) * nominal_length;
1250 if (polygon_extend_over_polyline_at_start > 0) {
1251 length += polygon_extend_over_polyline_at_start;
1254 const double polygon_extend_over_polyline_at_end =
penwidth / 2 - 0.2 * nominal_length;
1255 if (polygon_extend_over_polyline_at_start > 0) {
1256 length += polygon_extend_over_polyline_at_end;
1286 const pointf base1 = a[3];
1287 const pointf base2 = a[1];
1289 const double full_length = q.
x / 2;
1290 assert(full_length > 0 &&
"non-positive full length");
1291 const double nominal_length = fabs(base1.
x - tip.
x);
1292 const double nominal_base_width = base2.
y - base1.
y;
1293 assert(nominal_base_width > 0 &&
"non-positive nominal base width");
1295 const double full_base_width =
1296 nominal_base_width * full_length / nominal_length;
1297 assert(full_base_width > 0 &&
"non-positive full base width");
1303 const double length_where_width_is_penwidth =
1304 full_length *
penwidth / full_base_width;
1305 const double overlap_at_tip = length_where_width_is_penwidth;
1307 const double overlap = overlap_at_tip;
1311 return 2 * full_length -
overlap;
1339 const pointf base1 = a[1];
1340 const pointf base2 = a[7];
1342 const pointf shaft1 = a[3];
1343 const double full_length = q.
x;
1344 assert(full_length > 0 &&
"non-positive full length");
1345 const double full_length_without_shaft = full_length - (base1.
x - shaft1.
x);
1346 assert(full_length_without_shaft > 0 &&
"non-positive full length without shaft");
1347 const double nominal_length = fabs(base1.
x - tip.
x);
1348 const double nominal_base_width = base2.
y - base1.
y;
1349 assert(nominal_base_width > 0 &&
"non-positive nominal base width");
1351 const double full_base_width =
1352 nominal_base_width * full_length_without_shaft / nominal_length;
1353 assert(full_base_width > 0 &&
"non-positive full base width");
1357 const double overlap_at_base =
penwidth / 2;
1359 const double length_where_width_is_penwidth =
1360 full_length_without_shaft *
penwidth / full_base_width;
1361 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(const pointf *V, double t, pointf *Left, pointf *Right)
double late_double(void *obj, attrsym_t *attr, double defaultValue, double minimum)
static Extype_t length(Exid_t *rhs, Exdisc_t *disc)
static void gen(Excc_t *, Exnode_t *)
geometric functions (e.g. on points and boxes)
static WUR pointf sub_pointf(pointf p, pointf q)
static WUR pointf add_pointf(pointf p, pointf q)
static WUR 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