Как найти ближайший город по координатам

Найти ближайшие города от заданных координат

Этот сервис позволяет найти все населенные пункты в радиусе от заданных координат.
Скрипт использует базу данных городов с географическими координатами и вычисляет расстояние между городами

Данный скрипт использует API получения ближайших городов(населенных пунктов) от заданных координат.

Купить этот скрипт для автономной работы можно здесь.

Вы можете также воспользоваться скриптом Найти ближайшие города от заданного.

Все гео-сервисы.



.

Прокомментировать/Отблагодарить

Вычисляем ближайшие объекты по координатам

Время на прочтение
5 мин

Количество просмотров 11K

Я разрабатывал один проект по недвижимости и появилась задача показывать объекты расположенные в радиусе 20 км с просматриваемым. Т.е. у нас есть объект, в нашем случае это поселок, и нужно отображать находящиеся рядом поселки из нашей базы данных в радиусе 20 км, при этом имея только координаты их расположения.

Исследование

Итак для решения задачи началось «гугление». И первое что было нагуглено это алгоритм расчета расстояний между двумя точками на шаре, статья уходила в Wikipedia. Статья конечно интересное, но как она поможет в моем деле!? Как выяснилось от нее будет толк, но не сразу. Смысл в том, что просчет расстояний по координатам хорош, но как делать выборку из базы и рассчитывать координаты «на ходу»!? Вероятно данным способом никак. Конечно, решение в лоб было каким то образом просчитать насколько можно сдвинуться от координаты чтобы получить нужное расстояние и запросить через какой-нибудь SQL BETWEEN.

Снова гуглим и нагугливаем ВОПРОС на Хабр Q&A. В лучшем ответе решение есть, но оно указывает, что у нас длина одного градуса в километрах равно 111 км, но это далеко не всегда так. Отсюда было понятно, что решение слишком не точное. Читаем дальше и там некий @alex40 предлагает решение как раз с between но выбирать по квадрату. Суть его решения заключается в том, чтобы взять диапазон координат по квадрату а не по окружности и запросить выборку как раз с оператором BETWEEN. И глядя на элегантность этого решения, я понял, что надо делать как то так, но оставался вопрос, что квадрат вносит слишком большую неточность.

Схема решения

Взять изначальную точку координат, и прибавить к ней число градусов соответствующее расстоянию, необходимому для выборки.

Если соединить эти точки, на которые мы прибавили изначальную координату получится квадрат (простите не ровно нарисовал).

Далее с помощью все той же википедии я открыл для себя несколько формул, и одна из них прямо то что нужно. Это формула вычисления длины градуса. Помните в начале я говорил, что 111 км. это слишком абстрактно из первого решения в вопросе. Так вот, эта формула позволяет вычислять длину градуса непосредственно на конкретной меридиане или параллели, нужно только знать радиус нашего шара. Там же на странице википедии есть предварительно рассчитанные данные, по которым можно будет проверить свою формулу

φ

Δ1
lat

Δ1
long

110.574 km

111.320 km

15°

110.649 km

107.551 km

30°

110.852 km

96.486 km

45°

111.133 km

78.847 km

60°

111.412 km

55.800 km

75°

111.618 km

28.902 km

90°

111.694 km

0.000 km

Расчеты

Приступаем к расчетам. Из открытых источников нам известно, что:

  • Средний радиус Земли R = 6371210 м.

  • Экваториальный радиус Земли RЭ = 6378,245 м.

  • Полярный радиус Земли RП = 6356,830 м.

Я для расчетов взял средний радиус. Естественно нужно помнить, что земля все-таки не идеальная сфера, поэтому погрешность есть и в этих расчетах, но для нашей задачи это допустимая погрешность.

Я написал небольшой код для проверки вычислений, и для того, чтобы я мог взять числа и проверить их на реальных данных.

Код для проверки

const EART_RADIUS = 6371210; //Радиус земли
const DISTANCE = 20000; //Интересующее нас расстояние

//https://en.wikipedia.org/wiki/Longitude#Length_of_a_degree_of_longitude
function computeDelta(degrees) {
  return Math.PI / 180 * EART_RADIUS * Math.cos(deg2rad(degrees));
}

function deg2rad(degrees) {
  return degrees * Math.PI / 180;
}

const latitude = 55.460531; //Интересующие нас координаты широты
const longitude = 37.210488; //Интересующие нас координаты долготы

const deltaLat = computeDelta(latitude); //Получаем дельту по широте
const deltaLon = computeDelta(longitude); // Дельту по долготе

const aroundLat = DISTANCE / deltaLat; // Вычисляем диапазон координат по широте
const aroundLon = DISTANCE / deltaLon; // Вычисляем диапазон координат по долготе

console.log(aroundLat, aroundLon);

В коде я сразу установил константу расстояния, радиуса земли и принял решение все считать в метрах, поскольку данные я нашел в метрах и лень было разделить их на 1000, да и в метрах казалось, что точность немного выше, чем в километрах с округлением.

