WallGeometryUpdater.js 21 KB

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