1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-27 21:24:47 +01:00

Show the map elevation from the map DEM if available

This commit is contained in:
Martin Tůma 2024-05-19 18:59:40 +02:00
parent 488e5e1cac
commit d1401bc302
12 changed files with 198 additions and 133 deletions

View File

@ -128,6 +128,7 @@ HEADERS += src/common/config.h \
src/map/ENC/objects.h \ src/map/ENC/objects.h \
src/map/ENC/rastertile.h \ src/map/ENC/rastertile.h \
src/map/ENC/style.h \ src/map/ENC/style.h \
src/map/IMG/dem.h \
src/map/IMG/demfile.h \ src/map/IMG/demfile.h \
src/map/IMG/demtile.h \ src/map/IMG/demtile.h \
src/map/IMG/jls.h \ src/map/IMG/jls.h \
@ -348,6 +349,7 @@ SOURCES += src/main.cpp \
src/map/ENC/mapdata.cpp \ src/map/ENC/mapdata.cpp \
src/map/ENC/rastertile.cpp \ src/map/ENC/rastertile.cpp \
src/map/ENC/style.cpp \ src/map/ENC/style.cpp \
src/map/IMG/dem.cpp \
src/map/IMG/demfile.cpp \ src/map/IMG/demfile.cpp \
src/map/IMG/jls.cpp \ src/map/IMG/jls.cpp \
src/map/conversion.cpp \ src/map/conversion.cpp \

View File

@ -471,7 +471,6 @@ void GUI::createActions()
_drawHillShadingAction = new QAction(tr("Show hillshading"), this); _drawHillShadingAction = new QAction(tr("Show hillshading"), this);
_drawHillShadingAction->setMenuRole(QAction::NoRole); _drawHillShadingAction->setMenuRole(QAction::NoRole);
_drawHillShadingAction->setCheckable(true); _drawHillShadingAction->setCheckable(true);
_drawHillShadingAction->setEnabled(false);
connect(_drawHillShadingAction, &QAction::triggered, _mapView, connect(_drawHillShadingAction, &QAction::triggered, _mapView,
&MapView::drawHillShading); &MapView::drawHillShading);
@ -2249,8 +2248,7 @@ void GUI::updateDataDEMDownloadAction()
void GUI::updateMapDEMDownloadAction() void GUI::updateMapDEMDownloadAction()
{ {
_downloadMapDEMAction->setEnabled(!_dem->url().isEmpty() _downloadMapDEMAction->setEnabled(!_dem->url().isEmpty()
&& _map->usesDEM() && !_dem->checkTiles(_map->llBounds())); && !_dem->checkTiles(_map->llBounds()));
_drawHillShadingAction->setEnabled(_map->usesDEM());
} }
void GUI::setTimeType(TimeType type) void GUI::setTimeType(TimeType type)

View File

@ -7,7 +7,6 @@
#include <QClipboard> #include <QClipboard>
#include <QOpenGLWidget> #include <QOpenGLWidget>
#include <QGeoPositionInfoSource> #include <QGeoPositionInfoSource>
#include "common/dem.h"
#include "data/poi.h" #include "data/poi.h"
#include "data/data.h" #include "data/data.h"
#include "map/map.h" #include "map/map.h"
@ -1181,9 +1180,7 @@ void MapView::mouseMoveEvent(QMouseEvent *event)
{ {
if (_cursorCoordinates->isVisible()) { if (_cursorCoordinates->isVisible()) {
Coordinates c(_map->xy2ll(mapToScene(event->pos()))); Coordinates c(_map->xy2ll(mapToScene(event->pos())));
DEM::lock(); _cursorCoordinates->setCoordinates(c, _map->elevation(c));
_cursorCoordinates->setCoordinates(c, DEM::elevation(c));
DEM::unlock();
} }
QGraphicsView::mouseMoveEvent(event); QGraphicsView::mouseMoveEvent(event);

110
src/map/IMG/dem.cpp Normal file
View File

@ -0,0 +1,110 @@
#include "dem.h"
using namespace IMG;
static double interpolate(double dx, double dy, double p0, double p1, double p2,
double p3)
{
return p0 * (1.0 - dx) * (1.0 - dy) + p1 * dx * (1.0 - dy)
+ p2 * dy * (1.0 - dx) + p3 * dx * dy;
}
static double val(const Matrix<qint16> &m, int row, int col)
{
qint16 v = m.at(row, col);
return (v == -32768) ? NAN : (double)v;
}
bool DEM::edgeCb(const MapData::Elevation *e, void *context)
{
EdgeCTX *ctx = (EdgeCTX*)context;
double x = (ctx->c.lon() - e->rect.left()) / e->xr;
double y = (e->rect.top() - ctx->c.lat()) / e->yr;
int row = qMin((int)y, e->m.h() - 1);
int col = qMin((int)x, e->m.w() - 1);
ctx->ele = val(e->m, row, col);
return std::isnan(ctx->ele);
}
double DEM::edge(const DEMTRee &tree, const Coordinates &c)
{
double min[2], max[2];
double ele = NAN;
EdgeCTX ctx(c, ele);
min[0] = c.lon();
min[1] = c.lat();
max[0] = c.lon();
max[1] = c.lat();
tree.Search(min, max, edgeCb, &ctx);
return ele;
}
double DEM::elevation(const DEMTRee &tree, const MapData::Elevation *e,
const Coordinates &c)
{
double x = (c.lon() - e->rect.left()) / e->xr;
double y = (e->rect.top() - c.lat()) / e->yr;
int row = qMin((int)y, e->m.h() - 1);
int col = qMin((int)x, e->m.w() - 1);
double p0 = val(e->m, row, col);
double p1 = (col == e->m.w() - 1)
? edge(tree, Coordinates(e->rect.left() + (col + 1) * e->xr + e->xr/2,
e->rect.top() - row * e->yr))
: val(e->m, row, col + 1);
double p2 = (row == e->m.h() - 1)
? edge(tree, Coordinates(e->rect.left() + col * e->xr,
e->rect.top() - (row + 1) * e->yr - e->yr/2))
: val(e->m, row + 1, col);
double p3 = ((col == e->m.w() - 1) || (row == e->m.h() - 1))
? edge(tree, Coordinates(e->rect.left() + (col + 1) * e->xr + e->xr/2,
e->rect.top() - (row + 1) * e->yr - e->yr/2))
: val(e->m, row + 1, col + 1);
return interpolate(x - col, y - row, p0, p1, p2, p3);
}
void DEM::buildTree(const QList<MapData::Elevation> &tiles, DEMTRee &tree)
{
double min[2], max[2];
for (int i = 0; i < tiles.size(); i++) {
const MapData::Elevation &e = tiles.at(i);
min[0] = e.rect.left();
min[1] = e.rect.bottom();
max[0] = e.rect.right();
max[1] = e.rect.top();
tree.Insert(min, max, &e);
}
}
bool DEM::elevationCb(const MapData::Elevation *e, void *context)
{
ElevationCTX *ctx = (ElevationCTX*)context;
ctx->ele = elevation(ctx->tree, e, ctx->c);
return std::isnan(ctx->ele);
}
void DEM::searchTree(const DEMTRee &tree, const Coordinates &c,
double &ele)
{
double min[2], max[2];
ElevationCTX ctx(tree, c, ele);
min[0] = c.lon();
min[1] = c.lat();
max[0] = c.lon();
max[1] = c.lat();
ele = NAN;
tree.Search(min, max, elevationCb, &ctx);
}

46
src/map/IMG/dem.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef IMG_DEM_H
#define IMG_DEM_H
#include "common/rtree.h"
#include "mapdata.h"
namespace IMG {
class DEM {
public:
typedef RTree<const MapData::Elevation*, double, 2> DEMTRee;
static void buildTree(const QList<MapData::Elevation> &tiles, DEMTRee &tree);
static void searchTree(const DEMTRee &tree, const Coordinates &c,
double &ele);
private:
struct ElevationCTX {
ElevationCTX(const DEMTRee &tree, const Coordinates &c, double &ele)
: tree(tree), c(c), ele(ele) {}
const DEMTRee &tree;
const Coordinates &c;
double &ele;
};
struct EdgeCTX {
EdgeCTX(const Coordinates &c, double &ele) : c(c), ele(ele) {}
const Coordinates &c;
double &ele;
};
MatrixD elevation() const;
static double edge(const DEMTRee &tree, const Coordinates &c);
static double elevation(const DEMTRee &tree, const MapData::Elevation *e,
const Coordinates &c);
static bool elevationCb(const MapData::Elevation *e, void *context);
static bool edgeCb(const MapData::Elevation *e, void *context);
};
}
#endif // IMG_ELEVATIONTREE_H

View File

@ -9,6 +9,7 @@
#include "map/hillshading.h" #include "map/hillshading.h"
#include "style.h" #include "style.h"
#include "lblfile.h" #include "lblfile.h"
#include "dem.h"
#include "rastertile.h" #include "rastertile.h"
using namespace IMG; using namespace IMG;
@ -108,20 +109,6 @@ static bool rectNearPolygon(const QPolygonF &polygon, const QRectF &rect)
|| polygon.containsPoint(rect.bottomRight(), Qt::OddEvenFill))); || polygon.containsPoint(rect.bottomRight(), Qt::OddEvenFill)));
} }
static double interpolate(double dx, double dy, double p0, double p1, double p2,
double p3)
{
return p0 * (1.0 - dx) * (1.0 - dy) + p1 * dx * (1.0 - dy)
+ p2 * dy * (1.0 - dx) + p3 * dx * dy;
}
static double val(const Matrix<qint16> &m, int row, int col)
{
qint16 v = m.at(row, col);
return (v == -32768) ? NAN : (double)v;
}
const QFont *RasterTile::poiFont(Style::FontSize size, int zoom, const QFont *RasterTile::poiFont(Style::FontSize size, int zoom,
bool extended) const bool extended) const
{ {
@ -465,100 +452,6 @@ void RasterTile::fetchData(QList<MapData::Poly> &polygons,
_data->points(pointRectD.toRectC(_proj, 20), _zoom, &points); _data->points(pointRectD.toRectC(_proj, 20), _zoom, &points);
} }
bool RasterTile::edgeCb(const MapData::Elevation *e, void *context)
{
EdgeCTX *ctx = (EdgeCTX*)context;
double x = (ctx->c.lon() - e->rect.left()) / e->xr;
double y = (e->rect.top() - ctx->c.lat()) / e->yr;
int row = qMin((int)y, e->m.h() - 1);
int col = qMin((int)x, e->m.w() - 1);
ctx->ele = val(e->m, row, col);
return std::isnan(ctx->ele);
}
double RasterTile::edge(const DEMTRee &tree, const Coordinates &c)
{
double min[2], max[2];
double ele = NAN;
EdgeCTX ctx(c, ele);
min[0] = c.lon();
min[1] = c.lat();
max[0] = c.lon();
max[1] = c.lat();
tree.Search(min, max, edgeCb, &ctx);
return ele;
}
double RasterTile::elevation(const DEMTRee &tree, const MapData::Elevation *e,
const Coordinates &c)
{
double x = (c.lon() - e->rect.left()) / e->xr;
double y = (e->rect.top() - c.lat()) / e->yr;
int row = qMin((int)y, e->m.h() - 1);
int col = qMin((int)x, e->m.w() - 1);
double p0 = val(e->m, row, col);
double p1 = (col == e->m.w() - 1)
? edge(tree, Coordinates(e->rect.left() + (col + 1) * e->xr + e->xr/2,
e->rect.top() - row * e->yr))
: val(e->m, row, col + 1);
double p2 = (row == e->m.h() - 1)
? edge(tree, Coordinates(e->rect.left() + col * e->xr,
e->rect.top() - (row + 1) * e->yr - e->yr/2))
: val(e->m, row + 1, col);
double p3 = ((col == e->m.w() - 1) || (row == e->m.h() - 1))
? edge(tree, Coordinates(e->rect.left() + (col + 1) * e->xr + e->xr/2,
e->rect.top() - (row + 1) * e->yr - e->yr/2))
: val(e->m, row + 1, col + 1);
return interpolate(x - col, y - row, p0, p1, p2, p3);
}
void RasterTile::buildTree(const QList<MapData::Elevation> &tiles, DEMTRee &tree)
{
double min[2], max[2];
for (int i = 0; i < tiles.size(); i++) {
const MapData::Elevation &e = tiles.at(i);
min[0] = e.rect.left();
min[1] = e.rect.bottom();
max[0] = e.rect.right();
max[1] = e.rect.top();
tree.Insert(min, max, &e);
}
}
bool RasterTile::elevationCb(const MapData::Elevation *e, void *context)
{
ElevationCTX *ctx = (ElevationCTX*)context;
ctx->ele = elevation(ctx->tree, e, ctx->c);
return std::isnan(ctx->ele);
}
void RasterTile::searchTree(const DEMTRee &tree, const Coordinates &c,
double &ele)
{
double min[2], max[2];
ElevationCTX ctx(tree, c, ele);
min[0] = c.lon();
min[1] = c.lat();
max[0] = c.lon();
max[1] = c.lat();
ele = NAN;
tree.Search(min, max, elevationCb, &ctx);
}
MatrixD RasterTile::elevation() const MatrixD RasterTile::elevation() const
{ {
MatrixD m(_rect.height() + 2, _rect.width() + 2); MatrixD m(_rect.height() + 2, _rect.width() + 2);
@ -586,14 +479,14 @@ MatrixD RasterTile::elevation() const
_data->elevations(rect, _zoom, &tiles); _data->elevations(rect, _zoom, &tiles);
buildTree(tiles, tree); DEM::buildTree(tiles, tree);
for (int i = 0; i < ll.size(); i++) for (int i = 0; i < ll.size(); i++)
searchTree(tree, ll.at(i), m.at(i)); DEM::searchTree(tree, ll.at(i), m.at(i));
} else { } else {
DEM::lock(); ::DEM::lock();
for (int i = 0; i < ll.size(); i++) for (int i = 0; i < ll.size(); i++)
m.at(i) = DEM::elevation(ll.at(i)); m.at(i) = ::DEM::elevation(ll.at(i));
DEM::unlock(); ::DEM::unlock();
} }
return m; return m;

View File

@ -77,15 +77,6 @@ private:
MatrixD elevation() const; MatrixD elevation() const;
static double edge(const DEMTRee &tree, const Coordinates &c);
static double elevation(const DEMTRee &tree, const MapData::Elevation *e,
const Coordinates &c);
static void buildTree(const QList<MapData::Elevation> &tiles, DEMTRee &tree);
static void searchTree(const DEMTRee &tree, const Coordinates &c,
double &ele);
static bool elevationCb(const MapData::Elevation *e, void *context);
static bool edgeCb(const MapData::Elevation *e, void *context);
Projection _proj; Projection _proj;
Transform _transform; Transform _transform;
MapData *_data; MapData *_data;

View File

@ -8,6 +8,7 @@
#include "IMG/imgdata.h" #include "IMG/imgdata.h"
#include "IMG/gmapdata.h" #include "IMG/gmapdata.h"
#include "IMG/rastertile.h" #include "IMG/rastertile.h"
#include "IMG/dem.h"
#include "osm.h" #include "osm.h"
#include "pcs.h" #include "pcs.h"
#include "rectd.h" #include "rectd.h"
@ -266,6 +267,22 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
} }
} }
double IMGMap::elevation(const Coordinates &c)
{
QList<MapData::Elevation> tiles;
DEM::DEMTRee tree;
MapData *d = _data.first();
double ele = NAN;
d->elevations(RectC(Coordinates(c), Coordinates(c)), d->zooms().max(),
&tiles);
DEM::buildTree(tiles, tree);
DEM::searchTree(tree, c, ele);
return ele;
}
Map* IMGMap::createIMG(const QString &path, const Projection &proj, bool *isDir) Map* IMGMap::createIMG(const QString &path, const Projection &proj, bool *isDir)
{ {
Q_UNUSED(proj); Q_UNUSED(proj);

View File

@ -74,7 +74,7 @@ public:
bool hidpi); bool hidpi);
void unload(); void unload();
bool usesDEM() const {return true;} double elevation(const Coordinates &c);
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}

View File

@ -1,5 +1,6 @@
#include <cmath> #include <cmath>
#include <QLineF> #include <QLineF>
#include "common/dem.h"
#include "map.h" #include "map.h"
@ -79,3 +80,14 @@ qreal Map::resolution(const QRectF &rect)
return ds/ps; return ds/ps;
} }
double Map::elevation(const Coordinates &c)
{
double ele;
DEM::lock();
ele = DEM::elevation(c);
DEM::unlock();
return ele;
}

View File

@ -56,8 +56,9 @@ public:
virtual void draw(QPainter *painter, const QRectF &rect, Flags flags) = 0; virtual void draw(QPainter *painter, const QRectF &rect, Flags flags) = 0;
virtual double elevation(const Coordinates &c);
virtual void clearCache() {} virtual void clearCache() {}
virtual bool usesDEM() const {return false;}
signals: signals:
void tilesLoaded(); void tilesLoaded();

View File

@ -71,8 +71,6 @@ public:
void draw(QPainter *painter, const QRectF &rect, Flags flags); void draw(QPainter *painter, const QRectF &rect, Flags flags);
bool usesDEM() const {return true;}
bool isValid() const {return _data.isValid();} bool isValid() const {return _data.isValid();}
QString errorString() const {return _data.errorString();} QString errorString() const {return _data.errorString();}