@loaders.gl/tile-converter 5.0.0-alpha.11 → 5.0.0-alpha.14

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 (152) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +180 -4
  3. package/bin/converter-v5.js +2 -0
  4. package/dist/converter.min.cjs +172 -182
  5. package/dist/i3s-server/bin/i3s-server.min.cjs +113 -158
  6. package/dist/index.cjs +18832 -19228
  7. package/dist/index.js +19566 -19968
  8. package/dist/v5/adapters.cjs +2002 -230
  9. package/dist/v5/adapters.d.ts +20 -0
  10. package/dist/v5/adapters.js +2005 -214
  11. package/dist/v5/archive-source.d.ts +36 -0
  12. package/dist/v5/browser-tileset-source.d.ts +55 -11
  13. package/dist/v5/browser.cjs +18 -0
  14. package/dist/v5/browser.d.ts +15 -1
  15. package/dist/v5/browser.js +26 -0
  16. package/dist/v5/conversion-api.d.ts +34 -0
  17. package/dist/v5/converter-cli.d.ts +1 -0
  18. package/dist/v5/converter-cli.js +1230 -0
  19. package/dist/v5/core.cjs +547 -77
  20. package/dist/v5/core.d.ts +3 -1
  21. package/dist/v5/core.js +540 -70
  22. package/dist/v5/feature-arrow.d.ts +1 -1
  23. package/dist/v5/i3s-mesh-conversion.d.ts +5 -1
  24. package/dist/v5/i3s-mesh-source-features.d.ts +2 -2
  25. package/dist/v5/i3s-mesh-source-material.d.ts +1 -1
  26. package/dist/v5/i3s-mesh-source.d.ts +2 -2
  27. package/dist/v5/i3s-selection-source.d.ts +70 -0
  28. package/dist/v5/index.cjs +15 -0
  29. package/dist/v5/index.d.ts +13 -1
  30. package/dist/v5/index.js +22 -0
  31. package/dist/v5/mesh-conversion.d.ts +21 -3
  32. package/dist/v5/mesh-draco.d.ts +2 -2
  33. package/dist/v5/mesh-features.d.ts +2 -2
  34. package/dist/v5/mesh-hierarchy.d.ts +47 -0
  35. package/dist/v5/mesh-source-features.d.ts +6 -5
  36. package/dist/v5/mesh-source-schema.d.ts +12 -0
  37. package/dist/v5/mesh-source-texture.d.ts +3 -3
  38. package/dist/v5/mesh-source.d.ts +10 -7
  39. package/dist/v5/mesh-tileset-sink.d.ts +5 -0
  40. package/dist/v5/mesh.d.ts +1 -1
  41. package/dist/v5/node-cli.d.ts +9 -0
  42. package/dist/v5/node-conversion.d.ts +34 -0
  43. package/dist/v5/node-feature-schema.d.ts +3 -0
  44. package/dist/v5/node-i3s-source.d.ts +41 -0
  45. package/dist/v5/node-source.d.ts +47 -0
  46. package/dist/v5/node.cjs +913 -0
  47. package/dist/v5/node.d.ts +6 -0
  48. package/dist/v5/node.js +890 -0
  49. package/dist/v5/point-cloud-attributes.d.ts +19 -0
  50. package/dist/v5/point-cloud-conversion.d.ts +1 -1
  51. package/dist/v5/point-cloud-copc.d.ts +44 -0
  52. package/dist/v5/point-cloud-file.d.ts +83 -0
  53. package/dist/v5/point-cloud-potree.d.ts +47 -0
  54. package/dist/v5/point-cloud-source-encoder.d.ts +1 -1
  55. package/dist/v5/point-cloud-source.d.ts +1 -1
  56. package/dist/v5/point-cloud-tileset.d.ts +44 -0
  57. package/dist/v5/point-cloud.d.ts +1 -1
  58. package/dist/v5/resource-manifest.d.ts +10 -1
  59. package/dist/v5/selected-mesh-source.d.ts +53 -0
  60. package/dist/v5/spatial-conversion.d.ts +1 -1
  61. package/dist/v5/tileset-source.d.ts +1 -1
  62. package/package.json +25 -32
  63. package/src/index.ts +4 -1
  64. package/src/v4/3d-tiles-converter/3d-tiles-converter.ts +11 -12
  65. package/src/v4/3d-tiles-converter/helpers/3d-tiles-content-converter.ts +7 -3
  66. package/src/v4/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.ts +2 -2
  67. package/src/v4/3d-tiles-converter/helpers/load-i3s.ts +4 -6
  68. package/src/v4/3d-tiles-converter/helpers/texture-atlas.ts +1 -1
  69. package/src/v4/3d-tiles-converter/helpers/validate-i3s-spatial-reference.ts +2 -2
  70. package/src/v4/3d-tiles-converter/json-templates/tileset.ts +58 -39
  71. package/src/v4/converter-cli.ts +10 -4
  72. package/src/v4/deps-installer/deps-installer.ts +3 -3
  73. package/src/v4/i3s-converter/helpers/attribute-metadata-info.ts +1 -1
  74. package/src/v4/i3s-converter/helpers/batch-ids-extensions.ts +9 -10
  75. package/src/v4/i3s-converter/helpers/conversion-gltf.ts +108 -0
  76. package/src/v4/i3s-converter/helpers/coordinate-converter.ts +6 -5
  77. package/src/v4/i3s-converter/helpers/create-scene-server-path.ts +5 -6
  78. package/src/v4/i3s-converter/helpers/feature-attributes.ts +4 -4
  79. package/src/v4/i3s-converter/helpers/geometry-attributes.ts +1 -1
  80. package/src/v4/i3s-converter/helpers/geometry-converter.ts +69 -77
  81. package/src/v4/i3s-converter/helpers/gltf-attributes.ts +58 -74
  82. package/src/v4/i3s-converter/helpers/load-3d-tiles.ts +6 -54
  83. package/src/v4/i3s-converter/helpers/node-debug.ts +7 -3
  84. package/src/v4/i3s-converter/helpers/node-index-document.ts +11 -9
  85. package/src/v4/i3s-converter/helpers/node-pages.ts +3 -4
  86. package/src/v4/i3s-converter/helpers/preprocess-3d-tiles.ts +2 -2
  87. package/src/v4/i3s-converter/helpers/tileset-traversal.ts +1 -1
  88. package/src/v4/i3s-converter/i3s-converter.ts +29 -31
  89. package/src/v4/i3s-converter/json-templates/geometry-definitions.ts +71 -66
  90. package/src/v4/i3s-converter/json-templates/layers.ts +97 -132
  91. package/src/v4/i3s-converter/json-templates/metadata.ts +31 -21
  92. package/src/v4/i3s-converter/json-templates/node.ts +60 -74
  93. package/src/v4/i3s-converter/json-templates/scene-server.ts +36 -27
  94. package/src/v4/i3s-converter/json-templates/shared-resources.ts +62 -123
  95. package/src/v4/i3s-converter/json-templates/store.ts +39 -57
  96. package/src/v4/i3s-converter/types.ts +4 -4
  97. package/src/v4/i3s-server/controllers/slpk-controller.ts +3 -3
  98. package/src/v4/i3s-server/utils/create-scene-server.ts +3 -3
  99. package/src/v4/lib/utils/builder-input.ts +8 -0
  100. package/src/v4/lib/utils/conversion-dump.ts +5 -1
  101. package/src/v4/lib/utils/file-utils.ts +1 -1
  102. package/src/v4/lib/utils/hash-string.ts +21 -0
  103. package/src/v4/lib/utils/lod-conversion-utils.ts +3 -3
  104. package/src/v4/pgm-loader.ts +2 -2
  105. package/src/v5/adapters.ts +53 -0
  106. package/src/v5/archive-source.ts +235 -0
  107. package/src/v5/browser-tileset-source.ts +418 -48
  108. package/src/v5/browser.ts +46 -0
  109. package/src/v5/conversion-api.ts +184 -17
  110. package/src/v5/conversion-archive.ts +2 -2
  111. package/src/v5/converter-cli.ts +28 -0
  112. package/src/v5/core.ts +7 -0
  113. package/src/v5/feature-arrow.ts +2 -2
  114. package/src/v5/i3s-mesh-conversion.ts +41 -3
  115. package/src/v5/i3s-mesh-sink.ts +1 -1
  116. package/src/v5/i3s-mesh-source-features.ts +3 -3
  117. package/src/v5/i3s-mesh-source-material.ts +18 -11
  118. package/src/v5/i3s-mesh-source.ts +3 -2
  119. package/src/v5/i3s-selection-source.ts +298 -0
  120. package/src/v5/index.ts +41 -0
  121. package/src/v5/mesh-conversion.ts +24 -4
  122. package/src/v5/mesh-draco.ts +2 -2
  123. package/src/v5/mesh-features.ts +3 -3
  124. package/src/v5/mesh-hierarchy.ts +648 -0
  125. package/src/v5/mesh-source-features.ts +165 -51
  126. package/src/v5/mesh-source-schema.ts +140 -0
  127. package/src/v5/mesh-source-texture.ts +49 -19
  128. package/src/v5/mesh-source.ts +80 -49
  129. package/src/v5/mesh-tileset-archive.ts +1 -1
  130. package/src/v5/mesh-tileset-sink.ts +2 -2
  131. package/src/v5/mesh.ts +1 -1
  132. package/src/v5/node-cli.ts +201 -0
  133. package/src/v5/node-conversion.ts +362 -0
  134. package/src/v5/node-feature-schema.ts +155 -0
  135. package/src/v5/node-i3s-source.ts +181 -0
  136. package/src/v5/node-source.ts +328 -0
  137. package/src/v5/node.ts +16 -0
  138. package/src/v5/point-cloud-attributes.ts +113 -0
  139. package/src/v5/point-cloud-conversion.ts +1 -1
  140. package/src/v5/point-cloud-copc.ts +289 -0
  141. package/src/v5/point-cloud-file.ts +306 -0
  142. package/src/v5/point-cloud-potree.ts +134 -0
  143. package/src/v5/point-cloud-source-encoder.ts +1 -1
  144. package/src/v5/point-cloud-source.ts +1 -1
  145. package/src/v5/point-cloud-spatial.ts +2 -2
  146. package/src/v5/point-cloud-tileset.ts +137 -0
  147. package/src/v5/point-cloud.ts +3 -3
  148. package/src/v5/resource-fetcher.ts +4 -1
  149. package/src/v5/resource-manifest.ts +40 -5
  150. package/src/v5/selected-mesh-source.ts +384 -0
  151. package/src/v5/spatial-conversion.ts +90 -19
  152. package/src/v5/tileset-source.ts +2 -2
