Format basic GPX
This commit is contained in:
parent
80a054f116
commit
74af851687
6 changed files with 181 additions and 0 deletions
|
|
@ -4,8 +4,14 @@ dist/
|
|||
yarn.lock
|
||||
.idea
|
||||
.gitignore
|
||||
.eslintignore
|
||||
.prettierignore
|
||||
.tx/
|
||||
layers/
|
||||
locales/*.json
|
||||
resources/boundaries/
|
||||
*.sh
|
||||
profiles2/
|
||||
Dockerfile
|
||||
tests/**/*.json
|
||||
tests/**/*.gpx
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ var paths = {
|
|||
'js/LayersConfig.js',
|
||||
'js/router/BRouter.js',
|
||||
'js/util/*.js',
|
||||
'js/format/*.js',
|
||||
'js/plugin/*.js',
|
||||
'js/control/*.js',
|
||||
'js/index.js',
|
||||
|
|
|
|||
76
js/format/Gpx.js
Normal file
76
js/format/Gpx.js
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
BR.Gpx = {
|
||||
format: function (geoJson) {
|
||||
const gpx = togpx(geoJson, {
|
||||
featureDescription: function () {},
|
||||
});
|
||||
const statsComment = BR.Gpx._statsComment(geoJson);
|
||||
const xml = '<?xml version="1.0" encoding="UTF-8"?>' + statsComment + gpx;
|
||||
return BR.Gpx.pretty(xml, 1);
|
||||
},
|
||||
|
||||
// <!-- track-length = 319 filtered ascend = 2 plain-ascend = -1 cost=533 energy=.0kwh time=44s -->
|
||||
_statsComment: function (geoJson) {
|
||||
const props = geoJson.features?.[0].properties;
|
||||
if (!props) return '';
|
||||
|
||||
let comment = '<!--';
|
||||
comment += ' track-length = ' + props['track-length'];
|
||||
comment += ' filtered ascend = ' + props['filtered ascend'];
|
||||
comment += ' plain-ascend = ' + props['plain-ascend'];
|
||||
comment += ' cost=' + props['cost'];
|
||||
if (props['total-energy']) {
|
||||
// TODO 'wh'? (also for stats, see issue),
|
||||
// see brouter OsmTrack.getFormattedEnergy
|
||||
comment += ' energy=' + (props['total-energy'] / 3600000).toFixed(1) + 'kwh';
|
||||
}
|
||||
if (props['total-time']) {
|
||||
// TODO format, e.g. total-time=14833 -> time=4h 7m 13s
|
||||
// see brouter OsmTrack.getFormattedTime2
|
||||
comment += ' time=' + props['total-time'] + 's';
|
||||
}
|
||||
comment += ' -->';
|
||||
return comment;
|
||||
},
|
||||
|
||||
// modified version of
|
||||
// https://gist.github.com/sente/1083506#gistcomment-2254622
|
||||
// MIT License, Copyright (c) 2016 Stuart Powers, ES6 version by Jonathan Gruber
|
||||
pretty: function (xml, indentSize = 2) {
|
||||
const PADDING = ' '.repeat(indentSize);
|
||||
const newline = '\n';
|
||||
// break into lines, keep trkpt with subelement ele in single line
|
||||
const reg = /(>)(<)(?!ele|\/trkpt)(\/?)/g;
|
||||
let pad = 0;
|
||||
|
||||
xml = xml.replace('<metadata/>', '');
|
||||
xml = xml.replace(reg, `$1${newline}$2$3`);
|
||||
|
||||
let lines = xml.split(newline);
|
||||
lines = lines.map((node, index) => {
|
||||
let indent = 0;
|
||||
if (node.match(/.+<\/\w[^>]*>$/)) {
|
||||
indent = 0;
|
||||
} else if (node.match(/^<\/\w/) && pad > 0) {
|
||||
pad -= 1;
|
||||
} else if (node.match(/^<\w[^>]*[^\/]>.*$/)) {
|
||||
indent = 1;
|
||||
} else {
|
||||
indent = 0;
|
||||
}
|
||||
|
||||
pad += indent;
|
||||
|
||||
return PADDING.repeat(pad - indent) + node;
|
||||
});
|
||||
|
||||
for (const [i, line] of lines.entries()) {
|
||||
// break gpx attributes into separate lines
|
||||
if (line.includes('<gpx ')) {
|
||||
lines[i] = line.replace(/ ([a-z:]+=")/gi, ` ${newline}${PADDING}$1`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join(newline);
|
||||
},
|
||||
};
|
||||
38
tests/format/Gpx.test.js
Normal file
38
tests/format/Gpx.test.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
BR = {};
|
||||
togpx = require('togpx');
|
||||
require('../../js/format/Gpx.js');
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const geoJson = require('./data/track.json');
|
||||
const path = 'tests/format/data/';
|
||||
|
||||
// resolve intended/accepted differences before comparing
|
||||
function adoptGpx(gpx) {
|
||||
const creator = 'togpx';
|
||||
const name = 'Track';
|
||||
const newline = '\n';
|
||||
|
||||
gpx = gpx.replace('=.0', '=0.0');
|
||||
gpx = gpx.replace(/creator="[^"]*"/, `creator="${creator}"`);
|
||||
gpx = gpx.replace(`creator="${creator}" version="1.1"`, `version="1.1" \n creator="${creator}"`);
|
||||
gpx = gpx.replace(/<trk>\n <name>[^<]*<\/name>/, `<trk>\n <name>${name}</name>`);
|
||||
gpx = gpx
|
||||
.split(newline)
|
||||
.map((line) => line.replace(/lon="([^"]*)" lat="([^"]*)"/, 'lat="$2" lon="$1"'))
|
||||
.join(newline);
|
||||
gpx = gpx.replace(/0"><ele>/g, '"><ele>');
|
||||
gpx = gpx.replace('</gpx>\n', '</gpx>');
|
||||
|
||||
return gpx;
|
||||
}
|
||||
|
||||
function read(fileName) {
|
||||
return adoptGpx(fs.readFileSync(path + fileName, 'utf8'));
|
||||
}
|
||||
|
||||
test('simple track', () => {
|
||||
const brouterGpx = read('track.gpx');
|
||||
const gpx = BR.Gpx.format(geoJson);
|
||||
expect(gpx).toEqual(brouterGpx);
|
||||
});
|
||||
20
tests/format/data/track.gpx
Normal file
20
tests/format/data/track.gpx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- track-length = 319 filtered ascend = 2 plain-ascend = -1 cost=533 energy=.0kwh time=44s -->
|
||||
<gpx
|
||||
xmlns="http://www.topografix.com/GPX/1/1"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
|
||||
creator="BRouter-1.6.1" version="1.1">
|
||||
<trk>
|
||||
<name>Track</name>
|
||||
<trkseg>
|
||||
<trkpt lon="8.467714" lat="49.488115"><ele>101.5</ele></trkpt>
|
||||
<trkpt lon="8.468340" lat="49.488794"><ele>101.5</ele></trkpt>
|
||||
<trkpt lon="8.468586" lat="49.488698"><ele>101.5</ele></trkpt>
|
||||
<trkpt lon="8.468743" lat="49.488636"><ele>101.5</ele></trkpt>
|
||||
<trkpt lon="8.469161" lat="49.488473"><ele>101.75</ele></trkpt>
|
||||
<trkpt lon="8.469971" lat="49.488151"><ele>103.5</ele></trkpt>
|
||||
<trkpt lon="8.470610" lat="49.488842"><ele>99.75</ele></trkpt>
|
||||
</trkseg>
|
||||
</trk>
|
||||
</gpx>
|
||||
40
tests/format/data/track.json
Normal file
40
tests/format/data/track.json
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"creator": "BRouter-1.1",
|
||||
"name": "Track",
|
||||
"track-length": "319",
|
||||
"filtered ascend": "2",
|
||||
"plain-ascend": "-1",
|
||||
"total-time": "44",
|
||||
"total-energy": "4412",
|
||||
"cost": "533",
|
||||
"voicehints": [
|
||||
[1,5,0],
|
||||
[5,2,0]
|
||||
],
|
||||
"messages": [
|
||||
["Longitude", "Latitude", "Elevation", "Distance", "CostPerKm", "ElevCost", "TurnCost", "NodeCost", "InitialCost", "WayTags", "NodeTags"],
|
||||
["8468340", "49488794", "101", "89", "1000", "0", "0", "0", "0", "highway=residential surface=asphalt cycleway=lane oneway=yes lcn=yes smoothness=good route_bicycle_icn=yes route_bicycle_ncn=yes route_bicycle_rcn=yes", ""],
|
||||
["8470671", "49488909", "99", "230", "1150", "0", "180", "0", "0", "highway=residential surface=asphalt oneway=yes smoothness=good", ""]
|
||||
]
|
||||
},
|
||||
"geometry": {
|
||||
"type": "LineString",
|
||||
"coordinates": [
|
||||
[8.467714, 49.488115, 101.5],
|
||||
[8.468340, 49.488794, 101.5],
|
||||
[8.468586, 49.488698, 101.5],
|
||||
[8.468743, 49.488636, 101.5],
|
||||
[8.469161, 49.488473, 101.75],
|
||||
[8.469971, 49.488151, 103.5],
|
||||
[8.470610, 49.488842, 99.75]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue