@loaders.gl/tile-converter 4.0.0-alpha.22 → 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 +106 -106
- package/dist/dist.min.js +1744 -1157
- 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/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 +36 -26
- 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/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 +20 -17
- 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/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 +32 -13
- 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/node-index-document.ts +5 -1
- package/src/i3s-converter/helpers/preprocess-3d-tiles.ts +1 -1
- package/src/i3s-converter/i3s-converter.ts +42 -17
- 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
|
+
}
|
|
@@ -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';
|
|
@@ -649,7 +650,14 @@ export default class I3SConverter {
|
|
|
649
650
|
|
|
650
651
|
const propertyTable = getPropertyTable(tileContent, this.options.metadataClass);
|
|
651
652
|
|
|
652
|
-
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
|
+
*/
|
|
653
661
|
this._convertPropertyTableToNodeAttributes(propertyTable);
|
|
654
662
|
}
|
|
655
663
|
|
|
@@ -735,7 +743,7 @@ export default class I3SConverter {
|
|
|
735
743
|
* @param boundingVolume - initialized bounding volume of the source tile
|
|
736
744
|
* @param tileContent - content of the source tile
|
|
737
745
|
* @param parentId - id of parent node in node pages
|
|
738
|
-
* @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
|
|
739
747
|
* @returns - converted node resources
|
|
740
748
|
*/
|
|
741
749
|
private async _convertResources(
|
|
@@ -1068,7 +1076,12 @@ export default class I3SConverter {
|
|
|
1068
1076
|
slpkChildPath: string
|
|
1069
1077
|
): Promise<void> {
|
|
1070
1078
|
if (attributes?.length && this.layers0?.attributeStorageInfo?.length) {
|
|
1071
|
-
|
|
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++) {
|
|
1072
1085
|
const folderName = this.layers0.attributeStorageInfo[index].key;
|
|
1073
1086
|
const fileBuffer = new Uint8Array(attributes[index]);
|
|
1074
1087
|
|
|
@@ -1150,19 +1163,31 @@ export default class I3SConverter {
|
|
|
1150
1163
|
};
|
|
1151
1164
|
|
|
1152
1165
|
for (const key in propertyTableWithObjectId) {
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
const
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
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
|
+
}
|
|
1166
1191
|
attributeIndex += 1;
|
|
1167
1192
|
}
|
|
1168
1193
|
}
|
|
@@ -2,7 +2,8 @@ import {isBrowser} from '@loaders.gl/core';
|
|
|
2
2
|
|
|
3
3
|
import {BROWSER_ERROR_MESSAGE} from '../constants';
|
|
4
4
|
import {path} from '@loaders.gl/loader-utils';
|
|
5
|
-
import {FileHandleFile
|
|
5
|
+
import {FileHandleFile} from '@loaders.gl/loader-utils';
|
|
6
|
+
import {parseZipLocalFileHeader} from '@loaders.gl/zip';
|
|
6
7
|
import {GZipCompression} from '@loaders.gl/compression';
|
|
7
8
|
import {writeFile} from '../lib/utils/file-utils';
|
|
8
9
|
|