AOJ-CGL练习记录

AOJ相关习题

题集链接
https://judge.u-aizu.ac.jp/onlinejudge/finder.jsp?course=CGL

CGL_1_A:Projection

求一个点在向量\(\overrightarrow{ab}\)上的投影坐标
设点\(c\),投影在\(\overrightarrow{ab}\)上为\(c'\),则\(c'\)的坐标就是:\(cos<\overrightarrow{ac},\overrightarrow{ab}>\times |\overrightarrow{ac}|+a\)

point touying(Line l, point c) //c投影在直线ab上的位置
{
    vec A = l.b - l.a;
    vec B = c - l.a;
    double La = changdu(A);
    double Lc = dianji(A, B) / (La * La);
    return A * Lc + l.a;
}

{%endfold%}

CGL_1_B:Reflection

求一个点\(c\)关于向量\(\overrightarrow{ab}\)的对称点\(c''\)
先求出\(c\)\(ab\)上的投影,那么\(c''=2\times \overrightarrow{cc'}+c\)

point fanshe(Line l, point c) //求c关于直线ab的对称点c'
{
    point A = touying(l, c);
    return (A - c) * 2.0 + c;
}

{%endfold%}

CGL_1_C:Counter-Clockwise

就是..根据图中的判断就是了

void Counter_Clockwise(point p,point p1,point p2)
{
    if (zhengfu(chaji(p2 - p1, p - p1)) == 1)
            cout << "COUNTER_CLOCKWISE" << endl;
        else if (zhengfu(chaji(p2 - p1, p - p1)) == -1)
            cout << "CLOCKWISE" << endl;
        else {
            if (zhengfu(dianji(p2 - p1, p - p1)) == -1)
                cout << "ONLINE_BACK" << endl;
            else {
                double j = changdu(p2 - p1);
                double k = changdu(p - p1);
                if (bijiao(j, k) >= 0)
                    cout << "ON_SEGMENT" << endl;
                else
                    cout << "ONLINE_FRONT" << endl;
            }
        }
}

{%endfold%}

CGL_2_A:Parallel/Orthogonal

先判平行,再用点积判垂直

bool pingxing(vec a,vec b)
{
    return bijiao(a.x*b.y,a.y*b.x)==0;
}
void Parallel/Orthogonal(Line l1,Line l2)
{
    if (pingxing(l1.b-l1.a,l2.b-l2.a))
            cout << "2" << endl;
    else {
        if (zhengfu(dianji(l1.b-l1.a,l2.b-l2.a))==0)
            cout << "1" << endl;
        else {
            cout << "0" << endl;
        }
    }
}

{%endfold%}

CGL_2_B:Intersection

线段相交要考虑蛮多的,首先,先按照x后y从小到大排一下.
最简单的情况,\(ab\)穿过\(cd\),那么必定有交点.
第二种,\(a\)\(cd\)上或者\(b\)\(cd\)
第三种,共线时,\(a\)\(cd\)之间或\(b\)\(cd\)之间.
处理好以上问题,就解决了

bool bijiao3(vec a, vec b, vec c)
{
    if (a.x <= c.x && c.x <= b.x && ((a.y <= c.y && c.y <= b.y || b.y <= c.y && c.y <= a.y)))
        return 1;
    return 0;
}
bool xianduan_xiangjiao(Segment l1,Segment l2) //两线段是否有交点
{
    if (l1.a.x == l1.b.x) {
        if (l1.a.y > l1.b.y)
            swap(l1.a, l1.b);
    } else if (l1.a.x > l1.b.x)
        swap(l1.a, l1.b);
    if (l2.a.x == l2.b.x) {
        if (l2.a.y > l2.b.y)
            swap(l2.a, l2.b);
    } else if (l2.a.x > l2.b.x)
        swap(l2.a, l2.b);

    double c1 = chaji(l1.b - l1.a, l2.a - l1.a), d1 = chaji(l1.b - l1.a, l2.b - l1.a);
    double c2 = chaji(l2.b - l2.a, l1.a - l2.a), d2 = chaji(l2.b - l2.a, l1.b - l2.a);
    
    if (zhengfu(c1 * d1) < 0 && zhengfu(c2 * d2) < 0) //ab横穿cd
        return 1;
    else if (zhengfu(c1 * d1) != 0 && zhengfu(c2 * d2) == 0) { //ab不穿过cd
        if (zhengfu(c2) == 0) {
            if (bijiao3(l2.a, l2.b, l1.a))
                return 1;
        }
        if (zhengfu(d2) == 0)
            if (bijiao3(l2.a, l2.b, l1.b))
                return 1;
    } else if (zhengfu(c1 * d1) == 0 && zhengfu(c2 * d2) != 0) { //cd不穿过ab
        if (c1 == 0)
            if (bijiao3(l1.a, l1.b, l2.a))
                return 1;
        if (d1 == 0)
            if (bijiao3(l1.a, l1.b, l2.b))
                return 1;
    } else if (zhengfu(c1 * d1) == 0 && zhengfu(c2 * d2) == 0) { //平行
        if (l1.a == l2.a || l1.a == l2.b || l1.b == l2.a || l1.b == l2.b)
            return 1;
        if (bijiao3(l1.a, l1.b, l2.a) == 1)
            return 1;
        if (bijiao3(l2.a, l2.b, l1.a) == 1)
            return 1;
    }
    return 0;
}

{%endfold%}

CGL_2_C:Cross Point

给你两个必定相交的线段,求交点

point xianduan_jiaodian(Segment l1,Segment l2)//两线段交点
{ 
    double tmpLeft, tmpRight, x = inf, y = inf;
    if (xianduan_xiangjiao(l1,l2)) {
        tmpLeft = (l2.b.x - l2.a.x) * (l1.a.y - l1.b.y) - (l1.b.x - l1.a.x) * (l2.a.y - l2.b.y);
        tmpRight = (l1.a.y - l2.a.y) * (l1.b.x - l1.a.x) * (l2.b.x - l2.a.x) + l2.a.x * (l2.b.y - l2.a.y) * (l1.b.x - l1.a.x) - l1.a.x * (l1.b.y - l1.a.y) * (l2.b.x - l2.a.x);

        x = tmpRight / tmpLeft;

        tmpLeft = (l1.a.x - l1.b.x) * (l2.b.y - l2.a.y) - (l1.b.y - l1.a.y) * (l2.a.x - l2.b.x);
        tmpRight = l1.b.y * (l1.a.x - l1.b.x) * (l2.b.y - l2.a.y) + (l2.b.x - l1.b.x) * (l2.b.y - l2.a.y) * (l1.a.y - l1.b.y) - l2.b.y * (l2.a.x - l2.b.x) * (l1.b.y - l1.a.y);
        y = tmpRight / tmpLeft;
    }
    return point(x, y);
}

{%endfold%}

CGL_2_D:Distance

  • 给定两个不相交线段,求两个线段最近距离
  • 很明显,最近距离就是两个端点到另一个线段的距离.
  • 那么两遍点到线段距离就出来了.
    • 点到线段距离有三种
    • 第一种是点在线段正上方,则距离为过点向线段作垂线
    • 第二种是点在左侧,就是左端点和该点连线
    • 第三种同第二种,不过在右侧
double dian_dao_xianduan(Segment l, point c) //点到线段的距离
{
    double L = changdu(l.b - l.a);
    double r = dianji(l.b - l.a, c - l.a) / (L * L);

    if (zhengfu(r) == -1) {
        return changdu(c - l.a);
    } else if (dayu_dengyu(r, 1)) {
        return changdu(c - l.b);
    } else {
        double L = r * changdu(l.b - l.a), l2 = changdu(c - l.a);
        return sqrt(l2 * l2 - L * L);
    }
}
double xianduanjuli(Segment l1,Segment l2) //两线段距离
{
    if (xianduan_xiangjiao(l1,l2))
        return 0.0;
    double minn = inf;
    double l = dian_dao_xianduan(l1, l2.a);
    minn = dayu_dengyu(minn, l) ? l : minn;
    l = dian_dao_xianduan(l1, l2.b);
    minn = dayu_dengyu(minn, l) ? l : minn;
    l = dian_dao_xianduan(l2, l1.a);
    minn = dayu_dengyu(minn, l) ? l : minn;
    l = dian_dao_xianduan(l2, l1.b);
    minn = dayu_dengyu(minn, l) ? l : minn;
    return minn;
}

{%endfold%}

CGL_3_A:Area

计算多边形面积的方法蛮多的.
最暴力的当属以原点和多边形临近两点构成三角形,然后计算三角形的有向面积.
多边形内外符号不同,最后留下的就是多边形面积,然后fabs一下就完事了.这个地方建议"脑洞大开"或者拿纸画画.
不过要是会三角剖分的话,把多边形按顶点分割成一堆三角形,然后求面积也阔以.

double duobianxingmianji(int n) //多边形面积
{
    double ans = 0;
    for (int i = 1; i <= n; i++)
        ans += chaji(p[i], p[(i + 1) % n]);
    ans = fabs(ans) * 0.5;
    return ans;
}

{%endfold%}

CGL_3_B:Is-Convex

问所给的多边形是不是凸的.
题目给的方法是计算内角和.
嘛,感觉好麻烦的亚子.
还不如暴力求个凸包,看看所给的多边形的点数是不是和凸包点数相同来的快.

void Andrew(int& tail)  //求凸包
{
    sort(p + 1, p + 1 + n);
    tail = 1;
    q[1] = p[1];
    for (int i = 2; i <= n; i++) {
        while (tail > 1 && xuanzhuan(q[tail - 1], q[tail], p[i]) < 0)
            tail--;
        q[++tail] = p[i];
    }
    int basic = tail;
    for (int i = n - 1; i >= 1; i--) {
        while (tail > basic && xuanzhuan(q[tail - 1], q[tail], p[i]) < 0)
            tail--;
        q[++tail] = p[i];
    }
}

{%endfold%}

CGL_3_C:Polygon-Point Containment

就,判断点和多边形的位置关系.
看网上都是角度和或者射线法.
结果就让我找到一个看起来很\(nb\)的象限角度法?
不用考虑角度的精度问题,还不用像射线法考虑多??

bool zaibianshang(point& t,int n) //点在多边形边上否
{
    for (int i = 1; i <=n; i++)
        if (dian_zai_xianshang(Line(p[i], p[(i + 1)%n]), t))
            return 1;
    return 0;
}
bool duobianxingnei(point& t,int n) //点在多边形内
{
    int t1, t2, sum, i;
    double f;
    p[0] = p[n];
    for (i = 0; i <= n; i++)
        p[i] = p[i] - t; // 坐标平移
    t1 = p[0].x >= 0 ? (p[0].y >= 0 ? 0 : 3) : (p[0].y >= 0 ? 1 : 2); // 计算象限

    for (sum = 0, i = 1; i <= n; i++) {
        if (fabs(p[i].x)<eps && fabs(p[i].y)<eps)
            break;
        // 被测点为多边形顶点
        f = chaji(p[i - 1], p[i - 1]);

        // 计算叉积
        if (fabs(f)<eps && p[i - 1].x * p[i].x <= 0 && p[i - 1].y * p[i].y <= 0)
            break; // 点在边上
        t2 = p[i].x >= 0 ? (p[i].y >= 0 ? 0 : 3) : (p[i].y >= 0 ? 1 : 2); // 计算象限
        if (t2 == (t1 + 1) % 4)
            sum += 1;
        // 情况1
        else if (t2 == (t1 + 3) % 4)
            sum -= 1;
        // 情况2
        else if (t2 == (t1 + 2) % 4)
        // 情况3
            if (f > 0)
                sum += 2;
            else
                sum -= 2;
        t1 = t2;
    }
    bool tf = 0;
    if (i <= n || sum)
        tf = 1;
    for (i = 0; i <= n; i++)
        p[i] = p[i] + t; // 恢复坐标
    return tf;
}

{%endfold%}

CGL_4_A:Convex Hull

就是...求凸包
这里有个蛋疼的地方,要求是先排y再排x

void Andrew(int& tail)
{
    sort(p + 1, p + 1 + n);
    tail = 1;
    q[1] = p[1];
    for (int i = 2; i <= n; i++) {
        while (tail > 1 && xuanzhuan(q[tail - 1], q[tail], p[i]) < 0)
            tail--;
        q[++tail] = p[i];
    }
    int basic = tail;
    for (int i = n - 1; i >= 1; i--) {
        while (tail > basic && xuanzhuan(q[tail - 1], q[tail], p[i]) < 0)
            tail--;
        q[++tail] = p[i];
    }
}

{%endfold%}

CGL_4_B:Diameter of a Convex Polygon

找到凸包距离最远的一对点.
就是旋转卡壳嘛.\(O(n)\)复杂度嘛.

double tubao_zhijing(int tail) //求出凸包直径
{
    double re = 0;
    if (tail == 2) //仅有两个点
        return changdu(q[2] - q[1]);
    q[0] = q[tail]; //把最后的点放到最前面
    for (int i = 0, j = 2; i < tail; i++) //枚举边
    {
        while (xuanzhuan(q[i], q[i + 1], q[j]) < xuanzhuan(q[i], q[i + 1], q[j + 1]))
            j = (j + 1) % tail;
        re = max(re, max(changdu(q[j] - q[i]), changdu(q[j] - q[i + 1])));
    }
    return re;
}

{%endfold%}

CGL_4_C:Convex Cut

用一条直线切割凸包,输出得到图形的坐标.
就是逆时针找交点,按照直线的方向,\(\overrightarrow{p_1p_2}\),先放入靠近\(p_2\)的点,然后按照叉积,向左旋转的放入点.

int zhixian_xianduan_xiangjiao(Line l1, Segment l2) //直线与线段是否有交点
{
    double c1 = chaji(l1.b - l1.a, l2.a - l1.a), d1 = chaji(l1.b - l1.a, l2.b - l1.a);
    if (zhengfu(c1) == 0 && zhengfu(d1) == 0) { //重合
        return -1;
    } else if (zhengfu(c1 * d1) <= 0) //有交点
        return 1;
    return 0; //平行
}
void qiegetubao(Line l)
{
    int tail = 0;
    q[0] = q[n];
    int tf = -1, x;
    for (int i = 0; i < n; i++) {
        if (zhengfu(xuanzhuan(l.a,l.b,q[i])) == 1)
            p[++tail] = q[i];
        int f = zhixian_xianduan_xiangjiao(l,Segment( q[i], q[i + 1]));

        if (f == 1) {
            tf = 1;
            p[++tail] = zhixian_xianduan_jiaodian(l, Segment(q[i], q[i + 1]));
        } else if (f == -1) {
            tf = 0;
            x = i;
            break;
        }
    }
    if (tf == 0) {
        //cout<<q[x+1]<<' '<<q[x]<<' '<<endl;
        if (zhengfu(dianji(l.b - l.a, q[x + 1] - q[x])) == -1)
            printf("%.8f\n", 0.0);
        else {
            for (int i = 1; i <= n; i++)
                p[i] = q[i];
            printf("%.8f\n", duobianxingmianji(n));
        }
    } else {
        /*for (int i = 1; i <= tail; i++)
            cout << p[i] << endl;*/
        printf("%.8f\n", duobianxingmianji(tail));
    }
    q[0] = point(0, 0);
}

{%endfold%}

CGL_5_A:Closest Pair

在空间内找到最近的点对
分治,建议到洛谷上搜索"平面最近点对(加强版)"

double solve(int l, int r)
{
    if (l == r)
        return inf;
    int mid = (l + r) >> 1;

    double ans = solve(l, mid);
    ans = min(ans, solve(mid + 1, r));

    int tot = 0;
    for (int i = l; i <= r; i++)
        if (fabs(p[mid].x - p[i].x) <= ans)
            temp[tot++] = p[i];

    sort(temp,temp+tot, cmp);

    for (int i = 0; i < tot; i++)
        for (int j = i + 1; j <tot; j++) {
            if (temp[j].y - temp[i].y > ans)
                break;
            ans = min(ans, changdu(temp[j] - temp[i]));
        }
    return ans;
}

{%endfold%}

CGL_6_A:Segment Intersections: Manhattan Geometry

扫描线算法,例题可在洛谷上搜索"扫描线"
求平面\(n\)条线段的交点个数.
有空单开一章来整理这个算法.

struct SegTree {
    int l, r;
    ll len;
    //  sum: 被完全覆盖的次数;
    //  len: 区间内被截的长度。
} tree[MAXN << 2];
 
void build_tree(int x, int l, int r)
{
    tree[x].l = l, tree[x].r = r;
    tree[x].len = 0;
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    build_tree(lson(x), l, mid);
    build_tree(rson(x), mid + 1, r);
    return;
}
 
void pushup(int x)
{
    tree[x].len = tree[x << 1].len + tree[x << 1 | 1].len;
    //      合并儿子信息
}
 
void edit_tree(int x, ll id, int c)
{
    int l = tree[x].l, r = tree[x].r;
    if (l == id && id == r) {
        tree[x].len += c;
        return;
    }
    int mid = (l + r) >> 1;
    if (id <= mid)
        edit_tree(lson(x), id, c);
    else
        edit_tree(rson(x), id, c);
    pushup(x);
}
 
int query(int x, int L, int R)
{
    int l = tree[x].l, r = tree[x].r;
    if (L <= l && r <= R)
        return tree[x].len;
    int mid = (l + r) >> 1;
    int res = 0;
    if (L <= mid)
        res += query(lson(x), L, R);
    if (R > mid)
        res += query(rson(x), L, R);
    return res;
}
vector<Line> l;
vector<int> X;
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        point a, b;
        cin >> a >> b;
        if (a.x != b.x) {
            if (a.x > b.x)
                swap(a, b);
            X.push_back(a.x), X.push_back(b.x);
            l.push_back(Line(a, b, 2));
        } else {
            if (a.y > b.y)
                swap(a, b);
            X.push_back(a.x);
            l.push_back(Line(a, a, 1));
            l.push_back(Line(b, b, 3));
        }
    }
     
    sort(l.begin(), l.end());
    sort(X.begin(), X.end());
 
    n = unique(X.begin(), X.end()) - X.begin(); //去重
    X.erase(X.begin() + n, X.end());
    if(n==1){
        cout<<0<<endl;
        return 0;
    }
    build_tree(1, 1, n); //根据X[]的坐标建立线段树
 
    int ans = 0;
    for (int i = 0; i < l.size(); i++) {
        if (l[i].mark!=2) {
            int id = lower_bound(X.begin(), X.end(), l[i].a.x) - X.begin();
            int c = l[i].mark == 3 ? -1 : 1;
            edit_tree(1, id+1, c);
        } else {
            int id1 = lower_bound(X.begin(), X.end(), l[i].a.x) - X.begin();
            int id2 = lower_bound(X.begin(), X.end(), l[i].b.x) - X.begin();
            ans += query(1, id1+1, id2+1);
        }
    }
    printf("%d\n", ans);
    return 0;
}

