OSM POI to OZI(wpt)

Ответить
Азимут
Новоприбывший
Сообщения: 12
Зарегистрирован: 13 июл 2011, 00:54
Репутация: 0

OSM POI to OZI(wpt)

Сообщение Азимут » 27 июл 2011, 23:35

Началось с того, что не смог я сделать нормальную навигацию на основе OSM-данных. В случае навигации на GPSMapEdit все POI-объекты выглядят одинаково и уныло.
Узнав про OGR, решил попробовать экспортировать данные. Использование ogr2ogr ни к чему толковому не привели: KML-генериться хороший, а в CSV не хватает некоторых полей, да и способ не особо гибкий. Обнаружив статью "Работа с векторными данными при помощи OGR и Python" подумал что нашел выход из ситуации и заодно в Python-е поковыряюсь.

Для работы используются файлы полученные здесь. Запускаем скрипт, указав имя входного shp-файла и имя выходного wpt-файла. Получаем результат с расстановкой иконок для Garmin, (так доступно больше вариантов типов).
Если у объекта есть имя, оно отображается в виде подписи к иконке, если нет, в качестве подписи используется тип.

Есть возможность пропускать ненужные типы через:
1) метод OGRLayer::SetAttributeFilter
2) фильтрацию при обходе объектов
что удобнее пока не решил.

По окончанию работы выводится статистка обработки, в том числе по объектам, для которых не удалось определить тип. Это происходит либо потому, что тип не указан в массиве типов (name_types), либо кто-то создал объект с кривым тегом, напр. я отловил несколько amenity=почта и т.д. Вывод идентификаторов таких объектов позволяет загрузить его в редактор и исправить.

С радостью выслушаю ваши пожелания и комментарии.
osm_to_wpt.py
(9.08 КБ) 988 скачиваний
А так же самая свежая версия на github

Код: Выделить всё

# http://gis-lab.info/qa/ogr-python.html
# -*- coding: utf-8 -*-

#from osgeo import gdal
#from osgeo import ogr
#from osgeo import osr
#from osgeo import gdal_array
#from osgeo import gdalconst

#import gdal
#import ogr
#import osr
#import gdalnumeric
#import gdalconst

# Скрипт для конвертации точек из OSM в wpt-файл.
# Строка запуска: osm_to_wpt.py имя_входного_файла.shp имя выходного файла
# Массив name_types содержит соответствие name и иконки в Ozi (пока для Garmin)

# Массив ignore_types содержит name, которые не должны попадать в выходной файл.
# Лучше ли для игнорирования использовать SetAttributeFilter пока не решил.

import sys, os.path

import osgeo.ogr as ogr
type_notfound = 0
poi_passed = 0
total_pocessed = 1
poi_ignored = 0
poi_skipped = 0
not_found_list = []
poi_converted = 0

head = 'OziExplorer Waypoint File Version 1.1\nWGS 84\nReserved 2\ngarmin\n'

# имя типа, id иконки в ozi
name_types = [['fuel', 25], ['traffic_signals', 146], ['post_office', 44], ['bank', 2], ['telephone', 63],  ['emergency_phone', 63], ['cafe', 3],
              ['pharmacy', 106], ['place_of_worship', 12], ['restaurant', 47], ['police', 151], ['parking', 42], ['bar', 3], ['pub', 3],
              ['speed_camera', 165], ['crossing', 18], ['car_wash', 0], ['drinking_water', 21], ['fast_food', 22],
			  ['marketplace', 55], ['shop', 55], ['toilets', 48], ['car_repair', 10], ['hospital', 36],['clinic', 36], ['doctors', 36], ['waste_basket', 148], ['waste_disposal', 148]]

# имена типов, которые не попадут в выходной файл
ignore_types = ['bus_stop', 'place_of_worship', 'school', 'library', 'street_lamp', 'university', 'courthouse', 'bench', 'bus_station', 'fire_station', 'kindergarten',\
				'bicycle_parking', 'turning_circle', 'public_building', 'cinema', 'steps', 'incline', 'platform', 'embassy', 'townhall', 'post_box', 'theatre',
				'fountain', 'arts_centre', 'taxi', 'sauna', 'bank', 'lamp', 'dentist', 'college']

