From e8ca5fc6d1fde0f606a06f78e03882ee992f4d4e Mon Sep 17 00:00:00 2001 From: Viktor Govako Date: Fri, 6 Oct 2023 04:35:22 -0300 Subject: [PATCH 1/2] [drape] Minor fixes and comments. Signed-off-by: Viktor Govako --- drape/visual_scale.hpp | 10 +++++----- drape_frontend/drape_engine.cpp | 7 +------ drape_frontend/user_event_stream.cpp | 12 +++++++++++- drape_frontend/user_event_stream.hpp | 25 ++++++++++++++----------- drape_frontend/visual_params.cpp | 13 +++++++------ drape_frontend/visual_params.hpp | 2 +- 6 files changed, 39 insertions(+), 30 deletions(-) diff --git a/drape/visual_scale.hpp b/drape/visual_scale.hpp index 68518196ab..1b559ff523 100644 --- a/drape/visual_scale.hpp +++ b/drape/visual_scale.hpp @@ -1,17 +1,17 @@ #pragma once +#include "platform/platform.hpp" namespace dp { +/// This fuction is called in iOS/Android native code. inline double VisualScale(double exactDensityDPI) { - double constexpr kMdpiDensityDPI = 160.; - double const tabletFactor = 1.2; // In case of tablets and iPads increased DPI is used to make visual scale bigger. if (GetPlatform().IsTablet()) - exactDensityDPI *= tabletFactor; + exactDensityDPI *= 1.2; - // For some old devices (for example iPad 2) the density could be less than 160 DPI. + // For some old devices (for example iPad 2) the density could be less than 160 DPI (mdpi). // Returns one in that case to keep readable text on the map. - return std::max(1.35, exactDensityDPI / kMdpiDensityDPI); + return std::max(1.35, exactDensityDPI / 160.0); } } // namespace dp diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 54878dfb2f..448f7441e7 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -31,7 +31,7 @@ DrapeEngine::DrapeEngine(Params && params) VisualParams::Init(params.m_vs, df::CalculateTileSize(m_viewport.GetWidth(), m_viewport.GetHeight())); - df::VisualParams::Instance().SetFontScale(params.m_fontsScaleFactor); + SetFontScaleFactor(params.m_fontsScaleFactor); gui::DrapeGui::Instance().SetSurfaceSize(m2::PointF(m_viewport.GetWidth(), m_viewport.GetHeight())); @@ -839,11 +839,6 @@ void DrapeEngine::EnableIsolines(bool enable) void DrapeEngine::SetFontScaleFactor(double scaleFactor) { - double const kMinScaleFactor = 0.5; - double const kMaxScaleFactor = 2.0; - - scaleFactor = base::Clamp(scaleFactor, kMinScaleFactor, kMaxScaleFactor); - VisualParams::Instance().SetFontScale(scaleFactor); } diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 96f97a7600..96416b895f 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -66,7 +66,6 @@ char const * UserEventStream::DOUBLE_TAP_AND_HOLD = "DoubleTapAndHold"; char const * UserEventStream::END_DOUBLE_TAP_AND_HOLD = "EndDoubleTapAndHold"; #endif -uint8_t constexpr TouchEvent::INVALID_MASKED_POINTER = 0xFF; void TouchEvent::SetFirstTouch(const Touch & touch) { @@ -129,6 +128,17 @@ void TouchEvent::Swap() SetSecondMaskedPointer(swapIndex(GetSecondMaskedPointer())); } +std::string DebugPrint(Touch const & t) +{ + return DebugPrint(t.m_location) + "; " + std::to_string(t.m_id) + "; " + std::to_string(t.m_force); +} + +std::string DebugPrint(TouchEvent const & e) +{ + return std::to_string(e.m_type) + "; { " + DebugPrint(e.m_touches[0]) + " }"; +} + + UserEventStream::UserEventStream() : m_state(STATE_EMPTY) , m_animationSystem(AnimationSystem::Instance()) diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 1f4172088f..fa26dda21d 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -54,6 +54,8 @@ struct Touch m2::PointF m_location = m2::PointF::Zero(); int64_t m_id = -1; // if id == -1 then touch is invalid float m_force = 0.0; // relative force of touch [0.0 - 1.0] + + friend std::string DebugPrint(Touch const & t); }; class TouchEvent : public UserEvent @@ -73,7 +75,7 @@ public: TOUCH_CANCEL }; - static uint8_t const INVALID_MASKED_POINTER; + static uint8_t constexpr INVALID_MASKED_POINTER = 0xFF; EventType GetType() const override { return UserEvent::EventType::Touch; } @@ -106,6 +108,8 @@ public: uint8_t GetSecondMaskedPointer() const; size_t GetMaskedCount(); + friend std::string DebugPrint(TouchEvent const & e); + private: void Swap(); @@ -330,7 +334,7 @@ private: class RotateEvent : public UserEvent { public: - explicit RotateEvent(double targetAzimuth, bool isAnim, TAnimationCreator const & parallelAnimCreator) + RotateEvent(double targetAzimuth, bool isAnim, TAnimationCreator const & parallelAnimCreator) : m_targetAzimuth(targetAzimuth) , m_isAnim(isAnim) , m_parallelAnimCreator(parallelAnimCreator) @@ -381,19 +385,18 @@ private: class ScrollEvent : public UserEvent { public: - ScrollEvent(double distanceX, double distanceY) - : m_distanceX(distanceX) - , m_distanceY(distanceY) - {} + ScrollEvent(double distanceX, double distanceY) + : m_distanceX(distanceX), m_distanceY(distanceY) + {} - EventType GetType() const override { return UserEvent::EventType::Scroll; } + EventType GetType() const override { return UserEvent::EventType::Scroll; } - double GetDistanceX() const { return m_distanceX; } - double GetDistanceY() const { return m_distanceY; } + double GetDistanceX() const { return m_distanceX; } + double GetDistanceY() const { return m_distanceY; } private: - double m_distanceX; - double m_distanceY; + double m_distanceX; + double m_distanceY; }; class UserEventStream diff --git a/drape_frontend/visual_params.cpp b/drape_frontend/visual_params.cpp index 6fb6419a60..320420cc31 100644 --- a/drape_frontend/visual_params.cpp +++ b/drape_frontend/visual_params.cpp @@ -55,8 +55,6 @@ void VisualParams::Init(double vs, uint32_t tileSize) vizParams.m_tileSize = tileSize; vizParams.m_visualScale = vs; - LOG(LINFO, ("Visual scale =", vs, "; Tile size =", tileSize)); - // Here we set up glyphs rendering parameters separately for high-res and low-res screens. if (vs <= 1.0) vizParams.m_glyphVisualParams = { 0.48f, 0.08f, 0.2f, 0.01f, 0.49f, 0.04f }; @@ -64,6 +62,8 @@ void VisualParams::Init(double vs, uint32_t tileSize) vizParams.m_glyphVisualParams = { 0.5f, 0.06f, 0.2f, 0.01f, 0.49f, 0.04f }; RISE_INITED; + + LOG(LINFO, ("Visual scale =", vs, "; Tile size =", tileSize, "; Resources =", GetResourcePostfix(vs))); } uint32_t VisualParams::GetGlyphSdfScale() const @@ -93,7 +93,7 @@ double VisualParams::GetFontScale() const void VisualParams::SetFontScale(double fontScale) { ASSERT_INITED; - m_fontScale = fontScale; + m_fontScale = base::Clamp(fontScale, 0.5, 2.0); } void VisualParams::SetVisualScale(double visualScale) @@ -110,7 +110,9 @@ std::string const & VisualParams::GetResourcePostfix(double visualScale) ASSERT_INITED; static VisualScale postfixes[] = { + /// @todo Not used in mobile because of minimal visual scale (@see visual_scale.hpp) {"mdpi", kMdpiScale}, + {"hdpi", kHdpiScale}, {"xhdpi", kXhdpiScale}, {"6plus", k6plusScale}, @@ -186,10 +188,9 @@ VisualParams::GlyphVisualParams const & VisualParams::GetGlyphVisualParams() con return m_glyphVisualParams; } -m2::RectD const & GetWorldRect() +m2::RectD GetWorldRect() { - static m2::RectD const worldRect = mercator::Bounds::FullRect(); - return worldRect; + return mercator::Bounds::FullRect(); } int GetTileScaleBase(ScreenBase const & s, uint32_t tileSize) diff --git a/drape_frontend/visual_params.hpp b/drape_frontend/visual_params.hpp index 5a4260c7f6..2f0089b418 100644 --- a/drape_frontend/visual_params.hpp +++ b/drape_frontend/visual_params.hpp @@ -75,7 +75,7 @@ private: DISALLOW_COPY_AND_MOVE(VisualParams); }; -m2::RectD const & GetWorldRect(); +m2::RectD GetWorldRect(); int GetTileScaleBase(ScreenBase const & s, uint32_t tileSize); int GetTileScaleBase(ScreenBase const & s); -- 2.45.3 From b0cb2565ab873f0dd5c23994fd223719d0c70297 Mon Sep 17 00:00:00 2001 From: Viktor Govako Date: Fri, 6 Oct 2023 09:36:48 -0300 Subject: [PATCH 2/2] [drape] Fixed "inertial" kinetic scroll. Signed-off-by: Viktor Govako --- drape_frontend/kinetic_scroller.cpp | 121 ++++++++++++++-------------- drape_frontend/kinetic_scroller.hpp | 17 ++-- 2 files changed, 68 insertions(+), 70 deletions(-) diff --git a/drape_frontend/kinetic_scroller.cpp b/drape_frontend/kinetic_scroller.cpp index cb46a97283..fc5de5bf83 100644 --- a/drape_frontend/kinetic_scroller.cpp +++ b/drape_frontend/kinetic_scroller.cpp @@ -1,27 +1,25 @@ #include "kinetic_scroller.hpp" #include "visual_params.hpp" -#include "indexer/scales.hpp" - -#include "base/logging.hpp" - #include namespace df { -double const kKineticDuration = 1.5; -double const kKineticFadeoff = 4.0; -double const kKineticThreshold = 50.0; -double const kKineticAcceleration = 0.4; -double const kKineticMaxSpeedStart = 1000.0; // pixels per second -double const kKineticMaxSpeedEnd = 10000.0; // pixels per second -double const kInstantVelocityThresholdUnscaled = 200.0; // pixels per second +double constexpr kKineticDuration = 1.5; +double constexpr kKineticFadeoff = 4.0; +double constexpr kKineticAcceleration = 0.4; + +/// @name Generic pixels per second. Should multiply on visual scale. +/// @{ +double constexpr kKineticMaxSpeedStart = 1000.0; +double constexpr kKineticMaxSpeedEnd = 5000.0; +double constexpr kInstantVelocityThreshold = 200.0; +/// @} double CalculateKineticMaxSpeed(ScreenBase const & modelView) { double const lerpCoef = 1.0 - GetNormalizedZoomLevel(modelView.GetScale()); - return (kKineticMaxSpeedStart * lerpCoef + kKineticMaxSpeedEnd * (1.0 - lerpCoef)) * - VisualParams::Instance().GetVisualScale(); + return kKineticMaxSpeedStart * lerpCoef + kKineticMaxSpeedEnd * (1.0 - lerpCoef); } class KineticScrollAnimation : public Animation @@ -122,25 +120,32 @@ void KineticScroller::Init(ScreenBase const & modelView) { ASSERT(!m_isActive, ()); m_isActive = true; - m_lastRect = modelView.GlobalRect(); - m_lastTimestamp = std::chrono::steady_clock::now(); - m_updatePosition = modelView.GlobalRect().GlobalCenter(); - m_updateTimestamp = m_lastTimestamp; + + m_points.clear(); + m_points.emplace_back(modelView.GlobalRect().Center(), ClockT::now()); } void KineticScroller::Update(ScreenBase const & modelView) { ASSERT(m_isActive, ()); - using namespace std::chrono; - auto const nowTimestamp = std::chrono::steady_clock::now(); - auto const curPos = modelView.GlobalRect().GlobalCenter(); - double const instantPixelLen = (modelView.GtoP(curPos) - modelView.GtoP(m_updatePosition)).Length(); - auto const updateElapsed = duration_cast>(nowTimestamp - m_updateTimestamp).count(); - m_instantVelocity = (updateElapsed >= 1e-5) ? instantPixelLen / updateElapsed : 0.0; + auto const nowTime = ClockT::now(); + if (m_points.size() > 1) + { + // Time window to store move points for better (smooth) _instant_ velocity calculation. + double constexpr kTimeWindowSec = 0.03; + auto it = std::find_if(m_points.begin(), m_points.end(), [&nowTime](auto const & e) + { + return GetDurationSeconds(nowTime, e.second) <= kTimeWindowSec; + }); - m_updateTimestamp = nowTimestamp; - m_updatePosition = curPos; + // Keep last point always. + if (it == m_points.end()) + --it; + m_points.erase(m_points.begin(), it); + } + + m_points.emplace_back(modelView.GlobalRect().Center(), nowTime); } bool KineticScroller::IsActive() const @@ -148,31 +153,33 @@ bool KineticScroller::IsActive() const return m_isActive; } -m2::PointD KineticScroller::GetDirection(ScreenBase const & modelView) const +// Calculate direction in mercator space, and velocity in pixel space. +// We need the same reaction on different zoom levels, and should calculate velocity on pixel space. +std::pair KineticScroller::GetDirectionAndVelocity(ScreenBase const & modelView) const { - // In KineticScroller we store m_direction in mixed state. - // Direction in mercator space, and length(m_direction) in pixel space. - // We need same reaction on different zoom levels, and should calculate velocity on pixel space. ASSERT(m_isActive, ()); - using namespace std::chrono; - auto const nowTimestamp = steady_clock::now(); - auto const elapsed = duration_cast>(nowTimestamp - m_lastTimestamp).count(); + ASSERT(!m_points.empty(), ()); + + // Or take m_points.back() ? m2::PointD const currentCenter = modelView.GlobalRect().GlobalCenter(); - m2::PointD const lastCenter = m_lastRect.GlobalCenter(); - double const pxDeltaLength = (modelView.GtoP(currentCenter) - modelView.GtoP(lastCenter)).Length(); - m2::PointD delta = currentCenter - lastCenter; - if (!delta.IsAlmostZero()) - { - delta = delta.Normalize(); + double const lengthPixel = (modelView.GtoP(currentCenter) - modelView.GtoP(m_points.front().first)).Length(); + double const elapsedSec = GetDurationSeconds(ClockT::now(), m_points.front().second); + if (elapsedSec < 1E-6) + return {{}, 0}; - // Velocity on pixels. - double const v = std::min(pxDeltaLength / elapsed, CalculateKineticMaxSpeed(modelView)); + double const vs = VisualParams::Instance().GetVisualScale(); - // At this point length(m_direction) already in pixel space, and delta normalized. - return delta * v; - } - return m2::PointD::Zero(); + // Most touch filtrations happen here. + double const velocity = lengthPixel / elapsedSec; + if (velocity < kInstantVelocityThreshold * vs) + return {{}, 0}; + + m2::PointD const delta = currentCenter - m_points.front().first; + if (delta.IsAlmostZero()) + return {{}, 0}; + + return {delta.Normalize(), std::min(velocity, CalculateKineticMaxSpeed(modelView) * vs)}; } void KineticScroller::Cancel() @@ -182,30 +189,20 @@ void KineticScroller::Cancel() drape_ptr KineticScroller::CreateKineticAnimation(ScreenBase const & modelView) { - static double vs = VisualParams::Instance().GetVisualScale(); - static double kVelocityThreshold = kKineticThreshold * vs; - static double kInstantVelocityThreshold = kInstantVelocityThresholdUnscaled * vs; - - if (m_instantVelocity < kInstantVelocityThreshold) - { - Cancel(); - return drape_ptr(); - } - - auto const direction = GetDirection(modelView); + auto const [dir, velocity] = GetDirectionAndVelocity(modelView); + // Cancel current animation in any case. Cancel(); + if (velocity < 1E-6) + return {}; - if (direction.Length() < kVelocityThreshold) - return drape_ptr(); - - // Before we start animation we have to convert length(m_direction) from pixel space to mercator space. + // Before we start animation we have to convert velocity vector from pixel space to mercator space. m2::PointD const center = modelView.GlobalRect().GlobalCenter(); - double const offset = (modelView.PtoG(modelView.GtoP(center) + direction) - center).Length(); + double const offset = (modelView.PtoG(modelView.GtoP(center) + dir * velocity) - center).Length(); double const glbLength = kKineticAcceleration * offset; - m2::PointD const glbDirection = direction.Normalize() * glbLength; + m2::PointD const glbDirection = dir * glbLength; m2::PointD const targetCenter = center + glbDirection; if (!df::GetWorldRect().IsPointInside(targetCenter)) - return drape_ptr(); + return {}; return make_unique_dp(center, glbDirection, kKineticDuration); } diff --git a/drape_frontend/kinetic_scroller.hpp b/drape_frontend/kinetic_scroller.hpp index d3950a7870..4ca944e420 100644 --- a/drape_frontend/kinetic_scroller.hpp +++ b/drape_frontend/kinetic_scroller.hpp @@ -4,9 +4,8 @@ #include "drape/pointers.hpp" -#include "geometry/any_rect2d.hpp" - #include +#include namespace df { @@ -20,13 +19,15 @@ public: drape_ptr CreateKineticAnimation(ScreenBase const & modelView); private: - m2::PointD GetDirection(ScreenBase const & modelView) const; + std::pair GetDirectionAndVelocity(ScreenBase const & modelView) const; - std::chrono::steady_clock::time_point m_lastTimestamp; - std::chrono::steady_clock::time_point m_updateTimestamp; + using ClockT = std::chrono::steady_clock; + static double GetDurationSeconds(ClockT::time_point const & t2, ClockT::time_point const & t1) + { + return std::chrono::duration_cast>(t2 - t1).count(); + } + + std::deque> m_points; bool m_isActive = false; - m2::AnyRectD m_lastRect; - m2::PointD m_updatePosition; - double m_instantVelocity = 0.0; }; } // namespace df -- 2.45.3