我是这样做的:
-
将曲线细分为几块
块的数量取决于曲线的顺序。由于我通常使用立方体,我凭经验发现大约 8 个块就足够了(就我的目的而言)。
-
计算离块最近的点
因此,只需将每个块作为线处理,并计算线上到鼠标位置的最近点(最小垂直距离)。通过为每个块计算它并记住最接近的一个。
现在我们知道哪个块包含“最近”点,所以从直线和垂直线的交点到上一步的鼠标位置,我们应该有一个参数 u=<0,1> 告诉我们块线上的位置最近的点是并且我们也知道块线(t0,t1)两个端点的曲线参数t。从这里我们可以简单地通过这样做来近似t为最近的点:
t = t0 + (t1-t0)*u
在图像t0=0.25 和t1=0.375 上。这有时就足够了,但如果您想要更好的解决方案,那么在此设置之后:
dt = (t1-t0)/4
t0 = t-dt
t1 = t+dt
使用t0,t,t1 计算 2 个块的 3 个端点并再次寻找最近的点。您可以递归执行几次,因为每次迭代都会提高结果的精度
点到线的垂直距离是通过计算线和垂直于它的轴之间的交点来计算的。因此,如果线由端点p0,p1 定义,查询点(鼠标)是q,那么二维坐标轴将是:
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
这是二维中的 2 个线性方程组。在 3D 中,您需要利用叉积来获得 dq,系统将包含 3 个方程。解决这个系统会给你u,v,其中u会告诉你块中最近的点在哪里,|v|是垂直距离本身。不要忘记,如果u 不在<0,1> 范围内,则必须使用线的更近端点作为最近点。
系统可以通过代数求解(但要注意极端情况,因为二维方程有 2 个解)或使用逆矩阵...