EFC - 1 year ago 175

iOS Question

I have an arbitrary

`CGPath`

`CGPathGetPathBoundingBox`

`BOOL moved = NO; // the first coord should be a move, the rest add lines`

CGPoint total = CGPointZero;

for (NSDictionary *coord in [polygon objectForKey:@"coordinates"]) {

CGPoint point = CGPointMake([(NSNumber *)[coord objectForKey:@"x"] floatValue],

[(NSNumber *)[coord objectForKey:@"y"] floatValue]);

if (moved) {

CGContextAddLineToPoint(context, point.x, point.y);

// calculate totals of x and y to help find the center later

// skip the first "move" point since it is repeated at the end in this data

total.x = total.x + point.x;

total.y = total.y + point.y;

} else {

CGContextMoveToPoint(context, point.x, point.y);

moved = YES; // we only move once, then we add lines

}

}

// the center is the average of the total points

CGPoint center = CGPointMake(total.x / ([[polygon objectForKey:@"coordinates"] count]-1), total.y / ([[polygon objectForKey:@"coordinates"] count]-1));

If you have a better idea, please share!

Answer Source

The technique works, but the code you put in the question doesn't. AFAICS, that only works for the few situations where you are doing straight-line polygons ONLY, *and* you have a list of points, *and* you haven't made the CGPath object yet.

I needed to do it for arbitrary CGPath objects. Using Adam's (other Adam) suggestion, and Apple's CGPathApply, I came up with this, which works very well:

```
{
float dataArray[3] = { 0, 0, 0 };
CGPathApply( (CGPathRef) YOUR_PATH, dataArray, pathApplierSumCoordinatesOfAllPoints);
float averageX = dataArray[0] / dataArray[2];
float averageY = dataArray[1] / dataArray[2];
CGPoint centerOfPath = CGPointMake(averageX, averageY);
}
static void pathApplierSumCoordinatesOfAllPoints(void* info, const CGPathElement* element)
{
float* dataArray = (float*) info;
float xTotal = dataArray[0];
float yTotal = dataArray[1];
float numPoints = dataArray[2];
switch (element->type)
{
case kCGPathElementMoveToPoint:
{
/** for a move to, add the single target point only */
CGPoint p = element->points[0];
xTotal += p.x;
yTotal += p.y;
numPoints += 1.0;
}
break;
case kCGPathElementAddLineToPoint:
{
/** for a line to, add the single target point only */
CGPoint p = element->points[0];
xTotal += p.x;
yTotal += p.y;
numPoints += 1.0;
}
break;
case kCGPathElementAddQuadCurveToPoint:
for( int i=0; i<2; i++ ) // note: quad has TWO not THREE
{
/** for a curve, we add all ppints, including the control poitns */
CGPoint p = element->points[i];
xTotal += p.x;
yTotal += p.y;
numPoints += 1.0;
}
break;
case kCGPathElementAddCurveToPoint:
for( int i=0; i<3; i++ ) // note: cubic has THREE not TWO
{
/** for a curve, we add all ppints, including the control poitns */
CGPoint p = element->points[i];
xTotal += p.x;
yTotal += p.y;
numPoints += 1.0;
}
break;
case kCGPathElementCloseSubpath:
/** for a close path, do nothing */
break;
}
//NSLog(@"new x=%2.2f, new y=%2.2f, new num=%2.2f", xTotal, yTotal, numPoints);
dataArray[0] = xTotal;
dataArray[1] = yTotal;
dataArray[2] = numPoints;
}
```