maplibre / maplibre-style-spec

MapLibre Style Specification & Utilities
https://maplibre.org/maplibre-style-spec/
Other
69 stars 59 forks source link

Design Proposal: Projection #568

Open HarelM opened 6 months ago

HarelM commented 6 months ago

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 commented 6 months ago

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

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

wipfli commented 6 months ago

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 commented 6 months ago

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 commented 6 months ago

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

HarelM commented 6 months ago

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 commented 6 months ago

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 commented 6 months ago

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:

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:

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 commented 6 months ago

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 commented 6 months ago

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 commented 6 months ago

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 commented 5 months ago

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 https://github.com/maplibre/maplibre-gl-js/pull/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.

https://github.com/maplibre/maplibre-style-spec/issues/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 commented 3 months ago

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 commented 1 month ago

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 commented 1 month ago

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 commented 1 month ago

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 commented 1 month ago

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 commented 1 month ago

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, https://github.com/maplibre/maplibre-gl-js/commit/768f7372c929fb20b456e3e54b5f61e446397628 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 commented 1 month ago

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):

(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 commented 1 month ago

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.