阴影部分就是这条直线的半平面。
形象的理解,多边形是一个房间,核是里面的一片区域,在这片区域里装摄像头,能监控到整个多边形。
只会S&I算法,当然这个算法也是最好的半平面交算法,好写,效率也很高。
由于本人太菜了,需要总结一下计算几何基础。
由于半平面交中直线是有向的,为了表示这样的直线,需要两个有序点对\(s=(x1,y1),\ t=(x2,y2)\),表示直线由\(s\)到\(t\)。此外半平面交中还需按极角排序,因此还需记录极角(一般规定极角为该直线正方向对应的射线与x轴正方向对应的射线的夹角)。
const eps = 1e-6;
int dcmp(double a, double b) { return fabs(a - b) < eps; }
按照上面这种表示法,求两条直线的交点应该是这样的(cross是向量叉积):
POINT inter(LINE a, LINE 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)); }
这个方法画图出来就很容易理解了。
判断一个点是否在直线右边:
int onright(POINT a, LINE b) { return cross(b.t - b.s, a - b.s) < 0; }
利用了有向面积的正负性判断。
poj3130 判断多边形是否有核
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef double db;
const int N = 57;
const db eps = 1e-6;
int dcmp(db a, db b) { return fabs(a - b) < eps; } //浮点数比较相等
struct VECTOR
{
db x, y;
VECTOR(db X = 0, db Y = 0) { x = X, y = Y; }
db getang() { return atan2(y, x); } //求极角
};
db cross(VECTOR a, VECTOR b) { return a.x * b.y - a.y * b.x; } //叉积
VECTOR operator+(VECTOR a, VECTOR b) { return VECTOR(a.x + b.x, a.y + b.y); } //基本向量运算
VECTOR operator-(VECTOR a, VECTOR b) { return VECTOR(a.x - b.x, a.y - b.y); }
VECTOR operator*(VECTOR a, db b) { return VECTOR(a.x * b, a.y * b); }
typedef VECTOR POINT;
struct LINE
{
POINT s, t;
db ang;
LINE() {}
LINE(POINT S, POINT T) { s = S, t = T, ang = (t - s).getang(); } //根据起点终点构造直线
};
int operator<(LINE a, LINE b) { return dcmp(a.ang, b.ang) ? cross(b.t - a.s, a.t - a.s) + eps > 0 : a.ang < b.ang; } //比较极角,极角相等时保证最左边的直线排的最前
POINT inter(LINE a, LINE 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)); } //计算两直线的交点
int onright(POINT a, LINE b) { return cross(b.t - b.s, a - b.s) < 0; } //判断一个点是否在某直线右边
int n;
POINT p[N];
LINE l[N];
int h, t;
LINE q1[N];
POINT q2[N];
int SI()
{
sort(l + 1, l + n + 1); //排序
h = 1, q1[t = 1] = l[1];
for (int i = 2; i <= n; i++)
{
if (dcmp(l[i].ang, l[i - 1].ang)) continue; //多条极角相同的直线,取最左边的一条
while (h < t && onright(q2[t - 1], l[i])) t--; //删掉队尾无用直线
while (h < t && onright(q2[h], l[i])) h++; //删掉队头无用直线
q1[++t] = l[i];
if (h < t) q2[t - 1] = inter(q1[t], q1[t - 1]); //加入交点
}
while (h < t && onright(q2[t - 1], q1[h])) t--; //最后检查
while (h < t && onright(q2[h], q1[t])) h++;
if (t - h <= 1) return 0; //半平面交上的点少于3个,无法构成多边形,该多边形的核不存在
return 1;
}
int main()
{
while (1)
{
scanf("%d", &n);
if (!n) break;
for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
l[1] = LINE(p[n], p[1]); //输入保证该线段左侧是多边形的内部,直接连线即可
for (int i = 2; i <= n; i++) l[i] = LINE(p[i - 1], p[i]);
printf(SI() ? "1\n" : "0\n");
}
return 0;
}
原文:https://www.cnblogs.com/zjlcnblogs/p/11116487.html