How to form CGPoint array in Objective-C?
Asked Answered
I

5

30

I want to get this structure:

CGPoint addLines1[] =
{
    CGPointMake(30.0, 150.0),
    CGPointMake(41.67, 145.19),
    CGPointMake(53.33, 103.25),
    CGPointMake(65.0, 131.67),
    CGPointMake(76.67, 106.11),
    CGPointMake(88.33, 110.20),
    CGPointMake(100.0, 111.54),
    CGPointMake(111.67, 112.13),
    CGPointMake(123.33, 115.66),
    CGPointMake(135.0, 123.7),
    CGPointMake(146.67, 125.53),
    CGPointMake(158.33, 115.1),
    CGPointMake(170.0, 69.38),
    CGPointMake(181.67, 112.47),
    CGPointMake(193.33, 65.1),
    CGPointMake(205.0, 103.33),
    CGPointMake(216.67, 92.6),
    CGPointMake(228.33, 54.76),
    CGPointMake(240.0, 79.66),
    CGPointMake(251.67, 53.81),
    CGPointMake(263.33, 56.81),
    CGPointMake(275.0, 88.19),
    CGPointMake(286.67, 74.81),
    CGPointMake(298.33, 28.1),
    CGPointMake(310, 20.0),
};

In order to make some calculations and draw data.

I have CGPoint *lines = appDelegate.averageResponseTimePoints;

How to make array addLines[] from *lines?

Ineligible answered 3/6, 2009 at 10:4 Comment(0)
B
50

C arrays are not really arrays at run time, where they are just pointers to a contiguous block of objects of the same type. When you see items[n], that's just syntactic sugar for *(items+n).

In your example addLines[1] would be *(lines+1) and addLines[0] would be *(lines+0), which is *lines. So, addLines is just lines without the pointer dereference. *lines is the first item in the array and lines is the whole array.

Arrays have some differences to pointers at compile time. For example, sizeof(addLines) would give you the size of the whole array.

Array-ness is lost as soon as you pass the array somewhere where it's size might be variable, but you can still use the subscript operator. For example:

#include <Foundation/Foundation.h>

#define showsize( expr ) ( printf(#expr " = %zd\n", ( expr ) ) )

CGPoint *
pass_back(CGPoint points[4])
{
    showsize(sizeof(points));
    return points;
}

int
main(void)
{
    CGPoint square[] = {CGPointMake(-1.0,  1.0),
                        CGPointMake( 1.0,  1.0),
                        CGPointMake( 1.0, -1.0),
                        CGPointMake(-1.0, -1.0)};
    CGPoint* returned;
    int i;

    showsize(sizeof(CGPoint));
    showsize(sizeof(CGPoint*));
    showsize(sizeof(square));
    returned = pass_back(square);
    showsize(sizeof(returned));

    for (i = 0; i < 4; ++i) {
        printf("returned[%d] = {%0.1f, %0.1f}\n", i, (float) returned[i].x,
                                                 (float) returned[i].y);
    }

    return 0;
}

This outputs the following on my Mac:

sizeof(CGPoint) = 8
sizeof(CGPoint*) = 4
sizeof(square) = 32
sizeof(points) = 4
sizeof(returned) = 4
returned[0] = {-1.0, 1.0}
returned[1] = {1.0, 1.0}
returned[2] = {1.0, -1.0}
returned[3] = {-1.0, -1.0}

Here, square is the size of four CGPoints, but once sent to the pass_back function, it's only the size of a pointer, because that's what it is. When the pointer comes back (and named returned) it can still be used like an array.

Note the magic number 4 in the loop. The pointer doesn't know the length of the array it's pointing to.

Arrays cannot be reassigned with the = operator. If you really must populate addLines with the points from lines, you can do that with something like the following:

memcpy(addLines, lines, sizeof(CGPoint) * numberOfPoints);

You'll have to get numberOfPoints from somewhere, and addLines will have to be large enough to handle those points. That's okay if the number of points is a constant, but it would be bad if the number of points can vary at run time, especially if the points come from the outside world (think arbitrary code execution).

I'd change averageResponseTimePoints to return an NSArray rather than a C-style array. You'll need to encapsulate the CGPoints in objects - either your own object or NSValues.

