【问题标题】:Finding Y given X on a Cubic Bezier Curve?在三次贝塞尔曲线上找到给定 X 的 Y?
【发布时间】:2012-07-03 00:21:47
【问题描述】:

我需要一种方法,在给定 x 坐标的情况下,我可以在三次贝塞尔曲线上找到 Y 坐标。

我遇到很多地方告诉我将其视为三次函数,然后尝试找到根,我理解。然而,三次贝塞尔曲线的方程是(对于 x 坐标):

X(t) = (1-t)^3 * X0 + 3*(1-t)^2 * t * X1 + 3*(1-t) * t^2 * X2 + t^3 * X3

让我感到困惑的是 (1-t) 值的添加。例如,如果我用一些随机数填充 X 值:

400 = (1-t)^3 * 100 + 3*(1-t)^2 * t * 600 + 3*(1-t) * t^2 * 800 + t^3 * 800

然后重新排列:

800t^3 + 3*(1-t)*800t^2 + 3*(1-t)^2*600t + (1-t)^3*100 -400 = 0

我仍然不知道(1-t) 系数的值。当(1-t) 仍然未知时,我应该如何解方程?

【问题讨论】:

  • 更多一道数学题...
  • 很好,我去问问数学部的人。我认为它被用于计算意味着这里的人可能知道。谢谢。
  • 即使在 2018 年,这个问题仍然出现得足够多,仍然需要一个真正的答案,所以我在stackoverflow.com/a/51883347/740553 上编写了用于获得符号解决方案的代码,第二个答案给出了不精确的答案(但通常足够好)二分搜索解决方案。

标签: c++ bezier curve cubic


【解决方案1】:

三次贝塞尔曲线有三种常用的表达方式。

第一个 x 作为 t 的函数

x(t) = sum( f_i(t) a_i )
     = (1-t)^3 * x0 + 3*(1-t)^2 * t * x1 + 3*(1-t) * t^2 * x2 + t^3 * x3

其次,y 是 x 的函数

y(x) = sum( f_i(x) a_i )
     = (1-x)^3 * y0 + 3*(1-x)^2 * x * y1 + 3*(1-x) * x^2 * y2 + x^3 * y3

前两个在数学上是相同的,只是对变量使用了不同的名称。

根据您的描述“在三次贝塞尔曲线上找到 Y 坐标,并在其上给出 x 坐标。”我猜你有一个使用第二个方程的问题正在尝试重新排列第一个方程来帮助你解决它,而你应该使用第二个方程。如果是这种情况,则无需重新排列或求解 - 只需插入 x 值即可获得解决方案。

你可能有第三种情况的方程,这是丑陋和困难的情况。 这是 x 和 y 参数都是第三个变量 t 的三次贝塞尔曲线。

x(t) = sum( f_i(t) x_i )
y(t) = sum( f_i(t) y_i )

如果这是你的情况。告诉我,我可以详细说明您需要做些什么来解决它。

【讨论】:

  • 你能帮我解决参数化的版本吗?我有参数化的xy。我需要y 给定x。所以我不知道t,但知道x
  • @activatedGeek - 你不一定能解决你的问题。可能没有解决方案,一个解决方案,许多解决方案,甚至无限多个解决方案(悲伤)。最好的办法是注意贝塞尔曲线保证落在其控制点的凸包内。然后考虑每个段 CVH 是否可以跨越你的 x 值,如果它确实将它保存在一个列表中,如果它没有 - 忘记它。现在在每个段上应用贝塞尔中点分割以获得贝塞尔段的新列表。重复丢弃和拆分,直到所有段都足够“小”。它们是您的解决方案。
  • 好的,我会直奔源头。你能告诉我this 是如何工作的吗?我了解曲线是如何绘制在左侧的。我不明白的是,如何将动画时间转换为映射Bezier curvet 参数以覆盖某些T seconds 中的动画。
  • 如果未来的访问者找到这个答案,对于单调递增的曲线(“看起来像正常函数的曲线,而不是真正的垂直/水平切线,或者在自身上弯曲'返回')有一个象征性的解决方案,在stackoverflow.com/a/51883347/740553 上进行了解释 - 这涵盖了很多用例,例如 CSS 动画、参数 EQ 等。
【解决方案2】:

