找到MKPolygon的精确质心(作为MKMapPoint)

时间:2014-09-10 01:11:05

标签: ios objective-c macos mapkit

这意味着排除任何interiorPolygons的区域。

一旦具有外points多边形的质心,一个(即,以Objective-C示例的形式)如何通过减法interiorPolygons调整质心?或者是否有更优雅的方式一次性计算质心?

如果您帮助使代码正常工作,它将是开源的(WIP here)。

可能会有所帮助:

  1. http://www.ecourses.ou.edu/cgi-bin/eBook.cgi?topic=st&chap_sec=07.2&page=case_sol
  2. https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon

2 个答案:

答案 0 :(得分:1)

今天想一想,将每个内部质心 按区域加权 添加到外部质心会产生合理的意义。 (左侧有一个内部多边形(孔)的正方形会使质心向右移动,与孔的面积成正比。)

不按比例缩放:nothing to scale

- (MKMapPoint)calculateCentroid
{
    switch (self.pointCount) {
        case 0: return MKMapPointMake(0.0,
                                      0.0);
        case 1: return MKMapPointMake(self.points[0].x,
                                      self.points[0].y);
        case 2: return MKMapPointMake((self.points[0].x + self.points[1].x) / 2.0,
                                      (self.points[0].y + self.points[1].y) / 2.0);

    }

    // onward implies pointCount >= 3

    MKMapPoint centroid;
    MKMapPoint *previousPoint = &(self.points[self.pointCount-1]); // for i=0, wrap around to the last point

    for (NSUInteger i = 0; i < self.pointCount; ++i) {
        MKMapPoint *point = &(self.points[i]);

        double delta = (previousPoint->x * point->y) - (point->x * previousPoint->y); // x[i-1]*y[i] + x[i]*y[i-1]

        centroid.x += (previousPoint->x + point->x) * delta; // (x[i-1] + x[i]) / delta
        centroid.y += (previousPoint->y + point->y) * delta; // (y[i-1] + y[i]) / delta

        previousPoint = point;
    }

    centroid.x /= 6.0 * self.area;
    centroid.y /= 6.0 * self.area;

    // interiorPolygons are holes (subtractive geometry model)
    for (MKPolygon *interiorPoly in self.interiorPolygons) {
        if (interiorPoly.area == 0.0) {
            continue; // avoid div-by-zero
        }

        centroid.x += interiorPoly.centroid.x / interiorPoly.area;
        centroid.y += interiorPoly.centroid.y / interiorPoly.area;
    }

    return centroid;
}

答案 1 :(得分:0)

在Swift 5中

private func centroidForCoordinates(_ coords: [CLLocationCoordinate2D]) -> CLLocationCoordinate2D? {
        guard let firstCoordinate = coordinates.first else {
            return nil
        }
        
        guard coords.count > 1 else {
            return firstCoordinate
        }
        
        var minX = firstCoordinate.longitude
        var maxX = firstCoordinate.longitude
        var minY = firstCoordinate.latitude
        var maxY = firstCoordinate.latitude
        
        for i in 1..<coords.count {
            let current = coords[i]
            if minX > current.longitude {
                minX = current.longitude
            } else if maxX < current.longitude {
                maxX = current.longitude
            } else if minY > current.latitude {
                minY = current.latitude
            } else if maxY < current.latitude {
                maxY = current.latitude
            }
        }
        
        let centerX = minX + ((maxX - minX) / 2)
        let centerY = minY + ((maxY - minY) / 2)
        return CLLocationCoordinate2D(latitude: centerY, longitude: centerX)
    }