@loaders.gl/tile-converter 4.5.3 → 5.0.0-alpha.10

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 (125) hide show
  1. package/LICENSE +14 -3
  2. package/README.md +464 -0
  3. package/dist/converter.min.cjs +199 -260
  4. package/dist/i3s-server/bin/i3s-server.min.cjs +106 -341
  5. package/dist/index.cjs +38482 -0
  6. package/dist/index.js +38453 -0
  7. package/dist/v5/adapters.cjs +1992 -0
  8. package/dist/v5/adapters.d.ts +22 -0
  9. package/dist/v5/adapters.js +1972 -0
  10. package/dist/v5/browser-sink.d.ts +37 -0
  11. package/dist/v5/browser-source.d.ts +38 -0
  12. package/dist/v5/browser-tileset-source.d.ts +70 -0
  13. package/dist/v5/browser.cjs +64 -0
  14. package/dist/v5/browser.d.ts +34 -0
  15. package/dist/v5/browser.js +57 -0
  16. package/dist/v5/conversion-api.d.ts +122 -0
  17. package/dist/v5/conversion-archive.d.ts +32 -0
  18. package/dist/v5/core.cjs +863 -0
  19. package/dist/v5/core.d.ts +16 -0
  20. package/dist/v5/core.js +845 -0
  21. package/dist/v5/feature-arrow.d.ts +36 -0
  22. package/dist/v5/i3s-mesh-conversion.d.ts +26 -0
  23. package/dist/v5/index.cjs +63 -0
  24. package/dist/v5/index.d.ts +32 -0
  25. package/dist/v5/index.js +59 -0
  26. package/dist/v5/mesh-conversion.d.ts +62 -0
  27. package/dist/v5/mesh-draco.d.ts +8 -0
  28. package/dist/v5/mesh-source-features.d.ts +21 -0
  29. package/dist/v5/mesh-source-texture.d.ts +4 -0
  30. package/dist/v5/mesh-source.d.ts +34 -0
  31. package/dist/v5/mesh-tileset-archive.d.ts +18 -0
  32. package/dist/v5/mesh-tileset-sink.d.ts +51 -0
  33. package/dist/v5/mesh.d.ts +81 -0
  34. package/dist/v5/point-cloud-conversion.d.ts +31 -0
  35. package/dist/v5/point-cloud-source-encoder.d.ts +49 -0
  36. package/dist/v5/point-cloud-source.d.ts +25 -0
  37. package/dist/v5/point-cloud.d.ts +24 -0
  38. package/dist/v5/resource-manifest.d.ts +58 -0
  39. package/dist/v5/spatial-conversion.d.ts +59 -0
  40. package/dist/v5/tileset-source.d.ts +21 -0
  41. package/package.json +53 -27
  42. package/src/common/README.md +5 -0
  43. package/src/index.ts +1 -2
  44. package/src/{3d-tiles-converter → v4/3d-tiles-converter}/3d-tiles-converter.ts +14 -3
  45. package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/3d-tiles-content-converter.ts +2 -2
  46. package/src/v4/3d-tiles-converter/helpers/validate-i3s-spatial-reference.ts +124 -0
  47. package/src/{3d-tiles-converter → v4/3d-tiles-converter}/json-templates/tileset.ts +4 -4
  48. package/src/{converter-cli.ts → v4/converter-cli.ts} +4 -4
  49. package/src/{deps-installer → v4/deps-installer}/deps-installer.ts +10 -7
  50. package/src/{i3s-converter → v4/i3s-converter}/helpers/attribute-metadata-info.ts +1 -1
  51. package/src/{i3s-converter → v4/i3s-converter}/helpers/batch-ids-extensions.ts +1 -1
  52. package/src/v4/i3s-converter/helpers/encode-string-attribute.ts +23 -0
  53. package/src/{i3s-converter → v4/i3s-converter}/helpers/geometry-attributes.ts +1 -1
  54. package/src/{i3s-converter → v4/i3s-converter}/helpers/geometry-converter.ts +34 -59
  55. package/src/{i3s-converter → v4/i3s-converter}/helpers/gltf-attributes.ts +7 -6
  56. package/src/{i3s-converter → v4/i3s-converter}/helpers/load-3d-tiles.ts +5 -9
  57. package/src/{i3s-converter → v4/i3s-converter}/helpers/node-debug.ts +5 -6
  58. package/src/{i3s-converter → v4/i3s-converter}/i3s-converter.ts +16 -19
  59. package/src/{i3s-converter → v4/i3s-converter}/json-templates/geometry-definitions.ts +4 -4
  60. package/src/{i3s-converter → v4/i3s-converter}/json-templates/layers.ts +6 -6
  61. package/src/{i3s-converter → v4/i3s-converter}/json-templates/node.ts +1 -1
  62. package/src/{i3s-converter → v4/i3s-converter}/json-templates/scene-server.ts +1 -1
  63. package/src/{i3s-converter → v4/i3s-converter}/json-templates/shared-resources.ts +1 -1
  64. package/src/{i3s-converter → v4/i3s-converter}/json-templates/store.ts +1 -1
  65. package/src/{i3s-server → v4/i3s-server}/README.md +2 -2
  66. package/src/{i3s-server → v4/i3s-server}/controllers/slpk-controller.ts +1 -1
  67. package/src/{i3s-server → v4/i3s-server}/routes/slpk-router.ts +2 -1
  68. package/src/v4/index.ts +2 -0
  69. package/src/{lib → v4/lib}/utils/compress-util.ts +8 -7
  70. package/src/{lib → v4/lib}/utils/conversion-dump.ts +4 -4
  71. package/src/{lib → v4/lib}/utils/file-utils.ts +2 -2
  72. package/src/{lib → v4/lib}/utils/lod-conversion-utils.ts +2 -4
  73. package/src/v5/adapters.ts +56 -0
  74. package/src/v5/browser-sink.ts +130 -0
  75. package/src/v5/browser-source.ts +155 -0
  76. package/src/v5/browser-tileset-source.ts +328 -0
  77. package/src/v5/browser.ts +105 -0
  78. package/src/v5/conversion-api.ts +287 -0
  79. package/src/v5/conversion-archive.ts +85 -0
  80. package/src/v5/core.ts +61 -0
  81. package/src/v5/feature-arrow.ts +429 -0
  82. package/src/v5/i3s-mesh-conversion.ts +152 -0
  83. package/src/v5/index.ts +99 -0
  84. package/src/v5/mesh-conversion.ts +200 -0
  85. package/src/v5/mesh-draco.ts +138 -0
  86. package/src/v5/mesh-source-features.ts +232 -0
  87. package/src/v5/mesh-source-texture.ts +122 -0
  88. package/src/v5/mesh-source.ts +360 -0
  89. package/src/v5/mesh-tileset-archive.ts +50 -0
  90. package/src/v5/mesh-tileset-sink.ts +324 -0
  91. package/src/v5/mesh.ts +517 -0
  92. package/src/v5/point-cloud-conversion.ts +80 -0
  93. package/src/v5/point-cloud-source-encoder.ts +105 -0
  94. package/src/v5/point-cloud-source.ts +84 -0
  95. package/src/v5/point-cloud.ts +271 -0
  96. package/src/v5/resource-manifest.ts +213 -0
  97. package/src/v5/spatial-conversion.ts +305 -0
  98. package/src/v5/tileset-source.ts +54 -0
  99. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/i3s-obb-to-3d-tiles-obb.ts +0 -0
  100. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/load-i3s.ts +0 -0
  101. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/texture-atlas.ts +0 -0
  102. /package/src/{constants.ts → v4/constants.ts} +0 -0
  103. /package/src/{i3s-converter → v4/i3s-converter}/helpers/coordinate-converter.ts +0 -0
  104. /package/src/{i3s-converter → v4/i3s-converter}/helpers/create-scene-server-path.ts +0 -0
  105. /package/src/{i3s-converter → v4/i3s-converter}/helpers/feature-attributes.ts +0 -0
  106. /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-index-document.ts +0 -0
  107. /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-pages.ts +0 -0
  108. /package/src/{i3s-converter → v4/i3s-converter}/helpers/preprocess-3d-tiles.ts +0 -0
  109. /package/src/{i3s-converter → v4/i3s-converter}/helpers/progress.ts +0 -0
  110. /package/src/{i3s-converter → v4/i3s-converter}/helpers/tileset-traversal.ts +0 -0
  111. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/metadata.ts +0 -0
  112. /package/src/{i3s-converter → v4/i3s-converter}/types.ts +0 -0
  113. /package/src/{i3s-server → v4/i3s-server}/app.ts +0 -0
  114. /package/src/{i3s-server → v4/i3s-server}/bin/www.ts +0 -0
  115. /package/src/{i3s-server → v4/i3s-server}/certs/cert.pem +0 -0
  116. /package/src/{i3s-server → v4/i3s-server}/certs/key.pem +0 -0
  117. /package/src/{i3s-server → v4/i3s-server}/utils/create-scene-server.ts +0 -0
  118. /package/src/{i3s-server → v4/i3s-server}/utils/server-utils.ts +0 -0
  119. /package/src/{lib → v4/lib}/json-schemas/conversion-dump-json-schema.ts +0 -0
  120. /package/src/{lib → v4/lib}/utils/cli-utils.ts +0 -0
  121. /package/src/{lib → v4/lib}/utils/geometry-utils.ts +0 -0
  122. /package/src/{lib → v4/lib}/utils/queue.ts +0 -0
  123. /package/src/{lib → v4/lib}/utils/statistic-utils.ts +0 -0
  124. /package/src/{lib → v4/lib}/utils/write-queue.ts +0 -0
  125. /package/src/{pgm-loader.ts → v4/pgm-loader.ts} +0 -0
