#pragma once #include "point2d.hpp" #include "rect2d.hpp" #include "rect_intersect.hpp" #include "angles.hpp" #include "../base/math.hpp" #include namespace m2 { /// axis aligned rect template class AnyRect { ang::Angle m_angle; /// @todo No need to store orthos separately. They are stored in m_angle. Point m_i; Point m_j; Point m_zero; Rect m_rect; static Point const Convert(Point const & p, Point const & fromI, Point const & fromJ, Point const & toI, Point const & toJ) { Point res; res.x = p.x * DotProduct(fromI, toI) + p.y * DotProduct(fromJ, toI); res.y = p.x * DotProduct(fromI, toJ) + p.y * DotProduct(fromJ, toJ); return res; } public: AnyRect() : m_i(1, 0), m_j(0, 1), m_zero(0, 0), m_rect() {} /// creating from regular rect explicit AnyRect(Rect const & r) : m_angle(0), m_i(m_angle.cos(), m_angle.sin()), m_j(-m_angle.sin(), m_angle.cos()) { if (r.IsValid()) { m_zero = Point(r.minX(), r.minY()); m_rect = Rect(0, 0, r.SizeX(), r.SizeY()); } else { m_zero = Point(0, 0); m_rect = r; } } AnyRect(Point const & zero, ang::Angle const & angle, Rect const & r) : m_angle(angle), m_i(m_angle.cos(), m_angle.sin()), m_j(-m_angle.sin(), m_angle.cos()), m_zero(Convert(zero, Point(1, 0), Point(0, 1), m_i, m_j)), m_rect(r) { } Point const & LocalZero() const { return m_zero; } Point const GlobalZero() const { m2::Point i(1, 0); m2::Point j(0, 1); return Convert(m_zero, m_i, m_j, i, j); } Point const & i() const { return m_i; } Point const & j() const { return m_j; } void SetAngle(ang::Angle const & a) { m2::Point glbZero = GlobalZero(); m_angle = a; m_i = m2::Point(m_angle.cos(), m_angle.sin()); m_j = m2::Point(-m_angle.sin(), m_angle.cos()); m_zero = Convert(glbZero, Point(1, 0), Point(0, 1), m_i, m_j); } ang::Angle const & Angle() const { return m_angle; } Point const GlobalCenter() const { return ConvertFrom(m_rect.Center()); } Point const LocalCenter() const { return m_rect.Center(); } bool IsPointInside(Point const & pt) const { return m_rect.IsPointInside(ConvertTo(pt)); } bool IsRectInside(AnyRect const & r) const { m2::Point pts[4]; r.GetGlobalPoints(pts); ConvertTo(pts, 4); return m_rect.IsPointInside(pts[0]) && m_rect.IsPointInside(pts[1]) && m_rect.IsPointInside(pts[2]) && m_rect.IsPointInside(pts[3]); } bool IsIntersect(AnyRect const & r) const { m2::Point pts[4]; if (r.GetLocalRect() == Rect()) return false; r.GetGlobalPoints(pts); ConvertTo(pts, 4); m2::Rect r1(pts[0], pts[0]); r1.Add(pts[1]); r1.Add(pts[2]); r1.Add(pts[3]); if (!GetLocalRect().IsIntersect(r1)) return false; if (r.IsRectInside(*this)) return true; if (IsRectInside(r)) return true; return Intersect(GetLocalRect(), pts[0], pts[1]) || Intersect(GetLocalRect(), pts[1], pts[2]) || Intersect(GetLocalRect(), pts[2], pts[3]) || Intersect(GetLocalRect(), pts[3], pts[0]); } /// Convert into coordinate system of this AnyRect Point const ConvertTo(Point const & p) const { m2::Point i(1, 0); m2::Point j(0, 1); return Convert(p - Convert(m_zero, m_i, m_j, i, j), i, j, m_i, m_j); } void ConvertTo(Point * pts, size_t count) const { for (size_t i = 0; i < count; ++i) pts[i] = ConvertTo(pts[i]); } /// Convert into global coordinates from the local coordinates of this AnyRect Point const ConvertFrom(Point const & p) const { m2::Point i(1, 0); m2::Point j(0, 1); return Convert(p + m_zero, m_i, m_j, i, j); } void ConvertFrom(Point * pts, size_t count) const { for (size_t i = 0; i < count; ++i) pts[i] = ConvertFrom(pts[i]); } Rect const & GetLocalRect() const { return m_rect; } Rect const GetGlobalRect() const { Point pts[4]; GetGlobalPoints(pts); Rect res(pts[0].x, pts[0].y, pts[0].x, pts[0].y); res.Add(pts[1]); res.Add(pts[2]); res.Add(pts[3]); return res; } void GetGlobalPoints(Point * pts) const { pts[0] = Point(ConvertFrom(Point(m_rect.minX(), m_rect.minY()))); pts[1] = Point(ConvertFrom(Point(m_rect.minX(), m_rect.maxY()))); pts[2] = Point(ConvertFrom(Point(m_rect.maxX(), m_rect.maxY()))); pts[3] = Point(ConvertFrom(Point(m_rect.maxX(), m_rect.minY()))); } template void Inflate(U const & dx, U const & dy) { m_rect.Inflate(dx, dy); } void Add(AnyRect const & r) { Point pts[4]; r.GetGlobalPoints(pts); ConvertTo(pts, 4); m_rect.Add(pts[0]); m_rect.Add(pts[1]); m_rect.Add(pts[2]); m_rect.Add(pts[3]); } void Offset(Point const & p) { m_zero = ConvertTo(ConvertFrom(m_zero) + p); } }; template AnyRect const Offset(AnyRect const & r, Point const & pt) { AnyRect res(r); res.Offset(pt); return res; } template AnyRect const Inflate(AnyRect const & r, U const & dx, U const & dy) { AnyRect res = r; res.Inflate(dx, dy); return res; } template AnyRect const Inflate(AnyRect const & r, Point const & pt) { return Inflate(r, pt.x, pt.y); } typedef AnyRect AnyRectD; typedef AnyRect AnyRectF; template inline string DebugPrint(m2::AnyRect const & r) { return DebugPrint(r.GetGlobalRect()); } }