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的流动相为气体(通常为高纯氦),这就要求被分析物必须能够气化,而生物样本中很多内源性代谢物都含有极性基团,具有沸点高、不易气化特…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
