4 #include "common/wgs84.h"
5 #include "common/rectc.h"
6 #include "common/programpaths.h"
7 #include "tileloader.h"
11 #define CAPABILITIES_FILE "capabilities.xml"
14 double WMSMap::sd2res(double scaleDenominator
) const
16 return scaleDenominator
* _wms
->projection().units().fromMeters(1.0)
20 QString
WMSMap::tileUrl() const
22 const WMS::Setup
&setup
= _wms
->setup();
24 QString url
= QString("%1%2service=WMS&version=%3&request=GetMap&bbox=$bbox"
25 "&width=%4&height=%5&layers=%6&styles=%7&format=%8&transparent=true")
26 .arg(_wms
->getMapUrl(), _wms
->getMapUrl().contains('?') ? "&" : "?",
27 _wms
->version(), QString::number(_tileSize
), QString::number(_tileSize
),
28 setup
.layer(), setup
.style(), setup
.format());
30 if (_wms
->version() >= "1.3.0")
31 url
.append(QString("&CRS=%1").arg(setup
.crs()));
33 url
.append(QString("&SRS=%1").arg(setup
.crs()));
35 for (int i
= 0; i
< setup
.dimensions().size(); i
++) {
36 const KV
<QString
, QString
> &dim
= setup
.dimensions().at(i
);
37 url
.append(QString("&%1=%2").arg(dim
.key(), dim
.value()));
43 void WMSMap::computeZooms()
47 const RangeF
&sd
= _wms
->scaleDenominator();
49 double ld
= log2(sd
.max() - EPSILON
) - log2(sd
.min() + EPSILON
);
50 int cld
= (int)ceil(ld
);
51 double step
= ld
/ (double)cld
;
52 double lmax
= log2(sd
.max() - EPSILON
);
53 for (int i
= 0; i
<= cld
; i
++)
54 _zooms
.append(pow(2.0, lmax
- i
* step
));
56 _zooms
.append(sd
.min() + EPSILON
);
59 void WMSMap::updateTransform()
61 double pixelSpan
= sd2res(_zooms
.at(_zoom
));
62 if (_wms
->projection().isGeographic())
63 pixelSpan
/= deg2rad(WGS84_RADIUS
);
64 _transform
= Transform(ReferencePoint(PointD(0, 0),
65 _wms
->projection().ll2xy(_wms
->bbox().topLeft())),
66 PointD(pixelSpan
, pixelSpan
));
69 WMSMap::WMSMap(const QString
&fileName
, const QString
&name
,
70 const WMS::Setup
&setup
, int tileSize
, QObject
*parent
)
71 : Map(fileName
, parent
), _name(name
), _tileLoader(0), _zoom(0),
72 _tileSize(tileSize
), _mapRatio(1.0)
74 QString
tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name
));
76 _tileLoader
= new TileLoader(tilesDir
, this);
77 _tileLoader
->setHeaders(setup
.headers());
78 connect(_tileLoader
, &TileLoader::finished
, this, &WMSMap::tilesLoaded
);
80 _wms
= new WMS(QDir(tilesDir
).filePath(CAPABILITIES_FILE
), setup
, this);
81 connect(_wms
, &WMS::downloadFinished
, this, &WMSMap::wmsReady
);
88 _tileLoader
->setUrl(tileUrl());
89 _bounds
= RectD(_wms
->bbox(), _wms
->projection());
94 void WMSMap::wmsReady()
102 void WMSMap::load(const Projection
&in
, const Projection
&out
,
103 qreal deviceRatio
, bool hidpi
)
108 _mapRatio
= hidpi
? deviceRatio
: 1.0;
111 void WMSMap::clearCache()
113 _tileLoader
->clearCache();
116 QRectF
WMSMap::bounds()
118 return QRectF(_transform
.proj2img(_bounds
.topLeft()) / _mapRatio
,
119 _transform
.proj2img(_bounds
.bottomRight()) / _mapRatio
);
122 int WMSMap::zoomFit(const QSize
&size
, const RectC
&rect
)
124 if (rect
.isValid()) {
125 RectD
prect(rect
, _wms
->projection());
126 PointD
sc(prect
.width() / size
.width(), prect
.height() / size
.height());
127 double resolution
= qMax(qAbs(sc
.x()), qAbs(sc
.y()));
128 if (_wms
->projection().isGeographic())
129 resolution
*= deg2rad(WGS84_RADIUS
);
132 for (int i
= 0; i
< _zooms
.size(); i
++) {
133 if (sd2res(_zooms
.at(i
)) < resolution
/ _mapRatio
)
138 _zoom
= _zooms
.size() - 1;
144 void WMSMap::setZoom(int zoom
)
152 _zoom
= qMin(_zoom
+ 1, _zooms
.size() - 1);
157 int WMSMap::zoomOut()
159 _zoom
= qMax(_zoom
- 1, 0);
164 QPointF
WMSMap::ll2xy(const Coordinates
&c
)
166 return _transform
.proj2img(_wms
->projection().ll2xy(c
)) / _mapRatio
;
169 Coordinates
WMSMap::xy2ll(const QPointF
&p
)
171 return _wms
->projection().xy2ll(_transform
.img2proj(p
* _mapRatio
));
174 qreal
WMSMap::tileSize() const
176 return (_tileSize
/ _mapRatio
);
179 void WMSMap::draw(QPainter
*painter
, const QRectF
&rect
, Flags flags
)
181 QPoint tl
= QPoint(qFloor(rect
.left() / tileSize()),
182 qFloor(rect
.top() / tileSize()));
183 QPoint br
= QPoint(qCeil(rect
.right() / tileSize()),
184 qCeil(rect
.bottom() / tileSize()));
186 QVector
<FetchTile
> tiles
;
187 tiles
.reserve((br
.x() - tl
.x()) * (br
.y() - tl
.y()));
188 for (int i
= tl
.x(); i
< br
.x(); i
++) {
189 for (int j
= tl
.y(); j
< br
.y(); j
++) {
190 PointD
ttl(_transform
.img2proj(QPointF(i
* _tileSize
,
192 PointD
tbr(_transform
.img2proj(QPointF(i
* _tileSize
+ _tileSize
,
193 j
* _tileSize
+ _tileSize
)));
194 RectD bbox
= (_wms
->cs().axisOrder() == CoordinateSystem::YX
)
195 ? RectD(PointD(tbr
.y(), tbr
.x()), PointD(ttl
.y(), ttl
.x()))
198 tiles
.append(FetchTile(QPoint(i
, j
), _zoom
, bbox
));
202 if (flags
& Map::Block
)
203 _tileLoader
->loadTilesSync(tiles
);
205 _tileLoader
->loadTilesAsync(tiles
);
207 for (int i
= 0; i
< tiles
.count(); i
++) {
208 FetchTile
&t
= tiles
[i
];
209 QPointF
tp(t
.xy().x() * tileSize(), t
.xy().y() * tileSize());
210 if (!t
.pixmap().isNull()) {
211 t
.pixmap().setDevicePixelRatio(_mapRatio
);
212 painter
->drawPixmap(tp
, t
.pixmap());