From 795972e4ac69000bc744183373c7b154bcaf3869 Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Wed, 1 Jun 2022 20:13:57 +0300 Subject: [PATCH 01/14] [routing] Extended navigation info about roads 2nd iteration for #849 Extended info about next street/road: - for next street it will show "[ref] name" . - for highway links - "[junction:ref]: [target:ref] > target". If no target - it will be replaced by name of next street. If no [target:ref] - it will be replaced by [ref] of next road. Signed-off-by: Anton Makouski --- .../maps/bookmarks/data/Metadata.java | 3 +- generator/osm2meta.cpp | 16 ++++- generator/osm2meta.hpp | 1 + indexer/feature_meta.cpp | 7 ++- indexer/feature_meta.hpp | 1 + indexer/map_object.hpp | 1 + routing/car_directions.cpp | 8 +-- routing/directions_engine.cpp | 20 +++---- routing/loaded_path_segment.hpp | 2 +- routing/pedestrian_directions.cpp | 4 +- routing/route.cpp | 58 ++++++++++++++++--- routing/route.hpp | 38 ++++++++---- routing/routing_helpers.cpp | 3 +- routing/routing_session.cpp | 40 ++++++++++++- 14 files changed, 156 insertions(+), 46 deletions(-) diff --git a/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java b/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java index d69937a102..1350c6b085 100644 --- a/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java +++ b/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java @@ -55,7 +55,8 @@ public class Metadata implements Parcelable FMD_CONTACT_VK(35), FMD_CONTACT_LINE(36), FMD_DESTINATION(37), - FMD_DESTINATION_REF(38); + FMD_DESTINATION_REF(38), + FMD_JUNCTION_REF(39); private final int mMetaType; MetadataType(int metadataType) diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index c2f9e93d88..337e31a513 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -148,7 +148,15 @@ string MetadataTagProcessorImpl::ValidateAndFormat_ele(string const & v) const string MetadataTagProcessorImpl::ValidateAndFormat_destination(string const & v) const { - return v; + string r; + strings::Tokenize(v, ";", [&](std::string_view d) + { + if (r.empty()) + r = d; + else + r += "; " + string(strings::Trim(d)); + }); + return r; } string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const & v) const @@ -156,6 +164,11 @@ string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const return v; } +string MetadataTagProcessorImpl::ValidateAndFormat_junction_ref(string const & v) const +{ + return v; +} + string MetadataTagProcessorImpl::ValidateAndFormat_turn_lanes(string const & v) const { return v; @@ -458,6 +471,7 @@ void MetadataTagProcessor::operator()(std::string const & k, std::string const & case Metadata::FMD_ELE: valid = ValidateAndFormat_ele(v); break; case Metadata::FMD_DESTINATION: valid = ValidateAndFormat_destination(v); break; case Metadata::FMD_DESTINATION_REF: valid = ValidateAndFormat_destination_ref(v); break; + case Metadata::FMD_JUNCTION_REF: valid = ValidateAndFormat_junction_ref(v); break; case Metadata::FMD_TURN_LANES: valid = ValidateAndFormat_turn_lanes(v); break; case Metadata::FMD_TURN_LANES_FORWARD: valid = ValidateAndFormat_turn_lanes_forward(v); break; case Metadata::FMD_TURN_LANES_BACKWARD: valid = ValidateAndFormat_turn_lanes_backward(v); break; diff --git a/generator/osm2meta.hpp b/generator/osm2meta.hpp index 9a5a628f8f..ee82bcd6db 100644 --- a/generator/osm2meta.hpp +++ b/generator/osm2meta.hpp @@ -18,6 +18,7 @@ struct MetadataTagProcessorImpl std::string ValidateAndFormat_ele(std::string const & v) const; std::string ValidateAndFormat_destination(std::string const & v) const; std::string ValidateAndFormat_destination_ref(std::string const & v) const; + std::string ValidateAndFormat_junction_ref(std::string const & v) const; std::string ValidateAndFormat_turn_lanes(std::string const & v) const; std::string ValidateAndFormat_turn_lanes_forward(std::string const & v) const; std::string ValidateAndFormat_turn_lanes_backward(std::string const & v) const; diff --git a/indexer/feature_meta.cpp b/indexer/feature_meta.cpp index df89d0b47e..6f9416ec05 100644 --- a/indexer/feature_meta.cpp +++ b/indexer/feature_meta.cpp @@ -76,6 +76,8 @@ bool Metadata::TypeFromString(string const & k, Metadata::EType & outType) outType = Metadata::FMD_DESTINATION; else if (k == "destination:ref") outType = Metadata::FMD_DESTINATION_REF; + else if (k == "junction:ref") + outType = Metadata::FMD_JUNCTION_REF; else if (k == "turn:lanes") outType = Metadata::FMD_TURN_LANES; else if (k == "turn:lanes:forward") @@ -173,8 +175,9 @@ string ToString(Metadata::EType type) case Metadata::FMD_CONTACT_LINE: return "contact:line"; case Metadata::FMD_INTERNET: return "internet_access"; case Metadata::FMD_ELE: return "ele"; - case Metadata::FMD_DESTINATION: return "desination"; - case Metadata::FMD_DESTINATION_REF: return "desination:ref"; + case Metadata::FMD_DESTINATION: return "destination"; + case Metadata::FMD_DESTINATION_REF: return "destination:ref"; + case Metadata::FMD_JUNCTION_REF: return "junction:ref"; case Metadata::FMD_TURN_LANES: return "turn:lanes"; case Metadata::FMD_TURN_LANES_FORWARD: return "turn:lanes:forward"; case Metadata::FMD_TURN_LANES_BACKWARD: return "turn:lanes:backward"; diff --git a/indexer/feature_meta.hpp b/indexer/feature_meta.hpp index a93dd1b86b..2ab35708f5 100644 --- a/indexer/feature_meta.hpp +++ b/indexer/feature_meta.hpp @@ -155,6 +155,7 @@ public: FMD_CONTACT_LINE = 36, FMD_DESTINATION = 37, FMD_DESTINATION_REF = 38, + FMD_JUNCTION_REF = 39, FMD_COUNT }; diff --git a/indexer/map_object.hpp b/indexer/map_object.hpp index 2c58e362d0..a659e63124 100644 --- a/indexer/map_object.hpp +++ b/indexer/map_object.hpp @@ -181,6 +181,7 @@ std::vector MetadataToProps(std::vector const & metadata) case Metadata::FMD_DESTINATION: case Metadata::FMD_DESTINATION_REF: + case Metadata::FMD_JUNCTION_REF: case Metadata::FMD_TURN_LANES: case Metadata::FMD_TURN_LANES_FORWARD: case Metadata::FMD_TURN_LANES_BACKWARD: diff --git a/routing/car_directions.cpp b/routing/car_directions.cpp index ec74406771..864c4f0535 100644 --- a/routing/car_directions.cpp +++ b/routing/car_directions.cpp @@ -418,8 +418,8 @@ void GetTurnDirectionBasic(IRoutingResult const & result, size_t const outgoingS if (!GetTurnInfo(result, outgoingSegmentIndex, vehicleSettings, turnInfo)) return; - turn.m_sourceName = turnInfo.m_ingoing->m_name; - turn.m_targetName = turnInfo.m_outgoing->m_name; + turn.m_sourceName = turnInfo.m_ingoing->m_roadNameInfo.m_name; + turn.m_targetName = turnInfo.m_outgoing->m_roadNameInfo.m_name; turn.m_turn = CarDirection::None; ASSERT_GREATER(turnInfo.m_ingoing->m_path.size(), 1, ()); @@ -531,7 +531,7 @@ size_t CheckUTurnOnRoute(IRoutingResult const & result, size_t const outgoingSeg if (checkedSegment.m_path.size() < 2) return 0; - if (checkedSegment.m_name == masterSegment.m_name && + if (checkedSegment.m_roadNameInfo.m_name == masterSegment.m_roadNameInfo.m_name && checkedSegment.m_highwayClass == masterSegment.m_highwayClass && checkedSegment.m_isLink == masterSegment.m_isLink && !checkedSegment.m_onRoundabout) { @@ -555,7 +555,7 @@ size_t CheckUTurnOnRoute(IRoutingResult const & result, size_t const outgoingSeg } // Avoid the UTurn on unnamed roads inside the rectangle based distinct. - if (checkedSegment.m_name.empty()) + if (checkedSegment.m_roadNameInfo.m_name.empty()) return 0; // Avoid returning to the same edge after uturn somewere else. diff --git a/routing/directions_engine.cpp b/routing/directions_engine.cpp index 7671ad10b9..d757714d48 100644 --- a/routing/directions_engine.cpp +++ b/routing/directions_engine.cpp @@ -66,18 +66,12 @@ void DirectionsEngine::LoadPathAttributes(FeatureID const & featureId, pathSegment.m_onRoundabout = ftypes::IsRoundAboutChecker::Instance()(*ft); pathSegment.m_isOneWay = ftypes::IsOneWayChecker::Instance()(*ft); - if (pathSegment.m_isLink) - { - if (auto const & dst_number = ft->GetMetadata(feature::Metadata::FMD_DESTINATION_REF); !dst_number.empty()) - pathSegment.m_name = "[" + string(dst_number) + "] "; - pathSegment.m_name += ft->GetMetadata(feature::Metadata::FMD_DESTINATION); - } - else - { - if (auto const & road_number = ft->GetRoadNumber(); !road_number.empty()) - pathSegment.m_name = "[" + road_number + "] "; - pathSegment.m_name += ft->GetName(StringUtf8Multilang::kDefaultCode); - } + pathSegment.m_roadNameInfo.m_isLink = pathSegment.m_isLink; + pathSegment.m_roadNameInfo.m_junction_ref = ft->GetMetadata(feature::Metadata::FMD_JUNCTION_REF); + pathSegment.m_roadNameInfo.m_destination_ref = ft->GetMetadata(feature::Metadata::FMD_DESTINATION_REF); + pathSegment.m_roadNameInfo.m_destination = ft->GetMetadata(feature::Metadata::FMD_DESTINATION); + pathSegment.m_roadNameInfo.m_ref = ft->GetRoadNumber(); + pathSegment.m_roadNameInfo.m_name = ft->GetName(StringUtf8Multilang::kDefaultCode); } void DirectionsEngine::GetSegmentRangeAndAdjacentEdges(IRoadGraph::EdgeListT const & outgoingEdges, @@ -355,7 +349,7 @@ RouterResultCode DirectionsEngine::MakeTurnAnnotation(IndexRoadGraph::EdgeVector // Street names contain empty names too for avoiding of freezing of old street name while // moving along unnamed street. - streets.emplace_back(max(junctions.size(), static_cast(1)) - 1, loadedSegmentIt->m_name); + streets.emplace_back(max(junctions.size(), static_cast(1)) - 1, loadedSegmentIt->m_roadNameInfo); // Turns information. if (!junctions.empty() && skipTurnSegments == 0) diff --git a/routing/loaded_path_segment.hpp b/routing/loaded_path_segment.hpp index 3a3b178866..59a618e45c 100644 --- a/routing/loaded_path_segment.hpp +++ b/routing/loaded_path_segment.hpp @@ -22,7 +22,7 @@ struct LoadedPathSegment { std::vector m_path; std::vector m_lanes; - std::string m_name; + RouteSegment::RoadNameInfo m_roadNameInfo; double m_weight = 0.0; /*!< Time in seconds to pass the segment. */ SegmentRange m_segmentRange; std::vector m_segments; /*!< Traffic segments for |m_path|. */ diff --git a/routing/pedestrian_directions.cpp b/routing/pedestrian_directions.cpp index c6e73b978b..bddffe9e82 100644 --- a/routing/pedestrian_directions.cpp +++ b/routing/pedestrian_directions.cpp @@ -30,8 +30,8 @@ size_t PedestrianDirectionsEngine::GetTurnDirection(IRoutingResult const & resul double const turnAngle = CalcTurnAngle(result, outgoingSegmentIndex, numMwmIds, vehicleSettings); - turn.m_sourceName = turnInfo.m_ingoing->m_name; - turn.m_targetName = turnInfo.m_outgoing->m_name; + turn.m_sourceName = turnInfo.m_ingoing->m_roadNameInfo.m_name; + turn.m_targetName = turnInfo.m_outgoing->m_roadNameInfo.m_name; turn.m_pedestrianTurn = PedestrianDirection::None; ASSERT_GREATER(turnInfo.m_ingoing->m_path.size(), 1, ()); diff --git a/routing/route.cpp b/routing/route.cpp index 36ae0b0e4c..a8ce24cb17 100644 --- a/routing/route.cpp +++ b/routing/route.cpp @@ -117,18 +117,41 @@ double Route::GetCurrentTimeToEndSec() const m_poly.GetDistFromCurPointToRoutePointMeters() / curSegSpeedMPerS); } -void Route::GetCurrentStreetName(string & name) const +void Route::GetCurrentStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const { - GetStreetNameAfterIdx(static_cast(m_poly.GetCurrentIter().m_ind), name); + GetStreetNameAfterIdx(static_cast(m_poly.GetCurrentIter().m_ind), roadNameInfo); } -void Route::GetStreetNameAfterIdx(uint32_t idx, string & name) const +void Route::GetNextTurnStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const +{ + double distance; + TurnItem turn; + GetCurrentTurn(distance, turn); + GetStreetNameAfterIdx(turn.m_index, roadNameInfo); +} + +// If exit is false, returns ref and name. +// If exit is true, returns m_junction_ref, m_destination_ref, m_destination, m_name. +// Handling of incomplete data or non-standard data: +// - We go trough 400m to find first segment with existing data. +// Bit for link we go through all segments till we reach non-link segment, +// Sometimes links are really long (e.g. 1km+ in USA) and they have no tags. +// - Normally for link both destination and destination:ref tags exist together. +// But sometimes only destination tag exists for link. And destination:ref can be calculated +// by checking next segments of route until link will end and normal r will start. +// Hopefully it will have ref tag. So we can show it instead of destination:ref. +// Also we can add info about it's name. +// - Sometimes exit is not tagged as link (e.g. if new r starts here). +// At the same time they can have all useful tags just like link. +// Usually destination:ref=ref in such cases, or only 1st part of destination:ref can match. +void Route::GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const { - name.clear(); auto const iterIdx = m_poly.GetIterToIndex(idx); if (!IsValid() || !iterIdx.IsValid()) return; + RouteSegment::RoadNameInfo roadNameInfoNext; + size_t i = idx; for (; i < m_poly.GetPolyline().GetSize(); ++i) { @@ -137,16 +160,33 @@ void Route::GetStreetNameAfterIdx(uint32_t idx, string & name) const if (i == 0) continue; - string const street = m_routeSegments[ConvertPointIdxToSegmentIdx(i)].GetStreet(); - if (!street.empty()) + auto const & r = m_routeSegments[ConvertPointIdxToSegmentIdx(i)].GetRoadNameInfo(); + + if (r.HasBasicTextInfo()) { - name = street; - return; + if (roadNameInfo.HasExitInfo()) + roadNameInfoNext = r; + else + roadNameInfo = r; + break; } + else if (r.HasExitInfo() && !roadNameInfo.HasExitInfo()) + roadNameInfo = r; + // For exit wait for non-exit + else if (roadNameInfo.HasExitInfo() && !r.m_isLink) + continue; + auto const furtherIter = m_poly.GetIterToIndex(i); CHECK(furtherIter.IsValid(), ()); if (m_poly.GetDistanceM(iterIdx, furtherIter) > kSteetNameLinkMeters) - return; + break; + } + + if (roadNameInfo.HasExitInfo()) + { + if (roadNameInfo.m_destination_ref.empty()) + roadNameInfo.m_destination_ref = roadNameInfoNext.m_ref; + roadNameInfo.m_name = roadNameInfoNext.m_name; } } diff --git a/routing/route.hpp b/routing/route.hpp index d3288460d1..dd75f8ecf4 100644 --- a/routing/route.hpp +++ b/routing/route.hpp @@ -64,15 +64,30 @@ public: uint8_t m_maxSpeedKmPH = 0; }; + struct RoadNameInfo + { + bool m_isLink; + // This is for street/road. |m_ref| |m_name|. + std::string m_ref; // Number of street/road .g. "CA 85". + std::string m_name; // E.g "Johnson Ave.". + // This is for 1st segment of link after junction. Exit |junction_ref| to |m_destination_ref| for |m_destination|. + std::string m_junction_ref; // Number of junction e.g. "398B". + std::string m_destination_ref; // Number of next road, e.g. "CA 85", Sometimes "CA 85 South". + std::string m_destination; // E.g. "Cupertino". + bool HasBasicTextInfo() const { return !m_ref.empty() || !m_name.empty(); } + bool HasExitInfo() const { return m_isLink || !m_junction_ref.empty() || !m_destination_ref.empty() || !m_destination.empty(); } + RoadNameInfo() { m_isLink = false; } + }; + RouteSegment(Segment const & segment, turns::TurnItem const & turn, - geometry::PointWithAltitude const & junction, std::string const & street, + geometry::PointWithAltitude const & junction, RoadNameInfo const & roadNameInfo, double distFromBeginningMeters, double distFromBeginningMerc, double timeFromBeginningS, traffic::SpeedGroup traffic, std::unique_ptr transitInfo) : m_segment(segment) , m_turn(turn) , m_junction(junction) - , m_street(street) + , m_roadNameInfo(roadNameInfo) , m_distFromBeginningMeters(distFromBeginningMeters) , m_distFromBeginningMerc(distFromBeginningMerc) , m_timeFromBeginningS(timeFromBeginningS) @@ -89,7 +104,7 @@ public: Segment const & GetSegment() const { return m_segment; } Segment & GetSegment() { return m_segment; } geometry::PointWithAltitude const & GetJunction() const { return m_junction; } - std::string const & GetStreet() const { return m_street; } + RoadNameInfo const & GetRoadNameInfo() const { return m_roadNameInfo; } traffic::SpeedGroup GetTraffic() const { return m_traffic; } turns::TurnItem const & GetTurn() const { return m_turn; } @@ -116,8 +131,8 @@ private: /// The furthest point of the segment from the beginning of the route along the route. geometry::PointWithAltitude m_junction; - /// Street name of |m_segment| if any. Otherwise |m_street| is empty. - std::string m_street; + /// RoadNameInfo of |m_segment| if any. Otherwise |m_roadInfo| is empty. + RoadNameInfo m_roadNameInfo; /// Distance from the route (not the subroute) beginning to the farthest end of |m_segment| in meters. double m_distFromBeginningMeters = 0.0; @@ -147,7 +162,7 @@ public: using TTurns = std::vector; using TTimeItem = std::pair; using TTimes = std::vector; - using TStreetItem = std::pair; + using TStreetItem = std::pair; using TStreets = std::vector; class SubrouteAttrs final @@ -299,11 +314,11 @@ public: /// set with MoveIterator() method. If it's not possible returns nullopt. std::optional GetCurrentIteratorTurn() const; - /// \brief Returns a name of a street where the user rides at this moment. - void GetCurrentStreetName(std::string & name) const; + /// \brief Returns name info of a street where the user rides at this moment. + void GetCurrentStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const; - /// \brief Returns a name of a street next to idx point of the path. Function avoids short unnamed links. - void GetStreetNameAfterIdx(uint32_t idx, std::string & name) const; + /// \brief Return name info of a street according to next turn. + void GetNextTurnStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const; /// \brief Gets turn information after the turn next to the nearest one. /// \param distanceToTurnMeters is a distance from current position to the second turn. @@ -390,6 +405,9 @@ private: void GetClosestTurn(size_t segIdx, turns::TurnItem & turn) const; size_t ConvertPointIdxToSegmentIdx(size_t pointIdx) const; + /// \brief Returns a name info of a street next to idx point of the path. + void GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const; + /// \returns Estimated time to pass the route segment with |segIdx|. double GetTimeToPassSegSec(size_t segIdx) const; diff --git a/routing/routing_helpers.cpp b/routing/routing_helpers.cpp index d1d78d34a8..47c4a16e86 100644 --- a/routing/routing_helpers.cpp +++ b/routing/routing_helpers.cpp @@ -4,6 +4,7 @@ #include "routing/fake_feature_ids.hpp" #include "routing/index_graph_starter.hpp" #include "routing/road_point.hpp" +#include "routing/route.hpp" #include "routing/segment.hpp" #include "routing/traffic_stash.hpp" #include "routing/world_graph.hpp" @@ -68,7 +69,7 @@ void FillSegmentInfo(vector const & segments, ++turnIdx; } - string curStreet; + RouteSegment::RoadNameInfo curStreet; if (!streets.empty()) { CHECK_LESS_OR_EQUAL(streetIdx, streets.size(), ()); diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index 94a2f2dbea..557a2cd685 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -10,6 +10,8 @@ #include "geometry/angles.hpp" #include "geometry/mercator.hpp" +#include "indexer/road_shields_parser.hpp" + #include using namespace location; @@ -339,6 +341,36 @@ SessionState RoutingSession::OnLocationPositionChanged(GpsInfo const & info) return m_state; } +void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) +{ + if (auto const & sh = ftypes::GetRoadShields(road.m_ref); !sh.empty()) + road.m_ref = sh[0].m_name; + if (auto const & sh = ftypes::GetRoadShields(road.m_destination_ref); !sh.empty()) + road.m_destination_ref = sh[0].m_name; + + name.clear(); + if (road.HasExitInfo()) + { + if (!road.m_junction_ref.empty()) + name = "[" + road.m_junction_ref + "]"; + + if (!road.m_destination_ref.empty()) + name += string(name.empty() ? "" : ": ") + "[" + road.m_destination_ref + "]"; + + if (!road.m_destination.empty()) + name += string(name.empty() ? "" : " ") + "> " + road.m_destination; + else if (!road.m_name.empty()) + name += (road.m_destination_ref.empty() ? " : " : " ") + road.m_name; + } + else + { + if (!road.m_ref.empty()) + name = "[" + road.m_ref + "]"; + if (!road.m_name.empty()) + name += (name.empty() ? "" : " ") + road.m_name; + } +} + void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const { CHECK_THREAD_CHECKER(m_threadChecker, ()); @@ -376,8 +408,12 @@ void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const info.m_exitNum = turn.m_exitNum; info.m_time = static_cast(max(kMinimumETASec, m_route->GetCurrentTimeToEndSec())); - m_route->GetCurrentStreetName(info.m_sourceName); - m_route->GetStreetNameAfterIdx(turn.m_index, info.m_targetName); + RouteSegment::RoadNameInfo sourceRoadNameInfo, targetRoadNameInfo; + m_route->GetCurrentStreetName(sourceRoadNameInfo); + GetFullRoadName(sourceRoadNameInfo, info.m_sourceName); + m_route->GetNextTurnStreetName(targetRoadNameInfo); + GetFullRoadName(targetRoadNameInfo, info.m_targetName); + info.m_completionPercent = GetCompletionPercent(); // Lane information and next street name. -- 2.45.3 From 0ac29af999acd4253cdb2def48f12e3680ee97ae Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Thu, 2 Jun 2022 12:42:02 +0300 Subject: [PATCH 02/14] Comments + fix of compile error Signed-off-by: Anton Makouski --- routing/loaded_path_segment.hpp | 1 + routing/route.cpp | 25 +++++++++++++------------ routing/routing_session.cpp | 5 +++++ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/routing/loaded_path_segment.hpp b/routing/loaded_path_segment.hpp index 59a618e45c..3bb3e74e28 100644 --- a/routing/loaded_path_segment.hpp +++ b/routing/loaded_path_segment.hpp @@ -3,6 +3,7 @@ #include "routing/road_point.hpp" #include "routing/turns.hpp" #include "routing/segment.hpp" +#include "routing/route.hpp" #include "indexer/ftypes_matcher.hpp" diff --git a/routing/route.cpp b/routing/route.cpp index a8ce24cb17..9fdb118de8 100644 --- a/routing/route.cpp +++ b/routing/route.cpp @@ -134,26 +134,26 @@ void Route::GetNextTurnStreetName(RouteSegment::RoadNameInfo & roadNameInfo) con // If exit is true, returns m_junction_ref, m_destination_ref, m_destination, m_name. // Handling of incomplete data or non-standard data: // - We go trough 400m to find first segment with existing data. -// Bit for link we go through all segments till we reach non-link segment, -// Sometimes links are really long (e.g. 1km+ in USA) and they have no tags. +// But for link we go through all segments till we reach non-link segment, +// This is for really long links (e.g. 1km+ in USA) which have no tags. // - Normally for link both destination and destination:ref tags exist together. -// But sometimes only destination tag exists for link. And destination:ref can be calculated -// by checking next segments of route until link will end and normal r will start. -// Hopefully it will have ref tag. So we can show it instead of destination:ref. -// Also we can add info about it's name. -// - Sometimes exit is not tagged as link (e.g. if new r starts here). +// But sometimes only |destination| tag exists for link. And |destination:ref| can be calculated +// by checking next segments of route until link will end and normal road will start. +// Hopefully it will have |ref| tag. So we can use it instead of |destination:ref|. +// Also we can use info about it's |name|. It can be useful if no |destination| tag. +// - Sometimes exit is not tagged as link (e.g. if new road starts here). // At the same time they can have all useful tags just like link. -// Usually destination:ref=ref in such cases, or only 1st part of destination:ref can match. +// Usually |destination:ref| = |ref| in such cases, or only 1st part of |destination:ref| can match. void Route::GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const { auto const iterIdx = m_poly.GetIterToIndex(idx); if (!IsValid() || !iterIdx.IsValid()) return; + // Info about 1st segment with existing basic (non-link) info after link. RouteSegment::RoadNameInfo roadNameInfoNext; - size_t i = idx; - for (; i < m_poly.GetPolyline().GetSize(); ++i) + for (size_t i = idx; i < m_poly.GetPolyline().GetSize(); ++i) { // Note. curIter.m_ind == 0 means route iter at zero point. No corresponding route segments at // |m_routeSegments| in this case. |name| should be cleared. @@ -172,10 +172,10 @@ void Route::GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roa } else if (r.HasExitInfo() && !roadNameInfo.HasExitInfo()) roadNameInfo = r; - // For exit wait for non-exit + // For exit wait for non-exit. else if (roadNameInfo.HasExitInfo() && !r.m_isLink) continue; - + // For non-exits check only during first |kSteetNameLinkMeters|. auto const furtherIter = m_poly.GetIterToIndex(i); CHECK(furtherIter.IsValid(), ()); if (m_poly.GetDistanceM(iterIdx, furtherIter) > kSteetNameLinkMeters) @@ -184,6 +184,7 @@ void Route::GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roa if (roadNameInfo.HasExitInfo()) { + // Use basic info from |roadNameInfoNext| to update |roadNameInfo|. if (roadNameInfo.m_destination_ref.empty()) roadNameInfo.m_destination_ref = roadNameInfoNext.m_ref; roadNameInfo.m_name = roadNameInfoNext.m_name; diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index 557a2cd685..24ec379a90 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -341,6 +341,11 @@ SessionState RoutingSession::OnLocationPositionChanged(GpsInfo const & info) return m_state; } +// For next street returns "[ref] name" . +// For highway exits (or main roads with exit info) returns "[junction:ref]: [target:ref] > target". +// If no |target| - it will be replaced by |name| of next street. +// If no |target:ref| - it will be replaced by |ref| of next road. +// So if link has no info at all, "[ref] name" of next road will be returned (as for next street). void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) { if (auto const & sh = ftypes::GetRoadShields(road.m_ref); !sh.empty()) -- 2.45.3 From 1923961e28c2b5833adad1aee5e4ed1367811926 Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Fri, 3 Jun 2022 13:24:02 +0300 Subject: [PATCH 03/14] Test fixes, small bugfixes and review fixes Signed-off-by: Anton Makouski --- routing/car_directions.cpp | 6 +++ routing/route.hpp | 13 +++--- .../routing_integration_tests/route_test.cpp | 2 +- .../routing_test_tools.cpp | 15 +++---- .../street_names_test.cpp | 3 +- routing/routing_session.cpp | 36 +++++++-------- routing/routing_tests/route_tests.cpp | 44 +++++++++++-------- .../routing_tests/routing_helpers_tests.cpp | 10 +++-- .../routing_tests/turns_generator_test.cpp | 2 +- routing/turns_generator.cpp | 3 +- 10 files changed, 73 insertions(+), 61 deletions(-) diff --git a/routing/car_directions.cpp b/routing/car_directions.cpp index 864c4f0535..ede4d02122 100644 --- a/routing/car_directions.cpp +++ b/routing/car_directions.cpp @@ -101,6 +101,12 @@ size_t CarDirectionsEngine::GetTurnDirection(IRoutingResult const & result, size NumMwmIds const & numMwmIds, RoutingSettings const & vehicleSettings, TurnItem & turnItem) { + // This is for jump from initial point to start of the route. + /// @todo Sometimes results of GetPossibleTurns are empty, sometimes are invalid. + ///E.g. Google Maps until you reach destination will guide you go to the left or to the right of first road. + if (turnItem.m_index == 2) + return 0; + size_t skipTurnSegments = CheckUTurnOnRoute(result, outgoingSegmentIndex, numMwmIds, vehicleSettings, turnItem); if (turnItem.m_turn == CarDirection::None) diff --git a/routing/route.hpp b/routing/route.hpp index dd75f8ecf4..d1f75266e3 100644 --- a/routing/route.hpp +++ b/routing/route.hpp @@ -66,17 +66,16 @@ public: struct RoadNameInfo { - bool m_isLink; // This is for street/road. |m_ref| |m_name|. - std::string m_ref; // Number of street/road .g. "CA 85". std::string m_name; // E.g "Johnson Ave.". + std::string m_ref; // Number of street/road e.g. "CA 85". // This is for 1st segment of link after junction. Exit |junction_ref| to |m_destination_ref| for |m_destination|. std::string m_junction_ref; // Number of junction e.g. "398B". - std::string m_destination_ref; // Number of next road, e.g. "CA 85", Sometimes "CA 85 South". + std::string m_destination_ref; // Number of next road, e.g. "CA 85", Sometimes "CA 85 South". Usually match |m_ref| of next main road. std::string m_destination; // E.g. "Cupertino". + bool m_isLink = false; bool HasBasicTextInfo() const { return !m_ref.empty() || !m_name.empty(); } bool HasExitInfo() const { return m_isLink || !m_junction_ref.empty() || !m_destination_ref.empty() || !m_destination.empty(); } - RoadNameInfo() { m_isLink = false; } }; RouteSegment(Segment const & segment, turns::TurnItem const & turn, @@ -314,6 +313,9 @@ public: /// set with MoveIterator() method. If it's not possible returns nullopt. std::optional GetCurrentIteratorTurn() const; + /// \brief Returns a name info of a street next to idx point of the path. + void GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const; + /// \brief Returns name info of a street where the user rides at this moment. void GetCurrentStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const; @@ -405,9 +407,6 @@ private: void GetClosestTurn(size_t segIdx, turns::TurnItem & turn) const; size_t ConvertPointIdxToSegmentIdx(size_t pointIdx) const; - /// \brief Returns a name info of a street next to idx point of the path. - void GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const; - /// \returns Estimated time to pass the route segment with |segIdx|. double GetTimeToPassSegSec(size_t segIdx) const; diff --git a/routing/routing_integration_tests/route_test.cpp b/routing/routing_integration_tests/route_test.cpp index a980e703f1..543e070e53 100644 --- a/routing/routing_integration_tests/route_test.cpp +++ b/routing/routing_integration_tests/route_test.cpp @@ -422,7 +422,7 @@ using namespace std; for (auto const & routeSegment : routeSegments) { TEST(routeSegment.GetSpeedCams().empty(), - (routeSegment.GetSegment(), routeSegment.GetStreet())); + (routeSegment.GetSegment(), routeSegment.GetRoadNameInfo().m_name)); } } diff --git a/routing/routing_integration_tests/routing_test_tools.cpp b/routing/routing_integration_tests/routing_test_tools.cpp index 6afb4a9728..0be88ec83d 100644 --- a/routing/routing_integration_tests/routing_test_tools.cpp +++ b/routing/routing_integration_tests/routing_test_tools.cpp @@ -183,19 +183,16 @@ void TestTurnCount(routing::Route const & route, uint32_t expectedTurnCount) void TestCurrentStreetName(routing::Route const & route, string const & expectedStreetName) { - string streetName; - route.GetCurrentStreetName(streetName); - TEST_EQUAL(streetName, expectedStreetName, ()); + RouteSegment::RoadNameInfo roadNameInfo; + route.GetCurrentStreetName(roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, expectedStreetName, ()); } void TestNextStreetName(routing::Route const & route, string const & expectedStreetName) { - string streetName; - double distance; - turns::TurnItem turn; - route.GetCurrentTurn(distance, turn); - route.GetStreetNameAfterIdx(turn.m_index, streetName); - TEST_EQUAL(streetName, expectedStreetName, ()); + RouteSegment::RoadNameInfo roadNameInfo; + route.GetNextTurnStreetName(roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, expectedStreetName, ()); } void TestRouteLength(Route const & route, double expectedRouteMeters, double relativeError) diff --git a/routing/routing_integration_tests/street_names_test.cpp b/routing/routing_integration_tests/street_names_test.cpp index 5e9d90e6ba..8de66caf74 100644 --- a/routing/routing_integration_tests/street_names_test.cpp +++ b/routing/routing_integration_tests/street_names_test.cpp @@ -52,8 +52,9 @@ UNIT_TEST(RussiaTulskayaToPaveletskayaStreetNamesTest) MoveRoute(route, ms::LatLon(55.73034, 37.63099)); + // No more extra last turn, so TestNextStreetName returns "". integration::TestCurrentStreetName(route, "Валовая улица"); - integration::TestNextStreetName(route, "улица Зацепский Вал"); + //integration::TestNextStreetName(route, "улица Зацепский Вал"); MoveRoute(route, ms::LatLon(55.730912, 37.636191)); diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index 24ec379a90..a0bdacc079 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -345,7 +345,7 @@ SessionState RoutingSession::OnLocationPositionChanged(GpsInfo const & info) // For highway exits (or main roads with exit info) returns "[junction:ref]: [target:ref] > target". // If no |target| - it will be replaced by |name| of next street. // If no |target:ref| - it will be replaced by |ref| of next road. -// So if link has no info at all, "[ref] name" of next road will be returned (as for next street). +// So if link has no info at all, "[ref] name" of next will be returned (as for next street). void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) { if (auto const & sh = ftypes::GetRoadShields(road.m_ref); !sh.empty()) @@ -355,25 +355,25 @@ void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) name.clear(); if (road.HasExitInfo()) - { - if (!road.m_junction_ref.empty()) - name = "[" + road.m_junction_ref + "]"; + { + if (!road.m_junction_ref.empty()) + name = "[" + road.m_junction_ref + "]"; - if (!road.m_destination_ref.empty()) - name += string(name.empty() ? "" : ": ") + "[" + road.m_destination_ref + "]"; + if (!road.m_destination_ref.empty()) + name += string(name.empty() ? "" : ": ") + "[" + road.m_destination_ref + "]"; - if (!road.m_destination.empty()) - name += string(name.empty() ? "" : " ") + "> " + road.m_destination; - else if (!road.m_name.empty()) - name += (road.m_destination_ref.empty() ? " : " : " ") + road.m_name; - } - else - { - if (!road.m_ref.empty()) - name = "[" + road.m_ref + "]"; - if (!road.m_name.empty()) - name += (name.empty() ? "" : " ") + road.m_name; - } + if (!road.m_destination.empty()) + name += string(name.empty() ? "" : " ") + "> " + road.m_destination; + else if (!road.m_name.empty()) + name += (road.m_destination_ref.empty() ? string(name.empty() ? "" : " ") : ": ") + road.m_name; + } + else + { + if (!road.m_ref.empty()) + name = "[" + road.m_ref + "]"; + if (!road.m_name.empty()) + name += (name.empty() ? "" : " ") + road.m_name; + } } void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const diff --git a/routing/routing_tests/route_tests.cpp b/routing/routing_tests/route_tests.cpp index 009c3eaf51..c139ec1c2f 100644 --- a/routing/routing_tests/route_tests.cpp +++ b/routing/routing_tests/route_tests.cpp @@ -29,7 +29,9 @@ static Route::TTurns const kTestTurns( {turns::TurnItem(1, turns::CarDirection::TurnLeft), turns::TurnItem(2, turns::CarDirection::TurnRight), turns::TurnItem(4, turns::CarDirection::ReachedYourDestination)}); -static Route::TStreets const kTestNames({{0, "Street1"}, {1, "Street2"}, {4, "Street3"}}); +static Route::TStreets const kTestNames({{0, {"Street1", "", "", "", "", false}}, + {1, {"Street2", "", "", "", "", false}}, + {4, {"Street3", "", "", "", "", false}}}); static Route::TTimes const kTestTimes({Route::TTimeItem(1, 5), Route::TTimeItem(3, 10), Route::TTimeItem(4, 15)}); @@ -39,11 +41,15 @@ static Route::TTurns const kTestTurns2( turns::TurnItem(2, turns::CarDirection::TurnRight), turns::TurnItem(3, turns::CarDirection::None), turns::TurnItem(4, turns::CarDirection::ReachedYourDestination)}); -static vector const kTestNames2 = {"Street0", "Street1", "Street2", "", "Street3"}; +static vector const kTestNames2 = {{"Street0", "", "", "", "", false}, + {"Street1", "", "", "", "", false}, + {"Street2", "", "", "", "", false}, + {"", "", "", "", "", false}, + {"Street3", "", "", "", "", false}}; static vector const kTestTimes2 = {0.0, 5.0, 6.0, 10.0, 15.0}; void GetTestRouteSegments(vector const & routePoints, Route::TTurns const & turns, - vector const & streets, vector const & times, + vector const & streets, vector const & times, vector & routeSegments) { CHECK_EQUAL(routePoints.size(), turns.size(), ()); @@ -290,7 +296,7 @@ UNIT_TEST(SelfIntersectedRouteMatchingTest) Route route("TestRouter", 0 /* route id */); route.SetGeometry(kRouteGeometry.begin(), kRouteGeometry.end()); - + vector routeSegments; GetTestRouteSegments(kRouteGeometry, kTestTurns2, kTestNames2, kTestTimes2, routeSegments); route.SetRouteSegments(move(routeSegments)); @@ -346,30 +352,30 @@ UNIT_TEST(RouteNameTest) GetTestRouteSegments(kTestGeometry, kTestTurns2, kTestNames2, kTestTimes2, routeSegments); route.SetRouteSegments(move(routeSegments)); - string name; - route.GetCurrentStreetName(name); - TEST_EQUAL(name, "Street1", ()); + RouteSegment::RoadNameInfo roadNameInfo; + route.GetCurrentStreetName(roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street1", (roadNameInfo.m_name)); - route.GetStreetNameAfterIdx(0, name); - TEST_EQUAL(name, "Street1", ()); + route.GetStreetNameAfterIdx(0, roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street1", (roadNameInfo.m_name)); - route.GetStreetNameAfterIdx(1, name); - TEST_EQUAL(name, "Street1", ()); + route.GetStreetNameAfterIdx(1, roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street1", (roadNameInfo.m_name)); - route.GetStreetNameAfterIdx(2, name); - TEST_EQUAL(name, "Street2", ()); + route.GetStreetNameAfterIdx(2, roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street2", (roadNameInfo.m_name)); - route.GetStreetNameAfterIdx(3, name); - TEST_EQUAL(name, "Street3", ()); + route.GetStreetNameAfterIdx(3, roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street3", (roadNameInfo.m_name)); - route.GetStreetNameAfterIdx(4, name); - TEST_EQUAL(name, "Street3", ()); + route.GetStreetNameAfterIdx(4, roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street3", (roadNameInfo.m_name)); location::GpsInfo info; info.m_longitude = 1.0; info.m_latitude = 2.0; route.MoveIterator(info); - route.GetCurrentStreetName(name); - TEST_EQUAL(name, "Street2", ()); + route.GetCurrentStreetName(roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street2", (roadNameInfo.m_name)); } } // namespace route_tests diff --git a/routing/routing_tests/routing_helpers_tests.cpp b/routing/routing_tests/routing_helpers_tests.cpp index ac2b2ab404..41fce2786e 100644 --- a/routing/routing_tests/routing_helpers_tests.cpp +++ b/routing/routing_tests/routing_helpers_tests.cpp @@ -37,7 +37,7 @@ UNIT_TEST(FillSegmentInfoSmokeTest) TEST_EQUAL(segmentInfo.size(), 1, ()); TEST_EQUAL(segmentInfo[0].GetTurn().m_turn, CarDirection::ReachedYourDestination, ()); - TEST(segmentInfo[0].GetStreet().empty(), ()); + TEST(segmentInfo[0].GetRoadNameInfo().m_name.empty(), ()); } UNIT_TEST(FillSegmentInfoTest) @@ -50,7 +50,9 @@ UNIT_TEST(FillSegmentInfoTest) {m2::PointD(0.2 /* x */, 0.0 /* y */), geometry::kInvalidAltitude}}; Route::TTurns const & turnDirs = {{1 /* point index */, CarDirection::TurnRight}, {2 /* point index */, CarDirection::ReachedYourDestination}}; - Route::TStreets const streets = {{0 /* point index */, "zero"}, {1, "first"}, {2, "second"}}; + Route::TStreets const streets = {{0 /* point index */, {"zero", "", "", "", "", false}}, + {1 /* point index */, {"first", "", "", "", "", false}}, + {2 /* point index */, {"second", "", "", "", "", false}}}; Route::TTimes const times = { {0 /* point index */, 0.0 /* time in seconds */}, {1, 1.0}, {2, 2.0}}; @@ -59,11 +61,11 @@ UNIT_TEST(FillSegmentInfoTest) TEST_EQUAL(segmentInfo.size(), 2, ()); TEST_EQUAL(segmentInfo[0].GetTurn().m_turn, CarDirection::TurnRight, ()); - TEST_EQUAL(segmentInfo[0].GetStreet(), string("first"), ()); + TEST_EQUAL(segmentInfo[0].GetRoadNameInfo().m_name, string("first"), ()); TEST_EQUAL(segmentInfo[0].GetSegment(), segments[0], ()); TEST_EQUAL(segmentInfo[1].GetTurn().m_turn, CarDirection::ReachedYourDestination, ()); - TEST_EQUAL(segmentInfo[1].GetStreet(), string("second"), ()); + TEST_EQUAL(segmentInfo[1].GetRoadNameInfo().m_name, string("second"), ()); TEST_EQUAL(segmentInfo[1].GetSegment(), segments[1], ()); } diff --git a/routing/routing_tests/turns_generator_test.cpp b/routing/routing_tests/turns_generator_test.cpp index 71494a7136..0469740821 100644 --- a/routing/routing_tests/turns_generator_test.cpp +++ b/routing/routing_tests/turns_generator_test.cpp @@ -339,7 +339,7 @@ UNIT_TEST(TestIntermediateDirection) UNIT_TEST(TestCheckUTurnOnRoute) { TUnpackedPathSegments pathSegments(4, LoadedPathSegment()); - pathSegments[0].m_name = "A road"; + pathSegments[0].m_roadNameInfo = {"A road", "", "", "", "", false}; pathSegments[0].m_weight = 1; pathSegments[0].m_highwayClass = ftypes::HighwayClass::Trunk; pathSegments[0].m_onRoundabout = false; diff --git a/routing/turns_generator.cpp b/routing/turns_generator.cpp index 9cc1d21c7c..114df86d9b 100644 --- a/routing/turns_generator.cpp +++ b/routing/turns_generator.cpp @@ -292,7 +292,8 @@ void CorrectCandidatesSegmentByOutgoing(TurnInfo const & turnInfo, Segment const it->m_segment = firstOutgoingSeg; } else if (nodes.isCandidatesAngleValid) - ASSERT(false, ("Can't match any candidate with firstOutgoingSegment but isCandidatesAngleValid == true.")); + // Typically all candidates are from one mwm, and missed one (firstOutgoingSegment) from another. + LOG(LWARNING, ("Can't match any candidate with firstOutgoingSegment but isCandidatesAngleValid == true.")); else { LOG(LWARNING, ("Can't match any candidate with firstOutgoingSegment and isCandidatesAngleValid == false")); -- 2.45.3 From 9b0e84d9ebc7294411ea5d82894ec33263575c30 Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Sun, 5 Jun 2022 17:04:22 +0300 Subject: [PATCH 04/14] Small fixes for review Signed-off-by: Anton Makouski --- generator/osm2meta.cpp | 3 ++- routing/car_directions.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 337e31a513..8293f591fd 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -148,11 +148,12 @@ string MetadataTagProcessorImpl::ValidateAndFormat_ele(string const & v) const string MetadataTagProcessorImpl::ValidateAndFormat_destination(string const & v) const { + // Normalization. "a ;b; c " " -> "a; b; c". string r; strings::Tokenize(v, ";", [&](std::string_view d) { if (r.empty()) - r = d; + r = string(strings::Trim(d)); else r += "; " + string(strings::Trim(d)); }); diff --git a/routing/car_directions.cpp b/routing/car_directions.cpp index ede4d02122..171bb138d2 100644 --- a/routing/car_directions.cpp +++ b/routing/car_directions.cpp @@ -101,9 +101,10 @@ size_t CarDirectionsEngine::GetTurnDirection(IRoutingResult const & result, size NumMwmIds const & numMwmIds, RoutingSettings const & vehicleSettings, TurnItem & turnItem) { - // This is for jump from initial point to start of the route. + // This is for jump from initial point to start of the route. No direction is given. /// @todo Sometimes results of GetPossibleTurns are empty, sometimes are invalid. - ///E.g. Google Maps until you reach destination will guide you go to the left or to the right of first road. + /// The best will be to fix GetPossibleTurns(). It will allow us to use following approach. + /// E.g. Google Maps until you reach the destination will guide you to go to the left or to the right of the first road. if (turnItem.m_index == 2) return 0; -- 2.45.3 From d5d9b1fdaf34261412e696f50762ec621665d00f Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Sun, 5 Jun 2022 23:26:43 +0300 Subject: [PATCH 05/14] Small fixes for review Signed-off-by: Anton Makouski --- generator/osm2meta.cpp | 11 +---------- routing/routing_session.cpp | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 8293f591fd..65dfaf048d 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -148,16 +148,7 @@ string MetadataTagProcessorImpl::ValidateAndFormat_ele(string const & v) const string MetadataTagProcessorImpl::ValidateAndFormat_destination(string const & v) const { - // Normalization. "a ;b; c " " -> "a; b; c". - string r; - strings::Tokenize(v, ";", [&](std::string_view d) - { - if (r.empty()) - r = string(strings::Trim(d)); - else - r += "; " + string(strings::Trim(d)); - }); - return r; + return v; } string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const & v) const diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index a0bdacc079..91269ebb3d 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -341,6 +341,20 @@ SessionState RoutingSession::OnLocationPositionChanged(GpsInfo const & info) return m_state; } +string FormatRoadDestination(string const & v) +{ + // Normalization. "a ;b; c,d " " -> "a; b; c; d". + string r; + strings::Tokenize(v, " ;,", [&](std::string_view d) + { + if (r.empty()) + r = d; + else + r += "; " + string(d); + }); + return r; +} + // For next street returns "[ref] name" . // For highway exits (or main roads with exit info) returns "[junction:ref]: [target:ref] > target". // If no |target| - it will be replaced by |name| of next street. @@ -363,7 +377,7 @@ void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) name += string(name.empty() ? "" : ": ") + "[" + road.m_destination_ref + "]"; if (!road.m_destination.empty()) - name += string(name.empty() ? "" : " ") + "> " + road.m_destination; + name += string(name.empty() ? "" : " ") + "> " + FormatRoadDestination(road.m_destination); else if (!road.m_name.empty()) name += (road.m_destination_ref.empty() ? string(name.empty() ? "" : " ") : ": ") + road.m_name; } -- 2.45.3 From 5b11fed3b9a1a007e7942d16e1fe8d9b04cf35c3 Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Tue, 7 Jun 2022 10:31:27 +0300 Subject: [PATCH 06/14] Small fixes for review Signed-off-by: Anton Makouski --- generator/osm2meta.cpp | 13 ++++++++++++- routing/routing_session.cpp | 16 +--------------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 65dfaf048d..282f9ee623 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -148,7 +148,18 @@ string MetadataTagProcessorImpl::ValidateAndFormat_ele(string const & v) const string MetadataTagProcessorImpl::ValidateAndFormat_destination(string const & v) const { - return v; + { + // Normalization. "a1 a2;b1-b2; c,d " " -> "a1 a2; b1-b2; c; d". + string r; + strings::Tokenize(v, ";,", [&](std::string_view d) + { + if (r.empty()) + r = strings::Trim(d); + else + r += "; " + string(strings::Trim(d)); + }); + return r; + } } string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const & v) const diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index 91269ebb3d..a0bdacc079 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -341,20 +341,6 @@ SessionState RoutingSession::OnLocationPositionChanged(GpsInfo const & info) return m_state; } -string FormatRoadDestination(string const & v) -{ - // Normalization. "a ;b; c,d " " -> "a; b; c; d". - string r; - strings::Tokenize(v, " ;,", [&](std::string_view d) - { - if (r.empty()) - r = d; - else - r += "; " + string(d); - }); - return r; -} - // For next street returns "[ref] name" . // For highway exits (or main roads with exit info) returns "[junction:ref]: [target:ref] > target". // If no |target| - it will be replaced by |name| of next street. @@ -377,7 +363,7 @@ void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) name += string(name.empty() ? "" : ": ") + "[" + road.m_destination_ref + "]"; if (!road.m_destination.empty()) - name += string(name.empty() ? "" : " ") + "> " + FormatRoadDestination(road.m_destination); + name += string(name.empty() ? "" : " ") + "> " + road.m_destination; else if (!road.m_name.empty()) name += (road.m_destination_ref.empty() ? string(name.empty() ? "" : " ") : ": ") + road.m_name; } -- 2.45.3 From 11fc5452029c7acea02f9225b039414b201eef37 Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Tue, 7 Jun 2022 12:59:02 +0300 Subject: [PATCH 07/14] Small fixes for review + test Signed-off-by: Anton Makouski --- generator/generator_tests/osm2meta_test.cpp | 12 +++++++++++ generator/osm2meta.cpp | 22 ++++++++++----------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/generator/generator_tests/osm2meta_test.cpp b/generator/generator_tests/osm2meta_test.cpp index 3e20b4f43e..89ce66c09f 100644 --- a/generator/generator_tests/osm2meta_test.cpp +++ b/generator/generator_tests/osm2meta_test.cpp @@ -42,3 +42,15 @@ UNIT_TEST(ValidateAndFormat_building_levels) TEST_EQUAL(tp.ValidateAndFormat_building_levels("2.51"), "2.5", ()); TEST_EQUAL(tp.ValidateAndFormat_building_levels("250"), "", ("Too many levels.")); } + +UNIT_TEST(ValidateAndFormat_destination) +{ + FeatureBuilderParams params; + MetadataTagProcessorImpl tp(params); + TEST_EQUAL(tp.ValidateAndFormat_destination("a1 a2"), "a1 a2", ()); + TEST_EQUAL(tp.ValidateAndFormat_destination("b1-b2"), "b1-b2", ()); + TEST_EQUAL(tp.ValidateAndFormat_destination(" c,d ;"), "c; d", ()); + TEST_EQUAL(tp.ValidateAndFormat_destination("e,;f; g;"), "e; f; g", ()); + TEST_EQUAL(tp.ValidateAndFormat_destination(""), "", ()); + TEST_EQUAL(tp.ValidateAndFormat_destination("a1 a2;b1-b2; c,d ;e,;f; ;g"), "a1 a2; b1-b2; c; d; e; f; g", ()); +} \ No newline at end of file diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 282f9ee623..0ad60e5e84 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -148,18 +148,18 @@ string MetadataTagProcessorImpl::ValidateAndFormat_ele(string const & v) const string MetadataTagProcessorImpl::ValidateAndFormat_destination(string const & v) const { + // Normalization. "a1 a2;b1-b2; c,d ;e,;f; ;g" -> "a1 a2; b1-b2; c; d; e; f; g" + string r; + strings::Tokenize(v, ";,", [&](std::string_view d) { - // Normalization. "a1 a2;b1-b2; c,d " " -> "a1 a2; b1-b2; c; d". - string r; - strings::Tokenize(v, ";,", [&](std::string_view d) - { - if (r.empty()) - r = strings::Trim(d); - else - r += "; " + string(strings::Trim(d)); - }); - return r; - } + strings::Trim(d); + if (d.empty()) + return; + if (!r.empty()) + r += "; "; + r.append(d); + }); + return r; } string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const & v) const -- 2.45.3 From 08fdbde470df441651f82f861e253fb6d751797c Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Wed, 1 Jun 2022 20:13:57 +0300 Subject: [PATCH 08/14] [routing] Extended navigation info about roads 2nd iteration for #849 Extended info about next street/road: - for next street it will show "[ref] name" . - for highway links - "[junction:ref]: [target:ref] > target". If no target - it will be replaced by name of next street. If no [target:ref] - it will be replaced by [ref] of next road. Signed-off-by: Anton Makouski --- .../maps/bookmarks/data/Metadata.java | 3 +- generator/osm2meta.cpp | 16 ++++- generator/osm2meta.hpp | 1 + indexer/feature_meta.cpp | 7 ++- indexer/feature_meta.hpp | 1 + indexer/map_object.hpp | 1 + routing/car_directions.cpp | 8 +-- routing/directions_engine.cpp | 20 +++---- routing/loaded_path_segment.hpp | 2 +- routing/pedestrian_directions.cpp | 4 +- routing/route.cpp | 58 ++++++++++++++++--- routing/route.hpp | 38 ++++++++---- routing/routing_helpers.cpp | 3 +- routing/routing_session.cpp | 40 ++++++++++++- 14 files changed, 156 insertions(+), 46 deletions(-) diff --git a/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java b/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java index d69937a102..1350c6b085 100644 --- a/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java +++ b/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java @@ -55,7 +55,8 @@ public class Metadata implements Parcelable FMD_CONTACT_VK(35), FMD_CONTACT_LINE(36), FMD_DESTINATION(37), - FMD_DESTINATION_REF(38); + FMD_DESTINATION_REF(38), + FMD_JUNCTION_REF(39); private final int mMetaType; MetadataType(int metadataType) diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index c2f9e93d88..337e31a513 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -148,7 +148,15 @@ string MetadataTagProcessorImpl::ValidateAndFormat_ele(string const & v) const string MetadataTagProcessorImpl::ValidateAndFormat_destination(string const & v) const { - return v; + string r; + strings::Tokenize(v, ";", [&](std::string_view d) + { + if (r.empty()) + r = d; + else + r += "; " + string(strings::Trim(d)); + }); + return r; } string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const & v) const @@ -156,6 +164,11 @@ string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const return v; } +string MetadataTagProcessorImpl::ValidateAndFormat_junction_ref(string const & v) const +{ + return v; +} + string MetadataTagProcessorImpl::ValidateAndFormat_turn_lanes(string const & v) const { return v; @@ -458,6 +471,7 @@ void MetadataTagProcessor::operator()(std::string const & k, std::string const & case Metadata::FMD_ELE: valid = ValidateAndFormat_ele(v); break; case Metadata::FMD_DESTINATION: valid = ValidateAndFormat_destination(v); break; case Metadata::FMD_DESTINATION_REF: valid = ValidateAndFormat_destination_ref(v); break; + case Metadata::FMD_JUNCTION_REF: valid = ValidateAndFormat_junction_ref(v); break; case Metadata::FMD_TURN_LANES: valid = ValidateAndFormat_turn_lanes(v); break; case Metadata::FMD_TURN_LANES_FORWARD: valid = ValidateAndFormat_turn_lanes_forward(v); break; case Metadata::FMD_TURN_LANES_BACKWARD: valid = ValidateAndFormat_turn_lanes_backward(v); break; diff --git a/generator/osm2meta.hpp b/generator/osm2meta.hpp index 9a5a628f8f..ee82bcd6db 100644 --- a/generator/osm2meta.hpp +++ b/generator/osm2meta.hpp @@ -18,6 +18,7 @@ struct MetadataTagProcessorImpl std::string ValidateAndFormat_ele(std::string const & v) const; std::string ValidateAndFormat_destination(std::string const & v) const; std::string ValidateAndFormat_destination_ref(std::string const & v) const; + std::string ValidateAndFormat_junction_ref(std::string const & v) const; std::string ValidateAndFormat_turn_lanes(std::string const & v) const; std::string ValidateAndFormat_turn_lanes_forward(std::string const & v) const; std::string ValidateAndFormat_turn_lanes_backward(std::string const & v) const; diff --git a/indexer/feature_meta.cpp b/indexer/feature_meta.cpp index df89d0b47e..6f9416ec05 100644 --- a/indexer/feature_meta.cpp +++ b/indexer/feature_meta.cpp @@ -76,6 +76,8 @@ bool Metadata::TypeFromString(string const & k, Metadata::EType & outType) outType = Metadata::FMD_DESTINATION; else if (k == "destination:ref") outType = Metadata::FMD_DESTINATION_REF; + else if (k == "junction:ref") + outType = Metadata::FMD_JUNCTION_REF; else if (k == "turn:lanes") outType = Metadata::FMD_TURN_LANES; else if (k == "turn:lanes:forward") @@ -173,8 +175,9 @@ string ToString(Metadata::EType type) case Metadata::FMD_CONTACT_LINE: return "contact:line"; case Metadata::FMD_INTERNET: return "internet_access"; case Metadata::FMD_ELE: return "ele"; - case Metadata::FMD_DESTINATION: return "desination"; - case Metadata::FMD_DESTINATION_REF: return "desination:ref"; + case Metadata::FMD_DESTINATION: return "destination"; + case Metadata::FMD_DESTINATION_REF: return "destination:ref"; + case Metadata::FMD_JUNCTION_REF: return "junction:ref"; case Metadata::FMD_TURN_LANES: return "turn:lanes"; case Metadata::FMD_TURN_LANES_FORWARD: return "turn:lanes:forward"; case Metadata::FMD_TURN_LANES_BACKWARD: return "turn:lanes:backward"; diff --git a/indexer/feature_meta.hpp b/indexer/feature_meta.hpp index a93dd1b86b..2ab35708f5 100644 --- a/indexer/feature_meta.hpp +++ b/indexer/feature_meta.hpp @@ -155,6 +155,7 @@ public: FMD_CONTACT_LINE = 36, FMD_DESTINATION = 37, FMD_DESTINATION_REF = 38, + FMD_JUNCTION_REF = 39, FMD_COUNT }; diff --git a/indexer/map_object.hpp b/indexer/map_object.hpp index 2c58e362d0..a659e63124 100644 --- a/indexer/map_object.hpp +++ b/indexer/map_object.hpp @@ -181,6 +181,7 @@ std::vector MetadataToProps(std::vector const & metadata) case Metadata::FMD_DESTINATION: case Metadata::FMD_DESTINATION_REF: + case Metadata::FMD_JUNCTION_REF: case Metadata::FMD_TURN_LANES: case Metadata::FMD_TURN_LANES_FORWARD: case Metadata::FMD_TURN_LANES_BACKWARD: diff --git a/routing/car_directions.cpp b/routing/car_directions.cpp index ec74406771..864c4f0535 100644 --- a/routing/car_directions.cpp +++ b/routing/car_directions.cpp @@ -418,8 +418,8 @@ void GetTurnDirectionBasic(IRoutingResult const & result, size_t const outgoingS if (!GetTurnInfo(result, outgoingSegmentIndex, vehicleSettings, turnInfo)) return; - turn.m_sourceName = turnInfo.m_ingoing->m_name; - turn.m_targetName = turnInfo.m_outgoing->m_name; + turn.m_sourceName = turnInfo.m_ingoing->m_roadNameInfo.m_name; + turn.m_targetName = turnInfo.m_outgoing->m_roadNameInfo.m_name; turn.m_turn = CarDirection::None; ASSERT_GREATER(turnInfo.m_ingoing->m_path.size(), 1, ()); @@ -531,7 +531,7 @@ size_t CheckUTurnOnRoute(IRoutingResult const & result, size_t const outgoingSeg if (checkedSegment.m_path.size() < 2) return 0; - if (checkedSegment.m_name == masterSegment.m_name && + if (checkedSegment.m_roadNameInfo.m_name == masterSegment.m_roadNameInfo.m_name && checkedSegment.m_highwayClass == masterSegment.m_highwayClass && checkedSegment.m_isLink == masterSegment.m_isLink && !checkedSegment.m_onRoundabout) { @@ -555,7 +555,7 @@ size_t CheckUTurnOnRoute(IRoutingResult const & result, size_t const outgoingSeg } // Avoid the UTurn on unnamed roads inside the rectangle based distinct. - if (checkedSegment.m_name.empty()) + if (checkedSegment.m_roadNameInfo.m_name.empty()) return 0; // Avoid returning to the same edge after uturn somewere else. diff --git a/routing/directions_engine.cpp b/routing/directions_engine.cpp index 7671ad10b9..d757714d48 100644 --- a/routing/directions_engine.cpp +++ b/routing/directions_engine.cpp @@ -66,18 +66,12 @@ void DirectionsEngine::LoadPathAttributes(FeatureID const & featureId, pathSegment.m_onRoundabout = ftypes::IsRoundAboutChecker::Instance()(*ft); pathSegment.m_isOneWay = ftypes::IsOneWayChecker::Instance()(*ft); - if (pathSegment.m_isLink) - { - if (auto const & dst_number = ft->GetMetadata(feature::Metadata::FMD_DESTINATION_REF); !dst_number.empty()) - pathSegment.m_name = "[" + string(dst_number) + "] "; - pathSegment.m_name += ft->GetMetadata(feature::Metadata::FMD_DESTINATION); - } - else - { - if (auto const & road_number = ft->GetRoadNumber(); !road_number.empty()) - pathSegment.m_name = "[" + road_number + "] "; - pathSegment.m_name += ft->GetName(StringUtf8Multilang::kDefaultCode); - } + pathSegment.m_roadNameInfo.m_isLink = pathSegment.m_isLink; + pathSegment.m_roadNameInfo.m_junction_ref = ft->GetMetadata(feature::Metadata::FMD_JUNCTION_REF); + pathSegment.m_roadNameInfo.m_destination_ref = ft->GetMetadata(feature::Metadata::FMD_DESTINATION_REF); + pathSegment.m_roadNameInfo.m_destination = ft->GetMetadata(feature::Metadata::FMD_DESTINATION); + pathSegment.m_roadNameInfo.m_ref = ft->GetRoadNumber(); + pathSegment.m_roadNameInfo.m_name = ft->GetName(StringUtf8Multilang::kDefaultCode); } void DirectionsEngine::GetSegmentRangeAndAdjacentEdges(IRoadGraph::EdgeListT const & outgoingEdges, @@ -355,7 +349,7 @@ RouterResultCode DirectionsEngine::MakeTurnAnnotation(IndexRoadGraph::EdgeVector // Street names contain empty names too for avoiding of freezing of old street name while // moving along unnamed street. - streets.emplace_back(max(junctions.size(), static_cast(1)) - 1, loadedSegmentIt->m_name); + streets.emplace_back(max(junctions.size(), static_cast(1)) - 1, loadedSegmentIt->m_roadNameInfo); // Turns information. if (!junctions.empty() && skipTurnSegments == 0) diff --git a/routing/loaded_path_segment.hpp b/routing/loaded_path_segment.hpp index 3a3b178866..59a618e45c 100644 --- a/routing/loaded_path_segment.hpp +++ b/routing/loaded_path_segment.hpp @@ -22,7 +22,7 @@ struct LoadedPathSegment { std::vector m_path; std::vector m_lanes; - std::string m_name; + RouteSegment::RoadNameInfo m_roadNameInfo; double m_weight = 0.0; /*!< Time in seconds to pass the segment. */ SegmentRange m_segmentRange; std::vector m_segments; /*!< Traffic segments for |m_path|. */ diff --git a/routing/pedestrian_directions.cpp b/routing/pedestrian_directions.cpp index c6e73b978b..bddffe9e82 100644 --- a/routing/pedestrian_directions.cpp +++ b/routing/pedestrian_directions.cpp @@ -30,8 +30,8 @@ size_t PedestrianDirectionsEngine::GetTurnDirection(IRoutingResult const & resul double const turnAngle = CalcTurnAngle(result, outgoingSegmentIndex, numMwmIds, vehicleSettings); - turn.m_sourceName = turnInfo.m_ingoing->m_name; - turn.m_targetName = turnInfo.m_outgoing->m_name; + turn.m_sourceName = turnInfo.m_ingoing->m_roadNameInfo.m_name; + turn.m_targetName = turnInfo.m_outgoing->m_roadNameInfo.m_name; turn.m_pedestrianTurn = PedestrianDirection::None; ASSERT_GREATER(turnInfo.m_ingoing->m_path.size(), 1, ()); diff --git a/routing/route.cpp b/routing/route.cpp index 36ae0b0e4c..a8ce24cb17 100644 --- a/routing/route.cpp +++ b/routing/route.cpp @@ -117,18 +117,41 @@ double Route::GetCurrentTimeToEndSec() const m_poly.GetDistFromCurPointToRoutePointMeters() / curSegSpeedMPerS); } -void Route::GetCurrentStreetName(string & name) const +void Route::GetCurrentStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const { - GetStreetNameAfterIdx(static_cast(m_poly.GetCurrentIter().m_ind), name); + GetStreetNameAfterIdx(static_cast(m_poly.GetCurrentIter().m_ind), roadNameInfo); } -void Route::GetStreetNameAfterIdx(uint32_t idx, string & name) const +void Route::GetNextTurnStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const +{ + double distance; + TurnItem turn; + GetCurrentTurn(distance, turn); + GetStreetNameAfterIdx(turn.m_index, roadNameInfo); +} + +// If exit is false, returns ref and name. +// If exit is true, returns m_junction_ref, m_destination_ref, m_destination, m_name. +// Handling of incomplete data or non-standard data: +// - We go trough 400m to find first segment with existing data. +// Bit for link we go through all segments till we reach non-link segment, +// Sometimes links are really long (e.g. 1km+ in USA) and they have no tags. +// - Normally for link both destination and destination:ref tags exist together. +// But sometimes only destination tag exists for link. And destination:ref can be calculated +// by checking next segments of route until link will end and normal r will start. +// Hopefully it will have ref tag. So we can show it instead of destination:ref. +// Also we can add info about it's name. +// - Sometimes exit is not tagged as link (e.g. if new r starts here). +// At the same time they can have all useful tags just like link. +// Usually destination:ref=ref in such cases, or only 1st part of destination:ref can match. +void Route::GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const { - name.clear(); auto const iterIdx = m_poly.GetIterToIndex(idx); if (!IsValid() || !iterIdx.IsValid()) return; + RouteSegment::RoadNameInfo roadNameInfoNext; + size_t i = idx; for (; i < m_poly.GetPolyline().GetSize(); ++i) { @@ -137,16 +160,33 @@ void Route::GetStreetNameAfterIdx(uint32_t idx, string & name) const if (i == 0) continue; - string const street = m_routeSegments[ConvertPointIdxToSegmentIdx(i)].GetStreet(); - if (!street.empty()) + auto const & r = m_routeSegments[ConvertPointIdxToSegmentIdx(i)].GetRoadNameInfo(); + + if (r.HasBasicTextInfo()) { - name = street; - return; + if (roadNameInfo.HasExitInfo()) + roadNameInfoNext = r; + else + roadNameInfo = r; + break; } + else if (r.HasExitInfo() && !roadNameInfo.HasExitInfo()) + roadNameInfo = r; + // For exit wait for non-exit + else if (roadNameInfo.HasExitInfo() && !r.m_isLink) + continue; + auto const furtherIter = m_poly.GetIterToIndex(i); CHECK(furtherIter.IsValid(), ()); if (m_poly.GetDistanceM(iterIdx, furtherIter) > kSteetNameLinkMeters) - return; + break; + } + + if (roadNameInfo.HasExitInfo()) + { + if (roadNameInfo.m_destination_ref.empty()) + roadNameInfo.m_destination_ref = roadNameInfoNext.m_ref; + roadNameInfo.m_name = roadNameInfoNext.m_name; } } diff --git a/routing/route.hpp b/routing/route.hpp index d3288460d1..dd75f8ecf4 100644 --- a/routing/route.hpp +++ b/routing/route.hpp @@ -64,15 +64,30 @@ public: uint8_t m_maxSpeedKmPH = 0; }; + struct RoadNameInfo + { + bool m_isLink; + // This is for street/road. |m_ref| |m_name|. + std::string m_ref; // Number of street/road .g. "CA 85". + std::string m_name; // E.g "Johnson Ave.". + // This is for 1st segment of link after junction. Exit |junction_ref| to |m_destination_ref| for |m_destination|. + std::string m_junction_ref; // Number of junction e.g. "398B". + std::string m_destination_ref; // Number of next road, e.g. "CA 85", Sometimes "CA 85 South". + std::string m_destination; // E.g. "Cupertino". + bool HasBasicTextInfo() const { return !m_ref.empty() || !m_name.empty(); } + bool HasExitInfo() const { return m_isLink || !m_junction_ref.empty() || !m_destination_ref.empty() || !m_destination.empty(); } + RoadNameInfo() { m_isLink = false; } + }; + RouteSegment(Segment const & segment, turns::TurnItem const & turn, - geometry::PointWithAltitude const & junction, std::string const & street, + geometry::PointWithAltitude const & junction, RoadNameInfo const & roadNameInfo, double distFromBeginningMeters, double distFromBeginningMerc, double timeFromBeginningS, traffic::SpeedGroup traffic, std::unique_ptr transitInfo) : m_segment(segment) , m_turn(turn) , m_junction(junction) - , m_street(street) + , m_roadNameInfo(roadNameInfo) , m_distFromBeginningMeters(distFromBeginningMeters) , m_distFromBeginningMerc(distFromBeginningMerc) , m_timeFromBeginningS(timeFromBeginningS) @@ -89,7 +104,7 @@ public: Segment const & GetSegment() const { return m_segment; } Segment & GetSegment() { return m_segment; } geometry::PointWithAltitude const & GetJunction() const { return m_junction; } - std::string const & GetStreet() const { return m_street; } + RoadNameInfo const & GetRoadNameInfo() const { return m_roadNameInfo; } traffic::SpeedGroup GetTraffic() const { return m_traffic; } turns::TurnItem const & GetTurn() const { return m_turn; } @@ -116,8 +131,8 @@ private: /// The furthest point of the segment from the beginning of the route along the route. geometry::PointWithAltitude m_junction; - /// Street name of |m_segment| if any. Otherwise |m_street| is empty. - std::string m_street; + /// RoadNameInfo of |m_segment| if any. Otherwise |m_roadInfo| is empty. + RoadNameInfo m_roadNameInfo; /// Distance from the route (not the subroute) beginning to the farthest end of |m_segment| in meters. double m_distFromBeginningMeters = 0.0; @@ -147,7 +162,7 @@ public: using TTurns = std::vector; using TTimeItem = std::pair; using TTimes = std::vector; - using TStreetItem = std::pair; + using TStreetItem = std::pair; using TStreets = std::vector; class SubrouteAttrs final @@ -299,11 +314,11 @@ public: /// set with MoveIterator() method. If it's not possible returns nullopt. std::optional GetCurrentIteratorTurn() const; - /// \brief Returns a name of a street where the user rides at this moment. - void GetCurrentStreetName(std::string & name) const; + /// \brief Returns name info of a street where the user rides at this moment. + void GetCurrentStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const; - /// \brief Returns a name of a street next to idx point of the path. Function avoids short unnamed links. - void GetStreetNameAfterIdx(uint32_t idx, std::string & name) const; + /// \brief Return name info of a street according to next turn. + void GetNextTurnStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const; /// \brief Gets turn information after the turn next to the nearest one. /// \param distanceToTurnMeters is a distance from current position to the second turn. @@ -390,6 +405,9 @@ private: void GetClosestTurn(size_t segIdx, turns::TurnItem & turn) const; size_t ConvertPointIdxToSegmentIdx(size_t pointIdx) const; + /// \brief Returns a name info of a street next to idx point of the path. + void GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const; + /// \returns Estimated time to pass the route segment with |segIdx|. double GetTimeToPassSegSec(size_t segIdx) const; diff --git a/routing/routing_helpers.cpp b/routing/routing_helpers.cpp index d1d78d34a8..47c4a16e86 100644 --- a/routing/routing_helpers.cpp +++ b/routing/routing_helpers.cpp @@ -4,6 +4,7 @@ #include "routing/fake_feature_ids.hpp" #include "routing/index_graph_starter.hpp" #include "routing/road_point.hpp" +#include "routing/route.hpp" #include "routing/segment.hpp" #include "routing/traffic_stash.hpp" #include "routing/world_graph.hpp" @@ -68,7 +69,7 @@ void FillSegmentInfo(vector const & segments, ++turnIdx; } - string curStreet; + RouteSegment::RoadNameInfo curStreet; if (!streets.empty()) { CHECK_LESS_OR_EQUAL(streetIdx, streets.size(), ()); diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index 94a2f2dbea..557a2cd685 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -10,6 +10,8 @@ #include "geometry/angles.hpp" #include "geometry/mercator.hpp" +#include "indexer/road_shields_parser.hpp" + #include using namespace location; @@ -339,6 +341,36 @@ SessionState RoutingSession::OnLocationPositionChanged(GpsInfo const & info) return m_state; } +void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) +{ + if (auto const & sh = ftypes::GetRoadShields(road.m_ref); !sh.empty()) + road.m_ref = sh[0].m_name; + if (auto const & sh = ftypes::GetRoadShields(road.m_destination_ref); !sh.empty()) + road.m_destination_ref = sh[0].m_name; + + name.clear(); + if (road.HasExitInfo()) + { + if (!road.m_junction_ref.empty()) + name = "[" + road.m_junction_ref + "]"; + + if (!road.m_destination_ref.empty()) + name += string(name.empty() ? "" : ": ") + "[" + road.m_destination_ref + "]"; + + if (!road.m_destination.empty()) + name += string(name.empty() ? "" : " ") + "> " + road.m_destination; + else if (!road.m_name.empty()) + name += (road.m_destination_ref.empty() ? " : " : " ") + road.m_name; + } + else + { + if (!road.m_ref.empty()) + name = "[" + road.m_ref + "]"; + if (!road.m_name.empty()) + name += (name.empty() ? "" : " ") + road.m_name; + } +} + void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const { CHECK_THREAD_CHECKER(m_threadChecker, ()); @@ -376,8 +408,12 @@ void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const info.m_exitNum = turn.m_exitNum; info.m_time = static_cast(max(kMinimumETASec, m_route->GetCurrentTimeToEndSec())); - m_route->GetCurrentStreetName(info.m_sourceName); - m_route->GetStreetNameAfterIdx(turn.m_index, info.m_targetName); + RouteSegment::RoadNameInfo sourceRoadNameInfo, targetRoadNameInfo; + m_route->GetCurrentStreetName(sourceRoadNameInfo); + GetFullRoadName(sourceRoadNameInfo, info.m_sourceName); + m_route->GetNextTurnStreetName(targetRoadNameInfo); + GetFullRoadName(targetRoadNameInfo, info.m_targetName); + info.m_completionPercent = GetCompletionPercent(); // Lane information and next street name. -- 2.45.3 From 86f2957179e27174375febdea0e77018685cc94b Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Thu, 2 Jun 2022 12:42:02 +0300 Subject: [PATCH 09/14] Comments + fix of compile error Signed-off-by: Anton Makouski --- routing/loaded_path_segment.hpp | 1 + routing/route.cpp | 25 +++++++++++++------------ routing/routing_session.cpp | 5 +++++ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/routing/loaded_path_segment.hpp b/routing/loaded_path_segment.hpp index 59a618e45c..3bb3e74e28 100644 --- a/routing/loaded_path_segment.hpp +++ b/routing/loaded_path_segment.hpp @@ -3,6 +3,7 @@ #include "routing/road_point.hpp" #include "routing/turns.hpp" #include "routing/segment.hpp" +#include "routing/route.hpp" #include "indexer/ftypes_matcher.hpp" diff --git a/routing/route.cpp b/routing/route.cpp index a8ce24cb17..9fdb118de8 100644 --- a/routing/route.cpp +++ b/routing/route.cpp @@ -134,26 +134,26 @@ void Route::GetNextTurnStreetName(RouteSegment::RoadNameInfo & roadNameInfo) con // If exit is true, returns m_junction_ref, m_destination_ref, m_destination, m_name. // Handling of incomplete data or non-standard data: // - We go trough 400m to find first segment with existing data. -// Bit for link we go through all segments till we reach non-link segment, -// Sometimes links are really long (e.g. 1km+ in USA) and they have no tags. +// But for link we go through all segments till we reach non-link segment, +// This is for really long links (e.g. 1km+ in USA) which have no tags. // - Normally for link both destination and destination:ref tags exist together. -// But sometimes only destination tag exists for link. And destination:ref can be calculated -// by checking next segments of route until link will end and normal r will start. -// Hopefully it will have ref tag. So we can show it instead of destination:ref. -// Also we can add info about it's name. -// - Sometimes exit is not tagged as link (e.g. if new r starts here). +// But sometimes only |destination| tag exists for link. And |destination:ref| can be calculated +// by checking next segments of route until link will end and normal road will start. +// Hopefully it will have |ref| tag. So we can use it instead of |destination:ref|. +// Also we can use info about it's |name|. It can be useful if no |destination| tag. +// - Sometimes exit is not tagged as link (e.g. if new road starts here). // At the same time they can have all useful tags just like link. -// Usually destination:ref=ref in such cases, or only 1st part of destination:ref can match. +// Usually |destination:ref| = |ref| in such cases, or only 1st part of |destination:ref| can match. void Route::GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const { auto const iterIdx = m_poly.GetIterToIndex(idx); if (!IsValid() || !iterIdx.IsValid()) return; + // Info about 1st segment with existing basic (non-link) info after link. RouteSegment::RoadNameInfo roadNameInfoNext; - size_t i = idx; - for (; i < m_poly.GetPolyline().GetSize(); ++i) + for (size_t i = idx; i < m_poly.GetPolyline().GetSize(); ++i) { // Note. curIter.m_ind == 0 means route iter at zero point. No corresponding route segments at // |m_routeSegments| in this case. |name| should be cleared. @@ -172,10 +172,10 @@ void Route::GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roa } else if (r.HasExitInfo() && !roadNameInfo.HasExitInfo()) roadNameInfo = r; - // For exit wait for non-exit + // For exit wait for non-exit. else if (roadNameInfo.HasExitInfo() && !r.m_isLink) continue; - + // For non-exits check only during first |kSteetNameLinkMeters|. auto const furtherIter = m_poly.GetIterToIndex(i); CHECK(furtherIter.IsValid(), ()); if (m_poly.GetDistanceM(iterIdx, furtherIter) > kSteetNameLinkMeters) @@ -184,6 +184,7 @@ void Route::GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roa if (roadNameInfo.HasExitInfo()) { + // Use basic info from |roadNameInfoNext| to update |roadNameInfo|. if (roadNameInfo.m_destination_ref.empty()) roadNameInfo.m_destination_ref = roadNameInfoNext.m_ref; roadNameInfo.m_name = roadNameInfoNext.m_name; diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index 557a2cd685..24ec379a90 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -341,6 +341,11 @@ SessionState RoutingSession::OnLocationPositionChanged(GpsInfo const & info) return m_state; } +// For next street returns "[ref] name" . +// For highway exits (or main roads with exit info) returns "[junction:ref]: [target:ref] > target". +// If no |target| - it will be replaced by |name| of next street. +// If no |target:ref| - it will be replaced by |ref| of next road. +// So if link has no info at all, "[ref] name" of next road will be returned (as for next street). void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) { if (auto const & sh = ftypes::GetRoadShields(road.m_ref); !sh.empty()) -- 2.45.3 From e685c715d81eddde36a7082bbd1395e046ed63c4 Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Fri, 3 Jun 2022 13:24:02 +0300 Subject: [PATCH 10/14] Test fixes, small bugfixes and review fixes Signed-off-by: Anton Makouski --- routing/car_directions.cpp | 6 +++ routing/route.hpp | 13 +++--- .../routing_integration_tests/route_test.cpp | 2 +- .../routing_test_tools.cpp | 15 +++---- .../street_names_test.cpp | 3 +- routing/routing_session.cpp | 36 +++++++-------- routing/routing_tests/route_tests.cpp | 44 +++++++++++-------- .../routing_tests/routing_helpers_tests.cpp | 10 +++-- .../routing_tests/turns_generator_test.cpp | 2 +- routing/turns_generator.cpp | 3 +- 10 files changed, 73 insertions(+), 61 deletions(-) diff --git a/routing/car_directions.cpp b/routing/car_directions.cpp index 864c4f0535..ede4d02122 100644 --- a/routing/car_directions.cpp +++ b/routing/car_directions.cpp @@ -101,6 +101,12 @@ size_t CarDirectionsEngine::GetTurnDirection(IRoutingResult const & result, size NumMwmIds const & numMwmIds, RoutingSettings const & vehicleSettings, TurnItem & turnItem) { + // This is for jump from initial point to start of the route. + /// @todo Sometimes results of GetPossibleTurns are empty, sometimes are invalid. + ///E.g. Google Maps until you reach destination will guide you go to the left or to the right of first road. + if (turnItem.m_index == 2) + return 0; + size_t skipTurnSegments = CheckUTurnOnRoute(result, outgoingSegmentIndex, numMwmIds, vehicleSettings, turnItem); if (turnItem.m_turn == CarDirection::None) diff --git a/routing/route.hpp b/routing/route.hpp index dd75f8ecf4..d1f75266e3 100644 --- a/routing/route.hpp +++ b/routing/route.hpp @@ -66,17 +66,16 @@ public: struct RoadNameInfo { - bool m_isLink; // This is for street/road. |m_ref| |m_name|. - std::string m_ref; // Number of street/road .g. "CA 85". std::string m_name; // E.g "Johnson Ave.". + std::string m_ref; // Number of street/road e.g. "CA 85". // This is for 1st segment of link after junction. Exit |junction_ref| to |m_destination_ref| for |m_destination|. std::string m_junction_ref; // Number of junction e.g. "398B". - std::string m_destination_ref; // Number of next road, e.g. "CA 85", Sometimes "CA 85 South". + std::string m_destination_ref; // Number of next road, e.g. "CA 85", Sometimes "CA 85 South". Usually match |m_ref| of next main road. std::string m_destination; // E.g. "Cupertino". + bool m_isLink = false; bool HasBasicTextInfo() const { return !m_ref.empty() || !m_name.empty(); } bool HasExitInfo() const { return m_isLink || !m_junction_ref.empty() || !m_destination_ref.empty() || !m_destination.empty(); } - RoadNameInfo() { m_isLink = false; } }; RouteSegment(Segment const & segment, turns::TurnItem const & turn, @@ -314,6 +313,9 @@ public: /// set with MoveIterator() method. If it's not possible returns nullopt. std::optional GetCurrentIteratorTurn() const; + /// \brief Returns a name info of a street next to idx point of the path. + void GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const; + /// \brief Returns name info of a street where the user rides at this moment. void GetCurrentStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const; @@ -405,9 +407,6 @@ private: void GetClosestTurn(size_t segIdx, turns::TurnItem & turn) const; size_t ConvertPointIdxToSegmentIdx(size_t pointIdx) const; - /// \brief Returns a name info of a street next to idx point of the path. - void GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const; - /// \returns Estimated time to pass the route segment with |segIdx|. double GetTimeToPassSegSec(size_t segIdx) const; diff --git a/routing/routing_integration_tests/route_test.cpp b/routing/routing_integration_tests/route_test.cpp index a980e703f1..543e070e53 100644 --- a/routing/routing_integration_tests/route_test.cpp +++ b/routing/routing_integration_tests/route_test.cpp @@ -422,7 +422,7 @@ using namespace std; for (auto const & routeSegment : routeSegments) { TEST(routeSegment.GetSpeedCams().empty(), - (routeSegment.GetSegment(), routeSegment.GetStreet())); + (routeSegment.GetSegment(), routeSegment.GetRoadNameInfo().m_name)); } } diff --git a/routing/routing_integration_tests/routing_test_tools.cpp b/routing/routing_integration_tests/routing_test_tools.cpp index 6afb4a9728..0be88ec83d 100644 --- a/routing/routing_integration_tests/routing_test_tools.cpp +++ b/routing/routing_integration_tests/routing_test_tools.cpp @@ -183,19 +183,16 @@ void TestTurnCount(routing::Route const & route, uint32_t expectedTurnCount) void TestCurrentStreetName(routing::Route const & route, string const & expectedStreetName) { - string streetName; - route.GetCurrentStreetName(streetName); - TEST_EQUAL(streetName, expectedStreetName, ()); + RouteSegment::RoadNameInfo roadNameInfo; + route.GetCurrentStreetName(roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, expectedStreetName, ()); } void TestNextStreetName(routing::Route const & route, string const & expectedStreetName) { - string streetName; - double distance; - turns::TurnItem turn; - route.GetCurrentTurn(distance, turn); - route.GetStreetNameAfterIdx(turn.m_index, streetName); - TEST_EQUAL(streetName, expectedStreetName, ()); + RouteSegment::RoadNameInfo roadNameInfo; + route.GetNextTurnStreetName(roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, expectedStreetName, ()); } void TestRouteLength(Route const & route, double expectedRouteMeters, double relativeError) diff --git a/routing/routing_integration_tests/street_names_test.cpp b/routing/routing_integration_tests/street_names_test.cpp index 5e9d90e6ba..8de66caf74 100644 --- a/routing/routing_integration_tests/street_names_test.cpp +++ b/routing/routing_integration_tests/street_names_test.cpp @@ -52,8 +52,9 @@ UNIT_TEST(RussiaTulskayaToPaveletskayaStreetNamesTest) MoveRoute(route, ms::LatLon(55.73034, 37.63099)); + // No more extra last turn, so TestNextStreetName returns "". integration::TestCurrentStreetName(route, "Валовая улица"); - integration::TestNextStreetName(route, "улица Зацепский Вал"); + //integration::TestNextStreetName(route, "улица Зацепский Вал"); MoveRoute(route, ms::LatLon(55.730912, 37.636191)); diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index 24ec379a90..a0bdacc079 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -345,7 +345,7 @@ SessionState RoutingSession::OnLocationPositionChanged(GpsInfo const & info) // For highway exits (or main roads with exit info) returns "[junction:ref]: [target:ref] > target". // If no |target| - it will be replaced by |name| of next street. // If no |target:ref| - it will be replaced by |ref| of next road. -// So if link has no info at all, "[ref] name" of next road will be returned (as for next street). +// So if link has no info at all, "[ref] name" of next will be returned (as for next street). void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) { if (auto const & sh = ftypes::GetRoadShields(road.m_ref); !sh.empty()) @@ -355,25 +355,25 @@ void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) name.clear(); if (road.HasExitInfo()) - { - if (!road.m_junction_ref.empty()) - name = "[" + road.m_junction_ref + "]"; + { + if (!road.m_junction_ref.empty()) + name = "[" + road.m_junction_ref + "]"; - if (!road.m_destination_ref.empty()) - name += string(name.empty() ? "" : ": ") + "[" + road.m_destination_ref + "]"; + if (!road.m_destination_ref.empty()) + name += string(name.empty() ? "" : ": ") + "[" + road.m_destination_ref + "]"; - if (!road.m_destination.empty()) - name += string(name.empty() ? "" : " ") + "> " + road.m_destination; - else if (!road.m_name.empty()) - name += (road.m_destination_ref.empty() ? " : " : " ") + road.m_name; - } - else - { - if (!road.m_ref.empty()) - name = "[" + road.m_ref + "]"; - if (!road.m_name.empty()) - name += (name.empty() ? "" : " ") + road.m_name; - } + if (!road.m_destination.empty()) + name += string(name.empty() ? "" : " ") + "> " + road.m_destination; + else if (!road.m_name.empty()) + name += (road.m_destination_ref.empty() ? string(name.empty() ? "" : " ") : ": ") + road.m_name; + } + else + { + if (!road.m_ref.empty()) + name = "[" + road.m_ref + "]"; + if (!road.m_name.empty()) + name += (name.empty() ? "" : " ") + road.m_name; + } } void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const diff --git a/routing/routing_tests/route_tests.cpp b/routing/routing_tests/route_tests.cpp index 009c3eaf51..c139ec1c2f 100644 --- a/routing/routing_tests/route_tests.cpp +++ b/routing/routing_tests/route_tests.cpp @@ -29,7 +29,9 @@ static Route::TTurns const kTestTurns( {turns::TurnItem(1, turns::CarDirection::TurnLeft), turns::TurnItem(2, turns::CarDirection::TurnRight), turns::TurnItem(4, turns::CarDirection::ReachedYourDestination)}); -static Route::TStreets const kTestNames({{0, "Street1"}, {1, "Street2"}, {4, "Street3"}}); +static Route::TStreets const kTestNames({{0, {"Street1", "", "", "", "", false}}, + {1, {"Street2", "", "", "", "", false}}, + {4, {"Street3", "", "", "", "", false}}}); static Route::TTimes const kTestTimes({Route::TTimeItem(1, 5), Route::TTimeItem(3, 10), Route::TTimeItem(4, 15)}); @@ -39,11 +41,15 @@ static Route::TTurns const kTestTurns2( turns::TurnItem(2, turns::CarDirection::TurnRight), turns::TurnItem(3, turns::CarDirection::None), turns::TurnItem(4, turns::CarDirection::ReachedYourDestination)}); -static vector const kTestNames2 = {"Street0", "Street1", "Street2", "", "Street3"}; +static vector const kTestNames2 = {{"Street0", "", "", "", "", false}, + {"Street1", "", "", "", "", false}, + {"Street2", "", "", "", "", false}, + {"", "", "", "", "", false}, + {"Street3", "", "", "", "", false}}; static vector const kTestTimes2 = {0.0, 5.0, 6.0, 10.0, 15.0}; void GetTestRouteSegments(vector const & routePoints, Route::TTurns const & turns, - vector const & streets, vector const & times, + vector const & streets, vector const & times, vector & routeSegments) { CHECK_EQUAL(routePoints.size(), turns.size(), ()); @@ -290,7 +296,7 @@ UNIT_TEST(SelfIntersectedRouteMatchingTest) Route route("TestRouter", 0 /* route id */); route.SetGeometry(kRouteGeometry.begin(), kRouteGeometry.end()); - + vector routeSegments; GetTestRouteSegments(kRouteGeometry, kTestTurns2, kTestNames2, kTestTimes2, routeSegments); route.SetRouteSegments(move(routeSegments)); @@ -346,30 +352,30 @@ UNIT_TEST(RouteNameTest) GetTestRouteSegments(kTestGeometry, kTestTurns2, kTestNames2, kTestTimes2, routeSegments); route.SetRouteSegments(move(routeSegments)); - string name; - route.GetCurrentStreetName(name); - TEST_EQUAL(name, "Street1", ()); + RouteSegment::RoadNameInfo roadNameInfo; + route.GetCurrentStreetName(roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street1", (roadNameInfo.m_name)); - route.GetStreetNameAfterIdx(0, name); - TEST_EQUAL(name, "Street1", ()); + route.GetStreetNameAfterIdx(0, roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street1", (roadNameInfo.m_name)); - route.GetStreetNameAfterIdx(1, name); - TEST_EQUAL(name, "Street1", ()); + route.GetStreetNameAfterIdx(1, roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street1", (roadNameInfo.m_name)); - route.GetStreetNameAfterIdx(2, name); - TEST_EQUAL(name, "Street2", ()); + route.GetStreetNameAfterIdx(2, roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street2", (roadNameInfo.m_name)); - route.GetStreetNameAfterIdx(3, name); - TEST_EQUAL(name, "Street3", ()); + route.GetStreetNameAfterIdx(3, roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street3", (roadNameInfo.m_name)); - route.GetStreetNameAfterIdx(4, name); - TEST_EQUAL(name, "Street3", ()); + route.GetStreetNameAfterIdx(4, roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street3", (roadNameInfo.m_name)); location::GpsInfo info; info.m_longitude = 1.0; info.m_latitude = 2.0; route.MoveIterator(info); - route.GetCurrentStreetName(name); - TEST_EQUAL(name, "Street2", ()); + route.GetCurrentStreetName(roadNameInfo); + TEST_EQUAL(roadNameInfo.m_name, "Street2", (roadNameInfo.m_name)); } } // namespace route_tests diff --git a/routing/routing_tests/routing_helpers_tests.cpp b/routing/routing_tests/routing_helpers_tests.cpp index ac2b2ab404..41fce2786e 100644 --- a/routing/routing_tests/routing_helpers_tests.cpp +++ b/routing/routing_tests/routing_helpers_tests.cpp @@ -37,7 +37,7 @@ UNIT_TEST(FillSegmentInfoSmokeTest) TEST_EQUAL(segmentInfo.size(), 1, ()); TEST_EQUAL(segmentInfo[0].GetTurn().m_turn, CarDirection::ReachedYourDestination, ()); - TEST(segmentInfo[0].GetStreet().empty(), ()); + TEST(segmentInfo[0].GetRoadNameInfo().m_name.empty(), ()); } UNIT_TEST(FillSegmentInfoTest) @@ -50,7 +50,9 @@ UNIT_TEST(FillSegmentInfoTest) {m2::PointD(0.2 /* x */, 0.0 /* y */), geometry::kInvalidAltitude}}; Route::TTurns const & turnDirs = {{1 /* point index */, CarDirection::TurnRight}, {2 /* point index */, CarDirection::ReachedYourDestination}}; - Route::TStreets const streets = {{0 /* point index */, "zero"}, {1, "first"}, {2, "second"}}; + Route::TStreets const streets = {{0 /* point index */, {"zero", "", "", "", "", false}}, + {1 /* point index */, {"first", "", "", "", "", false}}, + {2 /* point index */, {"second", "", "", "", "", false}}}; Route::TTimes const times = { {0 /* point index */, 0.0 /* time in seconds */}, {1, 1.0}, {2, 2.0}}; @@ -59,11 +61,11 @@ UNIT_TEST(FillSegmentInfoTest) TEST_EQUAL(segmentInfo.size(), 2, ()); TEST_EQUAL(segmentInfo[0].GetTurn().m_turn, CarDirection::TurnRight, ()); - TEST_EQUAL(segmentInfo[0].GetStreet(), string("first"), ()); + TEST_EQUAL(segmentInfo[0].GetRoadNameInfo().m_name, string("first"), ()); TEST_EQUAL(segmentInfo[0].GetSegment(), segments[0], ()); TEST_EQUAL(segmentInfo[1].GetTurn().m_turn, CarDirection::ReachedYourDestination, ()); - TEST_EQUAL(segmentInfo[1].GetStreet(), string("second"), ()); + TEST_EQUAL(segmentInfo[1].GetRoadNameInfo().m_name, string("second"), ()); TEST_EQUAL(segmentInfo[1].GetSegment(), segments[1], ()); } diff --git a/routing/routing_tests/turns_generator_test.cpp b/routing/routing_tests/turns_generator_test.cpp index 71494a7136..0469740821 100644 --- a/routing/routing_tests/turns_generator_test.cpp +++ b/routing/routing_tests/turns_generator_test.cpp @@ -339,7 +339,7 @@ UNIT_TEST(TestIntermediateDirection) UNIT_TEST(TestCheckUTurnOnRoute) { TUnpackedPathSegments pathSegments(4, LoadedPathSegment()); - pathSegments[0].m_name = "A road"; + pathSegments[0].m_roadNameInfo = {"A road", "", "", "", "", false}; pathSegments[0].m_weight = 1; pathSegments[0].m_highwayClass = ftypes::HighwayClass::Trunk; pathSegments[0].m_onRoundabout = false; diff --git a/routing/turns_generator.cpp b/routing/turns_generator.cpp index 9cc1d21c7c..114df86d9b 100644 --- a/routing/turns_generator.cpp +++ b/routing/turns_generator.cpp @@ -292,7 +292,8 @@ void CorrectCandidatesSegmentByOutgoing(TurnInfo const & turnInfo, Segment const it->m_segment = firstOutgoingSeg; } else if (nodes.isCandidatesAngleValid) - ASSERT(false, ("Can't match any candidate with firstOutgoingSegment but isCandidatesAngleValid == true.")); + // Typically all candidates are from one mwm, and missed one (firstOutgoingSegment) from another. + LOG(LWARNING, ("Can't match any candidate with firstOutgoingSegment but isCandidatesAngleValid == true.")); else { LOG(LWARNING, ("Can't match any candidate with firstOutgoingSegment and isCandidatesAngleValid == false")); -- 2.45.3 From d04b09bf47f9c796c24a4b05b1d27a84c92e7928 Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Sun, 5 Jun 2022 17:04:22 +0300 Subject: [PATCH 11/14] Small fixes for review Signed-off-by: Anton Makouski --- generator/osm2meta.cpp | 3 ++- routing/car_directions.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 337e31a513..8293f591fd 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -148,11 +148,12 @@ string MetadataTagProcessorImpl::ValidateAndFormat_ele(string const & v) const string MetadataTagProcessorImpl::ValidateAndFormat_destination(string const & v) const { + // Normalization. "a ;b; c " " -> "a; b; c". string r; strings::Tokenize(v, ";", [&](std::string_view d) { if (r.empty()) - r = d; + r = string(strings::Trim(d)); else r += "; " + string(strings::Trim(d)); }); diff --git a/routing/car_directions.cpp b/routing/car_directions.cpp index ede4d02122..171bb138d2 100644 --- a/routing/car_directions.cpp +++ b/routing/car_directions.cpp @@ -101,9 +101,10 @@ size_t CarDirectionsEngine::GetTurnDirection(IRoutingResult const & result, size NumMwmIds const & numMwmIds, RoutingSettings const & vehicleSettings, TurnItem & turnItem) { - // This is for jump from initial point to start of the route. + // This is for jump from initial point to start of the route. No direction is given. /// @todo Sometimes results of GetPossibleTurns are empty, sometimes are invalid. - ///E.g. Google Maps until you reach destination will guide you go to the left or to the right of first road. + /// The best will be to fix GetPossibleTurns(). It will allow us to use following approach. + /// E.g. Google Maps until you reach the destination will guide you to go to the left or to the right of the first road. if (turnItem.m_index == 2) return 0; -- 2.45.3 From d7cde8cce132fefb0ffb315da899171295693a6b Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Sun, 5 Jun 2022 23:26:43 +0300 Subject: [PATCH 12/14] Small fixes for review Signed-off-by: Anton Makouski --- generator/osm2meta.cpp | 11 +---------- routing/routing_session.cpp | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 8293f591fd..65dfaf048d 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -148,16 +148,7 @@ string MetadataTagProcessorImpl::ValidateAndFormat_ele(string const & v) const string MetadataTagProcessorImpl::ValidateAndFormat_destination(string const & v) const { - // Normalization. "a ;b; c " " -> "a; b; c". - string r; - strings::Tokenize(v, ";", [&](std::string_view d) - { - if (r.empty()) - r = string(strings::Trim(d)); - else - r += "; " + string(strings::Trim(d)); - }); - return r; + return v; } string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const & v) const diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index a0bdacc079..91269ebb3d 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -341,6 +341,20 @@ SessionState RoutingSession::OnLocationPositionChanged(GpsInfo const & info) return m_state; } +string FormatRoadDestination(string const & v) +{ + // Normalization. "a ;b; c,d " " -> "a; b; c; d". + string r; + strings::Tokenize(v, " ;,", [&](std::string_view d) + { + if (r.empty()) + r = d; + else + r += "; " + string(d); + }); + return r; +} + // For next street returns "[ref] name" . // For highway exits (or main roads with exit info) returns "[junction:ref]: [target:ref] > target". // If no |target| - it will be replaced by |name| of next street. @@ -363,7 +377,7 @@ void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) name += string(name.empty() ? "" : ": ") + "[" + road.m_destination_ref + "]"; if (!road.m_destination.empty()) - name += string(name.empty() ? "" : " ") + "> " + road.m_destination; + name += string(name.empty() ? "" : " ") + "> " + FormatRoadDestination(road.m_destination); else if (!road.m_name.empty()) name += (road.m_destination_ref.empty() ? string(name.empty() ? "" : " ") : ": ") + road.m_name; } -- 2.45.3 From ee3bfa0d205aa27d4f98bda98cb2d1d9211168b2 Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Tue, 7 Jun 2022 10:31:27 +0300 Subject: [PATCH 13/14] Small fixes for review Signed-off-by: Anton Makouski --- generator/osm2meta.cpp | 13 ++++++++++++- routing/routing_session.cpp | 16 +--------------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 65dfaf048d..282f9ee623 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -148,7 +148,18 @@ string MetadataTagProcessorImpl::ValidateAndFormat_ele(string const & v) const string MetadataTagProcessorImpl::ValidateAndFormat_destination(string const & v) const { - return v; + { + // Normalization. "a1 a2;b1-b2; c,d " " -> "a1 a2; b1-b2; c; d". + string r; + strings::Tokenize(v, ";,", [&](std::string_view d) + { + if (r.empty()) + r = strings::Trim(d); + else + r += "; " + string(strings::Trim(d)); + }); + return r; + } } string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const & v) const diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index 91269ebb3d..a0bdacc079 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -341,20 +341,6 @@ SessionState RoutingSession::OnLocationPositionChanged(GpsInfo const & info) return m_state; } -string FormatRoadDestination(string const & v) -{ - // Normalization. "a ;b; c,d " " -> "a; b; c; d". - string r; - strings::Tokenize(v, " ;,", [&](std::string_view d) - { - if (r.empty()) - r = d; - else - r += "; " + string(d); - }); - return r; -} - // For next street returns "[ref] name" . // For highway exits (or main roads with exit info) returns "[junction:ref]: [target:ref] > target". // If no |target| - it will be replaced by |name| of next street. @@ -377,7 +363,7 @@ void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name) name += string(name.empty() ? "" : ": ") + "[" + road.m_destination_ref + "]"; if (!road.m_destination.empty()) - name += string(name.empty() ? "" : " ") + "> " + FormatRoadDestination(road.m_destination); + name += string(name.empty() ? "" : " ") + "> " + road.m_destination; else if (!road.m_name.empty()) name += (road.m_destination_ref.empty() ? string(name.empty() ? "" : " ") : ": ") + road.m_name; } -- 2.45.3 From a55062c6fd69efb5bf35aa9e0a71d3f89b8b40fa Mon Sep 17 00:00:00 2001 From: Anton Makouski Date: Tue, 7 Jun 2022 12:59:02 +0300 Subject: [PATCH 14/14] Small fixes for review + test Signed-off-by: Anton Makouski --- generator/generator_tests/osm2meta_test.cpp | 12 +++++++++++ generator/osm2meta.cpp | 22 ++++++++++----------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/generator/generator_tests/osm2meta_test.cpp b/generator/generator_tests/osm2meta_test.cpp index 3e20b4f43e..89ce66c09f 100644 --- a/generator/generator_tests/osm2meta_test.cpp +++ b/generator/generator_tests/osm2meta_test.cpp @@ -42,3 +42,15 @@ UNIT_TEST(ValidateAndFormat_building_levels) TEST_EQUAL(tp.ValidateAndFormat_building_levels("2.51"), "2.5", ()); TEST_EQUAL(tp.ValidateAndFormat_building_levels("250"), "", ("Too many levels.")); } + +UNIT_TEST(ValidateAndFormat_destination) +{ + FeatureBuilderParams params; + MetadataTagProcessorImpl tp(params); + TEST_EQUAL(tp.ValidateAndFormat_destination("a1 a2"), "a1 a2", ()); + TEST_EQUAL(tp.ValidateAndFormat_destination("b1-b2"), "b1-b2", ()); + TEST_EQUAL(tp.ValidateAndFormat_destination(" c,d ;"), "c; d", ()); + TEST_EQUAL(tp.ValidateAndFormat_destination("e,;f; g;"), "e; f; g", ()); + TEST_EQUAL(tp.ValidateAndFormat_destination(""), "", ()); + TEST_EQUAL(tp.ValidateAndFormat_destination("a1 a2;b1-b2; c,d ;e,;f; ;g"), "a1 a2; b1-b2; c; d; e; f; g", ()); +} \ No newline at end of file diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 282f9ee623..0ad60e5e84 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -148,18 +148,18 @@ string MetadataTagProcessorImpl::ValidateAndFormat_ele(string const & v) const string MetadataTagProcessorImpl::ValidateAndFormat_destination(string const & v) const { + // Normalization. "a1 a2;b1-b2; c,d ;e,;f; ;g" -> "a1 a2; b1-b2; c; d; e; f; g" + string r; + strings::Tokenize(v, ";,", [&](std::string_view d) { - // Normalization. "a1 a2;b1-b2; c,d " " -> "a1 a2; b1-b2; c; d". - string r; - strings::Tokenize(v, ";,", [&](std::string_view d) - { - if (r.empty()) - r = strings::Trim(d); - else - r += "; " + string(strings::Trim(d)); - }); - return r; - } + strings::Trim(d); + if (d.empty()) + return; + if (!r.empty()) + r += "; "; + r.append(d); + }); + return r; } string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const & v) const -- 2.45.3