php 电子围栏算法
最近公司有围栏的需求,要求车辆进入设置好的围栏中时报警,反之亦然。
这个函数解决了判断一个坐标在指定的几个坐标围成的围栏中。
这个围栏可以是任意形状,任意大小,任意区域。不依赖任何第三方。纯函数。
/**
* @name 围栏算法,判断一个坐标,是否在围栏里面.如:['113.664673,34.810146','113.681667,34.796896','113.69231,34.794711','113.702009,34.809159']
* @author zlx3323
* @param array $fences 围栏,是一组坐标数组 如:113.674458,34.804719
* @param string $point 要判断的坐标
* @return bool
*/
public function getDistance($macid,$longitude2, $latitude2) {
$userid = DB::name('merchant_shop_commodity')->where('macid',$macid)->value('userid');
$isfence = Gps::name('gps_realtime')->where('macid',$macid)->value('isfence');
$fence = Gps::name('gps_police_setting')->where('userid',$userid)->value('fence');
//判断是否围栏通知
if($fence){
$point = $longitude2.','.$latitude2;
$fences = DB::name('gps_fencelist')->where('macid',$macid)->where('is_round',0)->field('lat_lng,status')->select();
if($fences){
foreach($fences as $k=>$vs){
$newsfences = json_decode($vs['lat_lng'],true);
$nvert = count($newsfences[0]);
$vertx = [];
$verty = [];
list($testy, $testx) = explode(',', $point);
$yes = 0;
foreach ($newsfences as $r=>$vo) {
foreach($vo as $k=>$vv){
list($lng, $lat) = explode(',', $vv);
$vertx[] = $lng;
$verty[] = $lat;
}
$i = $j = $c = 0;
for ($i = 0, $j = $nvert - 1; $i < $nvert; $j = $i++) {
if (( ($verty[$i] > $testy) != ($verty[$j] > $testy) ) &&
($testx < ($vertx[$j] - $vertx[$i]) * ($testy - $verty[$i]) / ($verty[$j] - $verty[$i]) + $vertx[$i]))
$c = !$c;
}
unset($verty);
unset($vertx);
//判断是否在围栏中
if($c){
$yes = 1;
}
}
if($yes ==1){
return $yes;
}
}
}
}
}
圆形围栏算法:
//计算圆形围栏距离
public function getroundDistance($macid='',$longitude2='', $latitude2='',$unit=1, $decimal=2){
$userid = DB::name('merchant_shop_commodity')->where('macid',$macid)->value('userid');
$isfence = Gps::name('gps_realtime')->where('macid',$macid)->value('isfence');
$fence = Gps::name('gps_police_setting')->where('userid',$userid)->value('fence');
//判断是否围栏通知
if($fence){
$fences = DB::name('gps_fencelist')->where('macid',$macid)->where('is_round',1)->field('lat_lng,radius,status')->select();
if($fences){
foreach($fences as $k=>$vo){
$lat_lng = explode(',', $vo['lat_lng']);
$fences[$k]['lat'] = $lat_lng[1];
$fences[$k]['lng'] = $lat_lng[0];
}
$yes = 0;
foreach($fences as $k=>$vo){
$longitude1 = $vo['lng'];
$latitude1 = $vo['lat'];
if($longitude1 && $latitude1){
$EARTH_RADIUS = 6370.996; // 地球半径系数
$PI = 3.1415926;
$radLat1 = $latitude1 * $PI / 180.0;
$radLat2 = $latitude2 * $PI / 180.0;
$radLng1 = $longitude1 * $PI / 180.0;
$radLng2 = $longitude2 * $PI /180.0;
$a = $radLat1 - $radLat2;
$b = $radLng1 - $radLng2;
$distance = 2 * asin(sqrt(pow(sin($a/2),2) + cos($radLat1) * cos($radLat2) * pow(sin($b/2),2)));
$distance = $distance * $EARTH_RADIUS * 1000;
if($unit==2){
$distance = $distance / 1000;
}
$result = round($distance, $decimal);
//判断是否在围栏中,radius为半径
if($result < $vo['radius']){
$yes = 1;
}
if($yes == 1){
return $yes;
}
}
}
}
}
}
数据库字段示例:
评论