Skip to content
Snippets Groups Projects
Commit b6cbbc98 authored by Armin Co's avatar Armin Co
Browse files

Fixed threading issues.

New rendering and thread sage gtk without crashes.
parent 99245536
No related branches found
No related tags found
No related merge requests found
......@@ -20,3 +20,8 @@ make
./run
````
## List of errors
- cairo-surface.c:930: cairo_surface_reference: Assertion `CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)' failed
- (qpong.app:4590): GLib-CRITICAL **: 22:41:50.315: Source ID 120 was not found when attempting to remove it
- (qpong.app:27121): GdkPixbuf-CRITICAL **: 22:17:54.606: gdk_pixbuf_get_width: assertion 'GDK_IS_PIXBUF (pixbuf)' failed** Gdk:ERROR:../../../../gdk/gdkcairo.c:197:gdk_cairo_surface_paint_pixbuf: assertion failed: (cairo_image_surface_get_width (surface) == gdk_pixbuf_get_width (pixbuf)) Bail out! Gdk:ERROR:../../../../gdk/gdkcairo.c:197:gdk_cairo_surface_paint_pixbuf: assertion failed: cairo_image_surface_get_width (surface) == gdk_pixbuf_get_width (pixbuf))
\ No newline at end of file
///
/// @file ArrayCanvas.cpp
/// @author Armin Co
///
/// @brief Implementation of the ArrayCanvas class.
///
#include "ArrayCanvas.hpp"
bool ArrayCanvas::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
// Clear background.
cr->save();
cr->set_source_rgba(0.0, 0.0, 0.0, 1.0);
cr->paint();
// Print arrays.
for (unsigned y = 0; y < k_drawingAreaHeight; y++)
{
for (unsigned x = 0; x < k_drawingAreaWidth; x++)
{
QColor c;
double xi = x * imageScaleFactor;
double yi = y * imageScaleFactor;
// Print obstacles
// c = m_obstacles->getValue(x, y);
// cr->set_source_rgba(c.r, c.g, c.b, c.a);
// cr->rectangle(xi, yi, imageScaleFactor, imageScaleFactor);
// cr->fill();
// Print position
c = m_bufPositionRepresentation->getValue(x, y);
cr->set_source_rgba(c.r, c.g, c.b, c.a);
cr->rectangle(xi, yi, imageScaleFactor, imageScaleFactor);
cr->fill();
// Print momentum
c = m_bufMomentumRepresentation->getValue(x, y);
cr->set_source_rgba(c.r, c.g, c.b, c.a);
cr->rectangle((xi+ k_drawingAreaWidth*imageScaleFactor), yi, imageScaleFactor, imageScaleFactor);
cr->fill();
}
}
constexpr int crossSize = 10;
QColor c = {1.0, 0.9, 0.9, 0.2};
cr->set_source_rgba(c.r, c.g, c.b, c.a);
// draw horizontal half of cross
cr->move_to((nx* imageScaleFactor + nx* imageScaleFactor/2 - crossSize* imageScaleFactor/2), (nx* imageScaleFactor/2));
cr->line_to(nx* imageScaleFactor + nx* imageScaleFactor/2 + crossSize* imageScaleFactor/2, (ny* imageScaleFactor/2));
cr->stroke();
// draw certical half of cross
cr->move_to((nx* imageScaleFactor + nx* imageScaleFactor/2), (nx* imageScaleFactor/2 - crossSize* imageScaleFactor/2));
cr->line_to((nx* imageScaleFactor + nx* imageScaleFactor/2), (nx* imageScaleFactor/2 + crossSize* imageScaleFactor/2));
cr->stroke();
// draw seperator between position and momentum image
cr->move_to(nx*imageScaleFactor, 0);
cr->line_to(nx*imageScaleFactor, ny * imageScaleFactor);
cr->stroke();
cr->restore();
return true;
}
\ No newline at end of file
///
/// @file ArrayCanvas.hpp
/// @author Armin Co
///
/// @brief Class that draws two ParticleImages to a canvas.
///
#ifndef QPONG_DRAWING_AREA_HPP
#define QPONG_DRAWING_AREA_HPP
#include <array>
#include <gtkmm/drawingarea.h>
#include <glibmm.h>
#include "ParticleImage.hpp"
/// @brief Class ArrayCanvas. Draws two ParticleImages when triggered.
///
class ArrayCanvas : public Gtk::DrawingArea
{
public:
/// @brief Class ArrayCanvas drawing area for two ParticleImages.
///
ArrayCanvas(ParticleImage *momentum, ParticleImage *position, ParticleImage *obstacles) : m_bufMomentumRepresentation{momentum}, m_bufPositionRepresentation{position}, m_obstacles{obstacles}
{
// Connect dispatcher
m_dispatcher.connect(sigc::mem_fun(*this, &ArrayCanvas::queueDraw));
}
/// @brief Trigger the redraw of this Canvas for example from another thread.
///
void triggerRedraw()
{
m_dispatcher.emit();
}
protected:
/// @brief Define the behaviour when on_draw is called.
///
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
private:
/// @brief Bridge between threads to trigger the redraw of the canvas.
///
Glib::Dispatcher m_dispatcher;
/// @brief ParitcleImage copys from the simulation, which will be drawn to the screen.
///
ParticleImage *m_bufPositionRepresentation;
ParticleImage *m_bufMomentumRepresentation;
ParticleImage *m_obstacles;
/// @brief Wraps function to trigger redraw.
/// This function cannot be called from another thread.
/// Therefore the call of this function will be triggered by the dispatcher.
///
void queueDraw()
{
queue_draw();
}
};
#endif
\ No newline at end of file
## library for the app
add_library(qpong
QuantumMath.cpp
Particle.cpp
ParticleImage.cpp
ArrayCanvas.cpp
QWindow.cpp
QDrawingArea.cpp
)
## create the application
......@@ -11,7 +11,7 @@ add_executable(qpong.app
main.cpp
)
# we do need some threads
## we do need some threads
find_package(Threads)
## get all GTKMM dependencies and configuration
......
///
/// @file Common.hpp
/// @author Armin Co
///
#ifndef QPONG_COMMON_HPP
#define QPONG_COMMON_HPP
namespace QPong
{
constexpr int arrayWidth = 512;
constexpr int arrayHeight = 512;
constexpr unsigned arraySize = arrayWidth * arrayHeight;
}
#endif
\ No newline at end of file
///
/// @file Configuration.hpp
/// @author Armin Co
///
/// @brief A collection of constants which configure the physical environment.
///
#ifndef QPONG_CONFIGURATION_HPP
#define QPONG_CONFIGURATION_HPP
/// @brief Width of the drawing area in pixels.
///
constexpr unsigned long k_drawingAreaWidth = 256; // crashes at 418
constexpr unsigned imageScaleFactor = 3;
/// @brief Height of the drawing area in pixels.
///
constexpr unsigned long k_drawingAreaHeight = k_drawingAreaWidth;
/// @brief Size of one time step.
///
constexpr double dt = 0.15;
/// @brief Start position on the x-Axis.
///
constexpr double k_x0 = 0.0;
/// @brief Start position on the y-Axis.
///
constexpr double k_y0 = -0.5;
/// @brief Acceleration of gravity.
///
constexpr double g = 9.81;
/// @brief Mass of the particle.
///
constexpr double m = 1.0;
/// @brief Planck constant.
///
constexpr double hbar = 0.0001;
/// @brief Initial momentum in x direction.
///
constexpr double k_px0 = 0.02;
/// @brief Initial impuls in y direction.
///
constexpr double k_py0 = 0.009;
/// @brief This constants scales the size of the momentum on initialisation.
///
constexpr double lambda = 80.0;
/// @brief Scale the max value at initialisation of the momentum
///
constexpr double A0 = 1.0;
#endif
\ No newline at end of file
......@@ -10,42 +10,125 @@
#include <gtk/gtk.h>
#include "Common.hpp"
#include "Particle.hpp"
#include "Configuration.hpp"
const Complex Ci(0.0, 1.0);
/// @brief Planck constant.
///
constexpr double hbar = 0.0001;
const std::complex<double> Ci(0.0, 1.0);
/// @brief Calc square of a number.
///
template <typename T>
const T sqr(const T n)
{
return n * n;
}
const double xAt(int i)
{
constexpr double dx = 2.0 / QPong::arrayWidth;
return i * dx - 1.0;
}
const double yAt(int iy)
{
constexpr double dy = 2.0 / QPong::arrayHeight;
return iy * dy - 1.0;
}
const double pxAt(int ix)
{
if (ix > QPong::arrayWidth / 2)
ix -= QPong::arrayWidth;
return ix * M_PI * hbar;
}
const double pyAt(int iy)
{
if (iy > QPong::arrayHeight / 2)
iy -= QPong::arrayHeight;
return iy * M_PI * hbar;
}
const double obstaclePotential(double x, double y, double x0, double y0)
{
y -= y0;
constexpr double vx = 100000.0;
double E = 0.0;
constexpr double height = 0.31;
if (y >= height)
{
double d = sqr(x-x0) + sqr(y-height);
E = 1.0 / (sqrt(d) * vx);
}
else if (y <= (-height))
{
double d = sqr(x-x0) + sqr((-y)-height);
E = 1.0 / (sqrt(d) * vx);
}
else if ( x >= x0 && y < height && y>-height)
{
double d = x-x0;
E = 1.0 / (d * vx);
}
else if (x < x0 && y < height && y > -height)
{
double d = x0-x;
E = 1.0 / (d * vx);
}
return E;
}
void Particle::initMomentum()
{
std::cout << "Initialising particle" << std::endl;
#pragma omp parallel for
for (unsigned iy = 0; iy < ny; iy++)
for (unsigned iy = 0; iy < QPong::arrayHeight; iy++)
{
double y = yAt(iy);
for (unsigned ix = 0; ix < nx; ix++)
for (unsigned ix = 0; ix < QPong::arrayWidth; ix++)
{
double x = xAt(ix);
unsigned index = nx * iy + ix;
m_psi[index] = A0 * exp(Ci / hbar * (x * k_px0 + y * k_py0) - lambda * (square(x - k_x0) + square(y - k_y0)));
unsigned index = QPong::arrayWidth * iy + ix;
constexpr double k_px0 = 0.025;
constexpr double k_py0 = 0.009;
constexpr double k_x0 = 0.0;
constexpr double k_y0 = -0.0;
constexpr double lambda = 70.0;
constexpr double A0 = 2.5;
m_psi[index] = A0 * exp(Ci / hbar * (x * k_px0 + y * k_py0) - lambda * (sqr(x - k_x0) + sqr(y - k_y0)));
}
}
}
Particle::Particle(ArrayCanvas &ac, ParticleImage *momentum, ParticleImage *position, ParticleImage *obstacles) : m_arrayCanvas{ac},m_bufMomentumRepresentation{momentum}, m_bufPositionRepresentation{position}, m_obstacleImage{obstacles}
Particle::Particle(ParticleImage *momentum, ParticleImage *position, ParticleImage *obstacles)
: m_bufMomentumRepresentation{momentum}
, m_bufPositionRepresentation{position}
, m_obstacleImage{obstacles}
, m_ready{false}
{
std::cout << "Creating particle" << std::endl;
m_players.insert(std::make_pair(Players::One, Player {-0.7, 0.0}));
m_players.insert(std::make_pair(Players::Two, Player { 0.7, 0.0}));
fftw_init_threads();
constexpr int k_numThreads = 4;
constexpr int k_numThreads = 8;
fftw_plan_with_nthreads(k_numThreads);
m_psi = static_cast<Complex *>(fftw_malloc(sizeof(fftw_complex) * n));
m_psi = static_cast<std::complex<double> *>(fftw_malloc(sizeof(fftw_complex) * QPong::arraySize));
m_planForward = fftw_plan_dft_2d(ny, nx, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_FORWARD, FFTW_MEASURE);
m_planBackward = fftw_plan_dft_2d(ny, nx, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_BACKWARD, FFTW_MEASURE);
m_planForward = fftw_plan_dft_2d(QPong::arrayHeight, QPong::arrayWidth, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_FORWARD, FFTW_MEASURE);
m_planBackward = fftw_plan_dft_2d(QPong::arrayHeight, QPong::arrayWidth, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_BACKWARD, FFTW_MEASURE);
initMomentum();
m_ready = true;
}
Particle::~Particle()
......@@ -55,49 +138,48 @@ Particle::~Particle()
fftw_destroy_plan(m_planBackward);
}
bool Particle::notReady()
{
return !m_ready;
}
void Particle::propagate()
{
#pragma omp parallel for
for (unsigned iy = 0; iy < ny; iy++)
constexpr double dt = 0.1;
for (unsigned iy = 0; iy < QPong::arrayHeight; iy++)
{
double y = yAt(iy);
#pragma omp parallel for
for (unsigned long ix = 0; ix < nx; ix++)
for (unsigned long ix = 0; ix < QPong::arrayWidth; ix++)
{
constexpr double l = 0.0007; //lambda
double x = xAt(ix);
// double E = obstaclePotential(x, y);
double E = (square(x) * square(x) + square(y/2)) * l;
// double E = (square(x) + square(y)) * l;
int index = nx * iy + ix;
m_psi[index] *= exp(-Ci * dt / hbar * E);
// Complex tmp = m_psi[index] * exp(-Ci * dt / hbar * E);
// m_psi[index] = tmp;
// m_bufPositionRepresentation->updateBuffer(index, tmp + E*600*Ci);
m_bufPositionRepresentation->updateBuffer(index, m_psi[index]);
double E = obstaclePotential(x, y, m_players[Players::One].x, m_players[Players::One].y);
double E2 = obstaclePotential(x, y, m_players[Players::Two].x, m_players[Players::Two].y);
double E3 = sqr(y) * sqr(y) * sqr(y) * sqr(y) * 0.00012;
int index = QPong::arrayWidth * iy + ix;
std::complex<double> tmp = m_psi[index] * exp(-Ci * dt / hbar * (E + E2 + E3));
m_psi[index] = tmp;
m_bufPositionRepresentation->updateBuffer(index, tmp, (E+E2+E3)*800);
}
}
fftw_execute (m_planForward); // transform into momentum repr.
#pragma omp parallel for
for (unsigned iy = 0; iy < ny; iy++)
for (unsigned iy = 0; iy < QPong::arrayHeight; iy++)
{
double py = pyAt(iy);
#pragma omp parallel for
for (unsigned long ix = 0; ix < nx; ix++)
for (unsigned long ix = 0; ix < QPong::arrayWidth; ix++)
{
double px = pxAt(ix);
double E = (square(px) + square(py)) / (2.0 * m);
constexpr double N = 1.0 / (nx * ny);
int index = nx * iy + ix;
constexpr double m = 1.0;
double E = (sqr(px) + sqr(py)) / (2.0 * m);
constexpr double N = 1.0 / (QPong::arrayWidth * QPong::arrayHeight);
int index = QPong::arrayWidth * iy + ix;
m_psi[index] *= exp(-Ci * dt / hbar * E) * N;
}
}
updateMomentumImage(); //momentum
fftw_execute(m_planBackward); // transform into position repr.
// updatePositionImage(); //position
}
......@@ -107,47 +189,48 @@ void Particle::updateMomentumImage()
unsigned py = 0;
unsigned long momentum_index = 0;
unsigned long array_index = 0;
#pragma omp parallel for
for (unsigned y = 0; y < ny; y++)
for (unsigned y = 0; y < QPong::arrayHeight; y++)
{
for (unsigned x = 0; x < nx; x++)
for (unsigned x = 0; x < QPong::arrayWidth; x++)
{
if (y >= ny / 2)
if (y >= QPong::arrayHeight / 2)
{
py = y - ny / 2;
py = y - QPong::arrayHeight / 2;
}
else
{
py = y + ny / 2;
py = y + QPong::arrayHeight / 2;
}
if (x >= nx / 2)
if (x >= QPong::arrayWidth / 2)
{
px = x - nx / 2;
px = x - QPong::arrayWidth / 2;
}
else
{
px = x + nx / 2;
px = x + QPong::arrayWidth / 2;
}
momentum_index = py * nx + px;
array_index = y * nx + x;
m_bufMomentumRepresentation->updateBuffer(array_index, (m_psi[momentum_index] * 142.42));
constexpr double scale = 164.0;
array_index = y * QPong::arrayWidth + x;
momentum_index = py * QPong::arrayWidth + px;
m_bufMomentumRepresentation->updateBuffer(array_index, (m_psi[momentum_index] * scale), 0.0);
}
}
}
void Particle::updatePositionImage()
void Particle::updateObstacle(Players player, Move direction)
{
#pragma omp parallel for
constexpr double stepSize = 0.05;
for (unsigned y = 0; y < ny; y++)
{
for (unsigned x = 0; x < nx; x++)
switch (direction)
{
unsigned index = y * nx + x;
m_bufPositionRepresentation->updateBuffer(index, m_psi[index]);
}
case Move::Up:
m_players[player].y -= stepSize;
break;
case Move::Down:
m_players[player].y += stepSize;
break;
}
}
\ No newline at end of file
......@@ -8,33 +8,65 @@
#ifndef QPONG_PARTICLE_HPP
#define QPONG_PARTICLE_HPP
#include <complex>
#include <map>
#include <math.h>
#include <fftw3.h>
#include "ArrayCanvas.hpp"
#include "QuantumMath.hpp"
#include "ParticleImage.hpp"
class ArrayCanvas; // Forward declaration
enum class Players
{
One,
Two
};
enum class Move
{
Up,
Down
};
struct Player
{
double x;
double y;
};
class Particle
{
public:
Particle() = delete;
Particle(ArrayCanvas &ac, ParticleImage *momentum, ParticleImage *position, ParticleImage *obstacles);
Particle(ParticleImage *momentum, ParticleImage *position, ParticleImage *obstacles);
~Particle();
/// @brief Execute one step of the simulation.
///
void propagate();
/// @brief Init the array with initial momentum.
/// Representation is in position representation.
///
void initMomentum();
/// @brief Update obstacle position
/// @param player
/// @param direction
///
void updateObstacle(Players player, Move direction);
/// @brief Check if everything is initialised.
///
bool notReady();
private:
Complex *m_psi;
ArrayCanvas &m_arrayCanvas;
std::complex<double> *m_psi;
fftw_plan m_planForward;
fftw_plan m_planBackward;
bool m_ready;
std::map<Players, Player> m_players;
ParticleImage *m_bufPositionRepresentation;
ParticleImage *m_bufMomentumRepresentation;
......@@ -43,7 +75,6 @@ private:
/// @brief Update the array at the ArrayCanvas
///
void updateMomentumImage();
void updatePositionImage();
};
#endif
\ No newline at end of file
......@@ -3,28 +3,75 @@
/// @author Armin Co
///
#include "ParticleImage.hpp"
#include "Common.hpp"
constexpr unsigned maxBufferCount = 2;
void ParticleImage::updateBuffer(unsigned index, Complex v)
ParticleImage::ParticleImage()
{
m_obsbuf = new double[QPong::arraySize];
m_pixbuf = new guint8[QPong::arraySize * 4];
m_complexBuffer = new std::complex<double>[QPong::arraySize];
}
m_buffer[index] = v;
void ParticleImage::updateBuffer(unsigned index, std::complex<double> v, double obs)
{
m_obsbuf[index] = obs;
m_complexBuffer[index] = v;
}
const QColor ParticleImage::getValue(const unsigned x, const unsigned y)
Glib::RefPtr<Gdk::Pixbuf> ParticleImage::getPixbuf()
{
unsigned long index = y * nx + x;
constexpr double scale_factor = 0.9;
Complex val = m_buffer[index];
for (unsigned i = 0; i < QPong::arraySize * 4;)
{
QColor c = getValue(i/4);
m_pixbuf[i++] = static_cast<guint8>(c.r * 255);
m_pixbuf[i++] = static_cast<guint8>(c.g * 255);
m_pixbuf[i++] = static_cast<guint8>(c.b * 255);
m_pixbuf[i++] = static_cast<guint8>( 255);
}
Glib::RefPtr<Gdk::Pixbuf> pb = Gdk::Pixbuf::create_from_data(m_pixbuf, Gdk::Colorspace::COLORSPACE_RGB, true, 8, QPong::arrayWidth, QPong::arrayHeight, QPong::arrayWidth * 4);
pb = pb.get()->scale_simple(1024, 1024, Gdk::InterpType::INTERP_NEAREST);
return pb;
}
const QColor ParticleImage::getValue(unsigned index)
{
std::complex<double> val = m_complexBuffer[index];
QColor c;
val *= scale_factor;
double r = real(val);
double i = imag(val);
c.r = square(r);
c.g = square(r) + square(i);
c.b = square(i);
double obs = m_obsbuf[index];
c.r = obs + r*r;
c.g = r*r + i*i;
// c.b = 0;
c.b = i*i;
if (c.r > 1.0)
{
c.r = 1.0;
}
if (c.g > 1.0)
{
c.g = 1.0;
}
if (c.b > 1.0)
{
c.b = 1.0;
}
return c;
}
const QColor ParticleImage::getValue(const unsigned x, const unsigned y)
{
unsigned index = y * QPong::arrayWidth + x;
return getValue(index);
}
\ No newline at end of file
......@@ -8,11 +8,13 @@
#ifndef QPONG_PARTICLE_IMAGE_HPP
#define QPONG_PARTICLE_IMAGE_HPP
#include <complex>
#include <array>
#include <cairomm/context.h>
#include <mutex>
#include "QuantumMath.hpp"
#include <gtkmm.h>
#include "Common.hpp"
/// @brief Convinient conatiner to store a RGBA value.
///
......@@ -31,17 +33,23 @@ struct QColor
class ParticleImage
{
public:
ParticleImage();
/// @return Get Color value from particle at position (x,y).
///
const QColor getValue(const unsigned x, const unsigned y);
const QColor getValue(unsigned index);
void updateBuffer(unsigned index, Complex v);
Glib::RefPtr<Gdk::Pixbuf> getPixbuf();
void updateBuffer(unsigned index, std::complex<double> v, double obs);
private:
/// @brief Buffer for array with complex values from simulation.
///
std::array<Complex, n> m_buffer;
double *m_obsbuf;
std::complex<double> *m_complexBuffer;
guint8 *m_pixbuf;
};
#endif
\ No newline at end of file
///
/// @file QDrawingArea.cpp
/// @author Armin Co
///
#include <thread>
#include "QDrawingArea.hpp"
QDrawingArea::QDrawingArea()
{
m_dispatcher.connect(sigc::mem_fun(*this, &QDrawingArea::queue_draw));
}
void QDrawingArea::triggerRedraw()
{
m_dispatcher.emit();
}
void QDrawingArea::setPixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf)
{
// if ((pixbuf != nullptr) && (m_image != nullptr))
m_image = pixbuf;
}
bool QDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context> &cr)
{
cr->save();
if (!m_image)
{
return true;
}
Gdk::Cairo::set_source_pixbuf(cr, m_image, 0, 0);
cr->paint();
cr->restore();
return true;
}
///
/// @file QDrawingArea.hpp
/// @author Armin Co
///
#ifndef QPONG_DRAWING_AREA_HPP
#define QPONG_DRAWING_AREA_HPP
#include <gtkmm.h>
#include <gdkmm.h>
class QDrawingArea : public Gtk::DrawingArea
{
public:
QDrawingArea();
virtual ~QDrawingArea(){};
void triggerRedraw();
void setPixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf);
protected:
bool on_draw(const Cairo::RefPtr<Cairo::Context> &cr) override;
private:
Glib::RefPtr<Gdk::Pixbuf> m_image;
Glib::Dispatcher m_dispatcher;
};
#endif
\ No newline at end of file
#include <iostream>
#include <chrono>
#include "QWindow.hpp"
bool propagating = true;
int propRate = 0;
int renderRate = 0;
/// @brief This functino has to run in its own thread and propagates the particle as fast as possible.
///
void simulation(Particle *p)
{
do
{
auto start = std::chrono::system_clock::now();
p->propagate();
propRate = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start).count();
}
while (propagating);
}
/// @brief This function has to run in its own thread an will redraw the canvas every ~25ms.
///
void render(QWindow *w)
{
do
{
using namespace std::chrono_literals;
auto start = std::chrono::system_clock::now();
std::this_thread::sleep_for(20ms);
w->emitImageDraw();
renderRate = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start).count();
} while (true);
}
QWindow::QWindow()
: m_button{"Initialise Particle"}
, m_label("Hi, you are playing QPong and this is a label!")
{
set_border_width(10);
m_momentum = new ParticleImage;
m_position = new ParticleImage;
m_particle = new Particle(m_momentum, m_position, m_obstacle);
add(m_box);
m_box.pack_start(m_vBox);
m_vBox.pack_start(m_button, Gtk::PACK_SHRINK);
m_vBox.pack_start(m_label, Gtk::PACK_SHRINK);
m_fpsBox.pack_start(m_renderRate, Gtk::PACK_EXPAND_WIDGET);
m_fpsBox.pack_start(m_proppergatingRate, Gtk::PACK_EXPAND_WIDGET);
m_vBox.pack_start(m_fpsBox, Gtk::PACK_SHRINK);
m_hBox.pack_start(m_positionArea);
m_hBox.pack_start(m_momentumArea);
m_vBox.pack_start(m_hBox);
m_label.set_margin_top(5);
m_label.set_margin_bottom(5);
m_proppergatingRate.set_text("0");
m_renderRate.set_text("0");
m_renderRate.set_margin_top(5);
m_renderRate.set_margin_bottom(5);
m_proppergatingRate.set_margin_top(5);
m_proppergatingRate.set_margin_bottom(5);
m_button.signal_clicked().connect(sigc::mem_fun(*this, &QWindow::onButtonPress));
this->signal_key_press_event().connect( sigc::mem_fun( *this, &QWindow::onKeyPress));
m_guiDispatcher.connect(sigc::mem_fun(*this, &QWindow::updateGui));
m_areaDispatcher.connect(sigc::mem_fun(*this, &QWindow::updateImage));
while (m_particle->notReady())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
m_propagatingThread = std::thread(simulation, m_particle);
m_propagatingThread.detach();
std::thread rendering(render, this);
rendering.detach();
m_box.show_all();
}
unsigned guiUpdates = 0;
void QWindow::updateGui()
{
guiUpdates++;
if (guiUpdates % 10 == 0)
{
std::stringstream ss;
ss << "image update rate: ";
ss << 1000 / renderRate;
m_renderRate.set_text(ss.str());
ss = std::stringstream();
ss << "simulation rate: ";
ss << 1000 / propRate;
m_proppergatingRate.set_text(ss.str());
}
}
bool QWindow::onKeyPress(GdkEventKey* event)
{
constexpr int q = 113;
if (event->keyval == q)
{
m_particle->updateObstacle(Players::One, Move::Up);
}
constexpr int a = 97;
if (event->keyval == a)
{
m_particle->updateObstacle(Players::One, Move::Down);
}
constexpr int ue = 252;
if (event->keyval == ue)
{
m_particle->updateObstacle(Players::Two, Move::Up);
}
constexpr int oe = 246;
if (event->keyval == oe)
{
m_particle->updateObstacle(Players::Two, Move::Down);
}
return true;
}
void QWindow::emitImageDraw()
{
m_areaDispatcher.emit();
m_guiDispatcher.emit();
}
void QWindow::updateImage()
{
m_positionArea.setPixbuf(m_position->getPixbuf());
m_momentumArea.setPixbuf(m_momentum->getPixbuf());
m_positionArea.triggerRedraw();
m_momentumArea.triggerRedraw();
}
void QWindow::onButtonPress()
{
propagating = false;
std::this_thread::sleep_for((std::chrono::seconds)1);
m_particle->initMomentum();
m_propagatingThread = std::thread(simulation, m_particle);
propagating = true;
m_propagatingThread.detach();
}
\ No newline at end of file
///
/// @file QWindow.hpp
/// @author Armin Co
///
#ifndef Q_WINDOW_HPP
#define Q_WINDOW_HPP
#include <thread>
#include <gtkmm.h>
#include "Particle.hpp"
#include "QDrawingArea.hpp"
/// @brief Definition of the QPong window
///
class QWindow : public Gtk::Window
{
public:
QWindow();
virtual ~QWindow(){}
void updateImage();
void updateGui();
void emitImageDraw();
protected:
/// @brief signal handlers
///
void onButtonPress();
bool onKeyPress(GdkEventKey* event);
private:
Gtk::Box m_box;
Gtk::VBox m_vBox;
Gtk::HBox m_hBox;
Gtk::Box m_fpsBox;
Gtk::Label m_label;
Gtk::Button m_button;
Gtk::Label m_renderRate;
Gtk::Label m_proppergatingRate;
Glib::Dispatcher m_guiDispatcher;
Glib::Dispatcher m_areaDispatcher;
QDrawingArea m_positionArea;
QDrawingArea m_momentumArea;
Particle *m_particle;
std::thread m_propagatingThread;
ParticleImage *m_momentum;
ParticleImage *m_position;
ParticleImage *m_obstacle;
};
#endif
\ No newline at end of file
///
/// @file QuantumMath.cpp
/// @author Armin Co
///
/// @brief Implementation of the QuantumMath functions.
///
#include "QuantumMath.hpp"
const double obstaclePotential(double x, double y)
{
double xPos = 0;
double yPos = 0;
constexpr double maxV = 1;
constexpr double l = 0.0007; //lambda
double E = (square(x) * square(x) + square(y/2)) * l;
return E;
}
const double xAt(int i)
{
return (i - (nx / 2)) * dx;
}
const double yAt(int iy)
{
return (iy - (ny / 2)) * dy;
}
const double pxAt(int ix)
{
if (ix > nx / 2)
ix -= nx;
return ix * 2.0 * M_PI * hbar / (nx * dx);
}
const double pyAt(int iy)
{
if (iy > ny / 2)
iy -= ny;
return iy * 2.0 * M_PI * hbar / (ny * dy);
}
///
/// @file QunatumMath.hpp
/// @author Armin Co
///
/// @brief Simple functions for math and other calculations.
#ifndef QPONG_Q_MATH_HPP
#define QPONG_Q_MATH_HPP
#include <complex>
#include "Configuration.hpp"
using Complex = std::complex<double>;
///
/// @brief Calc square of a number.
///
template <typename T>
const T square(const T n)
{
return n * n;
}
// Points in x direction.
const int nx = k_drawingAreaWidth;
// Points in y direction.
const int ny = k_drawingAreaHeight;
// Number of all points/pixels.
constexpr int n = nx * ny;
const double dx = 2.0 / nx;
const double dy = 2.0 / ny;
/// @brief Potential of the obstachle that is controlled by the player.
///
const double obstaclePotential(double x, double y);
/// @brief Get index to access array in position representation.
///
const double xAt(int i);
const double yAt(int iy);
/// @brief Get index to access array in momentum representation.
///
const double pxAt(int ix);
const double pyAt(int iy);
#endif
\ No newline at end of file
......@@ -4,122 +4,23 @@
///
/// @brief Application
///
#include <iostream>
#include <chrono>
#include <thread>
#include <gtkmm.h>
#include "ArrayCanvas.hpp"
#include "Particle.hpp"
#include "Configuration.hpp"
bool propagating = true;
/// @brief This functino has to run in its own thread and propagates the particle as fast as possible.
///
void simulation(Particle *p)
{
do
{
p->propagate();
}
while (propagating);
}
/// @brief This function has to run in its own thread an will redraw the canvas every ~25ms.
///
void render(ArrayCanvas *ac)
{
do
{
using namespace std::chrono_literals;
std::this_thread::sleep_for(5ms);
ac->triggerRedraw();
} while (true);
}
class QWindow : public Gtk::Window
{
public:
QWindow() : m_button{"Initialise Particle"}
{
m_momentum = new ParticleImage;
m_position = new ParticleImage;
m_obstacles = new ParticleImage;
m_ac = new ArrayCanvas(m_momentum, m_position, m_obstacles);
m_particle = new Particle(*m_ac, m_momentum, m_position, m_obstacles);
set_border_width(10);
m_button.signal_clicked().connect(sigc::mem_fun(*this, &QWindow::on_button_clicked));
add(m_box);
m_box.pack_start(m_vBox);
m_vBox.pack_start(m_button, Gtk::PACK_SHRINK);
m_vBox.pack_start(m_label, Gtk::PACK_SHRINK);
m_vBox.pack_start(*m_ac);
m_label.set_margin_top(5);
m_label.set_margin_bottom(5);
m_ac->show();
m_button.show();
m_box.show();
m_vBox.show();
m_label.show();
m_label.set_text("Hi, you are playing QPong and this is a label!");
m_propagatingThread = std::thread(simulation, m_particle);
m_propagatingThread.detach();
std::cout << "Starting to draw images" << std::endl;
std::thread rendering(render,m_ac);
rendering.detach();
}
virtual ~QWindow(){}
protected:
// signal handlers:
void on_button_clicked()
{
propagating = false;
std::this_thread::sleep_for((std::chrono::seconds)1);
m_particle->initMomentum();
m_propagatingThread = std::thread(simulation, m_particle);
propagating = true;
m_propagatingThread.detach();
}
// Member widgets:
Gtk::Box m_box;
Gtk::VBox m_vBox;
Gtk::Label m_label;
Gtk::Button m_button;
ArrayCanvas *m_ac;
// qpong
Particle *m_particle;
std::thread m_propagatingThread;
ParticleImage *m_momentum;
ParticleImage *m_position;
ParticleImage *m_obstacles;
};
#include "QWindow.hpp"
/// @brief MAIN
///
int main(int argc, char* argv[])
{
std::cout << "Starting QPong" << std::endl;
std::cout << "QPong -- Starting" << std::endl;
auto app = Gtk::Application::create(argc, argv, "de.armin-co.qpong");
std::cout << "Creating window" << std::endl;
QWindow window;
window.set_default_size(k_drawingAreaWidth*imageScaleFactor*2+130, k_drawingAreaWidth*imageScaleFactor+100);
window.set_default_size(1920, 1200);
std::cout << "QPong -- Window created!" << std::endl;
return app->run(window);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment