@loaders.gl/tile-converter 4.0.0-alpha.5 → 4.0.0-alpha.7

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 (368) hide show
  1. package/bin/converter.js +1 -1
  2. package/dist/3d-tiles-attributes-worker.d.ts +28 -0
  3. package/dist/3d-tiles-attributes-worker.d.ts.map +1 -0
  4. package/dist/3d-tiles-attributes-worker.js +3 -0
  5. package/dist/3d-tiles-attributes-worker.js.map +7 -0
  6. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts +13 -1
  7. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts.map +1 -1
  8. package/dist/3d-tiles-converter/3d-tiles-converter.js +274 -233
  9. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts +9 -16
  10. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts.map +1 -1
  11. package/dist/3d-tiles-converter/helpers/b3dm-converter.js +256 -246
  12. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +22 -9
  13. package/dist/3d-tiles-converter/helpers/texture-atlas.js +47 -28
  14. package/dist/3d-tiles-converter/json-templates/tileset.js +38 -35
  15. package/dist/bundle.js +2 -2
  16. package/dist/constants.d.ts +2 -0
  17. package/dist/constants.d.ts.map +1 -0
  18. package/dist/constants.js +4 -0
  19. package/dist/converter-cli.d.ts +2 -0
  20. package/dist/converter-cli.d.ts.map +1 -0
  21. package/dist/converter-cli.js +280 -0
  22. package/dist/converter.min.js +185 -190
  23. package/dist/deps-installer/deps-installer.d.ts +11 -3
  24. package/dist/deps-installer/deps-installer.d.ts.map +1 -1
  25. package/dist/deps-installer/deps-installer.js +59 -18
  26. package/dist/dist.min.js +15153 -37895
  27. package/dist/es5/3d-tiles-attributes-worker.js +25 -0
  28. package/dist/es5/3d-tiles-attributes-worker.js.map +1 -0
  29. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js +467 -0
  30. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js.map +1 -0
  31. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js +293 -0
  32. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -0
  33. package/dist/es5/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +18 -0
  34. package/dist/es5/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js.map +1 -0
  35. package/dist/es5/3d-tiles-converter/helpers/texture-atlas.js +33 -0
  36. package/dist/es5/3d-tiles-converter/helpers/texture-atlas.js.map +1 -0
  37. package/dist/es5/3d-tiles-converter/json-templates/tileset.js +61 -0
  38. package/dist/es5/3d-tiles-converter/json-templates/tileset.js.map +1 -0
  39. package/dist/es5/bundle.js +6 -0
  40. package/dist/es5/bundle.js.map +1 -0
  41. package/dist/es5/constants.js +9 -0
  42. package/dist/es5/constants.js.map +1 -0
  43. package/dist/es5/converter-cli.js +289 -0
  44. package/dist/es5/converter-cli.js.map +1 -0
  45. package/dist/es5/deps-installer/deps-installer.js +123 -0
  46. package/dist/es5/deps-installer/deps-installer.js.map +1 -0
  47. package/dist/es5/i3s-attributes-worker.js +25 -0
  48. package/dist/es5/i3s-attributes-worker.js.map +1 -0
  49. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js +116 -0
  50. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js.map +1 -0
  51. package/dist/es5/i3s-converter/helpers/coordinate-converter.js +90 -0
  52. package/dist/es5/i3s-converter/helpers/coordinate-converter.js.map +1 -0
  53. package/dist/es5/i3s-converter/helpers/create-scene-server-path.js +41 -0
  54. package/dist/es5/i3s-converter/helpers/create-scene-server-path.js.map +1 -0
  55. package/dist/es5/i3s-converter/helpers/feature-attributes.js +174 -0
  56. package/dist/es5/i3s-converter/helpers/feature-attributes.js.map +1 -0
  57. package/dist/es5/i3s-converter/helpers/geometry-attributes.js +213 -0
  58. package/dist/es5/i3s-converter/helpers/geometry-attributes.js.map +1 -0
  59. package/dist/es5/i3s-converter/helpers/geometry-converter.js +1181 -0
  60. package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -0
  61. package/dist/es5/i3s-converter/helpers/gltf-attributes.js +80 -0
  62. package/dist/es5/i3s-converter/helpers/gltf-attributes.js.map +1 -0
  63. package/dist/es5/i3s-converter/helpers/node-debug.js +76 -0
  64. package/dist/es5/i3s-converter/helpers/node-debug.js.map +1 -0
  65. package/dist/es5/i3s-converter/helpers/node-index-document.js +492 -0
  66. package/dist/es5/i3s-converter/helpers/node-index-document.js.map +1 -0
  67. package/dist/es5/i3s-converter/helpers/node-pages.js +519 -0
  68. package/dist/es5/i3s-converter/helpers/node-pages.js.map +1 -0
  69. package/dist/es5/i3s-converter/i3s-converter.js +1512 -0
  70. package/dist/es5/i3s-converter/i3s-converter.js.map +1 -0
  71. package/dist/es5/i3s-converter/json-templates/geometry-definitions.js +107 -0
  72. package/dist/es5/i3s-converter/json-templates/geometry-definitions.js.map +1 -0
  73. package/dist/es5/i3s-converter/json-templates/layers.js +163 -0
  74. package/dist/es5/i3s-converter/json-templates/layers.js.map +1 -0
  75. package/dist/es5/i3s-converter/json-templates/metadata.js +31 -0
  76. package/dist/es5/i3s-converter/json-templates/metadata.js.map +1 -0
  77. package/dist/es5/i3s-converter/json-templates/node.js +99 -0
  78. package/dist/es5/i3s-converter/json-templates/node.js.map +1 -0
  79. package/dist/es5/i3s-converter/json-templates/scene-server.js +39 -0
  80. package/dist/es5/i3s-converter/json-templates/scene-server.js.map +1 -0
  81. package/dist/es5/i3s-converter/json-templates/shared-resources.js +173 -0
  82. package/dist/es5/i3s-converter/json-templates/shared-resources.js.map +1 -0
  83. package/dist/es5/i3s-converter/json-templates/store.js +107 -0
  84. package/dist/es5/i3s-converter/json-templates/store.js.map +1 -0
  85. package/dist/es5/i3s-converter/types.js +2 -0
  86. package/dist/es5/i3s-converter/types.js.map +1 -0
  87. package/dist/es5/i3s-server/app.js +18 -0
  88. package/dist/es5/i3s-server/app.js.map +1 -0
  89. package/dist/es5/i3s-server/controllers/index-controller.js +55 -0
  90. package/dist/es5/i3s-server/controllers/index-controller.js.map +1 -0
  91. package/dist/es5/i3s-server/routes/index.js +37 -0
  92. package/dist/es5/i3s-server/routes/index.js.map +1 -0
  93. package/dist/es5/index.js +21 -0
  94. package/dist/es5/index.js.map +1 -0
  95. package/dist/es5/lib/utils/compress-util.js +346 -0
  96. package/dist/es5/lib/utils/compress-util.js.map +1 -0
  97. package/dist/es5/lib/utils/file-utils.js +208 -0
  98. package/dist/es5/lib/utils/file-utils.js.map +1 -0
  99. package/dist/es5/lib/utils/geometry-utils.js +15 -0
  100. package/dist/es5/lib/utils/geometry-utils.js.map +1 -0
  101. package/dist/es5/lib/utils/lod-conversion-utils.js +44 -0
  102. package/dist/es5/lib/utils/lod-conversion-utils.js.map +1 -0
  103. package/dist/es5/lib/utils/queue.js +47 -0
  104. package/dist/es5/lib/utils/queue.js.map +1 -0
  105. package/dist/es5/lib/utils/statistic-utills.d.ts +25 -0
  106. package/dist/es5/lib/utils/statistic-utills.js +147 -0
  107. package/dist/es5/lib/utils/statistic-utills.js.map +1 -0
  108. package/dist/es5/lib/utils/write-queue.js +214 -0
  109. package/dist/es5/lib/utils/write-queue.js.map +1 -0
  110. package/dist/es5/pgm-loader.js +41 -0
  111. package/dist/es5/pgm-loader.js.map +1 -0
  112. package/dist/es5/workers/3d-tiles-attributes-worker.js +28 -0
  113. package/dist/es5/workers/3d-tiles-attributes-worker.js.map +1 -0
  114. package/dist/es5/workers/i3s-attributes-worker.js +30 -0
  115. package/dist/es5/workers/i3s-attributes-worker.js.map +1 -0
  116. package/dist/esm/3d-tiles-attributes-worker.js +16 -0
  117. package/dist/esm/3d-tiles-attributes-worker.js.map +1 -0
  118. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js +245 -0
  119. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js.map +1 -0
  120. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js +218 -0
  121. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -0
  122. package/dist/esm/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +10 -0
  123. package/dist/esm/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js.map +1 -0
  124. package/dist/esm/3d-tiles-converter/helpers/texture-atlas.js +27 -0
  125. package/dist/esm/3d-tiles-converter/helpers/texture-atlas.js.map +1 -0
  126. package/dist/esm/3d-tiles-converter/json-templates/tileset.js +37 -0
  127. package/dist/esm/3d-tiles-converter/json-templates/tileset.js.map +1 -0
  128. package/dist/esm/bundle.js +4 -0
  129. package/dist/esm/bundle.js.map +1 -0
  130. package/dist/esm/constants.js +2 -0
  131. package/dist/esm/constants.js.map +1 -0
  132. package/dist/esm/converter-cli.js +232 -0
  133. package/dist/esm/converter-cli.js.map +1 -0
  134. package/dist/esm/deps-installer/deps-installer.js +44 -0
  135. package/dist/esm/deps-installer/deps-installer.js.map +1 -0
  136. package/dist/esm/i3s-attributes-worker.js +16 -0
  137. package/dist/esm/i3s-attributes-worker.js.map +1 -0
  138. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js +105 -0
  139. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js.map +1 -0
  140. package/dist/esm/i3s-converter/helpers/coordinate-converter.js +80 -0
  141. package/dist/esm/i3s-converter/helpers/coordinate-converter.js.map +1 -0
  142. package/dist/esm/i3s-converter/helpers/create-scene-server-path.js +16 -0
  143. package/dist/esm/i3s-converter/helpers/create-scene-server-path.js.map +1 -0
  144. package/dist/esm/i3s-converter/helpers/feature-attributes.js +147 -0
  145. package/dist/esm/i3s-converter/helpers/feature-attributes.js.map +1 -0
  146. package/dist/esm/i3s-converter/helpers/geometry-attributes.js +190 -0
  147. package/dist/esm/i3s-converter/helpers/geometry-attributes.js.map +1 -0
  148. package/dist/esm/i3s-converter/helpers/geometry-converter.js +895 -0
  149. package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -0
  150. package/dist/esm/i3s-converter/helpers/gltf-attributes.js +73 -0
  151. package/dist/esm/i3s-converter/helpers/gltf-attributes.js.map +1 -0
  152. package/dist/esm/i3s-converter/helpers/node-debug.js +72 -0
  153. package/dist/esm/i3s-converter/helpers/node-debug.js.map +1 -0
  154. package/dist/esm/i3s-converter/helpers/node-index-document.js +188 -0
  155. package/dist/esm/i3s-converter/helpers/node-index-document.js.map +1 -0
  156. package/dist/esm/i3s-converter/helpers/node-pages.js +206 -0
  157. package/dist/esm/i3s-converter/helpers/node-pages.js.map +1 -0
  158. package/dist/esm/i3s-converter/i3s-converter.js +764 -0
  159. package/dist/esm/i3s-converter/i3s-converter.js.map +1 -0
  160. package/dist/esm/i3s-converter/json-templates/geometry-definitions.js +89 -0
  161. package/dist/esm/i3s-converter/json-templates/geometry-definitions.js.map +1 -0
  162. package/dist/esm/i3s-converter/json-templates/layers.js +133 -0
  163. package/dist/esm/i3s-converter/json-templates/layers.js.map +1 -0
  164. package/dist/esm/i3s-converter/json-templates/metadata.js +22 -0
  165. package/dist/esm/i3s-converter/json-templates/metadata.js.map +1 -0
  166. package/dist/esm/i3s-converter/json-templates/node.js +80 -0
  167. package/dist/esm/i3s-converter/json-templates/node.js.map +1 -0
  168. package/dist/esm/i3s-converter/json-templates/scene-server.js +28 -0
  169. package/dist/esm/i3s-converter/json-templates/scene-server.js.map +1 -0
  170. package/dist/esm/i3s-converter/json-templates/shared-resources.js +123 -0
  171. package/dist/esm/i3s-converter/json-templates/shared-resources.js.map +1 -0
  172. package/dist/esm/i3s-converter/json-templates/store.js +98 -0
  173. package/dist/esm/i3s-converter/json-templates/store.js.map +1 -0
  174. package/dist/esm/i3s-converter/types.js +2 -0
  175. package/dist/esm/i3s-converter/types.js.map +1 -0
  176. package/dist/esm/i3s-server/app.js +16 -0
  177. package/dist/esm/i3s-server/app.js.map +1 -0
  178. package/dist/esm/i3s-server/bin/www +102 -0
  179. package/dist/esm/i3s-server/certs/cert.pem +19 -0
  180. package/dist/esm/i3s-server/certs/key.pem +27 -0
  181. package/dist/esm/i3s-server/controllers/index-controller.js +24 -0
  182. package/dist/esm/i3s-server/controllers/index-controller.js.map +1 -0
  183. package/dist/esm/i3s-server/routes/index.js +16 -0
  184. package/dist/esm/i3s-server/routes/index.js.map +1 -0
  185. package/dist/esm/index.js +3 -0
  186. package/dist/esm/index.js.map +1 -0
  187. package/dist/esm/lib/utils/compress-util.js +168 -0
  188. package/dist/esm/lib/utils/compress-util.js.map +1 -0
  189. package/dist/esm/lib/utils/file-utils.js +87 -0
  190. package/dist/esm/lib/utils/file-utils.js.map +1 -0
  191. package/dist/esm/lib/utils/geometry-utils.js +8 -0
  192. package/dist/esm/lib/utils/geometry-utils.js.map +1 -0
  193. package/dist/esm/lib/utils/lod-conversion-utils.js +37 -0
  194. package/dist/esm/lib/utils/lod-conversion-utils.js.map +1 -0
  195. package/dist/esm/lib/utils/queue.js +15 -0
  196. package/dist/esm/lib/utils/queue.js.map +1 -0
  197. package/dist/esm/lib/utils/statistic-utills.d.ts +25 -0
  198. package/dist/esm/lib/utils/statistic-utills.js +62 -0
  199. package/dist/esm/lib/utils/statistic-utills.js.map +1 -0
  200. package/dist/esm/lib/utils/write-queue.js +85 -0
  201. package/dist/esm/lib/utils/write-queue.js.map +1 -0
  202. package/dist/esm/pgm-loader.js +15 -0
  203. package/dist/esm/pgm-loader.js.map +1 -0
  204. package/dist/esm/workers/3d-tiles-attributes-worker.js +8 -0
  205. package/dist/esm/workers/3d-tiles-attributes-worker.js.map +1 -0
  206. package/dist/esm/workers/i3s-attributes-worker.js +7 -0
  207. package/dist/esm/workers/i3s-attributes-worker.js.map +1 -0
  208. package/dist/i3s-attributes-worker.d.ts +45 -0
  209. package/dist/i3s-attributes-worker.d.ts.map +1 -0
  210. package/dist/i3s-attributes-worker.js +9 -0
  211. package/dist/i3s-attributes-worker.js.map +7 -0
  212. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts +13 -0
  213. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts.map +1 -0
  214. package/dist/i3s-converter/helpers/batch-ids-extensions.js +141 -0
  215. package/dist/i3s-converter/helpers/coordinate-converter.d.ts +9 -9
  216. package/dist/i3s-converter/helpers/coordinate-converter.d.ts.map +1 -1
  217. package/dist/i3s-converter/helpers/coordinate-converter.js +118 -72
  218. package/dist/i3s-converter/helpers/create-scene-server-path.d.ts +5 -5
  219. package/dist/i3s-converter/helpers/create-scene-server-path.d.ts.map +1 -1
  220. package/dist/i3s-converter/helpers/create-scene-server-path.js +27 -15
  221. package/dist/i3s-converter/helpers/feature-attributes.d.ts +56 -0
  222. package/dist/i3s-converter/helpers/feature-attributes.d.ts.map +1 -0
  223. package/dist/i3s-converter/helpers/feature-attributes.js +216 -0
  224. package/dist/i3s-converter/helpers/geometry-attributes.d.ts +4 -19
  225. package/dist/i3s-converter/helpers/geometry-attributes.d.ts.map +1 -1
  226. package/dist/i3s-converter/helpers/geometry-attributes.js +188 -185
  227. package/dist/i3s-converter/helpers/geometry-converter.d.ts +36 -39
  228. package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -1
  229. package/dist/i3s-converter/helpers/geometry-converter.js +1150 -689
  230. package/dist/i3s-converter/helpers/gltf-attributes.d.ts +9 -0
  231. package/dist/i3s-converter/helpers/gltf-attributes.d.ts.map +1 -0
  232. package/dist/i3s-converter/helpers/gltf-attributes.js +85 -0
  233. package/dist/i3s-converter/helpers/node-debug.d.ts +7 -1
  234. package/dist/i3s-converter/helpers/node-debug.d.ts.map +1 -1
  235. package/dist/i3s-converter/helpers/node-debug.js +106 -72
  236. package/dist/i3s-converter/helpers/node-index-document.d.ts +95 -0
  237. package/dist/i3s-converter/helpers/node-index-document.d.ts.map +1 -0
  238. package/dist/i3s-converter/helpers/node-index-document.js +250 -0
  239. package/dist/i3s-converter/helpers/node-pages.d.ts +81 -41
  240. package/dist/i3s-converter/helpers/node-pages.d.ts.map +1 -1
  241. package/dist/i3s-converter/helpers/node-pages.js +313 -144
  242. package/dist/i3s-converter/i3s-converter.d.ts +60 -113
  243. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
  244. package/dist/i3s-converter/i3s-converter.js +858 -951
  245. package/dist/i3s-converter/json-templates/geometry-definitions.d.ts +7 -0
  246. package/dist/i3s-converter/json-templates/geometry-definitions.d.ts.map +1 -0
  247. package/dist/i3s-converter/json-templates/geometry-definitions.js +87 -0
  248. package/dist/i3s-converter/json-templates/layers.d.ts +5 -30
  249. package/dist/i3s-converter/json-templates/layers.d.ts.map +1 -1
  250. package/dist/i3s-converter/json-templates/layers.js +132 -194
  251. package/dist/i3s-converter/json-templates/metadata.js +24 -21
  252. package/dist/i3s-converter/json-templates/node.js +82 -77
  253. package/dist/i3s-converter/json-templates/scene-server.js +30 -27
  254. package/dist/i3s-converter/json-templates/shared-resources.js +116 -122
  255. package/dist/i3s-converter/json-templates/store.js +100 -95
  256. package/dist/i3s-converter/types.d.ts +137 -6
  257. package/dist/i3s-converter/types.d.ts.map +1 -1
  258. package/dist/i3s-converter/types.js +2 -2
  259. package/dist/i3s-server/app.js +2 -9
  260. package/dist/i3s-server/controllers/index-controller.js +16 -24
  261. package/dist/i3s-server/routes/index.js +11 -15
  262. package/dist/index.d.ts +0 -2
  263. package/dist/index.d.ts.map +1 -1
  264. package/dist/index.js +10 -5
  265. package/dist/lib/utils/compress-util.d.ts +12 -20
  266. package/dist/lib/utils/compress-util.d.ts.map +1 -1
  267. package/dist/lib/utils/compress-util.js +238 -160
  268. package/dist/lib/utils/file-utils.d.ts +22 -14
  269. package/dist/lib/utils/file-utils.d.ts.map +1 -1
  270. package/dist/lib/utils/file-utils.js +133 -36
  271. package/dist/lib/utils/geometry-utils.d.ts +9 -0
  272. package/dist/lib/utils/geometry-utils.d.ts.map +1 -0
  273. package/dist/lib/utils/geometry-utils.js +18 -0
  274. package/dist/lib/utils/lod-conversion-utils.d.ts +21 -12
  275. package/dist/lib/utils/lod-conversion-utils.d.ts.map +1 -1
  276. package/dist/lib/utils/lod-conversion-utils.js +72 -39
  277. package/dist/lib/utils/queue.d.ts +7 -0
  278. package/dist/lib/utils/queue.d.ts.map +1 -0
  279. package/dist/lib/utils/queue.js +18 -0
  280. package/dist/lib/utils/statistic-utills.d.ts +3 -25
  281. package/dist/lib/utils/statistic-utills.d.ts.map +1 -1
  282. package/dist/lib/utils/statistic-utills.js +58 -67
  283. package/dist/lib/utils/write-queue.d.ts +39 -0
  284. package/dist/lib/utils/write-queue.d.ts.map +1 -0
  285. package/dist/lib/utils/write-queue.js +80 -0
  286. package/dist/pgm-loader.d.ts.map +1 -1
  287. package/dist/pgm-loader.js +23 -14
  288. package/dist/workers/3d-tiles-attributes-worker.d.ts +2 -0
  289. package/dist/workers/3d-tiles-attributes-worker.d.ts.map +1 -0
  290. package/dist/workers/3d-tiles-attributes-worker.js +9 -0
  291. package/dist/workers/i3s-attributes-worker.d.ts +2 -0
  292. package/dist/workers/i3s-attributes-worker.d.ts.map +1 -0
  293. package/dist/workers/i3s-attributes-worker.js +5 -0
  294. package/package.json +32 -24
  295. package/src/3d-tiles-attributes-worker.ts +43 -0
  296. package/src/3d-tiles-converter/3d-tiles-converter.ts +102 -40
  297. package/src/3d-tiles-converter/helpers/b3dm-converter.ts +39 -44
  298. package/src/constants.ts +2 -0
  299. package/src/converter-cli.ts +370 -0
  300. package/src/deps-installer/deps-installer.ts +71 -0
  301. package/src/i3s-attributes-worker.ts +59 -0
  302. package/src/i3s-converter/helpers/batch-ids-extensions.ts +205 -0
  303. package/src/i3s-converter/helpers/coordinate-converter.ts +33 -26
  304. package/src/i3s-converter/helpers/create-scene-server-path.ts +9 -5
  305. package/src/i3s-converter/helpers/feature-attributes.ts +247 -0
  306. package/src/i3s-converter/helpers/geometry-attributes.ts +98 -47
  307. package/src/i3s-converter/helpers/geometry-converter.ts +1635 -0
  308. package/src/i3s-converter/helpers/gltf-attributes.ts +100 -0
  309. package/src/i3s-converter/helpers/node-debug.ts +68 -16
  310. package/src/i3s-converter/helpers/node-index-document.ts +315 -0
  311. package/src/i3s-converter/helpers/node-pages.ts +222 -101
  312. package/src/i3s-converter/i3s-converter.ts +408 -555
  313. package/src/i3s-converter/json-templates/geometry-definitions.ts +83 -0
  314. package/src/i3s-converter/json-templates/layers.ts +27 -91
  315. package/src/i3s-converter/json-templates/shared-resources.ts +3 -3
  316. package/src/i3s-converter/types.ts +156 -5
  317. package/src/index.ts +0 -4
  318. package/src/lib/utils/{compress-util.js → compress-util.ts} +105 -18
  319. package/src/lib/utils/file-utils.ts +139 -0
  320. package/src/lib/utils/geometry-utils.ts +14 -0
  321. package/src/lib/utils/{lod-conversion-utils.js → lod-conversion-utils.ts} +27 -5
  322. package/src/lib/utils/queue.ts +17 -0
  323. package/src/lib/utils/write-queue.ts +110 -0
  324. package/src/pgm-loader.ts +2 -2
  325. package/src/workers/3d-tiles-attributes-worker.ts +6 -0
  326. package/src/workers/i3s-attributes-worker.ts +7 -0
  327. package/dist/3d-tiles-converter/3d-tiles-converter.js.map +0 -1
  328. package/dist/3d-tiles-converter/helpers/b3dm-converter.js.map +0 -1
  329. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js.map +0 -1
  330. package/dist/3d-tiles-converter/helpers/texture-atlas.js.map +0 -1
  331. package/dist/3d-tiles-converter/json-templates/tileset.js.map +0 -1
  332. package/dist/bundle.js.map +0 -1
  333. package/dist/deps-installer/deps-installer.js.map +0 -1
  334. package/dist/i3s-converter/helpers/coordinate-converter.js.map +0 -1
  335. package/dist/i3s-converter/helpers/create-scene-server-path.js.map +0 -1
  336. package/dist/i3s-converter/helpers/geometry-attributes.js.map +0 -1
  337. package/dist/i3s-converter/helpers/geometry-converter.js.map +0 -1
  338. package/dist/i3s-converter/helpers/node-debug.js.map +0 -1
  339. package/dist/i3s-converter/helpers/node-pages.js.map +0 -1
  340. package/dist/i3s-converter/i3s-converter.js.map +0 -1
  341. package/dist/i3s-converter/json-templates/layers.js.map +0 -1
  342. package/dist/i3s-converter/json-templates/metadata.js.map +0 -1
  343. package/dist/i3s-converter/json-templates/node.js.map +0 -1
  344. package/dist/i3s-converter/json-templates/scene-server.js.map +0 -1
  345. package/dist/i3s-converter/json-templates/shared-resources.js.map +0 -1
  346. package/dist/i3s-converter/json-templates/store.js.map +0 -1
  347. package/dist/i3s-converter/types.js.map +0 -1
  348. package/dist/i3s-server/app.js.map +0 -1
  349. package/dist/i3s-server/controllers/index-controller.js.map +0 -1
  350. package/dist/i3s-server/routes/index.js.map +0 -1
  351. package/dist/index.js.map +0 -1
  352. package/dist/lib/utils/compress-util.js.map +0 -1
  353. package/dist/lib/utils/file-utils.js.map +0 -1
  354. package/dist/lib/utils/lod-conversion-utils.js.map +0 -1
  355. package/dist/lib/utils/statistic-utills.js.map +0 -1
  356. package/dist/pgm-loader.js.map +0 -1
  357. package/src/deps-installer/deps-installer.d.ts +0 -10
  358. package/src/deps-installer/deps-installer.js +0 -22
  359. package/src/i3s-converter/helpers/geometry-converter.d.ts +0 -44
  360. package/src/i3s-converter/helpers/geometry-converter.js +0 -992
  361. package/src/lib/utils/compress-util.d.ts +0 -53
  362. package/src/lib/utils/file-utils.d.ts +0 -43
  363. package/src/lib/utils/file-utils.js +0 -38
  364. package/src/lib/utils/lod-conversion-utils.d.ts +0 -32
  365. /package/dist/{i3s-server → es5/i3s-server}/bin/www +0 -0
  366. /package/dist/{i3s-server → es5/i3s-server}/certs/cert.pem +0 -0
  367. /package/dist/{i3s-server → es5/i3s-server}/certs/key.pem +0 -0
  368. /package/src/lib/utils/{statistic-utills.js → statistic-utills.ts} +0 -0
