1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-07 16:02:51 +02:00

Compare commits

..

14 Commits
11.3 ... 11.4

Author SHA1 Message Date
fafe6c4b03 Various KML/KMZ parsing fixes and code cleanup 2022-09-02 22:53:38 +02:00
b156e25023 Properly handle PhotoOverlay icon URLs 2022-09-02 09:55:11 +02:00
e15deccfca Added Catalan localization stub 2022-09-02 08:42:28 +02:00
9b24bccfed Added PhotoOverlay support
+ non-shared styles
2022-09-02 08:36:58 +02:00
589c602d21 Document styles are not inherited 2022-09-01 00:49:21 +02:00
b7df3cbe0e Added support for KMZ data files + KML icons
fixes #312
2022-09-01 00:28:00 +02:00
f08f5893a3 Only offset the waypoint icons when they are using the symbol icons 2022-09-01 00:25:48 +02:00
1d5f7db12f Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (464 of 464 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/nb_NO/
2022-08-30 08:58:07 +02:00
532a1eb69f Translated using Weblate (Norwegian Bokmål)
Currently translated at 98.7% (458 of 464 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/nb_NO/
2022-08-20 11:22:56 +02:00
1efb4e494d Properly abort the connections on timeout 2022-08-17 01:50:24 +02:00
4653f771a6 Code cleanup 2022-08-15 09:12:37 +02:00
22e5ffaa0c Added support for non-SQL Orux maps
+ error handling fixes/improvements
2022-08-11 23:39:36 +02:00
9a4514a464 Version++ 2022-08-11 23:38:48 +02:00
7d47f243ea Added Orux maps to supported offline maps 2022-08-11 01:02:58 +02:00
16 changed files with 3039 additions and 179 deletions

View File

@ -1,4 +1,4 @@
version: 11.3.{build} version: 11.4.{build}
configuration: configuration:
- Release - Release

View File

@ -11,7 +11,8 @@ GPS log file formats.
* Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases, * Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases,
Garmin IMG/GMAP & JNX maps, TwoNav RMaps, GeoTIFF images, BSB charts, KMZ maps, Garmin IMG/GMAP & JNX maps, TwoNav RMaps, GeoTIFF images, BSB charts, KMZ maps,
AlpineQuest maps, Locus/OsmAnd/RMaps SQLite maps, Mapsforge vector maps, AlpineQuest maps, Locus/OsmAnd/RMaps SQLite maps, Mapsforge vector maps,
QCT maps, GEMF maps, Osmdroid SQLite maps, ESRI World-File georeferenced images). QCT maps, GEMF maps, Osmdroid SQLite maps, Orux maps,
ESRI World-File georeferenced images).
* Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts * Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts
graphs. graphs.
* Support for DEM files (SRTM HGT). * Support for DEM files (SRTM HGT).

View File

@ -3,7 +3,7 @@ unix:!macx:!android {
} else { } else {
TARGET = GPXSee TARGET = GPXSee
} }
VERSION = 11.3 VERSION = 11.4
QT += core \ QT += core \
gui \ gui \

