检查鼠标是否在贝塞尔曲线上方

时间:2018-09-07 03:52:08

标签: c# math bezier

我的方法是使曲线穿过曲线并检查鼠标到各个点的距离

但是随着曲线的变陡,这些点之间的距离越来越近,如果鼠标距离阈值过高,则会优先考虑循环中的第一个点,而不是鼠标的壁橱。

有没有办法得到统一的分数?还是要检查鼠标是否在贝塞尔曲线上方并获取其位置?

2 个答案:

答案 0 :(得分:1)

有两种主要方法-将曲线细分为小线段和分析解决方案。

对于第二种情况,您必须根据参数t建立从点到曲线的平方距离的多项式,对其进行微分,然后找到结果的零(5阶多项式)。然后从距离中选择最小值,以指向t[i], t=0, t=1。 另一个角度-获取点到曲线上的投影,因此该点的曲线切线垂直于矢量点-曲线点,因此应给出相同的表达式。

enter image description here

关于均匀点-这是一个相当棘手的问题,因为无法通过分析来计算曲线长度。但是细分给出了很好的近似值。

答案 1 :(得分:1)

我这样做是这样的:

  1. 将您弯曲成几个块

    块的数量取决于曲线的顺序。由于我通常使用三次,因此我凭经验发现〜8个块就足够了(出于我的目的)。

  2. 计算与块的最接近点

    因此,只需将每个块作为线进行处理,并计算该线上与鼠标位置最近的点(最小垂直距离)。通过为每个块计算并记住最接近的块。

    chunks

    现在,在此之后,我们知道哪个块包含“最接近”的点,因此从直线和垂直线之间的交点到上一步中通过鼠标位置的点,我们应该有一个参数u=<0,1>来告诉我们块上的位置线最接近的点是,并且我们还知道块线(t)的两个端点的曲线参数t0,t1。通过执行以下操作,我们可以从中近似t到最接近的点:

    t = t0 + (t1-t0)*u
    

    在图像t0=0.25t1=0.375上。有时这足够了,但是如果您想要更好的解决方案,那么在此之后进行设置即可:

    dt = (t1-t0)/4
    t0 = t-dt
    t1 = t+dt
    

    使用t0,t,t1计算2个块的3个端点,然后再次寻找最接近的点。您可以递归执行几次,因为每次迭代都会提高结果的精度

    increase accuracy

点到直线的垂直距离是通过计算直线和穿过该点的垂直于其的轴之间的交点来计算的。因此,如果该线是由端点p0,p1定义的,并且查询点(鼠标)是q,则2D轴将是:

dp=p1-p0        // line direction
dq=(dp.y,-dp.x) // axis direction is perpendicular to dp
dq/= |dq|       // normalize
p(u) = p0+dp*u  // point on line
p(v) = q +dq*v  // point on axis
u = <0,1>       // parameter on line
v = <-inf,+inf> // parameter on axis

我们想知道u,v

p0+dp*u = q +dq*v

是2D中2个线性方程的系统。在3D中,您需要利用叉积来获得dq,并且系统将包含3个方程式。解决该系统将为您提供u,v,其中u会告诉您最接近点在块中的哪个位置,而|v|则是垂直距离本身。不要忘记,如果u不在<0,1>范围内,则必须使用直线的更近端点作为最接近点。

该系统既可以代数求解(但请注意边缘情况,因为2D方程有2个解)或使用逆矩阵...