如何判断一个点是否在一个多边形内,何时会用到这个场景。
我们就模拟一个真是场景。我们公司是快递公司,在本地区域有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 (需翻墙)
查看源码,百度里面有一个http://api.map.baidu.com/library/GeoUtils/1.2/src/GeoUtils_min.js文件
其中isPointInPolygon方法就是判断点是否在多边形内部,源码如下:
- //点在多边形内
- function ptInPolygon(){
- var pts = [];
- var pt1 = new BMap.Point(116.395, 39.910);
- var pt2 = new BMap.Point(116.394, 39.914);
- var pt3 = new BMap.Point(116.403, 39.920);
- var pt4 = new BMap.Point(116.402, 39.914);
- var pt5 = new BMap.Point(116.410, 39.913);
- pts.push(pt1);
- pts.push(pt2);
- pts.push(pt3);
- pts.push(pt4);
- pts.push(pt5);
- var ply = new BMap.Polygon(pts);
- var pt =new BMap.Point(116.400, 39.914);
- var result = BMapLib.GeoUtils.isPointInPolygon(pt, ply);
- if(result == true){
- alert("点在多边形内");
- } else {
- alert("点在多边形外")
- }
- //演示:将面添加到地图上
- map.clearOverlays();
- var mkr = new BMap.Marker(pt);
- map.addOverlay(mkr);
- map.addOverlay(ply);
- }
PHP版的也有好几个,都是翻译Javascript但试了下,几乎没一个可以判断验证的。后来在一个论坛中找到了一个很精准的计算多边形内代码,贴出来和大家分享。
- $point=[
- 'lng'=>121.427417,
- 'lat'=>31.20357
- ];
- $arr=[
- [
- 'lng'=>121.23036,
- 'lat'=>31.218609
- ],
- [
- 'lng'=>121.233666,
- 'lat'=>31.210579
- ],
- [
- 'lng'=>121.247177,
- 'lat'=>31.206749
- ],
- [
- 'lng'=>121.276353,
- 'lat'=>31.190811
- ],
- [
- 'lng'=>121.267442,
- 'lat'=>31.237383
- ],
- ];
- $a= is_point_in_polygon($point, $arr);
- var_dump($a);
- /**
- * 判断一个坐标是否在一个多边形内(由多个坐标围成的)
- * 基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则
- * 在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。
- * @param $point 指定点坐标
- * @param $pts 多边形坐标 顺时针方向
- */
- function is_point_in_polygon($point, $pts) {
- $N = count($pts);
- $boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
- $intersectCount = 0;//cross points count of x
- $precision = 2e-10; //浮点类型计算时候与0比较时候的容差
- $p1 = 0;//neighbour bound vertices
- $p2 = 0;
- $p = $point; //测试点
- $p1 = $pts[0];//left vertex
- for ($i = 1; $i <= $N; ++$i) {//check all rays
- // dump($p1);
- if ($p['lng'] == $p1['lng'] && $p['lat'] == $p1['lat']) {
- return $boundOrVertex;//p is an vertex
- }
- $p2 = $pts[$i % $N];//right vertex
- if ($p['lat'] < min($p1['lat'], $p2['lat']) || $p['lat'] > max($p1['lat'], $p2['lat'])) {//ray is outside of our interests
- $p1 = $p2;
- continue;//next ray left point
- }
- 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)
- if($p['lng'] <= max($p1['lng'], $p2['lng'])){//x is before of ray
- if ($p1['lat'] == $p2['lat'] && $p['lng'] >= 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
- $xinters = ($p['lat'] - $p1['lat']) * ($p2['lng'] - $p1['lng']) / ($p2['lat'] - $p1['lat']) + $p1['lng'];//cross point of lng
- if (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
- $p3 = $pts[($i+1) % $N]; //next vertex
- if ($p['lat'] >= min($p1['lat'], $p3['lat']) && $p['lat'] <= 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;
- }
- }
本文转载自:https://www.cnblogs.com/dcb3688/p/4608026.html,仅供收藏学习。