From f8488d2257eb3204a7475f55ec4714ff575166de Mon Sep 17 00:00:00 2001 From: dch0ph Date: Fri, 12 Apr 2024 21:13:51 +0100 Subject: [PATCH 01/18] Interpret additional access tags mode specific access tags relevant to primary mode of highway interpreted to determine access marking for: Road types (motorcar > motor_vehicle > vehicle) Footway (foot) Cycleway (bicycle) Bridleway (horse) --- INSTALL.md | 7 +++++ functions.sql | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ project.mml | 39 ++++++++----------------- style/roads.mss | 72 +++++++++++++++++++++++----------------------- 4 files changed, 131 insertions(+), 63 deletions(-) create mode 100644 functions.sql diff --git a/INSTALL.md b/INSTALL.md index 74029fb1a..7bbfb282d 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -47,6 +47,13 @@ The indexes can be created in parallel with scripts/indexes.py -0 | xargs -0 -P0 -I{} psql -d gis -c "{}" ``` +### Database functions +Some functions need to be loaded into the database for current versions. These can be added / re-loaded at any point using: + +```sh +psql -d gis -f functions.sql +``` + ## Scripted download Some features are rendered using preprocessed shapefiles. diff --git a/functions.sql b/functions.sql new file mode 100644 index 000000000..e85ccc332 --- /dev/null +++ b/functions.sql @@ -0,0 +1,76 @@ +/* Additional database functions for openstreetmap-carto */ + +/* Access functions below adapted from https://github.com/imagico/osm-carto-alternative-colors/tree/591c861112b4e5d44badd108f4cd1409146bca0b/sql/roads.sql */ + + +/* Simplified 'yes', 'restricted', 'no', NULL scale for access restriction + 'no' is returned if the rendering for highway category does not support 'destination'. + NULL is functionally equivalent to 'yes', but indicates the absence of a restriction + rather than a positive access = yes */ +CREATE OR REPLACE FUNCTION carto_int_access(primary_mode text, accesstag text) + RETURNS text + LANGUAGE SQL + IMMUTABLE PARALLEL SAFE +AS $$ +SELECT + CASE + WHEN accesstag IN ('yes', 'designated', 'permissive', 'customers') THEN 'yes' + WHEN accesstag IN ('destination', 'delivery', 'permit') THEN + CASE WHEN primary_mode IN ('motorcar', 'pedestrian') THEN 'restricted' ELSE 'no' END + WHEN accesstag IN ('no', 'private', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' + ELSE NULL + END +END +$$; + +/* Classify highways into access categories which will be treated in the same way + Default is NULL in which case only the access tag will be used (e.g. highway=track) + Note that bicycle, horse arguments are only relevant if considering highway=path */ +CREATE OR REPLACE FUNCTION carto_highway_primary_mode(highway text, bicycle text, horse text) + RETURNS text + LANGUAGE SQL + IMMUTABLE PARALLEL SAFE +AS $$ +SELECT + CASE + WHEN highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link', 'primary', 'primary_link', 'secondary', + 'secondary_link', 'tertiary', 'tertiary_link', 'residential', 'unclassified', 'living_street', 'service', 'road') THEN 'motorcar' + WHEN highway = 'pedestrian' THEN 'pedestrian' + WHEN highway IN ('footway', 'steps') THEN 'foot' + WHEN highway = 'bridleway' THEN 'horse' + WHEN highway = 'cycleway' THEN 'bicycle' + WHEN highway = 'path' THEN carto_path_primary_mode(bicycle, horse) + ELSE NULL + END +END +$$; + +/* Return int_access value which will be used to determine access marking. + Only a restricted number of types can be returned, with NULL corresponding to no access restriction */ +CREATE OR REPLACE FUNCTION carto_highway_int_access(highway text, "access" text, foot text, bicycle text, horse text, motorcar text, motor_vehicle text, vehicle text) + RETURNS text + LANGUAGE SQL + IMMUTABLE PARALLEL SAFE +AS $$ +SELECT + CASE carto_highway_primary_mode(highway, bicycle, horse) + WHEN 'motorcar' THEN + carto_int_access('motorcar', CASE + WHEN motorcar IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN motorcar + WHEN motor_vehicle IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN motor_vehicle + WHEN vehicle IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN vehicle + ELSE "access" END) + WHEN 'pedestrian' THEN carto_int_access('pedestrian', 'no') + WHEN 'foot' THEN carto_int_access('foot', CASE WHEN foot IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN foot ELSE "access" END) + WHEN 'bicycle' THEN carto_int_access('bicycle', CASE WHEN bicycle IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN bicycle ELSE "access" END) + WHEN 'horse' THEN carto_int_access('horse', CASE WHEN horse IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN horse ELSE "access" END) + ELSE carto_int_access(NULL, "access") + END +END +$$; + +/* Uncomment lines below to create generated column for int_access +ALTER TABLE planet_osm_line DROP COLUMN IF EXISTS int_access; +ALTER TABLE planet_osm_line + ADD int_access text GENERATED ALWAYS AS (CASE WHEN highway IS NOT NULL THEN carto_highway_int_access(highway, "access", foot, bicycle, horse, tags->'motorcar', tags->'motor_vehicle', tags->'vehicle') ELSE NULL END) STORED; +*/ diff --git a/project.mml b/project.mml index 8152046e5..32803027a 100644 --- a/project.mml +++ b/project.mml @@ -449,7 +449,7 @@ Layer: bicycle, tracktype, int_surface, - access, + int_access, construction, service, link, @@ -467,9 +467,7 @@ Layer: WHEN surface IN ('paved', 'asphalt', 'cobblestone', 'cobblestone:flattened', 'sett', 'concrete', 'concrete:lanes', 'concrete:plates', 'paving_stones', 'metal', 'wood', 'unhewn_cobblestone') THEN 'paved' END AS int_surface, - CASE WHEN access IN ('destination') THEN 'destination'::text - WHEN access IN ('no', 'private') THEN 'no'::text - END AS access, + carto_highway_int_access(highway, access, foot, bicycle, horse, tags->'motorcar', tags->'motor_vehicle', tags->'vehicle') AS int_access, construction, CASE WHEN service IN ('parking_aisle', 'drive-through', 'driveway') THEN 'INT-minor'::text @@ -496,10 +494,7 @@ Layer: bicycle, tracktype, 'null', - CASE - WHEN access IN ('destination') THEN 'destination'::text - WHEN access IN ('no', 'private') THEN 'no'::text - END AS access, + NULL, construction, CASE WHEN service IN ('parking_aisle', 'drive-through', 'driveway') THEN 'INT-minor'::text ELSE 'INT-normal'::text END AS service, 'no' AS link, @@ -514,7 +509,7 @@ Layer: z_order, CASE WHEN substring(feature for 8) = 'railway_' THEN 2 ELSE 1 END, CASE WHEN feature IN ('railway_INT-preserved-ssy', 'railway_INT-spur-siding-yard', 'railway_tram-service') THEN 0 ELSE 1 END, - CASE WHEN access IN ('no', 'private') THEN 0 WHEN access IN ('destination') THEN 1 ELSE 2 END, + CASE int_access WHEN 'no' THEN 0 WHEN 'restricted' THEN 1 ELSE 2 END, CASE WHEN int_surface IN ('unpaved') THEN 0 ELSE 1 END ) AS tunnels properties: @@ -686,7 +681,7 @@ Layer: bicycle, tracktype, int_surface, - access, + int_access, construction, service, link, @@ -704,9 +699,7 @@ Layer: WHEN surface IN ('paved', 'asphalt', 'cobblestone', 'cobblestone:flattened', 'sett', 'concrete', 'concrete:lanes', 'concrete:plates', 'paving_stones', 'metal', 'wood', 'unhewn_cobblestone') THEN 'paved' END AS int_surface, - CASE WHEN access IN ('destination') THEN 'destination'::text - WHEN access IN ('no', 'private') THEN 'no'::text - END AS access, + carto_highway_int_access(highway, access, foot, bicycle, horse, tags->'motorcar', tags->'motor_vehicle', tags->'vehicle') AS int_access, construction, CASE WHEN service IN ('parking_aisle', 'drive-through', 'driveway') OR leisure IN ('slipway') THEN 'INT-minor'::text @@ -741,10 +734,7 @@ Layer: 'concrete:plates', 'paving_stones', 'metal', 'wood', 'unhewn_cobblestone') THEN 'paved' ELSE NULL END AS int_surface, - CASE - WHEN access IN ('destination') THEN 'destination'::text - WHEN access IN ('no', 'private') THEN 'no'::text - END AS access, + NULL, construction, CASE WHEN service IN ('parking_aisle', 'drive-through', 'driveway') OR leisure IN ('slipway') THEN 'INT-minor'::text ELSE 'INT-normal'::text END AS service, 'no' AS link, @@ -763,7 +753,7 @@ Layer: z_order, CASE WHEN substring(feature for 8) = 'railway_' THEN 2 ELSE 1 END, CASE WHEN feature IN ('railway_INT-preserved-ssy', 'railway_INT-spur-siding-yard', 'railway_tram-service') THEN 0 ELSE 1 END, - CASE WHEN access IN ('no', 'private') THEN 0 WHEN access IN ('destination') THEN 1 ELSE 2 END, + CASE int_access WHEN 'no' THEN 0 WHEN 'restricted' THEN 1 ELSE 2 END, CASE WHEN int_surface IN ('unpaved') THEN 0 ELSE 1 END, osm_id ) AS roads_sql @@ -918,7 +908,7 @@ Layer: bicycle, tracktype, int_surface, - access, + int_access, construction, service, link, @@ -936,9 +926,7 @@ Layer: WHEN surface IN ('paved', 'asphalt', 'cobblestone', 'cobblestone:flattened', 'sett', 'concrete', 'concrete:lanes', 'concrete:plates', 'paving_stones', 'metal', 'wood', 'unhewn_cobblestone') THEN 'paved' END AS int_surface, - CASE WHEN access IN ('destination') THEN 'destination'::text - WHEN access IN ('no', 'private') THEN 'no'::text - END AS access, + carto_highway_int_access(highway, access, foot, bicycle, horse, tags->'motorcar', tags->'motor_vehicle', tags->'vehicle') AS int_access, construction, CASE WHEN service IN ('parking_aisle', 'drive-through', 'driveway') THEN 'INT-minor'::text @@ -965,10 +953,7 @@ Layer: bicycle, tracktype, 'null', - CASE - WHEN access IN ('destination') THEN 'destination'::text - WHEN access IN ('no', 'private') THEN 'no'::text - END AS access, + NULL, construction, CASE WHEN service IN ('parking_aisle', 'drive-through', 'driveway') THEN 'INT-minor'::text ELSE 'INT-normal'::text END AS service, 'no' AS link, @@ -983,7 +968,7 @@ Layer: z_order, CASE WHEN substring(feature for 8) = 'railway_' THEN 2 ELSE 1 END, CASE WHEN feature IN ('railway_INT-preserved-ssy', 'railway_INT-spur-siding-yard', 'railway_tram-service') THEN 0 ELSE 1 END, - CASE WHEN access IN ('no', 'private') THEN 0 WHEN access IN ('destination') THEN 1 ELSE 2 END, + CASE int_access WHEN 'no' THEN 0 WHEN 'restricted' THEN 1 ELSE 2 END, CASE WHEN int_surface IN ('unpaved') THEN 0 ELSE 1 END ) AS bridges properties: diff --git a/style/roads.mss b/style/roads.mss index 1141d9105..4cbc58466 100644 --- a/style/roads.mss +++ b/style/roads.mss @@ -644,7 +644,7 @@ [feature = 'highway_steps'] { #bridges { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-width: @steps-width-z14 + 2 * (@paths-background-width + @paths-bridge-casing-width); [zoom >= 15] { line-width: @steps-width-z15 + 2 * (@paths-background-width + @paths-bridge-casing-width); } @@ -653,7 +653,7 @@ } } #tunnels { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-width: @steps-width-z14 + 2 * (@paths-background-width + @paths-tunnel-casing-width); [zoom >= 15] { line-width: @steps-width-z15 + 2 * (@paths-background-width + @paths-tunnel-casing-width); } @@ -666,7 +666,7 @@ [feature = 'highway_bridleway'], [feature = 'highway_path'][horse = 'designated'] { #bridges { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-width: @bridleway-width-z13 + 2 * (@paths-background-width + @paths-bridge-casing-width); [zoom >= 15] { line-width: @bridleway-width-z15 + 2 * (@paths-background-width + @paths-bridge-casing-width); } @@ -675,7 +675,7 @@ } } #tunnels { - [zoom >= 13][access != 'no'], + [zoom >= 13][int_access != 'no'], [zoom >= 15] { line-width: @bridleway-width-z13 + 2 * (@paths-background-width + @paths-tunnel-casing-width); [zoom >= 15] { line-width: @bridleway-width-z15 + 2 * (@paths-background-width + @paths-tunnel-casing-width); } @@ -688,7 +688,7 @@ [feature = 'highway_footway'], [feature = 'highway_path'][bicycle != 'designated'][horse != 'designated'] { #bridges { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-width: @footway-width-z14 + 2 * (@paths-background-width + @paths-bridge-casing-width); [zoom >= 15] { line-width: @footway-width-z15 + 2 * (@paths-background-width + @paths-bridge-casing-width); } @@ -700,7 +700,7 @@ } } #tunnels { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-width: @footway-width-z14 + 2 * (@paths-background-width + @paths-tunnel-casing-width); [zoom >= 15] { line-width: @footway-width-z15 + 2 * (@paths-background-width + @paths-tunnel-casing-width); } @@ -716,7 +716,7 @@ [feature = 'highway_cycleway'], [feature = 'highway_path'][bicycle = 'designated'] { #bridges { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-width: @cycleway-width-z13 + 2 * (@paths-background-width + @paths-bridge-casing-width); [zoom >= 15] { line-width: @cycleway-width-z15 + 2 * (@paths-background-width + @paths-bridge-casing-width); } @@ -728,7 +728,7 @@ } } #tunnels { - [zoom >= 13][access != 'no'], + [zoom >= 13][int_access != 'no'], [zoom >= 15] { line-width: @cycleway-width-z13 + 2 * (@paths-background-width + @paths-tunnel-casing-width); [zoom >= 15] { line-width: @cycleway-width-z15 + 2 * (@paths-background-width + @paths-tunnel-casing-width); } @@ -743,7 +743,7 @@ [feature = 'highway_track'] { #bridges { - [zoom >= 13][access != 'no'] { + [zoom >= 13][int_access != 'no'] { line-color: @bridge-casing; line-join: round; line-width: @track-width-z13 + 2 * (@paths-background-width + @paths-bridge-casing-width); @@ -767,7 +767,7 @@ } } #tunnels { - [zoom >= 13][access != 'no'], + [zoom >= 13][int_access != 'no'], [zoom >= 15] { line-color: @tunnel-casing; line-dasharray: 4,2; @@ -870,7 +870,7 @@ [feature = 'highway_bridleway'], [feature = 'highway_path'][horse = 'designated'] { #bridges { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-width: @bridleway-width-z13 + 2 * @paths-background-width; [zoom >= 15] { line-width: @bridleway-width-z15 + 2 * @paths-background-width; } @@ -879,7 +879,7 @@ } } #tunnels { - [zoom >= 13][access != 'no'], + [zoom >= 13][int_access != 'no'], [zoom >= 15] { line-color: @bridleway-casing; line-cap: round; @@ -893,7 +893,7 @@ [feature = 'highway_footway'], [feature = 'highway_path'][bicycle != 'designated'][horse != 'designated'] { #bridges { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-width: @footway-width-z14 + 2 * @paths-background-width; [zoom >= 15] { line-width: @footway-width-z15 + 2 * @paths-background-width; } @@ -905,7 +905,7 @@ } } #tunnels { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-color: @footway-casing; line-cap: round; @@ -922,7 +922,7 @@ [feature = 'highway_cycleway'], [feature = 'highway_path'][bicycle = 'designated'] { #bridges { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-width: @cycleway-width-z13 + 2 * @paths-background-width; [zoom >= 15] { line-width: @cycleway-width-z15 + 2 * @paths-background-width; } @@ -934,7 +934,7 @@ } } #tunnels { - [zoom >= 13][access != 'no'], + [zoom >= 13][int_access != 'no'], [zoom >= 15] { line-color: @cycleway-casing; line-cap: round; @@ -950,7 +950,7 @@ [feature = 'highway_steps'] { #bridges { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-width: @steps-width-z14 + 2 * @paths-background-width; [zoom >= 15] { line-width: @steps-width-z15 + 2 * @paths-background-width; } @@ -959,7 +959,7 @@ } } #tunnels { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { line-color: @steps-casing; line-cap: round; @@ -973,7 +973,7 @@ [feature = 'highway_track'] { /* We don't set opacity here, so it's 1.0. Aside from that, it's basically a copy of roads-fill::background in the track part of ::fill */ #bridges { - [zoom >= 13][access != 'no'] { + [zoom >= 13][int_access != 'no'] { line-color: @track-casing; line-join: round; line-width: @track-width-z13 + 2 * @paths-background-width; @@ -997,7 +997,7 @@ } } #tunnels { - [zoom >= 13][access != 'no'], + [zoom >= 13][int_access != 'no'], [zoom >= 15] { line-color: @track-casing; line-join: round; @@ -2258,7 +2258,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } [feature = 'highway_steps'] { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { #roads-fill[zoom >= 15] { background/line-color: @steps-casing; @@ -2268,7 +2268,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ background/line-opacity: 0.4; } line/line-color: @steps-fill; - [access = 'no'] { line/line-color: @steps-fill-noaccess; } + [int_access = 'no'] { line/line-color: @steps-fill-noaccess; } line/line-dasharray: 2,1; line/line-width: @steps-width-z14; [zoom >= 15] { line/line-width: @steps-width-z15; } @@ -2277,7 +2277,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ [feature = 'highway_bridleway'], [feature = 'highway_path'][horse = 'designated'] { - [zoom >= 13][access != 'no'], + [zoom >= 13][int_access != 'no'], [zoom >= 15] { #roads-fill[zoom >= 15] { background/line-color: @bridleway-casing; @@ -2287,7 +2287,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ background/line-opacity: 0.4; } line/line-color: @bridleway-fill; - [access = 'no'] { line/line-color: @bridleway-fill-noaccess; } + [int_access = 'no'] { line/line-color: @bridleway-fill-noaccess; } line/line-dasharray: 4,2; line/line-width: @bridleway-width-z13; [zoom >= 15] { line/line-width: @bridleway-width-z15; } @@ -2300,7 +2300,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ [feature = 'highway_footway'], [feature = 'highway_path'][bicycle != 'designated'][horse != 'designated'] { - [zoom >= 14][access != 'no'], + [zoom >= 14][int_access != 'no'], [zoom >= 15] { #roads-fill[zoom >= 15] { background/line-color: @footway-casing; @@ -2319,7 +2319,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } } line/line-color: @footway-fill; - [access = 'no'] { line/line-color: @footway-fill-noaccess; } + [int_access = 'no'] { line/line-color: @footway-fill-noaccess; } line/line-dasharray: 1,3; line/line-join: round; line/line-cap: round; @@ -2343,7 +2343,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } [zoom >= 15][int_surface = null] { line/line-color: @footway-fill; - [access = 'no'] { line/line-color: @footway-fill-noaccess; } + [int_access = 'no'] { line/line-color: @footway-fill-noaccess; } line/line-dasharray: 1,3,2,4; line/line-join: round; line/line-cap: round; @@ -2361,7 +2361,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } [zoom >= 15][int_surface = 'unpaved'] { line/line-color: @footway-fill; - [access = 'no'] { line/line-color: @footway-fill-noaccess; } + [int_access = 'no'] { line/line-color: @footway-fill-noaccess; } line/line-dasharray: 1,4; line/line-join: round; line/line-cap: round; @@ -2381,7 +2381,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ [feature = 'highway_cycleway'], [feature = 'highway_path'][bicycle = 'designated'] { - [zoom >= 13][access != 'no'], + [zoom >= 13][int_access != 'no'], [zoom >= 15] { #roads-fill[zoom >= 15] { background/line-color: @cycleway-casing; @@ -2400,7 +2400,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } } line/line-color: @cycleway-fill; - [access = 'no'] { line/line-color: @cycleway-fill-noaccess; } + [int_access = 'no'] { line/line-color: @cycleway-fill-noaccess; } line/line-dasharray: 1,3; line/line-join: round; line/line-cap: round; @@ -2424,7 +2424,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } [zoom >= 15][int_surface = null] { line/line-color: @cycleway-fill; - [access = 'no'] { line/line-color: @cycleway-fill-noaccess; } + [int_access = 'no'] { line/line-color: @cycleway-fill-noaccess; } line/line-dasharray: 1,3,2,4; line/line-join: round; line/line-cap: round; @@ -2442,7 +2442,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } [zoom >= 15][int_surface = 'unpaved'] { line/line-color: @cycleway-fill; - [access = 'no'] { line/line-color: @cycleway-fill-noaccess; } + [int_access = 'no'] { line/line-color: @cycleway-fill-noaccess; } line/line-dasharray: 1,4; line/line-join: round; line/line-cap: round; @@ -2461,7 +2461,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } [feature = 'highway_track'] { - [zoom >= 13][access != 'no'], + [zoom >= 13][int_access != 'no'], [zoom >= 15] { /* The white casing that you mainly see against forests and other dark features */ #roads-fill[zoom >= 15] { @@ -2481,7 +2481,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ /* Set the properties of the brown inside */ line/line-color: @track-fill; - [access = 'no'] { line/line-color: @track-fill-noaccess; } + [int_access = 'no'] { line/line-color: @track-fill-noaccess; } line/line-dasharray: 5,4,2,4; line/line-cap: round; line/line-join: round; @@ -3378,7 +3378,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ #tunnels::fill, #roads-fill::fill, #bridges::fill { - [access = 'destination'] { + [int_access = 'restricted'] { [feature = 'highway_secondary'], [feature = 'highway_tertiary'], [feature = 'highway_unclassified'], @@ -3441,7 +3441,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } } } - [access = 'no'] { + [int_access = 'no'] { [feature = 'highway_motorway'], [feature = 'highway_trunk'], [feature = 'highway_primary'], From 9c8098bf0eeef2d2e10a3055a7d8a200ea2fc292 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Sat, 13 Apr 2024 09:29:55 +0100 Subject: [PATCH 02/18] Function load in CI --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb8a37cab..02cbbdf38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,8 @@ jobs: osm2pgsql -G --hstore --style openstreetmap-carto.style --tag-transform-script openstreetmap-carto.lua -d gis -r xml <(echo '') - name: Create indexes run: psql -1Xq -v ON_ERROR_STOP=1 -d gis -f indexes.sql + - name: Load functions + run: psql -1Xq -v ON_ERROR_STOP=1 -d gis -f functions.sql - name: Load empty shapefiles run: scripts/get-external-data.py --no-update --cache -D scripts/empty_files - name: Test queries are valid From a413991f6eebc1370053c809adf2bb16932bc20a Mon Sep 17 00:00:00 2001 From: dch0ph Date: Sat, 13 Apr 2024 09:37:58 +0100 Subject: [PATCH 03/18] Add carto_path_primary_path --- functions.sql | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/functions.sql b/functions.sql index e85ccc332..bee0e7634 100644 --- a/functions.sql +++ b/functions.sql @@ -23,6 +23,22 @@ SELECT END $$; +/* Try to promote path to cycleway (if bicycle allowed), then bridleway (if horse) + This duplicates existing behaviour where designated access is required */ +CREATE OR REPLACE FUNCTION carto_path_primary_mode(bicycle text, horse text) + RETURNS text + LANGUAGE SQL + IMMUTABLE PARALLEL SAFE +AS $$ +SELECT + CASE + WHEN bicycle IN ('designated') THEN 'bicycle' + WHEN horse IN ('designated') THEN 'horse' + ELSE 'foot' + END +END +$$; + /* Classify highways into access categories which will be treated in the same way Default is NULL in which case only the access tag will be used (e.g. highway=track) Note that bicycle, horse arguments are only relevant if considering highway=path */ From 911569ebf56544207f334a65986b3b8dce2fe269 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Fri, 26 Apr 2024 21:48:09 +0100 Subject: [PATCH 04/18] Moving customers, permit Following discussion moving: access=customers -> "restricted" marking access=permit -> "no" marking --- functions.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/functions.sql b/functions.sql index bee0e7634..e94f62503 100644 --- a/functions.sql +++ b/functions.sql @@ -14,10 +14,10 @@ CREATE OR REPLACE FUNCTION carto_int_access(primary_mode text, accesstag text) AS $$ SELECT CASE - WHEN accesstag IN ('yes', 'designated', 'permissive', 'customers') THEN 'yes' - WHEN accesstag IN ('destination', 'delivery', 'permit') THEN + WHEN accesstag IN ('yes', 'designated', 'permissive') THEN 'yes' + WHEN accesstag IN ('destination', 'delivery', 'customers') THEN CASE WHEN primary_mode IN ('motorcar', 'pedestrian') THEN 'restricted' ELSE 'no' END - WHEN accesstag IN ('no', 'private', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' + WHEN accesstag IN ('no', 'private', 'permit', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' ELSE NULL END END From 8f386d23802e8d62c25f477a8925f83405877b10 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Sun, 28 Apr 2024 16:41:54 +0100 Subject: [PATCH 05/18] Major changes in response to comments Functions renamed for clarity Changed logic for mode-specific tags, only ignoring 'unknown' values unknown access type return for unknown/uninterpretable path promoted to cycleway/bridleway in SQL rather than MSS --- functions.sql | 59 +++++++++++++++++++++++-------------------------- project.mml | 42 +++++------------------------------ style/roads.mss | 35 +++++++++-------------------- 3 files changed, 44 insertions(+), 92 deletions(-) diff --git a/functions.sql b/functions.sql index e94f62503..a3b880315 100644 --- a/functions.sql +++ b/functions.sql @@ -2,12 +2,12 @@ /* Access functions below adapted from https://github.com/imagico/osm-carto-alternative-colors/tree/591c861112b4e5d44badd108f4cd1409146bca0b/sql/roads.sql */ - -/* Simplified 'yes', 'restricted', 'no', NULL scale for access restriction - 'no' is returned if the rendering for highway category does not support 'destination'. +/* Simplified 'yes', 'destination', 'no', 'unknown', NULL scale for access restriction + 'no' is returned if the rendering for highway category does not support 'restricted'. NULL is functionally equivalent to 'yes', but indicates the absence of a restriction - rather than a positive access = yes */ -CREATE OR REPLACE FUNCTION carto_int_access(primary_mode text, accesstag text) + rather than a positive access = yes. 'unknown' corresponds to an uninterpretable + access restriction e.g. access=unknown or motorcar=occasionally */ +CREATE OR REPLACE FUNCTION carto_int_access(int_highway text, accesstag text) RETURNS text LANGUAGE SQL IMMUTABLE PARALLEL SAFE @@ -16,33 +16,33 @@ SELECT CASE WHEN accesstag IN ('yes', 'designated', 'permissive') THEN 'yes' WHEN accesstag IN ('destination', 'delivery', 'customers') THEN - CASE WHEN primary_mode IN ('motorcar', 'pedestrian') THEN 'restricted' ELSE 'no' END - WHEN accesstag IN ('no', 'private', 'permit', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' - ELSE NULL + CASE WHEN int_highway IN ('road', 'pedestrian') THEN 'restricted' ELSE 'no' END + WHEN accesstag IN ('no', 'permit', 'private', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' + WHEN NULL THEN NULL + ELSE 'unknown' END END $$; /* Try to promote path to cycleway (if bicycle allowed), then bridleway (if horse) This duplicates existing behaviour where designated access is required */ -CREATE OR REPLACE FUNCTION carto_path_primary_mode(bicycle text, horse text) +CREATE OR REPLACE FUNCTION carto_path_type(bicycle text, horse text) RETURNS text LANGUAGE SQL IMMUTABLE PARALLEL SAFE AS $$ SELECT CASE - WHEN bicycle IN ('designated') THEN 'bicycle' - WHEN horse IN ('designated') THEN 'horse' - ELSE 'foot' + WHEN bicycle IN ('designated') THEN 'cycleway' + WHEN horse IN ('designated') THEN 'bridleway' + ELSE 'path' END END $$; -/* Classify highways into access categories which will be treated in the same way - Default is NULL in which case only the access tag will be used (e.g. highway=track) +/* Coalesce highways that will be treated in the same way, e.g. all roads become 'road' Note that bicycle, horse arguments are only relevant if considering highway=path */ -CREATE OR REPLACE FUNCTION carto_highway_primary_mode(highway text, bicycle text, horse text) +CREATE OR REPLACE FUNCTION carto_highway_int_highway(highway text, bicycle text, horse text) RETURNS text LANGUAGE SQL IMMUTABLE PARALLEL SAFE @@ -50,13 +50,10 @@ AS $$ SELECT CASE WHEN highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link', 'primary', 'primary_link', 'secondary', - 'secondary_link', 'tertiary', 'tertiary_link', 'residential', 'unclassified', 'living_street', 'service', 'road') THEN 'motorcar' - WHEN highway = 'pedestrian' THEN 'pedestrian' - WHEN highway IN ('footway', 'steps') THEN 'foot' - WHEN highway = 'bridleway' THEN 'horse' - WHEN highway = 'cycleway' THEN 'bicycle' - WHEN highway = 'path' THEN carto_path_primary_mode(bicycle, horse) - ELSE NULL + 'secondary_link', 'tertiary', 'tertiary_link', 'residential', 'unclassified', 'living_street', 'service', 'road') THEN 'road' + WHEN highway IN ('footway', 'steps') THEN 'footway' + WHEN highway = 'path' THEN carto_path_type(bicycle, horse) + ELSE highway END END $$; @@ -69,17 +66,17 @@ CREATE OR REPLACE FUNCTION carto_highway_int_access(highway text, "access" text, IMMUTABLE PARALLEL SAFE AS $$ SELECT - CASE carto_highway_primary_mode(highway, bicycle, horse) - WHEN 'motorcar' THEN - carto_int_access('motorcar', CASE - WHEN motorcar IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN motorcar - WHEN motor_vehicle IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN motor_vehicle - WHEN vehicle IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN vehicle + CASE carto_highway_int_highway(highway, bicycle, horse) + WHEN 'road' THEN + carto_int_access('road', CASE + WHEN motorcar <> 'unknown' THEN motorcar + WHEN motor_vehicle <> 'unknown' THEN motor_vehicle + WHEN vehicle <> 'unknown' THEN vehicle ELSE "access" END) WHEN 'pedestrian' THEN carto_int_access('pedestrian', 'no') - WHEN 'foot' THEN carto_int_access('foot', CASE WHEN foot IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN foot ELSE "access" END) - WHEN 'bicycle' THEN carto_int_access('bicycle', CASE WHEN bicycle IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN bicycle ELSE "access" END) - WHEN 'horse' THEN carto_int_access('horse', CASE WHEN horse IN ('yes', 'designated', 'permissive', 'no', 'private', 'destination', 'customers', 'delivery', 'permit') THEN horse ELSE "access" END) + WHEN 'footway' THEN carto_int_access('footway', CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END) + WHEN 'cycleway' THEN carto_int_access('cycleway', CASE WHEN bicycle <> 'unknown' THEN bicycle ELSE "access" END) + WHEN 'brideway' THEN carto_int_access('bridleway', CASE WHEN horse <> 'unknown' THEN horse ELSE "access" END) ELSE carto_int_access(NULL, "access") END END diff --git a/project.mml b/project.mml index 32803027a..870ef15d1 100644 --- a/project.mml +++ b/project.mml @@ -444,9 +444,6 @@ Layer: (SELECT way, (CASE WHEN feature IN ('highway_motorway_link', 'highway_trunk_link', 'highway_primary_link', 'highway_secondary_link', 'highway_tertiary_link') THEN substr(feature, 0, length(feature)-4) ELSE feature END) AS feature, - horse, - foot, - bicycle, tracktype, int_surface, int_access, @@ -457,10 +454,7 @@ Layer: FROM ( -- subselect that contains both roads and rail SELECT way, - 'highway_' || highway AS feature, --only motorway to tertiary links are accepted later on - horse, - foot, - bicycle, + 'highway_' || (CASE WHEN highway = 'path' THEN carto_path_type(bicycle, horse) ELSE highway END) AS feature, --only motorway to tertiary links are accepted later on tracktype, CASE WHEN surface IN ('unpaved', 'compacted', 'dirt', 'earth', 'fine_gravel', 'grass', 'grass_paver', 'gravel', 'ground', 'mud', 'pebblestone', 'salt', 'sand', 'woodchips', 'clay', 'ice', 'snow') THEN 'unpaved' @@ -489,9 +483,6 @@ Layer: WHEN (railway = 'rail' AND service IN ('spur', 'siding', 'yard')) THEN 'INT-spur-siding-yard' WHEN (railway = 'tram' AND service IN ('spur', 'siding', 'yard')) THEN 'tram-service' ELSE railway END) AS feature, - horse, - foot, - bicycle, tracktype, 'null', NULL, @@ -676,9 +667,6 @@ Layer: (SELECT way, (CASE WHEN feature IN ('highway_motorway_link', 'highway_trunk_link', 'highway_primary_link', 'highway_secondary_link', 'highway_tertiary_link') THEN substr(feature, 0, length(feature)-4) ELSE feature END) AS feature, - horse, - foot, - bicycle, tracktype, int_surface, int_access, @@ -689,10 +677,7 @@ Layer: FROM ( -- subselect that contains both roads and rail/aero SELECT way, - ('highway_' || highway) AS feature, --only motorway to tertiary links are accepted later on - horse, - foot, - bicycle, + 'highway_' || (CASE WHEN highway = 'path' THEN carto_path_type(bicycle, horse) ELSE highway END) AS feature, --only motorway to tertiary links are accepted later on tracktype, CASE WHEN surface IN ('unpaved', 'compacted', 'dirt', 'earth', 'fine_gravel', 'grass', 'grass_paver', 'gravel', 'ground', 'mud', 'pebblestone', 'salt', 'sand', 'woodchips', 'clay', 'ice', 'snow') THEN 'unpaved' @@ -724,9 +709,6 @@ Layer: WHEN (railway = 'rail' AND service IN ('spur', 'siding', 'yard')) THEN 'INT-spur-siding-yard' WHEN (railway = 'tram' AND service IN ('spur', 'siding', 'yard')) THEN 'tram-service' ELSE railway END)) AS feature, - horse, - foot, - bicycle, tracktype, CASE WHEN surface IN ('unpaved', 'compacted', 'dirt', 'earth', 'fine_gravel', 'grass', 'grass_paver', 'gravel', 'ground', 'mud', 'pebblestone', 'salt', 'sand', 'woodchips', 'clay', 'ice', 'snow') THEN 'unpaved' @@ -903,9 +885,6 @@ Layer: (SELECT way, (CASE WHEN feature IN ('highway_motorway_link', 'highway_trunk_link', 'highway_primary_link', 'highway_secondary_link', 'highway_tertiary_link') THEN substr(feature, 0, length(feature)-4) ELSE feature END) AS feature, - horse, - foot, - bicycle, tracktype, int_surface, int_access, @@ -916,10 +895,7 @@ Layer: FROM ( -- subselect that contains both roads and rail/aero SELECT way, - 'highway_' || highway AS feature, --only motorway to tertiary links are accepted later on - horse, - foot, - bicycle, + 'highway_' || (CASE WHEN highway = 'path' THEN carto_path_type(bicycle, horse) ELSE highway END) AS feature, --only motorway to tertiary links are accepted later on tracktype, CASE WHEN surface IN ('unpaved', 'compacted', 'dirt', 'earth', 'fine_gravel', 'grass', 'grass_paver', 'gravel', 'ground', 'mud', 'pebblestone', 'salt', 'sand', 'woodchips', 'clay', 'ice', 'snow') THEN 'unpaved' @@ -948,9 +924,6 @@ Layer: WHEN (railway = 'rail' AND service IN ('spur', 'siding', 'yard')) THEN 'INT-spur-siding-yard' WHEN (railway = 'tram' AND service IN ('spur', 'siding', 'yard')) THEN 'tram-service' ELSE railway END) AS feature, - horse, - foot, - bicycle, tracktype, 'null', NULL, @@ -1908,8 +1881,7 @@ Layer: CASE WHEN oneway IN ('yes', '-1') THEN oneway WHEN junction IN ('roundabout') AND (oneway IS NULL OR NOT oneway IN ('no', 'reversible')) THEN 'yes' - END AS oneway, - horse, bicycle + END AS oneway FROM planet_osm_line l WHERE highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link', 'primary', 'primary_link', 'secondary', 'secondary_link', 'tertiary', 'tertiary_link', 'residential', 'unclassified', 'road', 'service', 'pedestrian', 'raceway', 'living_street', 'construction') @@ -1934,15 +1906,13 @@ Layer: table: |- (SELECT way, - highway, + CASE WHEN highway = 'path' THEN carto_path_type(bicycle, horse) ELSE highway END AS highway, construction, name, CASE WHEN oneway IN ('yes', '-1') THEN oneway WHEN junction IN ('roundabout') AND (oneway IS NULL OR NOT oneway IN ('no', 'reversible')) THEN 'yes' - END AS oneway, - horse, - bicycle + END AS oneway FROM planet_osm_line WHERE highway IN ('bridleway', 'footway', 'cycleway', 'path', 'track', 'steps', 'construction') AND (name IS NOT NULL diff --git a/style/roads.mss b/style/roads.mss index 4cbc58466..51bfb1555 100644 --- a/style/roads.mss +++ b/style/roads.mss @@ -663,8 +663,7 @@ } } - [feature = 'highway_bridleway'], - [feature = 'highway_path'][horse = 'designated'] { + [feature = 'highway_bridleway'] { #bridges { [zoom >= 14][int_access != 'no'], [zoom >= 15] { @@ -685,8 +684,7 @@ } } - [feature = 'highway_footway'], - [feature = 'highway_path'][bicycle != 'designated'][horse != 'designated'] { + [feature = 'highway_footway'] { #bridges { [zoom >= 14][int_access != 'no'], [zoom >= 15] { @@ -713,8 +711,7 @@ } } - [feature = 'highway_cycleway'], - [feature = 'highway_path'][bicycle = 'designated'] { + [feature = 'highway_cycleway'] { #bridges { [zoom >= 14][int_access != 'no'], [zoom >= 15] { @@ -867,8 +864,7 @@ } ::bridges_and_tunnels_background { - [feature = 'highway_bridleway'], - [feature = 'highway_path'][horse = 'designated'] { + [feature = 'highway_bridleway'] { #bridges { [zoom >= 14][int_access != 'no'], [zoom >= 15] { @@ -891,7 +887,7 @@ } [feature = 'highway_footway'], - [feature = 'highway_path'][bicycle != 'designated'][horse != 'designated'] { + [feature = 'highway_path'] { #bridges { [zoom >= 14][int_access != 'no'], [zoom >= 15] { @@ -919,8 +915,7 @@ } } - [feature = 'highway_cycleway'], - [feature = 'highway_path'][bicycle = 'designated'] { + [feature = 'highway_cycleway'] { #bridges { [zoom >= 14][int_access != 'no'], [zoom >= 15] { @@ -2275,8 +2270,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } } - [feature = 'highway_bridleway'], - [feature = 'highway_path'][horse = 'designated'] { + [feature = 'highway_bridleway'] { [zoom >= 13][int_access != 'no'], [zoom >= 15] { #roads-fill[zoom >= 15] { @@ -2299,7 +2293,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } [feature = 'highway_footway'], - [feature = 'highway_path'][bicycle != 'designated'][horse != 'designated'] { + [feature = 'highway_path'] { [zoom >= 14][int_access != 'no'], [zoom >= 15] { #roads-fill[zoom >= 15] { @@ -2379,8 +2373,7 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ } } - [feature = 'highway_cycleway'], - [feature = 'highway_path'][bicycle = 'designated'] { + [feature = 'highway_cycleway'] { [zoom >= 13][int_access != 'no'], [zoom >= 15] { #roads-fill[zoom >= 15] { @@ -4152,18 +4145,10 @@ tertiary is rendered from z10 and is not included in osm_planet_roads. */ text-upright: left; text-dy: -3; } + [highway = 'path'], [highway = 'footway'] { text-fill: @footway-oneway-arrow-color; } - [highway = 'path'] { - text-fill: @footway-oneway-arrow-color; - [horse = 'designated'] { - text-fill: @bridleway-oneway-arrow-color; - } - [bicycle = 'designated'] { - text-fill: @cycleway-oneway-arrow-color; - } - } [highway = 'steps'] { text-fill: @steps-oneway-arrow-color; } From e04589c9bb7ad506f99ac2a42e216c4527144e11 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Tue, 30 Apr 2024 19:12:18 +0100 Subject: [PATCH 06/18] Use foot primary mode for highway=pedestrian --- functions.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions.sql b/functions.sql index a3b880315..bd56f78b2 100644 --- a/functions.sql +++ b/functions.sql @@ -73,7 +73,7 @@ SELECT WHEN motor_vehicle <> 'unknown' THEN motor_vehicle WHEN vehicle <> 'unknown' THEN vehicle ELSE "access" END) - WHEN 'pedestrian' THEN carto_int_access('pedestrian', 'no') + WHEN 'pedestrian' THEN carto_int_access('pedestrian', CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END) WHEN 'footway' THEN carto_int_access('footway', CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END) WHEN 'cycleway' THEN carto_int_access('cycleway', CASE WHEN bicycle <> 'unknown' THEN bicycle ELSE "access" END) WHEN 'brideway' THEN carto_int_access('bridleway', CASE WHEN horse <> 'unknown' THEN horse ELSE "access" END) From a3002500f7ce6e52cb40d82d4e778b54a0a5d32f Mon Sep 17 00:00:00 2001 From: dch0ph Date: Wed, 1 May 2024 11:37:27 +0100 Subject: [PATCH 07/18] Typo fix --- functions.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions.sql b/functions.sql index bd56f78b2..ff6599e52 100644 --- a/functions.sql +++ b/functions.sql @@ -76,7 +76,7 @@ SELECT WHEN 'pedestrian' THEN carto_int_access('pedestrian', CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END) WHEN 'footway' THEN carto_int_access('footway', CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END) WHEN 'cycleway' THEN carto_int_access('cycleway', CASE WHEN bicycle <> 'unknown' THEN bicycle ELSE "access" END) - WHEN 'brideway' THEN carto_int_access('bridleway', CASE WHEN horse <> 'unknown' THEN horse ELSE "access" END) + WHEN 'bridleway' THEN carto_int_access('bridleway', CASE WHEN horse <> 'unknown' THEN horse ELSE "access" END) ELSE carto_int_access(NULL, "access") END END From 8f92b8d8c2e35027533eedc872b02dc157883499 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Wed, 1 May 2024 20:39:03 +0100 Subject: [PATCH 08/18] Remove incorrect END statements --- functions.sql | 4 ---- 1 file changed, 4 deletions(-) diff --git a/functions.sql b/functions.sql index ff6599e52..852b5c3a0 100644 --- a/functions.sql +++ b/functions.sql @@ -21,7 +21,6 @@ SELECT WHEN NULL THEN NULL ELSE 'unknown' END -END $$; /* Try to promote path to cycleway (if bicycle allowed), then bridleway (if horse) @@ -37,7 +36,6 @@ SELECT WHEN horse IN ('designated') THEN 'bridleway' ELSE 'path' END -END $$; /* Coalesce highways that will be treated in the same way, e.g. all roads become 'road' @@ -55,7 +53,6 @@ SELECT WHEN highway = 'path' THEN carto_path_type(bicycle, horse) ELSE highway END -END $$; /* Return int_access value which will be used to determine access marking. @@ -79,7 +76,6 @@ SELECT WHEN 'bridleway' THEN carto_int_access('bridleway', CASE WHEN horse <> 'unknown' THEN horse ELSE "access" END) ELSE carto_int_access(NULL, "access") END -END $$; /* Uncomment lines below to create generated column for int_access From 42a9e75a0dddf5f1540f17baecb58e0cf2ba6ec1 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Sat, 4 May 2024 12:51:06 +0100 Subject: [PATCH 09/18] Fix regression on introducing explicit unknown --- functions.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions.sql b/functions.sql index 852b5c3a0..bd2bd921f 100644 --- a/functions.sql +++ b/functions.sql @@ -18,7 +18,7 @@ SELECT WHEN accesstag IN ('destination', 'delivery', 'customers') THEN CASE WHEN int_highway IN ('road', 'pedestrian') THEN 'restricted' ELSE 'no' END WHEN accesstag IN ('no', 'permit', 'private', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' - WHEN NULL THEN NULL + WHEN accesstag IS NULL THEN NULL ELSE 'unknown' END $$; From f99920e05b8a76b8ac73aa25e3fcd0385139cbe3 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Tue, 7 May 2024 18:53:37 +0100 Subject: [PATCH 10/18] Fix regression for highway=path --- functions.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/functions.sql b/functions.sql index bd2bd921f..08df7227e 100644 --- a/functions.sql +++ b/functions.sql @@ -72,6 +72,7 @@ SELECT ELSE "access" END) WHEN 'pedestrian' THEN carto_int_access('pedestrian', CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END) WHEN 'footway' THEN carto_int_access('footway', CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END) + WHEN 'path' THEN carto_int_access('path', CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END) WHEN 'cycleway' THEN carto_int_access('cycleway', CASE WHEN bicycle <> 'unknown' THEN bicycle ELSE "access" END) WHEN 'bridleway' THEN carto_int_access('bridleway', CASE WHEN horse <> 'unknown' THEN horse ELSE "access" END) ELSE carto_int_access(NULL, "access") From cdc9ace29730978e73b1e07647d82142373e4334 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Fri, 10 May 2024 17:59:53 +0100 Subject: [PATCH 11/18] Alter 'destination' outcome for 2-state access 'destination' on path / footway etc. interpreted as 'yes' (matching current behaviour) --- functions.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions.sql b/functions.sql index 08df7227e..cf3b791cc 100644 --- a/functions.sql +++ b/functions.sql @@ -16,7 +16,7 @@ SELECT CASE WHEN accesstag IN ('yes', 'designated', 'permissive') THEN 'yes' WHEN accesstag IN ('destination', 'delivery', 'customers') THEN - CASE WHEN int_highway IN ('road', 'pedestrian') THEN 'restricted' ELSE 'no' END + CASE WHEN int_highway IN ('road', 'pedestrian') THEN 'restricted' ELSE 'yes' END WHEN accesstag IN ('no', 'permit', 'private', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' WHEN accesstag IS NULL THEN NULL ELSE 'unknown' From a1dfd944182826557e1c121ffa455c6a0a2c4ff5 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Sat, 15 Jun 2024 12:27:31 +0100 Subject: [PATCH 12/18] Simplify functions.sql Reduce number of functions Tidy comments --- functions.sql | 57 +++++++++++++++++---------------------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/functions.sql b/functions.sql index cf3b791cc..73b4e785b 100644 --- a/functions.sql +++ b/functions.sql @@ -6,8 +6,8 @@ 'no' is returned if the rendering for highway category does not support 'restricted'. NULL is functionally equivalent to 'yes', but indicates the absence of a restriction rather than a positive access = yes. 'unknown' corresponds to an uninterpretable - access restriction e.g. access=unknown or motorcar=occasionally */ -CREATE OR REPLACE FUNCTION carto_int_access(int_highway text, accesstag text) + access restriction e.g. access=unknown or motorcar=occasionally */ +CREATE OR REPLACE FUNCTION carto_int_access(accesstag text, allow_restricted boolean) RETURNS text LANGUAGE SQL IMMUTABLE PARALLEL SAFE @@ -16,7 +16,7 @@ SELECT CASE WHEN accesstag IN ('yes', 'designated', 'permissive') THEN 'yes' WHEN accesstag IN ('destination', 'delivery', 'customers') THEN - CASE WHEN int_highway IN ('road', 'pedestrian') THEN 'restricted' ELSE 'yes' END + CASE WHEN allow_restricted = TRUE THEN 'restricted' ELSE 'yes' END WHEN accesstag IN ('no', 'permit', 'private', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' WHEN accesstag IS NULL THEN NULL ELSE 'unknown' @@ -38,49 +38,30 @@ SELECT END $$; -/* Coalesce highways that will be treated in the same way, e.g. all roads become 'road' - Note that bicycle, horse arguments are only relevant if considering highway=path */ -CREATE OR REPLACE FUNCTION carto_highway_int_highway(highway text, bicycle text, horse text) - RETURNS text - LANGUAGE SQL - IMMUTABLE PARALLEL SAFE -AS $$ -SELECT - CASE - WHEN highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link', 'primary', 'primary_link', 'secondary', - 'secondary_link', 'tertiary', 'tertiary_link', 'residential', 'unclassified', 'living_street', 'service', 'road') THEN 'road' - WHEN highway IN ('footway', 'steps') THEN 'footway' - WHEN highway = 'path' THEN carto_path_type(bicycle, horse) - ELSE highway - END -$$; - -/* Return int_access value which will be used to determine access marking. - Only a restricted number of types can be returned, with NULL corresponding to no access restriction */ +/* Return int_access value which will be used to determine access marking */ CREATE OR REPLACE FUNCTION carto_highway_int_access(highway text, "access" text, foot text, bicycle text, horse text, motorcar text, motor_vehicle text, vehicle text) RETURNS text LANGUAGE SQL IMMUTABLE PARALLEL SAFE AS $$ SELECT - CASE carto_highway_int_highway(highway, bicycle, horse) - WHEN 'road' THEN - carto_int_access('road', CASE + CASE + WHEN highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link', 'primary', 'primary_link', 'secondary', + 'secondary_link', 'tertiary', 'tertiary_link', 'residential', 'unclassified', 'living_street', 'service', 'road') THEN + carto_int_access(CASE WHEN motorcar <> 'unknown' THEN motorcar WHEN motor_vehicle <> 'unknown' THEN motor_vehicle WHEN vehicle <> 'unknown' THEN vehicle - ELSE "access" END) - WHEN 'pedestrian' THEN carto_int_access('pedestrian', CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END) - WHEN 'footway' THEN carto_int_access('footway', CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END) - WHEN 'path' THEN carto_int_access('path', CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END) - WHEN 'cycleway' THEN carto_int_access('cycleway', CASE WHEN bicycle <> 'unknown' THEN bicycle ELSE "access" END) - WHEN 'bridleway' THEN carto_int_access('bridleway', CASE WHEN horse <> 'unknown' THEN horse ELSE "access" END) - ELSE carto_int_access(NULL, "access") + ELSE "access" END, TRUE) + WHEN highway = 'path' THEN + CASE carto_path_type(bicycle, horse) + WHEN 'cycleway' THEN carto_int_access(CASE WHEN bicycle <> 'unknown' THEN bicycle ELSE "access" END, FALSE) + WHEN 'bridleway' THEN carto_int_access(CASE WHEN horse <> 'unknown' THEN horse ELSE "access" END, FALSE) + ELSE carto_int_access(CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END, FALSE) + END + WHEN highway IN ('pedestrian', 'footway', 'steps') THEN carto_int_access(CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END, FALSE) + WHEN highway = 'cycleway' THEN carto_int_access(CASE WHEN bicycle <> 'unknown' THEN bicycle ELSE "access" END, FALSE) + WHEN highway = 'bridleway' THEN carto_int_access(CASE WHEN horse <> 'unknown' THEN horse ELSE "access" END, FALSE) + ELSE carto_int_access("access", TRUE) END $$; - -/* Uncomment lines below to create generated column for int_access -ALTER TABLE planet_osm_line DROP COLUMN IF EXISTS int_access; -ALTER TABLE planet_osm_line - ADD int_access text GENERATED ALWAYS AS (CASE WHEN highway IS NOT NULL THEN carto_highway_int_access(highway, "access", foot, bicycle, horse, tags->'motorcar', tags->'motor_vehicle', tags->'vehicle') ELSE NULL END) STORED; -*/ From 194d6419989240babd959a6b66754e82513d160d Mon Sep 17 00:00:00 2001 From: dch0ph Date: Sat, 22 Jun 2024 12:09:26 +0100 Subject: [PATCH 13/18] Tidy access functions Consistent formatting of CASE/WHEN Use more idiomatic COALESCE(NULLIF(...),) --- functions.sql | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/functions.sql b/functions.sql index 73b4e785b..4b744c66d 100644 --- a/functions.sql +++ b/functions.sql @@ -14,12 +14,12 @@ CREATE OR REPLACE FUNCTION carto_int_access(accesstag text, allow_restricted boo AS $$ SELECT CASE - WHEN accesstag IN ('yes', 'designated', 'permissive') THEN 'yes' - WHEN accesstag IN ('destination', 'delivery', 'customers') THEN - CASE WHEN allow_restricted = TRUE THEN 'restricted' ELSE 'yes' END - WHEN accesstag IN ('no', 'permit', 'private', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' - WHEN accesstag IS NULL THEN NULL - ELSE 'unknown' + WHEN accesstag IN ('yes', 'designated', 'permissive') THEN 'yes' + WHEN accesstag IN ('destination', 'delivery', 'customers') THEN + CASE WHEN allow_restricted = TRUE THEN 'restricted' ELSE 'yes' END + WHEN accesstag IN ('no', 'permit', 'private', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' + WHEN accesstag IS NULL THEN NULL + ELSE 'unknown' END $$; @@ -46,22 +46,23 @@ CREATE OR REPLACE FUNCTION carto_highway_int_access(highway text, "access" text, AS $$ SELECT CASE - WHEN highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link', 'primary', 'primary_link', 'secondary', - 'secondary_link', 'tertiary', 'tertiary_link', 'residential', 'unclassified', 'living_street', 'service', 'road') THEN - carto_int_access(CASE - WHEN motorcar <> 'unknown' THEN motorcar - WHEN motor_vehicle <> 'unknown' THEN motor_vehicle - WHEN vehicle <> 'unknown' THEN vehicle - ELSE "access" END, TRUE) - WHEN highway = 'path' THEN - CASE carto_path_type(bicycle, horse) - WHEN 'cycleway' THEN carto_int_access(CASE WHEN bicycle <> 'unknown' THEN bicycle ELSE "access" END, FALSE) - WHEN 'bridleway' THEN carto_int_access(CASE WHEN horse <> 'unknown' THEN horse ELSE "access" END, FALSE) - ELSE carto_int_access(CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END, FALSE) - END - WHEN highway IN ('pedestrian', 'footway', 'steps') THEN carto_int_access(CASE WHEN foot <> 'unknown' THEN foot ELSE "access" END, FALSE) - WHEN highway = 'cycleway' THEN carto_int_access(CASE WHEN bicycle <> 'unknown' THEN bicycle ELSE "access" END, FALSE) - WHEN highway = 'bridleway' THEN carto_int_access(CASE WHEN horse <> 'unknown' THEN horse ELSE "access" END, FALSE) - ELSE carto_int_access("access", TRUE) + WHEN highway IN ('motorway', 'motorway_link', 'trunk', 'trunk_link', 'primary', 'primary_link', 'secondary', + 'secondary_link', 'tertiary', 'tertiary_link', 'residential', 'unclassified', 'living_street', 'service', 'road') THEN + carto_int_access( + COALESCE( + NULLIF(motorcar, 'unknown'), + NULLIF(motor_vehicle, 'unknown'), + NULLIF(vehicle, 'unknown'), + "access"), TRUE) + WHEN highway = 'path' THEN + CASE carto_path_type(bicycle, horse) + WHEN 'cycleway' THEN carto_int_access(COALESCE(NULLIF(bicycle, 'unknown'), "access"), FALSE) + WHEN 'bridleway' THEN carto_int_access(COALESCE(NULLIF(horse, 'unknown'), "access"), FALSE) + ELSE carto_int_access(COALESCE(NULLIF(foot, 'unknown'), "access"), FALSE) + END + WHEN highway IN ('pedestrian', 'footway', 'steps') THEN carto_int_access(COALESCE(NULLIF(foot, 'unknown'), "access"), FALSE) + WHEN highway = 'cycleway' THEN carto_int_access(COALESCE(NULLIF(bicycle, 'unknown'), "access"), FALSE) + WHEN highway = 'bridleway' THEN carto_int_access(COALESCE(NULLIF(horse, 'unknown'), "access"), FALSE) + ELSE carto_int_access("access", TRUE) END $$; From c4c775cee0521cc2d53b4eefacbd38e87f3f4618 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Wed, 26 Jun 2024 18:21:07 +0100 Subject: [PATCH 14/18] Update functions.sql Change argument name accesstag -> accessvalue Improve documentation Simplify logic for promoted paths --- functions.sql | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/functions.sql b/functions.sql index 4b744c66d..95c7c8b45 100644 --- a/functions.sql +++ b/functions.sql @@ -7,18 +7,18 @@ NULL is functionally equivalent to 'yes', but indicates the absence of a restriction rather than a positive access = yes. 'unknown' corresponds to an uninterpretable access restriction e.g. access=unknown or motorcar=occasionally */ -CREATE OR REPLACE FUNCTION carto_int_access(accesstag text, allow_restricted boolean) +CREATE OR REPLACE FUNCTION carto_int_access(accessvalue text, allow_restricted boolean) RETURNS text LANGUAGE SQL IMMUTABLE PARALLEL SAFE AS $$ SELECT CASE - WHEN accesstag IN ('yes', 'designated', 'permissive') THEN 'yes' - WHEN accesstag IN ('destination', 'delivery', 'customers') THEN + WHEN accessvalue IN ('yes', 'designated', 'permissive') THEN 'yes' + WHEN accessvalue IN ('destination', 'delivery', 'customers') THEN CASE WHEN allow_restricted = TRUE THEN 'restricted' ELSE 'yes' END - WHEN accesstag IN ('no', 'permit', 'private', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' - WHEN accesstag IS NULL THEN NULL + WHEN accessvalue IN ('no', 'permit', 'private', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' + WHEN accessvalue IS NULL THEN NULL ELSE 'unknown' END $$; @@ -38,7 +38,8 @@ SELECT END $$; -/* Return int_access value which will be used to determine access marking */ +/* Return int_access value which will be used to determine access marking. + Return values are documented above for carto_int_access function */ CREATE OR REPLACE FUNCTION carto_highway_int_access(highway text, "access" text, foot text, bicycle text, horse text, motorcar text, motor_vehicle text, vehicle text) RETURNS text LANGUAGE SQL @@ -56,8 +57,8 @@ SELECT "access"), TRUE) WHEN highway = 'path' THEN CASE carto_path_type(bicycle, horse) - WHEN 'cycleway' THEN carto_int_access(COALESCE(NULLIF(bicycle, 'unknown'), "access"), FALSE) - WHEN 'bridleway' THEN carto_int_access(COALESCE(NULLIF(horse, 'unknown'), "access"), FALSE) + WHEN 'cycleway' THEN carto_int_access(bicycle, FALSE) + WHEN 'bridleway' THEN carto_int_access(horse, FALSE) ELSE carto_int_access(COALESCE(NULLIF(foot, 'unknown'), "access"), FALSE) END WHEN highway IN ('pedestrian', 'footway', 'steps') THEN carto_int_access(COALESCE(NULLIF(foot, 'unknown'), "access"), FALSE) From 15c75d6ef4ae75ffa661d8785be35a76d91d645a Mon Sep 17 00:00:00 2001 From: dch0ph Date: Wed, 26 Jun 2024 18:24:27 +0100 Subject: [PATCH 15/18] Remove obsolete comment from MML --- project.mml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/project.mml b/project.mml index b2e58ae26..22f22b89d 100644 --- a/project.mml +++ b/project.mml @@ -455,7 +455,7 @@ Layer: FROM ( -- subselect that contains both roads and rail SELECT way, - 'highway_' || (CASE WHEN highway = 'path' THEN carto_path_type(bicycle, horse) ELSE highway END) AS feature, --only motorway to tertiary links are accepted later on + 'highway_' || (CASE WHEN highway = 'path' THEN carto_path_type(bicycle, horse) ELSE highway END) AS feature, tracktype, CASE WHEN surface IN ('unpaved', 'compacted', 'dirt', 'earth', 'fine_gravel', 'grass', 'grass_paver', 'gravel', 'ground', 'mud', 'pebblestone', 'salt', 'sand', 'woodchips', 'clay', 'ice', 'snow') THEN 'unpaved' @@ -684,7 +684,7 @@ Layer: FROM ( -- subselect that contains both roads and rail/aero SELECT way, - 'highway_' || (CASE WHEN highway = 'path' THEN carto_path_type(bicycle, horse) ELSE highway END) AS feature, --only motorway to tertiary links are accepted later on + 'highway_' || (CASE WHEN highway = 'path' THEN carto_path_type(bicycle, horse) ELSE highway END) AS feature, tracktype, CASE WHEN surface IN ('unpaved', 'compacted', 'dirt', 'earth', 'fine_gravel', 'grass', 'grass_paver', 'gravel', 'ground', 'mud', 'pebblestone', 'salt', 'sand', 'woodchips', 'clay', 'ice', 'snow') THEN 'unpaved' @@ -908,7 +908,7 @@ Layer: FROM ( -- subselect that contains both roads and rail/aero SELECT way, - 'highway_' || (CASE WHEN highway = 'path' THEN carto_path_type(bicycle, horse) ELSE highway END) AS feature, --only motorway to tertiary links are accepted later on + 'highway_' || (CASE WHEN highway = 'path' THEN carto_path_type(bicycle, horse) ELSE highway END) AS feature, tracktype, CASE WHEN surface IN ('unpaved', 'compacted', 'dirt', 'earth', 'fine_gravel', 'grass', 'grass_paver', 'gravel', 'ground', 'mud', 'pebblestone', 'salt', 'sand', 'woodchips', 'clay', 'ice', 'snow') THEN 'unpaved' From 1d369dced2e982559722a8f07acb2ae0cc556749 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Fri, 9 Aug 2024 18:22:16 +0100 Subject: [PATCH 16/18] Avoid unknown overload Return "unrecognised" rather than "unknown" if access restriction is not one of recognised values --- functions.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/functions.sql b/functions.sql index 95c7c8b45..f2974cdda 100644 --- a/functions.sql +++ b/functions.sql @@ -2,10 +2,10 @@ /* Access functions below adapted from https://github.com/imagico/osm-carto-alternative-colors/tree/591c861112b4e5d44badd108f4cd1409146bca0b/sql/roads.sql */ -/* Simplified 'yes', 'destination', 'no', 'unknown', NULL scale for access restriction +/* Simplified 'yes', 'destination', 'no', 'unrecognised', NULL scale for access restriction 'no' is returned if the rendering for highway category does not support 'restricted'. NULL is functionally equivalent to 'yes', but indicates the absence of a restriction - rather than a positive access = yes. 'unknown' corresponds to an uninterpretable + rather than a positive access = yes. 'unrecognised' corresponds to an uninterpretable access restriction e.g. access=unknown or motorcar=occasionally */ CREATE OR REPLACE FUNCTION carto_int_access(accessvalue text, allow_restricted boolean) RETURNS text @@ -19,7 +19,7 @@ SELECT CASE WHEN allow_restricted = TRUE THEN 'restricted' ELSE 'yes' END WHEN accessvalue IN ('no', 'permit', 'private', 'agricultural', 'forestry', 'agricultural;forestry') THEN 'no' WHEN accessvalue IS NULL THEN NULL - ELSE 'unknown' + ELSE 'unrecognised' END $$; From b1f77c2e96cf2f82184f2fbd9da6d64120807399 Mon Sep 17 00:00:00 2001 From: dch0ph Date: Thu, 15 Aug 2024 20:20:53 +0100 Subject: [PATCH 17/18] Extend code comments Note on short-circuiting logic in carto_highway_int_access --- functions.sql | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/functions.sql b/functions.sql index f2974cdda..8b0d62176 100644 --- a/functions.sql +++ b/functions.sql @@ -39,7 +39,12 @@ SELECT $$; /* Return int_access value which will be used to determine access marking. - Return values are documented above for carto_int_access function */ + Return values are documented above for carto_int_access function. + + Note that the code handling the promotion of highway=path assumes that + promotion to cycleway or bridleway is based on the value of bicycle or + horse respectively. A more general formulation would be, for example, + WHEN 'cycleway' THEN carto_int_access(COALESCE(NULLIF(bicycle, 'unknown'), "access"), FALSE) */ CREATE OR REPLACE FUNCTION carto_highway_int_access(highway text, "access" text, foot text, bicycle text, horse text, motorcar text, motor_vehicle text, vehicle text) RETURNS text LANGUAGE SQL From af8400aff570ea956362d73b32b4b2a60f80758e Mon Sep 17 00:00:00 2001 From: dch0ph Date: Sun, 13 Oct 2024 20:20:48 +0100 Subject: [PATCH 18/18] Fix broken bridge on path Bridge not being rendered on highway=path --- style/roads.mss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/style/roads.mss b/style/roads.mss index 99ee75729..84da2dba0 100644 --- a/style/roads.mss +++ b/style/roads.mss @@ -684,7 +684,8 @@ } } - [feature = 'highway_footway'] { + [feature = 'highway_footway'], + [feature = 'highway_path'] { #bridges { [zoom >= 14][int_access != 'no'], [zoom >= 15] {