本路由继承自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)的更多相关文章

  1. 算法:Astar寻路算法改进

    早前写了一篇<RCP:gef智能寻路算法(A star)> 出现了一点问题. 在AStar算法中,默认寻路起点和终点都是N x N的方格,但如果用在路由上,就会出现问题. 如果,需要连线的 ...

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

    寻路算法有非常多种,A*寻路算法被公觉得最好的寻路算法. 首先要理解什么是A*寻路算法,能够參考这三篇文章: http://www.gamedev.net/page/resources/_/techn ...

  3. 无递归 A星寻路算法

    整理硬盘的时候,发现我早些年写的A星寻路算法.特放上来,待有缘人拿去,无递归噢,性能那是杠杠的. 码上伺候 public class Node { public int X { get; set; } ...

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

    在此把这个算法称作B* 寻路算法(Branch Star 分支寻路算法,且与A*对应),本算法适用于游戏中怪物的自动寻路,其效率远远超过A*算法,经过测试,效率是普通A*算法的几十上百倍. 通过引入该 ...

  5. 数据结构和算法总结(三):A* 寻路算法

    前言 复习下寻路相关的东西,而且A star寻路在游戏开发中应用挺多的,故记录下. 正文 迪杰斯特拉算法 说起A*得先谈谈Dijkstra算法,它是在BFS基础上的一种带权值的两点最短寻路贪心算法. ...

  6. 三角网格上的寻路算法Part.2—A*算法

    背景 继上一篇三角网格Dijkstra寻路算法之后,本篇将继续介绍一种更加智能,更具效率的寻路算法-A*算法,本文将首先介绍该算法的思想原理,再通过对比来说明二者之间的相同与不同之处,然后采用类似Di ...

  7. A星寻路算法介绍

    你是否在做一款游戏的时候想创造一些怪兽或者游戏主角,让它们移动到特定的位置,避开墙壁和障碍物呢? 如果是的话,请看这篇教程,我们会展示如何使用A星寻路算法来实现它! 在网上已经有很多篇关于A星寻路算法 ...

  8. A*寻路算法探究

    A*寻路算法探究 A*算法常用在游戏的寻路,是一种静态网路中求解最短路径的搜索方法,也是解决很多搜索问题的算法.相对于Dijkstra,BFS这些算法在复杂的搜索更有效率.本文在U3D中进行代码的测试 ...

  9. A*寻路算法

    对于初学者而言,A*寻路已经是个比较复杂的算法了,为了便于理解,本文降低了A*算法的难度,规定只能横竖(四方向)寻路,而无法直接走对角线,使得整个算法更好理解. 简而言之,A*寻路就是计算从起点经过该 ...

随机推荐

  1. RVM 多版本Ruby管理-Gentoo

    发现了一个非常Amzaing的Ruby的工具RVM,用于安装和管理Ruby的多个版本.相比较于直接在系统中安装不同版本的Ruby,然后使用时切换到对应的版本,这种方式实在是酷毙了,使ruby安装变得非 ...

  2. My安卓知识5--百度地图api的使用,周边信息检索

    虽然查了很多资料,但是这个问题还是解决不了,不知道为什么检索城市内的相关信息能用,检索周边信息语句就是用不了.代码如下,第一段是检索保定市内的加油站,第二段是检索周边的加油站.centerToMyLo ...

  3. Daily Scrum 12.14

    今日完成任务: 优化了问题页面显示问题的算法:两名开发人员有CCF考试,今天没有完成任务,任务顺延到明天. 明日任务: 黎柱金 解决资源显示全部为同一个PDF的BUG 晏旭瑞 资源搜索问题 孙思权 做 ...

  4. windows下mongodb权限设置解决方法

    mongodb简介: MongoDB 是一个跨平台的,面向文档的数据库,提供高性能,高可用性和可扩展性方便. MongoDB工作在收集和文件的概念. MongoDB默认设置为无权限访问限制,所以可以直 ...

  5. 基于御安全APK加固的游戏反外挂方案

    一. 前言 随着移动互联网的兴起,移动游戏市场近几年突然爆发,收入规模快速增长.根据第三方数据统计,国内移动游戏2015年市场规模已达514.6亿.由于手游市场强势兴起,而且后续增长势头会愈加猛烈.火 ...

  6. cocoapods specs 镜像

    在使用cocoapods 进行update 或者 install的时候 每次回去更新获取的pod specs,每次速度都不是很理想,博主最近对github上的specs仓库进行了镜像,分别在gitca ...

  7. block反向界面传值

    1.在第二个界面的.h文件中申明block @property(nonatomic,copy)void(^myBlock)(NSString * str); 2.在返回第一个界面的点击事件中赋值要传递 ...

  8. jackson2.5.0升级到2.7.0

    开发环境:spring-mvc4.1.7.jackson2.7.0 问题描述:项目中将原来的jackson2.5.0升级到2.7.0,导致服务调用出错. mvc相关的配置文件如下: <?xml ...

  9. psp工具需求分析

    PSP个人软件过程开发工具需求分析文档 a.业务需求    a.1 背景 二十一世纪是软件开发的黄金时期,有人把过去的十年称作软件高度发展的十年,不可置疑,越来越多的软件设计需求是物联网时代的趋势,越 ...

  10. Web调试利器OpenWindow

    有些时候调试web页面,在循环里面我们不方便设置断点进行调试,或者调试起来比较麻烦,我们就可以用openWindow的方法打印出想要查看的信息,既方便又省时. 代码如下: OpenWindow = w ...