2523
lang/gpxsee_ca.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -200,13 +200,13 @@
<location filename="../src/GUI/elevationgraph.cpp" line="60"/> <location filename="../src/GUI/elevationgraph.cpp" line="60"/>
<source>Up</source> <source>Up</source>
<extracomment>Use an Unicode arrow (U+2197) when there is no abbreviation or extremly short term for &quot;Up&quot; in your language</extracomment> <extracomment>Use an Unicode arrow (U+2197) when there is no abbreviation or extremly short term for &quot;Up&quot; in your language</extracomment>
<translation type="unfinished">Opp</translation> <translation>Opp</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/elevationgraph.cpp" line="64"/> <location filename="../src/GUI/elevationgraph.cpp" line="64"/>
<source>Down</source> <source>Down</source>
<extracomment>Use an Unicode arrow (U+2198) when there is no abbreviation or extremly short term for &quot;Down&quot; in your language</extracomment> <extracomment>Use an Unicode arrow (U+2198) when there is no abbreviation or extremly short term for &quot;Down&quot; in your language</extracomment>
<translation type="unfinished">Ned</translation> <translation>Ned</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/elevationgraph.cpp" line="67"/> <location filename="../src/GUI/elevationgraph.cpp" line="67"/>
@ -374,7 +374,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="219"/> <location filename="../src/GUI/gui.cpp" line="219"/>
<source>Open directory...</source> <source>Open directory...</source>
<translation type="unfinished">Åpne mappe </translation> <translation>Åpne mappe </translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="224"/> <location filename="../src/GUI/gui.cpp" line="224"/>
@ -598,7 +598,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="477"/> <location filename="../src/GUI/gui.cpp" line="477"/>
<source>Show tabs</source> <source>Show tabs</source>
<translation type="unfinished"></translation> <translation>Vis faner</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="486"/> <location filename="../src/GUI/gui.cpp" line="486"/>
@ -712,7 +712,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="955"/> <location filename="../src/GUI/gui.cpp" line="955"/>
<source>Open directory</source> <source>Open directory</source>
<translation type="unfinished">Åpne mappe</translation> <translation>Åpne mappe</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="1959"/> <location filename="../src/GUI/gui.cpp" line="1959"/>
@ -1029,7 +1029,7 @@
<message> <message>
<location filename="../src/GUI/gearratiograph.cpp" line="28"/> <location filename="../src/GUI/gearratiograph.cpp" line="28"/>
<source>Top</source> <source>Top</source>
<translation type="unfinished">Topp</translation> <translation>Topp</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gearratiograph.cpp" line="30"/> <location filename="../src/GUI/gearratiograph.cpp" line="30"/>
@ -1236,7 +1236,7 @@
<message> <message>
<location filename="../src/map/maplist.cpp" line="157"/> <location filename="../src/map/maplist.cpp" line="157"/>
<source>GEMF maps</source> <source>GEMF maps</source>
<translation type="unfinished"></translation> <translation>GEMF-kart</translation>
</message> </message>
<message> <message>
<location filename="../src/map/maplist.cpp" line="162"/> <location filename="../src/map/maplist.cpp" line="162"/>
@ -1256,7 +1256,7 @@
<message> <message>
<location filename="../src/map/maplist.cpp" line="166"/> <location filename="../src/map/maplist.cpp" line="166"/>
<source>Orux maps</source> <source>Orux maps</source>
<translation type="unfinished"></translation> <translation>Orux-kart</translation>
</message> </message>
<message> <message>
<location filename="../src/map/maplist.cpp" line="167"/> <location filename="../src/map/maplist.cpp" line="167"/>
@ -1266,7 +1266,7 @@
<message> <message>
<location filename="../src/map/maplist.cpp" line="169"/> <location filename="../src/map/maplist.cpp" line="169"/>
<source>Osmdroid SQLite maps</source> <source>Osmdroid SQLite maps</source>
<translation type="unfinished"></translation> <translation>Osmdroid SQLite-kart</translation>
</message> </message>
<message> <message>
<location filename="../src/map/maplist.cpp" line="170"/> <location filename="../src/map/maplist.cpp" line="170"/>
@ -1286,7 +1286,7 @@
<message> <message>
<location filename="../src/map/maplist.cpp" line="177"/> <location filename="../src/map/maplist.cpp" line="177"/>
<source>All files</source> <source>All files</source>
<translation type="unfinished">Alle filer</translation> <translation>Alle filer</translation>
</message> </message>
<message> <message>
<location filename="../src/map/maplist.cpp" line="168"/> <location filename="../src/map/maplist.cpp" line="168"/>
@ -1921,7 +1921,7 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="779"/> <location filename="../src/GUI/optionsdialog.cpp" line="779"/>
<source>Initial paths</source> <source>Initial paths</source>
<translation type="unfinished">Forvalgte stier</translation> <translation>Forvalgte stier</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="814"/> <location filename="../src/GUI/optionsdialog.cpp" line="814"/>

View File

@ -37,7 +37,7 @@ Unicode true
; The name of the installer ; The name of the installer
Name "GPXSee" Name "GPXSee"
; Program version ; Program version
!define VERSION "11.3" !define VERSION "11.4"
; The file to write ; The file to write
OutFile "GPXSee-${VERSION}_x64.exe" OutFile "GPXSee-${VERSION}_x64.exe"

View File

@ -99,18 +99,26 @@ void WaypointItem::updateCache()
QPainterPath p; QPainterPath p;
qreal pointSize = _font.bold() ? HS(_size) : _size; qreal pointSize = _font.bold() ? HS(_size) : _size;
if (_showLabel) { if (_showLabel && !_waypoint.name().isEmpty()) {
QFontMetrics fm(_font); QFontMetrics fm(_font);
_labelBB = fm.tightBoundingRect(_waypoint.name()); _labelBB = fm.tightBoundingRect(_waypoint.name());
if (_showIcon && _icon) { if (_showIcon && _icon) {
if (_font.bold()) if (_font.bold())
p.addRect(-_icon->width() * 0.625, -_icon->height() * 1.25, p.addRect(-_icon->width() * 0.625, _waypoint.icon().isNull()
? -_icon->height() * 1.25 : -_icon->height() * 0.625,
_icon->width() * 1.25, _icon->height() * 1.25); _icon->width() * 1.25, _icon->height() * 1.25);
else else
p.addRect(-_icon->width()/2.0, -_icon->height(), _icon->width(), p.addRect(-_icon->width()/2.0, _waypoint.icon().isNull()
? -_icon->height() : -_icon->height()/2, _icon->width(),
_icon->height()); _icon->height());
p.addRect(0, 0, _labelBB.width(), _labelBB.height() + fm.descent());
if (_waypoint.icon().isNull())
p.addRect(0, 0, _labelBB.width(), _labelBB.height()
+ fm.descent());
else
p.addRect(_icon->width()/2, _icon->height()/2, _labelBB.width(),
_labelBB.height() + fm.descent());
} else { } else {
p.addRect(-pointSize/2, -pointSize/2, pointSize, pointSize); p.addRect(-pointSize/2, -pointSize/2, pointSize, pointSize);
p.addRect(pointSize/2, pointSize/2, _labelBB.width(), p.addRect(pointSize/2, pointSize/2, _labelBB.width(),
@ -119,10 +127,12 @@ void WaypointItem::updateCache()
} else { } else {
if (_showIcon && _icon) { if (_showIcon && _icon) {
if (_font.bold()) if (_font.bold())
p.addRect(-_icon->width() * 0.625, -_icon->height() * 1.25, p.addRect(-_icon->width() * 0.625, _waypoint.icon().isNull()
? -_icon->height() * 1.25 : -_icon->height() * 0.625,
_icon->width() * 1.25, _icon->height() * 1.25); _icon->width() * 1.25, _icon->height() * 1.25);
else else
p.addRect(-_icon->width()/2, -_icon->height(), _icon->width(), p.addRect(-_icon->width()/2, _waypoint.icon().isNull()
? -_icon->height() : -_icon->height()/2, _icon->width(),
_icon->height()); _icon->height());
} else } else
p.addRect(-pointSize/2, -pointSize/2, pointSize, pointSize); p.addRect(-pointSize/2, -pointSize/2, pointSize, pointSize);
@ -140,12 +150,16 @@ void WaypointItem::paint(QPainter *painter,
painter->setPen(_color); painter->setPen(_color);
if (_showLabel) { if (_showLabel && !_waypoint.name().isEmpty()) {
painter->setFont(_font); painter->setFont(_font);
if (_showIcon && _icon) if (_showIcon && _icon) {
painter->drawText(-qMax(_labelBB.x(), 0), _labelBB.height(), if (_waypoint.icon().isNull())
_waypoint.name()); painter->drawText(-qMax(_labelBB.x(), 0), _labelBB.height(),
else _waypoint.name());
else
painter->drawText(_icon->width()/2 - qMax(_labelBB.x(), 0),
_icon->height()/2 + _labelBB.height(), _waypoint.name());
} else
painter->drawText(pointSize/2 - qMax(_labelBB.x(), 0), pointSize/2 painter->drawText(pointSize/2 - qMax(_labelBB.x(), 0), pointSize/2
+ _labelBB.height(), _waypoint.name()); + _labelBB.height(), _waypoint.name());
} }
@ -153,11 +167,13 @@ void WaypointItem::paint(QPainter *painter,
painter->setBrush(QBrush(_color, Qt::SolidPattern)); painter->setBrush(QBrush(_color, Qt::SolidPattern));
if (_showIcon && _icon) { if (_showIcon && _icon) {
if (_font.bold()) if (_font.bold())
painter->drawPixmap(-_icon->width() * 0.625, -_icon->height() * 1.25, painter->drawPixmap(-_icon->width() * 0.625, _waypoint.icon().isNull()
? -_icon->height() * 1.25 : -_icon->height() * 0.625,
_icon->scaled(_icon->width() * 1.25, _icon->height() * 1.25, _icon->scaled(_icon->width() * 1.25, _icon->height() * 1.25,
Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
else else
painter->drawPixmap(-_icon->width()/2.0, -_icon->height(), *_icon); painter->drawPixmap(-_icon->width()/2.0, _waypoint.icon().isNull()
? -_icon->height() : -_icon->height()/2, *_icon);
} else } else
painter->drawEllipse(-pointSize/2, -pointSize/2, pointSize, pointSize); painter->drawEllipse(-pointSize/2, -pointSize/2, pointSize, pointSize);

View File

@ -68,7 +68,7 @@ void NetworkTimeout::timerEvent(QTimerEvent *ev)
return; return;
QNetworkReply *reply = static_cast<QNetworkReply*>(parent()); QNetworkReply *reply = static_cast<QNetworkReply*>(parent());
if (reply->isRunning()) if (reply->isRunning())
reply->close(); reply->abort();
_timer.stop(); _timer.stop();
} }

View File

@ -1,6 +1,7 @@
#include <cctype> #include <cctype>
#include <cmath> #include <cmath>
#include <QFileInfo> #include <QFileInfo>
#include <QTemporaryDir>
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
#include <QUrl> #include <QUrl>
#include <QCoreApplication> #include <QCoreApplication>
@ -139,3 +140,9 @@ QString Util::displayName(const QString &path)
return path; return path;
#endif // Q_OS_ANDROID #endif // Q_OS_ANDROID
} }
const QTemporaryDir &Util::tempDir()
{
static QTemporaryDir dir;
return dir;
}

View File

@ -3,12 +3,15 @@
#include <QString> #include <QString>
class QTemporaryDir;
namespace Util namespace Util
{ {
int str2int(const char *str, int len); int str2int(const char *str, int len);
double niceNum(double x, bool round); double niceNum(double x, bool round);
QString file2name(const QString &path); QString file2name(const QString &path);
QString displayName(const QString &path); QString displayName(const QString &path);
const QTemporaryDir &tempDir();
} }
#endif // UTIL_H #endif // UTIL_H

View File

@ -53,6 +53,7 @@ static QMultiMap<QString, Parser*> parsers()
map.insert("gpx", &gpx); map.insert("gpx", &gpx);
map.insert("tcx", &tcx); map.insert("tcx", &tcx);
map.insert("kml", &kml); map.insert("kml", &kml);
map.insert("kmz", &kml);
map.insert("fit", &fit); map.insert("fit", &fit);
map.insert("csv", &csv); map.insert("csv", &csv);
map.insert("igc", &igc); map.insert("igc", &igc);
@ -162,7 +163,7 @@ QString Data::formats()
+ qApp->translate("Data", "IGC files") + " (*.igc);;" + qApp->translate("Data", "IGC files") + " (*.igc);;"
+ qApp->translate("Data", "ITN files") + " (*.itn);;" + qApp->translate("Data", "ITN files") + " (*.itn);;"
+ qApp->translate("Data", "JPEG images") + " (*.jpg *.jpeg);;" + qApp->translate("Data", "JPEG images") + " (*.jpg *.jpeg);;"
+ qApp->translate("Data", "KML files") + " (*.kml);;" + qApp->translate("Data", "KML files") + " (*.kml *.kmz);;"
+ qApp->translate("Data", "LOC files") + " (*.loc);;" + qApp->translate("Data", "LOC files") + " (*.loc);;"
+ qApp->translate("Data", "NMEA files") + " (*.nmea);;" + qApp->translate("Data", "NMEA files") + " (*.nmea);;"
+ qApp->translate("Data", "ONmove files") + " (*.omd *.ghp);;" + qApp->translate("Data", "ONmove files") + " (*.omd *.ghp);;"

View File

@ -11,6 +11,7 @@
#include "common/garmin.h" #include "common/garmin.h"
#include "common/textcodec.h" #include "common/textcodec.h"
#include "common/color.h" #include "common/color.h"
#include "common/util.h"
#include "address.h" #include "address.h"
#include "gpiparser.h" #include "gpiparser.h"
@ -388,12 +389,6 @@ static quint32 readAddress(DataStream &stream, Waypoint &waypoint)
return rs + rh.size; return rs + rh.size;
} }
static const QTemporaryDir &tempDir()
{
static QTemporaryDir dir;
return dir;
}
static quint32 readImageInfo(DataStream &stream, Waypoint &waypoint, static quint32 readImageInfo(DataStream &stream, Waypoint &waypoint,
const QString &fileName, int &imgId) const QString &fileName, int &imgId)
{ {
@ -408,12 +403,12 @@ static quint32 readImageInfo(DataStream &stream, Waypoint &waypoint,
ba.resize(size); ba.resize(size);
stream.readRawData(ba.data(), ba.size()); stream.readRawData(ba.data(), ba.size());
if (tempDir().isValid()) { if (Util::tempDir().isValid()) {
QBuffer buf(&ba); QBuffer buf(&ba);
QImageReader ir(&buf); QImageReader ir(&buf);
QByteArray id(fileName.toUtf8() + QByteArray::number(imgId++)); QByteArray id(fileName.toUtf8() + QByteArray::number(imgId++));
QFile imgFile(tempDir().path() + "/" + QString("%0.%1").arg( QFile imgFile(Util::tempDir().path() + "/" + QString("%0.%1").arg(
QCryptographicHash::hash(id, QCryptographicHash::Sha1).toHex(), QCryptographicHash::hash(id, QCryptographicHash::Sha1).toHex(),
QString(ir.format()))); QString(ir.format())));
imgFile.open(QIODevice::WriteOnly); imgFile.open(QIODevice::WriteOnly);

View File

@ -1,5 +1,33 @@
/*
WARNING: This code uses internal Qt API - the QZipReader class for reading
ZIP files - and things may break if Qt changes the API. For Qt5 this is not
a problem as we can "see the future" now and there are no changes in all
the supported Qt5 versions up to the last one (5.15). In Qt6 the class
might change or even disappear in the future, but this is very unlikely
as there were no changes for several years and The Qt Company's policy
is: "do not invest any resources into any desktop related stuff unless
absolutely necessary". There is an issue (QTBUG-3897) since the year 2009 to
include the ZIP reader into the public API, which aptly illustrates the
effort The Qt Company is willing to make about anything desktop related...
*/
#include <QFileInfo>
#include <QTemporaryDir>
#include <QCryptographicHash>
#include <QtEndian>
#include <QUrl>
#include <QRegularExpression>
#include <private/qzipreader_p.h>
#include "common/util.h"
#include "kmlparser.h" #include "kmlparser.h"
static bool isZIP(QFile *file)
{
quint32 magic;
return (file->read((char *)&magic, sizeof(magic)) == (qint64)sizeof(magic)
&& qFromLittleEndian(magic) == 0x04034b50);
}
qreal KMLParser::number() qreal KMLParser::number()
{ {
@ -463,6 +491,9 @@ void KMLParser::multiGeometry(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints, const QString &name, const QString &desc, QVector<Waypoint> &waypoints, const QString &name, const QString &desc,
const QDateTime &timestamp) const QDateTime &timestamp)
{ {
TrackData *tp = 0;
Area *ap = 0;
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Point")) { if (_reader.name() == QLatin1String("Point")) {
waypoints.append(Waypoint()); waypoints.append(Waypoint());
@ -472,28 +503,90 @@ void KMLParser::multiGeometry(QList<TrackData> &tracks, QList<Area> &areas,
w.setTimestamp(timestamp); w.setTimestamp(timestamp);
point(w); point(w);
} else if (_reader.name() == QLatin1String("LineString")) { } else if (_reader.name() == QLatin1String("LineString")) {
tracks.append(TrackData()); if (!tp) {
TrackData &t = tracks.last(); tracks.append(TrackData());
t.append(SegmentData()); tp = &tracks.last();
t.setName(name); tp->setName(name);
t.setDescription(desc); tp->setDescription(desc);
lineString(t.last()); }
tp->append(SegmentData());
lineString(tp->last());
} else if (_reader.name() == QLatin1String("Polygon")) { } else if (_reader.name() == QLatin1String("Polygon")) {
areas.append(Area()); if (!ap) {
Area &a = areas.last(); areas.append(Area());
a.setName(name); ap = &areas.last();
a.setDescription(desc); ap->setName(name);
polygon(a); ap->setDescription(desc);
}
polygon(*ap);
} else } else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
} }
void KMLParser::placemark(QList<TrackData> &tracks, QList<Area> &areas, void KMLParser::photoOverlay(const Ctx &ctx, QVector<Waypoint> &waypoints,
QVector<Waypoint> &waypoints) QMap<QString, QPixmap> &icons)
{ {
QString name, desc, phone, address; QString img, id;
Waypoint w;
static QRegularExpression re("\\$\\[[^\\]]+\\]");
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("name"))
w.setName(_reader.readElementText());
else if (_reader.name() == QLatin1String("description"))
w.setDescription(_reader.readElementText());
else if (_reader.name() == QLatin1String("phoneNumber"))
w.setPhone(_reader.readElementText());
else if (_reader.name() == QLatin1String("address"))
w.setAddress(_reader.readElementText());
else if (_reader.name() == QLatin1String("TimeStamp"))
w.setTimestamp(timeStamp());
else if (_reader.name() == QLatin1String("Style")) {
style(ctx.dir, icons);
id = QString();
} else if (_reader.name() == QLatin1String("StyleMap"))
styleMap(icons);
else if (_reader.name() == QLatin1String("Icon"))
img = icon();
else if (_reader.name() == QLatin1String("Point"))
point(w);
else if (_reader.name() == QLatin1String("styleUrl"))
id = styleUrl();
else
_reader.skipCurrentElement();
}
if (!w.coordinates().isNull()) {
w.setIcon(icons.value(id));
img.replace(re, "0");
if (!QUrl(img).scheme().isEmpty())
w.addLink(Link(img, "Photo Overlay"));
else if (ctx.zip && Util::tempDir().isValid()) {
QFileInfo fi(img);
QByteArray id(ctx.path.toUtf8() + img.toUtf8());
QString path(Util::tempDir().path() + "/" + QString("%0.%1")
.arg(QCryptographicHash::hash(id, QCryptographicHash::Sha1)
.toHex(), QString(fi.suffix())));
QFile::rename(ctx.dir.absoluteFilePath(img), path);
w.addImage(path);
} else if (!ctx.zip)
w.addImage(ctx.dir.absoluteFilePath(img));
waypoints.append(w);
}
}
void KMLParser::placemark(const Ctx &ctx, QList<TrackData> &tracks,
QList<Area> &areas, QVector<Waypoint> &waypoints,
QMap<QString, QPixmap> &icons)
{
QString name, desc, phone, address, id;
QDateTime timestamp; QDateTime timestamp;
Waypoint *wp = 0;
TrackData *tp = 0;
Area *ap = 0;
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("name")) if (_reader.name() == QLatin1String("name"))
@ -506,87 +599,185 @@ void KMLParser::placemark(QList<TrackData> &tracks, QList<Area> &areas,
address = _reader.readElementText(); address = _reader.readElementText();
else if (_reader.name() == QLatin1String("TimeStamp")) else if (_reader.name() == QLatin1String("TimeStamp"))
timestamp = timeStamp(); timestamp = timeStamp();
else if (_reader.name() == QLatin1String("Style")) {
style(ctx.dir, icons);
id = QString();
} else if (_reader.name() == QLatin1String("StyleMap"))
styleMap(icons);
else if (_reader.name() == QLatin1String("MultiGeometry")) else if (_reader.name() == QLatin1String("MultiGeometry"))
multiGeometry(tracks, areas, waypoints, name, desc, timestamp); multiGeometry(tracks, areas, waypoints, name, desc, timestamp);
else if (_reader.name() == QLatin1String("Point")) { else if (_reader.name() == QLatin1String("Point")) {
waypoints.append(Waypoint()); waypoints.append(Waypoint());
Waypoint &w = waypoints.last(); wp = &waypoints.last();
w.setName(name); point(*wp);
w.setDescription(desc);
w.setTimestamp(timestamp);
w.setAddress(address);
w.setPhone(phone);
point(w);
} else if (_reader.name() == QLatin1String("LineString") } else if (_reader.name() == QLatin1String("LineString")
|| _reader.name() == QLatin1String("LinearRing")) { || _reader.name() == QLatin1String("LinearRing")) {
tracks.append(TrackData()); tracks.append(TrackData());
TrackData &t = tracks.last(); tp = &tracks.last();
t.append(SegmentData()); tp->append(SegmentData());
t.setName(name); lineString(tp->last());
t.setDescription(desc);
lineString(t.last());
} else if (_reader.name() == QLatin1String("Track")) { } else if (_reader.name() == QLatin1String("Track")) {
tracks.append(TrackData()); tracks.append(TrackData());
TrackData &t = tracks.last(); tp = &tracks.last();
t.append(SegmentData()); tp->append(SegmentData());
t.setName(name); track(tp->last());
t.setDescription(desc);
track(t.last());
} else if (_reader.name() == QLatin1String("MultiTrack")) { } else if (_reader.name() == QLatin1String("MultiTrack")) {
tracks.append(TrackData()); tracks.append(TrackData());
TrackData &t = tracks.last(); tp = &tracks.last();
t.setName(name); multiTrack(*tp);
t.setDescription(desc);
multiTrack(t);
} else if (_reader.name() == QLatin1String("Polygon")) { } else if (_reader.name() == QLatin1String("Polygon")) {
areas.append(Area()); areas.append(Area());
Area &a = areas.last(); ap = &areas.last();
a.setName(name); polygon(*ap);
a.setDescription(desc); } else if (_reader.name() == QLatin1String("styleUrl"))
polygon(a); id = styleUrl();
} else else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
if (wp) {
wp->setName(name);
wp->setDescription(desc);
wp->setTimestamp(timestamp);
wp->setAddress(address);
wp->setPhone(phone);
wp->setIcon(icons.value(id));
} else if (tp) {
tp->setName(name);
tp->setDescription(desc);
} else if (ap) {
ap->setName(name);
ap->setDescription(desc);
}
} }
void KMLParser::folder(QList<TrackData> &tracks, QList<Area> &areas, QString KMLParser::icon()
QVector<Waypoint> &waypoints) {
QString path;
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("href"))
path = _reader.readElementText();
else
_reader.skipCurrentElement();
}
return path;
}
QString KMLParser::styleUrl()
{
QString id(_reader.readElementText());
return (id.at(0) == '#') ? id.right(id.size() - 1) : QString();
}
void KMLParser::iconStyle(const QDir &dir, const QString &id,
QMap<QString, QPixmap> &icons)
{ {
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Placemark")) if (_reader.name() == QLatin1String("Icon"))
placemark(tracks, areas, waypoints); icons.insert(id, QPixmap(dir.absoluteFilePath(icon())));
else if (_reader.name() == QLatin1String("Folder"))
folder(tracks, areas, waypoints);
else else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
} }
void KMLParser::document(QList<TrackData> &tracks, QList<Area> &areas, void KMLParser::styleMapPair(const QString &id, QMap<QString, QPixmap> &icons)
QVector<Waypoint> &waypoints)
{ {
QString key, url;
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Document")) if (_reader.name() == QLatin1String("key"))
document(tracks, areas, waypoints); key = _reader.readElementText();
else if (_reader.name() == QLatin1String("Placemark")) else if (_reader.name() == QLatin1String("styleUrl"))
placemark(tracks, areas, waypoints); url = styleUrl();
else if (_reader.name() == QLatin1String("Folder")) else
folder(tracks, areas, waypoints); _reader.skipCurrentElement();
}
if (key == "normal")
icons.insert(id, icons.value(url));
}
void KMLParser::styleMap(QMap<QString, QPixmap> &icons)
{
QString id = _reader.attributes().value("id").toString();
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Pair"))
styleMapPair(id, icons);
else else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
} }
void KMLParser::kml(QList<TrackData> &tracks, QList<Area> &areas, void KMLParser::style(const QDir &dir, QMap<QString, QPixmap> &icons)
QVector<Waypoint> &waypoints) {
QString id = _reader.attributes().value("id").toString();
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("IconStyle"))
iconStyle(dir, id, icons);
else
_reader.skipCurrentElement();
}
}
void KMLParser::folder(const Ctx &ctx, QList<TrackData> &tracks,
QList<Area> &areas, QVector<Waypoint> &waypoints,
QMap<QString, QPixmap> &icons)
{ {
while (_reader.readNextStartElement()) { while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Document")) if (_reader.name() == QLatin1String("Document"))
document(tracks, areas, waypoints); document(ctx, tracks, areas, waypoints);
else if (_reader.name() == QLatin1String("Placemark"))
placemark(tracks, areas, waypoints);
else if (_reader.name() == QLatin1String("Folder")) else if (_reader.name() == QLatin1String("Folder"))
folder(tracks, areas, waypoints); folder(ctx, tracks, areas, waypoints, icons);
else if (_reader.name() == QLatin1String("Placemark"))
placemark(ctx, tracks, areas, waypoints, icons);
else if (_reader.name() == QLatin1String("PhotoOverlay"))
photoOverlay(ctx, waypoints, icons);
else
_reader.skipCurrentElement();
}
}
void KMLParser::document(const Ctx &ctx, QList<TrackData> &tracks,
QList<Area> &areas, QVector<Waypoint> &waypoints)
{
QMap<QString, QPixmap> icons;
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Document"))
document(ctx, tracks, areas, waypoints);
else if (_reader.name() == QLatin1String("Folder"))
folder(ctx, tracks, areas, waypoints, icons);
else if (_reader.name() == QLatin1String("Placemark"))
placemark(ctx, tracks, areas, waypoints, icons);
else if (_reader.name() == QLatin1String("PhotoOverlay"))
photoOverlay(ctx, waypoints, icons);
else if (_reader.name() == QLatin1String("Style"))
style(ctx.dir, icons);
else if (_reader.name() == QLatin1String("StyleMap"))
styleMap(icons);
else
_reader.skipCurrentElement();
}
}
void KMLParser::kml(const Ctx &ctx, QList<TrackData> &tracks,
QList<Area> &areas, QVector<Waypoint> &waypoints)
{
QMap<QString, QPixmap> icons;
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Document"))
document(ctx, tracks, areas, waypoints);
else if (_reader.name() == QLatin1String("Folder"))
folder(ctx, tracks, areas, waypoints, icons);
else if (_reader.name() == QLatin1String("Placemark"))
placemark(ctx, tracks, areas, waypoints, icons);
else if (_reader.name() == QLatin1String("PhotoOverlay"))
photoOverlay(ctx, waypoints, icons);
else else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }
@ -596,15 +787,50 @@ bool KMLParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Area> &areas, QVector<Waypoint> &waypoints) QList<RouteData> &routes, QList<Area> &areas, QVector<Waypoint> &waypoints)
{ {
Q_UNUSED(routes); Q_UNUSED(routes);
QFileInfo fi(*file);
_reader.clear(); _reader.clear();
_reader.setDevice(file);
if (_reader.readNextStartElement()) { if (isZIP(file)) {
if (_reader.name() == QLatin1String("kml")) QZipReader zip(fi.absoluteFilePath(), QIODevice::ReadOnly);
kml(tracks, areas, waypoints); QTemporaryDir tempDir;
else if (!tempDir.isValid() || !zip.extractAll(tempDir.path()))
_reader.raiseError("Not a KML file"); _reader.raiseError("Error extracting ZIP file");
else {
QDir zipDir(tempDir.path());
QFileInfoList files(zipDir.entryInfoList(QStringList("*.kml"),
QDir::Files));
if (files.isEmpty())
_reader.raiseError("No KML file found in ZIP file");
else {
QFile kmlFile(files.first().absoluteFilePath());
if (!kmlFile.open(QIODevice::ReadOnly))
_reader.raiseError("Error opening KML file");
else {
_reader.setDevice(&kmlFile);
if (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("kml"))
kml(Ctx(fi.absoluteFilePath(), zipDir, true),
tracks, areas, waypoints);
else
_reader.raiseError("Not a KML file");
}
}
}
}
} else {
file->reset();
_reader.setDevice(file);
if (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("kml"))
kml(Ctx(fi.absoluteFilePath(), fi.absoluteDir(), false), tracks,
areas, waypoints);
else
_reader.raiseError("Not a KML file");
}
} }
return !_reader.error(); return !_reader.error();

View File

@ -3,6 +3,7 @@
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <QDateTime> #include <QDateTime>
#include <QDir>
#include "parser.h" #include "parser.h"
class KMLParser : public Parser class KMLParser : public Parser
@ -14,17 +15,28 @@ public:
int errorLine() const {return _reader.lineNumber();} int errorLine() const {return _reader.lineNumber();}
private: private:
void kml(QList<TrackData> &tracks, QList<Area> &areas, struct Ctx {
Ctx(const QString &path, const QDir &dir, bool zip)
: path(path), dir(dir), zip(zip) {}
QString path;
QDir dir;
bool zip;
};
void kml(const Ctx &ctx, QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints); QVector<Waypoint> &waypoints);
void document(QList<TrackData> &tracks, QList<Area> &areas, void document(const Ctx &ctx, QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints);
void folder(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints);
void placemark(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints); QVector<Waypoint> &waypoints);
void folder(const Ctx &ctx, QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints, QMap<QString, QPixmap> &icons);
void placemark(const Ctx &ctx, QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints, QMap<QString, QPixmap> &icons);
void multiGeometry(QList<TrackData> &tracks, QList<Area> &areas, void multiGeometry(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints, const QString &name, const QString &desc, QVector<Waypoint> &waypoints, const QString &name, const QString &desc,
const QDateTime &timestamp); const QDateTime &timestamp);
void photoOverlay(const Ctx &ctx, QVector<Waypoint> &waypoints,
QMap<QString, QPixmap> &icons);
void track(SegmentData &segment); void track(SegmentData &segment);
void multiTrack(TrackData &t); void multiTrack(TrackData &t);
void lineString(SegmentData &segment); void lineString(SegmentData &segment);
@ -45,6 +57,13 @@ private:
QDateTime timeStamp(); QDateTime timeStamp();
qreal number(); qreal number();
QDateTime time(); QDateTime time();
QString icon();
QString styleUrl();
void style(const QDir &dir, QMap<QString, QPixmap> &icons);
void styleMapPair(const QString &id, QMap<QString, QPixmap> &icons);
void styleMap(QMap<QString, QPixmap> &icons);
void iconStyle(const QDir &dir, const QString &id,
QMap<QString, QPixmap> &icons);
QXmlStreamReader _reader; QXmlStreamReader _reader;
}; };

View File

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

View File

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