4 #include "common/rectc.h"
5 #include "common/wgs84.h"
6 #include "common/programpaths.h"
8 #include "tileloader.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
);
34 _tileLoader
->setUrl(_wmts
->tileUrl());
35 _bounds
= RectD(_wmts
->bbox(), _wmts
->projection());
39 void WMTSMap::wmtsReady()
47 void WMTSMap::load(const Projection
&in
, const Projection
&out
,
48 qreal deviceRatio
, bool hidpi
)
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())
106 return lb
.isValid() ? lb
& tb
: tb
;
109 RectC
WMTSMap::llBounds(const Projection
&)
111 if (_wmts
->bbox().isValid())
112 return _wmts
->bbox();
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
);
133 for (int i
= 0; i
< _wmts
->zooms().size(); i
++) {
134 if (sd2res(_wmts
->zooms().at(i
).scaleDenominator()) < resolution
135 / coordinatesRatio())
140 _zoom
= _wmts
->zooms().size() - 1;
146 void WMTSMap::setZoom(int zoom
)
152 int WMTSMap::zoomIn()
154 _zoom
= qMin(_zoom
+ 1, _wmts
->zooms().size() - 1);
159 int WMTSMap::zoomOut()
161 _zoom
= qMax(_zoom
- 1, 0);
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
);
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()));