Modern graphic computer programs can, among other, even more stunning capabilities, fill a closed region. Though not all of them can protect the user from accidentally choosing to fill the background rather than the inner part. Besides being a channel hopper at home your boss' favourite hobby is colouring the pictures, you cannot protest long about adding this magnificent protection feature to his graphic program.
This means that your job is to write a program, which determines whether a point belong to a polygon, given the array of its vertices.
To make life a bit simpler you may assume that:
4 1 1 1 3 3 3 3 1 2 2 12 1 1 1 9 3 9 3 5 5 5 5 9 7 9 7 1 5 1 5 3 3 3 3 1 4 2 0
T F
//用之前分析写的射线法 、角度和法和 改进弧长法 判断点是否在任意多边形内的程序都AC了此题,对自己写的射线法精确度有了更大的信心!
//射线法
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<cstdlib> #include<queue> #include<stack> #include<map> #include<vector> #include<algorithm> using namespace std; #define maxn 10005 #define eps 1e-8 #define max(x,y) (x>y?x:y) #define min(x,y) (x<y?x:y) struct point { double x,y; }; int n; point p0,p[maxn]; int Fabs(double d) { if(fabs(d)<eps) return 0; else return d>0?1:-1; } double x_multi(point p1,point p2,point p3) { return (p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y); } bool Onsegment(point p1,point p2,point p3) { double min_x=min(p1.x,p2.x); double min_y=min(p1.y,p2.y); double max_x=max(p1.x,p2.x); double max_y=max(p1.y,p2.y); if(p3.x>=min_x&&p3.x<=max_x&&p3.y>=min_y&&p3.y<=max_y) return true; return false; } bool Is_intersected(point p1,point p2,point p3,point p4) { double d1=x_multi(p1,p2,p3); double d2=x_multi(p1,p2,p4); double d3=x_multi(p3,p4,p1); double d4=x_multi(p3,p4,p2); if(d1*d2<0.0&&d3*d4<0.0) return true; // if(d1==0.0&&Onsegment(p1,p2,p3)) // return true; if(d2==0.0&&Onsegment(p1,p2,p4)) return true; if(d3==0.0&&Onsegment(p3,p4,p1)) return true; if(d4==0.0&&Onsegment(p3,p4,p2)) return true; return false; } double Dot(point p1,point p2,point p3) { return (p2.x-p1.x)*(p3.x-p1.x)+(p2.y-p1.y)*(p3.y-p1.y); } int pointonsegment(point p1,point p2,point p3) { return Fabs(x_multi(p1,p2,p3))==0&&Fabs(Dot(p1,p2,p3))<=0; } bool point_is_inside() //射线法判读点是否在多边形内 { int i,num=0; point p1,p2,p3; p1.x=999999999.0,p1.y=p0.y; for(i=0;i<n;i++) { if(p[i].y==p[(i+1)%n].y) { if(pointonsegment(p0,p[i],p[(i+1)%n])) return true; } else { p2=p[i],p3=p[(i+1)%n]; if(p2.y>p3.y) swap(p2,p3); if(Is_intersected(p0,p1,p2,p3)) num++; } } return num%2==1; } int main() { int i,j; while(scanf("%d",&n),n) { for(i=0;i<n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); scanf("%lf%lf",&p0.x,&p0.y); if(point_is_inside()) puts("T"); else puts("F"); } return 0; }
//角度和法
double x_multi(point p1,point p2,point p3) { return (p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y); } double Len_ab(point p1,point p2) { return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); } double Dot(point p1,point p2,point p3) { return (p2.x-p1.x)*(p3.x-p1.x)+(p2.y-p1.y)*(p3.y-p1.y); } int pointonsegment(point p1,point p2,point p3) { return Fabs(x_multi(p1,p2,p3))==0&&Fabs(Dot(p1,p2,p3))<=0; } bool point_is_inside() { int i; double sum=0.0; for(i=0;i<n;i++) { if(p0==p[i]) //点在多边形端点上 return true; if(p[i]==p[(i+1)%n]) //去重点 continue; if(pointonsegment(p0,p[i],p[(i+1)%n])) //点在多边形边上 return true; double a=Len_ab(p0,p[i]); double b=Len_ab(p0,p[(i+1)%n]); double c=Len_ab(p[i],p[(i+1)%n]); sum+=Fabs(x_multi(p0,p[i],p[(i+1)%n]))*acos((a*a+b*b-c*c)/(2.0*a*b)); //计算角度和,叉积大于0则加上,小于0则减去 } sum=fabs(sum); if(Fabs(sum-2.0*pi)==0) return true; return false; }
//改进弧长法:
int get_tmp(point p1) { return p1.x>=0?(p1.y>=0?0:3):(p1.y>=0?1:2); } bool point_is_inside() { int tmp1,tmp2,sum=0,i; point p1; p1.x=p[0].x-p0.x,p1.y=p[0].y-p0.y; tmp1=get_tmp(p1); for(i=0;i<n;i++) { if(p[i]==p0) break; int t0=Fabs(x_multi(p0,p[i],p[(i+1)%n])); int t1=Fabs((p[i].x-p0.x)*(p[(i+1)%n].x-p0.x)); int t2=Fabs((p[i].y-p0.y)*(p[(i+1)%n].y-p0.y)); if(!t0&&t1<=0&&t2<=0) break; p1.x=p[(i+1)%n].x-p0.x,p1.y=p[(i+1)%n].y-p0.y; tmp2=get_tmp(p1); switch((tmp2-tmp1+4)%4) { case 1:{ sum++; break; } case 2: { if(t0>0) sum+=2; else sum-=2; break; } case 3: { sum--; break; } } tmp1=tmp2; } if(i<n||sum) return true; return false; }