diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index bcc2bbdf41..5a0dab7b7c 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -384,7 +384,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) { m_myPositionController->DeactivateRouting(); if (m_enable3dInNavigation) - DiscardPerspective(); + DisablePerspective(); } break; } @@ -404,7 +404,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) { m_myPositionController->DeactivateRouting(); if (m_enable3dInNavigation) - DiscardPerspective(); + DisablePerspective(); break; } @@ -861,45 +861,33 @@ int FrontendRenderer::GetCurrentZoomLevelForData() const return (m_currentZoomLevel <= upperScale ? m_currentZoomLevel : upperScale); } -void FrontendRenderer::DiscardPerspective(ScreenBase const & screen) +void FrontendRenderer::DisablePerspective() { - if (!screen.isPerspective()) - return; - - m_discardedFOV = screen.GetAngleFOV(); - m_discardedAngle = screen.GetRotationAngle(); + m_perspectiveDiscarded = false; AddUserEvent(DisablePerspectiveEvent()); } -void FrontendRenderer::DiscardPerspective() +void FrontendRenderer::CheckMinAllowableIn3dScale() { - m_discardedFOV = 0.0; - m_discardedAngle = 0.0; - AddUserEvent(DisablePerspectiveEvent()); -} - -void FrontendRenderer::RecoverPerspective() -{ - if (m_discardedFOV <= 0.0) + if (!m_enable3dInNavigation || + m_userEventStream.IsInPerspectiveAnimation()) return; - AddUserEvent(EnablePerspectiveEvent(m_discardedAngle, m_discardedFOV, - true /* animated */, true /* immediately start */)); - m_discardedFOV = 0.0; - m_discardedAngle = 0.0; + bool const switchTo2d = m_currentZoomLevel < scales::GetMinAllowableIn3dScale(); + + if ((!switchTo2d && !m_perspectiveDiscarded) || + (switchTo2d && !m_userEventStream.GetCurrentScreen().isPerspective())) + return; + + m_perspectiveDiscarded = switchTo2d; + AddUserEvent(SwitchViewModeEvent(switchTo2d)); } void FrontendRenderer::ResolveZoomLevel(ScreenBase const & screen) { m_currentZoomLevel = GetDrawTileScale(screen); - if (m_enable3dInNavigation && !m_userEventStream.IsInPerspectiveAnimation()) - { - if (m_currentZoomLevel < m_min3dZoomLevel) - DiscardPerspective(screen); - else - RecoverPerspective(); - } + CheckMinAllowableIn3dScale(); } void FrontendRenderer::OnTap(m2::PointD const & pt, bool isLongTap) diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 172facfad1..58d4ca548b 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -152,10 +152,9 @@ private: int GetCurrentZoomLevel() const; int GetCurrentZoomLevelForData() const; void ResolveZoomLevel(ScreenBase const & screen); + void CheckMinAllowableIn3dScale(); - void DiscardPerspective(ScreenBase const & screen); - void DiscardPerspective(); - void RecoverPerspective(); + void DisablePerspective(); void OnTap(m2::PointD const & pt, bool isLong) override; void OnForceTap(m2::PointD const & pt) override; @@ -241,11 +240,8 @@ private: unique_ptr m_tileTree; int m_currentZoomLevel = -1; - // TODO: Calculate min zoom level based on the device capabilities. - int const m_min3dZoomLevel = 17; - double m_discardedFOV = 0.0; - double m_discardedAngle = 0.0; + bool m_perspectiveDiscarded = false; ref_ptr m_requestedTiles; uint64_t m_maxGeneration; diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index fa31e1df73..c8c8e8acfb 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -1,6 +1,8 @@ #include "drape_frontend/user_event_stream.hpp" #include "drape_frontend/visual_params.hpp" +#include "indexer/scales.hpp" + #include "base/logging.hpp" #include "base/macros.hpp" @@ -188,29 +190,30 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & TouchCancel(m_touches); break; case UserEvent::EVENT_ENABLE_PERSPECTIVE: - if (e.m_enable3dMode.m_isAnim) - { - if (e.m_enable3dMode.m_immediatelyStart) - { - SetEnable3dModeAnimation(e.m_enable3dMode.m_rotationAngle); - m_navigator.Enable3dMode(0.0 /* current rotation angle */, - e.m_enable3dMode.m_rotationAngle, - e.m_enable3dMode.m_angleFOV); - viewportChanged = true; - } + if (!e.m_enable3dMode.m_immediatelyStart) m_pendingEvent.reset(new UserEvent(e.m_enable3dMode)); - } else - { - m_navigator.Enable3dMode(e.m_enable3dMode.m_rotationAngle, - e.m_enable3dMode.m_rotationAngle, - e.m_enable3dMode.m_angleFOV); - viewportChanged = true; - } + SetEnable3dMode(e.m_enable3dMode.m_rotationAngle, e.m_enable3dMode.m_angleFOV, + e.m_enable3dMode.m_isAnim, viewportChanged); + m_discardedFOV = m_discardedAngle = 0.0; break; case UserEvent::EVENT_DISABLE_PERSPECTIVE: if (m_navigator.Screen().isPerspective()) SetDisable3dModeAnimation(); + m_discardedFOV = m_discardedAngle = 0.0; + break; + case UserEvent::EVENT_SWITCH_VIEW_MODE: + if (e.m_switchViewMode.m_to2d) + { + m_discardedFOV = m_navigator.Screen().GetAngleFOV(); + m_discardedAngle = m_navigator.Screen().GetRotationAngle(); + SetDisable3dModeAnimation(); + } + else if (m_discardedFOV > 0.0) + { + SetEnable3dMode(m_discardedAngle, m_discardedFOV, true /* isAnim */, viewportChanged); + m_discardedFOV = m_discardedAngle = 0.0; + } break; default: ASSERT(false, ()); @@ -234,11 +237,10 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & if (m_animation->GetType() == ModelViewAnimationType::FollowAndRotate && m_pendingEvent != nullptr && m_pendingEvent->m_type == UserEvent::EVENT_ENABLE_PERSPECTIVE) { - SetEnable3dModeAnimation(m_pendingEvent->m_enable3dMode.m_rotationAngle); - m_navigator.Enable3dMode(0.0 /* current rotation angle */, - m_pendingEvent->m_enable3dMode.m_rotationAngle, - m_pendingEvent->m_enable3dMode.m_angleFOV); - viewportChanged = true; + SetEnable3dMode(m_pendingEvent->m_enable3dMode.m_rotationAngle, + m_pendingEvent->m_enable3dMode.m_angleFOV, + m_pendingEvent->m_enable3dMode.m_isAnim, + viewportChanged); m_pendingEvent.reset(); } @@ -325,7 +327,17 @@ bool UserEventStream::SetCenter(m2::PointD const & center, int zoom, bool isAnim ang::AngleD angle; m2::RectD localRect; - ScreenBase const &screen = GetCurrentScreen(); + ScreenBase const & currentScreen = GetCurrentScreen(); + + bool const finishIn3d = m_discardedFOV > 0.0 && zoom >= scales::GetMinAllowableIn3dScale(); + bool const finishIn2d = currentScreen.isPerspective() && zoom < scales::GetMinAllowableIn3dScale(); + + ScreenBase screen = currentScreen; + if (finishIn3d) + screen.ApplyPerspective(m_discardedAngle, m_discardedAngle, m_discardedFOV); + else if (finishIn2d) + screen.ResetPerspective(); + double const scale3d = screen.PixelRect().SizeX() / screen.PixelRectIn3d().SizeX(); if (zoom == -1) { @@ -357,6 +369,18 @@ bool UserEventStream::SetCenter(m2::PointD const & center, int zoom, bool isAnim targetCenter = targetCenter.Move(centerOffset3d, angle.cos(), -angle.sin()); } + if (finishIn2d || finishIn3d) + { + double const scaleToCurrent = + finishIn2d ? currentScreen.PixelRect().SizeX() / currentScreen.PixelRectIn3d().SizeX() + : 1.0 / scale3d; + + double const currentGSizeY = localRect.SizeY() * scaleToCurrent; + targetCenter = targetCenter.Move((currentGSizeY - localRect.SizeY()) / 2.0, + angle.cos(), -angle.sin()); + localRect.Scale(scaleToCurrent); + } + return SetRect(m2::AnyRectD(targetCenter, angle, localRect), isAnim); } @@ -458,20 +482,27 @@ bool UserEventStream::FilterEventWhile3dAnimation(UserEvent::EEventType type) co type != UserEvent::EVENT_SET_RECT; } -void UserEventStream::SetEnable3dModeAnimation(double maxRotationAngle) +void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, bool isAnim, bool & viewportChanged) { - ResetCurrentAnimation(); + bool const finishAnimation = m_animation != nullptr && m_animation->GetType() == ModelViewAnimationType::Default; + ResetCurrentAnimation(finishAnimation); - double const startAngle = 0.0; - double const endAngle = maxRotationAngle; - double const rotateDuration = PerspectiveAnimation::GetRotateDuration(startAngle, endAngle); - m_perspectiveAnimation.reset( - new PerspectiveAnimation(rotateDuration, 0.0 /* delay */, startAngle, endAngle)); + double const startAngle = isAnim ? 0.0 : maxRotationAngle; + if (isAnim) + { + double const endAngle = maxRotationAngle; + double const rotateDuration = PerspectiveAnimation::GetRotateDuration(startAngle, endAngle); + m_perspectiveAnimation.reset( + new PerspectiveAnimation(rotateDuration, 0.0 /* delay */, startAngle, endAngle)); + } + m_navigator.Enable3dMode(startAngle, maxRotationAngle, angleFOV); + viewportChanged = true; } void UserEventStream::SetDisable3dModeAnimation() { - ResetCurrentAnimation(); + bool const finishAnimation = m_animation != nullptr && m_animation->GetType() == ModelViewAnimationType::Default; + ResetCurrentAnimation(finishAnimation); double const startAngle = m_navigator.Screen().GetRotationAngle(); double const endAngle = 0.0; diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 2f16472774..62e0db2614 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -166,6 +166,13 @@ struct DisablePerspectiveEvent DisablePerspectiveEvent() {} }; +struct SwitchViewModeEvent +{ + SwitchViewModeEvent(bool to2d): m_to2d(to2d) {} + + bool m_to2d; +}; + struct RotateEvent { RotateEvent(double targetAzimut) : m_targetAzimut(targetAzimut) {} @@ -194,7 +201,8 @@ struct UserEvent EVENT_ROTATE, EVENT_FOLLOW_AND_ROTATE, EVENT_ENABLE_PERSPECTIVE, - EVENT_DISABLE_PERSPECTIVE + EVENT_DISABLE_PERSPECTIVE, + EVENT_SWITCH_VIEW_MODE }; UserEvent(TouchEvent const & e) : m_type(EVENT_TOUCH) { m_touchEvent = e; } @@ -207,6 +215,7 @@ struct UserEvent UserEvent(FollowAndRotateEvent const & e) : m_type(EVENT_FOLLOW_AND_ROTATE) { m_followAndRotate = e; } UserEvent(EnablePerspectiveEvent const & e) : m_type(EVENT_ENABLE_PERSPECTIVE) { m_enable3dMode = e; } UserEvent(DisablePerspectiveEvent const & e) : m_type(EVENT_DISABLE_PERSPECTIVE) { m_disable3dMode = e; } + UserEvent(SwitchViewModeEvent const & e) : m_type(EVENT_SWITCH_VIEW_MODE) { m_switchViewMode = e; } EEventType m_type; union @@ -221,6 +230,7 @@ struct UserEvent FollowAndRotateEvent m_followAndRotate; EnablePerspectiveEvent m_enable3dMode; DisablePerspectiveEvent m_disable3dMode; + SwitchViewModeEvent m_switchViewMode; }; }; @@ -291,7 +301,7 @@ private: double azimuth, int preferredZoomLevel, bool isAnim); bool FilterEventWhile3dAnimation(UserEvent::EEventType type) const; - void SetEnable3dModeAnimation(double maxRotationAngle); + void SetEnable3dMode(double maxRotationAngle, double angleFOV, bool isAnim, bool & viewportChanged); void SetDisable3dModeAnimation(); m2::AnyRectD GetCurrentRect() const; @@ -352,8 +362,12 @@ private: array m_touches; unique_ptr m_animation; + unique_ptr m_perspectiveAnimation; unique_ptr m_pendingEvent; + double m_discardedFOV = 0.0; + double m_discardedAngle = 0.0; + ref_ptr m_listener; #ifdef DEBUG diff --git a/indexer/scales.hpp b/indexer/scales.hpp index d9bd82a0b7..6844c2aaaf 100644 --- a/indexer/scales.hpp +++ b/indexer/scales.hpp @@ -20,6 +20,12 @@ namespace scales inline int GetNavigationScale() { return UPPER_STYLE_SCALE - 4; } /// Default pedestrian navigation mode scale inline int GetPedestrianNavigationScale() { return UPPER_STYLE_SCALE - 1; } + /// Default navigation 3d mode scale + inline int GetNavigation3dScale() { return UPPER_STYLE_SCALE - 2; } + /// Default pedestrian navigation 3d mode scale + inline int GetPedestrianNavigation3dScale() { return UPPER_STYLE_SCALE; } + /// Minimal allowable scale in 3d mode + inline int GetMinAllowableIn3dScale() { return 17; } double GetScaleLevelD(double ratio); double GetScaleLevelD(m2::RectD const & r); diff --git a/map/framework.cpp b/map/framework.cpp index 40fb4b125f..7dca4dec93 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1057,7 +1057,10 @@ void Framework::ShowSearchResult(search::Result const & res) } StopLocationFollow(); - ShowRect(df::GetRectForDrawScale(scale, center)); + if (m_currentModelView.isPerspective()) + CallDrapeFunction(bind(&df::DrapeEngine::SetModelViewCenter, _1, center, scale, true)); + else + ShowRect(df::GetRectForDrawScale(scale, center)); search::AddressInfo info; info.MakeFrom(res); @@ -1115,10 +1118,18 @@ size_t Framework::ShowAllSearchResults(search::Results const & results) if (minInd != -1) { m2::PointD const pt = results.GetResult(minInd).GetFeatureCenter(); + + if (m_currentModelView.isPerspective()) + { + StopLocationFollow(); + SetViewportCenter(pt); + return count; + } + if (!viewport.IsPointInside(pt)) { viewport.SetSizesToIncludePoint(pt); - CallDrapeFunction(bind(&df::DrapeEngine::StopLocationFollow, _1)); + StopLocationFollow(); } } @@ -1846,11 +1857,10 @@ void Framework::FollowRoute() { ASSERT(m_drapeEngine != nullptr, ()); - int const scale = (m_currentRouterType == RouterType::Pedestrian) ? - scales::GetUpperComfortScale() : - scales::GetNavigationScale(); - int const scale3d = (m_currentRouterType == RouterType::Pedestrian) ? scale + 1 : scale + 2; - + int const scale = (m_currentRouterType == RouterType::Pedestrian) ? scales::GetUpperComfortScale() + : scales::GetNavigationScale(); + int const scale3d = (m_currentRouterType == RouterType::Pedestrian) ? scales::GetPedestrianNavigation3dScale() + : scales::GetNavigation3dScale(); m_drapeEngine->FollowRoute(scale, scale3d, kRotationAngle, kAngleFOV); m_drapeEngine->SetRoutePoint(m2::PointD(), true /* isStart */, false /* isValid */); }