@loaders.gl/3d-tiles 4.0.0-alpha.8 → 4.0.0-beta.1

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 (170) hide show
  1. package/dist/3d-tiles-archive/3d-tiles-archive-archive.d.ts +30 -0
  2. package/dist/3d-tiles-archive/3d-tiles-archive-archive.d.ts.map +1 -0
  3. package/dist/3d-tiles-archive/3d-tiles-archive-parser.d.ts +10 -0
  4. package/dist/3d-tiles-archive/3d-tiles-archive-parser.d.ts.map +1 -0
  5. package/dist/3d-tiles-archive-loader.d.ts +13 -0
  6. package/dist/3d-tiles-archive-loader.d.ts.map +1 -0
  7. package/dist/cesium-ion-loader.d.ts +2 -2
  8. package/dist/cesium-ion-loader.d.ts.map +1 -1
  9. package/dist/dist.min.js +10981 -4462
  10. package/dist/es5/3d-tiles-archive/3d-tiles-archive-archive.js +126 -0
  11. package/dist/es5/3d-tiles-archive/3d-tiles-archive-archive.js.map +1 -0
  12. package/dist/es5/3d-tiles-archive/3d-tiles-archive-parser.js +69 -0
  13. package/dist/es5/3d-tiles-archive/3d-tiles-archive-parser.js.map +1 -0
  14. package/dist/es5/3d-tiles-archive-loader.js +50 -0
  15. package/dist/es5/3d-tiles-archive-loader.js.map +1 -0
  16. package/dist/es5/cesium-ion-loader.js.map +1 -1
  17. package/dist/es5/index.js +14 -0
  18. package/dist/es5/index.js.map +1 -1
  19. package/dist/es5/lib/filesystems/tiles-3d-archive-file-system.js +151 -0
  20. package/dist/es5/lib/filesystems/tiles-3d-archive-file-system.js.map +1 -0
  21. package/dist/es5/lib/ion/ion.js +3 -9
  22. package/dist/es5/lib/ion/ion.js.map +1 -1
  23. package/dist/es5/lib/parsers/helpers/parse-3d-implicit-tiles.js +63 -38
  24. package/dist/es5/lib/parsers/helpers/parse-3d-implicit-tiles.js.map +1 -1
  25. package/dist/es5/lib/parsers/helpers/parse-3d-tile-gltf-view.js +3 -3
  26. package/dist/es5/lib/parsers/helpers/parse-3d-tile-gltf-view.js.map +1 -1
  27. package/dist/es5/lib/parsers/helpers/parse-3d-tile-subtree.js +70 -55
  28. package/dist/es5/lib/parsers/helpers/parse-3d-tile-subtree.js.map +1 -1
  29. package/dist/es5/lib/parsers/parse-3d-tile-composite.js +3 -1
  30. package/dist/es5/lib/parsers/parse-3d-tile-composite.js.map +1 -1
  31. package/dist/es5/lib/parsers/parse-3d-tile-gltf.js +14 -12
  32. package/dist/es5/lib/parsers/parse-3d-tile-gltf.js.map +1 -1
  33. package/dist/es5/lib/parsers/parse-3d-tile-header.js +14 -12
  34. package/dist/es5/lib/parsers/parse-3d-tile-header.js.map +1 -1
  35. package/dist/es5/lib/parsers/parse-3d-tile-point-cloud.js +6 -6
  36. package/dist/es5/lib/parsers/parse-3d-tile-point-cloud.js.map +1 -1
  37. package/dist/es5/lib/parsers/parse-3d-tile.js +3 -1
  38. package/dist/es5/lib/parsers/parse-3d-tile.js.map +1 -1
  39. package/dist/es5/lib/utils/version.js +1 -1
  40. package/dist/es5/lib/utils/version.js.map +1 -1
  41. package/dist/es5/tile-3d-subtree-loader.js.map +1 -1
  42. package/dist/es5/tile-3d-writer.js.map +1 -1
  43. package/dist/es5/tiles-3d-loader.js +2 -0
  44. package/dist/es5/tiles-3d-loader.js.map +1 -1
  45. package/dist/es5/types.js.map +1 -1
  46. package/dist/esm/3d-tiles-archive/3d-tiles-archive-archive.js +46 -0
  47. package/dist/esm/3d-tiles-archive/3d-tiles-archive-archive.js.map +1 -0
  48. package/dist/esm/3d-tiles-archive/3d-tiles-archive-parser.js +23 -0
  49. package/dist/esm/3d-tiles-archive/3d-tiles-archive-parser.js.map +1 -0
  50. package/dist/esm/3d-tiles-archive-loader.js +20 -0
  51. package/dist/esm/3d-tiles-archive-loader.js.map +1 -0
  52. package/dist/esm/cesium-ion-loader.js.map +1 -1
  53. package/dist/esm/index.js +2 -0
  54. package/dist/esm/index.js.map +1 -1
  55. package/dist/esm/lib/filesystems/tiles-3d-archive-file-system.js +49 -0
  56. package/dist/esm/lib/filesystems/tiles-3d-archive-file-system.js.map +1 -0
  57. package/dist/esm/lib/ion/ion.js +3 -9
  58. package/dist/esm/lib/ion/ion.js.map +1 -1
  59. package/dist/esm/lib/parsers/helpers/parse-3d-implicit-tiles.js +45 -23
  60. package/dist/esm/lib/parsers/helpers/parse-3d-implicit-tiles.js.map +1 -1
  61. package/dist/esm/lib/parsers/helpers/parse-3d-tile-gltf-view.js +5 -6
  62. package/dist/esm/lib/parsers/helpers/parse-3d-tile-gltf-view.js.map +1 -1
  63. package/dist/esm/lib/parsers/helpers/parse-3d-tile-subtree.js +18 -24
  64. package/dist/esm/lib/parsers/helpers/parse-3d-tile-subtree.js.map +1 -1
  65. package/dist/esm/lib/parsers/parse-3d-tile-composite.js +3 -1
  66. package/dist/esm/lib/parsers/parse-3d-tile-composite.js.map +1 -1
  67. package/dist/esm/lib/parsers/parse-3d-tile-gltf.js +7 -8
  68. package/dist/esm/lib/parsers/parse-3d-tile-gltf.js.map +1 -1
  69. package/dist/esm/lib/parsers/parse-3d-tile-header.js +8 -5
  70. package/dist/esm/lib/parsers/parse-3d-tile-header.js.map +1 -1
  71. package/dist/esm/lib/parsers/parse-3d-tile-point-cloud.js +2 -4
  72. package/dist/esm/lib/parsers/parse-3d-tile-point-cloud.js.map +1 -1
  73. package/dist/esm/lib/parsers/parse-3d-tile.js +3 -1
  74. package/dist/esm/lib/parsers/parse-3d-tile.js.map +1 -1
  75. package/dist/esm/lib/utils/version.js +1 -1
  76. package/dist/esm/lib/utils/version.js.map +1 -1
  77. package/dist/esm/tile-3d-subtree-loader.js.map +1 -1
  78. package/dist/esm/tile-3d-writer.js.map +1 -1
  79. package/dist/esm/tiles-3d-loader.js +2 -0
  80. package/dist/esm/tiles-3d-loader.js.map +1 -1
  81. package/dist/esm/types.js.map +1 -1
  82. package/dist/index.d.ts +3 -0
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/lib/filesystems/tiles-3d-archive-file-system.d.ts +32 -0
  85. package/dist/lib/filesystems/tiles-3d-archive-file-system.d.ts.map +1 -0
  86. package/dist/lib/parsers/helpers/parse-3d-implicit-tiles.d.ts +4 -1
  87. package/dist/lib/parsers/helpers/parse-3d-implicit-tiles.d.ts.map +1 -1
  88. package/dist/lib/parsers/helpers/parse-3d-tile-gltf-view.d.ts.map +1 -1
  89. package/dist/lib/parsers/helpers/parse-3d-tile-subtree.d.ts.map +1 -1
  90. package/dist/lib/parsers/parse-3d-tile-gltf.d.ts +2 -2
  91. package/dist/lib/parsers/parse-3d-tile-gltf.d.ts.map +1 -1
  92. package/dist/lib/parsers/parse-3d-tile-header.d.ts +30 -2
  93. package/dist/lib/parsers/parse-3d-tile-header.d.ts.map +1 -1
  94. package/dist/lib/parsers/parse-3d-tile-point-cloud.d.ts +1 -1
  95. package/dist/lib/parsers/parse-3d-tile-point-cloud.d.ts.map +1 -1
  96. package/dist/lib/parsers/parse-3d-tile.d.ts +1 -1
  97. package/dist/lib/parsers/parse-3d-tile.d.ts.map +1 -1
  98. package/dist/tile-3d-subtree-loader.d.ts +3 -3
  99. package/dist/tile-3d-subtree-loader.d.ts.map +1 -1
  100. package/dist/tile-3d-writer.d.ts +2 -2
  101. package/dist/tile-3d-writer.d.ts.map +1 -1
  102. package/dist/tiles-3d-loader.d.ts +2 -1
  103. package/dist/tiles-3d-loader.d.ts.map +1 -1
  104. package/dist/types.d.ts +49 -8
  105. package/dist/types.d.ts.map +1 -1
  106. package/package.json +10 -8
  107. package/src/3d-tiles-archive/3d-tiles-archive-archive.ts +85 -0
  108. package/src/3d-tiles-archive/3d-tiles-archive-parser.ts +52 -0
  109. package/src/3d-tiles-archive-loader.ts +47 -0
  110. package/src/cesium-ion-loader.ts +2 -3
  111. package/src/index.ts +3 -0
  112. package/src/lib/filesystems/tiles-3d-archive-file-system.ts +97 -0
  113. package/src/lib/ion/ion.ts +3 -3
  114. package/src/lib/parsers/helpers/parse-3d-implicit-tiles.ts +76 -32
  115. package/src/lib/parsers/helpers/parse-3d-tile-gltf-view.ts +8 -3
  116. package/src/lib/parsers/helpers/parse-3d-tile-subtree.ts +44 -62
  117. package/src/lib/parsers/parse-3d-tile-composite.ts +1 -1
  118. package/src/lib/parsers/parse-3d-tile-gltf.ts +11 -10
  119. package/src/lib/parsers/parse-3d-tile-header.ts +39 -6
  120. package/src/lib/parsers/parse-3d-tile-point-cloud.ts +10 -3
  121. package/src/lib/parsers/parse-3d-tile.ts +2 -2
  122. package/src/tile-3d-subtree-loader.ts +3 -3
  123. package/src/tile-3d-writer.ts +2 -2
  124. package/src/tiles-3d-loader.ts +16 -4
  125. package/src/types.ts +52 -9
  126. package/dist/bundle.js +0 -5
  127. package/dist/cesium-ion-loader.js +0 -41
  128. package/dist/index.js +0 -26
  129. package/dist/lib/classes/helpers/tile-3d-accessor-utils.js +0 -113
  130. package/dist/lib/classes/tile-3d-batch-table-hierarchy.js +0 -197
  131. package/dist/lib/classes/tile-3d-batch-table.js +0 -245
  132. package/dist/lib/classes/tile-3d-feature-table.js +0 -72
  133. package/dist/lib/constants.js +0 -26
  134. package/dist/lib/encoders/encode-3d-tile-batched-model.js +0 -46
  135. package/dist/lib/encoders/encode-3d-tile-composite.js +0 -24
  136. package/dist/lib/encoders/encode-3d-tile-instanced-model.js +0 -38
  137. package/dist/lib/encoders/encode-3d-tile-point-cloud.js +0 -39
  138. package/dist/lib/encoders/encode-3d-tile.js +0 -33
  139. package/dist/lib/encoders/helpers/encode-3d-tile-header.js +0 -30
  140. package/dist/lib/ion/ion.js +0 -68
  141. package/dist/lib/parsers/helpers/normalize-3d-tile-colors.js +0 -65
  142. package/dist/lib/parsers/helpers/normalize-3d-tile-normals.js +0 -30
  143. package/dist/lib/parsers/helpers/normalize-3d-tile-positions.js +0 -42
  144. package/dist/lib/parsers/helpers/parse-3d-implicit-tiles.js +0 -266
  145. package/dist/lib/parsers/helpers/parse-3d-tile-gltf-view.js +0 -96
  146. package/dist/lib/parsers/helpers/parse-3d-tile-header.js +0 -28
  147. package/dist/lib/parsers/helpers/parse-3d-tile-subtree.js +0 -104
  148. package/dist/lib/parsers/helpers/parse-3d-tile-tables.js +0 -93
  149. package/dist/lib/parsers/helpers/parse-utils.js +0 -32
  150. package/dist/lib/parsers/parse-3d-tile-batched-model.js +0 -33
  151. package/dist/lib/parsers/parse-3d-tile-composite.js +0 -24
  152. package/dist/lib/parsers/parse-3d-tile-gltf.js +0 -28
  153. package/dist/lib/parsers/parse-3d-tile-header.js +0 -192
  154. package/dist/lib/parsers/parse-3d-tile-instanced-model.js +0 -172
  155. package/dist/lib/parsers/parse-3d-tile-point-cloud.js +0 -433
  156. package/dist/lib/parsers/parse-3d-tile.js +0 -33
  157. package/dist/lib/utils/obb/s2-corners-to-obb.js +0 -37
  158. package/dist/lib/utils/s2/converters/s2-to-boundary.js +0 -61
  159. package/dist/lib/utils/s2/converters/s2-to-obb-points.js +0 -36
  160. package/dist/lib/utils/s2/converters/s2-to-region.js +0 -59
  161. package/dist/lib/utils/s2/index.js +0 -23
  162. package/dist/lib/utils/s2/s2-geometry-functions.js +0 -29
  163. package/dist/lib/utils/s2/s2-token-functions.js +0 -68
  164. package/dist/lib/utils/s2/s2geometry/s2-cell-utils.js +0 -32
  165. package/dist/lib/utils/s2/s2geometry/s2-geometry.js +0 -260
  166. package/dist/lib/utils/version.js +0 -7
  167. package/dist/tile-3d-subtree-loader.js +0 -23
  168. package/dist/tile-3d-writer.js +0 -27
  169. package/dist/tiles-3d-loader.js +0 -76
  170. package/dist/types.js +0 -2
