Yuri3's Code Library

Some Code Template Just for Fun.

View the Project on GitHub Yuri3-xr/CP-library

:warning: Geometry/GeometryTemplate.hpp

Depends on

Code

#pragma once

#include "../Template/Template.hpp"

namespace Geometry {
// using T = i64;
// constexpr T eps = 0;

using T = double;
constexpr T eps = 1E-10;

bool equal(const T &x, const T &y) { return abs(x - y) <= eps; }
int sgn(T x) { return (x > 0) - (x < 0); }
inline constexpr int type(T x, T y) {
    if (x == 0 and y == 0) return 0;
    if (y < 0 or (y == 0 and x > 0)) return -1;
    return 1;
}
struct Point {
    T x, y;
    constexpr Point(T _x = 0, T _y = 0) : x(_x), y(_y) {}
    constexpr Point operator+() const noexcept { return *this; }
    constexpr Point operator-() const noexcept { return Point(-x, -y); }
    constexpr Point operator+(const Point &p) const {
        return Point(x + p.x, y + p.y);
    }
    constexpr Point operator-(const Point &p) const {
        return Point(x - p.x, y - p.y);
    }
    constexpr Point &operator+=(const Point &p) {
        return x += p.x, y += p.y, *this;
    }
    constexpr Point &operator-=(const Point &p) {
        return x -= p.x, y -= p.y, *this;
    }
    constexpr T operator*(const Point &p) const { return x * p.x + y * p.y; }
    const Point operator/(T d) const { return Point(x / d, y / d); }
    constexpr Point &operator*=(const T &k) { return x *= k, y *= k, *this; }
    constexpr Point operator*(const T &k) { return Point(x * k, y * k); }
    constexpr bool operator==(const Point &r) const noexcept {
        return r.x == x and r.y == y;
    }
    constexpr bool operator!=(const Point &r) const noexcept {
        return !(*this == r);
    }
    constexpr T cross(const Point &r) const { return x * r.y - y * r.x; }
    constexpr T cross(Point a, Point b) const {
        return (a - *this).cross(b - *this);
    }
    constexpr bool operator<(const Point &r) const {
        return std::pair(x, y) < std::pair(r.x, r.y);
    }

    // 1 : left, 0 : same, -1 : right
    constexpr int toleft(const Point &r) const {
        auto t = cross(r);
        return t > eps ? 1 : t < -eps ? -1 : 0;
    }

    constexpr bool arg_cmp(const Point &r) const {
        int L = type(x, y), R = type(r.x, r.y);
        if (L != R) return L < R;

        T X = x * r.y, Y = r.x * y;
        if (X != Y) return X > Y;
        return x < r.x;
    }
};
bool arg_cmp(const Point &l, const Point &r) { return l.arg_cmp(r); }
std::ostream &operator<<(std::ostream &os, const Point &p) {
    return os << p.x << " " << p.y;
}
std::istream &operator>>(std::istream &is, Point &p) {
    is >> p.x >> p.y;
    return is;
}

struct Line {
    Point a, b;
    Line() = default;
    Line(Point a, Point b) : a(a), b(b) {}
    // ax + by = c
    Line(T A, T B, T C) {
        if (A == 0) {
            a = Point(0, C / B), b = Point(1, C / B);
        } else if (B == 0) {
            a = Point(C / A, 0), b = Point(C / A, 1);
        } else {
            a = Point(0, C / B), b = Point(C / A, 0);
        }
    }
    // 1 : left, 0 : same, -1 : right
    constexpr int toleft(const Point &r) const {
        auto t = (b - a).cross(r - a);
        return t > eps ? 1 : t < -eps ? -1 : 0;
    }

