@loaders.gl/3d-tiles 4.0.0-alpha.4 → 4.0.0-alpha.5

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 (155) hide show
  1. package/dist/bundle.d.ts +2 -0
  2. package/dist/bundle.d.ts.map +1 -0
  3. package/dist/cesium-ion-loader.d.ts +6 -0
  4. package/dist/cesium-ion-loader.d.ts.map +1 -0
  5. package/dist/dist.min.js +12227 -0
  6. package/dist/index.d.ts +10 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +1 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/lib/classes/helpers/tile-3d-accessor-utils.d.ts +8 -0
  11. package/dist/lib/classes/helpers/tile-3d-accessor-utils.d.ts.map +1 -0
  12. package/dist/lib/classes/helpers/tile-3d-accessor-utils.js.map +1 -1
  13. package/dist/lib/classes/tile-3d-batch-table-hierarchy.d.ts +10 -0
  14. package/dist/lib/classes/tile-3d-batch-table-hierarchy.d.ts.map +1 -0
  15. package/dist/lib/classes/tile-3d-batch-table-hierarchy.js.map +1 -1
  16. package/dist/lib/classes/tile-3d-batch-table.d.ts +34 -0
  17. package/dist/lib/classes/tile-3d-batch-table.d.ts.map +1 -0
  18. package/dist/lib/classes/tile-3d-batch-table.js +16 -1
  19. package/dist/lib/classes/tile-3d-batch-table.js.map +1 -1
  20. package/dist/lib/classes/tile-3d-feature-table.d.ts +15 -0
  21. package/dist/lib/classes/tile-3d-feature-table.d.ts.map +1 -0
  22. package/dist/lib/classes/tile-3d-feature-table.js +9 -2
  23. package/dist/lib/classes/tile-3d-feature-table.js.map +1 -1
  24. package/dist/lib/constants.d.ts +22 -0
  25. package/dist/lib/constants.d.ts.map +1 -0
  26. package/dist/lib/constants.js +2 -1
  27. package/dist/lib/constants.js.map +1 -1
  28. package/dist/lib/encoders/encode-3d-tile-batched-model.d.ts +2 -0
  29. package/dist/lib/encoders/encode-3d-tile-batched-model.d.ts.map +1 -0
  30. package/dist/lib/encoders/encode-3d-tile-batched-model.js.map +1 -1
  31. package/dist/lib/encoders/encode-3d-tile-composite.d.ts +2 -0
  32. package/dist/lib/encoders/encode-3d-tile-composite.d.ts.map +1 -0
  33. package/dist/lib/encoders/encode-3d-tile-composite.js.map +1 -1
  34. package/dist/lib/encoders/encode-3d-tile-instanced-model.d.ts +2 -0
  35. package/dist/lib/encoders/encode-3d-tile-instanced-model.d.ts.map +1 -0
  36. package/dist/lib/encoders/encode-3d-tile-instanced-model.js.map +1 -1
  37. package/dist/lib/encoders/encode-3d-tile-point-cloud.d.ts +2 -0
  38. package/dist/lib/encoders/encode-3d-tile-point-cloud.d.ts.map +1 -0
  39. package/dist/lib/encoders/encode-3d-tile-point-cloud.js.map +1 -1
  40. package/dist/lib/encoders/encode-3d-tile.d.ts +2 -0
  41. package/dist/lib/encoders/encode-3d-tile.d.ts.map +1 -0
  42. package/dist/lib/encoders/encode-3d-tile.js.map +1 -1
  43. package/dist/lib/encoders/helpers/encode-3d-tile-header.d.ts +3 -0
  44. package/dist/lib/encoders/helpers/encode-3d-tile-header.d.ts.map +1 -0
  45. package/dist/lib/encoders/helpers/encode-3d-tile-header.js.map +1 -1
  46. package/dist/lib/ion/ion.d.ts +4 -0
  47. package/dist/lib/ion/ion.d.ts.map +1 -0
  48. package/dist/lib/ion/ion.js.map +1 -1
  49. package/dist/lib/parsers/helpers/normalize-3d-tile-colors.d.ts +7 -0
  50. package/dist/lib/parsers/helpers/normalize-3d-tile-colors.d.ts.map +1 -0
  51. package/dist/lib/parsers/helpers/normalize-3d-tile-colors.js.map +1 -1
  52. package/dist/lib/parsers/helpers/normalize-3d-tile-normals.d.ts +6 -0
  53. package/dist/lib/parsers/helpers/normalize-3d-tile-normals.d.ts.map +1 -0
  54. package/dist/lib/parsers/helpers/normalize-3d-tile-normals.js.map +1 -1
  55. package/dist/lib/parsers/helpers/normalize-3d-tile-positions.d.ts +2 -0
  56. package/dist/lib/parsers/helpers/normalize-3d-tile-positions.d.ts.map +1 -0
  57. package/dist/lib/parsers/helpers/normalize-3d-tile-positions.js.map +1 -1
  58. package/dist/lib/parsers/helpers/parse-3d-implicit-tiles.d.ts +46 -0
  59. package/dist/lib/parsers/helpers/parse-3d-implicit-tiles.d.ts.map +1 -0
  60. package/dist/lib/parsers/helpers/parse-3d-implicit-tiles.js +222 -0
  61. package/dist/lib/parsers/helpers/parse-3d-implicit-tiles.js.map +1 -0
  62. package/dist/lib/parsers/helpers/parse-3d-tile-gltf-view.d.ts +7 -0
  63. package/dist/lib/parsers/helpers/parse-3d-tile-gltf-view.d.ts.map +1 -0
  64. package/dist/lib/parsers/helpers/parse-3d-tile-gltf-view.js +1 -1
  65. package/dist/lib/parsers/helpers/parse-3d-tile-gltf-view.js.map +1 -1
  66. package/dist/lib/parsers/helpers/parse-3d-tile-header.d.ts +2 -0
  67. package/dist/lib/parsers/helpers/parse-3d-tile-header.d.ts.map +1 -0
  68. package/dist/lib/parsers/helpers/parse-3d-tile-header.js.map +1 -1
  69. package/dist/lib/parsers/helpers/parse-3d-tile-subtree.d.ts +9 -0
  70. package/dist/lib/parsers/helpers/parse-3d-tile-subtree.d.ts.map +1 -0
  71. package/dist/lib/parsers/helpers/parse-3d-tile-subtree.js +64 -0
  72. package/dist/lib/parsers/helpers/parse-3d-tile-subtree.js.map +1 -0
  73. package/dist/lib/parsers/helpers/parse-3d-tile-tables.d.ts +3 -0
  74. package/dist/lib/parsers/helpers/parse-3d-tile-tables.d.ts.map +1 -0
  75. package/dist/lib/parsers/helpers/parse-3d-tile-tables.js +1 -1
  76. package/dist/lib/parsers/helpers/parse-3d-tile-tables.js.map +1 -1
  77. package/dist/lib/parsers/helpers/parse-utils.d.ts +4 -0
  78. package/dist/lib/parsers/helpers/parse-utils.d.ts.map +1 -0
  79. package/dist/lib/parsers/helpers/parse-utils.js.map +1 -1
  80. package/dist/lib/parsers/parse-3d-tile-batched-model.d.ts +2 -0
  81. package/dist/lib/parsers/parse-3d-tile-batched-model.d.ts.map +1 -0
  82. package/dist/lib/parsers/parse-3d-tile-batched-model.js.map +1 -1
  83. package/dist/lib/parsers/parse-3d-tile-composite.d.ts +2 -0
  84. package/dist/lib/parsers/parse-3d-tile-composite.d.ts.map +1 -0
  85. package/dist/lib/parsers/parse-3d-tile-composite.js.map +1 -1
  86. package/dist/lib/parsers/parse-3d-tile-gltf.d.ts +2 -0
  87. package/dist/lib/parsers/parse-3d-tile-gltf.d.ts.map +1 -0
  88. package/dist/lib/parsers/parse-3d-tile-gltf.js +10 -0
  89. package/dist/lib/parsers/parse-3d-tile-gltf.js.map +1 -0
  90. package/dist/lib/parsers/parse-3d-tile-header.d.ts +19 -0
  91. package/dist/lib/parsers/parse-3d-tile-header.d.ts.map +1 -0
  92. package/dist/lib/parsers/parse-3d-tile-header.js +72 -0
  93. package/dist/lib/parsers/parse-3d-tile-header.js.map +1 -1
  94. package/dist/lib/parsers/parse-3d-tile-instanced-model.d.ts +2 -0
  95. package/dist/lib/parsers/parse-3d-tile-instanced-model.d.ts.map +1 -0
  96. package/dist/lib/parsers/parse-3d-tile-instanced-model.js.map +1 -1
  97. package/dist/lib/parsers/parse-3d-tile-point-cloud.d.ts +3 -0
  98. package/dist/lib/parsers/parse-3d-tile-point-cloud.d.ts.map +1 -0
  99. package/dist/lib/parsers/parse-3d-tile-point-cloud.js +1 -1
  100. package/dist/lib/parsers/parse-3d-tile-point-cloud.js.map +1 -1
  101. package/dist/lib/parsers/parse-3d-tile.d.ts +2 -0
  102. package/dist/lib/parsers/parse-3d-tile.d.ts.map +1 -0
  103. package/dist/lib/parsers/parse-3d-tile.js +4 -0
  104. package/dist/lib/parsers/parse-3d-tile.js.map +1 -1
  105. package/dist/lib/utils/version.d.ts +2 -0
  106. package/dist/lib/utils/version.d.ts.map +1 -0
  107. package/dist/lib/utils/version.js +1 -1
  108. package/dist/lib/utils/version.js.map +1 -1
  109. package/dist/tile-3d-subtree-loader.d.ts +7 -0
  110. package/dist/tile-3d-subtree-loader.d.ts.map +1 -0
  111. package/dist/tile-3d-subtree-loader.js +14 -0
  112. package/dist/tile-3d-subtree-loader.js.map +1 -0
  113. package/dist/tile-3d-writer.d.ts +6 -0
  114. package/dist/tile-3d-writer.d.ts.map +1 -0
  115. package/dist/tiles-3d-loader.d.ts +6 -0
  116. package/dist/tiles-3d-loader.d.ts.map +1 -0
  117. package/dist/tiles-3d-loader.js +9 -2
  118. package/dist/tiles-3d-loader.js.map +1 -1
  119. package/dist/types.d.ts +80 -0
  120. package/dist/types.d.ts.map +1 -0
  121. package/package.json +10 -10
  122. package/src/index.ts +1 -0
  123. package/src/lib/classes/helpers/{tile-3d-accessor-utils.js → tile-3d-accessor-utils.ts} +0 -0
  124. package/src/lib/classes/{tile-3d-batch-table-hierarchy.js → tile-3d-batch-table-hierarchy.ts} +0 -0
  125. package/src/lib/classes/{tile-3d-batch-table.js → tile-3d-batch-table.ts} +14 -4
  126. package/src/lib/classes/{tile-3d-feature-table.js → tile-3d-feature-table.ts} +5 -2
  127. package/src/lib/{constants.js → constants.ts} +2 -1
  128. package/src/lib/encoders/{encode-3d-tile-batched-model.js → encode-3d-tile-batched-model.ts} +0 -0
  129. package/src/lib/encoders/{encode-3d-tile-composite.js → encode-3d-tile-composite.ts} +0 -0
  130. package/src/lib/encoders/{encode-3d-tile-instanced-model.js → encode-3d-tile-instanced-model.ts} +0 -0
  131. package/src/lib/encoders/{encode-3d-tile-point-cloud.js → encode-3d-tile-point-cloud.ts} +0 -0
  132. package/src/lib/encoders/{encode-3d-tile.js → encode-3d-tile.ts} +0 -0
  133. package/src/lib/encoders/helpers/{encode-3d-tile-header.js → encode-3d-tile-header.ts} +0 -0
  134. package/src/lib/ion/{ion.js → ion.ts} +0 -0
  135. package/src/lib/parsers/helpers/{normalize-3d-tile-colors.js → normalize-3d-tile-colors.ts} +1 -1
  136. package/src/lib/parsers/helpers/{normalize-3d-tile-normals.js → normalize-3d-tile-normals.ts} +0 -0
  137. package/src/lib/parsers/helpers/{normalize-3d-tile-positions.js → normalize-3d-tile-positions.ts} +0 -0
  138. package/src/lib/parsers/helpers/parse-3d-implicit-tiles.ts +319 -0
  139. package/src/lib/parsers/helpers/{parse-3d-tile-gltf-view.js → parse-3d-tile-gltf-view.ts} +1 -1
  140. package/src/lib/parsers/helpers/{parse-3d-tile-header.js → parse-3d-tile-header.ts} +0 -0
  141. package/src/lib/parsers/helpers/parse-3d-tile-subtree.ts +105 -0
  142. package/src/lib/parsers/helpers/{parse-3d-tile-tables.js → parse-3d-tile-tables.ts} +1 -1
  143. package/src/lib/parsers/helpers/{parse-utils.js → parse-utils.ts} +0 -0
  144. package/src/lib/parsers/{parse-3d-tile-batched-model.js → parse-3d-tile-batched-model.ts} +0 -0
  145. package/src/lib/parsers/{parse-3d-tile-composite.js → parse-3d-tile-composite.ts} +0 -0
  146. package/src/lib/parsers/parse-3d-tile-gltf.js +16 -0
  147. package/src/lib/parsers/parse-3d-tile-header.ts +152 -0
  148. package/src/lib/parsers/{parse-3d-tile-instanced-model.js → parse-3d-tile-instanced-model.ts} +6 -0
  149. package/src/lib/parsers/{parse-3d-tile-point-cloud.js → parse-3d-tile-point-cloud.ts} +2 -2
  150. package/src/lib/parsers/{parse-3d-tile.js → parse-3d-tile.ts} +8 -0
  151. package/src/lib/utils/{version.js → version.ts} +0 -0
  152. package/src/tile-3d-subtree-loader.ts +19 -0
  153. package/src/tiles-3d-loader.ts +17 -2
  154. package/src/types.ts +40 -1
  155. package/src/lib/parsers/parse-3d-tile-header.js +0 -69
