简单多边形与圆相交模板

分5种情况,模板转载自:http://hi.baidu.com/billdu/item/703ad4e15d819db52f140b0b

题目大意:给你个简单多边形,和一个圆心在原点处的圆,求这个多边形与圆的重合部分的面积。

也就是这个意思了……

但是这看上去也太恶心了,怎么办?其实想一想就知道,我们平日求多边形面积用的就是三角形剖分,所以说我们应该化繁为简,通过求出来各三角形与圆的交,从而求出总面积。而且,剖分用的原点正好在圆心,这是很方便的一件事情。

现在问题就转化成一个顶点在圆心的三角形了。但是这才是麻烦的开始,除去退化情况,我们应该至少考虑到以下五种情况:

(一)三角形的两条边全部短于半径。

最方便了,不是么?

(二)三角形的两条边全部长于半径,且另一条边与圆心的距离也长于半径。

只需要求出扇形的面积即可。

(三)三角形的两条边全部长于半径,但另一条边与圆心的距离短于半径,并且垂足落在这条边上。

求出扇形的面积,再减去那个弓形的面积。也就是说再挖去一个扇形,补上一个三角形。

(四)三角形的两条边全部长于半径,但另一条边与圆心的距离短于半径,且垂足未落在这条边上。

与上一个很像……一开始我就在这里WA了很长时间。事实上只需求一个扇形。

(五)三角形的两条边一条长于半径,另外一条短于半径。

先求出交点,再剖成扇形和三角形求解。

代码:HDU 4404

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>

#define CL(arr, val) memset(arr, val, sizeof(arr))
#define REP(i, n)for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)for((i) = (h); (i) >= (l); --(i))
#define L(x)(x) << 1
#define R(x)(x) << 1 | 1
#define MID(l, r)(l + r) >> 1
#define Min(x, y)x < y ? x : y
#define Max(x, y)x < y ? y : x
#define E(x)(1 << (x))
#define iabs(x) (x) < 0 ? -(x) : (x)
#define OUT(x)printf("%I64d\n", x)
#define lowbit(x)(x)&(-x)
#define Read()freopen("data.in", "r", stdin)
#define Write()freopen("data.out", "w", stdout);

const double eps = 1e-10;
typedef long long LL;
const int inf = ~0u>>2;

using namespace std;

inline double max (double a, double b) { if (a > b) return a; else return b; }
inline double min (double a, double b) { if (a < b) return a; else return b; }
inline int fi (double a)
{
    if (a > eps) return 1;
    else if (a >= -eps) return 0;
    else return -1;
}
class Vector
{
public:
    double x, y;
    Vector (void) {}
    Vector (double x0, double y0) : x(x0), y(y0) {}
    double operator * (const Vector& a) const { return x * a.y - y * a.x; }
    double operator % (const Vector& a) const { return x * a.x + y * a.y; }
    Vector verti (void) const { return Vector(-y, x); }
    double length (void) const { return sqrt(x * x + y * y); }
    Vector adjust (double len)
    {
        double ol = len / length();
        return Vector(x * ol, y * ol);
    }
    Vector oppose (void) { return Vector(-x, -y); }
};
class point
{
public:
    double x, y;
    point (void) {}
    point (double x0, double y0) : x(x0), y(y0) {}
    Vector operator - (const point& a) const { return Vector(x - a.x, y - a.y); }
    point operator + (const Vector& a) const { return point(x + a.x, y + a.y); }
};
class segment
{
public:
    point a, b;
    segment (void) {}
    segment (point a0, point b0) : a(a0), b(b0) {}
    point intersect (const segment& s) const
    {
        Vector v1 = s.a - a, v2 = s.b - a, v3 = s.b - b, v4 = s.a - b;
        double s1 = v1 * v2, s2 = v3 * v4;
        double se = s1 + s2;
        s1 /= se, s2 /= se;
        return point(a.x * s2 + b.x * s1, a.y * s2 + b.y * s1);
    }
    point pverti (const point& p) const
    {
        Vector t = (b - a).verti();
        segment uv(p, p + t);
        return intersect(uv);
    }
    bool on_segment (const point& p) const
    {
        if (fi(min(a.x, b.x) - p.x) <= 0 && fi(p.x - max(a.x, b.x)) <= 0 &&
            fi(min(a.y, b.y) - p.y) <= 0 && fi(p.y - max(a.y, b.y)) <= 0) return true;
        else return false;
    }
};

double radius;
point polygon[110];

double kuras_area (point a, point b, double cx, double cy)
{
    point ori(cx, cy);
    int sgn = fi((b - ori) * (a - ori));
    double da = (a - ori).length(), db = (b - ori).length();
    int ra = fi(da - radius), rb = fi(db - radius);
    double angle = acos(((b - ori) % (a - ori)) / (da * db));
    segment t(a, b); point h, u; Vector seg;
    double ans, dlt, mov, tangle;

    if (fi(da) == 0 || fi(db) == 0) return 0;
    else if (sgn == 0) return 0;
    else if (ra <= 0 && rb <= 0) return fabs((b - ori) * (a - ori)) / 2 * sgn;
    else if (ra >= 0 && rb >= 0)
    {
        h = t.pverti(ori);
        dlt = (h - ori).length();
        if (!t.on_segment(h) || fi(dlt - radius) >= 0)
            return radius * radius * (angle / 2) * sgn;
        else
        {
            ans = radius * radius * (angle / 2);
            tangle = acos(dlt / radius);
            ans -= radius * radius * tangle;
            ans += radius * sin(tangle) * dlt;
            return ans * sgn;
        }
    }
    else
    {
        h = t.pverti(ori);
        dlt = (h - ori).length();
        seg = b - a;
        mov = sqrt(radius * radius - dlt * dlt);
        seg = seg.adjust(mov);
        if (t.on_segment(h + seg)) u = h + seg;
        else u = h + seg.oppose();
        if (ra == 1) swap(a, b);
        ans = fabs((a - ori) * (u - ori)) / 2;
        tangle = acos(((u - ori) % (b - ori)) / ((u - ori).length() * (b - ori).length()));
        ans += radius * radius * (tangle / 2);
        return ans * sgn;
    }
}

const double pi = acos(-1.0);

int main ()
{
    //freopen("data.in", "r", stdin);

    int n;
    double area, x, y, cx, cy;
    double x0, y0, v0, th, t, g;
    double vx, vy;

    while(~scanf("%lf%lf%lf%lf%lf%lf%lf", &x0, &y0, &v0, &th, &t, &g, &radius)) {
        if(x0 == 0 && y0 == 0 && v0 == 0 && th == 0 && t == 0 && g == 0 && radius == 0)  break;
        vx = v0*cos(pi*th/180.0); vy = v0*sin(pi*th/180.0);
        cx = x0 + vx*t;
        cy = y0 + (vy*t - 0.5*g*t*t);
        scanf("%d", &n);
        for(int i = 0; i < n; ++i) {
            scanf("%lf%lf", &x, &y);
            polygon[i] = point(x, y);
        }
        area = 0;
        for (int i = 0; i < n; i++)
            area += kuras_area(polygon[i], polygon[(i + 1) % n], cx, cy);
        printf("%.2f\n", fabs(area));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/vongang/p/2700682.html