maps/backend/initdb/02_tile_functions.sql
2026-04-05 18:05:14 +02:00

216 lines
No EOL
6 KiB
PL/PgSQL

-- Zoom-dependent tile functions for Martin.
-- These apply geometry simplification and feature filtering so that
-- low-zoom tiles contain fewer, simpler features.
--------------------------------------------------------------------------------
-- planet_osm_polygon
--------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION tile_polygon(z integer, x integer, y integer)
RETURNS bytea AS $$
DECLARE
bounds geometry;
tolerance double precision;
result bytea;
BEGIN
bounds := ST_TileEnvelope(z, x, y);
-- Simplification tolerance scales with zoom: lower zoom = more aggressive
tolerance := CASE
WHEN z >= 13 THEN 0 -- full detail
WHEN z >= 11 THEN 1 -- light simplification
WHEN z >= 9 THEN 10 -- moderate
ELSE 50 -- heavy
END;
WITH features AS (
SELECT
osm_id,
name,
building,
landuse,
"natural",
amenity,
leisure,
water,
waterway,
CASE
WHEN tolerance = 0 THEN ST_AsMVTGeom(way, bounds)
ELSE ST_AsMVTGeom(
ST_Simplify(way, tolerance, true),
bounds
)
END AS geom
FROM planet_osm_polygon
WHERE way && bounds
-- Feature filtering by zoom level:
AND CASE
-- zoom 8-9: only water, large forests/parks
WHEN z < 10 THEN
"natural" IN ('water', 'wood') OR landuse IN ('forest', 'reservoir')
-- zoom 10-11: add more landuse
WHEN z < 12 THEN
"natural" IN ('water', 'wood', 'wetland', 'heath', 'scrub')
OR landuse IN ('forest', 'reservoir', 'residential', 'industrial',
'commercial', 'farmland', 'meadow', 'grass')
OR leisure IN ('park', 'nature_reserve', 'garden')
-- zoom 12: add buildings (large only)
WHEN z < 13 THEN
"natural" IS NOT NULL OR landuse IS NOT NULL OR leisure IS NOT NULL
OR water IS NOT NULL
OR (building IS NOT NULL AND ST_Area(way) > 5000)
-- zoom 13+: everything
ELSE true
END
)
SELECT ST_AsMVT(features, 'planet_osm_polygon') INTO result FROM features;
RETURN result;
END;
$$ LANGUAGE plpgsql STABLE PARALLEL SAFE;
--------------------------------------------------------------------------------
-- planet_osm_line
--------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION tile_line(z integer, x integer, y integer)
RETURNS bytea AS $$
DECLARE
bounds geometry;
tolerance double precision;
result bytea;
BEGIN
bounds := ST_TileEnvelope(z, x, y);
tolerance := CASE
WHEN z >= 13 THEN 0
WHEN z >= 11 THEN 5
ELSE 20
END;
WITH features AS (
SELECT
osm_id,
name,
highway,
railway,
waterway,
CASE
WHEN tolerance = 0 THEN ST_AsMVTGeom(way, bounds)
ELSE ST_AsMVTGeom(
ST_Simplify(way, tolerance, true),
bounds
)
END AS geom
FROM planet_osm_line
WHERE way && bounds
AND CASE
-- zoom 10-11: only major roads and rivers
WHEN z < 12 THEN
highway IN ('motorway', 'trunk', 'primary', 'secondary')
OR railway IN ('rail')
OR waterway IN ('river', 'canal')
-- zoom 12: add tertiary roads
WHEN z < 13 THEN
highway IN ('motorway', 'trunk', 'primary', 'secondary',
'tertiary', 'motorway_link', 'trunk_link')
OR railway IS NOT NULL
OR waterway IS NOT NULL
-- zoom 13+: everything
ELSE true
END
)
SELECT ST_AsMVT(features, 'planet_osm_line') INTO result FROM features;
RETURN result;
END;
$$ LANGUAGE plpgsql STABLE PARALLEL SAFE;
--------------------------------------------------------------------------------
-- planet_osm_point
--------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION tile_point(z integer, x integer, y integer)
RETURNS bytea AS $$
DECLARE
bounds geometry;
result bytea;
BEGIN
bounds := ST_TileEnvelope(z, x, y);
WITH features AS (
SELECT
osm_id,
name,
place,
amenity,
shop,
tourism,
"natural",
ST_AsMVTGeom(way, bounds) AS geom
FROM planet_osm_point
WHERE way && bounds
AND CASE
-- zoom 12: only cities/towns/villages and major POIs
WHEN z < 13 THEN
place IN ('city', 'town', 'village')
-- zoom 13: add hamlets and named POIs
WHEN z < 14 THEN
place IS NOT NULL
OR (name IS NOT NULL AND (amenity IS NOT NULL OR tourism IS NOT NULL))
-- zoom 14+: everything
ELSE true
END
)
SELECT ST_AsMVT(features, 'planet_osm_point') INTO result FROM features;
RETURN result;
END;
$$ LANGUAGE plpgsql STABLE PARALLEL SAFE;
--------------------------------------------------------------------------------
-- planet_osm_roads
--------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION tile_roads(z integer, x integer, y integer)
RETURNS bytea AS $$
DECLARE
bounds geometry;
tolerance double precision;
result bytea;
BEGIN
bounds := ST_TileEnvelope(z, x, y);
tolerance := CASE
WHEN z >= 10 THEN 0
WHEN z >= 8 THEN 10
ELSE 50
END;
WITH features AS (
SELECT
osm_id,
name,
highway,
ref,
CASE
WHEN tolerance = 0 THEN ST_AsMVTGeom(way, bounds)
ELSE ST_AsMVTGeom(
ST_Simplify(way, tolerance, true),
bounds
)
END AS geom
FROM planet_osm_roads
WHERE way && bounds
AND CASE
-- zoom 6-7: motorways only
WHEN z < 8 THEN
highway IN ('motorway', 'trunk')
-- zoom 8-9: add primary roads
WHEN z < 10 THEN
highway IN ('motorway', 'trunk', 'primary')
-- zoom 10+: everything in the roads table
ELSE true
END
)
SELECT ST_AsMVT(features, 'planet_osm_roads') INTO result FROM features;
RETURN result;
END;
$$ LANGUAGE plpgsql STABLE PARALLEL SAFE;