1
1
# openpoiservice/server/parse_osm.py
2
- from openpoiservice .server import db
3
- from openpoiservice .server import categories_tools , ops_settings
4
- from openpoiservice .server .db_import .models import POIs , Tags , Categories
5
- from openpoiservice .server .db_import .objects import PoiObject , TagsObject
2
+
6
3
import logging
7
4
from bisect import bisect_left
8
5
from collections import deque
9
6
7
+ import numpy as np
8
+ from cykhash .khashsets import Int64Set
9
+
10
+ from openpoiservice .server import categories_tools , ops_settings
11
+ from openpoiservice .server import db
12
+ from openpoiservice .server .db_import .models import POIs , Tags , Categories
13
+ from openpoiservice .server .db_import .node_store import NodeStore
14
+ from openpoiservice .server .db_import .objects import PoiObject , TagsObject
15
+
10
16
logger = logging .getLogger (__name__ )
11
17
12
18
19
+ # deprecated, remove later
13
20
class WayObject (object ):
14
21
""" Class that creates a way object. """
15
22
@@ -60,20 +67,22 @@ def __init__(self, osm_file_index, update_mode=False):
60
67
self .tags_cnt = 0
61
68
self .categories_cnt = 0
62
69
self .relation_ways = {}
63
- self .nodes = {}
64
- self .process_ways = []
70
+ self .nodes_store = NodeStore ()
71
+ self .process_ways_set = Int64Set ()
65
72
self .poi_objects = []
66
73
self .tags_objects = []
67
74
self .categories_objects = []
68
- self .ways_temp = []
69
- self .ways_obj = None
70
- self .tags_object = None
71
- self .poi_object = None
72
- self .process_ways_length = None
73
75
self .update_mode = update_mode
74
76
self .osm_file_index = osm_file_index
75
77
self .failed = False
76
78
79
+ # deprecated, remove later
80
+ self .nodes = {}
81
+ self .process_ways = []
82
+ self .ways_obj = None
83
+ self .ways_temp = []
84
+
85
+
77
86
def parse_nodes (self , osm_nodes ):
78
87
"""
79
88
Callback function called by imposm while nodes are parsed.
@@ -89,6 +98,7 @@ def parse_nodes(self, osm_nodes):
89
98
self .failed = True
90
99
return
91
100
101
+
92
102
def parse_relations (self , relations ):
93
103
"""
94
104
Callback function called by imposm while relations are parsed. The idea is to extract polygons which may
@@ -116,6 +126,8 @@ def parse_relations(self, relations):
116
126
self .relation_ways [osmid_rel_member ].update ({"relation_id" : osmid })
117
127
self .relations_cnt += 1
118
128
129
+
130
+ # deprecated, remove later
119
131
def parse_ways (self , ways ):
120
132
"""
121
133
Callback function called by imposm while ways are parsed. If a category can't be found it may likely
@@ -149,6 +161,8 @@ def parse_ways(self, ways):
149
161
self .ways_obj = WayObject (osmid , osm_type , tags , refs , categories , len (refs ))
150
162
self .process_ways .append (self .ways_obj )
151
163
164
+
165
+ # deprecated, remove later
152
166
def parse_coords_for_ways (self , coords ):
153
167
"""
154
168
Callback function called by imposm while coordinates are parsed. Due due ordering we can use coords
@@ -225,6 +239,93 @@ def parse_coords_for_ways(self, coords):
225
239
226
240
self .ways_temp = []
227
241
242
+
243
+ def parse_ways_first (self , ways ):
244
+ """
245
+ Callback function called by imposm while ways are parsed. If a category can't be found it may likely
246
+ be that the osmid of this way can be found in self.relation_ways which will contain additional tags
247
+ and therefore eventually a category. A way object is added to a list process_ways which at this point
248
+ is lacking coordinates -> next step.
249
+
250
+ :param ways: osm way objects
251
+ :type ways: list of osm ways
252
+ """
253
+ for osmid , tags , refs in ways :
254
+ if len (refs ) >= 1000 :
255
+ continue
256
+
257
+ categories = categories_tools .get_category (tags )
258
+
259
+ if len (categories ) == 0 and osmid in self .relation_ways :
260
+ tags = self .relation_ways [osmid ]
261
+ categories = categories_tools .get_category (tags )
262
+
263
+ if len (categories ) > 0 :
264
+ self .ways_cnt += 1
265
+ for ref in refs :
266
+ self .nodes_store .append (ref , (None , None ))
267
+ self .process_ways_set .add (osmid )
268
+
269
+
270
+ def parse_coords_and_store (self , coords ):
271
+ for osmid , lat , lng in coords :
272
+ if osmid in self .nodes_store :
273
+ self .nodes_store .set (osmid , (lat , lng ))
274
+
275
+
276
+ def parse_ways_second (self , ways ):
277
+ """
278
+ Callback function called by imposm while ways are parsed. If a category can't be found it may likely
279
+ be that the osmid of this way can be found in self.relation_ways which will contain additional tags
280
+ and therefore eventually a category. A way object is added to a list process_ways which at this point
281
+ is lacking coordinates -> next step.
282
+
283
+ :param ways: osm way objects
284
+ :type ways: list of osm ways
285
+ """
286
+ for osmid , tags , refs in ways :
287
+ if osmid not in self .process_ways_set :
288
+ continue
289
+ categories = categories_tools .get_category (tags )
290
+ # from way
291
+ osm_type = 2
292
+
293
+ if len (categories ) == 0 and osmid in self .relation_ways :
294
+ # current way is the outer ring of a relation which was marked as having a category
295
+ tags = self .relation_ways [osmid ]
296
+ categories = categories_tools .get_category (tags )
297
+ # from relation
298
+ osm_type = 3
299
+
300
+ # Calculate centroid of way
301
+ refs = set (refs )
302
+ sum_lat = 0
303
+ sum_lng = 0
304
+ way_valid = True
305
+ for ref in refs :
306
+ if ref not in self .nodes_store : # should never ha
307
+ way_valid = False
308
+ break
309
+ lat , lng = self .nodes_store .get (ref )
310
+ if lat is None or lng is None or np .isnan (lat ) or np .isnan (lng ):
311
+ way_valid = False
312
+ break
313
+ sum_lat += lat
314
+ sum_lng += lng
315
+ if not way_valid :
316
+ continue
317
+
318
+ self .process_ways_set .remove (osmid )
319
+ centroid_lat = sum_lat / len (refs )
320
+ centroid_lng = sum_lng / len (refs )
321
+ try :
322
+ self .create_poi (osm_type , osmid , [centroid_lat , centroid_lng ], tags , categories )
323
+ except Exception as e :
324
+ logger .debug (e )
325
+ self .failed = True
326
+ return
327
+
328
+
228
329
def create_poi (self , osm_type , osm_id , lat_lng , tags , categories = None ):
229
330
"""
230
331
Creates a poi entity if a category is found. Stored afterwards.
@@ -257,6 +358,7 @@ def create_poi(self, osm_type, osm_id, lat_lng, tags, categories=None):
257
358
258
359
self .store_poi (PoiObject (osm_type , osm_id , lat_lng , categories ))
259
360
361
+
260
362
def store_poi (self , poi_object ):
261
363
"""
262
364
Appends poi storage objects to buffer for bulk storage to database.
@@ -273,6 +375,7 @@ def store_poi(self, poi_object):
273
375
logger .debug (f"Pois: { self .pois_count } , tags: { self .tags_cnt } , categories: { self .categories_cnt } " )
274
376
self .save_buffer ()
275
377
378
+
276
379
def store_tags (self , tags_object ):
277
380
"""
278
381
Appends tags storage objects to buffer for bulk storage to database.
@@ -285,6 +388,7 @@ def store_tags(self, tags_object):
285
388
value = tags_object .value
286
389
))
287
390
391
+
288
392
def store_categories (self , osmtype , osmid , category ):
289
393
"""
290
394
Appends category storage objects to buffer for bulk storage to database.
@@ -296,6 +400,7 @@ def store_categories(self, osmtype, osmid, category):
296
400
category = category
297
401
))
298
402
403
+
299
404
def save_buffer (self ):
300
405
"""
301
406
Save POIs, tags and categories to database and clear buffer.
0 commit comments