Files
presensi/app/Modules/Geo/Services/GeoFenceService.php
2026-03-05 14:37:36 +07:00

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