競技プログラミング用 C++ ライブラリ
geometry/linear.hpp · GitHub で見る
共通ページ
#include "lib/geometry/linear.hpp"
using namespace geometry;
Segment<std::int64_t> s{IPoint{0, 0}, IPoint{4, 0}};
Segment<std::int64_t> t{IPoint{2, -1}, IPoint{2, 1}};
bool hit = intersects(s, t); // true
auto points = intersection(s, t); // (2,0) の1点
Real d = distance(s, IPoint{5, 1}); // sqrt(2)
Line<T>{a,b} は a・b を通る無限直線、Segment<T>{a,b} は両端を含む線分です。a・b は Point<T> です。引数同士の座標型は揃えて使います。
始点と終点が同じものも点として扱います。整数の交差判定は128 bitの整数で行い、交点・射影・距離は Real または FPoint で返します。
| 操作 | 内容・返り値 | 計算量 |
|---|---|---|
Line<T>{a,b}, Segment<T>{a,b}
|
直線・閉線分の構築。端点は .a,.b
|
\(O(1)\) |
parallel(l,m,eps = epsilon) |
方向ベクトルの外積が0か | \(O(1)\) |
orthogonal(l,m,eps = epsilon) |
方向ベクトルの内積が0か | \(O(1)\) |
on_line(l,p,eps = epsilon) |
p が直線上か | \(O(1)\) |
on_segment(s,p,eps = epsilon) |
p が線分上か。端点も含む | \(O(1)\) |
intersects(a,b,eps = epsilon) |
直線・線分の任意の組で共通点があるか | \(O(1)\) |
projection(l,p) |
p の直線への射影。退化直線ならその点 | \(O(1)\) |
reflection(l,p) |
直線について p と対称な点。退化直線ならその点を中心に点対称 | \(O(1)\) |
intersection(l,m,eps = epsilon) |
直線同士の唯一の交点を optional<FPoint> で返す。平行・一致直線は nullopt
|
\(O(1)\) |
intersection(s,t,eps = epsilon) |
線分同士の共通部分を vector<FPoint> で返す。0点・1点・重なりの両端2点 |
\(O(1)\) |
intersection(l,s,eps = epsilon), intersection(s,l,eps)
|
直線と線分の共通部分。重なる場合は線分の両端 | \(O(1)\) |
distance(a,b) |
点・直線・線分の任意の組の最短距離。対称な引数順も使用可 | \(O(1)\) |
distance_squared(a,b) |
同じ組の距離二乗。点同士は wide_t<T>、それ以外は Real
|
\(O(1)\) |
perpendicular_bisector(a,b) |
垂直二等分線を optional<Line<Real>> で返す。同一点なら nullopt
|
\(O(1)\) |
線分同士の重なりの両端は辞書順です。直線と線分の重なりは線分の a・b の順です。退化した入力でも共通部分が1点なら、その点を返します。
parallel・orthogonal は方向ベクトルに対する判定なので、零ベクトルを含む場合は両方 true です。幾何学的な交差判定には intersects を使います。
整数の場合は EPS を無視します。実数の交差判定では外積・内積に対する絶対 EPS を使い、線分の座標範囲判定には座標単位の EPS を使います。 直線同士・直線と線分・線分同士の距離では、必要なら第3引数に EPS を渡せます。点への距離・射影では EPS で位置を動かしません。 128 bitの中間値と実数精度については点の説明の前提に従います。実数の交点を厳密な有理数として返す関数ではありません。
全ての操作の時間・追加空間は \(O(1)\) です。
#ifndef GEOMETRY_LINEAR_HPP
#define GEOMETRY_LINEAR_HPP
#include "point.hpp"
#include <algorithm>
#include <array>
#include <vector>
namespace geometry {
template<class T> struct Line { Point<T> a, b; };
template<class T> struct Segment { Point<T> a, b; };
template<class T>
constexpr bool parallel(Line<T> l, Line<T> m, Real eps = epsilon) {
using W = wide_t<T>;
return sign((W(l.b.x) - l.a.x) * (W(m.b.y) - m.a.y) - (W(l.b.y) - l.a.y) * (W(m.b.x) - m.a.x), eps) == 0;
}
template<class T>
constexpr bool orthogonal(Line<T> l, Line<T> m, Real eps = epsilon) {
using W = wide_t<T>;
return sign((W(l.b.x) - l.a.x) * (W(m.b.x) - m.a.x) + (W(l.b.y) - l.a.y) * (W(m.b.y) - m.a.y), eps) == 0;
}
template<class T>
constexpr bool on_line(Line<T> l, Point<T> p, Real eps = epsilon) {
return l.a == l.b ? almost_equal(l.a, p, eps) : orientation(l.a, l.b, p, eps) == 0;
}
template<class T>
constexpr bool on_segment(Segment<T> s, Point<T> p, Real eps = epsilon) {
if (orientation(s.a, s.b, p, eps)) return false;
if constexpr (integer<T>)
return std::min(s.a.x, s.b.x) <= p.x && p.x <= std::max(s.a.x, s.b.x)
&& std::min(s.a.y, s.b.y) <= p.y && p.y <= std::max(s.a.y, s.b.y);
else return std::min(s.a.x, s.b.x) - eps <= p.x && p.x <= std::max(s.a.x, s.b.x) + eps
&& std::min(s.a.y, s.b.y) - eps <= p.y && p.y <= std::max(s.a.y, s.b.y) + eps;
}
template<class T>
constexpr bool intersects(Segment<T> s, Segment<T> t, Real eps = epsilon) {
int a = orientation(s.a, s.b, t.a, eps), b = orientation(s.a, s.b, t.b, eps);
int c = orientation(t.a, t.b, s.a, eps), d = orientation(t.a, t.b, s.b, eps);
return (!a && on_segment(s, t.a, eps)) || (!b && on_segment(s, t.b, eps))
|| (!c && on_segment(t, s.a, eps)) || (!d && on_segment(t, s.b, eps)) || (a * b < 0 && c * d < 0);
}
template<class T>
constexpr bool intersects(Line<T> l, Segment<T> s, Real eps = epsilon) {
if (l.a == l.b) return on_segment(s, l.a, eps);
return orientation(l.a, l.b, s.a, eps) * orientation(l.a, l.b, s.b, eps) <= 0;
}
template<class T>
constexpr bool intersects(Segment<T> s, Line<T> l, Real eps = epsilon) { return intersects(l, s, eps); }
template<class T>
constexpr bool intersects(Line<T> l, Line<T> m, Real eps = epsilon) {
if (l.a == l.b) return on_line(m, l.a, eps);
if (m.a == m.b) return on_line(l, m.a, eps);
return !parallel(l, m, eps) || on_line(l, m.a, eps);
}
template<class T>
FPoint projection(Line<T> l, Point<T> p) {
using W = wide_t<T>;
W x = W(l.b.x) - l.a.x, y = W(l.b.y) - l.a.y, n = x * x + y * y;
if (!n) return to_real(l.a);
Real t = Real(x * (W(p.x) - l.a.x) + y * (W(p.y) - l.a.y)) / Real(n);
return {Real(l.a.x) + Real(x) * t, Real(l.a.y) + Real(y) * t};
}
template<class T>
FPoint reflection(Line<T> l, Point<T> p) { return projection(l, p) * Real(2) - to_real(p); }
template<class T>
std::optional<FPoint> intersection(Line<T> l, Line<T> m, Real eps = epsilon) {
if (l.a == l.b) return on_line(m, l.a, eps) ? std::optional(to_real(l.a)) : std::nullopt;
if (m.a == m.b) return on_line(l, m.a, eps) ? std::optional(to_real(m.a)) : std::nullopt;
using W = wide_t<T>;
W x = W(l.b.x) - l.a.x, y = W(l.b.y) - l.a.y, u = W(m.b.x) - m.a.x, v = W(m.b.y) - m.a.y;
W d = x * v - y * u;
if (!sign(d, eps)) return std::nullopt;
Real t = Real((W(m.a.x) - l.a.x) * v - (W(m.a.y) - l.a.y) * u) / Real(d);
return FPoint{Real(l.a.x) + Real(x) * t, Real(l.a.y) + Real(y) * t};
}
template<class T>
std::vector<FPoint> intersection(Segment<T> s, Segment<T> t, Real eps = epsilon) {
if (!intersects(s, t, eps)) return {};
if (auto p = intersection(Line<T>{s.a, s.b}, Line<T>{t.a, t.b}, eps)) return {*p};
std::array<Point<T>, 4> candidates{s.a, s.b, t.a, t.b};
std::sort(candidates.begin(), candidates.end());
std::vector<FPoint> result;
std::optional<Point<T>> first, last;
for (auto p : candidates) if (on_segment(s, p, eps) && on_segment(t, p, eps)) {
if (!first) first = p;
last = p;
}
if (first) {
result.push_back(to_real(*first));
if (!almost_equal(*first, *last, eps)) result.push_back(to_real(*last));
}
return result;
}
template<class T>
std::vector<FPoint> intersection(Line<T> l, Segment<T> s, Real eps = epsilon) {
if (!intersects(l, s, eps)) return {};
if (auto p = intersection(l, Line<T>{s.a, s.b}, eps)) return {*p};
if (almost_equal(s.a, s.b, eps)) return {to_real(s.a)};
return {to_real(s.a), to_real(s.b)};
}
template<class T>
std::vector<FPoint> intersection(Segment<T> s, Line<T> l, Real eps = epsilon) { return intersection(l, s, eps); }
template<class T>
Real distance_squared(Line<T> l, Point<T> p) {
if (l.a == l.b) return Real(distance_squared(l.a, p));
Real c = Real(cross(l.a, l.b, p));
return c * c / Real(distance_squared(l.a, l.b));
}
template<class T>
Real distance_squared(Segment<T> s, Point<T> p) {
using W = wide_t<T>;
W x = W(s.b.x) - s.a.x, y = W(s.b.y) - s.a.y;
W n = x * x + y * y, d = (W(p.x) - s.a.x) * x + (W(p.y) - s.a.y) * y;
if (d <= 0) return Real(distance_squared(s.a, p));
if (d >= n) return Real(distance_squared(s.b, p));
Real c = Real(cross(s.a, s.b, p));
return c * c / Real(n);
}
template<class T> Real distance(Line<T> l, Point<T> p) { return std::sqrt(distance_squared(l, p)); }
template<class T> Real distance(Point<T> p, Line<T> l) { return distance(l, p); }
template<class T> Real distance(Segment<T> s, Point<T> p) { return std::sqrt(distance_squared(s, p)); }
template<class T> Real distance(Point<T> p, Segment<T> s) { return distance(s, p); }
template<class T> Real distance_squared(Point<T> p, Line<T> l) { return distance_squared(l, p); }
template<class T> Real distance_squared(Point<T> p, Segment<T> s) { return distance_squared(s, p); }
template<class T>
Real distance_squared(Line<T> l, Line<T> m, Real eps = epsilon) {
if (intersects(l, m, eps)) return 0;
return l.a == l.b ? distance_squared(m, l.a) : distance_squared(l, m.a);
}
template<class T>
Real distance_squared(Line<T> l, Segment<T> s, Real eps = epsilon) {
if (intersects(l, s, eps)) return 0;
return l.a == l.b ? distance_squared(s, l.a) : std::min(distance_squared(l, s.a), distance_squared(l, s.b));
}
template<class T>
Real distance_squared(Segment<T> s, Line<T> l, Real eps = epsilon) { return distance_squared(l, s, eps); }
template<class T>
Real distance_squared(Segment<T> s, Segment<T> t, Real eps = epsilon) {
if (intersects(s, t, eps)) return 0;
return std::min({distance_squared(s, t.a), distance_squared(s, t.b), distance_squared(t, s.a), distance_squared(t, s.b)});
}
template<class T> Real distance(Line<T> l, Line<T> m, Real eps = epsilon) { return std::sqrt(distance_squared(l, m, eps)); }
template<class T> Real distance(Line<T> l, Segment<T> s, Real eps = epsilon) { return std::sqrt(distance_squared(l, s, eps)); }
template<class T> Real distance(Segment<T> s, Line<T> l, Real eps = epsilon) { return distance(l, s, eps); }
template<class T> Real distance(Segment<T> s, Segment<T> t, Real eps = epsilon) { return std::sqrt(distance_squared(s, t, eps)); }
template<class T>
std::optional<Line<Real>> perpendicular_bisector(Point<T> a, Point<T> b) {
if (a == b) return std::nullopt;
using W = wide_t<T>;
FPoint mid{Real(a.x) / 2 + Real(b.x) / 2, Real(a.y) / 2 + Real(b.y) / 2};
FPoint d{Real(W(b.y) - a.y), Real(W(a.x) - b.x)};
return Line<Real>{mid, mid + d};
}
}
#endif
#line 1 "geometry/linear.hpp"
#line 1 "geometry/point.hpp"
#line 1 "components/radix_sort.hpp"
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <utility>
#include <vector>
template <int Bits, class T, class Key>
void stable_radix_sort(std::vector<T> &values, Key &&key) {
static_assert(1 <= Bits && Bits <= 16);
constexpr unsigned buckets = 1U << Bits, mask = buckets - 1;
using K = std::remove_cvref_t<decltype(key(std::declval<const T &>()))>;
static_assert(std::is_integral_v<K> && std::is_unsigned_v<K> && sizeof(K) <= sizeof(std::uint64_t));
if (values.size() < 2) return;
if (values.size() < 256) {
std::stable_sort(values.begin(), values.end(), [&](const T &a, const T &b) { return key(a) < key(b); });
return;
}
std::uint64_t first = key(values.front()), previous = first, varying = 0;
bool sorted = true;
for (std::size_t i = 1; i < values.size(); ++i) {
std::uint64_t current = key(values[i]);
varying |= first ^ current;
sorted &= previous <= current;
previous = current;
}
if (sorted) return;
std::vector<T> scratch(values.size());
using Counts = std::conditional_t<(Bits <= 11), std::array<std::size_t, buckets>, std::vector<std::size_t>>;
Counts count = [] {
if constexpr (Bits <= 11) return Counts{};
else return Counts(buckets);
}();
for (int shift = 0; shift < 64; shift += Bits) {
if (!((varying >> shift) & mask)) continue;
std::fill(count.begin(), count.end(), 0);
for (const auto &value : values) ++count[(static_cast<std::uint64_t>(key(value)) >> shift) & mask];
std::size_t sum = 0;
for (auto &x : count) {
auto n = x;
x = sum, sum += n;
}
for (auto &&value : values) scratch[count[(static_cast<std::uint64_t>(key(value)) >> shift) & mask]++] = std::move(value);
values.swap(scratch);
}
}
template <class T, class Key>
void stable_radix_sort(std::vector<T> &values, Key key) {
stable_radix_sort<8>(values, std::move(key));
}
namespace radix_sort_detail {
template <int Bits = 8, class T, class Key>
void sort_by_key(std::vector<T> &values, Key key) {
using K = std::remove_cvref_t<decltype(key(std::declval<const T &>()))>;
if constexpr (std::is_integral_v<K> && !std::is_same_v<K, bool> && sizeof(K) <= 8 && std::is_default_constructible_v<T>) {
using U = std::make_unsigned_t<K>;
constexpr U sign = std::is_signed_v<K> ? U(1) << (sizeof(K) * 8 - 1) : U(0);
stable_radix_sort<Bits>(values, [&](const T &value) { return U(U(key(value)) ^ sign); });
} else std::sort(values.begin(), values.end(), [&](const T &a, const T &b) { return key(a) < key(b); });
}
}
#line 5 "geometry/point.hpp"
#include <cmath>
#line 7 "geometry/point.hpp"
#include <istream>
#include <numbers>
#include <optional>
#include <ostream>
#line 12 "geometry/point.hpp"
namespace geometry {
using Real = long double;
inline constexpr Real epsilon = 1e-12L;
inline constexpr Real pi = std::numbers::pi_v<Real>;
enum class Location { outside = -1, boundary = 0, inside = 1 };
template<class T>
inline constexpr bool integer = std::is_integral_v<T> || std::is_same_v<T, __int128_t> || std::is_same_v<T, __uint128_t>;
template<class T>
using wide_t = std::conditional_t<integer<T>, __int128_t, Real>;
template<class T>
struct Point {
static_assert((std::is_arithmetic_v<T> && std::is_signed_v<T>) || std::is_same_v<T, __int128_t>);
T x{}, y{};
constexpr Point() = default;
constexpr Point(T x, T y) : x(x), y(y) {}
template<class U> explicit constexpr Point(const Point<U>& p) : x(static_cast<T>(p.x)), y(static_cast<T>(p.y)) {}
constexpr bool operator==(const Point&) const = default;
constexpr bool operator<(const Point& p) const { return x < p.x || (x == p.x && y < p.y); }
constexpr Point operator-() const { return {-x, -y}; }
constexpr Point& operator+=(const Point& p) { x += p.x; y += p.y; return *this; }
constexpr Point& operator-=(const Point& p) { x -= p.x; y -= p.y; return *this; }
constexpr Point& operator*=(T c) { x *= c; y *= c; return *this; }
constexpr Point& operator/=(T c) { x /= c; y /= c; return *this; }
friend constexpr Point operator+(Point p, const Point& q) { p += q; return p; }
friend constexpr Point operator-(Point p, const Point& q) { p -= q; return p; }
friend constexpr Point operator*(Point p, T c) { p *= c; return p; }
friend constexpr Point operator*(T c, Point p) { p *= c; return p; }
friend constexpr Point operator/(Point p, T c) { p /= c; return p; }
friend std::istream& operator>>(std::istream& in, Point& p) { return in >> p.x >> p.y; }
friend std::ostream& operator<<(std::ostream& out, const Point& p) { return out << p.x << ' ' << p.y; }
};
using IPoint = Point<std::int64_t>;
using FPoint = Point<Real>;
template<class T>
constexpr int sign(T value, Real eps = epsilon) {
if constexpr (integer<T>) return (value > 0) - (value < 0);
else return (value > eps) - (value < -eps);
}
template<class T>
constexpr wide_t<T> dot(Point<T> a, Point<T> b) {
return wide_t<T>(a.x) * b.x + wide_t<T>(a.y) * b.y;
}
template<class T>
constexpr wide_t<T> cross(Point<T> a, Point<T> b) {
return wide_t<T>(a.x) * b.y - wide_t<T>(a.y) * b.x;
}
template<class T>
constexpr wide_t<T> cross(Point<T> a, Point<T> b, Point<T> c) {
using W = wide_t<T>;
return (W(b.x) - a.x) * (W(c.y) - a.y) - (W(b.y) - a.y) * (W(c.x) - a.x);
}
template<class T>
constexpr wide_t<T> norm2(Point<T> p) { return dot(p, p); }
template<class T>
constexpr wide_t<T> distance_squared(Point<T> a, Point<T> b) {
using W = wide_t<T>;
W x = W(a.x) - b.x, y = W(a.y) - b.y;
return x * x + y * y;
}
template<class T>
constexpr int orientation(Point<T> a, Point<T> b, Point<T> c, Real eps = epsilon) { return sign(cross(a, b, c), eps); }
template<class T>
constexpr int ccw(Point<T> a, Point<T> b, Point<T> c, Real eps = epsilon) {
if (int turn = orientation(a, b, c, eps)) return turn;
using W = wide_t<T>;
W x = W(b.x) - a.x, y = W(b.y) - a.y, u = W(c.x) - a.x, v = W(c.y) - a.y;
if (sign(x * u + y * v, eps) < 0) return 2;
if (sign(u * u + v * v - x * x - y * y, eps) > 0) return -2;
return 0;
}
template<class T>
constexpr FPoint to_real(Point<T> p) { return FPoint(p); }
template<class T>
Real length(Point<T> p) { return std::hypot(Real(p.x), Real(p.y)); }
template<class T>
Real distance(Point<T> a, Point<T> b) {
return std::hypot(Real(wide_t<T>(a.x) - b.x), Real(wide_t<T>(a.y) - b.y));
}
template<class T>
constexpr bool almost_equal(Point<T> a, Point<T> b, Real eps = epsilon) {
if constexpr (integer<T>) return a == b;
else return std::abs(Real(a.x) - b.x) <= eps && std::abs(Real(a.y) - b.y) <= eps;
}
template<class T>
constexpr Point<T> rotate90(Point<T> p) { return {-p.y, p.x}; }
template<class T>
Real argument(Point<T> p) { return std::atan2(Real(p.y), Real(p.x)); }
template<class T>
Real angle(Point<T> a, Point<T> b) { return std::atan2(Real(cross(a, b)), Real(dot(a, b))); }
template<class T>
FPoint rotate(Point<T> p, Real theta) {
Real c = std::cos(theta), s = std::sin(theta);
return {Real(p.x) * c - Real(p.y) * s, Real(p.x) * s + Real(p.y) * c};
}
template<class T>
std::optional<FPoint> unit(Point<T> p) {
Real n = length(p);
if (!n) return std::nullopt;
return to_real(p) / n;
}
template<class T>
struct PolarLess {
bool operator()(Point<T> a, Point<T> b) const {
if (a == Point<T>{} || b == Point<T>{}) return a == Point<T>{} && b != Point<T>{};
auto half = [](Point<T> p) { return p.y < 0 || (p.y == 0 && p.x < 0); };
if (half(a) != half(b)) return half(a) < half(b);
if constexpr (integer<T> && sizeof(T) <= 4) {
auto c = std::int64_t(a.x) * b.y - std::int64_t(a.y) * b.x;
if (c) return c > 0;
auto norm = [](Point<T> p) { return std::uint64_t(std::int64_t(p.x) * p.x) + std::uint64_t(std::int64_t(p.y) * p.y); };
return norm(a) < norm(b);
} else {
if (auto c = cross(a, b); c != 0) return c > 0;
return norm2(a) < norm2(b);
}
}
};
template<class T>
void polar_sort(std::vector<Point<T>> &points) {
if constexpr (integer<T> && sizeof(T) <= 4) {
if (points.size() >= 256) {
struct Entry { std::uint64_t key; Point<T> point; };
std::vector<Entry> order;
order.reserve(points.size());
constexpr std::uint64_t scale = (std::uint64_t(1) << 61) - 1;
for (auto p : points) {
std::int64_t x = p.x, y = p.y;
std::uint64_t a = x < 0 ? -x : x, b = y < 0 ? -y : y;
unsigned quadrant = y < 0 ? (x < 0 ? 2 : 3) : (x < 0 ? 1 : 0);
unsigned octant = quadrant * 2 + ((a < b) ^ (quadrant & 1));
std::uint64_t ratio = a || b ? std::min(scale, std::uint64_t(double(std::min(a, b)) / double(std::max(a, b)) * double(scale))) : 0;
if (octant & 1) ratio = scale - ratio;
order.push_back({(std::uint64_t(octant) << 61) | ratio, p});
}
stable_radix_sort<11>(order, [](const Entry &entry) { return entry.key; });
for (std::size_t first = 0; first < order.size();) {
std::size_t last = first + 1;
while (last < order.size() && order[last].key == order[first].key) ++last;
auto less = [](const Entry &a, const Entry &b) { return PolarLess<T>{}(a.point, b.point); };
if (last - first <= 8 || !std::is_sorted(order.begin() + first, order.begin() + last, less))
std::sort(order.begin() + first, order.begin() + last, less);
first = last;
}
for (std::size_t i = 0; i < points.size(); ++i) points[i] = order[i].point;
return;
}
}
std::sort(points.begin(), points.end(), PolarLess<T>{});
}
}
#line 8 "geometry/linear.hpp"
namespace geometry {
template<class T> struct Line { Point<T> a, b; };
template<class T> struct Segment { Point<T> a, b; };
template<class T>
constexpr bool parallel(Line<T> l, Line<T> m, Real eps = epsilon) {
using W = wide_t<T>;
return sign((W(l.b.x) - l.a.x) * (W(m.b.y) - m.a.y) - (W(l.b.y) - l.a.y) * (W(m.b.x) - m.a.x), eps) == 0;
}
template<class T>
constexpr bool orthogonal(Line<T> l, Line<T> m, Real eps = epsilon) {
using W = wide_t<T>;
return sign((W(l.b.x) - l.a.x) * (W(m.b.x) - m.a.x) + (W(l.b.y) - l.a.y) * (W(m.b.y) - m.a.y), eps) == 0;
}
template<class T>
constexpr bool on_line(Line<T> l, Point<T> p, Real eps = epsilon) {
return l.a == l.b ? almost_equal(l.a, p, eps) : orientation(l.a, l.b, p, eps) == 0;
}
template<class T>
constexpr bool on_segment(Segment<T> s, Point<T> p, Real eps = epsilon) {
if (orientation(s.a, s.b, p, eps)) return false;
if constexpr (integer<T>)
return std::min(s.a.x, s.b.x) <= p.x && p.x <= std::max(s.a.x, s.b.x)
&& std::min(s.a.y, s.b.y) <= p.y && p.y <= std::max(s.a.y, s.b.y);
else return std::min(s.a.x, s.b.x) - eps <= p.x && p.x <= std::max(s.a.x, s.b.x) + eps
&& std::min(s.a.y, s.b.y) - eps <= p.y && p.y <= std::max(s.a.y, s.b.y) + eps;
}
template<class T>
constexpr bool intersects(Segment<T> s, Segment<T> t, Real eps = epsilon) {
int a = orientation(s.a, s.b, t.a, eps), b = orientation(s.a, s.b, t.b, eps);
int c = orientation(t.a, t.b, s.a, eps), d = orientation(t.a, t.b, s.b, eps);
return (!a && on_segment(s, t.a, eps)) || (!b && on_segment(s, t.b, eps))
|| (!c && on_segment(t, s.a, eps)) || (!d && on_segment(t, s.b, eps)) || (a * b < 0 && c * d < 0);
}
template<class T>
constexpr bool intersects(Line<T> l, Segment<T> s, Real eps = epsilon) {
if (l.a == l.b) return on_segment(s, l.a, eps);
return orientation(l.a, l.b, s.a, eps) * orientation(l.a, l.b, s.b, eps) <= 0;
}
template<class T>
constexpr bool intersects(Segment<T> s, Line<T> l, Real eps = epsilon) { return intersects(l, s, eps); }
template<class T>
constexpr bool intersects(Line<T> l, Line<T> m, Real eps = epsilon) {
if (l.a == l.b) return on_line(m, l.a, eps);
if (m.a == m.b) return on_line(l, m.a, eps);
return !parallel(l, m, eps) || on_line(l, m.a, eps);
}
template<class T>
FPoint projection(Line<T> l, Point<T> p) {
using W = wide_t<T>;
W x = W(l.b.x) - l.a.x, y = W(l.b.y) - l.a.y, n = x * x + y * y;
if (!n) return to_real(l.a);
Real t = Real(x * (W(p.x) - l.a.x) + y * (W(p.y) - l.a.y)) / Real(n);
return {Real(l.a.x) + Real(x) * t, Real(l.a.y) + Real(y) * t};
}
template<class T>
FPoint reflection(Line<T> l, Point<T> p) { return projection(l, p) * Real(2) - to_real(p); }
template<class T>
std::optional<FPoint> intersection(Line<T> l, Line<T> m, Real eps = epsilon) {
if (l.a == l.b) return on_line(m, l.a, eps) ? std::optional(to_real(l.a)) : std::nullopt;
if (m.a == m.b) return on_line(l, m.a, eps) ? std::optional(to_real(m.a)) : std::nullopt;
using W = wide_t<T>;
W x = W(l.b.x) - l.a.x, y = W(l.b.y) - l.a.y, u = W(m.b.x) - m.a.x, v = W(m.b.y) - m.a.y;
W d = x * v - y * u;
if (!sign(d, eps)) return std::nullopt;
Real t = Real((W(m.a.x) - l.a.x) * v - (W(m.a.y) - l.a.y) * u) / Real(d);
return FPoint{Real(l.a.x) + Real(x) * t, Real(l.a.y) + Real(y) * t};
}
template<class T>
std::vector<FPoint> intersection(Segment<T> s, Segment<T> t, Real eps = epsilon) {
if (!intersects(s, t, eps)) return {};
if (auto p = intersection(Line<T>{s.a, s.b}, Line<T>{t.a, t.b}, eps)) return {*p};
std::array<Point<T>, 4> candidates{s.a, s.b, t.a, t.b};
std::sort(candidates.begin(), candidates.end());
std::vector<FPoint> result;
std::optional<Point<T>> first, last;
for (auto p : candidates) if (on_segment(s, p, eps) && on_segment(t, p, eps)) {
if (!first) first = p;
last = p;
}
if (first) {
result.push_back(to_real(*first));
if (!almost_equal(*first, *last, eps)) result.push_back(to_real(*last));
}
return result;
}
template<class T>
std::vector<FPoint> intersection(Line<T> l, Segment<T> s, Real eps = epsilon) {
if (!intersects(l, s, eps)) return {};
if (auto p = intersection(l, Line<T>{s.a, s.b}, eps)) return {*p};
if (almost_equal(s.a, s.b, eps)) return {to_real(s.a)};
return {to_real(s.a), to_real(s.b)};
}
template<class T>
std::vector<FPoint> intersection(Segment<T> s, Line<T> l, Real eps = epsilon) { return intersection(l, s, eps); }
template<class T>
Real distance_squared(Line<T> l, Point<T> p) {
if (l.a == l.b) return Real(distance_squared(l.a, p));
Real c = Real(cross(l.a, l.b, p));
return c * c / Real(distance_squared(l.a, l.b));
}
template<class T>
Real distance_squared(Segment<T> s, Point<T> p) {
using W = wide_t<T>;
W x = W(s.b.x) - s.a.x, y = W(s.b.y) - s.a.y;
W n = x * x + y * y, d = (W(p.x) - s.a.x) * x + (W(p.y) - s.a.y) * y;
if (d <= 0) return Real(distance_squared(s.a, p));
if (d >= n) return Real(distance_squared(s.b, p));
Real c = Real(cross(s.a, s.b, p));
return c * c / Real(n);
}
template<class T> Real distance(Line<T> l, Point<T> p) { return std::sqrt(distance_squared(l, p)); }
template<class T> Real distance(Point<T> p, Line<T> l) { return distance(l, p); }
template<class T> Real distance(Segment<T> s, Point<T> p) { return std::sqrt(distance_squared(s, p)); }
template<class T> Real distance(Point<T> p, Segment<T> s) { return distance(s, p); }
template<class T> Real distance_squared(Point<T> p, Line<T> l) { return distance_squared(l, p); }
template<class T> Real distance_squared(Point<T> p, Segment<T> s) { return distance_squared(s, p); }
template<class T>
Real distance_squared(Line<T> l, Line<T> m, Real eps = epsilon) {
if (intersects(l, m, eps)) return 0;
return l.a == l.b ? distance_squared(m, l.a) : distance_squared(l, m.a);
}
template<class T>
Real distance_squared(Line<T> l, Segment<T> s, Real eps = epsilon) {
if (intersects(l, s, eps)) return 0;
return l.a == l.b ? distance_squared(s, l.a) : std::min(distance_squared(l, s.a), distance_squared(l, s.b));
}
template<class T>
Real distance_squared(Segment<T> s, Line<T> l, Real eps = epsilon) { return distance_squared(l, s, eps); }
template<class T>
Real distance_squared(Segment<T> s, Segment<T> t, Real eps = epsilon) {
if (intersects(s, t, eps)) return 0;
return std::min({distance_squared(s, t.a), distance_squared(s, t.b), distance_squared(t, s.a), distance_squared(t, s.b)});
}
template<class T> Real distance(Line<T> l, Line<T> m, Real eps = epsilon) { return std::sqrt(distance_squared(l, m, eps)); }
template<class T> Real distance(Line<T> l, Segment<T> s, Real eps = epsilon) { return std::sqrt(distance_squared(l, s, eps)); }
template<class T> Real distance(Segment<T> s, Line<T> l, Real eps = epsilon) { return distance(l, s, eps); }
template<class T> Real distance(Segment<T> s, Segment<T> t, Real eps = epsilon) { return std::sqrt(distance_squared(s, t, eps)); }
template<class T>
std::optional<Line<Real>> perpendicular_bisector(Point<T> a, Point<T> b) {
if (a == b) return std::nullopt;
using W = wide_t<T>;
FPoint mid{Real(a.x) / 2 + Real(b.x) / 2, Real(a.y) / 2 + Real(b.y) / 2};
FPoint d{Real(W(b.y) - a.y), Real(W(a.x) - b.x)};
return Line<Real>{mid, mid + d};
}
}