半平面交
一条直线将平面分为两个半平面
直线是有向的,不妨规定每条直线取沿直线方向的左边作为半平面
n条直线左边的半平面的交就是半平面交
半平面交的结果是一个凸多边形,由顶点表示,当然特殊情况的话可能无界,为一个点、线段、空等
形象的比喻:相当于一块蛋糕你不断的用刀切,舍弃刀右边的部分,最后剩下的一块就是半平面交的结果
多边形的核
凸多边形的核就是本身,其他多边形的核是所有边的半平面交的结果
如何算半平面交
首先先引入有向直线的定义
struct Line
{
Point p;
Vector v;
double ang;
Line (){}
Line (Point p,Vector v):p(p),v(v) { ang=atan2(v.y,v.x); }
bool operator < (const Line &L) const {
return ang<L.ang;
}
}; // 由一个点和一个方向向量组成
这里提供两个算法:
O(N^2)的算法
大概思路
枚举多边形的每一条边(不妨设他为AB),算出这条直线切割后的多边形,然后继续用下一条边切割这个剩下的多边形,最后切割完成的多边形就是核
那么如何算出每条直线切割之后的多边形呢?
1.点在直线的左边 -> 添加进多边形
2.如果两条直线AB和CD有交点,且这个交点在线段CD上,那么把交点加入到多边形中
代码如下
polygon CutPolygon(polygon poly2, Point A,Point B)//用有向直线去切割多边形
{
polygon newpoly;
int m = 0,n = poly2.sz;
for(int i = 0; i < n; i++)
{
Point C = poly2.a[i], D = poly2.a[(i+1)%n];//切割如下图
if(dcmp(Cross(B-A, C-A)) >= 0) newpoly.a[m++] = C;
if(dcmp(Cross(B-A, C-D)) != 0) {
Point ip = GetIntersection(A, B-A, C, D-C);
if(OnSegment(ip, C, D)) newpoly.a[m++] = ip;//判断ip是不是在线段CD上
}
}
newpoly.sz = m;
return newpoly;
}
double Get_Kernel(polygon poly)
{
polygon knl;
knl.a[0] = Point(-INF,-INF); knl.a[1] = Point(INF,-INF);
knl.a[2] = Point(INF,INF); knl.a[3] = Point(-INF,INF);
knl.sz = 4; //初始大平面
for(int i = 0; i < poly.sz; i++) //不停地用多边形的边去切割平面
{
Point A = poly.a[i], B = poly.a[(i+1)%poly.sz];
knl = CutPolygon(knl,A,B);
}
double ans = 0;//求核的面积,可以自己修改
for(int i = 0; i < knl.sz; i++)
ans += area(knl.a[i], knl.a[(i+1)%knl.sz]);
return ans;
}
O(NlogN)的算法
占坑 明天补