现在的位置: 首页 > 综合 > 正文

zoj 1081 Points Within[判断点在简单多边形内]

2017年05月25日 ⁄ 综合 ⁄ 共 2469字 ⁄ 字号 评论关闭

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=81

题目的很简单:给你一个多边形,再给你一系列的点,问你这些是否在多边形内。输出这些点与多边形的关系。。

学到了一种射线法判断点是否在多变型内。通过点在水平或者竖直引一条射线,看与多边形的交点个数。奇数就是在多边形内,偶数就是在多边形外。最开始,我是很怀疑这种方法的。主要还是射线穿过端点的情况。

对于上面的情况:

我们对于穿过端点的射线,交点算几次呢??我们这里只算一次。为了统一,我们要求这样来进行统计交点。

1.平行和重合于射线的多边形边不算。

2.对于相交于端点的交点,如果该点是该边的较高点(y值较大),算一次。。

基本上这样就可以了。。

Code:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

const int N = 105;
const double eps = 1e-8;
const double pi = acos(-1);
const double INF = 0x3f3f3f3f;
//点
struct POINT
{
    double x, y;
    POINT(){ }
    POINT(double a, double b){
        x = a;
        y = b;
    }
}p[N];
//线段
struct Seg
{
    POINT a, b;
    Seg() { }
    Seg(POINT x, POINT y){
        a = x;
        b = y;
    }
};
//直线
struct Line
{
    POINT a, b;
    Line() {}
    Line(POINT x, POINT y){
        a = x;
        b = y;
    }
};
//叉乘
double cross(POINT o, POINT a, POINT b)
{
    return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y);
}
//求两点间的距离
double dis(POINT a, POINT b)
{
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
int n, m, k;

//两条直线的位置关系,平行,重合和相交
int Line_cross(Seg l1, Seg l2)
{
    //两条直线平行
    if(fabs(cross(l1.a, l2.a, l2.b) - cross(l1.b, l2.a, l2.b)) < eps && fabs(cross(l1.a, l2.a, l2.b)) > eps) return 0;
    //重合..
    if(fabs(cross(l1.a, l2.a, l2.b)) < eps && fabs(cross(l1.b, l2.a, l2.b)) < eps) return 2;
    //有交点///
    return 1;
}

//判断点在线段上
bool On_Seg(POINT a, Seg s)
{
    if(fabs(cross(a, s.a, s.b)) > eps) return false;
    double maxx = max(s.a.x, s.b.x), minx = min(s.a.x, s.b.x);
    double maxy = max(s.a.y, s.b.y), miny = min(s.a.y, s.b.y);
    if(a.x >= minx && a.x <= maxx && a.y >= miny && a.y <= maxy) return true;
    return false;
}
//判断线段相交
bool Seg_cross(Seg s1, Seg s2)
{
    double cs1 = cross(s1.a, s2.a, s2.b);
    double cs2 = cross(s1.b, s2.a, s2.b);
    double cs3 = cross(s2.a, s1.a, s1.b);
    double cs4 = cross(s2.b, s1.a, s1.b);
    // 互相跨立
    if(cs1 * cs2 < 0 && cs3 * cs4 < 0) return true;
    if(On_Seg(s1.a, s2)) return true;
    if(On_Seg(s1.b, s2)) return true;
    if(On_Seg(s2.a, s1)) return true;
    if(On_Seg(s2.b, s1)) return true;
    return false;
}

bool PointInPolygon(POINT q)
{
    int cnt = 0;
    Seg s(q, POINT(INF, q.y));
    p[n] = p[0];
    for(int i = 0; i < n; i ++){
        if(On_Seg(q, Seg(p[i], p[i + 1]))) {
            return true;
        }
        //平行重合者不算...
        if(Line_cross(s, Seg(p[i], p[i + 1])) == 0 || Line_cross(s, Seg(p[i], p[i + 1])) == 2) continue;
        if(!Seg_cross(s, Seg(p[i], p[i + 1]))) continue;
        int on = -1;
        if(On_Seg(p[i], s)) on = i;
        if(On_Seg(p[i + 1], s)) on = i + 1;
        if(on != -1){
            if(fabs(p[on].y - max(p[i].y, p[i + 1].y)) < eps)
            cnt ++;
        }
        else cnt ++;
    }
    return cnt % 2;
}
int main()
{
//    freopen("11.txt", "r", stdin);
    k = 1;
    while(scanf("%d", &n) && n){
        scanf("%d", &m);
        for(int i = 0; i < n; i ++){
            scanf("%lf %lf", &p[i].x, &p[i].y);
        }
        if(k != 1) puts("");
        printf("Problem %d:\n", k ++);
        for(int i = 0; i < m; i ++){
            POINT test;
            scanf("%lf %lf", &test.x, &test.y);
            if(PointInPolygon(test)) puts("Within");
            else puts("Outside");
        }
    }
    return 0;
}

----->

又学习了。。


抱歉!评论已关闭.