C. Beer Coasters 计算几何
比赛地址:
https://www.jisuanke.com/contest/7321?view=challenges
题意:
给你一个圆和一个矩形,求两者相交的距离,其中矩形是以对角线形式给出。
基本思路:
计算几何,不会写,直接套多边形和圆相交模板,这里顺便存一个比较好用的计算几何模板。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
const double eps = 1e-8;
const double INF = 1e20;
const double pi = acos (-1.0);
int dcmp (double x) {
if (fabs(x) < eps) return 0;
return (x < 0 ? -1 : 1);
}
inline double sqr (double x) {return x*x;}
//*************点
struct Point {
double x, y;
Point(double _x = 0, double _y = 0) : x(_x), y(_y) {}
void input() { scanf("%lf%lf", &x, &y); }
void output() { printf("%.2f %.2f\n", x, y); }
bool operator==(const Point &b) const {
return (dcmp(x - b.x) == 0 && dcmp(y - b.y) == 0);
}
bool operator<(const Point &b) const {
return (dcmp(x - b.x) == 0 ? dcmp(y - b.y) < 0 : x < b.x);
}
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*(double a) {
return Point(x * a, y * a);
}
Point operator/(double a) {
return Point(x / a, y / a);
}
double len2() {//返回长度的平方
return sqr(x) + sqr(y);
}
double len() {//返回长度
return sqrt(len2());
}
Point change_len(double r) {//转化为长度为r的向量
double l = len();
if (dcmp(l) == 0) return *this;//零向量返回自身
r /= l;
return Point(x * r, y * r);
}
Point rotate_left() {//顺时针旋转90度
return Point(-y, x);
}
Point rotate_right() {//逆时针旋转90度
return Point(y, -x);
}
Point rotate(Point p, double ang) {//绕点p逆时针旋转ang
Point v = (*this) - p;
double c = cos(ang), s = sin(ang);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
Point normal() {//单位法向量
double l = len();
return Point(-y / l, x / l);
}
};
double cross (Point a, Point b) {//叉积
return a.x * b.y - a.y * b.x;
}
double dot (Point a, Point b) {//点积
return a.x * b.x + a.y * b.y;
}
double dis (Point a, Point b) {//两个点的距离
Point p = b - a;
return p.len();
}
double rad_degree (double rad) {//弧度转化为角度
return rad / pi * 180;
}
double rad (Point a, Point b) {//两个向量的夹角
return fabs(atan2(fabs(cross(a, b)), dot(a, b)));
}
bool parallel (Point a, Point b) {//向量平行
double p = rad(a, b);
return dcmp(p) == 0 || dcmp(p - pi) == 0;
}
//************直线 线段
struct Line {
Point s, e;//直线的两个点
Line() {}
Line(Point _s, Point _e) : s(_s), e(_e) {}
//一个点和倾斜角确定直线
Line(Point p, double ang) {
s = p;
if (dcmp(ang - pi / 2) == 0) {
e = s + Point(0, 1);
} else
e = s + Point(1, tan(ang));
}
//ax+by+c=0确定直线
Line(double a, double b, double c) {
if (dcmp(a) == 0) {
s = Point(0, -c / b);
e = Point(1, -c / b);
} else if (dcmp(b) == 0) {
s = Point(-c / a, 0);
e = Point(-c / a, 1);
} else {
s = Point(0, -c / b);
e = Point(1, (-c - a) / b);
}
}
void input() {
s.input();
e.input();
}
void adjust() {
if (e < s) swap(e, s);
}
double length() {//求线段长度
return dis(s, e);
}
double angle() {//直线的倾斜角
double k = atan2(e.y - s.y, e.x - s.x);
if (dcmp(k) < 0) k += pi;
if (dcmp(k - pi) == 0) k -= pi;
return k;
}
};
int relation (Point p, Line l) {//点和直线的关系
//1:在左侧 2:在右侧 3:在直线上
int c = dcmp(cross(p - l.s, l.e - l.s));
if (c < 0) return 1;
else if (c > 0) return 2;
else return 3;
}
bool point_on_seg (Point p, Line l) {//判断点在线段上
return dcmp(cross(p - l.s, l.e - l.s)) == 0 &&
dcmp(dot(p - l.s, p - l.e) <= 0);
//如果忽略端点交点改成小于号就好了
}
bool parallel (Line a, Line b) {//直线平行
return parallel(a.e - a.s, b.e - b.s);
}
int seg_cross_seg (Line a, Line v) {//线段相交判断
//1:规范相交 2:不规范相交 3:不相交
int d1 = dcmp(cross(a.e - a.s, v.s - a.s));
int d2 = dcmp(cross(a.e - a.s, v.e - a.s));
int d3 = dcmp(cross(v.e - v.s, a.s - v.s));
int d4 = dcmp(cross(v.e - v.s, a.e - v.s));
if ((d1 ^ d2) == -2 && (d3 ^ d4) == -2) return 2;
return (d1 == 0 && dcmp(dot(v.s - a.s, v.s - a.e)) <= 0) ||
(d2 == 0 && dcmp(dot(v.e - a.s, v.e - a.e)) <= 0) ||
(d3 == 0 && dcmp(dot(a.s - v.s, a.s - v.e)) <= 0) ||
(d4 == 0 && dcmp(dot(a.e - v.s, a.e - v.e)) <= 0);
}
int line_cross_seg (Line a, Line v) {//直线和线段相交判断
//1:规范相交 2:非规范相交 3:不相交
int d1 = dcmp(cross(a.e - a.s, v.s - a.s));
int d2 = dcmp(cross(a.e - a.s, v.e - a.s));
if (d1 ^ d2 == -2) return 2;
return (d1 == 0 || d2 == 0);
}
int line_cross_line (Line a, Line v) {//直线相交判断
//0:平行 1:重合 2:相交
if (parallel(a, v)) return relation(a.e, v) == 3;
return 2;
}
Point line_intersection (Line a, Line v) {//直线交点
//调用前确保有交点
double a1 = cross(v.e - v.s, a.s - v.s);
double a2 = cross(v.e - v.s, a.e - v.s);
return Point((a.s.x * a2 - a.e.x * a1) / (a2 - a1), (a.s.y * a2 - a.e.y * a1) / (a2 - a1));
}
double point_to_line (Point p, Line a) {//点到直线的距离
return fabs(cross(p - a.s, a.e - a.s) / a.length());
}
double point_to_seg (Point p, Line a) {//点到线段的距离
if (dcmp(dot(p - a.s, a.e - a.s)) < 0 || dcmp(dot(p - a.e, a.s - a.e)) < 0)
return min(dis(p, a.e), dis(p, a.s));
return point_to_line(p, a);
}
Point projection (Point p, Line a) {//点在直线上的投影
return a.s + (((a.e - a.s) * dot(a.e - a.s, p - a.s)) / (a.e - a.s).len2());
}
Point symmetry (Point p, Line a) {//点关于直线的对称点
Point q = projection(p, a);
return Point(2 * q.x - p.x, 2 * q.y - p.y);
}
//***************圆
struct Circle {
//圆心 半径
Point p;
double r;
Circle() {}
Circle(Point _p, double _r) : p(_p), r(_r) {}
Circle(double a, double b, double _r) {
p = Point(a, b);
r = _r;
}
void input() {
p.input();
scanf("%lf", &r);
}
void output() {
p.output();
printf(" %.2f\n", r);
}
bool operator==(const Circle &a) const {
return p == a.p && (dcmp(r - a.r) == 0);
}
double area() {//面积
return pi * r * r;
}
double circumference() {//周长
return 2 * pi * r;
}
};
int relation (Point p, Circle a) {//点和圆的关系
//0:圆外 1:圆上 2:圆内
double d = dis(p, a.p);
if (dcmp(d - a.r) == 0) return 1;
return (dcmp(d - a.r) < 0 ? 2 : 0);
}
int relation (Line a, Circle b) {//直线和圆的关系
//0:相离 1:相切 2:相交
double p = point_to_line(b.p, a);
if (dcmp(p - b.r) == 0) return 1;
return (dcmp(p - b.r) < 0 ? 2 : 0);
}
int relation (Circle a, Circle v) {//两圆的位置关系
//1:内含 2:内切 3:相交 4:外切 5:相离
double d = dis(a.p, v.p);
if (dcmp(d - a.r - v.r) > 0) return 5;
if (dcmp(d - a.r - v.r) == 0) return 4;
double l = fabs(a.r - v.r);
if (dcmp(d - a.r - v.r) < 0 && dcmp(d - l) > 0) return 3;
if (dcmp(d - l) == 0) return 2;
if (dcmp(d - l) < 0) return 1;
}
Circle out_circle (Point a, Point b, Point c) {//三角形外接圆
Line u = Line((a + b) / 2, ((a + b) / 2) + (b - a).rotate_left());
Line v = Line((b + c) / 2, ((b + c) / 2) + (c - b).rotate_left());
Point p = line_intersection(u, v);
double r = dis(p, a);
return Circle(p, r);
}
Circle in_circle (Point a, Point b, Point c) {//三角形内切圆
Line u, v;
double m = atan2(b.y - a.y, b.x - a.x), n = atan2(c.y - a.y, c.x - a.x);
u.s = a;
u.e = u.s + Point(cos((n + m) / 2), sin((n + m) / 2));
v.s = b;
m = atan2(a.y - b.y, a.x - b.x), n = atan2(c.y - b.y, c.x - b.x);
v.e = v.s + Point(cos((n + m) / 2), sin((n + m) / 2));
Point p = line_intersection(u, v);
double r = point_to_seg(p, Line(a, b));
return Circle(p, r);
}
int circle_intersection (Circle a, Circle v, Point &p1, Point &p2) {//两个圆的交点
//返回交点个数 交点保存在引用中
int rel = relation(a, v);
if (rel == 1 || rel == 5) return 0;
double d = dis(a.p, v.p);
double l = (d * d + a.r * a.r - v.r * v.r) / (2 * d);
double h = sqrt(a.r * a.
r - l * l);
Point tmp = a.p + (v.p - a.p).change_len(l);
p1 = tmp + ((v.p - a.p).rotate_left().change_len(h));
p2 = tmp + ((v.p - a.p).rotate_right().change_len(h));
if (rel == 2 || rel == 4) return 1;
return 2;
}
int line_cirlce_intersection (Line v, Circle u, Point &p1, Point &p2) {//直线和圆的交点
//返回交点个数 交点保存在引用中
if (!relation(v, u)) return 0;
Point a = projection(u.p, v);
double d = point_to_line(u.p, v);
d = sqrt(u.r * u.r - d * d);
if (dcmp(d) == 0) {
p1 = a, p2 = a;
return 1;
}
p1 = a + (v.e - v.s).change_len(d);
p2 = a - (v.e - v.s).change_len(d);
return 2;
}
int get_circle (Point a, Point b, double r1, Circle &c1, Circle &c2) {//得到过ab半径为r1的了两个圆
//返回得到圆的个数 圆保存在两个引用中
Circle x(a, r1), y(b, r1);
int t = circle_intersection(x, y, c1.p, c2.p);
if (!t) return 0;
c1.r = c2.r = r1;
return t;
}
int get_circle (Line u, Point q, double r1, Circle &c1, Circle &c2) {//得到和直线u相切 过点q 半径为r1的圆
double d = point_to_line(q, u);
if (dcmp(d - r1 * 2) > 0) return 0;
if (dcmp(d) == 0) {
c1.p = q + ((u.e - u.s).rotate_left().change_len(r1));
c2.p = q + ((u.e - u.s).rotate_right().change_len(r1));
c1.r = c2.r = r1;
return 2;
}
Line u1 = Line(u.s + (u.e - u.s).rotate_left().change_len(r1), u.e + (u.e - u.s).rotate_left().change_len(r1));
Line u2 = Line(u.s + (u.e - u.s).rotate_right().change_len(r1), u.e + (u.e - u.s).rotate_right().change_len(r1));
Circle cc = Circle(q, r1);
Point p1, p2;
if (!line_cirlce_intersection(u1, cc, p1, p2))
line_cirlce_intersection(u2, cc, p1, p2);
c1 = Circle(p1, r1);
if (p1 == p2) {
c2 = c1;
return 1;
}
c2 = Circle(p2, r1);
return 2;
}
int get_circle (Line u, Line v, double r1, Circle &c1, Circle &c2, Circle &c3, Circle &c4) {//和直线u,v相切 半径为r1的圆
if (parallel(u, v)) return 0;
Line u1 = Line(u.s + (u.e - u.s).rotate_left().change_len(r1), u.e + (u.e - u.s).rotate_left().change_len(r1));
Line u2 = Line(u.s + (u.e - u.s).rotate_right().change_len(r1), u.e + (u.e - u.s).rotate_right().change_len(r1));
Line v1 = Line(v.s + (v.e - v.s).rotate_left().change_len(r1), v.e + (v.e - v.s).rotate_left().change_len(r1));
Line v2 = Line(v.s + (v.e - v.s).rotate_right().change_len(r1), v.e + (v.e - v.s).rotate_right().change_len(r1));
c1.r = c2.r = c3.r = c4.r = r1;
c1.p = line_intersection(u1, v1);
c2.p = line_intersection(u1, v2);
c3.p = line_intersection(u2, v1);
c4.p = line_intersection(u2, v2);
return 4;
}
int get_circle (Circle cx, Circle cy, double r1, Circle &c1, Circle &c2) {//和两个圆相切 半径为r1的圆
//确保两个圆外离
Circle x(cx.p, r1 + cx.r), y(cy.p, r1 + cy.r);
int t = circle_intersection(x, y, c1.p, c2.p);
if (!t) return 0;
c1.r = c2.r = r1;
return t;
}
int tan_line (Point q, Circle a, Line &u, Line &v) {//过一点作圆切线
int x = relation(q, a);
if (x == 2) return 0;
if (x == 1) {
u = Line(q, q + (q - a.p).rotate_left());
v = u;
return 1;
}
double d = dis(a.p, q);
double l = a.r * a.r / d;
double h = sqrt(a.r * a.r - l * l);
u = Line(q, a.p + (q - a.p).change_len(l) + (q - a.p).rotate_left().change_len(h));
v = Line(q, a.p + (q - a.p).change_len(l) + (q - a.p).rotate_right().change_len(h));
return 2;
}
double area_circle (Circle a, Circle v) {//两圆相交面积
int rel = relation(a, v);
if (rel >= 4) return 0;
if (rel <= 2) return min(a.area(), v.area());
double d = dis(a.p, v.p);
double hf = (a.r + v.r + d) / 2;
double ss = 2 * sqrt(hf * (hf - a.r) * (hf - v.r) * (hf - d));
double a1 = acos((a.r * a.r + d * d - v.r * v.r) / (2 * a.r * d));
a1 = a1 * a.r * a.r;
double a2 = acos((v.r * v.r + d * d - a.r * a.r) / (2 * v.r * d));
a2 = a2 * v.r * v.r;
return a1 + a2 - ss;
}
double circle_traingle_area (Point a, Point b, Circle c) {//圆心三角形的面积
//a.output (), b.output (), c.output ();
Point p = c.p;
double r = c.r; //cout << cross (p-a, p-b) << endl;
if (dcmp(cross(p - a, p - b)) == 0) return 0;
Point q[5];
int len = 0;
q[len++] = a;
Line l(a, b);
Point p1, p2;
if (line_cirlce_intersection(l, c, q[1], q[2]) == 2) {
if (dcmp(dot(a - q[1], b - q[1])) < 0) q[len++] = q[1];
if (dcmp(dot(a - q[2], b - q[2])) < 0) q[len++] = q[2];
}
q[len++] = b;
if (len == 4 && dcmp(dot(q[0] - q[1], q[2] - q[1])) > 0)
swap(q[1], q[2]);
double res = 0;
for (int i = 0; i < len - 1; i++) {
if (relation(q[i], c) == 0 || relation(q[i + 1], c) == 0) {
double arg = rad(q[i] - p, q[i + 1] - p);
res += r * r * arg / 2.0;
} else {
res += fabs(cross(q[i] - p, q[i + 1] - p)) / 2;
}
} //cout << res << ".." << endl;
return res;
}
//*************多边形
bool is_convex (Point *p, int n) {//判断n边行是不是凸的
bool s[2];
s[0] = s[1] = 0;
for (int i = 0; i < n; i++) {
int j = (i + 1) % n;
int k = (j + 1) % n;
s[dcmp(cross(p[j] - p[i], p[k] - p[i])) + 1] = 1;
if (s[0] && s[2]) return 0;
}
return 1;
}
double polygon_area (Point *p, int n) {//多边形的有向面积,加上绝对值就是面积
//n个点
double area = 0;
for (int i = 1; i < n - 1; i++) {
area += cross(p[i] - p[0], p[i + 1] - p[0]);
}
return area / 2;
}
bool relation (Point a, Point *b, int n) {//点和多边形的关系(凸凹都可以)
//0:外部 1:内部 2:边上 3:顶点
int w = 0;
for (int i = 0; i < n; i++) {
if (a == b[i] || a == b[(i + 1) % n])
return 3;
if (point_on_seg(a, Line(b[(i + 1) % n], b[i])))
return 2;
int k = dcmp(cross(b[(i + 1) % n] - b[i], a - b[i]));
int d1 = dcmp(b[i].y - a.y);
int d2 = dcmp(b[(i + 1) % n].y - a.y);
if (k > 0 && d1 <= 0 && d2 > 0)
w++;
if (k < 0 && d2 <= 0 && d1 > 0)
w--;
}
if (w != 0)
return 1;
return 0;
}
int convex_cut (Line u, Point *p, int n, Point *po) {//直线切割多边形左侧
//返回切割后多边形的数量
int top = 0;
for (int i = 0; i < n; i++) {
int d1 = dcmp(cross(u.e - u.s, p[i] - u.s));
int d2 = dcmp(cross(u.e - u.s, p[(i + 1) % n] - u.s));
if (d1 >= 0) po[top++] = p[i];
if (d1 * d2 < 0) po[top++] = line_intersection(u, Line(p[i], p[(i + 1) % n]));
}
return top;
}
double convex_circumference (Point *p, int n) {//多边形的周长(凹凸都可以)
double ans = 0;
for (int i = 0; i < n; i++) {
ans += dis(p[i], p[(i + 1) % n]);
}
return ans;
}
double area_polygon_circle (Circle c, Point *p, int n) {//多边形和圆交面积
double ans = 0;
for (int i = 0; i < n; i++) {
int j = (i + 1) % n; //cout << i << " " << j << "//" << endl;
if (dcmp(cross(p[j] - c.p, p[i] - c.p)) >= 0)
ans += circle_traingle_area(p[i], p[j], c);
else
ans -= circle_traingle_area(p[i], p[j], c);
}
return fabs(ans);
}
Point centre_of_gravity (Point *p, int n) {//多边形的重心(凹凸都可以)
double sum = 0.0, sumx = 0, sumy = 0;
Point p1 = p[0], p2 = p[1], p3;
for (int i = 2; i <= n - 1; i++) {
p3 = p[i];
double area = cross(p2 - p1, p3 - p2) / 2.0;
sum += area;
sumx += (p1.x + p2.x + p3.x) * area;
sumy += (p1.y + p2.y + p3.y) * area;
p2 = p3;
}
return Point(sumx / (3.0 * sum), sumy / (3.0 * sum));
}
int convex_hull (Point *p, Point *ch, int n) {//求凸包
//所有的点集 凸包点集 点集的点数
sort(p, p + n);
int m = 0;
for (int i = 0; i < n; i++) {
while (m > 1 && cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 1]) <= 0)
m--;
ch[m++] = p[i];
}
int k = m;
for (int i = n - 2; i >= 0; i--) {
while (m > k && cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 1]) <= 0)
m--;
ch[m++] = p[i];
}
if (n > 1)
m--;
return m;
}
const int maxn = 10;
Point p[maxn];
int main () {
double x,y,r;
cin >> x >> y >> r;
Circle o = Circle(Point(x,y),r);
double a1,a2,b1,b2;
cin >> a1 >> a2 >> b1 >> b2;
//点的录入要保证顺逆时针关系;
p[0] = Point(a1,a2),p[1] = Point(a1,b2),p[2] = Point(b1,b2),p[3] = Point(b1,a2);
double ans = area_polygon_circle(o,p,4);
printf("%.4lf\n",ans);
return 0;
}