1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-24 11:45:53 +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 format("image/png");
bool invert = false;
bool wmts, rest = false, invertAxis = false;
Range z(ZOOM_MIN, ZOOM_MAX);
RectC b(Coordinates(BOUNDS_LEFT, BOUNDS_TOP),
Coordinates(BOUNDS_RIGHT, BOUNDS_BOTTOM));
const QXmlStreamAttributes &attr = reader.attributes();
bool wmts = (attr.hasAttribute("type") && attr.value("type") == "WMTS")
? true : false;
wmts = (reader.attributes().value("type") == "WMTS") ? true : false;
while (reader.readNextStartElement()) {
if (reader.name() == "name")
name = reader.readElementText();
else if (reader.name() == "url")
else if (reader.name() == "url") {
rest = (reader.attributes().value("type") == "REST") ? true : false;
url = reader.readElementText();
else if (reader.name() == "zoom") {
} else if (reader.name() == "zoom") {
z = zooms(reader);
reader.skipCurrentElement();
} else if (reader.name() == "bounds") {
@ -155,7 +154,7 @@ Map *MapSource::map(QXmlStreamReader &reader)
else if (reader.name() == "set")
set = reader.readElementText();
else if (reader.name() == "axis")
invert = (reader.readElementText() == "yx") ? true : false;
invertAxis = (reader.readElementText() == "yx") ? true : false;
else
reader.skipCurrentElement();
}
@ -163,7 +162,8 @@ Map *MapSource::map(QXmlStreamReader &reader)
if (reader.error())
return 0;
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
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,
const Range &zooms, const RectC &bounds, QObject *parent)
: Map(parent), _name(name), _zooms(zooms), _bounds(bounds)
const Range &zooms, const RectC &bounds, QObject *parent) :
Map(parent), _name(name), _zooms(zooms), _bounds(bounds),
_block(false), _valid(false)
{
_block = false;
QString dir(TILES_DIR + "/" + _name);
_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()

View File

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

View File

@ -17,13 +17,6 @@ static bool loadTileFile(Tile &tile, const QString &file)
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)
{
QList<Download> dl;

View File

@ -9,7 +9,8 @@ class TileLoader
{
public:
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 loadTilesSync(QList<Tile> &list);

View File

@ -194,6 +194,7 @@ void WMTS::layer(QXmlStreamReader &reader, const QString &layer,
{
QString id;
RectC bounds;
QString tpl;
while (reader.readNextStartElement()) {
if (reader.name() == "Identifier")
@ -202,12 +203,19 @@ void WMTS::layer(QXmlStreamReader &reader, const QString &layer,
tileMatrixSetLink(reader, set);
else if (reader.name() == "WGS84BoundingBox")
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();
}
if (id == layer)
if (id == layer) {
_bounds = bounds;
_tileUrl = tpl;
}
}
void WMTS::contents(QXmlStreamReader &reader, const QString &layer,
@ -264,9 +272,7 @@ bool WMTS::getCapabilities(const QString &url, const QString &file)
{
QList<Download> dl;
QString capabilitiesUrl = QString("%1?service=WMTS&Version=1.0.0"
"&request=GetCapabilities").arg(url);
dl.append(Download(capabilitiesUrl, file));
dl.append(Download(url, file));
QEventLoop wait;
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,
const QString &set)
bool WMTS::load(const QString &file, const WMTS::Setup &setup)
{
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 (!getCapabilities(url, file))
if (!getCapabilities(capaUrl, file))
return false;
if (!parseCapabilities(file, layer, set))
if (!parseCapabilities(file, setup.layer, setup.set))
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()) {
_errorString = "No usable tile matrix found";
return false;
@ -300,6 +320,10 @@ bool WMTS::load(const QString &file, const QString &url, const QString &layer,
_errorString = "Missing CRS definition";
return false;
}
if (_tileUrl.isNull()) {
_errorString = "Missing tile URL";
return false;
}
return true;
}
@ -325,6 +349,14 @@ QList<WMTS::Zoom> WMTS::zooms() const
}
#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)
{
dbg.nospace() << "Zoom(" << zoom.id << ", " << zoom.scaleDenominator << ", "

View File

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

View File

@ -9,30 +9,27 @@
#define CAPABILITIES_FILE "capabilities.xml"
WMTSMap::WMTSMap(const QString &name, const QString &url, const QString &format,
const QString &layer, const QString &style, const QString &set,
bool invertAxis, QObject *parent) :
Map(parent), _name(name), _url(url), _layer(layer), _set(set),
WMTSMap::WMTSMap(const QString &name, const WMTS::Setup &setup, bool invertAxis,
QObject *parent) : Map(parent), _name(name), _setup(setup),
_invertAxis(invertAxis), _zoom(0), _valid(false)
{
QString dir(TILES_DIR + "/" + _name);
QString file = dir + "/" + CAPABILITIES_FILE;
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(_set);
_tileLoader = TileLoader(tileUrl, dir);
if (!QDir().mkpath(dir)) {
_errorString = "Error creating tiles dir";
return;
}
WMTS wmts;
if (!wmts.load(file, _url, _layer, _set)) {
if (!wmts.load(file, _setup)) {
_errorString = wmts.errorString();
return;
}
_bounds = wmts.bounds();
_zooms = wmts.zooms();
_projection = wmts.projection();
_tileLoader = TileLoader(wmts.tileUrl(), dir);
updateTransform();
_block = false;
@ -91,10 +88,12 @@ void WMTSMap::clearCache()
_tileLoader.clearCache();
WMTS wmts;
if (!wmts.load(file, _url, _layer, _set))
if (!wmts.load(file, _setup))
return;
_bounds = wmts.bounds();
_zooms = wmts.zooms();
_projection = wmts.projection();
_tileLoader = TileLoader(wmts.tileUrl(), dir);
if (_zoom >= _zooms.size())
_zoom = _zooms.size() - 1;

View File

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