Here's an example of how you could write averageResponseTimePoints:

- (NSArray*) averageResponseTimePoints
{
    NSMutableArray* result = [[[NSMutableArray alloc] init] autorelease];

    for (int i = 0; i < numberOfPoints; ++i) {
        NSValue* point = [NSValue value:points+i
                           withObjCType:@encode(CGPoint)];
        [result addObject:point];
    }

    return result;
}

If your code runs with CocoaTouch, you can use this to create the point value instead:

NSValue* point = [NSValue valueWithCGPoint:points[i]];

To get the CGPoints out of the array, you could write something like this:

for (NSValue* value in result) {
    NSPoint pt;
    [value getValue:&pt];
    NSLog(@"%f %f", pt.x, pt.y);
}

Or with CocoaTouch:

CGPoint pt = [value CGPointValue];
Biting answered 3/6, 2009 at 10:40 Comment(5)
Consider difference between two methods: valueWithCGPoint: and valueWithPointer:. Details hereKalindi
"C arrays are not really arrays at run time". Yes they are - they're perfectly valid C arrays. What you mean is that they are not NSArrays.Reprint
@Reprint What Will means is that “The C ‘runtime’ has no concept of an ‘array’— C arrays are language/compiler-level tricks, and only understood as pointers at runtime.” So no, at runtime they're not ‘perfectly valid C arrays’, because in this respect C is hands-off at the point of runtime.Burnedout
@Reprint This distinction is more clear in comparison to languages that do have runtime representations of arrays— Objective-C's NSArray, C++'s STL array/deque/list/etc, Java isArray()-adhering types, C# IsArray-adhering types, JavaScript's Array, etc.Burnedout
You are applying a "modern" definition of arrays. I'll take one of the C inventors terminology as authoritative: lysator.liu.se/c/bwk-tutor.html#arrayReprint
R
52

For iOS:

Create array:

NSArray *myCGPointArray = @[[NSValue valueWithCGPoint:CGPointMake(30.0, 150.0)],[NSValue valueWithCGPoint:CGPointMake(41.67, 145.19)]];

Get 1st CGPoint object:

CGPoint myPoint = [myCGPointArray[0] CGPointValue];
Ringhals answered 21/5, 2012 at 10:44 Comment(0)
B
50

C arrays are not really arrays at run time, where they are just pointers to a contiguous block of objects of the same type. When you see items[n], that's just syntactic sugar for *(items+n).

In your example addLines[1] would be *(lines+1) and addLines[0] would be *(lines+0), which is *lines. So, addLines is just lines without the pointer dereference. *lines is the first item in the array and lines is the whole array.

Arrays have some differences to pointers at compile time. For example, sizeof(addLines) would give you the size of the whole array.

Array-ness is lost as soon as you pass the array somewhere where it's size might be variable, but you can still use the subscript operator. For example:

#include <Foundation/Foundation.h>

#define showsize( expr ) ( printf(#expr " = %zd\n", ( expr ) ) )

CGPoint *
pass_back(CGPoint points[4])
{
    showsize(sizeof(points));
    return points;
}

int
main(void)
{
    CGPoint square[] = {CGPointMake(-1.0,  1.0),
                        CGPointMake( 1.0,  1.0),
                        CGPointMake( 1.0, -1.0),
                        CGPointMake(-1.0, -1.0)};
    CGPoint* returned;
    int i;

    showsize(sizeof(CGPoint));
    showsize(sizeof(CGPoint*));
    showsize(sizeof(square));
    returned = pass_back(square);
    showsize(sizeof(returned));

    for (i = 0; i < 4; ++i) {
        printf("returned[%d] = {%0.1f, %0.1f}\n", i, (float) returned[i].x,
                                                 (float) returned[i].y);
    }

    return 0;
}

This outputs the following on my Mac:

sizeof(CGPoint) = 8
sizeof(CGPoint*) = 4
sizeof(square) = 32
sizeof(points) = 4
sizeof(returned) = 4
returned[0] = {-1.0, 1.0}
returned[1] = {1.0, 1.0}
returned[2] = {1.0, -1.0}
returned[3] = {-1.0, -1.0}

Here, square is the size of four CGPoints, but once sent to the pass_back function, it's only the size of a pointer, because that's what it is. When the pointer comes back (and named returned) it can still be used like an array.

