Kalkulahin o Query ang Great Circle Disstance sa pagitan ng Points of Latitude at Longitude Gamit ang Haversine Formula (PHP, JavaScript, Java, Python, MySQL, MSSQL Examples)
Ngayong buwan, nagprograma ako sa PHP at MySQL para sa GIS. Habang nagsasaliksik ng paksa, nahirapan akong maghanap heograpikal na mga kalkulasyon upang mahanap ang distansya sa pagitan ng dalawang lokasyon, kaya gusto kong ibahagi ang mga ito dito.
Ang simpleng paraan ng pagkalkula ng distansya sa pagitan ng dalawang puntos ay ang paggamit ng pormula na Pythagorean upang makalkula ang hypotenuse ng isang tatsulok (A² + B² = C²). Ito ay kilala bilang ang Ang layo ng Euclidean.
Iyan ay isang kawili-wiling simula, ngunit hindi ito naaangkop sa heograpiya dahil ang distansya sa pagitan ng mga linya ng latitude at longitude ay hindi pantay na distansya sa pagitan. Habang papalapit ka sa ekwador, lalong humihiwalay ang mga linya ng latitud. Kung gagamit ka ng simpleng triangulation equation, maaari nitong sukatin nang tumpak ang distansya sa isang lokasyon at mali sa isa dahil sa curvature ng Earth.
Mahusay na Distansya ng Circle
Ang mga rutang naglakbay ng malalayong distansya sa paligid ng Earth ay kilala bilang ang Great Circle Distance. Iyon ay... ang pinakamaikling distansya sa pagitan ng dalawang punto sa isang globo ay naiiba sa mga punto sa isang patag na mapa. Pagsamahin iyon sa katotohanang ang mga linya ng latitude at longitude ay hindi pantay na distansiya... at mayroon kang mahirap na pagkalkula.
Narito ang isang kamangha-manghang paliwanag sa video kung paano gumagana ang Great Circles.
Ang Haversine Formula
Ang distansya gamit ang curvature ng Earth ay kasama sa Haversine formula, na gumagamit ng trigonometry upang payagan ang curvature ng Earth. Kapag nahanap mo ang distansya sa pagitan ng 2 lugar sa Earth (habang lumilipad ang uwak), ang isang tuwid na linya ay talagang isang arko.
Naaangkop ito sa paglipad sa himpapawid – tumingin ka na ba sa aktwal na mapa ng mga flight at napansin mong naka-arko ang mga ito? Iyon ay dahil ang paglipad sa isang arko sa pagitan ng dalawang punto ay mas maikli kaysa direkta sa lokasyon.
PHP: Kalkulahin ang Distansya sa Pagitan ng 2 Mga Punto ng Latitude at Longhitud
Narito ang formula ng PHP para sa pagkalkula ng distansya sa pagitan ng dalawang punto (kasama ang conversion ng Mile vs. Kilometer) na bilugan sa dalawang decimal na lugar.
function getDistanceBetweenPointsNew($latitude1, $longitude1, $latitude2, $longitude2, $unit = 'miles') {
$theta = $longitude1 - $longitude2;
$distance = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));
$distance = acos($distance);
$distance = rad2deg($distance);
$distance = $distance * 60 * 1.1515;
switch($unit) {
case 'miles':
break;
case 'kilometers' :
$distance = $distance * 1.609344;
}
return (round($distance,2));
}
Ang mga variable ay:
- $Latitude1 – isang variable para sa latitude ng iyong unang lokasyon.
- $Longitude1 – isang variable para sa longitude ng iyong unang lokasyon
- $Latitude2 – isang variable para sa latitude ng iyong pangalawang lokasyon.
- $Longitude2 – isang variable para sa longitude ng iyong pangalawang lokasyon.
- $unit – ang default na nilalang miles. Maaari itong i-update o ipasa bilang kilometro.
Java: Kalkulahin ang Distansya sa Pagitan ng 2 Punto ng Latitude at Longitude
public static double getDistanceBetweenPointsNew(double latitude1, double longitude1, double latitude2, double longitude2, String unit) {
double theta = longitude1 - longitude2;
double distance = 60 * 1.1515 * (180/Math.PI) * Math.acos(
Math.sin(latitude1 * (Math.PI/180)) * Math.sin(latitude2 * (Math.PI/180)) +
Math.cos(latitude1 * (Math.PI/180)) * Math.cos(latitude2 * (Math.PI/180)) * Math.cos(theta * (Math.PI/180))
);
if (unit.equals("miles")) {
return Math.round(distance, 2);
} else if (unit.equals("kilometers")) {
return Math.round(distance * 1.609344, 2);
} else {
return 0;
}
}
Ang mga variable ay:
- latitude1 – isang variable para sa latitude ng iyong unang lokasyon.
- longhitud1 – isang variable para sa longitude ng iyong unang lokasyon
- latitude2 – isang variable para sa latitude ng iyong pangalawang lokasyon.
- longhitud2 – isang variable para sa longitude ng iyong pangalawang lokasyon.
- yunit – ang default na nilalang miles. Maaari itong i-update o ipasa bilang kilometro.
JavaScript: Kalkulahin ang Distansya sa Pagitan ng 2 Punto ng Latitude at Longitude
function getDistanceBetweenPoints(latitude1, longitude1, latitude2, longitude2, unit = 'miles') {
let theta = longitude1 - longitude2;
let distance = 60 * 1.1515 * (180/Math.PI) * Math.acos(
Math.sin(latitude1 * (Math.PI/180)) * Math.sin(latitude2 * (Math.PI/180)) +
Math.cos(latitude1 * (Math.PI/180)) * Math.cos(latitude2 * (Math.PI/180)) * Math.cos(theta * (Math.PI/180))
);
if (unit == 'miles') {
return Math.round(distance, 2);
} else if (unit == 'kilometers') {
return Math.round(distance * 1.609344, 2);
}
}
Ang mga variable ay:
- latitude1 – isang variable para sa latitude ng iyong unang lokasyon.
- longhitud1 – isang variable para sa longitude ng iyong unang lokasyon
- latitude2 – isang variable para sa latitude ng iyong pangalawang lokasyon.
- longhitud2 – isang variable para sa longitude ng iyong pangalawang lokasyon.
- yunit – ang default na nilalang miles. Maaari itong i-update o ipasa bilang kilometro.
Python: Kalkulahin ang Distansya sa Pagitan ng 2 Punto ng Latitude at Longitude
Narito ang formula ng Python para sa pagkalkula ng distansya sa pagitan ng dalawang punto (kasama ang conversion ng Mile vs. Kilometer) na bilugan sa dalawang decimal na lugar. Credit sa aking anak, Bill Karr, isang Data Scientist para sa OpenINSIGHTS, para sa code.
from numpy import sin, cos, arccos, pi, round
def rad2deg(radians):
degrees = radians * 180 / pi
return degrees
def deg2rad(degrees):
radians = degrees * pi / 180
return radians
def getDistanceBetweenPointsNew(latitude1, longitude1, latitude2, longitude2, unit = 'miles'):
theta = longitude1 - longitude2
distance = 60 * 1.1515 * rad2deg(
arccos(
(sin(deg2rad(latitude1)) * sin(deg2rad(latitude2))) +
(cos(deg2rad(latitude1)) * cos(deg2rad(latitude2)) * cos(deg2rad(theta)))
)
)
if unit == 'miles':
return round(distance, 2)
if unit == 'kilometers':
return round(distance * 1.609344, 2)
Ang mga variable ay:
- latitude1 – isang variable para sa iyong unang lokasyon latitud.
- longhitud1 – isang variable para sa iyong unang lokasyon longitude
- latitude2 – isang variable para sa iyong pangalawang lokasyon latitud.
- longhitud2 – isang variable para sa iyong pangalawang lokasyon longitude.
- yunit – ang default na nilalang miles. Maaari itong i-update o ipasa bilang kilometro.
MySQL: Kinukuha ang Lahat ng Mga Tala sa loob ng Isang Saklaw Sa pamamagitan ng Pagkalkula ng Distansya Sa Milya Gamit ang Latitude at Longitude
Ang paggamit ng Spatial Data Types sa MySQL ay isang mas mahusay at maginhawang paraan upang gumana sa geographical na data, kabilang ang pagkalkula ng mga distansya sa pagitan ng mga punto. Sinusuportahan ng MySQL ang Mga Uri ng Spatial Data tulad ng POINT
, LINESTRING
, at POLYGON
, kasama ng mga spatial na function tulad ng ST_Distance
.
Kapag ginamit mo ang ST_Distance
function sa MySQL na may heograpikal na data na kinakatawan bilang POINT
mga coordinate, isinasaalang-alang nito ang kurbada ng ibabaw ng Earth. Ang spherical model na ginamit ng ST_Distance
gumagamit ng Haversine formula. Ang pagtatantya na ito ay angkop para sa karamihan ng mga praktikal na layunin ngunit maaaring magpakilala ng bahagyang mga kamalian para sa napakalayo na distansya.
Narito kung paano mo makalkula ang mga distansya sa pagitan ng dalawang punto gamit ang Spatial Data Types:
- Gumawa ng Table na may Spatial Data Type: Una, gumawa ng table na may a
POINT
column upang mag-imbak ng mga heograpikal na punto. Halimbawa:
CREATE TABLE locations (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
coordinates POINT
);
Ipasok ang iyong mga heograpikal na punto sa talahanayang ito gamit ang POINT
tagabuo:
INSERT INTO locations (name, coordinates)
VALUES
('Point A', POINT(40.7128, -74.0060)), -- New York City
('Point B', POINT(34.0522, -118.2437)); -- Los Angeles
- Kalkulahin ang Distansya Gamit ang ST_Distance: Maaari mong kalkulahin ang distansya sa pagitan ng dalawang punto gamit ang
ST_Distance
function. Narito ang isang halimbawang query upang kalkulahin ang distansya sa pagitan ng dalawang punto:
SELECT
id1,
id2,
(ST_Distance(coordinates1, coordinates2) / 1609.344) AS distance_in_miles
FROM (
SELECT
l1.id AS id1,
l2.id AS id2,
l1.coordinates AS coordinates1,
l2.coordinates AS coordinates2
FROM
locations l1,
locations l2
WHERE
l1.id = 1 AND l2.id = 2
) AS distances;
Palitan 1
at 2
gamit ang mga ID ng dalawang puntos na gusto mong kalkulahin ang distansya sa pagitan.
- Resulta: Ibabalik ng query ang distansya sa pagitan ng dalawang punto sa milya.
Paggamit ng Spatial Data Types at ang ST_Distance
Ang function ay nagbibigay ng isang mas mahusay at tumpak na paraan upang gumana sa heograpikal na data sa MySQL. Pinapasimple din nito ang pagkalkula ng mga distansya sa pagitan ng mga punto, na ginagawang mas madaling pamahalaan at i-query ang iyong data.
MySQL: Kinukuha ang Lahat ng Mga Tala sa loob ng Isang Saklaw Sa pamamagitan ng Pagkalkula ng Distansya Sa Kilometro Gamit ang Latitude at Longitude
Bilang default ST_Distance
ibinabalik ang distansya sa metro, kaya kailangan mo lang i-update ang query para sa mga kilometro:
SELECT
id1,
id2,
(ST_Distance(coordinates1, coordinates2) / 1000) AS distance_in_kilometers
FROM (
SELECT
l1.id AS id1,
l2.id AS id2,
l1.coordinates AS coordinates1,
l2.coordinates AS coordinates2
FROM
locations l1,
locations l2
WHERE
l1.id = 1 AND l2.id = 2
) AS distances;
Microsoft SQL Server Geographic Distansya: STDistance
Kung gumagamit ka ng Microsoft SQL Server, nag-aalok sila ng sarili nilang function, STDistance para sa pagkalkula ng distansya sa pagitan ng dalawang punto gamit ang uri ng data ng Geography.
DECLARE @g geography;
DECLARE @h geography;
SET @g = geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656)', 4326);
SET @h = geography::STGeomFromText('POINT(-122.34900 47.65100)', 4326);
SELECT @g.STDistance(@h);
Hat tip kay Manash Sahoo, founder at senior architect sa Ion Tatlo.