Half plane cross Notes

What is the half-plane cross

  • One directed straight into two parts would plane, when a predetermined counterclockwise direction as a positive direction, the directional linear counterclockwise half-plane that is a plane of this line.

Hatched portion is a half-plane of this line.

  • Given several pieces directed straight later and a predetermined positive direction, the intersection of these half-plane linear half-plane is the straight lines cross.

Half-plane cross used to do

  • Is given a polygonal, seeking its core. Nuclear is a convex polygon within the polygon, each point in the nucleus can be seen in every corner of the polygon. Corresponds to the nuclear point connection with any point on the polygon are within the polygon.

Image understanding, the polygon is a room, which is the core of an area, put the camera in this area where, to be able to monitor the entire polygon.

Seeking post half plane

S & I only method, of course, this algorithm is the best half-plane intersection algorithm, good writing, efficiency is very high.

Computational Geometry foundation

Because I too dishes, you need to sum up the basic computational geometry.

Linear representation

Since the half-plane is a straight line in the cross direction, in order to express such a straight line, two points of the ordered \ (S = (X1, Y1), \ T = (X2, Y2) \) , represented by the straight line \ ( S \) to \ (T \) . Further half-plane cross-polar angle by the need to sort, so the need to record a polar angle (polar angle generally corresponding to a predetermined angle for the positive direction of the x-ray linear axis positive direction corresponding to the radiation).

Floating-point comparison

const eps = 1e-6;
int dcmp(double a, double b) { return fabs(a - b) < eps; }

Line intersection

According to the above this notation, the intersection of two straight lines seeking should be such (cross is a vector cross product):

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)); }

This method of drawing out the very easy to understand.

In the left or the right straight

Is a point in the right line:

int onright(POINT a, LINE b) { return cross(b.t - b.s, a - b.s) < 0; }

Using a negative judgment directed area.

Into the title

S & algorithm general steps I

  • The polar angle in accordance with input straight from small to large order
    Tips: polar angle size of some of the line is equal, if the counter-clockwise direction is positive, then clearly the right location is more of a straight line is of no use, then we retain only the leftmost straight .
  • 开两个双端队列q1,q2,q1用来存半平面交上的直线,q2用来存半平面交上的点。
  • 将第一条直线加入q1。
  • 依次加入每条直线l[i],若q1中直线个数>1,则比较q2末尾的点是否在l[i]右边,是则弹出q1队尾的直线以及q2队尾的点,如此循环,直到不能删为止。
  • 若q1中直线个数>1,则比较q2队头的点是否在l[i]右边,是则弹出q1队头的直线以及q2队头的点,如此循环,直到不能删为止。
  • 将l[i]入队,算出l[i]与q1队尾直线的交点,将该交点加入q2队尾。
  • 做完所有直线以后,检查q2队尾的点是否在q1队头直线右边,是则弹出q1队尾的直线以及q2队尾的点,如此循环,直到不能删为止。
  • 检查q2队头的点是否在q1队尾直线右边,是则弹出q1队头的直线以及q2队头的点,如此循环,直到不能删为止。
  • 此时q1中的直线即为半平面交的每条边,q2即为半平面交上的点(还要加上最后加入的直线与最早加入的直线的交点)。

流程解释

  • 为什么要排序?
    排序后我们就是在逆时针地加入每条直线,这样直线间关系就存在了单调性,保证了后面过程的正确性。
  • 为什么要用双端队列?
    因为求半平面交的过程实际上是环形的,新加入的直线不仅会影响到最后加入的直线,也会影响到最早加入的直线。

    依次加入直线AB,直线CD,直线EF,直线HG
    AB,CD的交点在HG右侧,那么此时最早加入的直线AB已无用处,将它出队。

代码

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;
}

一道例题 from SDOI2013

Guess you like

Origin www.cnblogs.com/zjlcnblogs/p/11116487.html