算法学习:计算几何基础及半平面交

 

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps  = 1e-6;
const int    MAXN = 20010;
const double lim  = 10000;
const double PI   = acos(-1.0);
int n, m;
inline int cmp(double x)
{
    if (x > eps)return 1;
    return x < -eps ? -1 : 0;
}
struct V
{
    double x, y;
    double ang;
    double angle()
    {//求取极角
        return atan2(y, x);
    }
    V(double X = 0, double Y = 0)
    {
        //初始化
        x = X, y = Y;
        ang = atan2(y, x);
    }
    bool operator ==(const V &b)
    {
        return cmp(x-b.x)&&cmp(y-b.y);
    }
    
};
typedef V  P;
V operator +(V a, V b) { return V(a.x + b.x, a.y + b.y); }
V operator -(V a, V b) { return V(a.x - b.x, a.y - b.y); }
V operator *(V a, double b) { return V(a.x *b, a.y*b ); }
V operator /(V a, double b) { return V(a.x /b, a.y/b ); }
struct L
{
    P s, t;
    double ang;
    L(P X = V(), P Y = V())
    {
        s = X, t = Y, ang = (Y - X).angle();
    }
};
typedef L S;
double cross(V a, V b)
{
    return a.x*b.y - a.y*b.x;
}
bool operator <(const L &a, const L &b)
{
    double r = a.ang - b.ang;
    if (cmp(r) != 0)    return cmp(r) == -1;
    //极角相同,默认偏下的更大
    return cmp(cross(a.t - a.s, b.t - a.s)) == -1;
}
double dot(V a, V b)
{
    return a.x*b.x + a.y*b.y;
}
bool is_parallel(L a, L b)
{
    return cmp(cross(a.t - a.s, b.t - b.s)) == 0;
}
P intersection(L a, L b)
{
    return a.s + (a.t - a.s)*(cross(b.t - b.s, a.s-b.s)) / cross(a.t - a.s, b.t - b.s);
}
double area(P *p, int n)
{
    double res = 0;
    p[n + 1] = p[1];
    for (int i = 1; i <= n; i++)
        res += cross(p[i], p[i + 1]);
    return fabs(res / 2);
}
bool is_right(L a, P b)
//判断点b是否在直线的右边(和起点连成的向量方向和直线向量方向相反)
{
    return cmp(cross(a.t - a.s, b - a.s)) < 0;
}
bool SI(L *l, int n, P *s, int &m)
//增量法求半平面交
{
    static L que[MAXN];
    static P que2[MAXN];
    int head = 0, tail = 0;
    sort(l + 1, l + 1 + n);
    que[head]=l[1];
    for (int i = 2; i <= n; i++)
    {
        if (cmp(l[i].ang - l[i - 1].ang))
        {
            if (head<tail && (is_parallel(que[head], que[head + 1]) || is_parallel(que[tail], que[tail - 1])))
            //若两个直线共线,但是极角不同,则没有半平面交
                return false;
            while (head < tail&&is_right(l[i], que2[tail - 1])) tail--;
            while (head < tail&&is_right(l[i], que2[head    ])) head++;
            que[++tail] = l[i];
            if (head < tail) 
                que2[tail - 1] = intersection(que[tail],que[tail-1]);
        }
    }
    while (head < tail&&is_right(que[head], que2[tail-1])) tail--;
    while (head < tail&&is_right(que[tail], que2[head  ])) head++;
    if (tail - head <= 1) return false;
    que2[tail] = intersection(que[head], que[tail]);
    m = 0;
    for (int i = head; i <= tail; i++)
        s[++m] = que2[i];
    return true;
}
P p[MAXN];
L l[MAXN];
double solve()
//求取半平面交的面积
//SI函数计算结果只是得到了半平面交的多边形数组
{
    P a = P(0, 0), b = P(lim, 0), c = P(lim, lim), d = P(0, lim);
    l[++n] = L(a, b);
    l[++n] = L(b, c);
    l[++n] = L(c, d);
    l[++n] = L(d, a);
    if (!SI(l, n, p, m))
        return 0;
    return area(p, m);
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        P a, b;
        scanf("%lf%lf%lf%lf", &a.x, &a.y, &b.x, &b.y);
        //直线方向,从起点指向终点
        //向量表示,终点减去起点
        l[i] = L(a, b);
    }
    printf("%.1f", solve());
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/rentu/p/11255620.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值