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

Projections public API #11002

Merged
merged 19 commits into from
Oct 14, 2021
Merged

Projections public API #11002

merged 19 commits into from
Oct 14, 2021

Conversation

ryanhamley
Copy link
Contributor

@ryanhamley ryanhamley commented Sep 10, 2021

Launch Checklist

  • briefly describe the changes in this PR
    • implements a public API for projections with style spec changes and get/setProjections methods
  • write tests for all new functionality
  • document any changes to public APIs
  • post benchmark scores
  • manually test the debug page
  • tagged @mapbox/map-design-team @mapbox/static-apis if this PR includes style spec API or visual changes
    • @mapbox/map-design-team for a review of the api
  • apply changelog label ('bug', 'feature', 'docs', etc) or use the label 'skip changelog'
  • add an entry inside this element for inclusion in the mapbox-gl-js changelog: <changelog></changelog>

TODO:

  • On initial change, the new projected tiles retain a "shadow" of the previous tiles for some reason

Screen Shot 2021-09-09 at 6 07 22 PM

  • Add render and unit tests
  • Add some documentation to the public API
  • Fix Flow

@ryanhamley ryanhamley changed the base branch from main to projections September 10, 2021 01:08
@ryanhamley ryanhamley marked this pull request as ready for review September 11, 2021 01:22
@ryanhamley ryanhamley self-assigned this Sep 11, 2021
@ryanhamley ryanhamley requested review from mourner and ansis September 11, 2021 01:22
@karimnaaji
Copy link
Contributor

cc @kiryldz

}
}
},
"center": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ryanhamley is there some sort of requires array (i.e.

"requires": [
{
"line-join": "miter"
}
],
) that we could add for both center and parallels to mark albers or lambert as required?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, center and parallels are never required. If they aren't supplied by the user, the defaults will be used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that. It's that center and parallels require name to equal specific values for custom values to work. Specifying this in the spec helps a tool like Studio understand that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I misunderstood your question. Yes, this makes sense and I will update the spec.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On that topic, since center and parallels need a conical projection and are specific to it (Albers/Lambert), have we considered reflecting that in the name structure of it? e.g. conical-center or conic-center, depending on what's most appropriate.

It makes it more clear that it's unused for non-conical projections, and allows other projection specific spec to be introduced.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

center is currently used for conic projections but could be eventually supported by non-conic projections.

parallels would only be for conic projections I think. Just parallels seems clear enough to me but I'm open to conic-parallels if others think it's clearer. d3's parameter is named just parallels. proj strings use lat_1 and lat_2.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

center is currently used for conic projections but could be eventually supported by non-conic projections.

Ok makes sense to leave center as is then.

