Creating a c-array of CGPoints - ios

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.

Related

Comparing two CGPoints for equality: returning not equal for two objects that output same point?

According to this question, using == and != should let you check for equality between two CGPoint objects.
However, the code below fails to consider two CGPoint objects as equal even though they output the same value.
What is the right way to check equality among CGPoint objects?
Code:
let boardTilePos = boardLayer.convert(boardTile.position, from: boardTile.parent!)
let shapeTilePos = boardLayer.convert(tile.position, from: tile.parent!)
print("board tile pos: \(boardTilePos). active tile pos: \(shapeTilePos). true/false: \(shapeTilePos == boardTilePos)")
Output:
board tile pos: (175.0, 70.0). active tile pos: (175.0, 70.0). true/false: false
Unfortunately, what you see in the console is not what your real value is.
import UIKit
var x = CGPoint(x:175.0,y:70.0)
var y = CGPoint(x:175.0,y:70.00000000000001)
print("\(x.equalTo(y)), \(x == y),\(x),\(y)")
The problem is, the console only allows for 10-16 but in reality your CGFloat can go even lower than that because on 64bit architecture, CGFloat is Double.
This means you have to cast your CGPoint values to a Float if you want to get equality that will appear on the console, so you need to do something like:
if Float(boxA.x) == Float(boxB.x) && Float(boxA.y) == Float(boxB.y)
{
//We have equality
}
Now I like to take it one step further.
In most cases, we are using CGPoint to determine points on the scene. Rarely do we ever want to be dealing with 1/2 points, they make our lives just confusing.
So instead of Float, I like to cast to Int. This will guarantee if two points are lying on the same CGPoint in scene space
if Int(boxA.x) == Int(boxB.x) && Int(boxA.y) == Int(boxB.y)
{
//We have equality
}
I'm providing an alternate answer since I don't agree with Knight0fDragon's implementation. This is only if you want to deal with factions of a point. If you only care about points in whole numbers, see Knight0fDragon's answer.
You don't always have the luxury of logging points to the console, or seeing if you're trying to compare points that are the victim of floating point math, like comparing (175.0, 70.0) to (175.0, 70.00001) (which both log as (175.0, 70.0) in the console). Yes, truncating to Int is a great way of understanding why two points that appear to print to the console as equal aren't. But it's not a catch all solution one should use for comparing every point. Depending on what level of precision you need, you want to take the absolute value of the difference of both x and y for each point, and see if it is in an acceptable range of a delta you specify.
var boxA = CGPoint(x:175.0, y:70.0)
var boxB = CGPoint(x:175.0, y:70.00000000000001)
let delta: CGFloat = 0.01
if (fabs(boxA.x - boxB.x) < delta) &&
(fabs(boxA.y - boxB.y) < delta) {
// equal enough for our needs
}
The answer to the question "What is the right way to check equality among CGPoint objects?" really depends on the way you compare floating point numbers.
CGPoint provides its own comparison method: equalTo(_ point2: CGPoint)
Try this:
shapeTilePos.equalTo(boardTilePos)

Getting data from a table

Using Tiled I generated a Lua file which contains a table. So I figured that I'd write a for loop which cycles through the table gets the tile id and checks if collision is true and add collision if it was. But, I've been unable to get the tile id's or check they're properties. But it returned a error saying that I tried to index nil value tileData.
Here is the Map file
return {
version = "1.1",
luaversion = "5.1",
-- more misc. data
tilesets = {
{
name = "Tileset1",
firstgid = 1,
tilewidth = 16,
tileheight = 16,
tiles = {
{
id = 0,
properties = {
["Collision"] = false
}
},
}
}
layers = {
{
type = "tilelayer",
name = "Tile Layer 1"
data = {
-- array of tile id's
}
}
}
}
And here is the for loop I wrote to cycle through the table
require("Protyping")
local map = love.filesystem.load("Protyping.lua")()
local tileset1 = map.tilesets
local tileData = tileset1.tiles
local colision_layer = map.layers[1].data
for y=1,16 do
for x=1,16 do
if tileData[colision_layer[x*y]].properties["Colision"] == true then
world:add("collider "..x*y,x*map.tilewidth, y*tileheight,tilewidth,tileheight)
end
end
end
Try this:
tileset1 = map.tilesets[1]
instead of
tileset1 = map.tilesets
lhf's answer (map.tilesets[1] instead of map.tilesets) fixes the error you were getting, but there are at least two other things you'll need to fix for your code to work.
The first is consistent spelling: you have a Collision property in your map data and a Colision check in your code.
The second thing you'll need to fix is the way that the individual tiles are being referenced. Tiled's layer data is made of 2-dimensional tile data laid out in a 1-dimensional array from left-to-right, starting at the top, so the index numbers look like this:
You would think you could just do x * y to get the index, but if you look closely, you'll see that this doesn't work. Instead, you have to do x + (y - 1) * width.
Or if you use zero-based x and y, it looks like this:
Personally, I prefer 0-based x and y (but as I get more comfortable with Lua, that may change, as Lua has 1-based arrays). If you do go with 0-based x and y, then the formula is x + 1 + y * width.
I happen to have just written a tutorial this morning that goes over the Tiled format and has some helper functions that do exactly this (using the 0-based formula). You may find it helpful: https://github.com/prust/sti-pg-example.
The tutorial uses Simple Tiled Implementation, which is a very nice library for working with Tiled lua files. Since you're trying to do collision, I should mention that STI has a plugins for both the bump collision library and the box2d (physics) collision library.

Most efficient way to check number of CGPoints in CGPathRef

I want to find out if my CGMutablePathRef has more then 3 points! This checking will happen frequently so Im looking for an efficient solution.
This reason I need to do this is because in my project the user draws a shape. As the user drags his/her finger a CGPoint(current location of finger) is added to the path and a physical body is added when the touchEnded: is called.. now if the user just taps the screen the CGMutablePathRef only has one point in it(my reasoning in my head) and I get the following error when I use the my CGMutablePathRef for adding the physical body.
Assertion failed: (count >= 2), function CreateChain, file /SourceCache/PhysicsKit/PhysicsKit-6.5.4/PhysicsKit/Box2D/Collision/Shapes/b2ChainShape.cpp, line 45.
Im looking to make a function to call that takes a cgpathref as a parameter and counts the points until it reaches 3 (or the end if there isn't 3) and returns a bool
Thanks :)
If you want to enumerate the elements of a CGPath, you have to use CGPathApply, and there is no support for early termination. You must enumerate all of the elements.
Grab my Rob_forEachElementOfCGPath function from this answer, and use it like this:
int numberOfSegmentsInCGPath(CGPathRef path) {
__block int count = 0;
Rob_forEachElementOfCGPath(path, ^(const CGPathElement *element) {
if (element->type != kCGPathElementMoveToPoint) {
++count;
}
});
return count;
}
There's no particularly efficient way to do this, but you could keep track of the number of points as you add them.
#interface MyPath : NSObject
#property (assign) int pointCount;
#property (assign) CGPathRef path;
#end
If you wanted to make sure you had complete control over it (and didn't want to worry about someone else incrementing your count or changing your path without incrementing), you could make the properties readonly and have an 'add point' function on the object ... Not great, but it would be more efficient than ApplyPath.

Cocos2d v3: What do you pass into drawPolyWithVerts?

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)
};

CGRect syntax I haven't seen before

I saw the syntax below in some example code and am not sure I understand it.
CGRect imageRect = (CGRect){.size = baseImage.size};
Is this simply a shorthand way of initializing a CGRect equivalent to:
CGRect imageRect = CGRectMake(0,0,baseImage.size.width, baseImage.size.height);
Is there any benefit to this syntax aside from slightly less typing?
That's C99 initializer syntax. You can use it with any structure.
The main advantage to an Objective-C is that it gives you some very Objective-C like syntax, where the fields are close to the values rather than implied by positioning. (That's not to say this is intentionally similar, or that it's the only advantage. But it is nice.)
It's sometimes slightly more typing, but I use it everywhere now.
Consider:
CGRect a = CGRectMake(a+c/2, b+d/2, c, d);
In order to understand this, you need to understand the order of the parameters. You also need to be able to catch the commas easily with your eyes. In this case, that's pretty easy, but if the expressions were more complicated you'd probably be storing them in a temporary variable first.
The C99 way:
CGRect a = (CGRect){
.origin.x = a+c/2,
.origin.y = b+d/2,
.size.width = c,
.size.height = d
};
It's longer, but it's more explicit. It's also very easy to follow what is assigned to what, no matter how long the expression are. It's also more like an Objective-C method. After all, if CGRect was a class, it would probably look like this:
CGRect *a = [[CGRect alloc] initWithOriginX:x originY:y width:w height:h];
You can also do things like this:
CGRect a = (CGRect){
.origin = myOrigin,
.size = computedSize
};
Here, you're building a rectangle using a CGPoint and CGSize. The compiler understands that .origin expects a CGPoint, and .size expects a CGSize. You've provided that. All's gravy.
The equivalent code would be CGRectMake(myOrigin.x, myOrigin.y, size.width, size.height). By using CGRectMake you're no longer expressing the same kind of meaning to the compiler. It can't stop you from assigning part of the size to the origin. It also won't stop you from assigning the width to the height. It doesn't even give you a good clue about which is the X and Y; if you've used APIs that provide vertical coordinates first, you'll get it wrong.
You can assign part from a structure and part from floats as well:
CGRect a = (CGRect){
.origin = myOrigin,
.size.width = c,
.size.height = d
};
The CGRectMake function predates C99. I have no evidence to this effect, but I think if C99 had come first CGRectMake probably wouldn't exist at all; it's the sort of crusty function you write when your language has no direct way to perform the initialization. But now it does.
Basically, if you use it for a while, you'll probably come to prefer C99 syntax. It's more explicit, more flexible, more Objective-C-like and harder to screw up.
Unfortunately, as of 4.6 Xcode will not autocomplete structure field names when in the C99 field initializer list.
This is not just shorthand syntax but is also useful when you want to change only the size and not the origin in CGRect and vice versa.
Eg : I want to change only the size and the position has a complicated syntax and I dont want to change it. Noramlly, I would do
CGRect imageRect = CGRectMake(sprite.origin.x,sprite.origin.y,40, 60);
With the other syntax i would do
CGRect imageRect = (CGRect){.size = sprite.size};
also we can directy use add, subtract and multiply methods
eg.
CGRect imageRect = (CGRect){.size = ccpAdd(sprite.size,addsize)};
Hope this helps
it looks like C99 / GCC style initializing http://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html

Resources