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: Projection #568

Open
HarelM opened this issue Mar 14, 2024 · 22 comments
Open

Design Proposal: Projection #568

HarelM opened this issue Mar 14, 2024 · 22 comments
Labels
enhancement New feature or request

Comments

@HarelM
Copy link
Collaborator

HarelM commented Mar 14, 2024

Design Proposal: Projection

Motivation

Allow users to set a projection for the map

Proposed Change

Add projection to the root object of the style.

{
   version: 8,
   sources: { ... },
   layers: [],
   projection: {
      type: "mercator" // or "globe"
   }
}

I'm not sure if it should be type or name...

API Modifications

Besides the part of the spec that needs to be added APIs for setProjection and getProjection should be added to the map object.

Migration Plan and Compatibility

This is a new feature. The default would be Mercator.

Rejected Alternatives

N/A

@HarelM HarelM added the enhancement New feature or request label Mar 14, 2024
@HarelM
Copy link
Collaborator Author

HarelM commented Mar 14, 2024

This is related to the following projection bounty:
maplibre/maplibre#272
Which is related to globe bounty:
maplibre/maplibre#190
As part of the globe implementation, we have found out that we need to properly define this.
See this globe initial PR:
maplibre/maplibre-gl-js#3783
Discussion about globe:
maplibre/maplibre#161

cc: @louwers @sjg-wdw @wipfli @Pheonor @kubapelc

@wipfli
Copy link
Contributor

wipfli commented Mar 14, 2024

Could there be a plugin system for projections? Because there are many projections and we probably don't want to include all of them in the library. Might be wrong though...

@wipfli
Copy link
Contributor

wipfli commented Mar 14, 2024

I would of course love to get support for https://en.m.wikipedia.org/wiki/Swiss_coordinate_system.

Talking of which, what is the difference between a projection and a coordinate system? And would the tiles always be assumed to use web mercator?

@wipfli
Copy link
Contributor

wipfli commented Mar 14, 2024

Cc @pka since you are looking into Equal Earth...

@HarelM
Copy link
Collaborator Author

HarelM commented Mar 14, 2024

Could there be a plugin system for projections?

That's an interesting thought, I would assume that after we include more than just globe and mercator we can design an API that will allow adding more projections. Note that current code has the projection implementation in the shaders, so adding a custom shader might prove tricky, but generally speaking, we should aim to be able to add more projections.

@kubapelc
Copy link

In globe, anything that satisfies the Projection interface can supply its own shader code as a string. But not shader uniforms, those are currently hardcoded. I'm a bit more worried about how custom projections would interact with transform, panning the map, zooming, etc. There is a lot of complex logic in the transform class. I haven't even looked at that for globe yet.

@sjg-wdw
Copy link

sjg-wdw commented Mar 14, 2024

Having implemented all of this in another toolkit here's some random thoughts.

Web Mercator is a deceptively simple projection. You can project back and forth with fairly simple functions and no iteration, no weird gridded offsets, that sort of thing. As such it can be unhelpful to design around. For example, doing the work in a shader is pretty easy, but much less so for something like UTM with a specialized ellipsoid and some strange offsets.

I'm not saying you need to implement all that madness, just design around it and drop in the pieces you already have.

A plugin system for projections is a good idea. It should be able to:

  • project between coordinate systems
  • project to model globe coordinates (kind of geocentric, but maybe not exactly)
  • tell if two coordinate systems are the same. Harder than it sounds

Then you can drop in your existing implementation.

As for what needs a projection, I'd say the overall map and each data source. As to how you specify it, just do what Proj does. I'm fond of proj strings, but I think there's a JSON version of the WKT formatting that would work better in this case.

At least having those defined would let you implement three cases you can sort of do easily:

  • Web Mercator with all Web Mercator sources
  • A random projection with sources in that same projection. You need to convert out to lat/lon for utility functions here, which might be a bit of work.
  • A globe with web mercator sources

Putting it all out there in proper form lets you expand as developers are interested in dealing with it. But for now you can just reject everything that's not implemented, like feeding UTM sources into a globe or some such.

