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

Design Proposal: Expanding tileSources bounds #60

Open
pramilk opened this issue Mar 17, 2023 · 36 comments
Open

Design Proposal: Expanding tileSources bounds #60

pramilk opened this issue Mar 17, 2023 · 36 comments
Labels
enhancement New feature or request

Comments

@pramilk
Copy link
Contributor

pramilk commented Mar 17, 2023

Design Proposal Template

Motivation

Bounds property in tile sources currently takes a bound and constraints the tiles from this bound. This is very constraining and does not provide flexibility that we need. Here are the current limitations we face.

  1. There is no way to specify a bound which should be excluded. For example in our case,

    • South Koria and Japan needs special handling and have a different tile source then the rest of the world. Since there is no support for exclusion, we add South Koria/Japan tile layers on top of rest of the world. This is causing un-necessary tile requests in this region
    • We have streetside/traffic coverage only in some portion of the world. Since exclusion is not supported, we have to download these tiles in regions which does not have any coverage.
  2. There is no way to specify multiple bounds. For example in our case

    • UK has a special imagery requirement. So inorder to only cover just UK, we have to add 3 tile sources to cover just UK (to exclude Iceland/France).
    • Also no way to provide multiple exclusions per tile source.

Proposed Change

Proposal is to expand bounds property to support inclusion and exclusion bound's along with min/max zoom for which these bounds will be applicable. Please look at below API modification for types.

API Modifications

Current TileJson type

type TileJSON = {
    tilejson: '2.2.0' | '2.1.0' | '2.0.1' | '2.0.0' | '1.0.0';
    name?: string;
    description?: string;
    version?: string;
    attribution?: string;
    template?: string;
    tiles: Array<string>;
    grids?: Array<string>;
    data?: Array<string>;
    minzoom?: number;
    maxzoom?: number;
    bounds?: [number, number, number, number];
    center?: [number, number, number];
};

Proposed TileJson with this change

type TileJSON = {
    tilejson: '2.2.0' | '2.1.0' | '2.0.1' | '2.0.0' | '1.0.0';
    name?: string;
    description?: string;
    version?: string;
    attribution?: string;
    template?: string;
    tiles: Array<string>;
    grids?: Array<string>;
    data?: Array<string>;
    minzoom?: number;
    maxzoom?: number;
    bounds?: TileJSONBounds;
    center?: [number, number, number];
};

type TileJSONBounds = [number, number, number, number] | {
    include?: Array<constrainedBounds>;
    exclude?: Array<constrainedBounds>;
};

type constrainedBounds = {
    bounds: [number, number, number, number];
    minzoom?: number;
    maxzoom?: number;
};

Alternative option with more flexibility is to support both bounds/polygon bounds.

type constrainedBounds = {
    type: "Bound" | "Polygon";
    coordinates: Array<[number, number]>;
    minzoom?: number;
    maxzoom?: number;
};

Migration Plan and Compatibility

It will be backward compatible.

@wipfli
Copy link
Contributor

wipfli commented Mar 17, 2023

That is an interesting proposal, thanks @pramilk for writing it.

If I understand correctly, this design would allow you to make a tile pyramid where arbitrary sub-pyramids are missing. Could it not be a problem that this design is too generic?

Also if I remember correctly some people from Esri wanted to have exactly this functionality in MapLibre GL JS. Let me reach out to them...

@ovivoda
Copy link
Contributor

ovivoda commented Mar 19, 2023

@pramilk can you please add an example for the way you are using MapLibre now for case 1 and case 2?
And how will you use it in the future if the proposal will be implemented. Maybe also give us a snippet of the tiles sources used now?

That way we will make sure we are on the same page, by fully understanding the use-case.

@HarelM
Copy link
Collaborator

HarelM commented Mar 19, 2023

I think this is a very interesting proposal, thanks!
Two questions/comments come to my mind.

  1. Complicating bounds can lead to performance issues due to complex spatial calculations. Can we avoid it?
  2. Can't this be achieved using a tile server with the relevant tiles for the relevant area? (Maybe besides missing tiles that can be solved using simple bounds)

@pramilk
Copy link
Contributor Author

pramilk commented Mar 20, 2023

If I understand correctly, this design would allow you to make a tile pyramid where arbitrary sub-pyramids are missing. Could it not be a problem that this design is too generic?

@wipfli, Yes it gives flexibility to uses who require this functionality without impacting any existing users. Please see my example /scenario in below example.

@pramilk can you please add an example for the way you are using MapLibre now for case 1 and case 2? And how will you use it in the future if the proposal will be implemented. Maybe also give us a snippet of the tiles sources used now?

That way we will make sure we are on the same page, by fully understanding the use-case.

@ovivoda, @wipfli
Here is our style endpoint for reference used in below examples. Style endpoint used on Bing Maps. Here are 3 examples of where we will be able to use this API.

