diff --git a/.gitignore b/.gitignore index 08797d41..058552a3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ data/ standard.xml maxspeed.xml signals.xml +electrification.xml *.mapcss *.d diff --git a/electrification.mml b/electrification.mml new file mode 100644 index 00000000..92015eab --- /dev/null +++ b/electrification.mml @@ -0,0 +1,382 @@ +scale: 1 +metatile: 2 +name: OpenRailwayMap Electrification +description: A map style for railway electrification +bounds: &world + - -180 + - -85.05112877980659 + - 180 + - 85.05112877980659 +center: + - 0 + - 0 + - 4 +format: png +interactivity: false +minzoom: 0 +maxzoom: 22 +srs: "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over" + +# Various parts to be included later on +_parts: + # Extents are used for tilemill, and don't actually make it to the generated XML + extents: &extents + extent: *world + srs-name: "900913" + srs: "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over" + extents84: &extents84 + extent: *world + srs-name: "WGS84" + srs: "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" + osm2pgsql: &osm2pgsql + type: "postgis" + dbname: "gis" + key_field: "" + geometry_field: "way" + extent: "-20037508,-20037508,20037508,20037508" + +Stylesheet: + - fonts.mss + - electrification_signals.mss + - electrification.mss + - common.mss + +Layer: + - id: railway_line_casing + geometry: line + <<: *extents + Datasource: + <<: *osm2pgsql + table: |- + (SELECT + way, railway, usage, service, + construction, + construction_railway, + CASE WHEN railway = 'rail' AND usage IN ('tourism', 'military', 'test') AND service IS NULL THEN 400 + WHEN railway = 'rail' AND usage IS NULL AND service IS NULL THEN 400 + WHEN railway = 'rail' AND usage IS NULL AND service = 'siding' THEN 870 + WHEN railway = 'rail' AND usage IS NULL AND service = 'yard' THEN 860 + WHEN railway = 'rail' AND usage IS NULL AND service = 'spur' THEN 880 + WHEN railway = 'rail' AND usage IS NULL AND service = 'crossover' THEN 300 + WHEN railway = 'rail' AND usage = 'main' AND service IS NULL THEN 1100 + WHEN railway = 'rail' AND usage = 'branch' AND service IS NULL THEN 1000 + WHEN railway = 'rail' AND usage = 'industrial' AND service IS NULL THEN 850 + WHEN railway = 'rail' AND usage = 'industrial' AND service IN ('siding', 'spur', 'yard', 'crossover') THEN 850 + WHEN railway IN ('preserved', 'construction') THEN 400 + ELSE 50 + END AS rank, + electrified, + frequency, + voltage, + construction_electrified, + construction_frequency, + proposed_electrified, + proposed_frequency, + railway_no_to_null(deelectrified) + FROM + (SELECT + way, railway, usage, service, + construction, + tags->'construction:railway' AS construction_railway, + electrified, + frequency, + voltage, + construction_electrified, + construction_frequency, + proposed_electrified, + proposed_frequency, + deelectrified, + layer + FROM openrailwaymap_osm_line + WHERE railway IN ('rail', 'tram', 'light_rail', 'subway', 'narrow_gauge', 'construction') + ) AS r + ORDER by layer, rank NULLS LAST + ) AS railway_line_casing + properties: + minzoom: 9 + - id: railway_line_low + geometry: line + <<: *extents + Datasource: + <<: *osm2pgsql + table: |- + (SELECT + way, railway, usage, + NULL AS service, + NULL AS construction, + NULL AS construction_railway, + NULL AS construction_usage, NULL AS construction_service, + NULL AS preserved_railway, NULL AS preserved_service, + NULL AS preserved_usage, + electrification_state AS state, + electrification_state_without_future AS state_now, + railway_voltage_for_state(electrification_state, voltage, construction_voltage, proposed_voltage) AS merged_voltage, + railway_frequency_for_state(electrification_state, frequency, construction_frequency, proposed_frequency) AS merged_frequency, + railway_to_int(voltage) AS voltage, + railway_to_float(frequency) AS frequency + FROM + (SELECT + way, railway, usage, + railway_electrification_state(railway, electrified, deelectrified, abandoned_electrified, construction_electrified, proposed_electrified, FALSE) AS electrification_state, + railway_electrification_state(railway, electrified, deelectrified, abandoned_electrified, NULL, NULL, TRUE) AS electrification_state_without_future, + frequency AS frequency, + voltage AS voltage, + construction_frequency AS construction_frequency, + construction_voltage AS construction_voltage, + proposed_frequency AS proposed_frequency, + proposed_voltage AS proposed_voltage, + layer + FROM openrailwaymap_osm_line + WHERE railway = 'rail' AND usage = 'main' AND service IS NULL + ) AS r + ORDER BY layer NULLS LAST + ) AS openrailwaymap_line_low + properties: + maxzoom: 7 + - id: railway_line_med + geometry: line + <<: *extents + Datasource: + <<: *osm2pgsql + table: |- + (SELECT + way, railway, usage, + NULL AS service, + NULL AS construction, + NULL AS construction_railway, + NULL AS construction_usage, NULL AS construction_service, + NULL AS preserved_railway, NULL AS preserved_service, + NULL AS preserved_usage, + CASE WHEN railway = 'rail' AND usage = 'main' THEN 1100 + WHEN railway = 'rail' AND usage = 'branch' THEN 1000 + ELSE 50 + END AS rank, + electrification_state AS state, + electrification_state_without_future AS state_now, + railway_voltage_for_state(electrification_state, voltage, construction_voltage, proposed_voltage) AS merged_voltage, + railway_frequency_for_state(electrification_state, frequency, construction_frequency, proposed_frequency) AS merged_frequency, + railway_to_int(voltage) AS voltage, + railway_to_float(frequency) AS frequency + FROM + (SELECT + way, railway, usage, + railway_electrification_state(railway, electrified, deelectrified, abandoned_electrified, construction_electrified, proposed_electrified, FALSE) AS electrification_state, + railway_electrification_state(railway, electrified, deelectrified, abandoned_electrified, NULL, NULL, TRUE) AS electrification_state_without_future, + frequency AS frequency, + voltage AS voltage, + construction_frequency AS construction_frequency, + construction_voltage AS construction_voltage, + proposed_frequency AS proposed_frequency, + proposed_voltage AS proposed_voltage, + layer + FROM openrailwaymap_osm_line + WHERE railway = 'rail' AND usage IN ('main', 'branch') AND service IS NULL + ) AS r + ORDER BY + layer, + rank NULLS LAST + ) AS railway_line_med + properties: + minzoom: 8 + maxzoom: 8 + - id: railway_line_fill + geometry: line + <<: *extents + Datasource: + <<: *osm2pgsql + table: |- + (SELECT + way, railway, usage, service, + construction, + construction_railway, + construction_usage, construction_service, + preserved_railway, preserved_service, + preserved_usage, + CASE WHEN railway = 'rail' AND usage IN ('tourism', 'military', 'test') AND service IS NULL THEN 400 + WHEN railway = 'rail' AND usage IS NULL AND service IS NULL THEN 400 + WHEN railway = 'rail' AND usage IS NULL AND service = 'siding' THEN 870 + WHEN railway = 'rail' AND usage IS NULL AND service = 'yard' THEN 860 + WHEN railway = 'rail' AND usage IS NULL AND service = 'spur' THEN 880 + WHEN railway = 'rail' AND usage IS NULL AND service = 'crossover' THEN 300 + WHEN railway = 'rail' AND usage = 'main' AND service IS NULL THEN 1100 + WHEN railway = 'rail' AND usage = 'branch' AND service IS NULL THEN 1000 + WHEN railway = 'rail' AND usage = 'industrial' AND service IS NULL THEN 850 + WHEN railway = 'rail' AND usage = 'industrial' AND service IN ('siding', 'spur', 'yard', 'crossover') THEN 850 + WHEN railway IN ('preserved', 'construction') THEN 400 + ELSE 50 + END AS rank, + electrification_state_without_future AS state, + railway_voltage_for_state(electrification_state_without_future, voltage, construction_voltage, proposed_voltage) AS voltage, + railway_frequency_for_state(electrification_state_without_future, frequency, construction_frequency, proposed_frequency) AS frequency + FROM + (SELECT + way, railway, usage, service, + construction, + tags->'construction:railway' AS construction_railway, + tags->'construction:usage' AS construction_usage, tags->'construction:service' AS construction_service, + tags->'preserved:railway' AS preserved_railway, tags->'preserved:service' AS preserved_service, + tags->'preserved:usage' AS preserved_usage, + railway_electrification_state(railway, electrified, deelectrified, abandoned_electrified, construction_electrified, proposed_electrified, FALSE) AS electrification_state, + railway_electrification_state(railway, electrified, deelectrified, abandoned_electrified, NULL, NULL, TRUE) AS electrification_state_without_future, + frequency AS frequency, + voltage AS voltage, + construction_frequency AS construction_frequency, + construction_voltage AS construction_voltage, + proposed_frequency AS proposed_frequency, + proposed_voltage AS proposed_voltage, + layer + FROM openrailwaymap_osm_line + WHERE railway IN ('rail', 'tram', 'light_rail', 'subway', 'narrow_gauge', 'construction', 'preserved') + ) AS r + ORDER BY + layer, + rank NULLS LAST + ) AS railway_line_fill + properties: + minzoom: 9 +# electrification_future renders with almost the same styling on top of the line fill and thereby adds dashing. + - id: electrification_future + geometry: line + <<: *extents + Datasource: + <<: *osm2pgsql + table: |- + (SELECT + way, railway, usage, service, + construction, + construction_railway, + construction_usage, construction_service, + preserved_railway, preserved_service, + preserved_usage, + CASE WHEN railway = 'rail' AND usage IN ('tourism', 'military', 'test') AND service IS NULL THEN 400 + WHEN railway = 'rail' AND usage IS NULL AND service IS NULL THEN 400 + WHEN railway = 'rail' AND usage IS NULL AND service = 'siding' THEN 870 + WHEN railway = 'rail' AND usage IS NULL AND service = 'yard' THEN 860 + WHEN railway = 'rail' AND usage IS NULL AND service = 'spur' THEN 880 + WHEN railway = 'rail' AND usage IS NULL AND service = 'crossover' THEN 300 + WHEN railway = 'rail' AND usage = 'main' AND service IS NULL THEN 1100 + WHEN railway = 'rail' AND usage = 'branch' AND service IS NULL THEN 1000 + WHEN railway = 'rail' AND usage = 'industrial' AND service IS NULL THEN 850 + WHEN railway = 'rail' AND usage = 'industrial' AND service IN ('siding', 'spur', 'yard', 'crossover') THEN 850 + WHEN railway IN ('preserved', 'construction') THEN 400 + ELSE 50 + END AS rank, + electrification_state AS state, + railway_voltage_for_state(electrification_state, voltage, construction_voltage, proposed_voltage) AS voltage, + railway_frequency_for_state(electrification_state, frequency, construction_frequency, proposed_frequency) AS frequency + FROM + (SELECT + way, railway, usage, service, + construction, + tags->'construction:railway' AS construction_railway, + tags->'construction:usage' AS construction_usage, tags->'construction:service' AS construction_service, + tags->'preserved:railway' AS preserved_railway, tags->'preserved:service' AS preserved_service, + tags->'preserved:usage' AS preserved_usage, + railway_electrification_state(railway, electrified, deelectrified, abandoned_electrified, construction_electrified, proposed_electrified, FALSE) AS electrification_state, + frequency AS frequency, + voltage AS voltage, + construction_frequency AS construction_frequency, + construction_voltage AS construction_voltage, + proposed_frequency AS proposed_frequency, + proposed_voltage AS proposed_voltage, + layer + FROM openrailwaymap_osm_line + WHERE railway IN ('rail', 'tram', 'light_rail', 'subway', 'narrow_gauge', 'construction', 'preserved') + ) AS r + ORDER BY + layer, + rank NULLS LAST + ) AS electrification_future + properties: + minzoom: 9 + - id: electrification-signals + geometry: point + <<: *extents + Datasource: + <<: *osm2pgsql + table: |- + (SELECT + way, + railway, + tags->'railway:signal:electricity' AS signal_electricity, + tags->'railway:signal:electricity:form' AS electricity_form, + tags->'railway:signal:electricity:turn_direction' AS electricity_turn_direction, + tags->'railway:signal:electricity:type' AS electricity_type, + signal_direction + FROM openrailwaymap_osm_signals + WHERE + railway = 'signal' + AND tags ? 'railway:signal:electricity' + ) AS railway_signals + properties: + minzoom: 15 + - id: railway_text_med + geometry: line + <<: *extents + Datasource: + <<: *osm2pgsql + table: |- + (SELECT + way, railway, usage, service, + construction, + tags->'construction:railway' AS construction_railway, + CASE WHEN railway = 'rail' AND usage = 'main' THEN 1100 + WHEN railway = 'rail' AND usage = 'branch' THEN 1000 + ELSE 50 + END AS rank, + layer, + railway_electrification_label(electrified, deelectrified, construction_electrified, proposed_electrified, voltage, frequency, construction_voltage, construction_frequency, proposed_voltage, proposed_frequency) AS label, + railway_electrification_state(railway, electrified, deelectrified, abandoned_electrified, construction_electrified, proposed_electrified, FALSE) AS state + FROM openrailwaymap_osm_line + WHERE + railway = 'rail' AND usage IN ('main', 'branch') AND service IS NULL + AND ( + electrified IS NOT NULL + OR deelectrified IS NOT NULL + OR construction_electrified IS NOT NULL + OR proposed_electrified IS NOT NULL + ) + ORDER by layer, rank NULLS LAST + ) AS railway_text_high + properties: + minzoom: 8 + maxzoom: 8 + - id: railway_text_high + geometry: line + <<: *extents + Datasource: + <<: *osm2pgsql + table: |- + (SELECT + way, railway, usage, service, + construction, + tags->'construction:railway' AS construction_railway, + CASE WHEN railway = 'rail' AND usage IN ('usage', 'military', 'test') AND service IS NULL THEN 400 + WHEN railway = 'rail' AND usage IS NULL AND service IS NULL THEN 400 + WHEN railway = 'rail' AND usage IS NULL AND service = 'siding' THEN 870 + WHEN railway = 'rail' AND usage IS NULL AND service = 'yard' THEN 860 + WHEN railway = 'rail' AND usage IS NULL AND service = 'spur' THEN 880 + WHEN railway = 'rail' AND usage IS NULL AND service = 'crossover' THEN 300 + WHEN railway = 'rail' AND usage = 'main' AND service IS NULL THEN 1100 + WHEN railway = 'rail' AND usage = 'branch' AND service IS NULL THEN 1000 + WHEN railway = 'rail' AND usage = 'industrial' AND service IS NULL THEN 850 + WHEN railway = 'rail' AND usage = 'industrial' AND service IN ('siding', 'spur', 'yard', 'crossover') THEN 850 + WHEN railway IN ('preserved', 'construction') THEN 400 + ELSE 50 + END AS rank, + layer, + railway_electrification_label(electrified, deelectrified, construction_electrified, proposed_electrified, voltage, frequency, construction_voltage, construction_frequency, proposed_voltage, proposed_frequency) AS label, + railway_electrification_state(railway, electrified, deelectrified, abandoned_electrified, construction_electrified, proposed_electrified, FALSE) AS state + FROM openrailwaymap_osm_line + WHERE + railway IN ('rail', 'tram', 'light_rail', 'subway', 'narrow_gauge', 'construction', 'preserved') + AND ( + electrified IS NOT NULL + OR deelectrified IS NOT NULL + OR construction_electrified IS NOT NULL + OR proposed_electrified IS NOT NULL + ) + ORDER by layer, rank NULLS LAST + ) AS railway_text_high + properties: + minzoom: 9 diff --git a/electrification.mss b/electrification.mss new file mode 100644 index 00000000..5325126a --- /dev/null +++ b/electrification.mss @@ -0,0 +1,279 @@ +@text-halo-color: white; +@text-halo-radius: 1; + +@construction-dashes: 5,5; +@proposed-dashes: 4,8; + +@color_no: black; +@color_delectrified: #70584D; +@color_lt750v_dc: #FF79B8; +@color_750v_dc: #F930FF; +@color_gt750v_lt1kv_dc: #D033FF; +@color_1kv_dc: #5C1CCB; +@color_gt1kv_lt1500v_dc: #007ACB; +@color_1500v_dc: #0098CB; +@color_gt1500v_lt3kv_dc: #00B7CB; +@color_3kv_dc: #0000FF; +@color_lt15kv_ac: #97FF2F; +@color_gte15kv_lt25kv_ac: #F1F100; +@color_15kv_1667hz: #00FF00; +@color_15kv_167hz: #00CB66; +@color_gt25kv_ac: #FF9F19; +@color_25kv_50: #FF0000; +@color_25kv_60: #C00000; + +/** + * Railway tracks with electrification under construction or proposed electrification + * are rendered with a second symbolizer called proposed_construction. + * It adds dashed lines on top of existing lines (e.g. black for electrified=no). + * + * Common rules in common.mss are defined for the ::fill and ::casing symbolizers only. + * Therefore, the rules from common.mss for ::fill need to be repeated here. + */ +#electrification_future[zoom>=9] { + ["railway"="rail"] { + ["usage"="main"]["service"=null] { + line-color: @railway_fill_color; + line-width: 1.5; + + [zoom>=6][zoom<=8] { + line-width: 2.5; + } + + [zoom>=9] { + line-width: 3.5; + } + } + + [zoom>=8]["usage"="branch"]["service"=null] { + line-color: @railway_fill_color; + line-width: 2.5; + + [zoom>=9] { + line-width: 3.5; + } + } + + [zoom=10]["usage"="industrial"]["service"=null], + [zoom>=11]["usage"="industrial"] { + line-color: @railway_fill_color; + line-width: 2; + + ["service"!=null] { + line-width: 1.5; + } + } + + [zoom>=13]["usage"=null]["service"=null], + [zoom>=11]["usage"=null]["service"="siding"], + [zoom>=11]["usage"=null]["service"="crossover"] { + line-color: @railway_fill_color; + line-width: 2; + } + + [zoom>=12]["usage"=null]["service"="yard"], + [zoom>=11]["usage"=null]["service"="spur"] { + line-color: @railway_fill_color; + line-width: 1.5; + } + } + + ["railway"="narrow_gauge"] { + [zoom>=10]["service"=null], + [zoom>=11]["service"="spur"], + [zoom>=11]["service"="siding"], + [zoom>=11]["service"="crossover"], + [zoom>=12]["service"="yard"] { + line-width: 3; + line-color: @railway_fill_color; + + ["usage"="industrial"], + ["service"="spur"], + ["service"!=null] { + line-width: 2; + } + } + } + + [zoom>=9] ["railway"="construction"]["construction_railway"="rail"]["usage"="main"]["service"=null], + [zoom>=9] ["railway"="construction"]["construction_railway"="rail"]["usage"="branch"]["service"=null], + [zoom>=10]["railway"="construction"]["construction_railway"="subway"]["service"=null], + [zoom>=10]["railway"="construction"]["construction_railway"="light_rail"]["service"=null], + [zoom>=11]["railway"="construction"]["construction_railway"="tram"]["service"=null], + [zoom>=13]["railway"="construction"], + [zoom>=10]["railway"="subway"]["service"=null], + [zoom>=13]["railway"="subway"], + [zoom>=10]["railway"="light_rail"]["service"=null], + [zoom>=13]["railway"="light_rail"], + [zoom>=11]["railway"="tram"]["service"=null], + [zoom>=13]["railway"="tram"] { + line-color: @railway_fill_color; + line-width: 3; + + [service!=null] { + line-width: 1.5; + } + } +} + +#electrification_future, +#railway_line_fill[zoom>=9]::fill, +#railway_line_low[zoom<=7]::fill, +#railway_line_med[zoom=8]::fill { + ["railway"="rail"]["usage"="main"]["service"=null], + [zoom>=8]["railway"="rail"]["usage"="branch"]["service"=null], + [zoom=10]["railway"="rail"]["usage"="industrial"]["service"=null], + [zoom>=13]["railway"="rail"]["usage"=null]["service"=null], + [zoom>=11]["railway"="rail"]["usage"="industrial"], + [zoom>=11]["railway"="rail"]["usage"=null]["service"="siding"], + [zoom>=11]["railway"="rail"]["usage"=null]["service"="crossover"], + [zoom>=12]["railway"="rail"]["usage"=null]["service"="yard"], + [zoom>=11]["railway"="rail"]["usage"=null]["service"="spur"], + [zoom>=10]["railway"="narrow_gauge"]["service"=null], + [zoom>=11]["railway"="narrow_gauge"]["service"="spur"], + [zoom>=11]["railway"="narrow_gauge"]["service"="siding"], + [zoom>=11]["railway"="narrow_gauge"]["service"="crossover"], + [zoom>=12]["railway"="narrow_gauge"]["service"="yard"], + /* service!=null is required to get a smaller Mapnik XML style with the Carto compiler. */ + [zoom>=9]["railway"="construction"]["construction_railway"="rail"]["usage"="main"]["service"=null], + [zoom>=9]["railway"="construction"]["construction_railway"="rail"]["usage"="branch"]["service"=null], + [zoom>=10]["railway"="construction"]["construction_railway"="subway"]["service"=null], + [zoom>=10]["railway"="construction"]["construction_railway"="light_rail"]["service"=null], + [zoom>=11]["railway"="construction"]["construction_railway"="tram"]["service"=null], + [zoom>=13]["railway"="construction"], + [zoom>=10]["railway"="subway"]["service"=null], + [zoom>=13]["railway"="subway"]["service"!=null], + [zoom>=10]["railway"="light_rail"]["service"=null], + [zoom>=13]["railway"="light_rail"]["service"!=null], + [zoom>=11]["railway"="tram"]["service"=null], + [zoom>=13]["railway"="tram"]["service"!=null] { + + ["state"="no"], + ["state"="proposed"][zoom < 9], + ["state"="construction"][zoom < 9] { + line-color: black; + } + + ["state"="deelectrified"], + ["state"="abandoned"] { + line-color: #70584D; + } + + #electrification_future { + ["state"="construction"] { + line-dasharray: @construction-dashes; + } + + ["state"="proposed"] { + line-dasharray: @proposed-dashes; + } + } + + [frequency=0]["voltage"<750] { + line-color: #FF79B8; + } + + [frequency=0]["voltage"=750] { + line-color: #F930FF; + } + + [frequency=0][voltage>750][voltage<1000] { + line-color: #D033FF; + } + + [frequency=0]["voltage"=1000] { + line-color: #5C1CCB; + } + + [frequency=0][voltage>1000][voltage<1500] { + line-color: #007ACB; + } + + [frequency=0]["voltage"=1500] { + line-color: #0098CB; + } + + [frequency=0][voltage>1500][voltage<3000] { + line-color: #00B7CB; + } + + [frequency=0]["voltage"=3000] { + line-color: #0000FF; + } + + [frequency=0][voltage>3000] { + line-color: #1969FF; + } + + [frequency!=null]["frequency"!=0][voltage<15000] { + line-color: #97FF2F; + } + + [frequency=null][frequency!=0][voltage>=15000][voltage<25000] { + line-color: #F1F100; + } + + [frequency=16.67][voltage=15000] { + line-color: #00FF00; + } + + [frequency=16.7][voltage=15000] { + line-color: #00CB66; + } + + [frequency=null][frequency!=0][voltage>=25000] { + line-color: #FF9F19; + } + + [frequency=50]["voltage"=25000] { + line-color: #FF0000; + } + + [frequency=60]["voltage"=25000] { + line-color: #C00000; + } + } +} + +#railway_text_med[zoom=8], +#railway_text_high[zoom>=9] { + ["railway"="rail"]["usage"="main"]["service"=null], + ["railway"="rail"]["usage"="branch"]["service"=null], + [zoom=10]["railway"="rail"]["usage"="industrial"]["service"=null], + [zoom>=13]["railway"="rail"]["usage"=null]["service"=null], + [zoom>=11]["railway"="rail"]["usage"="industrial"], + [zoom>=11]["railway"="rail"]["usage"=null]["service"="siding"], + [zoom>=11]["railway"="rail"]["usage"=null]["service"="crossover"], + [zoom>=12]["railway"="rail"]["usage"=null]["service"="yard"], + [zoom>=11]["railway"="rail"]["usage"=null]["service"="spur"], + [zoom>=11]["railway"="narrow_gauge"]["service"=null], + [zoom>=11]["railway"="narrow_gauge"]["service"="spur"], + [zoom>=11]["railway"="narrow_gauge"]["service"="siding"], + [zoom>=11]["railway"="narrow_gauge"]["service"="crossover"], + [zoom>=12]["railway"="narrow_gauge"]["service"="yard"], + /* service!=null is required to get a smaller Mapnik XML style with the Carto compiler. */ + [zoom>=11]["railway"="construction"]["construction_railway"="rail"]["usage"="main"]["service"=null], + [zoom>=11]["railway"="construction"]["construction_railway"="rail"]["usage"="branch"]["service"=null], + [zoom>=12]["railway"="construction"]["construction_railway"="subway"]["service"=null], + [zoom>=12]["railway"="construction"]["construction_railway"="light_rail"]["service"=null], + [zoom>=13]["railway"="construction"]["construction_railway"="tram"]["service"=null], + [zoom>=13]["railway"="construction"], + [zoom>=12]["railway"="subway"]["service"=null], + [zoom>=13]["railway"="subway"]["service"!=null], + [zoom>=12]["railway"="light_rail"]["service"=null], + [zoom>=13]["railway"="light_rail"]["service"!=null], + [zoom>=13]["railway"="tram"]["service"=null], + [zoom>=13]["railway"="tram"]["service"!=null] { + text-name: [label]; + text-face-name: @bold-fonts; + text-size: 11; + text-placement: line; + text-spacing: 100; + text-min-distance: 30; + text-halo-radius: @text-halo-radius; + text-halo-fill: @text-halo-color; + ["state"!="present"] { + text-face-name: @oblique-fonts; + } + } +} diff --git a/electrification_signals.mss b/electrification_signals.mss new file mode 100644 index 00000000..dbbe0039 --- /dev/null +++ b/electrification_signals.mss @@ -0,0 +1,127 @@ +@de-el-size: 18; +@de-el-size-with-arrow: @de-el-size * 1.286; + +#electrification-signals[zoom>=17] { + ["signal_direction"!=null] { + /*************************************/ + /* DE pantograph down advance El 3 */ + /* AT Ankündigung Stromabnehmer tief */ + /*************************************/ + ["electricity_type"="pantograph_down_advance"]["electricity_form"="sign"] { + ["signal_electricity"="DE-ESO:el3"], + ["signal_electricity"="AT-V2:andkündigung_stromabnehmer_tief"] { + marker-file: url("symbols/de/el3.svg"); + marker-width: @de-el-size; + marker-height: @de-el-size; + marker-allow-overlap: true; + } + } + + /************************************/ + /* DE power off advance sign El 1v */ + /* AT Ankündigung Hauptschalter aus */ + /************************************/ + ["electricity_type"="power_off_advance"]["electricity_form"="sign"] { + ["signal_electricity"="DE-ESO:el1v"], + ["signal_electricity"="AT-V2:ankündigung_hauptschalter_aus"] { + marker-file: url("symbols/de/el1v.svg"); + marker-width: @de-el-size; + marker-height: @de-el-size; + marker-allow-overlap: true; + } + } + + /*******************************************************/ + /* DE end of catenary sign El 6 */ + /* AT Halt für Fahrzeuge mit angehobenem Stromabnehmer */ + /*******************************************************/ + ["electricity_type"="end_of_catenary"]["electricity_form"="sign"] { + ["signal_electricity"="DE-ESO:el6"], + ["signal_electricity"="AT-V2:halt_fuer_fahrzeuge_mit_angehobenem_stromabnehmer"] { + marker-file: url("symbols/de/el6.svg"); + marker-width: @de-el-size; + marker-height: @de-el-size; + marker-allow-overlap: true; + + ["electricity_turn_direction"="right"] { + marker-file: url("symbols/de/el6-right.svg"); + marker-width: @de-el-size; + marker-height: @de-el-size-with-arrow; + } + + ["electricity_turn_direction"="left"] { + marker-file: url("symbols/de/el6-left.svg"); + marker-width: @de-el-size; + marker-height: @de-el-size-with-arrow; + } + } + } + + /**************************/ + /* DE power on sign El 2 */ + /* AT Hauptschalter ein */ + /**************************/ + ["electricity_type"="power_on"]["electricity_form"="sign"] { + ["signal_electricity"="DE-ESO:el2"], + ["signal_electricity"="AT-V2:hauptschalter_ein"] { + marker-file: url("symbols/de/el2.svg"); + marker-width: @de-el-size; + marker-height: @de-el-size; + marker-allow-overlap: true; + } + } + + /*************************/ + /* DE pantograph up El 5 */ + /* AT Stromabnehmer hoch */ + /*************************/ + ["electricity_type"="pantograph_up"]["electricity_form"="sign"] { + ["signal_electricity"="DE-ESO:el5"], + ["signal_electricity"="AT-V2:stromabnehmer_hoch"] { + marker-file: url("symbols/de/el5.svg"); + marker-width: @de-el-size; + marker-height: @de-el-size; + marker-allow-overlap: true; + } + } + + /**************************/ + /* DE power off sign El 1 */ + /* AT Hauptschalter aus */ + /**************************/ + ["electricity_type"="power_off"]["electricity_form"="sign"] { + ["signal_electricity"="DE-ESO:el1"], + ["signal_electricity"="AT-V2:hauptschalter_aus"] { + marker-file: url("symbols/de/el1.svg"); + marker-width: @de-el-size; + marker-height: @de-el-size; + marker-allow-overlap: true; + } + } + + /***************************/ + /* DE pantograph down El 4 */ + /* AT Stromabnehmer tief */ + /***************************/ + ["electricity_type"="pantograph_down"]["electricity_form"="sign"] { + ["signal_electricity"="DE-ESO:el4"], + ["signal_electricity"="AT-V2:stromabnehmer_tief"] { + marker-file: url("symbols/de/el4.svg"); + marker-width: @de-el-size; + marker-height: @de-el-size; + marker-allow-overlap: true; + } + } + } + + /*******************************************/ + /* DE tram power off shortly signal (St 7) */ + /*******************************************/ + ["signal_electricity"="DE-BOStrab:st7"]["electricity_type"="power_off_shortly"]["electricity_form"="sign"], + ["signal_electricity"="DE-AVG:st7"]["electricity_type"="power_off_shortly"]["electricity_form"="sign"] { + marker-file: url("symbols/de/bostrab/st7.svg"); + marker-width: 11; + marker-height: 12; + marker-allow-overlap: true; + } +} diff --git a/sql/functions.sql b/sql/functions.sql index b08bd1c0..04b44c3a 100644 --- a/sql/functions.sql +++ b/sql/functions.sql @@ -1,3 +1,30 @@ +CREATE OR REPLACE FUNCTION railway_no_to_null(value TEXT) RETURNS TEXT AS $$ +BEGIN + IF value = 'no' THEN + RETURN NULL; + END IF; + RETURN value; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION railway_to_float(value TEXT) RETURNS FLOAT AS $$ +BEGIN + IF value ~ '^[0-9.]+$' THEN + RETURN value::FLOAT; + END IF; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION railway_to_int(value TEXT) RETURNS INTEGER AS $$ +BEGIN + IF value ~ '^-?[0-9]+$' THEN + RETURN value::INTEGER; + END IF; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + CREATE OR REPLACE FUNCTION railway_get_first_pos(pos_value TEXT) RETURNS TEXT AS $$ DECLARE pos_part1 TEXT; @@ -325,3 +352,116 @@ BEGIN RETURN name; END; $$ LANGUAGE plpgsql; + +-- Get state of electrification +CREATE OR REPLACE FUNCTION railway_electrification_state(railway TEXT, electrified TEXT, + deelectrified TEXT, abandoned_electrified TEXT, construction_electrified TEXT, + proposed_electrified TEXT, ignore_future_states BOOLEAN) RETURNS TEXT AS $$ +DECLARE + state TEXT; + valid_values TEXT[] := ARRAY['contact_line', 'yes', 'rail', 'ground-level_power_supply', 'contact_line;rail', 'rail;contact_line']; +BEGIN + state := NULL; + IF electrified = ANY(valid_values) THEN + return 'present'; + END IF; + IF electrified = 'no' THEN + state := 'no'; + END IF; + IF NOT ignore_future_states AND construction_electrified = ANY(valid_values) THEN + RETURN 'construction'; + END IF; + IF NOT ignore_future_states AND proposed_electrified = ANY(valid_values) THEN + RETURN 'proposed'; + END IF; + IF state = 'no' AND deelectrified = ANY(valid_values) THEN + RETURN 'deelectrified'; + END IF; + IF state = 'no' AND abandoned_electrified = ANY(valid_values) THEN + RETURN 'abandoned'; + END IF; + RETURN state; +END; +$$ LANGUAGE plpgsql; + +-- Get voltage for given state +CREATE OR REPLACE FUNCTION railway_voltage_for_state(state TEXT, voltage TEXT, construction_voltage TEXT, proposed_voltage TEXT) RETURNS INTEGER AS $$ +BEGIN + IF state = 'present' THEN + RETURN railway_to_int(voltage); + END IF; + IF state = 'construction' THEN + RETURN railway_to_int(construction_voltage); + END IF; + IF state = 'proposed' THEN + RETURN railway_to_int(proposed_voltage); + END IF; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + +-- Get frequency for given state +CREATE OR REPLACE FUNCTION railway_frequency_for_state(state TEXT, frequency TEXT, construction_frequency TEXT, proposed_frequency TEXT) RETURNS FLOAT AS $$ +BEGIN + IF state = 'present' THEN + RETURN railway_to_float(frequency); + END IF; + IF state = 'construction' THEN + RETURN railway_to_float(construction_frequency); + END IF; + IF state = 'proposed' THEN + RETURN railway_to_float(proposed_frequency); + END IF; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + +-- Get label for electrification +CREATE OR REPLACE FUNCTION railway_electrification_label(electrified TEXT, deelectrified TEXT, + construction_electrified TEXT, proposed_electrified TEXT, voltage TEXT, frequency TEXT, + construction_voltage TEXT, construction_frequency TEXT, proposed_voltage TEXT, + proposed_frequency TEXT) RETURNS TEXT AS $$ +DECLARE + volt TEXT; + freq TEXT; + volt_int INTEGER; + kilovolt NUMERIC(3, 1); + volt_text TEXT; + freq_text TEXT; +BEGIN + -- Select right values for voltage and frequency part of the label + IF railway_no_to_null(electrified) IS NOT NULL OR railway_no_to_null(deelectrified) IS NOT NULL THEN + volt := voltage; + freq := frequency; + ELSIF railway_no_to_null(construction_electrified) IS NOT NULL THEN + volt := construction_voltage; + freq := construction_frequency; + ELSIF railway_no_to_null(proposed_electrified) IS NOT NULL THEN + volt := proposed_voltage; + freq := proposed_frequency; + ELSE + RETURN NULL; + END IF; + -- Grounded sections + IF volt = '0' THEN + RETURN '0V'; + END IF; + -- Round voltage nicely + volt_int := railway_to_int(volt); + IF volt_int < 1000 THEN + volt_text := volt || 'V'; + ELSIF volt_int % 1000 = 0 THEN + volt_text := (volt_int/1000)::TEXT || 'kV'; + ELSE + volt_text := (volt_int::FLOAT / 1000::FLOAT)::NUMERIC(3, 1)::TEXT || 'kV'; + END IF; + -- Output voltage and frequency + IF freq = '0' THEN + RETURN volt_text || ' ='; + END IF; + IF freq IS NOT NULL THEN + RETURN volt_text || ' ' || freq || 'Hz'; + END IF; + RETURN volt_text; +END; +$$ LANGUAGE plpgsql; diff --git a/sql/osm_carto_views.sql b/sql/osm_carto_views.sql index 6a57b15d..d9f70e35 100644 --- a/sql/osm_carto_views.sql +++ b/sql/osm_carto_views.sql @@ -13,6 +13,17 @@ CREATE OR REPLACE VIEW openrailwaymap_osm_line AS tags->'maxspeed:forward' AS maxspeed_forward, tags->'maxspeed:backward' AS maxspeed_backward, tags->'railway:preferred_direction' AS preferred_direction, + tags->'electrified' AS electrified, + tags->'frequency' AS frequency, + tags->'voltage' AS voltage, + tags->'construction:electrified' AS construction_electrified, + tags->'construction:frequency' AS construction_frequency, + tags->'construction:voltage' AS construction_voltage, + tags->'proposed:electrified' AS proposed_electrified, + tags->'proposed:frequency' AS proposed_frequency, + tags->'proposed:voltage' AS proposed_voltage, + tags->'deelectrified' AS deelectrified, + tags->'abandoned:electrified' AS abandoned_electrified, ref, name, layer,