我需要找出画布中贝塞尔曲线特定点的 Y 坐标。你知道吗,怎么找出来?谢谢
5 回答
使用 de Casteljau 的算法,您可以找到任何 t、百分比或插值步长的贝塞尔曲线的坐标 x 和 y。所以 at of .1 会给你 x 和 y 从一开始就在曲线的 10% 处。0.9 的 t 从一开始就是 90%,依此类推。
在我们的三次贝塞尔曲线中,我们有 p0(点 0)、cp0(控制点 0)、cp1(控制点 1)和 p1(点 1)。
在算法的第一步,我们画一条连接 p0 和 cp0 的线,另一条连接 cp0 和 cp1 的线,还有一条连接 cp1 和 p1 的线。然后对于所有这 3 行,我们将在它们上找到从它们开始的 t % 的点。
我将要点如下:
- p0 -> cp0 = A
- cp0 -> cp1 = B
cp1 -> p1 = C
Ax = ( (1 - t) * p0x ) + (t * cp0x); Ay = ( (1 - t) * p0y ) + (t * cp0y); Bx = ( (1 - t) * cp0x ) + (t * cp1x); By = ( (1 - t) * cp0y ) + (t * cp1y); Cx = ( (1 - t) * cp1x ) + (t * p1x); Cy = ( (1 - t) * cp1y ) + (t * p1y);
第二步与第一步非常相似。首先,我们将这四个点用线连接起来,然后在它们上面找到了 3 个新点。在这一步中,我们将用线连接这 3 个点,在它们上面找到 2 个新点。我将这两个新点称为 D 和 E。
Dx = ( (1 - t) * Ax ) + (t * Bx);
Dy = ( (1 - t) * Ay ) + (t * By);
Ex = ( (1 - t) * Bx ) + (t * Cx);
Ey = ( (1 - t) * By ) + (t * Cy);
最后,我们可以将这最后两个点与另一条线连接起来,并在其上找到最后一个点,这将为我们提供该 t 的贝塞尔曲线上的点。我将此点称为 P。
Px = ( (1 - t) * Dx ) + (t * Ex);
Py = ( (1 - t) * Dy ) + (t * Ey);
好了,我们现在有了贝塞尔曲线上一个点的 x 和 y 坐标,该点距离开始时间为 t%。我会尽快添加一些图片。
剪切并粘贴准备好的答案:
// Points are objects with x and y properties
// p0: start point
// p1: handle of start point
// p2: handle of end point
// p3: end point
// t: progression along curve 0..1
// returns an object containing x and y values for the given t
BezierCubicXY = function(p0, p1, p2, p3, t) {
var ret = {};
var coords = ['x', 'y'];
var i, k;
for (i in coords) {
k = coords[i];
ret[k] = Math.pow(1 - t, 3) * p0[k] + 3 * Math.pow(1 - t, 2) * t * p1[k] + 3 * (1 - t) * Math.pow(t, 2) * p2[k] + Math.pow(t, 3) * p3[k];
}
return ret;
}
我一直在试图找出同样的东西,我想我至少解决了方形贝塞尔曲线,这是只有一个控制点的贝塞尔曲线。
数学解释
方形贝塞尔曲线的数学公式是:
其中“X”是结果,“A”是起点位置,“B”是控制点,“C”是终点。
't' 是一个介于 0 和 1 之间的数字,表示您要计算线上的哪个点。0 代表起点,1 代表终点,0.5 代表曲线的中心。
该函数用于计算线上一个点的 X 和 Y 坐标。如果要计算 X,只需填写 A、B 和 C 点的 X 坐标。
现在为了确定属于 X 的 Y,我们需要确定所述 X 坐标的“t”。
我们可以将相同的贝塞尔方程写成二次形式 ( ):
这使我们能够使用二次公式来推导求解方程的“t”值。二次公式实际上是2个公式。
和
结果公式为:
和
代码解决方案
我们可以在代码中将其描述为:
GetYValues(StartPoint, ControlPoint, EndPoint, X)
{
Ax = StartPoint.X
Bx = ControlPoint.X
Cx = EndPoint.X
q1 = 2*Ax - 2*Bx;
q2 = Sqrt(5*Ax*Ax - 10*Ax*Bx + Ax*Cx - Ax*X + 2*Bx*X + 4*Bx*Bx)
q3 = 2*Ax - 4*Bx + 2*Cx
t1 = (q1 + q2) / q3
t2 = (q1 - q2) / q3
Ay = StartPoint.Y
By = ControlPoint.Y
Cy = EndPoint.Y
Y1 = Ay*(1-t1)*(1-t1) + By*2*(1-t1)*t1 + Cy*t1
Y2 = Ay*(1-t2)*(1-t2) + By*2*(1-t2)*t2 + Cy*t2
return [Y1,Y2]
}
现在,我还没有对此进行测试,并且该函数不会检查实际上是否有任何有效点,因此肯定会有一些值会引发异常。请务必检查“除以 0”和“小于 0 的数字的平方根”。
此解决方案的问题
这个方程的一个大问题是它只适用于方形贝塞尔曲线,而大多数贝塞尔曲线实际上是三次方的。我试图找到一种类似的方法来解决这个问题的三次版本,不幸的是,这要困难一个数量级。我能找到的用于求解三次方程的唯一公式可以在这里找到Cubic function。这个公式包含虚数,我不知道如何处理这些。
另一个问题是,对于有 4 个或更多控制点的贝塞尔曲线,根本没有办法求解方程。
结论
最后,您最好的选择是将贝塞尔曲线简单地转换为直线,这非常容易计算。
@DerekR:尽管您在此处介绍的内容很清楚,并且可能对许多人有所帮助,但我认为您自己和 immo 的答案以及以下所有评论都没有解决问题。
(我的数学很糟糕,我一直在尝试解决同样的问题,所以我可能无法理解后续评论。)
我认为问题是:知道两个端点和两个控制点的X,Y坐标,并假设范围是0到1,那么给定Y,Y是多少?
我是新手,还不能发布图片,但你可以在duck.cc/images/beziercurve_findY.png 看到曲线
圆的等式是: (xh)^2 + (yk)^2 = r^2 其中 h,k 是中心的 x,y 坐标。所以 y 的等式是 y = sqrt(r^2 - (xh)^2) + k 。Math.sqrt(..)
大多数语言都带有一个数学包,所以我假设你可以做一些Math.pow(..)
如果我的数学不正确,任何人都可以纠正我。