iOS - отметьте [CGPoint], чтобы сделать прямую линию - PullRequest
0 голосов
/ 01 сентября 2018

Если у меня есть массив CGPoints, как я могу проверить, производят ли они прямую линию?

Например, представьте сетку. Предполагая, что я нанес на карту все точки на сетке, как я могу проверить, все ли точки образуют прямую горизонтальную, вертикальную или диагональную линию?

1 Ответ

0 голосов
/ 01 сентября 2018

Один из способов сделать это - вычислить линию наилучшего соответствия для ваших точек, чтобы определить, лежат ли они на линии.

func pointsFormALine(_ points: [CGPoint]) -> Bool {

    // helper function to test if CGFloat is close enough to zero
    // to be considered zero
    func isZero(_ f: CGFloat) -> Bool {
        let epsilon: CGFloat = 0.00001

        return abs(f) < epsilon
    }

    // variables for computing linear regression
    var sumXX: CGFloat = 0  // sum of X^2
    var sumXY: CGFloat = 0  // sum of X * Y
    var sumX:  CGFloat = 0  // sum of X
    var sumY:  CGFloat = 0  // sum of Y

    for point in points {
        sumXX += point.x * point.x
        sumXY += point.x * point.y
        sumX  += point.x
        sumY  += point.y
    }

    // n is the number of points
    let n = CGFloat(points.count)

    // compute numerator and denominator of the slope
    let num = n * sumXY - sumX * sumY
    let den = n * sumXX - sumX * sumX

    // is the line vertical or horizontal?
    if isZero(num) || isZero(den) {
        return true
    }

    // calculate slope of line
    let m = num / den

    // calculate the y-intercept
    let b = (sumY - m * sumX) / n

    print("y = \(m)x + \(b)")

    // check fit by summing the squares of the errors
    var error: CGFloat = 0
    for point in points {
        // apply equation of line y = mx + b to compute predicted y
        let predictedY = m * point.x + b
        error += pow(predictedY - point.y, 2)
    }

    return isZero(error)
}

Тест:

pointsFormALine([CGPoint(x: 1, y: 2), CGPoint(x: 2, y: 4), CGPoint(x: 5, y: 10)])  // true
pointsFormALine([CGPoint(x: 1, y: 2), CGPoint(x: 1, y: 4), CGPoint(x: 1, y: 10)])  // true
pointsFormALine([CGPoint(x: 1, y: 2), CGPoint(x: 2, y: 2), CGPoint(x: 5, y: 2)])   // true
pointsFormALine([CGPoint(x: 1, y: 2), CGPoint(x: 2, y: 1), CGPoint(x: 2, y: 2)])   // false
...