Dijkstra 算法的实现方案

news2024/11/15 17:35:29

下面是一个基于 Dijkstra 算法的实现方案,能够在 DEM(数字高程模型)数据上进行寻路,并满足以下需求:

使用 Qt C++ 编写;
规避 DEM 中的障碍物;
支持指定起点和终点;
使用 GDAL 库读取 DEM 文件;
输出路径到 TXT 文件;
输出的坐标为地理坐标(例如经纬度),而不是像素坐标。
前置条件
GDAL 库:确保你的开发环境已经安装了 GDAL 库,并在 Qt 项目中正确配置了 GDAL 库路径。
Qt 环境:确保已经安装 Qt 并配置开发环境。
实现步骤

  1. 初始化项目并引入 GDAL
    在 Qt 项目的 .pro 文件中引入 GDAL 库和必要的标志:

QT += core
CONFIG += c++11
LIBS += -lgdal
2. 代码实现
下面是实现该功能的代码。

#include <QCoreApplication>
#include <gdal_priv.h>
#include <iostream>
#include <vector>
#include <queue>
#include <fstream>

struct Node {
    int x, y;
    double cost;
    bool operator>(const Node& other) const { return cost > other.cost; }
};

class DEMPathFinder {
public:
    DEMPathFinder(const std::string &demPath);
    bool findPath(double startLon, double startLat, double endLon, double endLat, const std::string &outputPath);

private:
    double geoTransform[6];
    int width, height;
    std::vector<std::vector<double>> elevationData;
    std::vector<std::vector<bool>> obstacles;

    bool loadDEM(const std::string &demPath);
    bool isValid(int x, int y);
    double calculateCost(int x, int y, int nx, int ny);
    void pixelToGeo(int x, int y, double &lon, double &lat);
    void geoToPixel(double lon, double lat, int &x, int &y);
};

DEMPathFinder::DEMPathFinder(const std::string &demPath) {
    GDALAllRegister();
    loadDEM(demPath);
}

bool DEMPathFinder::loadDEM(const std::string &demPath) {
    GDALDataset *dataset = (GDALDataset*) GDALOpen(demPath.c_str(), GA_ReadOnly);
    if (dataset == nullptr) return false;

    dataset->GetGeoTransform(geoTransform);
    width = dataset->GetRasterXSize();
    height = dataset->GetRasterYSize();

    elevationData.resize(height, std::vector<double>(width));
    obstacles.resize(height, std::vector<bool>(width, false));

    GDALRasterBand *band = dataset->GetRasterBand(1);
    for (int y = 0; y < height; ++y) {
        band->RasterIO(GF_Read, 0, y, width, 1, elevationData[y].data(), width, 1, GDT_Float64, 0, 0);
        for (int x = 0; x < width; ++x) {
            if (elevationData[y][x] == -9999) { // 假设 -9999 表示障碍物
                obstacles[y][x] = true;
            }
        }
    }
    GDALClose(dataset);
    return true;
}

bool DEMPathFinder::isValid(int x, int y) {
    return x >= 0 && x < width && y >= 0 && y < height && !obstacles[y][x];
}

double DEMPathFinder::calculateCost(int x, int y, int nx, int ny) {
    return 1.0 + std::abs(elevationData[ny][nx] - elevationData[y][x]);
}

void DEMPathFinder::pixelToGeo(int x, int y, double &lon, double &lat) {
    lon = geoTransform[0] + x * geoTransform[1] + y * geoTransform[2];
    lat = geoTransform[3] + x * geoTransform[4] + y * geoTransform[5];
}

void DEMPathFinder::geoToPixel(double lon, double lat, int &x, int &y) {
    x = static_cast<int>((lon - geoTransform[0]) / geoTransform[1]);
    y = static_cast<int>((lat - geoTransform[3]) / geoTransform[5]);
}

