]> git.openstreetmap.org Git - nominatim.git/blob - settings/flex-base.lua
initial flex import scripts
[nominatim.git] / settings / flex-base.lua
1 -- Core functions for Nominatim import flex style.
2 --
3
4
5 -- The single place table.
6 place_table = osm2pgsql.define_table{
7     name = "place",
8     ids = { type = 'any', id_column = 'osm_id', type_column = 'osm_type' },
9     columns = {
10         { column = 'class', type = 'text', not_null = true },
11         { column = 'type', type = 'text', not_null = true },
12         { column = 'admin_level', type = 'smallint' },
13         { column = 'name', type = 'hstore' },
14         { column = 'address', type = 'hstore' },
15         { column = 'extratags', type = 'hstore' },
16         { column = 'geometry', type = 'geometry', projection = 'WGS84', not_null = true },
17     }
18 }
19
20 ------------- Place class ------------------------------------------
21
22 local Place = {}
23 Place.__index = Place
24
25 function Place.new(object, geom_func)
26     local self = setmetatable({}, Place)
27     self.object = object
28     self.geom_func = geom_func
29
30     self.admin_level = tonumber(self.object:grab_tag('admin_level'))
31     if self.admin_level == nil
32        or self.admin_level <= 0 or self.admin_level > 15
33        or math.floor(self.admin_level) ~= self.admin_level then
34         self.admin_level = 15
35     end
36
37     self.num_entries = 0
38     self.has_name = false
39     self.names = {}
40     self.address = {}
41     self.extratags = {}
42
43     return self
44 end
45
46 function Place:delete(data)
47     if data.match ~= nil then
48         for k, v in pairs(self.object.tags) do
49             if data.match(k, v) then
50                 self.object.tags[k] = nil
51             end
52         end
53     end
54 end
55
56 function Place:grab_extratags(data)
57     local count = 0
58
59     if data.match ~= nil then
60         for k, v in pairs(self.object.tags) do
61             if data.match(k, v) then
62                 self.object.tags[k] = nil
63                 self.extratags[k] = v
64                 count = count + 1
65             end
66         end
67     end
68
69     return count
70 end
71
72 function Place:grab_address(data)
73     local count = 0
74
75     if data.match ~= nil then
76         for k, v in pairs(self.object.tags) do
77             if data.match(k, v) then
78                 self.object.tags[k] = nil
79
80                 if data.include_on_name == true then
81                     self.has_name = true
82                 end
83
84                 if data.out_key ~= nil then
85                     self.address[data.out_key] = v
86                     return 1
87                 end
88
89                 if k:sub(1, 5) == 'addr:' then
90                     self.address[k:sub(6)] = v
91                 elseif k:sub(1, 6) == 'is_in:' then
92                     self.address[k:sub(7)] = v
93                 else
94                     self.address[k] = v
95                 end
96                 count = count + 1
97             end
98         end
99     end
100
101     return count
102 end
103
104 function Place:set_address(key, value)
105     self.address[key] = value
106 end
107
108 function Place:grab_name(data)
109     local count = 0
110
111     if data.match ~= nil then
112         for k, v in pairs(self.object.tags) do
113             if data.match(k, v) then
114                 self.object.tags[k] = nil
115                 self.names[k] = v
116                 if data.include_on_name ~= false then
117                     self.has_name = true
118                 end
119                 count = count + 1
120             end
121         end
122     end
123
124     return count
125 end
126
127 function Place:grab_tag(key)
128     return self.object:grab_tag(key)
129 end
130
131 function Place:tags()
132     return self.object.tags
133 end
134
135 function Place:write_place(k, v, mtype, save_extra_mains)
136     if mtype == nil then
137         return 0
138     end
139
140     v = v or self.object.tags[k]
141     if v == nil then
142         return 0
143     end
144
145     if type(mtype) == 'table' then
146         mtype = mtype[v] or mtype[1]
147     end
148
149     if mtype == 'always' or (self.has_name and mtype == 'named') then
150         return self:write_row(k, v, save_extra_mains)
151     end
152
153     if mtype == 'named_with_key' then
154         local names = {}
155         local prefix = k .. ':name'
156         for namek, namev in pairs(self.object.tags) do
157             if namek:sub(1, #prefix) == prefix
158                and (#namek == #prefix
159                     or namek:sub(#prefix + 1, #prefix + 1) == ':') then
160                 names[namek:sub(#k + 2)] = namev
161             end
162         end
163
164         if next(names) ~= nil then
165             local saved_names = self.names
166             self.names = names
167
168             local results = self:write_row(k, v, save_extra_mains)
169
170             self.names = saved_names
171
172             return results
173         end
174     end
175
176     return 0
177 end
178
179 function Place:write_row(k, v, save_extra_mains)
180     if self.geometry == nil then
181         self.geometry = self.geom_func(self.object)
182     end
183     if self.geometry:is_null() then
184         return 0
185     end
186
187     if save_extra_mains then
188         for extra_k, extra_v in pairs(self.object.tags) do
189             if extra_k ~= k then
190                 self.extratags[extra_k] = extra_v
191             end
192         end
193     end
194
195     place_table:insert{
196         class = k,
197         type = v,
198         admin_level = self.admin_level,
199         name = next(self.names) and self.names,
200         address = next(self.address) and self.address,
201         extratags = next(self.extratags) and self.extratags,
202         geometry = self.geometry
203     }
204
205     if save_extra_mains then
206         for k, v in pairs(self.object.tags) do
207             self.extratags[k] = nil
208         end
209     end
210
211     self.num_entries = self.num_entries + 1
212
213     return 1
214 end
215
216
217 function tag_match(data)
218     if data == nil or next(data) == nil then
219         return nil
220     end
221
222     local tests = {}
223
224     if data.keys ~= nil then
225         for _, key in pairs(data.keys) do
226             if key:sub(1, 1) == '*' then
227                 if #key > 1 then
228                     local suffix = key:sub(2)
229                     tests[#tests + 1] = function (k, v)
230                         return k:sub(-#suffix) == suffix
231                     end
232                 end
233             elseif key:sub(#key, #key) == '*' then
234                 local prefix = key:sub(1, #key - 1)
235                 tests[#tests + 1] = function (k, v)
236                     return k:sub(1, #prefix) == prefix
237                 end
238             else
239                 tests[#tests + 1] = function (k, v)
240                     return k == key
241                 end
242             end
243         end
244     end
245
246     if data.tags ~= nil then
247         local tags = {}
248         for k, vlist in pairs(data.tags) do
249             tags[k] = {}
250             for _, v in pairs(vlist) do
251                 tags[k][v] = true
252             end
253         end
254         tests[#tests + 1] = function (k, v)
255             return tags[k] ~= nil and tags[k][v] ~= nil
256         end
257     end
258
259     return function (k, v)
260         for _, func in pairs(tests) do
261             if func(k, v) then
262                 return true
263             end
264         end
265         return false
266     end
267 end
268
269
270 -- Process functions for all data types
271 function osm2pgsql.process_node(object)
272
273     local function geom_func(o)
274         return o:as_point()
275     end
276
277     process_tags(Place.new(object, geom_func))
278 end
279
280 function osm2pgsql.process_way(object)
281
282     local function geom_func(o)
283         local geom = o:as_polygon()
284
285         if geom:is_null() then
286             geom = o:as_linestring()
287         end
288
289         return geom
290     end
291
292     process_tags(Place.new(object, geom_func))
293 end
294
295 function relation_as_multipolygon(o)
296     return o:as_multipolygon()
297 end
298
299 function relation_as_multiline(o)
300     return o:as_multilinestring():line_merge()
301 end
302
303 function osm2pgsql.process_relation(object)
304     local geom_func = RELATION_TYPES[object.tags.type]
305
306     if geom_func ~= nil then
307         process_tags(Place.new(object, geom_func))
308     end
309 end
310
311 function process_tags(o)
312     local fallback
313
314     o:delete{match = PRE_DELETE}
315     o:grab_extratags{match = PRE_EXTRAS}
316
317     -- Exception for boundary/place double tagging
318     if o.object.tags.boundary == 'administrative' then
319         o:grab_extratags{match = function (k, v)
320             return k == 'place' and v:sub(1,3) ~= 'isl'
321         end}
322     end
323
324     -- address keys
325     o:grab_address{match=function (k, v) return COUNTRY_TAGS(k, v) and #v == 2 end,
326                    out_key='country'}
327     if o:grab_name{match=HOUSENAME_TAGS} > 0 then
328         fallback = {'place', 'house'}
329     end
330     if o:grab_address{match=HOUSENUMBER_TAGS, include_on_name = true} > 0 and fallback == nil then
331         fallback = {'place', 'house'}
332     end
333     if o:grab_address{match=POSTCODES, out_key='postcode'} > 0 and fallback == nil then
334         fallback = {'place', 'postcode'}
335     end
336
337     local is_interpolation = o:grab_address{match=INTERPOLATION_TAGS} > 0
338
339     if ADD_TIGER_COUNTY then
340         local v = o:grab_tag('tiger:county')
341         if v ~= nil then
342             v, num = v:gsub(',.*', ' county')
343             if num == 0 then
344                 v = v .. ' county'
345             end
346             o:set_address('tiger:county', v)
347         end
348     end
349     o:grab_address{match=ADDRESS_TAGS}
350
351     if is_interpolation then
352         o:write_place('place', 'houses', 'always', SAVE_EXTRA_MAINS)
353         return
354     end
355
356     -- name keys
357     o:grab_name{match = NAMES}
358     o:grab_name{match = REFS, include_on_name = false}
359
360     o:delete{match = POST_DELETE}
361     o:grab_extratags{match = POST_EXTRAS}
362
363     -- collect main keys
364     local num_mains = 0
365     for k, v in pairs(o:tags()) do
366         num_mains = num_mains + o:write_place(k, v, MAIN_KEYS[k], SAVE_EXTRA_MAINS)
367     end
368
369     if num_mains == 0 then
370         for tag, mtype in pairs(MAIN_FALLBACK_KEYS) do
371             if o:write_place(tag, nil, mtype, SAVE_EXTRA_MAINS) > 0 then
372                 return
373             end
374         end
375
376         if fallback ~= nil then
377             o:write_place(fallback[1], fallback[2], 'always', SAVE_EXTRA_MAINS)
378         end
379     end
380 end
381
382