@loaders.gl/tiles 4.5.3 → 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 +136 -1
- package/dist/dist.dev.js +22570 -4947
- package/dist/dist.min.js +3 -1
- package/dist/image-set.d.ts +94 -0
- package/dist/image-set.d.ts.map +1 -0
- package/dist/image-set.js +243 -0
- package/dist/image-set.js.map +1 -0
- package/dist/index.cjs +10171 -2117
- package/dist/index.cjs.map +3 -4
- package/dist/index.d.ts +50 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -8
- package/dist/index.js.map +1 -1
- package/dist/point-cloud/point-cloud-tile.d.ts +47 -0
- package/dist/point-cloud/point-cloud-tile.d.ts.map +1 -0
- package/dist/point-cloud/point-cloud-tile.js +70 -0
- package/dist/point-cloud/point-cloud-tile.js.map +1 -0
- package/dist/point-cloud/point-cloud-tileset.d.ts +135 -0
- package/dist/point-cloud/point-cloud-tileset.d.ts.map +1 -0
- package/dist/point-cloud/point-cloud-tileset.js +549 -0
- package/dist/point-cloud/point-cloud-tileset.js.map +1 -0
- package/dist/point-cloud/types.d.ts +81 -0
- package/dist/point-cloud/types.d.ts.map +1 -0
- package/dist/point-cloud/types.js +5 -0
- package/dist/point-cloud/types.js.map +1 -0
- package/dist/raster-set.d.ts +124 -0
- package/dist/raster-set.d.ts.map +1 -0
- package/dist/raster-set.js +348 -0
- package/dist/raster-set.js.map +1 -0
- 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 +37 -0
- package/dist/tileset-2d/adapter.d.ts.map +1 -0
- package/dist/tileset-2d/adapter.js +5 -0
- package/dist/tileset-2d/adapter.js.map +1 -0
- package/dist/tileset-2d/index.d.ts +7 -0
- package/dist/tileset-2d/index.d.ts.map +1 -0
- package/dist/tileset-2d/index.js +6 -0
- package/dist/tileset-2d/index.js.map +1 -0
- package/dist/tileset-2d/tile-2d-header.d.ts +68 -0
- package/dist/tileset-2d/tile-2d-header.d.ts.map +1 -0
- package/dist/tileset-2d/tile-2d-header.js +181 -0
- package/dist/tileset-2d/tile-2d-header.js.map +1 -0
- package/dist/tileset-2d/tileset-2d.d.ts +200 -0
- package/dist/tileset-2d/tileset-2d.d.ts.map +1 -0
- package/dist/tileset-2d/tileset-2d.js +532 -0
- package/dist/tileset-2d/tileset-2d.js.map +1 -0
- package/dist/tileset-2d/types.d.ts +44 -0
- package/dist/tileset-2d/types.d.ts.map +1 -0
- package/dist/tileset-2d/types.js +5 -0
- package/dist/tileset-2d/types.js.map +1 -0
- package/dist/tileset-2d.d.ts +2 -0
- package/dist/tileset-2d.d.ts.map +1 -0
- package/dist/tileset-2d.js +5 -0
- package/dist/tileset-2d.js.map +1 -0
- package/dist/tileset-3d/common/indexed-archive-tileset-source.d.ts +60 -0
- package/dist/tileset-3d/common/indexed-archive-tileset-source.d.ts.map +1 -0
- package/dist/tileset-3d/common/indexed-archive-tileset-source.js +130 -0
- package/dist/tileset-3d/common/indexed-archive-tileset-source.js.map +1 -0
- 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 +410 -0
- package/dist/tileset-3d/common/tile-3d.d.ts.map +1 -0
- package/dist/tileset-3d/common/tile-3d.js +1056 -0
- package/dist/tileset-3d/common/tile-3d.js.map +1 -0
- package/dist/tileset-3d/common/tileset-3d.d.ts +360 -0
- package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -0
- package/dist/tileset-3d/common/tileset-3d.js +846 -0
- package/dist/tileset-3d/common/tileset-3d.js.map +1 -0
- package/dist/tileset-3d/common/tileset-cache.d.ts +29 -0
- package/dist/tileset-3d/common/tileset-cache.d.ts.map +1 -0
- package/dist/{tileset → tileset-3d/common}/tileset-cache.js +12 -4
- package/dist/tileset-3d/common/tileset-cache.js.map +1 -0
- 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 +228 -0
- package/dist/tileset-3d/common/tileset-source.d.ts.map +1 -0
- package/dist/tileset-3d/common/tileset-source.js +17 -0
- package/dist/tileset-3d/common/tileset-source.js.map +1 -0
- package/dist/{tileset → tileset-3d/common}/tileset-traverser.d.ts +35 -3
- package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -0
- package/dist/{tileset → tileset-3d/common}/tileset-traverser.js +61 -13
- package/dist/tileset-3d/common/tileset-traverser.js.map +1 -0
- 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 +221 -0
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts.map +1 -0
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js +770 -0
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js.map +1 -0
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts +110 -0
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts.map +1 -0
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js +331 -0
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js.map +1 -0
- package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.d.ts.map +1 -0
- package/dist/{tileset → tileset-3d}/format-i3s/i3s-pending-tiles-register.js +3 -0
- package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.js.map +1 -0
- package/dist/tileset-3d/format-i3s/i3s-source.d.ts +116 -0
- package/dist/tileset-3d/format-i3s/i3s-source.d.ts.map +1 -0
- package/dist/tileset-3d/format-i3s/i3s-source.js +450 -0
- package/dist/tileset-3d/format-i3s/i3s-source.js.map +1 -0
- package/dist/tileset-3d/format-i3s/i3s-tile-manager.d.ts.map +1 -0
- package/dist/{tileset → tileset-3d}/format-i3s/i3s-tile-manager.js +5 -2
- package/dist/tileset-3d/format-i3s/i3s-tile-manager.js.map +1 -0
- package/dist/{tileset → tileset-3d}/format-i3s/i3s-tileset-traverser.d.ts +2 -2
- package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.d.ts.map +1 -0
- package/dist/{tileset → tileset-3d}/format-i3s/i3s-tileset-traverser.js +17 -23
- package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.js.map +1 -0
- package/dist/{tileset → tileset-3d}/helpers/3d-tiles-options.d.ts +1 -1
- package/dist/tileset-3d/helpers/3d-tiles-options.d.ts.map +1 -0
- package/dist/{tileset → tileset-3d}/helpers/3d-tiles-options.js +3 -0
- package/dist/tileset-3d/helpers/3d-tiles-options.js.map +1 -0
- package/dist/{tileset → tileset-3d}/helpers/bounding-volume.d.ts +7 -3
- package/dist/tileset-3d/helpers/bounding-volume.d.ts.map +1 -0
- package/dist/{tileset → tileset-3d}/helpers/bounding-volume.js +20 -91
- package/dist/tileset-3d/helpers/bounding-volume.js.map +1 -0
- package/dist/tileset-3d/helpers/frame-state.d.ts +93 -0
- package/dist/tileset-3d/helpers/frame-state.d.ts.map +1 -0
- package/dist/{tileset → tileset-3d}/helpers/frame-state.js +92 -10
- package/dist/tileset-3d/helpers/frame-state.js.map +1 -0
- package/dist/{tileset → tileset-3d}/helpers/i3s-lod.d.ts +1 -1
- package/dist/tileset-3d/helpers/i3s-lod.d.ts.map +1 -0
- package/dist/{tileset → tileset-3d}/helpers/i3s-lod.js +21 -9
- package/dist/tileset-3d/helpers/i3s-lod.js.map +1 -0
- 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 +72 -0
- package/dist/tileset-3d/helpers/tiles-3d-lod.d.ts.map +1 -0
- package/dist/tileset-3d/helpers/tiles-3d-lod.js +257 -0
- package/dist/tileset-3d/helpers/tiles-3d-lod.js.map +1 -0
- 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/{tileset → tileset-3d}/helpers/transform-utils.d.ts +1 -1
- package/dist/tileset-3d/helpers/transform-utils.d.ts.map +1 -0
- package/dist/tileset-3d/helpers/transform-utils.js.map +1 -0
- package/dist/tileset-3d/helpers/zoom.d.ts.map +1 -0
- package/dist/tileset-3d/helpers/zoom.js.map +1 -0
- package/dist/types.d.ts +14 -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/image-set.ts +328 -0
- package/src/index.ts +157 -9
- package/src/point-cloud/point-cloud-tile.ts +80 -0
- package/src/point-cloud/point-cloud-tileset.ts +767 -0
- package/src/point-cloud/types.ts +99 -0
- package/src/raster-set.ts +504 -0
- 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 +46 -0
- package/src/tileset-2d/index.ts +33 -0
- package/src/tileset-2d/tile-2d-header.ts +224 -0
- package/src/tileset-2d/tileset-2d.ts +715 -0
- package/src/tileset-2d/types.ts +39 -0
- package/src/tileset-2d.ts +5 -0
- package/src/tileset-3d/common/indexed-archive-tileset-source.ts +205 -0
- package/src/tileset-3d/common/tile-3d-contracts.ts +115 -0
- package/src/tileset-3d/common/tile-3d.ts +1310 -0
- package/src/tileset-3d/common/tileset-3d.ts +1166 -0
- package/src/{tileset → tileset-3d/common}/tileset-cache.ts +16 -8
- 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 +284 -0
- package/src/{tileset → tileset-3d/common}/tileset-traverser.ts +74 -14
- package/src/tileset-3d/format-3d-tiles/implicit-tiling.ts +1059 -0
- package/src/tileset-3d/format-3d-tiles/tiles-3d-source.ts +1025 -0
- package/src/tileset-3d/format-3d-tiles/tileset-3d-traverser.ts +379 -0
- package/src/{tileset → tileset-3d}/format-i3s/i3s-pending-tiles-register.ts +4 -0
- package/src/tileset-3d/format-i3s/i3s-source.ts +557 -0
- package/src/{tileset → tileset-3d}/format-i3s/i3s-tile-manager.ts +6 -2
- package/src/{tileset → tileset-3d}/format-i3s/i3s-tileset-traverser.ts +20 -24
- package/src/{tileset → tileset-3d}/helpers/3d-tiles-options.ts +5 -1
- package/src/{tileset → tileset-3d}/helpers/bounding-volume.ts +31 -114
- package/src/tileset-3d/helpers/frame-state.ts +322 -0
- package/src/{tileset → tileset-3d}/helpers/i3s-lod.ts +24 -10
- package/src/tileset-3d/helpers/s2-bounding-volume.ts +35 -0
- package/src/tileset-3d/helpers/tiles-3d-lod.ts +370 -0
- package/src/tileset-3d/helpers/tiles-3d-request-priority.ts +301 -0
- package/src/{tileset → tileset-3d}/helpers/transform-utils.ts +1 -1
- package/src/types.ts +18 -0
- package/src/utils/doubly-linked-list.ts +2 -0
- package/src/utils/managed-array.ts +2 -0
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.d.ts +0 -7
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.d.ts.map +0 -1
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.js +0 -53
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.js.map +0 -1
- package/dist/tileset/format-i3s/i3s-pending-tiles-register.d.ts.map +0 -1
- package/dist/tileset/format-i3s/i3s-pending-tiles-register.js.map +0 -1
- package/dist/tileset/format-i3s/i3s-tile-manager.d.ts.map +0 -1
- package/dist/tileset/format-i3s/i3s-tile-manager.js.map +0 -1
- package/dist/tileset/format-i3s/i3s-tileset-traverser.d.ts.map +0 -1
- package/dist/tileset/format-i3s/i3s-tileset-traverser.js.map +0 -1
- package/dist/tileset/helpers/3d-tiles-options.d.ts.map +0 -1
- package/dist/tileset/helpers/3d-tiles-options.js.map +0 -1
- package/dist/tileset/helpers/bounding-volume.d.ts.map +0 -1
- package/dist/tileset/helpers/bounding-volume.js.map +0 -1
- package/dist/tileset/helpers/frame-state.d.ts +0 -28
- package/dist/tileset/helpers/frame-state.d.ts.map +0 -1
- package/dist/tileset/helpers/frame-state.js.map +0 -1
- package/dist/tileset/helpers/i3s-lod.d.ts.map +0 -1
- package/dist/tileset/helpers/i3s-lod.js.map +0 -1
- package/dist/tileset/helpers/tiles-3d-lod.d.ts +0 -8
- package/dist/tileset/helpers/tiles-3d-lod.d.ts.map +0 -1
- package/dist/tileset/helpers/tiles-3d-lod.js +0 -113
- package/dist/tileset/helpers/tiles-3d-lod.js.map +0 -1
- package/dist/tileset/helpers/transform-utils.d.ts.map +0 -1
- package/dist/tileset/helpers/transform-utils.js.map +0 -1
- package/dist/tileset/helpers/zoom.d.ts.map +0 -1
- package/dist/tileset/helpers/zoom.js.map +0 -1
- package/dist/tileset/tile-3d.d.ts +0 -230
- package/dist/tileset/tile-3d.d.ts.map +0 -1
- package/dist/tileset/tile-3d.js +0 -631
- package/dist/tileset/tile-3d.js.map +0 -1
- package/dist/tileset/tileset-3d.d.ts +0 -284
- package/dist/tileset/tileset-3d.d.ts.map +0 -1
- package/dist/tileset/tileset-3d.js +0 -814
- package/dist/tileset/tileset-3d.js.map +0 -1
- package/dist/tileset/tileset-cache.d.ts +0 -19
- package/dist/tileset/tileset-cache.d.ts.map +0 -1
- package/dist/tileset/tileset-cache.js.map +0 -1
- package/dist/tileset/tileset-traverser.d.ts.map +0 -1
- package/dist/tileset/tileset-traverser.js.map +0 -1
- package/src/tileset/format-3d-tiles/tileset-3d-traverser.ts +0 -63
- package/src/tileset/helpers/frame-state.ts +0 -183
- package/src/tileset/helpers/tiles-3d-lod.ts +0 -149
- package/src/tileset/tile-3d.ts +0 -788
- package/src/tileset/tileset-3d.ts +0 -1037
- /package/dist/{tileset → tileset-3d}/format-i3s/i3s-pending-tiles-register.d.ts +0 -0
- /package/dist/{tileset → tileset-3d}/format-i3s/i3s-tile-manager.d.ts +0 -0
- /package/dist/{tileset → tileset-3d}/helpers/transform-utils.js +0 -0
- /package/dist/{tileset → tileset-3d}/helpers/zoom.d.ts +0 -0
- /package/dist/{tileset → tileset-3d}/helpers/zoom.js +0 -0
- /package/src/{tileset → tileset-3d}/helpers/zoom.ts +0 -0
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
// loaders.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright vis.gl contributors
|
|
4
|
+
import { TILE_REFINEMENT, TILE_TYPE } from "../../constants.js";
|
|
5
|
+
// TypeScript's legacy `node` resolution does not inspect package `exports`, but this public
|
|
6
|
+
// subpath is resolved by the package at runtime and avoids loading unrelated DGGS decoders.
|
|
7
|
+
// @ts-expect-error Conditional package subpath exports require a modern module resolver.
|
|
8
|
+
import { getS2DescendantIndex, getS2IndexFromToken, getS2TokenFromIndex } from '@math.gl/dggs/s2';
|
|
9
|
+
import { convertS2BoundingVolumeToOBB } from "../helpers/s2-bounding-volume.js";
|
|
10
|
+
const QUADTREE_CHILD_COUNT = 4;
|
|
11
|
+
const OCTREE_CHILD_COUNT = 8;
|
|
12
|
+
const AVAILABILITY_RANK_CACHE = new WeakMap();
|
|
13
|
+
/**
|
|
14
|
+
* Creates the lazy reference stored on an implicit subtree-root header.
|
|
15
|
+
*
|
|
16
|
+
* @param descriptor - Shared implicit hierarchy description.
|
|
17
|
+
* @param coordinates - Global coordinates of the subtree root.
|
|
18
|
+
* @returns Serializable reference with its concrete subtree URL.
|
|
19
|
+
*/
|
|
20
|
+
export function createImplicitSubtreeReference(descriptor, coordinates) {
|
|
21
|
+
return {
|
|
22
|
+
coordinates,
|
|
23
|
+
subtreeUrl: replaceImplicitUrlTemplate(descriptor.subtreesUrlTemplate, coordinates),
|
|
24
|
+
descriptor,
|
|
25
|
+
resource: findImplicitPackageResource(descriptor.resourceFiles, replaceImplicitUrlTemplate(descriptor.subtreesUrlTemplate, coordinates))
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Materializes the available tiles described by one subtree file without performing I/O.
|
|
30
|
+
*
|
|
31
|
+
* The function deliberately stops at the subtree boundary. Available child subtrees become lazy
|
|
32
|
+
* references so traversal, SSE, request-volume checks, and the request scheduler decide when the
|
|
33
|
+
* next network request is useful.
|
|
34
|
+
*
|
|
35
|
+
* @param subtree - Parsed availability data for one subtree resource.
|
|
36
|
+
* @param reference - Coordinates and hierarchy description for the subtree root.
|
|
37
|
+
* @returns Materialized root and diagnostic counts.
|
|
38
|
+
* @throws If the subtree root is unavailable or the descriptor is invalid.
|
|
39
|
+
*/
|
|
40
|
+
export function materializeImplicitSubtree(subtree, reference) {
|
|
41
|
+
const { descriptor } = reference;
|
|
42
|
+
validateImplicitDescriptor(descriptor);
|
|
43
|
+
validateImplicitSubtree(subtree, descriptor);
|
|
44
|
+
const counters = { tileCount: 0, childSubtreeCount: 0 };
|
|
45
|
+
const root = materializeAvailableTile(subtree, reference, { localLevel: 0, mortonIndex: 0 }, reference.coordinates, counters);
|
|
46
|
+
if (!root) {
|
|
47
|
+
throw new Error(`Invalid 3D Tiles subtree: root tile is unavailable at ${reference.subtreeUrl}`);
|
|
48
|
+
}
|
|
49
|
+
return { root, ...counters };
|
|
50
|
+
}
|
|
51
|
+
/** Validates availability lengths and tightly packed draft attribute/property row counts. */
|
|
52
|
+
function validateImplicitSubtree(subtree, descriptor) {
|
|
53
|
+
const childCount = getImplicitChildCount(descriptor.subdivisionScheme);
|
|
54
|
+
const tileElementCount = (childCount ** descriptor.subtreeLevels - 1) / (childCount - 1);
|
|
55
|
+
const childSubtreeElementCount = childCount ** descriptor.subtreeLevels;
|
|
56
|
+
validateAvailabilityLength(subtree.tileAvailability, tileElementCount, 'tile');
|
|
57
|
+
const contentAvailabilityStreams = Array.isArray(subtree.contentAvailability)
|
|
58
|
+
? subtree.contentAvailability
|
|
59
|
+
: subtree.contentAvailability
|
|
60
|
+
? [subtree.contentAvailability]
|
|
61
|
+
: [];
|
|
62
|
+
for (const contentAvailability of contentAvailabilityStreams) {
|
|
63
|
+
validateAvailabilityLength(contentAvailability, tileElementCount, 'content');
|
|
64
|
+
}
|
|
65
|
+
validateAvailabilityLength(subtree.childSubtreeAvailability, childSubtreeElementCount, 'child subtree');
|
|
66
|
+
const availableTileCount = countAvailableElements(subtree.tileAvailability, tileElementCount);
|
|
67
|
+
const availableContentCount = contentAvailabilityStreams[0]
|
|
68
|
+
? countAvailableElements(contentAvailabilityStreams[0], tileElementCount)
|
|
69
|
+
: 0;
|
|
70
|
+
validateAttributeLengths(subtree.tileAttributes, availableTileCount, 'tile');
|
|
71
|
+
validateAttributeLengths(subtree.contentAttributes, availableContentCount, 'content');
|
|
72
|
+
if (subtree.tilePropertyRows && subtree.tilePropertyRows.length !== availableTileCount) {
|
|
73
|
+
throw new Error('3DTILES_subtree: tile property-table count does not match availability');
|
|
74
|
+
}
|
|
75
|
+
if (subtree.contentPropertyRows && subtree.contentPropertyRows.length !== availableContentCount) {
|
|
76
|
+
throw new Error('3DTILES_subtree: content property-table count does not match availability');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Verifies that a bitstream contains every bit required by its implicit subtree. */
|
|
80
|
+
function validateAvailabilityLength(availability, elementCount, label) {
|
|
81
|
+
if (availability.constant === 0 || availability.constant === 1) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (!availability.explicitBitstream ||
|
|
85
|
+
availability.explicitBitstream.byteLength * 8 < elementCount) {
|
|
86
|
+
throw new Error(`3DTILES_subtree: ${label} availability bitstream is too short`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Counts available elements within the meaningful, unpadded part of an availability stream. */
|
|
90
|
+
function countAvailableElements(availability, elementCount) {
|
|
91
|
+
if (availability.constant === 1) {
|
|
92
|
+
return elementCount;
|
|
93
|
+
}
|
|
94
|
+
if (availability.constant === 0) {
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
97
|
+
let availableCount = 0;
|
|
98
|
+
for (let index = 0; index < elementCount; index++) {
|
|
99
|
+
if (getAvailabilityValue(availability, index)) {
|
|
100
|
+
availableCount++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return availableCount;
|
|
104
|
+
}
|
|
105
|
+
/** Validates standard subtree attribute accessor counts after availability expansion. */
|
|
106
|
+
function validateAttributeLengths(attributes, availableCount, label) {
|
|
107
|
+
const componentCounts = {
|
|
108
|
+
TILE_BOUNDING_BOX: 16,
|
|
109
|
+
TILE_BOUNDING_SPHERE: 4,
|
|
110
|
+
TILE_GEOMETRIC_ERROR: 1,
|
|
111
|
+
TILE_REFINE: 1,
|
|
112
|
+
TILE_TRANSFORM: 16,
|
|
113
|
+
CONTENT_BOUNDING_BOX: 16,
|
|
114
|
+
CONTENT_BOUNDING_SPHERE: 4
|
|
115
|
+
};
|
|
116
|
+
for (const [semantic, values] of Object.entries(attributes || {})) {
|
|
117
|
+
const componentCount = componentCounts[semantic];
|
|
118
|
+
if (componentCount && values.length !== availableCount * componentCount) {
|
|
119
|
+
throw new Error(`3DTILES_subtree: ${label} attribute ${semantic} count does not match availability`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Replaces implicit coordinate placeholders in a content or subtree URL.
|
|
125
|
+
*
|
|
126
|
+
* @param templateUrl - URL containing level/x/y/z placeholders.
|
|
127
|
+
* @param coordinates - Global coordinates to insert.
|
|
128
|
+
* @returns URL with all coordinate placeholders replaced.
|
|
129
|
+
*/
|
|
130
|
+
export function replaceImplicitUrlTemplate(templateUrl, coordinates, properties = {}) {
|
|
131
|
+
const values = {
|
|
132
|
+
level: coordinates.level,
|
|
133
|
+
x: coordinates.x,
|
|
134
|
+
y: coordinates.y,
|
|
135
|
+
z: coordinates.z,
|
|
136
|
+
...properties
|
|
137
|
+
};
|
|
138
|
+
return templateUrl.replace(/{([^{}]+)}/g, (match, propertyName) => {
|
|
139
|
+
const value = Object.hasOwn(values, propertyName)
|
|
140
|
+
? values[propertyName]
|
|
141
|
+
: values[propertyName.toLowerCase()];
|
|
142
|
+
return value === undefined ? match : String(value);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Builds one available tile and recursively materializes descendants in the same subtree.
|
|
147
|
+
*
|
|
148
|
+
* @param subtree - Parsed availability declarations.
|
|
149
|
+
* @param reference - Current subtree reference.
|
|
150
|
+
* @param localCoordinates - Level and Morton index relative to the current subtree.
|
|
151
|
+
* @param globalCoordinates - Coordinates relative to the complete implicit hierarchy.
|
|
152
|
+
* @param counters - Mutable diagnostic counters owned by the public materializer call.
|
|
153
|
+
* @returns Header for an available tile, or `null` for a sparse unavailable position.
|
|
154
|
+
*/
|
|
155
|
+
function materializeAvailableTile(subtree, reference, localCoordinates, globalCoordinates, counters) {
|
|
156
|
+
const { descriptor } = reference;
|
|
157
|
+
const childCount = getImplicitChildCount(descriptor.subdivisionScheme);
|
|
158
|
+
const availabilityIndex = getLevelOffset(childCount, localCoordinates.localLevel) + localCoordinates.mortonIndex;
|
|
159
|
+
if (!getAvailabilityValue(subtree.tileAvailability, availabilityIndex)) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
counters.tileCount++;
|
|
163
|
+
const contentAvailability = getContentAvailability(subtree.contentAvailability, availabilityIndex);
|
|
164
|
+
const children = [];
|
|
165
|
+
if (globalCoordinates.level < descriptor.maximumLevel) {
|
|
166
|
+
if (localCoordinates.localLevel + 1 < descriptor.subtreeLevels) {
|
|
167
|
+
for (let childIndex = 0; childIndex < childCount; childIndex++) {
|
|
168
|
+
const childCoordinates = getChildCoordinates(globalCoordinates, childIndex, descriptor.subdivisionScheme);
|
|
169
|
+
const childHeader = materializeAvailableTile(subtree, reference, {
|
|
170
|
+
localLevel: localCoordinates.localLevel + 1,
|
|
171
|
+
mortonIndex: localCoordinates.mortonIndex * childCount + childIndex
|
|
172
|
+
}, childCoordinates, counters);
|
|
173
|
+
if (childHeader) {
|
|
174
|
+
children.push(childHeader);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
for (let childIndex = 0; childIndex < childCount; childIndex++) {
|
|
180
|
+
const childSubtreeIndex = localCoordinates.mortonIndex * childCount + childIndex;
|
|
181
|
+
if (getAvailabilityValue(subtree.childSubtreeAvailability, childSubtreeIndex)) {
|
|
182
|
+
const childCoordinates = getChildCoordinates(globalCoordinates, childIndex, descriptor.subdivisionScheme);
|
|
183
|
+
children.push(createLazyImplicitTileHeader(subtree, descriptor, childCoordinates));
|
|
184
|
+
counters.childSubtreeCount++;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return formatImplicitTileHeader(subtree, descriptor, reference, globalCoordinates, availabilityIndex, contentAvailability, children);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Creates a contentless placeholder for an available child subtree.
|
|
193
|
+
*
|
|
194
|
+
* @param descriptor - Shared implicit hierarchy description.
|
|
195
|
+
* @param coordinates - Global coordinates of the child subtree root.
|
|
196
|
+
* @returns Header that participates in culling and SSE before its subtree is requested.
|
|
197
|
+
*/
|
|
198
|
+
function createLazyImplicitTileHeader(subtree, descriptor, coordinates) {
|
|
199
|
+
const resourceFiles = mergeImplicitPackageFiles(descriptor.resourceFiles, subtree.resourceFiles);
|
|
200
|
+
const childDescriptor = resourceFiles ? { ...descriptor, resourceFiles } : descriptor;
|
|
201
|
+
const reference = createImplicitSubtreeReference(childDescriptor, coordinates);
|
|
202
|
+
return {
|
|
203
|
+
id: getImplicitTileId(reference, coordinates),
|
|
204
|
+
children: [],
|
|
205
|
+
implicitSubtree: reference,
|
|
206
|
+
boundingVolume: calculateImplicitBoundingVolume(descriptor.rootBoundingVolume, coordinates, descriptor.subdivisionScheme),
|
|
207
|
+
geometricError: descriptor.rootLodMetricValue / 2 ** coordinates.level,
|
|
208
|
+
lodMetricType: descriptor.lodMetricType,
|
|
209
|
+
lodMetricValue: descriptor.rootLodMetricValue / 2 ** coordinates.level,
|
|
210
|
+
refine: descriptor.refine,
|
|
211
|
+
type: TILE_TYPE.EMPTY,
|
|
212
|
+
implicitMetadata: getImplicitSubtreeMetadata(subtree),
|
|
213
|
+
_scaleGeometricError: descriptor.scaleGeometricError !== false
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/** Decodes supported standard subtree attributes for one tightly packed available row. */
|
|
217
|
+
function getSubtreeAttributeOverrides(attributes, rowIndex, scope) {
|
|
218
|
+
if (!attributes || rowIndex < 0) {
|
|
219
|
+
return {};
|
|
220
|
+
}
|
|
221
|
+
const box = getAttributeComponents(attributes[scope === 'tile' ? 'TILE_BOUNDING_BOX' : 'CONTENT_BOUNDING_BOX'], rowIndex, 16);
|
|
222
|
+
const sphere = getAttributeComponents(attributes[scope === 'tile' ? 'TILE_BOUNDING_SPHERE' : 'CONTENT_BOUNDING_SPHERE'], rowIndex, 4);
|
|
223
|
+
const boundingVolume = box
|
|
224
|
+
? {
|
|
225
|
+
box: [
|
|
226
|
+
box[12],
|
|
227
|
+
box[13],
|
|
228
|
+
box[14],
|
|
229
|
+
box[0] / 2,
|
|
230
|
+
box[1] / 2,
|
|
231
|
+
box[2] / 2,
|
|
232
|
+
box[4] / 2,
|
|
233
|
+
box[5] / 2,
|
|
234
|
+
box[6] / 2,
|
|
235
|
+
box[8] / 2,
|
|
236
|
+
box[9] / 2,
|
|
237
|
+
box[10] / 2
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
: sphere
|
|
241
|
+
? { sphere }
|
|
242
|
+
: undefined;
|
|
243
|
+
if (scope === 'content') {
|
|
244
|
+
return { boundingVolume };
|
|
245
|
+
}
|
|
246
|
+
const geometricError = getAttributeComponents(attributes.TILE_GEOMETRIC_ERROR, rowIndex, 1)?.[0];
|
|
247
|
+
if (geometricError !== undefined && (!Number.isFinite(geometricError) || geometricError < 0)) {
|
|
248
|
+
throw new Error('3DTILES_subtree: TILE_GEOMETRIC_ERROR must be nonnegative');
|
|
249
|
+
}
|
|
250
|
+
const refineValue = getAttributeComponents(attributes.TILE_REFINE, rowIndex, 1)?.[0];
|
|
251
|
+
if (refineValue !== undefined && refineValue !== 0 && refineValue !== 1) {
|
|
252
|
+
throw new Error('3DTILES_subtree: TILE_REFINE must be 0 or 1');
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
boundingVolume,
|
|
256
|
+
geometricError,
|
|
257
|
+
refine: refineValue === undefined
|
|
258
|
+
? undefined
|
|
259
|
+
: refineValue === 0
|
|
260
|
+
? TILE_REFINEMENT.ADD
|
|
261
|
+
: TILE_REFINEMENT.REPLACE,
|
|
262
|
+
transform: getAttributeComponents(attributes.TILE_TRANSFORM, rowIndex, 16)
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/** Copies one logical accessor element and validates its available-row count. */
|
|
266
|
+
function getAttributeComponents(values, rowIndex, componentCount) {
|
|
267
|
+
if (!values) {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
const offset = rowIndex * componentCount;
|
|
271
|
+
if (offset + componentCount > values.length) {
|
|
272
|
+
throw new Error('3DTILES_subtree: attribute accessor is shorter than availability');
|
|
273
|
+
}
|
|
274
|
+
return Array.from({ length: componentCount }, (_unused, componentIndex) => Number(values[offset + componentIndex]));
|
|
275
|
+
}
|
|
276
|
+
/** Returns the tightly packed property/attribute row index for an available element. */
|
|
277
|
+
function getAvailabilityRank(availability, index) {
|
|
278
|
+
if (availability.constant === 1) {
|
|
279
|
+
return index;
|
|
280
|
+
}
|
|
281
|
+
if (availability.constant === 0) {
|
|
282
|
+
return 0;
|
|
283
|
+
}
|
|
284
|
+
let ranks = AVAILABILITY_RANK_CACHE.get(availability);
|
|
285
|
+
if (!ranks) {
|
|
286
|
+
const bitCount = (availability.explicitBitstream?.byteLength || 0) * 8;
|
|
287
|
+
ranks = new Uint32Array(bitCount + 1);
|
|
288
|
+
for (let candidateIndex = 0; candidateIndex < bitCount; candidateIndex++) {
|
|
289
|
+
ranks[candidateIndex + 1] =
|
|
290
|
+
ranks[candidateIndex] + Number(getAvailabilityValue(availability, candidateIndex));
|
|
291
|
+
}
|
|
292
|
+
AVAILABILITY_RANK_CACHE.set(availability, ranks);
|
|
293
|
+
}
|
|
294
|
+
return ranks[index];
|
|
295
|
+
}
|
|
296
|
+
/** Locates a concrete generated URI in a retained glTF package. */
|
|
297
|
+
function findImplicitPackageResource(files, resourceUrl) {
|
|
298
|
+
if (!files?.length) {
|
|
299
|
+
return undefined;
|
|
300
|
+
}
|
|
301
|
+
const urlWithoutQuery = resourceUrl.split('?')[0];
|
|
302
|
+
const packageRelativePath = /^gltf-package:\/\/[^/]+\/(.*)$/.exec(urlWithoutQuery)?.[1];
|
|
303
|
+
const exactFileIndex = files.findIndex(file => {
|
|
304
|
+
const reference = file.originalUri || file.name;
|
|
305
|
+
return (file.uri === urlWithoutQuery ||
|
|
306
|
+
Boolean(reference && (urlWithoutQuery === reference || packageRelativePath === reference)));
|
|
307
|
+
});
|
|
308
|
+
if (exactFileIndex >= 0) {
|
|
309
|
+
return { fileIndex: exactFileIndex, files };
|
|
310
|
+
}
|
|
311
|
+
const fileIndex = files.findIndex(file => {
|
|
312
|
+
const reference = file.originalUri || file.name;
|
|
313
|
+
return Boolean(reference &&
|
|
314
|
+
(urlWithoutQuery.endsWith(`/${reference}`) || urlWithoutQuery.endsWith(`:${reference}`)));
|
|
315
|
+
});
|
|
316
|
+
return fileIndex < 0 ? undefined : { fileIndex, files };
|
|
317
|
+
}
|
|
318
|
+
/** Layers files declared by a child package over inherited parent-package files. */
|
|
319
|
+
function mergeImplicitPackageFiles(parentFiles, childFiles) {
|
|
320
|
+
if (!childFiles?.length) {
|
|
321
|
+
return parentFiles;
|
|
322
|
+
}
|
|
323
|
+
if (!parentFiles?.length) {
|
|
324
|
+
return childFiles;
|
|
325
|
+
}
|
|
326
|
+
const childReferences = new Set(childFiles.flatMap(file => [file.uri, file.originalUri, file.name].filter(Boolean)));
|
|
327
|
+
return [
|
|
328
|
+
...childFiles,
|
|
329
|
+
...parentFiles.filter(file => ![file.uri, file.originalUri, file.name].some(reference => reference && childReferences.has(reference)))
|
|
330
|
+
];
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Formats an available implicit tile as a runtime header.
|
|
334
|
+
*
|
|
335
|
+
* @param descriptor - Shared implicit hierarchy description.
|
|
336
|
+
* @param reference - Current subtree reference used to build stable IDs.
|
|
337
|
+
* @param coordinates - Global tile coordinates.
|
|
338
|
+
* @param contentAvailability - Availability for each content stream in source order.
|
|
339
|
+
* @param children - Materialized or lazy child headers.
|
|
340
|
+
* @returns Runtime tile header.
|
|
341
|
+
*/
|
|
342
|
+
function formatImplicitTileHeader(subtree, descriptor, reference, coordinates, availabilityIndex, contentAvailability, children) {
|
|
343
|
+
const tilePropertyIndex = getAvailabilityRank(subtree.tileAvailability, availabilityIndex);
|
|
344
|
+
const tileProperties = subtree.tilePropertyRows?.[tilePropertyIndex];
|
|
345
|
+
const primaryContentAvailability = Array.isArray(subtree.contentAvailability)
|
|
346
|
+
? subtree.contentAvailability[0]
|
|
347
|
+
: subtree.contentAvailability;
|
|
348
|
+
const contentPropertyIndex = primaryContentAvailability &&
|
|
349
|
+
getAvailabilityValue(primaryContentAvailability, availabilityIndex)
|
|
350
|
+
? getAvailabilityRank(primaryContentAvailability, availabilityIndex)
|
|
351
|
+
: -1;
|
|
352
|
+
const contentProperties = subtree.contentPropertyRows?.[contentPropertyIndex];
|
|
353
|
+
const tileTemplateProperties = subtree.tileTemplatePropertyRows?.[tilePropertyIndex] || tileProperties;
|
|
354
|
+
const contentTemplateProperties = subtree.contentTemplatePropertyRows?.[contentPropertyIndex] || contentProperties;
|
|
355
|
+
const templateProperties = { ...tileTemplateProperties, ...contentTemplateProperties };
|
|
356
|
+
const tileAttributes = getSubtreeAttributeOverrides(subtree.tileAttributes, tilePropertyIndex, 'tile');
|
|
357
|
+
const contentAttributes = getSubtreeAttributeOverrides(subtree.contentAttributes, contentPropertyIndex, 'content');
|
|
358
|
+
const contentUrlTemplates = descriptor.contentUrlTemplates?.length
|
|
359
|
+
? descriptor.contentUrlTemplates
|
|
360
|
+
: [descriptor.contentUrlTemplate];
|
|
361
|
+
const contentEntries = contentUrlTemplates
|
|
362
|
+
.map((templateUrl, contentIndex) => {
|
|
363
|
+
if (!contentAvailability[contentIndex] || !templateUrl) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
const contentUrl = replaceImplicitUrlTemplate(templateUrl, coordinates, templateProperties);
|
|
367
|
+
if (/{[^{}]+}/.test(contentUrl)) {
|
|
368
|
+
throw new Error(`Implicit content URI has unresolved template values: ${contentUrl}`);
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
contentIndex,
|
|
372
|
+
contentUrl
|
|
373
|
+
};
|
|
374
|
+
})
|
|
375
|
+
.filter((entry) => Boolean(entry));
|
|
376
|
+
const availableContentUrls = contentEntries.map(entry => entry.contentUrl);
|
|
377
|
+
const resourceFiles = mergeImplicitPackageFiles(descriptor.resourceFiles, subtree.resourceFiles);
|
|
378
|
+
const content = contentEntries.map(({ contentIndex, contentUrl }) => {
|
|
379
|
+
const packageResource = findImplicitPackageResource(resourceFiles, contentUrl);
|
|
380
|
+
return {
|
|
381
|
+
...(descriptor.contentHeaders?.[contentIndex] ||
|
|
382
|
+
(contentIndex === 0 ? descriptor.contentHeader : {}) ||
|
|
383
|
+
{}),
|
|
384
|
+
...contentAttributes,
|
|
385
|
+
uri: contentUrl,
|
|
386
|
+
...(contentProperties ? { metadata: { properties: contentProperties } } : {}),
|
|
387
|
+
...(packageResource ? { _resource: packageResource } : {})
|
|
388
|
+
};
|
|
389
|
+
});
|
|
390
|
+
const contentUrl = availableContentUrls[0];
|
|
391
|
+
const computedLodMetricValue = descriptor.rootLodMetricValue / 2 ** coordinates.level;
|
|
392
|
+
const lodMetricValue = tileAttributes.geometricError ?? computedLodMetricValue;
|
|
393
|
+
const computedBoundingVolume = calculateImplicitBoundingVolume(descriptor.rootBoundingVolume, coordinates, descriptor.subdivisionScheme);
|
|
394
|
+
return {
|
|
395
|
+
id: getImplicitTileId(reference, coordinates),
|
|
396
|
+
children,
|
|
397
|
+
contentUrl,
|
|
398
|
+
content: content.length > 1 ? content : content[0],
|
|
399
|
+
contents: descriptor.useCanonicalContents && content.length ? content : undefined,
|
|
400
|
+
contentUrls: availableContentUrls,
|
|
401
|
+
refine: tileAttributes.refine || descriptor.refine,
|
|
402
|
+
type: getImplicitTileType(contentUrl),
|
|
403
|
+
lodMetricType: descriptor.lodMetricType,
|
|
404
|
+
lodMetricValue,
|
|
405
|
+
geometricError: lodMetricValue,
|
|
406
|
+
boundingVolume: tileAttributes.boundingVolume || computedBoundingVolume,
|
|
407
|
+
transform: tileAttributes.transform,
|
|
408
|
+
transformMatrix: tileAttributes.transform,
|
|
409
|
+
metadata: tileProperties ? { properties: tileProperties } : undefined,
|
|
410
|
+
implicitMetadata: getImplicitSubtreeMetadata(subtree, tileProperties, contentProperties),
|
|
411
|
+
_scaleGeometricError: descriptor.scaleGeometricError !== false
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Copies subtree metadata references without interpreting property-table schemas.
|
|
416
|
+
*
|
|
417
|
+
* Keeping the references on generated headers makes metadata available to applications while
|
|
418
|
+
* avoiding a false promise that the runtime has already decoded classes, enums, or values.
|
|
419
|
+
*
|
|
420
|
+
* @param subtree - Parsed subtree containing optional metadata declarations.
|
|
421
|
+
* @returns Metadata references, or `undefined` when the subtree declares none.
|
|
422
|
+
*/
|
|
423
|
+
function getImplicitSubtreeMetadata(subtree, tileProperties, contentProperties) {
|
|
424
|
+
if (!subtree.propertyTables &&
|
|
425
|
+
subtree.tileMetadata === undefined &&
|
|
426
|
+
!subtree.contentMetadata &&
|
|
427
|
+
subtree.subtreeMetadata === undefined &&
|
|
428
|
+
!tileProperties &&
|
|
429
|
+
!contentProperties) {
|
|
430
|
+
return undefined;
|
|
431
|
+
}
|
|
432
|
+
return {
|
|
433
|
+
propertyTables: subtree.propertyTables,
|
|
434
|
+
tileMetadata: subtree.tileMetadata,
|
|
435
|
+
contentMetadata: subtree.contentMetadata,
|
|
436
|
+
subtreeMetadata: subtree.subtreeMetadata,
|
|
437
|
+
tileProperties,
|
|
438
|
+
contentProperties
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Returns a stable identity for contentless and content-bearing implicit tiles.
|
|
443
|
+
*
|
|
444
|
+
* @param reference - Owning subtree reference.
|
|
445
|
+
* @param coordinates - Global tile coordinates.
|
|
446
|
+
* @returns Stable source identity independent of content availability.
|
|
447
|
+
*/
|
|
448
|
+
function getImplicitTileId(reference, coordinates) {
|
|
449
|
+
return `${reference.subtreeUrl}#implicit=${coordinates.level}/${coordinates.x}/${coordinates.y}/${coordinates.z}`;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Reads an availability bit without assuming 32-bit coordinate or Morton arithmetic.
|
|
453
|
+
*
|
|
454
|
+
* @param availability - Constant or expanded bitstream availability.
|
|
455
|
+
* @param index - Zero-based availability index.
|
|
456
|
+
* @returns Whether the addressed tile, content, or child subtree exists.
|
|
457
|
+
*/
|
|
458
|
+
function getAvailabilityValue(availability, index) {
|
|
459
|
+
if (typeof availability?.constant === 'number') {
|
|
460
|
+
return Boolean(availability.constant);
|
|
461
|
+
}
|
|
462
|
+
const bitstream = availability?.explicitBitstream;
|
|
463
|
+
if (!bitstream) {
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
const byteIndex = Math.floor(index / 8);
|
|
467
|
+
const bitIndex = index % 8;
|
|
468
|
+
return Boolean((bitstream[byteIndex] >> bitIndex) & 1);
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Reads every content availability stream for one tile in descriptor/source order.
|
|
472
|
+
*
|
|
473
|
+
* @param availability - Single or multiple-content availability declaration.
|
|
474
|
+
* @returns Availability flags aligned with the content URL templates.
|
|
475
|
+
*/
|
|
476
|
+
function getContentAvailability(availability, index) {
|
|
477
|
+
const streams = Array.isArray(availability) ? availability : [availability];
|
|
478
|
+
return streams.map(stream => getAvailabilityValue(stream || { constant: 0 }, index));
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Calculates the breadth-first availability offset for a local subtree level.
|
|
482
|
+
*
|
|
483
|
+
* @param childCount - Branching factor of the subdivision scheme.
|
|
484
|
+
* @param localLevel - Level relative to the subtree root.
|
|
485
|
+
* @returns First availability index for the requested level.
|
|
486
|
+
*/
|
|
487
|
+
function getLevelOffset(childCount, localLevel) {
|
|
488
|
+
return (childCount ** localLevel - 1) / (childCount - 1);
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Calculates one child's global implicit coordinates.
|
|
492
|
+
*
|
|
493
|
+
* @param parent - Global parent coordinates.
|
|
494
|
+
* @param childIndex - Morton-ordered child index.
|
|
495
|
+
* @param subdivisionScheme - Quadtree or octree subdivision.
|
|
496
|
+
* @returns Global child coordinates.
|
|
497
|
+
*/
|
|
498
|
+
function getChildCoordinates(parent, childIndex, subdivisionScheme) {
|
|
499
|
+
return {
|
|
500
|
+
level: parent.level + 1,
|
|
501
|
+
x: parent.x * 2 + (childIndex & 1),
|
|
502
|
+
y: parent.y * 2 + ((childIndex >> 1) & 1),
|
|
503
|
+
z: subdivisionScheme === 'OCTREE' ? parent.z * 2 + ((childIndex >> 2) & 1) : 0
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Returns the branching factor for a supported implicit subdivision scheme.
|
|
508
|
+
*
|
|
509
|
+
* @param subdivisionScheme - Quadtree or octree subdivision.
|
|
510
|
+
* @returns Four for quadtrees or eight for octrees.
|
|
511
|
+
*/
|
|
512
|
+
function getImplicitChildCount(subdivisionScheme) {
|
|
513
|
+
return subdivisionScheme === 'OCTREE' ? OCTREE_CHILD_COUNT : QUADTREE_CHILD_COUNT;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Calculates the bounding volume for global implicit coordinates.
|
|
517
|
+
*
|
|
518
|
+
* Region volumes are divided in longitude/latitude and, for octrees, height. Oriented boxes are
|
|
519
|
+
* divided along their half-axis vectors. S2 roots use math.gl's Hilbert-aware descendant indexing
|
|
520
|
+
* to produce the exact child token and a corresponding geospatial oriented box.
|
|
521
|
+
*
|
|
522
|
+
* @param rootBoundingVolume - Bounding volume of the complete implicit hierarchy.
|
|
523
|
+
* @param coordinates - Global tile coordinates.
|
|
524
|
+
* @param subdivisionScheme - Quadtree or octree subdivision.
|
|
525
|
+
* @returns Bounding volume for the addressed tile.
|
|
526
|
+
*/
|
|
527
|
+
function calculateImplicitBoundingVolume(rootBoundingVolume, coordinates, subdivisionScheme) {
|
|
528
|
+
if (rootBoundingVolume.region) {
|
|
529
|
+
const [west, south, east, north, minimumHeight, maximumHeight] = rootBoundingVolume.region;
|
|
530
|
+
const divisionCount = 2 ** coordinates.level;
|
|
531
|
+
const longitudeSpan = east >= west ? east - west : east + 2 * Math.PI - west;
|
|
532
|
+
const longitudeSize = longitudeSpan / divisionCount;
|
|
533
|
+
const latitudeSize = (north - south) / divisionCount;
|
|
534
|
+
const childWest = normalizeRegionLongitude(west + longitudeSize * coordinates.x);
|
|
535
|
+
const childEast = normalizeRegionLongitude(west + longitudeSize * (coordinates.x + 1));
|
|
536
|
+
const childSouth = south + latitudeSize * coordinates.y;
|
|
537
|
+
let childMinimumHeight = minimumHeight;
|
|
538
|
+
let childMaximumHeight = maximumHeight;
|
|
539
|
+
if (subdivisionScheme === 'OCTREE') {
|
|
540
|
+
const heightSize = (maximumHeight - minimumHeight) / divisionCount;
|
|
541
|
+
childMinimumHeight = minimumHeight + heightSize * coordinates.z;
|
|
542
|
+
childMaximumHeight = childMinimumHeight + heightSize;
|
|
543
|
+
}
|
|
544
|
+
return {
|
|
545
|
+
region: [
|
|
546
|
+
childWest,
|
|
547
|
+
childSouth,
|
|
548
|
+
childEast,
|
|
549
|
+
childSouth + latitudeSize,
|
|
550
|
+
childMinimumHeight,
|
|
551
|
+
childMaximumHeight
|
|
552
|
+
]
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
if (rootBoundingVolume.box) {
|
|
556
|
+
if (rootBoundingVolume.s2VolumeInfo) {
|
|
557
|
+
return calculateS2ImplicitBoundingVolume(rootBoundingVolume, coordinates, subdivisionScheme);
|
|
558
|
+
}
|
|
559
|
+
if (rootBoundingVolume.extensions?.['3DTILES_shape_cylinder_region']) {
|
|
560
|
+
return {
|
|
561
|
+
...rootBoundingVolume,
|
|
562
|
+
box: [...rootBoundingVolume.box]
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
const box = rootBoundingVolume.box;
|
|
566
|
+
const divisionCount = 2 ** coordinates.level;
|
|
567
|
+
const xOffset = -1 + (2 * coordinates.x + 1) / divisionCount;
|
|
568
|
+
const yOffset = -1 + (2 * coordinates.y + 1) / divisionCount;
|
|
569
|
+
const zOffset = -1 + (2 * coordinates.z + 1) / divisionCount;
|
|
570
|
+
const divideHeight = subdivisionScheme === 'OCTREE';
|
|
571
|
+
const center = [
|
|
572
|
+
box[0] + box[3] * xOffset + box[6] * yOffset + (divideHeight ? box[9] * zOffset : 0),
|
|
573
|
+
box[1] + box[4] * xOffset + box[7] * yOffset + (divideHeight ? box[10] * zOffset : 0),
|
|
574
|
+
box[2] + box[5] * xOffset + box[8] * yOffset + (divideHeight ? box[11] * zOffset : 0)
|
|
575
|
+
];
|
|
576
|
+
return {
|
|
577
|
+
box: [
|
|
578
|
+
...center,
|
|
579
|
+
box[3] / divisionCount,
|
|
580
|
+
box[4] / divisionCount,
|
|
581
|
+
box[5] / divisionCount,
|
|
582
|
+
box[6] / divisionCount,
|
|
583
|
+
box[7] / divisionCount,
|
|
584
|
+
box[8] / divisionCount,
|
|
585
|
+
divideHeight ? box[9] / divisionCount : box[9],
|
|
586
|
+
divideHeight ? box[10] / divisionCount : box[10],
|
|
587
|
+
divideHeight ? box[11] / divisionCount : box[11]
|
|
588
|
+
]
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
throw new Error(`Unsupported implicit 3D Tiles bounding volume: ${JSON.stringify(rootBoundingVolume)}`);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Calculates an implicit descendant of an S2 root using math.gl's canonical Hilbert hierarchy.
|
|
595
|
+
*
|
|
596
|
+
* @param rootBoundingVolume - Normalized S2 root volume.
|
|
597
|
+
* @param coordinates - Global implicit tile coordinates.
|
|
598
|
+
* @param subdivisionScheme - Quadtree or octree subdivision.
|
|
599
|
+
* @returns Child volume with updated S2 metadata and oriented box.
|
|
600
|
+
*/
|
|
601
|
+
function calculateS2ImplicitBoundingVolume(rootBoundingVolume, coordinates, subdivisionScheme) {
|
|
602
|
+
const rootS2VolumeInfo = rootBoundingVolume.s2VolumeInfo;
|
|
603
|
+
const rootIndex = getS2IndexFromToken(rootS2VolumeInfo.token);
|
|
604
|
+
const descendantIndex = getS2DescendantIndex(rootIndex, coordinates.level, coordinates.x, coordinates.y);
|
|
605
|
+
const divisionCount = 2 ** coordinates.level;
|
|
606
|
+
const heightSize = (rootS2VolumeInfo.maximumHeight - rootS2VolumeInfo.minimumHeight) / divisionCount;
|
|
607
|
+
const childS2VolumeInfo = {
|
|
608
|
+
token: getS2TokenFromIndex(descendantIndex),
|
|
609
|
+
minimumHeight: rootS2VolumeInfo.minimumHeight +
|
|
610
|
+
(subdivisionScheme === 'OCTREE' ? heightSize * coordinates.z : 0),
|
|
611
|
+
maximumHeight: rootS2VolumeInfo.minimumHeight +
|
|
612
|
+
(subdivisionScheme === 'OCTREE'
|
|
613
|
+
? heightSize * (coordinates.z + 1)
|
|
614
|
+
: heightSize * divisionCount)
|
|
615
|
+
};
|
|
616
|
+
const extensions = rootBoundingVolume.extensions ? { ...rootBoundingVolume.extensions } : undefined;
|
|
617
|
+
if (extensions?.['3DTILES_bounding_volume_S2']) {
|
|
618
|
+
extensions['3DTILES_bounding_volume_S2'] = childS2VolumeInfo;
|
|
619
|
+
}
|
|
620
|
+
if (extensions?.['3DTILES_shape_s2']) {
|
|
621
|
+
extensions['3DTILES_shape_s2'] = childS2VolumeInfo;
|
|
622
|
+
}
|
|
623
|
+
return {
|
|
624
|
+
...rootBoundingVolume,
|
|
625
|
+
...(extensions ? { extensions } : {}),
|
|
626
|
+
s2VolumeInfo: childS2VolumeInfo,
|
|
627
|
+
box: convertS2BoundingVolumeToOBB(childS2VolumeInfo)
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
/** Normalize a longitude while preserving the positive pi boundary for non-wrapped regions. */
|
|
631
|
+
function normalizeRegionLongitude(longitude) {
|
|
632
|
+
let normalizedLongitude = longitude;
|
|
633
|
+
while (normalizedLongitude > Math.PI) {
|
|
634
|
+
normalizedLongitude -= 2 * Math.PI;
|
|
635
|
+
}
|
|
636
|
+
while (normalizedLongitude < -Math.PI) {
|
|
637
|
+
normalizedLongitude += 2 * Math.PI;
|
|
638
|
+
}
|
|
639
|
+
return normalizedLongitude;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Detects the runtime tile category from an available content URL.
|
|
643
|
+
*
|
|
644
|
+
* @param contentUrl - Concrete content URL, if content is available.
|
|
645
|
+
* @returns Runtime tile category.
|
|
646
|
+
*/
|
|
647
|
+
function getImplicitTileType(contentUrl) {
|
|
648
|
+
if (!contentUrl) {
|
|
649
|
+
return TILE_TYPE.EMPTY;
|
|
650
|
+
}
|
|
651
|
+
const extension = contentUrl.split('?')[0].split('.').pop()?.toLowerCase();
|
|
652
|
+
switch (extension) {
|
|
653
|
+
case 'pnts':
|
|
654
|
+
return TILE_TYPE.POINTCLOUD;
|
|
655
|
+
case 'i3dm':
|
|
656
|
+
case 'b3dm':
|
|
657
|
+
case 'glb':
|
|
658
|
+
case 'gltf':
|
|
659
|
+
return TILE_TYPE.SCENEGRAPH;
|
|
660
|
+
default:
|
|
661
|
+
return extension || TILE_TYPE.EMPTY;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Validates descriptor invariants before allocating a runtime subtree.
|
|
666
|
+
*
|
|
667
|
+
* @param descriptor - Serializable implicit hierarchy description.
|
|
668
|
+
* @throws If levels, scheme, or maximum-level semantics are invalid.
|
|
669
|
+
*/
|
|
670
|
+
function validateImplicitDescriptor(descriptor) {
|
|
671
|
+
if (descriptor.subdivisionScheme !== 'QUADTREE' && descriptor.subdivisionScheme !== 'OCTREE') {
|
|
672
|
+
throw new Error(`Unsupported implicit subdivision scheme: ${descriptor.subdivisionScheme}`);
|
|
673
|
+
}
|
|
674
|
+
if (!Number.isInteger(descriptor.subtreeLevels) || descriptor.subtreeLevels < 1) {
|
|
675
|
+
throw new Error('Implicit subtreeLevels must be a positive integer');
|
|
676
|
+
}
|
|
677
|
+
if (!Number.isInteger(descriptor.maximumLevel) || descriptor.maximumLevel < 0) {
|
|
678
|
+
throw new Error('Implicit availableLevels must describe at least the root level');
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
//# sourceMappingURL=implicit-tiling.js.map
|