#pragma once #include "base/assert.hpp" #include "base/base.hpp" #include "base/math.hpp" #include "base/matrix.hpp" #include "std/array.hpp" #include "std/cmath.hpp" #include "std/functional.hpp" #include "std/sstream.hpp" #include "std/typeinfo.hpp" namespace m2 { template class Point { public: typedef T value_type; T x, y; Point() : x(T()), y(T()) {} Point(T x_, T y_) : x(x_), y(y_) {} template Point(Point const & u) : x(u.x), y(u.y) {} static Point Zero() { return Point(0, 0); } bool EqualDxDy(Point const & p, T eps) const { return ((fabs(x - p.x) < eps) && (fabs(y - p.y) < eps)); } // TODO (@y, @m): rename to SquaredLength. T SquareLength(Point const & p) const { return math::sqr(x - p.x) + math::sqr(y - p.y); } double Length(Point const & p) const { return sqrt(SquareLength(p)); } bool IsAlmostZero() const { return AlmostEqualULPs(*this, Point(0,0)); } Point Move(T len, T ang) const { return Point(x + len * cos(ang), y + len * sin(ang)); } Point Move(T len, T angSin, T angCos) const { return m2::Point(x + len * angCos, y + len * angSin); } Point const & operator-=(Point const & a) { x -= a.x; y -= a.y; return *this; } Point const & operator+=(Point const & a) { x += a.x; y += a.y; return *this; } template Point const & operator*=(U const & k) { x = static_cast(x * k); y = static_cast(y * k); return *this; } template Point const & operator=(Point const & a) { x = static_cast(a.x); y = static_cast(a.y); return *this; } bool operator == (m2::Point const & p) const { return x == p.x && y == p.y; } bool operator != (m2::Point const & p) const { return !(*this == p); } m2::Point operator + (m2::Point const & pt) const { return m2::Point(x + pt.x, y + pt.y); } m2::Point operator - (m2::Point const & pt) const { return m2::Point(x - pt.x, y - pt.y); } m2::Point operator -() const { return m2::Point(-x, -y); } m2::Point operator * (T scale) const { return m2::Point(x * scale, y * scale); } m2::Point const operator * (math::Matrix const & m) const { m2::Point res; res.x = x * m(0, 0) + y * m(1, 0) + m(2, 0); res.y = x * m(0, 1) + y * m(1, 1) + m(2, 1); return res; } m2::Point operator / (T scale) const { return m2::Point(x / scale, y / scale); } m2::Point mid(m2::Point const & p) const { return m2::Point((x + p.x) * 0.5, (y + p.y) * 0.5); } T SquaredLength() const { return x * x + y * y; } /// @name VectorOperationsOnPoint // @{ double Length() const { return sqrt(SquaredLength()); } Point Normalize() const { ASSERT(!IsAlmostZero(), ()); double const module = this->Length(); return Point(x / module, y / module); } std::pair, Point > Normals(T prolongationFactor = 1) const { T const prolongatedX = prolongationFactor * x; T const prolongatedY = prolongationFactor * y; return std::pair, Point >(Point(static_cast(-prolongatedY), static_cast(prolongatedX)), Point(static_cast(prolongatedY), static_cast(-prolongatedX))); } // @} m2::Point const & operator *= (math::Matrix const & m) { T tempX = x; x = tempX * m(0, 0) + y * m(1, 0) + m(2, 0); y = tempX * m(0, 1) + y * m(1, 1) + m(2, 1); return *this; } void Rotate(double angle) { T cosAngle = cos(angle); T sinAngle = sin(angle); T oldX = x; x = cosAngle * oldX - sinAngle * y; y = sinAngle * oldX + cosAngle * y; } // Returns vector rotated 90 degrees counterclockwise. Point Ort() const { return Point(-y, x); } void Transform(m2::Point const & org, m2::Point const & dx, m2::Point const & dy) { T oldX = x; x = org.x + oldX * dx.x + y * dy.x; y = org.y + oldX * dx.y + y * dy.y; } struct Hash { size_t operator()(m2::Point const & p) const { return my::Hash(p.x, p.y); } }; }; template inline Point const operator- (Point const & a, Point const & b) { return Point(a.x - b.x, a.y - b.y); } template inline Point const operator+ (Point const & a, Point const & b) { return Point(a.x + b.x, a.y + b.y); } // Dot product of a and b, equals to |a|*|b|*cos(angle_between_a_and_b). template T const DotProduct(Point const & a, Point const & b) { return a.x * b.x + a.y * b.y; } // Value of cross product of a and b, equals to |a|*|b|*sin(angle_between_a_and_b). template T const CrossProduct(Point const & a, Point const & b) { return a.x * b.y - a.y * b.x; } template Point const Rotate(Point const & pt, T a) { Point res(pt); res.Rotate(a); return res; } template Point const Shift(Point const & pt, U const & dx, U const & dy) { return Point(pt.x + dx, pt.y + dy); } template Point const Shift(Point const & pt, Point const & offset) { return Shift(pt, offset.x, offset.y); } template Point const Floor(Point const & pt) { Point res; res.x = floor(pt.x); res.y = floor(pt.y); return res; } template std::string DebugPrint(m2::Point const & p) { ostringstream out; out.precision(20); out << "m2::Point<" << typeid(T).name() << ">(" << p.x << ", " << p.y << ")"; return out.str(); } template bool AlmostEqualAbs(m2::Point const & a, m2::Point const & b, double const eps) { return my::AlmostEqualAbs(a.x, b.x, eps) && my::AlmostEqualAbs(a.y, b.y, eps); } template bool AlmostEqualULPs(m2::Point const & a, m2::Point const & b, unsigned int maxULPs = 256) { return my::AlmostEqualULPs(a.x, b.x, maxULPs) && my::AlmostEqualULPs(a.y, b.y, maxULPs); } /// Calculate three points of a triangle (p1, p2 and p3) which give an arrow that /// presents an equilateral triangle with the median /// starting at point b and having direction b,e. /// The height of the equilateral triangle is l and the base of the triangle is 2 * w template > void GetArrowPoints(PointT const & b, PointT const & e, T w, T l, array, 3> & arrPnts) { ASSERT(!m2::AlmostEqualULPs(b, e), ()); PointT const beVec = e - b; PointT beNormalizedVec = beVec.Normalize(); std::pair beNormVecs = beNormalizedVec.Normals(w); arrPnts[0] = e + beNormVecs.first; arrPnts[1] = e + beNormalizedVec * l; arrPnts[2] = e + beNormVecs.second; } /// Returns a point which is belonged to the segment p1, p2 with respet the indent shiftFromP1 from p1. /// If shiftFromP1 is more the distance between (p1, p2) it returns p2. /// If shiftFromP1 is less or equal zero it returns p1. template Point PointAtSegment(Point const & p1, Point const & p2, T shiftFromP1) { Point p12 = p2 - p1; shiftFromP1 = my::clamp(shiftFromP1, static_cast(0.0), static_cast(p12.Length())); return p1 + p12.Normalize() * shiftFromP1; } template TArchive & operator >> (TArchive & ar, m2::Point & pt) { ar >> pt.x; ar >> pt.y; return ar; } template TArchive & operator << (TArchive & ar, m2::Point const & pt) { ar << pt.x; ar << pt.y; return ar; } template bool operator< (Point const & l, Point const & r) { if (l.x != r.x) return l.x < r.x; return l.y < r.y; } typedef Point PointF; typedef Point PointD; typedef Point PointU; typedef Point PointU64; typedef Point PointI; typedef Point PointI64; } // namespace m2 namespace my { template bool AlmostEqualULPs(m2::Point const & p1, m2::Point const & p2, unsigned int maxULPs = 256) { return m2::AlmostEqualULPs(p1, p2, maxULPs); } template bool AlmostEqualAbs(m2::Point const & p1, m2::Point const & p2, double const & eps) { return m2::AlmostEqualAbs(p1, p2, eps); } } // namespace my