diff --git a/anim/task.cpp b/anim/task.cpp index 8b8726ba7c..01e548eef1 100644 --- a/anim/task.cpp +++ b/anim/task.cpp @@ -55,4 +55,9 @@ namespace anim { return State() == ECancelled; } + + bool Task::IsRunning() const + { + return State() == EInProgress; + } } diff --git a/anim/task.hpp b/anim/task.hpp index 538481ae15..b1366e9c80 100644 --- a/anim/task.hpp +++ b/anim/task.hpp @@ -40,5 +40,6 @@ namespace anim bool IsCancelled() const; bool IsEnded() const; + bool IsRunning() const; }; } diff --git a/map/location_state.cpp b/map/location_state.cpp index 9b0544aab4..c9eef2d7d8 100644 --- a/map/location_state.cpp +++ b/map/location_state.cpp @@ -149,8 +149,7 @@ namespace location m_framework->ShowRectFixed(m2::AnyRectD(rect.Center(), a, m2::RectD(-dx/2, -dy/2, dx/2, dy/2))); SetIsCentered(true); - if (m_compassProcessMode == ECompassFollow) - FollowCompass(); + CheckFollowCompass(); m_locationProcessMode = ELocationCenterOnly; break; @@ -160,8 +159,7 @@ namespace location m_framework->SetViewportCenter(center); SetIsCentered(true); - if (m_compassProcessMode == ECompassFollow) - FollowCompass(); + CheckFollowCompass(); break; @@ -374,43 +372,54 @@ namespace location return false; } + void State::CheckFollowCompass() + { + if (m_hasCompass && (CompassProcessMode() == ECompassFollow) && IsCentered()) + FollowCompass(); + } + void State::FollowCompass() { if (!m_framework->GetNavigator().DoSupportRotation()) return; - m_framework->GetRenderPolicy()->GetAnimController()->Lock(); + shared_ptr controller = m_framework->GetRenderPolicy()->GetAnimController(); - m_framework->GetInformationDisplay().locationState()->StopAnimation(); - StopAnimation(); + controller->Lock(); double startAngle = m_framework->GetNavigator().Screen().GetAngle(); - double endAngle = -m_headingRad; + double endAngle = -m_compassFilter.GetHeadingRad(); - double period = 2 * math::pi; + bool shouldRotate = false; - startAngle = fmod(startAngle, period); - endAngle = fmod(endAngle, period); - - if (fabs(startAngle - endAngle) > 20.0 / 180.0 * math::pi) + if (m_rotateScreenTask && m_rotateScreenTask->IsRunning()) { - if (fabs(startAngle - endAngle) > math::pi) - { - if (startAngle > endAngle) - startAngle -= 2 * math::pi; - else - endAngle -= 2 * math::pi; - } + // if the end angle seriously changed we should re-create rotation task. + if (fabs(ang::GetShortestDistance(m_rotateScreenTask->EndAngle(), endAngle)) > ang::DegreeToRad(10)) + shouldRotate = true; + } + else + { + // if there are no current rotate screen task or the task is finished already + // we check for the distance between current screen angle and headingAngle + if (fabs(ang::GetShortestDistance(startAngle, endAngle)) > ang::DegreeToRad(10)) + shouldRotate = true; + } + + if (shouldRotate) + { + m_framework->GetInformationDisplay().locationState()->StopAnimation(); + StopAnimation(); m_rotateScreenTask.reset(new RotateScreenTask(m_framework, startAngle, endAngle, 2)); - m_framework->GetRenderPolicy()->GetAnimController()->AddTask(m_rotateScreenTask); + controller->AddTask(m_rotateScreenTask); } - m_framework->GetRenderPolicy()->GetAnimController()->Unlock(); + controller->Unlock(); } void State::StopAnimation() diff --git a/map/location_state.hpp b/map/location_state.hpp index e63a6d5f18..d894c00179 100644 --- a/map/location_state.hpp +++ b/map/location_state.hpp @@ -124,6 +124,8 @@ namespace location void SetIsCentered(bool flag); bool IsCentered() const; + void CheckFollowCompass(); + /// @name GPS location updates routine. //@{ void SkipLocationCentering(); diff --git a/map/rotate_screen_task.cpp b/map/rotate_screen_task.cpp index 24d929c7a8..42246e9294 100644 --- a/map/rotate_screen_task.cpp +++ b/map/rotate_screen_task.cpp @@ -10,13 +10,14 @@ RotateScreenTask::RotateScreenTask(Framework * framework, m_endAngle(endAngle) { m_startTime = 0; - m_interval = fabs(endAngle - m_startAngle) / (2 * math::pi) * speed; + m_dist = ang::GetShortestDistance(m_startAngle, m_endAngle); + m_interval = fabs(m_dist) / (2 * math::pi) * speed; + m_endAngle = m_startAngle + m_dist; } void RotateScreenTask::OnStart(double ts) { m_startTime = ts; - m_curAngle = m_startAngle; anim::Task::OnStart(ts); } @@ -28,14 +29,13 @@ void RotateScreenTask::OnStep(double ts) return; } - if (IsEnded()) + if (!IsRunning()) return; double elapsedSec = ts - m_startTime; - double angle = m_startAngle + (m_endAngle - m_startAngle) * elapsedSec / m_interval; + double angle = m_startAngle + m_dist * elapsedSec / m_interval; - m_framework->GetNavigator().Rotate(angle - m_curAngle); - m_curAngle = angle; + m_framework->GetNavigator().SetAngle(angle); } void RotateScreenTask::OnEnd(double ts) @@ -43,3 +43,8 @@ void RotateScreenTask::OnEnd(double ts) /// ensuring that the final angle is reached m_framework->GetNavigator().SetAngle(m_endAngle); } + +double RotateScreenTask::EndAngle() const +{ + return m_endAngle; +} diff --git a/map/rotate_screen_task.hpp b/map/rotate_screen_task.hpp index 634b6499c7..7cbde9f446 100644 --- a/map/rotate_screen_task.hpp +++ b/map/rotate_screen_task.hpp @@ -12,9 +12,9 @@ private: double m_startTime; double m_startAngle; + double m_dist; double m_endAngle; double m_interval; - double m_curAngle; public: @@ -26,4 +26,6 @@ public: void OnStart(double ts); void OnStep(double ts); void OnEnd(double ts); + + double EndAngle() const; };