@@ -3862,6 +3871,52 @@
}
}
},
"projection": {
"name": {
"type": "string",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why this isn't an enum?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want the API to be as flexible as possible. We may make it possible in future versions of this API for developers to supply their own projections, in which case an enum wouldn't work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making this enum allows Studio to pull a list of known values from the spec rather than asking the user to get the string right or hard coding something in. This is also how current properties that require specific values are shaped.

"projection": {
"name": {
"type": "string",
"doc": "The name of the projection to be used for rendering the map. Available projections are Albers Alaska ('alaska'), Albers USA ('albers'), Equal Earth ('equal-earth'), Equirectangular/WGS84 ('equirectangular'), Globe ('globe'), Lambert ('lambert'), Mercator ('mercator'), Natural Earth ('natural-earth'), and Winkel Tripel ('winkel').",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to remove the "Available projections" documented here into a values object for type: enum.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the names here changed since the initial PR state.

Copy link
Member

@mourner mourner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good overall! The only doubt I have is around getProjectionOptions and related logic like handling string vs object — it seems like it's spread or repeated around across many places (setProjection in three different classes, both inside the method and also outside before calling it, etc.), so the flow gets confusing. It's hard to pinpoint exactly, but ideally each part of that logic would only happen at one place.

@@ -43,6 +43,7 @@
<fieldset>
<label>Projection:</label>
<select id="projName">
<option value="albers" selected>Albers USA</option>
<option value="alaska">Albers Alaska</option>
<option value="albers" selected>Albers USA</option>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: duplicate albers

"projection": {
"name": {
"type": "string",
"doc": "The name of the projection to be used for rendering the map. Available projections are Albers Alaska ('alaska'), Albers USA ('albers'), Equal Earth ('equal-earth'), Equirectangular/WGS84 ('equirectangular'), Globe ('globe'), Lambert ('lambert'), Mercator ('mercator'), Natural Earth ('natural-earth'), and Winkel Tripel ('winkel').",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the names here changed since the initial PR state.

"required": true,
"sdk-support": {
"basic functionality": {
"js": "2.5.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"js": "2.5.0"
"js": "2.6.0"

@@ -94,6 +94,15 @@
"delay": 0
}
},
"projection": {
"type": "projection",
"doc": "The projection the map should be rendered in. Possible projections are Albers USA, Albers Alaska, Equal Earth, Equirectangular (WGS84), Globe, Lambert, Mercator, Natural Earth, and Winkel Tripel.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should Globe be removed in this first phase? I think it's also referenced further down.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, my incoming commit that updates the style spec also removes references to globe. I was guessing at what would be included when I first wrote this out.

Comment on lines +102 to +103
"center": [-154, 50],
"parallels": [55, 65]
Copy link
Contributor

@karimnaaji karimnaaji Oct 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a spec for globe view yet, but it seems like it could be a fit under the projection namespace. I've got a few questions:

  • Are these properties (center/parallel) shared between all current projections? Addressed by other comment
  • When we introduce globe and if we find that it's a good fit under the projection namespace, could we extend this spec so that these two properties are optional?
  • Is there room to eventually have globe or projection specific properties under the projection namespace? (e.g. globe-*, for any specific visual styling or tuning of the globe)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there room to eventually have globe or projection specific properties under the projection namespace? (e.g. globe-*, for any specific visual styling or tuning of the globe)

Yes, I think so

When we introduce globe and if we find that it's a good fit under the projection namespace, could we extend this spec so that these two properties are optional?

They should be optional now

}
}
},
"center": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On that topic, since center and parallels need a conical projection and are specific to it (Albers/Lambert), have we considered reflecting that in the name structure of it? e.g. conical-center or conic-center, depending on what's most appropriate.

It makes it more clear that it's unused for non-conical projections, and allows other projection specific spec to be introduced.

* @example
* var map = new mapboxgl.Map({
* container: 'map',
* center: [-122.420679, 37.772537],
* zoom: 13,
* style: style_object,
* hash: true,
* projection: 'winkel',
* projection: {
Copy link
Contributor

@karimnaaji karimnaaji Oct 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it strictly necessary to have projection as part of the map constructor? Removing it could simplify the logic wrt _projectionSetAtRuntime.

For consistency I'd expect projection/terrain/fog to have very similar behaviors/usage as they are all root properties. What's surprising may be that we have a projection in the map constructor but no terrain or fog in it, so we wouldn't have completeness here.

Is there any issue with setting the map projection after the style has loaded?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at all the parameters, it seems like this would be the first style specification introduced as option to the map constructor.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way it's implemented right now a projection provided by the style is used differently than terrain provided by the style. It interprets the projection in the style more as a default than as a fixed value. If a projection has already been set at runtime, it will ignore the projection in the style. This is similar to how zoom/center/bearing can be set in a style. They are only used if nothing else is set. zoom/center/etc can be set in the map constructor.

Conceptually, projections are kind of a map setting whose default can be specified in a style.

Fog and terrain are completely a part of the style. Projections and camera settings are part of how the style is used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all is somewhat vague and a bit unsure. We should discuss this more before releasing.

Copy link
Contributor

@karimnaaji karimnaaji left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, we can continue some review details on the larger PR once this one is merged.

@ryanhamley ryanhamley merged commit 0cc5e30 into projections Oct 14, 2021
@ryanhamley ryanhamley deleted the projections-api branch October 14, 2021 00:16
ansis added a commit that referenced this pull request Oct 19, 2021
* rough projection support

* projections stencil clipping and refactor (#410)

* Enable stencil clipping for line and fill layers

* Use buffers from tile

* Refactor tile bounds buffers

* Rename things to not exclusively be RasterBounds

* Create projections directory

* More refactoring

* Combine matrix calculations

* Cleanup

* Refactor projections to new folder

* Begin debug work

* Tile boundaries are working

* Refactor indexbuffer and segmentvector to per painter

* merge projectx and projecty functions

* nits

Co-authored-by: Ansis Brammanis <ansis@mapbox.com>

* Projections fix location issues (#414)

* Add debug page

* Add projection option

* Wire up projection code with worker

* Rename projections folder to projection

* Refactor and update free camera

* Add Projection type and fix center calculations

* Fix bug with transform._center

* Make Winkel projection noop for now

* Update demo HTML and CSS

* temp remove undistortion

Co-authored-by: Ansis Brammanis <ansis@mapbox.com>

* [projections] Adaptive geometry resampling for alternative projections (#10753)

* implement adaptive resampling of reprojected geometry

* address feedback

* Refactor projections code to get all tests passing (#10732)

* [projections] Simplify and optimize tile transform code (#10780)

* simplify projections tile transform

* skip resampling for mercator

* [projections] Fix performance regression in draw_background (#10747)

* separate tiles for background layers

* additional lint & flow fixes

* try fixing tests

* try fixing render tests

Co-authored-by: Ansis Brammanis <ansis@mapbox.com>

* Pin chrome to version 91 (#10887) (#10896)

* Pin to chrome version 91

* Pin chrome version for test-browser

Co-authored-by: Arindam Bose <arindam.bose@mapbox.com>

* Refactor raw projections, handle projection options (#10913)

* refactor raw projections, handle projection options

* add unprojection to winkel tripel

* fix flow

* Pin chrome to version 91 (#10887)

* Pin to chrome version 91

* Pin chrome version for test-browser

* fix lint

* remove to superfluous sin calls

Co-authored-by: Arindam Bose <arindam.bose@mapbox.com>

* Fix bearing for non-mercator projections (#10781)

* Use adaptive resampling with MARTINI & Earcut for non-Mercator tiles (#10980)

* use adaptive resampling and earcut for non-Mercator tile bounds

* fix unit test

* use adaptive MARTINI mesh for non-Mercator raster tiles

* Clamp unproject to valid geo range in alternate projections (#10992)

* clamp unproject to mercator bounds in all projections

* fix marker test

* avoid wrapping center for non-Mercator projections

* extend alt projections clamping to full lat range

* correct zoom, bearing and shear for projections (#10976)

* fix zoom, bearing and skew for projections

* refactor adjustments

* lint

* add comments

* Fix circle and heatmap on alternate projections (#11074)

* fix circle & heatmap on alternate projections (blunder)

* fix unit test

* fix pitch, line-width and other properties for projections (#11080)

and:
- fix fill-extrusions
- remove global projection variable to allow multiple maps on one page
- avoid recalculating tileTransform

* Add Equal Earth, Natural Earth and Lambert Conformal Conic projections (#11091)

* Fix constraining logic for alternate projections (#11092)

* adaptive bbox for projections, refactor resampling

* better precision for adaptive bounds

* remove leftover

* fix zoom/shear adjustments near poles

* optimize tile transform

* fix lint

* attempt to fix tests

* simplify, clarify and consolidate constraining logic

* minor renames in transform

* safer clamping for zoom adjustments

* Projections public API (#11002)

Co-authored-by: Ansis Brammanis <ansis@mapbox.com>

* fix conflicts

* fix seams around alternate-projected tiles (#11119)

* fix unit tests

* remove alaska

* Basic support for custom maxBounds in alternate projections (#11121)

* rudimentary support for custom maxBounds in alternate projections

* fix flow

* fix image and video sources in alternate projections (#11123)

* clean up debug pages

* remove uncessary deg <--> rad conversions

* fix filename casing

* fix queryRenderedFeatures for alternate projections (#11125)

* Projections fixups (#11127)

* disable terrain and fog for alternate projections (#11126)

* Lazily instantiate projected tile debug buffers and release projected buffers when tiles are unloaded (#11128)

* enable lod tile loading for projections (#11129)

* enable lod tile loading for projections

to significantly reduce the number of tiles at low zoom levels

* use Math.hypot(...)

Co-authored-by: Vladimir Agafonkin <agafonkin@gmail.com>

* add comments

Co-authored-by: Vladimir Agafonkin <agafonkin@gmail.com>

* allow map.setProjection(null)

* add limitations

* avoid recreating tile buffer

Co-authored-by: Karim Naaji <karim.naaji@gmail.com>

* fix assertion error

* fix requires

* center projections vertically

Center projections vertically in 0 to 1 range. This shouldn't matter but
there is some constraining behavior that is currently affected by this.

* Fix tile buffer destroyed but not reset (#11134)

* mention settin bounds in projection docs

Co-authored-by: Ryan Hamley <ryan.hamley@mapbox.com>
Co-authored-by: Vladimir Agafonkin <agafonkin@gmail.com>
Co-authored-by: Arindam Bose <arindam.bose@mapbox.com>
Co-authored-by: Karim Naaji <karim.naaji@gmail.com>
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