133 行
4.8 KiB
PHP
133 行
4.8 KiB
PHP
<?php
|
||
|
||
namespace SmallProgramApi\Helper;
|
||
|
||
/**
|
||
* 电子围栏辅助类
|
||
* 用于判断坐标点是否在电子围栏内
|
||
*/
|
||
class FenceHelper
|
||
{
|
||
/**
|
||
* 判断点是否在多边形内(射线法)
|
||
* @param float $lng 经度
|
||
* @param float $lat 纬度
|
||
* @param array $polygon 多边形坐标数组 [['lng' => x, 'lat' => y], ...]
|
||
* @return bool
|
||
*/
|
||
public static function isPointInPolygon($lng, $lat, $polygon)
|
||
{
|
||
if (empty($polygon) || count($polygon) < 3) {
|
||
return false;
|
||
}
|
||
|
||
$count = count($polygon);
|
||
$inside = false;
|
||
|
||
for ($i = 0, $j = $count - 1; $i < $count; $j = $i++) {
|
||
$xi = $polygon[$i]['lng'];
|
||
$yi = $polygon[$i]['lat'];
|
||
$xj = $polygon[$j]['lng'];
|
||
$yj = $polygon[$j]['lat'];
|
||
|
||
if ((($yi > $lat) != ($yj > $lat)) &&
|
||
($lng < ($xj - $xi) * ($lat - $yi) / ($yj - $yi) + $xi)) {
|
||
$inside = !$inside;
|
||
}
|
||
}
|
||
|
||
return $inside;
|
||
}
|
||
|
||
/**
|
||
* 判断点是否在任意一个围栏内
|
||
* @param float $lng 经度
|
||
* @param float $lat 纬度
|
||
* @param array $fences 围栏数据数组
|
||
* @return array 返回结果 ['in_fence' => bool, 'fence_name' => string]
|
||
*/
|
||
public static function checkPointInFences($lng, $lat, $fences)
|
||
{
|
||
if (empty($fences)) {
|
||
return ['in_fence' => false, 'fence_name' => ''];
|
||
}
|
||
|
||
foreach ($fences as $fence) {
|
||
// 只检查启用的围栏
|
||
if (isset($fence['is_active']) && $fence['is_active'] != 1) {
|
||
continue;
|
||
}
|
||
|
||
// 只处理多边形围栏
|
||
if (isset($fence['fence_type']) && $fence['fence_type'] != 1) {
|
||
continue;
|
||
}
|
||
|
||
$fenceData = $fence['fence_data'];
|
||
|
||
// 如果fence_data是字符串,尝试解析
|
||
if (is_string($fenceData)) {
|
||
$fenceData = json_decode($fenceData, true);
|
||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
// 如果fence_data是数组格式(新格式)
|
||
if (is_array($fenceData)) {
|
||
// 检查是否是多个多边形的数组格式
|
||
if (isset($fenceData[0]) && is_array($fenceData[0])) {
|
||
// 新格式:[{id: '', paths: [{lat: x, lng: y}]}, ...]
|
||
if (isset($fenceData[0]['paths'])) {
|
||
foreach ($fenceData as $polygon) {
|
||
if (isset($polygon['paths']) && is_array($polygon['paths'])) {
|
||
$points = [];
|
||
foreach ($polygon['paths'] as $point) {
|
||
if (isset($point['lat']) && isset($point['lng'])) {
|
||
$points[] = ['lng' => $point['lng'], 'lat' => $point['lat']];
|
||
}
|
||
}
|
||
|
||
if (count($points) >= 3 && self::isPointInPolygon($lng, $lat, $points)) {
|
||
return [
|
||
'in_fence' => true,
|
||
'fence_name' => $fence['fence_name'] ? $fence['fence_name'] : '配送区域'
|
||
];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// 旧格式:直接是坐标点数组 [{lng: x, lat: y}, ...]
|
||
else {
|
||
$points = [];
|
||
foreach ($fenceData as $point) {
|
||
if (isset($point['lng']) && isset($point['lat'])) {
|
||
$points[] = ['lng' => $point['lng'], 'lat' => $point['lat']];
|
||
}
|
||
}
|
||
|
||
if (count($points) >= 3 && self::isPointInPolygon($lng, $lat, $points)) {
|
||
return [
|
||
'in_fence' => true,
|
||
'fence_name' => $fence['fence_name'] ? $fence['fence_name'] : '配送区域'
|
||
];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return ['in_fence' => false, 'fence_name' => ''];
|
||
}
|
||
|
||
/**
|
||
* 获取门店的电子围栏数据
|
||
* @param int $storeId 门店ID
|
||
* @return array
|
||
*/
|
||
public static function getStoreFences($storeId)
|
||
{
|
||
$FenceModel = new \Common\Model\StoreDeliveryFenceModel();
|
||
return $FenceModel->where(['store_id' => $storeId, 'is_active' => 1])->select();
|
||
}
|
||
} |