Skip to content

Instantly share code, notes, and snippets.

@hleinone
Created April 25, 2017 06:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hleinone/7bd459b84c15ca5b6e832d0ebb20bfd7 to your computer and use it in GitHub Desktop.
Save hleinone/7bd459b84c15ca5b6e832d0ebb20bfd7 to your computer and use it in GitHub Desktop.
Normalizes GPX file by replacing track points with exactly same coordinate with interpolated values, removing leaps with inhuman speed.
var fs = require("fs");
var xml2js = require("xml2js");
var gpx = process.argv[2];
// https://gist.github.com/wteuber/6241786
Math.fmod = function(a, b) {
return Number((a - (Math.floor(a / b) * b)).toPrecision(8));
};
function clockwiseDiff(from, to) {
return normalizeLongitude(Math.fmod(to - from - 360, 360) + 360);
};
function normalizeLongitude(lon) {
return Math.fmod(Math.fmod(lon + 180, 360) + 360, 360) - 180;
};
fs.exists(gpx, function(exists) {
if (!exists) {
console.error("File " + gpx + " not found");
return;
}
fs.readFile(gpx, "utf8", function(error, data) {
if (error) {
console.error("Reading file " + gpx + " failed: " + error);
return;
}
xml2js.parseString(data, function(error, result) {
if (error) {
console.error("Parsing GPX file " + gpx + " failed: " + error);
return;
}
var trkseg = result.gpx.trk[0].trkseg[0];
var trkpts = trkseg.trkpt;
var trkptsGroupedByCoordinate = trkpts.reduce(function(res, elem, idx, src) {
var last = res[res.length - 1];
if (!last || last[last.length - 1]["$"].lat != elem["$"].lat || last[last.length - 1]["$"].lon != elem["$"].lon) {
res.push([elem]);
} else {
last.push(elem);
}
return res;
}, []);
var trkptsInterpolated = trkptsGroupedByCoordinate.reduce(function(res, elem, idx, src) {
if (elem.length == 1) {
res.push(elem[0]);
} else {
if (idx < src.length - 1) {
var from = elem[0];
var to = src[idx + 1][0];
var fromT = new Date(from.time[0]).getTime();
var toT = new Date(to.time[0]).getTime();
var tDiff = toT - fromT;
var latDiff = new Number(to["$"].lat) - new Number(from["$"].lat);
var lonDiff = clockwiseDiff(new Number(from["$"].lon), new Number(to["$"].lon));
var eleDiff = new Number(to.ele[0]) - new Number(from.ele[0]);
elem.forEach(function(item, index) {
if (index == 0) {
res.push(item);
} else {
var t = new Date(item.time[0]).getTime();
var factor = (t - fromT) / tDiff;
// Interpolate latitude
item["$"].lat = new Number(from["$"].lat) + (factor * latDiff);
// Interpolate longitude
item["$"].lon = normalizeLongitude(new Number(from["$"].lon) + (factor * lonDiff));
// Interpolate elevation
item.ele[0] = new Number(from.ele[0]) + (factor * eleDiff);
res.push(item);
}
});
} else {
elem.forEach(function(item) {
res.push(item);
});
}
}
return res;
}, []);
result.gpx.trk[0].trkseg[0].trkpt = trkptsInterpolated;
var builder = new xml2js.Builder();
var xml = builder.buildObject(result);
console.log(xml);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment