@loaders.gl/tiles 5.0.0-alpha.5 → 5.0.0-alpha.6

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.
Files changed (41) hide show
  1. package/dist/dist.dev.js +228 -11
  2. package/dist/dist.min.js +2 -2
  3. package/dist/index.cjs +223 -11
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/tileset-3d/common/indexed-archive-tileset-source.d.ts +3 -3
  6. package/dist/tileset-3d/common/indexed-archive-tileset-source.d.ts.map +1 -1
  7. package/dist/tileset-3d/common/indexed-archive-tileset-source.js.map +1 -1
  8. package/dist/tileset-3d/common/tile-3d.d.ts.map +1 -1
  9. package/dist/tileset-3d/common/tile-3d.js +4 -2
  10. package/dist/tileset-3d/common/tile-3d.js.map +1 -1
  11. package/dist/tileset-3d/common/tileset-3d.d.ts +30 -2
  12. package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -1
  13. package/dist/tileset-3d/common/tileset-3d.js +4 -0
  14. package/dist/tileset-3d/common/tileset-3d.js.map +1 -1
  15. package/dist/tileset-3d/common/tileset-source.d.ts +8 -8
  16. package/dist/tileset-3d/common/tileset-source.d.ts.map +1 -1
  17. package/dist/tileset-3d/common/tileset-source.js.map +1 -1
  18. package/dist/tileset-3d/common/tileset-traverser.d.ts +14 -0
  19. package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -1
  20. package/dist/tileset-3d/common/tileset-traverser.js +17 -2
  21. package/dist/tileset-3d/common/tileset-traverser.js.map +1 -1
  22. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts +2 -2
  23. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts.map +1 -1
  24. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js.map +1 -1
  25. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts +65 -0
  26. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts.map +1 -1
  27. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js +209 -0
  28. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js.map +1 -1
  29. package/dist/tileset-3d/format-i3s/i3s-source.d.ts +5 -3
  30. package/dist/tileset-3d/format-i3s/i3s-source.d.ts.map +1 -1
  31. package/dist/tileset-3d/format-i3s/i3s-source.js +14 -7
  32. package/dist/tileset-3d/format-i3s/i3s-source.js.map +1 -1
  33. package/package.json +13 -13
  34. package/src/tileset-3d/common/indexed-archive-tileset-source.ts +4 -9
  35. package/src/tileset-3d/common/tile-3d.ts +6 -2
  36. package/src/tileset-3d/common/tileset-3d.ts +34 -2
  37. package/src/tileset-3d/common/tileset-source.ts +8 -12
  38. package/src/tileset-3d/common/tileset-traverser.ts +28 -2
  39. package/src/tileset-3d/format-3d-tiles/tiles-3d-source.ts +4 -4
  40. package/src/tileset-3d/format-3d-tiles/tileset-3d-traverser.ts +236 -0
  41. package/src/tileset-3d/format-i3s/i3s-source.ts +25 -9
