# [cairo] Drawing an arrow

Angus Johnson angus at internode.on.net
Wed Nov 24 02:48:18 PST 2010

```On 24/11/2010 8:50 PM, donn wrote:
> On 23/11/2010 19:09, Stefan Salewski wrote:
>> Can you imagine building an arrow of 3 or more line segments?
> The OP is a question I would like to see answered too. The problem is
> how to find the three points to define the arrow. If you have a
> bezier-curve, so the line is some S shape, how do you get the arrow to
> point along the direction that the curve sort of ends in?

This isn't a simple task. What I do in another library is ...
1. flatten the curve (into a series of straight edges)
2. given a specified distance between arrow tip and arrow base,
shorten the curve by that distance (removing some segments and/or
shortening the last)
3. get the angle 'a' between the original end and the new end. (I don't
recommend using the angle of the very last straight segment, or the
control point, because if the bezier is very curved near the end the
arrow base will be no where near where the adjusted line starts.)
4. use the perpendicular of 'a' and a specified distance from the base
to locate arrow 'wings' points.

Also, I suggest it'd be very helpful to have a couple of basic arrow
drawing routines in the library - that returns coords for 3 pointed and
4 pointed arrows of a specified size (ie between tip and base).
eg typedef cairo_path_end_type enum {CAIRO_END_TYPE_START,
CAIRO_END_TYPE_END, CAIRO_END_TYPE_BOTH} cairo_path_end_type_t;
cairo_path_t*  cairo_get_3pt_arrow_coords_for_path(cairo_t *cr, double
size, cairo_path_end_type_t ends);

They could be combined with the following couple of functions ...
1. cairo_bool_t cairo_get_point_at_dist_from_path_end(cairo_t *cr,
double dist, cairo_path_end_type_t end, double *x, double *y);
2. cairo_bool_t cairo_shorten_path(cairo_t *cr, double dist,
cairo_path_end_type_t ends);
```