问题描述
编辑:我刚刚将控制点更改为交叉点。这就是它不再适合的原因。
我知道这是非常冒昧的。但我正在开发一个 Web 应用程序,我需要计算与二次贝塞尔曲线和直线的交点。
- 线性贝塞尔曲线:
P=s(W-V)+V
- 二次贝塞尔曲线:
P=t²(A-2B+C)+t(-2A+2B)+A
因为 W
、V
、A
、B
和 C
是点,所以我可以做两个等式。我重新排列第一个方程来分离 s 来求解方程。
我很确定我做对了,但我的交叉点不在这条线上。所以我想知道并通过正确的公式制作了我自己的二次贝塞尔曲线,我的交点达到了这条曲线。现在我想知道我做错了什么?
那是我的职责:
intersectsWithLineAtT(linestartPoint,lineEndPoint)
{
let result = []
let A = this.startPoint,B = this.controlPoint,C = this.endPoint,V = linestartPoint,W = lineEndPoint
if (!Common.isLineIntersectingLine(A,B,V,W)
&& !Common.isLineIntersectingLine(B,C,W)
&& !Common.isLineIntersectingLine(A,W))
return null
let alpha = Point.add(Point.subtract(A,Point.multiply(B,2)),C)
let beta = Point.add(Point.multiply(A,-2),2))
let gamma = A
let delta = V
let epsilon = Point.subtract(W,V)
let a = alpha.x * (epsilon.y / epsilon.x) - alpha.y
let b = beta.x * (epsilon.y / epsilon.x) - beta.y
let c = (gamma.x - delta.x) * (epsilon.y / epsilon.x) - gamma.y + delta.y
let underSquareRoot = b * b - 4 * a * c
if (Common.compareFloats(0,underSquareRoot))
result.push(-b / 2 * a)
else if (underSquareRoot > 0)
{
result.push((-b + Math.sqrt(underSquareRoot)) / (2 * a))
result.push((-b - Math.sqrt(underSquareRoot)) / (2 * a))
}
result = result.filter((t) =>
{
return (t >= 0 && t <= 1)
})
return result.length > 0 ? result : null
}
希望有人能帮助我。
莉娜
解决方法
曲线/直线相交问题与求根问题相同,在我们旋转所有坐标以使直线位于 x 轴的顶部之后:
其中涉及一个涉及 atan2 的快速技巧:
const d = W.minus(V);
const angle = -atan2(d.y,d.x);
const rotated = [A,B,C].map(p => p.minus(V).rotate(angle));
假设您正在使用理解向量运算的点类。如果没有,使用标准 {x,y}
对象很容易做到:
const rotated = [A,C].map(p => {
p.x -= V.x;
p.y -= V.y;
return {
x: p.x * cos(a) - p.y * sin(a),y: p.x * sin(a) + p.y * cos(a)
};
});
然后我们需要找出哪些 t
值产生 y=0
,这(正如您也使用过的)只是应用二次公式。而且我们不需要为折叠维度而烦恼:我们已经将问题简化为仅在 y
维度中寻找解决方案,因此采用
const a = rotated[0].y;
const b = rotated[1].y;
const c = rotated[2].y;
并将其与我们知道 Py = t²(a-b+c)+t(-2a+2b)+a
的事实相结合,我们只是通过通常检查负、零和正判别式以及检查除以零来计算出 t = -b/2a +/- sqrt(b² - 4ac))/2a
。
这为我们旋转情况下的 y=0 截距以及未旋转情况下曲线和直线之间的交点提供了零个或多个 t
值。不需要额外的计算。当然,除了“评估 B(t) 以获得实际的 (x,y) 坐标”。