 EFC -5 years ago 341
iOS Question

# Finding the center of a CGPath

I have an arbitrary

`CGPath`
and I'd like to find it's geographic center. I can get the path bounding box with
`CGPathGetPathBoundingBox`
and then find the center of that box. But is there a better way to find the center of a path?

Update for those who like to see code: here is code for using the average-of-points method suggested by Adam in the answers (don't miss the even better technique in the answers below)...

``````    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) {
// 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! Adam

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 = { 0, 0, 0 };
CGPathApply( (CGPathRef) YOUR_PATH, dataArray, pathApplierSumCoordinatesOfAllPoints);

float averageX = dataArray / dataArray;
float averageY = dataArray  / dataArray;
CGPoint centerOfPath = CGPointMake(averageX, averageY);
}

static void pathApplierSumCoordinatesOfAllPoints(void* info, const CGPathElement* element)
{
float* dataArray = (float*) info;
float xTotal = dataArray;
float yTotal = dataArray;
float numPoints = dataArray;

switch (element->type)
{
case kCGPathElementMoveToPoint:
{
/** for a move to, add the single target point only */

CGPoint p = element->points;
xTotal += p.x;
yTotal += p.y;
numPoints += 1.0;

}
break;
{
/** for a line to, add the single target point only */

CGPoint p = element->points;
xTotal += p.x;
yTotal += p.y;
numPoints += 1.0;

}
break;
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;
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 = xTotal;
dataArray = yTotal;
dataArray = numPoints;
}
``````
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download