第四节:对角线距离——八方向移动下的精确距离计算,如何避免高估代价

聊完曼哈顿距离和欧氏距离,咱们来看看实际项目中最常用的一个——对角线距离

说白了,它就是专门为八方向移动设计的。你想想看,在栅格地图上,机器人既能上下左右走,也能斜着走。这时候再用曼哈顿距离,代价就估高了。为什么?因为斜着走一步,实际距离只有√2,但曼哈顿距离算出来是2。这一来一回,差距就出来了。

4.1 对角线距离的数学定义

先看公式。假设起点是 (x1, y1),终点是 (x2, y2):

dx = |x1 - x2|
dy = |y1 - y2|

对角线距离 = min(dx, dy) * √2 + |dx - dy|

这个公式怎么理解?
我习惯这么想:先尽可能走斜线,走到不能再斜了,剩下的直线部分就直着走。

  • min(dx, dy):能走斜线的步数
  • √2:斜线一步的实际代价
  • |dx - dy|:剩下的直线步数,代价为1

举个例子。起点 (0,0),终点 (5,3)。
dx=5,dy=3。
min=3,所以先走3步斜线,代价 3*1.414 ≈ 4.242。
剩下 |5-3|=2 步直线,代价 2*1 = 2。
总代价 ≈ 6.242。

这个值比曼哈顿距离(5+3=8)小,比欧氏距离(√34≈5.83)大。很合理,对吧?

4.2 为什么曼哈顿距离会高估代价

我在项目中遇到过好几次这样的问题。一开始用曼哈顿距离做A*,结果发现机器人明明可以斜着走,但路径规划出来的路线却绕来绕去。

原因很简单:曼哈顿距离高估了实际代价

你想想看,从 (0,0) 到 (3,3),曼哈顿距离是6。但实际走对角线,只需要3步,代价约4.242。差了将近2个点。

高估代价会带来什么后果?

  • A* 算法会倾向于探索更多节点,因为启发式函数不够紧
  • 搜索空间变大,计算时间变长
  • 严重时,可能找不到最优路径
注意: 如果启发式函数高估了实际代价,A* 就不再保证找到最优解了。这是理论上的硬伤。

4.3 如何避免高估代价——我的调优经验

嗯,这里要注意。对角线距离本身已经比曼哈顿距离精确了,但还不够。为什么?因为实际移动中,斜线移动的代价可能不是严格的√2。

我遇到过的情况是这样的:

有一次做仓储机器人项目,地面是环氧树脂,摩擦力比较小。机器人斜着走的时候,轮子打滑,实际走的距离比理论值多了5%。这时候如果用严格的√2,代价还是低估了。

所以我的建议是:

  1. 先用理论值 √2:大部分场景下够用
  2. 实测修正:让机器人实际跑一下,记录斜线移动的真实代价
  3. 微调系数:比如把 √2 改成 1.45 或 1.5,看效果
小技巧: 我习惯把斜线代价设成 1.414,然后乘以一个修正因子 k。k 的初始值是1.0,实测后根据误差调整。这样代码改动最小。

4.4 代码实现

直接上代码。这是我项目里用的一段,稍微简化了一下:

# 对角线距离计算
def diagonal_distance(start, goal):
    dx = abs(start[0] - goal[0])
    dy = abs(start[1] - goal[1])
    
    # 斜线代价,可调参数
    D = 1.0          # 直线代价
    D2 = 1.414       # 斜线代价,理论值
    
    # 核心公式
    return D * (dx + dy) + (D2 - 2 * D) * min(dx, dy)

# 或者更直观的写法
def diagonal_distance_v2(start, goal):
    dx = abs(start[0] - goal[0])
    dy = abs(start[1] - goal[1])
    
    # 先走斜线
    diagonal_steps = min(dx, dy)
    # 再走直线
    straight_steps = abs(dx - dy)
    
    return diagonal_steps * 1.414 + straight_steps * 1.0

我个人习惯用第一种写法,因为调参方便。把 D 和 D2 抽出来,改一个地方就行。

4.5 什么时候用对角线距离

场景 推荐距离 原因
四方向移动(上下左右) 曼哈顿距离 不能斜走,曼哈顿就是精确的
八方向移动(可斜走) 对角线距离 精确匹配移动能力
任意方向移动 欧氏距离 没有方向限制,欧氏最准
有障碍物的复杂环境 对角线距离 + 障碍物惩罚 需要额外处理

4.6 避坑指南

我曾经踩过一个坑,分享给你:

有一次做AGV调度,地图是网格化的,但机器人实际移动是连续的。我用对角线距离做A*,结果路径规划出来全是锯齿状的。为什么?因为对角线距离假设机器人可以完美走斜线,但实际场地里,斜线路径上可能有障碍物,机器人只能走折线。

后来我加了一个路径平滑的后处理步骤,才解决了这个问题。

核心要点:
  • 对角线距离适合八方向移动,比曼哈顿更精确
  • 公式:min(dx,dy)*√2 + |dx-dy|
  • 实际项目中,斜线代价可能需要微调
  • 高估代价会导致A*搜索效率下降,甚至找不到最优解
  • 别忘了路径平滑——对角线距离规划出来的路径可能不够顺

最后说一句。对角线距离不是万能的。如果你的机器人是差速轮,可以任意方向移动,那直接用欧氏距离就行。但如果是四轮车、履带车,或者有方向限制的机器人,对角线距离就是你的最佳选择。

下一节,咱们聊聊欧氏距离的陷阱——为什么它有时候会低估代价,以及怎么处理。