Format OsmAnd voice hints
This commit is contained in:
parent
ea564006e9
commit
8f2261037c
5 changed files with 169 additions and 13 deletions
|
|
@ -24,6 +24,7 @@ BR.Gpx = {
|
||||||
let gpx = togpx(geoJson, {
|
let gpx = togpx(geoJson, {
|
||||||
featureTitle: function () {},
|
featureTitle: function () {},
|
||||||
featureDescription: function () {},
|
featureDescription: function () {},
|
||||||
|
featureCoordTimes: function () {},
|
||||||
transform: gpxTransform,
|
transform: gpxTransform,
|
||||||
});
|
});
|
||||||
const statsComment = BR.Gpx._statsComment(geoJson);
|
const statsComment = BR.Gpx._statsComment(geoJson);
|
||||||
|
|
|
||||||
|
|
@ -87,12 +87,38 @@
|
||||||
return transform;
|
return transform;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getDuration: function (voicehintsIndex) {
|
||||||
|
const timeList = this.track.properties.times;
|
||||||
|
const indexInTrack = this.voicehints[voicehintsIndex][0];
|
||||||
|
const currTime = timeList[indexInTrack];
|
||||||
|
const len = this.voicehints.length;
|
||||||
|
const nextIndex = voicehintsIndex < len - 1 ? this.voicehints[voicehintsIndex + 1][0] : timeList.length - 1;
|
||||||
|
const nextTime = timeList[nextIndex];
|
||||||
|
|
||||||
|
const duration = nextTime - currTime;
|
||||||
|
|
||||||
|
// TODO remove
|
||||||
|
const time = this.voicehints[voicehintsIndex][4];
|
||||||
|
const p = 5;
|
||||||
|
if (!(time.toPrecision(p) === duration.toPrecision(p))) {
|
||||||
|
console.error(
|
||||||
|
`${voicehintsIndex}: ${time.toPrecision(p)} =? ${duration.toPrecision(p)}, ${time} =? ${duration}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return duration;
|
||||||
|
},
|
||||||
|
|
||||||
_loopHints: function (hintCallback) {
|
_loopHints: function (hintCallback) {
|
||||||
for (const values of this.voicehints) {
|
for (const [i, values] of this.voicehints.entries()) {
|
||||||
const [indexInTrack, commandId, exitNumber, distance, time, geometry] = values;
|
const [indexInTrack, commandId, exitNumber, distance, time, angle, geometry] = values;
|
||||||
const hint = { indexInTrack, commandId, exitNumber, distance, time, geometry };
|
const hint = { indexInTrack, commandId, exitNumber, distance, time, angle, geometry };
|
||||||
if (time > 0) {
|
|
||||||
hint.speed = distance / time;
|
// TODO remove server hint time
|
||||||
|
//hint.time = this._getDuration(i);
|
||||||
|
this._getDuration(i);
|
||||||
|
if (hint.time > 0) {
|
||||||
|
hint.speed = distance / hint.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
const coord = this.track.geometry.coordinates[indexInTrack];
|
const coord = this.track.geometry.coordinates[indexInTrack];
|
||||||
|
|
@ -255,10 +281,76 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BR.OsmAndVoiceHints = BR.VoiceHints.extend({
|
||||||
|
_addToTransform: function (transform) {
|
||||||
|
transform.gpx = function (gpx, features) {
|
||||||
|
gpx['@creator'] = 'OsmAndRouter';
|
||||||
|
|
||||||
|
gpx.rte.push({
|
||||||
|
rtept: this._createRoutePoints(gpx),
|
||||||
|
});
|
||||||
|
|
||||||
|
// reorder trk after rte
|
||||||
|
const trk = gpx.trk;
|
||||||
|
delete gpx.trk;
|
||||||
|
gpx.trk = trk;
|
||||||
|
|
||||||
|
return gpx;
|
||||||
|
}.bind(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
_createRoutePoints: function (gpx) {
|
||||||
|
const rteptList = [];
|
||||||
|
|
||||||
|
const trkseg = gpx.trk[0].trkseg[0];
|
||||||
|
let trkpt = trkseg.trkpt[0];
|
||||||
|
const startTime = this.track.properties.times[this.voicehints[0][0]];
|
||||||
|
rteptList.push({
|
||||||
|
'@lat': trkpt['@lat'],
|
||||||
|
'@lon': trkpt['@lon'],
|
||||||
|
desc: 'start',
|
||||||
|
extensions: { time: Math.round(startTime), offset: 0 },
|
||||||
|
});
|
||||||
|
|
||||||
|
this._loopHints((hint, cmd, coord) => {
|
||||||
|
const rtept = {
|
||||||
|
'@lat': coord[1],
|
||||||
|
'@lon': coord[0],
|
||||||
|
desc: cmd.message,
|
||||||
|
extensions: {
|
||||||
|
time: Math.round(hint.time),
|
||||||
|
turn: cmd.name,
|
||||||
|
'turn-angle': hint.angle,
|
||||||
|
offset: hint.indexInTrack,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (hint.time === 0) {
|
||||||
|
delete properties.extensions.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
rteptList.push(rtept);
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastIndex = trkseg.trkpt.length - 1;
|
||||||
|
trkpt = trkseg.trkpt[lastIndex];
|
||||||
|
rteptList.push({
|
||||||
|
'@lat': trkpt['@lat'],
|
||||||
|
'@lon': trkpt['@lon'],
|
||||||
|
desc: 'destination',
|
||||||
|
extensions: { time: 0, offset: lastIndex },
|
||||||
|
});
|
||||||
|
|
||||||
|
return rteptList;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
BR.voiceHints = function (geoJson, turnInstructionMode, transportMode) {
|
BR.voiceHints = function (geoJson, turnInstructionMode, transportMode) {
|
||||||
switch (turnInstructionMode) {
|
switch (turnInstructionMode) {
|
||||||
case 2:
|
case 2:
|
||||||
return new BR.LocusVoiceHints(geoJson, turnInstructionMode, transportMode);
|
return new BR.LocusVoiceHints(geoJson, turnInstructionMode, transportMode);
|
||||||
|
case 3:
|
||||||
|
return new BR.OsmAndVoiceHints(geoJson, turnInstructionMode, transportMode);
|
||||||
case 4:
|
case 4:
|
||||||
return new BR.CommentVoiceHints(geoJson, turnInstructionMode, transportMode);
|
return new BR.CommentVoiceHints(geoJson, turnInstructionMode, transportMode);
|
||||||
case 5:
|
case 5:
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,16 @@ const geoJson = require('./data/track.json');
|
||||||
const path = 'tests/format/data/';
|
const path = 'tests/format/data/';
|
||||||
|
|
||||||
// resolve intended/accepted differences before comparing
|
// resolve intended/accepted differences before comparing
|
||||||
function adoptGpx(gpx) {
|
function adoptGpx(gpx, replaceCreator = true) {
|
||||||
const creator = 'togpx';
|
const creator = 'togpx';
|
||||||
const name = 'Track';
|
const name = 'Track';
|
||||||
const newline = '\n';
|
const newline = '\n';
|
||||||
|
|
||||||
gpx = gpx.replace('=.0', '=0.0');
|
gpx = gpx.replace('=.0', '=0.0');
|
||||||
gpx = gpx.replace(/creator="[^"]*"/, `creator="${creator}"`);
|
if (replaceCreator) {
|
||||||
gpx = gpx.replace(`creator="${creator}" version="1.1"`, `version="1.1" \n creator="${creator}"`);
|
gpx = gpx.replace(/creator="[^"]*"/, `creator="${creator}"`);
|
||||||
|
}
|
||||||
|
gpx = gpx.replace(/creator="([^"]*)" version="1.1"/, 'version="1.1" \n creator="$1"');
|
||||||
gpx = gpx.replace(/<trk>\n <name>[^<]*<\/name>/, `<trk>\n <name>${name}</name>`);
|
gpx = gpx.replace(/<trk>\n <name>[^<]*<\/name>/, `<trk>\n <name>${name}</name>`);
|
||||||
gpx = gpx
|
gpx = gpx
|
||||||
.split(newline)
|
.split(newline)
|
||||||
|
|
@ -30,8 +32,8 @@ function adoptGpx(gpx) {
|
||||||
return gpx;
|
return gpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
function read(fileName) {
|
function read(fileName, replaceCreator) {
|
||||||
return BR.Gpx.pretty(adoptGpx(fs.readFileSync(path + fileName, 'utf8')));
|
return BR.Gpx.pretty(adoptGpx(fs.readFileSync(path + fileName, 'utf8'), replaceCreator));
|
||||||
}
|
}
|
||||||
|
|
||||||
test('simple track', () => {
|
test('simple track', () => {
|
||||||
|
|
@ -51,6 +53,12 @@ describe('voice hints', () => {
|
||||||
expect(gpx).toEqual(brouterGpx);
|
expect(gpx).toEqual(brouterGpx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('3-osmand', () => {
|
||||||
|
const brouterGpx = read('3-osmand.gpx', false);
|
||||||
|
const gpx = BR.Gpx.format(geoJson, 3);
|
||||||
|
expect(gpx).toEqual(brouterGpx);
|
||||||
|
});
|
||||||
|
|
||||||
test('4-comment', () => {
|
test('4-comment', () => {
|
||||||
let brouterGpx = read('4-comment.gpx');
|
let brouterGpx = read('4-comment.gpx');
|
||||||
brouterGpx = brouterGpx.replace(/;\s*([-0-9]+.[0-9]+?)0+;/g, (match, p1) => `;${p1.padStart(10)};`); // remove trailing zeros
|
brouterGpx = brouterGpx.replace(/;\s*([-0-9]+.[0-9]+?)0+;/g, (match, p1) => `;${p1.padStart(10)};`); // remove trailing zeros
|
||||||
|
|
|
||||||
54
tests/format/data/3-osmand.gpx
Normal file
54
tests/format/data/3-osmand.gpx
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?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="OsmAndRouter" version="1.1">
|
||||||
|
<rte>
|
||||||
|
<rtept lat="49.488115" lon="8.467714">
|
||||||
|
<desc>start</desc>
|
||||||
|
<extensions>
|
||||||
|
<time>10</time>
|
||||||
|
<offset>0</offset>
|
||||||
|
</extensions>
|
||||||
|
</rtept>
|
||||||
|
<rtept lat="49.488794" lon="8.468340">
|
||||||
|
<desc>right</desc>
|
||||||
|
<extensions>
|
||||||
|
<time>25</time>
|
||||||
|
<turn>TR</turn>
|
||||||
|
<turn-angle>89</turn-angle>
|
||||||
|
<offset>1</offset>
|
||||||
|
</extensions>
|
||||||
|
</rtept>
|
||||||
|
<rtept lat="49.488151" lon="8.469971">
|
||||||
|
<desc>left</desc>
|
||||||
|
<extensions>
|
||||||
|
<time>10</time>
|
||||||
|
<turn>TL</turn>
|
||||||
|
<turn-angle>-90</turn-angle>
|
||||||
|
<offset>5</offset>
|
||||||
|
</extensions>
|
||||||
|
</rtept>
|
||||||
|
<rtept lat="49.488842" lon="8.470610">
|
||||||
|
<desc>destination</desc>
|
||||||
|
<extensions>
|
||||||
|
<time>0</time>
|
||||||
|
<offset>6</offset>
|
||||||
|
</extensions>
|
||||||
|
</rtept>
|
||||||
|
</rte>
|
||||||
|
<trk>
|
||||||
|
<name>3-osmand</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>
|
||||||
|
|
@ -13,14 +13,15 @@
|
||||||
"total-energy": "4412",
|
"total-energy": "4412",
|
||||||
"cost": "533",
|
"cost": "533",
|
||||||
"voicehints": [
|
"voicehints": [
|
||||||
[1,5,0,140.0,24.90994644165039," 6(90)6 (0)6 (-89)2"],
|
[1,5,0,140.0,24.90994644165039,89," 6(90)6 (0)6 (-89)2"],
|
||||||
[5,2,0,90.0,9.614852905273438," 6(-89)6 (0)6 (89)6"]
|
[5,2,0,90.0,9.614852905273438,-90," 6(-89)6 (0)6 (89)6"]
|
||||||
],
|
],
|
||||||
"messages": [
|
"messages": [
|
||||||
["Longitude", "Latitude", "Elevation", "Distance", "CostPerKm", "ElevCost", "TurnCost", "NodeCost", "InitialCost", "WayTags", "NodeTags"],
|
["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", ""],
|
["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", ""]
|
["8470671", "49488909", "99", "230", "1150", "0", "180", "0", "0", "highway=residential surface=asphalt oneway=yes smoothness=good", ""]
|
||||||
]
|
],
|
||||||
|
"times": [0.0,9.592433,12.270765,14.129882,19.406338,34.50238,44.117233]
|
||||||
},
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"type": "LineString",
|
"type": "LineString",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue