Cocos2d v3: What do you pass into drawPolyWithVerts? - ios

I've looked at the documentation for CCDrawNode, and the method to draw a polygon is
- (void)drawPolyWithVerts:(const CGPoint *)verts
count:(NSUInteger)count
fillColor:(CCColor *)fill
borderWidth:(CGFloat)width
borderColor:(CCColor *)line
http://www.cocos2d-swift.org/docs/api/Classes/CCDrawNode.html#//api/name/drawPolyWithVerts:count:fillColor:borderWidth:borderColor:
I'm confused by the (const CGPoint *)certs parameter. I thought a CGPoint was a struct, and so didn't need a pointer.
Also, I'm a assuming you'll need a series of points to construct a polygon, and I thought CGPoint just represented one point.
I've checked through the Cocos 2d Programming Guide and I couldn't see anything about this method in there.
https://www.makegameswith.us/docs/#!/cocos2d/1.1/overview
I've also check out CGGeometry Reference on Apple's site, but couldn't see anything there.
https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/CGGeometry/Reference/reference.html#//apple_ref/c/func/CGPointMake
I think I'm missing something fairly basic about C / Objective-C, but I can't figure it out.
My Question
What do i pass into drawPolyWithVerts:(const CGPoint *)verts, and how do I make it?

As user667648 pointed out in the comments, the answer is to pass a C array of CGPoints into the method.
Example:
CGPoint polygon[4] =
{
CGPointMake(0, 0),
CGPointMake(2, 0),
CGPointMake(0, 7),
CGPointMake(2, 25)
};

Related

Plot a CGPoint given origin, angle and distance

I am having trouble plotting a new CGPoint when given an origin, distance and angle. The task is pretty simple: I have a line with three edit handles attached to it - one on each end and one in the center. When the the end handles are dragged, the line is moved relative to the handle being dragged. That functionality is working properly. When the center handle is dragged, the two endpoint handles should maintain their relationship to one another as shown in the image below. So when dragging the center handle the two other handles should move with it.
Here is my current code to plot the points:
func pointFromPoint(origin:CGPoint, distance:Double, degrees:Double) -> CGPoint {
var endPoint = CGPoint()
endPoint.x = CGFloat(distance * cos(degrees) + Double(origin.x))
endPoint.y = CGFloat(distance * sin(degrees) + Double(origin.y))
return endPoint
}
When using this function, the new CGPoint locations seems to fall in random locations. Can anyone spot anything wrong in my math? Thanks!
Most trigonometry functions need radians, not degrees.
Also, as #Putz1103 pointed out, you can probably use the delta x and delta y of the UITouch of the movement instead of calculating the new position of the ends based on the center point's movement.

Creating a c-array of CGPoints

I'd like to create a constant array of CGPoints in a c style array.
I started with this but got the error Initializer element is not a compile time constant
static CGPoint locations[5] =
{
CGPointMake(180, 180),
CGPointMake(300, 130),
CGPointMake(435, 120),
CGPointMake(470, 230),
CGPointMake(565, 200),
};
I removed the static thinking it might be something to do with that, but the error remained.
How can you create an array of CGPoints (and more widely, any similarly defined struct).
NB: I've posted this question and answer partially for my own reference as I can never remember this off the top of my head and waste too much time researching the answer from other sources. Here's hoping it helps others!
It turns out the CGPointMake function call is the thing that "isn't a compile time constant" and so the CGPoints need to be treated like raw structs:
static CGPoint locations[5] =
{
(CGPoint){180, 180},
(CGPoint){300, 130},
(CGPoint){435, 120},
(CGPoint){470, 230},
(CGPoint){565, 200},
};
The cast isn't strictly required, but for my own sanity, I'd keep it to show each of those numbers is actually part of a CGPoint. This is also valid:
static CGPoint locations[5] = {
{180, 180},
{300, 130},
{435, 120},
{470, 230},
{565, 200},
};
Calling a function is always a runtime activity. The contents of an array initializer list needs to be computed at compilation time.

Does MKOverlayPathView need drawMapRect?