@@ -1,23 +1,15 @@
1
- import type {Tile3D, Tileset3DProps} from '@loaders.gl/tiles';
2
- import type {BatchTableJson, B3DMContent} from '@loaders.gl/3d-tiles';
1
+ // loaders.gl, MIT license
3
2
 
3
+ import type {Tileset3DProps} from '@loaders.gl/tiles';
4
+ import type {FeatureTableJson} from '@loaders.gl/3d-tiles';
5
+ import type {WriteQueueItem} from '../lib/utils/write-queue';
4
6
  import type {
5
- AttributeStorageInfo,
6
7
  SceneLayer3D,
7
8
  BoundingVolumes,
8
- Node3DIndexDocument,
9
- NodeReference,
10
9
  MaxScreenThresholdSQ,
11
- NodeInPage,
12
- LodSelection,
13
- SharedResources,
14
- Attribute,
15
- ESRIField,
16
- Field,
17
- PopupInfo,
18
- FieldInfo
10
+ NodeInPage
19
11
  } from '@loaders.gl/i3s';
20
- import {load, encode} from '@loaders.gl/core';
12
+ import {load, encode, fetchFile, getLoaderOptions, isBrowser} from '@loaders.gl/core';
21
13
  import {Tileset3D} from '@loaders.gl/tiles';
