@loaders.gl/tiles 4.4.5 → 5.0.0-alpha.2

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 (227) hide show
  1. package/LICENSE +14 -3
  2. package/README.md +110 -1
  3. package/dist/dist.dev.js +6588 -2057
  4. package/dist/dist.min.js +1 -1
  5. package/dist/image-set.d.ts +94 -0
  6. package/dist/image-set.d.ts.map +1 -0
  7. package/dist/image-set.js +243 -0
  8. package/dist/image-set.js.map +1 -0
  9. package/dist/index.cjs +6872 -2160
  10. package/dist/index.cjs.map +3 -4
  11. package/dist/index.d.ts +33 -9
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +18 -8
  14. package/dist/index.js.map +1 -1
  15. package/dist/point-cloud/point-cloud-tile.d.ts +47 -0
  16. package/dist/point-cloud/point-cloud-tile.d.ts.map +1 -0
  17. package/dist/point-cloud/point-cloud-tile.js +70 -0
  18. package/dist/point-cloud/point-cloud-tile.js.map +1 -0
  19. package/dist/point-cloud/point-cloud-tileset.d.ts +131 -0
  20. package/dist/point-cloud/point-cloud-tileset.d.ts.map +1 -0
  21. package/dist/point-cloud/point-cloud-tileset.js +510 -0
  22. package/dist/point-cloud/point-cloud-tileset.js.map +1 -0
  23. package/dist/point-cloud/types.d.ts +64 -0
  24. package/dist/point-cloud/types.d.ts.map +1 -0
  25. package/dist/point-cloud/types.js +5 -0
  26. package/dist/point-cloud/types.js.map +1 -0
  27. package/dist/raster-set.d.ts +113 -0
  28. package/dist/raster-set.d.ts.map +1 -0
  29. package/dist/raster-set.js +274 -0
  30. package/dist/raster-set.js.map +1 -0
  31. package/dist/tileset-2d/adapter.d.ts +38 -0
  32. package/dist/tileset-2d/adapter.d.ts.map +1 -0
  33. package/dist/tileset-2d/adapter.js +5 -0
  34. package/dist/tileset-2d/adapter.js.map +1 -0
  35. package/dist/tileset-2d/index.d.ts +7 -0
  36. package/dist/tileset-2d/index.d.ts.map +1 -0
  37. package/dist/tileset-2d/index.js +6 -0
  38. package/dist/tileset-2d/index.js.map +1 -0
  39. package/dist/tileset-2d/tile-2d-header.d.ts +68 -0
  40. package/dist/tileset-2d/tile-2d-header.d.ts.map +1 -0
  41. package/dist/tileset-2d/tile-2d-header.js +181 -0
  42. package/dist/tileset-2d/tile-2d-header.js.map +1 -0
  43. package/dist/tileset-2d/tileset-2d.d.ts +201 -0
  44. package/dist/tileset-2d/tileset-2d.d.ts.map +1 -0
  45. package/dist/tileset-2d/tileset-2d.js +532 -0
  46. package/dist/tileset-2d/tileset-2d.js.map +1 -0
  47. package/dist/tileset-2d/types.d.ts +44 -0
  48. package/dist/tileset-2d/types.d.ts.map +1 -0
  49. package/dist/tileset-2d/types.js +5 -0
  50. package/dist/tileset-2d/types.js.map +1 -0
  51. package/dist/tileset-2d.d.ts +2 -0
  52. package/dist/tileset-2d.d.ts.map +1 -0
  53. package/dist/tileset-2d.js +5 -0
  54. package/dist/tileset-2d.js.map +1 -0
  55. package/dist/tileset-3d/common/indexed-archive-tileset-source.d.ts +60 -0
  56. package/dist/tileset-3d/common/indexed-archive-tileset-source.d.ts.map +1 -0
  57. package/dist/tileset-3d/common/indexed-archive-tileset-source.js +125 -0
  58. package/dist/tileset-3d/common/indexed-archive-tileset-source.js.map +1 -0
  59. package/dist/{tileset → tileset-3d/common}/tile-3d.d.ts +133 -29
  60. package/dist/tileset-3d/common/tile-3d.d.ts.map +1 -0
  61. package/dist/{tileset → tileset-3d/common}/tile-3d.js +282 -77
  62. package/dist/tileset-3d/common/tile-3d.js.map +1 -0
  63. package/dist/tileset-3d/common/tileset-3d.d.ts +317 -0
  64. package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -0
  65. package/dist/tileset-3d/common/tileset-3d.js +807 -0
  66. package/dist/tileset-3d/common/tileset-3d.js.map +1 -0
  67. package/dist/tileset-3d/common/tileset-cache.d.ts +29 -0
  68. package/dist/tileset-3d/common/tileset-cache.d.ts.map +1 -0
  69. package/dist/{tileset → tileset-3d/common}/tileset-cache.js +12 -4
  70. package/dist/tileset-3d/common/tileset-cache.js.map +1 -0
  71. package/dist/tileset-3d/common/tileset-source.d.ts +204 -0
  72. package/dist/tileset-3d/common/tileset-source.d.ts.map +1 -0
  73. package/dist/tileset-3d/common/tileset-source.js +17 -0
  74. package/dist/tileset-3d/common/tileset-source.js.map +1 -0
  75. package/dist/{tileset → tileset-3d/common}/tileset-traverser.d.ts +15 -2
  76. package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -0
  77. package/dist/{tileset → tileset-3d/common}/tileset-traverser.js +30 -3
  78. package/dist/tileset-3d/common/tileset-traverser.js.map +1 -0
  79. package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts +111 -0
  80. package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts.map +1 -0
  81. package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js +340 -0
  82. package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js.map +1 -0
  83. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts +189 -0
  84. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts.map +1 -0
  85. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js +510 -0
  86. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js.map +1 -0
  87. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts +43 -0
  88. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts.map +1 -0
  89. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js +119 -0
  90. package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js.map +1 -0
  91. package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.d.ts.map +1 -0
  92. package/dist/{tileset → tileset-3d}/format-i3s/i3s-pending-tiles-register.js +3 -0
  93. package/dist/tileset-3d/format-i3s/i3s-pending-tiles-register.js.map +1 -0
  94. package/dist/tileset-3d/format-i3s/i3s-source.d.ts +99 -0
  95. package/dist/tileset-3d/format-i3s/i3s-source.d.ts.map +1 -0
  96. package/dist/tileset-3d/format-i3s/i3s-source.js +299 -0
  97. package/dist/tileset-3d/format-i3s/i3s-source.js.map +1 -0
  98. package/dist/tileset-3d/format-i3s/i3s-tile-manager.d.ts.map +1 -0
  99. package/dist/{tileset → tileset-3d}/format-i3s/i3s-tile-manager.js +5 -2
  100. package/dist/tileset-3d/format-i3s/i3s-tile-manager.js.map +1 -0
  101. package/dist/{tileset → tileset-3d}/format-i3s/i3s-tileset-traverser.d.ts +2 -2
  102. package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.d.ts.map +1 -0
  103. package/dist/{tileset → tileset-3d}/format-i3s/i3s-tileset-traverser.js +17 -23
  104. package/dist/tileset-3d/format-i3s/i3s-tileset-traverser.js.map +1 -0
  105. package/dist/{tileset → tileset-3d}/helpers/3d-tiles-options.d.ts +1 -1
  106. package/dist/tileset-3d/helpers/3d-tiles-options.d.ts.map +1 -0
  107. package/dist/{tileset → tileset-3d}/helpers/3d-tiles-options.js +3 -0
  108. package/dist/tileset-3d/helpers/3d-tiles-options.js.map +1 -0
  109. package/dist/tileset-3d/helpers/bounding-volume.d.ts.map +1 -0
  110. package/dist/{tileset → tileset-3d}/helpers/bounding-volume.js +1 -0
  111. package/dist/tileset-3d/helpers/bounding-volume.js.map +1 -0
  112. package/dist/tileset-3d/helpers/frame-state.d.ts +86 -0
  113. package/dist/tileset-3d/helpers/frame-state.d.ts.map +1 -0
  114. package/dist/{tileset → tileset-3d}/helpers/frame-state.js +84 -9
  115. package/dist/tileset-3d/helpers/frame-state.js.map +1 -0
  116. package/dist/{tileset → tileset-3d}/helpers/i3s-lod.d.ts +1 -1
  117. package/dist/tileset-3d/helpers/i3s-lod.d.ts.map +1 -0
  118. package/dist/{tileset → tileset-3d}/helpers/i3s-lod.js +1 -1
  119. package/dist/tileset-3d/helpers/i3s-lod.js.map +1 -0
  120. package/dist/tileset-3d/helpers/tiles-3d-lod.d.ts +72 -0
  121. package/dist/tileset-3d/helpers/tiles-3d-lod.d.ts.map +1 -0
  122. package/dist/tileset-3d/helpers/tiles-3d-lod.js +257 -0
  123. package/dist/tileset-3d/helpers/tiles-3d-lod.js.map +1 -0
  124. package/dist/tileset-3d/helpers/tiles-3d-request-priority.d.ts +134 -0
  125. package/dist/tileset-3d/helpers/tiles-3d-request-priority.d.ts.map +1 -0
  126. package/dist/tileset-3d/helpers/tiles-3d-request-priority.js +179 -0
  127. package/dist/tileset-3d/helpers/tiles-3d-request-priority.js.map +1 -0
  128. package/dist/{tileset → tileset-3d}/helpers/transform-utils.d.ts +1 -1
  129. package/dist/tileset-3d/helpers/transform-utils.d.ts.map +1 -0
  130. package/dist/tileset-3d/helpers/transform-utils.js.map +1 -0
  131. package/dist/tileset-3d/helpers/zoom.d.ts.map +1 -0
  132. package/dist/tileset-3d/helpers/zoom.js.map +1 -0
  133. package/dist/types.d.ts +9 -0
  134. package/dist/types.d.ts.map +1 -1
  135. package/dist/types.js +3 -0
  136. package/dist/types.js.map +1 -1
  137. package/dist/utils/doubly-linked-list.d.ts.map +1 -1
  138. package/dist/utils/doubly-linked-list.js +1 -0
  139. package/dist/utils/doubly-linked-list.js.map +1 -1
  140. package/dist/utils/managed-array.d.ts.map +1 -1
  141. package/dist/utils/managed-array.js +1 -0
  142. package/dist/utils/managed-array.js.map +1 -1
  143. package/package.json +7 -6
  144. package/src/image-set.ts +328 -0
  145. package/src/index.ts +99 -9
  146. package/src/point-cloud/point-cloud-tile.ts +80 -0
  147. package/src/point-cloud/point-cloud-tileset.ts +713 -0
  148. package/src/point-cloud/types.ts +82 -0
  149. package/src/raster-set.ts +412 -0
  150. package/src/tileset-2d/adapter.ts +47 -0
  151. package/src/tileset-2d/index.ts +33 -0
  152. package/src/tileset-2d/tile-2d-header.ts +224 -0
  153. package/src/tileset-2d/tileset-2d.ts +716 -0
  154. package/src/tileset-2d/types.ts +39 -0
  155. package/src/tileset-2d.ts +5 -0
  156. package/src/tileset-3d/common/indexed-archive-tileset-source.ts +205 -0
  157. package/src/{tileset → tileset-3d/common}/tile-3d.ts +348 -93
  158. package/src/tileset-3d/common/tileset-3d.ts +1087 -0
  159. package/src/{tileset → tileset-3d/common}/tileset-cache.ts +16 -8
  160. package/src/tileset-3d/common/tileset-source.ts +255 -0
  161. package/src/{tileset → tileset-3d/common}/tileset-traverser.ts +32 -4
  162. package/src/tileset-3d/format-3d-tiles/implicit-tiling.ts +534 -0
  163. package/src/tileset-3d/format-3d-tiles/tiles-3d-source.ts +632 -0
  164. package/src/tileset-3d/format-3d-tiles/tileset-3d-traverser.ts +140 -0
  165. package/src/{tileset → tileset-3d}/format-i3s/i3s-pending-tiles-register.ts +4 -0
  166. package/src/tileset-3d/format-i3s/i3s-source.ts +366 -0
  167. package/src/{tileset → tileset-3d}/format-i3s/i3s-tile-manager.ts +6 -2
  168. package/src/{tileset → tileset-3d}/format-i3s/i3s-tileset-traverser.ts +19 -24
  169. package/src/{tileset → tileset-3d}/helpers/3d-tiles-options.ts +5 -1
  170. package/src/{tileset → tileset-3d}/helpers/bounding-volume.ts +2 -0
  171. package/src/tileset-3d/helpers/frame-state.ts +311 -0
  172. package/src/{tileset → tileset-3d}/helpers/i3s-lod.ts +2 -2
  173. package/src/tileset-3d/helpers/tiles-3d-lod.ts +370 -0
  174. package/src/tileset-3d/helpers/tiles-3d-request-priority.ts +301 -0
  175. package/src/{tileset → tileset-3d}/helpers/transform-utils.ts +1 -1
  176. package/src/types.ts +13 -0
  177. package/src/utils/doubly-linked-list.ts +2 -0
  178. package/src/utils/managed-array.ts +2 -0
  179. package/dist/tileset/format-3d-tiles/tileset-3d-traverser.d.ts +0 -7
  180. package/dist/tileset/format-3d-tiles/tileset-3d-traverser.d.ts.map +0 -1
  181. package/dist/tileset/format-3d-tiles/tileset-3d-traverser.js +0 -53
  182. package/dist/tileset/format-3d-tiles/tileset-3d-traverser.js.map +0 -1
  183. package/dist/tileset/format-i3s/i3s-pending-tiles-register.d.ts.map +0 -1
  184. package/dist/tileset/format-i3s/i3s-pending-tiles-register.js.map +0 -1
  185. package/dist/tileset/format-i3s/i3s-tile-manager.d.ts.map +0 -1
  186. package/dist/tileset/format-i3s/i3s-tile-manager.js.map +0 -1
  187. package/dist/tileset/format-i3s/i3s-tileset-traverser.d.ts.map +0 -1
  188. package/dist/tileset/format-i3s/i3s-tileset-traverser.js.map +0 -1
  189. package/dist/tileset/helpers/3d-tiles-options.d.ts.map +0 -1
  190. package/dist/tileset/helpers/3d-tiles-options.js.map +0 -1
  191. package/dist/tileset/helpers/bounding-volume.d.ts.map +0 -1
  192. package/dist/tileset/helpers/bounding-volume.js.map +0 -1
  193. package/dist/tileset/helpers/frame-state.d.ts +0 -28
  194. package/dist/tileset/helpers/frame-state.d.ts.map +0 -1
  195. package/dist/tileset/helpers/frame-state.js.map +0 -1
  196. package/dist/tileset/helpers/i3s-lod.d.ts.map +0 -1
  197. package/dist/tileset/helpers/i3s-lod.js.map +0 -1
  198. package/dist/tileset/helpers/tiles-3d-lod.d.ts +0 -8
  199. package/dist/tileset/helpers/tiles-3d-lod.d.ts.map +0 -1
  200. package/dist/tileset/helpers/tiles-3d-lod.js +0 -113
  201. package/dist/tileset/helpers/tiles-3d-lod.js.map +0 -1
  202. package/dist/tileset/helpers/transform-utils.d.ts.map +0 -1
  203. package/dist/tileset/helpers/transform-utils.js.map +0 -1
  204. package/dist/tileset/helpers/zoom.d.ts.map +0 -1
  205. package/dist/tileset/helpers/zoom.js.map +0 -1
  206. package/dist/tileset/tile-3d.d.ts.map +0 -1
  207. package/dist/tileset/tile-3d.js.map +0 -1
  208. package/dist/tileset/tileset-3d.d.ts +0 -284
  209. package/dist/tileset/tileset-3d.d.ts.map +0 -1
  210. package/dist/tileset/tileset-3d.js +0 -814
  211. package/dist/tileset/tileset-3d.js.map +0 -1
  212. package/dist/tileset/tileset-cache.d.ts +0 -19
  213. package/dist/tileset/tileset-cache.d.ts.map +0 -1
  214. package/dist/tileset/tileset-cache.js.map +0 -1
  215. package/dist/tileset/tileset-traverser.d.ts.map +0 -1
  216. package/dist/tileset/tileset-traverser.js.map +0 -1
  217. package/src/tileset/format-3d-tiles/tileset-3d-traverser.ts +0 -63
  218. package/src/tileset/helpers/frame-state.ts +0 -183
  219. package/src/tileset/helpers/tiles-3d-lod.ts +0 -149
  220. package/src/tileset/tileset-3d.ts +0 -1037
  221. /package/dist/{tileset → tileset-3d}/format-i3s/i3s-pending-tiles-register.d.ts +0 -0
  222. /package/dist/{tileset → tileset-3d}/format-i3s/i3s-tile-manager.d.ts +0 -0
  223. /package/dist/{tileset → tileset-3d}/helpers/bounding-volume.d.ts +0 -0
  224. /package/dist/{tileset → tileset-3d}/helpers/transform-utils.js +0 -0
  225. /package/dist/{tileset → tileset-3d}/helpers/zoom.d.ts +0 -0
  226. /package/dist/{tileset → tileset-3d}/helpers/zoom.js +0 -0
  227. /package/src/{tileset → tileset-3d}/helpers/zoom.ts +0 -0