@@ -0,0 +1,319 @@
1
+ import type {Availability, BoundingVolume, Subtree} from '../../../types';
2
+ import {Tile3DSubtreeLoader} from '../../../tile-3d-subtree-loader';
3
+ import {load} from '@loaders.gl/core';
4
+
5
+ const QUADTREE_DEVISION_COUNT = 4;
6
+ const OCTREE_DEVISION_COUNT = 8;
7
+
8
+ const SUBDIVISION_COUNT_MAP = {
9
+ QUADTREE: QUADTREE_DEVISION_COUNT,
10
+ OCTREE: OCTREE_DEVISION_COUNT
11
+ };
12
+
13
+ /**
14
+ * Recursively parse implicit tiles tree
15
+ * Spec - https://github.com/CesiumGS/3d-tiles/tree/main/extensions/3DTILES_implicit_tiling
16
+ * TODO Check out do we able to use Tile3D class as return type here.
17
+ * @param subtree
18
+ * @param lodMetricValue
19
+ * @param options
20
+ * @param parentData
21
+ * @param childIndex
22
+ * @param level
23
+ * @param globalData
24
+ */
25
+ // eslint-disable-next-line max-statements
26
+ export async function parseImplicitTiles(params: {
27
+ subtree: Subtree;
28
+ options: any;
29
+ parentData?: {mortonIndex: number; x: number; y: number; z: number};
30
+ childIndex?: number;
31
+ level?: number;
32
+ globalData?: {level: number; mortonIndex: number; x: number; y: number; z: number};
33
+ }) {
34
+ const {
35
+ options,
36
+ parentData = {
37
+ mortonIndex: 0,
38
+ x: 0,
39
+ y: 0,
40
+ z: 0
41
+ },
42
+ childIndex = 0,
43
+ globalData = {
44
+ level: 0,
45
+ mortonIndex: 0,
46
+ x: 0,
47
+ y: 0,
48
+ z: 0
49
+ }
50
+ } = params;
51
+ let {subtree, level = 0} = params;
52
+ const {
53
+ subdivisionScheme,
54
+ subtreeLevels,
55
+ maximumLevel,
56
+ contentUrlTemplate,
57
+ subtreesUriTemplate,
58
+ basePath
59
+ } = options;
60
+
61
+ const tile = {children: [], lodMetricValue: 0, contentUrl: ''};
62
+
63
+ const childrenPerTile = SUBDIVISION_COUNT_MAP[subdivisionScheme];
64
+
65
+ const childX = childIndex & 0b01;
66
+ const childY = (childIndex >> 1) & 0b01;
67
+ const childZ = (childIndex >> 2) & 0b01;
68
+
69
+ const levelOffset = (childrenPerTile ** level - 1) / (childrenPerTile - 1);
70
+ let childTileMortonIndex = concatBits(parentData.mortonIndex, childIndex);
71
+ let tileAvailabilityIndex = levelOffset + childTileMortonIndex;
72
+
73
+ // Local tile coordinates
74
+ let childTileX = concatBits(parentData.x, childX);
75
+ let childTileY = concatBits(parentData.y, childY);
76
+ let childTileZ = concatBits(parentData.z, childZ);
77
+
78
+ // TODO Remove after real implicit tileset will be tested.
79
+ // Degug data
80
+ // tile.level = level + globalData.level;
81
+ // tile.x = concatBits(globalData.x, childTileX);
82
+ // tile.y = concatBits(globalData.y, childTileY);
83
+ // tile.z = concatBits(globalData.z, childTileZ);
84
+ // tile.mortonIndex = childTileMortonIndex;
85
+ // End of debug data
86
+
87
+ let isChildSubtreeAvailable = false;
88
+
89
+ if (level + 1 > subtreeLevels) {
90
+ isChildSubtreeAvailable = getAvailabilityResult(
91
+ subtree.childSubtreeAvailability,
92
+ childTileMortonIndex
93
+ );
94
+ }
95
+
96
+ const x = concatBits(globalData.x, childTileX);
97
+ const y = concatBits(globalData.y, childTileY);
98
+ const z = concatBits(globalData.z, childTileZ);
99
+ const lev = level + globalData.level;
100
+
101
+ if (isChildSubtreeAvailable) {
102
+ const subtreePath = `${basePath}/${subtreesUriTemplate}`;
103
+ const childSubtreeUrl = replaceContentUrlTemplate(subtreePath, lev, x, y, z);
104
+ const childSubtree = await load(childSubtreeUrl, Tile3DSubtreeLoader);
105
+
106
+ subtree = childSubtree;
107
+
108
+ globalData.mortonIndex = childTileMortonIndex;
109
+ globalData.x = childTileX;
110
+ globalData.y = childTileY;
111
+ globalData.z = childTileZ;
112
+ globalData.level = level;
113
+
114
+ childTileMortonIndex = 0;
115
+ tileAvailabilityIndex = 0;
116
+ childTileX = 0;
117
+ childTileY = 0;
118
+ childTileZ = 0;
119
+ level = 0;
120
+ }
121
+
122
+ const isTileAvailable = getAvailabilityResult(subtree.tileAvailability, tileAvailabilityIndex);
123
+
124
+ if (!isTileAvailable || level > maximumLevel) {
125
+ return tile;
126
+ }
127
+
128
+ const isContentAvailable = getAvailabilityResult(
129
+ subtree.contentAvailability,
130
+ tileAvailabilityIndex
131
+ );
132
+
133
+ if (isContentAvailable) {
134
+ tile.contentUrl = replaceContentUrlTemplate(contentUrlTemplate, lev, x, y, z);
135
+ }
136
+
137
+ const childTileLevel = level + 1;
138
+ const pData = {mortonIndex: childTileMortonIndex, x: childTileX, y: childTileY, z: childTileZ};
139
+
140
+ for (let index = 0; index < childrenPerTile; index++) {
141
+ const currentTile = await parseImplicitTiles({
142
+ subtree,
143
+ options,
144
+ parentData: pData,
145
+ childIndex: index,
146
+ level: childTileLevel,
147
+ globalData
148
+ });
149
+
150
+ if (currentTile.contentUrl || currentTile.children.length) {
151
+ const globalLevel = lev + 1;
152
+ const childCoordinates = {childTileX, childTileY, childTileZ};
153
+ const formattedTile = formatTileData(currentTile, globalLevel, childCoordinates, options);
154
+ // @ts-ignore
155
+ tile.children.push(formattedTile);
156
+ }
157
+ }
158
+
159
+ return tile;
160
+ }
161
+
162
+ function getAvailabilityResult(availabilityData: Availability, index: number): boolean {
163
+ if ('constant' in availabilityData) {
164
+ return Boolean(availabilityData.constant);
165
+ }
166
+
167
+ if (availabilityData.explicitBitstream) {
168
+ return getBooleanValueFromBitstream(index, availabilityData.explicitBitstream);
169
+ }
170
+
171
+ return false;
172
+ }
173
+
174
+ /**
175
+ * Do formatting of implicit tile data.
176
+ * TODO Check out do we able to use Tile3D class as type here.
177
+ * @param tile
178
+ * @param lodMetricValue
179
+ * @param options
180
+ * @returns
181
+ */
182
+ function formatTileData(
183
+ tile,
184
+ level: number,
185
+ childCoordinates: {childTileX: number; childTileY: number; childTileZ: number},
186
+ options: any
187
+ ) {
188
+ const {
189
+ basePath,
190
+ refine,
191
+ getRefine,
192
+ lodMetricType,
193
+ getTileType,
194
+ rootLodMetricValue,
195
+ rootBoundingVolume
196
+ } = options;
197
+ const uri = tile.contentUrl && tile.contentUrl.replace(`${basePath}/`, '');
198
+ const lodMetricValue = rootLodMetricValue / 2 ** level;
199
+ const boundingVolume = calculateBoundingVolumeForChildTile(
200
+ level,
201
+ rootBoundingVolume,
202
+ childCoordinates
203
+ );
204
+
205
+ return {
206
+ children: tile.children,
207
+ contentUrl: tile.contentUrl,
208
+ content: {uri},
209
+ id: tile.contentUrl,
210
+ refine: getRefine(refine),
211
+ type: getTileType(tile),
212
+ lodMetricType,
213
+ lodMetricValue,
214
+ boundingVolume
215
+ // Temp debug values. Remove when real implicit tileset will be tested.
216
+ // x: tile.x,
217
+ // y: tile.y,
218
+ // z: tile.z,
219
+ // level: tile.level
220
+ };
221
+ }
222
+
223
+ /**
224
+ * Calculate child bounding volume.
225
+ * Spec - https://github.com/CesiumGS/3d-tiles/tree/main/extensions/3DTILES_implicit_tiling#subdivision-rules
226
+ * @param level
227
+ * @param rootBoundingVolume
228
+ * @param childCoordinates
229
+ */
230
+ function calculateBoundingVolumeForChildTile(
231
+ level: number,
232
+ rootBoundingVolume: BoundingVolume,
233
+ childCoordinates: {childTileX: number; childTileY: number; childTileZ: number}
234
+ ): BoundingVolume | null {
235
+ if (rootBoundingVolume.region) {
236
+ const {childTileX, childTileY, childTileZ} = childCoordinates;
237
+ const [west, south, east, north, minimumHeight, maximumHeight] = rootBoundingVolume.region;
238
+ const boundingVolumesCount = 2 ** level;
239
+
240
+ const sizeX = (east - west) / boundingVolumesCount;
241
+ const sizeY = (north - south) / boundingVolumesCount;
242
+ const sizeZ = (maximumHeight - minimumHeight) / boundingVolumesCount;
243
+
244
+ const [childWest, childEast] = [west + sizeX * childTileX, west + sizeX * (childTileX + 1)];
245
+ const [childSouth, childNorth] = [south + sizeY * childTileY, south + sizeY * (childTileY + 1)];
246
+ const [childMinimumHeight, childMaximumHeight] = [
247
+ minimumHeight + sizeZ * childTileZ,
248
+ minimumHeight + sizeZ * (childTileZ + 1)
249
+ ];
250
+
251
+ return {
252
+ region: [childWest, childSouth, childEast, childNorth, childMinimumHeight, childMaximumHeight]
253
+ };
254
+ }
255
+
256
+ // eslint-disable-next-line no-console
257
+ console.warn('Unsupported bounding volume type: ', rootBoundingVolume);
258
+ return null;
259
+ }
260
+
261
+ /**
262
+ * Do binary concatenation
263
+ * @param first
264
+ * @param second
265
+ */
266
+ function concatBits(first: number, second: number): number {
267
+ return parseInt(first.toString(2) + second.toString(2), 2);
268
+ }
269
+
270
+ /**
271
+ * Replace implicit tile content url with real coordinates.
272
+ * @param templateUrl
273
+ * @param level
274
+ * @param x
275
+ * @param y
276
+ * @param z
277
+ */
278
+ export function replaceContentUrlTemplate(
279
+ templateUrl: string,
280
+ level: number,
281
+ x: number,
282
+ y: number,
283
+ z: number
284
+ ): string {
285
+ const mapUrl = generateMapUrl({level, x, y, z});
286
+ return templateUrl.replace(/{level}|{x}|{y}|{z}/gi, (matched) => mapUrl[matched]);
287
+ }
288
+
289
+ /**
290
+ * Get Map object for content url generation
291
+ * @param items
292
+ */
293
+ function generateMapUrl(items: {[key: string]: number}): {[key: string]: string} {
294
+ const mapUrl = {};
295
+
296
+ for (const key in items) {
297
+ mapUrl[`{${key}}`] = items[key];
298
+ }
299
+ return mapUrl;
300
+ }
301
+
302
+ /**
303
+ * Get boolean value from bistream by index
304
+ * A boolean value is encoded as a single bit, either 0 (false) or 1 (true).
305
+ * Multiple boolean values are packed tightly in the same buffer.
306
+ * These buffers of tightly-packed bits are sometimes referred to as bitstreams.
307
+ * Spec - https://github.com/CesiumGS/3d-tiles/tree/implicit-revisions/specification/Metadata#booleans
308
+ * @param availabilitiIndex
309
+ */
310
+ function getBooleanValueFromBitstream(
311
+ availabilityIndex: number,
312
+ availabilityBuffer: Uint8Array
313
+ ): boolean {
314
+ const byteIndex = Math.floor(availabilityIndex / 8);
315
+ const bitIndex = availabilityIndex % 8;
316
+ const bitValue = (availabilityBuffer[byteIndex] >> bitIndex) & 1;
317
+
318
+ return bitValue === 1;
319
+ }
@@ -90,6 +90,6 @@ function extractGLTFBufferOrURL(tile, gltfFormat, options) {
90
90
  case GLTF_FORMAT.EMBEDDED:
91
91
  break;
92
92
  default:
93
- throw new Error(`b3dm: Illegal glTF format field`);
93
+ throw new Error('b3dm: Illegal glTF format field');
94
94
  }
