riCOM_cpp
This repository contains the C++ implementation of the riCOM (Real Time Centre Of Mass) algorithm for 4D Scanning electron microscopy.
Functions
main.cpp File Reference
#include <string>
#include "Ricom.h"
#include "Camera.h"
Include dependency graph for main.cpp:

Go to the source code of this file.

Functions

int run_cli (int argc, char *argv[], Ricom *ricom)
 
int run_gui (Ricom *ricom)
 
void log2file (Ricom *ricom)
 
std::string get_os ()
 
int main (int argc, char *argv[])
 

Function Documentation

◆ get_os()

std::string get_os ( )

Definition at line 59 of file main.cpp.

59 {return "Unknown"};

◆ log2file()

void log2file ( Ricom ricom)

Definition at line 82 of file main.cpp.

83 {
84  if (freopen("ricom.log", "a", stdout) == NULL)
85  {
86  std::cout << "Error redirecting output to log file" << std::endl;
87  }
88  if (freopen("ricom.log", "a", stderr) == NULL)
89  {
90  std::cout << "Error redirecting error output to log file" << std::endl;
91  }
92  ricom->b_print2file = true;
93  auto t = std::time(nullptr);
94  auto tm = *std::localtime(&t);
95  std::cout << std::endl;
96  std::cout << "Ricom version " << version << " started at " << std::put_time(&tm, "%d/%m/%Y %H:%M:%S") << std::endl;
97  std::cout << "OS: " << get_os() << std::endl;
98 }
bool b_print2file
Definition: Ricom.h:222
std::string get_os()
Definition: main.cpp:59

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 62 of file main.cpp.

63 {
64 
65  Ricom ricom;
66 
67  if (argc == 1)
68  {
69 #ifdef _WIN32
70  FreeConsole();
71 #endif
72  log2file(&ricom);
73  return run_gui(&ricom);
74  }
75  else
76  {
77  return run_cli(argc, argv, &ricom);
78  }
79 }
Definition: Ricom.h:154
int run_gui(Ricom *ricom)
Definition: RunGUI.cpp:67
void log2file(Ricom *ricom)
Definition: main.cpp:82
int run_cli(int argc, char *argv[], Ricom *ricom)
Definition: RunCLI.cpp:21

◆ run_cli()

int run_cli ( int  argc,
char *  argv[],
Ricom ricom 
)

Definition at line 21 of file RunCLI.cpp.

