Sort Array of CGPoints - objective-c

I am trying to figure out what the fastest/cleanest way to sort an array of CGPoints would be. I think I could achieve this using loops but that might not be the fastest and I hope it isn't the cleanest way. I would like to take an array of random CGPoints and sort them say by smallest x coordinate to largest, or smallest x and y coordinate to largest.

After the correct comment by Chuck, I've updated the answer using the sortUsingComparator method:
Here is the complete code with sample data:
First we generate 100 random values that we enter to the Array:
NSMutableArray *testArray = [[NSMutableArray alloc] initWithCapacity:100];
for (int i=0; i<100; i++) {
CGPoint testPoint = CGPointMake(arc4random()%100, arc4random()%100);
[testArray addObject:[NSValue valueWithCGPoint:testPoint]];
}
and here is the actual code to sort the array:
[testArray sortUsingComparator:^(id firstObject, id secondObject) {
CGPoint firstPoint = [firstObject CGPointValue];
CGPoint secondPoint = [secondObject CGPointValue];
return firstPoint.x>secondPoint.x;
}];
finally we can verify that the array was sorted, by printing it:
NSLog(#"%#",testArray);

The C qsort() function is probably your best bet if you just have a plain array of CGPoints. Something like this:
int compareXCoords(CGPoint *a, CGPoint *b) {
return b->x - a->x;
}
// Later:
CGPoint points[100];
// initialize points somehow
qsort(points, 100, sizeof(CGPoint), compareXCoords);
// points is now sorted by the points' x coordinates

According to my comment, it's a good solution insert them on a NSMutableArray keeping the sort you decide.
You have to do something like this:
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:1];
CGPoint candidate;
// Look for the position it has to be
int 0;
for (CGPoint point in array) {
i++;
// Compare candidate with current point
// You have to define this condition, when point is greater than candidate
if (point > candidate) {
break;
}
}
[array insertObjectAtIndex:i-1];
Maybe my code has some errors, I can't check if it's correct now.

Related

Most efficient way to draw lines from array of points in cocos2d

Given an NSMutableArray of dynamic CGPoints, what is the fastest and most efficient way to draw lines from array[0] to array[1], array[1] to array[2], etc.? Should I rewrite my function in C or C++ for better performance? Currently my framerate suffers dramatically when there are more than ~20 points in the array. I am using cocos2d v2.0.0-rc2 and I currently have:
-(void)draw
{
for (int i = 0; i < [points count]; i+=2)
{
CGPoint startFromArray = [[points objectAtIndex:i] CGPointValue];
CGPoint endFromArray = [[points objectAtIndex:i+1] CGPointValue];
ccDrawLine(startFromArray, endFromArray);
}
[super draw];
}
There's no need to use iteration here. Cocos2d has a built-in function called ccDrawPoly(). You can use it like this:
CGPoint *verts = malloc(sizeof(CGPoint) * [points count]);
for (int i = 0; i < [points count]; i++) {
verts[i] = [[points objectAtIndex:i] CGPointValue];
}
ccDrawPoly(verts, [points count], NO);
free(verts);
Obviously, you'll get even better performance if you store your CGPoints in a C array instead of boxing and unboxing them from NSValues, but if you really need the mutability, that can't be helped.
As for the third argument of ccDrawPoly(), setting it to YES will connect the start and end points of the array, making a closed polygon, while using NO will just make a bunch of open lines.

Copy NSMutableArray into array of floats for GLES rendering

I have an NSMutableArray called mVerticies stored as a member of my class and I'd like to place them into a float array to draw them with glVertexAttribPointer.
Normally when drawing, I would have something like:
float verticies[] = {-1, -1, 1, -1};
// ... prepare to draw
glVertexAttribPointer(GLKVertexAttribPosition,
2, GL_FLOAT, GL_FALSE, 0, verticies);
// ... draw
But in order to use the glVertexAttribPointer function, i need a float[]. The verticies are stored as an NSMutableArray because they change quite often. Is there an easy way to either store a dynamic float[] as a member or to quickly convert an NSMutableArray to a float[]?
Assuming the values are stored as NSNumbers, you can do something like this:
float *floatsArray = malloc([numbersArray count] * sizeof(float));
if (floatsArray == NULL) {
// handle error
}
[numbersArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSNumber *number, NSUInteger idx, BOOL *stop) {
floatsArray[idx] = [number floatValue];
}];
// use floatsArray
free(floatsArray);
You need to use malloc if you just want a raw chunk memory to read and write values directly.
If you have an NSArray array containing NSNumber instances:
float *vertices = malloc(sizeof(float) * [array count]);
for (int i = 0; i < [array count]; i++) {
vertices[i] = [[array objectAtIndex:i] floatValue];
}
// draw cool 3D objects and stuff
glVertexAttribPointer(....)
// then, when you're totally done with the memory
free(vertices);
Unlike Objective-C objects, the vertices pointer doesn't have a retain count, so you need to free it yourself, and keep track of when you can free it, because when you call free it will be gone immediately.
Just loop through the values. Assuming your floats are stored as NSNumbers:
NSUInteger count = [mutableVerticesArray count];
float vertices[count];
for (NSUInteger i = 0; i < count; i++) {
vertices[i] = [[mutableVerticesArray objectAtIndex:i] floatValue];
}
// Drawing etc.

How to cycle through an array of CGPoints

I have created an array of 16 CGpoints representing 16 positions on a game board. This is how i set up the array CGPoint cgpointarray[16]; I would like to create a for loop to cycle through each item in the array and check if the touch is within x distance of a position (i have the position as a CGPoint. I don't have much experiance with xcode or objective c. I know the python equivalent would be
for (i in cgpointarray){
//Stuff to do
}
How would i accomplish this? Thanks
for (int i = 0; i < 16; i++){
CGPoint p = cgpointarray[i];
//do something
}
Or if you want to use the NSArray Class:
NSMutableArray *points = [NSMutableArray array];
[points addObject:[ NSValue valueWithCGPoint:CGPointMake(1,2)]];
for(NSValue *v in points) {
CGPoint p = v.CGPointValue;
//do something
}
( not tested in XCode )
This should do it:
for (NSUInteger i=0; i < sizeof(cgpointarray)/sizeof(CGPoint); i++) {
CGPoint point = cgpointarray[i];
// Do stuff with point
}
I would normally go for the NSValue approach above but sometimes you are working with an API where you can't change the output. #Andrews approach is cool but I prefer the simplicity of .count:
NSArray* arrayOfStructyThings = [someAPI giveMeAnNSArrayOfStructs];
for (NSUInteger i = 0; i < arrayOfStructyThings.count; ++i) {
SomeOldStruct tr = arrayOfStructyThings[i];
.... do your worst here ...
}

Find the closest CCSprite

I am trying to find the closest "player" to a "ball" and each of these objects are CCSprite Objects. This is my first app, so if there's a better way to do this, feel free to suggest it :)
Here's my code so far:
for(CCSprite *currentPlayer in players) {
// distance formula
CGFloat dx = ball.position.x - currentPlayer.position.x;
CGFloat dy = ball.position.y - currentPlayer.position.y;
CGFloat distance = sqrt(dx*dx + dy*dy);
// add the distance to the distances array
[distances addObject:[NSNumber numberWithFloat:distance]];
NSLog(#"This happen be 5 times before the breakpoint");
NSLog(#"%#", [NSNumber numberWithInt:distance]);
}
So this seems to work well; it logs each distance of the player from the ball. But then when I loop through my "distances" array, like this:
for(NSNumber *distance in distances ) {
NSLog(#"Distance loop");
NSLog(#"%#", [NSNumber numberWithInt:distance]);
}
And this is logging a huge number each time, like 220255312. I declare my distances array like this:
// setting the distance array
NSMutableArray *distances = [[NSMutableArray alloc] init];
What am I doing wrong?
Thanks for your time!
Use distance for the #"%#" like this:
for(NSNumber *distance in distances ) {
NSLog(#"Distance loop");
NSLog(#"%#", distance);
}
[NSNumber numberWithInt:distance]
In your first part distance is a CGFloat.
In the second part distance is a NSNumber.
numberWithInt can't take a NSNumber as its argument.
Hope this helps!
CCSprite *nearestPlayer;
for(CCSprite *currentPlayer in players) {
if(nearestPlayer == nil){
nearestPlayer = currentPlayer;
}
if(ccpDistance(ball.position, currentPlayer.position) < ccpDistance(ball.position, nearestPlayer.position)){
nearestPlayer = currentPlayer;
}
}

Access C Array within blocks (variable array count) Objective-C

Blocks are fine but what about writing C arrays?
Given this simplified situation:
CGPoint points[10];
[myArray forEachElementWithBlock:^(int idx) {
points[idx] = CGPointMake(10, 20); // error here
// Cannot refer to declaration with an array type inside block
}];
after searching a while found this possible solution, to put it in a struct:
__block struct {
CGPoint points[100];
} pointStruct;
[myArray forEachElementWithBlock:^(int idx) {
pointStruct.points[idx] = CGPointMake(10, 20);
}];
this would work but there is a little limitation I have to create the c array dynamically:
int count = [str countOccurencesOfString:#";"];
__block struct {
CGPoint points[count]; // error here
// Fields must have a constant size: 'variable length array in structure' extension will never be supported
} pointStruct;
How can I access my CGPoint array within a block?
OR
Is it even possible at all or do I have to rewrite the block method to get the full functionality?
Another simple answer which works for me is the following:
CGPoint points[10], *pointsPtr;
pointsPtr = points;
[myArray forEachElementWithBlock:^(int idx) {
pointsPtr[idx] = CGPointMake(10, 20);
}];
Maybe you can allocate the array on the heap?
// Allocates a plain C array on the heap. The array will have
// [myArray count] items, each sized to fit a CGPoint.
CGPoint *points = calloc([myArray count], sizeof(CGPoint));
// Make sure the allocation succeded, you might want to insert
// some more graceful error handling here.
NSParameterAssert(points != NULL);
// Loop over myArray, doing whatever you want
[myArray forEachElementWithBlock:^(int idx) {
points[idx] = …;
}];
// Free the memory taken by the C array. Of course you might
// want to do something else with the array, otherwise this
// excercise does not make much sense :)
free(points), points = NULL;