mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-06-27 03:29:16 +02:00
Added support for downloading DEM tiles
This commit is contained in:
@ -16,7 +16,7 @@
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <private/qzipreader_p.h>
|
||||
#include "common/coordinates.h"
|
||||
#include "common/rectc.h"
|
||||
#include "dem.h"
|
||||
|
||||
|
||||
@ -66,19 +66,26 @@ static qreal height(const Coordinates &c, const QByteArray *data)
|
||||
}
|
||||
|
||||
|
||||
QString DEM::_dir;
|
||||
QCache<DEM::Key, QByteArray> DEM::_data;
|
||||
|
||||
QString DEM::baseName(const Key &key)
|
||||
QString DEM::Tile::latStr() const
|
||||
{
|
||||
const char ns = (key.lat() >= 0) ? 'N' : 'S';
|
||||
const char ew = (key.lon() >= 0) ? 'E' : 'W';
|
||||
|
||||
return QString("%1%2%3%4.hgt").arg(ns)
|
||||
.arg(qAbs(key.lat()), 2, 10, QChar('0')).arg(ew)
|
||||
.arg(qAbs(key.lon()), 3, 10, QChar('0'));
|
||||
const char ns = (_lat >= 0) ? 'N' : 'S';
|
||||
return QString("%1%2").arg(ns).arg(qAbs(_lat), 2, 10, QChar('0'));
|
||||
}
|
||||
|
||||
QString DEM::Tile::lonStr() const
|
||||
{
|
||||
const char ew = (_lon >= 0) ? 'E' : 'W';
|
||||
return QString("%1%2").arg(ew).arg(qAbs(_lon), 3, 10, QChar('0'));
|
||||
}
|
||||
|
||||
QString DEM::Tile::baseName() const
|
||||
{
|
||||
return QString("%1%2.hgt").arg(latStr(), lonStr());
|
||||
}
|
||||
|
||||
QString DEM::_dir;
|
||||
QCache<DEM::Tile, QByteArray> DEM::_data;
|
||||
|
||||
QString DEM::fileName(const QString &baseName)
|
||||
{
|
||||
return QDir(_dir).absoluteFilePath(baseName);
|
||||
@ -87,6 +94,7 @@ QString DEM::fileName(const QString &baseName)
|
||||
void DEM::setDir(const QString &path)
|
||||
{
|
||||
_dir = path;
|
||||
_data.clear();
|
||||
}
|
||||
|
||||
qreal DEM::elevation(const Coordinates &c)
|
||||
@ -94,11 +102,11 @@ qreal DEM::elevation(const Coordinates &c)
|
||||
if (_dir.isEmpty())
|
||||
return NAN;
|
||||
|
||||
Key k(qFloor(c.lon()), qFloor(c.lat()));
|
||||
Tile tile(qFloor(c.lon()), qFloor(c.lat()));
|
||||
|
||||
QByteArray *ba = _data[k];
|
||||
QByteArray *ba = _data[tile];
|
||||
if (!ba) {
|
||||
QString bn(baseName(k));
|
||||
QString bn(tile.baseName());
|
||||
QString fn(fileName(bn));
|
||||
QString zn(fn + ".zip");
|
||||
|
||||
@ -106,22 +114,30 @@ qreal DEM::elevation(const Coordinates &c)
|
||||
QZipReader zip(zn, QIODevice::ReadOnly);
|
||||
ba = new QByteArray(zip.fileData(bn));
|
||||
qreal ele = height(c, ba);
|
||||
_data.insert(k, ba);
|
||||
_data.insert(tile, ba);
|
||||
return ele;
|
||||
} else {
|
||||
QFile file(fn);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qWarning("%s: %s", qPrintable(file.fileName()),
|
||||
qPrintable(file.errorString()));
|
||||
_data.insert(k, new QByteArray());
|
||||
_data.insert(tile, new QByteArray());
|
||||
return NAN;
|
||||
} else {
|
||||
ba = new QByteArray(file.readAll());
|
||||
qreal ele = height(c, ba);
|
||||
_data.insert(k, ba);
|
||||
_data.insert(tile, ba);
|
||||
return ele;
|
||||
}
|
||||
}
|
||||
} else
|
||||
return height(c, ba);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
QDebug operator<<(QDebug dbg, const DEM::Tile &tile)
|
||||
{
|
||||
dbg.nospace() << "Tile(" << tile.baseName() << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
||||
|
@ -8,18 +8,23 @@
|
||||
|
||||
class QString;
|
||||
class Coordinates;
|
||||
class RectC;
|
||||
|
||||
class DEM
|
||||
{
|
||||
private:
|
||||
class Key {
|
||||
public:
|
||||
class Tile {
|
||||
public:
|
||||
Key(int lon, int lat) : _lon(lon), _lat(lat) {}
|
||||
Tile(int lon, int lat) : _lon(lon), _lat(lat) {}
|
||||
|
||||
int lon() const {return _lon;}
|
||||
int lat() const {return _lat;}
|
||||
|
||||
bool operator==(const Key &other) const
|
||||
QString lonStr() const;
|
||||
QString latStr() const;
|
||||
QString baseName() const;
|
||||
|
||||
bool operator==(const Tile &other) const
|
||||
{
|
||||
return (_lon == other._lon && _lat == other._lat);
|
||||
}
|
||||
@ -28,22 +33,23 @@ private:
|
||||
int _lon, _lat;
|
||||
};
|
||||
|
||||
static QString baseName(const Key &key);
|
||||
static QString fileName(const QString &baseName);
|
||||
|
||||
static QString _dir;
|
||||
static QCache<Key, QByteArray> _data;
|
||||
|
||||
public:
|
||||
static void setDir(const QString &path);
|
||||
static qreal elevation(const Coordinates &c);
|
||||
|
||||
friend HASH_T qHash(const Key &key);
|
||||
private:
|
||||
static QString fileName(const QString &baseName);
|
||||
|
||||
static QString _dir;
|
||||
static QCache<Tile, QByteArray> _data;
|
||||
};
|
||||
|
||||
inline HASH_T qHash(const DEM::Key &key)
|
||||
inline HASH_T qHash(const DEM::Tile &tile)
|
||||
{
|
||||
return (qHash(key.lon()) ^ qHash(key.lat()));
|
||||
return (qHash(tile.lon()) ^ qHash(tile.lat()));
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
QDebug operator<<(QDebug dbg, const DEM::Tile &tile);
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
#endif // DEM_H
|
||||
|
102
src/data/demloader.cpp
Normal file
102
src/data/demloader.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
#include <QtMath>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include "common/rectc.h"
|
||||
#include "demloader.h"
|
||||
|
||||
|
||||
#define DOWNLOAD_LIMIT 32
|
||||
|
||||
static QList<DEM::Tile> tiles(const RectC &rect)
|
||||
{
|
||||
QList<DEM::Tile> list;
|
||||
|
||||
if (!rect.isValid())
|
||||
return list;
|
||||
|
||||
for (int i = qFloor(rect.top()); i >= qFloor(rect.bottom()); i--)
|
||||
for (int j = qFloor(rect.left()); j <= qFloor(rect.right()); j++)
|
||||
list.append(DEM::Tile(j, i));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static bool isZip(const QUrl &url)
|
||||
{
|
||||
QFileInfo fi(url.fileName());
|
||||
return (fi.suffix().toLower() == "zip");
|
||||
}
|
||||
|
||||
|
||||
DEMLoader::DEMLoader(const QString &dir, QObject *parent)
|
||||
: QObject(parent), _dir(dir)
|
||||
{
|
||||
_downloader = new Downloader(this);
|
||||
connect(_downloader, &Downloader::finished, this, &DEMLoader::finished);
|
||||
}
|
||||
|
||||
bool DEMLoader::loadTiles(const RectC &rect)
|
||||
{
|
||||
QList<DEM::Tile> tl(tiles(rect));
|
||||
QList<Download> dl;
|
||||
|
||||
/* Create the user DEM dir only when a download is requested as it will
|
||||
override the global DEM dir. */
|
||||
if (!QDir().mkpath(_dir)) {
|
||||
qWarning("%s: %s", qPrintable(_dir), "Error creating DEM directory");
|
||||
return false;
|
||||
}
|
||||
/* This also clears the DEM data cache which is necessary to use the data
|
||||
from the downloaded DEM tiles. */
|
||||
DEM::setDir(_dir);
|
||||
|
||||
for (int i = 0; i < tl.size(); i++) {
|
||||
const DEM::Tile &t = tl.at(i);
|
||||
QString fn(tileFile(t));
|
||||
QString zn(fn + ".zip");
|
||||
|
||||
if (!(QFileInfo(zn).exists() || QFileInfo(fn).exists())) {
|
||||
QUrl url(tileUrl(t));
|
||||
dl.append(Download(url, isZip(url) ? zn : fn));
|
||||
}
|
||||
}
|
||||
|
||||
if (dl.size() > DOWNLOAD_LIMIT) {
|
||||
qWarning("DEM download limit exceeded. Limit/requested: %u/%u.",
|
||||
DOWNLOAD_LIMIT, dl.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
return _downloader->get(dl, _authorization);
|
||||
}
|
||||
|
||||
bool DEMLoader::checkTiles(const RectC &rect) const
|
||||
{
|
||||
QList<DEM::Tile> tl(tiles(rect));
|
||||
|
||||
for (int i = 0; i < tl.size(); i++) {
|
||||
const DEM::Tile &t = tl.at(i);
|
||||
QString fn(tileFile(t));
|
||||
QString zn(fn + ".zip");
|
||||
|
||||
if (!(QFileInfo(zn).exists() || QFileInfo(fn).exists()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QUrl DEMLoader::tileUrl(const DEM::Tile &tile) const
|
||||
{
|
||||
QString url(_url);
|
||||
|
||||
url.replace("$lon", tile.lonStr());
|
||||
url.replace("$lat", tile.latStr());
|
||||
|
||||
return QUrl(url);
|
||||
}
|
||||
|
||||
QString DEMLoader::tileFile(const DEM::Tile &tile) const
|
||||
{
|
||||
return _dir + QLatin1Char('/') + tile.baseName();
|
||||
}
|
37
src/data/demloader.h
Normal file
37
src/data/demloader.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef DEMLOADER_H
|
||||
#define DEMLOADER_H
|
||||
|
||||
#include <QObject>
|
||||
#include "common/downloader.h"
|
||||
#include "dem.h"
|
||||
|
||||
class RectC;
|
||||
|
||||
class DEMLoader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DEMLoader(const QString &dir, QObject *parent = 0);
|
||||
|
||||
void setUrl(const QString &url) {_url = url;}
|
||||
void setAuthorization(const Authorization &authorization)
|
||||
{_authorization = authorization;}
|
||||
|
||||
bool loadTiles(const RectC &rect);
|
||||
bool checkTiles(const RectC &rect) const;
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
private:
|
||||
QUrl tileUrl(const DEM::Tile &tile) const;
|
||||
QString tileFile(const DEM::Tile &tile) const;
|
||||
|
||||
Downloader *_downloader;
|
||||
QString _url;
|
||||
QString _dir;
|
||||
Authorization _authorization;
|
||||
};
|
||||
|
||||
#endif // DEMLOADER_H
|
Reference in New Issue
Block a user