1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-27 21:24:47 +01:00

Switched to XML defined online map sources

This commit is contained in:
Martin Tůma 2018-01-28 22:56:08 +01:00
parent 8a7edcfd8d
commit aa07b20aa4
15 changed files with 323 additions and 113 deletions

View File

@ -40,7 +40,7 @@ build_script:
copy pkg\pcs.csv installer
copy pkg\maps.txt installer
copy pkg\maps.xml installer
copy licence.txt installer

View File

@ -115,7 +115,8 @@ HEADERS += src/config.h \
src/map/angularunits.h \
src/map/primemeridian.h \
src/map/linearunits.h \
src/map/ct.h
src/map/ct.h \
src/map/omd.h
SOURCES += src/main.cpp \
src/common/coordinates.cpp \
src/common/rectc.cpp \
@ -200,7 +201,8 @@ SOURCES += src/main.cpp \
src/map/gcs.cpp \
src/map/angularunits.cpp \
src/map/primemeridian.cpp \
src/map/linearunits.cpp
src/map/linearunits.cpp \
src/map/omd.cpp
RESOURCES += gpxsee.qrc
TRANSLATIONS = lang/gpxsee_cs.ts \
lang/gpxsee_sv.ts \
@ -216,7 +218,7 @@ macx {
icons/fit.icns \
icons/igc.icns \
icons/nmea.icns \
pkg/maps.txt \
pkg/maps.xml \
pkg/ellipsoids.csv \
pkg/gcs.csv \
pkg/pcs.csv

View File

@ -83,7 +83,7 @@ Section "GPXSee" SEC_APP
; Put the files there
File "gpxsee.exe"
File "maps.txt"
File "maps.xml"
File "ellipsoids.csv"
File "gcs.csv"
File "pcs.csv"

View File

@ -90,7 +90,7 @@ Section "GPXSee" SEC_APP
; Put the files there
File "gpxsee.exe"
File "maps.txt"
File "maps.xml"
File "ellipsoids.csv"
File "gcs.csv"
File "pcs.csv"

View File

@ -1,5 +0,0 @@
Open Topo Map https://a.tile.opentopomap.org/$z/$x/$y.png 17
4UMaps http://4umaps.eu/$z/$x/$y.png 15
Open Street Map http://tile.openstreetmap.org/$z/$x/$y.png 19
USGS Topo https://navigator.er.usgs.gov/tiles/tcr.cgi/$z/$x/$y.png 15
USGS Imagery https://navigator.er.usgs.gov/tiles/aerial_Imagery.cgi/$z/$x/$y 15

28
pkg/maps.xml Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<omd>
<map>
<name>Open Topo Map</name>
<url>https://a.tile.opentopomap.org/$z/$x/$y.png</url>
<zoom max="17"/>
</map>
<map>
<name>4UMaps</name>
<url>http://4umaps.eu/$z/$x/$y.png</url>
<zoom min="2" max="15"/>
<bounds bottom="-65"/>
</map>
<map>
<name>Open Street Map</name>
<url>http://tile.openstreetmap.org/$z/$x/$y.png</url>
</map>
<map>
<name>USGS Topo</name>
<url>https://navigator.er.usgs.gov/tiles/tcr.cgi/$z/$x/$y.png</url>
<zoom min="2" max="15"/>
</map>
<map>
<name>USGS Imagery</name>
<url>https://navigator.er.usgs.gov/tiles/aerial_Imagery.cgi/$z/$x/$y</url>
<zoom min="2" max="15"/>
</map>
</omd>

View File

@ -108,13 +108,8 @@ void GUI::loadMaps()
else if (QFile::exists(GLOBAL_MAP_DIR))
offline = GLOBAL_MAP_DIR;
if (!offline.isNull()) {
if (!_ml->loadDir(offline)) {
qWarning("Error reading map dir: %s",
qPrintable(_ml->errorString()));
_ml->clear();
}
}
if (!offline.isNull() && !_ml->loadDir(offline))
qWarning(qPrintable(_ml->errorString()));
_map = new EmptyMap(this);
}

