Ближайшая станция метро рядом со мной
Одна из функций сайта GeoTree.ru — поиск ближайшей станции метро от меня на карте. Для этого перейдите в меню «Ближайшие объекты» -> «Метро».
На карте будут отображены ближайшие станции метро относительно центра карты.
Если на карте нет ни одной станции — уменьшите масштаб.
Если на карте слишком много станций — передвиньте карту на интересующую Вас область и увеличьте масштаб.
$address = 'ул. Габричевского, 8';
echo findMetro($address); // Щукинская
function findMetro($address) {
// Определение координат заданного адреса
$address = str_replace(' ', '%20', $address);
$contentGeocoder = file_get_contents("https://maps.googleapis.com/maps/api/geocode/json?key=QWERTY1234&address=Москва,%20$address"); // ключ получил на console.developers.google.com/apis
$jsonGeocoder = json_decode($contentGeocoder, true);
$latitudeFrom = $jsonGeocoder["results"][0]["geometry"]["location"]["lat"];
$longitudeFrom = $jsonGeocoder["results"][0]["geometry"]["location"]["lng"];
// Подключение к базе данных с таблицей метро
include '../php/db_connection.php';
$link = mysqli_connect($host, $user, $password, $database) or die("Не удалось подключиться к базе данных");
// Определение ближайшего метро путём перебора
$min = 10000000;
for($metroI = 1; $metroI <= 250; $metroI++) {
// Запрос на выборку для определения координат и названия станции метро
$result = mysqli_query($link, "SELECT name, latitude, longitude FROM metro WHERE id = $metroI");
$row = mysqli_fetch_assoc($result);
// Вычисление расстояния между заданным адресом и станцией метро по формуле Хаверсина
$latFrom = deg2rad($latitudeFrom);
$lonFrom = deg2rad($longitudeFrom);
$latTo = deg2rad($row[latitude]);
$lonTo = deg2rad($row[longitude]);
$latDelta = $latTo - $latFrom;
$lonDelta = $lonTo - $lonFrom;
$angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) + cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
$distance = $angle * 6371000;
// Если расстояние до станции метро меньше, чем минимальное найденное,— назначаем его минимальным, запоминаем название
if($distance < $min) {
$min = $distance;
$closestMetro = $row[name];
}
}
return $closestMetro;
}
Таблица БД с метро: название станции, координаты по широте, долготе

