27 #include <wx/button.h>
28 #include <wx/checkbox.h>
29 #include <wx/clrpicker.h>
30 #include <wx/combobox.h>
32 #include <wx/msgdlg.h>
33 #include <wx/radiobut.h>
34 #include <wx/settings.h>
36 #include <wx/spinctrl.h>
37 #include <wx/statbox.h>
38 #include <wx/statline.h>
39 #include <wx/stattext.h>
40 #include <wx/textctrl.h>
42 #include <wx/aui/auibook.h>
43 #include <wx/aui/framemanager.h>
45 #include <wx/aui/dockart.h>
57 parent->
open(newFile,
false);
61 parent->
open(firstFile,
true);
64 virtual void stop()
const override {
68 virtual void pause()
const override {
79 this->Create(window, wxID_ANY, wxDefaultPosition, size);
81 manager = makeAuto<wxAuiManager>(
this);
83 wxPanel* visBar = createVisBar();
84 pane = alignedNew<OrthoPane>(
this, parent, settings);
85 wxPanel* plotBar = createPlotBar();
86 statsBar = createStatsBar();
88 timelineBar = alignedNew<TimeLine>(
this,
Path(), makeShared<TimeLineCallbacks>(parent));
89 progressBar = alignedNew<ProgressPanel>(
this);
96 info.Center().MinSize(wxSize(300, 300)).CaptionVisible(
false).DockFixed(
true).CloseButton(
false);
97 manager->AddPane(&*pane, info);
99 info.Bottom().MinSize(wxSize(-1, 40)).CaptionVisible(
false).DockFixed(
true).CloseButton(
false);
100 manager->AddPane(timelineBar, info.Show(
false));
101 manager->AddPane(progressBar, info.Show(
true));
104 .MinSize(wxSize(300, -1))
105 .CaptionVisible(
true)
108 .Caption(
"Visualization");
109 manager->AddPane(visBar, info);
112 .MinSize(wxSize(300, -1))
113 .CaptionVisible(
true)
116 .Caption(
"Run statistics");
117 manager->AddPane(statsBar, info);
118 info.Caption(
"Particle data");
119 manager->AddPane(plotBar, info);
135 wxWindow* RunPage::createParticleBox(wxPanel* parent) {
136 wxStaticBox* particleBox =
new wxStaticBox(parent, wxID_ANY,
"", wxDefaultPosition, wxSize(-1, 135));
138 wxBoxSizer* boxSizer =
new wxBoxSizer(wxVERTICAL);
140 wxBoxSizer* cutoffSizer =
new wxBoxSizer(wxHORIZONTAL);
142 wxStaticText* text =
new wxStaticText(particleBox, wxID_ANY,
"Cutoff [km]");
143 cutoffSizer->Add(text, 10, wxALIGN_CENTER_VERTICAL);
147 cutoffCtrl->onValueChanged = [
this](
const double value) {
148 this->updateCutoff(value * 1.e3_f);
151 cutoffCtrl->SetToolTip(
152 "Specifies the cutoff distance in kilometers for rendering particles. When set to a positive number, "
153 "only particles in a layer of specified thickness are rendered. Zero means all particles are "
155 cutoffSizer->Add(cutoffCtrl, 1, wxALIGN_CENTER_VERTICAL);
157 boxSizer->Add(cutoffSizer);
159 wxBoxSizer* particleSizeSizer =
new wxBoxSizer(wxHORIZONTAL);
161 text =
new wxStaticText(particleBox, wxID_ANY,
"Particle radius");
162 particleSizeSizer->Add(text, 10, wxALIGN_CENTER_VERTICAL);
165 particleSizeCtrl->SetToolTip(
166 "Multiplier of a particle radius. Must be set to 1 to get the actual size of particles in N-body "
168 particleSizeCtrl->onValueChanged = [
this](
const Float value) {
173 particleSizeSizer->Add(particleSizeCtrl, 1, wxALIGN_CENTER_VERTICAL);
175 boxSizer->Add(particleSizeSizer);
178 wxBoxSizer* grayscaleSizer =
new wxBoxSizer(wxHORIZONTAL);
181 wxBoxSizer* keySizer =
new wxBoxSizer(wxHORIZONTAL);
183 wxCheckBox* keyBox =
new wxCheckBox(particleBox, wxID_ANY,
"Show key");
185 "If checked, the color palette and the length scale are included in the rendered image.");
187 keySizer->Add(keyBox);
188 keySizer->AddSpacer(33);
189 wxCheckBox* ghostBox =
new wxCheckBox(particleBox, wxID_ANY,
"Show ghosts");
191 keySizer->Add(ghostBox);
193 boxSizer->Add(keySizer);
195 wxBoxSizer* aaSizer =
new wxBoxSizer(wxHORIZONTAL);
197 wxCheckBox* aaBox =
new wxCheckBox(particleBox, wxID_ANY,
"Anti-aliasing");
200 "If checked, particles are drawn with anti-aliasing, creating smoother image, but it also takes "
201 "longer to render it.");
205 wxCheckBox* smoothBox =
new wxCheckBox(particleBox, wxID_ANY,
"Smooth particles");
206 smoothBox->SetToolTip(
207 "If checked, particles are drawn semi-transparently. The transparency of a particle follows "
208 "smoothing kernel, imitating actual smoothing of SPH particles.");
209 smoothBox->Enable(
false);
210 aaSizer->Add(smoothBox);
211 boxSizer->Add(aaSizer);
213 particleBox->SetSizer(boxSizer);
215 keyBox->Bind(wxEVT_CHECKBOX, [
this](wxCommandEvent& evt) {
216 const bool value = evt.IsChecked();
220 ghostBox->Bind(wxEVT_CHECKBOX, [
this](wxCommandEvent& evt) {
221 const bool value = evt.IsChecked();
225 aaBox->Bind(wxEVT_CHECKBOX, [
this, smoothBox](wxCommandEvent& evt) {
226 const bool value = evt.IsChecked();
228 smoothBox->Enable(value);
231 smoothBox->Bind(wxEVT_CHECKBOX, [
this](wxCommandEvent& evt) {
232 const bool value = evt.IsChecked();
240 wxWindow* RunPage::createRaymarcherBox(wxPanel* parent) {
241 wxStaticBox* raytraceBox =
new wxStaticBox(parent, wxID_ANY,
"", wxDefaultPosition, wxSize(-1, 150));
242 wxBoxSizer* boxSizer =
new wxBoxSizer(wxVERTICAL);
243 wxBoxSizer* levelSizer =
new wxBoxSizer(wxHORIZONTAL);
245 wxStaticText* text =
new wxStaticText(raytraceBox, wxID_ANY,
"Surface level");
246 levelSizer->Add(text, 10, wxALIGN_CENTER_VERTICAL);
249 levelCtrl->onValueChanged = [
this](
const Float value) {
255 levelSizer->Add(levelCtrl, 1, wxALIGN_CENTER_VERTICAL);
257 boxSizer->Add(levelSizer);
259 wxBoxSizer* sunlightSizer =
new wxBoxSizer(wxHORIZONTAL);
261 text =
new wxStaticText(raytraceBox, wxID_ANY,
"Sunlight");
262 sunlightSizer->Add(text, 10, wxALIGN_CENTER_VERTICAL);
265 sunlightCtrl->onValueChanged = [
this](
const Float value) {
271 sunlightSizer->Add(sunlightCtrl, 1, wxALIGN_CENTER_VERTICAL);
273 boxSizer->Add(sunlightSizer);
275 wxBoxSizer* ambientSizer =
new wxBoxSizer(wxHORIZONTAL);
277 text =
new wxStaticText(raytraceBox, wxID_ANY,
"Ambient");
278 ambientSizer->Add(text, 10, wxALIGN_CENTER_VERTICAL);
281 ambientCtrl->onValueChanged = [
this](
const Float value) {
287 ambientSizer->Add(ambientCtrl, 1, wxALIGN_CENTER_VERTICAL);
289 boxSizer->Add(ambientSizer);
291 wxBoxSizer* emissionSizer =
new wxBoxSizer(wxHORIZONTAL);
293 text =
new wxStaticText(raytraceBox, wxID_ANY,
"Emission");
294 emissionSizer->Add(text, 10, wxALIGN_CENTER_VERTICAL);
297 emissionCtrl->onValueChanged = [
this](
const Float value) {
303 emissionSizer->Add(emissionCtrl, 1, wxALIGN_CENTER_VERTICAL);
305 boxSizer->Add(emissionSizer);
307 raytraceBox->SetSizer(boxSizer);
311 wxWindow* RunPage::createVolumeBox(wxPanel* parent) {
312 wxStaticBox* volumeBox =
new wxStaticBox(parent, wxID_ANY,
"", wxDefaultPosition, wxSize(-1, 120));
313 wxBoxSizer* boxSizer =
new wxBoxSizer(wxVERTICAL);
315 wxBoxSizer* emissionSizer =
new wxBoxSizer(wxHORIZONTAL);
317 wxStaticText* text =
new wxStaticText(volumeBox, wxID_ANY,
"Emission [km^-1]");
318 emissionSizer->Add(text, 10, wxALIGN_CENTER_VERTICAL);
321 emissionCtrl->onValueChanged = [
this](
const Float value) {
328 emissionSizer->Add(emissionCtrl, 1, wxALIGN_CENTER_VERTICAL);
330 boxSizer->Add(emissionSizer);
332 wxBoxSizer* absorptionSizer =
new wxBoxSizer(wxHORIZONTAL);
334 text =
new wxStaticText(volumeBox, wxID_ANY,
"Absorption [km^-1]");
335 absorptionSizer->Add(text, 10, wxALIGN_CENTER_VERTICAL);
338 absorptionCtrl->onValueChanged = [
this](
const Float value) {
345 absorptionSizer->Add(absorptionCtrl, 1, wxALIGN_CENTER_VERTICAL);
347 boxSizer->Add(absorptionSizer);
349 wxBoxSizer* factorSizer =
new wxBoxSizer(wxHORIZONTAL);
351 text =
new wxStaticText(volumeBox, wxID_ANY,
"Compression");
352 factorSizer->Add(text, 10, wxALIGN_CENTER_VERTICAL);
355 factorCtrl->onValueChanged = [
this](
const Float value) {
361 factorSizer->Add(factorCtrl, 1, wxALIGN_CENTER_VERTICAL);
363 boxSizer->Add(factorSizer);
365 volumeBox->SetSizer(boxSizer);
369 static void enableRecursive(wxWindow* window,
const bool enable) {
370 window->Enable(enable);
371 for (wxWindow* child : window->GetChildren()) {
372 enableRecursive(child, enable);
376 wxPanel* RunPage::createVisBar() {
378 wxPanel* visbarPanel =
new wxPanel(
this);
379 visbarPanel->SetLabel(
"Visualization");
381 wxBoxSizer* visbarSizer =
new wxBoxSizer(wxVERTICAL);
383 wxBoxSizer* buttonSizer =
new wxBoxSizer(wxHORIZONTAL);
384 wxButton* resetView =
new wxButton(visbarPanel, wxID_ANY,
"Reset view");
385 resetView->SetToolTip(
"Resets the camera rotation.");
386 resetView->Bind(wxEVT_BUTTON, [
this](wxCommandEvent&
UNUSED(evt)) {
390 controller->
refresh(std::move(camera));
392 buttonSizer->Add(resetView);
394 wxButton*
refresh =
new wxButton(visbarPanel, wxID_ANY,
"Refresh");
395 refresh->SetToolTip(
"Updates the particle order and repaints the current view");
396 refresh->Bind(wxEVT_BUTTON, [
this](wxCommandEvent&
UNUSED(evt)) {
399 AutoPtr<ICamera> camera = controller->getCurrentCamera();
400 controller->refresh(std::move(camera));
401 controller->redrawOnNextTimeStep();
406 wxButton* snap =
new wxButton(visbarPanel, wxID_ANY,
"Save image");
407 snap->SetToolTip(
"Saves the currently rendered image.");
408 buttonSizer->Add(snap);
409 snap->Bind(wxEVT_BUTTON, [
this](wxCommandEvent&
UNUSED(evt)) {
418 visbarSizer->Add(buttonSizer);
419 visbarSizer->AddSpacer(10);
421 wxCheckBox* autoRefresh =
new wxCheckBox(visbarPanel, wxID_ANY,
"Refresh on timestep");
422 autoRefresh->Bind(wxEVT_CHECKBOX, [
this](wxCommandEvent& evt) {
427 autoRefresh->SetToolTip(
428 "When checked, the image is updated on every timestep, otherwise the image is only updated when "
429 "pressing the 'Refresh' button. Note that repainting the image on every timestep may decrease "
430 "the performance of the code.");
431 visbarSizer->Add(autoRefresh);
433 wxCheckBox* autoCamera =
new wxCheckBox(visbarPanel, wxID_ANY,
"Auto-zoom");
434 autoCamera->Bind(wxEVT_CHECKBOX, [
this](wxCommandEvent& evt) {
439 autoCamera->SetToolTip(
440 "When checked, parameters of the camera (position, field of view, etc.) are automatically adjusted "
441 "during the simulation.");
442 visbarSizer->Add(autoCamera);
443 visbarSizer->AddSpacer(10);
471 wxBoxSizer* quantitySizer =
new wxBoxSizer(wxHORIZONTAL);
473 quantitySizer->Add(
new wxStaticText(visbarPanel, wxID_ANY,
"Quantity: "), 10, wxALIGN_CENTER_VERTICAL);
474 quantityBox =
new ComboBox(visbarPanel,
"", wxSize(200, -1));
475 quantityBox->SetToolTip(
476 "Selects which quantity to visualize using associated color scale. Quantity values can be also "
477 "obtained by left-clicking on a particle.");
478 quantityBox->SetWindowStyle(wxCB_SIMPLE | wxCB_READONLY);
479 quantityBox->SetSelection(0);
480 quantityBox->Bind(wxEVT_COMBOBOX, [
this](wxCommandEvent&
UNUSED(evt)) {
482 const int idx = quantityBox->GetSelection();
483 this->setColorizer(idx);
486 quantitySizer->Add(quantityBox, 1, wxALIGN_CENTER_VERTICAL, 5);
488 visbarSizer->Add(quantitySizer);
489 visbarSizer->AddSpacer(10);
491 wxRadioButton* particleButton =
492 new wxRadioButton(visbarPanel, wxID_ANY,
"Particles", wxDefaultPosition,
buttonSize, wxRB_GROUP);
493 particleButton->SetToolTip(
"Render individual particles with optional smoothing.");
494 visbarSizer->Add(particleButton);
495 wxWindow* particleBox = this->createParticleBox(visbarPanel);
496 visbarSizer->Add(particleBox, 0, wxALL, 5);
497 visbarSizer->AddSpacer(10);
500 wxRadioButton* surfaceButton =
501 new wxRadioButton(visbarPanel, wxID_ANY,
"Raymarched surface", wxDefaultPosition,
buttonSize, 0);
502 visbarSizer->Add(surfaceButton);
503 wxWindow* raytracerBox = this->createRaymarcherBox(visbarPanel);
504 visbarSizer->Add(raytracerBox, 0, wxALL, 5);
505 visbarSizer->AddSpacer(10);
507 wxRadioButton* volumeButton =
508 new wxRadioButton(visbarPanel, wxID_ANY,
"Volumetric raytracer", wxDefaultPosition,
buttonSize, 0);
509 visbarSizer->Add(volumeButton);
510 wxWindow* volumeBox = this->createVolumeBox(visbarPanel);
511 visbarSizer->Add(volumeBox, 0, wxALL, 5);
512 visbarSizer->AddSpacer(10);
527 auto enableControls = [=](
int renderIdx) {
528 enableRecursive(particleBox, renderIdx == 0);
529 enableRecursive(raytracerBox, renderIdx == 1);
530 enableRecursive(volumeBox, renderIdx == 2);
534 particleButton->Bind(wxEVT_RADIOBUTTON, [=](wxCommandEvent&
UNUSED(evt)) {
536 controller->
setRenderer(makeAuto<ParticleRenderer>(gui));
551 surfaceButton->Bind(wxEVT_RADIOBUTTON, [=](wxCommandEvent&
UNUSED(evt)) {
555 controller->
setRenderer(makeAuto<RayMarcher>(scheduler, gui));
557 }
catch (
const std::exception& e) {
558 wxMessageBox(std::string(
"Cannot initialize raytracer.\n\n") + e.what(),
"Error", wxOK);
561 particleButton->SetValue(
true);
562 controller->
setRenderer(makeAuto<ParticleRenderer>(gui));
566 volumeButton->Bind(wxEVT_RADIOBUTTON, [=](wxCommandEvent&
UNUSED(evt)) {
571 controller->
setRenderer(makeAuto<VolumeRenderer>(scheduler, volumeGui));
575 visbarSizer->AddSpacer(16);
576 quantityPanel =
new wxPanel(visbarPanel, wxID_ANY);
577 visbarSizer->Add(quantityPanel);
578 quantityPanelSizer = visbarSizer;
580 visbarPanel->SetSizer(visbarSizer);
584 void RunPage::updateCutoff(
const double cutoff) {
596 wxPanel* RunPage::createPlotBar() {
597 wxPanel* sidebarPanel =
new wxPanel(
this);
598 wxBoxSizer* sidebarSizer =
new wxBoxSizer(wxVERTICAL);
600 sidebarSizer->Add(probe.
get(), 1, wxALIGN_TOP | wxEXPAND);
601 sidebarSizer->AddSpacer(5);
604 for (
const auto& plotData : *list) {
605 plots.
push(plotData.plot);
611 firstPlot =
new PlotView(sidebarPanel, wxSize(300, 200), wxSize(10, 10), list, 0, tics);
612 sidebarSizer->Add(firstPlot, 1, wxALIGN_TOP | wxEXPAND);
613 sidebarSizer->AddSpacer(5);
615 secondPlot =
new PlotView(sidebarPanel, wxSize(300, 200), wxSize(10, 10), list, 1, tics);
616 sidebarSizer->Add(secondPlot, 1, wxALIGN_TOP | wxEXPAND);
618 sidebarPanel->SetSizerAndFit(sidebarSizer);
622 wxPanel* RunPage::createStatsBar() {
623 wxPanel* statsPanel =
new wxPanel(
this);
624 wxBoxSizer* statsSizer =
new wxBoxSizer(wxVERTICAL);
626 wxFont font = wxSystemSettings::GetFont(wxSYS_SYSTEM_FONT);
628 statsPanel->SetFont(font);
630 statsText =
new wxTextCtrl(
631 statsPanel, wxID_ANY,
"", wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxTE_MULTILINE);
634 statsSizer->Add(statsText, 1, wxEXPAND | wxALL, 5);
635 statsPanel->SetSizer(statsSizer);
640 template <
typename TValue>
643 const std::string& desc,
645 const std::string units =
"") {
647 *text << desc << stats.
get<TValue>(id) << units <<
"\n";
651 void RunPage::makeStatsText(
const Size particleCnt,
const Statistics& stats) {
653 *statsText <<
" - particles: ";
654 if (particleCnt > 0) {
655 *statsText << int(particleCnt) <<
"\n";
657 *statsText <<
"N/A\n";
665 std::stringstream ss;
671 *statsText <<
" * set by: " << ss.str() <<
"\n";
717 void RunPage::setColorizer(
const Size idx) {
721 if (idx == selectedIdx) {
724 this->replaceQuantityBar(idx);
732 wxBoxSizer* seedSizer =
new wxBoxSizer(wxHORIZONTAL);
733 seedSizer->Add(
new wxStaticText(parent, wxID_ANY,
"Seed"), 0, wxALIGN_CENTER_VERTICAL);
734 wxSpinCtrl* seedSpinner =
new wxSpinCtrl(parent, wxID_ANY,
"", wxDefaultPosition,
spinnerSize);
735 seedSizer->Add(seedSpinner, 0, wxALIGN_CENTER_VERTICAL);
736 sizer->Add(seedSizer);
737 sizer->AddSpacer(15);
739 wxRadioButton* overlapButton =
new wxRadioButton(
740 parent, wxID_ANY,
"Connected particles", wxDefaultPosition, wxSize(-1, 25), wxRB_GROUP);
741 sizer->Add(overlapButton);
743 wxRadioButton* boundButton =
744 new wxRadioButton(parent, wxID_ANY,
"Bound particles", wxDefaultPosition, wxSize(-1, 25), 0);
745 sizer->Add(boundButton);
747 sizer->AddSpacer(15);
748 wxCheckBox* highlightBox =
new wxCheckBox(parent, wxID_ANY,
"Highlight component");
749 highlightBox->SetValue(
bool(componentId->getHighlightIdx()));
750 sizer->Add(highlightBox);
752 wxBoxSizer* highlightSizer =
new wxBoxSizer(wxHORIZONTAL);
753 highlightSizer->AddSpacer(30);
754 wxStaticText* text =
new wxStaticText(parent, wxID_ANY,
"Index");
755 highlightSizer->Add(text, 0, wxALIGN_CENTER_VERTICAL);
756 wxSpinCtrl* highlightIndex =
new wxSpinCtrl(parent, wxID_ANY,
"", wxDefaultPosition,
spinnerSize);
757 highlightIndex->SetValue(componentId->getHighlightIdx().valueOr(0));
758 highlightIndex->Enable(highlightBox->GetValue());
759 highlightSizer->Add(highlightIndex);
760 sizer->Add(highlightSizer);
762 overlapButton->Bind(wxEVT_RADIOBUTTON, [
this, componentId, colorizer](wxCommandEvent&
UNUSED(evt)) {
766 boundButton->Bind(wxEVT_RADIOBUTTON, [
this, componentId, colorizer](wxCommandEvent&
UNUSED(evt)) {
767 componentId->setConnectivity(
771 seedSpinner->Bind(wxEVT_SPINCTRL, [
this, componentId, colorizer](wxSpinEvent& evt) {
772 const int seed = evt.GetValue();
773 componentId->setSeed(seed);
777 highlightBox->Bind(wxEVT_CHECKBOX, [
this, colorizer, componentId, highlightIndex](wxCommandEvent& evt) {
778 const bool value = evt.IsChecked();
782 componentId->setHighlightIdx(highlightIndex->GetValue());
784 componentId->setHighlightIdx(
NOTHING);
786 highlightIndex->Enable(value);
791 highlightIndex->Bind(wxEVT_SPINCTRL, [
this, componentId, colorizer](wxSpinEvent& evt) {
794 const int index = evt.GetValue();
795 componentId->setHighlightIdx(index);
802 void RunPage::replaceQuantityBar(
const Size idx) {
803 quantityPanel->Destroy();
805 quantityPanel =
new wxPanel(
this, wxID_ANY);
809 if (dynamicCast<ComponentIdColorizer>(newColorizer.
get())) {
810 wxBoxSizer* sizer =
new wxBoxSizer(wxVERTICAL);
811 sizer->Add(
new wxStaticText(quantityPanel, wxID_ANY, newColorizer->
name()));
812 wxBoxSizer* offsetSizer =
new wxBoxSizer(wxHORIZONTAL);
813 offsetSizer->AddSpacer(25);
814 sizer->Add(offsetSizer);
815 wxBoxSizer* actSizer =
new wxBoxSizer(wxVERTICAL);
816 addComponentIdBar(quantityPanel, actSizer, newColorizer);
817 offsetSizer->Add(actSizer);
818 quantityPanel->SetSizerAndFit(sizer);
821 quantityPanelSizer->Add(quantityPanel);
828 progressBar->
update(stats);
837 progressBar->
onRunStart(className, instanceName);
845 wxAuiPaneInfo& timelineInfo = manager->GetPane(timelineBar);
846 wxAuiPaneInfo& progressInfo = manager->GetPane(progressBar);
847 wxAuiPaneInfo& statsInfo = manager->GetPane(statsBar);
849 if (!timelineInfo.IsShown()) {
850 timelineInfo.Show(show);
851 progressInfo.Show(!show);
852 statsInfo.Show(!show);
864 this->makeStatsText(particleCnt, dummyStats);
868 timelineBar->
update(path);
871 for (
auto plot : plots) {
882 executeOnMainThread([
this, stats, particleCnt] { this->makeStatsText(particleCnt, stats); });
888 if (selectedParticlePlot) {
895 selectedParticlePlot->setColorizer(colorizer);
900 for (
auto plot : plots) {
901 plot->onTimeStep(storage, stats);
906 firstPlot->Refresh();
907 secondPlot->Refresh();
915 waitingDialog->EndModal(0);
921 colorizerList = std::move(colorizers);
923 for (
auto& e : colorizerList) {
924 items.Add(e->name().c_str());
926 quantityBox->Set(items);
927 const Size actSelectedIdx = (selectedIdx < colorizerList.size()) ? selectedIdx : 0;
928 quantityBox->SetSelection(actSelectedIdx);
933 probe->
update(particle, color);
942 const wxSize size = pane->GetSize();
943 return wxSize(
max(size.x, 1),
max(size.y, 1));
949 : wxDialog(parent, wxID_ANY,
"Info", wxDefaultPosition, wxDefaultSize, wxCAPTION | wxSYSTEM_MENU) {
950 const wxSize size = wxSize(320, 90);
952 wxStaticText* text =
new wxStaticText(
this, wxID_ANY,
"Waiting for simulation to finish ...");
953 wxBoxSizer* sizer =
new wxBoxSizer(wxVERTICAL);
954 sizer->AddStretchSpacer();
955 sizer->Add(text, 1, wxALIGN_CENTER_HORIZONTAL);
956 sizer->AddStretchSpacer();
957 this->SetSizer(sizer);
959 this->CentreOnScreen();
967 wxMessageBox(
"Simulation is currently in progress. Do you want to stop it and close the window?",
969 wxYES_NO | wxCENTRE);
970 if (retval == wxYES) {
973 waitingDialog->ShowModal();
974 controller->
quit(
true);
#define SPH_ASSERT(x,...)
void saveToFile(const wxBitmap &wx, const Path &path)
Defines projection transforming 3D particles onto 2D screen.
Helper functions to check the internal consistency of the code.
@ NO_THROW
Function cannot throw exceptions.
@ MAIN_THREAD
Function can only be executed from main thread.
#define CHECK_FUNCTION(flags)
Object converting quantity values of particles into colors.
Looking for problems in SPH simulation and reporting potential errors.
uint32_t Size
Integral type used to index arrays (by default).
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
void printStat(ILogger &logger, const Statistics &stats, const StatisticsId id, const std::string &message, const std::string &unit="", const std::string &emptyValue="")
Logging routines of the run.
NAMESPACE_SPH_BEGIN void executeOnMainThread(const Function< void()> &function)
Posts a callback to be executed on main thread.
Posting events to be executed on main thread.
constexpr INLINE T max(const T &f1, const T &f2)
#define NAMESPACE_SPH_END
const NothingType NOTHING
Frame showing information about selected particle.
Renderer drawing individual particles as dots.
Array< PlotData > getPlotList(const GuiSettings &gui)
Simple thread pool with fixed number of threads.
QuantityId
Unique IDs of basic quantities of SPH particles.
@ MASS
Paricles masses, always a scalar quantity.
const wxSize buttonSize(250, -1)
const wxSize spinnerSize(100, -1)
StatisticsId
List of values that are computed and displayed every timestep.
@ COLLISION_EVAL_TIME
Wallclock duration of collision evaluation.
@ SPH_EVAL_TIME
Wallclock duration of evaluation of SPH derivatives.
@ BREAKUP_COUNT
Number of fragmentation collisions.
@ LIMITING_QUANTITY
Quantity that currently limits the timestep.
@ POSTPROCESS_EVAL_TIME
Wallclock spent on data dump, particle visualization, etc.
@ RUN_TIME
Current time of the simulation in code units. Does not necessarily have to be 0 when run starts.
@ TIMESTEP_VALUE
Current value of timestep.
@ AGGREGATE_COUNT
Number of aggregates in the simulation (single particles are not counted as aggregates).
@ TIMESTEP_CRITERION
Criterion that currently limits the timestep.
@ TOTAL_COLLISION_COUNT
Number of collisions in the timestep.
@ INDEX
Current number of time step, indexed from 0.
@ OVERLAP_COUNT
Number of particle overlaps detected during collision evaluation.
@ TIMESTEP_ELAPSED
Wallclock time spend on computing last timestep.
@ GRAVITY_BUILD_TIME
Wallclock duration of gravity tree building.
@ MERGER_COUNT
Number of mergers in the timestep.
@ GRAVITY_EVAL_TIME
Wallclock duration of gravity evaluation.
@ BOUNCE_COUNT
Number of bounce collisions.
Criteria for computing the time step.
@ DERIVATIVE
Timestep based on value-to-derivative ratio.
Optional< Path > doSaveFileDialog(const std::string &title, Array< FileFormat > &&formats)
Random utility functions for drawing stuff to DC.
static AffineMatrix identity()
Generic dynamically allocated resizable storage.
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
Main GUI class connection the simulation with UI controls.
bool isRunning() const
Returns true if a simulation is running.
void setRenderer(AutoPtr< IRenderer > &&newRenderer)
Sets a new renderer used to draw particles.
AutoPtr< ICamera > getCurrentCamera() const
Returns the camera currently used for the rendering.
void quit(const bool waitForFinish=false)
Closes down the model, clears all allocated resources. Must be called only once.
const wxBitmap & getRenderedBitmap() const
Renders a bitmap of current view.
SharedPtr< IColorizer > getCurrentColorizer() const
Returns the colorizer currently used for rendering into the window.
void open(const Path &path, const bool sequence=false)
Opens a simulation snapshot from given file.
void stop(const bool waitForFinish=false)
Stops the current simulation.
void pause()
Pause the current simulation.
void refresh(AutoPtr< ICamera > &&camera)
Re-renders the particles with given camera.
Optional< Size > getSelectedParticle() const
bool tryRedraw()
If possible, redraws the particles with data from storage.
GuiSettings & getParams()
Returns the settings object.
void setColorizer(const SharedPtr< IColorizer > &newColorizer)
Sets a new colorizer to be displayed.
INLINE TValue get(const GuiSettingsId id) const
INLINE GuiSettings & set(const GuiSettingsId id, const TValue &value)
Interface defining a camera or view, used by a renderer.
virtual AutoPtr< ICamera > clone() const =0
virtual void setCutoff(const Optional< float > newCutoff)=0
Modifies the clipping distance of the camera.
virtual void transform(const AffineMatrix &matrix)=0
Transforms the current view by given matrix.
virtual std::string name() const =0
Returns the name of the colorizer.
virtual void initialize(const Storage &storage, const RefEnum ref)=0
Initialize the colorizer before by getting necessary quantities from storage.
virtual ICamera & getCamera()=0
virtual void onTimeStep(const Storage &storage, const Statistics &stats)=0
virtual void resetView()=0
Object representing a 1D interval of real numbers.
Wrapper of type value of which may or may not be present.
INLINE Type & value()
Returns the reference to the stored value.
void update(const Particle &selectedParticle, const Rgba colorizerColor)
Object holding information about single particle.
Object representing a path on a filesystem.
bool empty() const
Checks if the path is empty.
void update(const Statistics &stats)
void onRunStart(const std::string &className, const std::string &instanceName)
Non-owning wrapper of pointer.
wxSize getCanvasSize() const
void setColorizerList(Array< SharedPtr< IColorizer >> &&colorizers)
void setProgress(const Statistics &stats)
void newPhase(const std::string &className, const std::string &instanceName)
void runStarted(const Storage &storage, const Path &path)
RunPage(wxWindow *window, Controller *controller, GuiSettings &guiSettings)
void showTimeLine(const bool show)
void onTimeStep(const Storage &storage, const Statistics &stats)
void setSelectedParticle(const Particle &particle, const Rgba color)
static const Settings & getDefaults()
\brief Returns a reference to object containing default values of all settings.
INLINE RawPtr< T > get() const
Object holding various statistics about current run.
TValue get(const StatisticsId idx) const
Returns value of a statistic.
bool has(const StatisticsId idx) const
Checks if the object contains a statistic with given ID.
Container storing all quantities used within the simulations.
Size getParticleCnt() const
Returns the number of particles.
bool has(const QuantityId key) const
Checks if the storage contains quantity with given key.
virtual void startSequence(const Path &firstFile) const override
TimeLineCallbacks(Controller *parent)
virtual void pause() const override
virtual void frameChanged(const Path &newFile) const override
virtual void stop() const override
void setFrame(const Size newFrame)
void update(const Path &inputFile)
int64_t elapsed(const TimerUnit unit) const
Returns elapsed time in timer units. Does not reset the timer.
void restart()
Reset elapsed duration to zero.
WaitDialog(wxWindow *parent)
@ COLORMAP_LOGARITHMIC_FACTOR
@ PARTICLE_RADIUS
Displayed radius of particle in units of smoothing length.
@ CAMERA_ORTHO_CUTOFF
Max z-coordinate of particle to be displayed by ortho renderer.
@ SURFACE_LEVEL
Value of iso-surface being constructed; lower value means larget bodies.
@ SURFACE_SUN_INTENSITY
Intentity of the sun.
@ SURFACE_AMBIENT
Ambient color for surface renderer.
SharedPtr< IScheduler > getScheduler(const RunSettings &settings=RunSettings::getDefaults())
@ OVERLAP
Specifies that overlapping particles belong into the same component.