@loaders.gl/i3s 4.0.0-alpha.1 → 4.0.0-alpha.11

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 (242) hide show
  1. package/dist/arcgis-webscene-loader.d.ts +7 -0
  2. package/dist/arcgis-webscene-loader.d.ts.map +1 -0
  3. package/dist/arcgis-webscene-loader.js +28 -0
  4. package/dist/bundle.d.ts +2 -0
  5. package/dist/bundle.d.ts.map +1 -0
  6. package/dist/bundle.js +2 -2
  7. package/dist/dist.min.js +15501 -0
  8. package/dist/es5/arcgis-webscene-loader.js +40 -0
  9. package/dist/es5/arcgis-webscene-loader.js.map +1 -0
  10. package/dist/es5/bundle.js +6 -0
  11. package/dist/es5/bundle.js.map +1 -0
  12. package/dist/es5/i3s-attribute-loader.js +195 -0
  13. package/dist/es5/i3s-attribute-loader.js.map +1 -0
  14. package/dist/es5/i3s-building-scene-layer-loader.js +46 -0
  15. package/dist/es5/i3s-building-scene-layer-loader.js.map +1 -0
  16. package/dist/es5/i3s-content-loader.js +56 -0
  17. package/dist/es5/i3s-content-loader.js.map +1 -0
  18. package/dist/es5/i3s-loader.js +193 -0
  19. package/dist/es5/i3s-loader.js.map +1 -0
  20. package/dist/es5/i3s-node-page-loader.js +39 -0
  21. package/dist/es5/i3s-node-page-loader.js.map +1 -0
  22. package/dist/es5/i3s-slpk-loader.js +20 -0
  23. package/dist/es5/i3s-slpk-loader.js.map +1 -0
  24. package/dist/es5/index.js +82 -0
  25. package/dist/es5/index.js.map +1 -0
  26. package/dist/es5/lib/helpers/i3s-nodepages-tiles.js +312 -0
  27. package/dist/es5/lib/helpers/i3s-nodepages-tiles.js.map +1 -0
  28. package/dist/es5/lib/parsers/constants.js +72 -0
  29. package/dist/es5/lib/parsers/constants.js.map +1 -0
  30. package/dist/es5/lib/parsers/parse-arcgis-webscene.js +158 -0
  31. package/dist/es5/lib/parsers/parse-arcgis-webscene.js.map +1 -0
  32. package/dist/es5/lib/parsers/parse-i3s-attribute.js +76 -0
  33. package/dist/es5/lib/parsers/parse-i3s-attribute.js.map +1 -0
  34. package/dist/es5/lib/parsers/parse-i3s-building-scene-layer.js +65 -0
  35. package/dist/es5/lib/parsers/parse-i3s-building-scene-layer.js.map +1 -0
  36. package/dist/es5/lib/parsers/parse-i3s-tile-content.js +510 -0
  37. package/dist/es5/lib/parsers/parse-i3s-tile-content.js.map +1 -0
  38. package/dist/es5/lib/parsers/parse-i3s.js +116 -0
  39. package/dist/es5/lib/parsers/parse-i3s.js.map +1 -0
  40. package/dist/es5/lib/parsers/parse-slpk/parse-slpk.js +107 -0
  41. package/dist/es5/lib/parsers/parse-slpk/parse-slpk.js.map +1 -0
  42. package/dist/es5/lib/parsers/parse-slpk/slpk-archieve.js +258 -0
  43. package/dist/es5/lib/parsers/parse-slpk/slpk-archieve.js.map +1 -0
  44. package/dist/es5/lib/parsers/parse-zip/buffer-file-provider.js +46 -0
  45. package/dist/es5/lib/parsers/parse-zip/buffer-file-provider.js.map +1 -0
  46. package/dist/es5/lib/parsers/parse-zip/cd-file-header.js +84 -0
  47. package/dist/es5/lib/parsers/parse-zip/cd-file-header.js.map +1 -0
  48. package/dist/es5/lib/parsers/parse-zip/file-provider.js +2 -0
  49. package/dist/es5/lib/parsers/parse-zip/file-provider.js.map +1 -0
  50. package/dist/es5/lib/parsers/parse-zip/local-file-header.js +72 -0
  51. package/dist/es5/lib/parsers/parse-zip/local-file-header.js.map +1 -0
  52. package/dist/es5/lib/utils/convert-i3s-obb-to-mbs.js +17 -0
  53. package/dist/es5/lib/utils/convert-i3s-obb-to-mbs.js.map +1 -0
  54. package/dist/es5/lib/utils/customize-/321/201olors.js +184 -0
  55. package/dist/es5/lib/utils/customize-/321/201olors.js.map +1 -0
  56. package/dist/es5/lib/utils/url-utils.js +33 -0
  57. package/dist/es5/lib/utils/url-utils.js.map +1 -0
  58. package/dist/es5/types.js +26 -0
  59. package/dist/es5/types.js.map +1 -0
  60. package/dist/es5/workers/i3s-content-worker-node.js +7 -0
  61. package/dist/es5/workers/i3s-content-worker-node.js.map +1 -0
  62. package/dist/es5/workers/i3s-content-worker.js +6 -0
  63. package/dist/es5/workers/i3s-content-worker.js.map +1 -0
  64. package/dist/esm/arcgis-webscene-loader.js +16 -0
  65. package/dist/esm/arcgis-webscene-loader.js.map +1 -0
  66. package/dist/esm/bundle.js +4 -0
  67. package/dist/esm/bundle.js.map +1 -0
  68. package/dist/esm/i3s-attribute-loader.js +119 -0
  69. package/dist/esm/i3s-attribute-loader.js.map +1 -0
  70. package/dist/esm/i3s-building-scene-layer-loader.js +19 -0
  71. package/dist/esm/i3s-building-scene-layer-loader.js.map +1 -0
  72. package/dist/esm/i3s-content-loader.js +30 -0
  73. package/dist/esm/i3s-content-loader.js.map +1 -0
  74. package/dist/esm/i3s-loader.js +87 -0
  75. package/dist/esm/i3s-loader.js.map +1 -0
  76. package/dist/esm/i3s-node-page-loader.js +15 -0
  77. package/dist/esm/i3s-node-page-loader.js.map +1 -0
  78. package/dist/esm/i3s-slpk-loader.js +13 -0
  79. package/dist/esm/i3s-slpk-loader.js.map +1 -0
  80. package/dist/esm/index.js +11 -0
  81. package/dist/esm/index.js.map +1 -0
  82. package/dist/esm/lib/helpers/i3s-nodepages-tiles.js +198 -0
  83. package/dist/esm/lib/helpers/i3s-nodepages-tiles.js.map +1 -0
  84. package/dist/esm/lib/parsers/constants.js +57 -0
  85. package/dist/esm/lib/parsers/constants.js.map +1 -0
  86. package/dist/esm/lib/parsers/parse-arcgis-webscene.js +70 -0
  87. package/dist/esm/lib/parsers/parse-arcgis-webscene.js.map +1 -0
  88. package/dist/esm/lib/parsers/parse-i3s-attribute.js +60 -0
  89. package/dist/esm/lib/parsers/parse-i3s-attribute.js.map +1 -0
  90. package/dist/esm/lib/parsers/parse-i3s-building-scene-layer.js +39 -0
  91. package/dist/esm/lib/parsers/parse-i3s-building-scene-layer.js.map +1 -0
  92. package/dist/esm/lib/parsers/parse-i3s-tile-content.js +435 -0
  93. package/dist/esm/lib/parsers/parse-i3s-tile-content.js.map +1 -0
  94. package/dist/esm/lib/parsers/parse-i3s.js +83 -0
  95. package/dist/esm/lib/parsers/parse-i3s.js.map +1 -0
  96. package/dist/esm/lib/parsers/parse-slpk/parse-slpk.js +41 -0
  97. package/dist/esm/lib/parsers/parse-slpk/parse-slpk.js.map +1 -0
  98. package/dist/esm/lib/parsers/parse-slpk/slpk-archieve.js +107 -0
  99. package/dist/esm/lib/parsers/parse-slpk/slpk-archieve.js.map +1 -0
  100. package/dist/esm/lib/parsers/parse-zip/buffer-file-provider.js +23 -0
  101. package/dist/esm/lib/parsers/parse-zip/buffer-file-provider.js.map +1 -0
  102. package/dist/esm/lib/parsers/parse-zip/cd-file-header.js +37 -0
  103. package/dist/esm/lib/parsers/parse-zip/cd-file-header.js.map +1 -0
  104. package/dist/esm/lib/parsers/parse-zip/file-provider.js +2 -0
  105. package/dist/esm/lib/parsers/parse-zip/file-provider.js.map +1 -0
  106. package/dist/esm/lib/parsers/parse-zip/local-file-header.js +25 -0
  107. package/dist/esm/lib/parsers/parse-zip/local-file-header.js.map +1 -0
  108. package/dist/esm/lib/utils/convert-i3s-obb-to-mbs.js +9 -0
  109. package/dist/esm/lib/utils/convert-i3s-obb-to-mbs.js.map +1 -0
  110. package/dist/esm/lib/utils/customize-/321/201olors.js +98 -0
  111. package/dist/esm/lib/utils/customize-/321/201olors.js.map +1 -0
  112. package/dist/esm/lib/utils/url-utils.js +28 -0
  113. package/dist/esm/lib/utils/url-utils.js.map +1 -0
  114. package/dist/esm/types.js +18 -0
  115. package/dist/esm/types.js.map +1 -0
  116. package/dist/esm/workers/i3s-content-worker-node.js +5 -0
  117. package/dist/esm/workers/i3s-content-worker-node.js.map +1 -0
  118. package/dist/esm/workers/i3s-content-worker.js +4 -0
  119. package/dist/esm/workers/i3s-content-worker.js.map +1 -0
  120. package/dist/i3s-attribute-loader.d.ts +21 -0
  121. package/dist/i3s-attribute-loader.d.ts.map +1 -0
  122. package/dist/i3s-attribute-loader.js +155 -132
  123. package/dist/i3s-building-scene-layer-loader.d.ts +6 -0
  124. package/dist/i3s-building-scene-layer-loader.d.ts.map +1 -0
  125. package/dist/i3s-building-scene-layer-loader.js +23 -18
  126. package/dist/i3s-content-loader.d.ts +6 -0
  127. package/dist/i3s-content-loader.d.ts.map +1 -0
  128. package/dist/i3s-content-loader.js +29 -22
  129. package/dist/i3s-content-worker-node.js +197 -0
  130. package/dist/i3s-content-worker-node.js.map +7 -0
  131. package/dist/i3s-content-worker.js +2308 -1376
  132. package/dist/i3s-loader.d.ts +11 -0
  133. package/dist/i3s-loader.d.ts.map +1 -0
  134. package/dist/i3s-loader.js +88 -81
  135. package/dist/i3s-node-page-loader.d.ts +7 -0
  136. package/dist/i3s-node-page-loader.d.ts.map +1 -0
  137. package/dist/i3s-node-page-loader.js +20 -20
  138. package/dist/i3s-slpk-loader.d.ts +13 -0
  139. package/dist/i3s-slpk-loader.d.ts.map +1 -0
  140. package/dist/i3s-slpk-loader.js +20 -0
  141. package/dist/index.d.ts +12 -0
  142. package/dist/index.d.ts.map +1 -0
  143. package/dist/index.js +23 -5
  144. package/dist/lib/helpers/i3s-nodepages-tiles.d.ts +74 -0
  145. package/dist/lib/helpers/i3s-nodepages-tiles.d.ts.map +1 -0
  146. package/dist/lib/helpers/i3s-nodepages-tiles.js +232 -219
  147. package/dist/lib/parsers/constants.d.ts +40 -0
  148. package/dist/lib/parsers/constants.d.ts.map +1 -0
  149. package/dist/lib/parsers/constants.js +87 -42
  150. package/dist/lib/parsers/parse-arcgis-webscene.d.ts +7 -0
  151. package/dist/lib/parsers/parse-arcgis-webscene.d.ts.map +1 -0
  152. package/dist/lib/parsers/parse-arcgis-webscene.js +88 -0
  153. package/dist/lib/parsers/parse-i3s-attribute.d.ts +12 -0
  154. package/dist/lib/parsers/parse-i3s-attribute.d.ts.map +1 -0
  155. package/dist/lib/parsers/parse-i3s-attribute.js +87 -62
  156. package/dist/lib/parsers/parse-i3s-building-scene-layer.d.ts +9 -0
  157. package/dist/lib/parsers/parse-i3s-building-scene-layer.d.ts.map +1 -0
  158. package/dist/lib/parsers/parse-i3s-building-scene-layer.js +41 -38
  159. package/dist/lib/parsers/parse-i3s-tile-content.d.ts +4 -0
  160. package/dist/lib/parsers/parse-i3s-tile-content.d.ts.map +1 -0
  161. package/dist/lib/parsers/parse-i3s-tile-content.js +460 -415
  162. package/dist/lib/parsers/parse-i3s.d.ts +6 -0
  163. package/dist/lib/parsers/parse-i3s.d.ts.map +1 -0
  164. package/dist/lib/parsers/parse-i3s.js +92 -73
  165. package/dist/lib/parsers/parse-slpk/parse-slpk.d.ts +4 -0
  166. package/dist/lib/parsers/parse-slpk/parse-slpk.d.ts.map +1 -0
  167. package/dist/lib/parsers/parse-slpk/parse-slpk.js +54 -0
  168. package/dist/lib/parsers/parse-slpk/slpk-archieve.d.ts +38 -0
  169. package/dist/lib/parsers/parse-slpk/slpk-archieve.d.ts.map +1 -0
  170. package/dist/lib/parsers/parse-slpk/slpk-archieve.js +142 -0
  171. package/dist/lib/parsers/parse-zip/buffer-file-provider.d.ts +37 -0
  172. package/dist/lib/parsers/parse-zip/buffer-file-provider.d.ts.map +1 -0
  173. package/dist/lib/parsers/parse-zip/buffer-file-provider.js +47 -0
  174. package/dist/lib/parsers/parse-zip/cd-file-header.d.ts +27 -0
  175. package/dist/lib/parsers/parse-zip/cd-file-header.d.ts.map +1 -0
  176. package/dist/lib/parsers/parse-zip/cd-file-header.js +48 -0
  177. package/dist/lib/parsers/parse-zip/file-provider.d.ts +31 -0
  178. package/dist/lib/parsers/parse-zip/file-provider.d.ts.map +1 -0
  179. package/dist/lib/parsers/parse-zip/file-provider.js +2 -0
  180. package/dist/lib/parsers/parse-zip/local-file-header.d.ts +25 -0
  181. package/dist/lib/parsers/parse-zip/local-file-header.d.ts.map +1 -0
  182. package/dist/lib/parsers/parse-zip/local-file-header.js +34 -0
  183. package/dist/lib/utils/convert-i3s-obb-to-mbs.d.ts +2 -0
  184. package/dist/lib/utils/convert-i3s-obb-to-mbs.d.ts.map +1 -0
  185. package/dist/lib/utils/convert-i3s-obb-to-mbs.js +19 -8
  186. package/dist/lib/utils/customize-/321/201olors.d.ts +14 -0
  187. package/dist/lib/utils/customize-/321/201olors.d.ts.map +1 -0
  188. package/dist/lib/utils/customize-/321/201olors.js +104 -0
  189. package/dist/lib/utils/url-utils.d.ts +22 -0
  190. package/dist/lib/utils/url-utils.d.ts.map +1 -0
  191. package/dist/lib/utils/url-utils.js +41 -29
  192. package/dist/types.d.ts +1065 -0
  193. package/dist/types.d.ts.map +1 -0
  194. package/dist/types.js +20 -2
  195. package/dist/workers/i3s-content-worker-node.d.ts +2 -0
  196. package/dist/workers/i3s-content-worker-node.d.ts.map +1 -0
  197. package/dist/workers/i3s-content-worker-node.js +7 -0
  198. package/dist/workers/i3s-content-worker.d.ts +2 -0
  199. package/dist/workers/i3s-content-worker.d.ts.map +1 -0
  200. package/dist/workers/i3s-content-worker.js +5 -4
  201. package/package.json +18 -16
  202. package/src/arcgis-webscene-loader.ts +31 -0
  203. package/src/i3s-attribute-loader.ts +9 -9
  204. package/src/i3s-content-loader.ts +17 -5
  205. package/src/i3s-loader.ts +24 -13
  206. package/src/i3s-node-page-loader.ts +6 -10
  207. package/src/i3s-slpk-loader.ts +27 -0
  208. package/src/index.ts +28 -7
  209. package/src/lib/helpers/i3s-nodepages-tiles.ts +84 -57
  210. package/src/lib/parsers/constants.ts +71 -37
  211. package/src/lib/parsers/parse-arcgis-webscene.ts +102 -0
  212. package/src/lib/parsers/parse-i3s-attribute.ts +21 -14
  213. package/src/lib/parsers/parse-i3s-building-scene-layer.ts +2 -1
  214. package/src/lib/parsers/parse-i3s-tile-content.ts +278 -194
  215. package/src/lib/parsers/parse-i3s.ts +55 -39
  216. package/src/lib/parsers/parse-slpk/parse-slpk.ts +72 -0
  217. package/src/lib/parsers/parse-slpk/slpk-archieve.ts +173 -0
  218. package/src/lib/parsers/parse-zip/buffer-file-provider.ts +55 -0
  219. package/src/lib/parsers/parse-zip/cd-file-header.ts +86 -0
  220. package/src/lib/parsers/parse-zip/file-provider.ts +34 -0
  221. package/src/lib/parsers/parse-zip/local-file-header.ts +65 -0
  222. package/src/lib/utils/customize-/321/201olors.ts +144 -0
  223. package/src/lib/utils/url-utils.ts +7 -7
  224. package/src/types.ts +875 -86
  225. package/src/workers/i3s-content-worker-node.ts +6 -0
  226. package/dist/bundle.js.map +0 -1
  227. package/dist/i3s-attribute-loader.js.map +0 -1
  228. package/dist/i3s-building-scene-layer-loader.js.map +0 -1
  229. package/dist/i3s-content-loader.js.map +0 -1
  230. package/dist/i3s-loader.js.map +0 -1
  231. package/dist/i3s-node-page-loader.js.map +0 -1
  232. package/dist/index.js.map +0 -1
  233. package/dist/lib/helpers/i3s-nodepages-tiles.js.map +0 -1
  234. package/dist/lib/parsers/constants.js.map +0 -1
  235. package/dist/lib/parsers/parse-i3s-attribute.js.map +0 -1
  236. package/dist/lib/parsers/parse-i3s-building-scene-layer.js.map +0 -1
  237. package/dist/lib/parsers/parse-i3s-tile-content.js.map +0 -1
  238. package/dist/lib/parsers/parse-i3s.js.map +0 -1
  239. package/dist/lib/utils/convert-i3s-obb-to-mbs.js.map +0 -1
  240. package/dist/lib/utils/url-utils.js.map +0 -1
  241. package/dist/types.js.map +0 -1
  242. package/dist/workers/i3s-content-worker.js.map +0 -1
@@ -4,79 +4,95 @@ import {load} from '@loaders.gl/core';
4
4
  import {TILE_TYPE, TILE_REFINEMENT, TILESET_TYPE} from '@loaders.gl/tiles';
5
5
  import I3SNodePagesTiles from '../helpers/i3s-nodepages-tiles';
6
6
  import {generateTileAttributeUrls, getUrlWithToken} from '../utils/url-utils';
7
+ import {
8
+ I3STilesetHeader,
9
+ I3STileHeader,
10
+ Mbs,
11
+ I3SMinimalNodeData,
12
+ Node3DIndexDocument
13
+ } from '../../types';
14
+ import type {LoaderOptions, LoaderContext} from '@loaders.gl/loader-utils';
7
15
 
8
- export function normalizeTileData(tile, options, context) {
9
- tile.url = context.url;
10
-
11
- if (tile.featureData) {
12
- tile.featureUrl = `${tile.url}/${tile.featureData[0].href}`;
13
- }
14
-
16
+ export function normalizeTileData(tile : Node3DIndexDocument, context: LoaderContext): I3STileHeader {
17
+ const url: string = context.url || '';
18
+ let contentUrl: string | undefined;
15
19
  if (tile.geometryData) {
16
- tile.contentUrl = `${tile.url}/${tile.geometryData[0].href}`;
20
+ contentUrl = `${url}/${tile.geometryData[0].href}`;
17
21
  }
18
22
 
23
+ let textureUrl: string | undefined;
19
24
  if (tile.textureData) {
20
- tile.textureUrl = `${tile.url}/${tile.textureData[0].href}`;
25
+ textureUrl = `${url}/${tile.textureData[0].href}`;
21
26
  }
22
27
 
28
+ let attributeUrls: string[] | undefined;
23
29
  if (tile.attributeData) {
24
- tile.attributeUrls = generateTileAttributeUrls(tile);
30
+ attributeUrls = generateTileAttributeUrls(url, tile);
25
31
  }
26
32
 
27
- return normalizeTileNonUrlData(tile);
33
+ return normalizeTileNonUrlData({
34
+ ...tile,
35
+ url,
36
+ contentUrl,
37
+ textureUrl,
38
+ attributeUrls,
39
+ isDracoGeometry: false
40
+ });
28
41
  }
29
42
 
30
- export function normalizeTileNonUrlData(tile) {
31
- const box = tile.obb
32
- ? [
33
- ...Ellipsoid.WGS84.cartographicToCartesian(tile.obb.center), // cartesian center of box
34
- ...tile.obb.halfSize, // halfSize
35
- ...tile.obb.quaternion // quaternion
36
- ]
37
- : undefined;
38
- let sphere;
43
+ export function normalizeTileNonUrlData(tile : I3SMinimalNodeData): I3STileHeader {
44
+ const boundingVolume: {box?: number[]; sphere?: number[]} = {};
45
+ let mbs: Mbs = [0, 0, 0, 1];
39
46
  if (tile.mbs) {
40
- sphere = [
47
+ mbs = tile.mbs;
48
+ boundingVolume.sphere = [
41
49
  ...Ellipsoid.WGS84.cartographicToCartesian(tile.mbs.slice(0, 3)), // cartesian center of sphere
42
50
  tile.mbs[3] // radius of sphere
51
+ ] as Mbs;
52
+ } else if (tile.obb) {
53
+ boundingVolume.box = [
54
+ ...Ellipsoid.WGS84.cartographicToCartesian(tile.obb.center), // cartesian center of box
55
+ ...tile.obb.halfSize, // halfSize
56
+ ...tile.obb.quaternion // quaternion
43
57
  ];
44
- } else if (box) {
45
58
  const obb = new OrientedBoundingBox().fromCenterHalfSizeQuaternion(
46
- box.slice(0, 3),
59
+ boundingVolume.box.slice(0, 3),
47
60
  tile.obb.halfSize,
48
61
  tile.obb.quaternion
49
62
  );
50
63
  const boundingSphere = obb.getBoundingSphere();
51
- sphere = [...boundingSphere.center, boundingSphere.radius];
52
- tile.mbs = [...tile.obb.center, boundingSphere.radius];
64
+ boundingVolume.sphere = [...boundingSphere.center , boundingSphere.radius] as Mbs;
65
+ mbs = [...tile.obb.center, boundingSphere.radius] as Mbs;
53
66
  }
54
67
 
55
- tile.boundingVolume = {
56
- sphere,
57
- box
58
- };
59
- tile.lodMetricType = tile.lodSelection[0].metricType;
60
- tile.lodMetricValue = tile.lodSelection[0].maxError;
61
- tile.transformMatrix = tile.transform;
62
- tile.type = TILE_TYPE.MESH;
63
- // TODO only support replacement for now
64
- tile.refine = TILE_REFINEMENT.REPLACE;
68
+ const lodMetricType = tile.lodSelection?.[0].metricType;
69
+ const lodMetricValue = tile.lodSelection?.[0].maxError;
70
+ const transformMatrix = tile.transform;
71
+ const type = TILE_TYPE.MESH;
72
+ /**
73
+ * I3S specification supports only REPLACE
74
+ */
75
+ const refine = TILE_REFINEMENT.REPLACE;
65
76
 
66
- return tile;
77
+ return {...tile, mbs, boundingVolume, lodMetricType, lodMetricValue, transformMatrix, type, refine};
67
78
  }
68
79
 
69
- export async function normalizeTilesetData(tileset, options, context) {
80
+ export async function normalizeTilesetData(tileset : I3STilesetHeader, options : LoaderOptions, context: LoaderContext) {
70
81
  tileset.url = context.url;
71
82
 
72
83
  if (tileset.nodePages) {
73
84
  tileset.nodePagesTile = new I3SNodePagesTiles(tileset, options);
74
- tileset.root = await tileset.nodePagesTile.formTileFromNodePages(0);
85
+ tileset.root = tileset.nodePagesTile.formTileFromNodePages(0);
75
86
  } else {
87
+ // @ts-expect-error options is not properly typed
76
88
  const rootNodeUrl = getUrlWithToken(`${tileset.url}/nodes/root`, options.i3s?.token);
77
89
  // eslint-disable-next-line no-use-before-define
78
90
  tileset.root = await load(rootNodeUrl, tileset.loader, {
79
- i3s: {loadContent: false, isTileHeader: true, isTileset: false}
91
+ ...options,
92
+ i3s: {
93
+ // @ts-expect-error options is not properly typed
94
+ ...options.i3s,
95
+ loadContent: false, isTileHeader: true, isTileset: false}
80
96
  });
81
97
  }
82
98
 
@@ -0,0 +1,72 @@
1
+ import type {SLPKLoaderOptions} from '../../../i3s-slpk-loader';
2
+ import {DataViewFileProvider} from '../parse-zip/buffer-file-provider';
3
+ import {parseZipCDFileHeader} from '../parse-zip/cd-file-header';
4
+ import {parseZipLocalFileHeader} from '../parse-zip/local-file-header';
5
+ import {SLPKArchive} from './slpk-archieve';
6
+
7
+ /**
8
+ * Returns one byte from the provided buffer at the provided position
9
+ * @param offset - position where to read
10
+ * @param buffer - buffer to read
11
+ * @returns one byte from the provided buffer at the provided position
12
+ */
13
+ const getByteAt = (offset: number, buffer: DataView): number => {
14
+ return buffer.getUint8(buffer.byteOffset + offset);
15
+ };
16
+
17
+ export async function parseSLPK(data: ArrayBuffer, options: SLPKLoaderOptions = {}) {
18
+ const archive = new DataView(data);
19
+ const cdFileHeaderSignature = [80, 75, 1, 2];
20
+
21
+ const searchWindow = [
22
+ getByteAt(archive.byteLength - 1, archive),
23
+ getByteAt(archive.byteLength - 2, archive),
24
+ getByteAt(archive.byteLength - 3, archive),
25
+ undefined
26
+ ];
27
+
28
+ let hashCDOffset = 0;
29
+
30
+ // looking for the last record in the central directory
31
+ for (let i = archive.byteLength - 4; i > -1; i--) {
32
+ searchWindow[3] = searchWindow[2];
33
+ searchWindow[2] = searchWindow[1];
34
+ searchWindow[1] = searchWindow[0];
35
+ searchWindow[0] = getByteAt(i, archive);
36
+ if (searchWindow.every((val, index) => val === cdFileHeaderSignature[index])) {
37
+ hashCDOffset = i;
38
+ break;
39
+ }
40
+ }
41
+
42
+ const fileProvider = new DataViewFileProvider(archive);
43
+
44
+ const cdFileHeader = await parseZipCDFileHeader(hashCDOffset, fileProvider);
45
+
46
+ if (cdFileHeader.fileName !== '@specialIndexFileHASH128@') {
47
+ throw new Error('No hash file in slpk');
48
+ }
49
+
50
+ const localFileHeader = await parseZipLocalFileHeader(
51
+ cdFileHeader.localHeaderOffset,
52
+ fileProvider
53
+ );
54
+ if (!localFileHeader) {
55
+ throw new Error('No hash file in slpk');
56
+ }
57
+
58
+ const fileDataOffset = localFileHeader.fileDataOffset;
59
+ const hashFile = archive.buffer.slice(
60
+ fileDataOffset,
61
+ fileDataOffset + localFileHeader.compressedSize
62
+ );
63
+
64
+ if (!hashFile) {
65
+ throw new Error('No hash file in slpk');
66
+ }
67
+
68
+ return await new SLPKArchive(data, hashFile).getFile(
69
+ options.slpk?.path ?? '',
70
+ options.slpk?.pathMode
71
+ );
72
+ }
@@ -0,0 +1,173 @@
1
+ import md5 from 'md5';
2
+ import {parseZipLocalFileHeader} from '../parse-zip/local-file-header';
3
+ import {DataViewFileProvider} from '../parse-zip/buffer-file-provider';
4
+ import {GZipCompression} from '@loaders.gl/compression';
5
+
6
+ /** Element of hash array */
7
+ type HashElement = {
8
+ /**
9
+ * File name hash
10
+ */
11
+ hash: Buffer;
12
+ /**
13
+ * File offset in the archive
14
+ */
15
+ offset: number;
16
+ };
17
+
18
+ /** Description of real paths for different file types */
19
+ const PATH_DESCRIPTIONS: {test: RegExp; extensions: string[]}[] = [
20
+ {
21
+ test: /^$/,
22
+ extensions: ['3dSceneLayer.json.gz']
23
+ },
24
+ {
25
+ test: /^nodepages\/\d+$/,
26
+ extensions: ['.json.gz']
27
+ },
28
+ {
29
+ test: /^nodes\/\d+$/,
30
+ extensions: ['/3dNodeIndexDocument.json.gz']
31
+ },
32
+ {
33
+ test: /^nodes\/\d+\/textures\/.+$/,
34
+ extensions: ['.jpg', '.png', '.bin.dds.gz', '.ktx']
35
+ },
36
+ {
37
+ test: /^nodes\/\d+\/geometries\/\d+$/,
38
+ extensions: ['.bin.gz', '.draco.gz']
39
+ },
40
+ {
41
+ test: /^nodes\/\d+\/attributes\/f_\d+\/\d+$/,
42
+ extensions: ['.bin.gz']
43
+ },
44
+ {
45
+ test: /^statistics\/f_\d+\/\d+$/,
46
+ extensions: ['.json.gz']
47
+ },
48
+ {
49
+ test: /^nodes\/\d+\/shared$/,
50
+ extensions: ['/sharedResource.json.gz']
51
+ }
52
+ ];
53
+
54
+ /**
55
+ * Class for handling information about slpk file
56
+ */
57
+ export class SLPKArchive {
58
+ slpkArchive: DataView;
59
+ hashArray: {hash: Buffer; offset: number}[];
60
+ constructor(slpkArchiveBuffer: ArrayBuffer, hashFile: ArrayBuffer) {
61
+ this.slpkArchive = new DataView(slpkArchiveBuffer);
62
+ this.hashArray = this.parseHashFile(hashFile);
63
+ }
64
+
65
+ /**
66
+ * Reads hash file from buffer and returns it in ready-to-use form
67
+ * @param hashFile - bufer containing hash file
68
+ * @returns Array containing file info
69
+ */
70
+ private parseHashFile(hashFile: ArrayBuffer): HashElement[] {
71
+ const hashFileBuffer = Buffer.from(hashFile);
72
+ const hashArray: HashElement[] = [];
73
+ for (let i = 0; i < hashFileBuffer.buffer.byteLength; i = i + 24) {
74
+ const offsetBuffer = new DataView(
75
+ hashFileBuffer.buffer.slice(
76
+ hashFileBuffer.byteOffset + i + 16,
77
+ hashFileBuffer.byteOffset + i + 24
78
+ )
79
+ );
80
+ const offset = offsetBuffer.getUint32(offsetBuffer.byteOffset, true);
81
+ hashArray.push({
82
+ hash: Buffer.from(
83
+ hashFileBuffer.subarray(hashFileBuffer.byteOffset + i, hashFileBuffer.byteOffset + i + 16)
84
+ ),
85
+ offset
86
+ });
87
+ }
88
+ return hashArray;
89
+ }
90
+
91
+ /**
92
+ * Returns file with the given path from slpk archive
93
+ * @param path - path inside the slpk
94
+ * @param mode - currently only raw mode supported
95
+ * @returns buffer with ready to use file
96
+ */
97
+ async getFile(path: string, mode: 'http' | 'raw' = 'raw'): Promise<Buffer> {
98
+ if (mode === 'http') {
99
+ const extensions = PATH_DESCRIPTIONS.find((val) => val.test.test(path))?.extensions;
100
+ if (extensions) {
101
+ let data: ArrayBuffer | undefined;
102
+ for (const ext of extensions) {
103
+ data = await this.getDataByPath(`${path}${ext}`);
104
+ if (data) {
105
+ break;
106
+ }
107
+ }
108
+ if (data) {
109
+ return Buffer.from(data);
110
+ }
111
+ }
112
+ }
113
+ if (mode === 'raw') {
114
+ const decompressedFile = await this.getDataByPath(`${path}.gz`);
115
+ if (decompressedFile) {
116
+ return Buffer.from(decompressedFile);
117
+ }
118
+ const fileWithoutCompression = await this.getFileBytes(path);
119
+ if (fileWithoutCompression) {
120
+ return Buffer.from(fileWithoutCompression);
121
+ }
122
+ }
123
+
124
+ throw new Error('No such file in the archieve');
125
+ }
126
+
127
+ /**
128
+ * returning uncompressed data for paths that ends with .gz and raw data for all other paths
129
+ * @param path - path inside the archive
130
+ * @returns buffer with the file data
131
+ */
132
+ private async getDataByPath(path: string): Promise<ArrayBuffer | undefined> {
133
+ const data = await this.getFileBytes(path);
134
+ if (!data) {
135
+ return undefined;
136
+ }
137
+ if (/\.gz$/.test(path)) {
138
+ const compression = new GZipCompression();
139
+
140
+ const decompressedData = await compression.decompress(data);
141
+ return decompressedData;
142
+ }
143
+ return Buffer.from(data);
144
+ }
145
+
146
+ /**
147
+ * Trying to get raw file data by adress
148
+ * @param path - path inside the archive
149
+ * @returns buffer with the raw file data
150
+ */
151
+ private async getFileBytes(path: string): Promise<ArrayBuffer | undefined> {
152
+ const nameHash = Buffer.from(md5(path), 'hex');
153
+ const fileInfo = this.hashArray.find((val) => Buffer.compare(val.hash, nameHash) === 0);
154
+ if (!fileInfo) {
155
+ return undefined;
156
+ }
157
+
158
+ const localFileHeader = await parseZipLocalFileHeader(
159
+ this.slpkArchive.byteOffset + fileInfo?.offset,
160
+ new DataViewFileProvider(this.slpkArchive)
161
+ );
162
+ if (!localFileHeader) {
163
+ return undefined;
164
+ }
165
+
166
+ const compressedFile = this.slpkArchive.buffer.slice(
167
+ localFileHeader.fileDataOffset,
168
+ localFileHeader.fileDataOffset + localFileHeader.compressedSize
169
+ );
170
+
171
+ return compressedFile;
172
+ }
173
+ }
@@ -0,0 +1,55 @@
1
+ import {FileProvider} from './file-provider';
2
+
3
+ /**
4
+ * Provides file data using DataView
5
+ */
6
+ export class DataViewFileProvider implements FileProvider {
7
+ /**
8
+ * The DataView from which data is provided
9
+ */
10
+ private file: DataView;
11
+
12
+ constructor(file: DataView) {
13
+ this.file = file;
14
+ }
15
+
16
+ /**
17
+ * Gets an unsigned 8-bit integer at the specified byte offset from the start of the file.
18
+ * @param offset The offset, in bytes, from the start of the file where to read the data.
19
+ */
20
+ getUint8(offset: number): Promise<number> {
21
+ return Promise.resolve(this.file.getUint8(offset));
22
+ }
23
+
24
+ /**
25
+ * Gets an unsigned 16-bit integer at the specified byte offset from the start of the file.
26
+ * @param offset The offset, in bytes, from the start of the file where to read the data.
27
+ */
28
+ getUint16(offset: number): Promise<number> {
29
+ return Promise.resolve(this.file.getUint16(offset, true));
30
+ }
31
+
32
+ /**
33
+ * Gets an unsigned 32-bit integer at the specified byte offset from the start of the file.
34
+ * @param offset The offset, in bytes, from the start of the file where to read the data.
35
+ */
36
+ getUint32(offset: number): Promise<number> {
37
+ return Promise.resolve(this.file.getUint32(offset, true));
38
+ }
39
+
40
+ /**
41
+ * returns an ArrayBuffer whose contents are a copy of this file bytes from startOffset, inclusive, up to endOffset, exclusive.
42
+ * @param startOffset The offset, in bytes, from the start of the file where to start reading the data.
43
+ * @param endOffset The offset, in bytes, from the start of the file where to end reading the data.
44
+ */
45
+ slice(startOffset: number, endOffset: number): Promise<ArrayBuffer> {
46
+ return Promise.resolve(this.file.buffer.slice(startOffset, endOffset));
47
+ }
48
+
49
+ /**
50
+ * the length (in bytes) of the data.
51
+ */
52
+ get length() {
53
+ return this.file.byteLength;
54
+ }
55
+ }
@@ -0,0 +1,86 @@
1
+ import {FileProvider} from './file-provider';
2
+
3
+ /**
4
+ * zip central directory file header info
5
+ * according to https://en.wikipedia.org/wiki/ZIP_(file_format)
6
+ */
7
+ export type ZipCDFileHeader = {
8
+ /** Compressed size */
9
+ compressedSize: number;
10
+ /** Uncompressed size */
11
+ uncompressedSize: number;
12
+ /** File name length */
13
+ fileNameLength: number;
14
+ /** File name */
15
+ fileName: string;
16
+ /** Extra field offset */
17
+ extraOffset: number;
18
+ /** Relative offset of local file header */
19
+ localHeaderOffset: number;
20
+ };
21
+
22
+ /**
23
+ * Parses central directory file header of zip file
24
+ * @param headerOffset - offset in the archive where header starts
25
+ * @param buffer - buffer containing whole array
26
+ * @returns Info from the header
27
+ */
28
+ export const parseZipCDFileHeader = async (
29
+ headerOffset: number,
30
+ buffer: FileProvider
31
+ ): Promise<ZipCDFileHeader> => {
32
+ const offsets = {
33
+ CD_COMPRESSED_SIZE_OFFSET: 20,
34
+ CD_UNCOMPRESSED_SIZE_OFFSET: 24,
35
+ CD_FILE_NAME_LENGTH_OFFSET: 28,
36
+ CD_EXTRA_FIELD_LENGTH_OFFSET: 30,
37
+ CD_LOCAL_HEADER_OFFSET_OFFSET: 42,
38
+ CD_FILE_NAME_OFFSET: 46
39
+ };
40
+
41
+ const compressedSize = await buffer.getUint32(headerOffset + offsets.CD_COMPRESSED_SIZE_OFFSET);
42
+
43
+ const uncompressedSize = await buffer.getUint32(
44
+ headerOffset + offsets.CD_UNCOMPRESSED_SIZE_OFFSET
45
+ );
46
+
47
+ const fileNameLength = await buffer.getUint16(headerOffset + offsets.CD_FILE_NAME_LENGTH_OFFSET);
48
+
49
+ const fileName = new TextDecoder().decode(
50
+ await buffer.slice(
51
+ headerOffset + offsets.CD_FILE_NAME_OFFSET,
52
+ headerOffset + offsets.CD_FILE_NAME_OFFSET + fileNameLength
53
+ )
54
+ );
55
+
56
+ const extraOffset = headerOffset + offsets.CD_FILE_NAME_OFFSET + fileNameLength;
57
+
58
+ const oldFormatOffset = await buffer.getUint32(
59
+ headerOffset + offsets.CD_LOCAL_HEADER_OFFSET_OFFSET
60
+ );
61
+
62
+ let fileDataOffset = oldFormatOffset;
63
+ if (fileDataOffset === 0xffffffff) {
64
+ let offsetInZip64Data = 4;
65
+ // looking for info that might be also be in zip64 extra field
66
+ if (compressedSize === 0xffffffff) {
67
+ offsetInZip64Data += 8;
68
+ }
69
+ if (uncompressedSize === 0xffffffff) {
70
+ offsetInZip64Data += 8;
71
+ }
72
+
73
+ // getUint32 needs to be replaced with getBigUint64 for archieves bigger than 2gb
74
+ fileDataOffset = await buffer.getUint32(extraOffset + offsetInZip64Data); // setting it to the one from zip64
75
+ }
76
+ const localHeaderOffset = fileDataOffset;
77
+
78
+ return {
79
+ compressedSize,
80
+ uncompressedSize,
81
+ fileNameLength,
82
+ fileName,
83
+ extraOffset,
84
+ localHeaderOffset
85
+ };
86
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Interface for providing file data
3
+ */
4
+ export interface FileProvider {
5
+ /**
6
+ * Gets an unsigned 8-bit integer at the specified byte offset from the start of the file.
7
+ * @param offset The offset, in bytes, from the start of the file where to read the data.
8
+ */
9
+ getUint8(offset: number): Promise<number>;
10
+
11
+ /**
12
+ * Gets an unsigned 16-bit integer at the specified byte offset from the start of the file.
13
+ * @param offset The offset, in bytes, from the start of the file where to read the data.
14
+ */
15
+ getUint16(offset: number): Promise<number>;
16
+
17
+ /**
18
+ * Gets an unsigned 32-bit integer at the specified byte offset from the start of the file.
19
+ * @param offset The offset, in bytes, from the file of the view where to read the data.
20
+ */
21
+ getUint32(offset: number): Promise<number>;
22
+
23
+ /**
24
+ * returns an ArrayBuffer whose contents are a copy of this file bytes from startOffset, inclusive, up to endOffset, exclusive.
25
+ * @param startOffset The offset, in bytes, from the start of the file where to start reading the data.
26
+ * @param endOffset The offset, in bytes, from the start of the file where to end reading the data.
27
+ */
28
+ slice(startOffset: number, endOffset: number): Promise<ArrayBuffer>;
29
+
30
+ /**
31
+ * the length (in bytes) of the data.
32
+ */
33
+ length: number;
34
+ }
@@ -0,0 +1,65 @@
1
+ import {FileProvider} from './file-provider';
2
+
3
+ /**
4
+ * zip local file header info
5
+ * according to https://en.wikipedia.org/wiki/ZIP_(file_format)
6
+ */
7
+ export type ZipLocalFileHeader = {
8
+ /** File name length */
9
+ fileNameLength: number;
10
+ /** File name */
11
+ fileName: string;
12
+ /** Extra field length */
13
+ extraFieldLength: number;
14
+ /** Offset of the file data */
15
+ fileDataOffset: number;
16
+ /** Compressed size */
17
+ compressedSize: number;
18
+ };
19
+
20
+ const offsets = {
21
+ COMPRESSED_SIZE_OFFSET: 18,
22
+ FILE_NAME_LENGTH_OFFSET: 26,
23
+ EXTRA_FIELD_LENGTH_OFFSET: 28,
24
+ FILE_NAME_OFFSET: 30
25
+ };
26
+
27
+ const signature = Buffer.from([0x50, 0x4b, 0x03, 0x04]);
28
+
29
+ /**
30
+ * Parses local file header of zip file
31
+ * @param headerOffset - offset in the archive where header starts
32
+ * @param buffer - buffer containing whole array
33
+ * @returns Info from the header
34
+ */
35
+ export const parseZipLocalFileHeader = async (
36
+ headerOffset: number,
37
+ buffer: FileProvider
38
+ ): Promise<ZipLocalFileHeader | undefined> => {
39
+ if (Buffer.from(await buffer.slice(headerOffset, headerOffset + 4)).compare(signature) !== 0) {
40
+ return Promise.resolve(undefined);
41
+ }
42
+
43
+ const fileNameLength = await buffer.getUint16(headerOffset + offsets.FILE_NAME_LENGTH_OFFSET);
44
+
45
+ const fileName = new TextDecoder().decode(
46
+ await buffer.slice(
47
+ headerOffset + offsets.FILE_NAME_OFFSET,
48
+ headerOffset + offsets.FILE_NAME_OFFSET + fileNameLength
49
+ )
50
+ );
51
+ const extraFieldLength = await buffer.getUint16(headerOffset + offsets.EXTRA_FIELD_LENGTH_OFFSET);
52
+
53
+ const fileDataOffset =
54
+ headerOffset + offsets.FILE_NAME_OFFSET + fileNameLength + extraFieldLength;
55
+
56
+ const compressedSize = await buffer.getUint32(headerOffset + offsets.COMPRESSED_SIZE_OFFSET);
57
+
58
+ return {
59
+ fileNameLength,
60
+ fileName,
61
+ extraFieldLength,
62
+ fileDataOffset,
63
+ compressedSize
64
+ };
65
+ };