mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-01-19 12:12:08 +01:00
288 lines
7.5 KiB
C++
288 lines
7.5 KiB
C++
#include <QFileInfo>
|
|
#include <QEventLoop>
|
|
#include <QXmlStreamReader>
|
|
#include <QStringList>
|
|
#include "downloader.h"
|
|
#include "crs.h"
|
|
#include "wms.h"
|
|
|
|
|
|
WMS::CTX::CTX(const Setup &setup) : setup(setup), formatSupported(false)
|
|
{
|
|
QStringList ll = setup.layer().split(',');
|
|
|
|
if (setup.style().isEmpty()) {
|
|
for (int i = 0; i < ll.size(); i++)
|
|
layers.append(Layer(ll.at(i)));
|
|
} else {
|
|
QStringList sl = setup.style().split(',');
|
|
if (ll.size() != sl.size())
|
|
return;
|
|
|
|
for (int i = 0; i < ll.size(); i++)
|
|
layers.append(Layer(ll.at(i), sl.at(i)));
|
|
}
|
|
}
|
|
|
|
void WMS::getMap(QXmlStreamReader &reader, CTX &ctx)
|
|
{
|
|
while (reader.readNextStartElement()) {
|
|
if (reader.name() == "Format") {
|
|
if (reader.readElementText() == ctx.setup.format())
|
|
ctx.formatSupported = true;
|
|
} else
|
|
reader.skipCurrentElement();
|
|
}
|
|
}
|
|
|
|
void WMS::request(QXmlStreamReader &reader, CTX &ctx)
|
|
{
|
|
while (reader.readNextStartElement()) {
|
|
if (reader.name() == "GetMap")
|
|
getMap(reader, ctx);
|
|
else
|
|
reader.skipCurrentElement();
|
|
}
|
|
}
|
|
|
|
QString WMS::style(QXmlStreamReader &reader)
|
|
{
|
|
QString name;
|
|
|
|
while (reader.readNextStartElement()) {
|
|
if (reader.name() == "Name")
|
|
name = reader.readElementText();
|
|
else
|
|
reader.skipCurrentElement();
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
RectC WMS::geographicBoundingBox(QXmlStreamReader &reader)
|
|
{
|
|
double left = NAN, top = NAN, right = NAN, bottom = NAN;
|
|
|
|
while (reader.readNextStartElement()) {
|
|
if (reader.name() == "westBoundLongitude")
|
|
left = reader.readElementText().toDouble();
|
|
else if (reader.name() == "eastBoundLongitude")
|
|
right = reader.readElementText().toDouble();
|
|
else if (reader.name() == "northBoundLatitude")
|
|
top = reader.readElementText().toDouble();
|
|
else if (reader.name() == "southBoundLatitude")
|
|
bottom = reader.readElementText().toDouble();
|
|
else
|
|
reader.skipCurrentElement();
|
|
}
|
|
|
|
return RectC(Coordinates(left, top), Coordinates(right, bottom));
|
|
}
|
|
|
|
void WMS::layer(QXmlStreamReader &reader, CTX &ctx,
|
|
const QList<QString> &pCRSs, const QList<QString> &pStyles,
|
|
RangeF &pScaleDenominator, RectC &pBoundingBox)
|
|
{
|
|
QString name;
|
|
QList<QString> CRSs(pCRSs);
|
|
QList<QString> styles(pStyles);
|
|
RangeF scaleDenominator(pScaleDenominator);
|
|
RectC boundingBox(pBoundingBox);
|
|
int index;
|
|
|
|
while (reader.readNextStartElement()) {
|
|
if (reader.name() == "Name")
|
|
name = reader.readElementText();
|
|
else if (reader.name() == "CRS" || reader.name() == "SRS")
|
|
CRSs.append(reader.readElementText());
|
|
else if (reader.name() == "Style")
|
|
styles.append(style(reader));
|
|
else if (reader.name() == "MinScaleDenominator") {
|
|
double sd = reader.readElementText().toDouble();
|
|
if (sd > 0)
|
|
scaleDenominator.setMin(sd);
|
|
} else if (reader.name() == "MaxScaleDenominator") {
|
|
double sd = reader.readElementText().toDouble();
|
|
if (sd > 0)
|
|
scaleDenominator.setMax(sd);
|
|
} else if (reader.name() == "LatLonBoundingBox") {
|
|
QXmlStreamAttributes attr = reader.attributes();
|
|
boundingBox = RectC(Coordinates(
|
|
attr.value("minx").toString().toDouble(),
|
|
attr.value("maxy").toString().toDouble()),
|
|
Coordinates(attr.value("maxx").toString().toDouble(),
|
|
attr.value("miny").toString().toDouble()));
|
|
reader.skipCurrentElement();
|
|
} else if (reader.name() == "EX_GeographicBoundingBox")
|
|
boundingBox = geographicBoundingBox(reader);
|
|
else if (reader.name() == "Layer")
|
|
layer(reader, ctx, CRSs, styles, scaleDenominator, boundingBox);
|
|
else
|
|
reader.skipCurrentElement();
|
|
}
|
|
|
|
if ((index = ctx.layers.indexOf(name)) >= 0) {
|
|
Layer &layer = ctx.layers[index];
|
|
layer.scaleDenominator = scaleDenominator;
|
|
layer.boundingBox = boundingBox;
|
|
layer.isDefined = true;
|
|
layer.hasStyle = styles.contains(layer.style) || layer.style.isEmpty();
|
|
layer.hasCRS = CRSs.contains(ctx.setup.crs());
|
|
}
|
|
}
|
|
|
|
void WMS::capability(QXmlStreamReader &reader, CTX &ctx)
|
|
{
|
|
QList<QString> CRSs;
|
|
QList<QString> styles;
|
|
RangeF scaleDenominator(133.295598991, 559082264.0287178);
|
|
RectC boundingBox;
|
|
|
|
while (reader.readNextStartElement()) {
|
|
if (reader.name() == "Layer")
|
|
layer(reader, ctx, CRSs, styles, scaleDenominator, boundingBox);
|
|
else if (reader.name() == "Request")
|
|
request(reader, ctx);
|
|
else
|
|
reader.skipCurrentElement();
|
|
}
|
|
}
|
|
|
|
void WMS::capabilities(QXmlStreamReader &reader, CTX &ctx)
|
|
{
|
|
_version = reader.attributes().value("version").toString();
|
|
|
|
while (reader.readNextStartElement()) {
|
|
if (reader.name() == "Capability")
|
|
capability(reader, ctx);
|
|
else
|
|
reader.skipCurrentElement();
|
|
}
|
|
}
|
|
|
|
bool WMS::parseCapabilities(const QString &path, const Setup &setup)
|
|
{
|
|
QFile file(path);
|
|
CTX ctx(setup);
|
|
QXmlStreamReader reader;
|
|
|
|
|
|
if (ctx.layers.isEmpty()) {
|
|
_errorString = "Invalid layers/styles list definition";
|
|
return false;
|
|
}
|
|
|
|
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
|
_errorString = file.errorString();
|
|
return false;
|
|
}
|
|
|
|
reader.setDevice(&file);
|
|
if (reader.readNextStartElement()) {
|
|
if (reader.name() == "WMS_Capabilities"
|
|
|| reader.name() == "WMT_MS_Capabilities")
|
|
capabilities(reader, ctx);
|
|
else
|
|
reader.raiseError("Not a WMS Capabilities XML file");
|
|
}
|
|
if (reader.error()) {
|
|
_errorString = QString("%1:%2: %3").arg(path).arg(reader.lineNumber())
|
|
.arg(reader.errorString());
|
|
return false;
|
|
}
|
|
|
|
if (!ctx.formatSupported) {
|
|
_errorString = ctx.setup.format() + ": format not provided";
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < ctx.layers.size(); i++) {
|
|
const Layer &layer = ctx.layers.at(i);
|
|
|
|
if (!layer.isDefined) {
|
|
_errorString = layer.name + ": layer not provided";
|
|
return false;
|
|
}
|
|
if (!layer.hasStyle) {
|
|
_errorString = layer.style + ": style not provided for layer "
|
|
+ layer.name;
|
|
return false;
|
|
}
|
|
if (!layer.hasCRS) {
|
|
_errorString = ctx.setup.crs() + ": CRS not provided for layer "
|
|
+ layer.name;
|
|
return false;
|
|
}
|
|
if (!layer.scaleDenominator.isValid()
|
|
|| layer.scaleDenominator.isNull()) {
|
|
_errorString = "Invalid scale denominator range for layer "
|
|
+ layer.name;
|
|
return false;
|
|
}
|
|
if (!layer.boundingBox.isValid()) {
|
|
_errorString = "Invalid/missing bounding box for layer "
|
|
+ layer.name;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
_projection = CRS::projection(ctx.setup.crs());
|
|
if (!_projection.isValid()) {
|
|
_errorString = ctx.setup.crs() + ": unknown CRS";
|
|
return false;
|
|
}
|
|
|
|
_boundingBox = ctx.layers.first().boundingBox;
|
|
for (int i = 1; i < ctx.layers.size(); i++)
|
|
_boundingBox &= ctx.layers.at(i).boundingBox;
|
|
if (_boundingBox.isNull()) {
|
|
_errorString = "Empty layers bounding box join";
|
|
return false;
|
|
}
|
|
|
|
_scaleDenominator = ctx.layers.first().scaleDenominator;
|
|
for (int i = 1; i < ctx.layers.size(); i++)
|
|
_scaleDenominator &= ctx.layers.at(i).scaleDenominator;
|
|
if (_scaleDenominator.isNull()) {
|
|
_errorString = "Empty layers scale denominator range join";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool WMS::getCapabilities(const QString &url, const QString &file,
|
|
const Authorization &authorization)
|
|
{
|
|
Downloader d;
|
|
QList<Download> dl;
|
|
|
|
dl.append(Download(url, file));
|
|
|
|
QEventLoop wait;
|
|
QObject::connect(&d, SIGNAL(finished()), &wait, SLOT(quit()));
|
|
if (d.get(dl, authorization))
|
|
wait.exec();
|
|
|
|
if (QFileInfo(file).exists())
|
|
return true;
|
|
else {
|
|
_errorString = "Error downloading capabilities XML file";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
WMS::WMS(const QString &file, const WMS::Setup &setup) : _valid(false)
|
|
{
|
|
QString capaUrl = QString("%1%2service=WMS&request=GetCapabilities")
|
|
.arg(setup.url(), setup.url().contains('?') ? "&" : "?");
|
|
|
|
if (!QFileInfo(file).exists())
|
|
if (!getCapabilities(capaUrl, file, setup.authorization()))
|
|
return;
|
|
if (!parseCapabilities(file, setup))
|
|
return;
|
|
|
|
_valid = true;
|
|
}
|