@deck.gl-community/geo-layers 9.2.8 → 9.3.0-beta.2

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.
Files changed (82) hide show
  1. package/dist/global-grid-layer/global-grid-cluster-layer.d.ts.map +1 -1
  2. package/dist/global-grid-layer/global-grid-cluster-layer.js +1 -0
  3. package/dist/global-grid-layer/global-grid-cluster-layer.js.map +1 -1
  4. package/dist/index.cjs +1799 -7
  5. package/dist/index.cjs.map +4 -4
  6. package/dist/index.d.ts +7 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +3 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/shared-tile-2d-layer/deck-tile-traversal.d.ts +5 -0
  11. package/dist/shared-tile-2d-layer/deck-tile-traversal.d.ts.map +1 -0
  12. package/dist/shared-tile-2d-layer/deck-tile-traversal.js +173 -0
  13. package/dist/shared-tile-2d-layer/deck-tile-traversal.js.map +1 -0
  14. package/dist/shared-tile-2d-layer/deck-tileset-adapter.d.ts +26 -0
  15. package/dist/shared-tile-2d-layer/deck-tileset-adapter.d.ts.map +1 -0
  16. package/dist/shared-tile-2d-layer/deck-tileset-adapter.js +174 -0
  17. package/dist/shared-tile-2d-layer/deck-tileset-adapter.js.map +1 -0
  18. package/dist/shared-tile-2d-layer/index.d.ts +4 -0
  19. package/dist/shared-tile-2d-layer/index.d.ts.map +1 -0
  20. package/dist/shared-tile-2d-layer/index.js +6 -0
  21. package/dist/shared-tile-2d-layer/index.js.map +1 -0
  22. package/dist/shared-tile-2d-layer/shared-tile-2d-layer.d.ts +151 -0
  23. package/dist/shared-tile-2d-layer/shared-tile-2d-layer.d.ts.map +1 -0
  24. package/dist/shared-tile-2d-layer/shared-tile-2d-layer.js +422 -0
  25. package/dist/shared-tile-2d-layer/shared-tile-2d-layer.js.map +1 -0
  26. package/dist/shared-tile-2d-layer/shared-tile-2d-view.d.ts +57 -0
  27. package/dist/shared-tile-2d-layer/shared-tile-2d-view.d.ts.map +1 -0
  28. package/dist/shared-tile-2d-layer/shared-tile-2d-view.js +253 -0
  29. package/dist/shared-tile-2d-layer/shared-tile-2d-view.js.map +1 -0
  30. package/dist/shared-tile-2d-layer/url-template.d.ts +9 -0
  31. package/dist/shared-tile-2d-layer/url-template.d.ts.map +1 -0
  32. package/dist/shared-tile-2d-layer/url-template.js +25 -0
  33. package/dist/shared-tile-2d-layer/url-template.js.map +1 -0
  34. package/dist/tile-grid-layer/tile-grid-layer.d.ts +47 -0
  35. package/dist/tile-grid-layer/tile-grid-layer.d.ts.map +1 -0
  36. package/dist/tile-grid-layer/tile-grid-layer.js +94 -0
  37. package/dist/tile-grid-layer/tile-grid-layer.js.map +1 -0
  38. package/dist/tile-source-layer/tile-source-layer.d.ts +2 -2
  39. package/dist/tile-source-layer/tile-source-layer.d.ts.map +1 -1
  40. package/dist/tileset/adapter.d.ts +38 -0
  41. package/dist/tileset/adapter.d.ts.map +1 -0
  42. package/dist/tileset/adapter.js +5 -0
  43. package/dist/tileset/adapter.js.map +1 -0
  44. package/dist/tileset/index.cjs +721 -0
  45. package/dist/tileset/index.cjs.map +7 -0
  46. package/dist/tileset/index.d.ts +8 -0
  47. package/dist/tileset/index.d.ts.map +1 -0
  48. package/dist/tileset/index.js +7 -0
  49. package/dist/tileset/index.js.map +1 -0
  50. package/dist/tileset/tile-2d-header.d.ts +71 -0
  51. package/dist/tileset/tile-2d-header.d.ts.map +1 -0
  52. package/dist/tileset/tile-2d-header.js +168 -0
  53. package/dist/tileset/tile-2d-header.js.map +1 -0
  54. package/dist/tileset/tileset-2d.d.ts +210 -0
  55. package/dist/tileset/tileset-2d.d.ts.map +1 -0
  56. package/dist/tileset/tileset-2d.js +531 -0
  57. package/dist/tileset/tileset-2d.js.map +1 -0
  58. package/dist/tileset/types.d.ts +44 -0
  59. package/dist/tileset/types.d.ts.map +1 -0
  60. package/dist/tileset/types.js +5 -0
  61. package/dist/tileset/types.js.map +1 -0
  62. package/dist/utils/memoize.d.ts +2 -0
  63. package/dist/utils/memoize.d.ts.map +1 -0
  64. package/dist/utils/memoize.js +36 -0
  65. package/dist/utils/memoize.js.map +1 -0
  66. package/package.json +17 -11
  67. package/src/global-grid-layer/global-grid-cluster-layer.ts +1 -1
  68. package/src/index.ts +14 -0
  69. package/src/shared-tile-2d-layer/deck-tile-traversal.ts +247 -0
  70. package/src/shared-tile-2d-layer/deck-tileset-adapter.ts +262 -0
  71. package/src/shared-tile-2d-layer/index.ts +7 -0
  72. package/src/shared-tile-2d-layer/shared-tile-2d-layer.ts +681 -0
  73. package/src/shared-tile-2d-layer/shared-tile-2d-view.ts +339 -0
  74. package/src/shared-tile-2d-layer/url-template.ts +40 -0
  75. package/src/tile-grid-layer/tile-grid-layer.ts +158 -0
  76. package/src/tile-source-layer/tile-source-layer.ts +2 -2
  77. package/src/tileset/adapter.ts +47 -0
  78. package/src/tileset/index.ts +22 -0
  79. package/src/tileset/tile-2d-header.ts +210 -0
  80. package/src/tileset/tileset-2d.ts +705 -0
  81. package/src/tileset/types.ts +38 -0
  82. package/src/utils/memoize.ts +38 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deck.gl-community/geo-layers",
