@loaders.gl/tile-converter 3.1.8 → 3.2.0-alpha.3

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 (238) hide show
  1. package/dist/3d-tiles-attributes-worker.d.ts +28 -0
  2. package/dist/3d-tiles-attributes-worker.d.ts.map +1 -0
  3. package/dist/3d-tiles-attributes-worker.js +4 -0
  4. package/dist/3d-tiles-attributes-worker.js.map +7 -0
  5. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts +82 -0
  6. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts.map +1 -0
  7. package/dist/3d-tiles-converter/3d-tiles-converter.js +268 -0
  8. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts +84 -0
  9. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts.map +1 -0
  10. package/dist/3d-tiles-converter/helpers/b3dm-converter.js +278 -0
  11. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.d.ts +13 -0
  12. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.d.ts.map +1 -0
  13. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +23 -0
  14. package/dist/3d-tiles-converter/helpers/texture-atlas.d.ts +9 -0
  15. package/dist/3d-tiles-converter/helpers/texture-atlas.d.ts.map +1 -0
  16. package/dist/3d-tiles-converter/helpers/texture-atlas.js +52 -0
  17. package/dist/3d-tiles-converter/json-templates/tileset.d.ts +15 -0
  18. package/dist/3d-tiles-converter/json-templates/tileset.d.ts.map +1 -0
  19. package/dist/3d-tiles-converter/json-templates/tileset.js +43 -0
  20. package/dist/bundle.d.ts +2 -0
  21. package/dist/bundle.d.ts.map +1 -0
  22. package/dist/bundle.js +5 -0
  23. package/dist/converter-cli.d.ts +2 -0
  24. package/dist/converter-cli.d.ts.map +1 -0
  25. package/dist/converter-cli.js +232 -0
  26. package/dist/converter.min.js +68 -68
  27. package/dist/deps-installer/deps-installer.d.ts +14 -0
  28. package/dist/deps-installer/deps-installer.d.ts.map +1 -0
  29. package/dist/deps-installer/deps-installer.js +31 -0
  30. package/dist/dist.min.js +1151 -1264
  31. package/dist/es5/3d-tiles-attributes-worker.js +29 -0
  32. package/dist/es5/3d-tiles-attributes-worker.js.map +1 -0
  33. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js +104 -44
  34. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  35. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js +34 -43
  36. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  37. package/dist/es5/converter-cli.js +306 -0
  38. package/dist/es5/converter-cli.js.map +1 -0
  39. package/dist/es5/deps-installer/deps-installer.js.map +1 -1
  40. package/dist/es5/i3s-attributes-worker.js +29 -0
  41. package/dist/es5/i3s-attributes-worker.js.map +1 -0
  42. package/dist/es5/i3s-converter/helpers/coordinate-converter.js +19 -11
  43. package/dist/es5/i3s-converter/helpers/coordinate-converter.js.map +1 -1
  44. package/dist/es5/i3s-converter/helpers/geometry-attributes.js +2 -2
  45. package/dist/es5/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  46. package/dist/es5/i3s-converter/helpers/geometry-converter.js +271 -182
  47. package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
  48. package/dist/es5/i3s-converter/helpers/gltf-attributes.js +71 -0
  49. package/dist/es5/i3s-converter/helpers/gltf-attributes.js.map +1 -0
  50. package/dist/es5/i3s-converter/helpers/node-pages.js +47 -99
  51. package/dist/es5/i3s-converter/helpers/node-pages.js.map +1 -1
  52. package/dist/es5/i3s-converter/i3s-converter.js +311 -245
  53. package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
  54. package/dist/es5/index.js +0 -16
  55. package/dist/es5/index.js.map +1 -1
  56. package/dist/es5/lib/utils/compress-util.js +14 -17
  57. package/dist/es5/lib/utils/compress-util.js.map +1 -1
  58. package/dist/es5/lib/utils/file-utils.js +39 -14
  59. package/dist/es5/lib/utils/file-utils.js.map +1 -1
  60. package/dist/es5/lib/utils/lod-conversion-utils.js.map +1 -1
  61. package/dist/es5/lib/utils/queue.js +61 -0
  62. package/dist/es5/lib/utils/queue.js.map +1 -0
  63. package/dist/es5/lib/utils/statistic-utills.js.map +1 -1
  64. package/dist/es5/lib/utils/write-queue.js +225 -0
  65. package/dist/es5/lib/utils/write-queue.js.map +1 -0
  66. package/dist/es5/pgm-loader.js +1 -1
  67. package/dist/es5/pgm-loader.js.map +1 -1
  68. package/dist/es5/workers/3d-tiles-attributes-worker.js +37 -0
  69. package/dist/es5/workers/3d-tiles-attributes-worker.js.map +1 -0
  70. package/dist/es5/workers/i3s-attributes-worker.js +40 -0
  71. package/dist/es5/workers/i3s-attributes-worker.js.map +1 -0
  72. package/dist/esm/3d-tiles-attributes-worker.js +16 -0
  73. package/dist/esm/3d-tiles-attributes-worker.js.map +1 -0
  74. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js +32 -5
  75. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  76. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js +23 -23
  77. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  78. package/dist/esm/converter-cli.js +230 -0
  79. package/dist/esm/converter-cli.js.map +1 -0
  80. package/dist/esm/deps-installer/deps-installer.js.map +1 -1
  81. package/dist/esm/i3s-attributes-worker.js +16 -0
  82. package/dist/esm/i3s-attributes-worker.js.map +1 -0
  83. package/dist/esm/i3s-converter/helpers/coordinate-converter.js +19 -11
  84. package/dist/esm/i3s-converter/helpers/coordinate-converter.js.map +1 -1
  85. package/dist/esm/i3s-converter/helpers/geometry-attributes.js +2 -2
  86. package/dist/esm/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  87. package/dist/esm/i3s-converter/helpers/geometry-converter.js +121 -62
  88. package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
  89. package/dist/esm/i3s-converter/helpers/gltf-attributes.js +54 -0
  90. package/dist/esm/i3s-converter/helpers/gltf-attributes.js.map +1 -0
  91. package/dist/esm/i3s-converter/helpers/node-pages.js +12 -4
  92. package/dist/esm/i3s-converter/helpers/node-pages.js.map +1 -1
  93. package/dist/esm/i3s-converter/i3s-converter.js +155 -50
  94. package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
  95. package/dist/esm/index.js +0 -2
  96. package/dist/esm/index.js.map +1 -1
  97. package/dist/esm/lib/utils/compress-util.js +6 -8
  98. package/dist/esm/lib/utils/compress-util.js.map +1 -1
  99. package/dist/esm/lib/utils/file-utils.js +11 -1
  100. package/dist/esm/lib/utils/file-utils.js.map +1 -1
  101. package/dist/esm/lib/utils/lod-conversion-utils.js.map +1 -1
  102. package/dist/esm/lib/utils/queue.js +19 -0
  103. package/dist/esm/lib/utils/queue.js.map +1 -0
  104. package/dist/esm/lib/utils/statistic-utills.js.map +1 -1
  105. package/dist/esm/lib/utils/write-queue.js +88 -0
  106. package/dist/esm/lib/utils/write-queue.js.map +1 -0
  107. package/dist/esm/pgm-loader.js +1 -1
  108. package/dist/esm/pgm-loader.js.map +1 -1
  109. package/dist/esm/workers/3d-tiles-attributes-worker.js +5 -0
  110. package/dist/esm/workers/3d-tiles-attributes-worker.js.map +1 -0
  111. package/dist/esm/workers/i3s-attributes-worker.js +4 -0
  112. package/dist/esm/workers/i3s-attributes-worker.js.map +1 -0
  113. package/dist/i3s-attributes-worker.d.ts +33 -0
  114. package/dist/i3s-attributes-worker.d.ts.map +1 -0
  115. package/dist/i3s-attributes-worker.js +10 -0
  116. package/dist/i3s-attributes-worker.js.map +7 -0
  117. package/dist/i3s-converter/helpers/coordinate-converter.d.ts +41 -0
  118. package/dist/i3s-converter/helpers/coordinate-converter.d.ts.map +1 -0
  119. package/dist/i3s-converter/helpers/coordinate-converter.js +122 -0
  120. package/dist/i3s-converter/helpers/create-scene-server-path.d.ts +9 -0
  121. package/dist/i3s-converter/helpers/create-scene-server-path.d.ts.map +1 -0
  122. package/dist/i3s-converter/helpers/create-scene-server-path.js +28 -0
  123. package/dist/i3s-converter/helpers/geometry-attributes.d.ts +8 -0
  124. package/dist/i3s-converter/helpers/geometry-attributes.d.ts.map +1 -0
  125. package/dist/i3s-converter/helpers/geometry-attributes.js +177 -0
  126. package/dist/i3s-converter/helpers/geometry-converter.d.ts +29 -0
  127. package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -0
  128. package/dist/i3s-converter/helpers/geometry-converter.js +901 -0
  129. package/dist/i3s-converter/helpers/gltf-attributes.d.ts +9 -0
  130. package/dist/i3s-converter/helpers/gltf-attributes.d.ts.map +1 -0
  131. package/dist/i3s-converter/helpers/gltf-attributes.js +56 -0
  132. package/dist/i3s-converter/helpers/node-debug.d.ts +8 -0
  133. package/dist/i3s-converter/helpers/node-debug.d.ts.map +1 -0
  134. package/dist/i3s-converter/helpers/node-debug.js +114 -0
  135. package/dist/i3s-converter/helpers/node-pages.d.ts +117 -0
  136. package/dist/i3s-converter/helpers/node-pages.d.ts.map +1 -0
  137. package/dist/i3s-converter/helpers/node-pages.js +208 -0
  138. package/dist/i3s-converter/i3s-converter.d.ts +323 -0
  139. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -0
  140. package/dist/i3s-converter/i3s-converter.js +1074 -0
  141. package/dist/i3s-converter/json-templates/layers.d.ts +95 -0
  142. package/dist/i3s-converter/json-templates/layers.d.ts.map +1 -0
  143. package/dist/i3s-converter/json-templates/layers.js +199 -0
  144. package/dist/i3s-converter/json-templates/metadata.d.ts +22 -0
  145. package/dist/i3s-converter/json-templates/metadata.d.ts.map +1 -0
  146. package/dist/i3s-converter/json-templates/metadata.js +25 -0
  147. package/dist/i3s-converter/json-templates/node.d.ts +61 -0
  148. package/dist/i3s-converter/json-templates/node.d.ts.map +1 -0
  149. package/dist/i3s-converter/json-templates/node.js +89 -0
  150. package/dist/i3s-converter/json-templates/scene-server.d.ts +28 -0
  151. package/dist/i3s-converter/json-templates/scene-server.d.ts.map +1 -0
  152. package/dist/i3s-converter/json-templates/scene-server.js +31 -0
  153. package/dist/i3s-converter/json-templates/shared-resources.d.ts +14 -0
  154. package/dist/i3s-converter/json-templates/shared-resources.d.ts.map +1 -0
  155. package/dist/i3s-converter/json-templates/shared-resources.js +129 -0
  156. package/dist/i3s-converter/json-templates/store.d.ts +95 -0
  157. package/dist/i3s-converter/json-templates/store.d.ts.map +1 -0
  158. package/dist/i3s-converter/json-templates/store.js +103 -0
  159. package/dist/i3s-converter/types.d.ts +114 -0
  160. package/dist/i3s-converter/types.d.ts.map +1 -0
  161. package/dist/i3s-converter/types.js +2 -0
  162. package/dist/i3s-server/app.d.ts +3 -0
  163. package/dist/i3s-server/app.d.ts.map +1 -0
  164. package/dist/i3s-server/app.js +14 -0
  165. package/dist/i3s-server/controllers/index-controller.d.ts +2 -0
  166. package/dist/i3s-server/controllers/index-controller.d.ts.map +1 -0
  167. package/dist/i3s-server/controllers/index-controller.js +23 -0
  168. package/dist/i3s-server/routes/index.d.ts +3 -0
  169. package/dist/i3s-server/routes/index.d.ts.map +1 -0
  170. package/dist/i3s-server/routes/index.js +16 -0
  171. package/dist/index.d.ts +3 -0
  172. package/dist/index.d.ts.map +1 -0
  173. package/dist/index.js +10 -0
  174. package/dist/lib/utils/compress-util.d.ts +45 -0
  175. package/dist/lib/utils/compress-util.d.ts.map +1 -0
  176. package/dist/lib/utils/compress-util.js +257 -0
  177. package/dist/{esm/lib → lib}/utils/file-utils.d.ts +6 -14
  178. package/dist/lib/utils/file-utils.d.ts.map +1 -0
  179. package/dist/lib/utils/file-utils.js +81 -0
  180. package/dist/lib/utils/lod-conversion-utils.d.ts +41 -0
  181. package/dist/lib/utils/lod-conversion-utils.d.ts.map +1 -0
  182. package/dist/lib/utils/lod-conversion-utils.js +76 -0
  183. package/dist/lib/utils/queue.d.ts +7 -0
  184. package/dist/lib/utils/queue.d.ts.map +1 -0
  185. package/dist/lib/utils/queue.js +18 -0
  186. package/dist/lib/utils/statistic-utills.d.ts +3 -0
  187. package/dist/lib/utils/statistic-utills.d.ts.map +1 -0
  188. package/dist/lib/utils/statistic-utills.js +64 -0
  189. package/dist/lib/utils/write-queue.d.ts +22 -0
  190. package/dist/lib/utils/write-queue.d.ts.map +1 -0
  191. package/dist/lib/utils/write-queue.js +62 -0
  192. package/dist/pgm-loader.d.ts +6 -0
  193. package/dist/pgm-loader.d.ts.map +1 -0
  194. package/dist/pgm-loader.js +23 -0
  195. package/dist/workers/3d-tiles-attributes-worker.d.ts +2 -0
  196. package/dist/workers/3d-tiles-attributes-worker.d.ts.map +1 -0
  197. package/dist/workers/3d-tiles-attributes-worker.js +9 -0
  198. package/dist/workers/i3s-attributes-worker.d.ts +2 -0
  199. package/dist/workers/i3s-attributes-worker.d.ts.map +1 -0
  200. package/dist/workers/i3s-attributes-worker.js +5 -0
  201. package/package.json +19 -18
  202. package/src/3d-tiles-attributes-worker.ts +43 -0
  203. package/src/3d-tiles-converter/3d-tiles-converter.ts +49 -6
  204. package/src/3d-tiles-converter/helpers/b3dm-converter.ts +21 -18
  205. package/src/converter-cli.ts +310 -0
  206. package/src/deps-installer/{deps-installer.js → deps-installer.ts} +11 -1
  207. package/src/i3s-attributes-worker.ts +46 -0
  208. package/src/i3s-converter/helpers/coordinate-converter.ts +29 -24
  209. package/src/i3s-converter/helpers/geometry-attributes.ts +4 -3
  210. package/src/i3s-converter/helpers/{geometry-converter.js → geometry-converter.ts} +425 -179
  211. package/src/i3s-converter/helpers/gltf-attributes.ts +68 -0
  212. package/src/i3s-converter/helpers/node-pages.ts +25 -17
  213. package/src/i3s-converter/i3s-converter.ts +154 -87
  214. package/src/i3s-converter/types.ts +90 -8
  215. package/src/index.ts +0 -4
  216. package/src/lib/utils/{compress-util.js → compress-util.ts} +105 -18
  217. package/src/lib/utils/file-utils.ts +84 -0
  218. package/src/lib/utils/{lod-conversion-utils.js → lod-conversion-utils.ts} +27 -5
  219. package/src/lib/utils/queue.ts +17 -0
  220. package/src/lib/utils/{statistic-utills.js → statistic-utills.ts} +0 -0
  221. package/src/lib/utils/write-queue.ts +75 -0
  222. package/src/workers/3d-tiles-attributes-worker.ts +6 -0
  223. package/src/workers/i3s-attributes-worker.ts +6 -0
  224. package/dist/es5/deps-installer/deps-installer.d.ts +0 -10
  225. package/dist/es5/i3s-converter/helpers/geometry-converter.d.ts +0 -44
  226. package/dist/es5/lib/utils/compress-util.d.ts +0 -53
  227. package/dist/es5/lib/utils/file-utils.d.ts +0 -43
  228. package/dist/es5/lib/utils/lod-conversion-utils.d.ts +0 -32
  229. package/dist/esm/deps-installer/deps-installer.d.ts +0 -10
  230. package/dist/esm/i3s-converter/helpers/geometry-converter.d.ts +0 -44
  231. package/dist/esm/lib/utils/compress-util.d.ts +0 -53
  232. package/dist/esm/lib/utils/lod-conversion-utils.d.ts +0 -32
  233. package/src/deps-installer/deps-installer.d.ts +0 -10
  234. package/src/i3s-converter/helpers/geometry-converter.d.ts +0 -44
  235. package/src/lib/utils/compress-util.d.ts +0 -53
  236. package/src/lib/utils/file-utils.d.ts +0 -43
  237. package/src/lib/utils/file-utils.js +0 -38
  238. package/src/lib/utils/lod-conversion-utils.d.ts +0 -32
