Geometry

昔作ったやつが残っていたのでとりあえず貼っておく 要整備

Spec

  • Convex_Hull
    • 凸包

Code

#include <algorithm>
#include <cmath>
#include <tuple>
#include <vector>
using namespace std;

using ld = long double;

const ld EPS = 1e-8;
inline bool eq(ld a, ld b) { return abs(a - b) < EPS; }
const ld PI = acos(-1);

namespace Geometory {
  struct Point {
    ld x, y;
    Point(ld x = 0, ld y = 0) : x(x), y(y) {}
    Point operator+(const Point& b) const { return Point(x + b.x, y + b.y); }
    Point operator-(const Point& b) const { return Point(x - b.x, y - b.y); }
    Point operator*(const ld b) const { return Point(x * b, y * b); }
    Point operator/(const ld b) const { return Point(x / b, y / b); }
    bool operator<(const Point& b) const {
      if (x != b.x)
        return x < b.x;
      else
        return y < b.y;
    }
    bool operator==(const Point& b) const { return eq(x, b.x) && eq(y, b.y); }
    ld norm() const { return x * x + y * y; }
    ld abs() const { return sqrt(norm()); }
    ld arg() const { return atan2(x, y); }
    Point rotate(const ld theta) const {
      ld co = cos(theta);
      ld si = sin(theta);
      return Point(co * x - si * y, si * x + y * co);
    }
    Point rotate90() const { return Point(-y, x); }
  };

  ld dot(const Point& a, const Point& b) { return a.x * b.x + a.y * b.y; }
  ld cross(const Point& a, const Point b) { return a.x * b.y - a.y * b.x; }

  struct Line {
    Point from, to;
    Line(Point from = Point(), Point to = Point()) : from(from), to(to) {}
  };

  struct Segment {
    Point from, to;
    Segment(Point from = Point(), Point to = Point()) : from(from), to(to) {}
  };

  bool is_orthogonal(const Line& la, const Line& lb) {
    return eq(0.0, dot(la.from - la.to, lb.from - lb.from));
  }
  bool is_parallel(const Line& la, const Line& lb) {
    return eq(0.0, cross(la.from - la.to, lb.from - lb.from));
  }
  bool is_Point_on(const Line& l, const Point& p) {
    return eq(0.0, cross(l.to - l.from, p - l.from));
  }
  bool is_Point_on(const Segment& s, const Point& p) {
    return (s.from - p).abs() + (p - s.to).abs() < (s.from - s.to).abs() + EPS;
  }
  ld distance(const Line& l, const Point& p) {
    return abs(cross(l.to - l.from, p - l.from)) / (l.to - l.from).abs();
  }
  ld distance(const Segment& s, const Point& p) {
    if (dot(s.to - s.from, p - s.from) < EPS) return (p - s.from).abs();
    if (dot(s.from - s.to, p - s.to) < EPS) return (p - s.to).abs();
    return abs(cross(s.to - s.from, p - s.from)) / (s.to - s.from).abs();
  }
  ld is_intersected(const Segment& a, const Segment& b) {
    return (cross(a.to - a.from, b.from - a.from) *
                cross(a.to - a.from, b.to - a.from) <
            EPS) &&
           (cross(b.to - b.from, a.from - b.from) *
                cross(b.to - b.from, a.to - b.from) <
            EPS);
  }

  ld is_intersected(const Segment& s, const Line& l) {
    // line -> ax + by + c = 0
    ld a = l.to.y - l.from.y;
    ld b = l.from.x - l.to.x;
    ld c = -a * l.from.x - b * l.from.y;
    ld t1 = a * s.from.x + b * s.from.y + c;
    ld t2 = a * s.to.x + b * s.to.y + c;
    return t1 * t2 <= 0;
  }

  Point intersection_point(const Segment& a, const Segment& b) {
    Point bp = b.to - b.from;
    ld d1 = abs(cross(bp, a.from - b.from));
    ld d2 = abs(cross(bp, a.to - b.from));
    ld t = d1 / (d1 + d2);
    return a.from + (a.to - a.from) * t;
  }

  Point intersection_point(const Line& a, const Line& b) {
    Point ap = a.to - a.from;
    Point bp = b.to - b.from;
    return a.from + ap * cross(bp, b.from - a.from) / cross(bp, ap);
  }
  // counterclockwise
  int ccw(const Point& a, const Point& b, const Point& c) {
    Point ba = b - a;
    Point ca = c - a;
    if (cross(ba, ca) > EPS) return 1;   // a - b --/ c
    if (cross(ba, ca) < EPS) return -1;  // a - b --| c
    if (dot(ba, ca) < 0) return 2;       // b - a - c
    if (b.norm() < c.norm()) return -2;  // a - b - c
    return 0;                            // a -- c -- b
  }

  vector<Point> Convex_Hull(vector<Point>& p) {
    int n = p.size();
    int k = 0;
    if (n >= 3) {
      sort(p.begin(), p.end());
      vector<Point> 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;
    } else {
      return p;
    }
  }
};