Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic z-ordering across groups of style layers #2108

Open
ZeLonewolf opened this issue Jan 30, 2023 · 40 comments
Open

Dynamic z-ordering across groups of style layers #2108

ZeLonewolf opened this issue Jan 30, 2023 · 40 comments
Labels
enhancement New feature or request need more info Further information is requested

Comments

@ZeLonewolf
Copy link
Contributor

ZeLonewolf commented Jan 30, 2023

Motivation

The OSM Americana project would like to efficiently and properly render "stacked" bridges and tunnels, in which multiple bridges or tunnels overlap each other. This occurs in large dense cities.

While there is currently a line-sort-key in the style specification, this only works on a single layer. In order to draw the various combinations of road, bridge, and tunnel, we are rendering a casing, a fill, sometimes a casing dash pattern, and sometimes an inner fill dash pattern. It is not currently possible in the style spec to merge all these together into a single layer, and thus each component of the style must be rendered as a separate layer.

What is needed is a group-line-sort-key in order to apply the sort-key logic across a consecutive group of layers.

For example, this location in Boston has several overlapping bridges:
image

The overlap is indicated with tagging of layer. So the first bridge might be layer=1, the second bridge is layer=2 and so forth.

Stacked roads are represented in vector tiles with an attribute that indicates the z-order of each road:
image

The desired end-state looks something like this, where the roads are drawn casing-fill-casing-fill-casing-fill for each layer. This is outlined in #2108 (comment):
image

Currently, the only way to do this is to repeat the entire road layer for layer=1, layer=2, etc., up to some value of N where nobody has mapped two or more overlapping roads with a value of layer that's greater than N. In practice, 5 layers should cover all cases on earth for roads (as of 2023). However, there's no guarantee that mappers use small values of layer -- the only thing that you can count on is the ordering. This is the hack currently used in the OSM Americana project.

In Sydney, Australia there's a series of similarly overlapping tunnels. However, these do not overlap properly (ZeLonewolf/openstreetmap-americana#27) -- the layer values descend to -4, -5, etc., well beyond that style's assumed limit of -2 for tunnels (after all -- how stacked could tunnels possibly be?).

image

Duplicating the entire transportation layer code to achieve bridge/tunnel layering is, a MASSIVE inflation of the layer count, and one of the reasons that the OSM Americana style.json is nearly a megabyte in size and most certainly is a performance problem.

Usage

Ideally, We would like to be able to specify that a group of layers should obey a sort-order key, where multiple passes are made across the group of layers, rendering one layer value at a time until all layer values are exhausted. It's sufficient to assume that the group of layers are all consecutive.

@HarelM
Copy link
Member

HarelM commented Jan 30, 2023

The fact that the text is 1 Mb doesn't mean the traffic is 1Mb and the fact that there are similar text is that file means compression will work better. Saying it's "probably" the reason is not data driven, can you please try and measure?

Regarding the duplication and ordering there are two possible solution from my point of view

  1. Solve it in an editor: much like complied code, you can have an editor that will take care of this and spit out a style.json that has this in it
  2. Define a very complicated spec that will be hard to implement and get right, the fact that you're having a hard time (from my understanding) defining exactly what you need in terms of spec is a bad sign.
  3. There was a proposition for casing-* to solve all kind of road casing. While I think casing isn't a good name, if this will solve the problem it might be a good middle ground.

@HarelM HarelM added enhancement New feature or request need more info Further information is requested labels Jan 30, 2023
@ZeLonewolf
Copy link
Contributor Author

ZeLonewolf commented Jan 30, 2023

The fact that the text is 1 Mb doesn't mean the traffic is 1Mb and the fact that there are similar text is that file means compression will work better. Saying it's "probably" the reason is not data driven, can you please try and measure?

Sure, here are some cursory statistics (and of course I could generate more as needed):

  1. For bridges of all kinds, we use 39 layers. The total stringified size of that layer collection is 119,761 bytes.
  2. Since we've duplicated the bridge layer for layer=1 through layer=4, that means this 119K of style code is repeated three additional times -- 359,283 bytes of style code exist because we don't have the ability to say "render these in layer order"
  1. Solve it in an editor: much like complied code, you can have an editor that will take care of this and spit out a style.json that has this in it