22
14
  import {CesiumIonLoader, Tiles3DLoader} from '@loaders.gl/3d-tiles';
23
15
  import {Geoid} from '@math.gl/geoid';
@@ -28,44 +20,56 @@ import transform from 'json-map-transform';
28
20
  import md5 from 'md5';
29
21
 
30
22
  import NodePages from './helpers/node-pages';
31
- import {writeFile, removeDir, writeFileForSlpk} from '../lib/utils/file-utils';
23
+ import {writeFile, removeDir, writeFileForSlpk, removeFile} from '../lib/utils/file-utils';
32
24
  import {
25
+ compressFileWithGzip,
33
26
  compressWithChildProcess
34
27
  // generateHash128FromZip,
35
28
  // addFileToZip
36
29
  } from '../lib/utils/compress-util';
37
30
  import {calculateFilesSize, timeConverter} from '../lib/utils/statistic-utills';
38
- import convertB3dmToI3sGeometry from './helpers/geometry-converter';
31
+ import convertB3dmToI3sGeometry, {getPropertyTable} from './helpers/geometry-converter';
39
32
  import {
40
33
  createBoundingVolumes,
41
- convertCommonToI3SExtentCoordinate
34
+ convertBoundingVolumeToI3SFullExtent
42
35
  } from './helpers/coordinate-converter';
43
36
  import {createSceneServerPath} from './helpers/create-scene-server-path';
44
37
  import {convertGeometricErrorToScreenThreshold} from '../lib/utils/lod-conversion-utils';
45
38
  import {PGMLoader} from '../pgm-loader';
46
39
 
47
40
  import {LAYERS as layersTemplate} from './json-templates/layers';
48
- import {NODE as nodeTemplate} from './json-templates/node';
41
+ import {GEOMETRY_DEFINITION as geometryDefinitionTemlate} from './json-templates/geometry-definitions';
49
42
  import {SHARED_RESOURCES as sharedResourcesTemplate} from './json-templates/shared-resources';
50
43
  import {validateNodeBoundingVolumes} from './helpers/node-debug';
51
- import TileHeader from '@loaders.gl/tiles/src/tileset/tile-3d';
52
- import {KTX2BasisUniversalTextureWriter} from '@loaders.gl/textures';
44
+ // loaders.gl, MIT license
45
+
46
+ import {Tile3D} from '@loaders.gl/tiles';
47
+ import {KTX2BasisWriterWorker} from '@loaders.gl/textures';
53
48
  import {LoaderWithParser} from '@loaders.gl/loader-utils';
54
49
  import {I3SMaterialDefinition, TextureSetDefinitionFormats} from '@loaders.gl/i3s/src/types';
55
50
  import {ImageWriter} from '@loaders.gl/images';
56
51
  import {GLTFImagePostprocessed} from '@loaders.gl/gltf';
57
- import {I3SConvertedResources} from './types';
52
+ import {I3SConvertedResources, SharedResourcesArrays} from './types';
53
+ import {getWorkerURL, WorkerFarm} from '@loaders.gl/worker-utils';
54
+ import {DracoWriterWorker} from '@loaders.gl/draco';
55
+ import WriteQueue from '../lib/utils/write-queue';
56
+ import {I3SAttributesWorker} from '../i3s-attributes-worker';
57
+ import {BROWSER_ERROR_MESSAGE} from '../constants';
58
+ import {
59
+ createdStorageAttribute,
60
+ createFieldAttribute,
61
+ createPopupInfo,
62
+ getAttributeType,
63
+ getFieldAttributeType
64
+ } from './helpers/feature-attributes';
65
+ import {NodeIndexDocument} from './helpers/node-index-document';
58
66
 
59
67
  const ION_DEFAULT_TOKEN =
60
- process.env.IonToken || // eslint-disable-line
68
+ process.env?.IonToken || // eslint-disable-line
61
69
  'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlYWMxMzcyYy0zZjJkLTQwODctODNlNi01MDRkZmMzMjIxOWIiLCJpZCI6OTYyMCwic2NvcGVzIjpbImFzbCIsImFzciIsImdjIl0sImlhdCI6MTU2Mjg2NjI3M30.1FNiClUyk00YH_nWfSGpiQAjR5V2OvREDq1PJ5QMjWQ'; // eslint-disable-line
62
70
  const HARDCODED_NODES_PER_PAGE = 64;
63
71
  const _3D_TILES = '3DTILES';
64
72
  const _3D_OBJECT_LAYER_TYPE = '3DObject';
65
- const STRING_TYPE = 'string';
66
- const SHORT_INT_TYPE = 'Int32';
67
- const DOUBLE_TYPE = 'double';
68
- const OBJECT_ID_TYPE = 'OBJECTID';
69
73
  const REFRESH_TOKEN_TIMEOUT = 1800; // 30 minutes in seconds
70
74
  const CESIUM_DATASET_PREFIX = 'https://';
71
75
  // const FS_FILE_TOO_LARGE = 'ERR_FS_FILE_TOO_LARGE';
@@ -75,11 +79,12 @@ const CESIUM_DATASET_PREFIX = 'https://';
75
79
  */
