XTPS.m 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. classdef XTPS < handle
  2. %XTPS Main GUI for RDXTPS front end.
  3. %
  4. % Default to contain three SliceViewerPanels for viewing.
  5. %
  6. % TODO:
  7. % Move Geometry and optResults into SliceViewerPanelSource completely so that
  8. % only one copy exist.
  9. % Move color stuff into Geometry so that can be saved.
  10. %
  11. % See also SliceViewerPanel
  12. %
  13. % Author Xiaohu Mo
  14. properties
  15. handles
  16. patient_dir
  17. dosecalcSetup
  18. end
  19. methods
  20. %-------------------------------------------------------------------------------
  21. function obj = XTPS() % XTPS constructor
  22. hMainFigure = figure('MenuBar', 'none', 'Name', 'RDXTPS: No Patient', 'Position', [100 100 800 600], 'Renderer', 'painters');
  23. obj.handles = guihandles(hMainFigure);
  24. obj.handles.hMainFigure = hMainFigure;
  25. % Adding widgets
  26. obj.handles.hROIPanel = uipanel('Parent', obj.handles.hMainFigure, 'Title', 'ROI display');
  27. obj.handles.hROITable = uitable('Parent', obj.handles.hROIPanel);
  28. obj.handles.hDosePanel = uipanel('Parent', obj.handles.hMainFigure, 'Title', 'Dose display');
  29. obj.handles.hDoseTable = uitable('Parent', obj.handles.hDosePanel);
  30. obj.handles.hDoseModeDropdown = uicontrol('Parent', obj.handles.hDosePanel, 'Style', 'popupmenu');
  31. obj.handles.hDoseModeLabel = uicontrol('Parent', obj.handles.hDosePanel, 'Style', 'text');
  32. obj.handles.hMiscPanel = uipanel('Parent', obj.handles.hMainFigure, 'Title', 'Misc settings');
  33. obj.handles.hTCSShow = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'checkbox');
  34. obj.handles.hWWLabel = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'edit');
  35. obj.handles.hWWSlider = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'slider');
  36. obj.handles.hWWEdit = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'edit');
  37. obj.handles.hWLLabel = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'edit');
  38. obj.handles.hWLSlider = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'slider');
  39. obj.handles.hWLEdit = uicontrol('Parent', obj.handles.hMiscPanel, 'Style', 'edit');
  40. obj.handles.hSVPS = SliceViewerPanelSource();
  41. obj.handles.hSliceViewerPanel(1) = SliceViewerPanel(obj.handles.hSVPS, 3, obj.handles.hMainFigure);
  42. obj.handles.hSliceViewerPanel(2) = SliceViewerPanel(obj.handles.hSVPS, 2, obj.handles.hMainFigure);
  43. obj.handles.hSliceViewerPanel(3) = SliceViewerPanel(obj.handles.hSVPS, 1, obj.handles.hMainFigure);
  44. % File menu
  45. obj.handles.hFileMenu = uimenu(obj.handles.hMainFigure, 'Label','File');
  46. obj.handles.hImportDicomRTMenu = uimenu(obj.handles.hFileMenu, 'Label', '1. Import DicomRT Geometry');
  47. % ---- Grozomah: This part edited by Peter for a test
  48. obj.handles.hNRRD1 = uimenu(obj.handles.hFileMenu, 'Label', '1a. Import nrrd Geometry');
  49. obj.handles.hNRRD2 = uimenu(obj.handles.hFileMenu, 'Label', '1b. Import nrrd Geometry 2');
  50. obj.handles.hDosecalcMenu = uimenu(obj.handles.hFileMenu, 'Label', '2. Beamlet Dose Calculation');
  51. % ---- Grozomah: This part edited by Peter for a test
  52. obj.handles.hTest1 = uimenu(obj.handles.hFileMenu, 'Label', '2a. Test 1');
  53. obj.handles.hTest2 = uimenu(obj.handles.hFileMenu, 'Label', '2b. Test 2');
  54. obj.handles.hOptimMenu = uimenu(obj.handles.hFileMenu, 'Label', '3. Plan Optimization');
  55. obj.handles.hSaveOptimResultsMenu = uimenu(obj.handles.hFileMenu, 'Label', '4. Save Optimization Results');
  56. obj.handles.hLoadGeometryMenu = uimenu(obj.handles.hFileMenu, 'Label', 'Load Geometry', 'Separator','on');
  57. obj.handles.hLoadOptresultsMenu = uimenu(obj.handles.hFileMenu, 'Label', 'Load OptResults');
  58. obj.handles.hSaveAsGeometryMenu = uimenu(obj.handles.hFileMenu, 'Label', 'Save Geometry As...', 'Separator','on');
  59. obj.handles.hSaveAsOptResultsMenu = uimenu(obj.handles.hFileMenu, 'Label', 'Save OptResults As...');
  60. obj.handles.hExportPinnacleMenu = uimenu(obj.handles.hFileMenu, 'Label', 'Export Pinnacle Files', 'Separator','on');
  61. % Tools menu
  62. obj.handles.hToolsMenu = uimenu(obj.handles.hMainFigure, 'Label', 'Tools');
  63. obj.handles.hPlotDVHMenu = uimenu(obj.handles.hToolsMenu, 'Label', 'Plot DVH');
  64. % Associate callbacks
  65. set(obj.handles.hMainFigure, 'ResizeFcn', @obj.set_layout);
  66. set(obj.handles.hROITable, 'CellSelectionCallback', @obj.ROITable_CellSelectionCallback);
  67. set(obj.handles.hDoseTable, 'CellSelectionCallback', @obj.DoseTable_CellSelectionCallback);
  68. set(obj.handles.hDoseTable, 'CellEditCallback', @obj.DoseTable_CellEditCallback);
  69. set(obj.handles.hImportDicomRTMenu, 'Callback', @obj.ImportDicomRTMenu_Callback);
  70. set(obj.handles.hDosecalcMenu, 'Callback', @obj.DosecalcMenu_Callback);
  71. % Grozomah
  72. set(obj.handles.hNRRD1, 'Callback', @obj.NRRD1_Callback);
  73. set(obj.handles.hNRRD2, 'Callback', @obj.NRRD2_Callback);
  74. % Grozomah
  75. set(obj.handles.hTest1, 'Callback', @obj.Test1_Callback);
  76. set(obj.handles.hTest2, 'Callback', @obj.Test2_Callback);
  77. set(obj.handles.hSaveOptimResultsMenu, 'Callback', @obj.SaveOptimResultsMenu_Callback);
  78. set(obj.handles.hOptimMenu, 'Callback', @obj.OptimMenu_Callback);
  79. set(obj.handles.hLoadGeometryMenu, 'Callback', @obj.LoadGeometryMenu_Callback);
  80. set(obj.handles.hLoadOptresultsMenu, 'Callback', @obj.LoadOptresultsMenu_Callback);
  81. set(obj.handles.hSaveAsGeometryMenu, 'Callback', @obj.SaveAsGeometryMenu_Callback);
  82. set(obj.handles.hSaveAsOptResultsMenu, 'Callback', @obj.SaveAsOptResultsMenu_Callback);
  83. set(obj.handles.hExportPinnacleMenu, 'Callback', @obj.ExportPinnacleMenu_Callback);
  84. set(obj.handles.hPlotDVHMenu, 'Callback', @obj.PlotDVHMenu_Callback);
  85. set(obj.handles.hDoseModeDropdown, 'Callback', @obj.DoseModeDropdown_Callback);
  86. set(obj.handles.hWWSlider, 'Callback', @obj.WWSlider_Callback);
  87. set(obj.handles.hWWEdit, 'Callback', @obj.WWEdit_Callback);
  88. set(obj.handles.hWLSlider, 'Callback', @obj.WLSlider_Callback);
  89. set(obj.handles.hWLEdit, 'Callback', @obj.WLEdit_Callback);
  90. set(obj.handles.hTCSShow, 'Callback', @obj.TCSShow_Callback);
  91. obj.set_widget_properties();
  92. obj.set_layout();
  93. obj.updateROITable();
  94. obj.updateDoseTable();
  95. obj.updateCTWindowControls();
  96. end % XTPS constructor
  97. %-------------------------------------------------------------------------------
  98. function set_widget_properties(obj)
  99. %% Set widget default properties, excluding those related to data
  100. h = obj.handles; % shortcut
  101. set(h.hROITable, 'ColumnEditable', logical([1 0 0]));
  102. set(h.hROITable, 'ColumnFormat', {'logical', 'char', 'char'});
  103. set(h.hROITable, 'ColumnName', {'V' 'C' 'ROI'});
  104. set(h.hROITable, 'ColumnWidth',{20 15 'auto'});
  105. set(h.hROITable, 'RowName', {'numbered'});
  106. set(h.hROITable, 'RowStriping', 'off');
  107. set(h.hROITable, 'ToolTipString', 'click to set color');
  108. set(h.hDoseTable, 'ColumnEditable', logical([0 1 1]));
  109. set(h.hDoseTable, 'ColumnFormat', {'char' 'numeric' 'numeric'});
  110. set(h.hDoseTable, 'ColumnName', {'C' 'Dose' 'Alpha'});
  111. set(h.hDoseTable, 'ColumnWidth',{15 'auto' 'auto'});
  112. set(h.hDoseTable, 'RowName', []);
  113. set(h.hDoseTable, 'RowStriping', 'off');
  114. set(h.hDoseTable, 'ToolTipString', 'click to set color');
  115. set(h.hDoseModeLabel, 'String', 'display mode');
  116. set(h.hDoseModeDropdown, 'String', {'None' 'Isodose' 'IsodoseLine' 'Colorwash'});
  117. set(h.hWWLabel, 'String', 'Win. Width');
  118. set(h.hWWSlider, 'Min', 0, 'Max', 2048, 'SliderStep', [10/2048 100/2048]);
  119. set(h.hWLLabel, 'String', 'Win. Level');
  120. set(h.hWLSlider, 'Min', 0, 'Max', 2048, 'SliderStep', [10/2048 100/2048]);
  121. set(h.hTCSShow, 'String', 'Show TCS planes', 'Value', get(h.hTCSShow, 'Max'));
  122. % BackgroundColor (get all ui object handles except uitable)
  123. set(findobj(h.hMainFigure, '-property', 'BackgroundColor', '-not', 'Type', 'uitable'), ...
  124. 'BackgroundColor', get(h.hMainFigure, 'Color'));
  125. end
  126. %-------------------------------------------------------------------------------
  127. function set_layout(obj, src, evt)
  128. % Set widget positions and size. Also as ResizeFcn.
  129. h = obj.handles; % shortcut
  130. set(findobj(h.hMainFigure, '-property', 'Units'), 'Units', 'Normalized');
  131. padding = [0.005 0.01];
  132. setPositionXY(h.hDosePanel, [0 0.2], [0.2 0.5], padding);
  133. setPositionXY(h.hROIPanel, [0 0.2], [0.5 1], padding);
  134. setPositionXY(h.hMiscPanel, [0 0.2], [0 0.2], padding);
  135. setPositionXY(h.hSliceViewerPanel(1).hPanel, [0.2 0.7], [0 1], padding);
  136. setPositionXY(h.hSliceViewerPanel(2).hPanel, [0.7 1], [0.5 1], padding);
  137. setPositionXY(h.hSliceViewerPanel(3).hPanel, [0.7 1], [0 0.5], padding);
  138. setPositionXY(h.hROITable, [0 1], [0 1], padding);
  139. setPositionXY(h.hDoseModeDropdown, [0.5 1], [0.9 1], padding);
  140. setPositionXY(h.hDoseModeLabel, [0 0.5], [0.9 1], padding);
  141. setPositionXY(h.hDoseTable, [0 1], [0 0.9], padding);
  142. setPositionXY(h.hWWLabel, [0 0.3], [0.67 1], padding, 1.5, 'characters');
  143. setPositionXY(h.hWWSlider, [0.3 0.85], [0.67 1], padding, 1.5, 'characters');
  144. setPositionXY(h.hWWEdit, [0.85 1], [0.67 1], padding, 1.5, 'characters');
  145. setPositionXY(h.hWLLabel, [0 0.3], [0.33 0.67], padding, 1.5, 'characters');
  146. setPositionXY(h.hWLSlider, [0.3 0.85], [0.33 0.67], padding, 1.5, 'characters');
  147. setPositionXY(h.hWLEdit, [0.85 1], [0.33 0.67], padding, 1.5, 'characters');
  148. setPositionXY(h.hTCSShow, [0 1], [0.0 0.33], padding, 1.5, 'characters');
  149. table_width = getWidthPixel(obj.handles.hROITable);
  150. set(obj.handles.hROITable, 'ColumnWidth', {20 15 table_width-20-15-35});
  151. table_width = getWidthPixel(obj.handles.hDoseTable);
  152. set(obj.handles.hDoseTable, 'ColumnWidth', {15 (table_width-15)/2-2 (table_width-15)/2-2});
  153. % Panel ResizeFcn not executed after init. Has to manually call.
  154. for i = 1:numel(h.hSliceViewerPanel)
  155. h.hSliceViewerPanel(i).set_layout();
  156. end
  157. end
  158. %-------------------------------------------------------------------------------
  159. function load_geometry(obj, geometry_filename)
  160. %% load geometry
  161. if nargin == 2 % load the geometry file if supplied
  162. load(geometry_filename);
  163. elseif nargin == 1 % Geometry should be loaded already
  164. Geometry = obj.handles.hSVPS.Geometry;
  165. if isempty(obj.handles.hSVPS.Geometry)
  166. % TODO appropriate handling
  167. return;
  168. end
  169. end
  170. % add x,y,z axis for plotting purposes
  171. Geometry.x = Geometry.start(1) + Geometry.voxel_size(1) * (0:size(Geometry.rhomw, 1)-1);
  172. Geometry.y = Geometry.start(2) + Geometry.voxel_size(2) * (0:size(Geometry.rhomw, 2)-1);
  173. Geometry.z = Geometry.start(3) + Geometry.voxel_size(3) * (0:size(Geometry.rhomw, 3)-1);
  174. for i = 1:numel(Geometry.ROIS)
  175. % TODO unify curves as N x 3 cell array so we don't need Xcurves & Ycurves,
  176. % but that way will break back-compatibility.
  177. if isfield(Geometry.ROIS{i}, 'Xcurves')
  178. Xcurves_coordinate = cellfun(@(c)c(1,1), Geometry.ROIS{i}.Xcurves);
  179. Geometry.ROIS{i}.Xcurves_slices = ...
  180. round((Xcurves_coordinate - Geometry.start(1)) / Geometry.voxel_size(1)) + 1;
  181. else
  182. % Old version doesn't have XYcurves. Create an empty index to skip plotting.
  183. Geometry.ROIS{i}.Xcurves_slices = [];
  184. end
  185. if isfield(Geometry.ROIS{i}, 'Ycurves')
  186. Ycurves_coordinate = cellfun(@(c)c(1,2), Geometry.ROIS{i}.Ycurves);
  187. Geometry.ROIS{i}.Ycurves_slices = ...
  188. round((Ycurves_coordinate - Geometry.start(2)) / Geometry.voxel_size(2)) + 1;
  189. else
  190. % Old version doesn't have XYcurves. Create an empty index to skip plotting.
  191. Geometry.ROIS{i}.Ycurves_slices = [];
  192. end
  193. Zcurves_coordinate = cellfun(@(c)c(1,3), Geometry.ROIS{i}.curves);
  194. Geometry.ROIS{i}.Zcurves_slices = ...
  195. round((Zcurves_coordinate - Geometry.start(3)) / Geometry.voxel_size(3)) + 1;
  196. end
  197. % Convert data into float
  198. if isinteger(Geometry.data)
  199. Geometry.data = single(Geometry.data);
  200. end
  201. % Init/set display settings if absent
  202. num_ROI = numel(Geometry.ROIS);
  203. for i = 1:num_ROI
  204. if ~isfield(Geometry.ROIS{i}, 'visible')
  205. Geometry.ROIS{i}.visible = false;
  206. end
  207. if ~isfield(Geometry.ROIS{i}, 'color')
  208. Geometry.ROIS{i}.color = rand(1,3);
  209. end
  210. end
  211. % Set/save to SliceViewerPanelSource
  212. obj.handles.hSVPS.Geometry = Geometry;
  213. obj.handles.hSVPS.TCSVisible = ...
  214. (get(obj.handles.hTCSShow, 'Value') == get(obj.handles.hTCSShow, 'Max'));
  215. % updates
  216. obj.handles.hSliceViewerPanel(1).load_data();
  217. obj.handles.hSliceViewerPanel(2).load_data();
  218. obj.handles.hSliceViewerPanel(3).load_data();
  219. obj.updateROITable();
  220. end
  221. %-------------------------------------------------------------------------------
  222. function load_optResults(obj, optresults_filename)
  223. if nargin == 2 % load the optResults file if supplied
  224. load(optresults_filename, 'optResults');
  225. obj.handles.hSVPS.optResults = optResults;
  226. elseif nargin == 1 % optResults should exist already
  227. % Do nothing for now
  228. end
  229. obj.updateDoseTable();
  230. end
  231. %-------------------------------------------------------------------------------
  232. function updateROITable(obj)
  233. % Update ROITable using values in Geometry.ROIS
  234. if isempty(obj.handles.hSVPS.Geometry); return; end
  235. tdata = get(obj.handles.hROITable, 'Data');
  236. % Update table data according to display settings
  237. for i = 1:numel(obj.handles.hSVPS.Geometry.ROIS)
  238. tdata{i, 1} = obj.handles.hSVPS.Geometry.ROIS{i}.visible;
  239. c = obj.handles.hSVPS.Geometry.ROIS{i}.color;
  240. tdata{i, 2} = sprintf('<html><span style="color:%s">&#x25A0</span></html>', rgb2str(c));
  241. tdata{i, 3} = obj.handles.hSVPS.Geometry.ROIS{i}.name;
  242. end
  243. set(obj.handles.hROITable, 'Data', tdata);
  244. drawnow;
  245. obj.set_layout();
  246. end
  247. %-------------------------------------------------------------------------------
  248. function updateDoseTable(obj)
  249. % Update DoseTable using data in SliceViewerPanelSource.dosedisp
  250. % if isempty(obj.handles.hSVPS.Geometry) && isempty(obj.handles.hSVPS.optResults); return; end
  251. tdata = cell(0);
  252. % Update table data according to display settings
  253. for i = 1:numel(obj.handles.hSVPS.dosedisp.level)
  254. tdata{i, 1} = sprintf('<html><span style="color:%s">&#x25A0</span></html>', rgb2str(obj.handles.hSVPS.dosedisp.color(i,:)));
  255. tdata{i, 2} = obj.handles.hSVPS.dosedisp.level(i);
  256. tdata{i, 3} = obj.handles.hSVPS.dosedisp.alpha(i);
  257. end
  258. % disable the callback to prevent recursion
  259. set(obj.handles.hDoseTable, 'CellSelectionCallback', []);
  260. set(obj.handles.hDoseTable, 'Data', tdata);
  261. drawnow; % Flush //IMPORTANT
  262. set(obj.handles.hDoseTable, 'CellSelectionCallback', @obj.DoseTable_CellSelectionCallback);
  263. end
  264. %-------------------------------------------------------------------------------
  265. function updateCTWindowControls(obj)
  266. set(obj.handles.hWWSlider, 'Value', obj.handles.hSVPS.ctWindow.ww);
  267. set(obj.handles.hWWEdit, 'String', num2str(obj.handles.hSVPS.ctWindow.ww));
  268. set(obj.handles.hWLSlider, 'Value', obj.handles.hSVPS.ctWindow.wl);
  269. set(obj.handles.hWLEdit, 'String', num2str(obj.handles.hSVPS.ctWindow.wl));
  270. end
  271. %-------------------------------------------------------------------------------
  272. function ROITable_CellSelectionCallback(obj, hObject, eventdata)
  273. % eventdata structure with the following fields (see UITABLE)
  274. % Indices: row and column indices of the cell(s) currently selecteds
  275. % Avoid "fake" event during initialization
  276. if ~isempty(eventdata.Indices)
  277. roi_idx = eventdata.Indices(1);
  278. if eventdata.Indices(2) == 1
  279. % toggle ROI display in display settings
  280. tdata = get(hObject, 'Data');
  281. obj.handles.hSVPS.Geometry.ROIS{roi_idx}.visible = ~tdata{roi_idx, 1};
  282. else % eventdata.Indices(2) ~= 1
  283. % pick and save color
  284. c = uisetcolor;
  285. if ~(isscalar(c) && c == 0)
  286. obj.handles.hSVPS.Geometry.ROIS{roi_idx}.color = c;
  287. % also make it visible
  288. obj.handles.hSVPS.Geometry.ROIS{roi_idx}.visible = true;
  289. end
  290. end
  291. obj.updateROITable();
  292. end
  293. end
  294. %-------------------------------------------------------------------------------
  295. function DoseTable_CellSelectionCallback(obj, tilde, eventdata)
  296. % eventdata structure with the following fields (see UITABLE)
  297. % Indices: row and column indices of the cell(s) currently selecteds
  298. % Avoid fake event during initialization
  299. if ~isempty(eventdata.Indices)
  300. if eventdata.Indices(2) == 1
  301. % pick and save color
  302. c = uisetcolor;
  303. if ~(isscalar(c) && c == 0)
  304. obj.handles.hSVPS.dosedisp.color(eventdata.Indices(1), :) = c;
  305. obj.updateDoseTable();
  306. end
  307. end
  308. end
  309. end
  310. %-------------------------------------------------------------------------------
  311. function DoseTable_CellEditCallback(obj, tilde, eventdata)
  312. % Update handles.hSVPS.dosedisp
  313. if eventdata.Indices(2) == 2
  314. obj.handles.hSVPS.dosedisp.level(eventdata.Indices(1)) = eventdata.NewData;
  315. elseif eventdata.Indices(2) == 3
  316. obj.handles.hSVPS.dosedisp.alpha(eventdata.Indices(1)) = eventdata.NewData;
  317. end
  318. obj.updateDoseTable();
  319. end
  320. %-------------------------------------------------------------------------------
  321. function WWSlider_Callback(obj, src, evt)
  322. % set window width property of SliceViewerPancelSource
  323. value = round(get(src, 'Value'));
  324. obj.handles.hSVPS.ctWindow.ww = value;
  325. obj.updateCTWindowControls();
  326. end
  327. %-------------------------------------------------------------------------------
  328. function WWEdit_Callback(obj, src, evt)
  329. % set window width property of SliceViewerPancelSource
  330. value = round(str2double(get(src, 'String')));
  331. % clipping to valid value
  332. value = max(value, get(obj.handles.hWWSlider, 'Min'));
  333. value = min(value, get(obj.handles.hWWSlider, 'Max'));
  334. obj.handles.hSVPS.ctWindow.ww = value;
  335. obj.updateCTWindowControls();
  336. end
  337. %-------------------------------------------------------------------------------
  338. function WLSlider_Callback(obj, src, evt)
  339. % set window width property of SliceViewerPancelSource
  340. value = round(get(src, 'Value'));
  341. obj.handles.hSVPS.ctWindow.wl = value;
  342. obj.updateCTWindowControls();
  343. end
  344. %-------------------------------------------------------------------------------
  345. function WLEdit_Callback(obj, src, evt)
  346. % set window width property of SliceViewerPancelSource
  347. value = round(str2double(get(src, 'String')));
  348. % clipping to valid value
  349. value = max(value, get(obj.handles.hWLSlider, 'Min'));
  350. value = min(value, get(obj.handles.hWLSlider, 'Max'));
  351. obj.handles.hSVPS.ctWindow.wl = value;
  352. obj.updateCTWindowControls();
  353. end
  354. %-------------------------------------------------------------------------------
  355. function ImportDicomRTMenu_Callback(obj, src, evt)
  356. [obj.handles.hSVPS.Geometry obj.patient_dir] = RDXTPS_geometry_setup_wizard_ASP();
  357. obj.load_geometry();
  358. end
  359. %-------------------------------------------------------------------------------
  360. % Grozomah
  361. function NRRD1_Callback(obj, src, evt)
  362. disp('NRRD1 called!')
  363. end
  364. %-------------------------------------------------------------------------------
  365. % Grozomah
  366. function NRRD2_Callback(obj, src, evt)
  367. disp('NRRD2 called!')
  368. end
  369. %-------------------------------------------------------------------------------
  370. function DosecalcMenu_Callback(obj, src, evt)
  371. % TODO fix patient_dir system
  372. % [obj.dosecalcSetup obj.patient_dir] = RDXTPS_dosecalcSetup(obj.dosecalcSetup, obj.patient_dir, obj.handles.hSVPS.Geometry);
  373. [obj.dosecalcSetup obj.patient_dir] = RDXTPS_dosecalcSetup(obj.dosecalcSetup, [], obj.handles.hSVPS.Geometry);
  374. % Temporary fix for Gustavo asking energy limit
  375. answer = inputdlg('Machine energy limit: (MeV)', 'Energy limit', 1, {'250'});
  376. maxMachineEnergyStr = answer{1};
  377. % run beamlet dose calculation
  378. cmdline = ['.' filesep 'RDXdosecalc.exe "' fullfile(obj.patient_dir, 'dosecalc_input.txt') '"' ' ' maxMachineEnergyStr];
  379. if ispc
  380. execline = ['cmd /c ' cmdline ' &'];
  381. elseif isunix
  382. % xterm -e "export LD_LIBRARY_PATH=. ; ./RDXdosecalc.exe '../patients/Knew/dosecalc_input.txt' ; read" &
  383. % TODO fix single quote
  384. cmdline = ['xterm -e "export LD_LIBRARY_PATH=. ; ./RDXdosecalc.exe ' fullfile(obj.patient_dir, 'dosecalc_input.txt') ' ; read" &'];
  385. end
  386. msgbox(sprintf('Start beamlet dose calculation.\nRun this if not started automatically:\n%s', cmdline));
  387. system(execline);
  388. end
  389. %-------------------------------------------------------------------------------
  390. % Grozomah
  391. function Test1_Callback(obj, src, evt)
  392. disp('Test 1 works!')
  393. end
  394. %-------------------------------------------------------------------------------
  395. % Grozomah
  396. function Test2_Callback(obj, src, evt)
  397. disp('Test 2 works!')
  398. end
  399. %-------------------------------------------------------------------------------
  400. function OptimMenu_Callback(obj, src, evt)
  401. % TODO fix patient_dir system
  402. % if isempty(obj.patient_dir)
  403. obj.patient_dir = uifile('getdir', 'Select the patient directory');
  404. % end
  405. source_filename = fullfile(obj.patient_dir, 'batch_dose.bin');
  406. target_filename = fullfile(obj.patient_dir, 'beamlet_batch_files', 'beamletbatch0.bin');
  407. mkdir(fullfile(obj.patient_dir, 'beamlet_batch_files'));
  408. try
  409. if ispc % MATLAB movefile() super slow on windows
  410. % TODO confirm overwrite
  411. system(['move "' source_filename '" "' target_filename '"']);
  412. else
  413. movefile(source_filename, target_filename);
  414. end
  415. catch
  416. msgbox('Error moving the beamlet file. Please do so manually.');
  417. end
  418. Nbeamlets = read_ryan_beamlets(target_filename, 'info');
  419. RDXTPS_optimSetup(Nbeamlets, obj.patient_dir, obj.handles.hSVPS.Geometry);
  420. % run optimizer
  421. %---
  422. cd('C:\010-work\003_localGit\WiscPlan_v2\WiscPlanPhotonkV125\WiscPlanEXE')
  423. cmdline = ['.' filesep 'RDXoptimizer.exe "' fullfile(obj.patient_dir, 'optInput.txt') '"'];
  424. msgbox(sprintf('Start optimization\nRun this if not started automatically:\n%s', cmdline));
  425. if ispc
  426. execline = ['cmd /c ' cmdline ' &'];
  427. elseif isunix
  428. % TODO fix single quote
  429. execline = [cmdline];
  430. end
  431. system(execline);
  432. end
  433. %-------------------------------------------------------------------------------
  434. function SaveOptimResultsMenu_Callback(obj, src, evt)
  435. % TODO fix patient_dir system
  436. % if isempty(obj.patient_dir)
  437. obj.patient_dir = uifile('getdir', 'Select the patient directory');
  438. % end
  439. [tilde, obj.handles.hSVPS.optResults] = loadOptResults(obj.patient_dir, 'optInput.txt');
  440. obj.load_optResults();
  441. end
  442. %-------------------------------------------------------------------------------
  443. function LoadGeometryMenu_Callback(obj, src, evt)
  444. [filename pathname] = uifile('get', '*.mat', 'Choose Geometry file to load');
  445. % do nothing if cancelled
  446. if isscalar(filename) && filename == 0; return; end
  447. obj.load_geometry(fullfile(pathname, filename));
  448. end
  449. %-------------------------------------------------------------------------------
  450. function LoadOptresultsMenu_Callback(obj, src, evt)
  451. [filename pathname] = uifile('get', '*.mat', 'Choose OptResults file to load');
  452. % do nothing if cancelled
  453. if isscalar(filename) && filename == 0; return; end
  454. obj.load_optResults(fullfile(pathname, filename));
  455. % % Extra dose scaling. Temporary code for comparison with Tomo plans
  456. % answer = inputdlg({'Dose', '% Volume'}, 'Scale final dose');
  457. % if ~isempty(answer)
  458. % % choose target
  459. % ROI_names = cellfun(@(c)c.name, obj.handles.hSVPS.Geometry.ROIS, 'UniformOutput', false);
  460. % [target_idx] = listdlg('ListString', ROI_names, ...
  461. % 'SelectionMode', 'single', 'Name', 'Target Selection', ...
  462. % 'PromptString', 'Please select the target ROI.');
  463. % opt_dose = prctile(obj.handles.hSVPS.optResults.dose{end}(obj.handles.hSVPS.Geometry.ROIS{target_idx}.ind), 100 - str2double(answer{2}));
  464. % obj.handles.hSVPS.optResults.dose{end} = obj.handles.hSVPS.optResults.dose{end} * str2double(answer{1}) / opt_dose;
  465. % end
  466. % % END OF Extra dose scaling
  467. msgbox('Load optResults successfully.')
  468. end
  469. %-------------------------------------------------------------------------------
  470. function ExportPinnacleMenu_Callback(obj, src, evt)
  471. if isempty(obj.handles.hSVPS.Geometry)
  472. obj.LoadGeometryMenu_Callback([], [], obj);
  473. end
  474. if isempty(obj.handles.hSVPS.optResults)
  475. obj.LoadOptresultsMenu_Callback([], [], obj);
  476. end
  477. RDXTPS_exportPinnGrid4Tomo(obj.handles.hSVPS.Geometry, obj.handles.hSVPS.optResults);
  478. end
  479. %-------------------------------------------------------------------------------
  480. function PlotDVHMenu_Callback(obj, src, evt)
  481. answer = inputdlg({'Enter figure number:', 'Enter line style'}, 'Choose figure');
  482. if isempty(answer{1})
  483. return;
  484. else
  485. fig_idx = str2double(answer{1});
  486. end
  487. if isempty(answer{2})
  488. line_style = '-';
  489. else
  490. line_style = answer{2};
  491. end
  492. figure(fig_idx); hold on;
  493. % temp solution for karthik dosimetry data
  494. answer = inputdlg('number of fractions');
  495. nfrac = str2double(answer{1});
  496. for roi_idx = 1:numel(obj.handles.hSVPS.Geometry.ROIS)
  497. if obj.handles.hSVPS.Geometry.ROIS{roi_idx}.visible == true % display == ON
  498. fprintf('%s\n', obj.handles.hSVPS.Geometry.ROIS{roi_idx}.name);
  499. % [dvh dosebins] = dvhist(obj.handles.hSVPS.optResults.dose{end}, obj.handles.hSVPS.Geometry.ROIS{roi_idx}.ind);
  500. % temp solution for karthik dosimetry data
  501. [dvh dosebins] = dvhist(obj.handles.hSVPS.optResults.dose{end}, ...
  502. obj.handles.hSVPS.Geometry, ...
  503. roi_idx, ...
  504. nfrac);
  505. plot(dosebins, dvh, ...
  506. 'Color', obj.handles.hSVPS.Geometry.ROIS{roi_idx}.color, ...
  507. 'LineStyle', line_style, ...
  508. 'DisplayName', obj.handles.hSVPS.Geometry.ROIS{roi_idx}.name);
  509. end
  510. end
  511. set(gca, 'XMinorTick', 'on', 'YMinorTick', 'on');
  512. grid(gca, 'on');
  513. box(gca, 'on');
  514. legend('show');
  515. xlabel('Dose (Gy)');
  516. ylabel('% volume');
  517. hold off;
  518. end
  519. %-------------------------------------------------------------------------------
  520. function DoseModeDropdown_Callback(obj, src, evt)
  521. str = get(obj.handles.hDoseModeDropdown, 'String');
  522. obj.handles.hSVPS.dosedisp.mode = str{get(obj.handles.hDoseModeDropdown, 'Value')};
  523. end
  524. %-------------------------------------------------------------------------------
  525. function TCSShow_Callback(obj, src, evt)
  526. obj.handles.hSVPS.TCSVisible = ...
  527. get(src, 'Value') == get(src, 'Max');
  528. end
  529. %-------------------------------------------------------------------------------
  530. function SaveAsGeometryMenu_Callback(obj, src, evt)
  531. [filename pathname] = uifile('put', '*.mat', 'Save Geometry as...');
  532. % do nothing if cancelled
  533. if isscalar(filename) && filename == 0; return; end
  534. Geometry = obj.handles.hSVPS.Geometry;
  535. for i = 1:numel(Geometry.ROIS)
  536. if isfield(Geometry.ROIS{i}, 'BW')
  537. Geometry.ROIS{i}.BW = [];
  538. end
  539. end
  540. save(fullfile(pathname, filename), 'Geometry');
  541. end
  542. %-------------------------------------------------------------------------------
  543. function SaveAsOptResultsMenu_Callback(obj, src, evt)
  544. [filename pathname] = uifile('put', '*.mat', 'Save OptResults as...');
  545. % do nothing if cancelled
  546. if isscalar(filename) && filename == 0; return; end
  547. optResults = obj.handles.hSVPS.optResults;
  548. save(fullfile(pathname, filename), 'optResults');
  549. end
  550. %-------------------------------------------------------------------------------
  551. end % methods
  552. end