@@ -21,7 +21,6 @@ import {Ellipsoid} from '@math.gl/geospatial';
21
21
  /* @ts-expect-error TS2732: Cannot find module 'node:module' or its corresponding type declarations. */
22
22
  import {createRequire} from 'node:module';
23
23
  /* @ts-expect-error TS2732: Cannot find module 'node:module' or its corresponding type declarations. */
24
- import {dirname, join} from 'node:path';
25
24
 
26
25
  import {DracoWriterWorker} from '@loaders.gl/draco';
27
26
  import {assert, encode} from '@loaders.gl/core';
@@ -34,6 +33,7 @@ import {
34
33
  import md5 from 'md5';
35
34
  import {v4 as uuidv4} from 'uuid';
36
35
  import {generateAttributes} from './geometry-attributes';
36
+ import {encodeStringAttribute} from './encode-string-attribute';
37
37
  import {createBoundingVolumesFromGeometry} from './coordinate-converter';
38
38
  import {
39
39
  ConvertedAttributes,
@@ -52,7 +52,7 @@ import {Geoid} from '@math.gl/geoid';
52
52
  import {prepareDataForAttributesConversion} from './gltf-attributes';
53
53
  import {getTextureByMetadataClass, handleBatchIdsExtensions} from './batch-ids-extensions';
54
54
  import {checkPropertiesLength, flattenPropertyTableByFeatureIds} from './feature-attributes';
55
- import {GL} from '@loaders.gl/math';
55
+ import {GL} from '@math.gl/geometry-utils';
56
56
 
57
57
  /*
58
58
  At the moment of writing the type TypedArrayConstructor is not exported in '@math.gl/types'.
@@ -304,7 +304,7 @@ async function _makeNodeResources({
304
304
  faceRange.buffer
305
305
  )
306
306
  );
307
- // prettier-ignore
307
+ // biome-ignore format: preserve intentional fixture layout
308
308
  const compressedGeometry = draco
309
309
  ? generateCompressedGeometry(
310
310
  vertexCount,
@@ -1028,15 +1028,18 @@ async function mergeMaterials(
1028
1028
  material1.mergedMaterials &&
1029
1029
  material2.mergedMaterials
1030
1030
  ) {
1031
- const buffer1 = Buffer.from(material1.texture.bufferView.data);
1032
- const buffer2 = Buffer.from(material2.texture.bufferView.data);
1031
+ const firstImageBytes = new Uint8Array(material1.texture.bufferView.data);
1032
+ const secondImageBytes = new Uint8Array(material2.texture.bufferView.data);
1033
1033
  try {
1034
1034
  // @ts-ignore
1035
1035
  const {joinImages} = await import('join-images');
1036
- const sharpData = await joinImages([buffer1, buffer2], {direction: 'horizontal'});
1037
- material1.texture.bufferView.data = await sharpData
1036
+ const sharpData = await joinImages([firstImageBytes, secondImageBytes], {
1037
+ direction: 'horizontal'
1038
+ });
1039
+ const encodedImage = await sharpData
1038
1040
  .toFormat(material1.texture.mimeType === 'image/png' ? 'png' : 'jpeg')
1039
1041
  .toBuffer();
1042
+ material1.texture.bufferView.data = new Uint8Array(encodedImage);
1040
1043
  } catch (error) {
1041
1044
  // eslint-disable-next-line no-console
1042
1045
  console.log(
@@ -1056,10 +1059,10 @@ async function mergeMaterials(
1056
1059
  * @param sourceMaterial - material object
1057
1060
  * @returns I3S material definition and texture
1058
1061
  */
1059
- function convertMaterial(sourceMaterial: GLTFMaterialPostprocessed): I3SMaterialWithTexture {
1062
+ export function convertMaterial(sourceMaterial: GLTFMaterialPostprocessed): I3SMaterialWithTexture {
1060
1063
  const material: I3SMaterialDefinition = {
1061
1064
  doubleSided: sourceMaterial.doubleSided,
1062
- emissiveFactor: sourceMaterial.emissiveFactor?.map((c) => Math.round(c * 255)) as [
1065
+ emissiveFactor: sourceMaterial.emissiveFactor?.map(c => Math.round(c * 255)) as [
1063
1066
  number,
1064
1067
  number,
1065
1068
  number
@@ -1069,9 +1072,9 @@ function convertMaterial(sourceMaterial: GLTFMaterialPostprocessed): I3SMaterial
1069
1072
  alphaMode: convertAlphaMode(sourceMaterial.alphaMode),
1070
1073
  pbrMetallicRoughness: {
1071
1074
  roughnessFactor:
1072
- sourceMaterial?.pbrMetallicRoughness?.roughnessFactor || DEFAULT_ROUGHNESS_FACTOR,
1075
+ sourceMaterial?.pbrMetallicRoughness?.roughnessFactor ?? DEFAULT_ROUGHNESS_FACTOR,
1073
1076
  metallicFactor:
1074
- sourceMaterial?.pbrMetallicRoughness?.metallicFactor || DEFAULT_METALLIC_FACTOR
1077
+ sourceMaterial?.pbrMetallicRoughness?.metallicFactor ?? DEFAULT_METALLIC_FACTOR
1075
1078
  }
1076
1079
  };
1077
1080
 
@@ -1095,8 +1098,10 @@ function convertMaterial(sourceMaterial: GLTFMaterialPostprocessed): I3SMaterial
1095
1098
  // Should use default baseColorFactor if it is not present in source material
1096
1099
  // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-pbrmetallicroughness
1097
1100
  const baseColorFactor = sourceMaterial?.pbrMetallicRoughness?.baseColorFactor;
1101
+ // This converter's I3S storage path uses byte-style color values; the I3S loader normalizes
1102
+ // them when creating the glTF-compatible material consumed by deck/luma.
1098
1103
  material.pbrMetallicRoughness.baseColorFactor =
1099
- ((baseColorFactor && baseColorFactor.map((c) => Math.round(c * 255))) as [
1104
+ ((baseColorFactor && baseColorFactor.map(c => Math.round(c * 255))) as [
1100
1105
  number,
1101
1106
  number,
1102
1107
  number,
@@ -1456,10 +1461,10 @@ function generateAttributeBuffer(type: string, value: any): ArrayBuffer {
1456
1461
  attributeBuffer = generateDoubleAttributeBuffer(value);
1457
1462
  break;
1458
1463
  case STRING_TYPE:
1459
- attributeBuffer = generateStringAttributeBuffer(value);
1464
+ attributeBuffer = encodeStringAttribute(value);
1460
1465
  break;
1461
1466
  default:
1462
- attributeBuffer = generateStringAttributeBuffer(value);
1467
+ attributeBuffer = encodeStringAttribute(value);
1463
1468
  }
1464
1469
 
1465
1470
  return attributeBuffer;
@@ -1472,7 +1477,7 @@ function generateAttributeBuffer(type: string, value: any): ArrayBuffer {
1472
1477
  * @returns attribute type.
1473
1478
  */
1474
1479
  function getAttributeType(key: string, attributeStorageInfo: any[]): string {
1475
- const attribute = attributeStorageInfo.find((attr) => attr.name === key);
1480
+ const attribute = attributeStorageInfo.find(attr => attr.name === key);
1476
1481
  if (!attribute) {
1477
1482
  // eslint-disable-next-line no-console
1478
1483
  console.error(
@@ -1495,7 +1500,7 @@ function getAttributeType(key: string, attributeStorageInfo: any[]): string {
1495
1500
  /**
1496
1501
  * Convert short integer to attribute arrayBuffer.
1497
1502
  * @param featureIds
1498
- * @returns - Buffer with objectId data.
1503
+ * @returns ArrayBuffer with objectId data.
1499
1504
  */
1500
1505
  function generateShortIntegerAttributeBuffer(featureIds: any[]): ArrayBuffer {
1501
1506
  const count = new Uint32Array([featureIds.length]);
@@ -1506,7 +1511,7 @@ function generateShortIntegerAttributeBuffer(featureIds: any[]): ArrayBuffer {
1506
1511
  /**
1507
1512
  * Convert double to attribute arrayBuffer.
1508
1513
  * @param featureIds
1509
- * @returns - Buffer with objectId data.
1514
+ * @returns ArrayBuffer with objectId data.
1510
1515
  */
1511
1516
  function generateDoubleAttributeBuffer(featureIds: any[]): ArrayBuffer {
1512
1517
  const count = new Uint32Array([featureIds.length]);
@@ -1516,36 +1521,6 @@ function generateDoubleAttributeBuffer(featureIds: any[]): ArrayBuffer {
1516
1521
  return concatenateArrayBuffers(count.buffer, padding.buffer, valuesArray.buffer);
1517
1522
  }
1518
1523
 
1519
- /**
1520
- * Convert batch table attributes to array buffer with batch table data.
1521
- * @param batchAttributes
1522
- * @returns - Buffer with batch table data.
1523
- */
1524
- function generateStringAttributeBuffer(batchAttributes: any[]): ArrayBuffer {
1525
- const stringCountArray = new Uint32Array([batchAttributes.length]);
1526
- let totalNumberOfBytes = 0;
1527
- const stringSizesArray = new Uint32Array(batchAttributes.length);
1528
- const stringBufferArray: ArrayBuffer[] = [];
1529
-
1530
- for (let index = 0; index < batchAttributes.length; index++) {
1531
- const currentString = `${String(batchAttributes[index])}\0`;
1532
- const currentStringBuffer = Buffer.from(currentString);
1533
- const currentStringSize = currentStringBuffer.length;
1534
- totalNumberOfBytes += currentStringSize;
1535
- stringSizesArray[index] = currentStringSize;
1536
- stringBufferArray.push(currentStringBuffer);
1537
- }
1538
-
1539
- const totalBytes = new Uint32Array([totalNumberOfBytes]);
1540
-
1541
- return concatenateArrayBuffers(
1542
- stringCountArray.buffer,
1543
- totalBytes.buffer,
1544
- stringSizesArray.buffer,
1545
- ...stringBufferArray
1546
- );
1547
- }
1548
-
1549
1524
  /**
1550
1525
  * Convert featureIds to BigUint64Array.
1551
1526
  * @param featureIds
@@ -1560,14 +1535,14 @@ function generateBigUint64Array(featureIds: any[]): BigUint64Array {
1560
1535
  }
1561
1536
 
1562
1537
  /**
1563
- * Generates draco compressed geometry
1564
- * @param vertexCount
1565
- * @param convertedAttributes - get rid of this argument here
1566
- * @param attributes - geometry attributes to compress
1567
- * @param libraries - dynamicaly loaded 3rd-party libraries
1568
- * @returns - Compressed geometry.
1538
+ * Generates Edge Breaker Draco geometry with I3S feature and texture metadata.
1539
+ * @param vertexCount - Number of vertices in the grouped triangle list.
1540
+ * @param convertedAttributes - Original attributes used to size the feature-index array.
1541
+ * @param attributes - Grouped I3S geometry attributes and inclusive face ranges.
1542
+ * @param libraries - Local Draco encoder library locations.
1543
+ * @returns Compressed geometry; the worker transfers the input attribute buffers.
1569
1544
  */
1570
- async function generateCompressedGeometry(
1545
+ export async function generateCompressedGeometry(
1571
1546
  vertexCount: number,
1572
1547
  convertedAttributes: Record<string, any>,
1573
1548
  attributes: Record<string, any>,
@@ -1629,7 +1604,7 @@ async function generateCompressedGeometry(
1629
1604
  modules: libraries,
1630
1605
  useLocalLibraries: true,
1631
1606
  draco: {
1632
- method: 'MESH_SEQUENTIAL_ENCODING',
1607
+ method: 'MESH_EDGEBREAKER_ENCODING',
1633
1608
  attributesMetadata
1634
1609
  },
1635
1610
  ['draco-writer']: {
@@ -1640,14 +1615,14 @@ async function generateCompressedGeometry(
1640
1615
  );
1641
1616
  }
1642
1617
 
1618
+ /** Resolve the published Node Draco writer, falling back to the dependency installer destination. */
1643
1619
  function getLocalDracoWriterWorkerUrl(): string {
1644
1620
  try {
1645
1621
  const require = createRequire(import.meta.url);
1646
- const packageJsonPath = require.resolve('@loaders.gl/draco/package.json');
1647
- return join(dirname(packageJsonPath), 'src/workers/draco-writer-worker-node.cjs');
1622
+ return require.resolve('@loaders.gl/draco/draco-writer-worker-node.cjs');
1648
1623
  } catch {
1649
1624
  // Fall back to monorepo-local path
1650
- return './modules/draco/src/workers/draco-writer-worker-node.cjs';
1625
+ return './modules/draco/dist/draco-writer-worker-node.cjs';
1651
1626
  }
1652
1627
  }
1653
1628
 
@@ -1671,7 +1646,7 @@ function generateFeatureIndexAttribute(
1671
1646
  orderedFeatureIndices.fill(fillIndex, startIndex, endIndex);
1672
1647
 
1673
1648
  fillIndex++;
1674
- startIndex = endIndex + 1;
1649
+ startIndex = endIndex;
1675
1650
  }
1676
1651
 
1677
1652
  return orderedFeatureIndices;
@@ -2,6 +2,7 @@ import type {Tiles3DTileContent} from '@loaders.gl/3d-tiles';
2
2
  import type {GLTFAccessorPostprocessed, GLTFNodePostprocessed} from '@loaders.gl/gltf';
3
3
  import {Matrix4, TypedArray, Vector3} from '@math.gl/core';
4
4
  import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
5
+ import {getImageData} from '@loaders.gl/images';
5
6
  import {Ellipsoid} from '@math.gl/geospatial';
6
7
  import {GLTFAttributesData} from '../types';
7
8
 
@@ -25,20 +26,20 @@ export function prepareDataForAttributesConversion(
25
26
  [];
26
27
 
27
28
  const images =
28
- tileContent.gltf?.images?.map((imageObject) => {
29
+ tileContent.gltf?.images?.map(imageObject => {
29
30
  // Need data only for uncompressed images because we can't get batchIds from compressed textures.
30
31
  if (imageObject?.image?.compressed) {
31
32
  return null;
32
33
  }
33
- const data = imageObject?.image?.data;
34
+ const {data, width, height} = getImageData(imageObject.image);
34
35
  const dataCopy = new Uint8Array(data.length);
35
36
  dataCopy.set(data);
36
37
  return {
37
38
  data: dataCopy,
38
39
  compressed: false,
39
- height: imageObject.image.height,
40
- width: imageObject.image.width,
41
- components: imageObject.image.components,
40
+ height,
41
+ width,
42
+ components: data.length / (width * height),
42
43
  mimeType: imageObject.mimeType
43
44
  };
44
45
  }) || [];
@@ -141,7 +142,7 @@ function prepareNodes(nodes: GLTFNodePostprocessed[]): void {
141
142
  ...node,
142
143
  mesh: {
143
144
  ...node.mesh,
144
- primitives: node.mesh?.primitives.map((primitive) => ({
145
+ primitives: node.mesh?.primitives.map(primitive => ({
145
146
  ...primitive,
146
147
  indices: {value: primitive?.indices?.value},
147
148
  attributes: getB3DMAttributesWithoutBufferView(primitive.attributes),
@@ -119,15 +119,11 @@ export async function loadFromArchive(
119
119
  const hashTable = await loadHashTable(fileProvider);
120
120
  const archive = new Tiles3DArchive(fileProvider, hashTable, tz3Path);
121
121
  const fileSystem = new ZipFileSystem(archive);
122
- // const loadOptionsWithoutDeprecatedFetch = {...loadOptions} as Tiles3DLoaderOptions & {
123
- // fetch?: unknown;
124
- // };
125
- // delete loadOptionsWithoutDeprecatedFetch.fetch;
126
- // const mergedOptions = {
127
- // ...loadOptionsWithoutDeprecatedFetch,
128
- // core: {...loadOptions?.core, fetch: fileSystem.fetch.bind(fileSystem)}
129
- // }
130
- const content = await load(filename, loader, loadOptions);
122
+ const archiveLoadOptions = {
123
+ ...loadOptions,
124
+ core: {...loadOptions?.core, fetch: fileSystem.fetch.bind(fileSystem)}
125
+ };
126
+ const content = await load(filename, loader, archiveLoadOptions);
131
127
  await fileSystem.destroy();
132
128
  return content;
133
129
  }
@@ -3,7 +3,7 @@ import {OrientedBoundingBox, BoundingSphere} from '@math.gl/culling';
3
3
  import {Vector3} from '@math.gl/core';
4
4
  import {Ellipsoid} from '@math.gl/geospatial';
5
5
 
6
- // prettier-ignore
6
+ // biome-ignore format: preserve intentional fixture layout
7
7
  const CUBE_POSITIONS = new Float32Array([
8
8
  -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1,
9
9
  -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1,
@@ -103,11 +103,10 @@ function getTileObbVertices(node: Node3DIndexDocument): number[] {
103
103
  let vertices = [];
104
104
 
105
105
  for (let i = 0; i < positions.length; i += 3) {
106
- const positionsVector = new Vector3(
107
- (positions[i] *= halfSize[0]),
108
- (positions[i + 1] *= halfSize[1]),
109
- (positions[i + 2] *= halfSize[2])
110
- );
106
+ positions[i] *= halfSize[0];
107
+ positions[i + 1] *= halfSize[1];
108
+ positions[i + 2] *= halfSize[2];
109
+ const positionsVector = new Vector3(positions[i], positions[i + 1], positions[i + 2]);
111
110
  const rotatedPositions = positionsVector
112
111
  // @ts-expect-error
113
112
  .transformByQuaternion(node.obb.quaternion)
@@ -49,7 +49,7 @@ import {validateNodeBoundingVolumes} from './helpers/node-debug';
49
49
  import {KTX2BasisWriterWorker} from '@loaders.gl/textures';
50
50
  import {LoaderWithParser} from '@loaders.gl/loader-utils';
51
51
  import {I3SMaterialDefinition, TextureSetDefinitionFormats} from '@loaders.gl/i3s';
52
- import {ImageWriter} from '@loaders.gl/images';
52
+ import {getImageData, ImageWriter} from '@loaders.gl/images';
53
53
  import {GLTFImagePostprocessed} from '@loaders.gl/gltf';
54
54
  import {
55
55
  GLTFPrimitiveModeString,
@@ -143,7 +143,7 @@ export default class I3SConverter {
143
143
  basis: {
144
144
  format: 'rgba32',
145
145
  // We need to load local fs workers because nodejs can't load workers from the Internet
146
- workerUrl: './modules/textures/dist/basis-worker-node.js'
146
+ workerUrl: './modules/textures/dist/basis-worker-node.cjs'
147
147
  },
148
148
  // We need to load local fs workers because nodejs can't load workers from the Internet
149
149
  draco: {workerUrl: './modules/draco/dist/draco-worker-node.js'},
@@ -382,7 +382,7 @@ export default class I3SConverter {
382
382
  ...this.loadOptions,
383
383
  '3d-tiles': {...this.loadOptions['3d-tiles'], loadGLTF: false}
384
384
  });
385
- } catch (error) {
385
+ } catch (_error) {
386
386
  // eslint-disable-next-line no-console
387
387
  console.log(
388
388
  `[warning]: Failed to load ${sourceTile.contentUrl}. An I3S tile with empty content will be added to the output tileset`
@@ -462,7 +462,7 @@ export default class I3SConverter {
462
462
  : tilesetPath;
463
463
  try {
464
464
  await removeDir(removePath);
465
- } catch (e) {
465
+ } catch (_e) {
466
466
  // do nothing
467
467
  }
468
468
 
@@ -532,7 +532,7 @@ export default class I3SConverter {
532
532
  this.layers0!.materialDefinitions = this.materialDefinitions;
533
533
  // @ts-ignore
534
534
  this.layers0.geometryDefinitions = transform(
535
- this.geometryConfigs.map((config) => ({
535
+ this.geometryConfigs.map(config => ({
536
536
  geometryConfig: {...config, draco: this.options.draco}
537
537
  })),
538
538
  geometryDefinitionTemlate()
@@ -540,9 +540,7 @@ export default class I3SConverter {
540
540
 
541
541
  if (this.layersHasTexture === false) {
542
542
  this.layers0!.store.defaultGeometrySchema.ordering =
543
- this.layers0!.store.defaultGeometrySchema.ordering.filter(
544
- (attribute) => attribute !== 'uv0'
545
- );
543
+ this.layers0!.store.defaultGeometrySchema.ordering.filter(attribute => attribute !== 'uv0');
546
544
  }
547
545
 
548
546
  await this._writeLayers0();
@@ -614,14 +612,14 @@ export default class I3SConverter {
614
612
  const slpkTilesetPath = join(tilesetPath, 'SceneServer', 'layers', '0');
615
613
  const slpkFileName = `${tilesetPath}.slpk`;
616
614
 
617
- await createZip(slpkTilesetPath, slpkFileName, async (fileList) => ({
615
+ await createZip(slpkTilesetPath, slpkFileName, async fileList => ({
618
616
  path: '@specialIndexFileHASH128@',
619
617
  file: await composeHashFile(fileList)
620
618
  }));
621
619
 
622
620
  try {
623
621
  await removeDir(tilesetPath);
624
- } catch (e) {
622
+ } catch (_e) {
625
623
  // do nothing
626
624
  }
627
625
  }
@@ -728,7 +726,7 @@ export default class I3SConverter {
728
726
  this.layersHasTexture ||
729
727
  Boolean(
730
728
  ('texture' in resources && resources.texture) ||
731
- ('texelCountHint' in resources && resources.texelCountHint)
729
+ ('texelCountHint' in resources && resources.texelCountHint)
732
730
  );
733
731
 
734
732
  if (this.generateBoundingVolumes && resources.boundingVolumes) {
@@ -737,7 +735,7 @@ export default class I3SConverter {
737
735
 
738
736
  const lodSelection = convertGeometricErrorToScreenThreshold(sourceTile, boundingVolumes);
739
737
  const maxScreenThresholdSQ = lodSelection.find(
740
- (val) => val.metricType === 'maxScreenThresholdSQ'
738
+ val => val.metricType === 'maxScreenThresholdSQ'
741
739
  ) || {maxError: 0};
742
740
 
743
741
  if (isDumped) {
@@ -837,7 +835,7 @@ export default class I3SConverter {
837
835
  let tileContent: Tiles3DTileContent | null = null;
838
836
  try {
839
837
  tileContent = await loadTile3DContent(this.sourceTileset, sourceTile, this.loadOptions);
840
- } catch (error) {
838
+ } catch (_error) {
841
839
  // eslint-disable-next-line no-console
842
840
  console.log(`[warning]: Failed to load ${sourceTile.contentUrl}`);
843
841
  }
@@ -1017,7 +1015,7 @@ export default class I3SConverter {
1017
1015
  definition: this.findOrCreateGeometryDefinition(
1018
1016
  Boolean(
1019
1017
  ('texture' in resources && resources.texture) ||
1020
- ('texelCountHint' in resources && resources.texelCountHint)
1018
+ ('texelCountHint' in resources && resources.texelCountHint)
1021
1019
  ),
1022
1020
  hasUvRegions
1023
1021
  ),
@@ -1268,18 +1266,17 @@ export default class I3SConverter {
1268
1266
 
1269
1267
  if (this.generateTextures) {
1270
1268
  formats.push({name: '1', format: 'ktx2'});
1271
- // For Node.js texture.image.data is type of Buffer
1272
- const copyArrayBuffer = texture.image.data.subarray();
1273
- const arrayToEncode = new Uint8Array(copyArrayBuffer);
1269
+ const imageData = getImageData(texture.image);
1270
+ const arrayToEncode = new Uint8Array(imageData.data);
1274
1271
  const ktx2TextureData = encode(
1275
- {...texture.image, data: arrayToEncode},
1272
+ {...imageData, data: arrayToEncode},
1276
1273
  // @ts-expect-error - Worker encoder typing is still WIP
1277
1274
  KTX2BasisWriterWorker,
1278
1275
  {
1279
1276
  ...KTX2BasisWriterWorker.options,
1280
1277
  ['ktx2-basis-writer']: {
1281
1278
  // We need to load local fs workers because nodejs can't load workers from the Internet
1282
- workerUrl: './modules/textures/dist/ktx2-basis-writer-worker-node.js'
1279
+ workerUrl: './modules/textures/dist/ktx2-basis-writer-worker-node.cjs'
1283
1280
  },
1284
1281
  reuseWorkers: true,
1285
1282
  _nodeWorkers: true,
@@ -18,7 +18,7 @@ const PLAIN_GEOMETRY_DEFINITION = () => ({
18
18
  },
19
19
  uv0: {
20
20
  path: 'hasTexture',
21
- transform: (val) => (val && {type: 'Float32', component: 2}) || false,
21
+ transform: val => (val && {type: 'Float32', component: 2}) || false,
22
22
  omitValues: [false]
23
23
  },
24
24
  color: {
@@ -29,7 +29,7 @@ const PLAIN_GEOMETRY_DEFINITION = () => ({
29
29
  },
30
30
  uvRegion: {
31
31
  path: 'hasUvRegions',
32
- transform: (val) => (val && {type: 'UInt16', component: 4}) || false,
32
+ transform: val => (val && {type: 'UInt16', component: 4}) || false,
33
33
  omitValues: [false]
34
34
  },
35
35
  featureId: {
@@ -54,7 +54,7 @@ const COMPRESSED_GEOMETRY_DEFINITION = () => ({
54
54
  },
55
55
  'compressedAttributes.attributes': {
56
56
  path: 'geometryConfig',
57
- transform: (val) => {
57
+ transform: val => {
58
58
  const result = ['position', 'normal'];
59
59
  if (val.hasTexture) {
60
60
  result.push('uv0');
@@ -72,7 +72,7 @@ const COMPRESSED_GEOMETRY_DEFINITION = () => ({
72
72
  export const GEOMETRY_DEFINITION = () => ({
73
73
  geometryBuffers: {
74
74
  path: 'geometryConfig',
75
- transform: (val) => {
75
+ transform: val => {
76
76
  const result = [transform(val, PLAIN_GEOMETRY_DEFINITION())];
77
77
  if (val.draco) {
78
78
  result.push(transform({geometryConfig: val}, COMPRESSED_GEOMETRY_DEFINITION()));
@@ -69,7 +69,7 @@ const FULL_EXTENT = () => ({
69
69
  export const LAYERS = () => ({
70
70
  version: {
71
71
  path: 'version',
72
- transform: (val) => val.toUpperCase()
72
+ transform: val => val.toUpperCase()
73
73
  },
74
74
  id: {
75
75
  path: 'id',
@@ -88,7 +88,7 @@ export const LAYERS = () => ({
88
88
  },
89
89
  spatialReference: {
90
90
  path: 'spatialReference',
91
- transform: (val) => transform(val, SPATIAL_REFERENCE())
91
+ transform: val => transform(val, SPATIAL_REFERENCE())
92
92
  },
93
93
  capabilities: {
94
94
  path: 'capabilities',
@@ -96,19 +96,19 @@ export const LAYERS = () => ({
96
96
  },
97
97
  store: {
98
98
  path: 'store',
99
- transform: (val) => transform(val, STORE)
99
+ transform: val => transform(val, STORE)
100
100
  },
101
101
  fullExtent: {
102
102
  path: 'fullExtent',
103
- transform: (val) => transform(val, FULL_EXTENT())
103
+ transform: val => transform(val, FULL_EXTENT())
104
104
  },
105
105
  heightModelInfo: {
106
106
  path: 'heightModelInfo',
107
- transform: (val) => transform(val, HEIGHT_MODEL_INFO())
107
+ transform: val => transform(val, HEIGHT_MODEL_INFO())
108
108
  },
109
109
  nodePages: {
110
110
  path: 'nodePages',
111
- transform: (val) => transform(val, NODE_PAGES())
111
+ transform: val => transform(val, NODE_PAGES())
112
112
  },
113
113
  materialDefinitions: {
114
114
  path: 'materialDefinitions',
@@ -60,7 +60,7 @@ export const NODE = () => ({
60
60
  },
61
61
  parentNode: {
62
62
  path: 'parentNode',
63
- transform: (val) => transform(val, PARENT_NODE()),
63
+ transform: val => transform(val, PARENT_NODE()),
64
64
  default: null
65
65
  },
66
66
  sharedResource: {
@@ -22,6 +22,6 @@ export const SCENE_SERVER = () => ({
22
22
  },
23
23
  layers: {
24
24
  path: 'layers0',
25
- transform: (layers0) => [layers0]
25
+ transform: layers0 => [layers0]
26
26
  }
27
27
  });
@@ -94,7 +94,7 @@ const TEXTURE_DEFINITION_INFO = () => ({
94
94
  images: {
95
95
  path: 'images',
96
96
  transform: (val, thisObject, originalObject) =>
97
- val.map((image) => transform(image, TEXTURE_DEFINITION_IMAGE()))
97
+ val.map(image => transform(image, TEXTURE_DEFINITION_IMAGE()))
98
98
  }
99
99
  });
100
100
 
@@ -1,7 +1,7 @@
1
1
  export const STORE = {
2
2
  id: {
3
3
  path: 'id',
4
- transform: (val) => val.toUpperCase()
4
+ transform: val => val.toUpperCase()
5
5
  },
6
6
  profile: {
7
7
  path: 'profile',
@@ -6,8 +6,8 @@ The server provides I3S Rest endpoints per specification https://github.com/Esri
6
6
  ## Development
7
7
 
8
8
  - install tsx globally `yarn global add tsx`
9
- - uncomment "local debug" lines in `modules/tile-converter/src/i3s-server/app.ts` and `modules/tile-converter/src/i3s-server/bin/www.ts` (see comments);
10
- - run `PORT=8080 HTTPS_PORT=4443 I3sLayerPath="./path/to/dataset" DEBUG=i3s-server:* npx tsx ./src/i3s-server/bin/www.ts`
9
+ - uncomment "local debug" lines in `src/v4/i3s-server/app.ts` and `src/v4/i3s-server/bin/www.ts` (see comments);
10
+ - run `PORT=8080 HTTPS_PORT=4443 I3sLayerPath="./path/to/dataset" DEBUG=i3s-server:* npx tsx ./src/v4/i3s-server/bin/www.ts`
11
11
 
12
12
  ## Usage
13
13
 
@@ -11,7 +11,7 @@ let slpkArchive: SLPKArchive;
11
11
  export async function loadArchive(fullLayerPath: string): Promise<void> {
12
12
  slpkArchive = await parseSLPKArchive(
13
13
  new NodeFile(fullLayerPath),
14
- (msg) => console.log(msg) // eslint-disable-line no-console
14
+ msg => console.log(msg) // eslint-disable-line no-console
15
15
  );
16
16
  // eslint-disable-next-line no-console
17
17
  console.log('The server is ready to use');
@@ -28,7 +28,8 @@ router.get('*', (req, res, next) => {
28
28
  try {
29
29
  const json = JSON.parse(textDecoder.decode(file));
30
30
  res.send(json);
31
- } catch (e) {
31
+ } catch (_e) {
32
+ // Express 4 sends typed arrays as JSON; adapt only at this Node.js HTTP boundary.
32
33
  res.send(Buffer.from(file));
33
34
  }
34
35
  } else {
@@ -0,0 +1,2 @@
1
+ export {default as I3SConverter} from './i3s-converter/i3s-converter';
2
+ export {default as Tiles3DConverter} from './3d-tiles-converter/3d-tiles-converter';
@@ -1,5 +1,6 @@
1
1
  import {createGzip} from 'zlib';
2
2
  import {createReadStream, createWriteStream} from 'fs';
3
+ import {pipeline} from 'stream';
3
4
 
4
5
  /**
5
6
  * Compress file to gzip file
@@ -14,15 +15,15 @@ export function compressFileWithGzip(pathFile: string): Promise<string> {
14
15
  const output = createWriteStream(compressedPathFile);
15
16
 
16
17
  return new Promise((resolve, reject) => {
17
- input.on('end', () => {
18
+ pipeline(input, gzip, output, error => {
19
+ if (error) {
20
+ console.log(`${compressedPathFile}: compression error!`); // eslint-disable-line no-undef,no-console
21
+ reject(error);
22
+ return;
23
+ }
24
+
18
25
  console.log(`${compressedPathFile} compressed and saved.`); // eslint-disable-line no-undef,no-console
19
26
  resolve(compressedPathFile);
20
27
  });
21
- input.on('error', (error) => {
22
- console.log(`${compressedPathFile}: compression error!`); // eslint-disable-line no-undef,no-console
23
- reject(error);
24
- });
25
- // @ts-ignore Seems typescript upgrade triggered this
26
- input.pipe(gzip).pipe(output);
27
28
  });
28
29
  }