Map API refactoring
[GPXSee.git] / src / map / wmtsmap.cpp
blob1da2dd29c8e430b61820e92253490ed8bfdd5e99
1 #include <QtCore>
2 #include <QPainter>
3 #include <QDir>
4 #include "common/rectc.h"
5 #include "common/wgs84.h"
6 #include "common/programpaths.h"
7 #include "transform.h"
8 #include "tileloader.h"
9 #include "wmts.h"
10 #include "wmtsmap.h"
13 #define CAPABILITIES_FILE "capabilities.xml"
15 WMTSMap::WMTSMap(const QString &fileName, const QString &name,
16 const WMTS::Setup &setup, qreal tileRatio,
17 QObject *parent) : Map(fileName, parent), _name(name), _tileLoader(0),
18 _zoom(0), _mapRatio(1.0), _tileRatio(tileRatio)
20 QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name));
22 _tileLoader = new TileLoader(tilesDir, this);
23 _tileLoader->setAuthorization(setup.authorization());
24 connect(_tileLoader, &TileLoader::finished, this, &WMTSMap::tilesLoaded);
26 _wmts = new WMTS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this);
27 connect(_wmts, &WMTS::downloadFinished, this, &WMTSMap::wmtsReady);
28 if (_wmts->isReady())
29 init();
32 void WMTSMap::init()
34 _tileLoader->setUrl(_wmts->tileUrl());
35 _bounds = RectD(_wmts->bbox(), _wmts->projection());
36 updateTransform();
39 void WMTSMap::wmtsReady()
41 if (_wmts->isValid())
42 init();
44 emit mapLoaded();
47 void WMTSMap::load(const Projection &in, const Projection &out,
48 qreal deviceRatio, bool hidpi)
50 Q_UNUSED(in);
51 Q_UNUSED(out);
53 _mapRatio = hidpi ? deviceRatio : 1.0;
56 void WMTSMap::clearCache()
58 _tileLoader->clearCache();
61 double WMTSMap::sd2res(double scaleDenominator) const
63 return scaleDenominator * 0.28e-3
64 * _wmts->projection().units().fromMeters(1.0);
67 Transform WMTSMap::transform(int zoom) const
69 const WMTS::Zoom &z = _wmts->zooms().at(zoom);
71 PointD topLeft = (_wmts->cs().axisOrder() == CoordinateSystem::YX)
72 ? PointD(z.topLeft().y(), z.topLeft().x()) : z.topLeft();
74 double pixelSpan = sd2res(z.scaleDenominator());
75 if (_wmts->projection().isGeographic())
76 pixelSpan /= deg2rad(WGS84_RADIUS);
77 return Transform(ReferencePoint(PointD(0, 0), topLeft),
78 PointD(pixelSpan, pixelSpan));
81 QRectF WMTSMap::tileBounds(int zoom) const
83 const WMTS::Zoom &z = _wmts->zooms().at(zoom);
85 return (z.limits().isNull())
86 ? QRectF(QPointF(0, 0), QSize(z.tile().width() * z.matrix().width(),
87 z.tile().height() * z.matrix().height()))
88 : QRectF(QPointF(z.limits().left() * z.tile().width(), z.limits().top()
89 * z.tile().height()), QSize(z.tile().width() * z.limits().width(),
90 z.tile().height() * z.limits().height()));
93 void WMTSMap::updateTransform()
95 _transform = transform(_zoom);
98 QRectF WMTSMap::bounds()
100 QRectF tb(tileBounds(_zoom));
101 QRectF lb = _bounds.isValid()
102 ? QRectF(_transform.proj2img(_bounds.topLeft()) / coordinatesRatio(),
103 _transform.proj2img(_bounds.bottomRight()) / coordinatesRatio())
104 : QRectF();
106 return lb.isValid() ? lb & tb : tb;
109 RectC WMTSMap::llBounds(const Projection &)
111 if (_wmts->bbox().isValid())
112 return _wmts->bbox();
113 else {
114 int maxZoom = _wmts->zooms().size() - 1;
115 QRectF tb(tileBounds(maxZoom));
116 Transform t(transform(maxZoom));
117 RectD rect(t.img2proj(tb.topLeft() * coordinatesRatio()),
118 t.img2proj(tb.bottomRight() * coordinatesRatio()));
119 return rect.toRectC(_wmts->projection());
123 int WMTSMap::zoomFit(const QSize &size, const RectC &rect)
125 if (rect.isValid()) {
126 RectD prect(rect, _wmts->projection());
127 PointD sc(prect.width() / size.width(), prect.height() / size.height());
128 double resolution = qMax(qAbs(sc.x()), qAbs(sc.y()));
129 if (_wmts->projection().isGeographic())
130 resolution *= deg2rad(WGS84_RADIUS);
132 _zoom = 0;
133 for (int i = 0; i < _wmts->zooms().size(); i++) {
134 if (sd2res(_wmts->zooms().at(i).scaleDenominator()) < resolution
135 / coordinatesRatio())
136 break;
137 _zoom = i;
139 } else
140 _zoom = _wmts->zooms().size() - 1;
142 updateTransform();
143 return _zoom;
146 void WMTSMap::setZoom(int zoom)
148 _zoom = zoom;
149 updateTransform();
152 int WMTSMap::zoomIn()
154 _zoom = qMin(_zoom + 1, _wmts->zooms().size() - 1);
155 updateTransform();
156 return _zoom;
159 int WMTSMap::zoomOut()
161 _zoom = qMax(_zoom - 1, 0);
162 updateTransform();
163 return _zoom;
166 qreal WMTSMap::coordinatesRatio() const
168 return _mapRatio > 1.0 ? _mapRatio / _tileRatio : 1.0;
171 qreal WMTSMap::imageRatio() const
173 return _mapRatio > 1.0 ? _mapRatio : _tileRatio;
176 QSizeF WMTSMap::tileSize(const WMTS::Zoom &zoom) const
178 return QSizeF(zoom.tile().width() / coordinatesRatio(),
179 zoom.tile().height() / coordinatesRatio());
182 void WMTSMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
184 const WMTS::Zoom &z = _wmts->zooms().at(_zoom);
185 QSizeF ts(tileSize(z));
187 QPoint tl = QPoint(qFloor(rect.left() / ts.width()),
188 qFloor(rect.top() / ts.height()));
189 QPoint br = QPoint(qCeil(rect.right() / ts.width()),
190 qCeil(rect.bottom() / ts.height()));
192 QVector<FetchTile> tiles;
193 tiles.reserve((br.x() - tl.x()) * (br.y() - tl.y()));
194 for (int i = tl.x(); i < br.x(); i++)
195 for (int j = tl.y(); j < br.y(); j++)
196 tiles.append(FetchTile(QPoint(i, j), z.id()));
198 if (flags & Map::Block)
199 _tileLoader->loadTilesSync(tiles);
200 else
201 _tileLoader->loadTilesAsync(tiles);
203 for (int i = 0; i < tiles.count(); i++) {
204 FetchTile &t = tiles[i];
205 QPointF tp(t.xy().x() * ts.width(), t.xy().y() * ts.height());
206 if (!t.pixmap().isNull()) {
207 t.pixmap().setDevicePixelRatio(imageRatio());
208 painter->drawPixmap(tp, t.pixmap());
213 QPointF WMTSMap::ll2xy(const Coordinates &c)
215 return _transform.proj2img(_wmts->projection().ll2xy(c))
216 / coordinatesRatio();
219 Coordinates WMTSMap::xy2ll(const QPointF &p)
221 return _wmts->projection().xy2ll(_transform.img2proj(p
222 * coordinatesRatio()));