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

Added support for TwoNav data files (trk, rte, wpt)

Resolves #411
This commit is contained in:
Martin Tůma 2021-12-24 13:43:23 +01:00
parent 932aadee5f
commit 321357b74d
5 changed files with 267 additions and 17 deletions

View File

@ -112,6 +112,7 @@ HEADERS += src/common/config.h \
src/GUI/pngexportdialog.h \ src/GUI/pngexportdialog.h \
src/GUI/timezoneinfo.h \ src/GUI/timezoneinfo.h \
src/GUI/passwordedit.h \ src/GUI/passwordedit.h \
src/data/twonavparser.h \
src/map/proj/polyconic.h \ src/map/proj/polyconic.h \
src/map/proj/webmercator.h \ src/map/proj/webmercator.h \
src/map/proj/transversemercator.h \ src/map/proj/transversemercator.h \
@ -312,6 +313,7 @@ SOURCES += src/main.cpp \
src/GUI/pngexportdialog.cpp \ src/GUI/pngexportdialog.cpp \
src/GUI/projectioncombobox.cpp \ src/GUI/projectioncombobox.cpp \
src/GUI/passwordedit.cpp \ src/GUI/passwordedit.cpp \
src/data/twonavparser.cpp \
src/map/proj/polyconic.cpp \ src/map/proj/polyconic.cpp \
src/map/proj/webmercator.cpp \ src/map/proj/webmercator.cpp \
src/map/proj/transversemercator.cpp \ src/map/proj/transversemercator.cpp \

View File

