20 #include <wx/checkbox.h>
21 #include <wx/dcmemory.h>
22 #include <wx/msgdlg.h>
27 : project(
Project::getInstance()) {
30 vis.initialize(project);
34 page = alignedNew<RunPage>(parent,
this, gui);
36 this->startRenderThread();
47 Controller::Vis::Vis() {
48 bitmap = makeAuto<wxBitmap>();
50 refreshPending =
false;
51 redrawOnNextTimeStep =
false;
54 void Controller::Vis::initialize(
const Project& project) {
65 bool Controller::Vis::isInitialized() {
66 return renderer && stats && colorizer && camera;
69 void Controller::Vis::refresh() {
71 renderThreadVar.notify_one();
84 sph.shouldContinue =
true;
88 sph.run = std::move(
run);
89 this->startRunThread();
114 continueVar.notify_one();
118 if (sph.thread.joinable()) {
122 this->startRunThread();
135 sph.shouldContinue =
false;
138 continueVar.notify_one();
140 if (waitForFinish && sph.thread.joinable()) {
155 wxMessageBox(
"Unknown type of file '" +
path.
native() +
"'",
"Fail", wxOK | wxCENTRE);
171 wxMessageBox(
"Cannot save the file.\n\n" + result.
error(),
"Fail", wxOK | wxCENTRE);
177 sph.onTimeStepCallbacks->push(dump);
178 }
else if (sph.storage) {
181 dump(*sph.storage, *vis.stats);
190 sph.shouldContinue =
false;
193 continueVar.notify_one();
197 if (sph.thread.joinable()) {
201 vis.renderer->cancelRender();
203 std::unique_lock<std::mutex> renderLock(vis.renderThreadMutex);
204 vis.renderThreadVar.notify_one();
207 if (vis.renderThread.joinable()) {
208 vis.renderThread.join();
220 wxWindow* window = wxWindow::FindWindowByLabel(
"Auto-zoom", page.
get());
222 wxCheckBox* checkbox =
dynamic_cast<wxCheckBox*
>(window);
223 checkbox->SetValue(enable);
228 this->
update(storage, stats);
231 void Controller::onStart(
const IJob& job) {
232 const std::string className = job.
className();
234 this->safePageCall([className, instanceName](
RunPage* page) { page->
newPhase(className, instanceName); });
242 if (sph.shouldContinue) {
246 this->
update(storage, stats);
253 this->safePageCall([endStats](
RunPage* page) {
270 this->safePageCall([stats](
RunPage* page) {
283 if (!sph.onTimeStepCallbacks->empty()) {
285 auto onTimeStepProxy = sph.onTimeStepCallbacks.lock();
286 for (
auto& func : onTimeStepProxy.get()) {
289 onTimeStepProxy->clear();
295 if (doRedraw && vis.timer->isExpired()) {
297 vis.timer->restart();
298 vis.redrawOnNextTimeStep =
false;
309 std::unique_lock<std::mutex> lock(continueMutex);
310 continueVar.wait(lock);
323 std::unique_lock<std::mutex> lock(updateMutex);
325 std::unique_lock<std::mutex> lock(updateMutex);
330 if (!vis.colorizer->hasData(
storage)) {
334 updateVar.notify_one();
336 updateVar.wait(lock);
344 bool Controller::shouldAbortRun()
const {
345 return !sph.shouldContinue;
404 return colorizerIds.
clone();
417 if (
id == defaultId) {
418 colorizers.
insert(0, colorizer);
420 colorizers.
push(colorizer);
428 vis.refreshPending =
false;
434 return vis.colorizer;
438 std::unique_lock<std::mutex> cameraLock(vis.cameraMutex);
439 return vis.camera->clone();
445 if (!vis.colorizer->isInitialized()) {
450 std::unique_lock<std::mutex> cameraLock(vis.cameraMutex);
466 float t = -std::numeric_limits<float>::lowest();
468 bool wasHitOutside =
true;
471 for (
Size i = 0; i < vis.positions.size(); ++i) {
477 if (cutoff != 0._f &&
abs(
dot(camDir, vis.positions[i])) > cutoff) {
484 const Vector r = vis.positions[i] - ray->origin;
485 const float t = float(
dot(r, rayDir));
486 const Vector projected = r - t * rayDir;
488 const float radiusSqr = float(
sqr(vis.positions[i][
H] *
radius));
489 const float distanceSqr = float(
getSqrLength(projected));
490 if (distanceSqr < radiusSqr *
sqr(1._f + toleranceEps)) {
491 const bool wasHitOutside = distanceSqr > radiusSqr;
493 if (t < first.t || (first.wasHitOutside && !wasHitOutside)) {
497 first.wasHitOutside = wasHitOutside;
501 if (
int(first.idx) == -1) {
511 vis.colorizer = newColorizer;
523 auto func = [
this, renderer = std::move(newRenderer)](
526 std::unique_lock<std::mutex> renderLock(vis.renderThreadMutex);
527 vis.renderer = std::move(renderer);
529 vis.renderer->initialize(
storage, *vis.colorizer, *vis.camera);
533 vis.renderer->cancelRender();
536 func(*sph.storage, *vis.stats);
539 sph.onTimeStepCallbacks->push(std::move(func));
545 vis.selectedParticle = particleIdx;
548 if (particleIdx && vis.colorizer->isInitialized()) {
549 const Rgba color = vis.colorizer->evalColor(particleIdx.
value());
565 project.
setPalette(vis.colorizer->name(), palette);
566 vis.colorizer->setPalette(palette);
571 return vis.selectedParticle;
582 vis.renderer->cancelRender();
583 std::unique_lock<std::mutex> renderLock(vis.renderThreadMutex);
585 vis.stats = makeAuto<Statistics>(stats);
596 vis.cameraMutex.lock();
598 vis.camera->autoSetup(
storage);
602 vis.cameraMutex.unlock();
605 vis.renderer->initialize(
storage, *colorizer, *camera);
614 vis.renderer->cancelRender();
615 std::unique_lock<std::mutex> renderLock(vis.renderThreadMutex);
618 vis.cameraMutex.lock();
621 vis.cameraMutex.unlock();
622 vis.renderer->initialize(*sph.storage, *vis.colorizer, *camera);
623 vis.timer->restart();
628 vis.renderer->cancelRender();
635 vis.redrawOnNextTimeStep =
true;
640 vis.renderer->cancelRender();
641 std::unique_lock<std::mutex> lock(vis.cameraMutex);
642 vis.camera = std::move(camera);
648 const Pixel imageSize = vis.camera->getSize();
649 const Float fov = imageSize.
y / wtp.value();
656 wxWeakRef<RunPage> weakPage = page.get();
663 void Controller::startRunThread() {
664 sph.thread = std::thread([
this] {
665 sph.shouldContinue =
true;
669 sph.run->run(sph.globals, *
this);
671 }
catch (
const std::exception& e) {
674 std::string(
"Error encountered during the run: \n") + desc,
"Fail", wxOK | wxCENTRE);
685 void Controller::startRenderThread() {
690 wxWeakRef<RunPage> page;
693 RenderOutput(Vis& vis, wxWeakRef<RunPage> page)
698 this->
update(bitmap, std::move(labels), isFinal);
703 const bool UNUSED(isFinal))
override {
705 if (vis.refreshPending) {
714 auto callback = [&vis = vis,
716 bitmap = std::move(newBitmap),
717 labels = std::move(labels)]()
mutable {
722 vis.refreshPending =
true;
723 vis.bitmap = std::move(bitmap);
725 if (!labels.empty()) {
726 wxMemoryDC dc(*vis.bitmap);
728 dc.SelectObject(wxNullBitmap);
738 vis.renderThread = std::thread([
this] {
739 RenderOutput output(vis, page.get());
743 std::unique_lock<std::mutex> renderLock(vis.renderThreadMutex);
744 vis.renderThreadVar.wait(renderLock, [
this] {
747 vis.needsRefresh =
false;
754 const wxSize canvasSize = page->getCanvasSize();
761 vis.cameraMutex.lock();
763 vis.cameraMutex.unlock();
765 const Pixel size =
Pixel(canvasSize.x, canvasSize.y);
768 vis.renderer->render(params, *vis.stats, output);
INLINE CopyableArray< T, TAllocator, TCounter > copyable(const Array< T, TAllocator, TCounter > &array)
#define SPH_ASSERT(x,...)
NAMESPACE_SPH_BEGIN void toWxBitmap(const Bitmap< Rgba > &bitmap, wxBitmap &wx)
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.
ColorizerId
Special colorizers that do not directly correspond to quantities.
@ TOTAL_STRESS
Total stress (sigma = S - pI)
@ FLAG
Particles of different bodies are colored differently.
@ COROTATING_VELOCITY
Velocities with a respect to the rotating body.
@ RADIUS
Radii/smoothing lenghts of particles.
@ SUMMED_DENSITY
Density computed from particle masses by direct summation of neighbours.
@ DENSITY_PERTURBATION
Relative difference of density and initial density (rho/rho0 - 1)
@ COMPONENT_ID
Color assigned to each component (group of connected particles)
@ VELOCITY
Particle velocities.
@ YIELD_REDUCTION
Reduction of stress tensor due to yielding (1 - f_vonMises)
@ PARTICLE_ID
Each particle drawn with different color.
@ TOTAL_ENERGY
Sum of kinetic and internal energy for given particle.
@ DAMAGE_ACTIVATION
Ratio of the stress and the activation strain.
@ BOUNDARY
Shows boundary particles.
@ AGGREGATE_ID
Color assigned to each aggregate.
@ TEMPERATURE
Temperature, computed from internal energy.
@ ACCELERATION
Acceleration of particles.
@ BEAUTY
Attempts to show the real-world look.
@ MATERIAL_ID
Particles with different materials are colored differently.
@ UVW
Shows UV mapping, u-coordinate in red and v-coordinate in blur.
Array< ExtColorizerId > getColorizerIds()
Returns IDs of all colorizers available in the application.
RunStatus
Status of the code.
@ STOPPED
Run has been stopped by the user.
@ RUNNING
Simulation in progress.
@ QUITTING
quit has been called, waiting for threads to finish
@ PAUSED
Run is paused, can be continued or stopped.
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.
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 sqr(const T &f) noexcept
Return a squared value.
INLINE auto abs(const T &f)
Renderer visualizing the surface as triangle mesh.
Periodically saves rendered images to disk.
#define NAMESPACE_SPH_END
const NothingType NOTHING
@ VELOCITY
Current velocities of particles, always a vector quantity.
@ DAMAGE
Damage, reducing the pressure and deviatoric stress.
@ POSITION
Positions of particles, always a vector quantity.
@ ENERGY
Specific internal energy, always a scalar quantity.
@ SMOOTHING_LENGTH
Smoothing lenghts of particles.
@ DENSITY
Density, always a scalar quantity.
@ MASS
Particle masses, always a scalar quantity.
Renderer drawing individual particles as dots.
Simple thread pool with fixed number of threads.
Tool to measure time spent in functions and profile the code.
#define MEASURE_SCOPE(name)
@ BULK_DENSITY
Bulk density, may be lower than the material density.
@ AV_ALPHA
Coefficient alpha of the artificial viscosity. Coefficient beta is always 2*alpha.
@ VELOCITY_DIVERGENCE
Velocity divergence.
@ STRAIN_RATE_CORRECTION_TENSOR
Correction tensor used to improve conservation of total angular momentum.
@ DEVIATORIC_STRESS
Deviatoric stress tensor, always a traceless tensor.
@ PRESSURE
Pressure, affected by yielding and fragmentation model, always a scalar quantity.
@ AV_BALSARA
Balsara factor.
@ MOMENT_OF_INERTIA
Moment of inertia of particles, analogy of particle masses for rotation.
@ VELOCITY_GRADIENT
Velocity gradient.
@ POSITION
Positions (velocities, accelerations) of particles, always a vector quantity,.
@ ENERGY
Specific internal energy, always a scalar quantity.
@ VELOCITY_ROTATION
Velocity rotation.
@ DENSITY
Density, always a scalar quantity.
@ MASS
Paricles masses, always a scalar quantity.
@ NEIGHBOUR_CNT
Number of neighbouring particles (in radius h * kernel.radius)
@ SOUND_SPEED
Sound speed, always a scalar quantity.
@ AV_STRESS
Artificial stress by Monaghan .
@ VIBRATIONAL_VELOCITY
Vibrational particle velocity, used by the block model of acoustic fluidization.
@ VELOCITY_GRADIENT_OF_DIVERGENCE
Statistics gathered and periodically displayed during the run.
@ POSTPROCESS_EVAL_TIME
Wallclock spent on data dump, particle visualization, etc.
Measuring time intervals and executing periodic events.
@ START_EXPIRED
Creates expired timer, calling elapsed immediately after creating will return the timer interval.
void printLabels(wxDC &dc, ArrayView< const IRenderOutput::Label > labels)
Random utility functions for drawing stuff to DC.
INLINE Float getSqrLength(const Vector &v)
INLINE float dot(const BasicVector< float > &v1, const BasicVector< float > &v2)
Make sure the vector is trivially constructible and destructible, needed for fast initialization of a...
INLINE Vector getNormalized(const Vector &v)
INLINE Vector row(const Size idx) const
Generic dynamically allocated resizable storage.
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
void insert(const TCounter position, U &&value)
Inserts a new element to given position in the array.
INLINE T & front() noexcept
Array clone() const
Performs a deep copy of all elements of the array.
bool isRunning() const
Returns true if a simulation is running.
Controller(wxWindow *parent)
Initialize the controller.
void setRenderer(AutoPtr< IRenderer > &&newRenderer)
Sets a new renderer used to draw particles.
void setAutoZoom(const bool enable)
Enables or disables auto-zoom during the simulation.
RawPtr< RunPage > getPage() const
AutoPtr< ICamera > getCurrentCamera() const
Returns the camera currently used for the rendering.
SharedPtr< INode > run
Root node of the simulation.
void quit(const bool waitForFinish=false)
Closes down the model, clears all allocated resources. Must be called only once.
Array< SharedPtr< IColorizer > > getColorizerList(const Storage &storage) const
void saveState(const Path &path)
Saves the state of the current run to the disk.
const wxBitmap & getRenderedBitmap() const
Renders a bitmap of current view.
void restart()
Starts the simulation with current setup.
SharedPtr< IColorizer > getCurrentColorizer() const
Returns the colorizer currently used for rendering into the window.
RunStatus getStatus() const
Returns the current status of the run.
Path path
Path to the loaded file, if used.
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 redrawOnNextTimeStep()
Redraws the image on the following timestep.
void setPaletteOverride(const Palette palette)
Modifies the color palette for current colorizer.
Optional< Size > getIntersectedParticle(const Pixel position, const float toleranceEps)
Returns the particle under given image position, or NOTHING if such particle exists.
void setSelectedParticle(const Optional< Size > &particleIdx)
Sets a selected particle or changes the current selection.
void pause()
Pause the current simulation.
void start(SharedPtr< INode > run, const RunSettings &globals)
Sets up and starts a new simulation.
void refresh(AutoPtr< ICamera > &&camera)
Re-renders the particles with given camera.
Optional< Size > getSelectedParticle() const
void update(const Storage &storage, const Statistics &stats)
Updates the colorizer list, reset the camera and the renderer, etc.
bool tryRedraw()
If possible, redraws the particles with data from storage.
RawPtr< const Storage > storage
GuiSettings & getParams()
Returns the settings object.
void setColorizer(const SharedPtr< IColorizer > &newColorizer)
Sets a new colorizer to be displayed.
const Storage & getStorage() const
Wrapper of type that either contains a value of given type, or an error message.
const Error & error() const
Returns the error message.
Helper type allowing to "derive" from enum class.
INLINE TValue get(const GuiSettingsId id) const
INLINE GuiSettings & set(const GuiSettingsId id, const TValue &value)
virtual Optional< float > getCutoff() const =0
Returns the clipping distance from plane passing through origin, perpendicular to camera direction.
virtual AffineMatrix getFrame() const =0
Returns the transformation matrix converting camera space to world space.
virtual Optional< ProjectedPoint > project(const Vector &r) const =0
Returns projected position of particle on the image.
virtual AutoPtr< ICamera > clone() const =0
virtual void resize(const Pixel newSize)=0
Changes the image size.
virtual Optional< CameraRay > unproject(const Coords &coords) const =0
Returns a ray in particle coordinates corresponding to given coordinates in the image plane.
virtual void initialize(const Storage &storage, const RefEnum ref)=0
Initialize the colorizer before by getting necessary quantities from storage.
virtual bool hasData(const Storage &storage) const =0
Checks if the storage constains all data necessary to initialize the colorizer.
Base class for all object performing an operation in a simulation hierarchy.
virtual std::string instanceName() const
Unique name representing this job.
virtual std::string className() const =0
Name representing the type of the job (e.e. "SPH").
virtual Expected< Path > dump(const Storage &storage, const Statistics &stats)=0
Saves data from particle storage into the file.
Wrapper of type value of which may or may not be present.
INLINE Type & value()
Returns the reference to the stored value.
INLINE Type valueOr(const TOther &other) const
Returns the stored value if the object has been initialized, otherwise returns provided parameter.
Represents a color palette, used for mapping arbitrary number to a color.
Object representing a path on a filesystem.
std::string native() const
Returns the native version of the path.
bool empty() const
Checks if the path is empty.
Path extension() const
Returns the extension of the filename.
GuiSettings & getGuiSettings()
void setPalette(const std::string &name, const Palette &palette)
Main frame of the application.
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)
void showTimeLine(const bool show)
void onTimeStep(const Storage &storage, const Statistics &stats)
void setSelectedParticle(const Particle &particle, const Rgba color)
Settings & set(const TEnum idx, TValue &&value, std::enable_if_t<!std::is_enum< std::decay_t< TValue >>::value, int >=0)
Saves a value into the settings.
Size size() const
Returns the number of entries in the settings.
Object holding various statistics about current run.
Statistics & set(const StatisticsId idx, TValue &&value)
Sets new values of a statistic.
Container storing all quantities used within the simulations.
Basic time-measuring tool. Starts automatically when constructed.
int64_t elapsed(const TimerUnit unit) const
Returns elapsed time in timer units. Does not reset the timer.
Optional< IoEnum > getIoEnum(const std::string &ext)
Returns the file type from file extension.
const EmptySettingsTag EMPTY_SETTINGS
@ RUN_OUTPUT_QUANTITIES
List of quantities to write to text output. Binary output always stores all quantitites.
@ RUN_OUTPUT_PATH
Path where all output files (dumps, logs, ...) will be written.
@ RUN_OUTPUT_TYPE
Selected format of the output file, see IoEnum.
@ RUN_OUTPUT_NAME
File name of the output file (including extension), where d is a placeholder for output number.
@ PARTICLE_RADIUS
Displayed radius of particle in units of smoothing length.
@ CAMERA_ORTHO_FOV
View field of view (zoom). Special value 0 means the field of view is computed from the bounding box.
AutoPtr< IOutput > getOutput(const RunSettings &settings)
AutoPtr< IColorizer > getColorizer(const Project &project, const ExtColorizerId id)
AutoPtr< IRenderer > getRenderer(const GuiSettings &settings)
AutoPtr< ICamera > getCamera(const GuiSettings &settings, const Pixel size)
Vector position(const Float a, const Float e, const Float u)
Computes the position on the elliptic trajectory.
Parameters of the rendered image.
Optional< Size > selected
Highlighted particle (only for interactive view).
struct RenderParams::@33 particles
Parameters of the particle renderer.
AutoPtr< ICamera > camera
Camera used for rendering.
void initialize(const GuiSettings &gui)
Sets up parameters using values stored in settings.