1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-06 14:53:21 +02:00

Improved scale computation on offline & WMTS maps

This commit is contained in:
Martin Tůma 2018-02-28 22:19:46 +01:00
parent 46cefada94
commit b9ed0c3933
12 changed files with 131 additions and 199 deletions

View File

@ -95,7 +95,8 @@ void MapView::centerOn(const QPointF &pos)
verticalScrollBar()->setValue(verticalScrollBar()->value()
+ offset.y());
_res = _map->resolution(pos);
QRectF vr(mapToScene(viewport()->rect()).boundingRect());
_res = _map->resolution(vr);
_mapScale->setResolution(_res);
}
@ -267,9 +268,8 @@ void MapView::setPalette(const Palette &palette)
void MapView::setMap(Map *map)
{
QPointF pos = mapToScene(viewport()->rect().center());
Coordinates center = _map->xy2ll(pos);
qreal resolution = _map->resolution(pos);
QRectF vr(mapToScene(viewport()->rect()).boundingRect());
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
_map->unload();
disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
@ -281,7 +281,7 @@ void MapView::setMap(Map *map)
digitalZoom(0);
_map->zoomFit(resolution, center);
_map->zoomFit(viewport()->rect().size(), cr);
_scene->setSceneRect(_map->bounds());
for (int i = 0; i < _tracks.size(); i++)
@ -296,7 +296,7 @@ void MapView::setMap(Map *map)
it.value()->setMap(_map);
updatePOIVisibility();
centerOn(_map->ll2xy(center));
centerOn(_map->ll2xy(cr.center()));
resetCachedContent();
QPixmapCache::clear();
@ -499,9 +499,9 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
bool hires)
{
QRect orig, adj;
qreal ratio, diff, origRes, q;
qreal ratio, diff, q;
QPointF origScene, origPos;
Coordinates origLL;
RectC origC;
// Enter plot mode
@ -526,9 +526,9 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
// Adjust the view for printing
if (hires) {
origScene = mapToScene(orig.center());
origLL = _map->xy2ll(origScene);
origRes = _map->resolution(origScene);
QRectF vr(mapToScene(orig).boundingRect());
origC = RectC(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
origScene = vr.center();
QPointF s(painter->device()->logicalDpiX()
/ (qreal)metric(QPaintDevice::PdmDpiX),
@ -558,7 +558,7 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
// Revert view changes to display mode
if (hires) {
_map->zoomFit(origRes, origLL);
_map->zoomFit(orig.size(), origC);
rescale();
centerOn(origScene);
}
@ -797,8 +797,8 @@ void MapView::scrollContentsBy(int dx, int dy)
{
QGraphicsView::scrollContentsBy(dx, dy);
QPointF center = mapToScene(viewport()->rect().center());
qreal res = _map->resolution(center);
QRectF sr(mapToScene(viewport()->rect()).boundingRect());
qreal res = _map->resolution(sr);
if (qMax(res, _res) / qMin(res, _res) > 1.1) {
_mapScale->setResolution(res);

View File

@ -15,8 +15,8 @@ static bool resCmp(const OfflineMap *m1, const OfflineMap *m2)
{
qreal r1, r2;
r1 = m1->resolution(m1->bounds().center());
r2 = m2->resolution(m2->bounds().center());
r1 = m1->resolution(m1->bounds());
r2 = m2->resolution(m2->bounds());
return r1 > r2;
}
@ -37,8 +37,8 @@ void Atlas::computeZooms()
_zooms.append(QPair<int, int>(0, _maps.count() - 1));
for (int i = 1; i < _maps.count(); i++) {
qreal last = _maps.at(i-1)->resolution(_maps.at(i)->bounds().center());
qreal cur = _maps.at(i)->resolution(_maps.at(i)->bounds().center());
qreal last = _maps.at(i-1)->resolution(_maps.at(i)->bounds());
qreal cur = _maps.at(i)->resolution(_maps.at(i)->bounds());
if (cur < last * ZOOM_THRESHOLD) {
_zooms.last().second = i-1;
_zooms.append(QPair<int, int>(i, _maps.count() - 1));
@ -169,26 +169,21 @@ QRectF Atlas::bounds() const
return QRectF(QPointF(0, 0), s);
}
qreal Atlas::resolution(const QPointF &p) const
qreal Atlas::resolution(const QRectF &rect) const
{
int idx = _zooms.at(_zoom).first;
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).second; i++) {
if (_bounds.at(i).second.contains(_maps.at(i)->xy2pp(p))) {
if (_bounds.at(i).second.contains(_maps.at(i)->xy2pp(rect.center()))) {
idx = i;
break;
}
}
return _maps.at(idx)->resolution(p);
return _maps.at(idx)->resolution(rect);
}
qreal Atlas::zoom() const
{
return _zoom;
}
qreal Atlas::zoomFit(const QSize &size, const RectC &br)
int Atlas::zoomFit(const QSize &size, const RectC &br)
{
_zoom = 0;
@ -217,33 +212,13 @@ qreal Atlas::zoomFit(const QSize &size, const RectC &br)
return _zoom;
}
qreal Atlas::zoomFit(qreal resolution, const Coordinates &c)
{
_zoom = 0;
for (int z = 0; z < _zooms.count(); z++) {
for (int i = _zooms.at(z).first; i <= _zooms.at(z).second; i++) {
if (!_bounds.at(i).first.contains(_maps.at(i)->ll2pp(c)))
continue;
if (_maps.at(i)->resolution(_maps.at(i)->ll2xy(c)) < resolution)
return _zoom;
_zoom = z;
break;
}
}
return _zoom;
}
qreal Atlas::zoomIn()
int Atlas::zoomIn()
{
_zoom = qMin(_zoom + 1, _zooms.size() - 1);
return _zoom;
}
qreal Atlas::zoomOut()
int Atlas::zoomOut()
{
_zoom = qMax(_zoom - 1, 0);
return _zoom;

View File

@ -17,13 +17,12 @@ public:
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const;
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);

View File

@ -6,8 +6,9 @@
#include "emptymap.h"
#define SCALE_MIN 0.5
#define SCALE_MAX 1.0E-6
#define ZOOM_MIN 0
#define ZOOM_MAX 19
#define TILE_SIZE 256
static QPointF ll2m(const Coordinates &c)
{
@ -19,10 +20,30 @@ static Coordinates m2ll(const QPointF &p)
return Coordinates(p.x(), rad2deg(2 * atan(exp(deg2rad(p.y()))) - M_PI/2));
}
static qreal zoom2scale(int zoom)
{
return (360.0/(qreal)((1<<zoom) * TILE_SIZE));
}
static int scale2zoom(qreal scale)
{
return (int)log2(360.0/(scale * (qreal)TILE_SIZE));
}
static int limitZoom(int zoom)
{
if (zoom < ZOOM_MIN)
return ZOOM_MIN;
if (zoom > ZOOM_MAX)
return ZOOM_MAX;
return zoom;
}
EmptyMap::EmptyMap(QObject *parent) : Map(parent)
{
_scale = SCALE_MAX;
_zoom = ZOOM_MAX;
}
QRectF EmptyMap::bounds() const
@ -30,49 +51,38 @@ QRectF EmptyMap::bounds() const
return QRectF(ll2xy(Coordinates(-180, 85)), ll2xy(Coordinates(180, -85)));
}
qreal EmptyMap::zoomFit(const QSize &size, const RectC &br)
int EmptyMap::zoomFit(const QSize &size, const RectC &br)
{
if (!br.isValid())
_scale = SCALE_MAX;
_zoom = ZOOM_MAX;
else {
QRectF tbr(ll2m(br.topLeft()), ll2m(br.bottomRight()));
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
_scale = qMax(sc.x(), sc.y());
_zoom = limitZoom(scale2zoom(qMax(sc.x(), sc.y())));
}
_scale = qMax(_scale, SCALE_MAX);
_scale = qMin(_scale, SCALE_MIN);
return _scale;
return _zoom;
}
qreal EmptyMap::zoomFit(qreal resolution, const Coordinates &c)
qreal EmptyMap::resolution(const QRectF &rect) const
{
_scale = (360.0 * resolution) / (WGS84_RADIUS * 2 * M_PI
* cos(deg2rad(c.lat())));
qreal scale = zoom2scale(_zoom);
_scale = qMax(_scale, SCALE_MAX);
_scale = qMin(_scale, SCALE_MIN);
return _scale;
return (WGS84_RADIUS * 2.0 * M_PI * scale / 360.0
* cos(2.0 * atan(exp(deg2rad(-rect.center().y() * scale))) - M_PI/2));
}
qreal EmptyMap::resolution(const QPointF &p) const
int EmptyMap::zoomIn()
{
return (WGS84_RADIUS * 2 * M_PI * _scale / 360.0
* cos(2.0 * atan(exp(deg2rad(-p.y() * _scale))) - M_PI/2));
_zoom = qMin(_zoom + 1, ZOOM_MAX);
return _zoom;
}
qreal EmptyMap::zoomIn()
int EmptyMap::zoomOut()
{
_scale = qMax(_scale / 2.0, SCALE_MAX);
return _scale;
}
qreal EmptyMap::zoomOut()
{
_scale = qMin(_scale * 2.0, SCALE_MIN);
return _scale;
_zoom = qMax(_zoom - 1, ZOOM_MIN);
return _zoom;
}
void EmptyMap::draw(QPainter *painter, const QRectF &rect)
@ -82,12 +92,13 @@ void EmptyMap::draw(QPainter *painter, const QRectF &rect)
QPointF EmptyMap::ll2xy(const Coordinates &c) const
{
qreal scale = zoom2scale(_zoom);
QPointF m = ll2m(c);
return QPointF(m.x() / _scale, m.y() / -_scale);
return QPointF(m.x() / scale, m.y() / -scale);
}
Coordinates EmptyMap::xy2ll(const QPointF &p) const
{
QPointF m(p.x() * _scale, -p.y() * _scale);
return m2ll(QPointF(p.x() * _scale, -p.y() * _scale));
qreal scale = zoom2scale(_zoom);
return m2ll(QPointF(p.x() * scale, -p.y() * scale));
}

View File

@ -14,13 +14,12 @@ public:
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const {return _scale;}
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c)
{return static_cast<const EmptyMap &>(*this).ll2xy(c);}
@ -34,7 +33,7 @@ private:
Coordinates xy2ll(const QPointF &p) const;
QString _name;
qreal _scale;
int _zoom;
};
#endif // EMPTYMAP_H

View File

@ -20,13 +20,12 @@ public:
virtual const QString &name() const = 0;
virtual QRectF bounds() const = 0;
virtual qreal resolution(const QPointF &p) const = 0;
virtual qreal resolution(const QRectF &rect) const = 0;
virtual qreal zoom() const = 0;
virtual qreal zoomFit(const QSize &size, const RectC &br) = 0;
virtual qreal zoomFit(qreal resolution, const Coordinates &c) = 0;
virtual qreal zoomIn() = 0;
virtual qreal zoomOut() = 0;
virtual int zoom() const = 0;
virtual int zoomFit(const QSize &size, const RectC &br) = 0;
virtual int zoomIn() = 0;
virtual int zoomOut() = 0;
virtual QPointF ll2xy(const Coordinates &c) = 0;
virtual Coordinates xy2ll(const QPointF &p) = 0;

View File

@ -14,17 +14,6 @@
#include "offlinemap.h"
void OfflineMap::computeResolution()
{
Coordinates tl = xy2ll((bounds().topLeft()));
Coordinates br = xy2ll(bounds().bottomRight());
qreal ds = tl.distanceTo(br);
qreal ps = QLineF(bounds().topLeft(), bounds().bottomRight()).length();
_resolution = ds/ps;
}
bool OfflineMap::getImageInfo(const QString &path)
{
QFileInfo ii(_imgPath);
@ -112,7 +101,6 @@ OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
_valid = false;
_img = 0;
_resolution = 0.0;
_zoom = 0;
_scale = QPointF(1.0, 1.0);
@ -190,7 +178,6 @@ OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
}
_inverted = _transform.inverted();
computeResolution();
_valid = true;
}
@ -203,7 +190,6 @@ OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent)
_valid = false;
_img = 0;
_resolution = 0.0;
_zoom = 0;
_scale = QPointF(1.0, 1.0);
@ -227,9 +213,7 @@ OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent)
_size = mf.size();
_projection = mf.projection();
_transform = mf.transform();
_inverted = _transform.inverted();
computeResolution();
_tarPath = fi.absolutePath() + "/" + fi.completeBaseName() + ".tar";
_valid = true;
@ -353,7 +337,7 @@ void OfflineMap::draw(QPainter *painter, const QRectF &rect)
painter->fillRect(rect, _backgroundColor);
}
QPointF OfflineMap::ll2xy(const Coordinates &c)
QPointF OfflineMap::ll2xy(const Coordinates &c) const
{
if (_ozf.isOpen()) {
QPointF p(_transform.map(_projection.ll2xy(c)));
@ -362,7 +346,7 @@ QPointF OfflineMap::ll2xy(const Coordinates &c)
return _transform.map(_projection.ll2xy(c));
}
Coordinates OfflineMap::xy2ll(const QPointF &p)
Coordinates OfflineMap::xy2ll(const QPointF &p) const
{
if (_ozf.isOpen()) {
return _projection.xy2ll(_inverted.map(QPointF(p.x() / _scale.x(),
@ -379,17 +363,18 @@ QRectF OfflineMap::bounds() const
return QRectF(QPointF(0, 0), _size);
}
qreal OfflineMap::resolution(const QPointF &p) const
qreal OfflineMap::resolution(const QRectF &rect) const
{
Q_UNUSED(p);
Coordinates tl = xy2ll((rect.topLeft()));
Coordinates br = xy2ll(rect.bottomRight());
if (_ozf.isOpen())
return _resolution / ((_scale.x() + _scale.y()) / 2.0);
else
return _resolution;
qreal ds = tl.distanceTo(br);
qreal ps = QLineF(rect.topLeft(), rect.bottomRight()).length();
return ds/ps;
}
qreal OfflineMap::zoomFit(const QSize &size, const RectC &br)
int OfflineMap::zoomFit(const QSize &size, const RectC &br)
{
if (_ozf.isOpen()) {
if (!br.isValid())
@ -411,23 +396,7 @@ qreal OfflineMap::zoomFit(const QSize &size, const RectC &br)
return _zoom;
}
qreal OfflineMap::zoomFit(qreal resolution, const Coordinates &c)
{
Q_UNUSED(c);
if (_ozf.isOpen()) {
for (int i = 0; i < _ozf.zooms(); i++) {
rescale(i);
qreal sr = _resolution / ((_scale.x() + _scale.y()) / 2.0);
if (sr >= resolution)
break;
}
}
return _zoom;
}
qreal OfflineMap::zoomIn()
int OfflineMap::zoomIn()
{
if (_ozf.isOpen())
rescale(qMax(_zoom - 1, 0));
@ -435,7 +404,7 @@ qreal OfflineMap::zoomIn()
return _zoom;
}
qreal OfflineMap::zoomOut()
int OfflineMap::zoomOut()
{
if (_ozf.isOpen())
rescale(qMin(_zoom + 1, _ozf.zooms() - 1));

View File

@ -24,16 +24,17 @@ public:
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const {return _zoom;}
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
QPointF ll2xy(const Coordinates &c)
{return static_cast<const OfflineMap &>(*this).ll2xy(c);}
Coordinates xy2ll(const QPointF &p)
{return static_cast<const OfflineMap &>(*this).xy2ll(p);}
void draw(QPainter *painter, const QRectF &rect);
@ -51,6 +52,9 @@ public:
{return _transform.map(p);}
private:
QPointF ll2xy(const Coordinates &c) const;
Coordinates xy2ll(const QPointF &p) const;
bool getTileInfo(const QStringList &tiles, const QString &path = QString());
bool getImageInfo(const QString &path);
bool totalSizeSet();
@ -59,7 +63,6 @@ private:
void drawOZF(QPainter *painter, const QRectF &rect);
void drawImage(QPainter *painter, const QRectF &rect);
void computeResolution();
void rescale(int zoom);
QString _name;
@ -77,7 +80,6 @@ private:
QSize _size;
int _zoom;
qreal _resolution;
QPointF _scale;
bool _valid;

View File

@ -90,7 +90,7 @@ int OnlineMap::limitZoom(int zoom) const
return zoom;
}
qreal OnlineMap::zoomFit(const QSize &size, const RectC &br)
int OnlineMap::zoomFit(const QSize &size, const RectC &br)
{
if (!br.isValid())
_zoom = _zooms.max();
@ -104,29 +104,21 @@ qreal OnlineMap::zoomFit(const QSize &size, const RectC &br)
return _zoom;
}
qreal OnlineMap::zoomFit(qreal resolution, const Coordinates &c)
{
_zoom = limitZoom((int)log2((WGS84_RADIUS * 2.0 * M_PI
* cos(deg2rad(c.lat()))) / (resolution * TILE_SIZE)));
return _zoom;
}
qreal OnlineMap::resolution(const QPointF &p) const
qreal OnlineMap::resolution(const QRectF &rect) const
{
qreal scale = zoom2scale(_zoom);
return (WGS84_RADIUS * 2.0 * M_PI * scale / 360.0
* cos(2.0 * atan(exp(deg2rad(-p.y() * scale))) - M_PI/2));
* cos(2.0 * atan(exp(deg2rad(-rect.center().y() * scale))) - M_PI/2));
}
qreal OnlineMap::zoomIn()
int OnlineMap::zoomIn()
{
_zoom = qMin(_zoom + 1, _zooms.max());
return _zoom;
}
qreal OnlineMap::zoomOut()
int OnlineMap::zoomOut()
{
_zoom = qMax(_zoom - 1, _zooms.min());
return _zoom;

View File

@ -18,13 +18,12 @@ public:
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const {return _zoom;}
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c)
{return static_cast<const OnlineMap &>(*this).ll2xy(c);}

View File

@ -119,7 +119,7 @@ QRectF WMTSMap::bounds() const
return _bounds.isValid() ? tileBounds.intersected(bounds) : tileBounds;
}
qreal WMTSMap::zoomFit(const QSize &size, const RectC &br)
int WMTSMap::zoomFit(const QSize &size, const RectC &br)
{
if (br.isValid()) {
QRectF tbr(_projection.ll2xy(br.topLeft()),
@ -142,37 +142,25 @@ qreal WMTSMap::zoomFit(const QSize &size, const RectC &br)
return _zoom;
}
qreal WMTSMap::zoomFit(qreal resolution, const Coordinates &c)
qreal WMTSMap::resolution(const QRectF &rect) const
{
Q_UNUSED(c);
Coordinates tl = xy2ll((rect.topLeft()));
Coordinates br = xy2ll(rect.bottomRight());
_zoom = 0;
qreal ds = tl.distanceTo(br);
qreal ps = QLineF(rect.topLeft(), rect.bottomRight()).length();
for (int i = 0; i < _zooms.size(); i++) {
if (sd2res(_zooms.at(i).scaleDenominator) < resolution)
break;
_zoom = i;
}
updateTransform();
return _zoom;
return ds/ps;
}
qreal WMTSMap::resolution(const QPointF &p) const
{
Q_UNUSED(p);
return sd2res(_zooms.at(_zoom).scaleDenominator);
}
qreal WMTSMap::zoomIn()
int WMTSMap::zoomIn()
{
_zoom = qMin(_zoom + 1, _zooms.size() - 1);
updateTransform();
return _zoom;
}
qreal WMTSMap::zoomOut()
int WMTSMap::zoomOut()
{
_zoom = qMax(_zoom - 1, 0);
updateTransform();

View File

@ -18,13 +18,12 @@ public:
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const {return _zoom;}
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c)
{return static_cast<const WMTSMap &>(*this).ll2xy(c);}