@loaders.gl/tiles 5.0.0-alpha.4 → 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 (48) hide show
  1. package/dist/dist.dev.js +476 -1643
  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-2d/adapter.d.ts +2 -3
  6. package/dist/tileset-2d/adapter.d.ts.map +1 -1
  7. package/dist/tileset-2d/tileset-2d.d.ts +2 -3
  8. package/dist/tileset-2d/tileset-2d.d.ts.map +1 -1
  9. package/dist/tileset-2d/tileset-2d.js.map +1 -1
  10. package/dist/tileset-3d/common/indexed-archive-tileset-source.d.ts +3 -3
  11. package/dist/tileset-3d/common/indexed-archive-tileset-source.d.ts.map +1 -1
  12. package/dist/tileset-3d/common/indexed-archive-tileset-source.js.map +1 -1
  13. package/dist/tileset-3d/common/tile-3d.d.ts.map +1 -1
  14. package/dist/tileset-3d/common/tile-3d.js +4 -2
  15. package/dist/tileset-3d/common/tile-3d.js.map +1 -1
  16. package/dist/tileset-3d/common/tileset-3d.d.ts +30 -2
  17. package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -1
  18. package/dist/tileset-3d/common/tileset-3d.js +4 -0
  19. package/dist/tileset-3d/common/tileset-3d.js.map +1 -1
  20. package/dist/tileset-3d/common/tileset-source.d.ts +8 -8
  21. package/dist/tileset-3d/common/tileset-source.d.ts.map +1 -1
  22. package/dist/tileset-3d/common/tileset-source.js.map +1 -1
  23. package/dist/tileset-3d/common/tileset-traverser.d.ts +14 -0
  24. package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -1
  25. package/dist/tileset-3d/common/tileset-traverser.js +17 -2
  26. package/dist/tileset-3d/common/tileset-traverser.js.map +1 -1
  27. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts +2 -2
  28. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts.map +1 -1
  29. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js.map +1 -1
  30. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts +65 -0
  31. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts.map +1 -1
  32. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js +209 -0
  33. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js.map +1 -1
  34. package/dist/tileset-3d/format-i3s/i3s-source.d.ts +5 -3
  35. package/dist/tileset-3d/format-i3s/i3s-source.d.ts.map +1 -1
  36. package/dist/tileset-3d/format-i3s/i3s-source.js +14 -7
  37. package/dist/tileset-3d/format-i3s/i3s-source.js.map +1 -1
  38. package/package.json +13 -13
  39. package/src/tileset-2d/adapter.ts +2 -3
  40. package/src/tileset-2d/tileset-2d.ts +2 -3
  41. package/src/tileset-3d/common/indexed-archive-tileset-source.ts +4 -9
  42. package/src/tileset-3d/common/tile-3d.ts +6 -2
  43. package/src/tileset-3d/common/tileset-3d.ts +34 -2
  44. package/src/tileset-3d/common/tileset-source.ts +8 -12
  45. package/src/tileset-3d/common/tileset-traverser.ts +28 -2
  46. package/src/tileset-3d/format-3d-tiles/tiles-3d-source.ts +4 -4
  47. package/src/tileset-3d/format-3d-tiles/tileset-3d-traverser.ts +236 -0
  48. package/src/tileset-3d/format-i3s/i3s-source.ts +25 -9
