做地图开发会遇到一个常规需求,就是获取当前经纬度对应的海拔高度,也叫做高程值,很遗憾各大地图厂商都未提供接口获取,可能是有明文规定,不能地图中提供对应的海拔高度值,于是需要另想他法,尽管谷歌地图在线的api接口是提供了海拔高度值,但是懂得都懂,国内哪里还能用谷歌地图?完全用不了啊,就算你开发者能用,99.99%的用户也是用不了,而且必须是在线,没有离线也不行。
通过查阅资料得知有个gdal的开源库,支持读取tif文件获取高程值,使用过了是可以,但是编译复杂,尝试过很多次直接集成源码的方式,终归失败,源码数量太多了,两千多个,也有不少的依赖,比如依赖zip和sqlite啥的,所以最终放弃这个方案,后面又找了一些类似tinytiff的开源库,都是用来读取tif文件的,但是没有看到获取高程值接口,而且只支持普通的tif文件。
在折腾的快要放弃的时候,往往就是离成功最近的时候,思索着有没有更简便的方式,而且跨平台,毕竟只是想获取个高程值,引入个这么大的库完全没有必要,有点杀鸡用牛刀的感觉。在经过使用gdal函数接口的过程中,规则都是从图片的像素坐标获取灰度值,然后这个灰度值对应的就是海拔,网上很少有人提到这点,其实这点极其重要,没搞过的人一直云里雾里的折腾编译gdal等开源库。后面还发现对应tif的还有个txt的文本文件,打开内容看到最前面写着左上角的经纬度坐标和水平和垂直比例尺等参数值,然后就是逐行的每个像素点的海拔值,这就非常美妙了,要的就是这种文件呢,自己写个算法去处理也是分分分钟的事情。一气呵成打完收工,自此不仅离线使用,速度纳秒级别,还支持所有平台,就一个类文件100行左右,不要太完美啊。
二、相关代码 #include "frmmain.h"#include "ui_frmmain.h"#include "qthelper.h"#include "gdalobj.h"#include "demread.h"frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain){ ui->setupUi(this); this->initForm(); //on_btnOpen_clicked(); QMetaObject::invokeMethod(this, "on_btnOpen_clicked", Qt::QueuedConnection);}frmMain::~frmMain(){ delete ui;}bool frmMain::eventFilter(QObject *watched, QEvent *event){ if (watched == ui->labImage) { if (event->type() == QEvent::MouseButtonPress) { pressed = true; lastPos = ((QMouseEvent *)event)->globalPos(); } else if (event->type() == QEvent::MouseButtonRelease) { pressed = false; } else if (event->type() == QEvent::MouseMove) { QMouseEvent *mouseEvent = (QMouseEvent *)event; if (pressed) { QPoint pos = mouseEvent->globalPos(); QScrollBar *scrollBarx = ui->scrollArea->horizontalScrollBar(); QScrollBar *scrollBary = ui->scrollArea->verticalScrollBar(); int offsetx = pos.x() - lastPos.x(); int offsety = pos.y() - lastPos.y(); scrollBarx->setValue(scrollBarx->value() - offsetx); scrollBary->setValue(scrollBary->value() - offsety); lastPos = pos; } else { QPoint pos = mouseEvent->pos(); ui->txtPos->setText(QString("%1, %2").arg(pos.x()).arg(pos.y())); int value; QSize size; QPointF lnglat; if (ui->cboxType->currentIndex() == 0) { if (ui->btnOpen->isEnabled()) { value = DemRead::getAltitude(pos); size = QSize(DemRead::width, DemRead::height); lnglat = DemRead::getLngLat(pos); } } else { value = gdal->getAltitude(pos); size = gdal->getSize(); lnglat = gdal->getLngLat(pos); } if (size.width() > 0) { ui->txtSize->setText(QString("%1 x %2").arg(size.width()).arg(size.height())); ui->txtLnglat->setText(QString("%1, %2").arg(lnglat.x()).arg(lnglat.y())); ui->txtAltitude->setText(QString("%1 米").arg(value)); } } } } return QWidget::eventFilter(watched, event);}void frmMain::initForm(){ pressed = false; lastPos = QPoint(); txtFile = QtHelper::appPath() + "/data/dem001.txt"; tifFile = QtHelper::appPath() + "/data/dem001.tif"; gdal = new GdalObj(this);#ifndef Q_CC_MSVC ui->cboxType->setCurrentIndex(0); ui->cboxType->setEnabled(false);#else ui->cboxType->setCurrentIndex(1);#endif ui->cboxInput->addItem("89.2883, 42.7083"); ui->cboxInput->addItem("121.4703, 31.2339"); ui->cboxInput->addItem("121.5527, 25.0557"); ui->cboxInput->addItem("121.1792, 26.4213"); ui->cboxInput->setCurrentIndex(0); QPixmap pixmap(tifFile); ui->labImage->installEventFilter(this); ui->labImage->setPixmap(pixmap); ui->labImage->setAttribute(Qt::WA_MouseTracking); ui->txtSize->setText(QString("%1 x %2").arg(pixmap.width()).arg(pixmap.height()));}void frmMain::readFinsh(){ ui->btnOpen->setEnabled(true); ui->btnGet->setEnabled(true); ui->txtSize->setText(QString("%1 x %2").arg(DemRead::width).arg(DemRead::height));}void frmMain::on_btnOpen_clicked(){ if (ui->cboxType->currentIndex() == 0) { //这里线程执行/防止卡主界面 ui->btnOpen->setEnabled(false); ui->btnGet->setEnabled(false); static QFutureWatcher<void> watcher; connect(&watcher, SIGNAL(finished()), this, SLOT(readFinsh())); watcher.setFuture(QtConcurrent::run(DemRead::readFile, txtFile)); } else { if (gdal->open(tifFile)) { QSize size = gdal->getSize(); ui->txtSize->setText(QString("%1 x %2").arg(size.width()).arg(size.height())); } }}void frmMain::on_btnGet_clicked(){ QString text = ui->cboxInput->lineEdit()->text(); QStringList list = text.split(","); QPointF lnglat(list.at(0).toDouble(), list.at(1).toDouble()); int value; QPoint pos; if (ui->cboxType->currentIndex() == 0) { pos = DemRead::getPos(lnglat); value = DemRead::getAltitude(lnglat); } else { pos = gdal->getPos(lnglat); value = gdal->getAltitude(lnglat); } ui->txtLnglat->setText(text); ui->txtAltitude->setText(QString("%1 米").arg(value)); ui->txtPos->setText(QString("%1, %2").arg(pos.x()).arg(pos.y())); //移动到对应图片中心点 ui->scrollArea->horizontalScrollBar()->setValue(pos.x() - (ui->scrollArea->width() / 2)); ui->scrollArea->verticalScrollBar()->setValue(pos.y() - (ui->scrollArea->height() / 2));}三、相关地址文件地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名:bin_map.zip国内站点:https://gitee.com/feiyangqingyun国际站点:https://github.com/feiyangqingyun四、效果图