-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
add MercatorCoordinate
type
#7488
Conversation
src/geo/mercator_coordinate.js
Outdated
* A `MercatorCoordinate` object represents a 3 dimensional position in projected web mercator coordinates. | ||
* | ||
* The "world size" used by `MercatorCoordinate` is 1, meaning `MercatorCoordinate(0, 0, 0)` is the north-west | ||
* corner of the mercator world and `MercatorCoordinate(1, 1, 0)` is the south-east corner of the mercator world. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This documentation provides great clarity, I really appreciate it.
A lot of geospatial people might be confused by this definition though since the web mercator projection is in meters and has a projected bounds of
-20026376.39 -20048966.10
20026376.39 20048966.10
Since MercatorCoordinate
here is a a unit vector, I'm wondering if we need to be more explicit that this is not ESPG:3857 web mercator 🤔 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andrewharvey thats for flagging this! I'll have to think more closely whether we should match that or if we should just clarify the documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the simplicity of a unit vector as the underlying representation compared to EPSG:3857, however I very much see it as an internal implementation detail.
I would think that most applications of custom layers are working with data in WGS84 LL so with these helper methods the actual implementation doesn't matter outside of GL JS internals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I clarified this a bit in 83cda37. Do you think this is clear enough?
Also, I think the projected bounds on that website are wrong. I think it should be 20037508
.
I like the simplicity of a unit vector as the underlying representation compared to EPSG:3857, however I very much see it as an internal implementation detail.
Yep, it makes conversion from vector tiles to these units and back simpler. It also allows vector tile positions to be stored without loss of precision. I think it makes sense to keep it as is.
Do you think renaming it would help? UnitMercatorCoordinate
to emphasize the unitness of it? or TiledMercatorCoordinate
to nod in the direction of the tiled coordinate spaces this borrows from? I think I'm leaning towards just MercatorCoordinate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the new documentation in 83cda37 👍
-1 to TiledMercatorCoordinate
, that makes me think xyz tiles which vary by zoom level, but in fact this MercatorCoordinate
doesn't vary my zoom level and isn't broken into tiles.
I like UnitMercatorCoordinate
since it's more explicit that these are unit coordinates (0 to 1),
The main thing that would be useful to have reviewed so far are the first couple commits. The last commit (8856fbf) is a big one and it replaces the previous internal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! I also really appreciate the clarity the PR brings because I was always confused by that Coordinate class in transform before.
src/geo/mercator_coordinate.js
Outdated
constructor(x: number, y: number, z?: number) { | ||
this.x = +x; | ||
this.y = +y; | ||
this.z = z === undefined ? 0 : +z; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: we can use ES default parameters for things like this (below too for altitude).
src/geo/transform.js
Outdated
const lat = clamp(lnglat.lat, -this.maxValidLatitude, this.maxValidLatitude); | ||
const clamped = new LngLat(lnglat.lng, lat); | ||
const coord = MercatorCoordinate.fromLngLat(clamped); | ||
return new Point(coord.x * this.worldSize, coord.y * this.worldSize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My only concern with this change is that we significantly increase the number of allocations in potentially hot code, like here — instead of a single Point
allocation, we do 3 — Point
, MercatorCoordinate
, Point
again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think this is significant enough to warrant splitting out the projection into lngToMercatorX(...)
and latToMercatorY(...)
for internal use?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps not, but I tend to be on the safe side :) Your call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does 0d4c2ca look good?
src/geo/transform.js
Outdated
minX = this.lngX(lngRange[0]); | ||
maxX = this.lngX(lngRange[1]); | ||
minX = this.project(new LngLat(lngRange[0], 0)).x; | ||
maxX = this.project(new LngLat(lngRange[1], 0)).x; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To add to my point above, here, instead of zero allocations, we do 4 * (1 + 3) = 16, along with double-projection.
* `MercatorCoordinate(1, 1, 0)` is the south-east corner. If you are familiar with | ||
* [vector tiles](https://github.com/mapbox/vector-tile-spec) it may be helpful to think | ||
* of the coordinate space as the `0/0/0` tile with an extent of `1`. | ||
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does there need to be a caveat about precision here? I.e. When using a mercator co-ordinate to place something on a custom layer, it may not match the exact location at higher zooms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those issues are more on the rendering side of things than the MercatorCoordinate
side. We should probably add caveats and work arounds in the docs for custom layers. #7268 kind of covers this
const ubr = this.pointCoordinate(new Point(0, this.height), 0); | ||
const w0 = Math.floor(Math.min(utl.column, utr.column, ubl.column, ubr.column)); | ||
const w1 = Math.floor(Math.max(utl.column, utr.column, ubl.column, ubr.column)); | ||
const utl = this.pointCoordinate(new Point(0, 0)); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This existed before this pr so I think it's ok to leave for now. I think the point creations should be fine. This code only runs once per source per frame
This adds a
MercatorCoordinate
to expose a way to convert from from LngLat to the mercator coordinates used by custom layers.fixes #7485
Launch Checklist
TODO
Transform
to useMercatorCoordinate
for projection