MKPolygon面积计算

时间:2014-02-26 10:43:58

标签: objective-c ios7 mapkit mkpolygon

我正在尝试为MKPolygon制作区域计算类别。 我发现了一些带有算法链接的JS代码https://github.com/mapbox/geojson-area/blob/master/index.js#L1http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409。 它说: enter image description here

enter image description here

这是我的代码,它给出了错误的结果(比实际的数千倍):

#define kEarthRadius 6378137
@implementation MKPolygon (AreaCalculation)
- (double) area {
    double area = 0;
    NSArray *coords = [self coordinates];
    if (coords.count > 2) {
        CLLocationCoordinate2D p1, p2;
        for (int i = 0; i < coords.count - 1; i++) {
            p1 = [coords[i] MKCoordinateValue];
            p2 = [coords[i + 1] MKCoordinateValue];
            area += degreesToRadians(p2.longitude - p1.longitude) * (2 + sinf(degreesToRadians(p1.latitude)) + sinf(degreesToRadians(p2.latitude)));
        }

        area = area * kEarthRadius * kEarthRadius / 2;
    }

    return area;
}
- (NSArray *)coordinates {
    NSMutableArray *points = [NSMutableArray arrayWithCapacity:self.pointCount];
    for (int i = 0; i < self.pointCount; i++) {
        MKMapPoint *point = &self.points[i];
        [points addObject:[NSValue valueWithMKCoordinate:MKCoordinateForMapPoint(* point)]];
    }
    return points.copy;
}

double degreesToRadians(double radius) {
    return radius * M_PI / 180;
}

@end

我错过了什么?

3 个答案:

答案 0 :(得分:6)

整个算法在 Swift 3.0

中实现
(1,A,10,C,120) (2,B,20,C,40) (3,A,10,B,50)

答案 1 :(得分:3)

循环中缺少i = N-1i+1 = 0(环绕)的最后一步。

答案 2 :(得分:1)

这可能会对某人有所帮助...... 您需要将形状边缘点传递给下面的方法,并返回多边形的正确区域

static double areaOfCurveWithPoints(const NSArray *shapeEdgePoints) {

    CGPoint initialPoint = [shapeEdgePoints.firstObject CGPointValue];

    CGMutablePathRef cgPath = CGPathCreateMutable();
    CGPathMoveToPoint(cgPath, &CGAffineTransformIdentity, initialPoint.x, initialPoint.y);

    for (int i = 1;i<shapeEdgePoints.count ;i++) {

        CGPoint point = [[shapeEdgePoints objectAtIndex:i] CGPointValue];
        CGPathAddLineToPoint(cgPath, &CGAffineTransformIdentity, point.x, point.y);
    }
    CGPathCloseSubpath(cgPath);

    CGRect frame = integralFrameForPath(cgPath);
    size_t bytesPerRow = bytesPerRowForWidth(frame.size.width);
    CGContextRef gc = createBitmapContextWithFrame(frame, bytesPerRow);
    CGContextSetFillColorWithColor(gc, [UIColor whiteColor].CGColor);
    CGContextAddPath(gc, cgPath);
    CGContextFillPath(gc);

    double area = areaFilledInBitmapContext(gc);

    CGPathRelease(cgPath);
    CGContextRelease(gc);

    return area;
}
static CGRect integralFrameForPath(CGPathRef path) {
    CGRect frame = CGPathGetBoundingBox(path);
    return CGRectIntegral(frame);
}

static size_t bytesPerRowForWidth(CGFloat width) {
    static const size_t kFactor = 64;
    // Round up to a multiple of kFactor, which must be a power of 2.
    return ((size_t)width + (kFactor - 1)) & ~(kFactor - 1);
}

static CGContextRef createBitmapContextWithFrame(CGRect frame, size_t bytesPerRow) {
    CGColorSpaceRef grayscale = CGColorSpaceCreateDeviceGray();
    CGContextRef gc = CGBitmapContextCreate(NULL, frame.size.width, frame.size.height, 8, bytesPerRow, grayscale, kCGImageAlphaNone);
    CGColorSpaceRelease(grayscale);
    CGContextTranslateCTM(gc, -frame.origin.x, -frame.origin.x);
    return gc;
}

static double areaFilledInBitmapContext(CGContextRef gc) {
    size_t width = CGBitmapContextGetWidth(gc);
    size_t height = CGBitmapContextGetHeight(gc);
    size_t stride = CGBitmapContextGetBytesPerRow(gc);

    // Get a pointer to the data
    unsigned char *bitmapData = (unsigned char *)CGBitmapContextGetData(gc);

    uint64_t coverage = 0;
    for (size_t y = 0; y < height; ++y) {
        for (size_t x = 0; x < width; ++x) {
            coverage += bitmapData[y * stride + x];
        }
    }
   // NSLog(@"coverage =%llu  UINT8_MAX =%d",coverage,UINT8_MAX);
    return (double)coverage / UINT8_MAX;
}