1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-06 23:03:22 +02:00

Improved capabilities xml parsing

Improved bounds handling
This commit is contained in:
Martin Tůma 2018-02-24 16:44:30 +01:00
parent fa3e6d8550
commit ee80260e46
4 changed files with 169 additions and 67 deletions

View File

@ -58,115 +58,156 @@ bool WMTS::createProjection(const QString &crs)
return false; return false;
} }
void WMTS::tileMatrix(QXmlStreamReader &reader) WMTS::TileMatrix WMTS::tileMatrix(QXmlStreamReader &reader)
{ {
Zoom zoom; TileMatrix matrix;
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == "Identifier") if (reader.name() == "Identifier")
zoom.id = reader.readElementText(); matrix.id = reader.readElementText();
else if (reader.name() == "ScaleDenominator") else if (reader.name() == "ScaleDenominator")
zoom.scaleDenominator = reader.readElementText().toDouble(); matrix.scaleDenominator = reader.readElementText().toDouble();
else if (reader.name() == "TopLeftCorner") { else if (reader.name() == "TopLeftCorner") {
QString str = reader.readElementText(); QString str = reader.readElementText();
QTextStream(&str) >> zoom.topLeft.rx() >> zoom.topLeft.ry(); QTextStream(&str) >> matrix.topLeft.rx() >> matrix.topLeft.ry();
} else if (reader.name() == "TileWidth") } else if (reader.name() == "TileWidth")
zoom.tile.setWidth(reader.readElementText().toInt()); matrix.tile.setWidth(reader.readElementText().toInt());
else if (reader.name() == "TileHeight") else if (reader.name() == "TileHeight")
zoom.tile.setHeight(reader.readElementText().toInt()); matrix.tile.setHeight(reader.readElementText().toInt());
else if (reader.name() == "MatrixWidth") else if (reader.name() == "MatrixWidth")
zoom.matrix.setWidth(reader.readElementText().toInt()); matrix.matrix.setWidth(reader.readElementText().toInt());
else if (reader.name() == "MatrixHeight") else if (reader.name() == "MatrixHeight")
zoom.matrix.setHeight(reader.readElementText().toInt()); matrix.matrix.setHeight(reader.readElementText().toInt());
else else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
Zoom &z = _zooms[zoom.id]; if (!matrix.isValid())
z.id = zoom.id; reader.raiseError("Invalid TileMatrix definition");
z.matrix = zoom.matrix;
z.scaleDenominator = zoom.scaleDenominator; return matrix;
z.tile = zoom.tile;
z.topLeft = zoom.topLeft;
} }
void WMTS::tileMatrixSet(QXmlStreamReader &reader, const QString &set) void WMTS::tileMatrixSet(QXmlStreamReader &reader, const QString &set)
{ {
QString id; QString id, crs;
QSet<TileMatrix> matrixes;
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == "Identifier") if (reader.name() == "Identifier")
id = reader.readElementText(); id = reader.readElementText();
else if (reader.name() == "SupportedCRS" && id == set) { else if (reader.name() == "SupportedCRS")
if (!createProjection(reader.readElementText())) crs = reader.readElementText();
reader.raiseError("Invalid/unknown CRS"); else if (reader.name() == "TileMatrix")
} else if (reader.name() == "TileMatrix" && id == set) matrixes.insert(tileMatrix(reader));
tileMatrix(reader);
else else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
if (id == set) {
if (!createProjection(crs)) {
reader.raiseError("Invalid/unknown CRS");
return;
} }
void WMTS::tileMatrixLimits(QXmlStreamReader &reader) _matrixes.unite(matrixes);
}
}
WMTS::MatrixLimits WMTS::tileMatrixLimits(QXmlStreamReader &reader)
{ {
QString id; MatrixLimits limits;
QRect limits;
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == "TileMatrix") if (reader.name() == "TileMatrix")
id = reader.readElementText(); limits.id = reader.readElementText();
else if (reader.name() == "MinTileRow") else if (reader.name() == "MinTileRow")
limits.setTop(reader.readElementText().toInt()); limits.rect.setTop(reader.readElementText().toInt());
else if (reader.name() == "MaxTileRow") else if (reader.name() == "MaxTileRow")
limits.setBottom(reader.readElementText().toInt()); limits.rect.setBottom(reader.readElementText().toInt());
else if (reader.name() == "MinTileCol") else if (reader.name() == "MinTileCol")
limits.setLeft(reader.readElementText().toInt()); limits.rect.setLeft(reader.readElementText().toInt());
else if (reader.name() == "MaxTileCol") else if (reader.name() == "MaxTileCol")
limits.setRight(reader.readElementText().toInt()); limits.rect.setRight(reader.readElementText().toInt());
else else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
_zooms[id].limits = limits; if (!limits.isValid())
reader.raiseError("Invalid TileMatrixLimits definition");
return limits;
} }
void WMTS::tileMatrixSetLimits(QXmlStreamReader &reader) QSet<WMTS::MatrixLimits> WMTS::tileMatrixSetLimits(QXmlStreamReader &reader)
{ {
QSet<MatrixLimits> limits;
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == "TileMatrixLimits") if (reader.name() == "TileMatrixLimits")
tileMatrixLimits(reader); limits.insert(tileMatrixLimits(reader));
else else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
return limits;
} }
void WMTS::tileMatrixSetLink(QXmlStreamReader &reader, const QString &set) void WMTS::tileMatrixSetLink(QXmlStreamReader &reader, const QString &set)
{ {
QString id; QString id;
QSet<MatrixLimits> limits;
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == "TileMatrixSet") if (reader.name() == "TileMatrixSet")
id = reader.readElementText(); id = reader.readElementText();
else if (reader.name() == "TileMatrixSetLimits" && id == set) else if (reader.name() == "TileMatrixSetLimits")
tileMatrixSetLimits(reader); limits = tileMatrixSetLimits(reader);
else else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
if (id == set)
_limits.unite(limits);
}
RectC WMTS::wgs84BoundingBox(QXmlStreamReader &reader)
{
Coordinates topLeft, bottomRight;
while (reader.readNextStartElement()) {
if (reader.name() == "LowerCorner") {
QString str = reader.readElementText();
QTextStream(&str) >> topLeft.rlon() >> bottomRight.rlat();
} else if (reader.name() == "UpperCorner") {
QString str = reader.readElementText();
QTextStream(&str) >> bottomRight.rlon() >> topLeft.rlat();
} else
reader.skipCurrentElement();
}
return RectC(topLeft, bottomRight);
} }
void WMTS::layer(QXmlStreamReader &reader, const QString &layer, void WMTS::layer(QXmlStreamReader &reader, const QString &layer,
const QString &set) const QString &set)
{ {
QString id; QString id;
RectC bounds;
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == "Identifier") if (reader.name() == "Identifier")
id = reader.readElementText(); id = reader.readElementText();
else if (reader.name() == "TileMatrixSetLink" && id == layer) else if (reader.name() == "TileMatrixSetLink")
tileMatrixSetLink(reader, set); tileMatrixSetLink(reader, set);
else if (reader.name() == "WGS84BoundingBox")
bounds = wgs84BoundingBox(reader);
else else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
if (id == layer)
_bounds = bounds;
} }
void WMTS::contents(QXmlStreamReader &reader, const QString &layer, void WMTS::contents(QXmlStreamReader &reader, const QString &layer,
@ -251,36 +292,44 @@ bool WMTS::load(const QString &file, const QString &url, const QString &layer,
if (!parseCapabilities(file, layer, set)) if (!parseCapabilities(file, layer, set))
return false; return false;
if (_matrixes.isEmpty()) {
_errorString = "No usable tile matrix found";
return false;
}
if (_projection.isNull()) { if (_projection.isNull()) {
_errorString = "Missing CRS definition"; _errorString = "Missing CRS definition";
return false; return false;
} }
if (_zooms.isEmpty()) {
_errorString = "No tile matrix found";
return false;
}
for (it = _zooms.constBegin(); it != _zooms.constEnd(); ++it) {
if (!it->isValid()) {
_errorString = it->id + ": invalid tile matrix definition";
return false;
}
}
return true; return true;
} }
QList<WMTS::Zoom> WMTS::zooms() const QList<WMTS::Zoom> WMTS::zooms() const
{ {
QList<Zoom> z(_zooms.values()); QList<Zoom> zooms;
qSort(z); QSet<TileMatrix>::const_iterator mi;
return z; QSet<MatrixLimits>::const_iterator li;
for (mi = _matrixes.constBegin(); mi != _matrixes.constEnd(); ++mi) {
if ((li = _limits.find(MatrixLimits(mi->id))) == _limits.constEnd())
zooms.append(Zoom(mi->id, mi->scaleDenominator, mi->topLeft,
mi->tile, mi->matrix, QRect()));
else
zooms.append(Zoom(Zoom(mi->id, mi->scaleDenominator, mi->topLeft,
mi->tile, mi->matrix, li->rect)));
}
qSort(zooms);
return zooms;
} }
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const WMTS::Zoom &zoom) QDebug operator<<(QDebug dbg, const WMTS::Zoom &zoom)
{ {
dbg.nospace() << "Zoom(" << zoom.scaleDenominator << ", " << zoom.topLeft dbg.nospace() << "Zoom(" << zoom.id << ", " << zoom.scaleDenominator << ", "
<< ", " << zoom.tile << ", " << zoom.matrix << ", " << zoom.limits << ")"; << zoom.topLeft << ", " << zoom.tile << ", " << zoom.matrix << ", "
<< zoom.limits << ")";
return dbg.space(); return dbg.space();
} }
#endif // QT_NO_DEBUG #endif // QT_NO_DEBUG

View File

@ -2,8 +2,10 @@
#define WMTS_H #define WMTS_H
#include <QSize> #include <QSize>
#include <QMap> #include <QSet>
#include <QList> #include <QList>
#include <QHash>
#include "common/rectc.h"
#include "projection.h" #include "projection.h"
class QXmlStreamReader; class QXmlStreamReader;
@ -20,18 +22,20 @@ public:
QSize matrix; QSize matrix;
QRect limits; QRect limits;
Zoom() : scaleDenominator(0) {} Zoom() {}
Zoom(const QString &id, qreal scaleDenominator, const QPointF &topLeft,
const QSize &tile, const QSize &matrix, const QRect &limits) :
id(id), scaleDenominator(scaleDenominator), topLeft(topLeft),
tile(tile), matrix(matrix), limits(limits) {}
bool operator<(const Zoom &other) const bool operator<(const Zoom &other) const
{return this->scaleDenominator > other.scaleDenominator;} {return scaleDenominator > other.scaleDenominator;}
bool isValid() const
{return scaleDenominator > 0 && !id.isEmpty() && tile.isValid()
&& matrix.isValid();}
}; };
bool load(const QString &path, const QString &url, const QString &layer, bool load(const QString &path, const QString &url, const QString &layer,
const QString &set); const QString &set);
const QString &errorString() const {return _errorString;} const QString &errorString() const {return _errorString;}
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;}
@ -40,11 +44,39 @@ public:
{_downloader = downloader;} {_downloader = downloader;}
private: private:
struct TileMatrix {
QString id;
qreal scaleDenominator;
QPointF topLeft;
QSize tile;
QSize matrix;
TileMatrix() : scaleDenominator(0) {}
bool operator==(const TileMatrix &other) const
{return this->id == other.id;}
bool isValid() const
{return !id.isEmpty() && scaleDenominator > 0 && tile.isValid()
&& matrix.isValid();}
};
struct MatrixLimits {
QString id;
QRect rect;
MatrixLimits() {}
MatrixLimits(const QString &id) : id(id) {}
bool operator==(const MatrixLimits &other) const
{return this->id == other.id;}
bool isValid() const
{return !id.isEmpty() && rect.isValid();}
};
bool createProjection(const QString &crs); bool createProjection(const QString &crs);
void tileMatrixLimits(QXmlStreamReader &reader); RectC wgs84BoundingBox(QXmlStreamReader &reader);
void tileMatrix(QXmlStreamReader &reader); MatrixLimits tileMatrixLimits(QXmlStreamReader &reader);
void tileMatrixSetLimits(QXmlStreamReader &reader); TileMatrix tileMatrix(QXmlStreamReader &reader);
QSet<MatrixLimits> tileMatrixSetLimits(QXmlStreamReader &reader);
void tileMatrixSet(QXmlStreamReader &reader, const QString &set); void tileMatrixSet(QXmlStreamReader &reader, const QString &set);
void tileMatrixSetLink(QXmlStreamReader &reader, const QString &set); void tileMatrixSetLink(QXmlStreamReader &reader, const QString &set);
void layer(QXmlStreamReader &reader, const QString &layer, void layer(QXmlStreamReader &reader, const QString &layer,
@ -57,14 +89,29 @@ private:
const QString &set); const QString &set);
bool getCapabilities(const QString &url, const QString &file); bool getCapabilities(const QString &url, const QString &file);
QMap<QString, Zoom> _zooms; QSet<TileMatrix> _matrixes;
QSet<MatrixLimits> _limits;
RectC _bounds;
Projection _projection; Projection _projection;
QString _errorString; QString _errorString;
static Downloader *_downloader; static Downloader *_downloader;
friend uint qHash(const WMTS::TileMatrix &key);
friend uint qHash(const WMTS::MatrixLimits &key);
}; };
inline uint qHash(const WMTS::TileMatrix &key)
{
return ::qHash(key.id);
}
inline uint qHash(const WMTS::MatrixLimits &key)
{
return ::qHash(key.id);
}
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
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

