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

WIP - support for non-mercator projections #1466

Closed
wants to merge 2 commits into from

Conversation

anandthakker
Copy link
Contributor

@anandthakker anandthakker commented Jun 21, 2016

Editing this comment because I stupidly made this PR by "converting" the original issue. The post (and all comments) from the original issue are preserved below. ( --@anandthakker )


Steps in this quest:

  • move worldSize out of lngX, latY, xLng, and yLat methods upstream (e.g. to project/unproject)
  • make Transform (and Map) accept alternative implementations of these functions in constructor
  • generate a sample tileset in a different projection
  • load it up in GL JS and see if anything broke (update: spot checked using debug/projection.html and things seem to work...)
  • more carefully assess impact throughout codebase, and guard with unit tests
  • decide how to handle the constrain option (see WIP - support for non-mercator projections #1466 (comment) )
  • similarly, decide on the correct behavior of fitBounds
  • Include support in geojson sources (upstream: Support multiple projections geojson-vt#57)

original issue comment:

Hey mapbox team! I first want to say I'm truly blown away by what you've built here. This is really, really impressive.

Anyhow, I'm curious to know if there is any interest in support non-mercator projections? I checked out the transformation logic and the projection appears to be hard-coded.

I'm sure there are optimizations to be had by assuming a single projection, but it would be really neat to be able to provide mapbox-gl with custom projection functions: not only would this enable other "common" map formats, but would open the door for some really creative visualizations (check out this and this).

It would also make mapbox-gl an ideal candidate for non-geo-based maps, like a cross-section of a human body with organs, circulatory system, nervous system, etc.

Thanks again for all the cool tech, and for developing in the open!

Cheers,
Mike

@tmcw
Copy link
Contributor

tmcw commented Sep 13, 2015

Braindump of thoughts here:

  • Geographical & literal projects are pretty different: what this ticked discusses is an analog to Leaflet's 'Simple' projection that doesn't attempt to transform the data at all. I think something like a no-op projection that uses coordinates in the 0..1 range would hit this usecase.

In terms of geographical projections - the bigger fish to fry with many more holes to fall down, I think it'd look like:

  • We'd implement a project transformer that sits on both sides of map rendering: it would request tiles, reproject, and then re-tile into a map-usable form. It would also sit in front of API methods to customize the px to and from lat lng conversions.
  • Web Mercator's clip around 85° is problematic for pole-preserving data. We could abuse coordinates < 0 to provide a second Mercator projection, like a Transverse Mercator projection, that 'fills in the blanks' with detailed data around the poles. The projection algorithm thus could select from different tiles for the same data and successfully get data for 90° and -90° latitude.

This is a sizeable can of worms: there's more complexity than I can communicate in one note, and I'm sure the rest of the gl-js team can also chip in that there are performance implications of this process and data implications with the projection-related simplification that we do.

@anandthakker
Copy link
Contributor

Building on @tmcw 's comment, another thought on this: Mapbox vector tiles really encode already-projected geometries. So, given a way to build a set of vector tiles where coordinates are projected with something other than 3857, the "reproject, and then re-tile" step need not happen in gl-js, and thus need not incur a perf hit. (This assumes, however, that all the VT sources being used are encoded in the same projection.)

See mapbox/tippecanoe#217 for one potential approach to building non-web-mercator vector tiles. Since GeoJSON sources rely on geojson-vt to encode users' geojson data into a vector-tile-based data structure, using GeoJSON in this approach would require adapting geojson-vt and GeoJSONSource to handle alternate an alternate projection function.

On the API-side of things, a question for the Mapbox team: is it plausible that this could be limited to providing alternate implementations for lngX, latY, xLng, and yLat? Seems too good to be true...

@anandthakker
Copy link
Contributor

is it plausible that this could be limited to providing alternate implementations for lngX, latY, xLng, and yLat?

Hmm, maybe also the bearing getter & setter...

@mourner
Copy link
Member

mourner commented Jun 2, 2016

Per chat with @anandthakker, next steps to experiment with this would be to:

  • move worldSize out of lngX, latY, xLng, and yLat methods upstream (e.g. to project/unproject)
  • make Transform (and Map) accept alternative implementations of these functions in constructor
  • generate a sample tileset in a different projection
  • load it up in GL JS and see if anything broke

I think the only invariant that we have to assume is that the projection scales logarithmically (size doubles with 1 zoom level).

@anandthakker
Copy link
Contributor

Quick update --

generate a sample tileset in a different projection

Did this quite easily thanks to tippecanoe's new -s option!

screen shot 2016-06-15 at 12 08 04 pm

Just used reproject to project my state boundaries geojson into an Albers equal area projection, and then ran cat states-albers.geojson | tippecanoe -s EPSG:3857 -o out.mbtiles, which just tells tippecanoe to treat the input as if it were already in Web Mercator. (Pretty sure this is analogous to what happened here.)

@anandthakker anandthakker changed the title Support for non-mercator projections? WIP - support for non-mercator projections Jun 21, 2016
@anandthakker
Copy link
Contributor

PSA: if you use the hub cli, don't use hub pull-request -i #, because it's bad

@anandthakker
Copy link
Contributor

is it plausible that this could be limited to providing alternate implementations for lngX, latY, xLng, and yLat? Seems too good to be true...

Heh, this was indeed a bit simplistic: in web mercator, x is a function of lng only and y is a function of lat only, but this is not true of other (most?) projections. So, to make this work, we'll need to remove the independent methods xLng, latY, etc., and work directly off of project and unproject. From a very initial look it seems like this may be possible

@anandthakker
Copy link
Contributor

The option to constrain the map to a lnglat bounding box also only makes sense in a projection like web mercator where lnglat rectangles are projected into rectangles

@anandthakker
Copy link
Contributor

I think it sorta works! Check out debug/projection.html for a working example.

Updating the top of the ticket with a couple of additional tasks.

The option to constrain the map to a lnglat bounding box also only makes sense in a projection like web mercator where lnglat rectangles are projected into rectangles

^ @mourner @tmcw any ideas on how best to handle this?

@anandthakker
Copy link
Contributor

decide how to handle the constrain option (see #1466 (comment) )
similarly, decide on the correct behavior of fitBounds

Having mulled on this a bit, I think a fairly complete solution would be:

  • A custom projection may additionally provide a projectedBoundingBox function which takes a latlong polygon (maybe a rectangle, maybe something else) and returns a rectangle in the projected coordinate space that fully contains the projected version of the given polygon.
  • If projectedBoundingBox is not provided, then all gl-js methods that normally expect bounds in latlong coordinates simply fall back to interpreting the bounds as being in projected coordinates.

@lucaswoj
Copy link
Contributor

We've been thinking about changing the behaviour of fitBounds #2112. It doesn't make much sense in web mercator either once pitching and rotating is introduced.

Having mulled on this a bit, I think a fairly complete solution would be:
...

This solution looks great! 👍

@anandthakker
Copy link
Contributor

@lucaswoj oh, shoot -- reading that ticket re: pitch/rotate made me realize that my proposal actually isn't complete after all: the projectedBoundingBox method I propose covers the "fitBounds" use case, but it doesn't cover the "maxBounds" use case, where, as I understand it, the intent is for the map view to be contained wholly within the given bounds (instead covering the given bounds).

So I guess we would need a projectedInnerBox method... but maybe it would be reasonable to proceed without this for now, especially since it sounds like in the long run there may be some revisions to these parts of the API.

@mtirwin
Copy link
Contributor

mtirwin commented Jul 9, 2016

👀

@lucaswoj
Copy link
Contributor

I am closing this PR because it has been inactive for a long time. The branch isn't going anywhere so please keep working on this feature and re-open the PR when it is ready!

Let me know if you have any questions.

@lucaswoj lucaswoj closed this Jul 20, 2016
@anandthakker
Copy link
Contributor

👍 I do plan to return to this and follow the plan outlined above, but it may be a couple weeks, so keeping closed until then SGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants