From 9beccf2fd26a6e2b6705e2be6efbb50196e4f610 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Tue, 5 Apr 2016 18:25:16 +0300 Subject: [PATCH 01/13] Animation system sketch --- drape_frontend/animation_system.cpp | 425 +++++++++++++++++++++++++++ drape_frontend/animation_system.h | 316 ++++++++++++++++++++ drape_frontend/drape_frontend.pro | 2 + drape_frontend/frontend_renderer.cpp | 2 + drape_frontend/user_event_stream.cpp | 29 +- 5 files changed, 772 insertions(+), 2 deletions(-) create mode 100644 drape_frontend/animation_system.cpp create mode 100644 drape_frontend/animation_system.h diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp new file mode 100644 index 0000000000..178f5b5ea1 --- /dev/null +++ b/drape_frontend/animation_system.cpp @@ -0,0 +1,425 @@ +#include "animation_system.h" +#include "animation/interpolations.hpp" + +namespace df +{ + +namespace +{ + +double CalcAnimSpeedDuration(double pxDiff, double pxSpeed) +{ + double const kEps = 1e-5; + + if (my::AlmostEqualAbs(pxDiff, 0.0, kEps)) + return 0.0; + + return fabs(pxDiff) / pxSpeed; +} + +} + +Interpolator::Interpolator(double duration, double delay) + : m_elapsedTime(0.0) + , m_duration(duration) + , m_delay(delay) +{ + ASSERT(m_duration >= 0.0, ()); +} + +Interpolator::~Interpolator() +{ +} + +bool Interpolator::IsFinished() const +{ + return m_elapsedTime > (m_duration + m_delay); +} + +void Interpolator::Advance(double elapsedSeconds) +{ + m_elapsedTime += elapsedSeconds; +} + +void Interpolator::SetMaxDuration(double maxDuration) +{ + m_duration = min(m_duration, maxDuration); +} + +double Interpolator::GetT() const +{ + if (IsFinished()) + return 1.0; + + return max(m_elapsedTime - m_delay, 0.0) / m_duration; +} + +double Interpolator::GetElapsedTime() const +{ + return m_elapsedTime; +} + +double Interpolator::GetDuration() const +{ + return m_duration; +} + +//static +double PositionInterpolator::GetMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor) +{ + double const kMinMoveDuration = 0.2; + double const kMinSpeedScalar = 0.2; + double const kMaxSpeedScalar = 7.0; + double const kEps = 1e-5; + + m2::RectD const & dispPxRect = convertor.PixelRect(); + double const pixelLength = convertor.GtoP(endPosition).Length(convertor.GtoP(startPosition)); + if (pixelLength < kEps) + return 0.0; + + double const minSize = min(dispPxRect.SizeX(), dispPxRect.SizeY()); + if (pixelLength < kMinSpeedScalar * minSize) + return kMinMoveDuration; + + double const pixelSpeed = kMaxSpeedScalar * minSize; + return CalcAnimSpeedDuration(pixelLength, pixelSpeed); +} + +PositionInterpolator::PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor) + : PositionInterpolator(0.0 /* delay */, startPosition, endPosition, convertor) +{ +} + +PositionInterpolator::PositionInterpolator(double delay, m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor) + : Interpolator(PositionInterpolator::GetMoveDuration(startPosition, endPosition, convertor), delay) + , m_startPosition(startPosition) + , m_endPosition(endPosition) + , m_position(startPosition) +{ + +} + +void PositionInterpolator::Advance(double elapsedSeconds) +{ + TBase::Advance(elapsedSeconds); + InterpolatePoint(m_startPosition, m_endPosition, GetT()); +} + +// static +double AngleInterpolator::GetRotateDuration(double startAngle, double endAngle) +{ + return 0.5 * fabs(endAngle - startAngle) / math::pi4; +} + +AngleInterpolator::AngleInterpolator(double startAngle, double endAngle) + : AngleInterpolator(0.0 /* delay */, startAngle, endAngle) +{ +} + +AngleInterpolator::AngleInterpolator(double delay, double startAngle, double endAngle) + : Interpolator(AngleInterpolator::GetRotateDuration(startAngle, endAngle), delay) + , m_startAngle(startAngle) + , m_endAngle(endAngle) + , m_angle(startAngle) +{ +} + +void AngleInterpolator::Advance(double elapsedSeconds) +{ + TBase::Advance(elapsedSeconds); + m_angle = InterpolateDouble(m_startAngle, m_endAngle, GetT()); +} + +// static +double ScaleInterpolator::GetScaleDuration(double startScale, double endScale) +{ + // Resize 2.0 times should be done for 0.3 seconds. + double constexpr kPixelSpeed = 2.0 / 0.3; + + if (startScale > endScale) + swap(startScale, endScale); + + return CalcAnimSpeedDuration(endScale / startScale, kPixelSpeed); +} + +ScaleInterpolator::ScaleInterpolator(double startScale, double endScale) + : ScaleInterpolator(0.0 /* delay */, startScale, endScale) +{ +} + +ScaleInterpolator::ScaleInterpolator(double delay, double startScale, double endScale) + : Interpolator(ScaleInterpolator::GetScaleDuration(startScale, endScale), delay) + , m_startScale(startScale) + , m_endScale(endScale) + , m_scale(startScale) +{ +} + +void ScaleInterpolator::Advance(double elapsedSeconds) +{ + TBase::Advance(elapsedSeconds); + m_scale = InterpolateDouble(m_startScale, m_endScale, GetT()); +} + +FollowAnimation::FollowAnimation(m2::PointD const & startPos, m2::PointD const & endPos, + double startAngle, double endAngle, + double startScale, double endScale, ScreenBase const & convertor) + : Animation(false, false) +{ + SetMove(startPos, endPos, convertor); + SetRotate(startAngle, endAngle); + SetScale(startScale, endScale); +} + +FollowAnimation::FollowAnimation() + : Animation(false, false) +{ +} + +void FollowAnimation::SetMove(m2::PointD const & startPos, m2::PointD const & endPos, + ScreenBase const & convertor) +{ + if (startPos != endPos) + m_positionInterpolator = make_unique_dp(startPos, endPos, convertor); +} + +void FollowAnimation::SetRotate(double startAngle, double endAngle) +{ + if (startAngle != endAngle) + m_angleInterpolator = make_unique_dp(startAngle, endAngle); +} + +void FollowAnimation::SetScale(double startScale, double endScale) +{ + if (startScale != endScale) + m_scaleInterpolator = make_unique_dp(startScale, endScale); +} + +void FollowAnimation::Advance(double elapsedSeconds) +{ + if (m_angleInterpolator != nullptr) + m_angleInterpolator->Advance(elapsedSeconds); + if (m_scaleInterpolator != nullptr) + m_scaleInterpolator->Advance(elapsedSeconds); + if (m_positionInterpolator != nullptr) + m_positionInterpolator->Advance(elapsedSeconds); +} + +void FollowAnimation::SetMaxDuration(double maxDuration) +{ + if (m_angleInterpolator != nullptr) + m_angleInterpolator->SetMaxDuration(maxDuration); + if (m_scaleInterpolator != nullptr) + m_scaleInterpolator->SetMaxDuration(maxDuration); + if (m_positionInterpolator != nullptr) + m_positionInterpolator->SetMaxDuration(maxDuration); +} + +double FollowAnimation::GetDuration() const +{ + double duration = 0; + if (m_angleInterpolator != nullptr) + duration = m_angleInterpolator->GetDuration(); + if (m_scaleInterpolator != nullptr) + duration = max(duration, m_scaleInterpolator->GetDuration()); + if (m_positionInterpolator != nullptr) + duration = max(duration, m_positionInterpolator->GetDuration()); + return duration; +} + +bool FollowAnimation::IsFinished() const +{ + return ((m_angleInterpolator == nullptr || m_angleInterpolator->IsFinished()) + && (m_scaleInterpolator == nullptr || m_scaleInterpolator->IsFinished()) + && (m_positionInterpolator == nullptr || m_positionInterpolator->IsFinished())); +} + +double FollowAnimation::GetScale(uint32_t object) const +{ + ASSERT(object & GetObjects(), ()); + ASSERT(m_scaleInterpolator != nullptr, ()); + + if (m_scaleInterpolator != nullptr) + return m_scaleInterpolator->GetScale(); + + return 0.0; +} + +double FollowAnimation::GetAngle(uint32_t object) const +{ + ASSERT(object & GetObjects(), ()); + ASSERT(m_angleInterpolator != nullptr, ()); + + if (m_angleInterpolator != nullptr) + return m_angleInterpolator->GetAngle(); + + return 0.0; +} + +m2::PointD FollowAnimation::GetPosition(uint32_t object) const +{ + ASSERT(object & GetObjects(), ()); + ASSERT(m_positionInterpolator != nullptr, ()); + + if (m_positionInterpolator != nullptr) + return m_positionInterpolator->GetPosition(); + + return m2::PointD(); +} + +uint32_t ParallelAnimation::GetMask(uint32_t object) const +{ + int mask = 0; + for (auto const & anim : m_animations) + mask |= anim->GetMask(object); + return mask; +} + +uint32_t ParallelAnimation::GetObjects() const +{ + int objects = 0; + for (auto const & anim : m_animations) + objects |= anim->GetObjects(); + return objects; +} + +void ParallelAnimation::AddAnimation(ref_ptr animation) +{ + m_animations.push_back(animation); +} + +void ParallelAnimation::OnStart() +{ + for (auto & anim : m_animations) + anim->OnStart(); +} + +void ParallelAnimation::OnFinish() +{ + +} + +void ParallelAnimation::Advance(double elapsedSeconds) +{ + auto iter = m_animations.begin(); + while (iter != m_animations.end()) + { + (*iter)->Advance(elapsedSeconds); + if ((*iter)->IsFinished()) + { + (*iter)->OnFinish(); + iter = m_animations.erase(iter); + } + else + ++iter; + } +} + +uint32_t SequenceAnimation::GetMask(uint32_t object) const +{ + int mask = 0; + if (!m_animations.empty()) + mask = m_animations.front()->GetMask(object); + return mask; +} + +uint32_t SequenceAnimation::GetObjects() const +{ + int objects = 0; + if (!m_animations.empty()) + objects = m_animations.front()->GetObjects(); + return objects; +} + +void SequenceAnimation::AddAnimation(ref_ptr animation) +{ + m_animations.push_back(animation); +} + +void SequenceAnimation::OnStart() +{ + if (m_animations.empty()) + return; + m_animations.front()->OnStart(); +} + +void SequenceAnimation::OnFinish() +{ + +} + +void SequenceAnimation::Advance(double elapsedSeconds) +{ + if (m_animations.empty()) + return; + m_animations.front()->Advance(elapsedSeconds); + if (m_animations.front()->IsFinished()) + { + m_animations.front()->OnFinish(); + m_animations.pop_front(); + } +} + +m2::AnyRectD AnimationSystem::GetRect(ScreenBase const & currentScreen) +{ + double scale = currentScreen.GetScale(); + double angle = currentScreen.GetAngle(); + m2::PointD pos = currentScreen.GlobalRect().GlobalZero(); + for (auto const & anim : m_animations) + { + if (anim->GetObjects() & kPlaneAnimObjBit) + { + int mask = anim->GetMask(kPlaneAnimObjBit); + if (mask & kScaleAnimationBit) + scale = anim->GetScale(kPlaneAnimObjBit); + if (mask & kMoveAnimationBit) + pos = anim->GetPosition(kPlaneAnimObjBit); + if (mask & kRotateAnimationBit) + angle = anim->GetAngle(kPlaneAnimObjBit); + } + } + m2::RectD rect = currentScreen.PixelRect(); + rect.Offset(-rect.Center()); + rect.Scale(scale); + return m2::AnyRectD(pos, angle, rect); +} + +bool AnimationSystem::AnimationExists(Animation::Object object) +{ + for (auto const & anim : m_animations) + { + if (anim->GetObjects() & (1 << object)) + return true; + } + return false; +} + +AnimationSystem & AnimationSystem::Instance() +{ + static AnimationSystem animSystem; + return animSystem; +} + +void AnimationSystem::AddAnimation(drape_ptr && animation) +{ + animation->OnStart(); + m_animations.insert(move(animation)); +} + +void AnimationSystem::Advance(double elapsedSeconds) +{ + auto iter = m_animations.begin(); + while (iter != m_animations.end()) + { + (*iter)->Advance(elapsedSeconds); + if ((*iter)->IsFinished()) + { + (*iter)->OnFinish(); + iter = m_animations.erase(iter); + } + else + ++iter; + } +} + +} // namespace df diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.h new file mode 100644 index 0000000000..6018020a16 --- /dev/null +++ b/drape_frontend/animation_system.h @@ -0,0 +1,316 @@ +#pragma once + +#include "animation/base_interpolator.hpp" + +#include "drape/pointers.hpp" + +#include "geometry/screenbase.hpp" + +#include "std/deque.hpp" +#include "std/noncopyable.hpp" + +namespace df +{ + +uint32_t constexpr kMoveAnimationBit = 1; +uint32_t constexpr kScaleAnimationBit = 1 << 1; +uint32_t constexpr kRotateAnimationBit = 1 << 2; +uint32_t constexpr kPerspectiveAnimationBit = 1 << 3; + +uint32_t constexpr kArrowAnimObjBit = 1; +uint32_t constexpr kPlaneAnimObjBit = 1 << 1; +uint32_t constexpr kSelectionAnimBit = 1 << 2; + +class Animation +{ +public: + enum Type + { + Sequence, + Parallel, + ModelView, + Perspective, + Arrow + }; + + enum Object + { + MyPositionArrow, + MapPlane, + Selection + }; + + Animation(bool couldBeInterrupted, bool couldBeMixed) + : m_couldBeInterrupted(couldBeInterrupted) + , m_couldBeMixed(couldBeMixed) + {} + + virtual void OnStart() {} + virtual void OnFinish() {} + + virtual Type GetType() const = 0; + + virtual uint32_t GetMask(uint32_t object) const = 0; + virtual uint32_t GetObjects() const = 0; + + virtual void SetMaxDuration(double maxDuration) = 0; + virtual double GetDuration() const = 0; + virtual bool IsFinished() const = 0; + + virtual void Advance(double elapsedSeconds) = 0; + + virtual double GetScale(uint32_t object) const = 0; + virtual double GetAngle(uint32_t object) const = 0; + virtual m2::PointD GetPosition(uint32_t object) const = 0; + + bool CouldBeInterrupted() const { return m_couldBeInterrupted; } + bool CouldBeMixed() const { return m_couldBeMixed; } + bool CouldBeMixedWith(uint32_t object, int mask) + { + return m_couldBeMixed && !(mask & GetMask(object)); + } + +protected: + bool m_couldBeInterrupted; + bool m_couldBeMixed; +}; + +class Interpolator +{ +public: + Interpolator(double duration, double delay = 0); + virtual ~Interpolator(); + + bool IsFinished() const; + virtual void Advance(double elapsedSeconds); + void SetMaxDuration(double maxDuration); + double GetDuration() const; + +protected: + double GetT() const; + double GetElapsedTime() const; + +private: + double m_elapsedTime; + double m_duration; + double m_delay; +}; + + +class PositionInterpolator: public Interpolator +{ + using TBase = Interpolator; + +public: + PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor); + PositionInterpolator(double delay, m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor); + + static double GetMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor); + + void Advance(double elapsedSeconds) override; + virtual m2::PointD GetPosition() const { return m_position; } + +private: + m2::PointD m_startPosition; + m2::PointD m_endPosition; + m2::PointD m_position; +}; + +class ScaleInterpolator: public Interpolator +{ + using TBase = Interpolator; + +public: + ScaleInterpolator(double startScale, double endScale); + ScaleInterpolator(double delay, double startScale, double endScale); + + static double GetScaleDuration(double startScale, double endScale); + + void Advance(double elapsedSeconds) override; + virtual double GetScale() const { return m_scale; } + +private: + double const m_startScale; + double const m_endScale; + double m_scale; +}; + +class AngleInterpolator: public Interpolator +{ + using TBase = Interpolator; + +public: + AngleInterpolator(double startAngle, double endAngle); + AngleInterpolator(double delay, double startAngle, double endAngle); + + static double GetRotateDuration(double startAngle, double endAngle); + + void Advance(double elapsedSeconds) override; + virtual double GetAngle() const { return m_angle; } + +private: + double const m_startAngle; + double const m_endAngle; + double m_angle; +}; + +class ArrowAnimation : public Animation +{ +public: + ArrowAnimation(m2::PointD const & startPos, m2::PointD const & endPos, + double startAngle, double endAngle, ScreenBase const & convertor) + : Animation(false, false) + { + m_positionInterpolator.reset(new PositionInterpolator(startPos, endPos, convertor)); + m_angleInterpolator.reset(new AngleInterpolator(startAngle, endAngle)); + } + + Animation::Type GetType() const override { return Animation::Arrow; } + + uint32_t GetMask(uint32_t object) const override + { + return (object & kArrowAnimObjBit) && + ((m_angleInterpolator != nullptr ? kRotateAnimationBit : 0) | + (m_positionInterpolator != nullptr ? kMoveAnimationBit : 0)); + } + + uint32_t GetObjects() const override + { + return kArrowAnimObjBit; + } + + void Advance(double elapsedSeconds) override; + +private: + drape_ptr m_positionInterpolator; + drape_ptr m_angleInterpolator; +}; + +class PerspectiveSwitchAnimation : public Animation +{ + PerspectiveSwitchAnimation() + : Animation(false, false) + {} + + Animation::Type GetType() const override { return Animation::Perspective; } + + uint32_t GetMask(uint32_t object) const override + { + return (object & kPlaneAnimObjBit) && + (m_angleInterpolator != nullptr ? kPerspectiveAnimationBit : 0); + } + + uint32_t GetObjects() const override + { + return kPlaneAnimObjBit; + } + + void Advance(double elapsedSeconds) override; + +private: + drape_ptr m_angleInterpolator; +}; + +class FollowAnimation : public Animation +{ +public: + FollowAnimation(m2::PointD const & startPos, m2::PointD const & endPos, + double startAngle, double endAngle, + double startScale, double endScale, ScreenBase const & convertor); + FollowAnimation(); + + void SetMove(m2::PointD const & startPos, m2::PointD const & endPos, ScreenBase const & convertor); + void SetRotate(double startAngle, double endAngle); + void SetScale(double startScale, double endScale); + + Animation::Type GetType() const override { return Animation::ModelView; } + + uint32_t GetMask(uint32_t object) const override + { + return (object & kPlaneAnimObjBit) ? + ((m_angleInterpolator != nullptr ? kPerspectiveAnimationBit : 0) | + (m_positionInterpolator != nullptr ? kMoveAnimationBit : 0) | + (m_scaleInterpolator != nullptr ? kScaleAnimationBit : 0)) : 0; + } + + uint32_t GetObjects() const override + { + return kPlaneAnimObjBit; + } + + void Advance(double elapsedSeconds) override; + + void SetMaxDuration(double maxDuration) override; + double GetDuration() const override; + bool IsFinished() const override; + + double GetScale(uint32_t object) const override; + double GetAngle(uint32_t object) const override; + m2::PointD GetPosition(uint32_t object) const override; + +private: + drape_ptr m_angleInterpolator; + drape_ptr m_positionInterpolator; + drape_ptr m_scaleInterpolator; +}; + +using TAnimations = vector>; + +class SequenceAnimation : public Animation +{ +public: + Animation::Type GetType() const override { return Animation::Sequence; } + uint32_t GetMask(uint32_t object) const override; + uint32_t GetObjects() const override; + + void AddAnimation(ref_ptr animation); + + void OnStart() override; + void OnFinish() override; + + void Advance(double elapsedSeconds) override; + +private: + deque> m_animations; +}; + +class ParallelAnimation : public Animation +{ +public: + Animation::Type GetType() const override { return Animation::Parallel; } + uint32_t GetMask(uint32_t object) const override; + uint32_t GetObjects() const override; + + void AddAnimation(ref_ptr animation); + + void OnStart() override; + void OnFinish() override; + + void Advance(double elapsedSeconds) override; + +private: + TAnimations m_animations; +}; + +class AnimationSystem : private noncopyable +{ +public: + static AnimationSystem & Instance(); + + m2::AnyRectD GetRect(ScreenBase const & currentScreen); + + bool AnimationExists(Animation::Object object); + + void AddAnimation(drape_ptr && animation); + + void Advance(double elapsedSeconds); + +private: + AnimationSystem() {} + +private: + + set> m_animations; +}; + +} diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index 1e3aa5482e..d8734a57d4 100755 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -92,6 +92,7 @@ SOURCES += \ watch/feature_processor.cpp \ watch/default_font.cpp \ batch_merge_helper.cpp \ + animation_system.cpp HEADERS += \ animation/base_interpolator.hpp \ @@ -191,3 +192,4 @@ HEADERS += \ watch/geometry_processors.hpp \ watch/feature_processor.hpp \ batch_merge_helper.hpp \ + animation_system.h diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 26a8863c43..a8acdd8f2a 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -1,5 +1,6 @@ #include "drape_frontend/animation/interpolation_holder.hpp" #include "drape_frontend/gui/drape_gui.hpp" +#include "drape_frontend/animation_system.h" #include "drape_frontend/framebuffer.hpp" #include "drape_frontend/frontend_renderer.hpp" #include "drape_frontend/message_subclasses.hpp" @@ -1506,6 +1507,7 @@ void FrontendRenderer::Routine::Do() m_renderer.RenderScene(modelView); isActiveFrame |= InterpolationHolder::Instance().Advance(frameTime); + AnimationSystem::Instance().Advance(frameTime); if (modelViewChanged) { diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 128a1f5720..8ca230b11a 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -1,5 +1,6 @@ #include "drape_frontend/user_event_stream.hpp" #include "drape_frontend/animation_constants.hpp" +#include "drape_frontend/animation_system.h" #include "drape_frontend/animation_utils.hpp" #include "drape_frontend/visual_params.hpp" @@ -253,6 +254,12 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & if (m_animation->IsFinished()) m_animation.reset(); } + if (AnimationSystem::Instance().AnimationExists(Animation::MapPlane)) + { + m2::AnyRectD const rect = AnimationSystem::Instance().GetRect(GetCurrentScreen()); + m_navigator.SetFromRect(rect); + modelViewChange = true; + } if (m_pendingEvent != nullptr && m_pendingEvent->m_type == UserEvent::EVENT_ENABLE_PERSPECTIVE && @@ -322,7 +329,25 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, m2::PointD const offset = GetCurrentScreen().PixelRect().Center() - m_navigator.P3dtoP(scaleCenter); - auto const creator = [this, &glbScaleCenter, &offset](m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, + ScreenBase const & startScreen = GetCurrentScreen(); + ScreenBase endScreen = startScreen; + m_navigator.CalculateScale(scaleCenter, factor, endScreen); + + drape_ptr anim = make_unique_dp(); + anim->SetScale(startScreen.GetScale(), endScreen.GetScale()); + anim->SetMove(startScreen.GlobalRect().GlobalZero(), + endScreen.GlobalRect().GlobalZero(), startScreen); + anim->SetMaxDuration(kMaxAnimationTimeSec); + if (df::IsAnimationAllowed(anim->GetDuration(), startScreen)) + { + AnimationSystem::Instance().AddAnimation(move(anim)); + return false; + } + + m_navigator.SetFromRect(endScreen.GlobalRect()); + return true; + + /*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, @@ -334,7 +359,7 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, ScreenBase screen = GetCurrentScreen(); m_navigator.CalculateScale(scaleCenter, factor, screen); - return SetRect(screen.GlobalRect(), true, creator); + return SetRect(screen.GlobalRect(), true, creator);*/ } m_navigator.Scale(scaleCenter, factor); From 05c5f5d766965216952cc99a413d5894942eaff2 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Mon, 18 Apr 2016 22:55:18 +0300 Subject: [PATCH 02/13] SetRect animation with new animation system --- drape_frontend/animation_system.cpp | 307 ++++++++++++++++------ drape_frontend/animation_system.h | 141 ++++++---- drape_frontend/my_position_controller.cpp | 6 +- drape_frontend/user_event_stream.cpp | 33 ++- 4 files changed, 336 insertions(+), 151 deletions(-) diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index 178f5b5ea1..6a1649f963 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -1,6 +1,11 @@ #include "animation_system.h" #include "animation/interpolations.hpp" +#include "base/logging.hpp" + +#include "boost/variant/variant.hpp" +#include "boost/variant/get.hpp" + namespace df { @@ -19,6 +24,35 @@ double CalcAnimSpeedDuration(double pxDiff, double pxSpeed) } +bool Animation::CouldBeMixedWith(TObject object, TObjectProperties const & properties) +{ + if (!m_couldBeMixed) + return false; + ASSERT(HasObject(object), ()); + + TObjectProperties const & selfProperties = GetProperties(object); + TObjectProperties intersection; + set_intersection(selfProperties.begin(), selfProperties.end(), + properties.begin(), properties.end(), + inserter(intersection, intersection.end())); + return intersection.empty(); +} + +bool Animation::CouldBeMixedWith(Animation const & animation) +{ + if (!m_couldBeMixed || animation.m_couldBeMixed) + return false; + + for (auto const & object : animation.GetObjects()) + { + if (!HasObject(object)) + continue; + if (!CouldBeMixedWith(object, animation.GetProperties(object))) + return false; + } + return true; +} + Interpolator::Interpolator(double duration, double delay) : m_elapsedTime(0.0) , m_duration(duration) @@ -102,7 +136,7 @@ PositionInterpolator::PositionInterpolator(double delay, m2::PointD const & star void PositionInterpolator::Advance(double elapsedSeconds) { TBase::Advance(elapsedSeconds); - InterpolatePoint(m_startPosition, m_endPosition, GetT()); + m_position = InterpolatePoint(m_startPosition, m_endPosition, GetT()); } // static @@ -164,35 +198,57 @@ void ScaleInterpolator::Advance(double elapsedSeconds) FollowAnimation::FollowAnimation(m2::PointD const & startPos, m2::PointD const & endPos, double startAngle, double endAngle, double startScale, double endScale, ScreenBase const & convertor) - : Animation(false, false) + : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) { + m_objects.insert(Animation::MapPlane); SetMove(startPos, endPos, convertor); SetRotate(startAngle, endAngle); SetScale(startScale, endScale); } FollowAnimation::FollowAnimation() - : Animation(false, false) + : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) { + m_objects.insert(Animation::MapPlane); } void FollowAnimation::SetMove(m2::PointD const & startPos, m2::PointD const & endPos, ScreenBase const & convertor) { if (startPos != endPos) + { m_positionInterpolator = make_unique_dp(startPos, endPos, convertor); + m_properties.insert(Animation::Position); + } } void FollowAnimation::SetRotate(double startAngle, double endAngle) { if (startAngle != endAngle) + { m_angleInterpolator = make_unique_dp(startAngle, endAngle); + m_properties.insert(Animation::Angle); + } } void FollowAnimation::SetScale(double startScale, double endScale) { if (startScale != endScale) + { m_scaleInterpolator = make_unique_dp(startScale, endScale); + m_properties.insert(Animation::Scale); + } +} + +Animation::TObjectProperties const & FollowAnimation::GetProperties(TObject object) const +{ + ASSERT(object == Animation::MapPlane, ()); + return m_properties; +} + +bool FollowAnimation::HasProperty(TObject object, TProperty property) const +{ + return HasObject(object) && m_properties.find(property) != m_properties.end(); } void FollowAnimation::Advance(double elapsedSeconds) @@ -234,58 +290,58 @@ bool FollowAnimation::IsFinished() const && (m_positionInterpolator == nullptr || m_positionInterpolator->IsFinished())); } -double FollowAnimation::GetScale(uint32_t object) const +Animation::TPropValue FollowAnimation::GetProperty(TObject object, TProperty property) const { - ASSERT(object & GetObjects(), ()); - ASSERT(m_scaleInterpolator != nullptr, ()); + ASSERT(object == Animation::MapPlane, ()); - if (m_scaleInterpolator != nullptr) - return m_scaleInterpolator->GetScale(); + switch (property) + { + case Animation::Position: + ASSERT(m_positionInterpolator != nullptr, ()); + if (m_positionInterpolator != nullptr) + return m_positionInterpolator->GetPosition(); + break; + case Animation::Scale: + ASSERT(m_scaleInterpolator != nullptr, ()); + if (m_scaleInterpolator != nullptr) + return m_scaleInterpolator->GetScale(); + break; + case Animation::Angle: + ASSERT(m_angleInterpolator != nullptr, ()); + if (m_angleInterpolator != nullptr) + return m_angleInterpolator->GetAngle(); + break; + default: + ASSERT(!"Wrong property", ()); + } return 0.0; } -double FollowAnimation::GetAngle(uint32_t object) const +Animation::TObjectProperties const & ParallelAnimation::GetProperties(TObject object) const { - ASSERT(object & GetObjects(), ()); - ASSERT(m_angleInterpolator != nullptr, ()); - - if (m_angleInterpolator != nullptr) - return m_angleInterpolator->GetAngle(); - - return 0.0; + ASSERT(HasObject(object), ()); + return m_properties.find(object)->second; } -m2::PointD FollowAnimation::GetPosition(uint32_t object) const +bool ParallelAnimation::HasProperty(TObject object, TProperty property) const { - ASSERT(object & GetObjects(), ()); - ASSERT(m_positionInterpolator != nullptr, ()); - - if (m_positionInterpolator != nullptr) - return m_positionInterpolator->GetPosition(); - - return m2::PointD(); + if (!HasObject(object)) + return false; + TObjectProperties properties = GetProperties(object); + return properties.find(property) != properties.end(); } -uint32_t ParallelAnimation::GetMask(uint32_t object) const +void ParallelAnimation::AddAnimation(drape_ptr && animation) { - int mask = 0; - for (auto const & anim : m_animations) - mask |= anim->GetMask(object); - return mask; -} - -uint32_t ParallelAnimation::GetObjects() const -{ - int objects = 0; - for (auto const & anim : m_animations) - objects |= anim->GetObjects(); - return objects; -} - -void ParallelAnimation::AddAnimation(ref_ptr animation) -{ - m_animations.push_back(animation); + TAnimObjects const & objects = animation->GetObjects(); + m_objects.insert(objects.begin(), objects.end()); + for (auto const & object : objects) + { + TObjectProperties const & properties = animation->GetProperties(object); + m_properties[object].insert(properties.begin(), properties.end()); + } + m_animations.push_back(move(animation)); } void ParallelAnimation::OnStart() @@ -315,25 +371,33 @@ void ParallelAnimation::Advance(double elapsedSeconds) } } -uint32_t SequenceAnimation::GetMask(uint32_t object) const +Animation::TAnimObjects const & SequenceAnimation::GetObjects() const { - int mask = 0; - if (!m_animations.empty()) - mask = m_animations.front()->GetMask(object); - return mask; + ASSERT(!m_animations.empty(), ()); + return m_animations.front()->GetObjects(); } -uint32_t SequenceAnimation::GetObjects() const +bool SequenceAnimation::HasObject(TObject object) const { - int objects = 0; - if (!m_animations.empty()) - objects = m_animations.front()->GetObjects(); - return objects; + ASSERT(!m_animations.empty(), ()); + return m_animations.front()->HasObject(object); } -void SequenceAnimation::AddAnimation(ref_ptr animation) +Animation::TObjectProperties const & SequenceAnimation::GetProperties(TObject object) const { - m_animations.push_back(animation); + ASSERT(!m_animations.empty(), ()); + return m_animations.front()->GetProperties(object); +} + +bool SequenceAnimation::HasProperty(TObject object, TProperty property) const +{ + ASSERT(!m_animations.empty(), ()); + return m_animations.front()->HasProperty(object, property); +} + +void SequenceAnimation::AddAnimation(drape_ptr && animation) +{ + m_animations.push_back(move(animation)); } void SequenceAnimation::OnStart() @@ -360,35 +424,38 @@ void SequenceAnimation::Advance(double elapsedSeconds) } } +AnimationSystem::AnimationSystem() +{ + +} + m2::AnyRectD AnimationSystem::GetRect(ScreenBase const & currentScreen) { - double scale = currentScreen.GetScale(); - double angle = currentScreen.GetAngle(); - m2::PointD pos = currentScreen.GlobalRect().GlobalZero(); - for (auto const & anim : m_animations) - { - if (anim->GetObjects() & kPlaneAnimObjBit) - { - int mask = anim->GetMask(kPlaneAnimObjBit); - if (mask & kScaleAnimationBit) - scale = anim->GetScale(kPlaneAnimObjBit); - if (mask & kMoveAnimationBit) - pos = anim->GetPosition(kPlaneAnimObjBit); - if (mask & kRotateAnimationBit) - angle = anim->GetAngle(kPlaneAnimObjBit); - } - } + const Animation::TObject obj = Animation::MapPlane; + double scale = boost::get( + GetProperty(obj, Animation::Scale, currentScreen.GetScale())); + double angle = boost::get( + GetProperty(obj, Animation::Angle, currentScreen.GetAngle())); + m2::PointD pos = boost::get( + GetProperty(obj, Animation::Position, currentScreen.GlobalRect().GlobalZero())); m2::RectD rect = currentScreen.PixelRect(); rect.Offset(-rect.Center()); rect.Scale(scale); return m2::AnyRectD(pos, angle, rect); } -bool AnimationSystem::AnimationExists(Animation::Object object) +bool AnimationSystem::AnimationExists(Animation::TObject object) const { - for (auto const & anim : m_animations) + if (m_animationChain.empty()) + return false; + for (auto const & anim : m_animationChain.front()) { - if (anim->GetObjects() & (1 << object)) + if (anim->HasObject(object)) + return true; + } + for (auto it = m_propertyCache.begin(); it != m_propertyCache.end(); ++it) + { + if (it->first.first == object) return true; } return false; @@ -400,25 +467,101 @@ AnimationSystem & AnimationSystem::Instance() return animSystem; } -void AnimationSystem::AddAnimation(drape_ptr && animation) +void AnimationSystem::AddAnimation(drape_ptr && animation, bool force) +{ + for (auto & lst : m_animationChain) + { + bool couldBeMixed = true; + for (auto it = lst.begin(); it != lst.end();) + { + auto & anim = *it; + if (!anim->CouldBeMixedWith(*animation)) + { + if (!force || !anim->CouldBeInterrupted()) + { + couldBeMixed = false; + break; + } + // TODO: do not interrupt anything until it's not clear that we can mix + anim->Interrupt(); + SaveAnimationResult(*anim); + it = lst.erase(it); + } + else + { + ++it; + } + } + if (couldBeMixed) + { + animation->OnStart(); + lst.emplace_back(move(animation)); + return; + } + } + + PushAnimation(move(animation)); +} + +void AnimationSystem::PushAnimation(drape_ptr && animation) { animation->OnStart(); - m_animations.insert(move(animation)); + TAnimationList list; + list.emplace_back(move(animation)); + m_animationChain.emplace_back(move(list)); } void AnimationSystem::Advance(double elapsedSeconds) { - auto iter = m_animations.begin(); - while (iter != m_animations.end()) + if (m_animationChain.empty()) + return; + + TAnimationList & frontList = m_animationChain.front(); + for (auto it = frontList.begin(); it != frontList.end();) { - (*iter)->Advance(elapsedSeconds); - if ((*iter)->IsFinished()) + auto & anim = *it; + anim->Advance(elapsedSeconds); + if (anim->IsFinished()) { - (*iter)->OnFinish(); - iter = m_animations.erase(iter); + anim->OnFinish(); + SaveAnimationResult(*anim); + it = frontList.erase(it); } else - ++iter; + { + ++it; + } + } +} + +Animation::TPropValue AnimationSystem::GetProperty(Animation::TObject object, Animation::TProperty property, Animation::TPropValue current) const +{ + if (!m_animationChain.empty()) + { + for (auto const & anim : m_animationChain.front()) + { + if (anim->HasProperty(object, property)) + return anim->GetProperty(object, property); + } + } + auto it = m_propertyCache.find(make_pair(object, property)); + if (it != m_propertyCache.end()) + { + Animation::TPropValue value(it->second); + m_propertyCache.erase(it); + return value; + } + return current; +} + +void AnimationSystem::SaveAnimationResult(Animation const & animation) +{ + for (auto const & object : animation.GetObjects()) + { + for (auto const & property : animation.GetProperties(object)) + { + m_propertyCache[make_pair(object, property)] = animation.GetProperty(object, property); + } } } diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.h index 6018020a16..1d5370bcd0 100644 --- a/drape_frontend/animation_system.h +++ b/drape_frontend/animation_system.h @@ -6,21 +6,15 @@ #include "geometry/screenbase.hpp" +#include "std/set.hpp" #include "std/deque.hpp" #include "std/noncopyable.hpp" +#include "boost/variant/variant_fwd.hpp" + namespace df { -uint32_t constexpr kMoveAnimationBit = 1; -uint32_t constexpr kScaleAnimationBit = 1 << 1; -uint32_t constexpr kRotateAnimationBit = 1 << 2; -uint32_t constexpr kPerspectiveAnimationBit = 1 << 3; - -uint32_t constexpr kArrowAnimObjBit = 1; -uint32_t constexpr kPlaneAnimObjBit = 1 << 1; -uint32_t constexpr kSelectionAnimBit = 1 << 2; - class Animation { public: @@ -40,6 +34,19 @@ public: Selection }; + enum ObjectProperty + { + Position, + Scale, + Angle + }; + + using TObject = uint32_t; + using TProperty = uint32_t; + using TPropValue = boost::variant; + using TAnimObjects = set; + using TObjectProperties = set; + Animation(bool couldBeInterrupted, bool couldBeMixed) : m_couldBeInterrupted(couldBeInterrupted) , m_couldBeMixed(couldBeMixed) @@ -47,11 +54,14 @@ public: virtual void OnStart() {} virtual void OnFinish() {} + virtual void Interrupt() {} virtual Type GetType() const = 0; - virtual uint32_t GetMask(uint32_t object) const = 0; - virtual uint32_t GetObjects() const = 0; + virtual TAnimObjects const & GetObjects() const = 0; + virtual bool HasObject(TObject object) const = 0; + virtual TObjectProperties const & GetProperties(TObject object) const = 0; + virtual bool HasProperty(TObject object, TProperty property) const = 0; virtual void SetMaxDuration(double maxDuration) = 0; virtual double GetDuration() const = 0; @@ -59,16 +69,12 @@ public: virtual void Advance(double elapsedSeconds) = 0; - virtual double GetScale(uint32_t object) const = 0; - virtual double GetAngle(uint32_t object) const = 0; - virtual m2::PointD GetPosition(uint32_t object) const = 0; + virtual TPropValue GetProperty(TObject object, TProperty property) const = 0; bool CouldBeInterrupted() const { return m_couldBeInterrupted; } bool CouldBeMixed() const { return m_couldBeMixed; } - bool CouldBeMixedWith(uint32_t object, int mask) - { - return m_couldBeMixed && !(mask & GetMask(object)); - } + bool CouldBeMixedWith(TObject object, TObjectProperties const & properties); + bool CouldBeMixedWith(Animation const & animation); protected: bool m_couldBeInterrupted; @@ -163,27 +169,31 @@ public: { m_positionInterpolator.reset(new PositionInterpolator(startPos, endPos, convertor)); m_angleInterpolator.reset(new AngleInterpolator(startAngle, endAngle)); + m_objects.insert(Animation::MyPositionArrow); + m_properties.insert(Animation::Position); + m_properties.insert(Animation::Angle); } Animation::Type GetType() const override { return Animation::Arrow; } - uint32_t GetMask(uint32_t object) const override + TAnimObjects const & GetObjects() const override { - return (object & kArrowAnimObjBit) && - ((m_angleInterpolator != nullptr ? kRotateAnimationBit : 0) | - (m_positionInterpolator != nullptr ? kMoveAnimationBit : 0)); + return m_objects; } - - uint32_t GetObjects() const override + bool HasObject(TObject object) const override { - return kArrowAnimObjBit; + return object == Animation::MyPositionArrow; } + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; void Advance(double elapsedSeconds) override; private: drape_ptr m_positionInterpolator; drape_ptr m_angleInterpolator; + TAnimObjects m_objects; + TObjectProperties m_properties; }; class PerspectiveSwitchAnimation : public Animation @@ -194,21 +204,23 @@ class PerspectiveSwitchAnimation : public Animation Animation::Type GetType() const override { return Animation::Perspective; } - uint32_t GetMask(uint32_t object) const override + TAnimObjects const & GetObjects() const override { - return (object & kPlaneAnimObjBit) && - (m_angleInterpolator != nullptr ? kPerspectiveAnimationBit : 0); + return m_objects; } - - uint32_t GetObjects() const override + bool HasObject(TObject object) const override { - return kPlaneAnimObjBit; + return m_objects.find(object) != m_objects.end(); } + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; void Advance(double elapsedSeconds) override; private: drape_ptr m_angleInterpolator; + TAnimObjects m_objects; + TObjectProperties m_properties; }; class FollowAnimation : public Animation @@ -225,18 +237,16 @@ public: Animation::Type GetType() const override { return Animation::ModelView; } - uint32_t GetMask(uint32_t object) const override + TAnimObjects const & GetObjects() const override { - return (object & kPlaneAnimObjBit) ? - ((m_angleInterpolator != nullptr ? kPerspectiveAnimationBit : 0) | - (m_positionInterpolator != nullptr ? kMoveAnimationBit : 0) | - (m_scaleInterpolator != nullptr ? kScaleAnimationBit : 0)) : 0; + return m_objects; } - - uint32_t GetObjects() const override + bool HasObject(TObject object) const override { - return kPlaneAnimObjBit; + return object == Animation::MapPlane; } + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; void Advance(double elapsedSeconds) override; @@ -244,26 +254,26 @@ public: double GetDuration() const override; bool IsFinished() const override; - double GetScale(uint32_t object) const override; - double GetAngle(uint32_t object) const override; - m2::PointD GetPosition(uint32_t object) const override; + TPropValue GetProperty(TObject object, TProperty property) const override; private: drape_ptr m_angleInterpolator; drape_ptr m_positionInterpolator; drape_ptr m_scaleInterpolator; + TObjectProperties m_properties; + TAnimObjects m_objects; }; -using TAnimations = vector>; - class SequenceAnimation : public Animation { public: Animation::Type GetType() const override { return Animation::Sequence; } - uint32_t GetMask(uint32_t object) const override; - uint32_t GetObjects() const override; + TAnimObjects const & GetObjects() const override; + bool HasObject(TObject object) const override; + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; - void AddAnimation(ref_ptr animation); + void AddAnimation(drape_ptr && animation); void OnStart() override; void OnFinish() override; @@ -271,17 +281,25 @@ public: void Advance(double elapsedSeconds) override; private: - deque> m_animations; + deque> m_animations; }; class ParallelAnimation : public Animation { public: Animation::Type GetType() const override { return Animation::Parallel; } - uint32_t GetMask(uint32_t object) const override; - uint32_t GetObjects() const override; + TAnimObjects const & GetObjects() const override + { + return m_objects; + } + bool HasObject(TObject object) const override + { + return m_objects.find(object) != m_objects.end(); + } + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; - void AddAnimation(ref_ptr animation); + void AddAnimation(drape_ptr && animation); void OnStart() override; void OnFinish() override; @@ -289,7 +307,9 @@ public: void Advance(double elapsedSeconds) override; private: - TAnimations m_animations; + list> m_animations; + TAnimObjects m_objects; + map m_properties; }; class AnimationSystem : private noncopyable @@ -299,18 +319,25 @@ public: m2::AnyRectD GetRect(ScreenBase const & currentScreen); - bool AnimationExists(Animation::Object object); + bool AnimationExists(Animation::TObject object) const; - void AddAnimation(drape_ptr && animation); + void AddAnimation(drape_ptr && animation, bool force); + void PushAnimation(drape_ptr && animation); void Advance(double elapsedSeconds); private: - AnimationSystem() {} + Animation::TPropValue GetProperty(Animation::TObject object, Animation::TProperty property, Animation::TPropValue current) const; + void SaveAnimationResult(Animation const & animation); + + AnimationSystem(); private: - - set> m_animations; + using TAnimationList = list>; + using TAnimationChain = deque; + using TPropertyCache = map, Animation::TPropValue>; + TAnimationChain m_animationChain; + mutable TPropertyCache m_propertyCache; }; } diff --git a/drape_frontend/my_position_controller.cpp b/drape_frontend/my_position_controller.cpp index 27992cf31c..4c79521a90 100644 --- a/drape_frontend/my_position_controller.cpp +++ b/drape_frontend/my_position_controller.cpp @@ -568,9 +568,9 @@ void MyPositionController::CheckAnimFinished() const void MyPositionController::AnimationStarted(ref_ptr anim) { - if (m_isPendingAnimation && m_animCreator != nullptr && anim != nullptr && - (anim->GetType() == ModelViewAnimationType::FollowAndRotate || - anim->GetType() == ModelViewAnimationType::Default)) + if (m_isPendingAnimation && m_animCreator != nullptr)// && anim != nullptr && + // (anim->GetType() == ModelViewAnimationType::FollowAndRotate || + // anim->GetType() == ModelViewAnimationType::Default)) { m_isPendingAnimation = false; m_animCreator(); diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 8ca230b11a..fda9f13b2d 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -340,7 +340,7 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, anim->SetMaxDuration(kMaxAnimationTimeSec); if (df::IsAnimationAllowed(anim->GetDuration(), startScreen)) { - AnimationSystem::Instance().AddAnimation(move(anim)); + AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); return false; } @@ -463,7 +463,16 @@ 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)); + drape_ptr anim = make_unique_dp(); + anim->SetRotate(startRect.Angle().val(), endRect.Angle().val()); + anim->SetMove(startRect.GlobalCenter(), endRect.GlobalCenter(), GetCurrentScreen()); + m2::RectD pixelRect = GetCurrentScreen().PixelRect(); + anim->SetScale(max(startRect.GetLocalRect().SizeX() / pixelRect.SizeX(), + startRect.GetLocalRect().SizeY() / pixelRect.SizeY()), + max(endRect.GetLocalRect().SizeX() / pixelRect.SizeX(), + endRect.GetLocalRect().SizeY() / pixelRect.SizeY())); + AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); + //m_animation.reset(new ModelViewAnimation(startRect, endRect, aDuration, mDuration, sDuration)); if (m_listener) m_listener->OnAnimationStarted(make_ref(m_animation)); }); @@ -525,15 +534,21 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD 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(), newCenter, screen); - double const duration = max(angleDuration, moveDuration); - if (df::IsAnimationAllowed(duration, 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); + + drape_ptr anim = make_unique_dp(); + anim->SetRotate(startRect.Angle().val(), -azimuth); + anim->SetMove(startRect.GlobalZero(), newCenter, screen); + + if (df::IsAnimationAllowed(anim->GetDuration(), screen)) { - m_animation.reset(new FollowAndRotateAnimation(startRect, targetLocalRect, userPos, - screen.GtoP(userPos), pixelPos, azimuth, duration)); + AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); + //m_animation.reset(new FollowAndRotateAnimation(startRect, targetLocalRect, userPos, + // screen.GtoP(userPos), pixelPos, azimuth, duration)); if (m_listener) - m_listener->OnAnimationStarted(make_ref(m_animation)); + m_listener->OnAnimationStarted(make_ref(nullptr/*m_animation*/)); return false; } } From 83cccde2f578f7cf93e59225df58dbd30167373b Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Wed, 20 Apr 2016 16:12:43 +0300 Subject: [PATCH 03/13] New scale and follow animations. --- drape_frontend/animation_system.cpp | 219 +++++++++++++++++++++++++-- drape_frontend/animation_system.h | 101 +++++++++++- drape_frontend/user_event_stream.cpp | 26 +--- 3 files changed, 305 insertions(+), 41 deletions(-) diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index 6a1649f963..747806cfb7 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -80,6 +80,11 @@ void Interpolator::SetMaxDuration(double maxDuration) m_duration = min(m_duration, maxDuration); } +void Interpolator::SetMinDuration(double minDuration) +{ + m_duration = max(m_duration, minDuration); +} + double Interpolator::GetT() const { if (IsFinished()) @@ -100,18 +105,22 @@ double Interpolator::GetDuration() const //static double PositionInterpolator::GetMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor) +{ + return GetPixelMoveDuration(convertor.GtoP(startPosition), convertor.GtoP(endPosition), convertor.PixelRectIn3d()); +} + +double PositionInterpolator::GetPixelMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect) { double const kMinMoveDuration = 0.2; double const kMinSpeedScalar = 0.2; double const kMaxSpeedScalar = 7.0; double const kEps = 1e-5; - m2::RectD const & dispPxRect = convertor.PixelRect(); - double const pixelLength = convertor.GtoP(endPosition).Length(convertor.GtoP(startPosition)); + double const pixelLength = endPosition.Length(startPosition); if (pixelLength < kEps) return 0.0; - double const minSize = min(dispPxRect.SizeX(), dispPxRect.SizeY()); + double const minSize = min(pixelRect.SizeX(), pixelRect.SizeY()); if (pixelLength < kMinSpeedScalar * minSize) return kMinMoveDuration; @@ -119,6 +128,15 @@ double PositionInterpolator::GetMoveDuration(m2::PointD const & startPosition, m return CalcAnimSpeedDuration(pixelLength, pixelSpeed); } +PositionInterpolator::PositionInterpolator(double duration, double delay, m2::PointD const & startPosition, m2::PointD const & endPosition) + : Interpolator(duration, delay) + , m_startPosition(startPosition) + , m_endPosition(endPosition) + , m_position(startPosition) +{ + +} + PositionInterpolator::PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor) : PositionInterpolator(0.0 /* delay */, startPosition, endPosition, convertor) { @@ -133,6 +151,21 @@ PositionInterpolator::PositionInterpolator(double delay, m2::PointD const & star } +PositionInterpolator::PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect) + : PositionInterpolator(0.0 /* delay */, startPosition, endPosition, pixelRect) +{ + +} + +PositionInterpolator::PositionInterpolator(double delay, m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect) + : Interpolator(PositionInterpolator::GetPixelMoveDuration(startPosition, endPosition, pixelRect), delay) + , m_startPosition(startPosition) + , m_endPosition(endPosition) + , m_position(startPosition) +{ + +} + void PositionInterpolator::Advance(double elapsedSeconds) { TBase::Advance(elapsedSeconds); @@ -142,7 +175,9 @@ void PositionInterpolator::Advance(double elapsedSeconds) // static double AngleInterpolator::GetRotateDuration(double startAngle, double endAngle) { - return 0.5 * fabs(endAngle - startAngle) / math::pi4; + double const kRotateDurationScalar = 0.75; + + return kRotateDurationScalar * fabs(ang::GetShortestDistance(startAngle, endAngle)) / math::pi; } AngleInterpolator::AngleInterpolator(double startAngle, double endAngle) @@ -195,7 +230,7 @@ void ScaleInterpolator::Advance(double elapsedSeconds) m_scale = InterpolateDouble(m_startScale, m_endScale, GetT()); } -FollowAnimation::FollowAnimation(m2::PointD const & startPos, m2::PointD const & endPos, +MapLinearAnimation::MapLinearAnimation(m2::PointD const & startPos, m2::PointD const & endPos, double startAngle, double endAngle, double startScale, double endScale, ScreenBase const & convertor) : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) @@ -206,13 +241,13 @@ FollowAnimation::FollowAnimation(m2::PointD const & startPos, m2::PointD const & SetScale(startScale, endScale); } -FollowAnimation::FollowAnimation() +MapLinearAnimation::MapLinearAnimation() : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) { m_objects.insert(Animation::MapPlane); } -void FollowAnimation::SetMove(m2::PointD const & startPos, m2::PointD const & endPos, +void MapLinearAnimation::SetMove(m2::PointD const & startPos, m2::PointD const & endPos, ScreenBase const & convertor) { if (startPos != endPos) @@ -222,7 +257,7 @@ void FollowAnimation::SetMove(m2::PointD const & startPos, m2::PointD const & en } } -void FollowAnimation::SetRotate(double startAngle, double endAngle) +void MapLinearAnimation::SetRotate(double startAngle, double endAngle) { if (startAngle != endAngle) { @@ -231,7 +266,7 @@ void FollowAnimation::SetRotate(double startAngle, double endAngle) } } -void FollowAnimation::SetScale(double startScale, double endScale) +void MapLinearAnimation::SetScale(double startScale, double endScale) { if (startScale != endScale) { @@ -240,18 +275,18 @@ void FollowAnimation::SetScale(double startScale, double endScale) } } -Animation::TObjectProperties const & FollowAnimation::GetProperties(TObject object) const +Animation::TObjectProperties const & MapLinearAnimation::GetProperties(TObject object) const { ASSERT(object == Animation::MapPlane, ()); return m_properties; } -bool FollowAnimation::HasProperty(TObject object, TProperty property) const +bool MapLinearAnimation::HasProperty(TObject object, TProperty property) const { return HasObject(object) && m_properties.find(property) != m_properties.end(); } -void FollowAnimation::Advance(double elapsedSeconds) +void MapLinearAnimation::Advance(double elapsedSeconds) { if (m_angleInterpolator != nullptr) m_angleInterpolator->Advance(elapsedSeconds); @@ -261,7 +296,7 @@ void FollowAnimation::Advance(double elapsedSeconds) m_positionInterpolator->Advance(elapsedSeconds); } -void FollowAnimation::SetMaxDuration(double maxDuration) +void MapLinearAnimation::SetMaxDuration(double maxDuration) { if (m_angleInterpolator != nullptr) m_angleInterpolator->SetMaxDuration(maxDuration); @@ -271,7 +306,7 @@ void FollowAnimation::SetMaxDuration(double maxDuration) m_positionInterpolator->SetMaxDuration(maxDuration); } -double FollowAnimation::GetDuration() const +double MapLinearAnimation::GetDuration() const { double duration = 0; if (m_angleInterpolator != nullptr) @@ -283,14 +318,14 @@ double FollowAnimation::GetDuration() const return duration; } -bool FollowAnimation::IsFinished() const +bool MapLinearAnimation::IsFinished() const { return ((m_angleInterpolator == nullptr || m_angleInterpolator->IsFinished()) && (m_scaleInterpolator == nullptr || m_scaleInterpolator->IsFinished()) && (m_positionInterpolator == nullptr || m_positionInterpolator->IsFinished())); } -Animation::TPropValue FollowAnimation::GetProperty(TObject object, TProperty property) const +Animation::TPropValue MapLinearAnimation::GetProperty(TObject object, TProperty property) const { ASSERT(object == Animation::MapPlane, ()); @@ -318,6 +353,157 @@ Animation::TPropValue FollowAnimation::GetProperty(TObject object, TProperty pro return 0.0; } +MapScaleAnimation::MapScaleAnimation(double startScale, double endScale, + m2::PointD const & globalPosition, m2::PointD const & offset) + : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) + , m_pixelOffset(offset) + , m_globalPosition(globalPosition) +{ + m_scaleInterpolator = make_unique_dp(startScale, endScale); + m_objects.insert(Animation::MapPlane); + m_properties.insert(Animation::Scale); + m_properties.insert(Animation::Position); +} + +Animation::TObjectProperties const & MapScaleAnimation::GetProperties(TObject object) const +{ + ASSERT(object == Animation::MapPlane, ()); + return m_properties; +} + +bool MapScaleAnimation::HasProperty(TObject object, TProperty property) const +{ + return HasObject(object) && m_properties.find(property) != m_properties.end(); +} + +void MapScaleAnimation::Advance(double elapsedSeconds) +{ + m_scaleInterpolator->Advance(elapsedSeconds); +} + +void MapScaleAnimation::SetMaxDuration(double maxDuration) +{ + m_scaleInterpolator->SetMaxDuration(maxDuration); +} + +double MapScaleAnimation::GetDuration() const +{ + return m_scaleInterpolator->GetDuration(); +} + +bool MapScaleAnimation::IsFinished() const +{ + return m_scaleInterpolator->IsFinished(); +} + +Animation::TPropValue MapScaleAnimation::GetProperty(TObject object, TProperty property) const +{ + + if (property == Animation::Position) + { + ScreenBase screen = AnimationSystem::Instance().GetLastScreen(); + screen.SetScale(m_scaleInterpolator->GetScale()); + return screen.PtoG(screen.GtoP(m_globalPosition) + m_pixelOffset); + } + if (property == Animation::Scale) + { + return m_scaleInterpolator->GetScale(); + } + ASSERT(!"Wrong property", ()); + return 0.0; +} + +MapFollowAnimation::MapFollowAnimation(m2::PointD const & globalPosition, + double startScale, double endScale, + double startAngle, double endAngle, + m2::PointD const & startPixelPosition, m2::PointD const & endPixelPosition, + m2::RectD const & pixelRect) + : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) + , m_globalPosition(globalPosition) +{ + m_scaleInterpolator = make_unique_dp(startScale, endScale); + m_angleInterpolator = make_unique_dp(startAngle, endAngle); + m_pixelPosInterpolator = make_unique_dp(startPixelPosition, endPixelPosition, pixelRect); + double const duration = GetDuration(); + m_scaleInterpolator->SetMinDuration(duration); + m_angleInterpolator->SetMinDuration(duration); + m_pixelPosInterpolator->SetMinDuration(duration); + + m_objects.insert(Animation::MapPlane); + m_properties.insert(Animation::Scale); + m_properties.insert(Animation::Angle); + m_properties.insert(Animation::Position); +} + +Animation::TObjectProperties const & MapFollowAnimation::GetProperties(TObject object) const +{ + ASSERT(object == Animation::MapPlane, ()); + return m_properties; +} + +bool MapFollowAnimation::HasProperty(TObject object, TProperty property) const +{ + return HasObject(object) && m_properties.find(property) != m_properties.end(); +} + +void MapFollowAnimation::Advance(double elapsedSeconds) +{ + m_angleInterpolator->Advance(elapsedSeconds); + m_scaleInterpolator->Advance(elapsedSeconds); + m_pixelPosInterpolator->Advance(elapsedSeconds); +} + +void MapFollowAnimation::SetMaxDuration(double maxDuration) +{ + m_angleInterpolator->SetMaxDuration(maxDuration); + m_scaleInterpolator->SetMaxDuration(maxDuration); + m_pixelPosInterpolator->SetMaxDuration(maxDuration); +} + +double MapFollowAnimation::GetDuration() const +{ + double duration = 0.0; + if (m_pixelPosInterpolator != nullptr) + duration = m_angleInterpolator->GetDuration(); + if (m_angleInterpolator != nullptr) + duration = max(duration, m_angleInterpolator->GetDuration()); + if (m_scaleInterpolator != nullptr) + duration = max(duration, m_scaleInterpolator->GetDuration()); + return duration; +} + +bool MapFollowAnimation::IsFinished() const +{ + return ((m_pixelPosInterpolator == nullptr || m_pixelPosInterpolator->IsFinished()) + && (m_angleInterpolator == nullptr || m_angleInterpolator->IsFinished()) + && (m_scaleInterpolator == nullptr || m_scaleInterpolator->IsFinished())); +} + +Animation::TPropValue MapFollowAnimation::GetProperty(TObject object, TProperty property) const +{ + + if (property == Animation::Position) + { + m2::RectD const pixelRect = AnimationSystem::Instance().GetLastScreen().PixelRect(); + m2::PointD const pixelPos = m_pixelPosInterpolator->GetPosition(); + m2::PointD formingVector = (pixelRect.Center() - pixelPos) * m_scaleInterpolator->GetScale(); + formingVector.y = -formingVector.y; + formingVector.Rotate(m_angleInterpolator->GetAngle()); + return m_globalPosition + formingVector; + } + if (property == Animation::Angle) + { + return m_angleInterpolator->GetAngle(); + } + if (property == Animation::Scale) + { + return m_scaleInterpolator->GetScale(); + } + ASSERT(!"Wrong property", ()); + return 0.0; +} + + Animation::TObjectProperties const & ParallelAnimation::GetProperties(TObject object) const { ASSERT(HasObject(object), ()); @@ -432,6 +618,7 @@ AnimationSystem::AnimationSystem() m2::AnyRectD AnimationSystem::GetRect(ScreenBase const & currentScreen) { const Animation::TObject obj = Animation::MapPlane; + m_lastScreen = make_unique_dp(currentScreen); double scale = boost::get( GetProperty(obj, Animation::Scale, currentScreen.GetScale())); double angle = boost::get( diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.h index 1d5370bcd0..c3b6238794 100644 --- a/drape_frontend/animation_system.h +++ b/drape_frontend/animation_system.h @@ -22,8 +22,10 @@ public: { Sequence, Parallel, - ModelView, - Perspective, + MapLinear, + MapScale, + MapFollow, + MapPerspective, Arrow }; @@ -90,6 +92,7 @@ public: bool IsFinished() const; virtual void Advance(double elapsedSeconds); void SetMaxDuration(double maxDuration); + void SetMinDuration(double minDuration); double GetDuration() const; protected: @@ -108,10 +111,14 @@ class PositionInterpolator: public Interpolator using TBase = Interpolator; public: + PositionInterpolator(double duration, double delay, m2::PointD const & startPosition, m2::PointD const & endPosition); PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor); PositionInterpolator(double delay, m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor); + PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect); + PositionInterpolator(double delay, m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect); static double GetMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor); + static double GetPixelMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect); void Advance(double elapsedSeconds) override; virtual m2::PointD GetPosition() const { return m_position; } @@ -202,7 +209,7 @@ class PerspectiveSwitchAnimation : public Animation : Animation(false, false) {} - Animation::Type GetType() const override { return Animation::Perspective; } + Animation::Type GetType() const override { return Animation::MapPerspective; } TAnimObjects const & GetObjects() const override { @@ -223,19 +230,19 @@ private: TObjectProperties m_properties; }; -class FollowAnimation : public Animation +class MapLinearAnimation : public Animation { public: - FollowAnimation(m2::PointD const & startPos, m2::PointD const & endPos, + MapLinearAnimation(m2::PointD const & startPos, m2::PointD const & endPos, double startAngle, double endAngle, double startScale, double endScale, ScreenBase const & convertor); - FollowAnimation(); + MapLinearAnimation(); void SetMove(m2::PointD const & startPos, m2::PointD const & endPos, ScreenBase const & convertor); void SetRotate(double startAngle, double endAngle); void SetScale(double startScale, double endScale); - Animation::Type GetType() const override { return Animation::ModelView; } + Animation::Type GetType() const override { return Animation::MapLinear; } TAnimObjects const & GetObjects() const override { @@ -264,6 +271,82 @@ private: TAnimObjects m_objects; }; +class MapScaleAnimation : public Animation +{ +public: + MapScaleAnimation(double startScale, double endScale, + m2::PointD const & globalPosition, m2::PointD const & offset); + + Animation::Type GetType() const override { return Animation::MapScale; } + + TAnimObjects const & GetObjects() const override + { + return m_objects; + } + bool HasObject(TObject object) const override + { + return object == Animation::MapPlane; + } + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; + + void Advance(double elapsedSeconds) override; + + void SetMaxDuration(double maxDuration) override; + double GetDuration() const override; + bool IsFinished() const override; + + TPropValue GetProperty(TObject object, TProperty property) const override; + +private: + drape_ptr m_scaleInterpolator; + m2::PointD const m_pixelOffset; + m2::PointD const m_globalPosition; + TObjectProperties m_properties; + TAnimObjects m_objects; +}; + +class MapFollowAnimation : public Animation +{ +public: + MapFollowAnimation(m2::PointD const & globalPosition, + double startScale, double endScale, + double startAngle, double endAngle, + m2::PointD const & startPixelPosition, m2::PointD const & endPixelPosition, + m2::RectD const & pixelRect); + + Animation::Type GetType() const override { return Animation::MapFollow; } + + TAnimObjects const & GetObjects() const override + { + return m_objects; + } + bool HasObject(TObject object) const override + { + return object == Animation::MapPlane; + } + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; + + void Advance(double elapsedSeconds) override; + + void SetMaxDuration(double maxDuration) override; + double GetDuration() const override; + bool IsFinished() const override; + + TPropValue GetProperty(TObject object, TProperty property) const override; + +private: + drape_ptr m_scaleInterpolator; + drape_ptr m_pixelPosInterpolator; + drape_ptr m_angleInterpolator; + + m2::PointD const m_globalPosition; + + TObjectProperties m_properties; + TAnimObjects m_objects; +}; + class SequenceAnimation : public Animation { public: @@ -326,6 +409,8 @@ public: void Advance(double elapsedSeconds); + ScreenBase const & GetLastScreen() { return *m_lastScreen.get(); } + private: Animation::TPropValue GetProperty(Animation::TObject object, Animation::TProperty property, Animation::TPropValue current) const; void SaveAnimationResult(Animation const & animation); @@ -338,6 +423,8 @@ private: using TPropertyCache = map, Animation::TPropValue>; TAnimationChain m_animationChain; mutable TPropertyCache m_propertyCache; + + drape_ptr m_lastScreen; }; } diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index fda9f13b2d..b797bcb385 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -333,11 +333,8 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, ScreenBase endScreen = startScreen; m_navigator.CalculateScale(scaleCenter, factor, endScreen); - drape_ptr anim = make_unique_dp(); - anim->SetScale(startScreen.GetScale(), endScreen.GetScale()); - anim->SetMove(startScreen.GlobalRect().GlobalZero(), - endScreen.GlobalRect().GlobalZero(), startScreen); - anim->SetMaxDuration(kMaxAnimationTimeSec); + drape_ptr anim = make_unique_dp(startScreen.GetScale(), endScreen.GetScale(), + glbScaleCenter, offset); if (df::IsAnimationAllowed(anim->GetDuration(), startScreen)) { AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); @@ -463,7 +460,7 @@ 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) { - drape_ptr anim = make_unique_dp(); + drape_ptr anim = make_unique_dp(); anim->SetRotate(startRect.Angle().val(), endRect.Angle().val()); anim->SetMove(startRect.GlobalCenter(), endRect.GlobalCenter(), GetCurrentScreen()); m2::RectD pixelRect = GetCurrentScreen().PixelRect(); @@ -531,22 +528,15 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD 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(), newCenter, screen); - //double const duration = max(angleDuration, moveDuration); - - drape_ptr anim = make_unique_dp(); - anim->SetRotate(startRect.Angle().val(), -azimuth); - anim->SetMove(startRect.GlobalZero(), newCenter, screen); + double targetScale = max(targetLocalRect.SizeX() / screen.PixelRect().SizeX(), + targetLocalRect.SizeY() / screen.PixelRect().SizeY()); + drape_ptr anim = make_unique_dp(userPos, screen.GetScale(), targetScale, + screen.GetAngle(), -azimuth, + screen.GtoP(userPos), pixelPos, screen.PixelRectIn3d()); if (df::IsAnimationAllowed(anim->GetDuration(), screen)) { AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); - //m_animation.reset(new FollowAndRotateAnimation(startRect, targetLocalRect, userPos, - // screen.GtoP(userPos), pixelPos, azimuth, duration)); if (m_listener) m_listener->OnAnimationStarted(make_ref(nullptr/*m_animation*/)); return false; From 8412a44ed713f225f6b0c5f94594d15807e5e3ab Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Thu, 21 Apr 2016 02:39:00 +0300 Subject: [PATCH 04/13] Perspective animation. --- drape_frontend/animation_system.cpp | 225 ++++++++++++++++++++++++--- drape_frontend/animation_system.h | 89 +++++++++-- drape_frontend/frontend_renderer.cpp | 5 +- drape_frontend/user_event_stream.cpp | 128 +++++++-------- drape_frontend/user_event_stream.hpp | 8 +- 5 files changed, 348 insertions(+), 107 deletions(-) diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index 747806cfb7..f52e753446 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -3,9 +3,6 @@ #include "base/logging.hpp" -#include "boost/variant/variant.hpp" -#include "boost/variant/get.hpp" - namespace df { @@ -75,6 +72,11 @@ void Interpolator::Advance(double elapsedSeconds) m_elapsedTime += elapsedSeconds; } +void Interpolator::Finish() +{ + m_elapsedTime = m_duration + m_delay + 1.0; +} + void Interpolator::SetMaxDuration(double maxDuration) { m_duration = min(m_duration, maxDuration); @@ -172,6 +174,12 @@ void PositionInterpolator::Advance(double elapsedSeconds) m_position = InterpolatePoint(m_startPosition, m_endPosition, GetT()); } +void PositionInterpolator::Finish() +{ + TBase::Finish(); + m_position = m_endPosition; +} + // static double AngleInterpolator::GetRotateDuration(double startAngle, double endAngle) { @@ -199,6 +207,12 @@ void AngleInterpolator::Advance(double elapsedSeconds) m_angle = InterpolateDouble(m_startAngle, m_endAngle, GetT()); } +void AngleInterpolator::Finish() +{ + TBase::Finish(); + m_angle = m_endAngle; +} + // static double ScaleInterpolator::GetScaleDuration(double startScale, double endScale) { @@ -230,6 +244,12 @@ void ScaleInterpolator::Advance(double elapsedSeconds) m_scale = InterpolateDouble(m_startScale, m_endScale, GetT()); } +void ScaleInterpolator::Finish() +{ + TBase::Finish(); + m_scale = m_endScale; +} + MapLinearAnimation::MapLinearAnimation(m2::PointD const & startPos, m2::PointD const & endPos, double startAngle, double endAngle, double startScale, double endScale, ScreenBase const & convertor) @@ -296,6 +316,17 @@ void MapLinearAnimation::Advance(double elapsedSeconds) m_positionInterpolator->Advance(elapsedSeconds); } +void MapLinearAnimation::Finish() +{ + if (m_angleInterpolator != nullptr) + m_angleInterpolator->Finish(); + if (m_scaleInterpolator != nullptr) + m_scaleInterpolator->Finish(); + if (m_positionInterpolator != nullptr) + m_positionInterpolator->Finish(); + Animation::Finish(); +} + void MapLinearAnimation::SetMaxDuration(double maxDuration) { if (m_angleInterpolator != nullptr) @@ -325,7 +356,7 @@ bool MapLinearAnimation::IsFinished() const && (m_positionInterpolator == nullptr || m_positionInterpolator->IsFinished())); } -Animation::TPropValue MapLinearAnimation::GetProperty(TObject object, TProperty property) const +Animation::PropertyValue MapLinearAnimation::GetProperty(TObject object, TProperty property) const { ASSERT(object == Animation::MapPlane, ()); @@ -381,6 +412,12 @@ void MapScaleAnimation::Advance(double elapsedSeconds) m_scaleInterpolator->Advance(elapsedSeconds); } +void MapScaleAnimation::Finish() +{ + m_scaleInterpolator->Finish(); + Animation::Finish(); +} + void MapScaleAnimation::SetMaxDuration(double maxDuration) { m_scaleInterpolator->SetMaxDuration(maxDuration); @@ -396,7 +433,7 @@ bool MapScaleAnimation::IsFinished() const return m_scaleInterpolator->IsFinished(); } -Animation::TPropValue MapScaleAnimation::GetProperty(TObject object, TProperty property) const +Animation::PropertyValue MapScaleAnimation::GetProperty(TObject object, TProperty property) const { if (property == Animation::Position) @@ -453,6 +490,14 @@ void MapFollowAnimation::Advance(double elapsedSeconds) m_pixelPosInterpolator->Advance(elapsedSeconds); } +void MapFollowAnimation::Finish() +{ + m_angleInterpolator->Finish(); + m_scaleInterpolator->Finish(); + m_pixelPosInterpolator->Finish(); + Animation::Finish(); +} + void MapFollowAnimation::SetMaxDuration(double maxDuration) { m_angleInterpolator->SetMaxDuration(maxDuration); @@ -479,7 +524,7 @@ bool MapFollowAnimation::IsFinished() const && (m_scaleInterpolator == nullptr || m_scaleInterpolator->IsFinished())); } -Animation::TPropValue MapFollowAnimation::GetProperty(TObject object, TProperty property) const +Animation::PropertyValue MapFollowAnimation::GetProperty(TObject object, TProperty property) const { if (property == Animation::Position) @@ -503,6 +548,66 @@ Animation::TPropValue MapFollowAnimation::GetProperty(TObject object, TProperty return 0.0; } +PerspectiveSwitchAnimation::PerspectiveSwitchAnimation(double startAngle, double endAngle) + : Animation(false, false) +{ + m_angleInterpolator = make_unique_dp(startAngle, endAngle); + m_objects.insert(Animation::MapPlane); + m_properties.insert(Animation::AnglePerspective); +} + +Animation::TObjectProperties const & PerspectiveSwitchAnimation::GetProperties(TObject object) const +{ + ASSERT(object == Animation::MapPlane, ()); + return m_properties; +} + +bool PerspectiveSwitchAnimation::HasProperty(TObject object, TProperty property) const +{ + return HasObject(object) && m_properties.find(property) != m_properties.end(); +} + +void PerspectiveSwitchAnimation::Advance(double elapsedSeconds) +{ + m_angleInterpolator->Advance(elapsedSeconds); +} + +void PerspectiveSwitchAnimation::Finish() +{ + m_angleInterpolator->Finish(); + Animation::Finish(); +} + +void PerspectiveSwitchAnimation::SetMaxDuration(double maxDuration) +{ + m_angleInterpolator->SetMaxDuration(maxDuration); +} + +double PerspectiveSwitchAnimation::GetDuration() const +{ + return m_angleInterpolator->GetDuration(); +} + +bool PerspectiveSwitchAnimation::IsFinished() const +{ + return m_angleInterpolator->IsFinished(); +} + +Animation::PropertyValue PerspectiveSwitchAnimation::GetProperty(TObject object, TProperty property) const +{ + ASSERT(object == Animation::MapPlane, ()); + + switch (property) + { + case Animation::AnglePerspective: + return m_angleInterpolator->GetAngle(); + break; + default: + ASSERT(!"Wrong property", ()); + } + + return 0.0; +} Animation::TObjectProperties const & ParallelAnimation::GetProperties(TObject object) const { @@ -557,6 +662,13 @@ void ParallelAnimation::Advance(double elapsedSeconds) } } +void ParallelAnimation::Finish() +{ + for (auto & anim : m_animations) + anim->Finish(); + Animation::Finish(); +} + Animation::TAnimObjects const & SequenceAnimation::GetObjects() const { ASSERT(!m_animations.empty(), ()); @@ -615,16 +727,19 @@ AnimationSystem::AnimationSystem() } -m2::AnyRectD AnimationSystem::GetRect(ScreenBase const & currentScreen) +double AnimationSystem::GetPerspectiveAngle(double currentAngle) +{ + return GetProperty(Animation::MapPlane, Animation::AnglePerspective, currentAngle).m_valueD; +} + +m2::AnyRectD AnimationSystem::GetRect(ScreenBase const & currentScreen, bool & viewportChanged) { const Animation::TObject obj = Animation::MapPlane; + viewportChanged |= m_lastScreen != nullptr && (m_lastScreen->isPerspective() != currentScreen.isPerspective()); m_lastScreen = make_unique_dp(currentScreen); - double scale = boost::get( - GetProperty(obj, Animation::Scale, currentScreen.GetScale())); - double angle = boost::get( - GetProperty(obj, Animation::Angle, currentScreen.GetAngle())); - m2::PointD pos = boost::get( - GetProperty(obj, Animation::Position, currentScreen.GlobalRect().GlobalZero())); + double scale = GetProperty(obj, Animation::Scale, currentScreen.GetScale()).m_valueD; + double angle = GetProperty(obj, Animation::Angle, currentScreen.GetAngle()).m_valueD; + m2::PointD pos = GetProperty(obj, Animation::Position, currentScreen.GlobalRect().GlobalZero()).m_valuePointD; m2::RectD rect = currentScreen.PixelRect(); rect.Offset(-rect.Center()); rect.Scale(scale); @@ -633,12 +748,13 @@ m2::AnyRectD AnimationSystem::GetRect(ScreenBase const & currentScreen) bool AnimationSystem::AnimationExists(Animation::TObject object) const { - if (m_animationChain.empty()) - return false; - for (auto const & anim : m_animationChain.front()) + if (!m_animationChain.empty()) { - if (anim->HasObject(object)) - return true; + for (auto const & anim : m_animationChain.front()) + { + if (anim->HasObject(object)) + return true; + } } for (auto it = m_propertyCache.begin(); it != m_propertyCache.end(); ++it) { @@ -692,12 +808,65 @@ void AnimationSystem::AddAnimation(drape_ptr && animation, bool force void AnimationSystem::PushAnimation(drape_ptr && animation) { - animation->OnStart(); + if (m_animationChain.empty()) + animation->OnStart(); + TAnimationList list; list.emplace_back(move(animation)); + m_animationChain.emplace_back(move(list)); } +void AnimationSystem::FinishAnimations(Animation::Type type, bool rewind) +{ + if (m_animationChain.empty()) + return; + + TAnimationList & frontList = m_animationChain.front(); + for (auto it = frontList.begin(); it != frontList.end();) + { + auto & anim = *it; + if (anim->GetType() == type) + { + if (rewind) + anim->Finish(); + SaveAnimationResult(*anim); + it = frontList.erase(it); + } + else + { + ++it; + } + } + if (frontList.empty()) + StartNextAnimations(); +} + +void AnimationSystem::FinishObjectAnimations(Animation::TObject object, bool rewind) +{ + if (m_animationChain.empty()) + return; + + TAnimationList & frontList = m_animationChain.front(); + for (auto it = frontList.begin(); it != frontList.end();) + { + auto & anim = *it; + if (anim->HasObject(object)) + { + if (rewind) + anim->Finish(); + SaveAnimationResult(*anim); + it = frontList.erase(it); + } + else + { + ++it; + } + } + if (frontList.empty()) + StartNextAnimations(); +} + void AnimationSystem::Advance(double elapsedSeconds) { if (m_animationChain.empty()) @@ -719,9 +888,11 @@ void AnimationSystem::Advance(double elapsedSeconds) ++it; } } + if (frontList.empty()) + StartNextAnimations(); } -Animation::TPropValue AnimationSystem::GetProperty(Animation::TObject object, Animation::TProperty property, Animation::TPropValue current) const +Animation::PropertyValue AnimationSystem::GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue current) const { if (!m_animationChain.empty()) { @@ -734,7 +905,7 @@ Animation::TPropValue AnimationSystem::GetProperty(Animation::TObject object, An auto it = m_propertyCache.find(make_pair(object, property)); if (it != m_propertyCache.end()) { - Animation::TPropValue value(it->second); + Animation::PropertyValue value(it->second); m_propertyCache.erase(it); return value; } @@ -752,4 +923,16 @@ void AnimationSystem::SaveAnimationResult(Animation const & animation) } } +void AnimationSystem::StartNextAnimations() +{ + m_animationChain.pop_front(); + if (m_animationChain.empty()) + return; + for (auto & anim : m_animationChain.front()) + { + // TODO: use propertyCache to load start values to the next animations + anim->OnStart(); + } +} + } // namespace df diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.h index c3b6238794..9f03206ebb 100644 --- a/drape_frontend/animation_system.h +++ b/drape_frontend/animation_system.h @@ -10,8 +10,6 @@ #include "std/deque.hpp" #include "std/noncopyable.hpp" -#include "boost/variant/variant_fwd.hpp" - namespace df { @@ -40,22 +38,53 @@ public: { Position, Scale, - Angle + Angle, + AnglePerspective + }; + + enum PropertyValueType + { + ValueD, + ValuePointD + }; + + struct PropertyValue + { + PropertyValue() + { + } + + PropertyValue(double value) + : m_type(ValueD), + m_valueD(value) + {} + + PropertyValue(m2::PointD value) + : m_type(ValuePointD), + m_valuePointD(value) + {} + + PropertyValueType m_type; + union + { + m2::PointD m_valuePointD; + double m_valueD; + }; }; using TObject = uint32_t; using TProperty = uint32_t; - using TPropValue = boost::variant; using TAnimObjects = set; using TObjectProperties = set; + using TAction = function; Animation(bool couldBeInterrupted, bool couldBeMixed) : m_couldBeInterrupted(couldBeInterrupted) , m_couldBeMixed(couldBeMixed) {} - virtual void OnStart() {} - virtual void OnFinish() {} + virtual void OnStart() {if (m_onStartAction != nullptr) m_onStartAction(*this);} + virtual void OnFinish() {if (m_onFinishAction != nullptr) m_onFinishAction(*this);} virtual void Interrupt() {} virtual Type GetType() const = 0; @@ -70,8 +99,13 @@ public: virtual bool IsFinished() const = 0; virtual void Advance(double elapsedSeconds) = 0; + virtual void Finish() { OnFinish(); } - virtual TPropValue GetProperty(TObject object, TProperty property) const = 0; + virtual PropertyValue GetProperty(TObject object, TProperty property) const = 0; + + void SetOnStartAction(TAction const & action) { m_onStartAction = action; } + void SetOnFinishAction(TAction const & action) { m_onFinishAction = action; } + void SetOnInterruptAction(TAction const & action) { m_onInterruptAction = action; } bool CouldBeInterrupted() const { return m_couldBeInterrupted; } bool CouldBeMixed() const { return m_couldBeMixed; } @@ -79,6 +113,9 @@ public: bool CouldBeMixedWith(Animation const & animation); protected: + TAction m_onStartAction; + TAction m_onFinishAction; + TAction m_onInterruptAction; bool m_couldBeInterrupted; bool m_couldBeMixed; }; @@ -91,6 +128,7 @@ public: bool IsFinished() const; virtual void Advance(double elapsedSeconds); + virtual void Finish(); void SetMaxDuration(double maxDuration); void SetMinDuration(double minDuration); double GetDuration() const; @@ -121,6 +159,7 @@ public: static double GetPixelMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect); void Advance(double elapsedSeconds) override; + void Finish() override; virtual m2::PointD GetPosition() const { return m_position; } private: @@ -140,6 +179,7 @@ public: static double GetScaleDuration(double startScale, double endScale); void Advance(double elapsedSeconds) override; + void Finish() override; virtual double GetScale() const { return m_scale; } private: @@ -159,6 +199,7 @@ public: static double GetRotateDuration(double startAngle, double endAngle); void Advance(double elapsedSeconds) override; + void Finish() override; virtual double GetAngle() const { return m_angle; } private: @@ -195,6 +236,7 @@ public: bool HasProperty(TObject object, TProperty property) const override; void Advance(double elapsedSeconds) override; + void Finish() override; private: drape_ptr m_positionInterpolator; @@ -205,9 +247,8 @@ private: class PerspectiveSwitchAnimation : public Animation { - PerspectiveSwitchAnimation() - : Animation(false, false) - {} +public: + PerspectiveSwitchAnimation(double startAngle, double endAngle); Animation::Type GetType() const override { return Animation::MapPerspective; } @@ -223,6 +264,13 @@ class PerspectiveSwitchAnimation : public Animation bool HasProperty(TObject object, TProperty property) const override; void Advance(double elapsedSeconds) override; + void Finish() override; + + void SetMaxDuration(double maxDuration) override; + double GetDuration() const override; + bool IsFinished() const override; + + PropertyValue GetProperty(TObject object, TProperty property) const override; private: drape_ptr m_angleInterpolator; @@ -256,12 +304,13 @@ public: bool HasProperty(TObject object, TProperty property) const override; void Advance(double elapsedSeconds) override; + void Finish() override; void SetMaxDuration(double maxDuration) override; double GetDuration() const override; bool IsFinished() const override; - TPropValue GetProperty(TObject object, TProperty property) const override; + PropertyValue GetProperty(TObject object, TProperty property) const override; private: drape_ptr m_angleInterpolator; @@ -291,12 +340,13 @@ public: bool HasProperty(TObject object, TProperty property) const override; void Advance(double elapsedSeconds) override; + void Finish() override; void SetMaxDuration(double maxDuration) override; double GetDuration() const override; bool IsFinished() const override; - TPropValue GetProperty(TObject object, TProperty property) const override; + PropertyValue GetProperty(TObject object, TProperty property) const override; private: drape_ptr m_scaleInterpolator; @@ -329,12 +379,13 @@ public: bool HasProperty(TObject object, TProperty property) const override; void Advance(double elapsedSeconds) override; + void Finish() override; void SetMaxDuration(double maxDuration) override; double GetDuration() const override; bool IsFinished() const override; - TPropValue GetProperty(TObject object, TProperty property) const override; + PropertyValue GetProperty(TObject object, TProperty property) const override; private: drape_ptr m_scaleInterpolator; @@ -388,6 +439,7 @@ public: void OnFinish() override; void Advance(double elapsedSeconds) override; + void Finish() override; private: list> m_animations; @@ -400,27 +452,32 @@ class AnimationSystem : private noncopyable public: static AnimationSystem & Instance(); - m2::AnyRectD GetRect(ScreenBase const & currentScreen); + m2::AnyRectD GetRect(ScreenBase const & currentScreen, bool & viewportChanged); + double GetPerspectiveAngle(double currentAngle); bool AnimationExists(Animation::TObject object) const; void AddAnimation(drape_ptr && animation, bool force); void PushAnimation(drape_ptr && animation); + void FinishAnimations(Animation::Type type, bool rewind); + void FinishObjectAnimations(Animation::TObject object, bool rewind); + void Advance(double elapsedSeconds); ScreenBase const & GetLastScreen() { return *m_lastScreen.get(); } private: - Animation::TPropValue GetProperty(Animation::TObject object, Animation::TProperty property, Animation::TPropValue current) const; + Animation::PropertyValue GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue current) const; void SaveAnimationResult(Animation const & animation); + void StartNextAnimations(); AnimationSystem(); private: using TAnimationList = list>; using TAnimationChain = deque; - using TPropertyCache = map, Animation::TPropValue>; + using TPropertyCache = map, Animation::PropertyValue>; TAnimationChain m_animationChain; mutable TPropertyCache m_propertyCache; diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index a8acdd8f2a..d5c54218c6 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -747,14 +747,15 @@ void FrontendRenderer::FollowRoute(int preferredZoomLevel, int preferredZoomLeve double rotationAngle, double angleFOV) { + m_myPositionController->ActivateRouting(!m_enablePerspectiveInNavigation ? preferredZoomLevel + : preferredZoomLevelIn3d); + if (m_enablePerspectiveInNavigation) { bool immediatelyStart = !m_myPositionController->IsRotationAvailable(); AddUserEvent(EnablePerspectiveEvent(rotationAngle, angleFOV, true /* animated */, immediatelyStart)); } - m_myPositionController->ActivateRouting(!m_enablePerspectiveInNavigation ? preferredZoomLevel - : preferredZoomLevelIn3d); m_overlayTree->SetFollowingMode(true); } diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index b797bcb385..43491875ce 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -145,7 +145,7 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & modelViewChange = !events.empty() || m_state == STATE_SCALE || m_state == STATE_DRAG; for (UserEvent const & e : events) { - if (m_perspectiveAnimation != nullptr && FilterEventWhile3dAnimation(e.m_type)) + if (m_perspectiveAnimation && FilterEventWhile3dAnimation(e.m_type)) continue; bool breakAnim = false; @@ -167,7 +167,7 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & TouchCancel(m_touches); break; case UserEvent::EVENT_SET_RECT: - if (m_perspectiveAnimation != nullptr) + if (m_perspectiveAnimation) { m_pendingEvent.reset(new UserEvent(e.m_rectEvent)); break; @@ -199,26 +199,20 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & } break; case UserEvent::EVENT_FOLLOW_AND_ROTATE: - m_pendingPerspective = false; breakAnim = SetFollowAndRotate(e.m_followAndRotate.m_userPos, e.m_followAndRotate.m_pixelZero, e.m_followAndRotate.m_azimuth, e.m_followAndRotate.m_preferredZoomLevel, e.m_followAndRotate.m_isAnim); TouchCancel(m_touches); break; case UserEvent::EVENT_ENABLE_PERSPECTIVE: - if (!e.m_enable3dMode.m_immediatelyStart) - { - m_pendingPerspective = true; - m_pendingEvent.reset(new UserEvent(e.m_enable3dMode)); - } - else - SetEnable3dMode(e.m_enable3dMode.m_rotationAngle, e.m_enable3dMode.m_angleFOV, - e.m_enable3dMode.m_isAnim, viewportChanged); + SetEnable3dMode(e.m_enable3dMode.m_rotationAngle, e.m_enable3dMode.m_angleFOV, + e.m_enable3dMode.m_isAnim, e.m_enable3dMode.m_immediatelyStart, + viewportChanged); m_discardedFOV = m_discardedAngle = 0.0; break; case UserEvent::EVENT_DISABLE_PERSPECTIVE: if (m_navigator.Screen().isPerspective()) - SetDisable3dModeAnimation(); + SetDisable3dModeAnimation(viewportChanged); m_discardedFOV = m_discardedAngle = 0.0; break; case UserEvent::EVENT_SWITCH_VIEW_MODE: @@ -226,11 +220,12 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & { m_discardedFOV = m_navigator.Screen().GetAngleFOV(); m_discardedAngle = m_navigator.Screen().GetRotationAngle(); - SetDisable3dModeAnimation(); + SetDisable3dModeAnimation(viewportChanged); } else if (m_discardedFOV > 0.0) { - SetEnable3dMode(m_discardedAngle, m_discardedFOV, true /* isAnim */, viewportChanged); + SetEnable3dMode(m_discardedAngle, m_discardedFOV, true /* isAnim */, true /* immediatelyStart */, + viewportChanged); m_discardedFOV = m_discardedAngle = 0.0; } break; @@ -256,44 +251,17 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & } if (AnimationSystem::Instance().AnimationExists(Animation::MapPlane)) { - m2::AnyRectD const rect = AnimationSystem::Instance().GetRect(GetCurrentScreen()); + m2::AnyRectD const rect = AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged); m_navigator.SetFromRect(rect); - modelViewChange = true; - } - if (m_pendingEvent != nullptr && - m_pendingEvent->m_type == UserEvent::EVENT_ENABLE_PERSPECTIVE && - !m_pendingPerspective && m_animation == nullptr) - { - SetEnable3dMode(m_pendingEvent->m_enable3dMode.m_rotationAngle, - m_pendingEvent->m_enable3dMode.m_angleFOV, - m_pendingEvent->m_enable3dMode.m_isAnim, - viewportChanged); - modelViewChange = true; - m_pendingEvent.reset(); - } - - if (m_perspectiveAnimation != nullptr) - { - double const angle = m_perspectiveAnimation->GetRotationAngle(); - m_navigator.SetRotationIn3dMode(angle); - modelViewChange = true; - TouchCancel(m_touches); - - if (m_perspectiveAnimation->IsFinished()) + ScreenBase const & screen = GetCurrentScreen(); + if (screen.isPerspective()) { - if (angle == 0.0) - { - m_navigator.Disable3dMode(); - viewportChanged = true; - - if (m_pendingEvent != nullptr && m_pendingEvent->m_type == UserEvent::EVENT_SET_RECT) - SetRect(m_pendingEvent->m_rectEvent.m_rect, m_pendingEvent->m_rectEvent.m_zoom, - m_pendingEvent->m_rectEvent.m_applyRotation, m_pendingEvent->m_rectEvent.m_isAnim); - } - m_pendingEvent.reset(); - m_perspectiveAnimation.reset(); + double const angle = AnimationSystem::Instance().GetPerspectiveAngle(screen.GetRotationAngle()); + m_navigator.SetRotationIn3dMode(angle); + //TouchCancel(m_touches); } + modelViewChange = true; } if (GetValidTouchesCount(m_touches) == 1) @@ -555,32 +523,64 @@ bool UserEventStream::FilterEventWhile3dAnimation(UserEvent::EEventType type) co type != UserEvent::EVENT_SET_RECT; } -void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, bool isAnim, bool & viewportChanged) +void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, + bool isAnim, bool immediatelyStart, + bool & viewportChanged) { - bool const finishAnimation = m_animation != nullptr && m_animation->GetType() == ModelViewAnimationType::Default; - ResetCurrentAnimation(finishAnimation); + AnimationSystem::Instance().FinishAnimations(Animation::MapLinear, true /* rewind */); + + m_navigator.SetFromRect(AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged)); double const startAngle = isAnim ? 0.0 : maxRotationAngle; - if (isAnim) + double const endAngle = maxRotationAngle; + if (isAnim || !immediatelyStart) { - double const endAngle = maxRotationAngle; - double const rotateDuration = PerspectiveAnimation::GetRotateDuration(startAngle, endAngle); - m_perspectiveAnimation.reset( - new PerspectiveAnimation(rotateDuration, 0.0 /* delay */, startAngle, endAngle)); + drape_ptr anim = make_unique_dp(startAngle, endAngle); + anim->SetOnStartAction([this, startAngle, endAngle, angleFOV](Animation const &) + { + m_perspectiveAnimation = true; + m_navigator.Enable3dMode(startAngle, endAngle, angleFOV); + }); + anim->SetOnFinishAction([this](Animation const &) + { + m_perspectiveAnimation = false; + }); + if (immediatelyStart) + { + //AnimationSystem::Instance().FinishObjectAnimations(Animation::MapPlane, false /* rewind */); + AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); + } + else + AnimationSystem::Instance().PushAnimation(move(anim)); } - m_navigator.Enable3dMode(startAngle, maxRotationAngle, angleFOV); - viewportChanged = true; } -void UserEventStream::SetDisable3dModeAnimation() +void UserEventStream::SetDisable3dModeAnimation(bool & viewportChanged) { - bool const finishAnimation = m_animation != nullptr && m_animation->GetType() == ModelViewAnimationType::Default; - ResetCurrentAnimation(finishAnimation); + AnimationSystem::Instance().FinishAnimations(Animation::MapLinear, true /* rewind */); + //AnimationSystem::Instance().FinishObjectAnimations(Animation::MapPlane, false /* rewind */); + m_navigator.SetFromRect(AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged)); double const startAngle = m_navigator.Screen().GetRotationAngle(); double const endAngle = 0.0; - double const rotateDuration = PerspectiveAnimation::GetRotateDuration(startAngle, endAngle); - m_perspectiveAnimation.reset(new PerspectiveAnimation(rotateDuration, 0.0 /* delay */, startAngle, endAngle)); + + drape_ptr anim = make_unique_dp(startAngle, endAngle); + anim->SetOnStartAction([this](Animation const &) + { + m_perspectiveAnimation = true; + }); + anim->SetOnFinishAction([this](Animation const &) + { + m_perspectiveAnimation = false; + m_navigator.Disable3dMode(); + if (m_pendingEvent != nullptr && m_pendingEvent->m_type == UserEvent::EVENT_SET_RECT) + { + SetRect(m_pendingEvent->m_rectEvent.m_rect, m_pendingEvent->m_rectEvent.m_zoom, + m_pendingEvent->m_rectEvent.m_applyRotation, m_pendingEvent->m_rectEvent.m_isAnim); + m_pendingEvent.reset(); + } + }); + AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); } void UserEventStream::ResetCurrentAnimation(bool finishAnimation) @@ -1160,7 +1160,7 @@ bool UserEventStream::IsWaitingForActionCompletion() const bool UserEventStream::IsInPerspectiveAnimation() const { - return m_perspectiveAnimation != nullptr; + return m_perspectiveAnimation; } void UserEventStream::SetKineticScrollEnabled(bool enabled) diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index e248910851..c589860f3a 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -310,8 +310,9 @@ private: double azimuth, int preferredZoomLevel, bool isAnim); bool FilterEventWhile3dAnimation(UserEvent::EEventType type) const; - void SetEnable3dMode(double maxRotationAngle, double angleFOV, bool isAnim, bool & viewportChanged); - void SetDisable3dModeAnimation(); + void SetEnable3dMode(double maxRotationAngle, double angleFOV, + bool isAnim, bool immediatelyStart, bool & viewportChanged); + void SetDisable3dModeAnimation(bool & viewportChanged); m2::AnyRectD GetCurrentRect() const; @@ -376,8 +377,7 @@ private: drape_ptr m_animation; - unique_ptr m_perspectiveAnimation; - bool m_pendingPerspective = false; + bool m_perspectiveAnimation; unique_ptr m_pendingEvent; double m_discardedFOV = 0.0; double m_discardedAngle = 0.0; From 241775452a88262e69293795fa98be070f12c1c8 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Thu, 21 Apr 2016 04:48:03 +0300 Subject: [PATCH 05/13] Zoom in perspective mode fixed. --- drape_frontend/my_position_controller.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drape_frontend/my_position_controller.cpp b/drape_frontend/my_position_controller.cpp index 4c79521a90..f701e946b2 100644 --- a/drape_frontend/my_position_controller.cpp +++ b/drape_frontend/my_position_controller.cpp @@ -321,7 +321,8 @@ void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool if (m_mode == location::Follow) ChangeModelView(m_position, kDoNotChangeZoom); else if (m_mode == location::FollowAndRotate) - ChangeModelView(m_position, m_drawDirection, GetRotationPixelCenter(), kDoNotChangeZoom); + ChangeModelView(m_position, m_drawDirection, + m_isInRouting ? m_centerPixelPositionRouting : m_centerPixelPosition, kDoNotChangeZoom); } m_isPositionAssigned = true; @@ -518,16 +519,17 @@ void MyPositionController::UpdateViewport() if (m_mode == location::Follow) ChangeModelView(m_position, kDoNotChangeZoom); else if (m_mode == location::FollowAndRotate) - ChangeModelView(m_position, m_drawDirection, GetRotationPixelCenter(), kDoNotChangeZoom); + ChangeModelView(m_position, m_drawDirection, + m_isInRouting ? m_centerPixelPositionRouting : m_centerPixelPosition, kDoNotChangeZoom); } m2::PointD MyPositionController::GetRotationPixelCenter() const { if (m_mode == location::Follow) - return m_centerPixelPosition; + return m_pixelRect.Center(); if (m_mode == location::FollowAndRotate) - return m_isInRouting ? m_centerPixelPositionRouting : m_centerPixelPosition; + return m_isInRouting ? GetRoutingRotationPixelCenter() : m_pixelRect.Center(); return m2::PointD::Zero(); } @@ -609,7 +611,7 @@ void MyPositionController::ActivateRouting(int zoomLevel) if (IsRotationAvailable()) { ChangeMode(location::FollowAndRotate); - ChangeModelView(m_position, m_drawDirection, GetRotationPixelCenter(), zoomLevel); + ChangeModelView(m_position, m_drawDirection, m_centerPixelPositionRouting, zoomLevel); } else { From 621f187fe6df06dc8ba2ad4fcf3c73744880da3e Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Thu, 21 Apr 2016 15:11:58 +0300 Subject: [PATCH 06/13] Perspective enabling fixed. --- drape_frontend/animation_system.cpp | 16 +++++++++- drape_frontend/animation_system.h | 3 ++ drape_frontend/user_event_stream.cpp | 45 ++++++++++++++-------------- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index f52e753446..63e92679f5 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -201,6 +201,14 @@ AngleInterpolator::AngleInterpolator(double delay, double startAngle, double end { } +AngleInterpolator::AngleInterpolator(double delay, double duration, double startAngle, double endAngle) + : Interpolator(duration, delay) + , m_startAngle(startAngle) + , m_endAngle(endAngle) + , m_angle(startAngle) +{ +} + void AngleInterpolator::Advance(double elapsedSeconds) { TBase::Advance(elapsedSeconds); @@ -551,11 +559,17 @@ Animation::PropertyValue MapFollowAnimation::GetProperty(TObject object, TProper PerspectiveSwitchAnimation::PerspectiveSwitchAnimation(double startAngle, double endAngle) : Animation(false, false) { - m_angleInterpolator = make_unique_dp(startAngle, endAngle); + m_angleInterpolator = make_unique_dp(GetRotateDuration(startAngle, endAngle), startAngle, endAngle); m_objects.insert(Animation::MapPlane); m_properties.insert(Animation::AnglePerspective); } +// static +double PerspectiveSwitchAnimation::GetRotateDuration(double startAngle, double endAngle) +{ + return 0.5 * fabs(endAngle - startAngle) / math::pi4; +} + Animation::TObjectProperties const & PerspectiveSwitchAnimation::GetProperties(TObject object) const { ASSERT(object == Animation::MapPlane, ()); diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.h index 9f03206ebb..5fc3b0a6da 100644 --- a/drape_frontend/animation_system.h +++ b/drape_frontend/animation_system.h @@ -195,6 +195,7 @@ class AngleInterpolator: public Interpolator public: AngleInterpolator(double startAngle, double endAngle); AngleInterpolator(double delay, double startAngle, double endAngle); + AngleInterpolator(double delay, double duration, double startAngle, double endAngle); static double GetRotateDuration(double startAngle, double endAngle); @@ -250,6 +251,8 @@ class PerspectiveSwitchAnimation : public Animation public: PerspectiveSwitchAnimation(double startAngle, double endAngle); + static double GetRotateDuration(double startAngle, double endAngle); + Animation::Type GetType() const override { return Animation::MapPerspective; } TAnimObjects const & GetObjects() const override diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 43491875ce..bf47cfd0e7 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -259,11 +259,13 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & { double const angle = AnimationSystem::Instance().GetPerspectiveAngle(screen.GetRotationAngle()); m_navigator.SetRotationIn3dMode(angle); - //TouchCancel(m_touches); } modelViewChange = true; } + if (m_perspectiveAnimation) + TouchCancel(m_touches); + if (GetValidTouchesCount(m_touches) == 1) { if (m_state == STATE_WAIT_DOUBLE_TAP) @@ -500,7 +502,7 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD targetLocalRect.SizeY() / screen.PixelRect().SizeY()); drape_ptr anim = make_unique_dp(userPos, screen.GetScale(), targetScale, screen.GetAngle(), -azimuth, - screen.GtoP(userPos), pixelPos, screen.PixelRectIn3d()); + screen.GtoP(userPos), pixelPos, screen.PixelRect()); if (df::IsAnimationAllowed(anim->GetDuration(), screen)) { @@ -533,32 +535,28 @@ void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, double const startAngle = isAnim ? 0.0 : maxRotationAngle; double const endAngle = maxRotationAngle; - if (isAnim || !immediatelyStart) + + drape_ptr anim = make_unique_dp(startAngle, endAngle); + anim->SetOnStartAction([this, startAngle, endAngle, angleFOV, &viewportChanged](Animation const &) { - drape_ptr anim = make_unique_dp(startAngle, endAngle); - anim->SetOnStartAction([this, startAngle, endAngle, angleFOV](Animation const &) - { - m_perspectiveAnimation = true; - m_navigator.Enable3dMode(startAngle, endAngle, angleFOV); - }); - anim->SetOnFinishAction([this](Animation const &) - { - m_perspectiveAnimation = false; - }); - if (immediatelyStart) - { - //AnimationSystem::Instance().FinishObjectAnimations(Animation::MapPlane, false /* rewind */); - AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); - } - else - AnimationSystem::Instance().PushAnimation(move(anim)); - } + m_perspectiveAnimation = true; + m_navigator.SetFromRect(AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged)); + m_navigator.Enable3dMode(startAngle, endAngle, angleFOV); + }); + anim->SetOnFinishAction([this](Animation const &) + { + m_perspectiveAnimation = false; + }); + if (immediatelyStart) + AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); + else + AnimationSystem::Instance().PushAnimation(move(anim)); } void UserEventStream::SetDisable3dModeAnimation(bool & viewportChanged) { AnimationSystem::Instance().FinishAnimations(Animation::MapLinear, true /* rewind */); - //AnimationSystem::Instance().FinishObjectAnimations(Animation::MapPlane, false /* rewind */); + m_navigator.SetFromRect(AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged)); double const startAngle = m_navigator.Screen().GetRotationAngle(); @@ -569,9 +567,10 @@ void UserEventStream::SetDisable3dModeAnimation(bool & viewportChanged) { m_perspectiveAnimation = true; }); - anim->SetOnFinishAction([this](Animation const &) + anim->SetOnFinishAction([this, &viewportChanged](Animation const &) { m_perspectiveAnimation = false; + m_navigator.SetFromRect(AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged)); m_navigator.Disable3dMode(); if (m_pendingEvent != nullptr && m_pendingEvent->m_type == UserEvent::EVENT_SET_RECT) { From c239c29805d00b1b90a516dc83eaee14c9428950 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Thu, 21 Apr 2016 23:08:52 +0300 Subject: [PATCH 07/13] Perspective animation refactoring. --- drape_frontend/animation_system.cpp | 158 +++++++++++++++++++-------- drape_frontend/animation_system.h | 73 ++++++++++--- drape_frontend/frontend_renderer.cpp | 6 +- drape_frontend/user_event_stream.cpp | 97 +++++++++------- drape_frontend/user_event_stream.hpp | 5 +- 5 files changed, 235 insertions(+), 104 deletions(-) diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index 63e92679f5..d1c47db21f 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -364,7 +364,7 @@ bool MapLinearAnimation::IsFinished() const && (m_positionInterpolator == nullptr || m_positionInterpolator->IsFinished())); } -Animation::PropertyValue MapLinearAnimation::GetProperty(TObject object, TProperty property) const +bool MapLinearAnimation::GetProperty(TObject object, TProperty property, PropertyValue & value) const { ASSERT(object == Animation::MapPlane, ()); @@ -373,23 +373,32 @@ Animation::PropertyValue MapLinearAnimation::GetProperty(TObject object, TProper case Animation::Position: ASSERT(m_positionInterpolator != nullptr, ()); if (m_positionInterpolator != nullptr) - return m_positionInterpolator->GetPosition(); - break; + { + value = m_positionInterpolator->GetPosition(); + return true; + } + return false; case Animation::Scale: ASSERT(m_scaleInterpolator != nullptr, ()); if (m_scaleInterpolator != nullptr) - return m_scaleInterpolator->GetScale(); - break; + { + value = m_scaleInterpolator->GetScale(); + return true; + } + return false; case Animation::Angle: ASSERT(m_angleInterpolator != nullptr, ()); if (m_angleInterpolator != nullptr) - return m_angleInterpolator->GetAngle(); - break; + { + value = m_angleInterpolator->GetAngle(); + return true; + } + return false; default: ASSERT(!"Wrong property", ()); } - return 0.0; + return false; } MapScaleAnimation::MapScaleAnimation(double startScale, double endScale, @@ -441,21 +450,22 @@ bool MapScaleAnimation::IsFinished() const return m_scaleInterpolator->IsFinished(); } -Animation::PropertyValue MapScaleAnimation::GetProperty(TObject object, TProperty property) const +bool MapScaleAnimation::GetProperty(TObject object, TProperty property, PropertyValue & value) const { - if (property == Animation::Position) { ScreenBase screen = AnimationSystem::Instance().GetLastScreen(); screen.SetScale(m_scaleInterpolator->GetScale()); - return screen.PtoG(screen.GtoP(m_globalPosition) + m_pixelOffset); + value = screen.PtoG(screen.GtoP(m_globalPosition) + m_pixelOffset); + return true; } if (property == Animation::Scale) { - return m_scaleInterpolator->GetScale(); + value = m_scaleInterpolator->GetScale(); + return true; } ASSERT(!"Wrong property", ()); - return 0.0; + return false; } MapFollowAnimation::MapFollowAnimation(m2::PointD const & globalPosition, @@ -532,9 +542,8 @@ bool MapFollowAnimation::IsFinished() const && (m_scaleInterpolator == nullptr || m_scaleInterpolator->IsFinished())); } -Animation::PropertyValue MapFollowAnimation::GetProperty(TObject object, TProperty property) const +bool MapFollowAnimation::GetProperty(TObject object, TProperty property, PropertyValue & value) const { - if (property == Animation::Position) { m2::RectD const pixelRect = AnimationSystem::Instance().GetLastScreen().PixelRect(); @@ -542,26 +551,35 @@ Animation::PropertyValue MapFollowAnimation::GetProperty(TObject object, TProper m2::PointD formingVector = (pixelRect.Center() - pixelPos) * m_scaleInterpolator->GetScale(); formingVector.y = -formingVector.y; formingVector.Rotate(m_angleInterpolator->GetAngle()); - return m_globalPosition + formingVector; + value = m_globalPosition + formingVector; + return true; } if (property == Animation::Angle) { - return m_angleInterpolator->GetAngle(); + value = m_angleInterpolator->GetAngle(); + return true; } if (property == Animation::Scale) { - return m_scaleInterpolator->GetScale(); + value = m_scaleInterpolator->GetScale(); + return true; } ASSERT(!"Wrong property", ()); - return 0.0; + return false; } -PerspectiveSwitchAnimation::PerspectiveSwitchAnimation(double startAngle, double endAngle) +PerspectiveSwitchAnimation::PerspectiveSwitchAnimation(double startAngle, double endAngle, double angleFOV) : Animation(false, false) + , m_startAngle(startAngle) + , m_endAngle(endAngle) + , m_angleFOV(angleFOV) + , m_needPerspectiveSwitch(false) { + m_isEnablePerspectiveAnim = m_endAngle > 0.0; m_angleInterpolator = make_unique_dp(GetRotateDuration(startAngle, endAngle), startAngle, endAngle); m_objects.insert(Animation::MapPlane); m_properties.insert(Animation::AnglePerspective); + m_properties.insert(Animation::SwitchPerspective); } // static @@ -592,6 +610,20 @@ void PerspectiveSwitchAnimation::Finish() Animation::Finish(); } +void PerspectiveSwitchAnimation::OnStart() +{ + if (m_isEnablePerspectiveAnim) + m_needPerspectiveSwitch = true; + Animation::OnStart(); +} + +void PerspectiveSwitchAnimation::OnFinish() +{ + if (!m_isEnablePerspectiveAnim) + m_needPerspectiveSwitch = true; + Animation::OnFinish(); +} + void PerspectiveSwitchAnimation::SetMaxDuration(double maxDuration) { m_angleInterpolator->SetMaxDuration(maxDuration); @@ -607,20 +639,29 @@ bool PerspectiveSwitchAnimation::IsFinished() const return m_angleInterpolator->IsFinished(); } -Animation::PropertyValue PerspectiveSwitchAnimation::GetProperty(TObject object, TProperty property) const +bool PerspectiveSwitchAnimation::GetProperty(TObject object, TProperty property, PropertyValue & value) const { ASSERT(object == Animation::MapPlane, ()); switch (property) { case Animation::AnglePerspective: - return m_angleInterpolator->GetAngle(); - break; + value = m_angleInterpolator->GetAngle(); + return true; + case Animation::SwitchPerspective: + if (m_needPerspectiveSwitch) + { + m_needPerspectiveSwitch = false; + value = SwitchPerspectiveParams(m_isEnablePerspectiveAnim, + m_startAngle, m_endAngle, m_angleFOV); + return true; + } + return false; default: ASSERT(!"Wrong property", ()); } - return 0.0; + return false; } Animation::TObjectProperties const & ParallelAnimation::GetProperties(TObject object) const @@ -741,23 +782,52 @@ AnimationSystem::AnimationSystem() } -double AnimationSystem::GetPerspectiveAngle(double currentAngle) +bool AnimationSystem::GetRect(ScreenBase const & currentScreen, m2::AnyRectD & rect) { - return GetProperty(Animation::MapPlane, Animation::AnglePerspective, currentAngle).m_valueD; + m_lastScreen = currentScreen; + + double scale = currentScreen.GetScale(); + double angle = currentScreen.GetAngle(); + m2::PointD pos = currentScreen.GlobalRect().GlobalZero(); + + Animation::PropertyValue value; + if (GetProperty(Animation::MapPlane, Animation::Scale, value)) + scale = value.m_valueD; + + if (GetProperty(Animation::MapPlane, Animation::Angle, value)) + angle = value.m_valueD; + + if (GetProperty(Animation::MapPlane, Animation::Position, value)) + pos = value.m_valuePointD; + + m2::RectD localRect = currentScreen.PixelRect(); + localRect.Offset(-localRect.Center()); + localRect.Scale(scale); + rect = m2::AnyRectD(pos, angle, localRect); + + return true; } -m2::AnyRectD AnimationSystem::GetRect(ScreenBase const & currentScreen, bool & viewportChanged) +bool AnimationSystem::GetPerspectiveAngle(double & angle) { - const Animation::TObject obj = Animation::MapPlane; - viewportChanged |= m_lastScreen != nullptr && (m_lastScreen->isPerspective() != currentScreen.isPerspective()); - m_lastScreen = make_unique_dp(currentScreen); - double scale = GetProperty(obj, Animation::Scale, currentScreen.GetScale()).m_valueD; - double angle = GetProperty(obj, Animation::Angle, currentScreen.GetAngle()).m_valueD; - m2::PointD pos = GetProperty(obj, Animation::Position, currentScreen.GlobalRect().GlobalZero()).m_valuePointD; - m2::RectD rect = currentScreen.PixelRect(); - rect.Offset(-rect.Center()); - rect.Scale(scale); - return m2::AnyRectD(pos, angle, rect); + Animation::PropertyValue value; + if (GetProperty(Animation::MapPlane, Animation::AnglePerspective, value)) + { + angle = value.m_valueD; + return true; + } + return false; +} + +bool AnimationSystem::SwitchPerspective(Animation::SwitchPerspectiveParams & params) +{ + Animation::PropertyValue value; + if (GetProperty(Animation::MapPlane, Animation::SwitchPerspective, value)) + { + params = value.m_valuePerspectiveParams; + return true; + } + return false; } bool AnimationSystem::AnimationExists(Animation::TObject object) const @@ -906,24 +976,24 @@ void AnimationSystem::Advance(double elapsedSeconds) StartNextAnimations(); } -Animation::PropertyValue AnimationSystem::GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue current) const +bool AnimationSystem::GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue & value) const { if (!m_animationChain.empty()) { for (auto const & anim : m_animationChain.front()) { if (anim->HasProperty(object, property)) - return anim->GetProperty(object, property); + return anim->GetProperty(object, property, value); } } auto it = m_propertyCache.find(make_pair(object, property)); if (it != m_propertyCache.end()) { - Animation::PropertyValue value(it->second); + value = it->second; m_propertyCache.erase(it); - return value; + return true; } - return current; + return false; } void AnimationSystem::SaveAnimationResult(Animation const & animation) @@ -932,7 +1002,9 @@ void AnimationSystem::SaveAnimationResult(Animation const & animation) { for (auto const & property : animation.GetProperties(object)) { - m_propertyCache[make_pair(object, property)] = animation.GetProperty(object, property); + Animation::PropertyValue value; + if (animation.GetProperty(object, property, value)) + m_propertyCache[make_pair(object, property)] = value; } } } diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.h index 5fc3b0a6da..0323647659 100644 --- a/drape_frontend/animation_system.h +++ b/drape_frontend/animation_system.h @@ -39,13 +39,34 @@ public: Position, Scale, Angle, - AnglePerspective + AnglePerspective, + SwitchPerspective }; enum PropertyValueType { ValueD, - ValuePointD + ValuePointD, + ValuePerspectiveParams + }; + + struct SwitchPerspectiveParams + { + SwitchPerspectiveParams() + : m_enable(false) + {} + + SwitchPerspectiveParams(bool enable, double startAngle, double endAngle, double angleFOV) + : m_enable(enable) + , m_startAngle(startAngle) + , m_endAngle(endAngle) + , m_angleFOV(angleFOV) + {} + + bool m_enable; + double m_startAngle; + double m_endAngle; + double m_angleFOV; }; struct PropertyValue @@ -55,20 +76,27 @@ public: } PropertyValue(double value) - : m_type(ValueD), - m_valueD(value) + : m_type(ValueD) + , m_valueD(value) {} PropertyValue(m2::PointD value) - : m_type(ValuePointD), - m_valuePointD(value) + : m_type(ValuePointD) + , m_valuePointD(value) {} + PropertyValue(SwitchPerspectiveParams const & params) + : m_type(ValuePerspectiveParams) + { + m_valuePerspectiveParams = params; + } + PropertyValueType m_type; union { m2::PointD m_valuePointD; double m_valueD; + SwitchPerspectiveParams m_valuePerspectiveParams; }; }; @@ -101,7 +129,7 @@ public: virtual void Advance(double elapsedSeconds) = 0; virtual void Finish() { OnFinish(); } - virtual PropertyValue GetProperty(TObject object, TProperty property) const = 0; + virtual bool GetProperty(TObject object, TProperty property, PropertyValue & value) const = 0; void SetOnStartAction(TAction const & action) { m_onStartAction = action; } void SetOnFinishAction(TAction const & action) { m_onFinishAction = action; } @@ -249,7 +277,7 @@ private: class PerspectiveSwitchAnimation : public Animation { public: - PerspectiveSwitchAnimation(double startAngle, double endAngle); + PerspectiveSwitchAnimation(double startAngle, double endAngle, double angleFOV); static double GetRotateDuration(double startAngle, double endAngle); @@ -269,14 +297,23 @@ public: void Advance(double elapsedSeconds) override; void Finish() override; + void OnStart() override; + void OnFinish() override; + void SetMaxDuration(double maxDuration) override; double GetDuration() const override; bool IsFinished() const override; - PropertyValue GetProperty(TObject object, TProperty property) const override; + bool GetProperty(TObject object, TProperty property, PropertyValue & value) const override; private: drape_ptr m_angleInterpolator; + double m_startAngle; + double m_endAngle; + double m_angleFOV; + + bool m_isEnablePerspectiveAnim; + mutable bool m_needPerspectiveSwitch; TAnimObjects m_objects; TObjectProperties m_properties; }; @@ -313,7 +350,7 @@ public: double GetDuration() const override; bool IsFinished() const override; - PropertyValue GetProperty(TObject object, TProperty property) const override; + bool GetProperty(TObject object, TProperty property, PropertyValue & value) const override; private: drape_ptr m_angleInterpolator; @@ -349,7 +386,7 @@ public: double GetDuration() const override; bool IsFinished() const override; - PropertyValue GetProperty(TObject object, TProperty property) const override; + bool GetProperty(TObject object, TProperty property, PropertyValue & value) const override; private: drape_ptr m_scaleInterpolator; @@ -388,7 +425,7 @@ public: double GetDuration() const override; bool IsFinished() const override; - PropertyValue GetProperty(TObject object, TProperty property) const override; + bool GetProperty(TObject object, TProperty property, PropertyValue & value) const override; private: drape_ptr m_scaleInterpolator; @@ -455,8 +492,10 @@ class AnimationSystem : private noncopyable public: static AnimationSystem & Instance(); - m2::AnyRectD GetRect(ScreenBase const & currentScreen, bool & viewportChanged); - double GetPerspectiveAngle(double currentAngle); + bool GetRect(ScreenBase const & currentScreen, m2::AnyRectD & rect); + + bool SwitchPerspective(Animation::SwitchPerspectiveParams & params); + bool GetPerspectiveAngle(double & angle); bool AnimationExists(Animation::TObject object) const; @@ -468,10 +507,10 @@ public: void Advance(double elapsedSeconds); - ScreenBase const & GetLastScreen() { return *m_lastScreen.get(); } + ScreenBase const & GetLastScreen() { return m_lastScreen; } private: - Animation::PropertyValue GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue current) const; + bool GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue & value) const; void SaveAnimationResult(Animation const & animation); void StartNextAnimations(); @@ -484,7 +523,7 @@ private: TAnimationChain m_animationChain; mutable TPropertyCache m_propertyCache; - drape_ptr m_lastScreen; + ScreenBase m_lastScreen; }; } diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index d5c54218c6..d8202866d5 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -1507,15 +1507,15 @@ void FrontendRenderer::Routine::Do() isActiveFrame |= m_renderer.m_texMng->UpdateDynamicTextures(); m_renderer.RenderScene(modelView); - isActiveFrame |= InterpolationHolder::Instance().Advance(frameTime); - AnimationSystem::Instance().Advance(frameTime); - if (modelViewChanged) { m_renderer.UpdateScene(modelView); m_renderer.EmitModelViewChanged(modelView); } + isActiveFrame |= InterpolationHolder::Instance().Advance(frameTime); + AnimationSystem::Instance().Advance(frameTime); + isActiveFrame |= m_renderer.m_userEventStream.IsWaitingForActionCompletion(); if (isActiveFrame) diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index bf47cfd0e7..50bd368ac9 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -206,13 +206,12 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & break; case UserEvent::EVENT_ENABLE_PERSPECTIVE: SetEnable3dMode(e.m_enable3dMode.m_rotationAngle, e.m_enable3dMode.m_angleFOV, - e.m_enable3dMode.m_isAnim, e.m_enable3dMode.m_immediatelyStart, - viewportChanged); + e.m_enable3dMode.m_isAnim, e.m_enable3dMode.m_immediatelyStart); m_discardedFOV = m_discardedAngle = 0.0; break; case UserEvent::EVENT_DISABLE_PERSPECTIVE: if (m_navigator.Screen().isPerspective()) - SetDisable3dModeAnimation(viewportChanged); + SetDisable3dModeAnimation(); m_discardedFOV = m_discardedAngle = 0.0; break; case UserEvent::EVENT_SWITCH_VIEW_MODE: @@ -220,12 +219,11 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & { m_discardedFOV = m_navigator.Screen().GetAngleFOV(); m_discardedAngle = m_navigator.Screen().GetRotationAngle(); - SetDisable3dModeAnimation(viewportChanged); + SetDisable3dModeAnimation(); } else if (m_discardedFOV > 0.0) { - SetEnable3dMode(m_discardedAngle, m_discardedFOV, true /* isAnim */, true /* immediatelyStart */, - viewportChanged); + SetEnable3dMode(m_discardedAngle, m_discardedFOV, true /* isAnim */, true /* immediatelyStart */); m_discardedFOV = m_discardedAngle = 0.0; } break; @@ -249,22 +247,23 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & if (m_animation->IsFinished()) m_animation.reset(); } - if (AnimationSystem::Instance().AnimationExists(Animation::MapPlane)) - { - m2::AnyRectD const rect = AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged); - m_navigator.SetFromRect(rect); - ScreenBase const & screen = GetCurrentScreen(); - if (screen.isPerspective()) - { - double const angle = AnimationSystem::Instance().GetPerspectiveAngle(screen.GetRotationAngle()); - m_navigator.SetRotationIn3dMode(angle); - } - modelViewChange = true; - } + ApplyAnimations(modelViewChange, viewportChanged); if (m_perspectiveAnimation) + { TouchCancel(m_touches); + } + else + { + if (m_pendingEvent != nullptr && m_pendingEvent->m_type == UserEvent::EVENT_SET_RECT) + { + SetRect(m_pendingEvent->m_rectEvent.m_rect, m_pendingEvent->m_rectEvent.m_zoom, + m_pendingEvent->m_rectEvent.m_applyRotation, m_pendingEvent->m_rectEvent.m_isAnim); + m_pendingEvent.reset(); + modelViewChange = true; + } + } if (GetValidTouchesCount(m_touches) == 1) { @@ -277,6 +276,35 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & return m_navigator.Screen(); } +void UserEventStream::ApplyAnimations(bool & modelViewChanged, bool & viewportChanged) +{ + if (AnimationSystem::Instance().AnimationExists(Animation::MapPlane)) + { + m2::AnyRectD rect; + if (AnimationSystem::Instance().GetRect(GetCurrentScreen(), rect)) + m_navigator.SetFromRect(rect); + + Animation::SwitchPerspectiveParams switchPerspective; + if (AnimationSystem::Instance().SwitchPerspective(switchPerspective)) + { + if (switchPerspective.m_enable) + m_navigator.Enable3dMode(switchPerspective.m_startAngle, switchPerspective.m_endAngle, switchPerspective.m_angleFOV); + else + m_navigator.Disable3dMode(); + viewportChanged = true; + } + + double perspectiveAngle; + if (AnimationSystem::Instance().GetPerspectiveAngle(perspectiveAngle) && + GetCurrentScreen().isPerspective()) + { + m_navigator.SetRotationIn3dMode(perspectiveAngle); + } + + modelViewChanged = true; + } +} + ScreenBase const & UserEventStream::GetCurrentScreen() const { return m_navigator.Screen(); @@ -526,22 +554,20 @@ bool UserEventStream::FilterEventWhile3dAnimation(UserEvent::EEventType type) co } void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, - bool isAnim, bool immediatelyStart, - bool & viewportChanged) + bool isAnim, bool immediatelyStart) { AnimationSystem::Instance().FinishAnimations(Animation::MapLinear, true /* rewind */); - - m_navigator.SetFromRect(AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged)); + m2::AnyRectD rect; + if (AnimationSystem::Instance().GetRect(GetCurrentScreen(), rect)) + m_navigator.SetFromRect(rect); double const startAngle = isAnim ? 0.0 : maxRotationAngle; double const endAngle = maxRotationAngle; - drape_ptr anim = make_unique_dp(startAngle, endAngle); - anim->SetOnStartAction([this, startAngle, endAngle, angleFOV, &viewportChanged](Animation const &) + drape_ptr anim = make_unique_dp(startAngle, endAngle, angleFOV); + anim->SetOnStartAction([this, startAngle, endAngle, angleFOV](Animation const &) { m_perspectiveAnimation = true; - m_navigator.SetFromRect(AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged)); - m_navigator.Enable3dMode(startAngle, endAngle, angleFOV); }); anim->SetOnFinishAction([this](Animation const &) { @@ -553,31 +579,24 @@ void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, AnimationSystem::Instance().PushAnimation(move(anim)); } -void UserEventStream::SetDisable3dModeAnimation(bool & viewportChanged) +void UserEventStream::SetDisable3dModeAnimation() { AnimationSystem::Instance().FinishAnimations(Animation::MapLinear, true /* rewind */); - - m_navigator.SetFromRect(AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged)); + m2::AnyRectD rect; + if (AnimationSystem::Instance().GetRect(GetCurrentScreen(), rect)) + m_navigator.SetFromRect(rect); double const startAngle = m_navigator.Screen().GetRotationAngle(); double const endAngle = 0.0; - drape_ptr anim = make_unique_dp(startAngle, endAngle); + drape_ptr anim = make_unique_dp(startAngle, endAngle, m_navigator.Screen().GetAngleFOV()); anim->SetOnStartAction([this](Animation const &) { m_perspectiveAnimation = true; }); - anim->SetOnFinishAction([this, &viewportChanged](Animation const &) + anim->SetOnFinishAction([this](Animation const &) { m_perspectiveAnimation = false; - m_navigator.SetFromRect(AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged)); - m_navigator.Disable3dMode(); - if (m_pendingEvent != nullptr && m_pendingEvent->m_type == UserEvent::EVENT_SET_RECT) - { - SetRect(m_pendingEvent->m_rectEvent.m_rect, m_pendingEvent->m_rectEvent.m_zoom, - m_pendingEvent->m_rectEvent.m_applyRotation, m_pendingEvent->m_rectEvent.m_isAnim); - m_pendingEvent.reset(); - } }); AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); } diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index c589860f3a..0e4251a637 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -311,8 +311,8 @@ private: bool FilterEventWhile3dAnimation(UserEvent::EEventType type) const; void SetEnable3dMode(double maxRotationAngle, double angleFOV, - bool isAnim, bool immediatelyStart, bool & viewportChanged); - void SetDisable3dModeAnimation(bool & viewportChanged); + bool isAnim, bool immediatelyStart); + void SetDisable3dModeAnimation(); m2::AnyRectD GetCurrentRect() const; @@ -353,6 +353,7 @@ private: void EndFilter(Touch const & t); void CancelFilter(Touch const & t); + void ApplyAnimations(bool & modelViewChanged, bool & viewportChanged); void ResetCurrentAnimation(bool finishAnimation = false); list m_events; From 7f70941510807ad818027bd6007b1725b01546c8 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Thu, 21 Apr 2016 23:34:56 +0300 Subject: [PATCH 08/13] Removed useless animation creator in SetRect. --- drape_frontend/user_event_stream.cpp | 60 ++++++++-------------------- drape_frontend/user_event_stream.hpp | 2 - 2 files changed, 17 insertions(+), 45 deletions(-) diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 50bd368ac9..425d5766d2 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -333,6 +333,7 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, drape_ptr anim = make_unique_dp(startScreen.GetScale(), endScreen.GetScale(), glbScaleCenter, offset); + anim->SetMaxDuration(kMaxAnimationTimeSec); if (df::IsAnimationAllowed(anim->GetDuration(), startScreen)) { AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); @@ -341,20 +342,6 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, m_navigator.SetFromRect(endScreen.GlobalRect()); return true; - - /*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)); - if (m_listener) - m_listener->OnAnimationStarted(make_ref(m_animation)); - }; - - ScreenBase screen = GetCurrentScreen(); - m_navigator.CalculateScale(scaleCenter, factor, screen); - - return SetRect(screen.GlobalRect(), true, creator);*/ } m_navigator.Scale(scaleCenter, factor); @@ -455,39 +442,26 @@ 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) - { - drape_ptr anim = make_unique_dp(); - anim->SetRotate(startRect.Angle().val(), endRect.Angle().val()); - anim->SetMove(startRect.GlobalCenter(), endRect.GlobalCenter(), GetCurrentScreen()); - m2::RectD pixelRect = GetCurrentScreen().PixelRect(); - anim->SetScale(max(startRect.GetLocalRect().SizeX() / pixelRect.SizeX(), - startRect.GetLocalRect().SizeY() / pixelRect.SizeY()), - max(endRect.GetLocalRect().SizeX() / pixelRect.SizeX(), - endRect.GetLocalRect().SizeY() / pixelRect.SizeY())); - AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); - //m_animation.reset(new ModelViewAnimation(startRect, endRect, aDuration, mDuration, sDuration)); - if (m_listener) - m_listener->OnAnimationStarted(make_ref(m_animation)); - }); -} - -bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim, TAnimationCreator const & animCreator) -{ if (isAnim) { - ScreenBase const & screen = m_navigator.Screen(); + ScreenBase const & screen = GetCurrentScreen(); m2::AnyRectD const startRect = GetCurrentRect(); - double const angleDuration = ModelViewAnimation::GetRotateDuration(startRect.Angle().val(), rect.Angle().val()); - double const moveDuration = ModelViewAnimation::GetMoveDuration(startRect.GlobalZero(), rect.GlobalZero(), screen); - double scaleDuration = ModelViewAnimation::GetScaleDuration(startRect.GetLocalRect().SizeX(), rect.GetLocalRect().SizeX()); - if (scaleDuration > kMaxAnimationTimeSec) - scaleDuration = kMaxAnimationTimeSec; - if (df::IsAnimationAllowed(max(max(angleDuration, moveDuration), scaleDuration), screen)) + m2::RectD const pixelRect = screen.PixelRect(); + + drape_ptr anim = make_unique_dp(); + anim->SetRotate(startRect.Angle().val(), rect.Angle().val()); + anim->SetMove(startRect.GlobalCenter(), rect.GlobalCenter(), screen); + + anim->SetScale(max(startRect.GetLocalRect().SizeX() / pixelRect.SizeX(), + startRect.GetLocalRect().SizeY() / pixelRect.SizeY()), + max(rect.GetLocalRect().SizeX() / pixelRect.SizeX(), + rect.GetLocalRect().SizeY() / pixelRect.SizeY())); + + if (df::IsAnimationAllowed(anim->GetDuration(), screen)) { - ASSERT(animCreator != nullptr, ()); - animCreator(startRect, rect, angleDuration, moveDuration, scaleDuration); + AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); + if (m_listener) + m_listener->OnAnimationStarted(nullptr); return false; } } diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 0e4251a637..8c849595d6 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -300,12 +300,10 @@ 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); bool SetFollowAndRotate(m2::PointD const & userPos, m2::PointD const & pixelPos, double azimuth, int preferredZoomLevel, bool isAnim); From c1185d5a02eda4204313e1bff6441e9a94ac0ed6 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Fri, 22 Apr 2016 01:10:44 +0300 Subject: [PATCH 09/13] Use sequence of animations when move duration is too long. --- drape_frontend/animation_system.cpp | 69 ++++++++++++++++++++++++++-- drape_frontend/animation_system.h | 13 +++++- drape_frontend/user_event_stream.cpp | 42 ++++++++++++++--- 3 files changed, 113 insertions(+), 11 deletions(-) diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index d1c47db21f..a76ba7c12e 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -724,10 +724,15 @@ void ParallelAnimation::Finish() Animation::Finish(); } +SequenceAnimation::SequenceAnimation() + : Animation(false /* couldBeInterrupted */, false /* couldBeMixed */) +{ + +} + Animation::TAnimObjects const & SequenceAnimation::GetObjects() const { - ASSERT(!m_animations.empty(), ()); - return m_animations.front()->GetObjects(); + return m_objects; } bool SequenceAnimation::HasObject(TObject object) const @@ -738,8 +743,8 @@ bool SequenceAnimation::HasObject(TObject object) const Animation::TObjectProperties const & SequenceAnimation::GetProperties(TObject object) const { - ASSERT(!m_animations.empty(), ()); - return m_animations.front()->GetProperties(object); + ASSERT(HasObject(object), ()); + return m_properties.find(object)->second; } bool SequenceAnimation::HasProperty(TObject object, TProperty property) const @@ -748,8 +753,46 @@ bool SequenceAnimation::HasProperty(TObject object, TProperty property) const return m_animations.front()->HasProperty(object, property); } +void SequenceAnimation::SetMaxDuration(double maxDuration) +{ + ASSERT(!"Not implemented", ()); +} + +double SequenceAnimation::GetDuration() const +{ + double duration = 0.0; + for (auto const & anim : m_animations) + { + duration += anim->GetDuration(); + } + return duration; +} + +bool SequenceAnimation::IsFinished() const +{ + return m_animations.empty(); +} + +bool SequenceAnimation::GetProperty(TObject object, TProperty property, PropertyValue &value) const +{ + for (auto const & anim : m_animations) + { + if (anim->HasProperty(object, property)) + return anim->GetProperty(object, property, value); + } + return false; +} + void SequenceAnimation::AddAnimation(drape_ptr && animation) { + // TODO: Add only current animation's properties. + TAnimObjects const & objects = animation->GetObjects(); + m_objects.insert(objects.begin(), objects.end()); + for (auto const & object : objects) + { + TObjectProperties const & properties = animation->GetProperties(object); + m_properties[object].insert(properties.begin(), properties.end()); + } m_animations.push_back(move(animation)); } @@ -773,7 +816,25 @@ void SequenceAnimation::Advance(double elapsedSeconds) if (m_animations.front()->IsFinished()) { m_animations.front()->OnFinish(); + AnimationSystem::Instance().SaveAnimationResult(*m_animations.front()); m_animations.pop_front(); + CalculateObjectProperties(); + } +} + +void SequenceAnimation::CalculateObjectProperties() +{ + m_objects.clear(); + m_properties.clear(); + for (auto const & anim : m_animations) + { + TAnimObjects const & objects = anim->GetObjects(); + m_objects.insert(objects.begin(), objects.end()); + for (auto const & object : objects) + { + TObjectProperties const & properties = anim->GetProperties(object); + m_properties[object].insert(properties.begin(), properties.end()); + } } } diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.h index 0323647659..7f5b4b6a44 100644 --- a/drape_frontend/animation_system.h +++ b/drape_frontend/animation_system.h @@ -441,12 +441,19 @@ private: class SequenceAnimation : public Animation { public: + SequenceAnimation(); Animation::Type GetType() const override { return Animation::Sequence; } TAnimObjects const & GetObjects() const override; bool HasObject(TObject object) const override; TObjectProperties const & GetProperties(TObject object) const override; bool HasProperty(TObject object, TProperty property) const override; + void SetMaxDuration(double maxDuration) override; + double GetDuration() const override; + bool IsFinished() const override; + + bool GetProperty(TObject object, TProperty property, PropertyValue &value) const override; + void AddAnimation(drape_ptr && animation); void OnStart() override; @@ -455,7 +462,11 @@ public: void Advance(double elapsedSeconds) override; private: + void CalculateObjectProperties(); + deque> m_animations; + TAnimObjects m_objects; + map m_properties; }; class ParallelAnimation : public Animation @@ -508,10 +519,10 @@ public: void Advance(double elapsedSeconds); ScreenBase const & GetLastScreen() { return m_lastScreen; } + void SaveAnimationResult(Animation const & animation); private: bool GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue & value) const; - void SaveAnimationResult(Animation const & animation); void StartNextAnimations(); AnimationSystem(); diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 425d5766d2..a4aeea8aa1 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -448,14 +448,14 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) m2::AnyRectD const startRect = GetCurrentRect(); m2::RectD const pixelRect = screen.PixelRect(); + double const startScale = max(startRect.GetLocalRect().SizeX() / pixelRect.SizeX(), + startRect.GetLocalRect().SizeY() / pixelRect.SizeY()); + double const endScale = max(rect.GetLocalRect().SizeX() / pixelRect.SizeX(), + rect.GetLocalRect().SizeY() / pixelRect.SizeY()); drape_ptr anim = make_unique_dp(); anim->SetRotate(startRect.Angle().val(), rect.Angle().val()); anim->SetMove(startRect.GlobalCenter(), rect.GlobalCenter(), screen); - - anim->SetScale(max(startRect.GetLocalRect().SizeX() / pixelRect.SizeX(), - startRect.GetLocalRect().SizeY() / pixelRect.SizeY()), - max(rect.GetLocalRect().SizeX() / pixelRect.SizeX(), - rect.GetLocalRect().SizeY() / pixelRect.SizeY())); + anim->SetScale(startScale, endScale); if (df::IsAnimationAllowed(anim->GetDuration(), screen)) { @@ -464,9 +464,39 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) m_listener->OnAnimationStarted(nullptr); return false; } + else + { + double const moveDuration = PositionInterpolator::GetMoveDuration(startRect.GlobalCenter(), rect.GlobalCenter(), screen); + if (moveDuration > kMaxAnimationTimeSec) + { + double const scaleFactor = moveDuration / kMaxAnimationTimeSec * 2.0; + + drape_ptr sequenceAnim = make_unique_dp(); + drape_ptr zoomOutAnim = make_unique_dp(); + zoomOutAnim->SetScale(startScale, startScale * scaleFactor); + zoomOutAnim->SetMaxDuration(kMaxAnimationTimeSec / 2.0); + + // TODO: Pass fixed duration instead of screen. + drape_ptr moveAnim = make_unique_dp(); + moveAnim->SetMove(startRect.GlobalCenter(), rect.GlobalCenter(), screen); + moveAnim->SetMaxDuration(kMaxAnimationTimeSec); + + drape_ptr zoomInAnim = make_unique_dp(); + zoomInAnim->SetScale(startScale * scaleFactor, endScale); + zoomInAnim->SetMaxDuration(kMaxAnimationTimeSec / 2.0); + + sequenceAnim->AddAnimation(move(zoomOutAnim)); + sequenceAnim->AddAnimation(move(moveAnim)); + sequenceAnim->AddAnimation(move(zoomInAnim)); + AnimationSystem::Instance().AddAnimation(move(sequenceAnim), true /* force */); + if (m_listener) + m_listener->OnAnimationStarted(nullptr); + return false; + } + } + } - m_animation.reset(); m_navigator.SetFromRect(rect); return true; } From c72ae449d2a513aff821b98f0470b8f092dd3a0e Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Fri, 22 Apr 2016 01:22:28 +0300 Subject: [PATCH 10/13] Return only current animation objects and properties from sequence of animations. --- drape_frontend/animation_system.cpp | 31 ++++++++++------------------- drape_frontend/animation_system.h | 2 +- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index a76ba7c12e..9dbd213eac 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -775,25 +775,15 @@ bool SequenceAnimation::IsFinished() const bool SequenceAnimation::GetProperty(TObject object, TProperty property, PropertyValue &value) const { - for (auto const & anim : m_animations) - { - if (anim->HasProperty(object, property)) - return anim->GetProperty(object, property, value); - } - return false; + ASSERT(!m_animations.empty(), ()); + return m_animations.front()->GetProperty(object, property, value); } void SequenceAnimation::AddAnimation(drape_ptr && animation) { - // TODO: Add only current animation's properties. - TAnimObjects const & objects = animation->GetObjects(); - m_objects.insert(objects.begin(), objects.end()); - for (auto const & object : objects) - { - TObjectProperties const & properties = animation->GetProperties(object); - m_properties[object].insert(properties.begin(), properties.end()); - } m_animations.push_back(move(animation)); + if (m_animations.size() == 1) + ObtainObjectProperties(); } void SequenceAnimation::OnStart() @@ -801,11 +791,12 @@ void SequenceAnimation::OnStart() if (m_animations.empty()) return; m_animations.front()->OnStart(); + Animation::OnStart(); } void SequenceAnimation::OnFinish() { - + Animation::OnFinish(); } void SequenceAnimation::Advance(double elapsedSeconds) @@ -818,21 +809,21 @@ void SequenceAnimation::Advance(double elapsedSeconds) m_animations.front()->OnFinish(); AnimationSystem::Instance().SaveAnimationResult(*m_animations.front()); m_animations.pop_front(); - CalculateObjectProperties(); + ObtainObjectProperties(); } } -void SequenceAnimation::CalculateObjectProperties() +void SequenceAnimation::ObtainObjectProperties() { m_objects.clear(); m_properties.clear(); - for (auto const & anim : m_animations) + if (!m_animations.empty()) { - TAnimObjects const & objects = anim->GetObjects(); + TAnimObjects const & objects = m_animations.front()->GetObjects(); m_objects.insert(objects.begin(), objects.end()); for (auto const & object : objects) { - TObjectProperties const & properties = anim->GetProperties(object); + TObjectProperties const & properties = m_animations.front()->GetProperties(object); m_properties[object].insert(properties.begin(), properties.end()); } } diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.h index 7f5b4b6a44..2865a2030e 100644 --- a/drape_frontend/animation_system.h +++ b/drape_frontend/animation_system.h @@ -462,7 +462,7 @@ public: void Advance(double elapsedSeconds) override; private: - void CalculateObjectProperties(); + void ObtainObjectProperties(); deque> m_animations; TAnimObjects m_objects; From c0e17f6df571c57bbeca807281ac78ef45edfdf4 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Fri, 22 Apr 2016 02:22:41 +0300 Subject: [PATCH 11/13] Kinetic scroll. --- drape_frontend/animation_system.cpp | 12 ++++ drape_frontend/animation_system.h | 4 +- drape_frontend/kinetic_scroller.cpp | 87 +++++++++++++++++++++------- drape_frontend/kinetic_scroller.hpp | 4 +- drape_frontend/user_event_stream.cpp | 10 +++- drape_frontend/user_event_stream.hpp | 2 +- 6 files changed, 91 insertions(+), 28 deletions(-) diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index 9dbd213eac..b6a38dc75b 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -813,6 +813,18 @@ void SequenceAnimation::Advance(double elapsedSeconds) } } +void SequenceAnimation::Finish() +{ + for (auto & anim : m_animations) + { + anim->Finish(); + AnimationSystem::Instance().SaveAnimationResult(*anim); + } + m_animations.clear(); + ObtainObjectProperties(); + Animation::Finish(); +} + void SequenceAnimation::ObtainObjectProperties() { m_objects.clear(); diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.h index 2865a2030e..2a72cf6830 100644 --- a/drape_frontend/animation_system.h +++ b/drape_frontend/animation_system.h @@ -24,7 +24,8 @@ public: MapScale, MapFollow, MapPerspective, - Arrow + Arrow, + KineticScroll }; enum Object @@ -460,6 +461,7 @@ public: void OnFinish() override; void Advance(double elapsedSeconds) override; + void Finish() override; private: void ObtainObjectProperties(); diff --git a/drape_frontend/kinetic_scroller.cpp b/drape_frontend/kinetic_scroller.cpp index 745c30dc6a..7d3b1484c7 100644 --- a/drape_frontend/kinetic_scroller.cpp +++ b/drape_frontend/kinetic_scroller.cpp @@ -25,39 +25,84 @@ double CalculateKineticMaxSpeed(ScreenBase const & modelView) return (kKineticMaxSpeedStart * lerpCoef + kKineticMaxSpeedEnd * (1.0 - lerpCoef)) * VisualParams::Instance().GetVisualScale(); } -class KineticScrollAnimation : public BaseModelViewAnimation +class KineticScrollAnimation : public Animation { public: // startRect - mercator visible on screen rect in moment when user release fingers. // direction - mercator space direction of moving. length(direction) - mercator distance on wich map will be offset. - KineticScrollAnimation(m2::AnyRectD const & startRect, m2::PointD const & direction, double duration) - : BaseModelViewAnimation(duration) - , m_targetCenter(startRect.GlobalCenter() + direction) - , m_angle(startRect.Angle()) - , m_localRect(startRect.GetLocalRect()) + KineticScrollAnimation(m2::PointD const & startPos, m2::PointD const & direction, double duration) + : Animation(true /* couldBeInterrupted */, true /* couldBeMixed */) + , m_endPos(startPos + direction) , m_direction(direction) + , m_duration(duration) + , m_elapsedTime(0.0) { + m_objects.insert(Animation::MapPlane); + m_properties.insert(Animation::Position); } - ModelViewAnimationType GetType() const override { return ModelViewAnimationType::KineticScroll; } + Animation::Type GetType() const override { return Animation::KineticScroll; } - m2::AnyRectD GetCurrentRect(ScreenBase const & screen) const override + TAnimObjects const & GetObjects() const override { + return m_objects; + } + + bool HasObject(TObject object) const override + { + return m_objects.find(object) != m_objects.end(); + } + + TObjectProperties const & GetProperties(TObject object) const override + { + ASSERT(HasObject(object), ()); + return m_properties; + } + + bool HasProperty(TObject object, TProperty property) const override + { + return HasObject(object) && m_properties.find(property) != m_properties.end(); + } + + void SetMaxDuration(double maxDuration) override + { + if (m_duration > maxDuration) + m_duration = maxDuration; + } + + double GetDuration() const override { return m_duration; } + bool IsFinished() const override { return m_elapsedTime >= m_duration; } + + void Advance(double elapsedSeconds) override + { + m_elapsedTime += elapsedSeconds; + } + void Finish() override { + m_elapsedTime = m_duration; + Animation::Finish(); + } + + bool GetProperty(TObject object, TProperty property, PropertyValue & value) const override + { + ASSERT(HasProperty(object, property), ()); // 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(ScreenBase const & screen) const override - { - return GetCurrentRect(screen); + value.m_valuePointD = m_endPos - m_direction * exp(-kKineticFadeoff * GetT()); + return true; } private: - m2::PointD m_targetCenter; - ang::AngleD m_angle; - m2::RectD m_localRect; + double GetT() const + { + return IsFinished() ? 1.0 : m_elapsedTime / m_duration; + } + + m2::PointD m_endPos; m2::PointD m_direction; + double m_duration; + double m_elapsedTime; + TAnimObjects m_objects; + TObjectProperties m_properties; }; KineticScroller::KineticScroller() @@ -116,11 +161,11 @@ void KineticScroller::CancelGrab() m_direction = m2::PointD::Zero(); } -drape_ptr KineticScroller::CreateKineticAnimation(ScreenBase const & modelView) +drape_ptr KineticScroller::CreateKineticAnimation(ScreenBase const & modelView) { static double kVelocityThreshold = kKineticThreshold * VisualParams::Instance().GetVisualScale(); if (m_direction.Length() < kVelocityThreshold) - return drape_ptr(); + return drape_ptr(); // Before we start animation we have to convert length(m_direction) from pixel space to mercator space. m2::PointD center = m_lastRect.GlobalCenter(); @@ -129,9 +174,9 @@ drape_ptr KineticScroller::CreateKineticAnimation(Screen m2::PointD const glbDirection = m_direction.Normalize() * glbLength; m2::PointD const targetCenter = center + glbDirection; if (!df::GetWorldRect().IsPointInside(targetCenter)) - return drape_ptr(); + return drape_ptr(); - return make_unique_dp(m_lastRect, glbDirection, kKineticDuration); + return make_unique_dp(center, glbDirection, kKineticDuration); } } // namespace df diff --git a/drape_frontend/kinetic_scroller.hpp b/drape_frontend/kinetic_scroller.hpp index 2d9de55aed..6353158f1f 100644 --- a/drape_frontend/kinetic_scroller.hpp +++ b/drape_frontend/kinetic_scroller.hpp @@ -1,6 +1,6 @@ #pragma once -#include "animation/model_view_animation.hpp" +#include "animation_system.h" #include "drape/pointers.hpp" @@ -18,7 +18,7 @@ public: bool IsActive() const; void GrabViewRect(ScreenBase const & modelView, double timeStamp); void CancelGrab(); - drape_ptr CreateKineticAnimation(ScreenBase const & modelView); + drape_ptr CreateKineticAnimation(ScreenBase const & modelView); private: double m_lastTimestamp; diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index a4aeea8aa1..077b3434cc 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -953,9 +953,13 @@ bool UserEventStream::EndDrag(Touch const & t, bool cancelled) if (m_kineticScrollEnabled && m_kineticTimer.TimeElapsedAs().count() >= kKineticDelayMs) { - m_animation = m_scroller.CreateKineticAnimation(m_navigator.Screen()); - if (m_listener) - m_listener->OnAnimationStarted(make_ref(m_animation)); + drape_ptr anim = m_scroller.CreateKineticAnimation(m_navigator.Screen()); + if (anim != nullptr) + { + AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); + if (m_listener) + m_listener->OnAnimationStarted(nullptr); + } m_scroller.CancelGrab(); return false; } diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 8c849595d6..fc26f7d080 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -376,7 +376,7 @@ private: drape_ptr m_animation; - bool m_perspectiveAnimation; + bool m_perspectiveAnimation = false; unique_ptr m_pendingEvent; double m_discardedFOV = 0.0; double m_discardedAngle = 0.0; From 6845b69475b1e95cd76869bb63412071dca770d4 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Fri, 22 Apr 2016 18:42:18 +0300 Subject: [PATCH 12/13] Remove old animations from UserEventStream. --- drape_frontend/animation_system.cpp | 29 +++- ...nimation_system.h => animation_system.hpp} | 15 +- drape_frontend/drape_frontend.pro | 4 +- .../user_event_stream_tests.cpp | 2 +- drape_frontend/frontend_renderer.cpp | 4 +- drape_frontend/frontend_renderer.hpp | 2 +- drape_frontend/kinetic_scroller.hpp | 2 +- drape_frontend/my_position_controller.cpp | 14 +- drape_frontend/my_position_controller.hpp | 4 +- drape_frontend/user_event_stream.cpp | 134 ++++++++---------- drape_frontend/user_event_stream.hpp | 8 +- 11 files changed, 114 insertions(+), 104 deletions(-) rename drape_frontend/{animation_system.h => animation_system.hpp} (96%) diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index b6a38dc75b..c5981ae7f2 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -1,4 +1,4 @@ -#include "animation_system.h" +#include "animation_system.hpp" #include "animation/interpolations.hpp" #include "base/logging.hpp" @@ -542,16 +542,33 @@ bool MapFollowAnimation::IsFinished() const && (m_scaleInterpolator == nullptr || m_scaleInterpolator->IsFinished())); } +// static +m2::PointD MapFollowAnimation::CalculateCenter(ScreenBase const & screen, m2::PointD const & userPos, + m2::PointD const & pixelPos, double azimuth) +{ + double const scale = screen.GlobalRect().GetLocalRect().SizeX() / screen.PixelRect().SizeX(); + return CalculateCenter(scale, screen.PixelRect(), userPos, pixelPos, azimuth); +} + +// static +m2::PointD MapFollowAnimation::CalculateCenter(double scale, m2::RectD const & pixelRect, + m2::PointD const & userPos, m2::PointD const & pixelPos, + double azimuth) +{ + m2::PointD formingVector = (pixelRect.Center() - pixelPos) * scale; + formingVector.y = -formingVector.y; + formingVector.Rotate(azimuth); + return userPos + formingVector; +} + +// static bool MapFollowAnimation::GetProperty(TObject object, TProperty property, PropertyValue & value) const { if (property == Animation::Position) { m2::RectD const pixelRect = AnimationSystem::Instance().GetLastScreen().PixelRect(); - m2::PointD const pixelPos = m_pixelPosInterpolator->GetPosition(); - m2::PointD formingVector = (pixelRect.Center() - pixelPos) * m_scaleInterpolator->GetScale(); - formingVector.y = -formingVector.y; - formingVector.Rotate(m_angleInterpolator->GetAngle()); - value = m_globalPosition + formingVector; + value = CalculateCenter(m_scaleInterpolator->GetScale(), pixelRect, m_globalPosition, + m_pixelPosInterpolator->GetPosition(), m_angleInterpolator->GetAngle()); return true; } if (property == Animation::Angle) diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.hpp similarity index 96% rename from drape_frontend/animation_system.h rename to drape_frontend/animation_system.hpp index 2a72cf6830..4bd282bdfe 100644 --- a/drape_frontend/animation_system.h +++ b/drape_frontend/animation_system.hpp @@ -105,15 +105,15 @@ public: using TProperty = uint32_t; using TAnimObjects = set; using TObjectProperties = set; - using TAction = function; + using TAction = function)>; Animation(bool couldBeInterrupted, bool couldBeMixed) : m_couldBeInterrupted(couldBeInterrupted) , m_couldBeMixed(couldBeMixed) {} - virtual void OnStart() {if (m_onStartAction != nullptr) m_onStartAction(*this);} - virtual void OnFinish() {if (m_onFinishAction != nullptr) m_onFinishAction(*this);} + virtual void OnStart() {if (m_onStartAction != nullptr) m_onStartAction(this);} + virtual void OnFinish() {if (m_onFinishAction != nullptr) m_onFinishAction(this);} virtual void Interrupt() {} virtual Type GetType() const = 0; @@ -364,8 +364,7 @@ private: class MapScaleAnimation : public Animation { public: - MapScaleAnimation(double startScale, double endScale, - m2::PointD const & globalPosition, m2::PointD const & offset); + MapScaleAnimation(double startScale, double endScale, m2::PointD const & globalPosition, m2::PointD const & offset); Animation::Type GetType() const override { return Animation::MapScale; } @@ -406,6 +405,12 @@ public: m2::PointD const & startPixelPosition, m2::PointD const & endPixelPosition, m2::RectD const & pixelRect); + static m2::PointD CalculateCenter(ScreenBase const & screen, m2::PointD const & userPos, + m2::PointD const & pixelPos, double azimuth); + + static m2::PointD CalculateCenter(double scale, m2::RectD const & pixelRect, + m2::PointD const & userPos, m2::PointD const & pixelPos, double azimuth); + Animation::Type GetType() const override { return Animation::MapFollow; } TAnimObjects const & GetObjects() const override diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index d8734a57d4..6aa3260811 100755 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -29,6 +29,7 @@ SOURCES += \ gui/ruler_helper.cpp \ gui/shape.cpp \ gui/skin.cpp \ + animation_system.cpp \ animation_utils.cpp \ apply_feature_functors.cpp \ area_shape.cpp \ @@ -92,7 +93,6 @@ SOURCES += \ watch/feature_processor.cpp \ watch/default_font.cpp \ batch_merge_helper.cpp \ - animation_system.cpp HEADERS += \ animation/base_interpolator.hpp \ @@ -114,6 +114,7 @@ HEADERS += \ gui/shape.hpp \ gui/skin.hpp \ animation_constants.hpp \ + animation_system.hpp \ animation_utils.hpp \ apply_feature_functors.hpp \ area_shape.hpp \ @@ -192,4 +193,3 @@ HEADERS += \ watch/geometry_processors.hpp \ watch/feature_processor.hpp \ batch_merge_helper.hpp \ - animation_system.h 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 dbd259fd12..91865064ab 100644 --- a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp +++ b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp @@ -36,7 +36,7 @@ public: void CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) const override {} void CorrectGlobalScalePoint(m2::PointD & pt) const override {} void OnScaleEnded() override {} - void OnAnimationStarted(ref_ptr /* anim */) override {} + void OnAnimationStarted(ref_ptr /* anim */) override {} void AddUserEvent(df::TouchEvent const & event) { diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index d8202866d5..ac074b0adc 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -1,6 +1,6 @@ #include "drape_frontend/animation/interpolation_holder.hpp" #include "drape_frontend/gui/drape_gui.hpp" -#include "drape_frontend/animation_system.h" +#include "drape_frontend/animation_system.hpp" #include "drape_frontend/framebuffer.hpp" #include "drape_frontend/frontend_renderer.hpp" #include "drape_frontend/message_subclasses.hpp" @@ -1391,7 +1391,7 @@ void FrontendRenderer::OnScaleEnded() PullToBoundArea(false /* randomPlace */, false /* applyZoom */); } -void FrontendRenderer::OnAnimationStarted(ref_ptr anim) +void FrontendRenderer::OnAnimationStarted(ref_ptr anim) { m_myPositionController->AnimationStarted(anim); } diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 4e9e4d363d..79e1baf00b 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -189,7 +189,7 @@ private: void CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) const override; void CorrectGlobalScalePoint(m2::PointD & pt) const override; void OnScaleEnded() override; - void OnAnimationStarted(ref_ptr anim) override; + void OnAnimationStarted(ref_ptr anim) override; class Routine : public threads::IRoutine { diff --git a/drape_frontend/kinetic_scroller.hpp b/drape_frontend/kinetic_scroller.hpp index 6353158f1f..dd8026f3de 100644 --- a/drape_frontend/kinetic_scroller.hpp +++ b/drape_frontend/kinetic_scroller.hpp @@ -1,6 +1,6 @@ #pragma once -#include "animation_system.h" +#include "animation_system.hpp" #include "drape/pointers.hpp" diff --git a/drape_frontend/my_position_controller.cpp b/drape_frontend/my_position_controller.cpp index f701e946b2..a8c4acf0de 100644 --- a/drape_frontend/my_position_controller.cpp +++ b/drape_frontend/my_position_controller.cpp @@ -1,9 +1,9 @@ #include "drape_frontend/my_position_controller.hpp" +#include "drape_frontend/animation_system.hpp" #include "drape_frontend/animation_utils.hpp" #include "drape_frontend/visual_params.hpp" #include "drape_frontend/animation/base_interpolator.hpp" #include "drape_frontend/animation/interpolations.hpp" -#include "drape_frontend/animation/model_view_animation.hpp" #include "geometry/mercator.hpp" @@ -568,11 +568,11 @@ void MyPositionController::CheckAnimFinished() const m_anim.reset(); } -void MyPositionController::AnimationStarted(ref_ptr anim) +void MyPositionController::AnimationStarted(ref_ptr anim) { - if (m_isPendingAnimation && m_animCreator != nullptr)// && anim != nullptr && - // (anim->GetType() == ModelViewAnimationType::FollowAndRotate || - // anim->GetType() == ModelViewAnimationType::Default)) + if (m_isPendingAnimation && m_animCreator != nullptr && anim != nullptr && + (anim->GetType() == Animation::MapFollow || + anim->GetType() == Animation::MapLinear)) { m_isPendingAnimation = false; m_animCreator(); @@ -581,8 +581,8 @@ void MyPositionController::AnimationStarted(ref_ptr anim void MyPositionController::CreateAnim(m2::PointD const & oldPos, double oldAzimut, ScreenBase const & screen) { - double const moveDuration = ModelViewAnimation::GetMoveDuration(oldPos, m_position, screen); - double const rotateDuration = ModelViewAnimation::GetRotateDuration(oldAzimut, m_drawDirection); + double const moveDuration = PositionInterpolator::GetMoveDuration(oldPos, m_position, screen); + double const rotateDuration = AngleInterpolator::GetRotateDuration(oldAzimut, m_drawDirection); if (df::IsAnimationAllowed(max(moveDuration, rotateDuration), screen)) { if (IsModeChangeViewport()) diff --git a/drape_frontend/my_position_controller.hpp b/drape_frontend/my_position_controller.hpp index 30ba569d01..076728bf31 100644 --- a/drape_frontend/my_position_controller.hpp +++ b/drape_frontend/my_position_controller.hpp @@ -15,7 +15,7 @@ namespace df { -class BaseModelViewAnimation; +class Animation; class MyPositionController { @@ -61,7 +61,7 @@ public: void ScaleStarted(); void ScaleEnded(); - void AnimationStarted(ref_ptr anim); + void AnimationStarted(ref_ptr anim); void Rotated(); diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 077b3434cc..1a42267480 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -1,6 +1,6 @@ #include "drape_frontend/user_event_stream.hpp" #include "drape_frontend/animation_constants.hpp" -#include "drape_frontend/animation_system.h" +#include "drape_frontend/animation_system.hpp" #include "drape_frontend/animation_utils.hpp" #include "drape_frontend/visual_params.hpp" @@ -117,6 +117,7 @@ void TouchEvent::Swap() UserEventStream::UserEventStream() : m_state(STATE_EMPTY) + , m_animationSystem(AnimationSystem::Instance()) , m_startDragOrg(m2::PointD::Zero()) , m_startDoubleTapAndHold(m2::PointD::Zero()) { @@ -233,19 +234,7 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & } if (breakAnim) - { - m_animation.reset(); modelViewChange = true; - } - } - - if (m_animation != nullptr) - { - m2::AnyRectD const rect = m_animation->GetCurrentRect(GetCurrentScreen()); - m_navigator.SetFromRect(rect); - modelViewChange = true; - if (m_animation->IsFinished()) - m_animation.reset(); } ApplyAnimations(modelViewChange, viewportChanged); @@ -278,14 +267,14 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & void UserEventStream::ApplyAnimations(bool & modelViewChanged, bool & viewportChanged) { - if (AnimationSystem::Instance().AnimationExists(Animation::MapPlane)) + if (m_animationSystem.AnimationExists(Animation::MapPlane)) { m2::AnyRectD rect; - if (AnimationSystem::Instance().GetRect(GetCurrentScreen(), rect)) + if (m_animationSystem.GetRect(GetCurrentScreen(), rect)) m_navigator.SetFromRect(rect); Animation::SwitchPerspectiveParams switchPerspective; - if (AnimationSystem::Instance().SwitchPerspective(switchPerspective)) + if (m_animationSystem.SwitchPerspective(switchPerspective)) { if (switchPerspective.m_enable) m_navigator.Enable3dMode(switchPerspective.m_startAngle, switchPerspective.m_endAngle, switchPerspective.m_angleFOV); @@ -295,7 +284,7 @@ void UserEventStream::ApplyAnimations(bool & modelViewChanged, bool & viewportCh } double perspectiveAngle; - if (AnimationSystem::Instance().GetPerspectiveAngle(perspectiveAngle) && + if (m_animationSystem.GetPerspectiveAngle(perspectiveAngle) && GetCurrentScreen().isPerspective()) { m_navigator.SetRotationIn3dMode(perspectiveAngle); @@ -318,9 +307,6 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, if (isAnim) { - // Reset current animation if there is any. - ResetCurrentAnimation(); - m2::PointD glbScaleCenter = m_navigator.PtoG(m_navigator.P3dtoP(scaleCenter)); if (m_listener) m_listener->CorrectGlobalScalePoint(glbScaleCenter); @@ -336,14 +322,18 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, anim->SetMaxDuration(kMaxAnimationTimeSec); if (df::IsAnimationAllowed(anim->GetDuration(), startScreen)) { - AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); + m_animationSystem.AddAnimation(move(anim), true /* force */); return false; } + // Reset current animation if there is any. + ResetCurrentAnimation(false /* finishAll */, make_pair(false, (uint32_t)0) /* finishAnim */); m_navigator.SetFromRect(endScreen.GlobalRect()); return true; } + // Reset current animation if there is any. + ResetCurrentAnimation(false /* finishAll */, make_pair(false, (uint32_t)0) /* finishAnim */); m_navigator.Scale(scaleCenter, factor); return true; } @@ -439,9 +429,6 @@ 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(); - if (isAnim) { ScreenBase const & screen = GetCurrentScreen(); @@ -459,9 +446,12 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) if (df::IsAnimationAllowed(anim->GetDuration(), screen)) { - AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); - if (m_listener) - m_listener->OnAnimationStarted(nullptr); + anim->SetOnStartAction([this](ref_ptr animation) + { + if (m_listener) + m_listener->OnAnimationStarted(animation); + }); + m_animationSystem.AddAnimation(move(anim), true /* force */); return false; } else @@ -476,6 +466,12 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) zoomOutAnim->SetScale(startScale, startScale * scaleFactor); zoomOutAnim->SetMaxDuration(kMaxAnimationTimeSec / 2.0); + zoomOutAnim->SetOnStartAction([this](ref_ptr animation) + { + if (m_listener) + m_listener->OnAnimationStarted(animation); + }); + // TODO: Pass fixed duration instead of screen. drape_ptr moveAnim = make_unique_dp(); moveAnim->SetMove(startRect.GlobalCenter(), rect.GlobalCenter(), screen); @@ -488,15 +484,14 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) sequenceAnim->AddAnimation(move(zoomOutAnim)); sequenceAnim->AddAnimation(move(moveAnim)); sequenceAnim->AddAnimation(move(zoomInAnim)); - AnimationSystem::Instance().AddAnimation(move(sequenceAnim), true /* force */); - if (m_listener) - m_listener->OnAnimationStarted(nullptr); + m_animationSystem.AddAnimation(move(sequenceAnim), true /* force */); return false; } } - } + // Reset current animation if there is any. + ResetCurrentAnimation(false /* finishAll */, make_pair(false, (uint32_t)0) /* finishAnim */); m_navigator.SetFromRect(rect); return true; } @@ -518,17 +513,11 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD } else { - if (m_animation != nullptr) - targetLocalRect = m_animation->GetTargetRect(GetCurrentScreen()).GetLocalRect(); - else - targetLocalRect = GetCurrentRect().GetLocalRect(); + targetLocalRect = GetTargetRect().GetLocalRect(); } if (isAnim) { - // Reset current animation if there is any. - ResetCurrentAnimation(); - ScreenBase const & screen = m_navigator.Screen(); double targetScale = max(targetLocalRect.SizeX() / screen.PixelRect().SizeX(), targetLocalRect.SizeY() / screen.PixelRect().SizeY()); @@ -538,15 +527,19 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD if (df::IsAnimationAllowed(anim->GetDuration(), screen)) { - AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); - if (m_listener) - m_listener->OnAnimationStarted(make_ref(nullptr/*m_animation*/)); + anim->SetOnStartAction([this](ref_ptr animation) + { + if (m_listener) + m_listener->OnAnimationStarted(animation); + }); + m_animationSystem.AddAnimation(move(anim), true /* force */); + return false; } } - m_animation.reset(); - m2::PointD const center = FollowAndRotateAnimation::CalculateCenter(m_navigator.Screen(), userPos, pixelPos, -azimuth); + ResetCurrentAnimation(false /* finishAll */, make_pair(false, (uint32_t)0) /* finishAnim */); + m2::PointD const center = MapFollowAnimation::CalculateCenter(m_navigator.Screen(), userPos, pixelPos, -azimuth); m_navigator.SetFromRect(m2::AnyRectD(center, -azimuth, targetLocalRect)); return true; } @@ -560,60 +553,56 @@ bool UserEventStream::FilterEventWhile3dAnimation(UserEvent::EEventType type) co void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, bool isAnim, bool immediatelyStart) { - AnimationSystem::Instance().FinishAnimations(Animation::MapLinear, true /* rewind */); - m2::AnyRectD rect; - if (AnimationSystem::Instance().GetRect(GetCurrentScreen(), rect)) - m_navigator.SetFromRect(rect); + ResetCurrentAnimation(false /* finishAll */, make_pair(true, (uint32_t)Animation::MapLinear)/* finishAnim */); double const startAngle = isAnim ? 0.0 : maxRotationAngle; double const endAngle = maxRotationAngle; drape_ptr anim = make_unique_dp(startAngle, endAngle, angleFOV); - anim->SetOnStartAction([this, startAngle, endAngle, angleFOV](Animation const &) + anim->SetOnStartAction([this, startAngle, endAngle, angleFOV](ref_ptr) { m_perspectiveAnimation = true; }); - anim->SetOnFinishAction([this](Animation const &) + anim->SetOnFinishAction([this](ref_ptr) { m_perspectiveAnimation = false; }); if (immediatelyStart) - AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); + m_animationSystem.AddAnimation(move(anim), true /* force */); else - AnimationSystem::Instance().PushAnimation(move(anim)); + m_animationSystem.PushAnimation(move(anim)); } void UserEventStream::SetDisable3dModeAnimation() { - AnimationSystem::Instance().FinishAnimations(Animation::MapLinear, true /* rewind */); - m2::AnyRectD rect; - if (AnimationSystem::Instance().GetRect(GetCurrentScreen(), rect)) - m_navigator.SetFromRect(rect); + ResetCurrentAnimation(false /* finishAll */, make_pair(true, (uint32_t)Animation::MapLinear) /* finishAnim */); double const startAngle = m_navigator.Screen().GetRotationAngle(); double const endAngle = 0.0; drape_ptr anim = make_unique_dp(startAngle, endAngle, m_navigator.Screen().GetAngleFOV()); - anim->SetOnStartAction([this](Animation const &) + anim->SetOnStartAction([this](ref_ptr) { m_perspectiveAnimation = true; }); - anim->SetOnFinishAction([this](Animation const &) + anim->SetOnFinishAction([this](ref_ptr) { m_perspectiveAnimation = false; }); - AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); + m_animationSystem.AddAnimation(move(anim), true /* force */); } -void UserEventStream::ResetCurrentAnimation(bool finishAnimation) + +void UserEventStream::ResetCurrentAnimation(bool finishAll, pair finishAnim) { - if (m_animation) - { - m2::AnyRectD const rect = finishAnimation ? m_animation->GetTargetRect(GetCurrentScreen()) : - m_animation->GetCurrentRect(GetCurrentScreen()); + if (finishAnim.first) + m_animationSystem.FinishAnimations((Animation::Type)finishAnim.second, true /* rewind */); + else + m_animationSystem.FinishObjectAnimations(Animation::MapPlane, finishAll); + + m2::AnyRectD rect; + if (m_animationSystem.GetRect(GetCurrentScreen(), rect)) m_navigator.SetFromRect(rect); - m_animation.reset(); - } } m2::AnyRectD UserEventStream::GetCurrentRect() const @@ -623,10 +612,8 @@ m2::AnyRectD UserEventStream::GetCurrentRect() const m2::AnyRectD UserEventStream::GetTargetRect() const { - if (m_animation) - return m_animation->GetTargetRect(GetCurrentScreen()); - else - return GetCurrentRect(); + // TODO: Calculate target rect inside the animation system. + return GetCurrentRect(); } bool UserEventStream::ProcessTouch(TouchEvent const & touch) @@ -956,9 +943,12 @@ bool UserEventStream::EndDrag(Touch const & t, bool cancelled) drape_ptr anim = m_scroller.CreateKineticAnimation(m_navigator.Screen()); if (anim != nullptr) { - AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); - if (m_listener) - m_listener->OnAnimationStarted(nullptr); + anim->SetOnStartAction([this](ref_ptr animation) + { + if (m_listener) + m_listener->OnAnimationStarted(animation); + }); + m_animationSystem.AddAnimation(move(anim), true /* force */); } m_scroller.CancelGrab(); return false; diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index fc26f7d080..a2447d55c8 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -2,8 +2,6 @@ #include "drape_frontend/kinetic_scroller.hpp" #include "drape_frontend/navigator.hpp" -#include "drape_frontend/animation/model_view_animation.hpp" -#include "drape_frontend/animation/perspective_animation.hpp" #include "drape/pointers.hpp" @@ -257,7 +255,7 @@ public: virtual void CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) const = 0; virtual void OnScaleEnded() = 0; - virtual void OnAnimationStarted(ref_ptr anim) = 0; + virtual void OnAnimationStarted(ref_ptr anim) = 0; }; UserEventStream(); @@ -352,7 +350,7 @@ private: void CancelFilter(Touch const & t); void ApplyAnimations(bool & modelViewChanged, bool & viewportChanged); - void ResetCurrentAnimation(bool finishAnimation = false); + void ResetCurrentAnimation(bool finishAll, pair finishAnim); list m_events; mutable mutex m_lock; @@ -374,7 +372,7 @@ private: array m_touches; - drape_ptr m_animation; + AnimationSystem & m_animationSystem; bool m_perspectiveAnimation = false; unique_ptr m_pendingEvent; From 5d59a349de5f68563e41129f0e8c36b75ec88f63 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Mon, 25 Apr 2016 12:51:21 +0300 Subject: [PATCH 13/13] Review fixes --- .../animation/model_view_animation.cpp | 192 ------- .../animation/model_view_animation.hpp | 107 ---- .../animation/perspective_animation.cpp | 32 -- .../animation/perspective_animation.hpp | 27 - drape_frontend/animation_system.cpp | 542 ++++++++++-------- drape_frontend/animation_system.hpp | 157 +++-- drape_frontend/animation_utils.cpp | 5 +- drape_frontend/drape_frontend.pro | 4 - drape_frontend/kinetic_scroller.cpp | 8 +- drape_frontend/user_event_stream.cpp | 244 +++++--- drape_frontend/user_event_stream.hpp | 4 +- .../drape_frontend.xcodeproj/project.pbxproj | 28 +- 12 files changed, 569 insertions(+), 781 deletions(-) delete mode 100644 drape_frontend/animation/model_view_animation.cpp delete mode 100644 drape_frontend/animation/model_view_animation.hpp delete mode 100644 drape_frontend/animation/perspective_animation.cpp delete mode 100644 drape_frontend/animation/perspective_animation.hpp diff --git a/drape_frontend/animation/model_view_animation.cpp b/drape_frontend/animation/model_view_animation.cpp deleted file mode 100644 index 99c5dd94d6..0000000000 --- a/drape_frontend/animation/model_view_animation.cpp +++ /dev/null @@ -1,192 +0,0 @@ -#include "model_view_animation.hpp" - -namespace df -{ - -ModelViewAnimation::ModelViewAnimation(m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, - double aDuration, double mDuration, double sDuration) - : BaseModelViewAnimation(max(max(aDuration, mDuration), sDuration)) - , m_angleInterpolator(startRect.Angle().val(), endRect.Angle().val()) - , m_startZero(startRect.GlobalZero()) - , m_endZero(endRect.GlobalZero()) - , m_startRect(startRect.GetLocalRect()) - , m_endRect(endRect.GetLocalRect()) - , m_angleDuration(aDuration) - , m_moveDuration(mDuration) - , m_scaleDuration(sDuration) -{ -} - -m2::AnyRectD ModelViewAnimation::GetCurrentRect(ScreenBase const & screen) const -{ - return GetRect(GetElapsedTime()); -} - -m2::AnyRectD ModelViewAnimation::GetTargetRect(ScreenBase const & screen) const -{ - return GetRect(GetDuration()); -} - -namespace -{ - -double GetSafeT(double elapsed, double duration) -{ - if (duration <= 0.0 || elapsed > duration) - return 1.0; - - return elapsed / duration; -} - -} // namespace - -m2::AnyRectD ModelViewAnimation::GetRect(double elapsedTime) const -{ - double dstAngle = m_angleInterpolator.Interpolate(GetSafeT(elapsedTime, m_angleDuration)); - m2::PointD dstZero = InterpolatePoint(m_startZero, m_endZero, GetSafeT(elapsedTime, m_moveDuration)); - m2::RectD dstRect = InterpolateRect(m_startRect, m_endRect, GetSafeT(elapsedTime, m_scaleDuration)); - - return m2::AnyRectD(dstZero, dstAngle, dstRect); -} - -double ModelViewAnimation::GetRotateDuration(double startAngle, double endAngle) -{ - double const kRotateDurationScalar = 0.75; - - return kRotateDurationScalar * fabs(ang::GetShortestDistance(startAngle, endAngle)) / math::pi; -} - -namespace -{ - -double CalcAnimSpeedDuration(double pxDiff, double pxSpeed) -{ - double const kEps = 1e-5; - - if (my::AlmostEqualAbs(pxDiff, 0.0, kEps)) - return 0.0; - - return fabs(pxDiff) / pxSpeed; -} - -} - -double ModelViewAnimation::GetMoveDuration(m2::PointD const & startPt, m2::PointD const & endPt, ScreenBase const & convertor) -{ - double const kMinMoveDuration = 0.2; - double const kMinSpeedScalar = 0.2; - double const kMaxSpeedScalar = 7.0; - double const kEps = 1e-5; - - m2::RectD const & dispPxRect = convertor.PixelRect(); - double const pixelLength = convertor.GtoP(endPt).Length(convertor.GtoP(startPt)); - if (pixelLength < kEps) - return 0.0; - - double const minSize = min(dispPxRect.SizeX(), dispPxRect.SizeY()); - if (pixelLength < kMinSpeedScalar * minSize) - return kMinMoveDuration; - - double const pixelSpeed = kMaxSpeedScalar * minSize; - return CalcAnimSpeedDuration(pixelLength, pixelSpeed); -} - -double ModelViewAnimation::GetScaleDuration(double startSize, double endSize) -{ - // Resize 2.0 times should be done for 0.3 seconds. - double constexpr kPixelSpeed = 2.0 / 0.3; - - if (startSize > endSize) - swap(startSize, endSize); - - return CalcAnimSpeedDuration(endSize / startSize, kPixelSpeed); -} - -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_globalPoint(globalPoint) - , m_pixelOffset(pixelOffset) -{ -} - -void ScaleAnimation::ApplyPixelOffset(ScreenBase const & screen, m2::AnyRectD & rect) const -{ - ScreenBase s = screen; - s.SetFromRect(rect); - - 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 ScaleAnimation::GetCurrentRect(ScreenBase const & screen) const -{ - m2::AnyRectD r = GetRect(GetElapsedTime()); - ApplyPixelOffset(screen, r); - return r; -} - -m2::AnyRectD ScaleAnimation::GetTargetRect(ScreenBase const & screen) const -{ - m2::AnyRectD r = GetRect(GetDuration()); - ApplyPixelOffset(screen, r); - return r; -} - -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_rect(startRect.GetLocalRect()) - , m_target(targetLocalRect) - , m_userPos(userPos) - , m_startPixelPos(startPixelPos) - , m_endPixelPos(endPixelPos) -{} - -m2::AnyRectD FollowAndRotateAnimation::GetCurrentRect(ScreenBase const & screen) const -{ - return GetRect(screen, GetElapsedTime()); -} - -m2::AnyRectD FollowAndRotateAnimation::GetTargetRect(ScreenBase const & screen) const -{ - return GetRect(screen, GetDuration()); -} - -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) -{ - double const scale = localRect.SizeX() / pixelRect.SizeX(); - m2::PointD formingVector = (pixelRect.Center() - pixelPos) * scale; - formingVector.y = -formingVector.y; - formingVector.Rotate(azimuth); - return userPos + formingVector; -} - -m2::AnyRectD FollowAndRotateAnimation::GetRect(ScreenBase const & screen, double elapsedTime) const -{ - double const t = GetSafeT(elapsedTime, GetDuration()); - double const azimuth = m_angleInterpolator.Interpolate(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); - - 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 deleted file mode 100644 index 910a66bbd7..0000000000 --- a/drape_frontend/animation/model_view_animation.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -#include "drape_frontend/animation/base_interpolator.hpp" -#include "drape_frontend/animation/interpolations.hpp" - -#include "geometry/any_rect2d.hpp" -#include "geometry/screenbase.hpp" - -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; -}; - -class ModelViewAnimation : public BaseModelViewAnimation -{ -public: - static double GetRotateDuration(double startAngle, double endAngle); - static double GetMoveDuration(m2::PointD const & startPt, m2::PointD const & endPt, ScreenBase const & convertor); - static double GetScaleDuration(double startSize, double endSize); - - /// aDuration - angleDuration - /// mDuration - moveDuration - /// 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; - -protected: - m2::AnyRectD GetRect(double elapsedTime) const; - -private: - InerpolateAngle m_angleInterpolator; - m2::PointD m_startZero, m_endZero; - m2::RectD m_startRect, m_endRect; - - double m_angleDuration; - double m_moveDuration; - double m_scaleDuration; -}; - -class ScaleAnimation : public ModelViewAnimation -{ -public: - 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 ApplyPixelOffset(ScreenBase const & screen, m2::AnyRectD & rect) const; - m2::PointD m_globalPoint; - m2::PointD m_pixelOffset; -}; - -class FollowAndRotateAnimation : public BaseModelViewAnimation -{ -public: - 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(ScreenBase const & screen, double elapsedTime) const; - - InerpolateAngle m_angleInterpolator; - m2::RectD m_rect; - m2::RectD m_target; - m2::PointD m_userPos; - m2::PointD m_startPixelPos; - m2::PointD m_endPixelPos; -}; - -} // namespace df diff --git a/drape_frontend/animation/perspective_animation.cpp b/drape_frontend/animation/perspective_animation.cpp deleted file mode 100644 index 7509035fa5..0000000000 --- a/drape_frontend/animation/perspective_animation.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "perspective_animation.hpp" -#include "drape_frontend/animation/interpolations.hpp" - -namespace df -{ - -// static -double PerspectiveAnimation::GetRotateDuration(double startAngle, double endAngle) -{ - return 0.5 * fabs(endAngle - startAngle) / math::pi4; -} - -PerspectiveAnimation::PerspectiveAnimation(double duration, double startRotationAngle, double endRotationAngle) - : PerspectiveAnimation(duration, 0.0 /* delay */, startRotationAngle, endRotationAngle) -{ -} - -PerspectiveAnimation::PerspectiveAnimation(double duration, double delay, double startRotationAngle, double endRotationAngle) - : BaseInterpolator(duration, delay) - , m_startRotationAngle(startRotationAngle) - , m_endRotationAngle(endRotationAngle) - , m_rotationAngle(startRotationAngle) -{ -} - -void PerspectiveAnimation::Advance(double elapsedSeconds) -{ - TBase::Advance(elapsedSeconds); - m_rotationAngle = InterpolateDouble(m_startRotationAngle, m_endRotationAngle, GetT()); -} - -} // namespace df diff --git a/drape_frontend/animation/perspective_animation.hpp b/drape_frontend/animation/perspective_animation.hpp deleted file mode 100644 index 7dc59b9fb9..0000000000 --- a/drape_frontend/animation/perspective_animation.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "drape_frontend/animation/base_interpolator.hpp" - -namespace df -{ - -class PerspectiveAnimation : public BaseInterpolator -{ - using TBase = BaseInterpolator; - -public: - PerspectiveAnimation(double duration, double startRotationAngle, double endRotationAngle); - PerspectiveAnimation(double duration, double delay, double startRotationAngle, double endRotationAngle); - - static double GetRotateDuration(double startAngle, double endAngle); - - void Advance(double elapsedSeconds) override; - double GetRotationAngle() const { return m_rotationAngle; } - -private: - double const m_startRotationAngle; - double const m_endRotationAngle; - double m_rotationAngle; -}; - -} // namespace df diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index c5981ae7f2..3039d5314c 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -19,35 +19,74 @@ double CalcAnimSpeedDuration(double pxDiff, double pxSpeed) return fabs(pxDiff) / pxSpeed; } -} - -bool Animation::CouldBeMixedWith(TObject object, TObjectProperties const & properties) +class PropertyBlender { - if (!m_couldBeMixed) - return false; - ASSERT(HasObject(object), ()); +public: + PropertyBlender() = default; - TObjectProperties const & selfProperties = GetProperties(object); - TObjectProperties intersection; - set_intersection(selfProperties.begin(), selfProperties.end(), - properties.begin(), properties.end(), - inserter(intersection, intersection.end())); - return intersection.empty(); -} - -bool Animation::CouldBeMixedWith(Animation const & animation) -{ - if (!m_couldBeMixed || animation.m_couldBeMixed) - return false; - - for (auto const & object : animation.GetObjects()) + void Blend(Animation::PropertyValue const & value) { - if (!HasObject(object)) - continue; - if (!CouldBeMixedWith(object, animation.GetProperties(object))) - return false; + // Now perspective parameters can't be blended. + if (value.m_type == Animation::PropertyValue::ValuePerspectiveParams) + { + m_value = value; + m_counter = 1; + return; + } + + if (m_counter != 0) + { + // New value type resets current blended value. + if (m_value.m_type != value.m_type) + { + m_value = value; + m_counter = 1; + return; + } + + if (value.m_type == Animation::PropertyValue::ValueD) + m_value.m_valueD += value.m_valueD; + else if (value.m_type == Animation::PropertyValue::ValuePointD) + m_value.m_valuePointD += value.m_valuePointD; + } + else + { + m_value = value; + } + m_counter++; } - return true; + + Animation::PropertyValue Finish() + { + if (m_counter == 0) + return m_value; + + double const scalar = 1.0 / m_counter; + m_counter = 0; + if (m_value.m_type == Animation::PropertyValue::ValueD) + m_value.m_valueD *= scalar; + else if (m_value.m_type == Animation::PropertyValue::ValuePointD) + m_value.m_valuePointD *= scalar; + + return m_value; + } + + bool IsEmpty() const + { + return m_counter == 0; + } + +private: + Animation::PropertyValue m_value; + uint32_t m_counter = 0; +}; + +} // namespace + +bool Animation::CouldBeBlendedWith(Animation const & animation) const +{ + return (GetType() != animation.GetType()) && + m_couldBeBlended && animation.m_couldBeBlended; } Interpolator::Interpolator(double duration, double delay) @@ -55,11 +94,7 @@ Interpolator::Interpolator(double duration, double delay) , m_duration(duration) , m_delay(delay) { - ASSERT(m_duration >= 0.0, ()); -} - -Interpolator::~Interpolator() -{ + ASSERT_GREATER_OR_EQUAL(m_duration, 0.0, ()); } bool Interpolator::IsFinished() const @@ -105,13 +140,57 @@ double Interpolator::GetDuration() const return m_duration; } +PositionInterpolator::PositionInterpolator(double duration, double delay, + m2::PointD const & startPosition, + m2::PointD const & endPosition) + : Interpolator(duration, delay) + , m_startPosition(startPosition) + , m_endPosition(endPosition) + , m_position(startPosition) +{} + +PositionInterpolator::PositionInterpolator(m2::PointD const & startPosition, + m2::PointD const & endPosition, + ScreenBase const & convertor) + : PositionInterpolator(0.0 /* delay */, startPosition, endPosition, convertor) +{} + +PositionInterpolator::PositionInterpolator(double delay, m2::PointD const & startPosition, + m2::PointD const & endPosition, + ScreenBase const & convertor) + : Interpolator(PositionInterpolator::GetMoveDuration(startPosition, endPosition, convertor), delay) + , m_startPosition(startPosition) + , m_endPosition(endPosition) + , m_position(startPosition) +{} + +PositionInterpolator::PositionInterpolator(m2::PointD const & startPosition, + m2::PointD const & endPosition, + m2::RectD const & pixelRect) + : PositionInterpolator(0.0 /* delay */, startPosition, endPosition, pixelRect) +{} + +PositionInterpolator::PositionInterpolator(double delay, m2::PointD const & startPosition, + m2::PointD const & endPosition, m2::RectD const & pixelRect) + : Interpolator(PositionInterpolator::GetPixelMoveDuration(startPosition, endPosition, pixelRect), delay) + , m_startPosition(startPosition) + , m_endPosition(endPosition) + , m_position(startPosition) +{} + //static -double PositionInterpolator::GetMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor) +double PositionInterpolator::GetMoveDuration(m2::PointD const & startPosition, + m2::PointD const & endPosition, + ScreenBase const & convertor) { - return GetPixelMoveDuration(convertor.GtoP(startPosition), convertor.GtoP(endPosition), convertor.PixelRectIn3d()); + return GetPixelMoveDuration(convertor.GtoP(startPosition), + convertor.GtoP(endPosition), + convertor.PixelRectIn3d()); } -double PositionInterpolator::GetPixelMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect) +double PositionInterpolator::GetPixelMoveDuration(m2::PointD const & startPosition, + m2::PointD const & endPosition, + m2::RectD const & pixelRect) { double const kMinMoveDuration = 0.2; double const kMinSpeedScalar = 0.2; @@ -130,44 +209,6 @@ double PositionInterpolator::GetPixelMoveDuration(m2::PointD const & startPositi return CalcAnimSpeedDuration(pixelLength, pixelSpeed); } -PositionInterpolator::PositionInterpolator(double duration, double delay, m2::PointD const & startPosition, m2::PointD const & endPosition) - : Interpolator(duration, delay) - , m_startPosition(startPosition) - , m_endPosition(endPosition) - , m_position(startPosition) -{ - -} - -PositionInterpolator::PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor) - : PositionInterpolator(0.0 /* delay */, startPosition, endPosition, convertor) -{ -} - -PositionInterpolator::PositionInterpolator(double delay, m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor) - : Interpolator(PositionInterpolator::GetMoveDuration(startPosition, endPosition, convertor), delay) - , m_startPosition(startPosition) - , m_endPosition(endPosition) - , m_position(startPosition) -{ - -} - -PositionInterpolator::PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect) - : PositionInterpolator(0.0 /* delay */, startPosition, endPosition, pixelRect) -{ - -} - -PositionInterpolator::PositionInterpolator(double delay, m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect) - : Interpolator(PositionInterpolator::GetPixelMoveDuration(startPosition, endPosition, pixelRect), delay) - , m_startPosition(startPosition) - , m_endPosition(endPosition) - , m_position(startPosition) -{ - -} - void PositionInterpolator::Advance(double elapsedSeconds) { TBase::Advance(elapsedSeconds); @@ -180,46 +221,16 @@ void PositionInterpolator::Finish() m_position = m_endPosition; } -// static -double AngleInterpolator::GetRotateDuration(double startAngle, double endAngle) -{ - double const kRotateDurationScalar = 0.75; +ScaleInterpolator::ScaleInterpolator(double startScale, double endScale) + : ScaleInterpolator(0.0 /* delay */, startScale, endScale) +{} - return kRotateDurationScalar * fabs(ang::GetShortestDistance(startAngle, endAngle)) / math::pi; -} - -AngleInterpolator::AngleInterpolator(double startAngle, double endAngle) - : AngleInterpolator(0.0 /* delay */, startAngle, endAngle) -{ -} - -AngleInterpolator::AngleInterpolator(double delay, double startAngle, double endAngle) - : Interpolator(AngleInterpolator::GetRotateDuration(startAngle, endAngle), delay) - , m_startAngle(startAngle) - , m_endAngle(endAngle) - , m_angle(startAngle) -{ -} - -AngleInterpolator::AngleInterpolator(double delay, double duration, double startAngle, double endAngle) - : Interpolator(duration, delay) - , m_startAngle(startAngle) - , m_endAngle(endAngle) - , m_angle(startAngle) -{ -} - -void AngleInterpolator::Advance(double elapsedSeconds) -{ - TBase::Advance(elapsedSeconds); - m_angle = InterpolateDouble(m_startAngle, m_endAngle, GetT()); -} - -void AngleInterpolator::Finish() -{ - TBase::Finish(); - m_angle = m_endAngle; -} +ScaleInterpolator::ScaleInterpolator(double delay, double startScale, double endScale) + : Interpolator(ScaleInterpolator::GetScaleDuration(startScale, endScale), delay) + , m_startScale(startScale) + , m_endScale(endScale) + , m_scale(startScale) +{} // static double ScaleInterpolator::GetScaleDuration(double startScale, double endScale) @@ -233,19 +244,6 @@ double ScaleInterpolator::GetScaleDuration(double startScale, double endScale) return CalcAnimSpeedDuration(endScale / startScale, kPixelSpeed); } -ScaleInterpolator::ScaleInterpolator(double startScale, double endScale) - : ScaleInterpolator(0.0 /* delay */, startScale, endScale) -{ -} - -ScaleInterpolator::ScaleInterpolator(double delay, double startScale, double endScale) - : Interpolator(ScaleInterpolator::GetScaleDuration(startScale, endScale), delay) - , m_startScale(startScale) - , m_endScale(endScale) - , m_scale(startScale) -{ -} - void ScaleInterpolator::Advance(double elapsedSeconds) { TBase::Advance(elapsedSeconds); @@ -258,10 +256,49 @@ void ScaleInterpolator::Finish() m_scale = m_endScale; } +AngleInterpolator::AngleInterpolator(double startAngle, double endAngle) + : AngleInterpolator(0.0 /* delay */, startAngle, endAngle) +{} + +AngleInterpolator::AngleInterpolator(double delay, double startAngle, double endAngle) + : Interpolator(AngleInterpolator::GetRotateDuration(startAngle, endAngle), delay) + , m_startAngle(ang::AngleIn2PI(startAngle)) + , m_endAngle(ang::AngleIn2PI(endAngle)) + , m_angle(m_startAngle) +{} + +AngleInterpolator::AngleInterpolator(double delay, double duration, double startAngle, double endAngle) + : Interpolator(duration, delay) + , m_startAngle(ang::AngleIn2PI(startAngle)) + , m_endAngle(ang::AngleIn2PI(endAngle)) + , m_angle(m_startAngle) +{} + +// static +double AngleInterpolator::GetRotateDuration(double startAngle, double endAngle) +{ + double const kRotateDurationScalar = 0.75; + startAngle = ang::AngleIn2PI(startAngle); + endAngle = ang::AngleIn2PI(endAngle); + return kRotateDurationScalar * fabs(ang::GetShortestDistance(startAngle, endAngle)) / math::pi; +} + +void AngleInterpolator::Advance(double elapsedSeconds) +{ + TBase::Advance(elapsedSeconds); + m_angle = m_startAngle + ang::GetShortestDistance(m_startAngle, m_endAngle) * GetT(); +} + +void AngleInterpolator::Finish() +{ + TBase::Finish(); + m_angle = m_endAngle; +} + MapLinearAnimation::MapLinearAnimation(m2::PointD const & startPos, m2::PointD const & endPos, - double startAngle, double endAngle, - double startScale, double endScale, ScreenBase const & convertor) - : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) + double startAngle, double endAngle, + double startScale, double endScale, ScreenBase const & convertor) + : Animation(true /* couldBeInterrupted */, false /* couldBeBlended */) { m_objects.insert(Animation::MapPlane); SetMove(startPos, endPos, convertor); @@ -270,13 +307,13 @@ MapLinearAnimation::MapLinearAnimation(m2::PointD const & startPos, m2::PointD c } MapLinearAnimation::MapLinearAnimation() - : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) + : Animation(true /* couldBeInterrupted */, false /* couldBeBlended */) { m_objects.insert(Animation::MapPlane); } void MapLinearAnimation::SetMove(m2::PointD const & startPos, m2::PointD const & endPos, - ScreenBase const & convertor) + ScreenBase const & convertor) { if (startPos != endPos) { @@ -305,7 +342,7 @@ void MapLinearAnimation::SetScale(double startScale, double endScale) Animation::TObjectProperties const & MapLinearAnimation::GetProperties(TObject object) const { - ASSERT(object == Animation::MapPlane, ()); + ASSERT_EQUAL(object, Animation::MapPlane, ()); return m_properties; } @@ -345,9 +382,15 @@ void MapLinearAnimation::SetMaxDuration(double maxDuration) m_positionInterpolator->SetMaxDuration(maxDuration); } +void MapLinearAnimation::SetMaxScaleDuration(double maxDuration) +{ + if (m_scaleInterpolator != nullptr) + m_scaleInterpolator->SetMaxDuration(maxDuration); +} + double MapLinearAnimation::GetDuration() const { - double duration = 0; + double duration = 0.0; if (m_angleInterpolator != nullptr) duration = m_angleInterpolator->GetDuration(); if (m_scaleInterpolator != nullptr) @@ -359,14 +402,14 @@ double MapLinearAnimation::GetDuration() const bool MapLinearAnimation::IsFinished() const { - return ((m_angleInterpolator == nullptr || m_angleInterpolator->IsFinished()) - && (m_scaleInterpolator == nullptr || m_scaleInterpolator->IsFinished()) - && (m_positionInterpolator == nullptr || m_positionInterpolator->IsFinished())); + return ((m_angleInterpolator == nullptr || m_angleInterpolator->IsFinished()) && + (m_scaleInterpolator == nullptr || m_scaleInterpolator->IsFinished()) && + (m_positionInterpolator == nullptr || m_positionInterpolator->IsFinished())); } bool MapLinearAnimation::GetProperty(TObject object, TProperty property, PropertyValue & value) const { - ASSERT(object == Animation::MapPlane, ()); + ASSERT_EQUAL(object, Animation::MapPlane, ()); switch (property) { @@ -374,7 +417,7 @@ bool MapLinearAnimation::GetProperty(TObject object, TProperty property, Propert ASSERT(m_positionInterpolator != nullptr, ()); if (m_positionInterpolator != nullptr) { - value = m_positionInterpolator->GetPosition(); + value = PropertyValue(m_positionInterpolator->GetPosition()); return true; } return false; @@ -382,7 +425,7 @@ bool MapLinearAnimation::GetProperty(TObject object, TProperty property, Propert ASSERT(m_scaleInterpolator != nullptr, ()); if (m_scaleInterpolator != nullptr) { - value = m_scaleInterpolator->GetScale(); + value = PropertyValue(m_scaleInterpolator->GetScale()); return true; } return false; @@ -390,24 +433,24 @@ bool MapLinearAnimation::GetProperty(TObject object, TProperty property, Propert ASSERT(m_angleInterpolator != nullptr, ()); if (m_angleInterpolator != nullptr) { - value = m_angleInterpolator->GetAngle(); + value = PropertyValue(m_angleInterpolator->GetAngle()); return true; } return false; default: - ASSERT(!"Wrong property", ()); + ASSERT(false, ("Wrong property:", property)); } return false; } MapScaleAnimation::MapScaleAnimation(double startScale, double endScale, - m2::PointD const & globalPosition, m2::PointD const & offset) - : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) + m2::PointD const & globalPosition, m2::PointD const & offset) + : Animation(true /* couldBeInterrupted */, true /* couldBeBlended */) + , m_scaleInterpolator(startScale, endScale) , m_pixelOffset(offset) , m_globalPosition(globalPosition) { - m_scaleInterpolator = make_unique_dp(startScale, endScale); m_objects.insert(Animation::MapPlane); m_properties.insert(Animation::Scale); m_properties.insert(Animation::Position); @@ -415,7 +458,7 @@ MapScaleAnimation::MapScaleAnimation(double startScale, double endScale, Animation::TObjectProperties const & MapScaleAnimation::GetProperties(TObject object) const { - ASSERT(object == Animation::MapPlane, ()); + ASSERT_EQUAL(object, Animation::MapPlane, ()); return m_properties; } @@ -426,28 +469,28 @@ bool MapScaleAnimation::HasProperty(TObject object, TProperty property) const void MapScaleAnimation::Advance(double elapsedSeconds) { - m_scaleInterpolator->Advance(elapsedSeconds); + m_scaleInterpolator.Advance(elapsedSeconds); } void MapScaleAnimation::Finish() { - m_scaleInterpolator->Finish(); + m_scaleInterpolator.Finish(); Animation::Finish(); } void MapScaleAnimation::SetMaxDuration(double maxDuration) { - m_scaleInterpolator->SetMaxDuration(maxDuration); + m_scaleInterpolator.SetMaxDuration(maxDuration); } double MapScaleAnimation::GetDuration() const { - return m_scaleInterpolator->GetDuration(); + return m_scaleInterpolator.GetDuration(); } bool MapScaleAnimation::IsFinished() const { - return m_scaleInterpolator->IsFinished(); + return m_scaleInterpolator.IsFinished(); } bool MapScaleAnimation::GetProperty(TObject object, TProperty property, PropertyValue & value) const @@ -455,34 +498,35 @@ bool MapScaleAnimation::GetProperty(TObject object, TProperty property, Property if (property == Animation::Position) { ScreenBase screen = AnimationSystem::Instance().GetLastScreen(); - screen.SetScale(m_scaleInterpolator->GetScale()); - value = screen.PtoG(screen.GtoP(m_globalPosition) + m_pixelOffset); + screen.SetScale(m_scaleInterpolator.GetScale()); + value = PropertyValue(screen.PtoG(screen.GtoP(m_globalPosition) + m_pixelOffset)); return true; } if (property == Animation::Scale) { - value = m_scaleInterpolator->GetScale(); + value = PropertyValue(m_scaleInterpolator.GetScale()); return true; } - ASSERT(!"Wrong property", ()); + ASSERT(false, ("Wrong property:", property)); return false; } MapFollowAnimation::MapFollowAnimation(m2::PointD const & globalPosition, double startScale, double endScale, double startAngle, double endAngle, - m2::PointD const & startPixelPosition, m2::PointD const & endPixelPosition, + m2::PointD const & startPixelPosition, + m2::PointD const & endPixelPosition, m2::RectD const & pixelRect) - : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) + : Animation(true /* couldBeInterrupted */, true /* couldBeBlended */) + , m_scaleInterpolator(startScale, endScale) + , m_pixelPosInterpolator(startPixelPosition, endPixelPosition, pixelRect) + , m_angleInterpolator(startAngle, endAngle) , m_globalPosition(globalPosition) { - m_scaleInterpolator = make_unique_dp(startScale, endScale); - m_angleInterpolator = make_unique_dp(startAngle, endAngle); - m_pixelPosInterpolator = make_unique_dp(startPixelPosition, endPixelPosition, pixelRect); - double const duration = GetDuration(); - m_scaleInterpolator->SetMinDuration(duration); - m_angleInterpolator->SetMinDuration(duration); - m_pixelPosInterpolator->SetMinDuration(duration); + double const duration = CalculateDuration(); + m_scaleInterpolator.SetMinDuration(duration); + m_angleInterpolator.SetMinDuration(duration); + m_pixelPosInterpolator.SetMinDuration(duration); m_objects.insert(Animation::MapPlane); m_properties.insert(Animation::Scale); @@ -492,7 +536,7 @@ MapFollowAnimation::MapFollowAnimation(m2::PointD const & globalPosition, Animation::TObjectProperties const & MapFollowAnimation::GetProperties(TObject object) const { - ASSERT(object == Animation::MapPlane, ()); + ASSERT_EQUAL(object, Animation::MapPlane, ()); return m_properties; } @@ -503,43 +547,41 @@ bool MapFollowAnimation::HasProperty(TObject object, TProperty property) const void MapFollowAnimation::Advance(double elapsedSeconds) { - m_angleInterpolator->Advance(elapsedSeconds); - m_scaleInterpolator->Advance(elapsedSeconds); - m_pixelPosInterpolator->Advance(elapsedSeconds); + m_angleInterpolator.Advance(elapsedSeconds); + m_scaleInterpolator.Advance(elapsedSeconds); + m_pixelPosInterpolator.Advance(elapsedSeconds); } void MapFollowAnimation::Finish() { - m_angleInterpolator->Finish(); - m_scaleInterpolator->Finish(); - m_pixelPosInterpolator->Finish(); + m_angleInterpolator.Finish(); + m_scaleInterpolator.Finish(); + m_pixelPosInterpolator.Finish(); Animation::Finish(); } void MapFollowAnimation::SetMaxDuration(double maxDuration) { - m_angleInterpolator->SetMaxDuration(maxDuration); - m_scaleInterpolator->SetMaxDuration(maxDuration); - m_pixelPosInterpolator->SetMaxDuration(maxDuration); + m_angleInterpolator.SetMaxDuration(maxDuration); + m_scaleInterpolator.SetMaxDuration(maxDuration); + m_pixelPosInterpolator.SetMaxDuration(maxDuration); } double MapFollowAnimation::GetDuration() const { - double duration = 0.0; - if (m_pixelPosInterpolator != nullptr) - duration = m_angleInterpolator->GetDuration(); - if (m_angleInterpolator != nullptr) - duration = max(duration, m_angleInterpolator->GetDuration()); - if (m_scaleInterpolator != nullptr) - duration = max(duration, m_scaleInterpolator->GetDuration()); - return duration; + return CalculateDuration(); +} + +double MapFollowAnimation::CalculateDuration() const +{ + return max(max(m_angleInterpolator.GetDuration(), + m_angleInterpolator.GetDuration()), m_scaleInterpolator.GetDuration()); } bool MapFollowAnimation::IsFinished() const { - return ((m_pixelPosInterpolator == nullptr || m_pixelPosInterpolator->IsFinished()) - && (m_angleInterpolator == nullptr || m_angleInterpolator->IsFinished()) - && (m_scaleInterpolator == nullptr || m_scaleInterpolator->IsFinished())); + return m_pixelPosInterpolator.IsFinished() && m_angleInterpolator.IsFinished() && + m_scaleInterpolator.IsFinished(); } // static @@ -561,39 +603,38 @@ m2::PointD MapFollowAnimation::CalculateCenter(double scale, m2::RectD const & p return userPos + formingVector; } -// static bool MapFollowAnimation::GetProperty(TObject object, TProperty property, PropertyValue & value) const { if (property == Animation::Position) { m2::RectD const pixelRect = AnimationSystem::Instance().GetLastScreen().PixelRect(); - value = CalculateCenter(m_scaleInterpolator->GetScale(), pixelRect, m_globalPosition, - m_pixelPosInterpolator->GetPosition(), m_angleInterpolator->GetAngle()); + value = PropertyValue(CalculateCenter(m_scaleInterpolator.GetScale(), pixelRect, m_globalPosition, + m_pixelPosInterpolator.GetPosition(), m_angleInterpolator.GetAngle())); return true; } if (property == Animation::Angle) { - value = m_angleInterpolator->GetAngle(); + value = PropertyValue(m_angleInterpolator.GetAngle()); return true; } if (property == Animation::Scale) { - value = m_scaleInterpolator->GetScale(); + value = PropertyValue(m_scaleInterpolator.GetScale()); return true; } - ASSERT(!"Wrong property", ()); + ASSERT(false, ("Wrong property:", property)); return false; } PerspectiveSwitchAnimation::PerspectiveSwitchAnimation(double startAngle, double endAngle, double angleFOV) - : Animation(false, false) + : Animation(false /* couldBeInterrupted */, true /* couldBeBlended */) + , m_angleInterpolator(GetRotateDuration(startAngle, endAngle), startAngle, endAngle) , m_startAngle(startAngle) , m_endAngle(endAngle) , m_angleFOV(angleFOV) + , m_isEnablePerspectiveAnim(m_endAngle > 0.0) , m_needPerspectiveSwitch(false) { - m_isEnablePerspectiveAnim = m_endAngle > 0.0; - m_angleInterpolator = make_unique_dp(GetRotateDuration(startAngle, endAngle), startAngle, endAngle); m_objects.insert(Animation::MapPlane); m_properties.insert(Animation::AnglePerspective); m_properties.insert(Animation::SwitchPerspective); @@ -602,12 +643,13 @@ PerspectiveSwitchAnimation::PerspectiveSwitchAnimation(double startAngle, double // static double PerspectiveSwitchAnimation::GetRotateDuration(double startAngle, double endAngle) { - return 0.5 * fabs(endAngle - startAngle) / math::pi4; + double const kScalar = 0.5; + return kScalar * fabs(endAngle - startAngle) / math::pi4; } Animation::TObjectProperties const & PerspectiveSwitchAnimation::GetProperties(TObject object) const { - ASSERT(object == Animation::MapPlane, ()); + ASSERT_EQUAL(object, Animation::MapPlane, ()); return m_properties; } @@ -618,12 +660,12 @@ bool PerspectiveSwitchAnimation::HasProperty(TObject object, TProperty property) void PerspectiveSwitchAnimation::Advance(double elapsedSeconds) { - m_angleInterpolator->Advance(elapsedSeconds); + m_angleInterpolator.Advance(elapsedSeconds); } void PerspectiveSwitchAnimation::Finish() { - m_angleInterpolator->Finish(); + m_angleInterpolator.Finish(); Animation::Finish(); } @@ -643,44 +685,47 @@ void PerspectiveSwitchAnimation::OnFinish() void PerspectiveSwitchAnimation::SetMaxDuration(double maxDuration) { - m_angleInterpolator->SetMaxDuration(maxDuration); + m_angleInterpolator.SetMaxDuration(maxDuration); } double PerspectiveSwitchAnimation::GetDuration() const { - return m_angleInterpolator->GetDuration(); + return m_angleInterpolator.GetDuration(); } bool PerspectiveSwitchAnimation::IsFinished() const { - return m_angleInterpolator->IsFinished(); + return m_angleInterpolator.IsFinished(); } bool PerspectiveSwitchAnimation::GetProperty(TObject object, TProperty property, PropertyValue & value) const { - ASSERT(object == Animation::MapPlane, ()); + ASSERT_EQUAL(object, Animation::MapPlane, ()); switch (property) { case Animation::AnglePerspective: - value = m_angleInterpolator->GetAngle(); + value = PropertyValue(m_angleInterpolator.GetAngle()); return true; case Animation::SwitchPerspective: if (m_needPerspectiveSwitch) { m_needPerspectiveSwitch = false; - value = SwitchPerspectiveParams(m_isEnablePerspectiveAnim, - m_startAngle, m_endAngle, m_angleFOV); + value = PropertyValue(SwitchPerspectiveParams(m_isEnablePerspectiveAnim, m_startAngle, m_endAngle, m_angleFOV)); return true; } return false; default: - ASSERT(!"Wrong property", ()); + ASSERT(false, ("Wrong property:", property)); } return false; } +ParallelAnimation::ParallelAnimation() + : Animation(true /* couldBeInterrupted */, true /* couldBeBlended */) +{} + Animation::TObjectProperties const & ParallelAnimation::GetProperties(TObject object) const { ASSERT(HasObject(object), ()); @@ -695,7 +740,7 @@ bool ParallelAnimation::HasProperty(TObject object, TProperty property) const return properties.find(property) != properties.end(); } -void ParallelAnimation::AddAnimation(drape_ptr && animation) +void ParallelAnimation::AddAnimation(drape_ptr animation) { TAnimObjects const & objects = animation->GetObjects(); m_objects.insert(objects.begin(), objects.end()); @@ -715,7 +760,8 @@ void ParallelAnimation::OnStart() void ParallelAnimation::OnFinish() { - + for (auto & anim : m_animations) + anim->OnFinish(); } void ParallelAnimation::Advance(double elapsedSeconds) @@ -730,7 +776,9 @@ void ParallelAnimation::Advance(double elapsedSeconds) iter = m_animations.erase(iter); } else + { ++iter; + } } } @@ -742,9 +790,8 @@ void ParallelAnimation::Finish() } SequenceAnimation::SequenceAnimation() - : Animation(false /* couldBeInterrupted */, false /* couldBeMixed */) + : Animation(true /* couldBeInterrupted */, true /* couldBeBlended */) { - } Animation::TAnimObjects const & SequenceAnimation::GetObjects() const @@ -772,16 +819,14 @@ bool SequenceAnimation::HasProperty(TObject object, TProperty property) const void SequenceAnimation::SetMaxDuration(double maxDuration) { - ASSERT(!"Not implemented", ()); + ASSERT(false, ("Not implemented")); } double SequenceAnimation::GetDuration() const { double duration = 0.0; for (auto const & anim : m_animations) - { duration += anim->GetDuration(); - } return duration; } @@ -790,13 +835,13 @@ bool SequenceAnimation::IsFinished() const return m_animations.empty(); } -bool SequenceAnimation::GetProperty(TObject object, TProperty property, PropertyValue &value) const +bool SequenceAnimation::GetProperty(TObject object, TProperty property, PropertyValue & value) const { ASSERT(!m_animations.empty(), ()); return m_animations.front()->GetProperty(object, property, value); } -void SequenceAnimation::AddAnimation(drape_ptr && animation) +void SequenceAnimation::AddAnimation(drape_ptr animation) { m_animations.push_back(move(animation)); if (m_animations.size() == 1) @@ -833,10 +878,8 @@ void SequenceAnimation::Advance(double elapsedSeconds) void SequenceAnimation::Finish() { for (auto & anim : m_animations) - { anim->Finish(); - AnimationSystem::Instance().SaveAnimationResult(*anim); - } + AnimationSystem::Instance().SaveAnimationResult(*m_animations.back()); m_animations.clear(); ObtainObjectProperties(); Animation::Finish(); @@ -846,21 +889,21 @@ void SequenceAnimation::ObtainObjectProperties() { m_objects.clear(); m_properties.clear(); - if (!m_animations.empty()) + + if (m_animations.empty()) + return; + + TAnimObjects const & objects = m_animations.front()->GetObjects(); + m_objects.insert(objects.begin(), objects.end()); + for (auto const & object : objects) { - TAnimObjects const & objects = m_animations.front()->GetObjects(); - m_objects.insert(objects.begin(), objects.end()); - for (auto const & object : objects) - { - TObjectProperties const & properties = m_animations.front()->GetProperties(object); - m_properties[object].insert(properties.begin(), properties.end()); - } + TObjectProperties const & properties = m_animations.front()->GetProperties(object); + m_properties[object].insert(properties.begin(), properties.end()); } } AnimationSystem::AnimationSystem() { - } bool AnimationSystem::GetRect(ScreenBase const & currentScreen, m2::AnyRectD & rect) @@ -921,36 +964,40 @@ bool AnimationSystem::AnimationExists(Animation::TObject object) const return true; } } - for (auto it = m_propertyCache.begin(); it != m_propertyCache.end(); ++it) + for (auto const & prop : m_propertyCache) { - if (it->first.first == object) + if (prop.first.first == object) return true; } return false; } +bool AnimationSystem::HasAnimations() const +{ + return !m_animationChain.empty(); +} + AnimationSystem & AnimationSystem::Instance() { static AnimationSystem animSystem; return animSystem; } -void AnimationSystem::AddAnimation(drape_ptr && animation, bool force) +void AnimationSystem::CombineAnimation(drape_ptr animation) { for (auto & lst : m_animationChain) { - bool couldBeMixed = true; + bool couldBeBlended = true; for (auto it = lst.begin(); it != lst.end();) { auto & anim = *it; - if (!anim->CouldBeMixedWith(*animation)) + if (!anim->CouldBeBlendedWith(*animation)) { - if (!force || !anim->CouldBeInterrupted()) + if (!anim->CouldBeInterrupted()) { - couldBeMixed = false; + couldBeBlended = false; break; } - // TODO: do not interrupt anything until it's not clear that we can mix anim->Interrupt(); SaveAnimationResult(*anim); it = lst.erase(it); @@ -960,18 +1007,17 @@ void AnimationSystem::AddAnimation(drape_ptr && animation, bool force ++it; } } - if (couldBeMixed) + if (couldBeBlended) { animation->OnStart(); lst.emplace_back(move(animation)); return; } } - PushAnimation(move(animation)); } -void AnimationSystem::PushAnimation(drape_ptr && animation) +void AnimationSystem::PushAnimation(drape_ptr animation) { if (m_animationChain.empty()) animation->OnStart(); @@ -1057,16 +1103,28 @@ void AnimationSystem::Advance(double elapsedSeconds) StartNextAnimations(); } -bool AnimationSystem::GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue & value) const +bool AnimationSystem::GetProperty(Animation::TObject object, Animation::TProperty property, + Animation::PropertyValue & value) const { if (!m_animationChain.empty()) { + PropertyBlender blender; for (auto const & anim : m_animationChain.front()) { if (anim->HasProperty(object, property)) - return anim->GetProperty(object, property, value); + { + Animation::PropertyValue val; + if (anim->GetProperty(object, property, val)) + blender.Blend(val); + } + } + if (!blender.IsEmpty()) + { + value = blender.Finish(); + return true; } } + auto it = m_propertyCache.find(make_pair(object, property)); if (it != m_propertyCache.end()) { @@ -1092,13 +1150,17 @@ void AnimationSystem::SaveAnimationResult(Animation const & animation) void AnimationSystem::StartNextAnimations() { - m_animationChain.pop_front(); if (m_animationChain.empty()) return; - for (auto & anim : m_animationChain.front()) + + m_animationChain.pop_front(); + if (!m_animationChain.empty()) { - // TODO: use propertyCache to load start values to the next animations - anim->OnStart(); + for (auto & anim : m_animationChain.front()) + { + //TODO (in future): use propertyCache to load start values to the next animations + anim->OnStart(); + } } } diff --git a/drape_frontend/animation_system.hpp b/drape_frontend/animation_system.hpp index 4bd282bdfe..8762c4cb94 100644 --- a/drape_frontend/animation_system.hpp +++ b/drape_frontend/animation_system.hpp @@ -1,14 +1,12 @@ #pragma once -#include "animation/base_interpolator.hpp" - #include "drape/pointers.hpp" #include "geometry/screenbase.hpp" -#include "std/set.hpp" #include "std/deque.hpp" #include "std/noncopyable.hpp" +#include "std/unordered_set.hpp" namespace df { @@ -44,55 +42,54 @@ public: SwitchPerspective }; - enum PropertyValueType - { - ValueD, - ValuePointD, - ValuePerspectiveParams - }; - struct SwitchPerspectiveParams { - SwitchPerspectiveParams() - : m_enable(false) - {} + SwitchPerspectiveParams() = default; - SwitchPerspectiveParams(bool enable, double startAngle, double endAngle, double angleFOV) + SwitchPerspectiveParams(bool enable, + double startAngle, double endAngle, + double angleFOV) : m_enable(enable) , m_startAngle(startAngle) , m_endAngle(endAngle) , m_angleFOV(angleFOV) {} - bool m_enable; - double m_startAngle; - double m_endAngle; - double m_angleFOV; + bool m_enable = false; + double m_startAngle = 0.0; + double m_endAngle = 0.0; + double m_angleFOV = 0.0; }; struct PropertyValue { - PropertyValue() + enum Type { - } + ValueD, + ValuePointD, + ValuePerspectiveParams + }; - PropertyValue(double value) + PropertyValue() + {} + + explicit PropertyValue(double value) : m_type(ValueD) , m_valueD(value) {} - PropertyValue(m2::PointD value) + explicit PropertyValue(m2::PointD const & value) : m_type(ValuePointD) , m_valuePointD(value) {} - PropertyValue(SwitchPerspectiveParams const & params) + explicit PropertyValue(SwitchPerspectiveParams const & params) : m_type(ValuePerspectiveParams) { m_valuePerspectiveParams = params; } - PropertyValueType m_type; + Type m_type; union { m2::PointD m_valuePointD; @@ -103,18 +100,18 @@ public: using TObject = uint32_t; using TProperty = uint32_t; - using TAnimObjects = set; - using TObjectProperties = set; + using TAnimObjects = unordered_set; + using TObjectProperties = unordered_set; using TAction = function)>; - Animation(bool couldBeInterrupted, bool couldBeMixed) + Animation(bool couldBeInterrupted, bool couldBeBlended) : m_couldBeInterrupted(couldBeInterrupted) - , m_couldBeMixed(couldBeMixed) + , m_couldBeBlended(couldBeBlended) {} - virtual void OnStart() {if (m_onStartAction != nullptr) m_onStartAction(this);} - virtual void OnFinish() {if (m_onFinishAction != nullptr) m_onFinishAction(this);} - virtual void Interrupt() {} + virtual void OnStart() { if (m_onStartAction != nullptr) m_onStartAction(this); } + virtual void OnFinish() { if (m_onFinishAction != nullptr) m_onFinishAction(this); } + virtual void Interrupt() { if (m_onInterruptAction != nullptr) m_onInterruptAction(this); } virtual Type GetType() const = 0; @@ -137,27 +134,26 @@ public: void SetOnInterruptAction(TAction const & action) { m_onInterruptAction = action; } bool CouldBeInterrupted() const { return m_couldBeInterrupted; } - bool CouldBeMixed() const { return m_couldBeMixed; } - bool CouldBeMixedWith(TObject object, TObjectProperties const & properties); - bool CouldBeMixedWith(Animation const & animation); + bool CouldBeBlendedWith(Animation const & animation) const; protected: TAction m_onStartAction; TAction m_onFinishAction; TAction m_onInterruptAction; bool m_couldBeInterrupted; - bool m_couldBeMixed; + bool m_couldBeBlended; }; class Interpolator { public: Interpolator(double duration, double delay = 0); - virtual ~Interpolator(); + virtual ~Interpolator(){} - bool IsFinished() const; virtual void Advance(double elapsedSeconds); virtual void Finish(); + + bool IsFinished() const; void SetMaxDuration(double maxDuration); void SetMinDuration(double minDuration); double GetDuration() const; @@ -172,23 +168,36 @@ private: double m_delay; }; - class PositionInterpolator: public Interpolator { using TBase = Interpolator; public: - PositionInterpolator(double duration, double delay, m2::PointD const & startPosition, m2::PointD const & endPosition); - PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor); - PositionInterpolator(double delay, m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor); - PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect); - PositionInterpolator(double delay, m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect); + PositionInterpolator(double duration, double delay, + m2::PointD const & startPosition, + m2::PointD const & endPosition); + PositionInterpolator(m2::PointD const & startPosition, + m2::PointD const & endPosition, + ScreenBase const & convertor); + PositionInterpolator(double delay, m2::PointD const & startPosition, + m2::PointD const & endPosition, + ScreenBase const & convertor); + PositionInterpolator(m2::PointD const & startPosition, + m2::PointD const & endPosition, + m2::RectD const & pixelRect); + PositionInterpolator(double delay, m2::PointD const & startPosition, + m2::PointD const & endPosition, + m2::RectD const & pixelRect); - static double GetMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor); - static double GetPixelMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect); + static double GetMoveDuration(m2::PointD const & startPosition, + m2::PointD const & endPosition, ScreenBase const & convertor); + static double GetPixelMoveDuration(m2::PointD const & startPosition, + m2::PointD const & endPosition, m2::RectD const & pixelRect); + // Interpolator overrides: void Advance(double elapsedSeconds) override; void Finish() override; + virtual m2::PointD GetPosition() const { return m_position; } private: @@ -207,8 +216,10 @@ public: static double GetScaleDuration(double startScale, double endScale); + // Interpolator overrides: void Advance(double elapsedSeconds) override; void Finish() override; + virtual double GetScale() const { return m_scale; } private: @@ -228,8 +239,10 @@ public: static double GetRotateDuration(double startAngle, double endAngle); + // Interpolator overrides: void Advance(double elapsedSeconds) override; void Finish() override; + virtual double GetAngle() const { return m_angle; } private: @@ -238,7 +251,8 @@ private: double m_angle; }; -class ArrowAnimation : public Animation +//TODO (in future): implement arrow animation on new animation system. +/*class ArrowAnimation : public Animation { public: ArrowAnimation(m2::PointD const & startPos, m2::PointD const & endPos, @@ -258,10 +272,12 @@ public: { return m_objects; } + bool HasObject(TObject object) const override { return object == Animation::MyPositionArrow; } + TObjectProperties const & GetProperties(TObject object) const override; bool HasProperty(TObject object, TProperty property) const override; @@ -273,7 +289,7 @@ private: drape_ptr m_angleInterpolator; TAnimObjects m_objects; TObjectProperties m_properties; -}; +};*/ class PerspectiveSwitchAnimation : public Animation { @@ -288,10 +304,12 @@ public: { return m_objects; } + bool HasObject(TObject object) const override { return m_objects.find(object) != m_objects.end(); } + TObjectProperties const & GetProperties(TObject object) const override; bool HasProperty(TObject object, TProperty property) const override; @@ -308,7 +326,7 @@ public: bool GetProperty(TObject object, TProperty property, PropertyValue & value) const override; private: - drape_ptr m_angleInterpolator; + AngleInterpolator m_angleInterpolator; double m_startAngle; double m_endAngle; double m_angleFOV; @@ -323,8 +341,8 @@ class MapLinearAnimation : public Animation { public: MapLinearAnimation(m2::PointD const & startPos, m2::PointD const & endPos, - double startAngle, double endAngle, - double startScale, double endScale, ScreenBase const & convertor); + double startAngle, double endAngle, + double startScale, double endScale, ScreenBase const & convertor); MapLinearAnimation(); void SetMove(m2::PointD const & startPos, m2::PointD const & endPos, ScreenBase const & convertor); @@ -337,10 +355,12 @@ public: { return m_objects; } + bool HasObject(TObject object) const override { return object == Animation::MapPlane; } + TObjectProperties const & GetProperties(TObject object) const override; bool HasProperty(TObject object, TProperty property) const override; @@ -352,6 +372,8 @@ public: bool IsFinished() const override; bool GetProperty(TObject object, TProperty property, PropertyValue & value) const override; + + void SetMaxScaleDuration(double maxDuration); private: drape_ptr m_angleInterpolator; @@ -364,7 +386,8 @@ private: class MapScaleAnimation : public Animation { public: - MapScaleAnimation(double startScale, double endScale, m2::PointD const & globalPosition, m2::PointD const & offset); + MapScaleAnimation(double startScale, double endScale, + m2::PointD const & globalPosition, m2::PointD const & offset); Animation::Type GetType() const override { return Animation::MapScale; } @@ -372,10 +395,12 @@ public: { return m_objects; } + bool HasObject(TObject object) const override { return object == Animation::MapPlane; } + TObjectProperties const & GetProperties(TObject object) const override; bool HasProperty(TObject object, TProperty property) const override; @@ -389,7 +414,7 @@ public: bool GetProperty(TObject object, TProperty property, PropertyValue & value) const override; private: - drape_ptr m_scaleInterpolator; + ScaleInterpolator m_scaleInterpolator; m2::PointD const m_pixelOffset; m2::PointD const m_globalPosition; TObjectProperties m_properties; @@ -402,7 +427,8 @@ public: MapFollowAnimation(m2::PointD const & globalPosition, double startScale, double endScale, double startAngle, double endAngle, - m2::PointD const & startPixelPosition, m2::PointD const & endPixelPosition, + m2::PointD const & startPixelPosition, + m2::PointD const & endPixelPosition, m2::RectD const & pixelRect); static m2::PointD CalculateCenter(ScreenBase const & screen, m2::PointD const & userPos, @@ -417,10 +443,12 @@ public: { return m_objects; } + bool HasObject(TObject object) const override { return object == Animation::MapPlane; } + TObjectProperties const & GetProperties(TObject object) const override; bool HasProperty(TObject object, TProperty property) const override; @@ -434,9 +462,11 @@ public: bool GetProperty(TObject object, TProperty property, PropertyValue & value) const override; private: - drape_ptr m_scaleInterpolator; - drape_ptr m_pixelPosInterpolator; - drape_ptr m_angleInterpolator; + double CalculateDuration() const; + + ScaleInterpolator m_scaleInterpolator; + PositionInterpolator m_pixelPosInterpolator; + AngleInterpolator m_angleInterpolator; m2::PointD const m_globalPosition; @@ -460,7 +490,7 @@ public: bool GetProperty(TObject object, TProperty property, PropertyValue &value) const override; - void AddAnimation(drape_ptr && animation); + void AddAnimation(drape_ptr animation); void OnStart() override; void OnFinish() override; @@ -479,19 +509,24 @@ private: class ParallelAnimation : public Animation { public: + ParallelAnimation(); + Animation::Type GetType() const override { return Animation::Parallel; } + TAnimObjects const & GetObjects() const override { return m_objects; } + bool HasObject(TObject object) const override { return m_objects.find(object) != m_objects.end(); } + TObjectProperties const & GetProperties(TObject object) const override; bool HasProperty(TObject object, TProperty property) const override; - void AddAnimation(drape_ptr && animation); + void AddAnimation(drape_ptr animation); void OnStart() override; void OnFinish() override; @@ -516,9 +551,10 @@ public: bool GetPerspectiveAngle(double & angle); bool AnimationExists(Animation::TObject object) const; + bool HasAnimations() const; - void AddAnimation(drape_ptr && animation, bool force); - void PushAnimation(drape_ptr && animation); + void CombineAnimation(drape_ptr animation); + void PushAnimation(drape_ptr animation); void FinishAnimations(Animation::Type type, bool rewind); void FinishObjectAnimations(Animation::TObject object, bool rewind); @@ -538,6 +574,7 @@ private: using TAnimationList = list>; using TAnimationChain = deque; using TPropertyCache = map, Animation::PropertyValue>; + TAnimationChain m_animationChain; mutable TPropertyCache m_propertyCache; diff --git a/drape_frontend/animation_utils.cpp b/drape_frontend/animation_utils.cpp index f647472a29..09ad468501 100644 --- a/drape_frontend/animation_utils.cpp +++ b/drape_frontend/animation_utils.cpp @@ -4,15 +4,12 @@ #include "indexer/scales.hpp" -// Zoom level before which animation can not be instant. -int const kInstantAnimationZoomLevel = 5; - namespace df { bool IsAnimationAllowed(double duration, ScreenBase const & screen) { - return duration > 0.0 && (duration < kMaxAnimationTimeSec || df::GetDrawTileScale(screen) < kInstantAnimationZoomLevel); + return duration > 0.0 && duration <= kMaxAnimationTimeSec; } } // namespace df diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index 6aa3260811..279cfd8ea8 100755 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -15,9 +15,7 @@ SOURCES += \ animation/base_interpolator.cpp \ animation/interpolation_holder.cpp \ animation/interpolations.cpp \ - animation/model_view_animation.cpp \ animation/opacity_animation.cpp \ - animation/perspective_animation.cpp \ animation/show_hide_animation.cpp \ gui/choose_position_mark.cpp \ gui/compass.cpp \ @@ -98,9 +96,7 @@ HEADERS += \ animation/base_interpolator.hpp \ animation/interpolation_holder.hpp \ animation/interpolations.hpp \ - animation/model_view_animation.hpp \ animation/opacity_animation.hpp \ - animation/perspective_animation.hpp \ animation/show_hide_animation.hpp \ animation/value_mapping.hpp \ gui/choose_position_mark.hpp \ diff --git a/drape_frontend/kinetic_scroller.cpp b/drape_frontend/kinetic_scroller.cpp index 7d3b1484c7..a636166e26 100644 --- a/drape_frontend/kinetic_scroller.cpp +++ b/drape_frontend/kinetic_scroller.cpp @@ -31,7 +31,7 @@ public: // startRect - mercator visible on screen rect in moment when user release fingers. // direction - mercator space direction of moving. length(direction) - mercator distance on wich map will be offset. KineticScrollAnimation(m2::PointD const & startPos, m2::PointD const & direction, double duration) - : Animation(true /* couldBeInterrupted */, true /* couldBeMixed */) + : Animation(true /* couldBeInterrupted */, true /* couldBeBlended */) , m_endPos(startPos + direction) , m_direction(direction) , m_duration(duration) @@ -77,7 +77,9 @@ public: { m_elapsedTime += elapsedSeconds; } - void Finish() override { + + void Finish() override + { m_elapsedTime = m_duration; Animation::Finish(); } @@ -87,7 +89,7 @@ public: ASSERT(HasProperty(object, property), ()); // Current position = target position - amplutide * e ^ (elapsed / duration). // We calculate current position not based on start position, but based on target position. - value.m_valuePointD = m_endPos - m_direction * exp(-kKineticFadeoff * GetT()); + value = PropertyValue(m_endPos - m_direction * exp(-kKineticFadeoff * GetT())); return true; } diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 1a42267480..ad3a449e95 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -29,6 +29,8 @@ uint64_t const kKineticDelayMs = 500; float const kForceTapThreshold = 0.75; +int const kDoNotChangeZoom = -1; + size_t GetValidTouchesCount(array const & touches) { size_t result = 0; @@ -40,6 +42,45 @@ size_t GetValidTouchesCount(array const & touches) return result; } +drape_ptr GetPrettyMoveAnimation(ScreenBase const screen, double startScale, double endScale, + m2::PointD const & startPt, m2::PointD const & endPt, + function)> onStartAnimation) +{ + double const moveDuration = PositionInterpolator::GetMoveDuration(startPt, endPt, screen); + double const scaleFactor = moveDuration / kMaxAnimationTimeSec * 2.0; + + drape_ptr sequenceAnim = make_unique_dp(); + drape_ptr zoomOutAnim = make_unique_dp(); + zoomOutAnim->SetScale(startScale, startScale * scaleFactor); + zoomOutAnim->SetMaxDuration(kMaxAnimationTimeSec * 0.5); + zoomOutAnim->SetOnStartAction(onStartAnimation); + + //TODO (in future): Pass fixed duration instead of screen. + drape_ptr moveAnim = make_unique_dp(); + moveAnim->SetMove(startPt, endPt, screen); + moveAnim->SetMaxDuration(kMaxAnimationTimeSec); + + drape_ptr zoomInAnim = make_unique_dp(); + zoomInAnim->SetScale(startScale * scaleFactor, endScale); + zoomInAnim->SetMaxDuration(kMaxAnimationTimeSec * 0.5); + + sequenceAnim->AddAnimation(move(zoomOutAnim)); + sequenceAnim->AddAnimation(move(moveAnim)); + sequenceAnim->AddAnimation(move(zoomInAnim)); + return sequenceAnim; +} + +double CalculateScale(ScreenBase const & screen, m2::RectD const & localRect) +{ + m2::RectD const pixelRect = screen.PixelRect(); + return max(localRect.SizeX() / pixelRect.SizeX(), localRect.SizeY() / pixelRect.SizeY()); +} + +double CalculateScale(ScreenBase const & screen, m2::AnyRectD const & rect) +{ + return CalculateScale(screen, rect.GetLocalRect()); +} + } // namespace #ifdef DEBUG @@ -189,7 +230,7 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & if (screen.isPerspective()) { m2::PointD pt = screen.P3dtoP(screen.PixelRectIn3d().Center()); - breakAnim = SetFollowAndRotate(screen.PtoG(pt), pt, e.m_rotate.m_targetAzimut, -1, true); + breakAnim = SetFollowAndRotate(screen.PtoG(pt), pt, e.m_rotate.m_targetAzimut, kDoNotChangeZoom, true); } else { @@ -277,9 +318,14 @@ void UserEventStream::ApplyAnimations(bool & modelViewChanged, bool & viewportCh if (m_animationSystem.SwitchPerspective(switchPerspective)) { if (switchPerspective.m_enable) - m_navigator.Enable3dMode(switchPerspective.m_startAngle, switchPerspective.m_endAngle, switchPerspective.m_angleFOV); + { + m_navigator.Enable3dMode(switchPerspective.m_startAngle, switchPerspective.m_endAngle, + switchPerspective.m_angleFOV); + } else + { m_navigator.Disable3dMode(); + } viewportChanged = true; } @@ -317,23 +363,14 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, ScreenBase endScreen = startScreen; m_navigator.CalculateScale(scaleCenter, factor, endScreen); - drape_ptr anim = make_unique_dp(startScreen.GetScale(), endScreen.GetScale(), - glbScaleCenter, offset); + auto anim = make_unique_dp(startScreen.GetScale(), endScreen.GetScale(), + glbScaleCenter, offset); anim->SetMaxDuration(kMaxAnimationTimeSec); - if (df::IsAnimationAllowed(anim->GetDuration(), startScreen)) - { - m_animationSystem.AddAnimation(move(anim), true /* force */); - return false; - } - - // Reset current animation if there is any. - ResetCurrentAnimation(false /* finishAll */, make_pair(false, (uint32_t)0) /* finishAnim */); - m_navigator.SetFromRect(endScreen.GlobalRect()); - return true; + m_animationSystem.CombineAnimation(move(anim)); + return false; } - // Reset current animation if there is any. - ResetCurrentAnimation(false /* finishAll */, make_pair(false, (uint32_t)0) /* finishAnim */); + ResetCurrentAnimations(); m_navigator.Scale(scaleCenter, factor); return true; } @@ -360,7 +397,7 @@ bool UserEventStream::SetCenter(m2::PointD const & center, int zoom, bool isAnim ScreenBase screen = currentScreen; bool finishIn2d = false; bool finishIn3d = false; - if (zoom != -1) + if (zoom != kDoNotChangeZoom) { bool const isScaleAllowableIn3d = IsScaleAllowableIn3d(zoom); finishIn3d = m_discardedFOV > 0.0 && isScaleAllowableIn3d; @@ -374,7 +411,7 @@ bool UserEventStream::SetCenter(m2::PointD const & center, int zoom, bool isAnim double const scale3d = screen.PixelRect().SizeX() / screen.PixelRectIn3d().SizeX(); - if (zoom == -1) + if (zoom == kDoNotChangeZoom) { m2::AnyRectD const r = GetTargetRect(); angle = r.Angle(); @@ -393,25 +430,24 @@ bool UserEventStream::SetCenter(m2::PointD const & center, int zoom, bool isAnim double const aspectRatio = screen.PixelRect().SizeY() / screen.PixelRect().SizeX(); if (aspectRatio > 1.0) - localRect.Inflate(0.0, localRect.SizeY() / 2.0 * aspectRatio); + localRect.Inflate(0.0, localRect.SizeY() * 0.5 * aspectRatio); else - localRect.Inflate(localRect.SizeX() / 2.0 / aspectRatio, 0.0); + localRect.Inflate(localRect.SizeX() * 0.5 / aspectRatio, 0.0); } if (screen.isPerspective()) { - double const centerOffset3d = localRect.SizeY() * (1.0 - 1.0 / (scale3d * cos(screen.GetRotationAngle()))) / 2.0; + double const centerOffset3d = localRect.SizeY() * (1.0 - 1.0 / (scale3d * cos(screen.GetRotationAngle()))) * 0.5; 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 scale = currentScreen.PixelRect().SizeX() / currentScreen.PixelRectIn3d().SizeX(); + double const scaleToCurrent = finishIn2d ? scale : 1.0 / scale3d; double const currentGSizeY = localRect.SizeY() * scaleToCurrent; - targetCenter = targetCenter.Move((currentGSizeY - localRect.SizeY()) / 2.0, + targetCenter = targetCenter.Move((currentGSizeY - localRect.SizeY()) * 0.5, angle.cos(), -angle.sin()); localRect.Scale(scaleToCurrent); } @@ -433,65 +469,42 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) { ScreenBase const & screen = GetCurrentScreen(); m2::AnyRectD const startRect = GetCurrentRect(); - m2::RectD const pixelRect = screen.PixelRect(); - - double const startScale = max(startRect.GetLocalRect().SizeX() / pixelRect.SizeX(), - startRect.GetLocalRect().SizeY() / pixelRect.SizeY()); - double const endScale = max(rect.GetLocalRect().SizeX() / pixelRect.SizeX(), - rect.GetLocalRect().SizeY() / pixelRect.SizeY()); + double const startScale = CalculateScale(screen, startRect); + double const endScale = CalculateScale(screen, rect); + drape_ptr anim = make_unique_dp(); anim->SetRotate(startRect.Angle().val(), rect.Angle().val()); anim->SetMove(startRect.GlobalCenter(), rect.GlobalCenter(), screen); anim->SetScale(startScale, endScale); + anim->SetMaxScaleDuration(kMaxAnimationTimeSec); + auto onStartHandler = [this](ref_ptr animation) + { + if (m_listener) + m_listener->OnAnimationStarted(animation); + }; if (df::IsAnimationAllowed(anim->GetDuration(), screen)) { - anim->SetOnStartAction([this](ref_ptr animation) - { - if (m_listener) - m_listener->OnAnimationStarted(animation); - }); - m_animationSystem.AddAnimation(move(anim), true /* force */); + anim->SetOnStartAction(onStartHandler); + m_animationSystem.CombineAnimation(move(anim)); return false; } else { - double const moveDuration = PositionInterpolator::GetMoveDuration(startRect.GlobalCenter(), rect.GlobalCenter(), screen); + m2::PointD const startPt = startRect.GlobalCenter(); + m2::PointD const endPt = rect.GlobalCenter(); + double const moveDuration = PositionInterpolator::GetMoveDuration(startPt, endPt, screen); if (moveDuration > kMaxAnimationTimeSec) { - double const scaleFactor = moveDuration / kMaxAnimationTimeSec * 2.0; - - drape_ptr sequenceAnim = make_unique_dp(); - drape_ptr zoomOutAnim = make_unique_dp(); - zoomOutAnim->SetScale(startScale, startScale * scaleFactor); - zoomOutAnim->SetMaxDuration(kMaxAnimationTimeSec / 2.0); - - zoomOutAnim->SetOnStartAction([this](ref_ptr animation) - { - if (m_listener) - m_listener->OnAnimationStarted(animation); - }); - - // TODO: Pass fixed duration instead of screen. - drape_ptr moveAnim = make_unique_dp(); - moveAnim->SetMove(startRect.GlobalCenter(), rect.GlobalCenter(), screen); - moveAnim->SetMaxDuration(kMaxAnimationTimeSec); - - drape_ptr zoomInAnim = make_unique_dp(); - zoomInAnim->SetScale(startScale * scaleFactor, endScale); - zoomInAnim->SetMaxDuration(kMaxAnimationTimeSec / 2.0); - - sequenceAnim->AddAnimation(move(zoomOutAnim)); - sequenceAnim->AddAnimation(move(moveAnim)); - sequenceAnim->AddAnimation(move(zoomInAnim)); - m_animationSystem.AddAnimation(move(sequenceAnim), true /* force */); + auto sequenceAnim = GetPrettyMoveAnimation(screen, startScale, endScale, startPt, endPt, + onStartHandler); + m_animationSystem.CombineAnimation(move(sequenceAnim)); return false; } } } - // Reset current animation if there is any. - ResetCurrentAnimation(false /* finishAll */, make_pair(false, (uint32_t)0) /* finishAnim */); + ResetCurrentAnimations(); m_navigator.SetFromRect(rect); return true; } @@ -502,7 +515,7 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD // Extract target local rect from current animation or calculate it from preferredZoomLevel // to preserve final scale. m2::RectD targetLocalRect; - if (preferredZoomLevel != -1) + if (preferredZoomLevel != kDoNotChangeZoom) { ScreenBase newScreen = GetCurrentScreen(); m2::RectD r = df::GetRectForDrawScale(preferredZoomLevel, m2::PointD::Zero()); @@ -519,26 +532,49 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD if (isAnim) { ScreenBase const & screen = m_navigator.Screen(); - double targetScale = max(targetLocalRect.SizeX() / screen.PixelRect().SizeX(), - targetLocalRect.SizeY() / screen.PixelRect().SizeY()); - drape_ptr anim = make_unique_dp(userPos, screen.GetScale(), targetScale, - screen.GetAngle(), -azimuth, - screen.GtoP(userPos), pixelPos, screen.PixelRect()); - - if (df::IsAnimationAllowed(anim->GetDuration(), screen)) + double const targetScale = CalculateScale(screen, targetLocalRect); + auto onStartHandler = [this](ref_ptr animation) { - anim->SetOnStartAction([this](ref_ptr animation) - { - if (m_listener) - m_listener->OnAnimationStarted(animation); - }); - m_animationSystem.AddAnimation(move(anim), true /* force */); + if (m_listener) + m_listener->OnAnimationStarted(animation); + }; + + double const startScale = CalculateScale(screen, GetCurrentRect()); + // Run pretty move animation if we are far from userPos. + m2::PointD const startPt = GetCurrentRect().GlobalCenter(); + double const moveDuration = PositionInterpolator::GetMoveDuration(startPt, userPos, screen); + if (moveDuration > kMaxAnimationTimeSec) + { + auto sequenceAnim = GetPrettyMoveAnimation(screen, startScale, targetScale, startPt, userPos, + onStartHandler); + sequenceAnim->SetOnFinishAction([this, userPos, pixelPos, onStartHandler, targetScale, azimuth] + (ref_ptr animation) + { + ScreenBase const & screen = m_navigator.Screen(); + double const startScale = CalculateScale(screen, GetCurrentRect()); + auto anim = make_unique_dp(userPos, startScale, targetScale, + screen.GlobalRect().Angle().val(), -azimuth, + screen.GtoP(userPos), pixelPos, screen.PixelRect()); + anim->SetOnStartAction(onStartHandler); + anim->SetMaxDuration(kMaxAnimationTimeSec); + m_animationSystem.CombineAnimation(move(anim)); + }); + m_animationSystem.CombineAnimation(move(sequenceAnim)); return false; } + + // Run follow-and-rotate animation. + auto anim = make_unique_dp(userPos, startScale, targetScale, + screen.GlobalRect().Angle().val(), -azimuth, + screen.GtoP(userPos), pixelPos, screen.PixelRect()); + anim->SetMaxDuration(kMaxAnimationTimeSec); + anim->SetOnStartAction(onStartHandler); + m_animationSystem.CombineAnimation(move(anim)); + return false; } - ResetCurrentAnimation(false /* finishAll */, make_pair(false, (uint32_t)0) /* finishAnim */); + ResetCurrentAnimations(); m2::PointD const center = MapFollowAnimation::CalculateCenter(m_navigator.Screen(), userPos, pixelPos, -azimuth); m_navigator.SetFromRect(m2::AnyRectD(center, -azimuth, targetLocalRect)); return true; @@ -546,19 +582,18 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD bool UserEventStream::FilterEventWhile3dAnimation(UserEvent::EEventType type) const { - return type != UserEvent::EVENT_RESIZE && - type != UserEvent::EVENT_SET_RECT; + return type != UserEvent::EVENT_RESIZE && type != UserEvent::EVENT_SET_RECT; } void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, bool isAnim, bool immediatelyStart) { - ResetCurrentAnimation(false /* finishAll */, make_pair(true, (uint32_t)Animation::MapLinear)/* finishAnim */); + ResetMapLinearAnimations(); double const startAngle = isAnim ? 0.0 : maxRotationAngle; double const endAngle = maxRotationAngle; - drape_ptr anim = make_unique_dp(startAngle, endAngle, angleFOV); + auto anim = make_unique_dp(startAngle, endAngle, angleFOV); anim->SetOnStartAction([this, startAngle, endAngle, angleFOV](ref_ptr) { m_perspectiveAnimation = true; @@ -568,19 +603,19 @@ void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, m_perspectiveAnimation = false; }); if (immediatelyStart) - m_animationSystem.AddAnimation(move(anim), true /* force */); + m_animationSystem.CombineAnimation(move(anim)); else m_animationSystem.PushAnimation(move(anim)); } void UserEventStream::SetDisable3dModeAnimation() { - ResetCurrentAnimation(false /* finishAll */, make_pair(true, (uint32_t)Animation::MapLinear) /* finishAnim */); + ResetMapLinearAnimations(); double const startAngle = m_navigator.Screen().GetRotationAngle(); double const endAngle = 0.0; - drape_ptr anim = make_unique_dp(startAngle, endAngle, m_navigator.Screen().GetAngleFOV()); + auto anim = make_unique_dp(startAngle, endAngle, m_navigator.Screen().GetAngleFOV()); anim->SetOnStartAction([this](ref_ptr) { m_perspectiveAnimation = true; @@ -589,20 +624,36 @@ void UserEventStream::SetDisable3dModeAnimation() { m_perspectiveAnimation = false; }); - m_animationSystem.AddAnimation(move(anim), true /* force */); + m_animationSystem.CombineAnimation(move(anim)); } - -void UserEventStream::ResetCurrentAnimation(bool finishAll, pair finishAnim) +void UserEventStream::ResetCurrentAnimations() { + uint32_t const kMapPlaneIndex = 0; + ResetCurrentAnimations(false /* finishAll */, make_pair(false, kMapPlaneIndex) /* finishAnim */); +} + +void UserEventStream::ResetMapLinearAnimations() +{ + uint32_t const kMapLinearIndex = static_cast(Animation::MapLinear); + ResetCurrentAnimations(false /* finishAll */, make_pair(true, kMapLinearIndex)/* finishAnim */); +} + +void UserEventStream::ResetCurrentAnimations(bool finishAll, pair finishAnim) +{ + bool const hasAnimations = m_animationSystem.HasAnimations(); + if (finishAnim.first) m_animationSystem.FinishAnimations((Animation::Type)finishAnim.second, true /* rewind */); else m_animationSystem.FinishObjectAnimations(Animation::MapPlane, finishAll); - m2::AnyRectD rect; - if (m_animationSystem.GetRect(GetCurrentScreen(), rect)) - m_navigator.SetFromRect(rect); + if (hasAnimations) + { + m2::AnyRectD rect; + if (m_animationSystem.GetRect(GetCurrentScreen(), rect)) + m_navigator.SetFromRect(rect); + } } m2::AnyRectD UserEventStream::GetCurrentRect() const @@ -908,7 +959,10 @@ void UserEventStream::BeginDrag(Touch const & t, double timestamp) m_navigator.StartDrag(t.m_location); if (m_kineticScrollEnabled && !m_scroller.IsActive()) + { + ResetCurrentAnimations(); m_scroller.InitGrab(m_navigator.Screen(), timestamp); + } } void UserEventStream::Drag(Touch const & t, double timestamp) @@ -948,7 +1002,7 @@ bool UserEventStream::EndDrag(Touch const & t, bool cancelled) if (m_listener) m_listener->OnAnimationStarted(animation); }); - m_animationSystem.AddAnimation(move(anim), true /* force */); + m_animationSystem.CombineAnimation(move(anim)); } m_scroller.CancelGrab(); return false; diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index a2447d55c8..6c370651fa 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -350,7 +350,9 @@ private: void CancelFilter(Touch const & t); void ApplyAnimations(bool & modelViewChanged, bool & viewportChanged); - void ResetCurrentAnimation(bool finishAll, pair finishAnim); + void ResetCurrentAnimations(); + void ResetMapLinearAnimations(); + void ResetCurrentAnimations(bool finishAll, pair finishAnim); list m_events; mutable mutex m_lock; diff --git a/xcode/drape_frontend/drape_frontend.xcodeproj/project.pbxproj b/xcode/drape_frontend/drape_frontend.xcodeproj/project.pbxproj index 102e59d606..4b4ddde44f 100644 --- a/xcode/drape_frontend/drape_frontend.xcodeproj/project.pbxproj +++ b/xcode/drape_frontend/drape_frontend.xcodeproj/project.pbxproj @@ -9,6 +9,9 @@ /* Begin PBXBuildFile section */ 3492DA0E1CA2D9BF00C1F3B3 /* animation_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3492DA0C1CA2D9BF00C1F3B3 /* animation_utils.cpp */; }; 3492DA0F1CA2D9BF00C1F3B3 /* animation_utils.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3492DA0D1CA2D9BF00C1F3B3 /* animation_utils.hpp */; }; + 454C19BB1CCE3EC0002A2C86 /* animation_constants.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 454C19B81CCE3EC0002A2C86 /* animation_constants.hpp */; }; + 454C19BC1CCE3EC0002A2C86 /* animation_system.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 454C19B91CCE3EC0002A2C86 /* animation_system.cpp */; }; + 454C19BD1CCE3EC0002A2C86 /* animation_system.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 454C19BA1CCE3EC0002A2C86 /* animation_system.hpp */; }; 56BF56DA1C7608C0006DD7CB /* choose_position_mark.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56BF56D81C7608C0006DD7CB /* choose_position_mark.cpp */; }; 56BF56DB1C7608C0006DD7CB /* choose_position_mark.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56BF56D91C7608C0006DD7CB /* choose_position_mark.hpp */; }; 56D545661C74A44900E3719C /* overlay_batcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56D545641C74A44900E3719C /* overlay_batcher.cpp */; }; @@ -102,8 +105,6 @@ 670948171BDF9C39005014C0 /* interpolation_holder.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 6709480A1BDF9C39005014C0 /* interpolation_holder.hpp */; }; 670948181BDF9C39005014C0 /* interpolations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6709480B1BDF9C39005014C0 /* interpolations.cpp */; }; 670948191BDF9C39005014C0 /* interpolations.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 6709480C1BDF9C39005014C0 /* interpolations.hpp */; }; - 6709481A1BDF9C39005014C0 /* model_view_animation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6709480D1BDF9C39005014C0 /* model_view_animation.cpp */; }; - 6709481B1BDF9C39005014C0 /* model_view_animation.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 6709480E1BDF9C39005014C0 /* model_view_animation.hpp */; }; 6709481C1BDF9C39005014C0 /* opacity_animation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6709480F1BDF9C39005014C0 /* opacity_animation.cpp */; }; 6709481D1BDF9C39005014C0 /* opacity_animation.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 670948101BDF9C39005014C0 /* opacity_animation.hpp */; }; 6709481E1BDF9C39005014C0 /* show_hide_animation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 670948111BDF9C39005014C0 /* show_hide_animation.cpp */; }; @@ -156,8 +157,6 @@ 6743D3701C3A9F090095054B /* framebuffer.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 6743D36A1C3A9F090095054B /* framebuffer.hpp */; }; 6743D3711C3A9F090095054B /* transparent_layer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6743D36B1C3A9F090095054B /* transparent_layer.cpp */; }; 6743D3721C3A9F090095054B /* transparent_layer.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 6743D36C1C3A9F090095054B /* transparent_layer.hpp */; }; - 6743D3751C3A9F530095054B /* perspective_animation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6743D3731C3A9F530095054B /* perspective_animation.cpp */; }; - 6743D3761C3A9F530095054B /* perspective_animation.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 6743D3741C3A9F530095054B /* perspective_animation.hpp */; }; 675D21661BFB785900717E4F /* ruler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 670948331BDF9C48005014C0 /* ruler.cpp */; }; 675D218C1BFB871D00717E4F /* proto_to_styles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 675D21851BFB871D00717E4F /* proto_to_styles.cpp */; }; 675D218D1BFB871D00717E4F /* proto_to_styles.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 675D21861BFB871D00717E4F /* proto_to_styles.hpp */; }; @@ -187,6 +186,9 @@ /* Begin PBXFileReference section */ 3492DA0C1CA2D9BF00C1F3B3 /* animation_utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = animation_utils.cpp; sourceTree = ""; }; 3492DA0D1CA2D9BF00C1F3B3 /* animation_utils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = animation_utils.hpp; sourceTree = ""; }; + 454C19B81CCE3EC0002A2C86 /* animation_constants.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = animation_constants.hpp; sourceTree = ""; }; + 454C19B91CCE3EC0002A2C86 /* animation_system.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = animation_system.cpp; sourceTree = ""; }; + 454C19BA1CCE3EC0002A2C86 /* animation_system.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = animation_system.hpp; sourceTree = ""; }; 56BF56D81C7608C0006DD7CB /* choose_position_mark.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = choose_position_mark.cpp; sourceTree = ""; }; 56BF56D91C7608C0006DD7CB /* choose_position_mark.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = choose_position_mark.hpp; sourceTree = ""; }; 56D545641C74A44900E3719C /* overlay_batcher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = overlay_batcher.cpp; sourceTree = ""; }; @@ -289,8 +291,6 @@ 6709480A1BDF9C39005014C0 /* interpolation_holder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = interpolation_holder.hpp; sourceTree = ""; }; 6709480B1BDF9C39005014C0 /* interpolations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = interpolations.cpp; sourceTree = ""; }; 6709480C1BDF9C39005014C0 /* interpolations.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = interpolations.hpp; sourceTree = ""; }; - 6709480D1BDF9C39005014C0 /* model_view_animation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = model_view_animation.cpp; sourceTree = ""; }; - 6709480E1BDF9C39005014C0 /* model_view_animation.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = model_view_animation.hpp; sourceTree = ""; }; 6709480F1BDF9C39005014C0 /* opacity_animation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opacity_animation.cpp; sourceTree = ""; }; 670948101BDF9C39005014C0 /* opacity_animation.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = opacity_animation.hpp; sourceTree = ""; }; 670948111BDF9C39005014C0 /* show_hide_animation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = show_hide_animation.cpp; sourceTree = ""; }; @@ -347,8 +347,6 @@ 6743D36A1C3A9F090095054B /* framebuffer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = framebuffer.hpp; sourceTree = ""; }; 6743D36B1C3A9F090095054B /* transparent_layer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = transparent_layer.cpp; sourceTree = ""; }; 6743D36C1C3A9F090095054B /* transparent_layer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = transparent_layer.hpp; sourceTree = ""; }; - 6743D3731C3A9F530095054B /* perspective_animation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = perspective_animation.cpp; sourceTree = ""; }; - 6743D3741C3A9F530095054B /* perspective_animation.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = perspective_animation.hpp; sourceTree = ""; }; 675D21851BFB871D00717E4F /* proto_to_styles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = proto_to_styles.cpp; sourceTree = ""; }; 675D21861BFB871D00717E4F /* proto_to_styles.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = proto_to_styles.hpp; sourceTree = ""; }; 675D21871BFB871D00717E4F /* rect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rect.h; sourceTree = ""; }; @@ -396,6 +394,9 @@ 670947411BDF9B99005014C0 /* drape_frontend */ = { isa = PBXGroup; children = ( + 454C19B81CCE3EC0002A2C86 /* animation_constants.hpp */, + 454C19B91CCE3EC0002A2C86 /* animation_system.cpp */, + 454C19BA1CCE3EC0002A2C86 /* animation_system.hpp */, 3492DA0C1CA2D9BF00C1F3B3 /* animation_utils.cpp */, 3492DA0D1CA2D9BF00C1F3B3 /* animation_utils.hpp */, 56D545641C74A44900E3719C /* overlay_batcher.cpp */, @@ -519,16 +520,12 @@ 670948051BDF9C0D005014C0 /* animation */ = { isa = PBXGroup; children = ( - 6743D3731C3A9F530095054B /* perspective_animation.cpp */, - 6743D3741C3A9F530095054B /* perspective_animation.hpp */, 670948071BDF9C39005014C0 /* base_interpolator.cpp */, 670948081BDF9C39005014C0 /* base_interpolator.hpp */, 670948091BDF9C39005014C0 /* interpolation_holder.cpp */, 6709480A1BDF9C39005014C0 /* interpolation_holder.hpp */, 6709480B1BDF9C39005014C0 /* interpolations.cpp */, 6709480C1BDF9C39005014C0 /* interpolations.hpp */, - 6709480D1BDF9C39005014C0 /* model_view_animation.cpp */, - 6709480E1BDF9C39005014C0 /* model_view_animation.hpp */, 6709480F1BDF9C39005014C0 /* opacity_animation.cpp */, 670948101BDF9C39005014C0 /* opacity_animation.hpp */, 670948111BDF9C39005014C0 /* show_hide_animation.cpp */, @@ -642,7 +639,6 @@ 675D218D1BFB871D00717E4F /* proto_to_styles.hpp in Headers */, 670947951BDF9BE1005014C0 /* line_shape_helper.hpp in Headers */, 670948501BDF9C48005014C0 /* skin.hpp in Headers */, - 6709481B1BDF9C39005014C0 /* model_view_animation.hpp in Headers */, 56D545671C74A44900E3719C /* overlay_batcher.hpp in Headers */, 670947B21BDF9BE1005014C0 /* read_mwm_task.hpp in Headers */, 670947C91BDF9BE1005014C0 /* text_shape.hpp in Headers */, @@ -659,13 +655,14 @@ 670948731BDF9C7F005014C0 /* frame_image.hpp in Headers */, 3492DA0F1CA2D9BF00C1F3B3 /* animation_utils.hpp in Headers */, 670947FB1BDF9BF5005014C0 /* backend_renderer.hpp in Headers */, + 454C19BD1CCE3EC0002A2C86 /* animation_system.hpp in Headers */, 670947DF1BDF9BE1005014C0 /* visual_params.hpp in Headers */, 670948171BDF9C39005014C0 /* interpolation_holder.hpp in Headers */, 670947FD1BDF9BF5005014C0 /* base_renderer.hpp in Headers */, 670947D51BDF9BE1005014C0 /* tile_utils.hpp in Headers */, 670947D91BDF9BE1005014C0 /* user_mark_shapes.hpp in Headers */, + 454C19BB1CCE3EC0002A2C86 /* animation_constants.hpp in Headers */, 6709481F1BDF9C39005014C0 /* show_hide_animation.hpp in Headers */, - 6743D3761C3A9F530095054B /* perspective_animation.hpp in Headers */, 670E393B1C46C59000E9C0A6 /* batch_merge_helper.hpp in Headers */, 670947931BDF9BE1005014C0 /* kinetic_scroller.hpp in Headers */, 670947E71BDF9BEC005014C0 /* frontend_renderer.hpp in Headers */, @@ -770,6 +767,7 @@ 67E91C791BDFC85E005CEE88 /* base_renderer.cpp in Sources */, 67E91C7A1BDFC85E005CEE88 /* circle_shape.cpp in Sources */, 67E91C7B1BDFC85E005CEE88 /* my_position_controller.cpp in Sources */, + 454C19BC1CCE3EC0002A2C86 /* animation_system.cpp in Sources */, 67E91C7C1BDFC85E005CEE88 /* selection_shape.cpp in Sources */, 67E91C7D1BDFC85E005CEE88 /* user_marks_provider.cpp in Sources */, 67E91C7E1BDFC85E005CEE88 /* visual_params.cpp in Sources */, @@ -796,7 +794,6 @@ 670948711BDF9C7F005014C0 /* feature_styler.cpp in Sources */, 670948471BDF9C48005014C0 /* layer_render.cpp in Sources */, 6709486C1BDF9C7F005014C0 /* cpu_drawer.cpp in Sources */, - 6743D3751C3A9F530095054B /* perspective_animation.cpp in Sources */, 670947C41BDF9BE1005014C0 /* text_handle.cpp in Sources */, 670947BD1BDF9BE1005014C0 /* rule_drawer.cpp in Sources */, 6709481E1BDF9C39005014C0 /* show_hide_animation.cpp in Sources */, @@ -804,7 +801,6 @@ 6709483D1BDF9C48005014C0 /* copyright_label.cpp in Sources */, 670947C81BDF9BE1005014C0 /* text_shape.cpp in Sources */, 670947CC1BDF9BE1005014C0 /* tile_info.cpp in Sources */, - 6709481A1BDF9C39005014C0 /* model_view_animation.cpp in Sources */, 670947961BDF9BE1005014C0 /* line_shape.cpp in Sources */, 670948681BDF9C7F005014C0 /* agg_curves.cpp in Sources */, 670947A91BDF9BE1005014C0 /* path_symbol_shape.cpp in Sources */,