BoxGeometryUpdater.js 21 KB

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