;+ ; NAME: ; RemoteView_rgbo ; PURPOSE: ; Sets up the RGBO vector for volume rendering ; CATEGORY: ; Volume rendering: RemoteView ; CALLING SEQUENCE: FUNCTION RemoteView_rgbo, $ rgbo = rgbo, $ rgb_range = rgb_range, $ full_range = full_range, $ full_color = full_color, $ full_opacity = full_opacity, $ mid_range = mid_range, $ mid_color = mid_color, $ mid_opacity = mid_opacity, $ opacity_power = opacity_power, $ update = update, $ postfix = postfix, $ data_range = data_range, $ rgb_index = rgb_index, $ silent = silent ; INPUTS: ; full_range=full_range ; scalar or array[2]; type: any; no default (MUST be specified) ; A scalar is interpreted as [0,full_range] ; The full range of values of rendered data in data units ; (e.g. cm^-3 for a rendering of densities) ; This range is converted to the byte range 'rgb_range' (using bytscl). ; OPTIONAL INPUT PARAMETERS: ; rgbo=rgbo array[256,4]; type: float ; rgbo vector to be updated. If 'rgbo' does not exist and /update ; is not set then a new rgbo vector is created. ; ; /update if set then the input rgbo vector is updated ; (ignored if rgbo is not defined) ; ; rgb_range = rgb_range ; scalar or array[2]; type: byte; default: [0B,255B] ; Range of elements in rgbo assigned to the data set. ; ; mid_range = mid_range ; scalar or array[2]; type: any; default: full_range ; A scalar is interpreted as [0,full_range] ; Internally this is restricted to be a subrange of 'full_range' ; ; Range of data values defining 'intermediate data values' ; ; full_color = full_color ; scalar or array[2]; default: [0,235] ; A scalar is interpreted as [0,full_color]. ; ; Range of colors to be used in the rendering. ; Internally this is restricted to the available colors (currently 236). ; color_range[0] is matched to data value full_range[0] ; color_range[1] is matched to data value full_range[1] ; ; mid_color = mid_color ; scalar or array[2]; default: full_color ; Internally this is restricted to be a subrange of 'full_color' ; Range of colors used for rendering the intermediate data values ; ; full_opacity = full_opacity ; scalar or array[2]; type: float; default: [0,1] ; range of opacity values ; ; mid_opacity = mid_opacity ; scalar or array[2]; type: float; default: full_opacity ; Internally this is restricted to be a subrange of 'full_opacity' ; Opacity applied to data values to mid-range data values ; ; opacity_power = opacity_power ; scalar; type: float; default: 1 ; power applied to opacity for mid-range data values ; ; OUTPUTS: ; rgbo array[256,4]; type: float ; rgbo color vector needed for volume rendering ; The first index [0,255] represent the data values. ; Only the range 'rgb_range' is filled. The rest is zero ; (if rgbo is created), or unmodified (if rgbo is updated) ; The colors values rgbo[0:2,*] are not yet multiplied ; with the opacities. ; ; data_range= data_range ; array[2], type: float ; The actual range of values of rendered data in data units. ; This is derived from the input 'full_range' ; rgb_index = rgb_index ; array[2], type: byte ; Actual range of elements in rgbo assigned to the data set. ; This is derived from the input 'rgb_range' ; INCLUDE: @compile_opt.pro ; On error, return to caller @skycolors.pro ; Dummy comment for Linux ; CALLS: ; InitVar, IsType, SetRange, flt_read, SuperArray, gridgen, who_am_i ; SIDE EFFECTS: ; Needs file remoteview_rgbo.txt, storing the color table information ; RESTRICTIONS: ; PROCEDURE: ; The original 3D matrix will cover a certain range of data values. Volume rendering ; can only handle a maximum of 256 different 'density values'. ; ; We first need to decide how many of these 256 colors we want to assign to the ; 3D density matrix. If only one 3D volume data set is rendered then the full ; range [0,255] can be used, but when several 3D volume data sets are merged ; each set is assigned its own subrange. This is done with keyword 'rgb_range' ; ; Next we need to set the range of data values in the 3D matrix to be rendered. ; 'full_range' sets the data range to be scaled to 'rgb_range'. The 3D matrix has ; to be converted to byte by the IDL bytscl command (as e.g. in href=RemoteView_Display3D=) ; ; rgb_range[0]+bytscl( Matrix, top=rgb_range[1]-rgb_range[0], min=full_range[0], max=full_range[1]) ; ; This scales the data values to the proper range 'rgb_range' ; Note that data values below full_range[0] are treated the same as full_range[0], and data ; values above full_range[1] the same as full_range[1]). ; ; 'mid_range' selects a subrange of 'full_range'. These two values separate the full range ; in three sections: ; low data values: [full_range[0], mid_range[0]] ; intermediate values: [mid_range [0], mid_range[1]] ; high data values: [midrange [1], full_range[0]] ; These three ranges are treated separately. ; ; To set up the rgbo vector an 8-bit color table and an opacity needs to be defined. ; The color table information is stored in two files (see RESTRICTIONS). ; Keywords 'full_color' and 'mid_color' select color ranges from this table. ; Keywords 'full_opacity' and 'mid_opacity' set the opacities. ; ; Data values, color indices and opacities are matched as follows: ; full_range[0] <-----> full_color[0] <------> full_opacity[0] ; mid_range [0] <-----> mid_color [0] <------> mid_opacity [0] ; mid_range [1] <-----> mid_color [1] <------> mid_opacity [1] ; full_range[1] <-----> full_color[1] <------> full_opacity[1] ; ; For the low data values (between full_range[0] and mid_range[1]) both color index ; and opacity are obtained by a linear scaling with the data values; the same is ; the case for the high data values (between mid_range[1] and full_range[1]). ; ; For the intermediate data values the color index scales linearly with the ; data values. The opacity scales as a power law of data value with the power ; specified in keyword opacity_power. ; MODIFICATION HISTORY: ; JUN-2000, Paul Hick (UCSD/CASS) ; AUG-2002, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; Color table file is now looked for in same directory as ; this source code file. ;- InitVar, update, /key refresh = 1-update OR IsType(rgbo, /undefined) InitVar, opacity_power, 2.0 InitVar, silent, 0 ; Index range in rgbo used for this data set default = [0B,255B] InitVar, rgb_range, default rgb_index = SetRange(default, rgb_range) ; Set data range to be rendered CASE n_elements(full_range) OF 0 : message, 'no density range specified' 1 : data_range = [0,full_range[0 ]] ELSE: data_range = full_range[0:1] ENDCASE ; Set up range for intermediate data values. ; Stay inside limits set by data_range. mid_data_range = SetRange(data_range, mid_range) ; Set opacity ranges opacity_range = SetRange([0,1], full_opacity) mid_opacity_range = SetRange(opacity_range, mid_opacity) ; Read color tables from file ; remoteview_rgbo.txt contains all RGB triplets. InitVar, postfix, '' IF NOT flt_read(filepath(root=who_am_i(/directory),'remoteview_rgbo'+postfix+'.txt'), $ rgb_table,silent=silent,error=error) THEN message, 'No rgbo color info: '+error rgb_table = transpose( byte(rgb_table) ) ; Color table available for the volume rendering. Add a 4th row for ; the opacities to the rows for R, G and B values filled with 255B. ncols = (size(rgb_table,/dim))[0] ; # colors for rgbo rendering IF silent EQ 0 THEN message, /info, strcompress(ncols,/rem)+' colors in rgbo color table' rgb_table = [ [rgb_table], [replicate(255B, ncols)] ] ; Set limits on color index ranges color_index = SetRange([0,ncols-1], full_color) mid_color_index = SetRange(color_index, mid_color ) ; Set up rgbo vector nrgb = rgb_index[1]-rgb_index[0]+1 ; # entries in rgb to be set color = bytarr(nrgb) ; nrgb colors opacity = fltarr(nrgb) ; nrgb opacities ; Find color index range occupied by the intermediate densities ; (in range [0, rgb_index[1]-rgb_index[0]]) mid_data_index = float(rgb_index[1]-rgb_index[0])/(data_range[1]-data_range[0])*(mid_data_range-data_range[0]) mid_data_index = round(mid_data_index) ; Set up color indices and opacities for the low data range by linear interpolation. IF mid_data_index[0] GT 0 THEN BEGIN color [0:mid_data_index[0]] = round( gridgen(mid_data_index[0]+1, range=[color_index [0], mid_color_index [0]]) ) opacity[0:mid_data_index[0]] = gridgen(mid_data_index[0]+1, range=[opacity_range[0], mid_opacity_range[0]]) ENDIF ; Set up color indices and opacities for the high data range by linear interpolation. IF mid_data_index[1] LT nrgb-1 THEN BEGIN color [mid_data_index[1]:*] = round( gridgen(nrgb-mid_data_index[1], range=[mid_color_index [1], color_index [1]]) ) opacity[mid_data_index[1]:*] = gridgen(nrgb-mid_data_index[1], range=[mid_opacity_range[1], opacity_range[1]]) ENDIF ; Set up color indices and opacities for the mid data range. ; The color indices are obtained by linear interpolation, the opacities by a power law. nmid = mid_data_index[1]-mid_data_index[0]+1 color [mid_data_index[0]:mid_data_index[1]] = round( mid_color_index [0]+(mid_color_index [1]-mid_color_index [0])*gridgen(nmid, /one) ) opacity[mid_data_index[0]:mid_data_index[1]] = mid_opacity_range[0]+(mid_opacity_range[1]-mid_opacity_range[0])*gridgen(nmid, /one)^opacity_power ; If /refresh keyword is set then create a new empty rgbo vector. IF refresh THEN rgbo = fltarr(256,4) ; Multiplying the r,g,b values with the opacities has the disadvantage ; that for zero opacities the information about the original color is ; lost. The color may still be needed (to draw e.g. a color legend). ;rgbo[rgb_index[0]:rgb_index[1],*] = SuperArray(opacity,4,/trail)*rgb_table[color,*] rgbo[rgb_index[0]:rgb_index[1],0:2] = rgb_table[color,0:2] rgbo[rgb_index[0]:rgb_index[1], 3] = rgb_table[color, 3]*opacity RETURN, rgbo & END