This doesn't make much sense, and it suggests that I haven't described the problem well enough for people not familiar with the challenge of styling complex features like layered roads. Obviously I could change the loop value and generate copies of the bridge layer that run from 1 to 100, but we've found that performance degrades significantly as the number of layers increases. We used to have over 1,000 layers and it would crash web browsers trying to load. We've gotten it down to a bit over 300 layers with some creative use of the style expression.

The approach taken by trivial stylings is just to give up and not even pretend that bridges can overlap, as shown in this OSM Bright rendering of the bridge ramps north of Boston:
image

Now, if maplibre/maplibre#167 and/or maplibre/maplibre#164 were solved, that would certainly reduce the size of the 119K road layer by quite a bit, since each iteration of casing/fill/dashes means the creation of a new layer. However, it doesn't fix the fact that I'd still have to generate potentially infinite numbers of copies of the bridge layer in order to handle unbounded values of layer that only represent ordering.

The layer tag in OSM is used as a sort ordering key and tends towards zero (most cases in the map of course are things like a single bridge, layer=1, or a single tunnel layer-1, and it's only in big city infrastructure that you tend to get up into larger values of layer as the stacks get more complicated. The taginfo entry shows that most values are smaller, but there are still hundreds of cases where the layer value gets to plus or minus 7. The point is that we shouldn't have to duplicate entire style layers just to get around the fact that we don't have a sort key that can work on a group of layers.

  1. Define a very complicated spec that will be hard to implement and get right, the fact that you're having a hard time (from my understanding) defining exactly what you need in terms of spec is a bad sign.

I'll take the heat for not describing the problem well, but I hope you can appreciate that a team of pretty smart people haven't been able to solve this beyond kludgery, and that I'm not making up the fact that we have this problem. I'm also not making up the fact that osm-carto (really, CartoCSS stacks generally) are able to solve this problem for arbitrary values of layer but right now, this is something maplibre cannot do.

Also I don't really think that sort key ordering of a group is conceptually complicated. I want to render ALL bridges of any type at layer=1. Then, I want to render ALL bridges of any type at layer=2. And so forth until we've exhausted all layer values present in the data.

Does maplibre intend to be powerful enough to match the features in CartoCSS? Hopefully the answer is "yes" and we're not just targeting lightweight use cases.

  1. There was a proposition for casing-* to solve all kind of road casing. While I think casing isn't a good name, if this will side the problem it might be a good middle ground.

Yes, that's maplibre/maplibre#164, which would certainly help reduce our layer count though it wouldn't solve arbitrary layering, which is what I'm attempting to describe.

To be clear -- I don't have the solution handy for how to do this, I'm just looking for the project to acknowledge that this is currently a gap that prevents it from matching other tech stacks feature-for-feature.

@wipfli
Copy link
Member

wipfli commented Jan 30, 2023

I know it is not ideal, but packing all higways into a single layer with level instructions can solve this problem. https://wipfli.guthub.io/single-highway-layer. For this to be complete, we would need data-driven styling of line caps and dash arrays.

@adamfranco
Copy link

Link above has a typo, should be https://wipfli.github.io/single-highway-layer instead of guthub. ;-)

@wipfli
Copy link
Member

wipfli commented Jan 30, 2023

Thanks @adamfranco. But just to understand the problem, which one do you think is more problematic for you?:

a) The style.json gets large (slow transmission, lot of mobile data usage) and can only handle a finite number of levels.
b) The rendering is slow with a large style

@zekefarwell
Copy link

I know it is not ideal, but packing all higways into a single layer with level instructions can solve this problem

To truly solve the problem it would have to be not just highways, but waterways, pipelines, buildings, and any other features that can have a layer=* tag. It would be a bit of an everything layer. Surley could be doable, but not sure if that's the best angle from which to solve the problem.

@zekefarwell
Copy link

b) The rendering is slow with a large style

Definitely this one. Even with a very fast connection rendering is slow and depends heavily on CPU speed.

@adamfranco
Copy link

adamfranco commented Jan 30, 2023

For me the bigger issue is (b). If one interacts with a complex map rendering using feature-rich OpenMapTiles (like Americana) and zooms at all, then the vector tiles may include ~1MB of data per zoom level. With just a bit of interaction the data loading of the vector tiles will greatly exceed the data-transfer of the style itself.

@HarelM
Copy link
Member

HarelM commented Jan 30, 2023