Note the magic number 4 in the loop. The pointer doesn't know the length of the array it's pointing to.

Arrays cannot be reassigned with the = operator. If you really must populate addLines with the points from lines, you can do that with something like the following:

memcpy(addLines, lines, sizeof(CGPoint) * numberOfPoints);

You'll have to get numberOfPoints from somewhere, and addLines will have to be large enough to handle those points. That's okay if the number of points is a constant, but it would be bad if the number of points can vary at run time, especially if the points come from the outside world (think arbitrary code execution).

I'd change averageResponseTimePoints to return an NSArray rather than a C-style array. You'll need to encapsulate the CGPoints in objects - either your own object or NSValues.

Here's an example of how you could write averageResponseTimePoints:

- (NSArray*) averageResponseTimePoints
{
    NSMutableArray* result = [[[NSMutableArray alloc] init] autorelease];

    for (int i = 0; i < numberOfPoints; ++i) {
        NSValue* point = [NSValue value:points+i
                           withObjCType:@encode(CGPoint)];
        [result addObject:point];
    }

    return result;
}

If your code runs with CocoaTouch, you can use this to create the point value instead:

NSValue* point = [NSValue valueWithCGPoint:points[i]];

To get the CGPoints out of the array, you could write something like this:

for (NSValue* value in result) {
    NSPoint pt;
    [value getValue:&pt];
    NSLog(@"%f %f", pt.x, pt.y);
}

Or with CocoaTouch:

CGPoint pt = [value CGPointValue];
Biting answered 3/6, 2009 at 10:40 Comment(5)
Consider difference between two methods: valueWithCGPoint: and valueWithPointer:. Details hereKalindi
"C arrays are not really arrays at run time". Yes they are - they're perfectly valid C arrays. What you mean is that they are not NSArrays.Reprint
@Reprint What Will means is that “The C ‘runtime’ has no concept of an ‘array’— C arrays are language/compiler-level tricks, and only understood as pointers at runtime.” So no, at runtime they're not ‘perfectly valid C arrays’, because in this respect C is hands-off at the point of runtime.Burnedout
@Reprint This distinction is more clear in comparison to languages that do have runtime representations of arrays— Objective-C's NSArray, C++'s STL array/deque/list/etc, Java isArray()-adhering types, C# IsArray-adhering types, JavaScript's Array, etc.Burnedout
You are applying a "modern" definition of arrays. I'll take one of the C inventors terminology as authoritative: lysator.liu.se/c/bwk-tutor.html#arrayReprint
A
4

Try this

CGPoint A[10];
A[0] = CGPointMake(10.0, 10.0);
A[1] = CGPointMake(10.0, 12.0);
float x = A[1].y;
NSLog(@"%.0f", x);

It works. Good Luck.

Almena answered 4/12, 2012 at 9:31 Comment(0)
Z
3

I tried Tibidabo's answer, and it didn't work for me. It said [myCGPointArray objectAtIndex:0] was of type id, so I couldn't call CGPointValue on it. hm.

this worked however:

NSArray *points = [NSArray arrayWithObjects:
                   [NSValue valueWithCGPoint:CGPointMake(5.5, 6.6)],
                   [NSValue valueWithCGPoint:CGPointMake(7.7, 8.8)],
                   nil];

NSValue *val = [points objectAtIndex:0];
CGPoint point = [val CGPointValue];
float X = point.x;
NSLog(@"cgpoint value is: %f", X);

or

NSArray *points = [NSArray arrayWithObjects:
                        [NSValue valueWithCGPoint:CGPointMake(20, 6.6)],
                        [NSValue valueWithCGPoint:CGPointMake(7.7, 8.8)],
                        nil];
float xCoordinate = [[points objectAtIndex:0] CGPointValue].x;

I found it here: How can I add CGPoint objects to an NSArray the easy way?, posted by Jarret Hardie.

Zakaria answered 24/3, 2013 at 21:3 Comment(0)
W
2

I solve my problem doing the next:


NSMutableArray *myArray = [[NSMutableArray alloc] init];
[myArray addObject:[NSValue valueWithCGPoint:myPoint]];

Thanks to michael-jensen for the solution!

Whoever answered 5/10, 2013 at 18:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.