Cesium3DTilesetHeatmap.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import Color from "../Core/Color.js";
  2. import defined from "../Core/defined.js";
  3. import JulianDate from "../Core/JulianDate.js";
  4. import CesiumMath from "../Core/Math.js";
  5. /**
  6. * A heatmap colorizer in a {@link Cesium3DTileset}. A tileset can colorize its visible tiles in a heatmap style.
  7. *
  8. * @alias Cesium3DTilesetHeatmap
  9. * @constructor
  10. * @private
  11. */
  12. function Cesium3DTilesetHeatmap(tilePropertyName) {
  13. /**
  14. * The tile variable to track for heatmap colorization.
  15. * Tile's will be colorized relative to the other visible tile's values for this variable.
  16. *
  17. * @type {String}
  18. */
  19. this.tilePropertyName = tilePropertyName;
  20. // Members that are updated every time a tile is colorized
  21. this._minimum = Number.MAX_VALUE;
  22. this._maximum = -Number.MAX_VALUE;
  23. // Members that are updated once every frame
  24. this._previousMinimum = Number.MAX_VALUE;
  25. this._previousMaximum = -Number.MAX_VALUE;
  26. // If defined uses a reference minimum maximum to colorize by instead of using last frames minimum maximum of rendered tiles.
  27. // For example, the _loadTimestamp can get a better colorization using setReferenceMinimumMaximum in order to take accurate colored timing diffs of various scenes.
  28. this._referenceMinimum = {};
  29. this._referenceMaximum = {};
  30. }
  31. /**
  32. * Convert to a usable heatmap value (i.e. a number). Ensures that tile values that aren't stored as numbers can be used for colorization.
  33. * @private
  34. */
  35. function getHeatmapValue(tileValue, tilePropertyName) {
  36. let value;
  37. if (tilePropertyName === "_loadTimestamp") {
  38. value = JulianDate.toDate(tileValue).getTime();
  39. } else {
  40. value = tileValue;
  41. }
  42. return value;
  43. }
  44. /**
  45. * Sets the reference minimum and maximum for the variable name. Converted to numbers before they are stored.
  46. *
  47. * @param {Object} minimum The minimum reference value.
  48. * @param {Object} maximum The maximum reference value.
  49. * @param {String} tilePropertyName The tile variable that will use these reference values when it is colorized.
  50. */
  51. Cesium3DTilesetHeatmap.prototype.setReferenceMinimumMaximum = function (
  52. minimum,
  53. maximum,
  54. tilePropertyName
  55. ) {
  56. this._referenceMinimum[tilePropertyName] = getHeatmapValue(
  57. minimum,
  58. tilePropertyName
  59. );
  60. this._referenceMaximum[tilePropertyName] = getHeatmapValue(
  61. maximum,
  62. tilePropertyName
  63. );
  64. };
  65. function getHeatmapValueAndUpdateMinimumMaximum(heatmap, tile) {
  66. const tilePropertyName = heatmap.tilePropertyName;
  67. if (defined(tilePropertyName)) {
  68. const heatmapValue = getHeatmapValue(
  69. tile[tilePropertyName],
  70. tilePropertyName
  71. );
  72. if (!defined(heatmapValue)) {
  73. heatmap.tilePropertyName = undefined;
  74. return heatmapValue;
  75. }
  76. heatmap._maximum = Math.max(heatmapValue, heatmap._maximum);
  77. heatmap._minimum = Math.min(heatmapValue, heatmap._minimum);
  78. return heatmapValue;
  79. }
  80. }
  81. const heatmapColors = [
  82. new Color(0.1, 0.1, 0.1, 1), // Dark Gray
  83. new Color(0.153, 0.278, 0.878, 1), // Blue
  84. new Color(0.827, 0.231, 0.49, 1), // Pink
  85. new Color(0.827, 0.188, 0.22, 1), // Red
  86. new Color(1.0, 0.592, 0.259, 1), // Orange
  87. new Color(1.0, 0.843, 0.0, 1),
  88. ]; // Yellow
  89. /**
  90. * Colorize the tile in heat map style based on where it lies within the minimum maximum window.
  91. * Heatmap colors are black, blue, pink, red, orange, yellow. 'Cold' or low numbers will be black and blue, 'Hot' or high numbers will be orange and yellow,
  92. * @param {Cesium3DTile} tile The tile to colorize relative to last frame's minimum and maximum values of all visible tiles.
  93. * @param {FrameState} frameState The frame state.
  94. */
  95. Cesium3DTilesetHeatmap.prototype.colorize = function (tile, frameState) {
  96. const tilePropertyName = this.tilePropertyName;
  97. if (
  98. !defined(tilePropertyName) ||
  99. !tile.contentAvailable ||
  100. tile._selectedFrame !== frameState.frameNumber
  101. ) {
  102. return;
  103. }
  104. const heatmapValue = getHeatmapValueAndUpdateMinimumMaximum(this, tile);
  105. const minimum = this._previousMinimum;
  106. const maximum = this._previousMaximum;
  107. if (minimum === Number.MAX_VALUE || maximum === -Number.MAX_VALUE) {
  108. return;
  109. }
  110. // Shift the minimum maximum window down to 0
  111. const shiftedMax = maximum - minimum + CesiumMath.EPSILON7; // Prevent divide by 0
  112. const shiftedValue = CesiumMath.clamp(
  113. heatmapValue - minimum,
  114. 0.0,
  115. shiftedMax
  116. );
  117. // Get position between minimum and maximum and convert that to a position in the color array
  118. const zeroToOne = shiftedValue / shiftedMax;
  119. const lastIndex = heatmapColors.length - 1.0;
  120. const colorPosition = zeroToOne * lastIndex;
  121. // Take floor and ceil of the value to get the two colors to lerp between, lerp using the fractional portion
  122. const colorPositionFloor = Math.floor(colorPosition);
  123. const colorPositionCeil = Math.ceil(colorPosition);
  124. const t = colorPosition - colorPositionFloor;
  125. const colorZero = heatmapColors[colorPositionFloor];
  126. const colorOne = heatmapColors[colorPositionCeil];
  127. // Perform the lerp
  128. const finalColor = Color.clone(Color.WHITE);
  129. finalColor.red = CesiumMath.lerp(colorZero.red, colorOne.red, t);
  130. finalColor.green = CesiumMath.lerp(colorZero.green, colorOne.green, t);
  131. finalColor.blue = CesiumMath.lerp(colorZero.blue, colorOne.blue, t);
  132. tile._debugColor = finalColor;
  133. };
  134. /**
  135. * Resets the tracked minimum maximum values for heatmap colorization. Happens right before tileset traversal.
  136. */
  137. Cesium3DTilesetHeatmap.prototype.resetMinimumMaximum = function () {
  138. // For heat map colorization
  139. const tilePropertyName = this.tilePropertyName;
  140. if (defined(tilePropertyName)) {
  141. const referenceMinimum = this._referenceMinimum[tilePropertyName];
  142. const referenceMaximum = this._referenceMaximum[tilePropertyName];
  143. const useReference = defined(referenceMinimum) && defined(referenceMaximum);
  144. this._previousMinimum = useReference ? referenceMinimum : this._minimum;
  145. this._previousMaximum = useReference ? referenceMaximum : this._maximum;
  146. this._minimum = Number.MAX_VALUE;
  147. this._maximum = -Number.MAX_VALUE;
  148. }
  149. };
  150. export default Cesium3DTilesetHeatmap;