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(); } }