【问题标题】:Calculate point on a Bézier curve according to t根据 t 计算贝塞尔曲线上的点
【发布时间】:2014-09-10 06:33:20
【问题描述】:

我正在尝试创建一个如下所示的栏:


(来源:hostingpics.net

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

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

所以我做了一个函数来计算 4 个点的贝塞尔曲线和一个 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;
}

此功能运行良好。

这样我就可以画出曲线了:


(来源:hostingpics.net

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

所以知道在贝塞尔曲线上找到一个点的方程是:

(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 如果你想看的话)(我可能在函数中重新复制它时出错了)。

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

【问题讨论】:

  • 你的曲线真的是二维曲线,还是函数 y=f(x)? IE。曲线能否自行循环?
  • @dbc 曲线永远不会循环回来(它是图像中的形状,它可能会弯曲但永远不会改变它的形状)

标签: c# bezier


【解决方案1】:

好吧,如果你的曲线真的是一个函数 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

【讨论】:

  • @user3564358 - 我的简化方法使您对曲线形状的控制较少,但您仍然有一些控制权 - 这可能足以满足您的目的。如果没有,您可以使用链接中建议的二进制搜索方法。
  • 别在意我的想法:效果很好! img4.hostingpics.net/pics/424171myCommandBar3.png 非常感谢,我为此浪费了很多时间。
猜你喜欢
  • 2011-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-26
  • 2016-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多