From: Patrick Niklaus Date: Sun, 12 Jun 2016 22:23:41 +0000 (+0200) Subject: Add support for OSRM 5.0 API and new instruction types X-Git-Tag: live~3849 X-Git-Url: https://git.openstreetmap.org/rails.git/commitdiff_plain/311acad0c43401fe3d7651d021154af2efbedff5 Add support for OSRM 5.0 API and new instruction types Add support for the new API in OSRM 5.x including new icon sprites for the new instruction types. --- diff --git a/app/assets/images/routing-sprite.png b/app/assets/images/routing-sprite.png index 42ec7b4cd..079f4dd7f 100644 Binary files a/app/assets/images/routing-sprite.png and b/app/assets/images/routing-sprite.png differ diff --git a/app/assets/images/routing-sprite.svg b/app/assets/images/routing-sprite.svg new file mode 100644 index 000000000..15aa57b2d --- /dev/null +++ b/app/assets/images/routing-sprite.svg @@ -0,0 +1,573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 + + + diff --git a/app/assets/javascripts/index/directions/graphhopper.js b/app/assets/javascripts/index/directions/graphhopper.js index c35085b35..9cf1dc1aa 100644 --- a/app/assets/javascripts/index/directions/graphhopper.js +++ b/app/assets/javascripts/index/directions/graphhopper.js @@ -1,15 +1,15 @@ function GraphHopperEngine(id, vehicleType) { var GH_INSTR_MAP = { - "-3": 6, // sharp left - "-2": 7, // left - "-1": 8, // slight left + "-3": 7, // sharp left + "-2": 6, // left + "-1": 5, // slight left 0: 0, // straight 1: 1, // slight right 2: 2, // right 3: 3, // sharp right - 4: -1, // finish reached - 5: -1, // via reached - 6: 11 // roundabout + 4: 8, // finish reached + 5: 8, // via reached + 6: 10 // roundabout }; return { @@ -44,7 +44,7 @@ function GraphHopperEngine(id, vehicleType) { var len = path.instructions.length; for (var i = 0; i < len; i++) { var instr = path.instructions[i]; - var instrCode = (i === len - 1) ? 15 : GH_INSTR_MAP[instr.sign]; + var instrCode = (i === len - 1) ? 14 : GH_INSTR_MAP[instr.sign]; var instrText = "" + (i + 1) + ". "; instrText += instr.text; var latLng = line[instr.interval[0]]; diff --git a/app/assets/javascripts/index/directions/mapquest.js b/app/assets/javascripts/index/directions/mapquest.js index 0f645ceeb..fbfed21cf 100644 --- a/app/assets/javascripts/index/directions/mapquest.js +++ b/app/assets/javascripts/index/directions/mapquest.js @@ -5,25 +5,25 @@ function MapQuestEngine(id, routeType) { var MQ_SPRITE_MAP = { - 0: 1, // straight - 1: 2, // slight right - 2: 3, // right - 3: 4, // sharp right - 4: 5, // reverse - 5: 6, // sharp left - 6: 7, // left - 7: 8, // slight left - 8: 5, // right U-turn - 9: 5, // left U-turn - 10: 2, // right merge - 11: 8, // left merge + 0: 0, // straight + 1: 1, // slight right + 2: 2, // right + 3: 3, // sharp right + 4: 4, // reverse + 5: 5, // sharp left + 6: 6, // left + 7: 7, // slight left + 8: 3, // right U-turn (mapped to shard-right symbol) + 9: 8, // left U-turn + 10: 21, // right merge + 11: 20, // left merge 12: 2, // right on-ramp - 13: 8, // left on-ramp - 14: 2, // right off-ramp - 15: 8, // left off-ramp - 16: 2, // right fork - 17: 8, // left fork - 18: 1 // straight fork + 13: 6, // left on-ramp + 14: 24, // right off-ramp + 15: 25, // left off-ramp + 16: 18, // right fork + 17: 19, // left fork + 18: 0 // straight fork }; return { diff --git a/app/assets/javascripts/index/directions/mapzen.js b/app/assets/javascripts/index/directions/mapzen.js index 348cb99c9..be4af26e4 100644 --- a/app/assets/javascripts/index/directions/mapzen.js +++ b/app/assets/javascripts/index/directions/mapzen.js @@ -1,35 +1,35 @@ function MapzenEngine(id, costing) { var MZ_INSTR_MAP = [ - 1, // kNone = 0; - 14, // kStart = 1; - 14, // kStartRight = 2; - 14, // kStartLeft = 3; - 15, // kDestination = 4; - 15, // kDestinationRight = 5; - 15, // kDestinationLeft = 6; - 1, // kBecomes = 7; - 1, // kContinue = 8; - 2, // kSlightRight = 9; - 3, // kRight = 10; - 4, // kSharpRight = 11; - 5, // kUturnRight = 12; - 5, // kUturnLeft = 13; - 6, // kSharpLeft = 14; - 7, // kLeft = 15; - 8, // kSlightLeft = 16; - 1, // kRampStraight = 17; + 0, // kNone = 0; + 8, // kStart = 1; + 8, // kStartRight = 2; + 8, // kStartLeft = 3; + 14, // kDestination = 4; + 14, // kDestinationRight = 5; + 14, // kDestinationLeft = 6; + 0, // kBecomes = 7; + 0, // kContinue = 8; + 1, // kSlightRight = 9; + 2, // kRight = 10; + 3, // kSharpRight = 11; + 4, // kUturnRight = 12; + 4, // kUturnLeft = 13; + 7, // kSharpLeft = 14; + 6, // kLeft = 15; + 5, // kSlightLeft = 16; + 0, // kRampStraight = 17; 2, // kRampRight = 18; - 8, // kRampLeft = 19; - 2, // kExitRight = 20; - 8, // kExitLeft = 21; - 1, // kStayStraight = 22; + 6, // kRampLeft = 19; + 24, // kExitRight = 20; + 25, // kExitLeft = 21; + 0, // kStayStraight = 22; 2, // kStayRight = 23; - 8, // kStayLeft = 24; - 1, // kMerge = 25; - 11, // kRoundaboutEnter = 26; - 12, // kRoundaboutExit = 27; - 18, // kFerryEnter = 28; - 1 // kFerryExit = 29; + 6, // kStayLeft = 24; + 20, // kMerge = 25; + 10, // kRoundaboutEnter = 26; + 11, // kRoundaboutExit = 27; + 17, // kFerryEnter = 28; + 0 // kFerryExit = 29; ]; return { diff --git a/app/assets/javascripts/index/directions/osrm.js b/app/assets/javascripts/index/directions/osrm.js index 2ee9da12b..6d2d5872c 100644 --- a/app/assets/javascripts/index/directions/osrm.js +++ b/app/assets/javascripts/index/directions/osrm.js @@ -2,100 +2,163 @@ // Doesn't yet support hints function OSRMEngine() { - var previousPoints, hintData; + var cachedHints = []; return { id: "osrm_car", creditline: 'OSRM', draggable: true, + _transformSteps: function(input_steps, line) { + var INSTRUCTION_TEMPLATE = { + 'continue': 'javascripts.directions.instructions.continue', + 'merge right': 'javascripts.directions.instructions.merge_right', + 'merge left': 'javascripts.directions.instructions.merge_left', + 'off ramp right': 'javascripts.directions.instructions.offramp_right', + 'off ramp left': 'javascripts.directions.instructions.offramp_left', + 'on ramp right': 'javascripts.directions.instructions.onramp_right', + 'on ramp left': 'javascripts.directions.instructions.onramp_left', + 'fork right': 'javascripts.directions.instructions.fork_right', + 'fork left': 'javascripts.directions.instructions.fork_left', + 'end of road right': 'javascripts.directions.instructions.endofroad_right', + 'end of road left': 'javascripts.directions.instructions.endofroad_left', + 'turn straight': 'javascripts.directions.instructions.continue', + 'turn slight right': 'javascripts.directions.instructions.slight_right', + 'turn right': 'javascripts.directions.instructions.turn_right', + 'turn sharp right': 'javascripts.directions.instructions.sharp_right', + 'turn uturn': 'javascripts.directions.instructions.uturn', + 'turn sharp left': 'javascripts.directions.instructions.sharp_left', + 'turn left': 'javascripts.directions.instructions.turn_left', + 'turn slight left': 'javascripts.directions.instructions.slight_left', + 'trun straight': 'javascripts.directions.instructions.follow', + 'roundabout': 'javascripts.directions.instructions.roundabout', + 'rotary': 'javascripts.directions.instructions.roundabout', + 'depart': 'javascripts.directions.instructions.start', + 'arrive': 'javascripts.directions.instructions.destination', + }; + var ICON_MAP = { + 'continue': 0, + 'merge right': 21, + 'merge left': 20, + 'off ramp right': 24, + 'off ramp left': 25, + 'on ramp right': 2, + 'on ramp left': 6, + 'fork right': 18, + 'fork left': 19, + 'end of road right': 22, + 'end of road left': 23, + 'turn straight': 0, + 'turn slight right': 1, + 'turn right': 2, + 'turn sharp right': 3, + 'turn uturn': 4, + 'turn slight left': 5, + 'turn left': 6, + 'turn sharp left': 7, + 'trun straight': 0, + 'roundabout': 10, + 'rotary': 10, + 'depart': 8, + 'arrive': 14 + }; + var transformed_steps = input_steps.map(function(step, idx) { + var maneuver_id; + + // special case handling + switch (step.maneuver.type) { + case 'on ramp': + case 'off ramp': + case 'merge': + case 'end of road': + case 'fork': + maneuver_id = step.maneuver.type + ' ' + (step.maneuver.modifier.indexOf('left') >= 0 ? 'left' : 'right'); + break; + case 'depart': + case 'arrive': + case 'roundabout': + case 'rotary': + maneuver_id = step.maneuver.type; + break; + case 'roundabout turn': + case 'turn': + maneuver_id = "turn " + step.maneuver.modifier; + break; + // for unknown types the fallback is turn + default: + maneuver_id = "turn " + step.maneuver.modifier; + break; + } + var template = INSTRUCTION_TEMPLATE[maneuver_id]; + + // convert lat,lng pairs to LatLng objects + var step_geometry = L.PolylineUtil.decode(step.geometry, { precision: 5 }).map(function(a) { return L.latLng(a); }) ; + // append step_geometry on line + Array.prototype.push.apply(line, step_geometry); + + var instText = "" + (idx + 1) + ". "; + var name = step.name ? "" + step.name + "" : I18n.t('javascripts.directions.instructions.unnamed'); + if (step.maneuver.type.match(/rotary|roundabout/)) { + instText += I18n.t(template + '_with_exit', { exit: step.maneuver.exit, name: name } ); + } else { + instText += I18n.t(template + '_without_exit', { name: name }); + } + return [[step.maneuver.location[1], step.maneuver.location[0]], ICON_MAP[maneuver_id], instText, step.distance, step_geometry]; + }); + + return transformed_steps; + }, + getRoute: function (points, callback) { - var TURN_INSTRUCTIONS = [ - "", - 'javascripts.directions.instructions.continue', // 1 - 'javascripts.directions.instructions.slight_right', // 2 - 'javascripts.directions.instructions.turn_right', // 3 - 'javascripts.directions.instructions.sharp_right', // 4 - 'javascripts.directions.instructions.uturn', // 5 - 'javascripts.directions.instructions.sharp_left', // 6 - 'javascripts.directions.instructions.turn_left', // 7 - 'javascripts.directions.instructions.slight_left', // 8 - 'javascripts.directions.instructions.via_point', // 9 - 'javascripts.directions.instructions.follow', // 10 - 'javascripts.directions.instructions.roundabout', // 11 - 'javascripts.directions.instructions.leave_roundabout', // 12 - 'javascripts.directions.instructions.stay_roundabout', // 13 - 'javascripts.directions.instructions.start', // 14 - 'javascripts.directions.instructions.destination', // 15 - 'javascripts.directions.instructions.against_oneway', // 16 - 'javascripts.directions.instructions.end_oneway', // 17 - 'javascripts.directions.instructions.ferry' // 18 - ]; var params = [ - { name: "z", value: "14" }, - { name: "output", value: "json" }, - { name: "instructions", value: true } + { name: "overview", value: "false" }, + { name: "geometries", value: "polyline" }, + { name: "steps", value: true } ]; - for (var i = 0; i < points.length; i++) { - params.push({ name: "loc", value: points[i].lat + "," + points[i].lng }); - if (hintData && previousPoints && previousPoints[i].equals(points[i])) { - params.push({ name: "hint", value: hintData.locations[i] }); - } + if (cachedHints.length === points.length) { + params.push({name: "hints", value: cachedHints.join(";")}); + } else { + // invalidate cache + cachedHints = []; } - if (hintData && hintData.checksum) { - params.push({ name: "checksum", value: hintData.checksum }); - } + var encoded_coords = points.map(function(p) { + return p.lng + ',' + p.lat; + }).join(';'); + + var req_url = document.location.protocol + OSM.OSRM_URL + encoded_coords; + + var onResponse = function (data) { + if (data.code !== 'Ok') + return callback(true); + + cachedHints = data.waypoints.map(function(wp) { + return wp.hint; + }); + + var line = []; + var transformLeg = function (leg) { + return this._transformSteps(leg.steps, line); + }; + + var steps = [].concat.apply([], data.routes[0].legs.map(transformLeg.bind(this))); + + callback(false, { + line: line, + steps: steps, + distance: data.routes[0].distance, + time: data.routes[0].duration + }); + }; return $.ajax({ - url: document.location.protocol + OSM.OSRM_URL, + url: req_url, data: params, dataType: "json", - success: function (data) { - if (data.status === 207) - return callback(true); - - previousPoints = points; - hintData = data.hint_data; - - var line = L.PolylineUtil.decode(data.route_geometry, { - precision: 6 - }); - - var steps = []; - for (i = 0; i < data.route_instructions.length; i++) { - var s = data.route_instructions[i]; - var linesegend; - var instCodes = s[0].split('-'); - if (s[8] === 2) { - /* indicates a ferry in car routing mode, see https://github.com/Project-OSRM/osrm-backend/blob/6cbbd1e5a1b441eb27055f56956e1bac14832a58/profiles/car.lua#L151 */ - instCodes = ["18"]; - } - var instText = "" + (i + 1) + ". "; - var name = s[1] ? "" + s[1] + "" : I18n.t('javascripts.directions.instructions.unnamed'); - if (instCodes[0] === "11" && instCodes[1]) { - instText += I18n.t(TURN_INSTRUCTIONS[instCodes[0]] + '_with_exit', { exit: instCodes[1], name: name } ); - } else { - instText += I18n.t(TURN_INSTRUCTIONS[instCodes[0]] + '_without_exit', { name: name }); - } - if ((i + 1) < data.route_instructions.length) { - linesegend = data.route_instructions[i + 1][3] + 1; - } else { - linesegend = s[3] + 1; - } - steps.push([line[s[3]], instCodes[0], instText, s[2], line.slice(s[3], linesegend)]); - } - - callback(false, { - line: line, - steps: steps, - distance: data.route_summary.total_distance, - time: data.route_summary.total_time - }); - }, + success: onResponse.bind(this), error: function () { callback(true); } diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index b54b49fd3..b2b6057be 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -1036,8 +1036,8 @@ div.direction { height: 20px; background-repeat: no-repeat; } -@for $i from 1 through 18 { -div.direction.i#{$i} { background-position: #{($i)*-20+20}px 0px; } +@for $i from 0 through 25 { +div.direction.i#{$i} { background-position: #{($i)*-20}px 0px; } } p#routing_summary { diff --git a/config/example.application.yml b/config/example.application.yml index 895601944..1f0705bd3 100644 --- a/config/example.application.yml +++ b/config/example.application.yml @@ -96,7 +96,7 @@ defaults: &defaults graphhopper_url: "//graphhopper.com/api/1/route" mapquest_directions_url: "//open.mapquestapi.com/directions/v2/route" mapzen_valhalla_url: "//valhalla.mapzen.com/route" - osrm_url: "//router.project-osrm.org/viaroute" + osrm_url: "//router.project-osrm.org/route/v1/driving/" # External authentication credentials #google_auth_id: "" #google_auth_secret: "" diff --git a/config/locales/en.yml b/config/locales/en.yml index 321821d02..1cfbf8ab1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2249,11 +2249,21 @@ en: instructions: continue_without_exit: Continue on %{name} slight_right_without_exit: Slight right onto %{name} + offramp_right_without_exit: Take the ramp on the right onto %{name} + onramp_right_without_exit: Turn right on the ramp onto %{name} + endofroad_right_without_exit: At the end of the road turn right onto %{name} + merge_right_without_exit: Merge right onto %{name} + fork_right_without_exit: At the fork turn right onto %{name} turn_right_without_exit: Turn right onto %{name} sharp_right_without_exit: Sharp right onto %{name} uturn_without_exit: U-turn along %{name} sharp_left_without_exit: Sharp left onto %{name} turn_left_without_exit: Turn left onto %{name} + offramp_left_without_exit: Take the ramp on the left onto %{name} + onramp_left_without_exit: Turn left on the ramp onto %{name} + endofroad_left_without_exit: At the end of the road turn left onto %{name} + merge_left_without_exit: Merge left onto %{name} + fork_left_without_exit: At the fork turn left onto %{name} slight_left_without_exit: Slight left onto %{name} via_point_without_exit: (via point) follow_without_exit: Follow %{name}