95
95
  }
@@ -0,0 +1,105 @@
1
+ import type {Subtree, ExplicitBitstream} from '../../../types';
2
+ import {fetchFile} from '@loaders.gl/core';
3
+
4
+ const SUBTREE_FILE_MAGIC = 0x74627573;
5
+ const SUBTREE_FILE_VERSION = 1;
6
+
7
+ /**
8
+ * Parse subtree file
9
+ * Spec - https://github.com/CesiumGS/3d-tiles/tree/main/extensions/3DTILES_implicit_tiling#subtree-file-format
10
+ * @param data
11
+ * @returns
12
+ */
13
+ // eslint-disable-next-line max-statements
14
+ export default async function parse3DTilesSubtree(data: ArrayBuffer): Promise<Subtree> {
15
+ const magic = new Uint32Array(data.slice(0, 4));
16
+
17
+ if (magic[0] !== SUBTREE_FILE_MAGIC) {
18
+ throw new Error('Wrong subtree file magic number');
19
+ }
20
+
21
+ const version = new Uint32Array(data.slice(4, 8));
22
+
23
+ if (version[0] !== SUBTREE_FILE_VERSION) {
24
+ throw new Error('Wrong subtree file verson, must be 1');
25
+ }
26
+
27
+ const jsonByteLength = parseUint64Value(data.slice(8, 16));
28
+ const stringAttribute = new Uint8Array(data, 24, jsonByteLength);
29
+
30
+ const textDecoder = new TextDecoder('utf8');
31
+ const string = textDecoder.decode(stringAttribute);
32
+ const subtree = JSON.parse(string);
33
+
34
+ const binaryByteLength = parseUint64Value(data.slice(16, 24));
35
+ let internalBinaryBuffer = new ArrayBuffer(0);
36
+
37
+ if (binaryByteLength) {
38
+ internalBinaryBuffer = data.slice(24 + jsonByteLength);
39
+ }
40
+
41
+ if ('bufferView' in subtree.tileAvailability) {
42
+ subtree.tileAvailability.explicitBitstream = await getExplicitBitstream(
43
+ subtree,
44
+ 'tileAvailability',
45
+ internalBinaryBuffer
46
+ );
47
+ }
48
+
49
+ if ('bufferView' in subtree.contentAvailability) {
50
+ subtree.contentAvailability.explicitBitstream = await getExplicitBitstream(
51
+ subtree,
52
+ 'contentAvailability',
53
+ internalBinaryBuffer
54
+ );
55
+ }
56
+
57
+ if ('bufferView' in subtree.childSubtreeAvailability) {
58
+ subtree.childSubtreeAvailability.explicitBitstream = await getExplicitBitstream(
59
+ subtree,
60
+ 'childSubtreeAvailability',
61
+ internalBinaryBuffer
62
+ );
63
+ }
64
+
65
+ return subtree;
66
+ }
67
+
68
+ /**
69
+ * Get explicit bitstream for subtree availability data.
70
+ * @param subtree
71
+ * @param name
72
+ * @param internalBinaryBuffer
73
+ */
74
+ async function getExplicitBitstream(
75
+ subtree: Subtree,
76
+ name: string,
77
+ internalBinaryBuffer: ArrayBuffer
78
+ ): Promise<ExplicitBitstream> {
79
+ const bufferViewIndex = subtree[name].bufferView;
80
+ const bufferView = subtree.bufferViews[bufferViewIndex];
81
+ const buffer = subtree.buffers[bufferView.buffer];
82
+
83
+ // External bitstream loading
84
+ if (buffer.uri) {
85
+ const response = await fetchFile(buffer.uri);
86
+ const data = await response.arrayBuffer();
87
+ // Return view of bitstream.
88
+ return new Uint8Array(data, bufferView.byteOffset, bufferView.byteLength);
89
+ }
90
+ // Return view of bitstream.
91
+ return new Uint8Array(internalBinaryBuffer, bufferView.byteOffset, bufferView.byteLength);
92
+ }
93
+
94
+ /**
95
+ * Parse buffer to return uint64 value
96
+ * @param buffer
97
+ * @returns 64-bit value until precision is lost after Number.MAX_SAFE_INTEGER
98
+ */
99
+ function parseUint64Value(buffer: ArrayBuffer): number {
100
+ const dataView = new DataView(buffer);
101
+ const left = dataView.getUint32(0, true);
102
+ const right = dataView.getUint32(4, true);
103
+ // combine the two 32-bit values
104
+ return left + 2 ** 32 * right;
105
+ }
@@ -4,7 +4,7 @@
4
4
  import {getStringFromArrayBuffer} from './parse-utils';