Суть этого кода в следующем. Мы не забываем перевести градусы координат в радианы, поскольку формула из википедии рассчитана на радианы. Мы вычисляем дельту ширины и долготы одинаково по одной и той же формуле, поскольку мы условились что у нас идеальный шар и эта погрешность нам допустима. С помощью формулы мы узнаем сколько градусов у нас в одном километре, а дальше простая пропорция.

1 градус — 63046.689652997775 метров
X градусов — 200000 метров

Если 1 градус, соответствует 63046.689652997775 метров (для широты вычисленной из координаты), то 20000 метров соответсвует X. Дальше, как в школе учили, наискосок умножаем на оставшееся делим. И так как там у нас получается умножение на 1, то это действие можно упустить и записать как `DISTANCE / deltaLat`. Тоже самое проделываем для координаты долготы.

На этих конкретных координатах получаются числа 0.31722522007226484 и 0.22583381380662185. По сути это и есть числа, готовые прибавляться к координатам, чтобы получить тот самый заветный квадрат.

Теперь мы можем добавить эти числа в SQL запрос, чтобы посмотреть, что за выборка у нас получится:

select
	name,
	latitude,
	longitude
from
	villages
where
	latitude between 55.460531 - 0.31722522007226484 and 55.460531 + 0.31722522007226484
	and longitude between 37.210488 - 0.22583381380662185 and 37.210488 + 0.22583381380662185;

Ну и в моей выборке оказалось 7 объектов. Конечно я взял эту выборку и проверил координаты с помощью линейки на Яндекс Картах. В моем случае все попали в радиус обозначенных 20км. Но мы же помним, что взяли квадрат, а не окружность для вычисления?! Я там даже схему нарисовал в начале, что за квадрат. Итак, если сделать окружность, внутри этого квадрата, она как раз будет радиусом примерно те же 20 км.

Я добавил картинку для наглядности. Видно, что если высота квадрата 40 км, и в нем окружность, то радиус ее тоже будет соответствовать 20 км. Остаются лишние области — углы квадрата, которые я закрасил зеленым. Это то что у нас может попасть в выборку, но они уже не соответствуют именно радиусу в 20 км. Т.е. это лишние данные. И вот тут приходит на помощь та самая формула, о которой я говорил в начале — Расчет расстояния между координатами. С помощью этой формулы можно сравнить исходную точку с координатами из выборки и отсечь те, что будут превышать те самые 20 км, поставленные в задаче.

Итог

Задача решена. Алгоритм придуман. Осталось упаковать это в «красивый» и «чистый» код, чтобы все было по феншую. Надеюсь статья была полезной, потому что когда я искал решения задачи, я наткнулся на множество формул, на множество идей, но не нашел места, где это было бы собрано вот так, как попытался собрать я в рамках данной статьи.

Ссылки

Расчет длины градуса

Расчет дистанции между координатами на сфере

Статья, которая помогла вникнуть в тему расчетов

Тоже полезная статья, в ней есть данные для расчетов

UPD:

1. Изменил картинку с ошибочным радиусом и описание высоты квадрата

Найти место по координатам, широта и долгота на карте

С помощью онлайн-карты GeoTree.ru вы можете найти место или адрес на карте по координатам.
Для этого укажите значение широты и долготы в соотетствующие поля и нажмите кнопку «переместить карту».
Вы можете ввести координаты в любом формате: в градусах с десятичной дробной частью или с указанием минут и секунд.

При помощи данного интрумента Вы можете:

  • найти место по широте и долготе
  • выполнить поиск адреса по координатам
  • узнать геокоординаты центра карты
  • найти широту и долготу на карте
  • выполнить поиск географических координат на карте
  • найти по широте и долготе интересующий Вас объект
  • увидеть координаты на карте
  • найти по координатам место или адрес

↑ Все API

Обратное геокодирование (адрес по координатам)

Находит ближайшие адреса (дома, улицы, города) по географическим координатам. Только для России.

Как вызвать

Чтобы вызвать метод, зарегистрируйтесь и подтвердите почту.

Пример запроса:

Песочница

{ «lat»: 55.878, «lon»: 37.653 }

cURL

curl -X POST 
  -H "Content-Type: application/json" 
  -H "Accept: application/json" 
  -H "Authorization: Token ${API_KEY}" 
  -d '{ "lat": 55.878, "lon": 37.653 }' 
  https://suggestions.dadata.ru/suggestions/api/4_1/rs/geolocate/address

.NET

// https://github.com/hflabs/dadata-csharp

var token = "${API_KEY}";
var api = new SuggestClientAsync(token);
var result = await api.Geolocate(lat: 55.878, lon: 37.653);

JavaScript

var url = "https://suggestions.dadata.ru/suggestions/api/4_1/rs/geolocate/address";
var token = "${API_KEY}";
var query = { lat: 55.878, lon: 37.653 };

