地图上点与多边形的关系判断

大家都知道,点与多边形的关系无非是点在多边形内、点在多边形外、点在多边形的边界上。那么,如何用代码是实现肉眼就能辨别的地理位置关系呢?~


多边形的外包矩形

> 如果一个点不在多边形的外包矩形内,那它肯定不在这个多边形内

射线法判断奇偶数

> 计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则在多边形内

这里写图片描述

  //判断点是否在多边形内:
       function isPointInPolygon(point,polygon){

        //如果是百度的点,用百度已有的方法判断该点是否在多边形的外包矩形内
        if((point instanceof BMap.Point)&&(polygon instanceof BMap.Polygon)){

              var polygonBounds = polygon.getBounds();
              var sw = polygonBounds.getSouthWest(); //西南脚点
              var ne = polygonBounds.getNorthEast(); //东北脚点

              var inRect = point.lng >= sw.lng && point.lng <= ne.lng && point.lat >= sw.lat && point.lat <= ne.lat ;

              if(!inRect){

               return false ; //如果不在外包矩形内,更不会在多边形内。直接返回false 

              }else{


                  var pts = polygon.getPath();//获取多边形的点集合。
                  /**
                  基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则在多边形内
                  */
                  var N = pts.length;
                  var boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
                  var intersectCount = 0;//cross points count of x 
                  var precision = 2e-10; //浮点类型计算时候与0比较时候的容差
                  var p1, p2;//neighbour bound vertices
                  var p = point; //测试点
                  p1 = pts[0];//left vertex 

                  for(var i = 1; i <= N; ++i){//check all rays            

                   if(p.equals(p1)){
                        return boundOrVertex;//p is an vertex
                    }

                   p2 = pts[i % N];//right vertex            

                   if(p.lat < Math.min(p1.lat, p2.lat) || p.lat > Math.max(p1.lat, p2.lat)){//ray is outside of our interests                
                    p1 = p2; 
                    continue;//next ray left point
                   }

                   if(p.lat > Math.min(p1.lat, p2.lat) && p.lat < Math.max(p1.lat, p2.lat)){//ray is crossing over by the algorithm (common part of)
                       if(p.lng <= Math.max(p1.lng, p2.lng)){//x is before of ray                    
                          if(p1.lat == p2.lat && p.lng >= Math.min(p1.lng, p2.lng)){//overlies on a horizontal ray
                             return boundOrVertex;
                    }

                       if(p1.lng == p2.lng){//ray is vertical                        
                         if(p1.lng == p.lng){//overlies on a vertical ray
                            return boundOrVertex;
                          }else{//before ray
                            ++intersectCount;
                          } 
                        }else{//cross point on the left side                        
                       var xinters = (p.lat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) + p1.lng;//cross point of lng                        
                       if(Math.abs(p.lng - xinters) < precision){//overlies on a ray
                            return boundOrVertex;
                        }

                        if(p.lng < xinters){//before ray
                            ++intersectCount;
                        } 
                    }
                 }
                 }else{//special case when ray is crossing through the vertex                

                    if(p.lat == p2.lat && p.lng <= p2.lng){//p crossing over p2                    
                    var p3 = pts[(i+1) % N]; //next vertex                    
                      if(p.lat >= Math.min(p1.lat, p3.lat) && p.lat <= Math.max(p1.lat, p3.lat)){//p.lat lies between p1.lat & p3.lat
                        ++intersectCount;
                      }else{
                        intersectCount += 2;
                     }
                 }
               }            

               p1 = p2;//next ray left point
               }

              if(intersectCount % 2 == 0){//偶数在多边形外
                 return false;
              } else { //奇数在多边形内
                 return true;
               }  

              }
         }
       }

其中3个点的坐标如下:

  var pointA = new BMap.Point(121.333777,31.206659);

  var pointB  = new BMap.Point(121.307313,31.203956);

  var pointC  = new BMap.Point(121.317967,31.224201);

多边形的可参考上一篇计算面积的点集合。

   //调用计算面积的方法
       setTimeout(function(){

        alert("A是否在范围内:"+isPointInPolygon(pointA,polygon) );
        alert("B是否在范围内:"+isPointInPolygon(pointB,polygon) );
        alert("C是否在范围内:"+isPointInPolygon(pointC,polygon) );


       },1000);

这里写图片描述
这里写图片描述

因为在代码里把在多边形上的点默认值为boundOrVertex =true 。所以C点也属于范围内的
这里写图片描述

通过计算点与范围的关系,可以拓展计算范围与范围的交叉重叠计算,在实际业务中很有用喔。

#define geo_max(a,b) (((a) > (b)) ? (a) : (b)) #define geo_min(a,b) (((a) < (b)) ? (a) : (b)) GEO_EXPORT mappoint geo_trangeo2map(georect* grt, geopoint* pt, maprect* mrt); GEO_EXPORT geopoint geo_tranmap2geo(maprect* mrt, mappoint* mpt, georect* grt); /* *判断点在不在矩形里.在返回0 * 不在返回-1 */ GEO_EXPORT int geo_gptingrt(geopoint* gpt, georect* grt); GEO_EXPORT int geo_mptinmrt(mappoint* mpt, maprect* mrt); GEO_EXPORT geobool geo_gptingpolygon(geopoint* gpt, geopoints *gpts); /* *返回单位为:米 */ GEO_EXPORT double geo_distance(geopoint* gptfrom, geopoint* gptto); GEO_EXPORT double geo_distance_pt2polyline(geopoint* gpt, geopoints* gpts, geopoint* rnearestpt); GEO_EXPORT double geo_distance_pt2polygon(geopoint* gpt, geopoints* gpts, geopoint* rnearestpt); /* *返回单位为:平方米 */ //GEO_EXPORT double geo_area(geopoints* gpts); /* *返回单位为:度 *正北为0度,顺时针为正 */ GEO_EXPORT double geo_direction(geopoint* gptfrom, geopoint* gptto); /* * 矩形与矩形的关系 * a 在 b 里面, 返回 0 * a 部份在 b 里面,返回 1 * a 没和 b 相交, 返回 -1 * /\ y * | * | * | * |------------> x * o */ int geo_grtingrt(georect* rta, georect* rtb); /* * 矩形与矩形的关系 * a 在 b 里面, 返回 0 * a 部份在 b 里面,返回 1 * a 没和 b 相交, 返回 -1 * * o * |------------> x * | * | * | * | * \/ y */ int geo_mrtinmrt(maprect* rta, maprect* rtb); //判断线段是否相关 //相交返回GEO_TRUE //不相交返回GEO_FALSE geobool geo_linecrossline(geopoint* lafrom, geopoint* lato, geopoint* lbfrom, geopoint* lbto); /* * 多边形多边形关系 * a 在 b 里面, 返回 0 * a 和 b 相交,返回 1 * a 没和 b 相交, 返回 -1 * b 在 a 里面, 返回 -2 * * /\ y * | * | * | * |------------> x * o */ int geo_gpolygoningpolygon(geopoints* gptsa, geopoints* gptsb);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值