diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e3f503781..c0b618a447 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * **Removed** * **Bug Fix** * **Enhancement** + * CHANGED: Pronunciation for names and destinations [#3132](https://github.com/valhalla/valhalla/pull/3132) ## Release Date: 2021-10-07 Valhalla 3.1.4 * **Removed** diff --git a/proto/sign.proto b/proto/sign.proto index 9e19fe4e9d..c3e790a8e7 100644 --- a/proto/sign.proto +++ b/proto/sign.proto @@ -1,21 +1,23 @@ syntax = "proto2"; option optimize_for = LITE_RUNTIME; package valhalla; +import public "tripcommon.proto"; message TripSignElement { - optional string text = 1; // The actual sign element text, examples: I 95 North or Derry Street - optional bool is_route_number = 2; // true if sign element is a reference route number such as: I 81 South or US 322 West - optional uint32 consecutive_count = 3; // The frequency of this sign element within a set a consecutive signs + optional string text = 1; // The actual sign element text, examples: I 95 North or Derry Street + optional bool is_route_number = 2; // true if sign element is a reference route number such as: I 81 South or US 322 West + optional uint32 consecutive_count = 3; // The frequency of this sign element within a set a consecutive signs + optional Pronunciation pronunciation = 4; // The pronunciation associated with this sign element } message TripSign { - repeated TripSignElement exit_numbers = 1; // The list of exit numbers, example: 67B - repeated TripSignElement exit_onto_streets = 2; // The list of exit branch street names, examples: I 95 North or Baltimore-Washington Parkway - repeated TripSignElement exit_toward_locations = 3; // The list of exit toward locations, examples: New York or I 395 South - repeated TripSignElement exit_names = 4; // The list of exit names - not used much in US, example: Gettysburg Pike - repeated TripSignElement guide_onto_streets = 5; // The list of guide branch street names, examples: US 22 West or Baltimore-Washington Parkway - repeated TripSignElement guide_toward_locations = 6; // The list of guide toward locations, examples: Lewistown or US 15 - repeated TripSignElement junction_names = 7; // The list of junction names, examples: 万年橋東 or Mannenbashi East - repeated TripSignElement guidance_view_junctions = 8; // The list of guidance view junctions, examples: AB12345;1 or AB12345;E + repeated TripSignElement exit_numbers = 1; // The list of exit numbers, example: 67B + repeated TripSignElement exit_onto_streets = 2; // The list of exit branch street names, examples: I 95 North or Baltimore-Washington Parkway + repeated TripSignElement exit_toward_locations = 3; // The list of exit toward locations, examples: New York or I 395 South + repeated TripSignElement exit_names = 4; // The list of exit names - not used much in US, example: Gettysburg Pike + repeated TripSignElement guide_onto_streets = 5; // The list of guide branch street names, examples: US 22 West or Baltimore-Washington Parkway + repeated TripSignElement guide_toward_locations = 6; // The list of guide toward locations, examples: Lewistown or US 15 + repeated TripSignElement junction_names = 7; // The list of junction names, examples: 万年橋東 or Mannenbashi East + repeated TripSignElement guidance_view_junctions = 8; // The list of guidance view junctions, examples: AB12345;1 or AB12345;E repeated TripSignElement guidance_view_signboards = 9; // The list of guidance view signboards, examples: SI_721701166;1 or SI_721701166;2 } diff --git a/proto/tripcommon.proto b/proto/tripcommon.proto index bfe06ed0a6..af33e89521 100644 --- a/proto/tripcommon.proto +++ b/proto/tripcommon.proto @@ -129,9 +129,21 @@ message TransitPlatformInfo { optional string station_name = 9; // The station name of the platform } +message Pronunciation { + enum Alphabet { + kIpa = 1; + kXKatakana = 2; + kXJeita = 3; + kNtSampa = 4; + } + optional Alphabet alphabet = 1 [default = kIpa]; + optional string value = 2; +} + message StreetName { - optional string value = 1; // The actual street name value, examples: I 95 North or Derry Street - optional bool is_route_number = 2; // true if the street name is a reference route number such as: I 81 South or US 322 West + optional string value = 1; // The actual street name value, examples: I 95 North or Derry Street + optional bool is_route_number = 2; // true if the street name is a reference route number such as: I 81 South or US 322 West + optional Pronunciation pronunciation = 3; // The pronunciation associated with this street name } message TurnLane { diff --git a/scripts/valhalla_build_config b/scripts/valhalla_build_config index 1b87ce61aa..0dfe980b4b 100755 --- a/scripts/valhalla_build_config +++ b/scripts/valhalla_build_config @@ -106,6 +106,10 @@ config = { }, 'service': { 'proxy': 'ipc:///tmp/odin' + }, + 'markup_formatter': { + 'markup_enabled': False, + 'phoneme_format': ' (phoneme>//)' } }, 'meili': { @@ -368,6 +372,10 @@ help_text = { }, 'service': { 'proxy': 'IPC linux domain socket file location' + }, + 'markup_formatter': { + 'markup_enabled': 'Boolean flag to use markup formatting', + 'phoneme_format': 'The phoneme format string that will be used by street names and signs' } }, 'meili': { diff --git a/src/baldr/CMakeLists.txt b/src/baldr/CMakeLists.txt index 54ce33a19f..d2d3344f68 100644 --- a/src/baldr/CMakeLists.txt +++ b/src/baldr/CMakeLists.txt @@ -54,6 +54,7 @@ set(sources location.cc pathlocation.cc predictedspeeds.cc + pronunciation.cc tilehierarchy.cc turn.cc shortcut_recovery.h diff --git a/src/baldr/edgeinfo.cc b/src/baldr/edgeinfo.cc index 044bce1ddd..db64795404 100644 --- a/src/baldr/edgeinfo.cc +++ b/src/baldr/edgeinfo.cc @@ -8,6 +8,7 @@ using namespace valhalla::baldr; namespace { // should return true for any tags which we should consider "named" +// do not return TaggedValue::kPronunciation bool IsNameTag(char ch) { static const std::unordered_set kNameTags = {TaggedValue::kBridge, TaggedValue::kTunnel}; @@ -78,26 +79,59 @@ NameInfo EdgeInfo::GetNameInfo(uint8_t index) const { // Get a list of names std::vector EdgeInfo::GetNames() const { - return GetTaggedValuesOrNames(false); -} + // Get each name + std::vector names; + names.reserve(name_count()); + const NameInfo* ni = name_info_list_; + for (uint32_t i = 0; i < name_count(); i++, ni++) { + if (ni->tagged_) + continue; -std::vector EdgeInfo::GetTaggedValues() const { - return GetTaggedValuesOrNames(true); + if (ni->name_offset_ < names_list_length_) { + names.push_back(names_list_ + ni->name_offset_); + } else { + throw std::runtime_error("GetNames: offset exceeds size of text list"); + } + } + return names; } -std::vector EdgeInfo::GetTaggedValuesOrNames(bool only_tagged_values) const { +// Get a list of tagged names +std::vector EdgeInfo::GetTaggedValues(bool only_pronunciations) const { // Get each name std::vector names; names.reserve(name_count()); const NameInfo* ni = name_info_list_; for (uint32_t i = 0; i < name_count(); i++, ni++) { - if ((only_tagged_values && !ni->tagged_) || (!only_tagged_values && ni->tagged_)) { + if (!ni->tagged_) continue; - } + if (ni->name_offset_ < names_list_length_) { - names.emplace_back(names_list_ + ni->name_offset_); + const auto* name = names_list_ + ni->name_offset_; + try { + TaggedValue tv = static_cast(name[0]); + if (tv == baldr::TaggedValue::kPronunciation) { + if (!only_pronunciations) + continue; + + size_t pos = 1; + while (pos < strlen(name)) { + const auto& header = *reinterpret_cast(name + pos); + pos += 3; + names.emplace_back((std::string(reinterpret_cast(&header), 3) + + std::string((name + pos), header.length_))); + + pos += header.length_; + } + + } else if (!only_pronunciations) { + names.push_back(name); + } + } catch (const std::invalid_argument& arg) { + LOG_DEBUG("invalid_argument thrown for name: " + std::string(name)); + } } else { - throw std::runtime_error("GetNames: offset exceeds size of text list"); + throw std::runtime_error("GetTaggedNames: offset exceeds size of text list"); } } return names; @@ -105,7 +139,8 @@ std::vector EdgeInfo::GetTaggedValuesOrNames(bool only_tagged_value // Get a list of names std::vector> -EdgeInfo::GetNamesAndTypes(bool include_tagged_values) const { +EdgeInfo::GetNamesAndTypes(std::vector& types, bool include_tagged_values) const { + // Get each name std::vector> name_type_pairs; name_type_pairs.reserve(name_count()); @@ -118,17 +153,19 @@ EdgeInfo::GetNamesAndTypes(bool include_tagged_values) const { if (ni->tagged_) { if (ni->name_offset_ < names_list_length_) { std::string name = names_list_ + ni->name_offset_; - if (name.size() > 1 && IsNameTag(name[0])) { - try { + try { + if (IsNameTag(name[0])) { name_type_pairs.push_back({name.substr(1), false}); - } catch (const std::invalid_argument& arg) { - LOG_DEBUG("invalid_argument thrown for name: " + name); + types.push_back(static_cast(name.at(0))); } + } catch (const std::invalid_argument& arg) { + LOG_DEBUG("invalid_argument thrown for name: " + name); } } else throw std::runtime_error("GetNamesAndTypes: offset exceeds size of text list"); } else if (ni->name_offset_ < names_list_length_) { name_type_pairs.push_back({names_list_ + ni->name_offset_, ni->is_route_num_}); + types.push_back(0); } else { throw std::runtime_error("GetNamesAndTypes: offset exceeds size of text list"); } @@ -149,27 +186,70 @@ const std::multimap& EdgeInfo::GetTags() const { if (ni->tagged_) { if (ni->name_offset_ < names_list_length_) { std::string name = names_list_ + ni->name_offset_; - if (name.size() > 1) { - uint8_t num = 0; - try { - num = static_cast(name.at(0)); - tag_cache_.emplace(static_cast(num), name.substr(1)); - } catch (const std::logic_error& arg) { - LOG_DEBUG("logic_error thrown for name: " + name); - } - } + try { + TaggedValue tv = static_cast(name[0]); + if (tv != baldr::TaggedValue::kPronunciation) + tag_cache_.emplace(tv, name.substr(1)); + } catch (const std::logic_error& arg) { LOG_DEBUG("logic_error thrown for name: " + name); } } else { throw std::runtime_error("GetTags: offset exceeds size of text list"); } } } - tag_cache_ready_ = true; + if (tag_cache_.size()) + tag_cache_ready_ = true; } return tag_cache_; } +std::unordered_map> EdgeInfo::GetPronunciationsMap() const { + std::unordered_map> index_pronunciation_map; + index_pronunciation_map.reserve(name_count()); + const NameInfo* ni = name_info_list_; + for (uint32_t i = 0; i < name_count(); i++, ni++) { + if (!ni->tagged_) + continue; + + if (ni->name_offset_ < names_list_length_) { + const auto* name = names_list_ + ni->name_offset_; + try { + TaggedValue tv = static_cast(name[0]); + if (tv == baldr::TaggedValue::kPronunciation) { + size_t pos = 1; + while (pos < strlen(name)) { + const auto& header = *reinterpret_cast(name + pos); + pos += 3; + std::unordered_map>::iterator iter = + index_pronunciation_map.find(header.name_index_); + + if (iter == index_pronunciation_map.end()) + index_pronunciation_map.emplace( + std::make_pair(header.name_index_, + std::make_pair(header.phonetic_alphabet_, + std::string((name + pos), header.length_)))); + else { + if (header.phonetic_alphabet_ > (iter->second).first) { + iter->second = std::make_pair(header.phonetic_alphabet_, + std::string((name + pos), header.length_)); + } + } + + pos += header.length_; + } + } + } catch (const std::invalid_argument& arg) { + LOG_DEBUG("invalid_argument thrown for name: " + std::string(name)); + } + } else { + throw std::runtime_error("GetPronunciationsMap: offset exceeds size of text list"); + } + } + + return index_pronunciation_map; +} + // Get the types. Are these names route numbers or not? uint16_t EdgeInfo::GetTypes() const { // Get the types. diff --git a/src/baldr/graphtile.cc b/src/baldr/graphtile.cc index 20e3b9a0ae..01f8da27e2 100644 --- a/src/baldr/graphtile.cc +++ b/src/baldr/graphtile.cc @@ -654,6 +654,7 @@ GraphTile::GetDirectedEdges(const uint32_t node_index, uint32_t& count, uint32_t return directededge(nodeinfo->edge_index()); } +// Convenience method to get the names for an edge std::vector GraphTile::GetNames(const DirectedEdge* edge) const { return edgeinfo(edge).GetNames(); } @@ -689,14 +690,77 @@ std::string GraphTile::GetName(const uint32_t textlist_offset) const { } } +// Convenience method to process the signs for an edge given the +// directed edge or node index. +std::vector GraphTile::ProcessSigns(const uint32_t idx, bool signs_on_node) const { + uint32_t count = header_->signcount(); + std::vector signs; + if (count == 0) { + return signs; + } + + // Signs are sorted by edge index. + // Binary search to find a sign with matching edge index. + int32_t low = 0; + int32_t high = count - 1; + int32_t mid; + int32_t found = count; + while (low <= high) { + mid = (low + high) / 2; + const auto& sign = signs_[mid]; + // matching edge index + if (idx == sign.index()) { + found = mid; + high = mid - 1; + } // need a smaller index + else if (idx < sign.index()) { + high = mid - 1; + } // need a bigger index + else { + low = mid + 1; + } + } + + // Add signs + for (; found < count && signs_[found].index() == idx; ++found) { + if (signs_[found].text_offset() < textlist_size_) { + + std::string text = (textlist_ + signs_[found].text_offset()); + + // only add named signs when asking for signs at the node and + // only add edge signs when asking for signs at the edges. + if (((signs_[found].type() == Sign::Type::kJunctionName || + (signs_[found].type() == Sign::Type::kPronunciation && signs_[found].route_num_type())) && + signs_on_node) || + (((signs_[found].type() != Sign::Type::kJunctionName && + signs_[found].type() != Sign::Type::kPronunciation) || + (signs_[found].type() == Sign::Type::kPronunciation && + !signs_[found].route_num_type())) && + !signs_on_node)) + signs.emplace_back(signs_[found].type(), signs_[found].route_num_type(), + signs_[found].tagged(), false, 0, 0, text); + } else { + throw std::runtime_error("GetSigns: offset exceeds size of text list"); + } + } + if (signs.size() == 0) { + LOG_ERROR("No signs found for idx = " + std::to_string(idx)); + } + return signs; +} + // Convenience method to get the signs for an edge given the // directed edge index. -std::vector GraphTile::GetSigns(const uint32_t idx, bool signs_on_node) const { +std::vector GraphTile::GetSigns( + const uint32_t idx, + std::unordered_map>& index_pronunciation_map, + bool signs_on_node) const { uint32_t count = header_->signcount(); std::vector signs; if (count == 0) { return signs; } + index_pronunciation_map.reserve(count); // Signs are sorted by edge index. // Binary search to find a sign with matching edge index. @@ -723,8 +787,36 @@ std::vector GraphTile::GetSigns(const uint32_t idx, bool signs_on_node // Add signs for (; found < count && signs_[found].index() == idx; ++found) { if (signs_[found].text_offset() < textlist_size_) { - // Skip tagged text strings (Future code is needed to handle tagged strings) - if (signs_[found].tagged()) { + + const auto* text = (textlist_ + signs_[found].text_offset()); + if (signs_[found].tagged() && signs_[found].type() == Sign::Type::kPronunciation) { + + // route_num_type indicates if this phonome is for a node or not + if ((signs_[found].route_num_type() && signs_on_node) || + (!signs_[found].route_num_type() && !signs_on_node)) { + size_t pos = 0; + while (pos < strlen(text)) { + const auto& header = *reinterpret_cast(text + pos); + pos += 3; + + std::unordered_map>::iterator iter = + index_pronunciation_map.find(header.name_index_); + + if (iter == index_pronunciation_map.end()) + index_pronunciation_map.emplace( + std::make_pair(header.name_index_, + std::make_pair(header.phonetic_alphabet_, + std::string((text + pos), header.length_)))); + else { + if (header.phonetic_alphabet_ > (iter->second).first) { + iter->second = std::make_pair(header.phonetic_alphabet_, + std::string((text + pos), header.length_)); + } + } + + pos += header.length_; + } + } continue; } @@ -733,7 +825,7 @@ std::vector GraphTile::GetSigns(const uint32_t idx, bool signs_on_node if ((signs_[found].type() == Sign::Type::kJunctionName && signs_on_node) || (signs_[found].type() != Sign::Type::kJunctionName && !signs_on_node)) signs.emplace_back(signs_[found].type(), signs_[found].route_num_type(), - (textlist_ + signs_[found].text_offset())); + signs_[found].tagged(), false, 0, 0, text); } else { throw std::runtime_error("GetSigns: offset exceeds size of text list"); } diff --git a/src/baldr/pronunciation.cc b/src/baldr/pronunciation.cc new file mode 100644 index 0000000000..35e4d234e1 --- /dev/null +++ b/src/baldr/pronunciation.cc @@ -0,0 +1,21 @@ +#include "baldr/pronunciation.h" + +namespace valhalla { +namespace baldr { + +// Constructor +Pronunciation::Pronunciation(const valhalla::Pronunciation_Alphabet alphabet, + const std::string& value) + : alphabet_(alphabet), value_(value) { +} + +valhalla::Pronunciation_Alphabet Pronunciation::alphabet() const { + return alphabet_; +} + +const std::string& Pronunciation::value() const { + return value_; +} + +} // namespace baldr +} // namespace valhalla diff --git a/src/baldr/streetname.cc b/src/baldr/streetname.cc index b063423732..9369e5138d 100644 --- a/src/baldr/streetname.cc +++ b/src/baldr/streetname.cc @@ -1,12 +1,18 @@ #include +#include + +#include "baldr/pronunciation.h" #include "baldr/streetname.h" namespace valhalla { namespace baldr { -StreetName::StreetName(const std::string& value, const bool is_route_number) - : value_(value), is_route_number_(is_route_number) { +// Constructor +StreetName::StreetName(const std::string& value, + const bool is_route_number, + const boost::optional& pronunciation) + : value_(value), is_route_number_(is_route_number), pronunciation_(pronunciation) { } StreetName::~StreetName() { @@ -20,6 +26,10 @@ bool StreetName::is_route_number() const { return is_route_number_; } +const boost::optional& StreetName::pronunciation() const { + return pronunciation_; +} + bool StreetName::operator==(const StreetName& rhs) const { return ((value_ == rhs.value_) && (is_route_number_ == rhs.is_route_number_)); } diff --git a/src/baldr/streetname_us.cc b/src/baldr/streetname_us.cc index 8e7022c6ee..f76ae19e41 100644 --- a/src/baldr/streetname_us.cc +++ b/src/baldr/streetname_us.cc @@ -1,5 +1,6 @@ #include +#include "baldr/pronunciation.h" #include "baldr/streetname.h" #include "baldr/streetname_us.h" @@ -15,8 +16,10 @@ const std::vector StreetNameUs::post_dirs_{" North", " East", const std::vector StreetNameUs::post_cardinal_dirs_{" North", " East", " South", " West"}; -StreetNameUs::StreetNameUs(const std::string& value, const bool is_route_number) - : StreetName(value, is_route_number) { +StreetNameUs::StreetNameUs(const std::string& value, + const bool is_route_number, + const boost::optional& pronunciation) + : StreetName(value, is_route_number, pronunciation) { } std::string StreetNameUs::GetPreDir() const { diff --git a/src/baldr/streetnames.cc b/src/baldr/streetnames.cc index 84c9bdfcf7..f0aa4fc581 100644 --- a/src/baldr/streetnames.cc +++ b/src/baldr/streetnames.cc @@ -1,10 +1,14 @@ #include #include +#include + +#include "baldr/pronunciation.h" #include "baldr/streetnames.h" #include "baldr/verbal_text_formatter.h" #include "baldr/verbal_text_formatter_us.h" #include "midgard/util.h" +#include "proto/tripcommon.pb.h" namespace valhalla { namespace baldr { @@ -14,7 +18,18 @@ StreetNames::StreetNames() : std::list>() { StreetNames::StreetNames(const std::vector>& names) { for (auto& name : names) { - this->emplace_back(std::make_unique(name.first, name.second)); + this->emplace_back(std::make_unique(name.first, name.second, boost::none)); + } +} + +StreetNames::StreetNames(const google::protobuf::RepeatedPtrField& names) { + for (auto& name : names) { + boost::optional pronunciation = + boost::make_optional(name.has_pronunciation(), + baldr::Pronunciation{name.pronunciation().alphabet(), + name.pronunciation().value()}); + this->emplace_back( + std::make_unique(name.value(), name.is_route_number(), pronunciation)); } } @@ -39,6 +54,11 @@ std::string StreetNames::ToString(uint32_t max_count, } name_string += (verbal_formatter) ? verbal_formatter->Format(street_name->value()) : street_name->value(); + if (street_name->pronunciation()) { + name_string += "("; + name_string += street_name->pronunciation()->value(); + name_string += ")"; + } ++count; } return name_string; @@ -70,8 +90,9 @@ std::string StreetNames::ToParameterString() const { std::unique_ptr StreetNames::clone() const { std::unique_ptr clone_street_names = std::make_unique(); for (const auto& street_name : *this) { - clone_street_names->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + clone_street_names->emplace_back(std::make_unique(street_name->value(), + street_name->is_route_number(), + street_name->pronunciation())); } return clone_street_names; @@ -83,8 +104,9 @@ StreetNames::FindCommonStreetNames(const StreetNames& other_street_names) const for (const auto& street_name : *this) { for (const auto& other_street_name : other_street_names) { if (*street_name == *other_street_name) { - common_street_names->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + common_street_names->emplace_back(std::make_unique(street_name->value(), + street_name->is_route_number(), + street_name->pronunciation())); break; } } @@ -102,16 +124,19 @@ StreetNames::FindCommonBaseNames(const StreetNames& other_street_names) const { // Use the name with the cardinal directional suffix // thus, 'US 30 West' will be used instead of 'US 30' if (!street_name->GetPostCardinalDir().empty()) { - common_base_names->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + common_base_names->emplace_back(std::make_unique(street_name->value(), + street_name->is_route_number(), + street_name->pronunciation())); } else if (!other_street_name->GetPostCardinalDir().empty()) { common_base_names->emplace_back( std::make_unique(other_street_name->value(), - street_name->is_route_number())); + other_street_name->is_route_number(), + other_street_name->pronunciation())); // Use street_name by default } else { - common_base_names->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + common_base_names->emplace_back(std::make_unique(street_name->value(), + street_name->is_route_number(), + street_name->pronunciation())); } break; } @@ -125,8 +150,9 @@ std::unique_ptr StreetNames::GetRouteNumbers() const { std::unique_ptr route_numbers = std::make_unique(); for (const auto& street_name : *this) { if (street_name->is_route_number()) { - route_numbers->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + route_numbers->emplace_back(std::make_unique(street_name->value(), + street_name->is_route_number(), + street_name->pronunciation())); } } @@ -137,8 +163,9 @@ std::unique_ptr StreetNames::GetNonRouteNumbers() const { std::unique_ptr non_route_numbers = std::make_unique(); for (const auto& street_name : *this) { if (!street_name->is_route_number()) { - non_route_numbers->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + non_route_numbers->emplace_back(std::make_unique(street_name->value(), + street_name->is_route_number(), + street_name->pronunciation())); } } diff --git a/src/baldr/streetnames_factory.cc b/src/baldr/streetnames_factory.cc index 13aa727f2f..fc23f1b5f6 100644 --- a/src/baldr/streetnames_factory.cc +++ b/src/baldr/streetnames_factory.cc @@ -6,6 +6,7 @@ #include "baldr/streetnames_factory.h" #include "baldr/streetnames_us.h" #include "midgard/util.h" +#include "proto/tripcommon.pb.h" namespace valhalla { namespace baldr { @@ -20,5 +21,15 @@ StreetNamesFactory::Create(const std::string& country_code, return std::make_unique(names); } +std::unique_ptr +StreetNamesFactory::Create(const std::string& country_code, + const google::protobuf::RepeatedPtrField& names) { + if (country_code == "US") { + return std::make_unique(names); + } + + return std::make_unique(names); +} + } // namespace baldr } // namespace valhalla diff --git a/src/baldr/streetnames_us.cc b/src/baldr/streetnames_us.cc index 3b5ff6a374..793f0224eb 100644 --- a/src/baldr/streetnames_us.cc +++ b/src/baldr/streetnames_us.cc @@ -1,8 +1,12 @@ #include #include +#include + +#include "baldr/pronunciation.h" #include "baldr/streetnames_us.h" #include "midgard/util.h" +#include "proto/tripcommon.pb.h" namespace valhalla { namespace baldr { @@ -12,7 +16,19 @@ StreetNamesUs::StreetNamesUs() : StreetNames() { StreetNamesUs::StreetNamesUs(const std::vector>& names) { for (auto& name : names) { - this->emplace_back(std::make_unique(name.first, name.second)); + this->emplace_back(std::make_unique(name.first, name.second, boost::none)); + } +} + +StreetNamesUs::StreetNamesUs(const google::protobuf::RepeatedPtrField& names) { + for (auto& name : names) { + boost::optional pronunciation = + boost::make_optional(name.has_pronunciation(), + baldr::Pronunciation{name.pronunciation().alphabet(), + name.pronunciation().value()}); + + this->emplace_back( + std::make_unique(name.value(), name.is_route_number(), pronunciation)); } } @@ -22,8 +38,9 @@ StreetNamesUs::~StreetNamesUs() { std::unique_ptr StreetNamesUs::clone() const { std::unique_ptr clone_street_names = std::make_unique(); for (const auto& street_name : *this) { - clone_street_names->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + clone_street_names->emplace_back(std::make_unique(street_name->value(), + street_name->is_route_number(), + street_name->pronunciation())); } return clone_street_names; @@ -36,7 +53,8 @@ StreetNamesUs::FindCommonStreetNames(const StreetNames& other_street_names) cons for (const auto& other_street_name : other_street_names) { if (*street_name == *other_street_name) { common_street_names->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + std::make_unique(street_name->value(), street_name->is_route_number(), + street_name->pronunciation())); break; } } @@ -55,15 +73,18 @@ StreetNamesUs::FindCommonBaseNames(const StreetNames& other_street_names) const // thus, 'US 30 West' will be used instead of 'US 30' if (!street_name->GetPostCardinalDir().empty()) { common_base_names->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + std::make_unique(street_name->value(), street_name->is_route_number(), + street_name->pronunciation())); } else if (!other_street_name->GetPostCardinalDir().empty()) { common_base_names->emplace_back( std::make_unique(other_street_name->value(), - street_name->is_route_number())); + other_street_name->is_route_number(), + other_street_name->pronunciation())); // Use street_name by default } else { common_base_names->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + std::make_unique(street_name->value(), street_name->is_route_number(), + street_name->pronunciation())); } break; } @@ -77,8 +98,9 @@ std::unique_ptr StreetNamesUs::GetRouteNumbers() const { std::unique_ptr route_numbers = std::make_unique(); for (const auto& street_name : *this) { if (street_name->is_route_number()) { - route_numbers->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + route_numbers->emplace_back(std::make_unique(street_name->value(), + street_name->is_route_number(), + street_name->pronunciation())); } } @@ -89,8 +111,9 @@ std::unique_ptr StreetNamesUs::GetNonRouteNumbers() const { std::unique_ptr non_route_numbers = std::make_unique(); for (const auto& street_name : *this) { if (!street_name->is_route_number()) { - non_route_numbers->emplace_back( - std::make_unique(street_name->value(), street_name->is_route_number())); + non_route_numbers->emplace_back(std::make_unique(street_name->value(), + street_name->is_route_number(), + street_name->pronunciation())); } } diff --git a/src/baldr/verbal_text_formatter.cc b/src/baldr/verbal_text_formatter.cc index 6cc50e6543..964c2921e6 100644 --- a/src/baldr/verbal_text_formatter.cc +++ b/src/baldr/verbal_text_formatter.cc @@ -1,9 +1,10 @@ +#include + +#include #include "baldr/verbal_text_formatter.h" #include "midgard/util.h" -#include - namespace valhalla { namespace baldr { @@ -15,7 +16,12 @@ VerbalTextFormatter::VerbalTextFormatter(const std::string& country_code, VerbalTextFormatter::~VerbalTextFormatter() { } -std::string VerbalTextFormatter::Format(const std::string& text) const { +std::string VerbalTextFormatter::Format(const std::string& text, + const boost::optional& markup_string) const { + // If markup string exists then use it + if (markup_string) { + return *markup_string; + } std::string verbal_text(text); return verbal_text; diff --git a/src/baldr/verbal_text_formatter_us.cc b/src/baldr/verbal_text_formatter_us.cc index 1b4dfc45d0..270fc4c8eb 100644 --- a/src/baldr/verbal_text_formatter_us.cc +++ b/src/baldr/verbal_text_formatter_us.cc @@ -1,6 +1,8 @@ #include #include +#include + #include "baldr/verbal_text_formatter.h" #include "baldr/verbal_text_formatter_us.h" #include "midgard/util.h" @@ -16,7 +18,13 @@ VerbalTextFormatterUs::VerbalTextFormatterUs(const std::string& country_code, VerbalTextFormatterUs::~VerbalTextFormatterUs() { } -std::string VerbalTextFormatterUs::Format(const std::string& text) const { +std::string VerbalTextFormatterUs::Format(const std::string& text, + const boost::optional& markup_string) const { + // If markup string exists then use it + if (markup_string) { + return VerbalTextFormatter::Format(text, markup_string); + } + std::string verbal_text(text); verbal_text = FormInterstateTts(verbal_text); diff --git a/src/baldr/verbal_text_formatter_us_tx.cc b/src/baldr/verbal_text_formatter_us_tx.cc index c6cb11638a..3bf7b92766 100644 --- a/src/baldr/verbal_text_formatter_us_tx.cc +++ b/src/baldr/verbal_text_formatter_us_tx.cc @@ -1,6 +1,8 @@ #include #include +#include + #include "baldr/verbal_text_formatter.h" #include "baldr/verbal_text_formatter_us.h" #include "baldr/verbal_text_formatter_us_tx.h" @@ -17,7 +19,13 @@ VerbalTextFormatterUsTx::VerbalTextFormatterUsTx(const std::string& country_code VerbalTextFormatterUsTx::~VerbalTextFormatterUsTx() { } -std::string VerbalTextFormatterUsTx::Format(const std::string& text) const { +std::string VerbalTextFormatterUsTx::Format(const std::string& text, + const boost::optional& markup_string) const { + // If markup string exists then use it + if (markup_string) { + return VerbalTextFormatter::Format(text, markup_string); + } + std::string verbal_text(text); verbal_text = FormFmTts(verbal_text); verbal_text = FormRmTts(verbal_text); diff --git a/src/mjolnir/bssbuilder.cc b/src/mjolnir/bssbuilder.cc index c279b4d351..419b580ef1 100644 --- a/src/mjolnir/bssbuilder.cc +++ b/src/mjolnir/bssbuilder.cc @@ -50,6 +50,8 @@ struct BSSConnection { uint64_t wayid = std::numeric_limits::max(); std::vector names = {}; std::vector tagged_values = {}; + std::vector pronunciations = {}; + std::vector shape = {}; // Is the outbound edge from the waynode is forward? bool is_forward_from_waynode = true; @@ -77,6 +79,8 @@ struct BSSConnection { wayid = edgeinfo.wayid(); names = edgeinfo.GetNames(); tagged_values = edgeinfo.GetTaggedValues(); + pronunciations = edgeinfo.GetTaggedValues(true); + is_forward_from_waynode = is_forward; speed = best.directededge->speed(); surface = best.directededge->surface(); @@ -115,7 +119,6 @@ DirectedEdge make_directed_edge(const GraphId endnode, directededge.set_forwardaccess(accesses[static_cast(!is_forward)]); directededge.set_reverseaccess(accesses[static_cast(is_forward)]); - directededge.set_named(conn.names.size()); directededge.set_named(conn.names.size() > 0 || conn.tagged_values.size() > 0); directededge.set_forward(is_forward); directededge.set_bss_connection(true); @@ -305,7 +308,9 @@ void add_bss_nodes_and_edges(GraphTileBuilder& tilebuilder_local, tilebuilder_local.AddEdgeInfo(tilebuilder_local.directededges().size(), new_bss_node_graphid, bss_to_waynode.way_node_id, bss_to_waynode.wayid, 0, 0, 0, bss_to_waynode.shape, - bss_to_waynode.names, bss_to_waynode.tagged_values, 0, added); + bss_to_waynode.names, bss_to_waynode.tagged_values, + bss_to_waynode.pronunciations, 0, added); + directededge.set_edgeinfo_offset(edge_info_offset); tilebuilder_local.directededges().emplace_back(std::move(directededge)); } @@ -442,7 +447,9 @@ void create_edges(GraphTileBuilder& tilebuilder_local, uint32_t edge_info_offset = tilebuilder_local.AddEdgeInfo(tilebuilder_local.directededges().size(), lower->way_node_id, lower->bss_node_id, lower->wayid, 0, 0, 0, lower->shape, - lower->names, lower->tagged_values, 0, added); + lower->names, lower->tagged_values, lower->pronunciations, 0, + added); + directededge.set_edgeinfo_offset(edge_info_offset); tilebuilder_local.directededges().emplace_back(std::move(directededge)); diff --git a/src/mjolnir/graphbuilder.cc b/src/mjolnir/graphbuilder.cc index 24a08fd9c5..37b5bf2933 100644 --- a/src/mjolnir/graphbuilder.cc +++ b/src/mjolnir/graphbuilder.cc @@ -385,6 +385,7 @@ void BuildTileSet(const std::string& ways_file, const std::string& edges_file, const std::string& complex_restriction_from_file, const std::string& complex_restriction_to_file, + const std::string& pronunciation_file, const std::string& tile_dir, const OSMData& osmdata, std::map::const_iterator tile_start, @@ -400,6 +401,11 @@ void BuildTileSet(const std::string& ways_file, sequence complex_restrictions_from(complex_restriction_from_file, false); sequence complex_restrictions_to(complex_restriction_to_file, false); + auto less_than = [](const OSMPronunciation& a, const OSMPronunciation& b) { + return a.way_id() < b.way_id(); + }; + sequence pronunciation(pronunciation_file, false); + auto database = pt.get_optional("admin"); bool infer_internal_intersections = pt.get("data_processing.infer_internal_intersections", true); @@ -693,6 +699,16 @@ void BuildTileSet(const std::string& ways_file, } } + OSMPronunciation p{0}; + if (w.has_pronunciation_tags()) { + OSMPronunciation target{w.way_id()}; + sequence::iterator pronunciation_it = + pronunciation.find(target, less_than); + if (pronunciation_it != pronunciation.end()) { + p = pronunciation_it; + } + } + // Get the shape for the edge and compute its length uint32_t edge_info_offset; auto found = geo_attribute_cache.cend(); @@ -703,10 +719,13 @@ void BuildTileSet(const std::string& ways_file, auto shape = EdgeShape(edge.llindex_, edge.attributes.llcount); uint16_t types = 0; - auto names = w.GetNames(ref, osmdata.name_offset_map, types); - auto tagged_values = w.GetTaggedValues(osmdata.name_offset_map); + std::vector names, tagged_values, pronunciations; + w.GetNames(ref, osmdata.name_offset_map, p, types, names, pronunciations); + w.GetTaggedValues(osmdata.name_offset_map, p, names.size(), tagged_values, + pronunciations); // Update bike_network type + if (bike_network) { bike_network |= w.bike_network(); } else { @@ -714,10 +733,11 @@ void BuildTileSet(const std::string& ways_file, } // Add edge info. Mean elevation is set to 1234 as a placeholder, set later if we have it. - edge_info_offset = graphtile.AddEdgeInfo(edge_pair.second, (*nodes[source]).graph_id, - (*nodes[target]).graph_id, w.way_id(), 1234, - bike_network, speed_limit, shape, names, - tagged_values, types, added, dual_refs); + edge_info_offset = + graphtile.AddEdgeInfo(edge_pair.second, (*nodes[source]).graph_id, + (*nodes[target]).graph_id, w.way_id(), 1234, bike_network, + speed_limit, shape, names, tagged_values, pronunciations, types, + added, dual_refs); if (added) { stats.edgeinfocount++; } @@ -785,11 +805,11 @@ void BuildTileSet(const std::string& ways_file, // TODO - update logic so we limit the CreateSignInfoList calls // Any exits for this directed edge? is auto and oneway? std::vector signs; + std::vector pronunciations; bool has_guide = - GraphBuilder::CreateSignInfoList(node, w, osmdata, signs, fork, forward, - (directededge.use() == Use::kRamp), + GraphBuilder::CreateSignInfoList(node, w, p, osmdata, signs, pronunciations, fork, + forward, (directededge.use() == Use::kRamp), (directededge.use() == Use::kTurnChannel)); - // add signs if signs exist // and directed edge if forward access and auto use // and directed edge is a link and not (link count=2 and driveforward count=1) @@ -799,7 +819,8 @@ void BuildTileSet(const std::string& ways_file, ((directededge.link() && (!((bundle.link_count == 2) && (bundle.driveforward_count == 1)))) || fork || has_guide)) { - graphtile.AddSigns(idx, signs); + + graphtile.AddSigns(idx, signs, pronunciations); directededge.set_sign(true); } @@ -1010,17 +1031,43 @@ void BuildTileSet(const std::string& ways_file, } if (admin_index != 0 && node.named_intersection() && allow_intersection_names[admin_index]) { + std::vector node_names; node_names = GetTagTokens(osmdata.node_names.name(node.name_index())); std::vector signs; signs.reserve(node_names.size()); - for (auto& name : node_names) { - signs.emplace_back(Sign::Type::kJunctionName, false, name); + + std::vector ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens; + GraphBuilder::GetPronunciationTokens(osmdata, node.name_pronunciation_ipa_index(), + node.name_pronunciation_nt_sampa_index(), + node.name_pronunciation_katakana_index(), + node.name_pronunciation_jeita_index(), ipa_tokens, + nt_sampa_tokens, katakana_tokens, jeita_tokens, true); + + bool add_ipa = (ipa_tokens.size() && node_names.size() == ipa_tokens.size()); + bool add_nt_sampa = (nt_sampa_tokens.size() && node_names.size() == nt_sampa_tokens.size()); + bool add_katakana = (katakana_tokens.size() && node_names.size() == katakana_tokens.size()); + bool add_jeita = (jeita_tokens.size() && node_names.size() == jeita_tokens.size()); + + std::vector pronunciations; + + for (size_t i = 0; i < node_names.size(); ++i) { + if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + GraphBuilder::BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, + jeita_tokens, i, pronunciations, add_ipa, + add_nt_sampa, add_katakana, add_jeita, count); + signs.emplace_back(Sign::Type::kJunctionName, false, false, (count != 0), size, count, + node_names[i]); + } else + signs.emplace_back(Sign::Type::kJunctionName, false, false, false, 0, 0, node_names[i]); } + if (signs.size()) { graphtile.nodes().back().set_named_intersection(true); - graphtile.AddSigns(graphtile.nodes().size() - 1, signs); + graphtile.AddSigns(graphtile.nodes().size() - 1, signs, pronunciations); } } // Set drive on right flag @@ -1082,6 +1129,7 @@ void BuildLocalTiles(const unsigned int thread_count, const std::string& edges_file, const std::string& complex_from_restriction_file, const std::string& complex_to_restriction_file, + const std::string& pronunciation_file, const std::map& tiles, const std::string& tile_dir, DataQuality& stats, @@ -1116,7 +1164,8 @@ void BuildLocalTiles(const unsigned int thread_count, threads[i].reset(new std::thread(BuildTileSet, std::cref(ways_file), std::cref(way_nodes_file), std::cref(nodes_file), std::cref(edges_file), std::cref(complex_from_restriction_file), - std::cref(complex_to_restriction_file), std::cref(tile_dir), + std::cref(complex_to_restriction_file), + std::cref(pronunciation_file), std::cref(tile_dir), std::cref(osmdata), tile_start, tile_end, tile_creation_date, std::cref(pt.get_child("mjolnir")), std::ref(results[i]))); } @@ -1173,6 +1222,7 @@ void GraphBuilder::Build(const boost::property_tree::ptree& pt, const std::string& edges_file, const std::string& complex_from_restriction_file, const std::string& complex_to_restriction_file, + const std::string& pronunciation_file, const std::map& tiles) { // Reclassify links (ramps). Cannot do this when building tiles since the // edge list needs to be modified @@ -1200,8 +1250,8 @@ void GraphBuilder::Build(const boost::property_tree::ptree& pt, // Build tiles at the local level. Form connected graph from nodes and edges. std::string tile_dir = pt.get("mjolnir.tile_dir"); BuildLocalTiles(threads, osmdata, ways_file, way_nodes_file, nodes_file, edges_file, - complex_from_restriction_file, complex_to_restriction_file, tiles, tile_dir, stats, - pt); + complex_from_restriction_file, complex_to_restriction_file, pronunciation_file, + tiles, tile_dir, stats, pt); stats.LogStatistics(); } @@ -1254,30 +1304,154 @@ std::string GraphBuilder::GetRef(const std::string& way_ref, const std::string& return refs; } +void GraphBuilder::GetPronunciationTokens(const OSMData& osmdata, + const uint32_t ipa_index, + const uint32_t nt_sampa_index, + const uint32_t katakana_index, + const uint32_t jeita_index, + std::vector& ipa_tokens, + std::vector& nt_sampa_tokens, + std::vector& katakana_tokens, + std::vector& jeita_tokens, + bool is_node_pronunciation) { + + if (is_node_pronunciation) { + if (ipa_index != 0) + ipa_tokens = GetTagTokens(osmdata.node_names.name(ipa_index)); + + if (nt_sampa_index != 0) + nt_sampa_tokens = GetTagTokens(osmdata.node_names.name(nt_sampa_index)); + + if (katakana_index != 0) + katakana_tokens = GetTagTokens(osmdata.node_names.name(katakana_index)); + + if (jeita_index != 0) + jeita_tokens = GetTagTokens(osmdata.node_names.name(jeita_index)); + + } else { + if (ipa_index != 0) + ipa_tokens = GetTagTokens(osmdata.name_offset_map.name(ipa_index)); + + if (nt_sampa_index != 0) + nt_sampa_tokens = GetTagTokens(osmdata.name_offset_map.name(nt_sampa_index)); + + if (katakana_index != 0) + katakana_tokens = GetTagTokens(osmdata.name_offset_map.name(katakana_index)); + + if (jeita_index != 0) + jeita_tokens = GetTagTokens(osmdata.name_offset_map.name(jeita_index)); + } +} + +void GraphBuilder::AddPronunciation(const baldr::PronunciationAlphabet alphabet, + const std::string& phoneme, + std::vector& pronunciations, + uint32_t& count) { + + // TODO set the language + if (phoneme.size()) { + linguistic_text_header_t header{static_cast(baldr::Language::kNone), 0, + static_cast(alphabet), static_cast(0)}; + header.length_ = phoneme.length(); + pronunciations.emplace_back((std::string(reinterpret_cast(&header), 3) + phoneme)); + count++; + } +} + +void GraphBuilder::BuildPronunciations(const std::vector& ipa_tokens, + const std::vector& nt_sampa_tokens, + const std::vector& katakana_tokens, + const std::vector& jeita_tokens, + const size_t index, + std::vector& pronunciations, + bool add_ipa, + bool add_nt_sampa, + bool add_katakana, + bool add_jeita, + uint32_t& count) { + if (add_ipa) + AddPronunciation(PronunciationAlphabet::kIpa, ipa_tokens[index], pronunciations, count); + + if (add_nt_sampa) + AddPronunciation(PronunciationAlphabet::kNtSampa, nt_sampa_tokens[index], pronunciations, count); + + if (add_katakana) + AddPronunciation(PronunciationAlphabet::kXKatakana, katakana_tokens[index], pronunciations, + count); + + if (add_jeita) + AddPronunciation(PronunciationAlphabet::kXJeita, jeita_tokens[index], pronunciations, count); +} + bool GraphBuilder::CreateSignInfoList(const OSMNode& node, const OSMWay& way, + const OSMPronunciation& pronunciation, const OSMData& osmdata, std::vector& exit_list, + std::vector& pronunciations, bool fork, bool forward, bool ramp, bool tc) { bool has_guide = false; + //////////////////////////////////////////////////////////////////////////// // NUMBER // Exit sign number if (way.junction_ref_index() != 0) { - std::vector j_refs = GetTagTokens(osmdata.name_offset_map.name(way.junction_ref_index())); - for (auto& j_ref : j_refs) { - exit_list.emplace_back(Sign::Type::kExitNumber, false, j_ref); + + std::vector ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens; + GetPronunciationTokens(osmdata, pronunciation.junction_ref_pronunciation_ipa_index(), + pronunciation.junction_ref_pronunciation_nt_sampa_index(), + pronunciation.junction_ref_pronunciation_katakana_index(), + pronunciation.junction_ref_pronunciation_jeita_index(), ipa_tokens, + nt_sampa_tokens, katakana_tokens, jeita_tokens); + + bool add_ipa = (ipa_tokens.size() && j_refs.size() == ipa_tokens.size()); + bool add_nt_sampa = (nt_sampa_tokens.size() && j_refs.size() == nt_sampa_tokens.size()); + bool add_katakana = (katakana_tokens.size() && j_refs.size() == katakana_tokens.size()); + bool add_jeita = (jeita_tokens.size() && j_refs.size() == jeita_tokens.size()); + + for (size_t i = 0; i < j_refs.size(); ++i) { + if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + exit_list.emplace_back(Sign::Type::kExitNumber, false, false, (count != 0), size, count, + j_refs[i]); + } else + exit_list.emplace_back(Sign::Type::kExitNumber, false, false, false, 0, 0, j_refs[i]); } } else if (node.has_ref() && !fork && ramp) { + std::vector n_refs = GetTagTokens(osmdata.node_names.name(node.ref_index())); - for (auto& n_ref : n_refs) { - exit_list.emplace_back(Sign::Type::kExitNumber, false, n_ref); + + std::vector ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens; + GetPronunciationTokens(osmdata, node.ref_pronunciation_ipa_index(), + node.ref_pronunciation_nt_sampa_index(), + node.ref_pronunciation_katakana_index(), + node.ref_pronunciation_jeita_index(), ipa_tokens, nt_sampa_tokens, + katakana_tokens, jeita_tokens, true); + + bool add_ipa = (ipa_tokens.size() && n_refs.size() == ipa_tokens.size()); + bool add_nt_sampa = (nt_sampa_tokens.size() && n_refs.size() == nt_sampa_tokens.size()); + bool add_katakana = (katakana_tokens.size() && n_refs.size() == katakana_tokens.size()); + bool add_jeita = (jeita_tokens.size() && n_refs.size() == jeita_tokens.size()); + + for (size_t i = 0; i < n_refs.size(); ++i) { + if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + exit_list.emplace_back(Sign::Type::kExitNumber, false, false, (count != 0), size, count, + n_refs[i]); + } else + exit_list.emplace_back(Sign::Type::kExitNumber, false, false, false, 0, 0, n_refs[i]); } } @@ -1291,12 +1465,40 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, has_branch = true; std::vector branch_refs = GetTagTokens(osmdata.name_offset_map.name(way.destination_ref_index())); - for (auto& branch_ref : branch_refs) { + + std::vector ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens; + GetPronunciationTokens(osmdata, pronunciation.destination_ref_pronunciation_ipa_index(), + pronunciation.destination_ref_pronunciation_nt_sampa_index(), + pronunciation.destination_ref_pronunciation_katakana_index(), + pronunciation.destination_ref_pronunciation_jeita_index(), ipa_tokens, + nt_sampa_tokens, katakana_tokens, jeita_tokens); + + bool add_ipa = (ipa_tokens.size() && branch_refs.size() == ipa_tokens.size()); + bool add_nt_sampa = (nt_sampa_tokens.size() && branch_refs.size() == nt_sampa_tokens.size()); + bool add_katakana = (katakana_tokens.size() && branch_refs.size() == katakana_tokens.size()); + bool add_jeita = (jeita_tokens.size() && branch_refs.size() == jeita_tokens.size()); + + for (size_t i = 0; i < branch_refs.size(); ++i) { if (tc || (!ramp && !fork)) { - exit_list.emplace_back(Sign::Type::kGuideBranch, true, branch_ref); + if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + exit_list.emplace_back(Sign::Type::kGuideBranch, true, false, (count != 0), size, count, + branch_refs[i]); + } else + exit_list.emplace_back(Sign::Type::kGuideBranch, true, false, false, 0, 0, branch_refs[i]); has_guide = true; + } else if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + exit_list.emplace_back(Sign::Type::kExitBranch, true, false, (count != 0), size, count, + branch_refs[i]); } else - exit_list.emplace_back(Sign::Type::kExitBranch, true, branch_ref); + exit_list.emplace_back(Sign::Type::kExitBranch, true, false, false, 0, 0, branch_refs[i]); } } @@ -1305,12 +1507,41 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, has_branch = true; std::vector branch_streets = GetTagTokens(osmdata.name_offset_map.name(way.destination_street_index())); - for (auto& branch_street : branch_streets) { + + std::vector ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens; + GetPronunciationTokens(osmdata, pronunciation.destination_street_pronunciation_ipa_index(), + pronunciation.destination_street_pronunciation_nt_sampa_index(), + pronunciation.destination_street_pronunciation_katakana_index(), + pronunciation.destination_street_pronunciation_jeita_index(), ipa_tokens, + nt_sampa_tokens, katakana_tokens, jeita_tokens); + + bool add_ipa = (ipa_tokens.size() && branch_streets.size() == ipa_tokens.size()); + bool add_nt_sampa = (nt_sampa_tokens.size() && branch_streets.size() == nt_sampa_tokens.size()); + bool add_katakana = (katakana_tokens.size() && branch_streets.size() == katakana_tokens.size()); + bool add_jeita = (jeita_tokens.size() && branch_streets.size() == jeita_tokens.size()); + + for (size_t i = 0; i < branch_streets.size(); ++i) { if (tc || (!ramp && !fork)) { - exit_list.emplace_back(Sign::Type::kGuideBranch, false, branch_street); + if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + exit_list.emplace_back(Sign::Type::kGuideBranch, false, false, (count != 0), size, count, + branch_streets[i]); + } else + exit_list.emplace_back(Sign::Type::kGuideBranch, false, false, false, 0, 0, + branch_streets[i]); has_guide = true; + } else if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + exit_list.emplace_back(Sign::Type::kExitBranch, false, false, (count != 0), size, count, + branch_streets[i]); } else - exit_list.emplace_back(Sign::Type::kExitBranch, false, branch_street); + exit_list.emplace_back(Sign::Type::kExitBranch, false, false, false, 0, 0, branch_streets[i]); } } @@ -1321,15 +1552,45 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, // Guide or Exit sign toward refs if (way.destination_ref_to_index() != 0) { + has_toward = true; std::vector toward_refs = GetTagTokens(osmdata.name_offset_map.name(way.destination_ref_to_index())); - for (auto& toward_ref : toward_refs) { + + std::vector ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens; + GetPronunciationTokens(osmdata, pronunciation.destination_ref_to_pronunciation_ipa_index(), + pronunciation.destination_ref_to_pronunciation_nt_sampa_index(), + pronunciation.destination_ref_to_pronunciation_katakana_index(), + pronunciation.destination_ref_to_pronunciation_jeita_index(), ipa_tokens, + nt_sampa_tokens, katakana_tokens, jeita_tokens); + + bool add_ipa = (ipa_tokens.size() && toward_refs.size() == ipa_tokens.size()); + bool add_nt_sampa = (nt_sampa_tokens.size() && toward_refs.size() == nt_sampa_tokens.size()); + bool add_katakana = (katakana_tokens.size() && toward_refs.size() == katakana_tokens.size()); + bool add_jeita = (jeita_tokens.size() && toward_refs.size() == jeita_tokens.size()); + + for (size_t i = 0; i < toward_refs.size(); ++i) { if (tc || (!ramp && !fork)) { - exit_list.emplace_back(Sign::Type::kGuideToward, true, toward_ref); + if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + exit_list.emplace_back(Sign::Type::kGuideToward, true, false, (count != 0), size, count, + toward_refs[i]); + } else + exit_list.emplace_back(Sign::Type::kGuideToward, true, false, false, 0, 0, toward_refs[i]); + has_guide = true; + } else if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + exit_list.emplace_back(Sign::Type::kExitToward, true, false, (count != 0), size, count, + toward_refs[i]); } else - exit_list.emplace_back(Sign::Type::kExitToward, true, toward_ref); + exit_list.emplace_back(Sign::Type::kExitToward, true, false, false, 0, 0, toward_refs[i]); } } @@ -1338,12 +1599,43 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, has_toward = true; std::vector toward_streets = GetTagTokens(osmdata.name_offset_map.name(way.destination_street_to_index())); - for (auto& toward_street : toward_streets) { + + std::vector ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens; + GetPronunciationTokens(osmdata, pronunciation.destination_street_to_pronunciation_ipa_index(), + pronunciation.destination_street_to_pronunciation_nt_sampa_index(), + pronunciation.destination_street_to_pronunciation_katakana_index(), + pronunciation.destination_street_to_pronunciation_jeita_index(), + ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens); + + bool add_ipa = (ipa_tokens.size() && toward_streets.size() == ipa_tokens.size()); + bool add_nt_sampa = (nt_sampa_tokens.size() && toward_streets.size() == nt_sampa_tokens.size()); + bool add_katakana = (katakana_tokens.size() && toward_streets.size() == katakana_tokens.size()); + bool add_jeita = (jeita_tokens.size() && toward_streets.size() == jeita_tokens.size()); + + for (size_t i = 0; i < toward_streets.size(); ++i) { if (tc || (!ramp && !fork)) { - exit_list.emplace_back(Sign::Type::kGuideToward, false, toward_street); + if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + exit_list.emplace_back(Sign::Type::kGuideToward, false, false, (count != 0), size, count, + toward_streets[i]); + } else + exit_list.emplace_back(Sign::Type::kGuideToward, false, false, false, 0, 0, + toward_streets[i]); + has_guide = true; + } else if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + exit_list.emplace_back(Sign::Type::kExitToward, false, false, (count != 0), size, count, + toward_streets[i]); + } else - exit_list.emplace_back(Sign::Type::kExitToward, false, toward_street); + exit_list.emplace_back(Sign::Type::kExitToward, false, false, false, 0, 0, toward_streets[i]); } } @@ -1355,17 +1647,73 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, : (forward ? way.destination_forward_index() : way.destination_backward_index()); std::vector toward_names = GetTagTokens(osmdata.name_offset_map.name(index)); - for (auto& toward_name : toward_names) { + + uint32_t ipa_index = + pronunciation.destination_pronunciation_ipa_index() + ? pronunciation.destination_pronunciation_ipa_index() + : (forward ? pronunciation.destination_forward_pronunciation_ipa_index() + : pronunciation.destination_backward_pronunciation_ipa_index()); + + uint32_t nt_sampa_index = + pronunciation.destination_pronunciation_nt_sampa_index() + ? pronunciation.destination_pronunciation_nt_sampa_index() + : (forward ? pronunciation.destination_forward_pronunciation_nt_sampa_index() + : pronunciation.destination_backward_pronunciation_nt_sampa_index()); + + uint32_t katakana_index = + pronunciation.destination_pronunciation_katakana_index() + ? pronunciation.destination_pronunciation_katakana_index() + : (forward ? pronunciation.destination_forward_pronunciation_katakana_index() + : pronunciation.destination_backward_pronunciation_katakana_index()); + + uint32_t jeita_index = + pronunciation.destination_pronunciation_jeita_index() + ? pronunciation.destination_pronunciation_jeita_index() + : (forward ? pronunciation.destination_forward_pronunciation_jeita_index() + : pronunciation.destination_backward_pronunciation_jeita_index()); + + std::vector ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens; + GetPronunciationTokens(osmdata, ipa_index, nt_sampa_index, katakana_index, jeita_index, + ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens); + + bool add_ipa = (ipa_tokens.size() && toward_names.size() == ipa_tokens.size()); + bool add_nt_sampa = (nt_sampa_tokens.size() && toward_names.size() == nt_sampa_tokens.size()); + bool add_katakana = (katakana_tokens.size() && toward_names.size() == katakana_tokens.size()); + bool add_jeita = (jeita_tokens.size() && toward_names.size() == jeita_tokens.size()); + + for (size_t i = 0; i < toward_names.size(); ++i) { + + auto toward_name = toward_names[i]; if (tc || (!ramp && !fork)) { - exit_list.emplace_back(Sign::Type::kGuideToward, false, toward_name); + if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + + exit_list.emplace_back(Sign::Type::kGuideToward, false, false, (count != 0), size, count, + toward_name); + + } else + exit_list.emplace_back(Sign::Type::kGuideToward, false, false, false, 0, 0, toward_name); + has_guide = true; + } else if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + + exit_list.emplace_back(Sign::Type::kExitToward, false, false, (count != 0), size, count, + toward_name); + } else - exit_list.emplace_back(Sign::Type::kExitToward, false, toward_name); + exit_list.emplace_back(Sign::Type::kExitToward, false, false, false, 0, 0, toward_name); } } //////////////////////////////////////////////////////////////////////////// - // Process exit_to only if other branch or toward info does not exist + // Process exit_to only if other branch or toward info does not exist No pronunciations. if (!has_branch && !has_toward) { if (node.has_exit_to() && !fork) { std::string tmp; @@ -1378,12 +1726,14 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, // remove the "To" For example: US 11;To I 81;Carlisle;Harrisburg if (boost::starts_with(tmp, "to ")) { - exit_list.emplace_back(Sign::Type::kExitToward, false, exit_to.substr(3)); + exit_list.emplace_back(Sign::Type::kExitToward, false, false, false, 0, 0, + exit_to.substr(3)); continue; } // remove the "Toward" For example: US 11;Toward I 81;Carlisle;Harrisburg if (boost::starts_with(tmp, "toward ")) { - exit_list.emplace_back(Sign::Type::kExitToward, false, exit_to.substr(7)); + exit_list.emplace_back(Sign::Type::kExitToward, false, false, false, 0, 0, + exit_to.substr(7)); continue; } @@ -1394,9 +1744,11 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, if (found != std::string::npos && (tmp.find(" to ", found + 4) == std::string::npos && tmp.find(" toward ") == std::string::npos)) { - exit_list.emplace_back(Sign::Type::kExitBranch, false, exit_to.substr(0, found)); + exit_list.emplace_back(Sign::Type::kExitBranch, false, false, false, 0, 0, + exit_to.substr(0, found)); - exit_list.emplace_back(Sign::Type::kExitToward, false, exit_to.substr(found + 4)); + exit_list.emplace_back(Sign::Type::kExitToward, false, false, false, 0, 0, + exit_to.substr(found + 4)); continue; } @@ -1407,14 +1759,16 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, if (found != std::string::npos && (tmp.find(" toward ", found + 8) == std::string::npos && tmp.find(" to ") == std::string::npos)) { - exit_list.emplace_back(Sign::Type::kExitBranch, false, exit_to.substr(0, found)); + exit_list.emplace_back(Sign::Type::kExitBranch, false, false, false, 0, 0, + exit_to.substr(0, found)); - exit_list.emplace_back(Sign::Type::kExitToward, false, exit_to.substr(found + 8)); + exit_list.emplace_back(Sign::Type::kExitToward, false, false, false, 0, 0, + exit_to.substr(found + 8)); continue; } // default to toward. - exit_list.emplace_back(Sign::Type::kExitToward, false, exit_to); + exit_list.emplace_back(Sign::Type::kExitToward, false, false, false, 0, 0, exit_to); } } } @@ -1426,8 +1780,29 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, if (node.has_name() && !node.named_intersection() && !fork && ramp) { // Get the name from OSMData using the name index std::vector names = GetTagTokens(osmdata.node_names.name(node.name_index())); - for (auto& name : names) { - exit_list.emplace_back(Sign::Type::kExitName, false, name); + + std::vector ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens; + GetPronunciationTokens(osmdata, node.name_pronunciation_ipa_index(), + node.name_pronunciation_nt_sampa_index(), + node.name_pronunciation_katakana_index(), + node.name_pronunciation_jeita_index(), ipa_tokens, nt_sampa_tokens, + katakana_tokens, jeita_tokens, true); + + bool add_ipa = (ipa_tokens.size() && names.size() == ipa_tokens.size()); + bool add_nt_sampa = (nt_sampa_tokens.size() && names.size() == nt_sampa_tokens.size()); + bool add_katakana = (katakana_tokens.size() && names.size() == katakana_tokens.size()); + bool add_jeita = (jeita_tokens.size() && names.size() == jeita_tokens.size()); + + for (size_t i = 0; i < names.size(); ++i) { + if (add_ipa || add_nt_sampa || add_katakana || add_jeita) { + uint32_t count = 0; + const size_t size = pronunciations.size(); + BuildPronunciations(ipa_tokens, nt_sampa_tokens, katakana_tokens, jeita_tokens, i, + pronunciations, add_ipa, add_nt_sampa, add_katakana, add_jeita, count); + exit_list.emplace_back(Sign::Type::kExitName, false, false, (count != 0), size, count, + names[i]); + } else + exit_list.emplace_back(Sign::Type::kExitName, false, false, false, 0, 0, names[i]); } } @@ -1440,7 +1815,7 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, GetTagTokens(osmdata.name_offset_map.name(way.fwd_jct_base_index()), '|'); // route number set to true for kGuidanceViewJct type means base type for (auto& name : names) { - exit_list.emplace_back(Sign::Type::kGuidanceViewJunction, true, name); + exit_list.emplace_back(Sign::Type::kGuidanceViewJunction, true, false, false, 0, 0, name); has_guidance_view = true; } } else if (!forward && way.bwd_jct_base_index() > 0) { @@ -1448,7 +1823,7 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, GetTagTokens(osmdata.name_offset_map.name(way.bwd_jct_base_index()), '|'); // route number set to true for kGuidanceViewJct type means base type for (auto& name : names) { - exit_list.emplace_back(Sign::Type::kGuidanceViewJunction, true, name); + exit_list.emplace_back(Sign::Type::kGuidanceViewJunction, true, false, false, 0, 0, name); has_guidance_view = true; } } @@ -1458,7 +1833,7 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, GetTagTokens(osmdata.name_offset_map.name(way.fwd_jct_overlay_index()), '|'); // route number set to false for kGuidanceViewJct type means overlay type for (auto& name : names) { - exit_list.emplace_back(Sign::Type::kGuidanceViewJunction, false, name); + exit_list.emplace_back(Sign::Type::kGuidanceViewJunction, false, false, false, 0, 0, name); has_guidance_view = true; } } else if (!forward && way.bwd_jct_overlay_index() > 0) { @@ -1466,7 +1841,7 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, GetTagTokens(osmdata.name_offset_map.name(way.bwd_jct_overlay_index()), '|'); // route number set to false for kGuidanceViewJct type means overlay type for (auto& name : names) { - exit_list.emplace_back(Sign::Type::kGuidanceViewJunction, false, name); + exit_list.emplace_back(Sign::Type::kGuidanceViewJunction, false, false, false, 0, 0, name); has_guidance_view = true; } } @@ -1476,7 +1851,7 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, GetTagTokens(osmdata.name_offset_map.name(way.fwd_signboard_base_index()), '|'); // route number set to true for kGuidanceViewSignboard type means base type for (auto& name : names) { - exit_list.emplace_back(Sign::Type::kGuidanceViewSignboard, true, name); + exit_list.emplace_back(Sign::Type::kGuidanceViewSignboard, true, false, false, 0, 0, name); has_guidance_view_signboard = true; } } else if (!forward && way.bwd_signboard_base_index() > 0) { @@ -1484,11 +1859,14 @@ bool GraphBuilder::CreateSignInfoList(const OSMNode& node, GetTagTokens(osmdata.name_offset_map.name(way.bwd_signboard_base_index()), '|'); // route number set to true for kGuidanceViewSignboard type means base type for (auto& name : names) { - exit_list.emplace_back(Sign::Type::kGuidanceViewSignboard, true, name); + exit_list.emplace_back(Sign::Type::kGuidanceViewSignboard, true, false, false, 0, 0, name); has_guidance_view_signboard = true; } } + // we have to sort because we need the key/indexes for phonemes + std::stable_sort(exit_list.begin(), exit_list.end()); + return (has_guide || has_guidance_view || has_guidance_view_signboard); } diff --git a/src/mjolnir/graphenhancer.cc b/src/mjolnir/graphenhancer.cc index bdde91bb46..bb27ebf070 100644 --- a/src/mjolnir/graphenhancer.cc +++ b/src/mjolnir/graphenhancer.cc @@ -1620,7 +1620,8 @@ void enhance(const boost::property_tree::ptree& pt, } // Update the named flag - auto names = tilebuilder->edgeinfo(&directededge).GetNamesAndTypes(true); + std::vector types; + auto names = tilebuilder->edgeinfo(&directededge).GetNamesAndTypes(types, false); directededge.set_named(names.size() > 0); // Speed assignment @@ -1631,8 +1632,9 @@ void enhance(const boost::property_tree::ptree& pt, uint32_t ntrans = nodeinfo.local_edge_count(); for (uint32_t k = 0; k < ntrans; k++) { DirectedEdge& fromedge = tilebuilder->directededge(nodeinfo.edge_index() + k); + std::vector types; if (ConsistentNames(country_code, names, - tilebuilder->edgeinfo(&fromedge).GetNamesAndTypes())) { + tilebuilder->edgeinfo(&fromedge).GetNamesAndTypes(types, false))) { directededge.set_name_consistency(k, true); } } diff --git a/src/mjolnir/graphfilter.cc b/src/mjolnir/graphfilter.cc index 272004b6da..98b4659948 100644 --- a/src/mjolnir/graphfilter.cc +++ b/src/mjolnir/graphfilter.cc @@ -101,7 +101,7 @@ void FilterTiles(GraphReader& reader, // Get signs from the base directed edge if (directededge->sign()) { - std::vector signs = tile->GetSigns(edgeid.id()); + std::vector signs = tile->ProcessSigns(edgeid.id()); if (signs.size() == 0) { LOG_ERROR("Base edge should have signs, but none found"); } @@ -149,7 +149,8 @@ void FilterTiles(GraphReader& reader, tilebuilder.AddEdgeInfo(w, nodeid, directededge->endnode(), edgeinfo.wayid(), edgeinfo.mean_elevation(), edgeinfo.bike_network(), edgeinfo.speed_limit(), encoded_shape, edgeinfo.GetNames(), - edgeinfo.GetTaggedValues(), edgeinfo.GetTypes(), added); + edgeinfo.GetTaggedValues(), edgeinfo.GetTaggedValues(true), + edgeinfo.GetTypes(), added); newedge.set_edgeinfo_offset(edge_info_offset); wayid.push_back(edgeinfo.wayid()); endnode.push_back(directededge->endnode()); @@ -173,7 +174,7 @@ void FilterTiles(GraphReader& reader, // Get named signs from the base node if (nodeinfo->named_intersection()) { - std::vector signs = tile->GetSigns(nodeid.id(), true); + std::vector signs = tile->ProcessSigns(nodeid.id(), true); if (signs.size() == 0) { LOG_ERROR("Base node should have signs, but none found"); } diff --git a/src/mjolnir/graphtilebuilder.cc b/src/mjolnir/graphtilebuilder.cc index 91fb3a78cc..35fe18251d 100644 --- a/src/mjolnir/graphtilebuilder.cc +++ b/src/mjolnir/graphtilebuilder.cc @@ -125,7 +125,7 @@ GraphTileBuilder::GraphTileBuilder(const std::string& tile_dir, for (uint32_t i = 0; i < header_->signcount(); i++) { name_info.insert({signs_[i].text_offset()}); signs_builder_.emplace_back(signs_[i].index(), signs_[i].type(), signs_[i].route_num_type(), - signs_[i].text_offset()); + signs_[i].tagged(), signs_[i].text_offset()); } // Create turn lane builders @@ -190,21 +190,18 @@ GraphTileBuilder::GraphTileBuilder(const std::string& tile_dir, } // Text list - for (auto ni : name_info) { - // Verify offsets as we add text. Identify any strings in the text list - // that are not referenced by any objects. - while (ni.name_offset_ != text_list_offset_) { - std::string unused_string(textlist_ + text_list_offset_); - textlistbuilder_.push_back(unused_string); - text_offset_map_.emplace(unused_string, text_list_offset_); - text_list_offset_ += unused_string.length() + 1; - LOG_WARN("Unused text string: " + unused_string); - } - std::string str(textlist_ + ni.name_offset_); - textlistbuilder_.push_back(str); - uint32_t offset = ni.name_offset_; - text_offset_map_.emplace(str, offset); - text_list_offset_ += str.length() + 1; + for (auto ni = name_info.begin(); ni != name_info.end(); ++ni) { + // compute the width of the entry by looking at the next offset or the end if its the last one + auto next = std::next(ni); + auto width = next != name_info.end() ? (next->name_offset_ - ni->name_offset_) + : (textlist_size_ - ni->name_offset_); + + // Keep the bytes for this entry....remove null terminating char as it is added in StoreTileData + textlistbuilder_.emplace_back(textlist_ + ni->name_offset_, width - 1); + // Remember what offset they had + text_offset_map_.emplace(textlistbuilder_.back(), ni->name_offset_); + // Keep track of how large it is for storing it back to disk later + text_list_offset_ += textlistbuilder_.back().length() + 1; } // Lane connectivity @@ -494,14 +491,51 @@ void GraphTileBuilder::AddAccessRestrictions(const std::vector& signs, + const std::vector& pronunciations) { + // Iterate through the list of sign info (with sign text) and add sign + // text to the text list. Skip signs with no text. + for (size_t i = 0; i < signs.size(); ++i) { + auto sign = signs[i]; + if (!(sign.text().empty())) { + uint32_t offset = AddName(sign.text()); + signs_builder_.emplace_back(idx, sign.type(), sign.is_route_num(), sign.is_tagged(), offset); + if (sign.has_phoneme()) { + bool phoneme_on_node = sign.type() == Sign::Type::kJunctionName; + uint32_t count = (sign.phoneme_start_index() + sign.phoneme_count()) - 1; + for (uint32_t x = sign.phoneme_start_index(); x <= count; x++) { + auto* p = const_cast(pronunciations[x].c_str()); + size_t pos = 0; + std::string updated_pronunciation; + + while (pos < strlen(p)) { + linguistic_text_header_t header = *reinterpret_cast(p + pos); + pos += 3; + header.name_index_ = i; + updated_pronunciation.append(std::string(reinterpret_cast(&header), 3) + + (p + pos)); + pos += header.length_; + } + + uint32_t offset = AddName(updated_pronunciation); + signs_builder_.emplace_back(idx, Sign::Type::kPronunciation, phoneme_on_node, true, offset); + } + } + } + } +} + // Add signs void GraphTileBuilder::AddSigns(const uint32_t idx, const std::vector& signs) { // Iterate through the list of sign info (with sign text) and add sign // text to the text list. Skip signs with no text. for (const auto& sign : signs) { if (!(sign.text().empty())) { - uint32_t offset = AddName(sign.text()); - signs_builder_.emplace_back(idx, sign.type(), sign.is_route_num(), offset); + uint32_t offset = 0; + offset = AddName(sign.text()); + signs_builder_.emplace_back(idx, sign.type(), sign.is_route_num(), sign.is_tagged(), offset); } } } @@ -547,6 +581,7 @@ uint32_t GraphTileBuilder::AddEdgeInfo(const uint32_t edgeindex, const shape_container_t& lls, const std::vector& names, const std::vector& tagged_values, + const std::vector& pronunciations, const uint16_t types, bool& added, bool diff_names) { @@ -580,6 +615,7 @@ uint32_t GraphTileBuilder::AddEdgeInfo(const uint32_t edgeindex, // Add name and add its offset to edge info's list. NameInfo ni{AddName(name)}; ni.is_route_num_ = 0; + ni.tagged_ = 0; if ((types & (1ULL << location))) { ni.is_route_num_ = 1; // set the ref bit. } @@ -605,6 +641,29 @@ uint32_t GraphTileBuilder::AddEdgeInfo(const uint32_t edgeindex, ++name_count; } } + + if (pronunciations.size()) { + if (name_count != kMaxNamesPerEdge) { + std::stringstream ss; + for (const auto& pronunciation : pronunciations) { + ss << pronunciation; + } + + auto encode_tag = [](valhalla::baldr::TaggedValue tag) { + return std::string(1, static_cast(tag)); + }; + + // Add pronunciations and add its offset to edge info's list. + NameInfo ni{AddName(encode_tag(valhalla::baldr::TaggedValue::kPronunciation) + ss.str())}; + + ni.is_route_num_ = 0; + ni.tagged_ = 1; + name_info_list.emplace_back(ni); + ++name_count; + } else + LOG_WARN("Too many names for edgeindex: " + std::to_string(edgeindex)); + } + edgeinfo.set_name_info_list(name_info_list); // Add to the map @@ -635,6 +694,7 @@ template uint32_t GraphTileBuilder::AddEdgeInfo>(const uint const std::vector&, const std::vector&, const std::vector&, + const std::vector&, const uint16_t, bool&, bool); @@ -648,6 +708,7 @@ template uint32_t GraphTileBuilder::AddEdgeInfo>(const uint32 const std::list&, const std::vector&, const std::vector&, + const std::vector&, const uint16_t, bool&, bool); @@ -663,6 +724,7 @@ uint32_t GraphTileBuilder::AddEdgeInfo(const uint32_t edgeindex, const std::string& llstr, const std::vector& names, const std::vector& tagged_values, + const std::vector& pronunciations, const uint16_t types, bool& added, bool diff_names) { @@ -696,6 +758,7 @@ uint32_t GraphTileBuilder::AddEdgeInfo(const uint32_t edgeindex, // Add name and add its offset to edge info's list. NameInfo ni{AddName(name)}; ni.is_route_num_ = 0; + ni.tagged_ = 0; if ((types & (1ULL << location))) { ni.is_route_num_ = 1; // set the ref bit. } @@ -722,6 +785,28 @@ uint32_t GraphTileBuilder::AddEdgeInfo(const uint32_t edgeindex, } } + if (pronunciations.size()) { + if (name_count != kMaxNamesPerEdge) { + std::stringstream ss; + for (const auto& pronunciation : pronunciations) { + ss << pronunciation; + } + + auto encode_tag = [](valhalla::baldr::TaggedValue tag) { + return std::string(1, static_cast(tag)); + }; + + // Add pronunciations and add its offset to edge info's list. + NameInfo ni{AddName(encode_tag(valhalla::baldr::TaggedValue::kPronunciation) + ss.str())}; + + ni.is_route_num_ = 0; + ni.tagged_ = 1; + name_info_list.emplace_back(ni); + ++name_count; + } else + LOG_WARN("Too many names for edgeindex: " + std::to_string(edgeindex)); + } + edgeinfo.set_name_info_list(name_info_list); // Add to the map diff --git a/src/mjolnir/graphvalidator.cc b/src/mjolnir/graphvalidator.cc index c621885147..9ce0710420 100644 --- a/src/mjolnir/graphvalidator.cc +++ b/src/mjolnir/graphvalidator.cc @@ -311,7 +311,7 @@ void validate( // Validate signs if (ni->named_intersection()) { - if (tile->GetSigns(i, true).size() == 0) { + if (tile->ProcessSigns(i, true).size() == 0) { LOG_ERROR("Node marked as having signs but none found"); } } @@ -326,7 +326,7 @@ void validate( // Validate signs if (de->sign()) { - if (tile->GetSigns(idx).size() == 0) { + if (tile->ProcessSigns(idx).size() == 0) { LOG_ERROR("Directed edge marked as having signs but none found"); } } diff --git a/src/mjolnir/hierarchybuilder.cc b/src/mjolnir/hierarchybuilder.cc index 82849764d2..632b7a3416 100644 --- a/src/mjolnir/hierarchybuilder.cc +++ b/src/mjolnir/hierarchybuilder.cc @@ -269,7 +269,7 @@ void FormTilesInNewLevel(GraphReader& reader, // Get signs from the base directed edge if (directededge->sign()) { - std::vector signs = tile->GetSigns(base_edge_id.id()); + std::vector signs = tile->ProcessSigns(base_edge_id.id()); if (signs.size() == 0) { LOG_ERROR("Base edge should have signs, but none found"); } @@ -322,7 +322,9 @@ void FormTilesInNewLevel(GraphReader& reader, tilebuilder->AddEdgeInfo(w, nodea, nodeb, edgeinfo.wayid(), edgeinfo.mean_elevation(), edgeinfo.bike_network(), edgeinfo.speed_limit(), encoded_shape, edgeinfo.GetNames(), edgeinfo.GetTaggedValues(), - edgeinfo.GetTypes(), added, diff_names); + edgeinfo.GetTaggedValues(true), edgeinfo.GetTypes(), added, + diff_names); + newedge.set_edgeinfo_offset(edge_info_offset); // Add directed edge @@ -357,7 +359,7 @@ void FormTilesInNewLevel(GraphReader& reader, // Get named signs from the base node if (baseni.named_intersection()) { - std::vector signs = tile->GetSigns(base_node.id(), true); + std::vector signs = tile->ProcessSigns(base_node.id(), true); if (signs.size() == 0) { LOG_ERROR("Base node should have signs, but none found"); } diff --git a/src/mjolnir/osmway.cc b/src/mjolnir/osmway.cc index 8399682d4a..3975385e9f 100644 --- a/src/mjolnir/osmway.cc +++ b/src/mjolnir/osmway.cc @@ -1,7 +1,9 @@ #include "mjolnir/osmway.h" +#include "baldr/edgeinfo.h" #include "mjolnir/util.h" #include "midgard/logging.h" +#include #include using namespace valhalla::baldr; @@ -98,19 +100,61 @@ void OSMWay::set_layer(int8_t layer) { layer_ = layer; } +void OSMWay::AddPronunciations(std::vector& pronunciations, + const UniqueNames& name_offset_map, + const uint32_t pronunciation_index, + const size_t name_tokens_size, + const size_t key, + const baldr::PronunciationAlphabet verbal_type) const { + std::vector pronunciation_tokens; + if (pronunciation_index != 0) + pronunciation_tokens = GetTagTokens(name_offset_map.name(pronunciation_index)); + else + return; + linguistic_text_header_t header{static_cast(baldr::Language::kNone), 0, + static_cast(verbal_type), static_cast(key)}; + std::string pronunciation; + // TODO: We need to address the fact that a name/ref value could of been entered incorrectly + // For example, name="XYZ Street;;ABC Street" + // name:pronunciation="pronunciation1;pronunciation2;pronunciation3" So we check for + // name_tokens_size == pronunciation_tokens.size() and we will not toss the second record in the + // vector, but we should as it is blank. We actually address with blank name in edgeinfo via + // tossing the name if GraphTileBuilder::AddName returns 0. Thought is we could address this now in + // GetTagTokens and if we have a mismatch then don't add the pronunciations. To date no data has + // been found as described, but it could happen. Address this issue with the Language updates. + + if (pronunciation_tokens.size() && name_tokens_size == pronunciation_tokens.size()) { + for (const auto& t : pronunciation_tokens) { + if (!t.size()) { // pronunciation is blank. skip and increment the index + ++header.name_index_; + continue; + } + header.length_ = t.size(); + pronunciation.append(std::string(reinterpret_cast(&header), 3) + t); + ++header.name_index_; + } + } + // keep the whole slew of them + pronunciations.emplace_back(std::move(pronunciation)); +} + // Get the names for the edge info based on the road class. -std::vector -OSMWay::GetNames(const std::string& ref, const UniqueNames& name_offset_map, uint16_t& types) const { +void OSMWay::GetNames(const std::string& ref, + const UniqueNames& name_offset_map, + const OSMPronunciation& pronunciation, + uint16_t& types, + std::vector& names, + std::vector& pronunciations) const { uint16_t location = 0; types = 0; - std::vector names; // Process motorway and trunk refs if ((ref_index_ != 0 || !ref.empty()) && ((static_cast(road_class_) == RoadClass::kMotorway) || (static_cast(road_class_) == RoadClass::kTrunk))) { std::vector tokens; + std::vector pronunciation_tokens; if (!ref.empty()) { tokens = GetTagTokens(ref); // use updated refs from relations. @@ -124,20 +168,49 @@ OSMWay::GetNames(const std::string& ref, const UniqueNames& name_offset_map, uin } names.insert(names.end(), tokens.begin(), tokens.end()); + + size_t key = names.size() - tokens.size(); + AddPronunciations(pronunciations, name_offset_map, pronunciation.ref_pronunciation_ipa_index(), + tokens.size(), key, PronunciationAlphabet::kIpa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.ref_pronunciation_nt_sampa_index(), tokens.size(), key, + PronunciationAlphabet::kNtSampa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.ref_pronunciation_katakana_index(), tokens.size(), key, + PronunciationAlphabet::kXKatakana); + AddPronunciations(pronunciations, name_offset_map, pronunciation.ref_pronunciation_jeita_index(), + tokens.size(), key, PronunciationAlphabet::kXJeita); } // TODO int_ref // Process name if (name_index_ != 0) { - names.emplace_back(name_offset_map.name(name_index_)); - location++; + + std::vector tokens; + tokens = GetTagTokens(name_offset_map.name(name_index_)); + location += tokens.size(); + + names.insert(names.end(), tokens.begin(), tokens.end()); + + size_t key = names.size() - tokens.size(); + AddPronunciations(pronunciations, name_offset_map, pronunciation.name_pronunciation_ipa_index(), + tokens.size(), key, PronunciationAlphabet::kIpa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.name_pronunciation_nt_sampa_index(), tokens.size(), key, + PronunciationAlphabet::kNtSampa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.name_pronunciation_katakana_index(), tokens.size(), key, + PronunciationAlphabet::kXKatakana); + AddPronunciations(pronunciations, name_offset_map, pronunciation.name_pronunciation_jeita_index(), + tokens.size(), key, PronunciationAlphabet::kXJeita); } // Process non limited access refs if (ref_index_ != 0 && (static_cast(road_class_) != RoadClass::kMotorway) && (static_cast(road_class_) != RoadClass::kTrunk)) { std::vector tokens; + if (!ref.empty()) { tokens = GetTagTokens(ref); // use updated refs from relations. } else { @@ -150,33 +223,102 @@ OSMWay::GetNames(const std::string& ref, const UniqueNames& name_offset_map, uin } names.insert(names.end(), tokens.begin(), tokens.end()); + + size_t key = names.size() - tokens.size(); + AddPronunciations(pronunciations, name_offset_map, pronunciation.ref_pronunciation_ipa_index(), + tokens.size(), key, PronunciationAlphabet::kIpa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.ref_pronunciation_nt_sampa_index(), tokens.size(), key, + PronunciationAlphabet::kNtSampa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.ref_pronunciation_katakana_index(), tokens.size(), key, + PronunciationAlphabet::kXKatakana); + AddPronunciations(pronunciations, name_offset_map, pronunciation.ref_pronunciation_jeita_index(), + tokens.size(), key, PronunciationAlphabet::kXJeita); } // Process alt_name if (alt_name_index_ != 0 && alt_name_index_ != name_index_) { - names.emplace_back(name_offset_map.name(alt_name_index_)); - location++; + + std::vector tokens; + tokens = GetTagTokens(name_offset_map.name(alt_name_index_)); + location += tokens.size(); + + names.insert(names.end(), tokens.begin(), tokens.end()); + + size_t key = names.size() - tokens.size(); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.alt_name_pronunciation_ipa_index(), tokens.size(), key, + PronunciationAlphabet::kIpa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.alt_name_pronunciation_nt_sampa_index(), tokens.size(), key, + PronunciationAlphabet::kNtSampa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.alt_name_pronunciation_katakana_index(), tokens.size(), key, + PronunciationAlphabet::kXKatakana); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.alt_name_pronunciation_jeita_index(), tokens.size(), key, + PronunciationAlphabet::kXJeita); } // Process official_name if (official_name_index_ != 0 && official_name_index_ != name_index_ && official_name_index_ != alt_name_index_) { - names.emplace_back(name_offset_map.name(official_name_index_)); - location++; + + std::vector tokens; + tokens = GetTagTokens(name_offset_map.name(official_name_index_)); + location += tokens.size(); + + names.insert(names.end(), tokens.begin(), tokens.end()); + + size_t key = names.size() - tokens.size(); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.official_name_pronunciation_ipa_index(), tokens.size(), key, + PronunciationAlphabet::kIpa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.official_name_pronunciation_nt_sampa_index(), tokens.size(), key, + PronunciationAlphabet::kNtSampa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.official_name_pronunciation_katakana_index(), tokens.size(), key, + PronunciationAlphabet::kXKatakana); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.official_name_pronunciation_jeita_index(), tokens.size(), key, + PronunciationAlphabet::kXJeita); } // Process name_en_ // TODO: process country specific names if (name_en_index_ != 0 && name_en_index_ != name_index_ && name_en_index_ != alt_name_index_ && name_en_index_ != official_name_index_) { - names.emplace_back(name_offset_map.name(name_en_index_)); - location++; + + std::vector tokens; + tokens = GetTagTokens(name_offset_map.name(name_en_index_)); + location += tokens.size(); + + names.insert(names.end(), tokens.begin(), tokens.end()); + + size_t key = names.size() - tokens.size(); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.name_en_pronunciation_ipa_index(), tokens.size(), key, + PronunciationAlphabet::kIpa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.name_en_pronunciation_nt_sampa_index(), tokens.size(), key, + PronunciationAlphabet::kNtSampa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.name_en_pronunciation_katakana_index(), tokens.size(), key, + PronunciationAlphabet::kXKatakana); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.name_en_pronunciation_jeita_index(), tokens.size(), key, + PronunciationAlphabet::kXJeita); } - return names; } -// Get the tagged values for an edge -std::vector OSMWay::GetTaggedValues(const UniqueNames& name_offset_map) const { +// Get the tagged names for an edge +void OSMWay::GetTaggedValues(const UniqueNames& name_offset_map, + const OSMPronunciation& pronunciation, + const size_t& names_size, + std::vector& names, + std::vector& pronunciations) const { - std::vector names; + std::vector tokens; auto encode_tag = [](TaggedValue tag) { return std::string(1, static_cast(tag)); @@ -187,13 +329,25 @@ std::vector OSMWay::GetTaggedValues(const UniqueNames& name_offset_ for (const auto& t : tokens) { names.emplace_back(encode_tag(TaggedValue::kTunnel) + t); } + + size_t key = (names_size + names.size()) - tokens.size(); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.tunnel_name_pronunciation_ipa_index(), tokens.size(), key, + PronunciationAlphabet::kIpa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.tunnel_name_pronunciation_nt_sampa_index(), tokens.size(), key, + PronunciationAlphabet::kNtSampa); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.tunnel_name_pronunciation_katakana_index(), tokens.size(), key, + PronunciationAlphabet::kXKatakana); + AddPronunciations(pronunciations, name_offset_map, + pronunciation.tunnel_name_pronunciation_jeita_index(), tokens.size(), key, + PronunciationAlphabet::kXJeita); } if (layer_ != 0) { names.emplace_back(encode_tag(TaggedValue::kLayer) + static_cast(layer_)); } - - return names; } } // namespace mjolnir diff --git a/src/mjolnir/pbfgraphparser.cc b/src/mjolnir/pbfgraphparser.cc index 5911510bd3..ca91197fc3 100644 --- a/src/mjolnir/pbfgraphparser.cc +++ b/src/mjolnir/pbfgraphparser.cc @@ -5,6 +5,7 @@ #include "graph_lua_proc.h" #include "mjolnir/luatagtransform.h" #include "mjolnir/osmaccess.h" +#include "mjolnir/osmpronunciation.h" #include #include @@ -483,6 +484,146 @@ struct graph_callback : public OSMPBF::Callback { if (!tag_.second.empty()) way_.set_tunnel_name_index(osmdata_.name_offset_map.index(tag_.second)); }; + tag_handlers_["name:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_name_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["name:en:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_name_en_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["alt_name:pronunciation"] = [this]() { + if (!tag_.second.empty() && allow_alt_name_) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_alt_name_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["official_name:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_official_name_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["tunnel:name:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_tunnel_name_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["name:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_name_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["name:en:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_name_en_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["alt_name:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty() && allow_alt_name_) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_alt_name_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["official_name:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_official_name_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["tunnel:name:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_tunnel_name_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["name:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_name_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["name:en:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_name_en_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["alt_name:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty() && allow_alt_name_) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_alt_name_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["official_name:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_official_name_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["tunnel:name:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_tunnel_name_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["name:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_name_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["name:en:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_name_en_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["alt_name:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty() && allow_alt_name_) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_alt_name_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["official_name:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_official_name_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["tunnel:name:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_tunnel_name_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; tag_handlers_["max_speed"] = [this]() { try { if (tag_.second == "unlimited") { @@ -610,6 +751,7 @@ struct graph_callback : public OSMPBF::Callback { LOG_INFO("out_of_range thrown for way id: " + std::to_string(osmid_)); } }; + tag_handlers_["ref"] = [this]() { if (!tag_.second.empty()) { if (!use_direction_on_ways_) @@ -626,6 +768,86 @@ struct graph_callback : public OSMPBF::Callback { int_ref_ = tag_.second; } }; + tag_handlers_["ref:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + if (!use_direction_on_ways_) + osm_pronunciation_.set_ref_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + else + ref_pronunciation_ = tag_.second; + } + }; + tag_handlers_["int_ref:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + if (!use_direction_on_ways_) + osm_pronunciation_.set_int_ref_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + else + int_ref_pronunciation_ = tag_.second; + } + }; + tag_handlers_["ref:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + if (!use_direction_on_ways_) + osm_pronunciation_.set_ref_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + else + ref_pronunciation_nt_sampa_ = tag_.second; + } + }; + tag_handlers_["int_ref:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + if (!use_direction_on_ways_) + osm_pronunciation_.set_int_ref_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + else + int_ref_pronunciation_nt_sampa_ = tag_.second; + } + }; + tag_handlers_["ref:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + if (!use_direction_on_ways_) + osm_pronunciation_.set_ref_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + else + ref_pronunciation_katakana_ = tag_.second; + } + }; + tag_handlers_["int_ref:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + if (!use_direction_on_ways_) + osm_pronunciation_.set_int_ref_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + else + int_ref_pronunciation_katakana_ = tag_.second; + } + }; + tag_handlers_["ref:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + if (!use_direction_on_ways_) + osm_pronunciation_.set_ref_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + else + ref_pronunciation_jeita_ = tag_.second; + } + }; + tag_handlers_["int_ref:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + if (!use_direction_on_ways_) + osm_pronunciation_.set_int_ref_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + else + int_ref_pronunciation_jeita_ = tag_.second; + } + }; tag_handlers_["direction"] = [this]() { if (!tag_.second.empty() && use_direction_on_ways_) direction_ = tag_.second; @@ -634,6 +856,38 @@ struct graph_callback : public OSMPBF::Callback { if (!tag_.second.empty() && use_direction_on_ways_) int_direction_ = tag_.second; }; + tag_handlers_["direction:pronunciation"] = [this]() { + if (!tag_.second.empty() && use_direction_on_ways_) + direction_pronunciation_ = tag_.second; + }; + tag_handlers_["int_direction:pronunciation"] = [this]() { + if (!tag_.second.empty() && use_direction_on_ways_) + int_direction_pronunciation_ = tag_.second; + }; + tag_handlers_["direction:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty() && use_direction_on_ways_) + direction_pronunciation_nt_sampa_ = tag_.second; + }; + tag_handlers_["int_direction:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty() && use_direction_on_ways_) + int_direction_pronunciation_nt_sampa_ = tag_.second; + }; + tag_handlers_["direction:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty() && use_direction_on_ways_) + direction_pronunciation_katakana_ = tag_.second; + }; + tag_handlers_["int_direction:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty() && use_direction_on_ways_) + int_direction_pronunciation_katakana_ = tag_.second; + }; + tag_handlers_["direction:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty() && use_direction_on_ways_) + direction_pronunciation_jeita_ = tag_.second; + }; + tag_handlers_["int_direction:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty() && use_direction_on_ways_) + int_direction_pronunciation_jeita_ = tag_.second; + }; tag_handlers_["sac_scale"] = [this]() { std::string value = tag_.second; boost::algorithm::to_lower(value); @@ -864,6 +1118,230 @@ struct graph_callback : public OSMPBF::Callback { way_.set_exit(true); } }; + tag_handlers_["destination:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:forward:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_forward_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:backward:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_backward_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:ref:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_ref_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:ref:to:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_ref_to_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:street:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_street_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:street:to:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_street_to_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["junction:ref:pronunciation"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_junction_ref_pronunciation_ipa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:forward:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_forward_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:backward:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_backward_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:ref:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_ref_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:ref:to:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_ref_to_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:street:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_street_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:street:to:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_street_to_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["junction:ref:pronunciation:nt-sampa"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_junction_ref_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:forward:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_forward_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:backward:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_backward_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:ref:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_ref_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:ref:to:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_ref_to_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:street:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_street_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:street:to:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_street_to_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["junction:ref:pronunciation:x-katakana"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_junction_ref_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:forward:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_forward_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:backward:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_backward_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:ref:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_ref_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:ref:to:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_ref_to_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:street:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_street_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["destination:street:to:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_destination_street_to_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; + tag_handlers_["junction:ref:pronunciation:x-jeita"] = [this]() { + if (!tag_.second.empty()) { + has_pronunciation_tags_ = true; + osm_pronunciation_.set_junction_ref_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tag_.second)); + } + }; tag_handlers_["turn:lanes"] = [this]() { // Turn lanes in the forward direction way_.set_fwd_turn_lanes_index(osmdata_.name_offset_map.index(tag_.second)); @@ -1053,6 +1531,22 @@ struct graph_callback : public OSMPBF::Callback { n.set_name_index(osmdata_.node_names.index(tag.second)); ++osmdata_.node_name_count; named_junction = maybe_named_junction; + } else if (tag.first == "name:pronunciation") { + n.set_name_pronunciation_ipa_index(osmdata_.node_names.index(tag.second)); + } else if (tag.first == "name:pronunciation:nt-sampa") { + n.set_name_pronunciation_nt_sampa_index(osmdata_.node_names.index(tag.second)); + } else if (tag.first == "name:pronunciation:x-katakana") { + n.set_name_pronunciation_katakana_index(osmdata_.node_names.index(tag.second)); + } else if (tag.first == "name:pronunciation:x-jeita") { + n.set_name_pronunciation_jeita_index(osmdata_.node_names.index(tag.second)); + } else if (tag.first == "ref:pronunciation") { + n.set_ref_pronunciation_ipa_index(osmdata_.node_names.index(tag.second)); + } else if (tag.first == "ref:pronunciation:nt-sampa") { + n.set_ref_pronunciation_nt_sampa_index(osmdata_.node_names.index(tag.second)); + } else if (tag.first == "ref:pronunciation:x-katakana") { + n.set_ref_pronunciation_katakana_index(osmdata_.node_names.index(tag.second)); + } else if (tag.first == "ref:pronunciation:x-jeita") { + n.set_ref_pronunciation_jeita_index(osmdata_.node_names.index(tag.second)); } else if (tag.first == "gate" && tag.second == "true") { osmdata_.edge_count += !intersection; intersection = true; @@ -1229,8 +1723,12 @@ struct graph_callback : public OSMPBF::Callback { way_.set_node_count(nodes.size()); osm_access_ = OSMAccess{osmid_}; - has_user_tags_ = false; + osm_pronunciation_ = OSMPronunciation{osmid_}; + + has_user_tags_ = false, has_pronunciation_tags_ = false; ref_ = int_ref_ = direction_ = int_direction_ = {}; + ref_pronunciation_ = int_ref_pronunciation_ = direction_pronunciation_ = + int_direction_pronunciation_ = {}; const auto& surface_exists = results.find("surface"); has_surface_tag_ = (surface_exists != results.end()); @@ -1341,52 +1839,37 @@ struct graph_callback : public OSMPBF::Callback { way_.set_use(Use::kRestArea); } } - if (use_direction_on_ways_ && !ref_.empty()) { - if (direction_.empty()) { - way_.set_ref_index(osmdata_.name_offset_map.index(ref_)); - } else { - std::vector refs = GetTagTokens(ref_); - std::vector directions = GetTagTokens(direction_); - - std::string tmp_ref; - if (refs.size() == directions.size()) { - for (uint32_t i = 0; i < refs.size(); i++) { - if (!tmp_ref.empty()) { - tmp_ref += ";"; - } - if (!directions.at(i).empty()) - tmp_ref += refs.at(i) + " " + directions.at(i); - else - tmp_ref += refs.at(i); - } - way_.set_ref_index(osmdata_.name_offset_map.index(tmp_ref)); - } else - way_.set_ref_index(osmdata_.name_offset_map.index(ref_)); - } - } - if (use_direction_on_ways_ && !int_ref_.empty()) { - if (int_direction_.empty()) { - way_.set_int_ref_index(osmdata_.name_offset_map.index(int_ref_)); - } else { - std::vector int_refs = GetTagTokens(int_ref_); - std::vector int_directions = GetTagTokens(int_direction_); - - std::string tmp_ref; - if (int_refs.size() == int_directions.size()) { - for (uint32_t i = 0; i < int_refs.size(); i++) { - if (!tmp_ref.empty()) { - tmp_ref += ";"; - } - if (!int_directions.at(i).empty()) - tmp_ref += int_refs.at(i) + " " + int_directions.at(i); - else - tmp_ref += int_refs.at(i); - } - way_.set_int_ref_index(osmdata_.name_offset_map.index(tmp_ref)); - } else - way_.set_int_ref_index(osmdata_.name_offset_map.index(int_ref_)); - } + if (use_direction_on_ways_) { + if (!ref_.empty()) + ProcessDirection(false); + + if (!int_ref_.empty()) + ProcessDirection(true); + + if (!ref_pronunciation_.empty()) + ProcessDirectionPronunciation(PronunciationAlphabet::kIpa, false); + + if (!int_ref_pronunciation_.empty()) + ProcessDirectionPronunciation(PronunciationAlphabet::kIpa, true); + + if (!ref_pronunciation_katakana_.empty()) + ProcessDirectionPronunciation(PronunciationAlphabet::kXKatakana, false); + + if (!int_ref_pronunciation_katakana_.empty()) + ProcessDirectionPronunciation(PronunciationAlphabet::kXKatakana, true); + + if (!ref_pronunciation_nt_sampa_.empty()) + ProcessDirectionPronunciation(PronunciationAlphabet::kNtSampa, false); + + if (!int_ref_pronunciation_nt_sampa_.empty()) + ProcessDirectionPronunciation(PronunciationAlphabet::kNtSampa, true); + + if (!ref_pronunciation_jeita_.empty()) + ProcessDirectionPronunciation(PronunciationAlphabet::kXJeita, false); + + if (!int_ref_pronunciation_jeita_.empty()) + ProcessDirectionPronunciation(PronunciationAlphabet::kXJeita, true); } // add int_refs to the end of the refs for now. makes sure that we don't add dups. @@ -1419,6 +1902,12 @@ struct graph_callback : public OSMPBF::Callback { way_.set_int_ref_index(0); } + // add int_ref pronunciations to the end of the pronunciation refs for now. makes sure that we + // don't add dups. + if (use_direction_on_ways_) { + MergeRefPronunciations(); + } + // Process mtb tags. auto mtb_scale = results.find("mtb:scale"); bool has_mtb_scale = mtb_scale != results.end(); @@ -1633,6 +2122,12 @@ struct graph_callback : public OSMPBF::Callback { way_.set_has_user_tags(true); access_->push_back(osm_access_); } + + if (has_pronunciation_tags_) { + way_.set_has_pronunciation_tags(true); + pronunciation_->push_back(osm_pronunciation_); + } + // Add the way to the list ways_->push_back(way_); } @@ -2068,6 +2563,7 @@ struct graph_callback : public OSMPBF::Callback { void reset(sequence* ways, sequence* way_nodes, sequence* access, + sequence* pronunciation, sequence* complex_restrictions_from, sequence* complex_restrictions_to, sequence* bss_nodes) { @@ -2075,11 +2571,261 @@ struct graph_callback : public OSMPBF::Callback { ways_.reset(ways); way_nodes_.reset(way_nodes); access_.reset(access); + pronunciation_.reset(pronunciation); complex_restrictions_from_.reset(complex_restrictions_from); complex_restrictions_to_.reset(complex_restrictions_to); bss_nodes_.reset(bss_nodes); } + void ProcessDirection(bool int_ref) { + + std::string ref, direction; + if (int_ref) { + ref = int_ref_; + direction = int_direction_; + } else { + ref = ref_; + direction = direction_; + } + + if (direction.empty()) { + if (int_ref) + way_.set_int_ref_index(osmdata_.name_offset_map.index(ref)); + else + way_.set_ref_index(osmdata_.name_offset_map.index(ref)); + } else { + std::vector refs = GetTagTokens(ref); + std::vector directions = GetTagTokens(direction); + + std::string tmp_ref; + if (refs.size() == directions.size()) { + for (uint32_t i = 0; i < refs.size(); i++) { + if (!tmp_ref.empty()) { + tmp_ref += ";"; + } + if (!directions.at(i).empty()) + tmp_ref += refs.at(i) + " " + directions.at(i); + else + tmp_ref += refs.at(i); + } + if (int_ref) + way_.set_int_ref_index(osmdata_.name_offset_map.index(tmp_ref)); + else + way_.set_ref_index(osmdata_.name_offset_map.index(tmp_ref)); + } else { + if (int_ref) + way_.set_int_ref_index(osmdata_.name_offset_map.index(ref)); + else + way_.set_ref_index(osmdata_.name_offset_map.index(ref)); + } + } + } + + void ProcessDirectionPronunciation(const PronunciationAlphabet type, bool int_ref) { + + std::string ref_pronunciation, direction_pronunciation; + if (int_ref) { + switch (type) { + case PronunciationAlphabet::kIpa: + ref_pronunciation = int_ref_pronunciation_; + direction_pronunciation = int_direction_pronunciation_; + break; + case PronunciationAlphabet::kXKatakana: + ref_pronunciation = int_ref_pronunciation_katakana_; + direction_pronunciation = int_direction_pronunciation_katakana_; + break; + case PronunciationAlphabet::kNtSampa: + ref_pronunciation = int_ref_pronunciation_nt_sampa_; + direction_pronunciation = int_direction_pronunciation_nt_sampa_; + break; + case PronunciationAlphabet::kXJeita: + ref_pronunciation = int_ref_pronunciation_jeita_; + direction_pronunciation = int_direction_pronunciation_jeita_; + break; + } + } else { + switch (type) { + case PronunciationAlphabet::kIpa: + ref_pronunciation = ref_pronunciation_; + direction_pronunciation = direction_pronunciation_; + break; + case PronunciationAlphabet::kXKatakana: + ref_pronunciation = ref_pronunciation_katakana_; + direction_pronunciation = direction_pronunciation_katakana_; + break; + case PronunciationAlphabet::kNtSampa: + ref_pronunciation = ref_pronunciation_nt_sampa_; + direction_pronunciation = direction_pronunciation_nt_sampa_; + break; + case PronunciationAlphabet::kXJeita: + ref_pronunciation = ref_pronunciation_jeita_; + direction_pronunciation = direction_pronunciation_jeita_; + break; + } + } + + if (direction_pronunciation.empty()) { + UpdateRefPronunciation(ref_pronunciation, type, int_ref); + } else { + std::vector refs = GetTagTokens(ref_pronunciation); + std::vector directions = GetTagTokens(direction_pronunciation); + + std::string tmp_ref; + if (refs.size() == directions.size()) { + for (uint32_t i = 0; i < refs.size(); i++) { + if (!tmp_ref.empty()) { + tmp_ref += ";"; + } + if (!directions.at(i).empty()) + tmp_ref += refs.at(i) + " " + directions.at(i); + else + tmp_ref += refs.at(i); + } + UpdateRefPronunciation(tmp_ref, type, int_ref); + } else + UpdateRefPronunciation(ref_pronunciation, type, int_ref); + } + } + + void UpdateRefPronunciation(const std::string& ref_pronunciation, + const PronunciationAlphabet type, + bool int_ref) { + if (int_ref) { + switch (type) { + case PronunciationAlphabet::kIpa: + osm_pronunciation_.set_int_ref_pronunciation_ipa_index( + osmdata_.name_offset_map.index(ref_pronunciation)); + break; + case PronunciationAlphabet::kXKatakana: + osm_pronunciation_.set_int_ref_pronunciation_katakana_index( + osmdata_.name_offset_map.index(ref_pronunciation)); + break; + case PronunciationAlphabet::kNtSampa: + osm_pronunciation_.set_int_ref_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(ref_pronunciation)); + break; + case PronunciationAlphabet::kXJeita: + osm_pronunciation_.set_int_ref_pronunciation_jeita_index( + osmdata_.name_offset_map.index(ref_pronunciation)); + break; + } + } else { + switch (type) { + case PronunciationAlphabet::kIpa: + osm_pronunciation_.set_ref_pronunciation_ipa_index( + osmdata_.name_offset_map.index(ref_pronunciation)); + break; + case PronunciationAlphabet::kXKatakana: + osm_pronunciation_.set_ref_pronunciation_katakana_index( + osmdata_.name_offset_map.index(ref_pronunciation)); + break; + case PronunciationAlphabet::kNtSampa: + osm_pronunciation_.set_ref_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(ref_pronunciation)); + break; + case PronunciationAlphabet::kXJeita: + osm_pronunciation_.set_ref_pronunciation_jeita_index( + osmdata_.name_offset_map.index(ref_pronunciation)); + break; + } + } + } + + void MergeRefPronunciations() { + + for (uint8_t type = static_cast(PronunciationAlphabet::kIpa); + type != static_cast(PronunciationAlphabet::kNtSampa) + 1; ++type) { + // add int_ref pronunciations to the end of the pronunciation refs for now. makes sure that we + // don't add dups. + + uint32_t index = 0; + std::string tmp; + switch (static_cast(type)) { + case PronunciationAlphabet::kIpa: + index = osm_pronunciation_.int_ref_pronunciation_ipa_index(); + tmp = + (index ? osmdata_.name_offset_map.name(osm_pronunciation_.ref_pronunciation_ipa_index()) + : ""); + break; + case PronunciationAlphabet::kXKatakana: + index = osm_pronunciation_.int_ref_pronunciation_katakana_index(); + tmp = (index ? osmdata_.name_offset_map.name( + osm_pronunciation_.ref_pronunciation_katakana_index()) + : ""); + break; + case PronunciationAlphabet::kNtSampa: + index = osm_pronunciation_.int_ref_pronunciation_nt_sampa_index(); + tmp = (index ? osmdata_.name_offset_map.name( + osm_pronunciation_.ref_pronunciation_nt_sampa_index()) + : ""); + break; + case PronunciationAlphabet::kXJeita: + index = osm_pronunciation_.int_ref_pronunciation_jeita_index(); + tmp = + (index + ? osmdata_.name_offset_map.name(osm_pronunciation_.ref_pronunciation_jeita_index()) + : ""); + break; + } + + if (index) { + std::vector rs = GetTagTokens(tmp); + std::vector is = GetTagTokens(osmdata_.name_offset_map.name(index)); + bool bFound = false; + + for (auto& i : is) { + for (auto& r : rs) { + if (i == r) { + bFound = true; + break; + } + } + if (!bFound) { + if (!tmp.empty()) { + tmp += ";"; + } + tmp += i; + } + bFound = false; + } + + switch (static_cast(type)) { + case PronunciationAlphabet::kIpa: + if (!tmp.empty()) { + osm_pronunciation_.set_ref_pronunciation_ipa_index(osmdata_.name_offset_map.index(tmp)); + } + // no matter what, clear out the int_ref. + osm_pronunciation_.set_int_ref_pronunciation_ipa_index(0); + break; + case PronunciationAlphabet::kXKatakana: + if (!tmp.empty()) { + osm_pronunciation_.set_ref_pronunciation_katakana_index( + osmdata_.name_offset_map.index(tmp)); + } + // no matter what, clear out the int_ref. + osm_pronunciation_.set_int_ref_pronunciation_katakana_index(0); + break; + case PronunciationAlphabet::kNtSampa: + if (!tmp.empty()) { + osm_pronunciation_.set_ref_pronunciation_nt_sampa_index( + osmdata_.name_offset_map.index(tmp)); + } + // no matter what, clear out the int_ref. + osm_pronunciation_.set_int_ref_pronunciation_nt_sampa_index(0); + break; + case PronunciationAlphabet::kXJeita: + if (!tmp.empty()) { + osm_pronunciation_.set_ref_pronunciation_jeita_index( + osmdata_.name_offset_map.index(tmp)); + } + // no matter what, clear out the int_ref. + osm_pronunciation_.set_int_ref_pronunciation_jeita_index(0); + break; + } + } + } + } + // WayCallback tag handlers using TagHandler = std::function; std::unordered_map tag_handlers_; @@ -2094,8 +2840,16 @@ struct graph_callback : public OSMPBF::Callback { bool has_surface_ = true; bool has_surface_tag_ = true; OSMAccess osm_access_; - bool has_user_tags_ = false; + OSMPronunciation osm_pronunciation_; + bool has_user_tags_ = false, has_pronunciation_tags_ = false; std::string ref_, int_ref_, direction_, int_direction_; + std::string ref_pronunciation_, int_ref_pronunciation_, ref_pronunciation_nt_sampa_, + int_ref_pronunciation_nt_sampa_, ref_pronunciation_katakana_, int_ref_pronunciation_katakana_, + ref_pronunciation_jeita_, int_ref_pronunciation_jeita_; + std::string direction_pronunciation_, int_direction_pronunciation_, + direction_pronunciation_nt_sampa_, int_direction_pronunciation_nt_sampa_, + direction_pronunciation_katakana_, int_direction_pronunciation_katakana_, + direction_pronunciation_jeita_, int_direction_pronunciation_jeita_; std::string name_, service_, amenity_; // Configuration option to include driveways @@ -2149,6 +2903,8 @@ struct graph_callback : public OSMPBF::Callback { // user entered access std::unique_ptr> access_; + // way pronunciations + std::unique_ptr> pronunciation_; // from complex restrictions std::unique_ptr> complex_restrictions_from_; // used to find out if a wayid is the to edge for a complex restriction @@ -2175,7 +2931,8 @@ OSMData PBFGraphParser::ParseWays(const boost::property_tree::ptree& pt, const std::vector& input_files, const std::string& ways_file, const std::string& way_nodes_file, - const std::string& access_file) { + const std::string& access_file, + const std::string& pronunciation_file) { // TODO: option 1: each one threads makes an osmdata and we splice them together at the end // option 2: synchronize around adding things to a single osmdata. will have to test to see // which is the least expensive (memory and speed). leaning towards option 2 @@ -2201,7 +2958,8 @@ OSMData PBFGraphParser::ParseWays(const boost::property_tree::ptree& pt, callback.reset(new sequence(ways_file, true), new sequence(way_nodes_file, true), - new sequence(access_file, true), nullptr, nullptr, nullptr); + new sequence(access_file, true), + new sequence(pronunciation_file, true), nullptr, nullptr, nullptr); // Parse the ways and find all node Ids needed (those that are part of a // way's node list. Iterate through each pbf input file. LOG_INFO("Parsing ways..."); @@ -2219,7 +2977,7 @@ OSMData PBFGraphParser::ParseWays(const boost::property_tree::ptree& pt, LOG_INFO("Finished with " + std::to_string(osmdata.osm_way_count) + " routable ways containing " + std::to_string(osmdata.osm_way_node_count) + " nodes"); - callback.reset(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + callback.reset(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); // we need to sort the access tags so that we can easily find them. LOG_INFO("Sorting osm access tags by way id..."); @@ -2228,6 +2986,14 @@ OSMData PBFGraphParser::ParseWays(const boost::property_tree::ptree& pt, access.sort([](const OSMAccess& a, const OSMAccess& b) { return a.way_id() < b.way_id(); }); } + // we need to sort the pronunciation indexes so that we can easily find them. + LOG_INFO("Sorting pronunciation indexes by way id..."); + { + sequence pronunciation(pronunciation_file, false); + pronunciation.sort( + [](const OSMPronunciation& a, const OSMPronunciation& b) { return a.way_id() < b.way_id(); }); + } + LOG_INFO("Finished"); // Return OSM data @@ -2266,7 +3032,7 @@ void PBFGraphParser::ParseRelations(const boost::property_tree::ptree& pt, } } - callback.reset(nullptr, nullptr, nullptr, + callback.reset(nullptr, nullptr, nullptr, nullptr, new sequence(complex_restriction_from_file, true), new sequence(complex_restriction_to_file, true), nullptr); @@ -2284,7 +3050,7 @@ void PBFGraphParser::ParseRelations(const boost::property_tree::ptree& pt, LOG_INFO("Finished with " + std::to_string(osmdata.lane_connectivity_map.size()) + " lane connections"); - callback.reset(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + callback.reset(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); // Sort complex restrictions. Keep this scoped so the file handles are closed when done sorting. LOG_INFO("Sorting complex restrictions by from id..."); @@ -2341,13 +3107,13 @@ void PBFGraphParser::ParseNodes(const boost::property_tree::ptree& pt, callback.current_way_node_index_ = callback.last_node_ = callback.last_way_ = callback.last_relation_ = 0; // we send a null way_nodes file so that only the bike share stations are parsed - callback.reset(nullptr, nullptr, nullptr, nullptr, nullptr, + callback.reset(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, new sequence(bss_nodes_file, true)); OSMPBF::Parser::parse(file_handle, static_cast(OSMPBF::Interest::NODES), callback); } } - callback.reset(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + callback.reset(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); // we need to sort the refs so that we can easily (sequentially) update them // during node processing, we use memory mapping here because otherwise we aren't @@ -2367,7 +3133,7 @@ void PBFGraphParser::ParseNodes(const boost::property_tree::ptree& pt, // each time we parse nodes we have to run through the way nodes file from the beginning because // because osm node ids are only sorted at the single pbf file level callback.reset(nullptr, new sequence(way_nodes_file, false), nullptr, nullptr, - nullptr, nullptr); + nullptr, nullptr, nullptr); callback.current_way_node_index_ = callback.last_node_ = callback.last_way_ = callback.last_relation_ = 0; OSMPBF::Parser::parse(file_handle, @@ -2376,7 +3142,7 @@ void PBFGraphParser::ParseNodes(const boost::property_tree::ptree& pt, callback); } uint64_t max_osm_id = callback.last_node_; - callback.reset(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + callback.reset(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); LOG_INFO("Finished with " + std::to_string(osmdata.osm_node_count) + " nodes contained in routable ways"); diff --git a/src/mjolnir/shortcutbuilder.cc b/src/mjolnir/shortcutbuilder.cc index 1e3785bf45..e1ff97752e 100644 --- a/src/mjolnir/shortcutbuilder.cc +++ b/src/mjolnir/shortcutbuilder.cc @@ -423,9 +423,11 @@ uint32_t AddShortcutEdges(GraphReader& reader, std::reverse(shape.begin(), shape.end()); } - // Get names and types - they apply over all edges of the shortcut + // Get names - they apply over all edges of the shortcut auto names = edgeinfo.GetNames(); auto tagged_values = edgeinfo.GetTaggedValues(); + auto pronunciations = edgeinfo.GetTaggedValues(true); + auto types = edgeinfo.GetTypes(); // Add any access restriction records. TODO - make sure we don't contract @@ -490,8 +492,9 @@ uint32_t AddShortcutEdges(GraphReader& reader, uint32_t idx = ((length & 0xfffff) | ((shape.size() & 0xfff) << 20)); uint32_t edge_info_offset = tilebuilder.AddEdgeInfo(idx, start_node, end_node, 0, 0, edgeinfo.bike_network(), - edgeinfo.speed_limit(), shape, names, tagged_values, types, forward, - diff_names); + edgeinfo.speed_limit(), shape, names, tagged_values, pronunciations, + types, forward, diff_names); + newedge.set_edgeinfo_offset(edge_info_offset); // Set the forward flag on this directed edge. If a new edge was added @@ -636,7 +639,7 @@ uint32_t FormShortcuts(GraphReader& reader, const TileLevel& level) { // Get signs from the base directed edge if (directededge->sign()) { - std::vector signs = tile->GetSigns(edgeid.id()); + std::vector signs = tile->ProcessSigns(edgeid.id()); if (signs.size() == 0) { LOG_ERROR("Base edge should have signs, but none found"); } @@ -682,7 +685,8 @@ uint32_t FormShortcuts(GraphReader& reader, const TileLevel& level) { edgeinfo.wayid(), edgeinfo.mean_elevation(), edgeinfo.bike_network(), edgeinfo.speed_limit(), edgeinfo.encoded_shape(), edgeinfo.GetNames(), - edgeinfo.GetTaggedValues(), edgeinfo.GetTypes(), added); + edgeinfo.GetTaggedValues(), edgeinfo.GetTaggedValues(true), + edgeinfo.GetTypes(), added); newedge.set_edgeinfo_offset(edge_info_offset); // Set the superseded mask - this is the shortcut mask that supersedes this edge @@ -704,7 +708,7 @@ uint32_t FormShortcuts(GraphReader& reader, const TileLevel& level) { // Get named signs from the base node if (nodeinfo.named_intersection()) { - std::vector signs = tile->GetSigns(n, true); + std::vector signs = tile->ProcessSigns(n, true); if (signs.size() == 0) { LOG_ERROR("Base node should have signs, but none found"); } diff --git a/src/mjolnir/transitbuilder.cc b/src/mjolnir/transitbuilder.cc index 8bbbb51691..7ee9ae755b 100644 --- a/src/mjolnir/transitbuilder.cc +++ b/src/mjolnir/transitbuilder.cc @@ -38,6 +38,7 @@ struct OSMConnectionEdge { uint64_t wayid; std::vector names; std::vector tagged_values; + std::vector pronunciations; std::list shape; OSMConnectionEdge(const GraphId& f, @@ -198,7 +199,8 @@ void ConnectToGraph(GraphTileBuilder& tilebuilder_local, bool added = false; uint32_t edge_info_offset = tilebuilder_local.AddEdgeInfo(0, conn.osm_node, endnode, conn.wayid, 0, 0, 0, conn.shape, - conn.names, conn.tagged_values, 0, added); + conn.names, conn.tagged_values, conn.pronunciations, 0, + added); directededge.set_edgeinfo_offset(edge_info_offset); directededge.set_forward(true); tilebuilder_local.directededges().emplace_back(std::move(directededge)); @@ -312,7 +314,8 @@ void ConnectToGraph(GraphTileBuilder& tilebuilder_local, std::reverse(r_shape.begin(), r_shape.end()); uint32_t edge_info_offset = tilebuilder_transit.AddEdgeInfo(0, origin_node, conn.osm_node, conn.wayid, 0, 0, 0, - r_shape, conn.names, conn.tagged_values, 0, added); + r_shape, conn.names, conn.tagged_values, + conn.pronunciations, 0, added); LOG_DEBUG("Add conn from stop to OSM: ei offset = " + std::to_string(edge_info_offset)); directededge.set_edgeinfo_offset(edge_info_offset); directededge.set_forward(true); diff --git a/src/mjolnir/util.cc b/src/mjolnir/util.cc index 0d2de82eec..6c418cdc49 100644 --- a/src/mjolnir/util.cc +++ b/src/mjolnir/util.cc @@ -34,6 +34,7 @@ const std::string nodes_file = "nodes.bin"; const std::string edges_file = "edges.bin"; const std::string tile_manifest_file = "tile_manifest.json"; const std::string access_file = "access.bin"; +const std::string pronunciation_file = "pronunciation.bin"; const std::string bss_nodes_file = "bss_nodes.bin"; const std::string cr_from_file = "complex_from_restrictions.bin"; const std::string cr_to_file = "complex_to_restrictions.bin"; @@ -218,6 +219,7 @@ bool build_tile_set(const boost::property_tree::ptree& original_config, std::string edges_bin = tile_dir + edges_file; std::string tile_manifest = tile_dir + tile_manifest_file; std::string access_bin = tile_dir + access_file; + std::string pronunciation_bin = tile_dir + pronunciation_file; std::string bss_nodes_bin = tile_dir + bss_nodes_file; std::string cr_from_bin = tile_dir + cr_from_file; std::string cr_to_bin = tile_dir + cr_to_file; @@ -231,7 +233,7 @@ bool build_tile_set(const boost::property_tree::ptree& original_config, if (start_stage <= BuildStage::kParseWays && BuildStage::kParseWays <= end_stage) { // Read the OSM protocol buffer file. Callbacks for ways are defined within the PBFParser class osm_data = PBFGraphParser::ParseWays(config.get_child("mjolnir"), input_files, ways_bin, - way_nodes_bin, access_bin); + way_nodes_bin, access_bin, pronunciation_bin); // Free all protobuf memory - cannot use the protobuffer lib after this! if (release_osmpbf_memory && BuildStage::kParseWays == end_stage) { @@ -312,7 +314,7 @@ bool build_tile_set(const boost::property_tree::ptree& original_config, // Build the graph using the OSMNodes and OSMWays from the parser GraphBuilder::Build(config, osm_data, ways_bin, way_nodes_bin, nodes_bin, edges_bin, cr_from_bin, - cr_to_bin, tiles); + cr_to_bin, pronunciation_bin, tiles); } // Enhance the local level of the graph. This adds information to the local @@ -389,6 +391,7 @@ bool build_tile_set(const boost::property_tree::ptree& original_config, remove_temp_file(nodes_bin); remove_temp_file(edges_bin); remove_temp_file(access_bin); + remove_temp_file(pronunciation_bin); remove_temp_file(bss_nodes_bin); remove_temp_file(cr_from_bin); remove_temp_file(cr_to_bin); diff --git a/src/mjolnir/valhalla_convert_transit.cc b/src/mjolnir/valhalla_convert_transit.cc index 075e7a3402..8c529799cc 100644 --- a/src/mjolnir/valhalla_convert_transit.cc +++ b/src/mjolnir/valhalla_convert_transit.cc @@ -649,12 +649,13 @@ void AddToGraph(GraphTileBuilder& tilebuilder_transit, // Add edge info to the tile and set the offset in the directed edge bool added = false; - std::vector names, tagged_values; + std::vector names, tagged_values, pronunciations; + std::list shape = {egress_ll, station_ll}; uint32_t edge_info_offset = tilebuilder_transit.AddEdgeInfo(0, egress_graphid, station_graphid, 0, 0, 0, 0, shape, - names, tagged_values, 0, added); + names, tagged_values, pronunciations, 0, added); directededge.set_edgeinfo_offset(edge_info_offset); directededge.set_forward(true); @@ -697,13 +698,13 @@ void AddToGraph(GraphTileBuilder& tilebuilder_transit, directededge.set_named(false); // Add edge info to the tile and set the offset in the directed edge bool added = false; - std::vector names, tagged_values; + std::vector names, tagged_values, pronunciations; std::list shape = {station_ll, egress_ll}; // TODO - these need to be valhalla graph Ids uint32_t edge_info_offset = tilebuilder_transit.AddEdgeInfo(0, station_graphid, egress_graphid, 0, 0, 0, 0, shape, - names, tagged_values, 0, added); + names, tagged_values, pronunciations, 0, added); directededge.set_edgeinfo_offset(edge_info_offset); directededge.set_forward(true); @@ -754,13 +755,13 @@ void AddToGraph(GraphTileBuilder& tilebuilder_transit, // Add edge info to the tile and set the offset in the directed edge bool added = false; - std::vector names, tagged_values; + std::vector names, tagged_values, pronunciations; std::list shape = {station_ll, platform_ll}; // TODO - these need to be valhalla graph Ids uint32_t edge_info_offset = tilebuilder_transit.AddEdgeInfo(0, station_graphid, platform_graphid, 0, 0, 0, 0, shape, - names, tagged_values, 0, added); + names, tagged_values, pronunciations, 0, added); directededge.set_edgeinfo_offset(edge_info_offset); directededge.set_forward(true); @@ -832,13 +833,14 @@ void AddToGraph(GraphTileBuilder& tilebuilder_transit, directededge.set_named(false); // Add edge info to the tile and set the offset in the directed edge bool added = false; - std::vector names, tagged_values; + std::vector names, tagged_values, pronunciations; std::list shape = {platform_ll, station_ll}; // TODO - these need to be valhalla graph Ids uint32_t edge_info_offset = tilebuilder_transit.AddEdgeInfo(0, platform_graphid, station_graphid, 0, 0, 0, 0, shape, - names, tagged_values, 0, added); + names, tagged_values, pronunciations, 0, added); + directededge.set_edgeinfo_offset(edge_info_offset); directededge.set_forward(true); @@ -904,7 +906,7 @@ void AddToGraph(GraphTileBuilder& tilebuilder_transit, // Leave the name empty. Use the trip Id to look up the route Id and // route within TripLegBuilder. bool added = false; - std::vector names, tagged_values; + std::vector names, tagged_values, pronunciations; std::vector points; std::vector distance; @@ -928,7 +930,8 @@ void AddToGraph(GraphTileBuilder& tilebuilder_transit, uint32_t edge_info_offset = tilebuilder_transit.AddEdgeInfo(transitedge.routeid, platform_graphid, endnode, 0, 0, 0, 0, - shape, names, tagged_values, 0, added); + shape, names, tagged_values, pronunciations, 0, added); + directededge.set_edgeinfo_offset(edge_info_offset); directededge.set_forward(added); diff --git a/src/odin/CMakeLists.txt b/src/odin/CMakeLists.txt index 0c7018e664..372cb166de 100644 --- a/src/odin/CMakeLists.txt +++ b/src/odin/CMakeLists.txt @@ -14,6 +14,7 @@ set(sources directionsbuilder.cc maneuversbuilder.cc + markup_formatter.cc narrative_dictionary.cc narrative_builder_factory.cc narrativebuilder.cc diff --git a/src/odin/directionsbuilder.cc b/src/odin/directionsbuilder.cc index 51897bcffd..64be7425b4 100644 --- a/src/odin/directionsbuilder.cc +++ b/src/odin/directionsbuilder.cc @@ -5,6 +5,7 @@ #include "odin/directionsbuilder.h" #include "odin/enhancedtrippath.h" #include "odin/maneuversbuilder.h" +#include "odin/markup_formatter.h" #include "odin/narrative_builder_factory.h" #include "odin/narrativebuilder.h" #include "proto/directions.pb.h" @@ -65,7 +66,7 @@ const std::unordered_map translate_travel_mode{ // NarrativeBuilder::Build to form the maneuver list. This method // calls PopulateDirectionsLeg to transform the maneuver list into the // trip directions. -void DirectionsBuilder::Build(Api& api) { +void DirectionsBuilder::Build(Api& api, const MarkupFormatter& markup_formatter) { const auto& options = api.options(); for (auto& trip_route : *api.mutable_trip()->mutable_routes()) { auto& directions_route = *api.mutable_directions()->mutable_routes()->Add(); @@ -92,7 +93,7 @@ void DirectionsBuilder::Build(Api& api) { // Create the instructions if desired if (options.directions_type() == DirectionsType::instructions) { std::unique_ptr narrative_builder = - NarrativeBuilderFactory::Create(options, &etp); + NarrativeBuilderFactory::Create(options, &etp, markup_formatter); narrative_builder->Build(maneuvers); } } @@ -155,6 +156,11 @@ void DirectionsBuilder::PopulateDirectionsLeg(const Options& options, auto* maneuver_street_name = trip_maneuver->add_street_name(); maneuver_street_name->set_value(street_name->value()); maneuver_street_name->set_is_route_number(street_name->is_route_number()); + if (street_name->pronunciation()) { + auto* pronunciation = maneuver_street_name->mutable_pronunciation(); + pronunciation->set_alphabet(street_name->pronunciation()->alphabet()); + pronunciation->set_value(street_name->pronunciation()->value()); + } } // Set begin street names @@ -162,6 +168,11 @@ void DirectionsBuilder::PopulateDirectionsLeg(const Options& options, auto* maneuver_begin_street_name = trip_maneuver->add_begin_street_name(); maneuver_begin_street_name->set_value(begin_street_name->value()); maneuver_begin_street_name->set_is_route_number(begin_street_name->is_route_number()); + if (begin_street_name->pronunciation()) { + auto* pronunciation = maneuver_begin_street_name->mutable_pronunciation(); + pronunciation->set_alphabet(begin_street_name->pronunciation()->alphabet()); + pronunciation->set_value(begin_street_name->pronunciation()->value()); + } } trip_maneuver->set_length(maneuver.length(options.units())); @@ -205,6 +216,7 @@ void DirectionsBuilder::PopulateDirectionsLeg(const Options& options, if (maneuver.HasExitSign() || maneuver.HasGuideSign() || maneuver.HasJunctionNameSign()) { auto* trip_sign = trip_maneuver->mutable_sign(); + // TODO: refactor sign assignments // Process exit number info if (maneuver.HasExitNumberSign()) { for (const auto& exit_number : maneuver.signs().exit_number_list()) { @@ -212,6 +224,11 @@ void DirectionsBuilder::PopulateDirectionsLeg(const Options& options, trip_exit_number->set_text(exit_number.text()); trip_exit_number->set_is_route_number(exit_number.is_route_number()); trip_exit_number->set_consecutive_count(exit_number.consecutive_count()); + if (exit_number.pronunciation()) { + auto* pronunciation = trip_exit_number->mutable_pronunciation(); + pronunciation->set_alphabet(exit_number.pronunciation()->alphabet()); + pronunciation->set_value(exit_number.pronunciation()->value()); + } } } @@ -222,6 +239,11 @@ void DirectionsBuilder::PopulateDirectionsLeg(const Options& options, trip_exit_onto_street->set_text(exit_branch.text()); trip_exit_onto_street->set_is_route_number(exit_branch.is_route_number()); trip_exit_onto_street->set_consecutive_count(exit_branch.consecutive_count()); + if (exit_branch.pronunciation()) { + auto* pronunciation = trip_exit_onto_street->mutable_pronunciation(); + pronunciation->set_alphabet(exit_branch.pronunciation()->alphabet()); + pronunciation->set_value(exit_branch.pronunciation()->value()); + } } } @@ -232,6 +254,11 @@ void DirectionsBuilder::PopulateDirectionsLeg(const Options& options, trip_exit_toward_location->set_text(exit_toward.text()); trip_exit_toward_location->set_is_route_number(exit_toward.is_route_number()); trip_exit_toward_location->set_consecutive_count(exit_toward.consecutive_count()); + if (exit_toward.pronunciation()) { + auto* pronunciation = trip_exit_toward_location->mutable_pronunciation(); + pronunciation->set_alphabet(exit_toward.pronunciation()->alphabet()); + pronunciation->set_value(exit_toward.pronunciation()->value()); + } } } @@ -242,6 +269,11 @@ void DirectionsBuilder::PopulateDirectionsLeg(const Options& options, trip_exit_name->set_text(exit_name.text()); trip_exit_name->set_is_route_number(exit_name.is_route_number()); trip_exit_name->set_consecutive_count(exit_name.consecutive_count()); + if (exit_name.pronunciation()) { + auto* pronunciation = trip_exit_name->mutable_pronunciation(); + pronunciation->set_alphabet(exit_name.pronunciation()->alphabet()); + pronunciation->set_value(exit_name.pronunciation()->value()); + } } } @@ -252,6 +284,11 @@ void DirectionsBuilder::PopulateDirectionsLeg(const Options& options, trip_guide_onto_street->set_text(guide_branch.text()); trip_guide_onto_street->set_is_route_number(guide_branch.is_route_number()); trip_guide_onto_street->set_consecutive_count(guide_branch.consecutive_count()); + if (guide_branch.pronunciation()) { + auto* pronunciation = trip_guide_onto_street->mutable_pronunciation(); + pronunciation->set_alphabet(guide_branch.pronunciation()->alphabet()); + pronunciation->set_value(guide_branch.pronunciation()->value()); + } } } @@ -262,6 +299,11 @@ void DirectionsBuilder::PopulateDirectionsLeg(const Options& options, trip_guide_toward_location->set_text(guide_toward.text()); trip_guide_toward_location->set_is_route_number(guide_toward.is_route_number()); trip_guide_toward_location->set_consecutive_count(guide_toward.consecutive_count()); + if (guide_toward.pronunciation()) { + auto* pronunciation = trip_guide_toward_location->mutable_pronunciation(); + pronunciation->set_alphabet(guide_toward.pronunciation()->alphabet()); + pronunciation->set_value(guide_toward.pronunciation()->value()); + } } } @@ -272,6 +314,11 @@ void DirectionsBuilder::PopulateDirectionsLeg(const Options& options, trip_junction_name->set_text(junction_name.text()); trip_junction_name->set_is_route_number(junction_name.is_route_number()); trip_junction_name->set_consecutive_count(junction_name.consecutive_count()); + if (junction_name.pronunciation()) { + auto* pronunciation = trip_junction_name->mutable_pronunciation(); + pronunciation->set_alphabet(junction_name.pronunciation()->alphabet()); + pronunciation->set_value(junction_name.pronunciation()->value()); + } } } } @@ -287,11 +334,16 @@ void DirectionsBuilder::PopulateDirectionsLeg(const Options& options, } // Set roundabout exit street names - for (const auto& roundabout_exit_street_names : maneuver.roundabout_exit_street_names()) { - auto* maneuver_roundabout_exit_street_names = trip_maneuver->add_roundabout_exit_street_names(); - maneuver_roundabout_exit_street_names->set_value(roundabout_exit_street_names->value()); - maneuver_roundabout_exit_street_names->set_is_route_number( - roundabout_exit_street_names->is_route_number()); + for (const auto& roundabout_exit_street_name : maneuver.roundabout_exit_street_names()) { + auto* maneuver_roundabout_exit_street_name = trip_maneuver->add_roundabout_exit_street_names(); + maneuver_roundabout_exit_street_name->set_value(roundabout_exit_street_name->value()); + maneuver_roundabout_exit_street_name->set_is_route_number( + roundabout_exit_street_name->is_route_number()); + if (roundabout_exit_street_name->pronunciation()) { + auto* pronunciation = maneuver_roundabout_exit_street_name->mutable_pronunciation(); + pronunciation->set_alphabet(roundabout_exit_street_name->pronunciation()->alphabet()); + pronunciation->set_value(roundabout_exit_street_name->pronunciation()->value()); + } } // Depart instructions diff --git a/src/odin/enhancedtrippath.cc b/src/odin/enhancedtrippath.cc index 2eb3dbd4aa..be4c596986 100644 --- a/src/odin/enhancedtrippath.cc +++ b/src/odin/enhancedtrippath.cc @@ -13,6 +13,7 @@ #include "odin/util.h" #include "proto/trip.pb.h" +#include "proto/tripcommon.pb.h" using namespace valhalla::midgard; using namespace valhalla::baldr; @@ -26,6 +27,18 @@ constexpr int kIsStraightestBuffer = 10; // Buffer between str constexpr uint32_t kBackwardTurnDegreeLowerBound = 124; constexpr uint32_t kBackwardTurnDegreeUpperBound = 236; +const std::string& Pronunciation_Alphabet_Name(valhalla::Pronunciation_Alphabet alphabet) { + static const std::unordered_map + values{{valhalla::Pronunciation_Alphabet::Pronunciation_Alphabet_kIpa, "kIpa"}, + {valhalla::Pronunciation_Alphabet::Pronunciation_Alphabet_kXKatakana, "kXKatakana"}, + {valhalla::Pronunciation_Alphabet::Pronunciation_Alphabet_kXJeita, "kXJeita"}, + {valhalla::Pronunciation_Alphabet::Pronunciation_Alphabet_kNtSampa, "kNtSampa"}}; + auto f = values.find(alphabet); + if (f == values.cend()) + throw std::runtime_error("Missing value in protobuf Pronunciation_Alphabet enum to string"); + return f->second; +} + const std::string& RoadClass_Name(int v) { static const std::unordered_map values{ {0, "kMotorway"}, {1, "kTrunk"}, {2, "kPrimary"}, {3, "kSecondary"}, @@ -999,6 +1012,11 @@ std::string EnhancedTripLeg_Edge::StreetNamesToString( str += "/"; } str += street_name.value(); + if (street_name.has_pronunciation()) { + str += "("; + str += street_name.pronunciation().value(); + str += ")"; + } } return str; } @@ -1012,6 +1030,11 @@ std::string EnhancedTripLeg_Edge::SignElementsToString( str += "/"; } str += sign_element.text(); + if (sign_element.has_pronunciation()) { + str += "("; + str += sign_element.pronunciation().value(); + str += ")"; + } } return str; } @@ -1243,6 +1266,14 @@ std::string EnhancedTripLeg_Edge::StreetNamesToParameterString( param_list += street_name.value(); param_list += "\", "; param_list += std::to_string(street_name.is_route_number()); + if (street_name.has_pronunciation()) { + param_list += ", "; + param_list += "Pronunciation_Alphabet_"; + param_list += Pronunciation_Alphabet_Name(street_name.pronunciation().alphabet()); + param_list += ", \""; + param_list += street_name.pronunciation().value(); + param_list += "\""; + } param_list += " }"; } str += param_list; @@ -1266,6 +1297,14 @@ std::string EnhancedTripLeg_Edge::SignElementsToParameterString( param_list += sign_element.text(); param_list += "\", "; param_list += std::to_string(sign_element.is_route_number()); + if (sign_element.has_pronunciation()) { + param_list += ", "; + param_list += "Pronunciation_Alphabet_"; + param_list += Pronunciation_Alphabet_Name(sign_element.pronunciation().alphabet()); + param_list += ", \""; + param_list += sign_element.pronunciation().value(); + param_list += "\""; + } param_list += " }"; } str += param_list; diff --git a/src/odin/maneuversbuilder.cc b/src/odin/maneuversbuilder.cc index e7bdef4d67..acbe7882b4 100644 --- a/src/odin/maneuversbuilder.cc +++ b/src/odin/maneuversbuilder.cc @@ -9,8 +9,10 @@ #include #include +#include #include "baldr/graphconstants.h" +#include "baldr/pronunciation.h" #include "baldr/streetnames.h" #include "baldr/streetnames_factory.h" #include "baldr/streetnames_us.h" @@ -1188,7 +1190,7 @@ void ManeuversBuilder::UpdateManeuver(Maneuver& maneuver, int node_index) { if ((maneuver.street_names().empty() && !maneuver.internal_intersection()) || UsableInternalIntersectionName(maneuver, node_index)) { maneuver.set_street_names( - StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), prev_edge->GetNameList())); + StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), prev_edge->name())); } // Update the internal turn count @@ -1247,29 +1249,47 @@ void ManeuversBuilder::UpdateManeuver(Maneuver& maneuver, int node_index) { if (prev_edge->has_sign()) { // Exit number for (const auto& exit_number : prev_edge->sign().exit_numbers()) { + boost::optional pronunciation = + boost::make_optional(exit_number.has_pronunciation(), + baldr::Pronunciation{exit_number.pronunciation().alphabet(), + exit_number.pronunciation().value()}); maneuver.mutable_signs() ->mutable_exit_number_list() - ->emplace_back(exit_number.text(), exit_number.is_route_number()); + ->emplace_back(exit_number.text(), exit_number.is_route_number(), pronunciation); } // Exit branch for (const auto& exit_onto_street : prev_edge->sign().exit_onto_streets()) { + boost::optional pronunciation = + boost::make_optional(exit_onto_street.has_pronunciation(), + baldr::Pronunciation{exit_onto_street.pronunciation().alphabet(), + exit_onto_street.pronunciation().value()}); maneuver.mutable_signs() ->mutable_exit_branch_list() - ->emplace_back(exit_onto_street.text(), exit_onto_street.is_route_number()); + ->emplace_back(exit_onto_street.text(), exit_onto_street.is_route_number(), pronunciation); } // Exit toward for (const auto& exit_toward_location : prev_edge->sign().exit_toward_locations()) { + boost::optional pronunciation = + boost::make_optional(exit_toward_location.has_pronunciation(), + baldr::Pronunciation{exit_toward_location.pronunciation().alphabet(), + exit_toward_location.pronunciation().value()}); maneuver.mutable_signs() ->mutable_exit_toward_list() - ->emplace_back(exit_toward_location.text(), exit_toward_location.is_route_number()); + ->emplace_back(exit_toward_location.text(), exit_toward_location.is_route_number(), + pronunciation); } // Exit name for (const auto& exit_name : prev_edge->sign().exit_names()) { + boost::optional pronunciation = + boost::make_optional(exit_name.has_pronunciation(), + baldr::Pronunciation{exit_name.pronunciation().alphabet(), + exit_name.pronunciation().value()}); maneuver.mutable_signs()->mutable_exit_name_list()->emplace_back(exit_name.text(), - exit_name.is_route_number()); + exit_name.is_route_number(), + pronunciation); } } @@ -1357,7 +1377,7 @@ void ManeuversBuilder::FinalizeManeuver(Maneuver& maneuver, int node_index) { if (!curr_edge->IsHighway() && !curr_edge->internal_intersection() && (curr_edge->name_size() > 1)) { std::unique_ptr curr_edge_names = - StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), curr_edge->GetNameList()); + StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), curr_edge->name()); std::unique_ptr common_base_names = curr_edge_names->FindCommonBaseNames(maneuver.street_names()); if (curr_edge_names->size() > common_base_names->size()) { @@ -1385,23 +1405,37 @@ void ManeuversBuilder::FinalizeManeuver(Maneuver& maneuver, int node_index) { if (curr_edge->has_sign()) { // Guide branch for (const auto& guide_onto_street : curr_edge->sign().guide_onto_streets()) { + boost::optional pronunciation = + boost::make_optional(guide_onto_street.has_pronunciation(), + baldr::Pronunciation{guide_onto_street.pronunciation().alphabet(), + guide_onto_street.pronunciation().value()}); maneuver.mutable_signs() ->mutable_guide_branch_list() - ->emplace_back(guide_onto_street.text(), guide_onto_street.is_route_number()); + ->emplace_back(guide_onto_street.text(), guide_onto_street.is_route_number(), + pronunciation); } // Guide toward for (const auto& guide_toward_location : curr_edge->sign().guide_toward_locations()) { + boost::optional pronunciation = + boost::make_optional(guide_toward_location.has_pronunciation(), + baldr::Pronunciation{guide_toward_location.pronunciation().alphabet(), + guide_toward_location.pronunciation().value()}); maneuver.mutable_signs() ->mutable_guide_toward_list() - ->emplace_back(guide_toward_location.text(), guide_toward_location.is_route_number()); + ->emplace_back(guide_toward_location.text(), guide_toward_location.is_route_number(), + pronunciation); } // Junction name for (const auto& junction_name : curr_edge->sign().junction_names()) { + boost::optional pronunciation = + boost::make_optional(junction_name.has_pronunciation(), + baldr::Pronunciation{junction_name.pronunciation().alphabet(), + junction_name.pronunciation().value()}); maneuver.mutable_signs() ->mutable_junction_name_list() - ->emplace_back(junction_name.text(), junction_name.is_route_number()); + ->emplace_back(junction_name.text(), junction_name.is_route_number(), pronunciation); } } @@ -2102,7 +2136,7 @@ bool ManeuversBuilder::CanManeuverIncludePrevEdge(Maneuver& maneuver, int node_i ///////////////////////////////////////////////////////////////////////////// // Determine previous edge names and common base names std::unique_ptr prev_edge_names = - StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), prev_edge->GetNameList()); + StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), prev_edge->name()); std::unique_ptr common_base_names = prev_edge_names->FindCommonBaseNames(maneuver.street_names()); @@ -2442,10 +2476,10 @@ bool ManeuversBuilder::IsLeftPencilPointUturn(int node_index, xedge_counts); std::unique_ptr prev_edge_names = - StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), prev_edge->GetNameList()); + StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), prev_edge->name()); std::unique_ptr curr_edge_names = - StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), curr_edge->GetNameList()); + StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), curr_edge->name()); // Process common base names std::unique_ptr common_base_names = @@ -2481,10 +2515,10 @@ bool ManeuversBuilder::IsRightPencilPointUturn(int node_index, xedge_counts); std::unique_ptr prev_edge_names = - StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), prev_edge->GetNameList()); + StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), prev_edge->name()); std::unique_ptr curr_edge_names = - StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), curr_edge->GetNameList()); + StreetNamesFactory::Create(trip_path_->GetCountryCode(node_index), curr_edge->name()); // Process common base names std::unique_ptr common_base_names = @@ -3029,7 +3063,8 @@ void ManeuversBuilder::EnhanceSignlessInterchnages(std::list& maneuver curr_man->mutable_signs() ->mutable_exit_branch_list() ->emplace_back(next_man->street_names().front()->value(), - next_man->street_names().front()->is_route_number()); + next_man->street_names().front()->is_route_number(), + next_man->street_names().front()->pronunciation()); } // on to the next maneuver... diff --git a/src/odin/markup_formatter.cc b/src/odin/markup_formatter.cc new file mode 100644 index 0000000000..12819f449e --- /dev/null +++ b/src/odin/markup_formatter.cc @@ -0,0 +1,121 @@ +#include + +#include +#include +#include +#include + +#include "odin/markup_formatter.h" +#include "proto/tripcommon.pb.h" + +namespace { +constexpr auto kQuotesTag = ""; +constexpr auto kPhoneticAlphabetTag = ""; +constexpr auto kTextualStringTag = ""; +constexpr auto kVerbalStringTag = ""; + +constexpr auto KSingleQuotes = "'"; +constexpr auto KDoubleQuotes = "\""; + +const std::string& PronunciationAlphabetToString(valhalla::Pronunciation_Alphabet alphabet) { + static const std::unordered_map + values{{valhalla::Pronunciation_Alphabet::Pronunciation_Alphabet_kIpa, "ipa"}, + {valhalla::Pronunciation_Alphabet::Pronunciation_Alphabet_kXKatakana, "x-katakana"}, + {valhalla::Pronunciation_Alphabet::Pronunciation_Alphabet_kXJeita, "x-jeita"}, + {valhalla::Pronunciation_Alphabet::Pronunciation_Alphabet_kNtSampa, "nt-sampa"}}; + auto f = values.find(alphabet); + if (f == values.cend()) + throw std::runtime_error("Missing value in protobuf Pronunciation_Alphabet enum to string"); + return f->second; +} + +} // namespace + +namespace valhalla { +namespace odin { + +// Constructor +MarkupFormatter::MarkupFormatter(const boost::property_tree::ptree& config) + : markup_enabled_(config.get("odin.markup_formatter.markup_enabled", false)), + phoneme_format_(config.get("odin.markup_formatter.phoneme_format", "")) { +} + +bool MarkupFormatter::markup_enabled() const { + return markup_enabled_; +} + +void MarkupFormatter::set_markup_enabled(bool markup_enabled) { + markup_enabled_ = markup_enabled; +} + +boost::optional +MarkupFormatter::Format(const std::unique_ptr& street_name) const { + // Check if markup is enabled + if (markup_enabled()) { + + // If pronunciation exists then process the phoneme format + if (street_name->pronunciation()) { + // Populate the phoneme markup string + std::string phoneme_markup_string = + FormatPhonemeElement(street_name->value(), street_name->pronunciation()); + + // If the markup string exists then return the street name with the phoneme + return boost::make_optional(!phoneme_markup_string.empty(), phoneme_markup_string); + } + } + return boost::none; +} + +boost::optional MarkupFormatter::Format(const Sign& sign) const { + // Check if markup is enabled + if (markup_enabled()) { + + // If pronunciation exists then process the phoneme format + if (sign.pronunciation()) { + // Populate the phoneme markup string + std::string phoneme_markup_string = FormatPhonemeElement(sign.text(), sign.pronunciation()); + + // If the markup string exists then return the sign with the phoneme + return boost::make_optional(!phoneme_markup_string.empty(), phoneme_markup_string); + } + } + return boost::none; +} + +const std::string& MarkupFormatter::phoneme_format() const { + return phoneme_format_; +} + +bool MarkupFormatter::UseSingleQuotes(valhalla::Pronunciation_Alphabet alphabet) const { + if (alphabet == valhalla::Pronunciation_Alphabet_kNtSampa) { + return true; + } + return false; +} + +void MarkupFormatter::FormatQuotes(std::string& markup_string, + valhalla::Pronunciation_Alphabet alphabet) const { + // Use the proper quotes depending on the pronunciation alphabet + UseSingleQuotes(alphabet) ? boost::replace_all(markup_string, kQuotesTag, KSingleQuotes) + : boost::replace_all(markup_string, kQuotesTag, KDoubleQuotes); +} + +std::string MarkupFormatter::FormatPhonemeElement( + const std::string& textual_string, + const boost::optional& pronunciation) const { + std::string phoneme_markup_string = phoneme_format(); + + // Use the proper quotes depending on the pronunciation alphabet + FormatQuotes(phoneme_markup_string, pronunciation->alphabet()); + + // Replace phrase tags with values + boost::replace_all(phoneme_markup_string, kPhoneticAlphabetTag, + PronunciationAlphabetToString(pronunciation->alphabet())); + boost::replace_all(phoneme_markup_string, kTextualStringTag, textual_string); + boost::replace_all(phoneme_markup_string, kVerbalStringTag, pronunciation->value()); + + return phoneme_markup_string; +} + +} // namespace odin +} // namespace valhalla diff --git a/src/odin/narrative_builder_factory.cc b/src/odin/narrative_builder_factory.cc index 76a5ca6f76..bf746345f7 100644 --- a/src/odin/narrative_builder_factory.cc +++ b/src/odin/narrative_builder_factory.cc @@ -1,6 +1,7 @@ #include "midgard/util.h" #include "odin/enhancedtrippath.h" +#include "odin/markup_formatter.h" #include "odin/narrative_builder_factory.h" #include "odin/narrativebuilder.h" #include "odin/util.h" @@ -10,8 +11,10 @@ namespace valhalla { namespace odin { -std::unique_ptr NarrativeBuilderFactory::Create(const Options& options, - const EnhancedTripLeg* trip_path) { +std::unique_ptr +NarrativeBuilderFactory::Create(const Options& options, + const EnhancedTripLeg* trip_path, + const MarkupFormatter& markup_formatter) { // Get the locale dictionary const auto phrase_dictionary = get_locales().find(options.language()); @@ -24,17 +27,22 @@ std::unique_ptr NarrativeBuilderFactory::Create(const Options& // if a NarrativeBuilder is derived with specific code for a particular // language then add logic here and return derived NarrativeBuilder if (phrase_dictionary->second->GetLanguageTag() == "cs-CZ") { - return std::make_unique(options, trip_path, *phrase_dictionary->second); + return std::make_unique(options, trip_path, *phrase_dictionary->second, + markup_formatter); } else if (phrase_dictionary->second->GetLanguageTag() == "hi-IN") { - return std::make_unique(options, trip_path, *phrase_dictionary->second); + return std::make_unique(options, trip_path, *phrase_dictionary->second, + markup_formatter); } else if (phrase_dictionary->second->GetLanguageTag() == "it-IT") { - return std::make_unique(options, trip_path, *phrase_dictionary->second); + return std::make_unique(options, trip_path, *phrase_dictionary->second, + markup_formatter); } else if (phrase_dictionary->second->GetLanguageTag() == "ru-RU") { - return std::make_unique(options, trip_path, *phrase_dictionary->second); + return std::make_unique(options, trip_path, *phrase_dictionary->second, + markup_formatter); } // otherwise just return pointer to NarrativeBuilder - return std::make_unique(options, trip_path, *phrase_dictionary->second); + return std::make_unique(options, trip_path, *phrase_dictionary->second, + markup_formatter); } } // namespace odin diff --git a/src/odin/narrativebuilder.cc b/src/odin/narrativebuilder.cc index 9cddc8f07f..65ceabc310 100644 --- a/src/odin/narrativebuilder.cc +++ b/src/odin/narrativebuilder.cc @@ -12,6 +12,7 @@ #include "odin/enhancedtrippath.h" #include "odin/maneuver.h" +#include "odin/markup_formatter.h" #include "odin/narrative_dictionary.h" #include "odin/narrativebuilder.h" #include "odin/util.h" @@ -42,9 +43,10 @@ namespace odin { NarrativeBuilder::NarrativeBuilder(const Options& options, const EnhancedTripLeg* trip_path, - const NarrativeDictionary& dictionary) + const NarrativeDictionary& dictionary, + const MarkupFormatter& markup_formatter) : options_(options), trip_path_(trip_path), dictionary_(dictionary), - articulated_preposition_enabled_(false) { + markup_formatter_(markup_formatter), articulated_preposition_enabled_(false) { } void NarrativeBuilder::Build(std::list& maneuvers) { @@ -974,14 +976,14 @@ std::string NarrativeBuilder::FormVerbalAlertContinueInstruction(Maneuver& maneu phrase_id = 3; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasJunctionNameSign()) { // Set the junction phrase - it takes priority over street names phrase_id = 2; // Assign guide sign junction_name = maneuver.signs().GetJunctionNameString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (!street_names.empty()) { phrase_id = 1; } @@ -1034,14 +1036,14 @@ std::string NarrativeBuilder::FormVerbalContinueInstruction(Maneuver& maneuver, phrase_id = 6; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasJunctionNameSign()) { // Set the junction phrase - it takes priority over street names phrase_id = 4; // Assign guide sign junction_name = maneuver.signs().GetJunctionNameString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (!street_names.empty()) { phrase_id = 2; } @@ -1224,14 +1226,14 @@ std::string NarrativeBuilder::FormVerbalTurnInstruction(Maneuver& maneuver, phrase_id = 5; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasJunctionNameSign()) { // Set the junction phrase - it takes priority over street names phrase_id = 4; // Assign guide sign junction_name = maneuver.signs().GetJunctionNameString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else { if (!street_names.empty()) { phrase_id = 1; @@ -1370,14 +1372,14 @@ std::string NarrativeBuilder::FormVerbalAlertUturnInstruction(Maneuver& maneuver phrase_id = 7; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasJunctionNameSign()) { // Set the junction phrase - it takes priority over street names phrase_id = 6; // Assign guide sign junction_name = maneuver.signs().GetJunctionNameString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else { if (!street_names.empty()) { phrase_id = 1; @@ -1432,14 +1434,14 @@ std::string NarrativeBuilder::FormVerbalUturnInstruction(Maneuver& maneuver, phrase_id = 7; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasJunctionNameSign()) { // Set the junction phrase - it takes priority over street names phrase_id = 6; // Assign guide sign junction_name = maneuver.signs().GetJunctionNameString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else { if (!street_names.empty()) { phrase_id += 1; @@ -1560,18 +1562,19 @@ std::string NarrativeBuilder::FormVerbalAlertRampStraightInstruction(Maneuver& m phrase_id = 1; exit_branch_sign = maneuver.signs().GetExitBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasExitTowardSign()) { phrase_id = 2; // Assign toward sign exit_toward_sign = maneuver.signs().GetExitTowardString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasExitNameSign()) { phrase_id = 4; // Assign name sign - exit_name_sign = maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, - delim, maneuver.verbal_formatter()); + exit_name_sign = + maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, delim, + maneuver.verbal_formatter(), &markup_formatter_); } return FormVerbalRampStraightInstruction(phrase_id, exit_branch_sign, exit_toward_sign, @@ -1598,20 +1601,21 @@ std::string NarrativeBuilder::FormVerbalRampStraightInstruction(Maneuver& maneuv // Assign branch sign exit_branch_sign = maneuver.signs().GetExitBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } if (maneuver.HasExitTowardSign()) { phrase_id += 2; // Assign toward sign exit_toward_sign = maneuver.signs().GetExitTowardString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } if (maneuver.HasExitNameSign() && !maneuver.HasExitBranchSign() && !maneuver.HasExitTowardSign()) { phrase_id += 4; // Assign name sign - exit_name_sign = maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, - delim, maneuver.verbal_formatter()); + exit_name_sign = + maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, delim, + maneuver.verbal_formatter(), &markup_formatter_); } return FormVerbalRampStraightInstruction(phrase_id, exit_branch_sign, exit_toward_sign, @@ -1762,18 +1766,19 @@ std::string NarrativeBuilder::FormVerbalAlertRampInstruction(Maneuver& maneuver, // Assign branch sign exit_branch_sign = maneuver.signs().GetExitBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasExitTowardSign()) { phrase_id += 2; // Assign toward sign exit_toward_sign = maneuver.signs().GetExitTowardString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasExitNameSign()) { phrase_id += 4; // Assign name sign - exit_name_sign = maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, - delim, maneuver.verbal_formatter()); + exit_name_sign = + maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, delim, + maneuver.verbal_formatter(), &markup_formatter_); } return FormVerbalRampInstruction(phrase_id, @@ -1826,20 +1831,21 @@ std::string NarrativeBuilder::FormVerbalRampInstruction(Maneuver& maneuver, // Assign branch sign exit_branch_sign = maneuver.signs().GetExitBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } if (maneuver.HasExitTowardSign()) { phrase_id += 2; // Assign toward sign exit_toward_sign = maneuver.signs().GetExitTowardString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } if (maneuver.HasExitNameSign() && !maneuver.HasExitBranchSign() && !maneuver.HasExitTowardSign()) { phrase_id += 4; // Assign name sign - exit_name_sign = maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, - delim, maneuver.verbal_formatter()); + exit_name_sign = + maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, delim, + maneuver.verbal_formatter(), &markup_formatter_); } return FormVerbalRampInstruction(phrase_id, @@ -1995,24 +2001,26 @@ std::string NarrativeBuilder::FormVerbalAlertExitInstruction(Maneuver& maneuver, phrase_id += 1; // Assign number sign exit_number_sign = - maneuver.signs().GetExitNumberString(0, false, delim, maneuver.verbal_formatter()); + maneuver.signs().GetExitNumberString(0, false, delim, maneuver.verbal_formatter(), + &markup_formatter_); } else if (maneuver.HasExitBranchSign()) { phrase_id += 2; // Assign branch sign exit_branch_sign = maneuver.signs().GetExitBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasExitTowardSign()) { phrase_id += 4; // Assign toward sign exit_toward_sign = maneuver.signs().GetExitTowardString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasExitNameSign()) { phrase_id += 8; // Assign name sign - exit_name_sign = maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, - delim, maneuver.verbal_formatter()); + exit_name_sign = + maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, delim, + maneuver.verbal_formatter(), &markup_formatter_); } return FormVerbalExitInstruction(phrase_id, @@ -2069,27 +2077,29 @@ std::string NarrativeBuilder::FormVerbalExitInstruction(Maneuver& maneuver, phrase_id += 1; // Assign number sign exit_number_sign = - maneuver.signs().GetExitNumberString(0, false, delim, maneuver.verbal_formatter()); + maneuver.signs().GetExitNumberString(0, false, delim, maneuver.verbal_formatter(), + &markup_formatter_); } if (maneuver.HasExitBranchSign()) { phrase_id += 2; // Assign branch sign exit_branch_sign = maneuver.signs().GetExitBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } if (maneuver.HasExitTowardSign()) { phrase_id += 4; // Assign toward sign exit_toward_sign = maneuver.signs().GetExitTowardString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } if (maneuver.HasExitNameSign() && !maneuver.HasExitNumberSign()) { phrase_id += 8; // Assign name sign - exit_name_sign = maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, - delim, maneuver.verbal_formatter()); + exit_name_sign = + maneuver.signs().GetExitNameString(element_max_count, limit_by_consecutive_count, delim, + maneuver.verbal_formatter(), &markup_formatter_); } return FormVerbalExitInstruction(phrase_id, @@ -2237,20 +2247,20 @@ std::string NarrativeBuilder::FormVerbalAlertKeepInstruction(Maneuver& maneuver, if (maneuver.HasGuideBranchSign()) { street_names = maneuver.signs().GetGuideBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } if (maneuver.HasGuideTowardSign()) { // Assign guide sign toward_sign = maneuver.signs().GetGuideTowardString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } } else { // For ramps with branch sign info - we use the sign info to match what users are seeing if (maneuver.ramp() && maneuver.HasExitBranchSign()) { street_names = maneuver.signs().GetExitBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else { // Assign the street names street_names = FormStreetNames(maneuver, maneuver.street_names(), @@ -2262,7 +2272,7 @@ std::string NarrativeBuilder::FormVerbalAlertKeepInstruction(Maneuver& maneuver, if (street_names.empty() && maneuver.HasExitBranchSign()) { street_names = maneuver.signs().GetExitBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } } @@ -2271,7 +2281,7 @@ std::string NarrativeBuilder::FormVerbalAlertKeepInstruction(Maneuver& maneuver, // Assign toward sign toward_sign = maneuver.signs().GetExitTowardString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } } @@ -2281,7 +2291,8 @@ std::string NarrativeBuilder::FormVerbalAlertKeepInstruction(Maneuver& maneuver, phrase_id += 1; // Assign number sign exit_number_sign = - maneuver.signs().GetExitNumberString(0, false, delim, maneuver.verbal_formatter()); + maneuver.signs().GetExitNumberString(0, false, delim, maneuver.verbal_formatter(), + &markup_formatter_); } else if (!street_names.empty()) { phrase_id += 2; } else if (!toward_sign.empty()) { @@ -2319,20 +2330,20 @@ std::string NarrativeBuilder::FormVerbalKeepInstruction(Maneuver& maneuver, if (maneuver.HasGuideBranchSign()) { street_names = maneuver.signs().GetGuideBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } if (maneuver.HasGuideTowardSign()) { // Assign guide sign toward_sign = maneuver.signs().GetGuideTowardString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } } else { // For ramps with branch sign info - we use the sign info to match what users are seeing if (maneuver.ramp() && maneuver.HasExitBranchSign()) { street_names = maneuver.signs().GetExitBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else { // Assign the street names street_names = FormStreetNames(maneuver, maneuver.street_names(), @@ -2344,7 +2355,7 @@ std::string NarrativeBuilder::FormVerbalKeepInstruction(Maneuver& maneuver, if (street_names.empty() && maneuver.HasExitBranchSign()) { street_names = maneuver.signs().GetExitBranchString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } } @@ -2353,7 +2364,7 @@ std::string NarrativeBuilder::FormVerbalKeepInstruction(Maneuver& maneuver, // Assign toward sign toward_sign = maneuver.signs().GetExitTowardString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } } @@ -2363,7 +2374,8 @@ std::string NarrativeBuilder::FormVerbalKeepInstruction(Maneuver& maneuver, phrase_id += 1; // Assign number sign exit_number_sign = - maneuver.signs().GetExitNumberString(0, false, delim, maneuver.verbal_formatter()); + maneuver.signs().GetExitNumberString(0, false, delim, maneuver.verbal_formatter(), + &markup_formatter_); } if (!street_names.empty()) { phrase_id += 2; @@ -2507,11 +2519,13 @@ std::string NarrativeBuilder::FormVerbalKeepToStayOnInstruction(Maneuver& maneuv std::string toward_sign; if (maneuver.HasGuideTowardSign()) { // Assign guide sign - toward_sign = maneuver.signs().GetGuideTowardString(element_max_count, limit_by_consecutive_count, - delim, maneuver.verbal_formatter()); + toward_sign = + maneuver.signs().GetGuideTowardString(element_max_count, limit_by_consecutive_count, delim, + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasExitTowardSign()) { - toward_sign = maneuver.signs().GetExitTowardString(element_max_count, limit_by_consecutive_count, - delim, maneuver.verbal_formatter()); + toward_sign = + maneuver.signs().GetExitTowardString(element_max_count, limit_by_consecutive_count, delim, + maneuver.verbal_formatter(), &markup_formatter_); } // Determine which phrase to use @@ -2521,7 +2535,8 @@ std::string NarrativeBuilder::FormVerbalKeepToStayOnInstruction(Maneuver& maneuv phrase_id += 1; // Assign number sign exit_number_sign = - maneuver.signs().GetExitNumberString(0, false, delim, maneuver.verbal_formatter()); + maneuver.signs().GetExitNumberString(0, false, delim, maneuver.verbal_formatter(), + &markup_formatter_); } if (!toward_sign.empty()) { phrase_id += 2; @@ -2663,7 +2678,7 @@ std::string NarrativeBuilder::FormVerbalMergeInstruction(Maneuver& maneuver, phrase_id = 4; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } // Check for merge relative direction @@ -2938,7 +2953,8 @@ std::string NarrativeBuilder::FormVerbalEnterRoundaboutInstruction(Maneuver& man // Assign guide sign guide_sign = maneuver.roundabout_exit_signs().GetGuideString(element_max_count, limit_by_consecutive_count, - delim, maneuver.verbal_formatter()); + delim, maneuver.verbal_formatter(), + &markup_formatter_); } else { if (!roundabout_exit_street_names.empty()) { // Increment for roundabout exit street name phrase @@ -3065,7 +3081,7 @@ std::string NarrativeBuilder::FormVerbalExitRoundaboutInstruction(Maneuver& mane phrase_id = 3; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else { if (!street_names.empty()) { // Increment for street name phrase @@ -3186,7 +3202,7 @@ std::string NarrativeBuilder::FormVerbalEnterFerryInstruction(Maneuver& maneuver phrase_id = 3; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (!street_names.empty()) { phrase_id = 1; if (!HasLabel(street_names, ferry_label)) { @@ -3926,14 +3942,14 @@ NarrativeBuilder::FormVerbalSuccinctTurnTransitionInstruction(Maneuver& maneuver phrase_id = 5; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasJunctionNameSign()) { // Set the junction phrase - it takes priority over street names phrase_id = 4; // Assign guide sign junction_name = maneuver.signs().GetJunctionNameString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } // Set instruction to the determined tagged phrase @@ -3973,14 +3989,14 @@ NarrativeBuilder::FormVerbalSuccinctUturnTransitionInstruction(Maneuver& maneuve phrase_id = 7; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } else if (maneuver.HasJunctionNameSign()) { // Set the junction phrase - it takes priority over street names phrase_id = 6; // Assign guide sign junction_name = maneuver.signs().GetJunctionNameString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } // Set instruction to the determined tagged phrase instruction = dictionary_.uturn_verbal_subset.phrases.at(std::to_string(phrase_id)); @@ -4021,7 +4037,7 @@ NarrativeBuilder::FormVerbalSuccinctMergeTransitionInstruction(Maneuver& maneuve phrase_id = 4; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } // Check for merge relative direction @@ -4078,7 +4094,8 @@ std::string NarrativeBuilder::FormVerbalSuccinctEnterRoundaboutTransitionInstruc // Assign guide sign guide_sign = maneuver.roundabout_exit_signs().GetGuideString(element_max_count, limit_by_consecutive_count, - delim, maneuver.verbal_formatter()); + delim, maneuver.verbal_formatter(), + &markup_formatter_); } // Set instruction to the determined tagged phrase @@ -4114,7 +4131,7 @@ std::string NarrativeBuilder::FormVerbalSuccinctExitRoundaboutTransitionInstruct phrase_id = 3; // Assign guide sign guide_sign = maneuver.signs().GetGuideString(element_max_count, limit_by_consecutive_count, delim, - maneuver.verbal_formatter()); + maneuver.verbal_formatter(), &markup_formatter_); } // Set instruction to the determined tagged phrase @@ -4436,9 +4453,12 @@ std::string NarrativeBuilder::FormStreetNames(const StreetNames& street_names, // Append next name to string street_names_string += - (verbal_formatter) ? verbal_formatter->Format(street_name->value()) : street_name->value(); + (verbal_formatter) + ? verbal_formatter->Format(street_name->value(), markup_formatter_.Format(street_name)) + : street_name->value(); ++count; } + return street_names_string; } @@ -4498,12 +4518,12 @@ void NarrativeBuilder::FormVerbalMultiCue(std::list& maneuvers) { // Set verbal succinct transition instruction as a verbal multi-cue if (prev_maneuver->HasVerbalSuccinctTransitionInstruction()) { prev_maneuver->set_verbal_succinct_transition_instruction( - FormVerbalMultiCue(prev_maneuver, maneuver, true)); + FormVerbalMultiCue(*prev_maneuver, maneuver, true)); } // Set verbal pre transition instruction as a verbal multi-cue prev_maneuver->set_verbal_pre_transition_instruction( - FormVerbalMultiCue(prev_maneuver, maneuver)); + FormVerbalMultiCue(*prev_maneuver, maneuver)); } // Update previous maneuver @@ -4511,38 +4531,44 @@ void NarrativeBuilder::FormVerbalMultiCue(std::list& maneuvers) { } } -std::string NarrativeBuilder::FormVerbalMultiCue(Maneuver* maneuver, +std::string NarrativeBuilder::FormVerbalMultiCue(Maneuver& maneuver, Maneuver& next_maneuver, bool process_succinct) { - // "0": " Then " - // "1": " Then, in , " - - std::string instruction; - instruction.reserve(kInstructionInitialCapacity); - // Set current verbal cue const std::string& current_verbal_cue = - ((process_succinct && maneuver->HasVerbalSuccinctTransitionInstruction()) - ? maneuver->verbal_succinct_transition_instruction() - : maneuver->verbal_pre_transition_instruction()); + ((process_succinct && maneuver.HasVerbalSuccinctTransitionInstruction()) + ? maneuver.verbal_succinct_transition_instruction() + : maneuver.verbal_pre_transition_instruction()); // Set next verbal cue std::string next_verbal_cue = next_maneuver.HasVerbalTransitionAlertInstruction() ? next_maneuver.verbal_transition_alert_instruction() : next_maneuver.verbal_pre_transition_instruction(); + return FormVerbalMultiCue(maneuver, current_verbal_cue, next_verbal_cue); +} + +std::string NarrativeBuilder::FormVerbalMultiCue(Maneuver& maneuver, + const std::string& first_verbal_cue, + const std::string& second_verbal_cue) { + // "0": " Then " + // "1": " Then, in , " + + std::string instruction; + instruction.reserve(kInstructionInitialCapacity); + // Set instruction to the proper verbal multi-cue uint8_t phrase_id = 0; - if (maneuver->distant_verbal_multi_cue()) { + if (maneuver.distant_verbal_multi_cue()) { phrase_id = 1; } instruction = dictionary_.verbal_multi_cue_subset.phrases.at(std::to_string(phrase_id)); // Replace phrase tags with values - boost::replace_all(instruction, kCurrentVerbalCueTag, current_verbal_cue); - boost::replace_all(instruction, kNextVerbalCueTag, next_verbal_cue); + boost::replace_all(instruction, kCurrentVerbalCueTag, first_verbal_cue); + boost::replace_all(instruction, kNextVerbalCueTag, second_verbal_cue); boost::replace_all(instruction, kLengthTag, - FormLength(*maneuver, dictionary_.post_transition_verbal_subset.metric_lengths, + FormLength(maneuver, dictionary_.post_transition_verbal_subset.metric_lengths, dictionary_.post_transition_verbal_subset.us_customary_lengths)); // If enabled, form articulated prepositions diff --git a/src/odin/sign.cc b/src/odin/sign.cc index 76dc30997f..434414c835 100644 --- a/src/odin/sign.cc +++ b/src/odin/sign.cc @@ -1,3 +1,5 @@ +#include "baldr/pronunciation.h" + #include "odin/sign.h" #include "odin/util.h" @@ -5,8 +7,11 @@ namespace valhalla { namespace odin { // Constructor -Sign::Sign(const std::string& text, const bool is_route_number) - : text_(text), is_route_number_(is_route_number), consecutive_count_(0) { +Sign::Sign(const std::string& text, + const bool is_route_number, + const boost::optional& pronunciation) + : text_(text), is_route_number_(is_route_number), consecutive_count_(0), + pronunciation_(pronunciation) { } const std::string& Sign::text() const { @@ -25,6 +30,10 @@ void Sign::set_consecutive_count(uint32_t consecutive_count) { consecutive_count_ = consecutive_count; } +const boost::optional& Sign::pronunciation() const { + return pronunciation_; +} + #ifdef LOGGING_LEVEL_TRACE std::string Sign::ToParameterString() const { const std::string delim = ", "; diff --git a/src/odin/signs.cc b/src/odin/signs.cc index 99e817e9be..60bd0d4810 100644 --- a/src/odin/signs.cc +++ b/src/odin/signs.cc @@ -53,9 +53,10 @@ std::vector* Signs::mutable_exit_number_list() { std::string Signs::GetExitNumberString(uint32_t max_count, bool limit_by_consecutive_count, const std::string& delim, - const VerbalTextFormatter* verbal_formatter) const { + const VerbalTextFormatter* verbal_formatter, + const MarkupFormatter* markup_formatter) const { return ListToString(exit_number_list_, max_count, limit_by_consecutive_count, delim, - verbal_formatter); + verbal_formatter, markup_formatter); } const std::vector& Signs::exit_branch_list() const { @@ -69,9 +70,10 @@ std::vector* Signs::mutable_exit_branch_list() { std::string Signs::GetExitBranchString(uint32_t max_count, bool limit_by_consecutive_count, const std::string& delim, - const VerbalTextFormatter* verbal_formatter) const { + const VerbalTextFormatter* verbal_formatter, + const MarkupFormatter* markup_formatter) const { return ListToString(exit_branch_list_, max_count, limit_by_consecutive_count, delim, - verbal_formatter); + verbal_formatter, markup_formatter); } const std::vector& Signs::exit_toward_list() const { @@ -85,9 +87,10 @@ std::vector* Signs::mutable_exit_toward_list() { std::string Signs::GetExitTowardString(uint32_t max_count, bool limit_by_consecutive_count, const std::string& delim, - const VerbalTextFormatter* verbal_formatter) const { + const VerbalTextFormatter* verbal_formatter, + const MarkupFormatter* markup_formatter) const { return ListToString(exit_toward_list_, max_count, limit_by_consecutive_count, delim, - verbal_formatter); + verbal_formatter, markup_formatter); } const std::vector& Signs::exit_name_list() const { @@ -101,9 +104,10 @@ std::vector* Signs::mutable_exit_name_list() { std::string Signs::GetExitNameString(uint32_t max_count, bool limit_by_consecutive_count, const std::string& delim, - const VerbalTextFormatter* verbal_formatter) const { - return ListToString(exit_name_list_, max_count, limit_by_consecutive_count, delim, - verbal_formatter); + const VerbalTextFormatter* verbal_formatter, + const MarkupFormatter* markup_formatter) const { + return ListToString(exit_name_list_, max_count, limit_by_consecutive_count, delim, verbal_formatter, + markup_formatter); } const std::vector& Signs::guide_branch_list() const { @@ -117,9 +121,10 @@ std::vector* Signs::mutable_guide_branch_list() { std::string Signs::GetGuideBranchString(uint32_t max_count, bool limit_by_consecutive_count, const std::string& delim, - const VerbalTextFormatter* verbal_formatter) const { + const VerbalTextFormatter* verbal_formatter, + const MarkupFormatter* markup_formatter) const { return ListToString(guide_branch_list_, max_count, limit_by_consecutive_count, delim, - verbal_formatter); + verbal_formatter, markup_formatter); } const std::vector& Signs::guide_toward_list() const { @@ -133,9 +138,10 @@ std::vector* Signs::mutable_guide_toward_list() { std::string Signs::GetGuideTowardString(uint32_t max_count, bool limit_by_consecutive_count, const std::string& delim, - const VerbalTextFormatter* verbal_formatter) const { + const VerbalTextFormatter* verbal_formatter, + const MarkupFormatter* markup_formatter) const { return ListToString(guide_toward_list_, max_count, limit_by_consecutive_count, delim, - verbal_formatter); + verbal_formatter, markup_formatter); } /* NOTE: This is functionally similar to GetGuideString() except that it @@ -178,7 +184,8 @@ std::vector Signs::GetGuideSigns(uint32_t max_count, bool limit_by_consecu std::string Signs::GetGuideString(uint32_t max_count, bool limit_by_consecutive_count, const std::string& delim, - const VerbalTextFormatter* verbal_formatter) const { + const VerbalTextFormatter* verbal_formatter, + const MarkupFormatter* markup_formatter) const { std::string guide_string; // If both branch and toward exist // and either unlimited max count or max count is greater than 1 @@ -188,18 +195,18 @@ std::string Signs::GetGuideString(uint32_t max_count, std::string guide_branch = GetGuideBranchString(static_cast( std::round(static_cast(max_count) / kNumberOfGuideSignTypes)), - limit_by_consecutive_count, delim, verbal_formatter); + limit_by_consecutive_count, delim, verbal_formatter, markup_formatter); // Truncate using integer division std::string guide_toward = GetGuideTowardString((max_count / kNumberOfGuideSignTypes), limit_by_consecutive_count, delim, - verbal_formatter); + verbal_formatter, markup_formatter); guide_string = guide_branch + delim + guide_toward; } else if (HasGuideBranch()) { - guide_string = - GetGuideBranchString(max_count, limit_by_consecutive_count, delim, verbal_formatter); + guide_string = GetGuideBranchString(max_count, limit_by_consecutive_count, delim, + verbal_formatter, markup_formatter); } else if (HasGuideToward()) { - guide_string = - GetGuideTowardString(max_count, limit_by_consecutive_count, delim, verbal_formatter); + guide_string = GetGuideTowardString(max_count, limit_by_consecutive_count, delim, + verbal_formatter, markup_formatter); } return guide_string; } @@ -215,9 +222,10 @@ std::vector* Signs::mutable_junction_name_list() { std::string Signs::GetJunctionNameString(uint32_t max_count, bool limit_by_consecutive_count, const std::string& delim, - const VerbalTextFormatter* verbal_formatter) const { + const VerbalTextFormatter* verbal_formatter, + const MarkupFormatter* markup_formatter) const { return ListToString(junction_name_list_, max_count, limit_by_consecutive_count, delim, - verbal_formatter); + verbal_formatter, markup_formatter); } bool Signs::HasExit() const { @@ -357,7 +365,8 @@ std::string Signs::ListToString(const std::vector& signs, uint32_t max_count, bool limit_by_consecutive_count, const std::string& delim, - const VerbalTextFormatter* verbal_formatter) const { + const VerbalTextFormatter* verbal_formatter, + const MarkupFormatter* markup_formatter) const { std::string sign_string; uint32_t count = 0; uint32_t consecutive_count = -1; @@ -389,7 +398,11 @@ std::string Signs::ListToString(const std::vector& signs, } // Concatenate exit text and update count - sign_string += (verbal_formatter) ? verbal_formatter->Format(sign.text()) : sign.text(); + sign_string += (verbal_formatter) + ? verbal_formatter->Format(sign.text(), + ((markup_formatter) ? markup_formatter->Format(sign) + : boost::none)) + : sign.text(); ++count; } diff --git a/src/odin/worker.cc b/src/odin/worker.cc index 42336751f9..59615987c3 100644 --- a/src/odin/worker.cc +++ b/src/odin/worker.cc @@ -27,7 +27,8 @@ using namespace valhalla::baldr; namespace valhalla { namespace odin { -odin_worker_t::odin_worker_t(const boost::property_tree::ptree& config) : service_worker_t(config) { +odin_worker_t::odin_worker_t(const boost::property_tree::ptree& config) + : service_worker_t(config), markup_formatter_(config) { // signal that the worker started successfully started(); } @@ -41,7 +42,7 @@ std::string odin_worker_t::narrate(Api& request) const { // get some annotated directions try { - odin::DirectionsBuilder().Build(request); + odin::DirectionsBuilder().Build(request, markup_formatter_); } catch (...) { throw valhalla_exception_t{202}; } // serialize those to the proper format diff --git a/src/thor/triplegbuilder.cc b/src/thor/triplegbuilder.cc index 1971c44605..4efce6d8eb 100644 --- a/src/thor/triplegbuilder.cc +++ b/src/thor/triplegbuilder.cc @@ -478,84 +478,97 @@ void SetHeadings(TripLeg_Edge* trip_edge, } } +// Populate the specified sign element with the specified sign attributes including pronunciation +// attributes if they exist +void PopulateSignElement( + uint32_t sign_index, + const SignInfo& sign, + const std::unordered_map>& pronunciations, + valhalla::TripSignElement* sign_element) { + sign_element->set_text(sign.text()); + sign_element->set_is_route_number(sign.is_route_num()); + + // Assign pronunciation alphabet and value if they exist + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + if (iter != pronunciations.end()) { + auto* pronunciation = sign_element->mutable_pronunciation(); + pronunciation->set_alphabet(GetTripPronunciationAlphabet( + static_cast((iter->second).first))); + pronunciation->set_value((iter->second).second); + } +} + // Walk the edge_signs, add sign information onto the trip_sign, honoring which to // add per the attributes-controller. void AddSignInfo(const AttributesController& controller, const std::vector& edge_signs, + const std::unordered_map>& pronunciations, valhalla::TripSign* trip_sign) { if (!edge_signs.empty()) { + uint32_t sign_index = 0; for (const auto& sign : edge_signs) { switch (sign.type()) { case valhalla::baldr::Sign::Type::kExitNumber: { if (controller.attributes.at(kEdgeSignExitNumber)) { - auto* trip_sign_exit_number = trip_sign->mutable_exit_numbers()->Add(); - trip_sign_exit_number->set_text(sign.text()); - trip_sign_exit_number->set_is_route_number(sign.is_route_num()); + PopulateSignElement(sign_index, sign, pronunciations, + trip_sign->mutable_exit_numbers()->Add()); } break; } case valhalla::baldr::Sign::Type::kExitBranch: { if (controller.attributes.at(kEdgeSignExitBranch)) { - auto* trip_sign_exit_onto_street = trip_sign->mutable_exit_onto_streets()->Add(); - trip_sign_exit_onto_street->set_text(sign.text()); - trip_sign_exit_onto_street->set_is_route_number(sign.is_route_num()); + PopulateSignElement(sign_index, sign, pronunciations, + trip_sign->mutable_exit_onto_streets()->Add()); } break; } case valhalla::baldr::Sign::Type::kExitToward: { if (controller.attributes.at(kEdgeSignExitToward)) { - auto* trip_sign_exit_toward_location = trip_sign->mutable_exit_toward_locations()->Add(); - trip_sign_exit_toward_location->set_text(sign.text()); - trip_sign_exit_toward_location->set_is_route_number(sign.is_route_num()); + PopulateSignElement(sign_index, sign, pronunciations, + trip_sign->mutable_exit_toward_locations()->Add()); } break; } case valhalla::baldr::Sign::Type::kExitName: { if (controller.attributes.at(kEdgeSignExitName)) { - auto* trip_sign_exit_name = trip_sign->mutable_exit_names()->Add(); - trip_sign_exit_name->set_text(sign.text()); - trip_sign_exit_name->set_is_route_number(sign.is_route_num()); + PopulateSignElement(sign_index, sign, pronunciations, + trip_sign->mutable_exit_names()->Add()); } break; } case valhalla::baldr::Sign::Type::kGuideBranch: { if (controller.attributes.at(kEdgeSignGuideBranch)) { - auto* trip_sign_guide_onto_street = trip_sign->mutable_guide_onto_streets()->Add(); - trip_sign_guide_onto_street->set_text(sign.text()); - trip_sign_guide_onto_street->set_is_route_number(sign.is_route_num()); + PopulateSignElement(sign_index, sign, pronunciations, + trip_sign->mutable_guide_onto_streets()->Add()); } break; } case valhalla::baldr::Sign::Type::kGuideToward: { if (controller.attributes.at(kEdgeSignGuideToward)) { - auto* trip_sign_guide_toward_location = - trip_sign->mutable_guide_toward_locations()->Add(); - trip_sign_guide_toward_location->set_text(sign.text()); - trip_sign_guide_toward_location->set_is_route_number(sign.is_route_num()); + PopulateSignElement(sign_index, sign, pronunciations, + trip_sign->mutable_guide_toward_locations()->Add()); } break; } case valhalla::baldr::Sign::Type::kGuidanceViewJunction: { if (controller.attributes.at(kEdgeSignGuidanceViewJunction)) { - auto* trip_sign_guidance_view_junction = - trip_sign->mutable_guidance_view_junctions()->Add(); - trip_sign_guidance_view_junction->set_text(sign.text()); - trip_sign_guidance_view_junction->set_is_route_number(sign.is_route_num()); + PopulateSignElement(sign_index, sign, pronunciations, + trip_sign->mutable_guidance_view_junctions()->Add()); } break; } case valhalla::baldr::Sign::Type::kGuidanceViewSignboard: { if (controller.attributes.at(kEdgeSignGuidanceViewSignboard)) { - auto* trip_sign_guidance_view_signboard = - trip_sign->mutable_guidance_view_signboards()->Add(); - trip_sign_guidance_view_signboard->set_text(sign.text()); - trip_sign_guidance_view_signboard->set_is_route_number(sign.is_route_num()); + PopulateSignElement(sign_index, sign, pronunciations, + trip_sign->mutable_guidance_view_signboards()->Add()); } break; } default: { break; } } + ++sign_index; } } } @@ -652,11 +665,12 @@ void AddTripIntersectingEdge(const AttributesController& controller, // Set the sign info for the intersecting edge if requested if (controller.attributes.at(kNodeIntersectingEdgeSignInfo)) { if (intersecting_de->sign()) { + std::unordered_map> pronunciations; std::vector edge_signs = - graphtile->GetSigns(intersecting_de - graphtile->directededge(0)); + graphtile->GetSigns(intersecting_de - graphtile->directededge(0), pronunciations); if (!edge_signs.empty()) { valhalla::TripSign* sign = intersecting_edge->mutable_sign(); - AddSignInfo(controller, edge_signs, sign); + AddSignInfo(controller, edge_signs, pronunciations, sign); } } } @@ -799,12 +813,35 @@ TripLeg_Edge* AddTripEdge(const AttributesController& controller, // Add names to edge if requested if (controller.attributes.at(kEdgeNames)) { - auto names_and_types = edgeinfo.GetNamesAndTypes(); + std::vector types; + auto names_and_types = edgeinfo.GetNamesAndTypes(types, true); trip_edge->mutable_name()->Reserve(names_and_types.size()); + std::unordered_map> pronunciations = + edgeinfo.GetPronunciationsMap(); + uint8_t name_index = 0; for (const auto& name_and_type : names_and_types) { + if (types.at(name_index) != 0) { + // Skip the tagged names + name_index++; + continue; + } + auto* trip_edge_name = trip_edge->mutable_name()->Add(); + // Assign name and type trip_edge_name->set_value(name_and_type.first); trip_edge_name->set_is_route_number(name_and_type.second); + std::unordered_map>::const_iterator iter = + pronunciations.find(name_index); + + // Assign pronunciation alphabet and value if one exists + if (iter != pronunciations.end()) { + auto* pronunciation = trip_edge_name->mutable_pronunciation(); + pronunciation->set_alphabet(GetTripPronunciationAlphabet( + static_cast((iter->second).first))); + pronunciation->set_value((iter->second).second); + } + + name_index++; } } @@ -827,32 +864,35 @@ TripLeg_Edge* AddTripEdge(const AttributesController& controller, // Set the signs (if the directed edge has sign information) and if requested if (directededge->sign()) { // Add the edge signs - std::vector edge_signs = graphtile->GetSigns(idx); + std::unordered_map> pronunciations; + std::vector edge_signs = graphtile->GetSigns(idx, pronunciations); if (!edge_signs.empty()) { valhalla::TripSign* sign = trip_edge->mutable_sign(); - AddSignInfo(controller, edge_signs, sign); + AddSignInfo(controller, edge_signs, pronunciations, sign); } } // Process the named junctions at nodes if (has_junction_name && start_tile) { // Add the node signs - std::vector node_signs = start_tile->GetSigns(start_node_idx, true); + std::unordered_map> pronunciations; + std::vector node_signs = start_tile->GetSigns(start_node_idx, pronunciations, true); if (!node_signs.empty()) { valhalla::TripSign* trip_sign = trip_edge->mutable_sign(); + uint32_t sign_index = 0; for (const auto& sign : node_signs) { switch (sign.type()) { case valhalla::baldr::Sign::Type::kJunctionName: { if (controller.attributes.at(kEdgeSignJunctionName)) { - auto* trip_sign_junction_name = trip_sign->mutable_junction_names()->Add(); - trip_sign_junction_name->set_text(sign.text()); - trip_sign_junction_name->set_is_route_number(sign.is_route_num()); + PopulateSignElement(sign_index, sign, pronunciations, + trip_sign->mutable_junction_names()->Add()); } break; } default: break; } + ++sign_index; } } } diff --git a/src/tyr/route_serializer_osrm.cc b/src/tyr/route_serializer_osrm.cc index cddd4bc989..0b523d851b 100644 --- a/src/tyr/route_serializer_osrm.cc +++ b/src/tyr/route_serializer_osrm.cc @@ -1249,18 +1249,23 @@ std::string get_mode(const valhalla::DirectionsLeg::Maneuver& maneuver, " Unhandled travel_mode: " + std::to_string(num)); } +const ::google::protobuf::RepeatedPtrField<::valhalla::StreetName>& +get_maneuver_street_names(const valhalla::DirectionsLeg::Maneuver& maneuver) { + // Roundabouts need to use the roundabout_exit_street_names + // if a maneuver begin street name exists then use it otherwise use the maneuver street name + // TODO: in the future we may switch to use both + return ((maneuver.type() == DirectionsLeg_Maneuver_Type_kRoundaboutEnter) + ? maneuver.roundabout_exit_street_names() + : (maneuver.begin_street_name_size() > 0) ? maneuver.begin_street_name() + : maneuver.street_name()); +} + // Get the names and ref names std::pair names_and_refs(const valhalla::DirectionsLeg::Maneuver& maneuver) { std::string names, refs; - // Roundabouts need to use the roundabout_exit_street_names - // if a maneuver begin street name exists then use it otherwise use the maneuver street name - // TODO: in the future we may switch to use both - auto& street_names = (maneuver.type() == DirectionsLeg_Maneuver_Type_kRoundaboutEnter) - ? maneuver.roundabout_exit_street_names() - : (maneuver.begin_street_name_size() > 0) ? maneuver.begin_street_name() - : maneuver.street_name(); + const auto& street_names = get_maneuver_street_names(maneuver); for (const auto& name : street_names) { // Check if the name is a ref @@ -1279,6 +1284,23 @@ names_and_refs(const valhalla::DirectionsLeg::Maneuver& maneuver) { return std::make_pair(names, refs); } +// Get the pronunciations string +std::string get_pronunciations(const valhalla::DirectionsLeg::Maneuver& maneuver) { + std::string pronunciations; + + const auto& street_names = get_maneuver_street_names(maneuver); + + for (const auto& name : street_names) { + if (name.has_pronunciation()) { + if (!pronunciations.empty()) { + pronunciations += "; "; + } + pronunciations += name.pronunciation().value(); + } + } + + return pronunciations; +} // Serialize each leg json::ArrayPtr serialize_legs(const google::protobuf::RepeatedPtrField& legs, @@ -1314,6 +1336,7 @@ json::ArrayPtr serialize_legs(const google::protobuf::RepeatedPtrFieldemplace("ref", ref); } + if (!pronunciation.empty()) { + step->emplace("pronunciation", pronunciation); + } // Check if speed limits were requested if (path_leg.shape_attributes().speed_limit_size() > 0) { diff --git a/src/valhalla_run_route.cc b/src/valhalla_run_route.cc index 08dd51f9b9..4a8d94f425 100644 --- a/src/valhalla_run_route.cc +++ b/src/valhalla_run_route.cc @@ -363,12 +363,13 @@ valhalla::DirectionsLeg DirectionsTest(valhalla::Api& api, valhalla::Location& orig, valhalla::Location& dest, PathStatistics& data, - bool verbose_lanes) { + bool verbose_lanes, + valhalla::odin::MarkupFormatter& markup_formatter) { // TEMPORARY? Change to PathLocation... const PathLocation& origin = PathLocation::fromPBF(orig); const PathLocation& destination = PathLocation::fromPBF(dest); - DirectionsBuilder::Build(api); + DirectionsBuilder::Build(api, markup_formatter); const auto& trip_directions = api.directions().routes(0).legs(0); EnhancedTripLeg etl(*api.mutable_trip()->mutable_routes(0)->mutable_legs(0)); std::string units = (api.options().units() == valhalla::Options::kilometers ? "km" : "mi"); @@ -670,6 +671,7 @@ int main(int argc, char* argv[]) { MultiModalPathAlgorithm mm(pt.get_child("thor")); TimeDepForward timedep_forward(pt.get_child("thor")); TimeDepReverse timedep_reverse(pt.get_child("thor")); + MarkupFormatter markup_formatter(pt); for (uint32_t i = 0; i < n; i++) { // Set origin and destination for this segment valhalla::Location origin = options.locations(i); @@ -736,7 +738,8 @@ int main(int argc, char* argv[]) { // Try the the directions auto t1 = std::chrono::high_resolution_clock::now(); - const auto& trip_directions = DirectionsTest(request, origin, dest, data, verbose_lanes); + const auto& trip_directions = + DirectionsTest(request, origin, dest, data, verbose_lanes, markup_formatter); auto t2 = std::chrono::high_resolution_clock::now(); auto msecs = std::chrono::duration_cast(t2 - t1).count(); diff --git a/taginfo.json b/taginfo.json index 3a35c2e6cf..739befb39a 100644 --- a/taginfo.json +++ b/taginfo.json @@ -268,6 +268,13 @@ ], "description": "Alternative name for the way, frequently used when a street has another official or locally preferred name" }, + { + "key": "alt_name:pronunciation", + "object_types": [ + "way" + ], + "description": "This tag contains a phonetic guide to pronouncing the alternative name for the way, frequently used when a street has another official or locally preferred name" + }, { "key": "area", "value": "yes", @@ -1568,6 +1575,13 @@ "way" ] }, + { + "key": "destination:pronunciation", + "description": "This tag contains a phonetic guide to pronouncing the toward location. Used for exit information, see: https://wiki.openstreetmap.org/wiki/Exit_Info", + "object_types": [ + "way" + ] + }, { "description": "Adds sinage information to the given edge in the graph which is helpful to know to where a given road leads. Forward and backward allow for distinct values based on the direction the way is drawn specifically useful for single carriageways.", "key": "destination:backward", @@ -1575,6 +1589,13 @@ "way" ] }, + { + "description": "This tag contains a phonetic guide to pronouncing the sinage information to the given edge in the graph which is helpful to know to where a given road leads. Forward and backward allow for distinct values based on the direction the way is drawn specifically useful for single carriageways.", + "key": "destination:backward:pronunciation", + "object_types": [ + "way" + ] + }, { "description": "Adds sinage information to the given edge in the graph which is helpful to know to where a given road leads. Forward and backward allow for distinct values based on the direction the way is drawn specifically useful for single carriageways.", "key": "destination:forward", @@ -1582,6 +1603,13 @@ "way" ] }, + { + "description": "This tag contains a phonetic guide to pronouncing the sinage information to the given edge in the graph which is helpful to know to where a given road leads. Forward and backward allow for distinct values based on the direction the way is drawn specifically useful for single carriageways.", + "key": "destination:forward:pronunciation", + "object_types": [ + "way" + ] + }, { "key": "destination:ref", "description": "Branch route number for sinage ie. exit information, see: https://wiki.openstreetmap.org/wiki/Exit_Info", @@ -1589,6 +1617,13 @@ "way" ] }, + { + "key": "destination:ref:pronunciation", + "description": "This tag contains a phonetic guide to pronouncing the branch route number for sinage ie. exit information, see: https://wiki.openstreetmap.org/wiki/Exit_Info", + "object_types": [ + "way" + ] + }, { "key": "destination:ref:to", "description": "Toward route number for sinage ie. exit information, see: https://wiki.openstreetmap.org/wiki/Exit_Info", @@ -1596,6 +1631,13 @@ "way" ] }, + { + "key": "destination:ref:to:pronunciation", + "description": "This tag contains a phonetic guide to pronouncing the toward route number for sinage ie. exit information, see: https://wiki.openstreetmap.org/wiki/Exit_Info", + "object_types": [ + "way" + ] + }, { "key": "destination:street", "description": "Branch road name for sinage ie. exit information, see: https://wiki.openstreetmap.org/wiki/Exit_Info", @@ -1603,6 +1645,13 @@ "way" ] }, + { + "key": "destination:street:pronunciation", + "description": "This tag contains a phonetic guide to pronouncing the branch road name for sinage ie. exit information, see: https://wiki.openstreetmap.org/wiki/Exit_Info", + "object_types": [ + "way" + ] + }, { "key": "destination:street:to", "description": "Toward road name for sinage ie. exit information, see: https://wiki.openstreetmap.org/wiki/Exit_Info", @@ -1610,6 +1659,13 @@ "way" ] }, + { + "key": "destination:street:to:pronunciation", + "description": "This tag contains a phonetic guide to pronouncing the toward road name for sinage ie. exit information, see: https://wiki.openstreetmap.org/wiki/Exit_Info", + "object_types": [ + "way" + ] + }, { "key": "emergency", "value": "yes", @@ -2809,7 +2865,14 @@ "object_types": [ "way" ], - "description": "International Route network and number." + "description": "International route network and number." + }, + { + "key": "int_ref:pronunciation", + "object_types": [ + "way" + ], + "description": "This tag contains a phonetic guide to pronouncing the international route network and number." }, { "key": "junction", @@ -2834,6 +2897,13 @@ "way" ] }, + { + "key": "junction:ref:pronunciation", + "description": "This tag contains a phonetic guide to pronouncing the junction/exit number for sinage ie. exit information, see: https://wiki.openstreetmap.org/wiki/Exit_Info", + "object_types": [ + "way" + ] + }, { "key": "lanes", "description": "Lane count", @@ -4121,6 +4191,29 @@ ], "description": "The name of the feature, street names, river names, POI names etc." }, + { + "key": "name:pronunciation", + "object_types": [ + "node", + "way" + ], + "description": "This tag contains a phonetic guide to pronouncing the name of the feature, street names, river names, POI names etc." + }, + { + "key": "tunnel:name", + "object_types": [ + "way" + ], + "description": "The tunnel name of the way." + }, + { + "key": "tunnel:name:pronunciation", + "object_types": [ + "node", + "way" + ], + "description": "This tag contains a phonetic guide to pronouncing the tunnel name of the way." + }, { "key": "name:en", "object_types": [ @@ -4129,6 +4222,13 @@ ], "description": "The english name of the feature" }, + { + "key": "name:en:pronunciation", + "object_types": [ + "way" + ], + "description": "This tag contains a phonetic guide to pronouncing the english name of the feature" + }, { "key": "ncn", "value": "yes", @@ -4189,6 +4289,13 @@ ], "description": "Official name for a country used in that country if it differs from what is in the name tag" }, + { + "key": "official_name:pronunciation", + "object_types": [ + "way" + ], + "description": "This tag contains a phonetic guide to pronouncing the official name for a country used in that country if it differs from what is in the name tag" + }, { "key": "access", "value": "conditional", @@ -4874,6 +4981,14 @@ ], "description": "Route network and number. Junction/exit number, see: https://wiki.openstreetmap.org/wiki/Exit_Info" }, + { + "key": "ref:pronunciation", + "object_types": [ + "node", + "way" + ], + "description": "This tag contains a phonetic guide to pronouncing the junction/exit number, see: https://wiki.openstreetmap.org/wiki/Exit_Info" + }, { "key": "restriction", "value": "no_left_turn", diff --git a/test/countryaccess.cc b/test/countryaccess.cc index d33fc0c39b..de12565617 100644 --- a/test/countryaccess.cc +++ b/test/countryaccess.cc @@ -92,14 +92,16 @@ void CountryAccess(const std::string& config_file) { std::string nodes_file = "test_nodes_amsterdam.bin"; std::string edges_file = "test_edges_amsterdam.bin"; std::string access_file = "test_access_amsterdam.bin"; + std::string pronunciation_file = "test_pronunciation_amsterdam.bin"; std::string cr_from_file = "test_from_cr_amsterdam.bin"; std::string cr_to_file = "test_to_cr_amsterdam.bin"; std::string bss_nodes_file = "test_bss_nodes_amsterdam.bin"; // Parse Amsterdam OSM data - auto osmdata = PBFGraphParser::ParseWays(conf.get_child("mjolnir"), - {VALHALLA_SOURCE_DIR "test/data/amsterdam.osm.pbf"}, - ways_file, way_nodes_file, access_file); + auto osmdata = + PBFGraphParser::ParseWays(conf.get_child("mjolnir"), + {VALHALLA_SOURCE_DIR "test/data/amsterdam.osm.pbf"}, ways_file, + way_nodes_file, access_file, pronunciation_file); PBFGraphParser::ParseRelations(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/amsterdam.osm.pbf"}, cr_from_file, @@ -115,7 +117,7 @@ void CountryAccess(const std::string& config_file) { // Build the graph using the OSMNodes and OSMWays from the parser GraphBuilder::Build(conf, osmdata, ways_file, way_nodes_file, nodes_file, edges_file, cr_from_file, - cr_to_file, tiles); + cr_to_file, pronunciation_file, tiles); // load a tile and test the default access. GraphId id(820099, 2, 0); diff --git a/test/data/netherlands_admin.sqlite b/test/data/netherlands_admin.sqlite index 7ecd9dd6f9..70e2f02a46 100644 Binary files a/test/data/netherlands_admin.sqlite and b/test/data/netherlands_admin.sqlite differ diff --git a/test/graphbuilder.cc b/test/graphbuilder.cc index 61367de97e..64957ffe05 100644 --- a/test/graphbuilder.cc +++ b/test/graphbuilder.cc @@ -37,6 +37,7 @@ const std::string tile_dir = "test/data/graphbuilder_tiles"; const size_t id_table_size = 1000; const std::string access_file = "test_access_harrisburg.bin"; +const std::string pronunciation_file = "test_pronunciation_harrisburg.bin"; const std::string bss_file = "test_bss_nodes_harrisburg.bin"; const std::string edges_file = "test_edges_harrisburg.bin"; const std::string from_restriction_file = "test_from_complex_restrictions_harrisburg.bin"; @@ -63,7 +64,7 @@ TEST(GraphBuilder, TestConstructEdges) { // This directory should be empty filesystem::remove_all(tile_dir); GraphBuilder::Build(config, osm_data, ways_file, way_nodes_file, nodes_file, edges_file, - from_restriction_file, to_restriction_file, tiles); + from_restriction_file, to_restriction_file, pronunciation_file, tiles); GraphReader reader(config.get_child("mjolnir")); EXPECT_EQ(reader.GetTileSet(2).size(), 4); // Clear the tile directory so it doesn't interfere with the next test with graphreader. @@ -85,7 +86,7 @@ TEST(Graphbuilder, TestConstructEdgesSubset) { // This directory should be empty filesystem::remove_all(tile_dir); GraphBuilder::Build(config, osm_data, ways_file, way_nodes_file, nodes_file, edges_file, - from_restriction_file, to_restriction_file, tiles); + from_restriction_file, to_restriction_file, pronunciation_file, tiles); GraphReader reader(config.get_child("mjolnir")); EXPECT_EQ(reader.GetTileSet(2).size(), 1); EXPECT_TRUE(reader.DoesTileExist(GraphId{5993698})); @@ -121,7 +122,7 @@ class HarrisburgTestSuiteEnv : public ::testing::Environment { const auto& mjolnir_config = config.get_child("mjolnir"); const std::vector& input_files = {pbf_file}; OSMData osmdata = PBFGraphParser::ParseWays(mjolnir_config, input_files, ways_file, - way_nodes_file, access_file); + way_nodes_file, access_file, pronunciation_file); PBFGraphParser::ParseRelations(mjolnir_config, input_files, from_restriction_file, to_restriction_file, osmdata); PBFGraphParser::ParseNodes(mjolnir_config, input_files, way_nodes_file, bss_file, osmdata); diff --git a/test/graphparser.cc b/test/graphparser.cc index 19a8904d08..0cca2f91e1 100644 --- a/test/graphparser.cc +++ b/test/graphparser.cc @@ -55,6 +55,7 @@ void BollardsGatesAndAccess(const std::string& config_file) { std::string ways_file = "test_ways.bin"; std::string way_nodes_file = "test_way_nodes.bin"; std::string access_file = "test_access.bin"; + std::string pronunciation_file = "test_pronunciation.bin"; std::string from_restriction_file = "test_from_complex_restrictions.bin"; std::string to_restriction_file = "test_to_complex_restrictions.bin"; std::string bss_nodes_file = "test_bss_nodes.bin"; @@ -62,7 +63,7 @@ void BollardsGatesAndAccess(const std::string& config_file) { auto osmdata = PBFGraphParser::ParseWays(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/liechtenstein-latest.osm.pbf"}, - ways_file, way_nodes_file, access_file); + ways_file, way_nodes_file, access_file, pronunciation_file); PBFGraphParser::ParseRelations(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/liechtenstein-latest.osm.pbf"}, @@ -220,13 +221,14 @@ void RemovableBollards(const std::string& config_file) { std::string ways_file = "test_ways.bin"; std::string way_nodes_file = "test_way_nodes.bin"; std::string access_file = "test_access.bin"; + std::string pronunciation_file = "test_pronunciation.bin"; std::string from_restriction_file = "test_from_complex_restrictions.bin"; std::string to_restriction_file = "test_to_complex_restrictions.bin"; std::string bss_nodes_file = "test_bss_nodes.bin"; auto osmdata = PBFGraphParser::ParseWays(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/rome.osm.pbf"}, ways_file, - way_nodes_file, access_file); + way_nodes_file, access_file, pronunciation_file); PBFGraphParser::ParseRelations(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/rome.osm.pbf"}, @@ -262,13 +264,15 @@ void Exits(const std::string& config_file) { std::string ways_file = "test_ways.bin"; std::string way_nodes_file = "test_way_nodes.bin"; std::string access_file = "test_access.bin"; + std::string pronunciation_file = "test_pronunciation.bin"; std::string from_restriction_file = "test_from_complex_restrictions.bin"; std::string to_restriction_file = "test_to_complex_restrictions.bin"; std::string bss_nodes_file = "test_bss_nodes.bin"; - auto osmdata = PBFGraphParser::ParseWays(conf.get_child("mjolnir"), - {VALHALLA_SOURCE_DIR "test/data/harrisburg.osm.pbf"}, - ways_file, way_nodes_file, access_file); + auto osmdata = + PBFGraphParser::ParseWays(conf.get_child("mjolnir"), + {VALHALLA_SOURCE_DIR "test/data/harrisburg.osm.pbf"}, ways_file, + way_nodes_file, access_file, pronunciation_file); PBFGraphParser::ParseRelations(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/harrisburg.osm.pbf"}, @@ -312,13 +316,15 @@ void Baltimore(const std::string& config_file) { std::string ways_file = "test_ways.bin"; std::string way_nodes_file = "test_way_nodes.bin"; std::string access_file = "test_access.bin"; + std::string pronunciation_file = "test_pronunciation.bin"; std::string from_restriction_file = "test_from_complex_restrictions.bin"; std::string to_restriction_file = "test_to_complex_restrictions.bin"; std::string bss_nodes_file = "test_bss_nodes.bin"; - auto osmdata = PBFGraphParser::ParseWays(conf.get_child("mjolnir"), - {VALHALLA_SOURCE_DIR "test/data/baltimore.osm.pbf"}, - ways_file, way_nodes_file, access_file); + auto osmdata = + PBFGraphParser::ParseWays(conf.get_child("mjolnir"), + {VALHALLA_SOURCE_DIR "test/data/baltimore.osm.pbf"}, ways_file, + way_nodes_file, access_file, pronunciation_file); PBFGraphParser::ParseRelations(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/baltimore.osm.pbf"}, @@ -438,13 +444,14 @@ void Bike(const std::string& config_file) { std::string ways_file = "test_ways.bin"; std::string way_nodes_file = "test_way_nodes.bin"; std::string access_file = "test_access.bin"; + std::string pronunciation_file = "test_pronunciation.bin"; std::string from_restriction_file = "test_from_complex_restrictions.bin"; std::string to_restriction_file = "test_to_complex_restrictions.bin"; std::string bss_nodes_file = "test_bss_nodes.bin"; auto osmdata = PBFGraphParser::ParseWays(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/bike.osm.pbf"}, ways_file, - way_nodes_file, access_file); + way_nodes_file, access_file, pronunciation_file); PBFGraphParser::ParseRelations(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/bike.osm.pbf"}, @@ -533,13 +540,14 @@ void Bus(const std::string& config_file) { std::string ways_file = "test_ways.bin"; std::string way_nodes_file = "test_way_nodes.bin"; std::string access_file = "test_access.bin"; + std::string pronunciation_file = "test_pronunciation.bin"; std::string from_restriction_file = "test_from_complex_restrictions.bin"; std::string to_restriction_file = "test_to_complex_restrictions.bin"; std::string bss_nodes_file = "test_bss_nodes.bin"; auto osmdata = PBFGraphParser::ParseWays(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/bus.osm.pbf"}, ways_file, - way_nodes_file, access_file); + way_nodes_file, access_file, pronunciation_file); PBFGraphParser::ParseRelations(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/bus.osm.pbf"}, from_restriction_file, @@ -614,13 +622,14 @@ void BicycleTrafficSignals(const std::string& config_file) { std::string ways_file = "test_ways.bin"; std::string way_nodes_file = "test_way_nodes.bin"; std::string access_file = "test_access.bin"; + std::string pronunciation_file = "test_pronunciation.bin"; std::string from_restriction_file = "test_from_complex_restrictions.bin"; std::string to_restriction_file = "test_to_complex_restrictions.bin"; std::string bss_nodes_file = "test_bss_nodes.bin"; auto osmdata = PBFGraphParser::ParseWays(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/nyc.osm.pbf"}, ways_file, - way_nodes_file, access_file); + way_nodes_file, access_file, pronunciation_file); PBFGraphParser::ParseRelations(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/nyc.osm.pbf"}, from_restriction_file, @@ -717,13 +726,14 @@ TEST(GraphParser, TestImportBssNode) { std::string nodes_file = "test_nodes.bin"; std::string edges_file = "test_edges.bin"; std::string access_file = "test_access.bin"; + std::string pronunciation_file = "test_pronunciation.bin"; std::string from_restriction_file = "test_from_complex_restrictions.bin"; std::string to_restriction_file = "test_to_complex_restrictions.bin"; std::string bss_nodes_file = "test_bss_nodes.bin"; auto osmdata = PBFGraphParser::ParseWays(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/rome.osm.pbf"}, ways_file, - way_nodes_file, access_file); + way_nodes_file, access_file, pronunciation_file); PBFGraphParser::ParseRelations(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/rome.osm.pbf"}, @@ -740,7 +750,7 @@ TEST(GraphParser, TestImportBssNode) { edges_file); GraphBuilder::Build(conf, osmdata, ways_file, way_nodes_file, nodes_file, edges_file, - from_restriction_file, to_restriction_file, tiles); + from_restriction_file, to_restriction_file, pronunciation_file, tiles); BssBuilder::Build(conf, bss_nodes_file); diff --git a/test/graphtilebuilder.cc b/test/graphtilebuilder.cc index 8ddd5c03ae..4e5fb39e64 100644 --- a/test/graphtilebuilder.cc +++ b/test/graphtilebuilder.cc @@ -110,12 +110,12 @@ TEST(GraphTileBuilder, TestDuplicateEdgeInfo) { // add edge info for node 0 to node 1 bool added = false; test.AddEdgeInfo(0, GraphId(0, 2, 0), GraphId(0, 2, 1), 1234, 555, 0, 120, - std::list{{0, 0}, {1, 1}}, {"einzelweg"}, {"1xyz tunnel"}, 0, added); + std::list{{0, 0}, {1, 1}}, {"einzelweg"}, {"1xyz tunnel"}, {}, 0, added); EXPECT_EQ(test.edge_offset_map_.size(), 1) << "There should be exactly two of these in here"; // add edge info for node 1 to node 0 test.AddEdgeInfo(0, GraphId(0, 2, 1), GraphId(0, 2, 0), 1234, 555, 0, 120, - std::list{{1, 1}, {0, 0}}, {"einzelweg"}, {"1xyz tunnel"}, 0, added); + std::list{{1, 1}, {0, 0}}, {"einzelweg"}, {"1xyz tunnel"}, {}, 0, added); EXPECT_EQ(test.edge_offset_map_.size(), 1) << "There should still be exactly two of these in here"; test.StoreTileData(); @@ -136,25 +136,27 @@ TEST(GraphTileBuilder, TestDuplicateEdgeInfo) { EXPECT_EQ(n3.size(), 1); EXPECT_EQ(n3.at(0), "1xyz tunnel"); // we always return the tag type in getnames - auto names_and_types = ei.GetNamesAndTypes(true); - EXPECT_EQ(names_and_types.size(), 2); + std::vector types; + auto names_and_types = ei.GetNamesAndTypes(types, false); + EXPECT_EQ(names_and_types.size(), 1); + EXPECT_EQ(types.size(), 1); auto n4 = names_and_types.at(0); EXPECT_EQ(n4.first, "einzelweg"); EXPECT_EQ(n4.second, false); - auto n5 = names_and_types.at(1); - EXPECT_EQ(n5.first, "xyz tunnel"); // no tag type in GetNamesAndTypes - EXPECT_EQ(n5.second, false); + auto t = types.at(0); + EXPECT_EQ(t, false); - names_and_types = ei.GetNamesAndTypes(false); - EXPECT_EQ(names_and_types.size(), 1); + const auto& names_and_types_tagged = ei.GetTags(); + EXPECT_EQ(names_and_types_tagged.size(), 1); n4 = names_and_types.at(0); EXPECT_EQ(n4.first, "einzelweg"); EXPECT_EQ(n4.second, false); - names_and_types = ei.GetNamesAndTypes(); // defaults to false + types.clear(); + names_and_types = ei.GetNamesAndTypes(types); // defaults to false EXPECT_EQ(names_and_types.size(), 1); n4 = names_and_types.at(0); diff --git a/test/gurka/test_build_admin.cc b/test/gurka/test_build_admin.cc index 19217226a8..6e1e1ddb37 100644 --- a/test/gurka/test_build_admin.cc +++ b/test/gurka/test_build_admin.cc @@ -279,7 +279,7 @@ TEST(AdminTest, TestBuildAdminFromPBF) { const NodeInfo* X_node = X_tile->node(X_node_id); EXPECT_EQ(X_node->drive_on_right(), false); EXPECT_EQ(X_node->named_intersection(), true); - EXPECT_EQ(X_tile->GetSigns(X_node_id.id(), true).at(0).text(), "namae wa nan desu ka"); + EXPECT_EQ(X_tile->ProcessSigns(X_node_id.id(), true).at(0).text(), "namae wa nan desu ka"); AdminInfo X_admin = X_tile->admininfo(X_node->admin_index()); EXPECT_EQ(X_admin.state_text(), "Hyogo"); EXPECT_EQ(X_admin.country_text(), "Japan"); diff --git a/test/gurka/test_phonemes.cc b/test/gurka/test_phonemes.cc new file mode 100644 index 0000000000..b1d6914ff1 --- /dev/null +++ b/test/gurka/test_phonemes.cc @@ -0,0 +1,1348 @@ +#include "gurka.h" +#include "test/test.h" +#include + +#if !defined(VALHALLA_SOURCE_DIR) +#define VALHALLA_SOURCE_DIR +#endif + +using namespace valhalla; +using namespace valhalla::baldr; +using namespace valhalla::gurka; +using namespace valhalla::mjolnir; + +valhalla::gurka::map BuildPBF(const std::string& workdir) { + const std::string ascii_map = R"( + A----B----C + \ + D-------E-------F-------G-------H-------I-------J-------K-------L-------M-------N + )"; + + const gurka::ways ways = + {{"AB", + {{"highway", "trunk"}, + {"name", "AB"}, + {"ref", "ref"}, + {"int_ref", "int_ref"}, + {"direction", "direction"}, + {"int_direction", "int_direction"}, + {"alt_name", "alt_name"}, + {"official_name", "official_name"}, + {"name:en", "name:en"}, + {"tunnel:name", "tunnel:name"}, + {"name:pronunciation", "name:pronunciation"}, + {"ref:pronunciation", "ref:pronunciation"}, + {"int_ref:pronunciation", "int_ref:pronunciation"}, + {"direction:pronunciation", "direction:pronunciation"}, + {"int_direction:pronunciation", "int_direction:pronunciation"}, + {"alt_name:pronunciation", "alt_name:pronunciation"}, + {"official_name:pronunciation", "official_name:pronunciation"}, + {"tunnel:name:pronunciation", "tunnel:name:pronunciation"}, + {"name:en:pronunciation", "name:en:pronunciation"}, + {"name:pronunciation:nt-sampa", "name:pronunciation:nt-sampa"}, + {"ref:pronunciation:nt-sampa", "ref:pronunciation:nt-sampa"}, + {"int_ref:pronunciation:nt-sampa", "int_ref:pronunciation:nt-sampa"}, + {"direction:pronunciation:nt-sampa", "direction:pronunciation:nt-sampa"}, + {"int_direction:pronunciation:nt-sampa", "int_direction:pronunciation:nt-sampa"}, + {"alt_name:pronunciation:nt-sampa", "alt_name:pronunciation:nt-sampa"}, + {"official_name:pronunciation:nt-sampa", "official_name:pronunciation:nt-sampa"}, + {"tunnel:name:pronunciation:nt-sampa", "tunnel:name:pronunciation:nt-sampa"}, + {"name:en:pronunciation:nt-sampa", "name:en:pronunciation:nt-sampa"}, + {"name:pronunciation:x-katakana", "name:pronunciation:x-katakana"}, + {"ref:pronunciation:x-katakana", "ref:pronunciation:x-katakana"}, + {"int_ref:pronunciation:x-katakana", "int_ref:pronunciation:x-katakana"}, + {"direction:pronunciation:x-katakana", "direction:pronunciation:x-katakana"}, + {"int_direction:pronunciation:x-katakana", "int_direction:pronunciation:x-katakana"}, + {"alt_name:pronunciation:x-katakana", "alt_name:pronunciation:x-katakana"}, + {"official_name:pronunciation:x-katakana", "official_name:pronunciation:x-katakana"}, + {"tunnel:name:pronunciation:x-katakana", "tunnel:name:pronunciation:x-katakana"}, + {"name:en:pronunciation:x-katakana", "name:en:pronunciation:x-katakana"}, + {"name:pronunciation:x-jeita", "name:pronunciation:x-jeita"}, + {"ref:pronunciation:x-jeita", "ref:pronunciation:x-jeita"}, + {"int_ref:pronunciation:x-jeita", "int_ref:pronunciation:x-jeita"}, + {"direction:pronunciation:x-jeita", "direction:pronunciation:x-jeita"}, + {"int_direction:pronunciation:x-jeita", "int_direction:pronunciation:x-jeita"}, + {"alt_name:pronunciation:x-jeita", "alt_name:pronunciation:x-jeita"}, + {"official_name:pronunciation:x-jeita", "official_name:pronunciation:x-jeita"}, + {"tunnel:name:pronunciation:x-jeita", "tunnel:name:pronunciation:x-jeita"}, + {"name:en:pronunciation:x-jeita", "name:en:pronunciation:x-jeita"}, + {"destination", "destination"}, + {"destination:pronunciation", "destination:pronunciation"}, + {"destination:pronunciation:nt-sampa", "destination:pronunciation:nt-sampa"}, + {"destination:pronunciation:x-katakana", "destination:pronunciation:x-katakana"}, + {"destination:pronunciation:x-jeita", "destination:pronunciation:x-jeita"}}}, + {"BC", + {{"highway", "trunk"}, + {"name", "BC"}, + {"alt_name", "alt_name"}, + {"official_name", "official_name"}, + {"name:en", "name:en"}, + {"name:pronunciation", "name:pronunciation"}, + {"alt_name:pronunciation:nt-sampa", "alt_name:pronunciation:nt-sampa"}, + {"alt_name:pronunciation:x-katakana", "alt_name:pronunciation:x-katakana"}, + {"official_name:pronunciation:x-katakana", "official_name:pronunciation:x-katakana"}, + {"official_name:pronunciation:x-jeita", "official_name:pronunciation:x-jeita"}, + {"name:en:pronunciation", "name:en:pronunciation"}, + {"name:en:pronunciation:x-katakana", "name:en:pronunciation:x-katakana"}, + {"destination:forward", "destination:forward"}, + {"destination:backward", "destination:backward"}, + {"destination:ref", "destination:ref"}, + {"destination:ref:to", "destination:ref:to"}, + {"destination:street", "destination:street"}, + {"destination:street:to", "destination:street:to"}, + {"junction:ref", "junction:ref"}, + {"destination:forward:pronunciation", "destination:forward:pronunciation"}, + {"destination:backward:pronunciation", "destination:backward:pronunciation"}, + {"destination:ref:pronunciation", "destination:ref:pronunciation"}, + {"destination:ref:to:pronunciation", "destination:ref:to:pronunciation"}, + {"destination:street:pronunciation", "destination:street:pronunciation"}, + {"destination:street:to:pronunciation", "destination:street:to:pronunciation"}, + {"junction:ref:pronunciation", "junction:ref:pronunciation"}, + {"destination:forward:pronunciation:x-katakana", + "destination:forward:pronunciation:x-katakana"}, + {"destination:backward:pronunciation:x-katakana", + "destination:backward:pronunciation:x-katakana"}, + {"destination:ref:pronunciation:x-katakana", "destination:ref:pronunciation:x-katakana"}, + {"destination:ref:to:pronunciation:x-katakana", + "destination:ref:to:pronunciation:x-katakana"}, + {"destination:street:pronunciation:x-katakana", + "destination:street:pronunciation:x-katakana"}, + {"destination:street:to:pronunciation:x-katakana", + "destination:street:to:pronunciation:x-katakana"}, + {"junction:ref:pronunciation:x-katakana", "junction:ref:pronunciation:x-katakana"}, + {"destination:forward:pronunciation:x-jeita", "destination:forward:pronunciation:x-jeita"}, + {"destination:backward:pronunciation:x-jeita", "destination:backward:pronunciation:x-jeita"}, + {"destination:ref:pronunciation:x-jeita", "destination:ref:pronunciation:x-jeita"}, + {"destination:ref:to:pronunciation:x-jeita", "destination:ref:to:pronunciation:x-jeita"}, + {"destination:street:pronunciation:x-jeita", "destination:street:pronunciation:x-jeita"}, + {"destination:street:to:pronunciation:x-jeita", + "destination:street:to:pronunciation:x-jeita"}, + {"junction:ref:pronunciation:x-jeita", "junction:ref:pronunciation:x-jeita"}}}, + {"BD", + {{"highway", "trunk"}, + {"destination:forward", "destination:forward"}, + {"destination:backward", "destination:backward"}, + {"destination:ref", "destination:ref"}, + {"destination:ref:to", "destination:ref:to"}, + {"destination:street", "destination:street"}, + {"destination:street:to", "destination:street:to"}, + {"junction:ref", "junction:ref"}, + {"destination:forward:pronunciation", "destination:forward:pronunciation"}, + {"destination:backward:pronunciation", "destination:backward:pronunciation"}, + {"destination:ref:pronunciation", "destination:ref:pronunciation"}, + {"destination:ref:to:pronunciation", "destination:ref:to:pronunciation"}, + {"destination:street:pronunciation", "destination:street:pronunciation"}, + {"destination:street:to:pronunciation", "destination:street:to:pronunciation"}, + {"junction:ref:pronunciation", "junction:ref:pronunciation"}, + {"destination:forward:pronunciation:x-katakana", + "destination:forward:pronunciation:x-katakana"}, + {"destination:backward:pronunciation:x-katakana", + "destination:backward:pronunciation:x-katakana"}, + {"destination:ref:pronunciation:x-katakana", "destination:ref:pronunciation:x-katakana"}, + {"destination:ref:to:pronunciation:x-katakana", + "destination:ref:to:pronunciation:x-katakana"}, + {"destination:street:pronunciation:x-katakana", + "destination:street:pronunciation:x-katakana"}, + {"destination:street:to:pronunciation:x-katakana", + "destination:street:to:pronunciation:x-katakana"}, + {"junction:ref:pronunciation:x-katakana", "junction:ref:pronunciation:x-katakana"}}}, + {"DE", + {{"highway", "primary"}, + {"name", "DE;xyz street;abc ave"}, + {"name:pronunciation", ";;name:pronunciation3"}, + {"destination", "destination1;destination2"}, + {"destination:pronunciation", "destination:pronunciation1;destination:pronunciation2"}}}, + {"EF", + {{"highway", "primary_link"}, + {"name", "EF;xyz street;abc ave"}, + {"name:pronunciation", ";name:pronunciation2;"}, + {"oneway", "yes"}, + {"destination", "destination1;destination2"}, + {"destination:pronunciation", ";"}}}, + {"FG", + {{"highway", "primary"}, + {"oneway", "yes"}, + {"name", "FG;xyz street;abc ave"}, + {"name:pronunciation", "name:pronunciation1;;"}, + {"destination", "destination1;destination2;destination3"}, + {"destination:pronunciation", ";;destination:pronunciation3"}}}, + {"GH", + {{"highway", "primary"}, + {"oneway", "yes"}, + {"name", "GH;xyz street;abc ave"}, + {"name:pronunciation", ";name:pronunciation2;name:pronunciation3"}, + {"destination", "destination1;destination2;destination3"}, + {"destination:pronunciation", ";destination:pronunciation2;"}}}, + {"HI", + {{"highway", "primary"}, + {"oneway", "yes"}, + {"name", "HI;xyz street;abc ave"}, + {"name:pronunciation:x-katakana", + ";name:pronunciation2:x-katakana;name:pronunciation3:x-katakana"}, + {"name:pronunciation:x-jeita", ";name:pronunciation2:x-jeita;name:pronunciation3:x-jeita"}, + {"destination", "destination1;destination2;destination3"}, + {"destination:pronunciation", ";destination:pronunciation2;destination:pronunciation3"}}}, + {"IJ", + {{"highway", "primary"}, + {"oneway", "yes"}, + {"name:pronunciation:x-katakana", ";name:pronunciation1;;"}, + {"name:pronunciation:x-jeita", ";;name:pronunciation2"}, + {"destination", "destination1;destination2;destination3"}, + {"destination:pronunciation", "destination:pronunciation1;;destination:pronunciation3"}}}, + {"JK", + {{"highway", "primary"}, + {"oneway", "yes"}, + {"destination", "destination1;destination2;destination3"}, + {"destination:pronunciation", "destination:pronunciation1;destination:pronunciation2;"}}}, + {"KL", + {{"highway", "primary"}, + {"oneway", "yes"}, + {"destination", "destination1;destination2;destination3"}, + {"destination:pronunciation", "destination:pronunciation1;;"}}}, + {"LM", + {{"highway", "primary"}, + {"oneway", "yes"}, + {"destination", "destination1;destination2;destination3"}, + {"destination:pronunciation:x-katakana", ";destination:pronunciation2:x-katakana;"}, + {"destination:pronunciation:x-jeita", ";destination:pronunciation2:x-jeita;"}}}, + {"MN", + {{"highway", "primary"}, + {"oneway", "yes"}, + {"destination", "destination1;destination2;destination3"}, + {"destination:pronunciation:x-katakana", ";;destination:pronunciation3:x-katakana"}, + {"destination:pronunciation:x-jeita", ";destination:pronunciation2:x-jeita;"}}}}; + + const gurka::nodes nodes = + {{"B", + {{"junction", "named"}, + {"name", "named junction"}, + {"highway", "motorway_junction"}, + {"name:pronunciation", "named junction:pronunciation"}, + {"name:pronunciation:nt-sampa", "named junction:pronunciation:nt-sampa"}, + {"name:pronunciation:x-katakana", "named junction:pronunciation:x-katakana"}, + {"name:pronunciation:x-jeita", "named junction:pronunciation:x-jeita"}}}, + {"E", + {{"ref", "node ref"}, + {"highway", "motorway_junction"}, + {"ref:pronunciation", "node ref:pronunciation"}, + {"ref:pronunciation:x-katakana", "node ref:pronunciation:x-katakana"}}}}; + + constexpr double gridsize = 100; + + const auto layout = gurka::detail::map_to_coordinates(ascii_map, gridsize, {5.1079374, 52.0887174}); + + auto pbf_filename = workdir + "/map.pbf"; + detail::build_pbf(layout, ways, nodes, {}, pbf_filename); + + valhalla::gurka::map result; + result.nodes = layout; + return result; +} + +TEST(Standalone, PhonemesWithAltandDirection) { + + const std::string workdir = "test/data/gurka_phonemes_alt_dir"; + + if (!filesystem::exists(workdir)) { + bool created = filesystem::create_directories(workdir); + EXPECT_TRUE(created); + } + + valhalla::gurka::map map = BuildPBF(workdir); + + const std::string sqlite = {VALHALLA_SOURCE_DIR "test/data/netherlands_admin.sqlite"}; + boost::property_tree::ptree& pt = map.config; + pt.put("mjolnir.data_processing.allow_alt_name", "true"); + pt.put("mjolnir.data_processing.use_direction_on_ways", "true"); + pt.put("mjolnir.tile_dir", workdir + "/tiles"); + pt.put("mjolnir.admin", sqlite); + + std::vector input_files = {workdir + "/map.pbf"}; + + build_tile_set(pt, input_files, mjolnir::BuildStage::kInitialize, mjolnir::BuildStage::kValidate, + false); + + GraphReader graph_reader(pt.get_child("mjolnir")); + + GraphId AB_edge_id; + const DirectedEdge* AB_edge = nullptr; + GraphId BA_edge_id; + const DirectedEdge* BA_edge = nullptr; + std::tie(AB_edge_id, AB_edge, BA_edge_id, BA_edge) = findEdge(graph_reader, map.nodes, "AB", "B"); + EXPECT_NE(AB_edge, nullptr); + EXPECT_NE(BA_edge, nullptr); + + GraphId BC_edge_id; + const DirectedEdge* BC_edge = nullptr; + GraphId CB_edge_id; + const DirectedEdge* CB_edge = nullptr; + std::tie(BC_edge_id, BC_edge, CB_edge_id, CB_edge) = findEdge(graph_reader, map.nodes, "BC", "C"); + EXPECT_NE(BC_edge, nullptr); + EXPECT_NE(CB_edge, nullptr); + + GraphId BD_edge_id; + const DirectedEdge* BD_edge = nullptr; + GraphId DB_edge_id; + const DirectedEdge* DB_edge = nullptr; + std::tie(BD_edge_id, BD_edge, DB_edge_id, DB_edge) = findEdge(graph_reader, map.nodes, "BD", "D"); + EXPECT_NE(BD_edge, nullptr); + EXPECT_NE(DB_edge, nullptr); + + GraphId DE_edge_id; + const DirectedEdge* DE_edge = nullptr; + GraphId ED_edge_id; + const DirectedEdge* ED_edge = nullptr; + std::tie(DE_edge_id, DE_edge, ED_edge_id, ED_edge) = findEdge(graph_reader, map.nodes, "DE", "E"); + EXPECT_NE(DE_edge, nullptr); + EXPECT_NE(ED_edge, nullptr); + + GraphId EF_edge_id; + const DirectedEdge* EF_edge = nullptr; + GraphId FE_edge_id; + const DirectedEdge* FE_edge = nullptr; + std::tie(EF_edge_id, EF_edge, FE_edge_id, FE_edge) = findEdge(graph_reader, map.nodes, "EF", "F"); + EXPECT_NE(EF_edge, nullptr); + EXPECT_NE(FE_edge, nullptr); + + GraphId FG_edge_id; + const DirectedEdge* FG_edge = nullptr; + GraphId GF_edge_id; + const DirectedEdge* GF_edge = nullptr; + std::tie(FG_edge_id, FG_edge, GF_edge_id, GF_edge) = findEdge(graph_reader, map.nodes, "FG", "G"); + EXPECT_NE(FG_edge, nullptr); + EXPECT_NE(GF_edge, nullptr); + + GraphId GH_edge_id; + const DirectedEdge* GH_edge = nullptr; + GraphId HG_edge_id; + const DirectedEdge* HG_edge = nullptr; + std::tie(GH_edge_id, GH_edge, HG_edge_id, HG_edge) = findEdge(graph_reader, map.nodes, "GH", "H"); + EXPECT_NE(GH_edge, nullptr); + EXPECT_NE(HG_edge, nullptr); + + GraphId HI_edge_id; + const DirectedEdge* HI_edge = nullptr; + GraphId IH_edge_id; + const DirectedEdge* IH_edge = nullptr; + std::tie(HI_edge_id, HI_edge, IH_edge_id, IH_edge) = findEdge(graph_reader, map.nodes, "HI", "I"); + EXPECT_NE(HI_edge, nullptr); + EXPECT_NE(IH_edge, nullptr); + + GraphId IJ_edge_id; + const DirectedEdge* IJ_edge = nullptr; + GraphId JI_edge_id; + const DirectedEdge* JI_edge = nullptr; + std::tie(IJ_edge_id, IJ_edge, JI_edge_id, JI_edge) = findEdge(graph_reader, map.nodes, "IJ", "J"); + EXPECT_NE(IJ_edge, nullptr); + EXPECT_NE(JI_edge, nullptr); + + GraphId JK_edge_id; + const DirectedEdge* JK_edge = nullptr; + GraphId KJ_edge_id; + const DirectedEdge* KJ_edge = nullptr; + std::tie(JK_edge_id, JK_edge, KJ_edge_id, KJ_edge) = findEdge(graph_reader, map.nodes, "JK", "K"); + EXPECT_NE(JK_edge, nullptr); + EXPECT_NE(KJ_edge, nullptr); + + GraphId KL_edge_id; + const DirectedEdge* KL_edge = nullptr; + GraphId LK_edge_id; + const DirectedEdge* LK_edge = nullptr; + std::tie(KL_edge_id, KL_edge, LK_edge_id, LK_edge) = findEdge(graph_reader, map.nodes, "KL", "L"); + EXPECT_NE(KL_edge, nullptr); + EXPECT_NE(LK_edge, nullptr); + + GraphId LM_edge_id; + const DirectedEdge* LM_edge = nullptr; + GraphId ML_edge_id; + const DirectedEdge* ML_edge = nullptr; + std::tie(LM_edge_id, LM_edge, ML_edge_id, ML_edge) = findEdge(graph_reader, map.nodes, "LM", "M"); + EXPECT_NE(LM_edge, nullptr); + EXPECT_NE(ML_edge, nullptr); + + GraphId MN_edge_id; + const DirectedEdge* MN_edge = nullptr; + GraphId NM_edge_id; + const DirectedEdge* NM_edge = nullptr; + std::tie(MN_edge_id, MN_edge, NM_edge_id, NM_edge) = findEdge(graph_reader, map.nodes, "MN", "N"); + EXPECT_NE(MN_edge, nullptr); + EXPECT_NE(NM_edge, nullptr); + + // Test the named junction on the node. nt-sampa wins + { + GraphId node_id = AB_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + + std::unordered_map> pronunciations; + std::vector signs = tile->GetSigns(node_id.id(), pronunciations, true); + + uint32_t sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + if (iter == pronunciations.end()) { + EXPECT_NE(iter, pronunciations.end()); + } else { + if ((iter->second).second == "named junction:pronunciation:nt-sampa") { + EXPECT_EQ(signs.at(sign_index).text(), "named junction"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == "destination:pronunciation:nt-sampa") { + EXPECT_EQ(signs.at(sign_index).text(), "destination"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++sign_index; + } + } + // Test the ref on the node katakana wins. Also, test empty pronunciations + { + + GraphId node_id = EF_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + auto edgeinfo = tile->edgeinfo(EF_edge); + + std::unordered_map> pronunciations; + std::vector signs = tile->GetSigns(EF_edge_id.id(), pronunciations); + + uint32_t sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + if (iter == pronunciations.end()) { + if (sign_index == 1) + EXPECT_EQ(signs.at(sign_index).text(), "destination1"); + if (sign_index == 2) + EXPECT_EQ(signs.at(sign_index).text(), "destination2"); + } else { + if ((iter->second).second == "node ref:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "node ref"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++sign_index; + } + + // blank pronunciations for names. + std::vector types; + auto names_and_types = edgeinfo.GetNamesAndTypes(types, true); + + EXPECT_NE(names_and_types.size(), 0); + + std::unordered_map> name_pronunciations = + edgeinfo.GetPronunciationsMap(); + uint8_t name_index = 0; + for (const auto& name_and_type : names_and_types) { + if (types.at(name_index) != 0) { + // Skip the tagged names + ++name_index; + continue; + } + std::unordered_map>::const_iterator iter = + name_pronunciations.find(name_index); + if (iter == name_pronunciations.end()) { + if (name_index != 0) + EXPECT_EQ(iter, name_pronunciations.end()); + } else { + // first and last name is missing in the name field + EXPECT_EQ(name_index, 1); + if ((iter->second).second == "name:pronunciation2") { + EXPECT_EQ(names_and_types.at(name_index).first, "xyz street"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++name_index; + } + } + + // Test 2 empty pronunciations + { + + GraphId node_id = FG_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + auto edgeinfo = tile->edgeinfo(FG_edge); + + std::unordered_map> pronunciations; + std::vector signs = tile->GetSigns(FG_edge_id.id(), pronunciations); + + uint32_t sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + + if (iter == pronunciations.end()) { + if (sign_index == 0) + EXPECT_EQ(signs.at(sign_index).text(), "destination1"); + else if (sign_index == 1) + EXPECT_EQ(signs.at(sign_index).text(), "destination2"); + else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } else if ((iter->second).second == "destination:pronunciation3") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination3"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + ++sign_index; + } + + // blank pronunciations for names. + std::vector types; + auto names_and_types = edgeinfo.GetNamesAndTypes(types, true); + + EXPECT_NE(names_and_types.size(), 0); + + std::unordered_map> name_pronunciations = + edgeinfo.GetPronunciationsMap(); + uint8_t name_index = 0; + for (const auto& name_and_type : names_and_types) { + if (types.at(name_index) != 0) { + // Skip the tagged names + ++name_index; + continue; + } + std::unordered_map>::const_iterator iter = + name_pronunciations.find(name_index); + if (iter == name_pronunciations.end()) { + if (name_index != 1 && name_index != 2) + EXPECT_EQ(iter, name_pronunciations.end()); + } else { + // first and last name is missing in the name field + EXPECT_EQ(name_index, 0); + if ((iter->second).second == "name:pronunciation1") { + EXPECT_EQ(names_and_types.at(name_index).first, "FG"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++name_index; + } + } + + // Test 2 empty pronunciations + { + + GraphId node_id = GH_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + auto edgeinfo = tile->edgeinfo(GH_edge); + + std::unordered_map> pronunciations; + std::vector signs = tile->GetSigns(GH_edge_id.id(), pronunciations); + + uint32_t sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + + if (iter == pronunciations.end()) { + if (sign_index == 0) + EXPECT_EQ(signs.at(sign_index).text(), "destination1"); + else if (sign_index == 2) + EXPECT_EQ(signs.at(sign_index).text(), "destination3"); + else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } else if ((iter->second).second == "destination:pronunciation2") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination2"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + ++sign_index; + } + + // blank pronunciations for names. + std::vector types; + auto names_and_types = edgeinfo.GetNamesAndTypes(types, true); + + EXPECT_NE(names_and_types.size(), 0); + + std::unordered_map> name_pronunciations = + edgeinfo.GetPronunciationsMap(); + uint8_t name_index = 0; + for (const auto& name_and_type : names_and_types) { + if (types.at(name_index) != 0) { + // Skip the tagged names + ++name_index; + continue; + } + std::unordered_map>::const_iterator iter = + name_pronunciations.find(name_index); + if (iter == name_pronunciations.end()) { + if (name_index != 0) + EXPECT_EQ(iter, name_pronunciations.end()); + } else { + if ((iter->second).second == "name:pronunciation2") { + EXPECT_EQ(names_and_types.at(name_index).first, "xyz street"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else if ((iter->second).second == "name:pronunciation3") { + EXPECT_EQ(names_and_types.at(name_index).first, "abc ave"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++name_index; + } + } + + // Test 1 empty pronunciation + { + + GraphId node_id = HI_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + auto edgeinfo = tile->edgeinfo(HI_edge); + + std::unordered_map> pronunciations; + std::vector signs = tile->GetSigns(HI_edge_id.id(), pronunciations); + + uint32_t sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + + if (iter == pronunciations.end()) { + if (sign_index == 0) + EXPECT_EQ(signs.at(sign_index).text(), "destination1"); + else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } else if ((iter->second).second == "destination:pronunciation2") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination2"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else if ((iter->second).second == "destination:pronunciation3") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination3"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + ++sign_index; + } + + // blank pronunciations for names. + std::vector types; + auto names_and_types = edgeinfo.GetNamesAndTypes(types, true); + + EXPECT_NE(names_and_types.size(), 0); + + std::unordered_map> name_pronunciations = + edgeinfo.GetPronunciationsMap(); + uint8_t name_index = 0; + for (const auto& name_and_type : names_and_types) { + if (types.at(name_index) != 0) { + // Skip the tagged names + ++name_index; + continue; + } + std::unordered_map>::const_iterator iter = + name_pronunciations.find(name_index); + if (iter == name_pronunciations.end()) { + if (name_index != 0) + EXPECT_EQ(iter, name_pronunciations.end()); + } else { + if ((iter->second).second == "name:pronunciation2:x-jeita") { + EXPECT_EQ(names_and_types.at(name_index).first, "xyz street"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else if ((iter->second).second == "name:pronunciation3:x-jeita") { + EXPECT_EQ(names_and_types.at(name_index).first, "abc ave"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++name_index; + } + } + + // Test 1 empty pronunciation + { + + GraphId node_id = IJ_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + auto edgeinfo = tile->edgeinfo(IJ_edge); + + std::unordered_map> pronunciations; + std::vector signs = tile->GetSigns(IJ_edge_id.id(), pronunciations); + + uint32_t sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + + if (iter == pronunciations.end()) { + if (sign_index == 1) + EXPECT_EQ(signs.at(sign_index).text(), "destination2"); + else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } else if ((iter->second).second == "destination:pronunciation1") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination1"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else if ((iter->second).second == "destination:pronunciation3") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination3"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + ++sign_index; + } + + // blank pronunciations for names. + std::vector types; + auto names_and_types = edgeinfo.GetNamesAndTypes(types, true); + + EXPECT_NE(names_and_types.size(), 0); + + std::unordered_map> name_pronunciations = + edgeinfo.GetPronunciationsMap(); + uint8_t name_index = 0; + for (const auto& name_and_type : names_and_types) { + if (types.at(name_index) != 0) { + // Skip the tagged names + ++name_index; + continue; + } + std::unordered_map>::const_iterator iter = + name_pronunciations.find(name_index); + if (iter == name_pronunciations.end()) { + if (name_index != 0) + EXPECT_EQ(iter, name_pronunciations.end()); + } else { + if ((iter->second).second == "name:pronunciation1:x-katakana") { + EXPECT_EQ(names_and_types.at(name_index).first, "xyz street"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "name:pronunciation2:x-jeita") { + EXPECT_EQ(names_and_types.at(name_index).first, "abc ave"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++name_index; + } + } + + // Test 1 empty pronunciation + { + + GraphId node_id = JK_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + auto edgeinfo = tile->edgeinfo(JK_edge); + + std::unordered_map> pronunciations; + std::vector signs = tile->GetSigns(JK_edge_id.id(), pronunciations); + + uint32_t sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + + if (iter == pronunciations.end()) { + if (sign_index == 2) + EXPECT_EQ(signs.at(sign_index).text(), "destination3"); + else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } else if ((iter->second).second == "destination:pronunciation1") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination1"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else if ((iter->second).second == "destination:pronunciation2") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination2"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + ++sign_index; + } + } + + // Test 2 empty pronunciations + { + + GraphId node_id = KL_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + auto edgeinfo = tile->edgeinfo(KL_edge); + + std::unordered_map> pronunciations; + std::vector signs = tile->GetSigns(KL_edge_id.id(), pronunciations); + + uint32_t sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + + if (iter == pronunciations.end()) { + if (sign_index == 1) + EXPECT_EQ(signs.at(sign_index).text(), "destination2"); + else if (sign_index == 2) + EXPECT_EQ(signs.at(sign_index).text(), "destination3"); + else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } else if ((iter->second).second == "destination:pronunciation1") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination1"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + ++sign_index; + } + } + + // Test 2 empty pronunciations and jeita wins + { + + GraphId node_id = LM_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + auto edgeinfo = tile->edgeinfo(LM_edge); + + std::unordered_map> pronunciations; + std::vector signs = tile->GetSigns(LM_edge_id.id(), pronunciations); + + uint32_t sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + + if (iter == pronunciations.end()) { + if (sign_index == 0) + EXPECT_EQ(signs.at(sign_index).text(), "destination1"); + else if (sign_index == 2) + EXPECT_EQ(signs.at(sign_index).text(), "destination3"); + else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } else if ((iter->second).second == "destination:pronunciation2:x-jeita") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination2"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + ++sign_index; + } + } + + // Test 2 empty pronunciations. Should have katakanna and jeita + { + + GraphId node_id = MN_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + auto edgeinfo = tile->edgeinfo(MN_edge); + + std::unordered_map> pronunciations; + std::vector signs = tile->GetSigns(MN_edge_id.id(), pronunciations); + + uint32_t sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + + if (iter == pronunciations.end()) { + if (sign_index == 0) + EXPECT_EQ(signs.at(sign_index).text(), "destination1"); + else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } else if ((iter->second).second == "destination:pronunciation3:x-katakana") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination3"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "destination:pronunciation2:x-jeita") { + + EXPECT_EQ(signs.at(sign_index).text(), "destination2"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + ++sign_index; + } + } + + // Test the names. nt-sampa wins. + { + + GraphId node_id = AB_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + auto edgeinfo = tile->edgeinfo(AB_edge); + std::vector types; + auto names_and_types = edgeinfo.GetNamesAndTypes(types, true); + + EXPECT_NE(names_and_types.size(), 0); + + std::unordered_map> pronunciations = + edgeinfo.GetPronunciationsMap(); + uint8_t name_index = 0; + for (const auto& name_and_type : names_and_types) { + if (types.at(name_index) != 0) { + // Skip the tagged names + ++name_index; + continue; + } + + std::unordered_map>::const_iterator iter = + pronunciations.find(name_index); + if (iter == pronunciations.end()) { + EXPECT_NE(iter, pronunciations.end()); + } else { + + if ((iter->second).second == "name:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "AB"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == "tunnel:name:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "tunnel:name"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == + "int_ref:pronunciation:nt-sampa int_direction:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "int_ref int_direction"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == + "ref:pronunciation:nt-sampa direction:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "ref direction"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == "alt_name:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "alt_name"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == "official_name:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "official_name"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == "name:en:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "name:en"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++name_index; + } + } + + // Test the signs. katakana wins. + { + GraphId node_id = BD_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + const NodeInfo* node_info = tile->node(node_id); + + std::unordered_map> pronunciations; + std::vector signs = tile->GetSigns(BD_edge_id.id(), pronunciations); + + uint32_t sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + if (iter == pronunciations.end()) { + EXPECT_NE(iter, pronunciations.end()); + } else { + + if ((iter->second).second == "destination:forward:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:forward"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "destination:street:to:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:street:to"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "destination:ref:to:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:ref:to"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "destination:ref:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:ref"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "destination:street:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:street"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "junction:ref:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "junction:ref"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++sign_index; + } + + node_id = DB_edge->endnode(); + tile = graph_reader.GetGraphTile(node_id); + node_info = tile->node(node_id); + + pronunciations.clear(); + signs.clear(); + signs = tile->GetSigns(DB_edge_id.id(), pronunciations); + + sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + if (iter == pronunciations.end()) { + EXPECT_NE(iter, pronunciations.end()); + } else { + + if ((iter->second).second == "destination:backward:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:backward"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "destination:street:to:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:street:to"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "destination:ref:to:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:ref:to"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "destination:ref:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:ref"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "destination:street:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:street"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else if ((iter->second).second == "junction:ref:pronunciation:x-katakana") { + EXPECT_EQ(signs.at(sign_index).text(), "junction:ref"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++sign_index; + } + + // more signs. jeita wins. + node_id = BC_edge->endnode(); + tile = graph_reader.GetGraphTile(node_id); + node_info = tile->node(node_id); + + pronunciations.clear(); + signs.clear(); + signs = tile->GetSigns(BC_edge_id.id(), pronunciations); + + sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + if (iter == pronunciations.end()) { + EXPECT_NE(iter, pronunciations.end()); + } else { + + if ((iter->second).second == "destination:forward:pronunciation:x-jeita") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:forward"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else if ((iter->second).second == "destination:street:to:pronunciation:x-jeita") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:street:to"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else if ((iter->second).second == "destination:ref:to:pronunciation:x-jeita") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:ref:to"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else if ((iter->second).second == "destination:ref:pronunciation:x-jeita") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:ref"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else if ((iter->second).second == "destination:street:pronunciation:x-jeita") { + EXPECT_EQ(signs.at(sign_index).text(), "destination:street"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else if ((iter->second).second == "junction:ref:pronunciation:x-jeita") { + EXPECT_EQ(signs.at(sign_index).text(), "junction:ref"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++sign_index; + } + + // ipa wins for the name. + // nt-sampa wins for the alt_name + // jeita wins for official_name + // katakana wins for name:en + { + auto edgeinfo = tile->edgeinfo(BC_edge); + std::vector types; + auto names_and_types = edgeinfo.GetNamesAndTypes(types, true); + + EXPECT_NE(names_and_types.size(), 0); + + std::unordered_map> pronunciations = + edgeinfo.GetPronunciationsMap(); + uint8_t name_index = 0; + for (const auto& name_and_type : names_and_types) { + if (types.at(name_index) != 0) { + // Skip the tagged names + ++name_index; + continue; + } + std::unordered_map>::const_iterator iter = + pronunciations.find(name_index); + if (iter == pronunciations.end()) { + EXPECT_NE(iter, pronunciations.end()); + } else { + + if ((iter->second).second == "name:pronunciation") { + EXPECT_EQ(names_and_types.at(name_index).first, "BC"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else if ((iter->second).second == "alt_name:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "alt_name"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == "official_name:pronunciation:x-jeita") { + EXPECT_EQ(names_and_types.at(name_index).first, "official_name"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXJeita)); + } else if ((iter->second).second == "name:en:pronunciation:x-katakana") { + EXPECT_EQ(names_and_types.at(name_index).first, "name:en"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kXKatakana)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++name_index; + } + } + + // more signs. should all be ipa + node_id = DE_edge->endnode(); + graph_reader.GetGraphTile(node_id); + node_info = tile->node(node_id); + + pronunciations.clear(); + signs.clear(); + + signs = tile->GetSigns(DE_edge_id.id(), pronunciations); + + sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + if (iter == pronunciations.end()) { + EXPECT_NE(iter, pronunciations.end()); + } else { + if ((iter->second).second == "destination:pronunciation1") { + EXPECT_EQ(signs.at(sign_index).text(), "destination1"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else if ((iter->second).second == "destination:pronunciation2") { + EXPECT_EQ(signs.at(sign_index).text(), "destination2"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++sign_index; + } + + // blank pronunciations for names. + { + auto edgeinfo = tile->edgeinfo(DE_edge); + std::vector types; + auto names_and_types = edgeinfo.GetNamesAndTypes(types, true); + + EXPECT_NE(names_and_types.size(), 0); + + std::unordered_map> pronunciations = + edgeinfo.GetPronunciationsMap(); + uint8_t name_index = 0; + for (const auto& name_and_type : names_and_types) { + if (types.at(name_index) != 0) { + // Skip the tagged names + ++name_index; + continue; + } + std::unordered_map>::const_iterator iter = + pronunciations.find(name_index); + if (iter == pronunciations.end()) { + if (name_index != 0 && name_index != 1) + EXPECT_EQ(iter, pronunciations.end()); + } else { + EXPECT_EQ(name_index, 2); + if ((iter->second).second == "name:pronunciation3") { + EXPECT_EQ(names_and_types.at(name_index).first, "abc ave"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++name_index; + } + } + + // more signs. should all be ipa + node_id = ED_edge->endnode(); + graph_reader.GetGraphTile(node_id); + node_info = tile->node(node_id); + + pronunciations.clear(); + signs.clear(); + signs = tile->GetSigns(ED_edge_id.id(), pronunciations); + + sign_index = 0; + EXPECT_NE(signs.size(), 0); + for (const auto& sign : signs) { + + std::unordered_map>::const_iterator iter = + pronunciations.find(sign_index); + if (iter == pronunciations.end()) { + EXPECT_NE(iter, pronunciations.end()); + } else { + + if ((iter->second).second == "destination:pronunciation1") { + EXPECT_EQ(signs.at(sign_index).text(), "destination1"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else if ((iter->second).second == "destination:pronunciation2") { + EXPECT_EQ(signs.at(sign_index).text(), "destination2"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kIpa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++sign_index; + } + } // end test the signs +} + +TEST(Standalone, PhonemesWithNoAltandDirection) { + + const std::string workdir = "test/data/gurka_phonemes"; + + if (!filesystem::exists(workdir)) { + bool created = filesystem::create_directories(workdir); + EXPECT_TRUE(created); + } + + valhalla::gurka::map map = BuildPBF(workdir); + + boost::property_tree::ptree& pt = map.config; + pt.put("mjolnir.data_processing.allow_alt_name", "false"); + pt.put("mjolnir.data_processing.use_direction_on_ways", "false"); + pt.put("mjolnir.tile_dir", workdir + "/tiles"); + + std::vector input_files = {workdir + "/map.pbf"}; + + build_tile_set(pt, input_files, mjolnir::BuildStage::kInitialize, mjolnir::BuildStage::kValidate, + false); + + GraphReader graph_reader(pt.get_child("mjolnir")); + + GraphId AB_edge_id; + const DirectedEdge* AB_edge = nullptr; + GraphId BA_edge_id; + const DirectedEdge* BA_edge = nullptr; + std::tie(AB_edge_id, AB_edge, BA_edge_id, BA_edge) = findEdge(graph_reader, map.nodes, "AB", "B"); + EXPECT_NE(AB_edge, nullptr); + EXPECT_NE(BA_edge, nullptr); + + // Test the names. nt-sampa wins. + { + + GraphId node_id = AB_edge->endnode(); + auto tile = graph_reader.GetGraphTile(node_id); + auto edgeinfo = tile->edgeinfo(AB_edge); + std::vector types; + auto names_and_types = edgeinfo.GetNamesAndTypes(types, true); + + EXPECT_NE(names_and_types.size(), 0); + + std::unordered_map> pronunciations = + edgeinfo.GetPronunciationsMap(); + uint8_t name_index = 0; + for (const auto& name_and_type : names_and_types) { + if (types.at(name_index) != 0) { + // Skip the tagged names + ++name_index; + continue; + } + + std::unordered_map>::const_iterator iter = + pronunciations.find(name_index); + + if (iter == pronunciations.end()) { + EXPECT_NE(iter, pronunciations.end()); + } else { + if ((iter->second).second == "name:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "AB"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == "tunnel:name:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "tunnel:name"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == "int_ref:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "int_ref"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == "ref:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "ref"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == "official_name:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "official_name"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else if ((iter->second).second == "name:en:pronunciation:nt-sampa") { + EXPECT_EQ(names_and_types.at(name_index).first, "name:en"); + EXPECT_EQ(static_cast((iter->second).first), + static_cast(baldr::PronunciationAlphabet::kNtSampa)); + } else + EXPECT_EQ((iter->second).second, "Extra key. This should not happen."); + } + ++name_index; + } + } +} diff --git a/test/gurka/test_route_with_pronunciations.cc b/test/gurka/test_route_with_pronunciations.cc new file mode 100644 index 0000000000..06ac94cd53 --- /dev/null +++ b/test/gurka/test_route_with_pronunciations.cc @@ -0,0 +1,513 @@ +#include "gurka.h" +#include + +#if !defined(VALHALLA_SOURCE_DIR) +#define VALHALLA_SOURCE_DIR +#endif + +using namespace valhalla; + +const std::unordered_map build_config{ + {"mjolnir.admin", {VALHALLA_SOURCE_DIR "test/data/netherlands_admin.sqlite"}}, + {"odin.markup_formatter.markup_enabled", "true"}, + {"odin.markup_formatter.phoneme_format", + " (phoneme>//)"}, +}; + +class RouteWithStreetnameAndSignPronunciation : public ::testing::Test { +protected: + static gurka::map map; + + static void SetUpTestSuite() { + constexpr double gridsize_metres = 100; + + const std::string ascii_map = R"( + J + | + | + | + I + /|\ + / | \ + / | \ + L----K-------------H----G + A----B-------------E----F + \ | / + \ | / + \|/ + C + | + | + | + D + O------PM------Q + | + | + | + N + + )"; + + const gurka::ways ways = { + {"ABEF", {{"highway", "motorway"}, {"name", ""}, {"ref", "I 70"}, {"oneway", "yes"}}}, + {"GHKL", {{"highway", "motorway"}, {"name", ""}, {"ref", "I 70"}, {"oneway", "yes"}}}, + {"JICDMN", + {{"highway", "primary"}, + {"name", "Lancaster Road"}, + {"name:pronunciation", "ˈlæŋkəstər ˈɹoʊd"}, + {"ref", "SR 37"}, + {"ref:pronunciation", "ˈsinjər 37"}}}, + {"BC", + {{"highway", "motorway_link"}, + {"name", ""}, + {"oneway", "yes"}, + {"junction:ref", "126B"}, + {"junction:ref:pronunciation", "1 26bi"}, + {"destination", "Granville;Lancaster"}, + {"destination:pronunciation", "ˈgɹænvɪl;ˈlæŋkəstər"}, + {"destination:street", "Lancaster Road"}, + {"destination:street:pronunciation", "ˈlæŋkəstər ˈɹoʊd"}, + {"destination:ref", "SR 37"}, + {"destination:ref:pronunciation", "ˈsinjər 37"}}}, + {"CE", + {{"highway", "motorway_link"}, + {"name", ""}, + {"oneway", "yes"}, + {"destination:ref", "I 70 East"}}}, + {"HI", + {{"highway", "motorway_link"}, + {"name", ""}, + {"oneway", "yes"}, + {"junction:ref", "126B"}, + {"junction:ref:pronunciation", "1 26bi"}, + {"destination:street:to", "Main Street"}, + {"destination:street:to:pronunciation", "meɪn strit"}, + {"destination:ref:to", "I 80"}, + {"destination:ref:to:pronunciation", "aɪ 80"}}}, + {"IK", + {{"highway", "motorway_link"}, + {"name", ""}, + {"oneway", "yes"}, + {"destination:ref", "I 70 West"}}}, + {"OPMQ", + {{"highway", "secondary"}, + {"name", "Granville Road"}, + {"name:pronunciation", "ˈgɹænvɪl ˈɹoʊd"}}}, + {"DP", + {{"highway", "secondary_link"}, + {"name", ""}, + {"oneway", "yes"}, + {"destination", "Granville"}, + {"destination:pronunciation", "ˈgɹænvɪl"}, + {"destination:street", "Granville Road"}, + {"destination:street:pronunciation", "ˈgɹænvɪl ˈɹoʊd"}}}, + }; + + const gurka::nodes nodes = {{"M", + {{"highway", "traffic_signals"}, + {"name", "M Junction"}, + {"name:pronunciation", "ɛm ˈʤʌŋkʃən"}}}}; + + const auto layout = + gurka::detail::map_to_coordinates(ascii_map, gridsize_metres, {5.1079374, 52.0887174}); + map = gurka::buildtiles(layout, ways, nodes, {}, + "test/data/gurka_route_with_streetname_and_sign_pronunciation", + build_config); + } +}; + +gurka::map RouteWithStreetnameAndSignPronunciation::map = {}; + +/////////////////////////////////////////////////////////////////////////////// +TEST_F(RouteWithStreetnameAndSignPronunciation, CheckStreetNamesAndSigns1) { + auto result = gurka::do_action(valhalla::Options::route, map, {"A", "D"}, "auto"); + gurka::assert::raw::expect_path(result, {"I 70", "", "Lancaster Road/SR 37"}); + + // Verify starting on I 70 + int maneuver_index = 0; + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name_size(), 1); + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name(0).value(), + "I 70"); + + // Verify sign pronunciations - alphabet & value + ++maneuver_index; + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_onto_streets_size(), + 2); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_onto_streets(0) + .text(), + "SR 37"); + + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_onto_streets(1) + .text(), + "Lancaster Road"); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_onto_streets(1) + .pronunciation() + .alphabet(), + Pronunciation_Alphabet_kIpa); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_onto_streets(1) + .pronunciation() + .value(), + "ˈlæŋkəstər ˈɹoʊd"); + + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations_size(), + 2); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(0) + .text(), + "Granville"); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(0) + .pronunciation() + .alphabet(), + Pronunciation_Alphabet_kIpa); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(0) + .pronunciation() + .value(), + "ˈgɹænvɪl"); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(1) + .text(), + "Lancaster"); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(1) + .pronunciation() + .alphabet(), + Pronunciation_Alphabet_kIpa); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(1) + .pronunciation() + .value(), + "ˈlæŋkəstər"); + + // Verify sign pronunciation instructions + gurka::assert::raw::expect_instructions_at_maneuver_index( + result, maneuver_index, "Take exit 126B onto SR 37/Lancaster Road toward Granville/Lancaster.", + "", "Take exit 126B (/1 26bi/).", + "Take exit 126B (/1 26bi/) onto SR 37 (/ˈsinjər 37/), Lancaster Road (/ˈlæŋkəstər ˈɹoʊd/) toward Granville (/ˈgɹænvɪl/), Lancaster (/ˈlæŋkəstər/).", + ""); + + // Verify street name pronunciation - alphabet & value + ++maneuver_index; + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name_size(), 2); + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name(0).value(), + "Lancaster Road"); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .street_name(0) + .pronunciation() + .alphabet(), + Pronunciation_Alphabet_kIpa); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .street_name(0) + .pronunciation() + .value(), + "ˈlæŋkəstər ˈɹoʊd"); + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name(1).value(), + "SR 37"); + + // Verify street name pronunciation instructions + gurka::assert::raw::expect_instructions_at_maneuver_index( + result, maneuver_index, "Turn right onto Lancaster Road/SR 37.", "Turn right.", + "Turn right onto Lancaster Road (/ˈlæŋkəstər ˈɹoʊd/).", + "Turn right onto Lancaster Road (/ˈlæŋkəstər ˈɹoʊd/), SR 37 (/ˈsinjər 37/).", + "Continue for 400 meters."); +} + +/////////////////////////////////////////////////////////////////////////////// +TEST_F(RouteWithStreetnameAndSignPronunciation, CheckStreetNamesAndSigns2) { + auto result = gurka::do_action(valhalla::Options::route, map, {"G", "J"}, "auto"); + gurka::assert::raw::expect_path(result, {"I 70", "", "Lancaster Road/SR 37"}); + + // Verify starting on I 70 + int maneuver_index = 0; + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name_size(), 1); + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name(0).value(), + "I 70"); + + // Verify sign pronunciations - alphabet & value + ++maneuver_index; + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations_size(), + 2); + + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(0) + .text(), + "I 80"); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(0) + .pronunciation() + .alphabet(), + Pronunciation_Alphabet_kIpa); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(0) + .pronunciation() + .value(), + "aɪ 80"); + + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(1) + .text(), + "Main Street"); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(1) + .pronunciation() + .alphabet(), + Pronunciation_Alphabet_kIpa); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .exit_toward_locations(1) + .pronunciation() + .value(), + "meɪn strit"); + + // Verify sign pronunciation instructions + gurka::assert::raw::expect_instructions_at_maneuver_index( + result, maneuver_index, "Take exit 126B toward I 80/Main Street.", "", + "Take exit 126B (/1 26bi/).", + "Take exit 126B (/1 26bi/) toward I 80 (/aɪ 80/), Main Street (/meɪn strit/).", + ""); +} + +/////////////////////////////////////////////////////////////////////////////// +TEST_F(RouteWithStreetnameAndSignPronunciation, CheckGuideSigns) { + auto result = gurka::do_action(valhalla::Options::route, map, {"J", "O"}, "auto"); + gurka::assert::raw::expect_path(result, {"Lancaster Road/SR 37", "Lancaster Road/SR 37", + "Lancaster Road/SR 37", "", "Granville Road"}); + + // Verify starting on Lancaster Road/SR 37 + int maneuver_index = 0; + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name_size(), 2); + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name(0).value(), + "Lancaster Road"); + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name(01).value(), + "SR 37"); + + // Verify guide sign pronunciations - alphabet & value + ++maneuver_index; + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .guide_onto_streets_size(), + 1); + + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .guide_onto_streets(0) + .text(), + "Granville Road"); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .guide_onto_streets(0) + .pronunciation() + .alphabet(), + Pronunciation_Alphabet_kIpa); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .guide_onto_streets(0) + .pronunciation() + .value(), + "ˈgɹænvɪl ˈɹoʊd"); + + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .guide_toward_locations_size(), + 1); + + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .guide_toward_locations(0) + .text(), + "Granville"); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .guide_toward_locations(0) + .pronunciation() + .alphabet(), + Pronunciation_Alphabet_kIpa); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .guide_toward_locations(0) + .pronunciation() + .value(), + "ˈgɹænvɪl"); + + // Verify guide sign pronunciation instructions + gurka::assert::raw::expect_instructions_at_maneuver_index( + result, maneuver_index, "Turn right toward Granville Road/Granville.", + "Turn right toward Granville Road (/ˈgɹænvɪl ˈɹoʊd/), Granville (/ˈgɹænvɪl/).", + "Turn right toward Granville Road (/ˈgɹænvɪl ˈɹoʊd/).", + "Turn right toward Granville Road (/ˈgɹænvɪl ˈɹoʊd/), Granville (/ˈgɹænvɪl/).", + "Continue for 500 meters."); +} + +/////////////////////////////////////////////////////////////////////////////// +TEST_F(RouteWithStreetnameAndSignPronunciation, CheckJunctionName) { + auto result = gurka::do_action(valhalla::Options::route, map, {"J", "Q"}, "auto"); + gurka::assert::raw::expect_path(result, + {"Lancaster Road/SR 37", "Lancaster Road/SR 37", + "Lancaster Road/SR 37", "Lancaster Road/SR 37", "Granville Road"}); + + // Verify starting on Lancaster Road/SR 37 + int maneuver_index = 0; + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name_size(), 2); + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name(0).value(), + "Lancaster Road"); + EXPECT_EQ(result.directions().routes(0).legs(0).maneuver(maneuver_index).street_name(01).value(), + "SR 37"); + + // Verify guide sign pronunciations - alphabet & value + ++maneuver_index; + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .junction_names_size(), + 1); + + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .junction_names(0) + .text(), + "M Junction"); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .junction_names(0) + .pronunciation() + .alphabet(), + Pronunciation_Alphabet_kIpa); + EXPECT_EQ(result.directions() + .routes(0) + .legs(0) + .maneuver(maneuver_index) + .sign() + .junction_names(0) + .pronunciation() + .value(), + "ɛm ˈʤʌŋkʃən"); + + // Verify junction name pronunciation instructions + gurka::assert::raw::expect_instructions_at_maneuver_index( + result, maneuver_index, "Turn left at M Junction.", + "Turn left at M Junction (/ɛm ˈʤʌŋkʃən/).", + "Turn left at M Junction (/ɛm ˈʤʌŋkʃən/).", + "Turn left at M Junction (/ɛm ˈʤʌŋkʃən/).", + "Continue for 400 meters."); +} diff --git a/test/instructions.cc b/test/instructions.cc index 8341e60350..0a0b6af321 100644 --- a/test/instructions.cc +++ b/test/instructions.cc @@ -5,6 +5,7 @@ #include "baldr/rapidjson_utils.h" #include "odin/directionsbuilder.h" +#include "odin/markup_formatter.h" #include "tyr/serializers.h" #include "proto/api.pb.h" @@ -41,7 +42,7 @@ void test_instructions(const std::string& filename, request.ParseFromString(path_bytes); // Build the directions - valhalla::odin::DirectionsBuilder().Build(request); + valhalla::odin::DirectionsBuilder().Build(request, valhalla::odin::MarkupFormatter()); // Validate routes size int found_routes_size = request.directions().routes_size(); @@ -113,7 +114,7 @@ void test_osrm_maneuver(const std::string& filename, request.mutable_options()->set_format(valhalla::Options_Format_osrm); // Build the directions - valhalla::odin::DirectionsBuilder().Build(request); + valhalla::odin::DirectionsBuilder().Build(request, valhalla::odin::MarkupFormatter()); // Serialize to osrm json string auto json_str = valhalla::tyr::serializeDirections(request); @@ -158,7 +159,7 @@ void test_osrm_destinations(const std::string& filename, request.mutable_options()->set_format(valhalla::Options_Format_osrm); // Build the directions - valhalla::odin::DirectionsBuilder().Build(request); + valhalla::odin::DirectionsBuilder().Build(request, valhalla::odin::MarkupFormatter()); // Serialize to osrm json string auto json_str = valhalla::tyr::serializeDirections(request); diff --git a/test/names.cc b/test/names.cc index f84507c5cb..2a9f1646b3 100644 --- a/test/names.cc +++ b/test/names.cc @@ -11,12 +11,33 @@ using namespace valhalla::baldr; namespace { +void TestKeyTypeValue(const std::string& pronunciation, + uint32_t expected_key, + PronunciationAlphabet expected_type, + const std::string& expected_value) { + + auto* p = const_cast(pronunciation.c_str()); + + size_t pos = 0; + while (pos < strlen(p)) { + const auto& header = *reinterpret_cast(p + pos); + pos += 3; + EXPECT_EQ(header.name_index_, expected_key); + EXPECT_EQ(static_cast(header.phonetic_alphabet_), expected_type); + EXPECT_EQ(std::string((p + pos), header.length_), expected_value); + + pos += header.length_; + } +} + TEST(Names, NamesTest) { OSMWay w1{1234}; OSMWay w2{1234}; OSMWay w3{1234}; + OSMPronunciation pronunciation{}; + std::vector pronunciations; UniqueNames name_offset_map; std::string ref = "I 79 North"; @@ -27,43 +48,94 @@ TEST(Names, NamesTest) { w2.set_ref_index(name_offset_map.index("PA 43")); w3.set_ref_index(name_offset_map.index("PA 272")); + pronunciation.set_name_pronunciation_ipa_index(name_offset_map.index("test name ipa")); + pronunciation.set_name_pronunciation_nt_sampa_index(name_offset_map.index("test name sampa")); + pronunciation.set_name_pronunciation_katakana_index(name_offset_map.index("test name katakana")); + pronunciation.set_name_pronunciation_jeita_index(name_offset_map.index("test name jeita")); + pronunciation.set_ref_pronunciation_ipa_index(name_offset_map.index("test ref ipa")); + pronunciation.set_ref_pronunciation_nt_sampa_index(name_offset_map.index("test ref sampa")); + pronunciation.set_ref_pronunciation_katakana_index(name_offset_map.index("test ref katakana")); + pronunciation.set_ref_pronunciation_jeita_index(name_offset_map.index("test ref jeita")); + w1.set_road_class(RoadClass::kMotorway); w2.set_road_class(RoadClass::kTrunk); w3.set_road_class(RoadClass::kPrimary); uint16_t types; - std::vector w1_names = w1.GetNames(ref, name_offset_map, types); + std::vector w1_names; + w1.GetNames(ref, name_offset_map, pronunciation, types, w1_names, pronunciations); // if road class = kTrunk or kMotorway, then ref comes first. ref from relation overrides // ref from name_offset_map EXPECT_EQ(w1_names.at(0), "I 79 North"); EXPECT_EQ(w1_names.at(1), "William Flynn Highway"); + TestKeyTypeValue(pronunciations.at(0), 0, PronunciationAlphabet::kIpa, "test ref ipa"); + TestKeyTypeValue(pronunciations.at(1), 0, PronunciationAlphabet::kNtSampa, "test ref sampa"); + TestKeyTypeValue(pronunciations.at(2), 0, PronunciationAlphabet::kXKatakana, "test ref katakana"); + TestKeyTypeValue(pronunciations.at(3), 0, PronunciationAlphabet::kXJeita, "test ref jeita"); + TestKeyTypeValue(pronunciations.at(4), 1, PronunciationAlphabet::kIpa, "test name ipa"); + TestKeyTypeValue(pronunciations.at(5), 1, PronunciationAlphabet::kNtSampa, "test name sampa"); + TestKeyTypeValue(pronunciations.at(6), 1, PronunciationAlphabet::kXKatakana, "test name katakana"); + TestKeyTypeValue(pronunciations.at(7), 1, PronunciationAlphabet::kXJeita, "test name jeita"); + EXPECT_EQ(types, 1) << "relation ref failed. ref not in correct position."; - std::vector w2_names = w2.GetNames("", name_offset_map, types); + std::vector w2_names; + pronunciations.clear(); + w2.GetNames("", name_offset_map, pronunciation, types, w2_names, pronunciations); // if road class = kTrunk or kMotorway, then ref comes first. use ref from name_offset_map EXPECT_EQ(w2_names.at(0), "PA 43"); EXPECT_EQ(w2_names.at(1), "Mon/Fayette Expressway"); + TestKeyTypeValue(pronunciations.at(0), 0, PronunciationAlphabet::kIpa, "test ref ipa"); + TestKeyTypeValue(pronunciations.at(1), 0, PronunciationAlphabet::kNtSampa, "test ref sampa"); + TestKeyTypeValue(pronunciations.at(2), 0, PronunciationAlphabet::kXKatakana, "test ref katakana"); + TestKeyTypeValue(pronunciations.at(3), 0, PronunciationAlphabet::kXJeita, "test ref jeita"); + TestKeyTypeValue(pronunciations.at(4), 1, PronunciationAlphabet::kIpa, "test name ipa"); + TestKeyTypeValue(pronunciations.at(5), 1, PronunciationAlphabet::kNtSampa, "test name sampa"); + TestKeyTypeValue(pronunciations.at(6), 1, PronunciationAlphabet::kXKatakana, "test name katakana"); + TestKeyTypeValue(pronunciations.at(7), 1, PronunciationAlphabet::kXJeita, "test name jeita"); + EXPECT_EQ(types, 1) << "ref_map failed. ref not in correct position."; - std::vector w3_names = w3.GetNames("", name_offset_map, types); + std::vector w3_names; + pronunciations.clear(); + w3.GetNames("", name_offset_map, pronunciation, types, w3_names, pronunciations); // if Road class < kTrunk, then name first then ref using ref from name_offset_map EXPECT_EQ(w3_names.at(0), "Lancaster Pike") << "Road class < kTrunk test failed."; EXPECT_EQ(w3_names.at(1), "PA 272") << "Road class < kTrunk test failed."; + TestKeyTypeValue(pronunciations.at(0), 0, PronunciationAlphabet::kIpa, "test name ipa"); + TestKeyTypeValue(pronunciations.at(1), 0, PronunciationAlphabet::kNtSampa, "test name sampa"); + TestKeyTypeValue(pronunciations.at(2), 0, PronunciationAlphabet::kXKatakana, "test name katakana"); + TestKeyTypeValue(pronunciations.at(3), 0, PronunciationAlphabet::kXJeita, "test name jeita"); + TestKeyTypeValue(pronunciations.at(4), 1, PronunciationAlphabet::kIpa, "test ref ipa"); + TestKeyTypeValue(pronunciations.at(5), 1, PronunciationAlphabet::kNtSampa, "test ref sampa"); + TestKeyTypeValue(pronunciations.at(6), 1, PronunciationAlphabet::kXKatakana, "test ref katakana"); + TestKeyTypeValue(pronunciations.at(7), 1, PronunciationAlphabet::kXJeita, "test ref jeita"); + EXPECT_EQ(types, 2) << "Road class < kTrunk test failed. ref not in correct position."; w3_names.clear(); - w3_names = w3.GetNames("PA 555", name_offset_map, types); + pronunciations.clear(); + w3.GetNames("PA 555", name_offset_map, pronunciation, types, w3_names, pronunciations); // if Road class < kTrunk, then name first then ref using ref from relations EXPECT_EQ(w3_names.at(0), "Lancaster Pike") << "ref from relations"; EXPECT_EQ(w3_names.at(1), "PA 555") << "ref from relations"; + TestKeyTypeValue(pronunciations.at(0), 0, PronunciationAlphabet::kIpa, "test name ipa"); + TestKeyTypeValue(pronunciations.at(1), 0, PronunciationAlphabet::kNtSampa, "test name sampa"); + TestKeyTypeValue(pronunciations.at(2), 0, PronunciationAlphabet::kXKatakana, "test name katakana"); + TestKeyTypeValue(pronunciations.at(3), 0, PronunciationAlphabet::kXJeita, "test name jeita"); + TestKeyTypeValue(pronunciations.at(4), 1, PronunciationAlphabet::kIpa, "test ref ipa"); + TestKeyTypeValue(pronunciations.at(5), 1, PronunciationAlphabet::kNtSampa, "test ref sampa"); + TestKeyTypeValue(pronunciations.at(6), 1, PronunciationAlphabet::kXKatakana, "test ref katakana"); + TestKeyTypeValue(pronunciations.at(7), 1, PronunciationAlphabet::kXJeita, "test ref jeita"); + EXPECT_EQ(types, 2) << "Road class < kTrunk test failed(ref from relations). ref not in correct position."; @@ -71,16 +143,62 @@ TEST(Names, NamesTest) { w3.set_official_name_index(name_offset_map.index("LP")); w3.set_name_en_index(name_offset_map.index("LancP")); + pronunciation.set_alt_name_pronunciation_ipa_index(name_offset_map.index("test alt name ipa")); + pronunciation.set_alt_name_pronunciation_nt_sampa_index( + name_offset_map.index("test alt name sampa")); + pronunciation.set_alt_name_pronunciation_katakana_index( + name_offset_map.index("test alt name katakana")); + pronunciation.set_alt_name_pronunciation_jeita_index(name_offset_map.index("test alt name jeita")); + pronunciation.set_official_name_pronunciation_ipa_index( + name_offset_map.index("test official name ipa")); + pronunciation.set_official_name_pronunciation_nt_sampa_index( + name_offset_map.index("test official name sampa")); + pronunciation.set_official_name_pronunciation_katakana_index( + name_offset_map.index("test official name katakana")); + pronunciation.set_official_name_pronunciation_jeita_index( + name_offset_map.index("test official name jeita")); + pronunciation.set_name_en_pronunciation_ipa_index(name_offset_map.index("test name en ipa")); + pronunciation.set_name_en_pronunciation_nt_sampa_index(name_offset_map.index("test name en sampa")); + pronunciation.set_name_en_pronunciation_katakana_index( + name_offset_map.index("test name en katakana")); + pronunciation.set_name_en_pronunciation_jeita_index(name_offset_map.index("test name en jeita")); + w3_names.clear(); - w3_names = w3.GetNames("", name_offset_map, types); + pronunciations.clear(); + w3.GetNames("", name_offset_map, pronunciation, types, w3_names, pronunciations); EXPECT_EQ(types, 2) << "all other names test failed. ref not in correct position."; // all other names should be last. - EXPECT_EQ(w3_names.at(2), "Lanc Pike") << "Alt name failed."; EXPECT_EQ(w3_names.at(3), "LP") << "official name failed."; EXPECT_EQ(w3_names.at(4), "LancP") << "name en failed."; + + TestKeyTypeValue(pronunciations.at(0), 0, PronunciationAlphabet::kIpa, "test name ipa"); + TestKeyTypeValue(pronunciations.at(1), 0, PronunciationAlphabet::kNtSampa, "test name sampa"); + TestKeyTypeValue(pronunciations.at(2), 0, PronunciationAlphabet::kXKatakana, "test name katakana"); + TestKeyTypeValue(pronunciations.at(3), 0, PronunciationAlphabet::kXJeita, "test name jeita"); + TestKeyTypeValue(pronunciations.at(4), 1, PronunciationAlphabet::kIpa, "test ref ipa"); + TestKeyTypeValue(pronunciations.at(5), 1, PronunciationAlphabet::kNtSampa, "test ref sampa"); + TestKeyTypeValue(pronunciations.at(6), 1, PronunciationAlphabet::kXKatakana, "test ref katakana"); + TestKeyTypeValue(pronunciations.at(7), 1, PronunciationAlphabet::kXJeita, "test ref jeita"); + TestKeyTypeValue(pronunciations.at(8), 2, PronunciationAlphabet::kIpa, "test alt name ipa"); + TestKeyTypeValue(pronunciations.at(9), 2, PronunciationAlphabet::kNtSampa, "test alt name sampa"); + TestKeyTypeValue(pronunciations.at(10), 2, PronunciationAlphabet::kXKatakana, + "test alt name katakana"); + TestKeyTypeValue(pronunciations.at(11), 2, PronunciationAlphabet::kXJeita, "test alt name jeita"); + TestKeyTypeValue(pronunciations.at(12), 3, PronunciationAlphabet::kIpa, "test official name ipa"); + TestKeyTypeValue(pronunciations.at(13), 3, PronunciationAlphabet::kNtSampa, + "test official name sampa"); + TestKeyTypeValue(pronunciations.at(14), 3, PronunciationAlphabet::kXKatakana, + "test official name katakana"); + TestKeyTypeValue(pronunciations.at(15), 3, PronunciationAlphabet::kXJeita, + "test official name jeita"); + TestKeyTypeValue(pronunciations.at(16), 4, PronunciationAlphabet::kIpa, "test name en ipa"); + TestKeyTypeValue(pronunciations.at(17), 4, PronunciationAlphabet::kNtSampa, "test name en sampa"); + TestKeyTypeValue(pronunciations.at(18), 4, PronunciationAlphabet::kXKatakana, + "test name en katakana"); + TestKeyTypeValue(pronunciations.at(19), 4, PronunciationAlphabet::kXJeita, "test name en jeita"); } TEST(Names, TaggedNamesTest) { @@ -88,6 +206,9 @@ TEST(Names, TaggedNamesTest) { OSMWay w1{1234}; OSMWay w2{1234}; + OSMPronunciation pronunciation1{}, pronunciation2{}; + std::vector pronunciations; + UniqueNames name_offset_map; w1.set_tunnel_name_index(name_offset_map.index("Ted Williams Tunnel")); @@ -95,11 +216,44 @@ TEST(Names, TaggedNamesTest) { w1.set_road_class(RoadClass::kMotorway); w2.set_road_class(RoadClass::kMotorway); - std::vector w1_tagged_values = w1.GetTaggedValues(name_offset_map); - EXPECT_EQ(w1_tagged_values.at(0), "1Ted Williams Tunnel"); - - std::vector w2_tagged_values = w2.GetTaggedValues(name_offset_map); - EXPECT_EQ(w2_tagged_values.at(0), "1Fort McHenry Tunnel"); + pronunciation1.set_tunnel_name_pronunciation_ipa_index(name_offset_map.index("tɛd ˈwɪljəmz ˈtʌnl")); + pronunciation1.set_tunnel_name_pronunciation_nt_sampa_index( + name_offset_map.index("tEd wIly@mz t@n@l")); + pronunciation1.set_tunnel_name_pronunciation_katakana_index( + name_offset_map.index("テッド ウィリャムズ タネル")); + pronunciation1.set_tunnel_name_pronunciation_jeita_index( + name_offset_map.index("チバダ'イガ&ク% セーモンマ'エ.")); + + pronunciation2.set_tunnel_name_pronunciation_ipa_index(name_offset_map.index("fɔːt McHenry ˈtʌnl")); + pronunciation2.set_tunnel_name_pronunciation_nt_sampa_index( + name_offset_map.index("fOrt m@kEnri t@n@l")); + pronunciation2.set_tunnel_name_pronunciation_katakana_index( + name_offset_map.index("フォート ムケンリー タネル")); + pronunciation2.set_tunnel_name_pronunciation_jeita_index( + name_offset_map.index("チバダ'イガ&ク% セーモンマ'エ.")); + + std::vector w1_tagged_names; + w1.GetTaggedValues(name_offset_map, pronunciation1, 0, w1_tagged_names, pronunciations); + EXPECT_EQ(w1_tagged_names.at(0), "1Ted Williams Tunnel"); + TestKeyTypeValue(pronunciations.at(0), 0, PronunciationAlphabet::kIpa, "tɛd ˈwɪljəmz ˈtʌnl"); + TestKeyTypeValue(pronunciations.at(1), 0, PronunciationAlphabet::kNtSampa, "tEd wIly@mz t@n@l"); + TestKeyTypeValue(pronunciations.at(2), 0, PronunciationAlphabet::kXKatakana, + "テッド ウィリャムズ タネル"); + TestKeyTypeValue(pronunciations.at(3), 0, PronunciationAlphabet::kXJeita, + "チバダ'イガ&ク% セーモンマ'エ."); + + pronunciations.clear(); + std::vector w2_tagged_names; + w2_tagged_names.emplace_back("test name"); // testing pronunciation index + + w2.GetTaggedValues(name_offset_map, pronunciation2, 0, w2_tagged_names, pronunciations); + EXPECT_EQ(w2_tagged_names.at(1), "1Fort McHenry Tunnel"); + TestKeyTypeValue(pronunciations.at(0), 1, PronunciationAlphabet::kIpa, "fɔːt McHenry ˈtʌnl"); + TestKeyTypeValue(pronunciations.at(1), 1, PronunciationAlphabet::kNtSampa, "fOrt m@kEnri t@n@l"); + TestKeyTypeValue(pronunciations.at(2), 1, PronunciationAlphabet::kXKatakana, + "フォート ムケンリー タネル"); + TestKeyTypeValue(pronunciations.at(3), 1, PronunciationAlphabet::kXJeita, + "チバダ'イガ&ク% セーモンマ'エ."); } } // namespace diff --git a/test/narrativebuilder.cc b/test/narrativebuilder.cc index e93405a136..da6e61d11b 100644 --- a/test/narrativebuilder.cc +++ b/test/narrativebuilder.cc @@ -5,6 +5,7 @@ #include "odin/enhancedtrippath.h" #include "odin/maneuver.h" +#include "odin/markup_formatter.h" #include "odin/narrative_builder_factory.h" #include "odin/narrative_dictionary.h" #include "odin/narrativebuilder.h" @@ -34,7 +35,7 @@ class NarrativeBuilderTest : public NarrativeBuilder { NarrativeBuilderTest(const Options& options, const NarrativeDictionary& dictionary, const EnhancedTripLeg* trip_path = nullptr) - : NarrativeBuilder(options, trip_path, dictionary) { + : NarrativeBuilder(options, trip_path, dictionary, MarkupFormatter()) { } std::string FormRampStraightInstruction(Maneuver& maneuver) { @@ -58,7 +59,7 @@ class NarrativeBuilderTest : public NarrativeBuilder { element_max_count, delim); } - std::string FormVerbalMultiCue(Maneuver* maneuver, Maneuver& next_maneuver) { + std::string FormVerbalMultiCue(Maneuver& maneuver, Maneuver& next_maneuver) { return NarrativeBuilder::FormVerbalMultiCue(maneuver, next_maneuver); } }; @@ -278,7 +279,8 @@ void TryBuild(const Options& options, std::list& maneuvers, std::list& expected_maneuvers, const EnhancedTripLeg* etp = nullptr) { - std::unique_ptr narrative_builder = NarrativeBuilderFactory::Create(options, etp); + std::unique_ptr narrative_builder = + NarrativeBuilderFactory::Create(options, etp, MarkupFormatter()); narrative_builder->Build(maneuvers); // Check maneuver list sizes @@ -8978,7 +8980,7 @@ void TryFormVerbalMultiCue(NarrativeBuilderTest& nbt, Maneuver current_maneuver, Maneuver next_maneuver, const std::string& expected) { - EXPECT_EQ(nbt.FormVerbalMultiCue(¤t_maneuver, next_maneuver), expected); + EXPECT_EQ(nbt.FormVerbalMultiCue(current_maneuver, next_maneuver), expected); } TEST(NarrativeBuilder, TestFormVerbalMultiCue) { diff --git a/test/node_search.cc b/test/node_search.cc index 3949024cea..ea2466906f 100644 --- a/test/node_search.cc +++ b/test/node_search.cc @@ -260,7 +260,7 @@ void graph_builder::write_tiles(uint8_t level) const { // make more complex edge geom so that there are 3 segments, affine // combination doesnt properly handle arcs but who cares edge_info_offset = tile.AddEdgeInfo(edge_index, e.first, e.second, 123, 456, 0, 55, shape, - {std::to_string(edge_index)}, {}, 0, add); + {std::to_string(edge_index)}, {}, {}, 0, add); } edge_builder.set_edgeinfo_offset(edge_info_offset); diff --git a/test/search.cc b/test/search.cc index 68179e6c54..1ce7f39567 100644 --- a/test/search.cc +++ b/test/search.cc @@ -96,10 +96,11 @@ void make_tile() { bool added; // make more complex edge geom so that there are 3 segments, affine combination doesnt properly // handle arcs but who cares - uint32_t edge_info_offset = tile.AddEdgeInfo(localedgeidx, u.first, v.first, 123, // way_id - 0, 0, - 120, // speed limit in kph - shape, {std::to_string(localedgeidx)}, {}, 0, added); + uint32_t edge_info_offset = + tile.AddEdgeInfo(localedgeidx, u.first, v.first, 123, // way_id + 0, 0, + 120, // speed limit in kph + shape, {std::to_string(localedgeidx)}, {}, {}, 0, added); // assert(added); edge_builder.set_edgeinfo_offset(edge_info_offset); tile.directededges().emplace_back(edge_builder); diff --git a/test/signinfo.cc b/test/signinfo.cc index 82a5bb2031..87cec08c1d 100644 --- a/test/signinfo.cc +++ b/test/signinfo.cc @@ -19,6 +19,8 @@ TEST(Signinfo, ExitToTest) { OSMWay way{}; OSMData osmdata{}; + OSMPronunciation pronunciation{}; + bool fork = false; bool forward = true; @@ -26,8 +28,9 @@ TEST(Signinfo, ExitToTest) { exit_node.set_name_index(osmdata.node_names.index("PATP West Exit")); std::vector signs; - bool has_guide = - GraphBuilder::CreateSignInfoList(exit_node, way, osmdata, signs, fork, forward, true, false); + std::vector pronunciations; + bool has_guide = GraphBuilder::CreateSignInfoList(exit_node, way, pronunciation, osmdata, signs, + pronunciations, fork, forward, true, false); EXPECT_FALSE(has_guide) << "Exits should not be Guides"; @@ -42,7 +45,8 @@ TEST(Signinfo, ExitToTest) { node.set_exit_to_index(osmdata.node_names.index("US 11;To I 81;Carlisle;Harrisburg")); signs.clear(); - has_guide = GraphBuilder::CreateSignInfoList(node, way, osmdata, signs, fork, forward, true, false); + has_guide = GraphBuilder::CreateSignInfoList(node, way, pronunciation, osmdata, signs, + pronunciations, fork, forward, true, false); EXPECT_FALSE(has_guide) << "Exits should not be Guides"; @@ -62,7 +66,8 @@ TEST(Signinfo, ExitToTest) { signs.clear(); node.set_exit_to_index(osmdata.node_names.index("US 11;Toward I 81;Carlisle;Harrisburg")); - has_guide = GraphBuilder::CreateSignInfoList(node, way, osmdata, signs, fork, forward, true, false); + has_guide = GraphBuilder::CreateSignInfoList(node, way, pronunciation, osmdata, signs, + pronunciations, fork, forward, true, false); EXPECT_FALSE(has_guide) << "Exits should not be Guides"; @@ -82,7 +87,8 @@ TEST(Signinfo, ExitToTest) { signs.clear(); node.set_exit_to_index(osmdata.node_names.index("I 95 To I 695")); - has_guide = GraphBuilder::CreateSignInfoList(node, way, osmdata, signs, fork, forward, true, false); + has_guide = GraphBuilder::CreateSignInfoList(node, way, pronunciation, osmdata, signs, + pronunciations, fork, forward, true, false); EXPECT_FALSE(has_guide) << "Exits should not be Guides"; @@ -98,7 +104,8 @@ TEST(Signinfo, ExitToTest) { signs.clear(); node.set_exit_to_index(osmdata.node_names.index("I 495 Toward I 270")); - has_guide = GraphBuilder::CreateSignInfoList(node, way, osmdata, signs, fork, forward, true, false); + has_guide = GraphBuilder::CreateSignInfoList(node, way, pronunciation, osmdata, signs, + pronunciations, fork, forward, true, false); EXPECT_FALSE(has_guide) << "Exits should not be Guides"; @@ -115,7 +122,8 @@ TEST(Signinfo, ExitToTest) { node.set_exit_to_index( osmdata.node_names.index("I 495 Toward I 270 To I 95")); // default to toward. Punt on parsing. - has_guide = GraphBuilder::CreateSignInfoList(node, way, osmdata, signs, fork, forward, true, false); + has_guide = GraphBuilder::CreateSignInfoList(node, way, pronunciation, osmdata, signs, + pronunciations, fork, forward, true, false); EXPECT_FALSE(has_guide) << "Exits should not be Guides"; @@ -132,7 +140,8 @@ TEST(Signinfo, ExitToTest) { signs.clear(); auto index = osmdata.name_offset_map.index("I 495 North"); way.set_destination_ref_index(index); - has_guide = GraphBuilder::CreateSignInfoList(node, way, osmdata, signs, fork, forward, true, false); + has_guide = GraphBuilder::CreateSignInfoList(node, way, pronunciation, osmdata, signs, + pronunciations, fork, forward, true, false); EXPECT_FALSE(has_guide) << "Exits should not be Guides"; @@ -148,7 +157,8 @@ TEST(Signinfo, ExitToTest) { signs.clear(); index = osmdata.name_offset_map.index("I 495 North"); way.set_destination_ref_index(index); - has_guide = GraphBuilder::CreateSignInfoList(node, way, osmdata, signs, fork, forward, false, true); + has_guide = GraphBuilder::CreateSignInfoList(node, way, pronunciation, osmdata, signs, + pronunciations, fork, forward, false, true); EXPECT_TRUE(has_guide) << "Guides should not be Exits"; @@ -166,8 +176,8 @@ TEST(Signinfo, ExitToTest) { signs.clear(); auto index2 = osmdata.name_offset_map.index("I 695 North"); way2.set_destination_ref_to_index(index2); - has_guide = - GraphBuilder::CreateSignInfoList(node, way2, osmdata, signs, fork, forward, true, false); + has_guide = GraphBuilder::CreateSignInfoList(node, way2, pronunciation, osmdata, signs, + pronunciations, fork, forward, true, false); EXPECT_FALSE(has_guide) << "Exits should not be Guides"; @@ -185,8 +195,8 @@ TEST(Signinfo, ExitToTest) { signs.clear(); auto index3 = osmdata.name_offset_map.index("I 695 North"); way3.set_destination_ref_to_index(index3); - has_guide = - GraphBuilder::CreateSignInfoList(node, way2, osmdata, signs, fork, forward, false, true); + has_guide = GraphBuilder::CreateSignInfoList(node, way2, pronunciation, osmdata, signs, + pronunciations, fork, forward, false, true); EXPECT_TRUE(has_guide) << "Guides should not be Exits"; @@ -202,8 +212,8 @@ TEST(Signinfo, ExitToTest) { // Add a ref toward guide sign and we should not add a exit number or exit name. note: using // exit_node signs.clear(); - has_guide = - GraphBuilder::CreateSignInfoList(exit_node, way2, osmdata, signs, fork, forward, false, true); + has_guide = GraphBuilder::CreateSignInfoList(exit_node, way2, pronunciation, osmdata, signs, + pronunciations, fork, forward, false, true); EXPECT_TRUE(has_guide) << "Guides should not be Exits"; diff --git a/test/turnlanes.cc b/test/turnlanes.cc index cddb405e6e..efd5ade3da 100644 --- a/test/turnlanes.cc +++ b/test/turnlanes.cc @@ -9,6 +9,7 @@ #include "baldr/turnlanes.h" #include "odin/directionsbuilder.h" #include "odin/enhancedtrippath.h" +#include "odin/markup_formatter.h" #include "proto/api.pb.h" #include "proto/directions.pb.h" @@ -94,7 +95,8 @@ void test_turn_lanes(const std::string& filename, request.ParseFromString(path_bytes); // Build the directions - valhalla::odin::DirectionsBuilder().Build(request); + + valhalla::odin::DirectionsBuilder().Build(request, valhalla::odin::MarkupFormatter()); // Validate routes size int found_routes_size = request.directions().routes_size(); diff --git a/test/utrecht.cc b/test/utrecht.cc index f22106d083..0db6901bec 100644 --- a/test/utrecht.cc +++ b/test/utrecht.cc @@ -25,6 +25,7 @@ namespace { std::string ways_file = "test_ways_utrecht.bin"; std::string way_nodes_file = "test_way_nodes_utrecht.bin"; std::string access_file = "test_access_utrecht.bin"; +std::string pronunciation_file = "test_pronunciation_utrecht.bin"; std::string from_restriction_file = "test_from_complex_restrictions_utrecht.bin"; std::string to_restriction_file = "test_to_complex_restrictions_utrecht.bin"; std::string bss_file = "test_bss_nodes_utrecht.bin"; @@ -220,7 +221,7 @@ class UtrecthTestSuiteEnv : public ::testing::Environment { auto osmdata = PBFGraphParser::ParseWays(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/utrecht_netherlands.osm.pbf"}, - ways_file, way_nodes_file, access_file); + ways_file, way_nodes_file, access_file, pronunciation_file); PBFGraphParser::ParseRelations(conf.get_child("mjolnir"), {VALHALLA_SOURCE_DIR "test/data/utrecht_netherlands.osm.pbf"}, diff --git a/test_requests/pronunciation_routes.txt b/test_requests/pronunciation_routes.txt new file mode 100644 index 0000000000..13e3b9f603 --- /dev/null +++ b/test_requests/pronunciation_routes.txt @@ -0,0 +1,8 @@ +-j '{"locations":[{"lat":40.057797,"lon":-82.517046,"street":"SR 16 West"},{"lat":40.060501,"lon":-82.520764,"street":"Lancaster Road"}],"costing":"auto","units":"miles"}' +-j '{"locations":[{"lat":40.057797,"lon":-82.517046,"street":"SR 16 West"},{"lat":40.058391,"lon":-82.521000,"street":"Lancaster Road"}],"costing":"auto","units":"miles"}' +-j '{"locations":[{"lat":39.943025,"lon":-82.551958,"street":"I 70"},{"lat":39.934822,"lon":-82.539345,"street":"Lancaster Road SW"}],"costing":"auto","units":"miles"}' +-j '{"locations":[{"lat":39.942137,"lon":-82.520094,"street":"I 70"},{"lat":39.936856,"lon":-82.537775,"street":"Lancaster Road SW"}],"costing":"auto","units":"miles"}' +-j '{"locations":[{"lat":40.727023,"lon":-74.001935,"street":"Sullivan Street"},{"lat":40.725950,"lon":-73.999626,"street":"Wooster Street"}],"costing":"auto","units":"miles"}' +-j '{"locations":[{"lat":40.727848,"lon":-74.003063,"street":"6th Avenue"},{"lat":40.727775,"lon":-74.001719,"street":"West Houston Street"}],"costing":"auto","units":"miles"}' +-j '{"locations":[{"lat":40.724937,"lon":-73.994538,"street":"East Houston Street"},{"lat":40.726596,"lon":-73.999007,"street":"West Houston Street"}],"costing":"auto","units":"miles"}' +-j '{"locations":[{"lat":47.399340,"lon":8.505593,"street":"Ottenbergstrasse"},{"lat":47.399557,"lon":8.504730,"street":"Limmattalstrasse"}],"costing":"auto","units":"kilometers"}' diff --git a/valhalla/baldr/edgeinfo.h b/valhalla/baldr/edgeinfo.h index e728c8ed2f..ed1506f414 100644 --- a/valhalla/baldr/edgeinfo.h +++ b/valhalla/baldr/edgeinfo.h @@ -36,7 +36,7 @@ struct NameInfo { // phonetic string, etc. uint32_t is_route_num_ : 1; // Flag used to indicate if this is a route number // vs just a name. - uint32_t tagged_ : 1; // Future use - this indicates the text string is + uint32_t tagged_ : 1; // This indicates the text string is // specially tagged (for example uses the first char as // the tag type). To make this forward and backward // compatible, tagged text will not be read in GetNames @@ -53,6 +53,15 @@ struct NameInfo { } }; +struct linguistic_text_header_t { + uint32_t language_ : 8; // this is just the language as we will derive locale by getting admin info + uint32_t length_ : 8; // pronunciation length + uint32_t phonetic_alphabet_ : 3; + uint32_t name_index_ : 4; // what name is this pronunciation for + uint32_t spare_ : 1; + uint32_t DO_NOT_USE_ : 8; // DONT EVER USE THIS WE DON'T ACTUALLY STORE IT IN THE TEXT LIST +}; + /** * Edge information not required in shortest path algorithm and is * common among the 2 directions. @@ -143,10 +152,12 @@ class EdgeInfo { std::vector GetNames() const; /** - * Convenience method to get the tagged values for an edge - * @return Returns a list (vector) of tagged values. + * Convenience method to get the names for an edge + * @param only_pronunciations Bool indicating whether or not to return only the pronunciations + * + * @return Returns a list (vector) of tagged names. */ - std::vector GetTaggedValues() const; + std::vector GetTaggedValues(bool only_pronunciations = false) const; /** * Convenience method to get the names and route number flags for an edge. @@ -154,8 +165,8 @@ class EdgeInfo { * * @return Returns a list (vector) of name/route number pairs. */ - std::vector> - GetNamesAndTypes(bool include_tagged_values = false) const; + std::vector> GetNamesAndTypes(std::vector& types, + bool include_tagged_names = false) const; /** * Convenience method to get tags of the edge. @@ -164,6 +175,13 @@ class EdgeInfo { */ const std::multimap& GetTags() const; + /** + * Convenience method to get a pronunciation map for an edge. + * @return Returns a unordered_map of type/name pairs with a key that references the name + * index from GetNamesAndTypes + */ + std::unordered_map> GetPronunciationsMap() const; + /** * Convenience method to get the types for the names. * @return Returns types - If a bit is set, it is a route number. @@ -220,8 +238,6 @@ class EdgeInfo { }; protected: - std::vector GetTaggedValuesOrNames(bool only_tagged_values) const; - // Fixed size information EdgeInfoInner ei_; diff --git a/valhalla/baldr/graphconstants.h b/valhalla/baldr/graphconstants.h index 5c680791c7..df91d1a90a 100644 --- a/valhalla/baldr/graphconstants.h +++ b/valhalla/baldr/graphconstants.h @@ -359,12 +359,23 @@ inline std::string to_string(Use u) { enum class TaggedValue : uint8_t { // must start at 1 due to nulls kLayer = 1, + kPronunciation = 2, // we used to have bug when we encoded 1 and 2 as their ASCII codes, but not actual 1 and 2 values // see https://github.com/valhalla/valhalla/issues/3262 kTunnel = static_cast('1'), kBridge = static_cast('2'), }; +enum class PronunciationAlphabet : uint8_t { + kNone = 0, + kIpa = 1, + kXKatakana = 2, + kXJeita = 3, + kNtSampa = 4 +}; +// must start at 1 due to nulls +enum class Language : uint8_t { kNone = 1 }; + // Speed type enum class SpeedType : uint8_t { kTagged = 0, // Tagged maximum speed diff --git a/valhalla/baldr/graphtile.h b/valhalla/baldr/graphtile.h index acb5a6d665..c22d0d8ea0 100644 --- a/valhalla/baldr/graphtile.h +++ b/valhalla/baldr/graphtile.h @@ -348,6 +348,7 @@ class GraphTile { /** * Convenience method to get the names for an edge * @param edge Directed edge + * * @return Returns a list (vector) of names. */ std::vector GetNames(const DirectedEdge* edge) const; @@ -381,6 +382,16 @@ class GraphTile { */ std::string GetName(const uint32_t textlist_offset) const; + /** + * Convenience method to process the signs for an edge given the directed + * edge index. + * @param idx Directed edge or node index. Used to lookup list of signs. + * @param signs_on_node Are we looking for signs at the node? These are the + * intersection names. + * @return Returns a list (vector) of signs. + */ + std::vector ProcessSigns(const uint32_t idx, bool signs_on_node = false) const; + /** * Convenience method to get the signs for an edge given the directed * edge index. @@ -389,7 +400,10 @@ class GraphTile { * intersection names. * @return Returns a list (vector) of signs. */ - std::vector GetSigns(const uint32_t idx, bool signs_on_node = false) const; + std::vector + GetSigns(const uint32_t idx, + std::unordered_map>& index_pronunciation_map, + bool signs_on_node = false) const; /** * Get the next departure given the directed edge Id and the current diff --git a/valhalla/baldr/pronunciation.h b/valhalla/baldr/pronunciation.h new file mode 100644 index 0000000000..484ac7d897 --- /dev/null +++ b/valhalla/baldr/pronunciation.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include + +#include + +namespace valhalla { +namespace baldr { + +class Pronunciation { +public: + /** + * Constructor. + * @param alphabet the phonetic alphabet. + * @param value text string with the pronunciation. + */ + Pronunciation(const valhalla::Pronunciation_Alphabet alphabet, const std::string& value); + + /** + * Returns the phonetic alphabet. + * @return the phonetic alphabet. + */ + valhalla::Pronunciation_Alphabet alphabet() const; + + /** + * Returns the pronunciation value. + * @return Returns the pronunciation value as a const reference to the text string. + */ + const std::string& value() const; + +protected: + valhalla::Pronunciation_Alphabet alphabet_; + std::string value_; +}; + +} // namespace baldr +} // namespace valhalla diff --git a/valhalla/baldr/sign.h b/valhalla/baldr/sign.h index 0724bcdba3..f4126a951a 100644 --- a/valhalla/baldr/sign.h +++ b/valhalla/baldr/sign.h @@ -25,7 +25,8 @@ class Sign { kGuideToward, kJunctionName, kGuidanceViewJunction, - kGuidanceViewSignboard + kGuidanceViewSignboard, + kPronunciation = 255 }; /** @@ -36,8 +37,12 @@ class Sign { * view type. * @param text_offset Offset to text in the names/text table. */ - Sign(const uint32_t idx, const Sign::Type& type, const bool rn_type, const uint32_t text_offset) - : index_(idx), type_(static_cast(type)), route_num_type_(rn_type), tagged_(0), + Sign(const uint32_t idx, + const Sign::Type& type, + const bool rn_type, + const bool tagged, + const uint32_t text_offset) + : index_(idx), type_(static_cast(type)), route_num_type_(rn_type), tagged_(tagged), text_offset_(text_offset) { } @@ -67,8 +72,8 @@ class Sign { } /** - * Does this sign record indicate a route number or the guidance view type. - * @return Returns true if the sign record is a route number or if this is a + * Does this sign record indicate a route number, phoneme for a node, or the guidance view type + * @return Returns true if the sign record is a route number, phoneme for a node, or if this is a * guidance view sign returning true indicates that we are a base image and false * if we are a overlay image */ @@ -77,7 +82,7 @@ class Sign { } /** - * Is the sign text tagged (Future use for special tagging such as language code) + * Is the sign text tagged * @return Returns true if the sign text is tagged. */ bool tagged() const { @@ -106,9 +111,7 @@ class Sign { uint32_t index_ : 22; // kMaxTileEdgeCount in nodeinfo.h: 22 bits uint32_t type_ : 8; uint32_t route_num_type_ : 1; - uint32_t tagged_ : 1; // For future use to support "tagged" text strings. - // Similar to EdgeInfo, for compatibility any tagged strings - // will be skipped until code is available to properly use them. + uint32_t tagged_ : 1; uint32_t text_offset_; }; diff --git a/valhalla/baldr/signinfo.h b/valhalla/baldr/signinfo.h index 7fe13a49a9..bff0d21aa3 100644 --- a/valhalla/baldr/signinfo.h +++ b/valhalla/baldr/signinfo.h @@ -19,8 +19,31 @@ class SignInfo { * @param rn Bool indicating if this sign is a route number. * @param text Text string. */ - SignInfo(const Sign::Type& type, const bool rn, const std::string& text) - : type_(type), is_route_num_(rn), text_(text) { + SignInfo(const Sign::Type& type, + const bool rn, + const bool tagged, + const bool has_phoneme, + const uint32_t phoneme_start_index, + const uint32_t phoneme_count, + const std::string& text) + : phoneme_start_index_(phoneme_start_index), phoneme_count_(phoneme_count), type_(type), + is_route_num_(rn), is_tagged_(tagged), has_phoneme_(has_phoneme), text_(text) { + } + + /** + * Returns the phoneme start index. + * @return Returns the phoneme start index. + */ + uint32_t phoneme_start_index() const { + return phoneme_start_index_; + } + + /** + * Returns the phoneme count. + * @return Returns the phoneme count. + */ + uint32_t phoneme_count() const { + return phoneme_count_; } /** @@ -39,6 +62,22 @@ class SignInfo { return is_route_num_; } + /** + * Is the sign text tagged + * @return Returns true if the sign text is tagged. + */ + bool is_tagged() const { + return is_tagged_; + } + + /** + * Does the sign have a phoneme? + * @return Returns true the sign has a phoneme? + */ + bool has_phoneme() const { + return has_phoneme_; + } + /** * Returns the sign text. * @return Returns the sign text as a const reference to the text string. @@ -47,9 +86,19 @@ class SignInfo { return text_; } + // operator < - for sorting. Sort by type. + bool operator<(const SignInfo& other) const { + return type() < other.type(); + } + protected: + uint32_t phoneme_start_index_; + uint32_t phoneme_count_; Sign::Type type_; bool is_route_num_; + bool is_tagged_; + bool has_phoneme_; + std::string text_; }; diff --git a/valhalla/baldr/streetname.h b/valhalla/baldr/streetname.h index 3476ada233..e4dffc92ec 100644 --- a/valhalla/baldr/streetname.h +++ b/valhalla/baldr/streetname.h @@ -4,6 +4,10 @@ #include #include +#include + +#include + namespace valhalla { namespace baldr { @@ -12,9 +16,12 @@ class StreetName { /** * Constructor. * @param value Street name string. - * @param is_route_number boolean indicating if street name is a reference route number. + * @param is_route_number boolean indicating if street name is a reference route number. + * @param pronunciation the pronunciation of this street name. */ - StreetName(const std::string& value, const bool is_route_number); + StreetName(const std::string& value, + const bool is_route_number, + const boost::optional& pronunciation = boost::none); virtual ~StreetName(); @@ -26,6 +33,12 @@ class StreetName { */ bool is_route_number() const; + /** + * Returns the pronunciation of this street name. + * @return the pronunciation of this street name. + */ + const boost::optional& pronunciation() const; + bool operator==(const StreetName& rhs) const; bool StartsWith(const std::string& prefix) const; @@ -45,6 +58,7 @@ class StreetName { protected: std::string value_; bool is_route_number_; + boost::optional pronunciation_; }; } // namespace baldr diff --git a/valhalla/baldr/streetname_us.h b/valhalla/baldr/streetname_us.h index dfd371ca37..4e62aafa31 100644 --- a/valhalla/baldr/streetname_us.h +++ b/valhalla/baldr/streetname_us.h @@ -1,12 +1,15 @@ #ifndef VALHALLA_BALDR_STREETNAME_US_H_ #define VALHALLA_BALDR_STREETNAME_US_H_ -#include - #include #include #include +#include + +#include +#include + namespace valhalla { namespace baldr { @@ -16,8 +19,11 @@ class StreetNameUs : public StreetName { * Constructor. * @param value Street name string. * @param is_route_number boolean indicating if street name is a reference route number. + * @param pronunciation the pronunciation of this street name. */ - StreetNameUs(const std::string& value, const bool is_route_number); + StreetNameUs(const std::string& value, + const bool is_route_number, + const boost::optional& pronunciation = boost::none); std::string GetPreDir() const override; diff --git a/valhalla/baldr/streetnames.h b/valhalla/baldr/streetnames.h index 14002674fc..b94c02efe8 100644 --- a/valhalla/baldr/streetnames.h +++ b/valhalla/baldr/streetnames.h @@ -9,6 +9,7 @@ #include #include #include +#include namespace valhalla { namespace baldr { @@ -19,6 +20,8 @@ class StreetNames : public std::list> { StreetNames(const std::vector>& names); + StreetNames(const google::protobuf::RepeatedPtrField& names); + virtual ~StreetNames(); std::string ToString(uint32_t max_count = 0, diff --git a/valhalla/baldr/streetnames_factory.h b/valhalla/baldr/streetnames_factory.h index 6ef5c70ebb..f183c51495 100644 --- a/valhalla/baldr/streetnames_factory.h +++ b/valhalla/baldr/streetnames_factory.h @@ -6,6 +6,7 @@ #include #include +#include namespace valhalla { namespace baldr { @@ -16,6 +17,10 @@ class StreetNamesFactory { static std::unique_ptr Create(const std::string& country_code, const std::vector>& names); + + static std::unique_ptr + Create(const std::string& country_code, + const google::protobuf::RepeatedPtrField& names); }; } // namespace baldr diff --git a/valhalla/baldr/streetnames_us.h b/valhalla/baldr/streetnames_us.h index 0a41c697ae..e7fe175020 100644 --- a/valhalla/baldr/streetnames_us.h +++ b/valhalla/baldr/streetnames_us.h @@ -6,6 +6,7 @@ #include #include +#include namespace valhalla { namespace baldr { @@ -16,6 +17,8 @@ class StreetNamesUs : public StreetNames { StreetNamesUs(const std::vector>& names); + StreetNamesUs(const google::protobuf::RepeatedPtrField& names); + ~StreetNamesUs(); std::unique_ptr clone() const override; diff --git a/valhalla/baldr/verbal_text_formatter.h b/valhalla/baldr/verbal_text_formatter.h index edde6b7db3..bb7255c0ce 100644 --- a/valhalla/baldr/verbal_text_formatter.h +++ b/valhalla/baldr/verbal_text_formatter.h @@ -4,6 +4,8 @@ #include #include +#include + namespace valhalla { namespace baldr { @@ -24,9 +26,12 @@ class VerbalTextFormatter { * Returns a text-to-speech formatted string based on the specified text. * * @param text the source string to transform. + * @param markup_string the optional markup string that should be used. + * * @return a text-to-speech formatted string based on the specified text. */ - virtual std::string Format(const std::string& text) const; + virtual std::string Format(const std::string& text, + const boost::optional& markup_string = boost::none) const; protected: virtual std::string ProcessNumberSplitMatch(const std::smatch& m) const; diff --git a/valhalla/baldr/verbal_text_formatter_us.h b/valhalla/baldr/verbal_text_formatter_us.h index 4c694b3802..73a2ccfb0a 100644 --- a/valhalla/baldr/verbal_text_formatter_us.h +++ b/valhalla/baldr/verbal_text_formatter_us.h @@ -1,13 +1,15 @@ #ifndef VALHALLA_BALDR_VERBAL_TEXT_FORMATTER_US_H_ #define VALHALLA_BALDR_VERBAL_TEXT_FORMATTER_US_H_ -#include - #include #include #include #include +#include + +#include + namespace valhalla { namespace baldr { @@ -121,9 +123,12 @@ class VerbalTextFormatterUs : public VerbalTextFormatter { * Returns a US text-to-speech formatted string based on the specified text. * * @param text the source string to transform. + * @param markup_string the optional markup string that should be used. + * * @return a US text-to-speech formatted string based on the specified text. */ - std::string Format(const std::string& text) const override; + std::string Format(const std::string& text, + const boost::optional& markup_string = boost::none) const override; protected: std::string ProcessNumberSplitMatch(const std::smatch& m) const override; diff --git a/valhalla/baldr/verbal_text_formatter_us_tx.h b/valhalla/baldr/verbal_text_formatter_us_tx.h index 88468a4db8..df2c48f07c 100644 --- a/valhalla/baldr/verbal_text_formatter_us_tx.h +++ b/valhalla/baldr/verbal_text_formatter_us_tx.h @@ -1,12 +1,14 @@ #ifndef VALHALLA_BALDR_VERBAL_TEXT_FORMATTER_US_TX_H_ #define VALHALLA_BALDR_VERBAL_TEXT_FORMATTER_US_TX_H_ -#include - #include #include #include +#include + +#include + namespace valhalla { namespace baldr { @@ -32,9 +34,12 @@ class VerbalTextFormatterUsTx : public VerbalTextFormatterUs { * Returns a Texas, US text-to-speech formatted string based on the specified text. * * @param text the source string to transform. + * @param markup_string the optional markup string that should be used. + * * @return a Texas, US text-to-speech formatted string based on the specified text. */ - std::string Format(const std::string& text) const override; + std::string Format(const std::string& text, + const boost::optional& markup_string = boost::none) const override; protected: std::string FormFmTts(const std::string& source) const; diff --git a/valhalla/mjolnir/graphbuilder.h b/valhalla/mjolnir/graphbuilder.h index d13f3ef03c..609a415719 100644 --- a/valhalla/mjolnir/graphbuilder.h +++ b/valhalla/mjolnir/graphbuilder.h @@ -35,6 +35,8 @@ class GraphBuilder { * not in memory * @param complex_to_restriction_file where to store the to complex restrictions so they are not * in memory + * @param pronunciation_file where to store the to pronunciations so they are not + * in memory */ static void Build(const boost::property_tree::ptree& pt, const OSMData& osmdata, @@ -44,6 +46,7 @@ class GraphBuilder { const std::string& edges_file, const std::string& complex_from_restriction_file, const std::string& complex_to_restriction_file, + const std::string& pronunciation_file, const std::map& tiles); static std::map BuildEdges(const ptree& conf, @@ -54,10 +57,40 @@ class GraphBuilder { static std::string GetRef(const std::string& way_ref, const std::string& relation_ref); + static void GetPronunciationTokens(const OSMData& osmdata, + const uint32_t ipa_index, + const uint32_t nt_sampa_index, + const uint32_t katakana_index, + const uint32_t jeita_index, + std::vector& ipa_tokens, + std::vector& nt_sampa_tokens, + std::vector& katakana_tokens, + std::vector& jeita_tokens, + bool is_node_pronunciation = false); + + static void AddPronunciation(const baldr::PronunciationAlphabet alphabet, + const std::string& phoneme, + std::vector& pronunciations, + uint32_t& count); + + static void BuildPronunciations(const std::vector& ipa_tokens, + const std::vector& nt_sampa_tokens, + const std::vector& katakana_tokens, + const std::vector& jeita_tokens, + const size_t index, + std::vector& pronunciations, + bool add_ipa, + bool add_nt_sampa, + bool add_katakana, + bool add_jeita, + uint32_t& count); + static bool CreateSignInfoList(const OSMNode& node, const OSMWay& way, + const OSMPronunciation& pronunciation, const OSMData& osmdata, std::vector& exits, + std::vector& pronunciations, bool fork, bool forward, bool ramp, diff --git a/valhalla/mjolnir/graphenhancer.h b/valhalla/mjolnir/graphenhancer.h index dc1ede7311..327d91d7b1 100644 --- a/valhalla/mjolnir/graphenhancer.h +++ b/valhalla/mjolnir/graphenhancer.h @@ -17,7 +17,7 @@ class GraphEnhancer { * Enhance the local level graph tile information. * @param pt property tree containing the hierarchy configuration * @param osmdata OSM data used to enhance the turn lanes. - * @param access_file where to store the nodes so they are not in memory + * @param access_file where to store the access tags so they are not in memory */ static void Enhance(const boost::property_tree::ptree& pt, const OSMData& osmdata, diff --git a/valhalla/mjolnir/graphtilebuilder.h b/valhalla/mjolnir/graphtilebuilder.h index 2c278ac5d6..c9d636f3ba 100644 --- a/valhalla/mjolnir/graphtilebuilder.h +++ b/valhalla/mjolnir/graphtilebuilder.h @@ -131,6 +131,15 @@ class GraphTileBuilder : public baldr::GraphTile { */ void AddAccessRestrictions(const std::vector& restrictions); + /** + * Add sign information. + * @param idx Directed edge index. + * @param signs Sign information. + */ + void AddSigns(const uint32_t idx, + const std::vector& signs, + const std::vector& pronunciations); + /** * Add sign information. * @param idx Directed edge index. @@ -180,26 +189,27 @@ class GraphTileBuilder : public baldr::GraphTile { /** * Add the edge info to the tile. * - * @param edgeindex The index of the edge - used with nodea and nodeb to - * form tuple that uniquely identifies the edge info since - * there are two directed edges per edge info. - * @param nodea One of two nodes - used with edgeindex and nodeb to - * form tuple that uniquely identifies the edge info since - * there are two directed edges per edge info. - * @param nodeb One of two nodes - used with edgeindex and nodea to - * form tuple that uniquely identifies the edge info since - * there are two directed edges per edge info. - * @param wayid The target edge is part of this the way id. - * @param elev Mean elevation. - * @param bn Bike network. - * @param spd Speed limit. [kph] - * @param lls The shape of the target edge. - * @param names The names of the target edge. - * @param types Bits indicating if the name is a ref vs a name. - * @param added Set to true if the target edge was newly added to the list, - * set to false if the target edge was already in the list. - * @param diff_names Indicates the opposing direction has different names. - * If true a new EdgeInfo is always added. + * @param edgeindex The index of the edge - used with nodea and nodeb to + * form tuple that uniquely identifies the edge info since + * there are two directed edges per edge info. + * @param nodea One of two nodes - used with edgeindex and nodeb to + * form tuple that uniquely identifies the edge info since + * there are two directed edges per edge info. + * @param nodeb One of two nodes - used with edgeindex and nodea to + * form tuple that uniquely identifies the edge info since + * there are two directed edges per edge info. + * @param wayid The target edge is part of this the way id. + * @param elev Mean elevation. + * @param bn Bike network. + * @param spd Speed limit. [kph] + * @param lls The shape of the target edge. + * @param names The names of the target edge. + * @param pronunciations The pronunciations of the target edge. + * @param types Bits indicating if the name is a ref vs a name. + * @param added Set to true if the target edge was newly added to the list, + * set to false if the target edge was already in the list. + * @param diff_names Indicates the opposing direction has different names. + * If true a new EdgeInfo is always added. * @return The edge info offset that will be stored in the directed edge. */ template @@ -213,33 +223,35 @@ class GraphTileBuilder : public baldr::GraphTile { const shape_container_t& lls, const std::vector& names, const std::vector& tagged_values, + const std::vector& pronunciations, const uint16_t types, bool& added, bool diff_names = false); /** * Add the edge info to the tile. This method accepts an encoded shape string. - * @param edgeindex The index of the edge - used with nodea and nodeb to - * form tuple that uniquely identifies the edge info since - * there are two directed edges per edge info. - * @param nodea One of two nodes - used with edgeindex and nodeb to - * form tuple that uniquely identifies the edge info since - * there are two directed edges per edge info. - * @param nodeb One of two nodes - used with edgeindex and nodea to - * form tuple that uniquely identifies the edge info since - * there are two directed edges per edge info. - * @param wayid The target edge is part of this the way id. - * @param elev Mean elevation. - * @param bn Bike network. - * @param spd Speed limit. - * @param llstr The shape of the target edge as an encoded string. - * @param names The names of the target edge. - * @param tagged_values The tagged names of the target edge. - * @param types Bits indicating if the name is a ref vs a name. - * @param added Set to true if the target edge was newly added to the list, - * set to false if the target edge was already in the list. - * @param diff_names Indicates the opposing direction has different names. - * If true a new EdgeInfo is always added. + * @param edgeindex The index of the edge - used with nodea and nodeb to + * form tuple that uniquely identifies the edge info since + * there are two directed edges per edge info. + * @param nodea One of two nodes - used with edgeindex and nodeb to + * form tuple that uniquely identifies the edge info since + * there are two directed edges per edge info. + * @param nodeb One of two nodes - used with edgeindex and nodea to + * form tuple that uniquely identifies the edge info since + * there are two directed edges per edge info. + * @param wayid The target edge is part of this the way id. + * @param elev Mean elevation. + * @param bn Bike network. + * @param spd Speed limit. + * @param llstr The shape of the target edge as an encoded string. + * @param names The names of the target edge. + * @param tagged_values The tagged names of the target edge. + * @param pronunciations The pronunciations of the target edge. + * @param types Bits indicating if the name is a ref vs a name. + * @param added Set to true if the target edge was newly added to the list, + * set to false if the target edge was already in the list. + * @param diff_names Indicates the opposing direction has different names. + * If true a new EdgeInfo is always added. * @return The edge info offset that will be stored in the directed edge. */ uint32_t AddEdgeInfo(const uint32_t edgeindex, @@ -252,6 +264,7 @@ class GraphTileBuilder : public baldr::GraphTile { const std::string& llstr, const std::vector& names, const std::vector& tagged_values, + const std::vector& pronunciations, const uint16_t types, bool& added, bool diff_names = false); diff --git a/valhalla/mjolnir/osmnode.h b/valhalla/mjolnir/osmnode.h index efcc6b6ba7..fe04aca9cc 100644 --- a/valhalla/mjolnir/osmnode.h +++ b/valhalla/mjolnir/osmnode.h @@ -57,6 +57,16 @@ struct OSMNode { uint32_t cash_only_toll_ : 1; uint32_t spare1_ : 5; + // pronunciations + uint32_t name_pronunciation_ipa_index_; + uint32_t name_pronunciation_nt_sampa_index_; + uint32_t name_pronunciation_katakana_index_; + uint32_t name_pronunciation_jeita_index_; + uint32_t ref_pronunciation_ipa_index_; + uint32_t ref_pronunciation_nt_sampa_index_; + uint32_t ref_pronunciation_katakana_index_; + uint32_t ref_pronunciation_jeita_index_; + // Lat,lng of the node at fixed 7digit precision uint32_t lng7_; uint32_t lat7_; @@ -423,6 +433,134 @@ struct OSMNode { return urban_; } + /** + * Sets the index for the ref ipa pronunciation + * @param idx Index for the reference ipa pronunciation. + */ + void set_ref_pronunciation_ipa_index(const uint32_t idx) { + ref_pronunciation_ipa_index_ = idx; + } + + /** + * Get the ref ipa pronunciation index. + * @return Returns the index for the ref ipa pronunciation. + */ + uint32_t ref_pronunciation_ipa_index() const { + return ref_pronunciation_ipa_index_; + } + + /** + * Sets the index for the ref nt-sampa pronunciation + * @param idx Index for the reference nt-sampa pronunciation. + */ + void set_ref_pronunciation_nt_sampa_index(const uint32_t idx) { + ref_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the ref nt-sampa pronunciation index. + * @return Returns the index for the ref nt-sampa pronunciation. + */ + uint32_t ref_pronunciation_nt_sampa_index() const { + return ref_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for the ref katakana pronunciation + * @param idx Index for the reference katakana pronunciation. + */ + void set_ref_pronunciation_katakana_index(const uint32_t idx) { + ref_pronunciation_katakana_index_ = idx; + } + + /** + * Get the ref katakana pronunciation index. + * @return Returns the index for the ref katakana pronunciation. + */ + uint32_t ref_pronunciation_katakana_index() const { + return ref_pronunciation_katakana_index_; + } + + /** + * Sets the index for the ref jeita pronunciation + * @param idx Index for the reference jeita pronunciation. + */ + void set_ref_pronunciation_jeita_index(const uint32_t idx) { + ref_pronunciation_jeita_index_ = idx; + } + + /** + * Get the ref jeita pronunciation index. + * @return Returns the index for the ref jeita pronunciation. + */ + uint32_t ref_pronunciation_jeita_index() const { + return ref_pronunciation_jeita_index_; + } + + /** + * Sets the index for name ipa pronunciation + * @param idx Index for the name ipa pronunciation. + */ + void set_name_pronunciation_ipa_index(const uint32_t idx) { + name_pronunciation_ipa_index_ = idx; + } + + /** + * Get the name ipa pronunciation index. + * @return Returns the index for the name ipa pronunciation. + */ + uint32_t name_pronunciation_ipa_index() const { + return name_pronunciation_ipa_index_; + } + + /** + * Sets the index for name nt-sampa pronunciation + * @param idx Index for the name nt-sampa pronunciation. + */ + void set_name_pronunciation_nt_sampa_index(const uint32_t idx) { + name_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the name nt-sampa pronunciation index. + * @return Returns the index for the name nt-sampa pronunciation. + */ + uint32_t name_pronunciation_nt_sampa_index() const { + return name_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for name katakana pronunciation + * @param idx Index for the name katakana pronunciation. + */ + void set_name_pronunciation_katakana_index(const uint32_t idx) { + name_pronunciation_katakana_index_ = idx; + } + + /** + * Get the name katakana pronunciation index. + * @return Returns the index for the name katakana pronunciation. + */ + uint32_t name_pronunciation_katakana_index() const { + return name_pronunciation_katakana_index_; + } + + /** + * Sets the index for name jeita pronunciation + * @param idx Index for the name jeita pronunciation. + */ + void set_name_pronunciation_jeita_index(const uint32_t idx) { + name_pronunciation_jeita_index_ = idx; + } + + /** + * Get the name jeita pronunciation index. + * @return Returns the index for the name jeita pronunciation. + */ + uint32_t name_pronunciation_jeita_index() const { + return name_pronunciation_jeita_index_; + } + /** * Set the country iso code index * @param country iso code Index into the 2 char Country ISO Code. diff --git a/valhalla/mjolnir/osmpronunciation.h b/valhalla/mjolnir/osmpronunciation.h new file mode 100644 index 0000000000..490e488d73 --- /dev/null +++ b/valhalla/mjolnir/osmpronunciation.h @@ -0,0 +1,1099 @@ +#ifndef VALHALLA_MJOLNIR_PBFGRAPHBUILDER_OSMPRONUNCIATION_H +#define VALHALLA_MJOLNIR_PBFGRAPHBUILDER_OSMPRONUNCIATION_H + +#include +#include +#include + +#include + +namespace valhalla { +namespace mjolnir { + +// OSM Pronunciation. IPA/Nt-sampa/Katakana/Jeita phonems/pronunciations +struct OSMPronunciation { + + /** + * Constructor + */ + OSMPronunciation() { + memset(this, 0, sizeof(OSMPronunciation)); + } + + /** + * Constructor with way id arg. + * @param id way id + */ + OSMPronunciation(const uint64_t id) { + memset(this, 0, sizeof(OSMPronunciation)); + set_way_id(id); + } + + /** + * Set way id. + * @param id way id + */ + void set_way_id(const uint64_t id) { + osmwayid_ = id; + } + + /** + * Get the way id + * @return Returns way id. + */ + uint64_t way_id() const { + return osmwayid_; + } + + /** + * Sets the index for the ref ipa pronunciation + * @param idx Index for the reference ipa pronunciation. + */ + void set_ref_pronunciation_ipa_index(const uint32_t idx) { + ref_pronunciation_ipa_index_ = idx; + } + + /** + * Get the ref ipa pronunciation index. + * @return Returns the index for the ref ipa pronunciation. + */ + uint32_t ref_pronunciation_ipa_index() const { + return ref_pronunciation_ipa_index_; + } + + /** + * Sets the index for int ret ipa pronunciation + * @param idx Index for the international reference ipa pronunciation. + */ + void set_int_ref_pronunciation_ipa_index(const uint32_t idx) { + int_ref_pronunciation_ipa_index_ = idx; + } + + /** + * Get the int ref ipa pronunciation index. + * @return Returns the index for the int ref ipa pronunciation. + */ + uint32_t int_ref_pronunciation_ipa_index() const { + return int_ref_pronunciation_ipa_index_; + } + + /** + * Sets the index for name ipa pronunciation + * @param idx Index for the name ipa pronunciation. + */ + void set_name_pronunciation_ipa_index(const uint32_t idx) { + name_pronunciation_ipa_index_ = idx; + } + + /** + * Get the name ipa pronunciation index. + * @return Returns the index for the name ipa pronunciation. + */ + uint32_t name_pronunciation_ipa_index() const { + return name_pronunciation_ipa_index_; + } + + /** + * Sets the index for name:en ipa pronunciation + * @param idx Index for the English name ipa pronunciation. + */ + void set_name_en_pronunciation_ipa_index(const uint32_t idx) { + name_en_pronunciation_ipa_index_ = idx; + } + + /** + * Get the name:en ipa pronunciation index. + * @return Returns the index for the English name ipa pronunciation. + */ + uint32_t name_en_pronunciation_ipa_index() const { + return name_en_pronunciation_ipa_index_; + } + + /** + * Sets the index for alt name ipa pronunciation + * @param idx Index for the alt name ipa pronunciation. + */ + void set_alt_name_pronunciation_ipa_index(const uint32_t idx) { + alt_name_pronunciation_ipa_index_ = idx; + } + + /** + * Get the alt name ipa pronunciation index. + * @return Returns the index for the alt name ipa pronunciation. + */ + uint32_t alt_name_pronunciation_ipa_index() const { + return alt_name_pronunciation_ipa_index_; + } + + /** + * Sets the index for official name ipa pronunciation + * @param idx Index for the official name ipa pronunciation. + */ + void set_official_name_pronunciation_ipa_index(const uint32_t idx) { + official_name_pronunciation_ipa_index_ = idx; + } + + /** + * Get the official name ipa pronunciation index. + * @return Returns the index for the official name ipa pronunciation. + */ + uint32_t official_name_pronunciation_ipa_index() const { + return official_name_pronunciation_ipa_index_; + } + + /** + * Sets the index for tunnel name ipa pronunciation + * @param idx Index for the tunnel name ipa pronunciation. + */ + void set_tunnel_name_pronunciation_ipa_index(const uint32_t idx) { + tunnel_name_pronunciation_ipa_index_ = idx; + } + + /** + * Get the tunnel name ipa pronunciation index. + * @return Returns the index for the tunnel name ipa pronunciation. + */ + uint32_t tunnel_name_pronunciation_ipa_index() const { + return tunnel_name_pronunciation_ipa_index_; + } + + /** + * Sets the index for destination ipa pronunciation. + * @param idx Index for the destination ipa pronunciation. + */ + void set_destination_pronunciation_ipa_index(const uint32_t idx) { + destination_pronunciation_ipa_index_ = idx; + } + + /** + * Get the get_destination ipa pronunciation index. + * @return Returns the index for the destination ipa pronunciation. + */ + uint32_t destination_pronunciation_ipa_index() const { + return destination_pronunciation_ipa_index_; + } + + /** + * Sets the index for destination in forward direction ipa pronunciation. + * @param idx Index for the destination ipa pronunciation. + */ + void set_destination_forward_pronunciation_ipa_index(const uint32_t idx) { + destination_forward_pronunciation_ipa_index_ = idx; + } + + /** + * Get the forward direction ipa pronunciation index. + * @return Returns the index for the forward direction ipa pronunciation. + */ + uint32_t destination_forward_pronunciation_ipa_index() const { + return destination_forward_pronunciation_ipa_index_; + } + + /** + * Sets the index for destination in backward direction ipa pronunciation. + * @param idx Index for the backward direction ipa pronunciation. + */ + void set_destination_backward_pronunciation_ipa_index(const uint32_t idx) { + destination_backward_pronunciation_ipa_index_ = idx; + } + + /** + * Get the backward direction ipa pronunciation index. + * @return Returns the index for the backward direction ipa pronunciation. + */ + uint32_t destination_backward_pronunciation_ipa_index() const { + return destination_backward_pronunciation_ipa_index_; + } + + /** + * Sets the index for destination ref ipa pronunciation. + * @param idx Index for the destination ref ipa pronunciation. + */ + void set_destination_ref_pronunciation_ipa_index(const uint32_t idx) { + destination_ref_pronunciation_ipa_index_ = idx; + } + + /** + * Get the destination ref ipa pronunciation index. + * @return Returns the index for the destination ref ipa pronunciation. + */ + uint32_t destination_ref_pronunciation_ipa_index() const { + return destination_ref_pronunciation_ipa_index_; + } + + /** + * Sets the index for destination ref to ipa pronunciation. + * @param idx Index for the destination ref to ipa pronunciation. + */ + void set_destination_ref_to_pronunciation_ipa_index(const uint32_t idx) { + destination_ref_to_pronunciation_ipa_index_ = idx; + } + + /** + * Get the destination ref to ipa pronunciation index. + * @return Returns the index for the destination ref to ipa pronunciation. + */ + uint32_t destination_ref_to_pronunciation_ipa_index() const { + return destination_ref_to_pronunciation_ipa_index_; + } + + /** + * Sets the index for destination street ipa pronunciation. + * @param idx Index for the destination street ipa pronunciation. + */ + void set_destination_street_pronunciation_ipa_index(const uint32_t idx) { + destination_street_pronunciation_ipa_index_ = idx; + } + + /** + * Get the destination_street ipa pronunciation index. + * @return Returns the index for the destination street ipa pronunciation. + */ + uint32_t destination_street_pronunciation_ipa_index() const { + return destination_street_pronunciation_ipa_index_; + } + + /** + * Sets the index for destination street to ipa pronunciation. + * @param idx Index for the destination street to ipa pronunciation. + */ + void set_destination_street_to_pronunciation_ipa_index(const uint32_t idx) { + destination_street_to_pronunciation_ipa_index_ = idx; + } + + /** + * Get the destination street to ipa pronunciation index. + * @return Returns the index for the destination street to ipa pronunciation. + */ + uint32_t destination_street_to_pronunciation_ipa_index() const { + return destination_street_to_pronunciation_ipa_index_; + } + + /** + * Sets the index for junction ref ipa pronunciation. + * @param idx Index for the junction ref ipa pronunciation. + */ + void set_junction_ref_pronunciation_ipa_index(const uint32_t idx) { + junction_ref_pronunciation_ipa_index_ = idx; + } + + /** + * Get the junction ref ipa pronunciation index. + * @return Returns the ipa pronunciation index for the junction ref. + */ + uint32_t junction_ref_pronunciation_ipa_index() const { + return junction_ref_pronunciation_ipa_index_; + } + + /** + * Sets the index for the ref nt-sampa pronunciation + * @param idx Index for the reference nt-sampa pronunciation. + */ + void set_ref_pronunciation_nt_sampa_index(const uint32_t idx) { + ref_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the ref nt-sampa pronunciation index. + * @return Returns the index for the ref nt-sampa pronunciation. + */ + uint32_t ref_pronunciation_nt_sampa_index() const { + return ref_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for int ret nt-sampa pronunciation + * @param idx Index for the international reference nt-sampa pronunciation. + */ + void set_int_ref_pronunciation_nt_sampa_index(const uint32_t idx) { + int_ref_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the int ref nt-sampa pronunciation index. + * @return Returns the index for the int ref nt-sampa pronunciation. + */ + uint32_t int_ref_pronunciation_nt_sampa_index() const { + return int_ref_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for name nt-sampa pronunciation + * @param idx Index for the name nt-sampa pronunciation. + */ + void set_name_pronunciation_nt_sampa_index(const uint32_t idx) { + name_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the name nt-sampa pronunciation index. + * @return Returns the index for the name nt-sampa pronunciation. + */ + uint32_t name_pronunciation_nt_sampa_index() const { + return name_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for name:en nt-sampa pronunciation + * @param idx Index for the English name nt-sampa pronunciation. + */ + void set_name_en_pronunciation_nt_sampa_index(const uint32_t idx) { + name_en_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the name:en nt-sampa pronunciation index. + * @return Returns the index for the English name nt-sampa pronunciation. + */ + uint32_t name_en_pronunciation_nt_sampa_index() const { + return name_en_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for alt name nt-sampa pronunciation + * @param idx Index for the alt name nt-sampa pronunciation. + */ + void set_alt_name_pronunciation_nt_sampa_index(const uint32_t idx) { + alt_name_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the alt name nt-sampa pronunciation index. + * @return Returns the index for the alt name nt-sampa pronunciation. + */ + uint32_t alt_name_pronunciation_nt_sampa_index() const { + return alt_name_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for official name nt-sampa pronunciation + * @param idx Index for the official name nt-sampa pronunciation. + */ + void set_official_name_pronunciation_nt_sampa_index(const uint32_t idx) { + official_name_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the official name nt-sampa pronunciation index. + * @return Returns the index for the official name nt-sampa pronunciation. + */ + uint32_t official_name_pronunciation_nt_sampa_index() const { + return official_name_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for tunnel name nt-sampa pronunciation + * @param idx Index for the tunnel name nt-sampa pronunciation. + */ + void set_tunnel_name_pronunciation_nt_sampa_index(const uint32_t idx) { + tunnel_name_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the tunnel name nt-sampa pronunciation index. + * @return Returns the index for the tunnel name nt-sampa pronunciation. + */ + uint32_t tunnel_name_pronunciation_nt_sampa_index() const { + return tunnel_name_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for destination nt-sampa pronunciation. + * @param idx Index for the destination nt-sampa pronunciation. + */ + void set_destination_pronunciation_nt_sampa_index(const uint32_t idx) { + destination_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the get_destination nt-sampa pronunciation index. + * @return Returns the index for the destination nt-sampa pronunciation. + */ + uint32_t destination_pronunciation_nt_sampa_index() const { + return destination_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for destination in forward direction nt-sampa pronunciation. + * @param idx Index for the destination nt-sampa pronunciation. + */ + void set_destination_forward_pronunciation_nt_sampa_index(const uint32_t idx) { + destination_forward_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the forward direction nt-sampa pronunciation index. + * @return Returns the index for the forward direction nt-sampa pronunciation. + */ + uint32_t destination_forward_pronunciation_nt_sampa_index() const { + return destination_forward_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for destination in backward direction nt-sampa pronunciation. + * @param idx Index for the backward direction nt-sampa pronunciation. + */ + void set_destination_backward_pronunciation_nt_sampa_index(const uint32_t idx) { + destination_backward_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the backward direction nt-sampa pronunciation index. + * @return Returns the index for the backward direction nt-sampa pronunciation. + */ + uint32_t destination_backward_pronunciation_nt_sampa_index() const { + return destination_backward_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for destination ref nt-sampa pronunciation. + * @param idx Index for the destination ref nt-sampa pronunciation. + */ + void set_destination_ref_pronunciation_nt_sampa_index(const uint32_t idx) { + destination_ref_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the destination ref nt-sampa pronunciation index. + * @return Returns the index for the destination ref nt-sampa pronunciation. + */ + uint32_t destination_ref_pronunciation_nt_sampa_index() const { + return destination_ref_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for destination ref to nt-sampa pronunciation. + * @param idx Index for the destination ref to nt-sampa pronunciation. + */ + void set_destination_ref_to_pronunciation_nt_sampa_index(const uint32_t idx) { + destination_ref_to_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the destination ref to nt-sampa pronunciation index. + * @return Returns the index for the destination ref to nt-sampa pronunciation. + */ + uint32_t destination_ref_to_pronunciation_nt_sampa_index() const { + return destination_ref_to_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for destination street nt-sampa pronunciation. + * @param idx Index for the destination street nt-sampa pronunciation. + */ + void set_destination_street_pronunciation_nt_sampa_index(const uint32_t idx) { + destination_street_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the destination_street nt-sampa pronunciation index. + * @return Returns the index for the destination street nt-sampa pronunciation. + */ + uint32_t destination_street_pronunciation_nt_sampa_index() const { + return destination_street_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for destination street to nt-sampa pronunciation. + * @param idx Index for the destination street to nt-sampa pronunciation. + */ + void set_destination_street_to_pronunciation_nt_sampa_index(const uint32_t idx) { + destination_street_to_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the destination street to nt-sampa pronunciation index. + * @return Returns the index for the destination street to nt-sampa pronunciation. + */ + uint32_t destination_street_to_pronunciation_nt_sampa_index() const { + return destination_street_to_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for junction ref nt-sampa pronunciation. + * @param idx Index for the junction ref nt-sampa pronunciation. + */ + void set_junction_ref_pronunciation_nt_sampa_index(const uint32_t idx) { + junction_ref_pronunciation_nt_sampa_index_ = idx; + } + + /** + * Get the junction ref nt-sampa pronunciation index. + * @return Returns the nt-sampa pronunciation index for the junction ref. + */ + uint32_t junction_ref_pronunciation_nt_sampa_index() const { + return junction_ref_pronunciation_nt_sampa_index_; + } + + /** + * Sets the index for the ref katakana pronunciation + * @param idx Index for the reference katakana pronunciation. + */ + void set_ref_pronunciation_katakana_index(const uint32_t idx) { + ref_pronunciation_katakana_index_ = idx; + } + + /** + * Get the ref katakana pronunciation index. + * @return Returns the index for the ref katakana pronunciation. + */ + uint32_t ref_pronunciation_katakana_index() const { + return ref_pronunciation_katakana_index_; + } + + /** + * Sets the index for int ret katakana pronunciation + * @param idx Index for the international reference katakana pronunciation. + */ + void set_int_ref_pronunciation_katakana_index(const uint32_t idx) { + int_ref_pronunciation_katakana_index_ = idx; + } + + /** + * Get the int ref katakana pronunciation index. + * @return Returns the index for the int ref katakana pronunciation. + */ + uint32_t int_ref_pronunciation_katakana_index() const { + return int_ref_pronunciation_katakana_index_; + } + + /** + * Sets the index for name katakana pronunciation + * @param idx Index for the name katakana pronunciation. + */ + void set_name_pronunciation_katakana_index(const uint32_t idx) { + name_pronunciation_katakana_index_ = idx; + } + + /** + * Get the name katakana pronunciation index. + * @return Returns the index for the name katakana pronunciation. + */ + uint32_t name_pronunciation_katakana_index() const { + return name_pronunciation_katakana_index_; + } + + /** + * Sets the index for name:en katakana pronunciation + * @param idx Index for the English name katakana pronunciation. + */ + void set_name_en_pronunciation_katakana_index(const uint32_t idx) { + name_en_pronunciation_katakana_index_ = idx; + } + + /** + * Get the name:en katakana pronunciation index. + * @return Returns the index for the English name katakana pronunciation. + */ + uint32_t name_en_pronunciation_katakana_index() const { + return name_en_pronunciation_katakana_index_; + } + + /** + * Sets the index for alt name katakana pronunciation + * @param idx Index for the alt name katakana pronunciation. + */ + void set_alt_name_pronunciation_katakana_index(const uint32_t idx) { + alt_name_pronunciation_katakana_index_ = idx; + } + + /** + * Get the alt name katakana pronunciation index. + * @return Returns the index for the alt name katakana pronunciation. + */ + uint32_t alt_name_pronunciation_katakana_index() const { + return alt_name_pronunciation_katakana_index_; + } + + /** + * Sets the index for official name katakana pronunciation + * @param idx Index for the official name katakana pronunciation. + */ + void set_official_name_pronunciation_katakana_index(const uint32_t idx) { + official_name_pronunciation_katakana_index_ = idx; + } + + /** + * Get the official name katakana pronunciation index. + * @return Returns the index for the official name katakana pronunciation. + */ + uint32_t official_name_pronunciation_katakana_index() const { + return official_name_pronunciation_katakana_index_; + } + + /** + * Sets the index for tunnel name katakana pronunciation + * @param idx Index for the tunnel name katakana pronunciation. + */ + void set_tunnel_name_pronunciation_katakana_index(const uint32_t idx) { + tunnel_name_pronunciation_katakana_index_ = idx; + } + + /** + * Get the tunnel name katakana pronunciation index. + * @return Returns the index for the tunnel name katakana pronunciation. + */ + uint32_t tunnel_name_pronunciation_katakana_index() const { + return tunnel_name_pronunciation_katakana_index_; + } + + /** + * Sets the index for destination katakana pronunciation. + * @param idx Index for the destination katakana pronunciation. + */ + void set_destination_pronunciation_katakana_index(const uint32_t idx) { + destination_pronunciation_katakana_index_ = idx; + } + + /** + * Get the get_destination katakana pronunciation index. + * @return Returns the index for the destination katakana pronunciation. + */ + uint32_t destination_pronunciation_katakana_index() const { + return destination_pronunciation_katakana_index_; + } + + /** + * Sets the index for destination in forward direction katakana pronunciation. + * @param idx Index for the destination katakana pronunciation. + */ + void set_destination_forward_pronunciation_katakana_index(const uint32_t idx) { + destination_forward_pronunciation_katakana_index_ = idx; + } + + /** + * Get the forward direction katakana pronunciation index. + * @return Returns the index for the forward direction katakana pronunciation. + */ + uint32_t destination_forward_pronunciation_katakana_index() const { + return destination_forward_pronunciation_katakana_index_; + } + + /** + * Sets the index for destination in backward direction katakana pronunciation. + * @param idx Index for the backward direction katakana pronunciation. + */ + void set_destination_backward_pronunciation_katakana_index(const uint32_t idx) { + destination_backward_pronunciation_katakana_index_ = idx; + } + + /** + * Get the backward direction katakana pronunciation index. + * @return Returns the index for the backward direction katakana pronunciation. + */ + uint32_t destination_backward_pronunciation_katakana_index() const { + return destination_backward_pronunciation_katakana_index_; + } + + /** + * Sets the index for destination ref katakana pronunciation. + * @param idx Index for the destination ref katakana pronunciation. + */ + void set_destination_ref_pronunciation_katakana_index(const uint32_t idx) { + destination_ref_pronunciation_katakana_index_ = idx; + } + + /** + * Get the destination ref katakana pronunciation index. + * @return Returns the index for the destination ref katakana pronunciation. + */ + uint32_t destination_ref_pronunciation_katakana_index() const { + return destination_ref_pronunciation_katakana_index_; + } + + /** + * Sets the index for destination ref to katakana pronunciation. + * @param idx Index for the destination ref to katakana pronunciation. + */ + void set_destination_ref_to_pronunciation_katakana_index(const uint32_t idx) { + destination_ref_to_pronunciation_katakana_index_ = idx; + } + + /** + * Get the destination ref to katakana pronunciation index. + * @return Returns the index for the destination ref to katakana pronunciation. + */ + uint32_t destination_ref_to_pronunciation_katakana_index() const { + return destination_ref_to_pronunciation_katakana_index_; + } + + /** + * Sets the index for destination street katakana pronunciation. + * @param idx Index for the destination street katakana pronunciation. + */ + void set_destination_street_pronunciation_katakana_index(const uint32_t idx) { + destination_street_pronunciation_katakana_index_ = idx; + } + + /** + * Get the destination_street katakana pronunciation index. + * @return Returns the index for the destination street katakana pronunciation. + */ + uint32_t destination_street_pronunciation_katakana_index() const { + return destination_street_pronunciation_katakana_index_; + } + + /** + * Sets the index for destination street to katakana pronunciation. + * @param idx Index for the destination street to katakana pronunciation. + */ + void set_destination_street_to_pronunciation_katakana_index(const uint32_t idx) { + destination_street_to_pronunciation_katakana_index_ = idx; + } + + /** + * Get the destination street to katakana pronunciation index. + * @return Returns the index for the destination street to katakana pronunciation. + */ + uint32_t destination_street_to_pronunciation_katakana_index() const { + return destination_street_to_pronunciation_katakana_index_; + } + + /** + * Sets the index for junction ref katakana pronunciation. + * @param idx Index for the junction ref katakana pronunciation. + */ + void set_junction_ref_pronunciation_katakana_index(const uint32_t idx) { + junction_ref_pronunciation_katakana_index_ = idx; + } + + /** + * Get the junction ref katakana pronunciation index. + * @return Returns the katakana pronunciation index for the junction ref. + */ + uint32_t junction_ref_pronunciation_katakana_index() const { + return junction_ref_pronunciation_katakana_index_; + } + + /** + * Sets the index for the ref jeita pronunciation + * @param idx Index for the reference jeita pronunciation. + */ + void set_ref_pronunciation_jeita_index(const uint32_t idx) { + ref_pronunciation_jeita_index_ = idx; + } + + /** + * Get the ref jeita pronunciation index. + * @return Returns the index for the ref jeita pronunciation. + */ + uint32_t ref_pronunciation_jeita_index() const { + return ref_pronunciation_jeita_index_; + } + + /** + * Sets the index for int ret jeita pronunciation + * @param idx Index for the international reference jeita pronunciation. + */ + void set_int_ref_pronunciation_jeita_index(const uint32_t idx) { + int_ref_pronunciation_jeita_index_ = idx; + } + + /** + * Get the int ref jeita pronunciation index. + * @return Returns the index for the int ref jeita pronunciation. + */ + uint32_t int_ref_pronunciation_jeita_index() const { + return int_ref_pronunciation_jeita_index_; + } + + /** + * Sets the index for name jeita pronunciation + * @param idx Index for the name jeita pronunciation. + */ + void set_name_pronunciation_jeita_index(const uint32_t idx) { + name_pronunciation_jeita_index_ = idx; + } + + /** + * Get the name jeita pronunciation index. + * @return Returns the index for the name jeita pronunciation. + */ + uint32_t name_pronunciation_jeita_index() const { + return name_pronunciation_jeita_index_; + } + + /** + * Sets the index for name:en jeita pronunciation + * @param idx Index for the English name jeita pronunciation. + */ + void set_name_en_pronunciation_jeita_index(const uint32_t idx) { + name_en_pronunciation_jeita_index_ = idx; + } + + /** + * Get the name:en jeita pronunciation index. + * @return Returns the index for the English name jeita pronunciation. + */ + uint32_t name_en_pronunciation_jeita_index() const { + return name_en_pronunciation_jeita_index_; + } + + /** + * Sets the index for alt name jeita pronunciation + * @param idx Index for the alt name jeita pronunciation. + */ + void set_alt_name_pronunciation_jeita_index(const uint32_t idx) { + alt_name_pronunciation_jeita_index_ = idx; + } + + /** + * Get the alt name jeita pronunciation index. + * @return Returns the index for the alt name jeita pronunciation. + */ + uint32_t alt_name_pronunciation_jeita_index() const { + return alt_name_pronunciation_jeita_index_; + } + + /** + * Sets the index for official name jeita pronunciation + * @param idx Index for the official name jeita pronunciation. + */ + void set_official_name_pronunciation_jeita_index(const uint32_t idx) { + official_name_pronunciation_jeita_index_ = idx; + } + + /** + * Get the official name jeita pronunciation index. + * @return Returns the index for the official name jeita pronunciation. + */ + uint32_t official_name_pronunciation_jeita_index() const { + return official_name_pronunciation_jeita_index_; + } + + /** + * Sets the index for tunnel name jeita pronunciation + * @param idx Index for the tunnel name jeita pronunciation. + */ + void set_tunnel_name_pronunciation_jeita_index(const uint32_t idx) { + tunnel_name_pronunciation_jeita_index_ = idx; + } + + /** + * Get the tunnel name jeita pronunciation index. + * @return Returns the index for the tunnel name jeita pronunciation. + */ + uint32_t tunnel_name_pronunciation_jeita_index() const { + return tunnel_name_pronunciation_jeita_index_; + } + + /** + * Sets the index for destination jeita pronunciation. + * @param idx Index for the destination jeita pronunciation. + */ + void set_destination_pronunciation_jeita_index(const uint32_t idx) { + destination_pronunciation_jeita_index_ = idx; + } + + /** + * Get the get_destination jeita pronunciation index. + * @return Returns the index for the destination jeita pronunciation. + */ + uint32_t destination_pronunciation_jeita_index() const { + return destination_pronunciation_jeita_index_; + } + + /** + * Sets the index for destination in forward direction jeita pronunciation. + * @param idx Index for the destination jeita pronunciation. + */ + void set_destination_forward_pronunciation_jeita_index(const uint32_t idx) { + destination_forward_pronunciation_jeita_index_ = idx; + } + + /** + * Get the forward direction jeita pronunciation index. + * @return Returns the index for the forward direction jeita pronunciation. + */ + uint32_t destination_forward_pronunciation_jeita_index() const { + return destination_forward_pronunciation_jeita_index_; + } + + /** + * Sets the index for destination in backward direction jeita pronunciation. + * @param idx Index for the backward direction jeita pronunciation. + */ + void set_destination_backward_pronunciation_jeita_index(const uint32_t idx) { + destination_backward_pronunciation_jeita_index_ = idx; + } + + /** + * Get the backward direction jeita pronunciation index. + * @return Returns the index for the backward direction jeita pronunciation. + */ + uint32_t destination_backward_pronunciation_jeita_index() const { + return destination_backward_pronunciation_jeita_index_; + } + + /** + * Sets the index for destination ref jeita pronunciation. + * @param idx Index for the destination ref jeita pronunciation. + */ + void set_destination_ref_pronunciation_jeita_index(const uint32_t idx) { + destination_ref_pronunciation_jeita_index_ = idx; + } + + /** + * Get the destination ref jeita pronunciation index. + * @return Returns the index for the destination ref jeita pronunciation. + */ + uint32_t destination_ref_pronunciation_jeita_index() const { + return destination_ref_pronunciation_jeita_index_; + } + + /** + * Sets the index for destination ref to jeita pronunciation. + * @param idx Index for the destination ref to jeita pronunciation. + */ + void set_destination_ref_to_pronunciation_jeita_index(const uint32_t idx) { + destination_ref_to_pronunciation_jeita_index_ = idx; + } + + /** + * Get the destination ref to jeita pronunciation index. + * @return Returns the index for the destination ref to jeita pronunciation. + */ + uint32_t destination_ref_to_pronunciation_jeita_index() const { + return destination_ref_to_pronunciation_jeita_index_; + } + + /** + * Sets the index for destination street jeita pronunciation. + * @param idx Index for the destination street jeita pronunciation. + */ + void set_destination_street_pronunciation_jeita_index(const uint32_t idx) { + destination_street_pronunciation_jeita_index_ = idx; + } + + /** + * Get the destination_street jeita pronunciation index. + * @return Returns the index for the destination street jeita pronunciation. + */ + uint32_t destination_street_pronunciation_jeita_index() const { + return destination_street_pronunciation_jeita_index_; + } + + /** + * Sets the index for destination street to jeita pronunciation. + * @param idx Index for the destination street to jeita pronunciation. + */ + void set_destination_street_to_pronunciation_jeita_index(const uint32_t idx) { + destination_street_to_pronunciation_jeita_index_ = idx; + } + + /** + * Get the destination street to jeita pronunciation index. + * @return Returns the index for the destination street to jeita pronunciation. + */ + uint32_t destination_street_to_pronunciation_jeita_index() const { + return destination_street_to_pronunciation_jeita_index_; + } + + /** + * Sets the index for junction ref jeita pronunciation. + * @param idx Index for the junction ref jeita pronunciation. + */ + void set_junction_ref_pronunciation_jeita_index(const uint32_t idx) { + junction_ref_pronunciation_jeita_index_ = idx; + } + + /** + * Get the junction ref jeita pronunciation index. + * @return Returns the jeita pronunciation index for the junction ref. + */ + uint32_t junction_ref_pronunciation_jeita_index() const { + return junction_ref_pronunciation_jeita_index_; + } + + // OSM way Id + uint64_t osmwayid_; + + // name and ref ipa pronunciations + uint32_t ref_pronunciation_ipa_index_; + uint32_t int_ref_pronunciation_ipa_index_; + uint32_t name_pronunciation_ipa_index_; + uint32_t name_en_pronunciation_ipa_index_; + uint32_t alt_name_pronunciation_ipa_index_; + uint32_t official_name_pronunciation_ipa_index_; + uint32_t tunnel_name_pronunciation_ipa_index_; + uint32_t direction_pronunciation_ipa_index_; + uint32_t int_direction_pronunciation_ipa_index_; + + // Sign Destination ipa pronunciations + uint32_t destination_pronunciation_ipa_index_; + uint32_t destination_forward_pronunciation_ipa_index_; + uint32_t destination_backward_pronunciation_ipa_index_; + uint32_t destination_ref_pronunciation_ipa_index_; + uint32_t destination_ref_to_pronunciation_ipa_index_; + uint32_t destination_street_pronunciation_ipa_index_; + uint32_t destination_street_to_pronunciation_ipa_index_; + uint32_t junction_ref_pronunciation_ipa_index_; + + // name and ref nt-sampa pronunciations + uint32_t ref_pronunciation_nt_sampa_index_; + uint32_t int_ref_pronunciation_nt_sampa_index_; + uint32_t name_pronunciation_nt_sampa_index_; + uint32_t name_en_pronunciation_nt_sampa_index_; + uint32_t alt_name_pronunciation_nt_sampa_index_; + uint32_t official_name_pronunciation_nt_sampa_index_; + uint32_t tunnel_name_pronunciation_nt_sampa_index_; + uint32_t direction_pronunciation_nt_sampa_index_; + uint32_t int_direction_pronunciation_nt_sampa_index_; + + // Sign Destination nt-sampa pronunciations + uint32_t destination_pronunciation_nt_sampa_index_; + uint32_t destination_forward_pronunciation_nt_sampa_index_; + uint32_t destination_backward_pronunciation_nt_sampa_index_; + uint32_t destination_ref_pronunciation_nt_sampa_index_; + uint32_t destination_ref_to_pronunciation_nt_sampa_index_; + uint32_t destination_street_pronunciation_nt_sampa_index_; + uint32_t destination_street_to_pronunciation_nt_sampa_index_; + uint32_t junction_ref_pronunciation_nt_sampa_index_; + + // name and ref katakana pronunciations + uint32_t ref_pronunciation_katakana_index_; + uint32_t int_ref_pronunciation_katakana_index_; + uint32_t name_pronunciation_katakana_index_; + uint32_t name_en_pronunciation_katakana_index_; + uint32_t alt_name_pronunciation_katakana_index_; + uint32_t official_name_pronunciation_katakana_index_; + uint32_t tunnel_name_pronunciation_katakana_index_; + uint32_t direction_pronunciation_katakana_index_; + uint32_t int_direction_pronunciation_katakana_index_; + + // Sign Destination katakana pronunciations + uint32_t destination_pronunciation_katakana_index_; + uint32_t destination_forward_pronunciation_katakana_index_; + uint32_t destination_backward_pronunciation_katakana_index_; + uint32_t destination_ref_pronunciation_katakana_index_; + uint32_t destination_ref_to_pronunciation_katakana_index_; + uint32_t destination_street_pronunciation_katakana_index_; + uint32_t destination_street_to_pronunciation_katakana_index_; + uint32_t junction_ref_pronunciation_katakana_index_; + + // name and ref jeita pronunciations + uint32_t ref_pronunciation_jeita_index_; + uint32_t int_ref_pronunciation_jeita_index_; + uint32_t name_pronunciation_jeita_index_; + uint32_t name_en_pronunciation_jeita_index_; + uint32_t alt_name_pronunciation_jeita_index_; + uint32_t official_name_pronunciation_jeita_index_; + uint32_t tunnel_name_pronunciation_jeita_index_; + uint32_t direction_pronunciation_jeita_index_; + uint32_t int_direction_pronunciation_jeita_index_; + + // Sign Destination jeita pronunciations + uint32_t destination_pronunciation_jeita_index_; + uint32_t destination_forward_pronunciation_jeita_index_; + uint32_t destination_backward_pronunciation_jeita_index_; + uint32_t destination_ref_pronunciation_jeita_index_; + uint32_t destination_ref_to_pronunciation_jeita_index_; + uint32_t destination_street_pronunciation_jeita_index_; + uint32_t destination_street_to_pronunciation_jeita_index_; + uint32_t junction_ref_pronunciation_jeita_index_; +}; + +} // namespace mjolnir +} // namespace valhalla + +#endif // VALHALLA_MJOLNIR_PBFGRAPHBUILDER_OSMPRONUNCIATION_H diff --git a/valhalla/mjolnir/osmway.h b/valhalla/mjolnir/osmway.h index e262eca116..f2c5f8e702 100644 --- a/valhalla/mjolnir/osmway.h +++ b/valhalla/mjolnir/osmway.h @@ -6,6 +6,7 @@ #include #include +#include "mjolnir/osmpronunciation.h" #include #include @@ -369,7 +370,7 @@ struct OSMWay { } /** - * Get the get_destination index. + * Get the destination index. * @return Returns the index for the destination. */ uint32_t destination_index() const { @@ -385,8 +386,8 @@ struct OSMWay { } /** - * Get the get_destination index. - * @return Returns the index for the destination. + * Get the destination in forward direction index. + * @return Returns the index for the destination in forward direction. */ uint32_t destination_forward_index() const { return destination_forward_index_; @@ -401,8 +402,8 @@ struct OSMWay { } /** - * Get the get_destination index. - * @return Returns the index for the destination. + * Get the destination in backward direction index. + * @return Returns the index for the destination in backward direction. */ uint32_t destination_backward_index() const { return destination_backward_index_; @@ -473,16 +474,16 @@ struct OSMWay { } /** - * Sets the index for junction ref. - * @param idx Index for the junction ref. + * Sets the index for junction ref pronunciation. + * @param idx Index for the junction ref pronunciation. */ void set_junction_ref_index(const uint32_t idx) { junction_ref_index_ = idx; } /** - * Get the junction ref index. - * @return Returns the index for the junction ref. + * Get the junction ref pronunciation index. + * @return Returns the index for the junction ref pronunciation. */ uint32_t junction_ref_index() const { return junction_ref_index_; @@ -908,6 +909,22 @@ struct OSMWay { return has_user_tags_; } + /** + * Sets the has_pronunciation_tags flag. + * @param has_pronunciation_tags Do pronunciation tags exist? + */ + void set_has_pronunciation_tags(const bool has_pronunciation_tags) { + has_pronunciation_tags_ = has_pronunciation_tags; + } + + /** + * Get the has_pronunciation_tags flag. + * @return Returns has_pronunciation_tags flag. + */ + bool has_pronunciation_tags() const { + return has_pronunciation_tags_; + } + /** * Sets the internal flag. * @param internal Is this part of a internal intersection? @@ -1594,6 +1611,13 @@ struct OSMWay { return turn_channel_; } + void AddPronunciations(std::vector& pronunciations, + const UniqueNames& name_offset_map, + const uint32_t pronunciation_index, + const size_t name_tokens_size, + const size_t key, + const baldr::PronunciationAlphabet verbal_type) const; + /** * Sets layer index(Z-level) of the way. * @param layer @@ -1614,9 +1638,18 @@ struct OSMWay { * @param name_offset_map map of unique names and refs from ways. * @return Returns vector of strings */ - std::vector - GetNames(const std::string& ref, const UniqueNames& name_offset_map, uint16_t& types) const; - std::vector GetTaggedValues(const UniqueNames& name_offset_map) const; + void GetNames(const std::string& ref, + const UniqueNames& name_offset_map, + const OSMPronunciation& pronunciation, + uint16_t& types, + std::vector& names, + std::vector& pronunciations) const; + + void GetTaggedValues(const UniqueNames& name_offset_map, + const OSMPronunciation& pronunciation, + const size_t& names_size, + std::vector& names, + std::vector& pronunciations) const; // OSM way Id uint64_t osmwayid_; @@ -1703,6 +1736,7 @@ struct OSMWay { uint32_t wheelchair_tag_ : 1; uint32_t spare0_ : 1; uint32_t has_user_tags_ : 1; + uint32_t has_pronunciation_tags_ : 1; uint32_t internal_ : 1; uint32_t hov_type_ : 1; uint32_t spare1_ : 1; diff --git a/valhalla/mjolnir/pbfgraphparser.h b/valhalla/mjolnir/pbfgraphparser.h index b898c2ddc5..4d71e0df24 100644 --- a/valhalla/mjolnir/pbfgraphparser.h +++ b/valhalla/mjolnir/pbfgraphparser.h @@ -23,12 +23,15 @@ class PBFGraphParser { * @param ways_file where to store the ways so they are not in memory * @param way_nodes_file where to store the nodes so they are not in memory * @param access_file where to store the access tags so they are not in memory + * @param pronunciation_file where to store the pronunciations so they are not in + * memory */ static OSMData ParseWays(const boost::property_tree::ptree& pt, const std::vector& input_files, const std::string& ways_file, const std::string& way_nodes_file, - const std::string& access_file); + const std::string& access_file, + const std::string& pronunciation_file); /** * Loads given input files diff --git a/valhalla/odin/directionsbuilder.h b/valhalla/odin/directionsbuilder.h index b31655a9b7..7a981c646d 100644 --- a/valhalla/odin/directionsbuilder.h +++ b/valhalla/odin/directionsbuilder.h @@ -5,6 +5,7 @@ #include #include +#include #include namespace valhalla { @@ -26,7 +27,7 @@ class DirectionsBuilder { * @param api the protobuf object containing the request, the path and a place * to store the resulting directions */ - static void Build(Api& api); + static void Build(Api& api, const MarkupFormatter& markup_formatter); protected: /** diff --git a/valhalla/odin/markup_formatter.h b/valhalla/odin/markup_formatter.h new file mode 100644 index 0000000000..7206e1f949 --- /dev/null +++ b/valhalla/odin/markup_formatter.h @@ -0,0 +1,69 @@ +#pragma once + +#include + +#include +#include + +#include +#include + +namespace valhalla { +namespace odin { + +class MarkupFormatter { +public: + /** + * Constructor. + * @param config the valhalla odin config values. + */ + explicit MarkupFormatter(const boost::property_tree::ptree& config = {}); + + /** + * Returns true if markup is enabled. + * @return true if markup is enabled. + */ + bool markup_enabled() const; + + /** + * Sets the markup enabled flag. + * @param markup_enabled bool flag to enable/disable markup. + */ + void set_markup_enabled(bool markup_enabled); + + /** + * Return the street name with phoneme markup if it exists. + * + * @param street_name the street name record to format. + * @return the street name with phoneme markup if it exists. + */ + boost::optional Format(const std::unique_ptr& street_name) const; + + /** + * Return the sign with phoneme markup if it exists. + * + * @param sign the sign record to format. + * @return the sign with phoneme markup if it exists. + */ + boost::optional Format(const Sign& sign) const; + +protected: + /** + * Returns the phoneme format string. + * @return the phoneme format string. + */ + const std::string& phoneme_format() const; + + bool UseSingleQuotes(valhalla::Pronunciation_Alphabet alphabet) const; + + void FormatQuotes(std::string& markup_string, valhalla::Pronunciation_Alphabet alphabet) const; + + std::string FormatPhonemeElement(const std::string& textual_string, + const boost::optional& pronunciation) const; + + bool markup_enabled_; + std::string phoneme_format_; +}; + +} // namespace odin +} // namespace valhalla diff --git a/valhalla/odin/narrative_builder_factory.h b/valhalla/odin/narrative_builder_factory.h index cd44605626..c628bd730a 100644 --- a/valhalla/odin/narrative_builder_factory.h +++ b/valhalla/odin/narrative_builder_factory.h @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -29,7 +30,8 @@ class NarrativeBuilderFactory { * @return NarrativeBuilder unique pointer. */ static std::unique_ptr Create(const Options& options, - const EnhancedTripLeg* trip_path); + const EnhancedTripLeg* trip_path, + const MarkupFormatter& markup_formatter); }; } // namespace odin diff --git a/valhalla/odin/narrativebuilder.h b/valhalla/odin/narrativebuilder.h index 51a3461b40..ecfe46934d 100644 --- a/valhalla/odin/narrativebuilder.h +++ b/valhalla/odin/narrativebuilder.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -20,7 +21,8 @@ class NarrativeBuilder { public: NarrativeBuilder(const Options& options, const EnhancedTripLeg* trip_path, - const NarrativeDictionary& dictionary); + const NarrativeDictionary& dictionary, + const MarkupFormatter& markup_formatter); virtual ~NarrativeBuilder() = default; @@ -584,7 +586,20 @@ class NarrativeBuilder { * @return the verbal multi-cue instruction based on the specified maneuvers. */ std::string - FormVerbalMultiCue(Maneuver* maneuver, Maneuver& next_maneuver, bool process_succinct = false); + FormVerbalMultiCue(Maneuver& maneuver, Maneuver& next_maneuver, bool process_succinct = false); + + /** + * Returns the verbal multi-cue instruction based on the specified maneuver and strings. + * + * @param maneuver The current quick maneuver. + * @param first_verbal_cue The first verbal cue in the returned instruction. + * @param second_verbal_cue The second verbal cue in the returned instruction. + * + * @return the verbal multi-cue instruction based on the specified maneuver and strings. + */ + std::string FormVerbalMultiCue(Maneuver& maneuver, + const std::string& first_verbal_cue, + const std::string& second_verbal_cue); /** * Returns true if a verbal multi-cue instruction should be formed for the @@ -631,6 +646,7 @@ class NarrativeBuilder { const Options& options_; const EnhancedTripLeg* trip_path_; const NarrativeDictionary& dictionary_; + MarkupFormatter markup_formatter_; // No ref - need our own copy bool articulated_preposition_enabled_; }; @@ -640,8 +656,9 @@ class NarrativeBuilder_csCZ : public NarrativeBuilder { public: NarrativeBuilder_csCZ(const Options& options, const EnhancedTripLeg* trip_path, - const NarrativeDictionary& dictionary) - : NarrativeBuilder(options, trip_path, dictionary) { + const NarrativeDictionary& dictionary, + const MarkupFormatter& markup_formatter) + : NarrativeBuilder(options, trip_path, dictionary, markup_formatter) { } protected: @@ -663,8 +680,9 @@ class NarrativeBuilder_hiIN : public NarrativeBuilder { public: NarrativeBuilder_hiIN(const Options& options, const EnhancedTripLeg* trip_path, - const NarrativeDictionary& dictionary) - : NarrativeBuilder(options, trip_path, dictionary) { + const NarrativeDictionary& dictionary, + const MarkupFormatter& markup_formatter) + : NarrativeBuilder(options, trip_path, dictionary, markup_formatter) { } protected: @@ -686,8 +704,9 @@ class NarrativeBuilder_itIT : public NarrativeBuilder { public: NarrativeBuilder_itIT(const Options& options, const EnhancedTripLeg* trip_path, - const NarrativeDictionary& dictionary) - : NarrativeBuilder(options, trip_path, dictionary) { + const NarrativeDictionary& dictionary, + const MarkupFormatter& markup_formatter) + : NarrativeBuilder(options, trip_path, dictionary, markup_formatter) { // Enable articulated prepositions for Itailian articulated_preposition_enabled_ = true; } @@ -708,8 +727,9 @@ class NarrativeBuilder_ruRU : public NarrativeBuilder { public: NarrativeBuilder_ruRU(const Options& options, const EnhancedTripLeg* trip_path, - const NarrativeDictionary& dictionary) - : NarrativeBuilder(options, trip_path, dictionary) { + const NarrativeDictionary& dictionary, + const MarkupFormatter& markup_formatter) + : NarrativeBuilder(options, trip_path, dictionary, markup_formatter) { } protected: diff --git a/valhalla/odin/sign.h b/valhalla/odin/sign.h index cb9961e755..c6bdfe8e63 100644 --- a/valhalla/odin/sign.h +++ b/valhalla/odin/sign.h @@ -4,6 +4,10 @@ #include #include +#include + +#include + namespace valhalla { namespace odin { @@ -13,8 +17,11 @@ class Sign { * Constructor. * @param text Text string. * @param is_route_number boolean indicating if sign element is a reference route number. + * @param pronunciation the pronunciation of this sign. */ - Sign(const std::string& text, const bool is_route_number); + Sign(const std::string& text, + const bool is_route_number, + const boost::optional& pronunciation = boost::none); /** * Returns the sign text. @@ -40,6 +47,12 @@ class Sign { */ void set_consecutive_count(uint32_t consecutive_count); + /** + * Returns the pronunciation of this sign. + * @return the pronunciation of this sign. + */ + const boost::optional& pronunciation() const; + #ifdef LOGGING_LEVEL_TRACE std::string ToParameterString() const; #endif @@ -50,6 +63,7 @@ class Sign { std::string text_; bool is_route_number_; uint32_t consecutive_count_; + boost::optional pronunciation_; }; } // namespace odin diff --git a/valhalla/odin/signs.h b/valhalla/odin/signs.h index 17773a1f5f..36d82f386f 100644 --- a/valhalla/odin/signs.h +++ b/valhalla/odin/signs.h @@ -7,6 +7,7 @@ #include #include +#include #include using namespace valhalla::baldr; @@ -34,7 +35,8 @@ class Signs { std::string GetExitNumberString(uint32_t max_count = 0, bool limit_by_consecutive_count = false, const std::string& delim = "/", - const VerbalTextFormatter* verbal_formatter = nullptr) const; + const VerbalTextFormatter* verbal_formatter = nullptr, + const MarkupFormatter* markup_formatter = nullptr) const; const std::vector& exit_branch_list() const; std::vector* mutable_exit_branch_list(); @@ -42,7 +44,8 @@ class Signs { std::string GetExitBranchString(uint32_t max_count = 0, bool limit_by_consecutive_count = false, const std::string& delim = "/", - const VerbalTextFormatter* verbal_formatter = nullptr) const; + const VerbalTextFormatter* verbal_formatter = nullptr, + const MarkupFormatter* markup_formatter = nullptr) const; const std::vector& exit_toward_list() const; std::vector* mutable_exit_toward_list(); @@ -50,7 +53,8 @@ class Signs { std::string GetExitTowardString(uint32_t max_count = 0, bool limit_by_consecutive_count = false, const std::string& delim = "/", - const VerbalTextFormatter* verbal_formatter = nullptr) const; + const VerbalTextFormatter* verbal_formatter = nullptr, + const MarkupFormatter* markup_formatter = nullptr) const; const std::vector& exit_name_list() const; std::vector* mutable_exit_name_list(); @@ -58,7 +62,8 @@ class Signs { std::string GetExitNameString(uint32_t max_count = 0, bool limit_by_consecutive_count = false, const std::string& delim = "/", - const VerbalTextFormatter* verbal_formatter = nullptr) const; + const VerbalTextFormatter* verbal_formatter = nullptr, + const MarkupFormatter* markup_formatter = nullptr) const; const std::vector& guide_branch_list() const; std::vector* mutable_guide_branch_list(); @@ -66,7 +71,8 @@ class Signs { std::string GetGuideBranchString(uint32_t max_count = 0, bool limit_by_consecutive_count = false, const std::string& delim = "/", - const VerbalTextFormatter* verbal_formatter = nullptr) const; + const VerbalTextFormatter* verbal_formatter = nullptr, + const MarkupFormatter* markup_formatter = nullptr) const; const std::vector& guide_toward_list() const; std::vector* mutable_guide_toward_list(); @@ -74,12 +80,14 @@ class Signs { std::string GetGuideTowardString(uint32_t max_count = 0, bool limit_by_consecutive_count = false, const std::string& delim = "/", - const VerbalTextFormatter* verbal_formatter = nullptr) const; + const VerbalTextFormatter* verbal_formatter = nullptr, + const MarkupFormatter* markup_formatter = nullptr) const; std::string GetGuideString(uint32_t max_count = 0, bool limit_by_consecutive_count = false, const std::string& delim = "/", - const VerbalTextFormatter* verbal_formatter = nullptr) const; + const VerbalTextFormatter* verbal_formatter = nullptr, + const MarkupFormatter* markup_formatter = nullptr) const; std::vector GetGuideSigns(uint32_t max_count = 0, bool limit_by_consecutive_count = false) const; @@ -90,7 +98,8 @@ class Signs { std::string GetJunctionNameString(uint32_t max_count = 0, bool limit_by_consecutive_count = false, const std::string& delim = "/", - const VerbalTextFormatter* verbal_formatter = nullptr) const; + const VerbalTextFormatter* verbal_formatter = nullptr, + const MarkupFormatter* markup_formatter = nullptr) const; bool HasExit() const; bool HasExitNumber() const; @@ -117,7 +126,8 @@ class Signs { uint32_t max_count = 0, bool limit_by_consecutive_count = false, const std::string& delim = "/", - const VerbalTextFormatter* verbal_formatter = nullptr) const; + const VerbalTextFormatter* verbal_formatter = nullptr, + const MarkupFormatter* markup_formatter = nullptr) const; #ifdef LOGGING_LEVEL_TRACE std::string ListToParameterString(const std::vector& signs) const; diff --git a/valhalla/odin/worker.h b/valhalla/odin/worker.h index e2319c2f03..e8c3439773 100644 --- a/valhalla/odin/worker.h +++ b/valhalla/odin/worker.h @@ -1,6 +1,7 @@ #ifndef __VALHALLA_ODIN_SERVICE_H__ #define __VALHALLA_ODIN_SERVICE_H__ +#include #include #include @@ -29,6 +30,9 @@ class odin_worker_t : public service_worker_t { std::string narrate(Api& request) const; void status(Api& request) const; +protected: + MarkupFormatter markup_formatter_; + private: std::string service_name() const override { return "odin"; diff --git a/valhalla/proto_conversions.h b/valhalla/proto_conversions.h index de38dd1ac7..9ae48a211a 100644 --- a/valhalla/proto_conversions.h +++ b/valhalla/proto_conversions.h @@ -127,6 +127,24 @@ inline TripLeg_Node_Type GetTripLegNodeType(const baldr::NodeType node_type) { " Unhandled NodeType: " + std::to_string(num)); } +inline Pronunciation_Alphabet +GetTripPronunciationAlphabet(const valhalla::baldr::PronunciationAlphabet pronunciation_alphabet) { + switch (pronunciation_alphabet) { + case baldr::PronunciationAlphabet::kNone: + case baldr::PronunciationAlphabet::kIpa: + return Pronunciation_Alphabet_kIpa; + case baldr::PronunciationAlphabet::kXKatakana: + return Pronunciation_Alphabet_kXKatakana; + case baldr::PronunciationAlphabet::kXJeita: + return Pronunciation_Alphabet_kXJeita; + case baldr::PronunciationAlphabet::kNtSampa: + return Pronunciation_Alphabet_kNtSampa; + } + auto num = static_cast(pronunciation_alphabet); + throw std::runtime_error(std::string(__FILE__) + ":" + std::to_string(__LINE__) + + " Unhandled PronunciationAlphabet: " + std::to_string(num)); +} + // Associate cycle lane values to TripLeg proto constexpr TripLeg_CycleLane kTripLegCycleLane[] = {TripLeg_CycleLane_kNoCycleLane, TripLeg_CycleLane_kShared,