    friend std::ostream &operator<<(std::ostream &os, Line &ls) {
        return os << "{"
                  << "(" << ls.a.x << ", " << ls.a.y << "), (" << ls.b.x << ", "
                  << ls.b.y << ")}";
    }
};
std::istream &operator>>(std::istream &is, Line &p) { return is >> p.a >> p.b; }

struct Segment : Line {
    Segment() = default;
    Segment(Point a, Point b) : Line(a, b) {}
};

std::ostream &operator<<(std::ostream &os, Segment &p) {
    return os << p.a << " to " << p.b;
}
std::istream &operator>>(std::istream &is, Segment &p) {
    is >> p.a >> p.b;
    return is;
}

struct Circle {
    Point p;
    T r;
    Circle() = default;
    Circle(Point p, T r) : p(p), r(r) {}
};

using pt = Point;
using Points = std::vector<pt>;
using Polygon = Points;
T cross(const pt &x, const pt &y) { return x.x * y.y - x.y * y.x; }
T dot(const pt &x, const pt &y) { return x.x * y.x + x.y * y.y; }

T abs2(const pt &x) { return dot(x, x); }

int ccw(const Point &a, Point b, Point c) {
    b = b - a, c = c - a;
    if (cross(b, c) > 0) return +1;    // "COUNTER_CLOCKWISE"
    if (cross(b, c) < 0) return -1;    // "CLOCKWISE"
    if (dot(b, c) < 0) return +2;      // "ONLINE_BACK"
    if (abs2(b) < abs2(c)) return -2;  // "ONLINE_FRONT"
    return 0;                          // "ON_SEGMENT"
}

bool parallel(const Line &a, const Line &b) {
    return (cross(a.b - a.a, b.b - b.a) == 0);
}

bool orthogonal(const Line &a, const Line &b) {
    return (dot(a.a - a.b, b.a - b.b) == 0);
}

bool intersect(const Line &l, const Point &p) {
    return abs(ccw(l.a, l.b, p)) != 1;
}

bool intersect(const Line &l, const Line &m) { return !parallel(l, m); }

bool intersect(const Segment &s, const Point &p) {
    return ccw(s.a, s.b, p) == 0;
}

bool intersect(const Line &l, const Segment &s) {
    return cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) <= 0;
}

bool intersect(const Segment &s, const Segment &t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
           ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

std::vector<Point> segInter(const Segment &sa, const Segment &sb) {
    // if no intersect point return {}
    // if inf intersect points return two end point
    auto a = sa.a, b = sa.b;
    auto c = sb.a, d = sb.b;
    auto oa = c.cross(d, a), ob = c.cross(d, b), oc = a.cross(b, c),
         od = a.cross(b, d);
    if (sgn(oa) * sgn(ob) < 0 && sgn(oc) * sgn(od) < 0)
        return {(a * ob - b * oa) / (ob - oa)};
    std::set<Point> s;
    if (intersect(Segment(c, d), a)) s.insert(a);
    if (intersect(Segment(c, d), b)) s.insert(b);
    if (intersect(Segment(a, b), c)) s.insert(c);
    if (intersect(Segment(a, b), d)) s.insert(d);
    return {begin(s), end(s)};
}

bool intersect(const Polygon &ps, const Polygon &qs) {
    int pl = size(ps), ql = size(qs), i = 0, j = 0;
    while ((i < pl or j < ql) and (i < 2 * pl) and (j < 2 * ql)) {
        auto ps0 = ps[(i + pl - 1) % pl], ps1 = ps[i % pl];
        auto qs0 = qs[(j + ql - 1) % ql], qs1 = qs[j % ql];
        if (intersect(Segment(ps0, ps1), Segment(qs0, qs1))) return true;
        Point a = ps1 - ps0;
        Point b = qs1 - qs0;
        T v = cross(a, b);
        T va = cross(qs1 - qs0, ps1 - qs0);
        T vb = cross(ps1 - ps0, qs1 - ps0);

        if (!v and va < 0 and vb < 0) return false;
        if (!v and !va and !vb) {
            i += 1;
        } else if (v >= 0) {
            if (vb > 0)
                i += 1;
            else
                j += 1;
        } else {
            if (va > 0)
                j += 1;
            else
                i += 1;
        }
    }
    return false;
}

T norm(const Point &p) { return p.x * p.x + p.y * p.y; }
Point projection(const Segment &l, const Point &p) {
    T t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}

Point crossPoint(const Line &l, const Line &m) {
    T A = cross(l.b - l.a, m.b - m.a);
    T B = cross(l.b - l.a, l.b - m.a);
    if (A == 0 and B == 0) return m.a;
    return m.a + (m.b - m.a) * (B / A);
}

Point crossPoint(const Segment &l, const Segment &m) {
    return crossPoint(Line(l), Line(m));
}

bool isConvex(const Points &p) {
    int n = (int)p.size();
    for (int i = 0; i < n; i++) {
        if (ccw(p[(i + n - 1) % n], p[i], p[(i + 1) % n]) == -1) return false;
    }
    return true;
}

Points convexHull(Points p) {
    int n = p.size(), k = 0;
    if (n <= 2) return p;
    std::sort(begin(p), end(p),
              [](pt x, pt y) { return (x.x != y.x ? x.x < y.x : x.y < y.y); });
    Points ch(2 * n);
    for (int i = 0; i < n; ch[k++] = p[i++]) {
        while (k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) <= 0)
            --k;
    }
    for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
        while (k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) <= 0)
            --k;
    }
    ch.resize(k - 1);
    return ch;
}