Use case for bounds exclusion:

  • Current:
    We render vector data except for South Koria and Japan. On top of Vector data we also have few raster layers (hill shading, road details, Building footprints). We need these as raster layers due to either the visual effect (Hill shading) we want or due to the size impact it will have on vector data (Building foot prints and road details).

    For South Koria/Japan (JK), due to data licensing and technical issues we can't surface vector data for JK. So we render raster tiles for JK region which already contains hill shading, building and road details in it. For Koria we render raster tiles for LOD 9-20 and for Japan we render raster tiles from 5-20. Rest of world (please ignore Japan, for this discussion) we have vector data. Since the current API does not support exclude bounds, these 3 raster layers (hill shading, building and road details) layers are still downloaded.

  • With the proposed API:
    We can exclude hill shading, building and road details from South Koria region for a certain zoom levels and from Japan for other zoom levels. Also since JK raster tiles is displayed only for a certain zoom level (9-20/5-20), setting min/max zoom for exclusion will help us to exclude these additional layers for these zoom levels.

Use case for multiple inclusions:

  • Current
    We have some special raster imagery for UK region (Ordnance survey). This imagery does not support transparent tiles (due to legacy reasons) for non-coverage areas. So in order to only cover UK with this imagery without covering it up Ireland and parts of France, we have to define 3 tile sources with different bounds. Our Style endpoint is here with 3 sources.

  • With the proposed API:
    With support for multiple bounds, we won't have to define 3 different tile sources in this case.

Use case for multiple inclusions:

  • Current
    We have streetside data only for limited regions in world scattered around the world which can't be defined by 1 bounds. So we just return transparent tiles for regions where coverage is missing.

  • With the proposed API:
    We can define array of bounds where the coverage is available. This will help reduce additional unnecessary download of coverage tiles in regions where coverage is missing.

Blue layer in this image represent coverage.
image

I think this is a very interesting proposal, thanks! Two questions/comments come to my mind.

  1. Complicating bounds can lead to performance issues due to complex spatial calculations. Can we avoid it?
  2. Can't this be achieved using a tile server with the relevant tiles for the relevant area? (Maybe besides missing tiles that can be solved using simple bounds)

@HarelM
#1: There is no performance penalty (except for extra Js download/compile time) as its expands the current bounds functionality. So, if a user does not have any requirement to use this new functionality, they don't have to face perf penalty. Extra Js size should be minimal less then 50 lines.
#2: Tile server can (does in our implementation) return empty tiles in these regions. But client still have to download them. For vector data, its downloaded, processed and then ignored. For Raster tiles they are downloaded, texturized and rendered.

@HarelM
Copy link
Collaborator

HarelM commented Mar 22, 2023

There was a comment in the shack channel about tilejson specification that will need to change as well, @pramilk can you please check this aspect?

@wipfli
Copy link
Contributor

wipfli commented Apr 2, 2023

Could this design also be used with many bounds? For example say I want to show high details for train stations globally up to z18, while the rest is z14.

@wipfli
Copy link
Contributor

wipfli commented Apr 2, 2023

Can includes and excludes be nested?

@wipfli
Copy link
Contributor

wipfli commented Apr 2, 2023

As @HarelM said it might be that this needs an extension of the TileJSON specification, see https://github.com/mapbox/tilejson-spec. It is an open specification and I think we should aim to contribute to it. But let us first figure out how to do it here and then bring that idea to the TileJSON repo.

For completeness let me mention that MapLibre has forked the style specification and the rendering engines MapLibre GL JS and MapLibre GL Native from Mapbox. However, the TileJSON and MVT specifications have so far not been forked.

@wipfli
Copy link
Contributor

wipfli commented Apr 2, 2023

Ah nice, @rbrundritt from Microsoft actually brought tiled tiles to the TileJSON repo back in 2019: mapbox/tilejson-spec#58

@wipfli
Copy link
Contributor

wipfli commented Apr 2, 2023

There are more issues in the TileJSON repo asking basically for this functionality:

mapbox/tilejson-spec#60

mapbox/tilejson-spec#49

@wipfli
Copy link
Contributor

wipfli commented Apr 3, 2023

@nyurik @stepankuzmin Do you think Martin could support such a modified version of the TileJSON spec?

I am asking because I think if we change the way sources can be handled in the frontend, we should also give users the tools to create such sources with more detailed coverage bounds...

cc @msbarry from Planetiler, @bdon from Protomaps, @e-n-f from tippecanoe

@bdon
Copy link

bdon commented Apr 3, 2023

A related issue recently added to felt/tippecanoe felt/tippecanoe#82 - is bounds specifications that cross the antimeridian using the 0-360 degree range. This is an addition to existing bounds, not a replacement.

@msbarry
Copy link

msbarry commented Apr 3, 2023

Planetiler just writes the "bounds" field to mbtiles metadata, and tile servers like martin construct the tilejson from that, so we'd need to decide on a standard for how to encode this modified data in mbtiles for tile servers that understand this change to handle, as well as maintaining backwards compatibility for older tile servers.

Right now planetiler supports a single bounds/minzoom/maxzoom and/or a polygon file. It wouldn't be hard to extend this to support multiple regions/minzooms/maxzooms, since it the bound tests all get funneled through this one class - just need to know how to encode the metadata.

Complicating bounds can lead to performance issues due to complex spatial calculations. Can we avoid it?

Initially the polygon testing did incur a performance overhead in planetiler, but I mitigated this by adding a preprocessing step that calculates every tile that the polygon touches at each zoom level (using a RoaringBitmap) and just test against that at tile generation time.

@wipfli
Copy link
Contributor

wipfli commented Apr 3, 2023

Thanks for pointing this out, @msbarry. Besides Martin, the other tile server that comes to mind is tileserver-gl. @acalcutt you are working a lot on tileserver-gl, do you think this proposal here could be integrated in tileserver-gl?

@acalcutt
Copy link
Contributor

acalcutt commented Apr 3, 2023

Right now, based on a quick look at the code, tileserver-gl generates it's TileJSON based on what is in the mbtiles metadata.

I think it depends how this changes the mbtiles file. I assume bounds/minzoom/maxzoom would still be in the mbtiles file, since that is part of the mbtiles-spec? Would include/exclude be new metadata values inside the mbtiles file?

as long as bounds/minzoom/maxzoom is still in the mbtiles file, I don't think this would affect tileserver. It would however need some work to support include/exclude...if that was added to the mbtiles metadata.

@wipfli
Copy link
Contributor

wipfli commented Apr 3, 2023

Thanks for the update @acalcutt. I did not know there was also an mbtiles specification... But good to know now, so if we go forward with the tileSouces bounds proposed here we will also want to have them in TileJSON and in the MBTiles specification I think.

@wipfli
Copy link
Contributor

wipfli commented Apr 3, 2023

Let me ping a few more people who appear to have been involved in the mbtiles issues in the past: @systemed, @pnorman, @sfkeller

@pnorman
Copy link

pnorman commented Apr 3, 2023

I don't see that there's any direct relationship with mbtiles here, as maplibre doesn't read mbtiles.

TileJSON is essentially unmaintained and I've wondered if it's necessary to look at forking it and transferring it to an org like OSGeo.

@acalcutt
Copy link
Contributor

acalcutt commented Apr 3, 2023

mbtiles and tilejson are related I think. all the information to generate tilejson from a mbtiles source comes from the mbtiles metadata.

That doesn't mean Tilejson/Maplibre can't support both formats, but if someone wanted to support this from a mbtiles source, this new information would need to be in the mbtiles metadata, so the tileserver could use that info to generate it's tilejson endpoints.

Just one more side note on the mbtiles-spec, it mentions bounds/minzoom/maxzoom being a requirement at some point. In a future revision of this specification, the bounds, minzoom, and maxzoom rows of the metadata table will be mandatory. https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md#future-directions

@sjg-wdw
Copy link

sjg-wdw commented Apr 3, 2023

I really like this idea. If you've ever cobbled together data sets with holes or weird constraints, this would help.

A couple things sprang to mind.
First, would it make sense to use a different keyword than "bounds" for the new format?
Similar to what's being contemplated for MBTiles, I think. The overall bounds is backward compatible, but then the new bounds is elsewhere and you only see it if your software looks for it.

Second, do you have a TileJSON example? Sometimes it's easier to understand if you can see a real world example. Your map is great here for that.

@acalcutt
Copy link
Contributor

acalcutt commented Apr 3, 2023

@sjg-wdw this is more what i was thinking with the mbtiles. If you kept old bounds/maxzoom/minzoom to keep it compliant, but added some new keywords for include/exclude, then something could be done to use them on the server side if they existed and this new tilejson format could be generated.

@sjg-wdw
Copy link

sjg-wdw commented Apr 3, 2023

@sjg-wdw this is more what i was thinking with the mbtiles. If you kept old bounds/maxzoom/minzoom to keep it compliant, but added some new keywords for include/exclude, then something could be done to use them on the server side if they existed and this new tilejson format could be generated.

Yes, I like this idea. Thinking back to some of the janky TileJSON parsers I may have written in the past, it seems safer to add keys rather than change them.

@pramilk
Copy link
Contributor Author

pramilk commented Apr 3, 2023

Another issue worth mentioning/considering.

Include/exclude bound ranges on tile source just means that the tiles will/will not be fetched for specific bounds. Layers will still try to render them (if they are in its zoom range). So might need a corresponding change in layers spec as well if user don't want layers to render data in include/exclude tile bounds.

