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

Added support for non-SQL Orux maps

+ error handling fixes/improvements
This commit is contained in:
Martin Tůma 2022-08-11 23:39:36 +02:00
parent 9a4514a464
commit 22e5ffaa0c
2 changed files with 135 additions and 68 deletions

View File

@ -234,6 +234,10 @@ void OruxMap::calibrationPoints(QXmlStreamReader &reader, const QSize &size,
return;
CalibrationPoint p(corner2point(corner, size), Coordinates(lon, lat));
if (!p.isValid()) {
reader.raiseError(QString("invalid calibration point"));
return;
}
points.append(p);
reader.readElementText();
@ -242,13 +246,15 @@ void OruxMap::calibrationPoints(QXmlStreamReader &reader, const QSize &size,
}
}
void OruxMap::mapCalibration(QXmlStreamReader &reader, int level)
void OruxMap::mapCalibration(QXmlStreamReader &reader, const QString &dir,
int level)
{
int zoom;
QSize tileSize, size, calibrationSize;
QString datum, projection;
QString datum, projection, fileName;
QList<CalibrationPoint> points;
Projection proj;
Transform t;
QXmlStreamAttributes attr = reader.attributes();
if (!intAttr(reader, attr, "layerLevel", zoom))
@ -256,10 +262,10 @@ void OruxMap::mapCalibration(QXmlStreamReader &reader, int level)
while (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("OruxTracker"))
oruxTracker(reader, level + 1);
oruxTracker(reader, dir, level + 1);
else if (reader.name() == QLatin1String("MapName")) {
QString name(reader.readElementText());
if (!level)
if (!level && dir.isEmpty())
_name = name;
} else if (reader.name() == QLatin1String("MapChunks")) {
int xMax, yMax, width, height;
@ -277,6 +283,8 @@ void OruxMap::mapCalibration(QXmlStreamReader &reader, int level)
return;
if (!strAttr(reader, attr, "projection", projection))
return;
if (!strAttr(reader, attr, "file_name", fileName))
return;
tileSize = QSize(width, height);
size = QSize(xMax * width, yMax * height);
@ -309,29 +317,50 @@ void OruxMap::mapCalibration(QXmlStreamReader &reader, int level)
calibrationSize = QSize(width, height);
reader.readElementText();
} else if (reader.name() == QLatin1String("CalibrationPoints"))
} else if (reader.name() == QLatin1String("CalibrationPoints")) {
calibrationPoints(reader, calibrationSize, points);
else
t = computeTransformation(proj, points);
if (!t.isValid()) {
reader.raiseError(t.errorString());
return;
}
} else
reader.skipCurrentElement();
}
if (tileSize.isValid()) {
Transform t(computeTransformation(proj, points));
_zooms.append(Zoom(zoom, tileSize, size, proj, t));
if (!t.isValid()) {
reader.raiseError("Invalid map calibration");
return;
}
QDir mapDir(QFileInfo(path()).absoluteDir());
QDir subDir = dir.isEmpty()
? mapDir : QDir(mapDir.absoluteFilePath(dir));
QString set(subDir.absoluteFilePath("set"));
_zooms.append(Zoom(zoom, tileSize, size, proj, t, fileName, set));
}
}
void OruxMap::oruxTracker(QXmlStreamReader &reader, int level)
void OruxMap::oruxTracker(QXmlStreamReader &reader, const QString &dir,
int level)
{
if (level > 1 || (level && !dir.isEmpty())) {
reader.raiseError("invalid map nesting");
return;
}
while (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("MapCalibration"))
mapCalibration(reader, level);
mapCalibration(reader, dir, level);
else
reader.skipCurrentElement();
}
}
bool OruxMap::readXML(const QString &path)
bool OruxMap::readXML(const QString &path, const QString &dir)
{
QFile file(path);
@ -341,7 +370,7 @@ bool OruxMap::readXML(const QString &path)
QXmlStreamReader reader(&file);
if (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("OruxTracker"))
oruxTracker(reader, 0);
oruxTracker(reader, dir, 0);
else
reader.raiseError("Not a Orux map calibration file");
}
@ -354,51 +383,67 @@ bool OruxMap::readXML(const QString &path)
return true;
}
OruxMap::OruxMap(const QString &fileName, QObject *parent)
: Map(fileName, parent), _zoom(0), _mapRatio(1.0), _valid(false)
{
QFileInfo fi(fileName);
QDir dir(fi.absoluteDir());
if (!readXML(fileName))
return;
if (_zooms.isEmpty()) {
_errorString = "No usable zoom level found";
return;
QStringList list(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot));
for (int i = 0; i < list.size(); i++) {
QDir subDir(dir.absoluteFilePath(list.at(i)));
if (!readXML(subDir.absoluteFilePath(list.at(i) + ".otrk2.xml"),
list.at(i))) {
_errorString = list.at(i) + ": " + _errorString;
return;
}
}
if (_zooms.isEmpty()) {
_errorString = "No usable zoom level found";
return;
}
}
std::sort(_zooms.begin(), _zooms.end());
QFileInfo fi(fileName);
QDir dir(fi.absoluteDir());
QString dbFile(dir.absoluteFilePath("OruxMapsImages.db"));
if (!QFileInfo::exists(dbFile)) {
_errorString = "Image DB file not found";
return;
if (dir.exists("OruxMapsImages.db")) {
QString dbFile(dir.absoluteFilePath("OruxMapsImages.db"));
_db = QSqlDatabase::addDatabase("QSQLITE", dbFile);
_db.setDatabaseName(dbFile);
_db.setConnectOptions("QSQLITE_OPEN_READONLY");
if (!_db.open()) {
_errorString = "Error opening database file";
return;
}
QSqlRecord r = _db.record("tiles");
if (r.isEmpty()
|| r.field(0).name() != "x"
|| META_TYPE(r.field(0).type()) != QMetaType::Int
|| r.field(1).name() != "y"
|| META_TYPE(r.field(1).type()) != QMetaType::Int
|| r.field(2).name() != "z"
|| META_TYPE(r.field(2).type()) != QMetaType::Int
|| r.field(3).name() != "image"
|| META_TYPE(r.field(3).type()) != QMetaType::QByteArray) {
_errorString = "Invalid table format";
return;
}
_db.close();
} else {
for (int i = 0; i < _zooms.size(); i++) {
if (!_zooms.at(i).set.exists()) {
_errorString = "missing set directory (level "
+ QString::number(_zooms.at(i).zoom) + ")";
return;
}
}
}
_db = QSqlDatabase::addDatabase("QSQLITE", dbFile);
_db.setDatabaseName(dbFile);
_db.setConnectOptions("QSQLITE_OPEN_READONLY");
if (!_db.open()) {
_errorString = "Error opening database file";
return;
}
QSqlRecord r = _db.record("tiles");
if (r.isEmpty()
|| r.field(0).name() != "x"
|| META_TYPE(r.field(0).type()) != QMetaType::Int
|| r.field(1).name() != "y"
|| META_TYPE(r.field(1).type()) != QMetaType::Int
|| r.field(2).name() != "z"
|| META_TYPE(r.field(2).type()) != QMetaType::Int
|| r.field(3).name() != "image"
|| META_TYPE(r.field(3).type()) != QMetaType::QByteArray) {
_errorString = "Invalid table format";
return;
}
_db.close();
_valid = true;
}
@ -436,12 +481,14 @@ int OruxMap::zoomOut()
void OruxMap::load()
{
_db.open();
if (_db.isValid())
_db.open();
}
void OruxMap::unload()
{
_db.close();
if (_db.isValid())
_db.close();
}
void OruxMap::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
@ -450,19 +497,37 @@ void OruxMap::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
_mapRatio = mapRatio;
}
QPixmap OruxMap::tile(int zoom, int x, int y) const
QPixmap OruxMap::tile(const Zoom &z, int x, int y) const
{
QSqlQuery query(_db);
query.prepare("SELECT image FROM tiles WHERE z=:z AND x=:x AND y=:y");
query.bindValue(":z", zoom);
query.bindValue(":x", x);
query.bindValue(":y", y);
query.exec();
if (!query.first())
return QPixmap();
if (_db.isValid()) {
QSqlQuery query(_db);
query.prepare("SELECT image FROM tiles WHERE z=:z AND x=:x AND y=:y");
query.bindValue(":z", z.zoom);
query.bindValue(":x", x);
query.bindValue(":y", y);
query.exec();
QImage img(QImage::fromData(query.value(0).toByteArray()));
return QPixmap::fromImage(img);
if (!query.first()) {
qWarning("%s: SQL %d-%d-%d: not found", qPrintable(name()), z.zoom,
x, y);
return QPixmap();
} else {
QImage img(QImage::fromData(query.value(0).toByteArray()));
return QPixmap::fromImage(img);
}
} else {
QString fileName(z.fileName + "_" + QString::number(x) + "_"
+ QString::number(y) + ".omc2");
QString path(z.set.absoluteFilePath(fileName));
if (!QFileInfo::exists(path)) {
qWarning("%s: %s: not found", qPrintable(name()),
qPrintable(fileName));
return QPixmap();
} else {
QImage img(path);
return QPixmap::fromImage(img);
}
}
}
void OruxMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
@ -484,14 +549,12 @@ void OruxMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
+ "_" + QString::number(x/z.tileSize.width())
+ "_" + QString::number(y/z.tileSize.height());
if (!QPixmapCache::find(key, &pixmap)) {
pixmap = tile(z.zoom, x/z.tileSize.width(), y/z.tileSize.height());
pixmap = tile(z, x/z.tileSize.width(), y/z.tileSize.height());
if (!pixmap.isNull())
QPixmapCache::insert(key, pixmap);
}
if (pixmap.isNull())
qWarning("%s: error loading tile image", qPrintable(key));
else {
if (!pixmap.isNull()) {
pixmap.setDevicePixelRatio(_mapRatio);
QPointF tp(tl.x() + i * ts.width(), tl.y() + j * ts.height());
painter->drawPixmap(tp, pixmap);

View File

@ -3,6 +3,7 @@
#include <QDebug>
#include <QSqlDatabase>
#include <QDir>
#include "map.h"
#include "projection.h"
#include "transform.h"
@ -44,9 +45,10 @@ public:
private:
struct Zoom {
Zoom(int zoom, const QSize &tileSize, const QSize &size,
const Projection &proj, const Transform &transform)
const Projection &proj, const Transform &transform,
const QString &fileName, const QString &set)
: zoom(zoom), tileSize(tileSize), size(size), projection(proj),
transform(transform) {}
transform(transform), fileName(fileName), set(set) {}
bool operator<(const Zoom &other) const
{return zoom < other.zoom;}
@ -55,14 +57,16 @@ private:
QSize size;
Projection projection;
Transform transform;
QString fileName;
QDir set;
};
bool readXML(const QString &path);
void oruxTracker(QXmlStreamReader &reader, int level);
void mapCalibration(QXmlStreamReader &reader, int level);
bool readXML(const QString &path, const QString &dir = QString());
void oruxTracker(QXmlStreamReader &reader, const QString &dir, int level);
void mapCalibration(QXmlStreamReader &reader, const QString &dir, int level);
void calibrationPoints(QXmlStreamReader &reader, const QSize &size,
QList<CalibrationPoint> &points);
QPixmap tile(int zoom, int x, int y) const;
QPixmap tile(const Zoom &z, int x, int y) const;
friend QDebug operator<<(QDebug dbg, const Zoom &zoom);