@loaders.gl/tile-converter 4.0.0-beta.4 → 4.0.0-beta.5
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/converter.min.cjs +93 -93
- package/dist/i3s-converter/helpers/feature-attributes.d.ts +28 -5
- package/dist/i3s-converter/helpers/feature-attributes.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/feature-attributes.js +96 -8
- package/dist/i3s-converter/helpers/feature-attributes.js.map +1 -1
- package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/geometry-converter.js +44 -1
- package/dist/i3s-converter/helpers/geometry-converter.js.map +1 -1
- package/dist/i3s-converter/helpers/load-3d-tiles.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/load-3d-tiles.js.map +1 -1
- package/dist/i3s-converter/i3s-converter.d.ts +9 -3
- package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
- package/dist/i3s-converter/i3s-converter.js +38 -18
- package/dist/i3s-converter/i3s-converter.js.map +1 -1
- package/dist/i3s-converter/types.d.ts +1 -1
- package/dist/i3s-converter/types.js.map +1 -1
- package/dist/index.cjs +204 -46
- package/package.json +14 -14
- package/src/i3s-converter/helpers/feature-attributes.ts +164 -11
- package/src/i3s-converter/helpers/geometry-converter.ts +99 -7
- package/src/i3s-converter/helpers/load-3d-tiles.ts +1 -0
- package/src/i3s-converter/i3s-converter.ts +72 -39
- package/src/i3s-converter/types.ts +1 -1
|
@@ -7,7 +7,11 @@ import type {
|
|
|
7
7
|
GLTFMeshPostprocessed,
|
|
8
8
|
GLTFTexturePostprocessed,
|
|
9
9
|
GLTF_EXT_feature_metadata_GLTF,
|
|
10
|
-
|
|
10
|
+
GLTF_EXT_feature_metadata_FeatureTable,
|
|
11
|
+
GLTF_EXT_feature_metadata_FeatureTexture,
|
|
12
|
+
GLTF_EXT_structural_metadata_GLTF,
|
|
13
|
+
GLTF_EXT_structural_metadata_PropertyTable,
|
|
14
|
+
GLTF_EXT_structural_metadata_PropertyTexture
|
|
11
15
|
} from '@loaders.gl/gltf';
|
|
12
16
|
|
|
13
17
|
import {Vector3, Matrix4, Vector4} from '@math.gl/core';
|
|
@@ -49,12 +53,7 @@ import type {GLTFAttributesData, TextureImageProperties, TypedArrayConstructor}
|
|
|
49
53
|
import {generateSyntheticIndices} from '../../lib/utils/geometry-utils';
|
|
50
54
|
import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
|
|
51
55
|
|
|
52
|
-
import {
|
|
53
|
-
EXT_FEATURE_METADATA,
|
|
54
|
-
EXT_STRUCTURAL_METADATA,
|
|
55
|
-
getPropertyTableFromExtFeatureMetadata,
|
|
56
|
-
getPropertyTableFromExtStructuralMetadata
|
|
57
|
-
} from '@loaders.gl/gltf';
|
|
56
|
+
import {EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA} from '@loaders.gl/gltf';
|
|
58
57
|
|
|
59
58
|
// Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md
|
|
60
59
|
const DEFAULT_ROUGHNESS_FACTOR = 1;
|
|
@@ -1648,6 +1647,99 @@ export function getPropertyTable(
|
|
|
1648
1647
|
}
|
|
1649
1648
|
}
|
|
1650
1649
|
|
|
1650
|
+
/**
|
|
1651
|
+
* Handles EXT_structural_metadata to get property table.
|
|
1652
|
+
* @param extension - Global level of EXT_STRUCTURAL_METADATA extension.
|
|
1653
|
+
* @param metadataClass - User selected feature metadata class name.
|
|
1654
|
+
* @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
|
|
1655
|
+
*/
|
|
1656
|
+
function getPropertyTableFromExtStructuralMetadata(
|
|
1657
|
+
extension: GLTF_EXT_structural_metadata_GLTF,
|
|
1658
|
+
metadataClass?: string
|
|
1659
|
+
): FeatureTableJson | null {
|
|
1660
|
+
/**
|
|
1661
|
+
* Note, 3dTiles is able to have multiple featureId attributes and multiple feature tables.
|
|
1662
|
+
* In I3S we should decide which featureIds attribute will be passed to geometry data.
|
|
1663
|
+
* So, we take only the feature table / feature texture to generate attributes storage info object.
|
|
1664
|
+
* If the user has selected the metadataClass, the table with the corresponding class will be used,
|
|
1665
|
+
* or just the first one otherwise.
|
|
1666
|
+
*/
|
|
1667
|
+
if (extension.propertyTables) {
|
|
1668
|
+
for (const propertyTable of extension.propertyTables) {
|
|
1669
|
+
if (propertyTable.class === metadataClass || !metadataClass) {
|
|
1670
|
+
return getPropertyData(propertyTable);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
if (extension.propertyTextures) {
|
|
1676
|
+
for (const propertyTexture of extension.propertyTextures) {
|
|
1677
|
+
if (propertyTexture.class === metadataClass || !metadataClass) {
|
|
1678
|
+
return getPropertyData(propertyTexture);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
return null;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
/**
|
|
1687
|
+
* Handles EXT_feature_metadata to get property table.
|
|
1688
|
+
* @param extension - Global level of EXT_FEATURE_METADATA extension.
|
|
1689
|
+
* @param metadataClass - User selected feature metadata class name.
|
|
1690
|
+
* @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
|
|
1691
|
+
*/
|
|
1692
|
+
function getPropertyTableFromExtFeatureMetadata(
|
|
1693
|
+
extension: GLTF_EXT_feature_metadata_GLTF,
|
|
1694
|
+
metadataClass?: string
|
|
1695
|
+
): FeatureTableJson | null {
|
|
1696
|
+
/**
|
|
1697
|
+
* Note, 3dTiles is able to have multiple featureId attributes and multiple feature tables.
|
|
1698
|
+
* In I3S we should decide which featureIds attribute will be passed to geometry data.
|
|
1699
|
+
* So, we take only the feature table / feature texture to generate attributes storage info object.
|
|
1700
|
+
* If the user has selected the metadataClass, the table with the corresponding class will be used,
|
|
1701
|
+
* or just the first one otherwise.
|
|
1702
|
+
*/
|
|
1703
|
+
if (extension.featureTables) {
|
|
1704
|
+
for (const featureTableName in extension.featureTables) {
|
|
1705
|
+
const featureTable = extension.featureTables[featureTableName];
|
|
1706
|
+
if (featureTable.class === metadataClass || !metadataClass) {
|
|
1707
|
+
return getPropertyData(featureTable);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
if (extension.featureTextures) {
|
|
1713
|
+
for (const featureTextureName in extension.featureTextures) {
|
|
1714
|
+
const featureTexture = extension.featureTextures[featureTextureName];
|
|
1715
|
+
if (featureTexture.class === metadataClass || !metadataClass) {
|
|
1716
|
+
return getPropertyData(featureTexture);
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
return null;
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
/**
|
|
1725
|
+
* Gets data from Property Table or Property Texture
|
|
1726
|
+
* @param featureObject - property table or texture from the extension
|
|
1727
|
+
* @returns Table containing property data
|
|
1728
|
+
*/
|
|
1729
|
+
function getPropertyData<
|
|
1730
|
+
Type extends
|
|
1731
|
+
| GLTF_EXT_structural_metadata_PropertyTable
|
|
1732
|
+
| GLTF_EXT_structural_metadata_PropertyTexture
|
|
1733
|
+
| GLTF_EXT_feature_metadata_FeatureTable
|
|
1734
|
+
| GLTF_EXT_feature_metadata_FeatureTexture
|
|
1735
|
+
>(featureObject: Type) {
|
|
1736
|
+
const propertyTableWithData = {};
|
|
1737
|
+
for (const propertyName in featureObject.properties) {
|
|
1738
|
+
propertyTableWithData[propertyName] = featureObject.properties[propertyName].data;
|
|
1739
|
+
}
|
|
1740
|
+
return propertyTableWithData;
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1651
1743
|
/**
|
|
1652
1744
|
* Check extensions which can be with property table inside.
|
|
1653
1745
|
* @param tileContent - 3DTiles tile content
|
|
@@ -62,6 +62,7 @@ export const loadTile3DContent = async (
|
|
|
62
62
|
const loadOptions = {
|
|
63
63
|
...tilesetLoadOptions,
|
|
64
64
|
[sourceTileset.loader.id]: {
|
|
65
|
+
// @ts-ignore
|
|
65
66
|
...(tilesetLoadOptions[sourceTileset.loader.id] || {}),
|
|
66
67
|
isTileset,
|
|
67
68
|
assetGltfUpAxis: (sourceTileset.asset && sourceTileset.asset.gltfUpAxis) || 'Y'
|
|
@@ -13,7 +13,7 @@ import type {
|
|
|
13
13
|
BoundingVolumes,
|
|
14
14
|
MaxScreenThresholdSQ,
|
|
15
15
|
NodeInPage,
|
|
16
|
-
|
|
16
|
+
Attribute
|
|
17
17
|
} from '@loaders.gl/i3s';
|
|
18
18
|
import {load, encode, isBrowser} from '@loaders.gl/core';
|
|
19
19
|
import {CesiumIonLoader, Tiles3DLoader} from '@loaders.gl/3d-tiles';
|
|
@@ -61,11 +61,12 @@ import {WorkerFarm} from '@loaders.gl/worker-utils';
|
|
|
61
61
|
import WriteQueue from '../lib/utils/write-queue';
|
|
62
62
|
import {BROWSER_ERROR_MESSAGE} from '../constants';
|
|
63
63
|
import {
|
|
64
|
+
getAttributeTypesFromPropertyTable,
|
|
65
|
+
getAttributeTypesFromSchema,
|
|
64
66
|
createdStorageAttribute,
|
|
67
|
+
getFieldAttributeType,
|
|
65
68
|
createFieldAttribute,
|
|
66
|
-
createPopupInfo
|
|
67
|
-
getAttributeType,
|
|
68
|
-
getFieldAttributeType
|
|
69
|
+
createPopupInfo
|
|
69
70
|
} from './helpers/feature-attributes';
|
|
70
71
|
import {NodeIndexDocument} from './helpers/node-index-document';
|
|
71
72
|
import {
|
|
@@ -663,16 +664,7 @@ export default class I3SConverter {
|
|
|
663
664
|
let boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel!);
|
|
664
665
|
|
|
665
666
|
const propertyTable = getPropertyTable(tileContent, this.options.metadataClass);
|
|
666
|
-
|
|
667
|
-
if (propertyTable) {
|
|
668
|
-
/*
|
|
669
|
-
Call the convertion procedure even if the node attributes have been already created.
|
|
670
|
-
We will append new attributes only in case the property table is updated.
|
|
671
|
-
According to ver 1.9 (see https://github.com/Esri/i3s-spec/blob/master/docs/1.9/attributeStorageInfo.cmn.md):
|
|
672
|
-
"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."
|
|
673
|
-
*/
|
|
674
|
-
this._convertPropertyTableToNodeAttributes(propertyTable);
|
|
675
|
-
}
|
|
667
|
+
this.createAttributeStorageInfo(tileContent, propertyTable);
|
|
676
668
|
|
|
677
669
|
const resourcesData = await this._convertResources(
|
|
678
670
|
sourceTile,
|
|
@@ -1165,42 +1157,83 @@ export default class I3SConverter {
|
|
|
1165
1157
|
}
|
|
1166
1158
|
|
|
1167
1159
|
/**
|
|
1168
|
-
*
|
|
1169
|
-
* @param
|
|
1160
|
+
* Creates attribute storage info based on either extension schema or property table.
|
|
1161
|
+
* @param tileContent - content of the source tile
|
|
1162
|
+
* @param propertyTable - feature properties from EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA
|
|
1170
1163
|
*/
|
|
1171
|
-
private
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1164
|
+
private createAttributeStorageInfo(
|
|
1165
|
+
tileContent: Tiles3DTileContent | null,
|
|
1166
|
+
propertyTable: FeatureTableJson | null
|
|
1167
|
+
): void {
|
|
1168
|
+
/*
|
|
1169
|
+
In case the tileset doesn't have either EXT_structural_metadata or EXT_feature_metadata
|
|
1170
|
+
that can be a source of attribute information so metadataClass is not specified
|
|
1171
|
+
we will collect attribute information for node attributes from the property table
|
|
1172
|
+
taken from each tile.
|
|
1173
|
+
*/
|
|
1174
|
+
let attributeTypesMap: Record<string, Attribute> | null = null;
|
|
1175
|
+
if (this.options.metadataClass) {
|
|
1176
|
+
if (!this.layers0!.attributeStorageInfo!.length && tileContent?.gltf) {
|
|
1177
|
+
attributeTypesMap = getAttributeTypesFromSchema(
|
|
1178
|
+
tileContent.gltf,
|
|
1179
|
+
this.options.metadataClass
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
} else if (propertyTable) {
|
|
1183
|
+
attributeTypesMap = getAttributeTypesFromPropertyTable(propertyTable);
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
if (attributeTypesMap) {
|
|
1187
|
+
this.createStorageAttributes(attributeTypesMap);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* Creates Attribute Storage Info objects based on attribute's types
|
|
1193
|
+
* @param attributeTypesMap - set of attribute's types
|
|
1194
|
+
*/
|
|
1195
|
+
private createStorageAttributes(attributeTypesMap: Record<string, Attribute>): void {
|
|
1196
|
+
if (!Object.keys(attributeTypesMap).length) {
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
const attributeTypes: Record<string, Attribute> = {
|
|
1200
|
+
OBJECTID: 'OBJECTID',
|
|
1201
|
+
...attributeTypesMap
|
|
1176
1202
|
};
|
|
1177
1203
|
|
|
1178
|
-
|
|
1204
|
+
let isUpdated = false;
|
|
1205
|
+
let attributeIndex = this.layers0!.attributeStorageInfo!.length;
|
|
1206
|
+
for (const key in attributeTypes) {
|
|
1179
1207
|
/*
|
|
1180
|
-
|
|
1181
|
-
According to ver 1.9 (see https://github.com/Esri/i3s-spec/blob/master/docs/1.9/attributeStorageInfo.cmn.md):
|
|
1182
|
-
"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."
|
|
1208
|
+
We will append a new attribute only in case it has not been added to the attribute storage info yet.
|
|
1183
1209
|
*/
|
|
1184
|
-
const
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
key,
|
|
1192
|
-
attributeType
|
|
1193
|
-
);
|
|
1210
|
+
const elementFound = this.layers0!.attributeStorageInfo!.find(
|
|
1211
|
+
(element) => element.name === key
|
|
1212
|
+
);
|
|
1213
|
+
if (!elementFound) {
|
|
1214
|
+
const attributeType = attributeTypes[key];
|
|
1215
|
+
|
|
1216
|
+
const storageAttribute = createdStorageAttribute(attributeIndex, key, attributeType);
|
|
1194
1217
|
const fieldAttributeType = getFieldAttributeType(attributeType);
|
|
1195
1218
|
const fieldAttribute = createFieldAttribute(key, fieldAttributeType);
|
|
1196
|
-
const popupInfo = createPopupInfo(propertyTableWithObjectId);
|
|
1197
1219
|
|
|
1198
1220
|
this.layers0!.attributeStorageInfo!.push(storageAttribute);
|
|
1199
1221
|
this.layers0!.fields!.push(fieldAttribute);
|
|
1200
|
-
|
|
1201
|
-
|
|
1222
|
+
attributeIndex += 1;
|
|
1223
|
+
isUpdated = true;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
if (isUpdated) {
|
|
1227
|
+
/*
|
|
1228
|
+
The attributeStorageInfo is updated. So, popupInfo should be recreated.
|
|
1229
|
+
Use attributeStorageInfo as a source of attribute names to create the popupInfo.
|
|
1230
|
+
*/
|
|
1231
|
+
const attributeNames: string[] = [];
|
|
1232
|
+
for (let info of this.layers0!.attributeStorageInfo!) {
|
|
1233
|
+
attributeNames.push(info.name);
|
|
1202
1234
|
}
|
|
1203
|
-
|
|
1235
|
+
this.layers0!.popupInfo = createPopupInfo(attributeNames);
|
|
1236
|
+
this.layers0!.layerType = _3D_OBJECT_LAYER_TYPE;
|
|
1204
1237
|
}
|
|
1205
1238
|
}
|
|
1206
1239
|
|
|
@@ -188,7 +188,7 @@ export type PreprocessData = {
|
|
|
188
188
|
/** Mesh topology types used in gltf primitives of the tileset */
|
|
189
189
|
meshTopologyTypes: Set<GLTFPrimitiveModeString>;
|
|
190
190
|
/**
|
|
191
|
-
*
|
|
191
|
+
* Feature metadata classes found in glTF extensions
|
|
192
192
|
* The tileset might contain multiple metadata classes provided by EXT_feature_metadata and EXT_structural_metadata extensions.
|
|
193
193
|
* Every class is a set of properties. But I3S can consume only one set of properties.
|
|
194
194
|
* On the pre-process we collect all classes from the tileset in order to show the prompt to select one class for conversion to I3S.
|