9

目前,我正在尝试使多个贝塞尔曲线具有等距点。我目前正在使用三次插值来查找这些点,但是由于贝塞尔曲线的工作方式,某些区域比其他区域更密集,并且由于距离可变,因此证明纹理映射很粗糙。 有没有办法通过距离而不是百分比来查找贝塞尔曲线上的点?此外,是否可以将其扩展到多条连接曲线?

4

3 回答 3

9

这称为“弧长”参数化。几年前我写了一篇关于这个的论文:

http://www.saccade.com/writing/graphics/RE-PARAM.PDF

这个想法是预先计算“参数化”曲线,并通过它评估曲线。

于 2009-05-12T22:23:58.293 回答
3

P_0 和 P_3 之间的距离(立方形式),是的,但我想你知道,是直截了当的。

曲线上的距离就是弧长:

图 1 http://www.codecogs.com/eq.latex?%5Cint_%7Bt_0%7D%5E%7Bt_1%7D%20%7B%20|P'(t)|%20dt

在哪里:

图 2 http://www.codecogs.com/eq.latex?P%27(t)%20=%20[%7Bx%27,y%27,z%27%7D]%20=%20[% 7B%5Cfrac%7Bdx(t)%7D%7Bdt%7D,%5Cfrac%7Bdy(t)%7D%7Bdt%7D,%5Cfrac%7Bdz(t)%7D%7Bdt%7D%7D]

(见其余)

可能你会有 t_0 = 0、t_1 = 1.0 和 dz(t) = 0(二维平面)。

于 2008-08-14T00:47:05.103 回答
2

我知道这是一个老问题,但我最近遇到了这个问题并创建了一个UIBezierPath扩展来解决X给定坐标的Y坐标,反之亦然。速写。

https://github.com/rkotzy/RKBezierMath

