diff --git a/Apps/Sandcastle/gallery/I3S 3D Object Layer.html b/Apps/Sandcastle/gallery/I3S 3D Object Layer.html index 0adbecb1c5d3..f63947dffc52 100644 --- a/Apps/Sandcastle/gallery/I3S 3D Object Layer.html +++ b/Apps/Sandcastle/gallery/I3S 3D Object Layer.html @@ -102,46 +102,31 @@

Loading...

Cesium.defined(pickedFeature.content.tile.i3sNode) ) { const i3sNode = pickedFeature.content.tile.i3sNode; - i3sNode.loadFields().then(function () { - const geometry = i3sNode.geometryData[0]; - if (pickedPosition) { - const location = geometry.getClosestPointIndexOnTriangle( - pickedPosition.x, - pickedPosition.y, - pickedPosition.z - ); + if (pickedPosition) { + i3sNode.loadFields().then(function () { let description = "No attributes"; let name; - if ( - location.index !== -1 && - geometry.customAttributes.featureIndex - ) { - console.log( - `pickedPosition(x,y,z) : ${pickedPosition.x}, ${pickedPosition.y}, ${pickedPosition.z}` - ); - const featureIndex = - geometry.customAttributes.featureIndex[location.index]; - if (Object.keys(i3sNode.fields).length > 0) { - description = - ''; - for (const fieldName in i3sNode.fields) { - if (i3sNode.fields.hasOwnProperty(fieldName)) { - const field = i3sNode.fields[fieldName]; - description += ``; - console.log( - `${field.name}: ${field.values[featureIndex]}` - ); - if ( - !Cesium.defined(name) && - isNameProperty(field.name) - ) { - name = field.values[featureIndex]; - } + console.log( + `pickedPosition(x,y,z) : ${pickedPosition.x}, ${pickedPosition.y}, ${pickedPosition.z}` + ); + + const fields = i3sNode.getFieldsForPickedPosition( + pickedPosition + ); + if (Object.keys(fields).length > 0) { + description = + '
${field.name}`; - description += `${field.values[featureIndex]}
'; + for (const fieldName in fields) { + if (i3sNode.fields.hasOwnProperty(fieldName)) { + description += ``; + console.log(`${fieldName}: ${fields[fieldName]}`); + if (!Cesium.defined(name) && isNameProperty(fieldName)) { + name = fields[fieldName]; } } - description += `
${fieldName}`; + description += `${fields[fieldName]}
`; } + description += ``; } if (!Cesium.defined(name)) { name = "unknown"; @@ -149,8 +134,8 @@

Loading...

selectedEntity.name = name; selectedEntity.description = description; viewer.selectedEntity = selectedEntity; - } - }); + }); + } } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); diff --git a/Apps/Sandcastle/gallery/I3S Feature Picking.html b/Apps/Sandcastle/gallery/I3S Feature Picking.html index 40a483927a64..3e9018886b71 100644 --- a/Apps/Sandcastle/gallery/I3S Feature Picking.html +++ b/Apps/Sandcastle/gallery/I3S Feature Picking.html @@ -102,46 +102,31 @@

Loading...

Cesium.defined(pickedFeature.content.tile.i3sNode) ) { const i3sNode = pickedFeature.content.tile.i3sNode; - i3sNode.loadFields().then(function () { - const geometry = i3sNode.geometryData[0]; - if (pickedPosition) { - const location = geometry.getClosestPointIndexOnTriangle( - pickedPosition.x, - pickedPosition.y, - pickedPosition.z - ); + if (pickedPosition) { + i3sNode.loadFields().then(function () { let description = "No attributes"; let name; - if ( - location.index !== -1 && - geometry.customAttributes.featureIndex - ) { - console.log( - `pickedPosition(x,y,z) : ${pickedPosition.x}, ${pickedPosition.y}, ${pickedPosition.z}` - ); - const featureIndex = - geometry.customAttributes.featureIndex[location.index]; - if (Object.keys(i3sNode.fields).length > 0) { - description = - ''; - for (const fieldName in i3sNode.fields) { - if (i3sNode.fields.hasOwnProperty(fieldName)) { - const field = i3sNode.fields[fieldName]; - description += ``; - console.log( - `${field.name}: ${field.values[featureIndex]}` - ); - if ( - !Cesium.defined(name) && - isNameProperty(field.name) - ) { - name = field.values[featureIndex]; - } + console.log( + `pickedPosition(x,y,z) : ${pickedPosition.x}, ${pickedPosition.y}, ${pickedPosition.z}` + ); + + const fields = i3sNode.getFieldsForPickedPosition( + pickedPosition + ); + if (Object.keys(fields).length > 0) { + description = + '
${field.name}`; - description += `${field.values[featureIndex]}
'; + for (const fieldName in fields) { + if (i3sNode.fields.hasOwnProperty(fieldName)) { + description += ``; + console.log(`${fieldName}: ${fields[fieldName]}`); + if (!Cesium.defined(name) && isNameProperty(fieldName)) { + name = fields[fieldName]; } } - description += `
${fieldName}`; + description += `${fields[fieldName]}
`; } + description += ``; } if (!Cesium.defined(name)) { name = "unknown"; @@ -149,8 +134,8 @@

Loading...

selectedEntity.name = name; selectedEntity.description = description; viewer.selectedEntity = selectedEntity; - } - }); + }); + } } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index b9f44a0ad8c1..7716f6594ba1 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -337,3 +337,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu - [Ilya Shevelev](https://github.com/ilyaly) - [Gabriel Aldous](https://github.com/Sn00pyW00dst0ck) - [金俊](https://github.com/jinjun1994) +- [Oussama Bonnor](https://github.com/oussamabonnor1) diff --git a/packages/engine/Source/Scene/I3SDataProvider.js b/packages/engine/Source/Scene/I3SDataProvider.js index c4a2da950500..ac0fe6cb36dc 100644 --- a/packages/engine/Source/Scene/I3SDataProvider.js +++ b/packages/engine/Source/Scene/I3SDataProvider.js @@ -626,7 +626,8 @@ I3SDataProvider.prototype._loadGeoidData = function () { console.log( "No Geoid Terrain service provided - no geoid conversion will be performed." ); - return Promise.resolve(); + this._geoidDataIsReadyPromise = Promise.resolve(); + return this._geoidDataIsReadyPromise; } this._geoidDataIsReadyPromise = geoidTerrainProvider.readyPromise.then( diff --git a/packages/engine/Source/Scene/I3SFeature.js b/packages/engine/Source/Scene/I3SFeature.js index 876fb8f2e548..f2c5b9822a2b 100644 --- a/packages/engine/Source/Scene/I3SFeature.js +++ b/packages/engine/Source/Scene/I3SFeature.js @@ -49,7 +49,7 @@ Object.defineProperties(I3SFeature.prototype, { /** * Loads the content. - * @returns {Promise.} A promise that is resolved when the data of the I3S feature is loaded + * @returns {Promise} A promise that is resolved when the data of the I3S feature is loaded * @private */ I3SFeature.prototype.load = function () { diff --git a/packages/engine/Source/Scene/I3SLayer.js b/packages/engine/Source/Scene/I3SLayer.js index 7fed8bae0aa4..e6b2f613125d 100644 --- a/packages/engine/Source/Scene/I3SLayer.js +++ b/packages/engine/Source/Scene/I3SLayer.js @@ -35,6 +35,11 @@ function I3SLayer(dataProvider, layerData, index) { .concat(`${layerData.href}`); } + this._version = layerData.store.version; + const splitVersion = this._version.split("."); + this._majorVersion = parseInt(splitVersion[0]); + this._minorVersion = splitVersion.length > 1 ? parseInt(splitVersion[1]) : 0; + this._resource = new Resource({ url: tilesetUrl }); this._resource.setQueryParameters( this._dataProvider.resource.queryParameters @@ -98,11 +103,68 @@ Object.defineProperties(I3SLayer.prototype, { return this._data; }, }, + + /** + * The version string of the loaded I3S dataset + * @memberof I3SLayer.prototype + * @type {String} + * @readonly + */ + version: { + get: function () { + return this._version; + }, + }, + + /** + * The major version number of the loaded I3S dataset + * @memberof I3SLayer.prototype + * @type {Number} + * @readonly + */ + majorVersion: { + get: function () { + return this._majorVersion; + }, + }, + + /** + * The minor version number of the loaded I3S dataset + * @memberof I3SLayer.prototype + * @type {Number} + * @readonly + */ + minorVersion: { + get: function () { + return this._minorVersion; + }, + }, + + /** + * When true, when the loaded I3S version is 1.6 or older + * @memberof I3SLayer.prototype + * @type {Boolean} + * @readonly + */ + legacyVersion16: { + get: function () { + if (!defined(this.version)) { + return undefined; + } + if ( + this.majorVersion < 1 || + (this.majorVersion === 1 && this.minorVersion <= 6) + ) { + return true; + } + return false; + }, + }, }); /** * Loads the content, including the root node definition and its children - * @returns {Promise.} A promise that is resolved when the layer data is loaded + * @returns {Promise} A promise that is resolved when the layer data is loaded * @private */ I3SLayer.prototype.load = function () { @@ -121,7 +183,7 @@ I3SLayer.prototype.load = function () { return that._tileset.readyPromise.then(function () { that._rootNode._tile = that._tileset._root; that._tileset._root._i3sNode = that._rootNode; - if (that._data.store.version === "1.6") { + if (that.legacyVersion16) { return that._rootNode._loadChildren(); } }); diff --git a/packages/engine/Source/Scene/I3SNode.js b/packages/engine/Source/Scene/I3SNode.js index 72b2f807e10c..8b8536b9a8a0 100644 --- a/packages/engine/Source/Scene/I3SNode.js +++ b/packages/engine/Source/Scene/I3SNode.js @@ -240,6 +240,52 @@ I3SNode.prototype.loadFields = function () { return Promise.all(promises); }; +/** + * Returns the fields for a given picked position + * @param {Cartesian3} pickedPosition The picked position + * @returns {Object} Object containing field names and their values + */ +I3SNode.prototype.getFieldsForPickedPosition = function (pickedPosition) { + const geometry = this.geometryData[0]; + if (!defined(geometry.customAttributes.featureIndex)) { + return {}; + } + + const location = geometry.getClosestPointIndexOnTriangle( + pickedPosition.x, + pickedPosition.y, + pickedPosition.z + ); + + if ( + location.index === -1 || + location.index > geometry.customAttributes.featureIndex.length + ) { + return {}; + } + + const featureIndex = geometry.customAttributes.featureIndex[location.index]; + return this.getFieldsForFeature(featureIndex); +}; + +/** + * Returns the fields for a given feature + * @param {Number} featureIndex Index of the feature whose attributes we want to get + * @returns {Object} Object containing field names and their values + */ +I3SNode.prototype.getFieldsForFeature = function (featureIndex) { + const featureFields = {}; + for (const fieldName in this.fields) { + if (this.fields.hasOwnProperty(fieldName)) { + const field = this.fields[fieldName]; + if (featureIndex >= 0 && featureIndex < field.values.length) { + featureFields[field.name] = field.values[featureIndex]; + } + } + } + return featureFields; +}; + /** * @private */ @@ -336,11 +382,6 @@ I3SNode.prototype._loadFeatureData = function () { this._featureData.push(newFeatureData); featurePromises.push(newFeatureData.load()); } - } else if (defined(this._data.mesh) && defined(this._data.mesh.attribute)) { - const featureURI = `./features/0`; - const newFeatureData = new I3SFeature(this, featureURI); - this._featureData.push(newFeatureData); - featurePromises.push(newFeatureData.load()); } return Promise.all(featurePromises); @@ -661,7 +702,10 @@ I3SNode.prototype._createContentURL = function () { }; // Load the geometry data - const dataPromises = [this._loadFeatureData(), this._loadGeometryData()]; + const dataPromises = [this._loadGeometryData()]; + if (this._dataProvider.legacyVersion16) { + dataPromises.push(this._loadFeatureData()); + } const that = this; return Promise.all(dataPromises).then(function () { diff --git a/packages/engine/Source/Scene/Model/Model.js b/packages/engine/Source/Scene/Model/Model.js index 947ad497dc49..858c6d69299e 100644 --- a/packages/engine/Source/Scene/Model/Model.js +++ b/packages/engine/Source/Scene/Model/Model.js @@ -49,22 +49,55 @@ import StyleCommandsNeeded from "./StyleCommandsNeeded.js"; * {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/AGI_articulations/README.md|AGI_articulations} * *
  • + * {@link https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/CESIUM_primitive_outline|CESIUM_primitive_outline} + *
  • + *
  • + * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/CESIUM_RTC/README.md|CESIUM_RTC} + *
  • + *
  • + * {@link https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_instance_features|EXT_instance_features} + *
  • + *
  • + * {@link https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_mesh_features|EXT_mesh_features} + *
  • + *
  • + * {@link https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_mesh_gpu_instancing|EXT_mesh_gpu_instancing} + *
  • + *
  • + * {@link https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_meshopt_compression|EXT_meshopt_compression} + *
  • + *
  • + * {@link https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata|EXT_structural_metadata} + *
  • + *
  • + * {@link https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_texture_webp|EXT_texture_webp} + *
  • + *
  • * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md|KHR_draco_mesh_compression} *
  • *
  • - * {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/README.md|KHR_materials_pbrSpecularGlossiness} + * {@link https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Archived/KHR_techniques_webgl/README.md|KHR_techniques_webgl} + *
  • + *
  • + * {@link https://github.com/KhronosGroup/glTF/blob/main/extensions/1.0/Khronos/KHR_materials_common/README.md|KHR_materials_common} + *
  • + *
  • + * {@link https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Archived/KHR_materials_pbrSpecularGlossiness|KHR_materials_pbrSpecularGlossiness} *
  • *
  • * {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit/README.md|KHR_materials_unlit} *
  • *
  • - * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_texture_transform/README.md|KHR_texture_transform} + * {@link https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_mesh_quantization|KHR_mesh_quantization} *
  • *
  • * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_texture_basisu|KHR_texture_basisu} *
  • *
  • - * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/1.0/Vendor/CESIUM_RTC/README.md|CESIUM_RTC} + * {@link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_texture_transform/README.md|KHR_texture_transform} + *
  • + *
  • + * {@link https://github.com/KhronosGroup/glTF/blob/main/extensions/1.0/Vendor/WEB3D_quantized_attributes/README.md|WEB3D_quantized_attributes} *
  • * *

    diff --git a/packages/engine/Specs/Scene/I3SDataProviderSpec.js b/packages/engine/Specs/Scene/I3SDataProviderSpec.js index c2ceec474afb..50a7999be80a 100644 --- a/packages/engine/Specs/Scene/I3SDataProviderSpec.js +++ b/packages/engine/Specs/Scene/I3SDataProviderSpec.js @@ -109,7 +109,7 @@ describe("Scene/I3SDataProvider", function () { const mockLayerData = { href: "layers/0/", attributeStorageInfo: [], - store: { rootNode: "mockRootNodeUrl" }, + store: { rootNode: "mockRootNodeUrl", version: "1.6" }, fullExtent: { xmin: 0, ymin: 1, xmax: 2, ymax: 3 }, spatialReference: { wkid: 4326 }, id: 0, diff --git a/packages/engine/Specs/Scene/I3SLayerSpec.js b/packages/engine/Specs/Scene/I3SLayerSpec.js index 54e8643bc460..6aab6e50fe3e 100644 --- a/packages/engine/Specs/Scene/I3SLayerSpec.js +++ b/packages/engine/Specs/Scene/I3SLayerSpec.js @@ -85,7 +85,7 @@ describe("Scene/I3SLayer", function () { rootIndex: 0, }, attributeStorageInfo: [], - store: { defaultGeometrySchema: {} }, + store: { defaultGeometrySchema: {}, version: "1.7" }, geometryDefinitions: geometryDefinitions, fullExtent: { xmin: 0, ymin: 1, xmax: 2, ymax: 3 }, spatialReference: { wkid: 4326 }, @@ -97,7 +97,7 @@ describe("Scene/I3SLayer", function () { rootIndex: 0, }, attributeStorageInfo: [], - store: { defaultGeometrySchema: {}, extent: [0, 1, 2, 3] }, + store: { defaultGeometrySchema: {}, extent: [0, 1, 2, 3], version: "1.7" }, spatialReference: { wkid: 4326 }, }; @@ -117,6 +117,11 @@ describe("Scene/I3SLayer", function () { expect(testLayer.resource.url).toContain("mockProviderUrl/mockLayerUrl/"); expect(testLayer.resource.queryParameters.testQuery).toEqual("test"); + expect(testLayer.version).toEqual("1.7"); + expect(testLayer.majorVersion).toEqual(1); + expect(testLayer.minorVersion).toEqual(7); + expect(testLayer.legacyVersion16).toEqual(false); + expect(testLayer.data).toEqual(layerData); expect(testLayer._extent.west).toEqual(CesiumMath.toRadians(0)); @@ -365,7 +370,11 @@ describe("Scene/I3SLayer", function () { nodesPerPage: 2, rootIndex: 0, }, - store: { defaultGeometrySchema: {}, extent: [0, 1, 2, 3] }, + store: { + defaultGeometrySchema: {}, + extent: [0, 1, 2, 3], + version: "1.7", + }, spatialReference: { wkid: 3857 }, }; const mockI3SProvider = createMockI3SProvider(); diff --git a/packages/engine/Specs/Scene/I3SNodeSpec.js b/packages/engine/Specs/Scene/I3SNodeSpec.js index 30a024bc5777..afda3ea07085 100644 --- a/packages/engine/Specs/Scene/I3SNodeSpec.js +++ b/packages/engine/Specs/Scene/I3SNodeSpec.js @@ -314,7 +314,7 @@ describe("Scene/I3SNode", function () { nodesPerPage: 64, }, attributeStorageInfo: attrStorageInfo, - store: { defaultGeometrySchema: {} }, + store: { defaultGeometrySchema: {}, version: "1.7" }, materialDefinitions: [ { doubleSided: true, @@ -389,10 +389,38 @@ describe("Scene/I3SNode", function () { }, ], ]; + const layerDataWithoutNodePages = { + href: "mockLayerUrl", + attributeStorageInfo: attrStorageInfo, + store: { defaultGeometrySchema: {}, version: "1.6" }, + materialDefinitions: [ + { + doubleSided: true, + pbrMetallicRoughness: { + metallicFactor: 0, + }, + }, + { + doubleSided: true, + pbrMetallicRoughness: { + baseColorTexture: { textureSetDefinitionId: 0 }, + metallicFactor: 0, + }, + }, + ], + textureSetDefinitions: [ + { + formats: [ + { name: "0", format: "dds" }, + { name: "1", format: "jpg" }, + ], + }, + ], + }; const mockI3SLayerWithoutNodePages = new I3SLayer( mockI3SProviderWithoutQuery, - layerData + layerDataWithoutNodePages ); mockI3SLayerWithoutNodePages._tileset = mockCesiumTileset; mockI3SLayerWithoutNodePages._geometryDefinitions = [ @@ -837,35 +865,13 @@ describe("Scene/I3SNode", function () { ).toEqual("test"); expect(rootNode.fields.testInt8.header.count).toEqual(2); - expect(rootNode.fields.testInt8.values[0]).toEqual(1); - expect(rootNode.fields.testInt8.values[1]).toEqual(2); expect(rootNode.fields.testUInt8.header.count).toEqual(2); - expect(rootNode.fields.testUInt8.values[0]).toEqual(1); - expect(rootNode.fields.testUInt8.values[1]).toEqual(2); - expect(rootNode.fields.testInt16.header.count).toEqual(2); - expect(rootNode.fields.testInt16.values[0]).toEqual(1); - expect(rootNode.fields.testInt16.values[1]).toEqual(2); expect(rootNode.fields.testUInt16.header.count).toEqual(2); - expect(rootNode.fields.testUInt16.values[0]).toEqual(1); - expect(rootNode.fields.testUInt16.values[1]).toEqual(2); - expect(rootNode.fields.testInt32.header.count).toEqual(2); - expect(rootNode.fields.testInt32.values[0]).toEqual(1); - expect(rootNode.fields.testInt32.values[1]).toEqual(-1); expect(rootNode.fields.testUInt32.header.count).toEqual(2); - expect(rootNode.fields.testUInt32.values[0]).toEqual(1); - expect(rootNode.fields.testUInt32.values[1]).toEqual( - Math.pow(2, 32) - 1 - ); - expect(rootNode.fields.testInt64.header.count).toEqual(2); - expect(rootNode.fields.testInt64.values[0]).toEqual(1); - expect(rootNode.fields.testInt64.values[1]).toEqual(-1); expect(rootNode.fields.testUInt64.header.count).toEqual(2); - expect(rootNode.fields.testUInt64.values[0]).toEqual(1); - expect(rootNode.fields.testUInt64.values[1]).toEqual(Math.pow(2, 64)); //Value loses precision because js doesn't support int64 - expect(rootNode.fields.testFloat32.header.count).toEqual(2); expect(rootNode.fields.testFloat32.values[0]).toEqual(1.0); expect(rootNode.fields.testFloat32.values[1]).toEqual(2.0); @@ -877,8 +883,28 @@ describe("Scene/I3SNode", function () { expect( rootNode.fields.testString.header.attributeValuesByteCount ).toEqual(16); - expect(rootNode.fields.testString.values[0]).toEqual("abc"); - expect(rootNode.fields.testString.values[1]).toEqual("def"); + + const featureFields0 = rootNode.getFieldsForFeature(0); + const featureFields1 = rootNode.getFieldsForFeature(1); + + expect(featureFields0.testInt8).toEqual(1); + expect(featureFields1.testInt8).toEqual(2); + expect(featureFields0.testUInt8).toEqual(1); + expect(featureFields1.testUInt8).toEqual(2); + expect(featureFields0.testInt16).toEqual(1); + expect(featureFields1.testInt16).toEqual(2); + expect(featureFields0.testUInt16).toEqual(1); + expect(featureFields1.testUInt16).toEqual(2); + expect(featureFields0.testInt32).toEqual(1); + expect(featureFields1.testInt32).toEqual(-1); + expect(featureFields0.testUInt32).toEqual(1); + expect(featureFields1.testUInt32).toEqual(Math.pow(2, 32) - 1); + expect(featureFields0.testInt64).toEqual(1); + expect(featureFields1.testInt64).toEqual(-1); + expect(featureFields0.testUInt64).toEqual(1); + expect(featureFields1.testUInt64).toEqual(Math.pow(2, 64)); //Value loses precision because js doesn't support int64 + expect(featureFields0.testString).toEqual("abc"); + expect(featureFields1.testString).toEqual("def"); }); }); @@ -1150,35 +1176,47 @@ describe("Scene/I3SNode", function () { it("loads feature data from node pages", function () { const nodeWithMesh = new I3SNode(mockI3SLayerWithNodePages, 1, true); - spyOn(nodeWithMesh._dataProvider, "_loadJson").and.returnValue( - Promise.resolve({ featureData: [], geometryData: [] }) - ); - return nodeWithMesh .load() .then(function () { return nodeWithMesh._loadFeatureData(); }) .then(function (result) { - expect(nodeWithMesh.featureData.length).toEqual(1); - expect(nodeWithMesh.featureData[0].resource.url).toContain( - "mockProviderUrl/mockLayerUrl/nodes/1/features/0" - ); - expect( - nodeWithMesh.featureData[0].resource.queryParameters.testQuery - ).toEqual("test"); - - expect(nodeWithMesh.featureData[0].data.featureData).toEqual([]); - expect(nodeWithMesh.featureData[0].data.geometryData).toEqual([]); - - expect(nodeWithMesh._dataProvider._loadJson).toHaveBeenCalledWith( - nodeWithMesh.featureData[0].resource - ); + //Expect nothing to be loaded. Feature data is not used when reading nodes from node pages + //because the information is all stored in the node page entry and binary data + expect(nodeWithMesh.featureData.length).toEqual(0); }); }); it("load feature data rejects invalid url", function () { - const nodeWithMesh = new I3SNode(mockI3SLayerWithNodePages, 1, true); + const nodeWithMesh = new I3SNode( + mockI3SLayerWithoutNodePages, + "mockNodeUrl", + true + ); + + spyOn(nodeWithMesh._dataProvider, "_loadJson").and.callFake(function ( + resource + ) { + if ( + resource + .getUrlComponent() + .endsWith( + "mockProviderUrl/mockLayerUrl/mockNodeUrl/mockFeatureDataUrl" + ) + ) { + return Promise.reject({ statusCode: 404 }); + } + if ( + resource + .getUrlComponent() + .endsWith("mockProviderUrl/mockLayerUrl/mockNodeUrl/") + ) { + return Promise.resolve(nodeWithContent); + } + + return Promise.reject(); + }); return nodeWithMesh .load() @@ -1200,18 +1238,15 @@ describe("Scene/I3SNode", function () { spyOn(nodeWithMesh._dataProvider, "_loadBinary").and.returnValue( Promise.resolve(new ArrayBuffer()) ); - spyOn(nodeWithMesh._dataProvider, "_loadJson").and.returnValue( - Promise.resolve({ featureData: [], geometryData: [] }) - ); + spyOn(nodeWithMesh, "_loadFeatureData").and.returnValue(Promise.all([])); const mockProcessor = { scheduleTask: function (payload) { //Expect results to match what was returned by our spy expect(payload.binaryData).toEqual(new ArrayBuffer()); - expect(payload.featureData).toEqual({ - featureData: [], - geometryData: [], - }); + + //Expect featureData to be undefined as it is only used for legacy versions (<= 1.6) + expect(payload.featureData).toBeUndefined(); expect(payload.bufferInfo).toEqual( mockI3SLayerWithNodePages._geometryDefinitions[0][1]