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;}}}}}}
数据库字段示例:

评论
