Files
UAS_WEBGIS_DeranggaArayAbim…/sig-02/includes/geo.php
T
Araya's Project 6462f2e396 First Commit
2026-06-10 12:12:51 +07:00

110 lines
2.8 KiB
PHP

<?php
/**
* Helper geometri & respons JSON.
*
* Perhitungan dilakukan di sisi server agar otoritatif:
* - Panjang LineString -> haversine (meter)
* - Luas / keliling Polygon -> rumus area geodesik bola (meter & m2)
*
* Koordinat mengikuti format GeoJSON: [longitude, latitude].
*/
const EARTH_RADIUS = 6378137.0; // radius WGS84 (meter)
/** Kirim respons JSON lalu hentikan eksekusi. */
function json_response($data, int $status = 200): void
{
http_response_code($status);
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE);
exit;
}
/** Ambil & decode body JSON dari request. */
function read_json_body(): array
{
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
return is_array($data) ? $data : [];
}
/** Jarak haversine antar dua titik [lng, lat] dalam meter. */
function haversine(array $a, array $b): float
{
$lon1 = deg2rad($a[0]);
$lat1 = deg2rad($a[1]);
$lon2 = deg2rad($b[0]);
$lat2 = deg2rad($b[1]);
$dLat = $lat2 - $lat1;
$dLon = $lon2 - $lon1;
$h = sin($dLat / 2) ** 2
+ cos($lat1) * cos($lat2) * sin($dLon / 2) ** 2;
return 2 * EARTH_RADIUS * asin(min(1.0, sqrt($h)));
}
/**
* Panjang total sebuah LineString (array of [lng, lat]) dalam meter.
*/
function line_length(array $coords): float
{
$total = 0.0;
$n = count($coords);
for ($i = 1; $i < $n; $i++) {
$total += haversine($coords[$i - 1], $coords[$i]);
}
return $total;
}
/**
* Luas polygon geodesik (ring tunggal, array of [lng, lat]) dalam meter persegi.
* Memakai pendekatan integral bola (mirip Google Maps computeSignedArea).
*/
function ring_area(array $ring): float
{
$n = count($ring);
if ($n < 3) {
return 0.0;
}
$area = 0.0;
for ($i = 0; $i < $n; $i++) {
$p1 = $ring[$i];
$p2 = $ring[($i + 1) % $n];
$area += deg2rad($p2[0] - $p1[0])
* (2 + sin(deg2rad($p1[1])) + sin(deg2rad($p2[1])));
}
$area = $area * EARTH_RADIUS * EARTH_RADIUS / 2.0;
return abs($area);
}
/** Keliling polygon (ring tunggal) dalam meter. */
function ring_perimeter(array $ring): float
{
if (count($ring) < 2) {
return 0.0;
}
// Pastikan ring tertutup untuk perhitungan keliling.
$closed = $ring;
if ($closed[0] !== $closed[count($closed) - 1]) {
$closed[] = $closed[0];
}
return line_length($closed);
}
/**
* Validasi & ekstrak geometry GeoJSON.
* Mengembalikan [type, coordinates] atau null bila tidak valid.
*/
function parse_geometry($geojson): ?array
{
if (is_string($geojson)) {
$geojson = json_decode($geojson, true);
}
if (!is_array($geojson) || empty($geojson['type']) || !isset($geojson['coordinates'])) {
return null;
}
return [$geojson['type'], $geojson['coordinates']];
}