mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-27 21:24:47 +01:00
Added support for SeeYou CUP files
This commit is contained in:
parent
ab6ea84255
commit
ecb82952f6
@ -181,7 +181,9 @@ HEADERS += src/common/config.h \
|
||||
src/GUI/limitedcombobox.h \
|
||||
src/GUI/pathtickitem.h \
|
||||
src/map/IMG/textitem.h \
|
||||
src/map/IMG/label.h
|
||||
src/map/IMG/label.h \
|
||||
src/data/csv.h \
|
||||
src/data/cupparser.h
|
||||
SOURCES += src/main.cpp \
|
||||
src/common/coordinates.cpp \
|
||||
src/common/rectc.cpp \
|
||||
@ -312,7 +314,9 @@ SOURCES += src/main.cpp \
|
||||
src/map/IMG/style.cpp \
|
||||
src/map/IMG/netfile.cpp \
|
||||
src/GUI/pathtickitem.cpp \
|
||||
src/map/IMG/textitem.cpp
|
||||
src/map/IMG/textitem.cpp \
|
||||
src/data/csv.cpp \
|
||||
src/data/cupparser.cpp
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
HEADERS += src/data/geojsonparser.h
|
||||
|
66
src/data/csv.cpp
Normal file
66
src/data/csv.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include "csv.h"
|
||||
|
||||
/*
|
||||
RFC 4180 parser with the following enchancements:
|
||||
- allows an arbitrary delimiter
|
||||
- allows LF line ends in addition to CRLF line ends
|
||||
*/
|
||||
|
||||
bool CSV::readEntry(QStringList &list)
|
||||
{
|
||||
int state = 0;
|
||||
char c;
|
||||
QByteArray field;
|
||||
|
||||
while (_device->getChar(&c)) {
|
||||
switch (state) {
|
||||
case 0:
|
||||
if (c == '\r')
|
||||
state = 3;
|
||||
else if (c == '\n') {
|
||||
list.append(field);
|
||||
_line++;
|
||||
return true;
|
||||
} else if (c == _delimiter) {
|
||||
list.append(field);
|
||||
field.clear();
|
||||
} else if (c == '"') {
|
||||
if (!field.isEmpty())
|
||||
return false;
|
||||
state = 1;
|
||||
} else
|
||||
field.append(c);
|
||||
break;
|
||||
case 1:
|
||||
if (c == '"')
|
||||
state = 2;
|
||||
else {
|
||||
field.append(c);
|
||||
if (c == '\n')
|
||||
_line++;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (c == '"') {
|
||||
field.append('"');
|
||||
state = 1;
|
||||
} else if (c == _delimiter || c == '\r' || c == '\n') {
|
||||
_device->ungetChar(c);
|
||||
state = 0;
|
||||
} else
|
||||
return false;
|
||||
break;
|
||||
case 3:
|
||||
if (c == '\n') {
|
||||
_device->ungetChar(c);
|
||||
state = 0;
|
||||
} else
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list.append(field);
|
||||
|
||||
return (state == 0);
|
||||
}
|
22
src/data/csv.h
Normal file
22
src/data/csv.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef CSV_H
|
||||
#define CSV_H
|
||||
|
||||
#include <QIODevice>
|
||||
|
||||
class CSV
|
||||
{
|
||||
public:
|
||||
CSV(QIODevice *device, char delimiter = ',')
|
||||
: _device(device), _delimiter(delimiter), _line(1) {}
|
||||
|
||||
bool readEntry(QStringList &list);
|
||||
bool atEnd() const {return _device->atEnd();}
|
||||
int line() const {return _line;}
|
||||
|
||||
private:
|
||||
QIODevice *_device;
|
||||
char _delimiter;
|
||||
int _line;
|
||||
};
|
||||
|
||||
#endif // CSV_H
|
@ -1,3 +1,4 @@
|
||||
#include "csv.h"
|
||||
#include "csvparser.h"
|
||||
|
||||
bool CSVParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
@ -7,42 +8,38 @@ bool CSVParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
Q_UNUSED(tracks);
|
||||
Q_UNUSED(routes);
|
||||
Q_UNUSED(polygons);
|
||||
bool res;
|
||||
CSV csv(file);
|
||||
QStringList entry;
|
||||
bool ok;
|
||||
|
||||
_errorLine = 1;
|
||||
_errorString.clear();
|
||||
|
||||
while (!file->atEnd()) {
|
||||
QByteArray line = file->readLine();
|
||||
QList<QByteArray> list = line.split(',');
|
||||
if (list.size() < 3) {
|
||||
while (!csv.atEnd()) {
|
||||
if (!csv.readEntry(entry) || entry.size() < 3) {
|
||||
_errorString = "Parse error";
|
||||
_errorLine = csv.line();
|
||||
return false;
|
||||
}
|
||||
|
||||
qreal lon = list[0].trimmed().toDouble(&res);
|
||||
if (!res || (lon < -180.0 || lon > 180.0)) {
|
||||
double lon = entry.at(0).trimmed().toDouble(&ok);
|
||||
if (!ok || (lon < -180.0 || lon > 180.0)) {
|
||||
_errorString = "Invalid longitude";
|
||||
_errorLine = csv.line();
|
||||
return false;
|
||||
}
|
||||
qreal lat = list[1].trimmed().toDouble(&res);
|
||||
if (!res || (lat < -90.0 || lat > 90.0)) {
|
||||
double lat = entry.at(1).trimmed().toDouble(&ok);
|
||||
if (!ok || (lat < -90.0 || lat > 90.0)) {
|
||||
_errorString = "Invalid latitude";
|
||||
_errorLine = csv.line();
|
||||
return false;
|
||||
}
|
||||
Waypoint wp(Coordinates(lon, lat));
|
||||
|
||||
QByteArray ba = list[2].trimmed();
|
||||
QString name = QString::fromUtf8(ba.data(), ba.size());
|
||||
wp.setName(name);
|
||||
|
||||
if (list.size() > 3) {
|
||||
ba = list[3].trimmed();
|
||||
wp.setDescription(QString::fromUtf8(ba.data(), ba.size()));
|
||||
}
|
||||
wp.setName(entry.at(2).trimmed());
|
||||
if (entry.size() > 3)
|
||||
wp.setDescription(entry.at(3).trimmed());
|
||||
|
||||
waypoints.append(wp);
|
||||
_errorLine++;
|
||||
|
||||
entry.clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
163
src/data/cupparser.cpp
Normal file
163
src/data/cupparser.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
#include <cmath>
|
||||
#include "csv.h"
|
||||
#include "cupparser.h"
|
||||
|
||||
|
||||
enum SegmentType {
|
||||
Header, Waypoints, Tasks
|
||||
};
|
||||
|
||||
static double latitude(const QString &str)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
if (str.length() != 9)
|
||||
return NAN;
|
||||
int deg = str.left(2).toInt(&ok);
|
||||
if (!ok || deg > 90)
|
||||
return NAN;
|
||||
double min = str.mid(2, 6).toDouble(&ok);
|
||||
if (!ok || min > 60)
|
||||
return NAN;
|
||||
|
||||
double dd = deg + min/60.0;
|
||||
return (str.right(1) == 'S') ? -dd : dd;
|
||||
}
|
||||
|
||||
static double longitude(const QString &str)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
if (str.length() != 10)
|
||||
return NAN;
|
||||
int deg = str.left(3).toInt(&ok);
|
||||
if (!ok || deg > 180)
|
||||
return NAN;
|
||||
double min = str.mid(3, 6).toDouble(&ok);
|
||||
if (!ok || min > 60)
|
||||
return NAN;
|
||||
|
||||
double dd = deg + min/60.0;
|
||||
return (str.right(1) == 'W') ? -dd : dd;
|
||||
}
|
||||
|
||||
static double elevation(const QString &str)
|
||||
{
|
||||
bool ok;
|
||||
double ele;
|
||||
|
||||
if (str.right(2) == "ft")
|
||||
ele = str.left(str.length() - 2).toDouble(&ok) * 0.3048;
|
||||
else if (str.right(1) == "m")
|
||||
ele = str.left(str.length() - 1).toDouble(&ok);
|
||||
else
|
||||
return NAN;
|
||||
|
||||
return ok ? ele : NAN;
|
||||
}
|
||||
|
||||
|
||||
bool CUPParser::waypoint(const QStringList &entry, QVector<Waypoint> &waypoints,
|
||||
QMap<QString, Coordinates> &turnpoints)
|
||||
{
|
||||
if (entry.size() < 11) {
|
||||
_errorString = "Invalid number of fields";
|
||||
return false;
|
||||
}
|
||||
|
||||
double lon = longitude(entry.at(4));
|
||||
if (std::isnan(lon)) {
|
||||
_errorString = "Invalid longitude";
|
||||
return false;
|
||||
}
|
||||
double lat = latitude(entry.at(3));
|
||||
if (std::isnan(lat)) {
|
||||
_errorString = "Invalid latitude";
|
||||
return false;
|
||||
}
|
||||
|
||||
Waypoint wp(Coordinates(lon, lat));
|
||||
wp.setName(entry.at(0));
|
||||
wp.setDescription(entry.at(10));
|
||||
wp.setElevation(elevation(entry.at(5)));
|
||||
waypoints.append(wp);
|
||||
|
||||
turnpoints.insert(wp.name(), wp.coordinates());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CUPParser::task(const QStringList &entry, QList<RouteData> &routes,
|
||||
const QMap<QString, Coordinates> &turnpoints)
|
||||
{
|
||||
if (entry.size() < 2) {
|
||||
_errorString = "Invalid number of fields";
|
||||
return false;
|
||||
}
|
||||
|
||||
RouteData r;
|
||||
r.setName(entry.at(0));
|
||||
for (int i = 1; i < entry.size(); i++) {
|
||||
if (!turnpoints.contains(entry.at(i))) {
|
||||
_errorString = entry.at(i) + ": unknown turnpoint";
|
||||
return false;
|
||||
}
|
||||
|
||||
Waypoint w(turnpoints[entry.at(i)]);
|
||||
w.setName(entry.at(i));
|
||||
r.append(w);
|
||||
}
|
||||
|
||||
routes.append(r);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CUPParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
QList<RouteData> &routes, QList<Area> &polygons,
|
||||
QVector<Waypoint> &waypoints)
|
||||
{
|
||||
Q_UNUSED(tracks);
|
||||
Q_UNUSED(polygons);
|
||||
CSV csv(file);
|
||||
SegmentType st = Header;
|
||||
QStringList entry;
|
||||
QMap<QString, Coordinates> turnpoints;
|
||||
|
||||
|
||||
while (!csv.atEnd()) {
|
||||
if (!csv.readEntry(entry)) {
|
||||
_errorString = "CSV parse error";
|
||||
_errorLine = csv.line();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (st == Header) {
|
||||
st = Waypoints;
|
||||
if (entry.size() >= 11 && entry.at(3) == "lat"
|
||||
&& entry.at(4) == "lon") {
|
||||
entry.clear();
|
||||
continue;
|
||||
}
|
||||
} else if (st == Waypoints && entry.size() == 1
|
||||
&& entry.at(0) == "-----Related Tasks-----") {
|
||||
st = Tasks;
|
||||
entry.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (st == Waypoints) {
|
||||
if (!waypoint(entry, waypoints, turnpoints))
|
||||
return false;
|
||||
} else if (st == Tasks) {
|
||||
if (entry.at(0) != "Options" && entry.at(0) != "ObsZone"
|
||||
&& !task(entry, routes, turnpoints))
|
||||
return false;
|
||||
}
|
||||
|
||||
entry.clear();
|
||||
_errorLine = csv.line();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
26
src/data/cupparser.h
Normal file
26
src/data/cupparser.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef CUPPARSER_H
|
||||
#define CUPPARSER_H
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
class CUPParser : public Parser
|
||||
{
|
||||
public:
|
||||
CUPParser() : _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:
|
||||
bool waypoint(const QStringList &entry, QVector<Waypoint> &waypoints,
|
||||
QMap<QString, Coordinates> &turnpoints);
|
||||
bool task(const QStringList &entry, QList<RouteData> &routes,
|
||||
const QMap<QString, Coordinates> &turnpoints);
|
||||
|
||||
QString _errorString;
|
||||
int _errorLine;
|
||||
};
|
||||
|
||||
#endif // CUPPARSER_H
|
@ -17,6 +17,7 @@
|
||||
#include "geojsonparser.h"
|
||||
#endif // ENABLE_GEOJSON
|
||||
#include "exifparser.h"
|
||||
#include "cupparser.h"
|
||||
#include "dem.h"
|
||||
#include "data.h"
|
||||
|
||||
@ -37,6 +38,7 @@ static SLFParser slf;
|
||||
static GeoJSONParser geojson;
|
||||
#endif // ENABLE_GEOJSON
|
||||
static EXIFParser exif;
|
||||
static CUPParser cup;
|
||||
|
||||
static QHash<QString, Parser*> parsers()
|
||||
{
|
||||
@ -60,6 +62,7 @@ static QHash<QString, Parser*> parsers()
|
||||
#endif // ENABLE_GEOJSON
|
||||
hash.insert("jpeg", &exif);
|
||||
hash.insert("jpg", &exif);
|
||||
hash.insert("cup", &cup);
|
||||
|
||||
return hash;
|
||||
}
|
||||
@ -147,6 +150,7 @@ QString Data::formats()
|
||||
return
|
||||
qApp->translate("Data", "Supported files") + " (" + supported + ");;"
|
||||
+ qApp->translate("Data", "CSV files") + " (*.csv);;"
|
||||
+ qApp->translate("Data", "CUP files") + " (*.cup);;"
|
||||
+ qApp->translate("Data", "FIT files") + " (*.fit);;"
|
||||
#ifdef ENABLE_GEOJSON
|
||||
+ qApp->translate("Data", "GeoJSON files") + " (*.geojson *.json);;"
|
||||
|
Loading…
Reference in New Issue
Block a user