@@ -1,12 +1,15 @@
1
+ import {getConversionMaterials} from './conversion-gltf';
2
+ import type {
3
+ ConversionAccessor,
4
+ ConversionMaterial,
5
+ ConversionNode,
6
+ ConversionPrimitive,
7
+ ConversionMesh,
8
+ ConversionTexture
9
+ } from './conversion-gltf';
1
10
  /* eslint-disable camelcase */
2
- import type {FeatureTableJson, Tiles3DTileContent} from '@loaders.gl/3d-tiles';
11
+ import type {FeatureTableJson, Tiles3DTileContent} from '@loaders.gl/tiles-3d/3d-tiles';
3
12
  import type {
4
- GLTFAccessorPostprocessed,
5
- GLTFMaterialPostprocessed,
6
- GLTFNodePostprocessed,
7
- GLTFMeshPrimitivePostprocessed,
8
- GLTFMeshPostprocessed,
9
- GLTFTexturePostprocessed,
10
13
  GLTF_EXT_feature_metadata_GLTF,
11
14
  GLTF_EXT_feature_metadata_FeatureTable,
12
15
  GLTF_EXT_feature_metadata_FeatureTexture,
@@ -23,15 +26,15 @@ import {createRequire} from 'node:module';
23
26
  /* @ts-expect-error TS2732: Cannot find module 'node:module' or its corresponding type declarations. */
24
27
 
25
28
  import {DracoWriterWorker} from '@loaders.gl/draco';
26
- import {assert, encode} from '@loaders.gl/core';
29
+ import {encode, assert} from '@loaders.gl/core';
27
30
  import {
28
31
  concatenateArrayBuffers,
29
32
  concatenateTypedArrays,
30
33
  NumberArray,
31
34
  TypedArray
32
- } from '@loaders.gl/loader-utils';
33
- import md5 from 'md5';
34
- import {v4 as uuidv4} from 'uuid';
35
+ } from '@loaders.gl/core/loader-utils';
36
+ import {hashString} from '../../lib/utils/hash-string';
37
+ import {randomUUID} from 'node:crypto';
35
38
  import {generateAttributes} from './geometry-attributes';
