@loaders.gl/tiles 5.0.0-alpha.1 → 5.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +14 -3
- package/dist/dist.dev.js +17482 -3685
- package/dist/dist.min.js +4 -1
- package/dist/index.cjs +4594 -422
- package/dist/index.cjs.map +3 -4
- package/dist/index.d.ts +16 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/point-cloud/point-cloud-tile.d.ts.map +1 -1
- package/dist/point-cloud/point-cloud-tile.js +3 -0
- package/dist/point-cloud/point-cloud-tile.js.map +1 -1
- package/dist/point-cloud/point-cloud-tileset.d.ts +4 -0
- package/dist/point-cloud/point-cloud-tileset.d.ts.map +1 -1
- package/dist/point-cloud/point-cloud-tileset.js +54 -12
- package/dist/point-cloud/point-cloud-tileset.js.map +1 -1
- package/dist/point-cloud/types.d.ts +17 -0
- package/dist/point-cloud/types.d.ts.map +1 -1
- package/dist/point-cloud/types.js +3 -0
- package/dist/point-cloud/types.js.map +1 -1
- package/dist/raster-set.d.ts +37 -29
- package/dist/raster-set.d.ts.map +1 -1
- package/dist/raster-set.js +25 -2
- package/dist/raster-set.js.map +1 -1
- package/dist/spatial/format-spatial-reference.d.ts +67 -0
- package/dist/spatial/format-spatial-reference.d.ts.map +1 -0
- package/dist/spatial/format-spatial-reference.js +233 -0
- package/dist/spatial/format-spatial-reference.js.map +1 -0
- package/dist/spatial/get-spatial-coordinate-frame.d.ts +9 -0
- package/dist/spatial/get-spatial-coordinate-frame.d.ts.map +1 -0
- package/dist/spatial/get-spatial-coordinate-frame.js +58 -0
- package/dist/spatial/get-spatial-coordinate-frame.js.map +1 -0
- package/dist/spatial/i3s-elevation.d.ts +20 -0
- package/dist/spatial/i3s-elevation.d.ts.map +1 -0
- package/dist/spatial/i3s-elevation.js +90 -0
- package/dist/spatial/i3s-elevation.js.map +1 -0
- package/dist/spatial/i3s-spatial-transformer.d.ts +189 -0
- package/dist/spatial/i3s-spatial-transformer.d.ts.map +1 -0
- package/dist/spatial/i3s-spatial-transformer.js +686 -0
- package/dist/spatial/i3s-spatial-transformer.js.map +1 -0
- package/dist/spatial/spatial-coordinate-transformer.d.ts +48 -0
- package/dist/spatial/spatial-coordinate-transformer.d.ts.map +1 -0
- package/dist/spatial/spatial-coordinate-transformer.js +211 -0
- package/dist/spatial/spatial-coordinate-transformer.js.map +1 -0
- package/dist/spatial/spatial-resource-registry.d.ts +44 -0
- package/dist/spatial/spatial-resource-registry.d.ts.map +1 -0
- package/dist/spatial/spatial-resource-registry.js +67 -0
- package/dist/spatial/spatial-resource-registry.js.map +1 -0
- package/dist/spatial/spatial-types.d.ts +190 -0
- package/dist/spatial/spatial-types.d.ts.map +1 -0
- package/dist/spatial/spatial-types.js +192 -0
- package/dist/spatial/spatial-types.js.map +1 -0
- package/dist/tileset-3d/common/tile-3d.d.ts +147 -4
- package/dist/tileset-3d/common/tile-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tile-3d.js +358 -76
- package/dist/tileset-3d/common/tile-3d.js.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.d.ts +168 -3
- package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.js +306 -23
- package/dist/tileset-3d/common/tileset-3d.js.map +1 -1
- package/dist/tileset-3d/common/tileset-cache.d.ts +11 -1
- package/dist/tileset-3d/common/tileset-cache.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-cache.js +11 -3
- package/dist/tileset-3d/common/tileset-cache.js.map +1 -1
- package/dist/tileset-3d/common/tileset-source.d.ts +32 -0
- package/dist/tileset-3d/common/tileset-source.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-source.js.map +1 -1
- package/dist/tileset-3d/common/tileset-traverser.d.ts +19 -1
- package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-traverser.js +39 -7
- package/dist/tileset-3d/common/tileset-traverser.js.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts +136 -0
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts.map +1 -0
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js +384 -0
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js.map +1 -0
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts +86 -3
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js +196 -21
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts +36 -0
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js +66 -0
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.js +3 -0
- package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-source.d.ts +14 -1
- package/dist/tileset-3d/format-i3s/i3s-source.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-source.js +107 -17
- package/dist/tileset-3d/format-i3s/i3s-source.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tile-manager.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tile-manager.js +3 -0
- package/dist/tileset-3d/format-i3s/i3s-tile-manager.js.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.js +3 -0
- package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.js.map +1 -1
- package/dist/tileset-3d/helpers/3d-tiles-options.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/3d-tiles-options.js +3 -0
- package/dist/tileset-3d/helpers/3d-tiles-options.js.map +1 -1
- package/dist/tileset-3d/helpers/bounding-volume.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/bounding-volume.js +4 -33
- package/dist/tileset-3d/helpers/bounding-volume.js.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.d.ts +62 -2
- package/dist/tileset-3d/helpers/frame-state.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.js +85 -9
- package/dist/tileset-3d/helpers/frame-state.js.map +1 -1
- package/dist/tileset-3d/helpers/i3s-lod.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/i3s-lod.js +20 -8
- package/dist/tileset-3d/helpers/i3s-lod.js.map +1 -1
- package/dist/tileset-3d/helpers/tiles-3d-lod.d.ts +61 -9
- package/dist/tileset-3d/helpers/tiles-3d-lod.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/tiles-3d-lod.js +198 -93
- package/dist/tileset-3d/helpers/tiles-3d-lod.js.map +1 -1
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.d.ts +134 -0
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.d.ts.map +1 -0
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.js +179 -0
- package/dist/tileset-3d/helpers/tiles-3d-request-priority.js.map +1 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/doubly-linked-list.d.ts.map +1 -1
- package/dist/utils/doubly-linked-list.js +1 -0
- package/dist/utils/doubly-linked-list.js.map +1 -1
- package/dist/utils/managed-array.d.ts.map +1 -1
- package/dist/utils/managed-array.js +1 -0
- package/dist/utils/managed-array.js.map +1 -1
- package/package.json +12 -9
- package/src/index.ts +61 -1
- package/src/point-cloud/point-cloud-tile.ts +4 -0
- package/src/point-cloud/point-cloud-tileset.ts +70 -12
- package/src/point-cloud/types.ts +21 -0
- package/src/raster-set.ts +118 -45
- package/src/spatial/format-spatial-reference.ts +311 -0
- package/src/spatial/get-spatial-coordinate-frame.ts +74 -0
- package/src/spatial/i3s-elevation.ts +96 -0
- package/src/spatial/i3s-spatial-transformer.ts +957 -0
- package/src/spatial/spatial-coordinate-transformer.ts +276 -0
- package/src/spatial/spatial-resource-registry.ts +79 -0
- package/src/spatial/spatial-types.ts +422 -0
- package/src/tileset-3d/common/tile-3d.ts +435 -84
- package/src/tileset-3d/common/tileset-3d.ts +445 -23
- package/src/tileset-3d/common/tileset-cache.ts +15 -7
- package/src/tileset-3d/common/tileset-source.ts +36 -0
- package/src/tileset-3d/common/tileset-traverser.ts +40 -7
- package/src/tileset-3d/format-3d-tiles/implicit-tiling.ts +612 -0
- package/src/tileset-3d/format-3d-tiles/tiles-3d-source.ts +254 -21
- package/src/tileset-3d/format-3d-tiles/tileset-3d-traverser.ts +77 -0
- package/src/tileset-3d/format-i3s/i3s-pending-tiles-register.ts +4 -0
- package/src/tileset-3d/format-i3s/i3s-source.ts +119 -18
- package/src/tileset-3d/format-i3s/i3s-tile-manager.ts +4 -0
- package/src/tileset-3d/format-i3s/i3s-tileset-traverser.ts +4 -0
- package/src/tileset-3d/helpers/3d-tiles-options.ts +4 -0
- package/src/tileset-3d/helpers/bounding-volume.ts +5 -55
- package/src/tileset-3d/helpers/frame-state.ts +142 -11
- package/src/tileset-3d/helpers/i3s-lod.ts +22 -8
- package/src/tileset-3d/helpers/tiles-3d-lod.ts +291 -112
- package/src/tileset-3d/helpers/tiles-3d-request-priority.ts +301 -0
- package/src/types.ts +9 -0
- package/src/utils/doubly-linked-list.ts +2 -0
- package/src/utils/managed-array.ts +2 -0
|
@@ -25,6 +25,8 @@ import type {
|
|
|
25
25
|
import {getZoomFromExtent, getZoomFromFullExtent} from '../helpers/zoom';
|
|
26
26
|
import {TILESET_TYPE} from '../../constants';
|
|
27
27
|
import type {TilesetTraverser, TilesetTraverserProps} from '../common/tileset-traverser';
|
|
28
|
+
import {getI3SSpatialReference} from '../../spatial/format-spatial-reference';
|
|
29
|
+
import {I3SSpatialTransformer} from '../../spatial/i3s-spatial-transformer';
|
|
28
30
|
|
|
29
31
|
const EMPTY_CONTENT_FORMATS: TilesetContentFormats = {
|
|
30
32
|
draco: false,
|
|
@@ -63,6 +65,10 @@ export class I3SSource implements Tileset3DSource {
|
|
|
63
65
|
private readonly queryParams: Record<string, string> = {};
|
|
64
66
|
private readonly resolver?: TilesetSourceResolver;
|
|
65
67
|
private rootTileset: TilesetJSON;
|
|
68
|
+
/** Spatial adapter created lazily after Tileset3D applies target options. */
|
|
69
|
+
private spatialTransformer?: I3SSpatialTransformer;
|
|
70
|
+
/** Root header prepared after asynchronous elevation sampling. */
|
|
71
|
+
private preparedRootHeader?: any;
|
|
66
72
|
|
|
67
73
|
/**
|
|
68
74
|
* Creates an I3S source.
|
|
@@ -79,6 +85,7 @@ export class I3SSource implements Tileset3DSource {
|
|
|
79
85
|
this.resolver = request.resolver;
|
|
80
86
|
this.coreApi = request.coreApi;
|
|
81
87
|
this.loadOptions = loadOptions;
|
|
88
|
+
this.initializeQueryParams(loadOptions);
|
|
82
89
|
}
|
|
83
90
|
|
|
84
91
|
/**
|
|
@@ -86,7 +93,7 @@ export class I3SSource implements Tileset3DSource {
|
|
|
86
93
|
*/
|
|
87
94
|
async initialize(): Promise<void> {
|
|
88
95
|
if (!this.rootTileset) {
|
|
89
|
-
this.rootTileset = await this.loadRootData(this.url, this.loadOptions);
|
|
96
|
+
this.rootTileset = await this.loadRootData(this.getTileUrl(this.url), this.loadOptions);
|
|
90
97
|
}
|
|
91
98
|
this.tileset = this.rootTileset;
|
|
92
99
|
|
|
@@ -94,14 +101,6 @@ export class I3SSource implements Tileset3DSource {
|
|
|
94
101
|
this.rootTileset.root = await this.rootTileset.root;
|
|
95
102
|
}
|
|
96
103
|
|
|
97
|
-
const i3sOptions = this.loadOptions.i3s;
|
|
98
|
-
if (i3sOptions && typeof i3sOptions === 'object' && 'token' in i3sOptions) {
|
|
99
|
-
const token = (i3sOptions as Record<string, unknown>).token;
|
|
100
|
-
if (typeof token === 'string') {
|
|
101
|
-
this.queryParams.token = token;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
104
|
this.metadata = {
|
|
106
105
|
type: this.type,
|
|
107
106
|
loader: this.loader,
|
|
@@ -110,7 +109,8 @@ export class I3SSource implements Tileset3DSource {
|
|
|
110
109
|
tileset: this.rootTileset,
|
|
111
110
|
lodMetricType: this.rootTileset.lodMetricType,
|
|
112
111
|
lodMetricValue: this.rootTileset.lodMetricValue,
|
|
113
|
-
refine: this.rootTileset.root?.refine
|
|
112
|
+
refine: this.rootTileset.root?.refine,
|
|
113
|
+
spatialReference: getI3SSpatialReference(this.rootTileset)
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -131,6 +131,26 @@ export class I3SSource implements Tileset3DSource {
|
|
|
131
131
|
return this.getMetadata().tileset;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/** Prepare option-dependent spatial state and the asynchronously placed root bound. */
|
|
135
|
+
async prepareTileset(tileset: Tileset3D): Promise<void> {
|
|
136
|
+
const spatialReference = tileset.spatialReference;
|
|
137
|
+
if (spatialReference.status === 'unresolved') {
|
|
138
|
+
throw new Error(
|
|
139
|
+
spatialReference.warnings[0] ||
|
|
140
|
+
'I3S spatial operations cannot be resolved from the supplied metadata and options'
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
if (spatialReference.status !== 'transformable' && spatialReference.status !== 'transformed') {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
this.spatialTransformer ||= new I3SSpatialTransformer(
|
|
147
|
+
spatialReference,
|
|
148
|
+
tileset.options.spatial
|
|
149
|
+
);
|
|
150
|
+
tileset.spatialReference = this.spatialTransformer.spatialReference;
|
|
151
|
+
this.preparedRootHeader = await this.transformTileHeader(this.getMetadata().tileset.root);
|
|
152
|
+
}
|
|
153
|
+
|
|
134
154
|
/**
|
|
135
155
|
* Creates the runtime root tile for an I3S subtree.
|
|
136
156
|
*/
|
|
@@ -139,7 +159,11 @@ export class I3SSource implements Tileset3DSource {
|
|
|
139
159
|
tilesetJson: TilesetJSON,
|
|
140
160
|
parentTile?: Tile3D | null
|
|
141
161
|
): Tile3D {
|
|
142
|
-
const
|
|
162
|
+
const rootHeader = parentTile ? tilesetJson.root : this.preparedRootHeader || tilesetJson.root;
|
|
163
|
+
if (this.spatialTransformer && !this.preparedRootHeader) {
|
|
164
|
+
throw new Error('I3S spatial root header was not prepared before tile initialization');
|
|
165
|
+
}
|
|
166
|
+
const rootTile = new Tile3DNode(tileset, rootHeader, parentTile || undefined);
|
|
143
167
|
if (parentTile) {
|
|
144
168
|
parentTile.children.push(rootTile);
|
|
145
169
|
rootTile.depth = parentTile.depth + 1;
|
|
@@ -170,16 +194,22 @@ export class I3SSource implements Tileset3DSource {
|
|
|
170
194
|
_tileOptions: {
|
|
171
195
|
attributeUrls: tile.header.attributeUrls,
|
|
172
196
|
textureUrl: tile.header.textureUrl,
|
|
197
|
+
textureUrls: tile.header.textureUrls,
|
|
173
198
|
textureFormat: tile.header.textureFormat,
|
|
174
199
|
textureLoaderOptions: tile.header.textureLoaderOptions,
|
|
175
200
|
materialDefinition: tile.header.materialDefinition,
|
|
201
|
+
layerType: tile.header.layerType,
|
|
202
|
+
pointRenderer: tile.header.pointRenderer,
|
|
203
|
+
pointSymbol: tile.header.pointSymbol,
|
|
176
204
|
isDracoGeometry: tile.header.isDracoGeometry,
|
|
177
205
|
mbs: tile.header.mbs
|
|
178
206
|
},
|
|
179
207
|
_tilesetOptions: {
|
|
180
208
|
store: metadata.tileset.store,
|
|
181
209
|
attributeStorageInfo: metadata.tileset.attributeStorageInfo,
|
|
182
|
-
fields: metadata.tileset.fields
|
|
210
|
+
fields: metadata.tileset.fields,
|
|
211
|
+
spatialReference: tile.tileset.spatialReference,
|
|
212
|
+
spatialOptions: tile.tileset.options.spatial
|
|
183
213
|
},
|
|
184
214
|
isTileHeader: false
|
|
185
215
|
}
|
|
@@ -198,8 +228,9 @@ export class I3SSource implements Tileset3DSource {
|
|
|
198
228
|
_frameState: FrameState
|
|
199
229
|
): Promise<any> {
|
|
200
230
|
const metadata = this.getMetadata();
|
|
201
|
-
if (metadata.tileset.nodePages) {
|
|
202
|
-
|
|
231
|
+
if (metadata.tileset.nodePages || metadata.tileset.pointNodePages) {
|
|
232
|
+
const header = await metadata.tileset.nodePagesTile.formTileFromNodePages(childId);
|
|
233
|
+
return await this.transformTileHeader(header);
|
|
203
234
|
}
|
|
204
235
|
|
|
205
236
|
const nodeUrl = this.getTileUrl(`${this.url}/nodes/${childId}`);
|
|
@@ -215,7 +246,8 @@ export class I3SSource implements Tileset3DSource {
|
|
|
215
246
|
}
|
|
216
247
|
};
|
|
217
248
|
|
|
218
|
-
|
|
249
|
+
const header = await this.loadResourceData(nodeUrl, options);
|
|
250
|
+
return await this.transformTileHeader(header);
|
|
219
251
|
}
|
|
220
252
|
|
|
221
253
|
/**
|
|
@@ -230,14 +262,48 @@ export class I3SSource implements Tileset3DSource {
|
|
|
230
262
|
return tilePath;
|
|
231
263
|
}
|
|
232
264
|
|
|
233
|
-
const
|
|
234
|
-
|
|
265
|
+
const queryDelimiterIndex = tilePath.indexOf('?');
|
|
266
|
+
if (queryDelimiterIndex === -1) {
|
|
267
|
+
return `${tilePath}?${new URLSearchParams(this.queryParams).toString()}`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const existingQuery = tilePath.slice(queryDelimiterIndex + 1);
|
|
271
|
+
const existingQueryKeys = new Set(
|
|
272
|
+
existingQuery.split('&').map(parameter => parameter.split('=', 1)[0])
|
|
273
|
+
);
|
|
274
|
+
const queryParams = new URLSearchParams();
|
|
275
|
+
for (const [key, value] of Object.entries(this.queryParams)) {
|
|
276
|
+
if (!existingQueryKeys.has(key)) {
|
|
277
|
+
queryParams.set(key, value);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const queryString = queryParams.toString();
|
|
282
|
+
return queryString ? `${tilePath}${existingQuery ? '&' : ''}${queryString}` : tilePath;
|
|
235
283
|
}
|
|
236
284
|
|
|
237
285
|
/**
|
|
238
286
|
* Derives the default view state from full extent or store extent metadata.
|
|
239
287
|
*/
|
|
240
|
-
getViewState(
|
|
288
|
+
getViewState(rootTile: Tile3D | null): TilesetSourceViewState {
|
|
289
|
+
if (this.spatialTransformer && rootTile) {
|
|
290
|
+
const center = new Vector3(rootTile.boundingVolume.center);
|
|
291
|
+
const cartographicCenter = new Vector3(rootTile.header.i3sLodMbs.slice(0, 3));
|
|
292
|
+
if (this.spatialTransformer.targetCoordinateFrame === 'geographic') {
|
|
293
|
+
return {
|
|
294
|
+
boundingVolume: rootTile.boundingVolume,
|
|
295
|
+
cartographicCenter,
|
|
296
|
+
cartesianCenter: center,
|
|
297
|
+
zoom: 1
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
boundingVolume: rootTile.boundingVolume,
|
|
302
|
+
cartographicCenter,
|
|
303
|
+
cartesianCenter: center,
|
|
304
|
+
zoom: 1
|
|
305
|
+
};
|
|
306
|
+
}
|
|
241
307
|
const metadata = this.getMetadata();
|
|
242
308
|
const fullExtent = metadata.tileset.fullExtent;
|
|
243
309
|
if (fullExtent) {
|
|
@@ -325,6 +391,20 @@ export class I3SSource implements Tileset3DSource {
|
|
|
325
391
|
return await this.loadWithCoreApi(url, options);
|
|
326
392
|
}
|
|
327
393
|
|
|
394
|
+
/**
|
|
395
|
+
* Initializes query parameters before any URL-backed resource is requested.
|
|
396
|
+
* @param loadOptions Loader options that may contain an ArcGIS token.
|
|
397
|
+
*/
|
|
398
|
+
private initializeQueryParams(loadOptions: LoaderOptions): void {
|
|
399
|
+
const i3sOptions = loadOptions.i3s;
|
|
400
|
+
if (i3sOptions && typeof i3sOptions === 'object' && 'token' in i3sOptions) {
|
|
401
|
+
const token = (i3sOptions as Record<string, unknown>).token;
|
|
402
|
+
if (typeof token === 'string') {
|
|
403
|
+
this.queryParams.token = token;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
328
408
|
/**
|
|
329
409
|
* Loads tile metadata or content through an injected resolver when present, otherwise through the injected core API.
|
|
330
410
|
*/
|
|
@@ -335,6 +415,27 @@ export class I3SSource implements Tileset3DSource {
|
|
|
335
415
|
|
|
336
416
|
return await this.loadWithCoreApi(url, options);
|
|
337
417
|
}
|
|
418
|
+
|
|
419
|
+
/** Transform one I3S header bound after target options and elevation providers are available. */
|
|
420
|
+
private async transformTileHeader(header: any): Promise<any> {
|
|
421
|
+
if (!this.spatialTransformer) {
|
|
422
|
+
return header;
|
|
423
|
+
}
|
|
424
|
+
const sourceBounds = {
|
|
425
|
+
mbs: header.mbs,
|
|
426
|
+
obb: header.obb,
|
|
427
|
+
normalReferenceFrame: this.getMetadata().tileset.store?.normalReferenceFrame
|
|
428
|
+
};
|
|
429
|
+
const transformedBounds = await this.spatialTransformer.transformBoundsAsync(sourceBounds);
|
|
430
|
+
return {
|
|
431
|
+
...header,
|
|
432
|
+
// Tileset3D traversal and culling operate in WGS84 ECEF independently of content output.
|
|
433
|
+
boundingVolume: transformedBounds.boundingVolume,
|
|
434
|
+
// Preserve the renderer/output-frame bound for applications and content coordination.
|
|
435
|
+
spatialBoundingVolume: transformedBounds.spatialBoundingVolume,
|
|
436
|
+
i3sLodMbs: transformedBounds.i3sLodMbs
|
|
437
|
+
};
|
|
438
|
+
}
|
|
338
439
|
}
|
|
339
440
|
|
|
340
441
|
function isTilesetRequest(input: TilesetSourceInput): input is TilesetSourceRequest {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
1
3
|
// This file is derived from the Cesium code base under Apache 2 license
|
|
2
4
|
// See LICENSE.md and https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md
|
|
3
5
|
|
|
4
6
|
/* eslint-disable */
|
|
5
|
-
import {Quaternion, Vector3, Matrix3,
|
|
7
|
+
import {Quaternion, Vector3, Matrix3, degrees} from '@math.gl/core';
|
|
6
8
|
import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
|
|
7
|
-
import {Ellipsoid} from '@math.gl/geospatial';
|
|
9
|
+
import {Ellipsoid, makeOBBFromRegion} from '@math.gl/geospatial';
|
|
8
10
|
import {assert} from '@loaders.gl/loader-utils';
|
|
9
11
|
|
|
10
12
|
// const scratchProjectedBoundingSphere = new BoundingSphere();
|
|
@@ -16,12 +18,6 @@ function defined(x) {
|
|
|
16
18
|
// const scratchMatrix = new Matrix3();
|
|
17
19
|
const scratchPoint = new Vector3();
|
|
18
20
|
const scratchScale = new Vector3();
|
|
19
|
-
const scratchNorthWest = new Vector3();
|
|
20
|
-
const scratchSouthEast = new Vector3();
|
|
21
|
-
const scratchCenter = new Vector3();
|
|
22
|
-
const scratchXAxis = new Vector3();
|
|
23
|
-
const scratchYAxis = new Vector3();
|
|
24
|
-
const scratchZAxis = new Vector3();
|
|
25
21
|
// const scratchRectangle = new Rectangle();
|
|
26
22
|
// const scratchOrientedBoundingBox = new OrientedBoundingBox();
|
|
27
23
|
// const scratchTransform = new Matrix4();
|
|
@@ -42,7 +38,7 @@ export function createBoundingVolume(boundingVolumeHeader, transform, result?) {
|
|
|
42
38
|
return createBox(boundingVolumeHeader.box, transform, result);
|
|
43
39
|
}
|
|
44
40
|
if (boundingVolumeHeader.region) {
|
|
45
|
-
return
|
|
41
|
+
return makeOBBFromRegion(boundingVolumeHeader.region);
|
|
46
42
|
}
|
|
47
43
|
|
|
48
44
|
if (boundingVolumeHeader.sphere) {
|
|
@@ -219,52 +215,6 @@ function createSphere(sphere, transform, result?) {
|
|
|
219
215
|
return new BoundingSphere(center, radius);
|
|
220
216
|
}
|
|
221
217
|
|
|
222
|
-
/**
|
|
223
|
-
* Create OrientedBoundingBox instance from region 3D tiles bounding volume
|
|
224
|
-
* @param region - region 3D tiles bounding volume
|
|
225
|
-
* @returns OrientedBoundingBox instance
|
|
226
|
-
*/
|
|
227
|
-
function createObbFromRegion(region: number[]): OrientedBoundingBox {
|
|
228
|
-
// [west, south, east, north, minimum height, maximum height]
|
|
229
|
-
// Latitudes and longitudes are in the WGS 84 datum as defined in EPSG 4979 and are in radians.
|
|
230
|
-
// Heights are in meters above (or below) the WGS 84 ellipsoid.
|
|
231
|
-
const [west, south, east, north, minHeight, maxHeight] = region;
|
|
232
|
-
|
|
233
|
-
const northWest = Ellipsoid.WGS84.cartographicToCartesian(
|
|
234
|
-
[degrees(west), degrees(north), minHeight],
|
|
235
|
-
scratchNorthWest
|
|
236
|
-
);
|
|
237
|
-
const southEast = Ellipsoid.WGS84.cartographicToCartesian(
|
|
238
|
-
[degrees(east), degrees(south), maxHeight],
|
|
239
|
-
scratchSouthEast
|
|
240
|
-
);
|
|
241
|
-
const centerInCartesian = new Vector3().addVectors(northWest, southEast).multiplyByScalar(0.5);
|
|
242
|
-
Ellipsoid.WGS84.cartesianToCartographic(centerInCartesian, scratchCenter);
|
|
243
|
-
|
|
244
|
-
Ellipsoid.WGS84.cartographicToCartesian(
|
|
245
|
-
[degrees(east), scratchCenter[1], scratchCenter[2]],
|
|
246
|
-
scratchXAxis
|
|
247
|
-
);
|
|
248
|
-
Ellipsoid.WGS84.cartographicToCartesian(
|
|
249
|
-
[scratchCenter[0], degrees(north), scratchCenter[2]],
|
|
250
|
-
scratchYAxis
|
|
251
|
-
);
|
|
252
|
-
Ellipsoid.WGS84.cartographicToCartesian(
|
|
253
|
-
[scratchCenter[0], scratchCenter[1], maxHeight],
|
|
254
|
-
scratchZAxis
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
return createBox(
|
|
258
|
-
[
|
|
259
|
-
...centerInCartesian,
|
|
260
|
-
...scratchXAxis.subtract(centerInCartesian),
|
|
261
|
-
...scratchYAxis.subtract(centerInCartesian),
|
|
262
|
-
...scratchZAxis.subtract(centerInCartesian)
|
|
263
|
-
],
|
|
264
|
-
new Matrix4()
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
218
|
/**
|
|
269
219
|
* Convert a bounding volume defined by OrientedBoundingBox to cartographic bounds
|
|
270
220
|
* @returns {CartographicBounds}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// loaders.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
1
5
|
import type {Tile3D} from '../common/tile-3d';
|
|
2
6
|
import {Vector3} from '@math.gl/core';
|
|
3
7
|
import {CullingVolume, Plane} from '@math.gl/culling';
|
|
@@ -6,20 +10,59 @@ import {GeospatialViewport, Viewport} from '../../types';
|
|
|
6
10
|
|
|
7
11
|
export type FrameState = {
|
|
8
12
|
camera: {
|
|
13
|
+
/** Camera position in WGS84 Cartesian meters. */
|
|
9
14
|
position: number[];
|
|
15
|
+
/** Normalized camera direction in WGS84 Cartesian coordinates. */
|
|
10
16
|
direction: number[];
|
|
17
|
+
/** Normalized camera up direction in WGS84 Cartesian coordinates. */
|
|
11
18
|
up: number[];
|
|
19
|
+
/** Camera position as `[longitude, latitude, height]`, with height in meters. */
|
|
20
|
+
cartographicPosition: [number, number, number];
|
|
21
|
+
/** Perspective vertical field of view in radians. */
|
|
22
|
+
verticalFieldOfView: number;
|
|
23
|
+
/** Elapsed seconds since camera position or direction last changed. */
|
|
24
|
+
timeSinceMovement: number;
|
|
12
25
|
};
|
|
13
26
|
viewport: GeospatialViewport;
|
|
14
27
|
topDownViewport: GeospatialViewport; // Use it to calculate projected radius for a tile
|
|
15
28
|
height: number;
|
|
16
29
|
cullingVolume: CullingVolume;
|
|
30
|
+
/** Optional world-space clipping planes applied to render-content culling. */
|
|
31
|
+
clippingPlanes?: Plane[];
|
|
17
32
|
frameNumber: number; // TODO: This can be the same between updates, what number is unique for between updates?
|
|
18
33
|
sseDenominator: number; // Assumes fovy = 60 degrees
|
|
34
|
+
/** View-dependent density used by perspective dynamic screen-space error for this traversal. */
|
|
35
|
+
dynamicScreenSpaceErrorDensity: number;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** Optional camera and projection measurements supplied when constructing a frame state. */
|
|
39
|
+
export type GetFrameStateOptions = {
|
|
40
|
+
/** Elapsed seconds since camera position or direction last changed. */
|
|
41
|
+
timeSinceCameraMovement?: number;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** Camera pose and timestamp retained between traversal frames. */
|
|
45
|
+
export type CameraMotionState = {
|
|
46
|
+
/** Last observed Earth-centered, Earth-fixed camera position. */
|
|
47
|
+
position: number[];
|
|
48
|
+
/** Last observed normalized Earth-centered, Earth-fixed camera direction. */
|
|
49
|
+
direction: number[];
|
|
50
|
+
/** Timestamp in milliseconds of the last observed pose change. */
|
|
51
|
+
lastMovementTime: number;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/** Updated camera state and elapsed stationary time for a traversal frame. */
|
|
55
|
+
export type CameraMotionUpdate = {
|
|
56
|
+
/** Camera pose to retain for the next traversal. */
|
|
57
|
+
state: CameraMotionState;
|
|
58
|
+
/** Elapsed seconds since the camera pose last changed. */
|
|
59
|
+
timeSinceMovement: number;
|
|
19
60
|
};
|
|
20
61
|
|
|
21
62
|
const scratchVector = new Vector3();
|
|
22
63
|
const scratchPosition = new Vector3();
|
|
64
|
+
const CAMERA_POSITION_EPSILON = 1e-5;
|
|
65
|
+
const CAMERA_DIRECTION_EPSILON = 1e-7;
|
|
23
66
|
const cullingVolume = new CullingVolume([
|
|
24
67
|
new Plane(),
|
|
25
68
|
new Plane(),
|
|
@@ -29,12 +72,26 @@ const cullingVolume = new CullingVolume([
|
|
|
29
72
|
new Plane()
|
|
30
73
|
]);
|
|
31
74
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Extracts a frame state appropriate for tile culling from a structural deck.gl viewport.
|
|
77
|
+
*
|
|
78
|
+
* `options.timeSinceCameraMovement` can be supplied by a caller that retains camera pose across
|
|
79
|
+
* calls. It defaults to a stationary camera so standalone callers do not defer requests.
|
|
80
|
+
*
|
|
81
|
+
* @param viewport - Geospatial viewport supplying camera and projection measurements.
|
|
82
|
+
* @param frameNumber - Current tileset traversal frame number.
|
|
83
|
+
* @param options - Additional camera and projection measurements for traversal.
|
|
84
|
+
* @returns Frame state used for visibility, SSE, and request-priority calculations.
|
|
85
|
+
*/
|
|
86
|
+
export function getFrameState(
|
|
87
|
+
viewport: GeospatialViewport,
|
|
88
|
+
frameNumber: number,
|
|
89
|
+
options: GetFrameStateOptions = {}
|
|
90
|
+
): FrameState {
|
|
35
91
|
// Traverse and and request. Update _selectedTiles so that we know what to render.
|
|
36
92
|
// Traverse and and request. Update _selectedTiles so that we know what to render.
|
|
37
|
-
const {
|
|
93
|
+
const {cameraUp, height} = viewport;
|
|
94
|
+
const cameraDirection = viewport.cameraDirection as number[] | undefined;
|
|
38
95
|
const {metersPerUnit} = viewport.distanceScales;
|
|
39
96
|
|
|
40
97
|
// TODO - Ellipsoid.eastNorthUpToFixedFrame() breaks on raw array, create a Vector.
|
|
@@ -49,10 +106,26 @@ export function getFrameState(viewport: GeospatialViewport, frameNumber: number)
|
|
|
49
106
|
);
|
|
50
107
|
|
|
51
108
|
// These should still be normalized as the transform has scale 1 (goes from meters to meters)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
109
|
+
let cameraDirectionCartesian: Vector3;
|
|
110
|
+
if (cameraDirection) {
|
|
111
|
+
cameraDirectionCartesian = new Vector3(
|
|
112
|
+
// @ts-ignore
|
|
113
|
+
enuToFixedTransform.transformAsVector(new Vector3(cameraDirection).scale(metersPerUnit))
|
|
114
|
+
).normalize();
|
|
115
|
+
} else {
|
|
116
|
+
// Concrete deck.gl viewports do not expose the legacy structural cameraDirection field.
|
|
117
|
+
// The near-plane center is on the view axis, so its world-space direction is equivalent and
|
|
118
|
+
// works for perspective foveation without coupling loaders.gl to deck.gl internals.
|
|
119
|
+
// getFrustumPlanes is required by traversal but omitted from the minimal structural Viewport
|
|
120
|
+
// type for compatibility with existing application-side declarations.
|
|
121
|
+
// @ts-expect-error Runtime geospatial viewports provide getFrustumPlanes.
|
|
122
|
+
const nearPlane = viewport.getFrustumPlanes().near;
|
|
123
|
+
const nearCenterCommon = closestPointOnPlane(nearPlane, viewport.cameraPosition);
|
|
124
|
+
const nearCenterCartesian = worldToCartesian(viewport, nearCenterCommon);
|
|
125
|
+
cameraDirectionCartesian = new Vector3(nearCenterCartesian)
|
|
126
|
+
.subtract(cameraPositionCartesian)
|
|
127
|
+
.normalize();
|
|
128
|
+
}
|
|
56
129
|
const cameraUpCartesian = new Vector3(
|
|
57
130
|
// @ts-ignore
|
|
58
131
|
enuToFixedTransform.transformAsVector(new Vector3(cameraUp).scale(metersPerUnit))
|
|
@@ -78,14 +151,72 @@ export function getFrameState(viewport: GeospatialViewport, frameNumber: number)
|
|
|
78
151
|
camera: {
|
|
79
152
|
position: cameraPositionCartesian,
|
|
80
153
|
direction: cameraDirectionCartesian,
|
|
81
|
-
up: cameraUpCartesian
|
|
154
|
+
up: cameraUpCartesian,
|
|
155
|
+
cartographicPosition: cameraPositionCartographic,
|
|
156
|
+
verticalFieldOfView:
|
|
157
|
+
Number.isFinite(viewport.fovy) && Number(viewport.fovy) > 0
|
|
158
|
+
? (Number(viewport.fovy) * Math.PI) / 180
|
|
159
|
+
: Math.PI / 3,
|
|
160
|
+
timeSinceMovement: options.timeSinceCameraMovement ?? Number.POSITIVE_INFINITY
|
|
82
161
|
},
|
|
83
162
|
viewport,
|
|
84
163
|
topDownViewport,
|
|
85
164
|
height,
|
|
86
165
|
cullingVolume,
|
|
166
|
+
clippingPlanes: viewport.clippingPlanes,
|
|
87
167
|
frameNumber, // TODO: This can be the same between updates, what number is unique for between updates?
|
|
88
|
-
sseDenominator: 1.15 // Assumes fovy = 60 degrees
|
|
168
|
+
sseDenominator: 1.15, // Assumes fovy = 60 degrees
|
|
169
|
+
// Tileset3D fills this immediately before traversal because it depends on the root volume.
|
|
170
|
+
dynamicScreenSpaceErrorDensity: 0
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Updates retained camera motion state and calculates how long the current pose has been stable.
|
|
176
|
+
*
|
|
177
|
+
* The first observation is treated as stationary so initial tileset loading is never delayed.
|
|
178
|
+
* Position and direction are both compared because orbiting in place changes request relevance
|
|
179
|
+
* without necessarily changing the viewport's camera position.
|
|
180
|
+
*
|
|
181
|
+
* @param previousState - Pose retained from the preceding traversal for this viewport.
|
|
182
|
+
* @param position - Current Earth-centered, Earth-fixed camera position.
|
|
183
|
+
* @param direction - Current normalized Earth-centered, Earth-fixed camera direction.
|
|
184
|
+
* @param currentTime - Current monotonic-enough wall-clock time in milliseconds.
|
|
185
|
+
* @returns Updated pose and elapsed stationary time.
|
|
186
|
+
*/
|
|
187
|
+
export function updateCameraMotionState(
|
|
188
|
+
previousState: CameraMotionState | undefined,
|
|
189
|
+
position: number[] | Vector3,
|
|
190
|
+
direction: number[] | Vector3,
|
|
191
|
+
currentTime: number
|
|
192
|
+
): CameraMotionUpdate {
|
|
193
|
+
const positionArray = Array.from(position);
|
|
194
|
+
const directionArray = Array.from(direction);
|
|
195
|
+
const positionChanged = previousState
|
|
196
|
+
? positionArray.length !== previousState.position.length ||
|
|
197
|
+
positionArray.some(
|
|
198
|
+
(value, index) => Math.abs(value - previousState.position[index]) > CAMERA_POSITION_EPSILON
|
|
199
|
+
)
|
|
200
|
+
: false;
|
|
201
|
+
const directionChanged = previousState
|
|
202
|
+
? directionArray.length !== previousState.direction.length ||
|
|
203
|
+
directionArray.some(
|
|
204
|
+
(value, index) =>
|
|
205
|
+
Math.abs(value - previousState.direction[index]) > CAMERA_DIRECTION_EPSILON
|
|
206
|
+
)
|
|
207
|
+
: false;
|
|
208
|
+
const lastMovementTime =
|
|
209
|
+
positionChanged || directionChanged
|
|
210
|
+
? currentTime
|
|
211
|
+
: (previousState?.lastMovementTime ?? Number.NEGATIVE_INFINITY);
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
state: {
|
|
215
|
+
position: positionArray,
|
|
216
|
+
direction: directionArray,
|
|
217
|
+
lastMovementTime
|
|
218
|
+
},
|
|
219
|
+
timeSinceMovement: Math.max((currentTime - lastMovementTime) / 1000, 0)
|
|
89
220
|
};
|
|
90
221
|
}
|
|
91
222
|
|
|
@@ -162,7 +293,7 @@ function commonSpacePlanesToWGS84(viewport) {
|
|
|
162
293
|
|
|
163
294
|
function closestPointOnPlane(
|
|
164
295
|
plane: {distance: number; normal: Vector3},
|
|
165
|
-
refPoint: [
|
|
296
|
+
refPoint: number[] | Vector3,
|
|
166
297
|
out: Vector3 = new Vector3()
|
|
167
298
|
): Vector3 {
|
|
168
299
|
const distanceToRef = plane.normal.dot(refPoint);
|
|
@@ -32,12 +32,25 @@ export function getLodStatus(tile: Tile3D, frameState: FrameState): 'DIG' | 'OUT
|
|
|
32
32
|
if (screenSize < 2) {
|
|
33
33
|
return 'OUT';
|
|
34
34
|
}
|
|
35
|
-
if (!tile.header.children
|
|
35
|
+
if (!tile.header.children) {
|
|
36
36
|
return 'DRAW';
|
|
37
|
-
} else if (tile.header.children) {
|
|
38
|
-
return 'DIG';
|
|
39
37
|
}
|
|
40
|
-
|
|
38
|
+
|
|
39
|
+
switch (tile.lodMetricType) {
|
|
40
|
+
case 'screenSpaceRelative': {
|
|
41
|
+
const viewportHeight = frameState.topDownViewport.height || 1;
|
|
42
|
+
return screenSize / viewportHeight <= tile.lodMetricValue ? 'DRAW' : 'DIG';
|
|
43
|
+
}
|
|
44
|
+
case 'distanceRangeFromDefaultCamera':
|
|
45
|
+
return tile.distanceToTile(frameState) >= tile.lodMetricValue ? 'DRAW' : 'DIG';
|
|
46
|
+
case 'maxScreenThresholdSQ': {
|
|
47
|
+
const diameterThreshold = Math.sqrt(tile.lodMetricValue / (Math.PI * 0.25));
|
|
48
|
+
return screenSize <= diameterThreshold ? 'DRAW' : 'DIG';
|
|
49
|
+
}
|
|
50
|
+
case 'maxScreenThreshold':
|
|
51
|
+
default:
|
|
52
|
+
return screenSize <= tile.lodMetricValue ? 'DRAW' : 'DIG';
|
|
53
|
+
}
|
|
41
54
|
}
|
|
42
55
|
|
|
43
56
|
/**
|
|
@@ -49,10 +62,11 @@ export function getLodStatus(tile: Tile3D, frameState: FrameState): 'DIG' | 'OUT
|
|
|
49
62
|
// eslint-disable-next-line max-statements
|
|
50
63
|
export function getProjectedRadius(tile: Tile3D, frameState: FrameState): number {
|
|
51
64
|
const {topDownViewport: viewport} = frameState;
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
65
|
+
const mbs = tile.header.i3sLodMbs || tile.header.mbs;
|
|
66
|
+
const mbsLat = mbs[1];
|
|
67
|
+
const mbsLon = mbs[0];
|
|
68
|
+
const mbsZ = mbs[2];
|
|
69
|
+
const mbsR = mbs[3];
|
|
56
70
|
const mbsCenterCartesian = [...tile.boundingVolume.center];
|
|
57
71
|
const cameraPositionCartographic = viewport.unprojectPosition(viewport.cameraPosition);
|
|
58
72
|
Ellipsoid.WGS84.cartographicToCartesian(cameraPositionCartographic, cameraPositionCartesian);
|