From d1ec2d1e323a855bd3a4ced6224111f4b6a9ec08 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Tue, 8 Sep 2015 11:00:06 +0300 Subject: [PATCH] Fixed zoom in follow-and-rotate mode --- .../animation/model_view_animation.cpp | 35 +++++- .../animation/model_view_animation.hpp | 25 +++- drape_frontend/kinetic_scroller.cpp | 6 +- drape_frontend/my_position_controller.cpp | 2 +- drape_frontend/navigator.cpp | 65 ----------- drape_frontend/user_event_stream.cpp | 108 +++++++++++------- drape_frontend/user_event_stream.hpp | 16 +-- 7 files changed, 133 insertions(+), 124 deletions(-) diff --git a/drape_frontend/animation/model_view_animation.cpp b/drape_frontend/animation/model_view_animation.cpp index 9df2bddcb7..f8b87c5b84 100644 --- a/drape_frontend/animation/model_view_animation.cpp +++ b/drape_frontend/animation/model_view_animation.cpp @@ -17,16 +17,47 @@ ModelViewAnimation::ModelViewAnimation(m2::AnyRectD const & startRect, m2::AnyRe { } -m2::AnyRectD ModelViewAnimation::GetCurrentRect() const +m2::AnyRectD ModelViewAnimation::GetCurrentRect(ScreenBase const & screen) const { return GetRect(GetElapsedTime()); } -m2::AnyRectD ModelViewAnimation::GetTargetRect() const +m2::AnyRectD ModelViewAnimation::GetTargetRect(ScreenBase const & screen) const { return GetRect(GetDuration()); } +FixedPointAnimation::FixedPointAnimation(m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, + double aDuration, double mDuration, double sDuration, + m2::PointD const & pixelPoint, m2::PointD const & globalPoint) + : ModelViewAnimation(startRect, endRect, aDuration, mDuration, sDuration) + , m_pixelPoint(pixelPoint) + , m_globalPoint(globalPoint) +{ +} + +void FixedPointAnimation::ApplyFixedPoint(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::AnyRectD FixedPointAnimation::GetCurrentRect(ScreenBase const & screen) const +{ + m2::AnyRectD r = GetRect(GetElapsedTime()); + ApplyFixedPoint(screen, r); + return r; +} + +m2::AnyRectD FixedPointAnimation::GetTargetRect(ScreenBase const & screen) const +{ + m2::AnyRectD r = GetRect(GetDuration()); + ApplyFixedPoint(screen, r); + return r; +} + namespace { diff --git a/drape_frontend/animation/model_view_animation.hpp b/drape_frontend/animation/model_view_animation.hpp index 2419c7e33d..63401ee933 100644 --- a/drape_frontend/animation/model_view_animation.hpp +++ b/drape_frontend/animation/model_view_animation.hpp @@ -14,8 +14,8 @@ class BaseModelViewAnimation : public BaseInterpolator public: BaseModelViewAnimation(double duration, double delay = 0) : BaseInterpolator(duration, delay) {} - virtual m2::AnyRectD GetCurrentRect() const = 0; - virtual m2::AnyRectD GetTargetRect() const = 0; + virtual m2::AnyRectD GetCurrentRect(ScreenBase const & screen) const = 0; + virtual m2::AnyRectD GetTargetRect(ScreenBase const & screen) const = 0; }; class ModelViewAnimation : public BaseModelViewAnimation @@ -30,10 +30,10 @@ public: /// sDuration - scaleDuration ModelViewAnimation(m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, double aDuration, double mDuration, double sDuration); - m2::AnyRectD GetCurrentRect() const override; - m2::AnyRectD GetTargetRect() const override; + m2::AnyRectD GetCurrentRect(ScreenBase const & screen) const override; + m2::AnyRectD GetTargetRect(ScreenBase const & screen) const override; -private: +protected: m2::AnyRectD GetRect(double elapsedTime) const; private: @@ -46,4 +46,19 @@ private: double m_scaleDuration; }; +class FixedPointAnimation : public ModelViewAnimation +{ +public: + FixedPointAnimation(m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, + double aDuration, double mDuration, double sDuration, + m2::PointD const & pixelPoint, m2::PointD const & globalPoint); + 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; + m2::PointD m_globalPoint; +}; + } // namespace df diff --git a/drape_frontend/kinetic_scroller.cpp b/drape_frontend/kinetic_scroller.cpp index cff46b7ddf..d3a7e1840a 100644 --- a/drape_frontend/kinetic_scroller.cpp +++ b/drape_frontend/kinetic_scroller.cpp @@ -39,16 +39,16 @@ public: { } - m2::AnyRectD GetCurrentRect() const override + m2::AnyRectD GetCurrentRect(ScreenBase const & screen) const override { // current position = target position - amplutide * e ^ (elapsed / duration) // we calculate current position not based on start position, but based on target position return m2::AnyRectD(m_targetCenter - m_direction * exp(-kKineticFadeoff * GetT()), m_angle, m_localRect); } - m2::AnyRectD GetTargetRect() const override + m2::AnyRectD GetTargetRect(ScreenBase const & screen) const override { - return GetCurrentRect(); + return GetCurrentRect(screen); } private: diff --git a/drape_frontend/my_position_controller.cpp b/drape_frontend/my_position_controller.cpp index 70946fda98..6cea13d8d8 100644 --- a/drape_frontend/my_position_controller.cpp +++ b/drape_frontend/my_position_controller.cpp @@ -172,7 +172,7 @@ void MyPositionController::CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) { if (IsModeChangeViewport()) { - m2::PointD const ptDiff = GetCurrentPixelBinding() - (pt1 + (pt2 - pt1) * 0.5); + m2::PointD const ptDiff = GetCurrentPixelBinding() - ((pt1 + pt2) * 0.5); pt1 += ptDiff; pt2 += ptDiff; } diff --git a/drape_frontend/navigator.cpp b/drape_frontend/navigator.cpp index c0d259cd15..8d01a2a750 100644 --- a/drape_frontend/navigator.cpp +++ b/drape_frontend/navigator.cpp @@ -372,71 +372,6 @@ void Navigator::Scale(m2::PointD const & pt, double factor) ScaleImpl(pt, endPt, pt, startPt, factor > 1, false); } -//namespace -//{ -// class ZoomAnim : public anim::Task -// { -// public: -// typedef function TScaleImplFn; -// ZoomAnim(m2::PointD const & startPt, m2::PointD const & endPt, -// m2::PointD const & target, TScaleImplFn const & fn, double deltaTime) -// : m_fn(fn) -// , m_startTime(0.0) -// , m_deltaTime(deltaTime) -// { -// m_finger1Start = target + (startPt - target); -// m_prevPt1 = m_finger1Start; -// m_deltaFinger1 = (endPt - startPt); - -// m_finger2Start = target - (startPt - target); -// m_prevPt2 = m_finger2Start; -// m_deltaFinger2 = -(endPt - startPt); -// } - -// virtual bool IsVisual() const { return true; } - -// void OnStart(double ts) -// { -// m_startTime = ts; -// } - -// void OnStep(double ts) -// { -// double elapsed = ts - m_startTime; -// if (my::AlmostEqual(elapsed, 0.0)) -// return; - -// double t = elapsed / m_deltaTime; -// if (t > 1.0 || my::AlmostEqual(t, 1.0)) -// { -// m_fn(m_finger1Start + m_deltaFinger1, m_finger2Start + m_deltaFinger2, m_prevPt1, m_prevPt2); -// End(); -// return; -// } - -// m2::PointD const current1 = m_finger1Start + m_deltaFinger1 * t; -// m2::PointD const current2 = m_finger2Start + m_deltaFinger2 * t; -// m_fn(current1, current2, m_prevPt1, m_prevPt2); -// m_prevPt1 = current1; -// m_prevPt2 = current2; -// } - -// private: -// m2::PointD m_prevPt1; -// m2::PointD m_prevPt2; - -// m2::PointD m_finger1Start; -// m2::PointD m_deltaFinger1; -// m2::PointD m_finger2Start; -// m2::PointD m_deltaFinger2; - -// TScaleImplFn m_fn; -// double m_startTime; -// double m_deltaTime; -// }; -//} - bool Navigator::CheckMinScale(ScreenBase const & screen) const { m2::RectD const & r = screen.ClipRect(); diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 228586cf0c..97914b167d 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -137,25 +137,25 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & { case UserEvent::EVENT_SCALE: breakAnim = SetScale(e.m_scaleEvent.m_pxPoint, e.m_scaleEvent.m_factor, e.m_scaleEvent.m_isAnim); - TouchCancel(m_touches); + TouchCancel(m_touches, 0.0); break; case UserEvent::EVENT_RESIZE: m_navigator.OnSize(e.m_resize.m_width, e.m_resize.m_height); viewportChanged = true; breakAnim = true; - TouchCancel(m_touches); + TouchCancel(m_touches, 0.0); break; case UserEvent::EVENT_SET_ANY_RECT: breakAnim = SetRect(e.m_anyRect.m_rect, e.m_anyRect.m_isAnim); - TouchCancel(m_touches); + TouchCancel(m_touches, 0.0); break; case UserEvent::EVENT_SET_RECT: breakAnim = SetRect(e.m_rectEvent.m_rect, e.m_rectEvent.m_zoom, e.m_rectEvent.m_applyRotation, e.m_rectEvent.m_isAnim); - TouchCancel(m_touches); + TouchCancel(m_touches, 0.0); break; case UserEvent::EVENT_SET_CENTER: breakAnim = SetCenter(e.m_centerEvent.m_center, e.m_centerEvent.m_zoom, e.m_centerEvent.m_isAnim); - TouchCancel(m_touches); + TouchCancel(m_touches, 0.0); break; case UserEvent::EVENT_TOUCH: breakAnim = ProcessTouch(e.m_touchEvent); @@ -178,7 +178,7 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & if (m_animation != nullptr) { - m2::AnyRectD rect = m_animation->GetCurrentRect(); + m2::AnyRectD rect = m_animation->GetCurrentRect(GetCurrentScreen()); m_navigator.SetFromRect(rect); modelViewChange = true; if (m_animation->IsFinished()) @@ -218,7 +218,15 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, m2::RectD sizeRect = rect.GetLocalRect(); sizeRect.Scale(1.0 / factor); - return SetRect(m2::AnyRectD(currentCenter, rect.Angle(), sizeRect), true); + + auto creator = [this, &scaleCenter, &glbScaleCenter](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)); + }; + + return SetRect(m2::AnyRectD(currentCenter, rect.Angle(), sizeRect), true, creator); } m_navigator.Scale(scaleCenter, factor); @@ -245,6 +253,15 @@ bool UserEventStream::SetRect(m2::RectD rect, int zoom, bool applyRotation, bool } bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) +{ + return SetRect(rect, isAnim, [this](m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, + double aDuration, double mDuration, double sDuration) + { + m_animation.reset(new ModelViewAnimation(startRect, endRect, aDuration, mDuration, sDuration)); + }); +} + +bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim, TAnimationCreator const & animCreator) { if (isAnim) { @@ -259,11 +276,14 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) if (max(max(angleDuration, moveDuration), scaleDuration) < MAX_ANIMATION_TIME) { - m_animation.reset(new ModelViewAnimation(startRect, rect, angleDuration, moveDuration, scaleDuration)); + ASSERT(animCreator != nullptr, ()); + animCreator(startRect, rect, angleDuration, moveDuration, scaleDuration); return false; } else + { m_animation.reset(); + } } m_navigator.SetFromRect(rect); @@ -278,7 +298,7 @@ m2::AnyRectD UserEventStream::GetCurrentRect() const m2::AnyRectD UserEventStream::GetTargetRect() const { if (m_animation) - return m_animation->GetTargetRect(); + return m_animation->GetTargetRect(GetCurrentScreen()); else return GetCurrentRect(); } @@ -294,32 +314,16 @@ bool UserEventStream::ProcessTouch(TouchEvent const & touch) switch (touchEvent.m_type) { case TouchEvent::TOUCH_DOWN: - isMapTouch |= TouchDown(touchEvent.m_touches); - if (isMapTouch && !m_scroller.IsActive()) - m_scroller.InitGrab(m_navigator.Screen(), touch.m_timeStamp); + isMapTouch |= TouchDown(touchEvent.m_touches, touch.m_timeStamp); break; case TouchEvent::TOUCH_MOVE: - isMapTouch |= TouchMove(touchEvent.m_touches); - if (isMapTouch && m_scroller.IsActive()) - m_scroller.GrabViewRect(m_navigator.Screen(), touch.m_timeStamp); + isMapTouch |= TouchMove(touchEvent.m_touches, touch.m_timeStamp); break; case TouchEvent::TOUCH_CANCEL: - isMapTouch |= TouchCancel(touchEvent.m_touches); - if (isMapTouch) - m_scroller.CancelGrab(); + isMapTouch |= TouchCancel(touchEvent.m_touches, touch.m_timeStamp); break; case TouchEvent::TOUCH_UP: - { - isMapTouch |= TouchUp(touchEvent.m_touches); - if (isMapTouch && touchEvent.GetMaskedCount() == GetValidTouchesCount(touchEvent.m_touches) && - m_kineticTimer.TimeElapsedAs().count() >= kKineticDelayMs) - { - m_scroller.GrabViewRect(m_navigator.Screen(), touch.m_timeStamp); - m_animation = m_scroller.CreateKineticAnimation(m_navigator.Screen()); - isMapTouch = false; - m_scroller.CancelGrab(); - } - } + isMapTouch |= TouchUp(touchEvent.m_touches, touch.m_timeStamp); break; default: ASSERT(false, ()); @@ -329,7 +333,7 @@ bool UserEventStream::ProcessTouch(TouchEvent const & touch) return isMapTouch; } -bool UserEventStream::TouchDown(array const & touches) +bool UserEventStream::TouchDown(array const & touches, double timestamp) { size_t touchCount = GetValidTouchesCount(touches); bool isMapTouch = true; @@ -364,7 +368,7 @@ bool UserEventStream::TouchDown(array const & touches) CancelTapDetector(); break; case STATE_DRAG: - EndDrag(touches[0]); + isMapTouch = EndDrag(touches[0], timestamp, true /* cancelled */); break; default: break; @@ -377,7 +381,7 @@ bool UserEventStream::TouchDown(array const & touches) return isMapTouch; } -bool UserEventStream::TouchMove(array const & touches) +bool UserEventStream::TouchMove(array const & touches, double timestamp) { size_t touchCount = GetValidTouchesCount(touches); bool isMapTouch = true; @@ -386,7 +390,7 @@ bool UserEventStream::TouchMove(array const & touches) { case STATE_EMPTY: if (touchCount == 1) - BeginDrag(touches[0]); + BeginDrag(touches[0], timestamp); else BeginScale(touches[0], touches[1]); break; @@ -402,7 +406,7 @@ bool UserEventStream::TouchMove(array const & touches) break; case STATE_DRAG: ASSERT_EQUAL(touchCount, 1, ()); - Drag(touches[0]); + Drag(touches[0], timestamp); break; case STATE_SCALE: ASSERT_EQUAL(touchCount, 2, ()); @@ -417,7 +421,7 @@ bool UserEventStream::TouchMove(array const & touches) return isMapTouch; } -bool UserEventStream::TouchCancel(array const & touches) +bool UserEventStream::TouchCancel(array const & touches, double timestamp) { size_t touchCount = GetValidTouchesCount(touches); bool isMapTouch = true; @@ -438,7 +442,7 @@ bool UserEventStream::TouchCancel(array const & touches) break; case STATE_DRAG: ASSERT_EQUAL(touchCount, 1, ()); - EndDrag(touches[0]); + isMapTouch = EndDrag(touches[0], timestamp, true /* cancelled */); break; case STATE_SCALE: ASSERT_EQUAL(touchCount, 2, ()); @@ -452,7 +456,7 @@ bool UserEventStream::TouchCancel(array const & touches) return isMapTouch; } -bool UserEventStream::TouchUp(array const & touches) +bool UserEventStream::TouchUp(array const & touches, double timestamp) { size_t touchCount = GetValidTouchesCount(touches); bool isMapTouch = true; @@ -473,7 +477,7 @@ bool UserEventStream::TouchUp(array const & touches) break; case STATE_DRAG: ASSERT_EQUAL(touchCount, 1, ()); - EndDrag(touches[0]); + isMapTouch = EndDrag(touches[0], timestamp, false /* cancelled */); break; case STATE_SCALE: ASSERT_EQUAL(touchCount, 2, ()); @@ -493,7 +497,7 @@ void UserEventStream::UpdateTouches(array const & touches) m_touches = touches; } -void UserEventStream::BeginDrag(Touch const & t) +void UserEventStream::BeginDrag(Touch const & t, double timestamp) { TEST_CALL(BEGIN_DRAG); ASSERT_EQUAL(m_state, STATE_EMPTY, ()); @@ -502,16 +506,22 @@ void UserEventStream::BeginDrag(Touch const & t) if (m_listener) m_listener->OnDragStarted(); m_navigator.StartDrag(t.m_location); + + if (!m_scroller.IsActive()) + m_scroller.InitGrab(m_navigator.Screen(), timestamp); } -void UserEventStream::Drag(Touch const & t) +void UserEventStream::Drag(Touch const & t, double timestamp) { TEST_CALL(DRAG); ASSERT_EQUAL(m_state, STATE_DRAG, ()); m_navigator.DoDrag(t.m_location); + + if (m_scroller.IsActive()) + m_scroller.GrabViewRect(m_navigator.Screen(), timestamp); } -void UserEventStream::EndDrag(Touch const & t) +bool UserEventStream::EndDrag(Touch const & t, double timestamp, bool cancelled) { TEST_CALL(END_DRAG); ASSERT_EQUAL(m_state, STATE_DRAG, ()); @@ -521,6 +531,22 @@ void UserEventStream::EndDrag(Touch const & t) m_startDragOrg = m2::PointD::Zero(); m_navigator.StopDrag(t.m_location); + + if (cancelled) + { + m_scroller.CancelGrab(); + return true; + } + + if (m_kineticTimer.TimeElapsedAs().count() >= kKineticDelayMs) + { + m_scroller.GrabViewRect(m_navigator.Screen(), timestamp); + m_animation = m_scroller.CreateKineticAnimation(m_navigator.Screen()); + m_scroller.CancelGrab(); + return false; + } + + return true; } void UserEventStream::BeginScale(Touch const & t1, Touch const & t2) diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index f3db949d04..4195fa3683 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -225,24 +225,26 @@ public: #endif private: + using TAnimationCreator = function; bool SetScale(m2::PointD const & pxScaleCenter, double factor, bool isAnim); bool SetCenter(m2::PointD const & center, int zoom, bool isAnim); bool SetRect(m2::RectD rect, int zoom, bool applyRotation, bool isAnim); bool SetRect(m2::AnyRectD const & rect, bool isAnim); + bool SetRect(m2::AnyRectD const & rect, bool isAnim, TAnimationCreator const & animCreator); m2::AnyRectD GetCurrentRect() const; bool ProcessTouch(TouchEvent const & touch); - bool TouchDown(array const & touches); - bool TouchMove(array const & touches); - bool TouchCancel(array const & touches); - bool TouchUp(array const & touches); + bool TouchDown(array const & touches, double timestamp); + bool TouchMove(array const & touches, double timestamp); + bool TouchCancel(array const & touches, double timestamp); + bool TouchUp(array const & touches, double timestamp); void UpdateTouches(array const & touches); - void BeginDrag(Touch const & t); - void Drag(Touch const & t); - void EndDrag(Touch const & t); + void BeginDrag(Touch const & t, double timestamp); + void Drag(Touch const & t, double timestamp); + bool EndDrag(Touch const & t, double timestamp, bool cancelled); void BeginScale(Touch const & t1, Touch const & t2); void Scale(Touch const & t1, Touch const & t2);