diff --git a/CHANGELOG.md b/CHANGELOG.md index c555c5315a..c0978d9366 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## main ### ✨ Features and improvements + - ⚠️ Add the ability to import a script in the worker thread and call `addProtocol` and `removeProtocol` there ([#3459](https://github.com/maplibre/maplibre-gl-js/pull/3459)) - this also changed how `addSourceType` works since now you'll need to load the script with `maplibregl.importScriptInWorkers`. - Upgraded to use Node JS 20 and removed the dependency of `gl` package from the tests to allow easier develpment setup. - Improved precision and added a subtle fade transition to marker opacity changes ([#3431](https://github.com/maplibre/maplibre-gl-js/pull/3431)) @@ -10,6 +11,7 @@ - Fix the shifted mouse events after a css transform scale on the map container ([#3437](https://github.com/maplibre/maplibre-gl-js/pull/3437)) - Fix markers remaining transparent when disabling terrain ([#3431](https://github.com/maplibre/maplibre-gl-js/pull/3431)) +- Fix labels disappearing when enabling terrain at high zoom ([#3545](https://github.com/maplibre/maplibre-gl-js/pull/3545)) - _...Add new stuff here..._ ## 4.0.0-pre.2 diff --git a/src/data/bucket/symbol_bucket.ts b/src/data/bucket/symbol_bucket.ts index 5810d648d2..dcbf020c0f 100644 --- a/src/data/bucket/symbol_bucket.ts +++ b/src/data/bucket/symbol_bucket.ts @@ -302,7 +302,7 @@ register('CollisionBuffers', CollisionBuffers); * `this.textCollisionBox`: Debug SymbolBuffers for text collision boxes * The results are sent to the foreground for rendering * - * 4. performSymbolPlacement(bucket, collisionIndex) is run on the foreground, + * 4. placement.ts is run on the foreground, * and uses the CollisionIndex along with current camera settings to determine * which symbols can actually show on the map. Collided symbols are hidden * using a dynamic "OpacityVertexArray". diff --git a/src/geo/transform.ts b/src/geo/transform.ts index 180e83cb02..6e414dd0f7 100644 --- a/src/geo/transform.ts +++ b/src/geo/transform.ts @@ -40,6 +40,7 @@ export class Transform { pixelMatrixInverse: mat4; glCoordMatrix: mat4; labelPlaneMatrix: mat4; + minElevationForCurrentTile: number; _fov: number; _pitch: number; _zoom: number; @@ -56,7 +57,6 @@ export class Transform { _constraining: boolean; _posMatrixCache: {[_: string]: mat4}; _alignedPosMatrixCache: {[_: string]: mat4}; - _minEleveationForCurrentTile: number; constructor(minZoom?: number, maxZoom?: number, minPitch?: number, maxPitch?: number, renderWorldCopies?: boolean) { this.tileSize = 512; // constant @@ -83,7 +83,7 @@ export class Transform { this._edgeInsets = new EdgeInsets(); this._posMatrixCache = {}; this._alignedPosMatrixCache = {}; - this._minEleveationForCurrentTile = 0; + this.minElevationForCurrentTile = 0; } clone(): Transform { @@ -99,7 +99,7 @@ export class Transform { this.height = that.height; this._center = that._center; this._elevation = that._elevation; - this._minEleveationForCurrentTile = that._minEleveationForCurrentTile; + this.minElevationForCurrentTile = that.minElevationForCurrentTile; this.zoom = that.zoom; this.angle = that.angle; this._fov = that._fov; @@ -816,7 +816,7 @@ export class Transform { // Calculate the camera to sea-level distance in pixel in respect of terrain const cameraToSeaLevelDistance = this.cameraToCenterDistance + this._elevation * this._pixelPerMeter / Math.cos(this._pitch); // In case of negative minimum elevation (e.g. the dead see, under the sea maps) use a lower plane for calculation - const minElevation = Math.min(this.elevation, this._minEleveationForCurrentTile); + const minElevation = Math.min(this.elevation, this.minElevationForCurrentTile); const cameraToLowestPointDistance = cameraToSeaLevelDistance - minElevation * this._pixelPerMeter / Math.cos(this._pitch); const lowestPlane = minElevation < 0 ? cameraToLowestPointDistance : cameraToSeaLevelDistance; diff --git a/src/render/terrain.ts b/src/render/terrain.ts index f6d7d0f010..7114b380f6 100644 --- a/src/render/terrain.ts +++ b/src/render/terrain.ts @@ -76,7 +76,7 @@ export type TerrainMesh = { */ export class Terrain { /** - * The style this terrain crresponds to + * The style this terrain corresponds to */ painter: Painter; /** diff --git a/src/source/terrain_source_cache.ts b/src/source/terrain_source_cache.ts index 909e823246..8d32bbfd1e 100644 --- a/src/source/terrain_source_cache.ts +++ b/src/source/terrain_source_cache.ts @@ -193,7 +193,7 @@ export class TerrainSourceCache extends Evented { } /** - * get a list of tiles, loaded after a spezific time. This is used to update depth & coords framebuffers. + * get a list of tiles, loaded after a specific time. This is used to update depth & coords framebuffers. * @param time - the time * @returns the relevant tiles */ diff --git a/src/ui/camera.ts b/src/ui/camera.ts index 39d8b87fdb..476b6edb93 100644 --- a/src/ui/camera.ts +++ b/src/ui/camera.ts @@ -1067,7 +1067,7 @@ export abstract class Camera extends Evented { } _updateElevation(k: number) { - this.transform._minEleveationForCurrentTile = this.terrain.getMinTileElevationForLngLatZoom(this._elevationCenter, this.transform.tileZoom); + this.transform.minElevationForCurrentTile = this.terrain.getMinTileElevationForLngLatZoom(this._elevationCenter, this.transform.tileZoom); const elevation = this.terrain.getElevationForLngLatZoom(this._elevationCenter, this.transform.tileZoom); // target terrain updated during flight, slowly move camera to new height if (k < 1 && elevation !== this._elevationTarget) { diff --git a/src/ui/map.ts b/src/ui/map.ts index 4ccab94cb5..d793a40134 100644 --- a/src/ui/map.ts +++ b/src/ui/map.ts @@ -1922,12 +1922,13 @@ export class Map extends Camera { this.terrain = null; if (this.painter.renderToTexture) this.painter.renderToTexture.destruct(); this.painter.renderToTexture = null; - this.transform._minEleveationForCurrentTile = 0; + this.transform.minElevationForCurrentTile = 0; this.transform.elevation = 0; } else { // add terrain const sourceCache = this.style.sourceCaches[options.source]; if (!sourceCache) throw new Error(`cannot load terrain, because there exists no source with ID: ${options.source}`); + sourceCache.reload(); // Warn once if user is using the same source for hillshade and terrain for (const index in this.style._layers) { const thisLayer = this.style._layers[index]; @@ -1937,14 +1938,14 @@ export class Map extends Camera { } this.terrain = new Terrain(this.painter, sourceCache, options); this.painter.renderToTexture = new RenderToTexture(this.painter, this.terrain); - this.transform._minEleveationForCurrentTile = this.terrain.getMinTileElevationForLngLatZoom(this.transform.center, this.transform.tileZoom); + this.transform.minElevationForCurrentTile = this.terrain.getMinTileElevationForLngLatZoom(this.transform.center, this.transform.tileZoom); this.transform.elevation = this.terrain.getElevationForLngLatZoom(this.transform.center, this.transform.tileZoom); this._terrainDataCallback = e => { if (e.dataType === 'style') { this.terrain.sourceCache.freeRtt(); } else if (e.dataType === 'source' && e.tile) { if (e.sourceId === options.source && !this._elevationFreeze) { - this.transform._minEleveationForCurrentTile = this.terrain.getMinTileElevationForLngLatZoom(this.transform.center, this.transform.tileZoom); + this.transform.minElevationForCurrentTile = this.terrain.getMinTileElevationForLngLatZoom(this.transform.center, this.transform.tileZoom); this.transform.elevation = this.terrain.getElevationForLngLatZoom(this.transform.center, this.transform.tileZoom); } this.terrain.sourceCache.freeRtt(e.tile.tileID); @@ -3070,12 +3071,12 @@ export class Map extends Camera { // update terrain stuff if (this.terrain) { this.terrain.sourceCache.update(this.transform, this.terrain); - this.transform._minEleveationForCurrentTile = this.terrain.getMinTileElevationForLngLatZoom(this.transform.center, this.transform.tileZoom); + this.transform.minElevationForCurrentTile = this.terrain.getMinTileElevationForLngLatZoom(this.transform.center, this.transform.tileZoom); if (!this._elevationFreeze) { this.transform.elevation = this.terrain.getElevationForLngLatZoom(this.transform.center, this.transform.tileZoom); } } else { - this.transform._minEleveationForCurrentTile = 0; + this.transform.minElevationForCurrentTile = 0; this.transform.elevation = 0; } diff --git a/test/integration/render/tests/symbol-geometry/point/expected.png b/test/integration/render/tests/symbol-geometry/point/expected.png index 20821f8145..fbc5e8d2e3 100644 Binary files a/test/integration/render/tests/symbol-geometry/point/expected.png and b/test/integration/render/tests/symbol-geometry/point/expected.png differ diff --git a/test/integration/render/tests/symbol-geometry/point/style.json b/test/integration/render/tests/symbol-geometry/point/style.json index 7ff4d872e9..760dfdb9a7 100644 --- a/test/integration/render/tests/symbol-geometry/point/style.json +++ b/test/integration/render/tests/symbol-geometry/point/style.json @@ -7,21 +7,29 @@ "height": 256 } }, - "center": [0, 0], + "center": [ + 0, + 0 + ], "zoom": 0, "sources": { "geometry": { "type": "geojson", "data": { "type": "FeatureCollection", - "features": [{ - "type": "Feature", - "properties": {}, - "geometry": { - "type": "Point", - "coordinates": [0, 0] + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } } - }] + ] } } }, @@ -38,15 +46,18 @@ "type": "symbol", "source": "geometry", "layout": { - "icon-image": "rocket-12", - "text-field": "Mapbox", - "text-font": [ - "Open Sans Semibold", - "Arial Unicode MS Bold" - ], - "text-allow-overlap": true, - "text-ignore-placement": true, - "text-offset": [0, 1] + "icon-image": "rocket-12", + "text-field": "MapLibre", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-allow-overlap": true, + "text-ignore-placement": true, + "text-offset": [ + 0, + 1 + ] } } ] diff --git a/test/integration/render/tests/terrain/symbol-add-terrain/expected.png b/test/integration/render/tests/terrain/symbol-add-terrain/expected.png new file mode 100644 index 0000000000..9f78f0b925 Binary files /dev/null and b/test/integration/render/tests/terrain/symbol-add-terrain/expected.png differ diff --git a/test/integration/render/tests/terrain/symbol-add-terrain/style.json b/test/integration/render/tests/terrain/symbol-add-terrain/style.json new file mode 100644 index 0000000000..413e7331b6 --- /dev/null +++ b/test/integration/render/tests/terrain/symbol-add-terrain/style.json @@ -0,0 +1,115 @@ +{ + "version": 8, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "timeout": 60000, + "metadata": { + "test": { + "height": 512, + "width": 512, + "operations": [ + [ + "wait" + ], + [ + "setTerrain" + ], + [ + "wait" + ], + [ + "setTerrain", + { + "source": "terrain", + "exaggeration": 1 + } + ], + [ + "wait" + ] + ] + } + }, + "center": [ + 35.38, + 31.55 + ], + "zoom": 16.25, + "pitch": 53, + "sources": { + "hillshadeSource": { + "type": "raster-dem", + "tiles": [ + "local://tiles/terrain/{z}-{x}-{y}.terrain.png" + ], + "minzoom": 0, + "maxzoom": 12 + }, + "terrain": { + "type": "raster-dem", + "tiles": [ + "local://tiles/terrain/{z}-{x}-{y}.terrain.png" + ], + "minzoom": 7, + "maxzoom": 12, + "tileSize": 256 + }, + "geometry": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + 35.38, + 31.55 + ] + } + } + ] + } + } + }, + "layers": [ + { + "id": "hills", + "type": "hillshade", + "source": "hillshadeSource", + "layout": { + "visibility": "visible" + }, + "paint": { + "hillshade-shadow-color": "#473B24", + "hillshade-illumination-anchor": "map", + "hillshade-illumination-direction": 150 + } + }, + { + "id": "geometry", + "type": "symbol", + "source": "geometry", + "layout": { + "icon-image": "rocket-12", + "text-field": "MapLibre", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-allow-overlap": true, + "text-ignore-placement": true, + "text-offset": [ + 0, + 1 + ] + } + } + ], + "terrain": { + "source": "terrain", + "exaggeration": 1 + } +} diff --git a/test/integration/render/tests/terrain/symbol/expected.png b/test/integration/render/tests/terrain/symbol/expected.png new file mode 100644 index 0000000000..efd6d2d765 Binary files /dev/null and b/test/integration/render/tests/terrain/symbol/expected.png differ diff --git a/test/integration/render/tests/terrain/symbol/style.json b/test/integration/render/tests/terrain/symbol/style.json new file mode 100644 index 0000000000..5ed45c2ced --- /dev/null +++ b/test/integration/render/tests/terrain/symbol/style.json @@ -0,0 +1,85 @@ +{ + "version": 8, + "sprite": "local://sprites/sprite", + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "metadata": { + "test": { + "height": 512, + "width": 512 + } + }, + "center": [ + 35.384566, + 31.556437 + ], + "zoom": 16.25, + "pitch": 53, + "bearing": 81.6, + "sources": { + "repeat": { + "type": "raster", + "tiles": [ + "local://tiles/white-with-x.png" + ], + "tileSize": 256 + }, + "terrain": { + "type": "raster-dem", + "tiles": [ + "local://tiles/terrain/{z}-{x}-{y}.terrain.png" + ], + "minzoom": 7, + "maxzoom": 12, + "tileSize": 256 + }, + "geometry": { + "type": "geojson", + "data": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + 35.384566, + 31.556437 + ] + } + } + ] + } + } + }, + "layers": [ + { + "id": "osm", + "type": "raster", + "source": "repeat" + }, + { + "id": "geometry", + "type": "symbol", + "source": "geometry", + "layout": { + "icon-image": "rocket-12", + "text-field": "MapLibre", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-allow-overlap": true, + "text-ignore-placement": true, + "text-offset": [ + 0, + 1 + ] + } + } + ], + "terrain": { + "source": "terrain", + "exaggeration": 1 + } +}