T area2(const Points &p) {
    T res = 0;
    for (int i = 0; i < (int)p.size(); i++) {
        res += cross(p[i], p[i == int(size(p)) - 1 ? 0 : i + 1]);
    }
    return res;
}

enum { _OUT, _ON, _IN };

int containsHullPoint(const Polygon &Q, const Point &p) {
    // Brute Force : O(|Q|)
    bool in = false;
    for (int i = 0; i < Q.size(); i++) {
        Point a = Q[i] - p, b = Q[(i + 1) % Q.size()] - p;
        if (a.y > b.y) std::swap(a, b);
        if (a.y <= 0 && 0 < b.y && cross(a, b) < 0) in = !in;
        if (cross(a, b) == 0 && dot(a, b) <= 0) return _ON;
    }
    return in ? _IN : _OUT;
}

Polygon minkowskiSum(const Polygon &P, const Polygon &Q) {
    std::vector<Segment> e1(P.size()), e2(Q.size()), ed(P.size() + Q.size());
    const auto cmp = [](const Segment &u, const Segment &v) {
        return (u.b - u.a).arg_cmp(v.b - v.a);
    };
    for (int i = 0; i < int(P.size()); i++)
        e1[i] = {P[i], P[(i + 1) % P.size()]};
    for (int i = 0; i < int(Q.size()); i++)
        e2[i] = {Q[i], Q[(i + 1) % Q.size()]};
    std::rotate(begin(e1), std::min_element(begin(e1), end(e1), cmp), end(e1));
    std::rotate(begin(e2), std::min_element(begin(e2), end(e2), cmp), end(e2));
    std::merge(begin(e1), end(e1), begin(e2), end(e2), begin(ed), cmp);
    const auto check = [](const Points &res, const Point &u) {
        const auto back1 = res.back(), back2 = *prev(end(res), 2);
        return equal(cross(back1 - back2, u - back2), eps) and
               dot(back1 - back2, u - back1) >= -eps;
    };
    auto u = e1[0].a + e2[0].a;
    Points res{u};
    res.reserve(P.size() + Q.size());
    for (const auto &v : ed) {
        u = u + v.b - v.a;
        while (int(size(res)) >= 2 and check(res, u)) res.pop_back();
        res.emplace_back(u);
    }
    if (res.size() and check(res, res[0])) res.pop_back();
    return res;
}

// -1 : on, 0 : out, 1 : in
// O(log(n))
int containsHullPointFast(const Polygon &p, const Point &a) {
    // Binary Search O(log|P|)
    if (p.size() == 1) return a == p[0] ? -1 : 0;
    if (p.size() == 2) return intersect(Segment(p[0], p[1]), a);
    if (a == p[0]) return -1;
    if ((p[1] - p[0]).toleft(a - p[0]) == -1 ||
        (p.back() - p[0]).toleft(a - p[0]) == 1)
        return 0;
    const auto cmp = [&](const Point &u, const Point &v) {
        return (u - p[0]).toleft(v - p[0]) == 1;
    };
    const size_t i = lower_bound(p.begin() + 1, p.end(), a, cmp) - p.begin();
    if (i == 1) return intersect(Segment(p[0], p[i]), a) ? -1 : 0;
    if (i == p.size() - 1 && intersect(Segment(p[0], p[i]), a)) return -1;
    if (intersect(Segment(p[i - 1], p[i]), a)) return -1;
    return (p[i] - p[i - 1]).toleft(a - p[i - 1]) > 0;
}

Points halfplaneIntersection(std::vector<Line> L, const T inf = 1e9) {
    // left half plane
    Point box[4] = {Point(inf, inf), Point(-inf, inf), Point(-inf, -inf),
                    Point(inf, -inf)};
    for (int i = 0; i < 4; i++) {
        L.emplace_back(box[i], box[(i + 1) % 4]);
    }
    std::sort(begin(L), end(L), [](const Line &l, const Line &r) {
        return (l.b - l.a).arg_cmp(r.b - r.a);
    });
    std::deque<Line> dq;
    int len = 0;
    auto check = [](const Line &a, const Line &b, const Line &c) {
        return a.toleft(crossPoint(b, c)) == -1;
    };
    for (int i = 0; i < (int)L.size(); i++) {
        while (dq.size() > 1 and check(L[i], *(end(dq) - 2), *(end(dq) - 1)))
            dq.pop_back();
        while (dq.size() > 1 and check(L[i], dq[0], dq[1])) dq.pop_front();
        // dump(L[i], si(dq));

        if (dq.size() and
            equal(cross(L[i].b - L[i].a, dq.back().b - dq.back().a), 0)) {
            if (dot(L[i].b - L[i].a, dq.back().b - dq.back().a) < eps)
                return {};
            if (L[i].toleft(dq.back().a) == -1)
                dq.pop_back();
            else
                continue;
        }
        dq.emplace_back(L[i]);
    }

    while (dq.size() > 2 and check(dq[0], *(end(dq) - 2), *(end(dq) - 1)))
        dq.pop_back();
    while (dq.size() > 2 and check(dq.back(), dq[0], dq[1])) dq.pop_front();
    if ((int)size(dq) < 3) return {};
    Polygon ret(dq.size());
    for (int i = 0; i < (int)dq.size(); i++)
        ret[i] = crossPoint(dq[i], dq[(i + 1) % dq.size()]);

    return ret;
}
} 
#line 2 "Geometry/GeometryTemplate.hpp"

#line 2 "Template/Template.hpp"

#include <bits/stdc++.h>

using i64 = std::int64_t;
#line 4 "Geometry/GeometryTemplate.hpp"

namespace Geometry {
// using T = i64;
// constexpr T eps = 0;

using T = double;
constexpr T eps = 1E-10;

bool equal(const T &x, const T &y) { return abs(x - y) <= eps; }
int sgn(T x) { return (x > 0) - (x < 0); }
inline constexpr int type(T x, T y) {
    if (x == 0 and y == 0) return 0;
    if (y < 0 or (y == 0 and x > 0)) return -1;
    return 1;
}
struct Point {
    T x, y;
    constexpr Point(T _x = 0, T _y = 0) : x(_x), y(_y) {}
    constexpr Point operator+() const noexcept { return *this; }
    constexpr Point operator-() const noexcept { return Point(-x, -y); }
    constexpr Point operator+(const Point &p) const {
        return Point(x + p.x, y + p.y);
    }
    constexpr Point operator-(const Point &p) const {
        return Point(x - p.x, y - p.y);
    }
    constexpr Point &operator+=(const Point &p) {
        return x += p.x, y += p.y, *this;
    }
    constexpr Point &operator-=(const Point &p) {
        return x -= p.x, y -= p.y, *this;
    }
    constexpr T operator*(const Point &p) const { return x * p.x + y * p.y; }
    const Point operator/(T d) const { return Point(x / d, y / d); }
    constexpr Point &operator*=(const T &k) { return x *= k, y *= k, *this; }
    constexpr Point operator*(const T &k) { return Point(x * k, y * k); }
    constexpr bool operator==(const Point &r) const noexcept {
        return r.x == x and r.y == y;
    }
    constexpr bool operator!=(const Point &r) const noexcept {
        return !(*this == r);
    }
    constexpr T cross(const Point &r) const { return x * r.y - y * r.x; }
    constexpr T cross(Point a, Point b) const {
        return (a - *this).cross(b - *this);
    }
    constexpr bool operator<(const Point &r) const {
        return std::pair(x, y) < std::pair(r.x, r.y);
    }

