@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.
- package/LICENSE +14 -3
- package/README.md +464 -0
- package/dist/converter.min.cjs +199 -260
- package/dist/i3s-server/bin/i3s-server.min.cjs +106 -341
- package/dist/index.cjs +38482 -0
- package/dist/index.js +38453 -0
- package/dist/v5/adapters.cjs +1992 -0
- package/dist/v5/adapters.d.ts +22 -0
- package/dist/v5/adapters.js +1972 -0
- package/dist/v5/browser-sink.d.ts +37 -0
- package/dist/v5/browser-source.d.ts +38 -0
- package/dist/v5/browser-tileset-source.d.ts +70 -0
- package/dist/v5/browser.cjs +64 -0
- package/dist/v5/browser.d.ts +34 -0
- package/dist/v5/browser.js +57 -0
- package/dist/v5/conversion-api.d.ts +122 -0
- package/dist/v5/conversion-archive.d.ts +32 -0
- package/dist/v5/core.cjs +863 -0
- package/dist/v5/core.d.ts +16 -0
- package/dist/v5/core.js +845 -0
- package/dist/v5/feature-arrow.d.ts +36 -0
- package/dist/v5/i3s-mesh-conversion.d.ts +26 -0
- package/dist/v5/index.cjs +63 -0
- package/dist/v5/index.d.ts +32 -0
- package/dist/v5/index.js +59 -0
- package/dist/v5/mesh-conversion.d.ts +62 -0
- package/dist/v5/mesh-draco.d.ts +8 -0
- package/dist/v5/mesh-source-features.d.ts +21 -0
- package/dist/v5/mesh-source-texture.d.ts +4 -0
- package/dist/v5/mesh-source.d.ts +34 -0
- package/dist/v5/mesh-tileset-archive.d.ts +18 -0
- package/dist/v5/mesh-tileset-sink.d.ts +51 -0
- package/dist/v5/mesh.d.ts +81 -0
- package/dist/v5/point-cloud-conversion.d.ts +31 -0
- package/dist/v5/point-cloud-source-encoder.d.ts +49 -0
- package/dist/v5/point-cloud-source.d.ts +25 -0
- package/dist/v5/point-cloud.d.ts +24 -0
- package/dist/v5/resource-manifest.d.ts +58 -0
- package/dist/v5/spatial-conversion.d.ts +59 -0
- package/dist/v5/tileset-source.d.ts +21 -0
- package/package.json +53 -27
- package/src/common/README.md +5 -0
- package/src/index.ts +1 -2
- package/src/{3d-tiles-converter → v4/3d-tiles-converter}/3d-tiles-converter.ts +14 -3
- package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/3d-tiles-content-converter.ts +2 -2
- package/src/v4/3d-tiles-converter/helpers/validate-i3s-spatial-reference.ts +124 -0
- package/src/{3d-tiles-converter → v4/3d-tiles-converter}/json-templates/tileset.ts +4 -4
- package/src/{converter-cli.ts → v4/converter-cli.ts} +4 -4
- package/src/{deps-installer → v4/deps-installer}/deps-installer.ts +10 -7
- package/src/{i3s-converter → v4/i3s-converter}/helpers/attribute-metadata-info.ts +1 -1
- package/src/{i3s-converter → v4/i3s-converter}/helpers/batch-ids-extensions.ts +1 -1
- package/src/v4/i3s-converter/helpers/encode-string-attribute.ts +23 -0
- package/src/{i3s-converter → v4/i3s-converter}/helpers/geometry-attributes.ts +1 -1
- package/src/{i3s-converter → v4/i3s-converter}/helpers/geometry-converter.ts +34 -59
- package/src/{i3s-converter → v4/i3s-converter}/helpers/gltf-attributes.ts +7 -6
- package/src/{i3s-converter → v4/i3s-converter}/helpers/load-3d-tiles.ts +5 -9
- package/src/{i3s-converter → v4/i3s-converter}/helpers/node-debug.ts +5 -6
- package/src/{i3s-converter → v4/i3s-converter}/i3s-converter.ts +16 -19
- package/src/{i3s-converter → v4/i3s-converter}/json-templates/geometry-definitions.ts +4 -4
- package/src/{i3s-converter → v4/i3s-converter}/json-templates/layers.ts +6 -6
- package/src/{i3s-converter → v4/i3s-converter}/json-templates/node.ts +1 -1
- package/src/{i3s-converter → v4/i3s-converter}/json-templates/scene-server.ts +1 -1
- package/src/{i3s-converter → v4/i3s-converter}/json-templates/shared-resources.ts +1 -1
- package/src/{i3s-converter → v4/i3s-converter}/json-templates/store.ts +1 -1
- package/src/{i3s-server → v4/i3s-server}/README.md +2 -2
- package/src/{i3s-server → v4/i3s-server}/controllers/slpk-controller.ts +1 -1
- package/src/{i3s-server → v4/i3s-server}/routes/slpk-router.ts +2 -1
- package/src/v4/index.ts +2 -0
- package/src/{lib → v4/lib}/utils/compress-util.ts +8 -7
- package/src/{lib → v4/lib}/utils/conversion-dump.ts +4 -4
- package/src/{lib → v4/lib}/utils/file-utils.ts +2 -2
- package/src/{lib → v4/lib}/utils/lod-conversion-utils.ts +2 -4
- package/src/v5/adapters.ts +56 -0
- package/src/v5/browser-sink.ts +130 -0
- package/src/v5/browser-source.ts +155 -0
- package/src/v5/browser-tileset-source.ts +328 -0
- package/src/v5/browser.ts +105 -0
- package/src/v5/conversion-api.ts +287 -0
- package/src/v5/conversion-archive.ts +85 -0
- package/src/v5/core.ts +61 -0
- package/src/v5/feature-arrow.ts +429 -0
- package/src/v5/i3s-mesh-conversion.ts +152 -0
- package/src/v5/index.ts +99 -0
- package/src/v5/mesh-conversion.ts +200 -0
- package/src/v5/mesh-draco.ts +138 -0
- package/src/v5/mesh-source-features.ts +232 -0
- package/src/v5/mesh-source-texture.ts +122 -0
- package/src/v5/mesh-source.ts +360 -0
- package/src/v5/mesh-tileset-archive.ts +50 -0
- package/src/v5/mesh-tileset-sink.ts +324 -0
- package/src/v5/mesh.ts +517 -0
- package/src/v5/point-cloud-conversion.ts +80 -0
- package/src/v5/point-cloud-source-encoder.ts +105 -0
- package/src/v5/point-cloud-source.ts +84 -0
- package/src/v5/point-cloud.ts +271 -0
- package/src/v5/resource-manifest.ts +213 -0
- package/src/v5/spatial-conversion.ts +305 -0
- package/src/v5/tileset-source.ts +54 -0
- /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/i3s-obb-to-3d-tiles-obb.ts +0 -0
- /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/load-i3s.ts +0 -0
- /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/texture-atlas.ts +0 -0
- /package/src/{constants.ts → v4/constants.ts} +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/coordinate-converter.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/create-scene-server-path.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/feature-attributes.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-index-document.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-pages.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/preprocess-3d-tiles.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/progress.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/tileset-traversal.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/json-templates/metadata.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/types.ts +0 -0
- /package/src/{i3s-server → v4/i3s-server}/app.ts +0 -0
- /package/src/{i3s-server → v4/i3s-server}/bin/www.ts +0 -0
- /package/src/{i3s-server → v4/i3s-server}/certs/cert.pem +0 -0
- /package/src/{i3s-server → v4/i3s-server}/certs/key.pem +0 -0
- /package/src/{i3s-server → v4/i3s-server}/utils/create-scene-server.ts +0 -0
- /package/src/{i3s-server → v4/i3s-server}/utils/server-utils.ts +0 -0
- /package/src/{lib → v4/lib}/json-schemas/conversion-dump-json-schema.ts +0 -0
- /package/src/{lib → v4/lib}/utils/cli-utils.ts +0 -0
- /package/src/{lib → v4/lib}/utils/geometry-utils.ts +0 -0
- /package/src/{lib → v4/lib}/utils/queue.ts +0 -0
- /package/src/{lib → v4/lib}/utils/statistic-utils.ts +0 -0
- /package/src/{lib → v4/lib}/utils/write-queue.ts +0 -0
- /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 '@
|
|
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
|
-
//
|
|
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
|
|
1032
|
-
const
|
|
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([
|
|
1037
|
-
|
|
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(
|
|
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
|
|
1075
|
+
sourceMaterial?.pbrMetallicRoughness?.roughnessFactor ?? DEFAULT_ROUGHNESS_FACTOR,
|
|
1073
1076
|
metallicFactor:
|
|
1074
|
-
sourceMaterial?.pbrMetallicRoughness?.metallicFactor
|
|
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(
|
|
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 =
|
|
1464
|
+
attributeBuffer = encodeStringAttribute(value);
|
|
1460
1465
|
break;
|
|
1461
1466
|
default:
|
|
1462
|
-
attributeBuffer =
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
1564
|
-
* @param vertexCount
|
|
1565
|
-
* @param convertedAttributes -
|
|
1566
|
-
* @param attributes - geometry attributes
|
|
1567
|
-
* @param libraries -
|
|
1568
|
-
* @returns
|
|
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: '
|
|
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
|
-
|
|
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/
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
40
|
-
width
|
|
41
|
-
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(
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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.
|
|
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 (
|
|
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 (
|
|
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(
|
|
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
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
1272
|
-
const
|
|
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
|
-
{...
|
|
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.
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
99
|
+
transform: val => transform(val, STORE)
|
|
100
100
|
},
|
|
101
101
|
fullExtent: {
|
|
102
102
|
path: 'fullExtent',
|
|
103
|
-
transform:
|
|
103
|
+
transform: val => transform(val, FULL_EXTENT())
|
|
104
104
|
},
|
|
105
105
|
heightModelInfo: {
|
|
106
106
|
path: 'heightModelInfo',
|
|
107
|
-
transform:
|
|
107
|
+
transform: val => transform(val, HEIGHT_MODEL_INFO())
|
|
108
108
|
},
|
|
109
109
|
nodePages: {
|
|
110
110
|
path: 'nodePages',
|
|
111
|
-
transform:
|
|
111
|
+
transform: val => transform(val, NODE_PAGES())
|
|
112
112
|
},
|
|
113
113
|
materialDefinitions: {
|
|
114
114
|
path: 'materialDefinitions',
|
|
@@ -94,7 +94,7 @@ const TEXTURE_DEFINITION_INFO = () => ({
|
|
|
94
94
|
images: {
|
|
95
95
|
path: 'images',
|
|
96
96
|
transform: (val, thisObject, originalObject) =>
|
|
97
|
-
val.map(
|
|
97
|
+
val.map(image => transform(image, TEXTURE_DEFINITION_IMAGE()))
|
|
98
98
|
}
|
|
99
99
|
});
|
|
100
100
|
|
|
@@ -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 `
|
|
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
|
-
|
|
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 (
|
|
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 {
|
package/src/v4/index.ts
ADDED
|
@@ -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
|
|
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
|
}
|