maplibre-gl 3.2.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/generate-docs.ts +1 -1
- package/dist/maplibre-gl-csp-worker.js +1 -1
- package/dist/maplibre-gl-csp-worker.js.map +1 -1
- package/dist/maplibre-gl-csp.js +1 -1
- package/dist/maplibre-gl-csp.js.map +1 -1
- package/dist/maplibre-gl-dev.js +223 -219
- package/dist/maplibre-gl-dev.js.map +1 -1
- package/dist/maplibre-gl.d.ts +200 -144
- package/dist/maplibre-gl.js +4 -4
- package/dist/maplibre-gl.js.map +1 -1
- package/package.json +25 -25
- package/src/geo/transform.test.ts +9 -16
- package/src/geo/transform.ts +10 -32
- package/src/render/draw_fill.test.ts +1 -1
- package/src/render/draw_symbol.test.ts +3 -3
- package/src/render/painter.ts +0 -1
- package/src/render/program.ts +0 -1
- package/src/render/terrain.test.ts +17 -0
- package/src/render/terrain.ts +31 -2
- package/src/source/raster_dem_tile_source.test.ts +14 -0
- package/src/source/raster_dem_tile_source.ts +0 -11
- package/src/source/raster_tile_source.test.ts +13 -0
- package/src/source/vector_tile_worker_source.test.ts +44 -74
- package/src/source/vector_tile_worker_source.ts +5 -16
- package/src/source/worker_tile.test.ts +143 -0
- package/src/source/worker_tile.ts +26 -7
- package/src/ui/camera.test.ts +12 -9
- package/src/ui/camera.ts +76 -94
- package/src/ui/handler_manager.ts +2 -2
- package/src/ui/hash.ts +1 -2
- package/src/ui/map.test.ts +17 -12
- package/src/ui/map.ts +131 -44
- package/src/ui/map_events.test.ts +76 -0
- package/src/ui/marker.test.ts +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maplibre-gl",
|
|
3
3
|
"description": "BSD licensed community fork of mapbox-gl, a WebGL interactive maps library",
|
|
4
|
-
"version": "3.2.
|
|
4
|
+
"version": "3.2.1",
|
|
5
5
|
"main": "dist/maplibre-gl.js",
|
|
6
6
|
"style": "dist/maplibre-gl.css",
|
|
7
7
|
"license": "BSD-3-Clause",
|
|
@@ -20,11 +20,12 @@
|
|
|
20
20
|
"@mapbox/unitbezier": "^0.0.1",
|
|
21
21
|
"@mapbox/vector-tile": "^1.3.1",
|
|
22
22
|
"@mapbox/whoots-js": "^3.1.0",
|
|
23
|
-
"@maplibre/maplibre-gl-style-spec": "^19.2.
|
|
23
|
+
"@maplibre/maplibre-gl-style-spec": "^19.2.2",
|
|
24
24
|
"@types/geojson": "^7946.0.10",
|
|
25
25
|
"@types/mapbox__point-geometry": "^0.1.2",
|
|
26
26
|
"@types/mapbox__vector-tile": "^1.3.0",
|
|
27
27
|
"@types/pbf": "^3.0.2",
|
|
28
|
+
"@types/supercluster": "^7.1.0",
|
|
28
29
|
"earcut": "^2.2.4",
|
|
29
30
|
"geojson-vt": "^3.2.1",
|
|
30
31
|
"gl-matrix": "^3.4.3",
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@mapbox/mapbox-gl-rtl-text": "^0.2.3",
|
|
43
44
|
"@mapbox/mvt-fixtures": "^3.10.0",
|
|
44
|
-
"@rollup/plugin-commonjs": "^25.0.
|
|
45
|
+
"@rollup/plugin-commonjs": "^25.0.3",
|
|
45
46
|
"@rollup/plugin-json": "^6.0.0",
|
|
46
47
|
"@rollup/plugin-node-resolve": "^15.1.0",
|
|
47
48
|
"@rollup/plugin-replace": "^5.0.2",
|
|
@@ -53,49 +54,48 @@
|
|
|
53
54
|
"@types/d3": "^7.4.0",
|
|
54
55
|
"@types/diff": "^5.0.3",
|
|
55
56
|
"@types/earcut": "^2.1.1",
|
|
56
|
-
"@types/eslint": "^8.
|
|
57
|
+
"@types/eslint": "^8.44.0",
|
|
57
58
|
"@types/gl": "^6.0.2",
|
|
58
59
|
"@types/glob": "^8.1.0",
|
|
59
|
-
"@types/jest": "^29.5.
|
|
60
|
+
"@types/jest": "^29.5.3",
|
|
60
61
|
"@types/jsdom": "^21.1.1",
|
|
61
62
|
"@types/minimist": "^1.2.2",
|
|
62
63
|
"@types/murmurhash-js": "^1.0.4",
|
|
63
64
|
"@types/nise": "^1.4.1",
|
|
64
|
-
"@types/node": "^20.
|
|
65
|
+
"@types/node": "^20.4.4",
|
|
65
66
|
"@types/offscreencanvas": "^2019.7.0",
|
|
66
67
|
"@types/pixelmatch": "^5.2.4",
|
|
67
68
|
"@types/pngjs": "^6.0.1",
|
|
68
|
-
"@types/react": "^18.2.
|
|
69
|
-
"@types/react-dom": "^18.2.
|
|
69
|
+
"@types/react": "^18.2.15",
|
|
70
|
+
"@types/react-dom": "^18.2.7",
|
|
70
71
|
"@types/request": "^2.48.8",
|
|
71
72
|
"@types/shuffle-seed": "^1.1.0",
|
|
72
|
-
"@types/supercluster": "^7.1.0",
|
|
73
73
|
"@types/window-or-global": "^1.0.4",
|
|
74
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
75
|
-
"@typescript-eslint/parser": "^5.
|
|
74
|
+
"@typescript-eslint/eslint-plugin": "^5.61.0",
|
|
75
|
+
"@typescript-eslint/parser": "^5.62.0",
|
|
76
76
|
"address": "^1.2.2",
|
|
77
77
|
"benchmark": "^2.1.4",
|
|
78
78
|
"canvas": "^2.11.2",
|
|
79
79
|
"cssnano": "^6.0.1",
|
|
80
80
|
"d3": "^7.8.5",
|
|
81
81
|
"d3-queue": "^3.0.7",
|
|
82
|
-
"devtools-protocol": "^0.0.
|
|
82
|
+
"devtools-protocol": "^0.0.1170846",
|
|
83
83
|
"diff": "^5.1.0",
|
|
84
84
|
"dts-bundle-generator": "^8.0.1",
|
|
85
|
-
"eslint": "^8.
|
|
85
|
+
"eslint": "^8.45.0",
|
|
86
86
|
"eslint-config-mourner": "^3.0.0",
|
|
87
87
|
"eslint-plugin-html": "^7.1.0",
|
|
88
88
|
"eslint-plugin-import": "^2.27.5",
|
|
89
|
-
"eslint-plugin-jest": "^27.2.
|
|
89
|
+
"eslint-plugin-jest": "^27.2.3",
|
|
90
90
|
"eslint-plugin-tsdoc": "0.2.17",
|
|
91
|
-
"eslint-plugin-react": "^7.
|
|
91
|
+
"eslint-plugin-react": "^7.33.0",
|
|
92
92
|
"expect": "^29.5.0",
|
|
93
93
|
"gl": "^6.0.2",
|
|
94
|
-
"glob": "^10.3.
|
|
94
|
+
"glob": "^10.3.3",
|
|
95
95
|
"is-builtin-module": "^3.2.1",
|
|
96
|
-
"jest": "^29.
|
|
96
|
+
"jest": "^29.6.1",
|
|
97
97
|
"jest-canvas-mock": "^2.5.2",
|
|
98
|
-
"jest-environment-jsdom": "^29.
|
|
98
|
+
"jest-environment-jsdom": "^29.6.1",
|
|
99
99
|
"jsdom": "^22.1.0",
|
|
100
100
|
"json-stringify-pretty-compact": "^4.0.0",
|
|
101
101
|
"minimist": "^1.2.8",
|
|
@@ -107,22 +107,22 @@
|
|
|
107
107
|
"pdf-merger-js": "^4.3.0",
|
|
108
108
|
"pixelmatch": "^5.3.0",
|
|
109
109
|
"pngjs": "^7.0.0",
|
|
110
|
-
"postcss": "^8.4.
|
|
110
|
+
"postcss": "^8.4.26",
|
|
111
111
|
"postcss-cli": "^10.1.0",
|
|
112
112
|
"postcss-inline-svg": "^6.0.0",
|
|
113
|
-
"pretty-bytes": "^6.1.
|
|
114
|
-
"puppeteer": "^20.
|
|
113
|
+
"pretty-bytes": "^6.1.1",
|
|
114
|
+
"puppeteer": "^20.9.0",
|
|
115
115
|
"react": "^18.2.0",
|
|
116
116
|
"react-dom": "^18.2.0",
|
|
117
|
-
"rollup": "^3.26.
|
|
117
|
+
"rollup": "^3.26.3",
|
|
118
118
|
"rollup-plugin-sourcemaps": "^0.6.3",
|
|
119
119
|
"rw": "^1.3.3",
|
|
120
|
-
"semver": "^7.5.
|
|
120
|
+
"semver": "^7.5.4",
|
|
121
121
|
"shuffle-seed": "^1.1.6",
|
|
122
122
|
"source-map-explorer": "^2.5.3",
|
|
123
123
|
"st": "^3.0.0",
|
|
124
|
-
"stylelint": "^15.10.
|
|
125
|
-
"stylelint-config-standard": "^
|
|
124
|
+
"stylelint": "^15.10.2",
|
|
125
|
+
"stylelint-config-standard": "^34.0.0",
|
|
126
126
|
"ts-jest": "^29.1.1",
|
|
127
127
|
"ts-node": "^10.9.1",
|
|
128
128
|
"tslib": "^2.6.0",
|
|
@@ -406,13 +406,16 @@ describe('transform', () => {
|
|
|
406
406
|
transform.resize(512, 512);
|
|
407
407
|
|
|
408
408
|
// expect same values because of no elevation change
|
|
409
|
-
|
|
410
|
-
|
|
409
|
+
const terrain = {
|
|
410
|
+
getElevationForLngLatZoom: () => 200,
|
|
411
|
+
pointCoordinate: () => null
|
|
412
|
+
};
|
|
413
|
+
transform.recalculateZoom(terrain as any);
|
|
411
414
|
expect(transform.zoom).toBe(14);
|
|
412
415
|
|
|
413
416
|
// expect new zoom because of elevation change
|
|
414
|
-
|
|
415
|
-
transform.recalculateZoom(
|
|
417
|
+
terrain.getElevationForLngLatZoom = () => 400;
|
|
418
|
+
transform.recalculateZoom(terrain as any);
|
|
416
419
|
expect(transform.zoom).toBe(14.127997275621933);
|
|
417
420
|
expect(transform.elevation).toBe(400);
|
|
418
421
|
|
|
@@ -420,8 +423,8 @@ describe('transform', () => {
|
|
|
420
423
|
expect(transform._center.lat).toBe(50.00000000000017);
|
|
421
424
|
|
|
422
425
|
// expect new zoom because of elevation change to point below sea level
|
|
423
|
-
|
|
424
|
-
transform.recalculateZoom(
|
|
426
|
+
terrain.getElevationForLngLatZoom = () => -200;
|
|
427
|
+
transform.recalculateZoom(terrain as any);
|
|
425
428
|
expect(transform.zoom).toBe(13.773740316343467);
|
|
426
429
|
expect(transform.elevation).toBe(-200);
|
|
427
430
|
});
|
|
@@ -458,14 +461,4 @@ describe('transform', () => {
|
|
|
458
461
|
expect(top).toBeCloseTo(79.1823898251593, 10);
|
|
459
462
|
expect(transform.getBounds().getNorthWest().toArray()).toStrictEqual(transform.pointLocation(new Point(0, top)).toArray());
|
|
460
463
|
});
|
|
461
|
-
|
|
462
|
-
test('getElevation with lng less than -180 wraps correctly', () => {
|
|
463
|
-
const OVERSCALETILEID_DOES_NOT_THROW = 4;
|
|
464
|
-
const terrain = {
|
|
465
|
-
getElevation: () => OVERSCALETILEID_DOES_NOT_THROW
|
|
466
|
-
} as any as Terrain;
|
|
467
|
-
const transform = new Transform(0, 22, 0, 85, true);
|
|
468
|
-
expect(transform.getElevation(new LngLat(-183, 40), terrain)).toBe(OVERSCALETILEID_DOES_NOT_THROW);
|
|
469
|
-
});
|
|
470
|
-
|
|
471
464
|
});
|
package/src/geo/transform.ts
CHANGED
|
@@ -30,7 +30,6 @@ export class Transform {
|
|
|
30
30
|
rotationMatrix: mat2;
|
|
31
31
|
pixelsToGLUnits: [number, number];
|
|
32
32
|
cameraToCenterDistance: number;
|
|
33
|
-
cameraToSeaLevelDistance: number;
|
|
34
33
|
mercatorMatrix: mat4;
|
|
35
34
|
projMatrix: mat4;
|
|
36
35
|
invProjMatrix: mat4;
|
|
@@ -40,7 +39,6 @@ export class Transform {
|
|
|
40
39
|
pixelMatrixInverse: mat4;
|
|
41
40
|
glCoordMatrix: mat4;
|
|
42
41
|
labelPlaneMatrix: mat4;
|
|
43
|
-
freezeElevation: boolean;
|
|
44
42
|
_fov: number;
|
|
45
43
|
_pitch: number;
|
|
46
44
|
_zoom: number;
|
|
@@ -57,11 +55,11 @@ export class Transform {
|
|
|
57
55
|
_constraining: boolean;
|
|
58
56
|
_posMatrixCache: {[_: string]: mat4};
|
|
59
57
|
_alignedPosMatrixCache: {[_: string]: mat4};
|
|
58
|
+
_minEleveationForCurrentTile: number;
|
|
60
59
|
|
|
61
60
|
constructor(minZoom?: number, maxZoom?: number, minPitch?: number, maxPitch?: number, renderWorldCopies?: boolean) {
|
|
62
61
|
this.tileSize = 512; // constant
|
|
63
62
|
this.maxValidLatitude = 85.051129; // constant
|
|
64
|
-
this.freezeElevation = false;
|
|
65
63
|
|
|
66
64
|
this._renderWorldCopies = renderWorldCopies === undefined ? true : !!renderWorldCopies;
|
|
67
65
|
this._minZoom = minZoom || 0;
|
|
@@ -84,6 +82,7 @@ export class Transform {
|
|
|
84
82
|
this._edgeInsets = new EdgeInsets();
|
|
85
83
|
this._posMatrixCache = {};
|
|
86
84
|
this._alignedPosMatrixCache = {};
|
|
85
|
+
this._minEleveationForCurrentTile = 0;
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
clone(): Transform {
|
|
@@ -99,6 +98,7 @@ export class Transform {
|
|
|
99
98
|
this.height = that.height;
|
|
100
99
|
this._center = that._center;
|
|
101
100
|
this._elevation = that._elevation;
|
|
101
|
+
this._minEleveationForCurrentTile = that._minEleveationForCurrentTile;
|
|
102
102
|
this.zoom = that.zoom;
|
|
103
103
|
this.angle = that.angle;
|
|
104
104
|
this._fov = that._fov;
|
|
@@ -470,30 +470,6 @@ export class Transform {
|
|
|
470
470
|
|
|
471
471
|
get point(): Point { return this.project(this.center); }
|
|
472
472
|
|
|
473
|
-
/**
|
|
474
|
-
* Updates the center-elevation value unless freezeElevation is activated.
|
|
475
|
-
* @param terrain - the terrain
|
|
476
|
-
*/
|
|
477
|
-
updateElevation(terrain?: Terrain) {
|
|
478
|
-
if (this.freezeElevation) return;
|
|
479
|
-
this.elevation = terrain ? this.getElevation(this._center, terrain) : 0;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
/**
|
|
483
|
-
* get the elevation from terrain for the current zoomlevel.
|
|
484
|
-
* @param lnglat - the location
|
|
485
|
-
* @param terrain - the terrain
|
|
486
|
-
* @returns elevation in meters
|
|
487
|
-
*/
|
|
488
|
-
getElevation(lnglat: LngLat, terrain: Terrain): number {
|
|
489
|
-
const merc = MercatorCoordinate.fromLngLat(lnglat.wrap());
|
|
490
|
-
const worldSize = (1 << this.tileZoom) * EXTENT;
|
|
491
|
-
const mercX = merc.x * worldSize, mercY = merc.y * worldSize;
|
|
492
|
-
const tileX = Math.floor(mercX / EXTENT), tileY = Math.floor(mercY / EXTENT);
|
|
493
|
-
const tileID = new OverscaledTileID(this.tileZoom, 0, this.tileZoom, tileX, tileY);
|
|
494
|
-
return terrain.getElevation(tileID, mercX % EXTENT, mercY % EXTENT, EXTENT);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
473
|
/**
|
|
498
474
|
* get the camera position in LngLat and altitudes in meter
|
|
499
475
|
* @returns An object with lngLat & altitude.
|
|
@@ -516,7 +492,7 @@ export class Transform {
|
|
|
516
492
|
recalculateZoom(terrain: Terrain) {
|
|
517
493
|
// find position the camera is looking on
|
|
518
494
|
const center = this.pointLocation(this.centerPoint, terrain);
|
|
519
|
-
const elevation =
|
|
495
|
+
const elevation = terrain.getElevationForLngLatZoom(center, this.tileZoom);
|
|
520
496
|
const deltaElevation = this.elevation - elevation;
|
|
521
497
|
if (!deltaElevation) return;
|
|
522
498
|
|
|
@@ -557,7 +533,7 @@ export class Transform {
|
|
|
557
533
|
*/
|
|
558
534
|
locationPoint(lnglat: LngLat, terrain?: Terrain): Point {
|
|
559
535
|
return terrain ?
|
|
560
|
-
this.coordinatePoint(this.locationCoordinate(lnglat),
|
|
536
|
+
this.coordinatePoint(this.locationCoordinate(lnglat), terrain.getElevationForLngLatZoom(lnglat, this.tileZoom), this.pixelMatrix3D) :
|
|
561
537
|
this.coordinatePoint(this.locationCoordinate(lnglat));
|
|
562
538
|
}
|
|
563
539
|
|
|
@@ -827,9 +803,11 @@ export class Transform {
|
|
|
827
803
|
this.glCoordMatrix = m;
|
|
828
804
|
|
|
829
805
|
// Calculate the camera to sea-level distance in pixel in respect of terrain
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
const
|
|
806
|
+
const cameraToSeaLevelDistance = this.cameraToCenterDistance + this._elevation * this._pixelPerMeter / Math.cos(this._pitch);
|
|
807
|
+
// In case of negative minimum elevation (e.g. the dead see, under the sea maps) use a lower plane for calculation
|
|
808
|
+
const minElevation = Math.min(this.elevation, this._minEleveationForCurrentTile);
|
|
809
|
+
const cameraToLowestPointDistance = cameraToSeaLevelDistance - minElevation * this._pixelPerMeter / Math.cos(this._pitch);
|
|
810
|
+
const lowestPlane = minElevation < 0 ? cameraToLowestPointDistance : cameraToSeaLevelDistance;
|
|
833
811
|
|
|
834
812
|
// Find the distance from the center point [width/2 + offset.x, height/2 + offset.y] to the
|
|
835
813
|
// center top point [width/2 + offset.x, 0] in Z units, using the law of sines.
|
|
@@ -28,7 +28,7 @@ describe('drawFill', () => {
|
|
|
28
28
|
const painterMock: Painter = constructMockPainer();
|
|
29
29
|
const layer: FillStyleLayer = constructMockLayer();
|
|
30
30
|
|
|
31
|
-
const programMock = new Program(null as any, null as any, null as any, null as any, null as any, null as any
|
|
31
|
+
const programMock = new Program(null as any, null as any, null as any, null as any, null as any, null as any);
|
|
32
32
|
(painterMock.useProgram as jest.Mock).mockReturnValue(programMock);
|
|
33
33
|
|
|
34
34
|
const mockTile = constructMockTile(layer);
|
|
@@ -62,7 +62,7 @@ describe('drawSymbol', () => {
|
|
|
62
62
|
|
|
63
63
|
const tileId = new OverscaledTileID(1, 0, 1, 0, 0);
|
|
64
64
|
tileId.posMatrix = mat4.create();
|
|
65
|
-
const programMock = new Program(null, null, null, null, null, null
|
|
65
|
+
const programMock = new Program(null, null, null, null, null, null);
|
|
66
66
|
(painterMock.useProgram as jest.Mock).mockReturnValue(programMock);
|
|
67
67
|
const bucketMock = new SymbolBucket(null);
|
|
68
68
|
bucketMock.icon = {
|
|
@@ -124,7 +124,7 @@ describe('drawSymbol', () => {
|
|
|
124
124
|
|
|
125
125
|
const tileId = new OverscaledTileID(1, 0, 1, 0, 0);
|
|
126
126
|
tileId.posMatrix = mat4.create();
|
|
127
|
-
const programMock = new Program(null, null, null, null, null, null
|
|
127
|
+
const programMock = new Program(null, null, null, null, null, null);
|
|
128
128
|
(painterMock.useProgram as jest.Mock).mockReturnValue(programMock);
|
|
129
129
|
const bucketMock = new SymbolBucket(null);
|
|
130
130
|
bucketMock.icon = {
|
|
@@ -189,7 +189,7 @@ describe('drawSymbol', () => {
|
|
|
189
189
|
|
|
190
190
|
const tileId = new OverscaledTileID(1, 0, 1, 0, 0);
|
|
191
191
|
tileId.posMatrix = mat4.create();
|
|
192
|
-
const programMock = new Program(null, null, null, null, null, null
|
|
192
|
+
const programMock = new Program(null, null, null, null, null, null);
|
|
193
193
|
(painterMock.useProgram as jest.Mock).mockReturnValue(programMock);
|
|
194
194
|
const bucketMock = new SymbolBucket(null);
|
|
195
195
|
bucketMock.icon = {
|
package/src/render/painter.ts
CHANGED
package/src/render/program.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type {DEMData} from '../data/dem_data';
|
|
|
11
11
|
import {Tile} from '../source/tile';
|
|
12
12
|
import {Painter} from './painter';
|
|
13
13
|
import {mat4} from 'gl-matrix';
|
|
14
|
+
import {LngLat} from '../geo/lng_lat';
|
|
14
15
|
|
|
15
16
|
describe('Terrain', () => {
|
|
16
17
|
test('pointCoordiate should not return null', () => {
|
|
@@ -193,4 +194,20 @@ describe('Terrain', () => {
|
|
|
193
194
|
expect(mockTerrain.getDEMElevation(null, 0.4, 0.2)).toBeCloseTo(42);
|
|
194
195
|
});
|
|
195
196
|
|
|
197
|
+
test('getElevationForLngLatZoom with lng less than -180 wraps correctly', () => {
|
|
198
|
+
const terrain = new Terrain(null, {} as any, {} as any);
|
|
199
|
+
|
|
200
|
+
const OVERSCALETILEID_DOES_NOT_THROW = 4;
|
|
201
|
+
terrain.getElevation = () => OVERSCALETILEID_DOES_NOT_THROW;
|
|
202
|
+
expect(terrain.getElevationForLngLatZoom(new LngLat(-183, 40), 0)).toBe(OVERSCALETILEID_DOES_NOT_THROW);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test('getMinTileElevationForLngLatZoom with lng less than -180 wraps correctly', () => {
|
|
206
|
+
const terrain = new Terrain(null, {} as any, {} as any);
|
|
207
|
+
|
|
208
|
+
const OVERSCALETILEID_DOES_NOT_THROW = 4;
|
|
209
|
+
terrain.getMinMaxElevation = () => ({minElevation: OVERSCALETILEID_DOES_NOT_THROW, maxElevation: 42});
|
|
210
|
+
expect(terrain.getMinTileElevationForLngLatZoom(new LngLat(-183, 40), 0)).toBe(OVERSCALETILEID_DOES_NOT_THROW);
|
|
211
|
+
});
|
|
212
|
+
|
|
196
213
|
});
|
package/src/render/terrain.ts
CHANGED
|
@@ -18,7 +18,7 @@ import {TerrainSourceCache} from '../source/terrain_source_cache';
|
|
|
18
18
|
import {SourceCache} from '../source/source_cache';
|
|
19
19
|
import {EXTENT} from '../data/extent';
|
|
20
20
|
import type {TerrainSpecification} from '@maplibre/maplibre-gl-style-spec';
|
|
21
|
-
import {earthRadius} from '../geo/lng_lat';
|
|
21
|
+
import {LngLat, earthRadius} from '../geo/lng_lat';
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* A terrain GPU related object
|
|
@@ -180,7 +180,18 @@ export class Terrain {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
/**
|
|
183
|
-
*
|
|
183
|
+
* Get the elevation for given {@link LngLat} in respect of exaggeration.
|
|
184
|
+
* @param lnglat - the location
|
|
185
|
+
* @param zoom - the zoom
|
|
186
|
+
* @returns the elevation
|
|
187
|
+
*/
|
|
188
|
+
getElevationForLngLatZoom(lnglat: LngLat, zoom: number) {
|
|
189
|
+
const {tileID, mercatorX, mercatorY} = this._getOverscaledTileIDFromLngLatZoom(lnglat, zoom);
|
|
190
|
+
return this.getElevation(tileID, mercatorX % EXTENT, mercatorY % EXTENT, EXTENT);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get the elevation for given coordinate in respect of exaggeration.
|
|
184
195
|
* @param tileID - the tile id
|
|
185
196
|
* @param x - between 0 .. EXTENT
|
|
186
197
|
* @param y - between 0 .. EXTENT
|
|
@@ -391,6 +402,11 @@ export class Terrain {
|
|
|
391
402
|
return 2 * Math.PI * earthRadius / Math.pow(2, zoom) / 5;
|
|
392
403
|
}
|
|
393
404
|
|
|
405
|
+
getMinTileElevationForLngLatZoom(lnglat: LngLat, zoom: number) {
|
|
406
|
+
const {tileID} = this._getOverscaledTileIDFromLngLatZoom(lnglat, zoom);
|
|
407
|
+
return this.getMinMaxElevation(tileID).minElevation ?? 0;
|
|
408
|
+
}
|
|
409
|
+
|
|
394
410
|
/**
|
|
395
411
|
* Get the minimum and maximum elevation contained in a tile. This includes any
|
|
396
412
|
* exaggeration included in the terrain.
|
|
@@ -409,4 +425,17 @@ export class Terrain {
|
|
|
409
425
|
return minMax;
|
|
410
426
|
}
|
|
411
427
|
|
|
428
|
+
_getOverscaledTileIDFromLngLatZoom(lnglat: LngLat, zoom: number): { tileID: OverscaledTileID; mercatorX: number; mercatorY: number} {
|
|
429
|
+
const mercatorCoordinate = MercatorCoordinate.fromLngLat(lnglat.wrap());
|
|
430
|
+
const worldSize = (1 << zoom) * EXTENT;
|
|
431
|
+
const mercatorX = mercatorCoordinate.x * worldSize;
|
|
432
|
+
const mercatorY = mercatorCoordinate.y * worldSize;
|
|
433
|
+
const tileX = Math.floor(mercatorX / EXTENT), tileY = Math.floor(mercatorY / EXTENT);
|
|
434
|
+
const tileID = new OverscaledTileID(zoom, 0, zoom, tileX, tileY);
|
|
435
|
+
return {
|
|
436
|
+
tileID,
|
|
437
|
+
mercatorX,
|
|
438
|
+
mercatorY
|
|
439
|
+
};
|
|
440
|
+
}
|
|
412
441
|
}
|
|
@@ -150,4 +150,18 @@ describe('RasterTileSource', () => {
|
|
|
150
150
|
});
|
|
151
151
|
server.respond();
|
|
152
152
|
});
|
|
153
|
+
|
|
154
|
+
it('serializes options', () => {
|
|
155
|
+
const source = createSource({
|
|
156
|
+
tiles: ['http://localhost:2900/raster-dem/{z}/{x}/{y}.png'],
|
|
157
|
+
minzoom: 2,
|
|
158
|
+
maxzoom: 10
|
|
159
|
+
});
|
|
160
|
+
expect(source.serialize()).toStrictEqual({
|
|
161
|
+
type: 'raster-dem',
|
|
162
|
+
tiles: ['http://localhost:2900/raster-dem/{z}/{x}/{y}.png'],
|
|
163
|
+
minzoom: 2,
|
|
164
|
+
maxzoom: 10
|
|
165
|
+
});
|
|
166
|
+
});
|
|
153
167
|
});
|
|
@@ -43,17 +43,6 @@ export class RasterDEMTileSource extends RasterTileSource implements Source {
|
|
|
43
43
|
this.encoding = options.encoding || 'mapbox';
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
serialize() {
|
|
47
|
-
return {
|
|
48
|
-
type: 'raster-dem',
|
|
49
|
-
url: this.url,
|
|
50
|
-
tileSize: this.tileSize,
|
|
51
|
-
tiles: this.tiles,
|
|
52
|
-
bounds: this.bounds,
|
|
53
|
-
encoding: this.encoding
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
46
|
loadTile(tile: Tile, callback: Callback<void>) {
|
|
58
47
|
const url = tile.tileID.canonical.url(this.tiles, this.map.getPixelRatio(), this.scheme);
|
|
59
48
|
tile.request = ImageRequest.getImage(this.map._requestManager.transformRequest(url, ResourceType.Tile), imageLoaded.bind(this), this.map._refreshExpiredTiles);
|
|
@@ -170,4 +170,17 @@ describe('RasterTileSource', () => {
|
|
|
170
170
|
expect((server.requests.pop() as any).aborted).toBe(true);
|
|
171
171
|
});
|
|
172
172
|
|
|
173
|
+
it('serializes options', () => {
|
|
174
|
+
const source = createSource({
|
|
175
|
+
tiles: ['http://localhost:2900/raster/{z}/{x}/{y}.png'],
|
|
176
|
+
minzoom: 2,
|
|
177
|
+
maxzoom: 10
|
|
178
|
+
});
|
|
179
|
+
expect(source.serialize()).toStrictEqual({
|
|
180
|
+
type: 'raster',
|
|
181
|
+
tiles: ['http://localhost:2900/raster/{z}/{x}/{y}.png'],
|
|
182
|
+
minzoom: 2,
|
|
183
|
+
maxzoom: 10
|
|
184
|
+
});
|
|
185
|
+
});
|
|
173
186
|
});
|
|
@@ -6,7 +6,7 @@ import {VectorTileWorkerSource} from '../source/vector_tile_worker_source';
|
|
|
6
6
|
import {StyleLayerIndex} from '../style/style_layer_index';
|
|
7
7
|
import {fakeServer, FakeServer} from 'nise';
|
|
8
8
|
import {Actor} from '../util/actor';
|
|
9
|
-
import {TileParameters, WorkerTileParameters} from './worker_source';
|
|
9
|
+
import {TileParameters, WorkerTileParameters, WorkerTileResult} from './worker_source';
|
|
10
10
|
import {WorkerTile} from './worker_tile';
|
|
11
11
|
import {setPerformance} from '../util/test/util';
|
|
12
12
|
|
|
@@ -18,7 +18,6 @@ describe('vector tile worker source', () => {
|
|
|
18
18
|
global.fetch = null;
|
|
19
19
|
server = fakeServer.create();
|
|
20
20
|
setPerformance();
|
|
21
|
-
|
|
22
21
|
});
|
|
23
22
|
|
|
24
23
|
afterEach(() => {
|
|
@@ -87,83 +86,54 @@ describe('vector tile worker source', () => {
|
|
|
87
86
|
expect(callback).toHaveBeenCalledTimes(1);
|
|
88
87
|
});
|
|
89
88
|
|
|
90
|
-
test('VectorTileWorkerSource#
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
parse
|
|
99
|
-
} as any as WorkerTile
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const callback1 = jest.fn();
|
|
103
|
-
const callback2 = jest.fn();
|
|
104
|
-
source.reloadTile({uid: 0} as any as WorkerTileParameters, callback1);
|
|
105
|
-
expect(parse).toHaveBeenCalledTimes(1);
|
|
106
|
-
|
|
107
|
-
source.loaded[0].status = 'parsing';
|
|
108
|
-
source.reloadTile({uid: 0} as any as WorkerTileParameters, callback2);
|
|
109
|
-
expect(parse).toHaveBeenCalledTimes(1);
|
|
110
|
-
|
|
111
|
-
parse.mock.calls[0][4]();
|
|
112
|
-
expect(parse).toHaveBeenCalledTimes(2);
|
|
113
|
-
expect(callback1).toHaveBeenCalledTimes(1);
|
|
114
|
-
expect(callback2).toHaveBeenCalledTimes(0);
|
|
115
|
-
|
|
116
|
-
parse.mock.calls[1][4]();
|
|
117
|
-
expect(callback1).toHaveBeenCalledTimes(1);
|
|
118
|
-
expect(callback2).toHaveBeenCalledTimes(1);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
test('VectorTileWorkerSource#reloadTile handles multiple pending reloads', () => {
|
|
122
|
-
// https://github.com/mapbox/mapbox-gl-js/issues/6308
|
|
123
|
-
const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []);
|
|
124
|
-
const parse = jest.fn();
|
|
89
|
+
test('VectorTileWorkerSource#loadTile reparses tile if the reloadTile has been called during parsing', (done) => {
|
|
90
|
+
const rawTileData = new Uint8Array([]);
|
|
91
|
+
function loadVectorData(params, callback) {
|
|
92
|
+
return callback(null, {
|
|
93
|
+
vectorTile: new vt.VectorTile(new Protobuf(rawTileData)),
|
|
94
|
+
rawData: rawTileData
|
|
95
|
+
});
|
|
96
|
+
}
|
|
125
97
|
|
|
126
|
-
|
|
127
|
-
'
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
};
|
|
98
|
+
const layerIndex = new StyleLayerIndex([{
|
|
99
|
+
id: 'test',
|
|
100
|
+
source: 'source',
|
|
101
|
+
'source-layer': 'test',
|
|
102
|
+
type: 'fill'
|
|
103
|
+
}]);
|
|
133
104
|
|
|
134
|
-
const
|
|
135
|
-
const callback2 = jest.fn();
|
|
136
|
-
const callback3 = jest.fn();
|
|
137
|
-
source.reloadTile({uid: 0} as any as WorkerTileParameters, callback1);
|
|
138
|
-
expect(parse).toHaveBeenCalledTimes(1);
|
|
105
|
+
const source = new VectorTileWorkerSource(actor, layerIndex, [], loadVectorData);
|
|
139
106
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
107
|
+
const parseWorkerTileMock = jest
|
|
108
|
+
.spyOn(WorkerTile.prototype, 'parse')
|
|
109
|
+
.mockImplementation(function(data, layerIndex, availableImages, actor, callback) {
|
|
110
|
+
this.status = 'parsing';
|
|
111
|
+
window.setTimeout(() => callback(null, {} as WorkerTileResult), 10);
|
|
112
|
+
});
|
|
143
113
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
parse.mock.calls[1][4]();
|
|
157
|
-
expect(parse).toHaveBeenCalledTimes(3);
|
|
158
|
-
expect(callback1).toHaveBeenCalledTimes(1);
|
|
159
|
-
expect(callback2).toHaveBeenCalledTimes(1);
|
|
160
|
-
expect(callback3).toHaveBeenCalledTimes(0);
|
|
161
|
-
|
|
162
|
-
parse.mock.calls[2][4]();
|
|
163
|
-
expect(callback1).toHaveBeenCalledTimes(1);
|
|
164
|
-
expect(callback2).toHaveBeenCalledTimes(1);
|
|
165
|
-
expect(callback3).toHaveBeenCalledTimes(1);
|
|
114
|
+
let loadCallbackCalled = false;
|
|
115
|
+
source.loadTile({
|
|
116
|
+
source: 'source',
|
|
117
|
+
uid: 0,
|
|
118
|
+
tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}},
|
|
119
|
+
request: {url: 'http://localhost:2900/faketile.pbf'}
|
|
120
|
+
} as any as WorkerTileParameters, (err, res) => {
|
|
121
|
+
expect(err).toBeFalsy();
|
|
122
|
+
expect(res).toBeDefined();
|
|
123
|
+
loadCallbackCalled = true;
|
|
124
|
+
});
|
|
166
125
|
|
|
126
|
+
source.reloadTile({
|
|
127
|
+
source: 'source',
|
|
128
|
+
uid: '0',
|
|
129
|
+
tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}},
|
|
130
|
+
} as any as WorkerTileParameters, (err, res) => {
|
|
131
|
+
expect(err).toBeFalsy();
|
|
132
|
+
expect(res).toBeDefined();
|
|
133
|
+
expect(parseWorkerTileMock).toHaveBeenCalledTimes(2);
|
|
134
|
+
expect(loadCallbackCalled).toBeTruthy();
|
|
135
|
+
done();
|
|
136
|
+
});
|
|
167
137
|
});
|
|
168
138
|
|
|
169
139
|
test('VectorTileWorkerSource#reloadTile does not reparse tiles with no vectorTile data but does call callback', () => {
|