Как сделать UIBezierPath гладким в Swift - PullRequest
0 голосов
/ 02 октября 2019

Я пытаюсь создать линейную диаграмму, которая представляет набор значений (x и y) в плавной кривой Безье. Это работает нормально, за исключением случаев, когда значения x близки друг к другу, а значения y переходят от непрерывной линии к более низкому или более высокому значению. Значения не показаны на самой диаграмме, но вот изображение, иллюстрирующее мою проблему:

Chart Issue

Как видите, линия проходит в обратном направлениидвижение, прежде чем перейти к следующей точке. Я бы хотел, чтобы этого не произошло и сгладилось. Для генерации точек данных я использую эту библиотеку из Minh Nguyen , которая мне очень помогла. Единственная проблема - эта проблема все еще. Для простоты вот код, который я сейчас использую:

private func controlPointsFrom(points: [CGPoint]) -> [CurvedSegment] {
    var result: [CurvedSegment] = []
    let delta: CGFloat = 0.3
    for i in 1..<points.count {
        let A = points[i-1]
        let B = points[i]
        let controlPoint1 = CGPoint(x: A.x + delta*(B.x-A.x), y: A.y + delta*(B.y - A.y))
        let controlPoint2 = CGPoint(x: B.x - delta*(B.x-A.x), y: B.y - delta*(B.y - A.y))
        let curvedSegment = CurvedSegment(controlPoint1: controlPoint1, controlPoint2: controlPoint2)
        result.append(curvedSegment)
    }

    for i in 1..<points.count-1 {
        let M = result[i-1].controlPoint2
        let N = result[i].controlPoint1
        let A = points[i]
        let MM = CGPoint(x: 2 * A.x - M.x, y: 2 * A.y - M.y)
        let NN = CGPoint(x: 2 * A.x - N.x, y: 2 * A.y - N.y)
        result[i].controlPoint1 = CGPoint(x: (MM.x + N.x)/2, y: (MM.y + N.y)/2)
        result[i-1].controlPoint2 = CGPoint(x: (NN.x + M.x)/2, y: (NN.y + M.y)/2)
    }
    return result
}

func createCurvedPath(_ dataPoints: [CGPoint]) -> UIBezierPath? {
    let path = UIBezierPath()
    path.move(to: dataPoints[0])
    var curveSegments: [CurvedSegment] = []
    let useDataPoints = dataPoints.filter { ($0.y < 1000) }
    curveSegments = controlPointsFrom(points: useDataPoints)
    for i in 1..<useDataPoints.count {
        path.addCurve(to: useDataPoints[i], controlPoint1: curveSegments[i - 1].controlPoint1, controlPoint2: curveSegments[i - 1].controlPoint2)
    }
    return path
}

Для документации я бы обратился к руководству / blogpost , на которое я ссылался ранее . Я полагаю, что проблема должна быть где-то в расчете controlPoint1 и controlPoint2 в функции controlPointsFrom. Когда я удаляю дельту или делаю ее равной 0, она просто становится прямой линией, но тогда проблема также не возникает. Так что математика должна быть другой, я думаю, чтобы отслеживать предыдущее значение и, возможно, не создавать контрольную точку с более высоким или более низким значением y, когда следующая точка ниже или выше соответственно. Но я не могу понять, как заставить это работать. Любой умный ум, который может сделать это?

Буду вечно благодарен!

1 Ответ

0 голосов
/ 02 октября 2019
...