Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Each handler can only create one layer? #1322

Answered by adjourn
adjourn asked this question in Q&A
Discussion options

I tried to get around the max zoom 15 limitation (on client-side at least, 15 still includes all data) by adding different zoom level POIs to different layers in order to use maplibre layer minzoom instead of more expensive filter and feature minzoom property combination.

However it seems that one handler can only add features to single layer.

// - if minZoom <=15, layer will be `poi15`
// - if >15, layer will be either `poi16`, `poi17`, etc
String layer = Utils.getLayerName("poi", minZoom);
var feat = features.point(layer);

However only poi15 layer is created. I did double check, other layer names like poi16 are created if I print them out, no errors.
Any idea what's going on here?

You must be logged in to vote

Figured it out on second (or third) round, dumb mistake as they usually are. Cause and fix in last comment:

if (sf.hasTag("barrier", "lift_gate")) { // some feature that has >15 zoom level
 minZoom = 16;
}
// - if minZoom <=15, layer will be "poi15"
// - if >15, layer will be either "poi16", "poi17", etc
String layer = Utils.getLayerName("poi", minZoom);
var feat = features
 .point(layer)
 .setZoomRange(minZoom, 15); // <- since minZoom was 16, this feature was culled, fix: Math.min(minZoom, 15)

Replies: 4 comments 3 replies

Comment options

Can you share a full standalone example using something like https://github.com/onthegomap/planetiler-examples/blob/main/Toilets.java as a starting point? Then it is much easier to debug...

You must be logged in to vote
0 replies
Comment options

As Oliver mentioned it would help to see a minimal example. Based on what you showed though, each call to features.point or features.line creates a feature in whatever layer you specify. You can call that multiple times in a handler method too, or do shared setup on each feature in a separate method or loop.

Also what zoom are you hoping to generate? It's possible to support z16 or higher, just haven't prioritized it

You must be logged in to vote
0 replies
Comment options

Sure thing: https://gist.github.com/adjourn/4ea3b00650eba6921891adbf39cc522f

Just ran this minimal example within my project and I get layer poi15 but no layer poi16, even though I see my prints in console that there are features with layer name poi16.

@msbarry Haven't been able to test it out but I'd say 18 for trivial details like benches, trash cans, etc, maybe 19 but it might be too much. I'm not generating a whole planet, I know that it would be very impractical time and file size wise, I generate limited areas.

Unfortunately I'm not advanced enough in Java yet to go start hacking or contributing to planetiler to support this myself.

You must be logged in to vote
3 replies
Comment options

To specify my POV, even z16 would be a huge leap forward if z17 or z18 were out of this world ask, any would help.

My main gripe is that z15 is not that zoomed in in very detailed areas like downtowns, it causes inefficiency in 2 ways:

  • plenty of "peer" features are hidden due to density, could pre-sort them on generation and push some to z16
  • plenty of features are just not that important (benches, trash cans, etc), would still like to have them but not in z15

I understand from another discussion that it's a limit of bits available. I don't have the full context, so I'm not sure how big number would be needed to go to z16, z17, z18, etc, I can only imagine there's a point where it becomes impractical for general use.

Comment options

You can also use group/gridrank to set a "rank" field on the pois that ranks them by priority within a grid (see openmaptiles poi for example). Then you can use the filter maplibre layer property to limit what zoom level they show up at.

So the only benefit of generating tiles at higher zoom levels is if you know your style won't need features until z16 or 17+ you can omit them from z15 to reduce the size. But the cost is that when clients download the z16/17+ tiles they need to re-download features that were already included in z15, and your tile archive will also get much larger from the duplicate features. For example if a Z15 tile was 100kb, each Z16 tile in it would be ~25kb so you'd probably need to be able to reduce the Z15 tile by 25-50% for it to be worth it to also generate Z16.

Alternatively you could generate a separate high-zoom tileset and serve low-zoom tiles up to z14 or 15 and high-zoom tiles at z15/16+ so you don't need to duplicate all of the features from low zoom tiles into high zoom tiles to save client bandwidth. But the cost there is extra hosting and style complexity.

