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\pcs.csv installer
copy pkg\maps.txt installer copy pkg\maps.xml installer
copy licence.txt installer copy licence.txt installer

View File

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

View File

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

View File

@ -90,7 +90,7 @@ Section "GPXSee" SEC_APP
; Put the files there ; Put the files there
File "gpxsee.exe" File "gpxsee.exe"
File "maps.txt" File "maps.xml"
File "ellipsoids.csv" File "ellipsoids.csv"
File "gcs.csv" File "gcs.csv"
File "pcs.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)) else if (QFile::exists(GLOBAL_MAP_DIR))
offline = GLOBAL_MAP_DIR; offline = GLOBAL_MAP_DIR;
if (!offline.isNull()) { if (!offline.isNull() && !_ml->loadDir(offline))
if (!_ml->loadDir(offline)) { qWarning(qPrintable(_ml->errorString()));
qWarning("Error reading map dir: %s",
qPrintable(_ml->errorString()));
_ml->clear();
}
}
_map = new EmptyMap(this); _map = new EmptyMap(this);
} }

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@ class MapList : public QObject
public: public:
MapList(QObject *parent = 0) : QObject(parent) {} MapList(QObject *parent = 0) : QObject(parent) {}
bool loadFile(const QString &path, bool *atlas = 0); bool loadFile(const QString &path);
bool loadDir(const QString &path); bool loadDir(const QString &path);
void clear(); void clear();
@ -25,11 +25,13 @@ public:
static QStringList filter(); static QStringList filter();
private: private:
bool loadFile(const QString &path, bool *atlas, bool dir);
Map *loadListEntry(const QByteArray &line); Map *loadListEntry(const QByteArray &line);
bool loadList(const QString &path); bool loadList(const QString &path, bool dir);
bool loadMap(const QString &path); bool loadMap(const QString &path, bool dir);
bool loadAtlas(const QString &path); bool loadAtlas(const QString &path, bool dir);
QList<Map*> _maps; QList<Map*> _maps;
QString _errorString; 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; Downloader *OnlineMap::downloader;
OnlineMap::OnlineMap(const QString &name, const QString &url, 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; _block = false;
_zooms = zooms; _zoom = _zooms.max();
_zoom = zooms.max();
QString path = TILES_DIR + QString("/") + name; QString path = TILES_DIR + QString("/") + name;
if (!QDir().mkpath(path)) if (!QDir().mkpath(path))
@ -167,7 +165,7 @@ void OnlineMap::clearCache()
QRectF OnlineMap::bounds() const 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 int OnlineMap::limitZoom(int zoom) const

View File

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