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'], ]); } }