;+ ; $Id: scc_measure.pro,v 1.18 2021/04/08 21:47:59 thompson Exp $ ; ; Project : STEREO - SECCHI ; ; Name : SCC_MEASURE ; ; Purpose : Measure 3D coordinates from two STEREO images ; ; Category : STEREO, SECCHI, Coordinates ; ; Explanation : Widget application to allow a user to select with the cursor a ; feature appearing in both images. The selected coordinates are ; used to locate the point in three-dimensional space. ; ; The user first selects a point on one image. The program then ; displays a line on the other image representing the ; line-of-sight from the first image. The user then selects the ; point along this line with the same feature. The 3D ; coordinates are then calculated and displayed within the widget ; as (Earth-based) Stonyhurst heliographic longitude and ; latitude, along with radial distance in solar radii. ; ; In essence, this is a demonstration procedure showing how to ; derive 3D information from STEREO data. ; ; Syntax : SCC_MEASURE, FILE_AHEAD, FILE_BEHIND ; ; or ; ; SCC_MEASURE, IMAGE_AHEAD, IMAGE_BEHIND, INDEX_AHEAD, INDEX_BEHIND ; ; Examples : FILE_AHEAD = '20061101_000535_n4c1A.fts' ; FILE_BEHIND = '20061101_000535_n4c1B.fts' ; SCC_MEASURE, FILE_AHEAD, FILE_BEHIND ; ; Inputs : FILE_AHEAD = Filename for the Ahead observatory. ; FILE_BEHIND = Filename for the Behind observatory ; ; Opt. Inputs : Instead of passing the filenames, one can pass in images and ; indices which have already been read in. In that case, the ; calling parameters are: ; ; IMAGE_AHEAD = Image for the Ahead observatory ; IMAGE_BEHIND = Image for the Behind observatory ; INDEX_AHEAD = FITS index structure for Ahead ; INDEX_BEHIND = FITS index structure for Behind ; ; With this method, it's also possible to substitute data from ; SOHO or other observatories for one of the STEREO satellites. ; ; Outputs : None. ; ; Opt. Outputs: None. ; ; Keywords : WSIZE = Window size to use for displaying the images. The ; default is 512. ; ; OUTFILE = Name of file to store results in. Use the "Store" ; button to write each selected measurement into this ; file. The stored points will also be displayed on ; the images. Use the "Clear stored" button to clear ; these points out from memory. At the same time, a ; blank line will be written to the output file to mark ; the separation between collections of points. ; ; APPEND = Append to existing output file. ; ; FORCESAVE = If set, saves last results in given output ; file upon exit, even if manual 'Save' has ; or has not been used. Has no effect if no ; output file was defined. ; ; CROP = If set, restricts chosing of points to the ; inner region so that a crop to half size ; can later be done (outside of scc_measure) ; ; NO_BLOCK = Call XMANAGER with /NO_BLOCK ; ; /DEBUG print diagnostic information ; ; ; Calls : SCCREADFITS, FITSHEAD2WCS, EXPTV, SCC_MEASURE_EVENT, ; SCC_MEASURE_SELECT_1ST, SCC_MEASURE_SELECT_2ND, BOOST_ARRAY, ; SCC_MEASURE_REDISPLAY, SSC_MEASURE_REPLOT, SSC_MEASURE_CLEANUP, ; SETWINDOW, GET_TV_SCALE, WCS_GET_COORD, CONVERT_SUNSPICE_COORD ; ; Common : SCC_MEASURE = Internal common block used by the widget program. ; ; Restrictions: None. ; ; Side effects: None. ; ; Prev. Hist. : None. ; ; Written : Version 1, 21-Sep-2006, William Thompson, GSFC ; ; $Log: scc_measure.pro,v $ ; Revision 1.18 2021/04/08 21:47:59 thompson ; Use TELESCOP when OBSRVTRY is not in header, to support SDO. ; ; Revision 1.17 2020/07/07 21:27:19 thompson ; Added "freeze size" options to allow image sizes to be adjusted separately. ; ; Revision 1.15 2011/08/31 15:51:34 thompson ; Added overplotting from file ; ; Revision 1.14 2010/10/25 18:33:38 thompson ; Handle case where TELESCOP keyword is not in header. ; ; Revision 1.13 2010/09/08 13:11:25 thompson ; Updated header ; ; Revision 1.12 2010/08/30 21:25:56 nathan ; added /debug and extended common block; variable window labels; define Cunit for SOHO ; ; Revision 1.11 2010/08/26 19:52:38 nathan ; add KEYWORD_NULL=0 to fitshead2wcs call for sccreadfits case ; ; Revision 1.10 2008/10/31 15:47:09 thompson ; Include support for Earth-based observatories, and SOHOd ; ; Revision 1.9 2007/12/26 22:27:34 thompson ; Fixed minor sub-pixel bug ; ; Revision 1.8 2007/09/19 22:15:20 thompson ; Corrected plot labels ; ; Revision 1.7 2007/09/12 21:21:46 thompson ; Made no_block a keyword ; ; Revision 1.6 2007/09/12 21:09:37 thompson ; *** empty log message *** ; ; Revision 1.5 2007/09/12 21:07:16 thompson ; Added /noblock ; ; Revision 1.4 2007/07/02 22:32:50 thompson ; Add SECCHIPREP keyword, option of passing in images and headers ; ; Revision 1.3 2007/05/24 17:35:07 antunes ; New interactive cropping tools for SECCHI Cors. ; ; Revision 1.2 2007/05/24 11:08:54 antunes ; Added return of Pixel positions clicked on to save file, also set ; autosave upon exit if /forcesave given. ; ; Revision 1.1 2006/09/27 17:04:24 nathan ; moved from dev/analysis ; ; Version 2, 26-Sep-2006, William Thompson, GSFC ; Added keywords OUTFILE, APPEND. Numerous improvements. ; ; Contact : WTHOMPSON ;- ; ;============================================================================== ; pro scc_measure_redisplay, window=k_window ; ; Procure to redisplay the windows after various operations such as changing ; the color table. ; common scc_measure, ahead, h_ahead, behind, h_behind, wcs_ahead, wcs_behind, $ win_left, win_right, image_left, image_right, lon_wid, lat_wid, rsun_wid, $ zoom_wid, unzoom_wid, maxz, param, pix_param, pix_left, pix_right, $ heeq_left, heeq_right, in_progress, win_last, lzoom, rzoom, lfrz_wid, rfrz_wid, $ color, lmin, lmax, rmin, rmax, lmin_wid, lmax_wid, rmin_wid, rmax_wid, $ subimage_left, subimage_right, origin_left, origin_right, outlun, out_wid, $ clear_wid, oplot_wid, n_stored, store_left, store_right, pixpair, pixforce, $ roi, debugon ; if n_elements(k_window) eq 1 then window = k_window else window = -1 ; ; If the left (or no) window was selected, then redisplay the left window. ; if (window eq win_left) or (window eq -1) then begin setwindow, win_left get_tv_scale, sx, sy, mx, my, jx, jy tv, image_left, jx, jy if n_stored gt 0 then $ plots, store_left[0,*], store_left[1,*], psym=1, color=color endif ; ; If the right (or no) window was selected, then redisplay the right window. ; if (window eq win_right) or (window eq -1) then begin setwindow, win_right get_tv_scale, sx, sy, mx, my, jx, jy tv, image_right, jx, jy if n_stored gt 0 then $ plots, store_right[0,*], store_right[1,*], psym=1, color=color endif ; ; If no particular window was selected, and some points have been selected, ; then recreate the plots on top of the image. ; if (window eq -1) and (win_last ne '') then begin ; ; If the point selection is in progress, then plot the point on the 1st ; window, and the line on the 2nd window. ; if in_progress then begin if win_last eq 'LEFT' then begin setwindow, win_left plots, pix_left[0], pix_left[1], psym=1, symsize=3, color=color setwindow, win_right plots, pix_param[0,*], pix_param[1,*], color=color x = [0,wcs_behind.naxis[1]-1] plots, x, poly(x, param), line=1, color=color end else begin setwindow, win_right plots, pix_right[0], pix_right[1], psym=1, symsize=3, color=color setwindow, win_left plots, pix_param[0,*], pix_param[1,*], color=color x = [0,wcs_ahead.naxis[1]-1] plots, x, poly(x, param), line=1, color=color endelse ; ; Otherwise, plot both points. ; end else begin setwindow, win_left plots, pix_left[0], pix_left[1], psym=1, symsize=3, color=color setwindow, win_right plots, pix_right[0], pix_right[1], psym=1, symsize=3, color=color endelse endif ; end ; ;============================================================================== ; pro scc_measure_oplot_from_file ; ; Procedure to overplot traces already saved in the output file. ; common scc_measure ; ; Read in the file. ; infile = (fstat(outlun)).name openr, inlun, infile, /get_lun delvarx, table, iseg line = 'string' noffset0 = 0 values = dblarr(7) while not eof(inlun) do begin readf, inlun, line ; ; Only use lines containing 7 numbers. ; on_ioerror, finish_segment reads, line, values boost_array, table, values goto, next_line ; ; Otherwise, end the segment. ; finish_segment: noffset = n_elements(table) / 7 if noffset ne noffset0 then begin boost_array, iseg, noffset noffset0 = noffset endif ; next_line: ; endwhile noffset = n_elements(table) / 7 if noffset ne noffset0 then boost_array, iseg, noffset free_lun, inlun ; ; Overplot the points in the left and right windows ; for j=0,n_elements(iseg)-1 do begin if j eq 0 then i0=0 else i0 = iseg[j-1] i1 = iseg[j] - 1 setwindow, win_left plots, table[5,i0:i1], table[6,i0:i1], psym=0, color=color setwindow, win_right plots, table[3,i0:i1], table[4,i0:i1], psym=0, color=color endfor ; end ; ;============================================================================== ; pro scc_measure_replot, left=left, right=right ; ; Procedure to replot the images, e.g. after changing the image range. ; common scc_measure ; ; Unless only the right image was selected, then plot the left image. Get the ; current min and max values. ; if not keyword_set(right) then begin setwindow, win_left widget_control, lmin_wid, get_value=lmin1 widget_control, lmax_wid, get_value=lmax1 if lmax1 gt lmin1 then begin lmin = lmin1 lmax = lmax1 endif widget_control, lmin_wid, set_value=lmin widget_control, lmax_wid, set_value=lmax exptv, subimage_left, /data, /nobox, /noexact, origin=origin_left, $ min=lmin, max=lmax, bscaled=image_left endif ; ; Unless only the left image was selected, then plot the right image. Get the ; current min and max values. ; if not keyword_set(left) then begin setwindow, win_right widget_control, rmin_wid, get_value=rmin1 widget_control, rmax_wid, get_value=rmax1 if rmax1 gt rmin1 then begin rmin = rmin1 rmax = rmax1 endif widget_control, rmin_wid, set_value=rmin widget_control, rmax_wid, set_value=rmax exptv, subimage_right, /data, /nobox, /noexact, origin=origin_right, $ min=rmin, max=rmax, bscaled=image_right endif ; ; Redisplay any overplots. ; scc_measure_redisplay ; end ; ;============================================================================== ; pro scc_measure_select_1st, ev, win_1st, win_2nd, image_1st, image_2nd, $ wcs_1st, wcs_2nd, sc_1st, sc_2nd, $ heeq_1st, heeq_2nd, param_1st, pix_1st ; ; Procedure to select the first point. ; common scc_measure ; ; Start by converting from device pixels to pixels within the image. Overplot ; the selected point. ; scc_measure_redisplay, window=win_1st setwindow, win_1st pix = convert_coord(ev.x, ev.y, /device, /to_data) pix_1st = pix[0:1] if roi[9] then begin ;ROI active if (pix_1st[0] lt roi[0] or pix_1st[0] gt roi[1] or $ pix_1st[1] lt roi[2] or pix_1st[1] gt roi[3]) then begin ; out of our region of interest, force an early routine roi[8]=0 ; failed return end else begin roi[8]=1 ; success endelse endif if (sc_1st eq 'ahead') then pixpair[0:1]=pix_1st else pixpair[2:3]=pix_1st if (pixforce ne 0) then pixforce=2; mark as 'needs to be saved' plots, pix_1st[0], pix_1st[1], psym=1, symsize=3, color=color ; ; Convert from image pixel into helioprojective-cartesian coordinates, in ; radians. ; coord = wcs_get_coord(wcs_1st, pix_1st) conv = !dpi / 180.d0 case wcs_1st.cunit[0] of 'arcmin': conv = conv / 60.d0 'arcsec': conv = conv / 3600.d0 'mas': conv = conv / 3600.d3 'rad': conv = 1.d0 else: conv = conv endcase coord = coord * conv ; ; Calculate the equivalent heliocentric coordinates for distances D within ; +/- maxz of Dsun. ; dsun = wcs_1st.position.dsun_obs d = dsun + maxz * [-1,1] cosy = cos(coord[1]) x = d * cosy * sin(coord[0]) y = d * sin(coord[1]) z = dsun - d * cosy * cos(coord[0]) ; ; Determine the spacecraft parameter to pass to convert_sunspice_coord. ; spacecraft = sc_1st test = execute('header = h_'+spacecraft) obsrvtry = 'Earth' if datatype(header) eq 'STC' then begin if tag_exist(header, 'OBSRVTRY') then begin obsrvtry = header.obsrvtry end else if tag_exist(header, 'TELESCOP') then begin obsrvtry = header.telescop endif end else begin temp = fxpar(header, 'OBSRVTRY', count=count) if count gt 0 then obsrvtry = temp else begin temp = fxpar(header, 'TELESCOP', count=count) if count gt 0 then obsrvtry = temp endelse endelse spacecraft = parse_sunspice_name(obsrvtry, /earth_default) if wcs_1st.position.soho and (not wcs_1st.position.pos_assumed) then $ spacecraft = 'SOHO' IF debugon THEN print,'Selected ',coord,' ',wcs_1st.cunit[0] if debugon THEN help,dsun,spacecraft ; ; Convert to HEEQ coordinates, with rearranging into HGRTN format as an ; intermediate state. ; coord = transpose([[z],[x],[y]]) convert_sunspice_coord, wcs_1st.time.observ_date, coord, 'HGRTN', 'HEEQ', $ spacecraft=spacecraft heeq_1st = coord ; ; Determine the spacecraft parameter to pass to convert_sunspice_coord. ; spacecraft = sc_2nd test = execute('header = h_'+spacecraft) obsrvtry = 'Earth' if datatype(header) eq 'STC' then begin if tag_exist(header, 'OBSRVTRY') then begin obsrvtry = header.obsrvtry end else if tag_exist(header, 'TELESCOP') then begin obsrvtry = header.telescop endif end else begin temp = fxpar(header, 'OBSRVTRY', count=count) if count gt 0 then obsrvtry = temp else begin temp = fxpar(header, 'TELESCOP', count=count) if count gt 0 then obsrvtry = temp endelse endelse spacecraft = parse_sunspice_name(obsrvtry, /earth_default) if wcs_2nd.position.soho and (not wcs_2nd.position.pos_assumed) then $ spacecraft = 'SOHO' ; ; Switch to the other window, and convert from HEEQ to heliocentric-cartesian ; x,y,z values for the other perspective. ; scc_measure_redisplay, window=win_2nd convert_sunspice_coord, wcs_2nd.time.observ_date, coord, 'HEEQ', 'HGRTN', $ spacecraft=spacecraft x = reform(coord[1,*]) y = reform(coord[2,*]) z = reform(coord[0,*]) ; ; Convert from heliocentric-cartesian to helioprojective-cartesian. Put into ; the target units. ; dsun = wcs_2nd.position.dsun_obs d = sqrt(x^2 + y^2 + (dsun-z)^2) coord = transpose([[atan(x,dsun-z)], [asin(y/d)]]) conv = 180.d0 / !dpi case wcs_2nd.cunit[0] of 'arcmin': conv = conv * 60.d0 'arcsec': conv = conv * 3600.d0 'mas': conv = conv * 3600.d3 'rad': conv = 1.d0 else: conv = conv endcase coord = coord * conv IF debugon THEN print,'Translating to ',coord,' ',wcs_2nd.cunit[0] IF debugon THEN help,dsun,spacecraft ; ; Convert from helioprojective-cartesian to image pixel coordinates, and ; overplot the points. ; pix_param = wcs_get_pixel(wcs_2nd, coord) plots, pix_param[0,*], pix_param[1,*], color=color ; ; Extrapolate over the full X-range of the image. ; param_1st = poly_fit(pix_param[0,*], pix_param[1,*], 1) x = [0,wcs_2nd.naxis[1]-1] plots, x, poly(x, param_1st), line=1, color=color ; ; Deactivate the zoom button, and clear out the text widgets. ; widget_control, zoom_wid, sensitive=0 widget_control, out_wid, sensitive=0 widget_control, lon_wid, set_value='' widget_control, lat_wid, set_value='' widget_control, rsun_wid, set_value='' ; end ; ;============================================================================== ; pro scc_measure_select_2nd, ev, win_2nd, image_2nd, wcs_2nd, sc_2nd, $ heeq_1st, heeq_2nd, param_1st, pix_2nd ; ; Procedure to select the 2nd point. ; common scc_measure ; ; Start by converting from device pixels to pixels within the image. ; scc_measure_redisplay, window=win_2nd pix = convert_coord(ev.x, ev.y, /device, /to_data) pix = pix[0:1] ; Find the intersection between the linear fit from the other window ; (PARAM_1ST) and the orthogonal line represented by the current selection. ; Overplot the selection. ; a0 = param_1st[0] a1 = param_1st[1] x = (pix[0] + a1*(pix[1]-a0)) / (1 + a1^2) pix_2nd = [x, a0 + a1*x] ; ; Now check our region of interest again ; if roi[9] then begin ;ROI active if (pix_2nd[0] lt roi[4] or pix_2nd[0] gt roi[5] or $ pix_2nd[1] lt roi[6] or pix_2nd[1] gt roi[7]) then begin ; out of our region of interest, force an early routine roi[8]=0 ; failed return end else begin roi[8]=1 ; success end endif if (sc_2nd eq 'ahead') then pixpair[0:1]=pix_2nd else pixpair[2:3]=pix_2nd if (pixforce ne 0) then pixforce=2; mark as 'needs to be saved' plots, pix_2nd[0], pix_2nd[1], psym=1, symsize=3, color=color ; ; Convert from image pixel into helioprojective-cartesian coordinates, in ; radians. Store the angles in the common block ; coord = wcs_get_coord(wcs_2nd, pix_2nd) conv = !dpi / 180.d0 case wcs_2nd.cunit[0] of 'arcmin': conv = conv / 60.d0 'arcsec': conv = conv / 3600.d0 'mas': conv = conv / 3600.d3 'rad': conv = 1.d0 else: conv = conv endcase coord = coord * conv ; ; Calculate the equivalent heliocentric coordinates for distances D within ; +/- maxz of Dsun. ; dsun = wcs_2nd.position.dsun_obs d = dsun + maxz * [-1,1] cosy = cos(coord[1]) x = d * cosy * sin(coord[0]) y = d * sin(coord[1]) z = dsun - d * cosy * cos(coord[0]) ; ; Determine the spacecraft parameter to pass to convert_sunspice_coord. ; spacecraft = sc_2nd test = execute('header = h_'+spacecraft) obsrvtry = 'Earth' if datatype(header) eq 'STC' then begin if tag_exist(header, 'OBSRVTRY') then begin obsrvtry = header.obsrvtry end else if tag_exist(header, 'TELESCOP') then begin obsrvtry = header.telescop endif end else begin temp = fxpar(header, 'OBSRVTRY', count=count) if count gt 0 then obsrvtry = temp else begin temp = fxpar(header, 'TELESCOP', count=count) if count gt 0 then obsrvtry = temp endelse endelse spacecraft = parse_sunspice_name(obsrvtry, /earth_default) if wcs_2nd.position.soho and (not wcs_2nd.position.pos_assumed) then $ spacecraft = 'SOHO' ; ; Convert to HEEQ coordinates, with rearranging into HGRTN format as an ; intermediate state. Store the coordinates in the common block ; coord = transpose([[z],[x],[y]]) convert_sunspice_coord, wcs_2nd.time.observ_date, coord, 'HGRTN', $ 'HEEQ', spacecraft=spacecraft heeq_2nd = coord ; ; Based on the HEEQ coordinates from the left and right images, find the ; intersection on the equatorial (x-y) plane. ; p1st = poly_fit(heeq_1st[0,*], heeq_1st[1,*], 1) p2nd = poly_fit(heeq_2nd[0,*], heeq_2nd[1,*], 1) x = (p1st[0] - p2nd[0]) / (p2nd[1] - p1st[1]) y = (poly(x,p1st) + poly(x,p2nd)) / 2 ; ; Using the same point, find the Z position. ; p1st = poly_fit(heeq_1st[0,*], heeq_1st[2,*], 1) p2nd = poly_fit(heeq_2nd[0,*], heeq_2nd[2,*], 1) z = (poly(x,p1st) + poly(x,p2nd)) / 2 ; ; Populate the widgets. ; rad = sqrt(x^2 + y^2 + z^2) lon = atan(y, x) * 180 / !dpi widget_control, lon_wid, set_value=ntrim(float(lon)) lat = asin(z / rad) * 180 / !dpi widget_control, lat_wid, set_value=ntrim(float(lat)) rad = rad / 6.95508e8 widget_control, rsun_wid, set_value=ntrim(float(rad)) ; ; Activate the zoom and store buttons. ; widget_control, zoom_wid, /sensitive if outlun gt 0 then widget_control, out_wid, /sensitive ; end ; ;============================================================================== ; pro scc_measure_cleanup, id ; ; Cleanup procedure, to make sure that the output file is properly closed. ; common scc_measure if outlun gt 0 then free_lun, outlun end ; ;============================================================================== ; pro store_scc_measure common scc_measure widget_control, lon_wid, get_value=lon widget_control, lat_wid, get_value=lat widget_control, rsun_wid, get_value=rad printf, outlun, lon, lat, rad, pixpair, format='(7(F11.5,1x))' ; printf, outlun, lon, lat, rad, format='(3F5.5)' flush, outlun widget_control, out_wid, sensitive=0 widget_control, clear_wid, /sensitive widget_control, oplot_wid, /sensitive n_stored = n_stored + 1 if n_stored eq 1 then begin store_left = pix_left store_right = pix_right end else begin boost_array, store_left, pix_left boost_array, store_right, pix_right endelse end ;============================================================================== ; pro scc_measure_event, ev ; ; Widget event handler. ; common scc_measure ; widget_control, ev.id, get_uvalue=uvalue case uvalue of 'EXIT': begin if (pixforce eq 2) then store_scc_measure widget_control, /destroy, ev.top end ; 'XLOADCT': xloadct, group=ev.top, updatecallback="scc_measure_redisplay" ; ; The plot color was changed. ; 'COLOR': begin widget_control, ev.id, get_value=color color = 0 > color < (!d.table_size - 1) widget_control, ev.id, set_value=color scc_measure_replot end ; ; The left window was selected. Start by converting from device pixels to ; pixels within the image. Overplot the selected point. ; 'LEFT': if ev.press gt 0 then begin if win_last eq 'LEFT' then in_progress = 0 if in_progress then begin scc_measure_select_2nd, ev, win_left, image_left, wcs_behind, $ 'behind', heeq_right, heeq_left, param, pix_left if roi[8] or (roi[9] eq 0) then in_progress = 0 end else begin scc_measure_select_1st, ev, win_left, win_right, image_left, $ image_right, wcs_behind, wcs_ahead, 'behind', 'ahead', $ heeq_left, heeq_right, param, pix_left if roi[8] or (roi[9] eq 0) then in_progress = 1 endelse if roi[8] or (roi[9] eq 0) then win_last = 'LEFT' endif ; ; The right window was selected. Start by converting from device pixels to ; pixels within the image. ; 'RIGHT': if ev.press gt 0 then begin if win_last eq 'RIGHT' then in_progress = 0 if in_progress then begin scc_measure_select_2nd, ev, win_right, image_right, wcs_ahead, $ 'ahead', heeq_left, heeq_right, param, pix_right if roi[8] or (roi[9] eq 0) then in_progress = 0 end else begin scc_measure_select_1st, ev, win_right, win_left, image_right, $ image_left, wcs_ahead, wcs_behind, 'ahead', 'behind', $ heeq_right, heeq_left, param, pix_right if roi[8] or (roi[9] eq 0) then in_progress = 1 endelse if roi[8] or (roi[9] eq 0) then win_last = 'RIGHT' endif ; ; Modify the image ranges. ; 'LMIN': scc_measure_replot, /left 'LMAX': scc_measure_replot, /left 'RMIN': scc_measure_replot, /right 'RMAX': scc_measure_replot, /right ; ; Store any selected points. ; 'STORE': begin store_scc_measure if (pixforce ne 0) then pixforce=1; mark as 'saved' end ; ; Clear the previously stored points from memory. ; 'CLEAR': begin n_stored = 0 printf, outlun flush, outlun widget_control, clear_wid, sensitive=0 scc_measure_redisplay end ; ; Overplot previously stored points from the output file. ; 'OPLOT': scc_measure_oplot_from_file ; ; Zoom in on the previously selected points. ; 'ZOOM': begin zoomed = 0 widget_control, lfrz_wid, get_value=lfrz if (not lfrz) and (min(wcs_behind.naxis/(2*lzoom)) gt 4) then begin zoomed = 1 lzoom = lzoom * 2 naxis = wcs_behind.naxis nn = naxis / lzoom origin_left = floor(pix_left - nn/2) > 0 if origin_left[0]+nn[0] gt naxis[0] then $ origin_left[0] = naxis[0] - nn[0] if origin_left[1]+nn[1] gt naxis[1] then $ origin_left[1] = naxis[1] - nn[1] ix = origin_left[0] iy = origin_left[1] subimage_left = behind[ix:ix+nn[0]-1, iy:iy+nn[1]-1] setwindow, win_left exptv, subimage_left, /data, /nobox, /noexact, origin=origin_left, $ min=lmin, max=lmax, bscaled=image_left plots, pix_left[0], pix_left[1], psym=1, symsize=3, color=color endif ; widget_control, rfrz_wid, get_value=rfrz if (not rfrz) and (min(wcs_ahead.naxis/(2*rzoom)) gt 4) then begin zoomed = 1 rzoom = rzoom * 2 naxis = wcs_ahead.naxis nn = naxis / rzoom origin_right = floor(pix_right - nn/2) > 0 if origin_right[0]+nn[0] gt naxis[0] then $ origin_right[0] = naxis[0] - nn[0] if origin_right[1]+nn[1] gt naxis[1] then $ origin_right[1] = naxis[1] - nn[1] ix = origin_right[0] iy = origin_right[1] subimage_right = ahead[ix:ix+nn[0]-1, iy:iy+nn[1]-1] setwindow, win_right exptv, subimage_right, /data, /nobox, /noexact, origin=origin_right, $ min=rmin, max=rmax, bscaled=image_right plots, pix_right[0], pix_right[1], psym=1, symsize=3, color=color endif ; ; ; Redisplay any overplots. ; if zoomed then begin widget_control, unzoom_wid, /sensitive scc_measure_redisplay endif end ; ; Zoom out from the previously zoomed image. ; 'UNZOOM': begin unzoomed = 0 widget_control, lfrz_wid, get_value=lfrz if (not lfrz) and (lzoom gt 1) then begin unzoomed = 1 lzoom = lzoom / 2 if lzoom eq 1 then begin setwindow, win_left subimage_left = behind origin_left = [0,0] exptv, behind, /data, /nobox, /noexact, min=lmin, max=lmax, $ bscaled=image_left if not in_progress then plots, pix_left[0], pix_left[1], psym=1, $ symsize=3, color=color end else begin naxis = wcs_behind.naxis nn = naxis / lzoom origin_left = floor(pix_left - nn/2) > 0 if origin_left[0]+nn[0] gt naxis[0] then $ origin_left[0] = naxis[0] - nn[0] if origin_left[1]+nn[1] gt naxis[1] then $ origin_left[1] = naxis[1] - nn[1] ix = origin_left[0] iy = origin_left[1] subimage_left = behind[ix:ix+nn[0]-1, iy:iy+nn[1]-1] setwindow, win_left exptv, subimage_left, /data, /nobox, /noexact, min=lmin, $ max=lmax, origin=origin_left, bscaled=image_left if not in_progress then plots, pix_left[0], pix_left[1], psym=1, $ symsize=3, color=color endelse endif ; widget_control, rfrz_wid, get_value=rfrz if (not rfrz) and (rzoom gt 1) then begin unzoomed = 1 rzoom = rzoom / 2 if rzoom eq 1 then begin setwindow, win_right subimage_right = ahead origin_right = [0,0] exptv, ahead, /data, /nobox, /noexact, min=rmin, max=rmax, $ bscaled=image_right if not in_progress then plots, pix_right[0], pix_right[1], $ psym=1, symsize=3, color=color end else begin naxis = wcs_ahead.naxis nn = naxis / rzoom origin_right = floor(pix_right - nn/2) > 0 if origin_right[0]+nn[0] gt naxis[0] then $ origin_right[0] = naxis[0] - nn[0] if origin_right[1]+nn[1] gt naxis[1] then $ origin_right[1] = naxis[1] - nn[1] ix = origin_right[0] iy = origin_right[1] subimage_right = ahead[ix:ix+nn[0]-1, iy:iy+nn[1]-1] setwindow, win_right exptv, subimage_right, /data, /nobox, /noexact, min=rmin, $ max=rmax, origin=origin_right, bscaled=image_right if not in_progress then plots, pix_right[0], pix_right[1], $ psym=1, symsize=3, color=color endelse endif ; if (lzoom eq 1) and (rzoom eq 1) then widget_control, unzoom_wid, sensitive=0 ; ; Redisplay any overplots. ; if unzoomed then scc_measure_redisplay end ; ; Dummy events for the LFRZ and RFRZ checkboxes. ; 'LFRZ': 'RFRZ': ; else: message, /continue, 'Unrecognized event ' + uvalue endcase ; end ; ;============================================================================== ; pro scc_measure, file_ahead, file_behind, index_ahead, index_behind, $ wsize=k_wsize, outfile=outfile, secchiprep=secchiprep, $ append=append, forcesave=forcesave, crop=crop, $ no_block=no_block, debug=debug, _extra=_extra ; ; Main procedure to set up the widget. ; common scc_measure ; IF keyword_set(DEBUG) THEN debugon=1 ELSE debugon=0 if (n_elements(forcesave) ne 0) then pixforce=1 else pixforce=0 pixpair=fltarr(4) if (xregistered("scc_measure") NE 0) then return ; if datatype(file_ahead,1) eq 'String' then begin if keyword_set(secchiprep) then begin secchi_prep, file_ahead, h_ahead, ahead, _extra=_extra secchi_prep, file_behind, h_behind, behind, _extra=_extra end else begin ahead = sccreadfits(file_ahead, h_ahead) behind = sccreadfits(file_behind, h_behind) endelse wcs_ahead = fitshead2wcs(h_ahead,KEYWORD_NULL=0) wcs_behind = fitshead2wcs(h_behind,KEYWORD_NULL=0) end else begin ahead = file_ahead h_ahead = index_ahead wcs_ahead = fitshead2wcs(index_ahead) behind = file_behind h_behind = index_behind wcs_behind = fitshead2wcs(index_behind) endelse ; ; Get correct label for windows ; IF datatype(h_ahead) NE 'STC' THEN h_ahead=fitshead2struct(h_ahead) IF datatype(h_behind) NE 'STC' THEN h_behind=fitshead2struct(h_behind) IF tag_exist(h_ahead, 'telescop') THEN BEGIN IF h_ahead.telescop EQ 'STEREO' THEN BEGIN IF h_ahead.obsrvtry EQ 'STEREO_A' THEN scright='Ahead' ELSE $ IF h_ahead.obsrvtry EQ 'STEREO_B' THEN scright='Behind' ENDIF ELSE scright=h_ahead.telescop ENDIF ELSE scright = 'First' IF tag_exist(h_behind, 'telescop') THEN BEGIN IF h_behind.telescop EQ 'STEREO' THEN BEGIN IF h_behind.obsrvtry EQ 'STEREO_A' THEN scleft='Ahead' ELSE $ IF h_behind.obsrvtry EQ 'STEREO_B' THEN scleft='Behind' ENDIF ELSE scleft=h_behind.telescop ENDIF ELSE scleft = 'Second' ; ; LASCO level-0.5 has CUNIT undefined ; IF scright EQ 'SOHO' THEN wcs_ahead.cunit =['arcsec','arcsec'] IF scleft EQ 'SOHO' THEN wcs_behind.cunit=['arcsec','arcsec'] ; ; If setting up for cropping, store the allowable region of interest, ; otherwise defaultq region is 'the entire image' ; roi =fltarr(10) if (n_elements(crop) ne 0) then begin roi[0]=wcs_ahead.naxis[0]/4 roi[1]=3*wcs_ahead.naxis[0]/4 roi[2]=wcs_ahead.naxis[1]/4 roi[3]=3*wcs_ahead.naxis[1]/4 roi[4]=wcs_behind.naxis[0]/4 roi[5]=3*wcs_behind.naxis[0]/4 roi[6]=wcs_behind.naxis[1]/4 roi[7]=3*wcs_behind.naxis[1]/4 roi[8]=1; status flag roi[9]=1; ROI active ; also mark our ROI within the data ahead[roi[0]:roi[1],roi[2]]=max(ahead) ahead[roi[0]:roi[1],roi[3]]=max(ahead) ahead[roi[0],roi[2]:roi[3]]=max(ahead) ahead[roi[1],roi[2]:roi[3]]=max(ahead) behind[roi[4]:roi[5],roi[6]]=max(behind) behind[roi[4]:roi[5],roi[7]]=max(behind) behind[roi[4],roi[6]:roi[7]]=max(behind) behind[roi[5],roi[6]:roi[7]]=max(behind) endif ; ; Set up the main widget base. ; main = widget_base(title="SECCHI 3D coordinate measuring tool", /column) ; ; Set up the two graphics windows. ; if n_elements(k_wsize) eq 1 then wsize=k_wsize else wsize=512 show = widget_base(main, /row) lcolumn = widget_base(show, /column, /frame) dummy = widget_label(lcolumn, value=scleft) left = widget_draw(lcolumn, xsize=wsize, ysize=wsize, retain=2, $ uvalue="LEFT", /button_events) dummy = widget_base(lcolumn, /row) lmin_wid = cw_field(dummy, title='Image minimum:', xsize=15, /floating, $ uvalue='LMIN', /return_events) lmax_wid = cw_field(dummy, title='maximum:', xsize=15, /floating, $ uvalue='LMAX', /return_events) lfrz_wid = cw_bgroup(dummy, 'Freeze size', uvalue='LFRZ', /nonexclusive) ; rcolumn = widget_base(show, /column, /frame) dummy = widget_label(rcolumn, value=scright) right = widget_draw(rcolumn, xsize=wsize, ysize=wsize, retain=2, $ uvalue="RIGHT", /button_events) dummy = widget_base(rcolumn, /row) rmin_wid = cw_field(dummy, title='Image minimum:', xsize=15, /floating, $ uvalue='RMIN', /return_events) rmax_wid = cw_field(dummy, title='maximum:', xsize=15, /floating, $ uvalue='RMAX', /return_events) rfrz_wid = cw_bgroup(dummy, 'Freeze size', uvalue='RFRZ', /nonexclusive) ; ; Define a row for the output, and define fields for the heliographic ; longitude, latitude, and radial distance. ; output = widget_base(main, /row) dummy = widget_label(output, value='Heliographic') lon_wid = cw_field(output, title='Longitude:', xsize=10, /noedit) lat_wid = cw_field(output, title='Latitude:', xsize=10, /noedit) rsun_wid = cw_field(output, title='Solar radii:', xsize=10, /noedit) out_wid = widget_button(output, value='Store', uvalue='STORE') clear_wid = widget_button(output, value='Clear stored', uvalue='CLEAR') oplot_wid = widget_button(output, value='Overplot from file', uvalue='OPLOT') ; ; Define a row for buttons. Place the exit button a little off from the other ; buttons. ; control = widget_base(main, /row) dummy = widget_button(control, uvalue="XLOADCT", value='Adjust color table') zoom_wid = widget_button(control, uvalue="ZOOM", value='Zoom in') unzoom_wid = widget_button(control, uvalue="UNZOOM", value='Zoom out') color = !d.table_size - 1 color_wid = widget_slider(control, uvalue="COLOR", value=color, minimum=0, $ maximum=!d.table_size-1, title='Plot color') dummy = widget_label(control, value=" ") dummy = widget_button(control, uvalue="EXIT", Value="Exit", /frame) ; ; Realize the widget, and draw the images. ; widget_control, main, /realize widget_control, left, get_value=win_left setwindow, win_left test = sigrange(behind) lmin = min(test, max=lmax) exptv, test, /data, /nobox, /noexact, bscaled=image_left subimage_left = behind origin_left = [0,0] widget_control, lmin_wid, set_value=lmin widget_control, lmax_wid, set_value=lmax ; widget_control, right, get_value=win_right setwindow, win_right test = sigrange(ahead) rmin = min(test, max=rmax) exptv, test, /data, /nobox, /noexact, bscaled=image_right subimage_right = ahead origin_right = [0,0] widget_control, rmin_wid, set_value=rmin widget_control, rmax_wid, set_value=rmax ; setwindow, win_left ;Makes sure that plot parameters are stored. ; ; Deactivate the zoom, unzoom, and store widgets. ; widget_control, zoom_wid, sensitive=0 widget_control, unzoom_wid, sensitive=0 widget_control, out_wid, sensitive=0 widget_control, clear_wid, sensitive=0 if not keyword_set(append) then widget_control, oplot_wid, sensitive=0 ; ; Determine the maximum scale of the two images, in meters. Make sure that ; it's at least 3 solar radii ; scale0 = max(wcs_ahead.naxis*wcs_ahead.cdelt) conv = !dpi / 180.d0 case wcs_ahead.cunit[0] of 'arcmin': conv = conv / 60.d0 'arcsec': conv = conv / 3600.d0 'mas': conv = conv / 3600.d3 'rad': conv = 1.d0 else: conv = conv endcase scale0 = scale0 * conv * wcs_ahead.position.dsun_obs ; scale1 = max(wcs_behind.naxis*wcs_behind.cdelt) conv = !dpi / 180.d0 case wcs_behind.cunit[0] of 'arcmin': conv = conv / 60.d0 'arcsec': conv = conv / 3600.d0 'mas': conv = conv / 3600.d3 'rad': conv = 1.d0 else: conv = conv endcase scale1 = scale1 * conv * wcs_behind.position.dsun_obs maxz = scale0 > scale1 > 2.1e9 ; ; If the OUTFILE parameter was passed, then open a file for writing. ; if n_elements(outfile) eq 1 then $ openw, outlun, outfile, /get_lun, append=append else $ outlun = -1 ; ; Initialize some control parameters, and set the widget going. ; in_progress = 0 win_last = '' lzoom = 1 rzoom = 1 n_stored = 0 ; xmanager, 'scc_measure', main, cleanup='scc_measure_cleanup', no_block=no_block end