diff --git a/libs/drape_frontend/drape_engine.cpp b/libs/drape_frontend/drape_engine.cpp index 05d0b4389..dcd1d1cbc 100644 --- a/libs/drape_frontend/drape_engine.cpp +++ b/libs/drape_frontend/drape_engine.cpp @@ -441,12 +441,13 @@ void DrapeEngine::SetCompassInfo(location::CompassInfo const & info) MessagePriority::Normal); } -void DrapeEngine::SetGpsInfo(location::GpsInfo const & info, bool isNavigable, +void DrapeEngine::SetGpsInfo(location::GpsInfo const & info, bool isNavigable, double distToNextTurn, double speedLimit, location::RouteMatchingInfo const & routeInfo) { - m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(info, isNavigable, routeInfo), - MessagePriority::Normal); + m_threadCommutator->PostMessage( + ThreadsCommutator::RenderThread, + make_unique_dp(info, isNavigable, distToNextTurn, speedLimit, routeInfo), + MessagePriority::Normal); } void DrapeEngine::SwitchMyPositionNextMode() diff --git a/libs/drape_frontend/drape_engine.hpp b/libs/drape_frontend/drape_engine.hpp index 39be90efa..9b83c1959 100644 --- a/libs/drape_frontend/drape_engine.hpp +++ b/libs/drape_frontend/drape_engine.hpp @@ -154,7 +154,8 @@ public: void UpdateMapStyle(); void SetCompassInfo(location::CompassInfo const & info); - void SetGpsInfo(location::GpsInfo const & info, bool isNavigable, location::RouteMatchingInfo const & routeInfo); + void SetGpsInfo(location::GpsInfo const & info, bool isNavigable, double distToNextTurn, double speedLimit, + location::RouteMatchingInfo const & routeInfo); void SwitchMyPositionNextMode(); void LoseLocation(); void StopLocationFollow(); diff --git a/libs/drape_frontend/frontend_renderer.cpp b/libs/drape_frontend/frontend_renderer.cpp index 3e38022b7..94fc630e9 100644 --- a/libs/drape_frontend/frontend_renderer.cpp +++ b/libs/drape_frontend/frontend_renderer.cpp @@ -438,7 +438,8 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; #endif ref_ptr msg = message; - m_myPositionController->OnLocationUpdate(msg->GetInfo(), msg->IsNavigable(), m_userEventStream.GetCurrentScreen()); + m_myPositionController->OnLocationUpdate(msg->GetInfo(), msg->IsNavigable(), msg->GetDistanceToNextTurn(), + msg->GetSpeedLimit(), m_userEventStream.GetCurrentScreen()); location::RouteMatchingInfo const & info = msg->GetRouteInfo(); if (info.HasDistanceFromBegin()) diff --git a/libs/drape_frontend/message_subclasses.hpp b/libs/drape_frontend/message_subclasses.hpp index 00325e25c..e0fc00574 100644 --- a/libs/drape_frontend/message_subclasses.hpp +++ b/libs/drape_frontend/message_subclasses.hpp @@ -481,9 +481,12 @@ private: class GpsInfoMessage : public Message { public: - GpsInfoMessage(location::GpsInfo const & info, bool isNavigable, location::RouteMatchingInfo const & routeInfo) + GpsInfoMessage(location::GpsInfo const & info, bool isNavigable, double distToNextTurn, double speedLimit, + location::RouteMatchingInfo const & routeInfo) : m_info(info) , m_isNavigable(isNavigable) + , m_distToNextTurn(distToNextTurn) + , m_speedLimit(speedLimit) , m_routeInfo(routeInfo) {} @@ -491,11 +494,15 @@ public: location::GpsInfo const & GetInfo() const { return m_info; } bool IsNavigable() const { return m_isNavigable; } + double const & GetSpeedLimit() const { return m_speedLimit; } + double const & GetDistanceToNextTurn() const { return m_distToNextTurn; } location::RouteMatchingInfo const & GetRouteInfo() const { return m_routeInfo; } private: location::GpsInfo const m_info; bool const m_isNavigable; + double const m_distToNextTurn; + double const m_speedLimit; location::RouteMatchingInfo const m_routeInfo; }; diff --git a/libs/drape_frontend/my_position_controller.cpp b/libs/drape_frontend/my_position_controller.cpp index ec02f6d60..f46fa8879 100644 --- a/libs/drape_frontend/my_position_controller.cpp +++ b/libs/drape_frontend/my_position_controller.cpp @@ -56,32 +56,18 @@ inline double GetVisualScale() return df::VisualParams::Instance().GetVisualScale(); } -// Calculate zoom value in meters per pixel -double CalculateZoomBySpeed(double speedMpS, bool isPerspectiveAllowed) +double CalculateZoomByMaxSpeed(double speedMpS, bool isPerspectiveAllowed) { using TSpeedScale = std::pair; - static std::array const scales3d = {{ - {20.0, 0.25}, - {40.0, 0.75}, - {60.0, 1.50}, - {75.0, 2.50}, - {85.0, 3.75}, - {95.0, 6.00}, + static std::array const scales2d = {{ + {0.0, 1.75}, {77.0, 4.50} // 48 mph }}; + static std::array const scales3d = {{{0.0, 1.00}, {77.0, 4.50}}}; - static std::array const scales2d = {{ - {20.0, 0.70}, - {40.0, 1.25}, - {60.0, 2.25}, - {75.0, 3.00}, - {85.0, 3.75}, - {95.0, 6.00}, - }}; + std::array const & scales = isPerspectiveAllowed ? scales3d : scales2d; - std::array const & scales = isPerspectiveAllowed ? scales3d : scales2d; - - double constexpr kDefaultSpeedKmpH = 80.0; - double const speedKmpH = speedMpS >= 0 ? measurement_utils::MpsToKmph(speedMpS) : kDefaultSpeedKmpH; + double constexpr kDefaultSpeedLimitKmpH = 50.0; + double const speedKmpH = speedMpS > 0 ? measurement_utils::MpsToKmph(speedMpS) : kDefaultSpeedLimitKmpH; size_t i = 0; for (size_t sz = scales.size(); i < sz; ++i) @@ -92,20 +78,64 @@ double CalculateZoomBySpeed(double speedMpS, bool isPerspectiveAllowed) if (i == 0) return scales.front().second / vs; - if (i == scales.size()) - return scales.back().second / vs; - double const minSpeed = scales[i - 1].first; - double const maxSpeed = scales[i].first; - double const k = (speedKmpH - minSpeed) / (maxSpeed - minSpeed); + return scales[i - 1].second / vs; +} - double const minScale = scales[i - 1].second; - double const maxScale = scales[i].second; +double CalculateZoomByDistanceToTurn(double distance, bool isPerspectiveAllowed) +{ + using TSpeedScale = std::pair; + static std::array const scales2d = {{ + {200, 0.50}, + {500, 0.80}, // 0.3 mi + {1200, 1.75}, // 0.75 mi + {2000, 3.50}, // 1.2 mi + {5000, 6.50} // 3 mi + }}; + static std::array const scales3d = {{ + {200, 0.25}, + {500, 0.60}, // 0.3 mi + {1200, 1.25}, // 0.75 mi + {2000, 3.50}, // 1.2 mi + {5000, 6.50} // 3 mi + }}; + + std::array const & scale = isPerspectiveAllowed ? scales3d : scales2d; + + double constexpr kDefaultDistance = 2000; + double const distanceM = distance >= 0 ? distance : kDefaultDistance; + + size_t i = 0; + for (size_t sz = scale.size(); i < sz; ++i) + if (scale[i].first >= distanceM) + break; + + double const vs = GetVisualScale(); + + if (i == 0) + return scale.front().second / vs; + if (i == scale.size()) + return scale.back().second / vs; + + double const minDist = scale[i - 1].first; + double const maxDist = scale[i].first; + double const k = (distanceM - minDist) / (maxDist - minDist); + + double const minScale = scale[i - 1].second; + double const maxScale = scale[i].second; double const zoom = minScale + k * (maxScale - minScale); return zoom / vs; } +double CalculateAutoZoom(double speedMpS, double distanceToTurn, bool isPerspectiveAllowed) +{ + double const zoomByDistance = CalculateZoomByDistanceToTurn(distanceToTurn, isPerspectiveAllowed); + double const zoomByMaxSpeed = CalculateZoomByMaxSpeed(speedMpS, isPerspectiveAllowed); + + return std::min(zoomByDistance, zoomByMaxSpeed); +} + void ResetNotification(uint64_t & notifyId) { notifyId = DrapeNotifier::kInvalidId; @@ -395,7 +425,8 @@ void MyPositionController::NextMode(ScreenBase const & screen) } } -void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool isNavigable, ScreenBase const & screen) +void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool isNavigable, double distanceToNextTurn, + double speedLimit, ScreenBase const & screen) { m2::PointD const oldPos = GetDrawablePosition(); double const oldAzimut = GetDrawableAzimut(); @@ -407,11 +438,13 @@ void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool m_errorRadius = rect.SizeX() * 0.5; m_horizontalAccuracy = info.m_horizontalAccuracy; - if (info.m_speed > 0.0) + if (distanceToNextTurn >= 0.0 || speedLimit >= 0.0) { double const mercatorPerMeter = m_errorRadius / info.m_horizontalAccuracy; - m_autoScale2d = mercatorPerMeter * CalculateZoomBySpeed(info.m_speed, false /* isPerspectiveAllowed */); - m_autoScale3d = mercatorPerMeter * CalculateZoomBySpeed(info.m_speed, true /* isPerspectiveAllowed */); + m_autoScale2d = + mercatorPerMeter * CalculateAutoZoom(speedLimit, distanceToNextTurn, false /* isPerspectiveAllowed */); + m_autoScale3d = + mercatorPerMeter * CalculateAutoZoom(speedLimit, distanceToNextTurn, true /* isPerspectiveAllowed */); } else { diff --git a/libs/drape_frontend/my_position_controller.hpp b/libs/drape_frontend/my_position_controller.hpp index 177016e7e..0ac4a638e 100644 --- a/libs/drape_frontend/my_position_controller.hpp +++ b/libs/drape_frontend/my_position_controller.hpp @@ -117,7 +117,8 @@ public: void OnEnterBackground(); void OnCompassTapped(); - void OnLocationUpdate(location::GpsInfo const & info, bool isNavigable, ScreenBase const & screen); + void OnLocationUpdate(location::GpsInfo const & info, bool isNavigable, double distanceToNextTurn, double speedLimit, + ScreenBase const & screen); void OnCompassUpdate(location::CompassInfo const & info, ScreenBase const & screen); void Render(ref_ptr context, ref_ptr mng, ScreenBase const & screen, diff --git a/libs/map/routing_manager.cpp b/libs/map/routing_manager.cpp index 5bb711350..5034ed81f 100644 --- a/libs/map/routing_manager.cpp +++ b/libs/map/routing_manager.cpp @@ -1171,6 +1171,7 @@ void RoutingManager::SetDrapeEngine(ref_ptr engine, bool is3dAl { auto routeMatchingInfo = GetRouteMatchingInfo(*m_gpsInfoCache); m_drapeEngine.SafeCall(&df::DrapeEngine::SetGpsInfo, *m_gpsInfoCache, m_routingSession.IsNavigable(), + m_routingSession.GetDistanceToNextTurn(), m_routingSession.GetCurrentSpeedLimit(), routeMatchingInfo); m_gpsInfoCache.reset(); } @@ -1515,7 +1516,9 @@ void RoutingManager::OnExtrapolatedLocationUpdate(location::GpsInfo const & info m_gpsInfoCache = make_unique(gpsInfo); auto routeMatchingInfo = GetRouteMatchingInfo(gpsInfo); - m_drapeEngine.SafeCall(&df::DrapeEngine::SetGpsInfo, gpsInfo, m_routingSession.IsNavigable(), routeMatchingInfo); + m_drapeEngine.SafeCall(&df::DrapeEngine::SetGpsInfo, gpsInfo, m_routingSession.IsNavigable(), + m_routingSession.GetDistanceToNextTurn(), m_routingSession.GetCurrentSpeedLimit(), + routeMatchingInfo); } void RoutingManager::DeleteSavedRoutePoints() diff --git a/libs/routing/routing_session.cpp b/libs/routing/routing_session.cpp index 35bb5500b..006d30722 100644 --- a/libs/routing/routing_session.cpp +++ b/libs/routing/routing_session.cpp @@ -363,6 +363,32 @@ void GetFullRoadName(RouteSegment::RoadNameInfo & road, std::string & name) } } +double RoutingSession::GetDistanceToNextTurn() const +{ + if (!m_route->IsValid()) + return -1; + + double distanceToTurnMeters = 0.; + turns::TurnItem turn; + m_route->GetNearestTurn(distanceToTurnMeters, turn); + return distanceToTurnMeters; +} + +double RoutingSession::GetCurrentSpeedLimit() const +{ + if (!m_route->IsValid()) + return -1; + + SpeedInUnits speedLimit; + m_route->GetCurrentSpeedLimit(speedLimit); + if (speedLimit.IsNumeric()) + return measurement_utils::KmphToMps(speedLimit.GetSpeedKmPH()); + else if (speedLimit.GetSpeed() == kNoneMaxSpeed) + return 0; + else + return -1.0; +} + void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const { CHECK_THREAD_CHECKER(m_threadChecker, ()); @@ -392,14 +418,7 @@ void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const info.m_distToTurn = platform::Distance::CreateFormatted(distanceToTurnMeters); info.m_turn = turn.m_turn; - SpeedInUnits speedLimit; - m_route->GetCurrentSpeedLimit(speedLimit); - if (speedLimit.IsNumeric()) - info.m_speedLimitMps = measurement_utils::KmphToMps(speedLimit.GetSpeedKmPH()); - else if (speedLimit.GetSpeed() == kNoneMaxSpeed) - info.m_speedLimitMps = 0; - else - info.m_speedLimitMps = -1.0; + info.m_speedLimitMps = GetCurrentSpeedLimit(); // The turn after the next one. if (m_routingSettings.m_showTurnAfterNext) diff --git a/libs/routing/routing_session.hpp b/libs/routing/routing_session.hpp index 555c717cd..990b3492b 100644 --- a/libs/routing/routing_session.hpp +++ b/libs/routing/routing_session.hpp @@ -100,6 +100,8 @@ public: SessionState OnLocationPositionChanged(location::GpsInfo const & info); void GetRouteFollowingInfo(FollowingInfo & info) const; + double GetDistanceToNextTurn() const; + double GetCurrentSpeedLimit() const; bool MatchLocationToRoute(location::GpsInfo & location, location::RouteMatchingInfo & routeMatchingInfo); void MatchLocationToRoadGraph(location::GpsInfo & location);