package/dist/dist.dev.js CHANGED
@@ -7063,6 +7063,10 @@ var __exports__ = (() => {
7063
7063
  foveatedTimeDelay: 0.2,
7064
7064
  maximumScreenSpaceError: 8,
7065
7065
  skipLevelOfDetail: false,
7066
+ baseScreenSpaceError: 1024,
7067
+ skipScreenSpaceErrorFactor: 16,
7068
+ skipLevels: 1,
7069
+ immediatelyLoadDesiredLevelOfDetail: false,
7066
7070
  dynamicScreenSpaceError: true,
7067
7071
  dynamicScreenSpaceErrorDensity: 2e-4,
7068
7072
  dynamicScreenSpaceErrorFactor: 24,
@@ -8295,6 +8299,10 @@ var __exports__ = (() => {
8295
8299
  var DEFAULT_PROPS4 = {
8296
8300
  loadSiblings: false,
8297
8301
  skipLevelOfDetail: false,
8302
+ baseScreenSpaceError: 1024,
8303
+ skipScreenSpaceErrorFactor: 16,
8304
+ skipLevels: 1,
8305
+ immediatelyLoadDesiredLevelOfDetail: false,
8298
8306
  updateTransforms: true,
8299
8307
  onTraversalEnd: () => {
8300
8308
  },
@@ -8303,6 +8311,8 @@ var __exports__ = (() => {
8303
8311
  };
8304
8312
  var TilesetTraverser = class {
8305
8313
  options;
8314
+ /** Whether loaded content has disabled skip-LOD traversal for this tileset. */
8315
+ disableSkipLevelOfDetail = false;
8306
8316
  // fulfill in traverse call
8307
8317
  root = null;
8308
8318
  // tiles should be rendered
@@ -8328,6 +8338,10 @@ var __exports__ = (() => {
8328
8338
  constructor(options) {
8329
8339
  this.options = { ...DEFAULT_PROPS4, ...options };
8330
8340
  }
8341
+ /** Returns whether skip-LOD traversal is enabled and supported by the loaded content. */
8342
+ isSkipLevelOfDetailEnabled() {
8343
+ return this.options.skipLevelOfDetail && !this.disableSkipLevelOfDetail;
8344
+ }
8331
8345
  // tiles should be visible
8332
8346
  traverse(root, frameState, options) {
8333
8347
  this.root = root;
@@ -8385,13 +8399,17 @@ var __exports__ = (() => {
8385
8399
  this.selectTile(tile, frameState);
8386
8400
  } else if (tile.refine === 2 /* REPLACE */) {
8387
8401
  this.loadTile(tile, frameState);
8388
- if (stoppedRefining || this.options.skipLevelOfDetail) {
8402
+ if (stoppedRefining || this.isSkipLevelOfDetailEnabled()) {
8389
8403
  this.selectTile(tile, frameState);
8390
8404
  }
8391
8405
  }
8392
8406
  this.touchTile(tile, frameState);
8393
8407
  tile._shouldRefine = shouldRefine && parentRefines;
8394
8408
  }
8409
+ this.completeTraversal(frameState);
8410
+ }
8411
+ /** Notifies the owning tileset when traversal is complete or its debounce interval expires. */
8412
+ completeTraversal(frameState) {
8395
8413
  const newTime = (/* @__PURE__ */ new Date()).getTime();
8396
8414
  if (this.traversalFinished(frameState) || newTime - this.lastUpdate > this.updateDebounceTime) {
8397
8415
  this.lastUpdate = newTime;
@@ -8406,7 +8424,8 @@ var __exports__ = (() => {
8406
8424
  }
8407
8425
  /* eslint-disable complexity, max-statements */
8408
8426
  updateAndPushChildren(tile, frameState, stack, depth) {
8409
- const { loadSiblings, skipLevelOfDetail } = this.options;
8427
+ const { loadSiblings } = this.options;
8428
+ const skipLevelOfDetail = this.isSkipLevelOfDetailEnabled();
8410
8429
  const children = tile.children;
8411
8430
  children.sort(this.compareDistanceToCamera.bind(this));
8412
8431
  const checkRefines = tile.refine === 2 /* REPLACE */ && tile.hasRenderContent && !skipLevelOfDetail;
@@ -8928,7 +8947,7 @@ var __exports__ = (() => {
8928
8947
  // eslint-disable-next-line complexity
8929
8948
  _calculateRequestPriority(allowUnloadedContent) {
8930
8949
  const traverser = this.tileset._traverser;
8931
- const { skipLevelOfDetail } = traverser.options;
8950
+ const skipLevelOfDetail = traverser.options.skipLevelOfDetail && !traverser.disableSkipLevelOfDetail;
8932
8951
  const maySkipTile = this.refine === 1 /* ADD */ || skipLevelOfDetail;
8933
8952
  if (maySkipTile && !this.isVisible && this._visible !== void 0) {
8934
8953
  return -1;
@@ -9158,9 +9177,11 @@ var __exports__ = (() => {
9158
9177
  return;
9159
9178
  }
9160
9179
  this._foveatedFactor = calculateFoveatedFactor(this.boundingVolume, frameState.camera);
9180
+ const traverser = this.tileset._traverser;
9181
+ const skipLevelOfDetail = traverser.options.skipLevelOfDetail && !traverser.disableSkipLevelOfDetail;
9161
9182
  const deferralEligible = isFoveatedRequestDeferred({
9162
9183
  refinement: this.refine,
9163
- skipLevelOfDetail: this.tileset._traverser.options.skipLevelOfDetail,
9184
+ skipLevelOfDetail,
9164
9185
  foveatedScreenSpaceError: options.foveatedScreenSpaceError,
9165
9186
  foveatedConeSize: options.foveatedConeSize,
9166
9187
  minimumScreenSpaceErrorRelaxation: options.foveatedMinimumScreenSpaceErrorRelaxation,
@@ -9424,6 +9445,196 @@ var __exports__ = (() => {
9424
9445
  }
9425
9446
  return true;
9426
9447
  }
9448
+ /**
9449
+ * Runs normal replacement traversal or the dedicated skip-LOD traversal selected by options.
9450
+ *
9451
+ * @param root - Root of the runtime subtree to traverse.
9452
+ * @param frameState - Current culling and LOD state.
9453
+ */
9454
+ executeTraversal(root, frameState) {
9455
+ if (!this.isSkipLevelOfDetailEnabled()) {
9456
+ super.executeTraversal(root, frameState);
9457
+ return;
9458
+ }
9459
+ this.executeSkipTraversal(root, frameState);
9460
+ }
9461
+ /**
9462
+ * Traverses visible replacement branches without requesting skipped intermediate content.
9463
+ *
9464
+ * Base-traversal tiles establish coarse coverage. Below that base, only final desired tiles and
9465
+ * tiles that cross the configured depth/SSE thresholds are requested. Already available
9466
+ * ancestors remain selectable while those requests stream in.
9467
+ *
9468
+ * @param root - Root of the runtime subtree to traverse.
9469
+ * @param frameState - Current culling and LOD state.
9470
+ */
9471
+ executeSkipTraversal(root, frameState) {
9472
+ const stack = [root];
9473
+ root._selectionDepth = root.parent ? root.parent._selectionDepth : 1;
9474
+ while (stack.length > 0) {
9475
+ const tile = stack.pop();
9476
+ const parentRefines = !tile.parent || tile.parent._shouldRefine;
9477
+ const shouldRefine = this.canTraverse(tile, frameState) && this.updateAndPushSkipChildren(tile, frameState, stack) && parentRefines;
9478
+ const stoppedRefining = !shouldRefine && parentRefines;
9479
+ if (!tile.hasRenderContent) {
9480
+ this.emptyTiles[tile.id] = tile;
9481
+ this.loadTile(tile, frameState);
9482
+ if (stoppedRefining) {
9483
+ this.selectDesiredTile(tile, frameState);
9484
+ }
9485
+ } else if (tile.refine === 1 /* ADD */) {
9486
+ this.loadTile(tile, frameState);
9487
+ this.selectDesiredTile(tile, frameState);
9488
+ } else if (tile.refine === 2 /* REPLACE */) {
9489
+ if (this.isInBaseTraversal(tile, frameState)) {
9490
+ this.loadTile(tile, frameState);
9491
+ if (stoppedRefining) {
9492
+ this.selectDesiredTile(tile, frameState);
9493
+ }
9494
+ } else if (stoppedRefining) {
9495
+ this.loadTile(tile, frameState);
9496
+ this.selectDesiredTile(tile, frameState);
9497
+ } else if (this.hasReachedSkippingThreshold(tile, frameState)) {
9498
+ this.loadTile(tile, frameState);
9499
+ }
9500
+ }
9501
+ this.touchTile(tile, frameState);
9502
+ tile._shouldRefine = shouldRefine;
9503
+ }
9504
+ this.completeTraversal(frameState);
9505
+ }
9506
+ /**
9507
+ * Updates and pushes visible children for skip traversal without requiring sibling readiness.
9508
+ *
9509
+ * @param tile - Parent whose children are considered.
9510
+ * @param frameState - Current culling and LOD state.
9511
+ * @param stack - Depth-first traversal stack.
9512
+ * @returns `true` when at least one visible child continues refinement.
9513
+ */
9514
+ updateAndPushSkipChildren(tile, frameState, stack) {
9515
+ this.updateChildTiles(tile, frameState);
9516
+ tile.children.sort(this.compareDistanceToCamera.bind(this));
9517
+ let hasVisibleChild = false;
9518
+ for (const child of tile.children) {
9519
+ child._selectionDepth = tile.hasRenderContent ? tile._selectionDepth + 1 : tile._selectionDepth;
9520
+ if (child.isVisibleAndInRequestVolume) {
9521
+ stack.push(child);
9522
+ hasVisibleChild = true;
9523
+ } else if (this.options.loadSiblings) {
9524
+ this.loadTile(child, frameState);
9525
+ this.touchTile(child, frameState);
9526
+ }
9527
+ }
9528
+ return hasVisibleChild;
9529
+ }
9530
+ /**
9531
+ * Determines whether a tile belongs to the coarse non-skipping portion of the traversal.
9532
+ *
9533
+ * @param tile - Tile considered for loading.
9534
+ * @param frameState - Current traversal frame.
9535
+ * @returns `true` when the tile should always be requested for fallback coverage.
9536
+ */
9537
+ isInBaseTraversal(tile, frameState) {
9538
+ if (this.options.immediatelyLoadDesiredLevelOfDetail) {
9539
+ return false;
9540
+ }
9541
+ if (!this.findNearestRequestedOrLoadedAncestor(tile, frameState)) {
9542
+ return true;
9543
+ }
9544
+ const configuredBaseScreenSpaceError = Number.isFinite(this.options.baseScreenSpaceError) ? Math.max(this.options.baseScreenSpaceError, 0) : 1024;
9545
+ const baseScreenSpaceError = Math.max(
9546
+ configuredBaseScreenSpaceError,
9547
+ tile.tileset.memoryAdjustedScreenSpaceError
9548
+ );
9549
+ if (tile._screenSpaceError === 0 && tile.parent) {
9550
+ return tile.parent._screenSpaceError > baseScreenSpaceError;
9551
+ }
9552
+ return tile._screenSpaceError > baseScreenSpaceError;
9553
+ }
9554
+ /**
9555
+ * Determines whether a skipped branch has crossed its configured request threshold.
9556
+ *
9557
+ * @param tile - Tile considered for loading.
9558
+ * @param frameState - Current traversal frame.
9559
+ * @returns `true` when the tile must be requested instead of skipped.
9560
+ */
9561
+ hasReachedSkippingThreshold(tile, frameState) {
9562
+ if (this.options.immediatelyLoadDesiredLevelOfDetail) {
9563
+ return false;
9564
+ }
9565
+ const progressiveResolutionLeaf = tile._priorityProgressiveResolution && tile._screenSpaceErrorProgressiveResolution <= tile.tileset.memoryAdjustedScreenSpaceError && Boolean(
9566
+ tile.parent && tile.parent._screenSpaceErrorProgressiveResolution > tile.tileset.memoryAdjustedScreenSpaceError
9567
+ );
9568
+ if (progressiveResolutionLeaf) {
9569
+ return true;
9570
+ }
9571
+ const ancestor = this.findNearestRequestedOrLoadedAncestor(tile, frameState);
9572
+ if (!ancestor) {
9573
+ return false;
9574
+ }
9575
+ const skipScreenSpaceErrorFactor = Number.isFinite(this.options.skipScreenSpaceErrorFactor) && this.options.skipScreenSpaceErrorFactor > 0 ? this.options.skipScreenSpaceErrorFactor : 16;
9576
+ const skipLevels = Number.isFinite(this.options.skipLevels) ? Math.max(Math.floor(this.options.skipLevels), 0) : 1;
9577
+ return tile._screenSpaceError < ancestor._screenSpaceError / skipScreenSpaceErrorFactor && tile.depth > ancestor.depth + skipLevels;
9578
+ }
9579
+ /**
9580
+ * Finds the nearest ancestor whose render content is loaded, loading, or requested this frame.
9581
+ *
9582
+ * @param tile - Descendant whose request threshold needs an anchor.
9583
+ * @param frameState - Current traversal frame.
9584
+ * @returns The nearest request anchor, or `null` when none exists.
9585
+ */
9586
+ findNearestRequestedOrLoadedAncestor(tile, frameState) {
9587
+ let ancestor = tile.parent;
9588
+ while (ancestor) {
9589
+ const contentIsUsableAnchor = ancestor.hasRenderContent && !ancestor.contentFailed && (!ancestor.hasUnloadedContent || ancestor._requestedFrame === frameState.frameNumber);
9590
+ if (contentIsUsableAnchor) {
9591
+ return ancestor;
9592
+ }
9593
+ ancestor = ancestor.parent;
9594
+ }
9595
+ return null;
9596
+ }
9597
+ /**
9598
+ * Selects the desired tile, its nearest ready ancestor, or nearby ready descendants.
9599
+ *
9600
+ * @param tile - Tile that ended the desired refinement branch.
9601
+ * @param frameState - Current culling state.
9602
+ */
9603
+ selectDesiredTile(tile, frameState) {
9604
+ let fallbackTile = tile;
9605
+ while (fallbackTile) {
9606
+ if (this.shouldSelectTile(fallbackTile, frameState)) {
9607
+ this.selectTile(fallbackTile, frameState);
9608
+ return;
9609
+ }
9610
+ fallbackTile = fallbackTile.parent;
9611
+ }
9612
+ this.selectLoadedDescendants(tile, frameState);
9613
+ }
9614
+ /**
9615
+ * Selects ready descendants near an unavailable desired tile to reduce temporary empty regions.
9616
+ *
9617
+ * @param root - Unavailable tile whose descendants are searched.
9618
+ * @param frameState - Current culling state.
9619
+ */
9620
+ selectLoadedDescendants(root, frameState) {
9621
+ const stack = [{ tile: root, depth: 0 }];
9622
+ while (stack.length > 0) {
9623
+ const { tile, depth } = stack.pop();
9624
+ for (const child of tile.children) {
9625
+ this.updateTile(child, frameState);
9626
+ if (!child.isVisibleAndInRequestVolume) {
9627
+ continue;
9628
+ }
9629
+ if (child.contentAvailable) {
9630
+ this.selectTile(child, frameState);
9631
+ this.touchTile(child, frameState);
9632
+ } else if (depth < 1) {
9633
+ stack.push({ tile: child, depth: depth + 1 });
9634
+ }
9635
+ }
9636
+ }
9637
+ }
9427
9638
  compareDistanceToCamera(a, b) {
9428
9639
  return b._distanceToCamera === 0 && a._distanceToCamera === 0 ? b._centerZDepth - a._centerZDepth : b._distanceToCamera - a._distanceToCamera;
9429
9640
  }
@@ -21015,8 +21226,10 @@ var __exports__ = (() => {
21015
21226
  var I3SSource = class {
21016
21227
  /** I3S format discriminator. */
21017
21228
  type = "I3S" /* I3S */;
21018
- /** Loader used for tile metadata and content requests. */
21229
+ /** Primary I3S loader used for root and child metadata requests. */
21019
21230
  loader;
21231
+ /** Worker-capable loader used for binary tile content when supplied by the format loader. */
21232
+ contentLoader;
21020
21233
  /** Root I3S layer URL. */
21021
21234
  url;
21022
21235
  /** Base path used for relative tile resource resolution. */
@@ -21051,6 +21264,7 @@ var __exports__ = (() => {
21051
21264
  this.rootTileset = isTilesetRequest2(input) ? null : input;
21052
21265
  this.tileset = this.rootTileset;
21053
21266
  this.loader = request.loader;
21267
+ this.contentLoader = getI3SContentLoader(request.loader);
21054
21268
  this.url = request.url;
21055
21269
  this.basePath = request.basePath || path_exports.dirname(request.url);
21056
21270
  this.resolver = request.resolver;
@@ -21171,7 +21385,7 @@ var __exports__ = (() => {
21171
21385
  isTileHeader: false
21172
21386
  }
21173
21387
  };
21174
- tile.content = await this.loadResourceData(contentUrl, options);
21388
+ tile.content = await this.loadResourceData(contentUrl, options, this.contentLoader);
21175
21389
  return { loaded: true };
21176
21390
  }
21177
21391
  /**
@@ -21306,11 +21520,11 @@ var __exports__ = (() => {
21306
21520
  /**
21307
21521
  * Loads data through injected core APIs so this module stays independent from `@loaders.gl/core`.
21308
21522
  */
21309
- async loadWithCoreApi(url, options) {
21523
+ async loadWithCoreApi(url, options, loader = this.loader) {
21310
21524
  if (!this.coreApi) {
21311
21525
  throw new Error("I3SSource requires an injected coreApi to load tileset data");
21312
21526
  }
21313
- return await this.coreApi.load(url, this.loader, options);
21527
+ return await this.coreApi.load(url, loader, options);
21314
21528
  }
21315
21529
  /**
21316
21530
  * Loads data through an injected resolver when present, otherwise through the injected core API.
@@ -21337,11 +21551,11 @@ var __exports__ = (() => {
21337
21551
  /**
21338
21552
  * Loads tile metadata or content through an injected resolver when present, otherwise through the injected core API.
21339
21553
  */
21340
- async loadResourceData(url, options) {
21554
+ async loadResourceData(url, options, loader = this.loader) {
21341
21555
  if (this.resolver) {
21342
- return await this.resolver.loadResource(url, this.loader, options);
21556
+ return await this.resolver.loadResource(url, loader, options);
21343
21557
  }
21344
- return await this.loadWithCoreApi(url, options);
21558
+ return await this.loadWithCoreApi(url, options, loader);
21345
21559
  }
21346
21560
  /** Transform one I3S header bound after target options and elevation providers are available. */
21347
21561
  async transformTileHeader(header) {
@@ -21364,6 +21578,9 @@ var __exports__ = (() => {
21364
21578
  };
21365
21579
  }
21366
21580
  };
21581
+ function getI3SContentLoader(loader) {
21582
+ return loader.contentLoader || loader;
21583
+ }
21367
21584
  function isTilesetRequest2(input) {
21368
21585
  return Boolean(
21369
21586
  input && typeof input === "object" && "url" in input && "loader" in input && !("type" in input)