【问题标题】:MKPolygon area calculationMKPolygon面积计算
【发布时间】:2014-02-26 10:43:58
【问题描述】:

我正在尝试为 MKPolygon 创建一个面积计算类别。 我找到了一些 JS 代码 https://github.com/mapbox/geojson-area/blob/master/index.js#L1 与算法的链接:http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409。 它说:

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

#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

我错过了什么?

【问题讨论】:

  • 循环中缺少i == N-1i+1 == 0(环绕)的最后一步。
  • @MartinR 谢谢,我会解决的。
  • @MartinR 你是对的。如果您发表评论作为答案,我会接受。
  • @Shmidt---我用你的公式来计算面积,但它似乎给了我错误的结果,如果你更新最终代码,那就太好了。我认为这里缺少一些东西。我需要这个在我的应用程序上工作。期待您的来信。

标签: objective-c ios7 mapkit mkpolygon


【解决方案1】:

Swift 3.0 中实现的整个算法:

import MapKit
let kEarthRadius = 6378137.0

// CLLocationCoordinate2D uses degrees but we need radians
func radians(degrees: Double) -> Double {
    return degrees * M_PI / 180;
}

func regionArea(locations: [CLLocationCoordinate2D]) -> Double {

    guard locations.count > 2 else { return 0 }
    var area = 0.0

    for i in 0..<locations.count {
        let p1 = locations[i > 0 ? i - 1 : locations.count - 1]
        let p2 = locations[i]

        area += radians(degrees: p2.longitude - p1.longitude) * (2 + sin(radians(degrees: p1.latitude)) + sin(radians(degrees: p2.latitude)) )
    }

    area = -(area * kEarthRadius * kEarthRadius / 2);

    return max(area, -area) // In order not to worry about is polygon clockwise or counterclockwise defined.
}

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 有人能解释一下这在代码形式中的实际含义吗?
    【解决方案3】:

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

    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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-12
      • 2018-01-09
      • 2018-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多