bool DEMPathFinder::findPath(double startLon, double startLat, double endLon, double endLat, const std::string &outputPath) {
    int startX, startY, endX, endY;
    geoToPixel(startLon, startLat, startX, startY);
    geoToPixel(endLon, endLat, endX, endY);

    std::priority_queue<Node, std::vector<Node>, std::greater<Node>> pq;
    std::vector<std::vector<double>> dist(height, std::vector<double>(width, std::numeric_limits<double>::infinity()));
    std::vector<std::vector<std::pair<int, int>>> prev(height, std::vector<std::pair<int, int>>(width, {-1, -1}));

    pq.push({startX, startY, 0});
    dist[startY][startX] = 0;

    int dx[] = {1, -1, 0, 0};
    int dy[] = {0, 0, 1, -1};

    while (!pq.empty()) {
        Node node = pq.top(); pq.pop();
        if (node.x == endX && node.y == endY) break;

        for (int i = 0; i < 4; ++i) {
            int nx = node.x + dx[i];
            int ny = node.y + dy[i];

            if (isValid(nx, ny)) {
                double newCost = node.cost + calculateCost(node.x, node.y, nx, ny);
                if (newCost < dist[ny][nx]) {
                    dist[ny][nx] = newCost;
                    pq.push({nx, ny, newCost});
                    prev[ny][nx] = {node.x, node.y};
                }
            }
        }
    }

    std::vector<std::pair<double, double>> path;
    for (int x = endX, y = endY; x != -1 && y != -1; ) {
        double lon, lat;
        pixelToGeo(x, y, lon, lat);
        path.push_back({lon, lat});
        auto [px, py] = prev[y][x];
        x = px;
        y = py;
    }

    std::ofstream outFile(outputPath);
    for (auto it = path.rbegin(); it != path.rend(); ++it) {
        outFile << it->first << ", " << it->second << std::endl;
    }

    return !path.empty();
}

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    DEMPathFinder pathFinder("path/to/your/dem/file.tif");
    if (pathFinder.findPath(102.0, 25.0, 103.0, 26.0, "output_path.txt")) {
        std::cout << "Path found and saved to output_path.txt" << std::endl;
    } else {
        std::cout << "Path not found" << std::endl;
    }

    return app.exec();
}

代码说明
加载 DEM 文件:使用 GDAL 加载 DEM 文件,并获取像素坐标到地理坐标的转换参数。
障碍物检测:假设 DEM 数据中的 -9999 表示障碍物,可根据需要修改。
Dijkstra 算法:使用优先队列进行路径搜索,寻找代价最低的路径。
地理坐标转换:实现了像素坐标和地理坐标的转换。
输出路径:将路径的地理坐标保存到 txt 文件中。
注意事项
将 “path/to/your/dem/file.tif” 替换为你的 DEM 文件路径;
GDAL 安装和库链接应配置正确,否则可能出现加载失败的情况。
这段代码可以在 DEM 数据上寻找到避开障碍物的最优路径,并输出路径的地理坐标。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2240969.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

矩阵中的路径(dfs)-acwing

题目 23. 矩阵中的路径 - AcWing题库 代码 class Solution { public://以每一个坐标作为dfs起点bool hasPath(vector<vector<char>>& matrix, string str) {for (int i 0; i < matrix.size(); i )for (int j 0; j < matrix[i].size(); j )if (dfs(…

WEB攻防-通用漏洞SQL注入sqlmapOracleMongodbDB2等

SQL注入课程体系&#xff1a; 1、数据库注入-access mysql mssql oracle mongodb postgresql 2、数据类型注入-数字型 字符型 搜索型 加密型&#xff08;base64 json等&#xff09; 3、提交方式注入-get post cookie http头等 4、查询方式注入-查询 增加 删除 更新 堆叠等 …

android studio 更改gradle版本方法(备忘)

如果出现类似以下&#xff1a; Your build is currently configured to use Java 17.0.11 and Gradle 6.1.1. 或者类似&#xff1a; Failed to calculate the value of task ‘:app:compileDebugJavaWithJavac‘ property ‘options.generatedSo 消息时需要修改gradle版本&…

设计模式之装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)

前言&#xff1a; 两个本想描述一样的意思的词&#xff0c;只因一字只差就让人觉得一个是好牛&#xff0c;一个好搞笑。往往我们去开发编程写代码时也经常将一些不恰当的用法用于业务需求实现中&#xff0c;但却不能意识到。一方面是由于编码不多缺少较大型项目的实践&#xff…

日志:中文 URI 参数乱码之 encodeURI、encodeURIComponent、escape 作为 Ajax 中文参数编码给 ASP 的记录

前面提到的了 ASP 输出 UTF-8 编码的中文不定时出现乱码的解决方案&#xff1a;ASP页面改为UTF-8编码后&#xff0c;刷新页面中文输入输出不定时乱码终极解决方案 今天遇到的则是输入 UTF-8 编码中文 URI 参数乱码的问题&#xff0c;第一次可以&#xff0c;刷新后取得的输入参…

Intern大模型训练营(八):Llamaindex RAG 实践

1. 基于 LlamaIndex 构建自己的 RAG 知识库 首先在Intern Studio中申请30% A100的开发机。 进入开发机后&#xff0c;创建新的conda环境&#xff0c;命名为 llamaindex&#xff0c;在命令行模式下运行&#xff1a; conda create -n llamaindex python3.10 复制完成后&#…

leetcode104:二叉树的最大深度

给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3示例 2&#xff1a; 输入&#xff1a;root [1,null,2] 输出…

Unity插件-Smart Inspector 免费的,接近虚幻引擎的蓝图Tab管理

习惯了虚幻的一张蓝图&#xff0c;关联所有Tab &#xff08;才发现Unity&#xff0c;的Component一直被人吐槽&#xff0c;但实际上是&#xff1a;本身结构Unity 的GameObject-Comp结构&#xff0c;是好的不能再好了&#xff0c;只是配上 smart Inspector就更清晰了&#xff0…

