PDA

View Full Version : How to put an arrow at the end of a drawn line?




BarryK88
May 31, 2011, 09:32 AM
Within my project the user is able to draw lines inside the view. However I'd like to have an arrow at the end of each line pointing in the right direction (of the drawer). Is there a way of doing this with CGContext?

Here's a snippit of my code within the touchesmoved method:

mouseSwiped = YES;
UITouch *touch2 = [touches anyObject];
CGPoint currentPoint = [touch2 locationInView:self.view];
currentPoint.y -= 100;
currentPoint.x -= 0;
UIGraphicsBeginImageContext(drawView.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

lastPoint = currentPoint;

I'm thinking of putting a function inside the touchesEnded method but I have no clue what the next thinking steps are.

Hope someone can help me out! Thanks in advance.



robbieduncan
May 31, 2011, 09:35 AM
An arrow is simply a filled triangle (or two if you want a fancier arrow filled and drawn at the end of the line. You seem to be able to use the core graphics functions so you should be able to draw a filled triangle. Calculation of the points for the triangle should not be too complex.

BarryK88
May 31, 2011, 09:36 AM
That's correct. However pointing it in the right direction is not. Any suggestions?

robbieduncan
May 31, 2011, 10:34 AM
That's correct. However pointing it in the right direction is not. Any suggestions?

Assuming you want a plain arrow (so a single triangle) then it's fairly simple.

We have a line drawn between lastPoint and currentPoint. If we assume, for sake of argument, that we don't want to increase the length of the line then one of the 3 points on the line is currentPoint (the point of the arrow).

If we follow the advise here (http://stackoverflow.com/questions/5224444/calculate-a-point-normal-to-a-line) it is relatively trivial to calculate points that are D pixels off the line on the normal through the middle of the line we have drawn. This is close to what we want, but not quite what we want as our arrows will be different size/shapes for different line lengths.

So we then look at calculating a point on the line such that the half way point between the end point and our calculated point is the correct point for the normal. This is not too hard (I assume you can do this: it's the cx, cy points below).

So if we assume lastPoint is (x1,y1) and currentPoint is (x2,y2). We want an arrow that is 2px back down the line and 1 px off the line.


lengthOfArrow = 2;
widthOfArrow = 1;
length = sqrt((x2-x1)^2+(y2-y2)^2);
cx = x2-((x2-x1)/length)*2*lengthOfArrow;
cy = y2-((y2-y1)/length)*2*lengthOfArrow;

ax1 = ((cx+x2)/2)+(widthOfArrow*((-1*(y2-cy))/length));
ax2 = ((cx+x2)/2)-(widthOfArrow*((-1*(y2-cy))/length));
ay1 = ((cy+y2)/2)+(widthOfArrow*(((x2-cx))/length));
ay2 = ((cy+y2)/2)-(widthOfArrow*(((x2-cx))/length));


The points for the arrow triangle are now currentPoint;(ax1,ay1);(ax2,ay2).

Note I've only checked this with a pencil and paper. It could actually be wrong.

BarryK88
Jun 1, 2011, 03:38 AM
Thanks Duncan for giving me good advice and taking time for me! I'll try implementing this within my project!