Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3D Tiles Next Metadata: Automatically unpack vector types #9495

Merged
merged 5 commits into from
Apr 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 103 additions & 1 deletion Source/Scene/MetadataClassProperty.js
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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 <code>ARRAY</code> 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 <code>ARRAY</code> 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.
*
Expand All @@ -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) {
Expand All @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions Source/Scene/MetadataEntity.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ MetadataEntity.getProperty = function (

if (defined(classProperty)) {
value = classProperty.normalize(value);
value = classProperty.unpackVectorTypes(value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future we may want to consider adding a result parameter to getProperty so it doesn't need to allocate the cartesian object. Looking at Cesium3DTileBatchTable it doesn't take a result parameter for getProperty either, maybe because the type could be anything without the new stricter type system?

}

return value;
Expand Down Expand Up @@ -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);
}
}
Expand Down
3 changes: 2 additions & 1 deletion Source/Scene/MetadataTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion Source/Scene/MetadataTableProperty.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

/**
Expand All @@ -209,6 +210,7 @@ MetadataTableProperty.prototype.set = function (index, value) {
}
//>>includeEnd('debug');

value = classProperty.packVectorTypes(value);
value = classProperty.unnormalize(value);

set(this, index, value);
Expand Down
25 changes: 25 additions & 0 deletions Source/Scene/MetadataType.js
Original file line number Diff line number Diff line change
Expand Up @@ -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].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
58 changes: 23 additions & 35 deletions Specs/Scene/Cesium3DTileFeatureSpec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Cartesian3,
Cartesian4,
Cesium3DTileFeature,
HeadingPitchRange,
} from "../../Source/Cesium.js";
Expand Down Expand Up @@ -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);
});

Expand All @@ -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"
);
Expand All @@ -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);
Expand All @@ -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
Expand Down
20 changes: 10 additions & 10 deletions Specs/Scene/Cesium3DTilesetSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
},
};
Expand Down Expand Up @@ -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);
Expand Down
Loading