@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,11 +1,49 @@
1
- import { Vector3, Matrix4, Vector4 } from '@math.gl/core';
2
- import { Ellipsoid } from '@math.gl/geospatial';
3
- import { DracoWriter } from '@loaders.gl/draco';
4
- import { encode, assert } from '@loaders.gl/core';
5
- import { concatenateArrayBuffers, concatenateTypedArrays } from '@loaders.gl/loader-utils';
6
- import md5 from 'md5';
7
- import { generateAttributes } from './geometry-attributes';
8
- import { createBoundingVolumesFromGeometry } from './coordinate-converter';
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.getPropertyTable = exports.convertAttributes = void 0;
30
+ const core_1 = require("@math.gl/core");
31
+ const geospatial_1 = require("@math.gl/geospatial");
32
+ const draco_1 = require("@loaders.gl/draco");
33
+ const core_2 = require("@loaders.gl/core");
34
+ const loader_utils_1 = require("@loaders.gl/loader-utils");
35
+ const md5_1 = __importDefault(require("md5"));
36
+ const uuid_1 = require("uuid");
37
+ const geometry_attributes_1 = require("./geometry-attributes");
38
+ const coordinate_converter_1 = require("./coordinate-converter");
39
+ const gltf_attributes_1 = require("./gltf-attributes");
40
+ const batch_ids_extensions_1 = require("./batch-ids-extensions");
41
+ const feature_attributes_1 = require("./feature-attributes");
42
+ const math_1 = require("@loaders.gl/math");
43
+ const geometry_utils_1 = require("../../lib/utils/geometry-utils");
44
+ // Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md
45
+ const DEFAULT_ROUGHNESS_FACTOR = 1;
46
+ const DEFAULT_METALLIC_FACTOR = 1;
9
47
  const VALUES_PER_VERTEX = 3;
10
48
  const VALUES_PER_TEX_COORD = 2;
11
49
  const VALUES_PER_COLOR_ELEMENT = 4;
@@ -13,730 +51,1153 @@ const STRING_TYPE = 'string';
13
51
  const SHORT_INT_TYPE = 'Int32';
14
52
  const DOUBLE_TYPE = 'Float64';
15
53
  const OBJECT_ID_TYPE = 'Oid32';
54
+ /*
55
+ * 'CUSTOM_ATTRIBUTE_2' - Attribute name which includes batch info and used by New York map.
56
+ * _BATCHID - Default attribute name which includes batch info.
57
+ * BATCHID - Legacy attribute name which includes batch info.
58
+ */
16
59
  const BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES = ['CUSTOM_ATTRIBUTE_2', '_BATCHID', 'BATCHID'];
17
- let scratchVector = new Vector3();
18
- export default async function convertB3dmToI3sGeometry(tileContent, nodeId, featuresHashArray, attributeStorageInfo, draco, generateBoundingVolumes, geoidHeightModel) {
19
- const useCartesianPositions = generateBoundingVolumes;
20
- const materialAndTextureList = convertMaterials(tileContent);
21
- const convertedAttributesMap = convertAttributes(tileContent, useCartesianPositions);
22
-
23
- if (generateBoundingVolumes) {
24
- _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeightModel);
25
- }
26
-
27
- if (convertedAttributesMap.has('default')) {
28
- materialAndTextureList.push({
29
- material: getDefaultMaterial()
30
- });
31
- }
32
-
33
- const result = [];
34
- let nodesCounter = nodeId;
35
- let {
36
- materials = []
37
- } = tileContent.gltf;
38
-
39
- if (!(materials !== null && materials !== void 0 && materials.length)) {
40
- materials.push({
41
- id: 'default'
42
- });
43
- }
44
-
45
- for (let i = 0; i < materials.length; i++) {
46
- const sourceMaterial = materials[i];
47
-
48
- if (!convertedAttributesMap.has(sourceMaterial.id)) {
49
- continue;
50
- }
51
-
52
- const convertedAttributes = convertedAttributesMap.get(sourceMaterial.id);
53
- const {
54
- material,
55
- texture
56
- } = materialAndTextureList[i];
57
- result.push(await _makeNodeResources({
58
- convertedAttributes,
59
- material,
60
- texture,
61
- tileContent,
62
- nodeId: nodesCounter,
63
- featuresHashArray,
64
- attributeStorageInfo,
65
- draco
66
- }));
67
- nodesCounter++;
68
- }
69
-
70
- if (!result.length) {
71
- return null;
72
- }
73
-
74
- return result;
60
+ const EXT_FEATURE_METADATA = 'EXT_feature_metadata';
61
+ const EXT_MESH_FEATURES = 'EXT_mesh_features';
62
+ let scratchVector = new core_1.Vector3();
63
+ /**
64
+ * Convert binary data from b3dm file to i3s resources
65
+ *
66
+ * @param tileContent - 3d tile content
67
+ * @param addNodeToNodePage - function to add new node to node pages
68
+ * @param propertyTable - batch table (corresponding to feature attributes data)
69
+ * @param featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes
70
+ * @param attributeStorageInfo - attributes metadata from 3DSceneLayer json
71
+ * @param draco - is converter should create draco compressed geometry
72
+ * @param generateBoundingVolumes - is converter should create accurate bounding voulmes from geometry attributes
73
+ * @param shouldMergeMaterials - Try to merge similar materials to be able to merge meshes into one node
74
+ * @param geoidHeightModel - model to convert elevation from elipsoidal to geoid
75
+ * @param workerSource - source code of used workers
76
+ * @returns Array of node resources to create one or more i3s nodes
77
+ */
78
+ async function convertB3dmToI3sGeometry(tileContent, addNodeToNodePage, propertyTable, featuresHashArray, attributeStorageInfo, draco, generateBoundingVolumes, shouldMergeMaterials, geoidHeightModel, workerSource) {
79
+ const useCartesianPositions = generateBoundingVolumes;
80
+ const materialAndTextureList = await convertMaterials(tileContent.gltf?.materials, shouldMergeMaterials);
81
+ const dataForAttributesConversion = (0, gltf_attributes_1.prepareDataForAttributesConversion)(tileContent);
82
+ const convertedAttributesMap = await convertAttributes(dataForAttributesConversion, materialAndTextureList, useCartesianPositions);
83
+ /** Usage of worker here brings more overhead than advantage */
84
+ // const convertedAttributesMap: Map<string, ConvertedAttributes> =
85
+ // await transformI3SAttributesOnWorker(dataForAttributesConversion, {
86
+ // reuseWorkers: true,
87
+ // _nodeWorkers: true,
88
+ // useCartesianPositions,
89
+ // source: workerSource.I3SAttributes
90
+ // });
91
+ if (generateBoundingVolumes) {
92
+ _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeightModel);
93
+ }
94
+ const result = [];
95
+ for (const materialAndTexture of materialAndTextureList) {
96
+ const originarMaterialId = materialAndTexture.mergedMaterials[0].originalMaterialId;
97
+ if (!convertedAttributesMap.has(originarMaterialId)) {
98
+ continue; // eslint-disable-line no-continue
99
+ }
100
+ const convertedAttributes = convertedAttributesMap.get(originarMaterialId);
101
+ if (!convertedAttributes) {
102
+ continue;
103
+ }
104
+ const { material, texture } = materialAndTexture;
105
+ const nodeId = await addNodeToNodePage();
106
+ result.push(await _makeNodeResources({
107
+ convertedAttributes,
108
+ material,
109
+ texture,
110
+ tileContent,
111
+ nodeId,
112
+ featuresHashArray,
113
+ propertyTable,
114
+ attributeStorageInfo,
115
+ draco,
116
+ workerSource
117
+ }));
118
+ }
119
+ if (!result.length) {
120
+ return null;
121
+ }
122
+ return result;
75
123
  }