# хранит статистику: сколько каких типов не удалось определить,
class not_found_stat:
	def __init__(self, name):
		self.name = name
		self.count = 1
	count = 0				# Количество совпадений
	name = ''				# Имя типа
	
# Перекодировка из  utf-8 в win1251
def utf8_to_win(utf8):
	s_uni = utf8.decode('utf8')
	try:
		s_cp1251 = s_uni.encode('cp1251')
		return s_cp1251
	except ValueError:
		print "Oops! Error encode: [" + utf8 + "]"	# бывает и такое
		return utf8

def usage():
	print "Usage: osm_to_wpt.py input_shapefile output_wptfile"
	sys.exit( 0 )

# Меняем текстовый тип на цифру для Garmin
def get_type(name, osmId):
	global type_notfound
	global poi_passed
	global not_found_list

	for name_type in name_types:
		if name_type[0] == name:
			poi_passed += 1
			return ('%d' % (name_type[1]))
	type_notfound += 1
	if len(not_found_list) == 0:
		new_item = not_found_stat(name)
		not_found_list.append(new_item)
	else:
		is_new_item = False
		for not_found_item in not_found_list:
			if not_found_item.name == name:
				not_found_item.count += 1
				return '0'
		new_item = not_found_stat(name)
		print "type not found of OSM_ID: " + osmId + " <=> " + name
		not_found_list.append(new_item)
	return '0'

def is_ignore(name):
	global poi_ignored
	for item in ignore_types:
		if item == name:
			poi_ignored += 1
			return True
	return False

if __name__ == '__main__':

	counter = 1				# счетчик строк wpt-файла

	args = sys.argv[ 1: ]

	if len( args ) != 2:
		usage()

	inPath = os.path.normpath(args[ 0 ])
	outPath = os.path.normpath(args[ 1 ])

	ogrData = ogr.Open( inPath, False )
	f = open( outPath, 'w' )

	# проверяем все ли в порядке
	if ogrData is None:
		print "ERROR: open failed"
		sys.exit( 1 )

	print "Number of layers", ogrData.GetLayerCount()
	layer = ogrData.GetLayer( 0 )
	if layer is None:
		print "ERROR: can't access layer"
		sys.exit( 1 )
	
	layer.ResetReading()

	fieldName2 = 'AMENITY'
	fieldValue2 = 'parking'

	fieldName3 = 'AMENITY'
	fieldValue3 = 'fuel'

	query = fieldName2 + '=' + fieldValue2 + ' or ' + fieldName3 + '=' + fieldValue3

	"""query1 = 'HIGHWAY != BUS_STOP'
	query2 = 'HIGHWAY != street_lamp'

	query = query1 + ' and ' + query2"""

#	query = fieldName4 + ' = ' + fieldValue4

