diff --git a/gpxsee.pro b/gpxsee.pro index 0b117c8d..d1db4a9e 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -118,6 +118,7 @@ HEADERS += src/common/config.h \ src/GUI/pngexportdialog.h \ src/GUI/timezoneinfo.h \ src/GUI/passwordedit.h \ + src/data/gpsdumpparser.h \ src/data/style.h \ src/data/twonavparser.h \ src/map/ENC/attributes.h \ @@ -338,6 +339,7 @@ SOURCES += src/main.cpp \ src/GUI/pngexportdialog.cpp \ src/GUI/projectioncombobox.cpp \ src/GUI/passwordedit.cpp \ + src/data/gpsdumpparser.cpp \ src/data/twonavparser.cpp \ src/map/ENC/atlasdata.cpp \ src/map/ENC/mapdata.cpp \ diff --git a/pkg/linux/gpxsee.desktop b/pkg/linux/gpxsee.desktop index 2db957a9..46c397f7 100644 --- a/pkg/linux/gpxsee.desktop +++ b/pkg/linux/gpxsee.desktop @@ -16,4 +16,4 @@ Icon=gpxsee Terminal=false Type=Application Categories=Graphics;Viewer;Education;Geography;Maps;Sports;Qt -MimeType=application/gpx+xml;application/vnd.garmin.tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/vnd.groundspeak.loc+xml;application/vnd.sigma.slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;application/vnd.garmin.gpi;application/vnd.suunto.sml+xml;image/jpeg;text/csv;application/vnd.garmin.img;application/vnd.garmin.jnx;application/vnd.garmin.gmap+xml;image/vnd.maptech.kap;application/vnd.oziexplorer.map;application/vnd.mapbox.mbtiles;application/vnd.twonav.rmap;application/vnd.trekbuddy.tba;application/vnd.gpxsee.map+xml;application/x-tar;image/tiff;application/vnd.google-earth.kmz;application/vnd.alpinequest.aqm;application/vnd.cgtk.gemf;application/vnd.rmaps.sqlite;application/vnd.osmdroid.sqlite;application/vnd.mapsforge.map;application/vnd.tomtom.ov2;application/vnd.tomtom.itn;application/vnd.esri.wld;application/vnd.onmove.omd;application/vnd.onmove.ghp;application/vnd.memory-map.qct;application/vnd.twonav.trk;application/vnd.twonav.rte;application/vnd.twonav.wpt;application/vnd.orux.map+xml;application/vnd.iho.s57-data;application/vnd.iho.s57-catalogue +MimeType=application/gpx+xml;application/vnd.garmin.tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/vnd.groundspeak.loc+xml;application/vnd.sigma.slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;application/vnd.garmin.gpi;application/vnd.suunto.sml+xml;image/jpeg;text/csv;application/vnd.garmin.img;application/vnd.garmin.jnx;application/vnd.garmin.gmap+xml;image/vnd.maptech.kap;application/vnd.oziexplorer.map;application/vnd.mapbox.mbtiles;application/vnd.twonav.rmap;application/vnd.trekbuddy.tba;application/vnd.gpxsee.map+xml;application/x-tar;image/tiff;application/vnd.google-earth.kmz;application/vnd.alpinequest.aqm;application/vnd.cgtk.gemf;application/vnd.rmaps.sqlite;application/vnd.osmdroid.sqlite;application/vnd.mapsforge.map;application/vnd.tomtom.ov2;application/vnd.tomtom.itn;application/vnd.esri.wld;application/vnd.onmove.omd;application/vnd.onmove.ghp;application/vnd.memory-map.qct;application/vnd.twonav.trk;application/vnd.twonav.rte;application/vnd.twonav.wpt;application/vnd.orux.map+xml;application/vnd.iho.s57-data;application/vnd.iho.s57-catalogue;application/vnd.gpsdump.wpt diff --git a/pkg/linux/gpxsee.xml b/pkg/linux/gpxsee.xml index a346a170..3e1fffa5 100644 --- a/pkg/linux/gpxsee.xml +++ b/pkg/linux/gpxsee.xml @@ -177,6 +177,16 @@ + + GPSDump Waypoint File + + + + + + + + diff --git a/src/data/data.cpp b/src/data/data.cpp index 5d513feb..9f9327f3 100644 --- a/src/data/data.cpp +++ b/src/data/data.cpp @@ -21,6 +21,7 @@ #include "itnparser.h" #include "onmoveparsers.h" #include "twonavparser.h" +#include "gpsdumpparser.h" #include "data.h" @@ -46,6 +47,7 @@ static ITNParser itn; static OMDParser omd; static GHPParser ghp; static TwoNavParser twonav; +static GPSDumpParser gpsdump; static QMultiMap parsers() { @@ -78,6 +80,7 @@ static QMultiMap parsers() map.insert("trk", &twonav); map.insert("rte", &twonav); map.insert("wpt", &twonav); + map.insert("wpt", &gpsdump); return map; } @@ -174,6 +177,7 @@ QString Data::formats() + qApp->translate("Data", "SML files") + " (*.sml);;" + qApp->translate("Data", "TCX files") + " (*.tcx);;" + qApp->translate("Data", "TwoNav files") + " (*.rte *.trk *.wpt);;" + + qApp->translate("Data", "GPSDump files") + " (*.wpt);;" + qApp->translate("Data", "All files") + " (*)"; } diff --git a/src/data/gpsdumpparser.cpp b/src/data/gpsdumpparser.cpp new file mode 100644 index 00000000..bb22fc2f --- /dev/null +++ b/src/data/gpsdumpparser.cpp @@ -0,0 +1,161 @@ +#include +#include "map/pcs.h" +#include "map/gcs.h" +#include "map/utm.h" +#include "gpsdumpparser.h" + +static double dms2dd(const QStringList &dms) +{ + bool ok; + + int deg = dms.at(1).toInt(&ok); + if (!ok) + return NAN; + int min = dms.at(2).toInt(&ok); + if (!ok) + return NAN; + double sec = dms.at(3).toDouble(&ok); + if (!ok) + return NAN; + + return deg + min/60.0 + sec/3600.0; +} + +static double parseLon(const QString &str) +{ + QStringList dms(str.split(' ')); + if (dms.size() < 4) + return NAN; + + double dd = dms2dd(dms); + if (std::isnan(dd)) + return NAN; + + if (dms.at(0) == 'W') + return -dd; + else if (dms.at(0) == 'E') + return dd; + else + return NAN; +} + +static double parseLat(const QString &str) +{ + QStringList dms(str.split(' ')); + if (dms.size() < 4) + return NAN; + + double dd = dms2dd(dms); + if (std::isnan(dd)) + return NAN; + + if (dms.at(0) == 'S') + return -dd; + else if (dms.at(0) == 'N') + return dd; + else + return NAN; +} + +static Coordinates parseGEO(const QString &lat, const QString &lon) +{ + return Coordinates(parseLon(lon), parseLat(lat)); +} + +static Coordinates parseUTM(const QString &zone, const QString &easting, + const QString &northing) +{ + bool ok; + + int z = zone.left(zone.size() - 1).toInt(&ok); + if (!ok) + return Coordinates(); + if (zone.right(1) < 'N') + z = -z; + + int x = easting.toInt(&ok); + if (!ok) + return Coordinates(); + int y = northing.toInt(&ok); + if (!ok) + return Coordinates(); + + Projection proj(PCS(GCS::WGS84(), Conversion(9807, UTM::setup(z), 9001))); + + return proj.xy2ll(PointD(x, y)); +} + +bool GPSDumpParser::parse(QFile *file, QList &tracks, + QList &routes, QList &polygons, QVector &waypoints) +{ + Q_UNUSED(tracks); + Q_UNUSED(routes); + Q_UNUSED(polygons); + + _errorLine = 1; + _errorString.clear(); + Type type = Unknown; + QRegularExpression dm("[ ]{2,}"); + + while (!file->atEnd()) { + QByteArray ba(file->readLine(4096).trimmed()); + + if (_errorLine == 1) { + if (ba == "$FormatGEO") + type = GEO; + else if (ba == "$FormatUTM") + type = UTM; + else { + _errorString = "Not a GPSDump waypoint file"; + return false; + } + } else if (!ba.isEmpty()) { + QString line(ba); + QStringList fields(line.split(dm)); + Coordinates c; + double ele = NAN; + QString desc; + bool ok; + + if (type == UTM) { + if (fields.size() < 5) { + _errorString = "Parse error"; + return false; + } + + c = parseUTM(fields.at(1), fields.at(2), fields.at(3)); + ele = fields.at(4).toDouble(&ok); + if (fields.size() > 5) + desc = fields.at(5); + } else { + if (fields.size() < 4) { + _errorString = "Parse error"; + return false; + } + + c = parseGEO(fields.at(1), fields.at(2)); + ele = fields.at(3).toDouble(&ok); + if (fields.size() > 4) + desc = fields.at(4); + } + + if (!c.isValid()) { + _errorString = "Invalid coordinates"; + return false; + } + + Waypoint w(c); + w.setName(fields.at(0)); + if (ok) + w.setElevation(ele); + if (!desc.isEmpty()) + w.setDescription(desc); + + waypoints.append(w); + } + + _errorLine++; + } + + return true; +} diff --git a/src/data/gpsdumpparser.h b/src/data/gpsdumpparser.h new file mode 100644 index 00000000..f9ae1f80 --- /dev/null +++ b/src/data/gpsdumpparser.h @@ -0,0 +1,27 @@ +#ifndef GPSDUMPPARSER_H +#define GPSDUMPPARSER_H + +#include "parser.h" + +class GPSDumpParser : public Parser +{ +public: + GPSDumpParser() : _errorLine(0) {} + + bool parse(QFile *file, QList &tracks, QList &routes, + QList &polygons, QVector &waypoints); + QString errorString() const {return _errorString;} + int errorLine() const {return _errorLine;} + +private: + enum Type { + Unknown, + GEO, + UTM + }; + + int _errorLine; + QString _errorString; +}; + +#endif // GPSDUMPPARSER_H