Initial WebGIS portal project
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* Menghitung jarak antara dua koordinat menggunakan formula Haversine.
|
||||
* @param float $lat1 Latitude titik pertama
|
||||
* @param float $lon1 Longitude titik pertama
|
||||
* @param float $lat2 Latitude titik kedua
|
||||
* @param float $lon2 Longitude titik kedua
|
||||
* @return float Jarak dalam satuan meter
|
||||
*/
|
||||
function calculateHaversineDistance($lat1, $lon1, $lat2, $lon2) {
|
||||
$earthRadius = 6371000; // Radius bumi dalam meter
|
||||
|
||||
$latFrom = deg2rad($lat1);
|
||||
$lonFrom = deg2rad($lon1);
|
||||
$latTo = deg2rad($lat2);
|
||||
$lonTo = deg2rad($lon2);
|
||||
|
||||
$latDelta = $latTo - $latFrom;
|
||||
$lonDelta = $lonTo - $lonFrom;
|
||||
|
||||
$angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
|
||||
cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
|
||||
|
||||
return $angle * $earthRadius;
|
||||
}
|
||||
|
||||
function calculateOsrmRouteDistance($lat1, $lon1, $lat2, $lon2): ?float
|
||||
{
|
||||
$coordinates = sprintf(
|
||||
'%.8F,%.8F;%.8F,%.8F',
|
||||
$lon1,
|
||||
$lat1,
|
||||
$lon2,
|
||||
$lat2
|
||||
);
|
||||
$url = 'https://router.project-osrm.org/route/v1/driving/' . $coordinates . '?overview=false&alternatives=false&steps=false';
|
||||
|
||||
$ch = curl_init($url);
|
||||
if ($ch === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_CONNECTTIMEOUT => 4,
|
||||
CURLOPT_TIMEOUT => 8,
|
||||
CURLOPT_USERAGENT => 'WebGIS-Peduli/1.0',
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($response === false || $httpCode !== 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$json = json_decode($response, true);
|
||||
if (!is_array($json) || ($json['code'] ?? '') !== 'Ok') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$distance = $json['routes'][0]['distance'] ?? null;
|
||||
|
||||
return is_numeric($distance) ? (float)$distance : null;
|
||||
}
|
||||
|
||||
function calculateRoadDistance($lat1, $lon1, $lat2, $lon2): ?float
|
||||
{
|
||||
return calculateOsrmRouteDistance((float)$lat1, (float)$lon1, (float)$lat2, (float)$lon2);
|
||||
}
|
||||
|
||||
function ensurePendudukDistanceColumns(PDO $pdo): void
|
||||
{
|
||||
$stmt = $pdo->query("SHOW COLUMNS FROM penduduk_miskin LIKE 'jarak_rute_m'");
|
||||
if ($stmt->fetch() === false) {
|
||||
$pdo->exec("ALTER TABLE penduduk_miskin ADD COLUMN jarak_rute_m DECIMAL(10, 2) NULL AFTER jarak_m");
|
||||
}
|
||||
}
|
||||
|
||||
function calculatePendudukCoverage(PDO $pdo, float $lat, float $lng): array
|
||||
{
|
||||
$stmtRi = $pdo->query("SELECT id, lat, lng, radius FROM rumah_ibadah");
|
||||
$rumahIbadah = $stmtRi->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$nearest = null;
|
||||
$nearestCovered = null;
|
||||
|
||||
foreach ($rumahIbadah as $ri) {
|
||||
$distance = calculateHaversineDistance($lat, $lng, (float)$ri['lat'], (float)$ri['lng']);
|
||||
$result = [
|
||||
'ibadah_id' => (int)$ri['id'],
|
||||
'ri_lat' => (float)$ri['lat'],
|
||||
'ri_lng' => (float)$ri['lng'],
|
||||
'jarak_m' => round($distance, 2),
|
||||
'distance' => $distance,
|
||||
];
|
||||
|
||||
if ($nearest === null || $distance < $nearest['distance']) {
|
||||
$nearest = $result;
|
||||
}
|
||||
|
||||
if ($distance <= (float)$ri['radius'] && ($nearestCovered === null || $distance < $nearestCovered['distance'])) {
|
||||
$nearestCovered = $result;
|
||||
}
|
||||
}
|
||||
|
||||
$selected = $nearestCovered ?? $nearest;
|
||||
$routeDistance = null;
|
||||
|
||||
if ($selected !== null) {
|
||||
$routeDistance = calculateRoadDistance($lat, $lng, $selected['ri_lat'], $selected['ri_lng']);
|
||||
}
|
||||
|
||||
return [
|
||||
'ibadah_id' => $selected['ibadah_id'] ?? null,
|
||||
'jarak_m' => $selected['jarak_m'] ?? null,
|
||||
'jarak_rute_m' => $routeDistance !== null ? round($routeDistance, 2) : null,
|
||||
'is_blank_spot' => $nearestCovered === null ? 1 : 0,
|
||||
];
|
||||
}
|
||||
|
||||
function recalculateAllPendudukCoverage(PDO $pdo): void
|
||||
{
|
||||
ensurePendudukDistanceColumns($pdo);
|
||||
|
||||
$stmt = $pdo->query("SELECT id, lat, lng FROM penduduk_miskin");
|
||||
$penduduk = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$update = $pdo->prepare("
|
||||
UPDATE penduduk_miskin
|
||||
SET ibadah_id = ?, jarak_m = ?, jarak_rute_m = ?, is_blank_spot = ?
|
||||
WHERE id = ?
|
||||
");
|
||||
|
||||
foreach ($penduduk as $row) {
|
||||
$coverage = calculatePendudukCoverage($pdo, (float)$row['lat'], (float)$row['lng']);
|
||||
$update->execute([
|
||||
$coverage['ibadah_id'],
|
||||
$coverage['jarak_m'],
|
||||
$coverage['jarak_rute_m'],
|
||||
$coverage['is_blank_spot'],
|
||||
$row['id'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user