Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Где мое почтовое отделение? — поиск почтового отделения ДубльГис по индексу

Anna | 18.06.2014 | нет комментариев
Однажды позже переезда пришлось озадачиться поиском своего почтового отделения. В последних версиях настольной версии 2Гис, к счастью, для большинства городов имеется информация об индексах зданий и в финальном выводе поиск свелся к выбору почтового отделения по номеру, равному последним трем цифрам индекса, впрочем число рутинных операций для этого было довольно огромно и захотелось на досуге в качестве разминки для ума и из любви к прикладным алгорифмам попытаться данный процесс автоматизировать.

Попытка №1

Вначале было решено пойти «в лоб», то есть обнаружить метод получить по индексу сразу адрес почтового отделения. Метод нашелся довольно стремительно — на сайте почты России имеется сервис Поиск отделений почтовой связи, реализующий данную задачу. Правда устойчивость и скорость работы данного обслуживания оставляет хотеть лучшего (последние несколько дней он вообще отключен в связи с проведением профилактических работ), было обнаружено довольно сторонних сервисов, зеркалирующих эту информацию, скажем ГдеПосылка либо Самостоятельный рейтинг почтовых отделений России. Впрочем появилась иная задача — полученный адрес дозволено было только целиком скормить приложению через пользовательский интерфейс в универсальное поле «Где»:

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

Попытка №2

Помимо адреса почтового отделения, приведенные выше сервисы так же информируют его наименование, которое, в всеобщем случае, состоит из названия населенного пункта и порядкового номера отделения если их несколько. Этой информации, в всеобщем случае, должно хватить для поиска по справочнику организаций (по населенному пункту и названию отделения). На данном этапе был реализован 1-й рабочий вариант плагина, опрашивающий все три приведенных обслуживания исходя из их доступности (репозиторий на GitHub). Впрочем в любом случае время отклика было нестабильным да и идеология настольного приложения 2Гис полагает вероятность полновесной работы в offline-режиме.

Попытка №3

Позже непродолжительных поисков offline-базы был обнаружен Эталонный Справочник Почтовых индексов объектов почтовой связи, представляющий собой DBF файл, да еще и обновляющийся с завидной периодичностью. Из 18-мегабайтного файла была сделана выборка только нужной информации и включена в плагин.
Впрочем на данном этапе был найден ряд задач с именами почтовых отделений и их отнесению к населенным пунктам. Фактически все из них удалось решить в нынешней реализации плагина (нынешняя ветка на GitHub).
Ниже представлен стержневой алгорифм образования критериев для поиска почтового отделения в справочнике организаций:

