PHP判断一个经纬度点是否在多边形区域内

如何判断一个点是否在一个多边形内,何时会用到这个场景。

我们就模拟一个真是场景。我们公司是快递公司,在本地区域有6个分点。每个分点有3-5个工人负责附近的快递派遣发送,所以根据每个点的服务区域我们就能大概知道我们的服务范围。如果客户要收发快递我们会告知是否在服务范围内,且那个点离的最近,应派谁去收发快递。……

网上其实找了好多判断点是否在经纬度的多边形内,但都是Javascript版:

http://www.voidcn.com/blog/jq_develop/article/p-3221513.html

http://www.html-js.com/article/1528

http://api.map.baidu.com/library/GeoUtils/1.2/examples/simple.html

google算法:

https://en.wikipedia.org/wiki/Geohash (需翻墙)

PHP判断一个经纬度点是否在多边形区域内

查看源码,百度里面有一个http://api.map.baidu.com/library/GeoUtils/1.2/src/GeoUtils_min.js文件

其中isPointInPolygon方法就是判断点是否在多边形内部,源码如下:

  1. //点在多边形内
  2. function ptInPolygon(){
  3.     var pts = [];
  4.     var pt1 = new BMap.Point(116.395, 39.910);
  5.     var pt2 = new BMap.Point(116.394, 39.914);
  6.     var pt3 = new BMap.Point(116.403, 39.920);
  7.     var pt4 = new BMap.Point(116.402, 39.914);
  8.     var pt5 = new BMap.Point(116.410, 39.913);
  9.     pts.push(pt1);
  10.     pts.push(pt2);
  11.     pts.push(pt3);
  12.     pts.push(pt4);
  13.     pts.push(pt5);
  14.     var ply = new BMap.Polygon(pts);
  15.     var pt =new BMap.Point(116.400, 39.914);
  16.     var result = BMapLib.GeoUtils.isPointInPolygon(pt, ply);
  17.     if(result == true){
  18.         alert("点在多边形内");
  19.     } else {
  20.         alert("点在多边形外")
  21.     }
  22.     //演示:将面添加到地图上    
  23.     map.clearOverlays();
  24.     var mkr = new BMap.Marker(pt);
  25.     map.addOverlay(mkr);
  26.     map.addOverlay(ply);
  27. }

PHP版的也有好几个,都是翻译Javascript但试了下,几乎没一个可以判断验证的。后来在一个论坛中找到了一个很精准的计算多边形内代码,贴出来和大家分享。

  1. $point=[
  2.       'lng'=>121.427417,
  3.       'lat'=>31.20357
  4.   ];
  5.   $arr=[
  6.       [
  7.           'lng'=>121.23036,
  8.           'lat'=>31.218609
  9.       ],
  10.       [
  11.           'lng'=>121.233666,
  12.           'lat'=>31.210579
  13.       ],
  14.       [
  15.           'lng'=>121.247177,
  16.           'lat'=>31.206749
  17.       ],
  18.       [
  19.           'lng'=>121.276353,
  20.           'lat'=>31.190811
  21.       ],
  22.       [
  23.           'lng'=>121.267442,
  24.           'lat'=>31.237383
  25.       ],
  26.   ];
  27.   $a= is_point_in_polygon($point$arr);
  28.   var_dump($a);
  29. /**
  30.  * 判断一个坐标是否在一个多边形内(由多个坐标围成的)
  31.  * 基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则
  32.  * 在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。
  33.  * @param $point 指定点坐标
  34.  * @param $pts 多边形坐标 顺时针方向
  35.  */
  36. function is_point_in_polygon($point$pts) {
  37.     $N = count($pts);
  38.     $boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
  39.     $intersectCount = 0;//cross points count of x 
  40.     $precision = 2e-10; //浮点类型计算时候与0比较时候的容差
  41.     $p1 = 0;//neighbour bound vertices
  42.     $p2 = 0;
  43.     $p = $point//测试点
  44.     $p1 = $pts[0];//left vertex        
  45.     for ($i = 1; $i <= $N; ++$i) {//check all rays
  46.         // dump($p1);
  47.         if ($p['lng'] == $p1['lng'] && $p['lat'] == $p1['lat']) {
  48.             return $boundOrVertex;//p is an vertex
  49.         }
  50.         $p2 = $pts[$i % $N];//right vertex            
  51.         if ($p['lat'] < min($p1['lat'], $p2['lat']) || $p['lat'] > max($p1['lat'], $p2['lat'])) {//ray is outside of our interests
  52.             $p1 = $p2;
  53.             continue;//next ray left point
  54.         }
  55.         if ($p['lat'] > min($p1['lat'], $p2['lat']) && $p['lat'] < max($p1['lat'], $p2['lat'])) {//ray is crossing over by the algorithm (common part of)
  56.             if($p['lng'] <= max($p1['lng'], $p2['lng'])){//x is before of ray
  57.                 if ($p1['lat'] == $p2['lat'] && $p['lng'] >= min($p1['lng'], $p2['lng'])) {//overlies on a horizontal ray
  58.                     return $boundOrVertex;
  59.                 }
  60.                 if ($p1['lng'] == $p2['lng']) {//ray is vertical                        
  61.                     if ($p1['lng'] == $p['lng']) {//overlies on a vertical ray
  62.                         return $boundOrVertex;
  63.                     } else {//before ray
  64.                         ++$intersectCount;
  65.                     }
  66.                 } else {//cross point on the left side
  67.                     $xinters = ($p['lat'] - $p1['lat']) * ($p2['lng'] - $p1['lng']) / ($p2['lat'] - $p1['lat']) + $p1['lng'];//cross point of lng
  68.                     if (abs($p['lng'] - $xinters) < $precision) {//overlies on a ray
  69.                         return $boundOrVertex;
  70.                     }
  71.                     if ($p['lng'] < $xinters) {//before ray
  72.                         ++$intersectCount;
  73.                     }
  74.                 }
  75.             }
  76.         } else {//special case when ray is crossing through the vertex
  77.             if ($p['lat'] == $p2['lat'] && $p['lng'] <= $p2['lng']) {//p crossing over p2
  78.                 $p3 = $pts[($i+1) % $N]; //next vertex
  79.                 if ($p['lat'] >= min($p1['lat'], $p3['lat']) && $p['lat'] <= max($p1['lat'], $p3['lat'])) { //p.lat lies between p1.lat & p3.lat
  80.                     ++$intersectCount;
  81.                 } else {
  82.                     $intersectCount += 2;
  83.                 }
  84.             }
  85.         }
  86.         $p1 = $p2;//next ray left point
  87.     }
  88.     if ($intersectCount % 2 == 0) {//偶数在多边形外
  89.         return false;
  90.     } else { //奇数在多边形内
  91.         return true;
  92.     }
  93. }

本文转载自:https://www.cnblogs.com/dcb3688/p/4608026.html,仅供收藏学习。

你想把广告放到这里吗?

发表评论

您必须 登录 才能发表留言!