路径规划——Jump Point Search算法

news2024/12/23 16:45:09

路径规划——Jump Point Search算法

算法原理

跳点搜索算法(Jump Point Search),简称JPS,是由澳大利亚两位教授于2011年提出的基于Grid格子的寻路算法。JPS算法在保留A Star算法的框架的同时,进一步优化了A Star算法寻找后继节点的操作。
A Star算法可见:A Star

JPS与A Star算法的主要区别在后继节点的拓展策略上,不同于A Star算法中直接获取当前节点所有非已访问过的可达邻居节点来进行拓展的策略,JPS根据当前节点的方向,并基于搜索跳点的策略来拓展后继节点,遵循“两个定义、三个规则”。

定义一,强迫邻居(forced neighbor):
如果节点n是x的邻居,并且节点n的邻居有障碍物,并且从parent(x)经过x再到n的路径长度比其他任何从parent(x)不经过x到n的路径短,其中parent(x)为路径中x的前一个点,则n为x的强迫邻居,x为n的跳点。

举例来具体说,如上图
先看直线方向(straight),x的父节点是4,如果从4经过x到达节点node与从4不经过到达节点node相比,前者路径较长则没必要加入到x的邻居节点(如节点1、2、3、6、7、8),其中节点3与8两者路径是相等的,这时路径具有对称性,而JPS的核心便是打破这种对称,所以节点3和8也是不需要加入的,这些节点称为inferior neighbors劣性节点;前者路径较短则需要将节点node加入到x的邻居节点(如节点5),这种节点称为natural neighbors自然节点;
再来看对角线方向(diagonal),x的父节点是6,同理,劣性节点有1、2、7、8,自然节点有2、3、5;

如果有障碍物,如下图

在这里插入图片描述

当原先的节点2处有障碍物时,从父节点4经过x到达节点3比不经过x到达节点3路径更短,这时节点3便不是inferior neighbor了,需要作为x的有效邻居节点进一步考虑,这种节点就是forced neighbor强迫邻居了。同样,对角线方向移动时,原先的节点4处有障碍物时,从父节点6经过x到达节点1比不经过节点x到达节点1路径更短,这时节点1便是forced neighbor加入到openlist了。

定义二,跳点(Jump Point):
1.如果点y是起点或者目标点,则y是跳点;
2.如果y有强迫邻居则y是跳点;
3.如果parent(y)到y是对角移动,并且y经过水平或垂直方向移动可以到达跳点,则y是跳点。

在这里插入图片描述

先看Jumping Straight,从p(x)到x,向左一直推进直到y,节点y有一个forced neigbor节点z,那么节点y便作为跳点加入到openlist,此处对应于定义2。
再看Jumping Diagonally,从p(x)沿着对角方向到x,然后节点x沿着水平方向和垂直方向搜索,均没有发现感兴趣的节点,于是继续沿着对角方向推进,一直到节点y,节点y沿着水平方向搜索时发现了感兴趣节点z,节点z有forced neighbor节点,那么节点y便作为跳点成为了节点x的后继节点,此处对应于定义3,被加入到openlist中,节点z被标记为特殊点,之后返回到y,并沿着垂直方向搜索,垂直方向上无特殊点,那么节点x的这个方向上的工作便结束了,之后沿着另一个对角方向搜索,有forced neighbor节点w,那么节点w也作为跳点被加入到openlist中,此处对应于定义2。

**规则一:**JPS搜索跳点的过程中,如果直线方向(为了和对角线区分,直线方向代表水平方向和垂直方向,且不包括对角线等斜线方向)和对角线方向都可以移动,则首先在直线方向搜索跳点,再在对角线方向搜索跳点。

**规则二:**1.如果从parent(x)到x是直线移动,n是x的邻居,若有从parent(x)到n的路径不经过x且路径长度小于或等于从parent(x)经过x到n的路径,则走到x后下一个点不会走到n;
2.如果从parent(x)到x是对角线移动,n是x的邻居,若有从parent(x)到n的路径不经过x且路径长度小于从parent(x)经过x到n的路径,则走到x后下一个点不会走到n。

**规则三:**只有跳点才会加入openlist,因为跳点会改变行走方向,而非跳点不会改变行走方向,最后寻找出来的路径点也都是跳点。

算法流程:

