给定一个X坐标,如何计算一个点的Y坐标,使其依赖于Bezier曲线

时间:2016-03-21 21:28:51

标签: python math 2d blender bezier

我有一个点(用粉红色圈出),它有一个已知的X坐标和一个已知的Y坐标,但Y坐标不正确。它目前停留在目标贝塞尔曲线(曲线部分为白色方块)的点上,如果它是两点之间的线。我需要为我的圆圈点计算正确的Y坐标,以便它最终在红叉上。

enter image description here

我是C#程序员,而不是数学家,所以如果这个答案可以用代码表达,或者解释方程中涉及的每个参数,那么这对我来说意义重大。如果我能得到我想要的答案,我甚至可能最终使用Python脚本扩展Blender。

更新:我已修改问题及其图片,以便更好地表达我遇到的问题。我只想找到一个方法来找出Y坐标在红十字会上是什么。考虑到这一点后,它可能是三角函数并且与贝塞尔曲线无关但我需要有一种方法可以找出放置在该曲线上任意点的标记的Y坐标,而不仅仅是第一段/第一段。

2 个答案:

答案 0 :(得分:1)

真正的数学答案:如果你想要精确的答案,你需要数学,结束;贝塞尔曲线是参数曲线,对于单个y值可以有多个x值(反之亦然),因此您不会在没有真正理解您正在做什么的情况下找到那些值

更简单的方法,不精确地说,作为编程练习,只需为每个人建立坐标 L ook U p T 曲线(例如{t=0 -> {x:...,y:...}, t=0.01 -> {x:...y:...}, ...}),然后只需在LUT中搜索给定的xy值,以找到(可能是多个)对应的y或{{1} }值。如果某些x需要y个值,请在x上对LUT进行排序,然后进行二分查找以找到最佳匹配项。如果某些x需要x,则可以对y进行排序并执行相同操作。

美好而简单。

但是,如果你想要精确的解决方案,作为一个你真正应该关心的程序员,那么你想要的是沿着"线"重新定位曲线。您正在尝试查找值(例如,"某些x&#34的所有y值;表示您正在寻找曲线与线y之间的所有交点)和然后,您只需检查在进行相交检测时获得的(x=a, y=-inf)--(x=a,y=inf)值。

如果你想在这里得到实际的真实答案,请看一下贝塞尔曲线上的这本入门书'关于intersection detection between curves and lines的部分(反过来依赖于root finding部分)。如果你正在处理三次曲线,你需要了解如何align curves,以便找到交叉点减少到找根,之后你需要运行Cardano的算法来查找您可能感兴趣的(可能是三个)值。

答案 1 :(得分:0)

贝塞尔曲线是参数化的

x(t)=fx(t)
y(t)=fy(t)

如果(x()t,y(t))指向Bezier曲线,t是参数,fx(),fy()是多项式函数。

这意味着贝塞尔曲线不一定是函数(每个y可以有多个x个值)。因此,您需要查找t所有参数x(t)=x0,其中x0是您的x - 坐标。

正如 @Mike'Pomax'Kamermans 在他的回答中提到的,你可以使用LUT或以代数方式计算fx(t)-x0=0多项式的根。

使用approximation search也有“更简单”的选项(类似于二分搜索,但也可用于非单调函数),这不需要太高的数学知识(但是粗略的速度慢)。比如像这个C ++代码:

double x0,y0;           // your point x0 valid y0 not yet
double ax0,ax1,ax2,ax3; // cubic Bezier fx() polynomial coefficients
double ay0,ay1,ay2,ay3; // cubic Bezier fy() polynomial coefficients
double ee,x,t,tt,ttt;
approx aa;
for (aa.init(0.0,1.0,0.025,6,&ee); !aa.done; aa.step()) // search t
{
  t = aa.a;
  tt = t*t;
  ttt = tt*t;
  x = ax0 + ax1*t + ax2*tt + ax3*ttt; // compute the x=fx(t)
  ee = fabs(x-x0);              // compute error of solution for the approximation search
}
// here aa.a holds found `t0`
t = aa.a;
tt = t*t;
ttt = tt*t;
y0 = ay0 + ay1*t + ay2*tt + ay3*ttt; // compute the final y0=fx(t0)

如果您需要所有可能的点,则需要递归地将搜索间隔t=<0.0,1.0>细分为<0.0,t0)(t0,1.0>,直到找不到新的解决方案。

[edit1]更多信息(Mike 'Pomax' Kamermans请求)

由于 2D贝塞尔曲线不一定是函数,单个y坐标可能会有更多x个值。就像这个例子一样:

example

编号的蓝点是渲染的 2D三次贝塞尔曲线的控制点。黄色的是具有上述递归的解决方案。这里有一些C ++示例:

double x0;              // input x coordinate
List<double> y0;        // output y coordinates

double ax0,ax1,ax2,ax3; // cubic coefficients
double ay0,ay1,ay2,ay3;
double px0,px1,px2,px3; // control points
double py0,py1,py2,py3;
//---------------------------------------------------------------------------
bool find_point(double t0,double t1,int layer)
    {
    approx aa;
    double ee,x,y,t,tt,ttt,dt;
    const double _zero=1e-4;    
    dt=0.025*(t1-t0); // approximation search step 
    if (dt<=_zero) return false; // stop if too small interval to search to avoid stack overflows
    if (layer>10) return false; // stop if too high recursion layer to avoid stack overflows (this also limits the max found solutions
    for (aa.init(t0,t1,dt,6,&ee); !aa.done; aa.step()) // search t
        {
        t  = aa.a;
        tt = t*t;
        ttt= tt*t;
        x  = ax0 + ax1*t + ax2*tt + ax3*ttt;    // compute the x=fx(t)
        ee = fabs(x-x0);                        // compute error of solution for the approximation search
        }
    // check the error of found solution
    if (aa.e0>_zero) return false;
    // here aa.aa holds found `t0`
    t  = aa.aa;
    // check bounds can cross the border a bit
    if (t<t0) return false;
    if (t>t1) return false;
    // add new solution
    tt = t*t;
    ttt= tt*t;
    y  = ay0 + ay1*t + ay2*tt + ay3*ttt;        // compute the final y0=fx(t0)
    y0.add(y);                                  // add to list of solutions
    // recursion to check for other solutions by dividing the interval by found solution
    if (t0<t-dt) find_point(t0,t-dt,layer+1);
    if (t1>t+dt) find_point(t+dt,t1,layer+1);
    }
//---------------------------------------------------------------------------
// here usage
void test()
 {
 // just compute the Bezier cubic polynomials from control points
 ax0=                              (    px0);
 ax1=                    (3.0*px1)-(3.0*px0);
 ax2=          (3.0*px2)-(6.0*px1)+(3.0*px0);
 ax3=(    px3)-(3.0*px2)+(3.0*px1)-(    px0);
 ay0=                              (    py0);
 ay1=                    (3.0*py1)-(3.0*py0);
 ay2=          (3.0*py2)-(6.0*py1)+(3.0*py0);
 ay3=(    py3)-(3.0*py2)+(3.0*py1)-(    py0);
 // Find the points from mouse x0 coordinate
 y0.num=0;              // clear found solutions list
 find_point(0.0,1.0,0); // recursively found solutions on interval t=<0,1> ,as highest recursion level 0
 }

这有垂直线的问题,因为那里有无限数量的解决方案......它只会找到其中的一小部分。否则这是安全的使用。 (添加了许多检查,因此它应该顺利运行)