Tue, 15 Sep 2020 17:36:45 +0300
ulkoilureitit
-- This configuration for the flex backend tries to be compatible with the -- original pgsql c-transform backend. There might be some corner cases but -- it should mostly do exactly the same. -- Set this to true if you were using option -K|--keep-coastlines. local keep_coastlines = true -- Set this to the table name prefix (what used to be option -p|--prefix). local prefix = 'planet_osm' -- Set this to true if multipolygons should be written as polygons into db -- (what used to be option -G|--multi-geometry). local multi_geometry = true -- Set this to true if you want an hstore column (what used to be option -- -k|--hstore). Can not be true if "hstore_all" is true. local hstore = true -- Set this to true if you want all tags in an hstore column (what used to -- be option -j|--hstore-all). Can not be true if "hstore" is true. local hstore_all = false -- Only keep objects that have a value in one of the non-hstore columns -- (normal action with --hstore is to keep all objects). Equivalent to -- what used to be set through option --hstore-match-only. local hstore_match_only = true -- Set this to add an additional hstore (key/value) column containing all tags -- that start with the specified string, eg "name:". Will produce an extra -- hstore column that contains all "name:xx" tags. Equivalent to what used to -- be set through option -z|--hstore-column. local hstore_column = nil -- There is some very old specialized handling of route relations in osm2pgsql, -- which you probably don't need. This is disabled here, but you can enable -- it by setting this to true. If you don't understand this, leave it alone. local enable_legacy_route_processing = false -- --------------------------------------------------------------------------- if hstore and hstore_all then error("hstore and hstore_all can't be both true") end -- Used for splitting up long linestrings if osm2pgsql.srid == 4326 then max_length = 1 else max_length = 100000 end -- Ways with any of the following keys will be treated as polygon local polygon_keys = { 'aeroway', 'amenity', 'building', 'harbour', 'historic', 'landuse', 'leisure', 'man_made', 'military', 'natural', 'office', 'place', 'power', 'public_transport', 'shop', 'sport', 'tourism', 'water', 'waterway', 'wetland', 'abandoned:aeroway', 'abandoned:amenity', 'abandoned:building', 'abandoned:landuse', 'abandoned:power', 'area:highway' } -- Objects without any of the following keys will be deleted local generic_keys = { 'access', 'addr:housename', 'addr:housenumber', 'addr:interpolation', 'admin_level', 'aerialway', 'aeroway', 'amenity', 'area', 'barrier', 'bicycle', 'boundary', 'brand', 'bridge', 'building', 'capital', 'construction', 'covered', 'culvert', 'cutting', 'denomination', 'disused', 'ele', 'embankment', 'foot', 'generation:source', 'harbour', 'healthcare', 'highway', 'historic', 'hours', 'intermittent', 'junction', 'landuse', 'layer', 'leisure', 'lock', 'man_made', 'military', 'motorcar', 'name', 'natural', 'office', 'oneway', 'operator', 'place', 'population', 'power', 'power_source', 'public_transport', 'railway', 'ref', 'religion', 'route', 'service', 'shop', 'sport', 'surface', 'toll', 'tourism', 'tower:type', 'tracktype', 'tunnel', 'water', 'waterway', 'wetland', 'width', 'wood', 'abandoned:aeroway', 'abandoned:amenity', 'abandoned:building', 'abandoned:landuse', 'abandoned:power', 'area:highway' } -- The following keys will be deleted local delete_keys = { 'attribution', 'comment', 'created_by', 'fixme', 'note', 'note:*', 'odbl', 'odbl:note', 'source', 'source:*', 'source_ref', 'way', 'way_area', 'z_order', } local point_columns = { 'access', 'addr:housename', 'addr:housenumber', 'addr:interpolation', 'admin_level', 'aerialway', 'aeroway', 'amenity', 'area', 'barrier', 'bicycle', 'brand', 'bridge', 'boundary', 'building', 'capital', 'construction', 'covered', 'culvert', 'cutting', 'denomination', 'disused', 'ele', 'embankment', 'foot', 'generator:source', 'harbour', 'highway', 'historic', 'horse', 'intermittent', 'junction', 'landuse', 'layer', 'leisure', 'lock', 'man_made', 'military', 'motorcar', 'name', 'name:fi', 'name:sv', 'minority_name', 'majority_name', 'bilingual_name', 'natural', 'office', 'oneway', 'operator', 'place', 'population', 'power', 'power_source', 'public_transport', 'railway', 'ref', 'religion', 'route', 'service', 'shop', 'sport', 'surface', 'toll', 'tourism', 'tower:type', 'tunnel', 'water', 'waterway', 'wetland', 'width', 'wood', } local non_point_columns = { 'access', 'addr:housename', 'addr:housenumber', 'addr:interpolation', 'admin_level', 'aerialway', 'aeroway', 'amenity', 'area', 'barrier', 'bicycle', 'brand', 'bridge', 'boundary', 'building', 'construction', 'covered', 'culvert', 'cutting', 'denomination', 'disused', 'embankment', 'foot', 'generator:source', 'harbour', 'highway', 'historic', 'horse', 'intermittent', 'junction', 'landuse', 'layer', 'leisure', 'lock', 'man_made', 'military', 'motorcar', 'name', 'name:fi', 'name:sv', 'minority_name', 'majority_name', 'bilingual_name', 'natural', 'office', 'oneway', 'operator', 'place', 'population', 'power', 'power_source', 'public_transport', 'railway', 'ref', 'ref_class', 'ref_width', 'religion', 'route', 'service', 'shop', 'sport', 'surface', 'toll', 'tourism', 'tower:type', 'tracktype', 'tunnel', 'water', 'waterway', 'wetland', 'width', 'wood', } -- highlight some suburbs in the capital region boroughs = { -- Helsinki ["Q2116584"] = 1, -- Vuosaari / Nordsjö ["Q2510635"] = 1, -- Oulunkylä / Åggelby ["Q3130945"] = 1, -- Viikki / Vik ["Q1614778"] = 1, -- Herttoniemi / Hertonäs -- Espoo ["Q166942"] = 1, -- Leppävaara / Alberga ["Q3107346"] = 1, -- Matinkylä / Mattby ["Q211491"] = 1, -- Espoonlahti / Esboviken ["Q211489"] = 1, -- Espoon keskus / Esbo centrum ["Q219044"] = 1, -- Kauklahti / Köklax ["Q1668730"] = 1, -- Tapiola / Hagalund -- Vantaa ["Q2640455"] = 1, -- Tikkurila / Dickursby ["Q4412122"] = 1, -- Aviapolis ["Q3736737"] = 1, -- Myyrmäki / Myrbacka ["Q4557316"] = 1, -- Kivistö ["Q4556551"] = 1, -- Koivukylä / Björkby ["Q3742144"] = 1, -- Korso ["Q4556262"] = 1, -- Hakunila / Håkansböle } -- -- Name in majority language for object. This is name unless both name:fi and -- name:sv disagree with name. -- @param tags Raw OSM tags -- @return Bilingual name -- function majority_name(tags) if tags.name ~= nil and tags['name:sv'] ~= nil and tags['name:fi'] and tags.name ~= tags['name:fi'] and tags.name ~= tags['name:sv'] then return tags['name:fi'] else return tags.name end end -- -- Name in minority language for object. This is the Swedish name if name is in -- Finnish, and the Finnish name if name is in Swedish. -- @param tags Raw OSM tags -- @return Bilingual name -- function minority_name(tags) if tags['name:sv'] ~= nil and tags['name'] ~= tags['name:sv'] then return tags['name:sv'] elseif tags['name:fi'] ~= nil and tags['name'] ~= tags['name:fi'] then return tags['name:fi'] else return nil end end function bilingual_name(tags) if tags.majority_name ~= nil and tags.minority_name ~= nil then return tags.majority_name .. '\n' .. tags.minority_name else return tags.majority_name end end -- Makes highway classes more sensible function highway_class(tags) if string.match(tags.highway, '_link$') then if tags.tags.functional_class == 'service' or tags.tags.functional_class == 'unclassified' then return tags.tags.functional_class elseif tags.tags.functional_class ~= nil then return tags.tags.functional_class..'_link' elseif tags.highway == 'motorway_link' then return 'trunk_link' else return tags.highway end elseif tags.highway == 'motorway' then if tags.tags.functional_class == 'primary' or tags.tags.functional_class == 'secondary' or tags.tags.functional_class == 'tertiary' then return tags.tags.functional_class elseif tags.tags.functional_class == 'service' then return 'service' else return 'trunk' end else if tags.highway ~= nil and tags.tags.functional_class ~= nil then return tags.tags.functional_class else return tags.highway end end end function has_shields(tags) return (tags.highway == 'trunk' or tags.highway == 'primary' or tags.highway == 'secondary' or tags.highway == 'tertiary') end -- https://stackoverflow.com/a/7615129 function mysplit(inputstr, sep) if sep == nil then sep = "%s" end local t={} for str in string.gmatch(inputstr, "([^"..sep.."]+)") do table.insert(t, str) end return t end function combine_stringlists(a, b) if a ~= nil and a ~= '' then if b ~= nil and b ~= '' then return a..';'..b else return a end else return b end end function combine_refs(a, b) return combine_stringlists(a, b) end -- Widths of ref characters in Liikenne font, used to calculate shield sizes character_widths = { ['0'] = 616, ['1'] = 337, ['2'] = 600, ['3'] = 621, ['4'] = 689, ['5'] = 623, ['6'] = 566, ['7'] = 499, ['8'] = 616, ['9'] = 566, [' '] = 260, ['E'] = 613, } function ref_width(ref) local result = 0 for i = 1, #ref do result = result + (character_widths[ref:sub(i, i)] or 0) end return math.max(math.ceil((result - 1000) / 77), 1) end function ref_widths(refs) local result = '' for _, ref in ipairs(mysplit(refs, ';')) do result = combine_stringlists(result, ref_width(ref)) end return result end -- Makes refs more sensible. -- 5-digit refs are not found on the ground so they are omitted. -- int_ref is added to refs. function highway_refs(tags) if has_shields(tags) and (tags.ref ~= nil or tags.tags.int_ref ~= nil) then if tags.junction == 'roundabout' then return nil else local result = '' local all_refs = combine_refs(tags.ref, tags.tags.int_ref) for _, ref in ipairs(mysplit(all_refs, ';')) do if tonumber(ref) == nil or tonumber(ref) < 10000 then ref = string.gsub(ref, '^E 0', 'E ') result = combine_refs(result, ref) end end return result end else return tags.ref end end -- classify road type by number function road_class_by_ref(ref) local n = tonumber(ref) if n ~= nil and n > 0 then if n < 40 then return 'valtatie' elseif n < 100 then return 'kantatie' elseif n < 1000 then return 'seututie' else return 'yhdystie' end elseif string.match(ref, '^E ?%d+$') then return 'eurooppatie' else return 'unknown' end end function classify_road_numbers(refs) local result = '' for _, ref in ipairs(mysplit(refs, ';')) do result = combine_stringlists(result, road_class_by_ref(ref)) end return result end function gen_columns(text_columns, with_hstore, area, geometry_type) columns = {} local add_column = function (name, type) columns[#columns + 1] = { column = name, type = type } end for _, c in ipairs(text_columns) do add_column(c, 'text') end add_column('z_order', 'int') if area ~= nil then if area then add_column('way_area', 'area') else add_column('way_area', 'real') end end if hstore_column then add_column(hstore_column, 'hstore') end if with_hstore then add_column('tags', 'hstore') end add_column('way', geometry_type) return columns end local tables = {} tables.point = osm2pgsql.define_table{ name = prefix .. '_point', ids = { type = 'node', id_column = 'osm_id' }, columns = gen_columns(point_columns, hstore or hstore_all, nil, 'point') } tables.line = osm2pgsql.define_table{ name = prefix .. '_line', ids = { type = 'way', id_column = 'osm_id' }, columns = gen_columns(non_point_columns, hstore or hstore_all, false, 'linestring') } tables.polygon = osm2pgsql.define_table{ name = prefix .. '_polygon', ids = { type = 'area', id_column = 'osm_id' }, columns = gen_columns(non_point_columns, hstore or hstore_all, true, 'geometry') } tables.roads = osm2pgsql.define_table{ name = prefix .. '_roads', ids = { type = 'way', id_column = 'osm_id' }, columns = gen_columns(non_point_columns, hstore or hstore_all, false, 'linestring') } tables.routes = osm2pgsql.define_way_table( prefix .. '_routes', { { column = 'tags', type = 'hstore' }, { column = 'ref', type = 'text' }, { column = 'name', type = 'text' }, { column = 'network', type = 'text' }, { column = 'route', type = 'text' }, { column = 'layer', type = 'text' }, { column = 'osm_way_id', type = 'text' }, { column = 'way', type = 'linestring' }, } ) local z_order_lookup = { proposed = {1, false}, construction = {2, false}, steps = {10, false}, cycleway = {10, false}, bridleway = {10, false}, footway = {10, false}, path = {10, false}, track = {11, false}, service = {15, false}, tertiary_link = {24, false}, secondary_link = {25, true}, primary_link = {27, true}, trunk_link = {28, true}, motorway_link = {29, true}, raceway = {30, false}, pedestrian = {31, false}, living_street = {32, false}, road = {33, false}, unclassified = {33, false}, residential = {33, false}, tertiary = {34, false}, secondary = {36, true}, primary = {37, true}, trunk = {38, true}, motorway = {39, true} } function as_bool(value) return value == 'yes' or value == 'true' or value == '1' end function get_z_order(tags) local z_order = 100 * math.floor(tonumber(tags.layer or '0') or 0) local roads = false local highway = tags['highway'] if highway then local r = z_order_lookup[highway] or {0, false} z_order = z_order + r[1] roads = r[2] end if tags.railway then z_order = z_order + 35 roads = true end if tags.boundary and tags.boundary == 'administrative' then roads = true end if as_bool(tags.bridge) then z_order = z_order + 100 end if as_bool(tags.tunnel) then z_order = z_order - 100 end return z_order, roads end function make_check_in_list_func(list) local h = {} for _, k in ipairs(list) do h[k] = true end return function(tags) for k, _ in pairs(tags) do if h[k] then return true end end return false end end local is_polygon = make_check_in_list_func(polygon_keys) local clean_tags = osm2pgsql.make_clean_tags_func(delete_keys) function make_column_hash(columns) local h = {} for _, k in ipairs(columns) do h[k] = true end return h end function make_get_output(columns, hstore_all) local h = make_column_hash(columns) if hstore_all then return function(tags) local output = {} local hstore_entries = {} for k, _ in pairs(tags) do if h[k] then output[k] = tags[k] end hstore_entries[k] = tags[k] end return output, hstore_entries end else return function(tags) local output = {} local hstore_entries = {} for k, _ in pairs(tags) do if h[k] then output[k] = tags[k] else hstore_entries[k] = tags[k] end end return output, hstore_entries end end end local has_generic_tag = make_check_in_list_func(generic_keys) local get_point_output = make_get_output(point_columns, hstore_all) local get_non_point_output = make_get_output(non_point_columns, hstore_all) function get_hstore_column(tags) local len = #hstore_column local h = {} for k, v in pairs(tags) do if k:sub(1, len) == hstore_column then h[k:sub(len + 1)] = v end end if next(h) then return h end return nil end function add_generic_tags(object, output) output.majority_name = majority_name(output) output.minority_name = minority_name(output) output.bilingual_name = bilingual_name(output) return output end function osm2pgsql.process_node(object) if clean_tags(object.tags) then return end if object.tags.layer then object.tags.layer = tonumber(object.tags.layer) end local output local output_hstore = {} if hstore or hstore_all then output, output_hstore = get_point_output(object.tags) if not next(output) and not next(output_hstore) then return end if hstore_match_only and not has_generic_tag(object.tags) then return end else output = object.tags if not has_generic_tag(object.tags) then return end end output = add_generic_tags(object, output) output.tags = output_hstore if hstore_column then output[hstore_column] = get_hstore_column(object.tags) end tables.point:add_row(output) end route_ways = {} function osm2pgsql.process_way(object) if clean_tags(object.tags) then return end if object.tags.layer then object.tags.layer = tonumber(object.tags.layer) end local add_area = false if object.tags.natural == 'coastline' then add_area = true if not keep_coastlines then object.tags.natural = nil end end local output local output_hstore = {} if hstore or hstore_all then output, output_hstore = get_non_point_output(object.tags) if not next(output) and not next(output_hstore) then return end if hstore_match_only and not has_generic_tag(object.tags) then return end if add_area and hstore_all then output_hstore.area = 'yes' end else output = object.tags if not has_generic_tag(object.tags) then return end end local polygon local area_tag = object.tags.area if area_tag == 'yes' or area_tag == '1' or area_tag == 'true' then polygon = true elseif area_tag == 'no' or area_tag == '0' or area_tag == 'false' then polygon = false else polygon = is_polygon(object.tags) end if add_area then output.area = 'yes' polygon = true end local z_order, roads = get_z_order(object.tags) output.z_order = z_order output = add_generic_tags(object, output) output.tags = output_hstore if output.highway ~= nil then if output.highway == 'construction' then return end output.highway = highway_class(output) output.ref = highway_refs(output) if output.highway == 'construction' and output.construction == 'motorway' then output.construction = 'trunk' elseif output.highway == 'construction' and output.construction == 'motorway_link' then output.construction = 'trunk_link' end -- classify references for for Finland shield rendering if output.ref ~= nil then output.ref_class = classify_road_numbers(output.ref) output.ref_width = ref_widths(output.ref) end end if hstore_column then output[hstore_column] = get_hstore_column(object.tags) end if polygon and object.is_closed then output.way = { create = 'area' } tables.polygon:add_row(output) else output.way = { create = 'line', split_at = max_length } tables.line:add_row(output) if roads then tables.roads:add_row(output) end end if osm2pgsql.stage == 2 then local routes = route_ways[object.id] if routes ~= nil then for index, route in ipairs(routes) do route_type = route.tags.route if route_type == 'bicycle' and route.tags.network ~= nil then route_type = route_type .. '_' .. route.tags.network end row = { tags = object.tags, ref = route.tags.ref, name = route.tags.name, network = route.tags.network, route = route_type, osm_way_id = object.id, layer = object.tags.layer or 0, geom = { create = 'line' } } tables.routes:add_row(row) end end end end function osm2pgsql.select_relation_members(relation) if relation.tags.type == 'route' and (relation.tags.route == 'foot' or relation.tags.route == 'hiking' or relation.tags.route == 'bicycle') then for _, member in ipairs(relation.members) do if member.type == 'w' then member_id = member.ref if not route_ways[member_id] then route_ways[member_id] = {} end table.insert(route_ways[member_id], relation) end end return { ways = osm2pgsql.way_member_ids(relation) } end end function osm2pgsql.process_relation(object) if clean_tags(object.tags) then return end local type = object.tags.type if (type ~= 'route') and (type ~= 'multipolygon') and (type ~= 'boundary') then return end object.tags.type = nil local output local output_hstore = {} if hstore or hstore_all then output, output_hstore = get_non_point_output(object.tags) if not next(output) and not next(output_hstore) then return end if hstore_match_only and not has_generic_tag(object.tags) then return end else output = object.tags if not has_generic_tag(object.tags) then return end end if not next(output) and not next(output_hstore) then return end if enable_legacy_route_processing and (hstore or hstore_all) and type == 'route' then if not object.tags.route_name then output_hstore.route_name = object.tags.name end local state = object.tags.state if state ~= 'alternate' and state ~= 'connection' then state = 'yes' end local network = object.tags.network if network == 'lcn' then output_hstore.lcn = output_hstore.lcn or state output_hstore.lcn_ref = output_hstore.lcn_ref or object.tags.ref elseif network == 'rcn' then output_hstore.rcn = output_hstore.rcn or state output_hstore.rcn_ref = output_hstore.rcn_ref or object.tags.ref elseif network == 'ncn' then output_hstore.ncn = output_hstore.ncn or state output_hstore.ncn_ref = output_hstore.ncn_ref or object.tags.ref elseif network == 'lwn' then output_hstore.lwn = output_hstore.lwn or state output_hstore.lwn_ref = output_hstore.lwn_ref or object.tags.ref elseif network == 'rwn' then output_hstore.rwn = output_hstore.rwn or state output_hstore.rwn_ref = output_hstore.rwn_ref or object.tags.ref elseif network == 'nwn' then output_hstore.nwn = output_hstore.nwn or state output_hstore.nwn_ref = output_hstore.nwn_ref or object.tags.ref end local pc = object.tags.preferred_color if pc == '0' or pc == '1' or pc == '2' or pc == '3' or pc == '4' then output_hstore.route_pref_color = pc else output_hstore.route_pref_color = '0' end end local make_boundary = false local make_polygon = false if type == 'boundary' then make_boundary = true elseif type == 'multipolygon' and object.tags.boundary then make_boundary = true elseif type == 'multipolygon' then make_polygon = true end local z_order, roads = get_z_order(object.tags) output.z_order = z_order output = add_generic_tags(object, output) output.tags = output_hstore if hstore_column then output[hstore_column] = get_hstore_column(object.tags) end if not make_polygon then output.way = { create = 'line', split_at = max_length } tables.line:add_row(output) if roads then tables.roads:add_row(output) end end if make_boundary or make_polygon then output.way = { create = 'area', multi = multi_geometry } tables.polygon:add_row(output) end end