Клуб API Карт

У Яндекса ошибка в функции определения ближайших станций метро?

Пост в архиве.

Очевидно ошибка, либо поясните, почему в запросе:

http://geocode-maps.yandex.ru/1.x/?geocode=30.335185,59.934778&kind=metro&format=json&rspn=1&spn=0.026,0.026

Напрочь отсутствует метро: Маяковская и Пл.Восстания, тогда как они очевидно ближе остальных перечисленных, следом за Невским проспектом и Гостинным двором.

4 комментария
Sergey Konstantinov
28 января 2016, 03:00
Вы неправы, эти станции дальше перечисленных:
http://maps.yandex.ru/-/CVB-BD0u
Если увеличить spn, то указанные станции попадут в выдачу:
http://geocode-maps.yandex.ru/1.x/?geocode=30.335185,59.934778&kind=metro&format=json&rspn=1&spn=0.05,0.05

Спасибо это я уже пробовал. Значит проблема все-таки в способе. По прямой они конечно ближе, но если идти не по воздуху - тогда увы.

Придется применить для поиска расстояний пешеходные маршруты, сравнивая вычисленные расстояния. Только у Яндекса же нет пеших маршрутов.

И что теперь делать? :-(

Предлагаемый метод "Правой пяткой за ухом почесать":

1) находим координаты себя

2) узнаем у Яндекса список ближайших станций метро в радиусе

3) берем координаты этих станций и идем в гугль

4) спрашиваем у гугла, какое расстояние переходного маршрута получится у нас до всех найденных координат станций

5) сравниваем, отдаем результат

Возражения?

Предлагаю Вашему вниманию свой код к вышеописанному порядку определения ближайших станций  метро:

 

$current_proxy = -1;

 

// Сортировщик станций

function sort_metro($a, $b) {

if ($a['distance'] == $b['distance']) {

return 0;

}

return ($a['distance'] < $b['distance']) ? -1 : 1;

}

 

function calculateTheDistance ($φA, $λA, $φB, $λB) {

 

    // перевести координаты в радианы

    $lat1 = $φA * M_PI / 180;

    $lat2 = $φB * M_PI / 180;

    $long1 = $λA * M_PI / 180;

    $long2 = $λB * M_PI / 180;

 

    // косинусы и синусы широт и разницы долгот

    $cl1 = cos($lat1);

    $cl2 = cos($lat2);

    $sl1 = sin($lat1);

    $sl2 = sin($lat2);

    $delta = $long2 - $long1;

    $cdelta = cos($delta);

    $sdelta = sin($delta);

 

    // вычисления длины большого круга

    $y = sqrt(pow($cl2 * $sdelta, 2) + pow($cl1 * $sl2 - $sl1 * $cl2 * $cdelta, 2));

    $x = $sl1 * $sl2 + $cl1 * $cl2 * $cdelta;

 

    //

    $ad = atan2($y, $x);

 

// радиус Земли

    //$dist = $ad * 6372795;

// радиус Земли по Яндексу

$dist = $ad * 6378137;

 

    return $dist;

}

 

function Rasstoyanie($lon1, $lat1, $mp) {

// форматируем расстояния между координатами

$point2 = explode(" ",$mp);

$tmp = calculateTheDistance($lat1, $lon1, $point2[1], $point2[0]);

if ($tmp > 1000) {

$tmp = $tmp/1000;

return round($tmp,2)." км";

} else {

return round($tmp)." м";

}

}

 

function Rasstoyanie_num($lon1, $lat1, $mp) {

// форматируем расстояния между координатами

$point2 = explode(" ",$mp);

$tmp = calculateTheDistance($lat1, $lon1, $point2[1], $point2[0]);

return round($tmp);

}

 

try