// Получаем наименование почтового отделения
string postOfficeName = LocalFileInformationService.Instance.GetPostOffice(postIndex);
if (postOfficeName != null)
{
	// Наименование отделения в виде "<Населенный пункт> <номер>"
	Match m = CITY_POST_OFFICE_NAME.Match(postOfficeName);
	String city;
	String number;
	if (m.Success)
	{
		// Почтовое отделение с номером
		city = m.Groups[1].Value;
		number = m.Groups[2].Value;
	}
	else
	{
		// Почтамт, либо единствненое отделение в небольшом населенном пункте
		city = postOfficeName;
		number = null;
	}
	try
	{
		ICriteriaSet criteries = _pBaseView.Factory.CreateCriteriaSet();
		// ищем организации в рубрике "Почтовые отделения"
		criteries.set_Criterion("grym_rub:name", "Почтовые отделения");
		string gisCityName;
		if (_cities.TryGetValue(city, out gisCityName))
		{
			// если в базе есть населенный пункт с наименованием, совпадающим с наименованием почтовго отделения, локализуем поиск в данном населенном пункте
criteries.set_Criterion("grym_city:name", gisCityName);
		}
		if (number != null)
		{
			// если у отделения есть номер, скорее каждого он будет в его наименовании
			criteries.set_Criterion("grym_name", number);
		}
		else
		{
			// узнаем число отделений в населенном пункте отделения
			int officesCount = LocalFileInformationService.Instance.GetCityPostOffices(city, postIndex.Substring(0, 3));
			if (officesCount > 2)
			{
				// если в городе огромнее 2-х (для верности) почтовых отделений, то отделение без номера скорее каждого именуется "Почтамт"
				criteries.set_Criterion("grym_name", "Почтамт");
			}
			else if (String.IsNullOrEmpty(gisCityName))
			{
				// напротив если не удалось локализовать поиск по населенному пункту (скажем пос. ?сный в г. Томск не входит в базу населенных пунктов), ищем назвнаие населенного пункта в наименовании почтового отделения
				// остается вопрос как быть с почтовыми отделениями, наименования которых не соответствуют наименованиям населенных пунктов, скажем отделенеие Томь в Черной речке и Тимирязевский в Тимирязево.
				if (((int)dr.Value["addr_count"]) > 0)
				{
					// определяем город в котором находится данный дом
					string featureCity = dr.Value["city"].ToString();
					// узнаем число отделений в населенном пункте к которому относится здание
					int officesCount2 = LocalFileInformationService.Instance.GetCityPostOffices(NormalizeCityName(featureCity), postIndex.Substring(0, 3));
					if (officesCount2 > 0)
					{
						// если мы находимся в населенном пункте с несколькими отделениями, значит скорее каждого мы в поселке, входящем в состав города (не вынесен как обособленный населенный пункт) (пос. ?сный, Томск)
						// значит необходимо искать по наименованию отделения
						criteries.set_Criterion("grym_name", city);
					}
					else
					{
						// в населенном пункте нет почтовых отделений именующихся так же как и сам населенный пункт. Необычно, придется легко вывести все почтовые отделения в населенном пункте
						// скажем почтовое отделение в пос. Черная речка, Томск именуется Томь
						criteries.set_Criterion("grym_city:name", featureCity);
					}
					// else Как быть с селом Тимирязево, тот, что входит состав города Томска, а почтовое отделение именуется Тимирязевский?
				}
				else
				{
					// Дом без адреса? Необычно, откуда тогда у него индекс
					criteries.set_Criterion("grym_name", city);
				}
			}
		}
		_pBaseView.Frame.DirectoryCollection.Search(criteries, "Почтовое отделение "   postIndex, "<criterion>Почтовое отделение</criterion><description>"   postOfficeName   "</description>");
	}
	catch (Exception e)
	{
		MessageBox.Show(e.Message   e.StackTrace   e.GetType().ToString());
	}
}
else
{
	MessageBox.Show("Упс, схоже такого индекса не существует.");
}

Осталась только задача с селом Тимирязево, официально входящим в состав города Томска — отделение в нем именуется «Тимирязевский», но само село не выделено в справочнике как независимый населенный пункт (что так и есть). Допустимо стоит возвратиться к пункту 1 и попытаться поработать с адресной информацией.

Попытка №4

Еще было предположение, что здание, в котором располагается почтовое отделение имеет тот же индекс, что и само отделение, но это оказалось не так, скажем Почтовое отделение №39 в Прокопьевске имеет индекс 653033. К тому же API 2Гис не разрешает в критериях поиска организаций указывать почтовый индекс здания.

Плюшки и совершенствования.

Автообновление.

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

Интерфейс.

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

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

class CustomMainController : IMapInfoController, IControlAppearance, IObjectCustomization
{
	private IMapInfoController _innerController;
	private IBaseViewThread _pBaseView;
	private string _currentCity;

	public CustomMainController(IBaseViewThread pBaseView)
	{
		_innerController = ((GrymCore.IMapInfoControllers2)pBaseView.Frame.Map.MapInfoControllers).FindMapInfoController("Grym.MapInfo.Default");
		_pBaseView = pBaseView;
		_currentCity=_pBaseView.BaseReference.Name;
		((GrymCore.IMapInfoControllers2)pBaseView.Frame.Map.MapInfoControllers).RemoveController(_innerController);
		((GrymCore.IMapInfoControllers2)pBaseView.Frame.Map.MapInfoControllers).AddController(this);

		PostalInformationServiceManager.Instance.BaseViewThread = _pBaseView;
	}

	public bool Check(IFeature f)
	{
		return _innerController.Check(f);
	}

	...
}

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

Завершение

На данном этапе первичная задач написания плагина (порешать увлекательную задачку, исследовать что-то новое, припомнить c#) как бы бы исполнена. Помимо того возникла идея иного плагина, расширяющего функциональность фильтра «Работает теперь». Следственно нужно принимать решение, что делать дальше. В этом хотелось бы прислушаться к суждению сообщества — внезапно кому-то будет увлекательна данная разработка либо появятся увлекательные идеи для ее становления.

Скачать:

Обыкновенная версия плагина
Версия плагина заменяющая индекс здания на ссылку (осмотрительно, версия нестабильна и может приводить к падению оболочки 2Гис).

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB