1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-06 14:53:21 +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;
}
void WMTS::tileMatrix(QXmlStreamReader &reader)
WMTS::TileMatrix WMTS::tileMatrix(QXmlStreamReader &reader)
{
Zoom zoom;
TileMatrix matrix;
while (reader.readNextStartElement()) {
if (reader.name() == "Identifier")
zoom.id = reader.readElementText();
matrix.id = reader.readElementText();
else if (reader.name() == "ScaleDenominator")
zoom.scaleDenominator = reader.readElementText().toDouble();
matrix.scaleDenominator = reader.readElementText().toDouble();
else if (reader.name() == "TopLeftCorner") {
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")
zoom.tile.setWidth(reader.readElementText().toInt());
matrix.tile.setWidth(reader.readElementText().toInt());
else if (reader.name() == "TileHeight")
zoom.tile.setHeight(reader.readElementText().toInt());
matrix.tile.setHeight(reader.readElementText().toInt());
else if (reader.name() == "MatrixWidth")
zoom.matrix.setWidth(reader.readElementText().toInt());
matrix.matrix.setWidth(reader.readElementText().toInt());
else if (reader.name() == "MatrixHeight")
zoom.matrix.setHeight(reader.readElementText().toInt());
matrix.matrix.setHeight(reader.readElementText().toInt());
else
reader.skipCurrentElement();
}
Zoom &z = _zooms[zoom.id];
z.id = zoom.id;
z.matrix = zoom.matrix;
z.scaleDenominator = zoom.scaleDenominator;
z.tile = zoom.tile;
z.topLeft = zoom.topLeft;
if (!matrix.isValid())
reader.raiseError("Invalid TileMatrix definition");
return matrix;
}
void WMTS::tileMatrixSet(QXmlStreamReader &reader, const QString &set)
{
QString id;
QString id, crs;
QSet<TileMatrix> matrixes;
while (reader.readNextStartElement()) {
if (reader.name() == "Identifier")
id = reader.readElementText();
else if (reader.name() == "SupportedCRS" && id == set) {
if (!createProjection(reader.readElementText()))
reader.raiseError("Invalid/unknown CRS");
} else if (reader.name() == "TileMatrix" && id == set)
tileMatrix(reader);
else if (reader.name() == "SupportedCRS")
crs = reader.readElementText();
else if (reader.name() == "TileMatrix")
matrixes.insert(tileMatrix(reader));
else
reader.skipCurrentElement();
}
if (id == set) {
if (!createProjection(crs)) {
reader.raiseError("Invalid/unknown CRS");
return;
}
_matrixes.unite(matrixes);
}
}
void WMTS::tileMatrixLimits(QXmlStreamReader &reader)
WMTS::MatrixLimits WMTS::tileMatrixLimits(QXmlStreamReader &reader)
{
QString id;
QRect limits;
MatrixLimits limits;
while (reader.readNextStartElement()) {
if (reader.name() == "TileMatrix")
id = reader.readElementText();
limits.id = reader.readElementText();
else if (reader.name() == "MinTileRow")
limits.setTop(reader.readElementText().toInt());
limits.rect.setTop(reader.readElementText().toInt());
else if (reader.name() == "MaxTileRow")
limits.setBottom(reader.readElementText().toInt());
limits.rect.setBottom(reader.readElementText().toInt());
else if (reader.name() == "MinTileCol")
limits.setLeft(reader.readElementText().toInt());
limits.rect.setLeft(reader.readElementText().toInt());
else if (reader.name() == "MaxTileCol")
limits.setRight(reader.readElementText().toInt());
limits.rect.setRight(reader.readElementText().toInt());
else
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()) {
if (reader.name() == "TileMatrixLimits")
tileMatrixLimits(reader);
limits.insert(tileMatrixLimits(reader));
else
reader.skipCurrentElement();
}
return limits;
}
void WMTS::tileMatrixSetLink(QXmlStreamReader &reader, const QString &set)
{
QString id;
QSet<MatrixLimits> limits;
while (reader.readNextStartElement()) {
if (reader.name() == "TileMatrixSet")
id = reader.readElementText();
else if (reader.name() == "TileMatrixSetLimits" && id == set)
tileMatrixSetLimits(reader);
else if (reader.name() == "TileMatrixSetLimits")
limits = tileMatrixSetLimits(reader);
else
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,
const QString &set)
{
QString id;
RectC bounds;
while (reader.readNextStartElement()) {
if (reader.name() == "Identifier")
id = reader.readElementText();
else if (reader.name() == "TileMatrixSetLink" && id == layer)
else if (reader.name() == "TileMatrixSetLink")
tileMatrixSetLink(reader, set);
else if (reader.name() == "WGS84BoundingBox")
bounds = wgs84BoundingBox(reader);
else
reader.skipCurrentElement();
}
if (id == layer)
_bounds = bounds;
}
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))
return false;
if (_matrixes.isEmpty()) {
_errorString = "No usable tile matrix found";
return false;
}
if (_projection.isNull()) {
_errorString = "Missing CRS definition";
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;
}
QList<WMTS::Zoom> WMTS::zooms() const
{
QList<Zoom> z(_zooms.values());
qSort(z);
return z;
QList<Zoom> zooms;
QSet<TileMatrix>::const_iterator mi;
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
QDebug operator<<(QDebug dbg, const WMTS::Zoom &zoom)
{
dbg.nospace() << "Zoom(" << zoom.scaleDenominator << ", " << zoom.topLeft
<< ", " << zoom.tile << ", " << zoom.matrix << ", " << zoom.limits << ")";
dbg.nospace() << "Zoom(" << zoom.id << ", " << zoom.scaleDenominator << ", "
<< zoom.topLeft << ", " << zoom.tile << ", " << zoom.matrix << ", "
<< zoom.limits << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

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

View File

@ -29,6 +29,7 @@ WMTSMap::WMTSMap(const QString &name, const QString &url, const QString &format,
_errorString = wmts.errorString();
return;
}
_bounds = wmts.bounds();
_zooms = wmts.zooms();
_projection = wmts.projection();
@ -108,14 +109,18 @@ void WMTSMap::emitLoaded()
QRectF WMTSMap::bounds() const
{
const WMTS::Zoom &z = _zooms.at(_zoom);
QRectF tileBounds, bounds;
if (z.limits.isNull())
return QRectF(QPointF(0, 0), QSize(z.tile.width() * z.matrix.width(),
z.tile.height() * z.matrix.height()));
else
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()));
tileBounds = (z.limits.isNull()) ?
QRectF(QPointF(0, 0), QSize(z.tile.width() * z.matrix.width(),
z.tile.height() * z.matrix.height())) : 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()));
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)

View File

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