geometry/point.hpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <complex> | ||
| 4 | #include <tuple> | ||
| 5 | #include <iostream> | ||
| 6 | #include <numeric> | ||
| 7 | |||
| 8 | template <typename T, typename AreaT=T> struct Point { | ||
| 9 | public: | ||
| 10 | T x, y; | ||
| 11 | 3331997 | Point() : x(0), y(0) {} | |
| 12 | 130742101 | Point(T x_, T y_) : x(x_), y(y_) {} | |
| 13 | ✗ | template <typename U, typename V> explicit Point(const Point<U, V>& p) : x(p.x), y(p.y) {} | |
| 14 | ✗ | Point(const std::pair<T, T>& p) : x(p.first), y(p.second) {} | |
| 15 | ✗ | Point(const std::complex<T>& p) : x(real(p)), y(imag(p)) {} | |
| 16 | ✗ | explicit operator std::pair<T, T> () const { return std::pair<T, T>(x, y); } | |
| 17 | ✗ | explicit operator std::complex<T> () const { return std::complex<T>(x, y); } | |
| 18 | ✗ | auto as_pair() const { return std::pair<T, T>(*this); } | |
| 19 | ✗ | auto as_complex() const { return std::complex<T>(*this); } | |
| 20 | |||
| 21 | ✗ | friend std::ostream& operator << (std::ostream& o, const Point& p) { return o << '(' << p.x << ',' << p.y << ')'; } | |
| 22 | 3331997 | friend std::istream& operator >> (std::istream& i, Point& p) { return i >> p.x >> p.y; } | |
| 23 |
8/8✓ Branch 2 → 3 taken 4640300 times.
✓ Branch 2 → 4 taken 60730740 times.
✓ Branch 3 → 4 taken 87 times.
✓ Branch 3 → 5 taken 4640213 times.
✓ Branch 5 → 6 taken 4638812 times.
✓ Branch 5 → 7 taken 60732228 times.
✓ Branch 6 → 7 taken 73 times.
✓ Branch 6 → 8 taken 4638739 times.
|
126101867 | friend bool operator == (const Point& a, const Point& b) { return a.x == b.x && a.y == b.y; } |
| 24 | ✗ | friend bool operator != (const Point& a, const Point& b) { return !(a==b); } | |
| 25 | |||
| 26 | ✗ | Point operator + () const { return Point(+x, +y); } | |
| 27 | ✗ | Point operator - () const { return Point(-x, -y); } | |
| 28 | |||
| 29 | ✗ | Point& operator += (const Point& p) { x += p.x, y += p.y; return *this; } | |
| 30 | ✗ | Point& operator -= (const Point& p) { x -= p.x, y -= p.y; return *this; } | |
| 31 | ✗ | Point& operator *= (const T& t) { x *= t, y *= t; return *this; } | |
| 32 | ✗ | Point& operator /= (const T& t) { x /= t, y /= t; return *this; } | |
| 33 | |||
| 34 | ✗ | friend Point operator + (const Point& a, const Point& b) { return Point(a.x+b.x, a.y+b.y); } | |
| 35 | ✗ | friend Point operator - (const Point& a, const Point& b) { return Point(a.x-b.x, a.y-b.y); } | |
| 36 | ✗ | friend Point operator * (const Point& a, const T& t) { return Point(a.x*t, a.y*t); } | |
| 37 | ✗ | friend Point operator * (const T& t ,const Point& a) { return Point(t*a.x, t*a.y); } | |
| 38 | ✗ | friend Point operator / (const Point& a, const T& t) { return Point(a.x/t, a.y/t); } | |
| 39 | |||
| 40 | ✗ | AreaT dist2() const { return AreaT(x) * AreaT(x) + AreaT(y) * AreaT(y); } | |
| 41 | ✗ | auto dist() const { return std::sqrt(dist2()); } | |
| 42 | ✗ | Point unit() const { return *this / this->dist(); } | |
| 43 | ✗ | auto angle() const { return std::atan2(y, x); } | |
| 44 | |||
| 45 | ✗ | T int_norm() const { return std::gcd(x,y); } | |
| 46 | ✗ | Point int_unit() const { if (!x && !y) return *this; return *this / this->int_norm(); } | |
| 47 | |||
| 48 | // Convenient free-functions, mostly for generic interop | ||
| 49 | ✗ | friend auto norm(const Point& a) { return a.dist2(); } | |
| 50 | ✗ | friend auto abs(const Point& a) { return a.dist(); } | |
| 51 | ✗ | friend auto unit(const Point& a) { return a.unit(); } | |
| 52 | ✗ | friend auto arg(const Point& a) { return a.angle(); } | |
| 53 | ✗ | friend auto int_norm(const Point& a) { return a.int_norm(); } | |
| 54 | ✗ | friend auto int_unit(const Point& a) { return a.int_unit(); } | |
| 55 | |||
| 56 | ✗ | Point perp_cw() const { return Point(y, -x); } | |
| 57 | ✗ | Point perp_ccw() const { return Point(-y, x); } | |
| 58 | |||
| 59 | 18497507 | friend AreaT dot(const Point& a, const Point& b) { return AreaT(a.x) * AreaT(b.x) + AreaT(a.y) * AreaT(b.y); } | |
| 60 | 193085463 | friend AreaT cross(const Point& a, const Point& b) { return AreaT(a.x) * AreaT(b.y) - AreaT(a.y) * AreaT(b.x); } | |
| 61 | ✗ | friend AreaT cross3(const Point& a, const Point& b, const Point& c) { return cross(b-a, c-a); } | |
| 62 | |||
| 63 | // Complex numbers and rotation | ||
| 64 | ✗ | friend Point conj(const Point& a) { return Point(a.x, -a.y); } | |
| 65 | |||
| 66 | // Returns conj(a) * b | ||
| 67 | ✗ | friend Point dot_cross(const Point& a, const Point& b) { return Point(dot(a, b), cross(a, b)); } | |
| 68 | ✗ | friend Point cmul(const Point& a, const Point& b) { return dot_cross(conj(a), b); } | |
| 69 | ✗ | friend Point cdiv(const Point& a, const Point& b) { return dot_cross(b, a) / b.dist2(); } | |
| 70 | |||
| 71 | // Must be a unit vector; otherwise multiplies the result by abs(u) | ||
| 72 | ✗ | Point rotate(const Point& u) const { return dot_cross(conj(u), *this); } | |
| 73 | ✗ | Point unrotate(const Point& u) const { return dot_cross(u, *this); } | |
| 74 | |||
| 75 | ✗ | friend bool lex_less(const Point& a, const Point& b) { | |
| 76 | ✗ | return std::tie(a.x, a.y) < std::tie(b.x, b.y); | |
| 77 | } | ||
| 78 | |||
| 79 | ✗ | friend bool same_dir(const Point& a, const Point& b) { return cross(a,b) == 0 && dot(a,b) > 0; } | |
| 80 | |||
| 81 | // check if 180 <= s..t < 360 | ||
| 82 |
2/2✓ Branch 2 → 3 taken 112244573 times.
✓ Branch 2 → 4 taken 18497507 times.
|
130742080 | friend bool is_reflex(const Point& a, const Point& b) { auto c = cross(a,b); return c ? (c < 0) : (dot(a, b) < 0); } |
| 83 | |||
| 84 | // operator < (s,t) for angles in [base,base+2pi) | ||
| 85 | ✗ | friend bool angle_less_from(const Point& base, const Point& s, const Point& t) { | |
| 86 | ✗ | int r = is_reflex(base, s) - is_reflex(base, t); | |
| 87 | ✗ | return r ? (r < 0) : (0 < cross(s, t)); | |
| 88 | } | ||
| 89 | // operator < (s,t) for angles in (base,base+2pi] | ||
| 90 | 65371040 | friend bool angle_less_upto(const Point& base, const Point& s, const Point& t) { | |
| 91 | 65371040 | int r = is_reflex(t, base) - is_reflex(s, base); | |
| 92 |
2/2✓ Branch 2 → 3 taken 3027657 times.
✓ Branch 2 → 4 taken 62343383 times.
|
65371040 | return r ? (r < 0) : (0 < cross(s, t)); |
| 93 | } | ||
| 94 | |||
| 95 | ✗ | friend auto angle_cmp_from(const Point& base) { | |
| 96 | ✗ | return [base](const Point& s, const Point& t) { return angle_less_from(base, s, t); }; | |
| 97 | } | ||
| 98 | 21 | friend auto angle_cmp_upto(const Point& base) { | |
| 99 | 65371040 | return [base](const Point& s, const Point& t) { return angle_less_upto(base, s, t); }; | |
| 100 | } | ||
| 101 | ✗ | friend auto angle_cmp_center_from(const Point& center, const Point& dir) { | |
| 102 | ✗ | return [center, dir](const Point& s, const Point& t) -> bool { return angle_less_from(dir, s-center, t-center); }; | |
| 103 | } | ||
| 104 | ✗ | friend auto angle_cmp_center_upto(const Point& center, const Point& dir) { | |
| 105 | ✗ | return [center, dir](const Point& s, const Point& t) -> bool { return angle_less_upto(dir, s-center, t-center); }; | |
| 106 | } | ||
| 107 | |||
| 108 | // is p in [s,t] taken ccw? 1/0/-1 for in/border/out | ||
| 109 | ✗ | friend int angle_between(const Point& s, const Point& t, const Point& p) { | |
| 110 | ✗ | if (same_dir(p, s) || same_dir(p, t)) return 0; | |
| 111 | ✗ | return angle_less_from(s, p, t) ? 1 : -1; | |
| 112 | } | ||
| 113 | }; | ||
| 114 |