{%endfold%}

CGL_7_A:Intersection

求圆的切线个数

int yuan_yuan_xiangjiao(cirles a, cirles b) //询问圆和圆的切线个数
{
    double l = changdu(b.o - a.o);
    if (bijiao(l, a.r + b.r) == 1)
        return 4;
    else if (bijiao(l, a.r + b.r) == 0)
        return 3;
    else {
        if (bijiao(l + min(a.r, b.r), max(a.r, b.r)) == 1)
            return 2;
        else if (bijiao(l + min(a.r, b.r), max(a.r, b.r)) == 0)
            return 1;
        else
            return 0;
    }
}

{%endfold%}

CGL_7_D:Cross Points of a Circle and a Line

求圆和直线的交点.
建议阅读"挑战程序设计竞赛2"

pair<point, point> zhixian_yuan_jiaodian(Line l, cirles a) //求直线与圆交点
{
    if (dayu_dengyu(a.r, zhixian_yuanxin_juli(l, a))) {
        vec a_i = touying(l, a.o);
        double L = changdu(l.b - l.a);
        double lt = changdu(a.o - a_i);
        double lr = sqrt(a.r * a.r - lt * lt);
        vec p = (l.b - l.a) / L * lr + a_i;
        return make_pair(a_i - (l.b - l.a) / L * lr, a_i + (l.b - l.a) / L * lr);
    } else
        return make_pair(0, 0);
}

{%endfold%}

CGL_7_E:Cross Points of Circles

求两个圆交点
建议阅读"挑战程序设计竞赛2"

pair<vec, vec> yuan_yuan_jiaodian(cirles a, cirles b) //求圆和圆的交点
{
    double l = changdu(a.o - b.o);
    double x = acos((a.r * a.r + l * l - b.r * b.r) / (2.0 * a.r * l));
    double t = atan2((b.o - a.o).y, (b.o - a.o).x);
    return make_pair(a.o + vec(cos(t - x) * a.r, sin(t - x) * a.r), a.o + vec(cos(x + t) * a.r, sin(t + x) * a.r));
}

{%endfold%}

CGL_7_F:Tangent to a Circle

过一个点做圆的切线
根据半径和圆心到点的距离求出夹角,旋转角度,得到交点

pair<point, point> guodian_yuan_qiedian(cirles a, point p) //过一点做圆的切线求切点
{
    double l = changdu(a.o - p);
    double t = asin(a.r / l);
    double lb = l * cos(t);
    vec x = a.o - p;
    x = x / l * lb;
    return make_pair(p + xiangliang_xuanzhuan(x, t), p + xiangliang_xuanzhuan(x, -t));
}

{%endfold%}

CGL_7_G:Common Tangent

求两个圆的公切线
根据圆和圆的位置进行判断