View File

@ -15,7 +15,6 @@
#define ELLIPSOID_FILE QString("ellipsoids.csv")
#define GCS_FILE QString("gcs.csv")
#define PCS_FILE QString("pcs.csv")
#define MAP_FILE QString("maps.txt")
#define MAP_DIR QString("maps")
#define POI_DIR QString("POI")

View File

@ -127,7 +127,7 @@ int MapFile::parse(QIODevice &device, QList<CalibrationPoint> &points,
ln++;
}
return 0;
return (ln == 1) ? 1 : 0;
}
bool MapFile::parseMapFile(QIODevice &device, QList<CalibrationPoint> &points,
@ -136,13 +136,13 @@ bool MapFile::parseMapFile(QIODevice &device, QList<CalibrationPoint> &points,
int el;
if (!device.open(QIODevice::ReadOnly)) {
_errorString = QString("Error opening map file: %1")
_errorString = QString("Error opening file: %1")
.arg(device.errorString());
return false;
}
if ((el = parse(device, points, projection, setup, datum))) {
_errorString = QString("Map file parse error on line %1").arg(el);
_errorString = QString("Parse error on line %1").arg(el);
return false;
}

View File

@ -4,70 +4,30 @@
#include "atlas.h"
#include "offlinemap.h"
#include "onlinemap.h"
#include "omd.h"
#include "maplist.h"
#define ZOOM_MAX 18
#define ZOOM_MIN 2
Map *MapList::loadListEntry(const QByteArray &line)
bool MapList::loadList(const QString &path, bool dir)
{
int max;
OMD omd;
QList<QByteArray> list = line.split('\t');
if (list.size() < 2)
return 0;
QByteArray ba1 = list.at(0).trimmed();
QByteArray ba2 = list.at(1).trimmed();
if (ba1.isEmpty() || ba2.isEmpty())
return 0;
if (list.size() == 3) {
bool ok;
max = QString(list.at(2).trimmed()).toInt(&ok);
if (!ok)
return 0;
} else
max = ZOOM_MAX;
return new OnlineMap(QString::fromUtf8(ba1.data(), ba1.size()),
QString::fromLatin1(ba2.data(), ba2.size()), Range(ZOOM_MIN, max), this);
}
bool MapList::loadList(const QString &path)
{
QFile file(path);
QList<Map*> maps;
if (!file.open(QFile::ReadOnly | QFile::Text)) {
_errorString = file.errorString();
if (!omd.loadFile(path)) {
if (dir)
_errorString += path + ": " + omd.errorString() + "\n";
else
_errorString = omd.errorString();
return false;
}
int ln = 0;
while (!file.atEnd()) {
ln++;
QByteArray line = file.readLine();
Map *map = loadListEntry(line);
if (map)
maps.append(map);
else {
for (int i = 0; i < maps.count(); i++)
delete maps.at(i);
_errorString = QString("Invalid map list entry on line %1.")
.arg(QString::number(ln));
return false;
}
}
_maps += maps;
_maps += omd.maps();
for (int i = 0; i < omd.maps().size(); i++)
omd.maps()[i]->setParent(this);
return true;
}
bool MapList::loadMap(const QString &path)
bool MapList::loadMap(const QString &path, bool dir)
{
OfflineMap *map = new OfflineMap(path, this);
@ -75,13 +35,16 @@ bool MapList::loadMap(const QString &path)
_maps.append(map);
return true;
} else {
_errorString = map->errorString();
if (dir)
_errorString += path + ": " + map->errorString() + "\n";
else
_errorString = map->errorString();
delete map;
return false;
}
}
bool MapList::loadAtlas(const QString &path)
bool MapList::loadAtlas(const QString &path, bool dir)
{
Atlas *atlas = new Atlas(path, this);
@ -89,39 +52,45 @@ bool MapList::loadAtlas(const QString &path)
_maps.append(atlas);
return true;
} else {
_errorString = atlas->errorString();
if (dir)
_errorString += path + ": " + atlas->errorString() + "\n";
else
_errorString = atlas->errorString();
delete atlas;
return false;
}
}
bool MapList::loadFile(const QString &path, bool *atlas)
bool MapList::loadFile(const QString &path, bool *atlas, bool dir)
{
QFileInfo fi(path);
QString suffix = fi.suffix().toLower();
if (Atlas::isAtlas(path)) {
if (atlas)
*atlas = true;
return loadAtlas(path);
} else if (suffix == "txt") {
if (atlas)
*atlas = false;
return loadList(path);
*atlas = true;
return loadAtlas(path, dir);
} else if (suffix == "xml") {
*atlas = false;
return loadList(path, dir);
} else {
if (atlas)
*atlas = false;
return loadMap(path);
*atlas = false;
return loadMap(path, dir);
}
}
bool MapList::loadFile(const QString &path)
{
bool atlas;
return loadFile(path, &atlas, false);
}
bool MapList::loadDir(const QString &path)
{
QDir md(path);
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
md.setSorting(QDir::DirsLast);
QFileInfoList ml = md.entryInfoList();
bool atlas;
bool atlas, ret = true;
for (int i = 0; i < ml.size(); i++) {
const QFileInfo &fi = ml.at(i);
@ -129,19 +98,16 @@ bool MapList::loadDir(const QString &path)
if (fi.isDir() && fi.fileName() != "set") {
if (!loadDir(fi.absoluteFilePath()))
return false;
ret = false;
} else if (filter().contains("*." + suffix)) {
if (!loadFile(fi.absoluteFilePath(), &atlas)) {
_errorString.prepend(QString("%1: ")
.arg(fi.canonicalFilePath()));
return false;
}
if (!loadFile(fi.absoluteFilePath(), &atlas, true))
ret = false;
if (atlas)
break;
}
}
return true;
return ret;
}
void MapList::clear()
@ -153,14 +119,16 @@ void MapList::clear()
QString MapList::formats()
{
return tr("Supported files (*.txt *.map *.tba *.tar *.tif *.tiff)") + ";;"
+ tr("Offline maps (*.map *.tba *.tar *.tif *.tiff)") + ";;"
+ tr("Online map lists (*.txt)");
return tr("Supported files (*.map *.tar *.tba *.tif *.tiff *.xml)") + ";;"
+ tr("OziExplorer maps (*.map)") + ";;"
+ tr("TrekBuddy maps/atlases (*.tar *.tba)") + ";;"
+ tr("GeoTIFF images (*.tif *.tiff)") + ";;"
+ tr("Online map definitions (*.xml)");
}
QStringList MapList::filter()
{
QStringList filter;
filter << "*.map" << "*.tba" << "*.tar" << "*.txt" << "*.tif" << "*.tiff";
filter << "*.map" << "*.tba" << "*.tar" << "*.xml" << "*.tif" << "*.tiff";
return filter;
}

View File

@ -14,7 +14,7 @@ class MapList : public QObject
public:
MapList(QObject *parent = 0) : QObject(parent) {}
bool loadFile(const QString &path, bool *atlas = 0);
bool loadFile(const QString &path);
bool loadDir(const QString &path);
void clear();
@ -25,11 +25,13 @@ public:
static QStringList filter();
private:
bool loadFile(const QString &path, bool *atlas, bool dir);
Map *loadListEntry(const QByteArray &line);
bool loadList(const QString &path);
bool loadMap(const QString &path);
bool loadAtlas(const QString &path);
bool loadList(const QString &path, bool dir);
bool loadMap(const QString &path, bool dir);
bool loadAtlas(const QString &path, bool dir);
QList<Map*> _maps;
QString _errorString;

190
src/map/omd.cpp Normal file
View File

@ -0,0 +1,190 @@
#include <QFile>
#include <QXmlStreamReader>
#include "onlinemap.h"
#include "omd.h"
#define ZOOM_MAX 19
#define ZOOM_MIN 0
#define BOUNDS_LEFT -180
#define BOUNDS_TOP 85.0511
#define BOUNDS_RIGHT 180
#define BOUNDS_BOTTOM -85.0511
Range OMD::zooms(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
int min, max;
bool res;
if (attr.hasAttribute("min")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
min = attr.value("min").toString().toInt(&res);
#else // QT_VERSION < 5
min = attr.value("min").toInt(&res);
#endif // QT_VERSION < 5
if (!res || (min < ZOOM_MIN || min > ZOOM_MAX)) {
reader.raiseError("Invalid minimal zoom level");
return Range();
}
} else
min = ZOOM_MIN;
if (attr.hasAttribute("max")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
max = attr.value("max").toString().toInt(&res);
#else // QT_VERSION < 5
max = attr.value("max").toInt(&res);
#endif // QT_VERSION < 5
if (!res || (max < ZOOM_MIN || max > ZOOM_MAX)) {
reader.raiseError("Invalid maximal zoom level");
return Range();
}
} else
max = ZOOM_MAX;
if (min > max || max < min) {
reader.raiseError("Invalid maximal/minimal zoom level combination");
return Range();
}
return Range(min, max);
}
RectC OMD::bounds(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
double top, left, bottom, right;
bool res;
if (attr.hasAttribute("top")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
top = attr.value("top").toString().toDouble(&res);
#else // QT_VERSION < 5
top = attr.value("top").toDouble(&res);
#endif // QT_VERSION < 5
if (!res || (top < BOUNDS_BOTTOM || top > BOUNDS_TOP)) {
reader.raiseError("Invalid bounds top value");
return RectC();
}
} else
top = BOUNDS_TOP;
if (attr.hasAttribute("bottom")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
bottom = attr.value("bottom").toString().toDouble(&res);
#else // QT_VERSION < 5
bottom = attr.value("bottom").toDouble(&res);
#endif // QT_VERSION < 5
if (!res || (bottom < BOUNDS_BOTTOM || bottom > BOUNDS_TOP)) {
reader.raiseError("Invalid bounds bottom value");
return RectC();
}
} else
bottom = BOUNDS_BOTTOM;
if (attr.hasAttribute("left")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
left = attr.value("left").toString().toDouble(&res);
#else // QT_VERSION < 5
left = attr.value("left").toDouble(&res);
#endif // QT_VERSION < 5
if (!res || (left < BOUNDS_LEFT || left > BOUNDS_RIGHT)) {
reader.raiseError("Invalid bounds left value");
return RectC();
}
} else
left = BOUNDS_LEFT;
if (attr.hasAttribute("right")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
right = attr.value("right").toString().toDouble(&res);
#else // QT_VERSION < 5
right = attr.value("right").toDouble(&res);
#endif // QT_VERSION < 5
if (!res || (right < BOUNDS_LEFT || right > BOUNDS_RIGHT)) {
reader.raiseError("Invalid bounds right value");
return RectC();
}
} else
right = BOUNDS_RIGHT;
if (bottom > top || top < bottom) {
reader.raiseError("Invalid bottom/top bounds combination");
return RectC();
}
if (left > right || right < left) {
reader.raiseError("Invalid left/right bounds combination");
return RectC();
}
return RectC(Coordinates(left, top), Coordinates(right, bottom));
}
void OMD::map(QXmlStreamReader &reader)
{
QString name, url;
Range z(ZOOM_MIN, ZOOM_MAX);
RectC b(Coordinates(BOUNDS_LEFT, BOUNDS_TOP),
Coordinates(BOUNDS_RIGHT, BOUNDS_BOTTOM));
while (reader.readNextStartElement()) {
if (reader.name() == "name")
name = reader.readElementText();
else if (reader.name() == "url")
url = reader.readElementText();
else if (reader.name() == "zoom") {
z = zooms(reader);
reader.skipCurrentElement();
} else if (reader.name() == "bounds") {
b = bounds(reader);
reader.skipCurrentElement();
} else
reader.skipCurrentElement();
}
_maps.append(new OnlineMap(name, url, z, b));
}
void OMD::omd(QXmlStreamReader &reader)
{
while (reader.readNextStartElement()) {
if (reader.name() == "map")
map(reader);
else
reader.skipCurrentElement();
}
}
bool OMD::loadFile(const QString &path)
{
QFile file(path);
QXmlStreamReader reader;
if (!file.open(QFile::ReadOnly | QFile::Text)) {
_errorString = file.errorString();
return false;
}
reader.setDevice(&file);
if (reader.readNextStartElement()) {
if (reader.name() == "omd")
omd(reader);
else
reader.raiseError("Not an online map definitions file");
}
if (reader.error())
_errorString = QString("%1: %2").arg(reader.lineNumber())
.arg(reader.errorString());
return !reader.error();
}
OMD::~OMD()
{
for (int i = 0; i < _maps.size(); i++)
if (!_maps.at(i)->parent())
delete _maps.at(i);
}

31
src/map/omd.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef OMD_H
#define OMD_H
#include <QList>
#include "common/range.h"
#include "common/rectc.h"
class Map;
class QXmlStreamReader;
class OMD
{
public:
~OMD();
bool loadFile(const QString &path);
const QString &errorString() const {return _errorString;}
const QList<Map*> &maps() const {return _maps;}
private:
RectC bounds(QXmlStreamReader &reader);
Range zooms(QXmlStreamReader &reader);
void map(QXmlStreamReader &reader);
void omd(QXmlStreamReader &reader);
QString _errorString;
QList<Map*> _maps;
};
#endif // OMD_H

View File

@ -46,13 +46,11 @@ static bool loadTileFile(Tile &tile, const QString &file)
Downloader *OnlineMap::downloader;
OnlineMap::OnlineMap(const QString &name, const QString &url,
const Range &zooms, QObject *parent) : Map(parent)
const Range &zooms, const RectC &bounds, QObject *parent)
: Map(parent), _name(name), _url(url), _zooms(zooms), _bounds(bounds)
{
_name = name;
_url = url;
_block = false;
_zooms = zooms;
_zoom = zooms.max();
_zoom = _zooms.max();
QString path = TILES_DIR + QString("/") + name;
if (!QDir().mkpath(path))
@ -167,7 +165,7 @@ void OnlineMap::clearCache()
QRectF OnlineMap::bounds() const
{
return QRectF(ll2xy(Coordinates(-180, 85)), ll2xy(Coordinates(180, -85)));
return QRectF(ll2xy(_bounds.topLeft()), ll2xy(_bounds.bottomRight()));
}
int OnlineMap::limitZoom(int zoom) const

View File

@ -3,6 +3,7 @@
#include "common/coordinates.h"
#include "common/range.h"
#include "common/rectc.h"
#include "map.h"
#include "tile.h"
@ -14,7 +15,7 @@ class OnlineMap : public Map
public:
OnlineMap(const QString &name, const QString &url, const Range &zooms,
QObject *parent = 0);
const RectC &bounds, QObject *parent = 0);
const QString &name() const {return _name;}
@ -57,10 +58,11 @@ private:
void loadTilesSync(QList<Tile> &list);
int limitZoom(int zoom) const;
Range _zooms;
int _zoom;
QString _name;
QString _url;
Range _zooms;
RectC _bounds;
int _zoom;
bool _block;
static Downloader *downloader;