Skip to content

Commit 7d94598

Browse files
committed
feat: convex hull implementation using Graham scan
1 parent 8338509 commit 7d94598

1 file changed

Lines changed: 43 additions & 6 deletions

File tree

src/alfred/math/flat-geometry.hpp

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
#ifndef AFMT_FLAT_GEOMETRY
33
#define AFMT_FLAT_GEOMETRY
44

5+
#include <algorithm>
56
#include <cmath>
67
#include <iostream>
8+
#include <vector>
79

810
// Recommended eps is 0.25 * given precision
911
template <long double eps>
@@ -53,7 +55,7 @@ struct Double {
5355
template <class T>
5456
struct Vec {
5557
T x, y;
56-
Vec(T _x = 0, T _y = 0) : x(_x), y(_y) {}
58+
constexpr Vec(T _x = 0, T _y = 0) : x(_x), y(_y) {}
5759
constexpr T norm(void) const { return x * x + y * y; }
5860
constexpr Vec operator+(void) const noexcept { return *this; }
5961
constexpr Vec operator-(void) const noexcept { return Vec(-x, -y); }
@@ -63,16 +65,17 @@ struct Vec {
6365
constexpr Vec &operator-=(const Vec &rhs) noexcept {
6466
return x -= rhs.x, y -= rhs.y, *this;
6567
}
66-
constexpr Vec &operator*=(T d) noexcept {
68+
constexpr Vec &operator*=(const T &d) noexcept {
6769
return x *= d, y *= d, *this;
6870
}
69-
constexpr Vec &operator/=(T d) noexcept {
71+
constexpr Vec &operator/=(const T &d) noexcept {
7072
return x /= d, y /= d, *this;
7173
}
7274
friend constexpr Vec operator+(Vec l, const Vec &r) noexcept { return l += r; }
7375
friend constexpr Vec operator-(Vec l, const Vec &r) noexcept { return l -= r; }
74-
friend constexpr Vec operator*(Vec l, const Vec &r) noexcept { return l *= r; }
75-
friend constexpr Vec operator/(Vec l, const Vec &r) noexcept { return l /= r; }
76+
friend constexpr Vec operator*(const T &l, Vec r) noexcept { return r *= l; }
77+
friend constexpr Vec operator*(Vec l, const T &r) noexcept { return l *= r; }
78+
friend constexpr Vec operator/(Vec l, const T &r) noexcept { return l /= r; }
7679
friend constexpr bool operator==(const Vec &l, const Vec &r) noexcept {
7780
return l.x == r.x && l.y == r.y;
7881
}
@@ -101,7 +104,41 @@ inline T cross(const Vec<T> &a, const Vec<T> &b) {
101104
}
102105

103106
template <class T>
104-
struct Segment {
107+
struct PolarAngleComparator {
108+
Point<T> o;
109+
Vec<T> base; // vector (x - o), counterclockwise, from base (included).
110+
PolarAngleComparator(
111+
const Point<T> &o = Point<T>(0, 0),
112+
const Vec<T> &base = Vec<T>(1, 0)
113+
) : o(o), base(base) {}
114+
115+
inline int get_half(const Vec<T> &v) {
116+
T crs = cross(base, v);
117+
if (crs > 0) return 0; // counterclockwise to base
118+
if (crs < 0) return 1; // clockwise to base
119+
return dot(base, v) < 0; // collinear to base, but opposite direction
120+
}
121+
122+
inline bool operator()(const Point<T> &a, const Point<T> &b) const {
123+
const Vec<T> va(a.x - o.x, a.y - o.y);
124+
const Vec<T> vb(b.x - o.x, b.y - o.y);
125+
int ha = get_half(va), hb = get_half(vb);
126+
return ha != hb ? ha < hb : cross(va, vb) > 0;
127+
}
105128
};
106129

130+
template <class T>
131+
std::vector<Point<T>> convex_hull(std::vector<Point<T>> P) { // graham scan, O(n log n)
132+
if (P.size() <= 1) return P;
133+
134+
std::vector<Point<T>> H;
135+
std::swap(P[0], *std::min_element(P.begin(), P.end()));
136+
std::sort(P.begin() + 1, P.end(), PolarAngleComparator<T>(P[0]));
137+
for (const auto &p : P) {
138+
while (H.size() >= 2 && cross(H.back() - H[H.size() - 2], p - H.back()) <= 0) H.pop_back();
139+
H.push_back(p);
140+
}
141+
return H;
142+
}
143+
107144
#endif

0 commit comments

Comments
 (0)