I'm having some inconsistencies modifying the Breadcrumb example, to have the CrumbPathView subclassed from MKOverlayPathView (like it's supposed to) rather than subclassed from MKOverlayView.
Trouble is, the docs are limited in stating the difference in how these 2 should be implemented. For a subclass of MKOverlayPathView it's advised to use:
- createPath
- applyStrokePropertiesToContext:atZoomScale:
- strokePath:inContext:
But is this in place of drawMapRect, or in addition to? It doesn't seem like much point if it's in addition to, because both would be used for similar implementations. But using it instead of drawMapRect, leaves the line choppy and broken.
Struggling to find any real world examples of subclassing MKOverlayPathView too...is there any point?
UPDATE - modified code from drawMapRect, to what should work:
- (void)createPath
{
CrumbPath *crumbs = (CrumbPath *)(self.overlay);
CGMutablePathRef newPath = [self createPathForPoints:crumbs.points
pointCount:crumbs.pointCount];
if (newPath != nil) {
CGPathAddPath(newPath, NULL, self.path);
[self setPath:newPath];
}
CGPathRelease(newPath);
}
- (void)applyStrokePropertiesToContext:(CGContextRef)context atZoomScale:(MKZoomScale)zoomScale
{
CGContextSetStrokeColorWithColor(context, [[UIColor greenColor] CGColor]);
CGFloat lineWidth = MKRoadWidthAtZoomScale(zoomScale);
CGContextSetLineWidth(context, lineWidth);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineCap(context, kCGLineCapRound);
}
- (void)strokePath:(CGPathRef)path inContext:(CGContextRef)context
{
CGContextAddPath(context, path);
CGContextStrokePath(context);
[self setPath:path];
}
This draws an initial line, but fails to continue the line...it doesn't add the path. I've confirmed that applyStrokePropertiesToContext and strokePath are getting called, upon every new location.
Here's a screenshot of the broken line that results (it draws for createPath, but not after that):
Here's a screenshot of the "choppy" path that happens when drawMapRect is included with createPath:
Without having seen more of your code I'm guessing, but here goes.
I suspect the path is being broken into segments, A->B, C->D, E->F rather than a path with points A,B,C,D, E and F. To be sure of that we'd need to see what is happening to self.overlay and whether it is being reset at any point.
In strokePath you set self.path to be the one that is being stroked. I doubt that is a good idea since the stroking could happen at any time just like viewForAnnotations.
As for the choppiness it may be a side effect or a poor bounds calculation on Apple's part. If your like ends near the boundary of a tile that Apple uses to cover the map it would probably only prompt the map to draw the one the line is within. But your stroke width extends into a neighbouring tile that hasn't been draw. I'm guessing again but you could test this out by moving the point that is just north of the W in "Queen St W" a fraction south, or by increasing the stroke width and see if the cut off line stays in the same place geographically.

Simple 2D "collision detection" iOS

I'm writing an application that will calculate a CGPoint and show a mark in an envelope (a diagram if you like). My envelope is just part of the background image in an UIImageView. What I want to do is to construct a sort of "line", corresponding to the envelopes limits (they're not straight lines, but curves) so that if the calculated CGPoint is to the left of this line, or to the right of another line, then the calculated point is not approved. Where it to be in the middle of these two, it's approved.
I was first thinking of drawing lines using CoreGraphics, but I'm not sure if one could check whether the calculated CGPoint is to the right or left of those lines.
The envelope is only 149px high, so I was also thinking of putting together a dictionary, where the keys where the y position and the values where the x position of the pixels that represented that defining boundary line.
The application is rather simple and is not animating anything. Does anybody have an idea of how to best come up with a solution for this sort of behavior?
You can do this by creating a CGPath that represents your boundary lines (the outline of your envelope) and testing that a point is contained in it with CGPathContainsPoint.
You'll have to do some trial and error to construct a CGPath that matches your envelope shape, try filling it in the drawRect method to see what your path actually is.
Here's an example with a circle path:
CGPoint viewCenter = CGPointMake(100,100);
CGPoint checkPoint = CGPointMake(110,110);
UIBezierPath *bpath = [UIBezierPath bezierPathWithArcCenter:viewCenter radius:50 startAngle:0 endAngle:DEGREES_TO_RADIANS(360) clockwise:YES];
CGPathRef path = [bpath CGPath];
BOOL inPath = CGPathContainsPoint(path, NULL, checkPoint, NO);
Here I have DEGREES_TO_RADIANS defined like this:
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)

how to get buffer zone around a uibezierpath

i have some uibezierpaths. as paths, they don't really have thickness.
but, I am hoping to find a way to define an area around a path like the grayish areas around the lines in this picture
basically, i want to test whether drawn lines fall within the buffer zone around the lines.
i thought this would be simple, but it's turning out to be much more complex than i thought. I can use the CGPathApply function to examine the points along my path, and then getting a range +or- each point, but it's more complicated than that with angles and curves. any ideas?
Expanding the width of a path is actually quite difficult. However, you could just stroke it with a thicker width and get pretty much the same effect. Something like...
CGContextSetRGBStrokeColor(context, 0.4, 0.4, 0.4, 1.0);
[path setLineWidth:15];
[path stroke];
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);
[path setLineWidth:3];
[path stroke];
...would produce a picture like the one in your question. But I doubt that's news to you.
The real trick is the test of "whether drawn lines fall within the buffer zone." That problem is very similar to one which I just answered for myself in another question. Take a look at the LineSample.zip code I shared there. This implements a bitmap/bitwise data comparison to detect hits on lines much like you need. You could just draw the thicker "buffer" paths into the bitmap for testing and show the thinner lines in your view.
Basically, you want to check if any point falls inside a region of specified size around your path.
It is actually very simple to do. First, you need a value which will define the amount of space around path you want to test. Let's say 20 points. So what you need to do is start a FOR loop, starting from -20 to 20, and at each iteration, create a copy of your path, translate the path's x and y co-odrinates, check each of them.
All of this is more clear in this code sample.
CGPoint touchPoint = /*get the point*/;
NSInteger space = 20;
for (NSInteger i = -space; i < space; i++) {
UIBezierPath *pathX = [UIBezierPath bezierPathWithCGPath:originalPath.CGPath];
[pathX applyTransform:CGAffineTransformMakeTranslation(i, 0)];
if ([pathX containsPoint:touchPoint]) {
/*YEAH!*/
}
else {
UIBezierPath *pathY = [UIBezierPath bezierPathWithCGPath:originalPath.CGPath];
[pathY applyTransform:CGAffineTransformMakeTranslation(0, i)];
if ([pathY containsPoint:touchPoint]) {
/*YEAH!*/
}
}
}

Resources