Oh and the type is a good idea for the UI control system to figure out what to do. I'd suggest flat and globe, letting an explicit projection set what kind of flat map. Then ask the projection system if it's web mercator.

@Pheonor
Copy link

Pheonor commented Mar 15, 2024

Very usefull feedback on previous experience, thanks !
For me, 'type' refers to 'globe' of 'flat' not the projection name.
Perhaps an explicit 'name' could be used.

@sjg-wdw
Copy link

sjg-wdw commented Mar 15, 2024

Naming projections can get a little wonky on the implementation side. Sometimes it's best to just use the full projection definition so developers know to avoid shortcuts.

@vlarrieu
Copy link

Naming projections can get a little wonky on the implementation side. Sometimes it's best to just use the full projection definition so developers know to avoid shortcuts.

Ok, so you suggest to keep 'type' with 'globe' or 'flat' value. Its clear for me.
We could extend the projection system later.

@syonfox
Copy link

syonfox commented Mar 26, 2024

One comment is that it seems the sky and globe details are linked.

Of the top of my head the current plan is something lie

{
  projection: { 
    type: "globe", ... // type spicific settings
  }
  sky: {
    
  }
}

I need to do some more digging but are the atmosphere and globe effects not inherently linked.

it was mentioned that maybe having a module system to support different projections.

my question would then be how many projections are planed on being supported.

Would you want to offer a polar mode and a dymaxine mode etc. Or is this out of scope.

to throw out another perspective the globe mode could be the actual parameter with its own options.

{
  globe: { //falsy foe disabled or truthy for defaults or object with defined parameters such as
    background: "color/ starmap config??",
    skybox: {...}, // this maybe is independent from terrain atmosphere effect. but could inharent those settings as default or something. 
    
  },
  sky: { //terrain atmosphere rendering settings ... in globe mode it applies to both globe atmosphere effect when zoomed out and the terrain atmosphere

  }
}

// note I see that the sky spec is being used in both the terrain mode and globe mode. 

As this idea progresses and I look at more of the implementation maplibre/maplibre-gl-js#3783

maybe it makes sense to have this be a new issue for a feature skybox that is used by both the terrain mode and the globe projection simpler to the sky effect.

Some questions are? is it more or less complicated to have these be shared between the 2 modes.

{
...
projection: {
 type: "globe"
 ...globeSpecifiecOptions
}
terrain: {} // options specific to the zoomed in terrain mode

sky: { // shared between terrain and globe mode
 
  skybox: "image url in galactic cordanates or cubemap... depends on implmenetation"
}
}

https://maplibre.org/maplibre-style-spec/root#sky

I think That this is getting away from details specific to the projection feature but is probably useful context.

#163 Ill link this here but one question is

Is it best to have these options in one simple place fore each projection mode or to make a general version of them.

ps thanks for the cool project it looks promising.

@HarelM
Copy link
Collaborator Author

HarelM commented May 31, 2024

I've added the projection configuration to allow adding this to the globe branch. It is still marked as experimental and follows the initial suggestion I made in the beginning of this thread.
We might change it to facilitate WKT formats in the future when we have a better understanding on how to do it properly.

@razor-1
Copy link

razor-1 commented Jul 21, 2024

Came across this by doing some digging into why maplibregl stopped working with mapbox styles, and it seems that this is the root cause - the mapbox style spec uses name, and thus when validating a style coming from mapbox, it fails. If this is still considered experimental, and there's no specific reason to use type, it might be nice to err on the side of compatibility with what's already there. Thank you.

@HarelM
Copy link
Collaborator Author

HarelM commented Jul 21, 2024

By changing this to name we risk infringing mapbox copy rights. There are probably other style features that are not compatible when moving from mapbox to maplibre or vise versa. You are welcome to build a tool to allow easier migration of styles from mapbox to maplibre that can benefit everyone 😊

@wipfli
Copy link
Contributor

wipfli commented Jul 22, 2024

MapLibre's style specification and Mapbox's style specification will diverge over time. As @HarelM said one reason is that there can by legal implications related to copyright if we were to copy the Mapbox API, another reason is that we just want to set our own priorities and build our own future.

@sjg-wdw
Copy link

