在一张图片中寻找起点与终点的最短路径,图片是bmp格式
代码分为三个类,一个是GUI界面,另一个是核心的A*算法,还有一个是定义的'点'的类
GUI界面
import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.event.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
public class MainFram extends JFrame implements ActionListener
{
//现在面板上把图片画出来,然后给按钮添加空间,发生点击时间时重绘图片,算法写在重绘的方法里
JLabel l1;
JButton b1,b2,b;
JPanel panBasic,pan1,pan2;
BufferedImage img;
String str="E:\\Editplus\\寻路图片\\1.bmp";
int i=1;
AStar load;
//zhijingxunlu load;
MainFram(){
setTitle("寻路算法");
l1=new JLabel("图片1");
b1=new JButton("<<");
b2=new JButton(">>");
b=new JButton("开始寻路");
setLayout(null);
this.setSize(650,400);
this.setLocation(200,200);
panBasic=new Mypanel();
l1.setBounds(270,10,50,30);
panBasic.setBounds(150,50,330,230);
b1.setBounds(180,290,50,30);
b2.setBounds(260,290,50,30);
b.setBounds(350,290,100,30);
this.add(l1);
this.add(panBasic);
this.add(b1);
this.add(b2);
this.add(b);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
b1.addActionListener(this);
b2.addActionListener(this);
b.addActionListener(this);
}
public static void main(String[] args)
{
new MainFram();
}
public void paint(){//绘制寻路图片的方法
Graphics g=panBasic.getGraphics();//获得当前界面上的值,后面改变图片都是重绘pan1,只有pan1由Graphics
load=new AStar();
//load=new zhijingxunlu();//Point
load.setImage(img);
g.setColor(Color.red);
g.drawString("起点",load.getsNode().getX(), load.getsNode().getY());
g.fillRect(load.getsNode().getX(), load.getsNode().getY(), 3, 3);
g.fillRect(load.geteNode().getX(), load.geteNode().getY(), 3, 3);
g.drawString("终点", load.geteNode().getX()-25,load.geteNode().getY());
System.out.println("起点:("+load.getsNode().getX()+","+load.getsNode().getY()+")");
System.out.println("终点:("+load.geteNode().getX()+","+load.geteNode().getY()+")");
load.search();//寻路算法Node
for(int i=0;i<load.resultList.size();i++){
g.fillRect(load.resultList.get(i).getX(),load.resultList.get(i).getY(),1,1);
}
System.out.println(load.resultList.size()+"个节点");
}
class Mypanel extends JPanel
{
public void paint(Graphics g){
super.paint(g);
try{
img=ImageIO.read(new File(str));
}
catch(IOException e){
System.out.println(e.toString());
}
g.drawImage(img,0,0,null);
}
}
public void actionPerformed(ActionEvent e){
if(e.getSource()==b1){
if(i>1){
--i;
str="E:\\Editplus\\寻路图片\\"+i+".bmp";
pan1=new Mypanel();
l1.setText("图片"+i);
this.repaint();
}
}
if(e.getSource()==b2){
if(i<15){
++i;
str="E:\\Editplus\\寻路图片\\"+i+".bmp";
pan2=new Mypanel();
l1.setText("图片"+i);
this.repaint();
}
}
if(e.getSource()==b){
paint();
}
}
}
像素点的类
class Node
{
private int x;//节点在地图中的横坐标
private int y;//节点在地图中的纵坐标
private int g;//从起始点移动到此点的距离
private int h;//到终点的曼哈顿距离
private int f;//g+h,判断依据
Node parNode;
Node(int i, int j, Node node)
{
this.x = i;
this.y = j;
this.parNode = node;
}
public void setX(int i)
{
this.x = i;
}
public void setY(int i)
{
this.y = i;
}
public void setparNode(Node node)
{
this.parNode = node;
}
public int getX()
{
return this.x;
}
public int getY()
{
return this.y;
}
public Node getparNode()
{
return this.parNode;
}
public void setF(int i)
{
this.f = i;
}
public void setG(int i)
{
this.g = i;
}
public void setH(int i)
{
this.h = i;
}
public int getF()
{
return this.f;
}
public int getH()
{
return this.h;
}
public int getG()
{
return this.g;
}
}
A*算法:A*算法用于找寻地图中两点之间的最短路径,详细讲解大家可以看这篇连接。点击打开链接(侵删)
import java.util.*;
import java.awt.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.awt.image.BufferedImage;
public class AStar {//输入图片 返回一个结果数组
private int map_Width;// 得到图片的宽的
private int map_Height;//得到图片的高度
private Node sNode; //创建初始点
private Node eNode; //创建终结点
private BufferedImage img=null; //传入的图片
private final int cost_straight=10;//上下左右移动
private final int cost_diagonal=14;//斜线上的移动
private final int stepLength=1;//寻找下一个点时的步长
private int map[][]; //地图
ArrayList<Node> openList=new ArrayList(); //开启列表
ArrayList<Node> closedList=new ArrayList(); //关闭列表
ArrayList<Node> resultList=new ArrayList(); //结果列表
AStar(){//构造函数
}
public void setImage(BufferedImage img){//传入图片
this.img=img;
this.map_Height=img.getHeight();
this.map_Width=img.getWidth();
initmap();
setNodes();
setNodee();
}
public void setNodes(){
Node n;
int x=2,y=0;
for(int i=0;i<img.getHeight();i++){
if(map[x][i]==1){
y=i;
break;
}
}
n=new Node(x,y,null);
this.sNode=n;
System.out.println("起点的坐标是:("+x+","+y+")");
}
public void setNodee(){
Node n;
int x=img.getWidth()-2,y=0;
for(int i=0;i<img.getHeight();i++){
if(map[x][i]==1){
y=i;
break;
}
}
n=new Node(x,y,null);
this.eNode=n;
System.out.println("终点的坐标是:("+x+","+y+")");
}
public void initmap(){
map=new int[map_Width+1][map_Height+1];
for(int i=0;i<map_Width;i++){
for(int j=0;j<map_Height;j++){
//像素颜色由红,绿,蓝三色组成,三色的值[0-255]2进制下的8位 16进制下的2位 用移位的方法分别获得
//三原色全部位0组成的就是黑色
int RGB=img.getRGB(i, j);//获得图片的16进制像素值
int R=(RGB&0xff0000)>>16;//获得16进制下的前两位,也就是2进制下的前8位
int G=(RGB&0xff00)>>8;//位与代表取那几位
int B=(RGB&0xff);
if(R==0&&G==0&&B==0){
map[i][j]=1;
}
else{
map[i][j]=0;
}
}
}
}
public void setsNode(Node n){
this.sNode=n;
}
public void seteNode(Node n){
this.eNode=n;
}
public Node getsNode(){
return sNode;
}
public Node geteNode(){
return eNode;
}
public void run(){
search();
}
public void search(){
if(sNode.getX()<0||sNode.getX()>map_Width
||sNode.getY()<0||sNode.getY()>map_Height
||eNode.getY()<0||eNode.getY()>map_Width
||eNode.getY()<0||eNode.getY()>map_Height
){//判断是否出界
System.out.println("超出了图像范围!");
return;
}
if(map[sNode.getX()][sNode.getY()]==0||map[eNode.getX()][eNode.getY()]==0){
System.out.println("节点选择不正确!!!");
return;
}
openList.add(sNode);//刚开始就将初始点添加到开启列表中
long begintime=System.currentTimeMillis();
resultList=search(sNode,eNode);//重载search方法,调用A*算法
if(resultList.size()==0){
System.out.println("没有找到路线");
return;
}
long endtime=System.currentTimeMillis();
System.out.println("寻路时间="+(endtime-begintime)+"ms");
return;
}
public ArrayList<Node> search(Node sNode,Node eNode){
//返回一个结果集
boolean flag=false;
Node node=null;//当前节点
while(openList.size()>0){
node=openList.get(0);//当前节点位上一下的F值最小的点
if(node.getX()==eNode.getX()&&node.getY()==eNode.getY()){
flag=true;//如果当前节点等于最终节点,那么跳出循环
break;
}
//检查当前节点周围的所有节点
//上
if(node.getY()-1>0){
checkPath(node.getX(),node.getY()-1,node,eNode,cost_straight);
}
//下
if(node.getY()+1<map_Height){
checkPath(node.getX(),node.getY()+1,node,eNode,cost_straight);
}
//左
if(node.getX()-1>0){
checkPath(node.getX()-1,node.getY(),node,eNode,cost_straight);
}
//右
if(node.getX()+1<map_Width){
checkPath(node.getX()+1,node.getY(),node,eNode,cost_straight);
}//四个方向,八个方向更为精确,但是耗时较大
//左下
if(node.getX()-1>0&&node.getY()+1<map_Height){
checkPath(node.getX()-1,node.getY()+1,node,eNode,cost_diagonal);
}
//右下
if(node.getX()+1<map_Width&&node.getY()+1<map_Height){
checkPath(node.getX()+1,node.getY()+1,node,eNode,cost_diagonal);
}
//左上
if(node.getX()-1>0&&node.getY()-1>0){
checkPath(node.getX()-1,node.getY()-1,node,eNode,cost_diagonal);
}
//右上
if(node.getX()+1<map_Width&&node.getY()-1>0){
checkPath(node.getX()+1,node.getY()-1,node,eNode,cost_diagonal);
}
closedList.add(openList.remove(0));
Collections.sort(openList,new CompareNode());
}
if(flag){
getPath(resultList, node);//由终点节点往前回溯找到结果集
}
return resultList;//结果集 路径所有的点都包含在其中
}
//如果没有处于开启列表中,那么添加到开启列表中,如果已经处于开启列表中,那么进行判断:
//是经过上一个节点再到达此处G值小还是原本的G值小,H值不变,G值的大小决定了F的大小
//如果经父节点的G值更小,那么更新此点的参数值,并将父节点指向上一个节点
public void checkPath(int x,int y,Node parNode,Node eNode,int cost){
Node node=new Node(x,y,parNode);
if(map[x][y]==0){
closedList.add(node);
return;//点在路外
}
if(isListContains(closedList, x, y)!=-1){
return ;//说明点处于关闭列表中
}
int dex=-1;
if((dex=isListContains(openList, x, y))!=-1){//说明在开启列表中
if(node.getparNode().getG()+cost<openList.get(dex).getG()){
node.setparNode(parNode);//检测新的路线是否更好,如果是改变他的父节点
CountG(node,cost);
CountF(eNode);
}
}
else{//不在关闭列表中 且不在开启列表中 就添加进来
node.setparNode(parNode);
Count(node,eNode,cost);
openList.add(node);
}
}
public int isListContains(ArrayList<Node> list,int x,int y){//检测这个点是否在这种状态集中
for(int i=0;i<list.size();i++){
if(list.get(i).getX()==x&&list.get(i).getY()==y){
return i;//返回i说明在这个集合中,并且索引值就是i
}
}
return -1;//说明不在
}
//从终点回溯到起点
public void getPath(ArrayList<Node> list,Node n){
if(n.getparNode()!=null){
getPath(list,n.getparNode());
}
list.add(n);
}
//重新更新节点的参数
public void Count(Node n,Node eNode,int cost){
CountF(n);
CountG(n,cost);
CountH(n,eNode);
}
public void CountF(Node n){
n.setF(n.getG()+n.getH());
}
public void CountG(Node n,int cost){
if(n.getparNode()==null){
n.setG(cost);
}
else
n.setG(n.getparNode().getG()+cost);
}
public void CountH(Node n,Node eNode){
n.setH(Math.abs(eNode.getX()-n.getX())+Math.abs(eNode.getY()-n.getY()));
}
//按照F的大小进行排序
class CompareNode implements Comparator<Node>{
//集成了接口一下是接口中的抽象方法
public int compare(Node o1, Node o2) {
//o1-o2是按照升序排列
return o1.getF()-o2.getF();
}
}
}