mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-28 05:34:47 +01:00
Added support for FIT course points
This commit is contained in:
parent
ee3d43e249
commit
6ee3a8ea8d
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#define RECORD_MESSAGE 20
|
#define RECORD_MESSAGE 20
|
||||||
#define EVENT_MESSAGE 21
|
#define EVENT_MESSAGE 21
|
||||||
|
#define COURSE_POINT 32
|
||||||
#define TIMESTAMP_FIELD 253
|
#define TIMESTAMP_FIELD 253
|
||||||
|
|
||||||
class Event {
|
class Event {
|
||||||
@ -48,10 +49,12 @@ public:
|
|||||||
|
|
||||||
class FITParser::CTX {
|
class FITParser::CTX {
|
||||||
public:
|
public:
|
||||||
CTX(QFile *file) : file(file), len(0), endian(0), timestamp(0),
|
CTX(QFile *file, QVector<Waypoint> &waypoints)
|
||||||
|
: file(file), waypoints(waypoints), len(0), endian(0), timestamp(0),
|
||||||
lastWrite(0), ratio(NAN) {}
|
lastWrite(0), ratio(NAN) {}
|
||||||
|
|
||||||
QFile *file;
|
QFile *file;
|
||||||
|
QVector<Waypoint> &waypoints;
|
||||||
quint32 len;
|
quint32 len;
|
||||||
quint8 endian;
|
quint8 endian;
|
||||||
quint32 timestamp, lastWrite;
|
quint32 timestamp, lastWrite;
|
||||||
@ -61,6 +64,41 @@ public:
|
|||||||
SegmentData segment;
|
SegmentData segment;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static QMap<int, QString> coursePointDescInit()
|
||||||
|
{
|
||||||
|
QMap<int, QString> map;
|
||||||
|
|
||||||
|
map.insert(1, "Summit");
|
||||||
|
map.insert(2, "Valley");
|
||||||
|
map.insert(3, "Water");
|
||||||
|
map.insert(4, "Food");
|
||||||
|
map.insert(5, "Danger");
|
||||||
|
map.insert(6, "Left");
|
||||||
|
map.insert(7, "Right");
|
||||||
|
map.insert(8, "Straight");
|
||||||
|
map.insert(9, "First aid");
|
||||||
|
map.insert(10, "Fourth category");
|
||||||
|
map.insert(11, "Third category");
|
||||||
|
map.insert(12, "Second category");
|
||||||
|
map.insert(13, "First category");
|
||||||
|
map.insert(14, "Hors category");
|
||||||
|
map.insert(15, "Sprint");
|
||||||
|
map.insert(16, "Left fork");
|
||||||
|
map.insert(17, "Right fork");
|
||||||
|
map.insert(18, "Middle fork");
|
||||||
|
map.insert(19, "Slight left");
|
||||||
|
map.insert(20, "Sharp left");
|
||||||
|
map.insert(21, "Slight right");
|
||||||
|
map.insert(22, "Sharp right");
|
||||||
|
map.insert(23, "U-Turn");
|
||||||
|
map.insert(24, "Segment start");
|
||||||
|
map.insert(25, "Segment end");
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QMap<int, QString> coursePointDesc = coursePointDescInit();
|
||||||
|
|
||||||
|
|
||||||
bool FITParser::readData(QFile *file, char *data, size_t size)
|
bool FITParser::readData(QFile *file, char *data, size_t size)
|
||||||
{
|
{
|
||||||
@ -167,10 +205,11 @@ bool FITParser::parseDefinitionMessage(CTX &ctx, quint8 header)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FITParser::readField(CTX &ctx, Field *field, quint32 &val)
|
bool FITParser::readField(CTX &ctx, Field *field, QVariant &val)
|
||||||
{
|
{
|
||||||
quint8 v8 = (quint8)-1;
|
quint8 v8 = (quint8)-1;
|
||||||
quint16 v16 = (quint16)-1;
|
quint16 v16 = (quint16)-1;
|
||||||
|
quint32 v32 = (quint32)-1;
|
||||||
bool ret;
|
bool ret;
|
||||||
|
|
||||||
val = (quint32)-1;
|
val = (quint32)-1;
|
||||||
@ -185,6 +224,12 @@ bool FITParser::readField(CTX &ctx, Field *field, quint32 &val)
|
|||||||
} else
|
} else
|
||||||
ret = skipValue(ctx, field->size);
|
ret = skipValue(ctx, field->size);
|
||||||
break;
|
break;
|
||||||
|
case 7: // UTF8 nul terminated string
|
||||||
|
{QByteArray ba(ctx.file->read(field->size));
|
||||||
|
ctx.len -= field->size;
|
||||||
|
ret = (ba.size() == field->size);
|
||||||
|
val = ret ? ba : QString();}
|
||||||
|
break;
|
||||||
case 0x83: // sint16
|
case 0x83: // sint16
|
||||||
case 0x84: // uint16
|
case 0x84: // uint16
|
||||||
if (field->size == 2) {
|
if (field->size == 2) {
|
||||||
@ -195,9 +240,10 @@ bool FITParser::readField(CTX &ctx, Field *field, quint32 &val)
|
|||||||
break;
|
break;
|
||||||
case 0x85: // sint32
|
case 0x85: // sint32
|
||||||
case 0x86: // uint32
|
case 0x86: // uint32
|
||||||
if (field->size == 4)
|
if (field->size == 4) {
|
||||||
ret = readValue(ctx, val);
|
ret = readValue(ctx, v32);
|
||||||
else
|
val = v32;
|
||||||
|
} else
|
||||||
ret = skipValue(ctx, field->size);
|
ret = skipValue(ctx, field->size);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -212,7 +258,8 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
|||||||
{
|
{
|
||||||
Field *field;
|
Field *field;
|
||||||
Event event;
|
Event event;
|
||||||
quint32 val;
|
QVariant val;
|
||||||
|
Waypoint w;
|
||||||
|
|
||||||
|
|
||||||
if (!def->fields && !def->devFields) {
|
if (!def->fields && !def->devFields) {
|
||||||
@ -228,50 +275,50 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (field->id == TIMESTAMP_FIELD)
|
if (field->id == TIMESTAMP_FIELD)
|
||||||
ctx.timestamp = val;
|
ctx.timestamp = val.toUInt();
|
||||||
else if (def->globalId == RECORD_MESSAGE) {
|
else if (def->globalId == RECORD_MESSAGE) {
|
||||||
switch (field->id) {
|
switch (field->id) {
|
||||||
case 0:
|
case 0:
|
||||||
if (val != 0x7fffffff)
|
if (val != 0x7fffffffU)
|
||||||
ctx.trackpoint.rcoordinates().setLat(
|
ctx.trackpoint.rcoordinates().setLat(
|
||||||
((qint32)val / (double)0x7fffffff) * 180);
|
((qint32)val.toUInt() / (double)0x7fffffff) * 180);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (val != 0x7fffffff)
|
if (val != 0x7fffffffU)
|
||||||
ctx.trackpoint.rcoordinates().setLon(
|
ctx.trackpoint.rcoordinates().setLon(
|
||||||
((qint32)val / (double)0x7fffffff) * 180);
|
((qint32)val.toUInt() / (double)0x7fffffff) * 180);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (val != 0xffff)
|
if (val != 0xffffU)
|
||||||
ctx.trackpoint.setElevation((val / 5.0) - 500);
|
ctx.trackpoint.setElevation((val.toUInt() / 5.0) - 500);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (val != 0xff)
|
if (val != 0xffU)
|
||||||
ctx.trackpoint.setHeartRate(val);
|
ctx.trackpoint.setHeartRate(val.toUInt());
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
if (val != 0xff)
|
if (val != 0xffU)
|
||||||
ctx.trackpoint.setCadence(val);
|
ctx.trackpoint.setCadence(val.toUInt());
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
if (val != 0xffff)
|
if (val != 0xffffU)
|
||||||
ctx.trackpoint.setSpeed(val / 1000.0f);
|
ctx.trackpoint.setSpeed(val.toUInt() / 1000.0f);
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
if (val != 0xffff)
|
if (val != 0xffffU)
|
||||||
ctx.trackpoint.setPower(val);
|
ctx.trackpoint.setPower(val.toUInt());
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
if (val != 0x7f)
|
if (val != 0x7fU)
|
||||||
ctx.trackpoint.setTemperature((qint8)val);
|
ctx.trackpoint.setTemperature((qint8)val.toUInt());
|
||||||
break;
|
break;
|
||||||
case 73:
|
case 73:
|
||||||
if (val != 0xffffffff)
|
if (val != 0xffffffffU)
|
||||||
ctx.trackpoint.setSpeed(val / 1000.0f);
|
ctx.trackpoint.setSpeed(val.toUInt() / 1000.0f);
|
||||||
break;
|
break;
|
||||||
case 78:
|
case 78:
|
||||||
if (val != 0xffffffff)
|
if (val != 0xffffffffU)
|
||||||
ctx.trackpoint.setElevation((val / 5.0) - 500);
|
ctx.trackpoint.setElevation((val.toUInt() / 5.0) - 500);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -280,13 +327,36 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
|||||||
} else if (def->globalId == EVENT_MESSAGE) {
|
} else if (def->globalId == EVENT_MESSAGE) {
|
||||||
switch (field->id) {
|
switch (field->id) {
|
||||||
case 0:
|
case 0:
|
||||||
event.id = val;
|
event.id = val.toUInt();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
event.type = val;
|
event.type = val.toUInt();
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
event.data = val;
|
event.data = val.toUInt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (def->globalId == COURSE_POINT) {
|
||||||
|
switch (field->id) {
|
||||||
|
case 1:
|
||||||
|
w.setTimestamp(QDateTime::fromTime_t(val.toUInt()
|
||||||
|
+ 631065600));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (val != 0x7fffffff)
|
||||||
|
w.rcoordinates().setLat(
|
||||||
|
((qint32)val.toUInt() / (double)0x7fffffff) * 180);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (val != 0x7fffffff)
|
||||||
|
w.rcoordinates().setLon(
|
||||||
|
((qint32)val.toUInt() / (double)0x7fffffff) * 180);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
w.setDescription(coursePointDesc.value(val.toUInt()));
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
w.setName(val.toString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -315,7 +385,9 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
|||||||
ctx.trackpoint = Trackpoint();
|
ctx.trackpoint = Trackpoint();
|
||||||
ctx.lastWrite = ctx.timestamp;
|
ctx.lastWrite = ctx.timestamp;
|
||||||
}
|
}
|
||||||
}
|
} else if (def->globalId == COURSE_POINT)
|
||||||
|
if (w.coordinates().isValid())
|
||||||
|
ctx.waypoints.append(w);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -381,9 +453,8 @@ bool FITParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
QList<Area> &polygons, QVector<Waypoint> &waypoints)
|
QList<Area> &polygons, QVector<Waypoint> &waypoints)
|
||||||
{
|
{
|
||||||
Q_UNUSED(routes);
|
Q_UNUSED(routes);
|
||||||
Q_UNUSED(waypoints);
|
|
||||||
Q_UNUSED(polygons);
|
Q_UNUSED(polygons);
|
||||||
CTX ctx(file);
|
CTX ctx(file, waypoints);
|
||||||
|
|
||||||
|
|
||||||
if (!parseHeader(ctx))
|
if (!parseHeader(ctx))
|
||||||
|
@ -21,7 +21,7 @@ private:
|
|||||||
bool readData(QFile *file, char *data, size_t size);
|
bool readData(QFile *file, char *data, size_t size);
|
||||||
template<class T> bool readValue(CTX &ctx, T &val);
|
template<class T> bool readValue(CTX &ctx, T &val);
|
||||||
bool skipValue(CTX &ctx, quint8 size);
|
bool skipValue(CTX &ctx, quint8 size);
|
||||||
bool readField(CTX &ctx, Field *field, quint32 &val);
|
bool readField(CTX &ctx, Field *field, QVariant &val);
|
||||||
|
|
||||||
bool parseHeader(CTX &ctx);
|
bool parseHeader(CTX &ctx);
|
||||||
bool parseRecord(CTX &ctx);
|
bool parseRecord(CTX &ctx);
|
||||||
|
@ -19,6 +19,7 @@ public:
|
|||||||
: _coordinates(coordinates), _elevation(NAN) {}
|
: _coordinates(coordinates), _elevation(NAN) {}
|
||||||
|
|
||||||
const Coordinates &coordinates() const {return _coordinates;}
|
const Coordinates &coordinates() const {return _coordinates;}
|
||||||
|
Coordinates &rcoordinates() {return _coordinates;}
|
||||||
const QString &name() const {return _name;}
|
const QString &name() const {return _name;}
|
||||||
const QString &description() const {return _description;}
|
const QString &description() const {return _description;}
|
||||||
const QString &comment() const {return _comment;}
|
const QString &comment() const {return _comment;}
|
||||||
|
Loading…
Reference in New Issue
Block a user