| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666 | classdef XTPS < handle%XTPS Main GUI for RDXTPS front end.%% Default to contain three SliceViewerPanels for viewing.%% TODO:%   Move Geometry and optResults into SliceViewerPanelSource completely so that%   only one copy exist.%   Move color stuff into Geometry so that can be saved.%% See also SliceViewerPanel%% Author Xiaohu Mo    properties        handles        patient_dir        dosecalcSetup    end    methods%-------------------------------------------------------------------------------        function obj = XTPS() % XTPS constructor            hMainFigure = figure('MenuBar', 'none', 'Name', 'RDXTPS: No Patient', 'Position', [100 100 800 600], 'Renderer', 'painters');            obj.handles = guihandles(hMainFigure);            obj.handles.hMainFigure = hMainFigure;            % Adding widgets            obj.handles.hROIPanel = uipanel('Parent', obj.handles.hMainFigure, 'Title', 'ROI display');            obj.handles.hROITable = uitable('Parent', obj.handles.hROIPanel);            obj.handles.hDosePanel = uipanel('Parent', obj.handles.hMainFigure, 'Title', 'Dose display');            obj.handles.hDoseTable = uitable('Parent', obj.handles.hDosePanel);            obj.handles.hDoseModeDropdown = uicontrol('Parent', obj.handles.hDosePanel, 'Style', 'popupmenu');            obj.handles.hDoseModeLabel = uicontrol('Parent', obj.handles.hDosePanel, 'Style', 'text');            obj.handles.hMiscPanel = uipanel('Parent', obj.handles.hMainFigure, 'Title', 'Misc settings');            obj.handles.hTCSShow = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'checkbox');            obj.handles.hWWLabel = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'edit');            obj.handles.hWWSlider = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'slider');            obj.handles.hWWEdit = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'edit');            obj.handles.hWLLabel = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'edit');            obj.handles.hWLSlider = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'slider');            obj.handles.hWLEdit = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'edit');            obj.handles.hSVPS = SliceViewerPanelSource();            obj.handles.hSliceViewerPanel(1) = SliceViewerPanel(obj.handles.hSVPS, 3, obj.handles.hMainFigure);            obj.handles.hSliceViewerPanel(2) = SliceViewerPanel(obj.handles.hSVPS, 2, obj.handles.hMainFigure);            obj.handles.hSliceViewerPanel(3) = SliceViewerPanel(obj.handles.hSVPS, 1, obj.handles.hMainFigure);            % File menu            obj.handles.hFileMenu             = uimenu(obj.handles.hMainFigure, 'Label','File');            obj.handles.hImportDicomRTMenu    = uimenu(obj.handles.hFileMenu, 'Label', '1. Import DicomRT Geometry');            % ---- Grozomah: This part edited by Peter            obj.handles.hNRRD1                = uimenu(obj.handles.hFileMenu, 'Label', '1a. Geometry wizard (am/nrrd)');            obj.handles.hNRRD2                = uimenu(obj.handles.hFileMenu, 'Label', '1b. Add Geometry ROI');            obj.handles.hImgPerturb           = uimenu(obj.handles.hFileMenu, 'Label', '1e. Implement image pertrubations');                        obj.handles.hDosecalcMenu         = uimenu(obj.handles.hFileMenu, 'Label', '2. Beamlet Dose Calculation');                        % ---- Grozomah: This part edited by Peter            obj.handles.hMergeBeamlets                = uimenu(obj.handles.hFileMenu, 'Label', '2a. Merge Beamlets');            obj.handles.hTest2                = uimenu(obj.handles.hFileMenu, 'Label', '2b. Test 2');                        obj.handles.hOptimMenu            = uimenu(obj.handles.hFileMenu, 'Label', '3. Plan Optimization');            obj.handles.hSaveOptimResultsMenu = uimenu(obj.handles.hFileMenu, 'Label', '4.a Save Optimization Results');            obj.handles.hGetFullDose          = uimenu(obj.handles.hFileMenu, 'Label', '4.b Get Full Dose');                        obj.handles.hLoadGeometryMenu     = uimenu(obj.handles.hFileMenu, 'Label', 'Load Geometry', 'Separator','on');            obj.handles.hLoadOptresultsMenu   = uimenu(obj.handles.hFileMenu, 'Label', 'Load OptResults');                        obj.handles.hSaveAsGeometryMenu   = uimenu(obj.handles.hFileMenu, 'Label', 'Save Geometry As...', 'Separator','on');            obj.handles.hSaveAsOptResultsMenu = uimenu(obj.handles.hFileMenu, 'Label', 'Save OptResults As...');                        obj.handles.hExportPinnacleMenu   = uimenu(obj.handles.hFileMenu, 'Label', 'Export Pinnacle Files', 'Separator','on');                        % Tools menu            obj.handles.hToolsMenu   = uimenu(obj.handles.hMainFigure, 'Label', 'Tools');                        obj.handles.hPlotDVHMenu = uimenu(obj.handles.hToolsMenu,  'Label', 'Plot DVH');                        % Associate callbacks            set(obj.handles.hMainFigure, 'ResizeFcn',               @obj.set_layout);            set(obj.handles.hROITable, 'CellSelectionCallback',     @obj.ROITable_CellSelectionCallback);            set(obj.handles.hDoseTable, 'CellSelectionCallback',    @obj.DoseTable_CellSelectionCallback);            set(obj.handles.hDoseTable, 'CellEditCallback',         @obj.DoseTable_CellEditCallback);            set(obj.handles.hImportDicomRTMenu, 'Callback',         @obj.ImportDicomRTMenu_Callback);            set(obj.handles.hDosecalcMenu, 'Callback',              @obj.DosecalcMenu_Callback);                        % Grozomah            set(obj.handles.hNRRD1, 'Callback',         @obj.NRRD1_Callback);            set(obj.handles.hNRRD2, 'Callback',         @obj.NRRD2_Callback);            set(obj.handles.hImgPerturb, 'Callback',    @obj.ImgPerturb_Callback);                                     % Grozomah            set(obj.handles.hMergeBeamlets, 'Callback',      @obj.MergeBeamlets_Callback);            set(obj.handles.hTest2, 'Callback',              @obj.Test2_Callback);            set(obj.handles.hGetFullDose, 'Callback',        @obj.GetFullDose_Callback);                        set(obj.handles.hSaveOptimResultsMenu, 'Callback',      @obj.SaveOptimResultsMenu_Callback);            set(obj.handles.hOptimMenu, 'Callback',                 @obj.OptimMenu_Callback);            set(obj.handles.hLoadGeometryMenu, 'Callback',          @obj.LoadGeometryMenu_Callback);            set(obj.handles.hLoadOptresultsMenu, 'Callback',        @obj.LoadOptresultsMenu_Callback);            set(obj.handles.hSaveAsGeometryMenu, 'Callback',        @obj.SaveAsGeometryMenu_Callback);            set(obj.handles.hSaveAsOptResultsMenu, 'Callback',      @obj.SaveAsOptResultsMenu_Callback);            set(obj.handles.hExportPinnacleMenu, 'Callback',        @obj.ExportPinnacleMenu_Callback);            set(obj.handles.hPlotDVHMenu, 'Callback',               @obj.PlotDVHMenu_Callback);            set(obj.handles.hDoseModeDropdown, 'Callback',          @obj.DoseModeDropdown_Callback);            set(obj.handles.hWWSlider, 'Callback',                  @obj.WWSlider_Callback);            set(obj.handles.hWWEdit, 'Callback',                    @obj.WWEdit_Callback);            set(obj.handles.hWLSlider, 'Callback',                  @obj.WLSlider_Callback);            set(obj.handles.hWLEdit, 'Callback',                    @obj.WLEdit_Callback);                                    set(obj.handles.hTCSShow, 'Callback',                   @obj.TCSShow_Callback);            obj.set_widget_properties();            obj.set_layout();            obj.updateROITable();            obj.updateDoseTable();            obj.updateCTWindowControls();        end % XTPS constructor%-------------------------------------------------------------------------------        function set_widget_properties(obj)        %% Set widget default properties, excluding those related to data            h = obj.handles; % shortcut            set(h.hROITable, 'ColumnEditable', logical([1 0 0]));            set(h.hROITable, 'ColumnFormat', {'logical', 'char', 'char'});            set(h.hROITable, 'ColumnName', {'V' 'C' 'ROI'});            set(h.hROITable, 'ColumnWidth',{20 15 'auto'});            set(h.hROITable, 'RowName', {'numbered'});            set(h.hROITable, 'RowStriping', 'off');            set(h.hROITable, 'ToolTipString', 'click to set color');            set(h.hDoseTable, 'ColumnEditable', logical([0 1 1]));            set(h.hDoseTable, 'ColumnFormat', {'char' 'numeric' 'numeric'});            set(h.hDoseTable, 'ColumnName', {'C' 'Dose' 'Alpha'});            set(h.hDoseTable, 'ColumnWidth',{15 'auto' 'auto'});            set(h.hDoseTable, 'RowName', []);            set(h.hDoseTable, 'RowStriping', 'off');            set(h.hDoseTable, 'ToolTipString', 'click to set color');            set(h.hDoseModeLabel, 'String', 'display mode');                        set(h.hDoseModeDropdown, 'String', {'None' 'Isodose' 'IsodoseLine' 'Colorwash'});                        set(h.hWWLabel, 'String', 'Win. Width');            set(h.hWWSlider, 'Min', 0, 'Max', 2048, 'SliderStep', [10/2048 100/2048]);            set(h.hWLLabel, 'String', 'Win. Level');            set(h.hWLSlider, 'Min', 0, 'Max', 2048, 'SliderStep', [10/2048 100/2048]);                        set(h.hTCSShow, 'String', 'Show TCS planes', 'Value', get(h.hTCSShow, 'Max'));            % BackgroundColor (get all ui object handles except uitable)            set(findobj(h.hMainFigure, '-property', 'BackgroundColor', '-not', 'Type', 'uitable'), ...                'BackgroundColor', get(h.hMainFigure, 'Color'));        end%-------------------------------------------------------------------------------        function set_layout(obj, src, evt)        % Set widget positions and size. Also as ResizeFcn.            h = obj.handles; % shortcut            set(findobj(h.hMainFigure, '-property', 'Units'), 'Units', 'Normalized');            padding = [0.005 0.01];            setPositionXY(h.hDosePanel, [0 0.2], [0.2 0.5], padding);            setPositionXY(h.hROIPanel, [0 0.2], [0.5 1], padding);            setPositionXY(h.hMiscPanel, [0 0.2], [0 0.2], padding);            setPositionXY(h.hSliceViewerPanel(1).hPanel, [0.2 0.7], [0 1], padding);            setPositionXY(h.hSliceViewerPanel(2).hPanel, [0.7 1], [0.5 1], padding);            setPositionXY(h.hSliceViewerPanel(3).hPanel, [0.7 1], [0 0.5], padding);            setPositionXY(h.hROITable, [0 1], [0 1], padding);            setPositionXY(h.hDoseModeDropdown, [0.5 1], [0.9 1], padding);            setPositionXY(h.hDoseModeLabel, [0 0.5], [0.9 1], padding);            setPositionXY(h.hDoseTable, [0 1], [0 0.9], padding);                        setPositionXY(h.hWWLabel, [0 0.3], [0.67 1], padding, 1.5, 'characters');            setPositionXY(h.hWWSlider, [0.3 0.85], [0.67 1], padding, 1.5, 'characters');            setPositionXY(h.hWWEdit, [0.85 1], [0.67 1], padding, 1.5, 'characters');            setPositionXY(h.hWLLabel, [0 0.3], [0.33 0.67], padding, 1.5, 'characters');            setPositionXY(h.hWLSlider, [0.3 0.85], [0.33 0.67], padding, 1.5, 'characters');            setPositionXY(h.hWLEdit, [0.85 1], [0.33 0.67], padding, 1.5, 'characters');            setPositionXY(h.hTCSShow, [0 1], [0.0 0.33], padding, 1.5, 'characters');                        table_width = getWidthPixel(obj.handles.hROITable);            set(obj.handles.hROITable, 'ColumnWidth', {20 15 table_width-20-15-35});            table_width = getWidthPixel(obj.handles.hDoseTable);            set(obj.handles.hDoseTable, 'ColumnWidth', {15 (table_width-15)/2-2 (table_width-15)/2-2});                        % Panel ResizeFcn not executed after init. Has to manually call.            for i = 1:numel(h.hSliceViewerPanel)                h.hSliceViewerPanel(i).set_layout();            end        end%-------------------------------------------------------------------------------        function load_geometry(obj, geometry_filename)        %% load geometry            if nargin == 2 % load the geometry file if supplied                load(geometry_filename);            elseif nargin == 1 % Geometry should be loaded already                Geometry = obj.handles.hSVPS.Geometry;                if isempty(obj.handles.hSVPS.Geometry)                    % TODO appropriate handling                    return;                end            end            % add x,y,z axis for plotting purposes            Geometry.x = Geometry.start(1) + Geometry.voxel_size(1) * (0:size(Geometry.rhomw, 1)-1);            Geometry.y = Geometry.start(2) + Geometry.voxel_size(2) * (0:size(Geometry.rhomw, 2)-1);            Geometry.z = Geometry.start(3) + Geometry.voxel_size(3) * (0:size(Geometry.rhomw, 3)-1);            for i = 1:numel(Geometry.ROIS)                % TODO unify curves as N x 3 cell array so we don't need Xcurves & Ycurves,                % but that way will break back-compatibility.                if isfield(Geometry.ROIS{i}, 'Xcurves')                    Xcurves_coordinate = cellfun(@(c)c(1,1), Geometry.ROIS{i}.Xcurves);                    Geometry.ROIS{i}.Xcurves_slices = ...                        round((Xcurves_coordinate - Geometry.start(1)) / Geometry.voxel_size(1)) + 1;                else                    % Old version doesn't have XYcurves. Create an empty index to skip plotting.                    Geometry.ROIS{i}.Xcurves_slices = [];                end                                if isfield(Geometry.ROIS{i}, 'Ycurves')                    Ycurves_coordinate = cellfun(@(c)c(1,2), Geometry.ROIS{i}.Ycurves);                    Geometry.ROIS{i}.Ycurves_slices = ...                        round((Ycurves_coordinate - Geometry.start(2)) / Geometry.voxel_size(2)) + 1;                else                    % Old version doesn't have XYcurves. Create an empty index to skip plotting.                    Geometry.ROIS{i}.Ycurves_slices = [];                end                                if isfield(Geometry.ROIS{i}, 'curves')                    Zcurves_coordinate = cellfun(@(c)c(1,3), Geometry.ROIS{i}.curves);                    Geometry.ROIS{i}.Zcurves_slices = ...                        round((Zcurves_coordinate - Geometry.start(3)) / Geometry.voxel_size(3)) + 1;                else                    Geometry.ROIS{i}.Zcurves_slices = [];                end            end                        % Convert data into float            if isinteger(Geometry.data)                Geometry.data = single(Geometry.data);            end            % Init/set display settings if absent            num_ROI = numel(Geometry.ROIS);            for i = 1:num_ROI                if ~isfield(Geometry.ROIS{i}, 'visible')                    Geometry.ROIS{i}.visible = false;                end                if ~isfield(Geometry.ROIS{i}, 'color')                    Geometry.ROIS{i}.color = rand(1,3);                end            end            % Set/save to SliceViewerPanelSource            obj.handles.hSVPS.Geometry = Geometry;            obj.handles.hSVPS.TCSVisible = ...                (get(obj.handles.hTCSShow, 'Value') == get(obj.handles.hTCSShow, 'Max'));                        % updates            obj.handles.hSliceViewerPanel(1).load_data();            obj.handles.hSliceViewerPanel(2).load_data();            obj.handles.hSliceViewerPanel(3).load_data();            obj.updateROITable();        end%-------------------------------------------------------------------------------        function load_optResults(obj, optresults_filename)            if nargin == 2 % load the optResults file if supplied                load(optresults_filename, 'optResults');                obj.handles.hSVPS.optResults = optResults;            elseif nargin == 1 % optResults should exist already                % Do nothing for now            end            obj.updateDoseTable();        end%-------------------------------------------------------------------------------        function updateROITable(obj)        % Update ROITable using values in Geometry.ROIS            if isempty(obj.handles.hSVPS.Geometry); return; end            tdata = get(obj.handles.hROITable, 'Data');            % Update table data according to display settings            for i = 1:numel(obj.handles.hSVPS.Geometry.ROIS)                tdata{i, 1} = obj.handles.hSVPS.Geometry.ROIS{i}.visible;                c = obj.handles.hSVPS.Geometry.ROIS{i}.color;                tdata{i, 2} = sprintf('<html><span style="color:%s">■</span></html>', rgb2str(c));                tdata{i, 3} = obj.handles.hSVPS.Geometry.ROIS{i}.name;            end            set(obj.handles.hROITable, 'Data', tdata);            drawnow;            obj.set_layout();        end%-------------------------------------------------------------------------------        function updateDoseTable(obj)        % Update DoseTable using data in SliceViewerPanelSource.dosedisp%             if isempty(obj.handles.hSVPS.Geometry) && isempty(obj.handles.hSVPS.optResults); return; end            tdata = cell(0);            % Update table data according to display settings            for i = 1:numel(obj.handles.hSVPS.dosedisp.level)                tdata{i, 1} = sprintf('<html><span style="color:%s">■</span></html>', rgb2str(obj.handles.hSVPS.dosedisp.color(i,:)));                tdata{i, 2} = obj.handles.hSVPS.dosedisp.level(i);                tdata{i, 3} = obj.handles.hSVPS.dosedisp.alpha(i);            end            % disable the callback to prevent recursion            set(obj.handles.hDoseTable, 'CellSelectionCallback', []);            set(obj.handles.hDoseTable, 'Data', tdata);            drawnow; % Flush //IMPORTANT            set(obj.handles.hDoseTable, 'CellSelectionCallback', @obj.DoseTable_CellSelectionCallback);        end%-------------------------------------------------------------------------------        function updateCTWindowControls(obj)            set(obj.handles.hWWSlider, 'Value', obj.handles.hSVPS.ctWindow.ww);            set(obj.handles.hWWEdit, 'String', num2str(obj.handles.hSVPS.ctWindow.ww));            set(obj.handles.hWLSlider, 'Value', obj.handles.hSVPS.ctWindow.wl);            set(obj.handles.hWLEdit, 'String', num2str(obj.handles.hSVPS.ctWindow.wl));        end%-------------------------------------------------------------------------------        function ROITable_CellSelectionCallback(obj, hObject, eventdata)        % eventdata  structure with the following fields (see UITABLE)        %	Indices: row and column indices of the cell(s) currently selecteds            % Avoid "fake" event during initialization            if ~isempty(eventdata.Indices)                roi_idx = eventdata.Indices(1);                if eventdata.Indices(2) == 1                    % toggle ROI display in display settings                    tdata = get(hObject, 'Data');                    obj.handles.hSVPS.Geometry.ROIS{roi_idx}.visible = ~tdata{roi_idx, 1};                else % eventdata.Indices(2) ~= 1                    % pick and save color                    c = uisetcolor;                    if ~(isscalar(c) && c == 0)                        obj.handles.hSVPS.Geometry.ROIS{roi_idx}.color = c;                        % also make it visible                        obj.handles.hSVPS.Geometry.ROIS{roi_idx}.visible = true;                    end                end                obj.updateROITable();            end        end%-------------------------------------------------------------------------------        function DoseTable_CellSelectionCallback(obj, tilde, eventdata)        % eventdata  structure with the following fields (see UITABLE)        %	Indices: row and column indices of the cell(s) currently selecteds            % Avoid fake event during initialization            if ~isempty(eventdata.Indices)                if eventdata.Indices(2) == 1                    % pick and save color                    c = uisetcolor;                    if ~(isscalar(c) && c == 0)                        obj.handles.hSVPS.dosedisp.color(eventdata.Indices(1), :) = c;                        obj.updateDoseTable();                    end                end            end        end%-------------------------------------------------------------------------------        function DoseTable_CellEditCallback(obj, tilde, eventdata)        % Update handles.hSVPS.dosedisp            if eventdata.Indices(2) == 2                obj.handles.hSVPS.dosedisp.level(eventdata.Indices(1)) = eventdata.NewData;            elseif eventdata.Indices(2) == 3                obj.handles.hSVPS.dosedisp.alpha(eventdata.Indices(1)) = eventdata.NewData;            end            obj.updateDoseTable();        end%-------------------------------------------------------------------------------        function WWSlider_Callback(obj, src, evt)            % set window width property of SliceViewerPancelSource            value = round(get(src, 'Value'));                        obj.handles.hSVPS.ctWindow.ww = value;            obj.updateCTWindowControls();        end%-------------------------------------------------------------------------------        function WWEdit_Callback(obj, src, evt)            % set window width property of SliceViewerPancelSource            value = round(str2double(get(src, 'String')));            % clipping to valid value            value = max(value, get(obj.handles.hWWSlider, 'Min'));            value = min(value, get(obj.handles.hWWSlider, 'Max'));                        obj.handles.hSVPS.ctWindow.ww = value;            obj.updateCTWindowControls();        end%-------------------------------------------------------------------------------        function WLSlider_Callback(obj, src, evt)            % set window width property of SliceViewerPancelSource            value = round(get(src, 'Value'));                        obj.handles.hSVPS.ctWindow.wl = value;            obj.updateCTWindowControls();        end%-------------------------------------------------------------------------------        function WLEdit_Callback(obj, src, evt)            % set window width property of SliceViewerPancelSource            value = round(str2double(get(src, 'String')));            % clipping to valid value            value = max(value, get(obj.handles.hWLSlider, 'Min'));            value = min(value, get(obj.handles.hWLSlider, 'Max'));                        obj.handles.hSVPS.ctWindow.wl = value;            obj.updateCTWindowControls();        end%-------------------------------------------------------------------------------        function ImportDicomRTMenu_Callback(obj, src, evt)            [obj.handles.hSVPS.Geometry obj.patient_dir] = RDXTPS_geometry_setup_wizard_ASP();            obj.load_geometry();                        obj.handles.hSVPS.Geometry.patient_dir                                    a=obj.handles.hSVPS.Geometry;            disp(1)        end        %-------------------------------------------------------------------------------% Grozomah        function NRRD1_Callback(obj, src, evt)            [obj.handles.hSVPS.Geometry] = load2geometry();            obj.load_geometry();                        [obj.handles.hSVPS.Geometry] = nrrd2ROI(obj.handles.hSVPS.Geometry);            obj.load_geometry();            disp('New ROI loaded!')        end%-------------------------------------------------------------------------------% Grozomah        function NRRD2_Callback(obj, src, evt)            [obj.handles.hSVPS.Geometry] = nrrd2ROI(obj.handles.hSVPS.Geometry);            obj.load_geometry();            disp('New ROI loaded!')        end        %-------------------------------------------------------------------------------        % Grozomah        function ImgPerturb_Callback(obj, src, evt)            disp('Perturb callback implemented')        end                %-------------------------------------------------------------------------------        function DosecalcMenu_Callback(obj, src, evt)            % TODO fix patient_dir system%             [obj.dosecalcSetup obj.patient_dir] = RDXTPS_dosecalcSetup(obj.dosecalcSetup, obj.patient_dir, obj.handles.hSVPS.Geometry);%             [obj.dosecalcSetup obj.patient_dir] = RDXTPS_dosecalcSetup(obj.dosecalcSetup, [], obj.handles.hSVPS.Geometry);% %             % Temporary fix for Gustavo asking energy limit%             answer = inputdlg('Machine energy limit: (MeV)', 'Energy limit', 1, {'250'});%             maxMachineEnergyStr = answer{1};% %             % run beamlet dose calculation %             cmdline = ['.' filesep 'RDXdosecalc.exe "' fullfile(obj.patient_dir, 'dosecalc_input.txt') '"' ' ' maxMachineEnergyStr];%             % Grozomah ##% %             cmdline = ['.' filesep 'RDXoptimizer.exe "' fullfile(obj.patient_dir, 'dosecalc_input.txt') '"'];%             %             if ispc%                 execline = ['cmd /c ' cmdline ' &'];%             elseif isunix%                 % xterm -e "export LD_LIBRARY_PATH=. ; ./RDXdosecalc.exe '../patients/Knew/dosecalc_input.txt' ; read" &%                 % TODO fix single quote%                 cmdline = ['xterm -e "export LD_LIBRARY_PATH=. ; ./RDXdosecalc.exe ' fullfile(obj.patient_dir, 'dosecalc_input.txt') ' ; read" &'];%             end%             msgbox(sprintf('Start beamlet dose calculation.\nRun this if not started automatically:\n%s', cmdline));%             system(execline);            obj.handles.hSVPS.Geometry.num_batches = helicalDosecalcSetup7(obj.handles.hSVPS.Geometry.patient_dir)        end        %-------------------------------------------------------------------------------        % Grozomah        function MergeBeamlets_Callback(obj, src, evt)            merge_beamlets(obj.handles.hSVPS.Geometry.num_batches, obj.handles.hSVPS.Geometry.patient_dir);            disp('Beamlets merged!')        end        %-------------------------------------------------------------------------------        % Grozomah        function Test2_Callback(obj, src, evt)            disp('Test 2 works!')        end%-------------------------------------------------------------------------------        function OptimMenu_Callback(obj, src, evt)            % TODO fix patient_dir system%             if isempty(obj.patient_dir)                obj.patient_dir = uifile('getdir', 'Select the patient directory');%             end            source_filename = fullfile(obj.patient_dir, 'batch_dose.bin');            target_filename = fullfile(obj.patient_dir, 'beamlet_batch_files', 'beamletbatch0.bin');            mkdir(fullfile(obj.patient_dir, 'beamlet_batch_files'));            try                if ispc % MATLAB movefile() super slow on windows                    % TODO confirm overwrite                    system(['move "' source_filename '" "' target_filename '"']);                else                    movefile(source_filename, target_filename);                end            catch                msgbox('Error moving the beamlet file. Please do so manually.');            end            Nbeamlets = read_ryan_beamlets(target_filename, 'info');            RDXTPS_optimSetup(Nbeamlets, obj.patient_dir, obj.handles.hSVPS.Geometry);            % run optimizer            %---            cd('C:\010-work\003_localGit\WiscPlan_v2\WiscPlanPhotonkV125\WiscPlanEXE')                        cmdline = ['.' filesep 'RDXoptimizer.exe "' fullfile(obj.patient_dir, 'optInput.txt') '"'];            msgbox(sprintf('Start optimization\nRun this if not started automatically:\n%s', cmdline));            if ispc                execline = ['cmd /c ' cmdline ' &'];            elseif isunix                % TODO fix single quote                execline = [cmdline];            end            system(execline);        end%-------------------------------------------------------------------------------        function SaveOptimResultsMenu_Callback(obj, src, evt)            % TODO fix patient_dir system%             if isempty(obj.patient_dir)                obj.patient_dir = uifile('getdir', 'Select the patient directory');%             end            [tilde, obj.handles.hSVPS.optResults] = loadOptResults(obj.patient_dir, 'optInput.txt');            obj.load_optResults();        end%-------------------------------------------------------------------------------        % Grozomah        function GetFullDose_Callback(obj, src, evt)            get_full_dose([obj.patient_dir])            disp('Full dose calculated.')        end        %-------------------------------------------------------------------------------        function LoadGeometryMenu_Callback(obj, src, evt)            [filename pathname] = uifile('get', '*.mat', 'Choose Geometry file to load');            % do nothing if cancelled            if isscalar(filename) && filename == 0; return; end            obj.load_geometry(fullfile(pathname, filename));        end%-------------------------------------------------------------------------------        function LoadOptresultsMenu_Callback(obj, src, evt)            [filename pathname] = uifile('get', '*.mat', 'Choose OptResults file to load');            % do nothing if cancelled            if isscalar(filename) && filename == 0; return; end            obj.load_optResults(fullfile(pathname, filename));            %             % Extra dose scaling. Temporary code for comparison with Tomo plans%             answer = inputdlg({'Dose', '% Volume'}, 'Scale final dose');%             if ~isempty(answer)%                 % choose target%                 ROI_names = cellfun(@(c)c.name, obj.handles.hSVPS.Geometry.ROIS, 'UniformOutput', false);%                 [target_idx] = listdlg('ListString', ROI_names, ...%                 'SelectionMode', 'single', 'Name', 'Target Selection', ...%                 'PromptString', 'Please select the target ROI.');%                 opt_dose = prctile(obj.handles.hSVPS.optResults.dose{end}(obj.handles.hSVPS.Geometry.ROIS{target_idx}.ind), 100 - str2double(answer{2}));%                 obj.handles.hSVPS.optResults.dose{end} = obj.handles.hSVPS.optResults.dose{end} * str2double(answer{1}) / opt_dose;%             end%             % END OF Extra dose scaling                        msgbox('Load optResults successfully.')        end%-------------------------------------------------------------------------------        function ExportPinnacleMenu_Callback(obj, src, evt)            if isempty(obj.handles.hSVPS.Geometry)                obj.LoadGeometryMenu_Callback([], [], obj);            end            if isempty(obj.handles.hSVPS.optResults)                obj.LoadOptresultsMenu_Callback([], [], obj);            end            RDXTPS_exportPinnGrid4Tomo(obj.handles.hSVPS.Geometry, obj.handles.hSVPS.optResults);        end%-------------------------------------------------------------------------------        function PlotDVHMenu_Callback(obj, src, evt)            answer = inputdlg({'Enter figure number:', 'Enter line style'}, 'Choose figure');            if isempty(answer{1})                return;            else                fig_idx = str2double(answer{1});            end            if isempty(answer{2})                line_style = '-';            else                line_style = answer{2};            end            figure(fig_idx); hold on;                        % temp solution for karthik dosimetry data            answer = inputdlg('number of fractions');            nfrac = str2double(answer{1});                                for roi_idx = 1:numel(obj.handles.hSVPS.Geometry.ROIS)                if obj.handles.hSVPS.Geometry.ROIS{roi_idx}.visible == true % display == ON                    fprintf('%s\n', obj.handles.hSVPS.Geometry.ROIS{roi_idx}.name);%                     [dvh dosebins] = dvhist(obj.handles.hSVPS.optResults.dose{end}, obj.handles.hSVPS.Geometry.ROIS{roi_idx}.ind);                    % temp solution for karthik dosimetry data                    [dvh dosebins] = dvhist(obj.handles.hSVPS.optResults.dose{end}, ...                        obj.handles.hSVPS.Geometry, ...                        roi_idx, ...                        nfrac);                                        plot(dosebins, dvh, ...                        'Color', obj.handles.hSVPS.Geometry.ROIS{roi_idx}.color, ...                        'LineStyle', line_style, ...                        'DisplayName', obj.handles.hSVPS.Geometry.ROIS{roi_idx}.name);                end            end            set(gca, 'XMinorTick', 'on', 'YMinorTick', 'on');            grid(gca, 'on');            box(gca, 'on');            legend('show');            xlabel('Dose (Gy)');            ylabel('% volume');            hold off;        end%-------------------------------------------------------------------------------        function DoseModeDropdown_Callback(obj, src, evt)            str = get(obj.handles.hDoseModeDropdown, 'String');            obj.handles.hSVPS.dosedisp.mode = str{get(obj.handles.hDoseModeDropdown, 'Value')};        end%-------------------------------------------------------------------------------        function TCSShow_Callback(obj, src, evt)            obj.handles.hSVPS.TCSVisible = ...                get(src, 'Value') == get(src, 'Max');        end%-------------------------------------------------------------------------------        function SaveAsGeometryMenu_Callback(obj, src, evt)            [filename pathname] = uifile('put', '*.mat', 'Save Geometry as...');            % do nothing if cancelled            if isscalar(filename) && filename == 0; return; end                        Geometry = obj.handles.hSVPS.Geometry;            for i = 1:numel(Geometry.ROIS)                if isfield(Geometry.ROIS{i}, 'BW')                    Geometry.ROIS{i}.BW = [];                end            end            save(fullfile(pathname, filename), 'Geometry');        end%-------------------------------------------------------------------------------        function SaveAsOptResultsMenu_Callback(obj, src, evt)            [filename pathname] = uifile('put', '*.mat', 'Save OptResults as...');            % do nothing if cancelled            if isscalar(filename) && filename == 0; return; end                        optResults = obj.handles.hSVPS.optResults;            save(fullfile(pathname, filename), 'optResults');        end%-------------------------------------------------------------------------------    end % methodsend
 |