根据t计算Bézier曲线上的点

时间:2014-09-10 06:33:20

标签: c# bezier

我正在尝试创建一个看起来像这样的栏:

http://img4.hostingpics.net/pics/530160commandBar.png

这是一个包含由发光分隔符分隔的按钮的栏。那些按钮有一个非矩形的形状,所以我想“我只是放一个透明的按钮,并绘制非矩形的形状,我将使用一个路径”。

我遇到的问题是我需要根据状态(启用,禁用)为按钮着色,因此我需要每个按钮的路径来轻松更改颜色。

所以我做了一个函数来计算4个点的Bézier曲线和一个T值,它代表曲线上0到1之间的点(0是曲线的起点,1是终点,0.5是曲线中间的点。)

public static Point CalculateBezierPoint(double t, Point p1, Point p2, Point p3, Point p4) {
    Point p = new Point();
    double tPower3 = t * t * t;
    double tPower2 = t * t;
    double oneMinusT = 1 - t;
    double oneMinusTPower3 = oneMinusT * oneMinusT*oneMinusT;
    double oneMinusTPower2 = oneMinusT * oneMinusT;
    p.X = oneMinusTPower3 * p1.X + (3 * oneMinusTPower2 * t * p2.X) + (3 * oneMinusT * tPower2 * p3.X) + tPower3 * p4.X;
    p.Y = oneMinusTPower3 * p1.Y + (3 * oneMinusTPower2 * t * p2.Y) + (3 * oneMinusT * tPower2 * p3.Y) + tPower3 * p4.Y; 
    return p;
}

此功能运作良好。

所以我可以绘制曲线:

http://img4.hostingpics.net/pics/417674myCommandBar1.png

所以这很准确。除了按钮宽度不相等(它们应该由分隔符分隔)。所以我需要的是一个函数,可以在知道X轴值的情况下找到曲线上点的Y轴值。

因此知道在Bézier曲线上找到一个点的等式是:

(x坐标)

Bx(t)=(1-t)^ 3 * P1.x + 3 *(1-t)^ 2 * t * P2.X + 3 *(1-t)* t ^ 2 * P3。 X + t ^ 3 * P4.X

(y坐标)

By(t)=(1-t)^ 3 * P1.Y + 3 *(1-t)^ 2 * t * P2.Y + 3 *(1-t)* t ^ 2 * P3。 Y + t ^ 3 * P4.Y

其中:

  • Bx是曲线上点的X轴值,By是其Y轴值;
  • P1是曲线的起点
  • P2是曲线的第一个控制点
  • P3是曲线的第二个控制点
  • P4是曲线的终点
  • t是我们想要在曲线上找到的点的0到1之间的位置

我认为我可以根据t解析Bx(t)方程,因为我在运行时知道Bx,P1,P2,P3和P4,只有t是未知的。所以我想要一个看起来像这样的等式:

t = ...

这是一个好主意,直​​到我记得我在数学方面很糟糕。我尝试了许多不起作用的东西,然后尝试在Wolframalpha中输入等式,这给了我一个〜50长线方程式无法工作(here如果你想看到它()我可能在错误中重复了它。)

无论如何,我在这里寻求帮助。谢谢你的帮助

1 个答案:

答案 0 :(得分:0)

那么,如果你的曲线实际上是一个函数y = f(x),为什么不用那种方式来表示,X只是一个线性参数?

    /// <summary>
    /// Calculate a bezier height Y of a parameter in the range [start..end]
    /// </summary>
    public static double CalculateBezierHeightInInterval(double start, double end, double param, double y1, double y2, double y3, double y4)
    {
        return CalculateBezierHeight((param - start) / (end - start), y1, y2, y3, y4);
    }

    /// <summary>
    /// Calculate a bezier height Y of a parameter in the range [0..1]
    /// </summary>
    public static double CalculateBezierHeight(double t, double y1, double y2, double y3, double y4)
    {
        double tPower3 = t * t * t;
        double tPower2 = t * t;
        double oneMinusT = 1 - t;
        double oneMinusTPower3 = oneMinusT * oneMinusT * oneMinusT;
        double oneMinusTPower2 = oneMinusT * oneMinusT;
        double Y = oneMinusTPower3 * y1 + (3 * oneMinusTPower2 * t * y2) + (3 * oneMinusT * tPower2 * y3) + tPower3 * y4;
        return Y;
    }

在此公式中,您不再需要求解X,因为X是Y的输入。另一方面,假设样本高度以均匀的X间隔出现,这对您来说可能是不合适的。

如果您需要通过控制控制点的X位置来获得额外的形状控制,可以使用此处的方法:y coordinate for a given x cubic bezier