如何从cgpoints数组中获取中心点?

Swi*_*yJD 2 arrays cgpoint ios swift

我有一组 CGPoints:

let points = [(1234.0, 1053.0), (1241.0, 1111.0), (1152.0, 1043.0)]
Run Code Online (Sandbox Code Playgroud)

我想做的是找到 CGPoints 的中心。所以我可以将一个对象放置在所有点的中心。如果这是一个整数数组,我会像这样减少数组:

points.reduce(0, +)
Run Code Online (Sandbox Code Playgroud)

然后除以数组总数以获得平均值。但由于它的 CGPoints 这不起作用。关于如何实现这一目标有什么想法吗?

Rob*_*Rob 5

Farhad 回答了有关如何平均所有这些数据点的问题。(+1)

\n\n

但这真的是你想要的吗?考虑:

\n\n

这个图片

\n\n

该凸形状由蓝点定义,但所有这些点的平均值是红点。但 \xe2\x80\x99 并不真正位于形状的中心。它是倾斜的,因为顶部附近有五个数据点,下面只有两个数据点。这个凸形状很好地说明了问题,但是\xe2\x80\x99不需要凸形状才能体现这个问题。数据点分布不相对均匀的任何情况都可以体现这种行为。

\n\n

绿点是多边形的质心。您可以看到它落在边界框中心(上图中的十字准线)下方,就像您\xe2\x80\x99d 所期望的那样。对于简单的形状,这可能是放置标签的更好位置。可以按下式计算:

\n\n
extension Array where Element == CGPoint {\n    /// Calculate signed area.\n    ///\n    /// See https://en.wikipedia.org/wiki/Centroid#Of_a_polygon\n    ///\n    /// - Returns: The signed area\n\n    func signedArea() -> CGFloat {\n        if isEmpty { return .zero }\n\n        var sum: CGFloat = 0\n        for (index, point) in enumerated() {\n            let nextPoint: CGPoint\n            if index < count-1 {\n                nextPoint = self[index+1]\n            } else {\n                nextPoint = self[0]\n            }\n\n            sum += point.x * nextPoint.y - nextPoint.x * point.y\n        }\n\n        return sum / 2\n    }\n\n    /// Calculate centroid\n    ///\n    /// See https://en.wikipedia.org/wiki/Centroid#Of_a_polygon\n    ///\n    /// - Note: If the area of the polygon is zero (e.g. the points are collinear), this returns `nil`.\n    ///\n    /// - Parameter points: Unclosed points of polygon.\n    /// - Returns: Centroid point.\n\n    func centroid() -> CGPoint? {\n        if isEmpty { return nil }\n\n        let area = signedArea()\n        if area == 0 { return nil }\n\n        var sumPoint: CGPoint = .zero\n\n        for (index, point) in enumerated() {\n            let nextPoint: CGPoint\n            if index < count-1 {\n                nextPoint = self[index+1]\n            } else {\n                nextPoint = self[0]\n            }\n\n            let factor = point.x * nextPoint.y - nextPoint.x * point.y\n            sumPoint.x += (point.x + nextPoint.x) * factor\n            sumPoint.y += (point.y + nextPoint.y) * factor\n        }\n\n        return sumPoint / 6 / area\n    }\n\n    func mean() -> CGPoint? {\n        if isEmpty { return nil }\n\n        return reduce(.zero, +) / CGFloat(count)\n    }\n}\n\nextension CGPoint {\n    static func + (lhs: CGPoint, rhs: CGPoint) -> CGPoint {\n        CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y)\n    }\n\n    static func - (lhs: CGPoint, rhs: CGPoint) -> CGPoint {\n        CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y)\n    }\n\n    static func / (lhs: CGPoint, rhs: CGFloat) -> CGPoint {\n        CGPoint(x: lhs.x / rhs, y: lhs.y / rhs)\n    }\n\n    static func * (lhs: CGPoint, rhs: CGFloat) -> CGPoint {\n        CGPoint(x: lhs.x * rhs, y: lhs.y * rhs)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

你\xe2\x80\x99d 计算质心如下:

\n\n
let points = [(1234.0, 1053.0), (1241.0, 1111.0), (1152.0, 1043.0)]\n    .map(CGPoint.init)\n\nguard let point = points.centroid() else { return }\n
Run Code Online (Sandbox Code Playgroud)\n\n

FWIW,对于复杂的凹形形状,即使质心也不是最佳的。请参阅找到不规则形状多边形的“视觉”中心的最快方法是什么?

\n