首先检查当前节点是否有强迫邻居,如果有,那么此节点便可以作为跳点加入到openlist中,如果没有,那么遵循三个规则沿着水平方向、垂直方向和对角方向寻找跳点。

算法实现

"""
    Filename: jps.py
    Description: Plan path using Jump-Point-Search Algorithm
    Author: Benxiaogu:https://github.com/Benxiaogu
    Date: 2024-08-18
"""
import heapq
import math
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation


class JPS:
    def __init__(self,grid,start,goal,board_size):
        self.grid = grid
        self.start = self.Node(start,0,0)
        self.goal = self.Node(goal,0,0)
        self.board_size = board_size
        self.path = []

    class Node:
        def __init__(self, position, g, h, parent=None):
            self.position = position    # position of node
            self.g = g                  # distance from node to start
            self.h = h                  # heuristic value from node to goal
            self.parent = parent        # parent node

        def __eq__(self, other) -> bool:
            return self.position == other.position
        
        def __lt__(self, other):
            # Prioritise nodes based on heuristic value
            return self.g+self.h < other.g+other.h or (self.g+self.h==other.g+other.h and self.h<other.h)

    def plan(self):
        open = []
        closed = []
        self.searched = [] # Used to record nodes that are searched

        nexts = [(-1,0),(0,1),(0,-1),(1,0),(-1,1),(1,1),(1,-1),(-1,-1)]

        self.start.h = self.heuristic(self.start.position)
        heapq.heappush(open, self.start)

        while open:
            # Select the node closest to the start node
            current_node = heapq.heappop(open)
            if current_node.position in closed:
                continue

            # self.searched.append(current_node.position)
            closed.append(current_node.position)
            
            # Find the goal
            if current_node == self.goal:
                self.goal = current_node
                while current_node:
                    self.path.append(current_node.position)
                    current_node = current_node.parent
                self.path = self.path[::-1]

                return self.goal.g

            for next in nexts:
                jumppoint = self.Jumping(current_node.position,next)
                if jumppoint and jumppoint not in closed:
                    h = self.heuristic(jumppoint)
                    g = current_node.g+self.calculate_cost(current_node.position, jumppoint)
                    jp_node = self.Node(jumppoint,g,h,current_node)
                    heapq.heappush(open,jp_node)
                    self.searched.append(jumppoint)
                    if jp_node == self.goal:
                        break

        
        return -1
    
    def Jumping(self, node, direction):
        new_node = (node[0]+direction[0], node[1]+direction[1])
        
        if self.grid[new_node[0]][new_node[1]] == 1:
            return None

        if new_node == self.goal.position:
            return new_node

        # Find forced neighbor at horizaontal and vertical direction
        if self.findForcedNeighbor(new_node, direction):
            return new_node
        
        # If current direction of search is diagonal, then search jump point horizaontally or vertically
        if direction[0]!=0 and direction[1]!=0:
            y_dir = (direction[0],0)
            x_dir = (0,direction[1])
            if self.Jumping(new_node,x_dir) or self.Jumping(new_node,y_dir):
                return new_node
        
        return self.Jumping(new_node,direction)

    def findForcedNeighbor(self, node, direction):
        """
            If there be forced neighbor, return Ture otherwise False
        """
        y,x = node

        # vertical
        if direction[0]!=0 and direction[1]==0:
            if (self.grid[y][x+1] != 0 and self.grid[y+direction[0]][x+1] == 0) or \
                (self.grid[y][x-1] != 0 and self.grid[y+direction[0]][x-1] == 0):
                return True
        
        # horizontal
        if direction[0]==0 and direction[1]!=0:
            if (self.grid[y+1][x] != 0 and self.grid[y+1][x+direction[1]] == 0) or \
                (self.grid[y-1][x] != 0 and self.grid[y-1][x+direction[1]] == 0):
                return True
        
        # diagonal
        if direction[0]!=0 and direction[1]!=0:
            if (self.grid[y-direction[0]][x] != 0 and self.grid[y-direction[0]][x+direction[1]] == 0) or \
                (self.grid[y][x-direction[1]] != 0 and self.grid[y+direction[0]][x-direction[1]] == 0):
                return True
        
        return False

    # def heuristic(self, node):
    #     # Manhattan distance from current node to goal node
    #     return abs(node[0] - self.goal.position[0]) + abs(node[1] - self.goal.position[1])
    
    # def heuristic(self, node):
    #     # Chebyshev Distance
    #     D = 1
    #     D2 = math.sqrt(2)
    #     dx = abs(node[0] - self.goal.position[0])
    #     dy = abs(node[1] - self.goal.position[1])
    #     return D * (dx + dy) + (D2 - 2 * D) * min(dx, dy)
    
    def heuristic(self, node):
        # Euclidean Distance
        D = 1
        dy = abs(node[0] - self.goal.position[0])
        dx = abs(node[1] - self.goal.position[1])
        return D * math.sqrt(dx * dx + dy * dy)
    
    def calculate_cost(self, start, end):
        # The distance from the current node to the next jump point
        return math.sqrt((start[0] - end[0]) ** 2 + (start[1] - end[1]) ** 2)
        