22 {
23  ricom->b_plot_cbed = false;
24  std::string save_img = "";
25  std::string save_dat = "";
26 
27  // command line arguments
28  for (int i = 1; i < argc; i++)
29  {
30  if (i + 1 != argc)
31  {
32  // Set filename to read from .mib file
33  if (strcmp(argv[i], "-filename") == 0)
34  {
35  if (std::filesystem::path(argv[i + 1]).extension() == ".t3p")
36  {
37  ricom->camera = RICOM::ADVAPIX;
38  ImGui::DragInt("dwell time", &ricom->dt, 1, 1);
39  }
40  else if (std::filesystem::path(argv[i + 1]).extension() == ".tpx3")
41  {ricom->camera = RICOM::CHEETAH;}
42  ricom->file_path = argv[i + 1];
43  ricom->mode = 0;
44  i++;
45  }
46  // Set IP of camera for TCP connection
47  if (strcmp(argv[i], "-ip") == 0)
48  {
49  ricom->socket.ip = argv[i + 1];
50  ricom->mode = 1;
51  i++;
52  }
53  // Set port data-read port of camera
54  if (strcmp(argv[i], "-port") == 0)
55  {
56  ricom->socket.port = std::stoi(argv[i + 1]);
57  ricom->mode = 1;
58  i++;
59  }
60  // Set width of image
61  if (strcmp(argv[i], "-nx") == 0)
62  {
63  ricom->nx = std::stoi(argv[i + 1]);
64  i++;
65  }
66  // Set height of image
67  if (strcmp(argv[i], "-ny") == 0)
68  {
69  ricom->ny = std::stoi(argv[i + 1]);
70  i++;
71  }
72  // Set dimension of camera
73  if (strcmp(argv[i], "-cam_nxy") == 0)
74  {
75  ricom->n_cam = std::stoi(argv[i + 1]);
76  ricom->offset[0] = ((float)ricom->n_cam - 1) / 2;
77  i++;
78  }
79  // Set skip per row
80  if (strcmp(argv[i], "-skipr") == 0)
81  {
82  ricom->skip_row = std::stoi(argv[i + 1]);
83  i++;
84  }
85  // Set skip per image
86  if (strcmp(argv[i], "-skipi") == 0)
87  {
88  ricom->skip_img = std::stoi(argv[i + 1]);
89  i++;
90  }
91  // Set kernel size
92  if (strcmp(argv[i], "-k") == 0)
93  {
94  ricom->kernel.kernel_size = std::stoi(argv[i + 1]);
95  i++;
96  }
97  // Set CBED Rotation
98  if (strcmp(argv[i], "-r") == 0)
99  {
100  ricom->kernel.rotation = std::stof(argv[i + 1]);
101  i++;
102  }
103  // Set CBED center offset
104  if (strcmp(argv[i], "-offset") == 0)
105  {
106  ricom->offset[0] = std::stof(argv[i + 1]);
107  i++;
108  ricom->offset[1] = std::stof(argv[i + 1]);
109  i++;
110  }
111  // Set CBED center offset
112  if (strcmp(argv[i], "-update_offset") == 0)
113  {
114  ricom->update_offset = (bool)std::stoi(argv[i + 1]);
115  i++;
116  }
117  // Set STEM radii
118  if (strcmp(argv[i], "-radius") == 0)
119  {
120  ricom->b_vSTEM = true;
121  ricom->detector.radius[0] = std::stof(argv[i + 1]);
122  i++;
123  ricom->detector.radius[1] = std::stof(argv[i + 1]);
124  i++;
125  }
126  // Set kernel filter
127  if (strcmp(argv[i], "-f") == 0)
128  {
129  ricom->kernel.b_filter = true;
130  ricom->kernel.kernel_filter_frequency[0] = std::stoi(argv[i + 1]);
131  i++;
132  ricom->kernel.kernel_filter_frequency[1] = std::stoi(argv[i + 1]);
133  i++;
134  }
135  // Set depth of pixel for raw mode
136 
137  // Set number of repetitions
138  if (strcmp(argv[i], "-rep") == 0)
139  {
140  ricom->rep = std::stoi(argv[i + 1]);
141  i++;
142  }
143  // Set Dwell Time
144  if (strcmp(argv[i], "-dwell_time") == 0)
145  {
146  ricom->dt = std::stof(argv[i + 1]);
147  ricom->camera = RICOM::ADVAPIX;
148  i++;
149  }
150  // Set Number of threads
151  if (strcmp(argv[i], "-threads") == 0)
152  {
153  ricom->n_threads = std::stoi(argv[i + 1]);
154  i++;
155  }
156  // Set Number queue size
157  if (strcmp(argv[i], "-queue_size") == 0)
158  {
159  ricom->queue_size = std::stoi(argv[i + 1]);
160  i++;
161  }
162  // Set redraw interval in ms
163  if (strcmp(argv[i], "-redraw_interval") == 0)
164  {
165  ricom->redraw_interval = std::stoi(argv[i + 1]);
166  ricom->b_plot2SDL = true;
167  i++;
168  }
169  // Set path to save reconstruction image
170  if (strcmp(argv[i], "-save_img_path") == 0)
171  {
172  save_img = argv[i + 1];
173  ricom->b_plot2SDL = true;
174  i++;
175  }
176  // Set path to save reconstruction data
177  if (strcmp(argv[i], "-save_data_path") == 0)
178  {
179  save_dat = argv[i + 1];
180  i++;
181  }
182  // plot electric field
183  if (strcmp(argv[i], "-plot_e_field") == 0)
184  {
185  ricom->b_e_mag = (bool)std::stoi(argv[i + 1]);
186  i++;
187  }
188  }
189  }
190 
191  if (ricom->b_plot2SDL)
192  {
193  std::vector<SdlImageWindow> image_windows;
194  std::thread run_thread;
195  // run_thread = std::thread(&Ricom::run, ricom, ricom->mode);
196  while (ricom->srf_ricom == NULL)
197  {
198  SDL_Delay(ricom->redraw_interval);
199  }
200 
201  // run_thread.detach();
202  ricom->run(ricom->mode);
203 
204  // // Initializing SDL
205  SDL_DisplayMode DM; // To get the current display size
206  SDL_Event event; // Event variable
207 
208  SDL_Init(SDL_INIT_EVERYTHING);
209  SDL_GetCurrentDisplayMode(0, &DM);
210  float scale = (std::min)(((float)DM.w) / ricom->nx, ((float)DM.h) / ricom->ny) * 0.8;
211  bool b_redraw = false;
212  image_windows.push_back(SdlImageWindow("riCOM", ricom->srf_ricom, ricom->nx, ricom->ny, scale));
213  if (ricom->b_vSTEM)
214  {
215  image_windows.push_back(SdlImageWindow("vSTEM", ricom->srf_stem, ricom->nx, ricom->ny, scale));
216  }
217  if (ricom->b_e_mag)
218  {
219  image_windows.push_back(SdlImageWindow("E-Field", ricom->srf_e_mag, ricom->nx, ricom->ny, scale));
220  }
221 
222  bool b_open_window = true;
223  while (b_open_window)
224  {
225  if (ricom->p_prog_mon != nullptr)
226  {
227  if (ricom->p_prog_mon->report_set_public)
228  {
229  b_redraw = true;
230  ricom->p_prog_mon->report_set_public = false;
231  }
232  else
233  {
234  b_redraw = true;
235  }
236  }
237 
238  if (b_redraw)
239  {
240  for (auto &wnd : image_windows)
241  {
242  wnd.update_image();
243  }
244  }
245 
246  while (SDL_PollEvent(&event))
247  {
248  if (event.type == SDL_QUIT ||
249  (event.type == SDL_WINDOWEVENT &&
250  event.window.event == SDL_WINDOWEVENT_CLOSE))
251  {
252  ricom->rc_quit = true;
253  SDL_Delay(ricom->redraw_interval);
254  b_open_window = false;
255  }
256  }
257  }
258  }
259  else
260  {
261  ricom->run(ricom->mode);
262  }
263  if (save_dat != "")
264  {
265  save_numpy(&save_dat, ricom->nx, ricom->ny, &ricom->ricom_image);
266  std::cout << "riCOM reconstruction data saved as " + save_dat << std::endl;
267  }
268  if (save_img != "")
269  {
270  save_image(&save_img, ricom->srf_ricom);
271  std::cout << "riCOM reconstruction image saved as " + save_img << std::endl;
272  }
273  return 0;
274 }
void save_numpy(std::string *path, int nx, int ny, std::vector< T > *data)
Definition: GuiUtils.cpp:17
void save_image(std::string *path, SDL_Surface *sdl_srf)
Definition: GuiUtils.cpp:30
std::atomic< bool > report_set_public
std::array< float, 2 > radius
Definition: Ricom.h:131
bool b_filter
Definition: Ricom.h:60
float rotation
Definition: Ricom.h:64
std::array< int, 2 > kernel_filter_frequency
Definition: Ricom.h:61
int kernel_size
Definition: Ricom.h:59
int skip_img
Definition: Ricom.h:270
void run(int mode)
Definition: Ricom.cpp:661
SocketConnector socket
Definition: Ricom.h:220
int redraw_interval
Definition: Ricom.h:223
int mode
Definition: Ricom.h:258
int n_threads
Definition: Ricom.h:276
int rep
Definition: Ricom.h:267
bool update_offset
Definition: Ricom.h:227
bool b_plot2SDL
Definition: Ricom.h:238
SDL_Surface * srf_e_mag
Definition: Ricom.h:293
std::string file_path
Definition: Ricom.h:221
int nx
Definition: Ricom.h:262
RICOM::cameras camera
Definition: Ricom.h:259
Ricom_detector detector
Definition: Ricom.h:241
bool rc_quit
Definition: Ricom.h:285
int queue_size
Definition: Ricom.h:278
bool b_e_mag
Definition: Ricom.h:234
SDL_Surface * srf_ricom
Definition: Ricom.h:287
ProgressMonitor * p_prog_mon
Definition: Ricom.h:225
bool b_plot_cbed
Definition: Ricom.h:230
SDL_Surface * srf_stem
Definition: Ricom.h:289
std::vector< float > ricom_image
Definition: Ricom.h:247
int skip_row
Definition: Ricom.h:269
int n_cam
Definition: Ricom.h:265
bool b_vSTEM
Definition: Ricom.h:233
int ny
Definition: Ricom.h:263
int dt
Definition: Ricom.h:266
std::array< float, 2 > offset
Definition: Ricom.h:243
Ricom_kernel kernel
Definition: Ricom.h:242
std::string ip
@ ADVAPIX
Definition: Ricom.h:148
@ CHEETAH
Definition: Ricom.h:149