@ -1,7 +1,6 @@
#include <QApplication> #include <QApplication>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QLineF>
#include "gpxparser.h" #include "gpxparser.h"
#include "tcxparser.h" #include "tcxparser.h"
#include "csvparser.h" #include "csvparser.h"
@ -20,6 +19,7 @@
#include "ov2parser.h" #include "ov2parser.h"
#include "itnparser.h" #include "itnparser.h"
#include "onmoveparsers.h" #include "onmoveparsers.h"
#include "twonavparser.h"
#include "data.h" #include "data.h"
@ -44,10 +44,11 @@ static OV2Parser ov2;
static ITNParser itn; static ITNParser itn;
static OMDParser omd; static OMDParser omd;
static GHPParser ghp; static GHPParser ghp;
static TwoNavParser twonav;
static QMap<QString, Parser*> parsers() static QMultiMap<QString, Parser*> parsers()
{ {
QMap<QString, Parser*> map; QMultiMap<QString, Parser*> map;
map.insert("gpx", &gpx); map.insert("gpx", &gpx);
map.insert("tcx", &tcx); map.insert("tcx", &tcx);
@ -72,11 +73,14 @@ static QMap<QString, Parser*> parsers()
map.insert("itn", &itn); map.insert("itn", &itn);
map.insert("omd", &omd); map.insert("omd", &omd);
map.insert("ghp", &ghp); map.insert("ghp", &ghp);
map.insert("trk", &twonav);
map.insert("rte", &twonav);
map.insert("wpt", &twonav);
return map; return map;
} }
QMap<QString, Parser*> Data::_parsers = parsers(); QMultiMap<QString, Parser*> Data::_parsers = parsers();
void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData) void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
{ {
@ -101,16 +105,21 @@ Data::Data(const QString &fileName, bool tryUnknown)
return; return;
} }
QMap<QString, Parser*>::iterator it; QMultiMap<QString, Parser*>::iterator it;
if ((it = _parsers.find(fi.suffix().toLower())) != _parsers.end()) { QString suffix(fi.suffix().toLower());
if (it.value()->parse(&file, trackData, routeData, _polygons, if ((it = _parsers.find(suffix)) != _parsers.end()) {
_waypoints)) { while (it != _parsers.end() && it.key() == suffix) {
processData(trackData, routeData); if (it.value()->parse(&file, trackData, routeData, _polygons,
_valid = true; _waypoints)) {
return; processData(trackData, routeData);
} else { _valid = true;
_errorLine = it.value()->errorLine(); return;
_errorString = it.value()->errorString(); } else {
_errorLine = it.value()->errorLine();
_errorString = it.value()->errorString();
}
file.reset();
++it;
} }
} else if (tryUnknown) { } else if (tryUnknown) {
for (it = _parsers.begin(); it != _parsers.end(); it++) { for (it = _parsers.begin(); it != _parsers.end(); it++) {
@ -137,6 +146,7 @@ QString Data::formats()
{ {
return return
qApp->translate("Data", "Supported files") + " (" + filter().join(" ") + ");;" qApp->translate("Data", "Supported files") + " (" + filter().join(" ") + ");;"
+ qApp->translate("Data", "TwoNav files") + " (*.rte *.trk *.wpt);;"
+ qApp->translate("Data", "CSV files") + " (*.csv);;" + qApp->translate("Data", "CSV files") + " (*.csv);;"
+ qApp->translate("Data", "CUP files") + " (*.cup);;" + qApp->translate("Data", "CUP files") + " (*.cup);;"
+ qApp->translate("Data", "FIT files") + " (*.fit);;" + qApp->translate("Data", "FIT files") + " (*.fit);;"
@ -162,7 +172,7 @@ QStringList Data::filter()
{ {
QStringList filter; QStringList filter;
for (QMap<QString, Parser*>::iterator it = _parsers.begin(); for (QMultiMap<QString, Parser*>::iterator it = _parsers.begin();
it != _parsers.end(); it++) it != _parsers.end(); it++)
filter << "*." + it.key(); filter << "*." + it.key();

View File

@ -2,7 +2,7 @@
#define DATA_H #define DATA_H
#include <QList> #include <QList>
#include <QMap> #include <QMultiMap>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include "waypoint.h" #include "waypoint.h"
@ -39,7 +39,7 @@ private:
QList<Area> _polygons; QList<Area> _polygons;
QVector<Waypoint> _waypoints; QVector<Waypoint> _waypoints;
static QMap<QString, Parser*> _parsers; static QMultiMap<QString, Parser*> _parsers;
}; };
#endif // DATA_H #endif // DATA_H

217
src/data/twonavparser.cpp Normal file
View File

@ -0,0 +1,217 @@
#include "common/textcodec.h"
#include "map/gcs.h"
#include "twonavparser.h"
static double lon(const QString &str)
{
QStringList l(str.split(QChar(0xBA)));
if (l.size() < 2)
return NAN;
bool ok;
double val = l.at(0).toDouble(&ok);
if (!ok)
return NAN;
if (l.at(1) == "W")
return -val;
else if (l.at(1) == "E")
return val;
else
return NAN;
}
static double lat(const QString &str)
{
QStringList l(str.split(QChar(0xBA)));
if (l.size() < 2)
return NAN;
bool ok;
double val = l.at(0).toDouble(&ok);
if (!ok)
return NAN;
if (l.at(1) == "S")
return -val;
else if (l.at(1) == "N")
return val;
else
return NAN;
}
static QDateTime timestamp(const QString &dateStr, const QString &timeStr)
{
QLocale l("C");
QDate date(l.toDate(dateStr, "dd-MMM-yy"));
if (date.isValid())
date = date.addYears(100);
else {
date = l.toDate(dateStr, "dd-MMM-yyyy");
if (!date.isValid())
return QDateTime();
}
QTime time(l.toTime(timeStr, "H:m:s.z"));
if (!time.isValid()) {
time = l.toTime(timeStr, "H:m:s");
if (!time.isValid())
return QDateTime();
}
return QDateTime(date, time);
}
bool TwoNavParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints)
{
Q_UNUSED(polygons);
TextCodec codec;
GCS gcs;
bool ok, route = false, track = false, waypoint = false;
_errorLine = 1;
_errorString.clear();
quint8 bom[3];
if (file->peek((char*)bom, sizeof(bom)) == sizeof(bom)
&& bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) {
file->seek(3);
codec = TextCodec(65001);
}
while (!file->atEnd()) {
QByteArray line(file->readLine().trimmed());
if (!line.size())
continue;
switch (line.at(0)) {
case 'B':
{line.remove(0, 1);
QByteArray encoding(line.trimmed());
if (encoding == "UTF-8")
codec = TextCodec(65001);
else {
_errorString = "Invalid/unknown encoding";
return false;
}}
break;
case 'G':
{line.remove(0, 1);
QString datum(line.trimmed());
gcs = GCS::gcs(datum);
if (gcs.isNull()) {
_errorString = "Invalid/unknown datum";
return false;
}}
break;
case 'U':
{line.remove(0, 1);
QByteArray cs(line.trimmed());
if (cs != "1") {
_errorString = "Invalid/unknown coordinate system";
return false;
}}
break;
case 'T':
{QStringList list(codec.toString(line).split(' ',
Qt::SkipEmptyParts));
if (list.size() < 4) {
_errorString = "Parse error";
return false;
}
Coordinates c(lon(list.at(3)), lat(list.at(2)));
if (!c.isValid()) {
_errorString = "Invalid coordinates";
return false;
}
Trackpoint t(gcs.toWGS84(c));
if (list.size() > 5) {
QDateTime ts(timestamp(list.at(4), list.at(5)));
if (!ts.isValid()) {
_errorString = "Invalid date/time";
return false;
}
t.setTimestamp(ts);
}
if (list.size() > 7) {
qreal elevation = list.at(7).toDouble(&ok);
if (!ok) {
_errorString = "Invalid altitude";
return false;
}
t.setElevation(elevation);
}
if (!track) {
tracks.append(TrackData());
tracks.last().append(SegmentData());
track = true;
}
tracks.last().last().append(t);}
break;
case 'W':
{QStringList list(codec.toString(line).split(' ',
Qt::SkipEmptyParts));
if (list.size() < 5) {
_errorString = "Parse error";
return false;
}
Coordinates c(lon(list.at(4)), lat(list.at(3)));
if (!c.isValid()) {
_errorString = "Invalid coordinates";
return false;
}
Waypoint w(gcs.toWGS84(c));
w.setName(list.at(1));
if (list.size() > 6) {
QDateTime ts(timestamp(list.at(5), list.at(6)));
if (!ts.isValid()) {
_errorString = "Invalid date/time";
return false;
}
w.setTimestamp(ts);
}
if (list.size() > 7) {
qreal elevation = list.at(7).toDouble(&ok);
if (!ok) {
_errorString = "Invalid altitude";
return false;
}
w.setElevation(elevation);
}
if (list.size() > 8)
w.setDescription(list.mid(8).join(' '));
if (route)
routes.last().append(w);
else {
waypoints.append(w);
waypoint = true;
}}
break;
case 'R':
{QStringList list(codec.toString(line).split(',',
Qt::SkipEmptyParts));
routes.append(RouteData());
routes.last().setName(list.at(1));
route = true;}
break;
}
_errorLine++;
}
if (!(waypoint | route | track)) {
_errorString = "No valid data found";
return false;
} else
return true;
}

21
src/data/twonavparser.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef TWONAVPARSER_H
#define TWONAVPARSER_H
#include "parser.h"
class TwoNavParser : public Parser
{
public:
TwoNavParser() : _errorLine(0) {}
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return _errorLine;}
private:
QString _errorString;
int _errorLine;
};
#endif // TWONAVPARSER_H