76
-
124
+ exports.default = convertB3dmToI3sGeometry;
125
+ /**
126
+ * Create bounding volumes based on positions
127
+ * @param convertedAttributesMap - geometry attributes map
128
+ * @param geoidHeightModel - geoid height model to convert elevation from elipsoidal to geoid
129
+ */
77
130
  function _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeightModel) {
78
- for (const attributes of convertedAttributesMap.values()) {
79
- const boundingVolumes = createBoundingVolumesFromGeometry(attributes.positions, geoidHeightModel);
80
- attributes.boundingVolumes = boundingVolumes;
81
- const cartographicOrigin = boundingVolumes.obb.center;
82
-
83
- for (let index = 0; index < attributes.positions.length; index += VALUES_PER_VERTEX) {
84
- const vertex = attributes.positions.subarray(index, index + VALUES_PER_VERTEX);
85
- Ellipsoid.WGS84.cartesianToCartographic(Array.from(vertex), scratchVector);
86
- scratchVector[2] = scratchVector[2] - geoidHeightModel.getHeight(scratchVector[1], scratchVector[0]);
87
- scratchVector = scratchVector.subtract(cartographicOrigin);
88
- attributes.positions.set(scratchVector, index);
89
- }
90
- }
91
- }
92
-
93
- async function _makeNodeResources({
94
- convertedAttributes,
95
- material,
96
- texture,
97
- tileContent,
98
- nodeId,
99
- featuresHashArray,
100
- attributeStorageInfo,
101
- draco
102
- }) {
103
- const boundingVolumes = convertedAttributes.boundingVolumes;
104
- const vertexCount = convertedAttributes.positions.length / VALUES_PER_VERTEX;
105
- const triangleCount = vertexCount / 3;
106
- const {
107
- faceRange,
108
- featureIds,
109
- positions,
110
- normals,
111
- colors,
112
- texCoords,
113
- featureCount
114
- } = generateAttributes({
115
- triangleCount,
116
- ...convertedAttributes
117
- });
118
-
119
- if (tileContent.batchTableJson) {
120
- makeFeatureIdsUnique(featureIds, convertedAttributes.featureIndices, featuresHashArray, tileContent.batchTableJson);
121
- }
122
-
123
- const header = new Uint32Array(2);
124
- const typedFeatureIds = generateBigUint64Array(featureIds);
125
- header.set([vertexCount, featureCount], 0);
126
- const fileBuffer = new Uint8Array(concatenateArrayBuffers(header.buffer, positions.buffer, normals.buffer, texture ? texCoords.buffer : new ArrayBuffer(0), colors.buffer, typedFeatureIds.buffer, faceRange.buffer));
127
- const compressedGeometry = draco ? await generateCompressedGeometry(vertexCount, convertedAttributes, {
128
- positions,
129
- normals,
130
- texCoords: texture ? texCoords : new Float32Array(0),
131
- colors,
132
- featureIds,
133
- faceRange
134
- }) : null;
135
- const attributes = convertBatchTableToAttributeBuffers(tileContent.batchTableJson, featureIds, attributeStorageInfo);
136
- return {
137
- geometry: fileBuffer,
138
- compressedGeometry,
139
- texture,
140
- sharedResources: getSharedResources(tileContent, nodeId),
141
- meshMaterial: material,
142
- vertexCount,
143
- attributes,
144
- featureCount,
145
- boundingVolumes
146
- };
147
- }
148
-
149
- function convertAttributes(tileContent, useCartesianPositions) {
150
- var _tileContent$gltf$sce;
151
-
152
- const attributesMap = new Map();
153
-
154
- for (const material of tileContent.gltf.materials || [{
155
- id: 'default'
156
- }]) {
157
- attributesMap.set(material.id, {
158
- positions: new Float32Array(0),
159
- normals: new Float32Array(0),
160
- texCoords: new Float32Array(0),
161
- colors: new Uint8Array(0),
162
- featureIndices: [],
163
- boundingVolumes: null
164
- });
165
- }
166
-
167
- const nodes = (tileContent.gltf.scene || ((_tileContent$gltf$sce = tileContent.gltf.scenes) === null || _tileContent$gltf$sce === void 0 ? void 0 : _tileContent$gltf$sce[0]) || tileContent.gltf).nodes;
168
- convertNodes(nodes, tileContent, attributesMap, useCartesianPositions);
169
-
170
- for (const attrKey of attributesMap.keys()) {
171
- const attributes = attributesMap.get(attrKey);
172
-
173
- if (attributes.positions.length === 0) {
174
- attributesMap.delete(attrKey);
175
- continue;
176
- }
177
-
178
- attributes.featureIndices = attributes.featureIndices.reduce((acc, value) => acc.concat(value));
179
- }
180
-
181
- return attributesMap;
182
- }
183
-
184
- function convertNodes(nodes, tileContent, attributesMap, useCartesianPositions, matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
185
- if (nodes) {
186
- for (const node of nodes) {
187
- convertNode(node, tileContent, attributesMap, useCartesianPositions, matrix);
188
- }
189
- }
190
- }
191
-
131
+ for (const attributes of convertedAttributesMap.values()) {
132
+ const boundingVolumes = (0, coordinate_converter_1.createBoundingVolumesFromGeometry)(attributes.positions, geoidHeightModel);
133
+ attributes.boundingVolumes = boundingVolumes;
134
+ const cartographicOrigin = boundingVolumes.obb.center;
135
+ for (let index = 0; index < attributes.positions.length; index += VALUES_PER_VERTEX) {
136
+ const vertex = attributes.positions.subarray(index, index + VALUES_PER_VERTEX);
137
+ geospatial_1.Ellipsoid.WGS84.cartesianToCartographic(Array.from(vertex), scratchVector);
138
+ scratchVector[2] =
139
+ scratchVector[2] - geoidHeightModel.getHeight(scratchVector[1], scratchVector[0]);
140
+ scratchVector = scratchVector.subtract(cartographicOrigin);
141
+ attributes.positions.set(scratchVector, index);
142
+ }
143
+ }
144
+ }
145
+ /**
146
+ *
147
+ * @param params
148
+ * @param params.convertedAttributes - Converted geometry attributes
149
+ * @param params.material - I3S PBR-like material definition
150
+ * @param params.texture - texture content
151
+ * @param params.tileContent - B3DM decoded content
152
+ * @param params.nodeId - new node ID
153
+ * @param params.featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes
154
+ * @param params.propertyTable - batch table (corresponding to feature attributes data)
155
+ * @param params.attributeStorageInfo - attributes metadata from 3DSceneLayer json
156
+ * @param params.draco - is converter should create draco compressed geometry
157
+ * @param params.workerSource - source code of used workers
158
+ * @returns Array of I3S node resources
159
+ */
160
+ async function _makeNodeResources({ convertedAttributes, material, texture, tileContent, nodeId, featuresHashArray, propertyTable, attributeStorageInfo, draco, workerSource }) {
161
+ const boundingVolumes = convertedAttributes.boundingVolumes;
162
+ const vertexCount = convertedAttributes.positions.length / VALUES_PER_VERTEX;
163
+ const { faceRange, featureIds, positions, normals, colors, uvRegions, texCoords, featureCount } = (0, geometry_attributes_1.generateAttributes)(convertedAttributes);
164
+ if (tileContent.batchTableJson) {
165
+ makeFeatureIdsUnique(featureIds, convertedAttributes.featureIndices, featuresHashArray, tileContent.batchTableJson);
166
+ }
167
+ const header = new Uint32Array(2);
168
+ const typedFeatureIds = generateBigUint64Array(featureIds);
169
+ header.set([vertexCount, featureCount], 0);
170
+ const fileBuffer = new Uint8Array((0, loader_utils_1.concatenateArrayBuffers)(header.buffer, positions.buffer, normals.buffer, texture ? texCoords.buffer : new ArrayBuffer(0), colors.buffer, uvRegions, typedFeatureIds.buffer, faceRange.buffer));
171
+ const compressedGeometry = draco
172
+ ? generateCompressedGeometry(vertexCount, convertedAttributes, {
173
+ positions,
174
+ normals,
175
+ texCoords: texture ? texCoords : new Float32Array(0),
176
+ colors,
177
+ uvRegions,
178
+ featureIds,
179
+ faceRange
180
+ }, workerSource.draco)
181
+ : null;
182
+ let attributes = [];
183
+ if (attributeStorageInfo && propertyTable) {
184
+ attributes = convertPropertyTableToAttributeBuffers(featureIds, propertyTable, attributeStorageInfo);
185
+ }
186
+ return {
187
+ nodeId,
188
+ geometry: fileBuffer,
189
+ compressedGeometry,
190
+ texture,
191
+ hasUvRegions: Boolean(uvRegions.length),
192
+ sharedResources: getSharedResources(tileContent.gltf?.materials || [], nodeId),
193
+ meshMaterial: material,
194
+ vertexCount,
195
+ attributes,
196
+ featureCount,
197
+ boundingVolumes
198
+ };
199
+ }
200
+ /**
201
+ * Convert attributes from the gltf nodes tree to i3s plain geometry
202
+ * @param attributesData - geometry attributes from gltf
203
+ * @param materialAndTextureList - array of data about materials and textures of the content
204
+ * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
205
+ * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
206
+ * @returns map of converted geometry attributes
207
+ */
208
+ async function convertAttributes(attributesData, materialAndTextureList, useCartesianPositions) {
209
+ const { nodes, images, cartographicOrigin, cartesianModelMatrix } = attributesData;
210
+ const attributesMap = new Map();
211
+ for (const materialAndTexture of materialAndTextureList) {
212
+ const attributes = {
213
+ positions: new Float32Array(0),
214
+ normals: new Float32Array(0),
215
+ texCoords: new Float32Array(0),
216
+ colors: new Uint8Array(0),
217
+ uvRegions: new Uint16Array(0),
218
+ featureIndicesGroups: [],
219
+ featureIndices: [],
220
+ boundingVolumes: null,
221
+ mergedMaterials: materialAndTexture.mergedMaterials
222
+ };
223
+ for (const mergedMaterial of materialAndTexture.mergedMaterials) {
224
+ attributesMap.set(mergedMaterial.originalMaterialId, attributes);
225
+ }
226
+ }
227
+ convertNodes(nodes, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions);
228
+ for (const attrKey of attributesMap.keys()) {
229
+ const attributes = attributesMap.get(attrKey);
230
+ if (!attributes) {
231
+ continue;
232
+ }
233
+ if (attributes.positions.length === 0) {
234
+ attributesMap.delete(attrKey);
235
+ continue; // eslint-disable-line no-continue
236
+ }
237
+ if (attributes.featureIndicesGroups) {
238
+ attributes.featureIndices = attributes.featureIndicesGroups.reduce((acc, value) => acc.concat(value));
239
+ delete attributes.featureIndicesGroups;
240
+ }
241
+ }
242
+ return attributesMap;
243
+ }
244
+ exports.convertAttributes = convertAttributes;
245
+ /**
246
+ * Gltf has hierarchical structure of nodes. This function converts nodes starting from those which are in gltf scene object.
247
+ * The goal is applying tranformation matrix for all children. Functions "convertNodes" and "convertNode" work together recursively.
248
+ * @param nodes - gltf nodes array
249
+ * @param images - gltf images array
250
+ * @param cartographicOrigin - cartographic origin of bounding volume
251
+ * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic
252
+ * @param attributesMap - for recursive concatenation of attributes
253
+ * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
254
+ * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
255
+ * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
256
+ * @returns {void}
257
+ */
258
+ function convertNodes(nodes, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
259
+ if (nodes) {
260
+ for (const node of nodes) {
261
+ convertNode(node, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix);
262
+ }
263
+ }
264
+ }
265
+ /**
266
+ * Generate transformation matrix for node
267
+ * Aapply all gltf transformations to initial transformation matrix.
268
+ * @param node
269
+ * @param matrix
270
+ */
192
271
  function getCompositeTransformationMatrix(node, matrix) {
193
- let transformationMatrix = matrix;
194
- const {
195
- matrix: nodeMatrix,
196
- rotation,
197
- scale,
198
- translation
199
- } = node;
200
-
201
- if (nodeMatrix) {
202
- transformationMatrix = matrix.multiplyRight(nodeMatrix);
203
- }
204
-
205
- if (rotation) {
206
- transformationMatrix = transformationMatrix.rotateXYZ(rotation);
207
- }
208
-
209
- if (scale) {
210
- transformationMatrix = transformationMatrix.scale(scale);
211
- }
212
-
213
- if (translation) {
214
- transformationMatrix = transformationMatrix.translate(translation);
215
- }
216
-
217
- return transformationMatrix;
218
- }
219
-
220
- function convertNode(node, tileContent, attributesMap, useCartesianPositions, matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
221
- const transformationMatrix = getCompositeTransformationMatrix(node, matrix);
222
- const mesh = node.mesh;
223
-
224
- if (mesh) {
225
- convertMesh(mesh, tileContent, attributesMap, useCartesianPositions, transformationMatrix);
226
- }
227
-
228
- convertNodes(node.children, tileContent, attributesMap, useCartesianPositions, transformationMatrix);
229
- }
230
-
231
- function convertMesh(mesh, content, attributesMap, useCartesianPositions = false, matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
232
- for (const primitive of mesh.primitives) {
233
- let outputAttributes = null;
234
-
235
- if (primitive.material) {
236
- outputAttributes = attributesMap.get(primitive.material.id);
237
- } else if (attributesMap.has('default')) {
238
- outputAttributes = attributesMap.get('default');
239
- }
240
-
241
- assert(outputAttributes !== null, 'Primitive - material mapping failed');
242
- const attributes = primitive.attributes;
243
- outputAttributes.positions = concatenateTypedArrays(outputAttributes.positions, transformVertexArray({
244
- vertices: attributes.POSITION.value,
245
- cartographicOrigin: content.cartographicOrigin,
246
- cartesianModelMatrix: content.cartesianModelMatrix,
247
- nodeMatrix: matrix,
248
- indices: primitive.indices.value,
249
- attributeSpecificTransformation: transformVertexPositions,
250
- useCartesianPositions
251
- }));
252
- outputAttributes.normals = concatenateTypedArrays(outputAttributes.normals, transformVertexArray({
253
- vertices: attributes.NORMAL && attributes.NORMAL.value,
254
- cartographicOrigin: content.cartographicOrigin,
255
- cartesianModelMatrix: content.cartesianModelMatrix,
256
- nodeMatrix: matrix,
257
- indices: primitive.indices.value,
258
- attributeSpecificTransformation: transformVertexNormals,
259
- useCartesianPositions: false
260
- }));
261
- outputAttributes.texCoords = concatenateTypedArrays(outputAttributes.texCoords, flattenTexCoords(attributes.TEXCOORD_0 && attributes.TEXCOORD_0.value, primitive.indices.value));
262
- outputAttributes.colors = concatenateTypedArrays(outputAttributes.colors, flattenColors(attributes.COLOR_0, primitive.indices.value));
263
- outputAttributes.featureIndices.push(flattenBatchIds(getBatchIdsByAttributeName(attributes), primitive.indices.value));
264
- }
265
- }
266
-
272
+ let transformationMatrix = matrix;
273
+ const { matrix: nodeMatrix, rotation, scale, translation } = node;
274
+ if (nodeMatrix) {
275
+ transformationMatrix = matrix.multiplyRight(nodeMatrix);
276
+ }
277
+ if (translation) {
278
+ transformationMatrix = transformationMatrix.translate(translation);
279
+ }
280
+ if (rotation) {
281
+ transformationMatrix = transformationMatrix.rotateXYZ(rotation);
282
+ }
283
+ if (scale) {
284
+ transformationMatrix = transformationMatrix.scale(scale);
285
+ }
286
+ return transformationMatrix;
287
+ }
288
+ /**
289
+ * Convert all primitives of node and all children nodes
290
+ * @param node - gltf node
291
+ * @param images - gltf images array
292
+ * @param cartographicOrigin - cartographic origin of bounding volume
293
+ * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic
294
+ * @param {Map} attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
295
+ * attributes
296
+ * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
297
+ * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
298
+ * @param {Matrix4} matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
299
+ */
300
+ function convertNode(node, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
301
+ const transformationMatrix = getCompositeTransformationMatrix(node, matrix);
302
+ const mesh = node.mesh;
303
+ if (mesh) {
304
+ convertMesh(mesh, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, transformationMatrix);
305
+ }
306
+ convertNodes(node.children || [], images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, transformationMatrix);
307
+ }
308
+ /**
309
+ * Convert all primitives of the mesh
310
+ * @param mesh - gltf mesh data
311
+ * @param images - gltf images array
312
+ * @param cartographicOrigin - cartographic origin of bounding volume
313
+ * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic
314
+ * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
315
+ * attributes
316
+ * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
317
+ * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
318
+ * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
319
+ * attributes
320
+
321
+ * @param {Matrix4} matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
322
+ */
323
+ function convertMesh(mesh, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions = false, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
324
+ for (const primitive of mesh.primitives) {
325
+ let outputAttributes = null;
326
+ let materialUvRegion;
327
+ if (primitive.material) {
328
+ outputAttributes = attributesMap.get(primitive.material.id);
329
+ materialUvRegion = outputAttributes?.mergedMaterials.find(({ originalMaterialId }) => originalMaterialId === primitive.material?.id)?.uvRegion;
330
+ }
331
+ else if (attributesMap.has('default')) {
332
+ outputAttributes = attributesMap.get('default');
333
+ }
334
+ (0, core_2.assert)(outputAttributes !== null, 'Primitive - material mapping failed');
335
+ (0, core_2.assert)(primitive.mode === math_1.GL.TRIANGLES || primitive.mode === math_1.GL.TRIANGLE_STRIP, `Primitive - unsupported mode ${primitive.mode}`);
336
+ const attributes = primitive.attributes;
337
+ if (!outputAttributes) {
338
+ continue;
339
+ }
340
+ const indices = normalizeIndices(primitive);
341
+ outputAttributes.positions = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.positions, transformVertexArray({
342
+ vertices: attributes.POSITION.value,
343
+ cartographicOrigin,
344
+ cartesianModelMatrix,
345
+ nodeMatrix: matrix,
346
+ indices,
347
+ attributeSpecificTransformation: transformVertexPositions,
348
+ useCartesianPositions
349
+ }));
350
+ outputAttributes.normals = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.normals, transformVertexArray({
351
+ vertices: attributes.NORMAL && attributes.NORMAL.value,
352
+ cartographicOrigin,
353
+ cartesianModelMatrix,
354
+ nodeMatrix: matrix,
355
+ indices,
356
+ attributeSpecificTransformation: transformVertexNormals,
357
+ useCartesianPositions: false
358
+ }));
359
+ outputAttributes.texCoords = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.texCoords, flattenTexCoords(attributes.TEXCOORD_0 && attributes.TEXCOORD_0.value, indices));
360
+ outputAttributes.colors = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.colors, flattenColors(attributes.COLOR_0, indices));
361
+ if (materialUvRegion) {
362
+ outputAttributes.uvRegions = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.uvRegions, createUvRegion(materialUvRegion, indices));
363
+ }
364
+ outputAttributes.featureIndicesGroups = outputAttributes.featureIndicesGroups || [];
365
+ outputAttributes.featureIndicesGroups.push(flattenBatchIds(getBatchIds(attributes, primitive, images), indices));
366
+ }
367
+ }
368
+ /**
369
+ * Converts TRIANGLE-STRIPS to independent TRIANGLES
370
+ * @param primitive - the primitive to get the indices from
371
+ * @returns indices of vertices of the independent triangles
372
+ */
373
+ function normalizeIndices(primitive) {
374
+ let indices = primitive.indices?.value;
375
+ if (!indices) {
376
+ const positions = primitive.attributes.POSITION.value;
377
+ return (0, geometry_utils_1.generateSyntheticIndices)(positions.length / VALUES_PER_VERTEX);
378
+ }
379
+ if (indices && primitive.mode === math_1.GL.TRIANGLE_STRIP) {
380
+ /*
381
+ TRIANGLE_STRIP geometry contains n+2 vertices for n triangles;
382
+ TRIANGLE geometry contains n*3 vertices for n triangles.
383
+ The conversion from TRIANGLE_STRIP to TRIANGLE implies duplicating adjacent vertices.
384
+ */
385
+ const TypedArrayConstructor = indices.constructor;
386
+ const newIndices = new TypedArrayConstructor((indices.length - 2) * 3);
387
+ // Copy the first triangle indices with no modification like [i0, i1, i2, ...] -> [i0, i1, i2, ...]
388
+ let triangleIndex = 0;
389
+ let currentTriangle = indices.slice(0, 3);
390
+ newIndices.set(currentTriangle, 0);
391
+ // The rest triangle indices are being taken from strips using the following logic:
392
+ // [i1, i2, i3, i4, i5, i6, ...] -> [i3, i2, i1, i2, i3, i4, i5, i4, i3, i4, i5, i6, ...]
393
+ for (let i = 1; i + 2 < indices.length; i++) {
394
+ triangleIndex += 3;
395
+ currentTriangle = indices.slice(i, i + 3);
396
+ if (i % 2 === 0) {
397
+ newIndices.set(currentTriangle, triangleIndex);
398
+ }
399
+ else {
400
+ // The following "reverce" is necessary to calculate normals correctly
401
+ newIndices.set(currentTriangle.reverse(), triangleIndex);
402
+ }
403
+ }
404
+ indices = newIndices;
405
+ }
406
+ return indices;
407
+ }
408
+ /**
409
+ * Convert vertices attributes (POSITIONS or NORMALS) to i3s compatible format
410
+ * @param args
411
+ * @param args.vertices - gltf primitive POSITION or NORMAL attribute
412
+ * @param args.cartographicOrigin - cartographic origin coordinates
413
+ * @param args.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format
414
+ * @param args.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices
415
+ * @param args.indices - gltf primitive indices
416
+ * @param args.attributeSpecificTransformation - function to do attribute - specific transformations
417
+ * @param args.useCartesianPositions - use coordinates as it is.
418
+ * @returns
419
+ */
267
420
  function transformVertexArray(args) {
268
- const {
269
- vertices,
270
- indices,
271
- attributeSpecificTransformation
272
- } = args;
273
- const newVertices = new Float32Array(indices.length * VALUES_PER_VERTEX);
274
-
275
- if (!vertices) {
421
+ const { vertices, indices, attributeSpecificTransformation } = args;
422
+ const newVertices = new Float32Array(indices.length * VALUES_PER_VERTEX);
423
+ if (!vertices) {
424
+ return newVertices;
425
+ }
426
+ for (let i = 0; i < indices.length; i++) {
427
+ const coordIndex = indices[i] * VALUES_PER_VERTEX;
428
+ const vertex = vertices.subarray(coordIndex, coordIndex + VALUES_PER_VERTEX);
429
+ let vertexVector = new core_1.Vector3(Array.from(vertex));
430
+ vertexVector = attributeSpecificTransformation(vertexVector, args);
431
+ newVertices[i * VALUES_PER_VERTEX] = vertexVector.x;
432
+ newVertices[i * VALUES_PER_VERTEX + 1] = vertexVector.y;
433
+ newVertices[i * VALUES_PER_VERTEX + 2] = vertexVector.z;
434
+ }
276
435
  return newVertices;
277
- }
278
-
279
- for (let i = 0; i < indices.length; i++) {
280
- const coordIndex = indices[i] * VALUES_PER_VERTEX;
281
- const vertex = vertices.subarray(coordIndex, coordIndex + VALUES_PER_VERTEX);
282
- let vertexVector = new Vector3(Array.from(vertex));
283
- vertexVector = attributeSpecificTransformation(vertexVector, args);
284
- newVertices[i * VALUES_PER_VERTEX] = vertexVector.x;
285
- newVertices[i * VALUES_PER_VERTEX + 1] = vertexVector.y;
286
- newVertices[i * VALUES_PER_VERTEX + 2] = vertexVector.z;
287
- }
288
-
289
- return newVertices;
290
- }
291
-
436
+ }
437
+ /**
438
+ * Trasform positions vector with the attribute specific transformations
439
+ * @param vertexVector - source positions vector to transform
440
+ * @param calleeArgs
441
+ * @param calleeArgs.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format
442
+ * @param calleeArgs.cartographicOrigin - cartographic origin coordinates
443
+ * @param calleeArgs.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices
444
+ * @param calleeArgs.useCartesianPositions - use coordinates as it is.
445
+ * @returns transformed positions vector
446
+ */
292
447
  function transformVertexPositions(vertexVector, calleeArgs) {
293
- const {
294
- cartesianModelMatrix,
295
- cartographicOrigin,
296
- nodeMatrix,
297
- useCartesianPositions
298
- } = calleeArgs;
299
-
300
- if (nodeMatrix) {
301
- vertexVector = vertexVector.transform(nodeMatrix);
302
- }
303
-
304
- vertexVector = vertexVector.transform(cartesianModelMatrix);
305
-
306
- if (useCartesianPositions) {
448
+ const { cartesianModelMatrix, cartographicOrigin, nodeMatrix, useCartesianPositions } = calleeArgs;
449
+ if (nodeMatrix) {
450
+ vertexVector = vertexVector.transform(nodeMatrix);
451
+ }
452
+ vertexVector = vertexVector.transform(cartesianModelMatrix);
453
+ if (useCartesianPositions) {
454
+ return vertexVector;
455
+ }
456
+ geospatial_1.Ellipsoid.WGS84.cartesianToCartographic([vertexVector[0], vertexVector[1], vertexVector[2]], vertexVector);
457
+ vertexVector = vertexVector.subtract(cartographicOrigin);
307
458
  return vertexVector;
308
- }
309
-
310
- Ellipsoid.WGS84.cartesianToCartographic([vertexVector[0], vertexVector[1], vertexVector[2]], vertexVector);
311
- vertexVector = vertexVector.subtract(cartographicOrigin);
312
- return vertexVector;
313
459
  }
