Missing parts on rivers
Impacted Features/Layers
Long rivers like the "Elbe" or "Danupe" are kind of cluttered on low zooms (~7). This also happens in various other places/rivers.
Screenshots
High Zoom (~8)
Low Zoom (~7)
My thoughts on the issue/solution:
I suspect that the reason for this issue comes from the complex relations within OSM dataset, which splits it into multiple polygons. I am not really into the planetiler framework, but I think it would make sense to add some relation management for rivers/streams/canals/riverbanks and combine into MultiPolygons in post-process.
I would appreciate it if someone could me give me some feedback on my thoughts and a brief overview of how the relations should be implemented. I would be happy to implement this, but I failed so far.
Thanks for opening this issue @mxzinke!
When refactoring Water.java we worked a bit on rivers breaking up at low zoom levels. Probably the issue is not related to feature selection based on tags and relations, because when you zoom in, the full river is there. If we had a problem with selecting river polygons based on way/relation tags, then parts would be missing at all zoom levels...
What is more likely to be the cause is that parts of a river polygon fall below the minimal area during post-processing here:
https://github.com/protomaps/basemaps/blob/11807bba74dcb35f27338e4b9274509c838330d4/tiles/src/main/java/com/protomaps/basemap/layers/Water.java#L437
This includes only features in the tiles which are larger than Earth.MIN_AREA (linear dimension in tile pixels, so 1 means a 1x1 square, 2 means a 2x2 square etc).
You can experiment with the function mergeNearbyPolygons and change some settings. Buffer and min feature size has quite some effect on the visual output. Let me know if you need any help getting started.
River polygons in OpenStreetMap can be split into multiple ways, e.g., something like this:
The middle section shares nodes with the outer sections. To merge them into one polygon, we need to apply a buffer and run merge nearby polygons. This should create something like
However, if you apply too much buffering then the result on S-shaped rivers like this example:
Will become something like this:
So it will look a bit like a string of pearls, which is probably also not what we want.
Note that FeatureMerge.mergeNearbyPolygons works on tile pixels, and each tile has 256 pixels. If we consider zoom 7, that means a pixel width of roughly
earth circumference / 2 ** 7 / 256 = 1200 m
At zoom 8 it would be
earth circumference / 2 ** 8 / 256 = 600 m
So you see that as the zoom level increases, the buffering decreases...
Okay, thanks @wipfli for clarifying. I took a deeper look into it.
First, I can clearly say that its really just about rivers. Impacted zoom are 7 and 8. On 9 it is already correctly put together. On zoom 6 or lower, river should be hidden since they are too small anyway.
I also noticed, I can add the waterway lines on lower zooms and add them in the style as a layer below the river polygons. But's an ugly fix. So I looked into you suggesting increase of buffering. Here are my results:
Here the code I used for that in Water.java layer class:
@Override
public List<VectorTile.Feature> postProcess(int zoom, List<VectorTile.Feature> items) throws GeometryException {
items = FeatureMerge.mergeLineStrings(items, 0.5, Earth.PIXEL_TOLERANCE, 4.0);
double mergeFactor = 1;
if (zoom <= 7) {
mergeFactor = 16;
} else if (zoom <= 8) {
mergeFactor = 12;
} else if (zoom <= 9) {
mergeFactor = 8;
} else if (zoom <= 10) {
mergeFactor = 2;
}
double buffer = Earth.BUFFER;
if (zoom >= 7) {
buffer = Earth.BUFFER * Math.pow(2, (zoom - 6) / 2);
}
return FeatureMerge.mergeNearbyPolygons(items, 0, Earth.MIN_AREA, 1 * mergeFactor, buffer);
}
I modified the minArea to be zero (just to test out), gave a higher minDist for merging and a buffer scaling up exponentially
As you can see, not much of a difference. Just some minor details more. I also tested out a bigger Buffer, but this causes the issues already described...
Additionally, I looked into the planetiler-openmaptiles Planetiler-Profile and found out that they're using the osm relations to create WaterwayRelation internally. Could we do similar to make sure polygons relating to the same OSM-Way and are actually combined? Hope it's somehow clear, what I mean.
https://github.com/openmaptiles/planetiler-openmaptiles/blob/3f520f5ab3dc895800feac4764d0476bb0ddaa54/src/main/java/org/openmaptiles/layers/Waterway.java#L146C1-L155C4
Would be awesome to not just workaround these kind of issues, but actually find a robust solution. What do you think?
Can you share an OpenStreetMap way id of a feature which does not get included at zoom 7?
Example the 'Elbe' very long river - Relation 123822 - here are some examples:
Parts shown only on zoom 9 and higher - OSM Way IDs
Parts shown only on zoom 8 and higher - OSM Way IDs:
Is this helpful? Do you need more examples from other rivers?
From what I can tell so far is that the river parts here have exactly the same tags as neighboring river tags. So I think they get through the process function in the same way. However, it probably fails during postProcess to merge and include them. Do you think that is correct?
Could be the cause within postProcess, but wouldn't it be easier to handle the river parts similar to the boundaries layer - via OsmRelationPreprocessor / through the relations? Then we could merge all river parts with same relation in postProcess. Or do I miss something?
It might be worth giving relation processing on rivers a try. Feel free to open a pull request. My understanding is just that during feature selection, all river parts get selected. So even with relation processing, you don't get more selected features. But then during post-processing, i.e., mergeNearbyPolygons, the river parts for some reason don't get merged, then they fall below the area limit and are removed...
@wipfli Are they removed based on area before or after merge? (Since we set Earth.MIN_AREA as a min area on FeatureMerge.mergeNearbyPolygons() in post processing)
I think they are dropped after merging, see https://github.com/onthegomap/planetiler/blob/2c91725f6d048fd60b02d3e7c29bb88838451048/planetiler-core/src/main/java/com/onthegomap/planetiler/FeatureMerge.java#L361
I am a bit of stuck with this issue. And in my eyes, it impacts the visual appeal of the map a lot.
@wipfli Do you know who knows more about it and maybe has more ideas on a potential solution?
I don't unfortunately
Tilezen for reference doesn't show many rivers until z8:
https://pmtiles.io/#map=7.12/50.91/12.549&url=https%3A%2F%2Fr2-public.protomaps.com%2Fprotomaps-sample-datasets%2Ftilezen.pmtiles
I can add the waterway lines on lower zooms and add them in the style as a layer below the river polygons. But's an ugly fix.
I think this is actually the correct solution, because any polygon representing a river's width is going to degenerate to 0 area as we zoom out, and it's not an efficient way to store a linear geometry (double the vertices).
That means at high zooms rivers are doubly represented by both their centerlines (LineString kind=river) and areas (Polygon kind=riverbank)
It looks like right now it's possible for some rivers/canals to have polygons at mid zooms but their centerlines are not appearing ....