首先说明的是此多边形是任意多边形,包括凹多边形:
方法一:射线法
以此点为原点的向右水平射线如果相交于多边形的点的个数为奇数个,则此点在多边形内部,但需要注意几个trick:
- 有可能射线与某条边的端点相交,如果相交的端点的纵坐标是较大的那个,则记录,否则忽略
- 有可能射线与某条边完全覆盖,忽略即可
public class CheckInPolygon {
private int xmult(int x0, int y0,int x1,int y1, int x2,int y2){
return (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);
}
private boolean isInSpanInclude(int y1, int y2,int y){
if(y1>y2)
return (y<=y1)&&(y>=y2);
else
return (y<=y2)&&(y>=y1);
}
private boolean isInSpanExclude(int y1, int y2,int y){
if(y1>y2)
return (y<y1)&&(y>y2);
else
return (y<y2)&&(y>y1);
}
/*
* The polygon is presented by anti-clockwise points (pointsX[],pointsY[])
*/
public boolean isInPolygon(int[] pointsX, int[] pointsY,int x,int y){
int N = pointsX.length ;
int num = 0;
for(int i=0;i<N-1;i++){
int x1 = pointsX[i], x2 = pointsX[i+1];
int y1 = pointsY[i], y2 = pointsY[i+1];
if(isOnSegment(x1,y1,x2,y2,x,y))
return true ;
else{
if(y==y1&&y==y2){continue;}
else{
if(y1>y2){
if(y==y1 || isInSpanExclude(y1, y2, y)){
if(xmult(x,y,x2,y2,x1,y1)>0)
num++;
}
}
else{
if(y==y2 || isInSpanExclude(y1, y2, y)){
if(xmult(x,y,x1,y1,x2,y2)>0)
num++;
}
}
}
}
}
int x1 = pointsX[N-1], x2 = pointsX[0];
int y1 = pointsY[N-1], y2 = pointsY[0];
if(isOnSegment(x1,y1,x2,y2,x,y))
return true ;
else{
if(y==y1&&y==y2){}
else{
if(y1>y2){
if(y==y1 || isInSpanExclude(y1, y2, y)){
if(xmult(x,y,x2,y2,x1,y1)>0)
num++;
}
}
else{
if(y==y2 || isInSpanExclude(y1, y2, y)){
if(xmult(x,y,x1,y1,x2,y2)>0)
num++;
}
}
}
}
if(num%2==1) return true;
return false ;
}
private boolean isOnSegment (int x1, int y1, int x2, int y2, int x, int y) {
return isInSpanInclude(y1,y2,y)&&(xmult(x,y,x1,y1,x2,y2)==0);
}
}
方法二:角度和判别法
如果此点在多边形内部,它连接的相邻的两个点构成的角的和一定是360度