int yuanyuan_gongqiexian(cirles a, cirles b, point* u, point* v) //求圆和圆公切线以及切线个数
{
    int cnt = 0;
    if (a.r < b.r) {
        swap(a, b);
        swap(u, v);
    }
    double l = changdu(a.o - b.o);
    double rdiff = a.r - b.r;
    double rsum = a.r + b.r;
    if (zhengfu(l - rdiff) < 0)
        return 0;
    double base = atan2((b.o - a.o).y, (b.o - a.o).x);
    if (zhengfu(l) == 0)
        return -1;
    if (zhengfu(l - rdiff) == 0) {
        u[cnt] = v[cnt] = a.Point(base);
        cnt++;
        return 1;
    }
    double ang = acos((a.r - b.r) / l);
    u[cnt] = a.Point(base + ang);
    v[cnt] = b.Point(base + ang);
    cnt++;
    u[cnt] = a.Point(base - ang);
    v[cnt] = b.Point(base - ang);
    cnt++;
    if (zhengfu(l - rsum) == 0) {
        u[cnt] = v[cnt] = a.Point(base);
        cnt++;
    } else if (zhengfu(l - rsum) > 0) {
        double ang = acos((a.r + b.r) / l);
        u[cnt] = a.Point(base + ang);
        v[cnt] = b.Point(pi + base + ang);
        cnt++;
        u[cnt] = a.Point(base - ang);
        v[cnt] = b.Point(pi + base - ang);
        cnt++;
    }
    return cnt;
}