{

$url='http://geocode-maps.yandex.ru/1.x/?geocode=';

$param='&kind=metro&format=json&rspn=1&spn=0.06,0.06';

 

    include_once(dirname(__FILE__).'/classes/mysqldatabase.php');

    include_once(dirname(__FILE__).'/classes/mysqlresultset.php');

 

$db = MySqlDatabase::getInstance();

$conn = $db->connect('mysq_server', 'login', 'password', 'db', 'utf8');

 

$cnt = 100;

$last_line = 0;

 

while (1){

$res = $db->fetchOne("SELECT `coord_dolgota`,`coord_shirota`,`oid` FROM `objects` WHERE ((`metro`= '' OR `metro` IS NULL)) LIMIT ".$cnt.",1;");

 

$dolgota = $res[0];

$shirota = $res[1];

$line = $res[2];

error_log($line);

$furl = $url.$dolgota.','.$shirota.$param;

 

 

if (!empty($dolgota) && !empty($shirota) && $last_line!=$line){

//error_log($furl."
");

$last_line=$line;

 

// забираем из яндекса список ближайших станций

$page = get_file_contents($furl);

if (!$page) die("No info");

 

$obj = json_decode($page);

 

 

if (!empty($obj->response->GeoObjectCollection->featureMember) && $obj->response->GeoObjectCollection->metaDataProperty->GeocoderResponseMetaData->found >= 1){

$google_dest = '';

$stations_arr = Array();

foreach ($obj->response->GeoObjectCollection->featureMember as $station) {

// Формируем массив найденных станций метро

$point = explode(' ',$station->GeoObject->Point->pos);

 

$stations_arr[] = Array(

'name' => (isset($station->GeoObject->metaDataProperty->GeocoderMetaData->AddressDetails->Country->Locality->Thoroughfare->Premise->PremiseName))?$station->GeoObject->metaDataProperty->GeocoderMetaData->AddressDetails->Country->Locality->Thoroughfare->Premise->PremiseName:((isset($station->GeoObject->metaDataProperty->GeocoderMetaData->AddressDetails->Country->AdministrativeArea->SubAdministrativeArea->Locality->Thoroughfare->Premise->PremiseName))?$station->GeoObject->metaDataProperty->GeocoderMetaData->AddressDetails->Country->AdministrativeArea->SubAdministrativeArea->Locality->Thoroughfare->Premise->PremiseName:''),

'line' => (isset($station->GeoObject->metaDataProperty->GeocoderMetaData->AddressDetails->Country->Locality->Thoroughfare->ThoroughfareName))?$station->GeoObject->metaDataProperty->GeocoderMetaData->AddressDetails->Country->Locality->Thoroughfare->ThoroughfareName:((isset($station->GeoObject->metaDataProperty->GeocoderMetaData->AddressDetails->Country->AdministrativeArea->SubAdministrativeArea->Locality->Thoroughfare->ThoroughfareName))?$station->GeoObject->metaDataProperty->GeocoderMetaData->AddressDetails->Country->AdministrativeArea->SubAdministrativeArea->Locality->Thoroughfare->ThoroughfareName:''),

'pos' => $station->GeoObject->Point->pos,

'lon' => $point[0],

'lat' => $point[1],

'distance' => 0

);

$point3 = explode(' ',$station->GeoObject->Point->pos);

$google_dest .= $point3[1].",".$point3[0]."|";;

}

// Удаляем последнюю "|"

$google_dest = substr($google_dest,0, strlen($google_dest)-1);

//print_r($stations_arr);

//exit();

 

// Формируем запрос к Google Matrix API

// https://developers.google.com/maps/documentation/distancematrix/?hl=ru

$google_uri = "http://maps.googleapis.com/maps/api/distancematrix/json?origins=".$shirota.",".$dolgota."&mode=walking&language=ru&units=metric&sensor=true&destinations=".$google_dest;

 

 

// Проксируем запросы для получения информации о растоянии между станциями метро

$google_response = '';

 

$google_json = get_file_contents($google_uri); 

$google_response = json_decode($google_json);

 

 

 

if (isset ($google_response->rows[0]->elements[0]->status)){

if ($google_response->rows[0]->elements[0]->status == "OVER_QUERY_LIMIT")

die("Google is blocked");

}

 

 

$count_station = count($stations_arr);

// Присваеваем полученные расстояния массиву станций метро

for ($i=0; $i

if (isset ($google_response->rows[0]->elements[$i]->status)){

if ($google_response->rows[0]->elements[$i]->status == "OK") {

// Если Гугль нашел нужное нам расстояние пешей прогулки

$stations_arr[$i]['distance'] = $google_response->rows[0]->elements[$i]->distance->value;

$stations_arr[$i]['duration'] = $google_response->rows[0]->elements[$i]->duration->value;

} else {

// если нет, тогда считаем сами

$stations_arr[$i]['distance'] = Rasstoyanie_num($dolgota, $shirota, $stations_arr[$i]['pos']);

}

}

}

 

if ($stations_arr) {

uasort($stations_arr, 'sort_metro');

$stations_arr[0]['name'] = str_replace('метро ', '', $stations_arr[0]['name']);

$db->update('UPDATE `objects` SET `metro` ="'.$stations_arr[0]['name'].'",`metro_dolgota` ="'.$stations_arr[0]['lon'].'",`metro_shirota` ="'.$stations_arr[0]['lat'].'",`metro_distance` ="'.$stations_arr[0]['distance'].'",`metro_line` ="'.$stations_arr[0]['line'].'" WHERE `oid` = "'.$line.'";');

}

 

++$line;

$fp = fopen($filename, "w");

fwrite($fp,$line);

fclose($fp);

 

//sleep(1);

} else $cnt++;

} else { 

$cnt++;

 

}

 

// ручной ограничитель под размер БД

if ($res[2]>=8644) exit("Готово.");

}

}

catch (Exception $e) {

    die($e->getMessage());

}

?>