1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-24 03:35:53 +01:00

Support all variants of TrekBuddy maps/atlases

Added support for gmi calibration files and arbitrary named tba/map/gmi files.
This commit is contained in:
Martin Tůma 2023-09-13 20:02:24 +02:00
parent b38cf31920
commit 722f3acb1e
7 changed files with 313 additions and 71 deletions

View File

@ -134,6 +134,7 @@ HEADERS += src/common/config.h \
src/map/encmap.h \ src/map/encmap.h \
src/map/ENC/iso8211.h \ src/map/ENC/iso8211.h \
src/map/gemfmap.h \ src/map/gemfmap.h \
src/map/gmifile.h \
src/map/oruxmap.h \ src/map/oruxmap.h \
src/map/osmdroidmap.h \ src/map/osmdroidmap.h \
src/map/proj/polyconic.h \ src/map/proj/polyconic.h \
@ -347,6 +348,7 @@ SOURCES += src/main.cpp \
src/map/encmap.cpp \ src/map/encmap.cpp \
src/map/ENC/iso8211.cpp \ src/map/ENC/iso8211.cpp \
src/map/gemfmap.cpp \ src/map/gemfmap.cpp \
src/map/gmifile.cpp \
src/map/oruxmap.cpp \ src/map/oruxmap.cpp \
src/map/osmdroidmap.cpp \ src/map/osmdroidmap.cpp \
src/map/proj/polyconic.cpp \ src/map/proj/polyconic.cpp \

View File

@ -27,6 +27,34 @@ static bool yCmp(OziMap *m1, OziMap *m2)
return TL(m1).y() > TL(m2).y(); return TL(m1).y() > TL(m2).y();
} }
static QString calibrationFile(const QString &path)
{
QDir dir(path);
QFileInfoList files = dir.entryInfoList(QDir::Files);
for (int i = 0; i < files.size(); i++) {
const QFileInfo &fi = files.at(i);
QString suffix(fi.suffix().toLower());
if (suffix == "map" || suffix == "gmi")
return fi.absoluteFilePath();
}
return QString();
}
static QString tbaFile(const QStringList &files)
{
for (int i = 0; i < files.size(); i++) {
QFileInfo fi(files.at(i));
if (fi.path() == "." && fi.suffix().toLower() == "tba")
return files.at(i);
}
return QString();
}
void Atlas::computeZooms() void Atlas::computeZooms()
{ {
std::sort(_maps.begin(), _maps.end(), resCmp); std::sort(_maps.begin(), _maps.end(), resCmp);
@ -86,7 +114,11 @@ Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent)
_errorString = "Error reading tar file"; _errorString = "Error reading tar file";
return; return;
} }
QString tbaFileName = fi.completeBaseName() + ".tba"; QString tbaFileName(tbaFile(tar.files()));
if (tbaFileName.isNull()) {
_errorString = "No tba file found";
return;
}
ba = tar.file(tbaFileName); ba = tar.file(tbaFileName);
} else { } else {
QFile tbaFile(fileName); QFile tbaFile(fileName);
@ -97,7 +129,7 @@ Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent)
ba = tbaFile.readAll(); ba = tbaFile.readAll();
} }
if (!ba.startsWith("Atlas 1.0")) { if (!ba.startsWith("Atlas 1.0")) {
_errorString = "Missing or invalid tba file"; _errorString = "Invalid tba file";
return; return;
} }
@ -108,20 +140,23 @@ Atlas::Atlas(const QString &fileName, bool TAR, QObject *parent)
QFileInfoList maps = zdir.entryInfoList(QDir::Dirs QFileInfoList maps = zdir.entryInfoList(QDir::Dirs
| QDir::NoDotAndDotDot); | QDir::NoDotAndDotDot);
for (int i = 0; i < maps.count(); i++) { for (int i = 0; i < maps.count(); i++) {
QString mapFile = maps.at(i).absoluteFilePath() + "/"
+ maps.at(i).fileName() + ".map";
OziMap *map; OziMap *map;
if (tar.isOpen()) if (TAR)
map = new OziMap(mapFile, tar, this); map = new OziMap(maps.at(i).absoluteFilePath(), tar, this);
else else {
map = new OziMap(mapFile, TAR, this); QString cf(calibrationFile(maps.at(i).absoluteFilePath()));
if (cf.isNull()) {
_errorString = "No calibration file found";
return;
}
map = new OziMap(cf, this);
}
if (map->isValid()) if (map->isValid())
_maps.append(map); _maps.append(map);
else { else {
_errorString = QString("Error loading map: %1: %2") _errorString = QString("%1: %2")
.arg(mapFile, map->errorString()); .arg(map->path(), map->errorString());
return; return;
} }
} }

97
src/map/gmifile.cpp Normal file
View File

