97 lines
3.1 KiB
PHP
97 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace App\Modules\Geo\Services;
|
|
|
|
/**
|
|
* Geo Fence Service
|
|
*
|
|
* Handles geofencing logic using Haversine formula for distance calculation.
|
|
*/
|
|
class GeoFenceService
|
|
{
|
|
/**
|
|
* Earth's radius in meters
|
|
*/
|
|
private const EARTH_RADIUS_METERS = 6371000;
|
|
|
|
/**
|
|
* Check if a point (latitude, longitude) is inside a zone
|
|
*
|
|
* Uses Haversine formula to calculate distance between two points
|
|
* on Earth's surface and compares it to zone radius.
|
|
*
|
|
* @param float $lat Latitude of the point to check
|
|
* @param float $lng Longitude of the point to check
|
|
* @param array $zone Zone data with 'latitude', 'longitude', and 'radius_meters'
|
|
* @return bool True if point is inside zone, false otherwise
|
|
*/
|
|
public function isInsideZone(float $lat, float $lng, array $zone): bool
|
|
{
|
|
// Validate zone data
|
|
if (!isset($zone['latitude']) || !isset($zone['longitude']) || !isset($zone['radius_meters'])) {
|
|
return false;
|
|
}
|
|
|
|
$zoneLat = (float) $zone['latitude'];
|
|
$zoneLng = (float) $zone['longitude'];
|
|
$radiusMeters = (int) $zone['radius_meters'];
|
|
|
|
// Calculate distance using Haversine formula
|
|
$distance = $this->calculateHaversineDistance($lat, $lng, $zoneLat, $zoneLng);
|
|
|
|
// Check if distance is within radius
|
|
return $distance <= $radiusMeters;
|
|
}
|
|
|
|
/**
|
|
* Calculate distance between two points using Haversine formula
|
|
*
|
|
* Haversine formula calculates the great-circle distance between
|
|
* two points on a sphere given their longitudes and latitudes.
|
|
*
|
|
* @param float $lat1 Latitude of first point
|
|
* @param float $lng1 Longitude of first point
|
|
* @param float $lat2 Latitude of second point
|
|
* @param float $lng2 Longitude of second point
|
|
* @return float Distance in meters
|
|
*/
|
|
private function calculateHaversineDistance(float $lat1, float $lng1, float $lat2, float $lng2): float
|
|
{
|
|
// Convert degrees to radians
|
|
$lat1Rad = deg2rad($lat1);
|
|
$lng1Rad = deg2rad($lng1);
|
|
$lat2Rad = deg2rad($lat2);
|
|
$lng2Rad = deg2rad($lng2);
|
|
|
|
// Calculate differences
|
|
$deltaLat = $lat2Rad - $lat1Rad;
|
|
$deltaLng = $lng2Rad - $lng1Rad;
|
|
|
|
// Haversine formula
|
|
$a = sin($deltaLat / 2) * sin($deltaLat / 2) +
|
|
cos($lat1Rad) * cos($lat2Rad) *
|
|
sin($deltaLng / 2) * sin($deltaLng / 2);
|
|
|
|
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
|
|
|
|
// Distance in meters
|
|
$distance = self::EARTH_RADIUS_METERS * $c;
|
|
|
|
return $distance;
|
|
}
|
|
|
|
/**
|
|
* Calculate distance between two points (public helper method)
|
|
*
|
|
* @param float $lat1 Latitude of first point
|
|
* @param float $lng1 Longitude of first point
|
|
* @param float $lat2 Latitude of second point
|
|
* @param float $lng2 Longitude of second point
|
|
* @return float Distance in meters
|
|
*/
|
|
public function calculateDistance(float $lat1, float $lng1, float $lat2, float $lng2): float
|
|
{
|
|
return $this->calculateHaversineDistance($lat1, $lng1, $lat2, $lng2);
|
|
}
|
|
}
|