76
80
  export default class I3SConverter {
77
81
  nodePages: NodePages;
78
- fileMap: {[key: string]: string};
79
82
  options: any;
80
83
  layers0Path: string;
81
- materialMap: Map<any, any>;
84
+ materialMap: Map<string, number>;
82
85
  materialDefinitions: I3SMaterialDefinition[];
86
+ geometryMap: Map<string, number>;
87
+ geometryConfigs: {hasTexture: boolean; hasUvRegions: boolean}[];
83
88
  vertexCounter: number;
84
89
  layers0: SceneLayer3D | null;
85
90
  featuresHashArray: string[];
@@ -96,14 +101,19 @@ export default class I3SConverter {
96
101
  Loader: LoaderWithParser = Tiles3DLoader;
97
102
  generateTextures: boolean;
98
103
  generateBoundingVolumes: boolean;
104
+ layersHasTexture: boolean;
105
+ workerSource: {[key: string]: string} = {};
106
+ writeQueue: WriteQueue<WriteQueueItem> = new WriteQueue();
107
+ compressList: string[] | null = null;
99
108
 
100
109
  constructor() {
101
- this.nodePages = new NodePages(writeFile, HARDCODED_NODES_PER_PAGE);
102
- this.fileMap = {};
110
+ this.nodePages = new NodePages(writeFile, HARDCODED_NODES_PER_PAGE, this);
103
111
  this.options = {};
104
112
  this.layers0Path = '';
105
113
  this.materialMap = new Map();
106
114
  this.materialDefinitions = [];
115
+ this.geometryMap = new Map();
116
+ this.geometryConfigs = [];
107
117
  this.vertexCounter = 0;
108
118
  this.layers0 = null;
109
119
  this.featuresHashArray = [];
@@ -114,6 +124,8 @@ export default class I3SConverter {
114
124
  this.validate = false;
115
125
  this.generateTextures = false;
116
126
  this.generateBoundingVolumes = false;
127
+ this.layersHasTexture = false;
128
+ this.compressList = null;
117
129
  }
118
130
 
119
131
  /**
@@ -129,6 +141,9 @@ export default class I3SConverter {
129
141
  * @param options.token Token for Cesium ION tilesets authentication
130
142
  * @param options.draco Generate I3S 1.7 draco compressed geometries
131
143
  * @param options.validate -enable validation
144
+ * @param options.generateTextures - generate alternative type of textures (to have non-compressed jpeg/png and compressed ktx2)
145
+ * @param options.generateBoundingVolumes - generate bounding volumes from vertices coordinates instead of source tiles bounding volumes
146
+ * @param options.instantNodeWriting - Keep created 3DNodeIndexDocument files on disk instead of memory. This option reduce memory usage but decelerates conversion speed
132
147
  */
133
148
  async convert(options: {
134
149
  inputUrl: string;
@@ -140,12 +155,16 @@ export default class I3SConverter {
140
155
  slpk?: boolean;
141
156
  token?: string;
142
157
  draco?: boolean;
158
+ mergeMaterials?: boolean;
143
159
  validate?: boolean;
144
160
  generateTextures?: boolean;
145
161
  generateBoundingVolumes?: boolean;
146
- /** @deprecated */
147
- inputType?: string;
162
+ instantNodeWriting?: boolean;
148
163
  }): Promise<any> {
164
+ if (isBrowser) {
165
+ console.log(BROWSER_ERROR_MESSAGE);
166
+ return BROWSER_ERROR_MESSAGE;
167
+ }
149
168
  this.conversionStartTime = process.hrtime();
150
169
  const {
151
170
  tilesetName,
@@ -154,19 +173,35 @@ export default class I3SConverter {
154
173
  inputUrl,
155
174
  validate,
156
175
  outputPath,
157
- draco,
176
+ draco = true,
158
177
  sevenZipExe,
159
178
  maxDepth,
160
179
  token,
161
180
  generateTextures,
162
- generateBoundingVolumes
181
+ generateBoundingVolumes,
182
+ instantNodeWriting = false,
183
+ mergeMaterials = true
163
184
  } = options;
164
- this.options = {maxDepth, slpk, sevenZipExe, egmFilePath, draco, token, inputUrl};
185
+ this.options = {
186
+ maxDepth,
187
+ slpk,
188
+ sevenZipExe,
189
+ egmFilePath,
190
+ draco,
191
+ token,
192
+ inputUrl,
193
+ instantNodeWriting,
194
+ mergeMaterials
195
+ };
196
+ this.compressList = (this.options.instantNodeWriting && []) || null;
165
197
  this.validate = Boolean(validate);
166
198
  this.Loader = inputUrl.indexOf(CESIUM_DATASET_PREFIX) !== -1 ? CesiumIonLoader : Tiles3DLoader;
167
199
  this.generateTextures = Boolean(generateTextures);
168
200
  this.generateBoundingVolumes = Boolean(generateBoundingVolumes);
169
201
 
202
+ this.writeQueue = new WriteQueue();
203
+ this.writeQueue.startListening();
204
+
170
205
  console.log('Loading egm file...'); // eslint-disable-line
171
206
  this.geoidHeightModel = await load(egmFilePath, PGMLoader);
172
207
  console.log('Loading egm file completed!'); // eslint-disable-line
@@ -175,19 +210,45 @@ export default class I3SConverter {
175
210
  this.nodePages.useWriteFunction(writeFileForSlpk);
176
211
  }
177
212
 
178
- const preloadOptions = await this._fetchPreloadOptions();
179
- const tilesetOptions: Tileset3DProps = {loadOptions: {basis: {format: 'rgba32'}}};
180
- if (preloadOptions.headers) {
181
- tilesetOptions.loadOptions!.fetch = {headers: preloadOptions.headers};
213
+ await this.loadWorkers();
214
+
215
+ try {
216
+ const preloadOptions = await this._fetchPreloadOptions();
217
+ const tilesetOptions: Tileset3DProps = {
218
+ loadOptions: {
219
+ _nodeWorkers: true,
220
+ reuseWorkers: true,
221
+ basis: {format: 'rgba32'}
222
+ // TODO - should no longer be needed with new Node workers
223
+ // 'basis-nodejs': {
224
+ // format: 'rgba32',
225
+ // workerUrl: './modules/textures/dist/basis-worker-node.js'
226
+ // },
227
+ // 'draco-nodejs': {workerUrl: './modules/draco/dist/draco-worker-node.js'}
228
+ }
229
+ };
230
+ if (preloadOptions.headers) {
231
+ tilesetOptions.loadOptions!.fetch = {headers: preloadOptions.headers};
232
+ }
233
+ Object.assign(tilesetOptions, preloadOptions);
234
+ const sourceTilesetJson = await load(inputUrl, this.Loader, tilesetOptions.loadOptions);
235
+ // console.log(tilesetJson); // eslint-disable-line
236
+ this.sourceTileset = new Tileset3D(sourceTilesetJson, tilesetOptions);
237
+
238
+ await this._createAndSaveTileset(
239
+ outputPath,
240
+ tilesetName,
241
+ sourceTilesetJson?.root?.boundingVolume?.region
242
+ );
243
+ await this._finishConversion({slpk: Boolean(slpk), outputPath, tilesetName});
244
+ return sourceTilesetJson;
245
+ } catch (error) {
246
+ throw error;
247
+ } finally {
248
+ // Clean up worker pools
249
+ const workerFarm = WorkerFarm.getWorkerFarm({});
250
+ workerFarm.destroy();
182
251
  }
183
- Object.assign(tilesetOptions, preloadOptions);
184
- const sourceTilesetJson = await load(inputUrl, this.Loader, tilesetOptions.loadOptions);
185
- // console.log(tilesetJson); // eslint-disable-line
186
- this.sourceTileset = new Tileset3D(sourceTilesetJson, tilesetOptions);
187
-
188
- await this._createAndSaveTileset(outputPath, tilesetName);
189
- await this._finishConversion({slpk: Boolean(slpk), outputPath, tilesetName});
190
- return sourceTilesetJson;
191
252
  }
192
253
 
193
254
  /**
@@ -195,7 +256,11 @@ export default class I3SConverter {
195
256
  * @param outputPath - path to save output data
196
257
  * @param tilesetName - new tileset path
197
258
  */
198
- private async _createAndSaveTileset(outputPath: string, tilesetName: string): Promise<void> {
259
+ private async _createAndSaveTileset(
260
+ outputPath: string,
261
+ tilesetName: string,
262
+ boundingVolumeRegion?: number[]
263
+ ): Promise<void> {
199
264
  const tilesetPath = join(`${outputPath}`, `${tilesetName}`);
200
265
  // Removing the tilesetPath needed to exclude erroneous files after conversion
201
266
  try {
@@ -206,30 +271,47 @@ export default class I3SConverter {
206
271
 
207
272
  this.layers0Path = join(tilesetPath, 'SceneServer', 'layers', '0');
208
273
 
209
- this._formLayers0(tilesetName);
274
+ this._formLayers0(tilesetName, boundingVolumeRegion);
210
275
 
211
276
  this.materialDefinitions = [];
212
277
  this.materialMap = new Map();
213
278
 
214
- const sourceRootTile: TileHeader = this.sourceTileset!.root!;
279
+ const sourceRootTile: Tile3D = this.sourceTileset!.root!;
215
280
  const boundingVolumes = createBoundingVolumes(sourceRootTile, this.geoidHeightModel!);
216
- const parentId = this.nodePages.push({
281
+ await this.nodePages.push({
217
282
  index: 0,
218
283
  lodThreshold: 0,
219
284
  obb: boundingVolumes.obb,
220
285
  children: []
221
286
  });
222
287
 
223
- const isCreateSlpk = this.options.slpk;
224
- const root0 = this._formRootNodeIndexDocument(boundingVolumes);
225
-
226
- await this._convertNodesTree(root0, sourceRootTile, parentId, boundingVolumes);
288
+ const rootNode = await NodeIndexDocument.createRootNode(boundingVolumes, this);
289
+ await this._convertNodesTree(rootNode, sourceRootTile);
227
290
 
228
291
  this.layers0!.materialDefinitions = this.materialDefinitions;
292
+ // @ts-ignore
293
+ this.layers0.geometryDefinitions = transform(
294
+ this.geometryConfigs.map((config) => ({
295
+ geometryConfig: {...config, draco: this.options.draco}
296
+ })),
297
+ geometryDefinitionTemlate()
298
+ );
299
+
300
+ if (this.layersHasTexture === false) {
301
+ this.layers0!.store.defaultGeometrySchema.ordering =
302
+ this.layers0!.store.defaultGeometrySchema.ordering.filter(
303
+ (attribute) => attribute !== 'uv0'
304
+ );
305
+ }
306
+
229
307
  await this._writeLayers0();
230
- createSceneServerPath(tilesetName, this.layers0, tilesetPath);
231
- await this._writeNodeIndexDocument(root0, 'root', join(this.layers0Path, 'nodes', 'root'));
232
- await this.nodePages.save(this.layers0Path, this.fileMap, isCreateSlpk);
308
+ createSceneServerPath(tilesetName, this.layers0!, tilesetPath);
309
+ for (const filePath of this.compressList || []) {
310
+ await compressFileWithGzip(filePath);
311
+ await removeFile(filePath);
312
+ }
313
+ await this.nodePages.save();
314
+ await this.writeQueue.finalize();
233
315
  await this._createSlpk(tilesetPath);
234
316
  }
235
317
 
@@ -237,8 +319,15 @@ export default class I3SConverter {
237
319
  * Form object of 3DSceneLayer https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DSceneLayer.cmn.md
238
320
  * @param tilesetName - Name of layer
239
321
  */
240
- private _formLayers0(tilesetName: string): void {
241
- const extent = convertCommonToI3SExtentCoordinate(this.sourceTileset);
322
+ private _formLayers0(tilesetName: string, boundingVolumeRegion?: number[]): void {
323
+ const fullExtent = convertBoundingVolumeToI3SFullExtent(
324
+ this.sourceTileset?.boundingVolume || this.sourceTileset?.root?.boundingVolume
325
+ );
326
+ if (boundingVolumeRegion) {
327
+ fullExtent.zmin = boundingVolumeRegion[4];
328
+ fullExtent.zmax = boundingVolumeRegion[5];
329
+ }
330
+ const extent = [fullExtent.xmin, fullExtent.ymin, fullExtent.xmax, fullExtent.ymax];
242
331
  const layers0data = {
243
332
  version: `{${uuidv4().toUpperCase()}}`,
244
333
  id: 0,
@@ -251,80 +340,37 @@ export default class I3SConverter {
251
340
  nodePages: {
252
341
  nodesPerPage: HARDCODED_NODES_PER_PAGE
253
342
  },
254
- compressGeometry: this.options.draco
343
+ compressGeometry: this.options.draco,
344
+ fullExtent
255
345
  };
256
-
257
346
  this.layers0 = transform(layers0data, layersTemplate());
258
347
  }
259
348
 
260
- /**
261
- * Convert and save the layer and embedded tiles
262
- * @param boundingVolumes - mbs and obb data about node's bounding volume
263
- * @return 3DNodeIndexDocument data https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md
264
- */
265
- private _formRootNodeIndexDocument(boundingVolumes: BoundingVolumes): Node3DIndexDocument {
266
- const root0data = {
267
- version: `{${uuidv4().toUpperCase()}}`,
268
- id: 'root',
269
- level: 0,
270
- lodSelection: [
271
- {
272
- metricType: 'maxScreenThresholdSQ',
273
- maxError: 0
274
- },
275
- {
276
- metricType: 'maxScreenThreshold',
277
- maxError: 0
278
- }
279
- ],
280
- ...boundingVolumes,
281
- children: []
282
- };
283
- return transform(root0data, nodeTemplate());
284
- }
285
-
286
349
  /**
287
350
  * Form object of 3DSceneLayer https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DSceneLayer.cmn.md
288
- * @param root0 - 3DNodeIndexDocument of root node https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md
351
+ * @param rootNode - 3DNodeIndexDocument of root node https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md
289
352
  * @param sourceRootTile - Source (3DTile) tile data
290
- * @param parentId - node id in node pages
291
- * @param boundingVolumes - mbs and obb data about node's bounding volume
292
353
  */
293
354
  private async _convertNodesTree(
294
- root0: Node3DIndexDocument,
295
- sourceRootTile: TileHeader,
296
- parentId: number,
297
- boundingVolumes: BoundingVolumes
355
+ rootNode: NodeIndexDocument,
356
+ sourceRootTile: Tile3D
298
357
  ): Promise<void> {
299
358
  await this.sourceTileset!._loadTile(sourceRootTile);
300
359
  if (this.isContentSupported(sourceRootTile)) {
301
- root0.children = root0.children || [];
302
- root0.children.push({
303
- id: '1',
304
- href: './1',
305
- ...boundingVolumes
306
- });
307
- const [child] = await this._createNode(root0, sourceRootTile, parentId, 0);
308
- const childPath = join(this.layers0Path, 'nodes', child.path!);
309
-
310
- if (this.options.slpk) {
311
- this.fileMap['nodes/1/3dNodeIndexDocument.json.gz'] = await writeFileForSlpk(
312
- childPath,
313
- JSON.stringify(child),
314
- '3dNodeIndexDocument.json'
315
- );
316
- } else {
317
- await writeFile(childPath, JSON.stringify(child));
360
+ const childNodes = await this._createNode(rootNode, sourceRootTile, 0);
361
+ for (const childNode of childNodes) {
362
+ await childNode.save();
318
363
  }
364
+ await rootNode.addChildren(childNodes);
319
365
  } else {
320
366
  await this._addChildrenWithNeighborsAndWriteFile({
321
- parentNode: root0,
367
+ parentNode: rootNode,
322
368
  sourceTiles: sourceRootTile.children,
323
- parentId,
324
369
  level: 1
325
370
  });
326
371
  }
327
372
  await sourceRootTile.unloadContent();
373
+ await rootNode.save();
328
374
  }
329
375
 
330
376
  /**
@@ -332,32 +378,15 @@ export default class I3SConverter {
332
378
  */
333
379
  private async _writeLayers0(): Promise<void> {
334
380
  if (this.options.slpk) {
335
- this.fileMap['3dSceneLayer.json.gz'] = await writeFileForSlpk(
336
- this.layers0Path,
337
- JSON.stringify(this.layers0),
338
- '3dSceneLayer.json'
339
- );
340
- } else {
341
- await writeFile(this.layers0Path, JSON.stringify(this.layers0));
342
- }
343
- }
344
-
345
- /**
346
- * Write 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md in file
347
- */
348
- private async _writeNodeIndexDocument(
349
- root0: Node3DIndexDocument,
350
- nodePath: string,
351
- rootPath: string
352
- ): Promise<void> {
353
- if (this.options.slpk) {
354
- this.fileMap[`nodes/${nodePath}/3dNodeIndexDocument.json.gz`] = await writeFileForSlpk(
355
- rootPath,
356
- JSON.stringify(root0),
357
- '3dNodeIndexDocument.json'
358
- );
381
+ await this.writeQueue.enqueue({
382
+ archiveKey: '3dSceneLayer.json.gz',
383
+ writePromise: () =>
384
+ writeFileForSlpk(this.layers0Path, JSON.stringify(this.layers0), '3dSceneLayer.json')
385
+ });
359
386
  } else {
360
- await writeFile(rootPath, JSON.stringify(root0));
387
+ await this.writeQueue.enqueue({
388
+ writePromise: () => writeFile(this.layers0Path, JSON.stringify(this.layers0))
389
+ });
361
390
  }
362
391
  }
363
392
 
@@ -374,7 +403,6 @@ export default class I3SConverter {
374
403
  slpkFileName,
375
404
  0,
376
405
  '.',
377
- // @ts-expect-error
378
406
  this.options.sevenZipExe
379
407
  );
380
408
 
@@ -407,65 +435,85 @@ export default class I3SConverter {
407
435
  /**
408
436
  * Add child nodes recursively and write them to files
409
437
  * @param data - arguments
438
+ * @param data.parentNode - 3DNodeIndexDocument of parent node
410
439
  * @param data.sourceTiles - array of source child nodes
411
- * @param data.parentNode - 3DNodeIndexDocument of parent node for processing child nodes
412
- * @param data.parentId - id of parent node in node pages
413
440
  * @param data.level - level of node (distanse to root node in the tree)
414
441
  */
415
442
  private async _addChildrenWithNeighborsAndWriteFile(data: {
416
- parentNode: Node3DIndexDocument;
417
- sourceTiles: TileHeader[];
418
- parentId: number;
443
+ parentNode: NodeIndexDocument;
444
+ sourceTiles: Tile3D[];
419
445
  level: number;
420
446
  }): Promise<void> {
421
- const childNodes = [];
422
- await this._addChildren({...data, childNodes});
423
- await this._addNeighborsAndWriteFile(data.parentNode, childNodes);
447
+ await this._addChildren(data);
448
+ await data.parentNode.addNeighbors();
449
+ }
450
+
451
+ /**
452
+ * Convert nested subtree of 3DTiles dataset
453
+ * @param param0
454
+ * @param data.parentNode - 3DNodeIndexDocument of parent node
455
+ * @param param0.sourceTile - source 3DTile data
456
+ * @param param0.level - tree level
457
+ */
458
+ private async convertNestedTileset({
459
+ parentNode,
460
+ sourceTile,
461
+ level
462
+ }: {
463
+ parentNode: NodeIndexDocument;
464
+ sourceTile: Tile3D;
465
+ level: number;
466
+ }) {
467
+ await this.sourceTileset!._loadTile(sourceTile);
468
+ await this._addChildren({
469
+ parentNode,
470
+ sourceTiles: sourceTile.children,
471
+ level: level + 1
472
+ });
473
+ await sourceTile.unloadContent();
474
+ }
475
+
476
+ /**
477
+ * Convert 3DTiles tile to I3S node
478
+ * @param param0
479
+ * @param param0.parentNode - 3DNodeIndexDocument of parent node
480
+ * @param param0.sourceTile - source 3DTile data
481
+ * @param param0.level - tree level
482
+ */
483
+ private async convertNode({
484
+ parentNode,
485
+ sourceTile,
486
+ level
487
+ }: {
488
+ parentNode: NodeIndexDocument;
489
+ sourceTile: Tile3D;
490
+ level: number;
491
+ }) {
492
+ const childNodes = await this._createNode(parentNode, sourceTile, level);
493
+ await parentNode.addChildren(childNodes);
424
494
  }
425
495
 
426
496
  /**
427
497
  * Add child nodes recursively and write them to files
428
- * @param data - arguments
429
- * @param data.childNodes - array of target child nodes
430
- * @param data.sourceTiles - array of source child nodes
431
- * @param data.parentNode - 3DNodeIndexDocument of parent node for processing child nodes
432
- * @param data.parentId - id of parent node in node pages
433
- * @param data.level - level of node (distanse to root node in the tree)
498
+ * @param param0 - arguments
499
+ * @param param0.parentNode - 3DNodeIndexDocument of parent node
500
+ * @param param0.sourceTile - source 3DTile data
501
+ * @param param0.level - tree level
434
502
  */
435
503
  private async _addChildren(data: {
436
- childNodes: NodeReference[];
437
- sourceTiles: TileHeader[];
438
- parentNode: Node3DIndexDocument;
439
- parentId: number;
504
+ parentNode: NodeIndexDocument;
505
+ sourceTiles: Tile3D[];
440
506
  level: number;
441
507
  }): Promise<void> {
442
- const {childNodes, sourceTiles, parentNode, parentId, level} = data;
508
+ const {sourceTiles, parentNode, level} = data;
443
509
  if (this.options.maxDepth && level > this.options.maxDepth) {
444
510
  return;
445
511
  }
446
512
  for (const sourceTile of sourceTiles) {
447
513
  if (sourceTile.type === 'json') {
448
- await this.sourceTileset!._loadTile(sourceTile);
449
- await this._addChildren({
450
- parentNode,
451
- sourceTiles: sourceTile.children,
452
- childNodes,
453
- parentId,
454
- level: level + 1
455
- });
456
- await sourceTile.unloadContent();
514
+ await this.convertNestedTileset({parentNode, sourceTile, level});
457
515
  } else {
458
- const children = await this._createNode(parentNode, sourceTile, parentId, level);
459
- parentNode.children = parentNode.children || [];
460
- for (const child of children) {
461
- parentNode.children.push({
462
- id: child.id,
463
- href: `../${child.path}`,
464
- obb: child.obb,
465
- mbs: child.mbs
466
- });
467
- childNodes.push(child);
468
- }
516
+ await this.convertNode({parentNode, sourceTile, level});
469
517
  }
470
518
  if (sourceTile.id) {
471
519
  console.log(sourceTile.id); // eslint-disable-line
@@ -473,80 +521,44 @@ export default class I3SConverter {
473
521
  }
474
522
  }
475
523
 
476
- /**
477
- * Add neightbors to 3DNodeIndexDocument and write it in a file
478
- * @param parentNode - arguments
479
- * @param childNodes - array of target child nodes
480
- */
481
- private async _addNeighborsAndWriteFile(
482
- parentNode: Node3DIndexDocument,
483
- childNodes: Node3DIndexDocument[]
484
- ): Promise<void> {
485
- for (const node of childNodes) {
486
- const childPath = join(this.layers0Path, 'nodes', node.path!);
487
- const nodePath = node.path;
488
- delete node.path;
489
-
490
- // Don't do large amount of "neightbors" to avoid big memory consumption
491
- if (Number(parentNode?.children?.length) < 1000) {
492
- for (const neighbor of parentNode.children || []) {
493
- // eslint-disable-next-line max-depth
494
- if (node.id === neighbor.id) {
495
- continue; // eslint-disable-line
496
- }
497
-
498
- if (node.neighbors) {
499
- node.neighbors.push({...neighbor});
500
- }
501
- }
502
- } else {
503
- // eslint-disable-next-line no-console, no-undef
504
- console.warn(
505
- `Node ${node.id}: neighbors attribute is omited because of large number of neigbors`
506
- );
507
- delete node.neighbors;
508
- }
509
- await this._writeNodeIndexDocument(node, nodePath!, childPath);
510
- node.neighbors = [];
511
- }
512
- }
513
-
514
524
  /**
515
525
  * Convert tile to one or more I3S nodes
516
- * @param parentTile - parent 3DNodeIndexDocument
517
- * @param sourceTile - source tile (3DTile)
518
- * @param parentId - id of parent node in node pages
519
- * @param level - level of node (distanse to root node in the tree)
526
+ * @param parentNode - 3DNodeIndexDocument of parent node
527
+ * @param sourceTile - source 3DTile data
528
+ * @param level - tree level
520
529
  */
521
530
  private async _createNode(
522
- parentTile: Node3DIndexDocument,
523
- sourceTile: TileHeader,
524
- parentId: number,
531
+ parentNode: NodeIndexDocument,
532
+ sourceTile: Tile3D,
525
533
  level: number
526
- ): Promise<Node3DIndexDocument[]> {
527
- if (this.validate) {
528
- this._checkAddRefinementTypeForTile(sourceTile);
529
- }
534
+ ): Promise<NodeIndexDocument[]> {
535
+ this._checkAddRefinementTypeForTile(sourceTile);
530
536
 
531
537
  await this._updateTilesetOptions();
532
538
  await this.sourceTileset!._loadTile(sourceTile);
533
539
 
534
540
  let boundingVolumes = createBoundingVolumes(sourceTile, this.geoidHeightModel!);
535
541
 
536
- const batchTable = sourceTile?.content?.batchTableJson;
542
+ const propertyTable = getPropertyTable(sourceTile.content);
537
543
 
538
- if (batchTable) {
539
- this._convertAttributeStorageInfo(sourceTile.content);
544
+ if (propertyTable && !this.layers0?.attributeStorageInfo?.length) {
545
+ this._convertPropertyTableToNodeAttributes(propertyTable);
540
546
  }
541
547
 
542
- const resourcesData = await this._convertResources(sourceTile);
548
+ const resourcesData = await this._convertResources(
549
+ sourceTile,
550
+ parentNode.inPageId,
551
+ propertyTable
552
+ );
543
553
 
544
- const nodes: Node3DIndexDocument[] = [];
554
+ const nodes: NodeIndexDocument[] = [];
555
+ const nodeIds: number[] = [];
545
556
  const nodesInPage: NodeInPage[] = [];
546
557
  const emptyResources = {
547
558
  geometry: null,
548
559
  compressedGeometry: null,
549
560
  texture: null,
561
+ hasUvRegions: false,
550
562
  sharedResources: null,
551
563
  meshMaterial: null,
552
564
  vertexCount: null,
@@ -556,6 +568,8 @@ export default class I3SConverter {
556
568
  };
557
569
 
558
570
  for (const resources of resourcesData || [emptyResources]) {
571
+ this.layersHasTexture = this.layersHasTexture || Boolean(resources.texture);
572
+
559
573
  if (this.generateBoundingVolumes && resources.boundingVolumes) {
560
574
  boundingVolumes = resources.boundingVolumes;
561
575
  }
@@ -565,34 +579,37 @@ export default class I3SConverter {
565
579
  (val) => val.metricType === 'maxScreenThresholdSQ'
566
580
  ) || {maxError: 0};
567
581
 
568
- const nodeInPage = this._createNodeInNodePages(
582
+ const nodeInPage = await this._updateNodeInNodePages(
569
583
  maxScreenThresholdSQ,
570
584
  boundingVolumes,
571
585
  sourceTile,
572
- parentId,
586
+ parentNode.inPageId,
573
587
  resources
574
588
  );
575
- const node = this._createNodeIndexDocument(
576
- parentTile,
589
+
590
+ const nodeData = await NodeIndexDocument.createNodeIndexDocument(
591
+ parentNode,
577
592
  boundingVolumes,
578
593
  lodSelection,
579
594
  nodeInPage,
580
595
  resources
581
596
  );
597
+ const node = await new NodeIndexDocument(nodeInPage.index, this).addData(nodeData);
598
+ nodes.push(node);
582
599
 
583
600
  if (nodeInPage.mesh) {
584
- await this._writeResources(resources, node.path!);
601
+ await this._writeResources(resources, node.id);
585
602
  }
586
603
 
587
604
  if (this.validate) {
588
- this.boundingVolumeWarnings = validateNodeBoundingVolumes(node);
605
+ this.boundingVolumeWarnings = validateNodeBoundingVolumes(nodeData);
589
606
 
590
607
  if (this.boundingVolumeWarnings && this.boundingVolumeWarnings.length) {
591
608
  console.warn('Bounding Volume Warnings: ', ...this.boundingVolumeWarnings); //eslint-disable-line
592
609
  }
593
610
  }
594
611
 
595
- nodes.push(node);
612
+ nodeIds.push(nodeInPage.index);
596
613
  nodesInPage.push(nodeInPage);
597
614
  }
598
615
 
@@ -601,56 +618,48 @@ export default class I3SConverter {
601
618
  await this._addChildrenWithNeighborsAndWriteFile({
602
619
  parentNode: nodes[0],
603
620
  sourceTiles: sourceTile.children,
604
- parentId: nodesInPage[0].index!,
605
621
  level: level + 1
606
622
  });
607
623
  return nodes;
608
624
  }
609
625
 
610
- /**
611
- * Convert attributesStorageInfo https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md
612
- * from B3DM batch table
613
- * @param sourceTileContent - tile content of 3DTile
614
- * @return {void}
615
- */
616
- private _convertAttributeStorageInfo(sourceTileContent: B3DMContent): void {
617
- // In legacy b3dm files sometimes sourceTileContent is null.
618
- const batchTable = sourceTileContent && sourceTileContent.batchTableJson;
619
- if (batchTable && !this.layers0?.attributeStorageInfo?.length) {
620
- this._convertBatchTableInfoToNodeAttributes(batchTable);
621
- }
622
- }
623
-
624
626
  /**
625
627
  * Convert tile to one or more I3S nodes
626
628
  * @param sourceTile - source tile (3DTile)
627
- * result.geometry - ArrayBuffer with geometry attributes
628
- * result.compressedGeometry - ArrayBuffer with compressed (draco) geometry
629
- * result.texture - texture image
630
- * result.sharedResources - shared resource data object
631
- * result.meshMaterial - PBR-like material object
632
- * result.vertexCount - number of vertices in geometry
633
- * result.attributes - feature attributes
634
- * result.featureCount - number of features
629
+ * @param parentId - id of parent node in node pages
630
+ * @param propertyTable - batch table from b3dm / feature properties from EXT_FEATURE_METADATA
631
+ * @returns - converted node resources
635
632
  */
636
- private async _convertResources(sourceTile: TileHeader): Promise<I3SConvertedResources[] | null> {
633
+ private async _convertResources(
634
+ sourceTile: Tile3D,
635
+ parentId: number,
636
+ propertyTable: FeatureTableJson | null
637
+ ): Promise<I3SConvertedResources[] | null> {
637
638
  if (!this.isContentSupported(sourceTile)) {
638
639
  return null;
639
640
  }
641
+ const draftObb = {
642
+ center: [],
643
+ halfSize: [],
644
+ quaternion: []
645
+ };
640
646
  const resourcesData = await convertB3dmToI3sGeometry(
641
647
  sourceTile.content,
642
- Number(this.nodePages.nodesCounter),
648
+ async () => (await this.nodePages.push({index: 0, obb: draftObb}, parentId)).index,
649
+ propertyTable,
643
650
  this.featuresHashArray,
644
651
  this.layers0?.attributeStorageInfo,
645
652
  this.options.draco,
646
653
  this.generateBoundingVolumes,
647
- this.geoidHeightModel!
654
+ this.options.mergeMaterials,
655
+ this.geoidHeightModel!,
656
+ this.workerSource
648
657
  );
649
658
  return resourcesData;
650
659
  }
651
660
 
652
661
  /**
653
- * Create a new node object (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/node.cmn.md)
662
+ * Update node object (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/node.cmn.md)
654
663
  * in node pages (https://github.com/Esri/i3s-spec/blob/master/docs/1.7/nodePage.cmn.md)
655
664
  * @param maxScreenThresholdSQ - Level of Details (LOD) metric
656
665
  * @param boundingVolumes - Bounding volumes
@@ -661,16 +670,17 @@ export default class I3SConverter {
661
670
  * @param resources.texture - texture image
662
671
  * @param resources.vertexCount - number of vertices in geometry
663
672
  * @param resources.featureCount - number of features
673
+ * @param resources.geometry - Uint8Array with geometry attributes
664
674
  * @return the node object in node pages
665
675
  */
666
- private _createNodeInNodePages(
676
+ private async _updateNodeInNodePages(
667
677
  maxScreenThresholdSQ: MaxScreenThresholdSQ,
668
678
  boundingVolumes: BoundingVolumes,
669
- sourceTile: TileHeader,
679
+ sourceTile: Tile3D,
670
680
  parentId: number,
671
681
  resources: I3SConvertedResources
672
- ): NodeInPage {
673
- const {meshMaterial, texture, vertexCount, featureCount, geometry} = resources;
682
+ ): Promise<NodeInPage> {
683
+ const {meshMaterial, texture, vertexCount, featureCount, geometry, hasUvRegions} = resources;
674
684
  const nodeInPage: NodeInPage = {
675
685
  index: 0,
676
686
  lodThreshold: maxScreenThresholdSQ.maxError,
@@ -680,7 +690,7 @@ export default class I3SConverter {
680
690
  if (geometry && this.isContentSupported(sourceTile)) {
681
691
  nodeInPage.mesh = {
682
692
  geometry: {
683
- definition: texture ? 0 : 1,
693
+ definition: this.findOrCreateGeometryDefinition(Boolean(texture), hasUvRegions),
684
694
  resource: 0
685
695
  },
686
696
  attribute: {
@@ -691,83 +701,33 @@ export default class I3SConverter {
691
701
  }
692
702
  };
693
703
  }
694
- const nodeId = this.nodePages.push(nodeInPage, parentId);
695
704
 
696
- if (meshMaterial) {
697
- this.nodePages.updateMaterialByNodeId(nodeId, this._findOrCreateMaterial(meshMaterial));
705
+ let nodeId = resources.nodeId;
706
+ let node;
707
+ if (!nodeId) {
708
+ node = await this.nodePages.push(nodeInPage, parentId);
709
+ } else {
710
+ node = await this.nodePages.getNodeById(nodeId);
698
711
  }
699
712
 
713
+ NodePages.updateAll(node, nodeInPage);
714
+ if (meshMaterial) {
715
+ NodePages.updateMaterialByNodeId(node, this._findOrCreateMaterial(meshMaterial));
716
+ }
700
717
  if (texture) {
701
718
  const texelCountHint = texture.image.height * texture.image.width;
702
- this.nodePages.updateTexelCountHintByNodeId(nodeId, texelCountHint);
719
+ NodePages.updateTexelCountHintByNodeId(node, texelCountHint);
703
720
  }
704
-
705
721
  if (vertexCount) {
706
722
  this.vertexCounter += vertexCount;
707
- this.nodePages.updateVertexCountByNodeId(nodeId, vertexCount);
723
+ NodePages.updateVertexCountByNodeId(node, vertexCount);
708
724
  }
709
- this.nodePages.updateNodeAttributeByNodeId(nodeId);
725
+ NodePages.updateNodeAttributeByNodeId(node);
710
726
  if (featureCount) {
711
- this.nodePages.updateFeatureCountByNodeId(nodeId, featureCount);
727
+ NodePages.updateFeatureCountByNodeId(node, featureCount);
712
728
  }
713
729
 
714
- return nodeInPage;
715
- }
716
-
717
- /**
718
- * Create a new node page object in node pages
719
- * @param parentNode - 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md object of the parent node
720
- * @param boundingVolumes - Bounding volumes
721
- * @param lodSelection - Level of Details (LOD) metrics
722
- * @param nodeInPage - corresponding node object in a node page
723
- * @param resources - the node resources data
724
- * @param resources.texture - texture image
725
- * @param resources.attributes - feature attributes
726
- * @return 3DNodeIndexDocument https://github.com/Esri/i3s-spec/blob/master/docs/1.7/3DNodeIndexDocument.cmn.md object
727
- */
728
- private _createNodeIndexDocument(
729
- parentNode: Node3DIndexDocument,
730
- boundingVolumes: BoundingVolumes,
731
- lodSelection: LodSelection[],
732
- nodeInPage: NodeInPage,
733
- resources: I3SConvertedResources
734
- ): Node3DIndexDocument {
735
- const {texture, attributes} = resources;
736
- const nodeId = nodeInPage.index!;
737
- const nodeData = {
738
- version: parentNode.version,
739
- id: nodeId.toString(),
740
- path: nodeId.toString(),
741
- level: parentNode.level! + 1,
742
- ...boundingVolumes,
743
- lodSelection,
744
- parentNode: {
745
- id: parentNode.id,
746
- href: `../${parentNode.id}`,
747
- mbs: parentNode.mbs,
748
- obb: parentNode.obb
749
- },
750
- children: [],
751
- neighbors: []
752
- };
753
- const node = transform(nodeData, nodeTemplate());
754
-
755
- if (nodeInPage.mesh) {
756
- node.geometryData = [{href: './geometries/0'}];
757
- node.sharedResource = {href: './shared'};
758
-
759
- if (texture) {
760
- node.textureData = [{href: './textures/0'}, {href: './textures/1'}];
761
- }
762
-
763
- if (attributes && attributes.length && this.layers0?.attributeStorageInfo?.length) {
764
- node.attributeData = [];
765
- for (let index = 0; index < attributes.length; index++) {
766
- const folderName = this.layers0.attributeStorageInfo[index].key;
767
- node.attributeData.push({href: `./attributes/${folderName}/0`});
768
- }
769
- }
770
- }
730
+ this.nodePages.saveNode(node);
771
731
 
772
732
  return node;
773
733
  }
@@ -794,7 +754,7 @@ export default class I3SConverter {
794
754
  const slpkChildPath = join('nodes', nodePath);
795
755
 
796
756
  await this._writeGeometries(geometryBuffer!, compressedGeometry!, childPath, slpkChildPath);
797
- await this._writeShared(sharedResources!, childPath, slpkChildPath, nodePath);
757
+ await this._writeShared(sharedResources, childPath, slpkChildPath, nodePath);
798
758
  await this._writeTexture(texture, childPath, slpkChildPath);
799
759
  await this._writeAttributes(attributes, childPath, slpkChildPath);
800
760
  }
@@ -808,33 +768,36 @@ export default class I3SConverter {
808
768
  */
809
769
  private async _writeGeometries(
810
770
  geometryBuffer: ArrayBuffer,
811
- compressedGeometry: ArrayBuffer,
771
+ compressedGeometry: Promise<ArrayBuffer>,
812
772
  childPath: string,
813
773
  slpkChildPath: string
814
774
  ): Promise<void> {
815
775
  if (this.options.slpk) {
816
776
  const slpkGeometryPath = join(childPath, 'geometries');
817
- this.fileMap[`${slpkChildPath}/geometries/0.bin.gz`] = await writeFileForSlpk(
818
- slpkGeometryPath,
819
- geometryBuffer,
820
- '0.bin'
821
- );
777
+ await this.writeQueue.enqueue({
778
+ archiveKey: `${slpkChildPath}/geometries/0.bin.gz`,
779
+ writePromise: () => writeFileForSlpk(slpkGeometryPath, geometryBuffer, '0.bin')
780
+ });
822
781
  } else {
823
782
  const geometryPath = join(childPath, 'geometries/0/');
824
- await writeFile(geometryPath, geometryBuffer, 'index.bin');
783
+ await this.writeQueue.enqueue({
784
+ writePromise: () => writeFile(geometryPath, geometryBuffer, 'index.bin')
785
+ });
825
786
  }
826
787
 
827
788
  if (this.options.draco) {
828
789
  if (this.options.slpk) {
829
790
  const slpkCompressedGeometryPath = join(childPath, 'geometries');
830
- this.fileMap[`${slpkChildPath}/geometries/1.bin.gz`] = await writeFileForSlpk(
831
- slpkCompressedGeometryPath,
832
- compressedGeometry,
833
- '1.bin'
834
- );
791
+ await this.writeQueue.enqueue({
792
+ archiveKey: `${slpkChildPath}/geometries/1.bin.gz`,
793
+ writePromise: () =>
794
+ writeFileForSlpk(slpkCompressedGeometryPath, compressedGeometry, '1.bin')
795
+ });
835
796
  } else {
836
797
  const compressedGeometryPath = join(childPath, 'geometries/1/');
837
- await writeFile(compressedGeometryPath, compressedGeometry, 'index.bin');
798
+ await this.writeQueue.enqueue({
799
+ writePromise: () => writeFile(compressedGeometryPath, compressedGeometry, 'index.bin')
800
+ });
838
801
  }
839
802
  }
840
803
  }
@@ -847,24 +810,26 @@ export default class I3SConverter {
847
810
  * @param nodePath - a node path
848
811
  */
849
812
  private async _writeShared(
850
- sharedResources: SharedResources,
813
+ sharedResources: SharedResourcesArrays | null,
851
814
  childPath: string,
852
815
  slpkChildPath: string,
853
816
  nodePath: string
854
817
  ): Promise<void> {
818
+ if (!sharedResources) {
819
+ return;
820
+ }
855
821
  sharedResources.nodePath = nodePath;
856
822
  const sharedData = transform(sharedResources, sharedResourcesTemplate());
857
823
  const sharedDataStr = JSON.stringify(sharedData);
858
824
  if (this.options.slpk) {
859
825
  const slpkSharedPath = join(childPath, 'shared');
860
- this.fileMap[`${slpkChildPath}/shared/sharedResource.json.gz`] = await writeFileForSlpk(
861
- slpkSharedPath,
862
- sharedDataStr,
863
- 'sharedResource.json'
864
- );
826
+ await this.writeQueue.enqueue({
827
+ archiveKey: `${slpkChildPath}/shared/sharedResource.json.gz`,
828
+ writePromise: () => writeFileForSlpk(slpkSharedPath, sharedDataStr, 'sharedResource.json')
829
+ });
865
830
  } else {
866
831
  const sharedPath = join(childPath, 'shared/');
867
- await writeFile(sharedPath, sharedDataStr);
832
+ await this.writeQueue.enqueue({writePromise: () => writeFile(sharedPath, sharedDataStr)});
868
833
  }
869
834
  }
870
835
 
@@ -892,9 +857,20 @@ export default class I3SConverter {
892
857
 
893
858
  if (this.generateTextures) {
894
859
  formats.push({name: '1', format: 'ktx2'});
895
- const ktx2TextureData = new Uint8Array(
896
- await encode(texture.image, KTX2BasisUniversalTextureWriter)
860
+ // For Node.js texture.image.data is type of Buffer
861
+ const copyArrayBuffer = texture.image.data.subarray();
862
+ const arrayToEncode = new Uint8Array(copyArrayBuffer);
863
+ const ktx2TextureData = encode(
864
+ {...texture.image, data: arrayToEncode},
865
+ KTX2BasisWriterWorker,
866
+ {
867
+ ...KTX2BasisWriterWorker.options,
868
+ source: this.workerSource.ktx2,
869
+ reuseWorkers: true,
870
+ _nodeWorkers: true
871
+ }
897
872
  );
873
+
898
874
  await this.writeTextureFile(ktx2TextureData, '1', 'ktx2', childPath, slpkChildPath);
899
875
  }
900
876
 
@@ -907,9 +883,7 @@ export default class I3SConverter {
907
883
 
908
884
  if (this.generateTextures) {
909
885
  formats.push({name: '0', format: 'jpg'});
910
- const decodedFromKTX2TextureData = new Uint8Array(
911
- await encode(texture.image!.data[0], ImageWriter)
912
- );
886
+ const decodedFromKTX2TextureData = encode(texture.image!.data[0], ImageWriter);
913
887
  await this.writeTextureFile(
914
888
  decodedFromKTX2TextureData,
915
889
  '0',
@@ -923,6 +897,7 @@ export default class I3SConverter {
923
897
 
924
898
  if (!this.layers0!.textureSetDefinitions!.length) {
925
899
  this.layers0!.textureSetDefinitions!.push({formats});
900
+ this.layers0!.textureSetDefinitions!.push({formats, atlas: true});
926
901
  }
927
902
  }
928
903
  }
@@ -936,25 +911,26 @@ export default class I3SConverter {
936
911
  * @param slpkChildPath
937
912
  */
938
913
  private async writeTextureFile(
939
- textureData: ArrayBuffer,
914
+ textureData: Uint8Array | Promise<ArrayBuffer>,
940
915
  name: string,
941
916
  format: 'jpg' | 'png' | 'ktx2',
942
917
  childPath: string,
943
918
  slpkChildPath: string
944
919
  ): Promise<void> {
945
- const texturePath = join(childPath, `textures/${name}/`);
946
- await writeFile(texturePath, textureData, `index.${format}`);
947
-
948
920
  if (this.options.slpk) {
949
921
  const slpkTexturePath = join(childPath, 'textures');
950
922
  const compress = false;
951
923
 
952
- this.fileMap[`${slpkChildPath}/textures/${name}.${format}`] = await writeFileForSlpk(
953
- slpkTexturePath,
954
- textureData,
955
- `${name}.${format}`,
956
- compress
957
- );
924
+ await this.writeQueue.enqueue({
925
+ archiveKey: `${slpkChildPath}/textures/${name}.${format}`,
926
+ writePromise: () =>
927
+ writeFileForSlpk(slpkTexturePath, textureData, `${name}.${format}`, compress)
928
+ });
929
+ } else {
930
+ const texturePath = join(childPath, `textures/${name}/`);
931
+ await this.writeQueue.enqueue({
932
+ writePromise: () => writeFile(texturePath, textureData, `index.${format}`)
933
+ });
958
934
  }
959
935
  }
960
936
 
@@ -965,25 +941,26 @@ export default class I3SConverter {
965
941
  * @param slpkChildPath - the resource path inside *slpk file
966
942
  */
967
943
  private async _writeAttributes(
968
- attributes: ArrayBuffer[],
944
+ attributes: ArrayBuffer[] | null = [],
969
945
  childPath: string,
970
946
  slpkChildPath: string
971
947
  ): Promise<void> {
972
- if (attributes.length && this.layers0?.attributeStorageInfo?.length) {
948
+ if (attributes?.length && this.layers0?.attributeStorageInfo?.length) {
973
949
  for (let index = 0; index < attributes.length; index++) {
974
950
  const folderName = this.layers0.attributeStorageInfo[index].key;
975
951
  const fileBuffer = new Uint8Array(attributes[index]);
976
952
 
977
953
  if (this.options.slpk) {
978
954
  const slpkAttributesPath = join(childPath, 'attributes', folderName);
979
- this.fileMap[`${slpkChildPath}/attributes/${folderName}.bin.gz`] = await writeFileForSlpk(
980
- slpkAttributesPath,
981
- fileBuffer,
982
- '0.bin'
983
- );
955
+ await this.writeQueue.enqueue({
956
+ archiveKey: `${slpkChildPath}/attributes/${folderName}.bin.gz`,
957
+ writePromise: () => writeFileForSlpk(slpkAttributesPath, fileBuffer, '0.bin')
958
+ });
984
959
  } else {
985
960
  const attributesPath = join(childPath, `attributes/${folderName}/0`);
986
- await writeFile(attributesPath, fileBuffer, 'index.bin');
961
+ await this.writeQueue.enqueue({
962
+ writePromise: () => writeFile(attributesPath, fileBuffer, 'index.bin')
963
+ });
987
964
  }
988
965
  }
989
966
  }
@@ -1014,7 +991,7 @@ export default class I3SConverter {
1014
991
  private _findOrCreateMaterial(material: I3SMaterialDefinition): number {
1015
992
  const hash = md5(JSON.stringify(material));
1016
993
  if (this.materialMap.has(hash)) {
1017
- return this.materialMap.get(hash);
994
+ return this.materialMap.get(hash) || 0;
1018
995
  }
1019
996
  const newMaterialId = this.materialDefinitions.push(material) - 1;
1020
997
  this.materialMap.set(hash, newMaterialId);
@@ -1022,133 +999,42 @@ export default class I3SConverter {
1022
999
  }
1023
1000
 
1024
1001
  /**
1025
- * Generate storage attribute for map segmentation.
1026
- * @param attributeIndex - order index of attribute (f_0, f_1 ...).
1027
- * @param key - attribute key from batch table.\
1028
- * @param attributeType - attribute type.
1029
- * @return Updated storageAttribute.
1030
- */
1031
- private _createdStorageAttribute(
1032
- attributeIndex: number,
1033
- key: string,
1034
- attributeType: Attribute
1035
- ): AttributeStorageInfo {
1036
- const storageAttribute = {
1037
- key: `f_${attributeIndex}`,
1038
- name: key,
1039
- ordering: ['attributeValues'],
1040
- header: [{property: 'count', valueType: 'UInt32'}],
1041
- attributeValues: {valueType: 'Int32', valuesPerElement: 1}
1042
- };
1043
-
1044
- switch (attributeType) {
1045
- case OBJECT_ID_TYPE:
1046
- this._setupIdAttribute(storageAttribute);
1047
- break;
1048
- case STRING_TYPE:
1049
- this._setupStringAttribute(storageAttribute);
1050
- break;
1051
- case DOUBLE_TYPE:
1052
- this._setupDoubleAttribute(storageAttribute);
1053
- break;
1054
- case SHORT_INT_TYPE:
1055
- break;
1056
- default:
1057
- this._setupStringAttribute(storageAttribute);
1058
- }
1059
-
1060
- return storageAttribute;
1061
- }
1062
-
1063
- /**
1064
- * Get the attribute type for attributeStorageInfo https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md
1065
- * @param key - attribute's key
1066
- * @param attribute - attribute's type in batchTable
1002
+ * Get unique geometry configuration index
1003
+ * In the end of conversion configurations will be transformed to geometryDefinitions array
1004
+ * @param hasTexture
1005
+ * @param hasUvRegions
1006
+ * @returns
1067
1007
  */
1068
- private getAttributeType(key: string, attribute: string): string {
1069
- if (key === OBJECT_ID_TYPE) {
1070
- return OBJECT_ID_TYPE;
1071
- }
1072
- if (typeof attribute === STRING_TYPE) {
1073
- return STRING_TYPE;
1074
- } else if (typeof attribute === 'number') {
1075
- return Number.isInteger(attribute) ? SHORT_INT_TYPE : DOUBLE_TYPE;
1008
+ private findOrCreateGeometryDefinition(hasTexture: boolean, hasUvRegions: boolean): number {
1009
+ const geometryConfig = {hasTexture, hasUvRegions};
1010
+ const hash = md5(JSON.stringify(geometryConfig));
1011
+ if (this.geometryMap.has(hash)) {
1012
+ return this.geometryMap.get(hash) || 0;
1076
1013
  }
1077
- return STRING_TYPE;
1078
- }
1079
-
1080
- /**
1081
- * Setup storage attribute as string.
1082
- * @param storageAttribute - attribute for map segmentation.
1083
- */
1084
- private _setupStringAttribute(storageAttribute: AttributeStorageInfo): void {
1085
- storageAttribute.ordering!.unshift('attributeByteCounts');
1086
- storageAttribute.header.push({property: 'attributeValuesByteCount', valueType: 'UInt32'});
1087
- storageAttribute.attributeValues = {
1088
- valueType: 'String',
1089
- encoding: 'UTF-8',
1090
- valuesPerElement: 1
1091
- };
1092
- storageAttribute.attributeByteCounts = {
1093
- valueType: 'UInt32',
1094
- valuesPerElement: 1
1095
- };
1096
- }
1097
-
1098
- /**
1099
- * Setup Id attribute for map segmentation.
1100
- * @param storageAttribute - attribute for map segmentation .
1101
- */
1102
- private _setupIdAttribute(storageAttribute: AttributeStorageInfo): void {
1103
- storageAttribute.attributeValues = {
1104
- valueType: 'Oid32',
1105
- valuesPerElement: 1
1106
- };
1107
- }
1108
-
1109
- /**
1110
- * Setup double attribute for map segmentation.
1111
- * @param storageAttribute - attribute for map segmentation .
1112
- */
1113
- private _setupDoubleAttribute(storageAttribute: AttributeStorageInfo): void {
1114
- storageAttribute.attributeValues = {
1115
- valueType: 'Float64',
1116
- valuesPerElement: 1
1117
- };
1118
- }
1119
-
1120
- /**
1121
- * Setup field attribute for map segmentation.
1122
- * @param key - attribute for map segmentation.
1123
- * @param fieldAttributeType - esri attribute type ('esriFieldTypeString' or 'esriFieldTypeOID').
1124
- */
1125
- private _createFieldAttribute(key: string, fieldAttributeType: ESRIField): Field {
1126
- return {
1127
- name: key,
1128
- type: fieldAttributeType,
1129
- alias: key
1130
- };
1014
+ const newGeometryId = this.geometryConfigs.push(geometryConfig) - 1;
1015
+ this.geometryMap.set(hash, newGeometryId);
1016
+ return newGeometryId;
1131
1017
  }
1132
1018
 
1133
1019
  /**
1134
- * Do conversion of 3DTiles batch table to I3s node attributes.
1135
- * @param batchTable - Table with layer meta data.
1020
+ * Do conversion of 3DTiles property table to I3s node attributes.
1021
+ * @param propertyTable - Table with layer meta data.
1136
1022
  */
1137
- private _convertBatchTableInfoToNodeAttributes(batchTable: BatchTableJson): void {
1023
+ private _convertPropertyTableToNodeAttributes(propertyTable: FeatureTableJson): void {
1138
1024
  let attributeIndex = 0;
1139
- const batchTableWithObjectId = {
1025
+ const propertyTableWithObjectId = {
1140
1026
  OBJECTID: [0],
1141
- ...batchTable
1027
+ ...propertyTable
1142
1028
  };
1143
1029
 
1144
- for (const key in batchTableWithObjectId) {
1145
- const firstAttribute = batchTableWithObjectId[key][0];
1146
- const attributeType = this.getAttributeType(key, firstAttribute);
1030
+ for (const key in propertyTableWithObjectId) {
1031
+ const firstAttribute = propertyTableWithObjectId[key][0];
1032
+ const attributeType = getAttributeType(key, firstAttribute);
1147
1033
 
1148
- const storageAttribute = this._createdStorageAttribute(attributeIndex, key, attributeType);
1149
- const fieldAttributeType = this._getFieldAttributeType(attributeType);
1150
- const fieldAttribute = this._createFieldAttribute(key, fieldAttributeType);
1151
- const popupInfo = this._createPopupInfo(batchTableWithObjectId);
1034
+ const storageAttribute = createdStorageAttribute(attributeIndex, key, attributeType);
1035
+ const fieldAttributeType = getFieldAttributeType(attributeType);
1036
+ const fieldAttribute = createFieldAttribute(key, fieldAttributeType);
1037
+ const popupInfo = createPopupInfo(propertyTableWithObjectId);
1152
1038
 
1153
1039
  this.layers0!.attributeStorageInfo!.push(storageAttribute);
1154
1040
  this.layers0!.fields!.push(fieldAttribute);
@@ -1159,62 +1045,6 @@ export default class I3SConverter {
1159
1045
  }
1160
1046
  }
1161
1047
 
1162
- /**
1163
- * Find and return attribute type based on key form Batch table.
1164
- * @param attributeType
1165
- */
1166
- private _getFieldAttributeType(attributeType: Attribute): ESRIField {
1167
- switch (attributeType) {
1168
- case OBJECT_ID_TYPE:
1169
- return 'esriFieldTypeOID';
1170
- case STRING_TYPE:
1171
- return 'esriFieldTypeString';
1172
- case SHORT_INT_TYPE:
1173
- return 'esriFieldTypeInteger';
1174
- case DOUBLE_TYPE:
1175
- return 'esriFieldTypeDouble';
1176
- default:
1177
- return 'esriFieldTypeString';
1178
- }
1179
- }
1180
-
1181
- /**
1182
- * Generate popup info to show metadata on the map.
1183
- * @param batchTable - Batch table data with OBJECTID.
1184
- * @return data for correct rendering of popup.
1185
- */
1186
- private _createPopupInfo(batchTable: BatchTableJson): PopupInfo {
1187
- const title = '{OBJECTID}';
1188
- const mediaInfos = [];
1189
- const fieldInfos: FieldInfo[] = [];
1190
- const popupElements: {
1191
- fieldInfos: FieldInfo[];
1192
- type: string;
1193
- }[] = [];
1194
- const expressionInfos = [];
1195
-
1196
- for (const key in batchTable) {
1197
- fieldInfos.push({
1198
- fieldName: key,
1199
- visible: true,
1200
- isEditable: false,
1201
- label: key
1202
- });
1203
- }
1204
- popupElements.push({
1205
- fieldInfos,
1206
- type: 'fields'
1207
- });
1208
-
1209
- return {
1210
- title,
1211
- mediaInfos,
1212
- popupElements,
1213
- fieldInfos,
1214
- expressionInfos
1215
- };
1216
- }
1217
-
1218
1048
  /**
1219
1049
  * Print statistics in the end of conversion
1220
1050
  * @param params - output files data
@@ -1279,7 +1109,7 @@ export default class I3SConverter {
1279
1109
  /** Do calculations of all tiles and tiles with "ADD" type of refinement.
1280
1110
  * @param tile
1281
1111
  */
1282
- private _checkAddRefinementTypeForTile(tile: TileHeader): void {
1112
+ private _checkAddRefinementTypeForTile(tile: Tile3D): void {
1283
1113
  const ADD_TILE_REFINEMENT = 1;
1284
1114
 
1285
1115
  if (tile.refine === ADD_TILE_REFINEMENT) {
@@ -1297,4 +1127,27 @@ export default class I3SConverter {
1297
1127
  private isContentSupported(sourceRootTile: Tile3D): boolean {
1298
1128
  return ['b3dm', 'glTF'].includes(sourceRootTile?.content?.type);
1299
1129
  }
1130
+
1131
+ private async loadWorkers(): Promise<void> {
1132
+ console.log(`Loading workers source...`); // eslint-disable-line no-undef, no-console
1133
+ if (this.options.draco) {
1134
+ const url = getWorkerURL(DracoWriterWorker, {...getLoaderOptions()});
1135
+ const sourceResponse = await fetchFile(url);
1136
+ const source = await sourceResponse.text();
1137
+ this.workerSource.draco = source;
1138
+ }
1139
+
1140
+ if (this.generateTextures) {
1141
+ const url = getWorkerURL(KTX2BasisWriterWorker, {...getLoaderOptions()});
1142
+ const sourceResponse = await fetchFile(url);
1143
+ const source = await sourceResponse.text();
1144
+ this.workerSource.ktx2 = source;
1145
+ }
1146
+
1147
+ const i3sAttributesWorkerUrl = getWorkerURL(I3SAttributesWorker, {...getLoaderOptions()});
1148
+ const sourceResponse = await fetchFile(i3sAttributesWorkerUrl);
1149
+ const source = await sourceResponse.text();
1150
+ this.workerSource.I3SAttributes = source;
1151
+ console.log(`Loading workers source completed!`); // eslint-disable-line no-undef, no-console
1152
+ }
1300
1153
  }