Клуб API Карт

Регионы и обратное геокодирование - разные названия регионов

Юрий Федоров
22 апреля 2014, 09:18

Всем доброго дня!

Коллеги, помогите пожалуйста разобраться. У меня есть ресурс, в котором хранятся данные с привязкой к регионам. Основной ключ привязки - osmid.

Задача по клику на карте определить страну и регион(область, республику) в этой стране, и получить osmid региона.

Делаю следующим образом:

Запрашиваю обратное геокодирование для координат клика:

      ymaps.geocode(coords).then(function (res) {

Записываю в свой массив ту информацию, которая идет между первой и второй запятой, например из ответа "Россия, Республика Бурятия, Курумканский район" я беру "Республика Бурятия":

     geocodeRegs.push(obj.properties.get('text').split(', ')[1])

Затем я запрашиваю список регионов

     var myQuery=ymaps.geoQuery(ymaps.regions.load(myCountry,{lang: 'ru', quality: 1}));

Записываю названия регионов в отдельный массив:

      myQuery.each(function (myQueryObj) {
      geoqueryRegs[myQueryObj.properties.get('name')]=myQueryObj.properties.get('osmId');

Далее я последовательно сравниваю массивы ответа geocode и geoquery. Можно было бы вместо этого использовать geoQuery.search, но есть проблема:

Одни и те же регионы в ответах geocode и geoQuery иногда называются по разному.

Пример:

  • Ответ geocode: "Республика Бурятия"
  • Ответ geoquery: "Бурятия"

Еще:

  • Ответ geocode: "Республика Саха (Якутия)"
  • Ответ geoquery: "Республика Саха"


Соответственно вопрос - я что-то не так делаю, или нужно проверять еще и на наличие вхождений подстрок ответов друг в друга, или делать свою базу соотношений?

 

Специально сделал пример с отладкой:

http://dryu.ru/devel/samples/ymaps_question1.html

 

var YMCMGetRegAndCoords = function  (YMCMContainer) {


 var myAllRegs = new ymaps.GeoObjectCollection();
 var CountryCount=0
 var ThreadOK=0;
 YMCMMap = new ymaps.Map(YMCMcontainer, {
    center:[68.78, 97.75],
    zoom:2,
    type: "yandex#map",
 });
 YMCMMap.controls
    .add('zoomControl')
    .add('mapTools')
    .add('typeSelector');
 YMCMMap.copyrights
    .add('&copy; <a href="http://dryu.ru">DrYu</a>')

 YMCMMap.events
    .add('click', function (e) {
       var coords = e.get('coordPosition');
       var country='';
       var subRegion='';
       var subRegionOsmid='';
       // Запрос на геокодирование
       ymaps.geocode(coords).then(function (res) {
         var geocodeRegs = [];
         // Переберём все найденные результаты.
         res.geoObjects.each(function (obj) {
            //сохраняем себе название страны
            country=obj.properties.get('text').split(', ')[0];
         //  alert(obj.properties.get('text'));
            if (obj.properties.get('text').split(', ')[1] != undefined) {
              var mustAdd=true;
              for (var reg in geocodeRegs) {
               if (obj.properties.get('text').split(', ')[1] == geocodeRegs[reg]) {mustAdd=false};
              }
              if (mustAdd){geocodeRegs.push(obj.properties.get('text').split(', ')[1])};
            }
          });
         // alertObj(geocodeRegs);
          var canQuery=false;
          for(var myCountry in YMCMCountries) {
            if (YMCMCountries[myCountry].NameRus == country) {
             canQuery=true;
            }
          }
         if (canQuery) {
           for(var myCountry in YMCMCountries) {
        //    alertObj(YMCMCountries[myCountry].NameRus);
             if (YMCMCountries[myCountry].NameRus == country) {
                var geoqueryRegs = [];
//               alert (country);

               var myQuery=ymaps.geoQuery(ymaps.regions.load(myCountry,{lang: 'ru', quality: 1}));
               myQuery.then(
                 function ()
                  {
                    myQuery.each(function (myQueryObj) {
                      //alertObj(myQueryObj.properties.getAll());
                      geoqueryRegs[myQueryObj.properties.get('name')]=myQueryObj.properties.get('osmId');

                    })
                  //  alertObj(geoqueryRegs);

                    for(var regGeocode in geocodeRegs) {
                     // alert(geocodeRegs[regGeocode]);
                      for(var regGeoquery in geoqueryRegs) {
                       if (regGeoquery == geocodeRegs[regGeocode]) {
                        subRegion=regGeoquery;
                        subRegionOsmid=geoqueryRegs[regGeoquery];
                        //alert ('Соответствие найдено: '+regGeoquery);
                       }

                      }
                    }
                    var myText='';
                    if (subRegion != '') {
                      myText='<h2>Успешно найдено!</h2>Страна: '+country+'<br> Регион: '+subRegion+'<br> OSMID: '+subRegionOsmid;
                    }
                    else {
                      myText='<h2>Соответствия не найдено!</h2>Страна: '+country;
                    }
                    myText=myText+'<h2>Регионы из ответа geocode:</h2>';

                    for(var regGeocode in geocodeRegs) {
                     myText=myText+geocodeRegs[regGeocode]+'<br>';
                    }
                    myText=myText+'<h2>Регионы из ответа geoquery:</h2>';
                     for(var regGeoquery in geoqueryRegs) {
                      myText=myText+regGeoquery+'<br>';
                     }
                    document.getElementById('debugconsole').innerHTML=myText;
                   },
                 function (){alert('No response');}
               )

             }
           }
         }
        else
        //Страна не в списке доступных для яндекс.регионов
        {
           document.getElementById('debugconsole').innerHTML='<h2>Страна не делится на регионы</h2>Страна: '+country;
        }
      });

   });



}

 

 

10 комментариев
Данные для модуля регионы берутся с OpenStreetMap.org. Сливать их со своей базой мы не имеем права согласно лицензии OSM.
Юрий Федоров
22 апреля 2014, 10:49

Ясно, спасибо!

Вроде бы корректно отрабатывает сравнение через подстроки

if ((regGeoquery == geocodeRegs[regGeocode]) || (regGeoquery.indexOf(geocodeRegs[regGeocode]) != -1 ) || (geocodeRegs[regGeocode].indexOf(regGeoquery) != -1 )) {

Юрий Федоров
22 апреля 2014, 11:18

Нет, все-таки не работает.

Могилевская область != Могилёвская область

Восточно-Казахстанская область != Восточно Казахстанская область

 

Вот этот код вроде лечит

                       var codeReg= geocodeRegs[regGeocode].toLowerCase();
                       var queryReg= regGeoquery.toLowerCase();
                       codeReg=codeReg.replace("-", " ");
                       queryReg=queryReg.replace("-", " ");
                       codeReg=codeReg.replace("ё", "е");
                       queryReg=queryReg.replace("ё", "е");
                       if ((codeReg.indexOf(queryReg) != -1 ) || (queryReg.indexOf(codeReg) != -1 )) {

                        subRegion=regGeoquery;
                        subRegionOsmid=geoqueryRegs[regGeoquery];

эти замены – какой-то АД

Так же как и на каждый клик делать запрос за регионами

Юрий Федоров
22 апреля 2014, 12:30

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

Про замены - как только будет понятно, что их достаточно - будем оптимизировать :-)

 

Есть альтернативное видение по получению нужного региона?

 

А какая задача?

Все у вас не правильно.

Если у вас загружены данные модуля регионов - молча пройдитесь по это коллекции ( можно через geoQuery) и просто выберите регион в который попадает точка.

"Правильные" названия брать надо из вики или КЛАДРа - в osm написано как кто-то написал.

Вообще задача определить страну и регион, да еще с привязкой к osm, очень не проста. И не решается на клиенте вообще.

Юрий Федоров
23 апреля 2014, 12:55

О, спасибо за идею про прохождение по коллекции.

буду делать так - через geocode определять страну, если она в списке (RU,BY,UA,KZ) - буду подгружать регионы и искать точку вхождения в них.

 

Юрий Федоров
24 апреля 2014, 12:21

Спасибо за идею, все получилось. В итоге через geocode запрашиваю страну и регионы, проверяю на то, что точка на суше и если страна в списке (RU,BY,UA,KZ) - запрашиваю поиск через geoquery. Единственный минус - приходится перед поиском добавлять регионы на карту.

var YMCMWaterRegions=['море','океан','озеро','водохранилище','залив','губа','пролив','волга'];

var YMCMCountries = {
    RU: {
         Osmid: 60189,
         Name: "Russia",
         NameRus: "Россия"
        },
    UA: {
         Osmid: 60189,
         Name: "Ukraine",
         NameRus: "Украина"
        },
    BY: {
         Osmid: 59065,
         Name: "Belarus",
         NameRus: "Беларусь"
        },
    KZ: {
         Osmid: 214665,
         Name: "Kazakhstan",
         NameRus: "Казахстан"
        }
}

var YMCMGetFromCoords = function  (MyMap, coords, callback) {

       var country=''; //Название страны
       var subRegion=''; //регион (область или республика)
       var subRegionOsmid=''; //OSMID региона
       // Запрос на геокодирование
       ymaps.geocode(coords).then(function (res) {
         var geocodeRegs = [];
         // Переберём все найденные результаты.
         res.geoObjects.each(function (obj) {
            //сохраняем себе название страны
            country=obj.properties.get('text').split(', ')[0];
            //Перебираем результаты, ищем названия и регионов.
            if (obj.properties.get('text').split(', ')[1] != undefined) {
              var mustAdd=true;
              for (var reg in geocodeRegs) {
               if (obj.properties.get('text').split(', ')[1] == geocodeRegs[reg]) {mustAdd=false};
              }
              if (mustAdd){geocodeRegs.push(obj.properties.get('text').split(', ')[1])};
            }
          });

          var isWater=false;
          //Проверяем, что точка на карте находится не в воде. Сравниваем с массивом YMCMWaterRegions
          for(var myWaterName in YMCMWaterRegions) {
              if (country.toLowerCase().indexOf(YMCMWaterRegions[myWaterName]) != -1 ) {
                   isWater=true;
              }
              if (geocodeRegs[0] != undefined ) {
                if (geocodeRegs[0].toLowerCase().indexOf(YMCMWaterRegions[myWaterName]) != -1 ) {
                   isWater=true;
                }
              }
          }
         if (isWater) {
          callback ('water',country,'null','null');
//          alert ("is water!");
         }
         else {

           var canQuery=false;
           var queryCountry=''
           //Проверяем вхождение страны в список стран с регионами
           for(var myCountry in YMCMCountries) {
             if (YMCMCountries[myCountry].NameRus == country) {
               canQuery=true;
               queryCountry=myCountry;
             }
           }
           if (canQuery) {
              //запрашиваем регионы для страны и добавляем их на карту. без добавления не будет работать поиск по координатам.
              var myQuery=ymaps.geoQuery(ymaps.regions.load(queryCountry,{lang: 'ru', quality: 1})).addToMap(MyMap);
              myQuery.then(
                function ()
                  {
                   //Ищем вхождение точки клика в регион
                   searchObj=myQuery.searchContaining(coords);
                   //чистим за собой карту, чтобы на ней не было регионов.
                   myQuery.each(function (myObj) {
                   MyMap.geoObjects.remove(myObj);
                  })
                  searchObj.each(function (myQueryObj) {
                    callback ('regioncountry',country,myQueryObj.properties.get('name'),myQueryObj.properties.get('osmId'));
                  })
                })
            }
            else
           //Страна не в списке доступных для яндекс.регионов
            {
              callback ('othercountry',country,'null','null');
            }
         }
      });

   };

Вы так и не сказали зачем это делаете, и что хотите.

Я уже говорил что на клиенте эту задачу решать не очень хорошо.