Skip to content

Commit

Permalink
feat: Add parsing of GPX extensions speed, course, hAcc, vAcc (#18)
Browse files Browse the repository at this point in the history
* Add parsing of GPX extensions speed, course, hAcc, vAcc

Apple Watches track additional values that weren't being parsed
these are:

speed - speed in meters
course - bearing
hAcc - horizontal accuracy
vAcc - vertical accuracy

Add support for parsing and storing these values.

* Suggestions from PR review
  • Loading branch information
rustyconover authored and tmcw committed Dec 25, 2019
1 parent 29a035f commit 99301bd
Show file tree
Hide file tree
Showing 3 changed files with 640 additions and 61 deletions.
100 changes: 77 additions & 23 deletions lib/gpx.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { nodeVal } from "./shared";

const attributeNames = [
["speed", "speeds"],
["course", "courses"],
["hAcc", "hAccs"],
["vAcc", "vAccs"],
["heartRate", "heartRates"]
];

function getLineStyle(extensions) {
const style = {};
if (extensions) {
Expand Down Expand Up @@ -72,11 +80,28 @@ function coordPair(x) {
ll.push(e);
}
}
return {
const result = {
coordinates: ll,
time: time ? nodeVal(time) : null,
heartRate: heartRate ? parseFloat(nodeVal(heartRate)) : null
};

const extensions = get1(x, "extensions");
if (extensions !== null) {
attributeNames
.map(r => r[0])
.filter(n => n !== "heartrate")
.forEach(name => {
const raw = get1(extensions, name);
if (raw !== null) {
const v = parseFloat(nodeVal(raw));
if (!isNaN(v)) {
result[name] = v;
}
}
});
}
return result;
}
function getRoute(node) {
const line = getPoints(node, "rtept");
Expand All @@ -98,46 +123,70 @@ function getPoints(node, pointname) {
const line = [];
const times = [];
const l = pts.length;
let heartRates = undefined;
const extendedValues = {};
if (l < 2) return {}; // Invalid line in GeoJSON
for (let i = 0; i < l; i++) {
const c = coordPair(pts[i]);
line.push(c.coordinates);
if (c.time) times.push(c.time);
if (c.heartRate || heartRates) {
if (!heartRates) heartRates = Array(i).fill(null);
heartRates.push(c.heartRate || null);
}
attributeNames
.map(r => r[0])
.forEach(name => {
if (c[name] || extendedValues[name]) {
if (!extendedValues[name]) {
extendedValues[name] = Array(i).fill(null);
}
extendedValues[name].push(c[name] || null);
}
});
}
return {
const result = {
line: line,
times: times,
heartRates: heartRates || []
times: times
};
attributeNames.forEach(n => {
if (extendedValues[n[0]]) {
result[n[1]] = extendedValues[n[0]] || [];
}
});
return result;
}
function getTrack(node) {
const segments = node.getElementsByTagName("trkseg");
const track = [];
const times = [];
const heartRates = [];
const extendedValues = {};
let line;
for (let i = 0; i < segments.length; i++) {
line = getPoints(segments[i], "trkpt");
if (line) {
if (line.line) track.push(line.line);
if (line.times && line.times.length) times.push(line.times);
if (heartRates.length || (line.heartRates && line.heartRates.length)) {
if (!heartRates.length) {
for (let s = 0; s < i; s++) {
heartRates.push(Array(track[s].length).fill(null));

attributeNames
.map(r => r[1])
.forEach(name => {
if (
(extendedValues[name] && extendedValues[name].length) ||
(line[name] && line[name].length)
) {
if (!extendedValues[name]) {
extendedValues[name] = [];
}
if (!extendedValues[name].length) {
for (let s = 0; s < i; s++) {
extendedValues[name].push(Array(track[s].length).fill(null));
}
}
if (line[name] && line[name].length) {
extendedValues[name].push(line[name]);
} else {
extendedValues[name].push(
Array(line.line.length || 0).fill(null)
);
}
}
}
if (line.heartRates && line.heartRates.length) {
heartRates.push(line.heartRates);
} else {
heartRates.push(Array(line.line.length || 0).fill(null));
}
}
});
}
}
if (track.length === 0) return;
Expand All @@ -147,8 +196,13 @@ function getTrack(node) {
);
if (times.length)
properties.coordTimes = track.length === 1 ? times[0] : times;
if (heartRates.length)
properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
attributeNames.forEach(n => {
if (extendedValues[n[1]] && extendedValues[n[1]].length) {
properties[n[1]] =
track.length === 1 ? extendedValues[n[1]][0] : extendedValues[n[1]];
}
});

return {
type: "Feature",
properties: properties,
Expand Down
Loading

0 comments on commit 99301bd

Please sign in to comment.