Concatenate total track
+ handle server voicehint time removed, times with 3 digits
This commit is contained in:
parent
954812cf52
commit
25f8828ae7
10 changed files with 412 additions and 47 deletions
|
|
@ -1149,6 +1149,8 @@
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/googlediff@0.1.0/javascript/diff_match_patch.js"></script>
|
||||||
|
|
||||||
<script src="dist/core-js-bundle.min.js"></script>
|
<script src="dist/core-js-bundle.min.js"></script>
|
||||||
<script src="dist/regenerator-runtime.js"></script>
|
<script src="dist/regenerator-runtime.js"></script>
|
||||||
<!-- <script src="dist/url-search-params.js"></script> -->
|
<!-- <script src="dist/url-search-params.js"></script> -->
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,9 @@ BR.Export = L.Class.extend({
|
||||||
this.update([]);
|
this.update([]);
|
||||||
},
|
},
|
||||||
|
|
||||||
update: function (latLngs) {
|
update: function (latLngs, segments) {
|
||||||
this.latLngs = latLngs;
|
this.latLngs = latLngs;
|
||||||
|
this.segments = segments;
|
||||||
|
|
||||||
if (latLngs.length < 2) {
|
if (latLngs.length < 2) {
|
||||||
this.exportButton.addClass('disabled');
|
this.exportButton.addClass('disabled');
|
||||||
|
|
@ -47,15 +48,38 @@ BR.Export = L.Class.extend({
|
||||||
var name = encodeURIComponent(exportForm['trackname'].value);
|
var name = encodeURIComponent(exportForm['trackname'].value);
|
||||||
var includeWaypoints = exportForm['include-waypoints'].checked;
|
var includeWaypoints = exportForm['include-waypoints'].checked;
|
||||||
|
|
||||||
var uri = this.router.getUrl(this.latLngs, this.pois.getMarkers(), null, format, name, includeWaypoints);
|
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
var evt = document.createEvent('MouseEvents');
|
if (true) {
|
||||||
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
var uri = this.router.getUrl(this.latLngs, this.pois.getMarkers(), null, format, name, includeWaypoints);
|
||||||
var link = document.createElement('a');
|
|
||||||
link.href = uri;
|
// var evt = document.createEvent('MouseEvents');
|
||||||
link.dispatchEvent(evt);
|
// evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
||||||
|
// var link = document.createElement('a');
|
||||||
|
// link.href = uri;
|
||||||
|
// link.dispatchEvent(evt);
|
||||||
|
//} else {
|
||||||
|
|
||||||
|
const track = this._formatTrack(format, name, includeWaypoints);
|
||||||
|
BR.Export.diff(uri, track, format);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_formatTrack: function (format, name, includeWaypoints) {
|
||||||
|
const track = BR.Export._concatTotalTrack(this.segments);
|
||||||
|
//console.log('GeoJson: ', trackGeoJson);
|
||||||
|
//console.log('GeoJson: ', JSON.stringify(trackGeoJson, null, 4));
|
||||||
|
switch (format) {
|
||||||
|
case 'gpx':
|
||||||
|
//console.log('gpx: ', gpx);
|
||||||
|
return BR.Gpx.format(track, 2, 'bike'); // TODO parse turnInstructionMode, transportMode
|
||||||
|
case 'geojson':
|
||||||
|
return JSON.stringify(track, null, 2);
|
||||||
|
case 'kml':
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
console.error('Export format not implemented: ' + format);
|
||||||
},
|
},
|
||||||
|
|
||||||
_validationMessage: function () {
|
_validationMessage: function () {
|
||||||
|
|
@ -72,6 +96,7 @@ BR.Export = L.Class.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
_generateTrackname: function () {
|
_generateTrackname: function () {
|
||||||
|
return; // TODO remove
|
||||||
var trackname = this.trackname;
|
var trackname = this.trackname;
|
||||||
this._getCityAtPosition(
|
this._getCityAtPosition(
|
||||||
this.latLngs[0],
|
this.latLngs[0],
|
||||||
|
|
@ -143,3 +168,150 @@ BR.Export = L.Class.extend({
|
||||||
BR.export = function () {
|
BR.export = function () {
|
||||||
return new BR.Export();
|
return new BR.Export();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BR.Export._concatTotalTrack = function (segments) {
|
||||||
|
const sumProperties = (p, fp, keys) => {
|
||||||
|
for (const key of keys) {
|
||||||
|
p[key] = (+p[key] + +fp[key]).toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let coordinates = [];
|
||||||
|
let properties;
|
||||||
|
|
||||||
|
//console.time('_concatTotalTrack');
|
||||||
|
for (const [segmentIndex, segment] of segments.entries()) {
|
||||||
|
const feature = segment.feature;
|
||||||
|
if (!feature) continue;
|
||||||
|
|
||||||
|
const coordOffset = coordinates.length > 0 ? coordinates.length - 1 : 0;
|
||||||
|
if (properties) {
|
||||||
|
const p = properties;
|
||||||
|
const fp = feature.properties;
|
||||||
|
|
||||||
|
sumProperties(p, fp, [
|
||||||
|
'cost',
|
||||||
|
'filtered ascend',
|
||||||
|
'plain-ascend',
|
||||||
|
'total-energy',
|
||||||
|
'total-time',
|
||||||
|
'track-length',
|
||||||
|
]);
|
||||||
|
|
||||||
|
p.messages = p.messages.concat(fp.messages.slice(1));
|
||||||
|
if (p.times && fp.times) {
|
||||||
|
const lastTime = p.times[p.times.length - 1];
|
||||||
|
for (const [timeIndex, time] of fp.times.entries()) {
|
||||||
|
if (timeIndex > 0) {
|
||||||
|
p.times.push(+(lastTime + time).toFixed(3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fp.voicehints) {
|
||||||
|
if (!p.voicehints) p.voicehints = [];
|
||||||
|
for (const fpHint of fp.voicehints) {
|
||||||
|
const hint = fpHint.slice();
|
||||||
|
hint[0] += coordOffset;
|
||||||
|
p.voicehints.push(hint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// clone
|
||||||
|
properties = Object.assign({}, feature.properties);
|
||||||
|
if (properties.voicehints) {
|
||||||
|
properties.voicehints = properties.voicehints.slice();
|
||||||
|
}
|
||||||
|
if (properties.times) {
|
||||||
|
properties.times = properties.times.slice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let featureCoordinates = feature.geometry.coordinates;
|
||||||
|
if (segmentIndex > 0) {
|
||||||
|
// remove first segment coordinate, same as previous last
|
||||||
|
featureCoordinates = featureCoordinates.slice(1);
|
||||||
|
}
|
||||||
|
coordinates = coordinates.concat(featureCoordinates);
|
||||||
|
}
|
||||||
|
//console.timeEnd('_concatTotalTrack');
|
||||||
|
|
||||||
|
return turf.featureCollection([turf.lineString(coordinates, properties)]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// <script src="https://unpkg.com/googlediff@0.1.0/javascript/diff_match_patch.js"></script>
|
||||||
|
BR.Export.diff = function (uri, track, format) {
|
||||||
|
BR.Util.get(
|
||||||
|
uri,
|
||||||
|
((err, text) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Error exporting "' + profileUrl + '": ' + err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format === 'gpx') {
|
||||||
|
text = BR.Gpx.pretty(BR.Export.adoptGpx(text));
|
||||||
|
} else if (format === 'geojson') {
|
||||||
|
text = JSON.stringify(JSON.parse(text), null, 2);
|
||||||
|
}
|
||||||
|
var dmp = new diff_match_patch();
|
||||||
|
var diff = dmp.diff_main(text, track);
|
||||||
|
dmp.diff_cleanupSemantic(diff);
|
||||||
|
|
||||||
|
if (dmp.diff_levenshtein(diff) > 0) {
|
||||||
|
let i = 0;
|
||||||
|
while (i < diff.length - 2) {
|
||||||
|
if (
|
||||||
|
diff[i][0] === 0 &&
|
||||||
|
diff[i + 1][0] === -1 &&
|
||||||
|
diff[i + 2][0] === 1 &&
|
||||||
|
(/(rteTime|rteSpeed)>\d+\.\d{0,2}$/.test(diff[i][1]) || /time=[0-9h ]*m \d$/.test(diff[i][1]))
|
||||||
|
) {
|
||||||
|
const del = +diff[i + 1][1];
|
||||||
|
const ins = +diff[i + 2][1];
|
||||||
|
if (Number.isInteger(del) && Number.isInteger(ins) && Math.abs(del - ins) === 1) {
|
||||||
|
diff.splice(i + 1, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dmp.diff_levenshtein(diff) > 0) {
|
||||||
|
//console.log('server: ', text);
|
||||||
|
//console.log('client: ', track);
|
||||||
|
console.log(diff);
|
||||||
|
bootbox.alert(dmp.diff_prettyHtml(diff));
|
||||||
|
} else {
|
||||||
|
console.log('diff equal');
|
||||||
|
}
|
||||||
|
}).bind(this)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO remove
|
||||||
|
// copied from Gpx.test.js
|
||||||
|
BR.Export.adoptGpx = function (gpx, replaceCreator = true) {
|
||||||
|
const creator = 'togpx';
|
||||||
|
const name = 'Track';
|
||||||
|
const newline = '\n';
|
||||||
|
|
||||||
|
gpx = gpx.replace(/=\.(?=\d)/, '=0.');
|
||||||
|
if (replaceCreator) {
|
||||||
|
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
|
||||||
|
.split(newline)
|
||||||
|
.map((line) => line.replace(/lon="([^"]*)" lat="([^"]*)"/, 'lat="$2" lon="$1"'))
|
||||||
|
.join(newline);
|
||||||
|
gpx = gpx.replace(/(lon|lat)="([-0-9]+.[0-9]+?)0+"/g, '$1="$2"'); // remove trailing zeros
|
||||||
|
gpx = gpx.replace('</gpx>\n', '</gpx>');
|
||||||
|
|
||||||
|
// added
|
||||||
|
gpx = gpx.replace(/>([-.0-9]+?0+)<\//g, (match, p1) => `>${+p1}</`); // remove trailing zeros
|
||||||
|
// trunc bc. float precision diffs
|
||||||
|
gpx = gpx.replace(/(rteTime|rteSpeed)>([^<]*)<\//g, (match, p1, p2) => `${p1}>${(+p2).toFixed(3)}</`);
|
||||||
|
gpx = gpx.replace(/\n?\s*<\/extensions>\n?\s*<extensions>/, ''); // ignore (invalid) double tag
|
||||||
|
|
||||||
|
return gpx;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -49,14 +49,25 @@ BR.Gpx = {
|
||||||
comment += ' energy=' + (props['total-energy'] / 3600000).toFixed(1) + 'kwh';
|
comment += ' energy=' + (props['total-energy'] / 3600000).toFixed(1) + 'kwh';
|
||||||
}
|
}
|
||||||
if (props['total-time']) {
|
if (props['total-time']) {
|
||||||
// TODO format, e.g. total-time=14833 -> time=4h 7m 13s
|
comment += ' time=' + BR.Gpx.formatTime(props['total-time']);
|
||||||
// see brouter OsmTrack.getFormattedTime2
|
|
||||||
comment += ' time=' + props['total-time'] + 's';
|
|
||||||
}
|
}
|
||||||
comment += ' -->';
|
comment += ' -->';
|
||||||
return comment;
|
return comment;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 14833 -> 4h 7m 13s
|
||||||
|
// see BRouter OsmTrack.getFormattedTime2
|
||||||
|
formatTime(seconds) {
|
||||||
|
const hours = Math.trunc(seconds / 3600);
|
||||||
|
const minutes = Math.trunc((seconds - hours * 3600) / 60);
|
||||||
|
seconds = seconds - hours * 3600 - minutes * 60;
|
||||||
|
let time = '';
|
||||||
|
if (hours != 0) time += hours + 'h ';
|
||||||
|
if (minutes != 0) time += minutes + 'm ';
|
||||||
|
if (seconds != 0) time += seconds + 's';
|
||||||
|
return time;
|
||||||
|
},
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
||||||
|
|
@ -11,21 +11,25 @@
|
||||||
|
|
||||||
class RoundaboutCommand extends Command {
|
class RoundaboutCommand extends Command {
|
||||||
constructor(command, exitNumber) {
|
constructor(command, exitNumber) {
|
||||||
this.name = command.name + exitNumber;
|
super(
|
||||||
this.locus = command.locus + exitNumber;
|
command.name + exitNumber,
|
||||||
this.orux = command.orux + exitNumber;
|
command.locus + exitNumber,
|
||||||
this.symbol = command.symbol + exitNumber;
|
command.orux + exitNumber,
|
||||||
this.message = command.message + exitNumber;
|
command.symbol + exitNumber,
|
||||||
|
command.message + exitNumber
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoundaboutLeftCommand extends RoundaboutCommand {
|
class RoundaboutLeftCommand extends RoundaboutCommand {
|
||||||
constructor(command, exitNumber) {
|
constructor(command, exitNumber) {
|
||||||
this.name = command.name + -exitNumber;
|
super(
|
||||||
this.locus = command.locus + -exitNumber;
|
command.name + -exitNumber,
|
||||||
this.orux = command.orux + exitNumber;
|
command.locus + -exitNumber,
|
||||||
this.symbol = command.symbol + -exitNumber;
|
command.orux + exitNumber,
|
||||||
this.message = command.message + -exitNumber;
|
command.symbol + -exitNumber,
|
||||||
|
command.message + -exitNumber
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,36 +86,25 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
_getDuration: function (voicehintsIndex) {
|
_getDuration: function (voicehintsIndex) {
|
||||||
const timeList = this.track.properties.times;
|
const times = this.track.properties.times;
|
||||||
|
if (!times) return 0;
|
||||||
|
|
||||||
const indexInTrack = this.voicehints[voicehintsIndex][0];
|
const indexInTrack = this.voicehints[voicehintsIndex][0];
|
||||||
const currTime = timeList[indexInTrack];
|
const currentTime = times[indexInTrack];
|
||||||
const len = this.voicehints.length;
|
const len = this.voicehints.length;
|
||||||
const nextIndex = voicehintsIndex < len - 1 ? this.voicehints[voicehintsIndex + 1][0] : timeList.length - 1;
|
const nextIndex = voicehintsIndex < len - 1 ? this.voicehints[voicehintsIndex + 1][0] : times.length - 1;
|
||||||
const nextTime = timeList[nextIndex];
|
const nextTime = times[nextIndex];
|
||||||
|
|
||||||
const duration = nextTime - currTime;
|
return nextTime - currentTime;
|
||||||
|
|
||||||
// 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) {
|
||||||
if (!this.voicehints) return;
|
if (!this.voicehints) return;
|
||||||
for (const [i, values] of this.voicehints.entries()) {
|
for (const [i, values] of this.voicehints.entries()) {
|
||||||
const [indexInTrack, commandId, exitNumber, distance, time, angle, geometry] = values;
|
const [indexInTrack, commandId, exitNumber, distance, angle, geometry] = values;
|
||||||
const hint = { indexInTrack, commandId, exitNumber, distance, time, angle, geometry };
|
const hint = { indexInTrack, commandId, exitNumber, distance, angle, geometry };
|
||||||
|
|
||||||
// TODO remove server hint time
|
hint.time = this._getDuration(i);
|
||||||
//hint.time = this._getDuration(i);
|
|
||||||
this._getDuration(i);
|
|
||||||
if (hint.time > 0) {
|
if (hint.time > 0) {
|
||||||
hint.speed = distance / hint.time;
|
hint.speed = distance / hint.time;
|
||||||
}
|
}
|
||||||
|
|
@ -229,8 +222,8 @@
|
||||||
|
|
||||||
extensions['locus:rteDistance'] = hint.distance;
|
extensions['locus:rteDistance'] = hint.distance;
|
||||||
if (hint.time > 0) {
|
if (hint.time > 0) {
|
||||||
extensions['locus:rteTime'] = hint.time;
|
extensions['locus:rteTime'] = hint.time.toFixed(3);
|
||||||
extensions['locus:rteSpeed'] = hint.speed;
|
extensions['locus:rteSpeed'] = hint.speed.toFixed(3);
|
||||||
}
|
}
|
||||||
extensions['locus:rtePointAction'] = cmd.locus;
|
extensions['locus:rtePointAction'] = cmd.locus;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,7 @@
|
||||||
trackMessages.update(track, segments);
|
trackMessages.update(track, segments);
|
||||||
trackAnalysis.update(track, segments);
|
trackAnalysis.update(track, segments);
|
||||||
|
|
||||||
exportRoute.update(latLngs);
|
exportRoute.update(latLngs, segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
routing.addTo(map);
|
routing.addTo(map);
|
||||||
|
|
|
||||||
40
tests/control/Export.test.js
Normal file
40
tests/control/Export.test.js
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
BR = {};
|
||||||
|
require('leaflet');
|
||||||
|
turf = require('@turf/turf');
|
||||||
|
require('../../js/control/Export.js');
|
||||||
|
|
||||||
|
// &lonlats=8.467712,49.488117;8.469354,49.488394;8.470556,49.488946;8.469982,49.489176 + turnInstructionMode=2
|
||||||
|
const segments = require('./data/segments.json');
|
||||||
|
const brouterTotal = require('./data/brouterTotal.json');
|
||||||
|
|
||||||
|
// resolve intended/accepted differences before comparing
|
||||||
|
function adopt(total, brouterTotal) {
|
||||||
|
// BRouter total aggregates messages over segments, client total does not,
|
||||||
|
// but that's Ok, so just fix for the test comparison
|
||||||
|
const messages = total.features[0].properties.messages;
|
||||||
|
const message = messages[4].slice();
|
||||||
|
messages[4] = message;
|
||||||
|
message[3] = (+message[3] + +messages[2][3] + +messages[3][3]).toString();
|
||||||
|
message[6] = (+message[6] + +messages[2][6] + +messages[3][6]).toString();
|
||||||
|
messages.splice(2, 2);
|
||||||
|
|
||||||
|
// fix minor float rounding difference
|
||||||
|
total.features[0].properties.times[6] = 28.833; // 28.832
|
||||||
|
|
||||||
|
total.features[0].properties.name = brouterTotal.features[0].properties.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
test('total track', () => {
|
||||||
|
const segmentsString = JSON.stringify(segments, null, 2);
|
||||||
|
let total = BR.Export._concatTotalTrack(segments);
|
||||||
|
adopt(total, brouterTotal);
|
||||||
|
expect(total).toEqual(brouterTotal);
|
||||||
|
|
||||||
|
// test original segments are not modified
|
||||||
|
expect(JSON.stringify(segments, null, 2)).toEqual(segmentsString);
|
||||||
|
|
||||||
|
// should be repeatable
|
||||||
|
total = BR.Export._concatTotalTrack(segments);
|
||||||
|
adopt(total, brouterTotal);
|
||||||
|
expect(total).toEqual(brouterTotal);
|
||||||
|
});
|
||||||
45
tests/control/data/brouterTotal.json
Normal file
45
tests/control/data/brouterTotal.json
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"type": "FeatureCollection",
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"creator": "BRouter-1.1",
|
||||||
|
"name": "brouter_1615489279610_0",
|
||||||
|
"track-length": "388",
|
||||||
|
"filtered ascend": "1",
|
||||||
|
"plain-ascend": "0",
|
||||||
|
"total-time": "44",
|
||||||
|
"total-energy": "4420",
|
||||||
|
"cost": "703",
|
||||||
|
"voicehints": [
|
||||||
|
[1,5,0,88.0,89],
|
||||||
|
[6,2,0,99.0,-90],
|
||||||
|
[7,2,0,10.0,-90]
|
||||||
|
],
|
||||||
|
"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", ""],
|
||||||
|
["8469852", "49489230", "100", "299", "1150", "0", "270", "0", "0", "highway=residential surface=asphalt oneway=yes smoothness=good", ""]
|
||||||
|
],
|
||||||
|
"times": [0,9.592,12.271,14.13,19.406,22.134,28.833,37.817,38.938,44.217]
|
||||||
|
},
|
||||||
|
"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.469355, 49.488395, 102.0],
|
||||||
|
[8.469971, 49.488151, 103.5],
|
||||||
|
[8.470671, 49.488909, 99.5],
|
||||||
|
[8.470561, 49.488951, 99.5],
|
||||||
|
[8.469984, 49.489178, 100.0]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
97
tests/control/data/segments.json
Normal file
97
tests/control/data/segments.json
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
[{
|
||||||
|
"feature": {
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"creator": "BRouter-1.1",
|
||||||
|
"name": "brouter_1615393581719_0",
|
||||||
|
"track-length": "177",
|
||||||
|
"filtered ascend": "0",
|
||||||
|
"plain-ascend": "1",
|
||||||
|
"total-time": "22",
|
||||||
|
"total-energy": "2213",
|
||||||
|
"cost": "280",
|
||||||
|
"voicehints": [
|
||||||
|
[1,5,0,88.0,89]
|
||||||
|
],
|
||||||
|
"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", ""],
|
||||||
|
["8469971", "49488151", "102", "88", "1150", "0", "90", "0", "0", "highway=residential surface=asphalt oneway=yes smoothness=good", ""]
|
||||||
|
],
|
||||||
|
"times": [0,9.592,12.271,14.13,19.406,22.134]
|
||||||
|
},
|
||||||
|
"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.469355, 49.488395, 102.0]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"feature": {
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"creator": "BRouter-1.1",
|
||||||
|
"name": "brouter_1615393581719_0",
|
||||||
|
"track-length": "162",
|
||||||
|
"filtered ascend": "1",
|
||||||
|
"plain-ascend": "-2",
|
||||||
|
"total-time": "17",
|
||||||
|
"total-energy": "1680",
|
||||||
|
"cost": "367",
|
||||||
|
"voicehints": [
|
||||||
|
[1,2,0,99.0,-90],
|
||||||
|
[2,2,0,10.0,-90]
|
||||||
|
],
|
||||||
|
"messages": [
|
||||||
|
["Longitude", "Latitude", "Elevation", "Distance", "CostPerKm", "ElevCost", "TurnCost", "NodeCost", "InitialCost", "WayTags", "NodeTags"],
|
||||||
|
["8469852", "49489230", "99", "162", "1150", "0", "180", "0", "0", "highway=residential surface=asphalt oneway=yes smoothness=good", ""]
|
||||||
|
],
|
||||||
|
"times": [0,6.698,15.683,16.804]
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "LineString",
|
||||||
|
"coordinates": [
|
||||||
|
[8.469355, 49.488395, 102.0],
|
||||||
|
[8.469971, 49.488151, 103.5],
|
||||||
|
[8.470671, 49.488909, 99.5],
|
||||||
|
[8.470561, 49.488951, 99.5]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"feature": {
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"creator": "BRouter-1.1",
|
||||||
|
"name": "brouter_1615393581719_0",
|
||||||
|
"track-length": "49",
|
||||||
|
"filtered ascend": "0",
|
||||||
|
"plain-ascend": "1",
|
||||||
|
"total-time": "5",
|
||||||
|
"total-energy": "527",
|
||||||
|
"cost": "56",
|
||||||
|
"messages": [
|
||||||
|
["Longitude", "Latitude", "Elevation", "Distance", "CostPerKm", "ElevCost", "TurnCost", "NodeCost", "InitialCost", "WayTags", "NodeTags"],
|
||||||
|
["8469852", "49489230", "100", "49", "1150", "0", "0", "0", "0", "highway=residential surface=asphalt oneway=yes smoothness=good", ""]
|
||||||
|
],
|
||||||
|
"times": [0,5.279]
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "LineString",
|
||||||
|
"coordinates": [
|
||||||
|
[8.470561, 49.488951, 99.5],
|
||||||
|
[8.469984, 49.489178, 100.0]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
@ -47,6 +47,11 @@ describe('voice hints', () => {
|
||||||
let brouterGpx = read('2-locus.gpx');
|
let brouterGpx = read('2-locus.gpx');
|
||||||
brouterGpx = brouterGpx.replace(/.0<\/locus:rteDistance/g, '</locus:rteDistance'); // ignore .0 decimal
|
brouterGpx = brouterGpx.replace(/.0<\/locus:rteDistance/g, '</locus:rteDistance'); // ignore .0 decimal
|
||||||
brouterGpx = brouterGpx.replace(/\n\s*<\/extensions>\n\s*<extensions>/, ''); // ignore (invalid) double tag
|
brouterGpx = brouterGpx.replace(/\n\s*<\/extensions>\n\s*<extensions>/, ''); // ignore (invalid) double tag
|
||||||
|
// ignore float rounding differences
|
||||||
|
brouterGpx = brouterGpx.replace(
|
||||||
|
/:(rteTime|rteSpeed)>([\d.]*)<\//g,
|
||||||
|
(match, p1, p2) => `:${p1}>${(+p2).toFixed(3)}</`
|
||||||
|
);
|
||||||
|
|
||||||
const gpx = BR.Gpx.format(geoJson, 2);
|
const gpx = BR.Gpx.format(geoJson, 2);
|
||||||
expect(gpx).toEqual(brouterGpx);
|
expect(gpx).toEqual(brouterGpx);
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@
|
||||||
"total-energy": "4412",
|
"total-energy": "4412",
|
||||||
"cost": "533",
|
"cost": "533",
|
||||||
"voicehints": [
|
"voicehints": [
|
||||||
[1,5,0,140.0,24.90994644165039,89," 6(90)6 (0)6 (-89)2"],
|
[1,5,0,140.0,89," 6(90)6 (0)6 (-89)2"],
|
||||||
[5,2,0,90.0,9.614852905273438,-90," 6(-89)6 (0)6 (89)6"]
|
[5,2,0,90.0,-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"],
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue