Вычисление или запрос расстояния по большому кругу между точками широты и долготы с использованием формулы гаверсинуса (примеры PHP, JavaScript, Java, Python, MySQL, MSSQL)
В этом месяце я программировал на PHP и MySQL для ГИС. Изучая эту тему, я с трудом нашел географические расчеты чтобы найти расстояние между двумя локациями, поэтому я хотел поделиться ими здесь.
Простым способом вычисления расстояния между двумя точками является использование формулы Пифагора для вычисления гипотенузы треугольника (A² + B² = C²). Это известно как Евклидово расстояние.
Это интересное начало, но оно неприменимо к географии, поскольку расстояние между линиями широты и долготы равно не равные расстояния друг от друга. По мере приближения к экватору линии широты расходятся дальше. Если вы используете простое уравнение триангуляции, оно может точно измерить расстояние в одном месте и неправильно в другом из-за кривизны Земли.
Расстояние по большому кругу
Маршруты, пройденные на большие расстояния вокруг Земли, известны как расстояние по Большому кругу. То есть… кратчайшее расстояние между двумя точками на сфере отличается от точек на плоской карте. Объедините это с тем фактом, что линии широты и долготы не равноудалены… и вы получите сложный расчет.
Вот фантастическое видео, объясняющее, как работают Великие круги.
Формула Хаверсина
Расстояние с использованием кривизны Земли включено в формулу Хаверсина, которая использует тригонометрию для учета кривизны Земли. Когда вы находите расстояние между двумя точками на Земле (по прямой), прямая линия на самом деле представляет собой дугу.
Это применимо в авиаперелетах — вы когда-нибудь смотрели на настоящую карту полетов и замечали, что они изогнуты? Все потому, что лететь по дуге между двумя точками короче, чем напрямую до локации.
PHP: вычислить расстояние между двумя точками широты и долготы
Вот формула PHP для расчета расстояния между двумя точками (вместе с преобразованием миль в километры), округленная до двух знаков после запятой.
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));
}
Переменные:
- $широта1 – переменная для широты вашего первого местоположения.
- $Долгота1 – переменная для долготы вашего первого местоположения
- $широта2 – переменная для широты вашего второго местоположения.
- $Долгота2 – переменная для долготы вашего второго местоположения.
- $единица - значение по умолчанию миль. Это может быть обновлено или передано как километров.
Java: рассчитать расстояние между двумя точками широты и долготы
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;
}
}
Переменные:
- широта1 – переменная для широты вашего первого местоположения.
- долгота1 – переменная для долготы вашего первого местоположения
- широта2 – переменная для широты вашего второго местоположения.
- долгота2 – переменная для долготы вашего второго местоположения.
- Ед. изм - значение по умолчанию миль. Это может быть обновлено или передано как километров.
JavaScript: рассчитать расстояние между двумя точками широты и долготы
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);
}
}
Переменные:
- широта1 – переменная для широты вашего первого местоположения.
- долгота1 – переменная для долготы вашего первого местоположения
- широта2 – переменная для широты вашего второго местоположения.
- долгота2 – переменная для долготы вашего второго местоположения.
- Ед. изм - значение по умолчанию миль. Это может быть обновлено или передано как километров.
Python: рассчитать расстояние между двумя точками широты и долготы
Вот формула Python для расчета расстояния между двумя точками (вместе с преобразованием миль в километры), округленная до двух десятичных знаков. Благодарность моему сыну Биллу Карру, специалисту по данным из OpenINSIGHTS, для кода.
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)
Переменные:
- широта1 – переменная для вашего первого местоположения широта.
- долгота1 – переменная для вашего первого местоположения долгота
- широта2 – переменная для вашего второго местоположения широта.
- долгота2 – переменная для вашего второго местоположения долгота.
- Ед. изм - значение по умолчанию миль. Это может быть обновлено или передано как километров.
MySQL: получение всех записей в диапазоне путем вычисления расстояния в милях с использованием широты и долготы
Использование пространственных типов данных в MySQL — более эффективный и удобный способ работы с географическими данными, включая расчет расстояний между точками. MySQL поддерживает такие типы пространственных данных, как POINT
, LINESTRING
качества POLYGON
, наряду с пространственными функциями, такими как ST_Distance
.
Когда вы используете ST_Distance
функция в MySQL с географическими данными, представленными как POINT
координаты, он учитывает кривизну поверхности Земли. Сферическая модель, используемая ST_Distance
использует формулу Хаверсина. Это приближение подходит для большинства практических целей, но может вносить небольшие неточности на очень больших расстояниях.
Вот как вы можете рассчитать расстояния между двумя точками, используя типы пространственных данных:
- Создайте таблицу с пространственным типом данных: Сначала создайте таблицу с
POINT
столбец для хранения географических точек. Например:
CREATE TABLE locations (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
coordinates POINT
);
Вставьте свои географические точки в эту таблицу, используя POINT
конструктор:
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
- Вычислить расстояние, используя ST_Distance: Вы можете рассчитать расстояние между двумя точками, используя
ST_Distance
функция. Вот пример запроса для расчета расстояния между двумя точками:
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;
Замените 1
и 2
с идентификаторами двух точек, между которыми вы хотите рассчитать расстояние.
- Результат: запрос вернет расстояние между двумя точками в милях.
Использование пространственных типов данных и ST_Distance
Функция обеспечивает более эффективный и точный способ работы с географическими данными в MySQL. Это также упрощает расчет расстояний между точками, упрощая управление данными и запросы к ним.
MySQL: получение всех записей в диапазоне путем вычисления расстояния в километрах с использованием широты и долготы
По умолчанию ST_Distance
возвращает расстояние в метрах, поэтому вам просто нужно обновить запрос на километры:
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: STDistance
Если вы используете Microsoft SQL Server, они предлагают свои собственные функции, STРасстояние для вычисления расстояния между двумя точками с использованием типа данных 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);
Совет Манашу Саху, основателю и старшему архитектору компании Ион Три.