#pragma once #include "../base/assert.hpp" #include "../base/base.hpp" #include "../base/math.hpp" #include "../base/matrix.hpp" #include "../std/cmath.hpp" #include "../std/sstream.hpp" #include "../std/typeinfo.hpp" namespace m2 { template class Point { public: typedef T value_type; T x, y; Point() {} 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)); } 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 AlmostEqual(*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); } /// @name VectorOperationsOnPoint // @{ double Length() const { return sqrt(x*x + y*y); } Point Normalize() const { ASSERT(!IsAlmostZero(), ()); double const module = this->Length(); return Point(x / module, y / module); } // @} 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; } 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; } }; 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 bool IsPointInsideTriangle(Point const & p, Point const & a, Point const & b, Point const & c) { T const cpab = CrossProduct(b - a, p - a); T const cpbc = CrossProduct(c - b, p - b); T const cpca = CrossProduct(a - c, p - c); return (cpab <= 0 && cpbc <= 0 && cpca <= 0) || (cpab >= 0 && cpbc >= 0 && cpca >= 0); } template bool IsPointStrictlyInsideTriangle(Point const & p, Point const & a, Point const & b, Point const & c) { T const cpab = CrossProduct(b - a, p - a); T const cpbc = CrossProduct(c - b, p - b); T const cpca = CrossProduct(a - c, p - c); return (cpab < 0 && cpbc < 0 && cpca < 0) || (cpab > 0 && cpbc > 0 && cpca > 0); } template bool SegmentsIntersect(Point const & a, Point const & b, Point const & c, Point const & d) { return max(a.x, b.x) >= min(c.x, d.x) && min(a.x, b.x) <= max(c.x, d.x) && max(a.y, b.y) >= min(c.y, d.y) && min(a.y, b.y) <= max(c.y, d.y) && CrossProduct(c - a, b - a) * CrossProduct(d - a, b - a) <= 0 && CrossProduct(a - c, d - c) * CrossProduct(b - c, d - c) <= 0; } /// Is segment (v, v1) in cone (vPrev, v, vNext)? /// @precondition Orientation CCW!!! template bool IsSegmentInCone(PointT v, PointT v1, PointT vPrev, PointT vNext) { PointT const diff = v1 - v; PointT const edgeL = vPrev - v; PointT const edgeR = vNext - v; double const cpLR = CrossProduct(edgeR, edgeL); if (my::AlmostEqual(cpLR, 0.0)) { // Points vPrev, v, vNext placed on one line; // use property that polygon has CCW orientation. return CrossProduct(vNext - vPrev, v1 - vPrev) > 0.0; } if (cpLR > 0) { // vertex is convex return CrossProduct(diff, edgeR) < 0 && CrossProduct(diff, edgeL) > 0.0; } else { // vertex is reflex return CrossProduct(diff, edgeR) < 0 || CrossProduct(diff, edgeL) > 0.0; } } template int GetOrientation(PointT const & p1, PointT const & p2, PointT const & pt) { double const sa = CrossProduct(p1 - pt, p2 - pt); if (sa > 0.0) return 1; if (sa < 0.0) return -1; return 0; } template 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 AlmostEqual(m2::Point const & a, m2::Point const & b, unsigned int maxULPs = 256) { return my::AlmostEqual(a.x, b.x, maxULPs) && my::AlmostEqual(a.y, b.y, maxULPs); } 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 my { template bool AlmostEqual(m2::Point const & p1, m2::Point const & p2, unsigned int maxULPs = 256) { return m2::AlmostEqual(p1, p2, maxULPs); } }