{%endfold%}

CGL_7_H:Intersection of a Circle and a Polygon

求多边形和圆相交的面积
将多边形的边的顶点与圆心连接行成三角形.
那么面积便是三角形在圆内的有向面积.
对每个三角形在圆内进行判断来计算.

point zhixian_zhixian_jiaodian(Line l1, Line l2) //两直线交点
{
    double t = ((l1.a.x - l2.a.x) * (l2.a.y - l2.b.y) - (l1.a.y - l2.a.y) * (l2.a.x - l2.b.x)) / ((l1.a.x - l1.b.x) * (l2.a.y - l2.b.y) - (l1.a.y - l1.b.y) * (l2.a.x - l2.b.x));
    return l1.a + (l1.b - l1.a) * t;
}

point xianduan_duandian_dian(point p, Segment l) //线段距离点p最近的端点
{
    point t = p;
    t.x += l.a.y - l.b.y;
    t.y += l.b.x - l.a.x;
    if (chaji(l.a - p, t - p) * chaji(l.b - p, t - p) > eps)
        return changdu(p - l.a) < changdu(p - l.b) ? l.a : l.b;
    return zhixian_zhixian_jiaodian(Line(p, t), l);
}

double distp(Line l) //长度的平方
{
    return (l.a.x - l.b.x) * (l.a.x - l.b.x) + (l.a.y - l.b.y) * (l.a.y - l.b.y);
}
double yuanxin_dian_sanjiao(Line l, cirles c) //求圆心与两点所成三角形有向面积
{
    double sign = 1.0;
    l.a = l.a - c.o;
    l.b = l.b - c.o;
    c.o = point(0.0, 0.0);
    if (fabs(chaji(l.a - c.o, l.b - c.o)) < eps)
        return 0.0;
    if (distp(Line(l.a, c.o)) > distp(Line(l.b, c.o))) {
        swap(l.a, l.b);
        sign = -1.0;
    }
    if (distp(Line(l.a, c.o)) < c.r * c.r + eps) { //a在圆内
        if (distp(Line(l.b, c.o)) < c.r * c.r + eps) //b也在圆内,返回叉积/2
            return chaji(l.a - c.o, l.b - c.o) / 2.0 * sign;
        point p1, p2;
        pair<point, point> q = zhixian_yuan_jiaodian(l, c); //oa和ob与圆的交点
        p1 = q.first;
        p2 = q.second;
        if (changdu(p1 - l.b) > changdu(p2 - l.b))
            swap(p1, p2);
        double ret1 = fabs(chaji(l.a - c.o, p1 - c.o));
        double ret2 = acos((p1.x * l.b.x + p1.y * l.b.y) / changdu(p1) / changdu(l.b)) * c.r * c.r;
        double ret = (ret1 + ret2) / 2.0;
        if (chaji(l.a - c.o, l.b - c.o) < eps && sign > 0.0 || chaji(l.a - c.o, l.b - c.o) > eps && sign < 0.0)
            ret = -ret;
        return ret;
    }
    point ins = xianduan_duandian_dian(c.o, l);
    if (distp(Line(c.o, ins)) > c.r * c.r - eps) {
        double ret = acos((l.a.x * l.b.x + l.a.y * l.b.y) / changdu(l.a) / changdu(l.b)) * c.r * c.r / 2.0;
        if (chaji(l.a - c.o, l.b - c.o) < eps && sign > 0.0 || chaji(l.a - c.o, l.b - c.o) > eps && sign < 0.0)
            ret = -ret;
        return ret;
    }
    point p1, p2;
    pair<point, point> q = zhixian_yuan_jiaodian(l, c); //oa和ob与圆的交点
    p1 = q.first;
    p2 = q.second;
    double cm = c.r / (changdu(c.o - l.a) - c.r);
    point m = point((c.o.x + cm * l.a.x) / (1 + cm), (c.o.y + cm * l.a.y) / (1 + cm));
    double cn = c.r / (changdu(c.o - l.b) - c.r);
    point n = point((c.o.x + cn * l.b.x) / (1 + cn), (c.o.y + cn * l.b.y) / (1 + cn));
    double ret1 = acos((m.x * n.x + m.y * n.y) / changdu(m) / changdu(n)) * c.r * c.r;
    double ret2 = acos((p1.x * p2.x + p1.y * p2.y) / changdu(p1) / changdu(p2)) * c.r * c.r - fabs(chaji(p1 - c.o, p2 - c.o));
    double ret = (ret1 - ret2) / 2.0;
    if (chaji(l.a - c.o, l.b - c.o) < eps && sign > 0.0 || chaji(l.a - c.o, l.b - c.o) > eps && sign < 0.0)
        ret = -ret;
    return ret;
}
double duobianxing_yuan_xiangjiao(cirles c, point p[], int n) //多边形与圆相交面积
{
    double sum = 0;
    for (int i = 0; i < n; i++)
        sum += yuanxin_dian_sanjiao(Line(p[i], p[i + 1]), c);
    return sum;
}

{%endfold%}

posted @ 2021-02-05 20:22  CrossAutomaton  阅读(266)  评论(0编辑  收藏  举报