Lut.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. import {
  2. Color,
  3. LinearSRGBColorSpace,
  4. MathUtils
  5. } from 'three';
  6. /**
  7. * Represents a lookup table for colormaps. It is used to determine the color
  8. * values from a range of data values.
  9. *
  10. * ```js
  11. * const lut = new Lut( 'rainbow', 512 );
  12. * const color = lut.getColor( 0.5 );
  13. * ```
  14. */
  15. class Lut {
  16. /**
  17. * Constructs a new Lut.
  18. *
  19. * @param {('rainbow'|'cooltowarm'|'blackbody'|'grayscale')} [colormap='rainbow'] - Sets a colormap from predefined list of colormaps.
  20. * @param {number} [count=32] - Sets the number of colors used to represent the data array.
  21. */
  22. constructor( colormap, count = 32 ) {
  23. /**
  24. * This flag can be used for type testing.
  25. *
  26. * @type {boolean}
  27. * @readonly
  28. * @default true
  29. */
  30. this.isLut = true;
  31. /**
  32. * The lookup table for the selected color map
  33. *
  34. * @type {Array<Color>}
  35. */
  36. this.lut = [];
  37. /**
  38. * The currently selected color map.
  39. *
  40. * @type {Array}
  41. */
  42. this.map = [];
  43. /**
  44. * The number of colors of the current selected color map.
  45. *
  46. * @type {number}
  47. * @default 32
  48. */
  49. this.n = 0;
  50. /**
  51. * The minimum value to be represented with the lookup table.
  52. *
  53. * @type {number}
  54. * @default 0
  55. */
  56. this.minV = 0;
  57. /**
  58. * The maximum value to be represented with the lookup table.
  59. *
  60. * @type {number}
  61. * @default 1
  62. */
  63. this.maxV = 1;
  64. this.setColorMap( colormap, count );
  65. }
  66. /**
  67. * Sets the given LUT.
  68. *
  69. * @param {Lut} value - The LUT to set.
  70. * @return {Lut} A reference to this LUT.
  71. */
  72. set( value ) {
  73. if ( value.isLut === true ) {
  74. this.copy( value );
  75. }
  76. return this;
  77. }
  78. /**
  79. * Sets the minimum value to be represented with this LUT.
  80. *
  81. * @param {number} min - The minimum value to be represented with the lookup table.
  82. * @return {Lut} A reference to this LUT.
  83. */
  84. setMin( min ) {
  85. this.minV = min;
  86. return this;
  87. }
  88. /**
  89. * Sets the maximum value to be represented with this LUT.
  90. *
  91. * @param {number} max - The maximum value to be represented with the lookup table.
  92. * @return {Lut} A reference to this LUT.
  93. */
  94. setMax( max ) {
  95. this.maxV = max;
  96. return this;
  97. }
  98. /**
  99. * Configure the lookup table for the given color map and number of colors.
  100. *
  101. * @param {string} colormap - The name of the color map.
  102. * @param {number} [count=32] - The number of colors.
  103. * @return {Lut} A reference to this LUT.
  104. */
  105. setColorMap( colormap, count = 32 ) {
  106. this.map = ColorMapKeywords[ colormap ] || ColorMapKeywords.rainbow;
  107. this.n = count;
  108. const step = 1.0 / this.n;
  109. const minColor = new Color();
  110. const maxColor = new Color();
  111. this.lut.length = 0;
  112. // sample at 0
  113. this.lut.push( new Color( this.map[ 0 ][ 1 ] ) );
  114. // sample at 1/n, ..., (n-1)/n
  115. for ( let i = 1; i < count; i ++ ) {
  116. const alpha = i * step;
  117. for ( let j = 0; j < this.map.length - 1; j ++ ) {
  118. if ( alpha > this.map[ j ][ 0 ] && alpha <= this.map[ j + 1 ][ 0 ] ) {
  119. const min = this.map[ j ][ 0 ];
  120. const max = this.map[ j + 1 ][ 0 ];
  121. minColor.setHex( this.map[ j ][ 1 ], LinearSRGBColorSpace );
  122. maxColor.setHex( this.map[ j + 1 ][ 1 ], LinearSRGBColorSpace );
  123. const color = new Color().lerpColors( minColor, maxColor, ( alpha - min ) / ( max - min ) );
  124. this.lut.push( color );
  125. }
  126. }
  127. }
  128. // sample at 1
  129. this.lut.push( new Color( this.map[ this.map.length - 1 ][ 1 ] ) );
  130. return this;
  131. }
  132. /**
  133. * Copies the given lut.
  134. *
  135. * @param {Lut} lut - The LUT to copy.
  136. * @return {Lut} A reference to this LUT.
  137. */
  138. copy( lut ) {
  139. this.lut = lut.lut;
  140. this.map = lut.map;
  141. this.n = lut.n;
  142. this.minV = lut.minV;
  143. this.maxV = lut.maxV;
  144. return this;
  145. }
  146. /**
  147. * Returns an instance of Color for the given data value.
  148. *
  149. * @param {number} alpha - The value to lookup.
  150. * @return {Color} The color from the LUT.
  151. */
  152. getColor( alpha ) {
  153. alpha = MathUtils.clamp( alpha, this.minV, this.maxV );
  154. alpha = ( alpha - this.minV ) / ( this.maxV - this.minV );
  155. const colorPosition = Math.round( alpha * this.n );
  156. return this.lut[ colorPosition ];
  157. }
  158. /**
  159. * Adds a color map to this Lut instance.
  160. *
  161. * @param {string} name - The name of the color map.
  162. * @param {Array} arrayOfColors - An array of color values. Each value is an array
  163. * holding a threshold and the actual color value as a hexadecimal number.
  164. * @return {Lut} A reference to this LUT.
  165. */
  166. addColorMap( name, arrayOfColors ) {
  167. ColorMapKeywords[ name ] = arrayOfColors;
  168. return this;
  169. }
  170. /**
  171. * Creates a canvas in order to visualize the lookup table as a texture.
  172. *
  173. * @return {HTMLCanvasElement} The created canvas.
  174. */
  175. createCanvas() {
  176. const canvas = document.createElement( 'canvas' );
  177. canvas.width = 1;
  178. canvas.height = this.n;
  179. this.updateCanvas( canvas );
  180. return canvas;
  181. }
  182. /**
  183. * Updates the given canvas with the Lut's data.
  184. *
  185. * @param {HTMLCanvasElement} canvas - The canvas to update.
  186. * @return {HTMLCanvasElement} The updated canvas.
  187. */
  188. updateCanvas( canvas ) {
  189. const ctx = canvas.getContext( '2d', { alpha: false } );
  190. const imageData = ctx.getImageData( 0, 0, 1, this.n );
  191. const data = imageData.data;
  192. let k = 0;
  193. const step = 1.0 / this.n;
  194. const minColor = new Color();
  195. const maxColor = new Color();
  196. const finalColor = new Color();
  197. for ( let i = 1; i >= 0; i -= step ) {
  198. for ( let j = this.map.length - 1; j >= 0; j -- ) {
  199. if ( i < this.map[ j ][ 0 ] && i >= this.map[ j - 1 ][ 0 ] ) {
  200. const min = this.map[ j - 1 ][ 0 ];
  201. const max = this.map[ j ][ 0 ];
  202. minColor.setHex( this.map[ j - 1 ][ 1 ], LinearSRGBColorSpace );
  203. maxColor.setHex( this.map[ j ][ 1 ], LinearSRGBColorSpace );
  204. finalColor.lerpColors( minColor, maxColor, ( i - min ) / ( max - min ) );
  205. data[ k * 4 ] = Math.round( finalColor.r * 255 );
  206. data[ k * 4 + 1 ] = Math.round( finalColor.g * 255 );
  207. data[ k * 4 + 2 ] = Math.round( finalColor.b * 255 );
  208. data[ k * 4 + 3 ] = 255;
  209. k += 1;
  210. }
  211. }
  212. }
  213. ctx.putImageData( imageData, 0, 0 );
  214. return canvas;
  215. }
  216. }
  217. const ColorMapKeywords = {
  218. 'rainbow': [[ 0.0, 0x0000FF ], [ 0.2, 0x00FFFF ], [ 0.5, 0x00FF00 ], [ 0.8, 0xFFFF00 ], [ 1.0, 0xFF0000 ]],
  219. 'cooltowarm': [[ 0.0, 0x3C4EC2 ], [ 0.2, 0x9BBCFF ], [ 0.5, 0xDCDCDC ], [ 0.8, 0xF6A385 ], [ 1.0, 0xB40426 ]],
  220. 'blackbody': [[ 0.0, 0x000000 ], [ 0.2, 0x780000 ], [ 0.5, 0xE63200 ], [ 0.8, 0xFFFF00 ], [ 1.0, 0xFFFFFF ]],
  221. 'grayscale': [[ 0.0, 0x000000 ], [ 0.2, 0x404040 ], [ 0.5, 0x7F7F80 ], [ 0.8, 0xBFBFBF ], [ 1.0, 0xFFFFFF ]]
  222. };
  223. export { Lut, ColorMapKeywords };
粤ICP备19079148号