    // 1 : left, 0 : same, -1 : right
    constexpr int toleft(const Point &r) const {
        auto t = cross(r);
        return t > eps ? 1 : t < -eps ? -1 : 0;
    }

    constexpr bool arg_cmp(const Point &r) const {
        int L = type(x, y), R = type(r.x, r.y);
        if (L != R) return L < R;

        T X = x * r.y, Y = r.x * y;
        if (X != Y) return X > Y;
        return x < r.x;
    }
};
bool arg_cmp(const Point &l, const Point &r) { return l.arg_cmp(r); }
std::ostream &operator<<(std::ostream &os, const Point &p) {
    return os << p.x << " " << p.y;
}
std::istream &operator>>(std::istream &is, Point &p) {
    is >> p.x >> p.y;
    return is;
}

struct Line {
    Point a, b;
    Line() = default;
    Line(Point a, Point b) : a(a), b(b) {}
    // ax + by = c
    Line(T A, T B, T C) {
        if (A == 0) {
            a = Point(0, C / B), b = Point(1, C / B);
        } else if (B == 0) {
            a = Point(C / A, 0), b = Point(C / A, 1);
        } else {
            a = Point(0, C / B), b = Point(C / A, 0);
        }
    }
    // 1 : left, 0 : same, -1 : right
    constexpr int toleft(const Point &r) const {
        auto t = (b - a).cross(r - a);
        return t > eps ? 1 : t < -eps ? -1 : 0;
    }

    friend std::ostream &operator<<(std::ostream &os, Line &ls) {
        return os << "{"
                  << "(" << ls.a.x << ", " << ls.a.y << "), (" << ls.b.x << ", "
                  << ls.b.y << ")}";
    }
};
std::istream &operator>>(std::istream &is, Line &p) { return is >> p.a >> p.b; }

struct Segment : Line {
    Segment() = default;
    Segment(Point a, Point b) : Line(a, b) {}
};

std::ostream &operator<<(std::ostream &os, Segment &p) {
    return os << p.a << " to " << p.b;
}
std::istream &operator>>(std::istream &is, Segment &p) {
    is >> p.a >> p.b;
    return is;
}

struct Circle {
    Point p;
    T r;
    Circle() = default;
    Circle(Point p, T r) : p(p), r(r) {}
};

using pt = Point;
using Points = std::vector<pt>;
using Polygon = Points;
T cross(const pt &x, const pt &y) { return x.x * y.y - x.y * y.x; }
T dot(const pt &x, const pt &y) { return x.x * y.x + x.y * y.y; }

T abs2(const pt &x) { return dot(x, x); }

int ccw(const Point &a, Point b, Point c) {
    b = b - a, c = c - a;
    if (cross(b, c) > 0) return +1;    // "COUNTER_CLOCKWISE"
    if (cross(b, c) < 0) return -1;    // "CLOCKWISE"
    if (dot(b, c) < 0) return +2;      // "ONLINE_BACK"
    if (abs2(b) < abs2(c)) return -2;  // "ONLINE_FRONT"
    return 0;                          // "ON_SEGMENT"
}

bool parallel(const Line &a, const Line &b) {
    return (cross(a.b - a.a, b.b - b.a) == 0);
}

bool orthogonal(const Line &a, const Line &b) {
    return (dot(a.a - a.b, b.a - b.b) == 0);
}

bool intersect(const Line &l, const Point &p) {
    return abs(ccw(l.a, l.b, p)) != 1;
}

bool intersect(const Line &l, const Line &m) { return !parallel(l, m); }

bool intersect(const Segment &s, const Point &p) {
    return ccw(s.a, s.b, p) == 0;
}

bool intersect(const Line &l, const Segment &s) {
    return cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) <= 0;
}

