Skip to content

Instantly share code, notes, and snippets.

@rmarianski
Created December 10, 2015 15:52
Show Gist options
  • Save rmarianski/875d49a992a9db963c96 to your computer and use it in GitHub Desktop.
Save rmarianski/875d49a992a9db963c96 to your computer and use it in GitHub Desktop.
Vector tiles dev migration 20151209
ALTER TABLE planet_osm_point DISABLE TRIGGER USER;
ALTER TABLE planet_osm_polygon DISABLE TRIGGER USER;
ALTER TABLE planet_osm_line DISABLE TRIGGER USER;
-- IF YOU UPDATE THIS, PLEASE UPDATE mz_calculate_landuse_kind
-- BELOW!
CREATE OR REPLACE FUNCTION mz_calculate_is_landuse(
landuse_val text, leisure_val text, natural_val text, highway_val text,
amenity_val text, aeroway_val text, tourism_val text, man_made_val text,
power_val text, boundary_val text)
RETURNS BOOLEAN AS $$
BEGIN
RETURN
landuse_val IN ('park', 'forest', 'residential', 'retail', 'commercial',
'industrial', 'railway', 'cemetery', 'grass', 'farmyard',
'farm', 'farmland', 'wood', 'meadow', 'village_green',
'recreation_ground', 'allotments', 'quarry', 'urban', 'rural'
'military', 'winter_sports')
OR leisure_val IN ('park', 'garden', 'playground', 'golf_course', 'sports_centre',
'pitch', 'stadium', 'common', 'nature_reserve')
OR natural_val IN ('wood', 'land', 'scrub', 'wetland', 'glacier', 'beach')
OR highway_val IN ('pedestrian', 'footway')
OR amenity_val IN ('university', 'school', 'college', 'library', 'fuel',
'parking', 'cinema', 'theatre', 'place_of_worship', 'hospital')
OR aeroway_val IN ('runway', 'taxiway', 'apron', 'aerodrome')
OR tourism_val IN ('zoo')
OR man_made_val IN ('pier', 'wastewater_plant', 'works', 'bridge', 'tower',
'breakwater', 'water_works', 'groyne', 'dike', 'cutline')
OR power_val IN ('plant', 'generator', 'substation', 'station', 'sub_station')
OR boundary_val IN ('national_park', 'protected_area');
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- calculate the collapse of several properties onto one string
-- 'kind'. this involves a series of precedence choices, as
-- it's possible for a feature to have values in several of
-- these categories. in general, the "most important" should go
-- first, or its presence should modify the later.
--
-- IF YOU UPDATE THIS, PLEASE UPDATE mz_calculate_is_landuse
-- ABOVE!
CREATE OR REPLACE FUNCTION mz_calculate_landuse_kind(
landuse_val text,
leisure_val text,
natural_val text,
highway_val text,
aeroway_val text,
amenity_val text,
tourism_val text,
man_made_val text,
power_val text,
boundary_val text)
RETURNS text AS $$
BEGIN
RETURN
CASE
WHEN boundary_val IN (
'national_park', 'protected_area')
THEN boundary_val
-- promote this above landuse as it's more specific, and we
-- don't want to lump nature reserves in with all of the
-- generic forests.
WHEN leisure_val = 'nature_reserve'
THEN leisure_val
WHEN landuse_val IN (
'park', 'forest', 'residential', 'retail', 'commercial', 'industrial',
'railway', 'cemetery', 'grass', 'farmyard', 'farm', 'farmland', 'wood',
'meadow', 'village_green', 'recreation_ground', 'allotments', 'quarry',
'urban', 'rural', 'military', 'winter_sports')
THEN landuse_val
WHEN leisure_val IN (
'park', 'garden', 'playground', 'golf_course', 'sports_centre', 'pitch',
'stadium', 'common')
THEN leisure_val
WHEN natural_val IN (
'wood', 'land', 'scrub', 'wetland', 'glacier', 'beach')
THEN natural_val
WHEN highway_val IN (
'pedestrian', 'footway')
THEN highway_val
WHEN amenity_val IN (
'university', 'school', 'college', 'library', 'fuel', 'parking',
'cinema', 'theatre', 'place_of_worship', 'hospital')
THEN amenity_val
WHEN aeroway_val IN (
'runway', 'taxiway', 'apron', 'aerodrome')
THEN aeroway_val
WHEN tourism_val IN (
'zoo')
THEN tourism_val
WHEN man_made_val IN (
'pier', 'wastewater_plant', 'works', 'bridge', 'tower', 'breakwater',
'water_works', 'groyne', 'dike', 'cutline')
THEN man_made_val
WHEN power_val IN (
'plant', 'generator', 'substation', 'station', 'sub_station')
THEN power_val
ELSE NULL END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_poi_level(
aerialway_val text,
aeroway_val text,
amenity_val text,
barrier_val text,
craft_val text,
highway_val text,
historic_val text,
leisure_val text,
lock_val text,
man_made_val text,
natural_val text,
office_val text,
power_val text,
railway_val text,
rental_val text,
shop_val text,
tourism_val text,
waterway_val text,
way_area real
)
RETURNS REAL AS $$
DECLARE
zoom REAL;
BEGIN
zoom = mz_one_pixel_zoom(way_area);
RETURN
CASE
WHEN aeroway_val IN ('aerodrome', 'airport')
THEN LEAST(zoom + 4.12, 13)
WHEN amenity_val = 'hospital'
THEN LEAST(zoom + 3.32, 14)
WHEN natural_val IN ('peak', 'volcano')
THEN 11 -- these are generally point features
WHEN railway_val IN ('station')
THEN LEAST(zoom + 0.38, 13)
WHEN tourism_val = 'zoo'
THEN LEAST(zoom + 3.00, 15)
WHEN (natural_val IN ('spring')
OR railway_val IN ('level_crossing'))
THEN 14 -- these are generally points
WHEN amenity_val IN ('bank', 'cinema', 'courthouse', 'embassy',
'fire_station', 'fuel', 'library', 'police', 'post_office',
'theatre')
THEN LEAST(zoom + 2.7, 16)
WHEN amenity_val IN ('biergarten', 'pub', 'bar', 'restaurant',
'fast_food', 'cafe')
THEN LEAST(zoom + 2.50, 17)
WHEN (amenity_val IN ('pharmacy', 'veterinary')
OR craft_val IN ('brewery', 'carpenter', 'confectionery', 'dressmaker',
'electrician', 'gardener', 'handicraft', 'hvac', 'metal_construction',
'painter', 'photographer', 'photographic_laboratory', 'plumber',
'pottery', 'sawmill', 'shoemaker', 'stonemason', 'tailor', 'winery'))
THEN LEAST(zoom + 3.3, 17)
WHEN amenity_val = 'nursing_home' THEN LEAST(zoom + 1.25, 16)
WHEN shop_val = 'music' THEN LEAST(zoom + 1.27, 17)
WHEN amenity_val = 'community_centre' THEN LEAST(zoom + 3.98, 17)
WHEN shop_val = 'sports' THEN LEAST(zoom + 1.53, 17)
WHEN amenity_val = 'college' THEN LEAST(zoom + 2.35, 16)
WHEN shop_val = 'mall' THEN LEAST(zoom + 2.74, 17)
WHEN leisure_val = 'stadium' THEN LEAST(zoom + 2.30, 15)
WHEN amenity_val = 'university' THEN LEAST(zoom + 2.55, 15)
WHEN tourism_val = 'museum' THEN LEAST(zoom + 1.43, 16)
WHEN historic_val = 'landmark' THEN LEAST(zoom + 1.76, 15)
WHEN leisure_val = 'marina' THEN LEAST(zoom + 3.45, 17)
WHEN amenity_val = 'place_of_worship' THEN LEAST(2 * zoom - 9.55, 17)
WHEN amenity_val = 'townhall' THEN LEAST(zoom + 1.85, 16)
WHEN shop_val = 'laundry' THEN LEAST(zoom + 4.90, 17)
WHEN shop_val = 'dry_cleaning' THEN LEAST(zoom + 4.90, 17)
WHEN amenity_val = 'ferry_terminal' THEN LEAST(zoom + 3.20, 15)
WHEN amenity_val = 'school' THEN LEAST(zoom + 2.30, 15)
WHEN natural_val = 'beach' THEN LEAST(zoom + 3.20, 14)
WHEN rental_val = 'ski' THEN LEAST(zoom + 1.27, 17)
WHEN shop_val = 'ski' THEN LEAST(zoom + 1.27, 17)
WHEN amenity_val = 'ski_rental' THEN LEAST(zoom + 1.27, 17)
WHEN amenity_val = 'ski_school' THEN LEAST(zoom + 2.30, 15)
WHEN man_made_val = 'snow_cannon' THEN LEAST(zoom + 4.90, 18)
WHEN highway_val = 'motorway_junction' THEN 12
WHEN (barrier_val IN ('gate')
OR craft_val IN ('sawmill')
OR highway_val IN ('gate', 'mini_roundabout')
OR lock_val IN ('yes')
OR man_made_val IN ('lighthouse', 'power_wind')
OR natural_val IN ('cave_entrance')
OR power_val IN ('generator')
OR waterway_val IN ('lock')
OR aerialway_val IN ('station')
OR railway_val IN ('halt', 'tram_stop')
OR tourism_val IN ('alpine_hut'))
THEN 15
WHEN (aeroway_val IN ('helipad')
OR amenity_val IN ('bus_station', 'car_sharing',
'picnic_site',
'prison', 'recycling', 'shelter')
OR barrier_val IN ('block', 'bollard', 'lift_gate')
OR craft_val IN ('brewery', 'winery', 'sawmill')
OR highway_val IN ('ford')
OR historic_val IN ('archaeological_site')
OR man_made_val IN ('windmill')
OR natural_val IN ('tree')
OR shop_val IN ('department_store', 'supermarket')
OR tourism_val IN ('camp_site', 'caravan_site', 'information', 'viewpoint')) THEN 16
WHEN (aeroway_val IN ('gate')
OR amenity_val IN (
'atm', 'bicycle_rental', 'bicycle_parking', 'bus_stop',
'drinking_water', 'emergency_phone',
'parking', 'post_box', 'telephone', 'theatre',
'toilets')
OR highway_val IN ('bus_stop', 'traffic_signals')
OR historic_val IN ('memorial')
OR leisure_val IN ('playground', 'slipway')
OR man_made_val IN ('mast', 'water_tower')
OR office_val IN ('accountant', 'administrative', 'advertising_agency',
'architect', 'association', 'company', 'consulting', 'educational_institution',
'employment_agency', 'estate_agent', 'financial', 'foundation', 'government',
'insurance', 'it', 'lawyer', 'newspaper', 'ngo', 'notary', 'physician',
'political_party', 'religion', 'research', 'tax_advisor', 'telecommunication',
'therapist', 'travel_agent', 'yes')
OR shop_val IN ('bakery', 'bicycle', 'books', 'butcher', 'car', 'car_repair',
'clothes', 'computer', 'convenience',
'doityourself', 'dry_cleaning', 'fashion', 'florist', 'gift',
'greengrocer', 'hairdresser', 'jewelry', 'mobile_phone',
'optician', 'pet')
OR tourism_val IN ('bed_and_breakfast', 'chalet', 'guest_house',
'hostel', 'hotel', 'motel')
OR railway_val IN ('subway_entrance')) THEN 17
WHEN (amenity_val IN ('bench', 'waste_basket')) THEN 18
ELSE NULL END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_ferry_level(way geometry)
RETURNS SMALLINT AS $$
DECLARE
way_length real := st_length(way);
BEGIN
RETURN (
CASE
-- this is about when the way is >= 2px in length
WHEN way_length > 1223 THEN 8
WHEN way_length > 611 THEN 9
WHEN way_length > 306 THEN 10
WHEN way_length > 153 THEN 11
WHEN way_length > 76 THEN 12
ELSE 13
END);
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_railway_level(railway_val text, service_val text)
RETURNS SMALLINT AS $$
BEGIN
RETURN CASE
WHEN railway_val = 'rail' THEN CASE
WHEN service_val IS NULL THEN 11
WHEN service_val IN ('spur', 'siding') THEN 12
WHEN service_val IN ('yard') THEN 13
WHEN service_val IN ('crossover') THEN 14
ELSE 15
END
WHEN railway_val IN ('tram', 'light_rail', 'narrow_gauge', 'monorail') THEN 15
ELSE NULL
END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_highway_level(highway_val text, service_val text)
RETURNS SMALLINT AS $$
BEGIN
RETURN CASE
WHEN highway_val IN ('motorway', 'trunk', 'motorway_link', 'primary') THEN 8
WHEN highway_val IN ('secondary') THEN 10
WHEN highway_val IN ('tertiary') THEN 11
WHEN highway_val IN ('trunk_link', 'residential', 'unclassified', 'road') THEN 12
WHEN highway_val IN ('primary_link', 'secondary_link', 'track',
'pedestrian', 'living_street') THEN 13
WHEN highway_val IN ('tertiary_link', 'minor', 'footpath', 'footway',
'steps', 'path', 'cycleway') THEN 14
WHEN highway_val = 'service' THEN CASE
WHEN service_val IS NULL THEN 14
WHEN service_val = 'alley' THEN 13
WHEN service_val IN ('driveway', 'parking_aisle', 'drive-through') THEN 15
ELSE NULL
END
ELSE NULL
END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_aeroway_level(aeroway_val text)
RETURNS SMALLINT AS $$
BEGIN
RETURN CASE
WHEN aeroway_val IN ('runway') THEN 9
WHEN aeroway_val IN ('taxiway') THEN 11
ELSE NULL
END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_aerialway_level(aerialway_val text)
RETURNS SMALLINT AS $$
BEGIN
RETURN CASE
WHEN aerialway_val IN ('gondola', 'cable_car') THEN 12
WHEN aerialway_val IN ('chair_lift') THEN 13
WHEN aerialway_val IN ('drag_lift', 'platter', 't-bar', 'goods',
'magic_carpet', 'rope_tow', 'yes', 'zip_line', 'j-bar',
'unknown', 'mixed_lift', 'canopy', 'cableway') THEN 15
ELSE NULL
END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_leisure_level(leisure_val text, sport_val text)
RETURNS SMALLINT AS $$
BEGIN
RETURN CASE
WHEN leisure_val IN ('track') THEN
CASE
WHEN sport_val IN ('athletics', 'running', 'horse_racing', 'bmx',
'disc_golf', 'cycling', 'ski_jumping', 'motor', 'karting',
'obstacle_course', 'equestrian', 'alpine_slide', 'soap_box_derby',
'mud_truck_racing', 'skiing', 'drag_racing', 'archery') THEN 14
ELSE NULL
END
ELSE NULL
END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_road_level(highway_val text, railway_val text, aeroway_val text, route_val text, service_val text, aerialway_val text, leisure_val text, sport_val text, way geometry)
RETURNS SMALLINT AS $$
BEGIN
RETURN LEAST(
CASE WHEN highway_val IS NOT NULL
THEN mz_calculate_highway_level(highway_val, service_val)
ELSE NULL END,
CASE WHEN aeroway_val IS NOT NULL
THEN mz_calculate_aeroway_level(aeroway_val)
ELSE NULL END,
CASE WHEN railway_val IS NOT NULL
THEN mz_calculate_railway_level(railway_val, service_val)
ELSE NULL END,
CASE WHEN route_val = 'ferry'
THEN mz_calculate_ferry_level(way)
ELSE NULL END,
CASE WHEN aerialway_val IS NOT NULL
THEN mz_calculate_aerialway_level(aerialway_val)
ELSE NULL END,
CASE WHEN leisure_val IS NOT NULL
THEN mz_calculate_leisure_level(leisure_val, sport_val)
ELSE NULL END);
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_is_water(
waterway_val text, natural_val text, landuse_val text)
RETURNS BOOLEAN AS $$
BEGIN
RETURN (
waterway_val IN ('riverbank', 'dock')
OR natural_val IN ('water')
OR landuse_val IN ('basin', 'reservoir')
);
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_is_building_or_part(
building_val text, buildingpart_val text)
RETURNS BOOLEAN AS $$
BEGIN
-- there are 12,000 uses of building=no, so we ought to take that into
-- account when figuring out if something is a building or not. also,
-- returning "kind=no" is a bit weird.
RETURN ((building_val IS NOT NULL AND building_val <> 'no') OR
(buildingpart_val IS NOT NULL AND buildingpart_val <> 'no'));
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_transit_level(route_val text)
RETURNS SMALLINT AS $$
BEGIN
RETURN (
CASE WHEN route_val IN ('train', 'railway') THEN 6
WHEN route_val IN ('subway', 'light_rail', 'tram') THEN 10
ELSE NULL END
);
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- mz_rel_get_tag returns the tag value associated with a given
-- key, or NULL if the tag is not set in the array.
--
-- tags in the planet_osm_rels table are stored in a flat array
-- rather than in an hstore variable. so this function makes it
-- easier to extract values from that array as if it were
-- associative.
--
CREATE OR REPLACE FUNCTION mz_rel_get_tag(
tags text[],
k text)
RETURNS text AS $$
DECLARE
lo CONSTANT integer := array_lower(tags, 1);
hi CONSTANT integer := array_upper(tags, 1);
BEGIN
-- if tags is null, then we're not going to find any values
-- in it, so just short-circuit and return NULL.
IF tags IS NULL THEN
RETURN NULL;
END IF;
-- tags is an array of key-value pairs inline, so to get the
-- keys only we want each odd offset.
FOR i IN 0 .. ((hi - lo - 1) / 2)
LOOP
IF tags[2 * i + lo] = k THEN
RETURN tags[2 * i + lo + 1];
END IF;
END LOOP;
RETURN NULL;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- mz_first_dedup returns the lexicographically first non-NULL
-- entry in an array of text.
--
-- this is used to get a single value from the array of perhaps
-- many relations that a way can be a member of. we're not
-- interested in NULL values, so those can be discarded. it
-- remains to be seen if lexicographic ordering is any good for
-- network names, but in the limited testing i've done so far,
-- it seems to do okay.
--
CREATE OR REPLACE FUNCTION mz_first_dedup(
arr text[])
RETURNS text AS $$
DECLARE
rv text;
BEGIN
SELECT DISTINCT y.x INTO rv FROM (SELECT unnest(arr) as x) y
WHERE y.x IS NOT NULL LIMIT 1;
RETURN rv;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- mz_get_rel_network returns a network tag, or NULL, for a
-- given way ID.
--
-- it does this by joining onto the relations slim table, so it
-- won't work if you dropped the slim tables, or didn't use slim
-- mode in osm2pgsql.
--
CREATE OR REPLACE FUNCTION mz_get_rel_network(
way_id bigint)
RETURNS text AS $$
BEGIN
RETURN mz_first_dedup(ARRAY(
SELECT mz_rel_get_tag(tags, 'network')
FROM planet_osm_rels
WHERE parts && ARRAY[way_id]
AND parts[way_off+1:rel_off] && ARRAY[way_id]));
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- adds the prefix onto every key in an hstore value
CREATE OR REPLACE FUNCTION mz_hstore_add_prefix(
tags hstore,
prefix text)
RETURNS hstore AS $$
DECLARE
new_tags hstore;
BEGIN
SELECT hstore(array_agg(prefix || key), array_agg(value))
INTO STRICT new_tags
FROM each(tags);
RETURN new_tags;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- OSM tags are often structured as a list separated by ':'s.
-- to preserve some kind of ordering information, we want to
-- insert an element in this "list" after the first element.
-- i.e: mz_insert_one_level('foo:bar', 'x') -> 'foo:x:bar'.
CREATE OR REPLACE FUNCTION mz_insert_one_level(
tag text,
str text)
RETURNS text AS $$
DECLARE
arr text[] = string_to_array(tag, ':');
fst text = arr[1];
len int = array_upper(arr, 1);
rst text[] = arr[2:len];
BEGIN
RETURN array_to_string(ARRAY[fst, str] || rst, ':');
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- adds an infix value into every key in an hstore value after
-- the first element. so 'foo:bar=>bat' with infix 'x' becomes
-- 'foo:x:bar=>bat'.
CREATE OR REPLACE FUNCTION mz_hstore_add_infix(
tags hstore,
infix text)
RETURNS hstore AS $$
DECLARE
new_tags hstore;
BEGIN
SELECT hstore(array_agg(mz_insert_one_level(key, infix)), array_agg(value))
INTO STRICT new_tags
FROM each(tags);
RETURN new_tags;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- returns the (possibly fractional) zoom at which the given way
-- area will be one square pixel nominally on screen (assuming
-- that tiles are 256x256px at integer zooms). sadly, features
-- aren't always rectangular and axis-aligned, but this should
-- still give a reasonable approximation to the zoom that it
-- would be appropriate to show them.
CREATE OR REPLACE FUNCTION mz_one_pixel_zoom(
way_area real)
RETURNS real AS $$
BEGIN
RETURN
-- can't take logarithm of zero, and some ways have
-- incredibly tiny areas, down to even zero. also, by z16
-- all features really should be visible, so we clamp the
-- computation at the way area which would result in 16
-- being returned.
CASE WHEN way_area < 5.704
THEN 16.0
ELSE (17.256-ln(way_area)/ln(4))
END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_calculate_landuse_min_zoom(
landuse_val TEXT,
leisure_val TEXT,
natural_val TEXT,
highway_val TEXT,
amenity_val TEXT,
aeroway_val TEXT,
tourism_val TEXT,
man_made_val TEXT,
power_val TEXT,
boundary_val TEXT,
way_area REAL)
RETURNS REAL AS $$
DECLARE
zoom REAL;
BEGIN
zoom = mz_one_pixel_zoom(way_area);
RETURN
CASE
WHEN (boundary_val IN ('national_park', 'protected_area')
OR leisure_val = 'nature_reserve')
THEN zoom
ELSE
GREATEST(LEAST(zoom, 16), 9)
END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- calculate the list of refs (or names) of transit routes that
-- a particular station is part of. this ends up being a very
-- complex function because it's bouncing around between the
-- nodes, ways and relations to calculate membership of various
-- sets.
CREATE OR REPLACE FUNCTION mz_calculate_transit_routes(
station_node_id BIGINT)
RETURNS text[] AS $$
DECLARE
-- IDs of "stop area" relations which contain the station nodes.
-- each individual line may have its own stop node, and this is
-- the relation which groups the stops together with the station.
stop_area_ids bigint[];
-- IDs of nodes which are tagged as stations or stops and are
-- members of the stop area relations. these will contain the
-- original `station_node_id`, but probably many others as well.
stations_and_stops bigint[];
-- IDs of ways which contain any of the stations and stops.
-- these are included because sometimes the stop node isn't
-- directly included in the route relation, only the way
-- representing the track itself.
lines bigint[];
BEGIN
stop_area_ids := ARRAY(
SELECT DISTINCT r.id
FROM planet_osm_rels r
WHERE r.parts && ARRAY[station_node_id]
AND r.parts[1:r.way_off] && ARRAY[station_node_id]
AND mz_rel_get_tag(r.tags, 'public_transport') = 'stop_area'
);
stations_and_stops := ARRAY(
SELECT DISTINCT n.id
FROM planet_osm_nodes n
JOIN (SELECT DISTINCT unnest(r.parts[1:r.way_off]) AS node_id
FROM planet_osm_rels r
WHERE r.id = ANY(stop_area_ids)) r
ON r.node_id = n.id
WHERE (
mz_rel_get_tag(n.tags, 'railway') IN ('station', 'stop') OR
mz_rel_get_tag(n.tags, 'public_transport') IN ('stop', 'stop_position'))
-- manually re-include the original station node, in case it's
-- not part of a public_transport=stop_area relation.
UNION SELECT station_node_id AS id
);
lines := ARRAY(
SELECT DISTINCT w.id
FROM planet_osm_ways w
WHERE w.nodes && stations_and_stops
AND mz_rel_get_tag(w.tags, 'railway') IN ('subway', 'light_rail', 'tram', 'rail')
);
RETURN ARRAY(
SELECT DISTINCT trim(both from "name")
FROM (
SELECT unnest(string_to_array(COALESCE(
-- prefer ref as it's less likely to contain the destination name
mz_rel_get_tag(tags, 'ref'),
mz_rel_get_tag(tags, 'name')
), ',')) AS "name"
FROM planet_osm_rels
WHERE ((
parts && stations_and_stops AND
parts[1:way_off] && stations_and_stops
) OR (
parts && lines AND
parts[way_off+1:rel_off] && lines
)) AND
mz_rel_get_tag(tags, 'type') = 'route' AND
mz_rel_get_tag(tags, 'route') IN ('subway', 'light_rail', 'tram', 'train')
) subquery
);
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- returns true if the text is numeric and can be cast
-- to a float without error.
CREATE OR REPLACE FUNCTION mz_is_numeric(
t text)
RETURNS BOOLEAN AS $$
BEGIN
RETURN t ~ '^([0-9]+[.]?[0-9]*|[.][0-9]+)$';
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- replicate some of the backend logic for filtering
-- buildings, as there are lots and lots and lots of
-- these, often with quite complex geometries, and
-- we don't want to saturate the network with lots of
-- buildings at z13 that we're going to filter out.
CREATE OR REPLACE FUNCTION mz_building_filter(
height text, levels text, way_area FLOAT, min_volume FLOAT, min_area FLOAT)
RETURNS BOOLEAN AS $$
BEGIN
RETURN CASE
-- if height is present, and can be parsed as a
-- float, then we can filter right here.
WHEN mz_is_numeric(height)
THEN (height::float * way_area) >= min_volume
-- looks like we assume each level is 3m, plus
-- 2 overall.
WHEN mz_is_numeric(levels)
THEN ((GREATEST(levels::float, 1) * 3 + 2) * way_area) >= min_volume
-- if height is present, but not numeric, then
-- we have no idea what it could be, and we must
-- assume it could be very large.
WHEN height IS NOT NULL OR levels IS NOT NULL
THEN TRUE
-- height isn't present, so just filter on area
-- as we did before.
ELSE way_area >= min_area
END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION mz_trigger_function_line()
RETURNS TRIGGER AS $$
BEGIN
NEW.mz_road_level := mz_calculate_road_level(NEW."highway", NEW."railway", NEW."aeroway", NEW."route", NEW."service", NEW."aerialway", NEW."leisure", NEW."sport", NEW."way");
NEW.mz_transit_level := mz_calculate_transit_level(NEW."route");
RETURN NEW;
END;
$$ LANGUAGE plpgsql VOLATILE;
UPDATE planet_osm_point SET
mz_poi_min_zoom = mz_calculate_poi_level("aerialway", "aeroway", "amenity", "barrier", "craft",
"highway", "historic", "leisure", "lock", "man_made", "natural", "office", "power", "railway",
"shop", "tourism", "waterway", 0::real)
WHERE highway='motorway_junction';
UPDATE planet_osm_point
SET mz_poi_min_zoom = mz_calculate_poi_level("aerialway", "aeroway", "amenity", "barrier", "craft", "highway", "historic", "leisure", "lock", "man_made", "natural", "office", "power", "railway", "tags"->'rental', "shop", "tourism", "waterway", 0::real)
WHERE "tags"->'rental' = 'ski' OR
shop = 'ski' OR
amenity IN ('ski_rental', 'ski_school') OR
man_made = 'snow_cannon';
UPDATE planet_osm_point SET
mz_poi_min_zoom = mz_calculate_poi_level("aerialway", "aeroway", "amenity", "barrier", "craft", "highway", "historic", "leisure", "lock", "man_made", "natural", "office", "power", "railway", "shop", "tourism", "waterway", 0::real)
WHERE "natural" = 'beach';
UPDATE planet_osm_point SET
mz_poi_min_zoom = mz_calculate_poi_level("aerialway", "aeroway", "amenity", "barrier", "craft", "highway", "historic", "leisure", "lock", "man_made", "natural", "office", "power", "railway", "shop", "tourism", "waterway", 0::real)
WHERE "amenity" = 'school';
-- UPDATE planet_osm_line
-- SET mz_road_level = mz_calculate_road_level(highway, railway, aeroway, route, service, aerialway, leisure, sport, way)
-- WHERE leisure='track';
UPDATE planet_osm_line SET mz_road_level = mz_calculate_road_level("highway", "railway", "aeroway", "route", "service", "aerialway", "way") WHERE highway='service' AND service='parking_aisle';
CREATE INDEX planet_osm_line_piste_geom_index ON planet_osm_line USING gist(way) WHERE tags ? 'piste:type';
CREATE INDEX planet_osm_line_railway_platform_index ON planet_osm_line USING gist(way) WHERE railway='platform';
UPDATE planet_osm_polygon SET
mz_poi_min_zoom = mz_calculate_poi_level("aerialway", "aeroway", "amenity", "barrier", "craft", "highway", "historic", "leisure", "lock", "man_made", "natural", "office", "power", "railway", "shop", "tourism", "waterway", 0::real)
WHERE highway='motorway_junction';
UPDATE planet_osm_polygon
SET mz_poi_min_zoom = mz_calculate_poi_level("aerialway", "aeroway", "amenity", "barrier", "craft", "highway", "historic", "leisure", "lock", "man_made", "natural", "office", "power", "railway", "tags"->'rental', "shop", "tourism", "waterway", way_area)
WHERE "tags"->'rental' = 'ski' OR
shop = 'ski' OR
amenity IN ('ski_rental', 'ski_school') OR
man_made = 'snow_cannon';
UPDATE planet_osm_polygon
SET mz_is_landuse = TRUE,
mz_landuse_min_zoom = mz_calculate_landuse_min_zoom("landuse", "leisure", "natural", "highway", "amenity", "aeroway", "tourism", "man_made", "power", "boundary", way_area)
WHERE landuse='winter_sports';
UPDATE planet_osm_polygon SET
mz_is_landuse = TRUE,
mz_landuse_min_zoom = mz_calculate_landuse_min_zoom("landuse", "leisure", "natural", "highway", "amenity", "aeroway", "tourism", "man_made", "power", "boundary", way_area),
mz_poi_min_zoom = mz_calculate_poi_level("aerialway", "aeroway", "amenity", "barrier", "craft", "highway", "historic", "leisure", "lock", "man_made", "natural", "office", "power", "railway", "shop", "tourism", "waterway", way_area)
WHERE "natural" = 'beach';
CREATE INDEX planet_osm_polygon_railway_platform_index ON planet_osm_polygon USING gist(way) WHERE railway='platform';
ALTER TABLE planet_osm_point ENABLE TRIGGER USER;
ALTER TABLE planet_osm_polygon ENABLE TRIGGER USER;
ALTER TABLE planet_osm_line ENABLE TRIGGER USER;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment