mirror of https://github.com/CesiumGS/cesium.git
775 lines
24 KiB
JavaScript
775 lines
24 KiB
JavaScript
import {
|
|
Cartesian2,
|
|
Cartesian3,
|
|
Cartesian4,
|
|
ComponentDatatype,
|
|
parseBatchTable,
|
|
MetadataClass,
|
|
MetadataComponentType,
|
|
MetadataType,
|
|
RuntimeError,
|
|
} from "../../index.js";
|
|
|
|
describe("Scene/parseBatchTable", function () {
|
|
const batchTableJson = {};
|
|
const count = 3;
|
|
const className = MetadataClass.BATCH_TABLE_CLASS_NAME;
|
|
|
|
function sortByName(a, b) {
|
|
if (a.name < b.name) {
|
|
return -1;
|
|
}
|
|
|
|
if (a.name > b.name) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
it("throws without count", function () {
|
|
expect(function () {
|
|
return parseBatchTable({
|
|
count: undefined,
|
|
batchTable: batchTableJson,
|
|
});
|
|
}).toThrowDeveloperError();
|
|
});
|
|
|
|
it("throws without batchTable", function () {
|
|
expect(function () {
|
|
return parseBatchTable({
|
|
count: count,
|
|
batchTable: undefined,
|
|
});
|
|
}).toThrowDeveloperError();
|
|
});
|
|
|
|
it("parses batch table with no properties", function () {
|
|
const metadata = parseBatchTable({
|
|
count: count,
|
|
batchTable: {},
|
|
});
|
|
|
|
expect(metadata).toBeDefined();
|
|
});
|
|
|
|
it("parses batch table with binary properties", function () {
|
|
const binaryBatchTable = {
|
|
height: {
|
|
byteOffset: 0,
|
|
componentType: "FLOAT",
|
|
type: "SCALAR",
|
|
},
|
|
};
|
|
|
|
const heightValues = new Float32Array([10.0, 15.0, 25.0]);
|
|
const binaryBody = new Uint8Array(heightValues.buffer);
|
|
|
|
const metadata = parseBatchTable({
|
|
count: 3,
|
|
batchTable: binaryBatchTable,
|
|
binaryBody: binaryBody,
|
|
});
|
|
const propertyTable = metadata.getPropertyTable(0);
|
|
expect(propertyTable.id).toBe(0);
|
|
expect(propertyTable.name).toBe("Batch Table");
|
|
|
|
expect(propertyTable.getProperty(0, "height")).toBe(10.0);
|
|
expect(propertyTable.getProperty(1, "height")).toBe(15.0);
|
|
expect(propertyTable.getProperty(2, "height")).toBe(25.0);
|
|
});
|
|
|
|
it("transcodes scalars to correct types", function () {
|
|
// making use of the fact that 0 is represented as NUL bytes
|
|
// in all of the above types
|
|
const binaryBatchTable = {
|
|
uint8Property: {
|
|
byteOffset: 0,
|
|
componentType: "UNSIGNED_BYTE",
|
|
type: "SCALAR",
|
|
},
|
|
uint16Property: {
|
|
byteOffset: 0,
|
|
componentType: "UNSIGNED_SHORT",
|
|
type: "SCALAR",
|
|
},
|
|
uint32Property: {
|
|
byteOffset: 0,
|
|
componentType: "UNSIGNED_INT",
|
|
type: "SCALAR",
|
|
},
|
|
int8Property: {
|
|
byteOffset: 0,
|
|
componentType: "BYTE",
|
|
type: "SCALAR",
|
|
},
|
|
int16Property: {
|
|
byteOffset: 0,
|
|
componentType: "SHORT",
|
|
type: "SCALAR",
|
|
},
|
|
int32Property: {
|
|
byteOffset: 0,
|
|
componentType: "INT",
|
|
type: "SCALAR",
|
|
},
|
|
floatProperty: {
|
|
byteOffset: 0,
|
|
componentType: "FLOAT",
|
|
type: "SCALAR",
|
|
},
|
|
doubleProperty: {
|
|
byteOffset: 0,
|
|
componentType: "DOUBLE",
|
|
type: "SCALAR",
|
|
},
|
|
};
|
|
|
|
// largest type is a double
|
|
const binaryBody = new Uint8Array(8);
|
|
|
|
const metadata = parseBatchTable({
|
|
count: 1,
|
|
batchTable: binaryBatchTable,
|
|
binaryBody: binaryBody,
|
|
});
|
|
const properties = metadata.schema.classes[className].properties;
|
|
|
|
expect(properties.uint8Property.componentType).toBe(
|
|
MetadataComponentType.UINT8,
|
|
);
|
|
expect(properties.uint16Property.componentType).toBe(
|
|
MetadataComponentType.UINT16,
|
|
);
|
|
expect(properties.uint32Property.componentType).toBe(
|
|
MetadataComponentType.UINT32,
|
|
);
|
|
expect(properties.int8Property.componentType).toBe(
|
|
MetadataComponentType.INT8,
|
|
);
|
|
expect(properties.int16Property.componentType).toBe(
|
|
MetadataComponentType.INT16,
|
|
);
|
|
expect(properties.int32Property.componentType).toBe(
|
|
MetadataComponentType.INT32,
|
|
);
|
|
expect(properties.floatProperty.componentType).toBe(
|
|
MetadataComponentType.FLOAT32,
|
|
);
|
|
expect(properties.doubleProperty.componentType).toBe(
|
|
MetadataComponentType.FLOAT64,
|
|
);
|
|
|
|
const propertyTable = metadata.getPropertyTable(0);
|
|
expect(propertyTable.getProperty(0, "uint8Property")).toBe(0);
|
|
expect(propertyTable.getProperty(0, "uint16Property")).toBe(0);
|
|
expect(propertyTable.getProperty(0, "uint32Property")).toBe(0);
|
|
expect(propertyTable.getProperty(0, "int8Property")).toBe(0);
|
|
expect(propertyTable.getProperty(0, "int16Property")).toBe(0);
|
|
expect(propertyTable.getProperty(0, "int32Property")).toBe(0);
|
|
expect(propertyTable.getProperty(0, "floatProperty")).toBe(0.0);
|
|
expect(propertyTable.getProperty(0, "doubleProperty")).toBe(0.0);
|
|
});
|
|
|
|
it("transcodes binary vectors to vector types", function () {
|
|
const vectorBatchTable = {
|
|
vec2Property: {
|
|
byteOffset: 0,
|
|
componentType: "FLOAT",
|
|
type: "VEC2",
|
|
},
|
|
uvec3Property: {
|
|
byteOffset: 0,
|
|
componentType: "UNSIGNED_INT",
|
|
type: "VEC3",
|
|
},
|
|
dvec4Property: {
|
|
byteOffset: 0,
|
|
componentType: "DOUBLE",
|
|
type: "VEC4",
|
|
},
|
|
};
|
|
// largest type is a vec4 of doubles
|
|
const binaryBody = new Uint8Array(8 * 4);
|
|
|
|
const metadata = parseBatchTable({
|
|
count: 1,
|
|
batchTable: vectorBatchTable,
|
|
binaryBody: binaryBody,
|
|
});
|
|
const properties = metadata.schema.classes[className].properties;
|
|
|
|
expect(properties.vec2Property.type).toBe(MetadataType.VEC2);
|
|
expect(properties.uvec3Property.type).toBe(MetadataType.VEC3);
|
|
expect(properties.dvec4Property.type).toBe(MetadataType.VEC4);
|
|
expect(properties.vec2Property.componentType).toBe(
|
|
MetadataComponentType.FLOAT32,
|
|
);
|
|
expect(properties.uvec3Property.componentType).toBe(
|
|
MetadataComponentType.UINT32,
|
|
);
|
|
expect(properties.dvec4Property.componentType).toBe(
|
|
MetadataComponentType.FLOAT64,
|
|
);
|
|
|
|
const propertyTable = metadata.getPropertyTable(0);
|
|
expect(propertyTable.getProperty(0, "vec2Property")).toEqual(
|
|
new Cartesian2(0.0, 0.0),
|
|
);
|
|
expect(propertyTable.getProperty(0, "uvec3Property")).toEqual(
|
|
new Cartesian3(0, 0, 0),
|
|
);
|
|
expect(propertyTable.getProperty(0, "dvec4Property")).toEqual(
|
|
new Cartesian4(0.0, 0.0, 0.0, 0.0),
|
|
);
|
|
});
|
|
|
|
it("parses batch table with JSON properties", function () {
|
|
const jsonBatchTable = {
|
|
location: [
|
|
[0, 0],
|
|
[1, 0],
|
|
],
|
|
payload: [
|
|
{
|
|
name: "Shopping Center",
|
|
color: [0.3, 0.3, 0.3],
|
|
stores: 15,
|
|
},
|
|
{
|
|
name: "School",
|
|
color: [0.6, 0.3, 0.3],
|
|
students: 1621,
|
|
},
|
|
],
|
|
};
|
|
|
|
const metadata = parseBatchTable({
|
|
count: 2,
|
|
batchTable: jsonBatchTable,
|
|
});
|
|
|
|
const properties = metadata.schema.classes[className].properties;
|
|
expect(properties).toEqual({});
|
|
|
|
const propertyTable = metadata.getPropertyTable(0);
|
|
expect(propertyTable.getProperty(0, "location")).toEqual(
|
|
jsonBatchTable.location[0],
|
|
);
|
|
expect(propertyTable.getProperty(1, "location")).toEqual(
|
|
jsonBatchTable.location[1],
|
|
);
|
|
expect(propertyTable.getProperty(0, "payload")).toEqual(
|
|
jsonBatchTable.payload[0],
|
|
);
|
|
expect(propertyTable.getProperty(1, "payload")).toEqual(
|
|
jsonBatchTable.payload[1],
|
|
);
|
|
});
|
|
|
|
const hierarchy = {
|
|
classes: [
|
|
{
|
|
name: "Wheels",
|
|
length: 8,
|
|
instances: {
|
|
tire_location: [
|
|
"front_left",
|
|
"front_right",
|
|
"back_left",
|
|
"back_right",
|
|
"front_left",
|
|
"front_right",
|
|
"back_left",
|
|
"back_right",
|
|
],
|
|
},
|
|
},
|
|
{
|
|
name: "Car",
|
|
length: 2,
|
|
instances: {
|
|
color: ["blue", "red"],
|
|
type: ["sedan", "truck"],
|
|
year: ["2020", "2018"],
|
|
},
|
|
},
|
|
],
|
|
instancesLength: 10,
|
|
classIds: [0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
|
parentIds: [4, 4, 4, 4, 4, 9, 9, 9, 9, 9],
|
|
parentCounts: [1, 1, 1, 1, 0, 1, 1, 1, 1, 0],
|
|
};
|
|
|
|
it("warns for deprecated HIERARCHY extension", function () {
|
|
const warn = spyOn(parseBatchTable, "_deprecationWarning");
|
|
const oldHierarchyBatchTable = {
|
|
HIERARCHY: hierarchy,
|
|
};
|
|
|
|
const metadata = parseBatchTable({
|
|
count: 10,
|
|
batchTable: oldHierarchyBatchTable,
|
|
});
|
|
|
|
expect(warn).toHaveBeenCalled();
|
|
|
|
const properties = metadata.schema.classes[className].properties;
|
|
expect(properties).toEqual({});
|
|
|
|
const propertyTable = metadata.getPropertyTable(0);
|
|
expect(propertyTable.getProperty(0, "tire_location")).toBe("front_left");
|
|
expect(propertyTable.getProperty(0, "color")).toBe("blue");
|
|
expect(propertyTable.getProperty(0, "type")).toBe("sedan");
|
|
expect(propertyTable.getProperty(0, "year")).toBe("2020");
|
|
|
|
expect(propertyTable.getProperty(4, "tire_location")).not.toBeDefined();
|
|
expect(propertyTable.getProperty(4, "color")).toBe("blue");
|
|
expect(propertyTable.getProperty(4, "type")).toBe("sedan");
|
|
expect(propertyTable.getProperty(4, "year")).toBe("2020");
|
|
|
|
expect(propertyTable.getProperty(6, "tire_location")).toBe("front_right");
|
|
expect(propertyTable.getProperty(6, "color")).toBe("red");
|
|
expect(propertyTable.getProperty(6, "type")).toBe("truck");
|
|
expect(propertyTable.getProperty(6, "year")).toBe("2018");
|
|
|
|
expect(propertyTable.getProperty(9, "tire_location")).not.toBeDefined();
|
|
expect(propertyTable.getProperty(9, "color")).toBe("red");
|
|
expect(propertyTable.getProperty(9, "type")).toBe("truck");
|
|
expect(propertyTable.getProperty(9, "year")).toBe("2018");
|
|
});
|
|
|
|
it("parses batch table with hierarchy", function () {
|
|
const oldHierarchyBatchTable = {
|
|
extensions: {
|
|
"3DTILES_batch_table_hierarchy": hierarchy,
|
|
},
|
|
};
|
|
|
|
const metadata = parseBatchTable({
|
|
count: 10,
|
|
batchTable: oldHierarchyBatchTable,
|
|
});
|
|
|
|
const properties = metadata.schema.classes[className].properties;
|
|
expect(properties).toEqual({});
|
|
|
|
const propertyTable = metadata.getPropertyTable(0);
|
|
expect(propertyTable.getProperty(0, "tire_location")).toBe("front_left");
|
|
expect(propertyTable.getProperty(0, "color")).toBe("blue");
|
|
expect(propertyTable.getProperty(0, "type")).toBe("sedan");
|
|
expect(propertyTable.getProperty(0, "year")).toBe("2020");
|
|
|
|
expect(propertyTable.getProperty(4, "tire_location")).not.toBeDefined();
|
|
expect(propertyTable.getProperty(4, "color")).toBe("blue");
|
|
expect(propertyTable.getProperty(4, "type")).toBe("sedan");
|
|
expect(propertyTable.getProperty(4, "year")).toBe("2020");
|
|
|
|
expect(propertyTable.getProperty(6, "tire_location")).toBe("front_right");
|
|
expect(propertyTable.getProperty(6, "color")).toBe("red");
|
|
expect(propertyTable.getProperty(6, "type")).toBe("truck");
|
|
expect(propertyTable.getProperty(6, "year")).toBe("2018");
|
|
|
|
expect(propertyTable.getProperty(9, "tire_location")).not.toBeDefined();
|
|
expect(propertyTable.getProperty(9, "color")).toBe("red");
|
|
expect(propertyTable.getProperty(9, "type")).toBe("truck");
|
|
expect(propertyTable.getProperty(9, "year")).toBe("2018");
|
|
});
|
|
|
|
it("stores extras and extensions in the transcoded StructuralMetadata", function () {
|
|
const batchTable = {
|
|
extras: {
|
|
author: "Cesium",
|
|
date: "2021-04-15",
|
|
},
|
|
extensions: {
|
|
"3DTILES_extension": {},
|
|
},
|
|
};
|
|
|
|
const metadata = parseBatchTable({
|
|
count: 1,
|
|
batchTable: batchTable,
|
|
});
|
|
|
|
expect(metadata.extras).toBe(batchTable.extras);
|
|
expect(metadata.extensions).toBe(batchTable.extensions);
|
|
});
|
|
|
|
it("throws if binaryBody is needed and not provided", function () {
|
|
const binaryBatchTable = {
|
|
height: {
|
|
byteOffset: 0,
|
|
componentType: "FLOAT",
|
|
type: "SCALAR",
|
|
},
|
|
};
|
|
|
|
expect(function () {
|
|
return parseBatchTable({
|
|
count: 1,
|
|
batchTable: binaryBatchTable,
|
|
binaryBody: undefined,
|
|
});
|
|
}).toThrowError(RuntimeError);
|
|
});
|
|
|
|
it("throws if parseAsPropertyAttributes is true and customAttributeOutput is not provided", function () {
|
|
const binaryBatchTable = {
|
|
height: {
|
|
byteOffset: 0,
|
|
componentType: "FLOAT",
|
|
type: "SCALAR",
|
|
},
|
|
};
|
|
|
|
const heightValues = new Float32Array([10.0, 15.0, 25.0]);
|
|
const binaryBody = new Uint8Array(heightValues.buffer);
|
|
|
|
expect(function () {
|
|
return parseBatchTable({
|
|
count: 3,
|
|
batchTable: binaryBatchTable,
|
|
binaryBody: binaryBody,
|
|
parseAsPropertyAttributes: true,
|
|
customAttributeOutput: undefined,
|
|
});
|
|
}).toThrowDeveloperError();
|
|
});
|
|
|
|
it("parses batch table as property attributes", function () {
|
|
const binaryBatchTable = {
|
|
height: {
|
|
byteOffset: 0,
|
|
componentType: "FLOAT",
|
|
type: "SCALAR",
|
|
},
|
|
windDirection: {
|
|
byteOffset: 12,
|
|
componentType: "FLOAT",
|
|
type: "VEC2",
|
|
},
|
|
};
|
|
|
|
// prettier-ignore
|
|
const values = new Float32Array([
|
|
// height values (float)
|
|
10.0, 15.0, 25.0,
|
|
// wind direction values (vec2)
|
|
1.0, 0.0,
|
|
1.1, 0.4,
|
|
0.3, 0.2,
|
|
]);
|
|
const binaryBody = new Uint8Array(values.buffer);
|
|
|
|
const customAttributes = [];
|
|
const metadata = parseBatchTable({
|
|
count: 3,
|
|
batchTable: binaryBatchTable,
|
|
binaryBody: binaryBody,
|
|
parseAsPropertyAttributes: true,
|
|
customAttributeOutput: customAttributes,
|
|
});
|
|
|
|
expect(customAttributes.length).toBe(2);
|
|
|
|
// Since the original properties is an unordered collection, sort
|
|
// to be sure of the order
|
|
const [heightAttribute, windDirectionAttribute] =
|
|
customAttributes.sort(sortByName);
|
|
expect(heightAttribute.name).toBe("_HEIGHT");
|
|
expect(heightAttribute.count).toBe(3);
|
|
expect(heightAttribute.type).toBe("SCALAR");
|
|
expect(heightAttribute.componentDatatype).toBe(ComponentDatatype.FLOAT);
|
|
expect(heightAttribute.typedArray).toEqual(values.slice(0, 3));
|
|
|
|
expect(windDirectionAttribute.name).toBe("_WINDDIRECTION");
|
|
expect(windDirectionAttribute.count).toBe(3);
|
|
expect(windDirectionAttribute.type).toBe("VEC2");
|
|
expect(windDirectionAttribute.componentDatatype).toBe(
|
|
ComponentDatatype.FLOAT,
|
|
);
|
|
expect(windDirectionAttribute.typedArray).toEqual(values.slice(3));
|
|
|
|
// The property table will not be created
|
|
const propertyTable = metadata.getPropertyTable(0);
|
|
expect(propertyTable).not.toBeDefined();
|
|
|
|
expect(metadata.propertyAttributes.length).toBe(1);
|
|
const [propertyAttribute] = metadata.propertyAttributes;
|
|
const metadataClass = propertyAttribute.class;
|
|
expect(metadataClass.id).toBe(MetadataClass.BATCH_TABLE_CLASS_NAME);
|
|
const heightClassProperty = metadataClass.properties.height;
|
|
expect(heightClassProperty.name).toBe("height");
|
|
expect(heightClassProperty.type).toBe(MetadataType.SCALAR);
|
|
expect(heightClassProperty.componentType).toBe(
|
|
MetadataComponentType.FLOAT32,
|
|
);
|
|
const windClassProperty = metadataClass.properties["windDirection"];
|
|
expect(windClassProperty.name).toBe("windDirection");
|
|
expect(windClassProperty.type).toBe(MetadataType.VEC2);
|
|
expect(windClassProperty.componentType).toBe(MetadataComponentType.FLOAT32);
|
|
|
|
const properties = propertyAttribute.properties;
|
|
const heightProperty = properties.height;
|
|
expect(heightProperty.attribute).toBe("_HEIGHT");
|
|
const windProperty = properties.windDirection;
|
|
expect(windProperty.attribute).toBe("_WINDDIRECTION");
|
|
});
|
|
|
|
it("sanitizes property attribute property IDs for use in GLSL", function () {
|
|
const binaryBatchTable = {
|
|
// will be converted to Height
|
|
"Height ⛰️": {
|
|
byteOffset: 0,
|
|
componentType: "FLOAT",
|
|
type: "SCALAR",
|
|
},
|
|
// gl_ prefix is reserved in GLSL and will be removed.
|
|
// this leaves 1234, which starts with a number, so a _ prefix will be
|
|
// added. Result: _1234
|
|
gl_1234: {
|
|
byteOffset: 12,
|
|
componentType: "FLOAT",
|
|
type: "VEC2",
|
|
},
|
|
};
|
|
|
|
// prettier-ignore
|
|
const values = new Float32Array([
|
|
10.0, 15.0, 25.0,
|
|
1.0, 0.0,
|
|
1.1, 0.4,
|
|
0.3, 0.2,
|
|
]);
|
|
const binaryBody = new Uint8Array(values.buffer);
|
|
|
|
const customAttributes = [];
|
|
const metadata = parseBatchTable({
|
|
count: 3,
|
|
batchTable: binaryBatchTable,
|
|
binaryBody: binaryBody,
|
|
parseAsPropertyAttributes: true,
|
|
customAttributeOutput: customAttributes,
|
|
});
|
|
|
|
expect(customAttributes.length).toBe(2);
|
|
|
|
// Since the original properties is an unordered collection, sort
|
|
// to be sure of the order.
|
|
const [numericAttribute, unicodeAttribute] =
|
|
customAttributes.sort(sortByName);
|
|
|
|
// Attributes are converted to upper-case like glTF attributes.
|
|
expect(numericAttribute.name).toBe("_1234");
|
|
expect(unicodeAttribute.name).toBe("_HEIGHT_");
|
|
|
|
// In the schema, the IDs are valid GLSL identifiers, while the name
|
|
// is the original property ID which may contain unicode.
|
|
const [propertyAttribute] = metadata.propertyAttributes;
|
|
const metadataClass = propertyAttribute.class;
|
|
const numericClassProperty = metadataClass.properties["_1234"];
|
|
expect(numericClassProperty.name).toBe("gl_1234");
|
|
const unicodeClassProperty = metadataClass.properties["Height_"];
|
|
expect(unicodeClassProperty.name).toBe("Height ⛰️");
|
|
|
|
const properties = propertyAttribute.properties;
|
|
const numericProperty = properties["_1234"];
|
|
expect(numericProperty.attribute).toBe("_1234");
|
|
const unicodeProperty = properties["Height_"];
|
|
expect(unicodeProperty.attribute).toBe("_HEIGHT_");
|
|
});
|
|
|
|
it("creates placeholder IDs for invalid GLSL identifiers", function () {
|
|
const binaryBatchTable = {
|
|
"✖️✖️✖️": {
|
|
byteOffset: 0,
|
|
componentType: "FLOAT",
|
|
type: "SCALAR",
|
|
},
|
|
temperature: {
|
|
byteOffset: 12,
|
|
componentType: "FLOAT",
|
|
type: "SCALAR",
|
|
},
|
|
// gl_ prefix will be removed, leading to a name collision with
|
|
// "temperature
|
|
gl_temperature: {
|
|
byteOffset: 24,
|
|
componentType: "FLOAT",
|
|
type: "SCALAR",
|
|
},
|
|
};
|
|
|
|
// prettier-ignore
|
|
const values = new Float32Array([
|
|
10.0, 15.0, 25.0,
|
|
20.0, 30.0, 15.0,
|
|
25.0, 20.0, 20.0,
|
|
]);
|
|
const binaryBody = new Uint8Array(values.buffer);
|
|
|
|
const customAttributes = [];
|
|
const metadata = parseBatchTable({
|
|
count: 3,
|
|
batchTable: binaryBatchTable,
|
|
binaryBody: binaryBody,
|
|
parseAsPropertyAttributes: true,
|
|
customAttributeOutput: customAttributes,
|
|
});
|
|
|
|
expect(customAttributes.length).toBe(3);
|
|
|
|
// Attributes are processed in a non-deterministic order (due to looping
|
|
// over a dictionary), but the set of results is constant.
|
|
const attributeNames = customAttributes.map(function (attribute) {
|
|
return attribute.name;
|
|
});
|
|
expect(attributeNames.sort()).toEqual(["_", "_PROPERTY_0", "_TEMPERATURE"]);
|
|
|
|
const [propertyAttribute] = metadata.propertyAttributes;
|
|
const metadataClass = propertyAttribute.class;
|
|
const classProperties = [
|
|
metadataClass.properties._,
|
|
metadataClass.properties.property_0,
|
|
metadataClass.properties.temperature,
|
|
];
|
|
|
|
// Again, the order is non-deterministic, but the attribute names will
|
|
// always be the original names
|
|
const classPropertyNames = classProperties.map(function (classProperty) {
|
|
return classProperty.name;
|
|
});
|
|
expect(classPropertyNames.sort()).toEqual(
|
|
Object.keys(binaryBatchTable).sort(),
|
|
);
|
|
|
|
const properties = propertyAttribute.properties;
|
|
expect(Object.keys(properties).sort()).toEqual([
|
|
"_",
|
|
"property_0",
|
|
"temperature",
|
|
]);
|
|
|
|
const semantics = Object.values(properties).map(function (property) {
|
|
return property.attribute;
|
|
});
|
|
expect(semantics.sort()).toEqual(["_", "_PROPERTY_0", "_TEMPERATURE"]);
|
|
});
|
|
|
|
it("handles typed arrays decoded from Draco pnts", function () {
|
|
const binaryBatchTable = {
|
|
height: {
|
|
byteOffset: 0,
|
|
componentType: "FLOAT",
|
|
type: "SCALAR",
|
|
// when decoding Draco, each property is stored in a separate typed
|
|
// array.
|
|
typedArray: new Float32Array([10.0, 15.0, 25.0]),
|
|
},
|
|
windDirection: {
|
|
byteOffset: 12,
|
|
componentType: "FLOAT",
|
|
type: "VEC2",
|
|
// prettier-ignore
|
|
typedArray: new Float32Array([
|
|
1.0, 0.0,
|
|
1.1, 0.4,
|
|
0.3, 0.2,
|
|
]),
|
|
},
|
|
};
|
|
// simulate the common case where everything is Draco-compressed.
|
|
const binaryBody = undefined;
|
|
|
|
const customAttributes = [];
|
|
const metadata = parseBatchTable({
|
|
count: 3,
|
|
batchTable: binaryBatchTable,
|
|
binaryBody: binaryBody,
|
|
parseAsPropertyAttributes: true,
|
|
customAttributeOutput: customAttributes,
|
|
});
|
|
|
|
expect(customAttributes.length).toBe(2);
|
|
|
|
// Since the original properties is an unordered collection, sort
|
|
// to be sure of the order
|
|
const [heightAttribute, windDirectionAttribute] =
|
|
customAttributes.sort(sortByName);
|
|
expect(heightAttribute.name).toBe("_HEIGHT");
|
|
expect(heightAttribute.count).toBe(3);
|
|
expect(heightAttribute.type).toBe("SCALAR");
|
|
expect(heightAttribute.componentDatatype).toBe(ComponentDatatype.FLOAT);
|
|
expect(heightAttribute.typedArray).toEqual(
|
|
binaryBatchTable.height.typedArray,
|
|
);
|
|
|
|
expect(windDirectionAttribute.name).toBe("_WINDDIRECTION");
|
|
expect(windDirectionAttribute.count).toBe(3);
|
|
expect(windDirectionAttribute.type).toBe("VEC2");
|
|
expect(windDirectionAttribute.componentDatatype).toBe(
|
|
ComponentDatatype.FLOAT,
|
|
);
|
|
expect(windDirectionAttribute.typedArray).toEqual(
|
|
binaryBatchTable.windDirection.typedArray,
|
|
);
|
|
|
|
// No property table will be created.
|
|
const propertyTable = metadata.getPropertyTable(0);
|
|
expect(propertyTable).not.toBeDefined();
|
|
|
|
expect(metadata.propertyAttributes.length).toBe(1);
|
|
const [propertyAttribute] = metadata.propertyAttributes;
|
|
const metadataClass = propertyAttribute.class;
|
|
expect(metadataClass.id).toBe(MetadataClass.BATCH_TABLE_CLASS_NAME);
|
|
const heightClassProperty = metadataClass.properties.height;
|
|
expect(heightClassProperty.name).toBe("height");
|
|
expect(heightClassProperty.type).toBe(MetadataType.SCALAR);
|
|
expect(heightClassProperty.componentType).toBe(
|
|
MetadataComponentType.FLOAT32,
|
|
);
|
|
const windClassProperty = metadataClass.properties["windDirection"];
|
|
expect(windClassProperty.name).toBe("windDirection");
|
|
expect(windClassProperty.type).toBe(MetadataType.VEC2);
|
|
expect(windClassProperty.componentType).toBe(MetadataComponentType.FLOAT32);
|
|
|
|
const properties = propertyAttribute.properties;
|
|
const heightProperty = properties.height;
|
|
expect(heightProperty.attribute).toBe("_HEIGHT");
|
|
const windProperty = properties.windDirection;
|
|
expect(windProperty.attribute).toBe("_WINDDIRECTION");
|
|
});
|
|
|
|
it("logs a warning and converts integer attribute property to float", function () {
|
|
const binaryBatchTable = {
|
|
height: {
|
|
byteOffset: 0,
|
|
componentType: "INT",
|
|
type: "SCALAR",
|
|
},
|
|
};
|
|
|
|
const heightValues = new Int32Array([10, 15, 25]);
|
|
const binaryBody = new Uint8Array(heightValues.buffer);
|
|
|
|
spyOn(parseBatchTable, "_oneTimeWarning");
|
|
const customAttributes = [];
|
|
parseBatchTable({
|
|
count: 3,
|
|
batchTable: binaryBatchTable,
|
|
binaryBody: binaryBody,
|
|
parseAsPropertyAttributes: true,
|
|
customAttributeOutput: customAttributes,
|
|
});
|
|
expect(customAttributes.length).toBe(1);
|
|
const [heightAttribute] = customAttributes.sort(sortByName);
|
|
expect(heightAttribute.name).toBe("_HEIGHT");
|
|
expect(heightAttribute.count).toBe(3);
|
|
expect(heightAttribute.type).toBe("SCALAR");
|
|
expect(heightAttribute.componentDatatype).toBe(ComponentDatatype.FLOAT);
|
|
expect(parseBatchTable._oneTimeWarning).toHaveBeenCalled();
|
|
});
|
|
});
|