Now using a strict horizontal map scale
[GPXSee.git] / src / map / wmtsmap.cpp
blobb1cd406cb0cc1c3fdc5e7a96022c1a11dfbb77b1
1 #include <QPainter>
2 #include "common/rectc.h"
3 #include "common/wgs84.h"
4 #include "config.h"
5 #include "transform.h"
6 #include "tileloader.h"
7 #include "wmts.h"
8 #include "wmtsmap.h"
11 #define CAPABILITIES_FILE "capabilities.xml"
13 bool WMTSMap::loadWMTS()
15 QString file = tilesDir() + "/" + CAPABILITIES_FILE;
17 WMTS wmts(file, _setup);
18 if (!wmts.isValid()) {
19 _errorString = wmts.errorString();
20 return false;
23 _bounds = wmts.bounds();
24 _zooms = wmts.zooms();
25 _projection = wmts.projection();
26 _tileLoader->setUrl(wmts.tileUrl());
28 if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown)
29 _cs = _projection.coordinateSystem();
30 else
31 _cs = _setup.coordinateSystem();
33 updateTransform();
35 return true;
38 WMTSMap::WMTSMap(const QString &name, const WMTS::Setup &setup, QObject *parent)
39 : Map(parent), _name(name), _setup(setup), _zoom(0), _valid(false)
41 if (!QDir().mkpath(tilesDir())) {
42 _errorString = "Error creating tiles dir";
43 return;
46 _tileLoader = new TileLoader(this);
47 _tileLoader->setDir(tilesDir());
48 _tileLoader->setAuthorization(_setup.authorization());
49 connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(loaded()));
51 _valid = loadWMTS();
54 void WMTSMap::clearCache()
56 _tileLoader->clearCache();
57 _zoom = 0;
59 if (!loadWMTS())
60 qWarning("%s: %s\n", qPrintable(_name), qPrintable(_errorString));
63 QString WMTSMap::tilesDir() const
65 return QString(TILES_DIR + "/" + _name);
68 double WMTSMap::sd2res(double scaleDenominator) const
70 return scaleDenominator * 0.28e-3 * _projection.units().fromMeters(1.0);
73 void WMTSMap::updateTransform()
75 const WMTS::Zoom &z = _zooms.at(_zoom);
77 PointD topLeft = (_cs.axisOrder() == CoordinateSystem::YX)
78 ? PointD(z.topLeft().y(), z.topLeft().x()) : z.topLeft();
80 double pixelSpan = sd2res(z.scaleDenominator());
81 if (_projection.isGeographic())
82 pixelSpan /= deg2rad(WGS84_RADIUS);
83 PointD tileSpan(z.tile().width() * pixelSpan, z.tile().height() * pixelSpan);
84 PointD bottomRight(topLeft.x() + tileSpan.x() * z.matrix().width(),
85 topLeft.y() - tileSpan.y() * z.matrix().height());
87 ReferencePoint tl(PointD(0, 0), topLeft);
88 ReferencePoint br(PointD(z.tile().width() * z.matrix().width(),
89 z.tile().height() * z.matrix().height()), bottomRight);
90 _transform = Transform(tl, br);
93 QRectF WMTSMap::bounds() const
95 const WMTS::Zoom &z = _zooms.at(_zoom);
96 QRectF tileBounds, bounds;
98 tileBounds = (z.limits().isNull()) ?
99 QRectF(QPointF(0, 0), QSize(z.tile().width() * z.matrix().width(),
100 z.tile().height() * z.matrix().height()))
101 : QRectF(QPointF(z.limits().left() * z.tile().width(), z.limits().top()
102 * z.tile().height()), QSize(z.tile().width() * z.limits().width(),
103 z.tile().height() * z.limits().height()));
105 bounds = _bounds.isValid() ? QRectF(ll2xy(_bounds.topLeft()),
106 ll2xy(_bounds.bottomRight())) : QRectF();
108 return _bounds.isValid() ? tileBounds.intersected(bounds) : tileBounds;
111 int WMTSMap::zoomFit(const QSize &size, const RectC &rect)
113 if (rect.isValid()) {
114 PointD tl(_projection.ll2xy(rect.topLeft()));
115 PointD br(_projection.ll2xy(rect.bottomRight()));
116 PointD sc((br.x() - tl.x()) / size.width(), (tl.y() - br.y())
117 / size.height());
118 double resolution = qMax(qAbs(sc.x()), qAbs(sc.y()));
119 if (_projection.isGeographic())
120 resolution *= deg2rad(WGS84_RADIUS);
122 _zoom = 0;
123 for (int i = 0; i < _zooms.size(); i++) {
124 if (sd2res(_zooms.at(i).scaleDenominator()) < resolution)
125 break;
126 _zoom = i;
128 } else
129 _zoom = _zooms.size() - 1;
131 updateTransform();
132 return _zoom;
135 void WMTSMap::setZoom(int zoom)
137 _zoom = zoom;
138 updateTransform();
141 int WMTSMap::zoomIn()
143 _zoom = qMin(_zoom + 1, _zooms.size() - 1);
144 updateTransform();
145 return _zoom;
148 int WMTSMap::zoomOut()
150 _zoom = qMax(_zoom - 1, 0);
151 updateTransform();
152 return _zoom;
155 void WMTSMap::draw(QPainter *painter, const QRectF &rect, bool block)
157 const WMTS::Zoom &z = _zooms.at(_zoom);
158 QPoint tl = QPoint((int)floor(rect.left() / (qreal)z.tile().width()),
159 (int)floor(rect.top() / (qreal)z.tile().height()));
160 QPoint br = QPoint((int)ceil(rect.right() / (qreal)z.tile().width()),
161 (int)ceil(rect.bottom() / (qreal)z.tile().height()));
163 QList<Tile> tiles;
164 for (int i = tl.x(); i < br.x(); i++)
165 for (int j = tl.y(); j < br.y(); j++)
166 tiles.append(Tile(QPoint(i, j), z.id()));
168 if (block)
169 _tileLoader->loadTilesSync(tiles);
170 else
171 _tileLoader->loadTilesAsync(tiles);
173 for (int i = 0; i < tiles.count(); i++) {
174 Tile &t = tiles[i];
175 QPoint tp(t.xy().x() * z.tile().width(), t.xy().y() * z.tile().height());
176 if (!t.pixmap().isNull())
177 painter->drawPixmap(tp, t.pixmap());
181 QPointF WMTSMap::ll2xy(const Coordinates &c) const
183 return _transform.proj2img(_projection.ll2xy(c));
186 Coordinates WMTSMap::xy2ll(const QPointF &p) const
188 return _projection.xy2ll(_transform.img2proj(p));