智慧水务管理系统 - 精河县供水工程综合管理平台

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. import Cartesian2 from "../Core/Cartesian2.js";
  2. import Cartesian3 from "../Core/Cartesian3.js";
  3. import Cartesian4 from "../Core/Cartesian4.js";
  4. import defined from "../Core/defined.js";
  5. import Matrix2 from "../Core/Matrix2.js";
  6. import Matrix3 from "../Core/Matrix3.js";
  7. import Matrix4 from "../Core/Matrix4.js";
  8. import RuntimeError from "../Core/RuntimeError.js";
  9. import MetadataClassProperty from "./MetadataClassProperty.js";
  10. import MetadataComponentType from "./MetadataComponentType.js";
  11. import MetadataType from "./MetadataType.js";
  12. /**
  13. * Utility functions for metadata picking.
  14. *
  15. * These are used by the `Picking.pickMetadata` function to decode
  16. * the metadata values that have been read from the frame buffer
  17. * into the actual metadata values, according to the structure
  18. * defined by the `MetadataClassProperty`.
  19. *
  20. * @private
  21. */
  22. const MetadataPicking = {};
  23. /**
  24. * Returns the value at the specified index of the given data view,
  25. * interpreting the data to have the given component type.
  26. *
  27. * @param {MetadataComponentType} componentType The `MetadataComponentType`
  28. * @param {DataView} dataView The data view
  29. * @param {number} index The index (byte offset)
  30. * @returns {number|bigint|undefined} The value
  31. * @throws RuntimeError If the given component type is not a valid
  32. * `MetadataComponentType`
  33. * @throws RangeError If reading the data from the given data view would
  34. * cause an out-of-bounds access
  35. *
  36. * @private
  37. */
  38. MetadataPicking.decodeRawMetadataValue = function (
  39. componentType,
  40. dataView,
  41. index,
  42. ) {
  43. switch (componentType) {
  44. case MetadataComponentType.INT8:
  45. return dataView.getInt8(index);
  46. case MetadataComponentType.UINT8:
  47. return dataView.getUint8(index);
  48. case MetadataComponentType.INT16:
  49. return dataView.getInt16(index, true);
  50. case MetadataComponentType.UINT16:
  51. return dataView.getUint16(index, true);
  52. case MetadataComponentType.INT32:
  53. return dataView.getInt32(index, true);
  54. case MetadataComponentType.UINT32:
  55. return dataView.getUint32(index, true);
  56. case MetadataComponentType.INT64:
  57. return dataView.getBigInt64(index, true);
  58. case MetadataComponentType.UINT64:
  59. return dataView.getBigUint64(index, true);
  60. case MetadataComponentType.FLOAT32:
  61. return dataView.getFloat32(index, true);
  62. case MetadataComponentType.FLOAT64:
  63. return dataView.getFloat64(index, true);
  64. }
  65. throw new RuntimeError(`Invalid component type: ${componentType}`);
  66. };
  67. /**
  68. * Decodes one component of a metadata value with the given property type
  69. * from the given data view.
  70. *
  71. * This will decode one component (e.g. one entry of a SCALAR array,
  72. * or one component of a VEC2 element).
  73. *
  74. * This will apply normalization to the raw component value if the given
  75. * class property is 'normalized'.
  76. *
  77. * @param {MetadataClassProperty} classProperty The class property
  78. * @param {DataView} dataView The data view containing the raw metadata values
  79. * @param {number} dataViewOffset The byte offset within the data view from
  80. * which the component should be read
  81. * @returns {number|bigint|undefined} The metadata value component
  82. * @throws RuntimeError If the component of the given property is not
  83. * a valid `MetadataComponentType`
  84. * @throws RangeError If reading the data from the given data view would
  85. * cause an out-of-bounds access
  86. */
  87. MetadataPicking.decodeRawMetadataValueComponent = function (
  88. classProperty,
  89. dataView,
  90. dataViewOffset,
  91. ) {
  92. const componentType = classProperty.componentType;
  93. const component = MetadataPicking.decodeRawMetadataValue(
  94. componentType,
  95. dataView,
  96. dataViewOffset,
  97. );
  98. if (classProperty.normalized) {
  99. return MetadataComponentType.normalize(component, componentType);
  100. }
  101. return component;
  102. };
  103. /**
  104. * Decodes one element of a metadata value with the given property type
  105. * from the given data view.
  106. *
  107. * When the given class property is vector- or matrix typed, then the
  108. * result will be an array, with a length that corresponds to the
  109. * number of vector- or matrix components.
  110. *
  111. * Otherwise, it will be a single value.
  112. *
  113. * In any case, the return value will be the "raw" value, which does
  114. * take into account normalization, but does NOT take into account
  115. * default/noData value handling.
  116. *
  117. * @param {MetadataClassProperty} classProperty The metadata class property
  118. * @param {DataView} dataView The data view containing the raw metadata values
  119. * @param {number} elementIndex The index of the element. This is the index
  120. * inside the array for array-typed properties, and 0 for non-array types.
  121. * @returns {number|number[]|bigint|bigint[]|undefined} The decoded metadata value element
  122. * @throws RuntimeError If the component of the given property is not
  123. * a valid `MetadataComponentType`
  124. * @throws RangeError If reading the data from the given data view would
  125. * cause an out-of-bounds access
  126. *
  127. */
  128. MetadataPicking.decodeRawMetadataValueElement = function (
  129. classProperty,
  130. dataView,
  131. elementIndex,
  132. ) {
  133. const componentType = classProperty.componentType;
  134. const componentSizeInBytes =
  135. MetadataComponentType.getSizeInBytes(componentType);
  136. const type = classProperty.type;
  137. const componentCount = MetadataType.getComponentCount(type);
  138. const elementSizeInBytes = componentSizeInBytes * componentCount;
  139. if (componentCount > 1) {
  140. const result = Array(componentCount);
  141. for (let i = 0; i < componentCount; i++) {
  142. const offset =
  143. elementIndex * elementSizeInBytes + i * componentSizeInBytes;
  144. const component = MetadataPicking.decodeRawMetadataValueComponent(
  145. classProperty,
  146. dataView,
  147. offset,
  148. );
  149. result[i] = component;
  150. }
  151. return result;
  152. }
  153. const offset = elementIndex * elementSizeInBytes;
  154. const result = MetadataPicking.decodeRawMetadataValueComponent(
  155. classProperty,
  156. dataView,
  157. offset,
  158. );
  159. return result;
  160. };
  161. /**
  162. * Decode the given raw values into the raw (array-based) form of
  163. * a metadata property value.
  164. *
  165. * (For decoding to types like `CartesianN`, the `decodeMetadataValues`
  166. * function can be used)
  167. *
  168. * The given values are a `Uint8Array` containing the RGBA
  169. * values that have been read from the metadata picking
  170. * frame buffer. They are assumed to contain the value for
  171. * the given class property, as encoded by the
  172. * `MetadataPickingPipelineStage` for metadata picking.
  173. *
  174. * When the given class property is an array, then (it has to be
  175. * a fixed-length array, and) the result will be an array with
  176. * the respective length.
  177. *
  178. * When the given class property is vector- or matrix typed,
  179. * then the result will be an array, with a length that corresponds
  180. * to the number of vector- or matrix components.
  181. *
  182. * (The case that the property is an array of vector- or matrix
  183. * elements is not supported on the side of the general metadata
  184. * shader infrastructure, but handled here nevertheless. For such
  185. * an input, the result would be an array of arrays, with each
  186. * element representing one of the vectors or matrices).
  187. *
  188. * In any case, the return value will be the "raw" value, which does
  189. * take into account normalization, but does NOT take into account
  190. * any offset/scale, or default/noData value handling.
  191. *
  192. * @param {MetadataClassProperty} classProperty The `MetadataClassProperty`
  193. * @param {Uint8Array} rawPixelValues The raw values
  194. * @returns {number|bigint|number[]|bigint[]|undefined} The value
  195. * @throws RuntimeError If the class property has an invalid component type
  196. *
  197. * @private
  198. */
  199. MetadataPicking.decodeRawMetadataValues = function (
  200. classProperty,
  201. rawPixelValues,
  202. ) {
  203. const dataView = new DataView(
  204. rawPixelValues.buffer,
  205. rawPixelValues.byteOffset,
  206. rawPixelValues.byteLength,
  207. );
  208. if (classProperty.isArray) {
  209. const arrayLength = classProperty.arrayLength;
  210. const result = Array(arrayLength);
  211. for (let i = 0; i < arrayLength; i++) {
  212. const element = MetadataPicking.decodeRawMetadataValueElement(
  213. classProperty,
  214. dataView,
  215. i,
  216. );
  217. result[i] = element;
  218. }
  219. return result;
  220. }
  221. const result = MetadataPicking.decodeRawMetadataValueElement(
  222. classProperty,
  223. dataView,
  224. 0,
  225. );
  226. return result;
  227. };
  228. /**
  229. * Converts the given type into an object representation where appropriate.
  230. *
  231. * When the given type is `SCALAR`, `STRING`, `BOOLEAN`, or `ENUM`, or
  232. * when the given value is `undefined`, then the given value will be
  233. * returned.
  234. *
  235. * Otherwise, for the `VECn/MATn` types, the given value is assumed to be
  236. * a numeric array, and is converted into the matching `CartesianN/MatrixN`
  237. * value.
  238. *
  239. * @param {string} type The `ClassProperty` type
  240. * @param {number|bigint|number[]|bigint[]|undefined} value The input value
  241. * @returns {undefined|number|bigint|string|boolean|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4} The object representation
  242. * @throws RuntimeError If the type is not a valid `MetadataType`
  243. */
  244. MetadataPicking.convertToObjectType = function (type, value) {
  245. if (!defined(value)) {
  246. return value;
  247. }
  248. if (
  249. type === MetadataType.SCALAR ||
  250. type === MetadataType.STRING ||
  251. type === MetadataType.BOOLEAN ||
  252. type === MetadataType.ENUM
  253. ) {
  254. return value;
  255. }
  256. const numbers = value.map((n) => Number(n));
  257. switch (type) {
  258. case MetadataType.VEC2:
  259. return Cartesian2.unpack(numbers, 0, new Cartesian2());
  260. case MetadataType.VEC3:
  261. return Cartesian3.unpack(numbers, 0, new Cartesian3());
  262. case MetadataType.VEC4:
  263. return Cartesian4.unpack(numbers, 0, new Cartesian4());
  264. case MetadataType.MAT2:
  265. return Matrix2.unpack(numbers, 0, new Matrix2());
  266. case MetadataType.MAT3:
  267. return Matrix3.unpack(numbers, 0, new Matrix3());
  268. case MetadataType.MAT4:
  269. return Matrix4.unpack(numbers, 0, new Matrix4());
  270. }
  271. // Should never happen:
  272. throw new RuntimeError(`Invalid metadata object type: ${type}`);
  273. };
  274. /**
  275. * Converts the given type into a raw value or array representation.
  276. *
  277. * For `VECn/MATn` types, the given value is converted into an array.
  278. * For other types, the value is returned directly
  279. *
  280. * @param {string} type The `ClassProperty` type
  281. * @param {undefined|number|bigint|string|boolean|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4} value The input value
  282. * @returns {undefined|number|bigint|string|boolean|number[]} The array representation
  283. * @throws RuntimeError If the type is not a valid `MetadataType`
  284. */
  285. MetadataPicking.convertFromObjectType = function (type, value) {
  286. if (!defined(value)) {
  287. return value;
  288. }
  289. if (
  290. type === MetadataType.SCALAR ||
  291. type === MetadataType.STRING ||
  292. type === MetadataType.BOOLEAN ||
  293. type === MetadataType.ENUM
  294. ) {
  295. return value;
  296. }
  297. switch (type) {
  298. case MetadataType.VEC2:
  299. return Cartesian2.pack(value, Array(2));
  300. case MetadataType.VEC3:
  301. return Cartesian3.pack(value, Array(3));
  302. case MetadataType.VEC4:
  303. return Cartesian4.pack(value, Array(4));
  304. case MetadataType.MAT2:
  305. return Matrix2.pack(value, Array(4));
  306. case MetadataType.MAT3:
  307. return Matrix3.pack(value, Array(9));
  308. case MetadataType.MAT4:
  309. return Matrix4.pack(value, Array(16));
  310. }
  311. // Should never happen:
  312. throw new RuntimeError(`Invalid metadata object type: ${type}`);
  313. };
  314. /**
  315. * Decode the given raw values into a metadata property value.
  316. *
  317. * This applies the value transform (offset/scale) to the result
  318. * of `decodeRawMetadataValues`, and converts this from array-based
  319. * types into object types like `CartesianN`.
  320. *
  321. * @param {MetadataClassProperty} classProperty The `MetadataClassProperty`
  322. * @param {object} metadataProperty The
  323. * `PropertyTextureProperty` or `PropertyAttributeProperty`
  324. * @param {Uint8Array} rawPixelValues The raw values
  325. * @returns {MetadataValue} The value
  326. * @throws RuntimeError If the class property has an invalid type
  327. * or component type
  328. * @throws RangeError If the given pixel values do not have sufficient
  329. * size to contain the expected value type
  330. *
  331. * @private
  332. */
  333. MetadataPicking.decodeMetadataValues = function (
  334. classProperty,
  335. metadataProperty,
  336. rawPixelValues,
  337. ) {
  338. let arrayBasedResult = MetadataPicking.decodeRawMetadataValues(
  339. classProperty,
  340. rawPixelValues,
  341. );
  342. if (metadataProperty.hasValueTransform) {
  343. // In the MetadataClassProperty, these offset/scale are always in
  344. // their array-based form (e.g. a number[3] for `VEC3`). But for
  345. // the PropertyTextureProperty and PropertyAttributeProperty,
  346. // the type of the offset/scale is defined to be
  347. // number|Cartesian2|Cartesian3|Cartesian4|Matrix2|Matrix3|Matrix4
  348. // So these types are converted into their array-based form here, before
  349. // applying them with `MetadataClassProperty.valueTransformInPlace`
  350. const offset = MetadataPicking.convertFromObjectType(
  351. classProperty.type,
  352. metadataProperty.offset,
  353. );
  354. const scale = MetadataPicking.convertFromObjectType(
  355. classProperty.type,
  356. metadataProperty.scale,
  357. );
  358. arrayBasedResult = MetadataClassProperty.valueTransformInPlace(
  359. arrayBasedResult,
  360. offset,
  361. scale,
  362. MetadataComponentType.applyValueTransform,
  363. );
  364. }
  365. if (classProperty.isArray) {
  366. const arrayLength = classProperty.arrayLength;
  367. const result = Array(arrayLength);
  368. for (let i = 0; i < arrayLength; i++) {
  369. const arrayBasedValue = arrayBasedResult[i];
  370. const objectBasedValue = MetadataPicking.convertToObjectType(
  371. classProperty.type,
  372. arrayBasedValue,
  373. );
  374. result[i] = objectBasedValue;
  375. }
  376. return result;
  377. }
  378. const objectResult = MetadataPicking.convertToObjectType(
  379. classProperty.type,
  380. arrayBasedResult,
  381. );
  382. return objectResult;
  383. };
  384. export default Object.freeze(MetadataPicking);