结果如下:

在这里插入图片描述
完整Python及C++代码:JPS

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2064337.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

异常在代码中的两个作用

一.异常的作用: 作用一:异常是用来查询bug的关键参考信息。 作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况。 二.举例: 例1: 一个JavaBean类: package com.itheima.a01MyExpection;public class Student { private String name; private int…

Mamba-YOLO : 基于SSM的YOLO目标检测算法(附代码)

代码地址&#xff1a;GitHub - HZAI-ZJNU/Mamba-YOLO: the official pytorch implementation of “Mamba-YOLO&#xff1a;SSMs-based for Object Detection” 论文地址&#xff1a;https://arxiv.org/pdf/2406.05835 在深度学习技术的快速进步推动下&#xff0c;YOLO系列为实时…

前端VUE低代码平台有哪些?盘点几款,你且看看有没有用得上的

前端低代码平台有哪些&#xff1f;盘点几款&#xff0c;你且看看有没有用得上的。 1、GOVIEW GoView 是一个使用 Vue3 搭建的低代码数据可视化开发平台&#xff0c;将图表或页面元素封装为基础组件&#xff0c;无需编写代码即可完成业务需求。它的技术栈为&#xff1a;Vue3 T…

vant 组件中事件选择器的一些小用法

获取当前所在的月份的月初和当天的日期 computed: {// 默然展示月初的第一天formattedFirstDayOfMonth() {const now new Date();const firstDayOfMonth new Date(now.getFullYear(), now.getMonth(), 1);const year firstDayOfMonth.getFullYear();const month (firstDay…

聚星文社原版本绘唐科技AI推文工具

聚星文社原版本绘唐科技AI推文工具是一种可以帮助用户生成推文内容的人工智能工具。它通过分析大量的文本和数据&#xff0c;学习了推文的写作风格和语言特点&#xff0c;并能够根据用户提供的关键词和要求&#xff0c;生成符合要求的推文内容。 这个工具可以快速生成高质量的推…

C语言一笔画迷宫

目录 开头程序程序的流程图程序游玩的效果结尾 开头 大家好&#xff0c;我叫这是我58。 程序 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> #include <Windows.h> void printmaze(const char strmaze[11][11]) {int ia 0;…

金蝶云星空元数据冲突SVN:replaced,tree conflict树冲突解决过程

文章目录 SVN:replaced,tree conflict树冲突解决过程问题解决方案 SVN:replaced,tree conflict树冲突解决过程 问题 解决方案

五参数防爆气象站

五参数防爆气象站是一种用于监测环境气象条件和预测潜在爆炸危险的装置。其功能包括以下五个方面&#xff1a; 温度监测&#xff1a;防爆气象站能够实时监测环境的温度变化&#xff0c;并且能够提供温度的历史记录和趋势预测。这对于防止设备过热和爆炸具有重要意义。 湿度监测…

场外个股期权优劣有哪些?场外个股期权有风险吗?

今天带你了解场外个股期权优劣有哪些&#xff1f;场外个股期权有风险吗&#xff1f;个股场外期权&#xff0c;作为非交易所交易的股票期权合约&#xff0c;为投资者提供了独特的投资渠道。 场外个股期权&#xff08;OTC个股期权&#xff09;的优势&#xff1a; 1.灵活性&…

网络间通信

1、udp通信 特点&#xff1a;&#xff08;1&#xff09;无连接 &#xff08;2&#xff09;不可靠 2、udp编程&#xff08;c/s模型&#xff09; ssize_t recvfrom(int sockfd, //socket的fd void *buf, //保存数据的一块空间的地址 …

鸿蒙弹窗实现乱象?带你玩转正确的实现姿势

最近看到很多童鞋吐槽鸿蒙自定义弹窗的实现,也有不少童鞋提供了各式各样的低耦,轻巧方向的优化方案,但多数参差不齐,甚至有基于老API(白玩,以后还得废弃掉…)给的方案,为避免如此“乱象”遂提出正确的实现姿势。 姿势一 如果您没有特别的要求,系统AlertDialog(API 6+)…

新加坡门店客流计数器,AI智能识别算法加持,精准完成统计分析

在数字化转型的大潮下&#xff0c;零售业正经历着前所未有的变革。为了更好地理解顾客行为并优化店铺运营&#xff0c;新加坡的零售门店开始采用搭载AI智能识别算法的客流计数器系统。这套系统不仅能够精准统计顾客流量&#xff0c;还能提供深入的分析报告&#xff0c;帮助商家…

tcp 和udp通信

一.recvfrom recvfrom函数是一个系统调用&#xff0c;用于从套接字接收数据。该函数通常与无连接的数据报服务&#xff08;如 UDP&#xff09;一起使用&#xff0c;但也可以与其他类型的套接字使用。与简单的 recv() 函数不同&#xff0c;recvfrom() 可以返回数据来源的地址信息…

“肯将玉钳作双戟,一舞天下定乾坤。”记唐铎《墨龙图》之中的笔墨画意

唐铎&#xff0c;1957 年生于北京&#xff0c;国家一级美术师&#xff0c;曾先后师从于刘文西、黄申发老师&#xff0c;原名唐京鸣&#xff0c;京城人士&#xff0c;取其名&#xff0c;不鸣则已&#xff0c;一鸣惊人之意&#xff0c;学画三十余年&#xff0c;专注于齐派虾蟹&am…

算法工程师第四十四天(99. 岛屿数量 深搜 99. 岛屿数量 广搜 100.岛屿的最大面积 )

参考文献 代码随想录 一、岛屿数量 题目描述 给定一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的矩阵&#xff0c;你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成&#xff0c;并且四周都是水域。你可以假设矩阵外均被水包…

Android 安卓Compose软键盘和Activity页面的协调处理问题

文章目录 问题展示1、输入框展示不完整&#xff0c;且布局被顶出屏幕外2、输入框被软键盘完全覆盖 解决方案最终演示 问题展示 1、输入框展示不完整&#xff0c;且布局被顶出屏幕外 这是默认处理的样式 2、输入框被软键盘完全覆盖 当在AndroidManifest.xml Activity标签上加…

天龙八部万象归一第8版单机安装教程+GM工具+虚拟机一键端

今天给大家带来一款单机游戏的架设&#xff1a;天龙八部万象归一第8版。 另外&#xff1a;本人承接各种游戏架设&#xff08;单机联网&#xff09; 本人为了学习和研究软件内含的设计思想和原理&#xff0c;带了架设教程仅供娱乐。 教程是本人亲自搭建成功的&#xff0c;绝对…

火影忍者2——漩涡鸣人(仙人模式)篇

老规矩&#xff0c;谈火影~ 火影忍者 之—— 漩涡鸣人&#xff08;仙人模式&#xff09;篇 众所周知&#xff0c;鸣仙是一个早期的A忍&#xff0c;技能破坏力贼大&#xff0c;一般遇到鸣仙&#xff08;除非我用了青水神卡&#xff09;我是直接退的 普攻 一技能 螺旋丸 普…

深信服应届生客户经理面试经验分享

吉祥知识星球http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247485367&idx1&sn837891059c360ad60db7e9ac980a3321&chksmc0e47eebf793f7fdb8fcd7eed8ce29160cf79ba303b59858ba3a6660c6dac536774afb2a6330#rd 《网安面试指南》http://mp.weixin.qq.com/s?…

如何使用mmdetection训练实例分割模型?

安装 anoconda 从官方网站下载并安装。 配置环境 conda create --name openmmlab python3.8 -y conda activate mmdet 安装 PyTorch 注意&#xff1a;这个步骤很关键&#xff0c;否则后面会出问题。一定要确保自己电脑当前安装和配置的cuda版本。 使用命令&#xff1a;nvcc …