QT、C++实现地图导航系统(mapSystem)
文章目录
- 地图导航系统
- 项目应用背景
- 技术栈选择
- 数据处理
- 算法实现
- 界面实现
- 源码展示
- 成果展示
- 源码下载 (免费)
地图导航系统
项目应用背景
电子地图导航系统的主要目的是为用户提供精确、实时的导航和位置信息,以帮助他们在城市或地区内轻松找到目的地。
①提供用户友好的界面,使用户能够轻松输入起点和目的地,并获取最佳的导航路线。
②支持用户个性化设置,例如选择不同的地图样式、导航偏好和关注的兴趣点,以满足不同用户的需求。
③提供可靠的地图数据,包括道路、建筑物、公共设施和兴趣点的详细信息,以帮助用户更好地理解其周围环境。
技术栈选择
用哈希map以及设置类进行数据的存储
对于地图导航系统,我们需要考虑到数据的存储防止内存的溢出,地图中的数据多并且杂需要进行数据清洗。对于我们需要的数据提取出来并存储下来。这样我们需要考虑数据的存储方式而且需要在数据调用时可以更快的将某条数据进行处理。
Floyd路径算法计算最短路径
考虑到该算法可以实现全局最短路径的搜索;既适用于有向图又适用于无向图;采用动态规划思想,通过逐步优化子问题的解决方案来找到整体的最优解;适用性广泛, Floyd算法适用于各种类型的图,包括稠密图和稀疏图,它不依赖于特定的图结构,因此可以用于多种应用领域。
QT实现图形界面开发
QT的图形界面实现简单容易;模块化,可扩展,QT的模块化架构允许你仅包含你需要的模块,从而减小应用程序的大小。
数据处理
Openstreetmap 数据osm数据的格式的特点,虽然是osm数据格式但是获取的数据格式xml可以通过解析xml数据格式的方式进行解析。
数据解析: 使用QT中的xml解析库函数进行数据的解析。读取其中的数据挑选出其中的ID 号,Lat维度,Lon经度。
算法实现
真实经纬度坐标结构体类型
经纬度坐标转换函数
构造解析OSM(XMl)类
数据类型转化
根据经纬度计算点与点之间距离
画出道路图
构造Floyd算法函数
界面实现
在Widget标出村落
共54个村落标注点,接收起点终点,进行画线
构造放大和缩小地图功能槽函数
源码展示
.pro文件
#-------------------------------------------------
#
# Project created by QtCreator 2023-09-22T10:19:55
#
#-------------------------------------------------QT += core gui
QT += xml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = cheshi
TEMPLATE = app# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mainwindow.cppHEADERS += \mainwindow.hFORMS += \mainwindow.uiRESOURCES += \resourcefile.qrc
mainwindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QPainter>
#include <QXmlStreamReader>
#include <QFile>
#include <unordered_map>
#include <QDebug>
#include <cmath>
#include <vector>
#include <QString>
#include <set>
#include <QGraphicsScene>
#include <QGraphicsEllipseItem>
#include <QGraphicsTextItem>const int INF = 10000000;
int ressssssssss(int x);namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);~MainWindow();//void on_InButton_clicked();//void on_OutButton_clicked();void showComBox();void zoomInOut();void floyd(int n);void initDist();void getPath(int start, int end);void initMap();void click();
private slots:void InButton_clicked();void OutButton_clicked();void showShortPath();void shortBtnclicked();protected:void paintEvent(QPaintEvent *event) override;
private:Ui::MainWindow *ui;};
struct coordinates //对应的经纬度坐标(double)
{int id;double lon;double lat;
};
struct coordinatesStr //对应的经纬度坐标(QString)
{QString id;QString lon;QString lat;
};
struct coordinatesInt //对应的经纬度坐标(int)
{QString id;int x;int y;
};class resolve_xml
{
public:double degreesToRadians(double degrees);double radiansToDegrees(double radians);double calculateDistance(coordinates node1, coordinates node2);void saveNode(int id,coordinates node);void strChangeDouble(coordinatesStr node);void findCommonNode();void changeCoor(QString strId);int imortant();std::map<QString,coordinatesInt>doubleCoorMap;std::vector<coordinatesInt>doubleCoor;std::vector<coordinatesInt>doubleWay;double minLat; //最小纬度double maxLat; //最大经度double minLon;double maxLon;
};
class Graph {
public:int vertices = 54;std::vector<int>result;std::vector<std::vector<int>> distance;std::vector<std::vector<int>> next;void addEdge(int source, int destination, int weight) {distance[source][destination] = weight;next[source][destination] = destination;}void floydWarshall() {//distance.assign(54, std::vector<int>(54, INF));next.assign(54, std::vector<int>(54, -1));for (int k = 0; k < vertices; ++k) {for (int i = 0; i < vertices; ++i) {for (int j = 0; j < vertices; ++j) {if (distance[i][k] != INF && distance[k][j] != INF && distance[i][k] + distance[k][j] < distance[i][j]) {distance[i][j] = distance[i][k] + distance[k][j];next[i][j] = next[i][k];}}}}}void printShortestPath(int start, int end) {if (distance[start][end] == INF) {//cout << "No path exists from Node " << start << " to Node " << end << endl;return;}//cout << "Shortest Path from Node " << start << " to Node " << end << ": ";result.push_back(start);while (start != end) {start = next[start][end];//cout << " -> " << start;result.push_back(start);}}
};#endif // MAINWINDOW_H
mainwindow.cpp文件
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <map>
#include <QGraphicsScene>
#include <QGraphicsEllipseItem>
#include <QGraphicsTextItem>const int MAXN = 10000000;Graph grap;
int n = 54;
//std::vector<std::vector<int>> prev(n, std::vector<int>(n, -1));
std::map<QString,coordinatesStr>mp;
std::map<QString,coordinates>doubleMap;
std::vector<QString>commonNode;
std::map<QString,QString>mapVillage;
std::map<QString,std::vector<QString>>mapWay;
std::map<QString,int>villageToInt;
std::map<int,QString>villageToString;
std::vector<QString>nodeVillage;//ui->graphicsView->setScene(scene);int dist[54][54]; // 保存点与点之间的距离
int prev[100][100]; // 保存路径上的前一个点
std::vector<int> path; // 存储最短路径上的点
int Matrix[54][54] = {0};
resolve_xml Xml;double resolve_xml::degreesToRadians(double degrees) {return degrees * M_PI / 180;
}
double resolve_xml::radiansToDegrees(double radians) {return radians * 180 / M_PI;
}
double resolve_xml::calculateDistance(coordinates node1, coordinates node2) { //经纬度坐标double dLat = degreesToRadians(node2.lat - node1.lat); //Haversine公式double dLon = degreesToRadians(node2.lon - node1.lon);double a = std::sin(dLat / 2) * std::sin(dLat / 2) +std::cos(degreesToRadians(node1.lat)) * std::cos(degreesToRadians(node2.lat)) *std::sin(dLon / 2) * std::sin(dLon / 2);double c = 2 * std::atan2(std::sqrt(a), std::sqrt(1 - a));double distance = 6378137 * c;return distance;
}void resolve_xml::strChangeDouble(coordinatesStr node)
{coordinates coor;coor.id = node.id.toInt();coor.lat = node.lat.toDouble();coor.lon = node.lon.toDouble();doubleMap[node.id] = coor;
}void resolve_xml::findCommonNode() //查找公共交点
{QFile file(":/qrc/map.osm");if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){qDebug() << "无法打开XML文件.";//exit(0);}QXmlStreamReader xml(&file);std::set<QString> wayNodes;int wayCount = 0;bool flag = false;while (!xml.atEnd() && !xml.hasError()) {QXmlStreamReader::TokenType token = xml.readNext();if (token == QXmlStreamReader::StartElement) {if (xml.name() == "way") {flag = true;}else if (xml.name() == "nd" && flag == true) {QString ndRef = xml.attributes().value("ref").toString();if (wayNodes.find(ndRef) != wayNodes.end()) {commonNode.push_back(ndRef);}else {wayNodes.insert(ndRef);}}else if(xml.name() == "relation"){flag = false;}else if(xml.name() == "member"){flag = false;}}}file.close();
}void resolve_xml::changeCoor(QString strId)
{coordinates coo = doubleMap[strId];coordinatesInt cooint ;int width = (maxLon - minLon) * 10000;int length = (maxLat - minLat) * 10000;int x = (maxLat - coo.lat ) * 10000 ;int y = (coo.lon - minLon) * 10000 ;cooint.id = strId;cooint.x = y;cooint.y = x;Xml.doubleCoor.push_back(cooint);Xml.doubleCoorMap[strId] = cooint;
}
/*void resolve_xml::saveNode(int id,coordinates node)
{mp[id] = node;
}*/
int resolve_xml:: imortant()
{std::vector<QString>strNode;std::vector<QString>strWay;coordinatesStr coorStr; //QString类型经纬度的结构体QString wayId; //way的IdQString tagKey;QString tagValue;QString nodeId; //node的IDQString nodeLon; //node的经度QString nodeLat; //node的纬度QFile fileName(":/qrc/map.osm");if (!fileName.open(QIODevice::ReadOnly | QIODevice::Text)){qDebug() << "无法打开XML文件.";return 1;}QXmlStreamReader xml(&fileName);while (!xml.atEnd() && !xml.hasError()) {QXmlStreamReader::TokenType token = xml.readNext();if (token == QXmlStreamReader::StartElement) {if(xml.name() == "node"){nodeId = xml.attributes().value("id").toString();nodeLon = xml.attributes().value("lon").toString();nodeLat = xml.attributes().value("lat").toString();coorStr.id = nodeId;coorStr.lat = nodeLat;coorStr.lon = nodeLon;mp[nodeId] = coorStr;strNode.push_back(nodeId);}else if (xml.name() == "way") {// 提取way元素的id属性值strWay.clear();wayId = xml.attributes().value("id").toString();//qDebug() << "Way ID:" << wayId;} else if (xml.name() == "nd") {// 提取nd元素的ref属性值QString ndRef = xml.attributes().value("ref").toString();strWay.push_back(ndRef);mapWay[wayId] = strWay;//qDebug() << "ND Ref:" << ndRef;} else if (xml.name() == "tag") {// 提取tag元素的k和v属性值QString str1 = tagKey;QString str2 = tagValue;tagKey = xml.attributes().value("k").toString();tagValue = xml.attributes().value("v").toString();if(tagValue == "village"){nodeVillage.push_back(str2);mapVillage[str2] = nodeId;}//qDebug() << "Tag Key:" << tagKey << ", Value:" << tagValue;}else if(xml.name() == "bounds"){//提取数据中的最大最小经纬度Xml.minLat = xml.attributes().value("minlat").toString().toDouble();Xml.minLon = xml.attributes().value("minlon").toString().toDouble();Xml.maxLat = xml.attributes().value("maxlat").toString().toDouble();Xml.maxLon = xml.attributes().value("maxlon").toString().toDouble();}}}if (xml.hasError()){qDebug() << "XML解析错误: " << xml.errorString();return 1;}for(auto it = mp.begin();it != mp.end();it++) //将QString的经纬度转化成double类型的经纬度{QString Id = it->first;coordinatesStr jw = it->second;Xml.strChangeDouble(jw);Xml.changeCoor(Id);//qDebug()<<Id;//qDebug()<<jw.lat<<" "<<jw.lon;}for(auto it = mapWay.begin();it != mapWay.end();it++){std::vector<QString> Strway = it->second;for(int i = 0;i < Strway.size();i++){QString Qstr = Strway[i];double x = doubleMap[Qstr].lat;double y = doubleMap[Qstr].lon;minLat = std::min(minLat,x);minLon = std::min(minLon,y);maxLat = std::max(maxLat,x);maxLon = std::max(maxLon,y);}}// qDebug()<<"xxxx"<<minLat<<minLon<<maxLat<<maxLon; //输出最大最小经纬度for(auto it = mapWay.begin();it != mapWay.end();it++) //保存所有way的点{QString way = it->first;std::vector<QString> Strway = it->second;for(int i = 0;i < Strway.size();i++){QString Qstr = Strway[i];//Xml.changeCoor(Qstr);}}for(auto it = mapWay.begin();it != mapWay.end();it++) //根据经纬度计算点与点之间距离,连接成路{QString way = it->first;//qDebug()<<way;std::vector<QString> Strway = it->second;//qDebug()<<"way nodeNumber:"<<Strway.size();int distanceWay = 0;for(int i = 1;i < Strway.size();i++){QString Qstr1 = Strway[i-1];QString Qstr2 = Strway[i];coordinates node1 = doubleMap[Qstr1];coordinates node2 = doubleMap[Qstr2];distanceWay += (int)Xml.calculateDistance(node1,node2);}//qDebug()<<"way distance:"<<distanceWay;}for(auto it = mapVillage.begin();it != mapVillage.end();it++){//qDebug()<<"village: "<<it->first<<"village nodeId: "<<it->second;}for(int i = 0;i < nodeVillage.size();i++){QString sst = nodeVillage[i];villageToInt[sst] = i;villageToString[i] = sst;//qDebug()<<sst<<i;}/*QString str = "121.1458065";bool ok;double value = str.toDouble(&ok);if (ok) {qDebug() << "Converted value:" << value;} else {qDebug() << "Conversion failed.";}*/Xml.findCommonNode();for(int i = 0;i < commonNode.size();i++){//qDebug()<<"commonNode"<<commonNode[i];}//qDebug()<<"commonNode size"<<commonNode.size()<<"way size:"<<mapWay.size()<<"village size"<<mapVillage.size();//qDebug()<<"---"<<Xml.doubleCoor.size();fileName.close();return 0;
}MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);
}
MainWindow::~MainWindow()
{delete ui;
}void MainWindow::showComBox()
{for(auto it = mapVillage.begin();it != mapVillage.end();it++){QString stt = it->first;ui->startBox->addItem(stt);}for(auto it = mapVillage.begin();it != mapVillage.end();it++){QString stt = it->first;ui->endBox->addItem(stt);}qDebug()<<mapVillage.size();
}void MainWindow::zoomInOut()
{// 连接放大按钮connect(ui->InButton, &QPushButton::clicked, this, &MainWindow::InButton_clicked);// 连接缩小按钮connect(ui->outButton, &QPushButton::clicked, this, &MainWindow::OutButton_clicked);//连接最短路径按钮connect(ui->shortBtn, &QPushButton::clicked, this, &MainWindow::shortBtnclicked);
}void MainWindow::InButton_clicked()
{qDebug() << "InButton was clicked or triggered!";double scaleFactor = 1.15;ui->graphicsView->scale(scaleFactor, scaleFactor);
}void MainWindow::OutButton_clicked()
{double scaleFactor = 1.15;ui->graphicsView->scale(1.0 / scaleFactor, 1.0 / scaleFactor);
}void MainWindow::showShortPath()
{QGraphicsScene *scene = ui->graphicsView->scene();ui->graphicsView->setRenderHint(QPainter::Antialiasing); //抗锯齿功能,画的线更润换// ui->graphicsView->setScene(scene);std::vector<QPointF>shortPath;QPainterPath pathVillage;for(int i = 0;i < path.size();i++){int intId = path[i];QString StrID = villageToString[intId];coordinatesInt coorvillage = Xml.doubleCoorMap[mapVillage[StrID]];QPointF points;points.setX(coorvillage.x);points.setY(coorvillage.y);shortPath.push_back(points);}qDebug()<<shortPath.size();int distance;for(int i = 1;i < path.size();i++){int intId1 = path[i-1];int intId2 = path[i];QString StrID1 = villageToString[intId1];QString StrID2 = villageToString[intId2];coordinates node1 = doubleMap[mapVillage[StrID1]];coordinates node2 = doubleMap[mapVillage[StrID2]];distance = Xml.calculateDistance(node1,node2);}QString setdist = QString::number(distance);setdist += " meter";ui->showDist->setText(setdist);/*if(shortPath.size() != 0){pathVillage.moveTo(shortPath[0]);for(int i = 1;i <shortPath.size();i++){pathVillage.lineTo(shortPath[i]);}QGraphicsPathItem *pathItems = new QGraphicsPathItem(pathVillage);scene->addItem(pathItems);// 可选:设置道路的样式QPen roadPenVillage(Qt::green, 2); // 示例:绿色,线宽为3pathItems->setPen(roadPenVillage);}*/if(!scene) {scene = new QGraphicsScene(this);ui->graphicsView->setScene(scene);}for( int i = 1; i < shortPath.size();i++){QPen pen(Qt::red);pen.setWidth(3);QPointF point1 = shortPath[i-1];QPointF point2 = shortPath[i];scene->addLine(point1.x(), point1.y(), point2.x(), point2.y(), pen); // 这里使用红色画笔}
}void MainWindow::floyd(int n)
{for(int k = 0; k < n; k++) {for(int i = 0; i < n; i++) {for(int j = 0; j < n; j++) {if(dist[i][k] != INT_MAX && dist[k][j] != INT_MAX && dist[i][j] > dist[i][k] + dist[k][j]) {dist[i][j] = dist[i][k] + dist[k][j];prev[i][j] = k;}}}}
}void MainWindow::initDist()
{n = 54;for(int i = 0; i < n; i++) {for(int j = 0; j < n; j++) {if(i == j) dist[i][j] = 0;else if ( j % 2 == 0){QString s1 = villageToString[i];QString s2 = villageToString[j];coordinates node1 = doubleMap[mapVillage[s1]];coordinates node2 = doubleMap[mapVillage[s2]];int distancesss = Xml.calculateDistance(node1,node2);qDebug()<<"s="<<distancesss;dist[i][j] = distancesss;}/*else if (Matrix[i][j] == 0){dist[i][j] = INT_MAX;}*/prev[i][j] = i;}}
}void MainWindow::getPath(int start, int end)
{//if(start != end) getPath(start, prev[start][end]);//path.push_back(end);//path.clear();/*QString cur1 = ui->startBox->currentText();QString cur2 = ui->endBox->currentText();int current1 = villageToInt[cur1];int current2 = villageToInt[cur2];path.push_back(current1);while (current1 != current2) {current1 = prev[current1][current2];path.push_back(current1);}*//*if (prev[start][end] == -1) {return ;}path.push_back(start);while (start != end) {start = prev[start][end];path.push_back(start);}*//*if (start == end || prev[start][end] == -1) {// 如果已经到达终点或者无法到达,返回包含起点的路径return {start};} else {// 递归调用,将路径从起点到 next[start][end] 和从 next[start][end] 到终点连接起来std::vector<int> path1 = getPath(start, prev[start][end]);std::vector<int> path2 = getPath(prev[start][end], end);// 合并两个路径path1.insert(path1.end(), path2.begin() + 1, path2.end());return path1;}*/if(start != end) getPath(start, prev[start][end]);path.push_back(end);
}void MainWindow::initMap()
{Matrix[0][32] = Matrix[32][0] = 1;Matrix[0][53] = Matrix[53][0] = 1;Matrix[0][48] = Matrix[48][0] = 1;Matrix[0][47] = Matrix[47][0] = 1;Matrix[0][49] = Matrix[49][0] = 1;Matrix[0][50] = Matrix[50][0] = 1;Matrix[0][51] = Matrix[51][0] = 1;Matrix[0][36] = Matrix[36][0] = 1;Matrix[0][35] = Matrix[35][0] = 1;Matrix[0][34] = Matrix[34][0] = 1;Matrix[0][37] = Matrix[37][0] = 1;Matrix[0][40] = Matrix[40][0] = 1;Matrix[0][50] = Matrix[50][0] = 1;Matrix[2][33] = Matrix[33][2] = 1;Matrix[2][3] = Matrix[3][2] = 1;Matrix[2][4] = Matrix[4][2] = 1;Matrix[4][3] = Matrix[3][4] = 1;Matrix[4][33] = Matrix[33][4] = 1;Matrix[5][8] = Matrix[8][5] = 1;Matrix[5][9] = Matrix[9][5] = 1;Matrix[5][10] = Matrix[10][5] = 1;Matrix[7][6] = Matrix[6][7] = 1;Matrix[7][4] = Matrix[4][7] = 1;Matrix[11][43] = Matrix[43][11] = 1;Matrix[11][45] = Matrix[45][11] = 1;Matrix[11][42] = Matrix[42][11] = 1;Matrix[12][13] = Matrix[13][12] = 1;Matrix[12][14] = Matrix[14][12] = 1;Matrix[12][15] = Matrix[15][12] = 1;Matrix[16][20] = Matrix[20][16] = 1;Matrix[17][19] = Matrix[19][17] = 1;Matrix[17][18] = Matrix[18][17] = 1;Matrix[20][17] = Matrix[17][20] = 1;Matrix[20][18] = Matrix[18][20] = 1;Matrix[20][19] = Matrix[19][20] = 1;Matrix[21][22] = Matrix[22][21] = 1;Matrix[21][23] = Matrix[23][21] = 1;Matrix[21][26] = Matrix[26][21] = 1;Matrix[26][27] = Matrix[27][26] = 1;Matrix[26][24] = Matrix[24][26] = 1;Matrix[24][25] = Matrix[25][24] = 1;Matrix[25][31] = Matrix[31][25] = 1;Matrix[28][29] = Matrix[29][28] = 1;Matrix[28][30] = Matrix[30][28] = 1;Matrix[34][36] = Matrix[36][34] = 1;Matrix[35][36] = Matrix[36][35] = 1;Matrix[40][34] = Matrix[34][40] = 1;Matrix[40][37] = Matrix[37][40] = 1;Matrix[41][37] = Matrix[37][41] = 1;Matrix[41][34] = Matrix[34][41] = 1;Matrix[44][39] = Matrix[39][44] = 1;Matrix[39][38] = Matrix[38][39] = 1;
}void MainWindow::click()
{test newobj(this);newobj.useMainWindowUI();}
void MainWindow::paintEvent(QPaintEvent *event)
{QMainWindow::paintEvent(event); // 调用父类的 paintEvent 以确保其他部分绘制正确/*QPainter painter(this);QPen pen;pen.setWidth(2);painter.setPen(pen);qDebug()<<" "<<Xml.doubleCoor.size();for(int i = 0;i <Xml.doubleCoor.size();i++){coordinatesInt it = Xml.doubleCoor[i];pen.setColor(Qt::red); // 设置画笔颜色painter.drawPoint(it.x, it.y); // 在坐标 (50, 50) 上绘制一个点}*/QGraphicsScene *scene = new QGraphicsScene(this);ui->graphicsView->setScene(scene);ui->graphicsView->setRenderHint(QPainter::Antialiasing); //抗锯齿// 示例点位和名字/*int len = nodeVillage.size();QList<QPointF> points;for(int i = 0;i < len;i++){QString villageNode = mapVillage[nodeVillage[i]];QPoint ppp;coordinatesInt coo = Xml.doubleCoorMap[villageNode];ppp.setX(coo.x);ppp.setY(coo.y);points.push_back(ppp);//qDebug()<<points.size();}for(int i = 0; i < nodeVillage.size(); ++i){// 为每个点位创建一个小的椭圆QGraphicsEllipseItem *ellipse = scene->addEllipse(points[i].x() - 5, points[i].y() - 5, 10, 10, QPen(Qt::black), QBrush(Qt::red));// 创建一个文本项以显示名字QGraphicsTextItem *text = scene->addText(nodeVillage[i]);text->setPos(points[i].x() + 10, points[i].y() - text->boundingRect().height() / 2);}*/std::vector<std::vector<QPointF>>roads;for(auto it = mapWay.begin();it != mapWay.end();it++){std::vector<QString> vectorStr = it->second;std::vector<QPointF>roadWay;for(int i = 0;i < vectorStr.size();i++){QString wayStr = vectorStr[i];coordinatesInt coorWay;coorWay = Xml.doubleCoorMap[wayStr];QPoint pointWay;pointWay.setX(coorWay.x);pointWay.setY(coorWay.y);roadWay.push_back(pointWay);}roads.push_back(roadWay);roadWay.clear();}for (const std::vector<QPointF> &road : roads) {QPainterPath pathsss;pathsss.moveTo(road[0]);for (int i = 1; i < road.size(); ++i){pathsss.lineTo(road[i]);}QGraphicsPathItem *pathItem = new QGraphicsPathItem(pathsss);scene->addItem(pathItem);// 可选:设置道路的样式QPen roadPen(Qt::blue, 2); // 示例:蓝色,线宽为2pathItem->setPen(roadPen);}// 示例点位和名字int len = nodeVillage.size();QList<QPointF> points;for(int i = 0;i < len;i++){QString villageNode = mapVillage[nodeVillage[i]];QPoint ppp;coordinatesInt coo = Xml.doubleCoorMap[villageNode];ppp.setX(coo.x);ppp.setY(coo.y);points.push_back(ppp);//qDebug()<<points.size();}for(int i = 0; i < nodeVillage.size(); ++i){// 为每个点位创建一个小的椭圆QGraphicsEllipseItem *ellipse = scene->addEllipse(points[i].x() - 5, points[i].y() - 5, 10, 10, QPen(Qt::black), QBrush(Qt::red));// 创建一个文本项以显示名字QGraphicsTextItem *text = scene->addText(nodeVillage[i]);text->setPos(points[i].x() + 10, points[i].y() - text->boundingRect().height() / 2);}
}
class CustomGraphicsView : public QGraphicsView //放大缩小只能点击,不能使用滚轮
{Q_OBJECT
public:explicit CustomGraphicsView(QWidget* parent = nullptr): QGraphicsView(parent) {}protected:void wheelEvent(QWheelEvent* event) override{}
};void MainWindow::shortBtnclicked()
{//initMap();/*for(int i = 0;i < 54;i++){for(int j = 0;j < 54;j++){if(i == j){grap.addEdge(i,j,0);}else{if(Matrix[i][j] == 1){QString s1 = villageToString[i];QString s2 = villageToString[j];coordinates node1 = doubleMap[mapVillage[s1]];coordinates node2 = doubleMap[mapVillage[s2]];int distancesss = Xml.calculateDistance(node1,node2);qDebug()<<"s="<<distancesss;//dist[i][j] = distancesss;grap.addEdge(i,j,distancesss);}else{grap.addEdge(i,j,MAXN);}}}}grap.floydWarshall();qDebug()<<grap.result.size();path = grap.result;*/initDist();floyd(54);QString textBox1 = ui->startBox->currentText();QString textBox2 = ui->endBox->currentText();int idx1 = villageToInt[textBox1];int idx2 = villageToInt[textBox2];//grap.printShortestPath(idx1,idx2);getPath(idx1,idx2);showShortPath();//path.clear();
}
成果展示
源码下载 (免费)
链接: https://pan.baidu.com/s/1Ai4m-X6GwLmkpbQpESRRDw
提取码: 0703
更多资料尽在 GitHub 欢迎各位读者去Star
⭐学术交流群Q 754410389 持续更新中~~~
相关文章:
QT、C++实现地图导航系统(mapSystem)
文章目录 地图导航系统项目应用背景技术栈选择数据处理算法实现界面实现源码展示成果展示源码下载 (免费) 地图导航系统 项目应用背景 电子地图导航系统的主要目的是为用户提供精确、实时的导航和位置信息,以帮助他们在城市或地区内轻松找到…...
STM32 定时器介绍--通用、高级定时器
目录 高级定时器 1.功能框图 1-时钟源 2-时基单元 3-输入捕获 4-输出比较 2.输入捕获的应用 3.输出比较的应用 4.初始化结构体 1-时基初始化结构体 2-输出比较结构体 3-PWM信号 周期和占空比的计算--以通用定时器为例 4-输入捕获结构体 5-断路和死区初始化结构体…...
淘宝天猫渠道会员购是什么意思?如何开通天猫淘宝渠道会员购有什么用?
淘宝天猫渠道会员购是什么意思? 淘宝天猫渠道会员购与淘宝天猫粉丝福利购意思基本相同,都可以领取淘宝天猫大额内部隐藏优惠券、通过草柴APP开通绑定渠道会员还可以获得购物返利。 草柴APP如何绑定开通淘宝天猫渠道会员? 1、手机下载安装「…...
(Note)机器学习面试题
机器学习 1.两位同事从上海出发前往深圳出差,他们在不同时间出发,搭乘的交通工具也不同,能准确描述两者“上海到深圳”距离差别的是: A.欧式距离 B.余弦距离 C.曼哈顿距离 D.切比雪夫距离 S:D 1. 欧几里得距离 计算公式&#x…...
思科:iOS和iOSXe软件存在漏洞
思科警告说,有人试图利用iOS软件和iOSXe软件中的一个安全缺陷,这些缺陷可能会让一个经过认证的远程攻击者在受影响的系统上实现远程代码执行。 中严重程度的脆弱性被追踪为 CVE-2023-20109 ,并以6.6分得分。它会影响启用Gdoi或G-Ikev2协议的软件的所有版本。 国际知名白帽黑客…...
CCF CSP认证 历年题目自练Day19
题目一 试题编号: 201812-1 试题名称: 小明上学 时间限制: 1.0s 内存限制: 512.0MB 问题描述: 题目背景 小明是汉东省政法大学附属中学的一名学生,他每天都要骑自行车往返于家和学校。为了能尽可能充…...
Java 开发环境配置
在本章节中我们将为大家介绍如何搭建Java开发环境。 目录 window系统安装java 下载JDK 配置环境变量 JAVA_HOME 设置 PATH设置 CLASSPATH 设置 测试JDK是否安装成功 Linux,UNIX,Solaris,FreeBSD环境变量设置 流行 Java 开发工具 使…...
[2023.09.26]: JsValue的转换体验与as关键字的浅析
昨天解决了焦点问题,今天就开始搬砖了。本以为可以一帆风顺,但是还是遇到了几个问题,不过还好,都被一一解决,这里我分享一下JsValue的转换体验以及关键字as的使用浅析。 场景描述 我是在什么情况下遇到JsValue的转换…...
SpringBoot Validation入参校验国际化
在 Spring Boot 中,可以使用 Validation 和国际化来实现对入参的校验。 常用的校验 NotNull验证字段值不能为 nullNotEmpty验证字段值不能为 null 或空字符串NotBlank验证字符串字段值不能为空、null,并且必须至少包含一个非空白字符Size验证字符串、…...
树莓集团涉足直播产业园区运营,成都直播产业园区再添黑马
树莓集团涉足成都直播产业园运营领域,这一消息引起了业界的广泛关注。在这个无限可能的直播领域中,树莓集团将与上市公司德商产投紧密合作,立志为成都直播行业的发展注入新的活力。成都天府蜂巢直播产业园推行着一系列创新的政策措施…...
中小学教师ChatGPT的23种用法
原文:中小学教师ChatGPT的23种用法 近日,ChatGPT引发舆论风暴,火遍全球。作为一款生成式人工智能软件,ChatGPT可以就任何议题生成文本,完成包括回答问题,撰写文章、论文、诗歌在内的多种工作。各界盛赞其“…...
Ubuntu性能分析-ftrace 底层驱动
1、框架介绍 ftrace内核驱动可以分为几部分:ftrace framework,RingBuffer,debugfs,Tracepoint,各种Tracer。 ftrace框架是整个ftrace功能的纽带,包括对内和的修改,Tracer的注册,RingBuffer的控制等等。 RingBuffer是静态动态ftrace的载体。 debugfs则提供了用户空间…...
网盘搜索引擎:点亮知识星空,畅享数字宝藏!
大家好!作为一名资深的网络产品运营人员,我今天要向大家介绍一款让你受益匪浅的神奇工具——网盘搜索引擎!它可以帮助你免费搜索查询各种云盘共享资源,包括影视作品、纪录片、小说、动漫等等。现在,我们急需网络流量&a…...
Mysql以key-val存储、正常存储的区别
场景 你作为一个服务端工程师,假设产品要求设计这么一个页面,页面上包含很多模块,每个模块都可以单独进行变更,有些模块是富文本。 实现方式有很多,我们来聊比较常用的两种,看看mysql的表如何设计。 第一…...
MySQL 索引优化实践(单表)
目录 一、前言二、表数据准备三、常见业务无索引查询耗时测试3.1、通过订单ID / 订单编号 查询指定订单3.2、查询订单列表 四、订单常见业务索引优化实践4.1、通过唯一索引和普通索引优化通过订单编号查询订单信息4.2、通过普通联合索引优化订单列表查询4.2.1、分析查询字段的查…...
react create-react-app v5配置 px2rem (暴露 eject方式)
环境信息: create-react-app v5 “react”: “^18.2.0” “postcss-plugin-px2rem”: “^0.8.1” 配置步骤: 我这个方式是 npm run eject 暴露 webpack配置的方法 1.安装 postcss-plugin-px2rem 和 lib-flexible cnpm install postcss-plugin-px2rem…...
AVL树的实现及原理
目录 AVL树的由来 AVL的实现原理 左单旋 右单旋 先左后右 先右后左 总结 AVL树的由来 查找,无论在什么情况下都与我们息息相关。在我们学习数组阶段学习到了线性查找,可是它的效率很低下,又演变出来了二分查找,它的效率非常…...
NestJs和Vite使用monorepo管理项目中,需要使用共享的文件夹步骤
NestJs和Vite使用monorepo管理项目中,需要使用共享的文件夹步骤 1 首先需要将nest-cli打包的功能通过webpack接管 nest-cli.json文件内容 {"$schema": "https://json.schemastore.org/nest-cli","collection": "nestjs/schematics",…...
我用PYQT5做的第一个实用的上位机项目(三)
基本的程序框架: 因为自己不是专业的程序员,只是一个搞电气控制的“票友”,所以尽量减少手动输入 代码量,能在Qt Dsigner里面完成的组态就不要放在代码里面完成。 在框架的建设方面,尽量做到集中和整合,位…...
代谢组学分析平台(二)
GC/MS分析生物样本为何要衍生化处理?有哪些衍生化的方法? GC的流动相为气体(通常为高纯氦),这就要求被分析物必须能够气化,而生物样本中很多内源性代谢物都含有极性基团,具有沸点高、不易气化特…...
【统计学】Top-down自上而下的角度模型召回率recall,精确率precision,特异性specificity,模型评价
最近在学 logistic regression model,又遇见了几个之前的老面孔。 召回率recall, 精确率precision,特异性spcificity,准确率accuracy,True positive rate,false positive rate等等名词在学习之初遇到的困难在于&#x…...
AutoDL使用tensorboard
目录 一,训练形成log文件 二. 切换logs目录 三,在AutoPanel中访问TensorBoard 一,训练形成log文件 例子: from torch.utils.tensorboard import SummaryWriter import numpy as npwriter SummaryWriter() for x in range(1, …...
代谢组学分析手段(一)
核磁共振技术(Nuclear Magnetic Resonance, NMR) 定义:指核磁矩不为零的原子核在外磁场的作用下,核自旋能级发生塞曼分裂,共振吸收某一特定频率的射频辐射的物理过程。 优点: (1)…...
网络基础入门(网络基础概念详解)
本篇文章主要是对网络初学的概念进行解释,可以让你对网络有一个大概整体的认知。 文章目录 一、简单认识网络 1、1 什么是网络 1、2 网络分类 二、网络模型 2、1OSI七层模型 2、1、1 简单认识协议 2、1、2 OSI七层模型解释 2、2 TCP/IP五层(或四层)模型 三、网络传…...
简化任务调度与管理:详解XXL-Job及Docker Compose安装
在现代应用程序开发中,任务调度和管理是至关重要的一部分。XXL-Job是一个强大的分布式任务调度平台,它使得任务的调度和管理变得更加轻松和高效。本文将介绍XXL-Job的基本概念,并详细演示如何使用Docker Compose进行快速安装和配置。 什么是X…...
QByteArray字节数组
QByteArray字节数组 文章目录 QByteArray字节数组1.1 QByteArray类基本使用说明1.2 设置数组字节大小1.3 返回数组大小1.4 将数据转为其他类型1.5 将数据转为C语言的字符指针返回1.6 数组数据追加1.7 清除数组数据为指定值1.8 数组数据插入1.9 删除指定位置指定长度的数据1.10 …...
ubuntu20.04.3中qt程序界面嵌套另一个qt界面
先上代码 #include "mainwindow.h" #include <QApplication> #include <iostream> using namespace std; #ifdef _WIN32// Windows 平台的代码 #include <windows.h> #elif __linux__// Linux 平台的代码// ...#include <X11/Xlib.h> #else…...
【chainlit】使用chainlit部署chatgpt
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…...
测开 | Vue速查知识点
文章目录 Vue知识1. Vue 概述2. Vue 代码格式3. Vue 指令3.1 v-bind & v-model3.2 v-on3.3 v-if和v-show3.4 v-for 4. 生命周期 Vue知识 1. Vue 概述 简介: Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的 渐进式框架。与其他…...
数据结构——二叉树的基本概念及顺序存储(堆)
目录 一.前言 二.树概念及结构 2.1 树的概念 2.2 树的相关概念 2.3 树的表现 2.4 树在实际中的应用(表示文件系统的目录树结构) 三.二叉树的概念及结构 3.1 概念 3.2 特殊的二叉树 3.3 二叉树的性质 3.4 二叉树的存储结构 3.4.1 顺序存储 3…...
wordpress能做手机站吗/百合seo培训
对于一个只有3、5个人的小团队,在时间很紧的情况下,文档什么的肯定是能省则省啦。不过,有两个文档是绝对不能省的。不但不能省,还要尽全力把它们做好,并且保持更新。这两个文档就是:使用Power Designer制作…...
做蛋糕网站的 实训报告图/营销推广的工具有哪些
memcached安装存档日期:2019年5月15日 | 首次出版:2009年9月15日 在由两部分组成的关于Memcached和Grails的上半部分的前半部分中,作者James Goodwill向您介绍了开源缓存解决方案memcached。 本文涵盖的主题包括安装,配置&#x…...
关于网站建设的请示范文/山东seo推广
Loadrunner一直被业内认为是最好用的性能测试工具,行业大哥大, 但是用过Loadrunner的朋友都知道,工具功能的确牛,但实际使用过程中总会有一些困扰新手的问题,无法录制脚本, 如遇到Loadrunner不支持的IE版本、对Chrome、…...
有哪些网站可以学做糕点的/重庆关键词搜索排名
react-native-app-introreact-native-app-intro是一个react native组件,实现了一个视觉差效果欢迎页,基于react-native-swiper,类似与谷歌应用程序比如Sheet,Drive,Docs等。支持iOS、Android安装基础使用你可以使用pag…...
苏州公司网站建设/浏览器下载安装2023版本
2019独角兽企业重金招聘Python工程师标准>>> GNOME开发人员Bastien Nocera在他最新的博客文章中谈到了他在过去几个星期内在Fedora Linux操作系统的蓝牙堆栈上实施的增强功能。开发者已经为Fedora Linux蓝牙软件包提交的补丁,让用户在GNOME桌面环境中可以…...
广州优化网站关键词/seo项目培训
总括 MATLAB和pyplot有当前的图形(figure)和当前的轴(axes)的概念,所有的作图命令都是对当前的对象作用。可以通过gca()获得当前的axes(轴),通过gcf()获得当前的图形(fig…...