-
Notifications
You must be signed in to change notification settings - Fork 0
/
westra2osm_lib.py
208 lines (174 loc) · 7.22 KB
/
westra2osm_lib.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#!/bin/env python3
# -*- coding: utf-8 -*-
'''
Утиліта для полегшення імпорта данних
Written by Andriy Danyleiko and Liudmyla Kislitsyna
Send bugs to [email protected]
'''
import math
import sys
import urllib.request
import random
import fastkml
import overpy
import lxml.html
def get_pass_from_overpass(longitude_west, latitude_south, longitude_east, latitude_north): #Задаєм стандартний BBOX
# південна_широта, західна_довгота, північна_широта, східна_довгота
'''
get pass from OSM database thru overpass API from bounding box.
Bbox formats:
bbox = left,bottom,right,top
bbox = min Longitude , min Latitude , max Longitude , max Latitude
example get_pass_from_overpass((42.79741601927622,76.61865234374999,43.24520272203359,77.81341552734375))
'''
_query_pattern = '''[out:json][timeout:25];
(
node["mountain_pass"="yes"]({0},{1},{2},{3});
);
out body;
>;
out skel qt;'''
api = overpy.Overpass()
result = api.query(_query_pattern.format(latitude_south,longitude_west,latitude_north,longitude_east))
osm_passes = []
for p in result.nodes:
saddle = MountainPass(p.tags.get('name'), coordinates=(float(p.lat), float(p.lon)), netlink='http://www.openstreetmap.org/node/{0}'.format(p.id))
if p.tags.get('alt_name'):
alt_names = [name.strip() for name in p.tags['alt_name'].split(';')]
saddle.alt_names = alt_names
if p.tags.get('ele'):
saddle.elevation = p.tags.get('ele')
if p.tags.get('rtsa_scale'):
saddle.scale = p.tags.get('rtsa_scale')
osm_passes.append(saddle)
return osm_passes
def distance_between_points(lat1, lon1, lat2, lon2):
'''
функція для пошуку відстані між точками у градусах
TODO: зробить у метрах
>>> distance_between_points(1, 1, 1, 2)
1.0
>>> distance_between_points(1, 1, 1, 1)
0.0
>>> distance_between_points(2,5,6,7) - 4.47213595499958 < sys.float_info.epsilon
True
'''
lat1 = float(lat1)
lon1 = float(lon1)
lat2 = float(lat2)
lon2 = float(lon2)
delta_lat = math.fabs(lat2 - lat1)
delta_lon = math.fabs(lon2 - lon1)
return math.sqrt(delta_lat ** 2 + delta_lon ** 2)
def point_inside_polygon(x,y,poly):
'''determine if a point is inside a given polygon or not
Polygon is a list of (x,y) pairs.
x may be latitude and y longtitude - it does not metter'''
n = len(poly)
inside =False
p1x,p1y = poly[0]
for i in range(n+1):
p2x,p2y = poly[i % n]
if y > min(p1y,p2y):
if y <= max(p1y,p2y):
if x <= max(p1x,p2x):
if p1y != p2y:
xinters = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
if p1x == p2x or x <= xinters:
inside = not inside
p1x,p1y = p2x,p2y
return inside
def poly2bbox(poly):
'''обчислюємо крайні точки полігона'''
lats = [point[0] for point in poly]
lons = [point[1] for point in poly]
longitude_west = min(lons) #долгота левой границы
longitude_east = max(lons) #долгота правой границы
latitude_north = max(lats) #широта верхней границы
latitude_south = min(lats) #широта нижней границы
return round(longitude_west,6), round(latitude_south,6), round(longitude_east,6), round(latitude_north,6)
def get_pass_westra(longitude_west, latitude_south, longitude_east, latitude_north, filename=None):
'''Функція для витягування геопривязаних перевалів із Вестри в kml xml формат.
poly will be converted to bbox'''
k = fastkml.kml.KML()
if filename:
f = open(filename)
k.from_string(f.read())
f.close()
else:
url = 'http://westra.ru/passes/kml/passes.php'
values = {'BBOX' : '{0},{1},{2},{3}'.format(longitude_west, latitude_south, longitude_east, latitude_north)}
r_url = url + '?BBOX=' + values['BBOX']
response = urllib.request.urlopen(r_url)
if response.getcode() != 200:
print ('westra.ru return not 200 HTTP code')
sys.exit(100)
k.from_string(response.read()) #TODO unicode
features = list(k.features())
if len(features) == 1:
features = features[0]
else:
raise NotImplementedError('There are more than 1 feature in object')
ff = list(features.features())
placemarks = []
for folder in ff:
if isinstance(folder,fastkml.kml.Folder):
for p in folder.features():
placemarks.append(p)
else:
raise NotImplementedError('There are not fastkml.kml.Folder object in list')
westra_passes = []
for p in placemarks:
coordinates = tuple(reversed(p._geometry.geometry.coords[0][:2]))
if p.name.startswith('вер. '):
continue
name = p.name.lstrip('пер. ')
root = lxml.html.fromstring(p.description)
netlink = root.xpath("b")[0].findall("a")[0].values()[0]
saddle = MountainPass(name, coordinates=coordinates, netlink=netlink)
#check alt_names
rows = root.xpath("table")[0].findall("tr")
if rows[1].getchildren()[0].text == 'Другие названия':
alt_names_text = rows[1].getchildren()[1].text # rows[1].getchildren()[0].text
if alt_names_text:
alt_names = [p.strip() for p in alt_names_text.split(',')]
saddle.alt_names = alt_names
westra_passes.append(saddle)
return westra_passes
class MountainPass(object):
'''class that describe some of features to possible compare it'''
def __init__(self, name, elevation=None, alt_names=None, coordinates=None, scale=None, netlink=None):
if name:
self.name = name
else:
self.name = '_Unnamed! {0}'.format(random.randint(1, 500))
self.elevation = elevation
self.alt_names = alt_names
self.coordinates = coordinates #lat,lon
self.scale = scale
self.netlink = netlink
def __repr__(self):
return '{0} instance with name "{1}"'.format(self.__class__, self.name)
def has_name(self, item):
if item == self.name:
return True
elif self.alt_names and item in self.alt_names:
return True
else:
return False
__contains__ = has_name
def human_names(self):
if self.alt_names:
return '{main_name} ({alt_names})'.format(main_name=self.name, alt_names=', '.join(self.alt_names))
else:
return self.name
def human_names_with_url(self):
return '<a href={link}>{text}</a>'.format(link=self.netlink, text=self.human_names())
def names(self):
if self.alt_names:
return set([self.name] + self.alt_names)
else:
return set([self.name])
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True, report=True) #raise_on_error=True