Thanks for the detailed answer, but I'm still missing a clear problem definition as @wipfli mentioned:
Is the problem the size of the file?
The number of the layers?
The missing ability to set render order (although I believe one can do it by simply ordering the layers inside the file, but I might be wrong)?
The performance of a lot of layers?
A missing spec definitions, if so, which?
The maintenance one need to do when there are multiple layers that are almost identical?
All of the above?
I don't mean to be rude, just want to better understand the problem statement before jumping to solutions, different problems may have different solutions...

@wipfli
Copy link
Member

wipfli commented Jan 30, 2023

I noticed that Google Maps shows physically correct level ordering including different styles for tunnels and bridges only from something like z14. At lower zooms, they just do highway=motorway on top of highway=trunk on top of highway=primary etc. I think this can have big performance impact. So if rendering performance is the main issue, I would say lets start experimenting with cartographic simplifications as the one done by Google / Apple maps. Note that this actually also looks better because important roads have fewer visual discontinuities which usually get cased by bridges/tunnels in OpenMapTiles-based map styles.

@ZeLonewolf
Copy link
Contributor Author

The main issue is the ability to render complex layerings at high zoom (13 or 14 is where the distinctions are generally visible). The discussion of performance is to demonstrate the pitfalls of naïve solutions such as "just replicate the layers multiple times". If we are able to jam our entire highway style into a single layer, that might minimize the problem, but it also kick the can down the road on more complex combinations like roads above or below buildings and that sort of thing.

@wipfli
Copy link
Member

wipfli commented Jan 30, 2023

Maybe then the scope or goal of this issue is actually to implement dynamic z-ordering across multiple MapLibre GL JS style layers...

@ZeLonewolf
Copy link
Contributor Author

Maybe then the scope or goal of this issue is actually to implement dynamic z-ordering across multiple MapLibre GL JS style layers...

Yes, that's exactly right, sorry if I didn't describe it well.

@wipfli
Copy link
Member

wipfli commented Jan 30, 2023

OK I don't know rendering stuff, but maybe if we had some sort of off-screen rendering we could first draw lines and polygons to the off-screen render target and only then decide how to overlap them in a final render step based on some sort of global z-sort-key

@ZeLonewolf ZeLonewolf changed the title Render support for complex layered objects Dynamic z-ordering across groups of style layers Jan 30, 2023
@ZeLonewolf
Copy link
Contributor Author

This is also apparently a duplicate of a Mapbox issue: mapbox/mapbox-gl-js#1349

@ZeLonewolf
Copy link
Contributor Author

The missing ability to set render order (although I believe one can do it by simply ordering the layers inside the file, but I might be wrong)?

This was my intent in opening this issue. Granted there are a number of related performance side effects that @zekefarwell and @adamfranco are laying out, but ultimately I can't z-order a group of layers to an arbitrary depth.

@HarelM
Copy link
Member

HarelM commented Jan 30, 2023

I'm lost... :-(

@ZeLonewolf
Copy link
Contributor Author

I'll mock up some illustrations which will hopefully better express the problem.

@ZeLonewolf
Copy link
Contributor Author

Suppose we have a stacked interchange as follows, with 4 different levels of bridges. In other words, the lowest level (layer=1) is a motorway viaduct, and there are additional bridges at higher levels, tagged layer=2,3,4. It would look something like this in the data:

image

We would desire a final result that looks something like this (casing and fill). Note how the layering between the different levels is discernible:

image

For example, in this stacked interchange in Boston, you can clearly see which bridge is on top of which other bridge:

image

So, in order to achieve the effect in our mock example, you would need 8 passes as follows:

image

image

image

image

image

image

image

image

@HarelM
Copy link
Member

HarelM commented Jan 30, 2023

This describes the current way things work, I'm falling to understand the problem statement... :-/

@ZeLonewolf
Copy link
Contributor Author

The problem is that I have to anticipate the highest possible value of layer that might exist in in the data, let's call that N. I then have to replicate N style layers for every feature that I want to participate in the layering scheme.

@HarelM
Copy link
Member

HarelM commented Jan 30, 2023

Is the problem the replication or that you don't know what N is?

@ZeLonewolf
Copy link
Contributor Author

ZeLonewolf commented Jan 30, 2023

The problem is that I don't know what N is. Replication is easy, it's just a for loop!

When we implemented this originally, we crawled the map looking for worst-case examples of stacked bridges and found that N=5 seemed to cover all the worst cases for roads. There's a few examples of layer>5 once you start including things like pedestrian overpasses over viaducts. So in other words, there's a copy of the road layer for 1 through 4 and then a final layer for all layer>=5.

