@loaders.gl/tiles 5.0.0-alpha.1 → 5.0.0-alpha.3
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/LICENSE +14 -3
- package/dist/dist.dev.js +17482 -3685
- package/dist/dist.min.js +4 -1
- package/dist/index.cjs +4594 -422
- package/dist/index.cjs.map +3 -4
- package/dist/index.d.ts +16 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/point-cloud/point-cloud-tile.d.ts.map +1 -1
- package/dist/point-cloud/point-cloud-tile.js +3 -0
- package/dist/point-cloud/point-cloud-tile.js.map +1 -1
- package/dist/point-cloud/point-cloud-tileset.d.ts +4 -0
- package/dist/point-cloud/point-cloud-tileset.d.ts.map +1 -1
- package/dist/point-cloud/point-cloud-tileset.js +54 -12
- package/dist/point-cloud/point-cloud-tileset.js.map +1 -1
- package/dist/point-cloud/types.d.ts +17 -0
- package/dist/point-cloud/types.d.ts.map +1 -1
- package/dist/point-cloud/types.js +3 -0
- package/dist/point-cloud/types.js.map +1 -1
- package/dist/raster-set.d.ts +37 -29
- package/dist/raster-set.d.ts.map +1 -1
- package/dist/raster-set.js +25 -2
- package/dist/raster-set.js.map +1 -1
- package/dist/spatial/format-spatial-reference.d.ts +67 -0
- package/dist/spatial/format-spatial-reference.d.ts.map +1 -0
- package/dist/spatial/format-spatial-reference.js +233 -0
- package/dist/spatial/format-spatial-reference.js.map +1 -0
- package/dist/spatial/get-spatial-coordinate-frame.d.ts +9 -0
- package/dist/spatial/get-spatial-coordinate-frame.d.ts.map +1 -0
- package/dist/spatial/get-spatial-coordinate-frame.js +58 -0
- package/dist/spatial/get-spatial-coordinate-frame.js.map +1 -0
- package/dist/spatial/i3s-elevation.d.ts +20 -0
- package/dist/spatial/i3s-elevation.d.ts.map +1 -0
- package/dist/spatial/i3s-elevation.js +90 -0
- package/dist/spatial/i3s-elevation.js.map +1 -0
- package/dist/spatial/i3s-spatial-transformer.d.ts +189 -0
- package/dist/spatial/i3s-spatial-transformer.d.ts.map +1 -0
- package/dist/spatial/i3s-spatial-transformer.js +686 -0
- package/dist/spatial/i3s-spatial-transformer.js.map +1 -0
- package/dist/spatial/spatial-coordinate-transformer.d.ts +48 -0
- package/dist/spatial/spatial-coordinate-transformer.d.ts.map +1 -0
- package/dist/spatial/spatial-coordinate-transformer.js +211 -0
- package/dist/spatial/spatial-coordinate-transformer.js.map +1 -0
- package/dist/spatial/spatial-resource-registry.d.ts +44 -0
- package/dist/spatial/spatial-resource-registry.d.ts.map +1 -0
- package/dist/spatial/spatial-resource-registry.js +67 -0
- package/dist/spatial/spatial-resource-registry.js.map +1 -0
- package/dist/spatial/spatial-types.d.ts +190 -0
- package/dist/spatial/spatial-types.d.ts.map +1 -0
- package/dist/spatial/spatial-types.js +192 -0
- package/dist/spatial/spatial-types.js.map +1 -0
- package/dist/tileset-3d/common/tile-3d.d.ts +147 -4
- package/dist/tileset-3d/common/tile-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tile-3d.js +358 -76
- package/dist/tileset-3d/common/tile-3d.js.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.d.ts +168 -3
- package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.js +306 -23
- package/dist/tileset-3d/common/tileset-3d.js.map +1 -1
- package/dist/tileset-3d/common/tileset-cache.d.ts +11 -1
- package/dist/tileset-3d/common/tileset-cache.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-cache.js +11 -3
- package/dist/tileset-3d/common/tileset-cache.js.map +1 -1
- package/dist/tileset-3d/common/tileset-source.d.ts +32 -0
- package/dist/tileset-3d/common/tileset-source.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-source.js.map +1 -1
- package/dist/tileset-3d/common/tileset-traverser.d.ts +19 -1
- package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-traverser.js +39 -7
- package/dist/tileset-3d/common/tileset-traverser.js.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts +136 -0
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts.map +1 -0
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js +384 -0
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js.map +1 -0
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts +86 -3
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js +196 -21
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts +36 -0
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js +66 -0
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.js +3 -0
- package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-source.d.ts +14 -1
- package/dist/tileset-3d/format-i3s/i3s-source.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-source.js +107 -17
- package/dist/tileset-3d/format-i3s/i3s-source.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tile-manager.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tile-manager.js +3 -0
- package/dist/tileset-3d/format-i3s/i3s-tile-manager.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.js +3 -0
- package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.js.map +1 -1
- package/dist/tileset-3d/helpers/3d-tiles-options.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/3d-tiles-options.js +3 -0
- package/dist/tileset-3d/helpers/3d-tiles-options.js.map +1 -1
- package/dist/tileset-3d/helpers/bounding-volume.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/bounding-volume.js +4 -33
- package/dist/tileset-3d/helpers/bounding-volume.js.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.d.ts +62 -2
- package/dist/tileset-3d/helpers/frame-state.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.js +85 -9
- package/dist/tileset-3d/helpers/frame-state.js.map +1 -1
- package/dist/tileset-3d/helpers/i3s-lod.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/i3s-lod.js +20 -8
- package/dist/tileset-3d/helpers/i3s-lod.js.map +1 -1
- package/dist/tileset-3d/helpers/tiles-3d-lod.d.ts +61 -9
- package/dist/tileset-3d/helpers/tiles-3d-lod.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/tiles-3d-lod.js +198 -93
- package/dist/tileset-3d/helpers/tiles-3d-lod.js.map +1 -1
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.d.ts +134 -0
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.d.ts.map +1 -0
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.js +179 -0
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.js.map +1 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/doubly-linked-list.d.ts.map +1 -1
- package/dist/utils/doubly-linked-list.js +1 -0
- package/dist/utils/doubly-linked-list.js.map +1 -1
- package/dist/utils/managed-array.d.ts.map +1 -1
- package/dist/utils/managed-array.js +1 -0
- package/dist/utils/managed-array.js.map +1 -1
- package/package.json +12 -9
- package/src/index.ts +61 -1
- package/src/point-cloud/point-cloud-tile.ts +4 -0
- package/src/point-cloud/point-cloud-tileset.ts +70 -12
- package/src/point-cloud/types.ts +21 -0
- package/src/raster-set.ts +118 -45
- package/src/spatial/format-spatial-reference.ts +311 -0
- package/src/spatial/get-spatial-coordinate-frame.ts +74 -0
- package/src/spatial/i3s-elevation.ts +96 -0
- package/src/spatial/i3s-spatial-transformer.ts +957 -0
- package/src/spatial/spatial-coordinate-transformer.ts +276 -0
- package/src/spatial/spatial-resource-registry.ts +79 -0
- package/src/spatial/spatial-types.ts +422 -0
- package/src/tileset-3d/common/tile-3d.ts +435 -84
- package/src/tileset-3d/common/tileset-3d.ts +445 -23
- package/src/tileset-3d/common/tileset-cache.ts +15 -7
- package/src/tileset-3d/common/tileset-source.ts +36 -0
- package/src/tileset-3d/common/tileset-traverser.ts +40 -7
- package/src/tileset-3d/format-3d-tiles/implicit-tiling.ts +612 -0
- package/src/tileset-3d/format-3d-tiles/tiles-3d-source.ts +254 -21
- package/src/tileset-3d/format-3d-tiles/tileset-3d-traverser.ts +77 -0
- package/src/tileset-3d/format-i3s/i3s-pending-tiles-register.ts +4 -0
- package/src/tileset-3d/format-i3s/i3s-source.ts +119 -18
- package/src/tileset-3d/format-i3s/i3s-tile-manager.ts +4 -0
- package/src/tileset-3d/format-i3s/i3s-tileset-traverser.ts +4 -0
- package/src/tileset-3d/helpers/3d-tiles-options.ts +4 -0
- package/src/tileset-3d/helpers/bounding-volume.ts +5 -55
- package/src/tileset-3d/helpers/frame-state.ts +142 -11
- package/src/tileset-3d/helpers/i3s-lod.ts +22 -8
- package/src/tileset-3d/helpers/tiles-3d-lod.ts +291 -112
- package/src/tileset-3d/helpers/tiles-3d-request-priority.ts +301 -0
- package/src/types.ts +9 -0
- package/src/utils/doubly-linked-list.ts +2 -0
- package/src/utils/managed-array.ts +2 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import {path} from '@loaders.gl/loader-utils';
|
|
5
|
+
import {path, RequestCache} from '@loaders.gl/loader-utils';
|
|
6
6
|
import {Ellipsoid} from '@math.gl/geospatial';
|
|
7
7
|
import {Vector3} from '@math.gl/core';
|
|
8
8
|
import type {CoreAPI, LoaderOptions, LoaderWithParser} from '@loaders.gl/loader-utils';
|
|
@@ -10,6 +10,7 @@ import type {Tile3D} from '../common/tile-3d';
|
|
|
10
10
|
import {Tileset3DTraverser} from './tileset-3d-traverser';
|
|
11
11
|
import type {Tileset3D} from '../common/tileset-3d';
|
|
12
12
|
import type {
|
|
13
|
+
TileChildrenLoadResult,
|
|
13
14
|
TileContentLoadResult,
|
|
14
15
|
TilesetContentFormats,
|
|
15
16
|
TilesetJSON,
|
|
@@ -24,6 +25,13 @@ import {Tile3D as Tile3DNode} from '../common/tile-3d';
|
|
|
24
25
|
import {getZoomFromBoundingVolume} from '../helpers/zoom';
|
|
25
26
|
import {TILESET_TYPE} from '../../constants';
|
|
26
27
|
import type {TilesetTraverser, TilesetTraverserProps} from '../common/tileset-traverser';
|
|
28
|
+
import type {FrameState} from '../helpers/frame-state';
|
|
29
|
+
import {get3DTilesSpatialReference} from '../../spatial/format-spatial-reference';
|
|
30
|
+
import {
|
|
31
|
+
materializeImplicitSubtree,
|
|
32
|
+
type ImplicitSubtreeReference,
|
|
33
|
+
type ParsedImplicitSubtree
|
|
34
|
+
} from './implicit-tiling';
|
|
27
35
|
|
|
28
36
|
const EMPTY_CONTENT_FORMATS: TilesetContentFormats = {
|
|
29
37
|
draco: false,
|
|
@@ -32,6 +40,24 @@ const EMPTY_CONTENT_FORMATS: TilesetContentFormats = {
|
|
|
32
40
|
ktx2: false
|
|
33
41
|
};
|
|
34
42
|
|
|
43
|
+
const DEFAULT_MAXIMUM_CACHED_SUBTREES = 32;
|
|
44
|
+
|
|
45
|
+
/** Diagnostics for source-managed implicit subtree loading. */
|
|
46
|
+
export type ImplicitTilingStats = {
|
|
47
|
+
/** Subtree resources requested from the resolver or core API. */
|
|
48
|
+
requestedSubtrees: number;
|
|
49
|
+
/** Successful subtree materializations, including parsed-cache hits. */
|
|
50
|
+
loadedSubtrees: number;
|
|
51
|
+
/** Requests served by the source's parsed-subtree cache. */
|
|
52
|
+
cacheHits: number;
|
|
53
|
+
/** Parsed subtree resources currently retained for reuse. */
|
|
54
|
+
cachedSubtrees: number;
|
|
55
|
+
/** Subtree resource requests currently in flight. */
|
|
56
|
+
pendingSubtrees: number;
|
|
57
|
+
/** Runtime headers created below already-existing subtree-root placeholders. */
|
|
58
|
+
materializedTiles: number;
|
|
59
|
+
};
|
|
60
|
+
|
|
35
61
|
/**
|
|
36
62
|
* {@link Tileset3DSource} implementation for 3D Tiles datasets.
|
|
37
63
|
*/
|
|
@@ -65,6 +91,22 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
65
91
|
metadata?: TilesetSourceMetadata;
|
|
66
92
|
|
|
67
93
|
private readonly queryParams: Record<string, string> = {};
|
|
94
|
+
/** Final request URLs cached by unmodified tile content URL. */
|
|
95
|
+
private readonly tileUrlCache: Map<string, string> = new Map();
|
|
96
|
+
/** Parsed subtree requests keyed by final source URL for deduplication and LRU reuse. */
|
|
97
|
+
private readonly implicitSubtreeCache: RequestCache<ParsedImplicitSubtree>;
|
|
98
|
+
/** Mutable counters exposed as a defensive snapshot through {@link getImplicitTilingStats}. */
|
|
99
|
+
private readonly implicitTilingStats: Omit<
|
|
100
|
+
ImplicitTilingStats,
|
|
101
|
+
'cachedSubtrees' | 'pendingSubtrees'
|
|
102
|
+
> = {
|
|
103
|
+
requestedSubtrees: 0,
|
|
104
|
+
loadedSubtrees: 0,
|
|
105
|
+
cacheHits: 0,
|
|
106
|
+
materializedTiles: 0
|
|
107
|
+
};
|
|
108
|
+
/** Whether the owning tileset has released this source. */
|
|
109
|
+
private destroyed = false;
|
|
68
110
|
private readonly extensionsUsed: string[] = [];
|
|
69
111
|
private readonly resolver?: TilesetSourceResolver;
|
|
70
112
|
private rootTileset: TilesetJSON;
|
|
@@ -84,6 +126,25 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
84
126
|
this.resolver = request.resolver;
|
|
85
127
|
this.coreApi = request.coreApi;
|
|
86
128
|
this.loadOptions = loadOptions;
|
|
129
|
+
const maximumCachedSubtrees = Number(
|
|
130
|
+
(loadOptions['3d-tiles'] as Record<string, unknown> | undefined)?.maximumCachedSubtrees
|
|
131
|
+
);
|
|
132
|
+
const maximumCacheEntries = Number.isFinite(maximumCachedSubtrees)
|
|
133
|
+
? Math.max(0, Math.floor(maximumCachedSubtrees))
|
|
134
|
+
: DEFAULT_MAXIMUM_CACHED_SUBTREES;
|
|
135
|
+
this.implicitSubtreeCache = new RequestCache({maxEntries: maximumCacheEntries});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Releases URL and parsed-subtree caches and blocks late subtree installation.
|
|
140
|
+
*
|
|
141
|
+
* The injected resolver or core API remains responsible for transport-level abort signals. A
|
|
142
|
+
* request that cannot be aborted may finish parsing, but it will not mutate destroyed tiles.
|
|
143
|
+
*/
|
|
144
|
+
destroy(): void {
|
|
145
|
+
this.destroyed = true;
|
|
146
|
+
this.tileUrlCache.clear();
|
|
147
|
+
this.implicitSubtreeCache.clear();
|
|
87
148
|
}
|
|
88
149
|
|
|
89
150
|
/**
|
|
@@ -104,7 +165,9 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
104
165
|
|
|
105
166
|
if (this.rootTileset.queryString) {
|
|
106
167
|
const searchParams = new URLSearchParams(this.rootTileset.queryString);
|
|
107
|
-
|
|
168
|
+
for (const [parameterName, parameterValue] of searchParams.entries()) {
|
|
169
|
+
this.setQueryParameter(parameterName, parameterValue);
|
|
170
|
+
}
|
|
108
171
|
}
|
|
109
172
|
|
|
110
173
|
this.asset = this.rootTileset.asset;
|
|
@@ -120,7 +183,7 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
120
183
|
}
|
|
121
184
|
|
|
122
185
|
if ('tilesetVersion' in this.asset) {
|
|
123
|
-
this.
|
|
186
|
+
this.setQueryParameter('v', this.asset.tilesetVersion);
|
|
124
187
|
}
|
|
125
188
|
|
|
126
189
|
this.properties = this.rootTileset.properties;
|
|
@@ -139,7 +202,8 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
139
202
|
tileset: this.rootTileset,
|
|
140
203
|
lodMetricType: this.rootTileset.lodMetricType,
|
|
141
204
|
lodMetricValue: this.rootTileset.lodMetricValue,
|
|
142
|
-
refine: this.rootTileset.root?.refine
|
|
205
|
+
refine: this.rootTileset.root?.refine,
|
|
206
|
+
spatialReference: get3DTilesSpatialReference(this.rootTileset)
|
|
143
207
|
};
|
|
144
208
|
}
|
|
145
209
|
|
|
@@ -161,7 +225,7 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
161
225
|
}
|
|
162
226
|
|
|
163
227
|
/**
|
|
164
|
-
* Builds
|
|
228
|
+
* Builds explicit runtime headers while leaving implicit subtree references lazy.
|
|
165
229
|
*/
|
|
166
230
|
initializeTileHeaders(
|
|
167
231
|
tileset: Tileset3D,
|
|
@@ -186,7 +250,7 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
186
250
|
const url = new URL(childTile.contentUrl);
|
|
187
251
|
const session = url.searchParams.get('session');
|
|
188
252
|
if (session) {
|
|
189
|
-
this.
|
|
253
|
+
this.setQueryParameter('session', session);
|
|
190
254
|
}
|
|
191
255
|
}
|
|
192
256
|
tile.children.push(childTile);
|
|
@@ -209,36 +273,114 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
209
273
|
* Loads binary content or nested tileset JSON for a runtime tile.
|
|
210
274
|
*/
|
|
211
275
|
async loadTileContent(tile: Tile3D): Promise<TileContentLoadResult> {
|
|
212
|
-
const
|
|
276
|
+
const contentUrls = (tile.contentUrls || [tile.contentUrl]).filter(Boolean);
|
|
213
277
|
const tilesetLoaderOptions =
|
|
214
278
|
(this.loadOptions[this.loader.id] as Record<string, unknown>) || {};
|
|
215
279
|
const options = {
|
|
216
280
|
...this.loadOptions,
|
|
217
281
|
[this.loader.id]: {
|
|
218
282
|
...tilesetLoaderOptions,
|
|
219
|
-
|
|
283
|
+
// Content bytes, rather than URL suffixes, distinguish external tilesets from renderable
|
|
284
|
+
// payloads. This is required for signed and extensionless resources.
|
|
285
|
+
isTileset: 'auto',
|
|
220
286
|
assetGltfUpAxis: (this.asset && this.asset.gltfUpAxis) || 'Y'
|
|
221
287
|
}
|
|
222
288
|
};
|
|
223
289
|
|
|
224
|
-
const
|
|
225
|
-
|
|
290
|
+
const contents = await Promise.all(
|
|
291
|
+
contentUrls.map(contentUrl => this.loadResourceData(this.getTileUrl(contentUrl), options))
|
|
292
|
+
);
|
|
293
|
+
tile.contents = contents;
|
|
294
|
+
tile.content = contents[0] || null;
|
|
295
|
+
const nestedTilesets = contents.filter(content => content?.shape === 'tileset3d');
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
loaded: true,
|
|
299
|
+
contents,
|
|
300
|
+
nestedTileset: nestedTilesets[0],
|
|
301
|
+
nestedTilesets
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Loads, materializes, and installs exactly one implicit subtree.
|
|
307
|
+
*
|
|
308
|
+
* Final URLs pass through the same query inheritance and archive/custom resolver path as render
|
|
309
|
+
* content. Parsed resources are deduplicated by final URL, while the pure materializer creates
|
|
310
|
+
* lazy placeholders for every available child subtree instead of recursively fetching them.
|
|
311
|
+
*
|
|
312
|
+
* @param tile - Existing contentless subtree-root placeholder.
|
|
313
|
+
* @param frameState - View state that made this request eligible; priority is consumed earlier.
|
|
314
|
+
* @returns Counts describing the installed subtree.
|
|
315
|
+
*/
|
|
316
|
+
async loadTileChildren(tile: Tile3D, frameState: FrameState): Promise<TileChildrenLoadResult> {
|
|
317
|
+
void frameState;
|
|
318
|
+
const reference = tile.header.implicitSubtree as ImplicitSubtreeReference | undefined;
|
|
319
|
+
if (!reference) {
|
|
320
|
+
return {loaded: false, tileCount: 0, childSubtreeCount: 0};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const subtreeUrl = this.getTileUrl(reference.subtreeUrl);
|
|
324
|
+
const subtree = await this.loadImplicitSubtreeResource(subtreeUrl);
|
|
325
|
+
if (this.destroyed || tile.isDestroyed()) {
|
|
326
|
+
return {loaded: false, tileCount: 0, childSubtreeCount: 0};
|
|
327
|
+
}
|
|
328
|
+
const materializedSubtree = materializeImplicitSubtree(subtree, {
|
|
329
|
+
...reference,
|
|
330
|
+
subtreeUrl
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
tile.applyImplicitSubtreeHeader(materializedSubtree.root);
|
|
334
|
+
const materializedTileCount = this.initializeMaterializedChildren(
|
|
335
|
+
tile.tileset,
|
|
336
|
+
tile,
|
|
337
|
+
materializedSubtree.root.children
|
|
338
|
+
);
|
|
339
|
+
this.implicitTilingStats.loadedSubtrees++;
|
|
340
|
+
this.implicitTilingStats.materializedTiles += materializedTileCount;
|
|
226
341
|
|
|
227
342
|
return {
|
|
228
343
|
loaded: true,
|
|
229
|
-
|
|
344
|
+
tileCount: materializedSubtree.tileCount,
|
|
345
|
+
childSubtreeCount: materializedSubtree.childSubtreeCount
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Returns a snapshot of implicit-subtree request, cache, and materialization counters.
|
|
351
|
+
*
|
|
352
|
+
* @returns Immutable-by-convention diagnostic values for runtime inspection.
|
|
353
|
+
*/
|
|
354
|
+
getImplicitTilingStats(): ImplicitTilingStats {
|
|
355
|
+
return {
|
|
356
|
+
...this.implicitTilingStats,
|
|
357
|
+
cachedSubtrees: this.implicitSubtreeCache.size - this.implicitSubtreeCache.pendingSize,
|
|
358
|
+
pendingSubtrees: this.implicitSubtreeCache.pendingSize
|
|
230
359
|
};
|
|
231
360
|
}
|
|
232
361
|
|
|
233
362
|
/**
|
|
234
363
|
* Resolves a tile content URL with source-managed query parameters.
|
|
364
|
+
*
|
|
365
|
+
* Existing per-resource parameters take precedence over inherited root, version, and session
|
|
366
|
+
* values. Completed URLs are cached by the original tile path; {@link setQueryParameter}
|
|
367
|
+
* invalidates the cache before changed source state can be observed.
|
|
368
|
+
*
|
|
369
|
+
* @param tilePath - Unmodified absolute content URL or data URL from the tile header.
|
|
370
|
+
* @returns Content URL with any missing source parameters appended.
|
|
235
371
|
*/
|
|
236
372
|
getTileUrl(tilePath: string): string {
|
|
237
373
|
if (tilePath.startsWith('data:')) {
|
|
238
374
|
return tilePath;
|
|
239
375
|
}
|
|
240
376
|
|
|
377
|
+
const cachedTileUrl = this.tileUrlCache.get(tilePath);
|
|
378
|
+
if (cachedTileUrl) {
|
|
379
|
+
return cachedTileUrl;
|
|
380
|
+
}
|
|
381
|
+
|
|
241
382
|
if (!Object.keys(this.queryParams).length) {
|
|
383
|
+
this.tileUrlCache.set(tilePath, tilePath);
|
|
242
384
|
return tilePath;
|
|
243
385
|
}
|
|
244
386
|
|
|
@@ -252,7 +394,27 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
252
394
|
}
|
|
253
395
|
|
|
254
396
|
const queryParams = mergedQueryParams.toString();
|
|
255
|
-
|
|
397
|
+
const tileUrl = queryParams ? `${pathWithoutQuery}?${queryParams}` : pathWithoutQuery;
|
|
398
|
+
this.tileUrlCache.set(tilePath, tileUrl);
|
|
399
|
+
return tileUrl;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Updates an inherited source query parameter and invalidates derived request URLs.
|
|
404
|
+
*
|
|
405
|
+
* Root tokens and tileset versions normally settle during initialization. Some providers expose
|
|
406
|
+
* a session parameter on a child URL, so invalidation is required to prevent URLs cached earlier
|
|
407
|
+
* in header construction from retaining stale authentication state.
|
|
408
|
+
*
|
|
409
|
+
* @param parameterName - Query parameter name.
|
|
410
|
+
* @param parameterValue - Query parameter value.
|
|
411
|
+
*/
|
|
412
|
+
private setQueryParameter(parameterName: string, parameterValue: string): void {
|
|
413
|
+
if (this.queryParams[parameterName] === parameterValue) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
this.queryParams[parameterName] = parameterValue;
|
|
417
|
+
this.tileUrlCache.clear();
|
|
256
418
|
}
|
|
257
419
|
|
|
258
420
|
/**
|
|
@@ -300,7 +462,8 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
300
462
|
* Updates content-format flags and installs nested tileset subtrees.
|
|
301
463
|
*/
|
|
302
464
|
onTileLoaded(tileset: Tileset3D, tile: Tile3D, loadResult: TileContentLoadResult): void {
|
|
303
|
-
const
|
|
465
|
+
const contents = tile.contents.length ? tile.contents : [tile.content];
|
|
466
|
+
const extensionsRemoved = contents.flatMap(content => content?.gltf?.extensionsRemoved || []);
|
|
304
467
|
if (extensionsRemoved.includes('KHR_draco_mesh_compression')) {
|
|
305
468
|
this.contentFormats.draco = true;
|
|
306
469
|
}
|
|
@@ -311,20 +474,26 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
311
474
|
this.contentFormats.ktx2 = true;
|
|
312
475
|
}
|
|
313
476
|
|
|
314
|
-
|
|
315
|
-
|
|
477
|
+
const nestedTilesets =
|
|
478
|
+
loadResult.nestedTilesets || (loadResult.nestedTileset ? [loadResult.nestedTileset] : []);
|
|
479
|
+
for (const nestedTileset of nestedTilesets) {
|
|
480
|
+
tileset._initializeTileHeaders(nestedTileset, tile);
|
|
316
481
|
}
|
|
317
482
|
}
|
|
318
483
|
|
|
319
484
|
/**
|
|
320
485
|
* Loads data through injected core APIs so this module stays independent from `@loaders.gl/core`.
|
|
321
486
|
*/
|
|
322
|
-
private async loadWithCoreApi(
|
|
487
|
+
private async loadWithCoreApi(
|
|
488
|
+
url: string,
|
|
489
|
+
options: LoaderOptions,
|
|
490
|
+
loader: LoaderWithParser = this.loader
|
|
491
|
+
): Promise<any> {
|
|
323
492
|
if (!this.coreApi) {
|
|
324
493
|
throw new Error('Tiles3DSource requires an injected coreApi to load tileset data');
|
|
325
494
|
}
|
|
326
495
|
|
|
327
|
-
return await this.coreApi.load(url,
|
|
496
|
+
return await this.coreApi.load(url, loader, options);
|
|
328
497
|
}
|
|
329
498
|
|
|
330
499
|
/**
|
|
@@ -339,14 +508,78 @@ export class Tiles3DSource implements Tileset3DSource {
|
|
|
339
508
|
}
|
|
340
509
|
|
|
341
510
|
/**
|
|
342
|
-
* Loads
|
|
511
|
+
* Loads an arbitrary source resource through an injected resolver or core API.
|
|
343
512
|
*/
|
|
344
|
-
private async loadResourceData(
|
|
513
|
+
private async loadResourceData(
|
|
514
|
+
url: string,
|
|
515
|
+
options: LoaderOptions,
|
|
516
|
+
loader: LoaderWithParser = this.loader
|
|
517
|
+
): Promise<any> {
|
|
345
518
|
if (this.resolver) {
|
|
346
|
-
return await this.resolver.loadResource(url,
|
|
519
|
+
return await this.resolver.loadResource(url, loader, options);
|
|
347
520
|
}
|
|
348
521
|
|
|
349
|
-
return await this.loadWithCoreApi(url, options);
|
|
522
|
+
return await this.loadWithCoreApi(url, options, loader);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Returns a parsed subtree from the LRU cache or starts one source-managed request.
|
|
527
|
+
*
|
|
528
|
+
* @param subtreeUrl - Final subtree URL after query inheritance.
|
|
529
|
+
* @returns Parsed subtree availability data.
|
|
530
|
+
*/
|
|
531
|
+
private async loadImplicitSubtreeResource(subtreeUrl: string): Promise<ParsedImplicitSubtree> {
|
|
532
|
+
const cachedSubtree = this.implicitSubtreeCache.get(subtreeUrl);
|
|
533
|
+
if (cachedSubtree) {
|
|
534
|
+
this.implicitTilingStats.cacheHits++;
|
|
535
|
+
return await cachedSubtree;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
this.implicitTilingStats.requestedSubtrees++;
|
|
539
|
+
const loaderOptions = (this.loadOptions[this.loader.id] as Record<string, unknown>) || {};
|
|
540
|
+
return await this.implicitSubtreeCache.getOrLoad(subtreeUrl, async () => {
|
|
541
|
+
return (await this.loadResourceData(subtreeUrl, {
|
|
542
|
+
...this.loadOptions,
|
|
543
|
+
[this.loader.id]: {
|
|
544
|
+
...loaderOptions,
|
|
545
|
+
isTileset: false,
|
|
546
|
+
isSubtree: true
|
|
547
|
+
}
|
|
548
|
+
})) as ParsedImplicitSubtree;
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Instantiates every header represented by one materialized subtree.
|
|
554
|
+
*
|
|
555
|
+
* @param tileset - Owning runtime tileset.
|
|
556
|
+
* @param parentTile - Existing materialized parent.
|
|
557
|
+
* @param childHeaders - Headers to install below the parent.
|
|
558
|
+
* @returns Number of newly allocated runtime tile nodes.
|
|
559
|
+
*/
|
|
560
|
+
private initializeMaterializedChildren(
|
|
561
|
+
tileset: Tileset3D,
|
|
562
|
+
parentTile: Tile3D,
|
|
563
|
+
childHeaders: Record<string, any>[]
|
|
564
|
+
): number {
|
|
565
|
+
let materializedTileCount = 0;
|
|
566
|
+
const stack: Array<{parentTile: Tile3D; childHeaders: Record<string, any>[]}> = [
|
|
567
|
+
{parentTile, childHeaders}
|
|
568
|
+
];
|
|
569
|
+
while (stack.length > 0) {
|
|
570
|
+
const entry = stack.pop()!;
|
|
571
|
+
for (const childHeader of entry.childHeaders) {
|
|
572
|
+
const childTile = new Tile3DNode(tileset, childHeader, entry.parentTile);
|
|
573
|
+
entry.parentTile.children.push(childTile);
|
|
574
|
+
childTile.depth = entry.parentTile.depth + 1;
|
|
575
|
+
tileset.stats.get('Tiles In Tileset(s)').incrementCount();
|
|
576
|
+
materializedTileCount++;
|
|
577
|
+
if (childHeader.children?.length) {
|
|
578
|
+
stack.push({parentTile: childTile, childHeaders: childHeader.children});
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return materializedTileCount;
|
|
350
583
|
}
|
|
351
584
|
}
|
|
352
585
|
|
|
@@ -7,8 +7,29 @@
|
|
|
7
7
|
|
|
8
8
|
import {TILE3D_OPTIMIZATION_HINT, TILE_REFINEMENT} from '../../constants';
|
|
9
9
|
import {TilesetTraverser} from '../common/tileset-traverser';
|
|
10
|
+
import type {Tile3D} from '../common/tile-3d';
|
|
11
|
+
import type {FrameState} from '../helpers/frame-state';
|
|
10
12
|
|
|
11
13
|
export class Tileset3DTraverser extends TilesetTraverser {
|
|
14
|
+
/** Pending implicit subtree requests keyed by viewport and tile identity. */
|
|
15
|
+
private readonly pendingImplicitSubtrees: Map<string, number> = new Map();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Reports whether every implicit subtree request started by this viewport traversal has settled.
|
|
19
|
+
*
|
|
20
|
+
* @param frameState - Traversal frame whose completion callback is being considered.
|
|
21
|
+
* @returns `true` when no matching subtree metadata request remains pending.
|
|
22
|
+
*/
|
|
23
|
+
protected traversalFinished(frameState: FrameState): boolean {
|
|
24
|
+
const viewportPrefix = `${frameState.viewport.id}:`;
|
|
25
|
+
for (const [requestKey, frameNumber] of this.pendingImplicitSubtrees) {
|
|
26
|
+
if (requestKey.startsWith(viewportPrefix) && frameNumber === frameState.frameNumber) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
|
|
12
33
|
compareDistanceToCamera(a, b) {
|
|
13
34
|
// Sort by farthest child first since this is going on a stack
|
|
14
35
|
return b._distanceToCamera === 0 && a._distanceToCamera === 0
|
|
@@ -16,6 +37,62 @@ export class Tileset3DTraverser extends TilesetTraverser {
|
|
|
16
37
|
: b._distanceToCamera - a._distanceToCamera;
|
|
17
38
|
}
|
|
18
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Starts an implicit subtree request only after culling, request-volume, and SSE eligibility.
|
|
42
|
+
*
|
|
43
|
+
* The current parent remains the traversal boundary while metadata is loading, which preserves
|
|
44
|
+
* REPLACE coverage and ADD accumulation. Request scheduling reads the tile's existing
|
|
45
|
+
* progressive-resolution and foveated metrics, so subtree metadata follows the same priority
|
|
46
|
+
* policy as render content. A completion notification lets the owning tileset publish the newly
|
|
47
|
+
* materialized traversal result on the next update.
|
|
48
|
+
*
|
|
49
|
+
* @param tile - Tile whose existing or lazy children should be updated.
|
|
50
|
+
* @param frameState - Current culling and LOD state.
|
|
51
|
+
*/
|
|
52
|
+
updateChildTiles(tile: Tile3D, frameState: FrameState): void {
|
|
53
|
+
if (
|
|
54
|
+
tile.hasUnloadedChildren &&
|
|
55
|
+
tile.isVisibleAndInRequestVolume &&
|
|
56
|
+
this.shouldRefine(tile, frameState)
|
|
57
|
+
) {
|
|
58
|
+
const requestKey = `${frameState.viewport.id}:${tile.id}`;
|
|
59
|
+
if (!this.pendingImplicitSubtrees.has(requestKey)) {
|
|
60
|
+
this.pendingImplicitSubtrees.set(requestKey, frameState.frameNumber);
|
|
61
|
+
void tile.tileset._loadTileChildren(tile, frameState).finally(() => {
|
|
62
|
+
this.handleImplicitSubtreeLoad(tile, frameState, requestKey);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
super.updateChildTiles(tile, frameState);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Resumes the same traversal frame after one lazy subtree request settles.
|
|
71
|
+
*
|
|
72
|
+
* Successful materialization traverses the new headers immediately. Failed or scheduler-cancelled
|
|
73
|
+
* requests finish the current traversal without retrying in a tight loop; a later application
|
|
74
|
+
* update may retry them.
|
|
75
|
+
*
|
|
76
|
+
* @param tile - Subtree-root tile whose request settled.
|
|
77
|
+
* @param frameState - Frame that started the request.
|
|
78
|
+
* @param requestKey - Viewport-scoped pending-request identity.
|
|
79
|
+
*/
|
|
80
|
+
private handleImplicitSubtreeLoad(
|
|
81
|
+
tile: Tile3D,
|
|
82
|
+
frameState: FrameState,
|
|
83
|
+
requestKey: string
|
|
84
|
+
): void {
|
|
85
|
+
this.pendingImplicitSubtrees.delete(requestKey);
|
|
86
|
+
if (this._frameNumber !== frameState.frameNumber) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (tile.childrenState === 'ready') {
|
|
90
|
+
this.executeTraversal(tile, frameState);
|
|
91
|
+
} else if (this.traversalFinished(frameState)) {
|
|
92
|
+
this.options.onTraversalEnd(frameState);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
19
96
|
updateTileVisibility(tile, frameState) {
|
|
20
97
|
super.updateTileVisibility(tile, frameState);
|
|
21
98
|
|