博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PHP 判断点是否在多边形内
阅读量:5789 次
发布时间:2019-06-18

本文共 6486 字,大约阅读时间需要 21 分钟。

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

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

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

google算法:

其中第三个是百度官网的一个示例

 

查看源码,百度里面有一个文件

其中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; }}

打印:bool(false)

$point=[      'lng'=>121.427417,      'lat'=>31.20357  ];

替换为

$point=[      'lng'=>121.257428,      'lat'=>31.222481   ];

打印:bool(true)

 

 

-------------  扩展  -------------------------

在百度地图上绘制多边形并保存绘制的点的经纬度

            
鼠标绘制工具

访问效果:

保存数据:

[{"city":"上海","ranges":"{\"service_area\":[{\"name\":\"多边形1\",\"points\":[{\"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}]},{\"name\":\"多边形2\",\"points\":[{\"lng\":121.05846,\"lat\":31.257636},{\"lng\":121.044662,\"lat\":31.151385},{\"lng\":121.165969,\"lat\":31.157318},{\"lng\":121.165969,\"lat\":31.157318},{\"lng\":121.165969,\"lat\":31.157318}]},{\"name\":\"多边形3\",\"points\":[{\"lng\":121.16482,\"lat\":31.269489},{\"lng\":121.165395,\"lat\":31.235901},{\"lng\":121.19414,\"lat\":31.240347},{\"lng\":121.201614,\"lat\":31.262081},{\"lng\":121.243583,\"lat\":31.279859},{\"lng\":121.244733,\"lat\":31.249239},{\"lng\":121.207363,\"lat\":31.293191},{\"lng\":121.207363,\"lat\":31.293191},{\"lng\":121.207363,\"lat\":31.293191},{\"lng\":121.207363,\"lat\":31.293191}]},{\"name\":\"多边形4\",\"points\":[{\"lng\":121.371789,\"lat\":31.274921},{\"lng\":121.326946,\"lat\":31.208232},{\"lng\":121.36719,\"lat\":31.136055},{\"lng\":121.552888,\"lat\":31.167701},{\"lng\":121.590257,\"lat\":31.154352},{\"lng\":121.623602,\"lat\":31.223056},{\"lng\":121.560936,\"lat\":31.280353},{\"lng\":121.519542,\"lat\":31.300102},{\"lng\":121.519542,\"lat\":31.300102},{\"lng\":121.519542,\"lat\":31.300102},{\"lng\":121.450553,\"lat\":31.252203}]}]}"}]

 

 

还有一个编辑和保存多边形文件是复制百度地图生成器样式修改的。

百度地图生成器:

文件下载:

效果:

2017-03-2更新:升级版百度多边形编辑

转载地址:http://xvmyx.baihongyu.com/

你可能感兴趣的文章
Java HashMap源码分析
查看>>
判断页面是否是微信打开的
查看>>
正则表达式模式
查看>>
loj 1271
查看>>
Android中intent如何传递自定义数据类型
查看>>
MFC中创建多线程
查看>>
Flex State
查看>>
自定义seekBar设置进度条背景图片
查看>>
第三部分:Android 应用程序接口指南---第二节:UI---第五章 设置(Settings)
查看>>
安装完QQ必须要删除掉的几个恐怖文件
查看>>
浏览器检测
查看>>
使用NPOI组件完成的Excel导出导入(附源代码,测试通过)
查看>>
jQuery插件AjaxFileUpload实现ajax文件上传
查看>>
paip.汉字简化大法总结
查看>>
.NET快速查找某个类所在的命名空间
查看>>
Ext checkbox
查看>>
ZIOZIA_百度百科
查看>>
彷微信主界面页面滑动时指示颜色条平滑滑动
查看>>
Android操作SQLite的完整示例(操作类对象)
查看>>
Nginx+Tomcat+Terracotta的Web服务器集群实做
查看>>