В данной записи, хочу рассказать, как решал задачу распределения списка организации по районам города. Из входных данных использовались адреса, введенные в базу в ручную сотрудниками, поэтому были весьма не консистентыми, некоторый содержали и индекса и город и улицу и адрес дома, некоторые не содержали даже указания города.
Изучение Api известных карт (Google, binq, Yandex), показало, что хоть они и знают про районы города, выдавать по запросу их не хотят.
В результате принял решение:- cначала с помощью вышеуказанных сервисов определить геокоординату адреса
- затем сформировать массивы геокоординат точек - углов регионов города (полигоны)
- определить в какой из полигонов попадает координата адреса.
Так как бесплатное использование сервисов ограничивает кол-во запросов (порядка 10-25тыс.) нужно было использовать сразу несколько из них. Для этого использовал библиотеку: https://github.com/chadly/Geocoding.net
Сначала нужно получить ApiKey на используемых сервисах. например для гугла тут: https://developers.google.com/maps/documentation/javascript/get-api-key
далее создаем объекты - геокодеры:
C# | 1
2
3
4
5
6
| public static Geocoding.IGeocoder[] Geocoders { get; } =
new Geocoding.IGeocoder[]
{
new Geocoding.Google.GoogleGeocoder(@"Ваш API=KEY"),
new Geocoding.Microsoft.BingMapsGeocoder(@"Ваш API=KEY~********~******-fjvUGlbOS-9-************"),
}; |
|
Далее по адресу получаем список-совпадений:
C# | 1
2
| var geocoder = geocoders[geocoderIndex];
IEnumerable<Geocoding.Address> addresses = await geocoder.GeocodeAsync(match); |
|
Первые элементы будут иметь большую релевантность, я всегда использовал первый.
Получить широту и долготу можно так:
C# | 1
2
| var addres = addresses.FirstOrDefault();
return new PointF(addres.Coordinates.Latitude, addres.Coordinates.Longitude); |
|
Дальше нужно создать полигоны районов. Открываем Гугл мэпс, вводим название города и района(округа), появляется контур- граница района. Прокликиваем по порядку каждую точку границы, внизу появляется её широта и долгота:
Собираем все точки района в массив:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| public static DistrictsDetector.District[] OmskDistricts { get; } =
new DistrictsDetector.District[]
{
new DistrictsDetector.District("Tsentral'nyy Okrug", new DistrictsDetector.MapPoint[]
{
new DistrictsDetector.MapPoint(55.032336f, 73.334465f),
new DistrictsDetector.MapPoint(55.033914f, 73.342365f),
new DistrictsDetector.MapPoint(55.027420f, 73.352678f),......
}),
new DistrictsDetector.District("Oktyabr'skiy Okrug", new DistrictsDetector.MapPoint[]
{
new DistrictsDetector.MapPoint(54.975745, 73.399492 ),
new DistrictsDetector.MapPoint(54.978650, 73.448036 ),
new DistrictsDetector.MapPoint(54.983776, 73.448425 ),......
}), |
|
Создаем функцию определения попадания точки в полигон:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
| private static bool IsPointInPolygon(MapPoint[] polygon, MapPoint point)
{
bool isInside = false;
for (int i = 0, j = polygon.Length - 1; i < polygon.Length; j = i++)
{
if (((polygon[i].Longitude > point.Longitude) != (polygon[j].Longitude > point.Longitude)) &&
(point.Latitude < (polygon[j].Latitude - polygon[i].Latitude) * (point.Longitude - polygon[i].Longitude) / (polygon[j].Longitude - polygon[i].Longitude) + polygon[i].Latitude))
{
isInside = !isInside;
}
}
return isInside;
} |
|
И проверяем попадание точки в каждый из районов.
MissionComplete
Посмотреть исходный код тестового проекта можно на ГИТхабе: https://github.com/setood/DistrictsDetector
Вам нужно будет указать ваши Api-key, и ввести полигоны нужных вам районов (там только Омск). Можно определять либо один конкретный адрес, либо загрузить файл- базу.
|