mapbox / mapbox-gl-js

Interactive, thoroughly customizable maps in the browser, powered by vector tiles and WebGL
https://docs.mapbox.com/mapbox-gl-js/
Other
11.24k stars 2.23k forks source link

Provide a means to determine occlusion of LatLng positions when using setTerrain() #10211

Open jaybo opened 3 years ago

jaybo commented 3 years ago

Motivation

I have an app which projects pixel based animations using a D3 canvas onto a mapboxgl map. All of the animated objects are at sea level and represent dynamic current velocities or tide stations. In V2, after enabling 3D terrains via setTerrain(), my D3 canvas objects don't correctly disappear when occluded by intervening terrain.

In the image below, the foreground arrows are correctly displayed, but all of the background yellow boxes (at sea level on another body of water in the distance) should not be visible since they should be hidden behind the intervening mountains. When the world was "flat" this wasn't an issue, but now with setTerrain() enabled, there is visual confusion.

image

Design Alternatives

While I could rewrite everything to project my pixel based D3 animations into geojson and add them to a mapbox layer, this is, er, work and I have no idea if performance would be impacted. And this seems like a general issue that others will also likely confront.

I would assume map.project() would be the best place to return this information. The current return value is:

Returns a Point representing pixel coordinates, relative to the map's container, 
that correspond to the specified geographical location.  

When the map is pitched and lnglat is completely behind the camera, 
there are no pixel coordinates corresponding to that location. 
In that case, the x and y components of the returned Point are set to Number.MAX_VALUE.

Design

Add an optional parameter to map.project() indicating that Number.MAX_VALUE should be returned also in the case of occlusion.

map.project(coordinate, onlyIfVisible = false);

This would introduce no backward compatibility issues.

A more general solution would be to add an additional API which explicitly handles elevation such as:

map.project3D(coordinate3D, onlyIfVisible = false);

Mock-Up

Concepts

Implementation

karimnaaji commented 3 years ago

Capturing some of the discussion about this API with @arindam1993 :

This specific function signature seems to be the most flexible to honor the above use cases:

getOcclusion({min:{latlng, altitude}, max:{latlng, altitude}} | {latlng, altitude?}) : bool | null
karimnaaji commented 3 years ago

As for naming, I think queryOcclusion would also work, as it seems like it's more common in our naming convention.

valentinbdv commented 2 hours ago

Hello, I hope all is well at Mapbox.

I would need something like this for a complex map project using terrain and 3D objects. As the issue is quite old, is there a solution already implemented to handle this or do you plan to make progress on this?

Thank you very much for your feedback.