@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/index.cjs CHANGED
@@ -1078,6 +1078,7 @@ function generateBatchIdsFromTexture(featureIdTexture, textureCoordinates, image
1078
1078
  }
1079
1079
 
1080
1080
  // src/i3s-converter/helpers/feature-attributes.ts
1081
+ var import_gltf2 = require("@loaders.gl/gltf");
1081
1082
  function flattenPropertyTableByFeatureIds(featureIdsMap, propertyTable) {
1082
1083
  const resultPropertyTable = {};
1083
1084
  for (const propertyName in propertyTable) {
@@ -1109,10 +1110,7 @@ var STRING_TYPE = "string";
1109
1110
  var SHORT_INT_TYPE = "Int32";
1110
1111
  var DOUBLE_TYPE = "double";
1111
1112
  var OBJECT_ID_TYPE = "OBJECTID";
1112
- function getAttributeType(key, attribute) {
1113
- if (key === OBJECT_ID_TYPE) {
1114
- return OBJECT_ID_TYPE;
1115
- }
1113
+ function getAttributeType(attribute) {
1116
1114
  if (typeof attribute === STRING_TYPE || typeof attribute === "bigint") {
1117
1115
  return STRING_TYPE;
1118
1116
  } else if (typeof attribute === "number") {
@@ -1166,18 +1164,18 @@ function createFieldAttribute(key, fieldAttributeType) {
1166
1164
  alias: key
1167
1165
  };
1168
1166
  }
1169
- function createPopupInfo(propertyTable) {
1167
+ function createPopupInfo(propertyNames) {
1170
1168
  const title = "{OBJECTID}";
1171
1169
  const mediaInfos = [];
1172
1170
  const fieldInfos = [];
1173
1171
  const popupElements = [];
1174
1172
  const expressionInfos = [];
1175
- for (const key in propertyTable) {
1173
+ for (const propertyName of propertyNames) {
1176
1174
  fieldInfos.push({
1177
- fieldName: key,
1175
+ fieldName: propertyName,
1178
1176
  visible: true,
1179
1177
  isEditable: false,
1180
- label: key
1178
+ label: propertyName
1181
1179
  });
1182
1180
  }
1183
1181
  popupElements.push({
@@ -1217,6 +1215,96 @@ function setupDoubleAttribute(storageAttribute) {
1217
1215
  valuesPerElement: 1
1218
1216
  };
1219
1217
  }
1218
+ function getAttributeTypesFromPropertyTable(propertyTable) {
1219
+ const attributeTypesMap = {};
1220
+ for (const key in propertyTable) {
1221
+ const firstAttribute = propertyTable[key][0];
1222
+ const attributeType = getAttributeType(firstAttribute);
1223
+ attributeTypesMap[key] = attributeType;
1224
+ }
1225
+ return attributeTypesMap;
1226
+ }
1227
+ var getAttributeTypesFromSchema = (gltfJson, metadataClass) => {
1228
+ var _a2, _b, _c, _d, _e, _f, _g, _h;
1229
+ const attributeTypesMap = {};
1230
+ const extFeatureMetadataSchemaClass = (_d = (_c = (_b = (_a2 = gltfJson.extensions) == null ? void 0 : _a2[import_gltf2.EXT_FEATURE_METADATA]) == null ? void 0 : _b.schema) == null ? void 0 : _c.classes) == null ? void 0 : _d[metadataClass];
1231
+ if (extFeatureMetadataSchemaClass) {
1232
+ for (let propertyName in extFeatureMetadataSchemaClass.properties) {
1233
+ const property = extFeatureMetadataSchemaClass.properties[propertyName];
1234
+ const attributeProperty = getAttributeTypeFromExtFeatureMetadata(property);
1235
+ attributeTypesMap[propertyName] = attributeProperty;
1236
+ }
1237
+ return attributeTypesMap;
1238
+ }
1239
+ const extStructuralMetadataSchemaClass = (_h = (_g = (_f = (_e = gltfJson.extensions) == null ? void 0 : _e[import_gltf2.EXT_STRUCTURAL_METADATA]) == null ? void 0 : _f.schema) == null ? void 0 : _g.classes) == null ? void 0 : _h[metadataClass];
1240
+ if (extStructuralMetadataSchemaClass) {
1241
+ for (let propertyName in extStructuralMetadataSchemaClass.properties) {
1242
+ const property = extStructuralMetadataSchemaClass.properties[propertyName];
1243
+ const attributeProperty = getAttributeTypeFromExtStructuralMetadata(property);
1244
+ attributeTypesMap[propertyName] = attributeProperty;
1245
+ }
1246
+ return attributeTypesMap;
1247
+ }
1248
+ return null;
1249
+ };
1250
+ var getAttributeTypeFromExtFeatureMetadata = (property) => {
1251
+ let attributeType;
1252
+ switch (property.type) {
1253
+ case "INT8":
1254
+ case "UINT8":
1255
+ case "INT16":
1256
+ case "UINT16":
1257
+ case "INT32":
1258
+ case "UINT32":
1259
+ attributeType = SHORT_INT_TYPE;
1260
+ break;
1261
+ case "FLOAT32":
1262
+ case "FLOAT64":
1263
+ attributeType = DOUBLE_TYPE;
1264
+ break;
1265
+ case "INT64":
1266
+ case "UINT64":
1267
+ case "BOOLEAN":
1268
+ case "ENUM":
1269
+ case "STRING":
1270
+ case "ARRAY":
1271
+ attributeType = STRING_TYPE;
1272
+ break;
1273
+ default:
1274
+ attributeType = STRING_TYPE;
1275
+ break;
1276
+ }
1277
+ return attributeType;
1278
+ };
1279
+ var getAttributeTypeFromExtStructuralMetadata = (property) => {
1280
+ let attributeType;
1281
+ if (property.array) {
1282
+ attributeType = STRING_TYPE;
1283
+ } else {
1284
+ switch (property.componentType) {
1285
+ case "INT8":
1286
+ case "UINT8":
1287
+ case "INT16":
1288
+ case "UINT16":
1289
+ case "INT32":
1290
+ case "UINT32":
1291
+ attributeType = SHORT_INT_TYPE;
1292
+ break;
1293
+ case "FLOAT32":
1294
+ case "FLOAT64":
1295
+ attributeType = DOUBLE_TYPE;
1296
+ break;
1297
+ case "INT64":
1298
+ case "UINT64":
1299
+ attributeType = STRING_TYPE;
1300
+ break;
1301
+ default:
1302
+ attributeType = STRING_TYPE;
1303
+ break;
1304
+ }
1305
+ }
1306
+ return attributeType;
1307
+ };
1220
1308
 
1221
1309
  // src/i3s-converter/helpers/geometry-converter.ts
1222
1310
  var import_math2 = require("@loaders.gl/math");
@@ -1231,7 +1319,7 @@ var generateSyntheticIndices = (vertexCount) => {
1231
1319
  };
1232
1320
 
1233
1321
  // src/i3s-converter/helpers/geometry-converter.ts
1234
- var import_gltf2 = require("@loaders.gl/gltf");
1322
+ var import_gltf3 = require("@loaders.gl/gltf");
1235
1323
  var DEFAULT_ROUGHNESS_FACTOR = 1;
1236
1324
  var DEFAULT_METALLIC_FACTOR = 1;
1237
1325
  var VALUES_PER_VERTEX2 = 3;
@@ -2137,15 +2225,15 @@ function getPropertyTable(tileContent, metadataClass) {
2137
2225
  }
2138
2226
  const { extensionName, extension } = getPropertyTableExtension(tileContent);
2139
2227
  switch (extensionName) {
2140
- case import_gltf2.EXT_STRUCTURAL_METADATA: {
2141
- propertyTable = (0, import_gltf2.getPropertyTableFromExtStructuralMetadata)(
2228
+ case import_gltf3.EXT_STRUCTURAL_METADATA: {
2229
+ propertyTable = getPropertyTableFromExtStructuralMetadata(
2142
2230
  extension,
2143
2231
  metadataClass
2144
2232
  );
2145
2233
  return propertyTable;
2146
2234
  }
2147
- case import_gltf2.EXT_FEATURE_METADATA: {
2148
- propertyTable = (0, import_gltf2.getPropertyTableFromExtFeatureMetadata)(
2235
+ case import_gltf3.EXT_FEATURE_METADATA: {
2236
+ propertyTable = getPropertyTableFromExtFeatureMetadata(
2149
2237
  extension,
2150
2238
  metadataClass
2151
2239
  );
@@ -2155,9 +2243,52 @@ function getPropertyTable(tileContent, metadataClass) {
2155
2243
  return null;
2156
2244
  }
2157
2245
  }
2246
+ function getPropertyTableFromExtStructuralMetadata(extension, metadataClass) {
2247
+ if (extension.propertyTables) {
2248
+ for (const propertyTable of extension.propertyTables) {
2249
+ if (propertyTable.class === metadataClass || !metadataClass) {
2250
+ return getPropertyData(propertyTable);
2251
+ }
2252
+ }
2253
+ }
2254
+ if (extension.propertyTextures) {
2255
+ for (const propertyTexture of extension.propertyTextures) {
2256
+ if (propertyTexture.class === metadataClass || !metadataClass) {
2257
+ return getPropertyData(propertyTexture);
2258
+ }
2259
+ }
2260
+ }
2261
+ return null;
2262
+ }
2263
+ function getPropertyTableFromExtFeatureMetadata(extension, metadataClass) {
2264
+ if (extension.featureTables) {
2265
+ for (const featureTableName in extension.featureTables) {
2266
+ const featureTable = extension.featureTables[featureTableName];
2267
+ if (featureTable.class === metadataClass || !metadataClass) {
2268
+ return getPropertyData(featureTable);
2269
+ }
2270
+ }
2271
+ }
2272
+ if (extension.featureTextures) {
2273
+ for (const featureTextureName in extension.featureTextures) {
2274
+ const featureTexture = extension.featureTextures[featureTextureName];
2275
+ if (featureTexture.class === metadataClass || !metadataClass) {
2276
+ return getPropertyData(featureTexture);
2277
+ }
2278
+ }
2279
+ }
2280
+ return null;
2281
+ }
2282
+ function getPropertyData(featureObject) {
2283
+ const propertyTableWithData = {};
2284
+ for (const propertyName in featureObject.properties) {
2285
+ propertyTableWithData[propertyName] = featureObject.properties[propertyName].data;
2286
+ }
2287
+ return propertyTableWithData;
2288
+ }
2158
2289
  function getPropertyTableExtension(tileContent) {
2159
2290
  var _a2, _b, _c, _d;
2160
- const extensionsWithPropertyTables = [import_gltf2.EXT_FEATURE_METADATA, import_gltf2.EXT_STRUCTURAL_METADATA];
2291
+ const extensionsWithPropertyTables = [import_gltf3.EXT_FEATURE_METADATA, import_gltf3.EXT_STRUCTURAL_METADATA];
2161
2292
  const extensionsUsed = (_a2 = tileContent == null ? void 0 : tileContent.gltf) == null ? void 0 : _a2.extensionsUsed;
2162
2293
  if (!extensionsUsed) {
2163
2294
  return { extensionName: null, extension: null };
@@ -3359,6 +3490,7 @@ var loadTile3DContent = async (sourceTileset, sourceTile, tilesetLoadOptions) =>
3359
3490
  const loadOptions = {
3360
3491
  ...tilesetLoadOptions,
3361
3492
  [sourceTileset.loader.id]: {
3493
+ // @ts-ignore
3362
3494
  ...tilesetLoadOptions[sourceTileset.loader.id] || {},
3363
3495
  isTileset,
3364
3496
  assetGltfUpAxis: sourceTileset.asset && sourceTileset.asset.gltfUpAxis || "Y"
@@ -3426,9 +3558,9 @@ var traverseDatasetWith = async (tile, traversalProps, processTile, postprocessT
3426
3558
  };
3427
3559
 
3428
3560
  // src/i3s-converter/helpers/preprocess-3d-tiles.ts
3429
- var import_gltf3 = require("@loaders.gl/gltf");
3430
- var import_core8 = require("@loaders.gl/core");
3431
3561
  var import_gltf4 = require("@loaders.gl/gltf");
3562
+ var import_core8 = require("@loaders.gl/core");
3563
+ var import_gltf5 = require("@loaders.gl/gltf");
3432
3564
  var GLTF_PRIMITIVE_MODES = [
3433
3565
  "POINTS" /* POINTS */,
3434
3566
  // 0
@@ -3453,7 +3585,7 @@ var analyzeTileContent = async (tileContent) => {
3453
3585
  if (!(tileContent == null ? void 0 : tileContent.gltfArrayBuffer)) {
3454
3586
  return defaultResult;
3455
3587
  }
3456
- const gltfData = await (0, import_core8.parse)(tileContent.gltfArrayBuffer, import_gltf3.GLTFLoader, {
3588
+ const gltfData = await (0, import_core8.parse)(tileContent.gltfArrayBuffer, import_gltf4.GLTFLoader, {
3457
3589
  gltf: { normalize: false, loadBuffers: false, loadImages: false, decompressMeshes: false }
3458
3590
  });
3459
3591
  const gltf = gltfData.json;
@@ -3483,13 +3615,13 @@ var getMeshTypesFromGLTF = (gltfJson) => {
3483
3615
  var getMetadataClassesFromGLTF = (gltfJson) => {
3484
3616
  var _a2, _b, _c, _d, _e, _f;
3485
3617
  const result = /* @__PURE__ */ new Set();
3486
- const extFeatureMetadataClasses = (_c = (_b = (_a2 = gltfJson.extensions) == null ? void 0 : _a2[import_gltf4.EXT_FEATURE_METADATA]) == null ? void 0 : _b.schema) == null ? void 0 : _c.classes;
3618
+ const extFeatureMetadataClasses = (_c = (_b = (_a2 = gltfJson.extensions) == null ? void 0 : _a2[import_gltf5.EXT_FEATURE_METADATA]) == null ? void 0 : _b.schema) == null ? void 0 : _c.classes;
3487
3619
  if (extFeatureMetadataClasses) {
3488
3620
  for (const classKey of Object.keys(extFeatureMetadataClasses)) {
3489
3621
  result.add(classKey);
3490
3622
  }
3491
3623
  }
3492
- const extStructuralMetadataClasses = (_f = (_e = (_d = gltfJson.extensions) == null ? void 0 : _d[import_gltf3.EXT_STRUCTURAL_METADATA]) == null ? void 0 : _e.schema) == null ? void 0 : _f.classes;
3624
+ const extStructuralMetadataClasses = (_f = (_e = (_d = gltfJson.extensions) == null ? void 0 : _d[import_gltf4.EXT_STRUCTURAL_METADATA]) == null ? void 0 : _e.schema) == null ? void 0 : _f.classes;
3493
3625
  if (extStructuralMetadataClasses) {
3494
3626
  for (const classKey of Object.keys(extStructuralMetadataClasses)) {
3495
3627
  result.add(classKey);
@@ -3965,9 +4097,7 @@ var I3SConverter = class {
3965
4097
  );
3966
4098
  let boundingVolumes = createBoundingVolumes(sourceBoundingVolume, this.geoidHeightModel);
3967
4099
  const propertyTable = getPropertyTable(tileContent, this.options.metadataClass);
3968
- if (propertyTable) {
3969
- this._convertPropertyTableToNodeAttributes(propertyTable);
3970
- }
4100
+ this.createAttributeStorageInfo(tileContent, propertyTable);
3971
4101
  const resourcesData = await this._convertResources(
3972
4102
  sourceTile,
3973
4103
  transformationMatrix,
@@ -4378,34 +4508,62 @@ var I3SConverter = class {
4378
4508
  return newGeometryId;
4379
4509
  }
4380
4510
  /**
4381
- * Do conversion of 3DTiles property table to I3s node attributes.
4382
- * @param propertyTable - Table with layer meta data.
4511
+ * Creates attribute storage info based on either extension schema or property table.
4512
+ * @param tileContent - content of the source tile
4513
+ * @param propertyTable - feature properties from EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA
4383
4514
  */
4384
- _convertPropertyTableToNodeAttributes(propertyTable) {
4385
- let attributeIndex = 0;
4386
- const propertyTableWithObjectId = {
4387
- OBJECTID: [0],
4388
- ...propertyTable
4389
- };
4390
- for (const key in propertyTableWithObjectId) {
4391
- const found = this.layers0.attributeStorageInfo.find((element) => element.name === key);
4392
- if (!found) {
4393
- const firstAttribute = propertyTableWithObjectId[key][0];
4394
- const attributeType = getAttributeType(key, firstAttribute);
4395
- const storageAttribute = createdStorageAttribute(
4396
- attributeIndex,
4397
- key,
4398
- attributeType
4515
+ createAttributeStorageInfo(tileContent, propertyTable) {
4516
+ let attributeTypesMap = null;
4517
+ if (this.options.metadataClass) {
4518
+ if (!this.layers0.attributeStorageInfo.length && (tileContent == null ? void 0 : tileContent.gltf)) {
4519
+ attributeTypesMap = getAttributeTypesFromSchema(
4520
+ tileContent.gltf,
4521
+ this.options.metadataClass
4399
4522
  );
4523
+ }
4524
+ } else if (propertyTable) {
4525
+ attributeTypesMap = getAttributeTypesFromPropertyTable(propertyTable);
4526
+ }
4527
+ if (attributeTypesMap) {
4528
+ this.createStorageAttributes(attributeTypesMap);
4529
+ }
4530
+ }
4531
+ /**
4532
+ * Creates Attribute Storage Info objects based on attribute's types
4533
+ * @param attributeTypesMap - set of attribute's types
4534
+ */
4535
+ createStorageAttributes(attributeTypesMap) {
4536
+ if (!Object.keys(attributeTypesMap).length) {
4537
+ return;
4538
+ }
4539
+ const attributeTypes = {
4540
+ OBJECTID: "OBJECTID",
4541
+ ...attributeTypesMap
4542
+ };
4543
+ let isUpdated = false;
4544
+ let attributeIndex = this.layers0.attributeStorageInfo.length;
4545
+ for (const key in attributeTypes) {
4546
+ const elementFound = this.layers0.attributeStorageInfo.find(
4547
+ (element) => element.name === key
4548
+ );
4549
+ if (!elementFound) {
4550
+ const attributeType = attributeTypes[key];
4551
+ const storageAttribute = createdStorageAttribute(attributeIndex, key, attributeType);
4400
4552
  const fieldAttributeType = getFieldAttributeType(attributeType);
4401
4553
  const fieldAttribute = createFieldAttribute(key, fieldAttributeType);
4402
- const popupInfo = createPopupInfo(propertyTableWithObjectId);
4403
4554
  this.layers0.attributeStorageInfo.push(storageAttribute);
4404
4555
  this.layers0.fields.push(fieldAttribute);
4405
- this.layers0.popupInfo = popupInfo;
4406
- this.layers0.layerType = _3D_OBJECT_LAYER_TYPE;
4556
+ attributeIndex += 1;
4557
+ isUpdated = true;
4558
+ }
4559
+ }
4560
+ if (isUpdated) {
4561
+ const attributeNames = [];
4562
+ for (let info of this.layers0.attributeStorageInfo) {
4563
+ attributeNames.push(info.name);
4407
4564
  }
4408
- attributeIndex += 1;
4565
+ this.layers0.popupInfo = createPopupInfo(attributeNames);
4566
+ this.layers0.layerType = _3D_OBJECT_LAYER_TYPE;
4409
4567
  }
4410
4568
  }
4411
4569
  /**
@@ -4548,7 +4706,7 @@ var import_worker_utils3 = require("@loaders.gl/worker-utils");
4548
4706
 
4549
4707
  // src/3d-tiles-converter/helpers/b3dm-converter.ts
4550
4708
  var import_core12 = require("@loaders.gl/core");
4551
- var import_gltf5 = require("@loaders.gl/gltf");
4709
+ var import_gltf6 = require("@loaders.gl/gltf");
4552
4710
  var import_d_tiles3 = require("@loaders.gl/3d-tiles");
4553
4711
  var import_core13 = require("@math.gl/core");
4554
4712
  var import_geospatial6 = require("@math.gl/geospatial");
@@ -4614,7 +4772,7 @@ var B3dmConverter = class {
4614
4772
  async buildGLTF(i3sAttributesData, featureAttributes) {
4615
4773
  const { tileContent, textureFormat, box } = i3sAttributesData;
4616
4774
  const { material, attributes, indices: originalIndices, modelMatrix } = tileContent;
4617
- const gltfBuilder = new import_gltf5.GLTFScenegraph();
4775
+ const gltfBuilder = new import_gltf6.GLTFScenegraph();
4618
4776
  const textureIndex = await this._addI3sTextureToGLTF(tileContent, textureFormat, gltfBuilder);
4619
4777
  const pbrMaterialInfo = this._convertI3sMaterialToGLTFMaterial(material, textureIndex);
4620
4778
  const materialIndex = gltfBuilder.addMaterial(pbrMaterialInfo);
@@ -4653,7 +4811,7 @@ var B3dmConverter = class {
4653
4811
  const sceneIndex = gltfBuilder.addScene({ nodeIndices: [nodeIndex] });
4654
4812
  gltfBuilder.setDefaultScene(sceneIndex);
4655
4813
  gltfBuilder.createBinaryChunk();
4656
- const gltfBuffer = (0, import_core12.encodeSync)(gltfBuilder.gltf, import_gltf5.GLTFWriter);
4814
+ const gltfBuffer = (0, import_core12.encodeSync)(gltfBuilder.gltf, import_gltf6.GLTFWriter);
4657
4815
  return gltfBuffer;
4658
4816
  }
4659
4817
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loaders.gl/tile-converter",
3
- "version": "4.0.0-beta.4",
3
+ "version": "4.0.0-beta.5",
4
4
  "description": "Converter",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -52,18 +52,18 @@
52
52
  "build-i3s-server-bundle": "esbuild src/i3s-server/bin/www.ts --outfile=dist/i3s-server/bin/i3s-server.min.cjs --platform=node --target=esnext,node14 --minify --bundle --define:__VERSION__=\\\"$npm_package_version\\\""
53
53
  },
54
54
  "dependencies": {
55
- "@loaders.gl/3d-tiles": "4.0.0-beta.4",
56
- "@loaders.gl/crypto": "4.0.0-beta.4",
57
- "@loaders.gl/draco": "4.0.0-beta.4",
58
- "@loaders.gl/gltf": "4.0.0-beta.4",
59
- "@loaders.gl/i3s": "4.0.0-beta.4",
60
- "@loaders.gl/images": "4.0.0-beta.4",
61
- "@loaders.gl/loader-utils": "4.0.0-beta.4",
62
- "@loaders.gl/polyfills": "4.0.0-beta.4",
63
- "@loaders.gl/textures": "4.0.0-beta.4",
64
- "@loaders.gl/tiles": "4.0.0-beta.4",
65
- "@loaders.gl/worker-utils": "4.0.0-beta.4",
66
- "@loaders.gl/zip": "4.0.0-beta.4",
55
+ "@loaders.gl/3d-tiles": "4.0.0-beta.5",
56
+ "@loaders.gl/crypto": "4.0.0-beta.5",
57
+ "@loaders.gl/draco": "4.0.0-beta.5",
58
+ "@loaders.gl/gltf": "4.0.0-beta.5",
59
+ "@loaders.gl/i3s": "4.0.0-beta.5",
60
+ "@loaders.gl/images": "4.0.0-beta.5",
61
+ "@loaders.gl/loader-utils": "4.0.0-beta.5",
62
+ "@loaders.gl/polyfills": "4.0.0-beta.5",
63
+ "@loaders.gl/textures": "4.0.0-beta.5",
64
+ "@loaders.gl/tiles": "4.0.0-beta.5",
65
+ "@loaders.gl/worker-utils": "4.0.0-beta.5",
66
+ "@loaders.gl/zip": "4.0.0-beta.5",
67
67
  "@math.gl/core": "^4.0.0",
68
68
  "@math.gl/culling": "^4.0.0",
69
69
  "@math.gl/geoid": "^4.0.0",
@@ -87,7 +87,7 @@
87
87
  "join-images": "^1.1.3",
88
88
  "sharp": "^0.31.3"
89
89
  },
90
- "gitHead": "848c20b474532d301f2c3f8d4e1fb9bf262b86d4",
90
+ "gitHead": "a6f5a0d1a316cc22396e5a4d480c14329d1ef146",
91
91
  "devDependencies": {
92
92
  "@types/express": "^4.17.17",
93
93
  "@types/node": "^20.4.2"
@@ -1,5 +1,5 @@
1
1
  import type {FeatureTableJson} from '@loaders.gl/3d-tiles';
2
- import {
2
+ import type {
3
3
  Attribute,
4
4
  AttributeStorageInfo,
5
5
  ESRIField,
@@ -7,6 +7,15 @@ import {
7
7
  FieldInfo,
8
8
  PopupInfo
9
9
  } from '@loaders.gl/i3s';
10
+ import type {
11
+ GLTFPostprocessed,
12
+ GLTF_EXT_feature_metadata_GLTF,
13
+ GLTF_EXT_feature_metadata_ClassProperty,
14
+ GLTF_EXT_structural_metadata_GLTF,
15
+ GLTF_EXT_structural_metadata_ClassProperty
16
+ } from '@loaders.gl/gltf';
17
+
18
+ import {EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA} from '@loaders.gl/gltf';
10
19
 
11
20
  /**
12
21
  * Takes attributes from property table based on featureIdsMap.
@@ -87,13 +96,9 @@ const DOUBLE_TYPE = 'double';
87
96
  const OBJECT_ID_TYPE = 'OBJECTID';
88
97
  /**
89
98
  * Get the attribute type for attributeStorageInfo https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md
90
- * @param key - attribute's key
91
99
  * @param attribute - attribute taken from propertyTable
92
100
  */
93
- export function getAttributeType(key: string, attribute: unknown): string {
94
- if (key === OBJECT_ID_TYPE) {
95
- return OBJECT_ID_TYPE;
96
- }
101
+ export function getAttributeType(attribute: unknown): string {
97
102
  if (typeof attribute === STRING_TYPE || typeof attribute === 'bigint') {
98
103
  return STRING_TYPE;
99
104
  } else if (typeof attribute === 'number') {
@@ -175,10 +180,10 @@ export function createFieldAttribute(key: string, fieldAttributeType: ESRIField)
175
180
 
176
181
  /**
177
182
  * Generate popup info to show metadata on the map.
178
- * @param propertyTable - table data with OBJECTID.
183
+ * @param propertyNames - array of property names including OBJECTID.
179
184
  * @return data for correct rendering of popup.
180
185
  */
181
- export function createPopupInfo(propertyTable: FeatureTableJson): PopupInfo {
186
+ export function createPopupInfo(propertyNames: string[]): PopupInfo {
182
187
  const title = '{OBJECTID}';
183
188
  const mediaInfos = [];
184
189
  const fieldInfos: FieldInfo[] = [];
@@ -188,12 +193,12 @@ export function createPopupInfo(propertyTable: FeatureTableJson): PopupInfo {
188
193
  }[] = [];
189
194
  const expressionInfos = [];
190
195
 
191
- for (const key in propertyTable) {
196
+ for (const propertyName of propertyNames) {
192
197
  fieldInfos.push({
193
- fieldName: key,
198
+ fieldName: propertyName,
194
199
  visible: true,
195
200
  isEditable: false,
196
- label: key
201
+ label: propertyName
197
202
  });
198
203
  }
199
204
  popupElements.push({
@@ -250,3 +255,151 @@ function setupDoubleAttribute(storageAttribute: AttributeStorageInfo): void {
250
255
  valuesPerElement: 1
251
256
  };
252
257
  }
258
+
259
+ /**
260
+ * Gets attribute's types based on the property table records.
261
+ * @param propertyTable - Table with layer meta data.
262
+ * @returns set of attribute types
263
+ * @example of returned object:
264
+ * {
265
+ * "opt_uint8": "Int32",
266
+ * "opt_uint64": "string"
267
+ * }
268
+ */
269
+ export function getAttributeTypesFromPropertyTable(
270
+ propertyTable: FeatureTableJson
271
+ ): Record<string, Attribute> {
272
+ const attributeTypesMap: Record<string, Attribute> = {};
273
+ for (const key in propertyTable) {
274
+ // Get attribute type based on the first element of each property.
275
+ const firstAttribute = propertyTable[key][0];
276
+ const attributeType = getAttributeType(firstAttribute);
277
+ attributeTypesMap[key] = attributeType;
278
+ }
279
+ return attributeTypesMap;
280
+ }
281
+
282
+ /**
283
+ * Gets attribute's types from the extension schema selected by the class name 'metadataClass'.
284
+ * @param gltfJson - JSON part of GLB content
285
+ * @param metadataClass - name of the schema class
286
+ * @returns set of attribute's types
287
+ * @example of returned object:
288
+ * {
289
+ * "opt_uint8": "Int32",
290
+ * "opt_uint64": "string"
291
+ * }
292
+ */
293
+ export const getAttributeTypesFromSchema = (
294
+ gltfJson: GLTFPostprocessed,
295
+ metadataClass: string
296
+ ): Record<string, Attribute> | null => {
297
+ const attributeTypesMap: Record<string, Attribute> = {};
298
+ const extFeatureMetadataSchemaClass = (
299
+ gltfJson.extensions?.[EXT_FEATURE_METADATA] as GLTF_EXT_feature_metadata_GLTF
300
+ )?.schema?.classes?.[metadataClass];
301
+ if (extFeatureMetadataSchemaClass) {
302
+ for (let propertyName in extFeatureMetadataSchemaClass.properties) {
303
+ const property = extFeatureMetadataSchemaClass.properties[propertyName];
304
+ const attributeProperty = getAttributeTypeFromExtFeatureMetadata(property);
305
+ attributeTypesMap[propertyName] = attributeProperty;
306
+ }
307
+ return attributeTypesMap;
308
+ }
309
+
310
+ const extStructuralMetadataSchemaClass = (
311
+ gltfJson.extensions?.[EXT_STRUCTURAL_METADATA] as GLTF_EXT_structural_metadata_GLTF
312
+ )?.schema?.classes?.[metadataClass];
313
+ if (extStructuralMetadataSchemaClass) {
314
+ for (let propertyName in extStructuralMetadataSchemaClass.properties) {
315
+ const property = extStructuralMetadataSchemaClass.properties[propertyName];
316
+ const attributeProperty = getAttributeTypeFromExtStructuralMetadata(property);
317
+ attributeTypesMap[propertyName] = attributeProperty;
318
+ }
319
+ return attributeTypesMap;
320
+ }
321
+
322
+ return null;
323
+ };
324
+
325
+ /**
326
+ * Gets the attribute type according to the Ext_feature_metadata extension class schema
327
+ * @see https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md
328
+ * @param property - schema of the class property for Ext_feature_metadata
329
+ * @returns attribute's type
330
+ */
331
+ const getAttributeTypeFromExtFeatureMetadata = (
332
+ property: GLTF_EXT_feature_metadata_ClassProperty
333
+ ): Attribute => {
334
+ let attributeType: Attribute;
335
+ switch (property.type) {
336
+ case 'INT8':
337
+ case 'UINT8':
338
+ case 'INT16':
339
+ case 'UINT16':
340
+ case 'INT32':
341
+ case 'UINT32':
342
+ attributeType = SHORT_INT_TYPE;
343
+ break;
344
+
345
+ case 'FLOAT32':
346
+ case 'FLOAT64':
347
+ attributeType = DOUBLE_TYPE;
348
+ break;
349
+
350
+ case 'INT64':
351
+ case 'UINT64':
352
+ case 'BOOLEAN':
353
+ case 'ENUM':
354
+ case 'STRING':
355
+ case 'ARRAY':
356
+ attributeType = STRING_TYPE;
357
+ break;
358
+
359
+ default:
360
+ attributeType = STRING_TYPE;
361
+ break;
362
+ }
363
+ return attributeType;
364
+ };
365
+
366
+ /**
367
+ * Gets the attribute type according to the Ext_structural_metadata extension class schema
368
+ * @see https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md
369
+ * @param property - schema of the class property for Ext_structural_metadata
370
+ * @returns attribute's type
371
+ */
372
+ const getAttributeTypeFromExtStructuralMetadata = (
373
+ property: GLTF_EXT_structural_metadata_ClassProperty
374
+ ): Attribute => {
375
+ let attributeType: Attribute;
376
+ if (property.array) {
377
+ attributeType = STRING_TYPE;
378
+ } else {
379
+ switch (property.componentType) {
380
+ case 'INT8':
381
+ case 'UINT8':
382
+ case 'INT16':
383
+ case 'UINT16':
384
+ case 'INT32':
385
+ case 'UINT32':
386
+ attributeType = SHORT_INT_TYPE;
387
+ break;
388
+
389
+ case 'FLOAT32':
390
+ case 'FLOAT64':
391
+ attributeType = DOUBLE_TYPE;
392
+ break;
393
+
394
+ case 'INT64':
395
+ case 'UINT64':
396
+ attributeType = STRING_TYPE;
397
+ break;
398
+
399
+ default:
400
+ attributeType = STRING_TYPE;
401
+ break;
402
+ }
403
+ }
404
+ return attributeType;
405
+ };