MetadataTable.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. import Check from "../Core/Check.js";
  2. import clone from "../Core/clone.js";
  3. import defaultValue from "../Core/defaultValue.js";
  4. import defined from "../Core/defined.js";
  5. import MetadataEntity from "./MetadataEntity.js";
  6. import MetadataTableProperty from "./MetadataTableProperty.js";
  7. /**
  8. * A table containing binary metadata for a collection of entities. This is
  9. * used for representing binary properties of a batch table, as well as binary
  10. * metadata in 3D Tiles next extensions.
  11. * <p>
  12. * For 3D Tiles Next details, see the {@link https://github.com/CesiumGS/3d-tiles/tree/main/extensions/3DTILES_metadata|3DTILES_metadata Extension} for 3D Tiles, as well as the {@link https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata|EXT_feature_metadata Extension} for glTF.
  13. * </p>
  14. *
  15. * @param {object} options Object with the following properties:
  16. * @param {number} options.count The number of entities in the table.
  17. * @param {object} [options.properties] A dictionary containing properties.
  18. * @param {MetadataClass} options.class The class that properties conform to.
  19. * @param {Object<string, Uint8Array>} [options.bufferViews] An object mapping bufferView IDs to Uint8Array objects.
  20. *
  21. * @alias MetadataTable
  22. * @constructor
  23. *
  24. * @private
  25. * @experimental This feature is using part of the 3D Tiles spec that is not final and is subject to change without Cesium's standard deprecation policy.
  26. */
  27. function MetadataTable(options) {
  28. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  29. const count = options.count;
  30. const metadataClass = options.class;
  31. //>>includeStart('debug', pragmas.debug);
  32. Check.typeOf.number.greaterThan("options.count", count, 0);
  33. Check.typeOf.object("options.class", metadataClass);
  34. //>>includeEnd('debug');
  35. let byteLength = 0;
  36. const properties = {};
  37. if (defined(options.properties)) {
  38. for (const propertyId in options.properties) {
  39. if (options.properties.hasOwnProperty(propertyId)) {
  40. const property = new MetadataTableProperty({
  41. count: count,
  42. property: options.properties[propertyId],
  43. classProperty: metadataClass.properties[propertyId],
  44. bufferViews: options.bufferViews,
  45. });
  46. properties[propertyId] = property;
  47. byteLength += property.byteLength;
  48. }
  49. }
  50. }
  51. this._count = count;
  52. this._class = metadataClass;
  53. this._properties = properties;
  54. this._byteLength = byteLength;
  55. }
  56. Object.defineProperties(MetadataTable.prototype, {
  57. /**
  58. * The number of entities in the table.
  59. *
  60. * @memberof MetadataTable.prototype
  61. * @type {number}
  62. * @readonly
  63. * @private
  64. */
  65. count: {
  66. get: function () {
  67. return this._count;
  68. },
  69. },
  70. /**
  71. * The class that properties conform to.
  72. *
  73. * @memberof MetadataTable.prototype
  74. * @type {MetadataClass}
  75. * @readonly
  76. * @private
  77. */
  78. class: {
  79. get: function () {
  80. return this._class;
  81. },
  82. },
  83. /**
  84. * The size of all typed arrays used in this table.
  85. *
  86. * @memberof MetadataTable.prototype
  87. * @type {number}
  88. * @readonly
  89. * @private
  90. */
  91. byteLength: {
  92. get: function () {
  93. return this._byteLength;
  94. },
  95. },
  96. });
  97. /**
  98. * Returns whether the table has this property.
  99. *
  100. * @param {string} propertyId The case-sensitive ID of the property.
  101. * @returns {boolean} Whether the table has this property.
  102. * @private
  103. */
  104. MetadataTable.prototype.hasProperty = function (propertyId) {
  105. return MetadataEntity.hasProperty(propertyId, this._properties, this._class);
  106. };
  107. /**
  108. * Returns whether the table has a property with the given semantic.
  109. *
  110. * @param {string} semantic The case-sensitive semantic of the property.
  111. * @returns {boolean} Whether the table has a property with the given semantic.
  112. * @private
  113. */
  114. MetadataTable.prototype.hasPropertyBySemantic = function (semantic) {
  115. return MetadataEntity.hasPropertyBySemantic(
  116. semantic,
  117. this._properties,
  118. this._class
  119. );
  120. };
  121. /**
  122. * Returns an array of property IDs.
  123. *
  124. * @param {string[]} [results] An array into which to store the results.
  125. * @returns {string[]} The property IDs.
  126. * @private
  127. */
  128. MetadataTable.prototype.getPropertyIds = function (results) {
  129. return MetadataEntity.getPropertyIds(this._properties, this._class, results);
  130. };
  131. /**
  132. * Returns a copy of the value of the property with the given ID.
  133. * <p>
  134. * If the property is an enum the name of the enum is returned.
  135. * </p>
  136. * <p>
  137. * If the property is normalized the normalized value is returned. The value is
  138. * in the range [-1.0, 1.0] for signed integer types and [0.0, 1.0] for unsigned
  139. * integer types.
  140. * </p>
  141. * <p>
  142. * If the property is not normalized and type or componentType is INT64 or
  143. * UINT64 a BigInt will be returned. On platforms that don't support BigInt a
  144. * number will be returned instead. Note that numbers only support up to 52 bits
  145. * of integer precision. Values greater than 2^53 - 1 or less than -(2^53 - 1)
  146. * may lose precision when read.
  147. * </p>
  148. *
  149. * @param {number} index The index of the entity.
  150. * @param {string} propertyId The case-sensitive ID of the property.
  151. * @returns {*} The value of the property or <code>undefined</code> if the entity does not have this property.
  152. *
  153. * @exception {DeveloperError} index is required and between zero and count - 1
  154. * @private
  155. */
  156. MetadataTable.prototype.getProperty = function (index, propertyId) {
  157. //>>includeStart('debug', pragmas.debug);
  158. Check.typeOf.string("propertyId", propertyId);
  159. //>>includeEnd('debug');
  160. const property = this._properties[propertyId];
  161. let value;
  162. if (defined(property)) {
  163. value = property.get(index);
  164. } else {
  165. value = getDefault(this._class, propertyId);
  166. }
  167. return value;
  168. };
  169. /**
  170. * Sets the value of the property with the given ID.
  171. * <p>
  172. * If the property is an enum the name of the enum must be provided, not the
  173. * integer value.
  174. * </p>
  175. * <p>
  176. * If the property is normalized a normalized value must be provided to this
  177. * function. The value must be in the range [-1.0, 1.0] for signed integer
  178. * types and [0.0, 1.0] for unsigned integer types.
  179. * </p>
  180. * <p>
  181. * If the property is not normalized and type or componentType is INT64 or
  182. * UINT64 a BigInt may be provided. On platforms that don't support BigInt a
  183. * number may be provided instead. Note that numbers only support up to 52 bits
  184. * of integer precision. Values greater than 2^53 - 1 or less than -(2^53 - 1)
  185. * may lose precision when set."
  186. * </p>
  187. *
  188. * @param {number} index The index of the entity.
  189. * @param {string} propertyId The case-sensitive ID of the property.
  190. * @param {*} value The value of the property that will be copied.
  191. * @returns {boolean} <code>true</code> if the property was set, <code>false</code> otherwise.
  192. *
  193. * @exception {DeveloperError} index is required and between zero and count - 1
  194. * @exception {DeveloperError} value does not match type
  195. * @exception {DeveloperError} value is out of range for type
  196. * @exception {DeveloperError} Array length does not match componentCount
  197. * @private
  198. */
  199. MetadataTable.prototype.setProperty = function (index, propertyId, value) {
  200. //>>includeStart('debug', pragmas.debug);
  201. Check.typeOf.string("propertyId", propertyId);
  202. //>>includeEnd('debug');
  203. const property = this._properties[propertyId];
  204. if (defined(property)) {
  205. property.set(index, value);
  206. return true;
  207. }
  208. return false;
  209. };
  210. /**
  211. * Returns a copy of the value of the property with the given semantic.
  212. *
  213. * @param {number} index The index of the entity.
  214. * @param {string} semantic The case-sensitive semantic of the property.
  215. * @returns {*} The value of the property or <code>undefined</code> if the entity does not have this semantic.
  216. *
  217. * @exception {DeveloperError} index is required and between zero and count - 1
  218. * @private
  219. */
  220. MetadataTable.prototype.getPropertyBySemantic = function (index, semantic) {
  221. //>>includeStart('debug', pragmas.debug);
  222. Check.typeOf.string("semantic", semantic);
  223. //>>includeEnd('debug');
  224. let property;
  225. const propertiesBySemantic = this._class.propertiesBySemantic;
  226. if (defined(propertiesBySemantic)) {
  227. property = propertiesBySemantic[semantic];
  228. }
  229. if (defined(property)) {
  230. return this.getProperty(index, property.id);
  231. }
  232. return undefined;
  233. };
  234. /**
  235. * Sets the value of the property with the given semantic.
  236. *
  237. * @param {number} index The index of the entity.
  238. * @param {string} semantic The case-sensitive semantic of the property.
  239. * @param {*} value The value of the property that will be copied.
  240. * @returns {boolean} <code>true</code> if the property was set, <code>false</code> otherwise.
  241. *
  242. * @exception {DeveloperError} index is required and between zero and count - 1
  243. * @exception {DeveloperError} value does not match type
  244. * @exception {DeveloperError} value is out of range for type
  245. * @exception {DeveloperError} Array length does not match componentCount
  246. * @private
  247. */
  248. MetadataTable.prototype.setPropertyBySemantic = function (
  249. index,
  250. semantic,
  251. value
  252. ) {
  253. //>>includeStart('debug', pragmas.debug);
  254. Check.typeOf.string("semantic", semantic);
  255. //>>includeEnd('debug');
  256. let property;
  257. const propertiesBySemantic = this._class.propertiesBySemantic;
  258. if (defined(propertiesBySemantic)) {
  259. property = propertiesBySemantic[semantic];
  260. }
  261. if (defined(property)) {
  262. return this.setProperty(index, property.id, value);
  263. }
  264. return false;
  265. };
  266. /**
  267. * Returns a typed array containing the property values for a given propertyId.
  268. *
  269. * @param {string} propertyId The case-sensitive ID of the property.
  270. * @returns {*} The typed array containing the property values or <code>undefined</code> if the property values are not stored in a typed array.
  271. *
  272. * @private
  273. */
  274. MetadataTable.prototype.getPropertyTypedArray = function (propertyId) {
  275. //>>includeStart('debug', pragmas.debug);
  276. Check.typeOf.string("propertyId", propertyId);
  277. //>>includeEnd('debug');
  278. const property = this._properties[propertyId];
  279. if (defined(property)) {
  280. return property.getTypedArray();
  281. }
  282. return undefined;
  283. };
  284. /**
  285. * Returns a typed array containing the property values for the property with the given semantic.
  286. *
  287. * @param {string} semantic The case-sensitive semantic of the property.
  288. * @returns {*} The typed array containing the property values or <code>undefined</code> if the property values are not stored in a typed array.
  289. *
  290. * @private
  291. */
  292. MetadataTable.prototype.getPropertyTypedArrayBySemantic = function (semantic) {
  293. //>>includeStart('debug', pragmas.debug);
  294. Check.typeOf.string("semantic", semantic);
  295. //>>includeEnd('debug');
  296. let property;
  297. const propertiesBySemantic = this._class.propertiesBySemantic;
  298. if (defined(propertiesBySemantic)) {
  299. property = propertiesBySemantic[semantic];
  300. }
  301. if (defined(property)) {
  302. return this.getPropertyTypedArray(property.id);
  303. }
  304. return undefined;
  305. };
  306. function getDefault(classDefinition, propertyId) {
  307. const classProperties = classDefinition.properties;
  308. if (!defined(classProperties)) {
  309. return undefined;
  310. }
  311. const classProperty = classProperties[propertyId];
  312. if (defined(classProperty) && defined(classProperty.default)) {
  313. let value = classProperty.default;
  314. if (classProperty.isArray) {
  315. value = clone(value, true);
  316. }
  317. value = classProperty.normalize(value);
  318. return classProperty.unpackVectorAndMatrixTypes(value);
  319. }
  320. }
  321. export default MetadataTable;