36
39
  import {encodeStringAttribute} from './encode-string-attribute';
37
40
  import {createBoundingVolumesFromGeometry} from './coordinate-converter';
@@ -47,21 +50,21 @@ import {
47
50
  I3SMaterialDefinition,
48
51
  MaterialDefinitionInfo,
49
52
  TextureDefinitionInfo
50
- } from '@loaders.gl/i3s';
51
- import {Geoid} from '@math.gl/geoid';
53
+ } from '@loaders.gl/tiles-3d/i3s';
54
+ import {Geoid} from '@math.gl/earth/geoid';
52
55
  import {prepareDataForAttributesConversion} from './gltf-attributes';
53
56
  import {getTextureByMetadataClass, handleBatchIdsExtensions} from './batch-ids-extensions';
54
57
  import {checkPropertiesLength, flattenPropertyTableByFeatureIds} from './feature-attributes';
55
- import {GL} from '@math.gl/geometry-utils';
58
+ import {GL} from '@math.gl/geometry/utils';
56
59
 
57
60
  /*
58
- At the moment of writing the type TypedArrayConstructor is not exported in '@math.gl/types'.
61
+ At the moment of writing the type TypedArrayConstructor is not exported in '@math.gl/core/types'.
59
62
  So the following import is replaced with the local import
60
- import type {TypedArrayConstructor} from '@math.gl/types';
63
+ import type {TypedArrayConstructor} from '@math.gl/core/types';
61
64
  */
62
- import type {GLTFAttributesData, TextureImageProperties, TypedArrayConstructor} from '../types';
65
+ import type {GLTFAttributesData, TextureImageProperties} from '../types';
63
66
  import {generateSyntheticIndices} from '../../lib/utils/geometry-utils';
64
- import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
67
+ import {BoundingSphere, OrientedBoundingBox} from '@math.gl/geometry/culling';
65
68
 
66
69
  import {EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA} from '@loaders.gl/gltf';
67
70
 