3
- "version": "9.2.8",
3
+ "version": "9.3.0-beta.2",
4
4
  "description": "Add-0n geospatial layers for deck.gl",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -22,6 +22,11 @@
22
22
  "types": "./dist/index.d.ts",
23
23
  "require": "./dist/index.cjs",
24
24
  "import": "./dist/index.js"
25
+ },
26
+ "./tileset": {
27
+ "types": "./dist/tileset/index.d.ts",
28
+ "require": "./dist/tileset/index.cjs",
29
+ "import": "./dist/tileset/index.js"
25
30
  }
26
31
  },
27
32
  "files": [
@@ -33,21 +38,22 @@
33
38
  "test-watch": "vitest"
34
39
  },
35
40
  "dependencies": {
36
- "@deck.gl/core": "~9.2.8",
37
- "@deck.gl/geo-layers": "~9.2.8",
38
- "@deck.gl/layers": "~9.2.8",
39
- "@loaders.gl/loader-utils": "^4.2.0",
40
- "@luma.gl/core": "~9.2.6",
41
- "@luma.gl/engine": "~9.2.6",
42
- "@luma.gl/shadertools": "~9.2.6",
41
+ "@deck.gl/core": "~9.3.0",
42
+ "@deck.gl/geo-layers": "~9.3.0",
43
+ "@deck.gl/layers": "~9.3.0",
44
+ "@loaders.gl/loader-utils": "^4.4.1",
45
+ "@luma.gl/core": "~9.3.2",
46
+ "@luma.gl/engine": "~9.3.2",
47
+ "@luma.gl/shadertools": "~9.3.2",
43
48
  "@math.gl/core": "^4.0.0",
49
+ "@probe.gl/stats": "^4.1.1",
44
50
  "a5-js": "^0.5.0",
45
51
  "h3-js": "^4.2.1"
46
52
  },
47
53
  "devDependencies": {
48
- "@deck.gl/test-utils": "~9.2.8",
49
- "@luma.gl/webgpu": "~9.2.6",
54
+ "@deck.gl/test-utils": "~9.3.0",
55
+ "@luma.gl/webgpu": "~9.3.2",
50
56
  "@probe.gl/test-utils": "^4.0.4"
51
57
  },
52
- "gitHead": "9cb179aa3d1707f32116034150ab7130ce88b18c"
58
+ "gitHead": "82660b8a29be0958c81acd00669b3034375186ea"
53
59
  }
@@ -34,7 +34,7 @@ export class GlobalGridClusterLayer<DataT = any, ExtraProps extends {} = {}> ext
34
34
  globalGrid: {type: 'object', compare: true, value: undefined!}
35
35
  } as const satisfies DefaultProps<GlobalGridClusterLayerProps>;
36
36
 
37
- declare state: {
37
+ state = null as unknown as {
38
38
  polygons: {polygon: number[][][]}[];
39
39
  };
40
40
 
package/src/index.ts CHANGED
@@ -4,6 +4,20 @@
4
4
 
5
5
  export type {TileSourceLayerProps} from './tile-source-layer/tile-source-layer';
6
6
  export {TileSourceLayer} from './tile-source-layer/tile-source-layer';
7
+ export type {
8
+ SharedTile2DLayerProps,
9
+ SharedTile2DLayerPickingInfo
10
+ } from './shared-tile-2d-layer/index';
11
+ export {SharedTile2DLayer, sharedTile2DDeckAdapter} from './shared-tile-2d-layer/index';
12
+ export type {SharedTileset2DProps, SharedTileset2DBaseProps} from './tileset/index';
13
+ export type {
14
+ SharedTileset2DAdapter,
15
+ SharedTileset2DTraversalContext,
16
+ SharedTileset2DTileContext
17
+ } from './tileset/index';
18
+ export {SharedTileset2D, SharedTile2DHeader} from './tileset/index';
19
+ export type {TileGridLayerProps} from './tile-grid-layer/tile-grid-layer';
20
+ export {TileGridLayer} from './tile-grid-layer/tile-grid-layer';
7
21
 
8
22
  export {GlobalGridLayer, type GlobalGridLayerProps} from './global-grid-layer/global-grid-layer';
9
23
 
@@ -0,0 +1,247 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {Viewport, WebMercatorViewport, _GlobeViewport} from '@deck.gl/core';
6
+ import {
7
+ CullingVolume,
8
+ Plane,
9
+ AxisAlignedBoundingBox,
10
+ makeOrientedBoundingBoxFromPoints
11
+ } from '@math.gl/culling';
12
+ import {lngLatToWorld} from '@math.gl/web-mercator';
13
+ import type {Bounds, TileIndex, ZRange} from '../tileset/types';
14
+ import {osmTile2lngLat} from './deck-tileset-adapter';
15
+
16
+ const TILE_SIZE = 512;
17
+ const MAX_MAPS = 3;
18
+ const REF_POINTS_5 = [
19
+ [0.5, 0.5],
20
+ [0, 0],
21
+ [0, 1],
22
+ [1, 0],
23
+ [1, 1]
24
+ ];
25
+ const REF_POINTS_9 = REF_POINTS_5.concat([
26
+ [0, 0.5],
27
+ [0.5, 0],
28
+ [1, 0.5],
29
+ [0.5, 1]
30
+ ]);
31
+ const REF_POINTS_11 = REF_POINTS_9.concat([
32
+ [0.25, 0.5],
33
+ [0.75, 0.5]
34
+ ]);
35
+
36
+ class OSMNode {
37
+ x: number;
38
+ y: number;
39
+ z: number;
40
+
41
+ private childVisible?: boolean;
42
+ private selected?: boolean;
43
+ private _children?: OSMNode[];
44
+
45
+ constructor(x: number, y: number, z: number) {
46
+ this.x = x;
47
+ this.y = y;
48
+ this.z = z;
49
+ }
50
+
51
+ get children(): OSMNode[] {
52
+ if (!this._children) {
53
+ const x = this.x * 2;
54
+ const y = this.y * 2;
55
+ const z = this.z + 1;
56
+ this._children = [
57
+ new OSMNode(x, y, z),
58
+ new OSMNode(x, y + 1, z),
59
+ new OSMNode(x + 1, y, z),
60
+ new OSMNode(x + 1, y + 1, z)
61
+ ];
62
+ }
63
+ return this._children;
64
+ }
65
+
66
+ update(params: {
67
+ viewport: Viewport;
68
+ project: ((xyz: number[]) => number[]) | null;
69
+ cullingVolume: CullingVolume;
70
+ elevationBounds: ZRange;
71
+ minZ: number;
72
+ maxZ: number;
73
+ bounds?: Bounds;
74
+ offset: number;
75
+ }): boolean {
76
+ const {viewport, cullingVolume, elevationBounds, minZ, maxZ, bounds, offset, project} = params;
77
+ const boundingVolume = this.getBoundingVolume(elevationBounds, offset, project);
78
+
79
+ if (bounds && !this.insideBounds(bounds)) {
80
+ return false;
81
+ }
82
+
83
+ const isInside = cullingVolume.computeVisibility(boundingVolume);
84
+ if (isInside < 0) {
85
+ return false;
86
+ }
87
+
88
+ if (!this.childVisible) {
89
+ let {z} = this;
90
+ if (z < maxZ && z >= minZ) {
91
+ const distance =
92
+ (boundingVolume.distanceTo(viewport.cameraPosition) * viewport.scale) / viewport.height;
93
+ z += Math.floor(Math.log2(distance));
94
+ }
95
+ if (z >= maxZ) {
96
+ this.selected = true;
97
+ return true;
98
+ }
99
+ }
100
+
101
+ this.selected = false;
102
+ this.childVisible = true;
103
+ for (const child of this.children) {
104
+ child.update(params);
105
+ }
106
+ return true;
107
+ }
108
+
109
+ getSelected(result: OSMNode[] = []): OSMNode[] {
110
+ if (this.selected) {
111
+ result.push(this);
112
+ }
113
+ if (this._children) {
114
+ for (const node of this._children) {
115
+ node.getSelected(result);
116
+ }
117
+ }
118
+ return result;
119
+ }
120
+
121
+ insideBounds([minX, minY, maxX, maxY]: Bounds): boolean {
122
+ const scale = Math.pow(2, this.z);
123
+ const extent = TILE_SIZE / scale;
124
+
125
+ return (
126
+ this.x * extent < maxX &&
127
+ this.y * extent < maxY &&
128
+ (this.x + 1) * extent > minX &&
129
+ (this.y + 1) * extent > minY
130
+ );
131
+ }
132
+
133
+ getBoundingVolume(
134
+ zRange: ZRange,
135
+ worldOffset: number,
136
+ project: ((xyz: number[]) => number[]) | null
137
+ ) {
138
+ if (project) {
139
+ const refPoints = this.z < 1 ? REF_POINTS_11 : this.z < 2 ? REF_POINTS_9 : REF_POINTS_5;
140
+ const refPointPositions: number[][] = [];
141
+ for (const p of refPoints) {
142
+ const lngLat: number[] = osmTile2lngLat(this.x + p[0], this.y + p[1], this.z);
143
+ lngLat[2] = zRange[0];
144
+ refPointPositions.push(project(lngLat));
145
+
146
+ if (zRange[0] !== zRange[1]) {
147
+ lngLat[2] = zRange[1];
148
+ refPointPositions.push(project(lngLat));
149
+ }
150
+ }
151
+
152
+ return makeOrientedBoundingBoxFromPoints(refPointPositions);
153
+ }
154
+
155
+ const scale = Math.pow(2, this.z);
156
+ const extent = TILE_SIZE / scale;
157
+ const originX = this.x * extent + worldOffset * TILE_SIZE;
158
+ const originY = TILE_SIZE - (this.y + 1) * extent;
159
+
160
+ return new AxisAlignedBoundingBox(
161
+ [originX, originY, zRange[0]],
162
+ [originX + extent, originY + extent, zRange[1]]
163
+ );
164
+ }
165
+ }
166
+
167
+ /** deck.gl-specific OSM tile traversal for geospatial viewports. */
168
+ export function getOSMTileIndices(
169
+ viewport: Viewport,
170
+ maxZ: number,
171
+ zRange: ZRange | null,
172
+ bounds?: Bounds
173
+ ): TileIndex[] {
174
+ const project: ((xyz: number[]) => number[]) | null =
175
+ viewport instanceof _GlobeViewport && viewport.resolution
176
+ ? (xyz) => viewport.projectPosition(xyz)
177
+ : null;
178
+
179
+ const planes: Plane[] = Object.values(viewport.getFrustumPlanes()).map(
180
+ ({normal, distance}) => new Plane(normal.clone().negate(), distance)
181
+ );
182
+ const cullingVolume = new CullingVolume(planes);
183
+
184
+ const unitsPerMeter = viewport.distanceScales.unitsPerMeter[2];
185
+ const elevationMin = (zRange && zRange[0] * unitsPerMeter) || 0;
186
+ const elevationMax = (zRange && zRange[1] * unitsPerMeter) || 0;
187
+ const minZ = viewport instanceof WebMercatorViewport && viewport.pitch <= 60 ? maxZ : 0;
188
+
189
+ if (bounds) {
190
+ const [minLng, minLat, maxLng, maxLat] = bounds;
191
+ const topLeft = lngLatToWorld([minLng, maxLat]);
192
+ const bottomRight = lngLatToWorld([maxLng, minLat]);
193
+ bounds = [topLeft[0], TILE_SIZE - topLeft[1], bottomRight[0], TILE_SIZE - bottomRight[1]];
194
+ }
195
+
196
+ const root = new OSMNode(0, 0, 0);
197
+ const traversalParams = {
198
+ viewport,
199
+ project,
200
+ cullingVolume,
201
+ elevationBounds: [elevationMin, elevationMax] as ZRange,
202
+ minZ,
203
+ maxZ,
204
+ bounds,
205
+ offset: 0
206
+ };
207
+
208
+ root.update(traversalParams);
209
+ updateWrappedWorldCopies(root, traversalParams, viewport);
210
+
211
+ return root.getSelected();
212
+ }
213
+
214
+ function updateWrappedWorldCopies(
215
+ root: OSMNode,
216
+ traversalParams: Parameters<OSMNode['update']>[0],
217
+ viewport: Viewport
218
+ ): void {
219
+ if (
220
+ !(viewport instanceof WebMercatorViewport) ||
221
+ !viewport.subViewports ||
222
+ viewport.subViewports.length <= 1
223
+ ) {
224
+ return;
225
+ }
226
+
227
+ sweepOffsets(root, traversalParams, -1, -MAX_MAPS);
228
+ sweepOffsets(root, traversalParams, 1, MAX_MAPS);
229
+ }
230
+
231
+ function sweepOffsets(
232
+ root: OSMNode,
233
+ traversalParams: Parameters<OSMNode['update']>[0],
234
+ startOffset: number,
235
+ limit: number
236
+ ): void {
237
+ traversalParams.offset = startOffset;
238
+ while (root.update(traversalParams)) {
239
+ traversalParams.offset += Math.sign(startOffset);
240
+ if (
241
+ (startOffset < 0 && traversalParams.offset < limit) ||
242
+ (startOffset > 0 && traversalParams.offset > limit)
243
+ ) {
244
+ break;
245
+ }
246
+ }
247
+ }
@@ -0,0 +1,262 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {Viewport} from '@deck.gl/core';
6
+ import {Matrix4} from '@math.gl/core';
7
+ import type {Bounds, GeoBoundingBox, TileBoundingBox, TileIndex, ZRange} from '../tileset/types';
8
+ import type {
9
+ SharedTileset2DAdapter,
10
+ SharedTileset2DTileContext,
11
+ SharedTileset2DTraversalContext
12
+ } from '../tileset/adapter';
13
+ import {getOSMTileIndices} from './deck-tile-traversal';
14
+
15
+ const TILE_SIZE = 512;
16
+ const DEFAULT_EXTENT: Bounds = [-Infinity, -Infinity, Infinity, Infinity];
17
+
18
+ /** deck.gl viewport type used by the shared tile layer adapter. */
19
+ export type SharedTile2DDeckViewState = Viewport;
20
+
21
+ /** Applies a model transform to an axis-aligned bounding box. */
22
+ export function transformBox(bbox: Bounds, modelMatrix: Matrix4): Bounds {
23
+ const transformedCoords = [
24
+ modelMatrix.transformAsPoint([bbox[0], bbox[1]]),
25
+ modelMatrix.transformAsPoint([bbox[2], bbox[1]]),
26
+ modelMatrix.transformAsPoint([bbox[0], bbox[3]]),
27
+ modelMatrix.transformAsPoint([bbox[2], bbox[3]])
28
+ ];
29
+ return [
30
+ Math.min(...transformedCoords.map((i) => i[0])),
31
+ Math.min(...transformedCoords.map((i) => i[1])),
32
+ Math.max(...transformedCoords.map((i) => i[0])),
33
+ Math.max(...transformedCoords.map((i) => i[1]))
34
+ ];
35
+ }
36
+
37
+ function getBoundingBox(viewport: Viewport, zRange: number[] | null, extent: Bounds): Bounds {
38
+ let bounds;
39
+ if (zRange && zRange.length === 2) {
40
+ const [minZ, maxZ] = zRange;
41
+ const bounds0 = viewport.getBounds({z: minZ});
42
+ const bounds1 = viewport.getBounds({z: maxZ});
43
+ bounds = [
44
+ Math.min(bounds0[0], bounds1[0]),
45
+ Math.min(bounds0[1], bounds1[1]),
46
+ Math.max(bounds0[2], bounds1[2]),
47
+ Math.max(bounds0[3], bounds1[3])
48
+ ];
49
+ } else {
50
+ bounds = viewport.getBounds();
51
+ }
52
+ if (!viewport.isGeospatial) {
53
+ return [
54
+ Math.max(Math.min(bounds[0], extent[2]), extent[0]),
55
+ Math.max(Math.min(bounds[1], extent[3]), extent[1]),
56
+ Math.min(Math.max(bounds[2], extent[0]), extent[2]),
57
+ Math.min(Math.max(bounds[3], extent[1]), extent[3])
58
+ ];
59
+ }
60
+ return [
61
+ Math.max(bounds[0], extent[0]),
62
+ Math.max(bounds[1], extent[1]),
63
+ Math.min(bounds[2], extent[2]),
64
+ Math.min(bounds[3], extent[3])
65
+ ];
66
+ }
67
+
68
+ /** Computes cull bounds in projected/world coordinates for one deck viewport. */
69
+ export function getCullBounds({
70
+ viewport,
71
+ z,
72
+ cullRect
73
+ }: {
74
+ viewport: Viewport;
75
+ z: ZRange | number | null;
76
+ cullRect: {x: number; y: number; width: number; height: number};
77
+ }): [number, number, number, number][] {
78
+ const subViewports = viewport.subViewports || [viewport];
79
+ return subViewports.map((v) => getCullBoundsInViewport(v, z || 0, cullRect));
80
+ }
81
+
82
+ function getCullBoundsInViewport(
83
+ viewport: Viewport,
84
+ z: ZRange | number,
85
+ cullRect: {x: number; y: number; width: number; height: number}
86
+ ): [number, number, number, number] {
87
+ if (!Array.isArray(z)) {
88
+ const x = cullRect.x - viewport.x;
89
+ const y = cullRect.y - viewport.y;
90
+ const {width, height} = cullRect;
91
+ const unprojectOption = {targetZ: z};
92
+
93
+ const topLeft = viewport.unproject([x, y], unprojectOption);
94
+ const topRight = viewport.unproject([x + width, y], unprojectOption);
95
+ const bottomLeft = viewport.unproject([x, y + height], unprojectOption);
96
+ const bottomRight = viewport.unproject([x + width, y + height], unprojectOption);
97
+
98
+ return [
99
+ Math.min(topLeft[0], topRight[0], bottomLeft[0], bottomRight[0]),
100
+ Math.min(topLeft[1], topRight[1], bottomLeft[1], bottomRight[1]),
101
+ Math.max(topLeft[0], topRight[0], bottomLeft[0], bottomRight[0]),
102
+ Math.max(topLeft[1], topRight[1], bottomLeft[1], bottomRight[1])
103
+ ];
104
+ }
105
+
106
+ const bounds0 = getCullBoundsInViewport(viewport, z[0], cullRect);
107
+ const bounds1 = getCullBoundsInViewport(viewport, z[1], cullRect);
108
+
109
+ return [
110
+ Math.min(bounds0[0], bounds1[0]),
111
+ Math.min(bounds0[1], bounds1[1]),
112
+ Math.max(bounds0[2], bounds1[2]),
113
+ Math.max(bounds0[3], bounds1[3])
114
+ ];
115
+ }
116
+
117
+ function getIndexingCoords(
118
+ bbox: Bounds,
119
+ scale: number,
120
+ modelMatrixInverse?: Matrix4 | null
121
+ ): Bounds {
122
+ if (modelMatrixInverse) {
123
+ return transformBox(bbox, modelMatrixInverse).map((i) => (i * scale) / TILE_SIZE) as Bounds;
124
+ }
125
+ return bbox.map((i) => (i * scale) / TILE_SIZE) as Bounds;
126
+ }
127
+
128
+ function getScale(z: number, tileSize: number): number {
129
+ return (Math.pow(2, z) * TILE_SIZE) / tileSize;
130
+ }
131
+
132
+ /** Converts an OSM tile coordinate to longitude/latitude. */
133
+ export function osmTile2lngLat(x: number, y: number, z: number): [number, number] {
134
+ const scale = getScale(z, TILE_SIZE);
135
+ const lng = (x / scale) * 360 - 180;
136
+ const n = Math.PI - (2 * Math.PI * y) / scale;
137
+ const lat = (180 / Math.PI) * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
138
+ return [lng, lat];
139
+ }
140
+
141
+ function tile2XY(x: number, y: number, z: number, tileSize: number): [number, number] {
142
+ const scale = getScale(z, tileSize);
143
+ return [(x / scale) * TILE_SIZE, (y / scale) * TILE_SIZE];
144
+ }
145
+
146
+ function tileToBoundingBox(
147
+ viewport: Viewport,
148
+ x: number,
149
+ y: number,
150
+ z: number,
151
+ tileSize: number = TILE_SIZE
152
+ ): TileBoundingBox {
153
+ if (viewport.isGeospatial) {
154
+ const [west, north] = osmTile2lngLat(x, y, z);
155
+ const [east, south] = osmTile2lngLat(x + 1, y + 1, z);
156
+ return {west, north, east, south};
157
+ }
158
+ const [left, top] = tile2XY(x, y, z, tileSize);
159
+ const [right, bottom] = tile2XY(x + 1, y + 1, z, tileSize);
160
+ return {left, top, right, bottom};
161
+ }
162
+
163
+ function getIdentityTileIndices(
164
+ viewport: Viewport,
165
+ z: number,
166
+ tileSize: number,
167
+ extent: Bounds,
168
+ modelMatrixInverse?: Matrix4 | null
169
+ ): TileIndex[] {
170
+ const bbox = getBoundingBox(viewport, null, extent);
171
+ const scale = getScale(z, tileSize);
172
+ const [minX, minY, maxX, maxY] = getIndexingCoords(bbox, scale, modelMatrixInverse);
173
+ const indices: TileIndex[] = [];
174
+
175
+ for (let x = Math.floor(minX); x < maxX; x++) {
176
+ for (let y = Math.floor(minY); y < maxY; y++) {
177
+ indices.push({x, y, z});
178
+ }
179
+ }
180
+ return indices;
181
+ }
182
+
183
+ function getTileZoomForViewport(viewport: Viewport, tileSize: number, zoomOffset: number): number {
184
+ return viewport.isGeospatial
185
+ ? Math.round(viewport.zoom + Math.log2(TILE_SIZE / tileSize)) + zoomOffset
186
+ : Math.ceil(viewport.zoom) + zoomOffset;
187
+ }
188
+
189
+ function applyZoomBounds(
190
+ z: number,
191
+ minZoom: number | undefined,
192
+ maxZoom: number | undefined,
193
+ extent?: Bounds | null
194
+ ): number | null {
195
+ if (typeof minZoom === 'number' && Number.isFinite(minZoom) && z < minZoom) {
196
+ if (!extent) {
197
+ return null;
198
+ }
199
+ z = minZoom;
200
+ }
201
+ if (typeof maxZoom === 'number' && Number.isFinite(maxZoom) && z > maxZoom) {
202
+ z = maxZoom;
203
+ }
204
+ return z;
205
+ }
206
+
207
+ function getDeckTileIndices(context: SharedTileset2DTraversalContext<Viewport>): TileIndex[] {
208
+ const {
209
+ viewState: viewport,
210
+ maxZoom,
211
+ minZoom,
212
+ zRange = null,
213
+ extent,
214
+ tileSize = TILE_SIZE,
215
+ modelMatrix,
216
+ modelMatrixInverse,
217
+ zoomOffset = 0
218
+ } = context;
219
+ let z = getTileZoomForViewport(viewport, tileSize, zoomOffset);
220
+ z = applyZoomBounds(z, minZoom, maxZoom, extent);
221
+ if (z === null) {
222
+ return [];
223
+ }
224
+
225
+ let transformedExtent = extent || undefined;
226
+ if (modelMatrix && modelMatrixInverse && extent && !viewport.isGeospatial) {
227
+ transformedExtent = transformBox(extent, modelMatrix);
228
+ }
229
+
230
+ return viewport.isGeospatial
231
+ ? getOSMTileIndices(viewport, z, zRange, extent || undefined)
232
+ : getIdentityTileIndices(
233
+ viewport,
234
+ z,
235
+ tileSize,
236
+ transformedExtent || DEFAULT_EXTENT,
237
+ modelMatrixInverse
238
+ );
239
+ }
240
+
241
+ function getDeckTileBoundingBox(
242
+ context: SharedTileset2DTileContext<Viewport>,
243
+ index: TileIndex
244
+ ): TileBoundingBox {
245
+ return tileToBoundingBox(context.viewState, index.x, index.y, index.z, context.tileSize);
246
+ }
247
+
248
+ /** Deck.gl adapter used by {@link SharedTile2DLayer} to drive a generic {@link SharedTileset2D}. */
249
+ export const sharedTile2DDeckAdapter: SharedTileset2DAdapter<Viewport> = {
250
+ getTileIndices: getDeckTileIndices,
251
+ getTileBoundingBox: getDeckTileBoundingBox
252
+ };
253
+
254
+ /** Type guard for geographic tile bounds. */
255
+ export function isGeoBoundingBox(v: any): v is GeoBoundingBox {
256
+ return (
257
+ Number.isFinite(v.west) &&
258
+ Number.isFinite(v.north) &&
259
+ Number.isFinite(v.east) &&
260
+ Number.isFinite(v.south)
261
+ );
262
+ }
@@ -0,0 +1,7 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ export {SharedTile2DLayer} from './shared-tile-2d-layer';
6
+ export type {SharedTile2DLayerProps, SharedTile2DLayerPickingInfo} from './shared-tile-2d-layer';
7
+ export {sharedTile2DDeckAdapter} from './deck-tileset-adapter';