Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- _...Add new stuff here..._

### 🐞 Bug fixes
- Fix getting the right zoom for getElevationForLngLat ([#6825](https://github.com/maplibre/maplibre-gl-js/pull/6825)) (by [@HarelM](https://github.com/HarelM))
- _...Add new stuff here..._

## 5.14.0
Expand Down
2 changes: 1 addition & 1 deletion src/data/dem_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export class DEMData {
}

_idx(x: number, y: number) {
if (x < -1 || x >= this.dim + 1 || y < -1 || y >= this.dim + 1) throw new RangeError('out of range source coordinates for DEM data');
if (x < -1 || x >= this.dim + 1 || y < -1 || y >= this.dim + 1) throw new RangeError(`Out of range source coordinates for DEM data. x: ${x}, y: ${y}, dim: ${this.dim}`);
return (y + 1) * this.stride + (x + 1);
}

Expand Down
2 changes: 1 addition & 1 deletion src/geo/projection/mercator_transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ export class MercatorTransform implements ITransform {

locationToScreenPoint(lnglat: LngLat, terrain?: Terrain): Point {
return terrain ?
this.coordinatePoint(MercatorCoordinate.fromLngLat(lnglat), terrain.getElevationForLngLat(lnglat), this._pixelMatrix3D) :
this.coordinatePoint(MercatorCoordinate.fromLngLat(lnglat), terrain.getElevationForLngLat(lnglat, this), this._pixelMatrix3D) :
this.coordinatePoint(MercatorCoordinate.fromLngLat(lnglat));
}

Expand Down
30 changes: 26 additions & 4 deletions src/render/terrain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {OverscaledTileID} from '../tile/tile_id';
import {Tile} from '../tile/tile';
import {LngLat} from '../geo/lng_lat';
import {MAX_TILE_ZOOM, MIN_TILE_ZOOM} from '../util/util';
import {MercatorTransform} from '../geo/projection/mercator_transform';
import type {TileManager} from '../tile/tile_manager';
import type {TerrainSpecification} from '@maplibre/maplibre-gl-style-spec';
import type {DEMData} from '../data/dem_data';
Expand Down Expand Up @@ -291,15 +292,36 @@ describe('Terrain', () => {
expect(mockTerrain.getDEMElevation(null, 0.4, 0.2)).toBeCloseTo(42);
});

test('getElevationForLngLat uses source max zoom', () => {
const terrain = new Terrain(null, {_source: {tileSize: 512}} as any, {} as any);
test('getElevationForLngLat uses covering tiles to get the right zoom', () => {
const zoom = 10;
const painter = {
context: new Context(gl),
width: 1,
height: 1,
getTileTexture: () => null
} as any as Painter;
const tileManager = {
_source: {minzoom: 3, maxzoom: 22, tileSize: 512},
_cache: {max: 10},
getTileByID: () => {
return new Tile(new OverscaledTileID(zoom, 0, 0, 0, 0), 256);
},
} as any as TileManager;
const terrain = new Terrain(
painter,
tileManager,
{exaggeration: 2} as any as TerrainSpecification,
);

const spy = vi.fn();
terrain.getElevation = spy;
terrain.getElevationForLngLat(new LngLat(0, 0));
const transform = new MercatorTransform({minZoom: 3, maxZoom: 22, minPitch: 0, maxPitch: 85, renderWorldCopies: true});
transform.resize(200, 200);
transform.setZoom(zoom);
terrain.getElevationForLngLat(new LngLat(0, 0), transform);

expect(spy).toHaveBeenCalled();
expect((spy.mock.calls[0][0] as OverscaledTileID).canonical.z).toBe(terrain.tileManager.maxzoom);
expect((spy.mock.calls[0][0] as OverscaledTileID).canonical.z).toBe(zoom);
});

test('getElevationForLngLatZoom with lng less than -180 wraps correctly', () => {
Expand Down
30 changes: 19 additions & 11 deletions src/render/terrain.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@

import {type Tile} from '../tile/tile';
import {mat4, vec2} from 'gl-matrix';
import {OverscaledTileID} from '../tile/tile_id';
import {RGBAImage} from '../util/image';
import {warnOnce} from '../util/util';
import {Pos3dArray, TriangleIndexArray} from '../data/array_types.g';
import pos3dAttributes from '../data/pos3d_attributes';
import {SegmentVector} from '../data/segment';
import {type Painter} from './painter';
import {Texture} from '../render/texture';
import type {Framebuffer} from '../gl/framebuffer';
import type Point from '@mapbox/point-geometry';
import {MercatorCoordinate} from '../geo/mercator_coordinate';
import {TerrainTileManager} from '../tile/terrain_tile_manager';
import {type TileManager} from '../tile/tile_manager';
import {EXTENT} from '../data/extent';
import type {TerrainSpecification} from '@maplibre/maplibre-gl-style-spec';
import {type LngLat, earthRadius} from '../geo/lng_lat';
import {Mesh} from './mesh';
import {isInBoundsForZoomLngLat} from '../util/world_bounds';
import {NORTH_POLE_Y, SOUTH_POLE_Y} from './subdivision';
import {coveringTiles} from '../geo/projection/covering_tiles';
import type Point from '@mapbox/point-geometry';
import type {Tile} from '../tile/tile';
import type {Framebuffer} from '../gl/framebuffer';
import type {TileManager} from '../tile/tile_manager';
import type {TerrainSpecification} from '@maplibre/maplibre-gl-style-spec';
import type {Painter} from './painter';
import type {IReadonlyTransform} from '../geo/transform_interface';

/**
* @internal
Expand Down Expand Up @@ -160,8 +162,7 @@ export class Terrain {
if (!(x >= 0 && x < extent && y >= 0 && y < extent)) return 0;
const terrain = this.getTerrainData(tileID);
const dem = terrain.tile?.dem;
if (!dem)
return 0;
if (!dem) return 0;

const pos = vec2.transformMat4([] as any, [x / extent * EXTENT, y / extent * EXTENT], terrain.u_terrain_matrix);
const coord = [pos[0] * dem.dim, pos[1] * dem.dim];
Expand Down Expand Up @@ -197,8 +198,15 @@ export class Terrain {
* @param lnglat - the location
* @returns the elevation
*/
getElevationForLngLat(lnglat: LngLat) {
return this.getElevationForLngLatZoom(lnglat, this.tileManager.maxzoom);
getElevationForLngLat(lnglat: LngLat, transform: IReadonlyTransform) {
const terrainCoveringTiles = coveringTiles(transform, {maxzoom: this.tileManager.maxzoom, minzoom: this.tileManager.minzoom, tileSize: 512, terrain: this});
let zoom = 0;
for (const tile of terrainCoveringTiles) {
if (tile.canonical.z > zoom) {
zoom = Math.min(tile.canonical.z, this.tileManager.maxzoom);
}
}
return this.getElevationForLngLatZoom(lnglat, zoom);
}

/**
Expand Down Expand Up @@ -241,7 +249,7 @@ export class Terrain {
sourceTile.needsTerrainPrepare = false;
}
// create matrix for lookup in dem data
const matrixKey = sourceTile && (sourceTile + sourceTile.tileID.key) + tileID.key;
const matrixKey = sourceTile && sourceTile.toString() + sourceTile.tileID.key + tileID.key;
if (matrixKey && !this._demMatrixCache[matrixKey]) {
const maxzoom = this.tileManager.getSource().maxzoom;
let dz = tileID.canonical.z - sourceTile.tileID.canonical.z;
Expand Down
3 changes: 2 additions & 1 deletion src/ui/camera.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2492,7 +2492,8 @@ describe('queryTerrainElevation', () => {
camera.queryTerrainElevation([1, 2]);

expect(camera.terrain.getElevationForLngLat).toHaveBeenCalledWith(
expect.objectContaining({lng: 1, lat: 2,})
expect.objectContaining({lng: 1, lat: 2,}),
camera.transform
);
});
});
Expand Down
2 changes: 1 addition & 1 deletion src/ui/camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1638,6 +1638,6 @@ export abstract class Camera extends Evented {
if (!this.terrain) {
return null;
}
return this.terrain.getElevationForLngLat(LngLat.convert(lngLatLike));
return this.terrain.getElevationForLngLat(LngLat.convert(lngLatLike), this.transform);
}
}
2 changes: 1 addition & 1 deletion src/ui/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ export class Map extends Camera {

calculateCameraOptionsFromTo(from: LngLat, altitudeFrom: number, to: LngLat, altitudeTo?: number): CameraOptions {
if (altitudeTo == null && this.terrain) {
altitudeTo = this.terrain.getElevationForLngLat(to);
altitudeTo = this.terrain.getElevationForLngLat(to, this.transform);
}
return super.calculateCameraOptionsFromTo(from, altitudeFrom, to, altitudeTo);
}
Expand Down
2 changes: 1 addition & 1 deletion src/ui/marker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ export class Marker extends Evented {
// Read depth framebuffer, getting position of terrain in line of sight to marker
const terrainDistance = map.terrain.depthAtPoint(this._pos);
// Transform marker position to clip space
const elevation = map.terrain.getElevationForLngLat(this._lngLat);
const elevation = map.terrain.getElevationForLngLat(this._lngLat, map.transform);
const markerDistance = map.transform.lngLatToCameraDepth(this._lngLat, elevation);
const forgiveness = .006;
if (markerDistance - terrainDistance < forgiveness) {
Expand Down