@@ -18,6 +18,11 @@ import {SimpleMeshLayer} from '@deck.gl/mesh-layers';
1818import { COORDINATE_SYSTEM } from '@deck.gl/core' ;
1919import type { Mesh } from '@loaders.gl/schema' ;
2020import { TerrainWorkerLoader } from '@loaders.gl/terrain' ;
21+ import {
22+ MAX_LATITUDE as MAX_WEB_MERCATOR_LATITUDE ,
23+ lngLatToWorld ,
24+ worldToLngLat
25+ } from '@math.gl/web-mercator' ;
2126import TileLayer , { TileLayerProps } from '../tile-layer/tile-layer' ;
2227import type {
2328 Bounds ,
@@ -33,8 +38,6 @@ const TILE_OVERLAP_PIXELS = 1;
3338const MIN_TERRAIN_MESH_MAX_ERROR = 1 ;
3439const MAX_LATITUDE = 90 ;
3540const MAX_LONGITUDE = 180 ;
36- const DEGREES_TO_RADIANS = Math . PI / 180 ;
37- const RADIANS_TO_DEGREES = 180 / Math . PI ;
3841
3942const defaultProps : DefaultProps < TerrainLayerProps > = {
4043 ...TileLayer . defaultProps ,
@@ -110,6 +113,7 @@ type TerrainLoadProps = {
110113 elevationData : string | null ;
111114 elevationDecoder : ElevationDecoder ;
112115 meshMaxError : number ;
116+ remapToWebMercatorTile ?: boolean ;
113117 signal ?: AbortSignal ;
114118} ;
115119
@@ -205,6 +209,7 @@ export default class TerrainLayer<ExtraPropsT extends {} = {}> extends Composite
205209 bounds,
206210 elevationDecoder,
207211 meshMaxError,
212+ remapToWebMercatorTile,
208213 signal
209214 } : TerrainLoadProps ) : Promise < Mesh > | null {
210215 if ( ! elevationData ) {
@@ -223,7 +228,16 @@ export default class TerrainLayer<ExtraPropsT extends {} = {}> extends Composite
223228 }
224229 } ;
225230 const { fetch} = this . props ;
226- return fetch ( elevationData , { propName : 'elevationData' , layer : this , loadOptions, signal} ) ;
231+ const terrain = fetch ( elevationData , {
232+ propName : 'elevationData' ,
233+ layer : this ,
234+ loadOptions,
235+ signal
236+ } ) ;
237+
238+ return remapToWebMercatorTile
239+ ? terrain . then ( mesh => ( mesh ? remapMeshToWebMercatorTile ( mesh , bounds ) : mesh ) )
240+ : terrain ;
227241 }
228242
229243 getTiledTerrainData ( tile : TileLoadProps ) : Promise < MeshAndTexture > {
@@ -245,22 +259,18 @@ export default class TerrainLayer<ExtraPropsT extends {} = {}> extends Composite
245259 topRight = [ bbox . right , bbox . top ] ;
246260 }
247261 const bounds : Bounds = [ bottomLeft [ 0 ] , bottomLeft [ 1 ] , topRight [ 0 ] , topRight [ 1 ] ] ;
248- const overlappedBounds = getOverlappedBounds (
249- bounds ,
250- this . props . tileSize ,
251- Boolean ( viewport . resolution && viewport . resolution > 0 )
252- ) ;
262+ const isGlobe = Boolean ( viewport . resolution && viewport . resolution > 0 ) ;
263+ const overlappedBounds = getOverlappedBounds ( bounds , this . props . tileSize , isGlobe ) ;
253264
254265 const terrain =
255266 this . loadTerrain ( {
256267 elevationData : dataUrl ,
257268 bounds : overlappedBounds ,
258269 elevationDecoder,
259270 meshMaxError,
271+ remapToWebMercatorTile : isGlobe ,
260272 signal
261- } ) ?. then ( mesh =>
262- viewport . resolution && mesh ? remapMeshToWebMercatorTile ( mesh , overlappedBounds ) : mesh
263- ) ?? Promise . resolve ( null ) ;
273+ } ) ?? Promise . resolve ( null ) ;
264274 const surface = textureUrl
265275 ? // If surface image fails to load, the tile should still be displayed
266276 fetch ( textureUrl , { propName : 'texture' , layer : this , loaders : [ ] , signal} ) . catch ( _ => null )
@@ -431,14 +441,14 @@ function remapMeshToWebMercatorTile(mesh: Mesh, bounds: Bounds): Mesh {
431441 }
432442
433443 const [ , south , , north ] = bounds ;
434- const northY = lngLatToMercatorY ( north ) ;
435- const southY = lngLatToMercatorY ( south ) ;
444+ const northY = lngLatToMercatorWorldY ( north ) ;
445+ const southY = lngLatToMercatorWorldY ( south ) ;
436446 const remappedPositions = new Float32Array ( positions ) ;
437447
438448 for ( let i = 0 ; i < texCoords . length / 2 ; i ++ ) {
439449 const v = texCoords [ i * 2 + 1 ] ;
440450 const mercatorY = northY + ( southY - northY ) * v ;
441- remappedPositions [ i * 3 + 1 ] = mercatorYToLat ( mercatorY ) ;
451+ remappedPositions [ i * 3 + 1 ] = worldToLngLat ( [ 0 , mercatorY ] ) [ 1 ] ;
442452 }
443453
444454 return {
@@ -453,12 +463,10 @@ function remapMeshToWebMercatorTile(mesh: Mesh, bounds: Bounds): Mesh {
453463 } ;
454464}
455465
456- function lngLatToMercatorY ( latitude : number ) : number {
457- const clampedLatitude = Math . max ( - 85.051129 , Math . min ( 85.051129 , latitude ) ) ;
458- const sin = Math . sin ( clampedLatitude * DEGREES_TO_RADIANS ) ;
459- return 0.5 - Math . log ( ( 1 + sin ) / ( 1 - sin ) ) / ( 4 * Math . PI ) ;
460- }
461-
462- function mercatorYToLat ( y : number ) : number {
463- return Math . atan ( Math . sinh ( Math . PI * ( 1 - 2 * y ) ) ) * RADIANS_TO_DEGREES ;
466+ function lngLatToMercatorWorldY ( latitude : number ) : number {
467+ const clampedLatitude = Math . max (
468+ - MAX_WEB_MERCATOR_LATITUDE ,
469+ Math . min ( MAX_WEB_MERCATOR_LATITUDE , latitude )
470+ ) ;
471+ return lngLatToWorld ( [ 0 , clampedLatitude ] ) [ 1 ] ;
464472}
0 commit comments