@@ -0,0 +1,534 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright vis.gl contributors
4
+
5
+ import {LOD_METRIC_TYPE, TILE_REFINEMENT, TILE_TYPE} from '../../constants';
6
+
7
+ const QUADTREE_CHILD_COUNT = 4;
8
+ const OCTREE_CHILD_COUNT = 8;
9
+
10
+ /** Global coordinates of a tile in an implicit quadtree or octree. */
11
+ export type ImplicitTileCoordinates = {
12
+ /** Zero-based level relative to the implicit-tile root. */
13
+ level: number;
14
+ /** Zero-based horizontal coordinate at {@link level}. */
15
+ x: number;
16
+ /** Zero-based vertical coordinate at {@link level}. */
17
+ y: number;
18
+ /** Zero-based height coordinate at {@link level}; always zero for quadtrees. */
19
+ z: number;
20
+ };
21
+
22
+ /** Serializable information shared by every subtree in one implicit-tile hierarchy. */
23
+ export type ImplicitTilingDescriptor = {
24
+ /** Absolute template URL for render content, or an empty string for a contentless hierarchy. */
25
+ contentUrlTemplate: string;
26
+ /** Non-URI content metadata inherited by each available implicit content resource. */
27
+ contentHeader?: Record<string, any>;
28
+ /** Absolute template URL for subtree availability files. */
29
+ subtreesUrlTemplate: string;
30
+ /** Spatial subdivision used by the hierarchy. */
31
+ subdivisionScheme: 'QUADTREE' | 'OCTREE';
32
+ /** Number of tile levels represented inside each subtree file. */
33
+ subtreeLevels: number;
34
+ /** Last valid global tile level, where the implicit root is level zero. */
35
+ maximumLevel: number;
36
+ /** Refinement mode inherited by generated tiles. */
37
+ refine: TILE_REFINEMENT | string;
38
+ /** LOD metric used by generated tiles. */
39
+ lodMetricType: LOD_METRIC_TYPE.GEOMETRIC_ERROR;
40
+ /** Source geometric error of the implicit root, in local meters. */
41
+ rootLodMetricValue: number;
42
+ /** Bounding volume of the complete implicit hierarchy. */
43
+ rootBoundingVolume: Record<string, any>;
44
+ };
45
+
46
+ /** Lazy pointer from a runtime tile to the subtree that defines it and its descendants. */
47
+ export type ImplicitSubtreeReference = {
48
+ /** Global coordinates of the referenced subtree root. */
49
+ coordinates: ImplicitTileCoordinates;
50
+ /** Absolute subtree URL before source-level query inheritance is applied. */
51
+ subtreeUrl: string;
52
+ /** Serializable hierarchy description used to materialize the subtree. */
53
+ descriptor: ImplicitTilingDescriptor;
54
+ };
55
+
56
+ /** Constant or bitstream-backed availability declaration from a parsed subtree. */
57
+ export type ImplicitAvailability = {
58
+ /** Constant availability value applied to every addressed element. */
59
+ constant?: number;
60
+ /** Expanded least-significant-bit-first availability buffer. */
61
+ explicitBitstream?: Uint8Array;
62
+ };
63
+
64
+ /** Parsed subset of the 3D Tiles subtree schema needed for hierarchy materialization. */
65
+ export type ParsedImplicitSubtree = {
66
+ /** Availability of tiles inside this subtree. */
67
+ tileAvailability: ImplicitAvailability;
68
+ /**
69
+ * Availability of tile content; only the first multiple-content stream is currently used.
70
+ * Omitted availability denotes a metadata-only subtree with no render content.
71
+ */
72
+ contentAvailability?: ImplicitAvailability | ImplicitAvailability[];
73
+ /** Availability of subtree roots immediately below this subtree. */
74
+ childSubtreeAvailability: ImplicitAvailability;
75
+ };
76
+
77
+ /** Runtime header produced for an available implicit tile. */
78
+ export type ImplicitTileHeader = Record<string, any> & {
79
+ /** Stable source identity, including global implicit coordinates. */
80
+ id: string;
81
+ /** Materialized children that are represented by the same subtree file. */
82
+ children: ImplicitTileHeader[];
83
+ /** Optional lazy reference when this tile begins a child subtree. */
84
+ implicitSubtree?: ImplicitSubtreeReference;
85
+ };
86
+
87
+ /** Result of materializing exactly one subtree resource. */
88
+ export type MaterializedImplicitSubtree = {
89
+ /** Header for the subtree root, including its in-subtree descendants. */
90
+ root: ImplicitTileHeader;
91
+ /** Number of available headers materialized from this subtree. */
92
+ tileCount: number;
93
+ /** Number of lazy child-subtree references created at the subtree boundary. */
94
+ childSubtreeCount: number;
95
+ };
96
+
97
+ /**
98
+ * Creates the lazy reference stored on an implicit subtree-root header.
99
+ *
100
+ * @param descriptor - Shared implicit hierarchy description.
101
+ * @param coordinates - Global coordinates of the subtree root.
102
+ * @returns Serializable reference with its concrete subtree URL.
103
+ */
104
+ export function createImplicitSubtreeReference(
105
+ descriptor: ImplicitTilingDescriptor,
106
+ coordinates: ImplicitTileCoordinates
107
+ ): ImplicitSubtreeReference {
108
+ return {
109
+ coordinates,
110
+ subtreeUrl: replaceImplicitUrlTemplate(descriptor.subtreesUrlTemplate, coordinates),
111
+ descriptor
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Materializes the available tiles described by one subtree file without performing I/O.
117
+ *
118
+ * The function deliberately stops at the subtree boundary. Available child subtrees become lazy
119
+ * references so traversal, SSE, request-volume checks, and the request scheduler decide when the
120
+ * next network request is useful.
121
+ *
122
+ * @param subtree - Parsed availability data for one subtree resource.
123
+ * @param reference - Coordinates and hierarchy description for the subtree root.
124
+ * @returns Materialized root and diagnostic counts.
125
+ * @throws If the subtree root is unavailable or the descriptor is invalid.
126
+ */
127
+ export function materializeImplicitSubtree(
128
+ subtree: ParsedImplicitSubtree,
129
+ reference: ImplicitSubtreeReference
130
+ ): MaterializedImplicitSubtree {
131
+ const {descriptor} = reference;
132
+ validateImplicitDescriptor(descriptor);
133
+
134
+ const counters = {tileCount: 0, childSubtreeCount: 0};
135
+ const root = materializeAvailableTile(
136
+ subtree,
137
+ reference,
138
+ {localLevel: 0, mortonIndex: 0},
139
+ reference.coordinates,
140
+ counters
141
+ );
142
+
143
+ if (!root) {
144
+ throw new Error(
145
+ `Invalid 3D Tiles subtree: root tile is unavailable at ${reference.subtreeUrl}`
146
+ );
147
+ }
148
+
149
+ return {root, ...counters};
150
+ }
151
+
152
+ /**
153
+ * Replaces implicit coordinate placeholders in a content or subtree URL.
154
+ *
155
+ * @param templateUrl - URL containing level/x/y/z placeholders.
156
+ * @param coordinates - Global coordinates to insert.
157
+ * @returns URL with all coordinate placeholders replaced.
158
+ */
159
+ export function replaceImplicitUrlTemplate(
160
+ templateUrl: string,
161
+ coordinates: ImplicitTileCoordinates
162
+ ): string {
163
+ const values: Record<string, number> = {
164
+ level: coordinates.level,
165
+ x: coordinates.x,
166
+ y: coordinates.y,
167
+ z: coordinates.z
168
+ };
169
+ return templateUrl.replace(/{(level|x|y|z)}/gi, (_match, coordinateName: string) =>
170
+ String(values[coordinateName.toLowerCase()])
171
+ );
172
+ }
173
+
174
+ /**
175
+ * Builds one available tile and recursively materializes descendants in the same subtree.
176
+ *
177
+ * @param subtree - Parsed availability declarations.
178
+ * @param reference - Current subtree reference.
179
+ * @param localCoordinates - Level and Morton index relative to the current subtree.
180
+ * @param globalCoordinates - Coordinates relative to the complete implicit hierarchy.
181
+ * @param counters - Mutable diagnostic counters owned by the public materializer call.
182
+ * @returns Header for an available tile, or `null` for a sparse unavailable position.
183
+ */
184
+ function materializeAvailableTile(
185
+ subtree: ParsedImplicitSubtree,
186
+ reference: ImplicitSubtreeReference,
187
+ localCoordinates: {localLevel: number; mortonIndex: number},
188
+ globalCoordinates: ImplicitTileCoordinates,
189
+ counters: {tileCount: number; childSubtreeCount: number}
190
+ ): ImplicitTileHeader | null {
191
+ const {descriptor} = reference;
192
+ const childCount = getImplicitChildCount(descriptor.subdivisionScheme);
193
+ const availabilityIndex =
194
+ getLevelOffset(childCount, localCoordinates.localLevel) + localCoordinates.mortonIndex;
195
+
196
+ if (!getAvailabilityValue(subtree.tileAvailability, availabilityIndex)) {
197
+ return null;
198
+ }
199
+
200
+ counters.tileCount++;
201
+ const contentAvailable = getAvailabilityValue(
202
+ getPrimaryContentAvailability(subtree.contentAvailability),
203
+ availabilityIndex
204
+ );
205
+ const children: ImplicitTileHeader[] = [];
206
+
207
+ if (globalCoordinates.level < descriptor.maximumLevel) {
208
+ if (localCoordinates.localLevel + 1 < descriptor.subtreeLevels) {
209
+ for (let childIndex = 0; childIndex < childCount; childIndex++) {
210
+ const childCoordinates = getChildCoordinates(
211
+ globalCoordinates,
212
+ childIndex,
213
+ descriptor.subdivisionScheme
214
+ );
215
+ const childHeader = materializeAvailableTile(
216
+ subtree,
217
+ reference,
218
+ {
219
+ localLevel: localCoordinates.localLevel + 1,
220
+ mortonIndex: localCoordinates.mortonIndex * childCount + childIndex
221
+ },
222
+ childCoordinates,
223
+ counters
224
+ );
225
+ if (childHeader) {
226
+ children.push(childHeader);
227
+ }
228
+ }
229
+ } else {
230
+ for (let childIndex = 0; childIndex < childCount; childIndex++) {
231
+ const childSubtreeIndex = localCoordinates.mortonIndex * childCount + childIndex;
232
+ if (getAvailabilityValue(subtree.childSubtreeAvailability, childSubtreeIndex)) {
233
+ const childCoordinates = getChildCoordinates(
234
+ globalCoordinates,
235
+ childIndex,
236
+ descriptor.subdivisionScheme
237
+ );
238
+ children.push(createLazyImplicitTileHeader(descriptor, childCoordinates));
239
+ counters.childSubtreeCount++;
240
+ }
241
+ }
242
+ }
243
+ }
244
+
245
+ return formatImplicitTileHeader(
246
+ descriptor,
247
+ reference,
248
+ globalCoordinates,
249
+ contentAvailable,
250
+ children
251
+ );
252
+ }
253
+
254
+ /**
255
+ * Creates a contentless placeholder for an available child subtree.
256
+ *
257
+ * @param descriptor - Shared implicit hierarchy description.
258
+ * @param coordinates - Global coordinates of the child subtree root.
259
+ * @returns Header that participates in culling and SSE before its subtree is requested.
260
+ */
261
+ function createLazyImplicitTileHeader(
262
+ descriptor: ImplicitTilingDescriptor,
263
+ coordinates: ImplicitTileCoordinates
264
+ ): ImplicitTileHeader {
265
+ const reference = createImplicitSubtreeReference(descriptor, coordinates);
266
+ return {
267
+ id: getImplicitTileId(reference, coordinates),
268
+ children: [],
269
+ implicitSubtree: reference,
270
+ boundingVolume: calculateImplicitBoundingVolume(
271
+ descriptor.rootBoundingVolume,
272
+ coordinates,
273
+ descriptor.subdivisionScheme
274
+ ),
275
+ geometricError: descriptor.rootLodMetricValue / 2 ** coordinates.level,
276
+ lodMetricType: descriptor.lodMetricType,
277
+ lodMetricValue: descriptor.rootLodMetricValue / 2 ** coordinates.level,
278
+ refine: descriptor.refine,
279
+ type: TILE_TYPE.EMPTY
280
+ };
281
+ }
282
+
283
+ /**
284
+ * Formats an available implicit tile as a runtime header.
285
+ *
286
+ * @param descriptor - Shared implicit hierarchy description.
287
+ * @param reference - Current subtree reference used to build stable IDs.
288
+ * @param coordinates - Global tile coordinates.
289
+ * @param contentAvailable - Whether the subtree declares render content for this tile.
290
+ * @param children - Materialized or lazy child headers.
291
+ * @returns Runtime tile header.
292
+ */
293
+ function formatImplicitTileHeader(
294
+ descriptor: ImplicitTilingDescriptor,
295
+ reference: ImplicitSubtreeReference,
296
+ coordinates: ImplicitTileCoordinates,
297
+ contentAvailable: boolean,
298
+ children: ImplicitTileHeader[]
299
+ ): ImplicitTileHeader {
300
+ const contentUrl =
301
+ contentAvailable && descriptor.contentUrlTemplate
302
+ ? replaceImplicitUrlTemplate(descriptor.contentUrlTemplate, coordinates)
303
+ : undefined;
304
+ const lodMetricValue = descriptor.rootLodMetricValue / 2 ** coordinates.level;
305
+
306
+ return {
307
+ id: getImplicitTileId(reference, coordinates),
308
+ children,
309
+ contentUrl,
310
+ content: contentUrl ? {...descriptor.contentHeader, uri: contentUrl} : undefined,
311
+ refine: descriptor.refine,
312
+ type: getImplicitTileType(contentUrl),
313
+ lodMetricType: descriptor.lodMetricType,
314
+ lodMetricValue,
315
+ geometricError: lodMetricValue,
316
+ boundingVolume: calculateImplicitBoundingVolume(
317
+ descriptor.rootBoundingVolume,
318
+ coordinates,
319
+ descriptor.subdivisionScheme
320
+ )
321
+ };
322
+ }
323
+
324
+ /**
325
+ * Returns a stable identity for contentless and content-bearing implicit tiles.
326
+ *
327
+ * @param reference - Owning subtree reference.
328
+ * @param coordinates - Global tile coordinates.
329
+ * @returns Stable source identity independent of content availability.
330
+ */
331
+ function getImplicitTileId(
332
+ reference: ImplicitSubtreeReference,
333
+ coordinates: ImplicitTileCoordinates
334
+ ): string {
335
+ return `${reference.subtreeUrl}#implicit=${coordinates.level}/${coordinates.x}/${coordinates.y}/${coordinates.z}`;
336
+ }
337
+
338
+ /**
339
+ * Reads an availability bit without assuming 32-bit coordinate or Morton arithmetic.
340
+ *
341
+ * @param availability - Constant or expanded bitstream availability.
342
+ * @param index - Zero-based availability index.
343
+ * @returns Whether the addressed tile, content, or child subtree exists.
344
+ */
345
+ function getAvailabilityValue(availability: ImplicitAvailability, index: number): boolean {
346
+ if (typeof availability?.constant === 'number') {
347
+ return Boolean(availability.constant);
348
+ }
349
+ const bitstream = availability?.explicitBitstream;
350
+ if (!bitstream) {
351
+ return false;
352
+ }
353
+ const byteIndex = Math.floor(index / 8);
354
+ const bitIndex = index % 8;
355
+ return Boolean((bitstream[byteIndex] >> bitIndex) & 1);
356
+ }
357
+
358
+ /**
359
+ * Selects the first content availability stream until multiple contents are supported.
360
+ *
361
+ * @param availability - Single or multiple-content availability declaration.
362
+ * @returns Primary content availability declaration.
363
+ */
364
+ function getPrimaryContentAvailability(
365
+ availability: ImplicitAvailability | ImplicitAvailability[] | undefined
366
+ ): ImplicitAvailability {
367
+ return Array.isArray(availability)
368
+ ? availability[0] || {constant: 0}
369
+ : availability || {constant: 0};
370
+ }
371
+
372
+ /**
373
+ * Calculates the breadth-first availability offset for a local subtree level.
374
+ *
375
+ * @param childCount - Branching factor of the subdivision scheme.
376
+ * @param localLevel - Level relative to the subtree root.
377
+ * @returns First availability index for the requested level.
378
+ */
379
+ function getLevelOffset(childCount: number, localLevel: number): number {
380
+ return (childCount ** localLevel - 1) / (childCount - 1);
381
+ }
382
+
383
+ /**
384
+ * Calculates one child's global implicit coordinates.
385
+ *
386
+ * @param parent - Global parent coordinates.
387
+ * @param childIndex - Morton-ordered child index.
388
+ * @param subdivisionScheme - Quadtree or octree subdivision.
389
+ * @returns Global child coordinates.
390
+ */
391
+ function getChildCoordinates(
392
+ parent: ImplicitTileCoordinates,
393
+ childIndex: number,
394
+ subdivisionScheme: 'QUADTREE' | 'OCTREE'
395
+ ): ImplicitTileCoordinates {
396
+ return {
397
+ level: parent.level + 1,
398
+ x: parent.x * 2 + (childIndex & 1),
399
+ y: parent.y * 2 + ((childIndex >> 1) & 1),
400
+ z: subdivisionScheme === 'OCTREE' ? parent.z * 2 + ((childIndex >> 2) & 1) : 0
401
+ };
402
+ }
403
+
404
+ /**
405
+ * Returns the branching factor for a supported implicit subdivision scheme.
406
+ *
407
+ * @param subdivisionScheme - Quadtree or octree subdivision.
408
+ * @returns Four for quadtrees or eight for octrees.
409
+ */
410
+ function getImplicitChildCount(subdivisionScheme: 'QUADTREE' | 'OCTREE'): number {
411
+ return subdivisionScheme === 'OCTREE' ? OCTREE_CHILD_COUNT : QUADTREE_CHILD_COUNT;
412
+ }
413
+
414
+ /**
415
+ * Calculates the bounding volume for global implicit coordinates.
416
+ *
417
+ * Region volumes are divided in longitude/latitude and, for octrees, height. Oriented boxes are
418
+ * divided along their half-axis vectors. S2-derived boxes retain the root box conservatively: the
419
+ * lower-level tiles module intentionally does not duplicate the S2 geometry implementation owned
420
+ * by `@loaders.gl/3d-tiles`, and a conservative volume avoids incorrect culling.
421
+ *
422
+ * @param rootBoundingVolume - Bounding volume of the complete implicit hierarchy.
423
+ * @param coordinates - Global tile coordinates.
424
+ * @param subdivisionScheme - Quadtree or octree subdivision.
425
+ * @returns Bounding volume for the addressed tile.
426
+ */
427
+ function calculateImplicitBoundingVolume(
428
+ rootBoundingVolume: Record<string, any>,
429
+ coordinates: ImplicitTileCoordinates,
430
+ subdivisionScheme: 'QUADTREE' | 'OCTREE'
431
+ ): Record<string, any> {
432
+ if (rootBoundingVolume.region) {
433
+ const [west, south, east, north, minimumHeight, maximumHeight] = rootBoundingVolume.region;
434
+ const divisionCount = 2 ** coordinates.level;
435
+ const longitudeSize = (east - west) / divisionCount;
436
+ const latitudeSize = (north - south) / divisionCount;
437
+ const childWest = west + longitudeSize * coordinates.x;
438
+ const childSouth = south + latitudeSize * coordinates.y;
439
+ let childMinimumHeight = minimumHeight;
440
+ let childMaximumHeight = maximumHeight;
441
+ if (subdivisionScheme === 'OCTREE') {
442
+ const heightSize = (maximumHeight - minimumHeight) / divisionCount;
443
+ childMinimumHeight = minimumHeight + heightSize * coordinates.z;
444
+ childMaximumHeight = childMinimumHeight + heightSize;
445
+ }
446
+ return {
447
+ region: [
448
+ childWest,
449
+ childSouth,
450
+ childWest + longitudeSize,
451
+ childSouth + latitudeSize,
452
+ childMinimumHeight,
453
+ childMaximumHeight
454
+ ]
455
+ };
456
+ }
457
+
458
+ if (rootBoundingVolume.box) {
459
+ if (rootBoundingVolume.s2VolumeInfo) {
460
+ return {box: [...rootBoundingVolume.box], s2VolumeInfo: rootBoundingVolume.s2VolumeInfo};
461
+ }
462
+ const box = rootBoundingVolume.box;
463
+ const divisionCount = 2 ** coordinates.level;
464
+ const xOffset = -1 + (2 * coordinates.x + 1) / divisionCount;
465
+ const yOffset = -1 + (2 * coordinates.y + 1) / divisionCount;
466
+ const zOffset = -1 + (2 * coordinates.z + 1) / divisionCount;
467
+ const divideHeight = subdivisionScheme === 'OCTREE';
468
+ const center = [
469
+ box[0] + box[3] * xOffset + box[6] * yOffset + (divideHeight ? box[9] * zOffset : 0),
470
+ box[1] + box[4] * xOffset + box[7] * yOffset + (divideHeight ? box[10] * zOffset : 0),
471
+ box[2] + box[5] * xOffset + box[8] * yOffset + (divideHeight ? box[11] * zOffset : 0)
472
+ ];
473
+ return {
474
+ box: [
475
+ ...center,
476
+ box[3] / divisionCount,
477
+ box[4] / divisionCount,
478
+ box[5] / divisionCount,
479
+ box[6] / divisionCount,
480
+ box[7] / divisionCount,
481
+ box[8] / divisionCount,
482
+ divideHeight ? box[9] / divisionCount : box[9],
483
+ divideHeight ? box[10] / divisionCount : box[10],
484
+ divideHeight ? box[11] / divisionCount : box[11]
485
+ ]
486
+ };
487
+ }
488
+
489
+ throw new Error(
490
+ `Unsupported implicit 3D Tiles bounding volume: ${JSON.stringify(rootBoundingVolume)}`
491
+ );
492
+ }
493
+
494
+ /**
495
+ * Detects the runtime tile category from an available content URL.
496
+ *
497
+ * @param contentUrl - Concrete content URL, if content is available.
498
+ * @returns Runtime tile category.
499
+ */
500
+ function getImplicitTileType(contentUrl?: string): TILE_TYPE | string {
501
+ if (!contentUrl) {
502
+ return TILE_TYPE.EMPTY;
503
+ }
504
+ const extension = contentUrl.split('?')[0].split('.').pop()?.toLowerCase();
505
+ switch (extension) {
506
+ case 'pnts':
507
+ return TILE_TYPE.POINTCLOUD;
508
+ case 'i3dm':
509
+ case 'b3dm':
510
+ case 'glb':
511
+ case 'gltf':
512
+ return TILE_TYPE.SCENEGRAPH;
513
+ default:
514
+ return extension || TILE_TYPE.EMPTY;
515
+ }
516
+ }
517
+
518
+ /**
519
+ * Validates descriptor invariants before allocating a runtime subtree.
520
+ *
521
+ * @param descriptor - Serializable implicit hierarchy description.
522
+ * @throws If levels, scheme, or maximum-level semantics are invalid.
523
+ */
524
+ function validateImplicitDescriptor(descriptor: ImplicitTilingDescriptor): void {
525
+ if (descriptor.subdivisionScheme !== 'QUADTREE' && descriptor.subdivisionScheme !== 'OCTREE') {
526
+ throw new Error(`Unsupported implicit subdivision scheme: ${descriptor.subdivisionScheme}`);
527
+ }
528
+ if (!Number.isInteger(descriptor.subtreeLevels) || descriptor.subtreeLevels < 1) {
529
+ throw new Error('Implicit subtreeLevels must be a positive integer');
530
+ }
531
+ if (!Number.isInteger(descriptor.maximumLevel) || descriptor.maximumLevel < 0) {
532
+ throw new Error('Implicit availableLevels must describe at least the root level');
533
+ }
534
+ }