This documentation is automatically generated by online-judge-tools/verification-helper
#include "Src/GeometryR2/CommonArea/CircleAndPolygon.hpp"
#pragma once
#include "../Circle.hpp"
#include "../Polygon.hpp"
#include "../CrossPoint/CircleAndSegment.hpp"
#include "../Distance/PointAndPoint.hpp"
namespace zawa {
namespace geometryR2 {
Real CommonArea(const Circle& c, const Polygon& poly) {
auto theta = [&](const Point& p, const Point& q) -> Real {
const Real cosT = (p.normSquare() + q.normSquare() - DistanceSquare(p, q)) / (2 * p.norm() * q.norm());
return acosl(cosT);
};
// signed common area of c and triangle(c.center(), p, q)
auto common_area = [&](Point p, Point q) -> Real {
p -= c.center();
q -= c.center();
if (Zero(Cross(p, q))) return 0;
const bool pin = Smaller(p.normSquare(), Square(c.radius())), qin = Smaller(q.normSquare(), Square(c.radius()));
if (pin and qin) return Cross(p, q) / 2;
const auto cps = CrossPoint(c, Segment{p, q});
if (cps.empty()) return Sign(Cross(p, q)) * c.sectorArea(theta(p, q));
Real res = 0;
if (pin) res += Cross(p, cps.front()) / 2;
else {
const Vector dir = p.normalized();
const Point v = c.center() + dir * c.radius();
res += Sign(Cross(v, cps.front())) * c.sectorArea(theta(v, cps.front()));
}
if (qin) res += Cross(cps.back(), q) / 2;
else {
const Vector dir = q.normalized();
const Point v = c.center() + dir * c.radius();
res += Sign(Cross(cps.back(), v)) * c.sectorArea(theta(cps.back(), v));
}
if (std::ssize(cps) == 2) res += Cross(cps[0], cps[1]) / 2;
return res;
};
Real res = 0;
for (usize i = 0 ; i < poly.size() ; i++) {
const Real kiyo = common_area(poly[i], poly[i+1==poly.size()?0u:i+1]);
res += kiyo;
}
return res;
}
} // namespace geometryR2
} // namespace zawa
#line 2 "Src/GeometryR2/CommonArea/CircleAndPolygon.hpp"
#line 2 "Src/GeometryR2/Circle.hpp"
#line 2 "Src/Template/TypeAlias.hpp"
#include <cstdint>
#include <cstddef>
namespace zawa {
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using usize = std::size_t;
} // namespace zawa
#line 2 "Src/GeometryR2/Real.hpp"
#line 4 "Src/GeometryR2/Real.hpp"
#include <cmath>
#include <cassert>
namespace zawa {
namespace geometryR2 {
using Real = long double;
namespace internal {
Real EPS{1e-12};
constexpr i32 negative{-1};
constexpr i32 zero{};
constexpr i32 positive{1};
} // namespace internal
Real& Eps() {
return internal::EPS;
}
i32 Sign(Real value) {
if (value < -Eps()) return internal::negative;
if (value > Eps()) return internal::positive;
return internal::zero;
}
bool Zero(Real value) {
return Sign(value) == internal::zero;
}
bool Positive(Real value) {
return Sign(value) == internal::positive;
}
bool Negative(Real value) {
return Sign(value) == internal::negative;
}
bool Equal(Real a, Real b) {
return Zero(a - b);
}
bool Smaller(Real a, Real b) {
return Negative(a - b);
}
bool Bigger(Real a, Real b) {
return Positive(a - b);
}
Real Square(Real value) {
return (Zero(value) ? value : value * value);
}
Real Sqrt(Real value) {
assert(!Negative(value));
return (Zero(value) ? value : sqrtl(value));
}
Real Abs(Real value) {
return (Negative(value) ? -value : value);
}
} // namespace geometryR2
} // namespace zawa
#line 2 "Src/GeometryR2/Angle.hpp"
#line 4 "Src/GeometryR2/Angle.hpp"
#line 6 "Src/GeometryR2/Angle.hpp"
namespace zawa {
namespace geometryR2 {
constexpr Real PI{acosl(-1)};
constexpr Real TAU{static_cast<Real>(2) * PI};
constexpr Real ArcToRadian(Real arc) {
return (arc * PI) / static_cast<Real>(180);
}
constexpr Real RadianToArc(Real radian) {
return (radian * static_cast<Real>(180)) / PI;
}
} // namespace geometryR2
} // namespace zawa
#line 2 "Src/GeometryR2/Point.hpp"
#line 5 "Src/GeometryR2/Point.hpp"
#line 7 "Src/GeometryR2/Point.hpp"
#include <iostream>
#line 9 "Src/GeometryR2/Point.hpp"
namespace zawa {
namespace geometryR2 {
class Point {
private:
Real x_{}, y_{};
public:
/* constructor */
Point() = default;
Point(Real x, Real y) : x_{x}, y_{y} {}
/* getter, setter */
Real x() const {
return x_;
}
Real& x() {
return x_;
}
Real y() const {
return y_;
}
Real& y() {
return y_;
}
/* operator */
Point& operator+=(const Point& rhs) {
x_ += rhs.x();
y_ += rhs.y();
return *this;
}
friend Point operator+(const Point& lhs, const Point& rhs) {
return Point{lhs} += rhs;
}
Point operator+() const {
return *this;
}
Point& operator-=(const Point& rhs) {
x_ -= rhs.x();
y_ -= rhs.y();
return *this;
}
friend Point operator-(const Point& lhs, const Point& rhs) {
return Point{lhs} -= rhs;
}
Point operator-() const {
return Point{} - *this;
}
Point& operator*=(Real k) {
x_ *= k;
y_ *= k;
return *this;
}
friend Point operator*(Real k, const Point& p) {
return Point{p} *= k;
}
friend Point operator*(const Point& p, Real k) {
return Point{p} *= k;
}
Point& operator/=(Real k) {
assert(!Zero(k));
x_ /= k;
y_ /= k;
return *this;
}
friend Point operator/(Real k, const Point& p) {
return Point{p} /= k;
}
friend Point operator/(const Point& p, Real k) {
return Point{p} /= k;
}
friend bool operator==(const Point& lhs, const Point& rhs) {
return Equal(lhs.x(), rhs.x()) and Equal(lhs.y(), rhs.y());
}
friend bool operator!=(const Point& lhs, const Point& rhs) {
return !Equal(lhs.x(), rhs.x()) or !Equal(lhs.y(), rhs.y());
}
friend bool operator<(const Point& lhs, const Point& rhs) {
return Smaller(lhs.x(), rhs.x()) or
(Equal(lhs.x(), rhs.x()) and Smaller(lhs.y(), rhs.y()));
}
friend bool operator<=(const Point& lhs, const Point& rhs) {
return Smaller(lhs.x(), rhs.x()) or
(Equal(lhs.x(), rhs.x()) and (Smaller(lhs.y(), rhs.y()) or Equal(lhs.y(), rhs.y())));
}
friend bool operator>(const Point& lhs, const Point& rhs) {
return Bigger(lhs.x(), rhs.x()) or
(Equal(lhs.x(), rhs.x()) and Bigger(lhs.y(), rhs.y()));
}
friend bool operator>=(const Point& lhs, const Point& rhs) {
return Bigger(lhs.x(), rhs.x()) or
(Equal(lhs.x(), rhs.x()) and (Bigger(lhs.y(), rhs.y()) or Equal(lhs.y(), rhs.y())));
}
friend std::istream& operator>>(std::istream& is, Point& p) {
is >> p.x_ >> p.y_;
return is;
}
friend std::ostream& operator<<(std::ostream& os, const Point& p) {
os << '(' << p.x_ << ',' << p.y_ << ')';
return os;
}
/* member function */
Real normSquare() const {
return Square(x_) + Square(y_);
}
Real norm() const {
return Sqrt(normSquare());
}
void normalize() {
assert((*this) != Point{});
(*this) /= norm();
}
Point normalized() const {
Point res{*this};
res.normalize();
return res;
}
Point rotated(Real radian) const {
return Point{
x_ * cosl(radian) - y_ * sinl(radian),
x_ * sinl(radian) + y_ * cosl(radian)
};
}
void rotate(Real radian) {
*this = rotated(radian);
}
Point rotatedByArc(Real arc) const {
return rotated(ArcToRadian(arc));
}
void rotateByArc(Real arc) {
*this = rotatedByArc(arc);
}
Real argument() const {
return (Negative(y_) ? TAU : static_cast<Real>(0)) + atan2l(y_, x_);
}
Real argumentByArc() const {
return RadianToArc(argument());
}
/* friend function */
friend Real Dot(const Point& lhs, const Point& rhs) {
return lhs.x() * rhs.x() + lhs.y() * rhs.y();
}
friend Real Cross(const Point& lhs, const Point& rhs) {
return lhs.x() * rhs.y() - lhs.y() * rhs.x();
}
friend Real Argument(const Point& lhs, const Point& rhs) {
return rhs.argument() - lhs.argument();
}
friend bool ArgComp(const Point& lhs, const Point& rhs) {
return Smaller(lhs.argument(), rhs.argument());
}
};
using Vector = Point;
} // namespace geometryR2
} // namespace zawa
#line 2 "Src/GeometryR2/Distance/PointAndPoint.hpp"
#line 4 "Src/GeometryR2/Distance/PointAndPoint.hpp"
namespace zawa {
namespace geometryR2 {
Real Distance(const Point& p0, const Point& p1) {
return Point{p1 - p0}.norm();
}
Real DistanceSquare(const Point& p0, const Point& p1) {
return Point{p1 - p0}.normSquare();
}
} // namespace geometryR2
} // namespace zawa
#line 8 "Src/GeometryR2/Circle.hpp"
#line 10 "Src/GeometryR2/Circle.hpp"
#include <utility>
namespace zawa {
namespace geometryR2 {
class Circle {
private:
Point center_{};
Real radius_{};
public:
/* constructor */
Circle() = default;
Circle(const Point& center, Real radius) : center_{center}, radius_{radius} {
assert(!Negative(radius));
}
Circle(Real x, Real y, Real r) : center_{x, y}, radius_{r} {
assert(!Negative(r));
}
Circle(const Point& p0, const Point& p1) : center_{p0 + (p1 - p0) / 2}, radius_{Distance(p0, p1) / 2} {}
/* getter setter */
const Point& center() const {
return center_;
}
Point& center() {
return center_;
}
Real radius() const {
return radius_;
}
Real& radius() {
return radius_;
}
Real area() const {
return PI * Square(radius_);
}
Real sectorArea(Real centerAngle) const {
return Square(radius_) * centerAngle / 2;
}
/* operator */
friend bool operator==(const Circle& lhs, const Circle& rhs) {
return lhs.center() == rhs.center() and Equal(lhs.radius(), rhs.radius());
}
friend bool operator!=(const Circle& lhs, const Circle& rhs) {
return lhs.center() != rhs.center() or !Equal(lhs.radius(), rhs.radius());
}
/* friend function */
friend u32 NumberCommonTangent(const Circle& c0, const Circle& c1) {
Real dist{DistanceSquare(c0.center(), c1.center())};
Real down{Square(Abs(c0.radius() - c1.radius()))};
if (Smaller(dist, down)) return 0;
if (Equal(dist, down)) return 1;
Real up{Square(c0.radius() + c1.radius())};
if (Smaller(dist, up)) return 2;
if (Equal(dist, up)) return 3;
return 4;
}
};
} // namespace geometryR2
} // namespace zawa
#line 2 "Src/GeometryR2/Polygon.hpp"
#line 2 "Src/GeometryR2/Relation.hpp"
#line 5 "Src/GeometryR2/Relation.hpp"
namespace zawa {
namespace geometryR2 {
enum RELATION {
// p0 -> p1 -> p2の順で直線上に並んでいる
ONLINE_FRONT = -2,
// (p1 - p0) -> (p2 - p0)が時計回りになっている
CLOCKWISE,
// p0 -> p2 -> p1の順で直線上に並んでいる
ON_SEGMENT,
// (p1 - p0) -> (p2 - p0)が反時計回りになっている
COUNTER_CLOCKWISE,
// p2 -> p0 -> p1、またはp1 -> p0 -> p2の順で直線上に並んでいる
ONLINE_BACK
};
RELATION Relation(const Point& p0, const Point& p1, const Point& p2) {
Point a{p1 - p0}, b{p2 - p0};
if (Positive(Cross(a, b))) return COUNTER_CLOCKWISE;
if (Negative(Cross(a, b))) return CLOCKWISE;
if (Negative(Dot(a, b))) return ONLINE_BACK;
if (Smaller(a.normSquare(), b.normSquare())) return ONLINE_FRONT;
return ON_SEGMENT;
};
} // namespace geometryR2
} // namespace zawa
#line 7 "Src/GeometryR2/Polygon.hpp"
#include <algorithm>
#line 10 "Src/GeometryR2/Polygon.hpp"
#include <concepts>
#include <vector>
namespace zawa {
namespace geometryR2 {
class Polygon {
private:
std::vector<Point> data_;
public:
/* member */
usize size() const {
return data_.size();
}
/* constructor */
Polygon() = default;
explicit Polygon(const std::vector<Point>& data) : data_{data} {}
explicit Polygon(usize n) : data_(n) {}
/* operator[] */
Point& operator[](usize i) {
assert(i < size());
return data_[i];
}
const Point& operator[](usize i) const {
assert(i < size());
return data_[i];
}
friend std::istream& operator>>(std::istream& is, Polygon& polygon) {
for (size_t i{} ; i < polygon.size() ; i++) {
is >> polygon[i];
}
return is;
}
friend std::ostream& operator<<(std::ostream& os, const Polygon& polygon) {
for (usize i{} ; i < polygon.size() ; i++) {
std::cout << polygon[i] << (i + 1 == polygon.size() ? "" : " ");
}
return os;
}
/* member function */
void orderRotate(usize i) {
assert(i < size());
std::rotate(data_.begin(), data_.begin() + i, data_.end());
}
void normalForm() {
auto index{std::distance(data_.begin(), std::min_element(data_.begin(), data_.end()))};
orderRotate(index);
}
Polygon normalFormed() const {
Polygon res{*this};
res.normalForm();
return res;
}
bool isConvex() const {
assert(size() >= static_cast<usize>(3));
for (usize i{} ; i < size() ; i++) {
if (Relation(data_[i], data_[i+1==size()?0:i+1], data_[i+2>=size()?i+2-size():i+2])
== CLOCKWISE) {
return false;
}
}
return true;
}
Real area() const {
if (std::ssize(data_) <= 2) return 0;
Real res{};
for (usize i{1} ; i < size() ; i++) {
res += Cross(data_[i] - data_[0], data_[i+1==size()?0:i+1] - data_[0]);
}
return res / static_cast<Real>(2);
}
void pushBack(const Point& p) {
data_.push_back(p);
}
void emplaceBack(Real x, Real y) {
data_.emplace_back(x, y);
}
void reserve(usize n) {
data_.reserve(n);
}
template <std::input_iterator RandomAccessIterator>
void insert(usize n, RandomAccessIterator first, RandomAccessIterator last) {
assert(n <= size());
data_.insert(std::next(data_.begin(), n), first, last);
}
};
} // namespace geometryR2
} // namespace zawa
#line 2 "Src/GeometryR2/CrossPoint/CircleAndSegment.hpp"
#line 2 "Src/GeometryR2/Segment.hpp"
#line 6 "Src/GeometryR2/Segment.hpp"
#line 9 "Src/GeometryR2/Segment.hpp"
namespace zawa {
namespace geometryR2 {
class Segment {
private:
Point p0_{}, p1_{};
public:
/* constructor */
Segment() = default;
Segment(const Point& p0, const Point& p1) : p0_{p0}, p1_{p1} {}
Segment(Real x0, Real y0, Real x1, Real y1) : p0_{x0, y0}, p1_{x1, y1} {}
/* getter setter */
const Point& p0() const {
return p0_;
}
Point& p0() {
return p0_;
}
const Point& p1() const {
return p1_;
}
Point& p1() {
return p1_;
}
/* member function */
bool valid() const {
return p0_ != p1_;
}
bool straddle(const Segment& s) const {
return Relation(p0_, p1_, s.p0()) * Relation(p0_, p1_, s.p1()) <= 0;
}
Real length() const {
assert(valid());
return Distance(p0_, p1_);
}
Point midpoint() const {
assert(valid());
return p0_ + Vector{p1_ - p0_} / static_cast<Real>(2);
}
};
} // namespace geometryR2
} // namespace zawa
#line 2 "Src/GeometryR2/Line.hpp"
#line 5 "Src/GeometryR2/Line.hpp"
#line 7 "Src/GeometryR2/Line.hpp"
namespace zawa {
namespace geometryR2 {
class Line {
private:
Point p0_{}, p1_{};
public:
/* constructor */
Line() = default;
Line(const Point& p0, const Point& p1) : p0_{p0}, p1_{p1} {}
// y = ax + b
Line(Real a, Real b) : p0_{static_cast<Real>(0), b}, p1_{static_cast<Real>(1), a + b} {}
/* getter, setter */
const Point& p0() const {
return p0_;
}
Point& p0() {
return p0_;
}
const Point& p1() const {
return p1_;
}
Point& p1() {
return p1_;
}
/* operator */
friend bool operator==(const Line& l0, const Line& l1) {
return Zero(Cross(l0.p1() - l0.p0(), l1.p1() - l1.p0())) and Zero(Cross(l0.p1() - l0.p0(), l1.p1() - l0.p0()));
}
friend bool operator!=(const Line& l0, const Line& l1) {
return !Zero(Cross(l0.p1() - l0.p0(), l1.p1() - l1.p0())) or !Zero(Cross(l0.p1() - l0.p0(), l1.p1() - l0.p0()));
}
/* member function */
bool valid() const {
return p0_ != p1_;
}
Vector slope() const {
assert(valid());
return Vector{p1() - p0()}.normalized();
}
};
} // namespace geometryR2
} // namespace zawa
#line 2 "Src/GeometryR2/Projection.hpp"
#line 6 "Src/GeometryR2/Projection.hpp"
#line 8 "Src/GeometryR2/Projection.hpp"
namespace zawa {
namespace geometryR2 {
Point Projection(const Point& point, const Line& line) {
assert(line.valid());
Real coeff{Dot(line.p1() - line.p0(), point - line.p0()) / DistanceSquare(line.p0(), line.p1())};
return coeff * line.p1() + (static_cast<Real>(1) - coeff) * line.p0();
}
} // namespace geometryR2
} // namespace zawa
#line 10 "Src/GeometryR2/CrossPoint/CircleAndSegment.hpp"
#line 14 "Src/GeometryR2/CrossPoint/CircleAndSegment.hpp"
namespace zawa {
namespace geometryR2 {
std::vector<Point> CrossPoint(const Circle& c, const Segment& s) {
assert(s.valid());
Point pr{Projection(c.center(), Line{s.p0(), s.p1()})};
if (Bigger(DistanceSquare(c.center(), pr), Square(c.radius()))) return {};
const Vector e = (s.p1() - s.p0()) / Distance(s.p0(), s.p1());
const Real l = Sqrt(
Square(c.radius()) - DistanceSquare(pr, c.center())
);
std::vector<Point> res;
// s0に近い方からresに入る
for (Point p : {pr - e * l, pr + e * l}) {
if (Relation(s.p0(), s.p1(), p) == RELATION::ON_SEGMENT) {
res.push_back(p);
}
}
return res;
}
} // namespace geometryR2
} // namespace zawa
#line 7 "Src/GeometryR2/CommonArea/CircleAndPolygon.hpp"
namespace zawa {
namespace geometryR2 {
Real CommonArea(const Circle& c, const Polygon& poly) {
auto theta = [&](const Point& p, const Point& q) -> Real {
const Real cosT = (p.normSquare() + q.normSquare() - DistanceSquare(p, q)) / (2 * p.norm() * q.norm());
return acosl(cosT);
};
// signed common area of c and triangle(c.center(), p, q)
auto common_area = [&](Point p, Point q) -> Real {
p -= c.center();
q -= c.center();
if (Zero(Cross(p, q))) return 0;
const bool pin = Smaller(p.normSquare(), Square(c.radius())), qin = Smaller(q.normSquare(), Square(c.radius()));
if (pin and qin) return Cross(p, q) / 2;
const auto cps = CrossPoint(c, Segment{p, q});
if (cps.empty()) return Sign(Cross(p, q)) * c.sectorArea(theta(p, q));
Real res = 0;
if (pin) res += Cross(p, cps.front()) / 2;
else {
const Vector dir = p.normalized();
const Point v = c.center() + dir * c.radius();
res += Sign(Cross(v, cps.front())) * c.sectorArea(theta(v, cps.front()));
}
if (qin) res += Cross(cps.back(), q) / 2;
else {
const Vector dir = q.normalized();
const Point v = c.center() + dir * c.radius();
res += Sign(Cross(cps.back(), v)) * c.sectorArea(theta(cps.back(), v));
}
if (std::ssize(cps) == 2) res += Cross(cps[0], cps[1]) / 2;
return res;
};
Real res = 0;
for (usize i = 0 ; i < poly.size() ; i++) {
const Real kiyo = common_area(poly[i], poly[i+1==poly.size()?0u:i+1]);
res += kiyo;
}
return res;
}
} // namespace geometryR2
} // namespace zawa