2014-02-26 7 views
7

Ich versuche, eine Bereich Berechnung Kategorie für MKPolygon zu machen. Ich fand einige JS-Code https://github.com/mapbox/geojson-area/blob/master/index.js#L1 mit einem Link zum Algorithmus: http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409. Dort heißt es: enter image description hereMKPolygon Bereich Berechnung

enter image description here

Hier ist mein Code, die ein falsches Ergebnis gab (in Tausend Mal mehr als tatsächliche):

#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 

Was habe ich verpasst?

+0

Der letzte Schritt für "i == N-1" und "i + 1 == 0" (Umbruch) fehlt in Ihrer Schleife. –

+0

@MartinR danke, ich werde es beheben. – Shmidt

+0

@MartinR Sie hatten Recht. Wenn Sie Ihren Kommentar als Antwort posten, werde ich ihn akzeptieren. – Shmidt

Antwort

3

Der letzte Schritt für i = N-1 und i+1 = 0 (Wrap-around) fehlt in Ihrer Schleife.

+0

Kann jemand erklären, was das eigentlich in Codeform bedeutet? – AndyDunn

1

Dies jemand helfen kann ... Sie müssen die Form Randpunkte in folgenden Methode zu übergeben, und es gibt den richtigen Bereich eines Polygons

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

Der gesamte Algorithmus in Swift 3.0 implementiert:

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