1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-28 13:41:16 +01:00

Added support for REST WMTS maps

This commit is contained in:
Martin Tůma 2018-02-25 02:31:01 +01:00
parent 55e967673c
commit 5e5ff6d96f
9 changed files with 105 additions and 49 deletions

View File

@ -126,21 +126,20 @@ Map *MapSource::map(QXmlStreamReader &reader)
{ {
QString name, url, layer, style, set; QString name, url, layer, style, set;
QString format("image/png"); QString format("image/png");
bool invert = false; bool wmts, rest = false, invertAxis = false;
Range z(ZOOM_MIN, ZOOM_MAX); Range z(ZOOM_MIN, ZOOM_MAX);
RectC b(Coordinates(BOUNDS_LEFT, BOUNDS_TOP), RectC b(Coordinates(BOUNDS_LEFT, BOUNDS_TOP),
Coordinates(BOUNDS_RIGHT, BOUNDS_BOTTOM)); Coordinates(BOUNDS_RIGHT, BOUNDS_BOTTOM));
const QXmlStreamAttributes &attr = reader.attributes(); wmts = (reader.attributes().value("type") == "WMTS") ? true : false;
bool wmts = (attr.hasAttribute("type") && attr.value("type") == "WMTS")
? true : false;
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == "name") if (reader.name() == "name")
name = reader.readElementText(); name = reader.readElementText();
else if (reader.name() == "url") else if (reader.name() == "url") {
rest = (reader.attributes().value("type") == "REST") ? true : false;
url = reader.readElementText(); url = reader.readElementText();
else if (reader.name() == "zoom") { } else if (reader.name() == "zoom") {
z = zooms(reader); z = zooms(reader);
reader.skipCurrentElement(); reader.skipCurrentElement();
} else if (reader.name() == "bounds") { } else if (reader.name() == "bounds") {
@ -155,7 +154,7 @@ Map *MapSource::map(QXmlStreamReader &reader)
else if (reader.name() == "set") else if (reader.name() == "set")
set = reader.readElementText(); set = reader.readElementText();
else if (reader.name() == "axis") else if (reader.name() == "axis")
invert = (reader.readElementText() == "yx") ? true : false; invertAxis = (reader.readElementText() == "yx") ? true : false;
else else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
@ -163,7 +162,8 @@ Map *MapSource::map(QXmlStreamReader &reader)
if (reader.error()) if (reader.error())
return 0; return 0;
else if (wmts) else if (wmts)
return new WMTSMap(name, url, format, layer, style, set, invert); return new WMTSMap(name, WMTS::Setup(url, layer, set, style, format,
rest), invertAxis);
else else
return new OnlineMap(name, url, z, b); return new OnlineMap(name, url, z, b);
} }

View File

@ -41,12 +41,21 @@ static int scale2zoom(qreal scale)
OnlineMap::OnlineMap(const QString &name, const QString &url, OnlineMap::OnlineMap(const QString &name, const QString &url,
const Range &zooms, const RectC &bounds, QObject *parent) const Range &zooms, const RectC &bounds, QObject *parent) :
: Map(parent), _name(name), _zooms(zooms), _bounds(bounds) Map(parent), _name(name), _zooms(zooms), _bounds(bounds),
_block(false), _valid(false)
{ {
_block = false; QString dir(TILES_DIR + "/" + _name);
_zoom = _zooms.max(); _zoom = _zooms.max();
_tileLoader = TileLoader(url, TILES_DIR + "/" + name); _tileLoader = TileLoader(url, dir);
if (!QDir().mkpath(dir)) {
_errorString = "Error creating tiles dir";
return;
}
_valid = true;
} }
void OnlineMap::load() void OnlineMap::load()

View File

@ -39,6 +39,9 @@ public:
void load(); void load();
void unload(); void unload();
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
private slots: private slots:
void emitLoaded(); void emitLoaded();
@ -53,6 +56,9 @@ private:
RectC _bounds; RectC _bounds;
int _zoom; int _zoom;
bool _block; bool _block;
bool _valid;
QString _errorString;
}; };
#endif // ONLINEMAP_H #endif // ONLINEMAP_H

View File

