@@ -832,6 +832,8 @@ bool SDL_Viewer(Drover &DICOM_data,
832
832
bool view_parameter_table = false ;
833
833
bool view_tables_enabled = true ;
834
834
bool view_table_metadata_enabled = false ;
835
+ bool view_tplans_enabled = true ;
836
+ bool view_tplan_metadata_enabled = false ;
835
837
bool save_time_profiles = false ;
836
838
bool view_script_editor_enabled = false ;
837
839
bool view_script_feedback = true ;
@@ -982,6 +984,13 @@ bool SDL_Viewer(Drover &DICOM_data,
982
984
// ImVec4 fail_colour = ImVec4(0.600f, 0.100f, 0.000f, 1.00f);
983
985
} table_display;
984
986
987
+ // RT Plans.
988
+ using disp_tplan_it_t = decltype (DICOM_data.tplan_data .begin ());
989
+ long int tplan_num = -1 ;
990
+ long int tplan_dynstate_num = -1 ;
991
+ long int tplan_statstate_num = -1 ;
992
+
993
+
985
994
// ------------------------------------------ Viewer State --------------------------------------------
986
995
auto background_colour = ImVec4 (0 .025f , 0 .087f , 0 .118f , 1 .00f );
987
996
@@ -1732,6 +1741,25 @@ bool SDL_Viewer(Drover &DICOM_data,
1732
1741
return out;
1733
1742
};
1734
1743
1744
+ // Recompute tplan iterators for the current tplan
1745
+ const auto recompute_tplan_iters = [ &DICOM_data,
1746
+ &tplan_num ](){
1747
+ std::tuple<bool , disp_tplan_it_t > out;
1748
+ std::get<bool >( out ) = false ;
1749
+
1750
+ do {
1751
+ const auto has_tplans = DICOM_data.Has_TPlan_Data ();
1752
+ if ( !has_tplans ) break ;
1753
+ if ( !isininc (1 , tplan_num+1 , DICOM_data.tplan_data .size ()) ) break ;
1754
+ auto tplan_ptr_it = std::next (DICOM_data.tplan_data .begin (), tplan_num);
1755
+ if ( tplan_ptr_it == std::end (DICOM_data.tplan_data ) ) break ;
1756
+
1757
+ std::get<bool >( out ) = true ;
1758
+ std::get<disp_tplan_it_t >( out ) = tplan_ptr_it;
1759
+ }while (false );
1760
+ return out;
1761
+ };
1762
+
1735
1763
1736
1764
const auto recompute_scale_bar_image_state = [ &scale_bar_img,
1737
1765
&scale_bar_texture,
@@ -2545,29 +2573,34 @@ bool SDL_Viewer(Drover &DICOM_data,
2545
2573
view_toggles.view_contouring_enabled = false ;
2546
2574
tagged_pos = {};
2547
2575
}
2548
- ImGui::MenuItem (" Image Metadata" , nullptr , &view_toggles.view_image_metadata_enabled );
2549
2576
ImGui::MenuItem (" Image Hover Tooltips" , nullptr , &view_toggles.show_image_hover_tooltips );
2550
2577
ImGui::MenuItem (" Meshes" , nullptr , &view_toggles.view_meshes_enabled );
2551
2578
if (ImGui::MenuItem (" Plots" , nullptr , &view_toggles.view_plots_enabled )){
2552
2579
lsamps_visible.clear ();
2553
2580
}
2554
- ImGui::MenuItem (" Mesh Metadata" , nullptr , &view_toggles.view_mesh_metadata_enabled );
2555
- ImGui::MenuItem (" Plot Hover Metadata" , nullptr , &view_toggles.view_plots_metadata );
2556
2581
if (ImGui::MenuItem (" Row and Column Profiles" , nullptr , &view_toggles.view_row_column_profiles )){
2557
2582
row_profile.samples .clear ();
2558
2583
col_profile.samples .clear ();
2559
2584
};
2560
2585
if (ImGui::MenuItem (" Time Profiles" , nullptr , &view_toggles.view_time_profiles )){
2561
2586
time_profile.samples .clear ();
2562
2587
};
2563
- ImGui::MenuItem (" Parameter Table " , nullptr , &view_toggles.view_parameter_table );
2588
+ ImGui::MenuItem (" RT Plans " , nullptr , &view_toggles.view_tplans_enabled );
2564
2589
ImGui::MenuItem (" Tables" , nullptr , &view_toggles.view_tables_enabled );
2565
- ImGui::MenuItem (" Table Metadata" , nullptr , &view_toggles.view_table_metadata_enabled );
2566
2590
ImGui::MenuItem (" Script Editor" , nullptr , &view_toggles.view_script_editor_enabled );
2567
2591
ImGui::MenuItem (" Script Feedback" , nullptr , &view_toggles.view_script_feedback );
2592
+ ImGui::MenuItem (" Parameter Table" , nullptr , &view_toggles.view_parameter_table );
2568
2593
ImGui::MenuItem (" Shader Editor" , nullptr , &view_toggles.view_shader_editor_enabled );
2569
2594
ImGui::EndMenu ();
2570
2595
}
2596
+ if (ImGui::BeginMenu (" Metadata" )){
2597
+ ImGui::MenuItem (" Image Metadata" , nullptr , &view_toggles.view_image_metadata_enabled );
2598
+ ImGui::MenuItem (" Mesh Metadata" , nullptr , &view_toggles.view_mesh_metadata_enabled );
2599
+ ImGui::MenuItem (" Plot Hover Metadata" , nullptr , &view_toggles.view_plots_metadata );
2600
+ ImGui::MenuItem (" RT Plan Metadata" , nullptr , &view_toggles.view_tplan_metadata_enabled );
2601
+ ImGui::MenuItem (" Table Metadata" , nullptr , &view_toggles.view_table_metadata_enabled );
2602
+ ImGui::EndMenu ();
2603
+ }
2571
2604
if (ImGui::BeginMenu (" Adjust" )){
2572
2605
if (ImGui::BeginMenu (" Toggle Style" )){
2573
2606
if (ImGui::MenuItem (" Dark Mode" , nullptr , nullptr )){
@@ -4808,6 +4841,117 @@ bool SDL_Viewer(Drover &DICOM_data,
4808
4841
throw ;
4809
4842
}
4810
4843
4844
+ // Display RT plans.
4845
+ const auto display_tplans = [&view_toggles,
4846
+ &drover_mutex,
4847
+ &mutex_dt,
4848
+ &tplan_num,
4849
+ &tplan_dynstate_num,
4850
+ &tplan_statstate_num,
4851
+ &recompute_tplan_iters,
4852
+ &display_metadata_table,
4853
+ &DICOM_data ]() -> void {
4854
+
4855
+ std::unique_lock<std::shared_timed_mutex> drover_lock (drover_mutex, mutex_dt);
4856
+ if (!drover_lock) return ;
4857
+
4858
+ if ( !view_toggles.view_tplans_enabled
4859
+ || !DICOM_data.Has_TPlan_Data () ) return ;
4860
+
4861
+ // Display a selection and navigation window.
4862
+ ImGui::SetNextWindowSize (ImVec2 (450 , 400 ), ImGuiCond_FirstUseEver);
4863
+ ImGui::SetNextWindowPos (ImVec2 (680 , 40 ), ImGuiCond_FirstUseEver);
4864
+ ImGui::Begin (" RT Plans" , &view_toggles.view_tplans_enabled );
4865
+
4866
+ // Scroll through RT plans.
4867
+ if (DICOM_data.Has_TPlan_Data ()){
4868
+ int scroll_tplans = tplan_num;
4869
+ const int N_tplans = DICOM_data.tplan_data .size ();
4870
+ ImGui::SliderInt (" Plan" , &scroll_tplans, 0 , N_tplans - 1 );
4871
+ const long int new_tplan_num = std::clamp (scroll_tplans, 0 , N_tplans - 1 );
4872
+ if (new_tplan_num != tplan_num){
4873
+ tplan_num = new_tplan_num;
4874
+ }
4875
+ }
4876
+
4877
+ ImGui::Checkbox (" View RT plan metadata" , &view_toggles.view_tplan_metadata_enabled );
4878
+
4879
+ if (auto [tplan_is_valid, tplan_ptr_it] = recompute_tplan_iters (); tplan_is_valid){
4880
+
4881
+ // Display the RT plan.
4882
+ //
4883
+ // Note: we currently only display the top-level metadata without any visual display.
4884
+ ImGui::Begin (" RT Plan" , &view_toggles.view_tplans_enabled );
4885
+ display_metadata_table ( (*tplan_ptr_it)->metadata );
4886
+ ImGui::End ();
4887
+
4888
+ if ( view_toggles.view_tplan_metadata_enabled
4889
+ && !(*tplan_ptr_it)->dynamic_states .empty () ){
4890
+ // Scroll through dynamic states.
4891
+ int scroll_dynstate = tplan_dynstate_num;
4892
+ const int N_dynstates = (*tplan_ptr_it)->dynamic_states .size ();
4893
+ ImGui::SliderInt (" Beam" , &scroll_dynstate, 0 , N_dynstates - 1 );
4894
+ const long int new_dynstate_num = std::clamp (scroll_dynstate, 0 , N_dynstates - 1 );
4895
+ if (new_dynstate_num != tplan_dynstate_num){
4896
+ tplan_dynstate_num = new_dynstate_num;
4897
+ }
4898
+ auto *dynstate_ptr = &( (*tplan_ptr_it)->dynamic_states .at (tplan_dynstate_num) );
4899
+
4900
+ // Display the selected dynamic state (i.e., the beam).
4901
+ {
4902
+ std::stringstream ss;
4903
+ ss << " Beam number: " << std::to_string (dynstate_ptr->BeamNumber ) << std::endl;
4904
+ ss << " Cumulative meterset: " << std::to_string (dynstate_ptr->FinalCumulativeMetersetWeight ) << std::endl;
4905
+ ss << " Number of control points: " << std::to_string (dynstate_ptr->static_states .size ()) << std::endl;
4906
+ ImGui::Text (" %s" , ss.str ().c_str ());
4907
+ }
4908
+ if (view_toggles.view_tplan_metadata_enabled ){
4909
+ ImGui::SetNextWindowSize (ImVec2 (650 , 650 ), ImGuiCond_FirstUseEver);
4910
+ ImGui::Begin (" Beam view" , &view_toggles.view_tplan_metadata_enabled );
4911
+ display_metadata_table ( dynstate_ptr->metadata );
4912
+ ImGui::End ();
4913
+ }
4914
+
4915
+ if ( !dynstate_ptr->static_states .empty () ){
4916
+ // Scroll through static states.
4917
+ int scroll_statstate = tplan_statstate_num;
4918
+ const int N_statstates = dynstate_ptr->static_states .size ();
4919
+ ImGui::SliderInt (" Control point" , &scroll_statstate, 0 , N_statstates - 1 );
4920
+ const long int new_statstate_num = std::clamp (scroll_statstate, 0 , N_statstates - 1 );
4921
+ if (new_statstate_num != tplan_statstate_num){
4922
+ tplan_statstate_num = new_statstate_num;
4923
+ }
4924
+ auto *statstate_ptr = &( dynstate_ptr->static_states .at (tplan_statstate_num) );
4925
+
4926
+ // Display the selected static state (i.e., the control point).
4927
+ {
4928
+ std::stringstream ss;
4929
+ ss << " Control point index: " << std::to_string (statstate_ptr->ControlPointIndex ) << std::endl
4930
+ << " Cumulative meterset: " << std::to_string (statstate_ptr->CumulativeMetersetWeight ) << std::endl
4931
+ << " Gantry angle: " << std::to_string (statstate_ptr->GantryAngle ) << std::endl;
4932
+ ImGui::Text (" %s" , ss.str ().c_str ());
4933
+ }
4934
+ if (view_toggles.view_tplan_metadata_enabled ){
4935
+ ImGui::SetNextWindowSize (ImVec2 (650 , 650 ), ImGuiCond_FirstUseEver);
4936
+ ImGui::Begin (" Control point view" , &view_toggles.view_tplan_metadata_enabled );
4937
+ display_metadata_table ( statstate_ptr->metadata );
4938
+ ImGui::End ();
4939
+ }
4940
+
4941
+ }
4942
+ }
4943
+ }
4944
+
4945
+ ImGui::End ();
4946
+ return ;
4947
+ };
4948
+ try {
4949
+ display_tplans ();
4950
+ }catch (const std::exception &e){
4951
+ FUNCWARN (" Exception in display_tplans(): '" << e.what () << " '" );
4952
+ throw ;
4953
+ }
4954
+
4811
4955
// Display the image navigation dialog.
4812
4956
const auto display_image_navigation = [&view_toggles,
4813
4957
&drover_mutex,
0 commit comments