编程之美4.4 扩展问题——判断点位于多边形内部

首先说明的是此多边形是任意多边形,包括凹多边形:
方法一:射线法
以此点为原点的向右水平射线如果相交于多边形的点的个数为奇数个,则此点在多边形内部,但需要注意几个trick:
  • 有可能射线与某条边的端点相交,如果相交的端点的纵坐标是较大的那个,则记录,否则忽略
  • 有可能射线与某条边完全覆盖,忽略即可
用Java写了一个代码,没有测试,但基本思路是这样的:
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度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值