На интерактивной карте города указано расположение станций и линий Московского метрополитена. Вы можете увидеть, где расположена интересующая вас станция или найти станцию метро, ближайшую к нужному вам месту (уточнить, как пройти или проехать к этому месту).
- Схема метро Москвы (перейти к карте).
- Самые популярные станции.
- Стоимость проезда в метро.
- Информация для туристов (о Москве).
Перечень станций вы найдёте в расположенном справа от карты меню. Выберите название нужной вам станции метро в перечне станций справа от карты. На карте вы сможете увидеть расположение этой станции метро и ближайшие улицы. Ниже карты размещена информация, какие станции московского метро расположены ближе всего к некоторым достопримечательностям и важным местам в Москве.
Вы можете также найти нужное вам место на карте Москвы или ближайшую к этому месту станцию метро воспользовавшись сервисом поиска. Введите название объекта или нужный вам адрес.
Если вы зашли на сайт используя планшет или мобильный телефон, возможно вам будет удобнее упрощённая версия карты для мобильных устройств.
Загрузка карты и сведений о станциях займёт некоторое время. Пожалуйста, подождите.
Отправьтесь на экскурсию по Москве (выбирайте здесь).
На карте могут быть неточности, в связи с высоким темпом строительства метро. Приносим извинения.
Ближайшие станции метро Москвы к некоторым объектам
| Кремль, Красная Площадь, Исторический музей, торговый центр «Охотный Ряд». | |
|
|
Третьяковская галерея. |
|
|
Большой театр. |
|
|
Московский государственный университет. |
|
|
Ленинградский, Ярославский и Казанский вокзалы. |
|
|
Киевский вокзал, торговый центр Европейский. |
- Экскурсии в Москве 📷. Самые популярные
экскурсии в Москве, где купить и сколько стоит. - Купить билеты 🎭 в театр, на концерт, мероприятия онлайн.
- Гостиницы.
👍 Гостиницы рядом со станциями метро, гостиницы поиск по карте. Сравнение цен, отзывы клиентов. - Билет на самолёт —
лучшие сайты для покупки авиабилетов.
- Билет на поезд (🚄 купить онлайн).
- Билет на междугородный автобус (🚌 купить онлайн).
- Музеи. Самые популярные музеи Москвы.
- Вокзалы. Вокзалы и аэропорты города.
- Погода. Погода в Москве сегодня, завтра, прогноз погоды.
- Полезные ссылки для направляющихся в Москву туристов (билеты на самолёт, автобус, экскурсии, путеводители онлайн).
- Такси Аэропорт — 🚕 в аэропорт или из аэропорта.
Некоторые из видов билетов на метро Москвы
Электронная карта ”Тройка”. Пластиковая электронная карта стоимостью 50 рублей плюс стоимость поездок. Стоимость поездки в метро по карте составляет от 28 рублей до 50 рублей (зависит от количества единовременно оплаченных поездок). Счёт на карте можно при необходимости пополнять. Залог можно вернуть при возврате карты в кассу.
Билет “Единый”. Билет действителен для метро и для поездок на наземном транспорте (автобус, трамвай, троллейбус). Стоимость билета на 1 поездку цена 50 рублей (2 поездки – 100, 20 поездок – 650 руб. и.т.д.).
Билет «90 минут». Билет действует в течение 90 минут с момента начала использования. Билет даёт право совершить неограниченное число поездок в наземном транспорте (автобус, трамвай, троллейбус) и не более 1 поездки в метро. Стоимость билета «90 минут» на одну поездку — 60 рублей (действителен в день продажи), на две поездки – 120 рублей (действителен 5 дней), на 60 поездок – 2400 рублей (действителен 90 дней).
- Экскурсии в Москве. Самые популярные
📷 экскурсии в Москве, где купить и сколько стоит. - Купить билеты в театр, на концерт, мероприятия онлайн.
- Гостиницы.
👍 Гостиницы рядом со станциями метро, гостиницы поиск по карте. Сравнение цен, отзывы клиентов. - Билет на самолёт —
лучшие сайты для покупки авиабилетов.
- Билет на поезд (🚄 купить онлайн).
- Билет на междугородный автобус (🚌 купить онлайн).
- Музеи. Самые популярные музеи Москвы.
- Вокзалы. Вокзалы и аэропорты города.
- Погода. Погода в Москве сегодня, завтра, прогноз погоды.
- Полезные ссылки для направляющихся в Москву туристов (билеты на самолёт, автобус, экскурсии, путеводители онлайн).
- Такси Аэропорт — 🚕 в аэропорт или из аэропорта.
В одном проекте, с которым пришлось столкнуться по долгу службы, клиент решил немного упростить жизнь гастарбайтеров-курьеров, которые занимаются доставкой товаров из интернет-магазина по Москве. Чтобы ребятам, плохо ориентирующимся в карте столицы, было проще и быстрее добираться до адресата, в путевом листе, помимо адреса, решили указывать ближайшую станцию метро. По задумке клиента, данное нововведение должно повысить скорость доставки и снизить процент потерявшихся курьеров на московских изогнутых улицах.
Путевой лист должен формироваться на сервере – это и стало основной проблемой. Раньше работать с адресами и прочими элементы карты, приходилось только на клиентской стороне. То есть все возможные манипуляции с объектами карты осуществлялись с помощью js и как реализовать подобный функционал на сервере не понятно.
Яндекс карты и http-запросы
Все оказалось предельно просто. У яндекса есть замечательный сервис «геокодирование» от яндекс карт, который позволяет делать http-запросы к своим api. Сервис позволяет определять координаты и получать информацию об объектах расположенных на яндекс картах. Подробнее можно почитать тут: документация. Данных, предоставляемых яндексом, вполне достаточно, чтобы решить задачку, подкинутую клиентом.
Api яндекса позволяют получать данные как в формате xml, так и json. Работать с json-он мне удобнее, поэтому в примерах используется именно он.
Чтобы получить ближайшую станцию метро, необходимо передать в api координаты точки на карте. Координаты должны быть в формате «долгота, широта». Но в базе данных с заказами нет такой информации, есть только адрес. Поэтому необходимо сделать предварительный запрос и получить координаты точки по определенному адресу. Сделать это можно вот так:
/**
* Получение координат адреса
*
* @param $address string - адрес точки
* @return bool | array - false или массив с координатами [долгота, широта]
*/
function getCoordNameByAddress($address){
// удаление лишних пробелов между словами
$address = preg_replace("/ {2,}/", " ", $address);
// замена пробелов на плюсы
$address = str_replace(" ", "+", $address);
// формируется урл для запроса
$url_get_coord = "https://geocode-maps.yandex.ru/1.x/?geocode={$address}&format=json&results=1";
$result = @file_get_contents($url_get_coord);
// если произошла ошибка при отправке запроса или ответе сервера
if(!$result) return false;
$result = json_decode($result);
// если ни чего не нашлось
if(count($result->response->GeoObjectCollection->featureMember) == 0) return false;
// получение координат точки
$coord = $result->response->GeoObjectCollection->featureMember[0]->GeoObject->Point->pos;
return explode(" ", $coord);
}
Получение ближайшей станции метро с помощью php
Теперь, имея координаты адресата, можно получить адрес и название ближайшего метро. В примере ниже, показано определение только названия станции. Но у вас не составит ни какого труда получить и другую информацию о метро, достаточно только вытащить нужные значения из массива данных, который отдает api. Также в запросе можно изменить или вовсе не использовать параметр «results», который определяет количество найденных объектов. Мне было нужно найти только одну станцию, поэтому в примере results равен 1.
/**
* Получение ближайшего метро по координатам
*
* @param array - массив с координатами [долгота, широта]
* @return bool | string - false или название ближайшего метро
*/
function getMetroNameByCoord($coord){
$coord_str = implode(",", $coord);
$url_get_metro = "https://geocode-maps.yandex.ru/1.x/?geocode={$coord_str}&kind=metro&format=json&results=1";
$result = @file_get_contents($url_get_metro);
// если произошла ошибка при отправке запроса или ответе сервера
if(!$result) return false;
$result = json_decode($result);
// если ни чего не нашлось
if(count($result->response->GeoObjectCollection->featureMember) == 0) return false;
return $result->response->GeoObjectCollection->featureMember[0]->GeoObject->name;
}
Поиск ближайшей станции метро по адресу с помощью php
И остается только привести пример использования двух, описанных выше, функций. Возьмем для примера адрес «Петровки 38» и найдем ближайшую к ней станцию метро. Возможно кому-нибудь, спешно покидающему здание МВД, пригодится эта информация.
// адрес $address = "Петровка улица, 38, Москва"; // получение координат адреса $coord = getCoordNameByAddress($address); // получение ближайшего метро по координатам $metro = getMetroNameByCoord($coord); // вывод результата var_dump($metro);
Послесловие
Яндекс установил лимит на количество обращений к своему сервису, он составляет 25 тысяч запросов в сутки. Это большой запас и его будет достаточно для многих сайтов или сервисов. Но если этого количества вам будет не достаточно, то всегда можно воспользоваться платной версией api, подробнее можно почитать тут.
Вступление:
Есть большой список организаций. Список постоянно пополняется сразу множеством организаций. Каждой нужно присвоить множество ближайших станций метро и расстояние по прямой до нее.
В этой статье я рассмотрю, как это можно сделать на php, не прибегая к js.
Задача:
Известна координата организации (можно узнать через http запрос). Также известны координаты всех станций метро (они заранее лежат в БД). Написать скрипт на php, который будет присваивать каждой организации несколько ближайших метро, а также можно расстояние до него.
Решение:
Это полезно для понимания! Почитайте базовые знания в географических координатах: https://leonid.shevtsov.me/post/chto-ty-dolzhen-znat-pro-geograficheskie-koordinaty/
1. Структура БД
Есть 3 таблицы: 1 — организация, 2 — метро, 3 — вспомогательная таблица (где я указываю id_org, id_metro, distance). Другими словами: связь многие-ко-многим через вспомогательную таблицу.
В таблице метро находятся все метро со своими координатами (долгота, широта). Да, надо заранее занести все координаты. Зато в будущем брать координаты из своей БД, и сопоставлять со своим id метро.
Координаты станций метро Москвы, правда, не всех, можно взять отсюда.
2. Выбираем из БД только ближайшие метро в определенном радиусе
Допустим у нас есть координаты организации. Также имеются координаты в БД для каждого метро, которые хранятся в таблице metro. Как выбрать с минимальными производительными затратами ближайшие метро, да еще узнать расстояния по прямой?
Для начала, рассмотрим и поймем логику, по которой будем действовать.
Возьмем самую простую систему координат и пусть точка О, с координатами (3,2) — это организация. (Рис. 1)
Точки М — это станции метро.
Зеленый круг — это радиус, в котором будем искать ближайшие станции метро.
Рис. 1
В первую очередь необходимо выбрать только те метро, которые попадают в радиус. (Для того, чтобы вычислять расстояния только до тех метро, которые попали в этот радиус, а не до всех существующих — ибо на реальной карте Москвы — их больше 180)
Применительно к рис.1:
Откладываем от точки О отрезки (радиус) по оси X (влево и вправо) и по оси Y (вверх и вниз) и получаем координаты квадрата, в котором будем искать метро.
Т.е., грубо и округленно координаты которых лежат в интервале:
по оси Х: от 0 до 6
по оси Y: от 0 до 6
Запрос к MySQL будет выглядеть примерно так:
SELECT * FROM `metro` WHERE `x` BETWEEN ‘0’ AND ‘6’ AND `y` BETWEEN ‘0’ AND ‘6’
В результате получим список метро, которые окажутся в нужном нам квадрате
А далее — выбрать нужное количество ближайших и записать их во вспомогательную таблицу.
3. Находим расстояние между двумя точками (организацией и метро)
На данном этапе у нас есть координаты каждого метро, и собственно координаты нашей организации.
Теперь надо поочередно для каждого метро рассчитать расстояние и выбрать нужное количество ближайших.
С последним все понятно, остановлюсь на нахождении расстояния между двумя точками координат (спутниковых, они же Yandex Map, они же Google Map)
Находим расстояние между 2мя точками через формулу:
cos(d) = sin(φА)·sin(φB) + cos(φА)·cos(φB)·cos(λА − λB),
Прочитать статью про эту формулу для наилучшего понимания =)
На php это будет выглядеть так (возвращает дистанцию в м.):
function distance($longitude1, $latitude1, $longitude2, $latitude2) { $earth_radius = 6372797; //средний радиус Земли в м $dLat = deg2rad($latitude2 - $latitude1); $dLon = deg2rad($longitude2 - $longitude1); $a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * sin($dLon/2) * sin($dLon/2); $c = 2 * asin(sqrt($a)); $d = $earth_radius * $c; return $d; }
Итак, по этому довольно простому алгоритму и формуле легко найти ближайшие метро.
Если у есть какие-либо вопросы — спрашивайте в комментариях.
Используем http запрос для получения ближайших метро
Также можно использовать get запрос для получения текстового списка метро в формате XML или JSON.
Подробнее в разделе офиц. документации
Например, запрос получения ближайших метро для Марсова Поля в СПб, будет выглядеть так:
http://geocode-maps.yandex.ru/1.x/?geocode=30.331393,59.943419&kind=metro
Недостаток: мы получим названия метро, которые будем вынуждены искать в своей БД.
Полезные ссылки:
Хабр. Как работает Yandex MAP API 2.0
Формула вычисления расстояния между двух точек на Земле. Все языки
Вторая часть статьи
Собственно, на свой вопрос я дал ответ в первой части. Во второй я рассмотрю дополнительный весьма полезный и интересный материал, но он больше предназначен для наилучшего понимания данной темы.
2ой способ нахождения расстояния между двумя точками спутниковых координат (или между двумя точками Yandex Map / Google Map)
Когда я рассматривал этот способ, я еще не знал формулы и кода, которые написал в первой части. Эти 2 способа работают почти одинаково. Разница вычислений составляет всего 2 метра. И для данного случая это совершенно не существенно.
Найдем расстояние от точки О до М3. (Рис. 2)
Рис. 2
Вспоминаем теорему Пифагора (квадрат гипотенузы равен сумме квадратов катетов). Т.к. координаты всех точек нам известны — то легко находим длину С (расстояние от метро до организации).
Гладко было на бумаге, да забыли про овраги
А если точнее, то координаты в Yandex Map (да и в Google Map) у нас указаны по долготе и широте в градусах, а следовательно, необходимо переводить градусы широты и долготы в метры, используя коэффициенты. Коэффициенты отличаются в зависимости от широты
Необходимые коэффициенты можно посмотреть в таблице «Длина градуса широты и долготы».
Таблица: длина градуса широты и долготы
Эту таблицу я не нашел в интернете — поэтому нашел ее в в книге: Министерство Обороны Союза ССР. Главное управление навигации и океанографии. Мореходные таблицы. 1976 г. =)
Рассмотрим код для окончательного понимания как этим пользоваться:
Функция возвращает расстояние в метрах между объектами
public function distance2($lng1, $lat1, $lng2, $lat2) { define('LNG_SPB', 55801); //градус долготы в метрах для СПБ define('LAT_SPB', 111414); //градус широты в метрах для СПБ define('LNG_MOSCOW', 63995); //градус долготы в метрах для Москвы define('LAT_MOSCOW', 111325); //градус широты в метрах для Москвы $diffLng = abs($lng2 - $lng1); // разница долготы по модулю $diffLat = abs($lat2 - $lat1); // разница широты по модулю $diffLngM = $diffLng * LNG_SPB; //расстояние в метрах по долготе $diffLatM = $diffLat * LAT_SPB; //расстояние в метрах по широте return $distance = sqrt($diffLngM*$diffLngM + $diffLatM*$diffLatM); }
Проверяем первый и второй способ
Для проверки, измеряем расстояние первым и вторым способом между м. «Невский проспект»: 30.327144,59.935387 и м. «Пл. Восстания»: 30.360704,59.931639. Координаты написаны в порядке (долгота, широта).
function distance() возвратит: 1916.0274249762 (м.)
function distance2() возвратит: 1918.6737626891 (м.)
А если на карте вручную кликнуть на эти станции метро (берем погрешность клика) — то расстояние будет: 1916 м.
Пишите комментарии и задавайте вопросы, если они есть =)
UPDATE 27.07.2017:
КОД НА MySQL:
Ищем организации в радиусе = 7 км.
SELECT *, 111.414 * DEGREES(ACOS(COS(RADIANS(59.901346)) * COS(RADIANS(X(coordinates))) * COS(RADIANS(30.355807 - Y(coordinates))) + SIN(RADIANS(59.901346)) * SIN(RADIANS(X(coordinates))))) AS distance_in_km FROM cemeteries WHERE MBRContains( LINESTRING(POINT(59.901346 - 0.009 * 3 , 30.355807 - 0.01792 * 6371), POINT(59.901346 + 0.009 * 3 , 30.355807 + 0.01792 * 3 )), coordinates ) AND ACOS(COS(RADIANS(59.901346)) * COS(RADIANS(X(coordinates))) * COS(RADIANS(Y(coordinates)) - RADIANS(30.355807)) + SIN(RADIANS(59.901346)) * SIN(radians(X(coordinates)))) <= 3 / 6371
http://stackoverflow.com/questions/6919661/select-within-20-kilometers-based-on-latitude-longitude — Рабочий пример c POINT на mysql!!!!!
http://stackoverflow.com/questions/24370975/find-distance-between-two-points-using-latitude-and-longitude-in-mysql — расстояние к км между двумя точками/ Рабочий пример с POINT
https://www.frameworks.su/article/rasstoyanie_do_bligayshih_stantsii_metro — хорошая статья с применением php и без POINT




