计算几何_半平面交
题意:求是否存在一个平面,平面内的所有点能够旋转360度之后,能够扫到整个多边形,既可以是凹多边形,也可以是凸多边形~
接题报告:
求半交平面。
O(n^2)
用直线切割多边形,剩下的多边形就是半交平面。
POJ 1279:
竟然我拿 G++交了不过,拿C++能够过!!!
template:
#include "stdio.h"
#include "math.h"
#define N 1800
#define eps 1e-10
struct Point{
double x;
double y;
};
struct CC{
int n;
Point P[N];
};
double xmult(Point p0,Point p1,Point p2) //叉积
{
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
Point intersectL(double a1,double b1,double c1,double a2,double b2,double c2) //用两直线方程求两直线交点
{
Point p;
p.y=(a2*c1-a1*c2)/(b1*a2-b2*a1);
if(fabs(a2)<eps)
p.x=(p.y*b1-c1)/a1;
else
p.x=(p.y*b2-c2)/a2;
return p;
}
void Getline(Point p1,Point p2,double &a,double &b,double &c) //求直线方程
{
a=p2.y-p1.y;
b=p2.x-p1.x;
c=p1.y*(p2.x-p1.x)-p1.x*(p2.y-p1.y);
}
bool Isame(Point p1,Point p2) //点的判重
{
return fabs(p1.x-p2.x)<eps && fabs(p1.y-p2.y)<eps;
}
CC cut(Point A,Point B,CC rc) //直线AB顺时针方向切割多边形rc
{
CC ret;
double r1,r2,a1,b1,c1,a2,b2,c2;
ret.n=0;
for(int i=0;i<rc.n;i++)
{
r1=xmult(A,B,rc.P[i]);
r2=xmult(A,B,rc.P[i+1]);
if(r1<eps&&r2<eps) //当该线段在AB的顺时针方向时,说明该线段的端点都是切割后多边形的顶点
{ //这里要注意精度问题
ret.P[ret.n++]=rc.P[i];
ret.P[ret.n++]=rc.P[i+1];
}
else if(r1>eps&&r2>eps) //当该线段在AB的逆时针方向时,舍去该线段,判断下一条线段
continue;
else
{ //当该线段的端点在AB的两侧时要把顺时针方向上的端点及它们交点作为切割后的顶点
Getline(A,B,a1,b1,c1);
Getline(rc.P[i],rc.P[i+1],a2,b2,c2);
Point crospoint=intersectL(a1,b1,c1,a2,b2,c2);
if(r1<eps)
{
ret.P[ret.n++]=rc.P[i];
ret.P[ret.n++]=crospoint;
}
else
{
ret.P[ret.n++]=crospoint;
ret.P[ret.n++]=rc.P[i+1];
}
}
}
if(ret.n==0) //区域为空集
return ret;
int j=1;
for(int i=1;i<ret.n;i++) //排除重复点
if(!Isame(ret.P[i],ret.P[i-1]))
ret.P[j++]=ret.P[i];
ret.n=j;
if(ret.n!=1&&Isame(ret.P[ret.n-1],ret.P[0]))
ret.n--;
ret.P[ret.n]=ret.P[0];
return ret; // 返回切割后的区域
}
int main()
{
int test,v;
CC cp,ret;
scanf("%d",&test);
while(test--)
{
scanf("%d",&v);
for(int i=0;i<v;i++)
scanf("%lf%lf",&cp.P[i].x,&cp.P[i].y);
cp.P[v]=cp.P[0];
cp.n=v;
ret=cp;
for(int i=0;i<cp.n;i++)
ret=cut(cp.P[i],cp.P[i+1],ret); //枚举每条边切割当前的区域
double area=0.0;
for(int i=1;i<ret.n-1;i++)
area+=xmult(ret.P[0],ret.P[i],ret.P[i+1]); //叉积求面积
printf("%.2lf/n",fabs(area)/2.0);
}
return 0;
}