@loaders.gl/tile-converter 4.0.0-alpha.21 → 4.0.0-alpha.23
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/dist/constants.d.ts +0 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -3
- package/dist/converter.min.js +114 -114
- package/dist/dist.min.js +2409 -1161
- package/dist/es5/constants.js +1 -5
- package/dist/es5/constants.js.map +1 -1
- package/dist/es5/deps-installer/deps-installer.js +1 -1
- package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js +26 -11
- package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
- package/dist/es5/i3s-converter/helpers/feature-attributes.js +14 -12
- package/dist/es5/i3s-converter/helpers/feature-attributes.js.map +1 -1
- package/dist/es5/i3s-converter/helpers/geometry-converter.js +61 -10
- package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
- package/dist/es5/i3s-converter/helpers/load-3d-tiles.js +70 -4
- package/dist/es5/i3s-converter/helpers/load-3d-tiles.js.map +1 -1
- package/dist/es5/i3s-converter/helpers/node-index-document.js +3 -2
- package/dist/es5/i3s-converter/helpers/node-index-document.js.map +1 -1
- package/dist/es5/i3s-converter/helpers/preprocess-3d-tiles.js +1 -2
- package/dist/es5/i3s-converter/helpers/preprocess-3d-tiles.js.map +1 -1
- package/dist/es5/i3s-converter/i3s-converter.js +70 -58
- package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
- package/dist/es5/i3s-server/controllers/slpk-controller.js +2 -2
- package/dist/es5/i3s-server/controllers/slpk-controller.js.map +1 -1
- package/dist/es5/pgm-loader.js +1 -1
- package/dist/es5/slpk-extractor/slpk-extractor.js +1 -1
- package/dist/es5/slpk-extractor/slpk-extractor.js.map +1 -1
- package/dist/esm/constants.js +0 -2
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/deps-installer/deps-installer.js +1 -1
- package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js +21 -6
- package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
- package/dist/esm/i3s-converter/helpers/feature-attributes.js +6 -4
- package/dist/esm/i3s-converter/helpers/feature-attributes.js.map +1 -1
- package/dist/esm/i3s-converter/helpers/geometry-converter.js +59 -8
- package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
- package/dist/esm/i3s-converter/helpers/load-3d-tiles.js +33 -4
- package/dist/esm/i3s-converter/helpers/load-3d-tiles.js.map +1 -1
- package/dist/esm/i3s-converter/helpers/node-index-document.js +2 -1
- package/dist/esm/i3s-converter/helpers/node-index-document.js.map +1 -1
- package/dist/esm/i3s-converter/helpers/preprocess-3d-tiles.js +1 -1
- package/dist/esm/i3s-converter/helpers/preprocess-3d-tiles.js.map +1 -1
- package/dist/esm/i3s-converter/i3s-converter.js +27 -22
- package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
- package/dist/esm/i3s-server/bin/i3s-server.min.js +71 -71
- package/dist/esm/i3s-server/controllers/slpk-controller.js +1 -1
- package/dist/esm/i3s-server/controllers/slpk-controller.js.map +1 -1
- package/dist/esm/pgm-loader.js +1 -1
- package/dist/esm/slpk-extractor/slpk-extractor.js +2 -1
- package/dist/esm/slpk-extractor/slpk-extractor.js.map +1 -1
- package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/batch-ids-extensions.js +37 -16
- package/dist/i3s-converter/helpers/feature-attributes.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/feature-attributes.js +6 -4
- package/dist/i3s-converter/helpers/geometry-converter.d.ts +2 -2
- package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/geometry-converter.js +93 -12
- package/dist/i3s-converter/helpers/load-3d-tiles.d.ts +15 -0
- package/dist/i3s-converter/helpers/load-3d-tiles.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/load-3d-tiles.js +51 -5
- package/dist/i3s-converter/helpers/node-index-document.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/node-index-document.js +4 -1
- package/dist/i3s-converter/helpers/preprocess-3d-tiles.js +2 -2
- package/dist/i3s-converter/i3s-converter.d.ts +1 -1
- package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
- package/dist/i3s-converter/i3s-converter.js +38 -17
- package/dist/i3s-server/controllers/slpk-controller.js +2 -2
- package/dist/slpk-extractor/slpk-extractor.d.ts.map +1 -1
- package/dist/slpk-extractor/slpk-extractor.js +2 -1
- package/dist/slpk-extractor.min.js +38 -38
- package/package.json +14 -14
- package/src/constants.ts +0 -3
- package/src/i3s-converter/helpers/batch-ids-extensions.ts +53 -14
- package/src/i3s-converter/helpers/feature-attributes.ts +8 -6
- package/src/i3s-converter/helpers/geometry-converter.ts +135 -12
- package/src/i3s-converter/helpers/load-3d-tiles.ts +61 -5
- package/src/i3s-converter/helpers/node-index-document.ts +5 -1
- package/src/i3s-converter/helpers/preprocess-3d-tiles.ts +1 -1
- package/src/i3s-converter/i3s-converter.ts +54 -22
- package/src/i3s-server/controllers/slpk-controller.ts +1 -1
- package/src/slpk-extractor/slpk-extractor.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loaders.gl/tile-converter",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
3
|
+
"version": "4.0.0-alpha.23",
|
|
4
4
|
"description": "Converter",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -45,18 +45,18 @@
|
|
|
45
45
|
"build-i3s-server-bundle": "esbuild src/i3s-server/bin/www.ts --outfile=dist/esm/i3s-server/bin/i3s-server.min.js --platform=node --target=esnext,node14 --external:join-images --minify --bundle --define:__VERSION__=\\\"$npm_package_version\\\""
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@loaders.gl/3d-tiles": "4.0.0-alpha.
|
|
49
|
-
"@loaders.gl/crypto": "4.0.0-alpha.
|
|
50
|
-
"@loaders.gl/draco": "4.0.0-alpha.
|
|
51
|
-
"@loaders.gl/gltf": "4.0.0-alpha.
|
|
52
|
-
"@loaders.gl/i3s": "4.0.0-alpha.
|
|
53
|
-
"@loaders.gl/images": "4.0.0-alpha.
|
|
54
|
-
"@loaders.gl/loader-utils": "4.0.0-alpha.
|
|
55
|
-
"@loaders.gl/polyfills": "4.0.0-alpha.
|
|
56
|
-
"@loaders.gl/textures": "4.0.0-alpha.
|
|
57
|
-
"@loaders.gl/tiles": "4.0.0-alpha.
|
|
58
|
-
"@loaders.gl/worker-utils": "4.0.0-alpha.
|
|
59
|
-
"@loaders.gl/zip": "4.0.0-alpha.
|
|
48
|
+
"@loaders.gl/3d-tiles": "4.0.0-alpha.23",
|
|
49
|
+
"@loaders.gl/crypto": "4.0.0-alpha.23",
|
|
50
|
+
"@loaders.gl/draco": "4.0.0-alpha.23",
|
|
51
|
+
"@loaders.gl/gltf": "4.0.0-alpha.23",
|
|
52
|
+
"@loaders.gl/i3s": "4.0.0-alpha.23",
|
|
53
|
+
"@loaders.gl/images": "4.0.0-alpha.23",
|
|
54
|
+
"@loaders.gl/loader-utils": "4.0.0-alpha.23",
|
|
55
|
+
"@loaders.gl/polyfills": "4.0.0-alpha.23",
|
|
56
|
+
"@loaders.gl/textures": "4.0.0-alpha.23",
|
|
57
|
+
"@loaders.gl/tiles": "4.0.0-alpha.23",
|
|
58
|
+
"@loaders.gl/worker-utils": "4.0.0-alpha.23",
|
|
59
|
+
"@loaders.gl/zip": "4.0.0-alpha.23",
|
|
60
60
|
"@math.gl/core": "^3.5.1",
|
|
61
61
|
"@math.gl/culling": "^3.5.1",
|
|
62
62
|
"@math.gl/geoid": "^3.5.1",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"join-images": "^1.1.3",
|
|
81
81
|
"sharp": "^0.31.3"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "e212f2a0c0e342f7cb65ce84fa2ff39f64b7d94b",
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@types/express": "^4.17.17",
|
|
86
86
|
"@types/node": "^20.4.2"
|
package/src/constants.ts
CHANGED
|
@@ -3,11 +3,16 @@ import type {NumericArray} from '@loaders.gl/loader-utils';
|
|
|
3
3
|
import type {
|
|
4
4
|
GLTF_EXT_feature_metadata_FeatureIdTexture,
|
|
5
5
|
GLTF_EXT_feature_metadata_GLTF,
|
|
6
|
-
GLTF_EXT_feature_metadata_Primitive
|
|
6
|
+
GLTF_EXT_feature_metadata_Primitive,
|
|
7
|
+
GLTF_EXT_structural_metadata
|
|
7
8
|
} from '@loaders.gl/gltf';
|
|
9
|
+
|
|
10
|
+
import type {GLTF_EXT_mesh_features} from '@loaders.gl/gltf';
|
|
11
|
+
|
|
8
12
|
import {TypedArray} from '@math.gl/core';
|
|
9
13
|
import {TextureImageProperties} from '../types';
|
|
10
|
-
import {
|
|
14
|
+
import {emod} from '@loaders.gl/math';
|
|
15
|
+
import {EXT_STRUCTURAL_METADATA, EXT_MESH_FEATURES, EXT_FEATURE_METADATA} from '@loaders.gl/gltf';
|
|
11
16
|
import {Tiles3DTileContent} from '@loaders.gl/3d-tiles';
|
|
12
17
|
|
|
13
18
|
/**
|
|
@@ -52,7 +57,6 @@ export function handleBatchIdsExtensions(
|
|
|
52
57
|
featureTexture: string | null
|
|
53
58
|
): NumericArray {
|
|
54
59
|
const extensions = primitive?.extensions;
|
|
55
|
-
|
|
56
60
|
if (!extensions) {
|
|
57
61
|
return [];
|
|
58
62
|
}
|
|
@@ -67,8 +71,13 @@ export function handleBatchIdsExtensions(
|
|
|
67
71
|
featureTexture
|
|
68
72
|
);
|
|
69
73
|
case EXT_MESH_FEATURES:
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
return handleExtMeshFeaturesExtension(attributes, extensionData as GLTF_EXT_mesh_features);
|
|
75
|
+
case EXT_STRUCTURAL_METADATA:
|
|
76
|
+
return handleExtStructuralMetadataExtension(
|
|
77
|
+
attributes,
|
|
78
|
+
extensionData as GLTF_EXT_structural_metadata
|
|
79
|
+
);
|
|
80
|
+
|
|
72
81
|
default:
|
|
73
82
|
return [];
|
|
74
83
|
}
|
|
@@ -77,6 +86,45 @@ export function handleBatchIdsExtensions(
|
|
|
77
86
|
return [];
|
|
78
87
|
}
|
|
79
88
|
|
|
89
|
+
function handleExtStructuralMetadataExtension(
|
|
90
|
+
attributes: {
|
|
91
|
+
[key: string]: GLTFAccessorPostprocessed;
|
|
92
|
+
},
|
|
93
|
+
extStructuralMetadata: GLTF_EXT_structural_metadata
|
|
94
|
+
): NumericArray {
|
|
95
|
+
// Take only first extension object to get batchIds attribute name.
|
|
96
|
+
const dataAttributeNames = extStructuralMetadata?.dataAttributeNames;
|
|
97
|
+
if (dataAttributeNames?.length) {
|
|
98
|
+
// Let's use the first element of the array
|
|
99
|
+
// TODO: What to do with others if any?
|
|
100
|
+
const batchIdsAttribute = attributes[dataAttributeNames[0]];
|
|
101
|
+
return batchIdsAttribute.value;
|
|
102
|
+
}
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Getting batchIds from EXT_mesh_features extensions.
|
|
108
|
+
* @param attributes - gltf accessors
|
|
109
|
+
* @param extMeshFeatures - EXT_mesh_features extension
|
|
110
|
+
* @returns an array of attribute values
|
|
111
|
+
*/
|
|
112
|
+
function handleExtMeshFeaturesExtension(
|
|
113
|
+
attributes: {
|
|
114
|
+
[key: string]: GLTFAccessorPostprocessed;
|
|
115
|
+
},
|
|
116
|
+
extMeshFeatures: GLTF_EXT_mesh_features
|
|
117
|
+
): NumericArray {
|
|
118
|
+
const dataAttributeNames = extMeshFeatures?.dataAttributeNames;
|
|
119
|
+
if (dataAttributeNames?.length) {
|
|
120
|
+
// Let's use the first element of the array
|
|
121
|
+
// TODO: What to do with others if any?
|
|
122
|
+
const batchIdsAttribute = attributes[dataAttributeNames[0]];
|
|
123
|
+
return batchIdsAttribute.value;
|
|
124
|
+
}
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
|
|
80
128
|
/**
|
|
81
129
|
* Get batchIds from EXT_feature_metadata extension.
|
|
82
130
|
* Docs - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata
|
|
@@ -218,12 +266,3 @@ function generateBatchIdsFromTexture(
|
|
|
218
266
|
|
|
219
267
|
return batchIds;
|
|
220
268
|
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Handle UVs if they are out of range [0,1].
|
|
224
|
-
* @param n
|
|
225
|
-
* @param m
|
|
226
|
-
*/
|
|
227
|
-
function emod(n: number): number {
|
|
228
|
-
return ((n % 1) + 1) % 1;
|
|
229
|
-
}
|
|
@@ -39,12 +39,14 @@ export function flattenPropertyTableByFeatureIds(
|
|
|
39
39
|
* @param properties
|
|
40
40
|
* @param featureIds
|
|
41
41
|
*/
|
|
42
|
-
function getPropertiesByFeatureIds(properties:
|
|
43
|
-
const resultProperties:
|
|
42
|
+
function getPropertiesByFeatureIds(properties: unknown[], featureIds: number[]): unknown[] {
|
|
43
|
+
const resultProperties: unknown[] = [];
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
45
|
+
if (properties) {
|
|
46
|
+
for (const featureId of featureIds) {
|
|
47
|
+
const property = properties[featureId] || null;
|
|
48
|
+
resultProperties.push(property);
|
|
49
|
+
}
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
return resultProperties;
|
|
@@ -64,7 +66,7 @@ export function checkPropertiesLength(
|
|
|
64
66
|
let needFlatten = false;
|
|
65
67
|
|
|
66
68
|
for (const attribute of Object.values(propertyTable)) {
|
|
67
|
-
if (featureIds.length !== attribute.length) {
|
|
69
|
+
if (!featureIds || !attribute || featureIds.length !== attribute.length) {
|
|
68
70
|
needFlatten = true;
|
|
69
71
|
}
|
|
70
72
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type {FeatureTableJson, Tiles3DTileContent} from '@loaders.gl/3d-tiles';
|
|
2
2
|
import type {
|
|
3
|
+
GLTF_EXT_mesh_features,
|
|
4
|
+
GLTF_EXT_structural_metadata,
|
|
3
5
|
GLTFAccessorPostprocessed,
|
|
4
6
|
GLTFMaterialPostprocessed,
|
|
5
7
|
GLTFNodePostprocessed,
|
|
@@ -47,7 +49,8 @@ import {GL} from '@loaders.gl/math';
|
|
|
47
49
|
import type {GLTFAttributesData, TextureImageProperties, TypedArrayConstructor} from '../types';
|
|
48
50
|
import {generateSyntheticIndices} from '../../lib/utils/geometry-utils';
|
|
49
51
|
import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
|
|
50
|
-
|
|
52
|
+
|
|
53
|
+
import {EXT_MESH_FEATURES, EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA} from '@loaders.gl/gltf';
|
|
51
54
|
|
|
52
55
|
// Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md
|
|
53
56
|
const DEFAULT_ROUGHNESS_FACTOR = 1;
|
|
@@ -1358,10 +1361,12 @@ function convertPropertyTableToAttributeBuffers(
|
|
|
1358
1361
|
|
|
1359
1362
|
for (const propertyName in propertyTableWithObjectIds) {
|
|
1360
1363
|
const type = getAttributeType(propertyName, attributeStorageInfo);
|
|
1361
|
-
|
|
1362
|
-
|
|
1364
|
+
if (type) {
|
|
1365
|
+
const value = propertyTableWithObjectIds[propertyName];
|
|
1366
|
+
const attributeBuffer = generateAttributeBuffer(type, value);
|
|
1363
1367
|
|
|
1364
|
-
|
|
1368
|
+
attributeBuffers.push(attributeBuffer);
|
|
1369
|
+
}
|
|
1365
1370
|
}
|
|
1366
1371
|
|
|
1367
1372
|
return attributeBuffers;
|
|
@@ -1401,6 +1406,20 @@ function generateAttributeBuffer(type: string, value: any): ArrayBuffer {
|
|
|
1401
1406
|
*/
|
|
1402
1407
|
function getAttributeType(key: string, attributeStorageInfo: any[]): string {
|
|
1403
1408
|
const attribute = attributeStorageInfo.find((attr) => attr.name === key);
|
|
1409
|
+
if (!attribute) {
|
|
1410
|
+
console.error(
|
|
1411
|
+
`attribute is null, key=${key}, attributeStorageInfo=${JSON.stringify(
|
|
1412
|
+
attributeStorageInfo,
|
|
1413
|
+
null,
|
|
1414
|
+
2
|
|
1415
|
+
)}`
|
|
1416
|
+
);
|
|
1417
|
+
return '';
|
|
1418
|
+
}
|
|
1419
|
+
if (!attribute.attributeValues) {
|
|
1420
|
+
console.error(`attributeValues is null, attribute=${attribute}`);
|
|
1421
|
+
return '';
|
|
1422
|
+
}
|
|
1404
1423
|
return attribute.attributeValues.valueType;
|
|
1405
1424
|
}
|
|
1406
1425
|
|
|
@@ -1577,8 +1596,8 @@ function generateFeatureIndexAttribute(
|
|
|
1577
1596
|
* Find property table in tile
|
|
1578
1597
|
* For example it can be batchTable for b3dm files or property table in gLTF extension.
|
|
1579
1598
|
* @param tileContent - 3DTiles tile content
|
|
1580
|
-
* @param metadataClass -
|
|
1581
|
-
* @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA
|
|
1599
|
+
* @param metadataClass - user selected feature metadata class name
|
|
1600
|
+
* @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA, EXT_MESH_FEATURES or EXT_STRUCTURAL_METADATA
|
|
1582
1601
|
*/
|
|
1583
1602
|
export function getPropertyTable(
|
|
1584
1603
|
tileContent: Tiles3DTileContent | null,
|
|
@@ -1587,7 +1606,7 @@ export function getPropertyTable(
|
|
|
1587
1606
|
if (!tileContent) {
|
|
1588
1607
|
return null;
|
|
1589
1608
|
}
|
|
1590
|
-
|
|
1609
|
+
let propertyTable: FeatureTableJson | null;
|
|
1591
1610
|
const batchTableJson = tileContent?.batchTableJson;
|
|
1592
1611
|
|
|
1593
1612
|
if (batchTableJson) {
|
|
@@ -1598,14 +1617,25 @@ export function getPropertyTable(
|
|
|
1598
1617
|
|
|
1599
1618
|
switch (extensionName) {
|
|
1600
1619
|
case EXT_MESH_FEATURES: {
|
|
1601
|
-
|
|
1602
|
-
|
|
1620
|
+
propertyTable = getPropertyTableFromExtMeshFeatures(
|
|
1621
|
+
extension as GLTF_EXT_mesh_features,
|
|
1622
|
+
metadataClass
|
|
1623
|
+
);
|
|
1624
|
+
return propertyTable;
|
|
1625
|
+
}
|
|
1626
|
+
case EXT_STRUCTURAL_METADATA: {
|
|
1627
|
+
propertyTable = getPropertyTableFromExtStructuralMetadata(
|
|
1628
|
+
extension as GLTF_EXT_structural_metadata,
|
|
1629
|
+
metadataClass
|
|
1630
|
+
);
|
|
1631
|
+
return propertyTable;
|
|
1603
1632
|
}
|
|
1604
1633
|
case EXT_FEATURE_METADATA: {
|
|
1605
|
-
|
|
1634
|
+
propertyTable = getPropertyTableFromExtFeatureMetadata(
|
|
1606
1635
|
extension as GLTF_EXT_feature_metadata_GLTF,
|
|
1607
1636
|
metadataClass
|
|
1608
1637
|
);
|
|
1638
|
+
return propertyTable;
|
|
1609
1639
|
}
|
|
1610
1640
|
default:
|
|
1611
1641
|
return null;
|
|
@@ -1618,9 +1648,18 @@ export function getPropertyTable(
|
|
|
1618
1648
|
*/
|
|
1619
1649
|
function getPropertyTableExtension(tileContent: Tiles3DTileContent): {
|
|
1620
1650
|
extensionName: null | string;
|
|
1621
|
-
extension:
|
|
1651
|
+
extension:
|
|
1652
|
+
| string
|
|
1653
|
+
| GLTF_EXT_feature_metadata_GLTF
|
|
1654
|
+
| GLTF_EXT_structural_metadata
|
|
1655
|
+
| GLTF_EXT_mesh_features
|
|
1656
|
+
| null;
|
|
1622
1657
|
} {
|
|
1623
|
-
const extensionsWithPropertyTables = [
|
|
1658
|
+
const extensionsWithPropertyTables = [
|
|
1659
|
+
EXT_FEATURE_METADATA,
|
|
1660
|
+
EXT_STRUCTURAL_METADATA,
|
|
1661
|
+
EXT_MESH_FEATURES
|
|
1662
|
+
];
|
|
1624
1663
|
const extensionsUsed = tileContent?.gltf?.extensionsUsed;
|
|
1625
1664
|
|
|
1626
1665
|
if (!extensionsUsed) {
|
|
@@ -1649,6 +1688,8 @@ function getPropertyTableExtension(tileContent: Tiles3DTileContent): {
|
|
|
1649
1688
|
/**
|
|
1650
1689
|
* Handle EXT_feature_metadata to get property table
|
|
1651
1690
|
* @param extension - global level of EXT_FEATURE_METADATA extension
|
|
1691
|
+
* @param metadataClass - user selected feature metadata class name
|
|
1692
|
+
* @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
|
|
1652
1693
|
*/
|
|
1653
1694
|
function getPropertyTableFromExtFeatureMetadata(
|
|
1654
1695
|
extension: GLTF_EXT_feature_metadata_GLTF,
|
|
@@ -1701,3 +1742,85 @@ function getPropertyTableFromExtFeatureMetadata(
|
|
|
1701
1742
|
);
|
|
1702
1743
|
return null;
|
|
1703
1744
|
}
|
|
1745
|
+
|
|
1746
|
+
/**
|
|
1747
|
+
* Handle EXT_structural_metadata to get property table
|
|
1748
|
+
* @param extension - global level of EXT_STRUCTURAL_METADATA extension
|
|
1749
|
+
* @param metadataClass - user selected feature metadata class name
|
|
1750
|
+
* @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
|
|
1751
|
+
*/
|
|
1752
|
+
function getPropertyTableFromExtStructuralMetadata(
|
|
1753
|
+
extension: GLTF_EXT_structural_metadata,
|
|
1754
|
+
metadataClass?: string
|
|
1755
|
+
): FeatureTableJson | null {
|
|
1756
|
+
if (extension?.propertyTables) {
|
|
1757
|
+
/**
|
|
1758
|
+
* Take only first feature table to generate attributes storage info object.
|
|
1759
|
+
* TODO: Think about getting data from all feature tables?
|
|
1760
|
+
* It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables.
|
|
1761
|
+
* In I3S we should decide which featureIds attribute will be passed to geometry data.
|
|
1762
|
+
*/
|
|
1763
|
+
const firstPropertyTable = extension?.propertyTables[0];
|
|
1764
|
+
const propertyTableWithData = {};
|
|
1765
|
+
|
|
1766
|
+
for (const propertyName in firstPropertyTable.properties) {
|
|
1767
|
+
propertyTableWithData[propertyName] = firstPropertyTable.properties[propertyName].data;
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
return propertyTableWithData;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
if (extension?.propertyTextures) {
|
|
1774
|
+
/**
|
|
1775
|
+
* Take only first feature table to generate attributes storage info object.
|
|
1776
|
+
* TODO: Think about getting data from all feature tables?
|
|
1777
|
+
* It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables.
|
|
1778
|
+
* In I3S we should decide which featureIds attribute will be passed to geometry data.
|
|
1779
|
+
*/
|
|
1780
|
+
if (extension?.propertyTextures) {
|
|
1781
|
+
const firstPropertyTexture = extension?.propertyTextures[0];
|
|
1782
|
+
const propertyTableWithData = {};
|
|
1783
|
+
|
|
1784
|
+
for (const propertyName in firstPropertyTexture.properties) {
|
|
1785
|
+
propertyTableWithData[propertyName] = firstPropertyTexture.properties[propertyName].data;
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
return propertyTableWithData;
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
console.warn(
|
|
1793
|
+
"The I3S converter couldn't handle EXT_structural_metadata extension: There is neither propertyTables, no propertyTextures in the extension."
|
|
1794
|
+
);
|
|
1795
|
+
return null;
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
/**
|
|
1799
|
+
* Handle EXT_mesh_features to get property table
|
|
1800
|
+
* @param extension - global level of EXT_MESH_FEATURES extension
|
|
1801
|
+
* @param metadataClass - user selected feature metadata class name
|
|
1802
|
+
* @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
|
|
1803
|
+
*/
|
|
1804
|
+
function getPropertyTableFromExtMeshFeatures(
|
|
1805
|
+
extension: GLTF_EXT_mesh_features,
|
|
1806
|
+
metadataClass?: string
|
|
1807
|
+
): FeatureTableJson | null {
|
|
1808
|
+
if (extension?.featureIds) {
|
|
1809
|
+
const firstFeatureId = extension?.featureIds[0];
|
|
1810
|
+
const propertyTableWithData = {};
|
|
1811
|
+
|
|
1812
|
+
// When firstFeatureId.propertyTable is defined, the property data will be taken from EXT_structural_metadata extension
|
|
1813
|
+
if (!firstFeatureId.propertyTable) {
|
|
1814
|
+
console.warn(
|
|
1815
|
+
'Should be implemented as we have the tileset with Ext_mesh_features not linked with EXT_structural_metadata extension'
|
|
1816
|
+
);
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
return propertyTableWithData;
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
console.warn(
|
|
1823
|
+
"The I3S converter couldn't handle EXT_mesh_features extension: There is no featureIds in the extension."
|
|
1824
|
+
);
|
|
1825
|
+
return null;
|
|
1826
|
+
}
|
|
@@ -4,7 +4,8 @@ import type {
|
|
|
4
4
|
Tiles3DTileJSONPostprocessed,
|
|
5
5
|
Tiles3DTilesetJSONPostprocessed
|
|
6
6
|
} from '@loaders.gl/3d-tiles';
|
|
7
|
-
import {
|
|
7
|
+
import {Tiles3DArchiveFileSystem} from '@loaders.gl/3d-tiles';
|
|
8
|
+
import {LoaderWithParser, load} from '@loaders.gl/core';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Load nested 3DTiles tileset. If the sourceTile is not nested tileset - do nothing
|
|
@@ -18,7 +19,7 @@ export const loadNestedTileset = async (
|
|
|
18
19
|
sourceTile: Tiles3DTileJSONPostprocessed,
|
|
19
20
|
tilesetLoadOptions: Tiles3DLoaderOptions
|
|
20
21
|
): Promise<void> => {
|
|
21
|
-
const isTileset = sourceTile
|
|
22
|
+
const isTileset = isNestedTileset(sourceTile);
|
|
22
23
|
if (!sourceTileset || !sourceTile.contentUrl || !isTileset) {
|
|
23
24
|
return;
|
|
24
25
|
}
|
|
@@ -30,7 +31,11 @@ export const loadNestedTileset = async (
|
|
|
30
31
|
assetGltfUpAxis: (sourceTileset.asset && sourceTileset.asset.gltfUpAxis) || 'Y'
|
|
31
32
|
}
|
|
32
33
|
};
|
|
33
|
-
const tileContent = await
|
|
34
|
+
const tileContent = await loadFromArchive(
|
|
35
|
+
sourceTile.contentUrl,
|
|
36
|
+
sourceTileset.loader,
|
|
37
|
+
loadOptions
|
|
38
|
+
);
|
|
34
39
|
|
|
35
40
|
if (tileContent.root) {
|
|
36
41
|
sourceTile.children = [tileContent.root];
|
|
@@ -49,7 +54,7 @@ export const loadTile3DContent = async (
|
|
|
49
54
|
sourceTile: Tiles3DTileJSONPostprocessed,
|
|
50
55
|
tilesetLoadOptions: Tiles3DLoaderOptions
|
|
51
56
|
): Promise<Tiles3DTileContent | null> => {
|
|
52
|
-
const isTileset = sourceTile
|
|
57
|
+
const isTileset = isNestedTileset(sourceTile);
|
|
53
58
|
if (!sourceTileset || !sourceTile.contentUrl || isTileset) {
|
|
54
59
|
return null;
|
|
55
60
|
}
|
|
@@ -62,7 +67,58 @@ export const loadTile3DContent = async (
|
|
|
62
67
|
assetGltfUpAxis: (sourceTileset.asset && sourceTileset.asset.gltfUpAxis) || 'Y'
|
|
63
68
|
}
|
|
64
69
|
};
|
|
65
|
-
const tileContent = await
|
|
70
|
+
const tileContent = await loadFromArchive(
|
|
71
|
+
sourceTile.contentUrl,
|
|
72
|
+
sourceTileset.loader,
|
|
73
|
+
loadOptions
|
|
74
|
+
);
|
|
66
75
|
|
|
67
76
|
return tileContent;
|
|
68
77
|
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Load a resource with load options and .3tz format support
|
|
81
|
+
* @param url - resource URL
|
|
82
|
+
* @param loader - loader to parse data (Tiles3DLoader / CesiumIonLoader)
|
|
83
|
+
* @param loadOptions - 3d-tiles loader options
|
|
84
|
+
* @returns 3d-tiles resource
|
|
85
|
+
*/
|
|
86
|
+
export async function loadFromArchive(
|
|
87
|
+
url: string,
|
|
88
|
+
loader: LoaderWithParser,
|
|
89
|
+
loadOptions: Tiles3DLoaderOptions
|
|
90
|
+
) {
|
|
91
|
+
const tz3UrlParts = url.split('.3tz');
|
|
92
|
+
let filename: string | null;
|
|
93
|
+
// No '.3tz'. The file will be loaded with global fetch function
|
|
94
|
+
if (tz3UrlParts.length === 1) {
|
|
95
|
+
filename = null;
|
|
96
|
+
} else if (tz3UrlParts.length === 2) {
|
|
97
|
+
filename = tz3UrlParts[1].slice(1);
|
|
98
|
+
if (filename === '') {
|
|
99
|
+
filename = 'tileset.json';
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
throw new Error('Unexpected URL format');
|
|
103
|
+
}
|
|
104
|
+
if (filename) {
|
|
105
|
+
const tz3Path = `${tz3UrlParts[0]}.3tz`;
|
|
106
|
+
const fileSystem = new Tiles3DArchiveFileSystem(tz3Path);
|
|
107
|
+
const content = await load(filename, loader, {
|
|
108
|
+
...loadOptions,
|
|
109
|
+
fetch: fileSystem.fetch.bind(fileSystem)
|
|
110
|
+
});
|
|
111
|
+
await fileSystem.destroy();
|
|
112
|
+
return content;
|
|
113
|
+
}
|
|
114
|
+
return await load(url, loader, loadOptions);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check if tile is nested tileset
|
|
119
|
+
* @param tile - 3DTiles header data
|
|
120
|
+
* @returns true if tile is nested tileset
|
|
121
|
+
*/
|
|
122
|
+
export function isNestedTileset(tile: Tiles3DTileJSONPostprocessed) {
|
|
123
|
+
return tile?.type === 'json' || tile?.type === '3tz';
|
|
124
|
+
}
|
|
@@ -323,7 +323,11 @@ export class NodeIndexDocument {
|
|
|
323
323
|
parentNode.converter.layers0?.attributeStorageInfo?.length
|
|
324
324
|
) {
|
|
325
325
|
node.attributeData = [];
|
|
326
|
-
|
|
326
|
+
const minimumLength =
|
|
327
|
+
attributes.length < parentNode.converter.layers0.attributeStorageInfo.length
|
|
328
|
+
? attributes.length
|
|
329
|
+
: parentNode.converter.layers0.attributeStorageInfo.length;
|
|
330
|
+
for (let index = 0; index < minimumLength; index++) {
|
|
327
331
|
const folderName = parentNode.converter.layers0.attributeStorageInfo[index].key;
|
|
328
332
|
node.attributeData.push({href: `./attributes/${folderName}/0`});
|
|
329
333
|
}
|
|
@@ -2,7 +2,7 @@ import {Tiles3DTileContent} from '@loaders.gl/3d-tiles';
|
|
|
2
2
|
import {GLTFPrimitiveModeString, PreprocessData} from '../types';
|
|
3
3
|
import {GLTF, GLTFLoader, GLTF_EXT_feature_metadata_GLTF} from '@loaders.gl/gltf';
|
|
4
4
|
import {parse} from '@loaders.gl/core';
|
|
5
|
-
import {EXT_FEATURE_METADATA} from '
|
|
5
|
+
import {EXT_FEATURE_METADATA} from '@loaders.gl/gltf';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* glTF primitive modes
|
|
@@ -12,7 +12,8 @@ import type {
|
|
|
12
12
|
SceneLayer3D,
|
|
13
13
|
BoundingVolumes,
|
|
14
14
|
MaxScreenThresholdSQ,
|
|
15
|
-
NodeInPage
|
|
15
|
+
NodeInPage,
|
|
16
|
+
AttributeStorageInfo
|
|
16
17
|
} from '@loaders.gl/i3s';
|
|
17
18
|
import {load, encode, isBrowser} from '@loaders.gl/core';
|
|
18
19
|
import {CesiumIonLoader, Tiles3DLoader} from '@loaders.gl/3d-tiles';
|
|
@@ -67,7 +68,12 @@ import {
|
|
|
67
68
|
getFieldAttributeType
|
|
68
69
|
} from './helpers/feature-attributes';
|
|
69
70
|
import {NodeIndexDocument} from './helpers/node-index-document';
|
|
70
|
-
import {
|
|
71
|
+
import {
|
|
72
|
+
isNestedTileset,
|
|
73
|
+
loadNestedTileset,
|
|
74
|
+
loadTile3DContent,
|
|
75
|
+
loadFromArchive
|
|
76
|
+
} from './helpers/load-3d-tiles';
|
|
71
77
|
import {Matrix4} from '@math.gl/core';
|
|
72
78
|
import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
|
|
73
79
|
import {createBoundingVolume} from '@loaders.gl/tiles';
|
|
@@ -251,7 +257,7 @@ export default class I3SConverter {
|
|
|
251
257
|
if (preloadOptions.headers) {
|
|
252
258
|
this.loadOptions.fetch = {headers: preloadOptions.headers};
|
|
253
259
|
}
|
|
254
|
-
this.sourceTileset = await
|
|
260
|
+
this.sourceTileset = await loadFromArchive(tilesetUrl, this.Loader, this.loadOptions);
|
|
255
261
|
|
|
256
262
|
const preprocessResult = await this.preprocessConversion();
|
|
257
263
|
|
|
@@ -349,7 +355,8 @@ export default class I3SConverter {
|
|
|
349
355
|
sourceTile: Tiles3DTileJSONPostprocessed,
|
|
350
356
|
traversalProps: null
|
|
351
357
|
): Promise<null> {
|
|
352
|
-
|
|
358
|
+
const isTileset = isNestedTileset(sourceTile);
|
|
359
|
+
if (isTileset) {
|
|
353
360
|
await loadNestedTileset(this.sourceTileset, sourceTile, this.loadOptions);
|
|
354
361
|
return null;
|
|
355
362
|
}
|
|
@@ -562,8 +569,9 @@ export default class I3SConverter {
|
|
|
562
569
|
sourceTile: Tiles3DTileJSONPostprocessed,
|
|
563
570
|
traversalProps: TraversalConversionProps
|
|
564
571
|
): Promise<TraversalConversionProps> {
|
|
565
|
-
|
|
566
|
-
|
|
572
|
+
const isTileset = isNestedTileset(sourceTile);
|
|
573
|
+
if (isTileset || sourceTile.type === 'empty') {
|
|
574
|
+
if (isTileset) {
|
|
567
575
|
if (sourceTile.id) {
|
|
568
576
|
console.log(`[load]: ${sourceTile.id}`); // eslint-disable-line
|
|
569
577
|
}
|
|
@@ -642,7 +650,14 @@ export default class I3SConverter {
|
|
|
642
650
|
|
|
643
651
|
const propertyTable = getPropertyTable(tileContent, this.options.metadataClass);
|
|
644
652
|
|
|
645
|
-
if (propertyTable
|
|
653
|
+
if (propertyTable) {
|
|
654
|
+
/*
|
|
655
|
+
Call the convertion procedure even if the node attributes have been already created.
|
|
656
|
+
We will append new attributes only in case the property table is updated.
|
|
657
|
+
According to ver 1.9 (see https://github.com/Esri/i3s-spec/blob/master/docs/1.9/attributeStorageInfo.cmn.md):
|
|
658
|
+
"The attributeStorageInfo object describes the structure of the binary attribute data resource of a layer, which is the same for every node in the layer."
|
|
659
|
+
But the specification of ver 2.1 doesn't have such a requirement ("...the same for every node...")
|
|
660
|
+
*/
|
|
646
661
|
this._convertPropertyTableToNodeAttributes(propertyTable);
|
|
647
662
|
}
|
|
648
663
|
|
|
@@ -728,7 +743,7 @@ export default class I3SConverter {
|
|
|
728
743
|
* @param boundingVolume - initialized bounding volume of the source tile
|
|
729
744
|
* @param tileContent - content of the source tile
|
|
730
745
|
* @param parentId - id of parent node in node pages
|
|
731
|
-
* @param propertyTable - batch table from b3dm / feature properties from EXT_FEATURE_METADATA
|
|
746
|
+
* @param propertyTable - batch table from b3dm / feature properties from EXT_FEATURE_METADATA, EXT_MESH_FEATURES or EXT_STRUCTURAL_METADATA
|
|
732
747
|
* @returns - converted node resources
|
|
733
748
|
*/
|
|
734
749
|
private async _convertResources(
|
|
@@ -1061,7 +1076,12 @@ export default class I3SConverter {
|
|
|
1061
1076
|
slpkChildPath: string
|
|
1062
1077
|
): Promise<void> {
|
|
1063
1078
|
if (attributes?.length && this.layers0?.attributeStorageInfo?.length) {
|
|
1064
|
-
|
|
1079
|
+
const minimumLength =
|
|
1080
|
+
attributes.length < this.layers0.attributeStorageInfo.length
|
|
1081
|
+
? attributes.length
|
|
1082
|
+
: this.layers0.attributeStorageInfo.length;
|
|
1083
|
+
|
|
1084
|
+
for (let index = 0; index < minimumLength; index++) {
|
|
1065
1085
|
const folderName = this.layers0.attributeStorageInfo[index].key;
|
|
1066
1086
|
const fileBuffer = new Uint8Array(attributes[index]);
|
|
1067
1087
|
|
|
@@ -1143,19 +1163,31 @@ export default class I3SConverter {
|
|
|
1143
1163
|
};
|
|
1144
1164
|
|
|
1145
1165
|
for (const key in propertyTableWithObjectId) {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
const
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1166
|
+
/*
|
|
1167
|
+
We will append new attributes only in case the property table is updated.
|
|
1168
|
+
According to ver 1.9 (see https://github.com/Esri/i3s-spec/blob/master/docs/1.9/attributeStorageInfo.cmn.md):
|
|
1169
|
+
"The attributeStorageInfo object describes the structure of the binary attribute data resource of a layer, which is the same for every node in the layer."
|
|
1170
|
+
But the specification of ver 2.1 doesn't have such a requirement ("...the same for every node...")
|
|
1171
|
+
*/
|
|
1172
|
+
const found = this.layers0!.attributeStorageInfo!.find((element) => element.name === key);
|
|
1173
|
+
if (!found) {
|
|
1174
|
+
const firstAttribute = propertyTableWithObjectId[key][0];
|
|
1175
|
+
const attributeType = getAttributeType(key, firstAttribute);
|
|
1176
|
+
|
|
1177
|
+
const storageAttribute: AttributeStorageInfo = createdStorageAttribute(
|
|
1178
|
+
attributeIndex,
|
|
1179
|
+
key,
|
|
1180
|
+
attributeType
|
|
1181
|
+
);
|
|
1182
|
+
const fieldAttributeType = getFieldAttributeType(attributeType);
|
|
1183
|
+
const fieldAttribute = createFieldAttribute(key, fieldAttributeType);
|
|
1184
|
+
const popupInfo = createPopupInfo(propertyTableWithObjectId);
|
|
1185
|
+
|
|
1186
|
+
this.layers0!.attributeStorageInfo!.push(storageAttribute);
|
|
1187
|
+
this.layers0!.fields!.push(fieldAttribute);
|
|
1188
|
+
this.layers0!.popupInfo = popupInfo;
|
|
1189
|
+
this.layers0!.layerType = _3D_OBJECT_LAYER_TYPE;
|
|
1190
|
+
}
|
|
1159
1191
|
attributeIndex += 1;
|
|
1160
1192
|
}
|
|
1161
1193
|
}
|