@ -0,0 +1,97 @@
#include "common/csv.h"
#include "pcs.h"
#include "gmifile.h"
static CalibrationPoint calibrationPoint(const QByteArray line)
{
bool xOk, yOk, lonOk, latOk;
QList<QByteArray> list = line.split(';');
if (list.size() != 4)
return CalibrationPoint();
int x = list.at(0).toInt(&xOk);
int y = list.at(1).toInt(&yOk);
double lon = list.at(2).toDouble(&lonOk);
double lat = list.at(3).toDouble(&latOk);
return (xOk && yOk && latOk && lonOk)
? CalibrationPoint(PointD(x, y), Coordinates(lon, lat))
: CalibrationPoint();
}
bool GmiFile::parse(QIODevice &device, QList<CalibrationPoint> &points)
{
int ln = 1;
int width, height;
bool ok;
if (!device.open(QIODevice::ReadOnly)) {
_errorString = device.errorString();
return false;
}
while (!device.atEnd()) {
QByteArray line = device.readLine(4096);
if (ln == 1) {
if (!line.startsWith("Map Calibration data file")) {
_errorString = "Not a GMI file";
return false;
}
} else if (ln == 2)
_image = line.trimmed();
else if (ln == 3) {
width = line.toInt(&ok);
if (!ok || ok <= 0) {
_errorString = "Invalid image width";
return false;
}
} else if (ln == 4) {
height = line.toInt(&ok);
if (!ok || ok <= 0) {
_errorString = "Invalid image height";
return false;
}
_size = QSize(width, height);
} else {
CalibrationPoint cp(calibrationPoint(line));
if (cp.isValid())
points.append(cp);
else
break;
}
ln++;
}
device.close();
return (points.size() >= 2);
}
bool GmiFile::computeTransformation(const QList<CalibrationPoint> &points)
{
QList<ReferencePoint> rp;
Projection proj(GCS::WGS84());
for (int i = 0; i < points.size(); i++)
rp.append(points.at(i).rp(proj));
_transform = Transform(rp);
if (!_transform.isValid()) {
_errorString = _transform.errorString();
return false;
}
return true;
}
GmiFile::GmiFile(QIODevice &file)
{
QList<CalibrationPoint> points;
if (!parse(file, points))
return;
if (!computeTransformation(points))
return;
}

33
src/map/gmifile.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef GMIFILE_H
#define GMIFILE_H
#include "transform.h"
#include "calibrationpoint.h"
class QIODevice;
class GCS;
class GmiFile
{
public:
GmiFile(QIODevice &file);
bool isValid() const {return !_image.isNull() && _transform.isValid();}
const QString &errorString() const {return _errorString;}
const Transform &transform() const {return _transform;}
const QString &image() const {return _image;}
const QSize &size() const {return _size;}
private:
bool parse(QIODevice &device, QList<CalibrationPoint> &points);
bool computeTransformation(const QList<CalibrationPoint> &points);
QString _image;
QSize _size;
Transform _transform;
QString _errorString;
};
#endif // GMIFILE_H

View File

@ -43,6 +43,7 @@ MapList::ParserMap MapList::parsers()
map.insert("rtmap", &RMap::create); map.insert("rtmap", &RMap::create);
map.insert("map", &MapsforgeMap::create); map.insert("map", &MapsforgeMap::create);
map.insert("map", &OziMap::createMAP); map.insert("map", &OziMap::createMAP);
map.insert("gmi", &OziMap::createMAP);
map.insert("kap", &BSBMap::create); map.insert("kap", &BSBMap::create);
map.insert("kmz", &KMZMap::create); map.insert("kmz", &KMZMap::create);
map.insert("aqm", &AQMMap::create); map.insert("aqm", &AQMMap::create);
@ -173,7 +174,8 @@ QString MapList::formats()
+ qApp->translate("MapList", "Osmdroid SQLite maps") + " (*.sqlite);;" + qApp->translate("MapList", "Osmdroid SQLite maps") + " (*.sqlite);;"
+ qApp->translate("MapList", "Locus/OsmAnd/RMaps SQLite maps") + qApp->translate("MapList", "Locus/OsmAnd/RMaps SQLite maps")
+ " (*.sqlitedb);;" + " (*.sqlitedb);;"
+ qApp->translate("MapList", "TrekBuddy maps/atlases") + " (*.tar *.tba);;" + qApp->translate("MapList", "TrekBuddy maps/atlases")
+ " (*.tar *.tba *.gmi *.map);;"
+ qApp->translate("MapList", "GeoTIFF images") + " (*.tif *.tiff);;" + qApp->translate("MapList", "GeoTIFF images") + " (*.tif *.tiff);;"
+ qApp->translate("MapList", "World-file georeferenced images") + qApp->translate("MapList", "World-file georeferenced images")
+ " (*.wld *.jgw *.gfw *.pgw *.tfw);;" + " (*.wld *.jgw *.gfw *.pgw *.tfw);;"