One of the option can be to expand the visibility property to be 'none' | 'visible' | 'constrained'. Where 'constrained' will force the layer to only render within the tile source constrain.

@wipfli
Copy link
Contributor

wipfli commented Apr 4, 2023

My intuition is that the performance penalty for rendering empty tiles is close to zero, but I have never measured it. Do you have some numbers on this @pramilk?

@sjg-wdw
Copy link

sjg-wdw commented Apr 4, 2023

Empty tiles are probably fine in most cases. But if you're doing something weird, sometimes the absence of data can be meaningful. It's best to load things precisely if you can rather than rely on empty tiles to tell you something.

How that relates to layers, though.... I think you're saying that a layer should be turned off if its source is not currently visible. But how many layers does that relate to other than background?

@pramilk
Copy link
Contributor Author

pramilk commented Apr 4, 2023

Regarding performance implication of rendering empty tiles: Client still have to download them.
For vector data, its downloaded, processed and then ignored.
For Raster tiles they are downloaded, texturized and rendered. It does not know if its empty or has some data.

@bdon
Copy link

bdon commented Apr 6, 2023

+1 to forking the unmaintained TileJSON spec

In practice I do not think the overhead of empty tiles is that important for end-user-facing map applications, simply because human users do not spend a lot of time looking at repetitive or empty parts of the world. Is there strong counterexamples?

One issue with the constrained bounds approach is that it becomes possible to express inconsistent bounds information.

  • What happens if the includes bounds and excludes bounds overlap? For clients to behave identically for identical tilesets they need to perform the exact same prioritization of possibly overlapping constrained bounds.
  • The relationship between excludes bounds and the zoom level at which it takes affect is direct but implicit: the client needs to project the 4 corners of a tile into geographic coordinates and test it against all of the constrained bounds. This is related to the fillzoom key in the existing TileJSON spec but I don't know of any open source software that actually uses fillzoom.

@vincentsarago
Copy link

👋 Hi, I'm not directly involved in Maplibre but I'm working on multiple tile servers (MVT / Raster) where we provide TileJSON documents so I'll be really interested to see where this discussion goes about Open Sourcing TileJSON.

Strictly talking about the bounds property, the OGC Features Specification for the spatial extent is defined as an array of bbox with the first one being the sum of the bbox and all other as regional bbox

ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/schemas/extent.yaml
see: https://github.com/developmentseed/tipg/blob/main/tipg/model.py#L32-L45

@wipfli
Copy link
Contributor

wipfli commented Apr 12, 2023

Hi @vincentsarago. Nice, which tile servers are you involved in?

@wipfli
Copy link
Contributor

wipfli commented Apr 12, 2023

@vincentsarago feel free to join the monthly meeting today at 8 PM CEST. We will discuss this design proposal today. Link to the zoom call is in the slack channel.

@vincentsarago
Copy link

vincentsarago commented Apr 12, 2023

@wipfli mostly two:

Thanks for the invite, I'll see if I can make it

@ovivoda
Copy link
Contributor

ovivoda commented Apr 15, 2023

Notes from TSC meeting on April 12:

  • Must be opt-in
  • Filter tiles API?

Action points:

  • Tighten the definition as there are many edge cases and possible problems which might explain why this wasn’t well defined before

@pnorman
Copy link

pnorman commented Apr 15, 2023

I think the work should be done in a TileJSON fork, once the spec is changed, Maplibre can use those new attributes of the spec.

@wipfli
Copy link
Contributor

wipfli commented Apr 15, 2023

wipfli/tilejson-spec#1 prepares a TileJSON spec fork. Since the original repository a) does not have a license file and b) the license in the readme is not MIT/BSD, I would like to get some advise on licensing before we actually bring this into the MapLibre org.

@HarelM HarelM added the enhancement New feature or request label Dec 31, 2023
@rbrundritt
Copy link

It's been 5 years since I originally made the update request to the tilejson spec for this. I now have another scenario where this would useful and aligns with where MapLibre is heading, elevation tiles.

I'm working on a scenario where I have a few thousand areas of interest on a map where the user will often be very close to the ground when viewing the map. In those areas I have high resolution elevation data generated from lidar data with 0.5m resolution. Most of my areas of interest are around 4 sq km's in size, but I still want to show the surrounding area with 3D terrain, but low resolution is fine, and actually preferred as I want to have an offline option.

That said, this also posses a bit more complexity since only a single terrain source is supported in MapLibre GL JS at this time, and I would have different max zoom range availability for the high/low resolution data.

In the mean time I'll like use combination of a request transform a custom service to bridge this gap for now.

@HarelM
Copy link
Collaborator

HarelM commented Oct 22, 2024

You might be able to use addProtocol for fetching specific areas while returning 404 for others or fetch a bigger tile and splice it and basically combining multiple sources into one custom source.

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

No branches or pull requests