From f799de450ae11f5f58d7fbd71c6676f1077e6f8b Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Fri, 9 Oct 2015 11:59:58 +0300 Subject: [PATCH] Improved animation in follow-and-rotate mode --- .../animation/model_view_animation.cpp | 26 ++++++----- .../animation/model_view_animation.hpp | 28 +++++++---- .../user_event_stream_tests.cpp | 1 + drape_frontend/frontend_renderer.cpp | 7 ++- drape_frontend/frontend_renderer.hpp | 1 + drape_frontend/kinetic_scroller.cpp | 2 + drape_frontend/my_position_controller.cpp | 6 +++ drape_frontend/my_position_controller.hpp | 1 + drape_frontend/navigator.cpp | 26 ++++++----- drape_frontend/navigator.hpp | 11 ++--- drape_frontend/user_event_stream.cpp | 46 ++++++++++++++----- drape_frontend/user_event_stream.hpp | 3 ++ 12 files changed, 109 insertions(+), 49 deletions(-) diff --git a/drape_frontend/animation/model_view_animation.cpp b/drape_frontend/animation/model_view_animation.cpp index e736d9c3fe..c4ab77cdf2 100644 --- a/drape_frontend/animation/model_view_animation.cpp +++ b/drape_frontend/animation/model_view_animation.cpp @@ -91,34 +91,38 @@ double ModelViewAnimation::GetScaleDuration(double startSize, double endSize) return CalcAnimSpeedDuration(endSize / startSize, pixelSpeed); } -FixedPointAnimation::FixedPointAnimation(m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, - double aDuration, double mDuration, double sDuration, - m2::PointD const & pixelPoint, m2::PointD const & globalPoint) +ScaleAnimation::ScaleAnimation(m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, + double aDuration, double mDuration, double sDuration, + m2::PointD const & globalPoint, m2::PointD const & pixelOffset) : ModelViewAnimation(startRect, endRect, aDuration, mDuration, sDuration) - , m_pixelPoint(pixelPoint) , m_globalPoint(globalPoint) + , m_pixelOffset(pixelOffset) { } -void FixedPointAnimation::ApplyFixedPoint(ScreenBase const & screen, m2::AnyRectD & rect) const +void ScaleAnimation::ApplyPixelOffset(ScreenBase const & screen, m2::AnyRectD & rect) const { ScreenBase s = screen; s.SetFromRect(rect); - m2::PointD const p = s.PtoG(m_pixelPoint); - rect.Offset(m_globalPoint - p); + + m2::PointD const pixelPoint = s.GtoP(m_globalPoint); + m2::PointD const newCenter = s.PtoG(pixelPoint + m_pixelOffset); + + + rect = m2::AnyRectD(newCenter, rect.Angle(), rect.GetLocalRect()); } -m2::AnyRectD FixedPointAnimation::GetCurrentRect(ScreenBase const & screen) const +m2::AnyRectD ScaleAnimation::GetCurrentRect(ScreenBase const & screen) const { m2::AnyRectD r = GetRect(GetElapsedTime()); - ApplyFixedPoint(screen, r); + ApplyPixelOffset(screen, r); return r; } -m2::AnyRectD FixedPointAnimation::GetTargetRect(ScreenBase const & screen) const +m2::AnyRectD ScaleAnimation::GetTargetRect(ScreenBase const & screen) const { m2::AnyRectD r = GetRect(GetDuration()); - ApplyFixedPoint(screen, r); + ApplyPixelOffset(screen, r); return r; } diff --git a/drape_frontend/animation/model_view_animation.hpp b/drape_frontend/animation/model_view_animation.hpp index 8af4753b76..01956fb2ac 100644 --- a/drape_frontend/animation/model_view_animation.hpp +++ b/drape_frontend/animation/model_view_animation.hpp @@ -9,11 +9,20 @@ namespace df { +enum class ModelViewAnimationType +{ + Default, + Scale, + FollowAndRotate, + KineticScroll +}; + class BaseModelViewAnimation : public BaseInterpolator { public: BaseModelViewAnimation(double duration, double delay = 0) : BaseInterpolator(duration, delay) {} + virtual ModelViewAnimationType GetType() const = 0; virtual m2::AnyRectD GetCurrentRect(ScreenBase const & screen) const = 0; virtual m2::AnyRectD GetTargetRect(ScreenBase const & screen) const = 0; }; @@ -30,6 +39,8 @@ public: /// sDuration - scaleDuration ModelViewAnimation(m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, double aDuration, double mDuration, double sDuration); + + ModelViewAnimationType GetType() const override { return ModelViewAnimationType::Default; } m2::AnyRectD GetCurrentRect(ScreenBase const & screen) const override; m2::AnyRectD GetTargetRect(ScreenBase const & screen) const override; @@ -46,21 +57,21 @@ private: double m_scaleDuration; }; -class FixedPointAnimation : public ModelViewAnimation +class ScaleAnimation : public ModelViewAnimation { public: - /// This animation extends ModelViewAnimation by adding point which must be in certain - /// pixel position on the screen. - FixedPointAnimation(m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, - double aDuration, double mDuration, double sDuration, - m2::PointD const & pixelPoint, m2::PointD const & globalPoint); + ScaleAnimation(m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, + double aDuration, double mDuration, double sDuration, + m2::PointD const & globalPoint, m2::PointD const & pixelOffset); + + ModelViewAnimationType GetType() const override { return ModelViewAnimationType::Scale; } m2::AnyRectD GetCurrentRect(ScreenBase const & screen) const override; m2::AnyRectD GetTargetRect(ScreenBase const & screen) const override; private: - void ApplyFixedPoint(ScreenBase const & screen, m2::AnyRectD & rect) const; - m2::PointD m_pixelPoint; + void ApplyPixelOffset(ScreenBase const & screen, m2::AnyRectD & rect) const; m2::PointD m_globalPoint; + m2::PointD m_pixelOffset; }; class FollowAndRotateAnimation : public BaseModelViewAnimation @@ -70,6 +81,7 @@ public: double newCenterOffset, double oldCenterOffset, double azimuth, double duration); + ModelViewAnimationType GetType() const override { return ModelViewAnimationType::FollowAndRotate; } m2::AnyRectD GetCurrentRect(ScreenBase const & screen) const override; m2::AnyRectD GetTargetRect(ScreenBase const & screen) const override; diff --git a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp index 185c774ea5..ffe9d08327 100644 --- a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp +++ b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp @@ -33,6 +33,7 @@ public: void OnScaleStarted() override {} void CorrectScalePoint(m2::PointD & pt) const override {} void CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) const override {} + void CorrectGlobalScalePoint(m2::PointD & pt) const override {} void OnScaleEnded() override {} void AddUserEvent(df::TouchEvent const & event) diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 026f2e6979..0dddb671e8 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -731,6 +731,11 @@ void FrontendRenderer::CorrectScalePoint(m2::PointD & pt) const m_myPositionController->CorrectScalePoint(pt); } +void FrontendRenderer::CorrectGlobalScalePoint(m2::PointD & pt) const +{ + m_myPositionController->CorrectGlobalScalePoint(pt); +} + void FrontendRenderer::CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) const { m_myPositionController->CorrectScalePoint(pt1, pt2); @@ -911,7 +916,7 @@ void FrontendRenderer::ChangeModelView(m2::PointD const & userPos, double azimut { ScreenBase const & screen = m_userEventStream.GetCurrentScreen(); m2::RectD const & pixelRect = screen.PixelRect(); - m2::AnyRectD targetRect = m_userEventStream.GetTargetRect(); + m2::AnyRectD targetRect = m_userEventStream.GetCurrentScreen().GlobalRect(); auto calculateOffset = [&pixelRect, &targetRect](m2::PointD const & pixelPos) { diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 8a979bc2dc..6aaa1ed9ce 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -151,6 +151,7 @@ private: void OnRotated() override; void CorrectScalePoint(m2::PointD & pt) const override; void CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) const override; + void CorrectGlobalScalePoint(m2::PointD & pt) const override; void OnScaleEnded() override; class Routine : public threads::IRoutine diff --git a/drape_frontend/kinetic_scroller.cpp b/drape_frontend/kinetic_scroller.cpp index dd4742a2e3..efa75b49a3 100644 --- a/drape_frontend/kinetic_scroller.cpp +++ b/drape_frontend/kinetic_scroller.cpp @@ -40,6 +40,8 @@ public: { } + ModelViewAnimationType GetType() const override { return ModelViewAnimationType::KineticScroll; } + m2::AnyRectD GetCurrentRect(ScreenBase const & screen) const override { // current position = target position - amplutide * e ^ (elapsed / duration) diff --git a/drape_frontend/my_position_controller.cpp b/drape_frontend/my_position_controller.cpp index eb2d563653..361de4674d 100644 --- a/drape_frontend/my_position_controller.cpp +++ b/drape_frontend/my_position_controller.cpp @@ -178,6 +178,12 @@ void MyPositionController::CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) } } +void MyPositionController::CorrectGlobalScalePoint(m2::PointD & pt) const +{ + if (IsModeChangeViewport()) + pt = m_position; +} + void MyPositionController::ScaleEnded() { SetModeInfo(ResetModeBit(m_modeInfo, BlockAnimation)); diff --git a/drape_frontend/my_position_controller.hpp b/drape_frontend/my_position_controller.hpp index 28feda0a78..2fa07ef0cc 100644 --- a/drape_frontend/my_position_controller.hpp +++ b/drape_frontend/my_position_controller.hpp @@ -58,6 +58,7 @@ public: void Rotated(); void CorrectScalePoint(m2::PointD & pt) const; void CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) const; + void CorrectGlobalScalePoint(m2::PointD & pt) const; void ScaleEnded(); void SetRenderShape(drape_ptr && shape); diff --git a/drape_frontend/navigator.cpp b/drape_frontend/navigator.cpp index f07f5c0738..9d7d9917f1 100644 --- a/drape_frontend/navigator.cpp +++ b/drape_frontend/navigator.cpp @@ -372,10 +372,15 @@ namespace } void Navigator::Scale(m2::PointD const & pt, double factor) +{ + CalculateScale(pt, factor, m_Screen); +} + +void Navigator::CalculateScale(m2::PointD const & pt, double factor, ScreenBase & screen) { m2::PointD startPt, endPt; - CalcScalePoints(pt, factor, m_Screen.PixelRect(), startPt, endPt); - ScaleImpl(pt, endPt, pt, startPt, factor > 1, false); + CalcScalePoints(pt, factor, screen.PixelRect(), startPt, endPt); + ScaleImpl(pt, endPt, pt, startPt, factor > 1, false, screen); } bool Navigator::CheckMinScale(ScreenBase const & screen) const @@ -407,13 +412,13 @@ bool Navigator::CheckBorders(ScreenBase const & screen) const bool Navigator::ScaleImpl(m2::PointD const & newPt1, m2::PointD const & newPt2, m2::PointD const & oldPt1, m2::PointD const & oldPt2, - bool skipMinScaleAndBordersCheck, - bool doRotateScreen) + bool skipMinScaleAndBordersCheck, bool doRotateScreen, + ScreenBase & screen) { - math::Matrix newM = m_Screen.GtoPMatrix() * ScreenBase::CalcTransform(oldPt1, oldPt2, newPt1, newPt2); + math::Matrix newM = screen.GtoPMatrix() * ScreenBase::CalcTransform(oldPt1, oldPt2, newPt1, newPt2); - double oldAngle = m_Screen.GetAngle(); - ScreenBase tmp = m_Screen; + double oldAngle = screen.GetAngle(); + ScreenBase tmp = screen; tmp.SetGtoPMatrix(newM); if (!doRotateScreen) tmp.Rotate(-(tmp.GetAngle() - oldAngle)); @@ -438,7 +443,7 @@ bool Navigator::ScaleImpl(m2::PointD const & newPt1, m2::PointD const & newPt2, if (!CheckBorders(tmp)) tmp = ScaleInto(tmp, worldR); - m_Screen = tmp; + screen = tmp; return true; } @@ -481,10 +486,9 @@ void Navigator::DoScale(m2::PointD const & pt1, m2::PointD const & pt2) m_Screen = PrevScreen; - if (!ScaleImpl(pt1, pt2, - m_LastPt1, m_LastPt2, + if (!ScaleImpl(pt1, pt2, m_LastPt1, m_LastPt2, pt1.Length(pt2) > m_LastPt1.Length(m_LastPt2), - m_IsRotatingDuringScale)) + m_IsRotatingDuringScale, m_Screen)) { m_Screen = PrevScreen; } diff --git a/drape_frontend/navigator.hpp b/drape_frontend/navigator.hpp index 154ec7f53b..12aa815016 100644 --- a/drape_frontend/navigator.hpp +++ b/drape_frontend/navigator.hpp @@ -44,6 +44,7 @@ public: bool IsRotatingDuringScale() const; void Scale(m2::PointD const & pt, double factor); + void CalculateScale(m2::PointD const & pt, double factor, ScreenBase & screen); bool InAction() const; private: @@ -77,12 +78,10 @@ private: // Do screen rotates during the two fingers scaling. bool m_IsRotatingDuringScale; // Used in DoScale and ScaleByPoint - bool ScaleImpl(m2::PointD const & newPt1, - m2::PointD const & newPt2, - m2::PointD const & oldPt1, - m2::PointD const & oldPt2, - bool skipMinScaleAndBordersCheck, - bool doRotateScreen); + bool ScaleImpl(m2::PointD const & newPt1, m2::PointD const & newPt2, + m2::PointD const & oldPt1, m2::PointD const & oldPt2, + bool skipMinScaleAndBordersCheck, bool doRotateScreen, + ScreenBase & screen); }; m2::AnyRectD ToRotated(Navigator const & navigator, m2::RectD const & rect); diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index b8fd5e0d02..895c90b47a 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -182,7 +182,10 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & } if (breakAnim) + { m_animation.reset(); + modelViewChange = true; + } if (m_animation != nullptr) { @@ -217,24 +220,25 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, if (isAnim) { - m2::AnyRectD rect = GetTargetRect(); - m2::PointD currentCenter = rect.GlobalZero(); - m2::PointD const glbScaleCenter = m_navigator.PtoG(scaleCenter); - m2::PointD const centerMove = (currentCenter - glbScaleCenter) / factor; + // Reset current animation if there is any. + ResetCurrentAnimation(); - currentCenter = glbScaleCenter + centerMove; + m2::PointD glbScaleCenter = m_navigator.PtoG(scaleCenter); + if (m_listener) + m_listener->CorrectGlobalScalePoint(glbScaleCenter); - m2::RectD sizeRect = rect.GetLocalRect(); - sizeRect.Scale(1.0 / factor); + ScreenBase screen = GetCurrentScreen(); + m_navigator.CalculateScale(scaleCenter, factor, screen); + m2::PointD offset = GetCurrentScreen().PixelRect().Center() - scaleCenter; - auto creator = [this, &scaleCenter, &glbScaleCenter](m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, - double aDuration, double mDuration, double sDuration) + auto creator = [this, &glbScaleCenter, &offset](m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, + double aDuration, double mDuration, double sDuration) { - m_animation.reset(new FixedPointAnimation(startRect, endRect, aDuration, mDuration, - sDuration, scaleCenter, glbScaleCenter)); + m_animation.reset(new ScaleAnimation(startRect, endRect, aDuration, mDuration, + sDuration, glbScaleCenter, offset)); }; - return SetRect(m2::AnyRectD(currentCenter, rect.Angle(), sizeRect), true, creator); + return SetRect(screen.GlobalRect(), true, creator); } m_navigator.Scale(scaleCenter, factor); @@ -262,6 +266,9 @@ bool UserEventStream::SetRect(m2::RectD rect, int zoom, bool applyRotation, bool bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) { + // Reset current animation if there is any. + ResetCurrentAnimation(); + return SetRect(rect, isAnim, [this](m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, double aDuration, double mDuration, double sDuration) { @@ -297,6 +304,9 @@ bool UserEventStream::SetFollowAndRotate(m2::AnyRectD const & rect, m2::PointD c { if (isAnim) { + // Reset current animation if there is any. + ResetCurrentAnimation(); + ScreenBase const & screen = m_navigator.Screen(); m2::AnyRectD const startRect = GetCurrentRect(); double const angleDuration = ModelViewAnimation::GetRotateDuration(startRect.Angle().val(), azimuth); @@ -314,6 +324,16 @@ bool UserEventStream::SetFollowAndRotate(m2::AnyRectD const & rect, m2::PointD c return true; } +void UserEventStream::ResetCurrentAnimation() +{ + if (m_animation != nullptr) + { + m2::AnyRectD rect = m_animation->GetCurrentRect(GetCurrentScreen()); + m_navigator.SetFromRect(rect); + m_animation.reset(); + } +} + m2::AnyRectD UserEventStream::GetCurrentRect() const { return m_navigator.Screen().GlobalRect(); @@ -374,7 +394,9 @@ bool UserEventStream::TouchDown(array const & touches) m_startDragOrg = touches[0].m_location; } else + { isMapTouch = false; + } } } } diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 311f475944..8ac7c9f997 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -214,6 +214,7 @@ public: virtual void OnScaleStarted() = 0; virtual void OnRotated() = 0; virtual void CorrectScalePoint(m2::PointD & pt) const = 0; + virtual void CorrectGlobalScalePoint(m2::PointD & pt) const = 0; virtual void CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) const = 0; virtual void OnScaleEnded() = 0; }; @@ -287,6 +288,8 @@ private: void EndFilter(Touch const & t); void CancelFilter(Touch const & t); + void ResetCurrentAnimation(); + private: TIsCountryLoaded m_isCountryLoaded;