bool intersect(const Segment &s, const Segment &t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
           ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

std::vector<Point> segInter(const Segment &sa, const Segment &sb) {
    // if no intersect point return {}
    // if inf intersect points return two end point
    auto a = sa.a, b = sa.b;
    auto c = sb.a, d = sb.b;
    auto oa = c.cross(d, a), ob = c.cross(d, b), oc = a.cross(b, c),
         od = a.cross(b, d);
    if (sgn(oa) * sgn(ob) < 0 && sgn(oc) * sgn(od) < 0)
        return {(a * ob - b * oa) / (ob - oa)};
    std::set<Point> s;
    if (intersect(Segment(c, d), a)) s.insert(a);
    if (intersect(Segment(c, d), b)) s.insert(b);
    if (intersect(Segment(a, b), c)) s.insert(c);
    if (intersect(Segment(a, b), d)) s.insert(d);
    return {begin(s), end(s)};
}

bool intersect(const Polygon &ps, const Polygon &qs) {
    int pl = size(ps), ql = size(qs), i = 0, j = 0;
    while ((i < pl or j < ql) and (i < 2 * pl) and (j < 2 * ql)) {
        auto ps0 = ps[(i + pl - 1) % pl], ps1 = ps[i % pl];
        auto qs0 = qs[(j + ql - 1) % ql], qs1 = qs[j % ql];
        if (intersect(Segment(ps0, ps1), Segment(qs0, qs1))) return true;
        Point a = ps1 - ps0;
        Point b = qs1 - qs0;
        T v = cross(a, b);
        T va = cross(qs1 - qs0, ps1 - qs0);
        T vb = cross(ps1 - ps0, qs1 - ps0);

        if (!v and va < 0 and vb < 0) return false;
        if (!v and !va and !vb) {
            i += 1;
        } else if (v >= 0) {
            if (vb > 0)
                i += 1;
            else
                j += 1;
        } else {
            if (va > 0)
                j += 1;
            else
                i += 1;
        }
    }
    return false;
}

T norm(const Point &p) { return p.x * p.x + p.y * p.y; }
Point projection(const Segment &l, const Point &p) {
    T t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}

Point crossPoint(const Line &l, const Line &m) {
    T A = cross(l.b - l.a, m.b - m.a);
    T B = cross(l.b - l.a, l.b - m.a);
    if (A == 0 and B == 0) return m.a;
    return m.a + (m.b - m.a) * (B / A);
}

Point crossPoint(const Segment &l, const Segment &m) {
    return crossPoint(Line(l), Line(m));
}

bool isConvex(const Points &p) {
    int n = (int)p.size();
    for (int i = 0; i < n; i++) {
        if (ccw(p[(i + n - 1) % n], p[i], p[(i + 1) % n]) == -1) return false;
    }
    return true;
}

Points convexHull(Points p) {
    int n = p.size(), k = 0;
    if (n <= 2) return p;
    std::sort(begin(p), end(p),
              [](pt x, pt y) { return (x.x != y.x ? x.x < y.x : x.y < y.y); });
    Points ch(2 * n);
    for (int i = 0; i < n; ch[k++] = p[i++]) {
        while (k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) <= 0)
            --k;
    }
    for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
        while (k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) <= 0)
            --k;
    }
    ch.resize(k - 1);
    return ch;
}

T area2(const Points &p) {
    T res = 0;
    for (int i = 0; i < (int)p.size(); i++) {
        res += cross(p[i], p[i == int(size(p)) - 1 ? 0 : i + 1]);
    }
    return res;
}

enum { _OUT, _ON, _IN };

int containsHullPoint(const Polygon &Q, const Point &p) {
    // Brute Force : O(|Q|)
    bool in = false;
    for (int i = 0; i < Q.size(); i++) {
        Point a = Q[i] - p, b = Q[(i + 1) % Q.size()] - p;
        if (a.y > b.y) std::swap(a, b);
        if (a.y <= 0 && 0 < b.y && cross(a, b) < 0) in = !in;
        if (cross(a, b) == 0 && dot(a, b) <= 0) return _ON;
    }
    return in ? _IN : _OUT;
}