View File

@ -12,42 +12,68 @@
#include "ozf.h" #include "ozf.h"
#include "image.h" #include "image.h"
#include "mapfile.h" #include "mapfile.h"
#include "gmifile.h"
#include "rectd.h" #include "rectd.h"
#include "ozimap.h" #include "ozimap.h"
static QString mapFile(const QStringList &files) QString OziMap::calibrationFile(const QStringList &files, const QString path,
CalibrationType &type)
{ {
for (int i = 0; i < files.size(); i++) { for (int i = 0; i < files.size(); i++) {
QFileInfo fi(files.at(i)); QFileInfo fi(files.at(i));
if (fi.path() == "." && fi.suffix() == "map") QString suffix(fi.suffix().toLower());
if (path.endsWith(fi.path())) {
if (suffix == "map") {
type = MAP;
return files.at(i);
} else if (suffix == "gmi") {
type = GMI;
return files.at(i); return files.at(i);
} }
}
}
type = Unknown;
return QString(); return QString();
} }
OziMap::OziMap(const QString &fileName, bool TAR, QObject *parent) OziMap::OziMap(const QString &fileName, QObject *parent)
: Map(fileName, parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0), : Map(fileName, parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0),
_valid(false) _hasProj(true), _valid(false)
{ {
QFileInfo fi(fileName); QFileInfo fi(fileName);
QString suffix(fi.suffix().toLower());
if (suffix == "tar") {
CalibrationType type;
if (TAR) {
_tar = new Tar(fileName); _tar = new Tar(fileName);
if (!_tar->open()) { if (!_tar->open()) {
_errorString = "Error reading tar file"; _errorString = "Error reading tar file";
return; return;
} }
QStringList files(_tar->files()); QStringList files(_tar->files());
QString mapFileName(mapFile(files)); QString cf(calibrationFile(files, ".", type));
if (mapFileName.isNull()) {
_errorString = "No map file found in tar file";
return;
}
QByteArray ba(_tar->file(mapFileName)); if (type == GMI) {
QByteArray ba(_tar->file(cf));
QBuffer buffer(&ba);
GmiFile gmi(buffer);
if (!gmi.isValid()) {
_errorString = gmi.errorString();
return;
} else {
_name = Util::file2name(fileName);
_map.size = gmi.size();
_map.path = gmi.image();
_transform = gmi.transform();
_projection = Projection(GCS::WGS84());
_hasProj = false;
}
} else if (type == MAP) {
QByteArray ba(_tar->file(cf));
QBuffer buffer(&ba); QBuffer buffer(&ba);
MapFile mf(buffer); MapFile mf(buffer);
if (!mf.isValid()) { if (!mf.isValid()) {
@ -60,6 +86,10 @@ OziMap::OziMap(const QString &fileName, bool TAR, QObject *parent)
_projection = mf.projection(); _projection = mf.projection();
_transform = mf.transform(); _transform = mf.transform();
} }
} else {
_errorString = "No calibration file found";
return;
}
if (!setTileInfo(files)) if (!setTileInfo(files))
return; return;
@ -67,6 +97,8 @@ OziMap::OziMap(const QString &fileName, bool TAR, QObject *parent)
_tar->close(); _tar->close();
} else { } else {
QFile file(fileName); QFile file(fileName);
if (suffix == "map") {
MapFile mf(file); MapFile mf(file);
if (!mf.isValid()) { if (!mf.isValid()) {
_errorString = mf.errorString(); _errorString = mf.errorString();
@ -78,6 +110,23 @@ OziMap::OziMap(const QString &fileName, bool TAR, QObject *parent)
_projection = mf.projection(); _projection = mf.projection();
_transform = mf.transform(); _transform = mf.transform();
} }
} else if (suffix == "gmi") {
GmiFile gmi(file);
if (!gmi.isValid()) {
_errorString = gmi.errorString();
return;
} else {
_name = Util::file2name(fileName);
_map.size = gmi.size();
_map.path = gmi.image();
_transform = gmi.transform();
_projection = Projection(GCS::WGS84());
_hasProj = false;
}
} else {
_errorString = "Unknown file type";
return;
}
QDir set(fi.absolutePath() + "/" + "set"); QDir set(fi.absolutePath() + "/" + "set");
if (set.exists()) { if (set.exists()) {
@ -92,21 +141,15 @@ OziMap::OziMap(const QString &fileName, bool TAR, QObject *parent)
_valid = true; _valid = true;
} }
OziMap::OziMap(const QString &fileName, Tar &tar, QObject *parent) OziMap::OziMap(const QString &dirName, Tar &tar, QObject *parent)
: Map(fileName, parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0), : Map(dirName, parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0),
_valid(false) _hasProj(true), _valid(false)
{ {
QFileInfo fi(fileName); CalibrationType type;
QFileInfo map(fi.absolutePath()); QString cf(calibrationFile(tar.files(), dirName, type));
QFileInfo layer(map.absolutePath());
QString mapFile = layer.fileName() + "/" + map.fileName() + "/"
+ fi.fileName();
QByteArray ba = tar.file(mapFile); if (type == MAP) {
if (ba.isNull()) { QByteArray ba = tar.file(cf);
_errorString = "Map file not found";
return;
}
QBuffer buffer(&ba); QBuffer buffer(&ba);
MapFile mf(buffer); MapFile mf(buffer);
if (!mf.isValid()) { if (!mf.isValid()) {
@ -118,7 +161,28 @@ OziMap::OziMap(const QString &fileName, Tar &tar, QObject *parent)
_map.size = mf.size(); _map.size = mf.size();
_projection = mf.projection(); _projection = mf.projection();
_transform = mf.transform(); _transform = mf.transform();
_tar = new Tar(fi.absolutePath() + "/" + fi.completeBaseName() + ".tar"); } else if (type == GMI) {
QByteArray ba = tar.file(cf);
QBuffer buffer(&ba);
GmiFile gmi(buffer);
if (!gmi.isValid()) {
_errorString = gmi.errorString();
return;
}
_name = Util::file2name(cf);
_map.size = gmi.size();
_transform = gmi.transform();
_projection = Projection(GCS::WGS84());
_hasProj = false;
} else {
_errorString = "No calibration file found";
return;
}
QFileInfo fi(cf);
QDir dir(dirName);
_tar = new Tar(dir.absoluteFilePath(fi.completeBaseName() + ".tar"));
if (!_tar->open()) { if (!_tar->open()) {
_errorString = _tar->fileName() + ": error reading tar file"; _errorString = _tar->fileName() + ": error reading tar file";
@ -221,10 +285,11 @@ bool OziMap::setTileInfo(const QStringList &tiles, const QString &path)
void OziMap::load(const Projection &in, const Projection &out, void OziMap::load(const Projection &in, const Projection &out,
qreal deviceRatio, bool hidpi) qreal deviceRatio, bool hidpi)
{ {
Q_UNUSED(in);
Q_UNUSED(out); Q_UNUSED(out);
_mapRatio = hidpi ? deviceRatio : 1.0; _mapRatio = hidpi ? deviceRatio : 1.0;
if (!_hasProj)
_projection = in;
if (_tar) { if (_tar) {
Q_ASSERT(!_tar->isOpen()); Q_ASSERT(!_tar->isOpen());
@ -413,7 +478,7 @@ Map *OziMap::createTAR(const QString &path, bool *isDir)
if (isDir) if (isDir)
*isDir = false; *isDir = false;
return new OziMap(path, true); return new OziMap(path);
} }
Map *OziMap::createMAP(const QString &path, bool *isDir) Map *OziMap::createMAP(const QString &path, bool *isDir)
@ -421,5 +486,5 @@ Map *OziMap::createMAP(const QString &path, bool *isDir)
if (isDir) if (isDir)
*isDir = false; *isDir = false;
return new OziMap(path, false); return new OziMap(path);
} }

View File

@ -14,8 +14,8 @@ class OziMap : public Map
Q_OBJECT Q_OBJECT
public: public:
OziMap(const QString &fileName, bool TAR, QObject *parent = 0); OziMap(const QString &fileName, QObject *parent = 0);
OziMap(const QString &fileName, Tar &tar, QObject *parent = 0); OziMap(const QString &dirName, Tar &tar, QObject *parent = 0);
~OziMap(); ~OziMap();
QString name() const {return _name;} QString name() const {return _name;}
@ -51,6 +51,10 @@ public:
static Map *createMAP(const QString &path, bool *isDir); static Map *createMAP(const QString &path, bool *isDir);
private: private:
enum CalibrationType {
Unknown, MAP, GMI
};
struct ImageInfo { struct ImageInfo {
QSize size; QSize size;
QString path; QString path;
@ -67,6 +71,9 @@ private:
void rescale(int zoom); void rescale(int zoom);
static QString calibrationFile(const QStringList &files, const QString path,
CalibrationType &type);
QString _name; QString _name;
Projection _projection; Projection _projection;
Transform _transform; Transform _transform;
@ -77,6 +84,7 @@ private:
int _zoom; int _zoom;
QPointF _scale; QPointF _scale;
qreal _mapRatio; qreal _mapRatio;
bool _hasProj;
bool _valid; bool _valid;
QString _errorString; QString _errorString;