@@ -1,4 +1,4 @@
1
- import type {LoaderWithParser} from '@loaders.gl/loader-utils';
1
+ import type {LoaderOptions, LoaderWithParser} from '@loaders.gl/loader-utils';
2
2
  import {Tiles3DLoader} from './tiles-3d-loader';
3
3
  import {getIonTilesetMetadata} from './lib/ion/ion';
4
4
 
@@ -18,7 +18,7 @@ async function preload(url, options = {}) {
18
18
  /**
19
19
  * Loader for 3D tiles from Cesium ION
20
20
  */
21
- export const CesiumIonLoader: LoaderWithParser = {
21
+ export const CesiumIonLoader: LoaderWithParser<unknown, never, LoaderOptions> = {
22
22
  ...Tiles3DLoader,
23
23
  id: 'cesium-ion',
24
24
  name: 'Cesium Ion',
@@ -33,7 +33,6 @@ export const CesiumIonLoader: LoaderWithParser = {
33
33
  },
34
34
  options: {
35
35
  'cesium-ion': {
36
- // @ts-expect-error
37
36
  ...Tiles3DLoader.options['3d-tiles'],
38
37
  accessToken: null
39
38
  }
package/src/index.ts CHANGED
@@ -2,6 +2,9 @@
2
2
  export {Tiles3DLoader} from './tiles-3d-loader';
3
3
  export {CesiumIonLoader} from './cesium-ion-loader';
4
4
  export {Tile3DSubtreeLoader} from './tile-3d-subtree-loader';
5
+ export type {Tiles3DArchiveFileLoaderOptions} from './3d-tiles-archive-loader';
6
+ export {Tiles3DArchiveFileLoader} from './3d-tiles-archive-loader';
7
+ export {Tiles3DArchiveFileSystem} from './lib/filesystems/tiles-3d-archive-file-system';
5
8
 
6
9
  // WRITERS
7
10
  export {Tile3DWriter} from './tile-3d-writer';
@@ -0,0 +1,97 @@
1
+ import {FileProvider} from '@loaders.gl/loader-utils';
2
+ import {
3
+ ZipFileSystem,
4
+ cdSignature as cdHeaderSignature,
5
+ searchFromTheEnd,
6
+ parseZipCDFileHeader,
7
+ HashElement,
8
+ parseHashFile,
9
+ parseZipLocalFileHeader
10
+ } from '@loaders.gl/zip';
11
+ import {Tiles3DArchive} from '../../3d-tiles-archive/3d-tiles-archive-archive';
12
+
13
+ /**
14
+ * FileSystem adapter for a 3tz (3D tiles archive format) file
15
+ * Holds FileProvider object that provides random access to archived files.
16
+ * The difference from ZipFileSystem is usage of `@3dtilesIndex1@` index file that increases
17
+ * access speed to archived files
18
+ * @see https://github.com/erikdahlstrom/3tz-specification/blob/master/Specification.md
19
+ */
20
+ export class Tiles3DArchiveFileSystem extends ZipFileSystem {
21
+ hashData?: HashElement[] | null;
22
+
23
+ /**
24
+ * Constructor
25
+ * @param file - instance of FileProvider or file path string
26
+ */
27
+ constructor(file: FileProvider | string) {
28
+ super(file);
29
+ }
30
+
31
+ /**
32
+ * Implementation of fetch against this file system.
33
+ * It tries to take `@3dtilesIndex1@` file from the archive and use it
34
+ * for faster access to archived files
35
+ * @param filename - name of a file
36
+ * @returns - Response with file data
37
+ */
38
+ async fetch(filename: string): Promise<Response> {
39
+ const fileProvider = await this.fileProvider;
40
+ if (!fileProvider) {
41
+ throw new Error('No data detected in the zip archive');
42
+ }
43
+ await this.parseHashFile();
44
+ if (this.hashData) {
45
+ const archive = new Tiles3DArchive(fileProvider, this.hashData);
46
+
47
+ const fileData = await archive.getFile(filename);
48
+ const response = new Response(fileData);
49
+ Object.defineProperty(response, 'url', {value: `${this.fileName || ''}/${filename}`});
50
+ return response;
51
+ }
52
+ return super.fetch(filename);
53
+ }
54
+
55
+ /**
56
+ * Try to get and parse '@3dtilesIndex1@' file, that allows to get direct access
57
+ * to files inside the archive
58
+ * @returns void
59
+ */
60
+ private async parseHashFile(): Promise<void> {
61
+ if (this.hashData !== undefined) {
62
+ return;
63
+ }
64
+
65
+ const fileProvider = await this.fileProvider;
66
+ if (!fileProvider) {
67
+ throw new Error('No data detected in the zip archive');
68
+ }
69
+
70
+ const hashCDOffset = await searchFromTheEnd(fileProvider, cdHeaderSignature);
71
+
72
+ const cdFileHeader = await parseZipCDFileHeader(hashCDOffset, fileProvider);
73
+
74
+ // '@3dtilesIndex1@' is index file that must be the last in the archive. It allows
75
+ // to improve load and read performance when the archive contains a very large number
76
+ // of files.
77
+ if (cdFileHeader?.fileName === '@3dtilesIndex1@') {
78
+ const localFileHeader = await parseZipLocalFileHeader(
79
+ cdFileHeader.localHeaderOffset,
80
+ fileProvider
81
+ );
82
+ if (!localFileHeader) {
83
+ throw new Error('corrupted 3tz');
84
+ }
85
+
86
+ const fileDataOffset = localFileHeader.fileDataOffset;
87
+ const hashFile = await fileProvider.slice(
88
+ fileDataOffset,
89
+ fileDataOffset + localFileHeader.compressedSize
90
+ );
91
+
92
+ this.hashData = parseHashFile(hashFile);
93
+ } else {
94
+ this.hashData = null;
95
+ }
96
+ }
97
+ }
@@ -34,7 +34,7 @@ export async function getIonAssets(accessToken) {
34
34
  assert(accessToken);
35
35
  const url = CESIUM_ION_URL;
36
36
  const headers = {Authorization: `Bearer ${accessToken}`};
37
- const response = await fetchFile(url, {fetch: {headers}});
37
+ const response = await fetchFile(url, {headers});
38
38
  if (!response.ok) {
39
39
  throw new Error(response.statusText);
40
40
  }
@@ -49,7 +49,7 @@ export async function getIonAssetMetadata(accessToken, assetId) {
49
49
  const url = `${CESIUM_ION_URL}/${assetId}`;
50
50
  // https://cesium.com/docs/rest-api/#operation/getAsset
51
51
  // Retrieves metadata information about a specific asset.
52
- let response = await fetchFile(`${url}`, {fetch: {headers}});
52
+ let response = await fetchFile(`${url}`, {headers});
53
53
  if (!response.ok) {
54
54
  throw new Error(response.statusText);
55
55
  }
@@ -57,7 +57,7 @@ export async function getIonAssetMetadata(accessToken, assetId) {
57
57
 
58
58
  // https://cesium.com/docs/rest-api/#operation/getAssetEndpoint
59
59
  // Retrieves information and credentials that allow you to access the tiled asset data for visualization and analysis.
60
- response = await fetchFile(`${url}/endpoint`, {fetch: {headers}});
60
+ response = await fetchFile(`${url}/endpoint`, {headers});
61
61
  if (!response.ok) {
62
62
  throw new Error(response.statusText);
63
63
  }
@@ -1,11 +1,14 @@
1
1
  import type {Availability, Tile3DBoundingVolume, Subtree} from '../../../types';
2
2
  import {Tile3DSubtreeLoader} from '../../../tile-3d-subtree-loader';
3
3
  import {load} from '@loaders.gl/core';
4
+ import {default as log} from '@probe.gl/log';
4
5
 
5
6
  import {getS2CellIdFromToken, getS2ChildCellId, getS2TokenFromCellId} from '../../utils/s2/index';
6
7
  import type {S2VolumeInfo} from '../../utils/obb/s2-corners-to-obb';
7
8
  import {convertS2BoundingVolumetoOBB} from '../../utils/obb/s2-corners-to-obb';
8
9
  import Long from 'long';
10
+ import {Tiles3DLoaderOptions} from '../../../tiles-3d-loader';
11
+ import {ImplicitOptions} from '../parse-3d-tile-header';
9
12
 
10
13
  const QUADTREE_DEVISION_COUNT = 4;
11
14
  const OCTREE_DEVISION_COUNT = 8;
@@ -83,15 +86,16 @@ function getChildS2VolumeBox(
83
86
  // eslint-disable-next-line max-statements
84
87
  export async function parseImplicitTiles(params: {
85
88
  subtree: Subtree;
86
- options: any;
89
+ implicitOptions: ImplicitOptions;
87
90
  parentData?: {mortonIndex: number; x: number; y: number; z: number};
88
91
  childIndex?: number;
89
92
  level?: number;
90
93
  globalData?: {level: number; mortonIndex: number; x: number; y: number; z: number};
91
94
  s2VolumeBox?: S2VolumeBox;
95
+ loaderOptions: Tiles3DLoaderOptions;
92
96
  }) {
93
97
  const {
94
- options,
98
+ implicitOptions,
95
99
  parentData = {
96
100
  mortonIndex: 0,
97
101
  x: 0,
@@ -106,7 +110,8 @@ export async function parseImplicitTiles(params: {
106
110
  y: 0,
107
111
  z: 0
108
112
  },
109
- s2VolumeBox
113
+ s2VolumeBox,
114
+ loaderOptions
110
115
  } = params;
111
116
  let {subtree, level = 0} = params;
112
117
  const {
@@ -116,43 +121,56 @@ export async function parseImplicitTiles(params: {
116
121
  contentUrlTemplate,
117
122
  subtreesUriTemplate,
118
123
  basePath
119
- } = options;
120
-
124
+ } = implicitOptions;
121
125
  const tile = {children: [], lodMetricValue: 0, contentUrl: ''};
122
126
 
127
+ if (!maximumLevel) {
128
+ // eslint-disable-next-line no-console
129
+ log.once(
130
+ `Missing 'maximumLevel' or 'availableLevels' property. The subtree ${contentUrlTemplate} won't be loaded...`
131
+ );
132
+ return tile;
133
+ }
134
+
135
+ const lev = level + globalData.level;
136
+ if (lev > maximumLevel) {
137
+ return tile;
138
+ }
139
+
123
140
  const childrenPerTile = SUBDIVISION_COUNT_MAP[subdivisionScheme];
141
+ const bitsPerTile = Math.log2(childrenPerTile);
124
142
 
125
- const childX = childIndex & 0b01;
126
- const childY = (childIndex >> 1) & 0b01;
127
- const childZ = (childIndex >> 2) & 0b01;
143
+ // childIndex is in range [0,4] for quadtrees and [0, 7] for octrees
144
+ const childX = childIndex & 0b01; // Get first bit for X
145
+ const childY = (childIndex >> 1) & 0b01; // Get second bit for Y
146
+ const childZ = (childIndex >> 2) & 0b01; // Get third bit for Z
128
147
 
129
148
  const levelOffset = (childrenPerTile ** level - 1) / (childrenPerTile - 1);
130
- let childTileMortonIndex = concatBits(parentData.mortonIndex, childIndex);
149
+ let childTileMortonIndex = concatBits(parentData.mortonIndex, childIndex, bitsPerTile);
131
150
  let tileAvailabilityIndex = levelOffset + childTileMortonIndex;
132
151
 
133
152
  // Local tile coordinates
134
- let childTileX = concatBits(parentData.x, childX);
135
- let childTileY = concatBits(parentData.y, childY);
136
- let childTileZ = concatBits(parentData.z, childZ);
153
+ let childTileX = concatBits(parentData.x, childX, 1);
154
+ let childTileY = concatBits(parentData.y, childY, 1);
155
+ let childTileZ = concatBits(parentData.z, childZ, 1);
137
156
 
138
157
  let isChildSubtreeAvailable = false;
139
158
 
140
- if (level + 1 > subtreeLevels) {
159
+ if (level >= subtreeLevels) {
141
160
  isChildSubtreeAvailable = getAvailabilityResult(
142
161
  subtree.childSubtreeAvailability,
143
162
  childTileMortonIndex
144
163
  );
145
164
  }
146
165
 
147
- const x = concatBits(globalData.x, childTileX);
148
- const y = concatBits(globalData.y, childTileY);
149
- const z = concatBits(globalData.z, childTileZ);
150
- const lev = level + globalData.level;
166
+ const x = concatBits(globalData.x, childTileX, level * bitsPerTile);
167
+ const y = concatBits(globalData.y, childTileY, level * bitsPerTile);
168
+ const z = concatBits(globalData.z, childTileZ, level * bitsPerTile);
151
169
 
152
170
  if (isChildSubtreeAvailable) {
153
171
  const subtreePath = `${basePath}/${subtreesUriTemplate}`;
154
172
  const childSubtreeUrl = replaceContentUrlTemplate(subtreePath, lev, x, y, z);
155
- const childSubtree = await load(childSubtreeUrl, Tile3DSubtreeLoader);
173
+ const childSubtree = await load(childSubtreeUrl, Tile3DSubtreeLoader, loaderOptions);
156
174
 
157
175
  subtree = childSubtree;
158
176
 
@@ -172,7 +190,7 @@ export async function parseImplicitTiles(params: {
172
190
 
173
191
  const isTileAvailable = getAvailabilityResult(subtree.tileAvailability, tileAvailabilityIndex);
174
192
 
175
- if (!isTileAvailable || level > maximumLevel) {
193
+ if (!isTileAvailable) {
176
194
  return tile;
177
195
  }
178
196
 
@@ -198,11 +216,12 @@ export async function parseImplicitTiles(params: {
198
216
  // Recursive calling...
199
217
  const childTileParsed = await parseImplicitTiles({
200
218
  subtree,
201
- options,
219
+ implicitOptions,
220
+ loaderOptions,
202
221
  parentData: pData,
203
222
  childIndex: index,
204
223
  level: childTileLevel,
205
- globalData,
224
+ globalData: {...globalData},
206
225
  s2VolumeBox: childS2VolumeBox
207
226
  });
208
227
 
@@ -213,7 +232,7 @@ export async function parseImplicitTiles(params: {
213
232
  childTileParsed,
214
233
  globalLevel,
215
234
  childCoordinates,
216
- options,
235
+ implicitOptions,
217
236
  s2VolumeBox
218
237
  );
219
238
  // @ts-ignore
@@ -224,13 +243,37 @@ export async function parseImplicitTiles(params: {
224
243
  return tile;
225
244
  }
226
245
 
227
- function getAvailabilityResult(availabilityData: Availability, index: number): boolean {
228
- if ('constant' in availabilityData) {
229
- return Boolean(availabilityData.constant);
246
+ /**
247
+ * Check tile availability in the bitstream array
248
+ * @param availabilityData - tileAvailability / contentAvailability / childSubtreeAvailability object
249
+ * @param index - index in the bitstream array
250
+ * @returns
251
+ */
252
+ function getAvailabilityResult(
253
+ availabilityData: Availability | Availability[],
254
+ index: number
255
+ ): boolean {
256
+ let availabilityObject: Availability;
257
+ if (Array.isArray(availabilityData)) {
258
+ /** TODO: we don't support `3DTILES_multiple_contents` extension at the moment.
259
+ * https://github.com/CesiumGS/3d-tiles/blob/main/extensions/3DTILES_implicit_tiling/README.md#multiple-contents
260
+ * Take first item in the array
261
+ */
262
+ availabilityObject = availabilityData[0];
263
+ if (availabilityData.length > 1) {
264
+ // eslint-disable-next-line no-console
265
+ log.once('Not supported extension "3DTILES_multiple_contents" has been detected');
266
+ }
267
+ } else {
268
+ availabilityObject = availabilityData;
269
+ }
270
+
271
+ if ('constant' in availabilityObject) {
272
+ return Boolean(availabilityObject.constant);
230
273
  }
231
274
 
232
- if (availabilityData.explicitBitstream) {
233
- return getBooleanValueFromBitstream(index, availabilityData.explicitBitstream);
275
+ if (availabilityObject.explicitBitstream) {
276
+ return getBooleanValueFromBitstream(index, availabilityObject.explicitBitstream);
234
277
  }
235
278
 
236
279
  return false;
@@ -248,7 +291,7 @@ function formatTileData(
248
291
  tile,
249
292
  level: number,
250
293
  childCoordinates: {childTileX: number; childTileY: number; childTileZ: number},
251
- options: any,
294
+ options: ImplicitOptions,
252
295
  s2VolumeBox?: S2VolumeBox
253
296
  ) {
254
297
  const {
@@ -337,11 +380,12 @@ function calculateBoundingVolumeForChildTile(
337
380
 
338
381
  /**
339
382
  * Do binary concatenation
340
- * @param first
341
- * @param second
383
+ * @param higher - number to put to higher part of result
384
+ * @param lower - number to put to lower part of result
385
+ * @param shift - number of bits to shift lower number
342
386
  */
343
- function concatBits(first: number, second: number): number {
344
- return parseInt(first.toString(2) + second.toString(2), 2);
387
+ function concatBits(higher: number, lower: number, shift: number): number {
388
+ return (higher << shift) + lower;
345
389
  }
346
390
 
347
391
  /**
@@ -8,7 +8,7 @@
8
8
  // - Also, should we have hard dependency on gltf module or use injection or auto-discovery for gltf parser?
9
9
 
10
10
  import {GLTFLoader, postProcessGLTF, _getMemoryUsageGLTF} from '@loaders.gl/gltf';
11
- import {LoaderContext, sliceArrayBuffer} from '@loaders.gl/loader-utils';
11
+ import {LoaderContext, sliceArrayBuffer, parseFromContext} from '@loaders.gl/loader-utils';
12
12
  import {Tiles3DTileContent} from '../../../types';
13
13
  import {Tiles3DLoaderOptions} from '../../../tiles-3d-loader';
14
14
 
@@ -74,15 +74,20 @@ export async function extractGLTF(
74
74
  if (!context) {
75
75
  return;
76
76
  }
77
- const {parse, fetch} = context;
78
77
  if (tile.gltfUrl) {
78
+ const {fetch} = context;
79
79
  const response = await fetch(tile.gltfUrl, options);
80
80
  tile.gltfArrayBuffer = await response.arrayBuffer();
81
81
  tile.gltfByteOffset = 0;
82
82
  }
83
83
  if (tile.gltfArrayBuffer) {
84
84
  // TODO - Should handle byteOffset... However, not used now...
85
- const gltfWithBuffers = await parse(tile.gltfArrayBuffer, GLTFLoader, options, context);
85
+ const gltfWithBuffers = await parseFromContext(
86
+ tile.gltfArrayBuffer,
87
+ GLTFLoader,
88
+ options,
89
+ context
90
+ );
86
91
  tile.gltf = postProcessGLTF(gltfWithBuffers);
87
92
  tile.gpuMemoryUsageInBytes = _getMemoryUsageGLTF(tile.gltf);
88
93
  delete tile.gltfArrayBuffer;
@@ -1,4 +1,4 @@
1
- import type {Subtree, ExplicitBitstream} from '../../../types';
1
+ import type {Subtree, Availability} from '../../../types';
2
2
  import type {LoaderContext, LoaderOptions} from '@loaders.gl/loader-utils';
3
3
 
4
4
  const SUBTREE_FILE_MAGIC = 0x74627573;
@@ -42,79 +42,54 @@ export default async function parse3DTilesSubtree(
42
42
  internalBinaryBuffer = data.slice(24 + jsonByteLength);
43
43
  }
44
44
 
45
- if ('bufferView' in subtree.tileAvailability) {
46
- subtree.tileAvailability.explicitBitstream = await getExplicitBitstream(
45
+ await loadExplicitBitstream(subtree, subtree.tileAvailability, internalBinaryBuffer, context);
46
+ if (Array.isArray(subtree.contentAvailability)) {
47
+ for (const contentAvailability of subtree.contentAvailability) {
48
+ await loadExplicitBitstream(subtree, contentAvailability, internalBinaryBuffer, context);
49
+ }
50
+ } else {
51
+ await loadExplicitBitstream(
47
52
  subtree,
48
- 'tileAvailability',
49
- internalBinaryBuffer,
50
- context
51
- );
52
- }
53
-
54
- if ('bufferView' in subtree.contentAvailability) {
55
- subtree.contentAvailability.explicitBitstream = await getExplicitBitstream(
56
- subtree,
57
- 'contentAvailability',
58
- internalBinaryBuffer,
59
- context
60
- );
61
- }
62
-
63
- if ('bufferView' in subtree.childSubtreeAvailability) {
64
- subtree.childSubtreeAvailability.explicitBitstream = await getExplicitBitstream(
65
- subtree,
66
- 'childSubtreeAvailability',
53
+ subtree.contentAvailability,
67
54
  internalBinaryBuffer,
68
55
  context
69
56
  );
70
57
  }
58
+ await loadExplicitBitstream(
59
+ subtree,
60
+ subtree.childSubtreeAvailability,
61
+ internalBinaryBuffer,
62
+ context
63
+ );
71
64
 
72
65
  return subtree;
73
66
  }
74
67
 
75
68
  /**
76
- * Get url for bitstream downloading
77
- * @param bitstreamRelativeUri
78
- * @param basePath
79
- * @returns
80
- */
81
- function resolveBufferUri(bitstreamRelativeUri: string, basePath: string): string {
82
- const hasProtocol = basePath.startsWith('http');
83
-
84
- if (hasProtocol) {
85
- const resolvedUri = new URL(bitstreamRelativeUri, basePath);
86
- return decodeURI(resolvedUri.toString());
87
- }
88
-
89
- /**
90
- * Adding http protocol only for new URL constructor usage.
91
- * It allows to resolve relative paths like ../../example with basePath.
92
- */
93
- const basePathWithProtocol = `http://${basePath}`;
94
- const resolvedUri = new URL(bitstreamRelativeUri, basePathWithProtocol);
95
- /**
96
- * Drop protocol and use just relative path.
97
- */
98
- return `/${resolvedUri.host}${resolvedUri.pathname}`;
99
- }
100
-
101
- /**
102
- * Get explicit bitstream for subtree availability data.
103
- * @param subtree
104
- * @param name
105
- * @param internalBinaryBuffer
69
+ * Load explicit bitstream for subtree availability data.
70
+ * @param subtree - subtree data
71
+ * @param availabilityObject - tileAvailability / contentAvailability / childSubtreeAvailability object
72
+ * @param internalBinaryBuffer - subtree binary buffer
73
+ * @param context - loaders.gl context
106
74
  */
107
- async function getExplicitBitstream(
75
+ async function loadExplicitBitstream(
108
76
  subtree: Subtree,
109
- name: string,
77
+ availabilityObject: Availability,
110
78
  internalBinaryBuffer: ArrayBuffer,
111
79
  context: LoaderContext | undefined
112
- ): Promise<ExplicitBitstream> {
113
- const bufferViewIndex = subtree[name].bufferView;
80
+ ): Promise<void> {
81
+ const bufferViewIndex = Number.isFinite(availabilityObject.bitstream)
82
+ ? availabilityObject.bitstream
83
+ : availabilityObject.bufferView;
84
+
85
+ if (typeof bufferViewIndex !== 'number') {
86
+ return;
87
+ }
88
+
114
89
  const bufferView = subtree.bufferViews[bufferViewIndex];
115
90
  const buffer = subtree.buffers[bufferView.buffer];
116
91
 
117
- if (!context?.url || !context.fetch) {
92
+ if (!context?.baseUrl) {
118
93
  throw new Error('Url is not provided');
119
94
  }
120
95
 
@@ -124,14 +99,21 @@ async function getExplicitBitstream(
124
99
 
125
100
  // External bitstream loading
126
101
  if (buffer.uri) {
127
- const bufferUri = resolveBufferUri(buffer.uri, context?.url);
102
+ const bufferUri = `${context?.baseUrl || ''}/${buffer.uri}`;
128
103
  const response = await context.fetch(bufferUri);
129
104
  const data = await response.arrayBuffer();
130
- // Return view of bitstream.
131
- return new Uint8Array(data, bufferView.byteOffset, bufferView.byteLength);
105
+ availabilityObject.explicitBitstream = new Uint8Array(
106
+ data,
107
+ bufferView.byteOffset,
108
+ bufferView.byteLength
109
+ );
110
+ return;
132
111
  }
133
- // Return view of bitstream.
134
- return new Uint8Array(internalBinaryBuffer, bufferView.byteOffset, bufferView.byteLength);
112
+ availabilityObject.explicitBitstream = new Uint8Array(
113
+ internalBinaryBuffer,
114
+ bufferView.byteOffset,
115
+ bufferView.byteLength
116
+ );
135
117
  }
136
118
 
137
119
  /**
@@ -38,7 +38,7 @@ export async function parseComposite3DTile(
38
38
  // extract each tile from the byte stream
39
39
  tile.tiles = [];
40
40
  while (tile.tiles.length < tile.tilesLength && (tile.byteLength || 0) - byteOffset > 12) {
41
- const subtile = {};
41
+ const subtile: Tiles3DTileContent = {shape: 'tile3d'};
42
42
  tile.tiles.push(subtile);
43
43
  byteOffset = await parse3DTile(arrayBuffer, byteOffset, options, context, subtile);
44
44
  // TODO - do we need to add any padding in between tiles?
@@ -1,6 +1,8 @@
1
- import type {LoaderContext} from '@loaders.gl/loader-utils';
2
- import type {Tiles3DLoaderOptions} from '../../tiles-3d-loader';
1
+ // loaders.gl, MIT license
2
+
3
+ import {parseFromContext, LoaderContext} from '@loaders.gl/loader-utils';
3
4
  import {_getMemoryUsageGLTF, GLTFLoader, postProcessGLTF} from '@loaders.gl/gltf';
5
+ import type {Tiles3DLoaderOptions} from '../../tiles-3d-loader';
4
6
  import {Tiles3DTileContent} from '../../types';
5
7
 
6
8
  export async function parseGltf3DTile(
@@ -8,26 +10,25 @@ export async function parseGltf3DTile(
8
10
  arrayBuffer: ArrayBuffer,
9
11
  options?: Tiles3DLoaderOptions,
10
12
  context?: LoaderContext
11
- ): Promise<void> {
13
+ ): Promise<number> {
12
14
  // Set flags
13
15
  // glTF models need to be rotated from Y to Z up
14
16
  // https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#y-up-to-z-up
15
17
  tile.rotateYtoZ = true;
16
18
  // Save gltf up axis
17
- tile.gltfUpAxis =
18
- options?.['3d-tiles'] && options['3d-tiles'].assetGltfUpAxis
19
- ? options['3d-tiles'].assetGltfUpAxis
20
- : 'Y';
19
+ tile.gltfUpAxis = options?.['3d-tiles']?.assetGltfUpAxis
20
+ ? options['3d-tiles'].assetGltfUpAxis
21
+ : 'Y';
21
22
 
22
23
  if (options?.['3d-tiles']?.loadGLTF) {
23
24
  if (!context) {
24
- return;
25
+ return arrayBuffer.byteLength;
25
26
  }
26
- const {parse} = context;
27
- const gltfWithBuffers = await parse(arrayBuffer, GLTFLoader, options, context);
27
+ const gltfWithBuffers = await parseFromContext(arrayBuffer, GLTFLoader, options, context);
28
28
  tile.gltf = postProcessGLTF(gltfWithBuffers);
29
29
  tile.gpuMemoryUsageInBytes = _getMemoryUsageGLTF(tile.gltf);
30
30
  } else {
31
31
  tile.gltfArrayBuffer = arrayBuffer;
32
32
  }
33
+ return arrayBuffer.byteLength;
33
34
  }