Viewing contents of file '../idllib/astron/contrib/knight/look.pro'
;+
; Name:
; look
; Purpose:
; This procedure produces a widget to view an image or series of images.
; o You roam in a grid of 2x2 windows with menus on three sides.
; o The plots are dynamic: horizontal and vertical cuts are updated
; as you move the mouse over the full and zoom images.
; o Zoom by dragging the left mouse over the full image.
; o Select numerous options in the Options menu,
; - blink compare (between 2 or more images)
; - movies (all or selected images)
; - catalogs (all or selected images)
; - enlargements (to window and to entire screen)
; - plots (surface, shade_surf, show3, etc.)
; - regions of interest
; - spatial filters, and ...
; o Look is extensible: you can define
; - one loading function, and
; - procedures and functions for display and image processing, e.g.,
; look_fourier - to filter square images
; lego, image_cont, threed, etc. - any IDL pro using 2-D param
; roberts, sin, alog10, etc. - any IDL function using 2-D arg
; o Read more on operation below. Here's a rendition:
; -----------------------------------------------------
; | Done | cuts: | | full |
; | | vertical ---> | plot/ | & |
; |xloadct| horizontal | zoom region | zoom |
; |switch | | | /|\ | stats |
; | |------------|------------------|---| |
; |Options| \|/ | cuts: | |Incre* |
; | menu | tv/roam | horizontal |Select*|
; | | full image | <--- vertical | |
; |filter | | | |
; | slider|-----------------------------------| |
; | dim3 | plot min slider | plot max slider | |
; | ... | =======|======= | =======|======= | |
; | dim7 | Autoscale/Fixed | Autoscale/Fixed | |
; -----------------------------------------------------
; | instructions or comments |
; -----------------------------------------------------
; Examples:
; look ; 1) Test with test images
; images = randomu(seed,10,10,100)
; look,images ; 2) Display series of 2-D images
; look,/noload ; 3) Use existing images from common
; common look ; 4) To access the stored images at main level
; look,/help ; 5) Just display the look.pro header
; look,/assoc ; 6) Use an associate variable; prompt for
; ; file and definition of variable.
; ; OR
; file = 'existing_file'
; definition = 'intarr(128,128)'
; look,/assoc,file=file,definition=definition
; ; The associate variable can have
; ; additional variables---with a tag.
; definition = '{struct,header:bytarr(100),data:intarr(128,128)}'
; ; Up to v3.6, the structure has to be named!
; look,/assoc,tag=1,file=file,definition=definition
; ; use tag #1 (data) in the structure
; look,loader_name='getdata',d imensions=[3,4,5]
; ; 7) Use getdata.pro to obtain the set of
; ; 3x4x5 images,
; ; each of size returned by getdata.
; ; Here 3 dimension sliders will be used.
; look,procedures='process'
; ; 8) Add processing procedures, e.g., to use
; ; YOUR OWN process.pro to
; ; modify the current image.
; look,functions=['roberts','sobel']
; ; 9) Add edge filters to Options menu
; look,options=['db','look_fourier','tv'],types=['f','p','p']
; ; 10)Add functions and procedures together.
; ; Specifying types avoids search of !path.
; look,userscalefunc=['bytscl','myfunc']
; ; 11)Add custom functions to auto scaling menu
; look,axes=['frame','index','a,b,c,d,e']
; ; 12) Replace 'dim 3' label with 'frame', etc.
; look,dim5marks=['raw counts','scaled counts','temperature','radiance']
; ; 13) Replace 'dim 5' label with a pulldown
; ; menu to select the dim5 index.
; tmp = {mark,mark:0l,tag:''}
; look,dim5marks=[{mark,3500,'slew start'},{mark,3650,'slew stop'}]
; ; 14) Same result as 13) but input is a
; ; structure array. This allows
; ; quick-access marks to be placed in the
; ; data, so the user can jump to them.
; ; The tagsname and structure name are
; ; arbitrary, but you need two tags:
; ; (0)=int/long and (1)=string
; look,units=['azimuth (200 !3m!5rad pixels)','elevation','counts']
; ; 15) Replace image dimensions and image value
; ; names with the 3 elements of units,
; ; e.g. 'y (pixels)' --> 'elevation'
; ; These are stored in common look_common
; ; in the 'all' structure, so they can be
; ; altered by the routine to fetch images,
; ; see units in Keywords section below.
; Loading Images:
; There are four ways to load data into look:
; 1. Pass images as a parameter: look,images
; 2. Load images into common look and call: look,/noload
; 3. Access images in a file via associate variable: look,/assoc,...
; 4. Give look a function that returns images: look,loader='getdata',...
; Operation:
; 1. The basic thing is to roam around the image and look at cuts.
; Buttons, sliders and lists control other features.
; 2. The mouse buttons control the following, on the full image.
; \ ______
; \______/ \
; | __________
; ____ ______|__/___ Middle button:
; Left button: \ | / | Click to recenter
; Click & drag \| _ _/ _ | the zoom region.
; on full image \ |l| | | | | |
; to define |\|e| |m| |r|\|
; the zoom | |f| |i| |t| \
; window. | |t| |d| | | |\____
; Select options. | |_| |_| |_| | Right button:
; | | Click to do controlled move
; | | of one quantity (*'d),
; | | e.g., the zoom center
; |_____________| in the x direction.
;
; 3. The plot buttons can be selected at any time.
; The plots appear in the zoom window (by default) or both windows.
; Toggle the "Use Full & Zoom" button to get either
; a. the plot of the full image in the zoom window or
; b. the plot of the zoom image in the full window or
; c. 2 plots: zoom and full in the 2 windows.
; 4. To zoom, click and drag the left mouse over the region of interest.
; Then you can roam in the zoom image also, looking at cuts.
; 5. To change the center of the zoom region, click the middle mouse
; button. To move the zoom region in a controlled manner,
; use the right button.
; 6. Moving the sliders at the bottom changes the plot and tv scales.
; You can use auto scaling or set the min & max, within the limits
; shown.
; 7. There are guards against choosing out-of-range quantities.
; 8. If you give a series of 2-D images, the sliders at the left allow
; you to move through the images---one slider per dimension.
; A catalog option allows display of multiple images.
; 9. The right mouse button allows controlled increments and decrements
; of the zoom center and width, selected by using the Increment type
; menu.
; 10.An options menu lists available processing and image display operators.
; The menu can contain user-supplied procedures or functions;
; see keywords options, types, procedures, and functions. Most of the
; options appear in pull-down sub-menus in the followiing categories:
; - xloadct
; - enlargement: on the window or the entire screen
; - catalog: all or selective
; - plot types: contour, histogram, surface, show3, etc.
; - region of interest
; - filters: smooth, median, leefilt
; - write Postscript file
; 11.There are more detailed notes below.
; Usage:
; look[,image][,/help][,options]
; Optional Inputs:
; image = one or more 2-D images
; Keywords:
; /assoc = flag to say the parameter is an associate variable
; Then the slider for dim3 becomes an index into the associated file.
; Related keywords are "filename" "definition" "dimensions" and "offset".
; axes = string array of names to replace dim 3, dim4, ...
; definition = string used to define the associate variable
; dimensions = the 3rd and higher dimensions for a series of images and
; the /assoc or loader= options, also needed for optical disks where
; only part of the disk has been written on
; dim3marks = string array or structure array of names used to create
; a pulldown menu for selecting the dim 3 index. The pulldown menu
; is labeled as "dim 3" or the 1st element of the axes keyword if
; present. The marks are values along the 3rd dimension and can be
; selected via the pulldown menu. The string array provides tags, each
; with the mark set to its index in the array. The structure array
; consists of a named structure with two tags, an int or long and a
; string, here called mark and tag:
; tmp = {look_mark,mark:0l,tag:''}
; dim3marks = [{look_mark,3600,'start'},{look_mark,3800,'end'}]
; dim4marks = ditto for dim 4
; dim5marks = ditto for dim 5
; dim6marks = ditto for dim 6
; dim7marks = ditto for dim 7
; filename = name of the file associated with the associate variable
; functions = synonym for options that are functions, cf. options
; /help = flag to print the header only and return
; interval = time in seconds between timer events (D=0.3s)
; kernel_width = the initial width of the smooth and median filters
; lines = # of lines in the comment/help scrollable widget (D=2)
; loader_name = name of an IDL function to return the ith image for
; display. It needs one parameter, a vector of the indices for the
; current image, and returns one parameter, the image. The
; important point is that allowing a function to return the image gives
; the user freedom to grab an image in a variety of ways---not tied
; directly to look.pro. A prototype function, returning a 10x10 array,
; is the following:
; function getdata,higherdims,comment
; comment = 'This is an 2-D Gaussian random image with non-zero mean.'
; return,randomn(seed,10,10)+higherdims(0)
; end
; To use this function with 100 images, the call to look is:
; look,...,loader='getdata',dimensions=100
; If the dimensions keyword is omitted, the user is asked to specify
; the # of images.
; Another example would be returning the magnitude, phase, real, or,
; imaginary part of a complex array:
; function getcomplex,higherdims,comment
; c= complex(dist(10),dist(10)*higherdims(0))
; case higherdims(1) of ; flag is the 2nd dimension
; 0: return,abs(c)
; 1: return,atan(imaginary(c),float(c))*!radeg
; 2: return,float(c)
; 3: return,imaginary(c)
; endcase
; end
; Then the dim4 slider would control the return value and the dim3
; slider would control the image index. In this example the call is:
; look,...,loader='getcomplex',dimensions=[...,4]
; /noload = flag to say the input comes directly from common look
; offset = byte offset pointing to the start of the associated data,
; the third argument to the assoc call.
; options = names of IDL functions or pros to process the current image for
; display or other action, e.g., to define a region of interest or to
; scale nonlinearly. The option names appear in the options menu.
; Each function accepts one parameter, the current image, and returns
; the modified image. You can use any idl function that
; operates on images or make your own. A prototype function is the
; following:
; function db,image
; return,alog10(image)*10
; end
; A procedure accepts one parameter, the current image scaled with look_scl.
; You can use any idl procedure that operates on images or make your own.
; A prototype procedure is the following:
; pro dbscl,image
; tvscl,db(image)
; return
; end
; To use this procedure, the call to look is:
; look,...,options='dbscl'
; Multiple options are easy, just make an array:
; look,...,options=['dbscl','lego','image_cont','slide_image']
; look has to determine whether the option is a function or a procedure
; and does a search for each option to find its source code. These
; searches are time-consuming if !path has many entries. You can
; shorten the search by including another keyword types; see below.
; procedures = synonym for options that are procedures, cf. options
; range = range of values to be displayed (D=3x range of images)
; tag = tag # if the associate variable is a (named) structure
; e.g., a = assoc(lun,{struct,hdr:0l,data:intarr(128,128)}).
; Then tag=1 references the data tag; see examples above.
; types = types of options, either 'pro' or 'function', corresponding to the
; options keyword to obviate the need for look to determine the option
; type, e.g., look,options=['sin','blob'],types=['function','pro']
; units = 3-element string array to replace labels on images and plots
; x (pixels) --> units(0)
; y (pixels) --> units(1)
; z (value) --> units(2)
; common look_common contains a structure ws that has the units tag
; and can be manipulated by the function used to fetch images, e.g.,
; function get_an_image,indices,comment
; common look_common
; ws.units = ['longitude (deg)','latitude (deg)','pressure (mbar)']
; ...
; return,image
; end
; userscalefunc = array of custom scaling function names, e.g.,
; .r
; - function myfunc, image
; - return, 4 * bytscl (image)
; - end
; look,...,userscalefunc=['bytscl','myfunc']
; /verbose = flag to print informational messages (debug mostly)
; viewers = array of names of procedures to call each time the display
; is updated by a mouse event. Procedures can do anything, e.g.,
; display other images, calculate statistics, or keep track of what
; has occurred in the program. The action of each viewer can be
; set to one of three states using the options menu:
; off: procedure not called
; on/all mouse: called for all mouse clicks AND movements
; on/click only: called for mouse clicks and drags only.
; You would choose "on/all mouse" if your procedure shows cuts but
; "on/click only" if your procedure shows images only. The
; "on/all mouse" option takes more time, so there will be
; delayed updates on cuts. Each viewer procedure
; takes no parameters but can obtain information from the two
; common blocks and should have two keywords: create and destroy.
; Whenever the viewer is toggled on (off), the procedure will be
; called with /create (/destroy). Here's an example.
; PRO my_display,create=create,destroy=destroy
; COMMON look
; COMMON look_common
; COMMON look_viewer,viewer_window
; IF keyword_set(create) THEN BEGIN
; window,/free,xsize = 256,ysize = 256, title = 'Sobel window'
; viewer_window = !d.window
; ENDIF
; IF keyword_set(destroy) THEN BEGIN
; wdelete,viewer_window
; return
; ENDIF
; wset,viewer_window
; tvscl,sobel(thisimage) ; example
; return
; END
; In addition the call to look would be:
; look,viewers='my_display',...
; Outputs:
; widget as rendered above
; Common blocks:
; look = images copied from the input parameter or loaded externally,
; declared and filled by user as one alternative to loading images:
; common look,images,catalog,index
; images = ...
; Note that catalog is another variable; it is loaded by look with
; the images selected by catalog/movie/blink. The same is true for
; index, which is a 2-D array of indices corresponding to the images.
; look_common = variables that need to be passed between routines,
; not likely to be needed by the user, except units (see above).
; Procedure:
; There are two top-level routines: one to initialize (look) and an
; event handler (look_event). There are a number of lower-level
; routines to perform specific tasks. After creating the widgets,
; look places the full image in the tv window and a zoom image
; in the optional plots window. The cut windows are left blank
; until the mouse is moved over the image in the tv window.
; The event loop does all the dynamic processing.
; Restrictions:
; All the images in a series have to have the same 2-D dimensions.
; All the sliders use whole numbers because IDL's cw_fslider lacks the
; ability to specify an increment.
; Slider value for the maximum slider may be incorrect, even though the
; the proper values are being sent. I don't understand this one.
; Future Additions:
; Report pixel values when scanning over the cut plots?
; Add a display of the actual values in the array.
; Add a color bar.
; Fourier filtering (A version for square images is look_fourier.pro.)
; Add a comment keyword, like the 2nd parameter of the loader.
; Modification history:
; Write, 21-26 Feb 95, FKKnight (knight@Ll.mit.edu)
; Add roaming in the zoom image, 27 Feb-1 Mar 95, FKK
; Fix bug if middle mouse is pressed first, 1 Mar 95, FKK
; Add xloadct and rescale plot min and max sliders when a new image is
; is accessed, 5 Mar 95, FKK
; Clean up, make fixes, add manual scale limits, 11-12 Mar 95, FKK
; Add dynamic help messages, 11 Mar 95, FKK
; Change common to allow input of images via common. This avoids
; copying a large number of images to the internal common block from
; the input parameter, 13 Mar 95, FKK
; Add search of path for "look.pro" in !PATH + current directory
; when the HELP button is selected, 09 Mar 95, GGA (gga@otl.sma.ch)
; Change timer interval from 0.1 to 0.3 [s],
; insert some code comments, 15 Mar 95, GGA.
; Add interval keyword to override the default, 15 Mar 95, FKK
; Add scroll increments (range/!d.n_colors) to sliders, 17 Mar 95, FKK
; Add function to right mouse: increase/decrease selected quantities
; by a selected increment (-10 to +10), 18 Mar 95, FKK
; Add switch to plot zoom and full images or just full image using
; the plot menu, 19 Mar 95, FKK
; Add a guard against out-of-range sliders, e.g., int's with
; imrange = (0:32767) would make range = (-32767:-2),
; but the guard may not be sufficient, 20 Mar 95, FKK
; Omit controlled mouse increments because there is no way to shift
; the mouse position in software---it has to be moved, 21 Mar 95, FKK
; Make the allowed range of increments larger, up to half the size of
; the image, which is probably more than enough, 21 Mar 95, FKK
; Add guards against not having images and not having Bill Thompson's
; routines available, 21 Mar 95, FKK
; Exchange the text on the toggle button 'Plot Zoom Only', 23 Mar 95, FKK
; Call setflag,/noscale to avoid rescaling data, 28 Mar 95, FKK
; Reset flags /noscale & /noexact on exit, 19 Jun 95, FKK
; Add range keyword to preselect a slider range, 3 Jul 95, FKK
; Add the associate variable code, 17 Jul 95, FKK
; Add catalog of associate variable, 18-19 Jul 95, FKK
; Add byte offset to start of assoc data, 30 Jul 95, FKK
; Add function keyword to give the ability to grab images from outside
; of look.pro and bring them in, e.g., from a frame grabber or an
; associate variable, 4 Aug 95, FKK
; Tried to fix scaling problem of imrange outside srange with another
; guard, 4 Aug 95, FKK
; Add an optional comment to the function return, 5 Aug 95, FKK
; Add the enlargement button and a keyword lines to tell the
; number of lines in the help/comment widget, 8 Aug 95, FKK
; Add a guard against calling widget_slider with small srange (using
; cw_fslider requires a mod to have a scroll keyword), 11 Aug 94, FKK
; Add a keyword, option_names, to name functions to process an image. This
; allows user-specified functions in the process menu, 11 Aug 95, FKK
; Revamp:
; change keyword option_names --> options
; change keyword last --> dimensions
; add smooth and median filters and a slider for filter width
; rearrange menus to group items better
; add restore image button to undo processing effects
; omit help button because xdisplayfile can't cope with >1000 lines
; change help text to reflect new widget arrangement
; 13 Aug 95, FKK
; Alter the min and max sliders, so they're easy to use, 15 Aug 95, FKK
; Revamp:
; change keyword options --> process_names
; change keyword function_name --> loader_name
; add keyword display_name to allow user-supplied display procedures
; retool the pull_down menu code
; 20 Aug 95, FKK
; Add selective catalog for large datasets. Change the catalog item to
; a pull-down menu with two options: all and selective, which,
; if chosen, brings up a widget to select first, last, and step values
; for the catalog display, 24 Aug 95, FKK
; Move look_fourier to a separate file with a new name: fourier.pro,
; 24 Aug 95, FKK
; Change menu names AGAIN to combine the two menus into one:
; display menu --> options menu ; for procedures and functions
; process menu --> options menu ; for procedures and functions
; Add code to distinguish between pro and function, but also add a
; keyword types to allow user to distinguish between pros and
; functions and synonyms for options, procedures=... and
; functions=..., 24 Aug 95, FKK
; Decouple from Bill Thompson's routines, needed three procedures so I
; mimicked them with only the options look needs:
; plot_image --> look_image
; exptv --> look_exptv
; put --> look_put
; ,26 Aug 95, FKK
; Revamp catalog, incl. proper index, processing, 27 Aug 95, FKK
; Allow even zoom width (odd only before), 30 Aug 95, FKK
; Add the region of interest processing using IDL's cw_defroi.pro. Had
; to block the timers during the cw_defroi life; cf. look_event,
; 31 Aug 95, FKK
; Replace cw_defroi.pro with look_defroi.pro, an augmented version,
; including roi selection by threshold. Keep look_defroi.pro in a
; separate file. 3 Sep 95, FKK
; Omit timers; add /motion_events to draw windows. Add crosshairs. Add
; drag box during zoom. Alter substitute test images, 8-10 Sep 95, FKK
; Replace border.pro with hard-coded border, 12 Sep 95, FKK
; Omit testimages (hassles betw IDL3.6 and IDL4.0);
; just use calculated ones, 14 Sep 95, FKK
; Add blink compare and fixed increments, 15-16 Sep 95, FKK, with advice
; from Vincent Coude' de Foresto and code from David Stern
; Add movies using xinteranimate, 16 Sep 95, FKK
; Make cuts smoother, per Andrew Cool's suggestion, 17-19 Sep 95, FKK
; Make press of Set Min= and Set Max= buttons work, 28 Sep 95, FKK
; Reorder subroutines and make image updates faster by relying on
; color table modifications where possible. See look_span_update.
; 8 Oct 95, FKK
; Add _extra keyword to allow non-look keywords, 13 Oct 95, FKK
; Add optional names of axes to replace dim 3, dim 4,... 18 Oct 95, FKK
; Add ability to input specific values for dim 3, dim 4,..., 30 Oct 95, FKK
; Replace each dim slider with 2 buttons (+ and -) and two editable
; text boxes for the dim value and an increment, 1 Nov 95, FKK
; Fix bugs in catlim 1) if min and max are equal, 2) bad defaults,
; 3) out of range integers, 5-7 Dec 95, FKK
; Improve the catalog/movie/blink options by adding a new mechanism
; for choosing frames that allows aborting and easy frame selection,
; 11-18 Dec 95, FKK
; Add a Laplacian filter, i.e., a high-pass filter, 24 Feb 96, FKK
; Guard against !d.n_colors = 2^24 in look_span_update, 2 Apr 96, FKK
; Change all !d.n_colors to (!d.n_colors<!d.table_size), 16 Apr 96, FKK
; Add printing to file from catalog/movie/blink and a "write PS file"
; option to the menu, 16-20 Apr 96, FKK
; Add optional labels to the catalog/movie/blink images, 19 Apr 96, FKK
; Add "catalog" variable to common "look" to hold the output of
; catalog/movie/blink. Now the definition for common look is:
; common look,images,catalog,index
; where catalog gets filled, if requested by user, 22 Apr 96, FKK
; Remove the "Set Max =" option below the slider and fix the slider
; entry widget so it responds to CR. Now the two button options
; are "Auto Max" and "FixSlide", and they seem to work naturally.
; Ditto for min. 22 Apr 96, FKK
; Restore help button and embellish the help widget, 22 Apr 96, FKK
; Restore some other test images and fix some bugs, 23 Apr 96, FKK
; Fix part of look_PSatt.pro, 24-25 Apr 96, FKK
; Fix 3 things: initialize COMMOM colors, make helpbutton work
; for non-Unix, scale # of help lines to screen, 6 May 96, FKK
; Added auto-scaling options: mean or median +/- three different user
; specifiable sigma levels (new keywords usermean and usermedian),
; remove top/bottom 5% or 10%, hist_equal, and custom (user-supplied
; function - new keyword userscalefunc), 25 Apr 97, DSR
; Added look_si2 function (improved version of look_si) to fix
; incorrect determination of coordinate conversion factors. This
; prevents crosshairs from being drawn outside the plot windows; also,
; horizontal and vertical cut windows now correspond exactly to the
; crosshair location. Changed look_cut to force crosshairs to be
; placed on the center of data cells. Axes changed to be centered on
; the data cells. 6 May 97, DSR
; Fixed some problems with slider adjustments which were created by the
; recent auto-scaling changes. Crosshairs are now erased after a
; switch to the opposite window. 8 May 97, DSR
; Crosscut windows are now cleared if the frame changes. Auto scaling
; may be done to either the full or the zoom plot, depending on the
; full/zoom/full & zoom button setting. 9 May 97, DSR
; Rewrote look_update. Special plots (contour, histogram, etc.) now
; persist if the frame number is changed. 13 May 97, DSR
; Decoupled ws.last_cutwid and ws.cut_oplot to fix bug with erasing
; crosshairs. 20 May 97, DSR
; Crosscut plots no longer made for cursor moves in special plot
; windows. 22 May 97, DSR
; New zoom window selection resets plot type to default. Zoom selection
; from special plot windows is not allowed. 23 May 97, DSR
; Crosscuts now active in contour plot windows. Set contour plot axis
; limits to be the same as for the corresponding image plot.
; 27 May 97, DSR
; Added modified version of cw_fslider.pro, to allow floating point
; values on the sliders. 30 May 97, DSR
; Fixed draw window event handling for version 5. Fixed on-line help
; bug (search for look.pro was incorrect). 12 Jun 97, DSR
; Changes to look_findbin (histogram search routine) - added check to
; prevent illegal array index references; bin size now computed if
; data range is small; number of bins limited to 200. 23 Jun 97, DSR
; Miscellaneous fixes missed in recent mods for floating point sliders.
; 22 Aug 97, DSR
; userscalefunc can now be an array of function names. Auto scaling
; menu now shows function names. Crosscut plots now use scaled image,
; rather than original image. Catalog option now uses hist_equal or
; custom scaling functions, if selected. 28 Aug 97, DSR
; Fix to force image scaling routines to return images of type float.
; 29 Aug 97, DSR
; Reset slider min/max values and scroll increment when a new image is
; read (added ll_fslider_set_minmax). 10 Sep 97, DSR.
; Fixed statistics display - added extra blank line. 23 Oct 97, DSR.
; Expanded slider label box to 9 chars, added label formatting.
; 29 Oct 97, DSR.
; Add the units keyword, 5 Dec 97, FKK
; Add pull-down menu for dimension selection. See dim3marks keyword
; explanation or test with 'IDL> look', 7-9 Dec 97, FKK
; Change the export capability in common look: catalog changed to 3-D
; array, index array added, option to store only indices, append
; capability, 10-12 Dec 97, FKK
; Add a button to determine whether the increment is updated when a new
; image is read. Update is nice if images span widely different ranges
; but frustrating if the images only vary slightly. 22 Dec 97, FKK
; Fix problem in catalog where index variable didn't exist at the
; beginnning: add extra test (n_elements(index) EQ 0), 9 Jan 98, FKK
; Fix movie for "Use Zoom Only" case. The ZOOM structure in LOOK_COMMON
; was being replaced by the zoom factor in look_catalog. 5 Mar 98, DSR
; Add viewers keyword to allow user to add procedures to do things
; triggered by mouse events (similar to procedures and functions
; keywords but automatic instead of being chosen from options
; menu), 26 Mar 98, FKK
; Improved code for display of vertical crosscuts (histogram case).
; 22 Jul 98, FKK
; Repair movie mode: allow zoomed movie for full and zoom images with
; default size to fill 1/4 of smaller screen dimension and range up
; full screen, guard against single frame sent to xinteranimate
; (slider error). Still can't do full & zoom movies together
; (xinteranimate restriction). 9 Sep 98, FKK
; look_auto_minmax changed to use fix / auto slider setting; catalog
; now auto scales each image separately. 20 Oct 98, DSR
; fixed catalog indexing scheme. 16 Jun 99, DSR
; Replace stdev calls (obsolete) with calls to moment. 14 Dec 99, DSR
; Fix to avoid calling moment with structure elements as keyword
; arguments. 14 Mar 00, DSR
; Added option to catalog to generate indices without displaying
; images. 22 Jun 00, DSR
; Changed catalog default to display images. 12 Jul 00, DSR
;-
;
; Copyright (c) 1993, Research Systems, Inc. All rights reserved.
; Unauthorized reproduction prohibited.
;+
; NAME:
; look_defroi
; PURPOSE:
; This function returns a where vector of the pixels in a region of interest,
; selected via a number of methods from within a draw widget.
; CATEGORY:
; Regions of interest, graphics.
; CALLING SEQUENCE:
; Result = look_defroi(draw[,options])
; INPUTS:
; Draw = id of drawable to draw the region, not the window number.
; KEYWORD PARAMETERS:
; CONTRAST = flag to select positive (/contrast, the default) or negative
; (contrast=0) for the threshold method of definiing the roi
; IMAGE = the real image that is displayed with the zoom factor in the
; drawable. Passing it in allows the threshold to be calculated exactly,
; even for non-unity zooms. Without it, a congrid is necessary and
; the resulting image is only an approximation.
; MODE = integer code for initial method of selecting pixels:
; 0=polygon, 1=point, 2=rectangle, 3=circle, 4=threshold
; OFFSET = offset of lower left corner of image within the
; drawable. Default = [0,0].
; ORDER = if set, return inverted subscripts, as if the array
; were output from top to bottom.
; RESTORE = Set to restore the drawable to its previous appearance
; on exit. Otherwise, the regions remain on the drawable.
; SIZE = the size of the underlying array, expressed
; as a two element vector: [columns, rows]. Default =
; (drawable_size-offset) / zoom.
; ZOOM = if the image array was expanded (via REBIN for example)
; specify this two element vector containing the expansion
; factor in X and Y. Default = [1,1]. Must be integer.
; OUTPUTS:
; Result = 1-D vector of subscripts of points within the region[s] defined.
; If no region was defined, a scalar -1 is returned.
; COMMON BLOCKS:
; None.
; SIDE EFFECTS:
; The regions are drawn within the drawable. Set the RESTORE
; keyword to undo the damage.
; RESTRICTIONS:
; This is a MODAL widget. No other widget applications will be
; responsive while this widget is in use. The draw widget should
; have the /motion and /button. For the threshold method, the
; return value can be off due to the congrid employed, unless the actual
; image is passed in.
; PROCEDURE:
; Defining the roi is interective: you select the method(s) and use the mouse.
; The left mouse button selects points (click or drag); the right deletes points.
; The methods are:
; - polygon: click on vertices
; - point: click on single pixels
; - rectangle: drag from lower left to upper right or vice versa
; - circle: drag from center to point on circumference
; - threshold: select positive or negative contrast and adjust slider.
; When you change the method, the current points are added to the total, so
; you can combine methods, except for the threshold method. The event loop
; is inside the main function, but mouse events in the drawable are processed
; in an event procedure. Some important points about the code are the
; following.
; - There are two pixel coordinate lists that are stored as uvalues.
; - Except for the threshold method, the displayed image is not needed.
; Instead the XOR graphics mode is used to draw and fill on top of
; the image.
; - For the threshold mode, the image is read using tvrd, so it is a
; scaled copy.
; - A structure, s, which holds the state information, is passed to the
; subroutines:
; look_defroi_draw: overlay outline or fill on drawable.
; look_defroi_nmode: concatenate current points with old ones
; look_defroi_event: process mouse events
; EXAMPLE:
; To obtain the average of the counts of a region within a drawable:
; Assume A = the array of interest, n columns, m rows, and that
; it is displayed in drawable D, at offset X=20, Y=100, and zoomed
; with a factor of 2:
; TV, REBIN(A, M*2, N*2), 20, 100 ;Display the image
; q = look_defroi(D, ZOOM=[2,2], OFFSET=[20,100], IMAGE_SIZE=[m,n])
; if q(0) ne -1 then print,'Average = ', total(a(q))/n_elements(q)
;
; MODIFICATION HISTORY:
; DMS, RSI, December, 1993. Written.
; modify for incorporating into look.pro:
; - change name from cw_defroi to look_defroi
; - add another mode, threshold with positive or negative contrast
; - allow floating zoom factors
; - allow a timer to be active in the drawable by only processing events
; with 8 tags (mouse events) Timer events have 3 tags.
; - add mode-specific instructions
; 31 Aug-1 Sep 95, FKKnight (knight@ll.mit.edu)
; add the image keyword and change image_size keyword to size. This allows
; an exact calculation of the return value. See notes above. 3 Sep 95, FKK
;-
; The following code (between the triple "*" lines) is imported from a
; modified verison of IDL's cw_fslider.pro routine.
;***************************************************************************
;***************************************************************************
;***************************************************************************
; $Id: llcw_fslider.pro,v 1.5 1994/02/10 22:11:18 dave Exp $
; Copyright (c) 1992-1993, Research Systems, Inc. All rights reserved.
; Unauthorized reproduction prohibited.
;
; NAME:
; LLCW_FSLIDER
;
; PURPOSE:
; The standard slider provided by the WIDGET_SLIDER() function is
; integer only. This compound widget provides a floating point
; slider.
;
; CATEGORY:
; Compound widgets.
;
; CALLING SEQUENCE:
; widget = LLCW_FSLIDER(Parent)
;
; INPUTS:
; Parent: The ID of the parent widget.
;
; KEYWORD PARAMETERS:
; DRAG: Set this keyword to zero if events should only
; be generated when the mouse is released. If it is
; non-zero, events will be generated continuously
; when the slider is adjusted. Note: On slow systems,
; /DRAG performance can be inadequate. The default
; is DRAG=0.
; EDIT: Set this keyword to make the slider label be
; editable. The default is EDIT=0.
; FORMAT: Provides the format in which the slider value is
; displayed. This should be a format as accepted by
; the STRING procedure. The default is FORMAT='(G13.6)'
; FRAME: Set this keyword to have a frame drawn around the
; widget. The default is FRAME=0.
; MAXIMUM: The maximum value of the slider. The default is
; MAXIMUM=100.
; MINIMUM: The minimum value of the slider. The default is
; MINIMUM=0.
; SUPPRESS_VALUE: If true, the current slider value is not displayed.
; The default is SUPPRESS_VALUE=0.
; TITLE: The title of slider. (The default is no title.)
; UVALUE: The user value for the widget.
; VALUE: The initial value of the slider
; VERTICAL: If set, the slider will be oriented vertically.
; The default is horizontal.
; XSIZE: For horizontal sliders, sets the length.
; YSIZE: For vertical sliders, sets the height.
;
; OUTPUTS:
; The ID of the created widget is returned.
;
; SIDE EFFECTS:
; This widget generates event structures containing a field
; named value when its selection thumb is moved. This is a
; floating point value.
;
; PROCEDURE:
; WIDGET_CONTROL, id, SET_VALUE=value can be used to change the
; current value displayed by the widget.
;
; WIDGET_CONTROL, id, GET_VALUE=var can be used to obtain the current
; value displayed by the widget.
;
; MODIFICATION HISTORY:
; April 2, 1992, SMR and AB
; Based on the RGB code from XPALETTE.PRO, but extended to
; support color systems other than RGB.
; 5 January 1993, Mark Rivers, Brookhaven National Labs
; Added EDIT keyword.
; 7 April 1993, AB, Removed state caching.
; 28 July 1993, ACY, set_value: check labelid before setting text.
; 30 May 1997, Douglas S. Reynolds (MIT Lincoln Laboratory)
; Added SCROLL keyword. Fixed bug in case where VALUE=0,
; and MINIMUM < VALUE < MAXIMUM.
; 25 June 1997, Douglas S. Reynolds (MIT Lincoln Laboratory)
; Fixed bug in computation of VALUE parameter in
; WIDGET_SLIDER call.
; 16 September 1997, Douglas S. Reynolds, MIT Lincoln Laboratory
; Added fslider_set_minmax, to allow the slider limits
; to be changed.
;
PRO ll_fslider_set_minmax, id, min = minvalue, max = maxvalue
; Change the minimum and maximum values for the floating point slider.
; Since the actual slider limits are fixed at 0 and 1000000, this is
; actually done by changing the minimum and maximum values stored in the
; "state" structure. These values are used by fslider_set_value and
; fslider_get_value to change or access the slider setting as seen by
; the user.
stash = WIDGET_INFO(id, /CHILD)
WIDGET_CONTROL, stash, GET_UVALUE = state
if n_elements (minvalue) ne 0 then state.bot = minvalue
if n_elements (maxvalue) ne 0 then state.top = maxvalue
WIDGET_CONTROL, stash, SET_UVALUE = state
END
PRO ll_fslider_set_value, id, value
; Set the value of both the slider and the label
ON_ERROR, 2 ;return to caller
stash = WIDGET_INFO(id, /CHILD)
WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY
WIDGET_CONTROL, state.slideid, $
SET_VALUE = 1000000. * $
(float(value) - state.bot) / (state.top - state.bot)
IF (state.labelid NE 0) THEN $
WIDGET_CONTROL, state.labelid, $
SET_VALUE = STRING(FLOAT(value), format=state.format)
WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY
END
FUNCTION ll_fslider_get_value, id
; Return the value of the slider
ON_ERROR, 2 ;return to caller
stash = WIDGET_INFO(id, /CHILD)
WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY
WIDGET_CONTROL, state.slideid, GET_VALUE = tmp
ret = ((tmp / 1000000.) * (state.top - state.bot)) + state.bot
WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY
return, ret
END
;-----------------------------------------------------------------------------
FUNCTION ll_fslide_event, ev
; Retrieve the structure from the child that contains the sub ids
parent=ev.handler
stash = WIDGET_INFO(parent, /CHILD)
WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY
; See which widget was adjusted, the slider or the label
if (ev.id eq state.slideid) then begin
; Get the non-adjusted value
WIDGET_CONTROL, state.slideid, GET_VALUE = nonadj
; Compute the floating point value
value = ((nonadj / 1000000.) * (state.top - state.bot)) + state.bot
drag = ev.drag
; Update label
IF (state.labelid NE 0) THEN $
WIDGET_CONTROL, state.labelid, $
SET_VALUE=STRING(value, format=state.format)
endif else if (ev.id eq state.labelid) then begin
WIDGET_CONTROL, state.labelid, GET_VALUE = tmp
value = float(tmp(0))
value = value > state.bot
value = value < state.top
;Update the slider, set new value
WIDGET_CONTROL, state.slideid, $
SET_VALUE = 1000000. * $
(value - state.bot) / (state.top - state.bot)
drag = 0
; Update the label so it has desired format
WIDGET_CONTROL, state.labelid, $
SET_VALUE=STRING(value, format=state.format)
endif
WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY
RETURN, { ID:parent, TOP:ev.top, HANDLER:0L, VALUE:value, DRAG:drag }
END
;-----------------------------------------------------------------------------
FUNCTION llcw_fslider, parent, $
DRAG = drag, $
EDIT = edit, $
FRAME = frame, $
MAXIMUM = max, $
MINIMUM = min, $
SUPPRESS_VALUE = sup, $
TITLE = title, $
UVALUE = uval, $
VALUE = val, $
VERTICAL = vert, $
XSIZE = xsize, $
YSIZE = ysize, $
FORMAT=format, $
SCROLL = scrollval
IF (N_PARAMS() EQ 0) THEN MESSAGE, 'Incorrect number of arguments'
ON_ERROR, 2 ;return to caller
; Defaults for keywords
IF NOT (KEYWORD_SET(drag)) THEN drag = 0
IF NOT (KEYWORD_SET(edit)) THEN edit = 0
IF NOT (KEYWORD_SET(frame)) THEN frame = 0
IF N_ELEMENTS(max) EQ 0 THEN max = 100.0
IF N_ELEMENTS(min) EQ 0 THEN min = 0.0
IF NOT (KEYWORD_SET(sup)) THEN sup = 0
IF NOT (KEYWORD_SET(title)) THEN title = ""
IF NOT (KEYWORD_SET(uval)) THEN uval = 0
;; IF NOT (KEYWORD_SET(val)) THEN val = min
if N_ELEMENTS(val) EQ 0 THEN val = min
IF NOT KEYWORD_SET(format) THEN format='(G13.6)'
; Convert slider increment from user units to internal units (0-1000000)
IF keyword_set (scrollval) THEN $
scrollinc = scrollval * 1000000 / (max - min) $
ELSE $
scrollinc = 10000
state = {slideid:0L, labelid:0L, top:max, bot:min, format:format }
; Motif 1.1 and newer sliders react differently to XSIZE and YSIZE
; keywords than Motif 1.0 or OpenLook. These defs are for horizontal sliders
version = WIDGET_INFO(/version)
newer_motif = (version.style eq 'Motif') and (version.release ne '1.0')
; The sizes of the parts depend on keywords and whether or not the
; float slider is vertical or horizontal
;these are display specific and known to be inherently evil
sld_thk = 16
chr_wid = 7
IF (KEYWORD_SET(vert)) THEN BEGIN
if (newer_motif) then begin
if (not KEYWORD_SET(xsize)) then xsize = 0
endif else begin
title_len = STRLEN(title) * chr_wid
xsize = (sld_thk * 1.4) + title_len ; Take label into account
endelse
IF NOT (KEYWORD_SET(ysize)) THEN ysize = 100
l_yoff = ysize / 2
ENDIF ELSE BEGIN ;horizontal slider
vert = 0
tmp = not keyword_set(xsize)
if (newer_motif) then begin
if (tmp) then xsize = 0
IF NOT (KEYWORD_SET(ysize)) THEN ysize = 0
endif else begin
if (tmp) then xsize = 100
IF (TITLE NE '') THEN sld_thk = sld_thk + 21
ysize = sld_thk ; Make the slider not waste label space
endelse
l_yoff = 0
ENDELSE
if (vert) then begin
mainbase = WIDGET_BASE(parent, FRAME = frame, /ROW)
labelbase = WIDGET_BASE(mainbase)
endif else begin
mainbase = WIDGET_BASE(parent, FRAME = frame, /COLUMN)
labelbase = mainbase
endelse
WIDGET_CONTROL, mainbase, SET_UVALUE = uval, EVENT_FUNC = 'll_fslide_event', $
PRO_SET_VALUE='LL_FSLIDER_SET_VALUE', $
FUNC_GET_VALUE='LL_FSLIDER_GET_VALUE'
IF (sup EQ 0) THEN $
; Only build the label if suppress_value is FALSE
state.labelid = WIDGET_TEXT(labelbase, YOFFSET = l_yoff, $
VALUE = STRING(FLOAT(val), format=state.format), $
edit=edit) $
ELSE state.labelid = 0
state.slideid = WIDGET_SLIDER(mainbase, $
TITLE = TITLE, $
XSIZE = xsize, $
YSIZE = ysize, $
/SUPPRESS_VALUE, $
MINIMUM = 0, $
MAXIMUM = 1000000, $
; Fix made to VALUE computation to prevent errors resulting from lack of
; automatic type conversion.
VALUE = 1000000. * $
(float(val) - state.bot) / $
;; (state.top - state.bot), $
(float(state.top) - state.bot), $
VERTICAL = vert, $
DRAG=drag, $
SCROLL = scrollinc)
;; SCROLL=10000)
WIDGET_CONTROL, WIDGET_INFO(mainbase, /CHILD), SET_UVALUE=state, /NO_COPY
RETURN, mainbase
END
;***************************************************************************
;***************************************************************************
;***************************************************************************
pro look_reset_sliders, image
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
allrange = [min(image), max(image)]
range = abs(allrange(1)-allrange(0)) ; make sure it's positive
srange = allrange+[-1,1]*range ; a total of 3x range of images
;; mag = 5 - fix (alog10 (srange(1) - srange(0)))
;; srange(0) = long (srange(0) * 10^mag) / 10^mag
;; srange(1) = long (srange(1) * 10^mag) / 10^mag
; Define the new scroll value
IF ws.bothfix EQ 0 THEN BEGIN
scroll_value = (srange(1)-srange(0))/((!d.n_colors<!d.table_size) > 1)
widget_control, ws.spanmagid, set_value = strtrim(string(scroll_value,format = '(g12.3)'),2)
ENDIF
; Change the slider limits for the new image
ll_fslider_set_minmax, ws.spansliders(0), min = srange(0), max = srange(1)
ll_fslider_set_minmax, ws.spansliders(1), min = srange(0), max = srange(1)
ws.srange = srange
end
; Apply current image scaling selection (from auto scaling menu) to an
; image
function look_apply_scalefunc, image
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
; For scaling function cases, force image to be float (some routines, like
; hist_equal and bytscl, return images of type byte)
case 1 of
all.scaletype eq 10: begin ; hist_equal
newimage = hist_equal (image)
newimage = float (newimage)
end
all.scaletype ge 11: begin ; custom scaling functions
newimage = call_function (all.scalefunc(all.scaletype-11), image)
newimage = float (newimage)
end
else: newimage = image
endcase
return, newimage
end
pro look_defroi_nmode, s, new
; Set new mode... Save old roi by concatenating it with s.subs.
n = s.npts
if (s.mode ne 1) and (n le 2) then n = 0 ;must have 3 pnts for polygon
WIDGET_CONTROL, s.mode_w, SET_VALUE=0 ;Revert to add mode
s.amode = 0
if n ge 1 then begin ;Old region to save?
CASE 1 OF
s.mode eq 1: begin ;Points?
WIDGET_CONTROL, s.xy_pnts, GET_UVALUE=xy, /NO_COPY ;Get old ROI
xy = xy(0,0:n-1) + s.image_size(0) * xy(1,0:n-1) ;points to subs
xy = REFORM(xy, n_elements(xy), /OVERWRITE) ;Make linear
END
s.mode eq 4: WIDGET_CONTROL, s.xy_pnts, GET_UVALUE=xy, /NO_COPY
ELSE: begin
look_defroi_DRAW, s, -1, /FILL
WIDGET_CONTROL, s.xy_pnts, GET_UVALUE=xy, /NO_COPY ;Get old ROI
xy = polyfillv(xy(0,0:n-1),xy(1,0:n-1),s.image_size(0), s.image_size(1))
END
ENDCASE
WIDGET_CONTROL, s.subs, GET_UVALUE=t, /NO_COPY ;Prev roi pnts
;Concatenate s and xy
if n_elements(t) le 0 then WIDGET_CONTROL, s.subs, SET_UVALUE=xy, /NO_COPY $
else WIDGET_CONTROL, s.subs, SET_UVALUE=[t,xy], /NO_COPY
endif ;Old region to save
s.mode = new
s.npts = 0
end
PRO look_defroi_DRAW, s, i, FILL = fill
; Draw the outline (or polygon if FILL is set)
; of the region or the ith segment if i < 0.
; Use the XOR drawing mode.
n = s.npts
if n lt 1 then return
WSET, s.win
DEVICE, SET_GRAPHICS=6 ;Xor drawing mode
col = 1
while col lt !d.table_size do col = col + col
WIDGET_CONTROL, s.xy_pnts, GET_UVALUE=xy, /NO_COPY ;Get ROI
xsave = !x.s & ysave = !y.s ;Set scaling to pixel coords
p = float([!d.x_size, !d.y_size])
f = s.offset / p
q = s.zoom / p
!x.s = [f(0), q(0)]
!y.s = [f(1), q(1)]
if s.mode eq 1 then BEGIN ;Point mode?
if i lt 0 then begin
i = 0 & i1 = n-1
ENDIF else i1 = i
for j = i, i1 do $
polyfill, xy(0,j) + [0, .9, .9, 0], xy(1,j) + [0,0,.9,.9], COLOR=col
ENDIF ELSE BEGIN ;Polygon/circle/rect
if n ge 2 then begin
if i lt 0 then plots, COLOR=col, xy(*, 0:n-1)+.5 $ ;All of it?
else plots, COLOR=col, xy(*, i:i+1)+.5 ;One segment
IF KEYWORD_SET(FILL) then POLYFILL, xy(*,0:n-1), COLOR=col
ENDIF
ENDELSE
!x.s = xsave & !y.s = ysave
WIDGET_CONTROL, s.xy_pnts, SET_UVALUE=xy, /NO_COPY ;Set ROI
DEVICE, SET_GRAPHICS=3 ;Copy mode
end
PRO look_defroi_event, ev, s
; This routine is only called from the look_defroi event loop.
; ev = event structure, s = state structure.
s.button = s.button or ev.press xor ev.release ;New button state: 1=down, 0=up
n = s.npts
x = (ev.x - s.offset(0)) / s.zoom(0) ;Pixel coordinates
y = (ev.y - s.offset(1)) / s.zoom(1)
if s.order then y0 = s.image_size(1)-y-1 else y0 = y
WIDGET_CONTROL, s.pos_w, $
SET_VALUE=string(x, y0, format='("Position: ",i,", ",i)')
if (x lt 0) or (y lt 0) or $ ;Within region?
(x ge s.image_size(0)) or (y ge s.image_size(1)) then return
if ev.press ne 0 then s.drag = [x,y] ;Start of drag operation
;widget_control,s.xy_pnts,set_value = string(ev,form = '(8i4)'),/append
if (s.mode eq 2) or (s.mode eq 3) then begin ;Rect or circle?
if s.button ne 0 then begin ;Drag
if n gt 0 then look_defroi_draw, s, -1 ;Remove old
t = s.drag
if s.mode eq 2 then begin ;Rectangle
n = 5
xy = [[t], [x, t(1)], [x, y], [t(0), y], [t]]
endif else begin ;Circle
n = 30 ;# of points
a = findgen(n+1) * (2 * !pi/(n-1))
r = sqrt((float(x)-t(0))^2 + (float(y) - t(0))^2)
xy = transpose([[t(0) + r * cos(a)], [t(1) + r * sin(a)]])
endelse
WIDGET_CONTROL, s.xy_pnts, SET_UVALUE=xy, /NO_COPY ;Restore UVALUE
s.npts = n
look_defroi_draw, s, -1
ENDIF ;DRAG
return
ENDIF ;Rect or circle
if s.button eq 0 then return ;Must be point or polygon...
tmode = s.amode ;Default mode
if s.button eq 4 then tmode = 1 ;Rt button to remove
if tmode then begin ;Remove prev point?
if (ev.press ne 0) and (n gt 0) then begin
look_defroi_DRAW, s, -1 ;Erase old region
WIDGET_CONTROL, s.xy_pnts, GET_UVALUE=xy, /NO_COPY ;Get ROI array
d = float(x-xy(0,0:n-1))^2 + float(y-xy(1,0:n-1))^2 ;Dist
t = min(d, ipnt) ;Closest...
if ipnt ne (n-1) then xy(0,ipnt) = xy(*,ipnt+1:*) ;Collapse
s.npts = n-1
WIDGET_CONTROL, s.xy_pnts, SET_UVALUE=xy, /NO_COPY ;Save ROI array
if n gt 1 then look_defroi_DRAW, s, -1 ;Draw new region
endif
return
endif ;Remove mode....
; Here we add a point
WIDGET_CONTROL, s.xy_pnts, GET_UVALUE=xy, /NO_COPY ;Get ROI array
; Add a point
if n_elements(xy) le 1 then xy = intarr(2,100)
; Remove duplicates...
if n gt 0 then if x eq xy(0,n-1) and y eq xy(1,n-1) then goto, done0
if s.mode eq 1 then for i=0, n-1 do $ ;Point mode?
IF x eq xy(0,i) and y eq xy(1,i) then goto, done0 ;No duplicates
if (n+1) ge n_elements(xy)/2 then xy = [[xy], [intarr(2,n)]] ;Extend array?
xy(0,n) = x ;New point
xy(1,n) = y
n = n + 1
s.npts = n
WIDGET_CONTROL, s.xy_pnts, SET_UVALUE=xy, /NO_COPY ;Restore UVALUE
if s.mode eq 0 then begin ;Polygon?
if n ge 2 then look_defroi_draw, s, n-2 ;Draw the new segment
endif else begin ;Point
look_defroi_draw, s, n-1 ;Draw new point
endelse
return
done0: WIDGET_CONTROL, s.xy_pnts, SET_UVALUE=xy, /NO_COPY
end
function look_defroi, draw, ZOOM = zoom, SIZE = image_size, $
OFFSET = offset, RESTORE = restore, ORDER = order,contrast = contrast $
,mode = mode,image = image
if n_elements(contrast) eq 0 then contrast = 1
if n_elements(mode) eq 0 then mode = 4 ; threshold is the default method
if n_elements(zoom) eq 0 then zoom = [1,1]
if n_elements(zoom) eq 1 then zoom = [zoom,zoom]
if n_elements(offset) le 0 then offset = [0,0]
if n_elements(image_size) le 0 then image_size = ([!d.x_size, !d.y_size]-offset) / zoom
WIDGET_CONTROL, draw, GET_VALUE=win
WSET, win
p = offset + image_size /2
TVCRS, p(0), p(1), /DEVICE
;
; =====>> Read the display; create image reduced by zoom factors
;
display = tvrd(offset(0),offset(1),image_size(0)*zoom(0),image_size(1)*zoom(1))
IF n_elements(image) EQ 0 THEN image = congrid(display,image_size(0),image_size(1))
min = min(image,max = max) ; Used for threshold slide definition
dmin = min(display,max = dmax) ; For translating display values to image values
range = float(max-min)
drange = float(dmax-dmin)
;print,zz
;
; =====>> Text for prompting
;
polygon_prompt = ['Add with left button: drag or click.' $
,'Remove with right button.']
point_prompt = polygon_prompt
rectangle_prompt = ['Drag with left button from lower left' $
,'to upper right or vice versa.']
circle_prompt = ['Drag with left button from center' $
,'to point on circle or vice versa.']
threshold_prompt = ['Select positve (>) or negative (<) contrast.' $
,'Move threshold slider to desired level.']
xsize = max([strlen(threshold_prompt),strlen(polygon_prompt),strlen(rectangle_prompt),strlen(point_prompt),strlen(circle_prompt)])
base = widget_base(title='Region of Interest', /COLUMN)
xy_pnts = WIDGET_TEXT(base, YSIZE=2, xsize = xsize,/FRAME, UVALUE=0, $
value=threshold_prompt,/scroll)
Options = CW_BGROUP(base, /ROW, /NO_RELEASE, /RETURN_NAME, $
['Done','Clear', 'Clear All', 'New', 'Cancel'])
tslide = widget_slider(base,title = 'Threshold, T',value = min,min = min,max = max,/drag)
row = widget_base(base,/row)
mode_map = [1,2,3,4,0]
junk = CW_BGROUP(row, /column, /EXCLUSIVE, /NO_REL, /RETURN_NAME, $
['Threshold, T','Polygon', 'Point', 'Rectangle', 'Circle'], SET_VALUE=mode_map(mode))
junk = CW_BGROUP(row, /ROW, /EXCLUSIVE, /NO_REL, /RETURN_NAME, $
['< T', '> T'], SET_VALUE=contrast)
mode_w = CW_BGROUP(base, /ROW, LABEL_LEFT = 'Mode:', /EXCLUSIVE, /NO_REL, $
/RETURN_NAME, ['Add', 'Remove'], SET_VALUE=0)
pos_w = WIDGET_TEXT(base, YSIZE=1, XSIZE=18, /FRAME, $
VALUE='Position: 0, 0')
WINDOW, /PIXMAP, /FREE, xs = !d.x_size, ys=!d.y_size ;Save window
backing = !d.window
DEVICE, copy = [0,0, !d.x_size, !d.y_size, 0, 0, win] ;Save it
s = { look_defroi_STRUCT, $ ;Structure containing state
base: base, $ ;Main base widget
xy_pnts: xy_pnts, $ ;Current roi vertex list
npts : 0L, $ ;# of points in current roi
subs : pos_w, $ ;Widget holding prev subscripts
pos_w : pos_w, $ ;Position text widget
mode: mode, $ ;major mode
amode: 0, $ ;0 for add, 1 for remove
draw: draw, $ ;draw widget id
win: win, $ ;draw widget window #
button: 0, $ ;button state
image_size : long(image_size), $ ;Image array size
mode_w: mode_w, $ ;Add/remove button widget
backing: backing, $ ;Pixmap for backing store
offset: fix(offset), $ ;offset of array within window
zoom : zoom, $ ;zoom factor
order : KEYWORD_SET(order), $ ;Image order
drag: [0,0]} ;Beginning of drag motion
WIDGET_CONTROL, base, /REALIZE
;WSHOW, win
WHILE 1 DO BEGIN ;Internal event loop
ev = WIDGET_EVENT([base, draw])
n = s.npts
if ev.id eq draw then BEGIN
; Fix for version 5 - now 9 tags, not 8
IF n_tags(ev) GE 8 THEN look_defroi_EVENT, ev, s ; Mouse event (not timer, e.g.)
ENDIF else BEGIN
IF ev.id EQ tslide THEN BEGIN ; Threshold slider changed
wset,win
thres = ev.value
dthres = float(thres-min)/range*drange+dmin
IF contrast THEN w = where(display LE dthres) $
ELSE w = where(display GT dthres)
IF w(0) NE -1 THEN BEGIN ; Set all pixels </> threshold to min
tmp = display
tmp(w) = min
tv,tmp,offset(0),offset(1)
ENDIF
IF contrast THEN xy = where(image GT thres,count) $
ELSE xy = where(image LE thres,count)
IF count GT 0 THEN BEGIN ; Catalog all image pixels >/< threshold
s.npts = count
WIDGET_CONTROL, s.xy_pnts, SET_UVALUE=xy, /NO_COPY
ENDIF
ENDIF ELSE case ev.value of
'Clear All': BEGIN
WIDGET_CONTROL, s.subs, GET_UVALUE=t, /NO_COPY ;Clr list of subscripts
t = 0
WSET, win
DEVICE, copy = [0,0, !d.x_size, !d.y_size, 0, 0, backing] ;Restore it
s.npts = 0
ENDCASE
'Clear': BEGIN
if (n ge 2) or (s.mode eq 1 and n ge 1) then $
look_defroi_draw, s, -1 ;Erase roi
s.npts = 0
look_defroi_NMODE, s, s.mode
ENDCASE
'New' : look_defroi_nmode, s, s.mode ;Make a new region...
'Cancel': BEGIN
xy = -1
goto, all_done
ENDCASE
; ['Polygon', 'Point', 'Rectangle', 'Circle'], SET_VALUE=0)
'Polygon': BEGIN
widget_control,xy_pnts,set_value = polygon_prompt,/append
look_defroi_nmode, s, 0
END
'Point' : BEGIN
widget_control,xy_pnts,set_value = point_prompt,/append
look_defroi_nmode, s, 1
END
'Rectangle' : BEGIN
widget_control,xy_pnts,set_value = rectangle_prompt,/append
look_defroi_nmode, s, 2
END
'Circle' : BEGIN
widget_control,xy_pnts,set_value = circle_prompt,/append
look_defroi_nmode, s, 3
END
'> T': contrast = 1
'< T': contrast = 0
'Threshold, T': BEGIN
widget_control,xy_pnts,set_value = threshold_prompt
look_defroi_nmode, s, 4
END
'Add': s.amode = 0
'Remove': s.amode = 1
'Done': BEGIN
look_defroi_nmode, s, 0 ;Save old region
WIDGET_CONTROL, s.subs, GET_UVALUE=t, /NO_COPY ;List of subscripts
xy = BYTARR(s.image_size(0), s.image_size(1)) ;Return only unique
IF n_elements(t) GT 0 THEN IF t(0) NE -1 THEN xy(t) = 1
if s.order then xy = reverse(xy,2) ;Flip it?
; print,zz
xy = where(temporary(xy))
all_done:
IF KEYWORD_SET(restore) then begin ;Undo damage?
WSET, win
DEVICE, copy = [0,0, !d.x_size, !d.y_size, 0, 0, backing] ;Restore it
ENDIF
WDELETE, backing
WIDGET_CONTROL, base, /DESTROY
return, xy
ENDCASE
ENDCASE
ENDELSE
ENDWHILE ;Event loop
END
;
; ============================
; =====>> BASIC IMAGE SCALING FOR PLOTTING
; ============================
;
FUNCTION look_scl,image,range
return,bytscl(image,min = range(0),max = range(1),top = (!d.n_colors<!d.table_size)-1)
END
;
; ============================
; =====>> Get the next image: either for catalog or as a new image
; ============================
;
FUNCTION look_get_image,ii,ws,noscale=noscale,noslide=noslide
; ii = vector of indices for new image
; ws = structure of needed quantities
COMMON look,images,catalog,index
ws.dcat(*) = -1 ; For use in look_put
ws.dcat(0:1) = ws.size(1:2) ; not necessary
ws.dcat(2:2+n_elements(ii)-1) = ii ; save indices in common
CASE 1 OF ; Choose option
ws.assoc: BEGIN
IF ws.is_struct THEN BEGIN
tmp = images(ii(0))
;; return,tmp.(ws.tag) ; return selected tag
retimage = tmp.(ws.tag) ; return selected tag
ENDIF ELSE BEGIN
;; return,images(ii(0))
retimage = images(ii(0))
ENDELSE
END
ws.func: BEGIN ; user-supplied function
text = ''
image = call_function(ws.loader_name,ii,text)
IF text NE '' THEN widget_control,ws.comtext,set_value = text,/append
;; return,image
retimage = image
END
ELSE: CASE ws.size(0) OF ; when images are passed as a parameter
;; 3: return,images(*,*,ii(0))
;; 4: return,images(*,*,ii(0),ii(1))
;; 5: return,images(*,*,ii(0),ii(1),ii(2))
;; 6: return,images(*,*,ii(0),ii(1),ii(2),ii(3))
;; 7: return,images(*,*,ii(0),ii(1),ii(2),ii(3),ii(4))
;; ELSE: return,images(*,*)
3: retimage = images(*,*,ii(0))
4: retimage = images(*,*,ii(0),ii(1))
5: retimage = images(*,*,ii(0),ii(1),ii(2))
6: retimage = images(*,*,ii(0),ii(1),ii(2),ii(3))
7: retimage = images(*,*,ii(0),ii(1),ii(2),ii(3),ii(4))
ELSE: retimage = images(*,*)
ENDCASE
ENDCASE
if not keyword_set (noscale) then retimage = look_apply_scalefunc (retimage)
if not keyword_set (noslide) then look_reset_sliders, retimage
return, retimage
END
;
; ============================
; =====>> Add a label of the current indices to the image
; ============================
;
FUNCTION look_addlabel,image,ii
; image = bytscl'd image ready for display but to have digits added here
; ii = set of image indices
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
p = 0 ; counter for total # of digits
szd = size(ws.digits) ; ned digit dimensions
x = szd(1) ; width of digit
szi = size(image) ; need height
y = szi(2)-1-szd(2) ; lower left y value for digits
IF y LE 0 THEN return,image ; not enough space in the array
w = ws.size(0)-3 ; highest index in loop, # dimensions-1
FOR i = 0,w DO BEGIN
si = byte(strtrim(ii(i),2))-48b ; indices (0-9) into digits array.
FOR j = 0,n_elements(si)-1 DO BEGIN ; add one digit at a time
IF (x*p+x) GT szi(1) THEN GOTO,DONE ; End if no more space.
image(x*p,y) = ws.digits(*,*,si(j))
p = p+1 ; increment counter of total digits
ENDFOR
IF (i EQ w) OR ((x*p+x) GT szi(1)) THEN GOTO,DONE
image(x*p,y) = ws.digits(*,*,10) ; add a ':'
p = p+1 ; increment counter of total digits
ENDFOR
DONE:
return,image
END
;
; ============================
; =====>> Routine to "blink compare" two images
; ============================
;
PRO look_blink,a,b,wid
; a,b = two bytscl'd images to compare
; wid = window id of the draw region
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
;
; =====>> Prompt the user
;
widget_control,ws.comtext,/append,set_value = 'Blink control: With mouse in blink window, left=faster, middle=slower, right=stop.'
;
; Code, except event stuff, copied from flick.pro by David Stern for X or
; Windows. I replaced flick's get_kbrd call with event loop, watching only for
; mouse events in the draw window. Note the /nowait keyword, which enables the
; blinking to continue even if a mouse button is not pressed.
;
rate = 1.0
ichl = 0
sfact = 1.5 ;Speed steps
cwin = !d.window
pix = intarr(2) ;Make 2 pixmaps
for i=0,1 do begin
window, /FREE, /PIX, xs = !d.x_size, ys = !d.y_size
pix(i) = !d.window
if i eq 0 then tv,a else tv,b
endfor
wset, cwin
while 1 do begin ; loop infinitely over each chl
device, copy=[0,0,!d.x_size, !d.y_size, 0, 0, pix(ichl)]
wait,1./rate ; This also empties the graphics buffer
ev = widget_event(wid,/nowait)
; Fix for version 5 - now 9 tags, not 8
;; help,/str,ev
IF n_tags(ev) GE 8 THEN CASE ev.press OF
1: rate = rate*sfact ; left --> Faster
2: rate = rate/sfact ; middle --> Slower
4: goto,done1 ; right --> Done
ELSE:
ENDCASE
ichl = 1 - ichl ; Other image
ENDWHILE
done1: wdelete, pix(0), pix(1)
return
END
;
; ============================
; =====>> Define a widget for index selection: - value + increment.
; ============================
;
FUNCTION look_mvpi,parent,value = value,uvalue = uvalue,menu = menu $
,title = title,size = digits,scroll = scroll,all_events = all
; parent = widget id of parent
; value = starting value of index
; uvalue = prefix for uvalue, actual uvalues are uvalue+['I-','','I+']
; title = optional label underneath the widgets, if present
; scroll = optional initial value of the increment, if present
; dimid = return values, the widget ids of the 4 widgets
; menu = pull-down menu, if present, to replace the title
dimi = strtrim(uvalue,2)
doscroll = n_elements(scroll) GT 0
dimid = lonarr(3+doscroll)
col = widget_base(parent,/column)
tmp = widget_base(col,/row)
dimid(0) = widget_button(tmp,value = '-',uvalue = dimi+'I-')
IF n_elements(all) EQ 0 THEN all = 0 ; default is to generate event on CR only
dimid(1) = widget_text(tmp,value = strtrim(value,2),uvalue = dimi+'VALUE' $
,/edit,xsize = digits,all_events = all)
dimid(2) = widget_button(tmp,value = '+',uvalue = dimi+'I+')
IF doscroll THEN dimid(3) = widget_text(tmp,value = strtrim(scroll,2),/edit,xsize = digits)
IF n_elements(menu) GT 0 THEN BEGIN
junk = cw_pdmenu(col,menu,/return_name,uvalue = dimi+'pdmenu')
ENDIF ELSE BEGIN
IF n_elements(title) GT 0 THEN IF title NE '' THEN $
junk = widget_label(col,value = title)
ENDELSE
return,dimid
END
;
; ============================
; =====>> Display catalog or movie of images or blink compare
; ============================
;
PRO look_catalog,testin,dofull,id,do_catalog = do_catalog
; testin = uvalue of the event
; dofull = flag to distinguish between full (1) or zoom (0) image
; id = widget id of the draw window
; do_catalog = flag to designate catalog so save widgets are added
COMMON look,images,catalog,index
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
;
; =====>> Setup
;
docatalog = strpos(testin,'cat') GE 0
domovie = strpos(testin,'movie') GE 0
doblink = strpos(testin,'blink') GE 0
IF dofull THEN xy = [ws.size(1),ws.size(2)] ELSE BEGIN
xy = [zoom.xrange(1)-zoom.xrange(0)+1,zoom.yrange(1)-zoom.yrange(0)+1]
ENDELSE
IF domovie THEN BEGIN
device,get_screen_size = scrdims ; screen size
scrfrac = [4,2,1] ; possible screen fractions to cover
times = (((scrdims(0)/xy(0)) < (scrdims(1)/xy(1)))/scrfrac) > 1
ENDIF
IF domovie THEN dozoom = domovie AND (max(times) GT min(times)) ELSE dozoom = 0; movie and zoom allowed
titles = ['first','-last','/step','blink']
IF doblink THEN BEGIN
ncol = 4
buttons = ['DONE','GO','STOP']
ENDIF ELSE BEGIN
ncol = 3
buttons = ['DONE','GO','STOP']
ENDELSE
nd = long(ws.size(0)-2) ; # of dimensions beyond 2 (3-D etc.)
IF nd LE 0 THEN return ; guard against 2-D only
cid = lonarr(3,ncol,nd) ; widget id's for all selection widgets
;
; =====>> Create widget
;
CASE 1 OF
domovie: parent = widget_base(/column,title = 'Movie')
doblink: parent = widget_base(/column,title = 'Blink Compare')
ELSE: parent = widget_base(/column,title = 'Catalog')
ENDCASE
dg = long(max(ceil(alog10(ws.size(3:nd+2)))))
nimages = 1l
FOR d = 0,nd-1 DO BEGIN ; dimensions
nimages = nimages*long(ws.size(d+3))
row = widget_base(parent,/row)
IF d EQ (nd-1) THEN tit = titles ELSE tit = strarr(ncol)
uv = titles+strtrim(d,2)
cid(0,0,d) = look_mvpi(row,val=ws.d(d+2),uv=uv(0),si=dg,ti=tit(0))
cid(0,1,d) = look_mvpi(row,val=ws.d(d+2),uv=uv(1),si=dg,ti=tit(1))
cid(0,2,d) = look_mvpi(row,val=1,uv=uv(2),si=dg,ti=tit(2))
IF doblink THEN $
cid(0,3,d) = look_mvpi(row,val=ws.d(d+2),uv=uv(3),si=dg,ti=tit(3))
junk = widget_label(row,value = ws.dimname(d))
ENDFOR
IF dozoom THEN zid = widget_slider(parent,title = 'zoom factor',uvalue = 'ZOOM',min = times(0),max = times(2),value = times(1))
row = widget_base(parent,/row)
bid = lonarr(n_elements(buttons))
FOR n = 0,n_elements(buttons)-1 DO BEGIN
bid(n) = widget_button(row,value = buttons(n),uvalue = buttons(n))
ENDFOR
tmp = widget_base(row,/row,/nonexclusive)
AddLabels = widget_button(tmp,value = 'Add Labels?',uvalue = 'AddLabels')
widget_control,AddLabels,set_button = ws.AddLabels
nput_pre = '# images = '
nput = 0l
nimid = widget_text(row,value = nput_pre+string(nput))
row = widget_base(parent,/row)
tmp = widget_button(row,value = 'Write PS file',uvalue = 'writePSfile')
tmp = widget_button(row,value = 'Modify PS attributes',uvalue = 'SetPSatt')
row = widget_base(parent,/row)
IF docatalog THEN BEGIN
catalog_pre = '# catalog images = '
sz = size(catalog)
IF sz(0) EQ 3 THEN ncatalog = sz(3) ELSE ncatalog = 0
ncatalogid = widget_text(row,value = catalog_pre+string(ncatalog))
index_pre = '# index sets = '
sz = size(index)
IF sz(0) EQ 2 THEN nindex = sz(2) ELSE nindex = 0
nindexid = widget_text(row,value = index_pre+string(nindex))
col = widget_base(parent,/column,/nonexclusive)
saveid = widget_button(col,value = 'Save images/indices in catalog/index of common look',uvalue = 'CATALOGSAVE')
widget_control,saveid,set_button = ws.catalogsave
indexid = widget_button(col,value = 'Only save selected indices in index of common look',uvalue = 'SAVE')
widget_control,indexid,set_button = ws.save
resetid = widget_button(col,value = 'Reset catalog and index at start of next save',uvalue = 'RESET')
widget_control,resetid,set_button = ws.reset
catshowid = widget_button(col,value = 'Display images in catalog (otherwise just generate indices)',uvalue = 'CATSHOWIMAGES')
widget_control,catshowid,set_button = ws.catshowimages
ENDIF
instrid = widget_text(parent,value = ['Adjust indices. Enter new value with CR.','Then hit GO button. Hitting STOP aborts.'],/scroll,ysize = 2)
widget_control,parent,/realize
;
; =====>> Processing loop: process events while watching for GO
;
go = 0 ; Flag to start processing
newvalues = 1 ; Flag to recalculate indices, # of images,...
LOOP:
;
; =====>> If an index was changed, recalculate the indices, etc.
;
IF newvalues THEN BEGIN
cidv = cid*0 ; Calculate # of images using current data
nput = 1l ; total number of images
step = lonarr(nd) ; step size along each dimension
nsteps = lonarr(nd) ; # of steps along each dimension
FOR d = 0l,nd-1 DO BEGIN ; loop to collect info from widgets
FOR i = 0l,ncol-1 DO BEGIN
widget_control,cid(1,i,d),get_value = tmp
cidv(1,i,d) = long(tmp)
ENDFOR
step(d) = cidv(1,2,d) > 1
nsteps(d) = floor((cidv(1,1,d)-cidv(1,0,d))/step(d))+1
nput = nput*nsteps(d)
ENDFOR
widget_control,nimid,set_value = nput_pre+strtrim(nput,2)
indices = lonarr(nput,nd) ; array of indices---easiest way to keep track
dups = [1,nsteps] ; duplication factors
dup = 1l ; duplication counter
FOR d = 0l,nd-1 DO BEGIN ; loop over dimensions
dup = dups(d)*dup ; # of times each index appears
t = reform(cidv(1,*,d)) ; a convenience
IF t(1) EQ t(0) THEN BEGIN ; along this dimension, no increments
indices(0,d) = replicate(t(0),nput)
ENDIF ELSE BEGIN ; along this dimension, replicate index vector
for kk = 0, nput / dup / nsteps(d) - 1 do begin
for ll = 0, nsteps(d) - 1 do begin
i0 = ll * dup + kk * nsteps(d) * dup
indices(i0:i0+dup-1,d) = t(0) + step(d) * ll
endfor
endfor
; v = lindgen(nsteps(d))*step(d)+t(0)
; tmp = lonarr(dup*nsteps(d))
; tmp(*) = transpose((lonarr(dup)+1)#v)
; indices(*,d) = tmp#(lonarr(nput/dup/nsteps(d))+1)
; print,indices(*,d)
ENDELSE
ENDFOR
newvalues = 0 ; reset flag
ENDIF
;
; =====>> If user said go, then display the next image.
;
IF go THEN BEGIN
IF iput LT nput THEN BEGIN
ii = reform(indices(iput,*))
;; tmp = look_apply_scalefunc (look_get_image(ii,ws))
if ws.catshowimages or ws.catalogsave then $
tmp = look_get_image(ii,ws,/noslide)
IF ws.save THEN BEGIN
IF ws.saveoffset EQ -1 OR n_elements(index) EQ 0 THEN BEGIN ; reset catalog and index arrays?
index = ii ; redefine the index variable
ws.saveoffset = 0 ; kludgey fix added 062299
ENDIF ELSE BEGIN
index = [[index],[ii]] ; append to index array
ENDELSE
IF ws.catalogsave THEN BEGIN
ws.saveoffset = ws.saveoffset + 1 ; increment offset
catalog(*,*,ws.saveoffset) = tmp
widget_control,ncatalogid,set_value = catalog_pre+strtrim(ws.saveoffset+1,2)
ENDIF
sz = size(index)
IF sz(0) EQ 2 THEN n = sz(2) ELSE n = 0
widget_control,nindexid,set_value = index_pre+strtrim(n,2)
ENDIF
if ws.catshowimages then begin
; Fix to use auto scaling
look_auto_minmax, scaleto = tmp, newrange = newlim, /no_update, /no_bound
;; tmp = look_scl(tmp,all.tvrange)
tmp = look_scl(tmp,newlim)
IF NOT dofull THEN $
tmp = tmp(zoom.xrange(0):zoom.xrange(1),zoom.yrange(0):zoom.yrange(1))
IF dozoom THEN tmp = rebin(tmp,xy(0)*zoomfact,xy(1)*zoomfact,/sample)
IF domovie THEN BEGIN
IF ws.AddLabels THEN tmp = look_addlabel(tmp,ii)
xinteranimate,image = tmp,frame = iput
ENDIF ELSE look_put,tmp,iput+1,nput
endif
ENDIF ELSE BEGIN
IF domovie THEN BEGIN
widget_control,parent,/destroy
xinteranimate
return
END
IF doblink THEN BEGIN
blink0 = tvrd()
;; tmp = look_scl(look_get_image(reform(cidv(1,3,*)),ws),all.tvrange)
; Fix to use auto scaling
;; tmp = look_scl(look_get_image(reform(cidv(1,3,*)),ws,/noscale,/noslide),all.tvrange)
tmp = look_get_image(reform(cidv(1,3,*)),ws,/noscale,/noslide)
look_auto_minmax, scaleto = tmp, newrange = newlim, /no_update, /no_bound
tmp = look_scl(tmp,newlim)
IF NOT dofull THEN $
tmp = tmp(zoom.xrange(0):zoom.xrange(1),zoom.yrange(0):zoom.yrange(1))
FOR n = 0,nput-1 DO look_put,tmp,n+1,nput
blink1 = tvrd()
widget_control,instrid,set_value = 'button control ON IMAGE: left->Faster, middle->Slower, right->Done',/append
look_blink,blink0,blink1,id
ENDIF
go = 0 ; and stop further display
ENDELSE
iput = iput+1 ; increment image counter
ENDIF
;
; =====>> Get events
;
ev = widget_event(parent,/nowait)
wait,0.05 ; to limit cpu usage during wait for event
IF ev.id EQ 0 THEN GOTO,LOOP
widget_control,ev.id,get_uvalue = uvalue,get_value = value
IF ws.debug THEN widget_control,ws.comtext,/append $
,set_value = strtrim(uvalue,2) $
+' '+strtrim(value,2)+' '+strtrim(ev.id,2)+' '+strtrim(ev.top,2) $
+' '+strtrim(ev.handler,2)
;
; =====>> Process events
;
test = string(uvalue)
CASE 1 OF
test EQ 'AddLabels': ws.AddLabels = ev.select
test EQ 'DONE': BEGIN
widget_control,parent,/destroy
return
END
(strpos(test,'I+') GE 0) OR (strpos(test,'I-') GE 0) OR (strpos(test,'VALUE') GE 0): BEGIN
IF strpos(test,'VALUE') GE 0 THEN sign = 0 $ ; CR, so add 0 to new below
ELSE sign = 2*(strpos(uvalue,'+') GE 0)-1 ; 1-->1 & 0-->-1
dim = fix(strmid(uvalue,5,1))
w = (where(titles EQ strmid(uvalue,0,5)))(0)
IF w GE 0 THEN BEGIN
widget_control,cid(1,w,dim),get_value = current
new = (long(current)+sign) > 0 < long((ws.size(dim+3)-1))
widget_control,cid(1,w,dim),set_value = strtrim(new,2)
ENDIF
IF (w EQ 0) THEN BEGIN ; first modified
widget_control,cid(1,1,dim),get_value = curlast
widget_control,cid(1,1,dim),set_value = strtrim(new > curlast,2)
; print,dummy
ENDIF
IF (w EQ 1) THEN BEGIN ; last modified
widget_control,cid(1,0,dim),get_value = curfirst
widget_control,cid(1,0,dim),set_value = strtrim(curfirst < new,2)
ENDIF
newvalues = 1
END
test EQ 'GO': BEGIN
iput = 0 ; reset the number of images stored
IF domovie THEN BEGIN
IF dozoom THEN widget_control,zid,get_value = zoomfact ELSE zoomfact = 1
; IF ws.debug THEN widget_control,ws.comtext,/append,set_value = 'zoom = '+strtrim(zoomfact,2)
xinteranimate,set = [xy(0)*zoomfact,xy(1)*zoomfact,nput > 2],/showload
ENDIF ELSE erase
IF ws.save THEN BEGIN ; Define output array?
IF ws.reset THEN BEGIN
ws.saveoffset = -1 ; reset pointer to first element in catalog
ws.reset = 0 ; unset reset flag
widget_control,resetid,set_button = 0 ; turn off reset button
catalog = 0 ; reset catalog variable
index = 0 ; reset index variable
ENDIF
IF ws.catalogsave THEN BEGIN
sz = [3,xy,nput,ws.size(nd+1),xy(0)*xy(1)*nput]
IF n_elements(catalog) EQ 1 THEN catalog = make_array(size = sz) $
ELSE catalog = [[[temporary(catalog)]],[[make_array(size = sz)]]]
ENDIF
ENDIF
go = 1
END
test EQ 'CATALOGSAVE': BEGIN
ws.catalogsave = ev.select
ws.save = ev.select OR ws.save ; OR in case catalog reset with index set
END
test EQ 'SAVE': ws.save = ev.select OR ws.catalogsave
test EQ 'RESET': ws.reset = ev.select
test EQ 'CATSHOWIMAGES': ws.catshowimages = ev.select
test EQ 'SetPSatt': look_PSatt
test EQ 'STOP': go = 0
test EQ 'writePSfile': look_put,tvrd(),1,1,filename = ws.PSfilename
ELSE:
ENDCASE
GOTO,LOOP
END
;
; ============================
; =====>> Fill the window with a plot: modeled after Bill Thompson's exptv
; ============================
;
PRO look_exptv,image,minimum = minimum,maximum = maximum,zoom = zoom,offset = offset,image = tvimage
; image = bytscl'd 2-D image
; minimum, maximum = not used
; zoom = output, floating 2-element vector of display size to image size
; offset = output, 2-element vector of pixel offsets to lower left corner of image
x = [0,!d.x_size-1] ; 1st and last x pixels of window
y = [0,!d.y_size-1] ; 1st and last y pixels of window
xw = x(1)-x(0)+1 ; window x width
yw = y(1)-y(0)+1 ; window y width
aw = float(yw)/xw ; window aspect ratio
si = size(image)
ai = float(si(2))/si(1) ; image aspect ratio
IF aw GT ai THEN BEGIN
y = y + [1,-1]*(yw-xw*ai)/2 ; window higher, so decrease y symmetrically
ENDIF ELSE BEGIN
x = x + [1,-1]*(xw-yw/ai)/2 ; image higher, so decrease x symmetrically
ENDELSE
erase
tvimage = congrid(image,x(1)-x(0)+1,y(1)-y(0)+1)
tv,tvimage,x(0),y(0)
zoom = float([x(1)-x(0)+1,y(1)-y(0)+1])/si(1:2)
offset = [x(0),y(0)]
return
END
;
; ============================
; =====>> Catalog output plots: modeled after Bill Thompson's put
; ============================
;
PRO look_put,image,iix,nnx,filename = filename
; image = 2-D imge, bytscl'd
; iix = # of the image: 1,...,nnx
; nnx = maximum number of plots
; filename = PS filename. If present, then assume SINGLE plot to 'PS' device.
;
; =====>> Special case: Assume iix=nnx=1, bytscl'd image, and 'PS' device.
;
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
IF n_elements(filename) GT 0 THEN BEGIN
IF (iix NE 1) OR (nnx NE 1) THEN BEGIN
widget_control,ws.comtext,/append,set_value = $
'look_put: Only one image allowed. No PS file written.'
return
ENDIF
widget_control,/hourglass
set_plot,'PS' ; Choose Postscript.
stretch,0,2^ws.PSatt.bits-1 ; expand/dilute color table to right # of elements
xcm = !d.x_size/!d.x_px_cm ; window x dimension in cm
ycm = !d.y_size/!d.y_px_cm ; window y dimension in cm
sz = size(image) ; image size
ai = float(sz(2))/sz(1) ; image aspect ratio
aw = float(!d.y_size)/!d.x_size ; window aspect ratio
IF aw GT ai THEN ycm = xcm*ai ELSE xcm = ycm/ai
device,file = ws.PSfilename,xsize = xcm,ysize = ycm
IF ws.PSattstr NE '' THEN stat = execute('device'+ws.PSattstr)
tv,image
stretch ; restore original # of elements in color table
device,/close ; close device
set_plot,'X'
widget_control,hourglass = 0
return
ENDIF
;
; =====>> Code from Bill Thompson's put.pro: arrange along the X and
; Y axes based on the size of the image and the size of the window.
;
S = SIZE(image)
NX = NNX
NY = 1
AMAX = 0
FOR NI = 1,NNX DO BEGIN
NJ = (NNX + NI - 1) / NI
AX = !D.X_SIZE / (S(1)*FLOAT(NI))
AY = !D.Y_SIZE / (S(2)*FLOAT(NJ))
AA = AX < AY
IF AA GT AMAX THEN BEGIN
AMAX = AA
NX = NI
NY = NJ
ENDIF
ENDFOR
;IX = ((IIX - 1) MOD NX) + 1
;IY = (IIX - 1)/NX + 1
;
; =====>> Display the image, assumed to be scaled properly
;
xw = !d.x_size/nx
yw = !d.y_size/ny
ai = float(s(2))/s(1)
aw = float(yw)/xw
IF aw GT ai THEN yw = xw*ai ELSE xw = yw/ai
mx = max(image)
c = congrid(image,xw,yw)
IF ws.AddLabels THEN c = look_addlabel(c,ws.dcat(2:*))
c(0,*) = mx ; add a border all around
c(xw-1,*) = mx
c(*,0) = mx
c(*,yw-1) = mx
tv,c,iix-1
return
END
;
; ============================
; =====>> Plot image with axes, modeled after Bill Thompson's plot_image
; ============================
;
PRO look_image,image,_extra = extra,origin = origin,scale = scale $
,minimum = minimum,mximum = maximum
; image = bytscl'd image to be tv'd
; _extra = any keyword for plot
; origin, scale, minimum, maximum = not used
IF n_elements(origin) EQ 0 THEN origin = [0,0]
plot,[0,1],_extra = extra,xstyle = 5,ystyle = 5,/nodata ; set !x.window & !y.window
x = !x.window*!d.x_size ; x pixels in plot window
y = !y.window*!d.y_size ; y pixels in plot window
xw = x(1)-x(0) ; x width in pixels
yw = y(1)-y(0) ; y width in pixels
si = size(image)
ai = float(si(2))/si(1) ; aspect ratio (y:x) of the image
aw = float(yw)/xw ; aspect ratio of the plot window
; Depending on aspect, change either y or x.
IF aw GT ai THEN y = y + [1,-1]*(yw-xw*ai)/2 ELSE x = x + [1,-1]*(xw-yw/ai)/2
erase
tv,congrid(image,x(1)-x(0),y(1)-y(0)),x(0),y(0)
xpos = x/!d.x_size ; After tv, add axes at xpos
ypos = y/!d.y_size ; ...and ypos
; Changed xrange and yrange to make ticks centered on the corresponding data
; boxes - this is done by extending the ranges by 0.5 on each end (DSR)
plot,[0,si(2)-1],_extra = extra,xstyle = 1,ystyle = 1 $
,/noerase,/nodata,position = [xpos(0),ypos(0),xpos(1),ypos(1)] $
,xrange = [0-0.5,si(1)-0.5]+origin(0),yrange = [0-0.5,si(2)-0.5]+origin(1)
;; ,xrange = [0,si(1)-1]+origin(0),yrange = [0,si(2)-1]+origin(1)
;print,zz
return
END
;
; ============================
; =====>> FIND FILE IN !PATH: like findfile but anywhere in !path
; ============================
;
FUNCTION look_in_path,filename
path=expand_path(!PATH,/array,count=count)
file=''
i=-1
REPEAT BEGIN
i=i+1
file=findfile(path(i)+'/'+filename)
ENDREP UNTIL file(0) ne '' or i eq count-1
return,file
END
;
; ============================
; =====>> DISPLAY AN ARRAY as text in a widget
; ============================
;
PRO look_xdisplay_event,ev
widget_control,ev.id,get_uvalue = uvalue
IF uvalue EQ 'DONE' THEN widget_control,ev.top,/destroy
return
END
PRO look_xdisplay_one,parent,buf,xsize = xsize,ysize = ysize,title = title
szb = size(buf)
junk = widget_text(parent,value = title)
CASE szb(szb(0)+1) OF
7: junk = widget_text(parent,xsize = xsize,ysize = ysize,/scroll,value = buf)
; 1: junk = widget_text(parent,xsize = xsize,ysize = ysize,/scroll,value = string(buf(0:szb(2) < 682,*),form = '(i3)'))
ELSE:
ENDCASE
return
END
PRO look_xdisplay,buf,buf2,xsize = xsize,ysize = ysize,titles = titles
; buf = 1D or 2D array, either strings or numbers, to display in a scrollable widget_text
; xsize = width in characters (D=80)
; ysize = height in lines (D=22)
IF n_elements(xsize) EQ 0 THEN xsize = 80
IF n_elements(ysize) EQ 0 THEN ysize = 22
parent = widget_base(/column,title = 'look_xdisplay')
junk = widget_button(parent,value = 'DONE',uvalue = 'DONE')
look_xdisplay_one,parent,buf,xsize = xsize,ysize = ysize,title = titles(0)
IF n_elements(buf2) GT 0 THEN look_xdisplay_one,parent,buf2,xsize = xsize,ysize = ysize,title = titles(1)
widget_control,parent,/realize
xmanager,'look_xdisplay',parent,event_handler = 'look_xdisplay_event'
return
END
;
; ============================
; =====>> 2 COORDINATE CONVERTERS: device <--> data
; ============================
;
; data <--> device
; given data coords, return slopes & intercepts to convert device to data
; OR
; given device coords, return slopes & intercepts to convert data to device
pro look_si,x,y,slopes,intercepts,to_data = to_data
IF keyword_set(to_data) THEN BEGIN
dat = convert_coord([x(0),x(1)],[y(0),y(1)],/to_data,/device)
slopes = [(x(1)-x(0))/(dat(0,1)-dat(0,0)),(y(1)-y(0))/(dat(1,1)-dat(1,0))]
intercepts = [x(0)-dat(0,0)*slopes(0),y(0)-dat(1,0)*slopes(1)]
ENDIF ELSE BEGIN
; Note (DSR): this is close, but not quite right for this application. A
; better approach is used in look_si2
dev = convert_coord([x(0),x(1)],[y(0),y(1)],/data,/to_device)
slopes = [(x(1)-x(0))/(dev(0,1)-dev(0,0)),(y(1)-y(0))/(dev(1,1)-dev(1,0))]
intercepts = [x(0)-dev(0,0)*slopes(0),y(0)-dev(1,0)*slopes(1)]
ENDELSE
return
end
; look_si2 is a corrected version of look_si, but *without* the to_data
; option (DSR)
pro look_si2,xrange,yrange,slopes,intercepts,to_data = to_data
IF keyword_set(to_data) THEN BEGIN
;; dat = convert_coord([x(0),x(1)],[y(0),y(1)],/to_data,/device)
;; slopes = [(x(1)-x(0))/(dat(0,1)-dat(0,0)),(y(1)-y(0))/(dat(1,1)-dat(1,0))]
;; intercepts = [x(0)-dat(0,0)*slopes(0),y(0)-dat(1,0)*slopes(1)]
message, /inform, 'look_si2 does not have the to_data option; use look_si'
ENDIF ELSE BEGIN
slopes = [((xrange(1) - xrange(0) + 1.) / $
(!D.X_SIZE * (!x.window(1) - !x.window(0)))), $
((yrange(1) - yrange(0) + 1.) / $
(!D.Y_SIZE * (!y.window(1) - !y.window(0))))]
intercepts = [-slopes(0) * !D.X_SIZE * !x.window(0), $
-slopes(1) * !D.Y_SIZE * !y.window(0)]
ENDELSE
return
end
; device <--> data
; given device coords, return data coords OR vice versa
FUNCTION look_cc,coord,slope,intercept
; Corrected: the slope and intercept conversion factors are based on
; the lower left corner of the data cell boundaries; they are not data
; centered. Therefore, the calculated coordinates should always be rounded
; down. Note also that the FIX function rounds positive values down, and
; negative values up. Therefore, 1 must be subtracted from negative values
; in order to obtain the desired downward rounding (DSR).
zz = slope*coord+intercept
nel = n_elements (zz)
for i = 0, nel - 1 do begin
if (zz(i) lt 0.) then zz(i) = zz(i) - 1.
endfor
return, fix (zz)
;; return,fix(slope*coord+intercept+0.5) ; want integer; it's a pixel number.
END
;
; ============================
; =====>> DECIDE IF CUTS NEED UPDATING AND DO IT
; ============================
;
;+
; NAME:
; look_cut
; PURPOSE:
; This procedure updates the horizontal and vertical cuts.
; INPUTS:
; tmp = structure containing state information, either all or zoom
; xn,yn = device coordinates of the mouse
; xincr,yincr = increments, in data coordinates, to be added to
; the converted values of xn,yn
; MODIFICATION HISTORY:
; add xn,yn,xincr,yincr, 21 Mar 95, FKK
; xincr, yincr not used anymore so remove them, 9 Sep 95, FKK
; add crosshairs code and docrosshairs flag, 9 Sep 95, FKK
;-
pro look_cut,tmp,xn,yn,docrosshairs = docrosshairs
COMMON look,images,catalog,index
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
; Don't do cross cut plots if the cursor is moved in a window that is
; showing a plot type other than the default (look_image) or contour
if (ws.plottype ne 0 and ws.plottype ne 1) and $
((ws.plotfullzoom eq 0 and tmp.id eq zoom.id) or $
(ws.plotfullzoom eq 1 and tmp.id eq all.id) or $
ws.plotfullzoom eq 2) then return
;
; =====>> Convert device to data coordinates.
;
wset,tmp.id
xm = look_cc(xn,tmp.slopes(0),tmp.intercepts(0))+tmp.xrange(0)
ym = look_cc(yn,tmp.slopes(1),tmp.intercepts(1))+tmp.yrange(0)
; Adjust cursor coordinates to force crosshairs into the middle of the
; current data cell (DSR)
xn = fix ((xm + 0.5 - tmp.xrange(0) - tmp.intercepts(0)) / tmp.slopes(0))
yn = fix ((ym + 0.5 - tmp.yrange(0) - tmp.intercepts(1)) / tmp.slopes(1))
; print,format = '($,4i5,a)',xm,ym,xm-tmp.datlast(0),ym-tmp.datlast(1),':'
;
; =====>> Is the mouse inside the plot region?
;
IF ((xm<tmp.xrange(1)>tmp.xrange(0)) EQ xm) AND ((ym<tmp.yrange(1)>tmp.yrange(0)) EQ ym) THEN BEGIN
; Changed 052097, DSR: decoupled ws.cut_oplot and ws.last_cutwid.
; ws.last_cutwid has the ID of the window used to make the last cut plots;
; ws.cut_oplot indicates whether the cut plots should be updated. In some
; cases (following calls to look_span_update), the cut windows need to be
; redrawn, but the crosshairs remain visible.
;; ws.cut_oplot = ws.last_cutwid EQ tmp.id ; 1 --> oplot 2x, 0 --> oplot 1x
; Erase crosshairs in other window, if switching windows
if ws.last_cutwid ne -1 and ws.last_cutwid ne tmp.id and $
keyword_set(docrosshairs) THEN BEGIN
wset,ws.last_cutwid
device,set_graphics = 6 ; XOR mode
if (ws.last_cutwid eq all.id) then xl = all.devlast(0) $
else xl = zoom.devlast(0)
if xl ge 0 then plots,[xl,xl],[0,!d.y_size],/dev
if (ws.last_cutwid eq all.id) then yl = all.devlast(1) $
else yl = zoom.devlast(1)
if yl ge 0 then plots,[0,!d.x_size],[yl,yl],/dev
device,set_graphics = 3 ; default (overwrite) mode
ENDIF
; Fix added to clear (and force a redraw of) the horizontal and vertical
; cut windows, once the cursor has switched between the full/zoom windows
if (ws.last_cutwid ne tmp.id) then begin
wset,tmp.vcutid ; Activate the vertical cut window
erase ; Clear the vertical cut window
wset,tmp.hcutid ; Activate the horizontal cut window
erase ; Clear the horizontal cut window
wset,tmp.id ; Reset the active window
tmp.datlast(0) = -1 ; Invalidate the saved X coordinate
tmp.datlast(1) = -1 ; Invalidate the saved Y coordinate
endif
;; ws.last_cutwid = tmp.id
newy = (ym NE tmp.datlast(1))
IF newy THEN BEGIN
wset,tmp.hcutid
xdata = lindgen(tmp.width(0))+tmp.xrange(0)
nx = n_elements(xdata)
ydata = thisimage(tmp.xrange(0):tmp.xrange(1),ym)
ny = n_elements(ydata)
IF NOT ws.cut_oplot(0) THEN erase
plot,xdata,ydata,xstyle = 1,ystyle = 1 $
,position = tmp.position,yrange = tmp.tvrange,xrange = tmp.xrange $
,title = 'HORIZONTAL CUT',xtit = ws.units(0),ytit = ws.units(2) $
,/nodata,/noerase
IF ws.cut_oplot(0) THEN $
oplot,ws.hcutxdata(0:nx-1),ws.hcutydata(0:ny-1) $
,color = !p.background,psym = 10*(nx LT 100)
; IF ws.cut_oplot(0) THEN BEGIN; this doesn't work: Does oplot set_graph?
; device,set_graphics = 6 ; XOR mode to blank out previous cut
; plots,ws.hcutxdata(0:nx-1,0),ws.hcutydata(0:ny-1,0) ; replot previous
; device,set_graphics = 3 ; COPY mode to plot new cut
; ENDIF
oplot,xdata,ydata,psym = 10*(nx LT 100)
ws.hcutxdata(0:nx-1) = xdata ; save it for the next call
ws.hcutydata(0:ny-1) = ydata ; ditto
tmp.datlast(1) = ym
IF keyword_set(docrosshairs) THEN BEGIN
wset,tmp.id
device,set_graphics = 6
plots,[0,!d.x_size],[yn,yn],/dev
yl = tmp.devlast(1)
; Erase the previous crosshair, unless this is the first entry in
; the new window
if ws.last_cutwid eq tmp.id and yl GE 0 THEN $
plots,[0,!d.x_size],[yl,yl],/dev
device,set_graphics = 3
tmp.devlast(1) = yn
ENDIF
ENDIF
newx = (xm NE tmp.datlast(0))
IF newx THEN BEGIN
wset,tmp.vcutid
xdata = reform(thisimage(xm,tmp.yrange(0):tmp.yrange(1)))
nx = n_elements(xdata)
ydata = lindgen(tmp.width(1))+tmp.yrange(0)
ny = n_elements(ydata)
IF NOT ws.cut_oplot(1) THEN erase
IF nx GE 2 THEN $ ; bug: need 2 pts in xrange
plot,xdata,ydata,xstyle = 1 $
,ystyle = 1,position = tmp.position,title = 'VERTICAL CUT' $
,xrange = tmp.tvrange,yrange = tmp.yrange $
,xtit = ws.units(2),ytit = ws.units(1) $
,/nodata,/noerase
IF ws.cut_oplot(1) THEN BEGIN
IF nx GE 100 THEN BEGIN ; erase the previous data---no histogram
oplot,ws.vcutxdata(0:nx-1),ws.vcutydata(0:ny-1),color = !p.background
ENDIF ELSE BEGIN ; vertical histogram (can't use psym=10)
ypsi = lindgen(ny-1)
yps = ws.vcutydata(0:ny-1)
ps = [1,1]#((yps(ypsi+1)+yps(ypsi))/2.)
xps = [1,1]#ws.vcutxdata(0:nx-1)
oplot,xps,[yps(0),ps(*),yps(ny-1)],color = !p.background
ENDELSE
ENDIF
IF nx GE 100 THEN BEGIN ; plot the current data---no histogram
oplot,xdata,ydata
ENDIF ELSE BEGIN ; vertical histogram (can't use psym=10)
ypsi = lindgen(ny-1)
yps = ydata
ps = [1,1]#((yps(ypsi+1)+yps(ypsi))/2.)
xps = [1,1]#xdata
oplot,xps,[yps(0),ps(*),yps(ny-1)]
ENDELSE
ws.vcutxdata(0:nx-1) = xdata ; save it for the next call
ws.vcutydata(0:ny-1) = ydata ; ditto
tmp.datlast(0) = xm
IF keyword_set(docrosshairs) THEN BEGIN
wset,tmp.id
device,set_graphics = 6
plots,[xn,xn],[0,!d.y_size],/dev
xl = tmp.devlast(0)
; Erase the previous crosshair, unless this is the first entry in
; the new window
if ws.last_cutwid eq tmp.id and xl GE 0 THEN $
plots,[xl,xl],[0,!d.y_size],/dev
device,set_graphics = 3
tmp.devlast(0) = xn
ENDIF
ENDIF
IF newx OR newy THEN BEGIN
ws.report(1:2) = [' x='+strtrim(xm,2),' y='+strtrim(ym,2)]
z = thisimage(xm,ym)
IF ws.size(ws.size(0)+1) EQ 1 THEN z = long(z) ; Don't print byte as char.
ws.report(3) = ' z='+strtrim(z,2)
widget_control,ws.reptext,set_value = ws.star+ws.report
ENDIF
ws.last_cutwid = tmp.id
; Set flag to update cut plots next time through (this may subsequently be
; unset by look_span_update)
ws.cut_oplot = 1
ENDIF
return
END
;
; ============================
; =====>> Calculate indices unique to first argument
; ============================
;
FUNCTION look_unique,a,b
; a,b = where vectors presumably with some common elements
; This function will return all of a's elements that are not in b.
; IN this case:
; a = indices for the entire image
; b = indices of the selected source region
tmp = [a,b] ; David Stern's idea.
tmp = tmp(sort(tmp)) ; Sort. Look for identical pairs, i.e., matches.
match = where((tmp(1:*) - tmp) LE 0,cnt)
IF cnt EQ 0 THEN return,a ELSE BEGIN
test = [a,tmp(match)] ; form vector of matches and one of inputs
test = test(sort(test)) ; and sort it
test = [test(0)-1,test,test(n_elements(test)-1)+1] ; add elements to both ends
; find each element where both neighbors are different
; Example:
; test=[-1,0,1,2,2,3,3,5,6] ; after adding additional first and last elements
; test-test(1:*)=[-1,-1,-1,0,-1,0,-2,-1], so ... NE 0 = [1,1,1,0,1,0,1,1]
; test(2:*)-test(1:*)=[-1,-1,0,-1,0,-2,-1], so ... NE 0 = [1,1,0,1,0,1,1]
; test(...AND...+1)=[0,1,5]
; Looks right.
return,test(where(((test-test(1:*)) NE 0) AND ((test(2:*)-test(1:*)) NE 0))+1)
ENDELSE
END
;
; ============================
; =====>> Print a line containing statistics
; ============================
;
PRO look_print_stats,sp,image,tagtext,wid
IF sp(0) eq -1 THEN text = 'No points in '+tagtext+' region.' ELSE BEGIN
nsp = n_elements(sp)
IF nsp GT 1 THEN begin
res = moment (image(sp), sdev = sd)
mean = res(0)
endif ELSE BEGIN
sd = 0
mean = image(sp)
ENDELSE
max = max(image(sp),min = min)
text = tagtext+': #pts='+strtrim(n_elements(sp),2) $
+' mean='+strtrim(mean,2)+' sd='+strtrim(sd,2) $
+' lo='+strtrim(min,2)+' hi='+strtrim(max,2)
ENDELSE
widget_control,wid,/append,set_value = text
return
END
; Find the value of the nth percentile in an image, based on its
; histogram. The percentile should be specified between 0 and 100.
function look_findbin, thisimage, percentile
bmin = min (thisimage)
bmax = max (thisimage)
if bmax - bmin lt 100 then begin
; Calculate bin size to create 100 bins
bins = (bmax - bmin) / 100.
endif else if bmax - bmin gt 200 then begin
; Limit number of bins to a maximum of 200
bins = (bmax - bmin) / 200.
endif else begin
bins = 1
endelse
ihist = histogram (thisimage, binsize=bins, omin=histmin, omax=histmax)
histdim = n_elements (ihist)
i = 0
cutoff = (percentile / 100.) * n_elements (thisimage)
cuttot = ihist(0)
while (cuttot lt cutoff and i lt histdim) do begin
i = i + 1
cuttot = cuttot + ihist(i)
endwhile
binval = i * bins + histmin
return, binval
end
pro look_update_scale_label, which, value
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
if which ne 0 and which ne 1 then return
if value ge 1000 then $
label = strtrim (string (value, format = '(i9)'), 2) $
else $
label = strtrim (string (value, format = '(g9.3)'), 2)
widget_control, ws.setids(which), set_value = label
end
; Update the sliders and the min/max value display windows
pro look_update_scales, minval, maxval
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
widget_control,ws.spansliders(0),set_value = minval
widget_control,ws.spansliders(1),set_value = maxval
;; widget_control,ws.setids(0),set_value = strtrim(string(minval),2)
;; widget_control,ws.setids(1),set_value = strtrim(string(maxval),2)
look_update_scale_label, 0, minval
look_update_scale_label, 1, maxval
end
;
; ============================
; =====>> Update the all and zoom displays.
; ============================
;
PRO look_update,flag
COMMON look,images,catalog,index
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
COMMON colors, r_orig, g_orig, b_orig, r_curr, g_curr, b_curr
;
; =====>> If no zoom region has been selected, show full image
; =====>> in both windows. Otherwise, add zoom and embellish full image.
;
ws.ctrange = all.tvrange ; make slider and color table ranges equal
tvlct,r_orig,g_orig,b_orig ; reset the color table
ws.zoomshown = 1
ws.fullshown = 1
all.devlast = [-1,-1] ; to omit XOR of old (now erased) crosshairs
zoom.devlast = [-1,-1]
ws.last_cutwid = -1 ; so cuts get updated
; =====>> Check input according to flag
; =====>> flag=0: no check
; =====>> flag=1: xrange/yrange --> center/width
; =====>> flag=2: center/width --> xrange/yrange
;
CASE flag OF
0:
1: BEGIN
zoom.center = [(zoom.xrange(1)+zoom.xrange(0))/2 $
,(zoom.yrange(1)+zoom.yrange(0))/2]
zoom.width = [(zoom.xrange(1)-zoom.xrange(0))+1 $
,(zoom.yrange(1)-zoom.yrange(0))+1]
END
2: BEGIN
half = -zoom.width/2
zoom.xrange = (zoom.center(0)+[half(0),(zoom.width(0)+half(0)) > 1]) $
> all.xrange(0) < all.xrange(1)
zoom.yrange = (zoom.center(1)+[half(1),(zoom.width(1)+half(1)) > 1]) $
> all.yrange(0) < all.yrange(1)
END
ENDCASE
; Create a temporary array for the zoom image
IF total(zoom.xrange-all.xrange+zoom.yrange-all.yrange) EQ 0 THEN BEGIN
widget_control,ws.reptext,set_value = ws.star+ws.report
zoomimage = thisimage ; case where zoom = full image
ENDIF else begin
zoomimage = thisimage(zoom.xrange(0):zoom.xrange(1) $
,zoom.yrange(0):zoom.yrange(1))
zoom.imrange = [min(zoomimage),max(zoomimage)]
ENDELSE
; Make the plot in the "zoom" window
wset, zoom.id ; activate the zoom window
if ws.plottype ne 0 and ws.plotfullzoom ne 1 then begin
; Special plot case. For "Full only", a special plot based on the full
; region is made in the zoom window. For "Full & Zoom", a special plot is
; made from the zoom image.
if ws.plotfullzoom eq 0 then $
look_update_special, thisimage, 'FULL' $
else $
look_update_special, zoomimage, 'ZOOM'
endif else begin
; For "Zoom only", a special plot is drawn in the full window, but the zoom
; window contains the normal image.
;; if all.scaletype eq 11 and all.scalefunc(0) ne "" then $
;; look_image,call_function(all.scalefunc(0),zoomimage) $
;; ,min=0,max=(!d.n_colors<!d.table_size)-1 $
;; ,title = 'ZOOM IMAGE',xtit = ws.units(0),ytit = ws.units(1) $
;; else if all.scaletype eq 10 then $
;; look_image,hist_equal(zoomimage) $
;; ,min=0,max=(!d.n_colors<!d.table_size)-1 $
;; ,title = 'ZOOM IMAGE',xtit = ws.units(0),ytit = ws.units(1) $
;; else $
look_image,look_scl(zoomimage,all.tvrange) $
,min=0,max=(!d.n_colors<!d.table_size)-1 $
,title = 'ZOOM IMAGE',xtit = ws.units(0),ytit = ws.units(1)
endelse
; Get zoom window coordinates and conversion factors
zoom.position = [!x.window(0),!y.window(0),!x.window(1),!y.window(1)]
; Corrected slope / intercept calculations. The conversion factors from
; look_si are not quite correct; the problem becomes more apparent with
; smaller zoom regions. look_si2 is an improved version (DSR).
;; look_si,[0,1],[0,1],slopes,intercepts
look_si2,zoom.xrange,zoom.yrange,slopes,intercepts
zoom.slopes = slopes
zoom.intercepts = intercepts
;
; =====>> Report the center and width of zoom region
;
ws.report(5) = ' x='+strtrim(zoom.center(0),2)
ws.report(6) = ' y='+strtrim(zoom.center(1),2)
z = thisimage(zoom.center(0),zoom.center(1))
IF ws.size(ws.size(0)+1) EQ 1 THEN z = long(z) ; Don't print a byte as a char.
ws.report(7) = ' z='+strtrim(z,2)
ws.report(9) = ' x='+strtrim(zoom.width(0),2)
ws.report(10) = ' y='+strtrim(zoom.width(1),2)
IF n_elements(zoomimage) GT 1 THEN begin
res = moment (zoomimage, sdev = sdev)
zoom.sd = sdev
mean = res(0)
endif ELSE BEGIN
zoom.sd = 0.
mean = 0
ENDELSE
zoom.mean = mean
ws.report(15) = ' mean='+strtrim(zoom.mean,2)
ws.report(16) = ' sd='+strtrim(zoom.sd,2)
widget_control,ws.reptext,set_value = ws.star+ws.report
;
; =====>> Renew the full image with the zoom region marked with
; =====>> a 0,1,2-pixel-wide border of contrasting values---map upper
; =====>> and lower halves of image values into each other.
; =====>> The border width depends on the image size.
;
wset,all.id ; activate the full window
tmpimage = thisimage
IF (all.x < all.y) GT 10 THEN indices = 0
IF (all.x < all.y) GT 100 THEN indices = [0,1]
IF (all.x < all.y) GT 255 THEN indices = [-1,0,1]
; If the zoom region is active, draw a box corresponding to it on top of
; the full image
IF n_elements (indices) ne 0 and $
total(zoom.xrange-all.xrange+zoom.yrange-all.yrange) NE 0 THEN begin
xmn = zoom.xrange(0)
xmx = zoom.xrange(1)
ymn = zoom.yrange(0)
ymx = zoom.yrange(1)
midrange = 0.5*(all.tvrange(1)-all.tvrange(0))
midway = all.tvrange(0)+midrange
therows = [ymn+indices,ymx+indices] < all.yrange(1) > all.yrange(0)
halfperi = tmpimage(xmn:xmx,therows)
hilo = halfperi*0-1
upper = where(halfperi LT midway)
IF upper(0) GE 0 THEN hilo(upper) = 1 ; -1(1) for >(<) midway
tmpimage(xmn:xmx,therows) = halfperi+hilo*midrange
thecols = [xmn+indices,xmx+indices] < all.xrange(1) > all.xrange(0)
halfperi = tmpimage(thecols,ymn:ymx)
hilo = halfperi*0-1
upper = where(halfperi LT midway)
IF upper(0) GE 0 THEN hilo(upper) = 1 ; -1(1) for >(<) midway
tmpimage(thecols,ymn:ymx) = halfperi+hilo*midrange
ENDIF
; Make the plot in the "full" window
if ws.plottype ne 0 and ws.plotfullzoom ne 0 then begin
; Special plot case. For "Zoom only", a special plot based on the zoom
; region is made in the full window. For "Full & Zoom", a special plot is
; made from the full image.
if ws.plotfullzoom eq 1 then $
look_update_special, zoomimage, 'ZOOM' $
else $
look_update_special, thisimage, 'FULL'
endif else begin
; For "Full only", a special plot is drawn in the zoom window, but the full
; window contains the normal image.
;; if all.scaletype eq 11 and all.scalefunc(0) ne "" then $
;; look_image,call_function(all.scalefunc(0),tmpimage) $
;; ,min=0,max=(!d.n_colors<!d.table_size)-1 $
;; ,title = 'FULL IMAGE',xtit = ws.units(0),ytit = ws.units(1) $
;; else if all.scaletype eq 10 then $
;; look_image,hist_equal(tmpimage) $
;; ,min=0,max=(!d.n_colors<!d.table_size)-1 $
;; ,title = 'FULL IMAGE',xtit = ws.units(0),ytit = ws.units(1) $
;; else $
look_image,look_scl(tmpimage,all.tvrange) $
,min=0,max=(!d.n_colors<!d.table_size)-1 $
,title = 'FULL IMAGE',xtit = ws.units(0),ytit = ws.units(1)
ENDELSE
;
; =====>> If present and toggled on, call each viewer.
;
FOR i = 0,n_elements(ws.viewers)-1 DO IF (ws.viewers(i) NE '') AND (ws.viewers_set(i) NE 0) THEN call_procedure,ws.viewers(i)
return
END
; Called by look_update to make special plots. The desired target window
; (full or zoom) should be active before calling this routine.
; "title" should be either 'FULL' or 'ZOOM'
pro look_update_special, image, title
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
case ws.plottype of
1: begin ; contour plot
si = size (image)
contour, image, nlevels = 8, title = title + ' CONTOUR', $
xrange = [0-0.5,si(1)-0.5], $
yrange = [0-0.5,si(2)-0.5], xstyle = 1, ystyle = 1
end
2: begin ; histogram
plot, title = title + ' HISTOGRAM', histogram(float(image), $
binsize = (float(all.tvrange(1))-all.tvrange(0))/(all.x < 100))
end
3: begin ; surface
surface, title = title + ' SURFACE', $
congrid(look_scl(image,all.tvrange),all.x < ws.mxd,all.y < ws.mxd)
end
4: begin ; shade_surf
shade_surf, title = title + ' SHADE_SURF', $
congrid(look_scl(image,all.tvrange),all.x < ws.mxd,all.y < ws.mxd)
end
5: begin ; show3
show3, $
congrid(look_scl(image,all.tvrange),all.x < ws.mxd,all.y < ws.mxd)
end
6: begin ; tvscl
erase
tvscl, look_scl(image,all.tvrange)
end
endcase
end
; ============================
; =====>> Set PS attributes
; ============================
;
PRO look_PSatt
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
parent = widget_base(/column,title = 'Choose PS attributes')
row = widget_base(parent,/row,/nonexclusive)
tmp = widget_button(row,value = 'DONE',uvalue = 'DONE')
tags = strupcase(tag_names(ws.PSatt))
w = where(tags NE 'BITS') ; save bits/pixel for next row of widgets
FOR i = 0,n_elements(w)-1 DO BEGIN
tmp = widget_button(row,value = '/'+tags(w(i)),uvalue = tags(w(i)))
widget_control,tmp,set_button = ws.PSatt.(w(i))
ENDFOR
row = widget_base(parent,/row)
bopt = ['1','2','4','8']
tmp = (where(ws.PSatt.bits EQ bopt))(0) > 0
tmp = cw_bselector(row,bopt,uvalue = 'BITS',label_left = 'Bits/pixel',set_value = tmp)
tmp = widget_button(row,value = 'New file',uvalue = 'PSFILENAME')
PSfileID = widget_text(row,/scroll,value = 'Current: '+ws.PSfilename)
widget_control,parent,/realize
;
; =====>> Get and Process Events Using uvalue's Until Done
;
MORE:
ev = widget_event(parent,/nowait)
IF ev.id EQ 0 THEN GOTO,MORE
widget_control,ev.id,get_uvalue = uvalue
CASE 1 OF
uvalue EQ 'BITS': ws.PSatt.bits = bopt(ev.value)
uvalue EQ 'DONE': BEGIN
widget_control,parent,/destroy
ws.PSattstr = ''
tags = tag_names(ws.PSatt)
FOR i = 0,n_tags(ws.PSatt)-1 DO BEGIN
ws.PSattstr = ws.PSattstr+','+tags(i)+'='+strtrim(ws.PSatt.(i),2)
ENDFOR
return
END
uvalue EQ 'PSFILENAME': BEGIN
ws.PSfilename = pickfile(file = ws.PSfilename,filter = '*.ps',/write)
widget_control,PSfileID,set_value = 'Current: '+ws.PSfilename
END
ELSE: stat = execute('ws.PSatt.'+uvalue+' = ev.select')
ENDCASE
GOTO,MORE
END
;
; ============================
; =====>> DO THE OPTIONAL PLOTS (called from look_event)
; ============================
;
PRO look_optmenu,uvalue,ev
; uvalue = uvalue from event
; ev = event structure
COMMON look,images,catalog,index
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
COMMON colors, r_orig, g_orig, b_orig, r_curr, g_curr, b_curr
;
; =====>> Choose number of plots: full or zoom or both
;
IF ws.plotfullzoom EQ 2 THEN nplots = 2 ELSE nplots = 1
IF uvalue EQ 'movie' AND (nplots EQ 2) THEN BEGIN
widget_control,ws.comtext,/append,set_value = $
'Movie mode requires only full or zoom---not both. Using full.'
nplots = 1
ENDIF
;
; =====>> Loop over the 1 or 2 plots.
;
id = [[zoom.id,all.id,all.id],[0,0,zoom.id]]
wid = [[zoom.wid,all.wid,all.wid],[0,0,zoom.wid]]
titles = [['FULL','ZOOM','FULL'],['','','ZOOM']]+' '
catalog_or_movie_or_blink = $
(uvalue EQ 'cat to screen') OR (uvalue EQ 'cat to window') $ ; catalog
OR (uvalue EQ 'movie') $ ; movie
OR (uvalue EQ 'blink to screen') OR (uvalue EQ 'blink to window') ; blink
FOR n = 0,nplots-1 DO BEGIN
wset,id(ws.plotfullzoom,n)
title = titles(ws.plotfullzoom,n)
dofull = strpos(title,'FULL') GE 0
IF id(ws.plotfullzoom,n) EQ zoom.id THEN ws.zoomshown = 0
IF id(ws.plotfullzoom,n) EQ all.id THEN ws.fullshown = 0
IF (n EQ 1) OR (ws.plotfullzoom EQ 1) THEN image = zoomimage ELSE image = thisimage
device,get_screen_size = scrdims
si = size(image)
wherecust = where (all.scalefunc eq uvalue, wherecount)
CASE 1 OF
uvalue EQ 'All Four Windows': BEGIN
wset,all.hcutid ; Get ready to read one draw window's data.
one = tvrd() ; Read one image; all others are same size.
szt = size(one) ; Make array for all four: 2 plots & 2 images
tmp = make_array(size = [2,szt(1:2)*2,szt(3),szt(4)*4])
x = szt(1) ; shorthand
y = szt(2) ; ditto
tmp(0:x-1,y:*) = one ; Place the horizontal cut plot, as an image.
wset,zoom.id ; Move to zoom window.
tmp(x:*,y:*) = tvrd() ; Place it as an image in the upper right.
wset,all.id ; Move to full window.
tmp(0:x-1,0:y-1) = tvrd() ; Place it as an image in the lower left.
wset,all.vcutid ; Move to full vcut window.
tmp(x:*,0:y-1) = tvrd() ; Place it as an image in the lower right.
look_put,tmp,1,1,filename = ws.PSfilename ; Output the entire array.
END
catalog_or_movie_or_blink: BEGIN
to_screen = strpos(uvalue,'to screen') GE 0
IF to_screen THEN BEGIN
bigbase = widget_base(title = title+' (To exit, kill window.)' $
,/row,group = ev.top)
bigdraw = widget_draw(bigbase $
,xsize = si(1)*((scrdims(0)-25)/si(1)) $
,ysize = si(2)*((scrdims(1)-25)/si(2)))
widget_control,/realize,bigbase
widget_control,get_value = bigid,bigdraw
wset,bigid
tvlct, r_orig, g_orig, b_orig ; update color table
look_catalog,uvalue,dofull,bigid
widget_control,bigbase,/destroy
ENDIF ELSE BEGIN
look_catalog,uvalue,dofull,wid(ws.plotfullzoom,n)
ENDELSE
END
uvalue EQ 'contour': BEGIN
;; contour,image,nlevels = 8,title = title+'CONTOUR'
ws.plottype = 1
look_update, 0
END
uvalue EQ 'full screen': BEGIN
times = (scrdims(0)/si(1)) < (scrdims(1)/si(2))
IF times EQ 0 THEN BEGIN
slide_image,look_scl(image,all.tvrange)
ENDIF ELSE BEGIN
bigbase = widget_base(title = title+strtrim(times,2)+ $
'X enlargement (To exit, kill window.)' $
,/row,group = ev.top)
bigdraw = widget_draw(bigbase,xsize = si(1)*times,ysize = si(2)*times)
widget_control,/realize,bigbase
widget_control,get_value = bigid,bigdraw
wset,bigid
tvlct, r_orig, g_orig, b_orig ; update via changing the color table
look_exptv,look_scl(rebin(image,si(1)*times,si(2)*times,/sample),all.tvrange)
ENDELSE
END
uvalue EQ 'full window': look_exptv,look_scl(image,all.tvrange),min=0,max=(!d.n_colors<!d.table_size)-1
uvalue EQ 'Full Window Only': BEGIN
wset,all.id
look_put,tvrd(),1,1,file = ws.PSfilename
END
uvalue EQ 'histogram': BEGIN
;; plot,title = title+'HISTOGRAM',histogram(float(image) $
;; ,binsize = (float(all.tvrange(1))-all.tvrange(0))/(all.x < 100))
ws.plottype = 2
look_update, 0
END
uvalue EQ 'Laplacian': BEGIN
IF dofull THEN thisimage = convol(thisimage,[[0,-1,0],[-1,4,-1],[0,-1,0]])
look_update,0
END
uvalue EQ 'leefilt': BEGIN
IF dofull THEN thisimage = leefilt(thisimage,ws.kernel_width)
look_update,0
END
uvalue EQ 'look_image': BEGIN
;; look_image,title = title+'IMAGE',min=0,max=(!d.n_colors<!d.table_size)-1 $
;; ,look_scl(image,all.tvrange),xtit = ws.units(0),ytit = ws.units(1)
ws.plottype = 0
look_update, 0
END
uvalue EQ 'median': BEGIN
IF dofull THEN thisimage = median(thisimage,ws.kernel_width)
look_update,0
END
uvalue EQ 'region of interest': BEGIN
look_exptv,look_scl(image,all.tvrange),zoom = z_xy,offset = offset
blink0 = look_scl(image,all.tvrange)
blink1 = blink0
min = min(image)
sp = look_defroi(wid(ws.plotfullzoom,n),zoom = z_xy,offset = offset $
,size = (size(image))(1:2),image = blink0)
widget_control,/hourglass
bg = look_unique(lindgen(n_elements(image)),sp)
look_print_stats,sp,image,'inside',ws.comtext
look_print_stats,bg,image,'outside',ws.comtext
IF bg(0) NE -1 THEN blink0(bg) = min
IF sp(0) NE -1 THEN blink1(sp) = min
look_exptv,blink0,zoom = z_xy,offset = offset,image = blink0
look_exptv,blink1,zoom = z_xy,offset = offset,image = blink1
look_blink,blink0,blink1,wid(ws.plotfullzoom,n)
END
uvalue EQ 'Set PS attributes': look_PSatt
uvalue EQ 'shade_surf': BEGIN
;; shade_surf,title = title+'SHADE_SURF' $
;; ,congrid(look_scl(image,all.tvrange),all.x < ws.mxd,all.y < ws.mxd)
ws.plottype = 4
look_update, 0
END
uvalue EQ 'show3': BEGIN
;; show3 $
;; ,congrid(look_scl(image,all.tvrange),all.x < ws.mxd,all.y < ws.mxd)
ws.plottype = 5
look_update, 0
END
uvalue EQ 'smooth': BEGIN
IF dofull THEN thisimage = smooth(thisimage,ws.kernel_width)
look_update,0
END
uvalue EQ 'surface': BEGIN
;; surface,title = title+'SURFACE' $
;; ,congrid(look_scl(image,all.tvrange),all.x < ws.mxd,all.y < ws.mxd)
ws.plottype = 3
look_update, 0
END
uvalue EQ 'tvscl': BEGIN
;; tvscl,look_scl(image,all.tvrange)
ws.plottype = 6
look_update, 0
END
uvalue EQ 'type image': look_xdisplay,image,title = title
strpos(uvalue,'-->on/all mouse') GT 0: BEGIN
w = ((where(ws.viewers+'-->on/all mouse' EQ uvalue)))(0)
IF w GT -1 THEN BEGIN
IF ws.viewers_set(w) EQ 0 THEN call_procedure,ws.viewers(w),/create
ws.viewers_set(w) = 2 ; toggle on for all mouse events
ENDIF
END
strpos(uvalue,'-->on/click only') GT 0: BEGIN
w = ((where(ws.viewers+'-->on/click only' EQ uvalue)))(0)
IF w GT -1 THEN BEGIN
IF ws.viewers_set(w) EQ 0 THEN call_procedure,ws.viewers(w),/create
ws.viewers_set(w) = 1 ; toggle on for mouse clicks only
ENDIF
END
strpos(uvalue,'-->off') GT 0: BEGIN
w = ((where(ws.viewers+'-->off' EQ uvalue)))(0)
IF w GT -1 THEN BEGIN
IF ws.viewers_set(w) NE 0 THEN call_procedure,ws.viewers(w),/destroy
ws.viewers_set(w) = 0 ; toggle off
ENDIF
END
uvalue EQ 'xloadct': xloadct
uvalue EQ 'Zoom Window Only': BEGIN
wset,zoom.id
look_put,tvrd(),1,1,file = ws.PSfilename
END
; Auto-scaling cases
uvalue EQ 'All data': begin
all.scaletype = 1
look_auto_minmax
look_update, 0
end
uvalue EQ 'Omit top / bottom 5%': begin
all.scaletype = 2
look_auto_minmax
look_update, 0
end
uvalue EQ 'Omit top / bottom 10%': begin
all.scaletype = 3
look_auto_minmax
look_update, 0
end
uvalue EQ 'Mean +/- 1 sigma': begin
all.scaletype = 4
look_auto_minmax
look_update, 0
end
uvalue EQ 'Mean +/- 2 sigma': begin
all.scaletype = 5
look_auto_minmax
look_update, 0
end
uvalue EQ 'Mean +/- 3 sigma': begin
all.scaletype = 6
look_auto_minmax
look_update, 0
end
uvalue EQ 'Median +/- 1 sigma': begin
all.scaletype = 7
look_auto_minmax
look_update, 0
end
uvalue EQ 'Median +/- 2 sigma': begin
all.scaletype = 8
look_auto_minmax
look_update, 0
end
uvalue EQ 'Median +/- 3 sigma': begin
all.scaletype = 9
look_auto_minmax
look_update, 0
end
uvalue EQ 'hist_equal': begin
all.scaletype = 10
look_auto_minmax
look_update, 0
end
;; uvalue EQ 'Custom': begin
wherecount gt 0: begin
all.scaletype = 11 + wherecust(0)
look_auto_minmax
look_update, 0
end
ELSE: BEGIN
IF ws.ispro(where(ws.optmenu.name EQ uvalue)) THEN BEGIN
call_procedure,uvalue,look_scl(image,all.tvrange)
ENDIF ELSE BEGIN
IF dofull THEN thisimage = call_function(uvalue,thisimage)
look_update,0
ENDELSE
END
ENDCASE
ENDFOR
return
END
;
; ============================
; =====>> Update the images after slider events or increments.
; ============================
;
FUNCTION look_span_update,value,j
; value = new value of the tvrange(j) for all and zoom
; j = which value, minimum (j=0) or maximum (j=1) to update
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
; mini = lower bounds for all and zoom
; maxi = upper bounds for all and zoom
IF j EQ 0 THEN BEGIN
mini = [all.tvrange(1),zoom.tvrange(1)]
maxi = [ws.srange(0),ws.srange(0)]
ENDIF ELSE BEGIN
mini = [ws.srange(1),ws.srange(1)]
maxi = [all.tvrange(0),zoom.tvrange(0)]
ENDELSE
save = [all.tvrange(j),zoom.tvrange(j)]
all.tvrange(j) = value < mini(0) > maxi(0)
zoom.tvrange(j) = value < mini(1) > maxi(1)
widget_control,ws.spansliders(j),set_value = all.tvrange(j)
IF ws.spanmode(j) NE 1 THEN ws.manrange(j) = all.tvrange(j)
;;widget_control,ws.setids(j),set_value = strtrim(all.tvrange(j),2)
look_update_scale_label, j, all.tvrange(j)
different = (save(0) NE all.tvrange(j)) OR (save(1) NE zoom.tvrange(j))
IF NOT different THEN return,0
;
; =====>> If possible, alter color table to save time.
;
COMMON colors, r_orig, g_orig, b_orig, r_curr, g_curr, b_curr
ctr = ws.ctrange ; just a shorthand
tvr = all.tvrange ; ditto
outside = (ctr(0) GT tvr(0)) OR (ctr(1) LT tvr(1))
ctspan = float(ctr(1)-ctr(0))
IF ctspan GT 0. THEN $
toosmall = ((tvr(1)-tvr(0))/ctspan) LT 0.1 ELSE toosmall = 1
; return whether either one of the values has changed
;IF ws.debug THEN widget_control,ws.comtext,/append $
; ,set_value = string([ctr,tvr,outside,toosmall],form = '(4f10.2,2i3)')
IF outside OR toosmall THEN return,different
nc = !d.n_colors < !d.table_size ; was !d.n_colors(=2^24 on true color devices)
n1 = (nc*(tvr(1)-ctr(0))/ctspan) < (nc-1) ; # of colors to set to nc-1
n0 = (nc*(tvr(0)-ctr(0))/ctspan) < n1 ; # of colors to set to 0
s = 0.*r_orig ; array of color table indices
IF n1 GT n0 THEN s(n0) = findgen(n1-n0)*nc/(n1-n0) ; ramp spanning color table
s(n1:*) = float(nc-1) ; indices set to top color index
r_curr = r_orig(s)
g_curr = g_orig(s)
b_curr = b_orig(s)
tvlct, r_curr, g_curr, b_curr ; update via changing the color table
; Changed 052097, DSR: unset ws.cut_oplot to force update of cut windows,
; but leave ws.last_cutwid alone so the existing crosshairs will be erased
;;ws.last_cutwid = -1 ; so cuts get updated
ws.cut_oplot = 0 ; flag to update cut plots
return,0 ; don't update images
END
;
; ============================
; =====>> Check for coordinates in range
; ============================
;
FUNCTION look_in_range,t,x,y
return,(t(0) GE x(0)) AND (t(0) LE x(1)) AND (t(1) GE y(0)) AND (t(1) LE y(1))
END
; Determine the min and max data values to map to the color range,
; depending on the autoscale option
; Options:
; no_update Don't update the scales
; newrange Optionally return the newly calculated extrema
; scaleto Image to use to determine limits (optional - if omitted,
; either the full or zoom image is used)
; nobound Don't limit min and max to slider limits
pro look_auto_minmax, newrange = imagerange, no_update = no_update, $
scaleto = scaleto, no_bound = no_bound
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
; Reset displayed image in case hist_equal or custom scaling were used
thisimage = fullimage
; If set to "Full only" or "Full & Zoom", scale to full image; otherwise,
; scale only to the zoom image
if n_elements (scaleto) ne 0 then $
useimage = scaleto $
else if ws.plotfullzoom eq 0 or ws.plotfullzoom eq 2 then $
useimage = thisimage $
else $
useimage = zoomimage
; Find the mean and standard deviation, if needed
if all.scaletype ge 4 and all.scaletype le 9 then $
thismom = moment (useimage, sdev=thisdev)
; Find the median, if needed
if all.scaletype ge 7 and all.scaletype le 9 then $
thismed = median (useimage)
case all.scaletype of
1: begin ; all data
imagerange = [min (useimage), max (useimage)]
end
2: begin ; eliminate top / bottom 5%
imin = look_findbin (useimage, 5)
imax = look_findbin (useimage, 95)
imagerange = [imin, imax]
end
3: begin ; eliminate top / bottom 10%
imin = look_findbin (useimage, 10)
imax = look_findbin (useimage, 90)
imagerange = [imin, imax]
end
4: begin ; mean +/- 1 sigma
imin = thismom(0) - all.meansig(0) * thisdev
imax = thismom(0) + all.meansig(0) * thisdev
imagerange = [imin, imax]
end
5: begin ; mean +/- 2 sigma
imin = thismom(0) - all.meansig(1) * thisdev
imax = thismom(0) + all.meansig(1) * thisdev
imagerange = [imin, imax]
end
6: begin ; mean +/- 3 sigma
imin = thismom(0) - all.meansig(2) * thisdev
imax = thismom(0) + all.meansig(2) * thisdev
imagerange = [imin, imax]
end
7: begin ; median +/- 1 sigma
imin = thismed - all.mediansig(0) * thisdev
imax = thismed + all.mediansig(0) * thisdev
imagerange = [imin, imax]
end
8: begin ; median +/- 2 sigma
imin = thismed - all.mediansig(1) * thisdev
imax = thismed + all.mediansig(1) * thisdev
imagerange = [imin, imax]
end
9: begin ; median +/- 3 sigma
imin = thismed - all.mediansig(2) * thisdev
imax = thismed + all.mediansig(2) * thisdev
imagerange = [imin, imax]
end
else: begin ; hist_equal, custom scaling functions
thisimage = look_apply_scalefunc (fullimage)
look_reset_sliders, thisimage
zoomimage = look_apply_scalefunc (zoomimage)
imagerange = [min (thisimage), max (thisimage)]
end
endcase
; Check to prevent exceeding the slider limits
if not keyword_set (no_bound) then $
imagerange = imagerange > ws.srange(0) < ws.srange(1)
; For fixed slider cases, don't use auto value determined above
if ws.spanmode(0) eq 0 then imagerange(0) = ws.manrange(0) ; Min slider
if ws.spanmode(1) eq 0 then imagerange(1) = ws.manrange(1) ; Max slider
if not keyword_set (no_update) then begin
look_update_scales, imagerange(0), imagerange(1)
i = look_span_update (imagerange(0), 0)
i = look_span_update (imagerange(1), 1)
endif
end
;
; ============================
; =====>> EVENT HANDLER
; ============================
;
PRO look_event,ev
COMMON look,images,catalog,index
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
;
; =====>> Get value and uvalue for event.
;
IF (where(tag_names(ev) EQ 'VALUE'))(0) EQ -1 THEN BEGIN
widget_control,ev.id,get_uvalue = uvalue,get_value = value
value = value(0) ; make a scalar
ENDIF ELSE BEGIN
widget_control,ev.id,get_uvalue = uvalue
value = ev.value
ENDELSE
IF n_elements(uvalue) EQ 0 THEN uvalue = '' ; shouldn't happen
IF ws.debug THEN widget_control,ws.comtext,/append $
,set_value = strtrim(uvalue,2) $
+' '+strtrim(value,2)+' '+strtrim(ev.id,2)+' '+strtrim(ev.top,2) $
+' '+strtrim(ev.handler,2)
;
; =====>> Treat different ids in a variety of ways.
; =====>> Do most of the widgets in a big case statement.
; =====>> Choose image, cut sliders, autoscale, and draw widget events.
;
; =====>> PROCESS THE EVENT USING A CASE STATEMENT ON THE UVALUE
; =====>> But treat tv and zoom separately
;
CASE 1 OF
strpos(uvalue,'apply') EQ 0: BEGIN
widget_control,ws.spanmagid,get_value = mag
IF strpos(uvalue,'+') GE 0 THEN sign = 1 ELSE sign = -1
IF ws.debug THEN widget_control $
,ws.comtext,/append,set_value = uvalue+' '+mag(0)+string(sign)
mag = sign*float(mag(0))
domin = (strpos(uvalue,'min') GE 0) OR (strpos(uvalue,'both') GE 0)
domax = (strpos(uvalue,'max') GE 0) OR (strpos(uvalue,'both') GE 0)
IF domin THEN domin = look_span_update(all.tvrange(0)+mag,0)
IF domax THEN domax = look_span_update(all.tvrange(1)+mag,1)
IF domin OR domax THEN look_update,0
END
uvalue eq 'bothfix?': BEGIN
text = ['Auto','Fix']
widget_control,ws.bothfixid,get_value = now
ws.bothfix = now NE text(1) ; toggle index in text array
widget_control,ws.bothfixid,set_value = text(ws.bothfix)
END
uvalue eq 'spanmin': IF look_span_update(value,0) THEN look_update,0
uvalue eq 'spanmax': IF look_span_update(value,1) THEN look_update,0
strpos(uvalue,'dim') GE 0: BEGIN
dim = fix(strmid(uvalue,3,1))-1 ; dim3->2, dim4->3, ..., dim7->6
; widget_control,ws.comtext,/append,set_value = uvalue+' '+strtrim(dim,2)
current = ws.d(dim) ; save current value
CASE strmid(uvalue,4,1) OF
'I': BEGIN
sign = 2*(strmid(uvalue,5,1) EQ '+')-1 ; 1-->1 & 0-->-1
widget_control,ws.dimid(1,dim-2),get_value = curdim
widget_control,ws.dimid(3,dim-2),get_value = curincr
ws.d(dim) = (long(curdim)+sign*long(curincr))
END
'p': BEGIN ; pull-down menu chosen
colon = strpos(value,':') ; assume 'previous' selected if no colon
IF colon EQ -1 THEN ws.d(dim) = ws.previous(dim) ELSE ws.d(dim) = long(strmid(value,0,colon))
; widget_control,ws.comtext,/append,set_value = string(value)+' '+strmid(value,0,colon)
END
ELSE: BEGIN
widget_control,ws.dimid(1,dim-2),get_value = curdim
ws.d(dim) = long(curdim)
END
ENDCASE
ws.previous(dim) = current ; save the old value as previous
ws.d(dim) = ws.d(dim) > 0 < (ws.size(dim+1)-1) ; restrict to allowed range
widget_control,ws.dimid(1,dim-2),set_value = strtrim(ws.d(dim),2) ; set new value
END
uvalue eq 'donebutton': BEGIN
widget_control,ev.top,/destroy
return
END
uvalue eq 'helpbutton': BEGIN
path = expand_path(!PATH,/array,count=count) ;GGA
file = ''
i = -1 ;GGA
REPEAT BEGIN
i = i+1
; Fix made here (DSR)
file = findfile(filepath(root_dir = path(i),'look.pro'))
END UNTIL file(0) ne '' or i eq count-1 ;GGA
if file(0) eq '' then BEGIN
widget_control,ws.comtext,set_value = 'No look.pro in !path',/append
ENDIF ELSE BEGIN
line = '' ; read buffer
openr,lun,/get_lun,file(0)
l = 0 ; line counter
WHILE NOT eof(lun) DO BEGIN
readf,lun,line
IF strpos(line,';-') EQ 0 THEN GOTO,NEXT
l = l+1 ; increment counter
ENDWHILE
NEXT:
device,get_scr = xyscr
buf = strarr(l)
point_lun,lun,0
FOR i = 0,l-1 DO BEGIN
readf,lun,line
buf(i) = line
ENDFOR
close,lun
free_lun,lun
; Fix made here (DSR)
;; look_xdisplay,ws.help.message,buf,ysize = 14.*(xyscr(1)/640.) $
look_xdisplay,ws.help.v+': '+ws.help.message,buf,ysize = 14.*(xyscr(1)/640.) $
,titles = ['One-line messages about widgets','Output from doc_library']
ENDELSE
END
uvalue eq 'starslide': ws.increment = value
uvalue eq 'kslider': ws.kernel_width = value
uvalue eq 'optpdmenu': look_optmenu,value,ev ; value is name of the button
uvalue eq 'plotfullorzoom?': BEGIN
ws.plotfullzoom = (ws.plotfullzoom + 1) MOD 3
widget_control,ws.fullzoombutton,set_value = ws.fullzoom(ws.plotfullzoom)
END
uvalue eq 'starpdmenu': BEGIN
ws.star = ' ' ; reset all to blanks
ws.star(ws.starlookup(value-1)) = '*' ; set selection to star
widget_control,ws.reptext,set_value = ws.star+ws.report
END
ELSE:
ENDCASE
;
; =====>> Respond to toggle of Auto Scale/Fix Slider button
;
IF (strpos(uvalue,'auto') GE 0) OR (strpos(uvalue,'set') GE 0) THEN BEGIN
tittype = ['Min','Max']
j = strpos(uvalue,'max') GE 0 ; 0(1) for 'minauto'('maxauto')
IF (strpos(uvalue,'set') GE 0) THEN ws.spanmode(j) = 0 ELSE $
ws.spanmode(j) = (ws.spanmode(j)+1) MOD 2
CASE ws.spanmode(j) OF
0: BEGIN
widget_control,ws.autoscale(j),set_value = 'FixSlide'
widget_control,ws.setids(j),get_value = mag
ws.manrange(j) = float(mag(0))
all.tvrange(j) = ws.manrange(j)
zoom.tvrange(j) = ws.manrange(j)
widget_control,ws.spansliders(j),set_value = all.tvrange(j)
END
1: BEGIN
widget_control,ws.autoscale(j),set_value = 'Auto '+tittype(j)
; Use min or max from currently selected autoscale option
look_auto_minmax, newrange = newlimits, /no_update
all.tvrange(j) = newlimits(j)
;; all.tvrange(j) = all.imrange(j)
zoom.tvrange(j) = newlimits(j)
;; zoom.tvrange(j) = zoom.imrange(j)
widget_control,ws.spansliders(j),set_value = all.tvrange(j)
;; widget_control,ws.setids(j),set_value = strtrim(all.tvrange(j),2)
look_update_scale_label, j, all.tvrange(j)
END
ENDCASE
look_update,0
ENDIF
;
; =====>> Get new image if requested.
;
IF (uvalue EQ 'restorebutton') OR (strpos(uvalue,'dim') EQ 0) THEN BEGIN
;; thisimage = look_get_image(ws.d(2:6),ws)
thisimage = look_get_image(ws.d(2:6),ws)
fullimage = thisimage
all.tvrange = [min(thisimage),max(thisimage)] > ws.srange(0) < ws.srange(1)
all.imrange = all.tvrange
look_auto_minmax, newrange = newlimits, /no_update
FOR j = 0,1 DO BEGIN
CASE ws.spanmode(j) OF
0: all.tvrange(j) = ws.manrange(j) ; FixSlide
1: all.tvrange(j) = newlimits(j) ; AutoScale (DSR)
ELSE:
ENDCASE
widget_control,ws.spansliders(j),set_value = all.tvrange(j)
;; widget_control,ws.setids(j),set_value = strtrim(all.tvrange(j),2)
look_update_scale_label, j, all.tvrange(j)
ENDFOR
zoom.tvrange = all.tvrange
zoom.imrange = zoom.tvrange
IF n_elements(thisimage) GT 1 THEN begin
res = moment (thisimage, sdev = sdev)
all.sd = sdev
mean = res(0)
endif ELSE BEGIN
all.sd = 0.
mean = 0
ENDELSE
all.mean = mean
ws.report(12) = ' mean='+strtrim(all.mean,2)
ws.report(13) = ' sd='+strtrim(all.sd,2)
look_update,0
; Clear the horizontal and vertical cut windows (they are from the
; previous frame)
wset,all.vcutid ; Activate the vertical cut window
erase ; Clear the vertical cut window
wset,all.hcutid ; Activate the horizontal cut window
erase ; Clear the horizontal cut window
wset,all.id ; Reset the active window
all.datlast(0) = -1 ; Invalidate the saved X coordinate
all.datlast(1) = -1 ; Invalidate the saved Y coordinate
zoom.datlast(0) = -1 ; Invalidate the saved X coordinate
zoom.datlast(1) = -1 ; Invalidate the saved Y coordinate
ENDIF
;
; =====>> Process the tv mouse events.
; =====>> (8 tags from draw widget events) ;GGA
; 9 tags in version 5 (DSR)
;
IF (uvalue EQ 'alldraw') AND (n_tags(ev) GE 8) THEN BEGIN
CASE 1 OF ; left mouse click/drag
(ev.press EQ 1): BEGIN
ws.drag(0) = 1 ; button is now down
ws.dragstart = [ev.x,ev.y] ; device coordinates at start of drag
ws.dragcorner = ws.dragstart ; device coordinates during drag
t = look_cc(ws.dragstart,all.slopes,all.intercepts)
; Addition to disallow zoom selection on special plots
if (ws.plottype eq 0 or ws.plotfullzoom eq 0) and $
look_in_range(t,all.xrange,all.yrange) THEN BEGIN
all.down(*,0) = t
wset,all.id
device,set_graphics = 6
yl = all.devlast(1) ; First erase the crosshairs
IF yl GE 0 THEN plots,[0,!d.x_size],[yl,yl],/dev
xl = all.devlast(0)
IF xl GE 0 THEN plots,[xl,xl],[0,!d.y_size],/dev
device,set_graphics = 3
all.devlast = [-1,-1]
ENDIF
END
(ev.release EQ 1): BEGIN
ws.drag(0) = 0 ; button is now up
ws.dragcorner = [-1,-1] ; reset drag corner
t = look_cc([ev.x,ev.y],all.slopes,all.intercepts)
; Addition to disallow zoom selection on special plots
if (ws.plottype eq 0 or ws.plotfullzoom eq 0) and $
look_in_range(t,all.xrange,all.yrange) THEN BEGIN
all.up(*,0) = t
all.devlast = -1 ; to avoid generating crosshairs in next look_cut
zoom.devlast = -1 ; to avoid generating crosshairs in next look_cut
zoom.xrange = [(all.down(0,0)<all.up(0,0)) < (all.xrange(1)-2) $
,all.down(0,0)>all.up(0,0)] > all.xrange(0)
zoom.xrange(1) = zoom.xrange(1) > (zoom.xrange(0)+2) < all.xrange(1)
zoom.yrange = [(all.down(1,0)<all.up(1,0)) < (all.yrange(1)-2) $
,all.down(1,0)>all.up(1,0)] > all.yrange(0)
zoom.yrange(1) = zoom.yrange(1) > (zoom.yrange(0)+2) < all.yrange(1)
; Reset the plot type if necessary, so the zoom window will show the
; newly selected zoom region
if ws.plottype ne 0 then ws.plottype = 0
look_update,1 ; xrange/yrange --> center/width
ENDIF
END
(ev.press EQ 0) AND (ev.release EQ 0): BEGIN ; motion event
; Addition to disallow zoom selection on special plots
if (ws.plottype eq 0 or ws.plotfullzoom eq 0) and $
ws.drag(0) THEN BEGIN
IF ws.debug THEN widget_control,ws.comtext,/append $
,set_value = string(uvalue+' motion') $
+string([ws.drag(0),ws.dragstart,ws.dragcorner],format = '(8i5)')
q = ws.dragstart ; start of drag
r = ws.dragcorner ; last drag corner
wset,all.id
device,set_graphics = 6
IF total(r) GE 0 THEN $ ; to erase last drag box, if it's there.
plots,[q(0),r(0),r(0),q(0),q(0)],[q(1),q(1),r(1),r(1),q(1)],/dev
; Then add new drag box
ws.dragcorner = [ev.x,ev.y]
r = ws.dragcorner
plots,[q(0),r(0),r(0),q(0),q(0)],[q(1),q(1),r(1),r(1),q(1)],/dev
device,set_graphics = 3
ENDIF ELSE IF ws.fullshown THEN look_cut,all,ev.x,ev.y,docrosshairs = 1-ws.drag(0)
;
; =====>> If present and toggled on, call each viewer.
;
FOR i = 0,n_elements(ws.viewers)-1 DO IF (ws.viewers(i) NE '') AND (ws.viewers_set(i) EQ 2) THEN call_procedure,ws.viewers(i)
END
(ev.press EQ 2): ; middle mouse click
(ev.release EQ 2): BEGIN
ws.drag(1) = 0 ; button is now up
t = look_cc([ev.x,ev.y],all.slopes,all.intercepts)
IF look_in_range(t,all.xrange,all.yrange) THEN BEGIN
zoom.center = t
all.devlast = -1 ; to avoid generating crosshairs in next look_cut
zoom.width = zoom.width > 2 < ((t < (all.max-t))*2)
look_update,2 ; center/width --> xrange/yrange
ENDIF
END
(ev.press EQ 4): ; right mouse click
(ev.release EQ 4): BEGIN
ws.drag(2) = 0 ; button is now up
all.devlast = -1 ; to avoid generating crosshairs in next look_cut
del = ws.increment
CASE (where(ws.star EQ '*'))(0) OF
5: zoom.center(0) = (zoom.center(0)+del) > all.xrange(0) < all.xrange(1)
6: zoom.center(1) = (zoom.center(1)+del) > all.yrange(0) < all.yrange(1)
9: zoom.width(0) = ((zoom.width(0)+del) > 1) > all.xrange(0) < all.xrange(1)
10: zoom.width(1) = ((zoom.width(1)+del) > 1) > all.yrange(0) < all.yrange(1)
ELSE:
ENDCASE
look_update,2
END
ELSE:
ENDCASE
ENDIF
;
; =====>> Motion event in zoom window
;
IF (uvalue EQ 'zoomdraw') AND (n_tags(ev) GE 8) AND ws.zoomshown THEN $
IF (ev.press EQ 0) AND (ev.release EQ 0) THEN look_cut,zoom,ev.x,ev.y,/docrosshairs
END ; of look_event
;
; ============================
; =====>> INITIALIZING ROUTINE
; ============================
;
PRO look,input,help=help,verbose = verbose,noload = noload $
,range = inputrange,associate = associate,tag = tag $
,dimensions = dimens,axes = axes $
,filename = filename,definition = definition,offset = offset $
,loader_name = loader_name,lines = comlines $
,options = options,procedures = procedures,functions = functions $
,types = types,kernel_width = kernel_width,on_error = on_error $
,debug = debug,_extra = extra, userscalefunc = userscalefunc $
,usermean = usermean, usermedian = usermedian $
,units = units $
,dim3marks = dim3marks,dim4marks = dim4marks,dim5marks = dim5marks $
,dim6marks = dim6marks,dim7marks = dim7marks $
,viewers = viewers
COMMON look,images,catalog,index
COMMON look_common,thisimage,zoomimage,fullimage,ws,all,zoom
COMMON colors, r_orig, g_orig, b_orig, r_curr, g_curr, b_curr
;
; =====>> HELP
;
IF keyword_set(help) THEN BEGIN
doc_library,'look'
return
ENDIF
;
; =====>> Set Defaults: internal parameters
;
IF n_elements(on_error) EQ 0 THEN on_error,2 ELSE on_error,on_error
IF !d.name NE 'X' THEN BEGIN
message,/inform,"Incorrect device:'+!d.name+'. Try set_plot,'X'"
return
ENDIF
versdate = '14 Mar 00'
maxsurfdim = 50
IF n_elements(r_orig) EQ 0 THEN loadct,0 ; in case no previous call to loadct
IF n_elements(associate) EQ 0 THEN associate = 0
IF n_elements(comlines) EQ 0 THEN comlines = 2
IF n_elements(debug) EQ 0 THEN debug = 0
IF n_elements(kernel_width) EQ 0 THEN kernel_width = 3
have_func = n_elements(loader_name) EQ 1
IF NOT have_func THEN loader_name = ''
IF n_elements(offset) EQ 0 THEN offset = 0
CASE n_elements(units) OF
0: units = ['x (pixels)','y (pixels)','z (value)']
1: units = [strtrim(units(0),2),'y (pixels)','z (value)']
2: units = [strtrim(units(0),2),strtrim(units(1),2),'z (value)']
ELSE:units = strtrim(units(0:2),2)
ENDCASE
IF n_elements(verbose) EQ 0 THEN verbose = 0
device,get_screen_size = scrdims ; ~plot+borders
;
; =====>> If needed, load test images.
;
needload = (n_elements(input) EQ 0) AND (NOT associate) AND (NOT have_func)
IF keyword_set(noload) THEN BEGIN ; force load?
IF n_elements(ws) EQ 1 THEN BEGIN
IF ws.assoc THEN BEGIN
associate = ws.assoc
definition = ws.definition
filename = ws.filename
tag = ws.tag
needload = 0
ENDIF
ENDIF
IF (n_elements(images) EQ 0) THEN BEGIN
message,/inform,'No data in common look with /noload keyword set.'
needload = 1
ENDIF ELSE needload = 0 ; use images---already stored
ENDIF
IF NOT needload AND (n_elements(input) GT 0) THEN images = input
IF needload THEN BEGIN
message,/inform,'Loading test data...'
d = min(scrdims)/3
dd = dist(d)
dr = randomn(seed,d,d)
dg = findgen(d)*4*!pi/d
IF !version.release GE '4.0' THEN BEGIN
ndemo = 3
nim = 7+ndemo
images = fltarr(d,d,nim)
openr,lun,/get,FILEPATH('galaxy.dat', SUBDIRECTORY = ["examples","data"])
tmp = bytarr(256,256)
readu,lun,tmp
images(*,*,0) = congrid(tmp,d,d)
close,lun
openr,lun,/get,FILEPATH('cereb.dat', SUBDIRECTORY = ["examples","data"])
tmp = bytarr(512,512,2)
readu,lun,tmp
images(*,*,1) = congrid(tmp(*,*,0),d,d)
images(*,*,2) = roberts(congrid(tmp(*,*,1),d,d)) < 20
close,lun
free_lun,lun
ENDIF ELSE BEGIN
images = fltarr(d,d,7)
ndemo = 0
ENDELSE
images(0,0,0+ndemo) = dd
images(0,0,1+ndemo) = .5*max(dd)+dr
images(0,0,2+ndemo) = dd+dr*sqrt(d)
images(0,0,3+ndemo) = (sin(dg)#cos(dg))*128+128
mul = 12
a = beselj(findgen(d)/max(d)*5,0)*mul
off = 80
images(0,0,4+ndemo) = a#a+off
images(0,0,5+ndemo) = images(*,*,4+ndemo)+dr*mul
images(0,0,6+ndemo) = median(images(*,*,5+ndemo),5)
dim3marks = ['barred spiral galaxy','brain','brain with Roberts filter','dist','noise','dist+noise','sin#cos','Besel','Besel+noise','smoothed Besel+noise']
axes = 'image menu'
units = ['x (pixels)','y (pixels)','counts (dn)']
ENDIF
;
; =====>> Now set the parameters based on the images. Size first.
;
CASE 1 OF
associate: BEGIN
IF n_elements(filename) EQ 0 THEN filename = pickfile()
openr,lun,filename,/get_lun,err = err
IF err NE 0 THEN BEGIN
message,/inform,'Unable to open '+filename+'. Aborting.'
return
END
IF n_elements(definition) EQ 0 THEN REPEAT BEGIN
definition = inquire('Enter definition of the associate variable, e.g., lonarr(100,100) or {struct,header:0,data:intarr(128,128)}',' ')
ENDREP UNTIL execute('tmp='+definition)
stat = execute('tmp='+definition)
szt = size(tmp)
is_struct = szt(szt(0)+1) EQ 8
exestring = 'images = assoc(lun,'+definition+','+strtrim(offset,2)+')'
IF NOT execute(exestring) THEN BEGIN
message,/inform,'Unable to define associate variable using '+definition+' on file '+filename
return
ENDIF
IF is_struct THEN BEGIN
IF n_elements(tag) EQ 0 THEN BEGIN
tags = tag_names(tmp)
nt = n_elements(tags)-1
i = 0
REPEAT BEGIN
si = size(tmp.(i))
i = i+1
ENDREP UNTIL (i EQ nt) OR (si(0) EQ 2)
tag = inquire('Enter tag # of images',i-1)
ENDIF
IF verbose THEN BEGIN
tags = tag_names(tmp)
message,/inform,'Chosen tag name is '+tags(tag)
ENDIF
ENDIF ELSE tag = -1
tmp = images(0)
IF is_struct THEN si = size(tmp.(tag)) ELSE si = size(images)
IF si(0) NE 2 THEN BEGIN
message,/inform,'Associate variable is not 2-D! Aborting.'
return
ENDIF
filestats = fstat(lun)
nb = nbytes(tmp)
IF n_elements(dimens) EQ 0 THEN d3 = filestats.size/nb ELSE d3 = dimens
si = [3,si(1),si(2),d3,si(3),filestats.size]
END
have_func: BEGIN
images = call_function(loader_name,lonarr(5))
si = size(images)
IF si(0) NE 2 THEN BEGIN
message,/inform,loader_name+' return is not 2-D! Aborting.'
return
ENDIF
x = strtrim(si(1),2) & y = strtrim(si(2),2)
IF n_elements(dimens) EQ 0 THEN dimens = inquire('Enter the dimensions of the array of images, e.g., enter 3 4 if '+loader_name+' returns '+x+' x '+y+'images from a '+x+' x '+y+' x 3 x 4 set',1)
n_el = si(4)
FOR i = 0,n_elements(dimens)-1 DO n_el = n_el*dimens(i)
filename = ''
definition = ''
is_struct = 0
tag = -1
si = [2+n_elements(dimens),si(1),si(2),dimens,si(3),n_el]
END
ELSE: BEGIN
filename = ''
definition = ''
is_struct = 0
tag = -1
si = size(images)
END
ENDCASE
IF si(si(0)+1) EQ 6 THEN BEGIN
message,/inform,'To use look with complex arrays, you need to make a function. Type look,/help for details.'
return
ENDIF
IF si(si(0)+1) EQ 7 THEN BEGIN
message,/inform,'Look doesn''t support strings. Type look,/help for details.'
return
ENDIF
IF verbose THEN print,'% LOOK: size=',si,form = '(a,10i8)'
;
; =====>> Set defaults based on images
;
nimages = 1 ; total number of images
FOR i = 3,si(0) DO nimages = nimages*si(i)
x = si(1) ; 4 conveniences
y = si(2)
; xgen and ygen are no longer needed, due to change to look_si2 (DSR)
;;xgen = lindgen(x)
;;ygen = lindgen(y)
xrange = [0,x-1]
yrange = [0,y-1]
dims = ([1.06,1.08]*[x,y]) < (scrdims/3) > (scrdims/4)
;
; =====>> Compose options menu from hardwired items plus user inputs
;
tmp = {look_pdmenu,flags:0,name:''}
optmenu = [ $
{look_pdmenu,1,'Options menu'} $
,{look_pdmenu,1,'blink compare'} $
,{look_pdmenu,0,'blink to screen'} $
,{look_pdmenu,2,'blink to window'} $
,{look_pdmenu,1,'catalog'} $
,{look_pdmenu,0,'cat to screen'} $
,{look_pdmenu,2,'cat to window'} $
,{look_pdmenu,1,'enlargement'} $
,{look_pdmenu,0,'full screen'} $
,{look_pdmenu,2,'full window'} $
,{look_pdmenu,0,'movie'} $
,{look_pdmenu,1,'plot types'} $
,{look_pdmenu,0,'contour'} $
,{look_pdmenu,0,'histogram'} $
,{look_pdmenu,0,'look_image'} $
,{look_pdmenu,0,'surface'} $
,{look_pdmenu,0,'shade_surf'} $
,{look_pdmenu,0,'show3'} $
,{look_pdmenu,2,'tvscl'} $
,{look_pdmenu,0,'region of interest'} $
,{look_pdmenu,1,'spatial filters'} $
,{look_pdmenu,0,'leefilt'} $
,{look_pdmenu,0,'median'} $
,{look_pdmenu,0,'smooth'} $
,{look_pdmenu,2,'Laplacian'} $
; ,{look_pdmenu,0,'type image'} $
,{look_pdmenu,1,'Autoscale options'} $
,{look_pdmenu,0,'All data'} $
,{look_pdmenu,0,'Omit top / bottom 5%'} $
,{look_pdmenu,0,'Omit top / bottom 10%'} $
,{look_pdmenu,0,'Mean +/- 1 sigma'} $
,{look_pdmenu,0,'Mean +/- 2 sigma'} $
,{look_pdmenu,0,'Mean +/- 3 sigma'} $
,{look_pdmenu,0,'Median +/- 1 sigma'} $
,{look_pdmenu,0,'Median +/- 2 sigma'} $
,{look_pdmenu,0,'Median +/- 3 sigma'} ]
; Build custom scaling function(s) into the menu
if n_elements (userscalefunc) eq 0 then optmenu = [ optmenu $
,{look_pdmenu,2,'hist_equal'} ] $
else begin
optmenu = [ optmenu, {look_pdmenu,0,'hist_equal'} ]
ncust = n_elements (userscalefunc)
for i = 1, ncust do begin
if i eq ncust then entry_type = 2 else entry_type = 0
optmenu = [ optmenu, {look_pdmenu,entry_type,userscalefunc(i-1)}]
endfor
endelse
optmenu = [ optmenu $
,{look_pdmenu,1,'Write PS file'} $
,{look_pdmenu,0,'Set PS attributes'} $
,{look_pdmenu,0,'Full Window Only'} $
,{look_pdmenu,0,'Zoom Window Only'} $
,{look_pdmenu,2,'All Four Windows'} $
,{look_pdmenu,0,'xloadct'} $
]
nopt = n_elements(optmenu)
n = n_elements(options)
np = n_elements(procedures)
nf = n_elements(functions)
ispro = bytarr(nopt+n+np+nf)
nt = nopt
IF np GT 0 THEN FOR i = 0,np-1 DO BEGIN ; add procedures
optmenu = [optmenu,{look_pdmenu,0,procedures(i)}]
ispro(nt+i) = 1
ENDFOR
nt = nopt+np
IF nf GT 0 THEN FOR i = 0,nf-1 DO BEGIN ; add functions
optmenu = [optmenu,{look_pdmenu,0,functions(i)}]
ispro(nt+i) = 0
ENDFOR
nt = nopt+np+nf
IF n GT 0 THEN BEGIN ; add options---more work!
FOR i = 0,n-1 DO BEGIN
optmenu = [optmenu,{look_pdmenu,0,options(i)}]
IF n_elements(types) EQ n THEN BEGIN
ispro(nt+i) = strpos(strupcase(types(i)),'P') GE 0
ENDIF ELSE BEGIN
print,'% LOOK: Checking '+options(i)+'...',form = '(a,$)'
file = look_in_path(options(i)+'.pro')
IF file(0) NE '' THEN BEGIN ; There's a file, so search it...
openr,lun,/get_lun,file(0)
line = ''
want = byte('PRO'+strupcase(options(i))+',') ; ... for "PRO<NAME>,"
REPEAT BEGIN
readf,lun,line
bline = byte(strupcase(line)) ; Change to bytes, omit blanks.
isapro = (where(bline(where(bline ne 32)),want))(0) NE -1
ENDREP UNTIL eof(lun) OR isapro
close,lun
free_lun,lun
ENDIF ELSE BEGIN ; No file, so it's an IDL built-in
tmp = intarr(2,2)
isapro = execute(options(i)+',tmp') ; Try to execute it as a procedure.
ENDELSE
ispro(nt+i) = isapro
IF isapro THEN print,'PRO' ELSE print,'FUNCTION'
ENDELSE
ENDFOR
ENDIF
IF n_elements(viewers) GT 0 THEN BEGIN ; add viewer on/off toggle switches
optmenu = [optmenu,{look_pdmenu,1,'viewers'}]
FOR i = 0,n_elements(viewers)-1 DO optmenu = [optmenu $
,{look_pdmenu,0,viewers(i)+'-->on/all mouse'} $
,{look_pdmenu,0,viewers(i)+'-->on/click only'} $
,{look_pdmenu,2,viewers(i)+'-->off'}]
ENDIF ELSE viewers = ''
optmenu(n_elements(optmenu)-1).flags = 2
;
; =====>> Set the display parameters (most of these could be set earlier)
;
id = bytarr(2,2) ; plotting window indices
xlast = -1 ; previous cursor coordinates
ylast = -1
report = [ $ ; text items in the reptext widget
'mouse pixel',' x=',' y=',' z=' $
,'zoom center',' x=',' y=',' z=' $
,'zoom width',' x=',' y=' $
,'full stats',' mean=',' sd=' $
,'zoom stats',' mean=',' sd=', ' '] ; Extra blank is kludge
star = replicate(' ',n_elements(report))
star(5) = '*' ; quantity controlled by rt button
starred = [4,5,6,8,9,10] ; those for star cw_pdmenu
starlookup = [5,5,6,9,9,10] ; map from starred to x's & y's
down = [-1,-1]
center = down
width = down
increment = 1 ; increment from click of rt mouse button
;
; =====>> Get the first image
;
CASE 1 OF
si(0) LT 2: message,'2-D or larger arrays only! Type look,/help.'
si(0) EQ 2: thisimage = images
si(0) GT 2: BEGIN
CASE 1 OF
associate: BEGIN
IF is_struct THEN BEGIN
tmp = images(0)
thisimage = tmp.(tag)
ENDIF ELSE BEGIN
thisimage = images(0)
ENDELSE
END
have_func: thisimage = call_function(loader_name,lonarr(5))
ELSE: thisimage = images(*,*,0)
ENDCASE
END
ENDCASE
fullimage = thisimage
zoomimage = thisimage ; Use full image to start
;
; =====>> Set the display ranges
; inputrange = user-specified parameter to override automatic setting
; imrange = the extremes of the first (current) image
; allrange = the extremes of all the images
; range = the difference in allrange values
; srange = the slider range
; tvrange = the extremes of the full image
;
IF n_elements(inputrange) NE 2 THEN BEGIN
mn = min(thisimage,max = mx)
IF mn EQ mx THEN mx = mn+1 ; take care of constant image
imrange = [mn,mx] ; range for first image
IF NOT associate AND NOT have_func THEN BEGIN
mn = min(images,max = mx)
IF mn EQ mx THEN mx = mn+1 ; take care of constant image
ENDIF
allrange = [mn,mx] ; range for all images
ENDIF ELSE BEGIN
imrange = inputrange
allrange = inputrange
ENDELSE
IF si(si(0)+1) LT 3 THEN imrange = long(imrange)
range = abs(allrange(1)-allrange(0)) ; make sure it's positive
srange = allrange+[-1,1]*range ; a total of 3x range of images
IF (srange(1) LT imrange(1)) OR (srange(0) GT imrange(0)) THEN BEGIN
message,/inform,'Overflow in slider range. Limiting to image range.'
; IF si(si(0)+1) EQ 2 THEN srange = [0,32767] ELSE $ ; positive integers
srange = allrange
ENDIF
IF (imrange(1) GT srange(1)) OR (imrange(0) LT srange(0)) THEN BEGIN
message,/inform,'Image range outside slider range. Limiting to slider range.'
imrange = srange
ENDIF
IF (srange(0) GT -1) AND (srange(1) LT 1) THEN srange = [-1,1]
tvrange = float(imrange)
;
; =====>> CREATE AND REGISTER WIDGETS: top, columns, parts of columns
;
IF xregistered("look") GT 0 THEN message,'Another look exists! Type retall & xmanager, then look,...'
looktop = widget_base(title='look: image-display widget ('+versdate+')',/column)
lookbase = widget_base(looktop,/row)
col1base = widget_base(lookbase,/column)
donebutton = widget_button(col1base,value='DONE',uvalue = 'donebutton')
helpbutton = widget_button(col1base,value='HELP',uvalue = 'helpbutton')
fullzoom = ['Use Full Only','Use Zoom Only','Use Full & Zoom']
fullzoombutton = widget_button(col1base,value = fullzoom(0),uval = 'plotfullorzoom?')
restorebutton = widget_button(col1base,value='Restore Image',uvalue = 'restorebutton')
tmp = cw_pdmenu(col1base,optmenu,/return_name,uvalue = 'optpdmenu')
kslider = widget_slider(col1base,title = 'filter width',uvalue = 'kslider',min = 1 $
,max = (si(1)-1) < (si(2)-1),value = kernel_width,scroll = 1)
dimid = -1
dimname = '2-D'
IF si(0) GT 2 THEN BEGIN ; "image" has more than 2 dimensions ;GGA
dimid = lonarr(4,si(0)-2)
dimname = strarr(si(0)-2)
FOR i = 3,si(0) DO BEGIN
IF n_elements(axes) GE (i-2) THEN stit = axes(i-3) ELSE stit = 'dim '+strtrim(i,2)
dimname(i-3) = stit
dimi = 'dim'+strtrim(i,2)
digits = ceil(alog10(si(i)))
menu = [{look_pdmenu,1,stit},{look_pdmenu,0,'previous'}] ; start of menu
; If keyword exists, then convert to variable marks and add to menu.
current = 'dim'+strtrim(i,2)+'marks'
stat = execute('nm = n_elements('+current+')')
IF nm GT 0 THEN BEGIN
stat = execute('marks = '+current) ; save in a global variable
sz = size(marks)
IF sz(sz(0)+1) NE 8 THEN BEGIN ; not a structure, so convert to structure
tmp = replicate({mark:0l,tag:''},nm)
FOR n = 0,nm-1 DO BEGIN
tmp(n).mark = n
tmp(n).tag = string(marks(n))
ENDFOR
marks = tmp ; save
ENDIF
FOR n = 0,nm-1 DO menu = $ ; add each element of struct array to menu
[menu,{look_pdmenu,0,strtrim(marks(n).(0),2)+': '+marks(n).(1)}]
ENDIF
menu = menu(0:(nm+1) < (si(i)+1)) ; limit the number of elements
menu(n_elements(menu)-1).flags = 2 ; flag the end of the menu
dimid(0,i-3) = look_mvpi(col1base,uvalue = dimi,title = stit $
,value = '0',size = digits,scroll = '1',menu = menu)
ENDFOR
ENDIF
col2base = widget_base(lookbase,/column)
col2draw1 = widget_draw(col2base,xsize=dims(0),ysize=dims(1))
col2draw2 = widget_draw(col2base,xsize=dims(0),ysize=dims(1),uvalue='alldraw',/button,/motion)
; Various changes here to make the scroll increment floating point
scroll_value = (srange(1)-srange(0))/((!d.n_colors<!d.table_size) > 1)
minslide = llcw_fslider(col2base,min = srange(0) $
,uvalue = 'spanmin',max = srange(1),value = imrange(0),/drag $
,scroll = scroll_value,/suppress, xsize=dims(0))
tmp = widget_base(col2base,/row)
autominbutton = widget_button(tmp,value = 'Auto Min',uval = 'minauto?')
minset = widget_text(tmp,xsize = 9,val = strtrim(imrange(0),2),/edit,uval = 'minset')
junk = widget_button(tmp,value = '-I',uvalue = 'applymin-')
junk = widget_button(tmp,value = '+I',uvalue = 'applymin+')
col3base = widget_base(lookbase,/column)
col3draw1 = widget_draw(col3base,xsize=dims(0),ysize=dims(1),uvalue='zoomdraw',/button,/motion)
col3draw2 = widget_draw(col3base,xsize=dims(0),ysize=dims(1))
maxslide = llcw_fslider(col3base,min = srange(0) $
,uvalue = 'spanmax',max = srange(1),value = imrange(1),/drag $
,scroll = scroll_value,/suppress, xsize=dims(0))
tmp = widget_base(col3base,/row)
automaxbutton = widget_button(tmp,value = 'Auto Max',uval = 'maxauto?')
maxset = widget_text(tmp,xsize = 9,val = strtrim(imrange(1),2),/edit,uval = 'maxset')
junk = widget_button(tmp,value = '-I',uvalue = 'applymax-')
junk = widget_button(tmp,value = '+I',uvalue = 'applymax+')
col4base = widget_base(lookbase,/column)
reptext = widget_text(col4base,xsize = 11,ysize = 18,value = star+report)
starslide = widget_slider(col4base,title = 'Increment for *',min = -(x < y)/2$
,max = (x < y)/2,value = increment,uvalue = 'starslide',scroll = 1)
np = n_elements(starred)
ppd_s = replicate({cw_pdmenu_s,flags:0,name:''},np+1)
ppd_s(0) = {cw_pdmenu_s,1,'Select *'}
tmp = report(starred)
FOR i = 1,np-1 DO ppd_s(i) = {cw_pdmenu_s,0,tmp(i-1)}
ppd_s(np) = {cw_pdmenu_s,2,tmp(np-1)}
starpdmenu = cw_pdmenu(col4base,ppd_s,/return_index,uvalue = 'starpdmenu')
tmp = widget_base(col4base,/row)
bothfixid = widget_button(tmp,value = 'Auto',uval = 'bothfix?')
junk = widget_label(tmp,value = 'I=')
spanmagid = widget_text(tmp,ysize = 1,xsize = 5,value = strtrim(string(scroll_value,format = '(g12.3)'),2),/edit,uvalue = 'spanmag')
;pm = ['+','-']
;signid = cw_bgroup(tmp,pm,button_uvalue = 'span'+pm,/no_release,/row,/frame $
; ,/exclusive,uvalue = 'spansign',set_value = 0)
tmp = widget_base(col4base,/row)
junk = widget_label(tmp,value = 'Both')
junk = widget_button(tmp,value = '-I',uvalue = 'applyboth-')
junk = widget_button(tmp,value = '+I',uvalue = 'applyboth+')
;
; =====>> Fill in the help structure with one-line messages
;
help = {look_aid,v:'value',uv:'uvalue',message:''}
help = {look_aid,'FULL IMAGE','alldraw',"Roam in tv image. Click and drag left mouse to zoom. Click middle to recenter."}
help = [help,{look_aid,'ZOOM IMAGE','zoomdraw',"Roam in zoom image to see cuts. Default display area also."}]
help = [help,{look_aid,'HORIZONTAL CUT','',"Show horizontal cut when roaming over the full or zoom image."}]
help = [help,{look_aid,'VERTICAL CUT','',"Show vertical cut when roaming over the full or zoom image."}]
help = [help,{look_aid,'DONE','donebutton','Press this button to exit.'}]
;help = [help,{look_aid,'HELP','helpbutton',"Press this button to call xdisplayfile,'look.pro'."}]
help = [help,{look_aid,'Use Full Only','',"Select Full Only, Zoom Only, or Full & Zoom."}]
help = [help,{look_aid,'Restore Image','restorebutton',"Reread the original image for current indices: restore unfiltered image."}]
help = [help,{look_aid,'Options menu','plotpdmenu',"Pull down menu of options"}]
;help = [help,{look_aid,'Enlargement','enlargement',"Fill the screen with the current image, magnified 2X, 3X, etc.---whatever fits."}]
help = [help,{look_aid,'filter width','kslider',"Kernel size of spatial filters smooth and median."}]
help = [help,{look_aid,'dim3, dim4,...','dim3',"Move each slider to select image number in a series."}]
help = [help,{look_aid,'*','',"In the Select * pop-up menu, use the left mouse button to select the *'d quantity."}]
help = [help,{look_aid,'*','',"On the full image, click the right mouse button to change the *'d quantity by mouse increment."}]
help = [help,{look_aid,'mouse pixel','mouse',"Report the mouse pixel and image value."}]
help = [help,{look_aid,'zoom center','zoom center',"Report the zoom center in image coordinates: pixels."}]
help = [help,{look_aid,'zoom width','zoom width',"Report the zoom width in image coordinates: pixels."}]
help = [help,{look_aid,'stats','stats',"Report the mean and st.dev. for full and zoom images."}]
help = [help,{look_aid,'Increment for *','starslide',"Set the increment so a right mouse click moves the *'d item."}]
help = [help,{look_aid,'Select *','starslide',"Use the left mouse button to select the *'d quantity."}]
help = [help,{look_aid,'plot min','spanmin',"Set display minimum. Slider ranges over 3x image range."}]
help = [help,{look_aid,'Auto Scale','minauto?',"Automatically set minimum to image minimum."}]
help = [help,{look_aid,'Fix Slider','minman?',"Use the current slider value as the plot minimum."}]
help = [help,{look_aid,'plot max','spanmax',"Set display maximum. Slider ranges over 3x image range."}]
help = [help,{look_aid,'AutoMax','maxauto?',"Automatically set max to image max."}]
help = [help,{look_aid,'FixSlide','maxman?',"Use the current slider value as the plot extremum."}]
help = [help,{look_aid,'Set Min=','maxman?',"Use the text value as the plot extremum."}]
help = [help,{look_aid,'I=,-I,+I','apply',"Apply the Increment, I, to the extrema, either min, max or Both."}]
help = [help,{look_aid,'Auto Scale options','autoscale',"Map the color table to a subset of the full data range"}]
;
; =====>> Fill in the help window and put widgets on the screen.
;
comtext = widget_text(lookTop,xsize = 50,ysize = comlines,value = help.v+': '+help.message,/scroll)
widget_control,lookbase,/realize ; PUT THEM ON THE SCREEN
;
; =====>> Get window indices and store in common
;
widget_control,get_value = id_c2d1,col2draw1
widget_control,get_value = id_c2d2,col2draw2
widget_control,get_value = id_c3d1,col3draw1
widget_control,get_value = id_c3d2,col3draw2
ids = [[id_c2d1,id_c2d2],[id_c3d1,id_c3d2]]
wids = [[col2draw1,col2draw2],[col3draw1,col3draw2]]
;
; =====>> Compute small images of the digits to label images
;
wmax = 0
FOR i = 0,9 DO BEGIN
xyouts,0,0,strtrim(i,2),width = w,/device
wmax = w*!d.x_size > wmax
ENDFOR
xd = wmax+2 ; add a 1-pixel border
yd = xd+2 ; assume a height
backgrd = bytarr(xd,yd)+!d.n_colors-1 ; usually white
digits = bytarr(xd,yd,11)
FOR i = 0,9 DO BEGIN
tv,backgrd
xyouts,1,1,strtrim(i,2),width = w,/device,color = !p.background
digits(*,*,i) = tvrd(0,0,xd,yd)
ENDFOR
tv,backgrd
xyouts,1,1,':',width = w,/device,color = !p.background
digits(*,*,10) = tvrd(0,0,xd,yd)
erase
;
; =====>> Fill the image widget & calculate scale (dev->data)
;
wset,id_c2d2
look_image,look_scl(thisimage,[min(thisimage),max(thisimage)]),origin = [0,0] $
,scale = 1,title = 'FULL IMAGE',xtit = units(0),ytit = units(1)
position = [!x.window(0),!y.window(0),!x.window(1),!y.window(1)]
; Corrected slope / intercept calculations. The conversion factors from
; look_si are not quite correct; look_si2 is an improved version (DSR).
;;look_si,xgen,ygen,slopes,intercepts
look_si2,xrange,yrange,slopes,intercepts
wset,id_c3d1
look_image,look_scl(thisimage,[min(thisimage),max(thisimage)]),origin = [0,0] $
,scale = 1,title = 'ZOOM IMAGE',xtit = units(0),ytit = units(1)
wset,id_c2d2
;
; =====>> Put all the information in structures to pass to event routine
;
if n_elements (userscalefunc) eq 0 then scalefunc = '' $
else scalefunc = userscalefunc
all = { $ ; structure for entire image
wid:wids(1,0) $ ; draw widget id for widget reference
,id:ids(1,0) $ ; draw widget id for wset,...
,hcutid:ids(0,0) $ ; draw id for horizontal cut
,vcutid:ids(1,1) $ ; draw id for vertical cut
,position:position $ ; lo.left & up.right of plot region
,min:[xrange(0),yrange(0)] $ ; minimum x&y coordinate values: (0,0)
,max:[xrange(1),yrange(1)] $ ; maximum x&y coordinate values
,mean:0. $
,sd:0. $
,xrange:xrange $ ; [min(0),max(0)] = x coordinate range
,yrange:yrange $ ; [min(1),max(1)] = y coordinate range
,center:[x,y]/2 $ ; center x&y coordinates
,width:[x,y] $ ; # of x&y pixels
,slopes:slopes $ ; device-->data x&y slopes
,intercepts:intercepts $ ; device-->data x&y intercepts
,imrange:imrange $ ; range of pixel values
,tvrange:tvrange $ ; range of tv and cut plots
,datlast:[-1,-1] $ ; last mouse pixel; data coords
,devlast:[-1,-1] $ ; last mouse pixel; device coords
,dragcorner:[-1,-1] $ ; storage for drag box, see look_event
,x:x,y:y $ ; # of x&y pixels
,down:lonarr(2,4)-1 $ ; data coords for mouse button presses
,up:lonarr(2,4)-1 $ ; data coords for mouse button releases
,scaletype:1 $ ; type of image scaling
,scalefunc:scalefunc $ ; user-supplied image scaling function
,meansig:[1.,2.,3.] $ ; sigma +/- mean for image scaling
,mediansig:[1.,2.,3.] $ ; sigma +/- median for image scaling
}
;;if n_elements (userscalefunc) gt 0 then all.scalefunc = userscalefunc
; Set mean scaling to the user specified sigma levels. Only use the first
; three levels, if more than three were given.
nmean = n_elements (usermean)
if nmean gt 3 then nmean = 3
if nmean gt 0 then all.meansig(0:nmean-1) = usermean(0:nmean-1)
; Set median scaling to the user specified sigma levels. Only use the first
; three levels, if more than three were given.
nmedian = n_elements (usermedian)
if nmedian gt 3 then nmedian = 3
if nmedian gt 0 then all.mediansig(0:nmedian-1) = usermedian(0:nmedian-1)
zoom = all ; same structure for zoom draw widget
zoom.id = ids(0,1) ; but change id for use with wset
zoom.wid = wids(0,1) ; but change id for widget
zoom.hcutid = ids(1,1) ; draw id for horizontal cut
zoom.vcutid = ids(0,0) ; draw id for vertical cut
xcut = thisimage(*,0)*0 ; x coordinates for hor or vert cuts
ycut = reform(thisimage(0,*)*0) ; y coordinates for hor or vert cuts
ws = { $ ; window structure
assoc:associate $ ; flag for associate variable
,filename:filename $ ; associate variable file name
,PSfilename:'idl.ps' $ ; PS filename for writing
,PSattstr:',color=1,bits=8,encap=0,pre=0,portrait=1' $ ; for device call
,PSatt:{look_PSatt $ ; PS attributes
,encap:0 $
,color:1 $
,bits:8 $
,portrait:1 $
,preview:0 $
} $
,PSct:5 $ ; PS color table number
,definition:definition $ ; associate variable definition
,is_struct:is_struct $ ; flag assoc being a structure
,tag:tag $ ; structure tag of image if is_struct
,func:have_func $ ; flag to say images come from function
,loader_name:loader_name $ ; name of function that returns images
,increment:increment $ ; increment on click of rt mouse button
,star:star $ ; quantity to increment with rt mouse
,starlookup:starlookup $ ; map from star pdmenu to x's & y's
,ids:ids $ ; draw widget ids for use with wset
,wids:wids $ ; draw widget ids for references
,last_cutwid: -1 $ ; draw widget id for last cut plots
,cut_oplot:[0,0] $ ; flags to renew hor & vert cut plots
,hcutxdata:long(xcut) $ ; x coordinates for hor cut
,hcutydata:xcut $ ; y coordinates for hor cut
,vcutxdata:ycut $ ; x coordinates for vert cut
,vcutydata:long(ycut) $ ; y coordinates for vert cut
,d:lonarr(7) $ ; current dims to browse in series
,previous:lonarr(7) $ ; previous dims for recalling
,dcat:lonarr(7) $ ; current dims for catalog/movie/blink
,size:si $ ; size vector for reference
,kernel_width:kernel_width $ ; width in pixels of spatial filters
,dimid:dimid $ ; widget ids for dimension sliders
,dimname:dimname $ ; names for dimensions
,mxd:maxsurfdim $ ; to avoid overlapping lines
,help:help $ ; help messages
,comtext:comtext $ ; id for comment text widget
,reptext:reptext $ ; id for report text widget
,report:report $ ; content of report text widget
,spansliders:[minslide,maxslide] $ ; ids for plot min and max sliders
,spanmagid:spanmagid $ ; id for increment text widget
,autoscale:[autominbutton,automaxbutton] $ ; IDs for autoscale buttons
,spanmode:[1,1] $ ; flags for min/max automatic scaling
,srange:srange $ ; range of sliders
,ctrange:tvrange $ ; range of color table
,manrange:all.tvrange $ ; manual range of tv and cut plots
,fullzoombutton:fullzoombutton $ ; id for plotfullzoom button
,plotfullzoom:0 $ ; plot flag---3 options
,fullzoom:fullzoom $ ; the text for fullzoombutton
,fullshown:1 $ ; Does the full window show full image?
,zoomshown:1 $ ; Does the zoom window show zoom image?
,plottype:0 $ ; Type of plot (0 = normal image)
,optmenu:optmenu $ ; names of optional plots
,ispro:ispro $ ; Is option a procedure or a function?
,debug:debug $ ; flag for debug output
,drag:bytarr(3) $ ; mouse buttons' state: 0=up, 1=down
,dragstart:[-1,-1] $ ; device coordinates at drag start
,dragcorner:[-1,-1] $ ; device coordinates at drag corner
,setids:[minset,maxset] $ ; ids for text widgets containing range
,AddLabels:1 $ ; flag to add labels to catalog images
,digits:digits $ ; maps of digits for image labels
,bothfixid:bothfixid $ ; widget id for Auto/Fix increment switch
,bothfix:0 $ ; flag to automatically update increment
,save:0 $ ; flag to save index data in common
,catalogsave:0 $ ; flag to save catalog data in common
,saveoffset:0 $ ; image offset in catalog in common
,reset:0 $ ; flag to reset catalog & index in common
,catshowimages:1 $ ; flag to display images in catalog
,catlims:[0L,100 < (nimages-1),1,0] $ ; catalog limits & blink compare
,units:units $ ; axes labels
,viewers:viewers $ ; names of procedures to execute on
; trigger of mouse events
,viewers_set:intarr(n_elements(viewers)) $ ; on/off toggle switches
}
;
; =====>> Report Statistics
;
IF n_elements(thisimage) GT 1 THEN begin
res = moment (thisimage, sdev = sdev)
all.sd = sdev
mean = res(0)
endif ELSE BEGIN
all.sd = 0.
mean = 0
ENDELSE
all.mean = mean
ws.report(12) = ' mean='+strtrim(all.mean,2)
ws.report(13) = ' sd='+strtrim(all.sd,2)
widget_control,ws.reptext,set_value = ws.star+ws.report
;
; =====>> TURN OVER CONTROL TO XMANAGER
;
xmanager,'look',lookbase,event_handler = 'look_event'
;
; =====>> And clean up.
;
IF associate THEN BEGIN
close,lun
free_lun,lun
ENDIF
COMMON colors, r_orig, g_orig, b_orig, r_curr, g_curr, b_curr
tvlct, r_orig, g_orig, b_orig ; restore original colors
end