如何在画布中找出贝塞尔曲线中特定点的Y坐标?

时间:2013-01-05 17:13:51

标签: canvas point bezier curve coordinate

我需要在画布中找出贝塞尔曲线特定点的Y坐标。你知道吗,如何找到它?谢谢

5 个答案:

答案 0 :(得分:29)

使用de Casteljau算法,您可以找到任何t,百分比或插值步长的贝塞尔曲线的坐标x和y。所以.1的t会给你从开头起10%曲线的x和y。 .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%。我很快就会添加一些图片。

enter image description here

答案 1 :(得分:6)

剪切并粘贴准备好的答案:

// 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;
}

答案 2 :(得分:2)

我一直试图想出同样的事情,我认为我解决了它至少对于方形贝塞尔曲线,它只是一个控制点的贝塞尔曲线。

数学解释

方形贝塞尔曲线的数学公式为:

其中'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个或更多控制点的贝塞尔曲线,根本无法求解该等式。

<强>结论

最后,最好的办法是简单地将贝塞尔曲线转换为直线,这样可以更容易地计算出来。

答案 3 :(得分:1)

圆的等式是: (x-h)^ 2 +(y-k)^ 2 = r ^ 2其中h,k是中心的x,y坐标。因此y的等式将是y = sqrt(r ^ 2 - (x-h)^ 2)+ k。大多数语言都带有Math包,所以我假设你可以做某种Math.sqrt(..)Math.pow(..)

如果我的数学已关闭,任何人都会纠正我。

答案 4 :(得分:0)

@DerekR:虽然你在这里介绍的内容很清楚,可能对很多人有帮助,但我认为答案以及你自己和immo的所有以下评论都没有解决问题。

(我的数学很糟糕,我一直试图解决同样的问题,所以我可能不理解后续评论。)

我认为问题是: 知道两个端点和两个控制点的X,Y坐标,假设范围是0到1,那么给定Y,Y是什么?

我是新手,无法发布图片,但您可以在duck.cc/images/beziercurve_findY.png看到曲线