#pragma rtGlobals=3 // Use modern global access method and strict wave access. #pragma IgorVersion = 6.2 #pragma ModuleName = PearlAreaDisplay #pragma version = 1.04 /// @file /// @brief visualization tools for 2D and 3D data. /// @ingroup ArpesPackage /// /// these tools were initially developed for monitoring output from EPICS area detector software. /// they are, however, useful for any kind of intensity versus x,y(,z) data. /// /// @section sec_2d 2D data /// /// TO DO... /// /// @section sec_3d 3D data /// // 3D data is handled by 3 windows. they don't have to be visible all at the same time. /// * 3D graphics in a Gizmo window /// * 2D graphics with profiles /// * Slicer panel /// /// data dictionary of global variables /// in view_xxxx folder: /// * gizmo_graphname = name of the gizmo window /// * slice_graphname = name of the slice/profiles graph window /// * slice_panelname = name of the slicer panel /// /// @section sec_misc Miscellaneous /// /// scienta HDF5 import, display, and slicer how-to /// @verbatim /// ad_display_brick(root:x03da_scienta_20130821_01560:data) /// ad_scale_scienta(root:x03da_scienta_20130821_01560:data) /// ad_scale_extra(root:x03da_scienta_20130821_01560:data,root:x03da_scienta_20130821_01560:MonoEnergy,root:x03da_scienta_20130821_01560:data) /// ad_display_brick(root:x03da_scienta_20130821_01560:data) /// ad_brick_slicer(root:x03da_scienta_20130821_01560:data, "gizmo_x03da_scienta_20130821_01") /// @endverbatim /// /// @author matthias muntwiler, matthias.muntwiler@psi.ch /// /// @copyright 2013-15 Paul Scherrer Institut @n /// Licensed under the Apache License, Version 2.0 (the "License"); @n /// you may not use this file except in compliance with the License. @n /// You may obtain a copy of the License at /// http://www.apache.org/licenses/LICENSE-2.0 /// @namespace PearlAreaDisplay /// @brief instant visualization of angle scan and manipulator position. /// /// PearlAreaDisplay is declared in @ref pearl-area-display.ipf. /// /// compose a valid and unique graph name from a data folder reference static function /s graphname_from_dfref(df, prefix) dfref df string prefix string name name = GetDataFolder(1, df) name = ReplaceString("root:", name, "") name = name[0, strlen(name) - 2] name = ReplaceString(" ", name, "") name = CleanupName(prefix + name, 0) if (CheckName(name, 6)) name = UniqueName(name, 6, 0) endif return name end /// open a new graph window with a 2D image. /// /// this is essentially display; appendimage. /// the graph is directly linked to the image wave. /// it is, thus, updated automatically. /// /// @param image wave which contains the image data. /// /// @return (string) name of the graph window /// function /s ad_display(image) wave image // wave which contains the image data from the detector // returns the name of the graph window dfref savedf = GetDataFolderDFR() dfref imagedf = GetWavesDataFolderDFR(image) setdatafolder imagedf string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "") string graphtitle = dfname + " View" string /g view_graphname = graphname_from_dfref(imagedf, "view_") svar graphname = view_graphname display /k=1/n=$graphname as graphtitle graphname = s_name appendimage /w=$graphname image setdatafolder savedf return graphname end /// display the histogram of a 2D image. /// /// the function will create additional objects in the same data folder as the image. /// this objects are displayed in the graph and are updated by calling ad_calc_profiles(). /// see the code. /// /// @param image wave which contains the image data from the detector. /// /// @return (string) name of the graph window /// function /s ad_display_histogram(image) wave image dfref savedf = GetDataFolderDFR() dfref imagedf = GetWavesDataFolderDFR(image) string s_imagedf = GetDataFolder(1, imagedf) setdatafolder imagedf make /n=(1)/o hist // histogram string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "") string graphtitle = dfname + " Histogram" string /g hist_graphname = graphname_from_dfref(imagedf, "hist_") svar graphname = hist_graphname display /k=1/n=$graphname as graphtitle graphname = s_name appendtograph /w=$graphname hist ModifyGraph /w=$graphname rgb(hist)=(39168,0,0) ModifyGraph /w=$graphname mode=6 ModifyGraph /w=$graphname mirror=1 ModifyGraph /w=$graphname minor=1 ModifyGraph /w=$graphname axThick=0.5 ModifyGraph /w=$graphname lblPosMode=1,lblPos=30,lblMargin=0 ModifyGraph /w=$graphname btLen=4 ModifyGraph /w=$graphname margin(left)=45,margin(bottom)=35,margin(top)=10,margin(right)=10 ModifyGraph /w=$graphname gfSize=10 Label /w=$graphname bottom "value" Label /w=$graphname left "# pixels" ad_calc_histogram(image) setdatafolder savedf return graphname end /// open a new profiles graph window. /// /// opens an extended graph window with profiles for the specified image. /// the function copies/creates all necessary data structures in a subfolder /// of the one which contains the image wave. /// the data folder name is derived from the image wave name by prefixing with "view_". /// there can be at most one profiles window of each image wave. /// the original wave must not be renamed while the graph window is used. /// to update the graph after modifying the original wave, call ad_update_profiles(). /// /// @param image wave which contains the image data. /// @param filter name of a filter function which maps the original data to the displayed data. /// the function must have the same parameters as ad_default_image_filter(). /// default: boxcar average (ad_box_filter()) using parameters view_filter_smoothing_x and _y. /// @return name of the graph window function /s ad_display_profiles(image, [filter]) wave image string filter variable show_legend = 0 // currently not supported if (WaveDims(image) != 2) abort "ad_display_profiles: image wave must be two-dimensional." endif if (ParamIsDefault(filter)) filter = "ad_box_filter" endif // data folders and references dfref savedf = GetDataFolderDFR() dfref imagedf = GetWavesDataFolderDFR(image) string s_imagedf = GetDataFolder(1, imagedf) setdatafolder imagedf string s_viewdf = CleanupName("view_" + NameOfWave(image), 0) newdatafolder /o/s $s_viewdf dfref viewdf = GetDataFolderDFR() s_viewdf = GetDataFolder(1, viewdf) // data structures string /g sourcepath = GetWavesDataFolder(image, 2) string viewname = "view_image" duplicate /o image, $viewname /wave=view make /n=(3,3)/o xprofiles // NX x 3 wave with 3 one-dimensional profiles along Y dimension make /n=(3,3)/o yprofiles // NY x 3 wave with 3 one-dimensional profiles along X dimension string /g view_filter string /g view_filter_options view_filter = filter view_filter_options = "" variable /g view_filter_smoothing_x = 1 variable /g view_filter_smoothing_y = 1 variable /g view_cursor_mode = 0 string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "") string graphtitle = dfname + NameOfWave(image) + " Profiles" string /g prof_graphname = graphname_from_dfref(imagedf, "prof_") svar graphname = prof_graphname variable /g graph_avg // average value in ROI (ROI is defined by the crosshairs A and B) variable /g graph_min // minimum value in ROI variable /g graph_max // maximum value in ROI variable /g graph_sum // sum of all values in ROI variable /g graph_sdev // standard deviation of all values in ROI // graph setup display /k=1 /n=$graphname /w=(100,100,500,400) as graphtitle graphname = s_name AppendToGraph /w=$graphname /L=xprofiles xprofiles[*][0],xprofiles[*][1],xprofiles[*][2] AppendToGraph /w=$graphname /VERT/B=yprofiles yprofiles[*][0],yprofiles[*][1],yprofiles[*][2] AppendImage /w=$graphname view string imgname = StringFromList(0, ImageNameList(graphname, ";")) ModifyImage /w=$graphname $imgname ctab= {*,*,BlueGreenOrange,0} ModifyGraph /w=$graphname rgb(xprofiles)=(39168,0,0),rgb(yprofiles)=(39168,0,0) ModifyGraph /w=$graphname rgb(xprofiles#1)=(0,26112,0),rgb(yprofiles#1)=(0,26112,0) ModifyGraph /w=$graphname rgb(xprofiles#2)=(0,9472,39168),rgb(yprofiles#2)=(0,9472,39168) ModifyGraph /w=$graphname mirror(xprofiles)=2,mirror(bottom)=3,mirror(yprofiles)=2,mirror(left)=3 ModifyGraph /w=$graphname nticks=3 ModifyGraph /w=$graphname minor=1 ModifyGraph /w=$graphname axThick=0.5 ModifyGraph /w=$graphname lblPosMode=1,lblPos=30,lblMargin=0 ModifyGraph /w=$graphname btLen=4 ModifyGraph /w=$graphname freePos(xprofiles)=0 ModifyGraph /w=$graphname freePos(yprofiles)=0 ModifyGraph /w=$graphname axisEnab(xprofiles)={0.64,1} ModifyGraph /w=$graphname axisEnab(bottom)={0,0.6} ModifyGraph /w=$graphname axisEnab(yprofiles)={0.64,1} ModifyGraph /w=$graphname axisEnab(left)={0,0.6} ModifyGraph /w=$graphname zero(left)=8 ModifyGraph /w=$graphname margin(left)=40,margin(bottom)=30,margin(top)=20,margin(right)=40 ModifyGraph /w=$graphname gfSize=10 // axis labels string labels = note(image) string lab lab = StringByKey("AxisLabelX", labels, "=", "\r") if (!strlen(lab)) lab = "X" endif Label /w=$graphname bottom lab + " (\\U)" lab = StringByKey("AxisLabelY", labels, "=", "\r") if (!strlen(lab)) lab = "Y" endif Label /w=$graphname left lab + " (\\U)" lab = StringByKey("AxisLabelD", labels, "=", "\r") if (!strlen(lab)) lab = "value" endif Label /w=$graphname xprofiles lab + " (\\U)" Label /w=$graphname yprofiles lab + " (\\U)" // legend if (show_legend) Legend /w=$graphname/C/N=text0/J/F=2/D=0.5/T={28}/A=RT/X=0.00/Y=0.00 "\\s(xprofiles)\tprofile A" AppendText /w=$graphname "\\s(xprofiles#1)\tprofile B" AppendText /w=$graphname "\\s(xprofiles#2)\tROI average" AppendText /w=$graphname "min\t\\{" + s_viewdf + "graph_min}" AppendText /w=$graphname "max\t\\{" + s_viewdf + "graph_max}" AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}" AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}" AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}" else TextBox /w=$graphname /C/N=text0 /F=0 /B=1 /X=1.00 /Y=1.00 lab = StringByKey("Dataset", labels, "=", "\r") if (strlen(lab)) AppendText /w=$graphname lab endif AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}" AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}" AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}" endif // interactive elements Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 A $imgname 0,0 Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 B $imgname DimSize(view, 0)-1, DimSize(view, 1)-1 variable pcurs pcurs = floor(DimSize(xprofiles, 0) / 3) Cursor /w=$graphname /A=0 /P /S=1 /H=0 C xprofiles#2 pcurs pcurs = floor(DimSize(xprofiles, 0) * 2 / 3) Cursor /w=$graphname /A=0 /P /S=1 /H=0 D xprofiles#2 pcurs pcurs = floor(DimSize(yprofiles, 0) / 3) Cursor /w=$graphname /A=0 /P /S=1 /H=0 E yprofiles#2 pcurs pcurs = floor(DimSize(yprofiles, 0) * 2 / 3) Cursor /w=$graphname /A=0 /P /S=1 /H=0 F yprofiles#2 pcurs ShowInfo /w=$graphname /CP=0 SetWindow $graphname, hook(ad_profiles_hook)=ad_profiles_hook ControlBar /w=$graphname 21 Button b_reset_cursors win=$graphname, title="reset cursors",pos={0,0},size={70,20},proc=PearlAreaDisplay#bp_reset_cursors Button b_reset_cursors win=$graphname, fColor=(65535,65535,65535),fSize=10 SetVariable sv_smoothing_x win=$graphname, title="X smoothing",pos={130,2},bodyWidth=40 SetVariable sv_smoothing_x win=$graphname, value=view_filter_smoothing_x,limits={1,100,1} SetVariable sv_smoothing_x win=$graphname, proc=PearlAreaDisplay#svp_smoothing SetVariable sv_smooting_y win=$graphname, title="Y smoothing",pos={240,2},bodyWidth=40 SetVariable sv_smooting_y win=$graphname, value=view_filter_smoothing_y,limits={1,100,1} SetVariable sv_smooting_y win=$graphname, proc=PearlAreaDisplay#svp_smoothing PopupMenu pm_export win=$graphname, mode=0,title="Export" PopupMenu pm_export win=$graphname, value="X profile;Y profile;X profile (collate);Y profile (collate)" PopupMenu pm_export win=$graphname, pos={308,0},bodyWidth=60,proc=PearlAreaDisplay#pmp_export PopupMenu pm_export win=$graphname, help={"Export profile of selected area and display in graph. Collate mode = display all profiles in same graph."} // data processing ad_update_profiles(image) setdatafolder savedf return graphname end /// update a profiles graph with new data. /// /// @param image wave which contains the image data. /// must be the same (by data folder and name) wave used with ad_display_profiles(). /// function ad_update_profiles(image) wave image // data folders and references dfref viewdf = get_view_folder(image) if (DataFolderRefStatus(viewdf) == 0) return -1 // data folder not found endif dfref savedf = GetDataFolderDFR() setdatafolder viewdf // data structures string viewname = "view_image" duplicate /o image, $viewname /wave=view // data processing svar view_filter svar view_filter_options nvar smoothing_x = view_filter_smoothing_x nvar smoothing_y = view_filter_smoothing_y funcref ad_default_image_filter filterfunc = $view_filter view_filter_options = ReplaceNumberByKey("SmoothingX", view_filter_options, smoothing_x, "=", ";") view_filter_options = ReplaceNumberByKey("SmoothingY", view_filter_options, smoothing_y, "=", ";") filterfunc(view, view_filter_options) ad_calc_cursor_profiles(view) setdatafolder savedf return 0 end /// switch cursors on a profiles graph /// /// the standard cursors allow to select the profiles to display in the profiles panes. /// additional cursors are shown in the profiles panes. /// /// in the background selection mode, additional cursors allow the user to select /// the limits of the background and peak integration regions. /// the meaning of the cursors depends on the particular processing function. /// /// @param mode cursor mode. /// @arg 0 (default) standard profile selection. cursors C-F on profile panes. /// @arg 1 background selection. cursors A-F on image. /// /// @param image image displayed in the graph. /// this is the original image, not the one in the view data folder. /// function ad_profiles_cursor_mode(image, mode) wave image variable mode dfref savedf = GetDataFolderDFR() wave view_image = get_view_image(image) dfref viewdf = GetWavesDataFolderDFR(view_image) svar /sdfr=viewdf graphname = prof_graphname nvar /sdfr=viewdf cursor_mode = view_cursor_mode wave /sdfr=viewdf xprofiles, yprofiles variable dx = DimSize(view_image, 0) variable dy = DimSize(view_image, 1) switch(mode) case 1: // background selection Cursor /w=$graphname /A=0 /P /I /S=2 /H=1 /L=1 A view_image 0, 0 Cursor /w=$graphname /A=0 /P /I /S=2 /H=1 /L=1 B view_image dx-1, dy-1 Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 C view_image round(0.2 * dx) -1, 0 Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 D view_image round(0.8 * dx) -1, 0 Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 E view_image round(0.4 * dx) -1, 0 Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 F view_image round(0.6 * dx) -1, 0 ShowInfo /w=$graphname /CP=0 cursor_mode = mode break default: Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 A view_image 0,0 Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 B view_image dx-1, dy-1 variable pcurs pcurs = floor(DimSize(xprofiles, 0) / 3) Cursor /w=$graphname /A=0 /P /S=1 /H=0 C xprofiles#2 pcurs pcurs = floor(DimSize(xprofiles, 0) * 2 / 3) Cursor /w=$graphname /A=0 /P /S=1 /H=0 D xprofiles#2 pcurs pcurs = floor(DimSize(yprofiles, 0) / 3) Cursor /w=$graphname /A=0 /P /S=1 /H=0 E yprofiles#2 pcurs pcurs = floor(DimSize(yprofiles, 0) * 2 / 3) Cursor /w=$graphname /A=0 /P /S=1 /H=0 F yprofiles#2 pcurs ShowInfo /w=$graphname /CP=0 cursor_mode = 0 endswitch setdatafolder savedf return 0 end /// move a cursor to the specified position in a profiles graph. /// /// this function can only set cursors in the image part of the profiles graph. /// /// @param image image displayed in the graph. /// this is the original image, not the one in the view data folder. /// @param cursorname name of the cursor, e.g. "A" or "B". /// other cursors are allowed but need to be activated separately. /// @param xa x-coordinate to move the cursor to. /// the position is coerced to the image scale. +/-inf is allowed. /// @param ya y-coordinate to move the cursor to. /// the position is coerced to the image scale. +/-inf is allowed. /// @param pscale scaling of the position argument /// @arg 0 (default) wave scaling /// @arg 1 point scaling /// function ad_profiles_set_cursor(image, cursorname, xa, ya, [pscale]) wave image string cursorname variable xa, ya variable pscale if (ParamIsDefault(pscale)) pscale = 0 endif // data folders and references dfref savedf = GetDataFolderDFR() wave view_image = get_view_image(image) dfref viewdf = GetWavesDataFolderDFR(view_image) svar /sdfr=viewdf graphname = prof_graphname variable pa, qa if (pscale) pa = xa qa = ya else pa = round((xa - DimOffset(view_image, 0)) / DimDelta(view_image, 0)) qa = round((ya - DimOffset(view_image, 1)) / DimDelta(view_image, 1)) endif pa = min(pa, DimSize(view_image, 0) - 1) pa = max(pa, 0) qa = min(qa, DimSize(view_image, 1) - 1) qa = max(qa, 0) Cursor /i /p /w=$graphname $cursorname view_image pa, qa setdatafolder savedf return 0 End /// draw permanent crosshairs in a profiles graph. /// /// adds dash-dotted horizontal and vertical crosshairs to a profiles graph. /// for each active cursor A and/or B, a pair of lines crossing at the cursor position is added. /// existing crosshairs are moved to the current cursor positions. /// optionally, existing crosshairs are removed from the graph. /// /// in contrast to the cursors, these crosshairs will be exported and printed with the graph. /// they are drawn using Igor's DrawLine operation. /// all lines drawn by this function are part of the "crosshairs" draw group. // the lines can be removed manually using the draw toolbox, or by calling this function with @c clean=1. /// /// @param image image displayed in the graph. /// this is the original image, not the one in the view data folder. /// @param clear 0 (default) = add/update lines. /// 1 = remove lines. /// function ad_profiles_crosshairs(image, [clear]) wave image variable clear if (ParamIsDefault(clear)) clear = 0 endif // data folders and references wave view_image = get_view_image(image) dfref viewdf = GetWavesDataFolderDFR(view_image) svar /sdfr=viewdf graphname = prof_graphname string cursors = "A;B" string colors = "39168,0,0;0,26112,0" string color variable ncursors variable icursor string cursorname string groupname = "crosshairs" variable xx, yy struct RGBColor rgb if (clear == 0) SetDrawEnv /W=$graphname push DrawAction /w=$graphname getgroup=$groupname, delete, begininsert SetDrawEnv /w=$graphname gstart, gname=$groupname SetDrawEnv /W=$graphname dash=4 SetDrawEnv /W=$graphname linethick=0.5 ncursors = ItemsInList(cursors, ";") for (icursor=0; icursor < ncursors; icursor += 1) cursorname = StringFromList(icursor, cursors, ";") color = StringFromList(icursor, colors, ";") rgb.red = str2num(StringFromList(0, color, ",")) rgb.green = str2num(StringFromList(1, color, ",")) rgb.blue = str2num(StringFromList(2, color, ",")) if (strlen(CsrInfo($cursorname, graphname)) > 0) xx = hcsr($cursorname, graphname) yy = vcsr($cursorname, graphname) SetDrawEnv /W=$graphname linefgc=(rgb.red, rgb.green, rgb.blue) SetDrawEnv /W=$graphname save SetDrawEnv /W=$graphname xcoord=bottom, ycoord=prel DrawLine /W=$graphname xx, 0, xx, 1 SetDrawEnv /W=$graphname xcoord=prel, ycoord=left DrawLine /W=$graphname 0, yy, 1, yy endif endfor SetDrawEnv /w=$graphname gstop DrawAction /w=$graphname endinsert SetDrawEnv /W=$graphname pop SetDrawEnv /W=$graphname save else DrawAction /w=$graphname getgroup=$groupname, delete endif return 0 end /// find the source image wave corresponding to the given view. /// /// @return wave reference of the original data wave. /// the reference may be invalid if the source wave cannot be found. /// static function /wave get_source_image(view) wave view // image wave displayed in a profiles window dfref viewdf = GetWavesDataFolderDFR(view) svar /z /sdfr=viewdf sourcepath if (svar_exists(sourcepath)) wave /z img = $sourcepath else wave /z img = $"" endif return img end /// create a view data folder. static function /df make_view_folder(source) wave source // wave which contains the raw data from the detector. // data folders and references dfref savedf = GetDataFolderDFR() dfref imagedf = GetWavesDataFolderDFR(source) string s_imagedf = GetDataFolder(1, imagedf) setdatafolder imagedf string s_viewdf = CleanupName("view_" + NameOfWave(source), 0) newdatafolder /o/s $s_viewdf dfref viewdf = GetDataFolderDFR() setdatafolder savedf return viewdf end /// find the view data folder corresponding to the given source. /// /// the result data folder reference may be invalid if no view is currently open. /// use the built-in DataFolderRefStatus function to check for validity. /// /// @param source wave which contains the image data. /// must be the same (by data folder and name) wave used with ad_display_profiles(). /// static function /df get_view_folder(source) wave source // data folders and references dfref savedf = GetDataFolderDFR() dfref imagedf = GetWavesDataFolderDFR(source) dfref viewdf setdatafolder imagedf string s_viewdf = CleanupName("view_" + NameOfWave(source), 0) if (DataFolderExists(s_viewdf)) setdatafolder $s_viewdf viewdf = GetDataFolderDFR() endif setdatafolder savedf return viewdf end /// find the view image wave corresponding to the given source. /// /// @param source wave which contains the image data. /// must be the same (by data folder and name) wave used with ad_display_profiles(). /// static function /wave get_view_image(source) wave source dfref viewdf = get_view_folder(source) string viewname = "view_image" wave /sdfr=viewdf view = $viewname return view end static function bp_reset_cursors(ba) : ButtonControl STRUCT WMButtonAction &ba switch( ba.eventCode ) case 2: // mouse up string imgname = StringFromList(0, ImageNameList(ba.win, ";")) wave /z image = ImageNameToWaveRef(ba.win, imgname) if (waveexists(image)) Cursor /i/p A $imgname 0,0 Cursor /i/p B $imgname DimSize(image, 0)-1, DimSize(image, 1)-1 endif break case -1: // control being killed break endswitch return 0 End static function svp_smoothing(sva) : SetVariableControl STRUCT WMSetVariableAction &sva string imglist switch( sva.eventCode ) case 1: // mouse up case 2: // Enter key case 3: // Live update imglist = ImageNameList(sva.win, ";") wave /z img = ImageNameToWaveRef(sva.win, StringFromList(0, imglist)) if (WaveExists(img)) wave source = get_source_image(img) if (WaveExists(source)) ad_update_profiles(source) endif endif break case -1: // control being killed break endswitch return 0 end static function pmp_export(pa) : PopupMenuControl STRUCT WMPopupAction &pa switch( pa.eventCode ) case 2: // mouse up variable popNum = pa.popNum string imgname = StringFromList(0, ImageNameList(pa.win, ";")) wave /z image = ImageNameToWaveRef(pa.win, imgname) if (waveexists(image) && (popNum >= 1) && (popNum <= 2)) ad_export_profile(image, popNum - 1, show=1) elseif (waveexists(image) && (popNum >= 3) && (popNum <= 4)) ad_export_profile(image, popNum - 3, show=2) endif break case -1: // control being killed break endswitch return 0 End /// hook function for user events in the profiles window. function ad_profiles_hook(s) struct WMWinHookStruct &s variable hookresult = 0 string imglist string cmd dfref viewdf switch(s.eventCode) case 2: // delete data folder after window is killed imglist = ImageNameList(s.winName, ";") wave /z img = ImageNameToWaveRef(s.winName, StringFromList(0, imglist)) if (WaveExists(img)) viewdf = GetWavesDataFolderDFR(img) cmd = "killdatafolder /z " + GetDataFolder(1, viewdf) Execute /P/Q/Z cmd endif break case 7: // update profiles when cursor is moved imglist = ImageNameList(s.winName, ";") wave /z img = ImageNameToWaveRef(s.winName, StringFromList(0, imglist)) if (WaveExists(img)) ad_calc_cursor_profiles(img) hookresult = 1 else hookresult = 0 endif break endswitch return hookresult end /// calculate profiles, statistics, and histogram of a cross-hair delimited region of interest. /// /// @param image wave which contains the image data from the detector. /// /// the function expects further objects as created by ad_display_profiles() /// in the same data folder as the image wave. /// the most recent profiles graph of the image must exist, /// and the cursors A and B must be set on the image. function ad_calc_cursor_profiles(image) wave image dfref savedf = GetDataFolderDFR() dfref imagedf = GetWavesDataFolderDFR(image) setdatafolder imagedf svar graphname = prof_graphname variable pa, qa // point coordinates cursor A if (strlen(CsrInfo(A, graphname)) > 0) pa = pcsr(A, graphname) qa = qcsr(A, graphname) else pa = 0 qa = 0 endif variable pb, qb // point coordinates cursor B if (strlen(CsrInfo(B, graphname)) > 0) pb = pcsr(B, graphname) qb = qcsr(B, graphname) else pb = DimSize(image, 0) - 1 qb = DimSize(image, 1) - 1 endif ad_calc_profiles(image, pa, qa, pb, qb) setdatafolder savedf end /// calculate profiles, statistics, and histogram of a rectangular region of interest. /// /// the region of interest a rectangle spanned by the two points A and B. /// pixels at these coordinates are included. /// /// @param image wave which contains the image data. /// @param pa first point coordinate of A. /// @param qa second point coordinate of A. /// @param pb first point coordinate of B. /// @param qb second point coordinate of B. /// /// the function expects further objects as created by ad_display_profiles() /// in the same data folder as the image wave. /// /// this function does not require that the graph exists as long as the data folder is complete. /// function ad_calc_profiles(image, pa, qa, pb, qb) wave image variable pa, qa variable pb, qb dfref savedf = GetDataFolderDFR() dfref imagedf = GetWavesDataFolderDFR(image) setdatafolder imagedf wave xprofiles wave yprofiles nvar graph_avg nvar graph_min nvar graph_max nvar graph_sum nvar graph_sdev // horizontal profiles at crosshairs redimension /n=(dimsize(image,0), 3) xprofiles setscale /p x dimoffset(image,0), dimdelta(image,0), WaveUnits(image,0), xprofiles setscale d 0, 0, waveunits(image,-1), xprofiles xprofiles[][0] = image[p][qa] xprofiles[][1] = image[p][qb] note /k xprofiles note xprofiles, "SourceWave=" + nameofwave(image) note xprofiles, "SourceDimension=0" note xprofiles, "SourceIndex0=" + num2str(qa) note xprofiles, "SourceIndex1=" + num2str(qb) // average horizontal profile between crosshairs variable qq, q0, q1 q0 = min(qa, qb) q1 = max(qa, qb) xprofiles[][2] = 0 for (qq = q0; qq <= q1; qq += 1) xprofiles[][2] += image[p][qq] endfor xprofiles[][2] /= q1 - q0 + 1 // vertical profiles at crosshairs redimension /n=(dimsize(image,1), 3) yprofiles setscale /p x dimoffset(image,1), dimdelta(image,1), WaveUnits(image,1), yprofiles setscale d 0, 0, waveunits(image,-1), yprofiles yprofiles[][0] = image[pa][p] yprofiles[][1] = image[pb][p] note /k yprofiles note yprofiles, "SourceWave=" + nameofwave(image) note yprofiles, "SourceDimension=1" note yprofiles, "SourceIndex0=" + num2str(pa) note yprofiles, "SourceIndex1=" + num2str(pb) // average vertical profile between crosshairs variable pp, p0, p1 p0 = min(pa, pb) p1 = max(pa, pb) yprofiles[][2] = 0 for (pp = p0; pp <= p1; pp += 1) yprofiles[][2] += image[pp][p] endfor yprofiles[][2] /= p1 - p0 + 1 // statistics between crosshairs Duplicate /r=[p0,p1][q0,q1]/o image, roi_image WaveStats /Q roi_image graph_avg = v_avg graph_min = v_min graph_max = v_max graph_sum = v_avg * v_npnts graph_sdev = v_sdev // histogram wave /z hist if (waveexists(hist)) Histogram /B=3 roi_image, hist endif setdatafolder savedf end /// export a profile from a profiles graph to the source data folder. /// /// this function does not require that the show exists as long as the view data folder is complete. /// /// @param view_image wave which contains the view image (image wave on display in profiles window). /// the function expects further objects as created by ad_display_profiles() /// in the same data folder as the view_image wave. /// @param dim dimension index (0 = x, 1 = y). /// @param trace select profile trace: /// * 0 = cursor A /// * 1 = cursor B /// * 2 = average between cursors (default) /// @param show display mode: /// * 0 = do not show (default) /// * 1 = display in new graph, or append to existing graph /// * 2 = collate: common graph for all profiles of a dimension. /// rename graph manually to detach it from future additions. /// @param overwrite overwrite mode: /// * 0 = create new wave (default). wave name may get a suffix to be unique. /// * 1 = overwrite existing wave /// function ad_export_profile(view_image, dim, [trace, show, overwrite]) wave view_image variable dim variable trace variable show variable overwrite dfref savedf = GetDataFolderDFR() if (ParamIsDefault(trace)) trace = 2 endif if (ParamIsDefault(show)) show = 0 endif if (ParamIsDefault(overwrite)) overwrite = 0 endif // view folder dfref imagedf = GetWavesDataFolderDFR(view_image) string dim_label switch(dim) case 0: wave /sdfr=imagedf profiles=xprofiles dim_label = "x" break case 1: wave /sdfr=imagedf profiles=yprofiles dim_label = "y" break default: return -1 // invalid argument endswitch string graphname_string = "export_graph_" + dim_label svar /z /sdfr=imagedf linked_graphname = $graphname_string // source folder wave /z source_image = get_source_image(view_image) if (WaveExists(source_image)) dfref sourcedf = GetWavesDataFolderDFR(source_image) setdatafolder sourcedf else return -2 // invalid source data folder endif // format dest wave name string profile_note = note(profiles) string name_base string name_dim string name_index string profile_name variable index_width = ceil(log(DimSize(view_image, 1 - dim))) variable index0 = NumberByKey("SourceIndex0", profile_note, "=", "\r") variable index1 = NumberByKey("SourceIndex1", profile_note, "=", "\r") name_dim = "_" + dim_label sprintf name_index, "%0*u_%0*u", index_width, index0, index_width, index1 name_base = NameOfWave(source_image) name_base = name_base[0, min(strlen(name_base), 31 - strlen(name_index) - strlen(name_dim) - 1)] profile_name = name_base + name_dim + name_index if ((overwrite == 0) && (CheckName(profile_name, 1))) profile_name = UniqueName(profile_name + "_", 1, 0) endif // create dest wave duplicate /o /r=[][trace] profiles, $profile_name /wave=dest_profile redimension /n=(dimsize(profiles, 0)) dest_profile profile_note = ReplaceStringByKey("SourceWave", profile_note, NameOfWave(source_image), "=", "\r") note /k dest_profile note dest_profile, profile_note print "created", GetWavesDataFolder(dest_profile, 2) if (show) string graphname string graphtitle if (show == 2) // common graph for all profiles of a dimension graphname = "export_profiles_" + dim_label graphtitle = UpperStr(dim_label) + " Profiles" else // one graph per source image if (svar_exists(linked_graphname) && (ItemsInList(WinList(linked_graphname, ";", "WIN:1"), ";") >= 1)) graphname = linked_graphname else graphname = GetWavesDataFolder(source_image, 0) + name_dim endif graphtitle = UpperStr(dim_label) + " Profiles: " + GetWavesDataFolder(source_image, 2) endif if ((ItemsInList(WinList(graphname, ";", "WIN:1"), ";") >= 1)) appendtograph /w=$graphname dest_profile else setdatafolder imagedf display /k=1 /n=$graphname dest_profile as graphtitle graphname = s_name ModifyGraph /w=$graphname mirror=1,nticks=3,minor=1 ModifyGraph /w=$graphname axThick=0.5,btLen=4 ModifyGraph /w=$graphname gfSize=10 ModifyGraph /w=$graphname grid=2,gridHair=0,gridRGB=(52224,52224,52224) Legend /w=$graphname /C/N=legend0/F=0/B=1/A=LT/X=0.00/Y=0.00 if (show != 2) string /g $graphname_string = graphname endif endif endif setdatafolder savedf return 0 end static function set_trace_colors(graphname) string graphname ModifyGraph /w=$graphname /z rgb[0]=(0, 0, 0) ModifyGraph /w=$graphname /z rgb[1]=(65535, 16385, 16385) ModifyGraph /w=$graphname /z rgb[2]=(2, 39321, 1) ModifyGraph /w=$graphname /z rgb[3]=(0, 0, 65535) ModifyGraph /w=$graphname /z rgb[4]=(39321, 1, 31457) ModifyGraph /w=$graphname /z rgb[5]=(48059, 48059, 48059) ModifyGraph /w=$graphname /z rgb[6]=(65535, 32768, 32768) ModifyGraph /w=$graphname /z rgb[7]=(0, 65535, 0) ModifyGraph /w=$graphname /z rgb[8]=(16385,65535,65535) ModifyGraph /w=$graphname /z rgb[9]=(65535, 32768, 58981) end /// calculate the histogram. /// /// @param image wave which contains the image data from the detector. /// the function expects further objects as created by ad_display_histogram() /// in the same data folder as the image wave. /// function ad_calc_histogram(image) wave image dfref savedf = GetDataFolderDFR() dfref imagedf = GetWavesDataFolderDFR(image) setdatafolder imagedf wave hist Histogram /B=3 image, hist setdatafolder savedf end /// abstract filter function for image display. /// /// this is a function prototype for filtering two-dimensional data for preview. /// to write your own filter, define a new function which has the same signature. /// /// @param image image to be filtered: original data and filter result. /// @param options filter options in key1=value1;key2=value2;... format. /// /// @return the result must be written to the incoming image wave. /// function ad_default_image_filter(image, options) wave image string options end /// boxcar smoothing filter. /// /// filters the image in X and Y directions using Igor's Smooth operation. /// /// @param image image to be filtered: original data and filter result. /// @param options smoothing factors in key1=value1;key2=value2;... format. /// * SmoothingX /// * SmoothingY /// function ad_box_filter(image, options) wave image string options variable xsmoothing = NumberByKey("SmoothingX", options, "=", ";") variable ysmoothing = NumberByKey("SmoothingY", options, "=", ";") if ((NumType(xsmoothing) == 0) && (xsmoothing >= 2)) Smooth /B /DIM=0 /E=3 xsmoothing, image endif if ((NumType(ysmoothing) == 0) && (ysmoothing >= 2)) Smooth /B /DIM=1 /E=3 ysmoothing, image endif end /// transpose image filter. /// /// transposes the image. /// /// @param image image to be transposed: original data and result. /// @param options not used. should be empty. /// function ad_transpose_filter(image, options) wave image string options MatrixTranspose image end // ################### 3D DATA ################## /// open a new "gizmo" window with three-dimensional data. /// /// @param data three-dimensional wave. /// /// @return name of the gizmo window. /// function /s ad_display_brick(data) wave data if(exists("NewGizmo") != 4) abort "Gizmo XOP must be installed." endif if (WaveDims(data) != 3) abort "ad_display_brick: data must be three-dimensional." endif dfref savedf = GetDataFolderDFR() dfref datadf = GetWavesDataFolderDFR(data) string s_datadf = GetDataFolder(1, datadf) dfref viewdf = make_view_folder(data) setdatafolder viewdf string dfname = ReplaceString("root:", s_datadf, "") string graphtitle = dfname + " Gizmo" string /g gizmo_graphname = graphname_from_dfref(datadf, "giz_") svar graphname = gizmo_graphname if ((strlen(graphname) > 0) && (wintype(graphname) == 13)) setdatafolder savedf return graphname // gizmo window exists endif variable nx = dimsize(data, 0) variable ny = dimsize(data, 1) variable nz = dimsize(data, 2) variable pp string obj string cmd // igor does not allow calling gizmo functions directly setdatafolder datadf sprintf cmd, "NewGizmo /k=1 /n=%s /w=(100,100,500,400) /t=\"%s\"", graphname, graphtitle execute /q cmd cmd = "AppendToGizmo /D Axes=BoxAxes, name=axes0" execute /q cmd obj = "surface_xmid" pp = round(nx / 2 - 1) sprintf cmd, "AppendToGizmo /D surface=%s, name=%s", nameofwave(data), obj execute /q cmd sprintf cmd, "ModifyGizmo modifyObject=%s, property={srcMode, 128}", obj execute /q cmd sprintf cmd, "ModifyGizmo ModifyObject=%s, property={plane, %d}", obj, pp execute /q cmd sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCtab, BlueGreenOrange}", obj execute /q cmd sprintf cmd, "ModifyGizmo ModifyObject=%s, property={SurfaceCTABScaling,128}", obj execute /q cmd sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCTABAlpha, 1.0}", obj execute /q cmd obj = "surface_ymid" pp = round(ny / 2 - 1) sprintf cmd, "AppendToGizmo /D surface=%s, name=%s", nameofwave(data), obj execute /q cmd sprintf cmd, "ModifyGizmo modifyObject=%s, property={srcMode, 64}", obj execute /q cmd sprintf cmd, "ModifyGizmo ModifyObject=%s, property={plane, %d}", obj, pp execute /q cmd sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCtab, BlueGreenOrange}", obj execute /q cmd sprintf cmd, "ModifyGizmo ModifyObject=%s, property={SurfaceCTABScaling,128}", obj execute /q cmd sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCTABAlpha, 1.0}", obj execute /q cmd obj = "surface_zmid" pp = round(nz / 2 - 1) sprintf cmd, "AppendToGizmo /D surface=%s, name=%s", nameofwave(data), obj execute /q cmd sprintf cmd, "ModifyGizmo modifyObject=%s, property={srcMode, 32}", obj execute /q cmd sprintf cmd, "ModifyGizmo ModifyObject=%s, property={plane, %d}", obj, pp execute /q cmd sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCtab, BlueGreenOrange}", obj execute /q cmd sprintf cmd, "ModifyGizmo ModifyObject=%s, property={SurfaceCTABScaling,128}", obj execute /q cmd sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCTABAlpha, 1.0}", obj execute /q cmd obj = "axes0" sprintf cmd, "ModifyGizmo ModifyObject=%s,property={-1,axisScalingMode,1}", obj execute /q cmd sprintf cmd, "ModifyGizmo ModifyObject=%s,property={-1,axisColor,0,0,0,1}", obj execute /q cmd sprintf cmd, "ModifyGizmo ModifyObject=%s,property={0,ticks,3}", obj execute /q cmd sprintf cmd, "ModifyGizmo ModifyObject=%s,property={1,ticks,3}", obj execute /q cmd sprintf cmd, "ModifyGizmo ModifyObject=%s,property={2,ticks,3}", obj execute /q cmd sprintf cmd, "ModifyGizmo modifyObject=%s property={Clipped,0}", obj execute /q cmd sprintf cmd, "ModifyGizmo modifyObject=%s property={-1,fontScaleFactor,2}", obj execute /q cmd sprintf cmd, "ModifyGizmo showAxisCue=1" execute /q cmd setdatafolder savedf return graphname end /// open a slicer panel for 3D data. /// /// if a panel exists, bring it to the front. /// /// @param data three-dimensional wave. /// function ad_brick_slicer(data) wave data // data folders and references dfref savedf = GetDataFolderDFR() dfref datadf = GetWavesDataFolderDFR(data) string s_datadf = GetDataFolder(1, datadf) dfref viewdf = make_view_folder(data) setdatafolder viewdf svar /z ex_panel = slicer_panelname if (svar_exists(ex_panel)) string panels = WinList("SlicerPanel*", ";", "WIN:64") if (WhichListItem(ex_panel, panels, ";") >= 0) dowindow /f $(StringFromList(0, panels, ";")) return 0 endif endif variable /g x_slice_pos variable /g y_slice_pos variable /g z_slice_pos variable /g slab_thickness string /g brick_path = getwavesdatafolder(data, 2) variable /g x_autoinc = 0 variable /g y_autoinc = 0 variable /g z_autoinc = 0 // axis labels string labels = note(data) string xlabel = StringByKey("AxisLabelX", labels, "=", "\r") if (!strlen(xlabel)) xlabel = "X" endif string ylabel = StringByKey("AxisLabelY", labels, "=", "\r") if (!strlen(ylabel)) ylabel = "Y" endif string zlabel = StringByKey("AxisLabelZ", labels, "=", "\r") if (!strlen(zlabel)) zlabel = "Z" endif string dlabel = StringByKey("Dataset", labels, "=", "\r") if (!strlen(dlabel)) dlabel = NameOfWave(data) endif // this section copied from slicer panel NewPanel /k=1 /W=(500,600,890,940) /N=SlicerPanel as "Brick Slicer" string /g slicer_panelname = S_name string panel = s_name GroupBox g_xslice win=$panel,pos={8,8},size={376,96},title=xlabel Slider sl_xslice_position win=$panel,pos={16,32},size={240,56},proc=PearlAreaDisplay#slp_slice_position Slider sl_xslice_position win=$panel,limits={0,100,1},variable=x_slice_pos,vert= 0 SetVariable sv_xslice_position win=$panel,pos={20,80},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="X" SetVariable sv_xslice_position win=$panel,limits={0,100,1},value=x_slice_pos Button b_xslice_center win=$panel,pos={122,80},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W618" Button b_xslice_center win=$panel,help={"reset to center position"} Button b_xslice_extract win=$panel,pos={288,80},size={68,20},proc=PearlAreaDisplay#bp_extract_slice,title="extract slice" Button b_xslice_extract win=$panel,help={"extract this slice to a separate wave"} //CheckBox cb_xslab_active win=$panel,pos={288,80},size={80,16},title="Display X Slab" //CheckBox cb_xslab_active win=$panel,value= 0 TitleBox tb_xslice_animation win=$panel,pos={288,32},size={356,16},title="animation",frame=0 TitleBox tb_xslice_animation win=$panel,anchor= MC Button b_xslice_back win=$panel,pos={288,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W646" Button b_xslice_back win=$panel,help={"animate backwards"} Button b_xslice_forward win=$panel,pos={312,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W649" Button b_xslice_forward win=$panel,help={"animate forward"} Button b_xslice_stop win=$panel,pos={336,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616" Button b_xslice_stop win=$panel,help={"stop animation"} GroupBox g_yslice win=$panel,pos={8,108},size={376,96},title=ylabel Slider sl_yslice_position win=$panel,pos={16,132},size={240,56},proc=PearlAreaDisplay#slp_slice_position Slider sl_yslice_position win=$panel,limits={0,100,1},variable=y_slice_pos,vert= 0 SetVariable sv_yslice_position win=$panel,pos={20,180},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Y" SetVariable sv_yslice_position win=$panel,limits={0,100,1},value=y_slice_pos Button b_yslice_center win=$panel,pos={122,180},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W618" Button b_yslice_center win=$panel,help={"reset to center position"} Button b_yslice_extract win=$panel,pos={288,180},size={68,20},proc=PearlAreaDisplay#bp_extract_slice,title="extract slice" Button b_yslice_extract win=$panel,help={"extract this slice to a separate wave"} //CheckBox cb_yslab_active win=$panel,pos={288,180},size={80,16},title="Display Y Slab" //CheckBox cb_yslab_active win=$panel,value= 0 TitleBox tb_yslice_animation win=$panel,pos={288,132},size={356,16},title="animation",frame=0 TitleBox tb_yslice_animation win=$panel,anchor= MC Button b_yslice_back win=$panel,pos={288,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W646" Button b_yslice_back win=$panel,help={"animate backwards"} Button b_yslice_forward win=$panel,pos={312,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W649" Button b_yslice_forward win=$panel,help={"animate forward"} Button b_yslice_stop win=$panel,pos={336,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616" Button b_yslice_stop win=$panel,help={"stop animation"} GroupBox g_zslice win=$panel,pos={8,208},size={376,96},title=zlabel Slider sl_zslice_position win=$panel,pos={16,232},size={240,56},proc=PearlAreaDisplay#slp_slice_position Slider sl_zslice_position win=$panel,limits={0,100,1},variable=z_slice_pos,vert= 0 SetVariable sv_zslice_position win=$panel,pos={20,280},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Z" SetVariable sv_zslice_position win=$panel,limits={0,100,1},value=z_slice_pos Button b_zslice_center win=$panel,pos={122,280},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W618" Button b_zslice_center win=$panel,help={"reset to center position"} Button b_zslice_extract win=$panel,pos={288,280},size={68,20},proc=PearlAreaDisplay#bp_extract_slice,title="extract slice" Button b_zslice_extract win=$panel,help={"extract this slice to a separate wave"} //CheckBox cb_zslab_active win=$panel,pos={288,280},size={80,16},title="Display Z Slab" //CheckBox cb_zslab_active win=$panel,value= 0 TitleBox tb_zslice_animation win=$panel,pos={288,232},size={356,16},title="animation",frame=0 TitleBox tb_zslice_animation win=$panel,anchor= MC Button b_zslice_back win=$panel,pos={288,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W646" Button b_zslice_back win=$panel,help={"animate backwards"} Button b_zslice_forward win=$panel,pos={312,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W649" Button b_zslice_forward win=$panel,help={"animate forward"} Button b_zslice_stop win=$panel,pos={336,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616" Button b_zslice_stop win=$panel,help={"stop animation"} TitleBox t_slicerpath win=$panel,pos={8,316},size={128,20},disable=2,title=dlabel //SetVariable setvar0 win=$panel,pos={240,316},size={120,16},title="slab thickness" //SetVariable setvar0 win=$panel,limits={1,inf,1},value=slab_thickness // update control limits and move slicing planes to the center setwindow $panel, userdata(control_datafolder) = GetDataFolder(1, viewdf) setwindow $panel, userdata(brick_path) = brick_path update_slice_info() x_slice_pos = dimoffset(data, 0) + dimsize(data, 0) * dimdelta(data, 0) / 2 y_slice_pos = dimoffset(data, 1) + dimsize(data, 1) * dimdelta(data, 1) / 2 z_slice_pos = dimoffset(data, 2) + dimsize(data, 2) * dimdelta(data, 2) / 2 svar /z /sdfr=viewdf gizmo_graphname if (svar_exists(gizmo_graphname) && (strlen(gizmo_graphname) > 0) && (wintype(gizmo_graphname) == 13)) ad_gizmo_set_plane(data, 0, x_slice_pos) ad_gizmo_set_plane(data, 1, y_slice_pos) ad_gizmo_set_plane(data, 2, z_slice_pos) endif svar /z /sdfr=viewdf slice_graphname if (svar_exists(slice_graphname) && (strlen(slice_graphname) > 0) && (wintype(slice_graphname) == 1)) ad_profiles_set_slice(data, 2, z_slice_pos) endif ad_slicer_init_bg() setdatafolder savedf end /// display three-dimensional data by 2D slice. /// /// to select the slice data to display, call ad_profiles_set_slice(), or open a ad_brick_slicer() panel. /// do not modify the content of the created view_ data folder. /// /// @param data three-dimensional wave. /// /// @return name of the graph window. /// function /s ad_display_slice(data) wave data if (WaveDims(data) != 3) abort "ad_display_slice: data must be three-dimensional." endif dfref savedf = GetDataFolderDFR() dfref datadf = GetWavesDataFolderDFR(data) string s_datadf = GetDataFolder(1, datadf) dfref viewdf = make_view_folder(data) setdatafolder viewdf string dfname = ReplaceString("root:", s_datadf, "") dfname = dfname[0, strlen(dfname) - 2] string graphtitle = dfname + " Slice" if (exists("slice_graphname") != 2) string /g slice_graphname = "" endif string /g slice_wavename = CleanupName("slice_" + NameOfWave(data), 0) svar graphname = slice_graphname svar slicename = slice_wavename make /n=(1,1)/o $slicename wave slice = $slicename if ((strlen(graphname) == 0) || (wintype(graphname) != 1)) graphname = ad_display_profiles(slice) endif variable z_slice_pos = dimoffset(data, 2) + dimsize(data, 2) * dimdelta(data, 2) / 2 ad_profiles_set_slice(data, 2, z_slice_pos) ad_profiles_set_cursor(slice, "A", -inf, -inf, pscale=1) ad_profiles_set_cursor(slice, "B", +inf, +inf, pscale=1) setdatafolder savedf return graphname end /// update controls with data scale limits. /// /// current folder must be slicer info static function update_slice_info() dfref savedf = GetDataFolderDFR() svar brick_path //svar slicer_panelname wave brick = $brick_path //dowindow /F $slicer_panelname variable lo, hi, inc lo = dimoffset(brick, 0) inc = dimdelta(brick, 0) hi = lo + inc * (dimsize(brick, 0) - 1) Slider sl_xslice_position,limits={lo,hi,inc} SetVariable sv_xslice_position,limits={lo,hi,inc} lo = dimoffset(brick, 1) inc = dimdelta(brick, 1) hi = lo + inc * (dimsize(brick, 1) - 1) Slider sl_yslice_position,limits={lo,hi,inc} SetVariable sv_yslice_position,limits={lo,hi,inc} lo = dimoffset(brick, 2) inc = dimdelta(brick, 2) hi = lo + inc * (dimsize(brick, 2) - 1) Slider sl_zslice_position,limits={lo,hi,inc} SetVariable sv_zslice_position,limits={lo,hi,inc} setdatafolder savedf end /// set the position of a slicing plane of a 3D brick in a Gizmo window. /// /// @param brick original data wave. /// @param dim dimension index: 0, 1, or 2. /// @param value new coordinate of the slicing plane (axis scaling). /// /// @return 0 if successful, non-zero otherwise /// function ad_gizmo_set_plane(brick, dim, value) wave brick variable dim variable value dfref savedf = GetDataFolderDFR() dfref datadf = GetWavesDataFolderDFR(brick) dfref viewdf = get_view_folder(brick) svar /z /sdfr=viewdf graphname=gizmo_graphname variable pp = round((value - dimoffset(brick, dim)) / dimdelta(brick, dim)) if ((pp < 0) || (pp >= dimsize(brick, dim))) return -1 // requested value out of range endif if (svar_exists(graphname) && (strlen(graphname) > 0) && (wintype(graphname) == 13)) string axes = "xyz" string obj = "surface_" + axes[dim] + "mid" string cmd sprintf cmd, "ModifyGizmo /N=%s ModifyObject=%s, property={plane, %d}", graphname, obj, pp execute /q cmd else return -2 // gizmo window not found endif return 0 end /// set the position of the slicing plane of a 3D brick in a profiles window. /// /// @param brick original data wave. /// @param dim dimension index: 0, 1, or 2. /// @param value new coordinate of the slicing plane (axis scaling). /// /// @return 0 if successful, non-zero otherwise /// function ad_profiles_set_slice(brick, dim, value) wave brick variable dim variable value dfref savedf = GetDataFolderDFR() dfref datadf = GetWavesDataFolderDFR(brick) dfref viewdf = get_view_folder(brick) svar /z /sdfr=viewdf graphname = slice_graphname svar /z /sdfr=viewdf slicename = slice_wavename variable pp = round((value - dimoffset(brick, dim)) / dimdelta(brick, dim)) if ((pp < 0) || (pp >= dimsize(brick, dim))) return -1 // requested value out of range endif if (svar_exists(graphname) && (strlen(graphname) > 0) && (wintype(graphname) == 1)) setdatafolder viewdf switch(dim) case 0: // X wave wdest = ad_extract_slab_x(brick, pp, pp, slicename) ad_update_profiles(wdest) break case 1: // Y wave wdest = ad_extract_slab_y(brick, pp, pp, slicename) ad_update_profiles(wdest) break case 2: // Z wave wdest = ad_extract_slab_z(brick, pp, pp, slicename) ad_update_profiles(wdest) break endswitch else return -2 // graph window not found endif setdatafolder savedf return 0 end static function slp_slice_position(sa) : SliderControl STRUCT WMSliderAction &sa dfref savedf = GetDataFolderDFR() switch( sa.eventCode ) case -1: // control being killed break default: if( sa.eventCode & 1 ) // value set string control_datafolder = GetUserData(sa.win, "", "control_datafolder") setdatafolder control_datafolder string brick_path = GetUserData(sa.win, "", "brick_path") wave brick = $brick_path string axis = StringFromList(1, sa.ctrlName, "_") variable dim = char2num(axis[0]) - char2num("x") ad_gizmo_set_plane(brick, dim, sa.curval) ad_profiles_set_slice(brick, dim, sa.curval) endif break endswitch setdatafolder savedf return 0 End /// set slice coordinate (button procedure). static function svp_slice_position(sva) : SetVariableControl STRUCT WMSetVariableAction &sva dfref savedf = GetDataFolderDFR() switch( sva.eventCode ) case 1: // mouse up case 2: // Enter key case 3: // Live update string control_datafolder = GetUserData(sva.win, "", "control_datafolder") setdatafolder control_datafolder string brick_path = GetUserData(sva.win, "", "brick_path") wave brick = $brick_path string axis = StringFromList(1, sva.ctrlName, "_") variable dim = char2num(axis[0]) - char2num("x") ad_gizmo_set_plane(brick, dim, sva.dval) ad_profiles_set_slice(brick, dim, sva.dval) break case -1: // control being killed break endswitch setdatafolder savedf return 0 End /// move slice (button procedure). static function bp_move_slice(ba) : ButtonControl STRUCT WMButtonAction &ba dfref savedf = GetDataFolderDFR() switch( ba.eventCode ) case 2: // mouse up string control_datafolder = GetUserData(ba.win, "", "control_datafolder") setdatafolder control_datafolder string brick_path = GetUserData(ba.win, "", "brick_path") wave brick = $brick_path string axis = StringFromList(1, ba.ctrlName, "_") string cmd = StringFromList(2, ba.ctrlName, "_") variable dim = char2num(axis[0]) - char2num("x") string posvariable = getdatafolder(1) + axis[0] + "_slice_pos" nvar pos = $(posvariable) strswitch (cmd) case "forward": ad_slicer_start_bg(brick, dim, posvariable, dimdelta(brick, dim)) break case "back": ad_slicer_start_bg(brick, dim, posvariable, -dimdelta(brick, dim)) break case "center": ad_slicer_stop_bg(posvariable) bp_move_slice_center(brick, dim, posvariable) break case "stop": ad_slicer_stop_bg(posvariable) break endswitch break case -1: // control being killed break endswitch setdatafolder savedf return 0 End /// export a slice (button procedure). /// /// extract a slice and saves it in a separate wave. static function bp_extract_slice(ba) : ButtonControl STRUCT WMButtonAction &ba dfref savedf = GetDataFolderDFR() switch( ba.eventCode ) case 2: // mouse up string control_datafolder = GetUserData(ba.win, "", "control_datafolder") setdatafolder control_datafolder string brick_path = GetUserData(ba.win, "", "brick_path") wave brick = $brick_path dfref brickdf = GetWavesDataFolderDFR(brick) string axis = StringFromList(1, ba.ctrlName, "_") string cmd = StringFromList(2, ba.ctrlName, "_") variable dim = char2num(axis[0]) - char2num("x") string posvariable = getdatafolder(1) + axis[0] + "_slice_pos" nvar pos = $(posvariable) variable pp = round((pos - dimoffset(brick, dim)) / dimdelta(brick, dim)) if ((pp < 0) || (pp >= dimsize(brick, dim))) return -1 // requested value out of range endif variable dig = ceil(log(dimsize(brick, dim))) string slicename sprintf slicename, "%s_%s%0*u", NameOfWave(brick), axis[0], dig, pp setdatafolder brickdf switch(dim) case 0: // X wave wdest = ad_extract_slab_x(brick, pp, pp, slicename) break case 1: // Y wave wdest = ad_extract_slab_y(brick, pp, pp, slicename) break case 2: // Z wave wdest = ad_extract_slab_z(brick, pp, pp, slicename) break endswitch string msg sprintf msg, "%s=%g", axis[0], pos note wdest, msg break case -1: // control being killed break endswitch setdatafolder savedf return 0 End /// move the slice to the center of the dimension (button procedure). static function bp_move_slice_center(brick, dim, posvariable) wave brick variable dim string posvariable nvar pos = $posvariable pos = dimoffset(brick, dim) + dimdelta(brick, dim) * dimsize(brick, dim) / 2 ad_gizmo_set_plane(brick, dim, pos) ad_profiles_set_slice(brick, dim, pos) end /// move a slice by one step (background task). static function ad_slicer_move_bg(s) STRUCT WMBackgroundStruct &s dfref savedf = GetDataFolderDFR() setdatafolder root:pearl_area:slicer wave /t bg_brickpaths wave /t bg_graphnames wave /t bg_variablepaths wave bg_dimensions wave bg_increments variable ii variable nn = numpnts(bg_brickpaths) variable dim variable pp for (ii = 0; ii < nn; ii += 1) wave /z brick = $bg_brickpaths[ii] nvar /z pos = $bg_variablepaths[ii] dim = bg_dimensions[0] pos += bg_increments[ii] // wrap around at limits pp = round((pos - dimoffset(brick, dim)) / dimdelta(brick, dim)) if (pp <= -0.5) pos = dimoffset(brick, dim) + dimdelta(brick, dim) * (dimsize(brick, dim) - 1) elseif (pp >= dimsize(brick, dim) - 0.5) pos = dimoffset(brick, dim) endif if (waveexists(brick)) ad_gizmo_set_plane(brick, dim, pos) ad_profiles_set_slice(brick, dim, pos) endif endfor setdatafolder savedf return 0 End /// initialize the slice animation background task. function ad_slicer_init_bg() dfref savedf = GetDataFolderDFR() setdatafolder root: newdatafolder /o/s pearl_area newdatafolder /o/s slicer make /n=0/o/t bg_brickpaths make /n=0/o/t bg_variablepaths make /n=0/o/i/u bg_dimensions make /n=0/o bg_increments CtrlNamedBackground ad_slicer, period = 30, proc = PearlAreaDisplay#ad_slicer_move_bg setdatafolder savedf return 0 end /// start the animation. /// /// @param brick 3D data wave /// @param dimension dimension to animate, 0, 1, or 2. /// @param posvariable full path to the global position variable. /// @param delta step increment, should be +/- dimdelta. /// function ad_slicer_start_bg(brick, dimension, posvariable, delta) wave brick // 3D data wave variable dimension // dimension to animate, 0, 1, or 2 string posvariable // full path to the global position variable variable delta // step increment, should be +/- dimdelta dfref savedf = GetDataFolderDFR() setdatafolder root:pearl_area:slicer wave /t bg_brickpaths wave /t bg_variablepaths wave bg_dimensions wave bg_increments // create entry in ad_slicer background task table variable idx FindValue /TEXT=posvariable /TXOP=4 /Z bg_variablepaths if (v_value >= 0) idx = v_value else idx = numpnts(bg_variablepaths) InsertPoints idx, 1, bg_brickpaths, bg_variablepaths, bg_dimensions, bg_increments endif // set background task bg_brickpaths[idx] = GetWavesDataFolder(brick, 2) bg_variablepaths[idx] = posvariable bg_dimensions[idx] = dimension bg_increments[idx] = delta // start background task if (numpnts(bg_variablepaths) > 0) CtrlNamedBackground ad_slicer, start endif setdatafolder savedf return 0 end /// stop the animation. /// /// @param posvariable full path to the global position variable. /// function ad_slicer_stop_bg(posvariable) string posvariable dfref savedf = GetDataFolderDFR() setdatafolder root:pearl_area:slicer wave /t bg_brickpaths wave /t bg_variablepaths wave bg_dimensions wave bg_increments // find entry in ad_slicer background task table FindValue /TEXT=posvariable /TXOP=4 /Z bg_variablepaths if (v_value >= 0) DeletePoints v_value, 1, bg_brickpaths, bg_variablepaths, bg_dimensions, bg_increments endif // stop background task if task table is empty if (numpnts(bg_variablepaths) == 0) CtrlNamedBackground ad_slicer, stop endif setdatafolder savedf return 0 end