@loaders.gl/tiles 5.0.0-alpha.5 → 5.0.0-alpha.7
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/dist/dist.dev.js +5122 -2641
- package/dist/dist.min.js +4 -2
- package/dist/index.cjs +1670 -403
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/spatial/format-spatial-reference.d.ts +1 -0
- package/dist/spatial/format-spatial-reference.d.ts.map +1 -1
- package/dist/spatial/format-spatial-reference.js +104 -46
- package/dist/spatial/format-spatial-reference.js.map +1 -1
- package/dist/spatial/get-spatial-coordinate-frame.d.ts +12 -1
- package/dist/spatial/get-spatial-coordinate-frame.d.ts.map +1 -1
- package/dist/spatial/get-spatial-coordinate-frame.js +105 -24
- package/dist/spatial/get-spatial-coordinate-frame.js.map +1 -1
- 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 +4 -0
- package/dist/spatial/spatial-coordinate-transformer.d.ts.map +1 -1
- package/dist/spatial/spatial-coordinate-transformer.js +89 -12
- package/dist/spatial/spatial-coordinate-transformer.js.map +1 -1
- 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-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.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 +29 -5
- package/dist/tileset-3d/common/tile-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tile-3d.js +151 -20
- package/dist/tileset-3d/common/tile-3d.js.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.d.ts +44 -2
- package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.js +31 -1
- package/dist/tileset-3d/common/tileset-3d.js.map +1 -1
- 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 +11 -8
- 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 +14 -0
- package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-traverser.js +21 -5
- package/dist/tileset-3d/common/tileset-traverser.js.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts +47 -1
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js +327 -30
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts +34 -2
- 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 +265 -14
- 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 +70 -3
- 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 +216 -4
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-source.d.ts +5 -3
- package/dist/tileset-3d/format-i3s/i3s-source.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-source.js +14 -7
- package/dist/tileset-3d/format-i3s/i3s-source.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 +19 -61
- package/dist/tileset-3d/helpers/bounding-volume.js.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.d.ts +4 -0
- package/dist/tileset-3d/helpers/frame-state.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.js +6 -1
- package/dist/tileset-3d/helpers/frame-state.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/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +14 -13
- package/src/index.ts +13 -1
- package/src/spatial/format-spatial-reference.ts +127 -53
- package/src/spatial/get-spatial-coordinate-frame.ts +126 -31
- package/src/spatial/normalize-crs-identifier.ts +26 -0
- package/src/spatial/spatial-coordinate-transformer.ts +106 -15
- package/src/spatial/tiles-3d-spatial-transformer.ts +206 -0
- package/src/tileset-3d/common/indexed-archive-tileset-source.ts +4 -9
- package/src/tileset-3d/common/tile-3d-contracts.ts +115 -0
- package/src/tileset-3d/common/tile-3d.ts +178 -20
- package/src/tileset-3d/common/tileset-3d.ts +63 -3
- package/src/tileset-3d/common/tileset-observability.ts +100 -0
- package/src/tileset-3d/common/tileset-source.ts +11 -12
- package/src/tileset-3d/common/tileset-traverser.ts +32 -5
- package/src/tileset-3d/format-3d-tiles/implicit-tiling.ts +481 -34
- package/src/tileset-3d/format-3d-tiles/tiles-3d-source.ts +390 -17
- package/src/tileset-3d/format-3d-tiles/tileset-3d-traverser.ts +243 -4
- package/src/tileset-3d/format-i3s/i3s-source.ts +25 -9
- package/src/tileset-3d/helpers/bounding-volume.ts +29 -62
- package/src/tileset-3d/helpers/frame-state.ts +6 -1
- package/src/tileset-3d/helpers/s2-bounding-volume.ts +35 -0
- package/src/types.ts +2 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// loaders.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {SpatialCoordinateTransformer} from './spatial-coordinate-transformer';
|
|
6
|
+
import {getSpatialCoordinateFrame} from './get-spatial-coordinate-frame';
|
|
7
|
+
import {Matrix4} from '@math.gl/core';
|
|
8
|
+
import {Ellipsoid} from '@math.gl/geospatial';
|
|
9
|
+
import type {TilesetSpatialOptions, TilesetSpatialReference} from './spatial-types';
|
|
10
|
+
|
|
11
|
+
/** Structural 3D Tiles volume shape used by the source adapter. */
|
|
12
|
+
export type Tiles3DSpatialBoundingVolume = {
|
|
13
|
+
box?: number[];
|
|
14
|
+
sphere?: number[];
|
|
15
|
+
region?: number[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Applies nonlinear CRS operations to 3D Tiles geometry bounds.
|
|
21
|
+
*
|
|
22
|
+
* Bounds are rebuilt from conservative samples. This intentionally produces an axis-aligned box
|
|
23
|
+
* in the target frame; it is safe for culling and screen-space-error calculations even when the
|
|
24
|
+
* source volume is rotated or the projection is nonlinear.
|
|
25
|
+
*/
|
|
26
|
+
export class Tiles3DSpatialTransformer {
|
|
27
|
+
/** Normalized reference describing the completed operation. */
|
|
28
|
+
readonly spatialReference: TilesetSpatialReference;
|
|
29
|
+
private readonly coordinateTransformer: SpatialCoordinateTransformer;
|
|
30
|
+
private readonly geographicCoordinateTransformer: SpatialCoordinateTransformer;
|
|
31
|
+
|
|
32
|
+
/** Creates a 3D Tiles transformer for a requested target CRS. */
|
|
33
|
+
constructor(spatialReference: TilesetSpatialReference, options: TilesetSpatialOptions = {}) {
|
|
34
|
+
this.coordinateTransformer = new SpatialCoordinateTransformer(spatialReference, options);
|
|
35
|
+
// 3D Tiles regions are always encoded as WGS84 longitude/latitude radians, independently
|
|
36
|
+
// of the tileset's local CRS. Build a second pipeline for that fixed source frame.
|
|
37
|
+
const geographicSpatialReference = {
|
|
38
|
+
...spatialReference,
|
|
39
|
+
sourceCrs: 'EPSG:4326' as const,
|
|
40
|
+
targetCrs: spatialReference.targetCrs || spatialReference.sourceCrs,
|
|
41
|
+
coordinateFrame: 'geographic' as const,
|
|
42
|
+
axisOrder: 'xy' as const
|
|
43
|
+
};
|
|
44
|
+
this.geographicCoordinateTransformer = new SpatialCoordinateTransformer(
|
|
45
|
+
geographicSpatialReference,
|
|
46
|
+
options
|
|
47
|
+
);
|
|
48
|
+
this.spatialReference = spatialReference;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Transform packed POSITION values into the target CRS. */
|
|
52
|
+
transformPositions(positions: ArrayLike<number>): Float64Array {
|
|
53
|
+
return this.coordinateTransformer.transformPositions(positions);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Transform packed NORMAL values using the corresponding source positions. */
|
|
57
|
+
transformNormals(normals: ArrayLike<number>, positions: ArrayLike<number>): Float32Array {
|
|
58
|
+
return this.coordinateTransformer.transformNormals(normals, positions);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Rebuild a conservative target-frame volume from a source volume. */
|
|
62
|
+
transformBoundingVolume(
|
|
63
|
+
volume: Tiles3DSpatialBoundingVolume,
|
|
64
|
+
sourceTransform?: ArrayLike<number>
|
|
65
|
+
): Tiles3DSpatialBoundingVolume {
|
|
66
|
+
const transform = sourceTransform ? new Matrix4(Array.from(sourceTransform)) : undefined;
|
|
67
|
+
const samples = volume.region
|
|
68
|
+
? getRegionSamples(volume.region)
|
|
69
|
+
: getVolumeSamples(volume).map(sample =>
|
|
70
|
+
transform ? Array.from(transform.transformAsPoint(sample)) : sample
|
|
71
|
+
);
|
|
72
|
+
if (!samples.length) {
|
|
73
|
+
return volume;
|
|
74
|
+
}
|
|
75
|
+
const transformed = volume.region
|
|
76
|
+
? samples.map(sample => this.transformRegionSample(sample))
|
|
77
|
+
: samples.map(sample => this.coordinateTransformer.transformPosition(sample));
|
|
78
|
+
return {box: createAxisAlignedBox(transformed)};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Transforms one WGS84 region sample into the selected output frame. */
|
|
82
|
+
private transformRegionSample(sample: number[]): number[] {
|
|
83
|
+
const [longitudeDegrees, latitudeDegrees, height] = sample;
|
|
84
|
+
const targetCrs = this.spatialReference.targetCrs || this.spatialReference.sourceCrs;
|
|
85
|
+
if (targetCrs && getSpatialCoordinateFrame(targetCrs) === 'geocentric') {
|
|
86
|
+
const cartesian = Ellipsoid.WGS84.cartographicToCartesian([
|
|
87
|
+
longitudeDegrees,
|
|
88
|
+
latitudeDegrees,
|
|
89
|
+
height
|
|
90
|
+
]);
|
|
91
|
+
return Array.from(cartesian);
|
|
92
|
+
}
|
|
93
|
+
return this.geographicCoordinateTransformer.transformPosition(sample);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Samples region corners, center lines, and both height planes in degrees/meters. */
|
|
98
|
+
function getRegionSamples(region: number[]): number[][] {
|
|
99
|
+
if (region.length < 6 || region.some(value => !Number.isFinite(value))) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
const [west, south, east, north, minimumHeight, maximumHeight] = region;
|
|
103
|
+
const longitudeEnd = east < west ? east + Math.PI * 2 : east;
|
|
104
|
+
const longitudes = getIntervalSamples(west, longitudeEnd);
|
|
105
|
+
const latitudes = getIntervalSamples(south, north);
|
|
106
|
+
const samples: number[][] = [];
|
|
107
|
+
for (const longitude of longitudes) {
|
|
108
|
+
for (const latitude of latitudes) {
|
|
109
|
+
for (const height of [minimumHeight, maximumHeight]) {
|
|
110
|
+
samples.push([(longitude * 180) / Math.PI, (latitude * 180) / Math.PI, height]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return samples;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Includes interval endpoints and every quarter-turn where ECEF axes reach an extremum. */
|
|
118
|
+
function getIntervalSamples(start: number, end: number): number[] {
|
|
119
|
+
const samples = [start, (start + end) / 2, end];
|
|
120
|
+
const angularStep = Math.PI / 2;
|
|
121
|
+
const firstCriticalIndex = Math.ceil(start / angularStep);
|
|
122
|
+
const lastCriticalIndex = Math.floor(end / angularStep);
|
|
123
|
+
for (
|
|
124
|
+
let criticalIndex = firstCriticalIndex;
|
|
125
|
+
criticalIndex <= lastCriticalIndex;
|
|
126
|
+
criticalIndex++
|
|
127
|
+
) {
|
|
128
|
+
samples.push(criticalIndex * angularStep);
|
|
129
|
+
}
|
|
130
|
+
return samples;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function getVolumeSamples(volume: Tiles3DSpatialBoundingVolume): number[][] {
|
|
134
|
+
if (volume.box && volume.box.length >= 12) {
|
|
135
|
+
const center = volume.box.slice(0, 3);
|
|
136
|
+
const axes = [volume.box.slice(3, 6), volume.box.slice(6, 9), volume.box.slice(9, 12)];
|
|
137
|
+
const samples: number[][] = [];
|
|
138
|
+
for (let firstIndex = 0; firstIndex <= 4; firstIndex++) {
|
|
139
|
+
for (let secondIndex = 0; secondIndex <= 4; secondIndex++) {
|
|
140
|
+
for (let thirdIndex = 0; thirdIndex <= 4; thirdIndex++) {
|
|
141
|
+
const first = firstIndex / 2 - 1;
|
|
142
|
+
const second = secondIndex / 2 - 1;
|
|
143
|
+
const third = thirdIndex / 2 - 1;
|
|
144
|
+
samples.push([
|
|
145
|
+
center[0] + first * axes[0][0] + second * axes[1][0] + third * axes[2][0],
|
|
146
|
+
center[1] + first * axes[0][1] + second * axes[1][1] + third * axes[2][1],
|
|
147
|
+
center[2] + first * axes[0][2] + second * axes[1][2] + third * axes[2][2]
|
|
148
|
+
]);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return samples;
|
|
153
|
+
}
|
|
154
|
+
if (volume.sphere && volume.sphere.length >= 4) {
|
|
155
|
+
const [x, y, z, radius] = volume.sphere;
|
|
156
|
+
const samples = [
|
|
157
|
+
[x - radius, y, z],
|
|
158
|
+
[x + radius, y, z],
|
|
159
|
+
[x, y - radius, z],
|
|
160
|
+
[x, y + radius, z],
|
|
161
|
+
[x, y, z - radius],
|
|
162
|
+
[x, y, z + radius]
|
|
163
|
+
];
|
|
164
|
+
for (let longitudeIndex = 0; longitudeIndex < 16; longitudeIndex++) {
|
|
165
|
+
const longitude = (longitudeIndex * Math.PI * 2) / 16;
|
|
166
|
+
samples.push([x + radius * Math.cos(longitude), y + radius * Math.sin(longitude), z]);
|
|
167
|
+
}
|
|
168
|
+
return samples;
|
|
169
|
+
}
|
|
170
|
+
// Regions are already WGS84 geographic volumes. Keep them unchanged until a dedicated
|
|
171
|
+
// geographic-region adapter can account for longitude wrapping and datum semantics.
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function createAxisAlignedBox(samples: number[][]): number[] {
|
|
176
|
+
const minimum = [Infinity, Infinity, Infinity];
|
|
177
|
+
const maximum = [-Infinity, -Infinity, -Infinity];
|
|
178
|
+
for (const sample of samples) {
|
|
179
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
180
|
+
minimum[axis] = Math.min(minimum[axis], sample[axis]);
|
|
181
|
+
maximum[axis] = Math.max(maximum[axis], sample[axis]);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const padding = [
|
|
185
|
+
Math.max((maximum[0] - minimum[0]) * 0.01, 1e-9),
|
|
186
|
+
Math.max((maximum[1] - minimum[1]) * 0.01, 1e-9),
|
|
187
|
+
Math.max((maximum[2] - minimum[2]) * 0.01, 1e-9)
|
|
188
|
+
];
|
|
189
|
+
const center = [
|
|
190
|
+
(minimum[0] + maximum[0]) / 2,
|
|
191
|
+
(minimum[1] + maximum[1]) / 2,
|
|
192
|
+
(minimum[2] + maximum[2]) / 2
|
|
193
|
+
];
|
|
194
|
+
return [
|
|
195
|
+
...center,
|
|
196
|
+
(maximum[0] - minimum[0]) / 2 + padding[0],
|
|
197
|
+
0,
|
|
198
|
+
0,
|
|
199
|
+
0,
|
|
200
|
+
(maximum[1] - minimum[1]) / 2 + padding[1],
|
|
201
|
+
0,
|
|
202
|
+
0,
|
|
203
|
+
0,
|
|
204
|
+
(maximum[2] - minimum[2]) / 2 + padding[2]
|
|
205
|
+
];
|
|
206
|
+
}
|
|
@@ -3,12 +3,7 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import {BlobFile, HttpFile, path} from '@loaders.gl/loader-utils';
|
|
6
|
-
import type {
|
|
7
|
-
CoreAPI,
|
|
8
|
-
LoaderOptions,
|
|
9
|
-
LoaderWithParser,
|
|
10
|
-
ReadableFile
|
|
11
|
-
} from '@loaders.gl/loader-utils';
|
|
6
|
+
import type {CoreAPI, Loader, LoaderOptions, ReadableFile} from '@loaders.gl/loader-utils';
|
|
12
7
|
import type {TilesetSourceResolver} from './tileset-source';
|
|
13
8
|
|
|
14
9
|
/** Options for {@link IndexedArchiveTilesetSource}. */
|
|
@@ -63,7 +58,7 @@ export class IndexedArchiveTilesetSource<ArchiveT> implements TilesetSourceResol
|
|
|
63
58
|
*/
|
|
64
59
|
async loadRoot<DataT>(
|
|
65
60
|
url: string,
|
|
66
|
-
loader:
|
|
61
|
+
loader: Loader<DataT>,
|
|
67
62
|
loadOptions: LoaderOptions
|
|
68
63
|
): Promise<DataT> {
|
|
69
64
|
return await this.parseArchiveResource(
|
|
@@ -83,7 +78,7 @@ export class IndexedArchiveTilesetSource<ArchiveT> implements TilesetSourceResol
|
|
|
83
78
|
*/
|
|
84
79
|
async loadResource<DataT>(
|
|
85
80
|
url: string,
|
|
86
|
-
loader:
|
|
81
|
+
loader: Loader<DataT>,
|
|
87
82
|
loadOptions: LoaderOptions
|
|
88
83
|
): Promise<DataT> {
|
|
89
84
|
const pathInArchive = this.resolveArchivePath(url, url);
|
|
@@ -93,7 +88,7 @@ export class IndexedArchiveTilesetSource<ArchiveT> implements TilesetSourceResol
|
|
|
93
88
|
private async parseArchiveResource<DataT>(
|
|
94
89
|
resourceUrl: string,
|
|
95
90
|
pathInArchive: string,
|
|
96
|
-
loader:
|
|
91
|
+
loader: Loader<DataT>,
|
|
97
92
|
loadOptions: LoaderOptions,
|
|
98
93
|
mode?: string
|
|
99
94
|
): Promise<DataT> {
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// loaders.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
/** Structural subset implemented by math.gl bounding volumes used by tile renderers. */
|
|
6
|
+
export type Tile3DBoundingVolume = {
|
|
7
|
+
distanceSquaredTo?(point: unknown): number;
|
|
8
|
+
intersectPlane?(plane: unknown): number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/** Renderer-neutral description of one ordered tile content entry. */
|
|
12
|
+
export type Tile3DContent = {
|
|
13
|
+
/** Zero-based source order, stable across loading and unloading. */
|
|
14
|
+
index: number;
|
|
15
|
+
/** Resolved content URI when declared by the tileset. */
|
|
16
|
+
uri?: string;
|
|
17
|
+
/** Tileset group index declared by this content entry. */
|
|
18
|
+
group?: number;
|
|
19
|
+
/** Normalized tile content kind, when detected. */
|
|
20
|
+
type?: string;
|
|
21
|
+
/** Decoded payload, or null while unloaded/failed. */
|
|
22
|
+
payload: unknown;
|
|
23
|
+
/** Raw content metadata reference. */
|
|
24
|
+
metadata: Record<string, unknown> | null;
|
|
25
|
+
/** Transformed content volume, with tile-volume fallback. */
|
|
26
|
+
boundingVolume: Tile3DBoundingVolume | null;
|
|
27
|
+
/** Normalized feature-id declarations for this content. */
|
|
28
|
+
featureIds: Tile3DFeatureIdSet[];
|
|
29
|
+
/** Whether the payload can currently be rendered. */
|
|
30
|
+
renderable: boolean;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** Renderer-neutral feature-id declaration from a tile content payload. */
|
|
34
|
+
export type Tile3DFeatureIdSet = {
|
|
35
|
+
/** Source of the feature identifiers. */
|
|
36
|
+
source: 'attribute' | 'property-table' | 'constant' | 'texture' | 'implicit';
|
|
37
|
+
/** glTF attribute name for attribute-backed identifiers. */
|
|
38
|
+
attribute?: string;
|
|
39
|
+
/** Structural-metadata property-table index. */
|
|
40
|
+
propertyTable?: number;
|
|
41
|
+
/** Constant feature identifier. */
|
|
42
|
+
constant?: number;
|
|
43
|
+
/** Texture-backed identifier declaration, when present. */
|
|
44
|
+
texture?: Record<string, unknown>;
|
|
45
|
+
/** Implicit identifier declaration, when present. */
|
|
46
|
+
implicit?: Record<string, unknown>;
|
|
47
|
+
/** Decoded identifier values, when supplied by a content loader. */
|
|
48
|
+
values?: Uint32Array | Uint16Array | Uint8Array;
|
|
49
|
+
/** Unrecognized source fields preserved for forward compatibility. */
|
|
50
|
+
details?: Record<string, unknown>;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** Raw metadata references inherited by a tile and its contents. */
|
|
54
|
+
export type Tile3DMetadataContext = {
|
|
55
|
+
/** Tileset-level metadata entity. */
|
|
56
|
+
tileset?: Record<string, unknown> | null;
|
|
57
|
+
/** Group metadata entity selected for the tile's primary content. */
|
|
58
|
+
group?: Record<string, unknown> | null;
|
|
59
|
+
/** All tileset groups, used to resolve a selected content entry's group. */
|
|
60
|
+
groups?: readonly (Record<string, unknown> | null)[];
|
|
61
|
+
/** Tile metadata entity. */
|
|
62
|
+
tile?: Record<string, unknown> | null;
|
|
63
|
+
/** Content metadata entity. */
|
|
64
|
+
content?: Record<string, unknown> | null;
|
|
65
|
+
/** Implicit-subtree metadata entity. */
|
|
66
|
+
subtree?: Record<string, unknown> | null;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/** Extracts mesh-feature declarations from a decoded glTF-like payload. */
|
|
70
|
+
export function getTile3DFeatureIdSets(payload: unknown): Tile3DFeatureIdSet[] {
|
|
71
|
+
const featureIdSets: Tile3DFeatureIdSet[] = [];
|
|
72
|
+
const visited = new Set<object>();
|
|
73
|
+
const visit = (value: unknown): void => {
|
|
74
|
+
if (!value || typeof value !== 'object') {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (visited.has(value as object)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
visited.add(value as object);
|
|
81
|
+
const record = value as Record<string, any>;
|
|
82
|
+
const declarations = record.extensions?.EXT_mesh_features?.featureIds;
|
|
83
|
+
if (Array.isArray(declarations)) {
|
|
84
|
+
for (const declaration of declarations) {
|
|
85
|
+
if (!declaration || typeof declaration !== 'object') {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const source = declaration.texture
|
|
89
|
+
? 'texture'
|
|
90
|
+
: declaration.implicit
|
|
91
|
+
? 'implicit'
|
|
92
|
+
: declaration.attribute !== undefined
|
|
93
|
+
? 'attribute'
|
|
94
|
+
: declaration.propertyTable !== undefined
|
|
95
|
+
? 'property-table'
|
|
96
|
+
: 'constant';
|
|
97
|
+
featureIdSets.push({
|
|
98
|
+
source,
|
|
99
|
+
attribute: declaration.attribute,
|
|
100
|
+
propertyTable: declaration.propertyTable,
|
|
101
|
+
constant: declaration.constant,
|
|
102
|
+
texture: declaration.texture,
|
|
103
|
+
implicit: declaration.implicit,
|
|
104
|
+
values: declaration.values,
|
|
105
|
+
details: declaration
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
for (const child of Object.values(record)) {
|
|
110
|
+
visit(child);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
visit(payload);
|
|
114
|
+
return featureIdSets;
|
|
115
|
+
}
|