views:

811

answers:

2

Hi, I am trying to draw a map annotation in my app - very much like MapKit's MKAnnotationView, but without the mapkit.

I have a problem with the ordering of the path for the view outline that I cant figure out.

Image of results:

http://img504.imageshack.us/img504/5458/screenshot20091010at703.png

Code:

CGFloat minx = CGRectGetMinX(currentBounds);
CGFloat midx = CGRectGetMidX(currentBounds);
CGFloat maxx = CGRectGetMaxX(currentBounds);
CGFloat miny = CGRectGetMinY(currentBounds)+10.0f;
CGFloat midy = CGRectGetMidY(currentBounds)+10.0f;
CGFloat maxy = CGRectGetMaxY(currentBounds)+10.0f;

CGContextBeginPath(currentContext);
CGContextMoveToPoint(currentContext, minx, miny+radius); //before top left arc
CGContextAddArcToPoint(currentContext, minx, miny, midx, miny, radius); //top left

CGPoint points1[] = {
CGPointMake(midx-10.0f, miny),
CGPointMake(midx, 0.0f), //tip of arrow
CGPointMake(midx+10.0f, miny),
};
CGContextAddLines(currentContext,  points1, 3);
CGContextAddArcToPoint(currentContext, maxx, miny, maxx, midy, radius); //top right
CGContextAddArcToPoint(currentContext, maxx, maxy, midx, maxy, radius); //bottom right
CGContextAddArcToPoint(currentContext, minx, maxy, minx, midy, radius); //bottom left
CGContextClosePath(currentContext);

CGContextClosePath(currentContext);
CGContextDrawPath(currentContext, kCGPathFillStroke);
//CGContextDrawPath(currentContext, kCGPathEOFillStroke);
+2  A: 

First, in PostScript (and derivatives such as AppKit drawing and Core Graphics), you normally draw a counter-clockwise path, especially when filling. A clockwise path like the one you show here is what you'd draw if you want to fill outside it.

Second, I'm assuming that this context has origin in the top-left (positive y going down), not the bottom-left (positive y going up).

Coming out of the first arc, the current point is dead-center at the bottom of the pointer. Would it not make more sense to set the second point of the arct command (CGContextAddArcToPoint) as the first base point of the pointer? Besides being more correct, you would only need to pass two points to CGContextAddLines.

Do you mean to close the path twice? I don't think it hurts anything, but it is redundant.

I would start drawing at the right base point of the pointer, then plot the lines to the next two points (tip and left base point, in that order), then plot all four arcs in (counterclockwise) succession, then closepath (once). That should be slightly simpler, and correct.

Peter Hosey
CGContextMoveToPoint(currentContext, midx+10.0f, miny); CGPoint points[] = { CGPointMake(midx, 0.0f), //point CGPointMake(midx-10.0f, miny), }; CGContextAddLines(currentContext, points, 2); CGContextAddArcToPoint(currentContext, minx, miny, minx, midy, radius); //TL CGContextAddArcToPoint(currentContext, minx, maxy, midx, maxy, radius); //BL CGContextAddArcToPoint(currentContext, maxx, maxy, maxx, midy, radius); //BR CGContextAddArcToPoint(currentContext, maxx, miny, midx, miny, radius); //TR *CLOSE PATH, DRAW*http://img36.imageshack.us/img36/92/screenshot20091010at816.png
Mobs
Peter, thanks for the tips.. excuse how brief that comment was - there is a character limit. It now appears that the starting point is not working?
Mobs
That code definitely should work as intended. I suggest filing a bug about closepath returning to the first lineto and not the moveto. https://bugreport.apple.com/
Peter Hosey
Incidentally, that appears to be the same problem that affects your original code: the `closepath` after the bottom-left arc jumps to the first `lineto` (left base point), skipping even the top-left arc.
Peter Hosey
Update: This is **not a bug**. Quoth the docs for CGContextAddLines: “The first point is the array specifies the initial starting point.” So that's implicitly a second moveto. Cut out the explicit moveto, and pass all three points of the pointer to CGContextAddLines.
Peter Hosey
A: 

So the CGContextMoveToPoint was not working, no matter what values were entered, with or without the CGContextPathBegin. Starting the path with the line at the corner of the pointer arrow allowed me to specify starting point. Thanks Peter for helping me understand it, and how to simplify the paths.

Mobs
It's not so much that it wasn't working as that CGContextAddToLines does an implicit `moveto` that canceled out your explicit one. See my newest comment on my answer.
Peter Hosey