◆ run_gui()

int run_gui ( Ricom ricom)

Definition at line 67 of file RunGUI.cpp.

68 {
69  std::thread run_thread;
70  std::thread py_thread;
71  if (SDL_Init(SDL_INIT_EVERYTHING) != 0) // fail here
72  {
73  printf("Error: %s\n", SDL_GetError());
74  return -1;
75  }
76 
77  // Decide GL+GLSL versions
78 #if defined(IMGUI_IMPL_OPENGL_ES2)
79  // GL ES 2.0 + GLSL 100
80  const char *glsl_version = "#version 100";
81  SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
82  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
83  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
84  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
85 #elif defined(__APPLE__)
86  // GL 3.2 Core + GLSL 150
87  const char *glsl_version = "#version 150";
88  SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac
89  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
90  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
91  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
92 #else
93  // GL 3.0 + GLSL 130
94  const char *glsl_version = "#version 130";
95  SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
96  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
97  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
98  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
99 #endif
100 
101  // Create window with graphics context
102  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
103  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
104  SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
105  SDL_Window *window = SDL_CreateWindow("riCOM", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1200, 800, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL);
106  if (window == NULL)
107  {
108  std::cout << "Window could not be created! SDL Error: " << SDL_GetError() << std::endl;
109  }
110  SDL_GLContext gl_context = SDL_GL_CreateContext(window);
111  SDL_GL_MakeCurrent(window, gl_context);
112  SDL_GL_SetSwapInterval(1); // Enable vsync
113 
114  // Setup Dear ImGui context
115  IMGUI_CHECKVERSION();
116  ImGui::CreateContext();
117  ImGuiIO &io = ImGui::GetIO();
118  (void)io;
119 
120  mINI::INIFile ini_file("imgui.ini");
121  mINI::INIStructure ini_cfg;
122  ini_file.read(ini_cfg);
123 
124  ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
125  // Setup Platform/Renderer backends
126  ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
127  ImGui_ImplOpenGL3_Init(glsl_version);
128 
129  io.Fonts->AddFontFromMemoryCompressedTTF(KarlaRegular_compressed_data, KarlaRegular_compressed_size, 14.0f);
130  io.Fonts->AddFontFromMemoryCompressedTTF(RobotoMedium_compressed_data, RobotoMedium_compressed_size, 14.0f);
131  io.Fonts->AddFontFromMemoryCompressedTTF(CousineRegular_compressed_data, CousineRegular_compressed_size, 14.0f);
132  io.Fonts->AddFontFromMemoryCompressedTTF(DroidSans_compressed_data, DroidSans_compressed_size, 14.0f);
133  io.Fonts->AddFontFromMemoryCompressedTTF(ProggyClean_compressed_data, ProggyClean_compressed_size, 14.0f);
134  io.Fonts->AddFontFromMemoryCompressedTTF(ProggyTiny_compressed_data, ProggyTiny_compressed_size, 14.0f);
135 
136  io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
137  io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
138  // Multi-Viewport not yet supported with SDL2
139  // io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;// Enable Multi-Viewport / Platform Windows
140 
141  ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
142  ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
143  ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
144  ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white
145 
146  ImVec2 menu_bar_size;
147  ImVec2 control_menu_size(200, 800);
148 
149  const size_t n_textures = 16;
150  GLuint uiTextureIDs[n_textures];
151  glGenTextures(n_textures, uiTextureIDs);
152 
153  for (size_t i = 0; i < n_textures; i++)
154  {
155  glBindTexture(GL_TEXTURE_2D, uiTextureIDs[i]);
156  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
157  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
158  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
159  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
160  }
161 
162  // create a file browser instances
163  ImGui::FileBrowser openFileDialog;
164  openFileDialog.SetTitle("Open .mib or .t3p file");
165  openFileDialog.SetTypeFilters({".mib", ".t3p", ".tpx3"});
166  ImGui::FileBrowser saveFileDialog(ImGuiFileBrowserFlags_EnterNewFilename | ImGuiFileBrowserFlags_CreateNewDir);
167  saveFileDialog.SetTitle("Save image as .png");
168  ImGui::FileBrowser saveDataDialog(ImGuiFileBrowserFlags_EnterNewFilename | ImGuiFileBrowserFlags_CreateNewDir);
169  saveDataDialog.SetTitle("Save COM data in binary format");
170  std::string filename = "";
171 
172  // Main loop conditional flags
173  bool b_done = false;
174  bool b_acq_open = false;
175  bool b_started = false;
176  bool b_file_selected = false;
177  bool b_restarted = false;
178 
179  // Cheetah Setting (to send to the server)
180  CheetahComm cheetah_comm;
181  ricom->socket.connect_socket();
182 
183 
184  // INI file settings to restore previous session settings
185  // Appearance
186  int font_index = 0;
187  int style_index = 0;
188  ImGuiINI::check_ini_setting(ini_cfg, "Appearance", "CBED Colormap", ricom->cbed_cmap);
189  ImGuiINI::check_ini_setting(ini_cfg, "Appearance", "Font", font_index);
190  ImGuiINI::set_font(font_index);
191  ImGuiINI::check_ini_setting(ini_cfg, "Appearance", "Style", style_index);
192  ImGuiINI::set_style(style_index);
193  // Hardware Settings
194  std::string python_path;
195 #ifdef _WIN32
196  python_path = "py";
197 #else
198  python_path = "python3";
199 #endif
200  ImGuiINI::check_ini_setting(ini_cfg, "Hardware", "Threads", ricom->n_threads);
201  ImGuiINI::check_ini_setting(ini_cfg, "Hardware", "Queue Size", ricom->queue_size);
202  ImGuiINI::check_ini_setting(ini_cfg, "Hardware", "Image Refresh Interval [ms]", ricom->redraw_interval);
203  // Advapix Settings
204  ImGuiINI::check_ini_setting(ini_cfg, "Advapix", "nx/y", ricom->n_cam);
205  // Cheetah Settings
206  ImGuiINI::check_ini_setting(ini_cfg, "Cheetah", "nx/y", ricom->n_cam);
207  ImGuiINI::check_ini_setting(ini_cfg, "Cheetah", "data_port", ricom->socket.port);
208  ImGuiINI::check_ini_setting(ini_cfg, "Cheetah", "ip", ricom->socket.ip);
209 
210  const char *cmaps[] = {"Parula", "Heat", "Jet", "Turbo", "Hot", "Gray", "Magma", "Inferno", "Plasma", "Viridis", "Cividis", "Github", "HSV"};
211  bool b_redraw = false;
212  bool b_trigger_update = false;
213  float menu_split_v = control_menu_size.y * 0.8f;
214 
215  // Initialize Frequency approximation (for plotting only)
216  ricom->kernel.approximate_frequencies((size_t)ricom->nx);
217 
218  // Initialize all possible Windows, so everything is on the stack
219  bool show_com_x = false;
220  bool show_com_y = false;
221  bool ricom_fft = false;
222  bool vstem_fft = false;
223  bool e_field_fft = false;
225  std::map<std::string, ImGuiImageWindow<float>> generic_windows_f;
226  std::map<std::string, ImGuiImageWindow<std::complex<float>>> generic_windows_c;
227  generic_windows_f.emplace("RICOM", ImGuiImageWindow<float>("RICOM", &uiTextureIDs[1], true, 9, common_flags | GIM_Flags::FftButton, &ricom->b_ricom));
228  generic_windows_f.emplace("RICOM-FFT", ImGuiImageWindow<float>("RICOM-FFT", &uiTextureIDs[2], false, 4, common_flags, &ricom_fft));
229  GENERIC_WINDOW("RICOM").fft_window = &GENERIC_WINDOW("RICOM-FFT");
230 
231  generic_windows_f.emplace("vSTEM", ImGuiImageWindow<float>("vSTEM", &uiTextureIDs[3], true, 9, common_flags | GIM_Flags::FftButton, &ricom->b_vSTEM));
232  generic_windows_f.emplace("vSTEM-FFT", ImGuiImageWindow<float>("vSTEM-FFT", &uiTextureIDs[4], false, 4, common_flags, &vstem_fft));
233  GENERIC_WINDOW("vSTEM").fft_window = &GENERIC_WINDOW("vSTEM-FFT");
234 
235  generic_windows_f.emplace("COM-X", ImGuiImageWindow<float>("RICOM-COMX", &uiTextureIDs[5], true, 9, common_flags, &show_com_x));
236  generic_windows_f.emplace("COM-Y", ImGuiImageWindow<float>("RICOM-COMY", &uiTextureIDs[6], true, 9, common_flags, &show_com_y));
237 
238  generic_windows_c.emplace("E-FIELD", ImGuiImageWindow<std::complex<float>>("E-Field", &uiTextureIDs[7], true, 12, common_flags | GIM_Flags::FftButton, &ricom->b_e_mag));
239  generic_windows_f.emplace("E-Field-FFT", ImGuiImageWindow<float>("E-Field-FFT", &uiTextureIDs[8], false, 4, common_flags, &e_field_fft));
240  GENERIC_WINDOW_C("E-FIELD").fft_window = &GENERIC_WINDOW("E-Field-FFT");
241 
242  ricom->kernel.draw_surfaces();
243  bind_tex(ricom->kernel.srf_kx, uiTextureIDs[9]);
244  bind_tex(ricom->kernel.srf_ky, uiTextureIDs[10]);
245 
246  ImGuiID dock_id = 3775;
247  Main_Dock main_dock(dock_id);
248  static int drag_min_pos = 1;
249 
250  // Main loop
251  while (!b_done)
252  {
253  // Poll and handle events (inputs, window resize, etc.)
254  SDL_Event event;
255  while (SDL_PollEvent(&event))
256  {
257  ImGui_ImplSDL2_ProcessEvent(&event);
258  if (event.type == SDL_QUIT)
259  b_done = true;
260  if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
261  b_done = true;
262  }
263 
264  // Start the Dear ImGui frame
265  ImGui_ImplOpenGL3_NewFrame();
266  ImGui_ImplSDL2_NewFrame();
267  ImGui::NewFrame();
268 
269  // Menu
270  if (ImGui::BeginMainMenuBar())
271  {
272  if (ImGui::BeginMenu("Appearance"))
273  {
274  ImGui::Combo("CBED Colormap", &ricom->cbed_cmap, cmaps, IM_ARRAYSIZE(cmaps));
275  ImGuiINI::ShowFontSelector("Font", font_index, ini_cfg);
276  ImGuiINI::ShowStyleSelector("Style", style_index, ini_cfg);
277  ImGui::EndMenu();
278  }
279  if (ImGui::BeginMenu("Hardware Settings"))
280  {
281  ImGui::Text("Plotting");
282  if (ImGui::DragInt("Image Refresh Interval [ms]", &ricom->redraw_interval, 20, 10, 1000))
283  {
284  ini_cfg["Hardware"]["Image Refresh Interval [ms]"] = std::to_string(ricom->redraw_interval);
285  }
286  ImGui::Separator();
287 
288  ImGui::Text("Multithreading");
289  if (ImGui::DragInt("Threads", &ricom->n_threads, 1, 1, *&ricom->n_threads_max))
290  {
291  ini_cfg["Hardware"]["Threads"] = std::to_string(ricom->n_threads);
292  }
293  if (ImGui::DragInt("Queue Size", &ricom->queue_size, 1, 1, 256))
294  {
295  ini_cfg["Hardware"]["Queue Size"] = std::to_string(ricom->queue_size);
296  }
297  ImGui::EndMenu();
298  }
299  if (ImGui::BeginMenu("Imaging Modes"))
300  {
301  if (ImGui::Checkbox("Show riCOM", &ricom->b_ricom))
302  {
303  if (&ricom->b_ricom)
304  {
305  GENERIC_WINDOW("RICOM").set_data(ricom->nx, ricom->ny, &ricom->ricom_image);
306  }
307  else
308  {
309  *GENERIC_WINDOW("RICOM").pb_open = false;
310  }
311  }
312  if (ImGui::Checkbox("Show CoM-X", &show_com_x))
313  {
314  if (show_com_x)
315  {
316  GENERIC_WINDOW("COM-X").set_data(ricom->nx, ricom->ny, &ricom->comx_image);
317  }
318  else
319  {
320  *GENERIC_WINDOW("COM-X").pb_open = false;
321  }
322  }
323  if (ImGui::Checkbox("Show CoM-Y", &show_com_y))
324  {
325  if (show_com_y)
326  {
327  GENERIC_WINDOW("COM-Y").set_data(ricom->nx, ricom->ny, &ricom->comy_image);
328  }
329  else
330  {
331  *GENERIC_WINDOW("COM-Y").pb_open = false;
332  }
333  }
334  if (ImGui::Checkbox("Show E-Field", &ricom->b_e_mag))
335  {
336  if (ricom->b_e_mag)
337  {
338  GENERIC_WINDOW_C("E-FIELD").set_data(ricom->nx, ricom->ny, &ricom->e_field_data);
339  }
340  else
341  {
342  *GENERIC_WINDOW_C("E-FIELD").pb_open = false;
343  }
344  }
345  if (ImGui::Checkbox("View vSTEM Image", &ricom->b_vSTEM))
346  {
347  if (ricom->b_vSTEM)
348  {
349  GENERIC_WINDOW("vSTEM").set_data(ricom->nx, ricom->ny, &ricom->stem_image);
350  }
351  else
352  {
353  *GENERIC_WINDOW("vSTEM").pb_open = false;
354  }
355  }
356  ImGui::EndMenu();
357  }
358  menu_bar_size = ImGui::GetWindowSize();
359  ImGui::EndMainMenuBar();
360  }
361 
362  const ImGuiViewport *viewport = ImGui::GetMainViewport();
363  if (ricom->p_prog_mon != nullptr)
364  {
365  if (ricom->p_prog_mon->report_set_public)
366  {
367  b_redraw = true;
368  ricom->p_prog_mon->report_set_public = false;
369  }
370  }
371  else
372  {
373  b_redraw = true;
374  }
375 
376  ImVec2 pos = viewport->Pos;
377  pos[1] += menu_bar_size.y;
378  ImGui::SetNextWindowPos(pos);
379 
380  control_menu_size.y = viewport->Size.y - menu_bar_size.y;
381  ImGui::SetNextWindowSize(control_menu_size);
382  ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1));
383 
384  ImGui::Begin("Navigation", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar);
385 
386  bool b_nx_changed = false;
387  ImGui::BeginChild("Controls", ImVec2(0, menu_split_v), false);
388  if (ImGui::CollapsingHeader("General Settings", ImGuiTreeNodeFlags_DefaultOpen))
389  {
390  ImGui::Text("Scan Area");
391  b_nx_changed = ImGui::DragInt("nx", &ricom->nx, 1, 1, SDL_MAX_SINT32);
392  ImGui::DragInt("ny", &ricom->ny, 1, 1, SDL_MAX_SINT32);
393  ImGui::DragInt("Repetitions", &ricom->rep, 1, 1, SDL_MAX_SINT32);
394  ImGui::BeginGroup();
395  ImGui::DragInt("skip row", &ricom->skip_row, 1, 0, SDL_MAX_SINT32);
396  ImGui::DragInt("skip img", &ricom->skip_img, 1, 0, SDL_MAX_SINT32);
397  ImGui::EndGroup();
398  if (ImGui::IsItemHovered())
399  {
400  ImGui::SetTooltip("Adjustments for Flyback time:\n skip row: skip n frames after each scan line\n skip img: skip n frames after each scan (when using repetitions)");
401  }
402 
403  ImGui::Text("CBED Centre");
404  int *max_nx = &ricom->n_cam;
405  bool offset_changed = ImGui::DragFloat2("Centre", &ricom->offset[0], 0.1f, 0.0, (float)*max_nx);
406  if (offset_changed)
407  {
408  ricom->b_recompute_detector = true;
409  ricom->b_recompute_kernel = true;
410  }
411  ImGui::Checkbox("Auto Centering", &ricom->update_offset);
412  }
413 
414  if (ImGui::CollapsingHeader("RICOM Settings", ImGuiTreeNodeFlags_DefaultOpen))
415  {
416  static int filter_max = 8;
417  static bool init_kernel_img = true;
418  bool kernel_changed = ImGui::DragInt("Kernel Size", &ricom->kernel.kernel_size, 1, 1, 300);
419  if (kernel_changed)
420  filter_max = ceil(sqrt(pow(ricom->kernel.kernel_size, 2) * 2));
421  bool rot_changed = ImGui::SliderFloat("Rotation", &ricom->kernel.rotation, 0.0f, 360.0f, "%.1f deg");
422  bool filter_changed = ImGui::Checkbox("Use filter?", &ricom->kernel.b_filter);
423  bool filter_changed2 = ImGui::DragInt2("low / high", &ricom->kernel.kernel_filter_frequency[0], 1, 0, filter_max);
424  if (init_kernel_img || rot_changed || kernel_changed || filter_changed || filter_changed2)
425  {
426  init_kernel_img = false;
427  if (ricom->b_busy)
428  {
429  ricom->b_recompute_kernel = true;
430  }
431  else
432  {
433  ricom->kernel.compute_kernel();
434  }
435  GENERIC_WINDOW("RICOM").reset_min_max();
436  ricom->kernel.draw_surfaces();
437  bind_tex(ricom->kernel.srf_kx, uiTextureIDs[9]);
438  bind_tex(ricom->kernel.srf_ky, uiTextureIDs[10]);
439  }
440  if (kernel_changed || b_nx_changed)
441  {
442  ricom->kernel.approximate_frequencies((size_t)ricom->nx);
443  }
444  float sxk = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y * 3) / 2;
445  ImGui::Image((void *)(intptr_t)uiTextureIDs[9], ImVec2(sxk, sxk), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f));
446  ImGui::SameLine();
447  ImGui::Image((void *)(intptr_t)uiTextureIDs[10], ImVec2(sxk, sxk), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f));
448  ImGui::PlotLines("Frequencies", ricom->kernel.f_approx.data(), ricom->kernel.f_approx.size(), 0, NULL, 0.0f, 1.0f, ImVec2(0, 50));
449  }
450  if (ricom->b_vSTEM)
451  {
452  if (ImGui::CollapsingHeader("vSTEM Settings", ImGuiTreeNodeFlags_DefaultOpen))
453  {
454  bool inner_changed = ImGui::SliderFloat("Inner Radius", &ricom->detector.radius[0], 0.0f, 182.0f, "%.1f px");
455  bool outer_changed = ImGui::SliderFloat("Outer Radius", &ricom->detector.radius[1], 0.0f, 182.0f, "%.1f px");
456  if (inner_changed || outer_changed)
457  {
458  ricom->b_recompute_detector = true;
459  GENERIC_WINDOW("vSTEM").reset_min_max();
460  }
461  }
462  }
463 
464  if (ImGui::CollapsingHeader("Stream reconstruction", ImGuiTreeNodeFlags_DefaultOpen)){
465 
466  if (ImGui::Button("Preview", ImVec2(-1.0f, 0.0f)))
467  {
468  cheetah_comm.stop();
469  ricom->b_continuous = true;
470  cheetah_comm.tpx3_det_config();
471  cheetah_comm.tpx3_cam_init();
472  cheetah_comm.tpx3_destination();
473 
474  // ricom->socket.connect_socket();
475  // ricom->socket.flush_socket();
476  b_started = true;
477  b_restarted = true;
478  ricom->camera = RICOM::CHEETAH;
479  run_thread = std::thread(&Ricom::run, ricom, 1);
480  run_thread.detach();
481  std::this_thread::sleep_for(std::chrono::milliseconds(500));
482  cheetah_comm.start();
483  // RICOM::run(ricom, RICOM::TCP);
484  // GENERIC_WINDOW("RICOM").set_data(ricom->nx, ricom->ny, &ricom->ricom_image);
485  }
486 
487  if (ImGui::Button("Acquire", ImVec2(-1.0f, 0.0f)))
488  {
489  cheetah_comm.stop();
490  ricom->b_continuous = false;
491  cheetah_comm.tpx3_det_config();
492  cheetah_comm.tpx3_cam_init();
493  cheetah_comm.tpx3_destination();
494  ricom->camera = RICOM::CHEETAH;
495  run_thread = std::thread(&Ricom::run, ricom, 1);
496  run_thread.detach();
497  std::this_thread::sleep_for(std::chrono::milliseconds(500));
498  cheetah_comm.start();
499  // GENERIC_WINDOW("RICOM").set_data(ricom->nx, ricom->ny, &ricom->ricom_image);
500  }
501 
502  if (ImGui::Button("Stop", ImVec2(-1.0f, 0.0f)))
503  {
504  cheetah_comm.stop();
505  ricom->rc_quit = true;
506  ricom->b_continuous = false;
507  // b_redraw = true;
508  }
509 
510  ImGui::Checkbox("Cumulative Mode", &ricom->b_cumulative);
511 
512  }
513 
514 
515  if (ImGui::CollapsingHeader("File reconstruction", ImGuiTreeNodeFlags_DefaultOpen))
516  {
517 
518  if (ImGui::Button("Open File", ImVec2(-1.0f, 0.0f)))
519  {
520  openFileDialog.Open();
521  }
522 
523  openFileDialog.Display();
524  if (openFileDialog.HasSelected())
525  {
526  filename = openFileDialog.GetSelected().string();
527  b_file_selected = true;
528  openFileDialog.ClearSelected();
529  ricom->mode = 0;
530  ricom->file_path = filename;
531  }
532  if (b_file_selected)
533  {
534  ImGui::Text("File: %s", filename.c_str());
535 
536  if (std::filesystem::path(filename).extension() == ".t3p")
537  {
538  ricom->camera = RICOM::ADVAPIX;
539  ImGui::DragInt("dwell time", &ricom->dt, 1, 1);
540  }
541  else if (std::filesystem::path(filename).extension() == ".tpx3")
542  ricom->camera = RICOM::CHEETAH;
543 
544  if (ImGui::Button("Run File", ImVec2(-1.0f, 0.0f)))
545  {
546  run_thread = std::thread(&Ricom::run, ricom, 0);
547  b_started = true;
548  b_restarted = true;
549  run_thread.detach();
550  // GENERIC_WINDOW("RICOM").set_data(ricom->nx, ricom->ny, &ricom->ricom_image);
551  }
552  }
553  }
554  ImGui::EndChild();
555 
556  float panel_h_min = control_menu_size.y * 0.4;
557  float panel_h_max = control_menu_size.y - 32;
558  v_splitter(5, menu_split_v, panel_h_min, panel_h_max, pos.y + ImGui::GetStyle().ItemSpacing.y * 3);
559 
560  ImGui::BeginChild("Progress", ImVec2(0, 0), true, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar);
561  ImGui::ProgressBar(ricom->fr_count / (ricom->fr_total), ImVec2(-1.0f, 0.0f));
562  ImGui::Text("Speed: %.2f kHz", ricom->fr_freq);
563  if (ImGui::Button("Quit", ImVec2(-1.0f, 0.0f)))
564  {
565  ricom->rc_quit = true;
566  b_redraw = true;
567  }
568 
569  ImGui::Text("COM= %.2f, %.2f", ricom->com_public[0], ricom->com_public[1]);
570 
571  // CBED Plot Area/DockSpace
572  ImGui::DockSpace(1319);
573  static auto first_time = true;
574  if (first_time)
575  {
576  first_time = false;
577  ImGui::DockBuilderRemoveNode(1319); // clear any previous layout
578  ImGui::DockBuilderAddNode(1319, ImGuiDockNodeFlags_DockSpace);
579  ImGui::DockBuilderDockWindow("CBED", 1319);
580  ImGui::DockBuilderFinish(1319);
581  }
582  ImGui::EndChild();
583  control_menu_size = ImGui::GetWindowSize();
584  ImGui::End();
585 
586  main_dock.render(ImVec2(control_menu_size.x, pos.y), ImVec2(viewport->Size.x - control_menu_size.x, viewport->Size.y - menu_bar_size.y));
587 
588  ImGui::Begin("CBED", nullptr, ImGuiWindowFlags_NoScrollbar);
589  ImGui::Checkbox("Plot CBED", &ricom->b_plot_cbed);
590  ImVec2 rem_space = ImGui::GetContentRegionAvail();
591  float tex_wh = (std::min)(rem_space.x, rem_space.y);
592  ImVec2 p = ImGui::GetCursorScreenPos();
593 
594  float com_rel_x = p.x + tex_wh * (ricom->com_public[0] / ricom->n_cam);
595  float com_rel_y = p.y + tex_wh * (ricom->com_public[1] / ricom->n_cam);
596 
597  float centre_x = p.x + tex_wh * (ricom->offset[0] / ricom->n_cam);
598  float centre_y = p.y + tex_wh * (ricom->offset[1] / ricom->n_cam);
599 
600  com_rel_x = (std::max)(p.x, com_rel_x);
601  com_rel_y = (std::max)(p.y, com_rel_y);
602  com_rel_x = (std::min)(p.x + tex_wh, com_rel_x);
603  com_rel_y = (std::min)(p.y + tex_wh, com_rel_y);
604 
605  float cross_width = tex_wh / 15.0f;
606  // if (b_redraw)
607  // {
608  // if (ricom->srf_cbed != NULL)
609  // {
610  // bind_tex(ricom->srf_cbed, uiTextureIDs[0]);
611  // }
612  // }
613  ImGui::Image((ImTextureID)uiTextureIDs[0], ImVec2(tex_wh, tex_wh), uv_min, uv_max, tint_col, border_col);
614  ImGui::GetWindowDrawList()->AddCircle(ImVec2(centre_x, centre_y), tex_wh * 0.03, IM_COL32(255, 255, 255, 255), 256);
615  ImGui::GetWindowDrawList()->AddLine(ImVec2(com_rel_x - cross_width, com_rel_y), ImVec2(com_rel_x + cross_width, com_rel_y), IM_COL32(255, 0, 0, 255), 1.5f);
616  ImGui::GetWindowDrawList()->AddLine(ImVec2(com_rel_x, com_rel_y - cross_width), ImVec2(com_rel_x, com_rel_y + cross_width), IM_COL32(255, 0, 0, 255), 1.5f);
617  if (ricom->b_vSTEM)
618  {
619  ImGui::GetWindowDrawList()->AddCircle(ImVec2(centre_x, centre_y), tex_wh * (ricom->detector.radius[0] / ricom->n_cam), IM_COL32(255, 50, 0, 255), 256);
620  ImGui::GetWindowDrawList()->AddCircle(ImVec2(centre_x, centre_y), tex_wh * (ricom->detector.radius[1] / ricom->n_cam), IM_COL32(255, 150, 0, 255), 256);
621  }
622  ImGui::End();
623 
624  if (b_acq_open)
625  {
626  ImVec2 pos_t = viewport->Pos;
627  pos_t[0] += control_menu_size[0] + 128;
628  pos_t[1] += menu_bar_size[1] + 128;
629  ImGui::SetNextWindowPos(pos_t, ImGuiCond_FirstUseEver);
630  ImVec2 size = {200, 400};
631  ImGui::SetNextWindowSize(size, ImGuiCond_FirstUseEver);
632 
633  ImGui::Begin("Acquisition Header", &b_acq_open);
634  ImGui::BeginChild("Scrolling");
635  ImGui::TextWrapped(ricom->socket.connection_information.data());
636  ImGui::EndChild();
637  ImGui::End();
638  }
639 
640  // Render all generic Image Windows
641  bool trigger = (b_trigger_update != ricom->b_busy) && (ricom->b_busy == false);
642  bool redraw_tick = (ricom->b_busy && b_redraw && b_started);
643  update_views(generic_windows_f, ricom, b_restarted, trigger, redraw_tick);
644  update_views(generic_windows_c, ricom, b_restarted, trigger, redraw_tick);
645 
646  b_restarted = false;
647  b_trigger_update = ricom->b_busy;
648 
649  // Rendering
650  ImGui::Render();
651  glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
652  glClear(GL_COLOR_BUFFER_BIT);
653  ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
654 
655  if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
656  {
657  SDL_Window *backup_current_window = SDL_GL_GetCurrentWindow();
658  SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
659  ImGui::UpdatePlatformWindows();
660  ImGui::RenderPlatformWindowsDefault();
661  SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
662  }
663 
664  SDL_GL_SwapWindow(window);
665 
666  b_redraw = false;
667  }
668 
669  if (run_thread.joinable())
670  run_thread.join();
671  if (py_thread.joinable())
672  py_thread.join();
673 
674  ImGui_ImplOpenGL3_Shutdown();
675  ImGui_ImplSDL2_Shutdown();
676  ImGui::DestroyContext();
677 
678  SDL_GL_DeleteContext(gl_context);
679  SDL_DestroyWindow(window);
680  SDL_Quit();
681 
682  ini_file.write(ini_cfg, true);
683  return 0;
684 }
void v_splitter(float thickness, float &size0, const float &min_h, const float &max_h, const float &offset)
Definition: GuiUtils.cpp:41
GIM_Flags
@ ColormapSelector
void bind_tex(SDL_Surface *srf, GLuint tex_id)
Definition: RunGUI.cpp:713
#define GENERIC_WINDOW_C(name)
Definition: RunGUI.cpp:56
#define GENERIC_WINDOW(name)
Definition: RunGUI.cpp:55
void update_views(std::map< std::string, ImGuiImageWindow< T >> &generic_windows_f, Ricom *ricom, bool b_restarted, bool trigger, bool b_redraw)
Definition: RunGUI.cpp:687
SDL_Surface * srf_kx
Definition: Ricom.h:69
void compute_kernel()
Definition: Ricom.cpp:21
void draw_surfaces()
Definition: Ricom.cpp:129
std::vector< float > f_approx
Definition: Ricom.h:68
void approximate_frequencies(size_t n_im)
Definition: Ricom.cpp:111
SDL_Surface * srf_ky
Definition: Ricom.h:70
std::vector< float > stem_image
Definition: Ricom.h:248
std::vector< float > comy_image
Definition: Ricom.h:246
std::array< float, 2 > com_public
Definition: Ricom.h:244
bool b_busy
Definition: Ricom.h:226
int cbed_cmap
Definition: Ricom.h:292
bool b_recompute_detector
Definition: Ricom.h:239
int n_threads_max
Definition: Ricom.h:277
float fr_count
Definition: Ricom.h:280
std::vector< float > comx_image
Definition: Ricom.h:245
std::vector< std::complex< float > > e_field_data
Definition: Ricom.h:255
int fr_total
Definition: Ricom.h:268
float fr_freq
Definition: Ricom.h:279
bool b_recompute_kernel
Definition: Ricom.h:240
bool b_continuous
Definition: Ricom.h:228
bool b_cumulative
Definition: Ricom.h:229
bool b_ricom
Definition: Ricom.h:235
std::string connection_information
void check_ini_setting(mINI::INIStructure &ini_cfg, std::string section, std::string key, char *value)
Definition: ImGuiINI.hpp:116
bool ShowFontSelector(const char *label, int &selectedFont, mINI::INIStructure &ini_cfg)
Definition: ImGuiINI.hpp:57
bool ShowStyleSelector(const char *label, int &style_idx, mINI::INIStructure &ini_cfg)
Definition: ImGuiINI.hpp:37
void set_font(int font_idx)
Definition: ImGuiINI.hpp:81
void set_style(int style_idx)
Definition: ImGuiINI.hpp:21