RDIFramework.NET CS敏捷开发框架 V6.1发布(.NET6+、Framework双引擎、全网唯一)

RDIFramework.NET C/S敏捷开发框架V6.1版本迎来重大更新与调整&#xff0c;全面重新设计业务逻辑代码&#xff0c;代码量减少一半以上&#xff0c;开发更加高效。全系统引入全新字体图标&#xff0c;整个界面焕然一新。底层引入最易上手的ORM框架SqlSugar&#xff0c;让开发更加…

运行springBlade项目历程

框架选择 官网地址&#xff1a;https://bladex.cn 使用手册&#xff1a;https://www.kancloud.cn/smallchill/blade 常见问题&#xff1a;https://sns.bladex.cn/article-14966.html 问答社区&#xff1a;https://sns.bladex.cn 环境配置 存在jdk8的情况下安装jdk17 jdk17gi…

图形 2.7 LDR与HDR

LDR与HDR B站视频&#xff1a;图形 2.7 LDR与HDR 文章目录 LDR与HDR基本概念LDRHDR为什么需要HDR不同显示屏的差异 Unity中的HDRCamera HDR 设置Lightmap HDR设置拾色器 HDR设置优缺点 HDR与Bloom通常Bloom渲染步骤渲染出原图获取图像中较亮部分高斯模糊叠加 Unity中Bloom渲染…

单片机设计智能翻译手势识别系统

目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 电路图采用Altium Designer进行设计&#xff1a; 三、实物设计图 四、程序源代码设计 五、获取资料内容 前言 在全球化的浪潮下&#xff0c;语言的多样性也为人们的交流带来了不小的挑战…

Python调用API翻译Excel中的英语句子并回填数据

一、问题描述 最近遇到一个把Excel表中两列单元格中的文本读取&#xff0c;然后翻译&#xff0c;再重新回填到单元格中的案例。大约有700多行&#xff0c;1400多个句子&#xff0c;一个个手动复制粘贴要花费不少时间&#xff0c;而且极易出错。这时&#xff0c;我们就可以请出…

TypeORM在Node.js中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 TypeORM在Node.js中的应用 TypeORM在Node.js中的应用 TypeORM在Node.js中的应用 引言 TypeORM 概述 定义与特点 发展历程 TypeO…

干货分享之Python爬虫与代理

嗨伙伴们&#xff0c;今天是干货分享哦&#xff0c;可千万不要错过。今天小蝌蚪教大家使用phthon时学会巧妙借用代理ip来更好地完成任务。 让我们先了解一下为什么说咱们要用爬虫代理ip呢&#xff0c;那是因为很多网站为了防止有人过度爬取数据&#xff0c;对自身资源造成损害…

腾讯云双11最强攻略:如何选购优惠产品,薅最划算的羊毛

目录 一、首选优惠产品 二、可参与拼团的产品&#xff1a;超值组合优惠 三、不推荐购买的产品 四、注意事项与优惠最大化技巧 总结 腾讯云的双11活动力度空前&#xff0c;适合个人开发者、中小企业甚至是大型公司。这份攻略将帮你了解该购买哪些产品&#xff0c;不该购买哪…

labview实现功能性全局变量

在日常的项目中&#xff0c;笔者最长使用的就是全局变量&#xff0c;这样用起来不仅省心省力&#xff0c;而且传值也很方便&#xff0c;没有什么阻碍&#xff0c;想要传什么数据一根线拉过去就可以了。后面才知道如果一直使用全局变量会导致读写卡死的状态&#xff0c;而且还有…

软件工程笔记二—— 软件生存期模型

目录 瀑布模型 瀑布模型的特点 阶段间具有顺序性和依赖性。 推迟实现的观点 质量保证的观点 瀑布模型的优点 瀑布模型的缺点 快速原型模型 快速原型模型的优点 快速原型模型的缺点 增量模型 增量模型的优点 增量构件开发 螺旋模型 完整的螺旋模型&#xff08;顺…

C++ —— 哈希详解 - 开散列与闭散列

目录 1. 哈希的概念 1.1 直接定址法 1.2 哈希冲突 1.3 负载因子 1.4 哈希函数 1.4.1 除法散列法/除留余数法 1.4.2 乘法散列法 1.4.3 全域散列法 1.5 处理哈希冲突 1.5.1 开放定址法&#xff08;闭散列&#xff09; 1. 线性探测&#xff08;挨着查找&#xff09; 2.…

微波无源器件 OMT1 一种用于倍频程接收机前端的十字转门四脊正交模耦合器(24-51GHz)

摘要&#xff1a; 我们报道了一种用于天文学射电望远镜的毫米波波长接收机的一种十字转门四脊OMT的设计&#xff0c;制造和实测结果。此四脊OMT被直接兼容到一个四脊馈电喇叭来实现可以拓展矩形波导单模带宽的双极化低噪声接收机。使用了24-51GHz的带宽&#xff0c;OMT证实了0.…