Bobo 有一个三角形和一个矩形,他想求他们交的面积。
具体地,三角形和矩形由 8 个整数 x
1,y
1,x
2,y
2,x
3,y
3,x
4,y
4 描述。 表示三角形的顶点坐标是 (x
1,y
1),(x
1,y
2),(x
2,y
1), 矩形的顶点坐标是 (x
3,y
3),(x
3,y
4),(x
4,y
4),(x
4,y
3).
输入包含不超过 30000 组数据。
每组数据的第一行包含 4 个整数 x
1,y
1,x
2,y
2 (x
1≠x
2,y
1≠y
2).
第二行包含 4 个整数 x
3,y
3,x
4,y
4 (x
3<x
4,y
3<y
4).
(0≤x
i,y
i≤10
4)
1 1 3 3 0 0 2 2 0 3 3 1 0 0 2 2 4462 1420 2060 2969 4159 257 8787 2970
1.00000000 0.75000000 439744.13967527
思路:用半平面交模版即可。注意初始向量的方向。
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
struct Point
{
double x,y;
}tri[4],rec[5],ch[10];
struct Line
{
Point p; //直线上任意一点
Point v; //直线方向向量
double angle; //极角
Line(){}
Line(Point p,Point v):p(p),v(v){angle=atan2(v.y,v.x);}
bool operator<(const Line& L)const{return angle<L.angle;}
}L[10];
Point Vector(Point a,Point b) //求向量a-b
{
Point c;
c.x=a.x-b.x;
c.y=a.y-b.y;
return c;
}
double cross(Point a,Point b) //叉积
{
return (a.x*b.y-a.y*b.x);
}
bool Onleft(Line L,Point p){return cross(L.v,Vector(p,L.p))>0;} //点P在有向直线L的左边(线上不算)
Point Getinter(Line a,Line b)
{
Point u=Vector(a.p,b.p);
double t=cross(b.v,u)/cross(a.v,b.v);
return (Point){a.p.x+a.v.x*t,a.p.y+a.v.y*t};
}
int Half(Line *L,int n,Point *poly)
{
sort(L,L+n);
int first,last;
Point *p=new Point[n];
Line *q=new Line[n];
q[first=last=0]=L[0];
for(int i=1;i<n;i++)
{
while(first<last&&!Onleft(L[i],p[last-1]))last--;
while(first<last&&!Onleft(L[i],p[first]))first++;
q[++last]=L[i];
if(fabs(cross(q[last].v,q[last-1].v))<1e-7)
{
last--;
if(Onleft(q[last],L[i].p))q[last]=L[i];
}
if(first<last)p[last-1]=Getinter(q[last-1],q[last]);
}
while(first<last&&!Onleft(q[first],p[last-1]))last--; //删除无用面
if(last-first<=1)return 0; //空集
p[last]=Getinter(q[last],q[first]);
int m=0;
for(int i=first;i<=last;i++)poly[m++]=p[i];
return m;
}
double Polyarea(Point *p,int n) //求多边形面积(任意形状都可)
{
double area=0;
for(int i=1;i<n-1;i++)
{
area+=cross(Vector(p[i],p[0]),Vector(p[i+1],p[0]));
}
return area/2;
}
int cmp1(const Point &x,const Point& y)
{
if(x.x==y.x)return x.y<y.y;
return x.x<y.x;
}
int cmp2(const Point &x,const Point& y)
{
if(x.x==y.x)return x.y>y.y;
return x.x<y.x;
}
int main()
{
double x1,y1,x2,y2,x3,y3,x4,y4;
while(scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2)!=EOF)
{
tri[0].x=x1,tri[0].y=y1;
tri[1].x=x1,tri[1].y=y2;
tri[2].x=x2,tri[2].y=y1;
if(x2>x1)sort(tri,tri+3,cmp2);
else sort(tri,tri+3,cmp1); //让点按逆时针排序
scanf("%lf%lf%lf%lf",&x3,&y3,&x4,&y4);
rec[0].x=x3,rec[0].y=y3;
rec[1].x=x4,rec[1].y=y3;
rec[2].x=x4,rec[2].y=y4;
rec[3].x=x3,rec[3].y=y4;
int n=0;
for(int i=0;i<3;i++)L[n++]=Line(tri[i],Vector(tri[(i+1)%3],tri[i]));
for(int i=0;i<4;i++)L[n++]=Line(rec[i],Vector(rec[(i+1)%4],rec[i]));
int m=Half(L,n,ch);
printf("%0.8lf\n",Polyarea(ch,m));
}
return 0;
}