@loaders.gl/tile-converter 5.0.0-alpha.12 → 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.
- package/LICENSE +1 -1
- package/README.md +4 -4
- package/dist/converter.min.cjs +149 -158
- package/dist/i3s-server/bin/i3s-server.min.cjs +113 -158
- package/dist/index.cjs +17486 -17479
- package/dist/index.js +25572 -25560
- package/dist/v5/adapters.cjs +540 -190
- package/dist/v5/adapters.d.ts +4 -0
- package/dist/v5/adapters.js +501 -151
- package/dist/v5/archive-source.d.ts +1 -1
- package/dist/v5/browser.d.ts +1 -1
- package/dist/v5/conversion-api.d.ts +25 -0
- package/dist/v5/converter-cli.js +23 -7
- package/dist/v5/core.cjs +76 -17
- package/dist/v5/core.d.ts +1 -1
- package/dist/v5/core.js +69 -10
- package/dist/v5/feature-arrow.d.ts +1 -1
- package/dist/v5/i3s-mesh-conversion.d.ts +1 -1
- package/dist/v5/i3s-mesh-source-features.d.ts +2 -2
- package/dist/v5/i3s-mesh-source-material.d.ts +1 -1
- package/dist/v5/i3s-mesh-source.d.ts +2 -2
- package/dist/v5/i3s-selection-source.d.ts +3 -3
- package/dist/v5/index.cjs +11 -6
- package/dist/v5/index.d.ts +5 -1
- package/dist/v5/index.js +8 -0
- package/dist/v5/mesh-conversion.d.ts +3 -3
- package/dist/v5/mesh-draco.d.ts +2 -2
- package/dist/v5/mesh-features.d.ts +2 -2
- package/dist/v5/mesh-source-features.d.ts +4 -4
- package/dist/v5/mesh-source-schema.d.ts +2 -2
- package/dist/v5/mesh-source-texture.d.ts +3 -3
- package/dist/v5/mesh-source.d.ts +5 -5
- package/dist/v5/mesh-tileset-sink.d.ts +1 -1
- package/dist/v5/mesh.d.ts +1 -1
- package/dist/v5/node-conversion.d.ts +2 -0
- package/dist/v5/node-i3s-source.d.ts +3 -3
- package/dist/v5/node-source.d.ts +1 -1
- package/dist/v5/node.cjs +19 -6
- package/dist/v5/node.js +19 -6
- package/dist/v5/point-cloud-attributes.d.ts +19 -0
- package/dist/v5/point-cloud-conversion.d.ts +1 -1
- package/dist/v5/point-cloud-copc.d.ts +44 -0
- package/dist/v5/point-cloud-file.d.ts +4 -4
- package/dist/v5/point-cloud-potree.d.ts +3 -3
- package/dist/v5/point-cloud-source-encoder.d.ts +1 -1
- package/dist/v5/point-cloud-source.d.ts +1 -1
- package/dist/v5/point-cloud-tileset.d.ts +3 -3
- package/dist/v5/point-cloud.d.ts +1 -1
- package/dist/v5/spatial-conversion.d.ts +1 -1
- package/dist/v5/tileset-source.d.ts +1 -1
- package/package.json +17 -32
- package/src/v4/3d-tiles-converter/3d-tiles-converter.ts +11 -12
- package/src/v4/3d-tiles-converter/helpers/3d-tiles-content-converter.ts +7 -3
- package/src/v4/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.ts +2 -2
- package/src/v4/3d-tiles-converter/helpers/load-i3s.ts +3 -3
- package/src/v4/3d-tiles-converter/helpers/texture-atlas.ts +1 -1
- package/src/v4/3d-tiles-converter/helpers/validate-i3s-spatial-reference.ts +2 -2
- package/src/v4/3d-tiles-converter/json-templates/tileset.ts +58 -39
- package/src/v4/converter-cli.ts +3 -3
- package/src/v4/deps-installer/deps-installer.ts +3 -3
- package/src/v4/i3s-converter/helpers/attribute-metadata-info.ts +1 -1
- package/src/v4/i3s-converter/helpers/batch-ids-extensions.ts +9 -10
- package/src/v4/i3s-converter/helpers/conversion-gltf.ts +108 -0
- package/src/v4/i3s-converter/helpers/coordinate-converter.ts +6 -5
- package/src/v4/i3s-converter/helpers/create-scene-server-path.ts +5 -6
- package/src/v4/i3s-converter/helpers/feature-attributes.ts +4 -4
- package/src/v4/i3s-converter/helpers/geometry-attributes.ts +1 -1
- package/src/v4/i3s-converter/helpers/geometry-converter.ts +69 -77
- package/src/v4/i3s-converter/helpers/gltf-attributes.ts +58 -74
- package/src/v4/i3s-converter/helpers/load-3d-tiles.ts +5 -5
- package/src/v4/i3s-converter/helpers/node-debug.ts +7 -3
- package/src/v4/i3s-converter/helpers/node-index-document.ts +6 -7
- package/src/v4/i3s-converter/helpers/node-pages.ts +3 -4
- package/src/v4/i3s-converter/helpers/preprocess-3d-tiles.ts +1 -1
- package/src/v4/i3s-converter/helpers/tileset-traversal.ts +1 -1
- package/src/v4/i3s-converter/i3s-converter.ts +29 -31
- package/src/v4/i3s-converter/json-templates/geometry-definitions.ts +71 -66
- package/src/v4/i3s-converter/json-templates/layers.ts +97 -132
- package/src/v4/i3s-converter/json-templates/metadata.ts +31 -21
- package/src/v4/i3s-converter/json-templates/node.ts +60 -74
- package/src/v4/i3s-converter/json-templates/scene-server.ts +36 -27
- package/src/v4/i3s-converter/json-templates/shared-resources.ts +62 -123
- package/src/v4/i3s-converter/json-templates/store.ts +39 -58
- package/src/v4/i3s-converter/types.ts +4 -4
- package/src/v4/i3s-server/controllers/slpk-controller.ts +3 -3
- package/src/v4/i3s-server/utils/create-scene-server.ts +3 -3
- package/src/v4/lib/utils/builder-input.ts +8 -0
- package/src/v4/lib/utils/conversion-dump.ts +5 -1
- package/src/v4/lib/utils/file-utils.ts +1 -1
- package/src/v4/lib/utils/hash-string.ts +21 -0
- package/src/v4/lib/utils/lod-conversion-utils.ts +3 -3
- package/src/v4/pgm-loader.ts +2 -2
- package/src/v5/adapters.ts +5 -0
- package/src/v5/archive-source.ts +4 -4
- package/src/v5/browser.ts +1 -0
- package/src/v5/conversion-api.ts +115 -8
- package/src/v5/conversion-archive.ts +2 -2
- package/src/v5/core.ts +1 -0
- package/src/v5/feature-arrow.ts +2 -2
- package/src/v5/i3s-mesh-conversion.ts +2 -2
- package/src/v5/i3s-mesh-source-features.ts +3 -3
- package/src/v5/i3s-mesh-source-material.ts +18 -11
- package/src/v5/i3s-mesh-source.ts +2 -2
- package/src/v5/i3s-selection-source.ts +4 -4
- package/src/v5/index.ts +15 -0
- package/src/v5/mesh-conversion.ts +4 -4
- package/src/v5/mesh-draco.ts +2 -2
- package/src/v5/mesh-features.ts +3 -3
- package/src/v5/mesh-hierarchy.ts +1 -1
- package/src/v5/mesh-source-features.ts +137 -55
- package/src/v5/mesh-source-schema.ts +10 -4
- package/src/v5/mesh-source-texture.ts +49 -19
- package/src/v5/mesh-source.ts +65 -46
- package/src/v5/mesh-tileset-archive.ts +1 -1
- package/src/v5/mesh-tileset-sink.ts +1 -1
- package/src/v5/mesh.ts +1 -1
- package/src/v5/node-cli.ts +4 -0
- package/src/v5/node-conversion.ts +19 -2
- package/src/v5/node-source.ts +2 -2
- package/src/v5/point-cloud-attributes.ts +113 -0
- package/src/v5/point-cloud-conversion.ts +1 -1
- package/src/v5/point-cloud-copc.ts +289 -0
- package/src/v5/point-cloud-file.ts +8 -8
- package/src/v5/point-cloud-potree.ts +8 -4
- package/src/v5/point-cloud-source-encoder.ts +1 -1
- package/src/v5/point-cloud-source.ts +1 -1
- package/src/v5/point-cloud-spatial.ts +2 -2
- package/src/v5/point-cloud-tileset.ts +4 -4
- package/src/v5/point-cloud.ts +3 -3
- package/src/v5/selected-mesh-source.ts +4 -4
- package/src/v5/spatial-conversion.ts +2 -2
- package/src/v5/tileset-source.ts +2 -2
package/dist/v5/adapters.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/v5/feature-arrow.ts
|
|
2
|
-
import { ArrowTableBuilder } from "@loaders.gl/schema-utils";
|
|
2
|
+
import { ArrowTableBuilder } from "@loaders.gl/core/schema-utils";
|
|
3
3
|
import { TileConversionError } from "@loaders.gl/tile-converter/v5/core";
|
|
4
4
|
var DEFAULT_FEATURE_ID_FIELD = "feature_id";
|
|
5
5
|
var FEATURE_CLASS_METADATA_KEY = "loaders.gl:feature-class";
|
|
@@ -321,8 +321,8 @@ function isBinaryType(dataType) {
|
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
// src/v5/point-cloud.ts
|
|
324
|
-
import { Tile3DWriter, TILE3D_TYPE } from "@loaders.gl/3d-tiles";
|
|
325
|
-
import { convertTableToMesh } from "@loaders.gl/schema-utils";
|
|
324
|
+
import { Tile3DWriter, TILE3D_TYPE } from "@loaders.gl/tiles-3d/3d-tiles";
|
|
325
|
+
import { convertTableToMesh } from "@loaders.gl/core/schema-utils";
|
|
326
326
|
import { TileConversionError as TileConversionError2 } from "@loaders.gl/tile-converter/v5/core";
|
|
327
327
|
function encodePointCloudTile(pointBatch, options = {}) {
|
|
328
328
|
return encodePointCloudTileWithMetadata(pointBatch, options).pnts;
|
|
@@ -585,8 +585,8 @@ function validateBatchTable(batchTableJson, batchIds) {
|
|
|
585
585
|
|
|
586
586
|
// src/v5/point-cloud-spatial.ts
|
|
587
587
|
import { Matrix4 } from "@math.gl/core";
|
|
588
|
-
import { getSpatialCoordinateFrame, createTilesetSpatialReference } from "@loaders.gl/tiles";
|
|
589
|
-
import { convertTableToMesh as convertTableToMesh2, makeMeshArrowTable } from "@loaders.gl/schema-utils";
|
|
588
|
+
import { getSpatialCoordinateFrame, createTilesetSpatialReference } from "@loaders.gl/tiles-3d";
|
|
589
|
+
import { convertTableToMesh as convertTableToMesh2, makeMeshArrowTable } from "@loaders.gl/core/schema-utils";
|
|
590
590
|
import { TileConversionError as TileConversionError3 } from "@loaders.gl/tile-converter/v5/core";
|
|
591
591
|
async function transformPointCloudSourceTile(sourceTile, options) {
|
|
592
592
|
options.signal?.throwIfAborted();
|
|
@@ -844,7 +844,7 @@ import { GLTFScenegraph, GLTFWriter } from "@loaders.gl/gltf";
|
|
|
844
844
|
import { getBinaryImageMetadata } from "@loaders.gl/images";
|
|
845
845
|
|
|
846
846
|
// src/v5/mesh-features.ts
|
|
847
|
-
import { convertArrowToSchema } from "@loaders.gl/schema-utils";
|
|
847
|
+
import { convertArrowToSchema } from "@loaders.gl/core/schema-utils";
|
|
848
848
|
import { TileConversionError as TileConversionError5 } from "@loaders.gl/tile-converter/v5/core";
|
|
849
849
|
function prepareMeshFeatureGeometry(mesh, features) {
|
|
850
850
|
if (!features) return mesh;
|
|
@@ -1398,7 +1398,7 @@ function validateMeshTextureTransform(transform) {
|
|
|
1398
1398
|
}
|
|
1399
1399
|
|
|
1400
1400
|
// src/v5/mesh-conversion.ts
|
|
1401
|
-
import { getSpatialCoordinateFrame as getSpatialCoordinateFrame2 } from "@loaders.gl/tiles";
|
|
1401
|
+
import { getSpatialCoordinateFrame as getSpatialCoordinateFrame2 } from "@loaders.gl/tiles-3d";
|
|
1402
1402
|
import { TileConversionError as TileConversionError8 } from "@loaders.gl/tile-converter/v5/core";
|
|
1403
1403
|
|
|
1404
1404
|
// src/v5/mesh-draco.ts
|
|
@@ -1888,8 +1888,8 @@ function createMeshTilesetSink(options) {
|
|
|
1888
1888
|
import {
|
|
1889
1889
|
Tiles3DArchiveWriter,
|
|
1890
1890
|
encodeTiles3DArchiveInBatches
|
|
1891
|
-
} from "@loaders.gl/3d-tiles/3d-tiles-archive-writer";
|
|
1892
|
-
import { SLPKWriter, encodeSLPKArchiveInBatches } from "@loaders.gl/i3s/i3s-slpk-writer";
|
|
1891
|
+
} from "@loaders.gl/tiles-3d/3d-tiles/3d-tiles-archive-writer";
|
|
1892
|
+
import { SLPKWriter, encodeSLPKArchiveInBatches } from "@loaders.gl/tiles-3d/i3s/i3s-slpk-writer";
|
|
1893
1893
|
import { TileConversionError as TileConversionError10 } from "@loaders.gl/tile-converter/v5/core";
|
|
1894
1894
|
async function createTileConversionArchive(files, options) {
|
|
1895
1895
|
const { resources, format, maxArchiveBytes, signal } = prepareArchiveInput(files, options);
|
|
@@ -1924,7 +1924,7 @@ function prepareArchiveInput(files, options) {
|
|
|
1924
1924
|
}
|
|
1925
1925
|
|
|
1926
1926
|
// src/v5/mesh-tileset-archive.ts
|
|
1927
|
-
import { Tiles3DArchiveWriter as Tiles3DArchiveWriter2 } from "@loaders.gl/3d-tiles/3d-tiles-archive-writer";
|
|
1927
|
+
import { Tiles3DArchiveWriter as Tiles3DArchiveWriter2 } from "@loaders.gl/tiles-3d/3d-tiles/3d-tiles-archive-writer";
|
|
1928
1928
|
import { TileConversionError as TileConversionError11 } from "@loaders.gl/tile-converter/v5/core";
|
|
1929
1929
|
async function createSingleMeshTilesetArchive(files, options) {
|
|
1930
1930
|
const { maxArchiveBytes, signal } = options;
|
|
@@ -1947,16 +1947,18 @@ async function createSingleMeshTilesetArchive(files, options) {
|
|
|
1947
1947
|
|
|
1948
1948
|
// src/v5/mesh-source.ts
|
|
1949
1949
|
import { Matrix4 as Matrix42 } from "@math.gl/core";
|
|
1950
|
+
import { getGLTFAccessor as getGLTFAccessor2, getGLTFAccessorValue as getGLTFAccessorValue2 } from "@loaders.gl/gltf";
|
|
1950
1951
|
import { TileConversionError as TileConversionError15 } from "@loaders.gl/tile-converter/v5/core";
|
|
1951
1952
|
import { createTilesetConversionSource } from "@loaders.gl/tile-converter/v5/core";
|
|
1952
1953
|
|
|
1953
1954
|
// src/v5/mesh-source-texture.ts
|
|
1954
1955
|
import { getBinaryImageMetadata as getBinaryImageMetadata2 } from "@loaders.gl/images";
|
|
1956
|
+
import { GLTFScenegraph as GLTFScenegraph2 } from "@loaders.gl/gltf";
|
|
1955
1957
|
import { TileConversionError as TileConversionError12 } from "@loaders.gl/tile-converter/v5/core";
|
|
1956
|
-
function mapMeshSourceTexture(textureInfo) {
|
|
1957
|
-
const texture = textureInfo?.
|
|
1958
|
-
const image = texture?.source;
|
|
1959
|
-
const sampler = texture?.sampler;
|
|
1958
|
+
function mapMeshSourceTexture(gltf, textureInfo) {
|
|
1959
|
+
const texture = textureInfo ? gltf.json.textures?.[textureInfo.index] : void 0;
|
|
1960
|
+
const image = texture?.source === void 0 ? void 0 : gltf.json.images?.[texture.source];
|
|
1961
|
+
const sampler = texture?.sampler === void 0 ? void 0 : gltf.json.samplers?.[texture.sampler];
|
|
1960
1962
|
const extensions = textureInfo?.extensions || {};
|
|
1961
1963
|
const hasTransform = Object.hasOwn(extensions, "KHR_texture_transform");
|
|
1962
1964
|
const transform = extensions.KHR_texture_transform;
|
|
@@ -1966,7 +1968,7 @@ function mapMeshSourceTexture(textureInfo) {
|
|
|
1966
1968
|
(name) => !["id", "index", "texture", "texCoord", "extensions", "extras"].includes(name)
|
|
1967
1969
|
) || !texture || Object.keys(texture).some(
|
|
1968
1970
|
(name) => !["id", "source", "sampler", "name", "extensions", "extras"].includes(name)
|
|
1969
|
-
) || Object.keys(texture.extensions || {}).length || !image || image.uri !== void 0 && image.bufferView !== void 0 || Object.keys(image.extensions || {}).length || image.uri === void 0 && (
|
|
1971
|
+
) || Object.keys(texture.extensions || {}).length || !image || image.uri !== void 0 && image.bufferView !== void 0 || Object.keys(image.extensions || {}).length || image.uri === void 0 && (image.bufferView === void 0 || !gltf.json.bufferViews?.[image.bufferView] || Object.keys(gltf.json.bufferViews?.[image.bufferView]?.extensions || {}).length || !["image/png", "image/jpeg"].includes(image.mimeType || "")) || sampler && (Object.keys(sampler.extensions || {}).length || Object.keys(sampler).some(
|
|
1970
1972
|
(name) => ![
|
|
1971
1973
|
"id",
|
|
1972
1974
|
"parameters",
|
|
@@ -1991,7 +1993,7 @@ function mapMeshSourceTexture(textureInfo) {
|
|
|
1991
1993
|
minFilter: sampler.minFilter
|
|
1992
1994
|
} : void 0;
|
|
1993
1995
|
return {
|
|
1994
|
-
...mapMeshSourceImage(image),
|
|
1996
|
+
...mapMeshSourceImage(gltf, image),
|
|
1995
1997
|
...hasTransform ? {
|
|
1996
1998
|
transform: {
|
|
1997
1999
|
offset: transform.offset,
|
|
@@ -2002,9 +2004,12 @@ function mapMeshSourceTexture(textureInfo) {
|
|
|
2002
2004
|
...selectedSampler && Object.values(selectedSampler).some((value) => value !== void 0) ? { sampler: selectedSampler } : {}
|
|
2003
2005
|
};
|
|
2004
2006
|
}
|
|
2005
|
-
function mapMeshSourceImage(image) {
|
|
2007
|
+
function mapMeshSourceImage(gltf, image) {
|
|
2006
2008
|
if (image.uri === void 0) {
|
|
2007
|
-
return {
|
|
2009
|
+
return {
|
|
2010
|
+
data: new GLTFScenegraph2(gltf).getTypedArrayForBufferView(image.bufferView),
|
|
2011
|
+
mimeType: image.mimeType
|
|
2012
|
+
};
|
|
2008
2013
|
}
|
|
2009
2014
|
const match = typeof image.uri === "string" ? /^data:(image\/(?:png|jpeg));base64,([A-Za-z0-9+/]+={0,2})$/.exec(image.uri) : null;
|
|
2010
2015
|
if (!match || image.mimeType !== void 0 && image.mimeType !== match[1]) {
|
|
@@ -2024,10 +2029,11 @@ function mapMeshSourceImage(image) {
|
|
|
2024
2029
|
mimeType: match[1]
|
|
2025
2030
|
};
|
|
2026
2031
|
}
|
|
2027
|
-
async function resolveMeshSourceTexture(textureInfo, readExternalResource, contentUri, signal) {
|
|
2028
|
-
const
|
|
2032
|
+
async function resolveMeshSourceTexture(gltf, textureInfo, readExternalResource, contentUri, signal) {
|
|
2033
|
+
const texture = textureInfo ? gltf.json.textures?.[textureInfo.index] : void 0;
|
|
2034
|
+
const image = texture?.source === void 0 ? void 0 : gltf.json.images?.[texture.source];
|
|
2029
2035
|
if (!image || image.uri === void 0 || image.uri.startsWith("data:"))
|
|
2030
|
-
return mapMeshSourceTexture(textureInfo);
|
|
2036
|
+
return mapMeshSourceTexture(gltf, textureInfo);
|
|
2031
2037
|
if (!readExternalResource || image.bufferView !== void 0)
|
|
2032
2038
|
throw new TileConversionError12(
|
|
2033
2039
|
"MESH_SOURCE_TEXTURE_UNSUPPORTED",
|
|
@@ -2046,16 +2052,39 @@ async function resolveMeshSourceTexture(textureInfo, readExternalResource, conte
|
|
|
2046
2052
|
"MESH_SOURCE_TEXTURE_UNSUPPORTED",
|
|
2047
2053
|
"External images require matching PNG/JPEG headers"
|
|
2048
2054
|
);
|
|
2055
|
+
const resolvedImage = {
|
|
2056
|
+
...image,
|
|
2057
|
+
uri: void 0,
|
|
2058
|
+
mimeType: metadata.mimeType,
|
|
2059
|
+
bufferView: (gltf.json.bufferViews || []).length
|
|
2060
|
+
};
|
|
2049
2061
|
const resolved = {
|
|
2050
|
-
...
|
|
2051
|
-
|
|
2052
|
-
...
|
|
2053
|
-
|
|
2062
|
+
...gltf,
|
|
2063
|
+
buffers: [
|
|
2064
|
+
...gltf.buffers,
|
|
2065
|
+
{
|
|
2066
|
+
arrayBuffer: data.buffer,
|
|
2067
|
+
byteOffset: data.byteOffset,
|
|
2068
|
+
byteLength: data.byteLength
|
|
2069
|
+
}
|
|
2070
|
+
],
|
|
2071
|
+
json: {
|
|
2072
|
+
...gltf.json,
|
|
2073
|
+
images: gltf.json.images.map(
|
|
2074
|
+
(entry, index) => index === texture.source ? resolvedImage : entry
|
|
2075
|
+
),
|
|
2076
|
+
bufferViews: [
|
|
2077
|
+
...gltf.json.bufferViews || [],
|
|
2078
|
+
{ buffer: gltf.buffers.length, byteLength: data.byteLength }
|
|
2079
|
+
]
|
|
2054
2080
|
}
|
|
2055
2081
|
};
|
|
2056
|
-
return mapMeshSourceTexture(resolved);
|
|
2082
|
+
return mapMeshSourceTexture(resolved, textureInfo);
|
|
2057
2083
|
}
|
|
2058
2084
|
|
|
2085
|
+
// src/v5/mesh-source-features.ts
|
|
2086
|
+
import { getGLTFAccessor, getGLTFAccessorValue } from "@loaders.gl/gltf";
|
|
2087
|
+
|
|
2059
2088
|
// src/v5/mesh-source-schema.ts
|
|
2060
2089
|
import { TileConversionError as TileConversionError13 } from "@loaders.gl/tile-converter/v5/core";
|
|
2061
2090
|
var SCALAR_TYPES = {
|
|
@@ -2141,9 +2170,9 @@ function createMeshSourceFeatureOptions(gltf, options) {
|
|
|
2141
2170
|
import { TileConversionError as TileConversionError14 } from "@loaders.gl/tile-converter/v5/core";
|
|
2142
2171
|
function extractMeshFeatures(gltf, primitive, payload, mesh, options) {
|
|
2143
2172
|
const declarations = primitive.extensions?.EXT_mesh_features?.featureIds;
|
|
2144
|
-
const metadata = gltf.extensions?.EXT_structural_metadata;
|
|
2173
|
+
const metadata = gltf.json.extensions?.EXT_structural_metadata;
|
|
2145
2174
|
const legacy = primitive.attributes._BATCHID;
|
|
2146
|
-
if (!declarations &&
|
|
2175
|
+
if (!declarations && legacy === void 0 && !metadata && !Object.keys(payload.batchTableJson || {}).length && !payload.header?.batchLength) {
|
|
2147
2176
|
if (Object.keys(primitive.attributes).some((name) => /^_FEATURE_ID_\d+$/.test(name)))
|
|
2148
2177
|
throw new TileConversionError14(
|
|
2149
2178
|
"MESH_FEATURE_MAPPING_REQUIRED",
|
|
@@ -2161,37 +2190,38 @@ function extractMeshFeatures(gltf, primitive, payload, mesh, options) {
|
|
|
2161
2190
|
"MESH_FEATURE_CLASS_REQUIRED",
|
|
2162
2191
|
"Feature metadata class must be explicit"
|
|
2163
2192
|
);
|
|
2164
|
-
const mapping = "schema" in options ? options : createMeshSourceFeatureOptions(gltf, options);
|
|
2193
|
+
const mapping = "schema" in options ? options : createMeshSourceFeatureOptions(gltf.json, options);
|
|
2194
|
+
const propertyMappings = /* @__PURE__ */ new Map();
|
|
2165
2195
|
let count;
|
|
2166
|
-
let
|
|
2196
|
+
let attributeReference = legacy;
|
|
2167
2197
|
let properties;
|
|
2168
2198
|
if (declarations) {
|
|
2169
|
-
if (legacy || declarations.length !== 1 || metadata?.propertyTables?.length !== 1 || metadata.propertyTextures?.length || metadata.propertyAttributes?.length)
|
|
2199
|
+
if (legacy !== void 0 || declarations.length !== 1 || metadata?.propertyTables?.length !== 1 || metadata.propertyTextures?.length || metadata.propertyAttributes?.length)
|
|
2170
2200
|
throw new TileConversionError14(
|
|
2171
2201
|
"MESH_FEATURE_MAPPING_UNSUPPORTED",
|
|
2172
2202
|
"Only one attribute-backed feature set and one property table are supported"
|
|
2173
2203
|
);
|
|
2174
2204
|
const declaration = declarations[0];
|
|
2175
|
-
if (!Number.isInteger(declaration.attribute) || declaration.attribute < 0 || declaration.propertyTable !== 0 || declaration.texture || declaration.implicit || declaration.nullFeatureId !== void 0)
|
|
2205
|
+
if (typeof declaration.attribute !== "number" || !Number.isInteger(declaration.attribute) || declaration.attribute < 0 || declaration.propertyTable !== 0 || declaration.texture || declaration.implicit || declaration.nullFeatureId !== void 0)
|
|
2176
2206
|
throw new TileConversionError14(
|
|
2177
2207
|
"MESH_FEATURE_MAPPING_UNSUPPORTED",
|
|
2178
2208
|
"Features require an attribute and property table 0 without null/texture/implicit IDs"
|
|
2179
2209
|
);
|
|
2180
|
-
|
|
2210
|
+
attributeReference = primitive.attributes[`_FEATURE_ID_${declaration.attribute}`];
|
|
2181
2211
|
const table = metadata.propertyTables[0];
|
|
2182
|
-
if (table.class !== options.metadataClass ||
|
|
2212
|
+
if (table.class !== options.metadataClass || !Number.isSafeInteger(declaration.featureCount) || declaration.featureCount <= 0 || declaration.featureCount > table.count)
|
|
2183
2213
|
throw new TileConversionError14(
|
|
2184
2214
|
"MESH_FEATURE_CLASS_MISMATCH",
|
|
2185
|
-
"Feature class and declared
|
|
2215
|
+
"Feature class must agree and declared feature count must fit the property table"
|
|
2186
2216
|
);
|
|
2187
2217
|
count = table.count;
|
|
2188
|
-
if (!Number.isSafeInteger(count) || count <= 0 || count >
|
|
2218
|
+
if (!Number.isSafeInteger(count) || count <= 0 || count > 4294967295) {
|
|
2189
2219
|
throw new TileConversionError14(
|
|
2190
2220
|
"MESH_FEATURE_IDS_INVALID",
|
|
2191
|
-
"Feature row count
|
|
2221
|
+
"Feature row count must fit uint32 indices"
|
|
2192
2222
|
);
|
|
2193
2223
|
}
|
|
2194
|
-
properties =
|
|
2224
|
+
properties = /* @__PURE__ */ Object.create(null);
|
|
2195
2225
|
const classProperties = metadata.schema?.classes?.[table.class]?.properties;
|
|
2196
2226
|
if (!classProperties)
|
|
2197
2227
|
throw new TileConversionError14(
|
|
@@ -2224,9 +2254,10 @@ function extractMeshFeatures(gltf, primitive, payload, mesh, options) {
|
|
|
2224
2254
|
);
|
|
2225
2255
|
}
|
|
2226
2256
|
const defaultValue = integer64 && property.default !== void 0 ? BigInt(property.default) : property.default ?? null;
|
|
2227
|
-
const decoded = data
|
|
2257
|
+
const decoded = data;
|
|
2228
2258
|
if (property.noData === void 0 || data === void 0) {
|
|
2229
|
-
properties[name] = decoded;
|
|
2259
|
+
if (decoded !== void 0) properties[name] = decoded;
|
|
2260
|
+
else propertyMappings.set(name, { defaultValue });
|
|
2230
2261
|
continue;
|
|
2231
2262
|
}
|
|
2232
2263
|
const sentinel = property.noData;
|
|
@@ -2236,10 +2267,9 @@ function extractMeshFeatures(gltf, primitive, payload, mesh, options) {
|
|
|
2236
2267
|
`Property ${name} requires a valid decoded noData mapping`
|
|
2237
2268
|
);
|
|
2238
2269
|
const comparable = integer64 ? BigInt(sentinel) : sentinel;
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
);
|
|
2270
|
+
const values = decoded;
|
|
2271
|
+
properties[name] = values;
|
|
2272
|
+
propertyMappings.set(name, { noData: comparable, defaultValue });
|
|
2243
2273
|
}
|
|
2244
2274
|
} else {
|
|
2245
2275
|
if (metadata)
|
|
@@ -2250,14 +2280,32 @@ function extractMeshFeatures(gltf, primitive, payload, mesh, options) {
|
|
|
2250
2280
|
count = payload.header?.batchLength ?? Number(payload.featureTableJson?.BATCH_LENGTH);
|
|
2251
2281
|
properties = payload.batchTableJson || {};
|
|
2252
2282
|
}
|
|
2283
|
+
const accessor = attributeReference === void 0 ? void 0 : getGLTFAccessor(gltf, attributeReference);
|
|
2284
|
+
const attribute = accessor ? {
|
|
2285
|
+
...accessor,
|
|
2286
|
+
components: accessor.type === "SCALAR" ? 1 : Number(accessor.type.slice(3)),
|
|
2287
|
+
value: getGLTFAccessorValue(gltf, accessor)
|
|
2288
|
+
} : void 0;
|
|
2253
2289
|
const vertexCount = mesh.attributes.POSITION.value.length / 3;
|
|
2254
|
-
if (!Number.isSafeInteger(count) || count <= 0 || !attribute || attribute.components !== 1 || attribute.normalized || attribute.value.length !== vertexCount
|
|
2255
|
-
(value) => !Number.isSafeInteger(value) || value < 0 || value >= count
|
|
2256
|
-
))
|
|
2290
|
+
if (!Number.isSafeInteger(count) || count <= 0 || !attribute || attribute.components !== 1 || attribute.normalized || attribute.value.length !== vertexCount)
|
|
2257
2291
|
throw new TileConversionError14(
|
|
2258
2292
|
"MESH_FEATURE_IDS_INVALID",
|
|
2259
2293
|
"Feature IDs must be one valid property-table row index per vertex"
|
|
2260
2294
|
);
|
|
2295
|
+
const vertexRows = declarations ? /* @__PURE__ */ new Set() : void 0;
|
|
2296
|
+
for (const value of attribute.value) {
|
|
2297
|
+
if (!Number.isSafeInteger(value) || value < 0 || value >= count)
|
|
2298
|
+
throw new TileConversionError14(
|
|
2299
|
+
"MESH_FEATURE_IDS_INVALID",
|
|
2300
|
+
"Feature IDs must reference valid property-table rows"
|
|
2301
|
+
);
|
|
2302
|
+
vertexRows?.add(Number(value));
|
|
2303
|
+
}
|
|
2304
|
+
if (declarations && vertexRows.size !== declarations[0].featureCount)
|
|
2305
|
+
throw new TileConversionError14(
|
|
2306
|
+
"MESH_FEATURE_IDS_INVALID",
|
|
2307
|
+
"Declared feature count must match distinct vertex feature IDs"
|
|
2308
|
+
);
|
|
2261
2309
|
const selectedAttribute = declarations ? `_FEATURE_ID_${declarations[0].attribute}` : "_BATCHID";
|
|
2262
2310
|
if (Object.keys(primitive.attributes).some(
|
|
2263
2311
|
(name) => (name === "_BATCHID" || /^_FEATURE_ID_\d+$/.test(name)) && name !== selectedAttribute
|
|
@@ -2270,39 +2318,70 @@ function extractMeshFeatures(gltf, primitive, payload, mesh, options) {
|
|
|
2270
2318
|
if (!values || !Array.isArray(values) && !ArrayBuffer.isView(values) || values.length !== count)
|
|
2271
2319
|
throw new TileConversionError14(
|
|
2272
2320
|
"MESH_FEATURE_PROPERTY_UNAVAILABLE",
|
|
2273
|
-
`Property ${name} must be a decoded column matching the
|
|
2321
|
+
`Property ${name} must be a decoded column matching the feature row count`
|
|
2274
2322
|
);
|
|
2275
2323
|
}
|
|
2276
2324
|
const sourceIdentifier = options.sourceFeatureIdProperty;
|
|
2277
|
-
if (sourceIdentifier && !properties[sourceIdentifier])
|
|
2325
|
+
if (sourceIdentifier && !properties[sourceIdentifier] && !propertyMappings.has(sourceIdentifier))
|
|
2278
2326
|
throw new TileConversionError14(
|
|
2279
2327
|
"MESH_FEATURE_ID_PROPERTY_REQUIRED",
|
|
2280
2328
|
"Stable source identifier property is missing"
|
|
2281
2329
|
);
|
|
2282
|
-
const batches = convertFeatureAttributesToArrowBatches(
|
|
2283
|
-
Array.from({ length: count }, (_, index) => ({
|
|
2284
|
-
featureId: sourceIdentifier ? properties[sourceIdentifier][index] : index,
|
|
2285
|
-
metadataClass: options.metadataClass,
|
|
2286
|
-
properties: Object.fromEntries(
|
|
2287
|
-
Object.entries(properties).filter(([name]) => name !== sourceIdentifier).map(([name, values]) => [name, values[index]])
|
|
2288
|
-
)
|
|
2289
|
-
})),
|
|
2290
|
-
mapping
|
|
2291
|
-
);
|
|
2292
2330
|
const indices = mesh.indices?.value;
|
|
2293
|
-
const
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2331
|
+
const cornerCount = indices?.length ?? vertexCount;
|
|
2332
|
+
if (cornerCount % 3)
|
|
2333
|
+
throw new TileConversionError14(
|
|
2334
|
+
"MESH_FEATURE_IDS_INVALID",
|
|
2335
|
+
"Triangle geometry requires complete triples"
|
|
2297
2336
|
);
|
|
2298
|
-
|
|
2299
|
-
|
|
2337
|
+
const triangleFeatureIndices = new Uint32Array(cornerCount / 3);
|
|
2338
|
+
const referencedRows = /* @__PURE__ */ new Set();
|
|
2339
|
+
const readFeatureRow = (corner) => {
|
|
2340
|
+
if (!Number.isSafeInteger(corner) || corner < 0 || corner >= vertexCount)
|
|
2341
|
+
throw new TileConversionError14(
|
|
2342
|
+
"MESH_FEATURE_IDS_INVALID",
|
|
2343
|
+
"Triangle indices must reference valid mesh vertices"
|
|
2344
|
+
);
|
|
2345
|
+
return Number(attribute.value[corner]);
|
|
2346
|
+
};
|
|
2347
|
+
for (let triangle = 0; triangle < triangleFeatureIndices.length; triangle++) {
|
|
2348
|
+
const firstCorner = indices?.[triangle * 3] ?? triangle * 3;
|
|
2349
|
+
const secondCorner = indices?.[triangle * 3 + 1] ?? triangle * 3 + 1;
|
|
2350
|
+
const thirdCorner = indices?.[triangle * 3 + 2] ?? triangle * 3 + 2;
|
|
2351
|
+
const firstRow = readFeatureRow(firstCorner);
|
|
2352
|
+
const secondRow = readFeatureRow(secondCorner);
|
|
2353
|
+
const thirdRow = readFeatureRow(thirdCorner);
|
|
2354
|
+
if ((firstRow !== secondRow || firstRow !== thirdRow) && firstCorner !== secondCorner && firstCorner !== thirdCorner && secondCorner !== thirdCorner)
|
|
2300
2355
|
throw new TileConversionError14(
|
|
2301
2356
|
"MESH_FEATURE_TRIANGLE_MIXED",
|
|
2302
2357
|
"All vertices of a nondegenerate triangle must reference the same feature row"
|
|
2303
2358
|
);
|
|
2304
|
-
triangleFeatureIndices[triangle] =
|
|
2359
|
+
triangleFeatureIndices[triangle] = firstRow;
|
|
2360
|
+
referencedRows.add(firstRow);
|
|
2305
2361
|
}
|
|
2362
|
+
const selectedRows = [...referencedRows].sort((left, right) => left - right);
|
|
2363
|
+
const denseRows = new Map(selectedRows.map((row, index) => [row, index]));
|
|
2364
|
+
for (let triangle = 0; triangle < triangleFeatureIndices.length; triangle++) {
|
|
2365
|
+
triangleFeatureIndices[triangle] = denseRows.get(triangleFeatureIndices[triangle]);
|
|
2366
|
+
}
|
|
2367
|
+
const readProperty = (name, row) => {
|
|
2368
|
+
const values = properties[name];
|
|
2369
|
+
const propertyMapping = propertyMappings.get(name);
|
|
2370
|
+
if (!values) return propertyMapping?.defaultValue;
|
|
2371
|
+
const value = values[row];
|
|
2372
|
+
return propertyMapping && value === propertyMapping.noData ? propertyMapping.defaultValue : value;
|
|
2373
|
+
};
|
|
2374
|
+
const propertyNames = [
|
|
2375
|
+
.../* @__PURE__ */ new Set([...Object.keys(properties), ...propertyMappings.keys()])
|
|
2376
|
+
].filter((name) => name !== sourceIdentifier);
|
|
2377
|
+
const batches = convertFeatureAttributesToArrowBatches(
|
|
2378
|
+
selectedRows.map((row) => ({
|
|
2379
|
+
featureId: sourceIdentifier ? readProperty(sourceIdentifier, row) : row,
|
|
2380
|
+
metadataClass: options.metadataClass,
|
|
2381
|
+
properties: Object.fromEntries(propertyNames.map((name) => [name, readProperty(name, row)]))
|
|
2382
|
+
})),
|
|
2383
|
+
mapping
|
|
2384
|
+
);
|
|
2306
2385
|
return {
|
|
2307
2386
|
batches,
|
|
2308
2387
|
triangleFeatureIndices,
|
|
@@ -2361,7 +2440,8 @@ function createMeshTilesetConversionSource(tileset, options = {}) {
|
|
|
2361
2440
|
"Mesh extraction requires decoded GLB/glTF or B3DM content"
|
|
2362
2441
|
);
|
|
2363
2442
|
}
|
|
2364
|
-
const
|
|
2443
|
+
const gltfWithBuffers = payload.gltf;
|
|
2444
|
+
const gltf = gltfWithBuffers.json;
|
|
2365
2445
|
if (gltf.animations?.length || gltf.skins?.length || Object.keys(gltf.extensions || {}).some(
|
|
2366
2446
|
(name) => !["EXT_structural_metadata", "CESIUM_RTC"].includes(name)
|
|
2367
2447
|
)) {
|
|
@@ -2387,19 +2467,20 @@ function createMeshTilesetConversionSource(tileset, options = {}) {
|
|
|
2387
2467
|
placement.multiplyRight(new Matrix42([1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1]));
|
|
2388
2468
|
if (axis === "X")
|
|
2389
2469
|
placement.multiplyRight(new Matrix42([0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1]));
|
|
2390
|
-
const roots = gltf.scene?.nodes || (gltf.scenes?.length === 1 ? gltf.scenes[0].nodes : void 0);
|
|
2470
|
+
const roots = (gltf.scene !== void 0 ? gltf.scenes?.[gltf.scene]?.nodes : void 0) || (gltf.scenes?.length === 1 ? gltf.scenes[0].nodes : void 0);
|
|
2391
2471
|
if (!roots?.length)
|
|
2392
2472
|
throw new TileConversionError15(
|
|
2393
2473
|
"MESH_SOURCE_SCENE_UNSUPPORTED",
|
|
2394
2474
|
"A default scene or exactly one scene is required"
|
|
2395
2475
|
);
|
|
2396
2476
|
let primitiveIndex = 0;
|
|
2397
|
-
const primitives = traverseMeshNodes(roots, placement);
|
|
2477
|
+
const primitives = traverseMeshNodes(gltfWithBuffers, roots, placement);
|
|
2398
2478
|
let current = primitives.next();
|
|
2399
2479
|
while (!current.done) {
|
|
2400
2480
|
const selected = current.value;
|
|
2401
2481
|
const next = primitives.next();
|
|
2402
2482
|
const resource = await extractPrimitive(
|
|
2483
|
+
gltfWithBuffers,
|
|
2403
2484
|
selected.primitive,
|
|
2404
2485
|
selected.transform,
|
|
2405
2486
|
`${item.tile.id}/${content.index}/${primitiveIndex++}`,
|
|
@@ -2408,7 +2489,7 @@ function createMeshTilesetConversionSource(tileset, options = {}) {
|
|
|
2408
2489
|
signal
|
|
2409
2490
|
);
|
|
2410
2491
|
const features = extractMeshFeatures(
|
|
2411
|
-
|
|
2492
|
+
gltfWithBuffers,
|
|
2412
2493
|
selected.primitive,
|
|
2413
2494
|
payload,
|
|
2414
2495
|
resource.mesh,
|
|
@@ -2431,9 +2512,10 @@ function createMeshTilesetConversionSource(tileset, options = {}) {
|
|
|
2431
2512
|
}
|
|
2432
2513
|
};
|
|
2433
2514
|
}
|
|
2434
|
-
function* traverseMeshNodes(nodes, parent, ancestors = /* @__PURE__ */ new Set()) {
|
|
2435
|
-
for (const
|
|
2436
|
-
|
|
2515
|
+
function* traverseMeshNodes(gltf, nodes, parent, ancestors = /* @__PURE__ */ new Set()) {
|
|
2516
|
+
for (const nodeIndex of nodes) {
|
|
2517
|
+
const node = gltf.json.nodes[nodeIndex];
|
|
2518
|
+
if (!node || ancestors.has(nodeIndex) || node.skin !== void 0 || node.weights || Object.keys(node.extensions || {}).length)
|
|
2437
2519
|
throw new TileConversionError15(
|
|
2438
2520
|
"MESH_SOURCE_NODE_UNSUPPORTED",
|
|
2439
2521
|
"Cyclic, skinned, morphed, or extended nodes are unsupported"
|
|
@@ -2441,18 +2523,24 @@ function* traverseMeshNodes(nodes, parent, ancestors = /* @__PURE__ */ new Set()
|
|
|
2441
2523
|
const transform = new Matrix42(parent).multiplyRight(
|
|
2442
2524
|
node.matrix ? new Matrix42(node.matrix) : new Matrix42().translate(node.translation || [0, 0, 0]).multiplyRight(new Matrix42().fromQuaternion(node.rotation || [0, 0, 0, 1])).scale(node.scale || [1, 1, 1])
|
|
2443
2525
|
);
|
|
2444
|
-
if (node.mesh) {
|
|
2445
|
-
|
|
2526
|
+
if (node.mesh !== void 0) {
|
|
2527
|
+
const mesh = gltf.json.meshes[node.mesh];
|
|
2528
|
+
if (mesh.weights || Object.keys(mesh.extensions || {}).length)
|
|
2446
2529
|
throw new TileConversionError15(
|
|
2447
2530
|
"MESH_SOURCE_NODE_UNSUPPORTED",
|
|
2448
2531
|
"Morph weights and mesh extensions are unsupported"
|
|
2449
2532
|
);
|
|
2450
|
-
for (const primitive of
|
|
2533
|
+
for (const primitive of mesh.primitives) yield { primitive, transform };
|
|
2451
2534
|
}
|
|
2452
|
-
yield* traverseMeshNodes(
|
|
2535
|
+
yield* traverseMeshNodes(
|
|
2536
|
+
gltf,
|
|
2537
|
+
node.children || [],
|
|
2538
|
+
transform,
|
|
2539
|
+
/* @__PURE__ */ new Set([...ancestors, nodeIndex])
|
|
2540
|
+
);
|
|
2453
2541
|
}
|
|
2454
2542
|
}
|
|
2455
|
-
async function extractPrimitive(primitive, transform, id, readExternalResource, contentUri, signal) {
|
|
2543
|
+
async function extractPrimitive(gltf, primitive, transform, id, readExternalResource, contentUri, signal) {
|
|
2456
2544
|
if (primitive.targets?.length || Object.keys(primitive.extensions || {}).some((name) => name !== "EXT_mesh_features"))
|
|
2457
2545
|
throw new TileConversionError15(
|
|
2458
2546
|
"MESH_SOURCE_PRIMITIVE_UNSUPPORTED",
|
|
@@ -2464,7 +2552,8 @@ async function extractPrimitive(primitive, transform, id, readExternalResource,
|
|
|
2464
2552
|
"Mesh placement requires a finite invertible affine transform with positive determinant"
|
|
2465
2553
|
);
|
|
2466
2554
|
const attributes = {};
|
|
2467
|
-
for (const [name,
|
|
2555
|
+
for (const [name, reference] of Object.entries(primitive.attributes)) {
|
|
2556
|
+
const accessor = getGLTFAccessor2(gltf, reference);
|
|
2468
2557
|
if (name === "_BATCHID" || /^_FEATURE_ID_\d+$/.test(name)) continue;
|
|
2469
2558
|
if (!["POSITION", "NORMAL", "COLOR_0", "TEXCOORD_0"].includes(name))
|
|
2470
2559
|
throw new TileConversionError15(
|
|
@@ -2472,17 +2561,17 @@ async function extractPrimitive(primitive, transform, id, readExternalResource,
|
|
|
2472
2561
|
`Unsupported mesh attribute ${name}`
|
|
2473
2562
|
);
|
|
2474
2563
|
attributes[name] = {
|
|
2475
|
-
value:
|
|
2476
|
-
size: accessor.
|
|
2564
|
+
value: getGLTFAccessorValue2(gltf, reference),
|
|
2565
|
+
size: accessor.type === "SCALAR" ? 1 : Number(accessor.type.slice(3)),
|
|
2477
2566
|
...accessor.normalized ? { normalized: true } : {}
|
|
2478
2567
|
};
|
|
2479
2568
|
}
|
|
2480
2569
|
const mesh = validateMeshGeometry(
|
|
2481
2570
|
{
|
|
2482
2571
|
topology: "triangle-list",
|
|
2483
|
-
mode: primitive.mode
|
|
2572
|
+
mode: [5, 6].includes(primitive.mode ?? 4) ? 4 : primitive.mode ?? 4,
|
|
2484
2573
|
attributes,
|
|
2485
|
-
indices: createTriangleIndices(primitive, (attributes.POSITION?.value.length ?? 0) / 3)
|
|
2574
|
+
indices: createTriangleIndices(gltf, primitive, (attributes.POSITION?.value.length ?? 0) / 3)
|
|
2486
2575
|
},
|
|
2487
2576
|
true
|
|
2488
2577
|
);
|
|
@@ -2520,14 +2609,15 @@ async function extractPrimitive(primitive, transform, id, readExternalResource,
|
|
|
2520
2609
|
mesh,
|
|
2521
2610
|
origin: minimum.map((value, axis) => value / 2 + maximum[axis] / 2),
|
|
2522
2611
|
material: await mapMeshSourceMaterial(
|
|
2523
|
-
primitive.material,
|
|
2612
|
+
primitive.material === void 0 ? void 0 : gltf.json.materials?.[primitive.material],
|
|
2524
2613
|
readExternalResource,
|
|
2525
2614
|
contentUri,
|
|
2526
|
-
signal
|
|
2615
|
+
signal,
|
|
2616
|
+
gltf
|
|
2527
2617
|
)
|
|
2528
2618
|
};
|
|
2529
2619
|
}
|
|
2530
|
-
async function mapMeshSourceMaterial(material, readExternalResource, contentUri, signal) {
|
|
2620
|
+
async function mapMeshSourceMaterial(material, readExternalResource, contentUri, signal, gltf) {
|
|
2531
2621
|
if (!material) return void 0;
|
|
2532
2622
|
const pbr = material.pbrMetallicRoughness;
|
|
2533
2623
|
if (Object.entries(material).some(
|
|
@@ -2552,6 +2642,7 @@ async function mapMeshSourceMaterial(material, readExternalResource, contentUri,
|
|
|
2552
2642
|
baseColorFactor: pbr?.baseColorFactor,
|
|
2553
2643
|
..."baseColorTexture" in (pbr || {}) ? {
|
|
2554
2644
|
baseColorTexture: await resolveMeshSourceTexture(
|
|
2645
|
+
gltf,
|
|
2555
2646
|
pbr.baseColorTexture,
|
|
2556
2647
|
readExternalResource,
|
|
2557
2648
|
contentUri,
|
|
@@ -2565,13 +2656,14 @@ async function mapMeshSourceMaterial(material, readExternalResource, contentUri,
|
|
|
2565
2656
|
doubleSided: material.doubleSided
|
|
2566
2657
|
};
|
|
2567
2658
|
}
|
|
2568
|
-
function createTriangleIndices(primitive, vertexCount) {
|
|
2569
|
-
const
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2659
|
+
function createTriangleIndices(gltf, primitive, vertexCount) {
|
|
2660
|
+
const accessor = primitive.indices === void 0 ? void 0 : getGLTFAccessor2(gltf, primitive.indices);
|
|
2661
|
+
const attribute = accessor ? {
|
|
2662
|
+
value: getGLTFAccessorValue2(gltf, accessor),
|
|
2663
|
+
size: 1,
|
|
2664
|
+
normalized: accessor.normalized
|
|
2573
2665
|
} : void 0;
|
|
2574
|
-
if (primitive.mode !== 5) return attribute;
|
|
2666
|
+
if (primitive.mode !== 5 && primitive.mode !== 6) return attribute;
|
|
2575
2667
|
const sourceIndices = validateMeshIndices(attribute, vertexCount, 5);
|
|
2576
2668
|
const indexCount = sourceIndices?.length ?? vertexCount;
|
|
2577
2669
|
if (!Number.isSafeInteger(indexCount) || indexCount < 3) {
|
|
@@ -2583,9 +2675,10 @@ function createTriangleIndices(primitive, vertexCount) {
|
|
|
2583
2675
|
const IndexArray = vertexCount < 65536 ? Uint16Array : Uint32Array;
|
|
2584
2676
|
const indices = new IndexArray((indexCount - 2) * 3);
|
|
2585
2677
|
for (let triangle = 0; triangle < indexCount - 2; triangle++) {
|
|
2586
|
-
const second = triangle + 1 + triangle % 2;
|
|
2587
|
-
const third = triangle + 2 - triangle % 2;
|
|
2588
|
-
|
|
2678
|
+
const second = primitive.mode === 6 ? triangle + 1 : triangle + 1 + triangle % 2;
|
|
2679
|
+
const third = primitive.mode === 6 ? triangle + 2 : triangle + 2 - triangle % 2;
|
|
2680
|
+
const first = primitive.mode === 6 ? 0 : triangle;
|
|
2681
|
+
indices[triangle * 3] = sourceIndices?.[first] ?? first;
|
|
2589
2682
|
indices[triangle * 3 + 1] = sourceIndices?.[second] ?? second;
|
|
2590
2683
|
indices[triangle * 3 + 2] = sourceIndices?.[third] ?? third;
|
|
2591
2684
|
}
|
|
@@ -2597,7 +2690,7 @@ import {
|
|
|
2597
2690
|
encodeI3SMeshLayer,
|
|
2598
2691
|
encodeI3SMeshLayerWithDraco,
|
|
2599
2692
|
preloadI3SMeshCompression
|
|
2600
|
-
} from "@loaders.gl/i3s";
|
|
2693
|
+
} from "@loaders.gl/tiles-3d/i3s";
|
|
2601
2694
|
import { TileConversionError as TileConversionError16 } from "@loaders.gl/tile-converter/v5/core";
|
|
2602
2695
|
import { createBoundedMemoryTileConversionSink as createBoundedMemoryTileConversionSink2 } from "@loaders.gl/tile-converter/v5/core";
|
|
2603
2696
|
function createI3SMeshConversionCodec(options) {
|
|
@@ -3220,6 +3313,7 @@ import {
|
|
|
3220
3313
|
import { getBinaryImageMetadata as getBinaryImageMetadata3 } from "@loaders.gl/images";
|
|
3221
3314
|
import { TileConversionError as TileConversionError20 } from "@loaders.gl/tile-converter/v5/core";
|
|
3222
3315
|
async function mapI3SMeshSourceMaterial(content, header, readExternalResource, contentUri, signal) {
|
|
3316
|
+
const gltf = { json: { asset: { version: "2.0" } }, buffers: [] };
|
|
3223
3317
|
const material = Object.fromEntries(
|
|
3224
3318
|
Object.entries(content.material || {}).filter(([, value]) => value !== void 0)
|
|
3225
3319
|
);
|
|
@@ -3286,7 +3380,7 @@ async function mapI3SMeshSourceMaterial(content, header, readExternalResource, c
|
|
|
3286
3380
|
}
|
|
3287
3381
|
}
|
|
3288
3382
|
const declaredFormat = resources[0]?.textureFormat;
|
|
3289
|
-
if (!image || !["image/png", "image/jpeg"].includes(image.mimeType) || declaredFormat && (declaredFormat === "png" ? image.mimeType !== "image/png" : declaredFormat === "jpg" ? image.mimeType !== "image/jpeg" : true)) {
|
|
3383
|
+
if (!(data instanceof Uint8Array) || !image || !["image/png", "image/jpeg"].includes(image.mimeType) || declaredFormat && (declaredFormat === "png" ? image.mimeType !== "image/png" : declaredFormat === "jpg" ? image.mimeType !== "image/jpeg" : true)) {
|
|
3290
3384
|
throw new TileConversionError20(
|
|
3291
3385
|
"I3S_MESH_SOURCE_TEXTURE_UNSUPPORTED",
|
|
3292
3386
|
"I3S base-color bytes must have matching PNG/JPEG headers"
|
|
@@ -3295,19 +3389,24 @@ async function mapI3SMeshSourceMaterial(content, header, readExternalResource, c
|
|
|
3295
3389
|
const sampler = Object.fromEntries(
|
|
3296
3390
|
["wrapS", "wrapT"].filter((name) => textureInfo[name] !== void 0).map((name) => [name, wrappingModes[textureInfo[name]]])
|
|
3297
3391
|
);
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
};
|
|
3392
|
+
gltf.buffers.push({
|
|
3393
|
+
arrayBuffer: data.buffer,
|
|
3394
|
+
byteOffset: data.byteOffset,
|
|
3395
|
+
byteLength: data.byteLength
|
|
3396
|
+
});
|
|
3397
|
+
gltf.json.buffers = [{ byteLength: data.byteLength }];
|
|
3398
|
+
gltf.json.bufferViews = [{ buffer: 0, byteLength: data.byteLength }];
|
|
3399
|
+
gltf.json.images = [{ mimeType: image.mimeType, bufferView: 0 }];
|
|
3400
|
+
gltf.json.samplers = [sampler];
|
|
3401
|
+
gltf.json.textures = [{ source: 0, sampler: 0 }];
|
|
3402
|
+
metallicRoughness.baseColorTexture = { texCoord: 0, index: 0 };
|
|
3305
3403
|
}
|
|
3306
3404
|
const mapped = await mapMeshSourceMaterial(
|
|
3307
3405
|
material,
|
|
3308
3406
|
void 0,
|
|
3309
3407
|
contentUri,
|
|
3310
|
-
signal
|
|
3408
|
+
signal,
|
|
3409
|
+
gltf
|
|
3311
3410
|
);
|
|
3312
3411
|
if (mapped?.baseColorTexture && !content.sourceAttributes?.uv0) {
|
|
3313
3412
|
throw new TileConversionError20(
|
|
@@ -3319,7 +3418,7 @@ async function mapI3SMeshSourceMaterial(content, header, readExternalResource, c
|
|
|
3319
3418
|
}
|
|
3320
3419
|
|
|
3321
3420
|
// src/v5/i3s-mesh-source-features.ts
|
|
3322
|
-
import { I3SAttributeLoader } from "@loaders.gl/i3s";
|
|
3421
|
+
import { I3SAttributeLoader } from "@loaders.gl/tiles-3d/i3s";
|
|
3323
3422
|
import { TileConversionError as TileConversionError21 } from "@loaders.gl/tile-converter/v5/core";
|
|
3324
3423
|
async function extractI3SMeshFeatures(content, item, metadata, options, readExternalResource, contentUri, signal) {
|
|
3325
3424
|
const maximumAttributeBytes = options.maxAttributeBytes;
|
|
@@ -3647,19 +3746,267 @@ function createI3SMeshTilesetConversionSource(tileset, options = {}) {
|
|
|
3647
3746
|
};
|
|
3648
3747
|
}
|
|
3649
3748
|
|
|
3650
|
-
// src/v5/point-cloud-
|
|
3651
|
-
import {
|
|
3749
|
+
// src/v5/point-cloud-attributes.ts
|
|
3750
|
+
import { convertTableToMesh as convertTableToMesh3 } from "@loaders.gl/core/schema-utils";
|
|
3652
3751
|
import { TileConversionError as TileConversionError23 } from "@loaders.gl/tile-converter/v5/core";
|
|
3752
|
+
function mapPointCloudAttributes(input, mapping) {
|
|
3753
|
+
const mesh = getPointCloudMesh(input);
|
|
3754
|
+
const attributes = /* @__PURE__ */ Object.create(null);
|
|
3755
|
+
const selected = /* @__PURE__ */ new Set();
|
|
3756
|
+
for (const [target, source] of Object.entries(mapping.attributes)) {
|
|
3757
|
+
if (!target || ["__proto__", "constructor", "prototype"].includes(target) || !Object.hasOwn(mesh.attributes, source))
|
|
3758
|
+
throw new TileConversionError23(
|
|
3759
|
+
"POINT_CLOUD_MAPPING_INVALID",
|
|
3760
|
+
`Invalid point attribute mapping ${target}: ${source}`
|
|
3761
|
+
);
|
|
3762
|
+
if (Object.hasOwn(mapping.drop || {}, source))
|
|
3763
|
+
throw new TileConversionError23(
|
|
3764
|
+
"POINT_CLOUD_MAPPING_INVALID",
|
|
3765
|
+
`Point attribute ${source} is both selected and dropped`
|
|
3766
|
+
);
|
|
3767
|
+
attributes[target] = { ...mesh.attributes[source] };
|
|
3768
|
+
selected.add(source);
|
|
3769
|
+
}
|
|
3770
|
+
const droppedAttributes = /* @__PURE__ */ Object.create(null);
|
|
3771
|
+
for (const [source, reason] of Object.entries(mapping.drop || {}).sort(
|
|
3772
|
+
([left], [right]) => left < right ? -1 : left > right ? 1 : 0
|
|
3773
|
+
)) {
|
|
3774
|
+
if (!Object.hasOwn(mesh.attributes, source) || typeof reason !== "string" || !reason.trim())
|
|
3775
|
+
throw new TileConversionError23(
|
|
3776
|
+
"POINT_CLOUD_MAPPING_INVALID",
|
|
3777
|
+
`Invalid loss declaration for ${source}`
|
|
3778
|
+
);
|
|
3779
|
+
droppedAttributes[source] = reason;
|
|
3780
|
+
}
|
|
3781
|
+
const unmapped = Object.keys(mesh.attributes).filter(
|
|
3782
|
+
(name) => !selected.has(name) && !Object.hasOwn(droppedAttributes, name)
|
|
3783
|
+
);
|
|
3784
|
+
if (unmapped.length || !attributes.POSITION)
|
|
3785
|
+
throw new TileConversionError23(
|
|
3786
|
+
"POINT_CLOUD_MAPPING_REQUIRED",
|
|
3787
|
+
`Map POSITION and explicitly retain or drop every attribute: ${unmapped.join(", ")}`
|
|
3788
|
+
);
|
|
3789
|
+
return {
|
|
3790
|
+
mesh: { ...mesh, attributes, schema: { fields: [], metadata: { ...mesh.schema?.metadata } } },
|
|
3791
|
+
droppedAttributes
|
|
3792
|
+
};
|
|
3793
|
+
}
|
|
3794
|
+
function getPointCloudMesh(input, maxInputBytes = Infinity) {
|
|
3795
|
+
const buffers = /* @__PURE__ */ new Set();
|
|
3796
|
+
let bytes = 0;
|
|
3797
|
+
const countBuffer = (buffer) => {
|
|
3798
|
+
if (!buffers.has(buffer)) {
|
|
3799
|
+
buffers.add(buffer);
|
|
3800
|
+
bytes += buffer.byteLength;
|
|
3801
|
+
}
|
|
3802
|
+
if (bytes > maxInputBytes)
|
|
3803
|
+
throw new TileConversionError23("POINT_CLOUD_INPUT_BUDGET", "Point input byte budget exceeded");
|
|
3804
|
+
};
|
|
3805
|
+
if ("shape" in input) {
|
|
3806
|
+
const checkColumn = (column) => {
|
|
3807
|
+
if (column.nullCount)
|
|
3808
|
+
throw new TileConversionError23(
|
|
3809
|
+
"POINT_CLOUD_NULL_UNSUPPORTED",
|
|
3810
|
+
"Null point values require an explicit preprocessing step"
|
|
3811
|
+
);
|
|
3812
|
+
for (const buffer of Object.values(column.buffers)) if (buffer) countBuffer(buffer.buffer);
|
|
3813
|
+
for (const view of column.variadicBuffers) countBuffer(view.buffer);
|
|
3814
|
+
for (const child of column.children) checkColumn(child);
|
|
3815
|
+
for (const dictionary of column.dictionary?.data || []) checkColumn(dictionary);
|
|
3816
|
+
};
|
|
3817
|
+
for (const batch of input.data.batches) checkColumn(batch.data);
|
|
3818
|
+
} else
|
|
3819
|
+
for (const attribute of Object.values(input.attributes)) countBuffer(attribute.value.buffer);
|
|
3820
|
+
const mesh = "shape" in input ? convertTableToMesh3(input) : input;
|
|
3821
|
+
if (mesh.topology !== "point-list" || mesh.indices)
|
|
3822
|
+
throw new TileConversionError23(
|
|
3823
|
+
"POINT_CLOUD_INPUT_INVALID",
|
|
3824
|
+
"Decoded unindexed point-list input is required"
|
|
3825
|
+
);
|
|
3826
|
+
return mesh;
|
|
3827
|
+
}
|
|
3828
|
+
|
|
3829
|
+
// src/v5/point-cloud-copc.ts
|
|
3830
|
+
import { COPCWriter } from "@loaders.gl/tiles-3d/copc";
|
|
3831
|
+
import { TileConversionError as TileConversionError24 } from "@loaders.gl/tile-converter/v5/core";
|
|
3832
|
+
var SCALAR_RANGES = {
|
|
3833
|
+
intensity: [0, 65535],
|
|
3834
|
+
classification: [0, 255],
|
|
3835
|
+
nir: [0, 65535],
|
|
3836
|
+
gpsTime: [-Infinity, Infinity],
|
|
3837
|
+
scanAngle: [-32768, 32767],
|
|
3838
|
+
userData: [0, 255],
|
|
3839
|
+
pointSourceId: [0, 65535],
|
|
3840
|
+
returnNumber: [1, 15],
|
|
3841
|
+
numberOfReturns: [1, 15],
|
|
3842
|
+
scannerChannel: [0, 3],
|
|
3843
|
+
scanDirectionFlag: [0, 1],
|
|
3844
|
+
edgeOfFlightLine: [0, 1],
|
|
3845
|
+
synthetic: [0, 1],
|
|
3846
|
+
keyPoint: [0, 1],
|
|
3847
|
+
withheld: [0, 1],
|
|
3848
|
+
overlap: [0, 1]
|
|
3849
|
+
};
|
|
3850
|
+
async function encodePointCloudCOPC(input, options) {
|
|
3851
|
+
const maxInputBytes = options.maxInputBytes ?? 64 * 1024 * 1024;
|
|
3852
|
+
const maxPoints = options.maxPoints ?? 1e6;
|
|
3853
|
+
const maxOutputBytes = options.maxOutputBytes ?? 128 * 1024 * 1024;
|
|
3854
|
+
if ([maxInputBytes, maxPoints, maxOutputBytes].some(
|
|
3855
|
+
(value) => !Number.isSafeInteger(value) || value < 1
|
|
3856
|
+
) || options.scale.length !== 3 || options.scale.some((value) => !Number.isFinite(value) || value <= 0) || options.offset.length !== 3 || options.offset.some((value) => !Number.isFinite(value)) || typeof options.wkt !== "string" || !options.wkt.trim() || !Number.isFinite(options.maxPositionError) || options.maxPositionError < 0)
|
|
3857
|
+
throw new TileConversionError24(
|
|
3858
|
+
"POINT_CLOUD_COPC_OPTIONS_INVALID",
|
|
3859
|
+
"COPC requires explicit finite scale, offset, CRS, precision and positive budgets"
|
|
3860
|
+
);
|
|
3861
|
+
options.signal?.throwIfAborted();
|
|
3862
|
+
const source = getPointCloudMesh(input, maxInputBytes);
|
|
3863
|
+
const { mesh, droppedAttributes } = mapPointCloudAttributes(source, options.mapping);
|
|
3864
|
+
const position = mesh.attributes.POSITION;
|
|
3865
|
+
const pointCount = mesh.header?.vertexCount ?? position.value.length / 3;
|
|
3866
|
+
if (!Number.isSafeInteger(pointCount) || pointCount < 1 || pointCount > maxPoints)
|
|
3867
|
+
throw new TileConversionError24(
|
|
3868
|
+
"POINT_CLOUD_POINT_BUDGET",
|
|
3869
|
+
"COPC requires a nonempty batch within the point limit"
|
|
3870
|
+
);
|
|
3871
|
+
if (!(position.value instanceof Float32Array || position.value instanceof Float64Array) || position.size !== 3 || position.normalized)
|
|
3872
|
+
throw new TileConversionError24(
|
|
3873
|
+
"POINT_CLOUD_POSITION_INVALID",
|
|
3874
|
+
"COPC requires decoded floating XYZ"
|
|
3875
|
+
);
|
|
3876
|
+
const extraNames = new Set(options.extraBytes?.map((field) => field.attribute) || []);
|
|
3877
|
+
const descriptorNames = new Set(
|
|
3878
|
+
options.extraBytes?.map((field) => field.name || field.attribute) || []
|
|
3879
|
+
);
|
|
3880
|
+
if (extraNames.size !== (options.extraBytes?.length || 0) || descriptorNames.size !== extraNames.size || options.extraBytes?.some((field) => {
|
|
3881
|
+
const name = field.name || field.attribute;
|
|
3882
|
+
const description = field.description || "";
|
|
3883
|
+
return !mesh.attributes[field.attribute] || !field.attribute || !name.length || name.length > 32 || description.length > 32 || /[^\x20-\x7e]/.test(name) || /[^\x20-\x7e]/.test(description);
|
|
3884
|
+
}))
|
|
3885
|
+
throw new TileConversionError24(
|
|
3886
|
+
"POINT_CLOUD_EXTRA_BYTES_INVALID",
|
|
3887
|
+
"Extra Bytes descriptors require unique mapped attributes and names/descriptions within 32 printable ASCII bytes"
|
|
3888
|
+
);
|
|
3889
|
+
for (const name of extraNames)
|
|
3890
|
+
if (name === "POSITION" || name === "COLOR_0" || Object.hasOwn(SCALAR_RANGES, name))
|
|
3891
|
+
throw new TileConversionError24(
|
|
3892
|
+
"POINT_CLOUD_EXTRA_BYTES_INVALID",
|
|
3893
|
+
"Map standard attributes directly instead of duplicating them as Extra Bytes"
|
|
3894
|
+
);
|
|
3895
|
+
for (const [name, attribute] of Object.entries(mesh.attributes)) {
|
|
3896
|
+
const color2 = name === "COLOR_0";
|
|
3897
|
+
const extra = extraNames.has(name);
|
|
3898
|
+
if (name !== "POSITION" && !color2 && !extra && !Object.hasOwn(SCALAR_RANGES, name))
|
|
3899
|
+
throw new TileConversionError24(
|
|
3900
|
+
"POINT_CLOUD_ATTRIBUTE_UNSUPPORTED",
|
|
3901
|
+
`COPC cannot preserve ${name}; supply an explicit supported mapping or drop reason`
|
|
3902
|
+
);
|
|
3903
|
+
if (attribute.transform || attribute.byteOffset || attribute.byteStride || attribute.componentType === "float16" || attribute.value.length !== pointCount * attribute.size || !color2 && attribute.normalized || name !== "POSITION" && !color2 && (extra ? ![1, 3].includes(attribute.size) : attribute.size !== 1))
|
|
3904
|
+
throw new TileConversionError24(
|
|
3905
|
+
"POINT_CLOUD_ATTRIBUTE_INVALID",
|
|
3906
|
+
`COPC requires packed decoded attributes: ${name}`
|
|
3907
|
+
);
|
|
3908
|
+
if (color2) {
|
|
3909
|
+
if (attribute.size !== 3 || !(attribute.value instanceof Uint8Array || attribute.value instanceof Uint16Array))
|
|
3910
|
+
throw new TileConversionError24(
|
|
3911
|
+
"POINT_CLOUD_COLOR_INVALID",
|
|
3912
|
+
"COPC requires explicitly mapped uint8/uint16 RGB"
|
|
3913
|
+
);
|
|
3914
|
+
} else if (extra) {
|
|
3915
|
+
for (const value of attribute.value)
|
|
3916
|
+
if (typeof value !== "bigint" && !Number.isFinite(value))
|
|
3917
|
+
throw new TileConversionError24(
|
|
3918
|
+
"POINT_CLOUD_ATTRIBUTE_RANGE",
|
|
3919
|
+
`Nonfinite Extra Bytes value: ${name}`
|
|
3920
|
+
);
|
|
3921
|
+
} else if (name !== "POSITION") {
|
|
3922
|
+
const [minimum2, maximum2] = SCALAR_RANGES[name];
|
|
3923
|
+
for (const value of attribute.value) {
|
|
3924
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < minimum2 || value > maximum2 || name !== "gpsTime" && !Number.isInteger(value))
|
|
3925
|
+
throw new TileConversionError24(
|
|
3926
|
+
"POINT_CLOUD_ATTRIBUTE_RANGE",
|
|
3927
|
+
`COPC value outside the qualified range: ${name}`
|
|
3928
|
+
);
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
let maximumPositionError = 0;
|
|
3933
|
+
const minimum = [Infinity, Infinity, Infinity];
|
|
3934
|
+
const maximum = [-Infinity, -Infinity, -Infinity];
|
|
3935
|
+
const errors = [0, 0, 0];
|
|
3936
|
+
for (let row = 0; row < pointCount; row++) {
|
|
3937
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
3938
|
+
const value = position.value[row * 3 + axis];
|
|
3939
|
+
const encoded = Math.round((value - options.offset[axis]) / options.scale[axis]);
|
|
3940
|
+
if (!Number.isFinite(value) || !Number.isSafeInteger(encoded) || encoded < -2147483648 || encoded > 2147483647)
|
|
3941
|
+
throw new TileConversionError24(
|
|
3942
|
+
"POINT_CLOUD_POSITION_RANGE",
|
|
3943
|
+
"COPC position exceeds signed int32 quantization"
|
|
3944
|
+
);
|
|
3945
|
+
minimum[axis] = Math.min(minimum[axis], value);
|
|
3946
|
+
maximum[axis] = Math.max(maximum[axis], value);
|
|
3947
|
+
errors[axis] = encoded * options.scale[axis] + options.offset[axis] - value;
|
|
3948
|
+
}
|
|
3949
|
+
maximumPositionError = Math.max(maximumPositionError, Math.hypot(...errors));
|
|
3950
|
+
if (maximumPositionError > options.maxPositionError)
|
|
3951
|
+
throw new TileConversionError24(
|
|
3952
|
+
"POINT_CLOUD_PRECISION_EXCEEDED",
|
|
3953
|
+
"COPC position rounding exceeds the declared error gate"
|
|
3954
|
+
);
|
|
3955
|
+
if (row % 16384 === 0) {
|
|
3956
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
3957
|
+
options.signal?.throwIfAborted();
|
|
3958
|
+
}
|
|
3959
|
+
}
|
|
3960
|
+
const width = Math.max(...maximum.map((value, axis) => value - minimum[axis]), ...options.scale);
|
|
3961
|
+
const radius = width / 2;
|
|
3962
|
+
if (!Number.isFinite(Math.hypot(radius, radius, radius)) || minimum.some((value, axis) => {
|
|
3963
|
+
const center = value + (maximum[axis] - value) / 2;
|
|
3964
|
+
return !Number.isFinite(value + maximum[axis]) || !Number.isFinite(center - radius) || !Number.isFinite(center + radius);
|
|
3965
|
+
}))
|
|
3966
|
+
throw new TileConversionError24("POINT_CLOUD_BOUNDS_INVALID", "COPC coordinate extent overflow");
|
|
3967
|
+
options.signal?.throwIfAborted();
|
|
3968
|
+
const color = mesh.attributes.COLOR_0;
|
|
3969
|
+
const copc = COPCWriter.encodeSync(mesh, {
|
|
3970
|
+
copc: {
|
|
3971
|
+
...options.organization,
|
|
3972
|
+
scale: [...options.scale],
|
|
3973
|
+
offset: [...options.offset],
|
|
3974
|
+
wkt: options.wkt,
|
|
3975
|
+
pointDataRecordFormat: mesh.attributes.nir ? 8 : color ? 7 : 6,
|
|
3976
|
+
colorDepth: color?.value instanceof Uint16Array ? 16 : 8,
|
|
3977
|
+
extraBytes: options.extraBytes
|
|
3978
|
+
}
|
|
3979
|
+
});
|
|
3980
|
+
options.signal?.throwIfAborted();
|
|
3981
|
+
if (copc.byteLength > maxOutputBytes)
|
|
3982
|
+
throw new TileConversionError24(
|
|
3983
|
+
"POINT_CLOUD_OUTPUT_BUDGET",
|
|
3984
|
+
"Completed COPC output exceeds the byte budget"
|
|
3985
|
+
);
|
|
3986
|
+
return { copc, pointCount, maximumPositionError, droppedAttributes };
|
|
3987
|
+
}
|
|
3988
|
+
function createCOPCConversionCodec(options) {
|
|
3989
|
+
return {
|
|
3990
|
+
async *convert(input, _inspection, signal) {
|
|
3991
|
+
const combinedSignal = options.signal && signal ? AbortSignal.any([options.signal, signal]) : options.signal || signal;
|
|
3992
|
+
yield await encodePointCloudCOPC(input, { ...options, signal: combinedSignal });
|
|
3993
|
+
}
|
|
3994
|
+
};
|
|
3995
|
+
}
|
|
3996
|
+
|
|
3997
|
+
// src/v5/point-cloud-tileset.ts
|
|
3998
|
+
import { PointCloudTileSource } from "@loaders.gl/tiles-3d/point-cloud-tile-source";
|
|
3999
|
+
import { TileConversionError as TileConversionError25 } from "@loaders.gl/tile-converter/v5/core";
|
|
3653
4000
|
async function convertPointCloudToTileset(input, options) {
|
|
3654
4001
|
const reference = options.spatialReference;
|
|
3655
4002
|
if (!reference || reference.status !== "native" || reference.sourceCrs !== "EPSG:4978" || reference.targetCrs && reference.targetCrs !== "EPSG:4978" || reference.coordinateFrame !== "geocentric" || reference.axisOrder !== "xyz" || reference.heightReference !== "ellipsoidal" || reference.verticalUnitScale !== 1 || reference.units?.some((unit) => unit !== "meter")) {
|
|
3656
|
-
throw new
|
|
4003
|
+
throw new TileConversionError25(
|
|
3657
4004
|
"POINT_CLOUD_TILESET_FRAME_UNSUPPORTED",
|
|
3658
4005
|
"Point authoring requires explicit native EPSG:4978 xyz meters and ellipsoidal heights"
|
|
3659
4006
|
);
|
|
3660
4007
|
}
|
|
3661
4008
|
if (options.archive && (!Number.isSafeInteger(options.archive.maxArchiveBytes) || options.archive.maxArchiveBytes < 0)) {
|
|
3662
|
-
throw new
|
|
4009
|
+
throw new TileConversionError25(
|
|
3663
4010
|
"INVALID_ARCHIVE_BYTE_LIMIT",
|
|
3664
4011
|
"Archive byte limit must be a non-negative safe integer"
|
|
3665
4012
|
);
|
|
@@ -3710,10 +4057,10 @@ async function convertPointCloudToTileset(input, options) {
|
|
|
3710
4057
|
}
|
|
3711
4058
|
|
|
3712
4059
|
// src/v5/point-cloud-file.ts
|
|
3713
|
-
import { COPCSourceLoader } from "@loaders.gl/copc";
|
|
3714
|
-
import { PotreeSourceLoader, encodePotreeDataset } from "@loaders.gl/potree";
|
|
3715
|
-
import { deduceMeshSchema } from "@loaders.gl/schema-utils";
|
|
3716
|
-
import { encodeZip, openZipArchive } from "@loaders.gl/zip";
|
|
4060
|
+
import { COPCSourceLoader } from "@loaders.gl/tiles-3d/copc";
|
|
4061
|
+
import { PotreeSourceLoader, encodePotreeDataset } from "@loaders.gl/tiles-3d/potree";
|
|
4062
|
+
import { deduceMeshSchema } from "@loaders.gl/core/schema-utils";
|
|
4063
|
+
import { encodeZip, openZipArchive } from "@loaders.gl/archives/zip";
|
|
3717
4064
|
async function encodePotreeArchive(input, options) {
|
|
3718
4065
|
validateLimit(options.maxArchiveBytes);
|
|
3719
4066
|
const dataset = await encodePotreeDataset(input, { potree: options.potree });
|
|
@@ -3867,8 +4214,8 @@ function validateLimit(value) {
|
|
|
3867
4214
|
}
|
|
3868
4215
|
|
|
3869
4216
|
// src/v5/point-cloud-potree.ts
|
|
3870
|
-
import { PointCloudTiler } from "@loaders.gl/schema-utils";
|
|
3871
|
-
import { encodePotreeDataset as encodePotreeDataset2 } from "@loaders.gl/potree";
|
|
4217
|
+
import { PointCloudTiler } from "@loaders.gl/core/schema-utils";
|
|
4218
|
+
import { encodePotreeDataset as encodePotreeDataset2 } from "@loaders.gl/tiles-3d/potree";
|
|
3872
4219
|
async function convertPointCloudToPotree(input, options) {
|
|
3873
4220
|
if (typeof options.projection !== "string" || !options.projection.trim()) {
|
|
3874
4221
|
throw new Error("Potree authoring requires an explicit native CRS declaration");
|
|
@@ -3939,15 +4286,15 @@ async function convertPointCloudToPotree(input, options) {
|
|
|
3939
4286
|
|
|
3940
4287
|
// src/v5/mesh-hierarchy.ts
|
|
3941
4288
|
import { Matrix4 as Matrix43 } from "@math.gl/core";
|
|
3942
|
-
import { get3DTilesSpatialReference } from "@loaders.gl/tiles";
|
|
4289
|
+
import { get3DTilesSpatialReference } from "@loaders.gl/tiles-3d";
|
|
3943
4290
|
import {
|
|
3944
|
-
TileConversionError as
|
|
4291
|
+
TileConversionError as TileConversionError26,
|
|
3945
4292
|
createBoundedMemoryTileConversionSink as createBoundedMemoryTileConversionSink5,
|
|
3946
4293
|
createTiles3DConversionSpatialContext
|
|
3947
4294
|
} from "@loaders.gl/tile-converter/v5/core";
|
|
3948
4295
|
function prepareMeshHierarchy(inspection, resourceIds) {
|
|
3949
4296
|
const rejectHierarchy = (message) => {
|
|
3950
|
-
throw new
|
|
4297
|
+
throw new TileConversionError26("MESH_HIERARCHY_UNSUPPORTED", message);
|
|
3951
4298
|
};
|
|
3952
4299
|
if (!inspection.documents?.length || inspection.documents.length > 32)
|
|
3953
4300
|
rejectHierarchy(
|
|
@@ -4127,7 +4474,7 @@ function createMeshHierarchyTilesetSink(options) {
|
|
|
4127
4474
|
);
|
|
4128
4475
|
const { maxPositionError } = options;
|
|
4129
4476
|
if (!Number.isFinite(maxPositionError) || maxPositionError < 0 || hierarchy.nodes.some((node) => !Number.isFinite(node.geometricError + maxPositionError)) || !Number.isFinite(hierarchy.geometricError + maxPositionError))
|
|
4130
|
-
throw new
|
|
4477
|
+
throw new TileConversionError26(
|
|
4131
4478
|
"MESH_GEOMETRIC_ERROR_INVALID",
|
|
4132
4479
|
"Hierarchy position allowance and resulting errors must be finite nonnegative meters"
|
|
4133
4480
|
);
|
|
@@ -4149,12 +4496,12 @@ function createMeshHierarchyTilesetSink(options) {
|
|
|
4149
4496
|
last: true
|
|
4150
4497
|
};
|
|
4151
4498
|
if (state !== "open" || !identifier || completedContents.has(identifier) || primitiveIdentifiers.has(resource.id) || primitiveIdentifiers.size >= 64 || !Number.isSafeInteger(primitiveIndex) || primitiveIndex !== (placements.get(identifier)?.length ?? 0) || typeof lastPrimitive !== "boolean" || !hierarchy.nodes.some((node2) => node2.resourceIds.includes(identifier)))
|
|
4152
|
-
throw new
|
|
4499
|
+
throw new TileConversionError26(
|
|
4153
4500
|
"MESH_HIERARCHY_PLACEMENT_INVALID",
|
|
4154
4501
|
"Hierarchy writes require ordered, distinct primitives for declared contents before close (at most 64)"
|
|
4155
4502
|
);
|
|
4156
4503
|
if (resource.spatialReference.coordinateEpoch !== hierarchy.coordinateEpoch)
|
|
4157
|
-
throw new
|
|
4504
|
+
throw new TileConversionError26(
|
|
4158
4505
|
"MESH_SOURCE_EPOCH_MISMATCH",
|
|
4159
4506
|
"Hierarchy output coordinate epoch must match its source"
|
|
4160
4507
|
);
|
|
@@ -4163,7 +4510,7 @@ function createMeshHierarchyTilesetSink(options) {
|
|
|
4163
4510
|
const node = hierarchy.nodes[nodeIndex];
|
|
4164
4511
|
const sibling = node.resourceIds.map((identifier2) => placements.get(identifier2)?.[0]).find(Boolean);
|
|
4165
4512
|
if (sibling && sibling.origin.some((value, axis) => value !== resource.origin[axis]))
|
|
4166
|
-
throw new
|
|
4513
|
+
throw new TileConversionError26(
|
|
4167
4514
|
"MESH_HIERARCHY_PLACEMENT_INVALID",
|
|
4168
4515
|
"Contents on one tile must share an encoded origin"
|
|
4169
4516
|
);
|
|
@@ -4190,7 +4537,7 @@ function createMeshHierarchyTilesetSink(options) {
|
|
|
4190
4537
|
/** Publishes original topology only after every source content has completed. */
|
|
4191
4538
|
async finalize(report) {
|
|
4192
4539
|
if (state !== "open" || completedContents.size !== hierarchy.nodes.reduce((count, node) => count + node.resourceIds.length, 0))
|
|
4193
|
-
throw new
|
|
4540
|
+
throw new TileConversionError26(
|
|
4194
4541
|
"MESH_HIERARCHY_INCOMPLETE",
|
|
4195
4542
|
"Finalization requires every declared hierarchy content"
|
|
4196
4543
|
);
|
|
@@ -4228,7 +4575,7 @@ function createMeshHierarchyTilesetSink(options) {
|
|
|
4228
4575
|
maximum[axis] = Math.max(maximum[axis], upper[axis]);
|
|
4229
4576
|
}
|
|
4230
4577
|
if ([...minimum, ...maximum].some((value) => !Number.isFinite(value)))
|
|
4231
|
-
throw new
|
|
4578
|
+
throw new TileConversionError26(
|
|
4232
4579
|
"MESH_TILESET_BOUNDS_INVALID",
|
|
4233
4580
|
"Hierarchy absolute bounds must remain finite"
|
|
4234
4581
|
);
|
|
@@ -4246,7 +4593,7 @@ function createMeshHierarchyTilesetSink(options) {
|
|
|
4246
4593
|
)
|
|
4247
4594
|
);
|
|
4248
4595
|
if ([...center, ...halfAxes].some((value) => !Number.isFinite(value)))
|
|
4249
|
-
throw new
|
|
4596
|
+
throw new TileConversionError26(
|
|
4250
4597
|
"MESH_TILESET_BOUNDS_INVALID",
|
|
4251
4598
|
"Hierarchy local bounds must remain finite"
|
|
4252
4599
|
);
|
|
@@ -4262,7 +4609,7 @@ function createMeshHierarchyTilesetSink(options) {
|
|
|
4262
4609
|
new Matrix43(inverse).multiplyRight(transforms[child])
|
|
4263
4610
|
);
|
|
4264
4611
|
if (tiles[child].transform.some((value) => !Number.isFinite(value)))
|
|
4265
|
-
throw new
|
|
4612
|
+
throw new TileConversionError26(
|
|
4266
4613
|
"MESH_TILESET_BOUNDS_INVALID",
|
|
4267
4614
|
"Relative hierarchy transforms must remain finite"
|
|
4268
4615
|
);
|
|
@@ -4301,13 +4648,13 @@ function createMeshHierarchyTilesetSink(options) {
|
|
|
4301
4648
|
|
|
4302
4649
|
// src/v5/selected-mesh-source.ts
|
|
4303
4650
|
import { coreApi, parse } from "@loaders.gl/core";
|
|
4304
|
-
import { Tiles3DLoader } from "@loaders.gl/3d-tiles";
|
|
4305
|
-
import { Tiles3DSource, Tileset3D } from "@loaders.gl/tiles";
|
|
4651
|
+
import { Tiles3DLoader } from "@loaders.gl/tiles-3d/3d-tiles";
|
|
4652
|
+
import { Tiles3DSource, Tileset3D } from "@loaders.gl/tiles-3d";
|
|
4306
4653
|
import {
|
|
4307
4654
|
createBrowserTilesetConversionSource,
|
|
4308
4655
|
selectBrowserTilesetContent,
|
|
4309
4656
|
createTiles3DConversionSpatialContext as createTiles3DConversionSpatialContext2,
|
|
4310
|
-
TileConversionError as
|
|
4657
|
+
TileConversionError as TileConversionError27
|
|
4311
4658
|
} from "@loaders.gl/tile-converter/v5/core";
|
|
4312
4659
|
import {
|
|
4313
4660
|
createMeshTilesetConversionSource as createMeshTilesetConversionSource2,
|
|
@@ -4340,7 +4687,7 @@ async function createSelectedMeshConversionSource(inspection, options) {
|
|
|
4340
4687
|
} = options;
|
|
4341
4688
|
const maxInputBytes = options.maxInputBytes ?? SELECTED_MESH_LIMITS.maxInputBytes;
|
|
4342
4689
|
if (!Number.isSafeInteger(maxInputBytes) || maxInputBytes < 1 || maxInputBytes > SELECTED_MESH_LIMITS.maxInputBytes)
|
|
4343
|
-
throw new
|
|
4690
|
+
throw new TileConversionError27(
|
|
4344
4691
|
"INVALID_SELECTED_MESH_OPTIONS",
|
|
4345
4692
|
"Selected mesh input budget must be a positive safe integer at most 16 MiB"
|
|
4346
4693
|
);
|
|
@@ -4349,7 +4696,7 @@ async function createSelectedMeshConversionSource(inspection, options) {
|
|
|
4349
4696
|
))
|
|
4350
4697
|
throw new Error("Select between 1 and 64 distinct content placements.");
|
|
4351
4698
|
if (preserveHierarchy !== void 0 && typeof preserveHierarchy !== "boolean")
|
|
4352
|
-
throw new
|
|
4699
|
+
throw new TileConversionError27(
|
|
4353
4700
|
"MESH_HIERARCHY_UNSUPPORTED",
|
|
4354
4701
|
"preserveHierarchy must be a boolean"
|
|
4355
4702
|
);
|
|
@@ -4414,7 +4761,7 @@ async function createSelectedMeshConversionSource(inspection, options) {
|
|
|
4414
4761
|
for await (const raw of rawSource.read(selectedInspection, signal2)) {
|
|
4415
4762
|
const selection = selectedContents.get(raw.resourceId);
|
|
4416
4763
|
if (!selection)
|
|
4417
|
-
throw new
|
|
4764
|
+
throw new TileConversionError27(
|
|
4418
4765
|
"INVALID_BROWSER_SELECTION",
|
|
4419
4766
|
"Source yielded an uninspected content placement"
|
|
4420
4767
|
);
|
|
@@ -4443,7 +4790,7 @@ async function createSelectedMeshConversionSource(inspection, options) {
|
|
|
4443
4790
|
const metadata = await meshSource.inspect(signal2);
|
|
4444
4791
|
const selectedContext = createTiles3DConversionSpatialContext2(metadata.spatialReference);
|
|
4445
4792
|
if (selectedContext.spatialReference.coordinateEpoch !== spatialContext.spatialReference.coordinateEpoch)
|
|
4446
|
-
throw new
|
|
4793
|
+
throw new TileConversionError27(
|
|
4447
4794
|
"MESH_SOURCE_EPOCH_MISMATCH",
|
|
4448
4795
|
"Selected content coordinate epoch must match the root; epoch transformations are unsupported"
|
|
4449
4796
|
);
|
|
@@ -4454,7 +4801,7 @@ async function createSelectedMeshConversionSource(inspection, options) {
|
|
|
4454
4801
|
throw new Error("Selected contents exceed the mesh primitive placement limit.");
|
|
4455
4802
|
decodedBytes += measureMeshBytes(resource);
|
|
4456
4803
|
if (decodedBytes > maxInputBytes)
|
|
4457
|
-
throw new
|
|
4804
|
+
throw new TileConversionError27(
|
|
4458
4805
|
"INPUT_RESOURCE_TOO_LARGE",
|
|
4459
4806
|
"Selected decoded geometry and encoded images exceed the aggregate input byte limit."
|
|
4460
4807
|
);
|
|
@@ -4569,14 +4916,14 @@ function measureMeshBytes(resource) {
|
|
|
4569
4916
|
}
|
|
4570
4917
|
|
|
4571
4918
|
// src/v5/archive-source.ts
|
|
4572
|
-
import { BlobFile, HttpFile } from "@loaders.gl/loader-utils";
|
|
4573
|
-
import { parseSLPKArchive } from "@loaders.gl/i3s";
|
|
4574
|
-
import { parse3DTilesArchive } from "@loaders.gl/3d-tiles";
|
|
4575
|
-
import { TileConversionError as
|
|
4919
|
+
import { BlobFile, HttpFile } from "@loaders.gl/core/loader-utils";
|
|
4920
|
+
import { parseSLPKArchive } from "@loaders.gl/tiles-3d/i3s";
|
|
4921
|
+
import { parse3DTilesArchive } from "@loaders.gl/tiles-3d/3d-tiles";
|
|
4922
|
+
import { TileConversionError as TileConversionError28 } from "@loaders.gl/tile-converter/v5/core";
|
|
4576
4923
|
async function openTileConversionArchive(descriptor, maxInputBytes, signal, fetcher = fetch) {
|
|
4577
4924
|
signal.throwIfAborted();
|
|
4578
4925
|
if (!["slpk", "3tz"].includes(descriptor.format))
|
|
4579
|
-
throw new
|
|
4926
|
+
throw new TileConversionError28("INVALID_ARCHIVE_SOURCE", "Select SLPK or 3TZ archive input");
|
|
4580
4927
|
validateArchiveEntityTag(descriptor.identity?.etag);
|
|
4581
4928
|
const transport = createTileConversionResourceFetcher({
|
|
4582
4929
|
maxInputBytes,
|
|
@@ -4643,12 +4990,12 @@ async function createTileConversionArchiveTransport(file, format, maxInputBytes,
|
|
|
4643
4990
|
const checkOpen = () => {
|
|
4644
4991
|
signal.throwIfAborted();
|
|
4645
4992
|
if (closed)
|
|
4646
|
-
throw new
|
|
4993
|
+
throw new TileConversionError28("ARCHIVE_SOURCE_CLOSED", "Conversion archive is closed");
|
|
4647
4994
|
};
|
|
4648
4995
|
try {
|
|
4649
4996
|
checkOpen();
|
|
4650
4997
|
if (!["slpk", "3tz"].includes(format) || !Number.isSafeInteger(maxInputBytes) || maxInputBytes < 1)
|
|
4651
|
-
throw new
|
|
4998
|
+
throw new TileConversionError28(
|
|
4652
4999
|
"INVALID_ARCHIVE_SOURCE",
|
|
4653
5000
|
"Archive source requires a supported format and positive safe byte budget"
|
|
4654
5001
|
);
|
|
@@ -4666,7 +5013,7 @@ async function createTileConversionArchiveTransport(file, format, maxInputBytes,
|
|
|
4666
5013
|
read: async (start, length) => {
|
|
4667
5014
|
checkOpen();
|
|
4668
5015
|
if (!Number.isSafeInteger(length) || length < 0 || length > maxInputBytes - readBytes)
|
|
4669
|
-
throw new
|
|
5016
|
+
throw new TileConversionError28(
|
|
4670
5017
|
"INPUT_RESOURCE_TOO_LARGE",
|
|
4671
5018
|
"Archive indexed reads exceed the input budget"
|
|
4672
5019
|
);
|
|
@@ -4715,7 +5062,7 @@ async function createTileConversionArchiveTransport(file, format, maxInputBytes,
|
|
|
4715
5062
|
}
|
|
4716
5063
|
function validateArchiveEntityTag(entityTag) {
|
|
4717
5064
|
if (entityTag !== void 0 && entityTag !== null && !/^"[\x21\x23-\x7e\x80-\xff]*"$/.test(entityTag))
|
|
4718
|
-
throw new
|
|
5065
|
+
throw new TileConversionError28(
|
|
4719
5066
|
"ARCHIVE_VALIDATOR_UNSUPPORTED",
|
|
4720
5067
|
"Remote archives require a strong quoted ETag, or Last-Modified without an ETag; weak/malformed ETags are unsupported"
|
|
4721
5068
|
);
|
|
@@ -4729,7 +5076,7 @@ function validateArchiveResponseValidator(headers) {
|
|
|
4729
5076
|
const modifiedTime = parseArchiveHttpDate(lastModified);
|
|
4730
5077
|
const responseTime = parseArchiveHttpDate(responseDate);
|
|
4731
5078
|
if (!Number.isFinite(modifiedTime) || !Number.isFinite(responseTime) || responseTime - modifiedTime < 6e4)
|
|
4732
|
-
throw new
|
|
5079
|
+
throw new TileConversionError28(
|
|
4733
5080
|
"ARCHIVE_VALIDATOR_UNSUPPORTED",
|
|
4734
5081
|
"Last-Modified archive identity requires a valid Date at least 60 seconds later; otherwise supply a strong ETag"
|
|
4735
5082
|
);
|
|
@@ -4741,11 +5088,11 @@ function parseArchiveHttpDate(value) {
|
|
|
4741
5088
|
|
|
4742
5089
|
// src/v5/i3s-selection-source.ts
|
|
4743
5090
|
import { coreApi as coreApi2, parse as parse2 } from "@loaders.gl/core";
|
|
4744
|
-
import { I3SLoader } from "@loaders.gl/i3s";
|
|
4745
|
-
import { I3SSource, Tileset3D as Tileset3D2 } from "@loaders.gl/tiles";
|
|
5091
|
+
import { I3SLoader } from "@loaders.gl/tiles-3d/i3s";
|
|
5092
|
+
import { I3SSource, Tileset3D as Tileset3D2 } from "@loaders.gl/tiles-3d";
|
|
4746
5093
|
import {
|
|
4747
5094
|
createI3SConversionSpatialContext,
|
|
4748
|
-
TileConversionError as
|
|
5095
|
+
TileConversionError as TileConversionError29
|
|
4749
5096
|
} from "@loaders.gl/tile-converter/v5/core";
|
|
4750
5097
|
function createRuntime(transport, layer, header) {
|
|
4751
5098
|
const libraries = transport.dracoLibraryOptions;
|
|
@@ -4857,7 +5204,7 @@ async function createSelectedI3SMeshConversionSource(inspection, options) {
|
|
|
4857
5204
|
validateSelectionOptions(options);
|
|
4858
5205
|
signal.throwIfAborted();
|
|
4859
5206
|
if (inspection.rootUrl !== options.rootUrl)
|
|
4860
|
-
throw new
|
|
5207
|
+
throw new TileConversionError29(
|
|
4861
5208
|
"INVALID_I3S_SELECTION",
|
|
4862
5209
|
"Selection transport must match the inspected layer"
|
|
4863
5210
|
);
|
|
@@ -4907,7 +5254,7 @@ async function createSelectedI3SMeshConversionSource(inspection, options) {
|
|
|
4907
5254
|
for await (const resource of meshSource.read(metadata, signal)) {
|
|
4908
5255
|
decodedBytes += measureMeshBytes(resource);
|
|
4909
5256
|
if (++meshCount > SELECTED_MESH_LIMITS.maxMeshResources || decodedBytes > (options.maxInputBytes ?? SELECTED_MESH_LIMITS.maxInputBytes))
|
|
4910
|
-
throw new
|
|
5257
|
+
throw new TileConversionError29(
|
|
4911
5258
|
"INPUT_RESOURCE_TOO_LARGE",
|
|
4912
5259
|
"Selected I3S decoded resources exceed the input/mesh budget"
|
|
4913
5260
|
);
|
|
@@ -4934,7 +5281,7 @@ function validateSelectionOptions(options) {
|
|
|
4934
5281
|
]
|
|
4935
5282
|
])
|
|
4936
5283
|
if (!Number.isSafeInteger(value) || value < 1 || value > maximum)
|
|
4937
|
-
throw new
|
|
5284
|
+
throw new TileConversionError29(
|
|
4938
5285
|
"INVALID_I3S_SELECTION_LIMIT",
|
|
4939
5286
|
"I3S selection limits must be positive safe integers within the bounded profile"
|
|
4940
5287
|
);
|
|
@@ -4945,6 +5292,7 @@ export {
|
|
|
4945
5292
|
convertPointCloudSource,
|
|
4946
5293
|
convertPointCloudToPotree,
|
|
4947
5294
|
convertPointCloudToTileset,
|
|
5295
|
+
createCOPCConversionCodec,
|
|
4948
5296
|
createI3SMeshConversionCodec,
|
|
4949
5297
|
createI3SMeshSink,
|
|
4950
5298
|
createI3SMeshTilesetConversionSource,
|
|
@@ -4963,6 +5311,7 @@ export {
|
|
|
4963
5311
|
createTileConversionArchiveTransport,
|
|
4964
5312
|
createTileConversionResourceFetcher,
|
|
4965
5313
|
encodeMeshTile,
|
|
5314
|
+
encodePointCloudCOPC,
|
|
4966
5315
|
encodePointCloudSource,
|
|
4967
5316
|
encodePointCloudSourceTile,
|
|
4968
5317
|
encodePointCloudTile,
|
|
@@ -4971,6 +5320,7 @@ export {
|
|
|
4971
5320
|
encodeTileConversionArchiveInBatches,
|
|
4972
5321
|
extractMeshVertices,
|
|
4973
5322
|
inspectI3SMeshConversionSource,
|
|
5323
|
+
mapPointCloudAttributes,
|
|
4974
5324
|
measureMeshBytes,
|
|
4975
5325
|
openPointCloudFile,
|
|
4976
5326
|
openTileConversionArchive,
|