package/dist/index.cjs CHANGED
@@ -2495,6 +2495,10 @@ var DEFAULT_PROPS3 = {
2495
2495
  foveatedTimeDelay: 0.2,
2496
2496
  maximumScreenSpaceError: 8,
2497
2497
  skipLevelOfDetail: false,
2498
+ baseScreenSpaceError: 1024,
2499
+ skipScreenSpaceErrorFactor: 16,
2500
+ skipLevels: 1,
2501
+ immediatelyLoadDesiredLevelOfDetail: false,
2498
2502
  dynamicScreenSpaceError: true,
2499
2503
  dynamicScreenSpaceErrorDensity: 2e-4,
2500
2504
  dynamicScreenSpaceErrorFactor: 24,
@@ -3691,6 +3695,10 @@ var ManagedArray = class {
3691
3695
  var DEFAULT_PROPS4 = {
3692
3696
  loadSiblings: false,
3693
3697
  skipLevelOfDetail: false,
3698
+ baseScreenSpaceError: 1024,
3699
+ skipScreenSpaceErrorFactor: 16,
3700
+ skipLevels: 1,
3701
+ immediatelyLoadDesiredLevelOfDetail: false,
3694
3702
  updateTransforms: true,
3695
3703
  onTraversalEnd: () => {
3696
3704
  },
@@ -3699,6 +3707,8 @@ var DEFAULT_PROPS4 = {
3699
3707
  };
3700
3708
  var TilesetTraverser = class {
3701
3709
  options;
3710
+ /** Whether loaded content has disabled skip-LOD traversal for this tileset. */
3711
+ disableSkipLevelOfDetail = false;
3702
3712
  // fulfill in traverse call
3703
3713
  root = null;
3704
3714
  // tiles should be rendered
@@ -3724,6 +3734,10 @@ var TilesetTraverser = class {
3724
3734
  constructor(options) {
3725
3735
  this.options = { ...DEFAULT_PROPS4, ...options };
3726
3736
  }
3737
+ /** Returns whether skip-LOD traversal is enabled and supported by the loaded content. */
3738
+ isSkipLevelOfDetailEnabled() {
3739
+ return this.options.skipLevelOfDetail && !this.disableSkipLevelOfDetail;
3740
+ }
3727
3741
  // tiles should be visible
3728
3742
  traverse(root, frameState, options) {
3729
3743
  this.root = root;
@@ -3776,13 +3790,17 @@ var TilesetTraverser = class {
3776
3790
  this.selectTile(tile, frameState);
3777
3791
  } else if (tile.refine === TILE_REFINEMENT.REPLACE) {
3778
3792
  this.loadTile(tile, frameState);
3779
- if (stoppedRefining || this.options.skipLevelOfDetail) {
3793
+ if (stoppedRefining || this.isSkipLevelOfDetailEnabled()) {
3780
3794
  this.selectTile(tile, frameState);
3781
3795
  }
3782
3796
  }
3783
3797
  this.touchTile(tile, frameState);
3784
3798
  tile._shouldRefine = shouldRefine && parentRefines;
3785
3799
  }
3800
+ this.completeTraversal(frameState);
3801
+ }
3802
+ /** Notifies the owning tileset when traversal is complete or its debounce interval expires. */
3803
+ completeTraversal(frameState) {
3786
3804
  const newTime = (/* @__PURE__ */ new Date()).getTime();
3787
3805
  if (this.traversalFinished(frameState) || newTime - this.lastUpdate > this.updateDebounceTime) {
3788
3806
  this.lastUpdate = newTime;
@@ -3797,7 +3815,8 @@ var TilesetTraverser = class {
3797
3815
  }
3798
3816
  /* eslint-disable complexity, max-statements */
3799
3817
  updateAndPushChildren(tile, frameState, stack, depth) {
3800
- const { loadSiblings, skipLevelOfDetail } = this.options;
3818
+ const { loadSiblings } = this.options;
3819
+ const skipLevelOfDetail = this.isSkipLevelOfDetailEnabled();
3801
3820
  const children = tile.children;
3802
3821
  children.sort(this.compareDistanceToCamera.bind(this));
3803
3822
  const checkRefines = tile.refine === TILE_REFINEMENT.REPLACE && tile.hasRenderContent && !skipLevelOfDetail;
@@ -4307,7 +4326,7 @@ var Tile3D = class {
4307
4326
  // eslint-disable-next-line complexity
4308
4327
  _calculateRequestPriority(allowUnloadedContent) {
4309
4328
  const traverser = this.tileset._traverser;
4310
- const { skipLevelOfDetail } = traverser.options;
4329
+ const skipLevelOfDetail = traverser.options.skipLevelOfDetail && !traverser.disableSkipLevelOfDetail;
4311
4330
  const maySkipTile = this.refine === TILE_REFINEMENT.ADD || skipLevelOfDetail;
4312
4331
  if (maySkipTile && !this.isVisible && this._visible !== void 0) {
4313
4332
  return -1;
@@ -4523,9 +4542,11 @@ var Tile3D = class {
4523
4542
  return;
4524
4543
  }
4525
4544
  this._foveatedFactor = calculateFoveatedFactor(this.boundingVolume, frameState.camera);
4545
+ const traverser = this.tileset._traverser;
4546
+ const skipLevelOfDetail = traverser.options.skipLevelOfDetail && !traverser.disableSkipLevelOfDetail;
4526
4547
  const deferralEligible = isFoveatedRequestDeferred({
4527
4548
  refinement: this.refine,
4528
- skipLevelOfDetail: this.tileset._traverser.options.skipLevelOfDetail,
4549
+ skipLevelOfDetail,
4529
4550
  foveatedScreenSpaceError: options.foveatedScreenSpaceError,
4530
4551
  foveatedConeSize: options.foveatedConeSize,
4531
4552
  minimumScreenSpaceErrorRelaxation: options.foveatedMinimumScreenSpaceErrorRelaxation,
@@ -4770,6 +4791,191 @@ var Tileset3DTraverser = class extends TilesetTraverser {
4770
4791
  }
4771
4792
  return true;
4772
4793
  }
4794
+ /**
4795
+ * Runs normal replacement traversal or the dedicated skip-LOD traversal selected by options.
4796
+ *
4797
+ * @param root - Root of the runtime subtree to traverse.
4798
+ * @param frameState - Current culling and LOD state.
4799
+ */
4800
+ executeTraversal(root, frameState) {
4801
+ if (!this.isSkipLevelOfDetailEnabled()) {
4802
+ super.executeTraversal(root, frameState);
4803
+ return;
4804
+ }
4805
+ this.executeSkipTraversal(root, frameState);
4806
+ }
4807
+ /**
4808
+ * Traverses visible replacement branches without requesting skipped intermediate content.
4809
+ *
4810
+ * Base-traversal tiles establish coarse coverage. Below that base, only final desired tiles and
4811
+ * tiles that cross the configured depth/SSE thresholds are requested. Already available
4812
+ * ancestors remain selectable while those requests stream in.
4813
+ *
4814
+ * @param root - Root of the runtime subtree to traverse.
4815
+ * @param frameState - Current culling and LOD state.
4816
+ */
4817
+ executeSkipTraversal(root, frameState) {
4818
+ const stack = [root];
4819
+ root._selectionDepth = root.parent ? root.parent._selectionDepth : 1;
4820
+ while (stack.length > 0) {
4821
+ const tile = stack.pop();
4822
+ const parentRefines = !tile.parent || tile.parent._shouldRefine;
4823
+ const shouldRefine = this.canTraverse(tile, frameState) && this.updateAndPushSkipChildren(tile, frameState, stack) && parentRefines;
4824
+ const stoppedRefining = !shouldRefine && parentRefines;
4825
+ if (!tile.hasRenderContent) {
4826
+ this.emptyTiles[tile.id] = tile;
4827
+ this.loadTile(tile, frameState);
4828
+ if (stoppedRefining) {
4829
+ this.selectDesiredTile(tile, frameState);
4830
+ }
4831
+ } else if (tile.refine === TILE_REFINEMENT.ADD) {
4832
+ this.loadTile(tile, frameState);
4833
+ this.selectDesiredTile(tile, frameState);
4834
+ } else if (tile.refine === TILE_REFINEMENT.REPLACE) {
4835
+ if (this.isInBaseTraversal(tile, frameState)) {
4836
+ this.loadTile(tile, frameState);
4837
+ if (stoppedRefining) {
4838
+ this.selectDesiredTile(tile, frameState);
4839
+ }
4840
+ } else if (stoppedRefining) {
4841
+ this.loadTile(tile, frameState);
4842
+ this.selectDesiredTile(tile, frameState);
4843
+ } else if (this.hasReachedSkippingThreshold(tile, frameState)) {
4844
+ this.loadTile(tile, frameState);
4845
+ }
4846
+ }
4847
+ this.touchTile(tile, frameState);
4848
+ tile._shouldRefine = shouldRefine;
4849
+ }
4850
+ this.completeTraversal(frameState);
4851
+ }
4852
+ /**
4853
+ * Updates and pushes visible children for skip traversal without requiring sibling readiness.
4854
+ *
4855
+ * @param tile - Parent whose children are considered.
4856
+ * @param frameState - Current culling and LOD state.
4857
+ * @param stack - Depth-first traversal stack.
4858
+ * @returns `true` when at least one visible child continues refinement.
4859
+ */
4860
+ updateAndPushSkipChildren(tile, frameState, stack) {
4861
+ this.updateChildTiles(tile, frameState);
4862
+ tile.children.sort(this.compareDistanceToCamera.bind(this));
4863
+ let hasVisibleChild = false;
4864
+ for (const child of tile.children) {
4865
+ child._selectionDepth = tile.hasRenderContent ? tile._selectionDepth + 1 : tile._selectionDepth;
4866
+ if (child.isVisibleAndInRequestVolume) {
4867
+ stack.push(child);
4868
+ hasVisibleChild = true;
4869
+ } else if (this.options.loadSiblings) {
4870
+ this.loadTile(child, frameState);
4871
+ this.touchTile(child, frameState);
4872
+ }
4873
+ }
4874
+ return hasVisibleChild;
4875
+ }
4876
+ /**
4877
+ * Determines whether a tile belongs to the coarse non-skipping portion of the traversal.
4878
+ *
4879
+ * @param tile - Tile considered for loading.
4880
+ * @param frameState - Current traversal frame.
4881
+ * @returns `true` when the tile should always be requested for fallback coverage.
4882
+ */
4883
+ isInBaseTraversal(tile, frameState) {
4884
+ if (this.options.immediatelyLoadDesiredLevelOfDetail) {
4885
+ return false;
4886
+ }
4887
+ if (!this.findNearestRequestedOrLoadedAncestor(tile, frameState)) {
4888
+ return true;
4889
+ }
4890
+ const configuredBaseScreenSpaceError = Number.isFinite(this.options.baseScreenSpaceError) ? Math.max(this.options.baseScreenSpaceError, 0) : 1024;
4891
+ const baseScreenSpaceError = Math.max(configuredBaseScreenSpaceError, tile.tileset.memoryAdjustedScreenSpaceError);
4892
+ if (tile._screenSpaceError === 0 && tile.parent) {
4893
+ return tile.parent._screenSpaceError > baseScreenSpaceError;
4894
+ }
4895
+ return tile._screenSpaceError > baseScreenSpaceError;
4896
+ }
4897
+ /**
4898
+ * Determines whether a skipped branch has crossed its configured request threshold.
4899
+ *
4900
+ * @param tile - Tile considered for loading.
4901
+ * @param frameState - Current traversal frame.
4902
+ * @returns `true` when the tile must be requested instead of skipped.
4903
+ */
4904
+ hasReachedSkippingThreshold(tile, frameState) {
4905
+ if (this.options.immediatelyLoadDesiredLevelOfDetail) {
4906
+ return false;
4907
+ }
4908
+ const progressiveResolutionLeaf = tile._priorityProgressiveResolution && tile._screenSpaceErrorProgressiveResolution <= tile.tileset.memoryAdjustedScreenSpaceError && Boolean(tile.parent && tile.parent._screenSpaceErrorProgressiveResolution > tile.tileset.memoryAdjustedScreenSpaceError);
4909
+ if (progressiveResolutionLeaf) {
4910
+ return true;
4911
+ }
4912
+ const ancestor = this.findNearestRequestedOrLoadedAncestor(tile, frameState);
4913
+ if (!ancestor) {
4914
+ return false;
4915
+ }
4916
+ const skipScreenSpaceErrorFactor = Number.isFinite(this.options.skipScreenSpaceErrorFactor) && this.options.skipScreenSpaceErrorFactor > 0 ? this.options.skipScreenSpaceErrorFactor : 16;
4917
+ const skipLevels = Number.isFinite(this.options.skipLevels) ? Math.max(Math.floor(this.options.skipLevels), 0) : 1;
4918
+ return tile._screenSpaceError < ancestor._screenSpaceError / skipScreenSpaceErrorFactor && tile.depth > ancestor.depth + skipLevels;
4919
+ }
4920
+ /**
4921
+ * Finds the nearest ancestor whose render content is loaded, loading, or requested this frame.
4922
+ *
4923
+ * @param tile - Descendant whose request threshold needs an anchor.
4924
+ * @param frameState - Current traversal frame.
4925
+ * @returns The nearest request anchor, or `null` when none exists.
4926
+ */
4927
+ findNearestRequestedOrLoadedAncestor(tile, frameState) {
4928
+ let ancestor = tile.parent;
4929
+ while (ancestor) {
4930
+ const contentIsUsableAnchor = ancestor.hasRenderContent && !ancestor.contentFailed && (!ancestor.hasUnloadedContent || ancestor._requestedFrame === frameState.frameNumber);
4931
+ if (contentIsUsableAnchor) {
4932
+ return ancestor;
4933
+ }
4934
+ ancestor = ancestor.parent;
4935
+ }
4936
+ return null;
4937
+ }
4938
+ /**
4939
+ * Selects the desired tile, its nearest ready ancestor, or nearby ready descendants.
4940
+ *
4941
+ * @param tile - Tile that ended the desired refinement branch.
4942
+ * @param frameState - Current culling state.
4943
+ */
4944
+ selectDesiredTile(tile, frameState) {
4945
+ let fallbackTile = tile;
4946
+ while (fallbackTile) {
4947
+ if (this.shouldSelectTile(fallbackTile, frameState)) {
4948
+ this.selectTile(fallbackTile, frameState);
4949
+ return;
4950
+ }
4951
+ fallbackTile = fallbackTile.parent;
4952
+ }
4953
+ this.selectLoadedDescendants(tile, frameState);
4954
+ }
4955
+ /**
4956
+ * Selects ready descendants near an unavailable desired tile to reduce temporary empty regions.
4957
+ *
4958
+ * @param root - Unavailable tile whose descendants are searched.
4959
+ * @param frameState - Current culling state.
4960
+ */
4961
+ selectLoadedDescendants(root, frameState) {
4962
+ const stack = [{ tile: root, depth: 0 }];
4963
+ while (stack.length > 0) {
4964
+ const { tile, depth } = stack.pop();
4965
+ for (const child of tile.children) {
4966
+ this.updateTile(child, frameState);
4967
+ if (!child.isVisibleAndInRequestVolume) {
4968
+ continue;
4969
+ }
4970
+ if (child.contentAvailable) {
4971
+ this.selectTile(child, frameState);
4972
+ this.touchTile(child, frameState);
4973
+ } else if (depth < 1) {
4974
+ stack.push({ tile: child, depth: depth + 1 });
4975
+ }
4976
+ }
4977
+ }
4978
+ }
4773
4979
  compareDistanceToCamera(a, b) {
4774
4980
  return b._distanceToCamera === 0 && a._distanceToCamera === 0 ? b._centerZDepth - a._centerZDepth : b._distanceToCamera - a._distanceToCamera;
4775
4981
  }
@@ -6888,8 +7094,10 @@ var EMPTY_CONTENT_FORMATS2 = {
6888
7094
  var I3SSource = class {
6889
7095
  /** I3S format discriminator. */
6890
7096
  type = TILESET_TYPE.I3S;
6891
- /** Loader used for tile metadata and content requests. */
7097
+ /** Primary I3S loader used for root and child metadata requests. */
6892
7098
  loader;
7099
+ /** Worker-capable loader used for binary tile content when supplied by the format loader. */
7100
+ contentLoader;
6893
7101
  /** Root I3S layer URL. */
6894
7102
  url;
6895
7103
  /** Base path used for relative tile resource resolution. */
@@ -6924,6 +7132,7 @@ var I3SSource = class {
6924
7132
  this.rootTileset = isTilesetRequest2(input) ? null : input;
6925
7133
  this.tileset = this.rootTileset;
6926
7134
  this.loader = request.loader;
7135
+ this.contentLoader = getI3SContentLoader(request.loader);
6927
7136
  this.url = request.url;
6928
7137
  this.basePath = request.basePath || path_exports.dirname(request.url);
6929
7138
  this.resolver = request.resolver;
@@ -7040,7 +7249,7 @@ var I3SSource = class {
7040
7249
  isTileHeader: false
7041
7250
  }
7042
7251
  };
7043
- tile.content = await this.loadResourceData(contentUrl, options);
7252
+ tile.content = await this.loadResourceData(contentUrl, options, this.contentLoader);
7044
7253
  return { loaded: true };
7045
7254
  }
7046
7255
  /**
@@ -7171,11 +7380,11 @@ var I3SSource = class {
7171
7380
  /**
7172
7381
  * Loads data through injected core APIs so this module stays independent from `@loaders.gl/core`.
7173
7382
  */
7174
- async loadWithCoreApi(url, options) {
7383
+ async loadWithCoreApi(url, options, loader = this.loader) {
7175
7384
  if (!this.coreApi) {
7176
7385
  throw new Error("I3SSource requires an injected coreApi to load tileset data");
7177
7386
  }
7178
- return await this.coreApi.load(url, this.loader, options);
7387
+ return await this.coreApi.load(url, loader, options);
7179
7388
  }
7180
7389
  /**
7181
7390
  * Loads data through an injected resolver when present, otherwise through the injected core API.
@@ -7202,11 +7411,11 @@ var I3SSource = class {
7202
7411
  /**
7203
7412
  * Loads tile metadata or content through an injected resolver when present, otherwise through the injected core API.
7204
7413
  */
7205
- async loadResourceData(url, options) {
7414
+ async loadResourceData(url, options, loader = this.loader) {
7206
7415
  if (this.resolver) {
7207
- return await this.resolver.loadResource(url, this.loader, options);
7416
+ return await this.resolver.loadResource(url, loader, options);
7208
7417
  }
7209
- return await this.loadWithCoreApi(url, options);
7418
+ return await this.loadWithCoreApi(url, options, loader);
7210
7419
  }
7211
7420
  /** Transform one I3S header bound after target options and elevation providers are available. */
7212
7421
  async transformTileHeader(header) {
@@ -7230,6 +7439,9 @@ var I3SSource = class {
7230
7439
  };
7231
7440
  }
7232
7441
  };
7442
+ function getI3SContentLoader(loader) {
7443
+ return loader.contentLoader || loader;
7444
+ }
7233
7445
  function isTilesetRequest2(input) {
7234
7446
  return Boolean(input && typeof input === "object" && "url" in input && "loader" in input && !("type" in input));
7235
7447
  }