From d11ffc9ea4196d1817854028a43449a9fd0c9e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Sat, 24 Feb 2018 01:59:03 +0100 Subject: [PATCH] Added tile matrix set limits handling Added axis order setting --- src/map/mapsource.cpp | 11 +++-- src/map/wmts.cpp | 103 ++++++++++++++++++++++++++++++++++++++---- src/map/wmts.h | 31 +++++++++---- src/map/wmtsmap.cpp | 34 ++++++++------ src/map/wmtsmap.h | 7 +-- 5 files changed, 145 insertions(+), 41 deletions(-) diff --git a/src/map/mapsource.cpp b/src/map/mapsource.cpp index ffa3de86..7707ddf5 100644 --- a/src/map/mapsource.cpp +++ b/src/map/mapsource.cpp @@ -124,7 +124,8 @@ RectC MapSource::bounds(QXmlStreamReader &reader) Map *MapSource::map(QXmlStreamReader &reader) { - QString name, url, format, layer, style, tileMatrixSet; + QString name, url, format, layer, style, set; + bool invert = false; Range z(ZOOM_MIN, ZOOM_MAX); RectC b(Coordinates(BOUNDS_LEFT, BOUNDS_TOP), Coordinates(BOUNDS_RIGHT, BOUNDS_BOTTOM)); @@ -150,8 +151,10 @@ Map *MapSource::map(QXmlStreamReader &reader) layer = reader.readElementText(); else if (reader.name() == "style") style = reader.readElementText(); - else if (reader.name() == "tilematrixset") - tileMatrixSet = reader.readElementText(); + else if (reader.name() == "set") + set = reader.readElementText(); + else if (reader.name() == "axis") + invert = (reader.readElementText() == "yx") ? true : false; else reader.skipCurrentElement(); } @@ -159,7 +162,7 @@ Map *MapSource::map(QXmlStreamReader &reader) if (reader.error()) return 0; else if (wmts) - return new WMTSMap(name, url, format, layer, style, tileMatrixSet); + return new WMTSMap(name, url, format, layer, style, set, invert); else return new OnlineMap(name, url, z, b); } diff --git a/src/map/wmts.cpp b/src/map/wmts.cpp index fc7dde58..5f745044 100644 --- a/src/map/wmts.cpp +++ b/src/map/wmts.cpp @@ -52,10 +52,13 @@ bool WMTS::createProjection(const QString &crs) void WMTS::tileMatrix(QXmlStreamReader &reader) { + int id; Zoom zoom; while (reader.readNextStartElement()) { - if (reader.name() == "ScaleDenominator") + if (reader.name() == "Identifier") + id = reader.readElementText().toInt(); + else if (reader.name() == "ScaleDenominator") zoom.scaleDenominator = reader.readElementText().toDouble(); else if (reader.name() == "TopLeftCorner") { QString str = reader.readElementText(); @@ -72,7 +75,11 @@ void WMTS::tileMatrix(QXmlStreamReader &reader) reader.skipCurrentElement(); } - _zooms.append(zoom); + Zoom &z = _zooms[id]; + z.matrix = zoom.matrix; + z.scaleDenominator = zoom.scaleDenominator; + z.tile = zoom.tile; + z.topLeft = zoom.topLeft; } void WMTS::tileMatrixSet(QXmlStreamReader &reader, const QString &set) @@ -92,27 +99,94 @@ void WMTS::tileMatrixSet(QXmlStreamReader &reader, const QString &set) } } -void WMTS::contents(QXmlStreamReader &reader, const QString &set) +void WMTS::tileMatrixLimits(QXmlStreamReader &reader) +{ + int id; + QRect limits; + + while (reader.readNextStartElement()) { + if (reader.name() == "TileMatrix") + id = reader.readElementText().toInt(); + else if (reader.name() == "MinTileRow") + limits.setTop(reader.readElementText().toInt()); + else if (reader.name() == "MaxTileRow") + limits.setBottom(reader.readElementText().toInt()); + else if (reader.name() == "MinTileCol") + limits.setLeft(reader.readElementText().toInt()); + else if (reader.name() == "MaxTileCol") + limits.setRight(reader.readElementText().toInt()); + else + reader.skipCurrentElement(); + } + + _zooms[id].limits = limits; +} + +void WMTS::tileMatrixSetLimits(QXmlStreamReader &reader) +{ + while (reader.readNextStartElement()) { + if (reader.name() == "TileMatrixLimits") + tileMatrixLimits(reader); + else + reader.skipCurrentElement(); + } +} + +void WMTS::tileMatrixSetLink(QXmlStreamReader &reader, const QString &set) +{ + QString id; + + while (reader.readNextStartElement()) { + if (reader.name() == "TileMatrixSet") + id = reader.readElementText(); + else if (reader.name() == "TileMatrixSetLimits" && id == set) + tileMatrixSetLimits(reader); + else + reader.skipCurrentElement(); + } +} + +void WMTS::layer(QXmlStreamReader &reader, const QString &layer, + const QString &set) +{ + QString id; + + while (reader.readNextStartElement()) { + if (reader.name() == "Identifier") + id = reader.readElementText(); + else if (reader.name() == "TileMatrixSetLink" && id == layer) + tileMatrixSetLink(reader, set); + else + reader.skipCurrentElement(); + } +} + +void WMTS::contents(QXmlStreamReader &reader, const QString &layer, + const QString &set) { while (reader.readNextStartElement()) { if (reader.name() == "TileMatrixSet") tileMatrixSet(reader, set); + else if (reader.name() == "Layer") + WMTS::layer(reader, layer, set); else reader.skipCurrentElement(); } } -void WMTS::capabilities(QXmlStreamReader &reader, const QString &set) +void WMTS::capabilities(QXmlStreamReader &reader, const QString &layer, + const QString &set) { while (reader.readNextStartElement()) { if (reader.name() == "Contents") - contents(reader, set); + contents(reader, layer, set); else reader.skipCurrentElement(); } } -bool WMTS::parseCapabilities(const QString &path, const QString &tileMatrixSet) +bool WMTS::parseCapabilities(const QString &path, const QString &layer, + const QString &set) { QFile file(path); QXmlStreamReader reader; @@ -126,7 +200,7 @@ bool WMTS::parseCapabilities(const QString &path, const QString &tileMatrixSet) if (reader.readNextStartElement()) { if (reader.name() == "Capabilities") - capabilities(reader, tileMatrixSet); + capabilities(reader, layer, set); else reader.raiseError("Not a Capabilities XML file"); } @@ -158,13 +232,13 @@ bool WMTS::getCapabilities(const QString &url, const QString &file) } } -bool WMTS::load(const QString &file, const QString &url, - const QString &tileMatrixSet) +bool WMTS::load(const QString &file, const QString &url, const QString &layer, + const QString &set) { if (!QFileInfo(file).exists()) if (!getCapabilities(url, file)) return false; - if (!parseCapabilities(file, tileMatrixSet)) + if (!parseCapabilities(file, layer, set)) return false; if (_projection.isNull()) { @@ -178,3 +252,12 @@ bool WMTS::load(const QString &file, const QString &url, return true; } + +#ifndef QT_NO_DEBUG +QDebug operator<<(QDebug dbg, const WMTS::Zoom &zoom) +{ + dbg.nospace() << "Zoom(" << zoom.scaleDenominator << ", " << zoom.topLeft + << ", " << zoom.tile << ", " << zoom.matrix << ", " << zoom.limits << ")"; + return dbg.space(); +} +#endif // QT_NO_DEBUG diff --git a/src/map/wmts.h b/src/map/wmts.h index e0172a9d..d82ea13f 100644 --- a/src/map/wmts.h +++ b/src/map/wmts.h @@ -2,7 +2,7 @@ #define WMTS_H #include -#include +#include #include "projection.h" class QXmlStreamReader; @@ -16,14 +16,15 @@ public: QPointF topLeft; QSize tile; QSize matrix; + QRect limits; }; - bool load(const QString &path, const QString &url, - const QString &tileMatrixSet); + bool load(const QString &path, const QString &url, const QString &layer, + const QString &set); const QString &errorString() const {return _errorString;} - const QList &zooms() {return _zooms;} - const Projection &projection() {return _projection;} + const QList zooms() const {return _zooms.values();} + const Projection &projection() const {return _projection;} static Downloader *downloader() {return _downloader;} static void setDownloader(Downloader *downloader) @@ -32,14 +33,22 @@ public: private: bool createProjection(const QString &crs); + void tileMatrixLimits(QXmlStreamReader &reader); void tileMatrix(QXmlStreamReader &reader); + void tileMatrixSetLimits(QXmlStreamReader &reader); void tileMatrixSet(QXmlStreamReader &reader, const QString &set); - void contents(QXmlStreamReader &reader, const QString &set); - void capabilities(QXmlStreamReader &reader, const QString &set); - bool parseCapabilities(const QString &path, const QString &tileMatrixSet); + void tileMatrixSetLink(QXmlStreamReader &reader, const QString &set); + void layer(QXmlStreamReader &reader, const QString &layer, + const QString &set); + void contents(QXmlStreamReader &reader, const QString &layer, + const QString &set); + void capabilities(QXmlStreamReader &reader, const QString &layer, + const QString &set); + bool parseCapabilities(const QString &path, const QString &layer, + const QString &set); bool getCapabilities(const QString &url, const QString &file); - QList _zooms; + QMap _zooms; Projection _projection; QString _errorString; @@ -47,4 +56,8 @@ private: static Downloader *_downloader; }; +#ifndef QT_NO_DEBUG +QDebug operator<<(QDebug dbg, const WMTS::Zoom &zoom); +#endif // QT_NO_DEBUG + #endif // WMTS_H diff --git a/src/map/wmtsmap.cpp b/src/map/wmtsmap.cpp index 84ab9365..e4a27e3b 100644 --- a/src/map/wmtsmap.cpp +++ b/src/map/wmtsmap.cpp @@ -10,9 +10,10 @@ #define CAPABILITIES_FILE "capabilities.xml" WMTSMap::WMTSMap(const QString &name, const QString &url, const QString &format, - const QString &layer, const QString &style, const QString &tileMatrixSet, - QObject *parent) : Map(parent), _name(name), _url(url), - _tileMatrixSet(tileMatrixSet), _zoom(0), _valid(false) + const QString &layer, const QString &style, const QString &set, + bool invertAxis, QObject *parent) : + Map(parent), _name(name), _url(url), _layer(layer), _set(set), + _invertAxis(invertAxis), _zoom(0), _valid(false) { QString dir(TILES_DIR + "/" + _name); QString file = dir + "/" + CAPABILITIES_FILE; @@ -20,11 +21,11 @@ WMTSMap::WMTSMap(const QString &name, const QString &url, const QString &format, QString 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(_url).arg(format).arg(layer).arg(style) - .arg(_tileMatrixSet); + .arg(_set); _tileLoader = TileLoader(tileUrl, dir); WMTS wmts; - if (!wmts.load(file, _url, _tileMatrixSet)) { + if (!wmts.load(file, _url, _layer, _set)) { _errorString = wmts.errorString(); return; } @@ -51,11 +52,13 @@ void WMTSMap::updateTransform() if (_projection.isGeographic()) pixelSpan /= deg2rad(WGS84_RADIUS); QPointF tileSpan(z.tile.width() * pixelSpan, z.tile.height() * pixelSpan); - QPointF bottomRight(z.topLeft.x() + tileSpan.x() * z.matrix.width(), - z.topLeft.y() - tileSpan.y() * z.matrix.height()); + QPointF topLeft = _invertAxis + ? QPointF(z.topLeft.y(), z.topLeft.x()) : z.topLeft; + QPointF bottomRight(topLeft.x() + tileSpan.x() * z.matrix.width(), + topLeft.y() - tileSpan.y() * z.matrix.height()); tl.xy = QPoint(0, 0); - tl.pp = z.topLeft; + tl.pp = topLeft; br.xy = QPoint(z.tile.width() * z.matrix.width(), z.tile.height() * z.matrix.height()); br.pp = bottomRight; @@ -87,7 +90,7 @@ void WMTSMap::clearCache() _tileLoader.clearCache(); WMTS wmts; - if (!wmts.load(file, _url, _tileMatrixSet)) + if (!wmts.load(file, _url, _layer, _set)) return; _zooms = wmts.zooms(); _projection = wmts.projection(); @@ -105,8 +108,9 @@ void WMTSMap::emitLoaded() QRectF WMTSMap::bounds() const { const WMTS::Zoom &z = _zooms.at(_zoom); - return QRectF(QPointF(0, 0), QSize(z.tile.width() * z.matrix.width(), - z.tile.height() * z.matrix.height())); + return QRectF(QPointF(z.limits.left() * z.tile.width(), z.limits.top() + * z.tile.height()), QSize(z.tile.width() * z.limits.width(), + z.tile.height() * z.limits.height())); } qreal WMTSMap::zoomFit(const QSize &size, const RectC &br) @@ -174,12 +178,12 @@ void WMTSMap::draw(QPainter *painter, const QRectF &rect) const WMTS::Zoom &z = _zooms.at(_zoom); QPoint tl = QPoint((int)floor(rect.left() / (qreal)z.tile.width()), (int)floor(rect.top() / (qreal)z.tile.height())); - QPoint br = QPoint((int)floor(rect.right() / (qreal)z.tile.width()), - (int)floor(rect.bottom() / (qreal)z.tile.height())); + QPoint br = QPoint((int)ceil(rect.right() / (qreal)z.tile.width()), + (int)ceil(rect.bottom() / (qreal)z.tile.height())); QList tiles; - for (int i = tl.x(); i <= br.x(); i++) - for (int j = tl.y(); j <= br.y(); j++) + for (int i = tl.x(); i < br.x(); i++) + for (int j = tl.y(); j < br.y(); j++) tiles.append(Tile(QPoint(i, j), _zoom)); if (_block) diff --git a/src/map/wmtsmap.h b/src/map/wmtsmap.h index 8be82205..40811bac 100644 --- a/src/map/wmtsmap.h +++ b/src/map/wmtsmap.h @@ -14,8 +14,8 @@ class WMTSMap : public Map public: WMTSMap(const QString &name, const QString &url, const QString &format, - const QString &layer, const QString &style, const QString &tileMatrixSet, - QObject *parent = 0); + const QString &layer, const QString &style, const QString &set, + bool invertAxis, QObject *parent = 0); const QString &name() const {return _name;} @@ -54,9 +54,10 @@ private: QPointF ll2xy(const Coordinates &c) const; Coordinates xy2ll(const QPointF &p) const; - QString _name, _url, _tileMatrixSet; + QString _name, _url, _layer, _set; TileLoader _tileLoader; QList _zooms; + bool _invertAxis; Projection _projection; QTransform _transform, _inverted; int _zoom;