diff options
author | rachytski <siarhei.rachytski@gmail.com> | 2011-10-03 14:31:37 +0400 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 01:25:21 +0300 |
commit | fd3a3a6d0fc3aeab9e7b0c4724d614dc587cb0ee (patch) | |
tree | 0c872119ff85927af83ec5919beea786832ba961 /geometry | |
parent | 31279661079d1426c2dac1971fb5bce6d086be32 (diff) |
refactored ScreenBase to support GUI rotation.
Diffstat (limited to 'geometry')
-rw-r--r-- | geometry/aa_rect2d.hpp | 31 | ||||
-rw-r--r-- | geometry/geometry_tests/screen_test.cpp | 14 | ||||
-rw-r--r-- | geometry/screenbase.cpp | 143 | ||||
-rw-r--r-- | geometry/screenbase.hpp | 106 | ||||
-rw-r--r-- | geometry/transformations.hpp | 9 |
5 files changed, 177 insertions, 126 deletions
diff --git a/geometry/aa_rect2d.hpp b/geometry/aa_rect2d.hpp index 53499ec001..e62a9829bd 100644 --- a/geometry/aa_rect2d.hpp +++ b/geometry/aa_rect2d.hpp @@ -15,6 +15,7 @@ namespace m2 { private: + ang::Angle<T> m_angle; Point<T> m_i; Point<T> m_j; Point<T> m_zero; @@ -39,25 +40,32 @@ namespace m2 AARect() : m_i(1, 0), m_j(0, 1), m_zero(0, 0), m_rect(){} /// creating from regular rect - AARect(Rect<T> const & r) - : m_i(1, 0), m_j(0, 1), + explicit AARect(Rect<T> const & r) + : m_angle(0), m_i(m_angle.cos(), m_angle.sin()), m_j(-m_angle.sin(), m_angle.cos()), m_zero(r == Rect<T>() ? Point<T>(0, 0) : Point<T>(r.minX(), r.minY())), m_rect(r == Rect<T>() ? Rect<T>() : Rect<T>(0, 0, r.SizeX(), r.SizeY())) { } AARect(Point<T> const & zero, ang::Angle<T> const & angle, Rect<T> const & r) - : m_i(angle.cos(), angle.sin()), m_j(-angle.sin(), angle.cos()), + : m_angle(angle), m_i(m_angle.cos(), m_angle.sin()), m_j(-m_angle.sin(), m_angle.cos()), m_zero(Convert(zero, Point<T>(1, 0), Point<T>(0, 1), m_i, m_j)), m_rect(r) { } - Point<T> const & zero() const + Point<T> const & LocalZero() const { return m_zero; } + Point<T> const GlobalZero() const + { + m2::PointD i(1, 0); + m2::PointD j(0, 1); + return Convert(m_zero, m_i, m_j, i, j); + } + Point<T> const & i() const { return m_i; @@ -68,6 +76,21 @@ namespace m2 return m_j; } + ang::Angle<T> const & angle() const + { + return m_angle; + } + + Point<T> const GlobalCenter() const + { + return ConvertFrom(m_rect.Center()); + } + + Point<T> const LocalCenter() const + { + return m_rect.Center(); + } + bool IsPointInside(Point<T> const & pt) const { return m_rect.IsPointInside(ConvertTo(pt)); diff --git a/geometry/geometry_tests/screen_test.cpp b/geometry/geometry_tests/screen_test.cpp index b13520bffe..d2bdd9610a 100644 --- a/geometry/geometry_tests/screen_test.cpp +++ b/geometry/geometry_tests/screen_test.cpp @@ -16,7 +16,7 @@ namespace m2::PointD b1(0.0, 0.0); m2::PointD b2(300.0, 300.0); - screen.SetFromRect(m2::RectD(b1, b2)); + screen.SetFromRect(m2::AARectD(m2::RectD(b1, b2))); b1 = screen.GtoP(b1); b2 = screen.GtoP(b2); @@ -37,7 +37,7 @@ UNIT_TEST(ScreenBase_P2G2P) check_set_from_rect(screen, 500, 1000); screen.OnSize(0, 0, 640, 480); - screen.SetFromRect(m2::RectD(-100, -200, 500, 680)); + screen.SetFromRect(m2::AARectD(m2::RectD(-100, -200, 500, 680))); /// checking that PtoG(GtoP(p)) == p @@ -55,7 +55,7 @@ UNIT_TEST(ScreenBase_AxisOrientation) ScreenBase screen; screen.OnSize(0, 0, 300, 200); - screen.SetFromRect(m2::RectD(0, 0, 300, 200)); + screen.SetFromRect(m2::AARectD(m2::RectD(0, 0, 300, 200))); TEST(is_equal(m2::PointD(150, 100), screen.GtoP(m2::PointD(150, 100))), ()); TEST(is_equal(m2::PointD(0, 0), screen.GtoP(m2::PointD(0, 200))), ()); @@ -68,7 +68,7 @@ UNIT_TEST(ScreenBase_X0Y0) { ScreenBase screen; screen.OnSize(10, 10, 300, 200); - screen.SetFromRect(m2::RectD(0, 0, 300, 200)); + screen.SetFromRect(m2::AARectD(m2::RectD(0, 0, 300, 200))); m2::PointD pxPt = screen.PtoG(m2::PointD(0, 0)); @@ -79,7 +79,7 @@ UNIT_TEST(ScreenBase_ChoosingMaxScale) { ScreenBase screen; screen.OnSize(10, 10, 300, 200); - screen.SetFromRect(m2::RectD(0, 0, 200, 400)); + screen.SetFromRect(m2::AARectD(m2::RectD(0, 0, 200, 400))); TEST(is_equal(screen.GtoP(m2::PointD(100, 200)), m2::PointD(160, 110)), ()); TEST(is_equal(screen.GtoP(m2::PointD(0, 0)), m2::PointD(110, 210)), ()); @@ -124,11 +124,11 @@ UNIT_TEST(ScreenBase_Rotate) { ScreenBase s; s.OnSize(0, 0, 100, 200); - s.SetFromRect(m2::RectD(0, 0, 100, 200)); + s.SetFromRect(m2::AARectD(m2::RectD(0, 0, 100, 200))); s.Rotate(math::pi / 4); m2::RectD pxRect = s.PixelRect(); - m2::RectD glbRect = s.GlobalRect(); + m2::AARectD glbRect = s.GlobalRect(); TEST(pxRect == m2::RectD(0, 0, 100, 200), ()); } diff --git a/geometry/screenbase.cpp b/geometry/screenbase.cpp index acabce0e17..bdbaa65c44 100644 --- a/geometry/screenbase.cpp +++ b/geometry/screenbase.cpp @@ -10,16 +10,17 @@ ScreenBase::ScreenBase() : m_PixelRect(0, 0, 640, 480), - m_GlobalRect(0, 0, 640, 480), m_Scale(1), - m_Angle(0.0) + m_Angle(0.0), + m_Org(320, 240), + m_GlobalRect(m2::RectD(0, 0, 640, 480)) { m_GtoP = math::Identity<double, 3>(); m_PtoG = math::Identity<double, 3>(); // UpdateDependentParameters(); } -ScreenBase::ScreenBase(m2::RectI const & pxRect, m2::RectD const & glbRect) +ScreenBase::ScreenBase(m2::RectI const & pxRect, m2::AARectD const & glbRect) { OnSize(pxRect); SetFromRect(glbRect); @@ -41,71 +42,119 @@ void ScreenBase::UpdateDependentParameters() m_Scale, m_Scale ), - GetAngle() + m_Angle.cos(), + m_Angle.sin() ), - m_GlobalRect.Center() + m_Org ); m_GtoP = math::Inverse(m_PtoG); - PtoG(m_PixelRect, m_ClipRect); - PtoG(m_PixelRect, m_GlobalRect); + double HalfSizeX = PtoG(m2::PointD(m_PixelRect.maxX(), m_PixelRect.Center().y)).Length(PtoG(m2::PointD(m_PixelRect.Center()))); + double HalfSizeY = PtoG(m2::PointD(m_PixelRect.Center().x, m_PixelRect.minY())).Length(PtoG(m2::PointD(m_PixelRect.Center()))); + + m_GlobalRect = m2::AARectD(m_Org, m_Angle, m2::RectD(-HalfSizeX, -HalfSizeY, HalfSizeX, HalfSizeY)); + m_ClipRect = m_GlobalRect.GetGlobalRect(); } -void ScreenBase::SetFromRect(m2::RectD const & GlobalRect) +void ScreenBase::SetFromRect(m2::AARectD const & GlobalRect) { - double hScale = GlobalRect.SizeX() / m_PixelRect.SizeX(); - double vScale = GlobalRect.SizeY() / m_PixelRect.SizeY(); + double hScale = GlobalRect.GetLocalRect().SizeX() / m_PixelRect.SizeX(); + double vScale = GlobalRect.GetLocalRect().SizeY() / m_PixelRect.SizeY(); m_Scale = max(hScale, vScale); - m_Angle = 0; - - /// Fit the global rect into pixel rect - - m2::PointD HalfSize(m_Scale * m_PixelRect.SizeX() / 2, - m_Scale * m_PixelRect.SizeY() / 2); - - m_GlobalRect = m2::RectD( - GlobalRect.Center() - HalfSize, - GlobalRect.Center() + HalfSize - ); + m_Angle = GlobalRect.angle(); + m_Org = GlobalRect.GlobalCenter(); UpdateDependentParameters(); } void ScreenBase::SetOrg(m2::PointD const & p) { - m_GlobalRect.Offset(p - m_GlobalRect.Center()); + m_Org = p; UpdateDependentParameters(); } void ScreenBase::Move(double dx, double dy) { - m_GlobalRect.Offset(m_GlobalRect.Center() - PtoG(m_PixelRect.Center() + m2::PointD(dx, dy))); - + m_Org = PtoG(GtoP(m_Org) - m2::PointD(dx, dy)); UpdateDependentParameters(); } -void ScreenBase::MoveG(m2::PointD const & delta) +void ScreenBase::MoveG(m2::PointD const & p) { - m_GlobalRect.Offset(delta); - + m_Org -= p; UpdateDependentParameters(); } void ScreenBase::Scale(double scale) { - m_GlobalRect.Scale( 1 / scale); m_Scale /= scale; UpdateDependentParameters(); } void ScreenBase::Rotate(double angle) { - m_Angle -= angle; + m_Angle = ang::AngleD(m_Angle.val() + angle); UpdateDependentParameters(); } +void ScreenBase::OnSize(m2::RectI const & r) +{ + m_PixelRect = m2::RectD(r); + UpdateDependentParameters(); +} + +void ScreenBase::OnSize(int x0, int y0, int w, int h) +{ + OnSize(m2::RectI(x0, y0, x0 + w, y0 + h)); +} + +math::Matrix<double, 3, 3> const & ScreenBase::GtoPMatrix() const +{ + return m_GtoP; +} + +math::Matrix<double, 3, 3> const & ScreenBase::PtoGMatrix() const +{ + return m_PtoG; +} + +m2::RectD const & ScreenBase::PixelRect() const +{ + return m_PixelRect; +} + +m2::AARectD const & ScreenBase::GlobalRect() const +{ + return m_GlobalRect; +} + +m2::RectD const & ScreenBase::ClipRect() const +{ + return m_ClipRect; +} + +double ScreenBase::GetScale() const +{ + return m_Scale; +} + +double ScreenBase::GetAngle() const +{ + return m_Angle.val(); +} + +int ScreenBase::GetWidth() const +{ + return my::rounds(m_PixelRect.SizeX()); +} + +int ScreenBase::GetHeight() const +{ + return my::rounds(m_PixelRect.SizeY()); +} + math::Matrix<double, 3, 3> const ScreenBase::CalcTransform(m2::PointD const & oldPt1, m2::PointD const & oldPt2, m2::PointD const & newPt1, m2::PointD const & newPt2) { @@ -136,34 +185,38 @@ void ScreenBase::SetGtoPMatrix(math::Matrix<double, 3, 3> const & m) /// Extracting transformation params, assuming that the matrix /// somehow represent a valid screen transformation /// into m_PixelRectangle - double dx, dy; - ExtractGtoPParams(m, m_Angle, m_Scale, dx, dy); - m_Scale = 1 / m_Scale; - - m_GlobalRect = m_PixelRect; - m_GlobalRect.Scale(m_Scale); + double dx, dy, a, s; + ExtractGtoPParams(m, a, s, dx, dy); + m_Angle = ang::AngleD(-a); + m_Scale = 1 / s; + m_Org = PtoG(m_PixelRect.Center()); - m_GlobalRect.Offset(m_PixelRect.Center() * m_PtoG - m_GlobalRect.Center()); + UpdateDependentParameters(); } -void ScreenBase::GtoP(m2::RectD const & gr, m2::RectD & sr) const +void ScreenBase::GtoP(m2::RectD const & glbRect, m2::RectD & pxRect) const { - sr = m2::RectD(GtoP(gr.LeftTop()), GtoP(gr.RightBottom())); + pxRect = m2::RectD(GtoP(glbRect.LeftTop()), GtoP(glbRect.RightBottom())); } -void ScreenBase::PtoG(m2::RectD const & sr, m2::RectD & gr) const +void ScreenBase::PtoG(m2::RectD const & pxRect, m2::RectD & glbRect) const { - gr = m2::RectD(PtoG(sr.LeftTop()), PtoG(sr.RightBottom())); + glbRect = m2::RectD(PtoG(pxRect.LeftTop()), PtoG(pxRect.RightBottom())); } -bool IsPanning(ScreenBase const & s1, ScreenBase const & s2) +bool IsPanningAndRotate(ScreenBase const & s1, ScreenBase const & s2) { - m2::PointD globPt(s1.GlobalRect().Center().x - s1.GlobalRect().minX(), - s1.GlobalRect().Center().y - s1.GlobalRect().minY()); + m2::RectD r1 = s1.GlobalRect().GetLocalRect(); + m2::RectD r2 = s2.GlobalRect().GetLocalRect(); + + m2::PointD c1 = r1.Center(); + m2::PointD c2 = r2.Center(); - m2::PointD p1 = s1.GtoP(s1.GlobalRect().Center()) - s1.GtoP(s1.GlobalRect().Center() + globPt); + m2::PointD globPt(c1.x - r1.minX(), + c1.y - r1.minY()); - m2::PointD p2 = s2.GtoP(s2.GlobalRect().Center()) - s2.GtoP(s2.GlobalRect().Center() + globPt); + m2::PointD p1 = s1.GtoP(s1.GlobalRect().ConvertFrom(c1)) - s1.GtoP(s1.GlobalRect().ConvertFrom(c1 + globPt)); + m2::PointD p2 = s2.GtoP(s2.GlobalRect().ConvertFrom(c2)) - s2.GtoP(s2.GlobalRect().ConvertFrom(c2 + globPt)); return p1.EqualDxDy(p2, 0.00001); } diff --git a/geometry/screenbase.hpp b/geometry/screenbase.hpp index 1aee190597..a50ce0deb7 100644 --- a/geometry/screenbase.hpp +++ b/geometry/screenbase.hpp @@ -2,6 +2,7 @@ #include "point2d.hpp" #include "rect2d.hpp" +#include "aa_rect2d.hpp" #include "../base/math.hpp" @@ -18,9 +19,10 @@ enum EOrientation class ScreenBase { m2::RectD m_PixelRect; - m2::RectD m_GlobalRect; + double m_Scale; - double m_Angle; + ang::AngleD m_Angle; + m2::PointD m_Org; protected: @@ -32,9 +34,12 @@ protected: /// @{ math::Matrix<double, 3, 3> m_GtoP; - /// Pixel to Global conversion matrix. GtoP inverted + /// Pixel to Global conversion matrix. Inverted GtoP matrix. math::Matrix<double, 3, 3> m_PtoG; + /// Global Rect + m2::AARectD m_GlobalRect; + /// X-axis aligned global rect used for clipping m2::RectD m_ClipRect; @@ -47,57 +52,35 @@ protected: public: ScreenBase(); - ScreenBase(m2::RectI const & pxRect, m2::RectD const & glbRect); + ScreenBase(m2::RectI const & pxRect, m2::AARectD const & glbRect); - void SetFromRect(m2::RectD const & rect); + void SetFromRect(m2::AARectD const & rect); void SetOrg(m2::PointD const & p); void Move(double dx, double dy); - void MoveG(m2::PointD const & delta); + void MoveG(m2::PointD const & p); + void Scale(double scale); void Rotate(double angle); - void ReverseTransformInPixelCoords(double s, double a, double dx, double dy); - - void OnSize(m2::RectI const & r) - { - m_PixelRect = m2::RectD(r); - UpdateDependentParameters(); - } - void OnSize(int x0, int y0, int w, int h) - { - m_PixelRect = m2::RectD(x0, y0, x0 + w, y0 + h); - UpdateDependentParameters(); - } + void OnSize(m2::RectI const & r); + void OnSize(int x0, int y0, int w, int h); public: - inline double GetScale() const { return m_Scale; }; - - inline double GetAngle() const - { - return m_Angle; - } - - inline int GetWidth() const - { - return my::rounds(m_PixelRect.SizeX()); - } - - inline int GetHeight() const - { - return my::rounds(m_PixelRect.SizeY()); - } + double GetScale() const; + double GetAngle() const; + int GetWidth() const; + int GetHeight() const; - /// @warning ClipRect() returns a PtoG(m_PixelRect) rect. - inline m2::RectD const & ClipRect() const + inline m2::PointD GtoP(m2::PointD const & pt) const { - return m_ClipRect; + return pt * m_GtoP; } - inline m2::PointD GtoP(m2::PointD const & pt) const + inline m2::PointD PtoG(m2::PointD const & pt) const { - return pt * m_GtoP; + return pt * m_PtoG; } inline void GtoP(double & x, double & y) const @@ -107,51 +90,33 @@ public: y = tempX * m_GtoP(1, 0) + y * m_GtoP(1, 1) + m_GtoP(2, 1); } - void GtoP(m2::RectD const & gr, m2::RectD & sr) const; - void PtoG(m2::RectD const & sr, m2::RectD & gr) const; - - math::Matrix<double, 3, 3> const GtoPMatrix() const + inline void PtoG(double & x, double & y) const { - return m_GtoP; + double tempX = x; + x = tempX * m_PtoG(0, 0) + y * m_PtoG(1, 0) + m_PtoG(2, 0); + y = tempX * m_PtoG(0, 1) + y * m_PtoG(1, 1) + m_PtoG(2, 1); } - math::Matrix<double, 3, 3> const PtoGMatrix() const - { - return m_PtoG; - } + void GtoP(m2::RectD const & gr, m2::RectD & sr) const; + void PtoG(m2::RectD const & pr, m2::RectD & gr) const; - m2::RectD const & PixelRect() const - { - return m_PixelRect; - } + math::Matrix<double, 3, 3> const & GtoPMatrix() const; + math::Matrix<double, 3, 3> const & PtoGMatrix() const; - m2::RectD const & GlobalRect() const - { - return m_GlobalRect; - } + m2::RectD const & PixelRect() const; + m2::AARectD const & GlobalRect() const; + m2::RectD const & ClipRect() const; /// Compute arbitrary pixel transformation, that translates the (oldPt1, oldPt2) -> (newPt1, newPt2) static math::Matrix<double, 3, 3> const CalcTransform(m2::PointD const & oldPt1, m2::PointD const & oldPt2, m2::PointD const & newPt1, m2::PointD const & newPt2); - /// Setting GtoP matrix extracts the Angle and GlobalRect, leaving PixelRect intact + /// Setting GtoP matrix extracts the Angle and m_Org parameters, leaving PixelRect intact void SetGtoPMatrix(math::Matrix<double, 3, 3> const & m); /// Extracting parameters from matrix, that is supposed to represent GtoP transformation static void ExtractGtoPParams(math::Matrix<double, 3, 3> const & m, double & a, double & s, double & dx, double & dy); - inline m2::PointD PtoG(m2::PointD const & pt) const - { - return pt * m_PtoG; - } - - inline void PtoG(double & x, double & y) const - { - double tempX = x; - x = tempX * m_PtoG(0, 0) + y * m_PtoG(1, 0) + m_PtoG(2, 0); - y = tempX * m_PtoG(0, 1) + y * m_PtoG(1, 1) + m_PtoG(2, 1); - } - bool operator != (ScreenBase const & src) const { return !(*this == src); @@ -163,6 +128,7 @@ public: } }; -bool IsPanning(ScreenBase const & s1, ScreenBase const & s2); +/// checking whether the s1 transforms into s2 without scaling, only with shift and rotation +bool IsPanningAndRotate(ScreenBase const & s1, ScreenBase const & s2); #include "../base/stop_mem_debug.hpp" diff --git a/geometry/transformations.hpp b/geometry/transformations.hpp index 8ba0743da2..6b1a58fd00 100644 --- a/geometry/transformations.hpp +++ b/geometry/transformations.hpp @@ -17,6 +17,15 @@ namespace math } template <typename T, typename U> + Matrix<T, 3, 3> const Rotate(Matrix<T, 3, 3> const & m, U const & cos, U const & sin) + { + Matrix<T, 3, 3> m1 = Identity<T, 3>(); + m1(0, 0) = cos; m1(0, 1) = sin; + m1(1, 0) = -sin; m1(1, 1) = cos; + return m * m1; + } + + template <typename T, typename U> Matrix<T, 3, 3> const Shift(Matrix<T, 3, 3> const & m, U const & dx, U const & dy) { Matrix<T, 3, 3> m1 = Identity<T, 3>(); |