extension UIBezierPath {

func solveBezerAtY(start: CGPoint, point1: CGPoint, point2: CGPoint, end: CGPoint, y: CGFloat) -> [CGPoint] {

    // bezier control points
    let C0 = start.y - y
    let C1 = point1.y - y
    let C2 = point2.y - y
    let C3 = end.y - y

    // The cubic polynomial coefficients such that Bez(t) = A*t^3 + B*t^2 + C*t + D
    let A = C3 - 3.0*C2 + 3.0*C1 - C0
    let B = 3.0*C2 - 6.0*C1 + 3.0*C0
    let C = 3.0*C1 - 3.0*C0
    let D = C0

    let roots = solveCubic(A, b: B, c: C, d: D)

    var result = [CGPoint]()

    for root in roots {
        if (root >= 0 && root <= 1) {
            result.append(bezierOutputAtT(start, point1: point1, point2: point2, end: end, t: root))
        }
    }

    return result
}

func solveBezerAtX(start: CGPoint, point1: CGPoint, point2: CGPoint, end: CGPoint, x: CGFloat) -> [CGPoint] {

    // bezier control points
    let C0 = start.x - x
    let C1 = point1.x - x
    let C2 = point2.x - x
    let C3 = end.x - x

    // The cubic polynomial coefficients such that Bez(t) = A*t^3 + B*t^2 + C*t + D
    let A = C3 - 3.0*C2 + 3.0*C1 - C0
    let B = 3.0*C2 - 6.0*C1 + 3.0*C0
    let C = 3.0*C1 - 3.0*C0
    let D = C0

    let roots = solveCubic(A, b: B, c: C, d: D)

    var result = [CGPoint]()

    for root in roots {
        if (root >= 0 && root <= 1) {
            result.append(bezierOutputAtT(start, point1: point1, point2: point2, end: end, t: root))
        }
    }

    return result

}

func solveCubic(a: CGFloat?, var b: CGFloat, var c: CGFloat, var d: CGFloat) -> [CGFloat] {

    if (a == nil) {
        return solveQuadratic(b, b: c, c: d)
    }

    b /= a!
    c /= a!
    d /= a!

    let p = (3 * c - b * b) / 3
    let q = (2 * b * b * b - 9 * b * c + 27 * d) / 27

    if (p == 0) {
        return [pow(-q, 1 / 3)]

    } else if (q == 0) {
        return [sqrt(-p), -sqrt(-p)]

    } else {

        let discriminant = pow(q / 2, 2) + pow(p / 3, 3)

        if (discriminant == 0) {
            return [pow(q / 2, 1 / 3) - b / 3]

        } else if (discriminant > 0) {
            let x = crt(-(q / 2) + sqrt(discriminant))
            let z = crt((q / 2) + sqrt(discriminant))
            return [x - z - b / 3]
        } else {

            let r = sqrt(pow(-(p/3), 3))
            let phi = acos(-(q / (2 * sqrt(pow(-(p / 3), 3)))))

            let s = 2 * pow(r, 1/3)

            return [
                s * cos(phi / 3) - b / 3,
                s * cos((phi + CGFloat(2) * CGFloat(M_PI)) / 3) - b / 3,
                s * cos((phi + CGFloat(4) * CGFloat(M_PI)) / 3) - b / 3
            ]

        }

    }
}

func solveQuadratic(a: CGFloat, b: CGFloat, c: CGFloat) -> [CGFloat] {

    let discriminant = b * b - 4 * a * c;

    if (discriminant < 0) {
        return []

    } else {
        return [
            (-b + sqrt(discriminant)) / (2 * a),
            (-b - sqrt(discriminant)) / (2 * a)
        ]
    }

}

private func crt(v: CGFloat) -> CGFloat {
    if (v<0) {
        return -pow(-v, 1/3)
    }
    return pow(v, 1/3)
}

private func bezierOutputAtT(start: CGPoint, point1: CGPoint, point2: CGPoint, end: CGPoint, t: CGFloat) -> CGPoint {

    // bezier control points
    let C0 = start
    let C1 = point1
    let C2 = point2
    let C3 = end

    // The cubic polynomial coefficients such that Bez(t) = A*t^3 + B*t^2 + C*t + D
    let A = CGPointMake(C3.x - 3.0*C2.x + 3.0*C1.x - C0.x, C3.y - 3.0*C2.y + 3.0*C1.y - C0.y)
    let B = CGPointMake(3.0*C2.x - 6.0*C1.x + 3.0*C0.x, 3.0*C2.y - 6.0*C1.y + 3.0*C0.y)
    let C = CGPointMake(3.0*C1.x - 3.0*C0.x, 3.0*C1.y - 3.0*C0.y)
    let D = C0

    return CGPointMake(((A.x*t+B.x)*t+C.x)*t+D.x, ((A.y*t+B.y)*t+C.y)*t+D.y)
}

// TODO: - future implementation
private func tangentAngleAtT(start: CGPoint, point1: CGPoint, point2: CGPoint, end: CGPoint, t: CGFloat) -> CGFloat {

    // bezier control points
    let C0 = start
    let C1 = point1
    let C2 = point2
    let C3 = end

    // The cubic polynomial coefficients such that Bez(t) = A*t^3 + B*t^2 + C*t + D
    let A = CGPointMake(C3.x - 3.0*C2.x + 3.0*C1.x - C0.x, C3.y - 3.0*C2.y + 3.0*C1.y - C0.y)
    let B = CGPointMake(3.0*C2.x - 6.0*C1.x + 3.0*C0.x, 3.0*C2.y - 6.0*C1.y + 3.0*C0.y)
    let C = CGPointMake(3.0*C1.x - 3.0*C0.x, 3.0*C1.y - 3.0*C0.y)

    return atan2(3.0*A.y*t*t + 2.0*B.y*t + C.y, 3.0*A.x*t*t + 2.0*B.x*t + C.x)
}

}
于 2016-01-15T04:40:56.887 回答