@ -29,6 +29,7 @@ WMTSMap::WMTSMap(const QString &name, const QString &url, const QString &format,
_errorString = wmts.errorString(); _errorString = wmts.errorString();
return; return;
} }
_bounds = wmts.bounds();
_zooms = wmts.zooms(); _zooms = wmts.zooms();
_projection = wmts.projection(); _projection = wmts.projection();
@ -108,14 +109,18 @@ void WMTSMap::emitLoaded()
QRectF WMTSMap::bounds() const QRectF WMTSMap::bounds() const
{ {
const WMTS::Zoom &z = _zooms.at(_zoom); const WMTS::Zoom &z = _zooms.at(_zoom);
QRectF tileBounds, bounds;
if (z.limits.isNull()) tileBounds = (z.limits.isNull()) ?
return QRectF(QPointF(0, 0), QSize(z.tile.width() * z.matrix.width(), QRectF(QPointF(0, 0), QSize(z.tile.width() * z.matrix.width(),
z.tile.height() * z.matrix.height())); z.tile.height() * z.matrix.height())) : QRectF(QPointF(z.limits.left()
else * z.tile.width(), z.limits.top() * z.tile.height()), QSize(z.tile.width()
return QRectF(QPointF(z.limits.left() * z.tile.width(), z.limits.top() * z.limits.width(), z.tile.height() * z.limits.height()));
* z.tile.height()), QSize(z.tile.width() * z.limits.width(),
z.tile.height() * z.limits.height())); bounds = _bounds.isValid() ? QRectF(ll2xy(_bounds.topLeft()),
ll2xy(_bounds.bottomRight())) : QRectF();
return _bounds.isValid() ? tileBounds.intersected(bounds) : tileBounds;
} }
qreal WMTSMap::zoomFit(const QSize &size, const RectC &br) qreal WMTSMap::zoomFit(const QSize &size, const RectC &br)

View File

@ -56,6 +56,7 @@ private:
QString _name, _url, _layer, _set; QString _name, _url, _layer, _set;
TileLoader _tileLoader; TileLoader _tileLoader;
RectC _bounds;
QList<WMTS::Zoom> _zooms; QList<WMTS::Zoom> _zooms;
bool _invertAxis; bool _invertAxis;
Projection _projection; Projection _projection;