Viewing contents of file '../idllib/user_contrib/hamill/tvstack.pro'
PRO TVSTACK, IMAGES, W_BORDER=W_BORDER, C_BORDER=C_BORDER, TVSCL=TVSCL, $
	POSITION=POSITION, $
	REVERSE_DIM=REVERSE_DIM, ROTATE_PAR=ROTATE_PAR, SKIP=SKIP

;+
; NAME:
;	TVSTACK
;
; PURPOSE:
;	This procedure displays a multidimensional array (e.g. 3D) as a stack of
;	images lain side by side, and by default scaled between the minimum and
;	maximum values in the array.  This is a method of visualizing 3D data
;	sets, for example reconstructions of tracer uptake in nuclear medicine.
;	For an image measuring NX by NY by NZ, the effect is somewhat the same
;	as typing
;
;		for z=0,nz-1 do tvscl, image(*,*,z), z
;
;	except that they aren't necessarily scaled to the frame maxima, and
;	some options are available through the keywords.
;
; CATEGORY:
;	IMAGE DISPLAY
;
; CALLING SEQUENCE:
;	TVSTACK, IMAGES
;
; INPUTS:
;	IMAGES: The multidimensional array to be displayed.  It may have any
;	number of dimensions but is displayed as if it is 3D.
;	
; KEYWORD PARAMETERS:
;	W_BORDER: Width of the border to be drawn around each frame displayed.
;		If framing is performed, each NX by NY image takes up
;		(NX+2*W_BORDER) pixels in the X direction and (NY+2*W_BORDER)
;		pixels in the Y direction.  Default = NO BORDER.
;	C_BORDER: Color of the border, if the W_BORDER keyword is set.  Default=
;		!d.n_colors/3.
;	TVSCL: If this keyword is set, each 2D image is scaled to its own max
;		and min.  By default, the max and min of the multidimensional
;		array are used.
;	POSITION: The screen position used by the first image frame in the
;		sequence.  Thus, images are positioned as if the command
;
;			for z=0,nz-1 do tvscl, image(*,*,z), position+z
;
;		were used.  Default = 0 (start in upper left corner of th
;		display window.)
;	REVERSE_DIM: which dimension of the image is to be reversed (using the
;		REVERSE function from the USERLIB); 1 means X, 2 means Y.
;		Default = NO REVERSAL.
;	ROTATE_PAR: what parameter to use to rotate the image frames, with the
;		IDL ROTATE function (q.v.) in which 0=no rotation, 1=90 degrees
;		CCW without transposing, and so on.  Defaul=NO ROTATION.
;	SKIP: Use this keyword if you desire to display only some of the images
;		for example every other one, which would be represented by
;		SKIP=2.  Images are positioned as if the command
;
;			for z=0,nz-1,SKIP do tvscl, image(*,*,z), z/SKIP
;
;		were used.  Default = 1, that is, do not skip.  If you specify
;		/SKIP you end up not skipping (!!!) because in this case you
;		specify steps of 1.
;
; OUTPUTS:
;	None; the procedure writes into the current display window.
;
; EXAMPLE:  A 3D gaussian can be displayed as follows:
;
;	n = 50
;	xysq = shift(dist(n)^2,n/2,n/2)	; x^2 + y^2
;	rsq = fltarr(n,n,n)		; array to hold r^2
;	for z=0,n-1 do rsq(0,0,z) = (z-n/2.0)^2 + xysq
;					; r^2 = x^2 + y^2 + z^2
;	fwhm=10.0 & sig=fwhm/(2*sqrt(2*alog(2))) & gauss_3D=exp(-rsq/(2*sig^2))
;					; 3D gaussian of 10 channels FWHM
;	tvstack, gauss_3D, /w_b		; display it
;
; MODIFICATION HISTORY:
; 	Written by:	James Hamill
;			Siemens Medical Systems
;			2501 N. Barrington Rd.
;			Hoffman Estates, IL  60195-7372
;			(708)304-7760
;			hamill@sgi.siemens.com
;			April, 1992
;-


ndim = 3		; expected # of dimensions

sizi = size(images)
if sizi(0) ne ndim then REFORM_FLAG=1 else REFORM_FLAG=0
nx = sizi(1)
ny = sizi(2)
nz = sizi(3)

if n_elements(w_border) eq 0 then w_border=0
if n_elements(c_border) eq 0 then c_border=!d.n_colors/3
if keyword_set(tvscl) eq 0 then tvscl_flag=0 else tvscl_flag=1
if n_elements(position) eq 0 then position=0
if n_elements(skip) eq 0 then skip=1

;  Max and min ...

if tvscl_flag ne 1 then begin
  mn=min(images)
  mx=max(images)
  if mx eq mn then mx=mn+1
endif

;  Set up buffer with the border color all around

xsize = nx + 2*w_border
ysize = ny + 2*w_border
buffer = replicate(c_border,fix(xsize),fix(ysize))

;  Display if the data are to be reformed first ... 

IF REFORM_FLAG THEN BEGIN

  nz = n_elements(images)/nx/ny
  imp = reform(images,nx,ny,nz)

  for z=0,nz-1,skip do begin
    if tvscl_flag eq 1 then $
	buffer(w_border,w_border) = bytscl(imp(*,*,z)) $
    else $
	buffer(w_border,w_border) = (!d.n_colors-1)*(imp(*,*,z)-mn)/(mx-mn)
    if keyword_set(reverse_dim) then buffer=reverse(buffer,reverse_dim)
    if keyword_set(rotate_par) then buffer=rotate(buffer,rotate_par)
    tv,buffer,z/skip+position
  endfor

;  ...otherwise display the data itself.

ENDIF ELSE BEGIN

  for z=0,nz-1,skip do begin
    if tvscl_flag eq 1 then $
	buffer(w_border,w_border) = bytscl(images(*,*,z)) $
    else $
	buffer(w_border,w_border) = (!d.n_colors-1)*(images(*,*,z)-mn)/(mx-mn)
    if keyword_set(reverse_dim) then buffer=reverse(buffer,reverse_dim)
    if keyword_set(rotate_par) then buffer=rotate(buffer,rotate_par)
    tv,buffer,z/skip+position
  endfor

ENDELSE


RETURN

end