From 7d900e3b5ab572cbab3edc9caed0d735929a138d Mon Sep 17 00:00:00 2001 From: "Daniel J. Hofmann" Date: Thu, 29 Jun 2017 22:12:25 +0200 Subject: [PATCH] Implements Exit Numbers + Names (`junction:ref` way tag for now) --- CHANGELOG.md | 3 ++ docs/http.md | 1 + docs/profiles.md | 2 ++ features/guidance/exit-numbers-names.feature | 28 +++++++++++++++++++ features/support/route.js | 4 +++ features/support/shared_steps.js | 4 ++- features/testbot/nil.feature | 1 + .../contiguous_internalmem_datafacade.hpp | 5 ++++ include/engine/datafacade/datafacade_base.hpp | 2 ++ include/engine/guidance/assemble_steps.hpp | 5 ++++ .../engine/guidance/collapsing_utility.hpp | 10 +++++-- include/engine/guidance/route_step.hpp | 3 ++ include/extractor/extraction_way.hpp | 4 +++ include/extractor/extractor_callbacks.hpp | 13 +++++---- include/util/debug.hpp | 3 +- include/util/guidance/name_announcements.hpp | 27 +++++++++++++++--- include/util/name_table.hpp | 2 +- profiles/car.lua | 2 +- profiles/lib/handlers.lua | 5 ++++ src/engine/api/json_factory.cpp | 2 ++ src/extractor/extraction_containers.cpp | 3 +- src/extractor/extractor_callbacks.cpp | 27 ++++++++++++------ src/extractor/scripting_environment_lua.cpp | 2 ++ src/util/name_table.cpp | 18 ++++++++---- taginfo.json | 5 ++++ unit_tests/mocks/mock_datafacade.hpp | 1 + unit_tests/util/name_table.cpp | 8 ++++++ 27 files changed, 160 insertions(+), 30 deletions(-) create mode 100644 features/guidance/exit-numbers-names.feature diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bb909a0a..c2ee5b63f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ - new parameter `approaches` for `route`, `table`, `trip` and `nearest` requests. This parameter keep waypoints on the curb side. 'approaches' accepts both 'curb' and 'unrestricted' values. Note : the curb side depend on the `ProfileProperties::left_hand_driving`, it's a global property set once by the profile. If you are working with a planet dataset, the api will be wrong in some countries, and right in others. + - Support for exits numbers and names. New member `exits` in `RouteStep`, based on `junction:ref` on ways + - Profiles: + - `result.exits` allows you to set a way's exit numbers and names, see [`junction:ref`](http://wiki.openstreetmap.org/wiki/Proposed_features/junction_details) - NodeJs Bindings - new parameter `approaches` for `route`, `table`, `trip` and `nearest` requests. - Tools diff --git a/docs/http.md b/docs/http.md index 2d5ce72a5..1e57b94c4 100644 --- a/docs/http.md +++ b/docs/http.md @@ -581,6 +581,7 @@ step. - `ref`: A reference number or code for the way. Optionally included, if ref data is available for the given way. - `pronunciation`: The pronunciation hint of the way name. Will be `undefined` if there is no pronunciation hit. - `destinations`: The destinations of the way. Will be `undefined` if there are no destinations. +- `exits`: The exit numbers or names of the way. Will be `undefined` if there are no exit numbers or names. - `mode`: A string signifying the mode of transportation. - `maneuver`: A `StepManeuver` object representing the maneuver. - `intersections`: A list of `Intersection` objects that are passed along the segment, the very first belonging to the StepManeuver diff --git a/docs/profiles.md b/docs/profiles.md index 64df6b5a2..0dc34377f 100644 --- a/docs/profiles.md +++ b/docs/profiles.md @@ -67,6 +67,8 @@ roundabout | Boolean | Is this part of a roundabou circular | Boolean | Is this part of a non-roundabout circular junction? name | String | Name of the way ref | String | Road number +destinations | String | The road's destinations +exits | String | The ramp's exit numbers or names pronunciation | String | Name pronunciation road_classification.motorway_class | Boolean | Guidance: way is a motorway road_classification.link_class | Boolean | Guidance: way is a slip/link road diff --git a/features/guidance/exit-numbers-names.feature b/features/guidance/exit-numbers-names.feature new file mode 100644 index 000000000..4a8d28a83 --- /dev/null +++ b/features/guidance/exit-numbers-names.feature @@ -0,0 +1,28 @@ +@routing @guidance +Feature: Exit Numbers and Names + + Background: + Given the profile "car" + Given a grid size of 10 meters + + Scenario: Exit number on the way after the motorway junction + Given the node map + """ + a . . b . c . . d + ` e . . f + """ + + And the nodes + | node | highway | + | b | motorway_junction | + + And the ways + | nodes | highway | name | junction:ref | + | abcd | motorway | MainRoad | | + | be | motorway_link | ExitRamp | 3 | + | ef | motorway_link | ExitRamp | | + + When I route I should get + | waypoints | route | turns | exits | + | a,f | MainRoad,ExitRamp,ExitRamp | depart,off ramp slight right,arrive | ,3, | + diff --git a/features/support/route.js b/features/support/route.js index 5bee6dac1..886d573dd 100644 --- a/features/support/route.js +++ b/features/support/route.js @@ -155,6 +155,10 @@ module.exports = function () { return this.extractInstructionList(instructions, s => s.destinations || ''); }; + this.exitsList = (instructions) => { + return this.extractInstructionList(instructions, s => s.exits || ''); + }; + this.reverseBearing = (bearing) => { if (bearing >= 180) return bearing - 180.; diff --git a/features/support/shared_steps.js b/features/support/shared_steps.js index d56dbc4d4..2d1b36507 100644 --- a/features/support/shared_steps.js +++ b/features/support/shared_steps.js @@ -34,7 +34,7 @@ module.exports = function () { var afterRequest = (err, res, body) => { if (err) return cb(err); if (body && body.length) { - let destinations, pronunciations, instructions, refs, bearings, turns, modes, times, + let destinations, exits, pronunciations, instructions, refs, bearings, turns, modes, times, distances, summary, intersections, lanes, locations, annotation, weight_name, weights, approaches; let json = JSON.parse(body); @@ -48,6 +48,7 @@ module.exports = function () { pronunciations = this.pronunciationList(json.routes[0]); refs = this.refList(json.routes[0]); destinations = this.destinationsList(json.routes[0]); + exits = this.exitsList(json.routes[0]); bearings = this.bearingList(json.routes[0]); turns = this.turnList(json.routes[0]); intersections = this.intersectionList(json.routes[0]); @@ -177,6 +178,7 @@ module.exports = function () { putValue('distances', distances); putValue('pronunciations', pronunciations); putValue('destinations', destinations); + putValue('exits', exits); putValue('weight_name', weight_name); putValue('weights', weights); putValue('weight', weight); diff --git a/features/testbot/nil.feature b/features/testbot/nil.feature index bb5372948..6d84a0909 100644 --- a/features/testbot/nil.feature +++ b/features/testbot/nil.feature @@ -14,6 +14,7 @@ Feature: Testbot - Check assigning nil values result.name = nil result.ref = nil result.destinations = nil + result.exits = nil result.pronunciation = nil result.turn_lanes_forward = nil result.turn_lanes_backward = nil diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index 17c8d3c7f..b4e595d47 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -808,6 +808,11 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade return m_name_table.GetDestinationsForID(id); } + StringView GetExitsForID(const NameID id) const override final + { + return m_name_table.GetExitsForID(id); + } + StringView GetDatasourceName(const DatasourceID id) const override final { return m_datasources->GetSourceName(id); diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp index 4d29ec4af..67f99d38a 100644 --- a/include/engine/datafacade/datafacade_base.hpp +++ b/include/engine/datafacade/datafacade_base.hpp @@ -158,6 +158,8 @@ class BaseDataFacade virtual StringView GetDestinationsForID(const NameID id) const = 0; + virtual StringView GetExitsForID(const NameID id) const = 0; + virtual std::string GetTimestamp() const = 0; virtual bool GetContinueStraightDefault() const = 0; diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp index 152f1eb7b..c832e3b0e 100644 --- a/include/engine/guidance/assemble_steps.hpp +++ b/include/engine/guidance/assemble_steps.hpp @@ -114,6 +114,7 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa const auto ref = facade.GetRefForID(step_name_id); const auto pronunciation = facade.GetPronunciationForID(step_name_id); const auto destinations = facade.GetDestinationsForID(step_name_id); + const auto exits = facade.GetExitsForID(step_name_id); const auto distance = leg_geometry.segment_distances[segment_index]; steps.push_back(RouteStep{step_name_id, @@ -121,6 +122,7 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa ref.to_string(), pronunciation.to_string(), destinations.to_string(), + exits.to_string(), NO_ROTARY_NAME, NO_ROTARY_NAME, segment_duration / 10., @@ -196,6 +198,7 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa facade.GetRefForID(step_name_id).to_string(), facade.GetPronunciationForID(step_name_id).to_string(), facade.GetDestinationsForID(step_name_id).to_string(), + facade.GetExitsForID(step_name_id).to_string(), NO_ROTARY_NAME, NO_ROTARY_NAME, duration / 10., @@ -237,6 +240,7 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa facade.GetRefForID(source_name_id).to_string(), facade.GetPronunciationForID(source_name_id).to_string(), facade.GetDestinationsForID(source_name_id).to_string(), + facade.GetExitsForID(source_name_id).to_string(), NO_ROTARY_NAME, NO_ROTARY_NAME, duration / 10., @@ -275,6 +279,7 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa facade.GetRefForID(target_name_id).to_string(), facade.GetPronunciationForID(target_name_id).to_string(), facade.GetDestinationsForID(target_name_id).to_string(), + facade.GetExitsForID(target_name_id).to_string(), NO_ROTARY_NAME, NO_ROTARY_NAME, ZERO_DURATION, diff --git a/include/engine/guidance/collapsing_utility.hpp b/include/engine/guidance/collapsing_utility.hpp index 895dbd34b..e84b77ac2 100644 --- a/include/engine/guidance/collapsing_utility.hpp +++ b/include/engine/guidance/collapsing_utility.hpp @@ -130,8 +130,14 @@ inline bool haveSameName(const RouteStep &lhs, const RouteStep &rhs) // ok, bite the sour grape and check the strings already else - return !util::guidance::requiresNameAnnounced( - lhs.name, lhs.ref, lhs.pronunciation, rhs.name, rhs.ref, rhs.pronunciation); + return !util::guidance::requiresNameAnnounced(lhs.name, + lhs.ref, + lhs.pronunciation, + lhs.exits, + rhs.name, + rhs.ref, + rhs.pronunciation, + rhs.exits); } // alias for readability, both turn right | left diff --git a/include/engine/guidance/route_step.hpp b/include/engine/guidance/route_step.hpp index a48c204aa..41127587a 100644 --- a/include/engine/guidance/route_step.hpp +++ b/include/engine/guidance/route_step.hpp @@ -62,6 +62,7 @@ struct RouteStep std::string ref; std::string pronunciation; std::string destinations; + std::string exits; std::string rotary_name; std::string rotary_pronunciation; double duration; // duration in seconds @@ -114,6 +115,7 @@ inline void RouteStep::Invalidate() ref.clear(); pronunciation.clear(); destinations.clear(); + exits.clear(); rotary_name.clear(); rotary_pronunciation.clear(); duration = 0; @@ -178,6 +180,7 @@ inline RouteStep &RouteStep::AdaptStepSignage(const RouteStep &origin) name = origin.name; pronunciation = origin.pronunciation; destinations = origin.destinations; + exits = origin.exits; ref = origin.ref; return *this; diff --git a/include/extractor/extraction_way.hpp b/include/extractor/extraction_way.hpp index 1783f539b..1007ad846 100644 --- a/include/extractor/extraction_way.hpp +++ b/include/extractor/extraction_way.hpp @@ -53,6 +53,7 @@ struct ExtractionWay ref.clear(); pronunciation.clear(); destinations.clear(); + exits.clear(); forward_travel_mode = TRAVEL_MODE_INACCESSIBLE; backward_travel_mode = TRAVEL_MODE_INACCESSIBLE; turn_lanes_forward.clear(); @@ -69,6 +70,8 @@ struct ExtractionWay const char *GetRef() const { return ref.c_str(); } void SetDestinations(const char *value) { detail::maybeSetString(destinations, value); } const char *GetDestinations() const { return destinations.c_str(); } + void SetExits(const char *value) { detail::maybeSetString(exits, value); } + const char *GetExits() const { return exits.c_str(); } void SetPronunciation(const char *value) { detail::maybeSetString(pronunciation, value); } const char *GetPronunciation() const { return pronunciation.c_str(); } void SetTurnLanesForward(const char *value) @@ -96,6 +99,7 @@ struct ExtractionWay std::string ref; std::string pronunciation; std::string destinations; + std::string exits; std::string turn_lanes_forward; std::string turn_lanes_backward; guidance::RoadClassification road_classification; diff --git a/include/extractor/extractor_callbacks.hpp b/include/extractor/extractor_callbacks.hpp index 73c09c398..84f2af29c 100644 --- a/include/extractor/extractor_callbacks.hpp +++ b/include/extractor/extractor_callbacks.hpp @@ -18,10 +18,10 @@ class Way; namespace std { -template <> struct hash> +template <> struct hash> { - std::size_t - operator()(const std::tuple &mk) const + std::size_t operator()( + const std::tuple &mk) const noexcept { std::size_t seed = 0; @@ -29,6 +29,7 @@ template <> struct hash(mk)); boost::hash_combine(seed, std::get<2>(mk)); boost::hash_combine(seed, std::get<3>(mk)); + boost::hash_combine(seed, std::get<4>(mk)); return seed; } }; @@ -55,9 +56,9 @@ struct ProfileProperties; class ExtractorCallbacks { private: - // used to deduplicate street names, refs, destinations, pronunciation: actually maps to name - // ids - using MapKey = std::tuple; + // used to deduplicate street names, refs, destinations, pronunciation, exits: + // actually maps to name ids + using MapKey = std::tuple; using MapVal = unsigned; std::unordered_map string_map; guidance::LaneDescriptionMap lane_description_map; diff --git a/include/util/debug.hpp b/include/util/debug.hpp index 3c5629291..a50f7688c 100644 --- a/include/util/debug.hpp +++ b/include/util/debug.hpp @@ -46,7 +46,8 @@ inline void print(const engine::guidance::RouteStep &step) std::cout << ")"; } std::cout << "] name[" << step.name_id << "]: " << step.name << " Ref: " << step.ref - << " Pronunciation: " << step.pronunciation << "Destination: " << step.destinations; + << " Pronunciation: " << step.pronunciation << "Destination: " << step.destinations + << "Exits: " << step.exits; } inline void print(const std::vector &steps) diff --git a/include/util/guidance/name_announcements.hpp b/include/util/guidance/name_announcements.hpp index a43706cb8..5892b9cfd 100644 --- a/include/util/guidance/name_announcements.hpp +++ b/include/util/guidance/name_announcements.hpp @@ -44,9 +44,11 @@ template inline bool requiresNameAnnounced(const std::string &from_name, const std::string &from_ref, const std::string &from_pronunciation, + const std::string &from_exits, const std::string &to_name, const std::string &to_ref, const std::string &to_pronunciation, + const std::string &to_exits, const SuffixTable &suffix_table) { // first is empty and the second is not @@ -128,17 +130,20 @@ inline bool requiresNameAnnounced(const std::string &from_name, (!from_name.empty() && from_ref.empty() && to_name.empty() && !to_ref.empty()); const auto pronunciation_changes = from_pronunciation != to_pronunciation; + const auto exits_change = from_exits != to_exits; - return !obvious_change || needs_announce || pronunciation_changes; + return !obvious_change || needs_announce || pronunciation_changes || exits_change; } // Overload without suffix checking inline bool requiresNameAnnounced(const std::string &from_name, const std::string &from_ref, const std::string &from_pronunciation, + const std::string &from_exits, const std::string &to_name, const std::string &to_ref, - const std::string &to_pronunciation) + const std::string &to_pronunciation, + const std::string &to_exits) { // Dummy since we need to provide a SuffixTable but do not have the data for it. // (Guidance Post-Processing does not keep the suffix table around at the moment) @@ -148,8 +153,15 @@ inline bool requiresNameAnnounced(const std::string &from_name, bool isSuffix(const std::string &) const { return false; } } static const table; - return requiresNameAnnounced( - from_name, from_ref, from_pronunciation, to_name, to_ref, to_pronunciation, table); + return requiresNameAnnounced(from_name, + from_ref, + from_pronunciation, + from_exits, + to_name, + to_ref, + to_pronunciation, + to_exits, + table); } inline bool requiresNameAnnounced(const NameID from_name_id, @@ -163,9 +175,13 @@ inline bool requiresNameAnnounced(const NameID from_name_id, return requiresNameAnnounced(name_table.GetNameForID(from_name_id).to_string(), name_table.GetRefForID(from_name_id).to_string(), name_table.GetPronunciationForID(from_name_id).to_string(), + name_table.GetExitsForID(from_name_id).to_string(), + // name_table.GetNameForID(to_name_id).to_string(), name_table.GetRefForID(to_name_id).to_string(), name_table.GetPronunciationForID(to_name_id).to_string(), + name_table.GetExitsForID(to_name_id).to_string(), + // suffix_table); // FIXME: converts StringViews to strings since the name change heuristics mutates in place } @@ -180,8 +196,11 @@ inline bool requiresNameAnnounced(const NameID from_name_id, return requiresNameAnnounced(name_table.GetNameForID(from_name_id).to_string(), name_table.GetRefForID(from_name_id).to_string(), name_table.GetPronunciationForID(from_name_id).to_string(), + name_table.GetExitsForID(from_name_id).to_string(), + // name_table.GetNameForID(to_name_id).to_string(), name_table.GetRefForID(to_name_id).to_string(), + name_table.GetExitsForID(to_name_id).to_string(), name_table.GetPronunciationForID(to_name_id).to_string()); // FIXME: converts StringViews to strings since the name change heuristics mutates in place } diff --git a/include/util/name_table.hpp b/include/util/name_table.hpp index fdf5d07ec..2e76be928 100644 --- a/include/util/name_table.hpp +++ b/include/util/name_table.hpp @@ -33,9 +33,9 @@ class NameTable // This class provides a limited view over all the string data we serialize out. // The following functions are a subset of what is available. // See the data facades for they provide full access to this serialized string data. - // (at time of writing this: get{Name,Ref,Pronunciation,Destinations}ForID(name_id);) util::StringView GetNameForID(const NameID id) const; util::StringView GetDestinationsForID(const NameID id) const; + util::StringView GetExitsForID(const NameID id) const; util::StringView GetRefForID(const NameID id) const; util::StringView GetPronunciationForID(const NameID id) const; diff --git a/profiles/car.lua b/profiles/car.lua index 09b7c226f..5a8d09d0f 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -347,7 +347,7 @@ function way_function(way, result) -- check whether forward/backward directions are routable 'handle_oneway', - -- check whether forward/backward directions are routable + -- check a road's destination 'handle_destinations', -- check whether we're using a special transport mode diff --git a/profiles/lib/handlers.lua b/profiles/lib/handlers.lua index 65233ba10..de520582a 100644 --- a/profiles/lib/handlers.lua +++ b/profiles/lib/handlers.lua @@ -32,6 +32,7 @@ function Handlers.handle_names(way,result,data,profile) 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 exits = way:get_value_by_key("junction:ref") -- Set the name that will be used for instructions if name then @@ -45,6 +46,10 @@ function Handlers.handle_names(way,result,data,profile) if pronunciation then result.pronunciation = pronunciation end + + if exits then + result.exits = exits + end end -- junctions diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp index 661c50e95..46b025bb3 100644 --- a/src/engine/api/json_factory.cpp +++ b/src/engine/api/json_factory.cpp @@ -250,6 +250,8 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo route_step.values["pronunciation"] = std::move(step.pronunciation); if (!step.destinations.empty()) route_step.values["destinations"] = std::move(step.destinations); + if (!step.exits.empty()) + route_step.values["exits"] = std::move(step.exits); if (!step.rotary_name.empty()) { route_step.values["rotary_name"] = std::move(step.rotary_name); diff --git a/src/extractor/extraction_containers.cpp b/src/extractor/extraction_containers.cpp index 23dd8cb99..c8771f01a 100644 --- a/src/extractor/extraction_containers.cpp +++ b/src/extractor/extraction_containers.cpp @@ -120,7 +120,8 @@ ExtractionContainers::ExtractionContainers() // Check if stxxl can be instantiated stxxl::vector dummy_vector; - // Insert four empty strings offsets for name, ref, destination and pronunciation + // Insert four empty strings offsets for name, ref, destination, pronunciation, and exits + name_offsets.push_back(0); name_offsets.push_back(0); name_offsets.push_back(0); name_offsets.push_back(0); diff --git a/src/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp index ba5db91d9..090f496d4 100644 --- a/src/extractor/extractor_callbacks.cpp +++ b/src/extractor/extractor_callbacks.cpp @@ -39,8 +39,8 @@ ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containe fallback_to_duration(properties.fallback_to_duration), force_split_edges(properties.force_split_edges) { - // we reserved 0, 1, 2, 3 for the empty case - string_map[MapKey("", "", "", "")] = 0; + // we reserved 0, 1, 2, 3, 4 for the empty case + string_map[MapKey("", "", "", "", "")] = 0; lane_description_map.data[TurnLaneDescription()] = 0; } @@ -254,7 +254,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti return lane_description_map.ConcurrentFindOrAdd(lane_description); }; - // Deduplicates street names, refs, destinations, pronunciation based on the string_map. + // Deduplicates street names, refs, destinations, pronunciation, exits. // In case we do not already store the key, inserts (key, id) tuple and return id. // Otherwise fetches the id based on the name and returns it without insertion. const auto turn_lane_id_forward = requestId(parsed_way.turn_lanes_forward); @@ -263,14 +263,17 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti const auto road_classification = parsed_way.road_classification; // Get the unique identifier for the street name, destination, and ref - const auto name_iterator = string_map.find( - MapKey(parsed_way.name, parsed_way.destinations, parsed_way.ref, parsed_way.pronunciation)); + const auto name_iterator = string_map.find(MapKey(parsed_way.name, + parsed_way.destinations, + parsed_way.ref, + parsed_way.pronunciation, + parsed_way.exits)); NameID name_id = EMPTY_NAMEID; if (string_map.end() == name_iterator) { // name_offsets has a sentinel element with the total name data size // take the sentinels index as the name id of the new name data pack - // (name [name_id], destination [+1], pronunciation [+2], ref [+3]) + // (name [name_id], destination [+1], pronunciation [+2], ref [+3], exits [+4]) name_id = external_memory.name_offsets.size() - 1; std::copy(parsed_way.name.begin(), @@ -293,8 +296,16 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti std::back_inserter(external_memory.name_char_data)); external_memory.name_offsets.push_back(external_memory.name_char_data.size()); - auto k = MapKey{ - parsed_way.name, parsed_way.destinations, parsed_way.ref, parsed_way.pronunciation}; + std::copy(parsed_way.exits.begin(), + parsed_way.exits.end(), + std::back_inserter(external_memory.name_char_data)); + external_memory.name_offsets.push_back(external_memory.name_char_data.size()); + + auto k = MapKey{parsed_way.name, + parsed_way.destinations, + parsed_way.ref, + parsed_way.pronunciation, + parsed_way.exits}; auto v = MapVal{name_id}; string_map.emplace(std::move(k), std::move(v)); } diff --git a/src/extractor/scripting_environment_lua.cpp b/src/extractor/scripting_environment_lua.cpp index 926d2b9a4..eef6961cc 100644 --- a/src/extractor/scripting_environment_lua.cpp +++ b/src/extractor/scripting_environment_lua.cpp @@ -330,6 +330,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context) sol::property(&ExtractionWay::GetPronunciation, &ExtractionWay::SetPronunciation), "destinations", sol::property(&ExtractionWay::GetDestinations, &ExtractionWay::SetDestinations), + "exits", + sol::property(&ExtractionWay::GetExits, &ExtractionWay::SetExits), "turn_lanes_forward", sol::property(&ExtractionWay::GetTurnLanesForward, &ExtractionWay::SetTurnLanesForward), "turn_lanes_backward", diff --git a/src/util/name_table.cpp b/src/util/name_table.cpp index 47101c228..f6ef670ba 100644 --- a/src/util/name_table.cpp +++ b/src/util/name_table.cpp @@ -37,7 +37,7 @@ StringView NameTable::GetNameForID(const NameID id) const if (id == INVALID_NAMEID) return {}; - return m_name_table.at(id); + return m_name_table.at(id + 0); } StringView NameTable::GetDestinationsForID(const NameID id) const @@ -48,6 +48,14 @@ StringView NameTable::GetDestinationsForID(const NameID id) const return m_name_table.at(id + 1); } +StringView NameTable::GetExitsForID(const NameID id) const +{ + if (id == INVALID_NAMEID) + return {}; + + return m_name_table.at(id + 4); +} + StringView NameTable::GetRefForID(const NameID id) const { if (id == INVALID_NAMEID) @@ -55,14 +63,14 @@ StringView NameTable::GetRefForID(const NameID id) const // Way string data is stored in blocks based on `id` as follows: // - // | name | destination | pronunciation | ref | + // | name | destination | pronunciation | ref | exits // ^ ^ // [range) // ^ id + 3 // // `id + offset` gives us the range of chars. // - // Offset 0 is name, 1 is destination, 2 is pronunciation, 3 is ref. + // Offset 0 is name, 1 is destination, 2 is pronunciation, 3 is ref, 4 is exits // See datafacades and extractor callbacks for details. const constexpr auto OFFSET_REF = 3u; return m_name_table.at(id + OFFSET_REF); @@ -75,14 +83,14 @@ StringView NameTable::GetPronunciationForID(const NameID id) const // Way string data is stored in blocks based on `id` as follows: // - // | name | destination | pronunciation | ref | + // | name | destination | pronunciation | ref | exits // ^ ^ // [range) // ^ id + 2 // // `id + offset` gives us the range of chars. // - // Offset 0 is name, 1 is destination, 2 is pronunciation, 3 is ref. + // Offset 0 is name, 1 is destination, 2 is pronunciation, 3 is ref, 4 is exits // See datafacades and extractor callbacks for details. const constexpr auto OFFSET_PRONUNCIATION = 2u; return m_name_table.at(id + OFFSET_PRONUNCIATION); diff --git a/taginfo.json b/taginfo.json index aefe902f5..02470a20f 100644 --- a/taginfo.json +++ b/taginfo.json @@ -350,6 +350,11 @@ "object_types": [ "way" ], "description": "Destination and direction of road for oneways for navigation instructions, supplements name." }, + { + "key": "junction:ref", + "object_types": [ "way" ], + "description": "Exit number or exit name of road for navigation instructions. Not to be confused with destination." + }, { "key": "junction", "object_types": [ "way" ], diff --git a/unit_tests/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp index 8b6485505..8ef56087d 100644 --- a/unit_tests/mocks/mock_datafacade.hpp +++ b/unit_tests/mocks/mock_datafacade.hpp @@ -201,6 +201,7 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade StringView GetRefForID(const NameID) const override final { return {}; } StringView GetPronunciationForID(const NameID) const override final { return {}; } StringView GetDestinationsForID(const NameID) const override final { return {}; } + StringView GetExitsForID(const NameID) const override final { return {}; } std::string GetTimestamp() const override { return ""; } bool GetContinueStraightDefault() const override { return true; } diff --git a/unit_tests/util/name_table.cpp b/unit_tests/util/name_table.cpp index f0a520f4b..b6cb174ca 100644 --- a/unit_tests/util/name_table.cpp +++ b/unit_tests/util/name_table.cpp @@ -45,12 +45,17 @@ std::string PrapareNameTableData(std::vector &data, bool fill_all) tmp = s + "_ref"; name_offsets.push_back(name_char_data.size()); std::copy(tmp.begin(), tmp.end(), std::back_inserter(name_char_data)); + + tmp = s + "_ext"; + name_offsets.push_back(name_char_data.size()); + std::copy(tmp.begin(), tmp.end(), std::back_inserter(name_char_data)); } else { name_offsets.push_back(name_char_data.size()); name_offsets.push_back(name_char_data.size()); name_offsets.push_back(name_char_data.size()); + name_offsets.push_back(name_char_data.size()); } } name_offsets.push_back(name_char_data.size()); @@ -89,6 +94,7 @@ BOOST_AUTO_TEST_CASE(check_name_table_fill) BOOST_CHECK_EQUAL(name_table.GetRefForID(id), expected_names[index] + "_ref"); BOOST_CHECK_EQUAL(name_table.GetDestinationsForID(id), expected_names[index] + "_des"); BOOST_CHECK_EQUAL(name_table.GetPronunciationForID(id), expected_names[index] + "_pro"); + BOOST_CHECK_EQUAL(name_table.GetExitsForID(id), expected_names[index] + "_ext"); } } @@ -112,6 +118,7 @@ BOOST_AUTO_TEST_CASE(check_name_table_nofill) BOOST_CHECK(name_table.GetRefForID(id).empty()); BOOST_CHECK(name_table.GetDestinationsForID(id).empty()); BOOST_CHECK(name_table.GetPronunciationForID(id).empty()); + BOOST_CHECK(name_table.GetExitsForID(id).empty()); } // CALLGRIND_STOP_INSTRUMENTATION; } @@ -123,6 +130,7 @@ BOOST_AUTO_TEST_CASE(check_invalid_ids) BOOST_CHECK_EQUAL(name_table.GetRefForID(INVALID_NAMEID), ""); BOOST_CHECK_EQUAL(name_table.GetDestinationsForID(INVALID_NAMEID), ""); BOOST_CHECK_EQUAL(name_table.GetPronunciationForID(INVALID_NAMEID), ""); + BOOST_CHECK_EQUAL(name_table.GetExitsForID(INVALID_NAMEID), ""); } BOOST_AUTO_TEST_SUITE_END()