Merge bd823c53a5 into 5476f6ab27
This commit is contained in:
commit
01c24a115b
@ -2,6 +2,7 @@
|
|||||||
Feature: Testbot - side bias
|
Feature: Testbot - side bias
|
||||||
|
|
||||||
Scenario: Left-hand bias
|
Scenario: Left-hand bias
|
||||||
|
Given the valhalla admin db "left"
|
||||||
Given the profile file "car" initialized with
|
Given the profile file "car" initialized with
|
||||||
"""
|
"""
|
||||||
profile.properties.left_hand_driving = true
|
profile.properties.left_hand_driving = true
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
Feature: Turn Lane Guidance
|
Feature: Turn Lane Guidance
|
||||||
|
|
||||||
Background:
|
Background:
|
||||||
|
Given the valhalla admin db "left"
|
||||||
Given the profile "car"
|
Given the profile "car"
|
||||||
Given a grid size of 100 meters
|
Given a grid size of 100 meters
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
Feature: Basic Roundabout
|
Feature: Basic Roundabout
|
||||||
|
|
||||||
Background:
|
Background:
|
||||||
|
Given the valhalla admin db "left"
|
||||||
Given a grid size of 10 meters
|
Given a grid size of 10 meters
|
||||||
Given the profile file "car" initialized with
|
Given the profile file "car" initialized with
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -6,6 +6,7 @@ const Timeout = require('node-timeout');
|
|||||||
const tryConnect = require('../lib/try_connect');
|
const tryConnect = require('../lib/try_connect');
|
||||||
const errorReason = require('./utils').errorReason;
|
const errorReason = require('./utils').errorReason;
|
||||||
|
|
||||||
|
const child_process = require('child_process');
|
||||||
class OSRMBaseLoader{
|
class OSRMBaseLoader{
|
||||||
constructor (scope) {
|
constructor (scope) {
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
@ -45,7 +46,7 @@ class OSRMBaseLoader{
|
|||||||
var retryCount = 0;
|
var retryCount = 0;
|
||||||
let retry = (err) => {
|
let retry = (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (retryCount < 10) {
|
if (retryCount < 1000) {
|
||||||
retryCount++;
|
retryCount++;
|
||||||
setTimeout(() => { tryConnect(this.scope.OSRM_IP, this.scope.OSRM_PORT, retry); }, 10);
|
setTimeout(() => { tryConnect(this.scope.OSRM_IP, this.scope.OSRM_PORT, retry); }, 10);
|
||||||
} else {
|
} else {
|
||||||
@ -88,6 +89,33 @@ class OSRMDirectLoader extends OSRMBaseLoader {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ValhallaDirectLoader extends OSRMBaseLoader {
|
||||||
|
constructor (scope) {
|
||||||
|
super(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
load (inputFile, callback) {
|
||||||
|
this.inputFile = inputFile;
|
||||||
|
this.shutdown(() => {
|
||||||
|
this.launch(callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
osrmUp (callback) {
|
||||||
|
if (this.osrmIsRunning()) return callback(new Error("osrm-routed already running!"));
|
||||||
|
|
||||||
|
var args = [this.inputFile, '1'];
|
||||||
|
this.child = child_process.execFile(`${process.env.VALHALLA_HOME}/valhalla_service`, args, this.scope.environment, (err) => {
|
||||||
|
if (err && err.signal !== 'SIGINT') {
|
||||||
|
this.child = null;
|
||||||
|
throw new Error(util.format('valhalla_service %s: %s', errorReason(err), err.cmd));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setTimeout/
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class OSRMDatastoreLoader extends OSRMBaseLoader {
|
class OSRMDatastoreLoader extends OSRMBaseLoader {
|
||||||
constructor (scope) {
|
constructor (scope) {
|
||||||
super(scope);
|
super(scope);
|
||||||
@ -135,6 +163,7 @@ class OSRMLoader {
|
|||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
this.sharedLoader = new OSRMDatastoreLoader(this.scope);
|
this.sharedLoader = new OSRMDatastoreLoader(this.scope);
|
||||||
this.directLoader = new OSRMDirectLoader(this.scope);
|
this.directLoader = new OSRMDirectLoader(this.scope);
|
||||||
|
this.valhallaLoader = new ValhallaDirectLoader(this.scope);
|
||||||
this.method = scope.DEFAULT_LOAD_METHOD;
|
this.method = scope.DEFAULT_LOAD_METHOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +180,9 @@ class OSRMLoader {
|
|||||||
this.loader = this.directLoader;
|
this.loader = this.directLoader;
|
||||||
this.directLoader.load(inputFile, callback);
|
this.directLoader.load(inputFile, callback);
|
||||||
});
|
});
|
||||||
|
} else if (this.method === 'valhalla') {
|
||||||
|
this.loader = this.valhallaLoader;
|
||||||
|
this.valhallaLoader.load(inputFile, callback);
|
||||||
} else {
|
} else {
|
||||||
callback(new Error('*** Unknown load method ' + method));
|
callback(new Error('*** Unknown load method ' + method));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,11 @@ module.exports = function () {
|
|||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.Given(/^the valhalla admin db "(.*?)"$/, (args, callback) => {
|
||||||
|
this.vahallaAdminDB = this.expandOptions(args);
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
|
||||||
this.Given(/^the extract extra arguments "(.*?)"$/, (args, callback) => {
|
this.Given(/^the extract extra arguments "(.*?)"$/, (args, callback) => {
|
||||||
this.extractArgs = this.expandOptions(args);
|
this.extractArgs = this.expandOptions(args);
|
||||||
callback();
|
callback();
|
||||||
@ -309,6 +314,11 @@ module.exports = function () {
|
|||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.Given(/^data is loaded with valhalla$/, (callback) => {
|
||||||
|
this.osrmLoader.setLoadMethod('valhalla');
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
|
||||||
this.Given(/^the HTTP method "([^"]*)"$/, (method, callback) => {
|
this.Given(/^the HTTP method "([^"]*)"$/, (method, callback) => {
|
||||||
this.httpMethod = method;
|
this.httpMethod = method;
|
||||||
callback();
|
callback();
|
||||||
|
|||||||
@ -111,17 +111,17 @@ module.exports = function () {
|
|||||||
// result is an object containing the calculated values for 'rate', 'status',
|
// result is an object containing the calculated values for 'rate', 'status',
|
||||||
// 'time', 'distance', 'speed' and 'mode', for forwards and backwards routing, as well as
|
// 'time', 'distance', 'speed' and 'mode', for forwards and backwards routing, as well as
|
||||||
// a bothw object that diffs forwards/backwards
|
// a bothw object that diffs forwards/backwards
|
||||||
var testRoutabilityRow = (i, cb) => {
|
var testRoutabilityRow = (rowIndex, cb) => {
|
||||||
var result = {};
|
var result = {};
|
||||||
|
|
||||||
var testDirection = (dir, callback) => {
|
var testDirection = (dir, callback) => {
|
||||||
var a = new classes.Location(this.origin[0] + (1+this.WAY_SPACING*i) * this.zoom, this.origin[1]),
|
var a = new classes.Location(this.origin[0] + (1+this.WAY_SPACING*rowIndex) * this.zoom, this.origin[1]),
|
||||||
b = new classes.Location(this.origin[0] + (3+this.WAY_SPACING*i) * this.zoom, this.origin[1]),
|
b = new classes.Location(this.origin[0] + (3+this.WAY_SPACING*rowIndex) * this.zoom, this.origin[1]),
|
||||||
r = {};
|
r = {};
|
||||||
|
|
||||||
r.which = dir;
|
r.which = dir;
|
||||||
|
|
||||||
this.requestRoute((dir === 'forw' ? [a, b] : [b, a]), [], [], this.queryParams, (err, res, body) => {
|
this.requestRoute((dir === 'forw' ? [a, b] : [b, a]), [], [], this.queryParams, `${this.scenarioCacheFile}_${rowIndex}_request.txt`, (err, res, body) => {
|
||||||
if (err) return callback(err);
|
if (err) return callback(err);
|
||||||
|
|
||||||
r.query = this.query;
|
r.query = this.query;
|
||||||
@ -132,7 +132,7 @@ module.exports = function () {
|
|||||||
r.route = this.wayList(r.json.routes[0]);
|
r.route = this.wayList(r.json.routes[0]);
|
||||||
r.summary = r.json.routes[0].legs.map(l => l.summary).join(',');
|
r.summary = r.json.routes[0].legs.map(l => l.summary).join(',');
|
||||||
|
|
||||||
if (r.route.split(',')[0] === util.format('w%d', i)) {
|
if (r.route.split(',')[0] === util.format('w%d', rowIndex)) {
|
||||||
r.time = r.json.routes[0].duration;
|
r.time = r.json.routes[0].duration;
|
||||||
r.distance = r.json.routes[0].distance;
|
r.distance = r.json.routes[0].distance;
|
||||||
r.rate = Math.round(r.distance / r.json.routes[0].weight * 10) / 10.;
|
r.rate = Math.round(r.distance / r.json.routes[0].weight * 10) / 10.;
|
||||||
|
|||||||
@ -101,8 +101,10 @@ module.exports = function() {
|
|||||||
|
|
||||||
this.setupScenarioCache = (scenarioID) => {
|
this.setupScenarioCache = (scenarioID) => {
|
||||||
this.scenarioCacheFile = this.getScenarioCacheFile(this.featureCacheDirectory, scenarioID);
|
this.scenarioCacheFile = this.getScenarioCacheFile(this.featureCacheDirectory, scenarioID);
|
||||||
|
this.scenarioCacheFilePBF = this.getScenarioCacheFilePBF(this.featureCacheDirectory, scenarioID);
|
||||||
this.processedCacheFile = this.getProcessedCacheFile(this.featureProcessedCacheDirectory, scenarioID);
|
this.processedCacheFile = this.getProcessedCacheFile(this.featureProcessedCacheDirectory, scenarioID);
|
||||||
this.inputCacheFile = this.getInputCacheFile(this.featureProcessedCacheDirectory, scenarioID);
|
this.inputCacheFile = this.getInputCacheFile(this.featureProcessedCacheDirectory, scenarioID);
|
||||||
|
this.inputCacheFilePBF = this.getInputCacheFilePBF(this.featureProcessedCacheDirectory, scenarioID);
|
||||||
this.rasterCacheFile = this.getRasterCacheFile(this.featureProcessedCacheDirectory, scenarioID);
|
this.rasterCacheFile = this.getRasterCacheFile(this.featureProcessedCacheDirectory, scenarioID);
|
||||||
this.speedsCacheFile = this.getSpeedsCacheFile(this.featureProcessedCacheDirectory, scenarioID);
|
this.speedsCacheFile = this.getSpeedsCacheFile(this.featureProcessedCacheDirectory, scenarioID);
|
||||||
this.penaltiesCacheFile = this.getPenaltiesCacheFile(this.featureProcessedCacheDirectory, scenarioID);
|
this.penaltiesCacheFile = this.getPenaltiesCacheFile(this.featureProcessedCacheDirectory, scenarioID);
|
||||||
@ -176,6 +178,11 @@ module.exports = function() {
|
|||||||
return path.join(featureCacheDirectory, scenarioID) + '.osm';
|
return path.join(featureCacheDirectory, scenarioID) + '.osm';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// test/cache/{feature_path}/{feature_hash}/{scenario}.osm
|
||||||
|
this.getScenarioCacheFilePBF = (featureCacheDirectory, scenarioID) => {
|
||||||
|
return path.join(featureCacheDirectory, scenarioID) + '.pbf';
|
||||||
|
};
|
||||||
|
|
||||||
// test/cache/{feature_path}/{feature_hash}/{osrm_hash}/
|
// test/cache/{feature_path}/{feature_hash}/{osrm_hash}/
|
||||||
this.getFeatureProcessedCacheDirectory = (featureCacheDirectory, osrmHash) => {
|
this.getFeatureProcessedCacheDirectory = (featureCacheDirectory, osrmHash) => {
|
||||||
return path.join(featureCacheDirectory, osrmHash);
|
return path.join(featureCacheDirectory, osrmHash);
|
||||||
@ -191,6 +198,11 @@ module.exports = function() {
|
|||||||
return path.join(featureProcessedCacheDirectory, scenarioID) + '.osm';
|
return path.join(featureProcessedCacheDirectory, scenarioID) + '.osm';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// test/cache/{feature_path}/{feature_hash}/{osrm_hash}/{scenario}.osm
|
||||||
|
this.getInputCacheFilePBF = (featureProcessedCacheDirectory, scenarioID) => {
|
||||||
|
return path.join(featureProcessedCacheDirectory, scenarioID) + '.pbf';
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,6 +10,8 @@ const tableDiff = require('../lib/table_diff');
|
|||||||
const ensureDecimal = require('../lib/utils').ensureDecimal;
|
const ensureDecimal = require('../lib/utils').ensureDecimal;
|
||||||
const errorReason = require('../lib/utils').errorReason;
|
const errorReason = require('../lib/utils').errorReason;
|
||||||
|
|
||||||
|
const child_process = require('child_process');
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
this.setGridSize = (meters) => {
|
this.setGridSize = (meters) => {
|
||||||
// the constant is calculated (with BigDecimal as: 1.0/(DEG_TO_RAD*EARTH_RADIUS_IN_METERS
|
// the constant is calculated (with BigDecimal as: 1.0/(DEG_TO_RAD*EARTH_RADIUS_IN_METERS
|
||||||
@ -168,7 +170,21 @@ module.exports = function () {
|
|||||||
if (exists) callback();
|
if (exists) callback();
|
||||||
else {
|
else {
|
||||||
this.OSMDB.toXML((xml) => {
|
this.OSMDB.toXML((xml) => {
|
||||||
fs.writeFile(this.scenarioCacheFile, xml, callback);
|
var q = d3.queue(1);
|
||||||
|
|
||||||
|
q.defer(fs.writeFile, this.scenarioCacheFile, xml);
|
||||||
|
q.defer((xml, cb) => {
|
||||||
|
delete require.cache[require.resolve('osmtogeojson/parse_osmxml')];
|
||||||
|
var osmtogeojson = require('osmtogeojson');
|
||||||
|
var osmxmltojson = require('osmtogeojson/parse_osmxml');
|
||||||
|
var json = osmxmltojson.parseFromString(xml);
|
||||||
|
var geojson = osmtogeojson(json);
|
||||||
|
fs.writeFile(`${this.scenarioCacheFile}.geojson`, JSON.stringify(geojson), cb);
|
||||||
|
}, xml);
|
||||||
|
|
||||||
|
var params = ['cat',this.scenarioCacheFile,'-O','-o',this.scenarioCacheFilePBF];
|
||||||
|
q.defer(child_process.execFile,'osmium', params, {maxBuffer: 1024 * 1024 * 1000, env: {}});
|
||||||
|
q.awaitAll(callback);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -178,7 +194,10 @@ module.exports = function () {
|
|||||||
fs.exists(this.inputCacheFile, (exists) => {
|
fs.exists(this.inputCacheFile, (exists) => {
|
||||||
if (exists) callback();
|
if (exists) callback();
|
||||||
else {
|
else {
|
||||||
fs.link(this.scenarioCacheFile, this.inputCacheFile, callback);
|
fs.link(this.scenarioCacheFile, this.inputCacheFile, (err) => {
|
||||||
|
if (err) callback(err);
|
||||||
|
fs.link(this.scenarioCacheFilePBF, this.inputCacheFilePBF, callback);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -239,23 +258,101 @@ module.exports = function () {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.valhallaBuildConfig = (p, callback) => {
|
||||||
|
let stamp = p.processedCacheFile + '.stamp_valhalla_config';
|
||||||
|
fs.exists(stamp, (exists) => {
|
||||||
|
if (exists) return callback();
|
||||||
|
|
||||||
|
// valhalla_build_config --mjolnir-tile-dir ${PWD}/valhalla_tiles
|
||||||
|
// --mjolnir-tile-extract ${PWD}/valhalla_tiles.tar
|
||||||
|
// --mjolnir-timezone ${PWD}/valhalla_tiles/timezones.sqlite
|
||||||
|
// --mjolnir-admin ${PWD}/valhalla_tiles/admins.sqlite > valhalla.json
|
||||||
|
|
||||||
|
var params = [];
|
||||||
|
|
||||||
|
if (p.vahallaAdminDB === 'left') {
|
||||||
|
params = [`--mjolnir-tile-dir`, `${p.inputCacheDir}/${p.scenarioID}_valhalla_tiles`,
|
||||||
|
`--mjolnir-admin`, `/data/valhalla/admins_left.sqlite`];
|
||||||
|
} else {
|
||||||
|
params = [`--mjolnir-tile-dir`, `${p.inputCacheDir}/${p.scenarioID}_valhalla_tiles`,
|
||||||
|
`--mjolnir-admin`, `/data/valhalla/admins_right.sqlite`];
|
||||||
|
}
|
||||||
|
|
||||||
|
child_process.execFile(`${process.env.VALHALLA_HOME}/scripts/valhalla_build_config`, params, {}, (error, stdout, stderr) => {
|
||||||
|
if (error) { throw error; }
|
||||||
|
// Disable heirarchy calculation - it's slow, and not needed for small tests.
|
||||||
|
var config = JSON.parse(stdout);
|
||||||
|
config.mjolnir.hierarchy = false;
|
||||||
|
fs.writeFile(`${p.inputCacheDir}/${p.scenarioID}_valhalla_config.json`, JSON.stringify(config), (err) => {
|
||||||
|
if (err) throw err;
|
||||||
|
fs.writeFile(stamp, 'ok', callback);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.valhallaBuildTiles = (p, callback) => {
|
||||||
|
let stamp = p.processedCacheFile + '.stamp_valhalla_tiles';
|
||||||
|
fs.exists(stamp, (exists) => {
|
||||||
|
if (exists) return callback();
|
||||||
|
|
||||||
|
var params = [`-c`,`${p.inputCacheDir}/${p.scenarioID}_valhalla_config.json`,
|
||||||
|
`${p.inputCacheFilePBF}`];
|
||||||
|
|
||||||
|
child_process.execFile(`${process.env.VALHALLA_HOME}/valhalla_build_tiles`, params, {}, (error, stdout, stderr) => {
|
||||||
|
if (error) { throw error; }
|
||||||
|
console.log(stdout);
|
||||||
|
console.log(stderr);
|
||||||
|
fs.writeFile(stamp, 'ok', callback);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.valhallaTarTiles = (p, callback) => {
|
||||||
|
let stamp = p.processedCacheFile + '.stamp_valhalla_tiles';
|
||||||
|
fs.exists(stamp, (exists) => {
|
||||||
|
if (exists) return callback();
|
||||||
|
var params = [`cf`,`${p.inputCacheDir}/${p.scenarioID}_valhalla_tiles.tar`,
|
||||||
|
`-C`, p.inputCacheDir, `${p.scenarioID}_valhalla_tiles`];
|
||||||
|
|
||||||
|
child_process.execFile('/usr/bin/tar', params, {}, (error, stdout, stderr) => {
|
||||||
|
if (error) { throw error; }
|
||||||
|
console.log(stdout);
|
||||||
|
console.log(stderr);
|
||||||
|
fs.writeFile(stamp, 'ok', callback);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.extractContractPartitionAndCustomize = (callback) => {
|
this.extractContractPartitionAndCustomize = (callback) => {
|
||||||
// a shallow copy of scenario parameters to avoid data inconsistency
|
// a shallow copy of scenario parameters to avoid data inconsistency
|
||||||
// if a cucumber timeout occurs during deferred jobs
|
// if a cucumber timeout occurs during deferred jobs
|
||||||
let p = {extractArgs: this.extractArgs, contractArgs: this.contractArgs,
|
let p = {extractArgs: this.extractArgs, contractArgs: this.contractArgs,
|
||||||
partitionArgs: this.partitionArgs, customizeArgs: this.customizeArgs,
|
partitionArgs: this.partitionArgs, customizeArgs: this.customizeArgs,
|
||||||
profileFile: this.profileFile, inputCacheFile: this.inputCacheFile,
|
profileFile: this.profileFile, inputCacheFile: this.inputCacheFile,
|
||||||
processedCacheFile: this.processedCacheFile, environment: this.environment};
|
inputCacheFilePBF: this.inputCacheFilePBF, vahallaAdminDB: this.vahallaAdminDB,
|
||||||
|
processedCacheFile: this.processedCacheFile, environment: this.environment,
|
||||||
|
inputCacheDir: this.featureProcessedCacheDirectory,
|
||||||
|
scenarioID: this.scenarioID };
|
||||||
let queue = d3.queue(1);
|
let queue = d3.queue(1);
|
||||||
queue.defer(this.extractData.bind(this), p);
|
queue.defer(this.extractData.bind(this), p);
|
||||||
queue.defer(this.partitionData.bind(this), p);
|
queue.defer(this.partitionData.bind(this), p);
|
||||||
queue.defer(this.contractData.bind(this), p);
|
queue.defer(this.contractData.bind(this), p);
|
||||||
queue.defer(this.customizeData.bind(this), p);
|
queue.defer(this.valhallaBuildConfig.bind(this), p);
|
||||||
|
queue.defer(this.valhallaBuildTiles.bind(this), p);
|
||||||
|
queue.defer(this.valhallaTarTiles.bind(this), p);
|
||||||
queue.awaitAll(callback);
|
queue.awaitAll(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.writeAndLinkOSM = (callback) => {
|
this.writeAndLinkOSM = (callback) => {
|
||||||
let queue = d3.queue(1);
|
let queue = d3.queue(1);
|
||||||
|
let p = { profileFile: this.profileFile, inputCacheFile: this.inputCacheFile,
|
||||||
|
inputCacheFilePBF: this.inputCacheFilePBF,
|
||||||
|
processedCacheFile: this.processedCacheFile, environment: this.environment,
|
||||||
|
inputCacheDir: this.featureProcessedCacheDirectory,
|
||||||
|
scenarioID: this.scenarioID };
|
||||||
queue.defer(this.writeOSM.bind(this));
|
queue.defer(this.writeOSM.bind(this));
|
||||||
queue.defer(this.linkOSM.bind(this));
|
queue.defer(this.linkOSM.bind(this));
|
||||||
queue.awaitAll(callback);
|
queue.awaitAll(callback);
|
||||||
@ -272,7 +369,8 @@ module.exports = function () {
|
|||||||
let queue = d3.queue(1);
|
let queue = d3.queue(1);
|
||||||
queue.defer(this.writeAndLinkOSM.bind(this));
|
queue.defer(this.writeAndLinkOSM.bind(this));
|
||||||
queue.defer(this.extractContractPartitionAndCustomize.bind(this));
|
queue.defer(this.extractContractPartitionAndCustomize.bind(this));
|
||||||
queue.defer(this.osrmLoader.load.bind(this.osrmLoader), this.processedCacheFile);
|
//queue.defer(this.osrmLoader.load.bind(this.osrmLoader), this.processedCacheFile);
|
||||||
|
queue.defer(this.osrmLoader.load.bind(this.osrmLoader), `${this.featureProcessedCacheDirectory}/${this.scenarioID}_valhalla_config.json`);
|
||||||
queue.awaitAll(callback);
|
queue.awaitAll(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ module.exports = function () {
|
|||||||
this.DEFAULT_ENVIRONMENT = Object.assign({STXXLCFG: stxxl_config}, process.env);
|
this.DEFAULT_ENVIRONMENT = Object.assign({STXXLCFG: stxxl_config}, process.env);
|
||||||
this.DEFAULT_PROFILE = 'bicycle';
|
this.DEFAULT_PROFILE = 'bicycle';
|
||||||
this.DEFAULT_INPUT_FORMAT = 'osm';
|
this.DEFAULT_INPUT_FORMAT = 'osm';
|
||||||
this.DEFAULT_LOAD_METHOD = 'datastore';
|
this.DEFAULT_LOAD_METHOD = process.env.OSRM_LOAD_METHOD && process.env.OSRM_LOAD_METHOD || 'datastore';
|
||||||
this.DEFAULT_ORIGIN = [1,1];
|
this.DEFAULT_ORIGIN = [1,1];
|
||||||
this.OSM_USER = 'osrm';
|
this.OSM_USER = 'osrm';
|
||||||
this.OSM_UID = 1;
|
this.OSM_UID = 1;
|
||||||
|
|||||||
@ -25,15 +25,18 @@ module.exports = function () {
|
|||||||
this.profile = this.OSRM_PROFILE || this.DEFAULT_PROFILE;
|
this.profile = this.OSRM_PROFILE || this.DEFAULT_PROFILE;
|
||||||
this.profileFile = path.join(this.PROFILES_PATH, this.profile + '.lua');
|
this.profileFile = path.join(this.PROFILES_PATH, this.profile + '.lua');
|
||||||
this.setupFeatureCache(feature);
|
this.setupFeatureCache(feature);
|
||||||
|
this.feature = feature;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.Before((scenario, callback) => {
|
this.Before((scenario, callback) => {
|
||||||
|
this.scenario = scenario;
|
||||||
this.osrmLoader.setLoadMethod(this.DEFAULT_LOAD_METHOD);
|
this.osrmLoader.setLoadMethod(this.DEFAULT_LOAD_METHOD);
|
||||||
this.setGridSize(this.DEFAULT_GRID_SIZE);
|
this.setGridSize(this.DEFAULT_GRID_SIZE);
|
||||||
this.setOrigin(this.DEFAULT_ORIGIN);
|
this.setOrigin(this.DEFAULT_ORIGIN);
|
||||||
this.queryParams = {};
|
this.queryParams = {};
|
||||||
this.extractArgs = '';
|
this.extractArgs = '';
|
||||||
|
this.vahallaAdminDB = '';
|
||||||
this.contractArgs = '';
|
this.contractArgs = '';
|
||||||
this.partitionArgs = '';
|
this.partitionArgs = '';
|
||||||
this.customizeArgs = '';
|
this.customizeArgs = '';
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
var Timeout = require('node-timeout');
|
var Timeout = require('node-timeout');
|
||||||
var request = require('request');
|
var request = require('request');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
this.paramsToString = (params) => {
|
this.paramsToString = (params) => {
|
||||||
@ -22,13 +23,20 @@ module.exports = function () {
|
|||||||
// FIXME this needs to be simplified!
|
// FIXME this needs to be simplified!
|
||||||
// - remove usage of node-timeout
|
// - remove usage of node-timeout
|
||||||
// - replace with node's native timout mechanism
|
// - replace with node's native timout mechanism
|
||||||
this.sendRequest = (baseUri, parameters, callback) => {
|
this.sendRequest = (baseUri, parameters, type, logfile, callback) => {
|
||||||
var limit = Timeout(this.TIMEOUT, { err: { statusCode: 408 } });
|
var limit = Timeout(this.TIMEOUT, { err: { statusCode: 408 } });
|
||||||
|
|
||||||
var runRequest = (cb) => {
|
var runRequest = (cb) => {
|
||||||
var params = this.paramsToString(parameters);
|
|
||||||
this.query = baseUri + (params.length ? '/' + params : '');
|
|
||||||
|
|
||||||
|
if (type === 'GET') {
|
||||||
|
|
||||||
|
var params = this.paramsToString(parameters);
|
||||||
|
console.log(params);
|
||||||
|
this.query = baseUri + (params.length ? ((params[0] != '?') ? '/' : '' + params) : '');
|
||||||
|
|
||||||
|
console.log(this.query);
|
||||||
|
|
||||||
|
if (logfile && typeof logfile !== 'function') fs.writeFileSync(logfile, `GET ${this.query}`);
|
||||||
request(this.query, (err, res, body) => {
|
request(this.query, (err, res, body) => {
|
||||||
if (err && err.code === 'ECONNREFUSED') {
|
if (err && err.code === 'ECONNREFUSED') {
|
||||||
return cb(new Error('*** osrm-routed is not running.'));
|
return cb(new Error('*** osrm-routed is not running.'));
|
||||||
@ -38,6 +46,19 @@ module.exports = function () {
|
|||||||
|
|
||||||
return cb(err, res, body);
|
return cb(err, res, body);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
this.query = baseUri;
|
||||||
|
if (logfile && typeof logfile !== 'function') fs.writeFileSync(logfile, `POST ${this.query}\n\n${JSON.stringify(parameters)}`);
|
||||||
|
request.post(this.query, {body: JSON.stringify(parameters)}, (err, res, body) => {
|
||||||
|
if (err && err.code === 'ECONNREFUSED') {
|
||||||
|
return cb(new Error('*** osrm-routed is not running.'));
|
||||||
|
} else if (err && err.statusCode === 408) {
|
||||||
|
return cb(new Error());
|
||||||
|
}
|
||||||
|
|
||||||
|
return cb(err, res, body);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
runRequest(limit((err, res, body) => {
|
runRequest(limit((err, res, body) => {
|
||||||
|
|||||||
@ -5,15 +5,15 @@ const request = require('request');
|
|||||||
const ensureDecimal = require('../lib/utils').ensureDecimal;
|
const ensureDecimal = require('../lib/utils').ensureDecimal;
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
this.requestPath = (service, params, callback) => {
|
this.requestPath = (service, params, logfile, callback) => {
|
||||||
var uri;
|
var uri;
|
||||||
if (service == 'timestamp') {
|
if (service == 'timestamp' || this.osrmLoader.method === 'valhalla') {
|
||||||
uri = [this.HOST, service].join('/');
|
uri = [this.HOST, service].join('/');
|
||||||
} else {
|
} else {
|
||||||
uri = [this.HOST, service, 'v1', this.profile].join('/');
|
uri = [this.HOST, service, 'v1', this.profile].join('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.sendRequest(uri, params, callback);
|
return this.sendRequest(uri, params, 'GET', logfile, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.requestUrl = (path, callback) => {
|
this.requestUrl = (path, callback) => {
|
||||||
@ -46,7 +46,7 @@ module.exports = function () {
|
|||||||
return waypoints.map(w => [w.lon, w.lat].map(ensureDecimal).join(','));
|
return waypoints.map(w => [w.lon, w.lat].map(ensureDecimal).join(','));
|
||||||
};
|
};
|
||||||
|
|
||||||
this.requestRoute = (waypoints, bearings, approaches, userParams, callback) => {
|
this.requestRoute = (waypoints, bearings, approaches, userParams, logfile, callback) => {
|
||||||
if (bearings.length && bearings.length !== waypoints.length) throw new Error('*** number of bearings does not equal the number of waypoints');
|
if (bearings.length && bearings.length !== waypoints.length) throw new Error('*** number of bearings does not equal the number of waypoints');
|
||||||
if (approaches.length && approaches.length !== waypoints.length) throw new Error('*** number of approaches does not equal the number of waypoints');
|
if (approaches.length && approaches.length !== waypoints.length) throw new Error('*** number of approaches does not equal the number of waypoints');
|
||||||
|
|
||||||
@ -60,6 +60,8 @@ module.exports = function () {
|
|||||||
|
|
||||||
params.coordinates = encodedWaypoints;
|
params.coordinates = encodedWaypoints;
|
||||||
|
|
||||||
|
console.log(params);
|
||||||
|
|
||||||
if (bearings.length) {
|
if (bearings.length) {
|
||||||
params.bearings = bearings.map(b => {
|
params.bearings = bearings.map(b => {
|
||||||
var bs = b.split(',');
|
var bs = b.split(',');
|
||||||
@ -71,7 +73,29 @@ module.exports = function () {
|
|||||||
if (approaches.length) {
|
if (approaches.length) {
|
||||||
params.approaches = approaches.join(';');
|
params.approaches = approaches.join(';');
|
||||||
}
|
}
|
||||||
return this.requestPath('route', params, callback);
|
|
||||||
|
if (this.osrmLoader.method === 'valhalla') {
|
||||||
|
|
||||||
|
var val_costing = 'auto';
|
||||||
|
if (this.profile === 'bicycle') {
|
||||||
|
val_costing = 'bicycle';
|
||||||
|
} else if (this.profile === 'foot') {
|
||||||
|
val_costing = 'pedestrian';
|
||||||
|
}
|
||||||
|
|
||||||
|
params = {
|
||||||
|
json: JSON.stringify({
|
||||||
|
locations: waypoints.map(w => {return{ lat: w.lat, lon: w.lon, node_snap_tolerance: 0};}),
|
||||||
|
costing: val_costing,
|
||||||
|
directions_options:{
|
||||||
|
units:'miles'}
|
||||||
|
}),
|
||||||
|
format: 'osrm'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return this.requestPath('route', params, logfile, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.requestNearest = (node, userParams, callback) => {
|
this.requestNearest = (node, userParams, callback) => {
|
||||||
@ -166,6 +190,7 @@ module.exports = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.bearingList = (instructions) => {
|
this.bearingList = (instructions) => {
|
||||||
|
|
||||||
return this.extractInstructionList(instructions, s => ('in' in s.intersections[0] ? this.reverseBearing(s.intersections[0].bearings[s.intersections[0].in]) : 0)
|
return this.extractInstructionList(instructions, s => ('in' in s.intersections[0] ? this.reverseBearing(s.intersections[0].bearings[s.intersections[0].in]) : 0)
|
||||||
+ '->' +
|
+ '->' +
|
||||||
('out' in s.intersections[0] ? s.intersections[0].bearings[s.intersections[0].out] : 0));
|
('out' in s.intersections[0] ? s.intersections[0].bearings[s.intersections[0].out] : 0));
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
|
var polyline = require('polyline');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
this.ShouldGetAResponse = () => {
|
this.ShouldGetAResponse = () => {
|
||||||
@ -28,10 +30,11 @@ module.exports = function () {
|
|||||||
if (e) return callback(e);
|
if (e) return callback(e);
|
||||||
var headers = new Set(table.raw()[0]);
|
var headers = new Set(table.raw()[0]);
|
||||||
|
|
||||||
var requestRow = (row, ri, cb) => {
|
var requestRow = (row, rowIndex, cb) => {
|
||||||
var got;
|
var got;
|
||||||
|
|
||||||
var afterRequest = (err, res, body) => {
|
var afterRequest = (err, res, body) => {
|
||||||
|
console.log(body);
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
if (body && body.length) {
|
if (body && body.length) {
|
||||||
let destinations, exits, pronunciations, instructions, refs, bearings, turns, modes, times, classes,
|
let destinations, exits, pronunciations, instructions, refs, bearings, turns, modes, times, classes,
|
||||||
@ -40,31 +43,80 @@ module.exports = function () {
|
|||||||
|
|
||||||
let json = JSON.parse(body);
|
let json = JSON.parse(body);
|
||||||
|
|
||||||
|
var hasRoute = false;
|
||||||
got.code = json.code;
|
got.code = json.code;
|
||||||
|
hasRoute = json.code === 'Ok' || json.code;
|
||||||
let hasRoute = json.code === 'Ok';
|
var route;
|
||||||
|
|
||||||
if (hasRoute) {
|
if (hasRoute) {
|
||||||
instructions = this.wayList(json.routes[0]);
|
route = json.routes[0];
|
||||||
pronunciations = this.pronunciationList(json.routes[0]);
|
instructions = this.wayList(route);
|
||||||
refs = this.refList(json.routes[0]);
|
pronunciations = this.pronunciationList(route);
|
||||||
destinations = this.destinationsList(json.routes[0]);
|
refs = this.refList(route);
|
||||||
exits = this.exitsList(json.routes[0]);
|
destinations = this.destinationsList(route);
|
||||||
bearings = this.bearingList(json.routes[0]);
|
exits = this.exitsList(route);
|
||||||
turns = this.turnList(json.routes[0]);
|
bearings = this.bearingList(route);
|
||||||
intersections = this.intersectionList(json.routes[0]);
|
turns = this.turnList(route);
|
||||||
modes = this.modeList(json.routes[0]);
|
intersections = this.intersectionList(route);
|
||||||
driving_sides = this.drivingSideList(json.routes[0]);
|
modes = this.modeList(route);
|
||||||
classes = this.classesList(json.routes[0]);
|
driving_sides = this.drivingSideList(route);
|
||||||
times = this.timeList(json.routes[0]);
|
classes = this.classesList(route);
|
||||||
distances = this.distanceList(json.routes[0]);
|
times = this.timeList(route);
|
||||||
lanes = this.lanesList(json.routes[0]);
|
distances = this.distanceList(route);
|
||||||
summary = this.summary(json.routes[0]);
|
lanes = this.lanesList(route);
|
||||||
locations = this.locations(json.routes[0]);
|
summary = this.summary(route);
|
||||||
annotation = this.annotationList(json.routes[0]);
|
locations = this.locations(route);
|
||||||
weight_name = this.weightName(json.routes[0]);
|
annotation = this.annotationList(route);
|
||||||
weights = this.weightList(json.routes[0]);
|
weight_name = this.weightName(route);
|
||||||
approaches = this.approachList(json.routes[0]);
|
weights = this.weightList(route);
|
||||||
|
approaches = this.approachList(route);
|
||||||
|
|
||||||
|
|
||||||
|
fs.writeFileSync(`${this.scenarioCacheFile}_${rowIndex}_response.json`,body);
|
||||||
|
|
||||||
|
var geojson = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
type: 'Feature',
|
||||||
|
properties: { type: 'startpoint' },
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [parseFloat(waypoints[0].lon),parseFloat(waypoints[0].lat)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
type: 'Feature',
|
||||||
|
properties: { type: 'endpoint' },
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [parseFloat(waypoints[1].lon), parseFloat(waypoints[1].lat)]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Feature',
|
||||||
|
geometry: {
|
||||||
|
type: 'LineString',
|
||||||
|
coordinates: []
|
||||||
|
},
|
||||||
|
properties: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
// OSRM route geometry
|
||||||
|
// TODO: Assume polyline5 for now
|
||||||
|
if (typeof route.geometry === 'string') {
|
||||||
|
if (this.osrmLoader.method === 'valhalla') {
|
||||||
|
geojson.features[2].geometry.coordinates = polyline.decode(route.geometry,6).map(c => c.reverse());
|
||||||
|
} else {
|
||||||
|
geojson.features[2].geometry.coordinates = polyline.decode(route.geometry).map(c => c.reverse());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
geojson.features[2].geometry = route.geometry;
|
||||||
|
}
|
||||||
|
fs.writeFileSync(`${this.scenarioCacheFile}_${rowIndex}_shape.geojson`,JSON.stringify(geojson));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headers.has('status')) {
|
if (headers.has('status')) {
|
||||||
@ -99,9 +151,9 @@ module.exports = function () {
|
|||||||
got.alternative = this.wayList(json.routes[1]);
|
got.alternative = this.wayList(json.routes[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var distance = hasRoute && json.routes[0].distance,
|
var distance = hasRoute && route.distance,
|
||||||
time = hasRoute && json.routes[0].duration,
|
time = hasRoute && route.duration,
|
||||||
weight = hasRoute && json.routes[0].weight;
|
weight = hasRoute && route.weight;
|
||||||
|
|
||||||
if (headers.has('distance')) {
|
if (headers.has('distance')) {
|
||||||
if (row.distance.length) {
|
if (row.distance.length) {
|
||||||
@ -200,6 +252,16 @@ module.exports = function () {
|
|||||||
putValue('driving_side', driving_sides);
|
putValue('driving_side', driving_sides);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var resultdata = {
|
||||||
|
feature: this.feature.getName(),
|
||||||
|
scenario: this.scenario.getName(),
|
||||||
|
row: rowIndex,
|
||||||
|
expected: table.hashes()[rowIndex],
|
||||||
|
got: got
|
||||||
|
}
|
||||||
|
console.log(resultdata);
|
||||||
|
fs.writeFileSync(`${this.scenarioCacheFile}_${rowIndex}_results.json`,JSON.stringify(resultdata));
|
||||||
|
|
||||||
for (var key in row) {
|
for (var key in row) {
|
||||||
if (this.FuzzyMatch.match(got[key], row[key])) {
|
if (this.FuzzyMatch.match(got[key], row[key])) {
|
||||||
got[key] = row[key];
|
got[key] = row[key];
|
||||||
@ -257,7 +319,9 @@ module.exports = function () {
|
|||||||
|
|
||||||
got.from = row.from;
|
got.from = row.from;
|
||||||
got.to = row.to;
|
got.to = row.to;
|
||||||
this.requestRoute(waypoints, bearings, approaches, params, afterRequest);
|
|
||||||
|
this.currentRowIndex = rowIndex;
|
||||||
|
this.requestRoute(waypoints, bearings, approaches, params, `${this.scenarioCacheFile}_${rowIndex}_request.txt`, afterRequest);
|
||||||
} else if (row.waypoints) {
|
} else if (row.waypoints) {
|
||||||
row.waypoints.split(',').forEach((n) => {
|
row.waypoints.split(',').forEach((n) => {
|
||||||
var node = this.findNodeByName(n.trim());
|
var node = this.findNodeByName(n.trim());
|
||||||
@ -265,7 +329,7 @@ module.exports = function () {
|
|||||||
waypoints.push(node);
|
waypoints.push(node);
|
||||||
});
|
});
|
||||||
got.waypoints = row.waypoints;
|
got.waypoints = row.waypoints;
|
||||||
this.requestRoute(waypoints, bearings, approaches, params, afterRequest);
|
this.requestRoute(waypoints, bearings, approaches, params, `${this.scenarioCacheFile}_${rowIndex}_request.txt`, afterRequest);
|
||||||
} else {
|
} else {
|
||||||
return cb(new Error('*** no waypoints'));
|
return cb(new Error('*** no waypoints'));
|
||||||
}
|
}
|
||||||
|
|||||||
6498
package-lock.json
generated
6498
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -4,11 +4,15 @@
|
|||||||
"private": false,
|
"private": false,
|
||||||
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"carto": "^0.18.2",
|
||||||
|
"mapnik": "^3.6.2",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"nan": "^2.6.2",
|
"nan": "^2.6.2",
|
||||||
"node-cmake": "^2.3.2",
|
"node-cmake": "^2.3.2",
|
||||||
"node-pre-gyp": "^0.6.36",
|
"node-pre-gyp": "^0.6.36",
|
||||||
"rimraf": "^2.5.4"
|
"osmtogeojson": "^3.0.0-beta.3",
|
||||||
|
"rimraf": "^2.5.4",
|
||||||
|
"xmldoc": "^1.1.0"
|
||||||
},
|
},
|
||||||
"browserify": {
|
"browserify": {
|
||||||
"transform": [
|
"transform": [
|
||||||
|
|||||||
243
scripts/tests2doc.js
Normal file
243
scripts/tests2doc.js
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
"use strict"
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const d3 = require('d3-queue');
|
||||||
|
|
||||||
|
|
||||||
|
var mapnik = require('mapnik');
|
||||||
|
|
||||||
|
mapnik.register_default_input_plugins();
|
||||||
|
mapnik.register_default_fonts()
|
||||||
|
|
||||||
|
//console.log(mapnik.fonts());
|
||||||
|
mapnik.registerFonts("/usr/share/fonts", { recurse: true });
|
||||||
|
|
||||||
|
const find = (dir) =>
|
||||||
|
fs.readdirSync(dir)
|
||||||
|
.reduce((files, file) =>
|
||||||
|
fs.statSync(path.join(dir, file)).isDirectory() ?
|
||||||
|
files.concat(find(path.join(dir, file))) :
|
||||||
|
files.concat(path.join(dir, file)),
|
||||||
|
[]);
|
||||||
|
|
||||||
|
function makemappng(basefile, routefile, callback) {
|
||||||
|
|
||||||
|
var stylesheet = `
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE Map[]>
|
||||||
|
<Map srs="+init=epsg:3857" buffer-size="8">
|
||||||
|
|
||||||
|
<Style name="testmap" filter-mode="all">
|
||||||
|
<Rule>
|
||||||
|
<Filter>[highway] = 'motorway'</Filter>
|
||||||
|
<LineSymbolizer stroke-width="12" stroke-linejoin="round" stroke-linecap="round" stroke="#bbbbbb" />
|
||||||
|
<LineSymbolizer stroke-width="10" stroke-linejoin="round" stroke-linecap="round" stroke="#aacc77" />
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='-10'>'name=' + [name]</TextSymbolizer>
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='10'>'highway=' + [highway]</TextSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
<Rule>
|
||||||
|
<Filter>[highway] = 'motorway_link'</Filter>
|
||||||
|
<LineSymbolizer stroke-width="12" stroke-linejoin="round" stroke-linecap="round" stroke="#bbbbbb" />
|
||||||
|
<LineSymbolizer stroke-width="10" stroke-linejoin="round" stroke-linecap="round" stroke="#77aacc" />
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='-10'>'name=' + [name]</TextSymbolizer>
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='10'>'highway=' + [highway]</TextSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
|
||||||
|
<Rule>
|
||||||
|
<Filter>[highway] = 'trunk'</Filter>
|
||||||
|
<LineSymbolizer stroke-width="12" stroke-linejoin="round" stroke-linecap="round" stroke="#bbbbbb" />
|
||||||
|
<LineSymbolizer stroke-width="10" stroke-linejoin="round" stroke-linecap="round" stroke="#ccaa77" />
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='-10'>'name=' + [name]</TextSymbolizer>
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='10'>'highway=' + [highway]</TextSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
<Rule>
|
||||||
|
<Filter>[highway] = 'trunk_link'</Filter>
|
||||||
|
<LineSymbolizer stroke-width="12" stroke-linejoin="round" stroke-linecap="round" stroke="#bbbbbb" />
|
||||||
|
<LineSymbolizer stroke-width="10" stroke-linejoin="round" stroke-linecap="round" stroke="#aa77cc" />
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='-10'>'name=' + [name]</TextSymbolizer>
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='10'>'highway=' + [highway]</TextSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
|
||||||
|
<Rule>
|
||||||
|
<Filter>[highway] = 'primary'</Filter>
|
||||||
|
<LineSymbolizer stroke-width="10" stroke-linejoin="round" stroke-linecap="round" stroke="#bbbbbb" />
|
||||||
|
<LineSymbolizer stroke-width="8" stroke-linejoin="round" stroke-linecap="round" stroke="#77ccaa" />
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='-8'>'name=' + [name]</TextSymbolizer>
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='8'>'highway=' + [highway]</TextSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
<Rule>
|
||||||
|
<Filter>[highway] = 'primary_link'</Filter>
|
||||||
|
<LineSymbolizer stroke-width="10" stroke-linejoin="round" stroke-linecap="round" stroke="#bbbbbb" />
|
||||||
|
<LineSymbolizer stroke-width="8" stroke-linejoin="round" stroke-linecap="round" stroke="#aa77cc" />
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='-8'>'name=' + [name]</TextSymbolizer>
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='8'>'highway=' + [highway]</TextSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
|
||||||
|
<Rule>
|
||||||
|
<Filter>[highway] = 'secondary' or [highway] = 'secondary_link' or [highway] = 'tertiary' or [highway] = 'tertiary_link' or [highway] = 'residential' or [highway] = 'service' or [highway] = 'living_street'</Filter>
|
||||||
|
<LineSymbolizer stroke-width="10" stroke-linejoin="round" stroke-linecap="round" stroke="#bbbbbb" />
|
||||||
|
<LineSymbolizer stroke-width="8" stroke-linejoin="round" stroke-linecap="round" stroke="#77bb77" />
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='-8'>'name=' + [name]</TextSymbolizer>
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='8'>'highway=' + [highway]</TextSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
|
||||||
|
<Rule>
|
||||||
|
<Filter>[route] = 'ferry'</Filter>
|
||||||
|
<LineSymbolizer stroke-width="10" stroke-linejoin="round" stroke-linecap="round" stroke="#bbbbbb" />
|
||||||
|
<LineSymbolizer stroke-width="8" stroke-linejoin="round" stroke-linecap="round" stroke="#7777bb" />
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='-8'>'name=' + [name]</TextSymbolizer>
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Bold" size="10" fill="black" placement="line" allow-overlap="true" dy='8'>'route=' + [route]</TextSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Layer name="testmap" srs="+init=epsg:4326">
|
||||||
|
<StyleName>testmap</StyleName>
|
||||||
|
<Datasource>
|
||||||
|
<Parameter name="type">geojson</Parameter>
|
||||||
|
<Parameter name="file">${basefile}</Parameter>
|
||||||
|
</Datasource>
|
||||||
|
</Layer>
|
||||||
|
|
||||||
|
<Style name="testroute-line" filter-mode="all">
|
||||||
|
<Rule>
|
||||||
|
<LineSymbolizer stroke-width="5" stroke-linejoin="round" stroke-linecap="round" stroke="#000077" offset="6"/>
|
||||||
|
<LineSymbolizer stroke-width="3" stroke-linejoin="round" stroke-linecap="round" stroke="#0000ff" offset="6"/>
|
||||||
|
</Rule>
|
||||||
|
</Style>
|
||||||
|
<Style name="testroute-markers" filter-mode="first">
|
||||||
|
<Rule>
|
||||||
|
<Filter>[type] = 'startpoint'</Filter>
|
||||||
|
<MarkersSymbolizer fill="green" width="20" height="20" stroke="green" allow-overlap="true"/>
|
||||||
|
</Rule>
|
||||||
|
<Rule>
|
||||||
|
<Filter>[type] = 'endpoint'</Filter>
|
||||||
|
<MarkersSymbolizer fill="red" width="20" height="20" stroke="red" allow-overlap="true"/>
|
||||||
|
</Rule>
|
||||||
|
</Style>
|
||||||
|
<Layer name="testroute" srs="+init=epsg:4326">
|
||||||
|
<StyleName>testroute-line</StyleName>
|
||||||
|
<StyleName>testroute-markers</StyleName>
|
||||||
|
<Datasource>
|
||||||
|
<Parameter name="type">geojson</Parameter>
|
||||||
|
<Parameter name="file">${routefile}</Parameter>
|
||||||
|
</Datasource>
|
||||||
|
</Layer>
|
||||||
|
</Map>`;
|
||||||
|
|
||||||
|
var map = new mapnik.Map(400, 300);
|
||||||
|
map.fromStringSync(stylesheet,{strict:true});
|
||||||
|
map.zoomAll();
|
||||||
|
|
||||||
|
var extent = map.extent;
|
||||||
|
extent[0] = extent[0] - Math.abs(extent[0]) * 0.00005;
|
||||||
|
extent[1] = extent[1] - Math.abs(extent[1]) * 0.00005;
|
||||||
|
|
||||||
|
extent[2] = extent[2] + Math.abs(extent[2]) * 0.00005;
|
||||||
|
extent[3] = extent[3] + Math.abs(extent[3]) * 0.00005;
|
||||||
|
map.zoomToBox(extent);
|
||||||
|
|
||||||
|
var buffer = new mapnik.Image(400,300)
|
||||||
|
map.render(buffer, {}, (err,image) => {
|
||||||
|
callback(image.encodeSync('png'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var report = "";
|
||||||
|
|
||||||
|
var toc = [];
|
||||||
|
|
||||||
|
find('test/cache').filter((f) => f.match(/[0-9]+_results.json$/)).forEach((f) => {
|
||||||
|
var files = f.match(/(.*?)_([0-9]+)_results.json$/,f);
|
||||||
|
|
||||||
|
var results = JSON.parse(fs.readFileSync(f));
|
||||||
|
|
||||||
|
// Generate map image
|
||||||
|
var imagefile = `${files[1]}_${files[2]}.png`.replace(/\//g,'_');
|
||||||
|
var png = makemappng(`${files[1]}.geojson`, `${files[1]}_${files[2]}_shape.geojson`, (png) => {
|
||||||
|
fs.writeFileSync(`report/${imagefile}`,png);
|
||||||
|
});
|
||||||
|
|
||||||
|
var osmfile = `${files[1]}`.replace(/\//g,'_');
|
||||||
|
var pbffile = `${files[1]}`.replace(/\//g,'_').replace(/.osm/,'.pbf');
|
||||||
|
var responsefile = `${files[1]}_${files[2]}_response.json`.replace(/\//g,'_');
|
||||||
|
var requestfile = `${files[1]}_${files[2]}_request.txt`.replace(/\//g,'_');
|
||||||
|
|
||||||
|
fs.writeFileSync(`report/${osmfile}`, fs.readFileSync(files[1]));
|
||||||
|
fs.writeFileSync(`report/${pbffile}`, fs.readFileSync(`${files[1].replace(/.osm$/,'.pbf')}`));
|
||||||
|
fs.writeFileSync(`report/${responsefile}`, fs.readFileSync(`${files[1]}_${files[2]}_response.json`));
|
||||||
|
fs.writeFileSync(`report/${requestfile}`, fs.readFileSync(`${files[1]}_${files[2]}_request.txt`));
|
||||||
|
|
||||||
|
toc.push({ title: `${results.feature} - ${results.scenario}`, link: imagefile });
|
||||||
|
|
||||||
|
if (typeof results.got.turns === 'object')
|
||||||
|
results.got.turns = results.got.turns.join(',');
|
||||||
|
|
||||||
|
if (typeof results.expected.turns === 'string')
|
||||||
|
results.expected.turns = results.expected.turns.replace(/slight /g,'').replace(/sharp /g, '');
|
||||||
|
if (typeof results.got.turns === 'string')
|
||||||
|
results.got.turns = results.got.turns.replace(/slight /g,'').replace(/sharp /g, '');
|
||||||
|
|
||||||
|
report += `<div class='scenario ${results.got.turns == results.expected.turns ? 'ok' : 'error'}'>
|
||||||
|
<h2><a href="${imagefile}">[link]</a> <a name="${imagefile}">${results.feature} - ${results.scenario}</a></h2>
|
||||||
|
<a href="${osmfile}">Download OSM XML file for this test</a><br/>
|
||||||
|
<a href="${pbffile}">Download OSM PBF file for this test</a><br/>
|
||||||
|
<a href="${requestfile}">Download request used for this test</a><br/>
|
||||||
|
<a href="${responsefile}">Download raw response for this test</a>
|
||||||
|
|
||||||
|
<table class="row">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="${imagefile}"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<table class="results">
|
||||||
|
<tr><th/>`;
|
||||||
|
Object.keys(results.expected).forEach((k) => {
|
||||||
|
report += `<th style="text-align: left">${k}</th>`;
|
||||||
|
});
|
||||||
|
report += `</tr>`;
|
||||||
|
report += `<tr><th style='text-align: right'>OSRM</th>`;
|
||||||
|
Object.keys(results.expected).forEach((k) => {
|
||||||
|
report += `<td style="text-align: left">${results.expected[k]}</td>`;
|
||||||
|
});
|
||||||
|
report += `</tr>`;
|
||||||
|
report += `<tr><th style='text-align: right'>Valhalla</th>`;
|
||||||
|
Object.keys(results.expected).forEach((k) => {
|
||||||
|
report += `<td style="text-align: left" class="${results.expected[k] === results.got[k] ? "ok" :"error" }">${results.got[k]}</td>`;
|
||||||
|
});
|
||||||
|
report += `</tr>
|
||||||
|
</table>
|
||||||
|
</td></tr></table>
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Generate HTML table
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`
|
||||||
|
<!DOCYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body { font-family: sans-serif; }
|
||||||
|
.results td { padding-left: 1em; font-family: monospace; }
|
||||||
|
.results th { padding-left: 1em; }
|
||||||
|
.scenario.error { background: #fbb; }
|
||||||
|
.error { color: red; }
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
Notes: OSRM "slight" and "sharp" indicators have been removed for comparison purposes.
|
||||||
|
<hr/>
|
||||||
|
`);
|
||||||
|
toc.forEach(r => {
|
||||||
|
console.log(`<a href='#${r.link}'>${r.title}</a><br/>`);
|
||||||
|
});
|
||||||
|
console.log(report);
|
||||||
|
console.log(`
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`);
|
||||||
Loading…
Reference in New Issue
Block a user