From 0a53775fb37ac8bffc9f90513db5820202e2f21f Mon Sep 17 00:00:00 2001 From: Patrick Niklaus Date: Thu, 26 May 2016 03:35:38 +0200 Subject: [PATCH] Expose pronunciation in RouteStep Uses name:pronunciation by default for cars. --- CHANGELOG.md | 2 ++ docs/http.md | 1 + features/car/names.feature | 17 +++++++++++++++++ features/support/route.js | 4 ++++ features/support/shared_steps.js | 10 +++++++--- include/engine/datafacade/datafacade_base.hpp | 2 ++ .../engine/datafacade/internal_datafacade.hpp | 8 ++++++++ include/engine/datafacade/shared_datafacade.hpp | 5 +++++ include/engine/guidance/assemble_steps.hpp | 7 ++++++- include/engine/guidance/route_step.hpp | 2 ++ include/extractor/extraction_way.hpp | 2 ++ profiles/car.lua | 8 ++++++-- src/engine/api/json_factory.cpp | 2 ++ src/extractor/extractor_callbacks.cpp | 12 +++++++++--- src/extractor/scripting_environment.cpp | 1 + taginfo.json | 1 + unit_tests/mocks/mock_datafacade.hpp | 1 + 17 files changed, 76 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 801418214..f82651c1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,9 +22,11 @@ - `bearing_before`/`bearing_after` of `StepManeuver` are now deprecated and will be removed in the next major release - `location` of `StepManeuvers` is now deprecated and will be removed in the next major release - every `RouteStep` now has property `intersections` containing a list of `Intersection` objects. + - Support for name pronounciations. New member `pronounciation` in `RouteStep`, based on `name:pronounciation`. - Profile changes: - duration parser now accepts P[n]DT[n]H[n]M[n]S, P[n]W, PTHHMMSS and PTHH:MM:SS ISO8601 formats. + - `result.pronounciation` allows you to set way name pronounciations. - Infrastructure: - Better support for osrm-routed binary upgrade on the fly [UNIX specific]: diff --git a/docs/http.md b/docs/http.md index 0cdb50ba3..6c7428e1f 100644 --- a/docs/http.md +++ b/docs/http.md @@ -436,6 +436,7 @@ step. | geojson | [GeoJSON `LineString`](http://geojson.org/geojson-spec.html#linestring) or [GeoJSON `Point`](http://geojson.org/geojson-spec.html#point) if it is only one coordinate (not wrapped by a GeoJSON feature)| - `name`: The name of the way along which travel proceeds. +- `pronunciation`: The pronunciation hint of the way name. Will be `undefined` if there is no pronunciation hit. - `mode`: A string signifying the mode of transportation. - `maneuver`: A `StepManeuver` object representing the maneuver. - `intersections`: A list of `Intersections` that are passed along the segment, the very first belonging to the StepManeuver diff --git a/features/car/names.feature b/features/car/names.feature index 7a4725340..1dfe94411 100644 --- a/features/car/names.feature +++ b/features/car/names.feature @@ -18,6 +18,23 @@ Feature: Car - Street names in instructions | from | to | route | | a | c | My Way,Your Way (A1),Your Way (A1) | + Scenario: Car - A named street with pronunciation + Given the node map + | a | b | d | + | | 1 | | + | | c | | + + And the ways + | nodes | name |name:pronunciation | ref | + | ab | My Way | | | + | bd | My Way | meyeway | A1 | + | cd | Your Way | yourewaye | | + + When I route I should get + | from | to | route | pronunciations | + | a | d | My Way,My Way (A1) | ,meyeway | + | 1 | c | Your Way,Your Way | yourewaye,yourewaye | + @todo Scenario: Car - Use way type to describe unnamed ways Given the node map diff --git a/features/support/route.js b/features/support/route.js index 342277ada..d309f54c8 100644 --- a/features/support/route.js +++ b/features/support/route.js @@ -139,6 +139,10 @@ module.exports = function () { return this.extractInstructionList(instructions, s => s.name); }; + this.pronunciationList = (instructions) => { + return this.extractInstructionList(instructions, s => s.pronunciation || ''); + }; + this.bearingList = (instructions) => { return this.extractInstructionList(instructions, s => s.maneuver.bearing_before + '->' + s.maneuver.bearing_after); }; diff --git a/features/support/shared_steps.js b/features/support/shared_steps.js index d001d7ca7..66649a8f0 100644 --- a/features/support/shared_steps.js +++ b/features/support/shared_steps.js @@ -1,3 +1,5 @@ +'use strict'; + var util = require('util'); var assert = require('assert'); @@ -31,14 +33,15 @@ module.exports = function () { var afterRequest = (err, res, body) => { if (err) return cb(err); if (body && body.length) { - var instructions, bearings, turns, modes, times, distances, summary, intersections; + let pronunciations, instructions, bearings, turns, modes, times, distances, summary, intersections; - var json = JSON.parse(body); + let json = JSON.parse(body); - var hasRoute = json.code === 'Ok'; + let hasRoute = json.code === 'Ok'; if (hasRoute) { instructions = this.wayList(json.routes[0]); + pronunciations = this.pronunciationList(json.routes[0]); bearings = this.bearingList(json.routes[0]); turns = this.turnList(json.routes[0]); intersections = this.intersectionList(json.routes[0]); @@ -122,6 +125,7 @@ module.exports = function () { putValue('modes', modes); putValue('times', times); putValue('distances', distances); + putValue('pronunciations', pronunciations); } var ok = true; diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp index 16564dbed..6d3c0b4ed 100644 --- a/include/engine/datafacade/datafacade_base.hpp +++ b/include/engine/datafacade/datafacade_base.hpp @@ -145,6 +145,8 @@ class BaseDataFacade virtual std::string GetNameForID(const unsigned name_id) const = 0; + virtual std::string GetPronunciationForID(const unsigned name_id) const = 0; + virtual std::size_t GetCoreSize() const = 0; virtual std::string GetTimestamp() const = 0; diff --git a/include/engine/datafacade/internal_datafacade.hpp b/include/engine/datafacade/internal_datafacade.hpp index 018fe84ef..9ae0c78ee 100644 --- a/include/engine/datafacade/internal_datafacade.hpp +++ b/include/engine/datafacade/internal_datafacade.hpp @@ -591,6 +591,14 @@ class InternalDataFacade final : public BaseDataFacade return result; } + std::string GetPronunciationForID(const unsigned name_id) const override final + { + // We store the pronounciation directly after the name of a street. + // We do this to get around the street length limit of 255 which would hit + // if we concatenate these. + return GetNameForID(name_id + 1); + } + virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final { return m_via_node_list.at(id); diff --git a/include/engine/datafacade/shared_datafacade.hpp b/include/engine/datafacade/shared_datafacade.hpp index 6f3357572..a43725fb5 100644 --- a/include/engine/datafacade/shared_datafacade.hpp +++ b/include/engine/datafacade/shared_datafacade.hpp @@ -660,6 +660,11 @@ class SharedDataFacade final : public BaseDataFacade return result; } + std::string GetPronunciationForID(const unsigned name_id) const override final + { + return GetNameForID(name_id + 1); + } + bool IsCoreNode(const NodeID id) const override final { if (m_is_core_node.size() > 0) diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp index e9622523b..7dc2bc5a7 100644 --- a/include/engine/guidance/assemble_steps.hpp +++ b/include/engine/guidance/assemble_steps.hpp @@ -98,10 +98,12 @@ std::vector assembleSteps(const DataFacadeT &facade, { BOOST_ASSERT(segment_duration >= 0); const auto name = facade.GetNameForID(step_name_id); + const auto pronunciation = facade.GetPronunciationForID(step_name_id); const auto distance = leg_geometry.segment_distances[segment_index]; steps.push_back(RouteStep{step_name_id, - name, + std::move(name), + std::move(pronunciation), NO_ROTARY_NAME, segment_duration / 10.0, distance, @@ -152,6 +154,7 @@ std::vector assembleSteps(const DataFacadeT &facade, BOOST_ASSERT(duration >= 0); steps.push_back(RouteStep{step_name_id, facade.GetNameForID(step_name_id), + facade.GetPronunciationForID(step_name_id), NO_ROTARY_NAME, duration / 10., distance, @@ -175,6 +178,7 @@ std::vector assembleSteps(const DataFacadeT &facade, steps.push_back(RouteStep{source_node.name_id, facade.GetNameForID(source_node.name_id), + facade.GetPronunciationForID(source_node.name_id), NO_ROTARY_NAME, duration / 10., leg_geometry.segment_distances[segment_index], @@ -204,6 +208,7 @@ std::vector assembleSteps(const DataFacadeT &facade, BOOST_ASSERT(!leg_geometry.locations.empty()); steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id), + facade.GetPronunciationForID(target_node.name_id), NO_ROTARY_NAME, ZERO_DURATION, ZERO_DISTANCE, diff --git a/include/engine/guidance/route_step.hpp b/include/engine/guidance/route_step.hpp index 319ae4025..e34da5dbc 100644 --- a/include/engine/guidance/route_step.hpp +++ b/include/engine/guidance/route_step.hpp @@ -49,6 +49,7 @@ struct RouteStep { unsigned name_id; std::string name; + std::string pronunciation; std::string rotary_name; double duration; double distance; @@ -63,6 +64,7 @@ struct RouteStep inline RouteStep getInvalidRouteStep() { return {0, + "", "", "", 0, diff --git a/include/extractor/extraction_way.hpp b/include/extractor/extraction_way.hpp index f82787d96..acb787645 100644 --- a/include/extractor/extraction_way.hpp +++ b/include/extractor/extraction_way.hpp @@ -31,6 +31,7 @@ struct ExtractionWay is_startpoint = true; is_access_restricted = false; name.clear(); + pronunciation.clear(); forward_travel_mode = TRAVEL_MODE_INACCESSIBLE; backward_travel_mode = TRAVEL_MODE_INACCESSIBLE; } @@ -46,6 +47,7 @@ struct ExtractionWay double backward_speed; double duration; std::string name; + std::string pronunciation; bool roundabout; bool is_access_restricted; bool is_startpoint; diff --git a/profiles/car.lua b/profiles/car.lua index b9fe8e86f..87dac1aec 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -349,6 +349,7 @@ function way_function (way, result) -- parse the remaining tags local name = way:get_value_by_key("name") + local pronunciation = way:get_value_by_key("name:pronunciation") local ref = way:get_value_by_key("ref") local junction = way:get_value_by_key("junction") -- local barrier = way:get_value_by_key("barrier", "") @@ -358,6 +359,7 @@ function way_function (way, result) -- Set the name that will be used for instructions local has_ref = ref and "" ~= ref local has_name = name and "" ~= name + local has_pronunciation = pronunciation and "" ~= pronunciation if has_name and has_ref then result.name = name .. " (" .. ref .. ")" @@ -365,8 +367,10 @@ function way_function (way, result) result.name = ref elseif has_name then result.name = name --- else - -- result.name = highway -- if no name exists, use way type + end + + if has_pronunciation then + result.pronunciation = pronunciation end if junction and ("roundabout" == junction or "mini_roundabout" == highway) then diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp index a574379ac..8e94b9107 100644 --- a/src/engine/api/json_factory.cpp +++ b/src/engine/api/json_factory.cpp @@ -196,6 +196,8 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo route_step.values["distance"] = std::round(step.distance * 10) / 10.; route_step.values["duration"] = std::round(step.duration * 10) / 10.; route_step.values["name"] = std::move(step.name); + if (!step.pronunciation.empty()) + route_step.values["pronunciation"] = std::move(step.pronunciation); if (!step.rotary_name.empty()) route_step.values["rotary_name"] = std::move(step.rotary_name); diff --git a/src/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp index 881c797fc..950d72892 100644 --- a/src/extractor/extractor_callbacks.cpp +++ b/src/extractor/extractor_callbacks.cpp @@ -146,9 +146,9 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti const constexpr auto MAX_STRING_LENGTH = 255u; // Get the unique identifier for the street name - const auto string_map_iterator = string_map.find(parsed_way.name); + const auto name_iterator = string_map.find(parsed_way.name); unsigned name_id = external_memory.name_lengths.size(); - if (string_map.end() == string_map_iterator) + if (string_map.end() == name_iterator) { auto name_length = std::min(MAX_STRING_LENGTH, parsed_way.name.size()); @@ -158,11 +158,17 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti std::back_inserter(external_memory.name_char_data)); external_memory.name_lengths.push_back(name_length); + + auto pronunciation_length = std::min(255u, parsed_way.pronunciation.size()); + std::copy(parsed_way.pronunciation.c_str(), parsed_way.pronunciation.c_str() + pronunciation_length, + std::back_inserter(external_memory.name_char_data)); + external_memory.name_lengths.push_back(pronunciation_length); + string_map.insert(std::make_pair(parsed_way.name, name_id)); } else { - name_id = string_map_iterator->second; + name_id = name_iterator->second; } const bool split_edge = (parsed_way.forward_speed > 0) && diff --git a/src/extractor/scripting_environment.cpp b/src/extractor/scripting_environment.cpp index 14da5e1ec..63ad07899 100644 --- a/src/extractor/scripting_environment.cpp +++ b/src/extractor/scripting_environment.cpp @@ -135,6 +135,7 @@ void ScriptingEnvironment::InitContext(ScriptingEnvironment::Context &context) .def_readwrite("forward_speed", &ExtractionWay::forward_speed) .def_readwrite("backward_speed", &ExtractionWay::backward_speed) .def_readwrite("name", &ExtractionWay::name) + .def_readwrite("pronunciation", &ExtractionWay::pronunciation) .def_readwrite("roundabout", &ExtractionWay::roundabout) .def_readwrite("is_access_restricted", &ExtractionWay::is_access_restricted) .def_readwrite("is_startpoint", &ExtractionWay::is_startpoint) diff --git a/taginfo.json b/taginfo.json index cfdfee2f3..945afdc21 100644 --- a/taginfo.json +++ b/taginfo.json @@ -57,6 +57,7 @@ {"key": "maxspeed:advisory"}, {"key": "maxspeed:advisory:forward"}, {"key": "maxspeed:advisory:backward"}, + {"key": "name:pronunciation", "description": "Pronunciation hint for names", "object_types": ["way"]}, {"key": "bridge", "value": "movable", "description": "uses capacity and duration"}, {"key": "capacity:car", "description": "used for movable bridges"}, {"key": "side_road", "value": "yes", "description": "gets speed penalty"}, diff --git a/unit_tests/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp index a39fda69a..478f11b60 100644 --- a/unit_tests/mocks/mock_datafacade.hpp +++ b/unit_tests/mocks/mock_datafacade.hpp @@ -171,6 +171,7 @@ class MockDataFacade final : public engine::datafacade::BaseDataFacade bool IsCoreNode(const NodeID /* id */) const override { return false; } unsigned GetNameIndexFromEdgeID(const unsigned /* id */) const override { return 0; } std::string GetNameForID(const unsigned /* name_id */) const override { return ""; } + std::string GetPronunciationForID(const unsigned /* name_id */) const override { return ""; } std::size_t GetCoreSize() const override { return 0; } std::string GetTimestamp() const override { return ""; } bool GetContinueStraightDefault() const override { return true; }