From 5c45de0785b4b5f618048fd2fa9f762f43b36c58 Mon Sep 17 00:00:00 2001 From: Benjamin Kraft Date: Sun, 10 Sep 2023 12:38:31 +0200 Subject: [PATCH] add single, drawing done --- src/GLWidget.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- src/GLWidget.h | 15 +++++++++++++++ src/MainWindow.cpp | 18 +++++++++++++----- src/MainWindow.h | 8 ++++---- src/Pendulum.cpp | 35 ++++++++++++++++++++++++++++++++++- src/Pendulum.h | 17 +++++++++++++++++ src/Simulation.cpp | 9 +++++++++ src/Simulation.h | 3 +++ src/Vector.cpp | 31 +++++++++++++++++++++++++++++++ src/Vector.h | 12 ++++++++++++ 10 files changed, 178 insertions(+), 11 deletions(-) create mode 100644 src/Vector.cpp create mode 100644 src/Vector.h diff --git a/src/GLWidget.cpp b/src/GLWidget.cpp index 0b5091e..7e81baf 100644 --- a/src/GLWidget.cpp +++ b/src/GLWidget.cpp @@ -2,9 +2,48 @@ #include #include #include +#include +#include "Simulation.h" +#include +#include + +GLWidget::GLWidget(Simulation * simulation) : simulation(simulation) { + startTimer(1000 / 144); + previousFrame = high_resolution_clock::now(); +} void GLWidget::paintEvent(QPaintEvent *e) { + + updateFPS(); + auto p = new QPainter(this); - p->fillRect(e->rect(), Qt::black); + p->setRenderHint(QPainter::Antialiasing); + p->fillRect(e->rect(), QColor(30, 30, 30)); + p->translate(e->rect().center()); + + simulation->draw(p, std::min(width(), height())); + p->end(); } + +void GLWidget::timerEvent(QTimerEvent *e) { + if (!AnyDialogOpen()) + update(); +} + +void GLWidget::updateFPS() { + auto thisFrame = high_resolution_clock::now(); + auto diff = duration_cast(thisFrame - previousFrame).count(); + currentFPS = 1000 / (diff == 0 ? 1 : diff); + previousFrame = thisFrame; +} + +bool GLWidget::AnyDialogOpen() { + for (auto widget : QApplication::topLevelWidgets()) + if (auto dialog = qobject_cast(widget)) + if (dialog->isVisible()) + return true; + return false; +} + + diff --git a/src/GLWidget.h b/src/GLWidget.h index 4db76f2..e606a45 100644 --- a/src/GLWidget.h +++ b/src/GLWidget.h @@ -1,7 +1,22 @@ #include #include +#include + +using namespace std::chrono; + +class Simulation; class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions { +public: + explicit GLWidget(Simulation *); protected: void paintEvent(QPaintEvent* e) override; + void timerEvent(QTimerEvent* e) override; +private: + Simulation * simulation; + time_point previousFrame; + int currentFPS; + void updateFPS(); + + static bool AnyDialogOpen(); }; \ No newline at end of file diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index bcff645..2d91947 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -8,11 +8,12 @@ #include #include #include -#include #include #include #include #include +#include +#include "Pendulum.h" MainWindow::MainWindow() { simulation = new Simulation; @@ -27,10 +28,10 @@ MainWindow::MainWindow() { } void MainWindow::buildUI() { - setMinimumSize(800, 500); + setMinimumSize(1000, 400); auto uiLyt = new QVBoxLayout; - glWidget = new GLWidget; + glWidget = new GLWidget(simulation); auto mainLyt = new QHBoxLayout(this); mainLyt->addLayout(uiLyt); @@ -260,13 +261,14 @@ QWidget * MainWindow::buildAddUI() { multipleLyt->addWidget(indexSlider); auto amountLabel = new QLabel; - auto amountSlider = new Slider(amountLabel, "Change Amount: %5.3f%%", &changeAmount, [](int v){ + auto amountSlider = new Slider(amountLabel, "Change Amount: %5.3f%%", &changeAmountPercentage, [](int v){ return double(v) / 1000; }, [](double v){ return int(v * 1000); }); - amountSlider->setMinimum(1); amountSlider->setMaximum(1000); + amountSlider->setFromTarget(); + amountSlider->setMinimum(1); multipleLyt->addWidget(amountLabel); multipleLyt->addWidget(amountSlider); } @@ -369,7 +371,13 @@ void MainWindow::normalizeLengths() { } void MainWindow::add() { + if (multiple){ + } else { + auto M = std::vector(masses.begin(), masses.begin() + segments); + auto L = std::vector(lengths.begin(), lengths.begin() + segments); + simulation->pendula.push_back(new Pendulum(M, L, color, startingAngle)); + } } void MainWindow::remove() { diff --git a/src/MainWindow.h b/src/MainWindow.h index fbb5ef6..16f2eb2 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -30,11 +30,11 @@ private: int count = 100; Property changeProperty = Angle; int changeIndex = 0; - double changeAmount = 0.001; + double changeAmountPercentage = 0.5; - QGridLayout * segmentGrid; - Slider * gravitySlider, * timescaleSlider; - Slider<> * substepsSlider; + QGridLayout * segmentGrid {}; + Slider * gravitySlider = nullptr, * timescaleSlider = nullptr; + Slider<> * substepsSlider = nullptr; public slots: diff --git a/src/Pendulum.cpp b/src/Pendulum.cpp index a7a47ec..3ebf50d 100644 --- a/src/Pendulum.cpp +++ b/src/Pendulum.cpp @@ -1 +1,34 @@ -#include "Pendulum.h" \ No newline at end of file +#include "Pendulum.h" +#include +#include + +Pendulum::Pendulum(const std::vector &M, + const std::vector &L, + QColor color, double startAngle) : M(M), L(L), color(color){ + + startAngle *= 3.141 / 180; + + Vector direction(-sin(startAngle), cos(startAngle)); + Vector currentPosition(0, 0); + + for (int i = 0; i < M.size(); i++){ + currentPosition = currentPosition + direction * L[i]; + X.push_back(currentPosition); + V.emplace_back(0, 0); + } +} + +void Pendulum::draw(QPainter *p, double scale) const { + p->setPen(color); + p->setBrush(Qt::white); + Vector previousX(0, 0); + + for (int i = 0; i < X.size(); i++){ + Vector x = X[i] * scale; + p->drawLine(previousX.x, previousX.y, x.x, x.y); + previousX = x; + + double r = sqrt(M[i] * scale / 5); + p->drawEllipse(QPointF(x.x, x.y), r * 2, r * 2); + } +} diff --git a/src/Pendulum.h b/src/Pendulum.h index eecc726..6dd6766 100644 --- a/src/Pendulum.h +++ b/src/Pendulum.h @@ -1,3 +1,20 @@ +#include +#include +#include +#include "Vector.h" + +class QPainter; + class Pendulum { +public: + explicit Pendulum(const std::vector &M, + const std::vector &L, + QColor color, double startAngle); + + void draw(QPainter*, double) const; +private: + std::vector X, V; + std::vector M, L; + QColor color; }; \ No newline at end of file diff --git a/src/Simulation.cpp b/src/Simulation.cpp index 1bbd888..9a9e273 100644 --- a/src/Simulation.cpp +++ b/src/Simulation.cpp @@ -1,3 +1,12 @@ #include "Simulation.h" +#include "Pendulum.h" +#include Simulation::Simulation() = default; + +void Simulation::draw(QPainter *p, int screenSize) const { + double scale = screenSize / size; + + for (const auto pendulum : pendula) + pendulum->draw(p, scale); +} diff --git a/src/Simulation.h b/src/Simulation.h index 1d0af59..7cd37e3 100644 --- a/src/Simulation.h +++ b/src/Simulation.h @@ -2,6 +2,7 @@ #include class Pendulum; +class QPainter; class Simulation { public: @@ -16,4 +17,6 @@ public: bool isPlaying = false; std::vector pendula; + + void draw(QPainter*, int) const; }; \ No newline at end of file diff --git a/src/Vector.cpp b/src/Vector.cpp new file mode 100644 index 0000000..9378f92 --- /dev/null +++ b/src/Vector.cpp @@ -0,0 +1,31 @@ +#include "Vector.h" +#include + +Vector::Vector(double x, double y) : x(x), y(y) {} + +double Vector::length() const { + return sqrt(x * x + y * y); +} + +void Vector::normalize() { + double l = length(); + x /= l; + y /= l; +} + +Vector operator+(Vector lhs, Vector rhs) { + return {lhs.x + rhs.x, lhs.y + rhs.y}; +} + +Vector operator-(Vector lhs, Vector rhs) { + return {lhs.x - rhs.x, lhs.y - rhs.y}; +} + +Vector operator*(Vector v, double factor){ + return {v.x * factor, v.y * factor}; +} + +Vector operator/(Vector v, double divisor){ + return {v.x / divisor, v.y / divisor}; +} + diff --git a/src/Vector.h b/src/Vector.h new file mode 100644 index 0000000..334f913 --- /dev/null +++ b/src/Vector.h @@ -0,0 +1,12 @@ +struct Vector { + double x, y; + Vector(double x, double y); + + double length() const; + void normalize(); + + friend Vector operator +(Vector lhs, Vector rhs); + friend Vector operator -(Vector lhs, Vector rhs); + friend Vector operator *(Vector v, double factor); + friend Vector operator /(Vector v, double divisor); +}; \ No newline at end of file