var options = {
    method: "POST",
    mode: "cors",
    headers: {
        "Content-Type": "application/json",
        "Accept": "application/json",
        "Authorization": "Token " + token
    },
    body: JSON.stringify(query)
}

fetch(url, options)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log("error", error));

PHP

// https://github.com/hflabs/dadata-php

$token = "${API_KEY}";
$dadata = new DadataDadataClient($token, null);
$result = $dadata->geolocate("address", 55.878, 37.653);

Python

# https://github.com/hflabs/dadata-py

from dadata import Dadata
token = "${API_KEY}"
dadata = Dadata(token)
result = dadata.geolocate(name="address", lat=55.878, lon=37.653)

Параметры запроса

Название Тип Обяз.? По умолч. Описание
lat number Географическая широта
lon number Географическая долгота
count number 10 Количество результатов (максимум — 20)
radius_meters number 100 Радиус поиска в метрах (максимум – 1000)
language string ru На каком языке вернуть результат (ru / en)

Пример запроса с ограничением по радиусу в 50 м:

{
  "lat": 55.601983, "lon": 37.359486, "radius_meters": 50
}

Что в ответе

Ответ:

{
    "suggestions": [
        {
            "value": "г Москва, ул Сухонская, д 11",
            "unrestricted_value": "127642, г Москва, ул Сухонская, д 11",
            "data": {...}
        },
        {
            "value": "г Москва, ул Сухонская, д 11А",
            "unrestricted_value": "127642, г Москва, ул Сухонская, д 11А",
            "data": {...}
        },
        {
            "value": "г Москва, ул Сухонская, д 13",
            "unrestricted_value": "127642, г Москва, ул Сухонская, д 13",
            "data": {...}
        },
        {
            "value": "г Москва, ул Сухонская, д 9",
            "unrestricted_value": "127642, г Москва, ул Сухонская, д 9",
            "data": {...}
        }
    ]
}

Адреса в ответе идут в порядке удаления от заданных координат.

У адреса обычный набор полей, но некоторые из них не заполняются:

city_area
city_district*
flat_*
timezone
beltway_hit
beltway_distance
metro

Покрытие координат

«Дадата» берет координаты домов и улиц из OpenStreetMap.

Покрытие по домам:

  • Москва — 97%,
  • Санкт-Петербург — 91%,
  • другие города-миллионники — 69%,
  • остальная Россия — 47%.

По улицам:

  • Москва — 95%,
  • Санкт-Петербург — 94%,
  • другие города-миллионники — 81%,
  • остальная Россия — 70%.

Примеры вызова

  • C# / .NET

  • iOS

  • Laravel

  • PHP

  • PHP (одним файлом)

  • Python

  • R

  • Symfony

Ограничения

Длина запроса (параметр query) — не более 300 символов.

Количество запросов в день — в соответствии с тарифным планом.

Максимальная частота запросов — 30 в секунду с одного IP-адреса.

Максимальная частота создания новых соединений — 60 в минуту с одного IP-адреса.

Стоимость

Метод бесплатный до 10 000 запросов в день. Больше — в составе годовой подписки.

Как найти координаты или выполнить поиск по широте и долготе

Чтобы найти место, введите на Google Картах GPS-координаты широты и долготы. Вы также можете найти координаты просмотренных ранее мест.

Если у места нет обычного адреса, то найти это место и поделиться им на Google Картах можно с помощью кода Plus Code.

Как ввести координаты места

  1. Откройте Google Карты на компьютере.
  2. В окно поиска введите координаты. Допускаются следующие форматы:
    • Десятичные градусы: 41.40338, 2.17403
    • Градусы, минуты и секунды: 41°24’12.2″N 2°10’26.5″E
    • Градусы и десятичные минуты: 41 24.2028, 2 10.4418

Как узнать координаты места

  1. Откройте Google Карты на компьютере.
  2. Нажмите на нужный участок карты правой кнопкой мыши.
    • Откроется всплывающее окно. В верхней части показываются широта и долгота в десятичном формате.
  3. Чтобы скопировать координаты, нажмите на них левой кнопкой мыши.

Как отформатировать координаты

Чтобы координаты распознавались в Google Картах, указывайте их только в следующем десятичном формате:

  • Правильно: 41.40338, 2.17403.
  • Неправильно: 41,40338, 2,17403.

Примечания

  • Сначала указывается широта, затем долгота.
  • Для широты используйте значения в диапазоне от -90 до 90.
  • Долготу указывайте в диапазоне от -180 до 180.

Эта информация оказалась полезной?

Как можно улучшить эту статью?

Понравилась статья? Поделить с друзьями:
  • Как найти плошадь ромба
  • Как найти наибольшее целое число области определения
  • Как найти квитанцию за квартиру налог
  • Как найти абсолютную погрешность измерения в физике
  • Суп получился слишком острый как исправить