【数组】求两个匀速运动质点的相交或最小距离
题目描述
两个质点初始位置,朝向角和速度分别为:(x0,y0,yaw0,v0),(x1,y1,yaw1,v1),它们在t=0时刻匀速直行运动,问它们是否会在同一时刻相交,如果不会,找出它们距离最小的时刻。相交判断距离小于1e-6,算法要求高效。
代码实现
import matheps = 1e-6def check(x0, y0, yaw0, v0, x1, y1, yaw1, v1):# 计算两个质点的速度分量v0_x = v0 * math.cos(yaw0)v0_y = v0 * math.sin(yaw0)v1_x = v1 * math.cos(yaw1)v1_y = v1 * math.sin(yaw1)# 相对速度分量(质点0相对于质点1)dv_x = v0_x - v1_xdv_y = v0_y - v1_y# 初始相对位置dx = x0 - x1dy = y0 - y1# 如果相对速度为0if dv_x == 0 and dv_y == 0:# 距离会始终不变,计算距离distance = math.sqrt(dx ** 2 + dy ** 2)return (True, 0.0) if distance < eps else (False, 0.0)# 如果相对速度不为0else:# 计算最小距离对应的时刻t_mint_min = -(dx * dv_x + dy * dv_y) / (dv_x ** 2 + dv_y ** 2)# 时刻不能为负数t_min = max(t_min, 0.0)# 计算t_min时刻的距离x0_t = x0 + v0_x * t_miny0_t = y0 + v0_y * t_minx1_t = x1 + v1_x * t_miny1_t = y1 + v1_y * t_mindistance = math.sqrt((x0_t - x1_t)**2 + (y0_t - y1_t)**2)# 判断是否相交(小于eps)is_intersect = distance < epsreturn (is_intersect, t_min)
t_min = -(dx * dv_x + dy * dv_y) / (dv_x ** 2 + dv_y ** 2)
要理解这个公式,我们需要从距离的数学表达和极值求解的角度来分析。
- 距离的平方公式
设时刻 t 时,两个质点的位置分别为:
-
质点0: (x0(t),y0(t))=(x0+v0x⋅t, y0+v0y⋅t)(x_0(t), y_0(t)) = (x_0 + v_{0x} \cdot t,\ y_0 + v_{0y} \cdot t)(x0(t),y0(t))=(x0+v0x⋅t, y0+v0y⋅t)
-
质点1: (x1(t),y1(t))=(x1+v1x⋅t, y1+v1y⋅t)(x_1(t), y_1(t)) = (x_1 + v_{1x} \cdot t,\ y_1 + v_{1y} \cdot t)(x1(t),y1(t))=(x1+v1x⋅t, y1+v1y⋅t)
两质点的距离平方为:
d2(t)=[x0(t)−x1(t)]2+[y0(t)−y1(t)]2d^2(t) = \left[ x_0(t) - x_1(t) \right]^2 + \left[ y_0(t) - y_1(t) \right]^2d2(t)=[x0(t)−x1(t)]2+[y0(t)−y1(t)]2
将位置表达式代入,展开后得到:
d2(t)=[(x0−x1)+(v0x−v1x)⋅t]2+[(y0−y1)+(v0y−v1y)⋅t]2d^2(t) = \left[ (x_0 - x_1) + (v_{0x} - v_{1x}) \cdot t \right]^2 + \left[ (y_0 - y_1) + (v_{0y} - v_{1y}) \cdot t \right]^2d2(t)=[(x0−x1)+(v0x−v1x)⋅t]2+[(y0−y1)+(v0y−v1y)⋅t]2
- 定义简化变量
为了简化推导,定义:
-
初始位置差: dx=x0−x1dx = x_0 - x_1dx=x0−x1 , dy=y0−y1dy = y_0 - y_1dy=y0−y1
-
相对速度分量: dvx=v0x−v1x,dvy=v0y−v1ydv_x = v_{0x} - v_{1x} , dv_y = v_{0y} - v_{1y}dvx=v0x−v1x,dvy=v0y−v1y
此时,距离平方可简化为:
d2(t)=(dx+dvx⋅t)2+(dy+dvy⋅t)2d^2(t) = \left( dx + dv_x \cdot t \right)^2 + \left( dy + dv_y \cdot t \right)^2d2(t)=(dx+dvx⋅t)2+(dy+dvy⋅t)2
- 求距离的最小值(极值)
距离 d(t) 是非负连续函数,且 d(t) 与 d2(t)d^2(t)d2(t) 的单调性一致(因为平方是单调递增函数)。因此,最小化 d(t) 等价于最小化 d2(t)d^2(t)d2(t) 。
对 d2(t)d^2(t)d2(t) 关于 t 求导,并令导数为0(极值点的必要条件):
步骤1:展开 d2(t)d^2(t)d2(t)
d2(t)=(dx)2+2⋅dx⋅dvx⋅t+(dvx)2⋅t2+(dy)2+2⋅dy⋅dvy⋅t+(dvy)2⋅t2d^2(t) = (dx)^2 + 2 \cdot dx \cdot dv_x \cdot t + (dv_x)^2 \cdot t^2 + (dy)^2 + 2 \cdot dy \cdot dv_y \cdot t + (dv_y)^2 \cdot t^2d2(t)=(dx)2+2⋅dx⋅dvx⋅t+(dvx)2⋅t2+(dy)2+2⋅dy⋅dvy⋅t+(dvy)2⋅t2
步骤2:求导
对 t 求导:
ddt[d2(t)]=2⋅dx⋅dvx+2⋅(dvx)2⋅t+2⋅dy⋅dvy+2⋅(dvy)2⋅t\frac{d}{dt} \left[ d^2(t) \right] = 2 \cdot dx \cdot dv_x + 2 \cdot (dv_x)^2 \cdot t + 2 \cdot dy \cdot dv_y + 2 \cdot (dv_y)^2 \cdot tdtd[d2(t)]=2⋅dx⋅dvx+2⋅(dvx)2⋅t+2⋅dy⋅dvy+2⋅(dvy)2⋅t
步骤3:令导数为0,解 t
令 ddt[d2(t)]=0\frac{d}{dt} \left[ d^2(t) \right] = 0dtd[d2(t)]=0 ,消去公因子 2 后:
dx⋅dvx+(dvx)2⋅t+dy⋅dvy+(dvy)2⋅t=0dx \cdot dv_x + (dv_x)^2 \cdot t + dy \cdot dv_y + (dv_y)^2 \cdot t = 0dx⋅dvx+(dvx)2⋅t+dy⋅dvy+(dvy)2⋅t=0
整理关于 t 的项:
t⋅[(dvx)2+(dvy)2]+(dx⋅dvx+dy⋅dvy)=0t \cdot \left[ (dv_x)^2 + (dv_y)^2 \right] + \left( dx \cdot dv_x + dy \cdot dv_y \right) = 0t⋅[(dvx)2+(dvy)2]+(dx⋅dvx+dy⋅dvy)=0
解得:
t=−dx⋅dvx+dy⋅dvy(dvx)2+(dvy)2t = -\frac{dx \cdot dv_x + dy \cdot dv_y}{(dv_x)^2 + (dv_y)^2}t=−(dvx)2+(dvy)2dx⋅dvx+dy⋅dvy
这就是最小距离对应的时刻 tmint_{\text{min}}tmin 。
- 物理意义
-
公式中的分子 dx⋅dvx+dy⋅dvydx \cdot dv_x + dy \cdot dv_ydx⋅dvx+dy⋅dvy 是初始位置差与相对速度的“点积”,反映了“位置差”与“相对速度”的对齐程度。
-
分母 (dvx)2+(dvy)2(dv_x)^2 + (dv_y)^2(dvx)2+(dvy)2 是相对速度的大小平方,保证分母非负。
当 tmin≥0t_{\text{min}} \geq 0tmin≥0 时,该时刻对应两质点距离最小的时刻;若 tmin<0t_{\text{min}} < 0tmin<0 ,则最小距离出现在 t=0 (因为质点从 t=0 开始运动,更早的时刻无意义)。
总结
公式 tmin=−dx⋅dvx+dy⋅dvy(dvx)2+(dvy)2t_{\text{min}} = -\frac{dx \cdot dv_x + dy \cdot dv_y}{(dv_x)^2 + (dv_y)^2}tmin=−(dvx)2+(dvy)2dx⋅dvx+dy⋅dvy 是通过求导找极值推导得到的,它给出了两质点距离最小时的时刻(仅考虑 t≥0t \geq 0t≥0 的情况)。