diff --git a/Source/Scene/MetadataClassProperty.js b/Source/Scene/MetadataClassProperty.js index 4ed551536e96..cbacf71d9349 100644 --- a/Source/Scene/MetadataClassProperty.js +++ b/Source/Scene/MetadataClassProperty.js @@ -1,3 +1,6 @@ +import Cartesian2 from "../Core/Cartesian2.js"; +import Cartesian3 from "../Core/Cartesian3.js"; +import Cartesian4 from "../Core/Cartesian4.js"; import Check from "../Core/Check.js"; import defaultValue from "../Core/defaultValue.js"; import defined from "../Core/defined.js"; @@ -294,6 +297,79 @@ MetadataClassProperty.prototype.unnormalize = function (value) { return normalize(this, value, MetadataType.unnormalize); }; +/** + * Unpack array values into {@link Cartesian2}, {@link Cartesian3}, or + * {@link Cartesian4} if this property is an ARRAY of length 2, 3, + * or 4, respectively. All other values (including arrays of other sizes) are + * passed through unaltered. + * + * @param {*} value the original, normalized values. + * @returns {*} The appropriate vector type if the value is a vector type. Otherwise, the value is returned unaltered. + * @private + */ +MetadataClassProperty.prototype.unpackVectorTypes = function (value) { + var type = this._type; + var componentCount = this._componentCount; + + if ( + type !== MetadataType.ARRAY || + !defined(componentCount) || + !MetadataType.isVectorCompatible(this._componentType) + ) { + return value; + } + + if (componentCount === 2) { + return Cartesian2.unpack(value); + } + + if (componentCount === 3) { + return Cartesian3.unpack(value); + } + + if (componentCount === 4) { + return Cartesian4.unpack(value); + } + + return value; +}; + +/** + * Pack a {@link Cartesian2}, {@link Cartesian3}, or {@link Cartesian4} into an + * array if this property is an ARRAY of length 2, 3, or 4, respectively. + * All other values (including arrays of other sizes) are passed through unaltered. + * + * @param {*} value The value of this property + * @returns {*} An array of the appropriate length if the property is a vector type. Otherwise, the value is returned unaltered. + * @private + */ +MetadataClassProperty.prototype.packVectorTypes = function (value) { + var type = this._type; + var componentCount = this._componentCount; + + if ( + type !== MetadataType.ARRAY || + !defined(componentCount) || + !MetadataType.isVectorCompatible(this._componentType) + ) { + return value; + } + + if (componentCount === 2) { + return Cartesian2.pack(value, []); + } + + if (componentCount === 3) { + return Cartesian3.pack(value, []); + } + + if (componentCount === 4) { + return Cartesian4.pack(value, []); + } + + return value; +}; + /** * Validates whether the given value conforms to the property. * @@ -304,11 +380,23 @@ MetadataClassProperty.prototype.validate = function (value) { var message; var type = this._type; if (type === MetadataType.ARRAY) { + var componentCount = this._componentCount; + + // arrays of length 2, 3, and 4 are implicitly converted to CartesianN + if ( + defined(componentCount) && + componentCount >= 2 && + componentCount <= 4 && + MetadataType.isVectorCompatible(this._componentType) + ) { + return validateVector(value, componentCount); + } + if (!Array.isArray(value)) { return getTypeErrorMessage(value, type); } var length = value.length; - if (defined(this._componentCount) && this._componentCount !== length) { + if (defined(componentCount) && componentCount !== length) { return "Array length does not match componentCount"; } for (var i = 0; i < length; ++i) { @@ -325,6 +413,20 @@ MetadataClassProperty.prototype.validate = function (value) { } }; +function validateVector(value, componentCount) { + if (componentCount === 2 && !(value instanceof Cartesian2)) { + return "vector value " + value + " must be a Cartesian2"; + } + + if (componentCount === 3 && !(value instanceof Cartesian3)) { + return "vector value " + value + " must be a Cartesian3"; + } + + if (componentCount === 4 && !(value instanceof Cartesian4)) { + return "vector value " + value + " must be a Cartesian4"; + } +} + function getTypeErrorMessage(value, type) { return "value " + value + " does not match type " + type; } diff --git a/Source/Scene/MetadataEntity.js b/Source/Scene/MetadataEntity.js index d6e3ec4a1fcf..c015531c1471 100644 --- a/Source/Scene/MetadataEntity.js +++ b/Source/Scene/MetadataEntity.js @@ -227,6 +227,7 @@ MetadataEntity.getProperty = function ( if (defined(classProperty)) { value = classProperty.normalize(value); + value = classProperty.unpackVectorTypes(value); } return value; @@ -269,6 +270,7 @@ MetadataEntity.setProperty = function ( if (defined(classDefinition)) { var classProperty = classDefinition.properties[propertyId]; if (defined(classProperty)) { + value = classProperty.packVectorTypes(value); value = classProperty.unnormalize(value); } } diff --git a/Source/Scene/MetadataTable.js b/Source/Scene/MetadataTable.js index a24959119a11..f2281fb787a7 100644 --- a/Source/Scene/MetadataTable.js +++ b/Source/Scene/MetadataTable.js @@ -243,7 +243,8 @@ function getDefault(classDefinition, propertyId) { if (classProperty.type === MetadataType.ARRAY) { value = value.slice(); // clone } - return classProperty.normalize(value); + value = classProperty.normalize(value); + return classProperty.unpackVectorTypes(value); } } } diff --git a/Source/Scene/MetadataTableProperty.js b/Source/Scene/MetadataTableProperty.js index 428a95b2521f..3e3805ba8977 100644 --- a/Source/Scene/MetadataTableProperty.js +++ b/Source/Scene/MetadataTableProperty.js @@ -187,7 +187,8 @@ MetadataTableProperty.prototype.get = function (index) { //>>includeEnd('debug'); var value = get(this, index); - return this._classProperty.normalize(value); + value = this._classProperty.normalize(value); + return this._classProperty.unpackVectorTypes(value); }; /** @@ -209,6 +210,7 @@ MetadataTableProperty.prototype.set = function (index, value) { } //>>includeEnd('debug'); + value = classProperty.packVectorTypes(value); value = classProperty.unnormalize(value); set(this, index, value); diff --git a/Source/Scene/MetadataType.js b/Source/Scene/MetadataType.js index 2f5b964efd06..a718ba634971 100644 --- a/Source/Scene/MetadataType.js +++ b/Source/Scene/MetadataType.js @@ -212,6 +212,31 @@ MetadataType.isUnsignedIntegerType = function (type) { } }; +/** + * Returns whether a type can be used in a vector, i.e. the {@link Cartesian2}, + * {@link Cartesian3}, or {@link Cartesian4} classes. This includes all numeric + * types except for types requiring 64-bits + */ +MetadataType.isVectorCompatible = function (type) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.string("type", type); + //>>includeEnd('debug'); + + switch (type) { + case MetadataType.INT8: + case MetadataType.UINT8: + case MetadataType.INT16: + case MetadataType.UINT16: + case MetadataType.INT32: + case MetadataType.UINT32: + case MetadataType.FLOAT32: + case MetadataType.FLOAT64: + return true; + default: + return false; + } +}; + /** * Normalizes signed integers to the range [-1.0, 1.0] and unsigned integers to * the range [0.0, 1.0]. diff --git a/Specs/Data/Cesium3DTiles/Metadata/AllMetadataTypes/tileset.json b/Specs/Data/Cesium3DTiles/Metadata/AllMetadataTypes/tileset.json index f478a2684d83..c29427d845e0 100644 --- a/Specs/Data/Cesium3DTiles/Metadata/AllMetadataTypes/tileset.json +++ b/Specs/Data/Cesium3DTiles/Metadata/AllMetadataTypes/tileset.json @@ -26,7 +26,7 @@ "description": "Center of the tileset as [longitude, latitude, height] where longitude and latitude are in radians, and height is in meters].", "type": "ARRAY", "componentType": "FLOAT64", - "componentCount": "3" + "componentCount": 3 }, "tileCount": { "description": "Total number of tiles in the tileset", diff --git a/Specs/Data/Cesium3DTiles/Metadata/TilesetMetadata/tileset.json b/Specs/Data/Cesium3DTiles/Metadata/TilesetMetadata/tileset.json index a7dc6b8f778d..bc0f96611bb2 100644 --- a/Specs/Data/Cesium3DTiles/Metadata/TilesetMetadata/tileset.json +++ b/Specs/Data/Cesium3DTiles/Metadata/TilesetMetadata/tileset.json @@ -29,7 +29,7 @@ "description": "Center of the tileset as [longitude, latitude, height] where longitude and latitude are in radians, and height is in meters].", "type": "ARRAY", "componentType": "FLOAT64", - "componentCount": "3" + "componentCount": 3 }, "tileCount": { "description": "Total number of tiles in the tileset", diff --git a/Specs/Scene/Cesium3DTileFeatureSpec.js b/Specs/Scene/Cesium3DTileFeatureSpec.js index 7d8ece8138a1..2d07267535ec 100644 --- a/Specs/Scene/Cesium3DTileFeatureSpec.js +++ b/Specs/Scene/Cesium3DTileFeatureSpec.js @@ -1,5 +1,6 @@ import { Cartesian3, + Cartesian4, Cesium3DTileFeature, HeadingPitchRange, } from "../../Source/Cesium.js"; @@ -55,22 +56,16 @@ describe( it("getPropertyInherited returns tile property by semantic", function () { var feature = new Cesium3DTileFeature(childContents["ll.b3dm"], 0); - expect(feature.getPropertyInherited("COLOR")).toEqual([ - 255, - 255, - 0, - 1.0, - ]); + expect(feature.getPropertyInherited("COLOR")).toEqual( + new Cartesian4(255, 255, 0, 1.0) + ); }); it("getPropertyInherited returns tile property", function () { var feature = new Cesium3DTileFeature(childContents["ll.b3dm"], 0); - expect(feature.getPropertyInherited("color")).toEqual([ - 255, - 255, - 0, - 1.0, - ]); + expect(feature.getPropertyInherited("color")).toEqual( + new Cartesian4(255, 255, 0, 1.0) + ); expect(feature.getPropertyInherited("population")).toBe(50); }); @@ -92,12 +87,9 @@ describe( it("getPropertyInherited returns tileset property by semantic", function () { var feature = new Cesium3DTileFeature(parentContent, 0); - expect(feature.getPropertyInherited("COLOR")).toEqual([ - 255, - 0, - 255, - 1.0, - ]); + expect(feature.getPropertyInherited("COLOR")).toEqual( + new Cartesian4(255, 0, 255, 1.0) + ); expect(feature.getPropertyInherited("DATE_ISO_8601")).toBe( "2021-04-07" ); @@ -106,17 +98,16 @@ describe( it("getPropertyInherited returns tileset property", function () { var feature = new Cesium3DTileFeature(parentContent, 0); - expect(feature.getPropertyInherited("color")).toEqual([ - 255, - 0, - 255, - 1.0, - ]); - expect(feature.getPropertyInherited("centerCartographic")).toEqual([ - -1.3196816996258511, - 0.6988767486400521, - 45.78600543644279, - ]); + expect(feature.getPropertyInherited("color")).toEqual( + new Cartesian4(255, 0, 255, 1.0) + ); + expect(feature.getPropertyInherited("centerCartographic")).toEqual( + new Cartesian3( + -1.3196816996258511, + 0.6988767486400521, + 45.78600543644279 + ) + ); expect(feature.getPropertyInherited("date")).toBe("2021-04-07"); expect(feature.getPropertyInherited("author")).toBe("Cesium"); expect(feature.getPropertyInherited("tileCount")).toBe(5); @@ -126,12 +117,9 @@ describe( // tile metadata is more specific than tileset metadata so this returns // yellow not magenta var feature = new Cesium3DTileFeature(childContents["ll.b3dm"], 0); - expect(feature.getPropertyInherited("color")).toEqual([ - 255, - 255, - 0, - 1.0, - ]); + expect(feature.getPropertyInherited("color")).toEqual( + new Cartesian4(255, 255, 0, 1.0) + ); // group metadata is more specific than tileset metadata, so this returns // 2 not 5 diff --git a/Specs/Scene/Cesium3DTilesetSpec.js b/Specs/Scene/Cesium3DTilesetSpec.js index aabdb5dac283..fdb0598d974a 100644 --- a/Specs/Scene/Cesium3DTilesetSpec.js +++ b/Specs/Scene/Cesium3DTilesetSpec.js @@ -5198,7 +5198,7 @@ describe( tilesetProperties.date ); expect(tilesetMetadata.getProperty("centerCartographic")).toEqual( - tilesetProperties.centerCartographic + Cartesian3.unpack(tilesetProperties.centerCartographic) ); expect(tilesetMetadata.getProperty("tileCount")).toBe( tilesetProperties.tileCount @@ -5298,23 +5298,23 @@ describe( ).then(function (tileset) { var expected = { "parent.b3dm": { - color: [0.5, 0.0, 1.0], + color: new Cartesian3(0.5, 0.0, 1.0), population: 530, }, "ll.b3dm": { - color: [1.0, 1.0, 0.0], + color: new Cartesian3(1.0, 1.0, 0.0), population: 50, }, "lr.b3dm": { - color: [1.0, 0.0, 0.5], + color: new Cartesian3(1.0, 0.0, 0.5), population: 230, }, "ur.b3dm": { - color: [1.0, 0.5, 0.0], + color: new Cartesian3(1.0, 0.5, 0.0), population: 150, }, "ul.b3dm": { - color: [1.0, 0.0, 0.0], + color: new Cartesian3(1.0, 0.0, 0.0), population: 100, }, }; @@ -5360,10 +5360,10 @@ describe( "Northeast", ]; var expectedColors = [ - [255, 255, 255], - [255, 0, 0], - [0, 255, 0], - [0, 0, 255], + new Cartesian3(255, 255, 255), + new Cartesian3(255, 0, 0), + new Cartesian3(0, 255, 0), + new Cartesian3(0, 0, 255), ]; var tiles = [transcodedRoot].concat(transcodedRoot.children); diff --git a/Specs/Scene/GroupMetadataSpec.js b/Specs/Scene/GroupMetadataSpec.js index 7141558bdee2..bab808f6ece8 100644 --- a/Specs/Scene/GroupMetadataSpec.js +++ b/Specs/Scene/GroupMetadataSpec.js @@ -1,4 +1,8 @@ -import { MetadataClass, GroupMetadata } from "../../Source/Cesium.js"; +import { + Cartesian3, + MetadataClass, + GroupMetadata, +} from "../../Source/Cesium.js"; describe("Scene/GroupMetadata", function () { it("creates group metadata with default values", function () { @@ -59,7 +63,9 @@ describe("Scene/GroupMetadata", function () { expect(groupMetadata.description).toBe("Building Metadata"); expect(groupMetadata.extras).toBe(extras); expect(groupMetadata.extensions).toBe(extensions); - expect(groupMetadata.getProperty("position")).toEqual(properties.position); + expect(groupMetadata.getProperty("position")).toEqual( + Cartesian3.unpack(properties.position) + ); }); it("constructor throws without id", function () { @@ -326,8 +332,7 @@ describe("Scene/GroupMetadata", function () { }); var value = groupMetadata.getProperty("position"); - expect(value).toEqual(position); - expect(value).not.toBe(position); // The value is cloned + expect(value).toEqual(Cartesian3.unpack(position)); }); it("getProperty returns the default value when the property is missing", function () { @@ -354,8 +359,7 @@ describe("Scene/GroupMetadata", function () { }); var value = groupMetadata.getProperty("position"); - expect(value).toEqual(position); - expect(value).not.toBe(position); // The value is cloned + expect(value).toEqual(Cartesian3.unpack(position)); }); it("getProperty throws without propertyId", function () { @@ -403,10 +407,10 @@ describe("Scene/GroupMetadata", function () { }, }); - var position = [1.0, 1.0, 1.0]; + var position = new Cartesian3(1.0, 1.0, 1.0); expect(groupMetadata.setProperty("position", position)).toBe(true); expect(groupMetadata.getProperty("position")).toEqual(position); - expect(groupMetadata.getProperty("position")).not.toBe(position); // The value is cloned + expect(groupMetadata.getProperty("position")).not.toBe(position); // copies value }); it("setProperty throws without propertyId", function () { diff --git a/Specs/Scene/Implicit3DTileContentSpec.js b/Specs/Scene/Implicit3DTileContentSpec.js index 1daa9a6744be..fe33de05cbd9 100644 --- a/Specs/Scene/Implicit3DTileContentSpec.js +++ b/Specs/Scene/Implicit3DTileContentSpec.js @@ -844,11 +844,15 @@ describe( var groups = tileset.metadata.groups; var ground = groups.ground; - expect(ground.getProperty("color")).toEqual([120, 68, 32]); + expect(ground.getProperty("color")).toEqual( + new Cartesian3(120, 68, 32) + ); expect(ground.getProperty("priority")).toBe(0); var sky = groups.sky; - expect(sky.getProperty("color")).toEqual([206, 237, 242]); + expect(sky.getProperty("color")).toEqual( + new Cartesian3(206, 237, 242) + ); expect(sky.getProperty("priority")).toBe(1); tiles.forEach(function (tile) { diff --git a/Specs/Scene/ImplicitSubtreeSpec.js b/Specs/Scene/ImplicitSubtreeSpec.js index 9f3952938e2f..f3e9701a1c21 100644 --- a/Specs/Scene/ImplicitSubtreeSpec.js +++ b/Specs/Scene/ImplicitSubtreeSpec.js @@ -1,4 +1,5 @@ import { + Cartesian3, ImplicitSubdivisionScheme, ImplicitSubtree, ImplicitTileCoordinates, @@ -1114,7 +1115,7 @@ describe("Scene/ImplicitSubtree", function () { for (var i = 0; i < buildingCounts.length; i++) { expect(metadataTable.getProperty(i, "highlightColor")).toEqual( - highlightColors[i] + Cartesian3.unpack(highlightColors[i]) ); expect(metadataTable.getProperty(i, "buildingCount")).toBe( buildingCounts[i] @@ -1171,7 +1172,7 @@ describe("Scene/ImplicitSubtree", function () { for (var i = 0; i < buildingCounts.length; i++) { expect(metadataTable.getProperty(i, "highlightColor")).toEqual( - highlightColors[i] + Cartesian3.unpack(highlightColors[i]) ); expect(metadataTable.getProperty(i, "buildingCount")).toBe( buildingCounts[i] @@ -1228,7 +1229,7 @@ describe("Scene/ImplicitSubtree", function () { for (var i = 0; i < buildingCounts.length; i++) { expect(metadataTable.getProperty(i, "highlightColor")).toEqual( - highlightColors[i] + Cartesian3.unpack(highlightColors[i]) ); expect(metadataTable.getProperty(i, "buildingCount")).toBe( buildingCounts[i] @@ -1480,7 +1481,7 @@ describe("Scene/ImplicitSubtree", function () { for (var i = 0; i < buildingCounts.length; i++) { expect(metadataTable.getProperty(i, "highlightColor")).toEqual( - highlightColors[i] + Cartesian3.unpack(highlightColors[i]) ); expect(metadataTable.getProperty(i, "buildingCount")).toBe( buildingCounts[i] diff --git a/Specs/Scene/ImplicitTileMetadataSpec.js b/Specs/Scene/ImplicitTileMetadataSpec.js index fbf8ad4bac93..8305f34d8796 100644 --- a/Specs/Scene/ImplicitTileMetadataSpec.js +++ b/Specs/Scene/ImplicitTileMetadataSpec.js @@ -1,4 +1,5 @@ import { + Cartesian3, ImplicitSubdivisionScheme, ImplicitSubtree, ImplicitTileCoordinates, @@ -212,7 +213,9 @@ describe("Scene/ImplicitTileMetadata", function () { }); it("getProperty returns the property value", function () { - expect(tileMetadata.getProperty("highlightColor")).toEqual([255, 255, 0]); + expect(tileMetadata.getProperty("highlightColor")).toEqual( + new Cartesian3(255, 255, 0) + ); expect(tileMetadata.getProperty("buildingCount")).toBe(350); }); @@ -233,27 +236,24 @@ describe("Scene/ImplicitTileMetadata", function () { }); it("getPropertyBySemantic returns the property value", function () { - expect(tileMetadata.getPropertyBySemantic("_HIGHLIGHT_COLOR")).toEqual([ - 255, - 255, - 0, - ]); + expect(tileMetadata.getPropertyBySemantic("_HIGHLIGHT_COLOR")).toEqual( + new Cartesian3(255, 255, 0) + ); }); it("setPropertyBySemantic sets property value", function () { - expect(tileMetadata.getPropertyBySemantic("_HIGHLIGHT_COLOR")).toEqual([ - 255, - 255, - 0, - ]); + expect(tileMetadata.getPropertyBySemantic("_HIGHLIGHT_COLOR")).toEqual( + new Cartesian3(255, 255, 0) + ); expect( - tileMetadata.setPropertyBySemantic("_HIGHLIGHT_COLOR", [0, 0, 0]) + tileMetadata.setPropertyBySemantic( + "_HIGHLIGHT_COLOR", + new Cartesian3(0, 0, 0) + ) ).toBe(true); - expect(tileMetadata.getPropertyBySemantic("_HIGHLIGHT_COLOR")).toEqual([ - 0, - 0, - 0, - ]); + expect(tileMetadata.getPropertyBySemantic("_HIGHLIGHT_COLOR")).toEqual( + new Cartesian3(0, 0, 0) + ); }); it("setPropertyBySemantic returns false if the semantic does not exist", function () { diff --git a/Specs/Scene/MetadataClassPropertySpec.js b/Specs/Scene/MetadataClassPropertySpec.js index 825e21043c4a..ce3eaab55282 100644 --- a/Specs/Scene/MetadataClassPropertySpec.js +++ b/Specs/Scene/MetadataClassPropertySpec.js @@ -1,4 +1,7 @@ import { + Cartesian2, + Cartesian3, + Cartesian4, FeatureDetection, MetadataClassProperty, MetadataEnum, @@ -329,6 +332,258 @@ describe("Scene/MetadataClassProperty", function () { } }); + it("packVectorTypes packs vectors", function () { + var properties = { + propertyVec2: { + type: "ARRAY", + componentType: "FLOAT32", + componentCount: 2, + }, + propertyIVec3: { + type: "ARRAY", + componentType: "INT32", + componentCount: 3, + }, + propertyDVec4: { + type: "ARRAY", + componentType: "FLOAT64", + componentCount: 4, + }, + }; + + var propertyValues = { + propertyVec2: [ + new Cartesian2(0.1, 0.8), + new Cartesian2(0.3, 0.5), + new Cartesian2(0.7, 0.2), + ], + propertyIVec3: [ + new Cartesian3(1, 2, 3), + new Cartesian3(4, 5, 6), + new Cartesian3(7, 8, 9), + ], + propertyDVec4: [ + new Cartesian4(0.1, 0.2, 0.3, 0.4), + new Cartesian4(0.3, 0.2, 0.1, 0.0), + new Cartesian4(0.1, 0.2, 0.4, 0.5), + ], + }; + + var packedValues = { + propertyVec2: [ + [0.1, 0.8], + [0.3, 0.5], + [0.7, 0.2], + ], + propertyIVec3: [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + propertyDVec4: [ + [0.1, 0.2, 0.3, 0.4], + [0.3, 0.2, 0.1, 0.0], + [0.1, 0.2, 0.4, 0.5], + ], + }; + + for (var propertyId in properties) { + if (properties.hasOwnProperty(propertyId)) { + var property = new MetadataClassProperty({ + id: propertyId, + property: properties[propertyId], + }); + var length = propertyValues[propertyId].length; + for (var i = 0; i < length; ++i) { + var value = propertyValues[propertyId][i]; + var packed = property.packVectorTypes(value); + expect(packed).toEqual(packedValues[propertyId][i]); + } + } + } + }); + + it("packVectorTypes does not affect non-vectors", function () { + if (!FeatureDetection.supportsBigInt()) { + return; + } + + var properties = { + propertyString: { + type: "STRING", + }, + propertyBoolean: { + type: "BOOLEAN", + }, + propertyArray: { + type: "ARRAY", + componentType: "UINT8", + componentCount: 5, + }, + propertyBigIntArray: { + type: "ARRAY", + componentType: "UINT64", + componentCount: 2, + }, + }; + + var propertyValues = { + propertyString: ["a", "bc", ""], + propertyBoolean: [true, false, false], + propertyArray: [ + [1, 2, 3, 4, 5], + [0, 1, 2, 3, 4], + [1, 4, 9, 16, 25], + ], + propertyBigIntArray: [ + [BigInt(0), BigInt(0)], // eslint-disable-line + [BigInt(1), BigInt(3)], // eslint-disable-line + [BigInt(45), BigInt(32)], // eslint-disable-line + ], + }; + + for (var propertyId in properties) { + if (properties.hasOwnProperty(propertyId)) { + var property = new MetadataClassProperty({ + id: propertyId, + property: properties[propertyId], + }); + var length = propertyValues[propertyId].length; + for (var i = 0; i < length; ++i) { + var value = propertyValues[propertyId][i]; + var packed = property.packVectorTypes(value); + expect(packed).toEqual(value); + } + } + } + }); + + it("unpackVectorTypes unpacks vectors", function () { + var properties = { + propertyVec2: { + type: "ARRAY", + componentType: "FLOAT32", + componentCount: 2, + }, + propertyIVec3: { + type: "ARRAY", + componentType: "INT32", + componentCount: 3, + }, + propertyDVec4: { + type: "ARRAY", + componentType: "FLOAT64", + componentCount: 4, + }, + }; + + var propertyValues = { + propertyVec2: [ + new Cartesian2(0.1, 0.8), + new Cartesian2(0.3, 0.5), + new Cartesian2(0.7, 0.2), + ], + propertyIVec3: [ + new Cartesian3(1, 2, 3), + new Cartesian3(4, 5, 6), + new Cartesian3(7, 8, 9), + ], + propertyDVec4: [ + new Cartesian4(0.1, 0.2, 0.3, 0.4), + new Cartesian4(0.3, 0.2, 0.1, 0.0), + new Cartesian4(0.1, 0.2, 0.4, 0.5), + ], + }; + + var packedValues = { + propertyVec2: [ + [0.1, 0.8], + [0.3, 0.5], + [0.7, 0.2], + ], + propertyIVec3: [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + propertyDVec4: [ + [0.1, 0.2, 0.3, 0.4], + [0.3, 0.2, 0.1, 0.0], + [0.1, 0.2, 0.4, 0.5], + ], + }; + + for (var propertyId in properties) { + if (properties.hasOwnProperty(propertyId)) { + var property = new MetadataClassProperty({ + id: propertyId, + property: properties[propertyId], + }); + var length = propertyValues[propertyId].length; + for (var i = 0; i < length; ++i) { + var value = packedValues[propertyId][i]; + var unpacked = property.unpackVectorTypes(value); + expect(unpacked).toEqual(propertyValues[propertyId][i]); + } + } + } + }); + + it("unpackVectorTypes does not affect non-vectors", function () { + if (!FeatureDetection.supportsBigInt()) { + return; + } + + var properties = { + propertyString: { + type: "STRING", + }, + propertyBoolean: { + type: "BOOLEAN", + }, + propertyArray: { + type: "ARRAY", + componentType: "UINT8", + componentCount: 5, + }, + propertyBigIntArray: { + type: "ARRAY", + componentType: "UINT64", + componentCount: 2, + }, + }; + + var propertyValues = { + propertyString: ["a", "bc", ""], + propertyBoolean: [true, false, false], + propertyArray: [ + [1, 2, 3, 4, 5], + [0, 1, 2, 3, 4], + [1, 4, 9, 16, 25], + ], + propertyBigIntArray: [ + [BigInt(0), BigInt(0)], // eslint-disable-line + [BigInt(1), BigInt(3)], // eslint-disable-line + [BigInt(45), BigInt(32)], // eslint-disable-line + ], + }; + + for (var propertyId in properties) { + if (properties.hasOwnProperty(propertyId)) { + var property = new MetadataClassProperty({ + id: propertyId, + property: properties[propertyId], + }); + var length = propertyValues[propertyId].length; + for (var i = 0; i < length; ++i) { + var value = propertyValues[propertyId][i]; + var unpacked = property.unpackVectorTypes(value); + expect(unpacked).toEqual(value); + } + } + } + }); + it("validate returns undefined if the value is valid", function () { var property = new MetadataClassProperty({ id: "position", @@ -339,7 +594,7 @@ describe("Scene/MetadataClassProperty", function () { }, }); - expect(property.validate([1.0, 2.0, 3.0])).toBeUndefined(); + expect(property.validate(new Cartesian3(1.0, 2.0, 3.0))).toBeUndefined(); }); it("validate returns error message if type is ARRAY and value is not an array", function () { @@ -348,14 +603,14 @@ describe("Scene/MetadataClassProperty", function () { property: { type: "ARRAY", componentType: "FLOAT32", - componentCount: 3, + componentCount: 8, }, }); expect(property.validate(8.0)).toBe("value 8 does not match type ARRAY"); }); - it("validate returns error message if type is ARRAY and the array length does not match componentCount", function () { + it("validate returns error message if type is a vector and value is not a Cartesian", function () { var property = new MetadataClassProperty({ id: "position", property: { @@ -365,6 +620,19 @@ describe("Scene/MetadataClassProperty", function () { }, }); + expect(property.validate(8.0)).toBe("vector value 8 must be a Cartesian3"); + }); + + it("validate returns error message if type is ARRAY and the array length does not match componentCount", function () { + var property = new MetadataClassProperty({ + id: "position", + property: { + type: "ARRAY", + componentType: "FLOAT32", + componentCount: 6, + }, + }); + expect(property.validate([1.0, 2.0])).toBe( "Array length does not match componentCount" ); diff --git a/Specs/Scene/MetadataEntitySpec.js b/Specs/Scene/MetadataEntitySpec.js index 1970b7eebc24..af9f252488d6 100644 --- a/Specs/Scene/MetadataEntitySpec.js +++ b/Specs/Scene/MetadataEntitySpec.js @@ -1,4 +1,8 @@ -import { MetadataClass, MetadataEntity } from "../../Source/Cesium.js"; +import { + Cartesian3, + MetadataClass, + MetadataEntity, +} from "../../Source/Cesium.js"; describe("Scene/MetadataEntity", function () { var classDefinition = new MetadataClass({ @@ -148,8 +152,7 @@ describe("Scene/MetadataEntity", function () { properties, classDefinition ); - expect(value).toEqual(properties.position); - expect(value).not.toBe(properties.position); // The value is cloned + expect(value).toEqual(Cartesian3.unpack(properties.position)); }); it("getProperty returns the default value when the property is missing", function () { diff --git a/Specs/Scene/MetadataTablePropertySpec.js b/Specs/Scene/MetadataTablePropertySpec.js index 291752e3617c..fb60bc043bc5 100644 --- a/Specs/Scene/MetadataTablePropertySpec.js +++ b/Specs/Scene/MetadataTablePropertySpec.js @@ -1,5 +1,6 @@ import { defaultValue, + Cartesian3, MetadataClassProperty, MetadataTableProperty, } from "../../Source/Cesium.js"; @@ -287,7 +288,7 @@ describe("Scene/MetadataTableProperty", function () { } }); - it("get returns fixed size arrays", function () { + it("get returns vectors", function () { var properties = { propertyInt8: { type: "ARRAY", @@ -319,16 +320,6 @@ describe("Scene/MetadataTableProperty", function () { componentType: "UINT32", componentCount: 3, }, - propertyInt64: { - type: "ARRAY", - componentType: "INT64", - componentCount: 3, - }, - propertyUint64: { - type: "ARRAY", - componentType: "UINT64", - componentCount: 3, - }, propertyFloat32: { type: "ARRAY", componentType: "FLOAT32", @@ -339,22 +330,6 @@ describe("Scene/MetadataTableProperty", function () { componentType: "FLOAT64", componentCount: 3, }, - propertyBoolean: { - type: "ARRAY", - componentType: "BOOLEAN", - componentCount: 3, - }, - propertyString: { - type: "ARRAY", - componentType: "STRING", - componentCount: 3, - }, - propertyEnum: { - type: "ARRAY", - componentType: "ENUM", - enumType: "myEnum", - componentCount: 3, - }, }; var propertyValues = { @@ -382,14 +357,6 @@ describe("Scene/MetadataTableProperty", function () { [0, 1, 2], [3, 4, 5], ], - propertyInt64: [ - [BigInt(-2), BigInt(-1), BigInt(0)], // eslint-disable-line - [BigInt(1), BigInt(2), BigInt(3)], // eslint-disable-line - ], - propertyUint64: [ - [BigInt(0), BigInt(1), BigInt(2)], // eslint-disable-line - [BigInt(3), BigInt(4), BigInt(5)], // eslint-disable-line - ], propertyFloat32: [ [-2.0, -1.0, 0.0], [1.0, 2.0, 3.0], @@ -398,6 +365,65 @@ describe("Scene/MetadataTableProperty", function () { [-2.0, -1.0, 0.0], [1.0, 2.0, 3.0], ], + }; + + for (var propertyId in properties) { + if (properties.hasOwnProperty(propertyId)) { + var property = MetadataTester.createProperty({ + property: properties[propertyId], + values: propertyValues[propertyId], + enums: enums, + }); + + var expectedValues = propertyValues[propertyId]; + var length = expectedValues.length; + for (var i = 0; i < length; ++i) { + var value = property.get(i); + expect(value).toEqual(Cartesian3.unpack(expectedValues[i])); + } + } + } + }); + + it("get returns fixed size arrays", function () { + var properties = { + propertyInt64: { + type: "ARRAY", + componentType: "INT64", + componentCount: 3, + }, + propertyUint64: { + type: "ARRAY", + componentType: "UINT64", + componentCount: 3, + }, + propertyBoolean: { + type: "ARRAY", + componentType: "BOOLEAN", + componentCount: 3, + }, + propertyString: { + type: "ARRAY", + componentType: "STRING", + componentCount: 3, + }, + propertyEnum: { + type: "ARRAY", + componentType: "ENUM", + enumType: "myEnum", + componentCount: 3, + }, + }; + + var propertyValues = { + propertyInt64: [ + [BigInt(-2), BigInt(-1), BigInt(0)], // eslint-disable-line + [BigInt(1), BigInt(2), BigInt(3)], // eslint-disable-line + ], + propertyUint64: [ + [BigInt(0), BigInt(1), BigInt(2)], // eslint-disable-line + [BigInt(3), BigInt(4), BigInt(5)], // eslint-disable-line + ], propertyBoolean: [ [false, true, false], [true, false, true], @@ -698,7 +724,7 @@ describe("Scene/MetadataTableProperty", function () { } }); - it("set sets fixed size arrays", function () { + it("set sets vector values", function () { var properties = { propertyInt8: { type: "ARRAY", @@ -730,16 +756,6 @@ describe("Scene/MetadataTableProperty", function () { componentType: "UINT32", componentCount: 3, }, - propertyInt64: { - type: "ARRAY", - componentType: "INT64", - componentCount: 3, - }, - propertyUint64: { - type: "ARRAY", - componentType: "UINT64", - componentCount: 3, - }, propertyFloat32: { type: "ARRAY", componentType: "FLOAT32", @@ -750,22 +766,6 @@ describe("Scene/MetadataTableProperty", function () { componentType: "FLOAT64", componentCount: 3, }, - propertyBoolean: { - type: "ARRAY", - componentType: "BOOLEAN", - componentCount: 3, - }, - propertyString: { - type: "ARRAY", - componentType: "STRING", - componentCount: 3, - }, - propertyEnum: { - type: "ARRAY", - componentType: "ENUM", - enumType: "myEnum", - componentCount: 3, - }, }; var propertyValues = { @@ -793,14 +793,6 @@ describe("Scene/MetadataTableProperty", function () { [0, 0, 0], [0, 0, 0], ], - propertyInt64: [ - [BigInt(0), BigInt(0), BigInt(0)], // eslint-disable-line - [BigInt(0), BigInt(0), BigInt(0)], // eslint-disable-line - ], - propertyUint64: [ - [BigInt(0), BigInt(0), BigInt(0)], // eslint-disable-line - [BigInt(0), BigInt(0), BigInt(0)], // eslint-disable-line - ], propertyFloat32: [ [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], @@ -809,6 +801,86 @@ describe("Scene/MetadataTableProperty", function () { [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], ], + }; + + var valuesToSet = { + propertyInt8: [new Cartesian3(-2, -1, 0), new Cartesian3(1, 2, 3)], + propertyUint8: [new Cartesian3(0, 1, 2), new Cartesian3(3, 4, 5)], + propertyInt16: [new Cartesian3(-2, -1, 0), new Cartesian3(1, 2, 3)], + propertyUint16: [new Cartesian3(0, 1, 2), new Cartesian3(3, 4, 5)], + propertyInt32: [new Cartesian3(-2, -1, 0), new Cartesian3(1, 2, 3)], + propertyUint32: [new Cartesian3(0, 1, 2), new Cartesian3(3, 4, 5)], + propertyFloat32: [ + new Cartesian3(-2.0, -1.0, 0.0), + new Cartesian3(1.0, 2.0, 3.0), + ], + propertyFloat64: [ + new Cartesian3(-2.0, -1.0, 0.0), + new Cartesian3(1.0, 2.0, 3.0), + ], + }; + + for (var propertyId in properties) { + if (properties.hasOwnProperty(propertyId)) { + var property = MetadataTester.createProperty({ + property: properties[propertyId], + values: propertyValues[propertyId], + enums: enums, + }); + var expectedValues = valuesToSet[propertyId]; + var length = expectedValues.length; + for (var i = 0; i < length; ++i) { + property.set(i, expectedValues[i]); + var value = property.get(i); + expect(value).toEqual(expectedValues[i]); + // Test setting / getting again + property.set(i, expectedValues[i]); + value = property.get(i); + expect(value).toEqual(expectedValues[i]); + } + } + } + }); + + it("set sets fixed size arrays", function () { + var properties = { + propertyInt64: { + type: "ARRAY", + componentType: "INT64", + componentCount: 3, + }, + propertyUint64: { + type: "ARRAY", + componentType: "UINT64", + componentCount: 3, + }, + propertyBoolean: { + type: "ARRAY", + componentType: "BOOLEAN", + componentCount: 3, + }, + propertyString: { + type: "ARRAY", + componentType: "STRING", + componentCount: 3, + }, + propertyEnum: { + type: "ARRAY", + componentType: "ENUM", + enumType: "myEnum", + componentCount: 3, + }, + }; + + var propertyValues = { + propertyInt64: [ + [BigInt(0), BigInt(0), BigInt(0)], // eslint-disable-line + [BigInt(0), BigInt(0), BigInt(0)], // eslint-disable-line + ], + propertyUint64: [ + [BigInt(0), BigInt(0), BigInt(0)], // eslint-disable-line + [BigInt(0), BigInt(0), BigInt(0)], // eslint-disable-line + ], propertyBoolean: [ [false, false, false], [true, true, true], @@ -824,30 +896,6 @@ describe("Scene/MetadataTableProperty", function () { }; var valuesToSet = { - propertyInt8: [ - [-2, -1, 0], - [1, 2, 3], - ], - propertyUint8: [ - [0, 1, 2], - [3, 4, 5], - ], - propertyInt16: [ - [-2, -1, 0], - [1, 2, 3], - ], - propertyUint16: [ - [0, 1, 2], - [3, 4, 5], - ], - propertyInt32: [ - [-2, -1, 0], - [1, 2, 3], - ], - propertyUint32: [ - [0, 1, 2], - [3, 4, 5], - ], propertyInt64: [ [BigInt(-2), BigInt(-1), BigInt(0)], // eslint-disable-line [BigInt(1), BigInt(2), BigInt(3)], // eslint-disable-line @@ -856,14 +904,6 @@ describe("Scene/MetadataTableProperty", function () { [BigInt(0), BigInt(1), BigInt(2)], // eslint-disable-line [BigInt(3), BigInt(4), BigInt(5)], // eslint-disable-line ], - propertyFloat32: [ - [-2.0, -1.0, 0.0], - [1.0, 2.0, 3.0], - ], - propertyFloat64: [ - [-2.0, -1.0, 0.0], - [1.0, 2.0, 3.0], - ], propertyBoolean: [ [false, true, false], [true, false, true], diff --git a/Specs/Scene/MetadataTableSpec.js b/Specs/Scene/MetadataTableSpec.js index 288ddf91d3eb..c470910b448b 100644 --- a/Specs/Scene/MetadataTableSpec.js +++ b/Specs/Scene/MetadataTableSpec.js @@ -1,4 +1,4 @@ -import { MetadataTable } from "../../Source/Cesium.js"; +import { Cartesian3, MetadataTable } from "../../Source/Cesium.js"; import MetadataTester from "../MetadataTester.js"; describe("Scene/MetadataTable", function () { @@ -308,8 +308,7 @@ describe("Scene/MetadataTable", function () { }); var value = metadataTable.getProperty(0, "position"); - expect(value).toEqual(position); - expect(value).not.toBe(position); // The value is cloned + expect(value).toEqual(Cartesian3.unpack(position)); expect(metadataTable.getProperty(0, "type")).toBe("Other"); }); diff --git a/Specs/Scene/Multiple3DTileContentSpec.js b/Specs/Scene/Multiple3DTileContentSpec.js index d188f176443f..d144d722f1bc 100644 --- a/Specs/Scene/Multiple3DTileContentSpec.js +++ b/Specs/Scene/Multiple3DTileContentSpec.js @@ -349,14 +349,18 @@ describe( var buildingsContent = innerContents[0]; var groupMetadata = buildingsContent.groupMetadata; expect(groupMetadata).toBeDefined(); - expect(groupMetadata.getProperty("color")).toEqual([255, 127, 0]); + expect(groupMetadata.getProperty("color")).toEqual( + new Cartesian3(255, 127, 0) + ); expect(groupMetadata.getProperty("priority")).toBe(10); expect(groupMetadata.getProperty("isInstanced")).toBe(false); var cubesContent = innerContents[1]; groupMetadata = cubesContent.groupMetadata; expect(groupMetadata).toBeDefined(); - expect(groupMetadata.getProperty("color")).toEqual([0, 255, 127]); + expect(groupMetadata.getProperty("color")).toEqual( + new Cartesian3(0, 255, 127) + ); expect(groupMetadata.getProperty("priority")).toBe(5); expect(groupMetadata.getProperty("isInstanced")).toBe(true); }); diff --git a/Specs/Scene/TilesetMetadataSpec.js b/Specs/Scene/TilesetMetadataSpec.js index 87ea2a5274ec..7310d6a58e03 100644 --- a/Specs/Scene/TilesetMetadataSpec.js +++ b/Specs/Scene/TilesetMetadataSpec.js @@ -1,4 +1,8 @@ -import { MetadataClass, TilesetMetadata } from "../../Source/Cesium.js"; +import { + Cartesian3, + MetadataClass, + TilesetMetadata, +} from "../../Source/Cesium.js"; describe("Scene/TilesetMetadata", function () { it("creates tileset metadata with default values", function () { @@ -306,8 +310,7 @@ describe("Scene/TilesetMetadata", function () { }); var value = tilesetMetadata.getProperty("position"); - expect(value).toEqual(position); - expect(value).not.toBe(position); // The value is cloned + expect(value).toEqual(Cartesian3.unpack(position)); }); it("getProperty returns the default value when the property is missing", function () { @@ -333,8 +336,7 @@ describe("Scene/TilesetMetadata", function () { }); var value = tilesetMetadata.getProperty("position"); - expect(value).toEqual(position); - expect(value).not.toBe(position); // The value is cloned + expect(value).toEqual(Cartesian3.unpack(position)); }); it("getProperty throws without propertyId", function () { @@ -379,7 +381,7 @@ describe("Scene/TilesetMetadata", function () { }, }); - var position = [1.0, 1.0, 1.0]; + var position = new Cartesian3(1.0, 1.0, 1.0); expect(tilesetMetadata.setProperty("position", position)).toBe(true); expect(tilesetMetadata.getProperty("position")).toEqual(position); expect(tilesetMetadata.getProperty("position")).not.toBe(position); // The value is cloned diff --git a/Specs/Scene/parseBatchTableSpec.js b/Specs/Scene/parseBatchTableSpec.js index efd5cd1d93ee..455d8ad6a011 100644 --- a/Specs/Scene/parseBatchTableSpec.js +++ b/Specs/Scene/parseBatchTableSpec.js @@ -1,4 +1,10 @@ -import { parseBatchTable, MetadataType } from "../../Source/Cesium.js"; +import { + Cartesian2, + Cartesian3, + Cartesian4, + parseBatchTable, + MetadataType, +} from "../../Source/Cesium.js"; describe("Scene/parseBatchTable", function () { var batchTableJson = {}; @@ -170,14 +176,15 @@ describe("Scene/parseBatchTable", function () { expect(properties.dvec4Property.componentCount).toBe(4); var featureTable = metadata.getFeatureTable("_batchTable"); - expect(featureTable.getProperty(0, "vec2Property")).toEqual([0.0, 0.0]); - expect(featureTable.getProperty(0, "uvec3Property")).toEqual([0, 0, 0]); - expect(featureTable.getProperty(0, "dvec4Property")).toEqual([ - 0.0, - 0.0, - 0.0, - 0.0, - ]); + expect(featureTable.getProperty(0, "vec2Property")).toEqual( + new Cartesian2(0.0, 0.0) + ); + expect(featureTable.getProperty(0, "uvec3Property")).toEqual( + new Cartesian3(0, 0, 0) + ); + expect(featureTable.getProperty(0, "dvec4Property")).toEqual( + new Cartesian4(0.0, 0.0, 0.0, 0.0) + ); }); it("parses batch table with JSON properties", function () {