@@ -0,0 +1,1074 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const core_1 = require("@loaders.gl/core");
7
+ const tiles_1 = require("@loaders.gl/tiles");
8
+ const _3d_tiles_1 = require("@loaders.gl/3d-tiles");
9
+ const path_1 = require("path");
10
+ const uuid_1 = require("uuid");
11
+ const process_1 = __importDefault(require("process"));
12
+ const json_map_transform_1 = __importDefault(require("json-map-transform"));
13
+ const md5_1 = __importDefault(require("md5"));
14
+ const node_pages_1 = __importDefault(require("./helpers/node-pages"));
15
+ const file_utils_1 = require("../lib/utils/file-utils");
16
+ const compress_util_1 = require("../lib/utils/compress-util");
17
+ const statistic_utills_1 = require("../lib/utils/statistic-utills");
18
+ const geometry_converter_1 = __importDefault(require("./helpers/geometry-converter"));
19
+ const coordinate_converter_1 = require("./helpers/coordinate-converter");
20
+ const create_scene_server_path_1 = require("./helpers/create-scene-server-path");
21
+ const lod_conversion_utils_1 = require("../lib/utils/lod-conversion-utils");
22
+ const pgm_loader_1 = require("../pgm-loader");
23
+ const layers_1 = require("./json-templates/layers");
24
+ const node_1 = require("./json-templates/node");
25
+ const shared_resources_1 = require("./json-templates/shared-resources");
26
+ const node_debug_1 = require("./helpers/node-debug");
27
+ const textures_1 = require("@loaders.gl/textures");
28
+ const images_1 = require("@loaders.gl/images");
29
+ const worker_utils_1 = require("@loaders.gl/worker-utils");
30
+ const draco_1 = require("@loaders.gl/draco");
31
+ const write_queue_1 = __importDefault(require("../lib/utils/write-queue"));
32
+ const i3s_attributes_worker_1 = require("../i3s-attributes-worker");
33
+ const ION_DEFAULT_TOKEN = process_1.default.env.IonToken || // eslint-disable-line
34
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlYWMxMzcyYy0zZjJkLTQwODctODNlNi01MDRkZmMzMjIxOWIiLCJpZCI6OTYyMCwic2NvcGVzIjpbImFzbCIsImFzciIsImdjIl0sImlhdCI6MTU2Mjg2NjI3M30.1FNiClUyk00YH_nWfSGpiQAjR5V2OvREDq1PJ5QMjWQ'; // eslint-disable-line
35
+ const HARDCODED_NODES_PER_PAGE = 64;
36
+ const _3D_TILES = '3DTILES';
37
+ const _3D_OBJECT_LAYER_TYPE = '3DObject';
38
+ const STRING_TYPE = 'string';
39
+ const SHORT_INT_TYPE = 'Int32';
40
+ const DOUBLE_TYPE = 'double';
41
+ const OBJECT_ID_TYPE = 'OBJECTID';
42
+ const REFRESH_TOKEN_TIMEOUT = 1800; // 30 minutes in seconds
43
+ const CESIUM_DATASET_PREFIX = 'https://';
44
+ // const FS_FILE_TOO_LARGE = 'ERR_FS_FILE_TOO_LARGE';
45
+ /**
46
+ * Converter from 3d-tiles tileset to i3s layer
47
+ */
48
+ class I3SConverter {
49
+ constructor() {
50
+ this.boundingVolumeWarnings = [];
51
+ this.conversionStartTime = [0, 0];
52
+ this.refreshTokenTime = [0, 0];
53
+ this.sourceTileset = null;
54
+ this.geoidHeightModel = null;
55
+ this.Loader = _3d_tiles_1.Tiles3DLoader;
56
+ this.workerSource = {};
57
+ this.writeQueue = new write_queue_1.default();
58
+ this.nodePages = new node_pages_1.default(file_utils_1.writeFile, HARDCODED_NODES_PER_PAGE);
59
+ this.options = {};
60
+ this.layers0Path = '';
61
+ this.materialMap = new Map();
62
+ this.materialDefinitions = [];
63
+ this.vertexCounter = 0;
64
+ this.layers0 = null;
65
+ this.featuresHashArray = [];
66
+ this.refinementCounter = {
67
+ tilesCount: 0,
68
+ tilesWithAddRefineCount: 0
69
+ };
70
+ this.validate = false;
71
+ this.generateTextures = false;
72
+ this.generateBoundingVolumes = false;
73
+ this.layersHasTexture = false;
74
+ }
75
+ /**
76
+ * Convert a 3d tileset
77
+ * @param options
78
+ * @param options.inputUrl the url to read the tileset from
79
+ * @param options.outputPath the output filename
80
+ * @param options.tilesetName the output name of the tileset
81
+ * @param options.maxDepth The max tree depth of conversion
82
+ * @param options.slpk Generate slpk (Scene Layer Packages) output file
83
+ * @param options.sevenZipExe Location of 7z.exe archiver to create slpk on Windows
84
+ * @param options.egmFilePath location of *.pgm file to convert heights from ellipsoidal to gravity-related format
85
+ * @param options.token Token for Cesium ION tilesets authentication
86
+ * @param options.draco Generate I3S 1.7 draco compressed geometries
87
+ * @param options.validate -enable validation
88
+ */
89
+ async convert(options) {
90
+ this.conversionStartTime = process_1.default.hrtime();
91
+ const { tilesetName, slpk, egmFilePath, inputUrl, validate, outputPath, draco, sevenZipExe, maxDepth, token, generateTextures, generateBoundingVolumes } = options;
92
+ this.options = { maxDepth, slpk, sevenZipExe, egmFilePath, draco, token, inputUrl };
93
+ this.validate = Boolean(validate);
94
+ this.Loader = inputUrl.indexOf(CESIUM_DATASET_PREFIX) !== -1 ? _3d_tiles_1.CesiumIonLoader : _3d_tiles_1.Tiles3DLoader;
95
+ this.generateTextures = Boolean(generateTextures);
96
+ this.generateBoundingVolumes = Boolean(generateBoundingVolumes);
97
+ this.writeQueue = new write_queue_1.default();
98
+ this.writeQueue.startListening();
99
+ console.log('Loading egm file...'); // eslint-disable-line
100
+ this.geoidHeightModel = await (0, core_1.load)(egmFilePath, pgm_loader_1.PGMLoader);
101
+ console.log('Loading egm file completed!'); // eslint-disable-line
102
+ if (slpk) {
103
+ this.nodePages.useWriteFunction(file_utils_1.writeFileForSlpk);
104
+ }
105
+ await this.loadWorkers();
106
+ try {
107
+ const preloadOptions = await this._fetchPreloadOptions();
108
+ const tilesetOptions = { loadOptions: { basis: { format: 'rgba32' } } };
109
+ if (preloadOptions.headers) {
110
+ tilesetOptions.loadOptions.fetch = { headers: preloadOptions.headers };
111
+ }
112
+ Object.assign(tilesetOptions, preloadOptions);
113
+ const sourceTilesetJson = await (0, core_1.load)(inputUrl, this.Loader, tilesetOptions.loadOptions);
114
+ // console.log(tilesetJson); // eslint-disable-line
115
+ this.sourceTileset = new tiles_1.Tileset3D(sourceTilesetJson, tilesetOptions);
116
+ await this._createAndSaveTileset(outputPath, tilesetName);
117
+ await this._finishConversion({ slpk: Boolean(slpk), outputPath, tilesetName });
118
+ return sourceTilesetJson;
119
+ }
120
+ catch (error) {
121
+ throw error;
122
+ }
123
+ finally {
124
+ // Clean up worker pools
125
+ const workerFarm = worker_utils_1.WorkerFarm.getWorkerFarm({});
126
+ workerFarm.destroy();
127
+ }
128
+ }
129
+ /**
130
+ * Convert and save the layer and embedded tiles
131
+ * @param outputPath - path to save output data
132
+ * @param tilesetName - new tileset path
133
+ */
134
+ async _createAndSaveTileset(outputPath, tilesetName) {
135
+ const tilesetPath = (0, path_1.join)(`${outputPath}`, `${tilesetName}`);
136
+ // Removing the tilesetPath needed to exclude erroneous files after conversion
137
+ try {
138
+ await (0, file_utils_1.removeDir)(tilesetPath);
139
+ }
140
+ catch (e) {
141
+ // do nothing
142
+ }
143
+ this.layers0Path = (0, path_1.join)(tilesetPath, 'SceneServer', 'layers', '0');
144
+ this._formLayers0(tilesetName);
145
+ this.materialDefinitions = [];
146
+ this.materialMap = new Map();
147
+ const sourceRootTile = this.sourceTileset.root;
148
+ const boundingVolumes = (0, coordinate_converter_1.createBoundingVolumes)(sourceRootTile, this.geoidHeightModel);
149
+ const parentId = this.nodePages.push({
150
+ index: 0,
151
+ lodThreshold: 0,
152
+ obb: boundingVolumes.obb,
153
+ children: []
154
+ });
155
+ const isCreateSlpk = this.options.slpk;
156
+ const root0 = this._formRootNodeIndexDocument(boundingVolumes);
157
+ await this._convertNodesTree(root0, sourceRootTile, parentId, boundingVolumes);
158
+ this.layers0.materialDefinitions = this.materialDefinitions;
159
+ if (this.layersHasTexture === false) {
160
+ this.layers0.store.defaultGeometrySchema.ordering =
161
+ this.layers0.store.defaultGeometrySchema.ordering.filter((attribute) => attribute !== 'uv0');
162
+ }
163
+ await this._writeLayers0();
164
+ (0, create_scene_server_path_1.createSceneServerPath)(tilesetName, this.layers0, tilesetPath);
165
+ await this._writeNodeIndexDocument(root0, 'root', (0, path_1.join)(this.layers0Path, 'nodes', 'root'));
166
+ await this.nodePages.save(this.layers0Path, this.writeQueue, isCreateSlpk);
167
+ await this.writeQueue.finalize();
168
+ await this._createSlpk(tilesetPath);
169
+ }
170
+ /**
171
+ * Form object of 3DSceneLayer https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DSceneLayer.cmn.md
172
+ * @param tilesetName - Name of layer
173
+ */
174
+ _formLayers0(tilesetName) {
175
+ const fullExtent = (0, coordinate_converter_1.convertBoundingVolumeToI3SFullExtent)(this.sourceTileset?.boundingVolume || this.sourceTileset?.root?.boundingVolume);
176
+ const extent = [fullExtent.xmin, fullExtent.ymin, fullExtent.xmax, fullExtent.ymax];
177
+ const layers0data = {
178
+ version: `{${(0, uuid_1.v4)().toUpperCase()}}`,
179
+ id: 0,
180
+ name: tilesetName,
181
+ href: './layers/0',
182
+ store: {
183
+ id: `{${(0, uuid_1.v4)().toUpperCase()}}`,
184
+ extent
185
+ },
186
+ nodePages: {
187
+ nodesPerPage: HARDCODED_NODES_PER_PAGE
188
+ },
189
+ compressGeometry: this.options.draco
190
+ };
191
+ this.layers0 = (0, json_map_transform_1.default)(layers0data, (0, layers_1.LAYERS)());
192
+ }
193
+ /**
194
+ * Convert and save the layer and embedded tiles
195
+ * @param boundingVolumes - mbs and obb data about node's bounding volume
196
+ * @return 3DNodeIndexDocument data https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md
197
+ */
198
+ _formRootNodeIndexDocument(boundingVolumes) {
199
+ const root0data = {
200
+ version: `{${(0, uuid_1.v4)().toUpperCase()}}`,
201
+ id: 'root',
202
+ level: 0,
203
+ lodSelection: [
204
+ {
205
+ metricType: 'maxScreenThresholdSQ',
206
+ maxError: 0
207
+ },
208
+ {
209
+ metricType: 'maxScreenThreshold',
210
+ maxError: 0
211
+ }
212
+ ],
213
+ ...boundingVolumes,
214
+ children: []
215
+ };
216
+ return (0, json_map_transform_1.default)(root0data, (0, node_1.NODE)());
217
+ }
218
+ /**
219
+ * Form object of 3DSceneLayer https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DSceneLayer.cmn.md
220
+ * @param root0 - 3DNodeIndexDocument of root node https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md
221
+ * @param sourceRootTile - Source (3DTile) tile data
222
+ * @param parentId - node id in node pages
223
+ * @param boundingVolumes - mbs and obb data about node's bounding volume
224
+ */
225
+ async _convertNodesTree(root0, sourceRootTile, parentId, boundingVolumes) {
226
+ await this.sourceTileset._loadTile(sourceRootTile);
227
+ if (this.isContentSupported(sourceRootTile)) {
228
+ root0.children = root0.children || [];
229
+ root0.children.push({
230
+ id: '1',
231
+ href: './1',
232
+ ...boundingVolumes
233
+ });
234
+ const [child] = await this._createNode(root0, sourceRootTile, parentId, 0);
235
+ const childPath = (0, path_1.join)(this.layers0Path, 'nodes', child.path);
236
+ if (this.options.slpk) {
237
+ this.writeQueue.enqueue({
238
+ archiveKey: 'nodes/1/3dNodeIndexDocument.json.gz',
239
+ writePromise: (0, file_utils_1.writeFileForSlpk)(childPath, JSON.stringify(child), '3dNodeIndexDocument.json')
240
+ });
241
+ }
242
+ else {
243
+ this.writeQueue.enqueue({ writePromise: (0, file_utils_1.writeFile)(childPath, JSON.stringify(child)) });
244
+ }
245
+ }
246
+ else {
247
+ await this._addChildrenWithNeighborsAndWriteFile({
248
+ parentNode: root0,
249
+ sourceTiles: sourceRootTile.children,
250
+ parentId,
251
+ level: 1
252
+ });
253
+ }
254
+ await sourceRootTile.unloadContent();
255
+ }
256
+ /**
257
+ * Write 3DSceneLayer https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DSceneLayer.cmn.md in file
258
+ */
259
+ async _writeLayers0() {
260
+ if (this.options.slpk) {
261
+ this.writeQueue.enqueue({
262
+ archiveKey: '3dSceneLayer.json.gz',
263
+ writePromise: (0, file_utils_1.writeFileForSlpk)(this.layers0Path, JSON.stringify(this.layers0), '3dSceneLayer.json')
264
+ });
265
+ }
266
+ else {
267
+ this.writeQueue.enqueue({
268
+ writePromise: (0, file_utils_1.writeFile)(this.layers0Path, JSON.stringify(this.layers0))
269
+ });
270
+ }
271
+ }
272
+ /**
273
+ * Write 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md in file
274
+ */
275
+ async _writeNodeIndexDocument(root0, nodePath, rootPath) {
276
+ if (this.options.slpk) {
277
+ this.writeQueue.enqueue({
278
+ archiveKey: `nodes/${nodePath}/3dNodeIndexDocument.json.gz`,
279
+ writePromise: (0, file_utils_1.writeFileForSlpk)(rootPath, JSON.stringify(root0), '3dNodeIndexDocument.json')
280
+ });
281
+ }
282
+ else {
283
+ this.writeQueue.enqueue({ writePromise: (0, file_utils_1.writeFile)(rootPath, JSON.stringify(root0)) });
284
+ }
285
+ }
286
+ /**
287
+ * Pack files into *.slpk archive
288
+ * @param tilesetPath - Path to save file
289
+ */
290
+ async _createSlpk(tilesetPath) {
291
+ if (this.options.slpk) {
292
+ const slpkTilesetPath = (0, path_1.join)(tilesetPath, 'SceneServer', 'layers', '0');
293
+ const slpkFileName = `${tilesetPath}.slpk`;
294
+ await (0, compress_util_1.compressWithChildProcess)(slpkTilesetPath, slpkFileName, 0, '.', this.options.sevenZipExe);
295
+ // TODO: `addFileToZip` corrupts archive so it can't be validated with windows i3s_converter.exe
296
+ // const fileHash128Path = `${tilesetPath}/@specialIndexFileHASH128@`;
297
+ // try {
298
+ // await generateHash128FromZip(slpkFileName, fileHash128Path);
299
+ // await addFileToZip(
300
+ // tilesetPath,
301
+ // '@specialIndexFileHASH128@',
302
+ // slpkFileName,
303
+ // this.options.sevenZipExe
304
+ // );
305
+ // } catch (error) {
306
+ // if (error.code === FS_FILE_TOO_LARGE) {
307
+ // console.warn(`${slpkFileName} file is too big to generate a hash`); // eslint-disable-line
308
+ // } else {
309
+ // console.error(error); // eslint-disable-line
310
+ // }
311
+ // }
312
+ // All converted files are contained in slpk now they can be deleted
313
+ try {
314
+ await (0, file_utils_1.removeDir)(tilesetPath);
315
+ }
316
+ catch (e) {
317
+ // do nothing
318
+ }
319
+ }
320
+ }
321
+ /**
322
+ * Add child nodes recursively and write them to files
323
+ * @param data - arguments
324
+ * @param data.sourceTiles - array of source child nodes
325
+ * @param data.parentNode - 3DNodeIndexDocument of parent node for processing child nodes
326
+ * @param data.parentId - id of parent node in node pages
327
+ * @param data.level - level of node (distanse to root node in the tree)
328
+ */
329
+ async _addChildrenWithNeighborsAndWriteFile(data) {
330
+ const childNodes = [];
331
+ await this._addChildren({ ...data, childNodes });
332
+ await this._addNeighborsAndWriteFile(data.parentNode, childNodes);
333
+ }
334
+ /**
335
+ * Add child nodes recursively and write them to files
336
+ * @param data - arguments
337
+ * @param data.childNodes - array of target child nodes
338
+ * @param data.sourceTiles - array of source child nodes
339
+ * @param data.parentNode - 3DNodeIndexDocument of parent node for processing child nodes
340
+ * @param data.parentId - id of parent node in node pages
341
+ * @param data.level - level of node (distanse to root node in the tree)
342
+ */
343
+ async _addChildren(data) {
344
+ const { childNodes, sourceTiles, parentNode, parentId, level } = data;
345
+ if (this.options.maxDepth && level > this.options.maxDepth) {
346
+ return;
347
+ }
348
+ for (const sourceTile of sourceTiles) {
349
+ if (sourceTile.type === 'json') {
350
+ await this.sourceTileset._loadTile(sourceTile);
351
+ await this._addChildren({
352
+ parentNode,
353
+ sourceTiles: sourceTile.children,
354
+ childNodes,
355
+ parentId,
356
+ level: level + 1
357
+ });
358
+ await sourceTile.unloadContent();
359
+ }
360
+ else {
361
+ const children = await this._createNode(parentNode, sourceTile, parentId, level);
362
+ parentNode.children = parentNode.children || [];
363
+ for (const child of children) {
364
+ parentNode.children.push({
365
+ id: child.id,
366
+ href: `../${child.path}`,
367
+ obb: child.obb,
368
+ mbs: child.mbs
369
+ });
370
+ childNodes.push(child);
371
+ }
372
+ }
373
+ if (sourceTile.id) {
374
+ console.log(sourceTile.id); // eslint-disable-line
375
+ }
376
+ }
377
+ }
378
+ /**
379
+ * Add neightbors to 3DNodeIndexDocument and write it in a file
380
+ * @param parentNode - arguments
381
+ * @param childNodes - array of target child nodes
382
+ */
383
+ async _addNeighborsAndWriteFile(parentNode, childNodes) {
384
+ for (const node of childNodes) {
385
+ const childPath = (0, path_1.join)(this.layers0Path, 'nodes', node.path);
386
+ const nodePath = node.path;
387
+ delete node.path;
388
+ // Don't do large amount of "neightbors" to avoid big memory consumption
389
+ if (Number(parentNode?.children?.length) < 1000) {
390
+ for (const neighbor of parentNode.children || []) {
391
+ // eslint-disable-next-line max-depth
392
+ if (node.id === neighbor.id) {
393
+ continue; // eslint-disable-line
394
+ }
395
+ if (node.neighbors) {
396
+ node.neighbors.push({ ...neighbor });
397
+ }
398
+ }
399
+ }
400
+ else {
401
+ // eslint-disable-next-line no-console, no-undef
402
+ console.warn(`Node ${node.id}: neighbors attribute is omited because of large number of neigbors`);
403
+ delete node.neighbors;
404
+ }
405
+ await this._writeNodeIndexDocument(node, nodePath, childPath);
406
+ node.neighbors = [];
407
+ }
408
+ }
409
+ /**
410
+ * Convert tile to one or more I3S nodes
411
+ * @param parentTile - parent 3DNodeIndexDocument
412
+ * @param sourceTile - source tile (3DTile)
413
+ * @param parentId - id of parent node in node pages
414
+ * @param level - level of node (distanse to root node in the tree)
415
+ */
416
+ async _createNode(parentTile, sourceTile, parentId, level) {
417
+ if (this.validate) {
418
+ this._checkAddRefinementTypeForTile(sourceTile);
419
+ }
420
+ await this._updateTilesetOptions();
421
+ await this.sourceTileset._loadTile(sourceTile);
422
+ let boundingVolumes = (0, coordinate_converter_1.createBoundingVolumes)(sourceTile, this.geoidHeightModel);
423
+ const batchTable = sourceTile?.content?.batchTableJson;
424
+ if (batchTable) {
425
+ this._convertAttributeStorageInfo(sourceTile.content);
426
+ }
427
+ const resourcesData = await this._convertResources(sourceTile);
428
+ const nodes = [];
429
+ const nodesInPage = [];
430
+ const emptyResources = {
431
+ geometry: null,
432
+ compressedGeometry: null,
433
+ texture: null,
434
+ sharedResources: null,
435
+ meshMaterial: null,
436
+ vertexCount: null,
437
+ attributes: null,
438
+ featureCount: null,
439
+ boundingVolumes: null
440
+ };
441
+ for (const resources of resourcesData || [emptyResources]) {
442
+ this.layersHasTexture = this.layersHasTexture || Boolean(resources.texture);
443
+ if (this.generateBoundingVolumes && resources.boundingVolumes) {
444
+ boundingVolumes = resources.boundingVolumes;
445
+ }
446
+ const lodSelection = (0, lod_conversion_utils_1.convertGeometricErrorToScreenThreshold)(sourceTile, boundingVolumes);
447
+ const maxScreenThresholdSQ = lodSelection.find((val) => val.metricType === 'maxScreenThresholdSQ') || { maxError: 0 };
448
+ const nodeInPage = this._createNodeInNodePages(maxScreenThresholdSQ, boundingVolumes, sourceTile, parentId, resources);
449
+ const node = this._createNodeIndexDocument(parentTile, boundingVolumes, lodSelection, nodeInPage, resources);
450
+ if (nodeInPage.mesh) {
451
+ await this._writeResources(resources, node.path);
452
+ }
453
+ if (this.validate) {
454
+ this.boundingVolumeWarnings = (0, node_debug_1.validateNodeBoundingVolumes)(node);
455
+ if (this.boundingVolumeWarnings && this.boundingVolumeWarnings.length) {
456
+ console.warn('Bounding Volume Warnings: ', ...this.boundingVolumeWarnings); //eslint-disable-line
457
+ }
458
+ }
459
+ nodes.push(node);
460
+ nodesInPage.push(nodeInPage);
461
+ }
462
+ sourceTile.unloadContent();
463
+ await this._addChildrenWithNeighborsAndWriteFile({
464
+ parentNode: nodes[0],
465
+ sourceTiles: sourceTile.children,
466
+ parentId: nodesInPage[0].index,
467
+ level: level + 1
468
+ });
469
+ return nodes;
470
+ }
471
+ /**
472
+ * Convert attributesStorageInfo https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md
473
+ * from B3DM batch table
474
+ * @param sourceTileContent - tile content of 3DTile
475
+ * @return {void}
476
+ */
477
+ _convertAttributeStorageInfo(sourceTileContent) {
478
+ // In legacy b3dm files sometimes sourceTileContent is null.
479
+ const batchTable = sourceTileContent && sourceTileContent.batchTableJson;
480
+ if (batchTable && !this.layers0?.attributeStorageInfo?.length) {
481
+ this._convertBatchTableInfoToNodeAttributes(batchTable);
482
+ }
483
+ }
484
+ /**
485
+ * Convert tile to one or more I3S nodes
486
+ * @param sourceTile - source tile (3DTile)
487
+ * result.geometry - ArrayBuffer with geometry attributes
488
+ * result.compressedGeometry - ArrayBuffer with compressed (draco) geometry
489
+ * result.texture - texture image
490
+ * result.sharedResources - shared resource data object
491
+ * result.meshMaterial - PBR-like material object
492
+ * result.vertexCount - number of vertices in geometry
493
+ * result.attributes - feature attributes
494
+ * result.featureCount - number of features
495
+ */
496
+ async _convertResources(sourceTile) {
497
+ if (!this.isContentSupported(sourceTile)) {
498
+ return null;
499
+ }
500
+ const resourcesData = await (0, geometry_converter_1.default)(sourceTile.content, Number(this.nodePages.nodesCounter), this.featuresHashArray, this.layers0?.attributeStorageInfo, this.options.draco, this.generateBoundingVolumes, this.geoidHeightModel, this.workerSource);
501
+ return resourcesData;
502
+ }
503
+ /**
504
+ * Create a new node object (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/node.cmn.md)
505
+ * in node pages (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/nodePage.cmn.md)
506
+ * @param maxScreenThresholdSQ - Level of Details (LOD) metric
507
+ * @param boundingVolumes - Bounding volumes
508
+ * @param sourceTile - source tile (3DTile)
509
+ * @param parentId - id of parent node in node pages
510
+ * @param resources - the node resources data
511
+ * @param resources.meshMaterial - PBR-like material object
512
+ * @param resources.texture - texture image
513
+ * @param resources.vertexCount - number of vertices in geometry
514
+ * @param resources.featureCount - number of features
515
+ * @return the node object in node pages
516
+ */
517
+ _createNodeInNodePages(maxScreenThresholdSQ, boundingVolumes, sourceTile, parentId, resources) {
518
+ const { meshMaterial, texture, vertexCount, featureCount, geometry } = resources;
519
+ const nodeInPage = {
520
+ index: 0,
521
+ lodThreshold: maxScreenThresholdSQ.maxError,
522
+ obb: boundingVolumes.obb,
523
+ children: []
524
+ };
525
+ if (geometry && this.isContentSupported(sourceTile)) {
526
+ nodeInPage.mesh = {
527
+ geometry: {
528
+ definition: texture ? 0 : 1,
529
+ resource: 0
530
+ },
531
+ attribute: {
532
+ resource: 0
533
+ },
534
+ material: {
535
+ definition: 0
536
+ }
537
+ };
538
+ }
539
+ const nodeId = this.nodePages.push(nodeInPage, parentId);
540
+ if (meshMaterial) {
541
+ this.nodePages.updateMaterialByNodeId(nodeId, this._findOrCreateMaterial(meshMaterial));
542
+ }
543
+ if (texture) {
544
+ const texelCountHint = texture.image.height * texture.image.width;
545
+ this.nodePages.updateTexelCountHintByNodeId(nodeId, texelCountHint);
546
+ }
547
+ if (vertexCount) {
548
+ this.vertexCounter += vertexCount;
549
+ this.nodePages.updateVertexCountByNodeId(nodeId, vertexCount);
550
+ }
551
+ this.nodePages.updateNodeAttributeByNodeId(nodeId);
552
+ if (featureCount) {
553
+ this.nodePages.updateFeatureCountByNodeId(nodeId, featureCount);
554
+ }
555
+ return nodeInPage;
556
+ }
557
+ /**
558
+ * Create a new node page object in node pages
559
+ * @param parentNode - 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md object of the parent node
560
+ * @param boundingVolumes - Bounding volumes
561
+ * @param lodSelection - Level of Details (LOD) metrics
562
+ * @param nodeInPage - corresponding node object in a node page
563
+ * @param resources - the node resources data
564
+ * @param resources.texture - texture image
565
+ * @param resources.attributes - feature attributes
566
+ * @return 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md object
567
+ */
568
+ _createNodeIndexDocument(parentNode, boundingVolumes, lodSelection, nodeInPage, resources) {
569
+ const { texture, attributes } = resources;
570
+ const nodeId = nodeInPage.index;
571
+ const nodeData = {
572
+ version: parentNode.version,
573
+ id: nodeId.toString(),
574
+ path: nodeId.toString(),
575
+ level: parentNode.level + 1,
576
+ ...boundingVolumes,
577
+ lodSelection,
578
+ parentNode: {
579
+ id: parentNode.id,
580
+ href: `../${parentNode.id}`,
581
+ mbs: parentNode.mbs,
582
+ obb: parentNode.obb
583
+ },
584
+ children: [],
585
+ neighbors: []
586
+ };
587
+ const node = (0, json_map_transform_1.default)(nodeData, (0, node_1.NODE)());
588
+ if (nodeInPage.mesh) {
589
+ node.geometryData = [{ href: './geometries/0' }];
590
+ node.sharedResource = { href: './shared' };
591
+ if (texture) {
592
+ node.textureData = [{ href: './textures/0' }, { href: './textures/1' }];
593
+ }
594
+ if (attributes && attributes.length && this.layers0?.attributeStorageInfo?.length) {
595
+ node.attributeData = [];
596
+ for (let index = 0; index < attributes.length; index++) {
597
+ const folderName = this.layers0.attributeStorageInfo[index].key;
598
+ node.attributeData.push({ href: `./attributes/${folderName}/0` });
599
+ }
600
+ }
601
+ }
602
+ return node;
603
+ }
604
+ /**
605
+ * Write node resources in files
606
+ * @param resources - source tile (3DTile)
607
+ * @param resources.geometry - Uint8Array with geometry attributes
608
+ * @param resources.compressedGeometry - Uint8Array with compressed (draco) geometry
609
+ * @param resources.texture - texture image
610
+ * @param resources.sharedResources - shared resource data object
611
+ * @param resources.attributes - feature attributes
612
+ * @return {Promise<void>}
613
+ */
614
+ async _writeResources(resources, nodePath) {
615
+ const { geometry: geometryBuffer, compressedGeometry, texture, sharedResources, attributes } = resources;
616
+ const childPath = (0, path_1.join)(this.layers0Path, 'nodes', nodePath);
617
+ const slpkChildPath = (0, path_1.join)('nodes', nodePath);
618
+ await this._writeGeometries(geometryBuffer, compressedGeometry, childPath, slpkChildPath);
619
+ await this._writeShared(sharedResources, childPath, slpkChildPath, nodePath);
620
+ await this._writeTexture(texture, childPath, slpkChildPath);
621
+ await this._writeAttributes(attributes, childPath, slpkChildPath);
622
+ }
623
+ /**
624
+ * Write non-compressed and compressed geometries in files
625
+ * @param geometryBuffer - Uint8Array with geometry attributes
626
+ * @param compressedGeometry - Uint8Array with compressed (draco) geometry
627
+ * @param childPath - a child path to write resources
628
+ * @param slpkChildPath - resource path inside *slpk file
629
+ */
630
+ async _writeGeometries(geometryBuffer, compressedGeometry, childPath, slpkChildPath) {
631
+ if (this.options.slpk) {
632
+ const slpkGeometryPath = (0, path_1.join)(childPath, 'geometries');
633
+ this.writeQueue.enqueue({
634
+ archiveKey: `${slpkChildPath}/geometries/0.bin.gz`,
635
+ writePromise: (0, file_utils_1.writeFileForSlpk)(slpkGeometryPath, geometryBuffer, '0.bin')
636
+ });
637
+ }
638
+ else {
639
+ const geometryPath = (0, path_1.join)(childPath, 'geometries/0/');
640
+ this.writeQueue.enqueue({
641
+ writePromise: (0, file_utils_1.writeFile)(geometryPath, geometryBuffer, 'index.bin')
642
+ });
643
+ }
644
+ if (this.options.draco) {
645
+ if (this.options.slpk) {
646
+ const slpkCompressedGeometryPath = (0, path_1.join)(childPath, 'geometries');
647
+ this.writeQueue.enqueue({
648
+ archiveKey: `${slpkChildPath}/geometries/1.bin.gz`,
649
+ writePromise: (0, file_utils_1.writeFileForSlpk)(slpkCompressedGeometryPath, compressedGeometry, '1.bin')
650
+ });
651
+ }
652
+ else {
653
+ const compressedGeometryPath = (0, path_1.join)(childPath, 'geometries/1/');
654
+ this.writeQueue.enqueue({
655
+ writePromise: (0, file_utils_1.writeFile)(compressedGeometryPath, compressedGeometry, 'index.bin')
656
+ });
657
+ }
658
+ }
659
+ }
660
+ /**
661
+ * Write shared resources in a file
662
+ * @param sharedResources - shared resource data object
663
+ * @param childPath - a child path to write resources
664
+ * @param slpkChildPath - resource path inside *slpk file
665
+ * @param nodePath - a node path
666
+ */
667
+ async _writeShared(sharedResources, childPath, slpkChildPath, nodePath) {
668
+ if (!sharedResources) {
669
+ return;
670
+ }
671
+ sharedResources.nodePath = nodePath;
672
+ const sharedData = (0, json_map_transform_1.default)(sharedResources, (0, shared_resources_1.SHARED_RESOURCES)());
673
+ const sharedDataStr = JSON.stringify(sharedData);
674
+ if (this.options.slpk) {
675
+ const slpkSharedPath = (0, path_1.join)(childPath, 'shared');
676
+ this.writeQueue.enqueue({
677
+ archiveKey: `${slpkChildPath}/shared/sharedResource.json.gz`,
678
+ writePromise: (0, file_utils_1.writeFileForSlpk)(slpkSharedPath, sharedDataStr, 'sharedResource.json')
679
+ });
680
+ }
681
+ else {
682
+ const sharedPath = (0, path_1.join)(childPath, 'shared/');
683
+ this.writeQueue.enqueue({ writePromise: (0, file_utils_1.writeFile)(sharedPath, sharedDataStr) });
684
+ }
685
+ }
686
+ /**
687
+ * Generates textures based on texture mime type and fill in textureSetDefinitions data.
688
+ * @param texture - the texture image
689
+ * @param childPath - a child path to write resources
690
+ * @param slpkChildPath - the resource path inside *slpk file
691
+ */
692
+ async _writeTexture(texture, childPath, slpkChildPath) {
693
+ if (texture) {
694
+ const format = this._getFormatByMimeType(texture?.mimeType);
695
+ const formats = [];
696
+ const textureData = texture.bufferView.data;
697
+ switch (format) {
698
+ case 'jpg':
699
+ case 'png': {
700
+ formats.push({ name: '0', format });
701
+ await this.writeTextureFile(textureData, '0', format, childPath, slpkChildPath);
702
+ if (this.generateTextures) {
703
+ formats.push({ name: '1', format: 'ktx2' });
704
+ const ktx2TextureData = (0, core_1.encode)(texture.image, textures_1.KTX2BasisWriterWorker, {
705
+ ...textures_1.KTX2BasisWriterWorker.options,
706
+ source: this.workerSource.ktx2,
707
+ reuseWorkers: true,
708
+ _nodeWorkers: true
709
+ });
710
+ await this.writeTextureFile(ktx2TextureData, '1', 'ktx2', childPath, slpkChildPath);
711
+ }
712
+ break;
713
+ }
714
+ case 'ktx2': {
715
+ formats.push({ name: '1', format });
716
+ await this.writeTextureFile(textureData, '1', format, childPath, slpkChildPath);
717
+ if (this.generateTextures) {
718
+ formats.push({ name: '0', format: 'jpg' });
719
+ const decodedFromKTX2TextureData = (0, core_1.encode)(texture.image.data[0], images_1.ImageWriter);
720
+ await this.writeTextureFile(decodedFromKTX2TextureData, '0', 'jpg', childPath, slpkChildPath);
721
+ }
722
+ }
723
+ }
724
+ if (!this.layers0.textureSetDefinitions.length) {
725
+ this.layers0.textureSetDefinitions.push({ formats });
726
+ }
727
+ }
728
+ }
729
+ /**
730
+ * Write the texture image in a file
731
+ * @param textureData
732
+ * @param name
733
+ * @param format
734
+ * @param childPath
735
+ * @param slpkChildPath
736
+ */
737
+ async writeTextureFile(textureData, name, format, childPath, slpkChildPath) {
738
+ if (this.options.slpk) {
739
+ const slpkTexturePath = (0, path_1.join)(childPath, 'textures');
740
+ const compress = false;
741
+ this.writeQueue.enqueue({
742
+ archiveKey: `${slpkChildPath}/textures/${name}.${format}`,
743
+ writePromise: (0, file_utils_1.writeFileForSlpk)(slpkTexturePath, textureData, `${name}.${format}`, compress)
744
+ });
745
+ }
746
+ else {
747
+ const texturePath = (0, path_1.join)(childPath, `textures/${name}/`);
748
+ this.writeQueue.enqueue({
749
+ writePromise: (0, file_utils_1.writeFile)(texturePath, textureData, `index.${format}`)
750
+ });
751
+ }
752
+ }
753
+ /**
754
+ * Write feature attributes in files
755
+ * @param attributes - feature attributes
756
+ * @param childPath - a child path to write resources
757
+ * @param slpkChildPath - the resource path inside *slpk file
758
+ */
759
+ async _writeAttributes(attributes = [], childPath, slpkChildPath) {
760
+ if (attributes?.length && this.layers0?.attributeStorageInfo?.length) {
761
+ for (let index = 0; index < attributes.length; index++) {
762
+ const folderName = this.layers0.attributeStorageInfo[index].key;
763
+ const fileBuffer = new Uint8Array(attributes[index]);
764
+ if (this.options.slpk) {
765
+ const slpkAttributesPath = (0, path_1.join)(childPath, 'attributes', folderName);
766
+ this.writeQueue.enqueue({
767
+ archiveKey: `${slpkChildPath}/attributes/${folderName}.bin.gz`,
768
+ writePromise: (0, file_utils_1.writeFileForSlpk)(slpkAttributesPath, fileBuffer, '0.bin')
769
+ });
770
+ }
771
+ else {
772
+ const attributesPath = (0, path_1.join)(childPath, `attributes/${folderName}/0`);
773
+ this.writeQueue.enqueue({
774
+ writePromise: (0, file_utils_1.writeFile)(attributesPath, fileBuffer, 'index.bin')
775
+ });
776
+ }
777
+ }
778
+ }
779
+ }
780
+ /**
781
+ * Return file format by its MIME type
782
+ * @param mimeType - feature attributes
783
+ */
784
+ _getFormatByMimeType(mimeType) {
785
+ switch (mimeType) {
786
+ case 'image/jpeg':
787
+ return 'jpg';
788
+ case 'image/png':
789
+ return 'png';
790
+ case 'image/ktx2':
791
+ return 'ktx2';
792
+ default:
793
+ return 'jpg';
794
+ }
795
+ }
796
+ /**
797
+ * Find or create material in materialDefinitions array
798
+ * @param material - end-to-end index of the node
799
+ * @return material id
800
+ */
801
+ _findOrCreateMaterial(material) {
802
+ const hash = (0, md5_1.default)(JSON.stringify(material));
803
+ if (this.materialMap.has(hash)) {
804
+ return this.materialMap.get(hash);
805
+ }
806
+ const newMaterialId = this.materialDefinitions.push(material) - 1;
807
+ this.materialMap.set(hash, newMaterialId);
808
+ return newMaterialId;
809
+ }
810
+ /**
811
+ * Generate storage attribute for map segmentation.
812
+ * @param attributeIndex - order index of attribute (f_0, f_1 ...).
813
+ * @param key - attribute key from batch table.\
814
+ * @param attributeType - attribute type.
815
+ * @return Updated storageAttribute.
816
+ */
817
+ _createdStorageAttribute(attributeIndex, key, attributeType) {
818
+ const storageAttribute = {
819
+ key: `f_${attributeIndex}`,
820
+ name: key,
821
+ ordering: ['attributeValues'],
822
+ header: [{ property: 'count', valueType: 'UInt32' }],
823
+ attributeValues: { valueType: 'Int32', valuesPerElement: 1 }
824
+ };
825
+ switch (attributeType) {
826
+ case OBJECT_ID_TYPE:
827
+ this._setupIdAttribute(storageAttribute);
828
+ break;
829
+ case STRING_TYPE:
830
+ this._setupStringAttribute(storageAttribute);
831
+ break;
832
+ case DOUBLE_TYPE:
833
+ this._setupDoubleAttribute(storageAttribute);
834
+ break;
835
+ case SHORT_INT_TYPE:
836
+ break;
837
+ default:
838
+ this._setupStringAttribute(storageAttribute);
839
+ }
840
+ return storageAttribute;
841
+ }
842
+ /**
843
+ * Get the attribute type for attributeStorageInfo https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md
844
+ * @param key - attribute's key
845
+ * @param attribute - attribute's type in batchTable
846
+ */
847
+ getAttributeType(key, attribute) {
848
+ if (key === OBJECT_ID_TYPE) {
849
+ return OBJECT_ID_TYPE;
850
+ }
851
+ if (typeof attribute === STRING_TYPE) {
852
+ return STRING_TYPE;
853
+ }
854
+ else if (typeof attribute === 'number') {
855
+ return Number.isInteger(attribute) ? SHORT_INT_TYPE : DOUBLE_TYPE;
856
+ }
857
+ return STRING_TYPE;
858
+ }
859
+ /**
860
+ * Setup storage attribute as string.
861
+ * @param storageAttribute - attribute for map segmentation.
862
+ */
863
+ _setupStringAttribute(storageAttribute) {
864
+ storageAttribute.ordering.unshift('attributeByteCounts');
865
+ storageAttribute.header.push({ property: 'attributeValuesByteCount', valueType: 'UInt32' });
866
+ storageAttribute.attributeValues = {
867
+ valueType: 'String',
868
+ encoding: 'UTF-8',
869
+ valuesPerElement: 1
870
+ };
871
+ storageAttribute.attributeByteCounts = {
872
+ valueType: 'UInt32',
873
+ valuesPerElement: 1
874
+ };
875
+ }
876
+ /**
877
+ * Setup Id attribute for map segmentation.
878
+ * @param storageAttribute - attribute for map segmentation .
879
+ */
880
+ _setupIdAttribute(storageAttribute) {
881
+ storageAttribute.attributeValues = {
882
+ valueType: 'Oid32',
883
+ valuesPerElement: 1
884
+ };
885
+ }
886
+ /**
887
+ * Setup double attribute for map segmentation.
888
+ * @param storageAttribute - attribute for map segmentation .
889
+ */
890
+ _setupDoubleAttribute(storageAttribute) {
891
+ storageAttribute.attributeValues = {
892
+ valueType: 'Float64',
893
+ valuesPerElement: 1
894
+ };
895
+ }
896
+ /**
897
+ * Setup field attribute for map segmentation.
898
+ * @param key - attribute for map segmentation.
899
+ * @param fieldAttributeType - esri attribute type ('esriFieldTypeString' or 'esriFieldTypeOID').
900
+ */
901
+ _createFieldAttribute(key, fieldAttributeType) {
902
+ return {
903
+ name: key,
904
+ type: fieldAttributeType,
905
+ alias: key
906
+ };
907
+ }
908
+ /**
909
+ * Do conversion of 3DTiles batch table to I3s node attributes.
910
+ * @param batchTable - Table with layer meta data.
911
+ */
912
+ _convertBatchTableInfoToNodeAttributes(batchTable) {
913
+ let attributeIndex = 0;
914
+ const batchTableWithObjectId = {
915
+ OBJECTID: [0],
916
+ ...batchTable
917
+ };
918
+ for (const key in batchTableWithObjectId) {
919
+ const firstAttribute = batchTableWithObjectId[key][0];
920
+ const attributeType = this.getAttributeType(key, firstAttribute);
921
+ const storageAttribute = this._createdStorageAttribute(attributeIndex, key, attributeType);
922
+ const fieldAttributeType = this._getFieldAttributeType(attributeType);
923
+ const fieldAttribute = this._createFieldAttribute(key, fieldAttributeType);
924
+ const popupInfo = this._createPopupInfo(batchTableWithObjectId);
925
+ this.layers0.attributeStorageInfo.push(storageAttribute);
926
+ this.layers0.fields.push(fieldAttribute);
927
+ this.layers0.popupInfo = popupInfo;
928
+ this.layers0.layerType = _3D_OBJECT_LAYER_TYPE;
929
+ attributeIndex += 1;
930
+ }
931
+ }
932
+ /**
933
+ * Find and return attribute type based on key form Batch table.
934
+ * @param attributeType
935
+ */
936
+ _getFieldAttributeType(attributeType) {
937
+ switch (attributeType) {
938
+ case OBJECT_ID_TYPE:
939
+ return 'esriFieldTypeOID';
940
+ case STRING_TYPE:
941
+ return 'esriFieldTypeString';
942
+ case SHORT_INT_TYPE:
943
+ return 'esriFieldTypeInteger';
944
+ case DOUBLE_TYPE:
945
+ return 'esriFieldTypeDouble';
946
+ default:
947
+ return 'esriFieldTypeString';
948
+ }
949
+ }
950
+ /**
951
+ * Generate popup info to show metadata on the map.
952
+ * @param batchTable - Batch table data with OBJECTID.
953
+ * @return data for correct rendering of popup.
954
+ */
955
+ _createPopupInfo(batchTable) {
956
+ const title = '{OBJECTID}';
957
+ const mediaInfos = [];
958
+ const fieldInfos = [];
959
+ const popupElements = [];
960
+ const expressionInfos = [];
961
+ for (const key in batchTable) {
962
+ fieldInfos.push({
963
+ fieldName: key,
964
+ visible: true,
965
+ isEditable: false,
966
+ label: key
967
+ });
968
+ }
969
+ popupElements.push({
970
+ fieldInfos,
971
+ type: 'fields'
972
+ });
973
+ return {
974
+ title,
975
+ mediaInfos,
976
+ popupElements,
977
+ fieldInfos,
978
+ expressionInfos
979
+ };
980
+ }
981
+ /**
982
+ * Print statistics in the end of conversion
983
+ * @param params - output files data
984
+ */
985
+ async _finishConversion(params) {
986
+ const { tilesCount, tilesWithAddRefineCount } = this.refinementCounter;
987
+ const addRefinementPercentage = tilesWithAddRefineCount
988
+ ? (tilesWithAddRefineCount / tilesCount) * 100
989
+ : 0;
990
+ const filesSize = await (0, statistic_utills_1.calculateFilesSize)(params);
991
+ const diff = process_1.default.hrtime(this.conversionStartTime);
992
+ const conversionTime = (0, statistic_utills_1.timeConverter)(diff);
993
+ console.log(`------------------------------------------------`); // eslint-disable-line no-undef, no-console
994
+ console.log(`Finishing conversion of ${_3D_TILES}`); // eslint-disable-line no-undef, no-console
995
+ console.log(`Total conversion time: ${conversionTime}`); // eslint-disable-line no-undef, no-console
996
+ console.log(`Vertex count: `, this.vertexCounter); // eslint-disable-line no-undef, no-console
997
+ console.log(`File(s) size: `, filesSize, ' bytes'); // eslint-disable-line no-undef, no-console
998
+ console.log(`Percentage of tiles with "ADD" refinement type:`, addRefinementPercentage, '%'); // eslint-disable-line no-undef, no-console
999
+ console.log(`------------------------------------------------`); // eslint-disable-line no-undef, no-console
1000
+ }
1001
+ /**
1002
+ * Fetch preload options for ION tileset
1003
+ */
1004
+ async _fetchPreloadOptions() {
1005
+ if (!this.Loader.preload) {
1006
+ return {};
1007
+ }
1008
+ const options = {
1009
+ 'cesium-ion': { accessToken: this.options.token || ION_DEFAULT_TOKEN }
1010
+ };
1011
+ const preloadOptions = await this.Loader.preload(this.options.inputUrl, options);
1012
+ this.refreshTokenTime = process_1.default.hrtime();
1013
+ return { ...options, ...preloadOptions };
1014
+ }
1015
+ /**
1016
+ * Update options of source tileset
1017
+ */
1018
+ async _updateTilesetOptions() {
1019
+ const diff = process_1.default.hrtime(this.refreshTokenTime);
1020
+ if (diff[0] < REFRESH_TOKEN_TIMEOUT) {
1021
+ return;
1022
+ }
1023
+ this.refreshTokenTime = process_1.default.hrtime();
1024
+ const preloadOptions = await this._fetchPreloadOptions();
1025
+ this.sourceTileset.options = { ...this.sourceTileset.options, ...preloadOptions };
1026
+ if (preloadOptions.headers) {
1027
+ this.sourceTileset.loadOptions.fetch = {
1028
+ ...this.sourceTileset.loadOptions.fetch,
1029
+ headers: preloadOptions.headers
1030
+ };
1031
+ console.log('Authorization Bearer token has been updated'); // eslint-disable-line no-undef, no-console
1032
+ }
1033
+ }
1034
+ /** Do calculations of all tiles and tiles with "ADD" type of refinement.
1035
+ * @param tile
1036
+ */
1037
+ _checkAddRefinementTypeForTile(tile) {
1038
+ const ADD_TILE_REFINEMENT = 1;
1039
+ if (tile.refine === ADD_TILE_REFINEMENT) {
1040
+ this.refinementCounter.tilesWithAddRefineCount += 1;
1041
+ console.warn('This tile uses "ADD" type of refinement'); // eslint-disable-line
1042
+ }
1043
+ this.refinementCounter.tilesCount += 1;
1044
+ }
1045
+ /**
1046
+ * Check if the tile's content format is supported by the converter
1047
+ * @param sourceRootTile
1048
+ * @returns
1049
+ */
1050
+ isContentSupported(sourceRootTile) {
1051
+ return ['b3dm', 'glTF'].includes(sourceRootTile?.content?.type);
1052
+ }
1053
+ async loadWorkers() {
1054
+ console.log(`Loading workers source...`); // eslint-disable-line no-undef, no-console
1055
+ if (this.options.draco) {
1056
+ const url = (0, worker_utils_1.getWorkerURL)(draco_1.DracoWriterWorker, { ...(0, core_1.getLoaderOptions)() });
1057
+ const sourceResponse = await (0, core_1.fetchFile)(url);
1058
+ const source = await sourceResponse.text();
1059
+ this.workerSource.draco = source;
1060
+ }
1061
+ if (this.generateTextures) {
1062
+ const url = (0, worker_utils_1.getWorkerURL)(textures_1.KTX2BasisWriterWorker, { ...(0, core_1.getLoaderOptions)() });
1063
+ const sourceResponse = await (0, core_1.fetchFile)(url);
1064
+ const source = await sourceResponse.text();
1065
+ this.workerSource.ktx2 = source;
1066
+ }
1067
+ const i3sAttributesWorkerUrl = (0, worker_utils_1.getWorkerURL)(i3s_attributes_worker_1.I3SAttributesWorker, { ...(0, core_1.getLoaderOptions)() });
1068
+ const sourceResponse = await (0, core_1.fetchFile)(i3sAttributesWorkerUrl);
1069
+ const source = await sourceResponse.text();
1070
+ this.workerSource.I3SAttributes = source;
1071
+ console.log(`Loading workers source completed!`); // eslint-disable-line no-undef, no-console
1072
+ }
1073
+ }
1074
+ exports.default = I3SConverter;