@loaders.gl/tiles 5.0.0-alpha.2 → 5.0.0-alpha.4
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 +1 -1
- package/dist/dist.dev.js +17325 -5650
- package/dist/dist.min.js +4 -1
- package/dist/index.cjs +1924 -178
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.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 +51 -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/raster-set.d.ts +10 -8
- package/dist/raster-set.d.ts.map +1 -1
- package/dist/raster-set.js +18 -1
- 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 +49 -1
- package/dist/tileset-3d/common/tile-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tile-3d.js +132 -64
- package/dist/tileset-3d/common/tile-3d.js.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.d.ts +25 -0
- package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.js +49 -7
- package/dist/tileset-3d/common/tileset-3d.js.map +1 -1
- package/dist/tileset-3d/common/tileset-source.d.ts +14 -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 +6 -1
- package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-traverser.js +11 -6
- package/dist/tileset-3d/common/tileset-traverser.js.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts +26 -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 +62 -18
- 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 +1 -7
- 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 +32 -55
- package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.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/helpers/bounding-volume.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/bounding-volume.js +3 -33
- package/dist/tileset-3d/helpers/bounding-volume.js.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.d.ts +3 -1
- package/dist/tileset-3d/helpers/frame-state.d.ts.map +1 -1
- package/dist/tileset-3d/helpers/frame-state.js +1 -0
- 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/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +12 -9
- package/src/index.ts +42 -1
- package/src/point-cloud/point-cloud-tileset.ts +66 -12
- package/src/point-cloud/types.ts +17 -0
- package/src/raster-set.ts +46 -11
- 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 +156 -69
- package/src/tileset-3d/common/tileset-3d.ts +77 -6
- package/src/tileset-3d/common/tileset-source.ts +15 -0
- package/src/tileset-3d/common/tileset-traverser.ts +11 -6
- package/src/tileset-3d/format-3d-tiles/implicit-tiling.ts +100 -22
- package/src/tileset-3d/format-3d-tiles/tiles-3d-source.ts +36 -56
- package/src/tileset-3d/format-i3s/i3s-source.ts +119 -18
- package/src/tileset-3d/helpers/bounding-volume.ts +3 -55
- package/src/tileset-3d/helpers/frame-state.ts +3 -0
- package/src/tileset-3d/helpers/i3s-lod.ts +22 -8
- package/src/types.ts +3 -0
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
I3SSource: () => I3SSource,
|
|
24
|
+
I3SSpatialTransformer: () => I3SSpatialTransformer,
|
|
24
25
|
ImageSet: () => ImageSet,
|
|
25
26
|
IndexedArchiveTilesetSource: () => IndexedArchiveTilesetSource,
|
|
26
27
|
LOD_METRIC_TYPE: () => LOD_METRIC_TYPE,
|
|
@@ -31,6 +32,7 @@ __export(index_exports, {
|
|
|
31
32
|
STRATEGY_NEVER: () => STRATEGY_NEVER,
|
|
32
33
|
STRATEGY_REPLACE: () => STRATEGY_REPLACE,
|
|
33
34
|
SharedTile2DHeader: () => SharedTile2DHeader,
|
|
35
|
+
SpatialCoordinateTransformer: () => SpatialCoordinateTransformer,
|
|
34
36
|
TILESET_TYPE: () => TILESET_TYPE,
|
|
35
37
|
TILE_CONTENT_STATE: () => TILE_CONTENT_STATE,
|
|
36
38
|
TILE_REFINEMENT: () => TILE_REFINEMENT,
|
|
@@ -41,13 +43,24 @@ __export(index_exports, {
|
|
|
41
43
|
Tileset3D: () => Tileset3D,
|
|
42
44
|
TilesetCache: () => TilesetCache,
|
|
43
45
|
TilesetTraverser: () => TilesetTraverser,
|
|
46
|
+
applyTilesetSpatialOptions: () => applyTilesetSpatialOptions,
|
|
44
47
|
calculateTransformProps: () => calculateTransformProps,
|
|
45
48
|
createBoundingVolume: () => createBoundingVolume,
|
|
46
49
|
createImplicitSubtreeReference: () => createImplicitSubtreeReference,
|
|
50
|
+
createTilesetSpatialReference: () => createTilesetSpatialReference,
|
|
51
|
+
get3DTilesSpatialReference: () => get3DTilesSpatialReference,
|
|
47
52
|
getFrameState: () => getFrameState,
|
|
53
|
+
getGeoidModel: () => getGeoidModel,
|
|
54
|
+
getI3SSpatialReference: () => getI3SSpatialReference,
|
|
48
55
|
getLodStatus: () => getLodStatus,
|
|
56
|
+
getSpatialCoordinateFrame: () => getSpatialCoordinateFrame,
|
|
49
57
|
isTileset3DSource: () => isTileset3DSource,
|
|
58
|
+
markTilesetSpatialReferenceTransformed: () => markTilesetSpatialReferenceTransformed,
|
|
50
59
|
materializeImplicitSubtree: () => materializeImplicitSubtree,
|
|
60
|
+
registerGeoidModel: () => registerGeoidModel,
|
|
61
|
+
registerGeoidModelFromPgm: () => registerGeoidModelFromPgm,
|
|
62
|
+
registerSpatialCrs: () => registerSpatialCrs,
|
|
63
|
+
registerSpatialDatumGrid: () => registerSpatialDatumGrid,
|
|
51
64
|
replaceImplicitUrlTemplate: () => replaceImplicitUrlTemplate
|
|
52
65
|
});
|
|
53
66
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -212,6 +225,232 @@ var RequestScheduler = class {
|
|
|
212
225
|
}
|
|
213
226
|
};
|
|
214
227
|
|
|
228
|
+
// ../loader-utils/src/lib/request-utils/request-cache.ts
|
|
229
|
+
var DEFAULT_MAX_ENTRIES = Number.POSITIVE_INFINITY;
|
|
230
|
+
var DEFAULT_MAX_BYTES = Number.POSITIVE_INFINITY;
|
|
231
|
+
var RequestCache = class {
|
|
232
|
+
/** Maximum number of settled entries retained by this cache. */
|
|
233
|
+
maxEntries;
|
|
234
|
+
/** Maximum estimated bytes retained by this cache. */
|
|
235
|
+
maxBytes;
|
|
236
|
+
getByteLength;
|
|
237
|
+
onRemove;
|
|
238
|
+
entries = /* @__PURE__ */ new Map();
|
|
239
|
+
retainedByteLength = 0;
|
|
240
|
+
/** Creates a request cache with optional entry and byte limits. */
|
|
241
|
+
constructor(props = {}) {
|
|
242
|
+
this.maxEntries = validateLimit(props.maxEntries, DEFAULT_MAX_ENTRIES, "maxEntries");
|
|
243
|
+
this.maxBytes = validateLimit(props.maxBytes, DEFAULT_MAX_BYTES, "maxBytes");
|
|
244
|
+
this.getByteLength = props.getByteLength || (() => 0);
|
|
245
|
+
this.onRemove = props.onRemove;
|
|
246
|
+
}
|
|
247
|
+
/** Number of pending and settled entries currently tracked. */
|
|
248
|
+
get size() {
|
|
249
|
+
return this.entries.size;
|
|
250
|
+
}
|
|
251
|
+
/** Number of requests that have not settled. */
|
|
252
|
+
get pendingSize() {
|
|
253
|
+
let pendingSize = 0;
|
|
254
|
+
for (const entry of this.entries.values()) {
|
|
255
|
+
pendingSize += entry.pending ? 1 : 0;
|
|
256
|
+
}
|
|
257
|
+
return pendingSize;
|
|
258
|
+
}
|
|
259
|
+
/** Estimated bytes retained by settled entries. */
|
|
260
|
+
get byteLength() {
|
|
261
|
+
return this.retainedByteLength;
|
|
262
|
+
}
|
|
263
|
+
/** Returns a cached request and updates its LRU position. */
|
|
264
|
+
get(key, signal) {
|
|
265
|
+
const entry = this.entries.get(key);
|
|
266
|
+
if (!entry) {
|
|
267
|
+
return void 0;
|
|
268
|
+
}
|
|
269
|
+
this.touch(key, entry);
|
|
270
|
+
return this.waitForEntry(key, entry, signal);
|
|
271
|
+
}
|
|
272
|
+
/** Returns whether a pending or settled entry exists without updating its LRU position. */
|
|
273
|
+
has(key) {
|
|
274
|
+
return this.entries.has(key);
|
|
275
|
+
}
|
|
276
|
+
/** Stores an already available value and returns it. */
|
|
277
|
+
set(key, value) {
|
|
278
|
+
this.removeEntry(key, "replace");
|
|
279
|
+
const byteLength = getValidByteLength(this.getByteLength(value));
|
|
280
|
+
const entry = {
|
|
281
|
+
promise: Promise.resolve(value),
|
|
282
|
+
pending: false,
|
|
283
|
+
waiterCount: 0,
|
|
284
|
+
byteLength
|
|
285
|
+
};
|
|
286
|
+
this.entries.set(key, entry);
|
|
287
|
+
this.retainedByteLength += byteLength;
|
|
288
|
+
this.trim();
|
|
289
|
+
return value;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Returns a cached value or starts one shared request.
|
|
293
|
+
*
|
|
294
|
+
* The loader receives a cache-owned abort signal. One caller aborting only rejects that caller;
|
|
295
|
+
* the shared request is cancelled when no waiters remain.
|
|
296
|
+
*/
|
|
297
|
+
getOrLoad(key, load, signal) {
|
|
298
|
+
const cached = this.get(key, signal);
|
|
299
|
+
if (cached) {
|
|
300
|
+
return cached;
|
|
301
|
+
}
|
|
302
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
303
|
+
return Promise.reject(createAbortError());
|
|
304
|
+
}
|
|
305
|
+
const controller = new AbortController();
|
|
306
|
+
let resolveRequest;
|
|
307
|
+
let rejectRequest;
|
|
308
|
+
const promise = new Promise((resolve2, reject) => {
|
|
309
|
+
resolveRequest = resolve2;
|
|
310
|
+
rejectRequest = reject;
|
|
311
|
+
});
|
|
312
|
+
const entry = {
|
|
313
|
+
promise,
|
|
314
|
+
controller,
|
|
315
|
+
pending: true,
|
|
316
|
+
waiterCount: 0,
|
|
317
|
+
byteLength: 0
|
|
318
|
+
};
|
|
319
|
+
this.entries.set(key, entry);
|
|
320
|
+
void entry.promise.then(
|
|
321
|
+
(value) => this.handleLoadedValue(key, entry, value),
|
|
322
|
+
() => this.handleLoadError(key, entry)
|
|
323
|
+
);
|
|
324
|
+
try {
|
|
325
|
+
void Promise.resolve(load(controller.signal)).then(resolveRequest, rejectRequest);
|
|
326
|
+
} catch (error) {
|
|
327
|
+
rejectRequest(error);
|
|
328
|
+
}
|
|
329
|
+
return this.waitForEntry(key, entry, signal);
|
|
330
|
+
}
|
|
331
|
+
/** Removes one cached or pending request. */
|
|
332
|
+
delete(key) {
|
|
333
|
+
return this.removeEntry(key, "delete");
|
|
334
|
+
}
|
|
335
|
+
/** Aborts pending requests and removes every entry. */
|
|
336
|
+
clear() {
|
|
337
|
+
for (const key of Array.from(this.entries.keys())) {
|
|
338
|
+
this.removeEntry(key, "clear");
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
handleLoadedValue(key, entry, value) {
|
|
342
|
+
if (this.entries.get(key) !== entry) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
entry.pending = false;
|
|
346
|
+
entry.controller = void 0;
|
|
347
|
+
try {
|
|
348
|
+
entry.byteLength = getValidByteLength(this.getByteLength(value));
|
|
349
|
+
} catch {
|
|
350
|
+
this.removeEntry(key, "error");
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
this.retainedByteLength += entry.byteLength;
|
|
354
|
+
this.trim();
|
|
355
|
+
}
|
|
356
|
+
handleLoadError(key, entry) {
|
|
357
|
+
var _a;
|
|
358
|
+
if (this.entries.get(key) === entry) {
|
|
359
|
+
this.removeEntry(key, ((_a = entry.controller) == null ? void 0 : _a.signal.aborted) ? "abort" : "error");
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
waitForEntry(key, entry, signal) {
|
|
363
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
364
|
+
return Promise.reject(createAbortError());
|
|
365
|
+
}
|
|
366
|
+
if (!entry.pending) {
|
|
367
|
+
return entry.promise;
|
|
368
|
+
}
|
|
369
|
+
entry.waiterCount++;
|
|
370
|
+
return new Promise((resolve2, reject) => {
|
|
371
|
+
let waiting = true;
|
|
372
|
+
const finishWaiting = () => {
|
|
373
|
+
if (!waiting) return;
|
|
374
|
+
waiting = false;
|
|
375
|
+
signal == null ? void 0 : signal.removeEventListener("abort", handleAbort);
|
|
376
|
+
entry.waiterCount--;
|
|
377
|
+
};
|
|
378
|
+
const handleAbort = () => {
|
|
379
|
+
if (!waiting) return;
|
|
380
|
+
finishWaiting();
|
|
381
|
+
reject(createAbortError());
|
|
382
|
+
if (entry.pending && entry.waiterCount === 0 && this.entries.get(key) === entry) {
|
|
383
|
+
this.removeEntry(key, "abort");
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
signal == null ? void 0 : signal.addEventListener("abort", handleAbort, { once: true });
|
|
387
|
+
void entry.promise.then(
|
|
388
|
+
(value) => {
|
|
389
|
+
if (!waiting) return;
|
|
390
|
+
finishWaiting();
|
|
391
|
+
resolve2(value);
|
|
392
|
+
},
|
|
393
|
+
(error) => {
|
|
394
|
+
if (!waiting) return;
|
|
395
|
+
finishWaiting();
|
|
396
|
+
reject(error);
|
|
397
|
+
}
|
|
398
|
+
);
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
touch(key, entry) {
|
|
402
|
+
this.entries.delete(key);
|
|
403
|
+
this.entries.set(key, entry);
|
|
404
|
+
}
|
|
405
|
+
trim() {
|
|
406
|
+
let settledEntryCount = this.entries.size - this.pendingSize;
|
|
407
|
+
if (settledEntryCount <= this.maxEntries && this.retainedByteLength <= this.maxBytes) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
for (const [key, entry] of this.entries) {
|
|
411
|
+
if (!entry.pending) {
|
|
412
|
+
this.removeEntry(key, "evict");
|
|
413
|
+
settledEntryCount--;
|
|
414
|
+
}
|
|
415
|
+
if (settledEntryCount <= this.maxEntries && this.retainedByteLength <= this.maxBytes) {
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
removeEntry(key, reason) {
|
|
421
|
+
var _a, _b;
|
|
422
|
+
const entry = this.entries.get(key);
|
|
423
|
+
if (!entry) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
this.entries.delete(key);
|
|
427
|
+
this.retainedByteLength -= entry.byteLength;
|
|
428
|
+
if (entry.pending) {
|
|
429
|
+
(_a = entry.controller) == null ? void 0 : _a.abort();
|
|
430
|
+
}
|
|
431
|
+
(_b = this.onRemove) == null ? void 0 : _b.call(this, key, reason);
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
function createAbortError() {
|
|
436
|
+
const error = new Error("Request aborted");
|
|
437
|
+
error.name = "AbortError";
|
|
438
|
+
return error;
|
|
439
|
+
}
|
|
440
|
+
function validateLimit(value, fallback, name) {
|
|
441
|
+
const limit = value ?? fallback;
|
|
442
|
+
if (limit < 0 || Number.isNaN(limit)) {
|
|
443
|
+
throw new Error(`${name} must be a non-negative number`);
|
|
444
|
+
}
|
|
445
|
+
return limit;
|
|
446
|
+
}
|
|
447
|
+
function getValidByteLength(value) {
|
|
448
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
449
|
+
throw new Error("Request cache entry byte length must be a non-negative finite number");
|
|
450
|
+
}
|
|
451
|
+
return value;
|
|
452
|
+
}
|
|
453
|
+
|
|
215
454
|
// ../loader-utils/src/lib/request-utils/range-request-scheduler.ts
|
|
216
455
|
var import_stats2 = require("@probe.gl/stats");
|
|
217
456
|
var RANGE_STATS_KEYS = {
|
|
@@ -269,7 +508,7 @@ var RangeRequestScheduler = class {
|
|
|
269
508
|
return Promise.reject(new Error("Byte range length cannot be negative"));
|
|
270
509
|
}
|
|
271
510
|
if ((_a = request.signal) == null ? void 0 : _a.aborted) {
|
|
272
|
-
return Promise.reject(
|
|
511
|
+
return Promise.reject(createAbortError2());
|
|
273
512
|
}
|
|
274
513
|
if (request.length === 0) {
|
|
275
514
|
return Promise.resolve(new ArrayBuffer(0));
|
|
@@ -484,7 +723,7 @@ var RangeRequestScheduler = class {
|
|
|
484
723
|
return;
|
|
485
724
|
}
|
|
486
725
|
request.settled = true;
|
|
487
|
-
request.reject(
|
|
726
|
+
request.reject(createAbortError2());
|
|
488
727
|
this.trackEvent({
|
|
489
728
|
type: "abort",
|
|
490
729
|
sourceId: request.sourceId,
|
|
@@ -714,7 +953,7 @@ function getTimestamp() {
|
|
|
714
953
|
var _a;
|
|
715
954
|
return ((_a = globalThis.performance) == null ? void 0 : _a.now()) ?? Date.now();
|
|
716
955
|
}
|
|
717
|
-
function
|
|
956
|
+
function createAbortError2() {
|
|
718
957
|
if (typeof DOMException !== "undefined") {
|
|
719
958
|
return new DOMException("Request aborted", "AbortError");
|
|
720
959
|
}
|
|
@@ -1216,7 +1455,7 @@ var HttpFile = class _HttpFile {
|
|
|
1216
1455
|
async open(signal) {
|
|
1217
1456
|
this.assertOpen();
|
|
1218
1457
|
if (signal == null ? void 0 : signal.aborted) {
|
|
1219
|
-
const error =
|
|
1458
|
+
const error = createAbortError3();
|
|
1220
1459
|
this.transport.trackFailure(error);
|
|
1221
1460
|
throw error;
|
|
1222
1461
|
}
|
|
@@ -1258,7 +1497,7 @@ var HttpFile = class _HttpFile {
|
|
|
1258
1497
|
async read(offset = 0, length = 0, signal) {
|
|
1259
1498
|
this.assertOpen();
|
|
1260
1499
|
if (signal == null ? void 0 : signal.aborted) {
|
|
1261
|
-
const error =
|
|
1500
|
+
const error = createAbortError3();
|
|
1262
1501
|
this.transport.trackFailure(error);
|
|
1263
1502
|
throw error;
|
|
1264
1503
|
}
|
|
@@ -1366,7 +1605,7 @@ function validateRange(offset, length, byteLength) {
|
|
|
1366
1605
|
throw new Error("HTTP byte range extends beyond the end of the file");
|
|
1367
1606
|
}
|
|
1368
1607
|
}
|
|
1369
|
-
function
|
|
1608
|
+
function createAbortError3() {
|
|
1370
1609
|
if (typeof DOMException !== "undefined") {
|
|
1371
1610
|
return new DOMException("Request aborted", "AbortError");
|
|
1372
1611
|
}
|
|
@@ -1379,12 +1618,12 @@ function waitForPromiseWithSignal(promise, signal) {
|
|
|
1379
1618
|
return promise;
|
|
1380
1619
|
}
|
|
1381
1620
|
if (signal.aborted) {
|
|
1382
|
-
return Promise.reject(
|
|
1621
|
+
return Promise.reject(createAbortError3());
|
|
1383
1622
|
}
|
|
1384
1623
|
return new Promise((resolve2, reject) => {
|
|
1385
1624
|
const abortListener = () => {
|
|
1386
1625
|
signal.removeEventListener("abort", abortListener);
|
|
1387
|
-
reject(
|
|
1626
|
+
reject(createAbortError3());
|
|
1388
1627
|
};
|
|
1389
1628
|
signal.addEventListener("abort", abortListener, { once: true });
|
|
1390
1629
|
promise.then(
|
|
@@ -1684,6 +1923,7 @@ function getFrameState(viewport, frameNumber, options = {}) {
|
|
|
1684
1923
|
topDownViewport,
|
|
1685
1924
|
height,
|
|
1686
1925
|
cullingVolume,
|
|
1926
|
+
clippingPlanes: viewport.clippingPlanes,
|
|
1687
1927
|
frameNumber,
|
|
1688
1928
|
// TODO: This can be the same between updates, what number is unique for between updates?
|
|
1689
1929
|
sseDenominator: 1.15,
|
|
@@ -2024,6 +2264,177 @@ function calculateTileRequestPriority(parameters) {
|
|
|
2024
2264
|
return progressiveResolutionDigits + foveatedSortingDigits + preferredSortingDigits;
|
|
2025
2265
|
}
|
|
2026
2266
|
|
|
2267
|
+
// dist/spatial/spatial-types.js
|
|
2268
|
+
var import_crs = require("@math.gl/crs");
|
|
2269
|
+
|
|
2270
|
+
// dist/spatial/get-spatial-coordinate-frame.js
|
|
2271
|
+
var GEOGRAPHIC_CRS = "EPSG:4326";
|
|
2272
|
+
var GEOCENTRIC_CRS = "EPSG:4978";
|
|
2273
|
+
function normalizeCrsIdentifier(identifier) {
|
|
2274
|
+
const normalizedIdentifier = identifier.trim().toUpperCase();
|
|
2275
|
+
const ogcMatch = normalizedIdentifier.match(/(?:\/DEF\/CRS\/|URN:OGC:DEF:CRS:)([A-Z0-9_-]+)(?:\/|::)(?:[^/:]*[/:])?([A-Z0-9_.-]+)$/);
|
|
2276
|
+
return ogcMatch ? `${ogcMatch[1]}:${ogcMatch[2]}` : normalizedIdentifier;
|
|
2277
|
+
}
|
|
2278
|
+
function getSpatialCoordinateFrame(definition) {
|
|
2279
|
+
var _a, _b;
|
|
2280
|
+
if (typeof definition === "string") {
|
|
2281
|
+
const normalized = normalizeCrsIdentifier(definition);
|
|
2282
|
+
if (normalized === GEOCENTRIC_CRS || /^GEOCCS\s*[\[(]/.test(normalized)) {
|
|
2283
|
+
return "geocentric";
|
|
2284
|
+
}
|
|
2285
|
+
if (normalized === GEOGRAPHIC_CRS || normalized === "EPSG:4490" || normalized === "EPSG:4979" || normalized === "OGC:CRS84" || normalized.includes("+PROJ=LONGLAT") || normalized.includes("+PROJ=LATLONG") || /^(?:GEOGCS|GEOGCRS|GEOGRAPHICCRS|GEOGRAPHIC2DCRS|GEOGRAPHIC3DCRS)\s*[\[(]/.test(normalized)) {
|
|
2286
|
+
return "geographic";
|
|
2287
|
+
}
|
|
2288
|
+
if (/^(?:GEODCRS|GEODETICCRS)\s*[\[(]/.test(normalized)) {
|
|
2289
|
+
return /CS\s*[\[(]\s*CARTESIAN/.test(normalized) ? "geocentric" : "geographic";
|
|
2290
|
+
}
|
|
2291
|
+
return "projected";
|
|
2292
|
+
}
|
|
2293
|
+
const projJsonDefinition = definition;
|
|
2294
|
+
if (projJsonDefinition.type === "BoundCRS" && projJsonDefinition.source_crs) {
|
|
2295
|
+
return getSpatialCoordinateFrame(projJsonDefinition.source_crs);
|
|
2296
|
+
}
|
|
2297
|
+
if (projJsonDefinition.type === "CompoundCRS" && ((_a = projJsonDefinition.components) == null ? void 0 : _a[0])) {
|
|
2298
|
+
return getSpatialCoordinateFrame(projJsonDefinition.components[0]);
|
|
2299
|
+
}
|
|
2300
|
+
if (String(projJsonDefinition.type).includes("Projected")) {
|
|
2301
|
+
return "projected";
|
|
2302
|
+
}
|
|
2303
|
+
if (String(projJsonDefinition.type).includes("Geographic")) {
|
|
2304
|
+
return "geographic";
|
|
2305
|
+
}
|
|
2306
|
+
if (String(projJsonDefinition.type).includes("Geodetic")) {
|
|
2307
|
+
return ((_b = projJsonDefinition.coordinate_system) == null ? void 0 : _b.subtype) === "Cartesian" ? "geocentric" : "geographic";
|
|
2308
|
+
}
|
|
2309
|
+
return "projected";
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2312
|
+
// dist/spatial/spatial-types.js
|
|
2313
|
+
function createTilesetSpatialReference(discovered, options = {}) {
|
|
2314
|
+
const hasSourceCrsOverride = options.sourceCrs !== void 0;
|
|
2315
|
+
const sourceCrs = options.sourceCrs || discovered.sourceCrs;
|
|
2316
|
+
const outputCoordinates = options.outputCoordinates || "auto";
|
|
2317
|
+
const targetCrs = options.targetCrs || (outputCoordinates === "ecef" ? "EPSG:4978" : void 0);
|
|
2318
|
+
const targetHeightReference = options.targetHeightReference || "native";
|
|
2319
|
+
const verticalUnitScale = discovered.verticalUnitScale ?? 1;
|
|
2320
|
+
const elevationUnitScale = discovered.elevationUnitScale ?? 1;
|
|
2321
|
+
const elevationOffset = discovered.elevationOffset || 0;
|
|
2322
|
+
const requiresSurface = discovered.elevationMode === "onTheGround" || discovered.elevationMode === "relativeToGround" || discovered.elevationMode === "relativeToScene";
|
|
2323
|
+
const hasElevationProvider = discovered.elevationMode === "relativeToScene" ? Boolean(options.sceneElevationProvider) : !requiresSurface || Boolean(options.terrainElevationProvider);
|
|
2324
|
+
const hasFormatVerticalOperation = verticalUnitScale !== 1 || elevationUnitScale !== 1 || discovered.elevationMode !== void 0 && (requiresSurface || discovered.elevationMode === "absoluteHeight" && elevationOffset !== 0);
|
|
2325
|
+
const needsHeightTransform = targetHeightReference !== "native" && targetHeightReference !== discovered.heightReference;
|
|
2326
|
+
const hasRequestedTransform = Boolean(targetCrs) || targetHeightReference !== "native" || outputCoordinates !== "auto" || hasFormatVerticalOperation;
|
|
2327
|
+
const hasRequiredTarget = outputCoordinates !== "target-crs" || Boolean(targetCrs);
|
|
2328
|
+
const hasHeightMetadata = !needsHeightTransform || (discovered.heightReference || "unknown") !== "unknown";
|
|
2329
|
+
const hasVerticalUnits = Number.isFinite(verticalUnitScale) && verticalUnitScale > 0 && Number.isFinite(elevationUnitScale) && elevationUnitScale > 0;
|
|
2330
|
+
const canTransform = Boolean(sourceCrs) && hasRequestedTransform && hasRequiredTarget && hasHeightMetadata && hasVerticalUnits && hasElevationProvider && outputCoordinates !== "local-enu";
|
|
2331
|
+
const provenance = hasSourceCrsOverride ? "caller-override" : discovered.provenance || "unknown";
|
|
2332
|
+
const coordinateFrame = hasSourceCrsOverride && sourceCrs ? getSpatialCoordinateFrame(sourceCrs) : discovered.coordinateFrame;
|
|
2333
|
+
const sourceCrsState = hasSourceCrsOverride ? "explicit" : discovered.sourceCrsState || (sourceCrs ? provenance === "format-default" ? "default" : "explicit" : "absent");
|
|
2334
|
+
const spatialReference = (0, import_crs.createSpatialReference)({
|
|
2335
|
+
crs: sourceCrs ? {
|
|
2336
|
+
state: sourceCrsState === "default" ? "default" : "explicit",
|
|
2337
|
+
definition: sourceCrs,
|
|
2338
|
+
representation: !hasSourceCrsOverride && discovered.sourceCrsRepresentation || (0, import_crs.inferCRSRepresentation)(sourceCrs),
|
|
2339
|
+
provenance,
|
|
2340
|
+
alternatives: hasSourceCrsOverride ? void 0 : discovered.sourceCrsAlternatives
|
|
2341
|
+
} : {
|
|
2342
|
+
state: sourceCrsState === "unknown" ? "unknown" : "absent",
|
|
2343
|
+
provenance
|
|
2344
|
+
},
|
|
2345
|
+
vertical: discovered.verticalCrs ? {
|
|
2346
|
+
state: "explicit",
|
|
2347
|
+
definition: discovered.verticalCrs,
|
|
2348
|
+
representation: (0, import_crs.inferCRSRepresentation)(discovered.verticalCrs),
|
|
2349
|
+
provenance: discovered.provenance || "metadata"
|
|
2350
|
+
} : void 0,
|
|
2351
|
+
coordinateEpoch: options.coordinateEpoch ?? discovered.coordinateEpoch,
|
|
2352
|
+
coordinateFrame,
|
|
2353
|
+
coordinateOrder: getCoordinateOrder(discovered.axisOrder),
|
|
2354
|
+
units: hasSourceCrsOverride ? void 0 : discovered.units
|
|
2355
|
+
});
|
|
2356
|
+
const normalizedSourceCrs = getKnownCRSDefinition(spatialReference.crs);
|
|
2357
|
+
const normalizedVerticalCrs = spatialReference.vertical ? getKnownCRSDefinition(spatialReference.vertical) : void 0;
|
|
2358
|
+
const normalizedTargetCrs = targetCrs ? cloneReadonlyCRSDefinition(targetCrs) : void 0;
|
|
2359
|
+
return Object.freeze({
|
|
2360
|
+
...spatialReference,
|
|
2361
|
+
sourceCrs: normalizedSourceCrs,
|
|
2362
|
+
verticalCrs: normalizedVerticalCrs,
|
|
2363
|
+
verticalUnitScale,
|
|
2364
|
+
coordinateEpoch: options.coordinateEpoch ?? discovered.coordinateEpoch,
|
|
2365
|
+
heightReference: discovered.heightReference || "unknown",
|
|
2366
|
+
elevationMode: discovered.elevationMode,
|
|
2367
|
+
elevationOffset: discovered.elevationOffset,
|
|
2368
|
+
elevationUnit: discovered.elevationUnit,
|
|
2369
|
+
elevationUnitScale,
|
|
2370
|
+
coordinateFrame: coordinateFrame || "unknown",
|
|
2371
|
+
axisOrder: discovered.axisOrder || "unknown",
|
|
2372
|
+
provenance,
|
|
2373
|
+
targetCrs: normalizedTargetCrs,
|
|
2374
|
+
targetHeightReference,
|
|
2375
|
+
outputCoordinates,
|
|
2376
|
+
status: hasRequestedTransform ? canTransform ? "transformable" : "unresolved" : "native",
|
|
2377
|
+
warnings: Object.freeze([...discovered.warnings || []])
|
|
2378
|
+
});
|
|
2379
|
+
}
|
|
2380
|
+
function applyTilesetSpatialOptions(discovered, options = {}) {
|
|
2381
|
+
return createTilesetSpatialReference({
|
|
2382
|
+
sourceCrs: discovered == null ? void 0 : discovered.sourceCrs,
|
|
2383
|
+
sourceCrsState: discovered == null ? void 0 : discovered.crs.state,
|
|
2384
|
+
sourceCrsRepresentation: (discovered == null ? void 0 : discovered.crs.state) === "explicit" || (discovered == null ? void 0 : discovered.crs.state) === "default" ? discovered.crs.representation : void 0,
|
|
2385
|
+
sourceCrsAlternatives: (discovered == null ? void 0 : discovered.crs.state) === "explicit" || (discovered == null ? void 0 : discovered.crs.state) === "default" ? discovered.crs.alternatives : void 0,
|
|
2386
|
+
verticalCrs: discovered == null ? void 0 : discovered.verticalCrs,
|
|
2387
|
+
units: discovered == null ? void 0 : discovered.units,
|
|
2388
|
+
verticalUnitScale: discovered == null ? void 0 : discovered.verticalUnitScale,
|
|
2389
|
+
coordinateEpoch: discovered == null ? void 0 : discovered.coordinateEpoch,
|
|
2390
|
+
heightReference: discovered == null ? void 0 : discovered.heightReference,
|
|
2391
|
+
elevationMode: discovered == null ? void 0 : discovered.elevationMode,
|
|
2392
|
+
elevationOffset: discovered == null ? void 0 : discovered.elevationOffset,
|
|
2393
|
+
elevationUnit: discovered == null ? void 0 : discovered.elevationUnit,
|
|
2394
|
+
elevationUnitScale: discovered == null ? void 0 : discovered.elevationUnitScale,
|
|
2395
|
+
coordinateFrame: discovered == null ? void 0 : discovered.coordinateFrame,
|
|
2396
|
+
axisOrder: discovered == null ? void 0 : discovered.axisOrder,
|
|
2397
|
+
provenance: discovered == null ? void 0 : discovered.provenance,
|
|
2398
|
+
warnings: discovered == null ? void 0 : discovered.warnings
|
|
2399
|
+
}, options);
|
|
2400
|
+
}
|
|
2401
|
+
function getKnownCRSDefinition(reference) {
|
|
2402
|
+
return reference.state === "explicit" || reference.state === "default" ? reference.definition : void 0;
|
|
2403
|
+
}
|
|
2404
|
+
function cloneReadonlyCRSDefinition(definition) {
|
|
2405
|
+
const spatialReference = (0, import_crs.createSpatialReference)({
|
|
2406
|
+
crs: {
|
|
2407
|
+
state: "explicit",
|
|
2408
|
+
definition,
|
|
2409
|
+
representation: (0, import_crs.inferCRSRepresentation)(definition),
|
|
2410
|
+
provenance: "caller-override"
|
|
2411
|
+
}
|
|
2412
|
+
});
|
|
2413
|
+
const clonedDefinition = getKnownCRSDefinition(spatialReference.crs);
|
|
2414
|
+
if (!clonedDefinition) {
|
|
2415
|
+
throw new Error("Failed to normalize a known target CRS definition");
|
|
2416
|
+
}
|
|
2417
|
+
return clonedDefinition;
|
|
2418
|
+
}
|
|
2419
|
+
function getCoordinateOrder(axisOrder) {
|
|
2420
|
+
switch (axisOrder) {
|
|
2421
|
+
case "xy":
|
|
2422
|
+
return ["x", "y"];
|
|
2423
|
+
case "yx":
|
|
2424
|
+
return ["y", "x"];
|
|
2425
|
+
case "xyz":
|
|
2426
|
+
return ["x", "y", "z"];
|
|
2427
|
+
default:
|
|
2428
|
+
return [];
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2431
|
+
function markTilesetSpatialReferenceTransformed(spatialReference) {
|
|
2432
|
+
if (spatialReference.status !== "transformable" && spatialReference.status !== "transformed") {
|
|
2433
|
+
throw new Error("Only a transformable spatial reference can be marked as transformed");
|
|
2434
|
+
}
|
|
2435
|
+
return Object.freeze({ ...spatialReference, status: "transformed" });
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2027
2438
|
// dist/tileset-3d/common/tileset-source.js
|
|
2028
2439
|
function isTileset3DSource(value) {
|
|
2029
2440
|
return Boolean(value && typeof value === "object" && "initialize" in value && "getRootTileset" in value && "initializeTileHeaders" in value && "loadTileContent" in value);
|
|
@@ -2083,6 +2494,7 @@ var DEFAULT_PROPS3 = {
|
|
|
2083
2494
|
foveatedInterpolationCallback: interpolateLinearly,
|
|
2084
2495
|
foveatedTimeDelay: 0.2,
|
|
2085
2496
|
maximumScreenSpaceError: 8,
|
|
2497
|
+
skipLevelOfDetail: false,
|
|
2086
2498
|
dynamicScreenSpaceError: true,
|
|
2087
2499
|
dynamicScreenSpaceErrorDensity: 2e-4,
|
|
2088
2500
|
dynamicScreenSpaceErrorFactor: 24,
|
|
@@ -2094,7 +2506,8 @@ var DEFAULT_PROPS3 = {
|
|
|
2094
2506
|
loadOptions: { fetch: {} },
|
|
2095
2507
|
attributions: [],
|
|
2096
2508
|
basePath: "",
|
|
2097
|
-
i3s: {}
|
|
2509
|
+
i3s: {},
|
|
2510
|
+
spatial: {}
|
|
2098
2511
|
};
|
|
2099
2512
|
var TILES_TOTAL = "Tiles In Tileset(s)";
|
|
2100
2513
|
var TILES_IN_MEMORY = "Tiles In Memory";
|
|
@@ -2125,6 +2538,18 @@ var Tileset3D = class {
|
|
|
2125
2538
|
root = null;
|
|
2126
2539
|
roots = {};
|
|
2127
2540
|
asset = {};
|
|
2541
|
+
/** Inline metadata schema declared by the source tileset, when present. */
|
|
2542
|
+
schema = null;
|
|
2543
|
+
/** External metadata schema URI declared by the source tileset, when present. */
|
|
2544
|
+
schemaUri = null;
|
|
2545
|
+
/** Metadata groups declared by the source tileset, in source order. */
|
|
2546
|
+
groups = [];
|
|
2547
|
+
/** Tileset-wide metadata entity, preserved without property-table decoding. */
|
|
2548
|
+
metadata = null;
|
|
2549
|
+
/** Tileset statistics metadata, preserved for application-level inspection. */
|
|
2550
|
+
statistics = null;
|
|
2551
|
+
/** Normalized source and target coordinate reference system metadata. */
|
|
2552
|
+
spatialReference = createTilesetSpatialReference({});
|
|
2128
2553
|
description = "";
|
|
2129
2554
|
properties;
|
|
2130
2555
|
extras = null;
|
|
@@ -2209,6 +2634,10 @@ var Tileset3D = class {
|
|
|
2209
2634
|
this.memoryAdjustedScreenSpaceError = this.options.maximumScreenSpaceError;
|
|
2210
2635
|
this._cacheBytes = cacheBytes;
|
|
2211
2636
|
this._maximumCacheOverflowBytes = maximumCacheOverflowBytes;
|
|
2637
|
+
const metadata = this._getSourceMetadata();
|
|
2638
|
+
if (metadata) {
|
|
2639
|
+
this.spatialReference = applyTilesetSpatialOptions(metadata.spatialReference, this.options.spatial);
|
|
2640
|
+
}
|
|
2212
2641
|
this.stats = new import_stats3.Stats({ id: this.url });
|
|
2213
2642
|
this._initializeStats();
|
|
2214
2643
|
this.tilesetInitializationPromise = this._initializeTileSet();
|
|
@@ -2527,10 +2956,13 @@ var Tileset3D = class {
|
|
|
2527
2956
|
for (const tile of this.selectedTiles) {
|
|
2528
2957
|
if (tile.contentAvailable && tile.content) {
|
|
2529
2958
|
tilesRenderable++;
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2959
|
+
const contents = tile.contents.length ? tile.contents : [tile.content];
|
|
2960
|
+
for (const content of contents) {
|
|
2961
|
+
if (content.pointCount) {
|
|
2962
|
+
pointsRenderable += content.pointCount;
|
|
2963
|
+
} else {
|
|
2964
|
+
pointsRenderable += content.vertexCount || 0;
|
|
2965
|
+
}
|
|
2534
2966
|
}
|
|
2535
2967
|
}
|
|
2536
2968
|
}
|
|
@@ -2540,20 +2972,21 @@ var Tileset3D = class {
|
|
|
2540
2972
|
this.stats.get(MAXIMUM_SSE).count = this.memoryAdjustedScreenSpaceError;
|
|
2541
2973
|
}
|
|
2542
2974
|
async _initializeTileSet() {
|
|
2543
|
-
var _a;
|
|
2975
|
+
var _a, _b, _c;
|
|
2544
2976
|
try {
|
|
2545
2977
|
const initializePromise = this.source.initialize();
|
|
2546
2978
|
const initialMetadata = this._getSourceMetadata();
|
|
2547
2979
|
if (initialMetadata) {
|
|
2548
2980
|
this._syncSourceState(initialMetadata);
|
|
2549
2981
|
}
|
|
2550
|
-
if (((_a = initialMetadata == null ? void 0 : initialMetadata.tileset) == null ? void 0 : _a.root) && typeof initialMetadata.tileset.root.then !== "function") {
|
|
2982
|
+
if (((_a = initialMetadata == null ? void 0 : initialMetadata.tileset) == null ? void 0 : _a.root) && typeof initialMetadata.tileset.root.then !== "function" && !this.source.prepareTileset) {
|
|
2551
2983
|
this.root = this._initializeTileHeaders(initialMetadata.tileset, null);
|
|
2552
2984
|
this._applyViewState();
|
|
2553
2985
|
}
|
|
2554
2986
|
await initializePromise;
|
|
2555
2987
|
const metadata = this.source.getMetadata();
|
|
2556
2988
|
this._syncSourceState(metadata);
|
|
2989
|
+
await ((_c = (_b = this.source).prepareTileset) == null ? void 0 : _c.call(_b, this));
|
|
2557
2990
|
if (!this.root) {
|
|
2558
2991
|
this.root = this._initializeTileHeaders(metadata.tileset, null);
|
|
2559
2992
|
}
|
|
@@ -2729,6 +3162,14 @@ var Tileset3D = class {
|
|
|
2729
3162
|
this.refine = metadata.refine;
|
|
2730
3163
|
this.contentFormats = this.source.contentFormats;
|
|
2731
3164
|
this.asset = this.source.asset || this.asset;
|
|
3165
|
+
const tileset = metadata.tileset;
|
|
3166
|
+
this.schema = tileset.schema || null;
|
|
3167
|
+
this.schemaUri = tileset.schemaUri || null;
|
|
3168
|
+
this.groups = tileset.groups || [];
|
|
3169
|
+
this.metadata = tileset.metadata || null;
|
|
3170
|
+
this.statistics = tileset.statistics ?? null;
|
|
3171
|
+
const spatialReference = applyTilesetSpatialOptions(metadata.spatialReference, this.options.spatial);
|
|
3172
|
+
this.spatialReference = preserveTransformedSpatialReference(this.spatialReference, spatialReference);
|
|
2732
3173
|
this.properties = this.source.properties ?? this.properties;
|
|
2733
3174
|
this.extras = this.source.extras ?? this.extras;
|
|
2734
3175
|
if ((_a = this.options.attributions) == null ? void 0 : _a.length) {
|
|
@@ -2762,6 +3203,9 @@ var Tileset3D = class {
|
|
|
2762
3203
|
}
|
|
2763
3204
|
}
|
|
2764
3205
|
};
|
|
3206
|
+
function preserveTransformedSpatialReference(current, next) {
|
|
3207
|
+
return (current == null ? void 0 : current.status) === "transformed" && current.sourceCrs === next.sourceCrs && current.targetCrs === next.targetCrs && current.targetHeightReference === next.targetHeightReference && current.outputCoordinates === next.outputCoordinates ? current : next;
|
|
3208
|
+
}
|
|
2765
3209
|
|
|
2766
3210
|
// dist/tileset-3d/common/indexed-archive-tileset-source.js
|
|
2767
3211
|
var IndexedArchiveTilesetSource = class {
|
|
@@ -2888,19 +3332,13 @@ function defined(x) {
|
|
|
2888
3332
|
}
|
|
2889
3333
|
var scratchPoint = new import_core6.Vector3();
|
|
2890
3334
|
var scratchScale = new import_core6.Vector3();
|
|
2891
|
-
var scratchNorthWest = new import_core6.Vector3();
|
|
2892
|
-
var scratchSouthEast = new import_core6.Vector3();
|
|
2893
|
-
var scratchCenter2 = new import_core6.Vector3();
|
|
2894
|
-
var scratchXAxis = new import_core6.Vector3();
|
|
2895
|
-
var scratchYAxis = new import_core6.Vector3();
|
|
2896
|
-
var scratchZAxis = new import_core6.Vector3();
|
|
2897
3335
|
function createBoundingVolume(boundingVolumeHeader, transform, result) {
|
|
2898
3336
|
assert(boundingVolumeHeader, "3D Tile: boundingVolume must be defined");
|
|
2899
3337
|
if (boundingVolumeHeader.box) {
|
|
2900
3338
|
return createBox(boundingVolumeHeader.box, transform, result);
|
|
2901
3339
|
}
|
|
2902
3340
|
if (boundingVolumeHeader.region) {
|
|
2903
|
-
return
|
|
3341
|
+
return (0, import_geospatial4.makeOBBFromRegion)(boundingVolumeHeader.region);
|
|
2904
3342
|
}
|
|
2905
3343
|
if (boundingVolumeHeader.sphere) {
|
|
2906
3344
|
return createSphere(boundingVolumeHeader.sphere, transform, result);
|
|
@@ -2978,22 +3416,6 @@ function createSphere(sphere, transform, result) {
|
|
|
2978
3416
|
}
|
|
2979
3417
|
return new import_culling3.BoundingSphere(center, radius);
|
|
2980
3418
|
}
|
|
2981
|
-
function createObbFromRegion(region) {
|
|
2982
|
-
const [west, south, east, north, minHeight, maxHeight] = region;
|
|
2983
|
-
const northWest = import_geospatial4.Ellipsoid.WGS84.cartographicToCartesian([(0, import_core6.degrees)(west), (0, import_core6.degrees)(north), minHeight], scratchNorthWest);
|
|
2984
|
-
const southEast = import_geospatial4.Ellipsoid.WGS84.cartographicToCartesian([(0, import_core6.degrees)(east), (0, import_core6.degrees)(south), maxHeight], scratchSouthEast);
|
|
2985
|
-
const centerInCartesian = new import_core6.Vector3().addVectors(northWest, southEast).multiplyByScalar(0.5);
|
|
2986
|
-
import_geospatial4.Ellipsoid.WGS84.cartesianToCartographic(centerInCartesian, scratchCenter2);
|
|
2987
|
-
import_geospatial4.Ellipsoid.WGS84.cartographicToCartesian([(0, import_core6.degrees)(east), scratchCenter2[1], scratchCenter2[2]], scratchXAxis);
|
|
2988
|
-
import_geospatial4.Ellipsoid.WGS84.cartographicToCartesian([scratchCenter2[0], (0, import_core6.degrees)(north), scratchCenter2[2]], scratchYAxis);
|
|
2989
|
-
import_geospatial4.Ellipsoid.WGS84.cartographicToCartesian([scratchCenter2[0], scratchCenter2[1], maxHeight], scratchZAxis);
|
|
2990
|
-
return createBox([
|
|
2991
|
-
...centerInCartesian,
|
|
2992
|
-
...scratchXAxis.subtract(centerInCartesian),
|
|
2993
|
-
...scratchYAxis.subtract(centerInCartesian),
|
|
2994
|
-
...scratchZAxis.subtract(centerInCartesian)
|
|
2995
|
-
], new import_core6.Matrix4());
|
|
2996
|
-
}
|
|
2997
3419
|
function orientedBoundingBoxToCartographicBounds(boundingVolume) {
|
|
2998
3420
|
const result = emptyCartographicBounds();
|
|
2999
3421
|
const { halfAxes } = boundingVolume;
|
|
@@ -3078,19 +3500,32 @@ function getLodStatus(tile, frameState) {
|
|
|
3078
3500
|
if (screenSize < 2) {
|
|
3079
3501
|
return "OUT";
|
|
3080
3502
|
}
|
|
3081
|
-
if (!tile.header.children
|
|
3503
|
+
if (!tile.header.children) {
|
|
3082
3504
|
return "DRAW";
|
|
3083
|
-
} else if (tile.header.children) {
|
|
3084
|
-
return "DIG";
|
|
3085
3505
|
}
|
|
3086
|
-
|
|
3506
|
+
switch (tile.lodMetricType) {
|
|
3507
|
+
case "screenSpaceRelative": {
|
|
3508
|
+
const viewportHeight = frameState.topDownViewport.height || 1;
|
|
3509
|
+
return screenSize / viewportHeight <= tile.lodMetricValue ? "DRAW" : "DIG";
|
|
3510
|
+
}
|
|
3511
|
+
case "distanceRangeFromDefaultCamera":
|
|
3512
|
+
return tile.distanceToTile(frameState) >= tile.lodMetricValue ? "DRAW" : "DIG";
|
|
3513
|
+
case "maxScreenThresholdSQ": {
|
|
3514
|
+
const diameterThreshold = Math.sqrt(tile.lodMetricValue / (Math.PI * 0.25));
|
|
3515
|
+
return screenSize <= diameterThreshold ? "DRAW" : "DIG";
|
|
3516
|
+
}
|
|
3517
|
+
case "maxScreenThreshold":
|
|
3518
|
+
default:
|
|
3519
|
+
return screenSize <= tile.lodMetricValue ? "DRAW" : "DIG";
|
|
3520
|
+
}
|
|
3087
3521
|
}
|
|
3088
3522
|
function getProjectedRadius(tile, frameState) {
|
|
3089
3523
|
const { topDownViewport: viewport } = frameState;
|
|
3090
|
-
const
|
|
3091
|
-
const
|
|
3092
|
-
const
|
|
3093
|
-
const
|
|
3524
|
+
const mbs = tile.header.i3sLodMbs || tile.header.mbs;
|
|
3525
|
+
const mbsLat = mbs[1];
|
|
3526
|
+
const mbsLon = mbs[0];
|
|
3527
|
+
const mbsZ = mbs[2];
|
|
3528
|
+
const mbsR = mbs[3];
|
|
3094
3529
|
const mbsCenterCartesian = [...tile.boundingVolume.center];
|
|
3095
3530
|
const cameraPositionCartographic = viewport.unprojectPosition(viewport.cameraPosition);
|
|
3096
3531
|
import_geospatial5.Ellipsoid.WGS84.cartographicToCartesian(cameraPositionCartographic, cameraPositionCartesian);
|
|
@@ -3341,7 +3776,7 @@ var TilesetTraverser = class {
|
|
|
3341
3776
|
this.selectTile(tile, frameState);
|
|
3342
3777
|
} else if (tile.refine === TILE_REFINEMENT.REPLACE) {
|
|
3343
3778
|
this.loadTile(tile, frameState);
|
|
3344
|
-
if (stoppedRefining) {
|
|
3779
|
+
if (stoppedRefining || this.options.skipLevelOfDetail) {
|
|
3345
3780
|
this.selectTile(tile, frameState);
|
|
3346
3781
|
}
|
|
3347
3782
|
}
|
|
@@ -3406,7 +3841,7 @@ var TilesetTraverser = class {
|
|
|
3406
3841
|
}
|
|
3407
3842
|
// tile to render in the browser
|
|
3408
3843
|
selectTile(tile, frameState) {
|
|
3409
|
-
if (this.shouldSelectTile(tile)) {
|
|
3844
|
+
if (this.shouldSelectTile(tile, frameState)) {
|
|
3410
3845
|
tile._selectedFrame = frameState.frameNumber;
|
|
3411
3846
|
this.selectedTiles[tile.id] = tile;
|
|
3412
3847
|
}
|
|
@@ -3456,8 +3891,13 @@ var TilesetTraverser = class {
|
|
|
3456
3891
|
shouldLoadTile(tile) {
|
|
3457
3892
|
return tile.hasUnloadedContent || tile.contentExpired;
|
|
3458
3893
|
}
|
|
3459
|
-
|
|
3460
|
-
|
|
3894
|
+
/**
|
|
3895
|
+
* Returns whether a tile's content is available and visible for rendering.
|
|
3896
|
+
* @param tile Tile considered for rendering.
|
|
3897
|
+
* @param frameState Current culling state.
|
|
3898
|
+
*/
|
|
3899
|
+
shouldSelectTile(tile, frameState) {
|
|
3900
|
+
return tile.contentAvailable && tile.contentVisibility(frameState) !== "outside";
|
|
3461
3901
|
}
|
|
3462
3902
|
/** Decide if tile LoD (level of detail) is not sufficient under current viewport */
|
|
3463
3903
|
shouldRefine(tile, frameState, useParentMetric = false) {
|
|
@@ -3529,6 +3969,35 @@ var TilesetTraverser = class {
|
|
|
3529
3969
|
|
|
3530
3970
|
// dist/tileset-3d/common/tile-3d.js
|
|
3531
3971
|
var scratchVector2 = new import_core8.Vector3();
|
|
3972
|
+
function getContentVisibility(contentVolumes, fallbackVolume, cullingVolume2, visibilityPlaneMask, clippingPlanes = []) {
|
|
3973
|
+
const volumes = contentVolumes.length ? contentVolumes : [fallbackVolume];
|
|
3974
|
+
let visibleVolume = false;
|
|
3975
|
+
let intersectingVolume = false;
|
|
3976
|
+
for (const contentVolume of volumes) {
|
|
3977
|
+
let visibility = "inside";
|
|
3978
|
+
if (visibilityPlaneMask !== import_culling4.CullingVolume.MASK_INSIDE) {
|
|
3979
|
+
visibility = cullingVolume2.computeVisibility(contentVolume);
|
|
3980
|
+
if (visibility === "outside") {
|
|
3981
|
+
continue;
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3984
|
+
let clipped = false;
|
|
3985
|
+
for (const clippingPlane of clippingPlanes) {
|
|
3986
|
+
if (contentVolume.intersectPlane(clippingPlane) === "outside") {
|
|
3987
|
+
clipped = true;
|
|
3988
|
+
break;
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3991
|
+
if (!clipped) {
|
|
3992
|
+
visibleVolume = true;
|
|
3993
|
+
intersectingVolume = intersectingVolume || visibility === "intersecting";
|
|
3994
|
+
}
|
|
3995
|
+
}
|
|
3996
|
+
if (!visibleVolume) {
|
|
3997
|
+
return "outside";
|
|
3998
|
+
}
|
|
3999
|
+
return intersectingVolume ? "intersecting" : "inside";
|
|
4000
|
+
}
|
|
3532
4001
|
function defined2(x) {
|
|
3533
4002
|
return x !== void 0 && x !== null;
|
|
3534
4003
|
}
|
|
@@ -3542,6 +4011,8 @@ var Tile3D = class {
|
|
|
3542
4011
|
refine;
|
|
3543
4012
|
type;
|
|
3544
4013
|
contentUrl;
|
|
4014
|
+
/** Resolved render-content URLs in source order; empty for contentless tiles. */
|
|
4015
|
+
contentUrls = [];
|
|
3545
4016
|
/** Different refinement algorithms used by I3S and 3D tiles */
|
|
3546
4017
|
lodMetricType = "geometricError";
|
|
3547
4018
|
/**
|
|
@@ -3561,6 +4032,17 @@ var Tile3D = class {
|
|
|
3561
4032
|
* not the content's metadata in the tileset JSON file.
|
|
3562
4033
|
*/
|
|
3563
4034
|
content = null;
|
|
4035
|
+
/** Loaded payloads in the same order as {@link contentUrls}; `content` remains the primary payload. */
|
|
4036
|
+
contents = [];
|
|
4037
|
+
/**
|
|
4038
|
+
* Metadata entity attached to this tile in the source tileset, if present.
|
|
4039
|
+
*
|
|
4040
|
+
* This is the raw 3D Tiles metadata reference. The generic tiles runtime preserves it without
|
|
4041
|
+
* decoding schema classes or binary property tables.
|
|
4042
|
+
*/
|
|
4043
|
+
metadata = null;
|
|
4044
|
+
/** Raw metadata entities attached to tile contents, in content source order. */
|
|
4045
|
+
contentMetadata = [];
|
|
3564
4046
|
contentState = TILE_CONTENT_STATE.UNLOADED;
|
|
3565
4047
|
gpuMemoryUsageInBytes = 0;
|
|
3566
4048
|
/** The tile's children - an array of Tile3D objects. */
|
|
@@ -3602,7 +4084,22 @@ var Tile3D = class {
|
|
|
3602
4084
|
_visibilityPlaneMask;
|
|
3603
4085
|
_visible = void 0;
|
|
3604
4086
|
_contentBoundingVolume;
|
|
4087
|
+
_contentBoundingVolumes = [];
|
|
4088
|
+
/** Source content-volume headers retained after render content is unloaded. */
|
|
4089
|
+
_contentBoundingVolumeHeaders = [];
|
|
3605
4090
|
_viewerRequestVolume;
|
|
4091
|
+
/** Bounding volume used to cull the tile's first renderable content entry. */
|
|
4092
|
+
get contentBoundingVolume() {
|
|
4093
|
+
return this._contentBoundingVolume;
|
|
4094
|
+
}
|
|
4095
|
+
/** All transformed render-content bounding volumes, including tile-volume fallbacks. */
|
|
4096
|
+
get contentBoundingVolumes() {
|
|
4097
|
+
return this._contentBoundingVolumes;
|
|
4098
|
+
}
|
|
4099
|
+
/** Bounding volume that limits when this tile may be requested, when declared. */
|
|
4100
|
+
get viewerRequestVolume() {
|
|
4101
|
+
return this._viewerRequestVolume;
|
|
4102
|
+
}
|
|
3606
4103
|
_initialTransform = new import_core8.Matrix4();
|
|
3607
4104
|
// Used by traverser, cannot be marked private
|
|
3608
4105
|
_priority = 0;
|
|
@@ -3643,6 +4140,10 @@ var Tile3D = class {
|
|
|
3643
4140
|
this.refine = this._getRefine(header.refine);
|
|
3644
4141
|
this.type = header.type;
|
|
3645
4142
|
this.contentUrl = header.contentUrl;
|
|
4143
|
+
this.contentUrls = header.contentUrls || (header.contentUrl ? [header.contentUrl] : []);
|
|
4144
|
+
this.metadata = header.metadata || null;
|
|
4145
|
+
const contentHeaders = Array.isArray(header.content) ? header.content : [header.content];
|
|
4146
|
+
this.contentMetadata = contentHeaders.filter(Boolean).map((contentHeader) => contentHeader.metadata || null);
|
|
3646
4147
|
this.childrenState = header.implicitSubtree ? "unloaded" : "ready";
|
|
3647
4148
|
this._initializeLodMetric(header);
|
|
3648
4149
|
this._initializeTransforms(header);
|
|
@@ -3774,7 +4275,8 @@ var Tile3D = class {
|
|
|
3774
4275
|
* Memory usage of tile on GPU
|
|
3775
4276
|
*/
|
|
3776
4277
|
_getGpuMemoryUsageInBytes() {
|
|
3777
|
-
|
|
4278
|
+
const contents = this.contents.length ? this.contents : [this.content];
|
|
4279
|
+
return contents.reduce((total, content) => total + ((content == null ? void 0 : content.gpuMemoryUsageInBytes) || (content == null ? void 0 : content.byteLength) || 0), 0);
|
|
3778
4280
|
}
|
|
3779
4281
|
/**
|
|
3780
4282
|
* Returns scheduler priority for render-content requests.
|
|
@@ -3855,6 +4357,10 @@ var Tile3D = class {
|
|
|
3855
4357
|
}
|
|
3856
4358
|
try {
|
|
3857
4359
|
const loadResult = await this.tileset.source.loadTileContent(this);
|
|
4360
|
+
if (loadResult.contents) {
|
|
4361
|
+
this.contents = loadResult.contents;
|
|
4362
|
+
this.content = this.contents[0] || null;
|
|
4363
|
+
}
|
|
3858
4364
|
if (this.tileset.options.contentLoader) {
|
|
3859
4365
|
await this.tileset.options.contentLoader(this);
|
|
3860
4366
|
}
|
|
@@ -3941,6 +4447,7 @@ var Tile3D = class {
|
|
|
3941
4447
|
this.refine = this._getRefine(materializedHeader.refine);
|
|
3942
4448
|
this.type = materializedHeader.type;
|
|
3943
4449
|
this.contentUrl = materializedHeader.contentUrl;
|
|
4450
|
+
this.contentUrls = materializedHeader.contentUrls || (materializedHeader.contentUrl ? [materializedHeader.contentUrl] : []);
|
|
3944
4451
|
this._initializeLodMetric(materializedHeader);
|
|
3945
4452
|
this._updateLodMetricScale();
|
|
3946
4453
|
this._initializeBoundingVolumes(this.header);
|
|
@@ -3948,9 +4455,12 @@ var Tile3D = class {
|
|
|
3948
4455
|
}
|
|
3949
4456
|
// Unloads the tile's content.
|
|
3950
4457
|
unloadContent() {
|
|
3951
|
-
|
|
3952
|
-
|
|
4458
|
+
for (const content of this.contents.length ? this.contents : [this.content]) {
|
|
4459
|
+
if (content && content.destroy) {
|
|
4460
|
+
content.destroy();
|
|
4461
|
+
}
|
|
3953
4462
|
}
|
|
4463
|
+
this.contents = [];
|
|
3954
4464
|
this.content = null;
|
|
3955
4465
|
if (this.header.content && this.header.content.destroy) {
|
|
3956
4466
|
this.header.content.destroy();
|
|
@@ -4038,12 +4548,16 @@ var Tile3D = class {
|
|
|
4038
4548
|
const { boundingVolume } = this;
|
|
4039
4549
|
return cullingVolume2.computeVisibilityWithPlaneMask(boundingVolume, parentVisibilityPlaneMask);
|
|
4040
4550
|
}
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4551
|
+
/**
|
|
4552
|
+
* Determines whether renderable content intersects the view and configured clipping planes.
|
|
4553
|
+
*
|
|
4554
|
+
* Clipping planes are render-only constraints; traversal continues to use the tile volume.
|
|
4555
|
+
*
|
|
4556
|
+
* @param frameState Current camera, culling, and optional clipping-plane state.
|
|
4557
|
+
* @returns The content visibility classification.
|
|
4558
|
+
*/
|
|
4559
|
+
contentVisibility(frameState) {
|
|
4560
|
+
return getContentVisibility(this._contentBoundingVolumes, this.boundingVolume, frameState.cullingVolume, this._visibilityPlaneMask, frameState.clippingPlanes);
|
|
4047
4561
|
}
|
|
4048
4562
|
/**
|
|
4049
4563
|
* Computes the (potentially approximate) distance from the closest point of the tile's bounding volume to the camera.
|
|
@@ -4135,15 +4649,18 @@ var Tile3D = class {
|
|
|
4135
4649
|
}
|
|
4136
4650
|
_initializeBoundingVolumes(tileHeader) {
|
|
4137
4651
|
this._contentBoundingVolume = null;
|
|
4652
|
+
this._contentBoundingVolumeHeaders = [];
|
|
4138
4653
|
this._viewerRequestVolume = null;
|
|
4139
4654
|
this._updateBoundingVolume(tileHeader);
|
|
4140
4655
|
}
|
|
4141
4656
|
_initializeContent(tileHeader) {
|
|
4657
|
+
var _a;
|
|
4142
4658
|
this.content = { _tileset: this.tileset, _tile: this };
|
|
4659
|
+
this.contents = [];
|
|
4143
4660
|
this.hasEmptyContent = true;
|
|
4144
4661
|
this.contentState = TILE_CONTENT_STATE.UNLOADED;
|
|
4145
4662
|
this.hasTilesetContent = false;
|
|
4146
|
-
if (tileHeader.contentUrl) {
|
|
4663
|
+
if (tileHeader.contentUrl || ((_a = tileHeader.contentUrls) == null ? void 0 : _a.length)) {
|
|
4147
4664
|
this.content = null;
|
|
4148
4665
|
this.hasEmptyContent = false;
|
|
4149
4666
|
}
|
|
@@ -4182,16 +4699,18 @@ var Tile3D = class {
|
|
|
4182
4699
|
* `content`.
|
|
4183
4700
|
*/
|
|
4184
4701
|
_isTileset() {
|
|
4185
|
-
|
|
4186
|
-
return ((_a = this.content) == null ? void 0 : _a.shape) === "tileset3d";
|
|
4702
|
+
return (this.contents.length ? this.contents : [this.content]).some((content) => (content == null ? void 0 : content.shape) === "tileset3d");
|
|
4187
4703
|
}
|
|
4188
4704
|
_onContentLoaded() {
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4705
|
+
const contents = this.contents.length ? this.contents : [this.content];
|
|
4706
|
+
for (const content of contents) {
|
|
4707
|
+
switch (content && content.type) {
|
|
4708
|
+
case "vctr":
|
|
4709
|
+
case "geom":
|
|
4710
|
+
this.tileset._traverser.disableSkipLevelOfDetail = true;
|
|
4711
|
+
break;
|
|
4712
|
+
default:
|
|
4713
|
+
}
|
|
4195
4714
|
}
|
|
4196
4715
|
if (this._isTileset()) {
|
|
4197
4716
|
this.hasTilesetContent = true;
|
|
@@ -4205,12 +4724,12 @@ var Tile3D = class {
|
|
|
4205
4724
|
this._viewerRequestVolume = createBoundingVolume(header.viewerRequestVolume, this.computedTransform, this._viewerRequestVolume);
|
|
4206
4725
|
}
|
|
4207
4726
|
const content = header.content;
|
|
4208
|
-
if (
|
|
4209
|
-
|
|
4210
|
-
}
|
|
4211
|
-
if (content.boundingVolume) {
|
|
4212
|
-
this._contentBoundingVolume = createBoundingVolume(content.boundingVolume, this.computedTransform, this._contentBoundingVolume);
|
|
4727
|
+
if (content) {
|
|
4728
|
+
this._contentBoundingVolumeHeaders = Array.isArray(content) ? content : [content];
|
|
4213
4729
|
}
|
|
4730
|
+
const contentHeaders = content ? Array.isArray(content) ? content : [content] : this._contentBoundingVolumeHeaders;
|
|
4731
|
+
this._contentBoundingVolumes = contentHeaders.length ? contentHeaders.map((headerEntry) => (headerEntry == null ? void 0 : headerEntry.boundingVolume) ? createBoundingVolume(headerEntry.boundingVolume, this.computedTransform) : this.boundingVolume) : [this.boundingVolume];
|
|
4732
|
+
this._contentBoundingVolume = this._contentBoundingVolumes[0] || null;
|
|
4214
4733
|
}
|
|
4215
4734
|
/**
|
|
4216
4735
|
* Updates the tile's computed transform, world-space geometric error, and bounding volumes.
|
|
@@ -4376,6 +4895,259 @@ function getObbSize(halfAxes) {
|
|
|
4376
4895
|
return size;
|
|
4377
4896
|
}
|
|
4378
4897
|
|
|
4898
|
+
// dist/spatial/i3s-elevation.js
|
|
4899
|
+
var LINEAR_UNIT_TO_METERS = Object.freeze({
|
|
4900
|
+
meter: 1,
|
|
4901
|
+
millimeter: 1e-3,
|
|
4902
|
+
centimeter: 0.01,
|
|
4903
|
+
decimeter: 0.1,
|
|
4904
|
+
kilometer: 1e3,
|
|
4905
|
+
foot: 0.3048,
|
|
4906
|
+
yard: 0.9144,
|
|
4907
|
+
mile: 1609.344,
|
|
4908
|
+
"us-foot": 1200 / 3937,
|
|
4909
|
+
"us-inch": 0.0254000508001016,
|
|
4910
|
+
"us-yard": 3600 / 3937,
|
|
4911
|
+
"us-mile": 6336e3 / 3937,
|
|
4912
|
+
"clarke-foot": 0.3047972654,
|
|
4913
|
+
"clarke-yard": 0.9143917962,
|
|
4914
|
+
"clarke-link": 0.201166195164,
|
|
4915
|
+
"sears-yard": 0.914398414616,
|
|
4916
|
+
"sears-foot": 0.304799471539,
|
|
4917
|
+
"sears-chain": 20.1167651216,
|
|
4918
|
+
"sears-1922-truncated-chain": 20.116756,
|
|
4919
|
+
"benoit-1895-b-chain": 20.1167824944,
|
|
4920
|
+
"indian-yard": 0.914398530744,
|
|
4921
|
+
"indian-1937-yard": 0.91439523,
|
|
4922
|
+
"gold-coast-foot": 0.304799710181
|
|
4923
|
+
});
|
|
4924
|
+
var LINEAR_UNIT_ALIASES = Object.freeze({
|
|
4925
|
+
m: "meter",
|
|
4926
|
+
metre: "meter",
|
|
4927
|
+
meters: "meter",
|
|
4928
|
+
metres: "meter",
|
|
4929
|
+
mm: "millimeter",
|
|
4930
|
+
millimetre: "millimeter",
|
|
4931
|
+
millimeters: "millimeter",
|
|
4932
|
+
millimetres: "millimeter",
|
|
4933
|
+
cm: "centimeter",
|
|
4934
|
+
centimetre: "centimeter",
|
|
4935
|
+
centimeters: "centimeter",
|
|
4936
|
+
centimetres: "centimeter",
|
|
4937
|
+
dm: "decimeter",
|
|
4938
|
+
decimetre: "decimeter",
|
|
4939
|
+
decimeters: "decimeter",
|
|
4940
|
+
decimetres: "decimeter",
|
|
4941
|
+
km: "kilometer",
|
|
4942
|
+
kilometre: "kilometer",
|
|
4943
|
+
kilometers: "kilometer",
|
|
4944
|
+
kilometres: "kilometer",
|
|
4945
|
+
ft: "foot",
|
|
4946
|
+
feet: "foot",
|
|
4947
|
+
"us-survey-foot": "us-foot",
|
|
4948
|
+
"us-survey-feet": "us-foot",
|
|
4949
|
+
yd: "yard",
|
|
4950
|
+
yards: "yard",
|
|
4951
|
+
mi: "mile",
|
|
4952
|
+
miles: "mile"
|
|
4953
|
+
});
|
|
4954
|
+
function getI3SLinearUnitScale(unit) {
|
|
4955
|
+
if (!unit) {
|
|
4956
|
+
return void 0;
|
|
4957
|
+
}
|
|
4958
|
+
const normalized = unit.trim().toLowerCase().replaceAll("_", "-");
|
|
4959
|
+
const canonical = LINEAR_UNIT_ALIASES[normalized] || normalized;
|
|
4960
|
+
return LINEAR_UNIT_TO_METERS[canonical];
|
|
4961
|
+
}
|
|
4962
|
+
function getI3SVerticalUnitScale(heightUnit, zFactor) {
|
|
4963
|
+
if (zFactor !== void 0) {
|
|
4964
|
+
return Number.isFinite(zFactor) && zFactor > 0 ? zFactor : void 0;
|
|
4965
|
+
}
|
|
4966
|
+
return heightUnit ? getI3SLinearUnitScale(heightUnit) : 1;
|
|
4967
|
+
}
|
|
4968
|
+
|
|
4969
|
+
// dist/spatial/format-spatial-reference.js
|
|
4970
|
+
function getI3SSpatialReference(layer) {
|
|
4971
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
4972
|
+
const spatialReference = layer.spatialReference || ((_a = layer.fullExtent) == null ? void 0 : _a.spatialReference);
|
|
4973
|
+
const sourceCrs = getI3SCrsDefinition(spatialReference);
|
|
4974
|
+
const verticalCrs = ((_b = layer.heightModelInfo) == null ? void 0 : _b.vertCRS) || getI3SVerticalCrsDefinition(spatialReference);
|
|
4975
|
+
const heightModel = (_c = layer.heightModelInfo) == null ? void 0 : _c.heightModel;
|
|
4976
|
+
const verticalUnit = (_d = layer.heightModelInfo) == null ? void 0 : _d.heightUnit;
|
|
4977
|
+
const verticalUnitScale = getI3SVerticalUnitScale(verticalUnit, layer.ZFactor);
|
|
4978
|
+
const heightReference = heightModel === "ellipsoidal" ? "ellipsoidal" : heightModel === "gravity_related_height" ? "orthometric" : "unknown";
|
|
4979
|
+
const sourceIdentifier = getCrsIdentifier(spatialReference);
|
|
4980
|
+
const coordinateFrame = sourceIdentifier === void 0 ? getWktCoordinateFrame(spatialReference == null ? void 0 : spatialReference.wkt) : getIdentifierCoordinateFrame(sourceIdentifier);
|
|
4981
|
+
const units = getI3SCoordinateUnits(coordinateFrame, verticalUnit, layer.ZFactor);
|
|
4982
|
+
const warnings = [];
|
|
4983
|
+
const elevationMode = getI3SElevationMode((_e = layer.elevationInfo) == null ? void 0 : _e.mode);
|
|
4984
|
+
const elevationUnit = layer.elevationInfo ? layer.elevationInfo.unit || "meter" : void 0;
|
|
4985
|
+
const elevationUnitScale = getI3SLinearUnitScale(elevationUnit);
|
|
4986
|
+
if (verticalUnitScale === void 0) {
|
|
4987
|
+
warnings.push(layer.ZFactor !== void 0 ? `I3S ZFactor ${layer.ZFactor} is not a positive finite conversion factor` : `Unsupported I3S vertical unit ${verticalUnit}`);
|
|
4988
|
+
}
|
|
4989
|
+
if (layer.elevationInfo && elevationUnitScale === void 0) {
|
|
4990
|
+
warnings.push(`Unsupported I3S elevation unit ${elevationUnit}`);
|
|
4991
|
+
}
|
|
4992
|
+
if (((_f = layer.elevationInfo) == null ? void 0 : _f.mode) && !elevationMode) {
|
|
4993
|
+
warnings.push(`Unsupported I3S elevation mode ${layer.elevationInfo.mode}`);
|
|
4994
|
+
}
|
|
4995
|
+
if (elevationMode && elevationMode !== "absoluteHeight") {
|
|
4996
|
+
warnings.push(`I3S elevation mode ${elevationMode} requires a terrain or scene elevation provider`);
|
|
4997
|
+
}
|
|
4998
|
+
return createTilesetSpatialReference({
|
|
4999
|
+
sourceCrs,
|
|
5000
|
+
sourceCrsRepresentation: sourceIdentifier !== void 0 ? "identifier" : sourceCrs ? "wkt" : void 0,
|
|
5001
|
+
sourceCrsAlternatives: sourceIdentifier !== void 0 && (spatialReference == null ? void 0 : spatialReference.wkt) ? [{ definition: spatialReference.wkt, representation: "wkt" }] : void 0,
|
|
5002
|
+
verticalCrs,
|
|
5003
|
+
units,
|
|
5004
|
+
verticalUnitScale: verticalUnitScale ?? Number.NaN,
|
|
5005
|
+
heightReference,
|
|
5006
|
+
elevationMode,
|
|
5007
|
+
elevationOffset: (_g = layer.elevationInfo) == null ? void 0 : _g.offset,
|
|
5008
|
+
elevationUnit,
|
|
5009
|
+
elevationUnitScale: ((_h = layer.elevationInfo) == null ? void 0 : _h.mode) && !elevationMode ? Number.NaN : elevationUnitScale ?? (layer.elevationInfo ? Number.NaN : 1),
|
|
5010
|
+
coordinateFrame,
|
|
5011
|
+
axisOrder: sourceCrs ? "xyz" : "unknown",
|
|
5012
|
+
provenance: sourceCrs ? "metadata" : "unknown",
|
|
5013
|
+
warnings
|
|
5014
|
+
});
|
|
5015
|
+
}
|
|
5016
|
+
function getI3SCoordinateUnits(coordinateFrame, verticalUnit, zFactor) {
|
|
5017
|
+
if (coordinateFrame === "geocentric") {
|
|
5018
|
+
return ["meter", "meter", "meter"];
|
|
5019
|
+
}
|
|
5020
|
+
if (coordinateFrame === "geographic" && (verticalUnit || zFactor === void 0)) {
|
|
5021
|
+
return ["degree", "degree", verticalUnit || "meter"];
|
|
5022
|
+
}
|
|
5023
|
+
return void 0;
|
|
5024
|
+
}
|
|
5025
|
+
function getI3SElevationMode(mode) {
|
|
5026
|
+
switch (mode) {
|
|
5027
|
+
case "absoluteHeight":
|
|
5028
|
+
case "onTheGround":
|
|
5029
|
+
case "relativeToGround":
|
|
5030
|
+
case "relativeToScene":
|
|
5031
|
+
return mode;
|
|
5032
|
+
default:
|
|
5033
|
+
return void 0;
|
|
5034
|
+
}
|
|
5035
|
+
}
|
|
5036
|
+
function get3DTilesSpatialReference(tileset) {
|
|
5037
|
+
var _a, _b;
|
|
5038
|
+
const geocentricCrs = getTilesetSemanticValue(tileset, "TILESET_CRS_GEOCENTRIC");
|
|
5039
|
+
const coordinateEpoch = getTilesetSemanticValue(tileset, "TILESET_CRS_COORDINATE_EPOCH");
|
|
5040
|
+
const warnings = [];
|
|
5041
|
+
let sourceCrs;
|
|
5042
|
+
let provenance = "unknown";
|
|
5043
|
+
let sourceCrsState;
|
|
5044
|
+
if (typeof geocentricCrs === "string" && geocentricCrs.toUpperCase() !== "UNKNOWN") {
|
|
5045
|
+
sourceCrs = geocentricCrs;
|
|
5046
|
+
provenance = "metadata";
|
|
5047
|
+
sourceCrsState = "explicit";
|
|
5048
|
+
} else if (geocentricCrs !== void 0) {
|
|
5049
|
+
warnings.push("3D Tiles geocentric CRS is explicitly unknown");
|
|
5050
|
+
provenance = "metadata";
|
|
5051
|
+
sourceCrsState = "unknown";
|
|
5052
|
+
} else if ((_b = (_a = tileset.root) == null ? void 0 : _a.boundingVolume) == null ? void 0 : _b.region) {
|
|
5053
|
+
sourceCrs = "EPSG:4978";
|
|
5054
|
+
provenance = "format-default";
|
|
5055
|
+
sourceCrsState = "default";
|
|
5056
|
+
} else if (tileset.schemaUri && !tileset.schema) {
|
|
5057
|
+
warnings.push("External 3D Tiles metadata schema must be loaded before CRS semantics can resolve");
|
|
5058
|
+
}
|
|
5059
|
+
const epoch = parseCoordinateEpoch(coordinateEpoch);
|
|
5060
|
+
if (coordinateEpoch !== void 0 && epoch === void 0) {
|
|
5061
|
+
warnings.push("3D Tiles coordinate epoch is not a finite decimal year");
|
|
5062
|
+
}
|
|
5063
|
+
return createTilesetSpatialReference({
|
|
5064
|
+
sourceCrs,
|
|
5065
|
+
sourceCrsState,
|
|
5066
|
+
sourceCrsRepresentation: sourceCrs ? "identifier" : void 0,
|
|
5067
|
+
coordinateEpoch: epoch,
|
|
5068
|
+
heightReference: sourceCrs ? "ellipsoidal" : "unknown",
|
|
5069
|
+
coordinateFrame: sourceCrs ? "geocentric" : "unknown",
|
|
5070
|
+
axisOrder: sourceCrs ? "xyz" : "unknown",
|
|
5071
|
+
provenance,
|
|
5072
|
+
warnings
|
|
5073
|
+
});
|
|
5074
|
+
}
|
|
5075
|
+
function parseCoordinateEpoch(value) {
|
|
5076
|
+
if (typeof value !== "string" && typeof value !== "number") {
|
|
5077
|
+
return void 0;
|
|
5078
|
+
}
|
|
5079
|
+
if (typeof value === "string" && !value.trim()) {
|
|
5080
|
+
return void 0;
|
|
5081
|
+
}
|
|
5082
|
+
const epoch = Number(value);
|
|
5083
|
+
return Number.isFinite(epoch) ? epoch : void 0;
|
|
5084
|
+
}
|
|
5085
|
+
function getI3SCrsDefinition(spatialReference) {
|
|
5086
|
+
const identifier = getCrsIdentifier(spatialReference);
|
|
5087
|
+
if (identifier !== void 0) {
|
|
5088
|
+
return `EPSG:${identifier}`;
|
|
5089
|
+
}
|
|
5090
|
+
return spatialReference == null ? void 0 : spatialReference.wkt;
|
|
5091
|
+
}
|
|
5092
|
+
function getI3SVerticalCrsDefinition(spatialReference) {
|
|
5093
|
+
const identifier = (spatialReference == null ? void 0 : spatialReference.latestVcsWkid) ?? (spatialReference == null ? void 0 : spatialReference.vcsWkid);
|
|
5094
|
+
return identifier === void 0 ? void 0 : `EPSG:${identifier}`;
|
|
5095
|
+
}
|
|
5096
|
+
function getCrsIdentifier(spatialReference) {
|
|
5097
|
+
return (spatialReference == null ? void 0 : spatialReference.latestWkid) ?? (spatialReference == null ? void 0 : spatialReference.wkid);
|
|
5098
|
+
}
|
|
5099
|
+
function getIdentifierCoordinateFrame(identifier) {
|
|
5100
|
+
if (identifier === 4978) {
|
|
5101
|
+
return "geocentric";
|
|
5102
|
+
}
|
|
5103
|
+
if (identifier === 4326 || identifier === 4490 || identifier === 4979) {
|
|
5104
|
+
return "geographic";
|
|
5105
|
+
}
|
|
5106
|
+
return "projected";
|
|
5107
|
+
}
|
|
5108
|
+
function getWktCoordinateFrame(wkt) {
|
|
5109
|
+
var _a;
|
|
5110
|
+
if (!wkt) {
|
|
5111
|
+
return "unknown";
|
|
5112
|
+
}
|
|
5113
|
+
const normalizedWkt = wkt.trim().toUpperCase();
|
|
5114
|
+
const rootKeyword = (_a = normalizedWkt.match(/^([A-Z][A-Z0-9_]*)\s*[\[(]/)) == null ? void 0 : _a[1];
|
|
5115
|
+
if (rootKeyword === "GEOCCS") {
|
|
5116
|
+
return "geocentric";
|
|
5117
|
+
}
|
|
5118
|
+
if (rootKeyword === "GEOGCS" || rootKeyword === "GEOGRAPHICCRS" || rootKeyword === "GEOGRAPHIC2DCRS" || rootKeyword === "GEOGRAPHIC3DCRS") {
|
|
5119
|
+
return "geographic";
|
|
5120
|
+
}
|
|
5121
|
+
if (rootKeyword === "PROJCS" || rootKeyword === "PROJCRS" || rootKeyword === "PROJECTEDCRS") {
|
|
5122
|
+
return "projected";
|
|
5123
|
+
}
|
|
5124
|
+
if (rootKeyword === "GEODCRS" || rootKeyword === "GEODETICCRS") {
|
|
5125
|
+
if (/\bCS\s*[\[(]\s*CARTESIAN\s*,\s*3\b/.test(normalizedWkt)) {
|
|
5126
|
+
return "geocentric";
|
|
5127
|
+
}
|
|
5128
|
+
if (/\bCS\s*[\[(]\s*ELLIPSOIDAL\s*,\s*[23]\b/.test(normalizedWkt)) {
|
|
5129
|
+
return "geographic";
|
|
5130
|
+
}
|
|
5131
|
+
}
|
|
5132
|
+
return "unknown";
|
|
5133
|
+
}
|
|
5134
|
+
function getTilesetSemanticValue(tileset, semantic) {
|
|
5135
|
+
var _a, _b, _c, _d;
|
|
5136
|
+
const classIdentifier = (_a = tileset.metadata) == null ? void 0 : _a.class;
|
|
5137
|
+
if (!classIdentifier) {
|
|
5138
|
+
return void 0;
|
|
5139
|
+
}
|
|
5140
|
+
const classDefinition = (_c = (_b = tileset.schema) == null ? void 0 : _b.classes) == null ? void 0 : _c[classIdentifier];
|
|
5141
|
+
const propertyDefinitions = classDefinition == null ? void 0 : classDefinition.properties;
|
|
5142
|
+
const propertyValues = (_d = tileset.metadata) == null ? void 0 : _d.properties;
|
|
5143
|
+
for (const [propertyIdentifier, propertyDefinition] of Object.entries(propertyDefinitions || {})) {
|
|
5144
|
+
if (propertyDefinition.semantic === semantic) {
|
|
5145
|
+
return propertyValues == null ? void 0 : propertyValues[propertyIdentifier];
|
|
5146
|
+
}
|
|
5147
|
+
}
|
|
5148
|
+
return void 0;
|
|
5149
|
+
}
|
|
5150
|
+
|
|
4379
5151
|
// dist/tileset-3d/format-3d-tiles/implicit-tiling.js
|
|
4380
5152
|
var QUADTREE_CHILD_COUNT = 4;
|
|
4381
5153
|
var OCTREE_CHILD_COUNT = 8;
|
|
@@ -4413,7 +5185,7 @@ function materializeAvailableTile(subtree, reference, localCoordinates, globalCo
|
|
|
4413
5185
|
return null;
|
|
4414
5186
|
}
|
|
4415
5187
|
counters.tileCount++;
|
|
4416
|
-
const
|
|
5188
|
+
const contentAvailability = getContentAvailability(subtree.contentAvailability, availabilityIndex);
|
|
4417
5189
|
const children = [];
|
|
4418
5190
|
if (globalCoordinates.level < descriptor.maximumLevel) {
|
|
4419
5191
|
if (localCoordinates.localLevel + 1 < descriptor.subtreeLevels) {
|
|
@@ -4432,15 +5204,15 @@ function materializeAvailableTile(subtree, reference, localCoordinates, globalCo
|
|
|
4432
5204
|
const childSubtreeIndex = localCoordinates.mortonIndex * childCount + childIndex;
|
|
4433
5205
|
if (getAvailabilityValue(subtree.childSubtreeAvailability, childSubtreeIndex)) {
|
|
4434
5206
|
const childCoordinates = getChildCoordinates(globalCoordinates, childIndex, descriptor.subdivisionScheme);
|
|
4435
|
-
children.push(createLazyImplicitTileHeader(descriptor, childCoordinates));
|
|
5207
|
+
children.push(createLazyImplicitTileHeader(subtree, descriptor, childCoordinates));
|
|
4436
5208
|
counters.childSubtreeCount++;
|
|
4437
5209
|
}
|
|
4438
5210
|
}
|
|
4439
5211
|
}
|
|
4440
5212
|
}
|
|
4441
|
-
return formatImplicitTileHeader(descriptor, reference, globalCoordinates,
|
|
5213
|
+
return formatImplicitTileHeader(subtree, descriptor, reference, globalCoordinates, contentAvailability, children);
|
|
4442
5214
|
}
|
|
4443
|
-
function createLazyImplicitTileHeader(descriptor, coordinates) {
|
|
5215
|
+
function createLazyImplicitTileHeader(subtree, descriptor, coordinates) {
|
|
4444
5216
|
const reference = createImplicitSubtreeReference(descriptor, coordinates);
|
|
4445
5217
|
return {
|
|
4446
5218
|
id: getImplicitTileId(reference, coordinates),
|
|
@@ -4451,23 +5223,56 @@ function createLazyImplicitTileHeader(descriptor, coordinates) {
|
|
|
4451
5223
|
lodMetricType: descriptor.lodMetricType,
|
|
4452
5224
|
lodMetricValue: descriptor.rootLodMetricValue / 2 ** coordinates.level,
|
|
4453
5225
|
refine: descriptor.refine,
|
|
4454
|
-
type: TILE_TYPE.EMPTY
|
|
5226
|
+
type: TILE_TYPE.EMPTY,
|
|
5227
|
+
implicitMetadata: getImplicitSubtreeMetadata(subtree)
|
|
4455
5228
|
};
|
|
4456
5229
|
}
|
|
4457
|
-
function formatImplicitTileHeader(descriptor, reference, coordinates,
|
|
4458
|
-
|
|
5230
|
+
function formatImplicitTileHeader(subtree, descriptor, reference, coordinates, contentAvailability, children) {
|
|
5231
|
+
var _a;
|
|
5232
|
+
const contentUrlTemplates = ((_a = descriptor.contentUrlTemplates) == null ? void 0 : _a.length) ? descriptor.contentUrlTemplates : [descriptor.contentUrlTemplate];
|
|
5233
|
+
const contentEntries = contentUrlTemplates.map((templateUrl, contentIndex) => {
|
|
5234
|
+
if (!contentAvailability[contentIndex] || !templateUrl) {
|
|
5235
|
+
return null;
|
|
5236
|
+
}
|
|
5237
|
+
return {
|
|
5238
|
+
contentIndex,
|
|
5239
|
+
contentUrl: replaceImplicitUrlTemplate(templateUrl, coordinates)
|
|
5240
|
+
};
|
|
5241
|
+
}).filter((entry) => Boolean(entry));
|
|
5242
|
+
const availableContentUrls = contentEntries.map((entry) => entry.contentUrl);
|
|
5243
|
+
const content = contentEntries.map(({ contentIndex, contentUrl: contentUrl2 }) => {
|
|
5244
|
+
var _a2;
|
|
5245
|
+
return {
|
|
5246
|
+
...((_a2 = descriptor.contentHeaders) == null ? void 0 : _a2[contentIndex]) || (contentIndex === 0 ? descriptor.contentHeader : {}) || {},
|
|
5247
|
+
uri: contentUrl2
|
|
5248
|
+
};
|
|
5249
|
+
});
|
|
5250
|
+
const contentUrl = availableContentUrls[0];
|
|
4459
5251
|
const lodMetricValue = descriptor.rootLodMetricValue / 2 ** coordinates.level;
|
|
4460
5252
|
return {
|
|
4461
5253
|
id: getImplicitTileId(reference, coordinates),
|
|
4462
5254
|
children,
|
|
4463
5255
|
contentUrl,
|
|
4464
|
-
content:
|
|
5256
|
+
content: content.length > 1 ? content : content[0],
|
|
5257
|
+
contentUrls: availableContentUrls,
|
|
4465
5258
|
refine: descriptor.refine,
|
|
4466
5259
|
type: getImplicitTileType(contentUrl),
|
|
4467
5260
|
lodMetricType: descriptor.lodMetricType,
|
|
4468
5261
|
lodMetricValue,
|
|
4469
5262
|
geometricError: lodMetricValue,
|
|
4470
|
-
boundingVolume: calculateImplicitBoundingVolume(descriptor.rootBoundingVolume, coordinates, descriptor.subdivisionScheme)
|
|
5263
|
+
boundingVolume: calculateImplicitBoundingVolume(descriptor.rootBoundingVolume, coordinates, descriptor.subdivisionScheme),
|
|
5264
|
+
implicitMetadata: getImplicitSubtreeMetadata(subtree)
|
|
5265
|
+
};
|
|
5266
|
+
}
|
|
5267
|
+
function getImplicitSubtreeMetadata(subtree) {
|
|
5268
|
+
if (!subtree.propertyTables && subtree.tileMetadata === void 0 && !subtree.contentMetadata && subtree.subtreeMetadata === void 0) {
|
|
5269
|
+
return void 0;
|
|
5270
|
+
}
|
|
5271
|
+
return {
|
|
5272
|
+
propertyTables: subtree.propertyTables,
|
|
5273
|
+
tileMetadata: subtree.tileMetadata,
|
|
5274
|
+
contentMetadata: subtree.contentMetadata,
|
|
5275
|
+
subtreeMetadata: subtree.subtreeMetadata
|
|
4471
5276
|
};
|
|
4472
5277
|
}
|
|
4473
5278
|
function getImplicitTileId(reference, coordinates) {
|
|
@@ -4485,8 +5290,9 @@ function getAvailabilityValue(availability, index) {
|
|
|
4485
5290
|
const bitIndex = index % 8;
|
|
4486
5291
|
return Boolean(bitstream[byteIndex] >> bitIndex & 1);
|
|
4487
5292
|
}
|
|
4488
|
-
function
|
|
4489
|
-
|
|
5293
|
+
function getContentAvailability(availability, index) {
|
|
5294
|
+
const streams = Array.isArray(availability) ? availability : [availability];
|
|
5295
|
+
return streams.map((stream) => getAvailabilityValue(stream || { constant: 0 }, index));
|
|
4490
5296
|
}
|
|
4491
5297
|
function getLevelOffset(childCount, localLevel) {
|
|
4492
5298
|
return (childCount ** localLevel - 1) / (childCount - 1);
|
|
@@ -4628,12 +5434,8 @@ var Tiles3DSource = class {
|
|
|
4628
5434
|
queryParams = {};
|
|
4629
5435
|
/** Final request URLs cached by unmodified tile content URL. */
|
|
4630
5436
|
tileUrlCache = /* @__PURE__ */ new Map();
|
|
4631
|
-
/** Parsed subtree
|
|
4632
|
-
implicitSubtreeCache
|
|
4633
|
-
/** URLs whose subtree resource requests have not settled. */
|
|
4634
|
-
pendingImplicitSubtreeUrls = /* @__PURE__ */ new Set();
|
|
4635
|
-
/** Maximum number of settled parsed subtrees retained by this source. */
|
|
4636
|
-
maximumCachedSubtrees;
|
|
5437
|
+
/** Parsed subtree requests keyed by final source URL for deduplication and LRU reuse. */
|
|
5438
|
+
implicitSubtreeCache;
|
|
4637
5439
|
/** Mutable counters exposed as a defensive snapshot through {@link getImplicitTilingStats}. */
|
|
4638
5440
|
implicitTilingStats = {
|
|
4639
5441
|
requestedSubtrees: 0,
|
|
@@ -4663,7 +5465,8 @@ var Tiles3DSource = class {
|
|
|
4663
5465
|
this.coreApi = request.coreApi;
|
|
4664
5466
|
this.loadOptions = loadOptions;
|
|
4665
5467
|
const maximumCachedSubtrees = Number((_a = loadOptions["3d-tiles"]) == null ? void 0 : _a.maximumCachedSubtrees);
|
|
4666
|
-
|
|
5468
|
+
const maximumCacheEntries = Number.isFinite(maximumCachedSubtrees) ? Math.max(0, Math.floor(maximumCachedSubtrees)) : DEFAULT_MAXIMUM_CACHED_SUBTREES;
|
|
5469
|
+
this.implicitSubtreeCache = new RequestCache({ maxEntries: maximumCacheEntries });
|
|
4667
5470
|
}
|
|
4668
5471
|
/**
|
|
4669
5472
|
* Releases URL and parsed-subtree caches and blocks late subtree installation.
|
|
@@ -4675,7 +5478,6 @@ var Tiles3DSource = class {
|
|
|
4675
5478
|
this.destroyed = true;
|
|
4676
5479
|
this.tileUrlCache.clear();
|
|
4677
5480
|
this.implicitSubtreeCache.clear();
|
|
4678
|
-
this.pendingImplicitSubtreeUrls.clear();
|
|
4679
5481
|
}
|
|
4680
5482
|
/**
|
|
4681
5483
|
* Fetches and validates top-level metadata, then normalizes common fields used by {@link Tileset3D}.
|
|
@@ -4721,7 +5523,8 @@ var Tiles3DSource = class {
|
|
|
4721
5523
|
tileset: this.rootTileset,
|
|
4722
5524
|
lodMetricType: this.rootTileset.lodMetricType,
|
|
4723
5525
|
lodMetricValue: this.rootTileset.lodMetricValue,
|
|
4724
|
-
refine: (_a = this.rootTileset.root) == null ? void 0 : _a.refine
|
|
5526
|
+
refine: (_a = this.rootTileset.root) == null ? void 0 : _a.refine,
|
|
5527
|
+
spatialReference: get3DTilesSpatialReference(this.rootTileset)
|
|
4725
5528
|
};
|
|
4726
5529
|
}
|
|
4727
5530
|
/**
|
|
@@ -4780,7 +5583,7 @@ var Tiles3DSource = class {
|
|
|
4780
5583
|
* Loads binary content or nested tileset JSON for a runtime tile.
|
|
4781
5584
|
*/
|
|
4782
5585
|
async loadTileContent(tile) {
|
|
4783
|
-
const
|
|
5586
|
+
const contentUrls = (tile.contentUrls || [tile.contentUrl]).filter(Boolean);
|
|
4784
5587
|
const tilesetLoaderOptions = this.loadOptions[this.loader.id] || {};
|
|
4785
5588
|
const options = {
|
|
4786
5589
|
...this.loadOptions,
|
|
@@ -4792,11 +5595,15 @@ var Tiles3DSource = class {
|
|
|
4792
5595
|
assetGltfUpAxis: this.asset && this.asset.gltfUpAxis || "Y"
|
|
4793
5596
|
}
|
|
4794
5597
|
};
|
|
4795
|
-
const
|
|
4796
|
-
tile.
|
|
5598
|
+
const contents = await Promise.all(contentUrls.map((contentUrl) => this.loadResourceData(this.getTileUrl(contentUrl), options)));
|
|
5599
|
+
tile.contents = contents;
|
|
5600
|
+
tile.content = contents[0] || null;
|
|
5601
|
+
const nestedTilesets = contents.filter((content) => (content == null ? void 0 : content.shape) === "tileset3d");
|
|
4797
5602
|
return {
|
|
4798
5603
|
loaded: true,
|
|
4799
|
-
|
|
5604
|
+
contents,
|
|
5605
|
+
nestedTileset: nestedTilesets[0],
|
|
5606
|
+
nestedTilesets
|
|
4800
5607
|
};
|
|
4801
5608
|
}
|
|
4802
5609
|
/**
|
|
@@ -4843,8 +5650,8 @@ var Tiles3DSource = class {
|
|
|
4843
5650
|
getImplicitTilingStats() {
|
|
4844
5651
|
return {
|
|
4845
5652
|
...this.implicitTilingStats,
|
|
4846
|
-
cachedSubtrees: this.implicitSubtreeCache.size - this.
|
|
4847
|
-
pendingSubtrees: this.
|
|
5653
|
+
cachedSubtrees: this.implicitSubtreeCache.size - this.implicitSubtreeCache.pendingSize,
|
|
5654
|
+
pendingSubtrees: this.implicitSubtreeCache.pendingSize
|
|
4848
5655
|
};
|
|
4849
5656
|
}
|
|
4850
5657
|
/**
|
|
@@ -4939,8 +5746,11 @@ var Tiles3DSource = class {
|
|
|
4939
5746
|
* Updates content-format flags and installs nested tileset subtrees.
|
|
4940
5747
|
*/
|
|
4941
5748
|
onTileLoaded(tileset, tile, loadResult) {
|
|
4942
|
-
|
|
4943
|
-
const
|
|
5749
|
+
const contents = tile.contents.length ? tile.contents : [tile.content];
|
|
5750
|
+
const extensionsRemoved = contents.flatMap((content) => {
|
|
5751
|
+
var _a;
|
|
5752
|
+
return ((_a = content == null ? void 0 : content.gltf) == null ? void 0 : _a.extensionsRemoved) || [];
|
|
5753
|
+
});
|
|
4944
5754
|
if (extensionsRemoved.includes("KHR_draco_mesh_compression")) {
|
|
4945
5755
|
this.contentFormats.draco = true;
|
|
4946
5756
|
}
|
|
@@ -4950,8 +5760,9 @@ var Tiles3DSource = class {
|
|
|
4950
5760
|
if (extensionsRemoved.includes("KHR_texture_basisu")) {
|
|
4951
5761
|
this.contentFormats.ktx2 = true;
|
|
4952
5762
|
}
|
|
4953
|
-
|
|
4954
|
-
|
|
5763
|
+
const nestedTilesets = loadResult.nestedTilesets || (loadResult.nestedTileset ? [loadResult.nestedTileset] : []);
|
|
5764
|
+
for (const nestedTileset of nestedTilesets) {
|
|
5765
|
+
tileset._initializeTileHeaders(nestedTileset, tile);
|
|
4955
5766
|
}
|
|
4956
5767
|
}
|
|
4957
5768
|
/**
|
|
@@ -4991,31 +5802,20 @@ var Tiles3DSource = class {
|
|
|
4991
5802
|
const cachedSubtree = this.implicitSubtreeCache.get(subtreeUrl);
|
|
4992
5803
|
if (cachedSubtree) {
|
|
4993
5804
|
this.implicitTilingStats.cacheHits++;
|
|
4994
|
-
this.implicitSubtreeCache.delete(subtreeUrl);
|
|
4995
|
-
this.implicitSubtreeCache.set(subtreeUrl, cachedSubtree);
|
|
4996
5805
|
return await cachedSubtree;
|
|
4997
5806
|
}
|
|
4998
5807
|
this.implicitTilingStats.requestedSubtrees++;
|
|
4999
|
-
this.pendingImplicitSubtreeUrls.add(subtreeUrl);
|
|
5000
5808
|
const loaderOptions = this.loadOptions[this.loader.id] || {};
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5809
|
+
return await this.implicitSubtreeCache.getOrLoad(subtreeUrl, async () => {
|
|
5810
|
+
return await this.loadResourceData(subtreeUrl, {
|
|
5811
|
+
...this.loadOptions,
|
|
5812
|
+
[this.loader.id]: {
|
|
5813
|
+
...loaderOptions,
|
|
5814
|
+
isTileset: false,
|
|
5815
|
+
isSubtree: true
|
|
5816
|
+
}
|
|
5817
|
+
});
|
|
5008
5818
|
});
|
|
5009
|
-
this.implicitSubtreeCache.set(subtreeUrl, subtreePromise);
|
|
5010
|
-
try {
|
|
5011
|
-
return await subtreePromise;
|
|
5012
|
-
} catch (error) {
|
|
5013
|
-
this.implicitSubtreeCache.delete(subtreeUrl);
|
|
5014
|
-
throw error;
|
|
5015
|
-
} finally {
|
|
5016
|
-
this.pendingImplicitSubtreeUrls.delete(subtreeUrl);
|
|
5017
|
-
this.trimImplicitSubtreeCache();
|
|
5018
|
-
}
|
|
5019
5819
|
}
|
|
5020
5820
|
/**
|
|
5021
5821
|
* Instantiates every header represented by one materialized subtree.
|
|
@@ -5046,20 +5846,6 @@ var Tiles3DSource = class {
|
|
|
5046
5846
|
}
|
|
5047
5847
|
return materializedTileCount;
|
|
5048
5848
|
}
|
|
5049
|
-
/** Evicts least-recently-used settled subtree entries until the configured bound is met. */
|
|
5050
|
-
trimImplicitSubtreeCache() {
|
|
5051
|
-
if (this.implicitSubtreeCache.size <= this.maximumCachedSubtrees) {
|
|
5052
|
-
return;
|
|
5053
|
-
}
|
|
5054
|
-
for (const subtreeUrl of this.implicitSubtreeCache.keys()) {
|
|
5055
|
-
if (!this.pendingImplicitSubtreeUrls.has(subtreeUrl)) {
|
|
5056
|
-
this.implicitSubtreeCache.delete(subtreeUrl);
|
|
5057
|
-
}
|
|
5058
|
-
if (this.implicitSubtreeCache.size <= this.maximumCachedSubtrees) {
|
|
5059
|
-
break;
|
|
5060
|
-
}
|
|
5061
|
-
}
|
|
5062
|
-
}
|
|
5063
5849
|
};
|
|
5064
5850
|
function isTilesetRequest(input) {
|
|
5065
5851
|
return Boolean(input && typeof input === "object" && "url" in input && "loader" in input && !("type" in input));
|
|
@@ -5081,8 +5867,8 @@ function normalizeTiles3DRequest(input) {
|
|
|
5081
5867
|
}
|
|
5082
5868
|
|
|
5083
5869
|
// dist/tileset-3d/format-i3s/i3s-source.js
|
|
5084
|
-
var
|
|
5085
|
-
var
|
|
5870
|
+
var import_geospatial10 = require("@math.gl/geospatial");
|
|
5871
|
+
var import_core13 = require("@math.gl/core");
|
|
5086
5872
|
|
|
5087
5873
|
// dist/tileset-3d/format-i3s/i3s-pending-tiles-register.js
|
|
5088
5874
|
var I3SPendingTilesRegister = class {
|
|
@@ -5262,6 +6048,836 @@ var I3STilesetTraverser = class extends TilesetTraverser {
|
|
|
5262
6048
|
}
|
|
5263
6049
|
};
|
|
5264
6050
|
|
|
6051
|
+
// dist/spatial/i3s-spatial-transformer.js
|
|
6052
|
+
var import_core12 = require("@math.gl/core");
|
|
6053
|
+
var import_geospatial9 = require("@math.gl/geospatial");
|
|
6054
|
+
|
|
6055
|
+
// dist/spatial/spatial-coordinate-transformer.js
|
|
6056
|
+
var import_core11 = require("@math.gl/core");
|
|
6057
|
+
var import_geospatial8 = require("@math.gl/geospatial");
|
|
6058
|
+
var import_proj42 = require("@math.gl/proj4");
|
|
6059
|
+
|
|
6060
|
+
// dist/spatial/spatial-resource-registry.js
|
|
6061
|
+
var import_geoid = require("@math.gl/geoid");
|
|
6062
|
+
var import_proj4 = require("@math.gl/proj4");
|
|
6063
|
+
var geoidModels = /* @__PURE__ */ new Map();
|
|
6064
|
+
function registerSpatialCrs(name, definition) {
|
|
6065
|
+
validateResourceName(name, "CRS");
|
|
6066
|
+
import_proj4.Proj4Projection.defineProjectionAliases({ [name]: definition });
|
|
6067
|
+
}
|
|
6068
|
+
function registerSpatialDatumGrid(name, data) {
|
|
6069
|
+
validateResourceName(name, "datum grid");
|
|
6070
|
+
import_proj4.Proj4Projection.registerDatumGrid(name, data);
|
|
6071
|
+
}
|
|
6072
|
+
function registerGeoidModel(name, geoid) {
|
|
6073
|
+
validateResourceName(name, "geoid model");
|
|
6074
|
+
geoidModels.set(name, geoid);
|
|
6075
|
+
}
|
|
6076
|
+
function registerGeoidModelFromPgm(name, data, options = {}) {
|
|
6077
|
+
const geoid = (0, import_geoid.parsePGM)(data, options);
|
|
6078
|
+
registerGeoidModel(name, geoid);
|
|
6079
|
+
return geoid;
|
|
6080
|
+
}
|
|
6081
|
+
function getGeoidModel(name) {
|
|
6082
|
+
return geoidModels.get(name);
|
|
6083
|
+
}
|
|
6084
|
+
function validateResourceName(name, resourceType) {
|
|
6085
|
+
if (!name.trim()) {
|
|
6086
|
+
throw new Error(`${resourceType} name must not be empty`);
|
|
6087
|
+
}
|
|
6088
|
+
}
|
|
6089
|
+
|
|
6090
|
+
// dist/spatial/spatial-coordinate-transformer.js
|
|
6091
|
+
var GEOGRAPHIC_CRS2 = "EPSG:4326";
|
|
6092
|
+
var GEOCENTRIC_CRS2 = "EPSG:4978";
|
|
6093
|
+
var SpatialCoordinateTransformer = class {
|
|
6094
|
+
/** Normalized spatial metadata describing this transformation. */
|
|
6095
|
+
spatialReference;
|
|
6096
|
+
/** Projection from the source CRS directly to the requested horizontal target CRS. */
|
|
6097
|
+
horizontalProjection;
|
|
6098
|
+
/** Projection from the source CRS to geographic longitude, latitude, and ellipsoidal height. */
|
|
6099
|
+
geographicProjection;
|
|
6100
|
+
/** Projection from adjusted geographic coordinates to the requested output CRS. */
|
|
6101
|
+
heightOutputProjection;
|
|
6102
|
+
/** Whether source coordinates use the WGS84 geocentric frame handled by math.gl. */
|
|
6103
|
+
sourceIsGeocentric;
|
|
6104
|
+
/** Whether output coordinates use the WGS84 geocentric frame handled by math.gl. */
|
|
6105
|
+
outputIsGeocentric;
|
|
6106
|
+
/** Whether source coordinates already use conventional WGS84 longitude/latitude order. */
|
|
6107
|
+
sourceIsGeographic;
|
|
6108
|
+
/** Whether output coordinates use conventional WGS84 longitude/latitude order. */
|
|
6109
|
+
outputIsGeographic;
|
|
6110
|
+
/** Geoid model used to convert between ellipsoidal and orthometric heights. */
|
|
6111
|
+
geoid;
|
|
6112
|
+
/**
|
|
6113
|
+
* Creates a coordinate transformer.
|
|
6114
|
+
*
|
|
6115
|
+
* @param spatialReference - Format-discovered and option-normalized spatial metadata.
|
|
6116
|
+
* @param options - Application options containing an optional geoid model.
|
|
6117
|
+
*/
|
|
6118
|
+
constructor(spatialReference, options = {}) {
|
|
6119
|
+
this.spatialReference = spatialReference;
|
|
6120
|
+
validateTransformRequest(spatialReference);
|
|
6121
|
+
const outputCrs = spatialReference.targetCrs || spatialReference.sourceCrs;
|
|
6122
|
+
this.sourceIsGeocentric = isWgs84Geocentric(spatialReference.sourceCrs);
|
|
6123
|
+
this.outputIsGeocentric = isWgs84Geocentric(outputCrs);
|
|
6124
|
+
this.sourceIsGeographic = isWgs84Geographic(spatialReference.sourceCrs);
|
|
6125
|
+
this.outputIsGeographic = isWgs84Geographic(outputCrs);
|
|
6126
|
+
if (spatialReference.sourceCrs && spatialReference.targetCrs && !this.sourceIsGeocentric && !this.outputIsGeocentric) {
|
|
6127
|
+
this.horizontalProjection = new import_proj42.Proj4Projection({
|
|
6128
|
+
from: getHorizontalProj4Definition(spatialReference.sourceCrs),
|
|
6129
|
+
to: getHorizontalProj4Definition(spatialReference.targetCrs),
|
|
6130
|
+
enforceAxis: false
|
|
6131
|
+
});
|
|
6132
|
+
}
|
|
6133
|
+
if (requiresHeightTransformation(spatialReference) || this.sourceIsGeocentric || this.outputIsGeocentric) {
|
|
6134
|
+
if (!this.sourceIsGeographic && !this.sourceIsGeocentric) {
|
|
6135
|
+
this.geographicProjection = new import_proj42.Proj4Projection({
|
|
6136
|
+
from: getHorizontalProj4Definition(spatialReference.sourceCrs),
|
|
6137
|
+
to: GEOGRAPHIC_CRS2,
|
|
6138
|
+
enforceAxis: false
|
|
6139
|
+
});
|
|
6140
|
+
}
|
|
6141
|
+
if (!this.outputIsGeographic && !this.outputIsGeocentric) {
|
|
6142
|
+
this.heightOutputProjection = new import_proj42.Proj4Projection({
|
|
6143
|
+
from: GEOGRAPHIC_CRS2,
|
|
6144
|
+
to: getHorizontalProj4Definition(outputCrs),
|
|
6145
|
+
enforceAxis: false
|
|
6146
|
+
});
|
|
6147
|
+
}
|
|
6148
|
+
}
|
|
6149
|
+
if (requiresHeightTransformation(spatialReference)) {
|
|
6150
|
+
this.geoid = resolveGeoid(options.geoidModel);
|
|
6151
|
+
if (!this.geoid) {
|
|
6152
|
+
const modelName = typeof options.geoidModel === "string" ? ` "${options.geoidModel}"` : "";
|
|
6153
|
+
throw new Error(`Height conversion requires a registered geoid model${modelName}; call registerGeoidModel() or pass a parsed Geoid instance`);
|
|
6154
|
+
}
|
|
6155
|
+
}
|
|
6156
|
+
}
|
|
6157
|
+
/**
|
|
6158
|
+
* Transforms one `[x, y, z?]` coordinate while retaining additional components.
|
|
6159
|
+
*
|
|
6160
|
+
* @param coordinate - Source coordinate in the format adapter's normalized `x/y/z` order.
|
|
6161
|
+
* @returns A new transformed coordinate array.
|
|
6162
|
+
*/
|
|
6163
|
+
transformPosition(coordinate) {
|
|
6164
|
+
if (coordinate.length < 2) {
|
|
6165
|
+
throw new Error("A spatial coordinate must contain at least x and y components");
|
|
6166
|
+
}
|
|
6167
|
+
const result = [...coordinate];
|
|
6168
|
+
if (requiresHeightTransformation(this.spatialReference) || this.sourceIsGeocentric || this.outputIsGeocentric) {
|
|
6169
|
+
if (result.length < 3 || !Number.isFinite(result[2])) {
|
|
6170
|
+
throw new Error("Three-dimensional CRS conversion requires a finite z coordinate");
|
|
6171
|
+
}
|
|
6172
|
+
const geographic = this.toGeographic(result);
|
|
6173
|
+
if (requiresHeightTransformation(this.spatialReference)) {
|
|
6174
|
+
const geoidUndulation = this.geoid.getHeight(geographic[1], geographic[0]);
|
|
6175
|
+
geographic[2] = transformHeight(geographic[2], geoidUndulation, this.spatialReference.heightReference, this.spatialReference.targetHeightReference);
|
|
6176
|
+
}
|
|
6177
|
+
const projected = this.fromGeographic(geographic);
|
|
6178
|
+
result.splice(0, projected.length, ...projected);
|
|
6179
|
+
return result;
|
|
6180
|
+
}
|
|
6181
|
+
if (this.horizontalProjection) {
|
|
6182
|
+
const projected = this.horizontalProjection.project(result.slice(0, 3));
|
|
6183
|
+
result.splice(0, projected.length, ...projected);
|
|
6184
|
+
}
|
|
6185
|
+
return result;
|
|
6186
|
+
}
|
|
6187
|
+
/** Convert one source coordinate to conventional WGS84 longitude, latitude, and height. */
|
|
6188
|
+
toGeographic(coordinate) {
|
|
6189
|
+
if (this.sourceIsGeocentric) {
|
|
6190
|
+
return Array.from(import_geospatial8.Ellipsoid.WGS84.cartesianToCartographic(new import_core11.Vector3(coordinate)));
|
|
6191
|
+
}
|
|
6192
|
+
if (this.sourceIsGeographic) {
|
|
6193
|
+
return coordinate.slice(0, 3);
|
|
6194
|
+
}
|
|
6195
|
+
return this.geographicProjection.project(coordinate.slice(0, 3));
|
|
6196
|
+
}
|
|
6197
|
+
/** Convert one conventional WGS84 geographic coordinate to the selected output CRS. */
|
|
6198
|
+
fromGeographic(coordinate) {
|
|
6199
|
+
if (this.outputIsGeocentric) {
|
|
6200
|
+
return Array.from(import_geospatial8.Ellipsoid.WGS84.cartographicToCartesian(new import_core11.Vector3(coordinate)));
|
|
6201
|
+
}
|
|
6202
|
+
if (this.outputIsGeographic) {
|
|
6203
|
+
return coordinate.slice(0, 3);
|
|
6204
|
+
}
|
|
6205
|
+
return this.heightOutputProjection.project(coordinate.slice(0, 3));
|
|
6206
|
+
}
|
|
6207
|
+
};
|
|
6208
|
+
function getHorizontalProj4Definition(definition) {
|
|
6209
|
+
if (!definition) {
|
|
6210
|
+
throw new Error("Cannot construct a projection because the CRS is unknown");
|
|
6211
|
+
}
|
|
6212
|
+
return (0, import_proj42.toProj4CRSDefinition)(definition, { mode: "horizontal" });
|
|
6213
|
+
}
|
|
6214
|
+
function validateTransformRequest(spatialReference) {
|
|
6215
|
+
if (spatialReference.outputCoordinates === "local-enu") {
|
|
6216
|
+
throw new Error("local-enu output requires a dataset-derived local origin and must be created by a tileset source");
|
|
6217
|
+
}
|
|
6218
|
+
if (spatialReference.outputCoordinates === "target-crs" && !spatialReference.targetCrs) {
|
|
6219
|
+
throw new Error("target-crs output requires targetCrs");
|
|
6220
|
+
}
|
|
6221
|
+
if (!spatialReference.sourceCrs && spatialReference.status === "unresolved") {
|
|
6222
|
+
throw new Error("Cannot transform coordinates because the source CRS is unknown");
|
|
6223
|
+
}
|
|
6224
|
+
if (requiresHeightTransformation(spatialReference) && spatialReference.heightReference === "unknown") {
|
|
6225
|
+
throw new Error("Cannot convert heights because the source height reference is unknown");
|
|
6226
|
+
}
|
|
6227
|
+
if (spatialReference.coordinateFrame === "geocentric" && !isWgs84Geocentric(spatialReference.sourceCrs)) {
|
|
6228
|
+
throw new Error("Only EPSG:4978 geocentric coordinates are supported by the current spatial transformer");
|
|
6229
|
+
}
|
|
6230
|
+
if (spatialReference.status === "unresolved") {
|
|
6231
|
+
throw new Error("The requested spatial output cannot be resolved from the available metadata");
|
|
6232
|
+
}
|
|
6233
|
+
}
|
|
6234
|
+
function isWgs84Geocentric(definition) {
|
|
6235
|
+
return typeof definition === "string" && normalizeCrsIdentifier2(definition) === GEOCENTRIC_CRS2;
|
|
6236
|
+
}
|
|
6237
|
+
function isWgs84Geographic(definition) {
|
|
6238
|
+
if (typeof definition !== "string") {
|
|
6239
|
+
return false;
|
|
6240
|
+
}
|
|
6241
|
+
const identifier = normalizeCrsIdentifier2(definition);
|
|
6242
|
+
return identifier === GEOGRAPHIC_CRS2 || identifier === "EPSG:4979" || identifier === "OGC:CRS84";
|
|
6243
|
+
}
|
|
6244
|
+
function normalizeCrsIdentifier2(identifier) {
|
|
6245
|
+
const normalizedIdentifier = identifier.trim().toUpperCase();
|
|
6246
|
+
const ogcMatch = normalizedIdentifier.match(/(?:\/DEF\/CRS\/|URN:OGC:DEF:CRS:)([A-Z0-9_-]+)(?:\/|::)(?:[^/:]*[/:])?([A-Z0-9_.-]+)$/);
|
|
6247
|
+
return ogcMatch ? `${ogcMatch[1]}:${ogcMatch[2]}` : normalizedIdentifier;
|
|
6248
|
+
}
|
|
6249
|
+
function requiresHeightTransformation(spatialReference) {
|
|
6250
|
+
const target = spatialReference.targetHeightReference;
|
|
6251
|
+
return target !== "native" && target !== spatialReference.heightReference;
|
|
6252
|
+
}
|
|
6253
|
+
function resolveGeoid(model) {
|
|
6254
|
+
return typeof model === "string" ? getGeoidModel(model) : model;
|
|
6255
|
+
}
|
|
6256
|
+
function transformHeight(height, geoidUndulation, source, target) {
|
|
6257
|
+
if (source === target || target === "native") {
|
|
6258
|
+
return height;
|
|
6259
|
+
}
|
|
6260
|
+
if (source === "orthometric" && target === "ellipsoidal") {
|
|
6261
|
+
return height + geoidUndulation;
|
|
6262
|
+
}
|
|
6263
|
+
if (source === "ellipsoidal" && target === "orthometric") {
|
|
6264
|
+
return height - geoidUndulation;
|
|
6265
|
+
}
|
|
6266
|
+
throw new Error(`Unsupported height conversion from ${source} to ${target}`);
|
|
6267
|
+
}
|
|
6268
|
+
|
|
6269
|
+
// dist/spatial/i3s-spatial-transformer.js
|
|
6270
|
+
var I3SSpatialTransformer = class {
|
|
6271
|
+
/** Descriptor attached to output after all adapter-owned spatial values have been transformed. */
|
|
6272
|
+
spatialReference;
|
|
6273
|
+
/** Broad coordinate frame of the selected output CRS. */
|
|
6274
|
+
targetCoordinateFrame;
|
|
6275
|
+
/** Source-to-target position operation. */
|
|
6276
|
+
positionTransformer;
|
|
6277
|
+
/** Source-to-WGS84 geographic operation used for vector-frame conversion. */
|
|
6278
|
+
sourceToGeographicTransformer;
|
|
6279
|
+
/** WGS84-geographic-to-target operation used for normal finite differences. */
|
|
6280
|
+
geographicToTargetTransformer;
|
|
6281
|
+
/** Source frame recorded by I3S metadata. */
|
|
6282
|
+
sourceCoordinateFrame;
|
|
6283
|
+
/** Source Z multiplier that normalizes stored elevation values to meters. */
|
|
6284
|
+
sourceVerticalUnitScale;
|
|
6285
|
+
/** I3S elevation placement mode. */
|
|
6286
|
+
elevationMode;
|
|
6287
|
+
/** I3S elevation offset normalized to meters. */
|
|
6288
|
+
elevationOffset;
|
|
6289
|
+
/** Terrain or scene provider selected for the declared placement mode. */
|
|
6290
|
+
elevationProvider;
|
|
6291
|
+
/** Provider height multiplier that normalizes returned values to meters. */
|
|
6292
|
+
providerUnitScale;
|
|
6293
|
+
/** Optional provider-height to layer-height datum operation. */
|
|
6294
|
+
providerHeightTransformer;
|
|
6295
|
+
/**
|
|
6296
|
+
* Creates an I3S spatial adapter.
|
|
6297
|
+
*
|
|
6298
|
+
* @param spatialReference - Transformable I3S spatial descriptor.
|
|
6299
|
+
* @param options - Registered geoid and custom resource options used by the shared transformer.
|
|
6300
|
+
*/
|
|
6301
|
+
constructor(spatialReference, options = {}) {
|
|
6302
|
+
var _a;
|
|
6303
|
+
if (spatialReference.status !== "transformable" && spatialReference.status !== "transformed") {
|
|
6304
|
+
throw new Error("I3SSpatialTransformer requires a requested, transformable spatial output");
|
|
6305
|
+
}
|
|
6306
|
+
const targetCrs = spatialReference.targetCrs || spatialReference.sourceCrs;
|
|
6307
|
+
if (!targetCrs) {
|
|
6308
|
+
throw new Error("I3S spatial transformation requires a target CRS");
|
|
6309
|
+
}
|
|
6310
|
+
this.positionTransformer = new SpatialCoordinateTransformer(spatialReference, options);
|
|
6311
|
+
this.sourceCoordinateFrame = spatialReference.coordinateFrame;
|
|
6312
|
+
this.sourceVerticalUnitScale = spatialReference.verticalUnitScale;
|
|
6313
|
+
this.elevationMode = spatialReference.elevationMode;
|
|
6314
|
+
this.elevationOffset = (spatialReference.elevationOffset || 0) * spatialReference.elevationUnitScale;
|
|
6315
|
+
this.elevationProvider = getElevationProvider(this.elevationMode, options);
|
|
6316
|
+
if (this.elevationProvider && (typeof this.elevationProvider.sampleElevations !== "function" || typeof this.elevationProvider.getElevationRange !== "function")) {
|
|
6317
|
+
throw new Error("An I3S elevation provider must implement sampleElevations() and getElevationRange()");
|
|
6318
|
+
}
|
|
6319
|
+
const providerUnitScale = getI3SLinearUnitScale(((_a = this.elevationProvider) == null ? void 0 : _a.unit) || "meter");
|
|
6320
|
+
if (this.elevationProvider && providerUnitScale === void 0) {
|
|
6321
|
+
throw new Error(`Unsupported elevation-provider unit ${this.elevationProvider.unit}`);
|
|
6322
|
+
}
|
|
6323
|
+
this.providerUnitScale = providerUnitScale || 1;
|
|
6324
|
+
this.targetCoordinateFrame = getSpatialCoordinateFrame(targetCrs);
|
|
6325
|
+
this.spatialReference = markTilesetSpatialReferenceTransformed(spatialReference);
|
|
6326
|
+
const sourceToGeographicReference = createTilesetSpatialReference({
|
|
6327
|
+
sourceCrs: spatialReference.sourceCrs,
|
|
6328
|
+
heightReference: spatialReference.heightReference,
|
|
6329
|
+
coordinateFrame: spatialReference.coordinateFrame,
|
|
6330
|
+
axisOrder: spatialReference.axisOrder,
|
|
6331
|
+
provenance: spatialReference.provenance
|
|
6332
|
+
}, { targetCrs: "EPSG:4326" });
|
|
6333
|
+
this.sourceToGeographicTransformer = new SpatialCoordinateTransformer(sourceToGeographicReference);
|
|
6334
|
+
if (requiresElevationSurface(this.elevationMode)) {
|
|
6335
|
+
if (!this.elevationProvider) {
|
|
6336
|
+
const providerName = this.elevationMode === "relativeToScene" ? "scene" : "terrain";
|
|
6337
|
+
throw new Error(`I3S elevation mode ${this.elevationMode} requires a ${providerName} elevation provider`);
|
|
6338
|
+
}
|
|
6339
|
+
if (spatialReference.heightReference === "unknown") {
|
|
6340
|
+
throw new Error(`I3S elevation mode ${this.elevationMode} requires a known source height reference`);
|
|
6341
|
+
}
|
|
6342
|
+
const providerHeightReference = this.elevationProvider.heightReference || spatialReference.heightReference;
|
|
6343
|
+
if (providerHeightReference !== spatialReference.heightReference) {
|
|
6344
|
+
if (spatialReference.heightReference !== "ellipsoidal" && spatialReference.heightReference !== "orthometric") {
|
|
6345
|
+
throw new Error("Converting elevation-provider heights requires an ellipsoidal or orthometric source height reference");
|
|
6346
|
+
}
|
|
6347
|
+
const providerHeightSpatialReference = createTilesetSpatialReference({
|
|
6348
|
+
sourceCrs: "EPSG:4326",
|
|
6349
|
+
heightReference: providerHeightReference,
|
|
6350
|
+
coordinateFrame: "geographic",
|
|
6351
|
+
axisOrder: "xyz",
|
|
6352
|
+
provenance: "caller-override"
|
|
6353
|
+
}, {
|
|
6354
|
+
targetCrs: "EPSG:4326",
|
|
6355
|
+
targetHeightReference: spatialReference.heightReference,
|
|
6356
|
+
geoidModel: options.geoidModel
|
|
6357
|
+
});
|
|
6358
|
+
this.providerHeightTransformer = new SpatialCoordinateTransformer(providerHeightSpatialReference, options);
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
const geographicToTargetReference = createTilesetSpatialReference({
|
|
6362
|
+
sourceCrs: "EPSG:4326",
|
|
6363
|
+
heightReference: spatialReference.heightReference,
|
|
6364
|
+
coordinateFrame: "geographic",
|
|
6365
|
+
axisOrder: "xyz",
|
|
6366
|
+
provenance: "format-default"
|
|
6367
|
+
}, {
|
|
6368
|
+
targetCrs,
|
|
6369
|
+
targetHeightReference: spatialReference.targetHeightReference,
|
|
6370
|
+
geoidModel: options.geoidModel
|
|
6371
|
+
});
|
|
6372
|
+
this.geographicToTargetTransformer = new SpatialCoordinateTransformer(geographicToTargetReference, options);
|
|
6373
|
+
}
|
|
6374
|
+
/** Transform one absolute I3S source position. */
|
|
6375
|
+
transformPosition(position) {
|
|
6376
|
+
const placedPosition = this.placeSourcePositionsSync(position);
|
|
6377
|
+
const transformed = this.positionTransformer.transformPosition([
|
|
6378
|
+
placedPosition[0],
|
|
6379
|
+
placedPosition[1],
|
|
6380
|
+
placedPosition[2]
|
|
6381
|
+
]);
|
|
6382
|
+
return [transformed[0], transformed[1], transformed[2]];
|
|
6383
|
+
}
|
|
6384
|
+
/** Transform one absolute I3S source position after asynchronous surface placement. */
|
|
6385
|
+
async transformPositionAsync(position) {
|
|
6386
|
+
const placedPosition = await this.placeSourcePositions(position);
|
|
6387
|
+
const transformed = this.positionTransformer.transformPosition([
|
|
6388
|
+
placedPosition[0],
|
|
6389
|
+
placedPosition[1],
|
|
6390
|
+
placedPosition[2]
|
|
6391
|
+
]);
|
|
6392
|
+
return [transformed[0], transformed[1], transformed[2]];
|
|
6393
|
+
}
|
|
6394
|
+
/** Transform an already placed, meter-normalized position to the requested target. */
|
|
6395
|
+
transformPlacedPosition(position) {
|
|
6396
|
+
const transformed = this.positionTransformer.transformPosition([
|
|
6397
|
+
position[0],
|
|
6398
|
+
position[1],
|
|
6399
|
+
position[2]
|
|
6400
|
+
]);
|
|
6401
|
+
return [transformed[0], transformed[1], transformed[2]];
|
|
6402
|
+
}
|
|
6403
|
+
/** Transform one absolute I3S source position to WGS84 longitude, latitude, and height. */
|
|
6404
|
+
transformSourcePositionToGeographic(position) {
|
|
6405
|
+
const placedPosition = this.placeSourcePositionsSync(position);
|
|
6406
|
+
const transformed = this.sourceToGeographicTransformer.transformPosition([
|
|
6407
|
+
placedPosition[0],
|
|
6408
|
+
placedPosition[1],
|
|
6409
|
+
placedPosition[2]
|
|
6410
|
+
]);
|
|
6411
|
+
return [transformed[0], transformed[1], transformed[2]];
|
|
6412
|
+
}
|
|
6413
|
+
/** Transform one source position to WGS84 after asynchronous elevation placement. */
|
|
6414
|
+
async transformSourcePositionToGeographicAsync(position) {
|
|
6415
|
+
const placedPosition = await this.placeSourcePositions(position);
|
|
6416
|
+
const transformed = this.sourceToGeographicTransformer.transformPosition([
|
|
6417
|
+
placedPosition[0],
|
|
6418
|
+
placedPosition[1],
|
|
6419
|
+
placedPosition[2]
|
|
6420
|
+
]);
|
|
6421
|
+
return [transformed[0], transformed[1], transformed[2]];
|
|
6422
|
+
}
|
|
6423
|
+
/**
|
|
6424
|
+
* Transform absolute Float64 positions and return stable Float32 offsets around a target origin.
|
|
6425
|
+
*
|
|
6426
|
+
* @param sourcePositions - Absolute positions in source CRS order.
|
|
6427
|
+
* @param sourceOrigin - Stable source origin, normally the node MBS or OBB center.
|
|
6428
|
+
*/
|
|
6429
|
+
transformPositions(sourcePositions, sourceOrigin) {
|
|
6430
|
+
const placedSourcePositions = this.placeSourcePositionsSync(sourcePositions);
|
|
6431
|
+
const placedSourceOrigin = this.placeSourcePositionsSync(sourceOrigin);
|
|
6432
|
+
return this.transformPlacedPositions(placedSourcePositions, placedSourceOrigin);
|
|
6433
|
+
}
|
|
6434
|
+
/**
|
|
6435
|
+
* Transform positions after asynchronously sampling any requested terrain or scene surface.
|
|
6436
|
+
*
|
|
6437
|
+
* @param sourcePositions - Absolute positions in source CRS order.
|
|
6438
|
+
* @param sourceOrigin - Stable source origin, normally the node MBS or OBB center.
|
|
6439
|
+
* @returns Renderer-ready target-frame offsets and stable origin metadata.
|
|
6440
|
+
*/
|
|
6441
|
+
async transformPositionsAsync(sourcePositions, sourceOrigin) {
|
|
6442
|
+
const combinedPositions = new Float64Array(sourcePositions.length + 3);
|
|
6443
|
+
combinedPositions.set(Array.from(sourcePositions), 0);
|
|
6444
|
+
combinedPositions.set(Array.from(sourceOrigin).slice(0, 3), sourcePositions.length);
|
|
6445
|
+
const placedPositions = await this.placeSourcePositions(combinedPositions);
|
|
6446
|
+
return this.transformPlacedPositions(placedPositions.subarray(0, sourcePositions.length), placedPositions.subarray(sourcePositions.length));
|
|
6447
|
+
}
|
|
6448
|
+
/** Transform already placed positions into renderer-relative target coordinates. */
|
|
6449
|
+
transformPlacedPositions(sourcePositions, sourceOrigin) {
|
|
6450
|
+
const origin = this.transformPlacedPosition(sourceOrigin);
|
|
6451
|
+
const positions = new Float32Array(sourcePositions.length);
|
|
6452
|
+
const absoluteSourcePositions = Float64Array.from(sourcePositions);
|
|
6453
|
+
for (let index = 0; index < sourcePositions.length; index += 3) {
|
|
6454
|
+
const transformed = this.transformPlacedPosition([
|
|
6455
|
+
sourcePositions[index],
|
|
6456
|
+
sourcePositions[index + 1],
|
|
6457
|
+
sourcePositions[index + 2]
|
|
6458
|
+
]);
|
|
6459
|
+
positions[index] = transformed[0] - origin[0];
|
|
6460
|
+
positions[index + 1] = transformed[1] - origin[1];
|
|
6461
|
+
positions[index + 2] = transformed[2] - origin[2];
|
|
6462
|
+
}
|
|
6463
|
+
const isGeographic = this.targetCoordinateFrame === "geographic";
|
|
6464
|
+
const modelMatrix = isGeographic ? new import_core12.Matrix4() : new import_core12.Matrix4().translate(origin);
|
|
6465
|
+
return {
|
|
6466
|
+
positions,
|
|
6467
|
+
sourcePositions: absoluteSourcePositions,
|
|
6468
|
+
origin,
|
|
6469
|
+
cartographicOrigin: isGeographic ? origin : [0, 0, 0],
|
|
6470
|
+
coordinateSystem: isGeographic ? "lnglat-offsets" : "cartesian",
|
|
6471
|
+
modelMatrix
|
|
6472
|
+
};
|
|
6473
|
+
}
|
|
6474
|
+
/**
|
|
6475
|
+
* Transform I3S normals into the selected target basis.
|
|
6476
|
+
*
|
|
6477
|
+
* Earth-centered normals are rotated directly. Vertex-reference-frame normals are first mapped
|
|
6478
|
+
* through the local east/north/up basis at each source position.
|
|
6479
|
+
*
|
|
6480
|
+
* @param normals - Three-component normal vectors.
|
|
6481
|
+
* @param sourcePositions - Absolute source position paired with each normal.
|
|
6482
|
+
* @param normalReferenceFrame - I3S normal frame declaration.
|
|
6483
|
+
*/
|
|
6484
|
+
transformNormals(normals, sourcePositions, normalReferenceFrame = "earth-centered") {
|
|
6485
|
+
const transformedNormals = new Float32Array(normals.length);
|
|
6486
|
+
for (let index = 0; index < normals.length; index += 3) {
|
|
6487
|
+
const geographic = this.sourceToGeographicTransformer.transformPosition([
|
|
6488
|
+
sourcePositions[index],
|
|
6489
|
+
sourcePositions[index + 1],
|
|
6490
|
+
sourcePositions[index + 2]
|
|
6491
|
+
]);
|
|
6492
|
+
const inputNormal = new import_core12.Vector3([
|
|
6493
|
+
normals[index],
|
|
6494
|
+
normals[index + 1],
|
|
6495
|
+
normals[index + 2]
|
|
6496
|
+
]).normalize();
|
|
6497
|
+
const ecefNormal = normalReferenceFrame === "earth-centered" ? inputNormal : localEnuVectorToEcef(inputNormal, geographic);
|
|
6498
|
+
const outputNormal = this.transformEcefNormal(ecefNormal, geographic);
|
|
6499
|
+
transformedNormals.set(outputNormal, index);
|
|
6500
|
+
}
|
|
6501
|
+
return transformedNormals;
|
|
6502
|
+
}
|
|
6503
|
+
/**
|
|
6504
|
+
* Rebuild an I3S node bound from transformed corner or sphere-axis samples.
|
|
6505
|
+
*
|
|
6506
|
+
* @param bounds - Source MBS/OBB fields.
|
|
6507
|
+
* @returns A generic tile `region` for geographic output or axis-aligned `box` otherwise.
|
|
6508
|
+
*/
|
|
6509
|
+
transformBoundingVolume(bounds) {
|
|
6510
|
+
const geographicSamples = this.getGeographicBoundSamples(bounds);
|
|
6511
|
+
const targetSamples = geographicSamples.map((position) => this.geographicToTargetTransformer.transformPosition(position));
|
|
6512
|
+
return this.targetCoordinateFrame === "geographic" ? { region: getGeographicRegion(targetSamples) } : { box: getAxisAlignedBox(targetSamples) };
|
|
6513
|
+
}
|
|
6514
|
+
/** Rebuild an I3S bound in the target frame after asynchronous elevation placement. */
|
|
6515
|
+
async transformBoundingVolumeAsync(bounds) {
|
|
6516
|
+
const geographicSamples = await this.getGeographicBoundSamplesAsync(bounds);
|
|
6517
|
+
const targetSamples = geographicSamples.map((position) => this.geographicToTargetTransformer.transformPosition(position));
|
|
6518
|
+
return this.targetCoordinateFrame === "geographic" ? { region: getGeographicRegion(targetSamples) } : { box: getAxisAlignedBox(targetSamples) };
|
|
6519
|
+
}
|
|
6520
|
+
/** Rebuild an I3S bound as a WGS84 geographic region for geographic traversal algorithms. */
|
|
6521
|
+
transformBoundingVolumeToGeographic(bounds) {
|
|
6522
|
+
return { region: getGeographicRegion(this.getGeographicBoundSamples(bounds)) };
|
|
6523
|
+
}
|
|
6524
|
+
/** Rebuild an I3S bound as WGS84 geographic after asynchronous elevation placement. */
|
|
6525
|
+
async transformBoundingVolumeToGeographicAsync(bounds) {
|
|
6526
|
+
return { region: getGeographicRegion(await this.getGeographicBoundSamplesAsync(bounds)) };
|
|
6527
|
+
}
|
|
6528
|
+
/** Rebuild an I3S bound as a WGS84 ECEF box for generic `Tileset3D` traversal. */
|
|
6529
|
+
transformBoundingVolumeToGeocentric(bounds) {
|
|
6530
|
+
const cartesianSamples = this.getGeographicBoundSamples(bounds).map((position) => Array.from(import_geospatial9.Ellipsoid.WGS84.cartographicToCartesian(new import_core12.Vector3(position))));
|
|
6531
|
+
return { box: getAxisAlignedBox(cartesianSamples) };
|
|
6532
|
+
}
|
|
6533
|
+
/** Rebuild an I3S bound as WGS84 ECEF after asynchronous elevation placement. */
|
|
6534
|
+
async transformBoundingVolumeToGeocentricAsync(bounds) {
|
|
6535
|
+
const cartesianSamples = (await this.getGeographicBoundSamplesAsync(bounds)).map((position) => Array.from(import_geospatial9.Ellipsoid.WGS84.cartographicToCartesian(new import_core12.Vector3(position))));
|
|
6536
|
+
return { box: getAxisAlignedBox(cartesianSamples) };
|
|
6537
|
+
}
|
|
6538
|
+
/** Return a WGS84 geographic MBS used by the I3S screen-threshold calculation. */
|
|
6539
|
+
transformBoundingSphereToGeographic(bounds) {
|
|
6540
|
+
var _a, _b;
|
|
6541
|
+
const sourceCenter = ((_a = bounds.mbs) == null ? void 0 : _a.length) ? Array.from(bounds.mbs).slice(0, 3) : bounds.obb ? Array.from(bounds.obb.center).slice(0, 3) : null;
|
|
6542
|
+
if (!sourceCenter) {
|
|
6543
|
+
throw new Error("I3S spatial transformation requires an MBS or OBB bound");
|
|
6544
|
+
}
|
|
6545
|
+
const placedCenter = this.placeSourcePositionsSync(sourceCenter);
|
|
6546
|
+
const geographicCenter = this.sourceToGeographicTransformer.transformPosition(Array.from(placedCenter));
|
|
6547
|
+
const radius = ((_b = bounds.mbs) == null ? void 0 : _b.length) ? bounds.mbs[3] : Math.hypot(...Array.from(bounds.obb.halfSize).slice(0, 3));
|
|
6548
|
+
return [geographicCenter[0], geographicCenter[1], geographicCenter[2], radius];
|
|
6549
|
+
}
|
|
6550
|
+
/** Return a placed WGS84 MBS used by the I3S screen-threshold calculation. */
|
|
6551
|
+
async transformBoundingSphereToGeographicAsync(bounds) {
|
|
6552
|
+
return getGeographicBoundingSphere(await this.getGeographicBoundSamplesAsync(bounds));
|
|
6553
|
+
}
|
|
6554
|
+
/**
|
|
6555
|
+
* Rebuild traversal, target-output, and I3S LOD bounds from one elevation-sampling batch.
|
|
6556
|
+
*
|
|
6557
|
+
* @param bounds - Source MBS/OBB fields.
|
|
6558
|
+
* @returns Parallel bounds in WGS84 ECEF, the selected output frame, and WGS84 geographic.
|
|
6559
|
+
*/
|
|
6560
|
+
async transformBoundsAsync(bounds) {
|
|
6561
|
+
const geographicSamples = await this.getGeographicBoundSamplesAsync(bounds);
|
|
6562
|
+
const cartesianSamples = geographicSamples.map((position) => Array.from(import_geospatial9.Ellipsoid.WGS84.cartographicToCartesian(new import_core12.Vector3(position))));
|
|
6563
|
+
const targetSamples = geographicSamples.map((position) => this.geographicToTargetTransformer.transformPosition(position));
|
|
6564
|
+
return {
|
|
6565
|
+
boundingVolume: { box: getAxisAlignedBox(cartesianSamples) },
|
|
6566
|
+
spatialBoundingVolume: this.targetCoordinateFrame === "geographic" ? { region: getGeographicRegion(targetSamples) } : { box: getAxisAlignedBox(targetSamples) },
|
|
6567
|
+
i3sLodMbs: requiresElevationSurface(this.elevationMode) ? getGeographicBoundingSphere(geographicSamples) : this.transformBoundingSphereToGeographic(bounds)
|
|
6568
|
+
};
|
|
6569
|
+
}
|
|
6570
|
+
/**
|
|
6571
|
+
* Rebuild Point Cloud traversal and target-output bounds from one elevation-sampling batch.
|
|
6572
|
+
*
|
|
6573
|
+
* @param bounds - Source OBB fields.
|
|
6574
|
+
* @returns WGS84 geographic traversal bound plus the selected output-frame bound.
|
|
6575
|
+
*/
|
|
6576
|
+
async transformPointCloudBoundsAsync(bounds) {
|
|
6577
|
+
const geographicSamples = await this.getGeographicBoundSamplesAsync(bounds);
|
|
6578
|
+
const targetSamples = geographicSamples.map((position) => this.geographicToTargetTransformer.transformPosition(position));
|
|
6579
|
+
return {
|
|
6580
|
+
boundingVolume: { region: getGeographicRegion(geographicSamples) },
|
|
6581
|
+
spatialBoundingVolume: this.targetCoordinateFrame === "geographic" ? { region: getGeographicRegion(targetSamples) } : { box: getAxisAlignedBox(targetSamples) }
|
|
6582
|
+
};
|
|
6583
|
+
}
|
|
6584
|
+
/** Sample a source I3S bound and normalize every sample to WGS84 geographic coordinates. */
|
|
6585
|
+
getGeographicBoundSamples(bounds) {
|
|
6586
|
+
const sourceSamples = getSourceBoundSamples(bounds, this.sourceCoordinateFrame, this.sourceToGeographicTransformer, this.sourceVerticalUnitScale);
|
|
6587
|
+
if (!sourceSamples.length) {
|
|
6588
|
+
throw new Error("I3S spatial transformation requires an MBS or OBB bound");
|
|
6589
|
+
}
|
|
6590
|
+
const placedSourceSamples = this.placeSourcePositionsSync(sourceSamples.flat(), true);
|
|
6591
|
+
const placedSamples = toPositionArrays(placedSourceSamples);
|
|
6592
|
+
return this.sourceCoordinateFrame === "geographic" ? placedSamples : placedSamples.map((position) => this.sourceToGeographicTransformer.transformPosition(position));
|
|
6593
|
+
}
|
|
6594
|
+
/** Sample, place, and normalize one source bound to WGS84 geographic coordinates. */
|
|
6595
|
+
async getGeographicBoundSamplesAsync(bounds) {
|
|
6596
|
+
const sourceSamples = getSourceBoundSamples(bounds, this.sourceCoordinateFrame, this.sourceToGeographicTransformer, this.sourceVerticalUnitScale);
|
|
6597
|
+
if (!sourceSamples.length) {
|
|
6598
|
+
throw new Error("I3S spatial transformation requires an MBS or OBB bound");
|
|
6599
|
+
}
|
|
6600
|
+
if (requiresElevationSurface(this.elevationMode)) {
|
|
6601
|
+
const geographicSamples = this.sourceCoordinateFrame === "geographic" ? sourceSamples : sourceSamples.map((position) => this.sourceToGeographicTransformer.transformPosition(position));
|
|
6602
|
+
return await this.placeGeographicBoundSamples(geographicSamples);
|
|
6603
|
+
}
|
|
6604
|
+
const placedSamples = toPositionArrays(await this.placeSourcePositions(sourceSamples.flat(), true));
|
|
6605
|
+
return this.sourceCoordinateFrame === "geographic" ? placedSamples : placedSamples.map((position) => this.sourceToGeographicTransformer.transformPosition(position));
|
|
6606
|
+
}
|
|
6607
|
+
/** Apply a provider's conservative surface range to an entire geographic bound footprint. */
|
|
6608
|
+
async placeGeographicBoundSamples(geographicSamples) {
|
|
6609
|
+
const elevationProvider = this.elevationProvider;
|
|
6610
|
+
const elevationRange = await elevationProvider.getElevationRange(getElevationBounds(geographicSamples));
|
|
6611
|
+
const minimumProviderHeight = elevationRange.minimum * this.providerUnitScale;
|
|
6612
|
+
const maximumProviderHeight = elevationRange.maximum * this.providerUnitScale;
|
|
6613
|
+
if (!Number.isFinite(minimumProviderHeight) || !Number.isFinite(maximumProviderHeight) || minimumProviderHeight > maximumProviderHeight) {
|
|
6614
|
+
throw new Error("Elevation provider returned an invalid range; minimum and maximum must be finite and ordered");
|
|
6615
|
+
}
|
|
6616
|
+
const sourceHeights = geographicSamples.map((position) => position[2]);
|
|
6617
|
+
const minimumSourceHeight = Math.min(...sourceHeights);
|
|
6618
|
+
const maximumSourceHeight = Math.max(...sourceHeights);
|
|
6619
|
+
const placedSamples = [];
|
|
6620
|
+
for (const [longitude, latitude] of geographicSamples) {
|
|
6621
|
+
const convertedMinimum = this.providerHeightTransformer ? this.providerHeightTransformer.transformPosition([
|
|
6622
|
+
longitude,
|
|
6623
|
+
latitude,
|
|
6624
|
+
minimumProviderHeight
|
|
6625
|
+
])[2] : minimumProviderHeight;
|
|
6626
|
+
const convertedMaximum = this.providerHeightTransformer ? this.providerHeightTransformer.transformPosition([
|
|
6627
|
+
longitude,
|
|
6628
|
+
latitude,
|
|
6629
|
+
maximumProviderHeight
|
|
6630
|
+
])[2] : maximumProviderHeight;
|
|
6631
|
+
const minimumSurfaceHeight = Math.min(convertedMinimum, convertedMaximum);
|
|
6632
|
+
const maximumSurfaceHeight = Math.max(convertedMinimum, convertedMaximum);
|
|
6633
|
+
const minimumHeight = this.elevationMode === "onTheGround" ? minimumSurfaceHeight : minimumSurfaceHeight + minimumSourceHeight + this.elevationOffset;
|
|
6634
|
+
const maximumHeight = this.elevationMode === "onTheGround" ? maximumSurfaceHeight : maximumSurfaceHeight + maximumSourceHeight + this.elevationOffset;
|
|
6635
|
+
placedSamples.push([longitude, latitude, minimumHeight], [longitude, latitude, maximumHeight]);
|
|
6636
|
+
}
|
|
6637
|
+
return placedSamples;
|
|
6638
|
+
}
|
|
6639
|
+
/** Apply source units and non-surface placement without awaiting external resources. */
|
|
6640
|
+
placeSourcePositionsSync(sourcePositions, sourceHeightsAreMeters = false) {
|
|
6641
|
+
if (requiresElevationSurface(this.elevationMode)) {
|
|
6642
|
+
throw new Error(`I3S elevation mode ${this.elevationMode} requires asynchronous surface placement`);
|
|
6643
|
+
}
|
|
6644
|
+
const positions = Float64Array.from(sourcePositions);
|
|
6645
|
+
const offset = this.elevationMode === "absoluteHeight" ? this.elevationOffset : 0;
|
|
6646
|
+
for (let index = 2; index < positions.length; index += 3) {
|
|
6647
|
+
positions[index] = positions[index] * (sourceHeightsAreMeters ? 1 : this.sourceVerticalUnitScale) + offset;
|
|
6648
|
+
}
|
|
6649
|
+
return positions;
|
|
6650
|
+
}
|
|
6651
|
+
/** Apply source units and all I3S elevation-placement modes. */
|
|
6652
|
+
async placeSourcePositions(sourcePositions, sourceHeightsAreMeters = false) {
|
|
6653
|
+
if (!requiresElevationSurface(this.elevationMode)) {
|
|
6654
|
+
return this.placeSourcePositionsSync(sourcePositions, sourceHeightsAreMeters);
|
|
6655
|
+
}
|
|
6656
|
+
const positions = Float64Array.from(sourcePositions);
|
|
6657
|
+
const geographicLocations = toPositionArrays(positions).map((position) => {
|
|
6658
|
+
const geographic = this.sourceToGeographicTransformer.transformPosition(position);
|
|
6659
|
+
return [geographic[0], geographic[1]];
|
|
6660
|
+
});
|
|
6661
|
+
const sampledHeights = await this.elevationProvider.sampleElevations(geographicLocations);
|
|
6662
|
+
if (sampledHeights.length !== geographicLocations.length) {
|
|
6663
|
+
throw new Error(`Elevation provider returned ${sampledHeights.length} heights for ${geographicLocations.length} positions`);
|
|
6664
|
+
}
|
|
6665
|
+
for (let positionIndex = 0; positionIndex < geographicLocations.length; positionIndex++) {
|
|
6666
|
+
const sampledHeight = sampledHeights[positionIndex] * this.providerUnitScale;
|
|
6667
|
+
if (!Number.isFinite(sampledHeight)) {
|
|
6668
|
+
throw new Error(`Elevation provider returned a non-finite height at index ${positionIndex}`);
|
|
6669
|
+
}
|
|
6670
|
+
const [longitude, latitude] = geographicLocations[positionIndex];
|
|
6671
|
+
const surfaceHeight = this.providerHeightTransformer ? this.providerHeightTransformer.transformPosition([longitude, latitude, sampledHeight])[2] : sampledHeight;
|
|
6672
|
+
const sourceHeight = positions[positionIndex * 3 + 2] * (sourceHeightsAreMeters ? 1 : this.sourceVerticalUnitScale);
|
|
6673
|
+
positions[positionIndex * 3 + 2] = this.elevationMode === "onTheGround" ? surfaceHeight : surfaceHeight + sourceHeight + this.elevationOffset;
|
|
6674
|
+
}
|
|
6675
|
+
return positions;
|
|
6676
|
+
}
|
|
6677
|
+
/** Transform one earth-centered normal to the selected target basis. */
|
|
6678
|
+
transformEcefNormal(ecefNormal, geographic) {
|
|
6679
|
+
if (this.targetCoordinateFrame === "geocentric") {
|
|
6680
|
+
return ecefNormal.normalize();
|
|
6681
|
+
}
|
|
6682
|
+
if (this.targetCoordinateFrame === "geographic") {
|
|
6683
|
+
return ecefVectorToLocalEnu(ecefNormal, geographic).normalize();
|
|
6684
|
+
}
|
|
6685
|
+
const cartesian = import_geospatial9.Ellipsoid.WGS84.cartographicToCartesian(new import_core12.Vector3(geographic));
|
|
6686
|
+
const jacobianColumns = [];
|
|
6687
|
+
for (const direction of getPositiveAxisDirections()) {
|
|
6688
|
+
const positiveGeographic = import_geospatial9.Ellipsoid.WGS84.cartesianToCartographic(new import_core12.Vector3(cartesian).add(direction));
|
|
6689
|
+
const negativeGeographic = import_geospatial9.Ellipsoid.WGS84.cartesianToCartographic(new import_core12.Vector3(cartesian).subtract(direction));
|
|
6690
|
+
const positiveTarget = this.geographicToTargetTransformer.transformPosition(positiveGeographic);
|
|
6691
|
+
const negativeTarget = this.geographicToTargetTransformer.transformPosition(negativeGeographic);
|
|
6692
|
+
jacobianColumns.push((positiveTarget[0] - negativeTarget[0]) / 2, (positiveTarget[1] - negativeTarget[1]) / 2, (positiveTarget[2] - negativeTarget[2]) / 2);
|
|
6693
|
+
}
|
|
6694
|
+
const normalMatrix = new import_core12.Matrix3(jacobianColumns);
|
|
6695
|
+
if (Math.abs(normalMatrix.determinant()) < 1e-12) {
|
|
6696
|
+
throw new Error("Cannot transform an I3S normal through a singular local projection");
|
|
6697
|
+
}
|
|
6698
|
+
normalMatrix.invert().transpose();
|
|
6699
|
+
return new import_core12.Vector3(ecefNormal).transformByMatrix3(normalMatrix).normalize();
|
|
6700
|
+
}
|
|
6701
|
+
};
|
|
6702
|
+
function getElevationProvider(mode, options) {
|
|
6703
|
+
return mode === "relativeToScene" ? options.sceneElevationProvider : requiresElevationSurface(mode) ? options.terrainElevationProvider : void 0;
|
|
6704
|
+
}
|
|
6705
|
+
function requiresElevationSurface(mode) {
|
|
6706
|
+
return mode === "onTheGround" || mode === "relativeToGround" || mode === "relativeToScene";
|
|
6707
|
+
}
|
|
6708
|
+
function toPositionArrays(positions) {
|
|
6709
|
+
if (positions.length % 3 !== 0) {
|
|
6710
|
+
throw new Error("I3S position arrays must contain complete XYZ tuples");
|
|
6711
|
+
}
|
|
6712
|
+
const result = [];
|
|
6713
|
+
for (let index = 0; index < positions.length; index += 3) {
|
|
6714
|
+
result.push([positions[index], positions[index + 1], positions[index + 2]]);
|
|
6715
|
+
}
|
|
6716
|
+
return result;
|
|
6717
|
+
}
|
|
6718
|
+
function getElevationBounds(geographicSamples) {
|
|
6719
|
+
const region = getGeographicRegion(geographicSamples);
|
|
6720
|
+
return {
|
|
6721
|
+
west: region[0] * 180 / Math.PI,
|
|
6722
|
+
south: region[1] * 180 / Math.PI,
|
|
6723
|
+
east: region[2] * 180 / Math.PI,
|
|
6724
|
+
north: region[3] * 180 / Math.PI
|
|
6725
|
+
};
|
|
6726
|
+
}
|
|
6727
|
+
function getGeographicBoundingSphere(geographicSamples) {
|
|
6728
|
+
if (!geographicSamples.length) {
|
|
6729
|
+
throw new Error("I3S spatial transformation requires at least one bound sample");
|
|
6730
|
+
}
|
|
6731
|
+
const cartesianSamples = geographicSamples.map((position) => import_geospatial9.Ellipsoid.WGS84.cartographicToCartesian(new import_core12.Vector3(position)));
|
|
6732
|
+
const cartesianCenter = new import_core12.Vector3();
|
|
6733
|
+
for (const sample of cartesianSamples) {
|
|
6734
|
+
cartesianCenter.add(sample);
|
|
6735
|
+
}
|
|
6736
|
+
cartesianCenter.scale(1 / cartesianSamples.length);
|
|
6737
|
+
let radius = 0;
|
|
6738
|
+
for (const sample of cartesianSamples) {
|
|
6739
|
+
radius = Math.max(radius, new import_core12.Vector3(sample).subtract(cartesianCenter).magnitude());
|
|
6740
|
+
}
|
|
6741
|
+
const geographicCenter = import_geospatial9.Ellipsoid.WGS84.cartesianToCartographic(cartesianCenter);
|
|
6742
|
+
return [geographicCenter[0], geographicCenter[1], geographicCenter[2], radius];
|
|
6743
|
+
}
|
|
6744
|
+
function getSourceBoundSamples(bounds, sourceFrame, sourceToGeographicTransformer, sourceVerticalUnitScale) {
|
|
6745
|
+
const obb = bounds.obb;
|
|
6746
|
+
if (obb) {
|
|
6747
|
+
const center2 = Array.from(obb.center).slice(0, 3);
|
|
6748
|
+
center2[2] *= sourceVerticalUnitScale;
|
|
6749
|
+
const halfSize = Array.from(obb.halfSize).slice(0, 3);
|
|
6750
|
+
const quaternion = new import_core12.Quaternion().fromArray(Array.from(obb.quaternion));
|
|
6751
|
+
const axes = [
|
|
6752
|
+
new import_core12.Vector3([halfSize[0], 0, 0]).transformByQuaternion(quaternion),
|
|
6753
|
+
new import_core12.Vector3([0, halfSize[1], 0]).transformByQuaternion(quaternion),
|
|
6754
|
+
new import_core12.Vector3([0, 0, halfSize[2]]).transformByQuaternion(quaternion)
|
|
6755
|
+
];
|
|
6756
|
+
if (sourceFrame === "geographic") {
|
|
6757
|
+
const geographicCenter = sourceToGeographicTransformer.transformPosition(center2);
|
|
6758
|
+
const cartesianCenter = import_geospatial9.Ellipsoid.WGS84.cartographicToCartesian(new import_core12.Vector3(geographicCenter));
|
|
6759
|
+
const cartesianAxes = bounds.normalReferenceFrame === "vertex-reference-frame" ? axes.map((axis) => localEnuVectorToEcef(axis, geographicCenter)) : axes;
|
|
6760
|
+
return getBoxSigns().map((signs) => {
|
|
6761
|
+
const corner = new import_core12.Vector3(cartesianCenter);
|
|
6762
|
+
for (let axisIndex = 0; axisIndex < 3; axisIndex++) {
|
|
6763
|
+
corner.add(new import_core12.Vector3(cartesianAxes[axisIndex]).scale(signs[axisIndex]));
|
|
6764
|
+
}
|
|
6765
|
+
return Array.from(import_geospatial9.Ellipsoid.WGS84.cartesianToCartographic(corner));
|
|
6766
|
+
});
|
|
6767
|
+
}
|
|
6768
|
+
return getBoxSigns().map((signs) => {
|
|
6769
|
+
const corner = new import_core12.Vector3(center2);
|
|
6770
|
+
for (let axisIndex = 0; axisIndex < 3; axisIndex++) {
|
|
6771
|
+
corner.add(new import_core12.Vector3(axes[axisIndex]).scale(signs[axisIndex]));
|
|
6772
|
+
}
|
|
6773
|
+
return Array.from(corner);
|
|
6774
|
+
});
|
|
6775
|
+
}
|
|
6776
|
+
const mbs = bounds.mbs ? Array.from(bounds.mbs) : [];
|
|
6777
|
+
if (mbs.length < 4) {
|
|
6778
|
+
return [];
|
|
6779
|
+
}
|
|
6780
|
+
const center = mbs.slice(0, 3);
|
|
6781
|
+
center[2] *= sourceVerticalUnitScale;
|
|
6782
|
+
const radius = mbs[3];
|
|
6783
|
+
if (sourceFrame === "geographic") {
|
|
6784
|
+
const geographicCenter = sourceToGeographicTransformer.transformPosition(center);
|
|
6785
|
+
const cartesianCenter = import_geospatial9.Ellipsoid.WGS84.cartographicToCartesian(new import_core12.Vector3(geographicCenter));
|
|
6786
|
+
return getAxisDirections().map((direction) => Array.from(import_geospatial9.Ellipsoid.WGS84.cartesianToCartographic(new import_core12.Vector3(cartesianCenter).add(new import_core12.Vector3(direction).scale(radius)))));
|
|
6787
|
+
}
|
|
6788
|
+
return getAxisDirections().map((direction) => Array.from(new import_core12.Vector3(center).add(new import_core12.Vector3(direction).scale(radius))));
|
|
6789
|
+
}
|
|
6790
|
+
function getBoxSigns() {
|
|
6791
|
+
return [-1, 1].flatMap((x) => [-1, 1].flatMap((y) => [-1, 1].map((z) => [x, y, z])));
|
|
6792
|
+
}
|
|
6793
|
+
function getAxisDirections() {
|
|
6794
|
+
return [
|
|
6795
|
+
[1, 0, 0],
|
|
6796
|
+
[-1, 0, 0],
|
|
6797
|
+
[0, 1, 0],
|
|
6798
|
+
[0, -1, 0],
|
|
6799
|
+
[0, 0, 1],
|
|
6800
|
+
[0, 0, -1]
|
|
6801
|
+
];
|
|
6802
|
+
}
|
|
6803
|
+
function getPositiveAxisDirections() {
|
|
6804
|
+
return [new import_core12.Vector3([1, 0, 0]), new import_core12.Vector3([0, 1, 0]), new import_core12.Vector3([0, 0, 1])];
|
|
6805
|
+
}
|
|
6806
|
+
function localEnuVectorToEcef(vector, geographic) {
|
|
6807
|
+
const longitude = geographic[0] * Math.PI / 180;
|
|
6808
|
+
const latitude = geographic[1] * Math.PI / 180;
|
|
6809
|
+
const east = new import_core12.Vector3([-Math.sin(longitude), Math.cos(longitude), 0]);
|
|
6810
|
+
const north = new import_core12.Vector3([
|
|
6811
|
+
-Math.sin(latitude) * Math.cos(longitude),
|
|
6812
|
+
-Math.sin(latitude) * Math.sin(longitude),
|
|
6813
|
+
Math.cos(latitude)
|
|
6814
|
+
]);
|
|
6815
|
+
const up = new import_core12.Vector3([
|
|
6816
|
+
Math.cos(latitude) * Math.cos(longitude),
|
|
6817
|
+
Math.cos(latitude) * Math.sin(longitude),
|
|
6818
|
+
Math.sin(latitude)
|
|
6819
|
+
]);
|
|
6820
|
+
return east.scale(vector[0]).add(north.scale(vector[1])).add(up.scale(vector[2]));
|
|
6821
|
+
}
|
|
6822
|
+
function ecefVectorToLocalEnu(vector, geographic) {
|
|
6823
|
+
const longitude = geographic[0] * Math.PI / 180;
|
|
6824
|
+
const latitude = geographic[1] * Math.PI / 180;
|
|
6825
|
+
const east = new import_core12.Vector3([-Math.sin(longitude), Math.cos(longitude), 0]);
|
|
6826
|
+
const north = new import_core12.Vector3([
|
|
6827
|
+
-Math.sin(latitude) * Math.cos(longitude),
|
|
6828
|
+
-Math.sin(latitude) * Math.sin(longitude),
|
|
6829
|
+
Math.cos(latitude)
|
|
6830
|
+
]);
|
|
6831
|
+
const up = new import_core12.Vector3([
|
|
6832
|
+
Math.cos(latitude) * Math.cos(longitude),
|
|
6833
|
+
Math.cos(latitude) * Math.sin(longitude),
|
|
6834
|
+
Math.sin(latitude)
|
|
6835
|
+
]);
|
|
6836
|
+
return new import_core12.Vector3([east.dot(vector), north.dot(vector), up.dot(vector)]);
|
|
6837
|
+
}
|
|
6838
|
+
function getAxisAlignedBox(positions) {
|
|
6839
|
+
const minimum = [Infinity, Infinity, Infinity];
|
|
6840
|
+
const maximum = [-Infinity, -Infinity, -Infinity];
|
|
6841
|
+
for (const position of positions) {
|
|
6842
|
+
for (let component = 0; component < 3; component++) {
|
|
6843
|
+
minimum[component] = Math.min(minimum[component], position[component]);
|
|
6844
|
+
maximum[component] = Math.max(maximum[component], position[component]);
|
|
6845
|
+
}
|
|
6846
|
+
}
|
|
6847
|
+
const center = minimum.map((value, index) => (value + maximum[index]) / 2);
|
|
6848
|
+
const halfSize = minimum.map((value, index) => (maximum[index] - value) / 2);
|
|
6849
|
+
return [center[0], center[1], center[2], halfSize[0], 0, 0, 0, halfSize[1], 0, 0, 0, halfSize[2]];
|
|
6850
|
+
}
|
|
6851
|
+
function getGeographicRegion(positions) {
|
|
6852
|
+
const referenceLongitude = positions[0][0];
|
|
6853
|
+
let minimumLongitude = Infinity;
|
|
6854
|
+
let maximumLongitude = -Infinity;
|
|
6855
|
+
let minimumLatitude = Infinity;
|
|
6856
|
+
let maximumLatitude = -Infinity;
|
|
6857
|
+
let minimumHeight = Infinity;
|
|
6858
|
+
let maximumHeight = -Infinity;
|
|
6859
|
+
for (const position of positions) {
|
|
6860
|
+
const longitude = referenceLongitude + normalizeLongitude(position[0] - referenceLongitude);
|
|
6861
|
+
minimumLongitude = Math.min(minimumLongitude, longitude);
|
|
6862
|
+
maximumLongitude = Math.max(maximumLongitude, longitude);
|
|
6863
|
+
minimumLatitude = Math.min(minimumLatitude, position[1]);
|
|
6864
|
+
maximumLatitude = Math.max(maximumLatitude, position[1]);
|
|
6865
|
+
minimumHeight = Math.min(minimumHeight, position[2]);
|
|
6866
|
+
maximumHeight = Math.max(maximumHeight, position[2]);
|
|
6867
|
+
}
|
|
6868
|
+
return [
|
|
6869
|
+
normalizeLongitude(minimumLongitude) * Math.PI / 180,
|
|
6870
|
+
minimumLatitude * Math.PI / 180,
|
|
6871
|
+
normalizeLongitude(maximumLongitude) * Math.PI / 180,
|
|
6872
|
+
maximumLatitude * Math.PI / 180,
|
|
6873
|
+
minimumHeight,
|
|
6874
|
+
maximumHeight
|
|
6875
|
+
];
|
|
6876
|
+
}
|
|
6877
|
+
function normalizeLongitude(longitude) {
|
|
6878
|
+
return ((longitude + 180) % 360 + 360) % 360 - 180;
|
|
6879
|
+
}
|
|
6880
|
+
|
|
5265
6881
|
// dist/tileset-3d/format-i3s/i3s-source.js
|
|
5266
6882
|
var EMPTY_CONTENT_FORMATS2 = {
|
|
5267
6883
|
draco: false,
|
|
@@ -5294,6 +6910,10 @@ var I3SSource = class {
|
|
|
5294
6910
|
queryParams = {};
|
|
5295
6911
|
resolver;
|
|
5296
6912
|
rootTileset;
|
|
6913
|
+
/** Spatial adapter created lazily after Tileset3D applies target options. */
|
|
6914
|
+
spatialTransformer;
|
|
6915
|
+
/** Root header prepared after asynchronous elevation sampling. */
|
|
6916
|
+
preparedRootHeader;
|
|
5297
6917
|
/**
|
|
5298
6918
|
* Creates an I3S source.
|
|
5299
6919
|
* @param input Root metadata request, or preloaded root metadata for tests and internal callers.
|
|
@@ -5309,6 +6929,7 @@ var I3SSource = class {
|
|
|
5309
6929
|
this.resolver = request.resolver;
|
|
5310
6930
|
this.coreApi = request.coreApi;
|
|
5311
6931
|
this.loadOptions = loadOptions;
|
|
6932
|
+
this.initializeQueryParams(loadOptions);
|
|
5312
6933
|
}
|
|
5313
6934
|
/**
|
|
5314
6935
|
* Fetches and normalizes root I3S metadata for runtime consumption.
|
|
@@ -5316,19 +6937,12 @@ var I3SSource = class {
|
|
|
5316
6937
|
async initialize() {
|
|
5317
6938
|
var _a;
|
|
5318
6939
|
if (!this.rootTileset) {
|
|
5319
|
-
this.rootTileset = await this.loadRootData(this.url, this.loadOptions);
|
|
6940
|
+
this.rootTileset = await this.loadRootData(this.getTileUrl(this.url), this.loadOptions);
|
|
5320
6941
|
}
|
|
5321
6942
|
this.tileset = this.rootTileset;
|
|
5322
6943
|
if (this.rootTileset.root && typeof this.rootTileset.root.then === "function") {
|
|
5323
6944
|
this.rootTileset.root = await this.rootTileset.root;
|
|
5324
6945
|
}
|
|
5325
|
-
const i3sOptions = this.loadOptions.i3s;
|
|
5326
|
-
if (i3sOptions && typeof i3sOptions === "object" && "token" in i3sOptions) {
|
|
5327
|
-
const token = i3sOptions.token;
|
|
5328
|
-
if (typeof token === "string") {
|
|
5329
|
-
this.queryParams.token = token;
|
|
5330
|
-
}
|
|
5331
|
-
}
|
|
5332
6946
|
this.metadata = {
|
|
5333
6947
|
type: this.type,
|
|
5334
6948
|
loader: this.loader,
|
|
@@ -5337,7 +6951,8 @@ var I3SSource = class {
|
|
|
5337
6951
|
tileset: this.rootTileset,
|
|
5338
6952
|
lodMetricType: this.rootTileset.lodMetricType,
|
|
5339
6953
|
lodMetricValue: this.rootTileset.lodMetricValue,
|
|
5340
|
-
refine: (_a = this.rootTileset.root) == null ? void 0 : _a.refine
|
|
6954
|
+
refine: (_a = this.rootTileset.root) == null ? void 0 : _a.refine,
|
|
6955
|
+
spatialReference: getI3SSpatialReference(this.rootTileset)
|
|
5341
6956
|
};
|
|
5342
6957
|
}
|
|
5343
6958
|
/**
|
|
@@ -5355,11 +6970,28 @@ var I3SSource = class {
|
|
|
5355
6970
|
async getRootTileset() {
|
|
5356
6971
|
return this.getMetadata().tileset;
|
|
5357
6972
|
}
|
|
6973
|
+
/** Prepare option-dependent spatial state and the asynchronously placed root bound. */
|
|
6974
|
+
async prepareTileset(tileset) {
|
|
6975
|
+
const spatialReference = tileset.spatialReference;
|
|
6976
|
+
if (spatialReference.status === "unresolved") {
|
|
6977
|
+
throw new Error(spatialReference.warnings[0] || "I3S spatial operations cannot be resolved from the supplied metadata and options");
|
|
6978
|
+
}
|
|
6979
|
+
if (spatialReference.status !== "transformable" && spatialReference.status !== "transformed") {
|
|
6980
|
+
return;
|
|
6981
|
+
}
|
|
6982
|
+
this.spatialTransformer ||= new I3SSpatialTransformer(spatialReference, tileset.options.spatial);
|
|
6983
|
+
tileset.spatialReference = this.spatialTransformer.spatialReference;
|
|
6984
|
+
this.preparedRootHeader = await this.transformTileHeader(this.getMetadata().tileset.root);
|
|
6985
|
+
}
|
|
5358
6986
|
/**
|
|
5359
6987
|
* Creates the runtime root tile for an I3S subtree.
|
|
5360
6988
|
*/
|
|
5361
6989
|
initializeTileHeaders(tileset, tilesetJson, parentTile) {
|
|
5362
|
-
const
|
|
6990
|
+
const rootHeader = parentTile ? tilesetJson.root : this.preparedRootHeader || tilesetJson.root;
|
|
6991
|
+
if (this.spatialTransformer && !this.preparedRootHeader) {
|
|
6992
|
+
throw new Error("I3S spatial root header was not prepared before tile initialization");
|
|
6993
|
+
}
|
|
6994
|
+
const rootTile = new Tile3D(tileset, rootHeader, parentTile || void 0);
|
|
5363
6995
|
if (parentTile) {
|
|
5364
6996
|
parentTile.children.push(rootTile);
|
|
5365
6997
|
rootTile.depth = parentTile.depth + 1;
|
|
@@ -5388,16 +7020,22 @@ var I3SSource = class {
|
|
|
5388
7020
|
_tileOptions: {
|
|
5389
7021
|
attributeUrls: tile.header.attributeUrls,
|
|
5390
7022
|
textureUrl: tile.header.textureUrl,
|
|
7023
|
+
textureUrls: tile.header.textureUrls,
|
|
5391
7024
|
textureFormat: tile.header.textureFormat,
|
|
5392
7025
|
textureLoaderOptions: tile.header.textureLoaderOptions,
|
|
5393
7026
|
materialDefinition: tile.header.materialDefinition,
|
|
7027
|
+
layerType: tile.header.layerType,
|
|
7028
|
+
pointRenderer: tile.header.pointRenderer,
|
|
7029
|
+
pointSymbol: tile.header.pointSymbol,
|
|
5394
7030
|
isDracoGeometry: tile.header.isDracoGeometry,
|
|
5395
7031
|
mbs: tile.header.mbs
|
|
5396
7032
|
},
|
|
5397
7033
|
_tilesetOptions: {
|
|
5398
7034
|
store: metadata.tileset.store,
|
|
5399
7035
|
attributeStorageInfo: metadata.tileset.attributeStorageInfo,
|
|
5400
|
-
fields: metadata.tileset.fields
|
|
7036
|
+
fields: metadata.tileset.fields,
|
|
7037
|
+
spatialReference: tile.tileset.spatialReference,
|
|
7038
|
+
spatialOptions: tile.tileset.options.spatial
|
|
5401
7039
|
},
|
|
5402
7040
|
isTileHeader: false
|
|
5403
7041
|
}
|
|
@@ -5410,8 +7048,9 @@ var I3SSource = class {
|
|
|
5410
7048
|
*/
|
|
5411
7049
|
async loadChildTileHeader(_parentTile, childId, _frameState) {
|
|
5412
7050
|
const metadata = this.getMetadata();
|
|
5413
|
-
if (metadata.tileset.nodePages) {
|
|
5414
|
-
|
|
7051
|
+
if (metadata.tileset.nodePages || metadata.tileset.pointNodePages) {
|
|
7052
|
+
const header2 = await metadata.tileset.nodePagesTile.formTileFromNodePages(childId);
|
|
7053
|
+
return await this.transformTileHeader(header2);
|
|
5415
7054
|
}
|
|
5416
7055
|
const nodeUrl = this.getTileUrl(`${this.url}/nodes/${childId}`);
|
|
5417
7056
|
const i3sLoaderOptions = this.loadOptions.i3s && typeof this.loadOptions.i3s === "object" ? this.loadOptions.i3s : {};
|
|
@@ -5422,7 +7061,8 @@ var I3SSource = class {
|
|
|
5422
7061
|
isTileHeader: true
|
|
5423
7062
|
}
|
|
5424
7063
|
};
|
|
5425
|
-
|
|
7064
|
+
const header = await this.loadResourceData(nodeUrl, options);
|
|
7065
|
+
return await this.transformTileHeader(header);
|
|
5426
7066
|
}
|
|
5427
7067
|
/**
|
|
5428
7068
|
* Resolves an I3S request URL with source-managed query parameters.
|
|
@@ -5434,21 +7074,51 @@ var I3SSource = class {
|
|
|
5434
7074
|
if (!Object.keys(this.queryParams).length) {
|
|
5435
7075
|
return tilePath;
|
|
5436
7076
|
}
|
|
5437
|
-
const
|
|
5438
|
-
|
|
7077
|
+
const queryDelimiterIndex = tilePath.indexOf("?");
|
|
7078
|
+
if (queryDelimiterIndex === -1) {
|
|
7079
|
+
return `${tilePath}?${new URLSearchParams(this.queryParams).toString()}`;
|
|
7080
|
+
}
|
|
7081
|
+
const existingQuery = tilePath.slice(queryDelimiterIndex + 1);
|
|
7082
|
+
const existingQueryKeys = new Set(existingQuery.split("&").map((parameter) => parameter.split("=", 1)[0]));
|
|
7083
|
+
const queryParams = new URLSearchParams();
|
|
7084
|
+
for (const [key, value] of Object.entries(this.queryParams)) {
|
|
7085
|
+
if (!existingQueryKeys.has(key)) {
|
|
7086
|
+
queryParams.set(key, value);
|
|
7087
|
+
}
|
|
7088
|
+
}
|
|
7089
|
+
const queryString = queryParams.toString();
|
|
7090
|
+
return queryString ? `${tilePath}${existingQuery ? "&" : ""}${queryString}` : tilePath;
|
|
5439
7091
|
}
|
|
5440
7092
|
/**
|
|
5441
7093
|
* Derives the default view state from full extent or store extent metadata.
|
|
5442
7094
|
*/
|
|
5443
|
-
getViewState(
|
|
7095
|
+
getViewState(rootTile) {
|
|
5444
7096
|
var _a;
|
|
7097
|
+
if (this.spatialTransformer && rootTile) {
|
|
7098
|
+
const center = new import_core13.Vector3(rootTile.boundingVolume.center);
|
|
7099
|
+
const cartographicCenter = new import_core13.Vector3(rootTile.header.i3sLodMbs.slice(0, 3));
|
|
7100
|
+
if (this.spatialTransformer.targetCoordinateFrame === "geographic") {
|
|
7101
|
+
return {
|
|
7102
|
+
boundingVolume: rootTile.boundingVolume,
|
|
7103
|
+
cartographicCenter,
|
|
7104
|
+
cartesianCenter: center,
|
|
7105
|
+
zoom: 1
|
|
7106
|
+
};
|
|
7107
|
+
}
|
|
7108
|
+
return {
|
|
7109
|
+
boundingVolume: rootTile.boundingVolume,
|
|
7110
|
+
cartographicCenter,
|
|
7111
|
+
cartesianCenter: center,
|
|
7112
|
+
zoom: 1
|
|
7113
|
+
};
|
|
7114
|
+
}
|
|
5445
7115
|
const metadata = this.getMetadata();
|
|
5446
7116
|
const fullExtent = metadata.tileset.fullExtent;
|
|
5447
7117
|
if (fullExtent) {
|
|
5448
7118
|
const { xmin, xmax, ymin, ymax, zmin, zmax } = fullExtent;
|
|
5449
|
-
const cartographicCenter = new
|
|
5450
|
-
const cartesianCenter = new
|
|
5451
|
-
|
|
7119
|
+
const cartographicCenter = new import_core13.Vector3(xmin + (xmax - xmin) / 2, ymin + (ymax - ymin) / 2, zmin + (zmax - zmin) / 2);
|
|
7120
|
+
const cartesianCenter = new import_core13.Vector3();
|
|
7121
|
+
import_geospatial10.Ellipsoid.WGS84.cartographicToCartesian(cartographicCenter, cartesianCenter);
|
|
5452
7122
|
return {
|
|
5453
7123
|
cartographicCenter,
|
|
5454
7124
|
cartesianCenter,
|
|
@@ -5458,9 +7128,9 @@ var I3SSource = class {
|
|
|
5458
7128
|
const extent = (_a = metadata.tileset.store) == null ? void 0 : _a.extent;
|
|
5459
7129
|
if (extent) {
|
|
5460
7130
|
const [xmin, ymin, xmax, ymax] = extent;
|
|
5461
|
-
const cartographicCenter = new
|
|
5462
|
-
const cartesianCenter = new
|
|
5463
|
-
|
|
7131
|
+
const cartographicCenter = new import_core13.Vector3(xmin + (xmax - xmin) / 2, ymin + (ymax - ymin) / 2, 0);
|
|
7132
|
+
const cartesianCenter = new import_core13.Vector3();
|
|
7133
|
+
import_geospatial10.Ellipsoid.WGS84.cartographicToCartesian(cartographicCenter, cartesianCenter);
|
|
5464
7134
|
return {
|
|
5465
7135
|
cartographicCenter,
|
|
5466
7136
|
cartesianCenter,
|
|
@@ -5469,7 +7139,7 @@ var I3SSource = class {
|
|
|
5469
7139
|
}
|
|
5470
7140
|
console.warn("Extent is not defined in the tileset header");
|
|
5471
7141
|
return {
|
|
5472
|
-
cartographicCenter: new
|
|
7142
|
+
cartographicCenter: new import_core13.Vector3(),
|
|
5473
7143
|
zoom: 1
|
|
5474
7144
|
};
|
|
5475
7145
|
}
|
|
@@ -5516,6 +7186,19 @@ var I3SSource = class {
|
|
|
5516
7186
|
}
|
|
5517
7187
|
return await this.loadWithCoreApi(url, options);
|
|
5518
7188
|
}
|
|
7189
|
+
/**
|
|
7190
|
+
* Initializes query parameters before any URL-backed resource is requested.
|
|
7191
|
+
* @param loadOptions Loader options that may contain an ArcGIS token.
|
|
7192
|
+
*/
|
|
7193
|
+
initializeQueryParams(loadOptions) {
|
|
7194
|
+
const i3sOptions = loadOptions.i3s;
|
|
7195
|
+
if (i3sOptions && typeof i3sOptions === "object" && "token" in i3sOptions) {
|
|
7196
|
+
const token = i3sOptions.token;
|
|
7197
|
+
if (typeof token === "string") {
|
|
7198
|
+
this.queryParams.token = token;
|
|
7199
|
+
}
|
|
7200
|
+
}
|
|
7201
|
+
}
|
|
5519
7202
|
/**
|
|
5520
7203
|
* Loads tile metadata or content through an injected resolver when present, otherwise through the injected core API.
|
|
5521
7204
|
*/
|
|
@@ -5525,6 +7208,27 @@ var I3SSource = class {
|
|
|
5525
7208
|
}
|
|
5526
7209
|
return await this.loadWithCoreApi(url, options);
|
|
5527
7210
|
}
|
|
7211
|
+
/** Transform one I3S header bound after target options and elevation providers are available. */
|
|
7212
|
+
async transformTileHeader(header) {
|
|
7213
|
+
var _a;
|
|
7214
|
+
if (!this.spatialTransformer) {
|
|
7215
|
+
return header;
|
|
7216
|
+
}
|
|
7217
|
+
const sourceBounds = {
|
|
7218
|
+
mbs: header.mbs,
|
|
7219
|
+
obb: header.obb,
|
|
7220
|
+
normalReferenceFrame: (_a = this.getMetadata().tileset.store) == null ? void 0 : _a.normalReferenceFrame
|
|
7221
|
+
};
|
|
7222
|
+
const transformedBounds = await this.spatialTransformer.transformBoundsAsync(sourceBounds);
|
|
7223
|
+
return {
|
|
7224
|
+
...header,
|
|
7225
|
+
// Tileset3D traversal and culling operate in WGS84 ECEF independently of content output.
|
|
7226
|
+
boundingVolume: transformedBounds.boundingVolume,
|
|
7227
|
+
// Preserve the renderer/output-frame bound for applications and content coordination.
|
|
7228
|
+
spatialBoundingVolume: transformedBounds.spatialBoundingVolume,
|
|
7229
|
+
i3sLodMbs: transformedBounds.i3sLodMbs
|
|
7230
|
+
};
|
|
7231
|
+
}
|
|
5528
7232
|
};
|
|
5529
7233
|
function isTilesetRequest2(input) {
|
|
5530
7234
|
return Boolean(input && typeof input === "object" && "url" in input && "loader" in input && !("type" in input));
|
|
@@ -6520,6 +8224,10 @@ var RasterSet = class _RasterSet {
|
|
|
6520
8224
|
static fromRasterSource(rasterSource, opts = {}) {
|
|
6521
8225
|
return new _RasterSet({ ...opts, rasterSource });
|
|
6522
8226
|
}
|
|
8227
|
+
/** Convenience factory for sources whose requests are not viewport-shaped. */
|
|
8228
|
+
static fromCallbacks(opts) {
|
|
8229
|
+
return new _RasterSet(opts);
|
|
8230
|
+
}
|
|
6523
8231
|
/** Whether the manager has no requests in flight and a current raster. */
|
|
6524
8232
|
get isLoaded() {
|
|
6525
8233
|
return this._loadCounter === 0 && Boolean(this._currentRequest);
|
|
@@ -6630,7 +8338,7 @@ var RasterSet = class _RasterSet {
|
|
|
6630
8338
|
try {
|
|
6631
8339
|
const abortController = new AbortController();
|
|
6632
8340
|
this._abortController = abortController;
|
|
6633
|
-
const raster = await this._opts.getRaster(
|
|
8341
|
+
const raster = await this._opts.getRaster(withAbortSignal(parameters, abortController.signal));
|
|
6634
8342
|
if (this._finalized || abortController.signal.aborted || requestId <= this._lastAcceptedRequestId) {
|
|
6635
8343
|
return;
|
|
6636
8344
|
}
|
|
@@ -6724,6 +8432,16 @@ var RasterSet = class _RasterSet {
|
|
|
6724
8432
|
this._abortController = null;
|
|
6725
8433
|
}
|
|
6726
8434
|
};
|
|
8435
|
+
function withAbortSignal(parameters, signal) {
|
|
8436
|
+
const request = Array.isArray(parameters) ? parameters.slice() : Object.create(Object.getPrototypeOf(parameters), Object.getOwnPropertyDescriptors(parameters));
|
|
8437
|
+
Object.defineProperty(request, "signal", {
|
|
8438
|
+
configurable: true,
|
|
8439
|
+
enumerable: true,
|
|
8440
|
+
value: signal,
|
|
8441
|
+
writable: true
|
|
8442
|
+
});
|
|
8443
|
+
return request;
|
|
8444
|
+
}
|
|
6727
8445
|
function normalizeRasterSetError(error, message) {
|
|
6728
8446
|
if (error instanceof Error) {
|
|
6729
8447
|
return error;
|
|
@@ -6738,7 +8456,7 @@ function isAbortError3(error) {
|
|
|
6738
8456
|
}
|
|
6739
8457
|
|
|
6740
8458
|
// dist/point-cloud/point-cloud-tileset.js
|
|
6741
|
-
var
|
|
8459
|
+
var import_core14 = require("@math.gl/core");
|
|
6742
8460
|
var import_culling6 = require("@math.gl/culling");
|
|
6743
8461
|
|
|
6744
8462
|
// dist/point-cloud/point-cloud-tile.js
|
|
@@ -6811,6 +8529,8 @@ var DEFAULT_PROPS5 = {
|
|
|
6811
8529
|
debounceTime: 0,
|
|
6812
8530
|
minimumNodePixelSize: 150,
|
|
6813
8531
|
maximumScreenSpaceError: 1,
|
|
8532
|
+
lodSelectionMetricType: "maxScreenThresholdSQ",
|
|
8533
|
+
densityThreshold: 1,
|
|
6814
8534
|
pointBudget: 2e6,
|
|
6815
8535
|
maxDepth: Number.POSITIVE_INFINITY,
|
|
6816
8536
|
onTileLoad: () => {
|
|
@@ -6900,7 +8620,7 @@ var PointCloudTileset = class {
|
|
|
6900
8620
|
const viewState = await ((_b = (_a = this.dataSource).getViewState) == null ? void 0 : _b.call(_a));
|
|
6901
8621
|
this.boundingVolume = (viewState == null ? void 0 : viewState.boundingVolume) || this.root.boundingVolume;
|
|
6902
8622
|
const center = (viewState == null ? void 0 : viewState.cartographicCenter) || this.root.boundingVolume.center;
|
|
6903
|
-
this.cartographicCenter = new
|
|
8623
|
+
this.cartographicCenter = new import_core14.Vector3(center);
|
|
6904
8624
|
this.zoom = (viewState == null ? void 0 : viewState.zoom) || this.estimateZoom(this.boundingVolume);
|
|
6905
8625
|
}
|
|
6906
8626
|
/**
|
|
@@ -6994,6 +8714,12 @@ var PointCloudTileset = class {
|
|
|
6994
8714
|
}
|
|
6995
8715
|
/** Whether a tile should refine to children based on its projected screen radius. */
|
|
6996
8716
|
shouldRefine(tile, traversalWeight) {
|
|
8717
|
+
if (tile.level < this.options.maxDepth && Number.isFinite(traversalWeight) && (tile.header.lodSelectionMetricType || this.options.lodSelectionMetricType) === "density-threshold") {
|
|
8718
|
+
const projectedArea = Math.max(1, Math.PI * traversalWeight * traversalWeight);
|
|
8719
|
+
const density = tile.pointCount / projectedArea;
|
|
8720
|
+
const threshold = tile.header.lodThreshold || this.options.densityThreshold;
|
|
8721
|
+
return density < threshold;
|
|
8722
|
+
}
|
|
6997
8723
|
return tile.level < this.options.maxDepth && Number.isFinite(traversalWeight) && traversalWeight >= this.options.minimumNodePixelSize;
|
|
6998
8724
|
}
|
|
6999
8725
|
/**
|
|
@@ -7191,9 +8917,13 @@ var PointCloudTileset = class {
|
|
|
7191
8917
|
if (!boundingVolume) {
|
|
7192
8918
|
return 1;
|
|
7193
8919
|
}
|
|
8920
|
+
if (boundingVolume.coordinateFrame === "cartesian") {
|
|
8921
|
+
return 1;
|
|
8922
|
+
}
|
|
7194
8923
|
const [minBounds, maxBounds] = boundingVolume.cartographicBounds;
|
|
7195
|
-
const longitudeSpan =
|
|
7196
|
-
|
|
8924
|
+
const longitudeSpan = boundingVolume.coversFullLongitude ? 360 : boundingVolume.wrapsDateline ? 360 - Math.abs(maxBounds[0] - minBounds[0]) : Math.abs(maxBounds[0] - minBounds[0]);
|
|
8925
|
+
const normalizedLongitudeSpan = Math.max(longitudeSpan, 1e-6);
|
|
8926
|
+
return Math.max(1, Math.round(Math.log2(360 / normalizedLongitudeSpan)));
|
|
7197
8927
|
}
|
|
7198
8928
|
haveSameIds(idsA, idsB) {
|
|
7199
8929
|
if (idsA.size !== idsB.size) {
|
|
@@ -7211,16 +8941,32 @@ var PointCloudTileset = class {
|
|
|
7211
8941
|
*/
|
|
7212
8942
|
getBoundingVolumeCorners(boundingVolume) {
|
|
7213
8943
|
const [minBounds, maxBounds] = boundingVolume.cartographicBounds;
|
|
7214
|
-
|
|
7215
|
-
[minBounds[0],
|
|
7216
|
-
[
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
8944
|
+
const longitudeIntervals = boundingVolume.coversFullLongitude ? [[-180, 180]] : boundingVolume.wrapsDateline ? [
|
|
8945
|
+
[minBounds[0], 180],
|
|
8946
|
+
[-180, maxBounds[0]]
|
|
8947
|
+
] : [[minBounds[0], maxBounds[0]]];
|
|
8948
|
+
const corners = [];
|
|
8949
|
+
const wrappedLongitudeSpan = 360 - Math.abs(maxBounds[0] - minBounds[0]);
|
|
8950
|
+
const longitudeReference = minBounds[0] + wrappedLongitudeSpan / 2;
|
|
8951
|
+
for (const [minimumLongitude, maximumLongitude] of longitudeIntervals) {
|
|
8952
|
+
const normalizeLongitude2 = (longitude) => {
|
|
8953
|
+
if (!boundingVolume.wrapsDateline) {
|
|
8954
|
+
return longitude;
|
|
8955
|
+
}
|
|
8956
|
+
let normalizedLongitude = longitude;
|
|
8957
|
+
while (normalizedLongitude - longitudeReference > 180) {
|
|
8958
|
+
normalizedLongitude -= 360;
|
|
8959
|
+
}
|
|
8960
|
+
while (normalizedLongitude - longitudeReference < -180) {
|
|
8961
|
+
normalizedLongitude += 360;
|
|
8962
|
+
}
|
|
8963
|
+
return normalizedLongitude;
|
|
8964
|
+
};
|
|
8965
|
+
const unwrappedMinimumLongitude = normalizeLongitude2(minimumLongitude);
|
|
8966
|
+
const unwrappedMaximumLongitude = normalizeLongitude2(maximumLongitude);
|
|
8967
|
+
corners.push([unwrappedMinimumLongitude, minBounds[1], minBounds[2] || 0], [unwrappedMinimumLongitude, minBounds[1], maxBounds[2] || 0], [unwrappedMinimumLongitude, maxBounds[1], minBounds[2] || 0], [unwrappedMinimumLongitude, maxBounds[1], maxBounds[2] || 0], [unwrappedMaximumLongitude, minBounds[1], minBounds[2] || 0], [unwrappedMaximumLongitude, minBounds[1], maxBounds[2] || 0], [unwrappedMaximumLongitude, maxBounds[1], minBounds[2] || 0], [unwrappedMaximumLongitude, maxBounds[1], maxBounds[2] || 0]);
|
|
8968
|
+
}
|
|
8969
|
+
return corners;
|
|
7224
8970
|
}
|
|
7225
8971
|
/**
|
|
7226
8972
|
* Build a culling volume directly from the viewport frustum in common space.
|