From ffa8d36c78d09acb7734229979fb35c2aab3f4bd Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Mon, 12 Oct 2015 16:14:36 +0300 Subject: [PATCH] F&R and scale animations blending, review fixes --- .../animation/model_view_animation.cpp | 52 ++++++++++++++----- .../animation/model_view_animation.hpp | 19 +++++-- drape_frontend/frontend_renderer.cpp | 26 +--------- drape_frontend/my_position_controller.cpp | 4 +- drape_frontend/navigator.cpp | 2 +- drape_frontend/user_event_stream.cpp | 36 ++++++++----- drape_frontend/user_event_stream.hpp | 19 +++---- 7 files changed, 86 insertions(+), 72 deletions(-) diff --git a/drape_frontend/animation/model_view_animation.cpp b/drape_frontend/animation/model_view_animation.cpp index c4ab77cdf2..a893ff9dc1 100644 --- a/drape_frontend/animation/model_view_animation.cpp +++ b/drape_frontend/animation/model_view_animation.cpp @@ -108,7 +108,6 @@ void ScaleAnimation::ApplyPixelOffset(ScreenBase const & screen, m2::AnyRectD & 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()); } @@ -126,37 +125,62 @@ m2::AnyRectD ScaleAnimation::GetTargetRect(ScreenBase const & screen) const return r; } -FollowAndRotateAnimation::FollowAndRotateAnimation(m2::AnyRectD const & startRect, m2::PointD const & userPos, - double newCenterOffset, double oldCenterOffset, +FollowAndRotateAnimation::FollowAndRotateAnimation(m2::AnyRectD const & startRect, + m2::RectD const & targetLocalRect, + m2::PointD const & userPos, + m2::PointD const & startPixelPos, + m2::PointD const & endPixelPos, double azimuth, double duration) : BaseModelViewAnimation(duration) - , m_angleInterpolator(startRect.Angle().val(), azimuth) + , m_angleInterpolator(startRect.Angle().val(), -azimuth) , m_rect(startRect.GetLocalRect()) + , m_target(targetLocalRect) , m_userPos(userPos) - , m_newCenterOffset(newCenterOffset) - , m_oldCenterOffset(oldCenterOffset) + , m_startPixelPos(startPixelPos) + , m_endPixelPos(endPixelPos) {} m2::AnyRectD FollowAndRotateAnimation::GetCurrentRect(ScreenBase const & screen) const { - return GetRect(GetElapsedTime()); + return GetRect(screen, GetElapsedTime()); } m2::AnyRectD FollowAndRotateAnimation::GetTargetRect(ScreenBase const & screen) const { - return GetRect(GetDuration()); + return GetRect(screen, GetDuration()); } -m2::AnyRectD FollowAndRotateAnimation::GetRect(double elapsedTime) const +m2::PointD FollowAndRotateAnimation::CalculateCenter(ScreenBase const & screen, m2::PointD const & userPos, + m2::PointD const & pixelPos, double azimuth) +{ + return CalculateCenter(screen.GlobalRect().GetLocalRect(), screen.PixelRect(), userPos, pixelPos, azimuth); +} + +m2::PointD FollowAndRotateAnimation::CalculateCenter(m2::RectD const & localRect, m2::RectD const & pixelRect, + m2::PointD const & userPos, m2::PointD const & pixelPos, + double azimuth) +{ + m2::PointD formingVector = pixelRect.Center() - pixelPos; + formingVector.x /= pixelRect.SizeX(); + formingVector.y /= pixelRect.SizeY(); + formingVector.x *= localRect.SizeX(); + formingVector.y *= localRect.SizeY(); + double const centerOffset = formingVector.Length(); + + m2::PointD viewVector = userPos.Move(1.0, azimuth + math::pi2) - userPos; + viewVector.Normalize(); + return userPos + (viewVector * centerOffset); +} + +m2::AnyRectD FollowAndRotateAnimation::GetRect(ScreenBase const & screen, double elapsedTime) const { double const t = GetSafeT(elapsedTime, GetDuration()); double const azimuth = m_angleInterpolator.Interpolate(t); - double const centerOffset = InterpolateDouble(m_oldCenterOffset, m_newCenterOffset, t); + m2::RectD const currentRect = InterpolateRect(m_rect, m_target, t); + m2::PointD const pixelPos = InterpolatePoint(m_startPixelPos, m_endPixelPos, t); + m2::PointD const centerPos = CalculateCenter(currentRect, screen.PixelRect(), m_userPos, pixelPos, azimuth); - m2::PointD viewVector = m_userPos.Move(1.0, azimuth + math::pi2) - m_userPos; - viewVector.Normalize(); - m2::PointD centerPos = m_userPos + (viewVector * centerOffset); - return m2::AnyRectD(centerPos, azimuth, m_rect); + return m2::AnyRectD(centerPos, azimuth, currentRect); } } // namespace df diff --git a/drape_frontend/animation/model_view_animation.hpp b/drape_frontend/animation/model_view_animation.hpp index 01956fb2ac..910a66bbd7 100644 --- a/drape_frontend/animation/model_view_animation.hpp +++ b/drape_frontend/animation/model_view_animation.hpp @@ -77,22 +77,31 @@ private: class FollowAndRotateAnimation : public BaseModelViewAnimation { public: - FollowAndRotateAnimation(m2::AnyRectD const & startRect, m2::PointD const & userPos, - double newCenterOffset, double oldCenterOffset, + FollowAndRotateAnimation(m2::AnyRectD const & startRect, + m2::RectD const & targetLocalRect, + m2::PointD const & userPos, + m2::PointD const & startPixelPos, + m2::PointD const & endPixelPos, 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; + static m2::PointD CalculateCenter(ScreenBase const & screen, m2::PointD const & userPos, + m2::PointD const & pixelPos, double azimuth); + static m2::PointD CalculateCenter(m2::RectD const & localRect, m2::RectD const & pixelRect, + m2::PointD const & userPos, m2::PointD const & pixelPos, + double azimuth); private: - m2::AnyRectD GetRect(double elapsedTime) const; + m2::AnyRectD GetRect(ScreenBase const & screen, double elapsedTime) const; InerpolateAngle m_angleInterpolator; m2::RectD m_rect; + m2::RectD m_target; m2::PointD m_userPos; - double m_newCenterOffset; - double m_oldCenterOffset; + m2::PointD m_startPixelPos; + m2::PointD m_endPixelPos; }; } // namespace df diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 0dddb671e8..aca934d6dc 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -914,31 +914,7 @@ void FrontendRenderer::ChangeModelView(m2::RectD const & rect) void FrontendRenderer::ChangeModelView(m2::PointD const & userPos, double azimuth, m2::PointD const & pxZero) { - ScreenBase const & screen = m_userEventStream.GetCurrentScreen(); - m2::RectD const & pixelRect = screen.PixelRect(); - m2::AnyRectD targetRect = m_userEventStream.GetCurrentScreen().GlobalRect(); - - auto calculateOffset = [&pixelRect, &targetRect](m2::PointD const & pixelPos) - { - m2::PointD formingVector = pixelPos; - formingVector.x /= pixelRect.SizeX(); - formingVector.y /= pixelRect.SizeY(); - formingVector.x *= targetRect.GetLocalRect().SizeX(); - formingVector.y *= targetRect.GetLocalRect().SizeY(); - - return formingVector.Length(); - }; - - double const newCenterOffset = calculateOffset(pixelRect.Center() - pxZero); - double const oldCenterOffset = calculateOffset(pixelRect.Center() - screen.GtoP(userPos)); - - m2::PointD viewVector = userPos.Move(1.0, -azimuth + math::pi2) - userPos; - viewVector.Normalize(); - - m2::AnyRectD const rect = m2::AnyRectD(viewVector * newCenterOffset + userPos, - -azimuth, targetRect.GetLocalRect()); - - AddUserEvent(FollowAndRotateEvent(rect, userPos, newCenterOffset, oldCenterOffset, -azimuth, true)); + AddUserEvent(FollowAndRotateEvent(userPos, pxZero, azimuth, true)); } ScreenBase const & FrontendRenderer::UpdateScene(bool & modelViewChanged) diff --git a/drape_frontend/my_position_controller.cpp b/drape_frontend/my_position_controller.cpp index 361de4674d..4ff23f34dd 100644 --- a/drape_frontend/my_position_controller.cpp +++ b/drape_frontend/my_position_controller.cpp @@ -534,8 +534,8 @@ void MyPositionController::CreateAnim(m2::PointD const & oldPos, double oldAzimu double moveDuration = ModelViewAnimation::GetMoveDuration(oldPos, m_position, screen); double rotateDuration = ModelViewAnimation::GetRotateDuration(oldAzimut, m_drawDirection); double maxDuration = max(moveDuration, rotateDuration); - double MAX_MY_POSITION_DURATION = 2.0; // in seconds - if (maxDuration > 0.0 && maxDuration < MAX_MY_POSITION_DURATION) + double kMaxMyPositionDuration = 2.0; // in seconds + if (maxDuration > 0.0 && maxDuration < kMaxMyPositionDuration) m_anim.reset(new MyPositionAnim(oldPos, m_position, moveDuration, oldAzimut, m_drawDirection, rotateDuration)); } diff --git a/drape_frontend/navigator.cpp b/drape_frontend/navigator.cpp index 9d7d9917f1..59cf0c9da8 100644 --- a/drape_frontend/navigator.cpp +++ b/drape_frontend/navigator.cpp @@ -415,7 +415,7 @@ bool Navigator::ScaleImpl(m2::PointD const & newPt1, m2::PointD const & newPt2, bool skipMinScaleAndBordersCheck, bool doRotateScreen, ScreenBase & screen) { - math::Matrix newM = screen.GtoPMatrix() * ScreenBase::CalcTransform(oldPt1, oldPt2, newPt1, newPt2); + math::Matrix const newM = screen.GtoPMatrix() * ScreenBase::CalcTransform(oldPt1, oldPt2, newPt1, newPt2); double oldAngle = screen.GetAngle(); ScreenBase tmp = screen; diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 895c90b47a..a7e43e4812 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -170,8 +170,7 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & } break; case UserEvent::EVENT_FOLLOW_AND_ROTATE: - breakAnim = SetFollowAndRotate(e.m_followAndRotate.m_targetRect, e.m_followAndRotate.m_userPos, - e.m_followAndRotate.m_newCenterOffset,e.m_followAndRotate.m_oldCenterOffset, + breakAnim = SetFollowAndRotate(e.m_followAndRotate.m_userPos, e.m_followAndRotate.m_pixelZero, e.m_followAndRotate.m_azimuth, e.m_followAndRotate.m_isAnim); TouchCancel(m_touches); break; @@ -231,8 +230,8 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, m_navigator.CalculateScale(scaleCenter, factor, screen); m2::PointD offset = GetCurrentScreen().PixelRect().Center() - scaleCenter; - auto creator = [this, &glbScaleCenter, &offset](m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, - double aDuration, double mDuration, double sDuration) + auto const creator = [this, &glbScaleCenter, &offset](m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, + double aDuration, double mDuration, double sDuration) { m_animation.reset(new ScaleAnimation(startRect, endRect, aDuration, mDuration, sDuration, glbScaleCenter, offset)); @@ -299,36 +298,47 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim, TAnimation return true; } -bool UserEventStream::SetFollowAndRotate(m2::AnyRectD const & rect, m2::PointD const & userPos, - double newCenterOffset, double oldCenterOffset, double azimuth, bool isAnim) +bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD const & pixelPos, double azimuth, bool isAnim) { + // Extract target local rect from current animation to preserve final scale. + m2::RectD targetLocalRect; + if (m_animation != nullptr) + targetLocalRect = m_animation->GetTargetRect(GetCurrentScreen()).GetLocalRect(); + else + targetLocalRect = GetCurrentRect().GetLocalRect(); + if (isAnim) { // Reset current animation if there is any. ResetCurrentAnimation(); ScreenBase const & screen = m_navigator.Screen(); + m2::PointD const newCenter = FollowAndRotateAnimation::CalculateCenter(screen, userPos, pixelPos, -azimuth); + m2::AnyRectD const startRect = GetCurrentRect(); - double const angleDuration = ModelViewAnimation::GetRotateDuration(startRect.Angle().val(), azimuth); - double const moveDuration = ModelViewAnimation::GetMoveDuration(startRect.GlobalZero(), rect.GlobalZero(), screen); + double const angleDuration = ModelViewAnimation::GetRotateDuration(startRect.Angle().val(), -azimuth); + double const moveDuration = ModelViewAnimation::GetMoveDuration(startRect.GlobalZero(), newCenter, screen); double const duration = max(angleDuration, moveDuration); if (duration > 0.0 && duration < kMaxAnimationTimeSec) { - m_animation.reset(new FollowAndRotateAnimation(startRect, userPos, newCenterOffset, oldCenterOffset, azimuth, duration)); + m_animation.reset(new FollowAndRotateAnimation(startRect, targetLocalRect, userPos, + screen.GtoP(userPos), pixelPos, azimuth, duration)); return false; } } m_animation.reset(); - m_navigator.SetFromRect(rect); + m2::PointD const center = FollowAndRotateAnimation::CalculateCenter(m_navigator.Screen(), userPos, pixelPos, -azimuth); + m_navigator.SetFromRect(m2::AnyRectD(center, -azimuth, targetLocalRect)); return true; } -void UserEventStream::ResetCurrentAnimation() +void UserEventStream::ResetCurrentAnimation(bool finishAnimation) { - if (m_animation != nullptr) + if (m_animation) { - m2::AnyRectD rect = m_animation->GetCurrentRect(GetCurrentScreen()); + m2::AnyRectD const rect = finishAnimation ? m_animation->GetTargetRect(GetCurrentScreen()) : + m_animation->GetCurrentRect(GetCurrentScreen()); m_navigator.SetFromRect(rect); m_animation.reset(); } diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 8ac7c9f997..9a77bae88c 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -127,20 +127,16 @@ struct SetAnyRectEvent struct FollowAndRotateEvent { - FollowAndRotateEvent(m2::AnyRectD const & targetRect, m2::PointD const & userPos, - double newCenterOffset, double oldCenterOffset, double azimuth, bool isAnim) - : m_targetRect(targetRect) - , m_userPos(userPos) - , m_newCenterOffset(newCenterOffset) - , m_oldCenterOffset(oldCenterOffset) + FollowAndRotateEvent(m2::PointD const & userPos, m2::PointD const & pixelZero, + double azimuth, bool isAnim) + : m_userPos(userPos) + , m_pixelZero(pixelZero) , m_azimuth(azimuth) , m_isAnim(isAnim) {} - m2::AnyRectD m_targetRect; m2::PointD m_userPos; - double m_newCenterOffset; - double m_oldCenterOffset; + m2::PointD m_pixelZero; double m_azimuth; bool m_isAnim; }; @@ -255,8 +251,7 @@ private: 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); - bool SetFollowAndRotate(m2::AnyRectD const & rect, m2::PointD const & userPos, - double newCenterOffset, double oldCenterOffset, double azimuth, bool isAnim); + bool SetFollowAndRotate(m2::PointD const & userPos, m2::PointD const & pixelPos, double azimuth, bool isAnim); m2::AnyRectD GetCurrentRect() const; @@ -288,7 +283,7 @@ private: void EndFilter(Touch const & t); void CancelFilter(Touch const & t); - void ResetCurrentAnimation(); + void ResetCurrentAnimation(bool finishAnimation = false); private: TIsCountryLoaded m_isCountryLoaded;