@@ -136,7 +139,7 @@ export default async function convertB3dmToI3sGeometry({
136
139
  }): Promise<I3SConvertedResources[] | null> {
137
140
  const useCartesianPositions = generateBoundingVolumes;
138
141
  const materialAndTextureList: I3SMaterialWithTexture[] = await convertMaterials(
139
- tileContent.gltf?.materials,
142
+ tileContent.gltf ? getConversionMaterials(tileContent.gltf) : [],
140
143
  shouldMergeMaterials
141
144
  );
142
145
 
@@ -339,7 +342,10 @@ async function _makeNodeResources({
339
342
  compressedGeometry,
340
343
  texture,
341
344
  hasUvRegions: Boolean(uvRegions.length),
342
- sharedResources: getSharedResources(tileContent.gltf?.materials || [], nodeId),
345
+ sharedResources: getSharedResources(
346
+ tileContent.gltf ? getConversionMaterials(tileContent.gltf) : [],
347
+ nodeId
348
+ ),
343
349
  meshMaterial: material,
344
350
  vertexCount,
345
351
  attributes,
@@ -437,7 +443,7 @@ function convertNodes({
437
443
  matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
438
444
  featureTexture
439
445
  }: {
440
- nodes: GLTFNodePostprocessed[];
446
+ nodes: ConversionNode[];
441
447
  images: (TextureImageProperties | null)[];
442
448
  cartographicOrigin: Vector3;
443
449
  cartesianModelMatrix: Matrix4;
@@ -468,7 +474,7 @@ function convertNodes({
468
474
  * @param node
469
475
  * @param matrix
470
476
  */
471
- function getCompositeTransformationMatrix(node: GLTFNodePostprocessed, matrix: Matrix4) {
477
+ function getCompositeTransformationMatrix(node: ConversionNode, matrix: Matrix4) {
472
478
  let transformationMatrix = matrix;
473
479
 
474
480
  const {matrix: nodeMatrix, rotation, scale, translation} = node;
@@ -515,7 +521,7 @@ function convertNode({
515
521
  matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
516
522
  featureTexture
517
523
  }: {
518
- node: GLTFNodePostprocessed;
524
+ node: ConversionNode;
519
525
  images: (TextureImageProperties | null)[];
520
526
  cartographicOrigin: Vector3;
521
527
  cartesianModelMatrix: Matrix4;
@@ -578,7 +584,7 @@ function convertMeshToTable({
578
584
  matrix,
579
585
  featureTexture
580
586
  }: {
581
- mesh: GLTFMeshPostprocessed;
587
+ mesh: ConversionMesh;
582
588
  images: (TextureImageProperties | null)[];
583
589
  cartographicOrigin: Vector3;
584
590
  cartesianModelMatrix: Matrix4;
@@ -604,7 +610,8 @@ function convertMeshToTable({
604
610
  assert(
605
611
  primitive.mode === undefined ||
606
612
  primitive.mode === GL.TRIANGLES ||
607
- primitive.mode === GL.TRIANGLE_STRIP,
613
+ primitive.mode === GL.TRIANGLE_STRIP ||
614
+ primitive.mode === GL.TRIANGLE_FAN,
608
615
  `Primitive - unsupported mode ${primitive.mode}`
609
616
  );
610
617
  const attributes = primitive.attributes;
@@ -661,44 +668,32 @@ function convertMeshToTable({
661
668
  }
662
669
  }
663
670
  /**
664
- * Converts TRIANGLE-STRIPS to independent TRIANGLES
671
+ * Converts triangle strips and fans to independent triangles
665
672
  * @param primitive - the primitive to get the indices from
666
673
  * @returns indices of vertices of the independent triangles
667
674
  */
668
- function normalizeIndices(primitive: GLTFMeshPrimitivePostprocessed): TypedArray {
669
- let indices: TypedArray | undefined = primitive.indices?.value;
670
- if (!indices) {
671
- const positions = primitive.attributes.POSITION.value;
672
- return generateSyntheticIndices(positions.length / VALUES_PER_VERTEX);
673
- }
674
-
675
- if (indices && primitive.mode === GL.TRIANGLE_STRIP) {
676
- /*
677
- TRIANGLE_STRIP geometry contains n+2 vertices for n triangles;
678
- TRIANGLE geometry contains n*3 vertices for n triangles.
679
- The conversion from TRIANGLE_STRIP to TRIANGLE implies duplicating adjacent vertices.
680
- */
681
- const TypedArrayConstructor = indices.constructor as TypedArrayConstructor;
682
- const newIndices = new TypedArrayConstructor((indices.length - 2) * 3);
683
-
684
- // Copy the first triangle indices with no modification like [i0, i1, i2, ...] -> [i0, i1, i2, ...]
685
- let triangleIndex = 0;
686
- let currentTriangle = indices.slice(0, 3);
687
- newIndices.set(currentTriangle, 0);
688
-
689
- // The rest triangle indices are being taken from strips using the following logic:
690
- // [i1, i2, i3, i4, i5, i6, ...] -> [i3, i2, i1, i2, i3, i4, i5, i4, i3, i4, i5, i6, ...]
691
- for (let i = 1; i + 2 < indices.length; i++) {
692
- triangleIndex += 3;
693
- currentTriangle = indices.slice(i, i + 3);
694
- if (i % 2 === 0) {
695
- newIndices.set(currentTriangle, triangleIndex);
696
- } else {
697
- // The following "reverce" is necessary to calculate normals correctly
698
- newIndices.set(currentTriangle.reverse(), triangleIndex);
699
- }
700
- }
701
- indices = newIndices;
675
+ function normalizeIndices(primitive: ConversionPrimitive): TypedArray {
676
+ const source = primitive.indices?.value;
677
+ const vertexCount = primitive.attributes.POSITION.value.length / VALUES_PER_VERTEX;
678
+ const count = source?.length ?? vertexCount;
679
+ if (primitive.mode !== GL.TRIANGLE_STRIP && primitive.mode !== GL.TRIANGLE_FAN) {
680
+ return source || generateSyntheticIndices(vertexCount);
681
+ }
682
+ const indices = new Uint32Array(Math.max(0, count - 2) * 3);
683
+ for (let triangleIndex = 0; triangleIndex + 2 < count; triangleIndex++) {
684
+ const first = primitive.mode === GL.TRIANGLE_FAN ? 0 : triangleIndex;
685
+ const second =
686
+ primitive.mode === GL.TRIANGLE_FAN
687
+ ? triangleIndex + 1
688
+ : triangleIndex + 1 + (triangleIndex % 2);
689
+ const third =
690
+ primitive.mode === GL.TRIANGLE_FAN
691
+ ? triangleIndex + 2
692
+ : triangleIndex + 2 - (triangleIndex % 2);
693
+ indices.set(
694
+ [source?.[first] ?? first, source?.[second] ?? second, source?.[third] ?? third],
695
+ triangleIndex * 3
696
+ );
702
697
  }
703
698
  return indices;
704
699
  }
@@ -822,10 +817,7 @@ function flattenTexCoords(texCoords: TypedArray, indices: TypedArray): Float32Ar
822
817
  * @param indices - gltf primitive indices
823
818
  * @returns flattened colors attribute
824
819
  */
825
- function flattenColors(
826
- colorsAttribute: GLTFAccessorPostprocessed,
827
- indices: TypedArray
828
- ): Uint8Array {
820
+ function flattenColors(colorsAttribute: ConversionAccessor, indices: TypedArray): Uint8Array {
829
821
  const components = colorsAttribute?.components || VALUES_PER_COLOR_ELEMENT;
830
822
  const newColors = new Uint8Array(indices.length * components);
831
823
  if (!colorsAttribute) {
@@ -888,9 +880,9 @@ function flattenBatchIds(batchedIds: NumberArray, indices: TypedArray): number[]
888
880
  */
889
881
  function getBatchIds(
890
882
  attributes: {
891
- [key: string]: GLTFAccessorPostprocessed;
883
+ [key: string]: ConversionAccessor;
892
884
  },
893
- primitive: GLTFMeshPrimitivePostprocessed,
885
+ primitive: ConversionPrimitive,
894
886
  images: (TextureImageProperties | null)[],
895
887
  featureTexture: string | null
896
888
  ): NumberArray {
@@ -926,7 +918,7 @@ function getBatchIds(
926
918
  * @returns Array of Couples I3SMaterialDefinition + texture content
927
919
  */
928
920
  async function convertMaterials(
929
- sourceMaterials: GLTFMaterialPostprocessed[] = [],
921
+ sourceMaterials: ConversionMaterial[] = [],
930
922
  shouldMergeMaterials: boolean
931
923
  ): Promise<I3SMaterialWithTexture[]> {
932
924
  let materials: I3SMaterialWithTexture[] = [];
@@ -1059,7 +1051,7 @@ async function mergeMaterials(
1059
1051
  * @param sourceMaterial - material object
1060
1052
  * @returns I3S material definition and texture
1061
1053
  */
1062
- export function convertMaterial(sourceMaterial: GLTFMaterialPostprocessed): I3SMaterialWithTexture {
1054
+ export function convertMaterial(sourceMaterial: ConversionMaterial): I3SMaterialWithTexture {
1063
1055
  const material: I3SMaterialDefinition = {
1064
1056
  doubleSided: sourceMaterial.doubleSided,
1065
1057
  emissiveFactor: sourceMaterial.emissiveFactor?.map(c => Math.round(c * 255)) as [
@@ -1092,7 +1084,7 @@ export function convertMaterial(sourceMaterial: GLTFMaterialPostprocessed): I3SM
1092
1084
  };
1093
1085
  }
1094
1086
 
1095
- sourceMaterial.id = Number.isFinite(sourceMaterial.id) ? sourceMaterial.id : uuidv4();
1087
+ sourceMaterial.id ||= randomUUID();
1096
1088
  const mergedMaterials: MergedMaterial[] = [{originalMaterialId: sourceMaterial.id}];
1097
1089
  if (!texture) {
1098
1090
  // Should use default baseColorFactor if it is not present in source material
@@ -1156,7 +1148,7 @@ function getDefaultMaterial(): I3SMaterialDefinition {
1156
1148
  * 2 arrays in format of i3s sharedResources data https://github.com/Esri/i3s-spec/blob/master/docs/1.7/sharedResource.cmn.md
1157
1149
  */
1158
1150
  function getSharedResources(
1159
- gltfMaterials: GLTFMaterialPostprocessed[],
1151
+ gltfMaterials: ConversionMaterial[],
1160
1152
  nodeId: number
1161
1153
  ): SharedResourcesArrays {
1162
1154
  const i3sResources: SharedResourcesArrays = {};
@@ -1187,7 +1179,7 @@ function getSharedResources(
1187
1179
  * @returns - Couple {materialDefinitionInfo, textureDefinitionInfo} extracted from gltf material data
1188
1180
  */
1189
1181
  function convertGLTFMaterialToI3sSharedResources(
1190
- gltfMaterial: GLTFMaterialPostprocessed,
1182
+ gltfMaterial: ConversionMaterial,
1191
1183
  nodeId: number
1192
1184
  ): {
1193
1185
  materialDefinitionInfo: MaterialDefinitionInfo;
@@ -1270,7 +1262,7 @@ function extractSharedResourcesMaterialInfo(
1270
1262
  * @returns texture definition infor for shared resource
1271
1263
  */
1272
1264
  function extractSharedResourcesTextureInfo(
1273
- texture: GLTFTexturePostprocessed,
1265
+ texture: ConversionTexture,
1274
1266
  nodeId: number
1275
1267
  ): TextureDefinitionInfo {
1276
1268
  return {
@@ -1294,7 +1286,7 @@ function extractSharedResourcesTextureInfo(
1294
1286
  * @param nodeId - I3S node ID
1295
1287
  * @returns calculate image ID according to the spec
1296
1288
  */
1297
- function generateImageId(texture: GLTFTexturePostprocessed, nodeId: number) {
1289
+ function generateImageId(texture: ConversionTexture, nodeId: number) {
1298
1290
  const {width, height} = texture.source?.image || {};
1299
1291
  if (!width || !height) {
1300
1292
  return '';
@@ -1386,7 +1378,7 @@ function getOrCreateUniqueFeatureId(
1386
1378
  featuresHashArray: any[]
1387
1379
  ): number {
1388
1380
  const batchTableStr = generateStringFromBatchTableByIndex(batchTable, index);
1389
- const hash = md5(batchTableStr);
1381
+ const hash = hashString(batchTableStr);
1390
1382
 
1391
1383
  if (featuresHashArray.includes(hash)) {
1392
1384
  return featuresHashArray.indexOf(hash);
@@ -1797,14 +1789,14 @@ function getPropertyTableExtension(tileContent: Tiles3DTileContent): {
1797
1789
  extension: string | GLTF_EXT_feature_metadata_GLTF | GLTF_EXT_structural_metadata_GLTF | null;
1798
1790
  } {
1799
1791
  const extensionsWithPropertyTables = [EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA];
1800
- const extensionsUsed = tileContent?.gltf?.extensionsUsed;
1792
+ const extensionsUsed = tileContent?.gltf?.json.extensionsUsed;
1801
1793
 
1802
1794
  if (!extensionsUsed) {
1803
1795
  return {extensionName: null, extension: null};
1804
1796
  }
1805
1797
 
1806
1798
  let extensionName: string = '';
1807
- for (const extensionItem of tileContent?.gltf?.extensionsUsed || []) {
1799
+ for (const extensionItem of tileContent?.gltf?.json.extensionsUsed || []) {
1808
1800
  if (extensionsWithPropertyTables.includes(extensionItem)) {
1809
1801
  extensionName = extensionItem;
1810
1802
  /*
@@ -1821,7 +1813,7 @@ function getPropertyTableExtension(tileContent: Tiles3DTileContent): {
1821
1813
  return {extensionName: null, extension: null};
1822
1814
  }
1823
1815
 
1824
- const extension = tileContent?.gltf?.extensions?.[extensionName] as
1816
+ const extension = tileContent?.gltf?.json.extensions?.[extensionName] as
1825
1817
  | string // EXT_mesh_features doesn't have global metadata
1826
1818
  | GLTF_EXT_feature_metadata_GLTF
1827
1819
  | GLTF_EXT_structural_metadata_GLTF;
@@ -1,7 +1,9 @@
1
- import type {Tiles3DTileContent} from '@loaders.gl/3d-tiles';
2
- import type {GLTFAccessorPostprocessed, GLTFNodePostprocessed} from '@loaders.gl/gltf';
3
- import {Matrix4, TypedArray, Vector3} from '@math.gl/core';
4
- import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
1
+ import {getConversionAccessor} from './conversion-gltf';
2
+ import type {GLTFWithBuffers} from '@loaders.gl/gltf';
3
+ import type {ConversionNode} from './conversion-gltf';
4
+ import type {Tiles3DTileContent} from '@loaders.gl/tiles-3d/3d-tiles';
5
+ import {Matrix4, Vector3} from '@math.gl/core';
6
+ import {BoundingSphere, OrientedBoundingBox} from '@math.gl/geometry/culling';
5
7
  import {getImageData} from '@loaders.gl/images';
6
8
  import {Ellipsoid} from '@math.gl/geospatial';
7
9
  import {GLTFAttributesData} from '../types';
@@ -19,32 +21,26 @@ export function prepareDataForAttributesConversion(
19
21
  tileTransform: Matrix4,
20
22
  boundingVolume: OrientedBoundingBox | BoundingSphere
21
23
  ): GLTFAttributesData {
22
- const nodes =
23
- tileContent.gltf?.scene?.nodes ||
24
- tileContent.gltf?.scenes?.[0]?.nodes ||
25
- tileContent.gltf?.nodes ||
24
+ const gltf = tileContent.gltf;
25
+ const json = gltf?.json;
26
+ const roots =
27
+ (json?.scene === undefined ? undefined : json.scenes?.[json.scene]?.nodes) ||
28
+ json?.scenes?.[0]?.nodes ||
29
+ json?.nodes?.map((_, index) => index) ||
26
30
  [];
27
-
28
- const images =
29
- tileContent.gltf?.images?.map(imageObject => {
30
- // Need data only for uncompressed images because we can't get batchIds from compressed textures.
31
- if (imageObject?.image?.compressed) {
32
- return null;
33
- }
34
- const {data, width, height} = getImageData(imageObject.image);
35
- const dataCopy = new Uint8Array(data.length);
36
- dataCopy.set(data);
37
- return {
38
- data: dataCopy,
39
- compressed: false,
40
- height,
41
- width,
42
- components: data.length / (width * height),
43
- mimeType: imageObject.mimeType
44
- };
45
- }) || [];
46
-
47
- prepareNodes(nodes);
31
+ const nodes = gltf ? prepareNodes(gltf, roots) : [];
32
+ const images = (gltf?.images || []).map((image, index) => {
33
+ if (!image || (image as any).compressed) return null;
34
+ const {data, width, height} = getImageData(image);
35
+ return {
36
+ data: Uint8Array.from(data),
37
+ compressed: false,
38
+ height,
39
+ width,
40
+ components: data.length / (width * height),
41
+ mimeType: json?.images?.[index]?.mimeType
42
+ };
43
+ });
48
44
 
49
45
  const {cartographicOrigin, modelMatrix: cartesianModelMatrix} = calculateTransformProps(
50
46
  tileContent,
@@ -60,25 +56,6 @@ export function prepareDataForAttributesConversion(
60
56
  };
61
57
  }
62
58
 
63
- /**
64
- * Keep only values for glTF attributes to pass data to worker thread.
65
- * @param attributes - geometry attributes
66
- * @returns attributes with only `value` item
67
- */
68
- function getB3DMAttributesWithoutBufferView(
69
- attributes: Record<string, GLTFAccessorPostprocessed>
70
- ): Record<string, {value: TypedArray}> {
71
- const attributesWithoutBufferView: Record<string, {value: TypedArray}> = {};
72
-
73
- for (const attributeName in attributes) {
74
- attributesWithoutBufferView[attributeName] = {
75
- value: attributes[attributeName].value
76
- };
77
- }
78
-
79
- return attributesWithoutBufferView;
80
- }
81
-
82
59
  /**
83
60
  * Calculate transformation properties to transform vertex attributes (POSITION, NORMAL, etc.)
84
61
  * from METER_OFFSET coorditantes to LNGLAT_OFFSET coordinates
@@ -133,30 +110,37 @@ export function calculateTransformProps(
133
110
  * Traverse all nodes to replace all sensible data with copy to avoid data corruption in worker.
134
111
  * @param nodes
135
112
  */
136
- function prepareNodes(nodes: GLTFNodePostprocessed[]): void {
137
- for (let index = 0; index < nodes.length; index++) {
138
- const node = nodes[index] as any;
139
-
140
- if (node.mesh) {
141
- nodes[index] = {
142
- ...node,
143
- mesh: {
144
- ...node.mesh,
145
- primitives: node.mesh?.primitives.map(primitive => ({
146
- ...primitive,
147
- indices: {value: primitive?.indices?.value},
148
- attributes: getB3DMAttributesWithoutBufferView(primitive.attributes),
149
- material: {
150
- id: primitive?.material?.id,
151
- uniqueId: primitive?.material?.uniqueId
152
- }
153
- }))
154
- }
155
- };
156
- }
157
-
158
- if (node.children) {
159
- prepareNodes(node.children);
160
- }
161
- }
113
+ function prepareNodes(
114
+ gltf: GLTFWithBuffers,
115
+ indices: number[],
116
+ ancestors = new Set<number>()
117
+ ): ConversionNode[] {
118
+ return indices.map(index => {
119
+ if (ancestors.has(index)) throw new Error('Cyclic glTF node hierarchy');
120
+ const node = gltf.json.nodes![index];
121
+ const mesh = node.mesh === undefined ? undefined : gltf.json.meshes?.[node.mesh];
122
+ return {
123
+ ...node,
124
+ mesh: mesh
125
+ ? {
126
+ primitives: mesh.primitives.map(primitive => ({
127
+ ...primitive,
128
+ indices:
129
+ primitive.indices === undefined
130
+ ? undefined
131
+ : getConversionAccessor(gltf, primitive.indices),
132
+ attributes: Object.fromEntries(
133
+ Object.entries(primitive.attributes).map(([name, reference]) => [
134
+ name,
135
+ getConversionAccessor(gltf, reference)
136
+ ])
137
+ ),
138
+ material:
139
+ primitive.material === undefined ? undefined : {id: String(primitive.material)}
140
+ }))
141
+ }
142
+ : undefined,
143
+ children: prepareNodes(gltf, node.children || [], new Set([...ancestors, index]))
144
+ };
145
+ });
162
146
  }
@@ -3,20 +3,12 @@ import type {
3
3
  Tiles3DTileContent,
4
4
  Tiles3DTileJSONPostprocessed,
5
5
  Tiles3DTilesetJSONPostprocessed
6
- } from '@loaders.gl/3d-tiles';
7
- import {Tiles3DArchive} from '@loaders.gl/3d-tiles';
6
+ } from '@loaders.gl/tiles-3d/3d-tiles';
7
+ import {parse3DTilesArchive} from '@loaders.gl/tiles-3d/3d-tiles';
8
8
  import {LoaderWithParser, load} from '@loaders.gl/core';
9
- import type {ReadableFile} from '@loaders.gl/loader-utils';
10
- import {HttpFile, NodeFile, isBrowser} from '@loaders.gl/loader-utils';
11
- import {
12
- CD_HEADER_SIGNATURE,
13
- ZipFileSystem,
14
- parseHashTable,
15
- parseZipCDFileHeader,
16
- parseZipLocalFileHeader,
17
- searchFromTheEnd,
18
- readRange
19
- } from '@loaders.gl/zip';
9
+ import type {ReadableFile} from '@loaders.gl/core/loader-utils';
10
+ import {HttpFile, NodeFile, isBrowser} from '@loaders.gl/core/loader-utils';
11
+ import {ZipFileSystem} from '@loaders.gl/archives/zip';
20
12
 
21
13
  /**
22
14
  * Load nested 3DTiles tileset. If the sourceTile is not nested tileset - do nothing
@@ -116,8 +108,7 @@ export async function loadFromArchive(
116
108
  if (filename) {
117
109
  const tz3Path = `${tz3UrlParts[0]}.3tz`;
118
110
  const fileProvider = createReadableFile(tz3Path);
119
- const hashTable = await loadHashTable(fileProvider);
120
- const archive = new Tiles3DArchive(fileProvider, hashTable, tz3Path);
111
+ const archive = await parse3DTilesArchive(fileProvider, undefined, tz3Path);
121
112
  const fileSystem = new ZipFileSystem(archive);
122
113
  const archiveLoadOptions = {
123
114
  ...loadOptions,
@@ -145,42 +136,3 @@ function createReadableFile(path: string): ReadableFile {
145
136
  }
146
137
  return isBrowser ? new HttpFile(path) : new NodeFile(path);
147
138
  }
148
-
149
- /**
150
- * Load hash file from 3TZ
151
- * @param fileProvider - binary reader of 3TZ
152
- * @returns hash table of the 3TZ file content or undefined if the hash file is not presented inside
153
- */
154
- async function loadHashTable(
155
- fileProvider: ReadableFile
156
- ): Promise<undefined | Record<string, bigint>> {
157
- let hashTable: undefined | Record<string, bigint>;
158
-
159
- const hashCDOffset = await searchFromTheEnd(fileProvider, CD_HEADER_SIGNATURE);
160
-
161
- const cdFileHeader = await parseZipCDFileHeader(hashCDOffset, fileProvider);
162
-
163
- // '@3dtilesIndex1@' is index file that must be the last in the archive. It allows
164
- // to improve load and read performance when the archive contains a very large number
165
- // of files.
166
- if (cdFileHeader?.fileName === '@3dtilesIndex1@') {
167
- const localFileHeader = await parseZipLocalFileHeader(
168
- cdFileHeader.localHeaderOffset,
169
- fileProvider
170
- );
171
- if (!localFileHeader) {
172
- throw new Error('corrupted 3tz');
173
- }
174
-
175
- const fileDataOffset = localFileHeader.fileDataOffset;
176
- const hashFile = await readRange(
177
- fileProvider,
178
- fileDataOffset,
179
- fileDataOffset + localFileHeader.compressedSize
180
- );
181
-
182
- hashTable = parseHashTable(hashFile);
183
- }
184
-
185
- return hashTable;
186
- }
@@ -1,5 +1,9 @@
1
- import type {Mbs, Node3DIndexDocument, Obb} from '@loaders.gl/i3s';
2
- import {OrientedBoundingBox, BoundingSphere} from '@math.gl/culling';
1
+ import type {Mbs, Node3DIndexDocument, Obb} from '@loaders.gl/tiles-3d/i3s';
2
+ import {
3
+ OrientedBoundingBox,
4
+ BoundingSphere,
5
+ makeOrientedBoundingBoxFromQuaternion
6
+ } from '@math.gl/geometry/culling';
3
7
  import {Vector3} from '@math.gl/core';
4
8
  import {Ellipsoid} from '@math.gl/geospatial';
5
9
 
@@ -85,7 +89,7 @@ function createBoundingSphereFromTileMbs(mbs: Mbs): BoundingSphere {
85
89
  */
86
90
  function createBoundingBoxFromTileObb(obb: Obb): OrientedBoundingBox {
87
91
  const {center, halfSize, quaternion} = obb;
88
- return new OrientedBoundingBox().fromCenterHalfSizeQuaternion(center, halfSize, quaternion);
92
+ return makeOrientedBoundingBoxFromQuaternion(center, halfSize, quaternion);
89
93
  }
90
94
 
91
95
  /**
@@ -5,12 +5,11 @@ import {
5
5
  Node3DIndexDocument,
6
6
  NodeInPage,
7
7
  NodeReference
8
- } from '@loaders.gl/i3s';
9
- import transform from 'json-map-transform';
10
- import {v4 as uuidv4} from 'uuid';
8
+ } from '@loaders.gl/tiles-3d/i3s';
9
+ import {randomUUID} from 'node:crypto';
11
10
  import {openJson, writeFileForSlpk} from '../../lib/utils/file-utils';
12
11
  import I3SConverter from '../i3s-converter';
13
- import {NODE as nodeTemplate} from '../json-templates/node';
12
+ import {createNode} from '../json-templates/node';
14
13
  import {I3SConvertedResources} from '../types';
15
14
  import {DumpMetadata} from '../../lib/utils/conversion-dump';
16
15
 
@@ -97,7 +96,7 @@ export class NodeIndexDocument {
97
96
  }
98
97
 
99
98
  /**
100
- * Add neighbors to child nodes of this node
99
+ * Add neighbors, save leaf documents and children, then release finalized child data.
101
100
  */
102
101
  public async addNeighbors(): Promise<void> {
103
102
  if (this.finalized) {
@@ -130,7 +129,10 @@ export class NodeIndexDocument {
130
129
  }
131
130
  await childNode.save();
132
131
  }
133
- // The save after adding neighbors is the last one. Finalize the the node
132
+ // Internal documents were saved during child traversal. A root mesh leaf has no such traversal.
133
+ if (!this.children.length) {
134
+ await this.save();
135
+ }
134
136
  this.finalize();
135
137
  }
136
138
 
@@ -250,7 +252,7 @@ export class NodeIndexDocument {
250
252
  */
251
253
  static createRootNodeIndexDocument(boundingVolumes: BoundingVolumes): Node3DIndexDocument {
252
254
  const root0data = {
253
- version: `{${uuidv4().toUpperCase()}}`,
255
+ version: `{${randomUUID().toUpperCase()}}`,
254
256
  id: 'root',
255
257
  level: 0,
256
258
  lodSelection: [
@@ -266,7 +268,7 @@ export class NodeIndexDocument {
266
268
  ...boundingVolumes,
267
269
  children: []
268
270
  };
269
- return transform(root0data, nodeTemplate());
271
+ return createNode(root0data);
270
272
  }
271
273
 
272
274
  /**
@@ -305,7 +307,7 @@ export class NodeIndexDocument {
305
307
  children: [],
306
308
  neighbors: []
307
309
  };
308
- const node = transform(nodeData, nodeTemplate());
310
+ const node = createNode(nodeData);
309
311
 
310
312
  if (nodeInPage.mesh) {
311
313
  node.geometryData = [{href: './geometries/0'}];
@@ -1,7 +1,6 @@
1
1
  import {join} from 'path';
2
- import transform from 'json-map-transform';
3
- import {METADATA as metadataTemplate} from '../json-templates/metadata';
4
- import {NodeInPage} from '@loaders.gl/i3s';
2
+ import {createMetadata} from '../json-templates/metadata';
3
+ import {NodeInPage} from '@loaders.gl/tiles-3d/i3s';
5
4
  import {isFileExists, openJson} from '../../lib/utils/file-utils';
6
5
  import I3SConverter from '../i3s-converter';
7
6
 
@@ -197,7 +196,7 @@ export default class NodePages {
197
196
  * Save metadata file (for slpk only)
198
197
  */
199
198
  async saveMetadata(): Promise<void> {
200
- const metadata = transform({nodeCount: this.nodesCounter}, metadataTemplate());
199
+ const metadata = createMetadata({nodeCount: this.nodesCounter});
201
200
  const compress = false;
202
201
  await this.converter.writeQueue.enqueue({
203
202
  archiveKey: 'metadata.json',