Format basic voice hint
Use togpx fork for now (outdated), see PR: https://github.com/tyrasd/togpx/pull/11
This commit is contained in:
parent
74af851687
commit
a9d27b4674
6 changed files with 169 additions and 13 deletions
|
|
@ -1,11 +1,37 @@
|
||||||
BR.Gpx = {
|
BR.Gpx = {
|
||||||
format: function (geoJson) {
|
format: function (geoJson, turnInstructionMode = 0) {
|
||||||
const gpx = togpx(geoJson, {
|
if (!geoJson) return '';
|
||||||
|
|
||||||
|
if (turnInstructionMode > 0) {
|
||||||
|
BR.Gpx._addVoiceHints(geoJson, turnInstructionMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
let gpx = togpx(geoJson, {
|
||||||
|
featureTitle: function () {},
|
||||||
featureDescription: function () {},
|
featureDescription: function () {},
|
||||||
|
transform: {
|
||||||
|
trk: function (trk, feature, coordsList) {
|
||||||
|
return {
|
||||||
|
name: feature.properties.name,
|
||||||
|
trkseg: trk.trkseg,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
wpt: function (wpt, feature, coord, index) {
|
||||||
|
return Object.assign(wpt, feature.properties);
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const statsComment = BR.Gpx._statsComment(geoJson);
|
const statsComment = BR.Gpx._statsComment(geoJson);
|
||||||
const xml = '<?xml version="1.0" encoding="UTF-8"?>' + statsComment + gpx;
|
gpx = '<?xml version="1.0" encoding="UTF-8"?>' + statsComment + gpx;
|
||||||
return BR.Gpx.pretty(xml, 1);
|
gpx = BR.Gpx.pretty(gpx);
|
||||||
|
return gpx;
|
||||||
|
},
|
||||||
|
|
||||||
|
_addVoiceHints: function (geoJson, turnInstructionMode) {
|
||||||
|
if (!geoJson.features) return;
|
||||||
|
|
||||||
|
const voiceHints = BR.voiceHints(geoJson);
|
||||||
|
voiceHints.add(turnInstructionMode);
|
||||||
},
|
},
|
||||||
|
|
||||||
// <!-- track-length = 319 filtered ascend = 2 plain-ascend = -1 cost=533 energy=.0kwh time=44s -->
|
// <!-- track-length = 319 filtered ascend = 2 plain-ascend = -1 cost=533 energy=.0kwh time=44s -->
|
||||||
|
|
@ -35,9 +61,13 @@ BR.Gpx = {
|
||||||
// modified version of
|
// modified version of
|
||||||
// https://gist.github.com/sente/1083506#gistcomment-2254622
|
// https://gist.github.com/sente/1083506#gistcomment-2254622
|
||||||
// MIT License, Copyright (c) 2016 Stuart Powers, ES6 version by Jonathan Gruber
|
// MIT License, Copyright (c) 2016 Stuart Powers, ES6 version by Jonathan Gruber
|
||||||
pretty: function (xml, indentSize = 2) {
|
pretty: function (xml, indentSize = 1) {
|
||||||
const PADDING = ' '.repeat(indentSize);
|
const PADDING = ' '.repeat(indentSize);
|
||||||
const newline = '\n';
|
const newline = '\n';
|
||||||
|
|
||||||
|
// Remove all the newlines and then remove all the spaces between tags
|
||||||
|
xml = xml.replace(/\s*(\r\n|\n|\r)\s*/gm, ' ').replace(/>\s+</g, '><');
|
||||||
|
|
||||||
// break into lines, keep trkpt with subelement ele in single line
|
// break into lines, keep trkpt with subelement ele in single line
|
||||||
const reg = /(>)(<)(?!ele|\/trkpt)(\/?)/g;
|
const reg = /(>)(<)(?!ele|\/trkpt)(\/?)/g;
|
||||||
let pad = 0;
|
let pad = 0;
|
||||||
|
|
|
||||||
94
js/format/VoiceHints.js
Normal file
94
js/format/VoiceHints.js
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
(function () {
|
||||||
|
class Command {
|
||||||
|
constructor(name, locus, orux, symbol, message) {
|
||||||
|
this.name = name;
|
||||||
|
this.locus = locus;
|
||||||
|
this.orux = orux;
|
||||||
|
this.symbol = symbol;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RoundaboutCommand {
|
||||||
|
constructor(command, exitNumber) {
|
||||||
|
this.name = command.name + exitNumber;
|
||||||
|
this.locus = command.locus + exitNumber;
|
||||||
|
this.orux = command.orux + exitNumber;
|
||||||
|
this.symbol = command.symbol + exitNumber;
|
||||||
|
this.message = command.message + exitNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RoundaboutLeftCommand {
|
||||||
|
constructor(command, exitNumber) {
|
||||||
|
this.name = command.name + -exitNumber;
|
||||||
|
this.locus = command.locus + -exitNumber;
|
||||||
|
this.orux = command.orux + exitNumber;
|
||||||
|
this.symbol = command.symbol + -exitNumber;
|
||||||
|
this.message = command.message + -exitNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BR.VoiceHints = L.Class.extend({
|
||||||
|
statics: {
|
||||||
|
commands: (function () {
|
||||||
|
return {
|
||||||
|
1: new Command('C', 1, 1002, 'Straight', 'straight'),
|
||||||
|
2: new Command('TL', 4, 1000, 'Left', 'left'),
|
||||||
|
3: new Command('TSLL', 3, 1017, 'TSLL', 'slight left'),
|
||||||
|
4: new Command('TSHL', 5, 1019, 'TSHL', 'sharp left'),
|
||||||
|
5: new Command('TR', 7, 1001, 'Right', 'right'),
|
||||||
|
6: new Command('TSLR', 6, 1016, 'TSLR', 'slight right'),
|
||||||
|
7: new Command('TSHR', 8, 1018, 'TSHR', 'sharp right'),
|
||||||
|
8: new Command('KL', 9, 1015, 'TSLL', 'keep left'),
|
||||||
|
9: new Command('KR', 10, 1014, 'TSLR', 'keep right'),
|
||||||
|
10: new Command('TU', 13, 1003, 'TU', 'u-turn'),
|
||||||
|
11: new Command('TRU', 14, 1003, 'TU', 'u-turn'), // Right U-turn
|
||||||
|
12: new Command('OFFR'), // Off route
|
||||||
|
13: new Command('RNDB', 26, 1008, 'RNDB', 'Take exit '), // Roundabout
|
||||||
|
14: new Command('RNLB', 26, 1008, 'RNLB', 'Take exit '), // Roundabout left
|
||||||
|
};
|
||||||
|
})(),
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function (geoJson) {
|
||||||
|
this.geoJson = geoJson;
|
||||||
|
|
||||||
|
for (const feature of geoJson.features) {
|
||||||
|
let voicehints = feature?.properties.voicehints;
|
||||||
|
if (voicehints) {
|
||||||
|
this.voicehints = voicehints;
|
||||||
|
this.track = feature;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
add: function (turnInstructionMode) {
|
||||||
|
if (!this.voicehints) return;
|
||||||
|
|
||||||
|
for (const hint of this.voicehints) {
|
||||||
|
const [indexInTrack, commandId, exitNumber] = hint;
|
||||||
|
const coord = this.track.geometry.coordinates[indexInTrack];
|
||||||
|
const cmd = this.getCommand(commandId, exitNumber);
|
||||||
|
const properties = { name: cmd.message, sym: cmd.symbol.toLowerCase(), type: cmd.symbol };
|
||||||
|
|
||||||
|
this.geoJson.features.push(turf.point(coord.slice(0, 2), properties));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getCommand: function (id, exitNumber) {
|
||||||
|
let command = BR.VoiceHints.commands[id];
|
||||||
|
if (id === 13) {
|
||||||
|
command = new RoundaboutCommand(command, exitNumber);
|
||||||
|
} else if (id === 14) {
|
||||||
|
command = new RoundaboutLeftCommand(command, exitNumber);
|
||||||
|
}
|
||||||
|
return command;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
BR.voiceHints = function (geoJson) {
|
||||||
|
return new BR.VoiceHints(geoJson);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -75,7 +75,7 @@
|
||||||
"mapbbcode": "MapBBCode/mapbbcode#v1.2.0",
|
"mapbbcode": "MapBBCode/mapbbcode#v1.2.0",
|
||||||
"osmtogeojson": "^3.0.0-beta.4",
|
"osmtogeojson": "^3.0.0-beta.4",
|
||||||
"regenerator-runtime": "^0.13.7",
|
"regenerator-runtime": "^0.13.7",
|
||||||
"togpx": "^0.5.4",
|
"togpx": "JarnoLeConte/togpx#13c65a8",
|
||||||
"topojson-client": "^3.1.0",
|
"topojson-client": "^3.1.0",
|
||||||
"url-search-params": "~0.5.0"
|
"url-search-params": "~0.5.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
BR = {};
|
BR = {};
|
||||||
|
turf = require('@turf/turf');
|
||||||
togpx = require('togpx');
|
togpx = require('togpx');
|
||||||
|
require('leaflet');
|
||||||
|
require('../../js/format/VoiceHints.js');
|
||||||
require('../../js/format/Gpx.js');
|
require('../../js/format/Gpx.js');
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
@ -21,7 +24,7 @@ function adoptGpx(gpx) {
|
||||||
.split(newline)
|
.split(newline)
|
||||||
.map((line) => line.replace(/lon="([^"]*)" lat="([^"]*)"/, 'lat="$2" lon="$1"'))
|
.map((line) => line.replace(/lon="([^"]*)" lat="([^"]*)"/, 'lat="$2" lon="$1"'))
|
||||||
.join(newline);
|
.join(newline);
|
||||||
gpx = gpx.replace(/0"><ele>/g, '"><ele>');
|
gpx = gpx.replace(/(lon|lat)="([-0-9]+.[0-9]+?)0+"/g, '$1="$2"'); // remove trailing zeros
|
||||||
gpx = gpx.replace('</gpx>\n', '</gpx>');
|
gpx = gpx.replace('</gpx>\n', '</gpx>');
|
||||||
|
|
||||||
return gpx;
|
return gpx;
|
||||||
|
|
@ -36,3 +39,11 @@ test('simple track', () => {
|
||||||
const gpx = BR.Gpx.format(geoJson);
|
const gpx = BR.Gpx.format(geoJson);
|
||||||
expect(gpx).toEqual(brouterGpx);
|
expect(gpx).toEqual(brouterGpx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('voice hints', () => {
|
||||||
|
test('5-gpsies', () => {
|
||||||
|
const brouterGpx = BR.Gpx.pretty(read('5-gpsies.gpx'));
|
||||||
|
const gpx = BR.Gpx.format(geoJson, 5);
|
||||||
|
expect(gpx).toEqual(brouterGpx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
22
tests/format/data/5-gpsies.gpx
Normal file
22
tests/format/data/5-gpsies.gpx
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?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">
|
||||||
|
<wpt lon="8.468340" lat="49.488794"><name>right</name><sym>right</sym><type>Right</type></wpt>
|
||||||
|
<wpt lon="8.469971" lat="49.488151"><name>left</name><sym>left</sym><type>Left</type></wpt>
|
||||||
|
<trk>
|
||||||
|
<name>5-gpsies</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>
|
||||||
11
yarn.lock
11
yarn.lock
|
|
@ -7189,7 +7189,7 @@ just-debounce@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea"
|
resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea"
|
||||||
integrity sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=
|
integrity sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=
|
||||||
|
|
||||||
jxon@~2.0.0-beta.5:
|
jxon@~2.0.0-beta.2:
|
||||||
version "2.0.0-beta.5"
|
version "2.0.0-beta.5"
|
||||||
resolved "https://registry.yarnpkg.com/jxon/-/jxon-2.0.0-beta.5.tgz#3b6a94104f9801ee682fd056645ff5473d9b343e"
|
resolved "https://registry.yarnpkg.com/jxon/-/jxon-2.0.0-beta.5.tgz#3b6a94104f9801ee682fd056645ff5473d9b343e"
|
||||||
integrity sha1-O2qUEE+YAe5oL9BWZF/1Rz2bND4=
|
integrity sha1-O2qUEE+YAe5oL9BWZF/1Rz2bND4=
|
||||||
|
|
@ -10565,13 +10565,12 @@ to-utf8@0.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852"
|
resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852"
|
||||||
integrity sha1-0Xrqcv8vujm55DYBvns/9y4ImFI=
|
integrity sha1-0Xrqcv8vujm55DYBvns/9y4ImFI=
|
||||||
|
|
||||||
togpx@^0.5.4:
|
togpx@JarnoLeConte/togpx#13c65a8:
|
||||||
version "0.5.4"
|
version "0.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/togpx/-/togpx-0.5.4.tgz#b33dbb0541df04bd6ba4f50b86da953424bb7773"
|
resolved "https://codeload.github.com/JarnoLeConte/togpx/tar.gz/13c65a82e3fbe8694f189d34fb7a339fa07700ec"
|
||||||
integrity sha1-sz27BUHfBL1rpPULhtqVNCS7d3M=
|
|
||||||
dependencies:
|
dependencies:
|
||||||
concat-stream "~1.0.1"
|
concat-stream "~1.0.1"
|
||||||
jxon "~2.0.0-beta.5"
|
jxon "~2.0.0-beta.2"
|
||||||
optimist "~0.3.5"
|
optimist "~0.3.5"
|
||||||
xmldom "~0.1.17"
|
xmldom "~0.1.17"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue