147 lines
4.9 KiB
Lua
147 lines
4.9 KiB
Lua
-- scripts/poi_flex.lua
|
|
-- osm2pgsql flex output for POI extraction
|
|
|
|
local pois = osm2pgsql.define_table({
|
|
name = 'pois',
|
|
ids = { type = 'any', type_column = 'osm_type', id_column = 'osm_id' },
|
|
columns = {
|
|
{ column = 'name', type = 'text', not_null = true },
|
|
{ column = 'category', type = 'text', not_null = true },
|
|
{ column = 'geometry', type = 'point', projection = 4326, not_null = true },
|
|
{ column = 'address', type = 'jsonb' },
|
|
{ column = 'tags', type = 'jsonb' },
|
|
{ column = 'opening_hours', type = 'text' },
|
|
{ column = 'phone', type = 'text' },
|
|
{ column = 'website', type = 'text' },
|
|
{ column = 'wheelchair', type = 'text' },
|
|
},
|
|
})
|
|
|
|
-- Maps OSM amenity/shop/tourism/leisure tags to normalized categories
|
|
local category_map = {
|
|
-- amenity
|
|
restaurant = 'restaurant',
|
|
fast_food = 'restaurant',
|
|
cafe = 'cafe',
|
|
pharmacy = 'pharmacy',
|
|
hospital = 'hospital',
|
|
clinic = 'hospital',
|
|
fuel = 'fuel',
|
|
parking = 'parking',
|
|
atm = 'atm',
|
|
bank = 'atm',
|
|
bus_station = 'public_transport',
|
|
hotel = 'hotel',
|
|
-- shop
|
|
supermarket = 'supermarket',
|
|
convenience = 'shop',
|
|
clothes = 'shop',
|
|
hairdresser = 'shop',
|
|
bakery = 'shop',
|
|
-- tourism
|
|
attraction = 'tourist_attraction',
|
|
museum = 'tourist_attraction',
|
|
viewpoint = 'tourist_attraction',
|
|
-- leisure
|
|
park = 'park',
|
|
garden = 'park',
|
|
playground = 'park',
|
|
}
|
|
|
|
local function get_category(tags)
|
|
for _, key in ipairs({'amenity', 'shop', 'tourism', 'leisure'}) do
|
|
local val = tags[key]
|
|
if val and category_map[val] then
|
|
return category_map[val]
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function build_address(tags)
|
|
local addr = {}
|
|
if tags['addr:street'] then addr.street = tags['addr:street'] end
|
|
if tags['addr:housenumber'] then addr.housenumber = tags['addr:housenumber'] end
|
|
if tags['addr:postcode'] then addr.postcode = tags['addr:postcode'] end
|
|
if tags['addr:city'] then addr.city = tags['addr:city'] end
|
|
if next(addr) then return addr end
|
|
return nil
|
|
end
|
|
|
|
local function build_extra_tags(tags)
|
|
local extra = {}
|
|
local dominated = {
|
|
'name', 'amenity', 'shop', 'tourism', 'leisure',
|
|
'addr:street', 'addr:housenumber', 'addr:postcode', 'addr:city',
|
|
'opening_hours', 'phone', 'contact:phone',
|
|
'website', 'contact:website', 'wheelchair',
|
|
}
|
|
local skip = {}
|
|
for _, k in ipairs(dominated) do skip[k] = true end
|
|
for k, v in pairs(tags) do
|
|
if not skip[k] and not k:match('^addr:') then
|
|
extra[k] = v
|
|
end
|
|
end
|
|
if next(extra) then return extra end
|
|
return nil
|
|
end
|
|
|
|
function osm2pgsql.process_node(object)
|
|
local tags = object.tags
|
|
if not tags.name then return end
|
|
local category = get_category(tags)
|
|
if not category then return end
|
|
|
|
pois:insert({
|
|
name = tags.name,
|
|
category = category,
|
|
geometry = object:as_point(),
|
|
address = build_address(tags),
|
|
tags = build_extra_tags(tags),
|
|
opening_hours = tags.opening_hours,
|
|
phone = tags.phone or tags['contact:phone'],
|
|
website = tags.website or tags['contact:website'],
|
|
wheelchair = tags.wheelchair,
|
|
})
|
|
end
|
|
|
|
function osm2pgsql.process_way(object)
|
|
local tags = object.tags
|
|
if not tags.name then return end
|
|
local category = get_category(tags)
|
|
if not category then return end
|
|
if not object.is_closed then return end
|
|
|
|
pois:insert({
|
|
name = tags.name,
|
|
category = category,
|
|
geometry = object:as_polygon():centroid(),
|
|
address = build_address(tags),
|
|
tags = build_extra_tags(tags),
|
|
opening_hours = tags.opening_hours,
|
|
phone = tags.phone or tags['contact:phone'],
|
|
website = tags.website or tags['contact:website'],
|
|
wheelchair = tags.wheelchair,
|
|
})
|
|
end
|
|
|
|
function osm2pgsql.process_relation(object)
|
|
local tags = object.tags
|
|
if not tags.name then return end
|
|
local category = get_category(tags)
|
|
if not category then return end
|
|
if tags.type ~= 'multipolygon' then return end
|
|
|
|
pois:insert({
|
|
name = tags.name,
|
|
category = category,
|
|
geometry = object:as_multipolygon():centroid(),
|
|
address = build_address(tags),
|
|
tags = build_extra_tags(tags),
|
|
opening_hours = tags.opening_hours,
|
|
phone = tags.phone or tags['contact:phone'],
|
|
website = tags.website or tags['contact:website'],
|
|
wheelchair = tags.wheelchair,
|
|
})
|
|
end
|