views:

955

answers:

3

Hi,

I am using the framework of route-me for working with locations. In this code the path between two markers(points) will be drawn as a line.

My Question: "What code should I add if I want to add an arrow in the middle(or top) of the line, so that it points the direction"

Thanks



- (void)drawInContext:(CGContextRef)theContext
{
    renderedScale = [contents metersPerPixel];

    float scale = 1.0f / [contents metersPerPixel];

    float scaledLineWidth = lineWidth;
    if(!scaleLineWidth) {
        scaledLineWidth *= renderedScale;
    }
    //NSLog(@"line width = %f, content scale = %f", scaledLineWidth, renderedScale);

    CGContextScaleCTM(theContext, scale, scale);

    CGContextBeginPath(theContext);
    CGContextAddPath(theContext, path);

    CGContextSetLineWidth(theContext, scaledLineWidth);
    CGContextSetStrokeColorWithColor(theContext, [lineColor CGColor]);
    CGContextSetFillColorWithColor(theContext, [fillColor CGColor]);

    // according to Apple's documentation, DrawPath closes the path if it's a filled style, so a call to ClosePath isn't necessary
    CGContextDrawPath(theContext, drawingMode);
}

+1  A: 

The drawing of the actual triangle/arrow is easy once you have two points on your path.

CGContextMoveToPoint( context , ax , ay );
CGContextAddLineToPoint( context , bx , by );
CGContextAddLineToPoint( context , cx , cy );
CGContextClosePath( context ); // for triangle

Getting the points is a little more tricky. You said path was a line, as opposed to a curve or series of curves. That makes it easier.

Use CGPathApply to pick two points on the path. Probably, this is the last two points, one of which may be kCGPathElementMoveToPoint and the other will be kCGPathElementAddLineToPoint. Let mx,my be the first point and nx,ny be the second, so the arrow will point from m towards n.

Assuming you want the arrow at the tip of the line, bx,by from above will equal nx,ny on the line. Choose a point dx,dy between mx,my and nx,ny to calculate the other points.

Now calculate ax,ay and cx,cy such that they are on a line with dx,dy and equidistant from path. The following should be close, although I probably got some signs wrong:

r = atan2( ny - my , nx - mx );
bx = nx;
by = ny;
dx = bx + sin( r ) * length;
dy = by + cos( r ) * length;
r += M_PI_2; // perpendicular to path
ax = dx + sin( r ) * width;
ay = dy + cos( r ) * width;
cx = dx - sin( r ) * width;
cy = dy - cos( r ) * width;

Length is the distance from the tip of the arrow to the base, and width is distance from the shaft to the barbs, or half the breadth of the arrow head.

If path is a curve, then instead of finding mx,my as the previous point or move, it will be the final control point of the final curve. Each control point is on a line tangent to the curve and passing through the adjacent point.

drawnonward
A: 

I found this question as I had the same. I took drawnonward's example and it was so close... But with a flipping of cos and sin, I was able to get it to work:

r = atan2( ny - my , nx - mx );
r += M_PI;
bx = nx;
by = ny;
dx = bx + cos( r ) * length;
dy = by + sin( r ) * length;
r += M_PI_2; // perpendicular to path
ax = dx + cos( r ) * width;
ay = dy + sin( r ) * width;
cx = dx - cos( r ) * width;
cy = dy - sin( r ) * width;

Once I did that, my arrows were pointed exactly the wrong way. So I added that second line (r += M_PI;)

Thanks go to drawnonward!

Doug Hays
A: 

Hi,

I got it a while ago by http://www.codeguru.com/cpp/g-m/gdi/article.php/c3683

Anyway thansk for the answers

Greetz

Pete