From df1ca81bb49de2e33c52a28f42b0c0adb1be0f04 Mon Sep 17 00:00:00 2001 From: Huyen Chau Nguyen Date: Fri, 28 Aug 2015 18:30:10 +0200 Subject: [PATCH] add trip plugin --- src/node_osrm.cpp | 117 +++++++++++++++++++++++++++++++++ test/osrm.test.js | 163 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 280 insertions(+) diff --git a/src/node_osrm.cpp b/src/node_osrm.cpp index 22dc13b..162186b 100644 --- a/src/node_osrm.cpp +++ b/src/node_osrm.cpp @@ -37,6 +37,7 @@ class Engine final : public node::ObjectWrap { static NAN_METHOD(nearest); static NAN_METHOD(table); static NAN_METHOD(match); + static NAN_METHOD(trip); static void Run(_NAN_METHOD_ARGS, route_parameters_ptr); static void AsyncRun(uv_work_t*); @@ -63,6 +64,7 @@ void Engine::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(lcons, "nearest", nearest); NODE_SET_PROTOTYPE_METHOD(lcons, "table", table); NODE_SET_PROTOTYPE_METHOD(lcons, "match", match); + NODE_SET_PROTOTYPE_METHOD(lcons, "trip", trip); lcons->Set(NanNew("libosrm_version"), NanNew(LIBOSRM_GIT_REVISION)); target->Set(NanNew("OSRM"), lcons->GetFunction()); NanAssignPersistent(constructor, lcons); @@ -377,6 +379,121 @@ NAN_METHOD(Engine::match) NanReturnUndefined(); } +// uses the same options as viaroute +NAN_METHOD(Engine::trip) +{ + NanScope(); + + if (args.Length() < 2) { + NanThrowTypeError("two arguments required"); + NanReturnUndefined(); + } + + if (!args[0]->IsObject()) { + NanThrowTypeError("first arg must be an object"); + NanReturnUndefined(); + } + + Local obj = args[0]->ToObject(); + + route_parameters_ptr params = make_unique(); + + params->zoom_level = 18; //no generalization + params->print_instructions = false; //turn by turn instructions + params->alternate_route = false; //get an alternate route, too + params->geometry = true; //retrieve geometry of route + params->compression = true; //polyline encoding + params->check_sum = 0; //see wiki + params->service = "trip"; //that's routing + params->output_format = "json"; + params->jsonp_parameter = ""; //set for jsonp wrapping + params->language = ""; //unused atm + + if (!obj->Has(NanNew("coordinates"))) { + NanThrowError("must provide a coordinates property"); + NanReturnUndefined(); + } + + Local coordinates = obj->Get(NanNew("coordinates")); + if (!coordinates->IsArray()) { + NanThrowError("coordinates must be an array of (lat/long) pairs"); + NanReturnUndefined(); + } + + Local coordinates_array = Local::Cast(coordinates); + if (coordinates_array->Length() < 2) { + NanThrowError("at least two coordinates must be provided"); + NanReturnUndefined(); + } + + for (uint32_t i = 0; i < coordinates_array->Length(); ++i) { + Local coordinate = coordinates_array->Get(i); + + if (!coordinate->IsArray()) { + NanThrowError("coordinates must be an array of (lat/long) pairs"); + NanReturnUndefined(); + } + + Local coordinate_pair = Local::Cast(coordinate); + if (coordinate_pair->Length() != 2) { + NanThrowError("coordinates must be an array of (lat/long) pairs"); + NanReturnUndefined(); + } + + params->coordinates.emplace_back(static_cast(coordinate_pair->Get(0)->NumberValue()*COORDINATE_PRECISION), + static_cast(coordinate_pair->Get(1)->NumberValue()*COORDINATE_PRECISION)); + } + + if (obj->Has(NanNew("alternateRoute"))) { + params->alternate_route = obj->Get(NanNew("alternateRoute"))->BooleanValue(); + } + + if (obj->Has(NanNew("checksum"))) { + params->check_sum = static_cast(obj->Get(NanNew("checksum"))->Uint32Value()); + } + + if (obj->Has(NanNew("zoomLevel"))) { + params->zoom_level = static_cast(obj->Get(NanNew("zoomLevel"))->Int32Value()); + } + + if (obj->Has(NanNew("printInstructions"))) { + params->print_instructions = obj->Get(NanNew("printInstructions"))->BooleanValue(); + } + + if (obj->Has(NanNew("geometry"))) { + params->geometry = obj->Get(NanNew("geometry"))->BooleanValue(); + } + + if (obj->Has(NanNew("jsonpParameter"))) { + params->jsonp_parameter = *v8::String::Utf8Value(obj->Get(NanNew("jsonpParameter"))); + } + + if (obj->Has(NanNew("hints"))) { + Local hints = obj->Get(NanNew("hints")); + + if (!hints->IsArray()) { + NanThrowError("hints must be an array of strings/null"); + NanReturnUndefined(); + } + + Local hints_array = Local::Cast(hints); + for (uint32_t i = 0; i < hints_array->Length(); ++i) { + Local hint = hints_array->Get(i); + if (hint->IsString()) { + params->hints.push_back(*v8::String::Utf8Value(hint)); + } else if(hint->IsNull()){ + params->hints.push_back(""); + }else{ + NanThrowError("hint must be null or string"); + NanReturnUndefined(); + } + } + } + + Run(args, std::move(params)); + NanReturnUndefined(); +} + NAN_METHOD(Engine::table) { NanScope(); diff --git a/test/osrm.test.js b/test/osrm.test.js index e652740..363656f 100644 --- a/test/osrm.test.js +++ b/test/osrm.test.js @@ -1,6 +1,8 @@ var OSRM = require('../'); var assert = require('assert'); +///////////////////////////// CONSTRUCTOR TESTS //////////////////////////////// + it('constructor: throws if new keyword is not used', function(done) { assert.throws(function() { OSRM(); }, /Cannot call constructor as function, you need to use 'new' keyword/); @@ -49,6 +51,8 @@ it('constructor: throws if given a non-string/obj argument', function() { /first argument must be a path string or params object/); }); +/////////////////////////////// ROUTE TESTS //////////////////////////////////// + it('route: routes Berlin', function(done) { var osrm = new OSRM("berlin-latest.osrm"); osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}, function(err, route) { @@ -171,6 +175,159 @@ it('route: routes Berlin with null hints', function(done) { }); }); + +/////////////////////////////// TRIP TESTS //////////////////////////////////// + +it('trip: trip in Berlin', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + osrm.trip({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}, function(err, trip) { + assert.ifError(err); + for (t = 0; t < trip.trips.length; t++) { + assert.equal(trip.trips[t].status_message, 'Found route between points'); + } + done(); + }); +}); + +it('trip: trip with many locations in Berlin', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + osrm.trip({coordinates: [[52.51663871100423,13.36761474609375],[52.506191342034576,13.374481201171875],[52.50535544522142,13.404693603515625],[52.50159371284434,13.388900756835938],[52.518727886767266,13.386840820312498],[52.528754547664185,13.4088134765625],[52.51705655410405,13.41156005859375],[52.512042174642346,13.420486450195312],[52.50368360390624,13.413619995117188],[52.504101570196205,13.36212158203125],[52.52248815280757,13.35113525390625],[52.53460237630516,13.36761474609375],[52.53710835019913,13.383407592773438],[52.536690697815736,13.392333984375],[52.532931647583325,13.42529296875],[52.52415927884915,13.399200439453125],[52.51956352925745,13.390960693359375],[52.533349335723294,13.375167846679688],[52.520399155853454,13.37860107421875],[52.52081696319122,13.355255126953125],[52.5143405029259,13.385467529296875],[52.513086884218325,13.398857116699219],[52.50744515744915,13.399200439453125],[52.49783165855699,13.409500122070312],[52.500339730516934,13.424949645996094],[52.50786308797268,13.440055847167969],[52.511624283857785,13.428382873535156],[52.50451953251202,13.437652587890625],[52.5199813445422,13.443145751953125],[52.52520370034151,13.431129455566406],[52.52896341209634,13.418426513671875],[52.517474393230245,13.429069519042969],[52.528127948407935,13.418083190917969],[52.52833681581998,13.405036926269531],[52.53084314728766,13.384437561035156],[52.53084314728766,13.374481201171875],[52.532305107923925,13.3978271484375],[52.526039219655445,13.418769836425781],[52.51642978796417,13.441085815429688],[52.51601193890388,13.448638916015625],[52.50535544522142,13.44623565673828],[52.502638670794546,13.430442810058594],[52.520190250694526,13.358688354492188],[52.531887409851336,13.358001708984375],[52.528545682238736,13.367271423339842],[52.52958999943304,13.387870788574219],[52.53961418106945,13.406410217285156],[52.50556442091497,13.399543762207031],[52.50389258754797,13.374824523925781],[52.51099744023003,13.386154174804688],[52.49657756892365,13.40229034423828]]}, function(err, trip) { + assert.ifError(err); + for (t = 0; t < trip.trips.length; t++) { + assert.equal(trip.trips[t].status_message, 'Found route between points'); + } + done(); + }); +}); + +it('trip: throws with too few or invalid args', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + assert.throws(function() { osrm.trip({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}) }, + /two arguments required/); + assert.throws(function() { osrm.trip(null, function(err, trip) {}) }, + /first arg must be an object/); + done(); +}); + +it('trip: throws with bad params', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + assert.throws(function () { osrm.trip({coordinates: []}, function(err) {}) }); + assert.throws(function() { osrm.trip({}, function(err, trip) {}) }, + /must provide a coordinates property/); + assert.throws(function() { osrm.trip({coordinates: null}, function(err, trip) {}) }, + "coordinates must be an array of (lat/long) pairs"); + assert.throws(function() { osrm.trip({coordinates: [52.519930, 13.438640]}, function(err, trip) {}) }, + "coordinates must be an array of (lat/long) pairs"); + assert.throws(function() { osrm.trip({coordinates: [[52.519930], [13.438640]]}, function(err, trip) {}) }, + "coordinates must be an array of (lat/long) pairs"); + assert.throws(function() { osrm.trip({coordinates: [[52.519930,13.438640], [52.513191,13.415852]], hints: null}, function(err, trip) {}) }, + "hints must be an array of strings/null"); + var options = { + coordinates: [[52.519930,13.438640], [52.513191,13.415852]], + alternateroute: false, + printInstructions: false, + hints: [[52.519930,13.438640]] + }; + assert.throws(function() { osrm.trip(options, function(err, trip) {}) }, + /hint must be null or string/); + done(); +}); + +it('trip: takes jsonp parameter', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + osrm.trip({coordinates: [[52.519930,13.438640], [52.513191,13.415852]], jsonpParameter: 'function'}, function(err, trip) { + assert.ifError(err); + for (t = 0; t < trip.trips.length; t++) { + assert.equal(trip.trips[t].status_message, 'Found route between points'); + } + done(); + }); +}); + +if (process.platform === 'darwin') { + // shared memory does not work on Mac OS for now. + it.skip('trip: routes Berlin using shared memory', function(done) {}); +} else { + it('trip: routes Berlin using shared memory', function(done) { + var osrm = new OSRM(); + osrm.trip({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}, function(err, trip) { + assert.ifError(err); + for (t = 0; t < trip.trips.length; t++) { + assert.equal(trip.trips[t].status_message, 'Found route between points'); + } + done(); + }); + }); +} + +it('trip: routes Berlin with hints', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + var options = { + coordinates: [[52.519930,13.438640], [52.513191,13.415852]], + alternateroute: false, + printInstructions: false + }; + osrm.trip(options, function(err, first) { + assert.ifError(err); + for (t = 0; t < first.trips.length; t++) { + assert.equal(first.trips[t].status_message, 'Found route between points'); + var checksum = first.trips[t].hint_data.checksum; + options.checksum = checksum; + assert.equal("number", typeof(checksum)); + + options.hints = []; + options.hints.length = options.coordinates.length; + + for (p = 0; p < first.trips[t].permutation.length; p++) { + options.hints[first.trips[t].permutation[p]] = first.trips[t].hint_data.locations[p]; + } + } + + osrm.trip(options, function(err, second) { + assert.ifError(err); + assert.deepEqual(first, second); + done(); + }); + }); +}); + +it('trip: trip through Berlin with options', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + var options = { + coordinates: [[52.519930,13.438640], [52.513191,13.415852]], + zoomLevel: 17, + alternateroute: false, + printInstructions: false, + geometry: false + }; + osrm.trip(options, function(err, trip) { + assert.ifError(err); + for (t = 0; t < trip.trips.length; t++) { + assert.equal(trip.trips[t].status_message, 'Found route between points'); + assert.equal(undefined, trip.trips[t].route_instructions); + assert.equal(undefined, trip.trips[t].alternative_geometries); + assert.equal(undefined, trip.trips[t].route_geometry); + } + done(); + }); +}); + +it('trip: routes Berlin with null hints', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + var options = { + coordinates: [[52.519930,13.438640], [52.513191,13.415852]], + alternateRoute: false, + printInstructions: false, + hints: ['', '', ''] + }; + osrm.trip(options, function(err, second) { + assert.ifError(err); + done(); + }); +}); + +/////////////////////////////// TABLE TESTS //////////////////////////////////// + it('table: distance table in Berlin', function(done) { var osrm = new OSRM("berlin-latest.osrm"); var options = { @@ -226,6 +383,8 @@ it('table: throws on invalid arguments', function(done) { done(); }); +/////////////////////////////// MATCH TESTS //////////////////////////////////// + it('match: match in Berlin', function(done) { var osrm = new OSRM("berlin-latest.osrm"); var options = { @@ -318,6 +477,8 @@ it('match: throws on invalid timestamps param', function(done) { done(); }); +////////////////////////////// NEAREST TESTS /////////////////////////////////// + it('nearest', function(done) { var osrm = new OSRM("berlin-latest.osrm"); osrm.nearest([52.4224, 13.333086], function(err, result) { @@ -342,6 +503,8 @@ it('nearest: throws on invalid args', function(done) { done(); }); +////////////////////////////// LOCATE TESTS //////////////////////////////////// + it('locate', function(done) { var osrm = new OSRM("berlin-latest.osrm"); osrm.locate([52.4224, 13.333086], function(err, result) {