php 电子围栏算法

php学习交流吧

共 4173字,需浏览 9分钟

 · 2021-12-10

最近公司有围栏的需求,要求车辆进入设置好的围栏中时报警,反之亦然。

这个函数解决了判断一个坐标在指定的几个坐标围成的围栏中。
这个围栏可以是任意形状,任意大小,任意区域。不依赖任何第三方。纯函数。

/** * @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; } } } } } }


数据库字段示例:

528bd4fb79191ddb8a3a9fe86c677cbf.webp


浏览 96
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报