Graphviz  2.41.20171026.1811
arrows.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 
15 #include "render.h"
16 
17 #define EPSILON .0001
18 
19 /* standard arrow length in points */
20 #define ARROW_LENGTH 10.
21 
22 #define NUMB_OF_ARROW_HEADS 4
23 /* each arrow in 8 bits. Room for NUMB_OF_ARROW_HEADS arrows in 32 bit int. */
24 
25 #define BITS_PER_ARROW 8
26 
27 #define BITS_PER_ARROW_TYPE 4
28 /* arrow types (in BITS_PER_ARROW_TYPE bits) */
29 #define ARR_TYPE_NONE (ARR_NONE)
30 #define ARR_TYPE_NORM 1
31 #define ARR_TYPE_CROW 2
32 #define ARR_TYPE_TEE 3
33 #define ARR_TYPE_BOX 4
34 #define ARR_TYPE_DIAMOND 5
35 #define ARR_TYPE_DOT 6
36 #define ARR_TYPE_CURVE 7
37 #define ARR_TYPE_GAP 8
38 /* Spare: 9-15 */
39 
40 /* arrow mods (in (BITS_PER_ARROW - BITS_PER_ARROW_TYPE) bits) */
41 #define ARR_MOD_OPEN (1<<(BITS_PER_ARROW_TYPE+0))
42 #define ARR_MOD_INV (1<<(BITS_PER_ARROW_TYPE+1))
43 #define ARR_MOD_LEFT (1<<(BITS_PER_ARROW_TYPE+2))
44 #define ARR_MOD_RIGHT (1<<(BITS_PER_ARROW_TYPE+3))
45 /* No spares */
46 
47 typedef struct arrowdir_t {
48  char *dir;
49  int sflag;
50  int eflag;
51 } arrowdir_t;
52 
53 static arrowdir_t Arrowdirs[] = {
54  {"forward", ARR_TYPE_NONE, ARR_TYPE_NORM},
55  {"back", ARR_TYPE_NORM, ARR_TYPE_NONE},
56  {"both", ARR_TYPE_NORM, ARR_TYPE_NORM},
57  {"none", ARR_TYPE_NONE, ARR_TYPE_NONE},
58  {(char *) 0, ARR_TYPE_NONE, ARR_TYPE_NONE}
59 };
60 
61 typedef struct arrowname_t {
62  char *name;
63  int type;
64 } arrowname_t;
65 
66 static arrowname_t Arrowsynonyms[] = {
67  /* synonyms for deprecated arrow names - included for backward compatibility */
68  /* evaluated before primary names else "invempty" would give different results */
69  {"invempty", (ARR_TYPE_NORM | ARR_MOD_INV | ARR_MOD_OPEN)}, /* oinv */
70  {(char *) 0, (ARR_TYPE_NONE)}
71 };
72 
73 static arrowname_t Arrowmods[] = {
74  {"o", ARR_MOD_OPEN},
75  {"r", ARR_MOD_RIGHT},
76  {"l", ARR_MOD_LEFT},
77  /* deprecated alternates for backward compat */
78  {"e", ARR_MOD_OPEN}, /* o - needed for "ediamond" */
79  {"half", ARR_MOD_LEFT}, /* l - needed for "halfopen" */
80  {(char *) 0, ARR_TYPE_NONE}
81 };
82 
83 static arrowname_t Arrownames[] = {
84  {"normal", ARR_TYPE_NORM},
85  {"crow", ARR_TYPE_CROW},
86  {"tee", ARR_TYPE_TEE},
87  {"box", ARR_TYPE_BOX},
88  {"diamond", ARR_TYPE_DIAMOND},
89  {"dot", ARR_TYPE_DOT},
90 // {"none", ARR_TYPE_NONE},
91  {"none", ARR_TYPE_GAP},
92 // {"gap", ARR_TYPE_GAP},
93  /* ARR_MOD_INV is used only here to define two additional shapes
94  since not all types can use it */
95  {"inv", (ARR_TYPE_NORM | ARR_MOD_INV)},
96  {"vee", (ARR_TYPE_CROW | ARR_MOD_INV)},
97  /* WARNING ugly kludge to deal with "o" v "open" conflict */
98  /* Define "open" as just "pen" since "o" already taken as ARR_MOD_OPEN */
99  /* Note that ARR_MOD_OPEN has no meaning for ARR_TYPE_CROW shape */
100  {"pen", (ARR_TYPE_CROW | ARR_MOD_INV)},
101  /* WARNING ugly kludge to deal with "e" v "empty" conflict */
102  /* Define "empty" as just "mpty" since "e" already taken as ARR_MOD_OPEN */
103  /* Note that ARR_MOD_OPEN has expected meaning for ARR_TYPE_NORM shape */
104  {"mpty", ARR_TYPE_NORM},
105  {"curve", ARR_TYPE_CURVE},
106  {"icurve", (ARR_TYPE_CURVE | ARR_MOD_INV)},
107  {(char *) 0, ARR_TYPE_NONE}
108 };
109 
110 typedef struct arrowtype_t {
111  int type;
112  double lenfact; /* ratio of length of this arrow type to standard arrow */
113  void (*gen) (GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag); /* generator function for type */
114 } arrowtype_t;
115 
116 /* forward declaration of functions used in Arrowtypes[] */
117 static void arrow_type_normal(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
118 static void arrow_type_crow(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
119 static void arrow_type_tee(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
120 static void arrow_type_box(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
121 static void arrow_type_diamond(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
122 static void arrow_type_dot(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
123 static void arrow_type_curve(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
124 static void arrow_type_gap(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag);
125 
126 static arrowtype_t Arrowtypes[] = {
127  {ARR_TYPE_NORM, 1.0, arrow_type_normal},
128  {ARR_TYPE_CROW, 1.0, arrow_type_crow},
129  {ARR_TYPE_TEE, 0.5, arrow_type_tee},
130  {ARR_TYPE_BOX, 1.0, arrow_type_box},
131  {ARR_TYPE_DIAMOND, 1.2, arrow_type_diamond},
132  {ARR_TYPE_DOT, 0.8, arrow_type_dot},
133  {ARR_TYPE_CURVE, 1.0, arrow_type_curve},
134  {ARR_TYPE_GAP, 0.5, arrow_type_gap},
135  {ARR_TYPE_NONE, 0.0, NULL}
136 };
137 
138 static char *arrow_match_name_frag(char *name, arrowname_t * arrownames, int *flag)
139 {
140  arrowname_t *arrowname;
141  size_t namelen = 0;
142  char *rest = name;
143 
144  for (arrowname = arrownames; arrowname->name; arrowname++) {
145  namelen = strlen(arrowname->name);
146  if (strncmp(name, arrowname->name, namelen) == 0) {
147  *flag |= arrowname->type;
148  rest += namelen;
149  break;
150  }
151  }
152  return rest;
153 }
154 
155 static char *arrow_match_shape(char *name, int *flag)
156 {
157  char *next, *rest;
158  int f = ARR_TYPE_NONE;
159 
160  rest = arrow_match_name_frag(name, Arrowsynonyms, &f);
161  if (rest == name) {
162  do {
163  next = rest;
164  rest = arrow_match_name_frag(next, Arrowmods, &f);
165  } while (next != rest);
166  rest = arrow_match_name_frag(rest, Arrownames, &f);
167  }
168  if (f && !(f & ((1 << BITS_PER_ARROW_TYPE) - 1)))
169  f |= ARR_TYPE_NORM;
170  *flag |= f;
171  return rest;
172 }
173 
174 static void arrow_match_name(char *name, int *flag)
175 {
176  char *rest = name;
177  char *next;
178  int i, f;
179 
180  *flag = 0;
181  for (i = 0; *rest != '\0' && i < NUMB_OF_ARROW_HEADS; ) {
182  f = ARR_TYPE_NONE;
183  next = rest;
184  rest = arrow_match_shape(next, &f);
185  if (f == ARR_TYPE_NONE) {
186  agerr(AGWARN, "Arrow type \"%s\" unknown - ignoring\n", next);
187  return;
188  }
189  if (f == ARR_TYPE_GAP && i == (NUMB_OF_ARROW_HEADS -1))
190  f = ARR_TYPE_NONE;
191  if ((f == ARR_TYPE_GAP) && (i == 0) && (*rest == '\0'))
192  f = ARR_TYPE_NONE;
193  if (f != ARR_TYPE_NONE)
194  *flag |= (f << (i++ * BITS_PER_ARROW));
195  }
196 }
197 
198 void arrow_flags(Agedge_t * e, int *sflag, int *eflag)
199 {
200  char *attr;
201  arrowdir_t *arrowdir;
202 
203  *sflag = ARR_TYPE_NONE;
205  if (E_dir && ((attr = agxget(e, E_dir)))[0]) {
206  for (arrowdir = Arrowdirs; arrowdir->dir; arrowdir++) {
207  if (streq(attr, arrowdir->dir)) {
208  *sflag = arrowdir->sflag;
209  *eflag = arrowdir->eflag;
210  break;
211  }
212  }
213  }
214  if (E_arrowhead && (*eflag == ARR_TYPE_NORM) && ((attr = agxget(e, E_arrowhead)))[0])
215  arrow_match_name(attr, eflag);
216  if (E_arrowtail && (*sflag == ARR_TYPE_NORM) && ((attr = agxget(e, E_arrowtail)))[0])
217  arrow_match_name(attr, sflag);
218  if (ED_conc_opp_flag(e)) {
219  edge_t *f;
220  int s0, e0;
221  /* pick up arrowhead of opposing edge */
222  f = agfindedge(agraphof(aghead(e)), aghead(e), agtail(e));
223  arrow_flags(f, &s0, &e0);
224  *eflag = *eflag | s0;
225  *sflag = *sflag | e0;
226  }
227 }
228 
229 double arrow_length(edge_t * e, int flag)
230 {
231  arrowtype_t *arrowtype;
232  double lenfact = 0.0;
233  int f, i;
234 
235  for (i = 0; i < NUMB_OF_ARROW_HEADS; i++) {
236  /* we don't simply index with flag because arrowtypes are not necessarily sorted */
237  f = (flag >> (i * BITS_PER_ARROW)) & ((1 << BITS_PER_ARROW_TYPE) - 1);
238  for (arrowtype = Arrowtypes; arrowtype->gen; arrowtype++) {
239  if (f == arrowtype->type) {
240  lenfact += arrowtype->lenfact;
241  break;
242  }
243  }
244  }
245  /* The original was missing the factor E_arrowsz, but I believe it
246  should be here for correct arrow clipping */
247  return ARROW_LENGTH * lenfact * late_double(e, E_arrowsz, 1.0, 0.0);
248 }
249 
250 /* inside function for calls to bezier_clip */
251 static boolean inside(inside_t * inside_context, pointf p)
252 {
253  return DIST2(p, inside_context->a.p[0]) <= inside_context->a.r[0];
254 }
255 
256 int arrowEndClip(edge_t* e, pointf * ps, int startp,
257  int endp, bezier * spl, int eflag)
258 {
259  inside_t inside_context;
260  pointf sp[4];
261  double elen, elen2;
262 
263  elen = arrow_length(e, eflag);
264  elen2 = elen * elen;
265  spl->eflag = eflag, spl->ep = ps[endp + 3];
266  if (endp > startp && DIST2(ps[endp], ps[endp + 3]) < elen2) {
267  endp -= 3;
268  }
269  sp[3] = ps[endp];
270  sp[2] = ps[endp + 1];
271  sp[1] = ps[endp + 2];
272  sp[0] = spl->ep; /* ensure endpoint starts inside */
273 
274  inside_context.a.p = &sp[0];
275  inside_context.a.r = &elen2;
276  bezier_clip(&inside_context, inside, sp, TRUE);
277 
278  ps[endp] = sp[3];
279  ps[endp + 1] = sp[2];
280  ps[endp + 2] = sp[1];
281  ps[endp + 3] = sp[0];
282  return endp;
283 }
284 
285 int arrowStartClip(edge_t* e, pointf * ps, int startp,
286  int endp, bezier * spl, int sflag)
287 {
288  inside_t inside_context;
289  pointf sp[4];
290  double slen, slen2;
291 
292  slen = arrow_length(e, sflag);
293  slen2 = slen * slen;
294  spl->sflag = sflag, spl->sp = ps[startp];
295  if (endp > startp && DIST2(ps[startp], ps[startp + 3]) < slen2) {
296  startp += 3;
297  }
298  sp[0] = ps[startp + 3];
299  sp[1] = ps[startp + 2];
300  sp[2] = ps[startp + 1];
301  sp[3] = spl->sp; /* ensure endpoint starts inside */
302 
303  inside_context.a.p = &sp[3];
304  inside_context.a.r = &slen2;
305  bezier_clip(&inside_context, inside, sp, FALSE);
306 
307  ps[startp] = sp[3];
308  ps[startp + 1] = sp[2];
309  ps[startp + 2] = sp[1];
310  ps[startp + 3] = sp[0];
311  return startp;
312 }
313 
314 /* arrowOrthoClip:
315  * For orthogonal routing, we know each Bezier of spl is a horizontal or vertical
316  * line segment. We need to guarantee the B-spline stays this way. At present, we shrink
317  * the arrows if necessary to fit the last segment at either end. Alternatively, we could
318  * maintain the arrow size by dropping the 3 points of spl, and adding a new spl encoding
319  * the arrow, something "ex_0,y_0 x_1,y_1 x_1,y_1 x_1,y_1 x_1,y_1", when the last line
320  * segment is x_1,y_1 x_2,y_2 x_3,y_3 x_0,y_0. With a good deal more work, we could guarantee
321  * that the truncated spl clips to the arrow shape.
322  */
323 void arrowOrthoClip(edge_t* e, pointf* ps, int startp, int endp, bezier* spl, int sflag, int eflag)
324 {
325  pointf p, q, r, s, t;
326  double d, tlen, hlen, maxd;
327 
328  if (sflag && eflag && (endp == startp)) { /* handle special case of two arrows on a single segment */
329  p = ps[endp];
330  q = ps[endp+3];
331  tlen = arrow_length (e, sflag);
332  hlen = arrow_length (e, eflag);
333  d = DIST(p, q);
334  if (hlen + tlen >= d) {
335  hlen = tlen = d/3.0;
336  }
337  if (p.y == q.y) { /* horz segment */
338  s.y = t.y = p.y;
339  if (p.x < q.x) {
340  t.x = q.x - hlen;
341  s.x = p.x + tlen;
342  }
343  else {
344  t.x = q.x + hlen;
345  s.x = p.x - tlen;
346  }
347  }
348  else { /* vert segment */
349  s.x = t.x = p.x;
350  if (p.y < q.y) {
351  t.y = q.y - hlen;
352  s.y = p.y + tlen;
353  }
354  else {
355  t.y = q.y + hlen;
356  s.y = p.y - tlen;
357  }
358  }
359  ps[endp] = ps[endp + 1] = s;
360  ps[endp + 2] = ps[endp + 3] = t;
361  spl->eflag = eflag, spl->ep = p;
362  spl->sflag = sflag, spl->sp = q;
363  return;
364  }
365  if (eflag) {
366  hlen = arrow_length(e, eflag);
367  p = ps[endp];
368  q = ps[endp+3];
369  d = DIST(p, q);
370  maxd = 0.9*d;
371  if (hlen >= maxd) { /* arrow too long */
372  hlen = maxd;
373  }
374  if (p.y == q.y) { /* horz segment */
375  r.y = p.y;
376  if (p.x < q.x) r.x = q.x - hlen;
377  else r.x = q.x + hlen;
378  }
379  else { /* vert segment */
380  r.x = p.x;
381  if (p.y < q.y) r.y = q.y - hlen;
382  else r.y = q.y + hlen;
383  }
384  ps[endp + 1] = p;
385  ps[endp + 2] = ps[endp + 3] = r;
386  spl->eflag = eflag;
387  spl->ep = q;
388  }
389  if (sflag) {
390  tlen = arrow_length(e, sflag);
391  p = ps[startp];
392  q = ps[startp+3];
393  d = DIST(p, q);
394  maxd = 0.9*d;
395  if (tlen >= maxd) { /* arrow too long */
396  tlen = maxd;
397  }
398  if (p.y == q.y) { /* horz segment */
399  r.y = p.y;
400  if (p.x < q.x) r.x = p.x + tlen;
401  else r.x = p.x - tlen;
402  }
403  else { /* vert segment */
404  r.x = p.x;
405  if (p.y < q.y) r.y = p.y + tlen;
406  else r.y = p.y - tlen;
407  }
408  ps[startp] = ps[startp + 1] = r;
409  ps[startp + 2] = q;
410  spl->sflag = sflag;
411  spl->sp = p;
412  }
413 }
414 
415 static void arrow_type_normal(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
416 {
417  pointf q, v, a[5];
418  double arrowwidth;
419 
420  arrowwidth = 0.35;
421  if (penwidth > 4)
422  arrowwidth *= penwidth / 4;
423 
424  v.x = -u.y * arrowwidth;
425  v.y = u.x * arrowwidth;
426  q.x = p.x + u.x;
427  q.y = p.y + u.y;
428  if (flag & ARR_MOD_INV) {
429  a[0] = a[4] = p;
430  a[1].x = p.x - v.x;
431  a[1].y = p.y - v.y;
432  a[2] = q;
433  a[3].x = p.x + v.x;
434  a[3].y = p.y + v.y;
435  } else {
436  a[0] = a[4] = q;
437  a[1].x = q.x - v.x;
438  a[1].y = q.y - v.y;
439  a[2] = p;
440  a[3].x = q.x + v.x;
441  a[3].y = q.y + v.y;
442  }
443  if (flag & ARR_MOD_LEFT)
444  gvrender_polygon(job, a, 3, !(flag & ARR_MOD_OPEN));
445  else if (flag & ARR_MOD_RIGHT)
446  gvrender_polygon(job, &a[2], 3, !(flag & ARR_MOD_OPEN));
447  else
448  gvrender_polygon(job, &a[1], 3, !(flag & ARR_MOD_OPEN));
449 }
450 
451 static void arrow_type_crow(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
452 {
453  pointf m, q, v, w, a[9];
454  double arrowwidth, shaftwidth;
455 
456  arrowwidth = 0.45;
457  if (penwidth > (4 * arrowsize) && (flag & ARR_MOD_INV))
458  arrowwidth *= penwidth / (4 * arrowsize);
459 
460  shaftwidth = 0;
461  if (penwidth > 1 && (flag & ARR_MOD_INV))
462  shaftwidth = 0.05 * (penwidth - 1) / arrowsize; /* arrowsize to cancel the arrowsize term already in u */
463 
464  v.x = -u.y * arrowwidth;
465  v.y = u.x * arrowwidth;
466  w.x = -u.y * shaftwidth;
467  w.y = u.x * shaftwidth;
468  q.x = p.x + u.x;
469  q.y = p.y + u.y;
470  m.x = p.x + u.x * 0.5;
471  m.y = p.y + u.y * 0.5;
472  if (flag & ARR_MOD_INV) { /* vee */
473  a[0] = a[8] = p;
474  a[1].x = q.x - v.x;
475  a[1].y = q.y - v.y;
476  a[2].x = m.x - w.x;
477  a[2].y = m.y - w.y;
478  a[3].x = q.x - w.x;
479  a[3].y = q.y - w.y;
480  a[4] = q;
481  a[5].x = q.x + w.x;
482  a[5].y = q.y + w.y;
483  a[6].x = m.x + w.x;
484  a[6].y = m.y + w.y;
485  a[7].x = q.x + v.x;
486  a[7].y = q.y + v.y;
487  } else { /* crow */
488  a[0] = a[8] = q;
489  a[1].x = p.x - v.x;
490  a[1].y = p.y - v.y;
491  a[2].x = m.x - w.x;
492  a[2].y = m.y - w.y;
493  a[3].x = p.x;
494  a[3].y = p.y;
495  a[4] = p;
496  a[5].x = p.x;
497  a[5].y = p.y;
498  a[6].x = m.x + w.x;
499  a[6].y = m.y + w.y;
500  a[7].x = p.x + v.x;
501  a[7].y = p.y + v.y;
502  }
503  if (flag & ARR_MOD_LEFT)
504  gvrender_polygon(job, a, 6, 1);
505  else if (flag & ARR_MOD_RIGHT)
506  gvrender_polygon(job, &a[3], 6, 1);
507  else
508  gvrender_polygon(job, a, 9, 1);
509 }
510 
511 static void arrow_type_gap(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
512 {
513  pointf q, a[2];
514 
515  q.x = p.x + u.x;
516  q.y = p.y + u.y;
517  a[0] = p;
518  a[1] = q;
519  gvrender_polyline(job, a, 2);
520 }
521 
522 static void arrow_type_tee(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
523 {
524  pointf m, n, q, v, a[4];
525 
526  v.x = -u.y;
527  v.y = u.x;
528  q.x = p.x + u.x;
529  q.y = p.y + u.y;
530  m.x = p.x + u.x * 0.2;
531  m.y = p.y + u.y * 0.2;
532  n.x = p.x + u.x * 0.6;
533  n.y = p.y + u.y * 0.6;
534  a[0].x = m.x + v.x;
535  a[0].y = m.y + v.y;
536  a[1].x = m.x - v.x;
537  a[1].y = m.y - v.y;
538  a[2].x = n.x - v.x;
539  a[2].y = n.y - v.y;
540  a[3].x = n.x + v.x;
541  a[3].y = n.y + v.y;
542  if (flag & ARR_MOD_LEFT) {
543  a[0] = m;
544  a[3] = n;
545  } else if (flag & ARR_MOD_RIGHT) {
546  a[1] = m;
547  a[2] = n;
548  }
549  gvrender_polygon(job, a, 4, 1);
550  a[0] = p;
551  a[1] = q;
552  gvrender_polyline(job, a, 2);
553 }
554 
555 static void arrow_type_box(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
556 {
557  pointf m, q, v, a[4];
558 
559  v.x = -u.y * 0.4;
560  v.y = u.x * 0.4;
561  m.x = p.x + u.x * 0.8;
562  m.y = p.y + u.y * 0.8;
563  q.x = p.x + u.x;
564  q.y = p.y + u.y;
565  a[0].x = p.x + v.x;
566  a[0].y = p.y + v.y;
567  a[1].x = p.x - v.x;
568  a[1].y = p.y - v.y;
569  a[2].x = m.x - v.x;
570  a[2].y = m.y - v.y;
571  a[3].x = m.x + v.x;
572  a[3].y = m.y + v.y;
573  if (flag & ARR_MOD_LEFT) {
574  a[0] = p;
575  a[3] = m;
576  } else if (flag & ARR_MOD_RIGHT) {
577  a[1] = p;
578  a[2] = m;
579  }
580  gvrender_polygon(job, a, 4, !(flag & ARR_MOD_OPEN));
581  a[0] = m;
582  a[1] = q;
583  gvrender_polyline(job, a, 2);
584 }
585 
586 static void arrow_type_diamond(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
587 {
588  pointf q, r, v, a[5];
589 
590  v.x = -u.y / 3.;
591  v.y = u.x / 3.;
592  r.x = p.x + u.x / 2.;
593  r.y = p.y + u.y / 2.;
594  q.x = p.x + u.x;
595  q.y = p.y + u.y;
596  a[0] = a[4] = q;
597  a[1].x = r.x + v.x;
598  a[1].y = r.y + v.y;
599  a[2] = p;
600  a[3].x = r.x - v.x;
601  a[3].y = r.y - v.y;
602  if (flag & ARR_MOD_LEFT)
603  gvrender_polygon(job, &a[2], 3, !(flag & ARR_MOD_OPEN));
604  else if (flag & ARR_MOD_RIGHT)
605  gvrender_polygon(job, a, 3, !(flag & ARR_MOD_OPEN));
606  else
607  gvrender_polygon(job, a, 4, !(flag & ARR_MOD_OPEN));
608 }
609 
610 static void arrow_type_dot(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
611 {
612  double r;
613  pointf AF[2];
614 
615  r = sqrt(u.x * u.x + u.y * u.y) / 2.;
616  AF[0].x = p.x + u.x / 2. - r;
617  AF[0].y = p.y + u.y / 2. - r;
618  AF[1].x = p.x + u.x / 2. + r;
619  AF[1].y = p.y + u.y / 2. + r;
620  gvrender_ellipse(job, AF, 2, !(flag & ARR_MOD_OPEN));
621 }
622 
623 
624 /* Draw a concave semicircle using a single cubic bezier curve that touches p at its midpoint.
625  * See http://digerati-illuminatus.blogspot.com.au/2008/05/approximating-semicircle-with-cubic.html for details.
626  */
627 static void arrow_type_curve(GVJ_t* job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
628 {
629  double arrowwidth = penwidth > 4 ? 0.5 * penwidth / 4 : 0.5;
630  pointf q, v, w;
631  pointf AF[4], a[2];
632 
633  q.x = p.x + u.x;
634  q.y = p.y + u.y;
635  v.x = -u.y * arrowwidth;
636  v.y = u.x * arrowwidth;
637  w.x = v.y; // same direction as u, same magnitude as v.
638  w.y = -v.x;
639  a[0] = p;
640  a[1] = q;
641 
642  AF[0].x = p.x + v.x + w.x;
643  AF[0].y = p.y + v.y + w.y;
644 
645  AF[3].x = p.x - v.x + w.x;
646  AF[3].y = p.y - v.y + w.y;
647 
648  if (flag & ARR_MOD_INV) { /* ----(-| */
649  AF[1].x = p.x + 0.95 * v.x + w.x + w.x * 4.0 / 3.0;
650  AF[1].y = AF[0].y + w.y * 4.0 / 3.0;
651 
652  AF[2].x = p.x - 0.95 * v.x + w.x + w.x * 4.0 / 3.0;
653  AF[2].y = AF[3].y + w.y * 4.0 / 3.0;
654  }
655  else { /* ----)-| */
656  AF[1].x = p.x + 0.95 * v.x + w.x - w.x * 4.0 / 3.0;
657  AF[1].y = AF[0].y - w.y * 4.0 / 3.0;
658 
659  AF[2].x = p.x - 0.95 * v.x + w.x - w.x * 4.0 / 3.0;
660  AF[2].y = AF[3].y - w.y * 4.0 / 3.0;
661  }
662 
663  gvrender_polyline(job, a, 2);
664  if (flag & ARR_MOD_LEFT)
665  Bezier(AF, 3, 0.5, NULL, AF);
666  else if (flag & ARR_MOD_RIGHT)
667  Bezier(AF, 3, 0.5, AF, NULL);
668  gvrender_beziercurve(job, AF, sizeof(AF) / sizeof(pointf), FALSE, FALSE, FALSE);
669 }
670 
671 
672 static pointf arrow_gen_type(GVJ_t * job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
673 {
674  int f;
675  arrowtype_t *arrowtype;
676 
677  f = flag & ((1 << BITS_PER_ARROW_TYPE) - 1);
678  for (arrowtype = Arrowtypes; arrowtype->type; arrowtype++) {
679  if (f == arrowtype->type) {
680  u.x *= arrowtype->lenfact * arrowsize;
681  u.y *= arrowtype->lenfact * arrowsize;
682  (arrowtype->gen) (job, p, u, arrowsize, penwidth, flag);
683  p.x = p.x + u.x;
684  p.y = p.y + u.y;
685  break;
686  }
687  }
688  return p;
689 }
690 
691 boxf arrow_bb(pointf p, pointf u, double arrowsize, int flag)
692 {
693  double s;
694  boxf bb;
695  double ax,ay,bx,by,cx,cy,dx,dy;
696  double ux2, uy2;
697 
698  /* generate arrowhead vector */
699  u.x -= p.x;
700  u.y -= p.y;
701  /* the EPSILONs are to keep this stable as length of u approaches 0.0 */
702  s = ARROW_LENGTH * arrowsize / (sqrt(u.x * u.x + u.y * u.y) + EPSILON);
703  u.x += (u.x >= 0.0) ? EPSILON : -EPSILON;
704  u.y += (u.y >= 0.0) ? EPSILON : -EPSILON;
705  u.x *= s;
706  u.y *= s;
707 
708  /* compute all 4 corners of rotated arrowhead bounding box */
709  ux2 = u.x / 2.;
710  uy2 = u.y / 2.;
711  ax = p.x - uy2;
712  ay = p.y - ux2;
713  bx = p.x + uy2;
714  by = p.y + ux2;
715  cx = ax + u.x;
716  cy = ay + u.y;
717  dx = bx + u.x;
718  dy = by + u.y;
719 
720  /* compute a right bb */
721  bb.UR.x = MAX(ax, MAX(bx, MAX(cx, dx)));
722  bb.UR.y = MAX(ay, MAX(by, MAX(cy, dy)));
723  bb.LL.x = MIN(ax, MIN(bx, MIN(cx, dx)));
724  bb.LL.y = MIN(ay, MIN(by, MIN(cy, dy)));
725 
726  return bb;
727 }
728 
729 void arrow_gen(GVJ_t * job, emit_state_t emit_state, pointf p, pointf u, double arrowsize, double penwidth, int flag)
730 {
731  obj_state_t *obj = job->obj;
732  double s;
733  int i, f;
734  emit_state_t old_emit_state;
735 
736  old_emit_state = obj->emit_state;
737  obj->emit_state = emit_state;
738 
739  /* Dotted and dashed styles on the arrowhead are ugly (dds) */
740  /* linewidth needs to be reset */
742 
743  gvrender_set_penwidth(job, penwidth);
744 
745  /* generate arrowhead vector */
746  u.x -= p.x;
747  u.y -= p.y;
748  /* the EPSILONs are to keep this stable as length of u approaches 0.0 */
749  s = ARROW_LENGTH / (sqrt(u.x * u.x + u.y * u.y) + EPSILON);
750  u.x += (u.x >= 0.0) ? EPSILON : -EPSILON;
751  u.y += (u.y >= 0.0) ? EPSILON : -EPSILON;
752  u.x *= s;
753  u.y *= s;
754 
755  /* the first arrow head - closest to node */
756  for (i = 0; i < NUMB_OF_ARROW_HEADS; i++) {
757  f = (flag >> (i * BITS_PER_ARROW)) & ((1 << BITS_PER_ARROW) - 1);
758  if (f == ARR_TYPE_NONE)
759  break;
760  p = arrow_gen_type(job, p, u, arrowsize, penwidth, f);
761  }
762 
763  obj->emit_state = old_emit_state;
764 }
char * name
Definition: arrows.c:62
#define ARR_TYPE_CURVE
Definition: arrows.c:36
#define MAX(a, b)
Definition: agerror.c:17
void gvrender_polygon(GVJ_t *job, pointf *af, int n, int filled)
Definition: gvrender.c:572
int eflag
Definition: types.h:112
int type
Definition: arrows.c:63
#define MIN(a, b)
Definition: arith.h:35
emit_state_t
Definition: gvcjob.h:182
#define ARR_MOD_OPEN
Definition: arrows.c:41
int type
Definition: arrows.c:111
double lenfact
Definition: arrows.c:112
Definition: geom.h:28
CGRAPH_API int agisdirected(Agraph_t *g)
Definition: graph.c:182
void(* gen)(GVJ_t *job, pointf p, pointf u, double arrowsize, double penwidth, int flag)
Definition: arrows.c:113
#define ARR_TYPE_NONE
Definition: arrows.c:29
#define BITS_PER_ARROW
Definition: arrows.c:25
#define ARR_TYPE_DOT
Definition: arrows.c:35
#define ARR_MOD_LEFT
Definition: arrows.c:43
int agerr(agerrlevel_t level, const char *fmt,...)
Definition: agerror.c:141
#define BITS_PER_ARROW_TYPE
Definition: arrows.c:27
void arrow_flags(Agedge_t *e, int *sflag, int *eflag)
Definition: arrows.c:198
int arrowEndClip(edge_t *e, pointf *ps, int startp, int endp, bezier *spl, int eflag)
Definition: arrows.c:256
double arrow_length(edge_t *e, int flag)
Definition: arrows.c:229
Definition: gvcjob.h:271
#define ARR_MOD_INV
Definition: arrows.c:42
struct inside_t::@18 a
#define ED_conc_opp_flag(e)
Definition: types.h:582
Definition: cgraph.h:388
obj_state_t * obj
Definition: gvcjob.h:278
CGRAPH_API Agraph_t * agraphof(void *obj)
Definition: obj.c:185
CGRAPH_API Agnode_t * agtail(Agedge_t *e)
Definition: edge.c:525
#define DIST(p, q)
Definition: geom.h:60
#define EPSILON
Definition: arrows.c:17
EXTERN Agsym_t * E_dir
Definition: globals.h:107
CGRAPH_API Agnode_t * aghead(Agedge_t *e)
Definition: edge.c:533
#define NUMB_OF_ARROW_HEADS
Definition: arrows.c:22
EXTERN Agsym_t * E_arrowhead
Definition: globals.h:107
#define DIST2(p, q)
Definition: geom.h:59
double y
Definition: geom.h:28
int sflag
Definition: types.h:111
#define ARR_TYPE_NORM
Definition: arrows.c:30
EXTERN Agsym_t * E_arrowtail
Definition: globals.h:107
pointf sp
Definition: types.h:113
#define ARR_MOD_RIGHT
Definition: arrows.c:44
GVC_t * gvc
Definition: gvcjob.h:272
void gvrender_set_style(GVJ_t *job, char **s)
Definition: gvrender.c:512
int sflag
Definition: arrows.c:49
#define ARR_TYPE_TEE
Definition: arrows.c:32
Definition: grammar.c:79
emit_state_t emit_state
Definition: gvcjob.h:201
char * dir
Definition: arrows.c:48
void gvrender_set_penwidth(GVJ_t *job, double penwidth)
Definition: gvrender.c:848
pointf ep
Definition: types.h:114
pointf Bezier(pointf *V, int degree, double t, pointf *Left, pointf *Right)
Definition: utils.c:221
void arrowOrthoClip(edge_t *e, pointf *ps, int startp, int endp, bezier *spl, int sflag, int eflag)
Definition: arrows.c:323
int eflag
Definition: arrows.c:50
#define NULL
Definition: logic.h:39
#define ARR_TYPE_DIAMOND
Definition: arrows.c:34
pointf * p
Definition: types.h:58
double x
Definition: geom.h:28
boxf arrow_bb(pointf p, pointf u, double arrowsize, int flag)
Definition: arrows.c:691
#define streq(s, t)
Definition: cghdr.h:52
double late_double(void *obj, attrsym_t *attr, double def, double low)
Definition: utils.c:87
struct arrowtype_t arrowtype_t
Definition: types.h:108
pointf LL
Definition: geom.h:35
#define ARROW_LENGTH
Definition: arrows.c:20
#define ARR_TYPE_CROW
Definition: arrows.c:31
struct arrowname_t arrowname_t
Definition: types.h:56
#define ARR_TYPE_BOX
Definition: arrows.c:33
double * r
Definition: types.h:59
#define agfindedge(g, t, h)
Definition: types.h:610
void gvrender_ellipse(GVJ_t *job, pointf *AF, int n, int filled)
Definition: gvrender.c:551
void arrow_gen(GVJ_t *job, emit_state_t emit_state, pointf p, pointf u, double arrowsize, double penwidth, int flag)
Definition: arrows.c:729
void gvrender_beziercurve(GVJ_t *job, pointf *AF, int n, int arrow_at_start, int arrow_at_end, boolean filled)
Definition: gvrender.c:617
char * agxget(void *obj, Agsym_t *sym)
Definition: attr.c:444
EXTERN Agsym_t * E_arrowsz
Definition: globals.h:107
pointf UR
Definition: geom.h:35
char ** defaultlinestyle
Definition: gvcint.h:137
Definition: geom.h:35
#define FALSE
Definition: cgraph.h:35
struct arrowdir_t arrowdir_t
void bezier_clip(inside_t *inside_context, boolean(*insidefn)(inside_t *inside_context, pointf p), pointf *sp, boolean left_inside)
Definition: splines.c:106
int arrowStartClip(edge_t *e, pointf *ps, int startp, int endp, bezier *spl, int sflag)
Definition: arrows.c:285
#define ARR_TYPE_GAP
Definition: arrows.c:37
void gvrender_polyline(GVJ_t *job, pointf *AF, int n)
Definition: gvrender.c:641
#define TRUE
Definition: cgraph.h:38