### Bezier曲线上的等距点

#### 3 个答案:

P_0和P_3之间的距离（立方体形式），是的，但我想你知道，这是直截了当的。

``````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)
}

}
``````