diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 906acf7..93d27a6 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -2,9 +2,9 @@ name: C++ Formatting on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] jobs: format: diff --git a/scripts/format.sh b/scripts/format.sh index e1f5d2d..82633d2 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash root="$(cd "$(dirname "$0")/.." && pwd)" -target="$root/refcode" +target="$root/src" mapfile -t files < <(find "$target" -type f \( -name '*.cpp' -o -name '*.hpp' \)) ((${#files[@]})) || { echo "no .cpp/.hpp files in $target"; exit 0; } declare -A before diff --git a/src/5-geometry/half_plane_intersection.cpp b/src/5-geometry/half_plane_intersection.cpp new file mode 100644 index 0000000..253df59 --- /dev/null +++ b/src/5-geometry/half_plane_intersection.cpp @@ -0,0 +1,60 @@ +#include "../common/common.hpp" +// INPUT: ln: A vector of directed lines (half-planes). +// - IMPORTANT: The valid region is to the LEFT of the line (s -> t). +// - Tip: Add a bounding box (4 lines) if the area might be unbounded. +// OUTPUT: A vector of vertices representing the intersection polygon. +// - Order: Counter-Clockwise (CCW). +// - Returns an empty vector if the intersection is empty or degenerate. +// TIME COMPLEXITY: O(nlogn) +struct Point { + ld x, y; +}; +struct Line { + Point s, t; +}; +constexpr ld EPS = 1e-9; +inline bool equals(ld a, ld b) { return abs(a - b) < EPS; } +bool line_intersect(Point &s1, Point &e1, Point &s2, Point &e2, Point &v) { + ld vx1 = e1.x - s1.x, vy1 = e1.y - s1.y; + ld vx2 = e2.x - s2.x, vy2 = e2.y - s2.y; + ld det = vx1 * (-vy2) - (-vx2) * vy1; + if (equals(det, 0)) return 0; + ld s = (ld)((s2.x - s1.x) * (-vy2) + (s2.y - s1.y) * vx2) / det; + v.x = s1.x + vx1 * s; + v.y = s1.y + vy1 * s; + return 1; +} +bool bad(Line &a, Line &b, Line &c) { + Point v; + if (!line_intersect(a.s, a.t, b.s, b.t, v)) return 0; + ld crs = (c.t.x - c.s.x) * (v.y - c.s.y) - (c.t.y - c.s.y) * (v.x - c.s.x); + return crs < 0 || equals(crs, 0); +} +vector hpi(vector &ln) { + auto lsgn = [&](const Line &a) { + if (a.s.y == a.t.y) return a.s.x > a.t.x; + return a.s.y > a.t.y; + }; + sort(ln.begin(), ln.end(), [&](const Line &a, const Line &b) { + if (lsgn(a) != lsgn(b)) return lsgn(a) < lsgn(b); + return (a.t.x - a.s.x) * (b.t.y - b.s.y) - (a.t.y - a.s.y) * (b.t.x - b.s.x) > 0; + }); + deque dq; + for (int i = 0; i < sz(ln); i++) { + while (dq.size() >= 2 && bad(dq[dq.size() - 2], dq.back(), ln[i])) + dq.pop_back(); + while (dq.size() >= 2 && bad(dq[0], dq[1], ln[i])) + dq.pop_front(); + if (dq.size() < 2 || !bad(dq.back(), ln[i], dq[0])) + dq.push_back(ln[i]); + } + vector ret; + if (dq.size() >= 3) + for (int i = 0; i < sz(dq); i++) { + int j = (i + 1) % sz(dq); + Point v; + if (!line_intersect(dq[i].s, dq[i].t, dq[j].s, dq[j].t, v)) continue; + ret.push_back(v); + } + return ret; +} diff --git a/src/common/common.hpp b/src/common/common.hpp index aa84e02..c085fc3 100644 --- a/src/common/common.hpp +++ b/src/common/common.hpp @@ -4,6 +4,7 @@ using namespace std; using ll = long long; +using ld = long double; using pii = pair; using pll = pair;