diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index 886441d148..76d113ecdf 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -75,17 +75,22 @@ private: } // namespace -bool AnimationSystem::GetRect(ScreenBase const & currentScreen, m2::AnyRectD & rect) +void AnimationSystem::UpdateLastScreen(ScreenBase const & currentScreen) { - return GetRect(currentScreen, bind(&AnimationSystem::GetProperty, this, _1, _2, _3), rect); + m_lastScreen = currentScreen; } -void AnimationSystem::GetTargetRect(ScreenBase const & currentScreen, m2::AnyRectD & rect) +bool AnimationSystem::GetScreen(ScreenBase const & currentScreen, ScreenBase & screen) { - GetRect(currentScreen, bind(&AnimationSystem::GetTargetProperty, this, _1, _2, _3), rect); + return GetScreen(currentScreen, bind(&AnimationSystem::GetProperty, this, _1, _2, _3), screen); } -bool AnimationSystem::GetRect(ScreenBase const & currentScreen, TGetPropertyFn const & getPropertyFn, m2::AnyRectD & rect) +void AnimationSystem::GetTargetScreen(ScreenBase const & currentScreen, ScreenBase & screen) +{ + GetScreen(currentScreen, bind(&AnimationSystem::GetTargetProperty, this, _1, _2, _3), screen); +} + +bool AnimationSystem::GetScreen(ScreenBase const & currentScreen, TGetPropertyFn const & getPropertyFn, ScreenBase & screen) { ASSERT(getPropertyFn != nullptr, ()); @@ -105,10 +110,8 @@ bool AnimationSystem::GetRect(ScreenBase const & currentScreen, TGetPropertyFn c if (getPropertyFn(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); + screen = currentScreen; + screen.SetFromParams(pos, angle, scale); return true; } diff --git a/drape_frontend/animation_system.hpp b/drape_frontend/animation_system.hpp index 7a23337e1a..c989da99f2 100644 --- a/drape_frontend/animation_system.hpp +++ b/drape_frontend/animation_system.hpp @@ -19,8 +19,9 @@ class AnimationSystem : private noncopyable public: static AnimationSystem & Instance(); - bool GetRect(ScreenBase const & currentScreen, m2::AnyRectD & rect); - void GetTargetRect(ScreenBase const & currentScreen, m2::AnyRectD & rect); + void UpdateLastScreen(ScreenBase const & currentScreen); + bool GetScreen(ScreenBase const & currentScreen, ScreenBase & screen); + void GetTargetScreen(ScreenBase const & currentScreen, ScreenBase & screen); bool SwitchPerspective(Animation::SwitchPerspectiveParams & params); bool GetPerspectiveAngle(double & angle); @@ -66,7 +67,7 @@ private: using TGetPropertyFn = function; - bool GetRect(ScreenBase const & currentScreen, TGetPropertyFn const & getPropertyFn, m2::AnyRectD & rect); + bool GetScreen(ScreenBase const & currentScreen, TGetPropertyFn const & getPropertyFn, ScreenBase & screen); bool GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue & value) const; diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 9b826a08c7..d8c9010db5 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -811,17 +811,24 @@ void FrontendRenderer::InvalidateRect(m2::RectD const & gRect) void FrontendRenderer::OnResize(ScreenBase const & screen) { - m2::RectD const viewportRect = screen.isPerspective() ? screen.PixelRectIn3d() : screen.PixelRect(); + m2::RectD const viewportRect = screen.PixelRectIn3d(); + double const kEps = 1e-5; + bool const viewportChanged = !m2::IsEqualSize(m_lastReadedModelView.PixelRectIn3d(), viewportRect, kEps, kEps); m_myPositionController->UpdatePixelPosition(screen); m_myPositionController->OnNewPixelRect(); - m_viewport.SetViewport(0, 0, viewportRect.SizeX(), viewportRect.SizeY()); - m_contextFactory->getDrawContext()->resize(viewportRect.SizeX(), viewportRect.SizeY()); + if (viewportChanged) + { + m_viewport.SetViewport(0, 0, viewportRect.SizeX(), viewportRect.SizeY()); + m_contextFactory->getDrawContext()->resize(viewportRect.SizeX(), viewportRect.SizeY()); + m_framebuffer->SetSize(viewportRect.SizeX(), viewportRect.SizeY()); + } + RefreshProjection(screen); RefreshPivotTransform(screen); - m_framebuffer->SetSize(viewportRect.SizeX(), viewportRect.SizeY()); + } void FrontendRenderer::AddToRenderGroup(dp::GLState const & state, @@ -1647,7 +1654,8 @@ void FrontendRenderer::PositionChanged(m2::PointD const & position) void FrontendRenderer::ChangeModelView(m2::PointD const & center, int zoomLevel) { - AddUserEvent(SetCenterEvent(center, zoomLevel, true)); + AddUserEvent(FollowAndRotateEvent(center, m_userEventStream.GetCurrentScreen().PixelRectIn3d().Center(), -m_userEventStream.GetCurrentScreen().GetAngle(), zoomLevel, true)); + //AddUserEvent(SetCenterEvent(center, zoomLevel, true)); } void FrontendRenderer::ChangeModelView(double azimuth) diff --git a/drape_frontend/navigator.cpp b/drape_frontend/navigator.cpp index 273e8c1194..ecaefccea2 100644 --- a/drape_frontend/navigator.cpp +++ b/drape_frontend/navigator.cpp @@ -26,18 +26,45 @@ Navigator::Navigator() { } -void Navigator::SetFromRects(m2::AnyRectD const & glbRect, m2::RectD const & pxRect) +void Navigator::SetFromRect2(m2::AnyRectD const & r) { + ScreenBase tmp = m_Screen; + m2::RectD const & worldR = df::GetWorldRect(); - m_Screen.SetFromRects(glbRect, pxRect); - m_Screen = ScaleInto(m_Screen, worldR); + tmp.SetFromRect2d(r); + tmp = ScaleInto(tmp, worldR); + + m_Screen = tmp; if (!m_InAction) + m_StartScreen = tmp; +} + +void Navigator::SetScreen(ScreenBase const & screen) +{ + m2::RectD const & worldR = df::GetWorldRect(); + ScreenBase tmp = screen; + tmp = ScaleInto(tmp, worldR); + + VisualParams const & p = VisualParams::Instance(); + + if (!CheckMaxScale(tmp, p.GetTileSize(), p.GetVisualScale())) { - m_StartScreen.SetFromRects(glbRect, pxRect); - m_StartScreen = ScaleInto(m_StartScreen, worldR); + int const scale = scales::GetUpperStyleScale() - 1; + m2::RectD newRect = df::GetRectForDrawScale(scale, screen.GetOrg()); + newRect.Scale(m_Screen.GetScale3d()); + CheckMinMaxVisibleScale(newRect, scale, m_Screen.GetScale3d()); + tmp = m_Screen; + tmp.SetFromRect(m2::AnyRectD(newRect)); + + ASSERT(CheckMaxScale(tmp, p.GetTileSize(), p.GetVisualScale()), ()); } + + m_Screen = tmp; + + if (!m_InAction) + m_StartScreen = tmp; } void Navigator::SetFromRect(m2::AnyRectD const & r) @@ -88,25 +115,11 @@ void Navigator::OnSize(int w, int h) { m2::RectD const & worldR = df::GetWorldRect(); - double const fov = m_Screen.GetAngleFOV(); - double const rotation = m_Screen.GetRotationAngle(); - if (m_Screen.isPerspective()) - { - m_Screen.ResetPerspective(); - m_StartScreen.ResetPerspective(); - } - m_Screen.OnSize(0, 0, w, h); m_Screen = ShrinkAndScaleInto(m_Screen, worldR); m_StartScreen.OnSize(0, 0, w, h); m_StartScreen = ShrinkAndScaleInto(m_StartScreen, worldR); - - if (fov != 0.0) - { - m_Screen.ApplyPerspective(rotation, rotation, fov); - m_StartScreen.ApplyPerspective(rotation, rotation, fov); - } } m2::PointD Navigator::GtoP(m2::PointD const & pt) const @@ -197,6 +210,7 @@ bool Navigator::ScaleImpl(m2::PointD const & newPt1, m2::PointD const & newPt2, { m2::PointD const center3d = oldPt1; m2::PointD const center2d = screen.P3dtoP(center3d); + m2::PointD const centerG = screen.PtoG(center2d); m2::PointD const offset = center2d - center3d; math::Matrix const newM = screen.GtoPMatrix() * ScreenBase::CalcTransform(oldPt1 + offset, oldPt2 + offset, @@ -204,6 +218,7 @@ bool Navigator::ScaleImpl(m2::PointD const & newPt1, m2::PointD const & newPt2, doRotateScreen); ScreenBase tmp = screen; tmp.SetGtoPMatrix(newM); + tmp.MatchGandP3d(centerG, center3d); if (!skipMinScaleAndBordersCheck && !CheckMinScale(tmp)) return false; @@ -310,13 +325,6 @@ void Navigator::Disable3dMode() m_Screen.ResetPerspective(); } -bool Navigator::UpdatePerspective() -{ - double const maxPerspAngle = m_Screen.GetMaxRotationAngle(); - m_Screen.UpdatePerspectiveParameters(); - return maxPerspAngle != m_Screen.GetMaxRotationAngle(); -} - m2::AnyRectD ToRotated(Navigator const & navigator, m2::RectD const & rect) { double const dx = rect.SizeX(); diff --git a/drape_frontend/navigator.hpp b/drape_frontend/navigator.hpp index 01c3272d95..25d9ea0fbb 100644 --- a/drape_frontend/navigator.hpp +++ b/drape_frontend/navigator.hpp @@ -18,9 +18,10 @@ class Navigator public: Navigator(); + void SetScreen(ScreenBase const & screen); void SetFromRect(m2::AnyRectD const & r); + void SetFromRect2(m2::AnyRectD const & r); void CenterViewport(m2::PointD const & p); - void SetFromRects(m2::AnyRectD const & glbRect, m2::RectD const & pxRect); void SetFromRect(m2::AnyRectD const & r, uint32_t tileSize, double visualScale); void OnSize(int w, int h); @@ -48,7 +49,6 @@ public: void Enable3dMode(double currentRotationAngle, double maxRotationAngle, double angleFOV); void SetRotationIn3dMode(double rotationAngle); void Disable3dMode(); - bool UpdatePerspective(); private: // Internal screen corresponding to the state when navigation began with StartDrag or StartScale. diff --git a/drape_frontend/screen_operations.cpp b/drape_frontend/screen_operations.cpp index 5060097425..acc083dedc 100644 --- a/drape_frontend/screen_operations.cpp +++ b/drape_frontend/screen_operations.cpp @@ -272,16 +272,4 @@ bool ApplyScale(m2::PointD const & pixelScaleCenter, double factor, ScreenBase & return true; } -double CalculatePerspectiveAngle(ScreenBase const & screen) -{ - double const kStartPerspectiveScale = 0.5; - double const kMaxScale = 0.2; - double const kMaxPerspectiveAngle = math::pi4; - - double const currentScale = screen.GetScale(); - if (currentScale > kStartPerspectiveScale) - return 0.0; - return kMaxPerspectiveAngle * (kStartPerspectiveScale - currentScale) / (kStartPerspectiveScale - kMaxScale); -} - } // namespace df diff --git a/drape_frontend/screen_operations.hpp b/drape_frontend/screen_operations.hpp index e9239180e5..dd34bdad7e 100644 --- a/drape_frontend/screen_operations.hpp +++ b/drape_frontend/screen_operations.hpp @@ -28,6 +28,4 @@ m2::PointD CalculateCenter(double scale, m2::RectD const & pixelRect, bool ApplyScale(m2::PointD const & pixelScaleCenter, double factor, ScreenBase & screen); -double CalculatePerspectiveAngle(ScreenBase const & screen); - } // namespace df diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index d5d7e10092..0f7c91dbbd 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -147,6 +147,8 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool swap(m_events, events); } + m2::RectD const prevPixelRect = GetCurrentScreen().PixelRect(); + m_modelViewChanged = !events.empty() || m_state == STATE_SCALE || m_state == STATE_DRAG; for (UserEvent const & e : events) { @@ -163,7 +165,6 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool break; case UserEvent::EVENT_RESIZE: m_navigator.OnSize(e.m_resize.m_width, e.m_resize.m_height); - m_viewportChanged = true; breakAnim = true; TouchCancel(m_touches); if (m_state == STATE_DOUBLE_TAP_HOLD) @@ -268,12 +269,13 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool } if (m_modelViewChanged) - m_viewportChanged |= m_navigator.UpdatePerspective(); + m_animationSystem.UpdateLastScreen(GetCurrentScreen()); modelViewChanged = m_modelViewChanged; - viewportChanged = m_viewportChanged; + + double const kEps = 1e-5; + viewportChanged = !m2::IsEqualSize(prevPixelRect, GetCurrentScreen().PixelRect(), kEps, kEps); m_modelViewChanged = false; - m_viewportChanged = false; return m_navigator.Screen(); } @@ -282,9 +284,9 @@ void UserEventStream::ApplyAnimations() { if (m_animationSystem.AnimationExists(Animation::MapPlane)) { - m2::AnyRectD rect; - if (m_animationSystem.GetRect(GetCurrentScreen(), rect)) - m_navigator.SetFromRect(rect); + ScreenBase screen; + if (m_animationSystem.GetScreen(GetCurrentScreen(), screen)) + m_navigator.SetScreen(screen); Animation::SwitchPerspectiveParams switchPerspective; if (m_animationSystem.SwitchPerspective(switchPerspective)) @@ -298,7 +300,6 @@ void UserEventStream::ApplyAnimations() { m_navigator.Disable3dMode(); } - m_viewportChanged = true; } double perspectiveAngle; @@ -434,15 +435,15 @@ bool UserEventStream::SetCenter(m2::PointD const & center, int zoom, bool isAnim bool UserEventStream::SetRect(m2::RectD rect, int zoom, bool applyRotation, bool isAnim) { - ScreenBase const & screen = GetCurrentScreen(); - CheckMinGlobalRect(rect, screen.GetScale3d()); - CheckMinMaxVisibleScale(rect, zoom, screen.GetScale3d()); + CheckMinGlobalRect(rect, kDefault3dScale); + CheckMinMaxVisibleScale(rect, zoom, kDefault3dScale); m2::AnyRectD targetRect = applyRotation ? ToRotated(m_navigator, rect) : m2::AnyRectD(rect); return SetRect(targetRect, isAnim); } bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) { + isAnim = false; if (isAnim) { auto onStartHandler = [this](ref_ptr animation) @@ -473,7 +474,7 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) } ResetMapPlaneAnimations(); - m_navigator.SetFromRect(rect); + m_navigator.SetFromRect2(rect); return true; } @@ -581,10 +582,9 @@ bool UserEventStream::FilterEventWhile3dAnimation(UserEvent::EEventType type) co void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, bool isAnim, bool immediatelyStart) { - ResetAnimationsBeforeSwitch3D(); + return; - //m_navigator.Enable3dMode(0.0, maxRotationAngle, angleFOV); - //return; + ResetAnimationsBeforeSwitch3D(); if (immediatelyStart) InterruptFollowAnimations(true /* force */); @@ -609,12 +609,11 @@ void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, void UserEventStream::SetDisable3dModeAnimation() { + return; + ResetAnimationsBeforeSwitch3D(); InterruptFollowAnimations(true /* force */); - //m_navigator.Disable3dMode(); - //return; - if (m_discardedFOV > 0.0 && IsScaleAllowableIn3d(GetDrawTileScale(GetCurrentScreen()))) { m_discardedFOV = m_discardedAngle = 0.0; @@ -676,9 +675,9 @@ m2::AnyRectD UserEventStream::GetCurrentRect() const m2::AnyRectD UserEventStream::GetTargetRect() const { - m2::AnyRectD targetRect; - m_animationSystem.GetTargetRect(m_navigator.Screen(), targetRect); - return targetRect; + ScreenBase targetScreen; + m_animationSystem.GetTargetScreen(m_navigator.Screen(), targetScreen); + return targetScreen.GlobalRect(); } bool UserEventStream::ProcessTouch(TouchEvent const & touch) @@ -1232,7 +1231,7 @@ void UserEventStream::UpdateDoubleTapAndHold(Touch const & touch) TEST_CALL(DOUBLE_TAP_AND_HOLD); ASSERT_EQUAL(m_state, STATE_DOUBLE_TAP_HOLD, ()); float const kPowerModifier = 10.0f; - float const scaleFactor = exp(kPowerModifier * (touch.m_location.y - m_startDoubleTapAndHold.y) / GetCurrentScreen().PixelRect().SizeY()); + float const scaleFactor = exp(kPowerModifier * (touch.m_location.y - m_startDoubleTapAndHold.y) / GetCurrentScreen().PixelRectIn3d().SizeY()); m_startDoubleTapAndHold = touch.m_location; m2::PointD scaleCenter = m_startDragOrg; diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index ebb5cab618..28d926f428 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -383,7 +383,6 @@ private: AnimationSystem & m_animationSystem; bool m_modelViewChanged = false; - bool m_viewportChanged = false; bool m_perspectiveAnimation = false; unique_ptr m_pendingEvent; diff --git a/geometry/rect2d.hpp b/geometry/rect2d.hpp index d49fa049d0..57f7b676b3 100644 --- a/geometry/rect2d.hpp +++ b/geometry/rect2d.hpp @@ -287,6 +287,12 @@ namespace m2 return true; } + template + inline bool IsEqualSize(Rect const & r1, Rect const & r2, double epsX, double epsY) + { + return fabs(r1.SizeX() - r2.SizeX()) < epsX && fabs(r1.SizeY() - r2.SizeY()) < epsY; + } + template inline m2::Rect const Add(m2::Rect const & r, m2::Point const & p) { diff --git a/geometry/screenbase.cpp b/geometry/screenbase.cpp index 7dc94b4efd..fb462fe11c 100644 --- a/geometry/screenbase.cpp +++ b/geometry/screenbase.cpp @@ -16,18 +16,19 @@ double constexpr kEndPerspectiveScale1 = 0.3e-5; double constexpr kEndPerspectiveScale2 = 0.13e-5; ScreenBase::ScreenBase() : - m_PixelRect(0, 0, 640, 480), + m_ViewportRect(0, 0, 640, 480), + m_PixelRect(m_ViewportRect), m_Scale(0.1), m_Angle(0.0), m_Org(320, 240), - m_3dFOV(0.0), + m_3dFOV(kPerspectiveAngleFOV), m_3dNearZ(0.001), m_3dFarZ(0.0), m_3dAngleX(0.0), m_3dMaxAngleX(0.0), - m_3dScaleX(1.0), - m_3dScaleY(1.0), + m_3dScale(1.0), m_isPerspective(false), + m_isAutoPerspective(true), m_GlobalRect(m_Org, ang::AngleD(0), m2::RectD(-320, -240, 320, 240)), m_ClipRect(m2::RectD(0, 0, 640, 480)) { @@ -43,7 +44,7 @@ ScreenBase::ScreenBase(m2::RectI const & pxRect, m2::AnyRectD const & glbRect) ScreenBase::ScreenBase(ScreenBase const & s, m2::PointD const & org, double scale, double angle) - : m_PixelRect(s.m_PixelRect), + : m_ViewportRect(s.m_ViewportRect), m_Scale(scale), m_Angle(angle), m_Org(org) { UpdateDependentParameters(); @@ -51,6 +52,8 @@ ScreenBase::ScreenBase(ScreenBase const & s, void ScreenBase::UpdateDependentParameters() { + m_PixelRect = CalculatePixelRect(m_Scale); + m_PtoG = math::Shift( /// 5. shifting on (E0, N0) math::Rotate( /// 4. rotating on the screen angle math::Scale( /// 3. scaling to translate pixel sizes to global @@ -79,38 +82,46 @@ void ScreenBase::UpdateDependentParameters() m_GlobalRect = m2::AnyRectD(m_Org, m_Angle, m2::RectD(-szX, -szY, szX, szY)); m_ClipRect = m_GlobalRect.GetGlobalRect(); + + double const kEps = 1e-5; + double angle = CalculatePerspectiveAngle(m_Scale); + m_isPerspective = angle > 0.0; + if (fabs(angle - m_3dAngleX) > kEps) + { + m_3dMaxAngleX = angle; + m_3dScale = CalculateScale3d(angle); + SetRotationAngle(angle); + } } -double ScreenBase::CalculatePerspectiveAngle(double scale) +double ScreenBase::CalculatePerspectiveAngle(double scale) const { + if (!m_isAutoPerspective) + return m_3dAngleX; + if (scale > kStartPerspectiveScale1) return 0.0; - else if (scale > kEndPerspectiveScale1) + + if (scale > kEndPerspectiveScale1) { double const k = (kStartPerspectiveScale1 - scale) / (kStartPerspectiveScale1 - kEndPerspectiveScale1); return kMaxPerspectiveAngle1 * k; } - else if (scale > kEndPerspectiveScale2) + + if (scale > kEndPerspectiveScale2) { double const k = (kEndPerspectiveScale1 - scale) / (kEndPerspectiveScale1 - kEndPerspectiveScale2); return kMaxPerspectiveAngle1 + (kMaxPerspectiveAngle2 - kMaxPerspectiveAngle1) * k; } - else - return kMaxPerspectiveAngle2 * 0.99; + + return kMaxPerspectiveAngle2 * 0.99; } void ScreenBase::UpdatePerspectiveParameters() { double const angle = CalculatePerspectiveAngle(m_Scale); if (angle > 0.0) - { - if (!m_isPerspective || (angle < kMaxPerspectiveAngle1 && m_3dMaxAngleX > kMaxPerspectiveAngle1)) - ApplyPerspective(angle, kMaxPerspectiveAngle1, kPerspectiveAngleFOV); - else if (angle > m_3dMaxAngleX) - ApplyPerspective(angle, kMaxPerspectiveAngle2, kPerspectiveAngleFOV); - else - SetRotationAngle(angle); - } + ApplyPerspective(angle, angle, kPerspectiveAngleFOV); else if (m_isPerspective) ResetPerspective(); } @@ -132,6 +143,48 @@ void ScreenBase::SetFromRect(m2::AnyRectD const & glbRect) SetFromRects(glbRect, m_PixelRect); } +void ScreenBase::SetFromRect2d(m2::AnyRectD const & glbRect) +{ + double hScale = glbRect.GetLocalRect().SizeX() / PixelRectIn3d().SizeX(); + double vScale = glbRect.GetLocalRect().SizeY() / PixelRectIn3d().SizeY(); + double scale = max(hScale, vScale); + + m_Scale = scale; + m_Angle = glbRect.Angle(); + m_Org = glbRect.GlobalCenter(); + + UpdateDependentParameters(); + UpdatePerspectiveParameters(); + +/* m2::PointD g_target(0.0, -glbRect.GetLocalRect().SizeY() * scale / vScale / 2.0); + g_target.Rotate(glbRect.Angle().val()); + g_target = glbRect.GlobalCenter() + g_target; + m2::PointD p_target(m_PixelRect.SizeX() / 2.0, m_PixelRect.SizeY()); + MatchGandP(g_target, p_target);*/ + + MatchGandP3d(glbRect.GlobalCenter(), PixelRectIn3d().Center()); +} + +void ScreenBase::SetFromParams(m2::PointD const & org, double angle, double scale) +{ + m_Scale = scale; + m_Angle = angle; + m_Org = org; + UpdateDependentParameters(); +} + +void ScreenBase::MatchGandP(m2::PointD const & g, m2::PointD const & p) +{ + m2::PointD g_current = PtoG(p); + SetOrg(m_Org - g_current + g); +} + +void ScreenBase::MatchGandP3d(m2::PointD const & g, m2::PointD const &p3d) +{ + m2::PointD g_current = PtoG(P3dtoP(p3d)); + SetOrg(m_Org - g_current + g); +} + void ScreenBase::SetOrg(m2::PointD const & p) { m_Org = p; @@ -164,7 +217,7 @@ void ScreenBase::Rotate(double angle) void ScreenBase::OnSize(m2::RectI const & r) { - m_PixelRect = m2::RectD(r); + m_ViewportRect = m2::RectD(r); UpdateDependentParameters(); } @@ -173,11 +226,6 @@ void ScreenBase::OnSize(int x0, int y0, int w, int h) OnSize(m2::RectI(x0, y0, x0 + w, y0 + h)); } -double ScreenBase::GetMinPixelRectSize() const -{ - return min(m_PixelRect.SizeX(), m_PixelRect.SizeY()); -} - void ScreenBase::SetScale(double scale) { m_Scale = scale; @@ -294,6 +342,32 @@ void ScreenBase::ExtractGtoPParams(MatrixT const & m, dy = m(2, 1); } +double ScreenBase::CalculateScale3d(double rotationAngle) const +{ + double const halfFOV = m_3dFOV / 2.0; + double const cameraZ = 1.0 / tan(halfFOV); + + // Ratio of the expanded plane's size to the original size. + double const y3dScale = cos(rotationAngle) + sin(rotationAngle) * tan(halfFOV + rotationAngle); + double const x3dScale = 1.0 + 2 * sin(rotationAngle) * cos(halfFOV) / (cameraZ * cos(halfFOV + rotationAngle)); + + return max(x3dScale, y3dScale); +} + +m2::RectD ScreenBase::CalculatePixelRect(double scale) const +{ + double const angle = CalculatePerspectiveAngle(scale); + if (angle > 0.0) + { + double const scale3d = CalculateScale3d(angle); + + return m2::RectD(m2::PointD(0.0, 0.0), + m2::PointD(m_ViewportRect.maxX(), m_ViewportRect.maxY()) * scale3d); + } + + return m_ViewportRect; +} + // Place the camera at the distance, where it gives the same view of plane as the // orthogonal projection does. Calculate what part of the map would be visible, // when it is rotated through maxRotationAngle around its near horizontal side. @@ -304,31 +378,21 @@ void ScreenBase::ApplyPerspective(double currentRotationAngle, double maxRotatio ASSERT_GREATER_OR_EQUAL(maxRotationAngle, 0.0, ()); ASSERT_LESS(maxRotationAngle, math::pi2, ()); - if (m_isPerspective) - ResetPerspective(); +// if (m_isPerspective) +// ResetPerspective(); m_isPerspective = true; m_3dMaxAngleX = maxRotationAngle; m_3dFOV = angleFOV; - double const halfFOV = m_3dFOV / 2.0; - double const cameraZ = 1.0 / tan(halfFOV); - - // Ratio of the expanded plane's size to the original size. - m_3dScaleY = cos(m_3dMaxAngleX) + sin(m_3dMaxAngleX) * tan(halfFOV + m_3dMaxAngleX); - m_3dScaleX = 1.0 + 2 * sin(m_3dMaxAngleX) * cos(halfFOV) / (cameraZ * cos(halfFOV + m_3dMaxAngleX)); - - m_3dScaleX = m_3dScaleY = max(m_3dScaleX, m_3dScaleY); - - double const dy = m_PixelRect.SizeY() * (m_3dScaleX - 1.0); - - m_PixelRect.setMaxX(m_PixelRect.maxX() * m_3dScaleX); - m_PixelRect.setMaxY(m_PixelRect.maxY() * m_3dScaleY); - - Move(0.0, dy / 2.0); + double const old_dy = m_ViewportRect.SizeY() * (m_3dScale - 1.0); + m_3dScale = CalculateScale3d(m_3dMaxAngleX); + double const new_dy = m_ViewportRect.SizeY() * (CalculateScale3d(m_3dMaxAngleX) - 1.0); SetRotationAngle(currentRotationAngle); + + Move(0.0, (new_dy - old_dy) / 2.0); } // Place the camera at the distance, where it gives the same view of plane as the @@ -347,12 +411,12 @@ void ScreenBase::SetRotationAngle(double rotationAngle) double const halfFOV = m_3dFOV / 2.0; double const cameraZ = 1.0 / tan(halfFOV); - double const offsetZ = cameraZ + sin(m_3dAngleX) * m_3dScaleY; - double const offsetY = cos(m_3dAngleX) * m_3dScaleX - 1.0; + double const offsetZ = cameraZ + sin(m_3dAngleX) * m_3dScale; + double const offsetY = cos(m_3dAngleX) * m_3dScale - 1.0; Matrix3dT scaleM = math::Identity(); - scaleM(0, 0) = m_3dScaleX; - scaleM(1, 1) = m_3dScaleY; + scaleM(0, 0) = m_3dScale; + scaleM(1, 1) = m_3dScale; Matrix3dT rotateM = math::Identity(); rotateM(1, 1) = cos(m_3dAngleX); @@ -365,7 +429,7 @@ void ScreenBase::SetRotationAngle(double rotationAngle) translateM(3, 2) = offsetZ; Matrix3dT projectionM = math::Zero(); - m_3dFarZ = cameraZ + 2.0 * sin(m_3dAngleX) * m_3dScaleY; + m_3dFarZ = cameraZ + 2.0 * sin(m_3dAngleX) * m_3dScale; projectionM(0, 0) = projectionM(1, 1) = cameraZ; projectionM(2, 2) = m_3dAngleX != 0.0 ? (m_3dFarZ + m_3dNearZ) / (m_3dFarZ - m_3dNearZ) : 0.0; @@ -381,14 +445,14 @@ void ScreenBase::ResetPerspective() { m_isPerspective = false; - double const dy = m_PixelRect.SizeY() * (1.0 - 1.0 / m_3dScaleX); + double const dy = m_PixelRect.SizeY() * (1.0 - 1.0 / m_3dScale); - m_PixelRect.setMaxX(m_PixelRect.maxX() / m_3dScaleX); - m_PixelRect.setMaxY(m_PixelRect.maxY() / m_3dScaleY); + m_PixelRect.setMaxX(m_PixelRect.maxX() / m_3dScale); + m_PixelRect.setMaxY(m_PixelRect.maxY() / m_3dScale); Move(0, -dy / 2.0); - m_3dScaleX = m_3dScaleY = 1.0; + m_3dScale = 1.0; m_3dAngleX = 0.0; m_3dMaxAngleX = 0.0; m_3dFOV = 0.0; diff --git a/geometry/screenbase.hpp b/geometry/screenbase.hpp index 8f99f76dbd..c3cf5eefe2 100644 --- a/geometry/screenbase.hpp +++ b/geometry/screenbase.hpp @@ -15,6 +15,7 @@ public: using Vector3dT = math::Matrix; private: + m2::RectD m_ViewportRect; m2::RectD m_PixelRect; double m_Scale; @@ -26,9 +27,9 @@ private: double m_3dFarZ; double m_3dAngleX; double m_3dMaxAngleX; - double m_3dScaleX; - double m_3dScaleY; + double m_3dScale; bool m_isPerspective; + bool m_isAutoPerspective; protected: /// @group Dependent parameters @@ -64,6 +65,9 @@ public: m2::PointD const & org, double scale, double angle); void SetFromRect(m2::AnyRectD const & rect); + void SetFromRect2d(m2::AnyRectD const & glbRect); + + void SetFromParams(m2::PointD const & org, double angle, double scale); void SetFromRects(m2::AnyRectD const & glbRect, m2::RectD const & pxRect); void SetOrg(m2::PointD const & p); @@ -115,6 +119,9 @@ public: void GtoP(m2::RectD const & gr, m2::RectD & sr) const; void PtoG(m2::RectD const & pr, m2::RectD & gr) const; + void MatchGandP(m2::PointD const & g, m2::PointD const & p); + void MatchGandP3d(m2::PointD const & g, m2::PointD const & p3d); + void GetTouchRect(m2::PointD const & pixPoint, double pixRadius, m2::AnyRectD & glbRect) const; void GetTouchRect(m2::PointD const & pixPoint, double const pxWidth, double const pxHeight, m2::AnyRectD & glbRect) const; @@ -134,7 +141,7 @@ public: double GetRotationAngle() const { return m_3dAngleX; } double GetMaxRotationAngle() const { return m_3dMaxAngleX; } double GetAngleFOV() const { return m_3dFOV; } - double GetScale3d() const { return m_3dScaleX; } + double GetScale3d() const { return m_3dScale; } m2::PointD P3dtoP(m2::PointD const & pt) const; @@ -148,17 +155,18 @@ public: m2::RectD PixelRectIn3d() const { - return m2::RectD(0.0, 0.0, m_PixelRect.maxX() / m_3dScaleX, m_PixelRect.maxY() / m_3dScaleY); + return m_ViewportRect; } - double GetMinPixelRectSize() const; + double CalculateScale3d(double rotationAngle) const; + m2::RectD CalculatePixelRect(double scale) const; + double CalculatePerspectiveAngle(double scale) const; /// Compute arbitrary pixel transformation, that translates the (oldPt1, oldPt2) -> (newPt1, newPt2) static MatrixT const CalcTransform(m2::PointD const & oldPt1, m2::PointD const & oldPt2, m2::PointD const & newPt1, m2::PointD const & newPt2, bool allowRotate); - static double CalculatePerspectiveAngle(double scale); /// Setting GtoP matrix extracts the Angle and m_Org parameters, leaving PixelRect intact void SetGtoPMatrix(MatrixT const & m);