实战|JPS跳点寻路实现运行路径规划

学更好的别人,

做更好的自己。

——《微卡智享》

本文长度为3087,预计阅读8分钟

前言

上两篇我们主要就是说了A*算法结合OpenCV进行室内地图路线规划,在具体使用过程中发现,遇到比较复杂的地形路线后,计算的时间太长了,经过了一些基础的优化(最近开始学习算法了)后,还是不足以使用到生产环境中,所以就有了今天这篇JPS的跳点算法。

format,png

实现效果

imgconvert.csdnimg.cn

上次A*算法用的是红色的线标的路线,这次JPS算法改为用蓝色的线标记,后续我会再写一篇两个算法的对比。

JPS算法

format,png

微卡智享

想了解JPS算法,最好是先明白了A*算法的整体思路,因为JPS算法实际上也是对A*算法一个改进,在A*算法中,每移动一次都会去计算周围八个邻居点的数据,这样我们的OpenList(开启列表)中的数量就会很多,然后每次都要从开启列表中找最近的点,所以搜索的效率会很慢。

而JPS的算法,是通过寻找跳点的方式,在过程中排除大量不感兴趣的点,这样就减少了我们OpenList(开启列表)中搜索的数量,大大地提高了搜索的速度,但是由于一部分点都用一个点来表示 . 路径表现上会感觉出寻路出的点 并不是最优路径。不过我觉得这个倒没有太大问题,因为速度快嘛。

format,png

直线运动

JPS算法中,当我们走直线运动时,只要直线上一直畅通无阻,那我们就直接忽略别的点不去计算,行动的规则如下图中灰色的格式就是我们可以一直忽略的点。

format,png

斜线运动

而在斜线运动中,我们可以直接忽略侧后方的点,如下图中灰色的是我们可以忽略的点。

format,png

强迫邻居

上面两个是JPS的一个行动的规则,但是在实际行动中,往往不可能是一条线走到底的情况,所以又引入了一个新的概念--强迫邻居。

直线运动的强迫邻居

当走直线运动的时候,我们需要判断一下行动方式左右两边是不是障碍点,如果是的话则这个点即为强迫邻居,并且这个强强迫邻居点的前方的点可要做为进行计算的点,而我们现在的当前点即可成为一个跳点加入到OpenList中,如下图中绿色点行动方向的左边黑点是障碍点,则紫色点可以列入到可进行计算的点中,而我们当前的绿色点即是跳点。

format,png

斜线运动的强迫邻居

斜线运动的时我们要判断行走方向的侧后方两个点是否为障碍点,如果是障碍点,则障碍点前方的点也要列入到可计算的点中,同时我们的当前点计为跳点,如下图中绿色点往右上行动,侧后方(左后方)黑色点为障碍点,则我们的紫色的点就要列入可计算的点中,而当前的绿色点即设置为跳点。

format,png

只要牢记住上面两种情况,我们就可以从中计算出跳点来加入到OpenList(开启列表)中即可。

计算流程方式(原贴:https://zhuanlan.zhihu.com/p/25093275)

format,png

format,png

 

核心代码

format,png

微卡智享

因为这个公司产品中需要,所以JPS我就不列表所有的代码了,其实从上面的流程里可以看到,JPS算法中最麻烦的就是跳点的计算了,所以我这里把计算跳点的函数列出来,别的相对来说我觉得都能写的出来。

//计算跳跃点,参数一:当前点,参数二:前一个点
Point JPSCalc::checkJumpPoint(Point targetpt, Point prept)
{
  //计算前一点到当前点的行动路径,x和y都不等于0说明是斜线走的
  //x=0说明是纵向移动,y=0说明是横向移动
  Point dir = targetpt - prept;
  //设置临时变量,如果没有跳跃点返回-1,-1代码跳出地图了
  Point tmp = Point(-1, -1);


  //检测当前点在地图中是否允许行动,如果当前点是障碍点直接返回tmp跳出
  if (isInSites(targetpt.x, targetpt.y)) {
    return tmp;
  }
  //如果是终点,直接返回当前点
  if (targetpt.x == finalpoint.x && targetpt.y == finalpoint.y) {
    return targetpt;
  }


  //1.检测当前点是否有强迫邻居,如果存在就返回当前点为跳跃点
  //1.1判断是斜线移动
  if (dir.x != 0 && dir.y != 0) {
    if ((!isInSites(targetpt.x - dir.x, targetpt.y + dir.y)
      && isInSites(targetpt.x - dir.x, targetpt.y))
      || (!isInSites(targetpt.x + dir.x, targetpt.y - dir.y)
        && isInSites(targetpt.x, targetpt.y - dir.y))) {
      //cout << "斜线强迫邻居:" << targetpt.x << "," << targetpt.y << endl;
      return targetpt;
    }


  }
  //1.2判断直线移动
  else {
    //1.2.1判断是横向移动
    if (dir.x != 0) {
      if ((!isInSites(targetpt.x + dir.x, targetpt.y + 1)
        && isInSites(targetpt.x, targetpt.y + 1))
        || (!isInSites(targetpt.x + dir.x, targetpt.y - 1)
          && isInSites(targetpt.x, targetpt.y - 1)))
      {
        //cout << "横向直线强迫邻居:" << targetpt.x << "," << targetpt.y << endl;
        return targetpt;
      }


    }
    //1.2.2判断是纵向移动
    else {
      if ((!isInSites(targetpt.x - 1, targetpt.y + dir.y)
        && isInSites(targetpt.x - 1, targetpt.y))
        || (!isInSites(targetpt.x + 1, targetpt.y + dir.y)
          && isInSites(targetpt.x + 1, targetpt.y))) {
        //cout << "纵向直线强迫邻居:" << targetpt.x << "," << targetpt.y << endl;
        return targetpt;
      }


    }
  }


  //2.不存在强迫邻居按行动路径继续寻找跳跃点
  //2.1 判断是斜线移动,先按水平方向查找
  if (dir.x != 0 && dir.y != 0) {
    //2.1.1按水平方向继续寻找跳跃点
    tmp = checkJumpPoint(Point(targetpt.x + dir.x, targetpt.y), targetpt);
    //2.2.2再增加一个垂直方向跟踪的跳跃点进行判断
    Point tmp2 = checkJumpPoint(Point(targetpt.x, targetpt.y + dir.y), targetpt);
    //只有返回的两个点判断x不是-1,说明能找到跳跃点,这样就返回当前点
    if (tmp.x != -1 || tmp2.x != -1) return targetpt;
  }
  //2.2 判断水平方向是否可移动,如果可以按原来轨迹方向继续寻找
  if (!isInSites(targetpt.x + dir.x, targetpt.y)
    || !isInSites(targetpt.x, targetpt.y + dir.y))
  {
    tmp = checkJumpPoint(Point(targetpt.x + dir.x, targetpt.y + dir.y), targetpt);
    if (tmp.x != -1) return tmp;
  }


  //最后返回tmp
  return tmp;
}


运行图片

format,png

下一篇我们就看看A*算法和JPS算法同时进行对比的效果。

format,png

扫描二维码

获取更多精彩

微卡智享

format,png

「 往期文章 」

实战|A*寻路算法遇到的问题及解决方法

实战|OpenCV结合A*算法实现简单的运动路径规划

学习|OpenCV匹配相似轮廓

 

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vaccae

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值