sjg-wdw commented Jul 22, 2024

This is one of the many reasons it would be good to get the style spec recognized by a standards body.

I recall there was some cultural resistance to that back in the day, but hopefully that's no longer the case. We could have standard versions of the style spec, vendor additions to it, and so on.

It would make these conversations much simpler and give users a path to pressuring their favorite vendor to at least put their changes in an extension.

@razor-1
Copy link

razor-1 commented Jul 22, 2024

Thanks, great points in the discussion here. One thing I'd like to highlight is that seemingly small changes here to the spec can end up being breaking changes downstream. So for example, maplibre/maplibre-gl-js@768f737 bringing in this change ideally would have required a new major version number for maplibre-gl-js, because styles that once validated no longer do.

@mclaeysb
Copy link

Picking up on @sjg-wdw 's mention of PROJJSON:

At Allmaps we build on the IIIF Georeference spec and have created, a.o., a MapLibre GL JS plugin allowing to display IIIF images of historical maps in MapLibre. We are currently looking into expanding the spec to include projection information.

Before looking into how to specify projections in the MapLibre spec, I first want to mention it's not fully clear to me yet how projections will be processed in MapLibre (and as I understand the MapLibre community is still experimenting with this):

  • Would the projection step happen in JS (using Proj4JS) and hence be able to take in any function and allow true custom projections?
  • Is it done using hard-coded functions in the vertex shader (as it's done in the two examples @Pheonor and @kubapelc) and accessed using the type in the (experimental) proposal of this issue?
  • I've also read @sjg-wdw mentioning a WASM port of PROJ as an alternative to Proj4JS.

(In Allmaps we will implement the reprojection following from it in our custom WebGL renderer. It would be very useful for us and other plugins to be able to read any projection/transformation objects used in JS (or shaders))

Now, how to specify projections? PROJJSON, as the literal JSON translation of the 'WKT2:2019 / ISO-19162:2019' spec, indeed seems like an excellent way to defining projections, if supporting any projection (and not just mercator/globe or a small set of projections) is the goal. It's also being adopted by projects like GeoParquet. I would say it's the best war forward.

But important: PROJ can take PROJJSON as input, but Proj4JS can't (yet). Hence this message: at Allmaps we're considering to support a PROJJSON implementation in Proj4JS. If MapLibre would like to join forces, please refer to this issue.

@HarelM
Copy link
Collaborator Author

HarelM commented Aug 14, 2024

The spec is relevant for both maplibre-gl-js and maplibre-native, so the implementation details are not relevant in this discussion (to some extent).
In theory we should define the most common and straight forward way for projection, later on we can see if there are implementation limitations and document them as well.
The current direction with globe is to do the direction in the shader code as a lot of the calculations are done there.
This is less than ideal in terms of extending it to other projections and writing the proj4js/proj in the shader requires some work.
In general, you are welcome to try and add more projections to maplibre-gl-js and see what it would require so that extending it would be easier and define a spec from that experiment.

@birkskyum
Copy link
Member

birkskyum commented Nov 2, 2024

I'm not sure how much utility additional zoom transitions would have, but with the lowZoomProj-highZoomProj convention we have a lot of flexible if something comes up - just ideation:

  • [other 2d world projection]-mercator: Transition from better 2D world projection, such as Equal Earth, to mercator on high zoom.
  • globe-[metric 2d projection]: This could be useful for people working with buildings, such as civil engineering/indoor-mapping/CAD/govs., where systems like UTM often are used.
  • globe-[conical 2d projection]: This could be useful for dealing with the poles. The Lambert projection is used a lot by northern countries and aviation.

@HarelM
Copy link
Collaborator Author

HarelM commented Nov 2, 2024

I'll copy the comment I made in the PR:
When looking at this PR I can't help but think about making the value an interpulatable with expression. This way you have full control over the transition and can develop other layers (custom mainly) knowing exactly when things change instead of making assumptions.
This can lead in the future to allow transition from any protection to any protection based on zoom level (or maybe other stuff, IDK).
Let me know what you think.

@birkskyum
Copy link
Member

Ongoing work on expression API in here

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

10 participants