From 2252f207a4761d01c15cfd757f59ba8a512e12d2 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Sun, 22 May 2016 20:51:27 +0300 Subject: [PATCH] Move functions that change ScreenBase into a separate file. --- drape_frontend/animation/scale_animation.cpp | 10 +- drape_frontend/animation/scale_animation.hpp | 6 +- drape_frontend/drape_frontend.pro | 2 + drape_frontend/frontend_renderer.cpp | 5 +- drape_frontend/navigator.cpp | 239 +-------------- drape_frontend/navigator.hpp | 14 +- drape_frontend/screen_operations.cpp | 306 +++++++++++++++++++ drape_frontend/screen_operations.hpp | 38 +++ drape_frontend/user_event_stream.cpp | 83 +---- drape_frontend/user_event_stream.hpp | 2 - 10 files changed, 373 insertions(+), 332 deletions(-) create mode 100644 drape_frontend/screen_operations.cpp create mode 100644 drape_frontend/screen_operations.hpp diff --git a/drape_frontend/animation/scale_animation.cpp b/drape_frontend/animation/scale_animation.cpp index e89d5c1176..5d998273c3 100644 --- a/drape_frontend/animation/scale_animation.cpp +++ b/drape_frontend/animation/scale_animation.cpp @@ -7,12 +7,12 @@ namespace df { -MapScaleAnimation::MapScaleAnimation(double startScale, double endScale, - m2::PointD const & globalPosition, m2::PointD const & offset) +MapScaleAnimation::MapScaleAnimation(double startScale, double endScale, m2::PointD const & globalScaleCenter, + m2::PointD const & pixelCenterOffset) : Animation(true /* couldBeInterrupted */, true /* couldBeBlended */) , m_scaleInterpolator(startScale, endScale) - , m_pixelOffset(offset) - , m_globalPosition(globalPosition) + , m_pixelCenterOffset(pixelCenterOffset) + , m_globalScaleCenter(globalScaleCenter) { m_objects.insert(Animation::MapPlane); m_properties.insert(Animation::Scale); @@ -62,7 +62,7 @@ bool MapScaleAnimation::GetProperty(TObject object, TProperty property, Property { ScreenBase screen = AnimationSystem::Instance().GetLastScreen(); screen.SetScale(m_scaleInterpolator.GetScale()); - value = PropertyValue(screen.PtoG(screen.GtoP(m_globalPosition) + m_pixelOffset)); + value = PropertyValue(screen.PtoG(screen.GtoP(m_globalScaleCenter) + m_pixelCenterOffset)); return true; } if (property == Animation::Scale) diff --git a/drape_frontend/animation/scale_animation.hpp b/drape_frontend/animation/scale_animation.hpp index 96dc5b2ca3..dc6a73f7af 100644 --- a/drape_frontend/animation/scale_animation.hpp +++ b/drape_frontend/animation/scale_animation.hpp @@ -10,7 +10,7 @@ class MapScaleAnimation : public Animation { public: MapScaleAnimation(double startScale, double endScale, - m2::PointD const & globalPosition, m2::PointD const & offset); + m2::PointD const & globalScaleCenter, m2::PointD const & pixelCenterOffset); Animation::Type GetType() const override { return Animation::MapScale; } @@ -38,8 +38,8 @@ public: private: ScaleInterpolator m_scaleInterpolator; - m2::PointD const m_pixelOffset; - m2::PointD const m_globalPosition; + m2::PointD const m_pixelCenterOffset; + m2::PointD const m_globalScaleCenter; TObjectProperties m_properties; TAnimObjects m_objects; }; diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index 332b9e4344..aa05e2d7fe 100755 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -74,6 +74,7 @@ SOURCES += \ route_renderer.cpp \ route_shape.cpp \ rule_drawer.cpp \ + screen_operations.cpp \ selection_shape.cpp \ stylist.cpp \ text_handle.cpp \ @@ -171,6 +172,7 @@ HEADERS += \ route_renderer.hpp \ route_shape.hpp \ rule_drawer.hpp \ + screen_operations.hpp \ selection_shape.hpp \ shape_view_params.hpp \ stylist.hpp \ diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index faac06dc66..783ee969f3 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -5,6 +5,7 @@ #include "drape_frontend/framebuffer.hpp" #include "drape_frontend/frontend_renderer.hpp" #include "drape_frontend/message_subclasses.hpp" +#include "drape_frontend/screen_operations.hpp" #include "drape_frontend/transparent_layer.hpp" #include "drape_frontend/visual_params.hpp" #include "drape_frontend/user_mark_shapes.hpp" @@ -1269,7 +1270,7 @@ void FrontendRenderer::DisablePerspective() void FrontendRenderer::CheckIsometryMinScale(ScreenBase const & screen) { - bool const isScaleAllowableIn3d = UserEventStream::IsScaleAllowableIn3d(m_currentZoomLevel); + bool const isScaleAllowableIn3d = IsScaleAllowableIn3d(m_currentZoomLevel); bool const isIsometry = m_enable3dBuildings && !m_choosePositionMode && isScaleAllowableIn3d; if (m_isIsometry != isIsometry) { @@ -1283,7 +1284,7 @@ void FrontendRenderer::CheckPerspectiveMinScale() if (!m_enablePerspectiveInNavigation || m_userEventStream.IsInPerspectiveAnimation()) return; - bool const switchTo2d = !UserEventStream::IsScaleAllowableIn3d(m_currentZoomLevel); + bool const switchTo2d = !IsScaleAllowableIn3d(m_currentZoomLevel); if ((!switchTo2d && !m_perspectiveDiscarded) || (switchTo2d && !m_userEventStream.GetCurrentScreen().isPerspective())) return; diff --git a/drape_frontend/navigator.cpp b/drape_frontend/navigator.cpp index 3544e57fab..d20c024cf5 100644 --- a/drape_frontend/navigator.cpp +++ b/drape_frontend/navigator.cpp @@ -1,4 +1,5 @@ #include "drape_frontend/navigator.hpp" +#include "drape_frontend/screen_operations.hpp" #include "drape_frontend/visual_params.hpp" #include "indexer/scales.hpp" @@ -15,18 +16,6 @@ #include "std/function.hpp" #include "std/bind.hpp" -namespace -{ - -/// @todo Review this logic in future. -/// Fix bug with floating point calculations (before Android release). -void ReduceRectHack(m2::RectD & r) -{ - r.Inflate(-1.0E-9, -1.0E-9); -} - -} // namespace - namespace df { @@ -132,159 +121,6 @@ m2::PointD Navigator::P3dtoP(m2::PointD const & pt) const return m_Screen.P3dtoP(pt); } -bool Navigator::CanShrinkInto(ScreenBase const & screen, m2::RectD const & boundRect) -{ - m2::RectD clipRect = screen.ClipRect(); - return (boundRect.SizeX() >= clipRect.SizeX()) - && (boundRect.SizeY() >= clipRect.SizeY()); -} - -ScreenBase const Navigator::ShrinkInto(ScreenBase const & screen, m2::RectD boundRect) -{ - ReduceRectHack(boundRect); - - ScreenBase res = screen; - - m2::RectD clipRect = res.ClipRect(); - if (clipRect.minX() < boundRect.minX()) - clipRect.Offset(boundRect.minX() - clipRect.minX(), 0); - if (clipRect.maxX() > boundRect.maxX()) - clipRect.Offset(boundRect.maxX() - clipRect.maxX(), 0); - if (clipRect.minY() < boundRect.minY()) - clipRect.Offset(0, boundRect.minY() - clipRect.minY()); - if (clipRect.maxY() > boundRect.maxY()) - clipRect.Offset(0, boundRect.maxY() - clipRect.maxY()); - - res.SetOrg(clipRect.Center()); - - // This assert fails near x = 180 (Philipines). - //ASSERT ( boundRect.IsRectInside(res.ClipRect()), (clipRect, res.ClipRect()) ); - return res; -} - -ScreenBase const Navigator::ScaleInto(ScreenBase const & screen, m2::RectD boundRect) -{ - ReduceRectHack(boundRect); - - ScreenBase res = screen; - - double scale = 1; - - m2::RectD clipRect = res.ClipRect(); - - ASSERT(boundRect.IsPointInside(clipRect.Center()), ("center point should be inside boundRect")); - - if (clipRect.minX() < boundRect.minX()) - { - double k = (boundRect.minX() - clipRect.Center().x) / (clipRect.minX() - clipRect.Center().x); - scale /= k; - clipRect.Scale(k); - } - if (clipRect.maxX() > boundRect.maxX()) - { - double k = (boundRect.maxX() - clipRect.Center().x) / (clipRect.maxX() - clipRect.Center().x); - scale /= k; - clipRect.Scale(k); - } - if (clipRect.minY() < boundRect.minY()) - { - double k = (boundRect.minY() - clipRect.Center().y) / (clipRect.minY() - clipRect.Center().y); - scale /= k; - clipRect.Scale(k); - } - if (clipRect.maxY() > boundRect.maxY()) - { - double k = (boundRect.maxY() - clipRect.Center().y) / (clipRect.maxY() - clipRect.Center().y); - scale /= k; - clipRect.Scale(k); - } - - res.Scale(scale); - res.SetOrg(clipRect.Center()); - - return res; -} - -ScreenBase const Navigator::ShrinkAndScaleInto(ScreenBase const & screen, m2::RectD boundRect) -{ - ReduceRectHack(boundRect); - - ScreenBase res = screen; - - m2::RectD globalRect = res.ClipRect(); - - m2::PointD newOrg = res.GetOrg(); - double scale = 1; - double offs = 0; - - if (globalRect.minX() < boundRect.minX()) - { - offs = boundRect.minX() - globalRect.minX(); - globalRect.Offset(offs, 0); - newOrg.x += offs; - - if (globalRect.maxX() > boundRect.maxX()) - { - double k = boundRect.SizeX() / globalRect.SizeX(); - scale /= k; - /// scaling always occur pinpointed to the rect center... - globalRect.Scale(k); - /// ...so we should shift a rect after scale - globalRect.Offset(boundRect.minX() - globalRect.minX(), 0); - } - } - - if (globalRect.maxX() > boundRect.maxX()) - { - offs = boundRect.maxX() - globalRect.maxX(); - globalRect.Offset(offs, 0); - newOrg.x += offs; - - if (globalRect.minX() < boundRect.minX()) - { - double k = boundRect.SizeX() / globalRect.SizeX(); - scale /= k; - globalRect.Scale(k); - globalRect.Offset(boundRect.maxX() - globalRect.maxX(), 0); - } - } - - if (globalRect.minY() < boundRect.minY()) - { - offs = boundRect.minY() - globalRect.minY(); - globalRect.Offset(0, offs); - newOrg.y += offs; - - if (globalRect.maxY() > boundRect.maxY()) - { - double k = boundRect.SizeY() / globalRect.SizeY(); - scale /= k; - globalRect.Scale(k); - globalRect.Offset(0, boundRect.minY() - globalRect.minY()); - } - } - - if (globalRect.maxY() > boundRect.maxY()) - { - offs = boundRect.maxY() - globalRect.maxY(); - globalRect.Offset(0, offs); - newOrg.y += offs; - - if (globalRect.minY() < boundRect.minY()) - { - double k = boundRect.SizeY() / globalRect.SizeY(); - scale /= k; - globalRect.Scale(k); - globalRect.Offset(0, boundRect.maxY() - globalRect.maxY()); - } - } - - res.SetOrg(globalRect.Center()); - res.Scale(scale); - - return res; -} - void Navigator::StartDrag(m2::PointD const & pt) { m_StartPt1 = m_LastPt1 = pt; @@ -346,78 +182,9 @@ void Navigator::StartScale(m2::PointD const & pt1, m2::PointD const & pt2) m_InAction = true; } -namespace +void Navigator::Scale(m2::PointD const & pixelCenterOffset, double factor) { - void CalcScalePoints(m2::PointD const & pt, double factor, m2::RectD const & pxRect, - m2::PointD & startPt, m2::PointD & endPt) - { - // pt is in x0, x0 + width - - if (pt.x != pxRect.maxX()) - { - // start scaling point is 1 / factor way between pt and right border - startPt.x = pt.x + (pxRect.maxX() - pt.x) / factor; - endPt.x = pxRect.maxX(); - } - else - { - // start scaling point is 1 - 1/factor way between left border and pt - startPt.x = pt.x + (pxRect.minX() - pt.x) / factor; - endPt.x = pxRect.minX(); - } - - if (pt.y != pxRect.maxY()) - { - startPt.y = pt.y + (pxRect.maxY() - pt.y) / factor; - endPt.y = pxRect.maxY(); - } - else - { - startPt.y = pt.y + (pxRect.minY() - pt.y) / factor; - endPt.y = pxRect.minY(); - } - } -} - -void Navigator::Scale(m2::PointD const & pt, double factor) -{ - CalculateScale(pt, factor, m_Screen); -} - -void Navigator::CalculateScale(m2::PointD const & pt, double factor, ScreenBase & screen) -{ - m2::PointD startPt, endPt; - CalcScalePoints(pt, factor, screen.isPerspective() ? screen.PixelRectIn3d() : screen.PixelRect(), startPt, endPt); - m2::PointD const newOffset = (endPt - pt) / 2.0; - m2::PointD const oldOffset = (startPt - pt) / 2.0; - ScaleImpl(pt - newOffset, pt + newOffset, pt - oldOffset, pt + oldOffset, factor > 1, false, screen); -} - -bool Navigator::CheckMinScale(ScreenBase const & screen) const -{ - m2::RectD const & r = screen.ClipRect(); - m2::RectD const & worldR = df::GetWorldRect(); - - return (r.SizeX() <= worldR.SizeX() || r.SizeY() <= worldR.SizeY()); -} - -bool Navigator::CheckMaxScale(ScreenBase const & screen) const -{ - VisualParams const & p = VisualParams::Instance(); - return CheckMaxScale(screen, p.GetTileSize(), p.GetVisualScale()); -} - -bool Navigator::CheckMaxScale(ScreenBase const & screen, uint32_t tileSize, double visualScale) const -{ - return (df::GetDrawTileScale(screen, tileSize, visualScale) <= scales::GetUpperStyleScale()); -} - -bool Navigator::CheckBorders(ScreenBase const & screen) const -{ - m2::RectD const & r = screen.ClipRect(); - m2::RectD const & worldR = df::GetWorldRect(); - - return (r.IsRectInside(worldR) || worldR.IsRectInside(r)); + ApplyScale(pixelCenterOffset, factor, m_Screen); } bool Navigator::ScaleImpl(m2::PointD const & newPt1, m2::PointD const & newPt2, diff --git a/drape_frontend/navigator.hpp b/drape_frontend/navigator.hpp index 0a39c02bc6..b7c6d945bb 100644 --- a/drape_frontend/navigator.hpp +++ b/drape_frontend/navigator.hpp @@ -40,8 +40,7 @@ public: void StopScale(m2::PointD const & pt1, m2::PointD const & pt2); bool IsRotatingDuringScale() const; - void Scale(m2::PointD const & pt, double factor); - void CalculateScale(m2::PointD const & pt, double factor, ScreenBase & screen); + void Scale(m2::PointD const & pixelCenterOffset, double factor); bool InAction() const; void Enable3dMode(double currentRotationAngle, double maxRotationAngle, double angleFOV); @@ -49,17 +48,6 @@ public: void Disable3dMode(); private: - bool CheckMinScale(ScreenBase const & screen) const; - bool CheckMaxScale(ScreenBase const & screen) const; - bool CheckMaxScale(ScreenBase const & screen, uint32_t tileSize, double visualScale) const; - bool CheckBorders(ScreenBase const & screen) const; - - static bool CanShrinkInto(ScreenBase const & screen, m2::RectD const & boundRect); - static ScreenBase const ShrinkInto(ScreenBase const & screen, m2::RectD boundRect); - - static ScreenBase const ScaleInto(ScreenBase const & screen, m2::RectD boundRect); - static ScreenBase const ShrinkAndScaleInto(ScreenBase const & screen, m2::RectD boundRect); - // Internal screen corresponding to the state when navigation began with StartDrag or StartScale. ScreenBase m_StartScreen; // Internal screen to do GtoP() and PtoG() calculations. It is always up to date with navigation. diff --git a/drape_frontend/screen_operations.cpp b/drape_frontend/screen_operations.cpp new file mode 100644 index 0000000000..96791960cd --- /dev/null +++ b/drape_frontend/screen_operations.cpp @@ -0,0 +1,306 @@ +#include "screen_operations.hpp" + +#include "drape_frontend/animation/interpolators.hpp" +#include "drape_frontend/animation/linear_animation.hpp" +#include "drape_frontend/animation/scale_animation.hpp" +#include "drape_frontend/animation_constants.hpp" +#include "drape_frontend/visual_params.hpp" + +#include "indexer/scales.hpp" + +#include "platform/platform.hpp" + +namespace +{ + +/// @todo Review this logic in future. +/// Fix bug with floating point calculations (before Android release). +void ReduceRectHack(m2::RectD & r) +{ + r.Inflate(-1.0E-9, -1.0E-9); +} + +} // namespace + +namespace df +{ + +string const kPrettyMoveAnim = "PrettyMove"; + +bool IsScaleAllowableIn3d(int scale) +{ + int minScale = scales::GetMinAllowableIn3dScale(); + if (df::VisualParams::Instance().GetVisualScale() <= 1.0) + --minScale; + if (GetPlatform().IsTablet()) + ++minScale; + return scale >= minScale; +} + +double CalculateScale(m2::RectD const & pixelRect, m2::RectD const & localRect) +{ + return max(localRect.SizeX() / pixelRect.SizeX(), localRect.SizeY() / pixelRect.SizeY()); +} + +m2::PointD 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; +} + +m2::PointD 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); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +bool CheckMinScale(ScreenBase const & screen) +{ + m2::RectD const & r = screen.ClipRect(); + m2::RectD const & worldR = df::GetWorldRect(); + + return (r.SizeX() <= worldR.SizeX() || r.SizeY() <= worldR.SizeY()); +} + +bool CheckMaxScale(ScreenBase const & screen) +{ + VisualParams const & p = VisualParams::Instance(); + return CheckMaxScale(screen, p.GetTileSize(), p.GetVisualScale()); +} + +bool CheckMaxScale(ScreenBase const & screen, uint32_t tileSize, double visualScale) +{ + return (df::GetDrawTileScale(screen, tileSize, visualScale) <= scales::GetUpperStyleScale()); +} + +bool CheckBorders(ScreenBase const & screen) +{ + m2::RectD const & r = screen.ClipRect(); + m2::RectD const & worldR = df::GetWorldRect(); + + return (r.IsRectInside(worldR) || worldR.IsRectInside(r)); +} + +bool CanShrinkInto(ScreenBase const & screen, m2::RectD const & boundRect) +{ + m2::RectD clipRect = screen.ClipRect(); + return (boundRect.SizeX() >= clipRect.SizeX()) + && (boundRect.SizeY() >= clipRect.SizeY()); +} + +ScreenBase const ShrinkInto(ScreenBase const & screen, m2::RectD boundRect) +{ + ReduceRectHack(boundRect); + + ScreenBase res = screen; + + m2::RectD clipRect = res.ClipRect(); + if (clipRect.minX() < boundRect.minX()) + clipRect.Offset(boundRect.minX() - clipRect.minX(), 0); + if (clipRect.maxX() > boundRect.maxX()) + clipRect.Offset(boundRect.maxX() - clipRect.maxX(), 0); + if (clipRect.minY() < boundRect.minY()) + clipRect.Offset(0, boundRect.minY() - clipRect.minY()); + if (clipRect.maxY() > boundRect.maxY()) + clipRect.Offset(0, boundRect.maxY() - clipRect.maxY()); + + res.SetOrg(clipRect.Center()); + + // This assert fails near x = 180 (Philipines). + //ASSERT ( boundRect.IsRectInside(res.ClipRect()), (clipRect, res.ClipRect()) ); + return res; +} + +ScreenBase const ScaleInto(ScreenBase const & screen, m2::RectD boundRect) +{ + ReduceRectHack(boundRect); + + ScreenBase res = screen; + + double scale = 1; + + m2::RectD clipRect = res.ClipRect(); + + ASSERT(boundRect.IsPointInside(clipRect.Center()), ("center point should be inside boundRect")); + + if (clipRect.minX() < boundRect.minX()) + { + double k = (boundRect.minX() - clipRect.Center().x) / (clipRect.minX() - clipRect.Center().x); + scale /= k; + clipRect.Scale(k); + } + if (clipRect.maxX() > boundRect.maxX()) + { + double k = (boundRect.maxX() - clipRect.Center().x) / (clipRect.maxX() - clipRect.Center().x); + scale /= k; + clipRect.Scale(k); + } + if (clipRect.minY() < boundRect.minY()) + { + double k = (boundRect.minY() - clipRect.Center().y) / (clipRect.minY() - clipRect.Center().y); + scale /= k; + clipRect.Scale(k); + } + if (clipRect.maxY() > boundRect.maxY()) + { + double k = (boundRect.maxY() - clipRect.Center().y) / (clipRect.maxY() - clipRect.Center().y); + scale /= k; + clipRect.Scale(k); + } + + res.Scale(scale); + res.SetOrg(clipRect.Center()); + + return res; +} + +ScreenBase const ShrinkAndScaleInto(ScreenBase const & screen, m2::RectD boundRect) +{ + ReduceRectHack(boundRect); + + ScreenBase res = screen; + + m2::RectD globalRect = res.ClipRect(); + + m2::PointD newOrg = res.GetOrg(); + double scale = 1; + double offs = 0; + + if (globalRect.minX() < boundRect.minX()) + { + offs = boundRect.minX() - globalRect.minX(); + globalRect.Offset(offs, 0); + newOrg.x += offs; + + if (globalRect.maxX() > boundRect.maxX()) + { + double k = boundRect.SizeX() / globalRect.SizeX(); + scale /= k; + /// scaling always occur pinpointed to the rect center... + globalRect.Scale(k); + /// ...so we should shift a rect after scale + globalRect.Offset(boundRect.minX() - globalRect.minX(), 0); + } + } + + if (globalRect.maxX() > boundRect.maxX()) + { + offs = boundRect.maxX() - globalRect.maxX(); + globalRect.Offset(offs, 0); + newOrg.x += offs; + + if (globalRect.minX() < boundRect.minX()) + { + double k = boundRect.SizeX() / globalRect.SizeX(); + scale /= k; + globalRect.Scale(k); + globalRect.Offset(boundRect.maxX() - globalRect.maxX(), 0); + } + } + + if (globalRect.minY() < boundRect.minY()) + { + offs = boundRect.minY() - globalRect.minY(); + globalRect.Offset(0, offs); + newOrg.y += offs; + + if (globalRect.maxY() > boundRect.maxY()) + { + double k = boundRect.SizeY() / globalRect.SizeY(); + scale /= k; + globalRect.Scale(k); + globalRect.Offset(0, boundRect.minY() - globalRect.minY()); + } + } + + if (globalRect.maxY() > boundRect.maxY()) + { + offs = boundRect.maxY() - globalRect.maxY(); + globalRect.Offset(0, offs); + newOrg.y += offs; + + if (globalRect.minY() < boundRect.minY()) + { + double k = boundRect.SizeY() / globalRect.SizeY(); + scale /= k; + globalRect.Scale(k); + globalRect.Offset(0, boundRect.maxY() - globalRect.maxY()); + } + } + + res.SetOrg(globalRect.Center()); + res.Scale(scale); + + return res; +} +//////////////////////////////////////////////// +bool ApplyScale(m2::PointD const & pixelCenterOffset, double factor, ScreenBase & screen) +{ + m2::PointD globalScaleCenter = screen.PtoG(screen.PixelRect().Center() - pixelCenterOffset); + ScreenBase tmp = screen; + tmp.Scale(factor); + + m2::PointD newCenter = tmp.PtoG(tmp.GtoP(globalScaleCenter) + pixelCenterOffset); + tmp.SetOrg(newCenter); + + if (!CheckMinScale(tmp)) + return false; + + m2::RectD const & worldR = df::GetWorldRect(); + + if (!CheckBorders(tmp)) + { + if (CanShrinkInto(tmp, worldR)) + tmp = ShrinkInto(tmp, worldR); + else + return false; + } + + if (!CheckMaxScale(tmp)) + return false; + + // re-checking the borders, as we might violate them a bit (don't know why). + if (!CheckBorders(tmp)) + tmp = ScaleInto(tmp, worldR); + + screen = tmp; + return true; +} + +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(); + sequenceAnim->SetCustomType(kPrettyMoveAnim); + + 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; +} + +} // namespace df diff --git a/drape_frontend/screen_operations.hpp b/drape_frontend/screen_operations.hpp new file mode 100644 index 0000000000..32e9eb166e --- /dev/null +++ b/drape_frontend/screen_operations.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "geometry/screenbase.hpp" +#include "animation/sequence_animation.hpp" + +namespace df +{ + +extern string const kPrettyMoveAnim; + +bool CheckMinScale(ScreenBase const & screen); +bool CheckMaxScale(ScreenBase const & screen); +bool CheckMaxScale(ScreenBase const & screen, uint32_t tileSize, double visualScale); +bool CheckBorders(ScreenBase const & screen); + +bool CanShrinkInto(ScreenBase const & screen, m2::RectD const & boundRect); + +ScreenBase const ShrinkInto(ScreenBase const & screen, m2::RectD boundRect); +ScreenBase const ScaleInto(ScreenBase const & screen, m2::RectD boundRect); +ScreenBase const ShrinkAndScaleInto(ScreenBase const & screen, m2::RectD boundRect); + +bool IsScaleAllowableIn3d(int scale); + +double CalculateScale(m2::RectD const & pixelRect, m2::RectD const & localRect); + +m2::PointD CalculateCenter(ScreenBase const & screen, m2::PointD const & userPos, + m2::PointD const & pixelPos, double azimuth); +m2::PointD CalculateCenter(double scale, m2::RectD const & pixelRect, + m2::PointD const & userPos, m2::PointD const & pixelPos, + double azimuth); + +bool ApplyScale(m2::PointD const & pixelCenterOffset, double factor, ScreenBase & screen); + +drape_ptr GetPrettyMoveAnimation(ScreenBase const screen, double startScale, double endScale, + m2::PointD const & startPt, m2::PointD const & endPt, + function)> onStartAnimation); + +} // namespace df diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index a94055a9e8..92dc5d5017 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -7,6 +7,7 @@ #include "drape_frontend/animation_constants.hpp" #include "drape_frontend/animation_system.hpp" #include "drape_frontend/animation_utils.hpp" +#include "drape_frontend/screen_operations.hpp" #include "drape_frontend/visual_params.hpp" #include "indexer/scales.hpp" @@ -34,8 +35,6 @@ uint64_t const kKineticDelayMs = 500; float const kForceTapThreshold = 0.75; -string const kPrettyMoveAnim = "PrettyMove"; - size_t GetValidTouchesCount(array const & touches) { size_t result = 0; @@ -47,47 +46,6 @@ 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(); - sequenceAnim->SetCustomType(kPrettyMoveAnim); - - 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 @@ -361,17 +319,17 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, if (m_listener) m_listener->CorrectScalePoint(scaleCenter); + m2::PointD const offset = GetCurrentScreen().PixelRect().Center() - m_navigator.P3dtoP(scaleCenter); + if (isAnim) { m2::PointD glbScaleCenter = m_navigator.PtoG(m_navigator.P3dtoP(scaleCenter)); if (m_listener) m_listener->CorrectGlobalScalePoint(glbScaleCenter); - m2::PointD const offset = GetCurrentScreen().PixelRect().Center() - m_navigator.P3dtoP(scaleCenter); - ScreenBase const & startScreen = GetCurrentScreen(); ScreenBase endScreen = startScreen; - m_navigator.CalculateScale(scaleCenter, factor, endScreen); + ApplyScale(offset, factor, endScreen); auto anim = make_unique_dp(startScreen.GetScale(), endScreen.GetScale(), glbScaleCenter, offset); @@ -392,21 +350,11 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, } ResetMapPlaneAnimations(); - m_navigator.Scale(scaleCenter, factor); + m_navigator.Scale(offset, factor); if (m_listener) m_listener->OnAnimatedScaleEnded(); - return true; -} -// static -bool UserEventStream::IsScaleAllowableIn3d(int scale) -{ - int minScale = scales::GetMinAllowableIn3dScale(); - if (df::VisualParams::Instance().GetVisualScale() <= 1.0) - --minScale; - if (GetPlatform().IsTablet()) - ++minScale; - return scale >= minScale; + return true; } bool UserEventStream::SetCenter(m2::PointD const & center, int zoom, bool isAnim) @@ -492,8 +440,8 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) { ScreenBase const & screen = GetCurrentScreen(); m2::AnyRectD const startRect = GetCurrentRect(); - double const startScale = CalculateScale(screen, startRect); - double const endScale = CalculateScale(screen, rect); + double const startScale = CalculateScale(screen.PixelRect(), startRect.GetLocalRect()); + double const endScale = CalculateScale(screen.PixelRect(), rect.GetLocalRect()); drape_ptr anim = make_unique_dp(); anim->SetRotate(startRect.Angle().val(), rect.Angle().val()); @@ -572,14 +520,14 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD if (isAnim) { ScreenBase const & screen = m_navigator.Screen(); - double const targetScale = CalculateScale(screen, targetLocalRect); + double const targetScale = CalculateScale(screen.PixelRect(), targetLocalRect); auto onStartHandler = [this](ref_ptr animation) { if (m_listener) m_listener->OnAnimationStarted(animation); }; - double const startScale = CalculateScale(screen, GetCurrentRect()); + double const startScale = CalculateScale(screen.PixelRect(), GetCurrentRect().GetLocalRect()); // Reset current follow-and-rotate animation if possible. if (!InterruptFollowAnimations()) @@ -596,7 +544,7 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD (ref_ptr animation) { ScreenBase const & screen = m_navigator.Screen(); - double const startScale = CalculateScale(screen, GetCurrentRect()); + double const startScale = CalculateScale(screen.PixelRect(), GetCurrentRect().GetLocalRect()); auto anim = make_unique_dp(userPos, startScale, targetScale, screen.GlobalRect().Angle().val(), -azimuth, screen.GtoP(userPos), pixelPos, screen.PixelRect()); @@ -1282,15 +1230,8 @@ void UserEventStream::UpdateDoubleTapAndHold(Touch const & touch) m2::PointD scaleCenter = m_startDragOrg; if (m_listener) m_listener->CorrectScalePoint(scaleCenter); - m_navigator.Scale(scaleCenter, scaleFactor); - - m2::PointD glbScaleCenter = m_navigator.PtoG(m_navigator.P3dtoP(scaleCenter)); - if (m_listener) - m_listener->CorrectGlobalScalePoint(glbScaleCenter); - m2::PointD const offset = GetCurrentScreen().PixelRect().Center() - m_navigator.P3dtoP(scaleCenter); - m2::PointD const center = m_navigator.PtoG(m_navigator.GtoP(glbScaleCenter) + offset); - m_navigator.SetFromRect(m2::AnyRectD(center, m_navigator.Screen().GetAngle(), m_navigator.Screen().GlobalRect().GetLocalRect())); + m_navigator.Scale(offset, scaleFactor); } void UserEventStream::EndDoubleTapAndHold(Touch const & touch) diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 7cdf881ea7..0ac2aba679 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -274,8 +274,6 @@ public: bool IsInPerspectiveAnimation() const; bool IsWaitingForActionCompletion() const; - static bool IsScaleAllowableIn3d(int scale); - void SetListener(ref_ptr listener) { m_listener = listener; } void SetKineticScrollEnabled(bool enabled);