314
-
460
+ /**
461
+ * Trasform normals vector with the attribute specific transformations
462
+ * @param vertexVector - source normals vector to transform
463
+ * @param calleeArgs
464
+ * @param calleeArgs.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format
465
+ * @param calleeArgs.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices
466
+ * @returns transformed normals vector
467
+ */
315
468
  function transformVertexNormals(vertexVector, calleeArgs) {
316
- const {
317
- cartesianModelMatrix,
318
- nodeMatrix
319
- } = calleeArgs;
320
-
321
- if (nodeMatrix) {
322
- vertexVector = vertexVector.transformAsVector(nodeMatrix);
323
- }
324
-
325
- vertexVector = vertexVector.transformAsVector(cartesianModelMatrix);
326
- return vertexVector;
327
- }
328
-
469
+ const { cartesianModelMatrix, nodeMatrix } = calleeArgs;
470
+ if (nodeMatrix) {
471
+ vertexVector = vertexVector.transformAsVector(nodeMatrix);
472
+ }
473
+ vertexVector = vertexVector.transformAsVector(cartesianModelMatrix);
474
+ return vertexVector;
475
+ }
476
+ /**
477
+ * Convert uv0 (texture coordinates) from coords based on indices to plain arrays, compatible with i3s
478
+ * @param texCoords - gltf primitive TEXCOORD_0 attribute
479
+ * @param indices - gltf primitive indices
480
+ * @returns flattened texture coordinates
481
+ */
329
482
  function flattenTexCoords(texCoords, indices) {
330
- const newTexCoords = new Float32Array(indices.length * VALUES_PER_TEX_COORD);
331
-
332
- if (!texCoords) {
333
- newTexCoords.fill(1);
483
+ const newTexCoords = new Float32Array(indices.length * VALUES_PER_TEX_COORD);
484
+ if (!texCoords) {
485
+ // We need dummy UV0s because it is required in 1.6
486
+ // https://github.com/Esri/i3s-spec/blob/master/docs/1.6/vertexAttribute.cmn.md
487
+ newTexCoords.fill(1);
488
+ return newTexCoords;
489
+ }
490
+ for (let i = 0; i < indices.length; i++) {
491
+ const coordIndex = indices[i] * VALUES_PER_TEX_COORD;
492
+ const texCoord = texCoords.subarray(coordIndex, coordIndex + VALUES_PER_TEX_COORD);
493
+ newTexCoords[i * VALUES_PER_TEX_COORD] = texCoord[0];
494
+ newTexCoords[i * VALUES_PER_TEX_COORD + 1] = texCoord[1];
495
+ }
334
496
  return newTexCoords;
335
- }
336
-
337
- for (let i = 0; i < indices.length; i++) {
338
- const coordIndex = indices[i] * VALUES_PER_TEX_COORD;
339
- const texCoord = texCoords.subarray(coordIndex, coordIndex + VALUES_PER_TEX_COORD);
340
- newTexCoords[i * VALUES_PER_TEX_COORD] = texCoord[0];
341
- newTexCoords[i * VALUES_PER_TEX_COORD + 1] = texCoord[1];
342
- }
343
-
344
- return newTexCoords;
345
- }
346
-
497
+ }
498
+ /**
499
+ * Convert color from COLOR_0 based on indices to plain arrays, compatible with i3s
500
+ * @param colorsAttribute - gltf primitive COLOR_0 attribute
501
+ * @param indices - gltf primitive indices
502
+ * @returns flattened colors attribute
503
+ */
347
504
  function flattenColors(colorsAttribute, indices) {
348
- const components = (colorsAttribute === null || colorsAttribute === void 0 ? void 0 : colorsAttribute.components) || VALUES_PER_COLOR_ELEMENT;
349
- const newColors = new Uint8Array(indices.length * components);
350
-
351
- if (!colorsAttribute) {
352
- newColors.fill(255);
505
+ const components = colorsAttribute?.components || VALUES_PER_COLOR_ELEMENT;
506
+ const newColors = new Uint8Array(indices.length * components);
507
+ if (!colorsAttribute) {
508
+ // Vertex color multiplies by material color so it must be normalized 1 by default
509
+ newColors.fill(255);
510
+ return newColors;
511
+ }
512
+ const colors = colorsAttribute.value;
513
+ for (let i = 0; i < indices.length; i++) {
514
+ const colorIndex = indices[i] * components;
515
+ const color = colors.subarray(colorIndex, colorIndex + components);
516
+ const colorUint8 = new Uint8Array(components);
517
+ for (let j = 0; j < color.length; j++) {
518
+ colorUint8[j] = color[j] * 255;
519
+ }
520
+ newColors.set(colorUint8, i * components);
521
+ }
353
522
  return newColors;
354
- }
355
-
356
- const colors = colorsAttribute.value;
357
-
358
- for (let i = 0; i < indices.length; i++) {
359
- const colorIndex = indices[i] * components;
360
- const color = colors.subarray(colorIndex, colorIndex + components);
361
- const colorUint8 = new Uint8Array(components);
362
-
363
- for (let j = 0; j < color.length; j++) {
364
- colorUint8[j] = color[j] * 255;
365
- }
366
-
367
- newColors.set(colorUint8, i * components);
368
- }
369
-
370
- return newColors;
371
- }
372
-
523
+ }
524
+ /**
525
+ * Create per-vertex uv-region array
526
+ * @param materialUvRegion - uv-region fragment for a single vertex
527
+ * @param indices - geometry indices data
528
+ * @returns - uv-region array
529
+ */
530
+ function createUvRegion(materialUvRegion, indices) {
531
+ const result = new Uint16Array(indices.length * 4);
532
+ for (let i = 0; i < result.length; i += 4) {
533
+ result.set(materialUvRegion, i);
534
+ }
535
+ return result;
536
+ }
537
+ /**
538
+ * Flatten batchedIds list based on indices to right ordered array, compatible with i3s
539
+ * @param batchedIds - gltf primitive
540
+ * @param indices - gltf primitive indices
541
+ * @returns flattened batch ids
542
+ */
373
543
  function flattenBatchIds(batchedIds, indices) {
374
- if (!batchedIds.length || !indices.length) {
544
+ if (!batchedIds.length || !indices.length) {
545
+ return [];
546
+ }
547
+ const newBatchIds = [];
548
+ for (let i = 0; i < indices.length; i++) {
549
+ const coordIndex = indices[i];
550
+ newBatchIds.push(batchedIds[coordIndex]);
551
+ }
552
+ return newBatchIds;
553
+ }
554
+ /**
555
+ * Get batchIds for featureIds creation
556
+ * @param attributes - gltf accessors
557
+ * @param primitive - gltf primitive data
558
+ * @param images - gltf texture images
559
+ */
560
+ function getBatchIds(attributes, primitive, images) {
561
+ const batchIds = (0, batch_ids_extensions_1.handleBatchIdsExtensions)(attributes, primitive, images);
562
+ if (batchIds.length) {
563
+ return batchIds;
564
+ }
565
+ for (let index = 0; index < BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES.length; index++) {
566
+ const possibleBatchIdAttributeName = BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES[index];
567
+ if (attributes[possibleBatchIdAttributeName] &&
568
+ attributes[possibleBatchIdAttributeName].value) {
569
+ return attributes[possibleBatchIdAttributeName].value;
570
+ }
571
+ }
375
572
  return [];
376
- }
377
-
378
- const newBatchIds = [];
379
-
380
- for (let i = 0; i < indices.length; i++) {
381
- const coordIndex = indices[i];
382
- newBatchIds.push(batchedIds[coordIndex]);
383
- }
384
-
385
- return newBatchIds;
386
- }
387
-
388
- function getBatchIdsByAttributeName(attributes) {
389
- let batchIds = [];
390
-
391
- for (let index = 0; index < BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES.length; index++) {
392
- const possibleBatchIdAttributeName = BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES[index];
393
-
394
- if (attributes[possibleBatchIdAttributeName] && attributes[possibleBatchIdAttributeName].value) {
395
- batchIds = attributes[possibleBatchIdAttributeName].value;
396
- break;
397
- }
398
- }
399
-
400
- return batchIds;
401
- }
402
-
403
- function convertMaterials(tileContent) {
404
- const result = [];
405
- const sourceMaterials = tileContent.gltf.materials || [];
406
-
407
- for (const sourceMaterial of sourceMaterials) {
408
- result.push(convertMaterial(sourceMaterial));
409
- }
410
-
411
- return result;
412
- }
413
-
573
+ }
574
+ /**
575
+ * Convert GLTF material to I3S material definitions and textures
576
+ * @param sourceMaterials Source GLTF materials
577
+ * @param shouldMergeMaterials - if true - the converter will try to merge similar materials
578
+ * to be able to merge primitives having those materials
579
+ * @returns Array of Couples I3SMaterialDefinition + texture content
580
+ */
581
+ async function convertMaterials(sourceMaterials = [], shouldMergeMaterials) {
582
+ let materials = [];
583
+ for (const sourceMaterial of sourceMaterials) {
584
+ materials.push(convertMaterial(sourceMaterial));
585
+ }
586
+ if (shouldMergeMaterials) {
587
+ materials = await mergeAllMaterials(materials);
588
+ }
589
+ return materials;
590
+ }
591
+ /**
592
+ * Merge materials when possible
593
+ * @param materials materials array
594
+ * @returns merged materials array
595
+ */
596
+ async function mergeAllMaterials(materials) {
597
+ const result = [];
598
+ while (materials.length > 0) {
599
+ let newMaterial = materials.splice(0, 1)[0];
600
+ const mergedIndices = [];
601
+ for (let i = 0; i < materials.length; i++) {
602
+ const material = materials[i];
603
+ if ((newMaterial.texture && material.texture) ||
604
+ (!newMaterial.texture && !material.texture)) {
605
+ newMaterial = await mergeMaterials(newMaterial, material);
606
+ mergedIndices.push(i);
607
+ }
608
+ }
609
+ if (newMaterial.texture && mergedIndices.length) {
610
+ const newWidth = newMaterial.mergedMaterials?.reduce((accum, { textureSize }) => accum + (textureSize?.width || 0), 0);
611
+ const newHeight = newMaterial.mergedMaterials?.reduce((accum, { textureSize }) => Math.max(accum, textureSize?.height || 0), 0);
612
+ let currentX = -1;
613
+ for (const aTextureMetadata of newMaterial.mergedMaterials) {
614
+ if (aTextureMetadata.textureSize) {
615
+ const newX = currentX +
616
+ 1 +
617
+ (aTextureMetadata.textureSize.width / newWidth) *
618
+ 2 ** (Uint16Array.BYTES_PER_ELEMENT * 8) -
619
+ 1;
620
+ aTextureMetadata.uvRegion = new Uint16Array([
621
+ currentX + 1,
622
+ 0,
623
+ newX,
624
+ (aTextureMetadata.textureSize.height / newHeight) *
625
+ 2 ** (Uint16Array.BYTES_PER_ELEMENT * 8) -
626
+ 1
627
+ ]);
628
+ currentX = newX;
629
+ }
630
+ }
631
+ newMaterial.texture.image.width = newWidth;
632
+ newMaterial.texture.image.height = newHeight;
633
+ }
634
+ for (const index of mergedIndices.reverse()) {
635
+ materials.splice(index, 1);
636
+ }
637
+ result.push(newMaterial);
638
+ }
639
+ if (!result.length) {
640
+ result.push({
641
+ material: getDefaultMaterial(),
642
+ mergedMaterials: [{ originalMaterialId: 'default' }]
643
+ });
644
+ }
645
+ return result;
646
+ }
647
+ /**
648
+ * Merge 2 materials including texture
649
+ * @param material1
650
+ * @param material2
651
+ * @returns
652
+ */
653
+ async function mergeMaterials(material1, material2) {
654
+ if (material1.texture?.bufferView &&
655
+ material2.texture?.bufferView &&
656
+ material1.mergedMaterials &&
657
+ material2.mergedMaterials) {
658
+ const buffer1 = Buffer.from(material1.texture.bufferView.data);
659
+ const buffer2 = Buffer.from(material2.texture.bufferView.data);
660
+ try {
661
+ // @ts-ignore
662
+ const { joinImages } = await Promise.resolve().then(() => __importStar(require('join-images')));
663
+ const sharpData = await joinImages([buffer1, buffer2], { direction: 'horizontal' });
664
+ material1.texture.bufferView.data = await sharpData
665
+ .toFormat(material1.texture.mimeType === 'image/png' ? 'png' : 'jpeg')
666
+ .toBuffer();
667
+ }
668
+ catch (error) {
669
+ console.log('Join images into a texture atlas has failed. Consider usage `--split-nodes` option. (See documentation https://loaders.gl/modules/tile-converter/docs/cli-reference/tile-converter)');
670
+ throw error;
671
+ }
672
+ // @ts-ignore
673
+ material1.material.pbrMetallicRoughness.baseColorTexture.textureSetDefinitionId = 1;
674
+ }
675
+ material1.mergedMaterials = material1.mergedMaterials.concat(material2.mergedMaterials);
676
+ return material1;
677
+ }
678
+ /**
679
+ * Convert texture and material from gltf 2.0 material object
680
+ * @param sourceMaterial - material object
681
+ * @returns I3S material definition and texture
682
+ */
414
683
  function convertMaterial(sourceMaterial) {
415
- const material = {
416
- doubleSided: sourceMaterial.doubleSided,
417
- emissiveFactor: sourceMaterial.emissiveFactor.map(c => Math.round(c * 255)),
418
- alphaMode: (sourceMaterial.alphaMode || 'OPAQUE').toLowerCase(),
419
- pbrMetallicRoughness: {
420
- roughnessFactor: sourceMaterial.pbrMetallicRoughness.roughnessFactor,
421
- metallicFactor: sourceMaterial.pbrMetallicRoughness.metallicFactor
422
- }
423
- };
424
- let texture;
425
-
426
- if (sourceMaterial.pbrMetallicRoughness.baseColorTexture) {
427
- texture = sourceMaterial.pbrMetallicRoughness.baseColorTexture.texture.source;
428
- material.pbrMetallicRoughness.baseColorTexture = {
429
- textureSetDefinitionId: 0
430
- };
431
- } else if (sourceMaterial.emissiveTexture) {
432
- texture = sourceMaterial.emissiveTexture.texture.source;
433
- material.pbrMetallicRoughness.baseColorTexture = {
434
- textureSetDefinitionId: 0
684
+ const material = {
685
+ doubleSided: sourceMaterial.doubleSided,
686
+ emissiveFactor: sourceMaterial.emissiveFactor?.map((c) => Math.round(c * 255)),
687
+ // It is in upper case in GLTF: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#alpha-coverage
688
+ // But it is in lower case in I3S: https://github.com/Esri/i3s-spec/blob/master/docs/1.7/materialDefinitions.cmn.md
689
+ alphaMode: convertAlphaMode(sourceMaterial.alphaMode),
690
+ pbrMetallicRoughness: {
691
+ roughnessFactor: sourceMaterial?.pbrMetallicRoughness?.roughnessFactor || DEFAULT_ROUGHNESS_FACTOR,
692
+ metallicFactor: sourceMaterial?.pbrMetallicRoughness?.metallicFactor || DEFAULT_METALLIC_FACTOR
693
+ }
435
694
  };
436
- }
437
-
438
- if (!texture) {
439
- const baseColorFactor = sourceMaterial.pbrMetallicRoughness.baseColorFactor;
440
- material.pbrMetallicRoughness.baseColorFactor = baseColorFactor && baseColorFactor.map(c => Math.round(c * 255)) || undefined;
441
- }
442
-
443
- return {
444
- material,
445
- texture
446
- };
447
- }
448
-
695
+ let texture;
696
+ if (sourceMaterial?.pbrMetallicRoughness?.baseColorTexture) {
697
+ texture = sourceMaterial.pbrMetallicRoughness.baseColorTexture.texture.source;
698
+ material.pbrMetallicRoughness.baseColorTexture = {
699
+ textureSetDefinitionId: 0
700
+ };
701
+ }
702
+ else if (sourceMaterial.emissiveTexture) {
703
+ texture = sourceMaterial.emissiveTexture.texture.source;
704
+ // ArcGIS webscene doesn't show emissiveTexture but shows baseColorTexture
705
+ material.pbrMetallicRoughness.baseColorTexture = {
706
+ textureSetDefinitionId: 0
707
+ };
708
+ }
709
+ sourceMaterial.id = Number.isFinite(sourceMaterial.id) ? sourceMaterial.id : (0, uuid_1.v4)();
710
+ let mergedMaterials = [{ originalMaterialId: sourceMaterial.id }];
711
+ if (!texture) {
712
+ // Should use default baseColorFactor if it is not present in source material
713
+ // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-pbrmetallicroughness
714
+ const baseColorFactor = sourceMaterial?.pbrMetallicRoughness?.baseColorFactor;
715
+ material.pbrMetallicRoughness.baseColorFactor =
716
+ (baseColorFactor && baseColorFactor.map((c) => Math.round(c * 255))) || undefined;
717
+ }
718
+ else {
719
+ mergedMaterials[0].textureSize = { width: texture.image.width, height: texture.image.height };
720
+ }
721
+ return { material, texture, mergedMaterials };
722
+ }
723
+ /**
724
+ * Converts from `alphaMode` material property from GLTF to I3S format
725
+ * @param gltfAlphaMode Gltf material `alphaMode` property
726
+ * @returns I3SMaterialDefinition.alphaMode property
727
+ */
728
+ function convertAlphaMode(gltfAlphaMode) {
729
+ switch (gltfAlphaMode) {
730
+ case 'OPAQUE':
731
+ return 'opaque';
732
+ case 'MASK':
733
+ return 'mask';
734
+ case 'BLEND':
735
+ return 'blend';
736
+ default:
737
+ return 'opaque';
738
+ }
739
+ }
740
+ /**
741
+ * Form default I3SMaterialDefinition
742
+ * @returns I3S material definition
743
+ */
449
744
  function getDefaultMaterial() {
450
- return {
451
- alphaMode: 'opaque',
452
- pbrMetallicRoughness: {}
453
- };
454
- }
455
-
456
- function getSharedResources(tileContent, nodeId) {
457
- const gltfMaterials = tileContent.gltf.materials;
458
- const i3sResources = {};
459
-
460
- if (!gltfMaterials || !gltfMaterials.length) {
745
+ return {
746
+ alphaMode: 'opaque',
747
+ pbrMetallicRoughness: {
748
+ metallicFactor: 1,
749
+ roughnessFactor: 1
750
+ }
751
+ };
752
+ }
753
+ /**
754
+ * Form "sharedResources" from gltf materials array
755
+ * @param gltfMaterials - GLTF materials array
756
+ * @param nodeId - I3S node ID
757
+ * @returns {materialDefinitionInfos: Object[], textureDefinitionInfos: Object[]} -
758
+ * 2 arrays in format of i3s sharedResources data https://github.com/Esri/i3s-spec/blob/master/docs/1.7/sharedResource.cmn.md
759
+ */
760
+ function getSharedResources(gltfMaterials, nodeId) {
761
+ const i3sResources = {};
762
+ if (!gltfMaterials || !gltfMaterials.length) {
763
+ return i3sResources;
764
+ }
765
+ i3sResources.materialDefinitionInfos = [];
766
+ for (const gltfMaterial of gltfMaterials) {
767
+ const { materialDefinitionInfo, textureDefinitionInfo } = convertGLTFMaterialToI3sSharedResources(gltfMaterial, nodeId);
768
+ i3sResources.materialDefinitionInfos.push(materialDefinitionInfo);
769
+ if (textureDefinitionInfo) {
770
+ i3sResources.textureDefinitionInfos = i3sResources.textureDefinitionInfos || [];
771
+ i3sResources.textureDefinitionInfos.push(textureDefinitionInfo);
772
+ }
773
+ }
461
774
  return i3sResources;
462
- }
463
-
464
- i3sResources.materialDefinitionInfos = [];
465
-
466
- for (const gltfMaterial of gltfMaterials) {
467
- const {
468
- materialDefinitionInfo,
469
- textureDefinitionInfo
470
- } = convertGLTFMaterialToI3sSharedResources(gltfMaterial, nodeId);
471
- i3sResources.materialDefinitionInfos.push(materialDefinitionInfo);
472
-
473
- if (textureDefinitionInfo) {
474
- i3sResources.textureDefinitionInfos = i3sResources.textureDefinitionInfos || [];
475
- i3sResources.textureDefinitionInfos.push(textureDefinitionInfo);
476
- }
477
- }
478
-
479
- return i3sResources;
480
- }
481
-
775
+ }
776
+ /**
777
+ * Convert gltf material into I3S sharedResources data
778
+ * @param gltfMaterial - gltf material data
779
+ * @param nodeId - I3S node ID
780
+ * @returns - Couple {materialDefinitionInfo, textureDefinitionInfo} extracted from gltf material data
781
+ */
482
782
  function convertGLTFMaterialToI3sSharedResources(gltfMaterial, nodeId) {
483
- const texture = gltfMaterial.pbrMetallicRoughness.baseColorTexture || gltfMaterial.emissiveTexture;
484
- let textureDefinitionInfo = null;
485
-
486
- if (texture) {
487
- textureDefinitionInfo = extractSharedResourcesTextureInfo(texture.texture, nodeId);
488
- }
489
-
490
- const {
491
- baseColorFactor,
492
- metallicFactor
493
- } = gltfMaterial.pbrMetallicRoughness;
494
- let colorFactor = baseColorFactor;
495
-
496
- if ((!baseColorFactor || baseColorFactor[3] === 0) && gltfMaterial.emissiveFactor) {
497
- colorFactor = gltfMaterial.emissiveFactor;
498
- colorFactor[3] = colorFactor[3] || 1;
499
- }
500
-
501
- return {
502
- materialDefinitionInfo: extractSharedResourcesMaterialInfo(colorFactor, metallicFactor),
503
- textureDefinitionInfo
504
- };
505
- }
506
-
507
- function extractSharedResourcesMaterialInfo(baseColorFactor, metallicFactor = 0) {
508
- const matDielectricColorComponent = 0.04 / 255;
509
- const black = new Vector4(0, 0, 0, 1);
510
- const unitVector = new Vector4(1, 1, 1, 1);
511
- const dielectricSpecular = new Vector4(matDielectricColorComponent, matDielectricColorComponent, matDielectricColorComponent, 0);
512
- const baseColorVector = new Vector4(baseColorFactor);
513
- const firstOperand = unitVector.subtract(dielectricSpecular).multiply(baseColorVector);
514
- const diffuse = firstOperand.lerp(firstOperand, black, metallicFactor);
515
- dielectricSpecular[3] = 1;
516
- const specular = dielectricSpecular.lerp(dielectricSpecular, baseColorVector, metallicFactor);
517
- return {
518
- diffuse: diffuse.toArray(),
519
- specular: specular.toArray()
520
- };
521
- }
522
-
783
+ const texture = gltfMaterial?.pbrMetallicRoughness?.baseColorTexture || gltfMaterial.emissiveTexture;
784
+ let textureDefinitionInfo = null;
785
+ if (texture) {
786
+ textureDefinitionInfo = extractSharedResourcesTextureInfo(texture.texture, nodeId);
787
+ }
788
+ const { baseColorFactor, metallicFactor } = gltfMaterial?.pbrMetallicRoughness || {};
789
+ let colorFactor = baseColorFactor;
790
+ // If alpha channel is 0 try to get emissive factor from gltf material.
791
+ if ((!baseColorFactor || baseColorFactor[3] === 0) && gltfMaterial.emissiveFactor) {
792
+ colorFactor = gltfMaterial.emissiveFactor;
793
+ colorFactor[3] = colorFactor[3] || 1;
794
+ }
795
+ return {
796
+ materialDefinitionInfo: extractSharedResourcesMaterialInfo(colorFactor || [1, 1, 1, 1], metallicFactor),
797
+ textureDefinitionInfo
798
+ };
799
+ }
800
+ /**
801
+ * Form "materialDefinition" which is part of "sharedResouces"
802
+ * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materials
803
+ * See formulas in appendix "Appendix B: BRDF Implementation":
804
+ * const dielectricSpecular = rgb(0.04, 0.04, 0.04)
805
+ * const black = rgb(0, 0, 0)
806
+ * cdiff = lerp(baseColor.rgb * (1 - dielectricSpecular.r), black, metallic)
807
+ * F0 = lerp(dieletricSpecular, baseColor.rgb, metallic)
808
+ *
809
+ * Assumption: F0 - specular in i3s ("specular reflection" <-> "reflectance value at normal incidence")
810
+ * cdiff - diffuse in i3s ("Diffuse color" <-> "'c' diffuse" (c means color?))
811
+ * @param baseColorFactor - RGBA color in 0..1 format
812
+ * @param metallicFactor - "metallicFactor" attribute of gltf material object
813
+ * @returns material definition info for I3S shared resource
814
+ */
815
+ function extractSharedResourcesMaterialInfo(baseColorFactor, metallicFactor = 1) {
816
+ const matDielectricColorComponent = 0.04 / 255; // Color from rgb (255) to 0..1 resolution
817
+ // All color resolutions are 0..1
818
+ const black = new core_1.Vector4(0, 0, 0, 1);
819
+ const unitVector = new core_1.Vector4(1, 1, 1, 1);
820
+ const dielectricSpecular = new core_1.Vector4(matDielectricColorComponent, matDielectricColorComponent, matDielectricColorComponent, 0);
821
+ const baseColorVector = new core_1.Vector4(baseColorFactor);
822
+ // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
823
+ // Formulas for Cdiff & F0
824
+ const firstOperand = unitVector.subtract(dielectricSpecular).multiply(baseColorVector);
825
+ const diffuse = firstOperand.lerp(firstOperand, black, metallicFactor);
826
+ dielectricSpecular[3] = 1;
827
+ const specular = dielectricSpecular.lerp(dielectricSpecular, baseColorVector, metallicFactor);
828
+ return {
829
+ params: {
830
+ // @ts-expect-error NumericArray
831
+ diffuse: diffuse.toArray(),
832
+ // @ts-expect-error NumericArray
833
+ specular: specular.toArray(),
834
+ renderMode: 'solid'
835
+ }
836
+ };
837
+ }
838
+ /**
839
+ * Form "textureDefinition" which is part of "sharedResouces"
840
+ * @param texture - texture image info
841
+ * @param nodeId - I3S node ID
842
+ * @returns texture definition infor for shared resource
843
+ */
523
844
  function extractSharedResourcesTextureInfo(texture, nodeId) {
524
- return {
525
- encoding: [texture.source.mimeType],
526
- images: [{
527
- id: generateImageId(texture, nodeId),
528
- size: texture.source.image.width,
529
- length: [texture.source.image.data.length]
530
- }]
531
- };
532
- }
533
-
845
+ return {
846
+ encoding: texture?.source?.mimeType ? [texture.source.mimeType] : undefined,
847
+ images: [
848
+ {
849
+ // 'i3s' has just size which is width of the image. Images are supposed to be square.
850
+ // https://github.com/Esri/i3s-spec/blob/master/docs/1.7/image.cmn.md
851
+ id: generateImageId(texture, nodeId),
852
+ size: texture.source?.image.width,
853
+ length: texture.source?.image.data.length ? [texture.source?.image.data.length] : undefined
854
+ }
855
+ ]
856
+ };
857
+ }
858
+ /**
859
+ * Formula for calculating imageId:
860
+ * https://github.com/Esri/i3s-spec/blob/0a6366a9249b831db8436c322f8d27521e86cf07/format/Indexed%203d%20Scene%20Layer%20Format%20Specification.md#generating-image-ids
861
+ * @param texture - texture image info
862
+ * @param nodeId - I3S node ID
863
+ * @returns calculate image ID according to the spec
864
+ */
534
865
  function generateImageId(texture, nodeId) {
535
- const {
536
- width,
537
- height
538
- } = texture.source.image;
539
- const levelCountOfTexture = 1;
540
- const indexOfLevel = 0;
541
- const indexOfTextureInStore = nodeId + 1;
542
- const zerosCount = 32 - indexOfTextureInStore.toString(2).length;
543
- const rightHalf = '0'.repeat(zerosCount).concat(indexOfTextureInStore.toString(2));
544
- const shiftedLevelCountOfTexture = levelCountOfTexture << 28;
545
- const shiftedIndexOfLevel = indexOfLevel << 24;
546
- const shiftedWidth = width - 1 << 12;
547
- const shiftedHeight = height - 1 << 0;
548
- const leftHalf = shiftedLevelCountOfTexture + shiftedIndexOfLevel + shiftedWidth + shiftedHeight;
549
- const imageId = BigInt("0b".concat(leftHalf.toString(2)).concat(rightHalf));
550
- return imageId.toString();
551
- }
552
-
866
+ const { width, height } = texture.source?.image || {};
867
+ if (!width || !height) {
868
+ return '';
869
+ }
870
+ const levelCountOfTexture = 1;
871
+ const indexOfLevel = 0;
872
+ const indexOfTextureInStore = nodeId + 1;
873
+ const zerosCount = 32 - indexOfTextureInStore.toString(2).length;
874
+ const rightHalf = '0'.repeat(zerosCount).concat(indexOfTextureInStore.toString(2));
875
+ const shiftedLevelCountOfTexture = levelCountOfTexture << 28;
876
+ const shiftedIndexOfLevel = indexOfLevel << 24;
877
+ const shiftedWidth = (width - 1) << 12;
878
+ const shiftedHeight = (height - 1) << 0;
879
+ const leftHalf = shiftedLevelCountOfTexture + shiftedIndexOfLevel + shiftedWidth + shiftedHeight;
880
+ const imageId = BigInt(`0b${leftHalf.toString(2)}${rightHalf}`);
881
+ return imageId.toString();
882
+ }
883
+ /**
884
+ * Make all feature ids unique through all nodes in layout.
885
+ * @param featureIds
886
+ * @param featureIndices
887
+ * @param featuresHashArray
888
+ * @param batchTable
889
+ * @returns {void}
890
+ */
553
891
  function makeFeatureIdsUnique(featureIds, featureIndices, featuresHashArray, batchTable) {
554
- const replaceMap = getFeaturesReplaceMap(featureIds, batchTable, featuresHashArray);
555
- replaceIndicesByUnique(featureIndices, replaceMap);
556
- replaceIndicesByUnique(featureIds, replaceMap);
892
+ const replaceMap = getFeaturesReplaceMap(featureIds, batchTable, featuresHashArray);
893
+ replaceIndicesByUnique(featureIndices, replaceMap);
894
+ replaceIndicesByUnique(featureIds, replaceMap);
557
895
  }
558
-
896
+ /**
897
+ * Generate replace map to make featureIds unique.
898
+ * @param featureIds
899
+ * @param batchTable
900
+ * @param featuresHashArray
901
+ * @returns
902
+ */
559
903
  function getFeaturesReplaceMap(featureIds, batchTable, featuresHashArray) {
560
- const featureMap = {};
561
-
562
- for (let index = 0; index < featureIds.length; index++) {
563
- const oldFeatureId = featureIds[index];
564
- const uniqueFeatureId = getOrCreateUniqueFeatureId(index, batchTable, featuresHashArray);
565
- featureMap[oldFeatureId.toString()] = uniqueFeatureId;
566
- }
567
-
568
- return featureMap;
569
- }
570
-
904
+ const featureMap = {};
905
+ for (let index = 0; index < featureIds.length; index++) {
906
+ const oldFeatureId = featureIds[index];
907
+ const uniqueFeatureId = getOrCreateUniqueFeatureId(index, batchTable, featuresHashArray);
908
+ featureMap[oldFeatureId.toString()] = uniqueFeatureId;
909
+ }
910
+ return featureMap;
911
+ }
912
+ /**
913
+ * Generates string for unique batch id creation.
914
+ * @param batchTable
915
+ * @param index
916
+ * @returns
917
+ */
571
918
  function generateStringFromBatchTableByIndex(batchTable, index) {
572
- let str = '';
573
-
574
- for (const key in batchTable) {
575
- str += batchTable[key][index];
576
- }
577
-
578
- return str;
579
- }
580
-
919
+ let str = '';
920
+ for (const key in batchTable) {
921
+ str += batchTable[key][index];
922
+ }
923
+ return str;
924
+ }
925
+ /**
926
+ * Return already exited featureId or creates and returns new to support unique feature ids throw nodes.
927
+ * @param index
928
+ * @param batchTable
929
+ * @param featuresHashArray
930
+ * @returns
931
+ */
581
932
  function getOrCreateUniqueFeatureId(index, batchTable, featuresHashArray) {
582
- const batchTableStr = generateStringFromBatchTableByIndex(batchTable, index);
583
- const hash = md5(batchTableStr);
584
-
585
- if (featuresHashArray.includes(hash)) {
586
- return featuresHashArray.indexOf(hash);
587
- }
588
-
589
- return featuresHashArray.push(hash) - 1;
590
- }
591
-
933
+ const batchTableStr = generateStringFromBatchTableByIndex(batchTable, index);
934
+ const hash = (0, md5_1.default)(batchTableStr);
935
+ if (featuresHashArray.includes(hash)) {
936
+ return featuresHashArray.indexOf(hash);
937
+ }
938
+ return featuresHashArray.push(hash) - 1;
939
+ }
940
+ /**
941
+ * Do replacement of indices for making them unique through all nodes.
942
+ * @param indicesArray
943
+ * @param featureMap
944
+ * @returns
945
+ */
592
946
  function replaceIndicesByUnique(indicesArray, featureMap) {
593
- for (let index = 0; index < indicesArray.length; index++) {
594
- indicesArray[index] = featureMap[indicesArray[index]];
595
- }
596
- }
597
-
598
- function convertBatchTableToAttributeBuffers(batchTable, featureIds, attributeStorageInfo) {
599
- const attributeBuffers = [];
600
-
601
- if (batchTable) {
602
- const batchTableWithFeatureIds = {
603
- OBJECTID: featureIds,
604
- ...batchTable
947
+ for (let index = 0; index < indicesArray.length; index++) {
948
+ indicesArray[index] = featureMap[indicesArray[index]];
949
+ }
950
+ }
951
+ /**
952
+ * Convert property table data to attribute buffers.
953
+ * @param featureIds
954
+ * @param propertyTable - table with metadata for particular feature.
955
+ * @param attributeStorageInfo
956
+ * @returns - Array of file buffers.
957
+ */
958
+ function convertPropertyTableToAttributeBuffers(featureIds, propertyTable, attributeStorageInfo) {
959
+ const attributeBuffers = [];
960
+ const needFlattenPropertyTable = (0, feature_attributes_1.checkPropertiesLength)(featureIds, propertyTable);
961
+ const properties = needFlattenPropertyTable
962
+ ? (0, feature_attributes_1.flattenPropertyTableByFeatureIds)(featureIds, propertyTable)
963
+ : propertyTable;
964
+ const propertyTableWithObjectIds = {
965
+ OBJECTID: featureIds,
966
+ ...properties
605
967
  };
606
-
607
- for (const key in batchTableWithFeatureIds) {
608
- const type = getAttributeType(key, attributeStorageInfo);
609
- let attributeBuffer = null;
610
-
611
- switch (type) {
968
+ for (const propertyName in propertyTableWithObjectIds) {
969
+ const type = getAttributeType(propertyName, attributeStorageInfo);
970
+ const value = propertyTableWithObjectIds[propertyName];
971
+ const attributeBuffer = generateAttributeBuffer(type, value);
972
+ attributeBuffers.push(attributeBuffer);
973
+ }
974
+ return attributeBuffers;
975
+ }
976
+ /**
977
+ * Generates attribute buffer based on attribute type
978
+ * @param type
979
+ * @param value
980
+ */
981
+ function generateAttributeBuffer(type, value) {
982
+ let attributeBuffer;
983
+ switch (type) {
612
984
  case OBJECT_ID_TYPE:
613
985
  case SHORT_INT_TYPE:
614
- attributeBuffer = generateShortIntegerAttributeBuffer(batchTableWithFeatureIds[key]);
615
- break;
616
-
986
+ attributeBuffer = generateShortIntegerAttributeBuffer(value);
987
+ break;
617
988
  case DOUBLE_TYPE:
618
- attributeBuffer = generateDoubleAttributeBuffer(batchTableWithFeatureIds[key]);
619
- break;
620
-
989
+ attributeBuffer = generateDoubleAttributeBuffer(value);
990
+ break;
621
991
  case STRING_TYPE:
622
- attributeBuffer = generateStringAttributeBuffer(batchTableWithFeatureIds[key]);
623
- break;
624
-
992
+ attributeBuffer = generateStringAttributeBuffer(value);
993
+ break;
625
994
  default:
626
- attributeBuffer = generateStringAttributeBuffer(batchTableWithFeatureIds[key]);
627
- }
628
-
629
- attributeBuffers.push(attributeBuffer);
995
+ attributeBuffer = generateStringAttributeBuffer(value);
630
996
  }
631
- }
632
-
633
- return attributeBuffers;
997
+ return attributeBuffer;
634
998
  }
635
-
999
+ /**
1000
+ * Return attribute type.
1001
+ * @param key
1002
+ * @param attributeStorageInfo
1003
+ * @returns attribute type.
1004
+ */
636
1005
  function getAttributeType(key, attributeStorageInfo) {
637
- const attribute = attributeStorageInfo.find(attr => attr.name === key);
638
- return attribute.attributeValues.valueType;
1006
+ const attribute = attributeStorageInfo.find((attr) => attr.name === key);
1007
+ return attribute.attributeValues.valueType;
639
1008
  }
640
-
1009
+ /**
1010
+ * Convert short integer to attribute arrayBuffer.
1011
+ * @param featureIds
1012
+ * @returns - Buffer with objectId data.
1013
+ */
641
1014
  function generateShortIntegerAttributeBuffer(featureIds) {
642
- const count = new Uint32Array([featureIds.length]);
643
- const valuesArray = new Uint32Array(featureIds);
644
- return concatenateArrayBuffers(count.buffer, valuesArray.buffer);
1015
+ const count = new Uint32Array([featureIds.length]);
1016
+ const valuesArray = new Uint32Array(featureIds);
1017
+ return (0, loader_utils_1.concatenateArrayBuffers)(count.buffer, valuesArray.buffer);
645
1018
  }
646
-
1019
+ /**
1020
+ * Convert double to attribute arrayBuffer.
1021
+ * @param featureIds
1022
+ * @returns - Buffer with objectId data.
1023
+ */
647
1024
  function generateDoubleAttributeBuffer(featureIds) {
648
- const count = new Uint32Array([featureIds.length]);
649
- const padding = new Uint8Array(4);
650
- const valuesArray = new Float64Array(featureIds);
651
- return concatenateArrayBuffers(count.buffer, padding.buffer, valuesArray.buffer);
1025
+ const count = new Uint32Array([featureIds.length]);
1026
+ const padding = new Uint8Array(4);
1027
+ const valuesArray = new Float64Array(featureIds);
1028
+ return (0, loader_utils_1.concatenateArrayBuffers)(count.buffer, padding.buffer, valuesArray.buffer);
652
1029
  }
653
-
1030
+ /**
1031
+ * Convert batch table attributes to array buffer with batch table data.
1032
+ * @param batchAttributes
1033
+ * @returns - Buffer with batch table data.
1034
+ */
654
1035
  function generateStringAttributeBuffer(batchAttributes) {
655
- const stringCountArray = new Uint32Array([batchAttributes.length]);
656
- let totalNumberOfBytes = 0;
657
- const stringSizesArray = new Uint32Array(batchAttributes.length);
658
- const stringBufferArray = [];
659
-
660
- for (let index = 0; index < batchAttributes.length; index++) {
661
- const currentString = "".concat(String(batchAttributes[index]), "\0");
662
- const currentStringBuffer = Buffer.from(currentString);
663
- const currentStringSize = currentStringBuffer.length;
664
- totalNumberOfBytes += currentStringSize;
665
- stringSizesArray[index] = currentStringSize;
666
- stringBufferArray.push(currentStringBuffer);
667
- }
668
-
669
- const totalBytes = new Uint32Array([totalNumberOfBytes]);
670
- return concatenateArrayBuffers(stringCountArray.buffer, totalBytes.buffer, stringSizesArray.buffer, ...stringBufferArray);
671
- }
672
-
1036
+ const stringCountArray = new Uint32Array([batchAttributes.length]);
1037
+ let totalNumberOfBytes = 0;
1038
+ const stringSizesArray = new Uint32Array(batchAttributes.length);
1039
+ const stringBufferArray = [];
1040
+ for (let index = 0; index < batchAttributes.length; index++) {
1041
+ const currentString = `${String(batchAttributes[index])}\0`;
1042
+ const currentStringBuffer = Buffer.from(currentString);
1043
+ const currentStringSize = currentStringBuffer.length;
1044
+ totalNumberOfBytes += currentStringSize;
1045
+ stringSizesArray[index] = currentStringSize;
1046
+ stringBufferArray.push(currentStringBuffer);
1047
+ }
1048
+ const totalBytes = new Uint32Array([totalNumberOfBytes]);
1049
+ return (0, loader_utils_1.concatenateArrayBuffers)(stringCountArray.buffer, totalBytes.buffer, stringSizesArray.buffer, ...stringBufferArray);
1050
+ }
1051
+ /**
1052
+ * Convert featureIds to BigUint64Array.
1053
+ * @param featureIds
1054
+ * @returns - Array of feature ids in BigUint64 format.
1055
+ */
673
1056
  function generateBigUint64Array(featureIds) {
674
- const typedFeatureIds = new BigUint64Array(featureIds.length);
675
-
676
- for (let index = 0; index < featureIds.length; index++) {
677
- typedFeatureIds[index] = BigInt(featureIds[index]);
678
- }
679
-
680
- return typedFeatureIds;
681
- }
682
-
683
- async function generateCompressedGeometry(vertexCount, convertedAttributes, attributes) {
684
- const {
685
- positions,
686
- normals,
687
- texCoords,
688
- colors,
689
- featureIds,
690
- faceRange
691
- } = attributes;
692
- const indices = new Uint32Array(vertexCount);
693
-
694
- for (let index = 0; index < indices.length; index++) {
695
- indices.set([index], index);
696
- }
697
-
698
- const featureIndices = new Uint32Array(convertedAttributes.featureIndices.length ? convertedAttributes.featureIndices : vertexCount);
699
- const featureIndex = generateFeatureIndexAttribute(featureIndices, faceRange);
700
- const compressedAttributes = {
701
- positions,
702
- normals,
703
- colors,
704
- 'feature-index': featureIndex
705
- };
706
-
707
- if (texCoords.length) {
708
- compressedAttributes.texCoords = texCoords;
709
- }
710
-
711
- const attributesMetadata = {
712
- 'feature-index': {
713
- 'i3s-attribute-type': 'feature-index',
714
- 'i3s-feature-ids': new Int32Array(featureIds)
715
- }
716
- };
717
- return new Uint8Array(await encode({
718
- attributes: compressedAttributes,
719
- indices
720
- }, DracoWriter, {
721
- draco: {
722
- method: 'MESH_SEQUENTIAL_ENCODING',
723
- attributesMetadata
724
- }
725
- }));
726
- }
727
-
1057
+ const typedFeatureIds = new BigUint64Array(featureIds.length);
1058
+ for (let index = 0; index < featureIds.length; index++) {
1059
+ typedFeatureIds[index] = BigInt(featureIds[index]);
1060
+ }
1061
+ return typedFeatureIds;
1062
+ }
1063
+ /**
1064
+ * Generates draco compressed geometry
1065
+ * @param {Number} vertexCount
1066
+ * @param {Object} convertedAttributes - get rid of this argument here
1067
+ * @param {Object} attributes - geometry attributes to compress
1068
+ * @param {string} dracoWorkerSoure - draco worker source code
1069
+ * @returns {Promise<object>} - COmpressed geometry.
1070
+ */
1071
+ async function generateCompressedGeometry(vertexCount, convertedAttributes, attributes, dracoWorkerSoure) {
1072
+ const { positions, normals, texCoords, colors, uvRegions, featureIds, faceRange } = attributes;
1073
+ const indices = new Uint32Array(vertexCount);
1074
+ for (let index = 0; index < indices.length; index++) {
1075
+ indices.set([index], index);
1076
+ }
1077
+ const featureIndices = new Uint32Array(convertedAttributes.featureIndices.length ? convertedAttributes.featureIndices : vertexCount);
1078
+ const featureIndex = generateFeatureIndexAttribute(featureIndices, faceRange);
1079
+ const compressedAttributes = {
1080
+ positions,
1081
+ normals,
1082
+ colors,
1083
+ 'feature-index': featureIndex
1084
+ };
1085
+ if (texCoords.length) {
1086
+ compressedAttributes.texCoords = texCoords;
1087
+ }
1088
+ const attributesMetadata = {
1089
+ 'feature-index': {
1090
+ 'i3s-attribute-type': 'feature-index',
1091
+ 'i3s-feature-ids': new Int32Array(featureIds)
1092
+ }
1093
+ };
1094
+ if (uvRegions.length) {
1095
+ compressedAttributes['uv-region'] = uvRegions;
1096
+ attributesMetadata['uv-region'] = {
1097
+ 'i3s-attribute-type': 'uv-region'
1098
+ };
1099
+ }
1100
+ return (0, core_2.encode)({ attributes: compressedAttributes, indices }, draco_1.DracoWriterWorker, {
1101
+ ...draco_1.DracoWriterWorker.options,
1102
+ source: dracoWorkerSoure,
1103
+ reuseWorkers: true,
1104
+ _nodeWorkers: true,
1105
+ draco: {
1106
+ method: 'MESH_SEQUENTIAL_ENCODING',
1107
+ attributesMetadata
1108
+ }
1109
+ });
1110
+ }
1111
+ /**
1112
+ * Generates ordered feature indices based on face range
1113
+ * @param featureIndex
1114
+ * @param faceRange
1115
+ * @returns
1116
+ */
728
1117
  function generateFeatureIndexAttribute(featureIndex, faceRange) {
729
- const orderedFeatureIndices = new Uint32Array(featureIndex.length);
730
- let fillIndex = 0;
731
- let startIndex = 0;
732
-
733
- for (let index = 1; index < faceRange.length; index += 2) {
734
- const endIndex = (faceRange[index] + 1) * VALUES_PER_VERTEX;
735
- orderedFeatureIndices.fill(fillIndex, startIndex, endIndex);
736
- fillIndex++;
737
- startIndex = endIndex + 1;
738
- }
739
-
740
- return orderedFeatureIndices;
741
- }
742
- //# sourceMappingURL=geometry-converter.js.map
1118
+ const orderedFeatureIndices = new Uint32Array(featureIndex.length);
1119
+ let fillIndex = 0;
1120
+ let startIndex = 0;
1121
+ for (let index = 1; index < faceRange.length; index += 2) {
1122
+ const endIndex = (faceRange[index] + 1) * VALUES_PER_VERTEX;
1123
+ orderedFeatureIndices.fill(fillIndex, startIndex, endIndex);
1124
+ fillIndex++;
1125
+ startIndex = endIndex + 1;
1126
+ }
1127
+ return orderedFeatureIndices;
1128
+ }
1129
+ /**
1130
+ * Find property table in tile
1131
+ * For example it can be batchTable for b3dm files or property table in gLTF extension.
1132
+ * @param sourceTile
1133
+ * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA
1134
+ */
1135
+ function getPropertyTable(tileContent) {
1136
+ const batchTableJson = tileContent?.batchTableJson;
1137
+ if (batchTableJson) {
1138
+ return batchTableJson;
1139
+ }
1140
+ const { extensionName, extension } = getPropertyTableExtension(tileContent);
1141
+ switch (extensionName) {
1142
+ case EXT_MESH_FEATURES: {
1143
+ console.warn('The I3S converter does not yet support the EXT_mesh_features extension');
1144
+ return null;
1145
+ }
1146
+ case EXT_FEATURE_METADATA: {
1147
+ return getPropertyTableFromExtFeatureMetadata(extension);
1148
+ }
1149
+ default:
1150
+ return null;
1151
+ }
1152
+ }
1153
+ exports.getPropertyTable = getPropertyTable;
1154
+ /**
1155
+ * Check extensions which can be with property table inside.
1156
+ * @param sourceTile
1157
+ */
1158
+ function getPropertyTableExtension(tileContent) {
1159
+ const extensionsWithPropertyTables = [EXT_FEATURE_METADATA, EXT_MESH_FEATURES];
1160
+ const extensionsUsed = tileContent?.gltf?.extensionsUsed;
1161
+ if (!extensionsUsed) {
1162
+ return { extensionName: null, extension: null };
1163
+ }
1164
+ let extensionName = '';
1165
+ for (const extensionItem of tileContent?.gltf?.extensionsUsed || []) {
1166
+ if (extensionsWithPropertyTables.includes(extensionItem)) {
1167
+ extensionName = extensionItem;
1168
+ break;
1169
+ }
1170
+ }
1171
+ const extension = tileContent?.gltf?.extensions?.[extensionName];
1172
+ return { extensionName, extension };
1173
+ }
1174
+ /**
1175
+ * Handle EXT_feature_metadata to get property table
1176
+ * @param extension
1177
+ * TODO add EXT_feature_metadata feature textures support.
1178
+ */
1179
+ function getPropertyTableFromExtFeatureMetadata(extension) {
1180
+ if (extension?.featureTextures) {
1181
+ console.warn('The I3S converter does not yet support the EXT_feature_metadata feature textures');
1182
+ return null;
1183
+ }
1184
+ if (extension?.featureTables) {
1185
+ /**
1186
+ * Take only first feature table to generate attributes storage info object.
1187
+ * TODO: Think about getting data from all feature tables?
1188
+ * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables.
1189
+ * In I3S we should decide which featureIds attribute will be passed to geometry data.
1190
+ */
1191
+ const firstFeatureTableName = Object.keys(extension.featureTables)?.[0];
1192
+ if (firstFeatureTableName) {
1193
+ const featureTable = extension?.featureTables[firstFeatureTableName];
1194
+ const propertyTable = {};
1195
+ for (const propertyName in featureTable.properties) {
1196
+ propertyTable[propertyName] = featureTable.properties[propertyName].data;
1197
+ }
1198
+ return propertyTable;
1199
+ }
1200
+ }
1201
+ console.warn("The I3S converter couldn't handle EXT_feature_metadata extension");
1202
+ return null;
1203
+ }