Skip to content

Conversation

@hiddewie
Copy link
Contributor

@hiddewie hiddewie commented Jun 7, 2025

Hi!

Over the past years I have been working on a fork of the OpenRailwayMap.

The announcement can be found on the OpenRailwayMap mailing list and on the OpenStreetMap community forum.

The fork has several features, and is actively being developed by me and several more contributors:

  • Vector-based data: the map is interactive with e.g. hover and popup showing data details.
  • Map style improvements: station size, state of lines and statons, signal support for many new countries.
  • Visual UI improvements like: configurable background map, map settings and dark mode.
  • Additional layers: loading gauge and track class.
  • Daily data updates for the entire planet.
  • OpenHistoricalMap integration for historical railway infrastructure.

At the moment the fork is hosted on https://openrailwaymap.app using Fly.io. This is purely practical, it could be hosted anywhere else.

This pull request is a starter to discuss:

  • Can we integrate the fork into the Github OpenRailwayMap organization
  • Can we publish the fork on the domain openrailwaymap.org?

These are open questions, any response is appreciated!

hiddewie and others added 16 commits May 24, 2025 16:53
Fixes #402

Vacancy detection already has a `railway` tag value, so does not need
`railway=signal`.


![image](https://github.com/user-attachments/assets/e07eda56-1a09-446e-a5f7-d8e04b7f53da)
Part of #321

For Berlin, the tiles of the signals layer change from 1.7MB to 2.1MB.

TODO:
- [x] implement for speed
- [x] implement for electricity
- [x] reuse tag info (use generated SQL?, modify view to function?)
- [x] Implement a nice tag description for every tag as feature property
title
- [x] Docs about how matching works
- [x] verify for EU import if any features changed

Changes in EU signals:
- DE zp10 is now detected correctly if it exists on the signal (e.g.
https://www.openstreetmap.org/node/110088505)
- DE HHA h1 is the default instead of h0, no difference for signals that
tag their states
- NL speed signals (277, 276, 279) favor H/L/G aspects over speed values
if the speed signal can show both (e.g.
https://www.openstreetmap.org/node/6013691025)
- PL sp, os, ms have different defaults if no states are tagged (e.g.
https://www.openstreetmap.org/node/3046407095)

http://localhost:8000/#view=13.53/47.35671/0.67842&style=signals

![image](https://github.com/user-attachments/assets/b613d2d0-af93-4ff5-936f-8dcdc21d8eca)

### Import comparison between master and this branch (Europe)

#### Master

```
2025-05-18 13:37:42  Reading input files done in 74s (1m 14s).
2025-05-18 13:37:42    Processed 21188740 nodes in 31s - 684k/s
2025-05-18 13:37:42    Processed 2229021 ways in 40s - 56k/s
2025-05-18 13:37:42    Processed 340088 relations in 3s - 113k/s

...
CREATE VIEW
Time: 54.704 ms
SELECT 384855
Time: 21623.621 ms (00:21.624)
CREATE INDEX
Time: 543.683 ms
CLUSTER
Time: 1185.724 ms (00:01.186)
Timing is on.
CREATE VIEW
Time: 2.917 ms
CREATE VIEW
Time: 1.791 ms
CREATE VIEW
Time: 3.016 ms
CREATE VIEW
Time: 1.750 ms
CREATE VIEW
Time: 2.224 ms
CREATE VIEW
Time: 2.335 ms
SELECT 102219
Time: 5919.989 ms (00:05.920)
CREATE INDEX
Time: 375.798 ms
SELECT 123412
Time: 4931.113 ms (00:04.931)
CREATE INDEX
Time: 28.485 ms
SELECT 102219
Time: 3070.182 ms (00:03.070)
CREATE INDEX
...

                         name                         |  size
------------------------------------------------------+---------
 railway_line (r)                                     | 654 MB
 platforms (r)                                        | 203 MB
 grouped_stations_with_route_count (m)                | 101 MB
 signal_features (m)                                  | 95 MB
 platforms_way_idx (i)                                | 86 MB
 signals (r)                                          | 80 MB
 stop_positions (r)                                   | 76 MB
 railway_line_way_idx (i)                             | 74 MB
 stations_clustered (m)                               | 73 MB
 pois (r)                                             | 70 MB
 stop_positions_way_idx (i)                           | 34 MB
 pois_way_idx (i)                                     | 24 MB
 stations (r)                                         | 23 MB
 signals_way_idx (i)                                  | 21 MB
 railway_positions (r)                                | 21 MB
 railway_switches (r)                                 | 16 MB
 signal_features_way_index (i)                        | 15 MB
 railway_positions_way_idx (i)                        | 8848 kB
 stop_areas (r)                                       | 7720 kB
 stop_areas_node_ref_ids_idx (i)                      | 7200 kB
 railway_switches_way_idx (i)                         | 7040 kB
 spatial_ref_sys (r)                                  | 6936 kB
 routes_stop_ref_ids_idx (i)                          | 6936 kB
 stations_clustered_station_ids (i)                   | 6760 kB
 stations_with_route_count (m)                        | 5640 kB
 stop_areas_stop_ref_ids_idx (i)                      | 5104 kB
 stations_way_idx (i)                                 | 5072 kB
 routes (r)                                           | 4648 kB
 routes_platform_ref_ids_idx (i)                      | 4176 kB
 grouped_stations_with_route_count_center_index (i)   | 4168 kB
 grouped_stations_with_route_count_buffered_index (i) | 4160 kB
 stations_with_route_count_idx (i)                    | 2736 kB
 stations_id_idx (i)                                  | 2736 kB
 boxes (r)                                            | 2000 kB
 subway_entrances (r)                                 | 1640 kB
 stop_areas_platform_ref_ids_idx (i)                  | 1216 kB
 turntables (r)                                       | 1112 kB
 subway_entrances_way_idx (i)                         | 632 kB
 boxes_way_idx (i)                                    | 336 kB
 spatial_ref_sys_pkey (i)                             | 208 kB
 turntables_way_idx (i)                               | 104 kB
 sql_features (r)                                     | 104 kB
 sql_implementation_info (r)                          | 48 kB
 sql_sizing (r)                                       | 48 kB
 sql_parts (r)                                        | 48 kB
 osm2pgsql_properties (r)                             | 16 kB
 osm2pgsql_properties_pkey (i)                        | 16 kB
(47 rows)

Time: 7.339 ms
Timing is on.
  size
---------
 1762 MB

```

#### This branch

```
2025-05-18 13:12:50  Reading input files done in 81s (1m 21s).
2025-05-18 13:12:50    Processed 21188740 nodes in 38s - 558k/s
2025-05-18 13:12:50    Processed 2229021 ways in 40s - 56k/s
2025-05-18 13:12:50    Processed 340088 relations in 3s - 113k/s

...
CREATE VIEW
Time: 70.365 ms
SELECT 384815
Time: 54559.599 ms (00:54.560)
CREATE INDEX
Time: 534.438 ms
CLUSTER
Time: 1675.338 ms (00:01.675)
CREATE FUNCTION
Time: 8.002 ms
DO
Time: 11.928 ms
CREATE FUNCTION
Time: 14.257 ms
DO
Time: 12.453 ms
CREATE FUNCTION
Time: 11.350 ms
DO
Time: 12.310 ms
Timing is on.
CREATE VIEW
Time: 12.079 ms
CREATE VIEW
Time: 12.335 ms
CREATE VIEW
Time: 14.242 ms
CREATE VIEW
Time: 13.268 ms
CREATE VIEW
Time: 12.490 ms
CREATE VIEW
Time: 12.486 ms
SELECT 102219
Time: 3678.441 ms (00:03.678)
CREATE INDEX
Time: 1559.621 ms (00:01.560)
SELECT 123412
Time: 4719.376 ms (00:04.719)
CREATE INDEX
Time: 36.647 ms
SELECT 102219
Time: 3117.260 ms (00:03.117)
CREATE INDEX
...
                         name                         |  size
------------------------------------------------------+---------
 railway_line (r)                                     | 612 MB
 platforms (r)                                        | 203 MB
 signal_features (m)                                  | 108 MB
 grouped_stations_with_route_count (m)                | 101 MB
 signals (r)                                          | 93 MB
 platforms_way_idx (i)                                | 86 MB
 stop_positions (r)                                   | 76 MB
 railway_line_way_idx (i)                             | 74 MB
 stations_clustered (m)                               | 73 MB
 pois (r)                                             | 70 MB
 stop_positions_way_idx (i)                           | 34 MB
 pois_way_idx (i)                                     | 24 MB
 stations (r)                                         | 23 MB
 signals_way_idx (i)                                  | 21 MB
 railway_positions (r)                                | 21 MB
 railway_switches (r)                                 | 16 MB
 signal_features_way_index (i)                        | 15 MB
 railway_positions_way_idx (i)                        | 8848 kB
 stop_areas (r)                                       | 7720 kB
 stop_areas_node_ref_ids_idx (i)                      | 7200 kB
 railway_switches_way_idx (i)                         | 7040 kB
 routes_stop_ref_ids_idx (i)                          | 6936 kB
 spatial_ref_sys (r)                                  | 6936 kB
 stations_clustered_station_ids (i)                   | 6760 kB
 stations_with_route_count (m)                        | 5640 kB
 stop_areas_stop_ref_ids_idx (i)                      | 5104 kB
 stations_way_idx (i)                                 | 5072 kB
 routes (r)                                           | 4648 kB
 routes_platform_ref_ids_idx (i)                      | 4176 kB
 grouped_stations_with_route_count_center_index (i)   | 4168 kB
 grouped_stations_with_route_count_buffered_index (i) | 4160 kB
 stations_with_route_count_idx (i)                    | 2736 kB
 stations_id_idx (i)                                  | 2736 kB
 boxes (r)                                            | 2000 kB
 subway_entrances (r)                                 | 1640 kB
 stop_areas_platform_ref_ids_idx (i)                  | 1216 kB
 turntables (r)                                       | 1112 kB
 subway_entrances_way_idx (i)                         | 632 kB
 boxes_way_idx (i)                                    | 336 kB
 spatial_ref_sys_pkey (i)                             | 208 kB
 sql_features (r)                                     | 104 kB
 turntables_way_idx (i)                               | 104 kB
 sql_implementation_info (r)                          | 48 kB
 sql_parts (r)                                        | 48 kB
 sql_sizing (r)                                       | 48 kB
 osm2pgsql_properties (r)                             | 16 kB
 osm2pgsql_properties_pkey (i)                        | 16 kB
(47 rows)

Time: 10.132 ms
Timing is on.
  size
---------
 1745 MB
```
Hi, recently the instruction for signalling in PL was updated (20th may)
and it implemented half speeds for certain speed signals (speeds up to
100 km/h, every 5 km/h from 10 km/h). Since it's quite new, I haven't
spotted any of those on railway network yet. However, for future edits,
I've allowed for half speeds to be rendered with W8, W9 and W27a signals

source:
https://www.plk-sa.pl/files/public/user_upload/pdf/Akty_prawne_i_przepisy/Instrukcje/Wydruk/Ie/05_Instrukcja_Ie-1-od_2025-05-20_WCAG.pdf

---------

Co-authored-by: Hidde Wieringa <hidde@hiddewieringa.nl>
This PR properly imports the feature (`railway` tag) and state of a
station.

For example a `disused:railway=yard` will be imported as `feature=yard`
and `state=disused`.

The UI can show the state, and render the station feature with a
different (gray?, brown?) color.

Razed station features will no longer be imported.
Part of #302 

See
https://wiki.openstreetmap.org/wiki/OpenRailwayMap/Tagging#Catenary_mast

http://localhost:8000/#view=14/52.27324/4.66677&style=electrification

![image](https://github.com/user-attachments/assets/162f1334-d8bc-4a88-a7e0-6b0aafe37b06)

http://localhost:8000/#view=15/52.27324/4.66677&style=electrification

![image](https://github.com/user-attachments/assets/1d88c79a-1e2e-483c-9127-cda0221e0767)


http://localhost:8000/#view=17.4/52.162278/4.559897&style=electrification

![image](https://github.com/user-attachments/assets/e838c7d8-92b0-4349-812d-c926e8e0f908)

http://localhost:8000/#view=14/52.37844/4.9105&style=electrification

![image](https://github.com/user-attachments/assets/90f39563-0735-4778-b6f5-97cef19c08ca)

http://localhost:8000/#view=15/52.37805/4.91108&style=electrification

![image](https://github.com/user-attachments/assets/79d2cd59-c8ff-4c1a-922a-817d245774ae)

http://localhost:8000/#view=16/52.377434/4.909438&style=electrification

![image](https://github.com/user-attachments/assets/18030a8f-c034-434d-9a08-38e4ebf64a91)
Followup on #412

Some small details were missing: tile generation, refs and taginfo.
Hi there, to better differentiate between D0 and mechanical distant
signals, I've added W1 sign to those icons (similarly to german
mechanical Vr signals)
Fixes #408

Stations still work fine:
http://localhost:8000/#view=14.01/51.38781/-0.06701&date=1969

![image](https://github.com/user-attachments/assets/1ec73dd0-32d5-4c64-b937-25dfa69f77bb)
Fixes #414

Opening the map in a blank state will continue from where the user left
off.

Using the URL hash will always override the last stored view.
Currently only `values` is handled, which is gone since #400.

`all` is a single `;`-delimited value, while `any` is a multiselect.
See https://github.com/maplibre/maplibre-gl-js/releases/tag/v5.6.0

This includes maplibre/maplibre-gl-js#5613
allowing for global map state (like theme and date). Uses
maplibre/maplibre-style-spec#1044,
maplibre/maplibre-style-spec#886,
maplibre/maplibre-gl-js#4964.

Changes: replace `date` with a global state property, to simplify map
rendering and dynamic date changes.
Align with wiki
https://wiki.openstreetmap.org/wiki/OpenRailwayMap/Tagging_in_Belgium
and tagged data.

http://localhost:8000/#view=15.24/50.485185/3.91251&style=signals

![image](https://github.com/user-attachments/assets/d1c526a7-69d5-40e7-badf-98aeeb627d64)

http://localhost:8000/#view=16.73/50.440429/3.815034&style=signals

![image](https://github.com/user-attachments/assets/c9a53775-d1b1-4fe6-8f33-e80ce1268bf6)

http://localhost:8000/#view=19.2/50.833946/4.3333266&style=signals

![image](https://github.com/user-attachments/assets/d05a70e9-4f5e-434b-bc4f-0c4224171a61)

http://localhost:8000/#view=17.06/50.836748/4.337766&style=signals

![image](https://github.com/user-attachments/assets/09c43cf0-2596-44d8-adb4-dc425e5464d3)
Reduces total tile size for zooms 10 to 12
The wrong files were cached.

e.g.
https://github.com/hiddewie/OpenRailwayMap-vector/actions/runs/15511274470/job/43672557791

```
Post job cleanup.
Warning: Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.
```

After, cache works:

https://github.com/hiddewie/OpenRailwayMap-vector/actions/runs/15511428649

![image](https://github.com/user-attachments/assets/33e331fb-e6f3-4859-a85e-7da813791509)
Part of #385

Currently mobile UI elements obstruct the map.

Changes:
- On small screens: hide text on icons
- Make date selection UI togglable. Show year only when in the past.
Hide by default on small screens, show by default on large screens
- For small screens, collapse the style selection by default. When the
button is pressed the element to select a style shows.
hiddewie added 13 commits June 11, 2025 19:19
Part of #431

Hosting the UI and tiles on Fly.io is getting expensive. Instead, let
Cloudflare proxy and cache all assets and tiles. This should improve
both latency, cache hit rates and data transfer.

There will be some graceful migration period were both
openrailwaymap.fly.dev and openrailwaymap.app work, and after that a
redirect.

Additionally: HTTP/3 support :) 

![image](https://github.com/user-attachments/assets/a2e6d5e0-4a38-4559-b41f-e0bdb2424fe0)
Fixes #428 

This only works for station entrances that are part of the
`public_transport=stop_area` relation.

http://localhost:8000/#view=15.68/48.585145/7.737522

![image](https://github.com/user-attachments/assets/97a3d8bd-c0b5-409d-9916-3b7e1272dbec)

http://localhost:8000/#view=17.54/48.584975/7.735184

![image](https://github.com/user-attachments/assets/39badad2-a390-4ca2-8aa1-6bbeab05ef55)
Fixes #349

The Americana style does not work in deployed domains. This project has
no affiliation with OSM US, so we drop the reference from the example in
the background styles. The example is replaced with Stadia Maps which
works cross domain, but requires a (free) API key.
Part of #302

Move power supplies to the electrification layer.


http://localhost:8000/#view=16.69/51.352199/4.629311&style=electrification

![image](https://github.com/user-attachments/assets/32f0297a-4aea-48a7-995c-56063a3adbfa)
From discussion in
#302

This pull request adds support for catenary masts that are a power
transition point.


http://localhost:8000/#view=16.87/52.349219/13.284871&style=electrification

![image](https://github.com/user-attachments/assets/a8b42851-365d-4e9a-a772-1cea9af00ae3)

![image](https://github.com/user-attachments/assets/ee5572aa-3301-45c5-8fc2-5d7e9b71b704)
Fixes #257

Add support for the tags `train`, `subway`, `light_rail`, `monorail`,
`funicular` and `miniature` to specify which type of vehicles stop at
the station.
)

Part of #431 

This pull request redirects all users that use the
`openrailwaymap.fly.dev` domain to `openrailwaymap.app` (proxied through
Cloudflare).


![image](https://github.com/user-attachments/assets/8ac71bf1-81f9-4b11-b630-8f20ce71bba9)
When image or wikimedia commons file tags are present, show the image(s)
in the feature popup.

~Current implementation is impacted by XSS.~

Wikidata lookup does not work: CORS is not enabled for the Wikidata
lookup API. Possible the API needs to be proxied.


![image](https://github.com/user-attachments/assets/af4ed2d2-13b4-43fb-b8ff-e79fd1e43ccf)
danieldegroot2 and others added 30 commits December 30, 2025 19:38
Added [badges](https://github.com/badges/shields).
Maintainers feel free to modify or discard changes.

[See changes
visually](https://github.com/danieldegroot2/OpenRailwayMap-vector/tree/readme-badges?tab=readme-ov-file#openrailwaymap-vector-map-styles)
(Scroll up slightly. You might have to (Ctrl+)(Shift+)F5 clear cache to
see valid BMC supporters count.)

---

I am aware this repository is [possibly being
integrated](OpenRailwayMap#132)
into the OpenRailwayMap-CartoCSS repository.
Check with the maintainers which content should be kept from each
repository / how ie. funding might be handled.

---------

Co-authored-by: Hidde Wieringa <hidde@hiddewieringa.nl>
Noticed during
#734 (comment)

For tall icons for the bottom icon of a signal feature, the reference is
always offset using the same fixed offset. This will overlap the
reference text with the icon.

Instead, output the icon offset such that the text label for the
reference can be offset by the same value (plus some padding).


(http://localhost:8000/#view=18.41/49.010647/8.384991/-19.5&style=signals):
<img width="1074" height="574" alt="image"
src="https://github.com/user-attachments/assets/c2288181-d5f6-4327-ab5d-0ac441065624"
/>


(http://localhost:8000/#view=18.08/49.00242/8.394911/-19.5&style=signals)
<img width="1074" height="574" alt="image"
src="https://github.com/user-attachments/assets/8ab6c7b6-c929-4611-9b9d-beadda7b015b"
/>


(http://localhost:8000/#view=19/48.9970422/8.4158721/-19.5&style=signals)
<img width="1074" height="574" alt="image"
src="https://github.com/user-attachments/assets/283ae76b-cfd9-44cc-8129-b91b11545251"
/>
AKN
<img width="361" height="822" alt="image"
src="https://github.com/user-attachments/assets/e7a6a3ff-d728-4a5d-b6d0-3228565b315f"
/>

Deutsche Regionaleisenbahn
<img width="1045" height="382" alt="image"
src="https://github.com/user-attachments/assets/27d2b859-a6e9-4c4a-8352-299a5a652a73"
/>

Thüringer Eisenbahn GmbH and Deutsche Regionaleisenbahn
<img width="567" height="395" alt="image"
src="https://github.com/user-attachments/assets/40323e54-e392-41ab-a14b-5691b1506567"
/>

Schieneninfrastruktur Ost-Niedersachsen GmbH
<img width="703" height="811" alt="image"
src="https://github.com/user-attachments/assets/218f9496-b8a5-4688-a214-f0e4a197354b"
/>
Adds GB stop & fixed distant boards.

Distant signals kept together.
Stop board placed to allow for a position light (shunt) signal, but
below an LC indicator. Only thing of note is that the order would be
slightly at issue with ETCS block markers, however I will create an
issue and then PR shortly after this is merged, as there are also other
order issues to work on.
For stacked signal icons, with multiple icons that have an icon with a
position defined, only the first position was removed on the catalog
lookup.

Found during testing of
#734 (comment)


(http://localhost:8000/#view=17.65/49.00464/8.411248/-19.5&style=signals):
<img width="847" height="596" alt="image"
src="https://github.com/user-attachments/assets/8a0731fe-6a35-402f-8e44-83b417428464"
/>
… lines (#748)

Part of #413 

Integrate railway routes for stations, platforms, stop positions and
railway lines in the popup UI and on the map when clicked.

Changes:
- [x] Import route details
- [x] Add routes in popup for lines
- [x] Add routes in popup for platforms
- [x] Add routes in popup for stop positions
- [x] Add routes in popup for stations
- [x] Add display of route on map when clicking route
- [x] Add display of route information when clicking route 

See:
- https://wiki.openstreetmap.org/wiki/Relation:route
- https://wiki.openstreetmap.org/wiki/Tag:route=train?uselang=en
Fixes #749

The wrong tag for opposite regime signals was used.

Related to #541, which fixed this for main signals.

Also, add the yellow distant signal marker board

Before:
<img width="524" height="556" alt="image"
src="https://github.com/user-attachments/assets/f794962a-e0aa-47d6-8540-d58059a7ff79"
/>

After:
<img width="433" height="501" alt="image"
src="https://github.com/user-attachments/assets/d6d898c1-69ce-4ba5-8dd7-66fdcd811e9b"
/>
Reverts the changes of the distant plates introduced in
#756.

Discussed in #749
…date (#760)

From #748

The nightly update fails because of timeouts on a delete query to reduce
data, and because of disk space issues.
After managing to go through the Podman pain, finally a new MR...

<img width="1389" height="737" alt="image"
src="https://github.com/user-attachments/assets/0b03a1fa-4340-4eed-9c7b-8d220d6c885a"
/>
<img width="1389" height="737" alt="image"
src="https://github.com/user-attachments/assets/935e9cf6-1e94-4ab0-9509-2a5b674437b4"
/>
<img width="1389" height="737" alt="image"
src="https://github.com/user-attachments/assets/b3572a1c-a153-45e5-a753-50073a1a627f"
/>


Downside is that F0 only, or signals without states, look weird, so
suggestions would be nice:

<img width="1389" height="737" alt="image"
src="https://github.com/user-attachments/assets/dcd20f24-4bd3-40c2-bc99-7cfad4353513"
/>

Ref can look weird too on long signals:
<img width="485" height="361" alt="image"
src="https://github.com/user-attachments/assets/1c43e9d8-1012-484c-b44e-fad8c7cca9f6"
/>
Followup on #748

Part of #413

Currently the API calls to display routes on the map are very slow, and
sometimes time out.

## API

Route 18173306, https://www.openstreetmap.org/relation/18173306.

Example query
```sql
explain analyze
SELECT jsonb_build_object(
         'type', 'Feature',
         'id', osm_id,
         'geometry', ST_AsGeoJSON(ST_Transform(way, 4326))::jsonb,
         'properties', to_jsonb(row) - 'way'
       ) as data
FROM (SELECT r.osm_id                        as osm_id,
             ST_LineMerge(st_collect(l.way)) as way,
             any_value(r.type)               as type,
             any_value(r.name)               as name,
             any_value(r.ref)                as ref,
             any_value(r.from)               as "from",
             any_value(r.to)                 as "to",
             any_value(r.operator)           as operator,
             any_value(r.brand)              as brand,
             any_value(r.color)              as color
      from routes r
             join route_line rl
                  on rl.route_id = r.osm_id
             join railway_line l
                  on rl.line_id = l.osm_id
      where r.osm_id = 18173306
      group by r.osm_id) row;
```

Before:

```
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|QUERY PLAN                                                                                                                                                                      |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|Subquery Scan on "row"  (cost=2484.03..211196.87 rows=1 width=32) (actual time=493.106..530.542 rows=1.00 loops=1)                                                              |
|  Buffers: shared hit=117464 read=55500                                                                                                                                         |
|  ->  GroupAggregate  (cost=2484.03..211183.72 rows=1 width=268) (actual time=490.630..527.912 rows=1.00 loops=1)                                                               |
|        Buffers: shared hit=117461 read=55500                                                                                                                                   |
|        ->  Gather  (cost=2484.03..211111.43 rows=408 width=336) (actual time=488.180..526.951 rows=73.00 loops=1)                                                              |
|              Workers Planned: 2                                                                                                                                                |
|              Workers Launched: 2                                                                                                                                               |
|              Buffers: shared hit=117461 read=55500                                                                                                                             |
|              ->  Parallel Hash Join  (cost=1484.03..210070.63 rows=170 width=336) (actual time=351.275..441.764 rows=24.33 loops=3)                                            |
|                    Hash Cond: (l.osm_id = rl.line_id)                                                                                                                          |
|                    Buffers: shared hit=117461 read=55500                                                                                                                       |
|                    ->  Parallel Seq Scan on railway_line l  (cost=0.00..188076.38 rows=1640738 width=199) (actual time=0.198..193.818 rows=1312590.00 loops=3)                 |
|                          Buffers: shared hit=116169 read=55500                                                                                                                 |
|                    ->  Parallel Hash  (cost=1481.94..1481.94 rows=167 width=153) (actual time=14.694..14.697 rows=24.33 loops=3)                                               |
|                          Buckets: 1024  Batches: 1  Memory Usage: 40kB                                                                                                         |
|                          Buffers: shared hit=1292                                                                                                                              |
|                          ->  Nested Loop  (cost=0.43..1481.94 rows=167 width=153) (actual time=43.639..43.921 rows=73.00 loops=1)                                              |
|                                Buffers: shared hit=1292                                                                                                                        |
|                                ->  Parallel Seq Scan on routes r  (cost=0.00..1472.50 rows=1 width=145) (actual time=43.549..43.795 rows=1.00 loops=1)                         |
|                                      Filter: (osm_id = 18173306)                                                                                                               |
|                                      Rows Removed by Filter: 25091                                                                                                             |
|                                      Buffers: shared hit=1288                                                                                                                  |
|                                ->  Index Scan using route_line_route_id_idx on route_line rl  (cost=0.43..6.60 rows=284 width=16) (actual time=0.055..0.074 rows=73.00 loops=1)|
|                                      Index Cond: (route_id = 18173306)                                                                                                         |
|                                      Index Searches: 1                                                                                                                         |
|                                      Buffers: shared hit=4                                                                                                                     |
|Planning:                                                                                                                                                                       |
|  Buffers: shared hit=8                                                                                                                                                         |
|Planning Time: 0.649 ms                                                                                                                                                         |
|JIT:                                                                                                                                                                            |
|  Functions: 51                                                                                                                                                                 |
|  Options: Inlining false, Optimization false, Expressions true, Deforming true                                                                                                 |
|  Timing: Generation 7.196 ms (Deform 3.479 ms), Inlining 0.000 ms, Optimization 3.535 ms, Emission 75.353 ms, Total 86.085 ms                                                  |
|Execution Time: 533.884 ms                                                                                                                                                      |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
```

After:
```
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|QUERY PLAN                                                                                                                                                          |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|Subquery Scan on "row"  (cost=0.86..1882.96 rows=1 width=32) (actual time=6.435..6.554 rows=1.00 loops=1)                                                           |
|  Buffers: shared hit=1559 read=28                                                                                                                                  |
|  ->  GroupAggregate  (cost=0.86..1869.82 rows=1 width=268) (actual time=4.411..4.414 rows=1.00 loops=1)                                                            |
|        Buffers: shared hit=1556 read=28                                                                                                                            |
|        ->  Nested Loop  (cost=0.86..1797.52 rows=408 width=336) (actual time=3.092..3.775 rows=73.00 loops=1)                                                      |
|              Buffers: shared hit=1556 read=28                                                                                                                      |
|              ->  Nested Loop  (cost=0.43..1611.09 rows=284 width=153) (actual time=3.048..3.330 rows=73.00 loops=1)                                                |
|                    Buffers: shared hit=1292                                                                                                                        |
|                    ->  Seq Scan on routes r  (cost=0.00..1601.65 rows=1 width=145) (actual time=3.004..3.255 rows=1.00 loops=1)                                    |
|                          Filter: (osm_id = 18173306)                                                                                                               |
|                          Rows Removed by Filter: 25091                                                                                                             |
|                          Buffers: shared hit=1288                                                                                                                  |
|                    ->  Index Scan using route_line_route_id_idx on route_line rl  (cost=0.43..6.60 rows=284 width=16) (actual time=0.039..0.054 rows=73.00 loops=1)|
|                          Index Cond: (route_id = 18173306)                                                                                                         |
|                          Index Searches: 1                                                                                                                         |
|                          Buffers: shared hit=4                                                                                                                     |
|              ->  Index Scan using railway_line_osm_id_index on railway_line l  (cost=0.43..0.65 rows=1 width=199) (actual time=0.005..0.005 rows=1.00 loops=73)    |
|                    Index Cond: (osm_id = rl.line_id)                                                                                                               |
|                    Index Searches: 73                                                                                                                              |
|                    Buffers: shared hit=264 read=28                                                                                                                 |
|Planning:                                                                                                                                                           |
|  Buffers: shared hit=30 read=6                                                                                                                                     |
|Planning Time: 1.357 ms                                                                                                                                             |
|Execution Time: 6.716 ms                                                                                                                                            |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
```
Problem: milestones and other positions are only rendered from zoom 10
onwards. Between zoom 10 and 13, only the zero-position markers are
rendered. From zoom 13 onwards, every position is rendered. The source
is queried from zoom 8 onwards, wasting bandwidth and performance on
not-shown position markers.

Before:
<img width="1432" height="168" alt="image"
src="https://github.com/user-attachments/assets/29931b09-3d1a-4a8a-ba05-65836582f39b"
/>

After:
<img width="1432" height="168" alt="image"
src="https://github.com/user-attachments/assets/c2285639-da31-42a4-b58e-91031cd05f4f"
/>
* Add Ortsstellbereich sign
* Add PZB-Sign (not yet used)
* Change font on crossing hint and anouncement sign
* Un-cram some signals for a more unified look

<img width="1268" height="409" alt="image"
src="https://github.com/user-attachments/assets/a5ff0046-6fb2-44f5-83ce-1a143c0b67bf"
/>

Crammed signals before
<img width="1430" height="236" alt="image"
src="https://github.com/user-attachments/assets/07027546-7d83-4dc9-b492-901971ed3cfc"
/>

And after
<img width="1430" height="236" alt="image"
src="https://github.com/user-attachments/assets/61f0f39f-fc84-4e60-8c35-945284b9b1de"
/>
edited operators:
- East Japan Railway: added synonyms
- West Japan Railway: added synonyms
- Shikoku Railway: changed order and added synonyms
- Hokkaido Railway: changed order
- Central Japan Railway: added synonyms
- Kyushu Railway: added synonyms
- Kintetsu Railway: changed color
- Hankyu Corporation: changed order
- Tokyu Railways: changed order and color, and added synonyms
- Seibu Railways: changed color and added synonyms
- Odakyu Electric Railways: changed color
- Nagoya Railroad: changed order
- Bureau of Transportation Tokyo Metropolitan Government: changed color
and added synonyms
- Keio Corporation: added synonyms
- Tobu Railway: added synonyms
- Korail: corrected color and delete synonyms (osm edit completed)
- 서해철도: corrected color
- 네오트랜스: corrected color and terms (osm edit completed)
- 주식회사에스알: changed terms and color (osm edit completed)

newly added operators:
- Japan Freight Railway Company
<img width="590" height="362" alt="스크린샷 2026-01-04 17 35 34"
src="https://github.com/user-attachments/assets/7d5c3566-410f-4a17-ae8c-367ed3bf40cb"
/>

- Osaka Metro
<img width="678" height="518" alt="스크린샷 2026-01-04 18 00 43"
src="https://github.com/user-attachments/assets/26651598-de3c-4ff2-a63a-f4c6df54fa1a"
/>

- HAPI-LINE Fukui Railway
<img width="1622" height="906" alt="image"
src="https://github.com/user-attachments/assets/77b20612-d464-41f6-8ecd-c28654d349f2"
/>

- Kyoto Tango Railway
<img width="1140" height="616" alt="image"
src="https://github.com/user-attachments/assets/bc49994f-a540-4ee1-b69d-b17d5b958738"
/>

- Nankai Electric Railway
<img width="1144" height="672" alt="image"
src="https://github.com/user-attachments/assets/c4a6202c-6d2b-4ddf-ab61-6cf5776d0183"
/>

- Keihan Electric Railway
<img width="1398" height="700" alt="image"
src="https://github.com/user-attachments/assets/1f2192dc-9c15-4d63-aa72-e9e3762e3422"
/>

- Hanshin Electric Railway
<img width="1658" height="926" alt="image"
src="https://github.com/user-attachments/assets/069c9f27-30e3-4493-9f48-54ad6c09c9e9"
/>

- Sanyo Electric Railway
<img width="1550" height="826" alt="image"
src="https://github.com/user-attachments/assets/e0b8fcc7-4dd9-434d-98d8-e0a15c84bbad"
/>

- Chizu Express
<img width="1096" height="796" alt="image"
src="https://github.com/user-attachments/assets/f32c8ee6-49b9-4738-b93e-fd588aff658d"
/>

- Ibara Railway
<img width="1166" height="636" alt="image"
src="https://github.com/user-attachments/assets/51042053-55ad-4f68-9d87-f5440ce47eb0"
/>

- Kita-Osaka Kyuko
<img width="1252" height="852" alt="image"
src="https://github.com/user-attachments/assets/e48366cd-46e1-4841-af37-1a626930e3e1"
/>

- Hankai Tramway
<img width="1178" height="808" alt="image"
src="https://github.com/user-attachments/assets/35c2ad28-bc8d-410d-b781-64c30bbd8ccf"
/>

- Transportation Bureau City of Nagoya
<img width="1262" height="654" alt="image"
src="https://github.com/user-attachments/assets/038fddfe-9516-40e5-a4eb-492f445e79a8"
/>

- Echigo Tokimeki Railway
<img width="1558" height="658" alt="image"
src="https://github.com/user-attachments/assets/a998bc01-d07c-49c7-8560-bdee34926b4b"
/>

- Toyama Chihou Tetsudo Inc.
<img width="1216" height="594" alt="image"
src="https://github.com/user-attachments/assets/11929755-34e6-4edc-b7a4-e3c50089dac6"
/>

- Hokuetsu Express
<img width="1074" height="730" alt="image"
src="https://github.com/user-attachments/assets/e573388e-2405-4a39-af96-f15572b29857"
/>

- Sapporo City Transportation Bureau 
<img width="1456" height="730" alt="image"
src="https://github.com/user-attachments/assets/bbe7e07a-3872-4816-9227-ae04bb300436"
/>

- Nishi-nippon Railroad
<img width="1108" height="750" alt="image"
src="https://github.com/user-attachments/assets/4f1569da-40a5-49d8-8857-ae14b412273c"
/>

- Fukuoka City Transportation Bureau 
<img width="2222" height="340" alt="image"
src="https://github.com/user-attachments/assets/0d562385-0f01-4e84-804f-9d3dc9a532e8"
/>

- Iyo Railway
<img width="1346" height="810" alt="image"
src="https://github.com/user-attachments/assets/37c1f4c8-851c-4299-81dd-9e7241514ee2"
/>

- Tosa Kuroshio Tetsudo
<img width="1144" height="576" alt="image"
src="https://github.com/user-attachments/assets/46ebc029-b8ac-4d33-af3a-87afeaee0810"
/>

- Takamatsu-Kotohira Electric Railroad 
<img width="1324" height="666" alt="image"
src="https://github.com/user-attachments/assets/5db4c54c-a34d-4cef-bd64-2baf4ed99a75"
/>

- Kominato Railway
<img width="1444" height="806" alt="image"
src="https://github.com/user-attachments/assets/916c37e0-cf2b-45f4-854b-bed1e6fec2e7"
/>

- IGR Iwate Galaxy Railway
<img width="1430" height="516" alt="image"
src="https://github.com/user-attachments/assets/760ab0bf-7469-4444-9c8f-2b2ad8c313d4"
/>

- Konan Railway
<img width="1200" height="806" alt="image"
src="https://github.com/user-attachments/assets/b9ae22a2-5b25-49e4-832e-e4b809668097"
/>

- Chichibu Railway
<img width="864" height="654" alt="image"
src="https://github.com/user-attachments/assets/7cbe2cb0-ab46-4363-8c6c-311d25d27c4a"
/>

- Sagami Railway
<img width="1412" height="664" alt="image"
src="https://github.com/user-attachments/assets/d68d32a7-8321-44e2-b669-c9743daf5099"
/>

- Hokuso Railway
<img width="1420" height="742" alt="image"
src="https://github.com/user-attachments/assets/c3865763-a10e-41fd-ba4f-86fbc068f3a3"
/>

- Keisei Electric Railway
<img width="1240" height="660" alt="image"
src="https://github.com/user-attachments/assets/da5a2cd7-434c-415e-96db-059c29d17c01"
/>

- Saitama Railway
<img width="1156" height="864" alt="image"
src="https://github.com/user-attachments/assets/0961e5f4-bf11-441f-a842-0b57c159dab3"
/>

- Tokyo Tama Intercity Railway
<img width="1314" height="710" alt="image"
src="https://github.com/user-attachments/assets/9ec18c34-661d-4ab2-9ed6-195ecc8a817e"
/>

- Tokyo Monorail
<img width="1082" height="730" alt="image"
src="https://github.com/user-attachments/assets/c0926e08-73bd-473d-b71a-7040ea11b82c"
/>

- Transportation Bureau City of Yokohama
<img width="1360" height="866" alt="image"
src="https://github.com/user-attachments/assets/c4a39b87-1667-496b-8249-68aeccc8ea9c"
/>

- Enoshima Electric Railway
<img width="886" height="752" alt="image"
src="https://github.com/user-attachments/assets/4cd5cad3-8390-4df6-ae6d-217ebcc18e5d"
/>

- Tokyo Waterfront Area Rapid Transit
<img width="1144" height="920" alt="image"
src="https://github.com/user-attachments/assets/297368e7-131b-4d67-8860-0f9aa7825aa8"
/>

- Metropolitan Intercity Railway
<img width="1238" height="664" alt="image"
src="https://github.com/user-attachments/assets/fbdd5f48-4494-4176-8cad-dfa98d290871"
/>

- 서울교통공사
<img width="1290" height="744" alt="image"
src="https://github.com/user-attachments/assets/85aeb5d5-6304-4025-a7f4-719c5cc148e0"
/>

- 공항철도주식회사
<img width="1298" height="640" alt="image"
src="https://github.com/user-attachments/assets/6737bcb6-206e-4e27-8fed-5dfe4e22c129"
/>

- 인천교통공사
<img width="1398" height="878" alt="image"
src="https://github.com/user-attachments/assets/2f30996f-acf0-4d0e-b6d6-2c1eed271760"
/>

- 지티엑스에이운영주식회사
<img width="988" height="774" alt="image"
src="https://github.com/user-attachments/assets/fa9abf1a-639e-44d6-b748-6e373db070f4"
/>

- 로템SRS, 우진메트로
<img width="1488" height="1078" alt="image"
src="https://github.com/user-attachments/assets/916d5a7e-ae32-4a6c-9f69-60738b810925"
/>
<img width="1256" height="644" alt="image"
src="https://github.com/user-attachments/assets/0dab2012-4145-45b7-b533-b3ae58686d6a"
/>

- 우이신설경전철운영(주)
<img width="1418" height="724" alt="image"
src="https://github.com/user-attachments/assets/dd998df3-c71a-4727-91d5-05fe3fab79f4"
/>

- 김포골드라인SRS
<img width="1566" height="1326" alt="image"
src="https://github.com/user-attachments/assets/46287cb3-d2f5-47ca-9536-c58ed3e859f7"
/>

- 용인에버라인운영(주)
<img width="1148" height="956" alt="image"
src="https://github.com/user-attachments/assets/88d14b99-6b38-43a8-b43c-bb36b7f9663e"
/>

- 부산교통공사
<img width="1306" height="786" alt="image"
src="https://github.com/user-attachments/assets/34658c8d-24a0-4a0f-b40a-38afe2d3b034"
/>

- 부산·김해경전철주식회사
<img width="1588" height="876" alt="image"
src="https://github.com/user-attachments/assets/4faba6ca-7c2a-45f7-9d33-379662057956"
/>

- 대구교통공사
<img width="1186" height="590" alt="image"
src="https://github.com/user-attachments/assets/a6782fb2-dec2-44da-a3a4-9a4ab25000ff"
/>

- 대전교통공사
<img width="1330" height="816" alt="image"
src="https://github.com/user-attachments/assets/02cdb7d3-7297-4451-9c77-5e640454d1fe"
/>

---------

Co-authored-by: Hidde Wieringa <hidde@hiddewieringa.nl>
## Add values on CBTC
Now specific type of CBTC (IL-CBTC and RF-CBTC) can be displayed on
OpenRailwayMap.
Considering conventional values of this key, legacy values are not
removed.

## Add values on ATC
Now supports displaying specific type of ATC. (see
https://osm.wiki/Key:railway:atc)

## Remove TASC
TASC was removed because it's not a train protection system. TASC is
just a kind of automation that helps train to stop at right position.

## Change order of KTCS
KTCS is an ETCS-compatible protection system, therefore if value of
`railway:ktcs` is 1 or 2, corresponding `railway:etcs` value is implied.
This means `railway:ktcs` is used in combination with `railway:etcs`.
For example, there are railways which are equipped only with ETCS, but
none only with KTCS (except metros). This is the reason that
`railway:ktcs` should override `railway:etcs`.

---------

Co-authored-by: Hidde Wieringa <hidde@hiddewieringa.nl>
Nightly update still fails sometimes because of disk space:
https://github.com/hiddewie/OpenRailwayMap-vector/actions/runs/20937798180/job/60164501320#step:12:9.

Prune the Docker daemon to retrieve disk space before outputting the
database image.
The OSM data has been updated so the search results are returned in a
slightly different order.
Part of #413 

When a route is rendered, show the stops as well.

The popup also includes the name the reference, local reference and
whether the stop is entry/exit only.

In the future we might change the stop icon based on whether it is
entry/exit only.

Additionally in the future, we might show the stop names with top
priority on the map.
Add funicular, monorail and miniature railway routes to the import.

Part of
#413 (comment).
Updated colors for various transportation entities and added new entries
for US railroads.

---------

Co-authored-by: Hidde Wieringa <hidde@hiddewieringa.nl>
Followup of #774

Part of #413.

During import of the new route types, the SQL was not updated to allow
the new route types. See
https://github.com/hiddewie/OpenRailwayMap-vector/actions/runs/21190217967/job/60954740748.
See https://wetten.overheid.nl/BWBR0017707/2026-01-01

Signal 291c (P bord, permissief), and signal 251 (special danger
location).

See wiki
https://wiki.openstreetmap.org/wiki/OpenRailwayMap/Tagging_in_Netherlands#Main_signals

(http://localhost:8000/#view=17.4/52.225781/6.858487&style=signals):
<img width="651" height="743" alt="image"
src="https://github.com/user-attachments/assets/4874c502-0861-4e7c-825a-3e326fc7b2ab"
/>

(http://localhost:8000/#view=16.44/52.899899/4.80016&style=signals):
<img width="438" height="475" alt="image"
src="https://github.com/user-attachments/assets/a0ac4c27-c81d-4aab-8602-b818eb1c6ff5"
/>
Currently UI tests are failing:
https://github.com/hiddewie/OpenRailwayMap-vector/actions/runs/21296575618/job/61303682120.

Also document how to run them locally.

Chrome fails to create an OpenGL context, so all tests fail there.
Instead, run all the UI tests (both ARM64 and AMD64) on Firefox.
Part of #413

Part of #780

Optimize the fetching of stations. This query became very slow (order of
seconds runtime) since the addition of the list of routes to the
stations.

## Query 1: station labels

Test query:
```sql
select standard_railway_text_stations(8, 137, 98, '{"lang":"it"}')
```
which translates to
```sql
explain analyze SELECT
  ST_AsMVTGeom(way, ST_TileEnvelope(8, 137, 98), extent => 4096, buffer => 64, clip_geom => true) AS way,
  id,
  osm_id,
  osm_type,
  feature,
  state,
  station,
  station_size,
  railway_ref as label,
  name,
  COALESCE(name_tags['name:' || (('{"lang":"it"}'::jsonb)->>'lang')::text], name) as localized_name,
  count,
  uic_ref,
  operator,
  operator_color,
  network,
  position,
  wikidata,
  wikimedia_commons,
  wikimedia_commons_file,
  image,
  mapillary,
  wikipedia,
  note,
  description,
  yard_purpose,
  yard_hump,
  station_routes
FROM railway_text_stations
WHERE way && ST_TileEnvelope(8, 137, 98)
  AND name IS NOT NULL;
```

Query plan before:
```
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|QUERY PLAN                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|Subquery Scan on railway_text_stations  (cost=64485.10..64522.71 rows=59 width=667) (actual time=1738.058..1738.275 rows=196.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
|  Buffers: shared hit=152441                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
|  ->  Sort  (cost=64485.10..64485.25 rows=59 width=708) (actual time=1738.035..1738.051 rows=196.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
|        Sort Key: (CASE WHEN (gs.state <> 'present'::text) THEN 100 WHEN ((gs.feature = 'station'::text) AND (gs.station = 'light_rail'::text)) THEN 450 WHEN ((gs.feature = 'station'::text) AND (gs.station = 'subway'::text)) THEN 400 WHEN (gs.feature = 'station'::text) THEN 800 WHEN ((gs.feature = 'halt'::text) AND (gs.station = 'light_rail'::text)) THEN 500 WHEN (gs.feature = 'halt'::text) THEN 550 WHEN (gs.feature = 'tram_stop'::text) THEN 300 WHEN (gs.feature = 'service_station'::text) THEN 600 WHEN (gs.feature = 'yard'::text) THEN 700 WHEN (gs.feature = 'junction'::text) THEN 650 WHEN (gs.feature = 'spur_junction'::text) THEN 420 WHEN (gs.feature = 'site'::text) THEN 600 WHEN (gs.feature = 'crossover'::text) THEN 700 ELSE 50 END) DESC NULLS LAST, gs.importance DESC NULLS LAST|
|        Sort Method: quicksort  Memory: 73kB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
|        Buffers: shared hit=152441                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
|        ->  Merge Left Join  (cost=9.56..64483.36 rows=59 width=708) (actual time=10.438..1737.101 rows=196.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
|              Merge Cond: ((gs.operator[1]) = ro.name)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
|              Buffers: shared hit=152441                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
|              ->  Sort  (cost=9.29..9.43 rows=59 width=449) (actual time=0.794..0.910 rows=196.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
|                    Sort Key: (gs.operator[1])                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
|                    Sort Method: quicksort  Memory: 108kB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
|                    Buffers: shared hit=43                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
|                    ->  Index Scan using grouped_stations_with_importance_center_index on grouped_stations_with_importance gs  (cost=0.28..7.55 rows=59 width=449) (actual time=0.076..0.313 rows=196.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
|                          Index Cond: (center && '0103000020110F00000100000005000000A0922B4E777F3541066FF8FE58515141A0922B4E777F35418A4F24C138EA5141B014DB56F6E237418A4F24C138EA5141B014DB56F6E23741066FF8FE58515141A0922B4E777F3541066FF8FE58515141'::geometry)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
|                          Filter: (name IS NOT NULL)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
|                          Rows Removed by Filter: 6                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
|                          Index Searches: 1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
|                          Buffers: shared hit=43                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
|              ->  Index Scan using railway_operator_name on railway_operator ro  (cost=0.28..12.68 rows=733 width=31) (actual time=0.022..0.310 rows=453.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
|                    Index Searches: 1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
|                    Buffers: shared hit=302                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
|              SubPlan 1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
|                ->  Aggregate  (cost=1092.37..1092.38 rows=1 width=32) (actual time=8.842..8.842 rows=1.00 loops=196)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
|                      Buffers: shared hit=152096                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
|                      ->  Seq Scan on routes r  (cost=0.00..1090.16 rows=126 width=64) (actual time=6.826..8.832 rows=1.08 loops=196)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
|                            Filter: (ARRAY[osm_id] <@ gs.route_ids)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
|                            Rows Removed by Filter: 25132                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
|                            Buffers: shared hit=152096                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
|Planning:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
|  Buffers: shared hit=3                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
|Planning Time: 0.951 ms                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
|Execution Time: 1738.698 ms                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
```

Query plan after:
```
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|QUERY PLAN                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|Subquery Scan on railway_text_stations  (cost=118.14..195.27 rows=121 width=813) (actual time=3.527..3.620 rows=84.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
|  Buffers: shared hit=1125                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
|  ->  Sort  (cost=118.14..118.44 rows=121 width=853) (actual time=3.512..3.523 rows=84.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
|        Sort Key: (any_value(CASE WHEN (gs.state <> 'present'::text) THEN 100 WHEN ((gs.feature = 'station'::text) AND (gs.station = 'light_rail'::text)) THEN 450 WHEN ((gs.feature = 'station'::text) AND (gs.station = 'subway'::text)) THEN 400 WHEN (gs.feature = 'station'::text) THEN 800 WHEN ((gs.feature = 'halt'::text) AND (gs.station = 'light_rail'::text)) THEN 500 WHEN (gs.feature = 'halt'::text) THEN 550 WHEN (gs.feature = 'tram_stop'::text) THEN 300 WHEN (gs.feature = 'service_station'::text) THEN 600 WHEN (gs.feature = 'yard'::text) THEN 700 WHEN (gs.feature = 'junction'::text) THEN 650 WHEN (gs.feature = 'spur_junction'::text) THEN 420 WHEN (gs.feature = 'site'::text) THEN 600 WHEN (gs.feature = 'crossover'::text) THEN 700 ELSE 50 END)) DESC NULLS LAST, (any_value(gs.importance)) DESC NULLS LAST|
|        Sort Method: quicksort  Memory: 53kB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
|        Buffers: shared hit=1125                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
|        ->  HashAggregate  (cost=103.35..113.95 rows=121 width=853) (actual time=2.903..3.312 rows=84.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
|              Group Key: gs.id, gs.center                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
|              Filter: (any_value(gs.name) IS NOT NULL)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
|              Batches: 1  Memory Usage: 216kB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
|              Buffers: shared hit=1125                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
|              ->  Nested Loop Left Join  (cost=11.93..84.44 rows=122 width=490) (actual time=1.372..2.209 rows=216.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
|                    Buffers: shared hit=1125                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
|                    ->  Hash Right Join  (cost=11.64..28.01 rows=122 width=434) (actual time=1.345..1.648 rows=216.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
|                          Hash Cond: (ro.name = gs.operator[1])                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
|                          Buffers: shared hit=477                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
|                          ->  Index Scan using railway_operator_name on railway_operator ro  (cost=0.28..12.68 rows=733 width=31) (actual time=0.025..0.266 rows=733.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
|                                Index Searches: 1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
|                                Buffers: shared hit=434                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
|                          ->  Hash  (cost=9.84..9.84 rows=122 width=425) (actual time=1.110..1.111 rows=216.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
|                                Buckets: 1024  Batches: 1  Memory Usage: 108kB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
|                                Buffers: shared hit=43                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
|                                ->  Subquery Scan on gs  (cost=0.28..9.84 rows=122 width=425) (actual time=0.090..0.564 rows=216.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
|                                      Buffers: shared hit=43                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
|                                      ->  ProjectSet  (cost=0.28..8.62 rows=122 width=525) (actual time=0.088..0.513 rows=216.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
|                                            Buffers: shared hit=43                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
|                                            ->  Index Scan using grouped_stations_with_importance_center_index on grouped_stations_with_importance  (cost=0.28..7.55 rows=61 width=449) (actual time=0.072..0.211 rows=202.00 loops=1)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
|                                                  Index Cond: (center && '0103000020110F00000100000005000000A0922B4E777F3541066FF8FE58515141A0922B4E777F35418A4F24C138EA5141B014DB56F6E237418A4F24C138EA5141B014DB56F6E23741066FF8FE58515141A0922B4E777F3541066FF8FE58515141'::geometry)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
|                                                  Index Searches: 1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
|                                                  Buffers: shared hit=43                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
|                    ->  Index Scan using routes_osm_id_idx on routes r  (cost=0.29..0.45 rows=1 width=64) (actual time=0.002..0.002 rows=1.00 loops=216)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
|                          Index Cond: (osm_id = gs.route_id)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
|                          Index Searches: 216                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
|                          Buffers: shared hit=648                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
|Planning Time: 1.451 ms                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
|Execution Time: 4.138 ms                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
```

Execution time goes from 1.8 seconds to 4ms.


## Query 2: station bubbles

Less impact, because only executed at higher zooms (so much smaller
bounding box and amount of data).

Test query:
```sql
select standard_railway_grouped_stations(13, 7179, 3254)
```
which translates to
```sql
explain analyze SELECT
  gs.id,
  nullif(array_to_string(osm_ids, U&'\001E'), '') as osm_id,
  nullif(array_to_string(osm_types, U&'\001E'), '') as osm_type,
  ST_AsMVTGeom(buffered, ST_TileEnvelope(13, 7179, 3254), extent => 4096, buffer => 64, clip_geom => true) AS way,
  feature,
  state,
  station,
  railway_ref as label,
  gs.name,
  uic_ref,
  nullif(array_to_string(operator, U&'\001E'), '') as operator,
  nullif(array_to_string(network, U&'\001E'), '') as network,
  nullif(array_to_string(position, U&'\001E'), '') as position,
  COALESCE(
    ro.color,
    'hsl(' || get_byte(sha256(operator[1]::bytea), 0) || ', 100%, 30%)'
  ) as operator_color,
  (select nullif(array_to_string(array_agg(r.osm_id || U&'\001E' || coalesce(r.color, '') || U&'\001E' || coalesce(r.name, '')), U&'\001D'), '') from routes r where ARRAY[r.osm_id] <@ gs.route_ids) as station_routes,
  nullif(array_to_string(wikidata, U&'\001E'), '') as wikidata,
  nullif(array_to_string(wikimedia_commons, U&'\001E'), '') as wikimedia_commons,
  nullif(array_to_string(wikimedia_commons_file, U&'\001E'), '') as wikimedia_commons_file,
  nullif(array_to_string(image, U&'\001E'), '') as image,
  nullif(array_to_string(mapillary, U&'\001E'), '') as mapillary,
  nullif(array_to_string(wikipedia, U&'\001E'), '') as wikipedia,
  nullif(array_to_string(note, U&'\001E'), '') as note,
  nullif(array_to_string(description, U&'\001E'), '') as description
FROM grouped_stations_with_importance gs
       LEFT JOIN railway_operator ro
                 ON ro.name = operator[1]
WHERE buffered && ST_TileEnvelope(13, 7179, 3254);
```

Query plan before:
```
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|QUERY PLAN                                                                                                                                                                                                                                      |
+-------------------------------…
Fixes #787

For (grouped) stations that have no `route_ids`, also query `null`
values for the routes IDs, to allow a null-join.

Now yards and service stations and and junctions are shown again.

<img width="860" height="627" alt="image"
src="https://github.com/user-attachments/assets/1db4dd54-bb4c-43df-8bde-d4446b34841e"
/>
Hi there, having again read the instructions of railway signalling and
seeing in situ examples of signals, I had to make a (last I hope) rework
of signalling (based similarly on German Hp, Hl and Ks systems). It
highly influences the tagging of well majority of signals, but in near
future I will make adjustments.

Some of tagging was simplified, since some signals must appear in
combined signals (eg. the next semaphore shows "stop")

Minor changes were made to shunting signal (as the sign form didn't
render) and missing form of some signals (that forced writing additional
line out of template).

Thanks in advance

---------

Co-authored-by: Hidde Wieringa <hidde@hiddewieringa.nl>
Before, a single error with the filename of a single file that does not
exist.

After, all errors are concatenated together into a single large error:
```
Error: Failed to resolve promises: Error: Failed to resolve promises: Error: Failed to resolve promises: Error: ENOENT: no such file or directory, open 'symbols/pl/s6-3-main.svg', Error: Failed to resolve promises: Error: Failed to resolve promises: Error: ENOENT: no such file or directory, open 'symbols/pl/s9-13a-4.svg', Error: Failed to resolve promises: Error: Failed to resolve promises: Error: ENOENT: no such file or directory, open 'symbols/pl/s6-3.svg', Error: ENOENT: no such file or directory, open 'symbols/pl/s9-3.svg'
```
Adds preliminary route indicators.

See https://www.railsigns.uk/photos/p_route2.html#pic_priup for some
photos, and https://www.railsigns.uk/sect6page5.html for a description.

I know that there are a few tagged on the approach to Reading West from
Southcote Junction.
Though, be aware that they were added using a slightly different tag
today, before being changed (see description of commit
689f4b5).
1. Changed color of '인천교통공사' to #ff671f, one of another symbolic color
of the operator, in order to visually differentiate it from '공항철도주식회사'.
2. Moved '(주)우진메트로' to #95296f because it was wrongly categorized. (and
those three operators belong to same parent company)
3. Added '우진메트로양산'.
<img width="1096" height="1392" alt="image"
src="https://github.com/user-attachments/assets/affa432e-2aaa-474a-a7fc-38059939123d"
/>
Fixes #794

If the user has not configured the preferred track layer visualization,
the track layer will default to the gauge. The configuration UI also
shows this default. However the map did not incorporate it in all
places, showing every line as having an unknown gauge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.