我认为这是一个公平的 CS 问题,所以我将尝试展示我是如何解决这个问题的。请注意,给定的 x 可能有超过 1 个相关联的 y 值。在我需要这个的情况下,保证不会出现这种情况,所以你必须弄清楚如何确定你想要哪一个。

我对 t 进行了迭代,生成了一个由 x 和 y 值组成的数组。为了我的目的,我以相当高的分辨率完成了它。 (我希望生成一个 8 位查找表,所以我使用了大约 1000 个点。)我只是将 t 插入贝塞尔方程中,以便将下一个 x 和下一个 y 坐标存储在数组中。一旦我生成了整个东西,我就扫描了数组以找到 2 个最接近的 x 值。 (或者如果有完全匹配,使用它。)然后我对那个非常小的线段进行线性插值以获得我需要的 y 值。

【讨论】:

    【解决方案3】:

    进一步开发表达式应该可以让您摆脱(1 - t) 因素

    如果你运行:

    expand(800*t^3 + 3*(1-t)*800*t^2 + 3*(1-t)^2*600*t + (1-t)^3*100 -400 = 0);
    

    wxMaximaMaple 中(您必须在此添加参数t),您会得到:

    100*t^3 - 900*t^2 + 1500*t - 300 = 0
    

    求解t的新三次方程(你可以使用the cubic equation formula),得到t后,你可以找到x在做:

    x = (x4 - x0) * t      (asuming x4 > x0) 
    

    【讨论】:

      【解决方案4】:

      贝塞尔曲线方程(获取x值):

      Bx = (-t^3 + 3*t^2 - 3*t + 1) * P0x + 
           (3*t^3 - 6*t^2 + 3*t) * P1x + 
           (-3*t^3 + 3*t^2) * P2x + 
           (t^3) * P3x
      

      以t的三次方形式重新排列

      0  = (-P0x + 3*P1x - 3*P2x + P3x) * t^3+ 
           (3*P0x - 6*P1x + 3*P2x) * t^2 + 
           (-3*P0x + 3*P1x) * t + 
           (P0x) * P3x - Bx
      

      使用三次公式求解此问题以找到 t 的值。 t 可能有多个实际值(如果您的曲线两次穿过相同的 x 点)。就我而言,我正在处理一种情况,即任何 x 值都只有一个 y 值。所以我能够将唯一的实根作为 t 的值。

      a = -P0x + 3.0 * P1x - 3.0 * P2x + P3x;
      b = 3.0 * P0x - 6.0 * P1x + 3.0 * P2x;
      c = -3.0 * P0x + 3.0 * P1x;
      d = P0x;
      t = CubicFormula(a, b, c, d);
      

      接下来将 t 的值放回 y 的贝塞尔曲线中

      By = (1-t)^3 * P0x + 
           3t(1-t)^2 * P1x + 
           3t^2(1-t) * P2x + 
           t^3 * P3x
      

      【讨论】:

      • “使用三次方程解决这个问题”是 maths.stackexchange 的好答案,但对于 Stackoverflow C++ 问题的答案却很糟糕。没有代码来显示三次公式的实现,这是一个不完整的答案。
      • 立方形式的最后一项应该是“(P0x) - Bx”而不是“(P0x) * P3x - Bx”吗? d 的公式是“P0x - Bx”而不仅仅是“P0x”?
      【解决方案5】:

      所以我一直在寻找某种方法,让我可以找到三次贝塞尔曲线上的 Y 坐标,给定一个 x 坐标。

      考虑点 (0, 0) 和 (0, 100) 之间的三次贝塞尔曲线,控制点位于 (0, 33) 和 (0, 66)。对于给定的 X,那里有无限数量的 Y。因此,在给定 X 的情况下,没有任何方程可以求解任意三次贝塞尔曲线的 Y。

      对于强大的解决方案,您可能希望从 De Casteljau's algorithm 开始

      递归地分割曲线,直到各个线段接近一条直线。然后,您可以检测这些不同的线段是否以及在何处与您的 x 相交,或者它们是否是 x 对应于您正在寻找的 x 的垂直线段(我上面的示例)。

      【讨论】:

      • 但是请记住,仅仅因为没有通用的解决方案,并不意味着没有适用于所有情况的解决方案。如果曲线是可逆的,那么肯定有解,这个问题的答案在stackoverflow.com/a/51883347/740553中讨论
      猜你喜欢
      • 1970-01-01
      • 2011-03-10
      • 2012-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-05
      • 2012-01-19
      相关资源
      最近更新 更多