赞
踩
main.cpp
主函数主要提供实现算法的对外接口,这里主要的流程是
1.调用MapData(mapPath)来读取地图数据
2.调用astar.PathPoint()进行Astar路径查找
3.Display(astarPath, mapData, xStart, yStart, xStop, yStop, “Astar”, true)函数进行最终路径的可视化显示
/* @Function:Astar External Implementation @Time:2022-01-10 @Author:Tang Gu Jie @E-Mail:2822902808@qq.com */ #include <iostream> #include <vector> #include <string> #include "Astar.h" #include "map.h" #include "display.h" int main() { //string mapPath = "map_small.txt"; //地图路径 //int xStart = 4; //int yStart = 0; //起点 //int xStop = 2; //int yStop = 6; //终点 string mapPath = "map_big.txt"; //地图路径 int xStart = 25; int yStart = 4; //起点 int xStop = 3; int yStop = 16; //终点 //f=a*g+b*h float weightA = 1.0; //权重a float weightB = 1.0; //权重b //地图数据 vector<vector<int>> mapData(MapData(mapPath)); /*** *@函数功能 初始化A星算法 ------------------------------------------------ *@参数 mapData 地图数据 *@参数 xStart 起点x值 *@参数 yStart 起点y值 *@参数 xStop 终点x值 *@参数 yStop 终点y值 *@参数 weightA 权重a值 *@参数 weightA 权重b值 *@参数 PathType 路径寻找的结果,初始化时赋为NOFINDPATHPOINT *@参数 DistanceType 距离类型,EUCLIDEAN欧式距离,MANHANTTAN曼哈顿距离 ------------------------------------------------ *@返回值 无 */ ASTAR::CAstar astar(mapData, xStart, yStart, xStop, yStop, weightA, weightB,ASTAR::CAstar::PathType::NOFINDPATHPOINT,ASTAR::CAstar::DistanceType::EUCLIDEAN); //A星算法路径寻找函数 std::vector<std::pair<int, int> >astarPath = astar.PathPoint(); if (astar.m_noPathFlag == ASTAR::CAstar::PathType::NOFINDPATHPOINT) { std::cout << "A星算法没能找到路径!!!" << std::endl; } else { for (int i = 0; i < astarPath.size(); i++) { std::cout << astarPath[i].first << "," << astarPath[i].second << std::endl; } /*** *@函数功能 显示路径结果,蓝色起点,红色终点,黑色障碍物 ------------------------------------------------ *@参数 mapData 地图数据 *@参数 xStart 起点x值 *@参数 yStart 起点y值 *@参数 xStop 终点x值 *@参数 yStop 终点y值 *@参数 "Astar" 图片的标题 *@参数 true 是否保存图片,ture保存,false不保存 ------------------------------------------------ *@返回值 无 */ Display(astarPath, mapData, xStart, yStart, xStop, yStop, "Astar", true); } return 0; }
map.h
/*
@Function:Map Data Read
@Time:2022-01-10
@Author:Tang Gu Jie
@E-Mail:2822902808@qq.com
*/
#pragma once
#ifndef __MAP__
#define __MAP
#include <vector>
#include<iostream>
using namespace std;
vector<vector<int>> MapData(std::string _mapPath);
#endif
map.cpp
/*该函数是读取map_big.txt形成一个二维数组num,其中num里面0表示可自由通行区域,1表示障碍物*/ /* @Function:Map Data Read @Time:2022-01-10 @Author:Tang Gu Jie @E-Mail:2822902808@qq.com */ #include "map.h" #include<fstream> #include<sstream> vector<vector<int>>MapData(std::string _mapPath) { ifstream f; //f.open("map_media.txt"); f.open(_mapPath); //f.open("map.txt"); string str; vector<vector<int> > num; while (getline(f, str)) //读取1行并将它赋值给字符串str { istringstream input(str); // c++风格的串流的输入操作 vector<int> tmp; int a; while (input >> a) //通过input将第一行的数据一个一个的输入给a tmp.push_back(a); num.push_back(tmp); } return num; }
地图数据的读取主要采用C++文件读取流的方式。 0表示自由通行区域,1表示障碍物,以下是map_big.txt
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Astar.h
在这头文件中,对外只提供了PathPoint()接口,该接口就是Astar算法入口函数,其次在该文件中,使用命名空间的机制,防止以后写其他的路径规划算法会用到相同的名字。通过枚举类型DistanceType已达到距离函数传参时见名之意的作用,此外还在构造函数中加入权重a和权重b,对应理论部分的 f ( n ) = a × g ( n ) + b × g ( n ) f(n)=a \times g(n)+b \times g(n) f(n)=a×g(n)+b×g(n),以此实现Astar算法的变形。
/* @Function:Astar Algorithm Implementation @Time:2022-01-10 @Author:Tang Gu Jie @E-Mail:2822902808@qq.com */ #pragma once #ifndef __ASTAR__ #define __ASTAR__ #include <iostream> #include <vector> #include <string> #include <map> //命名空间 ASTAR namespace ASTAR { //节点结构体 struct Node { int SnodeX; //节点X值 int SnodeY; //节点Y值 int SparentX; //父节点X值 int SparentY; //父节点Y值 float Sgn;; //节点的g值 float Shn; //节点的h值 float Sfn; //节点的f值 }; class CAstar { public: //路径类型的枚举类型,NOFINDPATHPOINT表示没找到路径点,FINDPATHPOINT找到路径点 enum PathType {NOFINDPATHPOINT=0, FINDPATHPOINT =1}; //距离类型 EUCLIDEAN欧式距离,MANHANTTAN曼哈顿距离 enum DistanceType {EUCLIDEAN=0,MANHANTTAN=1}; PathType m_noPathFlag; public: /*初始化函数*/ CAstar(std::vector<std::vector<int>>_mapData, //地图数据,以二维数据存储 int _xStart, //起始点X值 int _yStart, //起始点Y值 int _xStop, //目标点X值 int _yStop, //目标点Y值 float _weightA, //权重a值 float _weightB, //权重b值 PathType _noPathFlag, //路径是否生成标志) DistanceType _distanceType, //距离类型 ); /*生成路径点*/ std::vector<std::pair<int, int>> PathPoint(); private: /*两点之间的欧式距离*/ //float EuclideanDistance(int _xNode, int _yNode, int _xTarget, int _yTarget); /*向OpenList插入数据*/ Node InsertOpen(int _xVal, int _yVal, int _parentXval, int _parentYval, float _hn, float _gn, float _fn); /*扩展一个节点的周围邻居*/ std::vector<Node> ExpandArray(int _xNodeExpanded, int _yNodeExpanded, float _gNodeExpanded, int _xTarget, int _yTarget, std::vector<std::vector<int>> _mapData, std::vector<Node>_closeList); /*该节点在openList-->multimap中的索引*/ float NodeIndex(std::multimap<float, Node> _openList, int _xNode, int _yNode); /*该节点在closeList-->vector中的索引*/ int CloseNodeIndex(std::vector<Node> _closeList, int _xNode, int _yNode); /*Astar的核心函数*/ void AstarCoreFunction(); /*获得A星算法的路径*/ std::vector<std::pair<int, int>> FindPath(std::vector<Node>_closeList, int _xStart, int _yStart, int _xStop, int _yStop); private: std::multimap<float, Node> m_openList; //openList列表,multimap类型(默认Key是从小到大排序) std::vector<Node> m_closeList; //closeList列表,vector列表 std::vector<std::vector<int>> m_mapData; //地图数据,双vector类型 float m_weightA; //权重a float m_weightB; //权重b int m_xStart; //起点x值 int m_yStart; //起点y值 int m_xStop; //终点x值 int m_yStop; //终点y值 }; } #endif
Astar.cpp
/* @Function:Astar Algorithm Implementation @Time:2022-01-10 @Author:Tang Gu Jie @E-Mail:2822902808@qq.com */ #include "Astar.h" #include <functional> std::function<float(int, int, int, int)>Distance; /*** *@函数功能 计算两点间的欧式距离 ------------------------------------------------ *@参数 _xNode 节点的x值 *@参数 _yNode 节点的y值 *@参数 _xTarget 终点的y值 *@参数 _yTarget 终点的y值 ------------------------------------------------ *@返回值 欧式距离值:根号√((x2-x1)^2+(y2-y1)^2) */ float EuclideanDistance(int _xNode, int _yNode, int _xTarget, int _yTarget) { float d = sqrt(pow(_xNode - _xTarget, 2) + pow(_yNode - _yTarget, 2)); return d; } /*** *@函数功能 计算两点间的曼哈顿距离 ------------------------------------------------ *@参数 _xNode 节点的x值 *@参数 _yNode 节点的y值 *@参数 _xTarget 终点的y值 *@参数 _yTarget 终点的y值 ------------------------------------------------ *@返回值 曼哈顿距离值:|(x2-x1)+(y2-y1)| */ float ManhattanDistance(int _xNode, int _yNode, int _xTarget, int _yTarget) { float d = std::abs(_xNode - _xTarget) + std::abs(_yNode - _yTarget); return d; } ASTAR::CAstar::CAstar(std::vector<std::vector<int>>_mapData, //地图数据,以二维数据存储 int _xStart, //起始点X值 int _yStart, //起始点Y值 int _xStop, //目标点X值 int _yStop, //目标点Y值 float _weightA, //权重a值 float _weightB, //权重b值 PathType _noPathFlag, //路径是否生成标志) DistanceType _distanceType //距离类型 ) :m_mapData(_mapData), m_xStart(_xStart), m_yStart(_yStart),m_xStop(_xStop), m_yStop(_yStop), m_noPathFlag(_noPathFlag),m_weightA(_weightA),m_weightB(_weightB) { switch (_distanceType) { case ASTAR::CAstar::EUCLIDEAN: { std::cout << "使用欧式距离!!!" << std::endl; Distance = EuclideanDistance; break; } case ASTAR::CAstar::MANHANTTAN: { std::cout << "使用曼哈顿距离!!!" << std::endl; Distance = ManhattanDistance; break; } default: break; } } /*** *@函数功能 向openList插入新的节点 ------------------------------------------------ *@参数 _xVal 当前节点的x值 *@参数 _yVal 当前节点的y值 *@参数 _parentXval 当前节点的父节点的x值 *@参数 _parentYval 当前节点的父节点的y值 *@参数 _hn 当前节点的h值(当前节点与终点的关系) *@参数 _gn 当前节点的g值(当前节点与上一个的关系) *@参数 _fn 当前节点的f值(f=g+h) ------------------------------------------------ *@返回值 Node 赋有上述参数的节点 */ ASTAR::Node ASTAR::CAstar::InsertOpen(int _xVal, int _yVal, int _parentXval, int _parentYval, float _hn, float _gn, float _fn) { Node node; node.SnodeX = _xVal; node.SnodeY = _yVal; node.SparentX = _parentXval; node.SparentY = _parentYval; node.Shn = _hn; node.Sgn = _gn; node.Sfn = _fn; return node; } /*** *@函数功能 扩展一个节点的周围邻居节点 ------------------------------------------------ *@参数 _xNodeExpanded 要扩展邻居的节点x值 *@参数 _yNodeExpanded 要扩展邻居的节点y值 *@参数 _gNodeExpanded 要扩展邻居的节点g值 *@参数 _xTarget 终点x值 *@参数 _yTarget 终点y值 *@参数 _mapData 地图数据 *@参数 _closeList 关闭列表 ------------------------------------------------ *@返回值 none */ std::vector<ASTAR::Node> ASTAR::CAstar::ExpandArray(int _xNodeExpanded, int _yNodeExpanded, float _gNodeExpanded, int _xTarget, int _yTarget,std::vector<std::vector<int>> _mapData, std::vector<ASTAR::Node>_closeList) { //节点的8领域,顺序为右下、下、左下、右、左、右上、上、左上 int mapHeight = _mapData.size(); int mapWidth = _mapData[1].size(); Node node; std::vector<Node> nodeList; bool expandFlag = false; for (int k = 1; k >= -1; k--) { for (int j = 1; j >= -1; j--) { if (k != j || j != 0) { int sx = _xNodeExpanded + k; int sy = _yNodeExpanded + j; if ((sx >= 0 && sx < mapHeight) && (sy >= 0 && sy < mapWidth) && _mapData[sx][sy] != 1) { expandFlag = true; for (int i = 0; i < _closeList.size(); i++) { if (sx == _closeList[i].SnodeX && sy == _closeList[i].SnodeY) { expandFlag = false; break; } } if (expandFlag == true) { node.SnodeX = sx; node.SnodeY = sy; node.SparentX = -1; //这个随便填 node.SparentY = -1; //这个随便填 node.Sgn = (_gNodeExpanded + EuclideanDistance(_xNodeExpanded, _yNodeExpanded, sx, sy)); node.Shn = (Distance(_xTarget, _yTarget, sx, sy)); node.Sfn = m_weightA*node.Sgn + m_weightB*node.Shn; nodeList.emplace_back(node); } } } } } return nodeList; } /*** *@函数功能 查询节点(x,y)在openList中的Key索引 ------------------------------------------------ *@参数 _openList 开启列表 *@参数 _xNode 节点x值 *@参数 _yNode 节点y值 ------------------------------------------------ *@返回值 key值索引,注意因为在multimap中,Key可能是重复的,-1.0表示没找到 */ float ASTAR::CAstar::NodeIndex(std::multimap<float, Node> _openList, int _xNode, int _yNode) { for (std::multimap<float, Node>::iterator it = _openList.begin(); it != _openList.end(); it++) { if (it->second.SnodeX == _xNode && it->second.SnodeY == _yNode) { return it->first; } } return -1.0; } /*** *@函数功能 查询节点(x,y)在closeList中的索引 ------------------------------------------------ *@参数 _closeList 关闭列表 *@参数 _xNode 节点x值 *@参数 _yNode 节点y值 ------------------------------------------------ *@返回值 i表示节点在vector中的索引,-1表示没有找到 */ int ASTAR::CAstar::CloseNodeIndex(std::vector<Node> _closeList, int _xNode, int _yNode) { for (int i = 0; i < _closeList.size(); i++) { if (_closeList[i].SnodeX == _xNode && _closeList[i].SnodeY == _yNode) { return i; } } return -1; } /*** *@函数功能 Astar的核心函数,所有的数据处理在这里完成 ------------------------------------------------ *@参数 无 *@参数 无 ------------------------------------------------ *@返回值 无,其实有一个隐藏的输出closeList,最终函数完成后,会完善closeList,最后根据closeList来逆变路径点 */ void ASTAR::CAstar::AstarCoreFunction() { float goalDistance = EuclideanDistance(m_xStart, m_yStart, m_xStop, m_yStop); float pathCost =0.0; float f_ = m_weightA*goalDistance + m_weightB*pathCost; //将起点放入到openList中 Node node = InsertOpen(m_xStart, m_yStart, m_xStart, m_yStart, goalDistance, pathCost, f_); m_openList.insert(std::make_pair(goalDistance, node)); while (true) { //对应伪代码-->if the queue(openList) is empty, return False; break; if (m_openList.size() == 0) break; //对应伪代码-->Remove the node "n" with the lowest f(n) from the priority queue. std::multimap<float, Node>::iterator pos = m_openList.begin(); //multimap键值默认是从小到大排布 int xNodeExpanded = pos->second.SnodeX; int yNodeExpanded = pos->second.SnodeY; float gNodeExpanded = pos->second.Sgn; // 对应伪代码-->Mark node "n" as expanded Node closeNode = pos->second; m_closeList.emplace_back(closeNode); m_openList.erase(pos); //对应伪代码-->if the node "n" is the goal state, return TRUE; break; if (xNodeExpanded == m_xStop && yNodeExpanded == m_yStop) { m_noPathFlag = FINDPATHPOINT; break; } //获得所有节点n的所有“可用”邻居集合 std::vector<Node> nodeList = ExpandArray(xNodeExpanded, yNodeExpanded, gNodeExpanded, m_xStop, m_yStop, m_mapData, m_closeList); for (int i = 0; i < nodeList.size(); i++) { int xNode = nodeList[i].SnodeX; int yNode = nodeList[i].SnodeY; float nodeIndex = NodeIndex(m_openList, xNode, yNode); if (nodeIndex == -1.0) { //对应伪代码-->If node m is not in openList, push node m into openList float gn = gNodeExpanded + EuclideanDistance(xNode, yNode, xNodeExpanded, yNodeExpanded); float hn = Distance(xNode, yNode, m_xStop, m_yStop); float fn = m_weightA*gn+ m_weightB*hn; Node node_ = InsertOpen(xNode, yNode, xNodeExpanded, yNodeExpanded, hn, gn, fn); m_openList.insert(std::make_pair(fn, node_)); } else { //对应伪代码-->If g(m)>g(n)+Cnm //lower_bound返回查找结果第一个迭代器,upper_bound返回最后一个查找结果的下一个位置的迭代器 std::multimap<float, Node>::iterator indexLow = m_openList.lower_bound(nodeIndex); std::multimap<float, Node>::iterator indexUpper = m_openList.upper_bound(nodeIndex); indexUpper--; if (indexLow == indexUpper) { //表示没有重复的键值 if (indexLow->second.Sgn > (gNodeExpanded + EuclideanDistance(xNode, yNode, xNodeExpanded, yNodeExpanded))) { indexLow->second.SparentX = xNodeExpanded; indexLow->second.SparentY = yNodeExpanded; indexLow->second.Sgn = gNodeExpanded + EuclideanDistance(xNode, yNode, xNodeExpanded, yNodeExpanded); indexLow->second.Sfn = m_weightA*indexLow->second.Sgn + m_weightB*indexLow->second.Shn; } } else { //表示有重复的键值 while (indexLow != indexUpper) { if (indexLow->second.SnodeX == xNode && indexLow->second.SnodeY == yNode) break; indexLow++; } if (indexLow->second.Sfn > (gNodeExpanded + EuclideanDistance(xNode, yNode, xNodeExpanded, yNodeExpanded))) { indexLow->second.SparentX = xNodeExpanded; indexLow->second.SparentY = yNodeExpanded; indexLow->second.Sgn = gNodeExpanded + EuclideanDistance(xNode, yNode, xNodeExpanded, yNodeExpanded); indexLow->second.Sfn = m_weightA*indexLow->second.Sgn + m_weightB*indexLow->second.Shn; } } } } } } /*** *@函数功能 路径寻找函数 ------------------------------------------------ *@参数 _closeList 关闭列表 *@参数 _xStart 起点X值 *@参数 _yStart 起点Y值 *@参数 _xStop 终点X值 *@参数 _yStop 终点Y值 ------------------------------------------------ *@返回值 路径节点 类型[(first,second),(),()...] */ std::vector<std::pair<int, int>> ASTAR::CAstar::FindPath(std::vector<Node>_closeList, int _xStart, int _yStart, int _xStop, int _yStop) { std::pair<int, int>path; std::vector<std::pair<int, int>>findPath; path.first = _xStop; path.second = _yStop; findPath.emplace_back(path); int index = CloseNodeIndex(_closeList, _xStop, _yStop); while (true) { if (_closeList[index].SparentX == _xStart && _closeList[index].SparentY == _yStart) { break; } int nodeX = _closeList[index].SparentX; int nodeY = _closeList[index].SparentY; path.first = nodeX; path.second = nodeY; findPath.emplace_back(path); index = CloseNodeIndex(_closeList, nodeX, nodeY); } return findPath; } /*** *@函数功能 对外的A星算法的接口 ------------------------------------------------ *@参数 无 ------------------------------------------------ *@返回值 路径节点 类型[(first,second),(),()...] */ std::vector<std::pair<int, int>> ASTAR::CAstar::PathPoint() { //AstarCoreFunction完善openList与closeList AstarCoreFunction(); //FindPath通过closeList进行寻找路径点 std::vector<std::pair<int, int> > pathPoint = FindPath(m_closeList, m_xStart, m_yStart, m_xStop, m_yStop); return pathPoint; }
特别说明如下:
"头文件" class A { ... public: A(string a) { switch(a) { case "a": flag1=true; break; case "b": flag2=true; break; default: break; } } public: bool flag1=false; bool flag2=false; .... }; "源文件" void test1() { ... } void test2() { ... } void f() { if (flag1==true) test1(); else if(flag2==true) test2(); ... }
openLIst的设计使用std::multimap,以Astar中的 f f f作为键, N o d e Node Node为值,这样就可以巧妙的使用multimap默认是按照键值进行排序的(默认从小到大)。必须使用迭代器取multimap的第一个元素,此时就是 f f f最小的节点。这样的好处,就是在插入节点的时候,节点就已经按照键值 f f f进行排序了。
关于函数距离的选择,其实不管欧式距离还是曼哈顿距离,其实改变的都是估计成本** h ( n ) h(n) h(n)**,对于 g ( n ) g(n) g(n)还是采用欧式距离,可以参考Dijkstra的方法,这个大家注意,我在这当时卡了很长时间,仿真效果也特别奇怪;对于权重a,b的变化,改变的只是 f ( n ) f(n) f(n)值,并不没有改变 g ( n ) g(n) g(n)和 h ( n ) h(n) h(n)。
一个节点的邻居节点使用8领域的方法,依此为右下,下,坐下;右,左;右上,上,左上。
函数的运行部分为PathPoint → \to → AstarCoreFunction+FindPath,具体的函数功能已在程序中标注上,大家可以自行理解。
display.h
/* @Function:Astar Algorithm Display @Time:2022-01-10 @Author:Tang Gu Jie @E-Mail:2822902808@qq.com */ #pragma once #ifndef __DISPLAY__ #define __DISPLAY__ #include<vector> #include<iostream> #include<opencv2/opencv.hpp> #include <string> #define Size 30 #define Menu Size/2 #define Width 1200 #define Height 1200 using namespace std; void Display(vector<pair<int,int> >_pathPoint,vector<vector<int>> _mapData, int _xStart, int _yStart, int _xStop, int _yStop,string _pictureName,bool _saveFlag); #endif
display.cpp
/* @Function:Astar Algorithm Display @Time:2022-01-10 @Author:Tang Gu Jie @E-Mail:2822902808@qq.com */ #include "display.h" //#include "fit.h" void Display(vector<pair<int, int> >_pathPoint, vector<vector<int>>_mapData,int _xStart,int _yStart,int _xStop,int _yStop,string _pictureName,bool _saveFlag) { int ROWS = _mapData.size(); int COLS = _mapData[1].size(); cv::Mat img(Height, Width, CV_8UC3, cv::Scalar(255, 255, 255)); cv::Point left_up, right_bottom; cv::Point point_first, point_second; //中间路径点--->黄色 for (int i = 0; i < _pathPoint.size(); i++) { left_up.x = _pathPoint[i].second * Size; left_up.y = _pathPoint[i].first * Size; right_bottom.x = left_up.x + Size; right_bottom.y = left_up.y + Size; cv::rectangle(img, left_up, right_bottom, cv::Scalar(0, 255, 255), CV_FILLED, 8, 0);//path yellow(full) } //障碍物--->黑色,起点--->蓝色,终点--->红色 for (int i = 0; i<ROWS; i++) { for (int j = 0; j<COLS; j++) { left_up.x = j * Size; //存储数组的列(j)对应矩形的x轴 left_up.y = i * Size; right_bottom.x = left_up.x + Size; right_bottom.y = left_up.y + Size; if (_mapData[i][j]) { cv::rectangle(img, left_up, right_bottom, cv::Scalar(0, 0, 0), CV_FILLED, 8, 0);//obstacles balck } else { if (i == _xStart&&j == _yStart) cv::rectangle(img, left_up, right_bottom, cv::Scalar(255, 0, 0), CV_FILLED, 8, 0);//start point blue(full) else if (i == _xStop&&j == _yStop) cv::rectangle(img, left_up, right_bottom, cv::Scalar(0, 0, 255), CV_FILLED, 8, 0);//goal point red(full) } } } //中间线--->黄色 for (int i = 1; i < COLS; i++) { point_first.x = i * Size; point_first.y = 1 * Size; point_second.x = i *Size; point_second.y = (ROWS - 1) * Size; cv::line(img, point_first, point_second, cv::Scalar(141,238,238), 2, 2); } for (int i = 1; i < ROWS;i++) { point_first.x = 1 * Size; point_first.y = i * Size; point_second.x = (COLS - 1) * Size; point_second.y = i * Size; cv::line(img, point_first, point_second, cv::Scalar(141,238,238), 2, 2); } //路径线--->黄色 point_first.x = _yStop * Size + Menu; point_first.y = _xStop * Size + Menu; for (int i = 0; i < _pathPoint.size(); i++) { left_up.x = _pathPoint[i].second * Size; left_up.y = _pathPoint[i].first * Size; point_second.x = left_up.x + Menu; point_second.y = left_up.y + Menu; cv::line(img, point_first, point_second, cv::Scalar(0, 0, 0), 2, 4); point_first = point_second; } if (_saveFlag) { string str1 = ".png"; _pictureName.append(str1); cv::imwrite(_pictureName, img); cout << "save png success" << endl; } cv::imshow(_pictureName, img); cv::waitKey(0); }
显示的实现是基于OpenCV3.4的,传入路径节点即可。C++下面的显示没有matlab或者python的方便,这是我借鉴一个网上博主写的,ROS下路径规划的插件底层使用C++实现的,其实最后还是需要C++来实现。
其中蓝色表示起点,红色表示终点,黑色为障碍物,白色为可通行部分,黑色的线为Astar得到的路径。
仿真一
|
|
|
|
仿真二
|
|
上述代码都是自己慢慢调试出来的,可能存在一些问题,发现问题的小伙伴加我QQ:2822902808,大家一起交流进步,谢谢。
理论部分参考我的上一篇博客:(一)路径规划算法—Graph Search Basis
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。