Polygon minkowskiSum(const Polygon &P, const Polygon &Q) {
    std::vector<Segment> e1(P.size()), e2(Q.size()), ed(P.size() + Q.size());
    const auto cmp = [](const Segment &u, const Segment &v) {
        return (u.b - u.a).arg_cmp(v.b - v.a);
    };
    for (int i = 0; i < int(P.size()); i++)
        e1[i] = {P[i], P[(i + 1) % P.size()]};
    for (int i = 0; i < int(Q.size()); i++)
        e2[i] = {Q[i], Q[(i + 1) % Q.size()]};
    std::rotate(begin(e1), std::min_element(begin(e1), end(e1), cmp), end(e1));
    std::rotate(begin(e2), std::min_element(begin(e2), end(e2), cmp), end(e2));
    std::merge(begin(e1), end(e1), begin(e2), end(e2), begin(ed), cmp);
    const auto check = [](const Points &res, const Point &u) {
        const auto back1 = res.back(), back2 = *prev(end(res), 2);
        return equal(cross(back1 - back2, u - back2), eps) and
               dot(back1 - back2, u - back1) >= -eps;
    };
    auto u = e1[0].a + e2[0].a;
    Points res{u};
    res.reserve(P.size() + Q.size());
    for (const auto &v : ed) {
        u = u + v.b - v.a;
        while (int(size(res)) >= 2 and check(res, u)) res.pop_back();
        res.emplace_back(u);
    }
    if (res.size() and check(res, res[0])) res.pop_back();
    return res;
}

// -1 : on, 0 : out, 1 : in
// O(log(n))
int containsHullPointFast(const Polygon &p, const Point &a) {
    // Binary Search O(log|P|)
    if (p.size() == 1) return a == p[0] ? -1 : 0;
    if (p.size() == 2) return intersect(Segment(p[0], p[1]), a);
    if (a == p[0]) return -1;
    if ((p[1] - p[0]).toleft(a - p[0]) == -1 ||
        (p.back() - p[0]).toleft(a - p[0]) == 1)
        return 0;
    const auto cmp = [&](const Point &u, const Point &v) {
        return (u - p[0]).toleft(v - p[0]) == 1;
    };
    const size_t i = lower_bound(p.begin() + 1, p.end(), a, cmp) - p.begin();
    if (i == 1) return intersect(Segment(p[0], p[i]), a) ? -1 : 0;
    if (i == p.size() - 1 && intersect(Segment(p[0], p[i]), a)) return -1;
    if (intersect(Segment(p[i - 1], p[i]), a)) return -1;
    return (p[i] - p[i - 1]).toleft(a - p[i - 1]) > 0;
}

Points halfplaneIntersection(std::vector<Line> L, const T inf = 1e9) {
    // left half plane
    Point box[4] = {Point(inf, inf), Point(-inf, inf), Point(-inf, -inf),
                    Point(inf, -inf)};
    for (int i = 0; i < 4; i++) {
        L.emplace_back(box[i], box[(i + 1) % 4]);
    }
    std::sort(begin(L), end(L), [](const Line &l, const Line &r) {
        return (l.b - l.a).arg_cmp(r.b - r.a);
    });
    std::deque<Line> dq;
    int len = 0;
    auto check = [](const Line &a, const Line &b, const Line &c) {
        return a.toleft(crossPoint(b, c)) == -1;
    };
    for (int i = 0; i < (int)L.size(); i++) {
        while (dq.size() > 1 and check(L[i], *(end(dq) - 2), *(end(dq) - 1)))
            dq.pop_back();
        while (dq.size() > 1 and check(L[i], dq[0], dq[1])) dq.pop_front();
        // dump(L[i], si(dq));

        if (dq.size() and
            equal(cross(L[i].b - L[i].a, dq.back().b - dq.back().a), 0)) {
            if (dot(L[i].b - L[i].a, dq.back().b - dq.back().a) < eps)
                return {};
            if (L[i].toleft(dq.back().a) == -1)
                dq.pop_back();
            else
                continue;
        }
        dq.emplace_back(L[i]);
    }

    while (dq.size() > 2 and check(dq[0], *(end(dq) - 2), *(end(dq) - 1)))
        dq.pop_back();
    while (dq.size() > 2 and check(dq.back(), dq[0], dq[1])) dq.pop_front();
    if ((int)size(dq) < 3) return {};
    Polygon ret(dq.size());
    for (int i = 0; i < (int)dq.size(); i++)
        ret[i] = crossPoint(dq[i], dq[(i + 1) % dq.size()]);

    return ret;
}
} 
Back to top page