1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-07 07:13:21 +02:00
GPXSee/src/map/mapsource.cpp

311 lines
8.5 KiB
C++
Raw Normal View History

#include <QFile>
#include <QXmlStreamReader>
#include "common/config.h"
#include "onlinemap.h"
2018-02-20 23:37:19 +01:00
#include "wmtsmap.h"
#include "wmsmap.h"
2018-09-22 14:17:24 +02:00
#include "osm.h"
2018-01-29 00:19:57 +01:00
#include "mapsource.h"
2018-09-25 21:07:44 +02:00
MapSource::Config::Config() : type(OSM), zooms(OSM::ZOOMS), bounds(OSM::BOUNDS),
format("image/png"), rest(false), tileRatio(1.0), tileSize(256),
scalable(false) {}
2018-04-07 18:42:25 +02:00
static CoordinateSystem coordinateSystem(QXmlStreamReader &reader)
{
QXmlStreamAttributes attr = reader.attributes();
if (attr.value("axis") == "yx")
2018-04-05 21:13:48 +02:00
return CoordinateSystem::YX;
else if (attr.value("axis") == "xy")
2018-04-05 21:13:48 +02:00
return CoordinateSystem::XY;
else
2018-04-05 21:13:48 +02:00
return CoordinateSystem::Unknown;
}
2018-02-27 21:50:29 +01:00
Range MapSource::zooms(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
int min, max;
bool res;
if (attr.hasAttribute("min")) {
min = attr.value("min").toString().toInt(&res);
2018-09-25 21:07:44 +02:00
if (!res || !OSM::ZOOMS.contains(min)) {
reader.raiseError("Invalid minimal zoom level");
2018-02-27 21:50:29 +01:00
return Range();
}
} else
2018-09-25 21:07:44 +02:00
min = OSM::ZOOMS.min();
if (attr.hasAttribute("max")) {
max = attr.value("max").toString().toInt(&res);
2018-09-25 21:07:44 +02:00
if (!res || !OSM::ZOOMS.contains(max)) {
reader.raiseError("Invalid maximal zoom level");
2018-02-27 21:50:29 +01:00
return Range();
}
} else
2018-09-25 21:07:44 +02:00
max = OSM::ZOOMS.max();
2018-02-27 21:50:29 +01:00
if (min > max) {
reader.raiseError("Invalid maximal/minimal zoom level combination");
2018-02-27 21:50:29 +01:00
return Range();
}
return Range(min, max);
}
2018-02-27 21:50:29 +01:00
RectC MapSource::bounds(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
double top, left, bottom, right;
bool res;
if (attr.hasAttribute("top")) {
top = attr.value("top").toString().toDouble(&res);
2018-09-25 21:07:44 +02:00
if (!res || (top < OSM::BOUNDS.bottom() || top > OSM::BOUNDS.top())) {
reader.raiseError("Invalid bounds top value");
2018-02-27 21:50:29 +01:00
return RectC();
}
} else
2018-09-25 21:07:44 +02:00
top = OSM::BOUNDS.top();
if (attr.hasAttribute("bottom")) {
bottom = attr.value("bottom").toString().toDouble(&res);
2018-09-25 21:07:44 +02:00
if (!res || (bottom < OSM::BOUNDS.bottom()
|| bottom > OSM::BOUNDS.top())) {
reader.raiseError("Invalid bounds bottom value");
2018-02-27 21:50:29 +01:00
return RectC();
}
} else
2018-09-25 21:07:44 +02:00
bottom = OSM::BOUNDS.bottom();
if (attr.hasAttribute("left")) {
left = attr.value("left").toString().toDouble(&res);
2018-09-25 21:07:44 +02:00
if (!res || (left < OSM::BOUNDS.left() || left > OSM::BOUNDS.right())) {
reader.raiseError("Invalid bounds left value");
2018-02-27 21:50:29 +01:00
return RectC();
}
} else
2018-09-25 21:07:44 +02:00
left = OSM::BOUNDS.left();
if (attr.hasAttribute("right")) {
right = attr.value("right").toString().toDouble(&res);
2018-09-25 21:07:44 +02:00
if (!res || (right < OSM::BOUNDS.left()
|| right > OSM::BOUNDS.right())) {
reader.raiseError("Invalid bounds right value");
2018-02-27 21:50:29 +01:00
return RectC();
}
} else
2018-09-25 21:07:44 +02:00
right = OSM::BOUNDS.right();
2018-02-27 21:50:29 +01:00
if (bottom >= top) {
reader.raiseError("Invalid bottom/top bounds combination");
2018-02-27 21:50:29 +01:00
return RectC();
}
2018-02-27 21:50:29 +01:00
if (left >= right) {
reader.raiseError("Invalid left/right bounds combination");
2018-02-27 21:50:29 +01:00
return RectC();
}
2018-02-27 21:50:29 +01:00
return RectC(Coordinates(left, top), Coordinates(right, bottom));
}
2018-12-08 02:27:27 +01:00
void MapSource::tile(QXmlStreamReader &reader, Config &config)
{
QXmlStreamAttributes attr = reader.attributes();
bool ok;
if (attr.hasAttribute("size")) {
int size = attr.value("size").toString().toInt(&ok);
if (!ok || size < 0) {
reader.raiseError("Invalid tile size");
return;
} else
config.tileSize = size;
}
if (attr.hasAttribute("type")) {
if (attr.value("type") == "raster")
config.scalable = false;
else if (attr.value("type") == "vector")
config.scalable = true;
else {
reader.raiseError("Invalid tile type");
return;
}
}
if (attr.hasAttribute("pixelRatio")) {
#ifdef ENABLE_HIDPI
qreal ratio = attr.value("pixelRatio").toString().toDouble(&ok);
if (!ok || ratio < 0) {
reader.raiseError("Invalid tile pixelRatio");
return;
} else
config.tileRatio = ratio;
#else // ENABLE_HIDPI
reader.raiseError("HiDPI maps not supported");
#endif // ENABLE_HIDPI
}
}
void MapSource::map(QXmlStreamReader &reader, Config &config)
{
const QXmlStreamAttributes &attr = reader.attributes();
2018-09-22 13:32:54 +02:00
QStringRef type = attr.value("type");
if (type == "WMTS")
config.type = WMTS;
else if (type == "WMS")
config.type = WMS;
else if (type == "TMS")
config.type = TMS;
2019-05-20 23:23:24 +02:00
else if (type == "QuadTiles")
config.type = QuadTiles;
2018-09-22 13:32:54 +02:00
else if (type == "OSM" || type.isEmpty())
config.type = OSM;
else {
reader.raiseError("Invalid map type");
return;
}
2018-02-20 23:37:19 +01:00
while (reader.readNextStartElement()) {
if (reader.name() == "name")
config.name = reader.readElementText();
2018-02-25 02:31:01 +01:00
else if (reader.name() == "url") {
config.rest = (reader.attributes().value("type") == "REST")
2018-02-27 21:50:29 +01:00
? true : false;
config.url = reader.readElementText();
2018-02-25 02:31:01 +01:00
} else if (reader.name() == "zoom") {
config.zooms = zooms(reader);
reader.skipCurrentElement();
} else if (reader.name() == "bounds") {
config.bounds = bounds(reader);
reader.skipCurrentElement();
} else if (reader.name() == "format")
config.format = reader.readElementText();
else if (reader.name() == "layer")
config.layer = reader.readElementText();
2018-02-20 23:37:19 +01:00
else if (reader.name() == "style")
config.style = reader.readElementText();
else if (reader.name() == "set") {
2018-04-07 18:42:25 +02:00
config.coordinateSystem = coordinateSystem(reader);
config.set = reader.readElementText();
2018-03-11 10:31:41 +01:00
} else if (reader.name() == "dimension") {
QXmlStreamAttributes attr = reader.attributes();
if (!attr.hasAttribute("id"))
reader.raiseError("Missing dimension id");
else
config.dimensions.append(KV<QString, QString>
(attr.value("id").toString(), reader.readElementText()));
} else if (reader.name() == "crs") {
2018-04-07 18:42:25 +02:00
config.coordinateSystem = coordinateSystem(reader);
config.crs = reader.readElementText();
} else if (reader.name() == "authorization") {
QXmlStreamAttributes attr = reader.attributes();
config.authorization = Authorization(
attr.value("username").toString(),
attr.value("password").toString());
reader.skipCurrentElement();
2018-08-18 21:06:36 +02:00
} else if (reader.name() == "tilePixelRatio") {
// Legacy tilePixelRatio tag support
#ifdef ENABLE_HIDPI
2018-12-08 02:27:27 +01:00
bool ok;
qreal ratio = reader.readElementText().toDouble(&ok);
if (!ok || ratio <= 0)
2018-08-18 21:06:36 +02:00
reader.raiseError("Invalid tilePixelRatio");
else
2018-12-08 02:27:27 +01:00
config.tileRatio = ratio;
#else // ENABLE_HIDPI
reader.raiseError("HiDPI maps not supported");
#endif // ENABLE_HIDPI
} else if (reader.name() == "tile") {
2018-12-08 02:27:27 +01:00
tile(reader, config);
reader.skipCurrentElement();
} else
reader.skipCurrentElement();
}
}
2018-05-22 22:40:15 +02:00
Map *MapSource::loadMap(const QString &path, QString &errorString)
{
Config config;
2018-05-22 22:40:15 +02:00
QFile file(path);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
2018-05-22 22:40:15 +02:00
errorString = file.errorString();
return 0;
}
2018-05-22 22:40:15 +02:00
QXmlStreamReader reader(&file);
if (reader.readNextStartElement()) {
2018-01-29 00:19:57 +01:00
if (reader.name() == "map")
map(reader, config);
else
2018-01-29 00:19:57 +01:00
reader.raiseError("Not an online map source file");
}
if (reader.error()) {
2018-05-22 22:40:15 +02:00
errorString = QString("%1: %2").arg(reader.lineNumber())
2018-02-20 23:37:19 +01:00
.arg(reader.errorString());
return 0;
}
if (config.name.isEmpty()) {
2018-05-22 22:40:15 +02:00
errorString = "Missing name definition";
return 0;
}
if (config.url.isEmpty()) {
2018-05-22 22:40:15 +02:00
errorString = "Missing URL definition";
return 0;
}
if (config.type == WMTS || config.type == WMS) {
if (config.layer.isEmpty()) {
2018-05-22 22:40:15 +02:00
errorString = "Missing layer definition";
return 0;
}
if (config.format.isEmpty()) {
2018-05-22 22:40:15 +02:00
errorString = "Missing format definition";
return 0;
}
}
if (config.type == WMTS) {
if (config.set.isEmpty()) {
2018-05-22 22:40:15 +02:00
errorString = "Missing set definiton";
return 0;
}
}
if (config.type == WMS) {
if (config.crs.isEmpty()) {
2018-05-22 22:40:15 +02:00
errorString = "Missing CRS definiton";
return 0;
}
}
2018-09-22 13:32:54 +02:00
switch (config.type) {
case WMTS:
return new WMTSMap(config.name, WMTS::Setup(config.url, config.layer,
config.set, config.style, config.format, config.rest,
config.coordinateSystem, config.dimensions, config.authorization),
config.tileRatio);
case WMS:
return new WMSMap(config.name, WMS::Setup(config.url, config.layer,
config.style, config.format, config.crs, config.coordinateSystem,
config.dimensions, config.authorization));
case TMS:
return new OnlineMap(config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization,
2019-05-20 23:23:24 +02:00
config.tileSize, config.scalable, true, false);
2018-09-22 13:32:54 +02:00
case OSM:
return new OnlineMap(config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization,
2019-05-20 23:23:24 +02:00
config.tileSize, config.scalable, false, false);
case QuadTiles:
return new OnlineMap(config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization,
config.tileSize, config.scalable, false, true);
2018-09-22 13:32:54 +02:00
default:
return 0;
}
}