diff --git a/map/bookmark_manager.cpp b/map/bookmark_manager.cpp index 9d9d926aad..5124c9a71a 100644 --- a/map/bookmark_manager.cpp +++ b/map/bookmark_manager.cpp @@ -1493,6 +1493,7 @@ UserMark const * BookmarkManager::FindNearestUserMark(TTouchRectHolder const & h CHECK_THREAD_CHECKER(m_threadChecker, ()); BestUserMarkFinder finder(holder, this); finder(UserMark::Type::ROUTING); + finder(UserMark::Type::ROAD_WARNING); finder(UserMark::Type::SEARCH); finder(UserMark::Type::API); for (auto & pair : m_categories) diff --git a/map/framework.cpp b/map/framework.cpp index ed75d3898c..ec9db46502 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1030,6 +1030,27 @@ void Framework::FillRouteMarkInfo(RouteMarkPoint const & rmp, place_page::Info & info.SetIntermediateIndex(rmp.GetIntermediateIndex()); } +void Framework::FillRoadTypeMarkInfo(RoadWarningMark const & roadTypeMark, place_page::Info & info) const +{ + CHECK(roadTypeMark.GetFeatureID().IsValid(), ()); + + FeaturesLoaderGuard const guard(m_model.GetDataSource(), roadTypeMark.GetFeatureID().m_mwmId); + FeatureType ft; + if (!guard.GetFeatureByIndex(roadTypeMark.GetFeatureID().m_index, ft)) + { + LOG(LERROR, ("Feature can't be loaded:", roadTypeMark.GetFeatureID())); + return; + } + FillInfoFromFeatureType(ft, info); + + + info.SetRoadType(ft, + roadTypeMark.GetRoadWarningType(), + RoadWarningMark::GetLocalizedRoadWarningType(roadTypeMark.GetRoadWarningType()), + roadTypeMark.GetDistance()); + info.SetMercator(roadTypeMark.GetPivot()); +} + void Framework::ShowBookmark(kml::MarkId id) { auto const * mark = m_bmManager->GetBookmark(id); @@ -2261,6 +2282,8 @@ void Framework::ActivateMapSelection(bool needAnimation, df::SelectionShape::ESe SetDisplacementMode(DisplacementModeManager::SLOT_MAP_SELECTION, ftypes::IsHotelChecker::Instance()(info.GetTypes()) /* show */); + m_routingManager.UpdateRouteMarksVisibility(info.IsRoadType() ? info.GetRoadType() : RoadWarningMarkType::Count); + if (m_activateMapSelectionFn) m_activateMapSelectionFn(info); else @@ -2275,6 +2298,8 @@ void Framework::DeactivateMapSelection(bool notifyUI) if (notifyUI && m_deactivateMapSelectionFn) m_deactivateMapSelectionFn(!somethingWasAlreadySelected); + m_routingManager.UpdateRouteMarksVisibility(RoadWarningMarkType::Count); + if (somethingWasAlreadySelected && m_drapeEngine != nullptr) m_drapeEngine->DeselectObject(); @@ -2445,6 +2470,9 @@ df::SelectionShape::ESelectedObject Framework::OnTapEventImpl(TapEvent const & t case UserMark::Type::ROUTING: FillRouteMarkInfo(*static_cast(mark), outInfo); break; + case UserMark::Type::ROAD_WARNING: + FillRoadTypeMarkInfo(*static_cast(mark), outInfo); + break; default: ASSERT(false, ("FindNearestUserMark returned invalid mark.")); } @@ -2491,7 +2519,7 @@ UserMark const * Framework::FindUserMarkInTapPosition(df::TapInfo const & tapInf { if (type == UserMark::Type::BOOKMARK) return tapInfo.GetBookmarkSearchRect(m_currentModelView); - if (type == UserMark::Type::ROUTING) + if (type == UserMark::Type::ROUTING || type == UserMark::Type::ROAD_WARNING) return tapInfo.GetRoutingPointSearchRect(m_currentModelView); return tapInfo.GetDefaultSearchRect(m_currentModelView); }); diff --git a/map/framework.hpp b/map/framework.hpp index 9c58c980e2..b8f54c56f8 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -704,6 +704,7 @@ private: void FillSearchResultInfo(SearchMarkPoint const & smp, place_page::Info & info) const; void FillMyPositionInfo(place_page::Info & info, df::TapInfo const & tapInfo) const; void FillRouteMarkInfo(RouteMarkPoint const & rmp, place_page::Info & info) const; + void FillRoadTypeMarkInfo(RoadWarningMark const & roadTypeMark, place_page::Info & info) const; public: void FillBookmarkInfo(Bookmark const & bmk, place_page::Info & info) const; diff --git a/map/place_page_info.cpp b/map/place_page_info.cpp index 279657ac3a..53350d5735 100644 --- a/map/place_page_info.cpp +++ b/map/place_page_info.cpp @@ -13,6 +13,7 @@ #include "indexer/feature_source.hpp" #include "indexer/feature_utils.hpp" #include "indexer/ftypes_sponsored.hpp" +#include "indexer/road_shields_parser.hpp" #include "platform/measurement_utils.hpp" #include "platform/preferred_languages.hpp" @@ -332,6 +333,50 @@ void Info::SetPartnerIndex(int index) m_partnerName = GetPartnerByIndex(m_partnerIndex).m_name; } +void Info::SetRoadType(FeatureType & ft, RoadWarningMarkType type, std::string const & localizedType, + std::string const & distance) +{ + CHECK(type != RoadWarningMarkType::Count, ()); + m_roadType = type; + + std::vector subtitle; + if (type == RoadWarningMarkType::Paid) + { + std::vector title; + auto shields = ftypes::GetRoadShields(ft); + for (auto const & shield : shields) + { + auto name = shield.m_name; + if (!shield.m_additionalText.empty()) + name += " " + shield.m_additionalText; + title.push_back(shield.m_name); + } + m_uiTitle = strings::JoinStrings(title, kSubtitleSeparator); + + if (m_uiTitle.empty()) + m_uiTitle = m_primaryFeatureName; + + if (m_uiTitle.empty()) + m_uiTitle = localizedType; + else + subtitle.push_back(localizedType); + } + else if (type == RoadWarningMarkType::Unpaved) + { + m_uiTitle = localizedType; + subtitle.push_back(distance); + } + else if (type == RoadWarningMarkType::Ferry) + { + m_uiTitle = m_primaryFeatureName; + subtitle.push_back(localizedType); + auto const operatorName = GetOperator(); + if (!operatorName.empty()) + subtitle.push_back(operatorName); + } + m_uiSubtitle = strings::JoinStrings(subtitle, kSubtitleSeparator); +} + namespace rating { namespace diff --git a/map/place_page_info.hpp b/map/place_page_info.hpp index 421113489f..7ae909e064 100644 --- a/map/place_page_info.hpp +++ b/map/place_page_info.hpp @@ -76,6 +76,7 @@ public: bool IsBookmark() const { return m_markGroupId != kml::kInvalidMarkGroupId && m_markId != kml::kInvalidMarkId; } bool IsMyPosition() const { return m_isMyPosition; } bool IsRoutePoint() const { return m_isRoutePoint; } + bool IsRoadType() const { return m_roadType != RoadWarningMarkType::Count; } /// Edit and add bool ShouldShowAddPlace() const; @@ -196,6 +197,11 @@ public: size_t GetIntermediateIndex() const { return m_intermediateIndex; } void SetIsRoutePoint() { m_isRoutePoint = true; } + /// Road type + void SetRoadType(FeatureType & ft, RoadWarningMarkType type, std::string const & localizedType, + std::string const & distance); + RoadWarningMarkType GetRoadType() const { return m_roadType; } + /// CountryId /// Which mwm this MapObject is in. /// Exception: for a country-name point it will be set to the topmost node for the mwm. @@ -272,6 +278,9 @@ private: size_t m_intermediateIndex = 0; bool m_isRoutePoint = false; + /// Road type + RoadWarningMarkType m_roadType = RoadWarningMarkType::Count; + bool m_isMyPosition = false; /// Editor diff --git a/map/routing_manager.cpp b/map/routing_manager.cpp index 5b46665725..d1f1c038ab 100644 --- a/map/routing_manager.cpp +++ b/map/routing_manager.cpp @@ -210,6 +210,46 @@ VehicleType GetVehicleType(RouterType routerType) } UNREACHABLE(); } + +RoadWarningMarkType GetRoadType(RoutingOptions::Road road) +{ + if (road == RoutingOptions::Road::Toll) + return RoadWarningMarkType::Paid; + if (road == RoutingOptions::Road::Ferry) + return RoadWarningMarkType::Ferry; + if (road == RoutingOptions::Road::Dirty) + return RoadWarningMarkType::Unpaved; + CHECK(false, ("Invalid road type to avoid:", road)); + return RoadWarningMarkType::Count; +} + +drape_ptr CreateDrapeSubroute(vector const & segments, m2::PointD const & startPt, + double baseDistance, double baseDepth, bool isTransit) +{ + auto subroute = make_unique_dp(); + subroute->m_baseDistance = baseDistance; + subroute->m_baseDepthIndex = baseDepth; + + if (isTransit) + { + subroute->m_polyline.Add(startPt); + return subroute; + } + + vector points; + points.reserve(segments.size() + 1); + points.push_back(startPt); + for (auto const & s : segments) + points.push_back(s.GetJunction().GetPoint()); + if (points.size() < 2) + { + LOG(LWARNING, ("Invalid subroute. Points number =", points.size())); + return nullptr; + } + + subroute->m_polyline = m2::PolylineD(points); + return subroute; +} } // namespace namespace marketing @@ -457,9 +497,12 @@ void RoutingManager::RemoveRoute(bool deactivateFollowing) { GetPlatform().RunTask(Platform::Thread::Gui, [this, deactivateFollowing]() { - m_bmManager->GetEditSession().ClearGroup(UserMark::Type::TRANSIT); - m_bmManager->GetEditSession().ClearGroup(UserMark::Type::SPEED_CAM); - + { + auto es = m_bmManager->GetEditSession(); + es.ClearGroup(UserMark::Type::TRANSIT); + es.ClearGroup(UserMark::Type::SPEED_CAM); + es.ClearGroup(UserMark::Type::ROAD_WARNING); + } if (deactivateFollowing) SetPointsFollowingMode(false /* enabled */); }); @@ -489,6 +532,70 @@ void RoutingManager::RemoveRoute(bool deactivateFollowing) } } +void RoutingManager::CollectRoadWarnings(std::vector const & segments, + m2::PointD const & startPt, double baseDistance, + GetMwmIdFn const & getMwmIdFn, RoadWarningsCollection & roadWarnings) +{ + auto const isImportantType = [](RoutingOptions::Road roadType) + { + return roadType == RoutingOptions::Road::Toll || roadType == RoutingOptions::Road::Ferry || + roadType == RoutingOptions::Road::Dirty; + }; + + double currentDistance = baseDistance; + double startDistance = baseDistance; + RoutingOptions::Road lastType = RoutingOptions::Road::Usual; + for (size_t i = 0; i < segments.size(); ++i) + { + auto const currentType = ChooseMainRoutingOptionRoad(segments[i].GetRoadTypes()); + if (currentType != lastType) + { + if (isImportantType(lastType)) + roadWarnings[lastType].back().m_distance = segments[i].GetDistFromBeginningMeters() - startDistance; + + if (isImportantType(currentType)) + { + startDistance = currentDistance; + auto const featureId = FeatureID(getMwmIdFn(segments[i].GetSegment().GetMwmId()), + segments[i].GetSegment().GetFeatureId()); + auto const markPoint = i == 0 ? startPt : segments[i - 1].GetJunction().GetPoint(); + roadWarnings[currentType].push_back(RoadInfo(markPoint, featureId)); + } + lastType = currentType; + } + currentDistance = segments[i].GetDistFromBeginningMeters(); + } + if (isImportantType(lastType)) + roadWarnings[lastType].back().m_distance = segments.back().GetDistFromBeginningMeters() - startDistance; +} + +void RoutingManager::CreateRoadWarningMarks(RoadWarningsCollection && roadWarnings) +{ + if (roadWarnings.empty()) + return; + + GetPlatform().RunTask(Platform::Thread::Gui, [this, roadWarnings = move(roadWarnings)]() + { + auto es = m_bmManager->GetEditSession(); + for (auto const & typeInfo : roadWarnings) + { + auto const type = GetRoadType(typeInfo.first); + for (size_t i = 0; i < typeInfo.second.size(); ++i) + { + auto const & routeInfo = typeInfo.second[i]; + auto mark = es.CreateUserMark(routeInfo.m_startPoint); + mark->SetIndex(static_cast(i)); + mark->SetIsVisible(i == 0); + mark->SetRoadWarningType(type); + mark->SetFeatureId(routeInfo.m_featureId); + std::string distanceStr; + measurement_utils::FormatDistance(routeInfo.m_distance, distanceStr); + mark->SetDistance(distanceStr); + } + } + }); +} + void RoutingManager::InsertRoute(Route const & route) { if (!m_drapeEngine) @@ -497,78 +604,54 @@ void RoutingManager::InsertRoute(Route const & route) // TODO: Now we always update whole route, so we need to remove previous one. RemoveRoute(false /* deactivateFollowing */); - shared_ptr transitRouteDisplay; auto numMwmIds = make_shared(); - if (m_currentRouterType == RouterType::Transit) + m_delegate.RegisterCountryFilesOnRoute(numMwmIds); + auto const getMwmId = [this, numMwmIds](routing::NumMwmId numMwmId) + { + return m_callbacks.m_dataSourceGetter().GetMwmIdByCountryFile(numMwmIds->GetFile(numMwmId)); + }; + + RoadWarningsCollection roadWarnings; + + auto const isTransitRoute = m_currentRouterType == RouterType::Transit; + shared_ptr transitRouteDisplay; + if (isTransitRoute) { - m_delegate.RegisterCountryFilesOnRoute(numMwmIds); - auto getMwmId = [this, numMwmIds](routing::NumMwmId numMwmId) - { - return m_callbacks.m_dataSourceGetter().GetMwmIdByCountryFile(numMwmIds->GetFile(numMwmId)); - }; transitRouteDisplay = make_shared(*m_transitReadManager, getMwmId, m_callbacks.m_stringsBundleGetter, m_bmManager, m_transitSymbolSizes); } vector segments; - vector points; double distance = 0.0; - auto const subroutesCount = route.GetSubrouteCount(); for (size_t subrouteIndex = route.GetCurrentSubrouteIdx(); subrouteIndex < subroutesCount; ++subrouteIndex) { route.GetSubrouteInfo(subrouteIndex, segments); - // Fill points. - double const currentBaseDistance = distance; - auto subroute = make_unique_dp(); - subroute->m_baseDistance = currentBaseDistance; - subroute->m_baseDepthIndex = static_cast(subroutesCount - subrouteIndex - 1); auto const startPt = route.GetSubrouteAttrs(subrouteIndex).GetStart().GetPoint(); - if (m_currentRouterType != RouterType::Transit) - { - points.clear(); - points.reserve(segments.size() + 1); - points.push_back(startPt); - for (auto const & s : segments) - points.push_back(s.GetJunction().GetPoint()); - if (points.size() < 2) - { - LOG(LWARNING, ("Invalid subroute. Points number =", points.size())); - continue; - } - subroute->m_polyline = m2::PolylineD(points); - } - else - { - subroute->m_polyline.Add(startPt); - } + auto subroute = CreateDrapeSubroute(segments, startPt, distance, + static_cast(subroutesCount - subrouteIndex - 1), isTransitRoute); + if (!subroute) + continue; distance = segments.back().GetDistFromBeginningMerc(); - switch (m_currentRouterType) { case RouterType::Vehicle: case RouterType::Taxi: { - subroute->m_routeType = m_currentRouterType == RouterType::Vehicle ? - df::RouteType::Car : df::RouteType::Taxi; + subroute->m_routeType = m_currentRouterType == RouterType::Vehicle ? df::RouteType::Car : df::RouteType::Taxi; subroute->AddStyle(df::SubrouteStyle(df::kRouteColor, df::kRouteOutlineColor)); FillTrafficForRendering(segments, subroute->m_traffic); - FillTurnsDistancesForRendering(segments, subroute->m_baseDistance, - subroute->m_turns); + FillTurnsDistancesForRendering(segments, subroute->m_baseDistance, subroute->m_turns); + CollectRoadWarnings(segments, startPt, subroute->m_baseDistance, getMwmId, roadWarnings); break; } case RouterType::Transit: { subroute->m_routeType = df::RouteType::Transit; - transitRouteDisplay->ProcessSubroute(segments, *subroute.get()); - - if (subroute->m_polyline.GetSize() < 2) - { - LOG(LWARNING, ("Invalid transit subroute. Points number =", subroute->m_polyline.GetSize())); + if (!transitRouteDisplay->ProcessSubroute(segments, *subroute.get())) continue; - } break; } case RouterType::Pedestrian: @@ -581,8 +664,7 @@ void RoutingManager::InsertRoute(Route const & route) { subroute->m_routeType = df::RouteType::Bicycle; subroute->AddStyle(df::SubrouteStyle(df::kRouteBicycle, df::RoutePattern(8.0, 2.0))); - FillTurnsDistancesForRendering(segments, subroute->m_baseDistance, - subroute->m_turns); + FillTurnsDistancesForRendering(segments, subroute->m_baseDistance, subroute->m_turns); break; } default: ASSERT(false, ("Unknown router type")); @@ -599,17 +681,18 @@ void RoutingManager::InsertRoute(Route const & route) { lock_guard lock(m_drapeSubroutesMutex); - m_transitRouteInfo = m_currentRouterType == RouterType::Transit ? transitRouteDisplay->GetRouteInfo() - : TransitRouteInfo(); + m_transitRouteInfo = isTransitRoute ? transitRouteDisplay->GetRouteInfo() : TransitRouteInfo(); } - if (m_currentRouterType == RouterType::Transit) + if (isTransitRoute) { GetPlatform().RunTask(Platform::Thread::Gui, [transitRouteDisplay = move(transitRouteDisplay)]() { transitRouteDisplay->CreateTransitMarks(); }); } + + CreateRoadWarningMarks(std::move(roadWarnings)); } void RoutingManager::FollowRoute() @@ -624,6 +707,7 @@ void RoutingManager::FollowRoute() m_currentRouterType == RouterType::Bicycle); m_delegate.OnRouteFollow(m_currentRouterType); + m_bmManager->GetEditSession().ClearGroup(UserMark::Type::ROAD_WARNING); HideRoutePoint(RouteMarkType::Start); SetPointsFollowingMode(true /* enabled */); @@ -1400,3 +1484,18 @@ bool RoutingManager::IsSpeedLimitExceeded() const { return m_routingSession.IsSpeedLimitExceeded(); } + +void RoutingManager::UpdateRouteMarksVisibility(RoadWarningMarkType selectedType) +{ + auto const markIds = m_bmManager->GetUserMarkIds(UserMark::Type::ROAD_WARNING); + if (markIds.empty()) + return; + + auto es = m_bmManager->GetEditSession(); + for (auto id : markIds) + { + auto mark = es.GetMarkForEdit(id); + auto const isVisible = mark->GetIndex() == 0 || selectedType == mark->GetRoadWarningType(); + mark->SetIsVisible(isVisible); + } +} diff --git a/map/routing_manager.hpp b/map/routing_manager.hpp index 09e1ed2caf..926a18bd2e 100644 --- a/map/routing_manager.hpp +++ b/map/routing_manager.hpp @@ -285,11 +285,34 @@ public: /// \brief It deletes file with saved route points if it exists. void DeleteSavedRoutePoints(); + void UpdateRouteMarksVisibility(RoadWarningMarkType selectedType); + void UpdatePreviewMode(); void CancelPreviewMode(); private: void InsertRoute(routing::Route const & route); + + struct RoadInfo + { + RoadInfo() = default; + + explicit RoadInfo(m2::PointD const & pt, FeatureID const & featureId) + : m_startPoint(pt) + , m_featureId(featureId) + {} + + m2::PointD m_startPoint; + FeatureID m_featureId; + double m_distance = 0.0; + }; + using RoadWarningsCollection = std::map>; + + using GetMwmIdFn = std::function; + void CollectRoadWarnings(std::vector const & segments, m2::PointD const & startPt, + double baseDistance, GetMwmIdFn const & getMwmIdFn, RoadWarningsCollection & roadWarnings); + void CreateRoadWarningMarks(RoadWarningsCollection && roadWarnings); + bool IsTrackingReporterEnabled() const; void MatchLocationToRoute(location::GpsInfo & info, location::RouteMatchingInfo & routeMatchingInfo) const; diff --git a/map/routing_mark.cpp b/map/routing_mark.cpp index 6bd0252b21..ff6bd25c0c 100644 --- a/map/routing_mark.cpp +++ b/map/routing_mark.cpp @@ -3,6 +3,8 @@ #include "drape_frontend/color_constants.hpp" #include "drape_frontend/visual_params.hpp" +#include "platform/localization.hpp" + #include namespace @@ -62,6 +64,12 @@ df::DepthLayer RouteMarkPoint::GetDepthLayer() const return df::DepthLayer::RoutingMarkLayer; } +void RouteMarkPoint::SetIsVisible(bool isVisible) +{ + SetDirty(); + m_markData.m_isVisible = isVisible; +} + void RouteMarkPoint::SetRoutePointType(RouteMarkType type) { SetDirty(); @@ -600,3 +608,66 @@ dp::Anchor SpeedCameraMark::GetAnchor() const { return dp::Center; } + +RoadWarningMark::RoadWarningMark(m2::PointD const & ptOrg) + : UserMark(ptOrg, Type::ROAD_WARNING) +{ + +} + +void RoadWarningMark::SetIndex(uint32_t index) +{ + SetDirty(); + m_index = index; +} + +void RoadWarningMark::SetIsVisible(bool isVisible) +{ + SetDirty(); + m_isVisible = isVisible; +} + +void RoadWarningMark::SetRoadWarningType(RoadWarningMarkType type) +{ + SetDirty(); + m_type = type; +} + +void RoadWarningMark::SetFeatureId(FeatureID const & featureId) +{ + SetDirty(); + m_featureId = featureId; +} + +void RoadWarningMark::SetDistance(std::string const & distance) +{ + SetDirty(); + m_distance = distance; +} + +drape_ptr RoadWarningMark::GetSymbolNames() const +{ + std::string symbolName; + switch (m_type) + { + case RoadWarningMarkType::Ferry: symbolName = "ferry"; break; + case RoadWarningMarkType::Paid: symbolName = "paid_road"; break; + case RoadWarningMarkType::Unpaved: symbolName = "unpaved_road"; break; + } + auto symbol = make_unique_dp(); + symbol->insert(std::make_pair(1 /* zoomLevel */, symbolName)); + return symbol; +} + +// static +std::string RoadWarningMark::GetLocalizedRoadWarningType(RoadWarningMarkType type) +{ + switch (type) + { + case RoadWarningMarkType::Ferry: return platform::GetLocalizedString("ferry_crossing"); + case RoadWarningMarkType::Paid: return platform::GetLocalizedString("toll_road"); + case RoadWarningMarkType::Unpaved: return platform::GetLocalizedString("unpaved_road"); + } + UNREACHABLE(); + return {}; +} diff --git a/map/routing_mark.hpp b/map/routing_mark.hpp index 1a45ab9abd..0471394dff 100644 --- a/map/routing_mark.hpp +++ b/map/routing_mark.hpp @@ -31,7 +31,7 @@ public: virtual ~RouteMarkPoint() {} bool IsVisible() const override { return m_markData.m_isVisible; } - void SetIsVisible(bool isVisible) { m_markData.m_isVisible = isVisible; } + void SetIsVisible(bool isVisible); dp::Anchor GetAnchor() const override; df::DepthLayer GetDepthLayer() const override; @@ -193,3 +193,46 @@ private: std::string m_title; dp::TitleDecl m_titleDecl; }; + +enum class RoadWarningMarkType : uint8_t +{ + // Do not change the order! + Unpaved, + Paid, + Ferry, + Count +}; + +class RoadWarningMark : public UserMark +{ +public: + explicit RoadWarningMark(m2::PointD const & ptOrg); + + dp::Anchor GetAnchor() const override { return dp::Anchor::Bottom; } + + void SetIndex(uint32_t index); + uint32_t GetIndex() const override { return m_index; } + + void SetIsVisible(bool isVisible); + bool IsVisible() const override { return m_isVisible; } + + void SetRoadWarningType(RoadWarningMarkType type); + RoadWarningMarkType GetRoadWarningType() const { return m_type; } + + void SetFeatureId(FeatureID const & featureId); + FeatureID GetFeatureID() const override { return m_featureId; } + + void SetDistance(std::string const & distance); + std::string GetDistance() const { return m_distance; } + + drape_ptr GetSymbolNames() const override; + + static std::string GetLocalizedRoadWarningType(RoadWarningMarkType type); + +private: + RoadWarningMarkType m_type = RoadWarningMarkType::Count; + FeatureID m_featureId; + uint32_t m_index = 0; + std::string m_distance; + bool m_isVisible = true; +}; diff --git a/map/transit/transit_display.cpp b/map/transit/transit_display.cpp index a3b4935384..14e29e7e49 100644 --- a/map/transit/transit_display.cpp +++ b/map/transit/transit_display.cpp @@ -184,7 +184,7 @@ TransitRouteInfo const & TransitRouteDisplay::GetRouteInfo() return m_routeInfo; } -void TransitRouteDisplay::ProcessSubroute(vector const & segments, df::Subroute & subroute) +bool TransitRouteDisplay::ProcessSubroute(vector const & segments, df::Subroute & subroute) { if (m_subrouteIndex > 0) { @@ -200,7 +200,7 @@ void TransitRouteDisplay::ProcessSubroute(vector const & segments, // Read transit display info. if (!m_transitReadManager.GetTransitDisplayInfo(transitDisplayInfos)) - return; + return false; subroute.m_maxPixelWidth = m_maxSubrouteWidth; subroute.m_styleType = df::SubrouteStyleType::Multiple; @@ -408,6 +408,12 @@ void TransitRouteDisplay::ProcessSubroute(vector const & segments, m_routeInfo.m_totalDistInMeters = prevDistance; m_routeInfo.m_totalTimeInSec = static_cast(ceil(prevTime)); + + auto const isValidSubroute = subroute.m_polyline.GetSize() > 1; + if (!isValidSubroute) + LOG(LWARNING, ("Invalid subroute. Points number =", subroute.m_polyline.GetSize())); + + return isValidSubroute; } void TransitRouteDisplay::CollectTransitDisplayInfo(vector const & segments, diff --git a/map/transit/transit_display.hpp b/map/transit/transit_display.hpp index 45f20c0d4f..f45bc632d5 100644 --- a/map/transit/transit_display.hpp +++ b/map/transit/transit_display.hpp @@ -107,7 +107,7 @@ public: GetStringsBundleFn const & getStringsBundleFn, BookmarkManager * bmManager, std::map const & transitSymbolSizes); - void ProcessSubroute(std::vector const & segments, df::Subroute & subroute); + bool ProcessSubroute(std::vector const & segments, df::Subroute & subroute); void CreateTransitMarks(); TransitRouteInfo const & GetRouteInfo(); diff --git a/map/user_mark.cpp b/map/user_mark.cpp index 475710c893..4e5d043702 100644 --- a/map/user_mark.cpp +++ b/map/user_mark.cpp @@ -95,6 +95,7 @@ string DebugPrint(UserMark::Type type) case UserMark::Type::BOOKMARK: return "BOOKMARK"; case UserMark::Type::DEBUG_MARK: return "DEBUG_MARK"; case UserMark::Type::ROUTING: return "ROUTING"; + case UserMark::Type::ROAD_WARNING: return "ROAD_WARNING"; case UserMark::Type::SPEED_CAM: return "SPEED_CAM"; case UserMark::Type::LOCAL_ADS: return "LOCAL_ADS"; case UserMark::Type::TRANSIT: return "TRANSIT"; diff --git a/map/user_mark.hpp b/map/user_mark.hpp index 87bd503bad..dc70dfa827 100644 --- a/map/user_mark.hpp +++ b/map/user_mark.hpp @@ -39,6 +39,7 @@ public: STATIC, ROUTING, SPEED_CAM, + ROAD_WARNING, TRANSIT, LOCAL_ADS, DEBUG_MARK,