;+ ; Project : SOHO - CDS ; ; Name : XCROP_CUBE ; ; Purpose : General N-dimensional cube cropping. ; ; Explanation : This is a routine that allows the user to interactively pick ; out a "rectangular" subset of any N-dimensional data cube in ; IDL. ; ; Although IDL allows up to 8 dimensions in an array, only 7 ; subscripts are allowed (!) so any "cropping" can be described ; by the start and stop indices of 7 dimensions. Thus a cropping ; is defined as a structure: ; ; c = {b:lonarr(7), e:lonarr(7)} ; ; and cropping an array given such a structure is done by ; ; cropped = cube(c.b(0):c.e(0),c.b(1):c.e(1),$ ; c.b(2):c.e(2),c.b(3):c.e(3),$ ; c.b(4):c.e(4),c.b(5):c.e(5),$ ; c.b(6):c.e(6)) ; ; Use : XCROP_CUBE,CUBE,CROP ; ; Inputs : CUBE : Any data array. ; ; CROP : A structure {b:lonarr(7), e:lonarr(7)}, where the B and ; E array describe the start and stop indices of the ; cropping, respectively. ; ; Opt. Inputs : CROP does not need to be defined on input. ; ; Outputs : CROP is modified by the user. ; ; Opt. Outputs: None. ; ; Keywords : FIXED_SIZE : The size of the cropping region may be fixed in ; each dimension individually. E.g., ; FIXED_SIZE=[0,1,0,1,0,0,0] will fix the size of ; dimensions 2 and 4. ; ; MISSING : The value of missing data (for color scaling ; purposes). ; ; GROUP_LEADER : Group leader. ; ; Calls : default, cw_enterb(), trim(), cw_cubeview(), prestore, ; find_draw_widget(), handle_killer_hookup, xmanager, ; ; Common : None ; ; Restrictions: ... ; ; Side effects: ... ; ; Category : Utility, Widgets ; ; Prev. Hist. : None ; ; Written : SVH Haugan, UiO, 26 September 1997 ; ; Modified : Not yet. ; ; Version : 1, 26 September 1997 ;- PRO xcrop_cube_oplot,info ;; Get info on what's displayed ;; widget_control,info.int.cube_id,get_value=cube_val ;; These are the displayed image dimensions xdi = cube_val.image_dim(0) & ydi = cube_val.image_dim(1) ;; Get the current crop handle_value,info.int.crop_h,crop ;; Get the device coordinates of the current crop x = [crop.b(xdi),crop.e(xdi)]+[-0.5,0.5] y = [crop.b(ydi),crop.e(ydi)]+[-0.5,0.5] prestore,info.int.cube_image_preg oplot,[x(0),x(0),x(1),x(1),x(0)],[y(0),y(1),y(1),y(0),y(0)] END PRO xcrop_cube_crop,info,ev ;; Get info on what's displayed ;; widget_control,info.int.cube_id,get_value=cube_val ;; These are the displayed image dimensions xdi = cube_val.image_dim(0) & ydi = cube_val.image_dim(1) ;; Get the current crop handle_value,info.int.crop_h,crop ;; Used to add halfpixels to enclose the pixels included. addsize = [-0.5d,0.5d] ;; Get the device coordinates of the current crop cip = info.int.cube_image_preg ;; shorthand x = pconvert(cip,[crop.b(xdi),crop.e(xdi)]+addsize,/data,/to_device) y = pconvert(cip,[crop.b(ydi),crop.e(ydi)]+addsize,/Y,/data,/to_device) x0 = x(0) & x1 = x(1) & y0 = y(0) & y1 = y(1) ;; Read state of motion events, and set them (for box_cursor) motion = widget_info(info.int.cube_image_win_id,/draw_motion_events) widget_control,info.int.cube_image_win_id,/draw_motion_events nx = (x(1)-x(0)) > 1 ny = (y(1)-y(0)) > 1 fixed = info.int.fixed_size([xdi,ydi]) ;; Do the box-cursor thingy ;; wset,info.int.cube_image_win box_cursor,x0,y0,nx,ny,/init,/anywhere,fixed_size=fixed widget_control,info.int.cube_image_win_id,draw_motion_events=motion orgsize = crop.e([xdi,ydi])-crop.b([xdi,ydi]) REPEAT BEGIN ;; try_again: ;; (with new addsize ;; Convert to data (i.e., cube pixel) coordinates ;; x = pconvert(cip,[x0,x0+nx],/device,/to_data) y = pconvert(cip,[y0,y0+ny],/device,/to_data,/Y) x = round(x-addsize) y = round(y-addsize) ;; Make sure we don't go outside limits ;; maxsz = info.int.sz(1+[xdi,ydi])-1 crop.b([xdi,ydi]) = ([x(0),y(0)] > 0) < maxsz crop.e([xdi,ydi]) = ([x(1),y(1)] > crop.b([xdi,ydi])) < maxsz ;; If any of the dimension sizes are fixed, make sure we stick to the ;; original size (by expanding/contracting the area and recalculate the ;; pixel sizes) redo = 0 ixi = [xdi,ydi] FOR i = 0,1 DO BEGIN IF info.int.fixed_size(ixi(i)) THEN BEGIN newsize = crop.e(ixi(i))-crop.b(ixi(i)) IF newsize NE orgsize(i) THEN BEGIN redo = 1 IF newsize GT orgsize(i) THEN addsize(i) = addsize(i)+0.05 $ ELSE addsize(i) = addsize(i)-0.05 print,"Redoing, addsize=",addsize ENDIF ENDIF END END UNTIL NOT redo ;; Get current sizes, update displayed values csz = crop.e-crop.b+1 FOR i = 0,6 DO widget_control,info.int.sztext_ids(i),set_value=trim(csz(i)) ;; Put back crop handle_value,info.int.crop_h,crop,/set ;; Redisplay the image widget_control,info.int.cube_id,set_value={origin:[0]} ;; Dummy ;; Overplot the crop xcrop_cube_oplot,info END PRO xcrop_cube_resize,info,dim,ev ;; Get crop handle_value,info.int.crop_h,crop sz = fix(ev.value) sz = (sz > 1) < info.int.sz(dim+1) widget_control,ev.id,set_value=trim(sz) current = crop.e(dim)-crop.b(dim)+1 delta = sz-current crop.b(dim) = (crop.b(dim)-(delta+sgn(delta))/2) > 0 crop.e(dim) = crop.b(dim)+sz-1 overshoot = crop.e(dim)-info.int.sz(dim+1)-1 IF overshoot GT 0 THEN BEGIN crop.b = crop.b-overshoot crop.e = crop.e-overshoot END ;; Set crop handle_value,info.int.crop_h,crop,/set xcrop_cube_oplot,info END PRO xcrop_cube_help,top htx = $ ['',$ 'XCROP_CUBE is a general widget for cropping (defining subsets of)',$ 'N-dimensional data cubes.',$ '',$ 'Below the command buttons are buttons showing the current size of',$ 'the cropping. You may change the sizes of the cropped region by',$ 'clicking on these buttons and typing in a different number',$ '',$ 'Below the size fields are two draw windows. The upper one shows',$ 'an image formed by taking a two-dimensional slice through the data',$ 'cube. The identity of the dimensions used to form the image are',$ 'shown by two buttons e.g.,', $ '',$ ' [ Dim:0 ] x [ Dim:1 ] ',$ '',$ 'meaning that the image displays dimensions 0 and 1. To view images',$ 'formed in other dimensions, click the buttons to change their values.',$ '',$ 'The lower draw window shows a plot of the data along one dimension,',$ 'shown with a similar button as e.g., [ Dim:2 ], which may also be',$ 'changed by clicking on it.',$ '',$ 'You may zoom in or out in the image/plot by clicking the right/left',$ 'buttons respectively, or move around (move the "focus point" of the',$ 'cube) by clicking the middle mouse button.',$ '',$ 'The outline of the current cropping region (in the two image',$ 'dimensions) is shown by a white rectangle plotted on top of the',$ 'image.',$ '',$ 'To modify the size or position of the cropping interactively, push',$ 'the "Crop" button at the top of the widget. This will cause the',$ 'upper plot region to act as a "box_cursor" zoom, and you may move',$ 'the box by clicking down the left mouse button and moving the cursor,',$ 'or resize the box by clicking down the middle button (near the corner',$ 'that you wish to move), moving the cursor around.',$ '',$ 'It is important that you remember to *end* this special mode by ',$ 'clicking the *right* mouse button - since normal event processing is',$ 'turned off during the box_cursor operation.',$ '',$ 'When you are satisfied with the result, press the [Exit] button'] xtext,htx,group=top END PRO xcrop_cube_event,ev widget_control,ev.top,get_uvalue=info,/no_copy widget_control,ev.id,get_uvalue=uval uval = str_sep(uval,':') CASE uval(0) OF 'EXIT':BEGIN widget_control,ev.top,/destroy return ENDCASE 'HELP':BEGIN xcrop_cube_help,ev.top ENDCASE 'CUT':BEGIN xcrop_cube_crop,info,ev ENDCASE 'SIZE':BEGIN xcrop_cube_resize,info,trim(uval(1)),ev ENDCASE 'CUBEVIEW':BEGIN xcrop_cube_oplot,info ENDCASE END widget_control,ev.top,set_uvalue=info,/no_copy END PRO xcrop_cube,cube,crop,group_leader=group_leader,fixed_size=fixed_size, $ missing=missing default,group_leader,0L sz = size(cube) ;; IDL v 4 allows 8-dimensional data, but just 7 subscripts! dcrop = {b:lonarr(7),e:lonarr(7)} dcrop.e = sz(1:sz(0))-1 IF sz(0) LT 7 THEN sz = [sz(0:sz(0)),replicate(1L,7-sz(0)),sz(sz(0)+1:*)] sz(0) = 7 default,crop,dcrop default,fixed_size,bytarr(7) IF n_elements(fixed_size) LT 7 THEN fixed_size = [fixed_size,bytarr(7)] top = widget_base(group_leader=group_leader,/column) commands = widget_base(top,/row) dummy = widget_button(commands,value='Help',uvalue='HELP') dummy = widget_button(commands,value='Exit',uvalue='EXIT') dummy = widget_button(commands,value='Crop',uvalue='CUT') ;; Display size. szbase = widget_base(top,/row) dummy = widget_label(szbase,value='Size:') sztext_ids = lonarr(7) currsize = crop.e-crop.b+1 FOR i = 0,6 DO BEGIN sztext_ids(i) = cw_enterb(szbase,value=trim(currsize(i)),$ uvalue='SIZE:'+trim(i)) IF fixed_size(i) THEN widget_control,sztext_ids(i),sensitive=0 IF i NE 6 THEN dummy = widget_label(szbase,value='x') END cube_id = cw_cubeview(top,value=cube,uvalue='CUBEVIEW',/all_events,$ xsize=400,ysize=300,missing=missing,$ origin=origin,scale=scale,phys_scale=phys_scale) widget_control,top,/realize widget_control,cube_id,get_value=cube_value widget_control,cube_value.internal.image_id,get_value=cw_pzoom_val widget_control,cube_value.internal.plot_id,get_value=cw_plotz_val prestore,cw_pzoom_val.plotreg cw_pzoom_win = !D.window prestore,cw_plotz_val.plotreg cw_plotz_win = !D.window cw_pzoom_win_id = find_draw_widget(cw_pzoom_win) cw_plotz_win_id = find_draw_widget(cw_plotz_win) int = {sz:sz,$ cube_id : cube_id,$ cube_plot_win : cw_plotz_win,$ cube_plot_win_id : cw_plotz_win_id,$ cube_plot_preg : cw_plotz_val.plotreg,$ cube_image_win : cw_pzoom_win,$ cube_image_win_id : cw_pzoom_win_id,$ cube_image_preg : cw_pzoom_val.plotreg,$ fixed_size : fixed_size,$ sztext_ids : sztext_ids,$ crop_h : handle_create(value=crop)} info = { int:int } xcrop_cube_oplot,info widget_control,top,set_uvalue=info handle_killer_hookup,int.crop_h ;; Will at least kill it on xkill,/all xmanager,'xcrop_cube',top,/modal handle_value,int.crop_h,crop handle_free,int.crop_h END