@loaders.gl/tiles 5.0.0-alpha.1 → 5.0.0-alpha.10
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/README.md +26 -0
- package/dist/dist.dev.js +20271 -5055
- package/dist/dist.min.js +3 -1
- package/dist/index.cjs +7849 -2081
- package/dist/index.cjs.map +3 -4
- package/dist/index.d.ts +25 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -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 +48 -31
- package/dist/raster-set.d.ts.map +1 -1
- package/dist/raster-set.js +104 -24
- package/dist/raster-set.js.map +1 -1
- package/dist/spatial/format-spatial-reference.d.ts +68 -0
- package/dist/spatial/format-spatial-reference.d.ts.map +1 -0
- package/dist/spatial/format-spatial-reference.js +291 -0
- package/dist/spatial/format-spatial-reference.js.map +1 -0
- package/dist/spatial/get-spatial-coordinate-frame.d.ts +20 -0
- package/dist/spatial/get-spatial-coordinate-frame.d.ts.map +1 -0
- package/dist/spatial/get-spatial-coordinate-frame.js +139 -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/normalize-crs-identifier.d.ts +15 -0
- package/dist/spatial/normalize-crs-identifier.d.ts.map +1 -0
- package/dist/spatial/normalize-crs-identifier.js +22 -0
- package/dist/spatial/normalize-crs-identifier.js.map +1 -0
- package/dist/spatial/spatial-coordinate-transformer.d.ts +52 -0
- package/dist/spatial/spatial-coordinate-transformer.d.ts.map +1 -0
- package/dist/spatial/spatial-coordinate-transformer.js +295 -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/spatial/tiles-3d-spatial-transformer.d.ts +32 -0
- package/dist/spatial/tiles-3d-spatial-transformer.d.ts.map +1 -0
- package/dist/spatial/tiles-3d-spatial-transformer.js +175 -0
- package/dist/spatial/tiles-3d-spatial-transformer.js.map +1 -0
- package/dist/tileset-2d/adapter.d.ts +2 -3
- package/dist/tileset-2d/adapter.d.ts.map +1 -1
- package/dist/tileset-2d/tileset-2d.d.ts +2 -3
- package/dist/tileset-2d/tileset-2d.d.ts.map +1 -1
- package/dist/tileset-2d/tileset-2d.js.map +1 -1
- package/dist/tileset-3d/common/indexed-archive-tileset-source.d.ts +3 -3
- package/dist/tileset-3d/common/indexed-archive-tileset-source.d.ts.map +1 -1
- package/dist/tileset-3d/common/indexed-archive-tileset-source.js +9 -4
- package/dist/tileset-3d/common/indexed-archive-tileset-source.js.map +1 -1
- package/dist/tileset-3d/common/tile-3d-contracts.d.ts +63 -0
- package/dist/tileset-3d/common/tile-3d-contracts.d.ts.map +1 -0
- package/dist/tileset-3d/common/tile-3d-contracts.js +51 -0
- package/dist/tileset-3d/common/tile-3d-contracts.js.map +1 -0
- package/dist/tileset-3d/common/tile-3d.d.ts +176 -5
- package/dist/tileset-3d/common/tile-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tile-3d.js +523 -89
- package/dist/tileset-3d/common/tile-3d.js.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.d.ts +192 -9
- package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.js +303 -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-content-traversal.d.ts +37 -0
- package/dist/tileset-3d/common/tileset-content-traversal.d.ts.map +1 -0
- package/dist/tileset-3d/common/tileset-content-traversal.js +80 -0
- package/dist/tileset-3d/common/tileset-content-traversal.js.map +1 -0
- package/dist/tileset-3d/common/tileset-observability.d.ts +60 -0
- package/dist/tileset-3d/common/tileset-observability.d.ts.map +1 -0
- package/dist/tileset-3d/common/tileset-observability.js +39 -0
- package/dist/tileset-3d/common/tileset-observability.js.map +1 -0
- package/dist/tileset-3d/common/tileset-source.d.ts +51 -9
- 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 +33 -1
- package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-traverser.js +59 -11
- package/dist/tileset-3d/common/tileset-traverser.js.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts +182 -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 +681 -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 +127 -6
- 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 +485 -27
- 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 +103 -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 +278 -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 +23 -6
- package/dist/tileset-3d/format-i3s/i3s-source.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-source.js +176 -25
- 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 +4 -1
- 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 +7 -3
- package/dist/tileset-3d/helpers/bounding-volume.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/bounding-volume.js +20 -91
- package/dist/tileset-3d/helpers/bounding-volume.js.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.d.ts +67 -2
- package/dist/tileset-3d/helpers/frame-state.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.js +92 -10
- 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/s2-bounding-volume.d.ts +17 -0
- package/dist/tileset-3d/helpers/s2-bounding-volume.d.ts.map +1 -0
- package/dist/tileset-3d/helpers/s2-bounding-volume.js +20 -0
- package/dist/tileset-3d/helpers/s2-bounding-volume.js.map +1 -0
- 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 +7 -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 -10
- package/src/index.ts +78 -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 +197 -67
- package/src/spatial/format-spatial-reference.ts +385 -0
- package/src/spatial/get-spatial-coordinate-frame.ts +169 -0
- package/src/spatial/i3s-elevation.ts +96 -0
- package/src/spatial/i3s-spatial-transformer.ts +957 -0
- package/src/spatial/normalize-crs-identifier.ts +26 -0
- package/src/spatial/spatial-coordinate-transformer.ts +376 -0
- package/src/spatial/spatial-resource-registry.ts +79 -0
- package/src/spatial/spatial-types.ts +422 -0
- package/src/spatial/tiles-3d-spatial-transformer.ts +206 -0
- package/src/tileset-2d/adapter.ts +2 -3
- package/src/tileset-2d/tileset-2d.ts +2 -3
- package/src/tileset-3d/common/indexed-archive-tileset-source.ts +13 -13
- package/src/tileset-3d/common/tile-3d-contracts.ts +115 -0
- package/src/tileset-3d/common/tile-3d.ts +629 -98
- package/src/tileset-3d/common/tileset-3d.ts +459 -29
- package/src/tileset-3d/common/tileset-cache.ts +15 -7
- package/src/tileset-3d/common/tileset-content-traversal.ts +114 -0
- package/src/tileset-3d/common/tileset-observability.ts +100 -0
- package/src/tileset-3d/common/tileset-source.ts +63 -13
- package/src/tileset-3d/common/tileset-traverser.ts +71 -11
- package/src/tileset-3d/format-3d-tiles/implicit-tiling.ts +1059 -0
- package/src/tileset-3d/format-3d-tiles/tiles-3d-source.ts +674 -28
- package/src/tileset-3d/format-3d-tiles/tileset-3d-traverser.ts +316 -0
- package/src/tileset-3d/format-i3s/i3s-pending-tiles-register.ts +4 -0
- package/src/tileset-3d/format-i3s/i3s-source.ts +220 -29
- package/src/tileset-3d/format-i3s/i3s-tile-manager.ts +4 -0
- package/src/tileset-3d/format-i3s/i3s-tileset-traverser.ts +6 -1
- package/src/tileset-3d/helpers/3d-tiles-options.ts +4 -0
- package/src/tileset-3d/helpers/bounding-volume.ts +31 -114
- package/src/tileset-3d/helpers/frame-state.ts +152 -13
- package/src/tileset-3d/helpers/i3s-lod.ts +22 -8
- package/src/tileset-3d/helpers/s2-bounding-volume.ts +35 -0
- 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 +11 -0
- package/src/utils/doubly-linked-list.ts +2 -0
- package/src/utils/managed-array.ts +2 -0
|
@@ -71,24 +71,32 @@ export class TilesetCache {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Unloads least-recently-used tiles until the byte-native cache target is met.
|
|
76
|
+
*
|
|
77
|
+
* Tiles touched after the frame sentinel remain protected, so {@link Tileset3D.cacheBytes} is a
|
|
78
|
+
* soft target rather than a hard cap on the visible working set. Overflow headroom affects
|
|
79
|
+
* memory-adjusted SSE, not eviction of unused tiles.
|
|
80
|
+
*
|
|
81
|
+
* @param tileset - Tileset that owns the cache and reports estimated content memory.
|
|
82
|
+
* @param unloadCallback - Callback that releases content and decrements the memory estimate.
|
|
83
|
+
*/
|
|
84
|
+
unloadTiles(
|
|
85
|
+
tileset: Tileset3D,
|
|
86
|
+
unloadCallback?: (tileset: Tileset3D, tile: Tile3D) => void
|
|
87
|
+
): void {
|
|
75
88
|
const trimTiles = this._trimTiles;
|
|
76
89
|
this._trimTiles = false;
|
|
77
90
|
|
|
78
91
|
const list = this._list;
|
|
79
92
|
|
|
80
|
-
const maximumMemoryUsageInBytes = tileset.maximumMemoryUsage * 1024 * 1024;
|
|
81
|
-
|
|
82
93
|
// Traverse the list only to the sentinel since tiles/nodes to the
|
|
83
94
|
// right of the sentinel were used this frame.
|
|
84
95
|
// The sub-list to the left of the sentinel is ordered from LRU to MRU.
|
|
85
96
|
const sentinel = this._sentinel;
|
|
86
97
|
let node = list.head;
|
|
87
98
|
|
|
88
|
-
while (
|
|
89
|
-
node !== sentinel &&
|
|
90
|
-
(tileset.gpuMemoryUsageInBytes > maximumMemoryUsageInBytes || trimTiles)
|
|
91
|
-
) {
|
|
99
|
+
while (node !== sentinel && (tileset.gpuMemoryUsageInBytes > tileset.cacheBytes || trimTiles)) {
|
|
92
100
|
// @ts-expect-error
|
|
93
101
|
const tile = node.item;
|
|
94
102
|
// @ts-expect-error
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// loaders.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {Tile3D} from './tile-3d';
|
|
6
|
+
import type {Tileset3D} from './tileset-3d';
|
|
7
|
+
import type {TileContentLoadResult} from './tileset-source';
|
|
8
|
+
import type {Tile3DContent} from './tile-3d-contracts';
|
|
9
|
+
import {TILESET_TYPE} from '../../constants';
|
|
10
|
+
|
|
11
|
+
/** Options for complete camera-independent tileset content traversal. */
|
|
12
|
+
export interface TraverseTilesetContentsOptions {
|
|
13
|
+
/** Cancel traversal and stop issuing further source requests. */
|
|
14
|
+
readonly signal?: AbortSignal;
|
|
15
|
+
/**
|
|
16
|
+
* Unload content loaded by this traversal when iteration advances or closes, including on error.
|
|
17
|
+
* Defaults to false. Preloaded content is retained. Use a runtime dedicated to this traversal;
|
|
18
|
+
* consume payloads before advancing and do not retain them or update the runtime concurrently.
|
|
19
|
+
*/
|
|
20
|
+
readonly unloadContent?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** One tile placement and its ordered content entries from a completed source read. */
|
|
24
|
+
export interface TilesetContentTraversalItem {
|
|
25
|
+
/** Runtime tile placement. Shared content resources are yielded once per placement. */
|
|
26
|
+
readonly tile: Tile3D;
|
|
27
|
+
/** Ordered content entries, including multiple contents declared by a single tile. */
|
|
28
|
+
readonly contents: readonly Tile3DContent[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Walks every declared tile placement and its loaded content without a camera or visibility test.
|
|
33
|
+
*
|
|
34
|
+
* Source implementations remain responsible for lazy subtree and node-page resolution. Children
|
|
35
|
+
* are visited in declaration order, nested tilesets are installed by the source before descent,
|
|
36
|
+
* and repeated resource URLs are not deduplicated because each placement can have a distinct
|
|
37
|
+
* transform. Content stays attached unless `unloadContent` is enabled. In that mode, newly loaded
|
|
38
|
+
* payloads are valid until iteration advances or closes. Tile placements and children remain
|
|
39
|
+
* available; callers still own the tileset, source, and archive lifetime.
|
|
40
|
+
*
|
|
41
|
+
* @param tileset - Initialized or initializing source-backed tileset runtime.
|
|
42
|
+
* @param options - Cancellation and decoded-content lifetime options.
|
|
43
|
+
* @returns One item for each visited tile placement in deterministic depth-first order.
|
|
44
|
+
*/
|
|
45
|
+
export async function* traverseTilesetContents(
|
|
46
|
+
tileset: Tileset3D,
|
|
47
|
+
options: TraverseTilesetContentsOptions = {}
|
|
48
|
+
): AsyncGenerator<TilesetContentTraversalItem> {
|
|
49
|
+
await tileset.tilesetInitializationPromise;
|
|
50
|
+
throwIfAborted(options.signal);
|
|
51
|
+
if (!tileset.root) {
|
|
52
|
+
throw new Error('Tileset initialization completed without a root tile');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const stack: Tile3D[] = [tileset.root];
|
|
56
|
+
const visitedTiles = new Set<Tile3D>();
|
|
57
|
+
while (stack.length > 0) {
|
|
58
|
+
throwIfAborted(options.signal);
|
|
59
|
+
const tile = stack.pop() as Tile3D;
|
|
60
|
+
if (visitedTiles.has(tile)) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
visitedTiles.add(tile);
|
|
64
|
+
|
|
65
|
+
if (tile.header.implicitSubtree && tile.childrenState !== 'ready') {
|
|
66
|
+
const loadChildren = tileset.source.loadTileChildrenForTraversal;
|
|
67
|
+
if (!loadChildren) {
|
|
68
|
+
throw new Error('Tileset source does not support camera-independent subtree loading');
|
|
69
|
+
}
|
|
70
|
+
const result = await loadChildren.call(tileset.source, tile, options.signal);
|
|
71
|
+
if (!result.loaded) {
|
|
72
|
+
throw new Error(`Unable to load implicit subtree for tile ${tile.id}`);
|
|
73
|
+
}
|
|
74
|
+
tile.childrenState = 'ready';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (tileset.type === TILESET_TYPE.I3S && tileset.source.loadTileChildrenForTraversal) {
|
|
78
|
+
const result = await tileset.source.loadTileChildrenForTraversal(tile, options.signal);
|
|
79
|
+
if (!result.loaded) {
|
|
80
|
+
throw new Error(`Unable to load I3S child nodes for tile ${tile.id}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
throwIfAborted(options.signal);
|
|
85
|
+
const loadsContent = tile.contentUrls.length > 0 && !tile.content;
|
|
86
|
+
try {
|
|
87
|
+
if (loadsContent) {
|
|
88
|
+
const loadResult: TileContentLoadResult = await tile.loadContentForTraversal();
|
|
89
|
+
throwIfAborted(options.signal);
|
|
90
|
+
if (!loadResult.loaded) {
|
|
91
|
+
throw new Error(`Unable to load tile content for tile ${tile.id}`);
|
|
92
|
+
}
|
|
93
|
+
tileset.source.onTileLoaded?.(tileset, tile, loadResult);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
yield {tile, contents: tile.contentEntries};
|
|
97
|
+
} finally {
|
|
98
|
+
if (options.unloadContent && loadsContent) {
|
|
99
|
+
tile.unloadContent();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
for (let childIndex = tile.children.length - 1; childIndex >= 0; childIndex--) {
|
|
104
|
+
stack.push(tile.children[childIndex]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Throws the signal reason when traversal is cancelled. */
|
|
110
|
+
function throwIfAborted(signal?: AbortSignal): void {
|
|
111
|
+
if (signal?.aborted) {
|
|
112
|
+
throw signal.reason ?? new DOMException('The operation was aborted', 'AbortError');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) vis.gl contributors
|
|
3
|
+
|
|
4
|
+
import type {Tileset3D} from './tileset-3d';
|
|
5
|
+
import type {Tile3D} from './tile-3d';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A deterministic, renderer-neutral snapshot of one {@link Tileset3D} traversal.
|
|
9
|
+
*
|
|
10
|
+
* Tile IDs are sorted so snapshots can be compared across runs even when child requests complete
|
|
11
|
+
* in a different order. Counts are reported for the completed traversal frame and cache values are
|
|
12
|
+
* expressed in bytes. This is an inspection contract; it does not alter traversal or request policy.
|
|
13
|
+
*/
|
|
14
|
+
export type Tileset3DTraversalSnapshot = {
|
|
15
|
+
/** Monotonically increasing traversal frame number. */
|
|
16
|
+
frameNumber: number;
|
|
17
|
+
/** IDs selected for rendering, sorted for stable comparisons. */
|
|
18
|
+
selectedTileIds: string[];
|
|
19
|
+
/** IDs whose content was requested, sorted for stable comparisons. */
|
|
20
|
+
requestedTileIds: string[];
|
|
21
|
+
/** IDs visited as hierarchy-only or empty tiles, sorted for stable comparisons. */
|
|
22
|
+
emptyTileIds: string[];
|
|
23
|
+
/** Number of selected tiles in the completed frame. */
|
|
24
|
+
visibleTileCount: number;
|
|
25
|
+
/** Number of selected tiles with renderable content. */
|
|
26
|
+
renderableTileCount: number;
|
|
27
|
+
/** Number of tile or subtree loads currently in flight. */
|
|
28
|
+
loadingTileCount: number;
|
|
29
|
+
/** Cumulative number of tiles loaded into the runtime cache. */
|
|
30
|
+
loadedTileCount: number;
|
|
31
|
+
/** Cumulative number of failed tile loads. */
|
|
32
|
+
failedTileCount: number;
|
|
33
|
+
/** Number of tiles currently retained in the runtime cache. */
|
|
34
|
+
cachedTileCount: number;
|
|
35
|
+
/** Estimated cached content bytes. */
|
|
36
|
+
cacheBytes: number;
|
|
37
|
+
/** Active memory-adjusted maximum SSE in logical/CSS pixels. */
|
|
38
|
+
maximumScreenSpaceError: number;
|
|
39
|
+
/** Source-specific implicit subtree counters, when the source exposes them. */
|
|
40
|
+
implicitTiling?: {
|
|
41
|
+
/** Number of subtree resources requested from the source. */
|
|
42
|
+
requestedSubtrees: number;
|
|
43
|
+
/** Number of subtree resources successfully materialized. */
|
|
44
|
+
loadedSubtrees: number;
|
|
45
|
+
/** Number of requests served by the parsed-subtree cache. */
|
|
46
|
+
cacheHits: number;
|
|
47
|
+
/** Number of parsed subtrees currently retained for reuse. */
|
|
48
|
+
cachedSubtrees: number;
|
|
49
|
+
/** Number of subtree requests currently in flight. */
|
|
50
|
+
pendingSubtrees: number;
|
|
51
|
+
/** Number of runtime tile headers created from materialized subtrees. */
|
|
52
|
+
materializedTiles: number;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Creates a stable observability snapshot from public {@link Tileset3D} state.
|
|
58
|
+
*
|
|
59
|
+
* The helper intentionally reads only public runtime fields and source diagnostics. It is safe to
|
|
60
|
+
* call from an instrumentation loop and does not retain tile or content references.
|
|
61
|
+
*
|
|
62
|
+
* @param tileset - Runtime whose most recent traversal should be inspected.
|
|
63
|
+
* @returns A serializable snapshot suitable for logs, regression fixtures, and benchmark output.
|
|
64
|
+
*/
|
|
65
|
+
export function getTileset3DTraversalSnapshot(tileset: Tileset3D): Tileset3DTraversalSnapshot {
|
|
66
|
+
const selectedTiles = tileset.selectedTiles.slice();
|
|
67
|
+
const requestedTiles = tileset.requestedTiles.slice();
|
|
68
|
+
const emptyTiles = tileset.emptyTiles.slice();
|
|
69
|
+
|
|
70
|
+
const getTileIds = (tiles: readonly Tile3D[]): string[] =>
|
|
71
|
+
tiles.map(tile => String(tile.id)).sort();
|
|
72
|
+
|
|
73
|
+
const getStatCount = (name: string): number => {
|
|
74
|
+
const count = tileset.stats.get(name).count;
|
|
75
|
+
return typeof count === 'number' && Number.isFinite(count) ? count : 0;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const implicitTilingSource = tileset.source as Tileset3D['source'] & {
|
|
79
|
+
getImplicitTilingStats?: () => Tileset3DTraversalSnapshot['implicitTiling'];
|
|
80
|
+
};
|
|
81
|
+
const implicitTiling = implicitTilingSource.getImplicitTilingStats?.();
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
frameNumber: tileset.frameNumber,
|
|
85
|
+
selectedTileIds: getTileIds(selectedTiles),
|
|
86
|
+
requestedTileIds: getTileIds(requestedTiles),
|
|
87
|
+
emptyTileIds: getTileIds(emptyTiles),
|
|
88
|
+
visibleTileCount: selectedTiles.length,
|
|
89
|
+
renderableTileCount: selectedTiles.filter(
|
|
90
|
+
tile => tile.contentAvailable && Boolean(tile.content)
|
|
91
|
+
).length,
|
|
92
|
+
loadingTileCount: getStatCount('Tiles Loading'),
|
|
93
|
+
loadedTileCount: getStatCount('Tiles Loaded'),
|
|
94
|
+
failedTileCount: getStatCount('Failed Tile Loads'),
|
|
95
|
+
cachedTileCount: getStatCount('Tiles In Memory'),
|
|
96
|
+
cacheBytes: tileset.gpuMemoryUsageInBytes,
|
|
97
|
+
maximumScreenSpaceError: tileset.memoryAdjustedScreenSpaceError,
|
|
98
|
+
...(implicitTiling ? {implicitTiling} : {})
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import type {CoreAPI,
|
|
5
|
+
import type {CoreAPI, Loader, LoaderOptions} from '@loaders.gl/loader-utils';
|
|
6
6
|
import type {Vector3} from '@math.gl/core';
|
|
7
7
|
import type {TilesetTraverser, TilesetTraverserProps} from './tileset-traverser';
|
|
8
8
|
import type {Tile3D} from './tile-3d';
|
|
9
9
|
import type {Tileset3D} from './tileset-3d';
|
|
10
10
|
import type {FrameState} from '../helpers/frame-state';
|
|
11
11
|
import type {TILESET_TYPE} from '../../constants';
|
|
12
|
+
import type {TilesetSpatialReference} from '../../spatial/spatial-types';
|
|
13
|
+
import type {Tile3DContent} from './tile-3d-contracts';
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Parsed top-level tileset payload consumed by {@link Tileset3D} or a {@link Tileset3DSource}.
|
|
@@ -23,18 +25,14 @@ export type TilesetSourceResolver = {
|
|
|
23
25
|
/**
|
|
24
26
|
* Loads and parses the root metadata resource for a source.
|
|
25
27
|
*/
|
|
26
|
-
loadRoot<DataT>(
|
|
27
|
-
url: string,
|
|
28
|
-
loader: LoaderWithParser<DataT>,
|
|
29
|
-
loadOptions: LoaderOptions
|
|
30
|
-
): Promise<DataT>;
|
|
28
|
+
loadRoot<DataT>(url: string, loader: Loader<DataT>, loadOptions: LoaderOptions): Promise<DataT>;
|
|
31
29
|
|
|
32
30
|
/**
|
|
33
31
|
* Loads and parses an arbitrary source-relative resource.
|
|
34
32
|
*/
|
|
35
33
|
loadResource<DataT>(
|
|
36
34
|
url: string,
|
|
37
|
-
loader:
|
|
35
|
+
loader: Loader<DataT>,
|
|
38
36
|
loadOptions: LoaderOptions
|
|
39
37
|
): Promise<DataT>;
|
|
40
38
|
};
|
|
@@ -46,7 +44,7 @@ export type TilesetSourceRequest = {
|
|
|
46
44
|
/** Absolute root metadata URL. */
|
|
47
45
|
url: string;
|
|
48
46
|
/** Loader used to fetch and parse the root metadata. */
|
|
49
|
-
loader:
|
|
47
|
+
loader: Loader;
|
|
50
48
|
/** Optional base path override for relative resources. */
|
|
51
49
|
basePath?: string;
|
|
52
50
|
/** Optional resource-loading strategy used for archive-backed datasets. */
|
|
@@ -69,8 +67,24 @@ export type TilesetSourceInput = TilesetJSON | TilesetSourceRequest;
|
|
|
69
67
|
export type TileContentLoadResult = {
|
|
70
68
|
/** Whether the tile content request produced usable content. */
|
|
71
69
|
loaded: boolean;
|
|
70
|
+
/** All payloads loaded for a tile, in source order. */
|
|
71
|
+
contents?: any[];
|
|
72
|
+
/** Optional normalized renderer-neutral descriptors for each content entry. */
|
|
73
|
+
contentEntries?: Tile3DContent[];
|
|
72
74
|
/** Nested tileset metadata to install below the loaded tile, if any. */
|
|
73
75
|
nestedTileset?: TilesetJSON;
|
|
76
|
+
/** Nested tilesets found among multiple content payloads. */
|
|
77
|
+
nestedTilesets?: TilesetJSON[];
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** Result of a source-managed lazy child-header request. */
|
|
81
|
+
export type TileChildrenLoadResult = {
|
|
82
|
+
/** Whether a subtree resource was loaded and installed. */
|
|
83
|
+
loaded: boolean;
|
|
84
|
+
/** Number of available tiles described by the subtree, including its existing root placeholder. */
|
|
85
|
+
tileCount: number;
|
|
86
|
+
/** Number of lazy child-subtree references installed at the new boundary. */
|
|
87
|
+
childSubtreeCount: number;
|
|
74
88
|
};
|
|
75
89
|
|
|
76
90
|
/**
|
|
@@ -104,8 +118,8 @@ export type TilesetSourceViewState = {
|
|
|
104
118
|
export type TilesetSourceMetadata = {
|
|
105
119
|
/** Format discriminator. */
|
|
106
120
|
type: TILESET_TYPE;
|
|
107
|
-
/**
|
|
108
|
-
loader:
|
|
121
|
+
/** Primary format loader used for metadata and default content requests. */
|
|
122
|
+
loader: Loader;
|
|
109
123
|
/** Absolute root metadata URL. */
|
|
110
124
|
url: string;
|
|
111
125
|
/** Base path used for relative resource resolution. */
|
|
@@ -118,6 +132,8 @@ export type TilesetSourceMetadata = {
|
|
|
118
132
|
lodMetricValue: number;
|
|
119
133
|
/** Root refinement mode used as fallback by runtime tiles. */
|
|
120
134
|
refine: string;
|
|
135
|
+
/** Format-discovered coordinate reference system metadata. */
|
|
136
|
+
spatialReference?: TilesetSpatialReference;
|
|
121
137
|
};
|
|
122
138
|
|
|
123
139
|
/**
|
|
@@ -126,8 +142,8 @@ export type TilesetSourceMetadata = {
|
|
|
126
142
|
export interface Tileset3DSource {
|
|
127
143
|
/** Tileset format discriminator. */
|
|
128
144
|
readonly type: TILESET_TYPE;
|
|
129
|
-
/**
|
|
130
|
-
readonly loader:
|
|
145
|
+
/** Primary format loader used for metadata and default content requests. */
|
|
146
|
+
readonly loader: Loader;
|
|
131
147
|
/** Absolute URL of the root tileset resource. */
|
|
132
148
|
readonly url: string;
|
|
133
149
|
/** Base directory used for relative resource resolution. */
|
|
@@ -157,6 +173,17 @@ export interface Tileset3DSource {
|
|
|
157
173
|
*/
|
|
158
174
|
initialize(): Promise<void>;
|
|
159
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Prepares option-dependent asynchronous source state before runtime headers are constructed.
|
|
178
|
+
*
|
|
179
|
+
* I3S uses this hook to sample elevation surfaces for its root bound after `Tileset3D` has
|
|
180
|
+
* applied spatial options. Sources without asynchronous header preparation omit the hook.
|
|
181
|
+
*/
|
|
182
|
+
prepareTileset?(tileset: Tileset3D): Promise<void>;
|
|
183
|
+
|
|
184
|
+
/** Releases source-local caches and prevents late asynchronous work from mutating runtime tiles. */
|
|
185
|
+
destroy?(): void;
|
|
186
|
+
|
|
160
187
|
/**
|
|
161
188
|
* Returns normalized source metadata after initialization completes.
|
|
162
189
|
*/
|
|
@@ -186,6 +213,25 @@ export interface Tileset3DSource {
|
|
|
186
213
|
*/
|
|
187
214
|
loadTileContent(tile: Tile3D): Promise<TileContentLoadResult>;
|
|
188
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Loads and installs a complete lazy child-header group for a runtime tile.
|
|
218
|
+
*
|
|
219
|
+
* Sources that implement this hook retain ownership of resource parsing, caching, query
|
|
220
|
+
* inheritance, and archive resolution. Traversal calls it only after visibility and LOD checks.
|
|
221
|
+
*/
|
|
222
|
+
loadTileChildren?(tile: Tile3D, frameState: FrameState): Promise<TileChildrenLoadResult>;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Loads all source-managed child headers without requiring camera or visibility state.
|
|
226
|
+
*
|
|
227
|
+
* This hook is used by complete dataset operations such as conversion. Implementations retain
|
|
228
|
+
* ownership of implicit subtrees, node pages, archive resolution, and query inheritance.
|
|
229
|
+
*/
|
|
230
|
+
loadTileChildrenForTraversal?(
|
|
231
|
+
tile: Tile3D,
|
|
232
|
+
signal?: AbortSignal
|
|
233
|
+
): Promise<TileChildrenLoadResult>;
|
|
234
|
+
|
|
189
235
|
/**
|
|
190
236
|
* Resolves a tile-relative path to the final request URL.
|
|
191
237
|
*/
|
|
@@ -204,7 +250,11 @@ export interface Tileset3DSource {
|
|
|
204
250
|
/**
|
|
205
251
|
* Loads child tile metadata on demand for formats that do not expose the full tree up front.
|
|
206
252
|
*/
|
|
207
|
-
loadChildTileHeader?(
|
|
253
|
+
loadChildTileHeader?(
|
|
254
|
+
parentTile: Tile3D,
|
|
255
|
+
childId: string,
|
|
256
|
+
frameState: FrameState | null
|
|
257
|
+
): Promise<any>;
|
|
208
258
|
|
|
209
259
|
/**
|
|
210
260
|
* Updates source-managed bookkeeping after a tile finishes loading.
|
|
@@ -10,6 +10,14 @@ import {FrameState} from '../helpers/frame-state';
|
|
|
10
10
|
export type TilesetTraverserProps = {
|
|
11
11
|
loadSiblings?: boolean;
|
|
12
12
|
skipLevelOfDetail?: boolean;
|
|
13
|
+
/** SSE above which tiles remain part of the non-skipping base traversal. */
|
|
14
|
+
baseScreenSpaceError?: number;
|
|
15
|
+
/** Required SSE reduction from the nearest requested or loaded ancestor before loading a tile. */
|
|
16
|
+
skipScreenSpaceErrorFactor?: number;
|
|
17
|
+
/** Minimum hierarchy levels between requested tiles during skip-LOD traversal. */
|
|
18
|
+
skipLevels?: number;
|
|
19
|
+
/** Requests only final tiles that meet the active SSE target when skip-LOD is enabled. */
|
|
20
|
+
immediatelyLoadDesiredLevelOfDetail?: boolean;
|
|
13
21
|
updateTransforms?: boolean;
|
|
14
22
|
onTraversalEnd?: (frameState) => any;
|
|
15
23
|
viewportTraversersMap?: Record<string, any>;
|
|
@@ -19,6 +27,10 @@ export type TilesetTraverserProps = {
|
|
|
19
27
|
export const DEFAULT_PROPS: Required<TilesetTraverserProps> = {
|
|
20
28
|
loadSiblings: false,
|
|
21
29
|
skipLevelOfDetail: false,
|
|
30
|
+
baseScreenSpaceError: 1024,
|
|
31
|
+
skipScreenSpaceErrorFactor: 16,
|
|
32
|
+
skipLevels: 1,
|
|
33
|
+
immediatelyLoadDesiredLevelOfDetail: false,
|
|
22
34
|
updateTransforms: true,
|
|
23
35
|
onTraversalEnd: () => {},
|
|
24
36
|
viewportTraversersMap: {},
|
|
@@ -28,6 +40,9 @@ export const DEFAULT_PROPS: Required<TilesetTraverserProps> = {
|
|
|
28
40
|
export class TilesetTraverser {
|
|
29
41
|
options: Required<TilesetTraverserProps>;
|
|
30
42
|
|
|
43
|
+
/** Whether loaded content has disabled skip-LOD traversal for this tileset. */
|
|
44
|
+
disableSkipLevelOfDetail: boolean = false;
|
|
45
|
+
|
|
31
46
|
// fulfill in traverse call
|
|
32
47
|
root: any = null;
|
|
33
48
|
|
|
@@ -35,6 +50,8 @@ export class TilesetTraverser {
|
|
|
35
50
|
selectedTiles: Record<string, Tile3D> = {};
|
|
36
51
|
// tiles should be loaded from server
|
|
37
52
|
requestedTiles: Record<string, Tile3D> = {};
|
|
53
|
+
/** Tiles intentionally held until the camera has remained still for the configured delay. */
|
|
54
|
+
deferredTiles: Record<string, Tile3D> = {};
|
|
38
55
|
// tiles does not have render content
|
|
39
56
|
emptyTiles: Record<string, Tile3D> = {};
|
|
40
57
|
|
|
@@ -56,6 +73,11 @@ export class TilesetTraverser {
|
|
|
56
73
|
this.options = {...DEFAULT_PROPS, ...options};
|
|
57
74
|
}
|
|
58
75
|
|
|
76
|
+
/** Returns whether skip-LOD traversal is enabled and supported by the loaded content. */
|
|
77
|
+
isSkipLevelOfDetailEnabled(): boolean {
|
|
78
|
+
return this.options.skipLevelOfDetail && !this.disableSkipLevelOfDetail;
|
|
79
|
+
}
|
|
80
|
+
|
|
59
81
|
// tiles should be visible
|
|
60
82
|
traverse(root, frameState, options) {
|
|
61
83
|
this.root = root; // for root screen space error
|
|
@@ -73,6 +95,7 @@ export class TilesetTraverser {
|
|
|
73
95
|
|
|
74
96
|
reset() {
|
|
75
97
|
this.requestedTiles = {};
|
|
98
|
+
this.deferredTiles = {};
|
|
76
99
|
this.selectedTiles = {};
|
|
77
100
|
this.emptyTiles = {};
|
|
78
101
|
this._traversalStack.reset();
|
|
@@ -137,7 +160,9 @@ export class TilesetTraverser {
|
|
|
137
160
|
// Always load tiles in the base traversal
|
|
138
161
|
// Select tiles that can't refine further
|
|
139
162
|
this.loadTile(tile, frameState);
|
|
140
|
-
|
|
163
|
+
// Skip-LOD keeps a ready ancestor selected while descendants stream in. This prevents
|
|
164
|
+
// replacement holes when traversal jumps over one or more hierarchy levels.
|
|
165
|
+
if (stoppedRefining || this.isSkipLevelOfDetailEnabled()) {
|
|
141
166
|
this.selectTile(tile, frameState);
|
|
142
167
|
}
|
|
143
168
|
}
|
|
@@ -149,6 +174,11 @@ export class TilesetTraverser {
|
|
|
149
174
|
tile._shouldRefine = shouldRefine && parentRefines;
|
|
150
175
|
}
|
|
151
176
|
|
|
177
|
+
this.completeTraversal(frameState);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Notifies the owning tileset when traversal is complete or its debounce interval expires. */
|
|
181
|
+
protected completeTraversal(frameState: FrameState): void {
|
|
152
182
|
const newTime = new Date().getTime();
|
|
153
183
|
if (this.traversalFinished(frameState) || newTime - this.lastUpdate > this.updateDebounceTime) {
|
|
154
184
|
this.lastUpdate = newTime;
|
|
@@ -165,7 +195,8 @@ export class TilesetTraverser {
|
|
|
165
195
|
|
|
166
196
|
/* eslint-disable complexity, max-statements */
|
|
167
197
|
updateAndPushChildren(tile: Tile3D, frameState: FrameState, stack, depth): boolean {
|
|
168
|
-
const {loadSiblings
|
|
198
|
+
const {loadSiblings} = this.options;
|
|
199
|
+
const skipLevelOfDetail = this.isSkipLevelOfDetailEnabled();
|
|
169
200
|
|
|
170
201
|
const children = tile.children;
|
|
171
202
|
|
|
@@ -188,9 +219,10 @@ export class TilesetTraverser {
|
|
|
188
219
|
}
|
|
189
220
|
stack.push(child);
|
|
190
221
|
hasVisibleChild = true;
|
|
191
|
-
} else if (checkRefines || loadSiblings) {
|
|
192
|
-
// Keep non-visible children loaded
|
|
193
|
-
//
|
|
222
|
+
} else if ((checkRefines || loadSiblings) && child._inRequestVolume) {
|
|
223
|
+
// Keep non-visible children loaded when they are inside their viewer request volume;
|
|
224
|
+
// they may still be needed before a replacement parent can refine. The request-volume
|
|
225
|
+
// check intentionally applies to sibling loading as well, preventing off-volume work.
|
|
194
226
|
this.loadTile(child, frameState);
|
|
195
227
|
this.touchTile(child, frameState);
|
|
196
228
|
}
|
|
@@ -225,7 +257,7 @@ export class TilesetTraverser {
|
|
|
225
257
|
|
|
226
258
|
// tile to render in the browser
|
|
227
259
|
selectTile(tile: Tile3D, frameState: FrameState): void {
|
|
228
|
-
if (this.shouldSelectTile(tile)) {
|
|
260
|
+
if (this.shouldSelectTile(tile, frameState)) {
|
|
229
261
|
// The tile can be selected right away and does not require traverseAndSelect
|
|
230
262
|
tile._selectedFrame = frameState.frameNumber;
|
|
231
263
|
this.selectedTiles[tile.id] = tile;
|
|
@@ -235,12 +267,30 @@ export class TilesetTraverser {
|
|
|
235
267
|
// tile to load from server
|
|
236
268
|
loadTile(tile: Tile3D, frameState: FrameState): void {
|
|
237
269
|
if (this.shouldLoadTile(tile)) {
|
|
270
|
+
if (this.shouldDeferTileRequest(tile)) {
|
|
271
|
+
this.deferredTiles[tile.id] = tile;
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
238
274
|
tile._requestedFrame = frameState.frameNumber;
|
|
239
275
|
tile._priority = tile._getPriority();
|
|
240
276
|
this.requestedTiles[tile.id] = tile;
|
|
241
277
|
}
|
|
242
278
|
}
|
|
243
279
|
|
|
280
|
+
/**
|
|
281
|
+
* Returns whether an eligible peripheral request should wait for camera motion to settle.
|
|
282
|
+
*
|
|
283
|
+
* Eligibility and the current time window are calculated together when tile visibility updates.
|
|
284
|
+
* Keeping the active state on the tile also lets a queued scheduler callback cancel work that
|
|
285
|
+
* became deferred after its original traversal.
|
|
286
|
+
*
|
|
287
|
+
* @param tile - Tile considered for loading.
|
|
288
|
+
* @returns `true` when the request should be retried after the remaining delay.
|
|
289
|
+
*/
|
|
290
|
+
shouldDeferTileRequest(tile: Tile3D): boolean {
|
|
291
|
+
return tile.priorityDeferred;
|
|
292
|
+
}
|
|
293
|
+
|
|
244
294
|
// cache tile
|
|
245
295
|
touchTile(tile: Tile3D, frameState: FrameState): void {
|
|
246
296
|
tile.tileset._cache.touch(tile);
|
|
@@ -271,10 +321,13 @@ export class TilesetTraverser {
|
|
|
271
321
|
return tile.hasUnloadedContent || tile.contentExpired;
|
|
272
322
|
}
|
|
273
323
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
324
|
+
/**
|
|
325
|
+
* Returns whether a tile's content is available and visible for rendering.
|
|
326
|
+
* @param tile Tile considered for rendering.
|
|
327
|
+
* @param frameState Current culling state.
|
|
328
|
+
*/
|
|
329
|
+
shouldSelectTile(tile: Tile3D, frameState: FrameState): boolean {
|
|
330
|
+
return tile.contentAvailable && tile.contentVisibility(frameState) !== 'outside';
|
|
278
331
|
}
|
|
279
332
|
|
|
280
333
|
/** Decide if tile LoD (level of detail) is not sufficient under current viewport */
|
|
@@ -323,6 +376,7 @@ export class TilesetTraverser {
|
|
|
323
376
|
// Ignores visibility.
|
|
324
377
|
executeEmptyTraversal(root: Tile3D, frameState: FrameState): boolean {
|
|
325
378
|
let allDescendantsLoaded = true;
|
|
379
|
+
let hasPendingLazyChildren = false;
|
|
326
380
|
const stack = this._emptyTraversalStack;
|
|
327
381
|
stack.push(root);
|
|
328
382
|
|
|
@@ -331,6 +385,12 @@ export class TilesetTraverser {
|
|
|
331
385
|
|
|
332
386
|
const traverse = !tile.hasRenderContent && this.canTraverse(tile, frameState);
|
|
333
387
|
const emptyLeaf = !tile.hasRenderContent && tile.children.length === 0;
|
|
388
|
+
if (tile.header.implicitSubtree) {
|
|
389
|
+
// An unresolved implicit boundary is not a proven empty leaf. Treating it as loaded would
|
|
390
|
+
// allow REPLACE traversal to drop its ancestor before availability and content are known.
|
|
391
|
+
hasPendingLazyChildren = true;
|
|
392
|
+
allDescendantsLoaded = false;
|
|
393
|
+
}
|
|
334
394
|
|
|
335
395
|
// Traversal stops but the tile does not have content yet
|
|
336
396
|
// There will be holes if the parent tries to refine to its children, so don't refine
|
|
@@ -353,6 +413,6 @@ export class TilesetTraverser {
|
|
|
353
413
|
}
|
|
354
414
|
}
|
|
355
415
|
}
|
|
356
|
-
return root.hasEmptyContent || allDescendantsLoaded;
|
|
416
|
+
return (root.hasEmptyContent && !hasPendingLazyChildren) || allDescendantsLoaded;
|
|
357
417
|
}
|
|
358
418
|
}
|