GeometryUpdater.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. import Check from "../Core/Check.js";
  2. import Color from "../Core/Color.js";
  3. import defaultValue from "../Core/defaultValue.js";
  4. import defined from "../Core/defined.js";
  5. import destroyObject from "../Core/destroyObject.js";
  6. import DeveloperError from "../Core/DeveloperError.js";
  7. import DistanceDisplayCondition from "../Core/DistanceDisplayCondition.js";
  8. import Event from "../Core/Event.js";
  9. import Iso8601 from "../Core/Iso8601.js";
  10. import oneTimeWarning from "../Core/oneTimeWarning.js";
  11. import ClassificationType from "../Scene/ClassificationType.js";
  12. import ShadowMode from "../Scene/ShadowMode.js";
  13. import ColorMaterialProperty from "./ColorMaterialProperty.js";
  14. import ConstantProperty from "./ConstantProperty.js";
  15. import Entity from "./Entity.js";
  16. import Property from "./Property.js";
  17. const defaultMaterial = new ColorMaterialProperty(Color.WHITE);
  18. const defaultShow = new ConstantProperty(true);
  19. const defaultFill = new ConstantProperty(true);
  20. const defaultOutline = new ConstantProperty(false);
  21. const defaultOutlineColor = new ConstantProperty(Color.BLACK);
  22. const defaultShadows = new ConstantProperty(ShadowMode.DISABLED);
  23. const defaultDistanceDisplayCondition = new ConstantProperty(
  24. new DistanceDisplayCondition()
  25. );
  26. const defaultClassificationType = new ConstantProperty(ClassificationType.BOTH);
  27. /**
  28. * An abstract class for updating geometry entities.
  29. * @alias GeometryUpdater
  30. * @constructor
  31. *
  32. * @param {Object} options An object with the following properties:
  33. * @param {Entity} options.entity The entity containing the geometry to be visualized.
  34. * @param {Scene} options.scene The scene where visualization is taking place.
  35. * @param {Object} options.geometryOptions Options for the geometry
  36. * @param {String} options.geometryPropertyName The geometry property name
  37. * @param {String[]} options.observedPropertyNames The entity properties this geometry cares about
  38. */
  39. function GeometryUpdater(options) {
  40. //>>includeStart('debug', pragmas.debug);
  41. Check.defined("options.entity", options.entity);
  42. Check.defined("options.scene", options.scene);
  43. Check.defined("options.geometryOptions", options.geometryOptions);
  44. Check.defined("options.geometryPropertyName", options.geometryPropertyName);
  45. Check.defined("options.observedPropertyNames", options.observedPropertyNames);
  46. //>>includeEnd('debug');
  47. const entity = options.entity;
  48. const geometryPropertyName = options.geometryPropertyName;
  49. this._entity = entity;
  50. this._scene = options.scene;
  51. this._fillEnabled = false;
  52. this._isClosed = false;
  53. this._onTerrain = false;
  54. this._dynamic = false;
  55. this._outlineEnabled = false;
  56. this._geometryChanged = new Event();
  57. this._showProperty = undefined;
  58. this._materialProperty = undefined;
  59. this._showOutlineProperty = undefined;
  60. this._outlineColorProperty = undefined;
  61. this._outlineWidth = 1.0;
  62. this._shadowsProperty = undefined;
  63. this._distanceDisplayConditionProperty = undefined;
  64. this._classificationTypeProperty = undefined;
  65. this._options = options.geometryOptions;
  66. this._geometryPropertyName = geometryPropertyName;
  67. this._id = `${geometryPropertyName}-${entity.id}`;
  68. this._observedPropertyNames = options.observedPropertyNames;
  69. this._supportsMaterialsforEntitiesOnTerrain = Entity.supportsMaterialsforEntitiesOnTerrain(
  70. options.scene
  71. );
  72. }
  73. Object.defineProperties(GeometryUpdater.prototype, {
  74. /**
  75. * Gets the unique ID associated with this updater
  76. * @memberof GeometryUpdater.prototype
  77. * @type {String}
  78. * @readonly
  79. */
  80. id: {
  81. get: function () {
  82. return this._id;
  83. },
  84. },
  85. /**
  86. * Gets the entity associated with this geometry.
  87. * @memberof GeometryUpdater.prototype
  88. *
  89. * @type {Entity}
  90. * @readonly
  91. */
  92. entity: {
  93. get: function () {
  94. return this._entity;
  95. },
  96. },
  97. /**
  98. * Gets a value indicating if the geometry has a fill component.
  99. * @memberof GeometryUpdater.prototype
  100. *
  101. * @type {Boolean}
  102. * @readonly
  103. */
  104. fillEnabled: {
  105. get: function () {
  106. return this._fillEnabled;
  107. },
  108. },
  109. /**
  110. * Gets a value indicating if fill visibility varies with simulation time.
  111. * @memberof GeometryUpdater.prototype
  112. *
  113. * @type {Boolean}
  114. * @readonly
  115. */
  116. hasConstantFill: {
  117. get: function () {
  118. return (
  119. !this._fillEnabled ||
  120. (!defined(this._entity.availability) &&
  121. Property.isConstant(this._showProperty) &&
  122. Property.isConstant(this._fillProperty))
  123. );
  124. },
  125. },
  126. /**
  127. * Gets the material property used to fill the geometry.
  128. * @memberof GeometryUpdater.prototype
  129. *
  130. * @type {MaterialProperty}
  131. * @readonly
  132. */
  133. fillMaterialProperty: {
  134. get: function () {
  135. return this._materialProperty;
  136. },
  137. },
  138. /**
  139. * Gets a value indicating if the geometry has an outline component.
  140. * @memberof GeometryUpdater.prototype
  141. *
  142. * @type {Boolean}
  143. * @readonly
  144. */
  145. outlineEnabled: {
  146. get: function () {
  147. return this._outlineEnabled;
  148. },
  149. },
  150. /**
  151. * Gets a value indicating if the geometry has an outline component.
  152. * @memberof GeometryUpdater.prototype
  153. *
  154. * @type {Boolean}
  155. * @readonly
  156. */
  157. hasConstantOutline: {
  158. get: function () {
  159. return (
  160. !this._outlineEnabled ||
  161. (!defined(this._entity.availability) &&
  162. Property.isConstant(this._showProperty) &&
  163. Property.isConstant(this._showOutlineProperty))
  164. );
  165. },
  166. },
  167. /**
  168. * Gets the {@link Color} property for the geometry outline.
  169. * @memberof GeometryUpdater.prototype
  170. *
  171. * @type {Property}
  172. * @readonly
  173. */
  174. outlineColorProperty: {
  175. get: function () {
  176. return this._outlineColorProperty;
  177. },
  178. },
  179. /**
  180. * Gets the constant with of the geometry outline, in pixels.
  181. * This value is only valid if isDynamic is false.
  182. * @memberof GeometryUpdater.prototype
  183. *
  184. * @type {Number}
  185. * @readonly
  186. */
  187. outlineWidth: {
  188. get: function () {
  189. return this._outlineWidth;
  190. },
  191. },
  192. /**
  193. * Gets the property specifying whether the geometry
  194. * casts or receives shadows from light sources.
  195. * @memberof GeometryUpdater.prototype
  196. *
  197. * @type {Property}
  198. * @readonly
  199. */
  200. shadowsProperty: {
  201. get: function () {
  202. return this._shadowsProperty;
  203. },
  204. },
  205. /**
  206. * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed.
  207. * @memberof GeometryUpdater.prototype
  208. *
  209. * @type {Property}
  210. * @readonly
  211. */
  212. distanceDisplayConditionProperty: {
  213. get: function () {
  214. return this._distanceDisplayConditionProperty;
  215. },
  216. },
  217. /**
  218. * Gets or sets the {@link ClassificationType} Property specifying if this geometry will classify terrain, 3D Tiles, or both when on the ground.
  219. * @memberof GeometryUpdater.prototype
  220. *
  221. * @type {Property}
  222. * @readonly
  223. */
  224. classificationTypeProperty: {
  225. get: function () {
  226. return this._classificationTypeProperty;
  227. },
  228. },
  229. /**
  230. * Gets a value indicating if the geometry is time-varying.
  231. * If true, all visualization is delegated to a DynamicGeometryUpdater
  232. * returned by GeometryUpdater#createDynamicUpdater.
  233. * @memberof GeometryUpdater.prototype
  234. *
  235. * @type {Boolean}
  236. * @readonly
  237. */
  238. isDynamic: {
  239. get: function () {
  240. return this._dynamic;
  241. },
  242. },
  243. /**
  244. * Gets a value indicating if the geometry is closed.
  245. * This property is only valid for static geometry.
  246. * @memberof GeometryUpdater.prototype
  247. *
  248. * @type {Boolean}
  249. * @readonly
  250. */
  251. isClosed: {
  252. get: function () {
  253. return this._isClosed;
  254. },
  255. },
  256. /**
  257. * Gets a value indicating if the geometry should be drawn on terrain.
  258. * @memberof EllipseGeometryUpdater.prototype
  259. *
  260. * @type {Boolean}
  261. * @readonly
  262. */
  263. onTerrain: {
  264. get: function () {
  265. return this._onTerrain;
  266. },
  267. },
  268. /**
  269. * Gets an event that is raised whenever the public properties
  270. * of this updater change.
  271. * @memberof GeometryUpdater.prototype
  272. *
  273. * @type {Boolean}
  274. * @readonly
  275. */
  276. geometryChanged: {
  277. get: function () {
  278. return this._geometryChanged;
  279. },
  280. },
  281. });
  282. /**
  283. * Checks if the geometry is outlined at the provided time.
  284. *
  285. * @param {JulianDate} time The time for which to retrieve visibility.
  286. * @returns {Boolean} true if geometry is outlined at the provided time, false otherwise.
  287. */
  288. GeometryUpdater.prototype.isOutlineVisible = function (time) {
  289. const entity = this._entity;
  290. const visible =
  291. this._outlineEnabled &&
  292. entity.isAvailable(time) &&
  293. this._showProperty.getValue(time) &&
  294. this._showOutlineProperty.getValue(time);
  295. return defaultValue(visible, false);
  296. };
  297. /**
  298. * Checks if the geometry is filled at the provided time.
  299. *
  300. * @param {JulianDate} time The time for which to retrieve visibility.
  301. * @returns {Boolean} true if geometry is filled at the provided time, false otherwise.
  302. */
  303. GeometryUpdater.prototype.isFilled = function (time) {
  304. const entity = this._entity;
  305. const visible =
  306. this._fillEnabled &&
  307. entity.isAvailable(time) &&
  308. this._showProperty.getValue(time) &&
  309. this._fillProperty.getValue(time);
  310. return defaultValue(visible, false);
  311. };
  312. /**
  313. * Creates the geometry instance which represents the fill of the geometry.
  314. *
  315. * @function
  316. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  317. * @returns {GeometryInstance} The geometry instance representing the filled portion of the geometry.
  318. *
  319. * @exception {DeveloperError} This instance does not represent a filled geometry.
  320. */
  321. GeometryUpdater.prototype.createFillGeometryInstance =
  322. DeveloperError.throwInstantiationError;
  323. /**
  324. * Creates the geometry instance which represents the outline of the geometry.
  325. *
  326. * @function
  327. * @param {JulianDate} time The time to use when retrieving initial attribute values.
  328. * @returns {GeometryInstance} The geometry instance representing the outline portion of the geometry.
  329. *
  330. * @exception {DeveloperError} This instance does not represent an outlined geometry.
  331. */
  332. GeometryUpdater.prototype.createOutlineGeometryInstance =
  333. DeveloperError.throwInstantiationError;
  334. /**
  335. * Returns true if this object was destroyed; otherwise, false.
  336. *
  337. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  338. */
  339. GeometryUpdater.prototype.isDestroyed = function () {
  340. return false;
  341. };
  342. /**
  343. * Destroys and resources used by the object. Once an object is destroyed, it should not be used.
  344. *
  345. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  346. */
  347. GeometryUpdater.prototype.destroy = function () {
  348. destroyObject(this);
  349. };
  350. /**
  351. * @param {Entity} entity
  352. * @param {Object} geometry
  353. * @private
  354. */
  355. GeometryUpdater.prototype._isHidden = function (entity, geometry) {
  356. const show = geometry.show;
  357. return (
  358. defined(show) && show.isConstant && !show.getValue(Iso8601.MINIMUM_VALUE)
  359. );
  360. };
  361. /**
  362. * @param {Entity} entity
  363. * @param {Object} geometry
  364. * @private
  365. */
  366. GeometryUpdater.prototype._isOnTerrain = function (entity, geometry) {
  367. return false;
  368. };
  369. /**
  370. * @param {GeometryOptions} options
  371. * @private
  372. */
  373. GeometryUpdater.prototype._getIsClosed = function (options) {
  374. return true;
  375. };
  376. /**
  377. * @param {Entity} entity
  378. * @param {Object} geometry
  379. * @private
  380. */
  381. GeometryUpdater.prototype._isDynamic = DeveloperError.throwInstantiationError;
  382. /**
  383. * @param {Entity} entity
  384. * @param {Object} geometry
  385. * @private
  386. */
  387. GeometryUpdater.prototype._setStaticOptions =
  388. DeveloperError.throwInstantiationError;
  389. /**
  390. * @param {Entity} entity
  391. * @param {String} propertyName
  392. * @param {*} newValue
  393. * @param {*} oldValue
  394. * @private
  395. */
  396. GeometryUpdater.prototype._onEntityPropertyChanged = function (
  397. entity,
  398. propertyName,
  399. newValue,
  400. oldValue
  401. ) {
  402. if (this._observedPropertyNames.indexOf(propertyName) === -1) {
  403. return;
  404. }
  405. const geometry = this._entity[this._geometryPropertyName];
  406. if (!defined(geometry)) {
  407. if (this._fillEnabled || this._outlineEnabled) {
  408. this._fillEnabled = false;
  409. this._outlineEnabled = false;
  410. this._geometryChanged.raiseEvent(this);
  411. }
  412. return;
  413. }
  414. const fillProperty = geometry.fill;
  415. const fillEnabled =
  416. defined(fillProperty) && fillProperty.isConstant
  417. ? fillProperty.getValue(Iso8601.MINIMUM_VALUE)
  418. : true;
  419. const outlineProperty = geometry.outline;
  420. let outlineEnabled = defined(outlineProperty);
  421. if (outlineEnabled && outlineProperty.isConstant) {
  422. outlineEnabled = outlineProperty.getValue(Iso8601.MINIMUM_VALUE);
  423. }
  424. if (!fillEnabled && !outlineEnabled) {
  425. if (this._fillEnabled || this._outlineEnabled) {
  426. this._fillEnabled = false;
  427. this._outlineEnabled = false;
  428. this._geometryChanged.raiseEvent(this);
  429. }
  430. return;
  431. }
  432. const show = geometry.show;
  433. if (this._isHidden(entity, geometry)) {
  434. if (this._fillEnabled || this._outlineEnabled) {
  435. this._fillEnabled = false;
  436. this._outlineEnabled = false;
  437. this._geometryChanged.raiseEvent(this);
  438. }
  439. return;
  440. }
  441. this._materialProperty = defaultValue(geometry.material, defaultMaterial);
  442. this._fillProperty = defaultValue(fillProperty, defaultFill);
  443. this._showProperty = defaultValue(show, defaultShow);
  444. this._showOutlineProperty = defaultValue(geometry.outline, defaultOutline);
  445. this._outlineColorProperty = outlineEnabled
  446. ? defaultValue(geometry.outlineColor, defaultOutlineColor)
  447. : undefined;
  448. this._shadowsProperty = defaultValue(geometry.shadows, defaultShadows);
  449. this._distanceDisplayConditionProperty = defaultValue(
  450. geometry.distanceDisplayCondition,
  451. defaultDistanceDisplayCondition
  452. );
  453. this._classificationTypeProperty = defaultValue(
  454. geometry.classificationType,
  455. defaultClassificationType
  456. );
  457. this._fillEnabled = fillEnabled;
  458. const onTerrain =
  459. this._isOnTerrain(entity, geometry) &&
  460. (this._supportsMaterialsforEntitiesOnTerrain ||
  461. this._materialProperty instanceof ColorMaterialProperty);
  462. if (outlineEnabled && onTerrain) {
  463. oneTimeWarning(oneTimeWarning.geometryOutlines);
  464. outlineEnabled = false;
  465. }
  466. this._onTerrain = onTerrain;
  467. this._outlineEnabled = outlineEnabled;
  468. if (this._isDynamic(entity, geometry)) {
  469. if (!this._dynamic) {
  470. this._dynamic = true;
  471. this._geometryChanged.raiseEvent(this);
  472. }
  473. } else {
  474. this._setStaticOptions(entity, geometry);
  475. this._isClosed = this._getIsClosed(this._options);
  476. const outlineWidth = geometry.outlineWidth;
  477. this._outlineWidth = defined(outlineWidth)
  478. ? outlineWidth.getValue(Iso8601.MINIMUM_VALUE)
  479. : 1.0;
  480. this._dynamic = false;
  481. this._geometryChanged.raiseEvent(this);
  482. }
  483. };
  484. /**
  485. * Creates the dynamic updater to be used when GeometryUpdater#isDynamic is true.
  486. *
  487. * @param {PrimitiveCollection} primitives The primitive collection to use.
  488. * @param {PrimitiveCollection} [groundPrimitives] The primitive collection to use for ground primitives.
  489. *
  490. * @returns {DynamicGeometryUpdater} The dynamic updater used to update the geometry each frame.
  491. *
  492. * @exception {DeveloperError} This instance does not represent dynamic geometry.
  493. * @private
  494. */
  495. GeometryUpdater.prototype.createDynamicUpdater = function (
  496. primitives,
  497. groundPrimitives
  498. ) {
  499. //>>includeStart('debug', pragmas.debug);
  500. Check.defined("primitives", primitives);
  501. Check.defined("groundPrimitives", groundPrimitives);
  502. if (!this._dynamic) {
  503. throw new DeveloperError(
  504. "This instance does not represent dynamic geometry."
  505. );
  506. }
  507. //>>includeEnd('debug');
  508. return new this.constructor.DynamicGeometryUpdater(
  509. this,
  510. primitives,
  511. groundPrimitives
  512. );
  513. };
  514. export default GeometryUpdater;