The moment someone tags two overlapping roads with layer values >=5 (for example, a layer=6 road on top of a layer=5 road), it'll render like an intersection instead of an overlap. While the wiki does recommend that people use the smallest possible values of layer, it's entirely valid to use larger numbers as long as the sort ordering is correct (higher layers have larger layer values).

Now at this point you are probably saying "who cares, you've got your five copies of your road layer, it's rendering the things, and it covers all the real world examples thrown out."

The problem now becomes that:

  1. It makes the style.json huge (numbers above)
  2. It performs poorly. I don't have a benchmark for assessing this but I'd be happy to run one if such a thing exists, so this is a subjective assessment, but we've put quite a bit of effort into speeding up performance and "too many layers" always seems to be the biggest issue.

I've already provided the numbers on the style.json size, and it should be obvious that a smaller style.json will load more quickly. We've also identified a very clear correlation between the number of layers and style performance, where >1000 layers means "crashes some web browsers" whereas a few hundred layers means "is noticeably laggy but still gets there eventually".

So you can take your pick from the following problem statements that are all equally valid here:

  1. I can't handle layer overlaps above a certain value because at some N, the style becomes so big that it crashes web browsers, and I'm relying on mappers never to use a value of layer that's bigger than my N.
  2. The layer-copying workaround for the lack of a group-sort function performs poorly
  3. The layer-copying workaround for the lack of a group-sort makes the style.json huge

Of all the problem statements, the number 2 is the most in-your-face, number 1 is dependent on both the decisions made by mappers and the complexity of the real world and will cause wrong rendering for cases of valid mapping, and number 3 is just unnecessary bloat that competes with tile data for network bandwidth.

@wipfli
Copy link
Member

wipfli commented Jan 30, 2023

Thanks for the illustrations. I guess maplibre has just a limitation here that it cannot handle arbitrary ordering between style layers.

@wipfli
Copy link
Member

wipfli commented Jan 31, 2023

The way I understand this issue is that it is not really a feature request, but more a description of the architecture that Mapbox designed. Allowing sorting only within a single layer is maybe just a limitation of the design they chose. And I think it is important for developers using MapLibre GL JS / Native to understand this limitation when designing map styles.

@ZeLonewolf can you maybe condense the insights from this thread in the opening paragraph of the issue?

I think we have a nice documentation here now of the current system and it would be great to take out the most relevant info and put it at the top of the thread. Like that, new people that come here and read this thread understand quickly the limitations of MapLibre.

@wipfli
Copy link
Member

wipfli commented Jan 31, 2023

Looking into the future we can also think about what would be useful modifications to the style specification https://maplibre.org/maplibre-gl-js-docs/style-spec/, but I would like to separate such an enhancement discussion from the description of the current state.

@hallahan
Copy link

You could just generate vector tiles where everything road, tunnel, bridge related is in the same layer?

@ZeLonewolf
Copy link
Contributor Author

@ZeLonewolf can you maybe condense the insights from this thread in the opening paragraph of the issue?

I've updated the summary, hopefully that's more clear.

@ZeLonewolf
Copy link
Contributor Author

You could just generate vector tiles where everything road, tunnel, bridge related is in the same layer?

That's already the case and is irrelevant to this issue. Here's a location with stacked bridges in OpenMapTile's transportation layer.

I think perhaps you meant to suggest that all roads be generated in one style layer, which is not currently possible due to the lack of support for casing, casing dash patterns and/or fill dash patterns, all of which we would need in order to condense our road style down to a single layer. Then we'd be able to use line-sort-key.

@zekefarwell
Copy link

zekefarwell commented Jan 31, 2023

I'm a bit surprised at the hesitance I'm reading in this thread. My understanding is that MapLibre aims to be the best open source vector tile renderer for OSM data (as well as other sources of course). With that in mind I had thought there would be a general openness to expanding functionality to match what is possible in Mapnik based raster maps.

The feature we are discussing in this thread is necessary for any OSM based map that aims to live up to the standard set by OpenStreetMap Carto. I highly recommend reading this post that dives into layered feature rendering in detail: https://imagico.de/blog/en/navigating-the-maze-part-1/ . The sense I've gotten from this thread is that improvements in this problem space are not welcome in MapLibre. Perhaps I've just gotten the wrong impression though.

@zstadler
Copy link
Contributor

Divergence alert!

Before using Mapbox-GL, the Israel Hiking Map was produced as a raster map using the no-longer-maintained Maperitive program. When writing the style definitions for Maperitive we didn't need to bother ourselves with OSM layers in the style definition.