5
5
 
6
6
  const SIZEOF_UINT32 = 4;
7
- const DEPRECATION_WARNING = `b3dm tile in legacy format.`;
7
+ const DEPRECATION_WARNING = 'b3dm tile in legacy format.';
8
8
 
9
9
  // eslint-disable-next-line max-statements
10
10
  export function parse3DTileTablesHeaderSync(tile, arrayBuffer, byteOffset) {
@@ -0,0 +1,16 @@
1
+ import {GLTFLoader} from '@loaders.gl/gltf';
2
+
3
+ export async function parseGltf3DTile(tile, arrayBuffer, options, context) {
4
+ // Set flags
5
+ // glTF models need to be rotated from Y to Z up
6
+ // https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#y-up-to-z-up
7
+ tile.rotateYtoZ = true;
8
+ // Save gltf up axis
9
+ tile.gltfUpAxis =
10
+ options['3d-tiles'] && options['3d-tiles'].assetGltfUpAxis
11
+ ? options['3d-tiles'].assetGltfUpAxis
12
+ : 'Y';
13
+
14
+ const {parse} = context;
15
+ tile.gltf = await parse(arrayBuffer, GLTFLoader, options, context);
16
+ }
@@ -0,0 +1,152 @@
1
+ import {Tile3DSubtreeLoader} from '../../tile-3d-subtree-loader';
2
+ import {load} from '@loaders.gl/core';
3
+ import {Tileset3D, LOD_METRIC_TYPE, TILE_REFINEMENT, TILE_TYPE} from '@loaders.gl/tiles';
4
+ import {Subtree} from '../../types';
5
+ import {parseImplicitTiles, replaceContentUrlTemplate} from './helpers/parse-3d-implicit-tiles';
6
+
7
+ function getTileType(tile) {
8
+ if (!tile.contentUrl) {
9
+ return TILE_TYPE.EMPTY;
10
+ }
11
+
12
+ const contentUrl = tile.contentUrl;
13
+ const fileExtension = contentUrl.split('.').pop();
14
+ switch (fileExtension) {
15
+ case 'pnts':
16
+ return TILE_TYPE.POINTCLOUD;
17
+ case 'i3dm':
18
+ case 'b3dm':
19
+ case 'glb':
20
+ case 'gltf':
21
+ return TILE_TYPE.SCENEGRAPH;
22
+ default:
23
+ return fileExtension;
24
+ }
25
+ }
26
+
27
+ function getRefine(refine) {
28
+ switch (refine) {
29
+ case 'REPLACE':
30
+ case 'replace':
31
+ return TILE_REFINEMENT.REPLACE;
32
+ case 'ADD':
33
+ case 'add':
34
+ return TILE_REFINEMENT.ADD;
35
+ default:
36
+ return refine;
37
+ }
38
+ }
39
+
40
+ export function normalizeTileData(tile, options) {
41
+ if (!tile) {
42
+ return null;
43
+ }
44
+ if (tile.content) {
45
+ const contentUri = tile.content.uri || tile.content.url;
46
+ tile.contentUrl = `${options.basePath}/${contentUri}`;
47
+ }
48
+ tile.id = tile.contentUrl;
49
+ tile.lodMetricType = LOD_METRIC_TYPE.GEOMETRIC_ERROR;
50
+ tile.lodMetricValue = tile.geometricError;
51
+ tile.transformMatrix = tile.transform;
52
+ tile.type = getTileType(tile);
53
+ tile.refine = getRefine(tile.refine);
54
+
55
+ return tile;
56
+ }
57
+
58
+ // normalize tile headers
59
+ export function normalizeTileHeaders(tileset) {
60
+ const basePath = tileset.basePath;
61
+ const root = normalizeTileData(tileset.root, tileset);
62
+
63
+ const stack: any[] = [];
64
+ stack.push(root);
65
+
66
+ while (stack.length > 0) {
67
+ const tile = stack.pop() || {};
68
+ const children = tile.children || [];
69
+ for (const childHeader of children) {
70
+ normalizeTileData(childHeader, {basePath});
71
+ stack.push(childHeader);
72
+ }
73
+ }
74
+
75
+ return root;
76
+ }
77
+
78
+ /**
79
+ * Do normalisation of implicit tile headers
80
+ * TODO Check if Tile3D class can be a return type here.
81
+ * @param tileset
82
+ */
83
+ export async function normalizeImplicitTileHeaders(tileset: Tileset3D) {
84
+ if (!tileset.root) {
85
+ return null;
86
+ }
87
+
88
+ const basePath = tileset.basePath;
89
+ const implicitTilingExtension = tileset.root.extensions['3DTILES_implicit_tiling'];
90
+ const {
91
+ subdivisionScheme,
92
+ maximumLevel,
93
+ subtreeLevels,
94
+ subtrees: {uri: subtreesUriTemplate}
95
+ } = implicitTilingExtension;
96
+ const subtreeUrl = replaceContentUrlTemplate(subtreesUriTemplate, 0, 0, 0, 0);
97
+ const rootSubtreeUrl = `${basePath}/${subtreeUrl}`;
98
+ const rootSubtree = await load(rootSubtreeUrl, Tile3DSubtreeLoader);
99
+ const contentUrlTemplate = `${basePath}/${tileset.root.content.uri}`;
100
+ const refine = tileset.root.refine;
101
+ // @ts-ignore
102
+ const rootLodMetricValue = tileset.root.geometricError;
103
+ const rootBoundingVolume = tileset.root.boundingVolume;
104
+
105
+ const options = {
106
+ contentUrlTemplate,
107
+ subtreesUriTemplate,
108
+ subdivisionScheme,
109
+ subtreeLevels,
110
+ maximumLevel,
111
+ refine,
112
+ basePath,
113
+ lodMetricType: LOD_METRIC_TYPE.GEOMETRIC_ERROR,
114
+ rootLodMetricValue,
115
+ rootBoundingVolume,
116
+ getTileType,
117
+ getRefine
118
+ };
119
+
120
+ return await normalizeImplicitTileData(tileset.root, rootSubtree, options);
121
+ }
122
+
123
+ /**
124
+ * Do implicit data normalisation to create hierarchical tile structure
125
+ * @param tile
126
+ * @param rootSubtree
127
+ * @param options
128
+ * @returns
129
+ */
130
+ export async function normalizeImplicitTileData(tile, rootSubtree: Subtree, options: any) {
131
+ if (!tile) {
132
+ return null;
133
+ }
134
+
135
+ tile.lodMetricType = LOD_METRIC_TYPE.GEOMETRIC_ERROR;
136
+ tile.lodMetricValue = tile.geometricError;
137
+ tile.transformMatrix = tile.transform;
138
+
139
+ const {children, contentUrl} = await parseImplicitTiles({subtree: rootSubtree, options});
140
+
141
+ if (contentUrl) {
142
+ tile.contentUrl = contentUrl;
143
+ tile.content = {uri: contentUrl.replace(`${options.basePath}/`, '')};
144
+ }
145
+
146
+ tile.refine = getRefine(tile.refine);
147
+ tile.type = getTileType(tile);
148
+ tile.children = children;
149
+ tile.id = tile.contentUrl;
150
+
151
+ return tile;
152
+ }
@@ -146,6 +146,7 @@ function extractInstancedAttributes(tile, featureTable, batchTable, instancesLen
146
146
  }
147
147
 
148
148
  instancePosition.copy(position);
149
+ // @ts-expect-error
149
150
  instanceTranslationRotationScale.translation = instancePosition;
150
151
 
151
152
  // Get the instance rotation
@@ -203,6 +204,7 @@ function extractInstancedAttributes(tile, featureTable, batchTable, instancesLen
203
204
  }
204
205
 
205
206
  instanceQuaternion.fromMatrix3(instanceRotation);
207
+ // @ts-expect-error
206
208
  instanceTranslationRotationScale.rotation = instanceQuaternion;
207
209
 
208
210
  // Get the instance scale
@@ -216,6 +218,7 @@ function extractInstancedAttributes(tile, featureTable, batchTable, instancesLen
216
218
  instanceScale.scale(nonUniformScale);
217
219
  }
218
220
 
221
+ // @ts-expect-error
219
222
  instanceTranslationRotationScale.scale = instanceScale;
220
223
 
221
224
  // Get the batchId
@@ -225,12 +228,15 @@ function extractInstancedAttributes(tile, featureTable, batchTable, instancesLen
225
228
  batchId = i;
226
229
  }
227
230
 
231
+ // @ts-expect-error
228
232
  const rotationMatrix = new Matrix4().fromQuaternion(instanceTranslationRotationScale.rotation);
229
233
 
230
234
  // Create the model matrix and the instance
231
235
  instanceTransform.identity();
236
+ // @ts-expect-error
232
237
  instanceTransform.translate(instanceTranslationRotationScale.translation);
233
238
  instanceTransform.multiplyRight(rotationMatrix);
239
+ // @ts-expect-error
234
240
  instanceTransform.scale(instanceTranslationRotationScale.scale);
235
241
 
236
242
  const modelMatrix = instanceTransform.clone();
@@ -137,7 +137,7 @@ function parseNormals(tile, featureTable) {
137
137
  }
138
138
 
139
139
  function parseBatchIds(tile, featureTable) {
140
- let batchTable = null;
140
+ let batchTable: Tile3DBatchTable | null = null;
141
141
  if (!tile.batchIds && featureTable.hasProperty('BATCH_ID')) {
142
142
  tile.batchIds = featureTable.getPropertyArray('BATCH_ID', GL.UNSIGNED_SHORT, 1);
143
143
 
@@ -250,7 +250,7 @@ export async function loadDraco(tile, dracoData, options, context) {
250
250
 
251
251
  tile.attributes = {
252
252
  positions: decodedPositions,
253
- colors: normalize3DTileColorAttribute(tile, decodedColors),
253
+ colors: normalize3DTileColorAttribute(tile, decodedColors, undefined),
254
254
  normals: decodedNormals,
255
255
  batchIds: decodedBatchIds,
256
256
  ...batchTableAttributes