#	layer.SetAttributeFilter( query )

	# начинаем просматривать объекты в исходном слое
	inFeat = layer.GetNextFeature()
	f.write( head ) # write wpt head

	# собственно цикл в котором и перебираем объекты, удовлетворяющие
	# условию фильтра
	feat = layer.GetNextFeature()
	featDef = layer.GetLayerDefn() # схема (таблица атрибутов) слоя
	while feat is not None:
		type = ''		# тип точки fuel, telephone и т.д.
		name = ''		# osm:name
		xPos = ''		# lat
		yPos = ''		# lon
		osmId = ''		# OSM_ID - идентификатор точки
		for i in range( featDef.GetFieldCount() ): # проходим по всем полям
			fieldDef = featDef.GetFieldDefn(i) # получаем i-тое поле
			field_name = fieldDef.GetNameRef() # и выводим информацию
			field_value = feat.GetFieldAsString(i)
			if len(field_value) > 0:
				if field_name == 'OSM_ID':
					osmId = field_value			# сохраняем OSM_ID
					geom = feat.GetGeometryRef()
					if geom is None:
						print "Invalid geometry"
					if geom.GetGeometryType() == ogr.wkbPoint:
						xPos = geom.GetX()		# сохраняем широту
						yPos = geom.GetY()		# сохраняем долготу
						coords = "%.7f, %.7f" % ( geom.GetY(), geom.GetX() )
					else:
						print "Non point geometry"
				elif field_name == 'HIGHWAY' or field_name == 'AMENITY' :	# Нам нужны тольк они
					type = field_value						# сохраняем тип
				if field_name == 'NAME':
					name = field_value						# сохраняем name
		if len(type) > 0 and not is_ignore(type):
			wpt_type = get_type(type, osmId)				# Преобразуем тип в ozi
			
			wpt_line = ('%d, ' % (counter))					# Добавляем номер строки
			if len(name) > 0:
				wpt_line += ('%s, ' % (utf8_to_win(name)))	# Если есть имя, то указываем его
			else:
				wpt_line += ('%s, ' % (type))				# иначе указываем тип
			wpt_line += ('%s, ' % (coords))					# добавляем координаты
			wpt_line += '40741.9547917, '					# пока без изменений
			wpt_line += ('%s, ' % (wpt_type))				# иконка

			wpt_line += '0, '								# пока без изменений
			if wpt_type == '0':								# если тип не найден
				wpt_line += '3, '							# отображать точку
			else:
				wpt_line += '4, '							# отображать иконку

			wpt_line += '0, 65535, '							# пока без изменений
			wpt_line += ('%s, ' % (utf8_to_win(name)))		# вставляем имя в комментарий. вот только зачем...
			wpt_line += '0, 0, '								# пока без изменений

			if wpt_type == '165':							# Если точка speed_camera
				wpt_line += '500, '							# отрисовываем вокруг нее
			else:
				wpt_line += '0, '							# ни чего необычного
				
			wpt_line += '-777, 6, 0,17,0,10.0,2,,,\n'		# пока без изменений
			f.write( wpt_line )								# пишем в выходной файл
			poi_converted += 1
			counter += 1
		else:
			poi_skipped += 1
		feat = layer.GetNextFeature() # переходим к следующему объекту
		total_pocessed += 1
	f.close()

	print ":::::::::::::::::::::::::"
	print "Feature count: ", layer.GetFeatureCount()
	print ('total_pocessed: %d' % (total_pocessed))
	print ('poi_converted: %d, (passed: %d, type_notfound: %d)' % (poi_converted, poi_passed, type_notfound))
	print ('poi_skipped: %d, (ignored: %d)' % (poi_skipped, poi_ignored))
	print ('not_found_list size: %d' % (len(not_found_list)))
	for item in not_found_list:
		print ('[%3d] %s' % (item.count, item.name))
Последний раз редактировалось Азимут 28 июл 2011, 10:59, всего редактировалось 1 раз.

Аватара пользователя
Максим Дубинин
MindingMyOwnBusiness
Сообщения: 9128
Зарегистрирован: 06 окт 2003, 20:20
Репутация: 747
Ваше звание: NextGIS
Откуда: Москва
Контактная информация:

Re: OSM POI to OZI(wpt)

Сообщение Максим Дубинин » 28 июл 2011, 00:42

напомните, пожалуйста, где и как используются wpt-файлы?
пристегивайтесь, турбулентность прямо по курсу

Азимут
Новоприбывший
Сообщения: 12
Зарегистрирован: 13 июл 2011, 00:54
Репутация: 0

Re: OSM POI to OZI(wpt)

Сообщение Азимут » 28 июл 2011, 09:42

Максим Дубинин писал(а):напомните, пожалуйста, где и как используются wpt-файлы?
Есть замечаельная программа Ozi Explorer :)

Аватара пользователя
Максим Дубинин
MindingMyOwnBusiness
Сообщения: 9128
Зарегистрирован: 06 окт 2003, 20:20
Репутация: 747
Ваше звание: NextGIS
Откуда: Москва
Контактная информация:

Re: OSM POI to OZI(wpt)

Сообщение Максим Дубинин » 30 июл 2011, 12:22

пристегивайтесь, турбулентность прямо по курсу

Азимут
Новоприбывший
Сообщения: 12
Зарегистрирован: 13 июл 2011, 00:54
Репутация: 0

Re: OSM POI to OZI(wpt)

Сообщение Азимут » 17 авг 2011, 11:28

Максим Дубинин писал(а):еще кажется в тему
PLT & WPT -> в SHP (python) готовый скрипт
Спасибо за ссылку.

Знакомые ездили на Кольский, дал им точки под Ozi. Говорят очень заправки/магазины/аптеки помогали.

Ответить

Вернуться в «GDAL/OGR»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 18 гостей