MetadataTable.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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. const properties = {};
  36. if (defined(options.properties)) {
  37. for (const propertyId in options.properties) {
  38. if (options.properties.hasOwnProperty(propertyId)) {
  39. properties[propertyId] = new MetadataTableProperty({
  40. count: count,
  41. property: options.properties[propertyId],
  42. classProperty: metadataClass.properties[propertyId],
  43. bufferViews: options.bufferViews,
  44. });
  45. }
  46. }
  47. }
  48. this._count = count;
  49. this._class = metadataClass;
  50. this._properties = properties;
  51. }
  52. Object.defineProperties(MetadataTable.prototype, {
  53. /**
  54. * The number of entities in the table.
  55. *
  56. * @memberof MetadataTable.prototype
  57. * @type {Number}
  58. * @readonly
  59. * @private
  60. */
  61. count: {
  62. get: function () {
  63. return this._count;
  64. },
  65. },
  66. /**
  67. * The class that properties conform to.
  68. *
  69. * @memberof MetadataTable.prototype
  70. * @type {MetadataClass}
  71. * @readonly
  72. * @private
  73. */
  74. class: {
  75. get: function () {
  76. return this._class;
  77. },
  78. },
  79. });
  80. /**
  81. * Returns whether the table has this property.
  82. *
  83. * @param {String} propertyId The case-sensitive ID of the property.
  84. * @returns {Boolean} Whether the table has this property.
  85. * @private
  86. */
  87. MetadataTable.prototype.hasProperty = function (propertyId) {
  88. return MetadataEntity.hasProperty(propertyId, this._properties, this._class);
  89. };
  90. /**
  91. * Returns whether the table has a property with the given semantic.
  92. *
  93. * @param {String} semantic The case-sensitive semantic of the property.
  94. * @returns {Boolean} Whether the table has a property with the given semantic.
  95. * @private
  96. */
  97. MetadataTable.prototype.hasPropertyBySemantic = function (semantic) {
  98. return MetadataEntity.hasPropertyBySemantic(
  99. semantic,
  100. this._properties,
  101. this._class
  102. );
  103. };
  104. /**
  105. * Returns an array of property IDs.
  106. *
  107. * @param {String[]} [results] An array into which to store the results.
  108. * @returns {String[]} The property IDs.
  109. * @private
  110. */
  111. MetadataTable.prototype.getPropertyIds = function (results) {
  112. return MetadataEntity.getPropertyIds(this._properties, this._class, results);
  113. };
  114. /**
  115. * Returns a copy of the value of the property with the given ID.
  116. * <p>
  117. * If the property is an enum the name of the enum is returned.
  118. * </p>
  119. * <p>
  120. * If the property is normalized the normalized value is returned. The value is
  121. * in the range [-1.0, 1.0] for signed integer types and [0.0, 1.0] for unsigned
  122. * integer types.
  123. * </p>
  124. * <p>
  125. * If the property is not normalized and type or componentType is INT64 or
  126. * UINT64 a BigInt will be returned. On platforms that don't support BigInt a
  127. * number will be returned instead. Note that numbers only support up to 52 bits
  128. * of integer precision. Values greater than 2^53 - 1 or less than -(2^53 - 1)
  129. * may lose precision when read.
  130. * </p>
  131. *
  132. * @param {Number} index The index of the entity.
  133. * @param {String} propertyId The case-sensitive ID of the property.
  134. * @returns {*} The value of the property or <code>undefined</code> if the entity does not have this property.
  135. *
  136. * @exception {DeveloperError} index is required and between zero and count - 1
  137. * @private
  138. */
  139. MetadataTable.prototype.getProperty = function (index, propertyId) {
  140. //>>includeStart('debug', pragmas.debug);
  141. Check.typeOf.string("propertyId", propertyId);
  142. //>>includeEnd('debug');
  143. const property = this._properties[propertyId];
  144. let value;
  145. if (defined(property)) {
  146. value = property.get(index);
  147. } else {
  148. value = getDefault(this._class, propertyId);
  149. }
  150. return value;
  151. };
  152. /**
  153. * Sets the value of the property with the given ID.
  154. * <p>
  155. * If the property is an enum the name of the enum must be provided, not the
  156. * integer value.
  157. * </p>
  158. * <p>
  159. * If the property is normalized a normalized value must be provided to this
  160. * function. The value must be in the range [-1.0, 1.0] for signed integer
  161. * types and [0.0, 1.0] for unsigned integer types.
  162. * </p>
  163. * <p>
  164. * If the property is not normalized and type or componentType is INT64 or
  165. * UINT64 a BigInt may be provided. On platforms that don't support BigInt a
  166. * number may be provided instead. Note that numbers only support up to 52 bits
  167. * of integer precision. Values greater than 2^53 - 1 or less than -(2^53 - 1)
  168. * may lose precision when set."
  169. * </p>
  170. *
  171. * @param {Number} index The index of the entity.
  172. * @param {String} propertyId The case-sensitive ID of the property.
  173. * @param {*} value The value of the property that will be copied.
  174. * @returns {Boolean} <code>true</code> if the property was set, <code>false</code> otherwise.
  175. *
  176. * @exception {DeveloperError} index is required and between zero and count - 1
  177. * @exception {DeveloperError} value does not match type
  178. * @exception {DeveloperError} value is out of range for type
  179. * @exception {DeveloperError} Array length does not match componentCount
  180. * @private
  181. */
  182. MetadataTable.prototype.setProperty = function (index, propertyId, value) {
  183. //>>includeStart('debug', pragmas.debug);
  184. Check.typeOf.string("propertyId", propertyId);
  185. //>>includeEnd('debug');
  186. const property = this._properties[propertyId];
  187. if (defined(property)) {
  188. property.set(index, value);
  189. return true;
  190. }
  191. return false;
  192. };
  193. /**
  194. * Returns a copy of the value of the property with the given semantic.
  195. *
  196. * @param {Number} index The index of the entity.
  197. * @param {String} semantic The case-sensitive semantic of the property.
  198. * @returns {*} The value of the property or <code>undefined</code> if the entity does not have this semantic.
  199. *
  200. * @exception {DeveloperError} index is required and between zero and count - 1
  201. * @private
  202. */
  203. MetadataTable.prototype.getPropertyBySemantic = function (index, semantic) {
  204. //>>includeStart('debug', pragmas.debug);
  205. Check.typeOf.string("semantic", semantic);
  206. //>>includeEnd('debug');
  207. let property;
  208. const propertiesBySemantic = this._class.propertiesBySemantic;
  209. if (defined(propertiesBySemantic)) {
  210. property = propertiesBySemantic[semantic];
  211. }
  212. if (defined(property)) {
  213. return this.getProperty(index, property.id);
  214. }
  215. return undefined;
  216. };
  217. /**
  218. * Sets the value of the property with the given semantic.
  219. *
  220. * @param {Number} index The index of the entity.
  221. * @param {String} semantic The case-sensitive semantic of the property.
  222. * @param {*} value The value of the property that will be copied.
  223. * @returns {Boolean} <code>true</code> if the property was set, <code>false</code> otherwise.
  224. *
  225. * @exception {DeveloperError} index is required and between zero and count - 1
  226. * @exception {DeveloperError} value does not match type
  227. * @exception {DeveloperError} value is out of range for type
  228. * @exception {DeveloperError} Array length does not match componentCount
  229. * @private
  230. */
  231. MetadataTable.prototype.setPropertyBySemantic = function (
  232. index,
  233. semantic,
  234. value
  235. ) {
  236. //>>includeStart('debug', pragmas.debug);
  237. Check.typeOf.string("semantic", semantic);
  238. //>>includeEnd('debug');
  239. let property;
  240. const propertiesBySemantic = this._class.propertiesBySemantic;
  241. if (defined(propertiesBySemantic)) {
  242. property = propertiesBySemantic[semantic];
  243. }
  244. if (defined(property)) {
  245. return this.setProperty(index, property.id, value);
  246. }
  247. return false;
  248. };
  249. /**
  250. * Returns a typed array containing the property values for a given propertyId.
  251. *
  252. * @param {String} propertyId The case-sensitive ID of the property.
  253. * @returns {*} The typed array containing the property values or <code>undefined</code> if the property values are not stored in a typed array.
  254. *
  255. * @private
  256. */
  257. MetadataTable.prototype.getPropertyTypedArray = function (propertyId) {
  258. //>>includeStart('debug', pragmas.debug);
  259. Check.typeOf.string("propertyId", propertyId);
  260. //>>includeEnd('debug');
  261. const property = this._properties[propertyId];
  262. if (defined(property)) {
  263. return property.getTypedArray();
  264. }
  265. return undefined;
  266. };
  267. /**
  268. * Returns a typed array containing the property values for the property with the given semantic.
  269. *
  270. * @param {String} semantic The case-sensitive semantic of the property.
  271. * @returns {*} The typed array containing the property values or <code>undefined</code> if the property values are not stored in a typed array.
  272. *
  273. * @private
  274. */
  275. MetadataTable.prototype.getPropertyTypedArrayBySemantic = function (semantic) {
  276. //>>includeStart('debug', pragmas.debug);
  277. Check.typeOf.string("semantic", semantic);
  278. //>>includeEnd('debug');
  279. let property;
  280. const propertiesBySemantic = this._class.propertiesBySemantic;
  281. if (defined(propertiesBySemantic)) {
  282. property = propertiesBySemantic[semantic];
  283. }
  284. if (defined(property)) {
  285. return this.getPropertyTypedArray(property.id);
  286. }
  287. return undefined;
  288. };
  289. function getDefault(classDefinition, propertyId) {
  290. const classProperties = classDefinition.properties;
  291. if (!defined(classProperties)) {
  292. return undefined;
  293. }
  294. const classProperty = classProperties[propertyId];
  295. if (defined(classProperty) && defined(classProperty.default)) {
  296. let value = classProperty.default;
  297. if (classProperty.isArray) {
  298. value = clone(value, true);
  299. }
  300. value = classProperty.normalize(value);
  301. return classProperty.unpackVectorAndMatrixTypes(value);
  302. }
  303. }
  304. export default MetadataTable;