| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- import Cartesian2 from "../Core/Cartesian2.js";
- import Cartesian3 from "../Core/Cartesian3.js";
- import Cartesian4 from "../Core/Cartesian4.js";
- import defined from "../Core/defined.js";
- import Matrix2 from "../Core/Matrix2.js";
- import Matrix3 from "../Core/Matrix3.js";
- import Matrix4 from "../Core/Matrix4.js";
- import RuntimeError from "../Core/RuntimeError.js";
- import MetadataClassProperty from "./MetadataClassProperty.js";
- import MetadataComponentType from "./MetadataComponentType.js";
- import MetadataType from "./MetadataType.js";
-
- /**
- * Utility functions for metadata picking.
- *
- * These are used by the `Picking.pickMetadata` function to decode
- * the metadata values that have been read from the frame buffer
- * into the actual metadata values, according to the structure
- * defined by the `MetadataClassProperty`.
- *
- * @private
- */
- const MetadataPicking = {};
-
- /**
- * Returns the value at the specified index of the given data view,
- * interpreting the data to have the given component type.
- *
- * @param {MetadataComponentType} componentType The `MetadataComponentType`
- * @param {DataView} dataView The data view
- * @param {number} index The index (byte offset)
- * @returns {number|bigint|undefined} The value
- * @throws RuntimeError If the given component type is not a valid
- * `MetadataComponentType`
- * @throws RangeError If reading the data from the given data view would
- * cause an out-of-bounds access
- *
- * @private
- */
- MetadataPicking.decodeRawMetadataValue = function (
- componentType,
- dataView,
- index,
- ) {
- switch (componentType) {
- case MetadataComponentType.INT8:
- return dataView.getInt8(index);
- case MetadataComponentType.UINT8:
- return dataView.getUint8(index);
- case MetadataComponentType.INT16:
- return dataView.getInt16(index, true);
- case MetadataComponentType.UINT16:
- return dataView.getUint16(index, true);
- case MetadataComponentType.INT32:
- return dataView.getInt32(index, true);
- case MetadataComponentType.UINT32:
- return dataView.getUint32(index, true);
- case MetadataComponentType.INT64:
- return dataView.getBigInt64(index, true);
- case MetadataComponentType.UINT64:
- return dataView.getBigUint64(index, true);
- case MetadataComponentType.FLOAT32:
- return dataView.getFloat32(index, true);
- case MetadataComponentType.FLOAT64:
- return dataView.getFloat64(index, true);
- }
- throw new RuntimeError(`Invalid component type: ${componentType}`);
- };
-
- /**
- * Decodes one component of a metadata value with the given property type
- * from the given data view.
- *
- * This will decode one component (e.g. one entry of a SCALAR array,
- * or one component of a VEC2 element).
- *
- * This will apply normalization to the raw component value if the given
- * class property is 'normalized'.
- *
- * @param {MetadataClassProperty} classProperty The class property
- * @param {DataView} dataView The data view containing the raw metadata values
- * @param {number} dataViewOffset The byte offset within the data view from
- * which the component should be read
- * @returns {number|bigint|undefined} The metadata value component
- * @throws RuntimeError If the component of the given property is not
- * a valid `MetadataComponentType`
- * @throws RangeError If reading the data from the given data view would
- * cause an out-of-bounds access
- */
- MetadataPicking.decodeRawMetadataValueComponent = function (
- classProperty,
- dataView,
- dataViewOffset,
- ) {
- const componentType = classProperty.componentType;
- const component = MetadataPicking.decodeRawMetadataValue(
- componentType,
- dataView,
- dataViewOffset,
- );
- if (classProperty.normalized) {
- return MetadataComponentType.normalize(component, componentType);
- }
- return component;
- };
-
- /**
- * Decodes one element of a metadata value with the given property type
- * from the given data view.
- *
- * When the given class property is vector- or matrix typed, then the
- * result will be an array, with a length that corresponds to the
- * number of vector- or matrix components.
- *
- * Otherwise, it will be a single value.
- *
- * In any case, the return value will be the "raw" value, which does
- * take into account normalization, but does NOT take into account
- * default/noData value handling.
- *
- * @param {MetadataClassProperty} classProperty The metadata class property
- * @param {DataView} dataView The data view containing the raw metadata values
- * @param {number} elementIndex The index of the element. This is the index
- * inside the array for array-typed properties, and 0 for non-array types.
- * @returns {number|number[]|bigint|bigint[]|undefined} The decoded metadata value element
- * @throws RuntimeError If the component of the given property is not
- * a valid `MetadataComponentType`
- * @throws RangeError If reading the data from the given data view would
- * cause an out-of-bounds access
- *
- */
- MetadataPicking.decodeRawMetadataValueElement = function (
- classProperty,
- dataView,
- elementIndex,
- ) {
- const componentType = classProperty.componentType;
- const componentSizeInBytes =
- MetadataComponentType.getSizeInBytes(componentType);
- const type = classProperty.type;
- const componentCount = MetadataType.getComponentCount(type);
- const elementSizeInBytes = componentSizeInBytes * componentCount;
- if (componentCount > 1) {
- const result = Array(componentCount);
- for (let i = 0; i < componentCount; i++) {
- const offset =
- elementIndex * elementSizeInBytes + i * componentSizeInBytes;
- const component = MetadataPicking.decodeRawMetadataValueComponent(
- classProperty,
- dataView,
- offset,
- );
- result[i] = component;
- }
- return result;
- }
- const offset = elementIndex * elementSizeInBytes;
- const result = MetadataPicking.decodeRawMetadataValueComponent(
- classProperty,
- dataView,
- offset,
- );
- return result;
- };
-
- /**
- * Decode the given raw values into the raw (array-based) form of
- * a metadata property value.
- *
- * (For decoding to types like `CartesianN`, the `decodeMetadataValues`
- * function can be used)
- *
- * The given values are a `Uint8Array` containing the RGBA
- * values that have been read from the metadata picking
- * frame buffer. They are assumed to contain the value for
- * the given class property, as encoded by the
- * `MetadataPickingPipelineStage` for metadata picking.
- *
- * When the given class property is an array, then (it has to be
- * a fixed-length array, and) the result will be an array with
- * the respective length.
- *
- * When the given class property is vector- or matrix typed,
- * then the result will be an array, with a length that corresponds
- * to the number of vector- or matrix components.
- *
- * (The case that the property is an array of vector- or matrix
- * elements is not supported on the side of the general metadata
- * shader infrastructure, but handled here nevertheless. For such
- * an input, the result would be an array of arrays, with each
- * element representing one of the vectors or matrices).
- *
- * In any case, the return value will be the "raw" value, which does
- * take into account normalization, but does NOT take into account
- * any offset/scale, or default/noData value handling.
- *
- * @param {MetadataClassProperty} classProperty The `MetadataClassProperty`
- * @param {Uint8Array} rawPixelValues The raw values
- * @returns {number|bigint|number[]|bigint[]|undefined} The value
- * @throws RuntimeError If the class property has an invalid component type
- *
- * @private
- */
- MetadataPicking.decodeRawMetadataValues = function (
- classProperty,
- rawPixelValues,
- ) {
- const dataView = new DataView(
- rawPixelValues.buffer,
- rawPixelValues.byteOffset,
- rawPixelValues.byteLength,
- );
- if (classProperty.isArray) {
- const arrayLength = classProperty.arrayLength;
- const result = Array(arrayLength);
- for (let i = 0; i < arrayLength; i++) {
- const element = MetadataPicking.decodeRawMetadataValueElement(
- classProperty,
- dataView,
- i,
- );
- result[i] = element;
- }
- return result;
- }
- const result = MetadataPicking.decodeRawMetadataValueElement(
- classProperty,
- dataView,
- 0,
- );
- return result;
- };
-
- /**
- * Converts the given type into an object representation where appropriate.
- *
- * When the given type is `SCALAR`, `STRING`, `BOOLEAN`, or `ENUM`, or
- * when the given value is `undefined`, then the given value will be
- * returned.
- *
- * Otherwise, for the `VECn/MATn` types, the given value is assumed to be
- * a numeric array, and is converted into the matching `CartesianN/MatrixN`
- * value.
- *
- * @param {string} type The `ClassProperty` type
- * @param {number|bigint|number[]|bigint[]|undefined} value The input value
- * @returns {undefined|number|bigint|string|boolean|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4} The object representation
- * @throws RuntimeError If the type is not a valid `MetadataType`
- */
- MetadataPicking.convertToObjectType = function (type, value) {
- if (!defined(value)) {
- return value;
- }
- if (
- type === MetadataType.SCALAR ||
- type === MetadataType.STRING ||
- type === MetadataType.BOOLEAN ||
- type === MetadataType.ENUM
- ) {
- return value;
- }
- const numbers = value.map((n) => Number(n));
- switch (type) {
- case MetadataType.VEC2:
- return Cartesian2.unpack(numbers, 0, new Cartesian2());
- case MetadataType.VEC3:
- return Cartesian3.unpack(numbers, 0, new Cartesian3());
- case MetadataType.VEC4:
- return Cartesian4.unpack(numbers, 0, new Cartesian4());
- case MetadataType.MAT2:
- return Matrix2.unpack(numbers, 0, new Matrix2());
- case MetadataType.MAT3:
- return Matrix3.unpack(numbers, 0, new Matrix3());
- case MetadataType.MAT4:
- return Matrix4.unpack(numbers, 0, new Matrix4());
- }
- // Should never happen:
- throw new RuntimeError(`Invalid metadata object type: ${type}`);
- };
-
- /**
- * Converts the given type into a raw value or array representation.
- *
- * For `VECn/MATn` types, the given value is converted into an array.
- * For other types, the value is returned directly
- *
- * @param {string} type The `ClassProperty` type
- * @param {undefined|number|bigint|string|boolean|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4} value The input value
- * @returns {undefined|number|bigint|string|boolean|number[]} The array representation
- * @throws RuntimeError If the type is not a valid `MetadataType`
- */
- MetadataPicking.convertFromObjectType = function (type, value) {
- if (!defined(value)) {
- return value;
- }
- if (
- type === MetadataType.SCALAR ||
- type === MetadataType.STRING ||
- type === MetadataType.BOOLEAN ||
- type === MetadataType.ENUM
- ) {
- return value;
- }
- switch (type) {
- case MetadataType.VEC2:
- return Cartesian2.pack(value, Array(2));
- case MetadataType.VEC3:
- return Cartesian3.pack(value, Array(3));
- case MetadataType.VEC4:
- return Cartesian4.pack(value, Array(4));
- case MetadataType.MAT2:
- return Matrix2.pack(value, Array(4));
- case MetadataType.MAT3:
- return Matrix3.pack(value, Array(9));
- case MetadataType.MAT4:
- return Matrix4.pack(value, Array(16));
- }
- // Should never happen:
- throw new RuntimeError(`Invalid metadata object type: ${type}`);
- };
-
- /**
- * Decode the given raw values into a metadata property value.
- *
- * This applies the value transform (offset/scale) to the result
- * of `decodeRawMetadataValues`, and converts this from array-based
- * types into object types like `CartesianN`.
- *
- * @param {MetadataClassProperty} classProperty The `MetadataClassProperty`
- * @param {object} metadataProperty The
- * `PropertyTextureProperty` or `PropertyAttributeProperty`
- * @param {Uint8Array} rawPixelValues The raw values
- * @returns {MetadataValue} The value
- * @throws RuntimeError If the class property has an invalid type
- * or component type
- * @throws RangeError If the given pixel values do not have sufficient
- * size to contain the expected value type
- *
- * @private
- */
- MetadataPicking.decodeMetadataValues = function (
- classProperty,
- metadataProperty,
- rawPixelValues,
- ) {
- let arrayBasedResult = MetadataPicking.decodeRawMetadataValues(
- classProperty,
- rawPixelValues,
- );
-
- if (metadataProperty.hasValueTransform) {
- // In the MetadataClassProperty, these offset/scale are always in
- // their array-based form (e.g. a number[3] for `VEC3`). But for
- // the PropertyTextureProperty and PropertyAttributeProperty,
- // the type of the offset/scale is defined to be
- // number|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4
- // So these types are converted into their array-based form here, before
- // applying them with `MetadataClassProperty.valueTransformInPlace`
-
- const offset = MetadataPicking.convertFromObjectType(
- classProperty.type,
- metadataProperty.offset,
- );
- const scale = MetadataPicking.convertFromObjectType(
- classProperty.type,
- metadataProperty.scale,
- );
- arrayBasedResult = MetadataClassProperty.valueTransformInPlace(
- arrayBasedResult,
- offset,
- scale,
- MetadataComponentType.applyValueTransform,
- );
- }
-
- if (classProperty.isArray) {
- const arrayLength = classProperty.arrayLength;
- const result = Array(arrayLength);
- for (let i = 0; i < arrayLength; i++) {
- const arrayBasedValue = arrayBasedResult[i];
- const objectBasedValue = MetadataPicking.convertToObjectType(
- classProperty.type,
- arrayBasedValue,
- );
- result[i] = objectBasedValue;
- }
- return result;
- }
- const objectResult = MetadataPicking.convertToObjectType(
- classProperty.type,
- arrayBasedResult,
- );
- return objectResult;
- };
-
- export default Object.freeze(MetadataPicking);
|