@ -17,13 +17,6 @@ static bool loadTileFile(Tile &tile, const QString &file)
Downloader *TileLoader::_downloader = 0; Downloader *TileLoader::_downloader = 0;
TileLoader::TileLoader(const QString &url, const QString &dir)
: _url(url), _dir(dir)
{
if (!QDir().mkpath(_dir))
qWarning("Error creating tiles dir: %s\n", qPrintable(_dir));
}
void TileLoader::loadTilesAsync(QList<Tile> &list) void TileLoader::loadTilesAsync(QList<Tile> &list)
{ {
QList<Download> dl; QList<Download> dl;

View File

@ -9,7 +9,8 @@ class TileLoader
{ {
public: public:
TileLoader() {} TileLoader() {}
TileLoader(const QString &url, const QString &dir); TileLoader(const QString &url, const QString &dir)
: _url(url), _dir(dir) {}
void loadTilesAsync(QList<Tile> &list); void loadTilesAsync(QList<Tile> &list);
void loadTilesSync(QList<Tile> &list); void loadTilesSync(QList<Tile> &list);

View File

@ -194,6 +194,7 @@ void WMTS::layer(QXmlStreamReader &reader, const QString &layer,
{ {
QString id; QString id;
RectC bounds; RectC bounds;
QString tpl;
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == "Identifier") if (reader.name() == "Identifier")
@ -202,12 +203,19 @@ void WMTS::layer(QXmlStreamReader &reader, const QString &layer,
tileMatrixSetLink(reader, set); tileMatrixSetLink(reader, set);
else if (reader.name() == "WGS84BoundingBox") else if (reader.name() == "WGS84BoundingBox")
bounds = wgs84BoundingBox(reader); bounds = wgs84BoundingBox(reader);
else else if (reader.name() == "ResourceURL") {
const QXmlStreamAttributes &attr = reader.attributes();
if (attr.value("resourceType") == "tile")
tpl = attr.value("template").toString();
reader.skipCurrentElement();
} else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
if (id == layer) if (id == layer) {
_bounds = bounds; _bounds = bounds;
_tileUrl = tpl;
}
} }
void WMTS::contents(QXmlStreamReader &reader, const QString &layer, void WMTS::contents(QXmlStreamReader &reader, const QString &layer,
@ -264,9 +272,7 @@ bool WMTS::getCapabilities(const QString &url, const QString &file)
{ {
QList<Download> dl; QList<Download> dl;
QString capabilitiesUrl = QString("%1?service=WMTS&Version=1.0.0" dl.append(Download(url, file));
"&request=GetCapabilities").arg(url);
dl.append(Download(capabilitiesUrl, file));
QEventLoop wait; QEventLoop wait;
QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit())); QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit()));
@ -281,17 +287,31 @@ bool WMTS::getCapabilities(const QString &url, const QString &file)
} }
} }
bool WMTS::load(const QString &file, const QString &url, const QString &layer, bool WMTS::load(const QString &file, const WMTS::Setup &setup)
const QString &set)
{ {
QMap<QString, Zoom>::const_iterator it; QString capaUrl = setup.rest ? setup.url :
QString("%1?service=WMTS&Version=1.0.0&request=GetCapabilities")
.arg(setup.url);
if (!QFileInfo(file).exists()) if (!QFileInfo(file).exists())
if (!getCapabilities(url, file)) if (!getCapabilities(capaUrl, file))
return false; return false;
if (!parseCapabilities(file, layer, set)) if (!parseCapabilities(file, setup.layer, setup.set))
return false; return false;
if (!setup.rest)
_tileUrl = QString("%1?service=WMTS&Version=1.0.0&request=GetTile"
"&Format=%2&Layer=%3&Style=%4&TileMatrixSet=%5&TileMatrix=$z"
"&TileRow=$y&TileCol=$x").arg(setup.url).arg(setup.format)
.arg(setup.layer).arg(setup.style).arg(setup.set);
else {
_tileUrl.replace("{Style}", setup.style);
_tileUrl.replace("{TileMatrixSet}", setup.set);
_tileUrl.replace("{TileMatrix}", "$z");
_tileUrl.replace("{TileRow}", "$y");
_tileUrl.replace("{TileCol}", "$x");
}
if (_matrixes.isEmpty()) { if (_matrixes.isEmpty()) {
_errorString = "No usable tile matrix found"; _errorString = "No usable tile matrix found";
return false; return false;
@ -300,6 +320,10 @@ bool WMTS::load(const QString &file, const QString &url, const QString &layer,
_errorString = "Missing CRS definition"; _errorString = "Missing CRS definition";
return false; return false;
} }
if (_tileUrl.isNull()) {
_errorString = "Missing tile URL";
return false;
}
return true; return true;
} }
@ -325,6 +349,14 @@ QList<WMTS::Zoom> WMTS::zooms() const
} }
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const WMTS::Setup &setup)
{
dbg.nospace() << "Setup(" << setup.url << ", " << setup.layer << ", "
<< setup.set << ", " << setup.style << ", " << setup.format << ", "
<< setup.rest << ")";
return dbg.space();
}
QDebug operator<<(QDebug dbg, const WMTS::Zoom &zoom) QDebug operator<<(QDebug dbg, const WMTS::Zoom &zoom)
{ {
dbg.nospace() << "Zoom(" << zoom.id << ", " << zoom.scaleDenominator << ", " dbg.nospace() << "Zoom(" << zoom.id << ", " << zoom.scaleDenominator << ", "

View File

@ -15,6 +15,20 @@ class Downloader;
class WMTS class WMTS
{ {
public: public:
struct Setup {
QString url;
QString layer;
QString set;
QString style;
QString format;
bool rest;
Setup(const QString &url, const QString &layer, const QString &set,
const QString &style, const QString &format, bool rest) :
url(url), layer(layer), set(set), style(style), format(format),
rest(rest) {}
};
struct Zoom { struct Zoom {
QString id; QString id;
qreal scaleDenominator; qreal scaleDenominator;
@ -32,13 +46,13 @@ public:
{return scaleDenominator > other.scaleDenominator;} {return scaleDenominator > other.scaleDenominator;}
}; };
bool load(const QString &path, const QString &url, const QString &layer, bool load(const QString &path, const Setup &setup);
const QString &set);
const QString &errorString() const {return _errorString;} const QString &errorString() const {return _errorString;}
const RectC &bounds() const {return _bounds;} const RectC &bounds() const {return _bounds;}
QList<Zoom> zooms() const; QList<Zoom> zooms() const;
const Projection &projection() const {return _projection;} const Projection &projection() const {return _projection;}
QString tileUrl() const {return _tileUrl;}
static Downloader *downloader() {return _downloader;} static Downloader *downloader() {return _downloader;}
static void setDownloader(Downloader *downloader) static void setDownloader(Downloader *downloader)
@ -94,6 +108,7 @@ private:
QSet<MatrixLimits> _limits; QSet<MatrixLimits> _limits;
RectC _bounds; RectC _bounds;
Projection _projection; Projection _projection;
QString _tileUrl;
QString _errorString; QString _errorString;
@ -114,6 +129,7 @@ inline uint qHash(const WMTS::MatrixLimits &key)
} }
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const WMTS::Setup &setup);
QDebug operator<<(QDebug dbg, const WMTS::Zoom &zoom); QDebug operator<<(QDebug dbg, const WMTS::Zoom &zoom);
#endif // QT_NO_DEBUG #endif // QT_NO_DEBUG

View File

@ -9,30 +9,27 @@
#define CAPABILITIES_FILE "capabilities.xml" #define CAPABILITIES_FILE "capabilities.xml"
WMTSMap::WMTSMap(const QString &name, const QString &url, const QString &format, WMTSMap::WMTSMap(const QString &name, const WMTS::Setup &setup, bool invertAxis,
const QString &layer, const QString &style, const QString &set, QObject *parent) : Map(parent), _name(name), _setup(setup),
bool invertAxis, QObject *parent) : _invertAxis(invertAxis), _zoom(0), _valid(false)
Map(parent), _name(name), _url(url), _layer(layer), _set(set),
_invertAxis(invertAxis), _zoom(0), _valid(false)
{ {
QString dir(TILES_DIR + "/" + _name); QString dir(TILES_DIR + "/" + _name);
QString file = dir + "/" + CAPABILITIES_FILE; QString file = dir + "/" + CAPABILITIES_FILE;
QString tileUrl = QString("%1?service=WMTS&Version=1.0.0&request=GetTile" if (!QDir().mkpath(dir)) {
"&Format=%2&Layer=%3&Style=%4&TileMatrixSet=%5&TileMatrix=$z&TileRow=$y" _errorString = "Error creating tiles dir";
"&TileCol=$x").arg(_url).arg(format).arg(layer).arg(style) return;
.arg(_set); }
_tileLoader = TileLoader(tileUrl, dir);
WMTS wmts; WMTS wmts;
if (!wmts.load(file, _url, _layer, _set)) { if (!wmts.load(file, _setup)) {
_errorString = wmts.errorString(); _errorString = wmts.errorString();
return; return;
} }
_bounds = wmts.bounds(); _bounds = wmts.bounds();
_zooms = wmts.zooms(); _zooms = wmts.zooms();
_projection = wmts.projection(); _projection = wmts.projection();
_tileLoader = TileLoader(wmts.tileUrl(), dir);
updateTransform(); updateTransform();
_block = false; _block = false;
@ -91,10 +88,12 @@ void WMTSMap::clearCache()
_tileLoader.clearCache(); _tileLoader.clearCache();
WMTS wmts; WMTS wmts;
if (!wmts.load(file, _url, _layer, _set)) if (!wmts.load(file, _setup))
return; return;
_bounds = wmts.bounds();
_zooms = wmts.zooms(); _zooms = wmts.zooms();
_projection = wmts.projection(); _projection = wmts.projection();
_tileLoader = TileLoader(wmts.tileUrl(), dir);
if (_zoom >= _zooms.size()) if (_zoom >= _zooms.size())
_zoom = _zooms.size() - 1; _zoom = _zooms.size() - 1;

View File

@ -13,9 +13,8 @@ class WMTSMap : public Map
Q_OBJECT Q_OBJECT
public: public:
WMTSMap(const QString &name, const QString &url, const QString &format, WMTSMap(const QString &name, const WMTS::Setup &setup, bool invertAxis,
const QString &layer, const QString &style, const QString &set, QObject *parent = 0);
bool invertAxis, QObject *parent = 0);
const QString &name() const {return _name;} const QString &name() const {return _name;}
@ -54,7 +53,8 @@ private:
QPointF ll2xy(const Coordinates &c) const; QPointF ll2xy(const Coordinates &c) const;
Coordinates xy2ll(const QPointF &p) const; Coordinates xy2ll(const QPointF &p) const;
QString _name, _url, _layer, _set; QString _name;
WMTS::Setup _setup;
TileLoader _tileLoader; TileLoader _tileLoader;
RectC _bounds; RectC _bounds;
QList<WMTS::Zoom> _zooms; QList<WMTS::Zoom> _zooms;