您的位置:首页 > 编程语言 > PHP开发

百度坐标点计算

2017-11-24 22:54 218 查看
前段时间因项目需求,用到了关于坐标点计算的几个方法,就在这里整理下:

1. 计算两个坐标点之间的距离

2. 已知一个坐标点和最大距离,求另一坐标可能在的坐标区域

3. 判断一个坐标点是否在一个多边形内

计算两个坐标点之间的距离

/**
* 计算两个坐标之间的距离
* @param $lat1 坐标点1的纬度
* @param $lng1 坐标点1的经度
* @param $lat2 坐标点2的纬度
* @param $lng2 坐标点2的经度
* @return float
*/
function GetDistance($lat1, $lng1, $lat2, $lng2){
$PI = 3.1415926535898;
$EARTH_RADIUS = 6378.137;
$radLat1 = $lat1 * ($PI / 180);
$radLat2 = $lat2 * ($PI / 180);

$a = $radLat1 - $radLat2;
$b = ($lng1 * ($PI / 180)) - ($lng2 * ($PI / 180));

$s = 2 * asin(sqrt(pow(sin($a/2),2) + cos($radLat1)*cos($radLat2)*pow(sin($b/2),2)));
return round($s * $EARTH_RADIUS * 1000);
}


已知一个坐标点和最大距离,求另一坐标可能在的坐标区域

/**
* 已知一个坐标点和最大距离,求另一坐标的区域范围
* @param $lng 经度
* @param $lat 纬度
* @param int $distance 距离
* @return array
*/
function returnSquarePoint($lng,$lat,$distance = 1500){
$earthRadius = 6371000;
//deg2rad()将角度转换为相应的弧度
//rad2deg()将弧度数转换为相应的角度数
$dlng =  2 * asin(sin($distance / (2 * $earthRadius)) / cos(deg2rad($lat)));
$dlng = rad2deg($dlng);
$dlat = $distance/$earthRadius;
$dlat = rad2deg($dlat);
return array(
'minLng'=>$lng - $dlng,
'maxLng'=>$lng + $dlng,
'minLat'=>$lat - $dlat,
'maxLat'=>$lat + $dlat
);
//所以,经度范围在minLng和maxLng之间,纬度范围在minLat和maxLat之间
}


判断一个坐标点是否在一个多边形内

基本思想:利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况,特殊情况特殊处理。

在看具体的实现方法之前,建议先了解下射线法思路,参考文档:

http://blog.csdn.net/qq_27161673/article/details/52973866

/**
* 判断一个百度坐标是否在一个多边形内(由多个坐标围成的,可以是不规则的形状)
* @param $point 指定点坐标,数组
* @param $pts 多边形坐标 顺时针方向
*/
function isPointInPolygon($point, $pts){
//先判断是否在该多边形的外包矩形中
$latList = array_column($pts,'lat');
$lngList = array_column($pts,'lng');
if($point['lat'] > max($latList) || $point['lat'] < min($latList) || $point['lng'] > max($lngList) || $point['lng'] < min($lngList)){
return false;
}

$N = count($pts);
$boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
$intersectCount = 0;//射线与多边形相交的次数
$precision = 2e-10; //浮点类型计算时候与0比较时候的容差
$p = $point; //测试点
$p1 = $pts[0];//初始左顶点
for ($i = 1; $i <= $N; ++$i) {
//点落在多边形的顶点处,与p1重合
if ($p['lng'] == $p1['lng'] && $p['lat'] == $p1['lat']) {
return $boundOrVertex;//p is an vertex
}

//选择与经度平行的线为射线
//p.lat不在p1.lat和p2.lat之间,即不会和p1与p2两点间的连线相交
$p2 = $pts[$i % $N];//右顶点
if ($p['lat'] < min($p1['lat'], $p2['lat']) || $p['lat'] > max($p1['lat'], $p2['lat'])) {
$p1 = $p2; //移动左顶点到下一个坐标点
continue;
}

//p.lat在p1.lat和p2.lat之间,且不与顶点经度相同(通常情况)
if ($p['lat'] > min($p1['lat'], $p2['lat']) && $p['lat'] < max($p1['lat'], $p2['lat'])) {
if ($p['lng'] <= max($p1['lng'], $p2['lng'])) {
//p1、p2在同一纬度,p的经度在p1与p2两点之间
if ($p1['lat'] == $p2['lat'] && $p['lng'] >= min($p1['lng'], $p2['lng'])) {
return $boundOrVertex;
}

if ($p1['lng'] == $p2['lng']) {
//p、p1、p2在同一经度,且p在p1与p2两点之间
if ($p1['lng'] == $p['lng']) {
return $boundOrVertex;
} else {//射线穿过p1、p2连线
++$intersectCount;
}
} else {
//$xinters是p1射线与p1、p2连线交点处的经度
$xinters = ($p['lat'] - $p1['lat']) * ($p2['lng'] - $p1['lng']) / ($p2['lat'] - $p1['lat']) + $p1['lng'];//cross point of lng
//var_dump('p1_lat:'.$p1['lat'].'--p1_lng:'.$p1['lng'].'--p2_lat:'.$p2['lat'].'--p2_lng:'.$p2['lng'].'--'.$xinters);
//p在p1、p2连线上
if (abs($p['lng'] - $xinters) < $precision) {
return $boundOrVertex;
}

//射线穿过p1、p2连线
if ($p['lng'] < $xinters) {
++$intersectCount;
}
}
}
} else {
//特殊情况:当射线穿过顶点p2时
if ($p['lat'] == $p2['lat'] && $p['lng'] <= $p2['lng']) {
$p3 = $pts[($i + 1) % $N]; //下一个顶点
//若p.lat在p1.lat 和 p3.lat之间(p1、p3在p2的两侧,且射线穿过顶点p2)
if ($p['lat'] >= min($p1['lat'], $p3['lat']) && $p['lat'] <= max($p1['lat'], $p3['lat'])) {
++$intersectCount;
} else {
//若p1、p3在p2的同一侧,且射线穿过顶点p2,则按照两次计算
$intersectCount += 2;
}
}
}
$p1 = $p2;//移动左顶点到下一个坐标点
}

if ($intersectCount % 2 == 0) {//偶数在多边形外
return false;
} else { //奇数在多边形内
return true;
}
}
$pts = array(
array('lat'=>39.910,'lng'=>116.395),
array('lat'=>39.914,'lng'=>116.394),
array('lat'=>39.920,'lng'=>116.403),
array('lat'=>39.914,'lng'=>116.402),
array('lat'=>39.913,'lng'=>116.410),
);
$point = array('lat'=>$lat,'lng'=>$lng);
if(isPointInPolygon($point, $pts)){
echo 1; //在多边形内
}else{
echo 0; //不在多边形内
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息