From 5e1a5836674412819fa8ca0345515adeea4b7683 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Tue, 5 Mar 2019 19:15:06 +0300 Subject: [PATCH] Restore map position after tracking of selected object. --- drape_frontend/drape_engine.cpp | 2 +- drape_frontend/frontend_renderer.cpp | 96 +++++++++++++++++++--------- drape_frontend/frontend_renderer.hpp | 18 ++++++ drape_frontend/user_event_stream.cpp | 18 ++++-- drape_frontend/user_event_stream.hpp | 7 +- map/routing_manager.cpp | 2 +- 6 files changed, 102 insertions(+), 41 deletions(-) diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 19779b6a2b..7de05e166d 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -199,7 +199,7 @@ void DrapeEngine::SetModelViewRect(m2::RectD const & rect, bool applyRotation, i void DrapeEngine::SetModelViewAnyRect(m2::AnyRectD const & rect, bool isAnim) { - PostUserEvent(make_unique_dp(rect, isAnim)); + PostUserEvent(make_unique_dp(rect, isAnim, true /* fitInViewport */)); } void DrapeEngine::ClearUserMarksGroup(kml::MarkGroupId groupId) diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 97d300a941..9f686e521a 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -1244,20 +1244,33 @@ void FrontendRenderer::ProcessSelection(ref_ptr msg) if (msg->IsDismiss()) { m_selectionShape->Hide(); + if (!m_myPositionController->IsModeChangeViewport() && m_selectionTrackInfo.is_initialized()) + { + AddUserEvent(make_unique_dp(m_selectionTrackInfo.get().m_startRect, true /* isAnim */, + false /* fitInViewport */)); + } + m_selectionTrackInfo.reset(); } else { double offsetZ = 0.0; - if (m_userEventStream.GetCurrentScreen().isPerspective()) + auto const & modelView = m_userEventStream.GetCurrentScreen(); + if (modelView.isPerspective()) { dp::TOverlayContainer selectResult; if (m_overlayTree->IsNeedUpdate()) - BuildOverlayTree(m_userEventStream.GetCurrentScreen()); + BuildOverlayTree(modelView); m_overlayTree->Select(msg->GetPosition(), selectResult); for (ref_ptr handle : selectResult) offsetZ = max(offsetZ, handle->GetPivotZ()); } m_selectionShape->Show(msg->GetSelectedObject(), msg->GetPosition(), offsetZ, msg->IsAnim()); + if (!m_myPositionController->IsModeChangeViewport()) + { + m2::PointD startPosition; + m_selectionShape->IsVisible(modelView, startPosition); + m_selectionTrackInfo = SelectionTrackInfo(modelView.GlobalRect(), startPosition); + } } } @@ -1991,13 +2004,15 @@ void FrontendRenderer::OnTouchMapAction(TouchEvent::ETouchType touchType) // the completion of touch actions. It helps to prevent the creation of redundant checks. auto const blockTimer = (touchType == TouchEvent::TOUCH_DOWN || touchType == TouchEvent::TOUCH_MOVE); m_myPositionController->ResetRoutingNotFollowTimer(blockTimer); + m_selectionTrackInfo.reset(); } + bool FrontendRenderer::OnNewVisibleViewport(m2::RectD const & oldViewport, m2::RectD const & newViewport, m2::PointD & gOffset) { gOffset = m2::PointD(0, 0); if (m_myPositionController->IsModeChangeViewport() || m_selectionShape == nullptr || - oldViewport == newViewport) + oldViewport == newViewport || !m_selectionTrackInfo.is_initialized()) { return false; } @@ -2009,43 +2024,62 @@ bool FrontendRenderer::OnNewVisibleViewport(m2::RectD const & oldViewport, m2::PointD pos; m2::PointD targetPos; - if (m_selectionShape->IsVisible(screen, pos) && - m_selectionShape->IsVisible(targetScreen, targetPos)) + if (!m_selectionShape->IsVisible(screen, pos) || !m_selectionShape->IsVisible(targetScreen, targetPos)) + return false; + + m2::RectD rect(pos, pos); + m2::RectD targetRect(targetPos, targetPos); + + if (m_overlayTree->IsNeedUpdate()) + BuildOverlayTree(screen); + + if (!(m_selectionShape->GetSelectedObject() == SelectionShape::OBJECT_POI && + m_overlayTree->GetSelectedFeatureRect(screen, rect) && + m_overlayTree->GetSelectedFeatureRect(targetScreen, targetRect))) { - m2::RectD rect(pos, pos); - m2::RectD targetRect(targetPos, targetPos); + double const r = m_selectionShape->GetRadius(); + rect.Inflate(r, r); + targetRect.Inflate(r, r); + } - if (m_overlayTree->IsNeedUpdate()) - BuildOverlayTree(screen); + double const kOffset = 50 * VisualParams::Instance().GetVisualScale(); + rect.Inflate(kOffset, kOffset); + targetRect.Inflate(kOffset, kOffset); - if (!(m_selectionShape->GetSelectedObject() == SelectionShape::OBJECT_POI && - m_overlayTree->GetSelectedFeatureRect(screen, rect) && - m_overlayTree->GetSelectedFeatureRect(targetScreen, targetRect))) + if (newViewport.SizeX() < rect.SizeX() || newViewport.SizeY() < rect.SizeY()) + return false; + + m2::PointD pOffset(0.0, 0.0); + if ((oldViewport.IsIntersect(targetRect) && !newViewport.IsRectInside(rect)) || + (newViewport.IsRectInside(rect) && m_selectionTrackInfo.get().m_snapSides != m2::PointI::Zero())) + { + // In case the rect of the selection is [partly] hidden, scroll the map to keep it visible. + // In case the rect of the selection is visible after the map scrolling, + // try to rollback part of that scrolling to return the map to its original position. + if (rect.minX() < newViewport.minX() || m_selectionTrackInfo.get().m_snapSides.x < 0) { - double const r = m_selectionShape->GetRadius(); - rect.Inflate(r, r); - targetRect.Inflate(r, r); + pOffset.x = std::max(m_selectionTrackInfo.get().m_startPos.x - pos.x, newViewport.minX() - rect.minX()); + m_selectionTrackInfo.get().m_snapSides.x = -1; + } + else if (rect.maxX() > newViewport.maxX() || m_selectionTrackInfo.get().m_snapSides.x > 0) + { + pOffset.x = std::min(m_selectionTrackInfo.get().m_startPos.x - pos.x, newViewport.maxX() - rect.maxX()); + m_selectionTrackInfo.get().m_snapSides.x = 1; } - if (oldViewport.IsIntersect(targetRect) && !newViewport.IsRectInside(rect)) + if (rect.minY() < newViewport.minY() || m_selectionTrackInfo.get().m_snapSides.y < 0) { - double const kOffset = 50 * VisualParams::Instance().GetVisualScale(); - m2::PointD pOffset(0.0, 0.0); - if (rect.minX() < newViewport.minX()) - pOffset.x = newViewport.minX() - rect.minX() + kOffset; - else if (rect.maxX() > newViewport.maxX()) - pOffset.x = newViewport.maxX() - rect.maxX() - kOffset; - - if (rect.minY() < newViewport.minY()) - pOffset.y = newViewport.minY() - rect.minY() + kOffset; - else if (rect.maxY() > newViewport.maxY()) - pOffset.y = newViewport.maxY() - rect.maxY() - kOffset; - - gOffset = screen.PtoG(screen.P3dtoP(pos + pOffset)) - screen.PtoG(screen.P3dtoP(pos)); - return true; + pOffset.y = std::max(m_selectionTrackInfo.get().m_startPos.y - pos.y, newViewport.minY() - rect.minY()); + m_selectionTrackInfo.get().m_snapSides.y = -1; + } + else if (rect.maxY() > newViewport.maxY() || m_selectionTrackInfo.get().m_snapSides.y > 0) + { + pOffset.y = std::min(m_selectionTrackInfo.get().m_startPos.y - pos.y, newViewport.maxY() - rect.maxY()); + m_selectionTrackInfo.get().m_snapSides.y = 1; } } - return false; + gOffset = screen.PtoG(screen.P3dtoP(pos + pOffset)) - screen.PtoG(screen.P3dtoP(pos)); + return true; } TTilesCollection FrontendRenderer::ResolveTileKeys(ScreenBase const & screen) diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 479825c613..447d365ab3 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -39,6 +39,8 @@ #include #include +#include + namespace dp { class Framebuffer; @@ -268,7 +270,23 @@ private: drape_ptr m_guiRenderer; gui::TWidgetsLayoutInfo m_lastWidgetsLayout; drape_ptr m_myPositionController; + drape_ptr m_selectionShape; + struct SelectionTrackInfo + { + SelectionTrackInfo() = default; + + SelectionTrackInfo(m2::AnyRectD const & startRect, m2::PointD const & startPos) + : m_startRect(startRect) + , m_startPos(startPos) + {} + + m2::AnyRectD m_startRect; + m2::PointD m_startPos; + m2::PointI m_snapSides = m2::PointI::Zero(); + }; + boost::optional m_selectionTrackInfo; + drape_ptr m_routeRenderer; drape_ptr m_trafficRenderer; drape_ptr m_transitSchemeRenderer; diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index b67fc6407f..b62be4ea7d 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -362,7 +362,7 @@ bool UserEventStream::OnSetScale(ref_ptr scaleEvent) bool UserEventStream::OnSetAnyRect(ref_ptr anyRectEvent) { - return SetRect(anyRectEvent->GetRect(), anyRectEvent->IsAnim()); + return SetRect(anyRectEvent->GetRect(), anyRectEvent->IsAnim(), anyRectEvent->FitInViewport()); } bool UserEventStream::OnSetRect(ref_ptr rectEvent) @@ -455,16 +455,22 @@ bool UserEventStream::SetRect(m2::RectD rect, int zoom, bool applyRotation, bool CheckMinGlobalRect(rect, kDefault3dScale); CheckMinMaxVisibleScale(rect, zoom, kDefault3dScale); m2::AnyRectD targetRect = applyRotation ? ToRotated(m_navigator, rect) : m2::AnyRectD(rect); - return SetRect(targetRect, isAnim, parallelAnimCreator); + return SetRect(targetRect, isAnim, true /* fitInViewport */, parallelAnimCreator); } -bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim, +bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim, bool fitInViewport, TAnimationCreator const & parallelAnimCreator) { ScreenBase tmp = GetCurrentScreen(); - tmp.SetFromRects(rect, tmp.PixelRectIn3d()); - tmp.MatchGandP3d(rect.GlobalCenter(), tmp.PixelRectIn3d().Center()); - + if (fitInViewport) + { + tmp.SetFromRects(rect, tmp.PixelRectIn3d()); + tmp.MatchGandP3d(rect.GlobalCenter(), tmp.PixelRectIn3d().Center()); + } + else + { + tmp.SetFromRects(rect, tmp.PixelRect()); + } return SetScreen(tmp, isAnim, parallelAnimCreator); } diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 836c26cc73..ac83bd4c00 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -194,19 +194,22 @@ private: class SetAnyRectEvent : public UserEvent { public: - SetAnyRectEvent(m2::AnyRectD const & rect, bool isAnim) + SetAnyRectEvent(m2::AnyRectD const & rect, bool isAnim, bool fitInViewport) : m_rect(rect) , m_isAnim(isAnim) + , m_fitInViewport(fitInViewport) {} EventType GetType() const override { return UserEvent::EventType::SetAnyRect; } m2::AnyRectD const & GetRect() const { return m_rect; } bool IsAnim() const { return m_isAnim; } + bool FitInViewport() const { return m_fitInViewport; } private: m2::AnyRectD m_rect; // destination mercator rect bool m_isAnim; + bool m_fitInViewport; }; class FollowAndRotateEvent : public UserEvent @@ -408,7 +411,7 @@ private: bool SetAngle(double azimuth, TAnimationCreator const & parallelAnimCreator = nullptr); bool SetRect(m2::RectD rect, int zoom, bool applyRotation, bool isAnim, TAnimationCreator const & parallelAnimCreator = nullptr); - bool SetRect(m2::AnyRectD const & rect, bool isAnim, + bool SetRect(m2::AnyRectD const & rect, bool isAnim, bool fitInViewport, TAnimationCreator const & parallelAnimCreator = nullptr); bool SetScreen(ScreenBase const & screen, bool isAnim, diff --git a/map/routing_manager.cpp b/map/routing_manager.cpp index 886f048ad1..5b46665725 100644 --- a/map/routing_manager.cpp +++ b/map/routing_manager.cpp @@ -619,7 +619,7 @@ void RoutingManager::FollowRoute() m_transitReadManager->BlockTransitSchemeMode(true /* isBlocked */); - // Switching on the extrapolatior only for following mode in car and bicycle navigation. + // Switching on the extrapolator only for following mode in car and bicycle navigation. m_extrapolator.Enable(m_currentRouterType == RouterType::Vehicle || m_currentRouterType == RouterType::Bicycle); m_delegate.OnRouteFollow(m_currentRouterType);