For example, this interchange was correctly rendered while the style described just how each highway should be rendered and no references to the OSM layer:

image

The approach taken by Maperitive is this:

For features that come from the OSM world, another thing that influences the drawing priority is the layer tag. This tag takes precedence over the ordering of rules and features mentioned above. So a bridge with layer=1 will be drawn above a canal OSM way if the canal has a layer value of 0 or below (or it doesn't have a layer value specified at all).

If I may proposed a similar approach for MapLibre, it could be this:

The elements in each tile are grouped by OSM layer and the rendering is done using the style definition in increasing layer value from the minimum to the maximum values that exist in a tile. Elements with no layer tag are grouped with layer=0 elements.

An interesting implication of this idea is that approach does not need any spec change. It can be an non-default option for Maplibre-GL-JS. Maps that want to leverage it will need to turn it on explicitly, while the rest of the world maps continue to work as before.

Clearly this is only a rough direction that needs further refinement before it can turn into an implementation.

@ZeLonewolf
Copy link
Contributor Author

The elements in each tile are grouped by OSM layer and the rendering is done using the style definition in increasing layer value from the minimum to the maximum values that exist in a tile. Elements with no layer tag are grouped with layer=0 elements.

An interesting implication of this idea is that approach does not need any spec change. It can be an non-default option for Maplibre-GL-JS. Maps that want to leverage it will need to turn it on explicitly, while the rest of the world maps continue to work as before.

This would not work for tunnels, which typically have a layer value <0. Generally you want tunnels to be drawn on top of surface features even though they're logically underneath them.

@zstadler
Copy link
Contributor

zstadler commented Feb 2, 2023

This would not work for tunnels, which typically have a layer value <0. Generally you want tunnels to be drawn on top of surface features even though they're logically underneath them.

You're right. This idea was too simplistic. Maperitive has a higher-level "drawing priority" on top of the OSM layer values:

Each of Maperitive map symbols has an intrinsic drawing priority. There is no point in displaying a text label which is then covered by some grassy field - text labels are for humans and if they are not visible, they have no function, since no one can read them. That's why all text symbols in Maperitive are drawn above anything else. The next symbol in priority is an icon (so texts can overlap icons, but not vice versa). After the icons, we have lines and contours. Below these come fill symbols. So poor old fill symbols are constantly pushed around (or below, to be precise) by their older brothers.

In addition, the default "drawing priority" of a layer can be overwritten. For example, some terrestrial contour lines do not align well with the outlines of water bodies and we want water areas to be drawn above the contour lines while the contour lines need to be drawn above other fill area, such as land use.

@ZeLonewolf
Copy link
Contributor Author

I'm exploring a mechanism where a layer can have a key that means "sort with previous", which indicates that the sort key should apply across multiple layers. It would reduce the size of Americana's style JSON by 2/3 and drop the layer count from over 300 to 142. However, it will be a fair amount of code to implement, and I don't know how it will perform yet. The mechanism I'm envisioning would have a version of the drawLine() function that can accept an array of layers and then slice and dice the layer buckets to get the desired draw ordering. Of course, this is all apocryphal until I can get it working.

@1ec5
Copy link
Contributor

1ec5 commented Apr 16, 2023

It is not currently possible in the style spec to merge all these together into a single layer

By the way, Mapbox GL JS started work on a line casing property: mapbox/mapbox-gl-js#4162 (comment). However, it doesn’t seem to be documented or usable yet, and it doesn’t address the need for other line components such as dash overlays.


Developers also want to be able to group style layers to implement visually complex markers. For example, it’s very common to want to put a solid colored disc behind a marker icon to signify that it’s clickable. Of course, one can redesign the icons themselves to include the disc, but many developers need more flexibility. For example, the icon’s image may depend on one property while the circle’s color or size depends on another; combining the two would bloat the sprite sheet.

Instead, a common workaround is to put a circle layer behind the symbol layer. This works until the point features end up too close to each other, causing the discs to overlap with each other without overlapping symbols in the symbol layer: mapbox/mapbox-gl-js#10002 mapbox/mapbox-gl-js#10021. With symbol collision enabled, discs and icons collide independently, ruining the illusion of these elements being grouped: mapbox/mapbox-gl-js#6025.1

Developers can avoid these issues by eschewing the style specification entirely, replacing their layers with DOM-backed markers or view-backed annotations (on iOS/macOS). These alternatives aren’t well-integrated into the style: they can’t underlap any style layers, and tilting the map ruins the illusion of these overlays being part of the map. Drawing images on demand using styleimagemissing or a custom OpenGL layer requires nontrivial platform-specific code. The ability to group layers would solve these problems, enabling developers to focus on writing styles instead of platform-specific workarounds.

Footnotes

  1. These specific Mapbox issues aren’t terribly important; they’re just examples of one of the most frequently asked questions among developers using GL JS or its native counterparts.

@bdon
Copy link
Contributor

bdon commented Aug 14, 2023

I made a proof of concept of arbitrary depth stacking that requires tileset-side support but no additional features in MapLibre GL. The essence is that for -1,0,1, or 97% of layer values, we use the traditional casing layer method, and for the remaining 3% we duplicate the feature and add a casing tag in the tiles that is drawn identical to the casing layer.

As a bonus, we combine 5 different road classifications into one layer using data-driven styles. For the equivalent "traditional" styling we would need 8 (-2,-1,0,1,2,3,4,5 typically) levels, * 5 classifications, * 2 casing or 80 layers. This style is 8 layers, with some caveats you can read about here:

https://github.com/bdon/HighRoadPlus

Sydney (tunnels to -5): link to map


Screenshot 2023-08-14 at 21 31 39

Boston 1/I93: link to map


Screenshot 2023-08-14 at 21 33 31

anyone have another favorite extreme case for testing?

@1ec5
Copy link
Contributor

1ec5 commented Aug 14, 2023

Thanks for documenting and demonstrating this workaround. Duplicating the feature to represent the casing does work, but it’s less than ideal for the reasons you’ve laid out. It reminds me of how the Mapbox Streets source duplicates the union of all waterbodies/waterways to allow for seamless water outlines. Or of how OpenMapTiles includes both the 3D building parts and a redundant building outline from OSM data. In both cases, the redundant features are useful or not depending on the style’s design needs.

OSM Americana has followed some of the documented approach, in terms of minimizing the number of line layers per layer to just three (body, casing, dashes). Unfortunately, for the various kinds of railroad tracks, we’re stuck because of a lack of data-driven styling for line-dasharray: #1235.

As a bonus, we combine 5 different road classifications into one layer using data-driven styles. For the equivalent "traditional" styling we would need 8 (-2,-1,0,1,2,3,4,5 typically) levels, * 5 classifications, * 2 casing or 80 layers.

While some styles color-code roads by road classification, others also implement things like surface or access restrictions using dash arrays.

Moreover, users intuitively expect features to layer based on physical elevation, even on a 2D map. Railroads can go over or under roads; so can buildings and in some cases waterways. But tunnels often still need to draw over the layer that obscures the tunnel in physical space (typically parks and waterbodies, not other roads). It’s a bit of a conundrum.

@bdon
Copy link
Contributor

bdon commented Aug 14, 2023

@1ec5 I think the tunnels over parks/waterbodies thing is addressed already by the majority of map styles -I'm more interested in the railways case. The 8-roads-layer approach I described above can still admit railways in separate layers (not included in those 8) with rail_tunnel, rail, and rail_bridge. Where the approach would fail is when a railway needs a layering relationship with roads layer <=-2 or >=2.

Do you have any specific places in OSM to point to here? I'll go spelunking for these situations, but it seems the common case of intense highway flyovers is negatively correlated to places that have lots of rail ...

Best place to start may be Japanese monorail systems!

@bdon
Copy link
Contributor

bdon commented Aug 14, 2023

I think this case is handled correctly railway & layer=2 https://www.openstreetmap.org/way/115521997#map=19/35.61102/139.75579

So we need to look for layer>=3...

way
  ["railway"]
  ["layer"~"^[3-9]$|^[1-9][0-9]+$"]
  ({{bbox}});
(._;>;);
out;

This finds all layer >=3 railways, then scrub around to find the ones that intersect or run concurrent to roads.

@1ec5
Copy link
Contributor

1ec5 commented Aug 14, 2023

The biggest complication regarding railways is that every distinct type of railway needs a different dash array: spurs and sidings, disused, monorails, narrow gauge, etc. Each of these types needs a separate line layer, which then gets duplicated per physical layer. Once line-dasharray supports data-driven styling, this will cease to be an issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request need more info Further information is requested
Projects
None yet
Development

No branches or pull requests

9 participants