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

zoj1081判断点是否在多边形内

2013年12月03日 ⁄ 综合 ⁄ 共 2452字 ⁄ 字号 评论关闭

首先判断要检测的点是否在边上

然后再判断射线是否经过一个线段的端点,如果经过低端点不计数,经过高端点计数

#include <vector>
#include <string>
#include <iostream>
#include <cmath>
#include <stdio.h>

using namespace std;

const double eps = 1e-10;

const int N = 103;

bool lessEqual(double a, double b) {//<=
    return a < b + eps;
}

bool largerEqual(double a, double b) {// >=
    return a + eps > b;
}

bool equal(double a, double b) {
    return fabs(a-b) < eps;
}


struct point {
    double x;
    double y;

    point(){}
    point(double a, double b) :x(a),y(b) {}
};

point ps[N];
int num;
int m;

//(b-a)X(c-a)
//如果b在c的右手边,为正;
//b在c的左手边,为负
//a,b,c共线,0
double x_multi(point &a, point &b, point &c) {
    return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
}

//(b-a)X(c-a)
//夹角小于90,正
//大于90,负
//等于90,0
double dot_multi(point &a, point &b, point &c) {
    return (b.x - a.x) * (c.x - a.x) + (b.y - a.y) * (c.y - a.y);
}

bool onSegment(point &a, point &b, point &c) {//c点是否在线段ab之间
    double max_x = max(a.x, b.x);
    double max_y = max(a.y, b.y);
    double min_x = min(a.x, b.x);
    double min_y = min(a.y, b.y);

    
    
    if (equal(x_multi(a,b,c),0.0) && lessEqual(c.x,max_x) && largerEqual(c.x, min_x) && lessEqual(c.y, max_y) && largerEqual(c.y, min_y))
        return true;
    return false;
}

bool onLine(point &a, point &b, point &c) {//已知a,b,c共线
    double max_x = max(a.x, b.x);
    double max_y = max(a.y, b.y);
    double min_x = min(a.x, b.x);
    double min_y = min(a.y, b.y);

    if (lessEqual(c.x,max_x) && largerEqual(c.x, min_x) && lessEqual(c.y, max_y) && largerEqual(c.y, min_y))
        return true;
    return false;
}

bool segmentIntersect(point &a, point &b, point &c, point &d) {//两条线段是否相交
    double d1 = x_multi(a,b,d);
    double d2 = x_multi(a,b,c);
    double d3 = x_multi(c,d,a);
    double d4 = x_multi(c,d,b);

    if (d1*d2 < 0 && d3 * d4 <0)
        return true;

    if (equal(d1,0.0) && onLine(a,b,d))
        return true;
    if (equal(d2,0.0) && onLine(a,b,c))
        return true;
    if (equal(d3,0.0) && onLine(c,d,a))
        return true;
    if (equal(d4,0.0) && onLine(c,d,b))
        return true;
    return false;
}

bool isInside(point &pt) {
    int count = 0;
    point end(1e9,pt.y);
    for (int i = 0; i < num; ++i) {
        int j = (i+1)%num;
        if (onSegment(ps[i], ps[j], pt))
            return true;
        if (!equal(ps[i].y, ps[j].y)) {
            point low = ps[i];
            if (low.y > ps[j].y)
                low = ps[j];
            if (onSegment(pt,end,low))//较低端点不计算
                continue;
            if (segmentIntersect(pt,end,ps[i],ps[j]))
                ++count;
            /*int tmp = -1;
            if (onSegment(pt,end,ps[i]))
                tmp = i;
            else if (onSegment(pt,end,ps[j]))
                tmp = j;
            if(tmp != -1 && equal(ps[tmp].y, max(ps[i].y,ps[j].y)))
                ++count;
            else if (tmp == -1 && segmentIntersect(ps[i],ps[j],pt,end))
                ++count;*/
        }
    }
    
    return count % 2==1;    
}

int main() {
    int ind = 1;
    while (scanf("%d", &num) && num !=0) {
        scanf("%d", &m);
       
        for (int i = 0; i < num ; ++i){
            scanf("%lf%lf",&ps[i].x, &ps[i].y);
           
        }
        if (ind !=1)
            cout<<endl;
        cout<<"Problem "<<ind<<":"<<endl;
        ++ind;
        for (int i = 0; i < m; ++i) {
            point pt;
            scanf("%lf%lf", &pt.x, &pt.y);
           
            if (isInside(pt))
                cout<<"Within"<<endl;
            else
                cout<<"Outside"<<endl;
                
        }
        
        
    }
}

抱歉!评论已关闭.