Comment options

Thanks for writing down your ideas and suggestions.

Any ideas why second layer is not added? Minimal example gist is linked in my previous comment. That would be one possibly workaround, even though it would not satisfy my two reasons listed below, still better than nothing - some stuff is just not possible with maplibre styles.


Why z15+ is such a big deal for me.

Reduce the weight of z15

Not the most important benefit for me but still, very welcomed one. z15 would not be "heavy" tile if it wasn't the last zoom level and didn't include everything. z15 is still mostly the "find something/look around" zoom level for my use cases (dense locations), z15+ is more about delving into details, so I don't mind having some duplicate data (mainly landuse and roads which are duplicated in every higher zoom level anyway). For example 95% of POI for me would not be in z15 at all, only the most important ones and big landmarks.

Satisfy customisability needs

I make very custom maps and that's the main reason for me. Not only do I target hundreds of features per map by ID, manually edit details on the fly if needed and move ones that are a bit off from design, I use strategies like this for example: feature gets included on z10 (to show icon), name field is added on z12, some other field on z14, etc. All done by taking the surrounding features into account on each zoom level to produce the most pleasing outcome or what is specified. This was a wonderful workflow for my use case from z1 to z14.

This worked wonders for place names, macro details like big parks, beaches, bays, harbours, etc but as soon as I started with POIs that should either progress from z14 to z16/z17 or even start displaying on z16/z17 (shops, bus stations, benches, list is very long) - it became instantly apparent that z15 is not enough for my use case.

Alternative is to do maplibre style trickery and you need a lot of it, in terms of complexity, number of layers and lines of code.. Now not only z15 is heavy but style file is also enormous.. And CPU is crying. Also Java code now lives two lives - one logic for z1-z14 and the other for z15. Especially if I want to continue with same outcome past z15 (when to show name or do something else with another field on particular zoom level). In many cases it's not possible due to how maplibre limits where you can read zoom, etc which is totally understandable - I also prefer to do it on generation, not on client CPU. All that complexity is massive compared to the fact that a simple Java if would solve the issue, not only the same way but better - data is not included if it's not needed.


You can also use group/gridrank to set a "rank" field on the pois

I considered it but there's a lot of manual, very custom ranking, not just "all hospitals are more important than supermarkets". I could have ID->rank lookups in code but how about adding/showing name at particular zoom level? Or some other custom field that defines some kind of visual outcome in map? So much complexity there and not everything is possible with maplibre style spec.

Alternatively you could generate a separate high-zoom tileset

Separate tileset for high zoom is also very interesting idea and I did consider it (at least a variation of it), hence this issue. I wanted to generate separate layers that I only show with minzoom: 16 | 17 | etc. Separate layer/tileset seems like the best workaround right now with only few drawbacks, of which you mentioned some: Java generation code still lives two lives, still requires extra layers, a lot more very complex styling code, some things are not possible (e.g show name at particular zoom), extra generation and hosting, etc.

Just a tad bit disappointed that I found the perfect workflow but I will most likely have to abandon it for lower zooms. I understand that my use case is a niche in some way, planetiler is mostly used to generate whole world and micro-details are usually not that important, i.e in most cases you don't care if mall A shows instead of neighbour mall B in z14. I get it, even though it's sucks for me, a lot.

Comment options

Figured it out on second (or third) round, dumb mistake as they usually are. Cause and fix in last comment:

if (sf.hasTag("barrier", "lift_gate")) { // some feature that has >15 zoom level
 minZoom = 16;
}
// - if minZoom <=15, layer will be "poi15"
// - if >15, layer will be either "poi16", "poi17", etc
String layer = Utils.getLayerName("poi", minZoom);
var feat = features
 .point(layer)
 .setZoomRange(minZoom, 15); // <- since minZoom was 16, this feature was culled, fix: Math.min(minZoom, 15)
You must be logged in to vote
0 replies
Answer selected by adjourn
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /