@loaders.gl/tile-converter 3.3.0-alpha.1 → 3.3.0-alpha.11

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