; file: sdo_featurelocator.pro = find (X,Y) location of an SDO feature ; init: Jan 16 2014 Rob Rutten Deil ; last: Jan 10 2021 Rob Rutten Deil ;+ ; find location coordinates of on-disk feature in an SDO image ; ; DESCRIPTION: ; Opens an SDO image on file, or from JSOC archive, or the very latest. ; Left-click in full image prints coarse coordinate values. ; Draw zoom-out box around the area of interest (also left button) ; and left-click on the feature of interest in the zoom-in image. ; The solar coordinates for the clicked location are printed in the shell: ; (X,Y) = arcsec from apparent disk center with Y along central meridian ; heliographic latitude and longitude in degrees ; Carrington rotation number and longitude in degrees ; mu = cos(theta) viewing angle ; After the first zoom window kill a 100 arcsec (X,Y) grid is overlaid. ; For file and archive images (X,Y) and mu are for the observing instant, ; for latest images for the actual click instant ("right now"). ; Kill the primary window to exit. ; ; INPUTS: ; specifier: 3 options ; archive mode: specifier='YYYY.MM.DD_HH:MM' ; get full-disk AIA or HMI image (4Kx4K) from JSOC archive ; any time from Apr 15 2010 until a week ago ; mandatory format, eg: '2013.12.21_12:00' ; latest mode: specifier='latest' ; get latest full-disk (1Kx1K ; any AIA; HMI 'magnetogram' only) ; latest means half hour ago for AIA, more for HMI magnetograms ; file mode: specifier = string path/filename of SDO image fits file ; must be level2 in my lingo (1.5 SDO lingo) with SDO-style index ; may also be a non-fulldisk cutout as in my 'target/level2' dirs ; may also be '/tmp/latestaia.fits','/tmp/latesthmi.fits' ; wav: SDO diagnostic name ; AIA: '94','131','171','193','211','304','335','1600','1700','4500' ; HMI: 'magnetogram','continuum','Dopplergram' ; (for latest mode only 'magnetogram') ; for file mode wav does not define the file but is used in intscale ; ; KEYWORD INPUT OPTIONS: ; rotate: rotate shown image over rotate degrees NWSE (clockwise); ; does not affect location measurements; eg: compare with SST ; fixfov: use fixed-size cutout (arcsec; default 0 = cut as drawn) ; start below-left of your feature, draw towards upper-right ; eg: fixfov=100 approx SST field (tiny! start close) ; raw = 1/0: if set then do not muck the intscale for better contrast ; ; OUTPUTS: ; on-screen image to draw a zoom cutout frame in and click on ; image .fits file in /tmp (JSOC name or jsoclatest.fits or omalatest.fits) ; ; METHOD: ; uses a hack of David Fanning's coyote library cgzimage.pro dd Jan 2014. ; ; RESTRICTIONS: ; needs my rridl IDL library ; https://robrutten.nl/rridl/rridl.zip ; needs David Fanning's coyote IDL library ; http://www.idlcoyote.com/documents/programs.php ; needs unix/linux curl and lynx for latest ; needs email registration at JSOC for archived ; works fine in my IDL 6.4 but may act differently in newer IDL (tell me?) ; ; HISTORY: ; Jan 23 2014 RR: start after help from David Fanning ; Jan 28 2014 RR: unreliable vso_get => ssw_jsoc_time2data ; added Carrington rotation and longitude, mu ; Apr 5 2014 RR: Carrington also for HMI ; May 31 2019 RR: latest mode, rotate, fixfov ; Jun 2 2019 RR: file mode, main-image coordinate printout ; Dec 9 2019 RR: raw (for 4500) ; Apr 24 2020 RR: use separate sdo_getimage.pro ; Jan 10 2021 RR: grid after first zoom kill ;- ; ========== hacked David Fanning coyote library cgzimage.pro ============== ;RR my (Rob Rutten) modifications marked by ;RR comment lines ; ========================================================================== ; docformat = 'rst' ; ; NAME: ; cgZImage ;RR modified below into sdo_cgzimage ; ; PURPOSE: Allows the user to interactively zoom into an ; image. Program controls are available by right-clicking in the ; full-sized image window. Zoom factors from 2x to 16x are ; available. Use the left mouse button to draw a box on the ; full-sized image to locate the region of the image to zoom. ; ;*************************************************************************** ; Copyright (c) 2010, by Fanning Software Consulting, Inc. All rights ; reserved. ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions are met: ; ; * Redistributions of source code must retain the above copyright ; notice, this list of conditions and the following disclaimer. ; * Redistributions in binary form must reproduce the above copyright ; notice, this list of conditions and the following disclaimer in the ; documentation and/or other materials provided with the distribution. ; * Neither the name of Fanning Software Consulting, Inc. nor the ; names of its contributors may be used to endorse or promote ; products derived from this software without specific prior ; written permission. ; THIS SOFTWARE IS PROVIDED BY FANNING SOFTWARE CONSULTING, INC. ''AS ; IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FANNING ; SOFTWARE CONSULTING, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, ; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ; LOSS OF USE, DATA, OR PROFITS; LOSS OF USE, DATA, OR PROFITS; OR ; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;RR America... "tort" was a new word for me ;***************************************************************************** ;+ ;RR ---------- below follow the comment blocks of the cgzimage.pro ;RR ---------- program in David Fanning's "coyote" library ; ; Allows the user to interactively zoom into an image. Program ; controls are available by right-clicking in the full-sized image ; window. Zoom factors from 2x to 16x are available. Use the left ; mouse button to draw a box on the full-sized image to locate the ; region of the image to zoom. ;RR And then leftclick on feature of interest in the zoom window ;RR [and maybe need to leftclick again on the primary full-size window] ;RR to get the full-scale pixel and solar (X,Y) etc coordinates of the ;RR clicked feature. ; ; :Categories: ; Graphics ; ; :Examples: ; Code examples:: ; IDL> image = cgDemoData(7) ; IDL> cgZImage, image ; 2D image ; IDL> image = cgDemoData(16) ; IDL> cgZImage, image ; True-Color image ; ; :Author: ; FANNING SOFTWARE CONSULTING:: ; David W. Fanning ; 1645 Sheely Drive ; Fort Collins, CO 80526 USA ; Phone: 970-221-0438 ; E-mail: david@idlcoyote.com ; Coyote's Guide to IDL Programming: http://www.idlcoyote.com ; ; :History: ; Change History:: ; Written, 20 September 2012 from previous FSC_ZImage program. DWF. ; Modernized the info structure handling to reflect modern ; sensibilities. 3 Oct 2012. DWF. ; Changes to allow this to work with very large images. Can now ; zoom to actual pixel values. Also fixed a problem that ; left zoom windows lying around unused if scroll bars were ; needed. 18 October 2012. DWF. ; The color palette was not always being included when images ; were zoomed. Fixed. 17 Nov 2012. DWF. ; Added ZoomFactor keyword to allow the zoom factor to be set ; on start-up. 28 Nov 2012. DWF. ; ; :Copyright: ; Copyright (c) 2012, Fanning Software Consulting, Inc. ;- ;+ ; Event handler for the motion events coming from the zoom ; window. Find the location and value of the image at the cursor ; location and report it to the status bar in the main image window. ; ; :Params: ; event: in, required, type=structure ; The event structure passed to the program by the window manager. ;- PRO cgZImage_ZoomWindow_Events, event ; Error handling Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg() RETURN ENDIF ; Get the info structure. Widget_Control, event.top, Get_UValue=tlb Widget_Control, tlb, Get_UValue=info ;RR addition possibleEventTypes = [ 'DOWN', 'UP', 'MOTION', 'SCROLL' ] thisEvent = possibleEventTypes[event.type] buttons = ['NONE', 'LEFT', 'MIDDLE', 'NONE', 'RIGHT'] ;RR do the following only after mouse-left click in zoom window if (thisevent eq 'DOWN') then begin ; Create the proper vectors to locate the cursor in the image. xvec = cgScaleVector(Findgen((*info).zxsize), (*info).xrange[0], (*info).xrange[1]) yvec = cgScaleVector(Findgen((*info).zysize), (*info).yrange[0], (*info).yrange[1]) xloc = 0 > Round(xvec[event.x]) < ((*info).xsize-1) yloc = 0 > Round(yvec[event.y]) < ((*info).ysize-1) ;RR call RR-added print routine printcoordinates,xloc,yloc,info ;; ; Create the text for the status bar. ;; dims = Image_Dimensions((*info).image, XSize=xsize, YSize=ysize, TrueIndex=trueindex) ;; CASE trueIndex OF ;; -1: value = ((*info).image)[xloc, yloc] ;; 0: BEGIN ;; image = Transpose((*info).image, [1,2,0]) ;; value = [(image[*,*,0])[xloc, yloc], (image[*,*,1])[xloc, yloc], (image[*,*,1])[xloc, yloc]] ;; Undefine, image ;; END ;; 1: BEGIN ;; image = Transpose((*info).image, [0,2,1]) ;; value = [(image[*,*,0])[xloc, yloc], (image[*,*,1])[xloc, yloc], (image[*,*,1])[xloc, yloc]] ;; Undefine, image ;; END ;; 2: BEGIN ;; value = [((*info).image[*,*,0])[xloc, yloc], ((*info).image[*,*,1])[xloc, yloc], ((*info).image[*,*,1])[xloc, yloc]] ;; END ;; ENDCASE ;; ;RR display line below window discarded, too small; print is better ;; ; Create the text for the statusbar widget and update the status bar. ;; IF Obj_Valid(*(*info).map) THEN BEGIN ;; *(*info).map -> GetProperty, XRANGE=xrange, YRANGE=yrange ;; xvec = cgScaleVector(Findgen((*info).xsize), xrange[0], xrange[1]) ;; yvec = cgScaleVector(Findgen((*info).ysize), yrange[0], yrange[1]) ;; ll = *(*info).map -> Inverse(xvec[xloc], yvec[yloc]) ;; loctext = 'Lat: ' + String(ll[1], Format='(F0.3)') + ' Lon: ' + String(ll[0], Format='(F0.3)') ;; ENDIF ELSE BEGIN ;; ;; loctext = 'XLoc: ' + Strtrim(xloc,2) + ' YLoc: ' + Strtrim(yloc,2) ;; loctext=sdotext ;; ENDELSE ;; imageType = Size(value, /TNAME) ;; IF imageType EQ 'BYTE' THEN value = Fix(value) ;; IF N_Elements(value) EQ 1 THEN BEGIN ;; valuetext = ' Value: ' + StrTrim(value,2) ;; ENDIF ELSE BEGIN ;; valuetext = ' RGB Value: (' + StrTrim(value[0],2) + ', ' + $ ;; StrTrim(value[1],2) + ', ' + StrTrim(value[2],2) + ')' ;; ENDELSE ;; ;RR Widget_Control, (*info).statusbar, Set_Value=loctext + valuetext ;; ;RR intensity value not of interest here ;; Widget_Control, (*info).statusbar, Set_Value=loctext ; Draw the box and a small circle to locate the cursor on the ; larger image. ;RR small circle gone? WSet, (*info).drawIndex Device, Copy=[0, 0, (*info).xsize, (*info).ysize, 0, 0, (*info).pixIndex] xvec = cgScaleVector(Findgen(!D.X_Size), 0, (*info).xsize) yvec = cgScaleVector(Findgen(!D.Y_Size), 0, (*info).ysize) xdloc = Value_Locate(xvec, xloc) ydloc = Value_Locate(yvec, yloc) cgPlotS, [(*info).xs, (*info).xs, (*info).xd, (*info).xd, (*info).xs], $ [(*info).ys, (*info).yd, (*info).yd, (*info).ys, (*info).ys], $ /Device, Color=(*info).boxcolor cgPlotS, xdloc, ydloc, /Device, PSYM='OpenCircle', Color=(*info).boxcolor, SymSize=1.5 ;RR endif else return ;RR other mouse button actions should do nothing end ; ----------------------------------------------------------------------- ;+ ; A clean-up routine for the zoom window, if the zoom window is killed. ; ; :Params: ; zoomID: in, required, type=long ; The zoom widget identifier ;- PRO cgZImage_ZoomDied, zoomID ; Come here when the zoom window dies. Basically, you ; want to erase the zoom box in the full-size window. ; Error handling Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg(/Quiet) RETURN ENDIF ; Get the TLB of the full-sized window. Widget_Control, zoomID, GET_UVALUE=tlb ; If that base is gone, disappear! IF Widget_Info(tlb, /VALID_ID) EQ 0 THEN RETURN ; Get the information you need to redisplay the image. Widget_Control, tlb, Get_UValue=info ; Redisplay the image. WSet, (*info).drawIndex cgImage, (*info).image, $ BETA=*(*info).beta, $ BOTTOM=*(*info).bottom, $ CLIP=*(*info).clip, $ EXCLUDE=*(*info).exclude, $ EXPONENT=*(*info).exponent, $ GAMMA=*(*info).gamma, $ INTERPOLATE=*(*info).interpolate, $ MAXVALUE=*(*info).max, $ MEAN=*(*info).mean, $ MISSING_COLOR=*(*info).missing_color, $ MISSING_INDEX=*(*info).missing_index, $ MISSING_VALUE=*(*info).missing_value, $ NEGATIVE=*(*info).negative, $ MINVALUE=*(*info).min, $ MULTIPLIER=*(*info).multiplier, $ NCOLORS=*(*info).ncolors, $ PALETTE=*(*info).palette, $ SCALE=*(*info).scale, $ SIGMA=*(*info).sigma, $ STRETCH=*(*info).stretch, $ TOP=*(*info).top ;RR (X,Y) grid overlay blocks 100x100 arcsec after first zoom window kill nx=4096 ny=4096 arcsecpx=0.6 xcen=0 ycen=0 xoffset=nx/2. yoffset=ny/2. xaxisarr=(indgen(nx)*float(nx)/(nx-1)-xoffset)*arcsecpx+xcen yaxisarr=(indgen(ny)*float(ny)/(ny-1)-yoffset)*arcsecpx+ycen contour,(*info).image,xaxisarr,yaxisarr,$ /nodata,/noerase,/xstyle,/ystyle,position=[0,0,1,1],$ xticklen=1,yticklen=1,xtickinterval=100,ytickinterval=100 xyouts,0.05,0.92,/norm,charsize=3,charthick=2,'(X,Y) grid 100 arcsec' oplot,[0,0],[0,0],psym=6,symsize=1.7 WSet, (*info).pixIndex Device, Copy=[0, 0, (*info).xsize, (*info).ysize, 0, 0, (*info).drawIndex] ; Clear the statusbar widget. Widget_Control, (*info).statusbar, Set_Value="" END ; ---------------------------------------------------------------------- ;+ ; Event handler for changing the rubber-band box color. ; ; :Params: ; event: in, required, type=structure ; The event structure passed to the program by the window manager. ;- PRO cgZImage_BoxColor, event ; Come here to change the selector box color. ; Error handling Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg() RETURN ENDIF ; Get the information you need to redisplay the image. Widget_Control, event.top, Get_UValue=info boxcolor = cgPickColorName((*info).boxColor, Group_Leader=event.top) (*info).boxColor = boxColor ; Redisplay the image. WSet, (*info).drawIndex cgImage, (*info).image, $ BETA=*(*info).beta, $ BOTTOM=*(*info).bottom, $ CLIP=*(*info).clip, $ EXCLUDE=*(*info).exclude, $ EXPONENT=*(*info).exponent, $ GAMMA=*(*info).gamma, $ INTERPOLATE=*(*info).interpolate, $ MAXVALUE=*(*info).max, $ MEAN=*(*info).mean, $ MISSING_COLOR=*(*info).missing_color, $ MISSING_INDEX=*(*info).missing_index, $ MISSING_VALUE=*(*info).missing_value, $ NEGATIVE=*(*info).negative, $ MINVALUE=*(*info).min, $ MULTIPLIER=*(*info).multiplier, $ NCOLORS=*(*info).ncolors, $ PALETTE=*(*info).palette, $ SCALE=*(*info).scale, $ SIGMA=*(*info).sigma, $ STRETCH=*(*info).stretch, $ TOP=*(*info).top WSet, (*info).pixIndex Device, Copy=[0, 0, (*info).xsize, (*info).ysize, 0, 0, (*info).drawIndex] ; Unmap the controls. Widget_Control, (*info).controlID, Map=0 (*info).mapcontrols = 0 END ; ---------------------------------------------------------------------- ;+ ; Event handler for changing the colors the image is displayed in. ; ; :Params: ; event: in, required, type=structure ; The event structure passed to the program by the window manager. ;- PRO cgZImage_LoadColors, event ; Come here to load colors or to respond to color loading events. ; Error handling Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg() RETURN ENDIF Widget_Control, event.top, Get_UValue=info ; What kind of event is this? thisEvent = Tag_Names(event, /Structure) ; Do the right thing. CASE thisEvent OF 'WIDGET_BUTTON': BEGIN TVLCT, (*info).r, (*info).g, (*info).b, *(*info).bottom XColors, Group=event.top, NColors = *(*info).ncolors, $ Bottom=*(*info).bottom, NotifyID=[event.id, event.top], $ Title='ZImage Colors (' + StrTrim((*info).drawIndex,2) + ')' Widget_Control, (*info).controlID, Map=0 (*info).mapcontrols = 0 END 'XCOLORS_LOAD':BEGIN ; Extract the new color table vectors from XCOLORS. (*info).r = event.r(*(*info).bottom:*(*info).bottom+*(*info).ncolors-1) (*info).g = event.g(*(*info).bottom:*(*info).bottom+*(*info).ncolors-1) (*info).b = event.b(*(*info).bottom:*(*info).bottom+*(*info).ncolors-1) ; Redisplay the image. WSet, (*info).drawIndex cgImage, (*info).image, $ BETA=*(*info).beta, $ BOTTOM=*(*info).bottom, $ CLIP=*(*info).clip, $ EXCLUDE=*(*info).exclude, $ EXPONENT=*(*info).exponent, $ GAMMA=*(*info).gamma, $ INTERPOLATE=*(*info).interpolate, $ MAXVALUE=*(*info).max, $ MEAN=*(*info).mean, $ MISSING_COLOR=*(*info).missing_color, $ MISSING_INDEX=*(*info).missing_index, $ MISSING_VALUE=*(*info).missing_value, $ NEGATIVE=*(*info).negative, $ MINVALUE=*(*info).min, $ MULTIPLIER=*(*info).multiplier, $ NCOLORS=*(*info).ncolors, $ PALETTE=*(*info).palette, $ SCALE=*(*info).scale, $ SIGMA=*(*info).sigma, $ STRETCH=*(*info).stretch, $ TOP=*(*info).top WSet, (*info).pixIndex Device, Copy=[0, 0, (*info).xsize, (*info).ysize, 0, 0, (*info).drawIndex] ; Is a zoom window open? If so, redisplay it as well. IF Widget_Info((*info).zoomDrawID, /Valid_ID) THEN BEGIN WSet, (*info).zoomWindowID IF Ptr_Valid((*info).zoomedImage) THEN BEGIN cgImage, *(*info).zoomedImage, $ BETA=*(*info).beta, $ BOTTOM=*(*info).bottom, $ CLIP=*(*info).clip, $ EXCLUDE=*(*info).exclude, $ EXPONENT=*(*info).exponent, $ GAMMA=*(*info).gamma, $ INTERPOLATE=*(*info).interpolate, $ MAXVALUE=*(*info).max, $ MEAN=*(*info).mean, $ MISSING_COLOR=*(*info).missing_color, $ MISSING_INDEX=*(*info).missing_index, $ MISSING_VALUE=*(*info).missing_value, $ NEGATIVE=*(*info).negative, $ MINVALUE=*(*info).min, $ MULTIPLIER=*(*info).multiplier, $ NCOLORS=*(*info).ncolors, $ PALETTE=*(*info).palette, $ SCALE=*(*info).scale, $ SIGMA=*(*info).sigma, $ STRETCH=*(*info).stretch, $ TOP=*(*info).top ENDIF ENDIF END ENDCASE END ; ---------------------------------------------------------------------- ;+ ; Event handler for quitting the program. ; ; :Params: ; event: in, required, type=structure ; The event structure passed to the program by the window manager. ;- PRO cgZImage_Quit, event Widget_Control, event.top, /Destroy END ; ---------------------------------------------------------------------- ;+ ; The clean-up routine for the program. Come here to release pointers and ; memory. ; ; :Params: ; tlb: in, required, type=long ; The identifier of the top-level base of the widget program. ;- PRO cgZImage_Cleanup, tlb ; The purpose of this program is to delete the pixmap window ; when the program cgZImage is destroyed. Get the info structure, ; which holds the pixmap window index number and delete the window. Widget_Control, tlb, Get_UValue=info IF N_Elements(info) NE 0 THEN BEGIN WDelete, (*info).pixIndex Ptr_Free, (*info).zoomedImage Ptr_Free, (*info).beta Ptr_Free, (*info).bottom Ptr_Free, (*info).clip Ptr_Free, (*info).exclude Ptr_Free, (*info).exponent Ptr_Free, (*info).gamma Ptr_Free, (*info).interpolate IF (*info).createdmap THEN BEGIN mapObj = *(*info).map Obj_Destroy, mapObj Ptr_Free, (*info).map ENDIF ELSE BEGIN ;RR added check to avoid warnings at quitting if Obj_Valid(*(*info).map) then mapObj = *(*info).map Ptr_Free, (*info).map ENDELSE Ptr_Free, (*info).max Ptr_Free, (*info).mean Ptr_Free, (*info).missing_color Ptr_Free, (*info).missing_index Ptr_Free, (*info).missing_value Ptr_Free, (*info).negative Ptr_Free, (*info).min Ptr_Free, (*info).multiplier Ptr_Free, (*info).ncolors Ptr_Free, (*info).palette Ptr_Free, (*info).scale Ptr_Free, (*info).sigma Ptr_Free, (*info).stretch Ptr_Free, (*info).top ENDIF END ; ---------------------------------------------------------------------- ;+ ; Event handler for changing the zoom factor. ; ; :Params: ; event: in, required, type=structure ; The event structure passed to the program by the window manager. ;- PRO cgZImage_Factor, event ; The purpose of this event handler is to set the zoom factor. ; Error handling Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg() ; Put the info structure back. IF N_Elements(info) NE 0 THEN Widget_Control, event.top, Set_UValue=info RETURN ENDIF Widget_Control, event.top, Get_UValue=info Widget_Control, event.id, Get_UValue=factor (*info).zoomfactor = factor[event.index] Widget_Control, (*info).controlID, Map=0 (*info).mapcontrols = 0 END ; ---------------------------------------------------------------------- ;+ ; Event handler for handling the rubber-band box events to create ; the zoom window. ; ; :Params: ; event: in, required, type=structure ; The event structure passed to the program by the window manager. ;- PRO cgZImage_DrawEvents, event ; This event handler continuously draws and erases the zoom box until it ; receives an UP event from the draw widget. Then it turns draw widget ; motion events OFF. ; Error handling Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg() ; Turn motion events off. Widget_Control, event.id, Draw_Motion_Events=0 RETURN ENDIF ; Get the info structure out of the top-level base. Widget_Control, event.top, Get_UValue=info ; What type of an event is this? possibleEventTypes = [ 'DOWN', 'UP', 'MOTION', 'SCROLL' ] thisEvent = possibleEventTypes[event.type] buttons = ['NONE', 'LEFT', 'MIDDLE', 'NONE', 'RIGHT'] CASE thisEvent OF 'DOWN': BEGIN ; Is this the left or right button? ; If RIGHT, then map or unmap controls. buttonPressed = buttons[event.press] IF buttonPressed EQ 'RIGHT' THEN BEGIN IF (*info).mapcontrols EQ 1 THEN BEGIN Widget_Control, (*info).controlID, Map=0 ;RR changed the below line according to Fanning email Jan 13 2014 (*info).mapcontrols = 0 ENDIF ELSE BEGIN Widget_Control, (*info).controlID, Map=1 (*info).mapcontrols = 1 ENDELSE RETURN ENDIF ; Set the static corners of the box to current ; cursor location. (*info).xs = event.x (*info).ys = event.y ;RR ------ get xloc, yloc for printout ; Make sure these are in image pixel coordinates, not just ; window pixel coordinates. x=event.x y=event.y xvec = cgScaleVector(Indgen((*info).xsize), 0, !D.X_Size-1) yvec = cgScaleVector(Indgen((*info).ysize), 0, !D.Y_Size-1) xloc = Value_Locate(xvec, x) yloc = Value_Locate(yvec, y) ;RR call RR-added printcoordinates printcoordinates,xloc,yloc,info ; Turn draw MOTION events ON. ;RR Widget_Control, event.id, Draw_Motion_Events=1 ;RR added draw_events=1 Widget_Control, event.id, Draw_Motion_Events=1, draw_button_events=1 ENDCASE ;RR end of DOWN 'UP': BEGIN ; Is this the left or right button? ; If RIGHT, then do nothing. buttonReleased = buttons[event.release] IF buttonReleased EQ 'RIGHT' THEN RETURN ; If this is an UP event, you need to erase the zoombox, turn ; motion events OFF, and draw the "zoomed" plot in both the draw ; widget and the pixmap. ; Turn motion events off. ;RR added draw_button_events=1 Widget_Control, event.id, Draw_Motion_Events=0,draw_button_events=1 ; Draw the "zoomed" image. Start by getting the LAST zoom ; box outline. These are indices into image array. event.x = 0 > event.x < ((*info).xsize - 1) event.y = 0 > event.y < ((*info).ysize - 1) x = [(*info).xs, event.x] y = [(*info).ys, event.y] ; Make sure the user didn't just click in the window. IF (*info).xs EQ event.x OR (*info).ys EQ event.y THEN BEGIN ; Erase the zoombox. WSet, (*info).drawIndex TVLCT, (*info).r, (*info).g, (*info).b ; Copy from the pximap. Device, Copy = [0, 0, (*info).xsize, (*info).ysize, 0, 0, (*info).pixIndex] RETURN ENDIF ; Make sure the x and y values are ordered as [min, max]. IF (*info).xs GT event.x THEN x = [event.x, (*info).xs] IF (*info).ys GT event.y THEN y = [event.y, (*info).ys] ; Make sure these are in image pixel coordinates, not just ; window pixel coordinates. xvec = cgScaleVector(Indgen((*info).xsize), 0, !D.X_Size-1) yvec = cgScaleVector(Indgen((*info).ysize), 0, !D.Y_Size-1) x = Value_Locate(xvec, x) y = Value_Locate(yvec, y) ;RR cut fixfov when specified if ((*info).fixfov ne 0) then begin x=[x[0],x[0]+fix((*info).fixfov/(*info).indexim.cdelt1)] y=[y[0],y[0]+fix((*info).fixfov/(*info).indexim.cdelt1)] endif (*info).xrange = x (*info).yrange = y ; Set the zoom factor and determine the new X and Y ; sizes of the Zoom Window. zoomXSize = (x[1] - x[0] + 1) * (*info).zoomFactor zoomYSize = (y[1] - y[0] + 1) * (*info).zoomFactor (*info).zxsize = zoomXSize (*info).zysize = zoomYSize ; Subset the image, and apply the zoom factor to it. CASE (*info).trueIndex OF -1: imageSubset = (*info).scaled[x[0]:x[1], y[0]:y[1]] 0: imageSubset = (*info).scaled[*, x[0]:x[1], y[0]:y[1]] 1: imageSubset = (*info).scaled[x[0]:x[1], *, y[0]:y[1]] 2: imageSubset = (*info).scaled[x[0]:x[1], y[0]:y[1], *] ENDCASE zoomedImage = cgResizeImage(imageSubset, zoomXSize, zoomYSize, Interp=0) IF Ptr_Valid((*info).zoomedImage) $ THEN *(*info).zoomedImage = zoomedImage $ ELSE (*info).zoomedImage = Ptr_New(zoomedImage, /No_Copy) ; If the Zoom Window exists, make it the proper size and load ; the zoomed image into it. If it does not exists, create it. IF Widget_Info((*info).zoomDrawID, /Valid_ID) THEN BEGIN ; If the new zoomed image needs scroll bars, or the window has ; scroll bars, destroy it and recreate it. dims = Image_Dimensions(*(*info).zoomedimage, XSIZE=ixsize, YSIZE=iysize) IF (ixsize GT (*info).maxSize) OR (iysize GT (*info).maxSize) OR ((*info).hasScrollBars) THEN BEGIN ; Get offset positions for the non-existing zoom window. Widget_Control, (*info).zoomDrawID, TLB_Get_Offset=offsets xpos = offsets[0] ypos = offsets[1] Widget_Control, (*info).zoomtlb, /Destroy ; Calculate a window size. Maximum window size is 800. dims = Image_Dimensions(*(*info).zoomedimage, XSIZE=ixsize, YSIZE=iysize) aspect = Float(ixsize)/iysize MAXSIZE = 800 IF ixsize GT MAXSIZE OR iysize GT MAXSIZE THEN BEGIN x_scroll_size = MAXSIZE < ixsize y_scroll_size = MAXSIZE < iysize (*info).hasScrollBars = 1 ; Make sure window is not off the display. maxwinsize = MaxWindowSize() IF (xpos + x_scroll_size) GT maxwinsize[0] THEN $ xpos = maxwinsize[0] - x_scroll_size IF (ypos + y_scroll_size) GT maxwinsize[1] THEN $ ypos = maxwinsize[1] - y_scroll_size ENDIF ELSE (*info).hasScrollBars = 0 ; Zoom window does not exist. Create it. zoomTLB = Widget_Base(Title='Zoomed Image', Group=event.top, $ XOffset=xpos, YOffset=ypos, $ ;RR next line back in again KILL_NOTIFY='cgZImage_ZoomDied', $ UVALUE=event.top, X_Scroll_Size=x_scroll_size, Y_Scroll_Size=y_scroll_size) ;RR add button_events zoomdraw = Widget_Draw(zoomtlb, XSize=zoomXSize, YSize=zoomYSize, $ /MOTION_EVENTS, /button_events,Event_Pro='cgZImage_ZoomWindow_Events') Widget_Control, zoomtlb, /Realize Widget_Control, zoomdraw, Get_Value=windowID (*info).zoomDrawID = zoomdraw (*info).zoomWindowID = windowID (*info).zoomTLB = zoomTLB WSet, windowID IF Ptr_Valid((*info).zoomedImage) THEN cgImage, *(*info).zoomedImage, PALETTE=*(*info).palette ;RR inserted next line following Fanning email, added group_leader XManager, "zoomwindow", zoomTLB, No_Block=1,$ CLEANUP="cgZImage_ZoomDied",group_leader=group_leader ENDIF ELSE BEGIN ; Zoomed window exists. Make it correct size and load image. Widget_Control, (*info).zoomDrawID, XSize=zoomXSize, YSize=zoomYSize WSet, (*info).zoomWindowID IF Ptr_Valid((*info).zoomedImage) THEN cgImage, *(*info).zoomedImage, PALETTE=*(*info).palette ENDELSE ENDIF ELSE BEGIN ; Get offset positions for the non-existing zoom window. Widget_Control, event.top, TLB_Get_Size=sizes, TLB_Get_Offset=offsets xpos = sizes[0] + offsets[0] + 20 ypos = offsets[1] + 40 ; Calculate a window size. Maximum window size is 800. dims = Image_Dimensions(*(*info).zoomedimage, XSIZE=ixsize, YSIZE=iysize) aspect = Float(ixsize)/iysize MAXSIZE = 800 IF ixsize GT MAXSIZE OR iysize GT MAXSIZE THEN BEGIN x_scroll_size = MAXSIZE < ixsize y_scroll_size = MAXSIZE < iysize (*info).hasScrollBars = 1 ; Make sure window is not off the display. maxwinsize = MaxWindowSize() IF (xpos + x_scroll_size) GT maxwinsize[0] THEN $ xpos = maxwinsize[0] - x_scroll_size IF (ypos + y_scroll_size) GT maxwinsize[1] THEN $ ypos = maxwinsize[1] - y_scroll_size ENDIF ELSE (*info).hasScrollBars = 0 ; Zoom window does not exist. Create it. zoomtlb = Widget_Base(Title='Zoomed Image', Group=event.top, TLB_Frame_Attr=1, $ XOffset=xpos, YOffset=ypos, KILL_NOTIFY='cgZImage_ZoomDied', $ UVALUE=event.top, X_Scroll_Size=x_scroll_size, Y_Scroll_Size=y_scroll_size) ;RR added /button_events below zoomdraw = Widget_Draw(zoomtlb, XSize=zoomXSize, YSize=zoomYSize, $ /MOTION_EVENTS, /button_events,Event_Pro='cgZImage_ZoomWindow_Events') Widget_Control, zoomtlb, /Realize Widget_Control, zoomdraw, Get_Value=windowID (*info).zoomDrawID = zoomdraw (*info).zoomWindowID = windowID (*info).zoomTLB = zoomTLB WSet, windowID IF Ptr_Valid((*info).zoomedImage) THEN cgImage, *(*info).zoomedImage, PALETTE=*(*info).palette ;RR inserted next line following Fanning email, added group_leader XManager, "zoomwindow", zoomTLB, No_Block=1,$ CLEANUP="cgZImage_ZoomDied",group_leader=group_leader ENDELSE ; If the controls were mapped, unmap them. IF (*info).mapcontrols EQ 1 THEN BEGIN Widget_Control, (*info).controlID, Map=0 (*info).mapcontrols = 0 ENDIF ENDCASE ;RR end of case UP 'MOTION': BEGIN ; Most of the action in this event handler occurs here while we are waiting ; for an UP event to occur. As long as we don't get it, keep erasing the ; old zoom box and drawing a new one. ; Erase the old zoom box. WSet, (*info).drawIndex TVLCT, (*info).r, (*info).g, (*info).b, *(*info).bottom Device, Copy = [0, 0, (*info).xsize, (*info).ysize, 0, 0, (*info).pixIndex] ; Update the dynamic corner of the zoom box to the current cursor location. (*info).xd = event.x (*info).yd = event.y ; Draw the zoom box. Device, Get_Decomposed=theState Device, Decomposed=1 PlotS, [(*info).xs, (*info).xs, (*info).xd, (*info).xd, (*info).xs], $ [(*info).ys, (*info).yd, (*info).yd, (*info).ys, (*info).ys], $ /Device, Color=cgColor((*info).boxcolor) Device, Decomposed=theState ENDCASE ENDCASE END ; ---------------------------------------------------------------------- ;RR extra pro to print solar coordinates at left-button click pro printcoordinates,xloc,yloc,info ;RR derotate location vector as measured from center if ((*info).rotate ne 0) then begin xvecrot=xloc-(*info).indexim.crpix1 yvecrot=yloc-(*info).indexim.crpix2 backrot=rotatevec([xvecrot,yvecrot],(*info).rotate) xloc=backrot[0]+(*info).indexim.crpix1 yloc=backrot[1]+(*info).indexim.crpix2 endif ;RR get solar coordinates with Markus Aschwanden's STEREO pro radius=1.001 ; rough coord_cart_helio,(*info).indexim,radius,xloc,yloc,solx,soly,carlong,carlat carrotnr=(*info).indexim.car_rot heliolong=carlong+(*info).indexim.crlt_obs-(*info).indexim.crln_obs if (carlong gt 180) then carlong=carlong-360. if (heliolong gt 180) then heliolong=heliolong-360. xystr='X,Y=' ;RR for latest differentially rotate (X,Y) up to the right-now second if ((*info).latest) then begin spawn,"date -uI'seconds' > /tmp/datenow" readcol,'/tmp/datenow',nowstr,format='A' tnow=repstr(nowstr,'+00:00','.00Z') tobs=(*info).indexim.t_obs newpos=rot_xy(solx,soly,tstart=tobs,tend=tnow) solx=newpos[0] soly=newpos[1] xystr='X,Y_now=' endif ;RR compute viewing angle mu (right now) robs=sqrt(solx^2+soly^2) rsun=(*info).indexim.rsun_obs if (robs lt rsun) then theta=asin(robs/rsun) else theta=!pi/2 muobs=abs(cos(theta)) ;RR define print line obstime=(*info).indexim.date_obs sdotext=obstime+': '$ +xystr+trimd(solx,1,/nospace)+'",'+trimd(soly,1,/nospace)+'"; '$ +'lat,long='+$ trimd(carlat,1,/nospace)+','+trimd(heliolong,1,/nospace)+'; '$ +'Car rot,long='+$ trimd(carrotnr,0,/nospace)+','+trimd(carlong,1,/nospace)+'; '$ +'mu='+trimd(muobs,2,/nospace) ;RR print solar coordinates print,' --- '+sdotext ;RR -------- end of block to give location printout for zoomed window end ; end of printcoordinates.pro ;+ ; Allows the user to interactively zoom into an image. Program ; controls are available by right-clicking in the full-sized image ; window. Zoom factors from 2x to 16x are available. Use the left ; mouse button to draw a box on the full-sized image to locate the ; region of the image to zoom. ; ; :Params: ; image: in, required, type=any ; A 2D or true-color image of any normal data type. If not a BYTE array, ; cgImage keywords for proper image scaling must be used to provide image ; scaling parameters. ; ; :Keywords: ; beta: in, optional, type=float, default=3.0 ; The beta factor in a Hyperpolic Sine stretch. Available only with 2D images. ; bottom: in, optional, type=integer, default=0 ; If the SCALE keyword is set, the image is scaled before display so that all ; displayed pixels have values greater than or equal to BOTTOM and less than ; or equal to TOP. Available only with 2D images. ; boxcolor: in, optional, type=string, default='gold' ; The name of the color of the rubber-band selection box. ; clip: in, optional, type=float, default=2 ; A number between 0 and 50 that indicates the percentage of pixels to clip ; off either end of the image histogram before performing a linear stretch. ; Available only with 2D images. ; exclude: in, optional, type=numeric ; The value to exclude in a standard deviation stretch. ; exponent: in, optional, type=float, default=4.0 ; The logarithm exponent in a logarithmic stretch. Available only with 2D images. ; filename: in, optional, type=string ; The name of a file that IDL can read with READ_IMAGE (e.g, GEOTIFF, TIF, JPEG, PNG, etc.). ; gamma: in, optional, type=float, default=1.5 ; The gamma factor in a gamma stretch. Available only with 2D images. ; group_leader: in, optional, type=long ; The widget identifier of the group leader for this program. When the group leader ; dies, this program will be destroyed, too. ; interpolate: in, optional, type=boolean, default=0 ; Set this keyword to interpolate with bilinear interpolation the display image as it ; is sized to its final position in the display window. Interpolation will potentially ; create image values that do not exist in the original image. The default is to do no ; interpolation, so that image values to not change upon resizing. Interpolation can ; result in smoother looking final images. ; map: in, optional, type=structure ; A cgMap object for navigating the input image. ; maxvalue: in, optional, type=varies ; If this value is defined, the data is linearly scaled between MINVALUE ; and MAXVALUE. MAXVALUE is set to MAX(image) by default. Setting this ; keyword to a value automatically sets `SCALE` to 1. If the maximum value of the ; image is greater than 255, this keyword is defined and SCALE=1. ; mean: in, optional, type=float, default=0.5 ; The mean factor in a logarithmic stretch. Available only with 2D images. ; minvalue: in, optional, type=varies ; If this value is defined, the data is linearly scaled between MINVALUE ; and `MAXVALUE`. MINVALUE is set to MIN(image) by default. Setting this ; keyword to a value automatically sets SCALE=1. If the minimum value of the ; image is less than 0, this keyword is defined and SCALE=1. ; missing_color: in, optional, type=string, default='white' ; The color name of the missing value. Available only with 2D images. ; missing_index: in, optional, type=integer, default=255 ; The index of the missing color in the final byte scaled image. Available only with 2D images. ; missing_value: in, optional, type=integer ; The number that represents the missing value in the image. Available only with 2D images. ; multiplier: in, optional, type=float ; The multiplication factor in a standard deviation stretch. The standard deviation ; is multiplied by this factor to produce the thresholds for a linear stretch. ; ncolors: in, optional, type=integer, default=256 ; If this keyword is supplied, the `TOP` keyword is ignored and the TOP keyword ; is set equal to NCOLORS-1. This keyword is provided to make cgImage easier ; to use with the color-loading programs such as cgLOADCT:: ; ; cgLoadCT, 5, NColors=100, Bottom=100 ; cgImage, image, NColors=100, Bottom=100 ; ; Setting this keyword to a value automatically sets SCALE=1. Available only with 2D images. ; negative: in, optional, type=boolean, default=0 ; Set this keyword if you want to display the image with a negative or reverse stretch. ; Available only with 2D images. ; palette: in, optional, type=byte ; Set this keyword to a 3x256 or 256x3 byte array containing the RGB color ; vectors to be loaded before the image is displayed. Such vectors can be ; obtained, for example, from cgLoadCT with the RGB_TABLE keyword:: ; ; cgLoadCT, 4, /BREWER, /REVERSE, RGB_TABLE=palette ; cgImage, cgDemoData(7), PALETTE=palette ; scale: in, optional, type=boolean, default=0 ; Set this keyword to byte scale the image before display. If this keyword is not set, ; the image is not scaled before display. This keyword will be set automatically by using ; any of the keywords normally associated with byte scaling an image. Available only with ; 2D images. If set, STRETCH is set to 1, unless it is set to another value. ; stretch: in, optional, type=integer/string, default=1 ; The type of scaling performed prior to display. May be specified as a number ; or as a string (e.g, 3 or "Log"). Available only with 2D images. ; ; Number Type of Stretch ; 0 None No scaling whatsoever is done. ; 1 Linear scaled = BytScl(image, MIN=minValue, MAX=maxValue) ; 2 Clip A histogram stretch, with a percentage of pixels clipped at both the top and bottom ; 3 Gamma scaled = GmaScl(image, MIN=minValue, MAX=maxValue, Gamma=gamma) ; 4 Log scaled = LogScl(image, MIN=minValue, MAX=maxValue, Mean=mean, Exponent=exponent) ; 5 Asinh scaled = AsinhScl(image, MIN=minValue, MAX=maxValue, Beta=beta) ; 6 SquareRoot A linear stretch of the square root histogram of the image values. ; 7 Equalization A linear stretch of the histogram equalized image histogram. ; 8 Gaussian A Gaussian normal function is applied to the image histogram. ; 9 MODIS Scaling done in the differential manner of the MODIS Rapid Response Team ; and implemented in the Coyote Library routine ScaleModis. ; sigma: in, optional, type=float, default=1.0 ; The sigma scale factor in a Gaussian stretch. Available only with 2D images. ; title: in, optional, type=string, default="" ; Set this keyword to the title of the plot window. ; top: in, optional, type=integer, default=255 ; If the SCALE keyword is set, the image is scaled before display so that all ; displayed pixels have values greater than or equal to BOTTOM and less than ; or equal to TOP. Available only with 2D images. ; zoomfactor: in, optional, type=string, default=3 ; Use this keyword to set the starting zoom factor. The values you can use are as follows:: ; 0: 'Actual' ; 1: '2x' ; 2: '3x' ; 3: '4x' ; 4: '5x' ; 5: '6x' ; 6: '7x' ; 7: '8x' ; 8: '12x' ; 9: '16x' ; ;- ;RR modified pro name, added indexim etc PRO sdo_cgZImage, indexim, image, rotate, latest, fixfov, $ BETA=beta, $ BOTTOM=bottom, $ BOXCOLOR=sboxcolor, $ CLIP=clip, $ EXCLUDE=exclude, $ EXPONENT=exponent, $ FILENAME=filename, $ GAMMA=gamma, $ GROUP_LEADER=group_leader, $ INTERPOLATE=interpolate, $ MAP=map, $ MAXVALUE=max, $ MEAN=mean, $ MISSING_COLOR=missing_color, $ MISSING_INDEX=missing_index, $ MISSING_VALUE=missing_value, $ NEGATIVE=negative, $ MINVALUE=min, $ MULTIPLIER=multiplier, $ NCOLORS=ncolors, $ PALETTE=palette, $ SCALE=scale, $ SIGMA=sigma, $ STRETCH=stretch, $ TITLE=title, $ TOP=top, $ ZOOMFACTOR=zoomfactor Compile_Opt idl2 ; Error handling Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg() RETURN ENDIF ; Was a filename used to pass in an image filename? Check to see if this is a GeoTiff image ; before doing anything else. If it is, use cgGeoMap to read it. Otherwise, read the image ; file with READ_IMAGE. IF N_Elements(filename) NE 0 THEN BEGIN check = Query_Tiff(filename, GEOTIFF=geo) IF (check EQ 1) && (Size(geo, /TNAME) EQ 'STRUCT') THEN BEGIN map = cgGeoMap(filename, IMAGE=image, Palette=palette) createdMap = 1 ENDIF ELSE BEGIN image = Read_Image(filename, r, g, b) IF N_Elements(r) NE 0 THEN palette = [[r],[g],[b]] ENDELSE ENDIF IF N_Elements(createdMap) EQ 0 THEN createdMap = 0 ; Was an image passed into the procedure? ; If not, find one in the IDL examples/data directory. IF N_Elements(image) EQ 0 THEN BEGIN image = ImageSelect(FILENAME='marsglobe.jpg', CANCEL=cancelled, /EXAMPLES) IF cancelled THEN RETURN ENDIF ; Make sure this is a 2D or true-color image. ndims = Size(image, /N_DIMENSIONS) IF (ndims LT 2) || (ndims GT 3) THEN Message, 'Only 2D or True-Color images are allowed in cgZImage.' ; Get image size. dims = Image_Dimensions(image, XSize=ixsize, YSize=iysize, $ XIndex=xindex, YIndex=yindex, TrueIndex=trueindex) IF trueIndex NE -1 THEN nframes = dims[trueIndex] ELSE nframes = 1 IF nframes GT 3 THEN BEGIN Help, image Message, 'Image does not have the correct dimensions for cgZImage.' ENDIF ; Check for keywords. IF N_Elements(sboxcolor) EQ 0 THEN boxcolor = 'gold' ELSE boxcolor = sboxcolor IF N_Elements(stretch) EQ 0 THEN BEGIN maxValue = Max(image, MIN=minValue) IF (minValue LT 0) || (maxValue GT 255) THEN stretch=1 ENDIF IF N_Elements(zoomfactor) EQ 0 THEN zoomfactor = 3 ELSE zoomfactor = 0 > zoomfactor < 9 ; Calculate a window size. Maximum window size is 600. aspect = Float(ixsize)/iysize MAXSIZE = 600 IF ixsize GT MAXSIZE OR iysize GT MAXSIZE THEN BEGIN IF ixsize NE iysize THEN BEGIN aspect = Float(iysize) / ixsize IF aspect LT 1 THEN BEGIN xsize = MAXSIZE ysize = (MAXSIZE * aspect) < MAXSIZE ENDIF ELSE BEGIN ysize = MAXSIZE xsize = (MAXSIZE / aspect) < MAXSIZE ENDELSE ENDIF ELSE BEGIN ysize = MAXSIZE xsize = MAXSIZE ENDELSE ENDIF ELSE BEGIN xsize = ixsize ysize = iysize ENDELSE ; Check cgImage keywords. IF N_Elements(beta) EQ 0 THEN betaptr = Ptr_New(/Allocate_Heap) ELSE betaptr = Ptr_New(beta) IF N_Elements(bottom) EQ 0 THEN bottomptr = Ptr_New(/Allocate_Heap) ELSE bottomptr = Ptr_New(bottom) IF N_Elements(clip) EQ 0 THEN clipptr = Ptr_New(/Allocate_Heap) ELSE clipptr = Ptr_New(clip) IF N_Elements(exclude) EQ 0 THEN excludeptr = Ptr_New(/Allocate_Heap) ELSE excludeptr = Ptr_New(exclude) IF N_Elements(exponent) EQ 0 THEN exponentptr = Ptr_New(/Allocate_Heap) ELSE exponentptr = Ptr_New(exponent) IF N_Elements(gamma) EQ 0 THEN gammaptr = Ptr_New(/Allocate_Heap) ELSE gammaptr = Ptr_New(gamma) IF N_Elements(interpolate) EQ 0 THEN interpolateptr = Ptr_New(/Allocate_Heap) ELSE interpolateptr = Ptr_New(interpolate) IF N_Elements(map) EQ 0 THEN mapptr = Ptr_New(/Allocate_Heap) ELSE mapptr = Ptr_New(map) IF N_Elements(max) EQ 0 THEN maxptr = Ptr_New(/Allocate_Heap) ELSE maxptr = Ptr_New(max) IF N_Elements(mean) EQ 0 THEN meanptr = Ptr_New(/Allocate_Heap) ELSE meanptr = Ptr_New(mean) IF N_Elements(missing_color) EQ 0 THEN missing_colorptr = Ptr_New(/Allocate_Heap) ELSE missing_colorptr = Ptr_New(missing_color) IF N_Elements(missing_index) EQ 0 THEN missing_indexptr = Ptr_New(/Allocate_Heap) ELSE missing_indexptr = Ptr_New(missing_index) IF N_Elements(missing_value) EQ 0 THEN missing_valueptr = Ptr_New(/Allocate_Heap) ELSE missing_valueptr = Ptr_New(missing_value) IF N_Elements(negative) EQ 0 THEN negativeptr = Ptr_New(/Allocate_Heap) ELSE negativeptr = Ptr_New(negative) IF N_Elements(min) EQ 0 THEN minptr = Ptr_New(/Allocate_Heap) ELSE minptr = Ptr_New(min) IF N_Elements(multiplier) EQ 0 THEN multiplierptr = Ptr_New(/Allocate_Heap) ELSE multiplierptr = Ptr_New(multiplier) IF N_Elements(ncolors) EQ 0 THEN ncolorsptr = Ptr_New(/Allocate_Heap) ELSE ncolorsptr = Ptr_New(ncolors) IF N_Elements(palette) EQ 0 THEN paletteptr = Ptr_New(/Allocate_Heap) ELSE paletteptr = Ptr_New(palette) IF N_Elements(scale) EQ 0 THEN scaleptr = Ptr_New(/Allocate_Heap) ELSE scaleptr = Ptr_New(scale) IF N_Elements(sigma) EQ 0 THEN sigmaptr = Ptr_New(/Allocate_Heap) ELSE sigmaptr = Ptr_New(sigma) IF N_Elements(stretch) EQ 0 THEN stretchptr = Ptr_New(/Allocate_Heap) ELSE stretchptr = Ptr_New(stretch) IF N_Elements(top) EQ 0 THEN topptr = Ptr_New(/Allocate_Heap) ELSE topptr = Ptr_New(top) ; Create a top-level base for this program. No resizing of this base. tlb = Widget_Base(TLB_Frame_Attr=1, TITLE=title) ; Create two bases. One for controls and the other for the ; draw widget. Leave the control base unmapped for now. controlID = Widget_Base(tlb, Map=0, Column=1) factorString = ['Actual', '2x', '3x', '4x', '5x', '6x', '7x', '8x', '12x', '16x'] factors = [Indgen(8) + 1, 12, 16] zoomfactorID = Widget_DropList(controlID, Value=factorString, $ Event_Pro='cgZImage_Factor', UValue=factors, Title='Zoom Factor') IF trueindex EQ -1 THEN BEGIN colors = Widget_Button(controlID, Value='Load Image Colors', Event_Pro='cgZImage_LoadColors') ENDIF void = Widget_Button(controlID, Value='Change Selection Box Color', Event_Pro='cgZImage_BoxColor') quitter = Widget_Button(controlID, Value='Exit Program', $ Event_Pro='cgZImage_Quit') drawbase = Widget_Base(tlb, Map=1, Column=1) drawID = Widget_Draw(drawbase, XSize=xsize, YSize=ysize, $ Button_Events=1, Event_Pro='cgZImage_DrawEvents') statusbar = Widget_Label(drawbase, Value="Ready for Zooming", SCR_XSIZE=xsize, /Sunken_Frame) ; Realize the program. Widget_Control, tlb, /Realize ; Set the initial default zoom factor. Widget_Control, zoomfactorID, SET_DROPLIST_SELECT=zoomfactor ; Get the window index number of the draw widget. ; Make the draw widget the current graphics window ; and display the image in it. Widget_Control, drawID, Get_Value=drawIndex WSet, drawIndex ;RR added next line: rotate; IDL rot.pro does degrees clockwise if (rotate ne 0) then image=rot(image,rotate,cubic=-0.5) cgImage, image, $ BETA=*betaptr, $ BOTTOM=*bottomptr, $ CLIP=*clipptr, $ EXCLUDE=*excludeptr, $ EXPONENT=*exponentptr, $ GAMMA=*gammaptr, $ INTERPOLATE=*interpolateptr, $ MAXVALUE=*maxptr, $ MEAN=*meanptr, $ MISSING_COLOR=*missing_colorptr, $ MISSING_INDEX=*missing_indexptr, $ MISSING_VALUE=*missing_valueptr, $ NEGATIVE=*negativeptr, $ MINVALUE=*minptr, $ MULTIPLIER=*multiplierptr, $ NCOLORS=*ncolorsptr, $ PALETTE=*paletteptr, $ SCALE=*scaleptr, $ SIGMA=*sigmaptr, $ STRETCH=*stretchptr, $ TOP=*topptr ; Set the title of the window. IF N_Elements(title) EQ 0 THEN BEGIN Widget_Control, tlb, TLB_Set_Title='Full Size Image (' + StrTrim(drawIndex,2) + ') -- ' + $ 'Right Click for Controls.' ENDIF ; Set the current zoom factor factor = factors[zoomfactor] ; Create a pixmap window the same size as the draw widget window. ; Store its window index number in a local variable. Display the ; image you just put in the draw widget in the pixmap window. Window, /Free, XSize=xsize, YSize=ysize, /Pixmap pixIndex = !D.Window cgImage, image, $ BETA=*betaptr, $ BOTTOM=*bottomptr, $ CLIP=*clipptr, $ EXCLUDE=*excludeptr, $ EXPONENT=*exponentptr, $ GAMMA=*gammaptr, $ INTERPOLATE=*interpolateptr, $ MAXVALUE=*maxptr, $ MEAN=*meanptr, $ MISSING_COLOR=*missing_colorptr, $ MISSING_INDEX=*missing_indexptr, $ MISSING_VALUE=*missing_valueptr, $ NEGATIVE=*negativeptr, $ MINVALUE=*minptr, $ MULTIPLIER=*multiplierptr, $ NCOLORS=*ncolorsptr, $ PALETTE=*paletteptr, $ SCALE=*scaleptr, $ SIGMA=*sigmaptr, $ STRETCH=*stretchptr, $ TOP=*topptr ; Get color vectors for this application. IF N_Elements(r) EQ 0 THEN TVLCT, r, g, b, /Get ; Scale the data, because this is what you will show in the zoomed window. scaled = cgImgScl(image, $ BETA=*betaptr, $ BOTTOM=*bottomptr, $ CLIP=*clipptr, $ EXCLUDE=*excludeptr, $ EXPONENT=*exponentptr, $ GAMMA=*gammaptr, $ INTERPOLATE=*interpolateptr, $ MAXVALUE=*maxptr, $ MEAN=*meanptr, $ MISSING_INDEX=*missing_indexptr, $ MISSING_VALUE=*missing_valueptr, $ NEGATIVE=*negativeptr, $ MINVALUE=*minptr, $ MULTIPLIER=*multiplierptr, $ NCOLORS=*ncolorsptr, $ SCALE=*scaleptr, $ SIGMA=*sigmaptr, $ STRETCH=*stretchptr, $ TOP=*topptr) ; Create an info structure to hold information required by the program. info = Ptr_New( { $ ;RR added the first bunch indexim:indexim, $ rotate:rotate, $ latest:latest, $ fixfov:fixfov, $ image:image, $ ; The original image. scaled:scaled, $ ; The scaled image. zoomedimage:Ptr_New(), $ ; The scaled and resized subimage. xsize:ixsize, $ ; The x size of the image. ysize:iysize, $ ; The y size of the image. drawIndex:drawIndex, $ ; The draw window index number. pixIndex:pixIndex, $ ; The pixmap window index number. boxcolor:boxcolor, $ ; The name of the drawing color. xs:0, $ ; X static corner of the zoom box. ys:0, $ ; Y static corner of the zoom box. xd:0, $ ; X dynamic corner of the zoom box. yd:0, $ ; Y dynamic corner of the zoom box. zoomDrawID:-1L, $ ; Zoomed image draw widget ID. zoomWindowID:-1, $ ; Zoomed image window index number. zoomTLB: -1, $ ; The zoom window TLB. statusbar:statusbar, $ ; The statusbar identifier. r:r, $ ; The red color vector. g:g, $ ; The green color vector. b:b, $ ; The blue color vector. beta:betaptr, $ bottom:bottomptr, $ clip:clipptr, $ createdMap: createdmap, $ exclude:excludeptr, $ exponent:exponentptr, $ gamma:gammaptr, $ interpolate:interpolateptr, $ map:mapptr, $ max:maxptr, $ mean:meanptr, $ missing_color:missing_colorptr, $ missing_index:missing_indexptr, $ missing_value:missing_valueptr, $ negative:negativeptr, $ min:minptr, $ multiplier:multiplierptr, $ ncolors:ncolorsptr, $ palette:paletteptr, $ scale:scaleptr, $ sigma:sigmaptr, $ stretch:stretchptr, $ top:topptr, $ xrange: [0,ixsize], $ yrange: [0,iysize], $ zxsize: 0, $ zysize: 0, $ zoomfactor:factor, $ ; The initial zoom factor. mapcontrols:0, $ ; A flag to tell if the controls are mapped. xindex:xindex, $ ; The X size index. yindex:yindex, $ ; The Y size index. trueIndex:trueIndex, $ ; The "true-color" index. 0 if image is 2D. MAXSIZE:800, $ ; The maximum window size. hasScrollBars: 0, $ ; A flag indicating the zoom window has scroll bars. controlID:controlID}, /No_Copy) ; The identifier of the control base to map. ; Store the info structure in the user value of the top-level base. Widget_Control, tlb, Set_UValue=info ; Register this program and set up the event loop. XManager, 'cgzimage', tlb, Cleanup='cgZImage_Cleanup', Group_Leader=group_leader, /No_Block END ; ---------------------------------------------------------------------- ; =================== MAIN CALL =================== pro sdo_featurelocator,specifier,wav,rotate=rotate,$ fixfov=fixfov,raw=raw ; answer a no-parameter query if (n_params() lt 2) then begin sp,sdo_featurelocator return endif ; default keywords if (n_elements(rotate) eq 0) then rotate=0 if (n_elements(fixfov) eq 0) then fixfov=0 if (n_elements(raw) eq 0) then raw=0 ; get image (no /intpolpair, better have original frame) sdo_getimage,specifier,wav,im,indexim,raw=raw,latest=latest ; wavnr business ; define permitted level2 fitsfilename strings (rrwavnr = index+1: ; 94,131,171,193,211,304,335,1600,1700,4500,mag,cont,dop ; 1 2 3 4 5 6 7 8 9 10 11 12 13 wavs=['94','131','171','193','211','304','335',$ ; rrwav 1-7 = AIA EUV '1600','1700','4500',$ ; rrwav 8-10 = AIA UV 'magnetogram','continuum','Dopplergram'] ; rrwav 11-13 = HMI nwavs=n_elements(wavs) ; check input sdowavs and fill rrwav array iwav=-1 for iw=0,nwavs-1 do if (wavs[iw] eq wav) then iwav=iw if (iwav eq -1 ) then begin print,' ===== ERROR: sdowav invalid = ',wav print,' ===== valid: ',wavs return endif rrwav=iwav+1 ; pretty up if (rrwav lt 11) then im=histo_opt_rr(im,1E-4) if (rrwav eq 8 or rrwav eq 9) then im=sqrt(im>1) if (rrwav eq 11) then im=im>(-100)<100 ; print instruction print,' --- draw zoom box around feature of interest (ll to ur for fixfov)' print,' --- in the zoom image click on feature of interest' print,' --- its solar coordinates are printed in shell (terminal)' ; enter image into hacked version above of David Fanning's cgzimage.pro forward_function coord_cart_helio ; bloody IDL sdo_cgzimage,indexim,im,rotate,latest,fixfov end ; =================== main for tests per IDLWAVE H-c ====================== ;; wav='171' ;; wav='94' wav='magnetogram' ;; wav='1700' ;; wav='1600' ;; wav='304' ;; wav='4500' ;; wav='continuum' ;; sdo_featurelocator,'2017.09.16_03:00',wav ;; sdo_featurelocator,'2018.06.22_08:20',wav ;; sdo_featurelocator,'2017.09.06_11:35',wav ;; sdo_featurelocator,'latest',wav,raw=0,rotate=60,fixfov=100 ; SST like ;; sdo_featurelocator,'/tmp/latestaia.fits',wav ; after the above ;; sdo_featurelocator,'2019.11.11_15:23','continuum' sdo_featurelocator,'2018.04.12_15:57','magnetogram' ; ALMA Costas end