RCP:gef智能寻路算法(A star)

本路由继承自AbstactRouter,参数只有EditPart(编辑器内容控制器),gridLength(寻路用单元格大小),style(FLOYD,FLOYD_FLAT,FOUR_DIR)。

字符集编码为GBK,本文只做简单的代码解析,源码戳我

如果源码不全,可以联系本人。

算法实现主要有三:

1、Astar单向寻路

2、地图预读

3、弗洛伊德平滑算法

Astar寻路的实现:


ANode minFNode = null;
while (true) {
minFNode = findMinNode(openList);
openList.remove(minFNode);
closedList.add(minFNode);
if (minFNode == null || minFNode.equals(endNode))
break;
search(minFNode, openList, closedList, startNode, endNode);
}

private void search(ANode node, List<ANode> openList,
List<ANode> closedList, ANode startNode, ANode endNode) {
ANode[] nodes = findAroundNode(node);
for (int i = 0, len = nodes.length; i < len; i++) {
if (nodes[i].getLevel() == ANodeLevel.DEAD)
continue;
nodes[i].g = (i > 3 ? nodes[i].getLevel().RE
: nodes[i].getLevel().BE) + node.g;
nodes[i].h = caculateH(nodes[i], endNode);
if (closedList.contains(nodes[i]))
continue;
if (!openList.contains(nodes[i])) {
openList.add(nodes[i]);
nodes[i].setParent(node);
} else if (openList.contains(nodes[i])) {
int idx = openList.indexOf(nodes[i]);
ANode n = openList.get(idx);
if (nodes[i].g < n.g) {
openList.remove(idx);
closedList.add(n);
nodes[i].setParent(n.getParent());
openList.add(idx, nodes[i]);
}
}
}
}

在网上大部分版本的Astar算法里,障碍只有两个参考值,即是可通过和不可通过

但在实际情况里,有可能会有较难度过的小溪,难以度过的河流,不能跨越的深涧,于是我在算法里引入了难易度概念,由ANodeLevel体现。


package galaxy.ide.configurable.editor.gef.router;

/**
* 节点等级,RE直角边,BE斜角边
*
* @author caiyu
* @date 2014-5-15
*/
public enum ANodeLevel {
EASY(10, 14), NORMAL(20, 28), HARD(50, 68), DEAD(2000, 2800);
/**
* 直角边
*/
public final int RE;
/**
* 斜角边
*/
public final int BE;

ANodeLevel(int RE, int BE) {
this.RE = RE;
this.BE = BE;
}
}

引入了四个难易程度,当然,这些难易程度自己可以调整。

障碍的难易程度是预读的,体现在代码:


    private void preReadingNodes(Point startPoint) {
Rectangle r;
for (Object c : this.editPart.getChildren()) {
if (c instanceof GraphicalEditPart) {
r = ((GraphicalEditPart) c).getFigure().getBounds();
preReader.read(r, startPoint, D);
}
}
}

预读器preReader源码如下:


    public void read(Rectangle r, Point startPoint, final int D) {
ANodeLevel level = ANodeLevel.HARD;
if (r.contains(this.startPoint) || r.contains(this.endPoint))
level = ANodeLevel.NORMAL;

int xS = ANodePreReader.calculateIndex(r.x, startPoint.x, D);
int xE = ANodePreReader
.calculateIndex(r.x + r.width(), startPoint.x, D);
int yS = ANodePreReader.calculateIndex(r.y, startPoint.y, D);
int yE = ANodePreReader.calculateIndex(r.y + r.height(), startPoint.y,
D);
Map<Integer, ANodeLevel> map;
for (int x = xS; x < xE; x++) {
for (int y = yS; y < yE; y++) {
map = pool.get(x);
if (map == null) {
map = new HashMap<Integer, ANodeLevel>();
pool.put(x, map);
}
map.put(y, level);
}
}
}

public ANode getNode(int x, int y) {
ANode node = new ANode(x, y);
Map<Integer, ANodeLevel> map = pool.get(x);
node.setLevel(map == null ? ANodeLevel.EASY
: map.get(y) == null ? ANodeLevel.EASY : map.get(y));
return node;
}

public static int calculateIndex(int v1, int v2, int distance) {
int offset = (v1 - v2) % distance;
return offset > 0 ? (v1 - v2) / distance + 1 : offset == 0 ? (v1 - v2)
/ distance : (v1 - v2) / distance - 1;
}

完成了以上,即可以实现智能绘图,应用该路由 new AStarConnectionRouter2(editPart,
20, AStarConnectionRouter.NONE);(不会在GEF中应用路由器的去看《GEF whole update》这本书)

如图所示:

可以看出,这个算法还有缺陷,并不平滑。我们加入弗洛伊德平滑算法new AStarConnectionRouter2(editPart,
20, AStarConnectionRouter.FLOYD);

,效果如图:

弗洛伊德平滑算法的原理:

1、如果A、B、C三点在同一直线上,视为三点共线,则去除B点

2、清理所有共线点之后,遍历任一点和其他点之间有无障碍物,如果没有,则去除两点之间的全部点。

算法实现:


    /**
* 弗洛伊德平滑处理
*
* @param D
* @param startPoint
*
* @param points
*/
public void floyd(ANode node, Point startPoint, int D) {
if ((this.style & FLOYD_SIMPLIFY) != FLOYD_SIMPLIFY
&& (this.style & FLOYD) != FLOYD)
return;
ANode fatherNode, currentNode = node, grandNode;
// 去除共线
while (true) {
fatherNode = currentNode.getParent();
if (fatherNode == null)
break;
grandNode = fatherNode.getParent();
if (grandNode == null)
break;
if (fatherNode.xIndex - currentNode.xIndex == grandNode.xIndex
- fatherNode.xIndex
&& fatherNode.yIndex - currentNode.yIndex == grandNode.yIndex
- fatherNode.yIndex) {
currentNode.setParent(grandNode);
} else
currentNode = fatherNode;
}
currentNode = node;

if ((this.style & FLOYD) != FLOYD)
return;
// 去除拐点
while (true) {
fatherNode = currentNode.getParent();
if (fatherNode == null)
break;
while (true) {
grandNode = fatherNode.getParent();
if (grandNode == null)
break;
if (linkable(currentNode, grandNode, startPoint, D)) {
currentNode.setParent(grandNode);
}
fatherNode = grandNode;
}
currentNode = currentNode.getParent();
if (currentNode == null)
break;
}
}

但是,上图的效果并不美观,有两个参考方案:

1、自己重写ConnectionFigure,使拐点圆滑

2、Astar算法只参考上下左右四个方向

只参考四个方向的使用例子new
AStarConnectionRouter2(editPart, 20, 
AStarConnectionRouter.FLOYD|
AStarConnectionRouter.FOUR_DIR);

如图所示:

以上,即实现了全部效果。

注意,在RouterStyle里有个TEST选项,该选项是测试使用,使用过程中会有大量bug。

new AStarConnectionRouter2(editPart,
20,
AStarConnectionRouter.FOUR_DIR
|
AStarConnectionRouter.FLOYD_SIMPLIFY
| AStarConnectionRouter.TEST);

该测试用于展示在寻路过程中AStar算法遍历到的节点,如图所示:

下一次再实现一个圆滑的弧线拐角,再来和大家分享。

源码下载请移步:http://pan.baidu.com/s/1hqgNN2s

RCP:gef智能寻路算法(A star),布布扣,bubuko.com

时间: 2024-08-04 15:57:09

RCP:gef智能寻路算法(A star)的相关文章

关于智能寻路算法的研究,A-Star算法拓展,B星寻路算法

B星算法的原理图: 以下是C语言的一段源码 #ifndef __ASTARPATHFINDER_H__ #define __ASTARPATHFINDER_H__ #include "cocos2d.h" USING_NS_CC; /**  * 横向移动一格的路径评分  */ static const int COST_HORIZONTAL = 20; /**  * 竖向移动一格的路径评分  */ static const int COST_VERTICAL = 5; /**  * 斜

算法:Astar寻路算法改进

早前写了一篇<RCP:gef智能寻路算法(A star)> 出现了一点问题. 在AStar算法中,默认寻路起点和终点都是N x N的方格,但如果用在路由上,就会出现问题. 如果,需要连线的终点并不在方格的四角上,就产生了斜线.于是我们可以对终点附近的点重新做一点儿处理,源码如下所示: int size = points.size(); if (size < 3) return; points.removePoint(size - 1); Point pointN1 = points.ge

A*(也叫A star, A星)寻路算法Java版

寻路算法有很多种,A*寻路算法被公认为最好的寻路算法. 首先要理解什么是A*寻路算法,可以参考这三篇文章: http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/a-pathfinding-for-beginners-r2003(英文) http://www.cppblog.com/christanxw/archive/2006/04/07/5126.html(中文) http://www.cnblog

一种高效的寻路算法 - B*寻路算法

在此把这个算法称作B* 寻路算法(Branch Star 分支寻路算法,且与A*对应),本算法适用于游戏中怪物的自动寻路,其效率远远超过A*算法,经过测试,效率是普通A*算法的几十上百倍. 通过引入该算法,一定程度上解决了游戏服务器端无法进行常规寻路的效率问题,除非服务器端有独立的AI处理线程,否则在服务器端无法允许可能消耗大量时间的寻路搜索,即使是业界普遍公认的最佳的A*,所以普遍的折中做法是服务器端只做近距离的寻路,或通过导航站点缩短A*的范围. 算法原理  本算法启发于自然界中真实动物的寻

这是一个真正靠谱的寻路算法

绝对没有其他看起来高大上 给别人讲都将不明白的理论.管你 人工智能 啥的 ,还有一百度一大篇的a*算法 ,其实大部分文章的理论都是讲不通的 或者没有讲清楚 更别说代码.做事刨根问底的牛脾气又上来了. 两周前 偶然原因接触到了寻路算法 于是百度 找到了a* .讲来将去大概意思就是持续性的找离目标近的节点 并且走过的节点不能重复走.反正百度搜a*算法 一搜一大片.在很简单的障碍的情况下是没问题 : 但是拐个弯就不行了,不是找最近的么,我让你一直找最近的. 直接迂在里面出不来了: 期间我曾经想过为什么

A*寻路算法入门(一)

大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流之用,请勿进行商业用途.同时,转载时不要移除本申明.如产生任何纠纷,均与本博客所有人.发表该翻译稿之人无任何关系.谢谢合作! 该篇博客由iOS课程团队的Johann Fradj发布,他现在是一个全职开发iOS的开发者.他是Hot Apps Factory(其是App Cooker的创造者)的共同创建

A*寻路算法的优化与改进

提要 通过对上一篇A*寻路算法的学习,我们对A*寻路应该有一定的了解了,但实际应用中,需要对算法进行一些改进和优化. Iterative Deepening Depth-first search- 迭代深化深度优先搜索 在深度优先搜索中一个比较坑爹情形就是在搜索树的一枝上没有要搜的结果,但是却非常深,甚至深不见底,这样就根本搜索不到结果.为了防止这种情况出现,就出现了Iterative Deepening的思想. 迭代深化搜索(Iterative deepening search, IDS)或者

[转] A*寻路算法C++简单实现

参考文章: http://www.policyalmanac.org/games/aStarTutorial.htm   这是英文原文<A*入门>,最经典的讲解,有demo演示 http://www.cnblogs.com/technology/archive/2011/05/26/2058842.html  这是国人翻译后整理的简版,有简单代码demo,不过有些错误,讲得很清晰,本文图片来自这篇 http://blog.csdn.net/b2b160/article/details/4057

HTML5-A*寻路算法

设置起点 设置终点 设置障碍 清除障碍 允许斜向跨越 HTML5-A*寻路算法,布布扣,bubuko.com