diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 2d91947..1208c20 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -373,6 +373,30 @@ void MainWindow::normalizeLengths() { void MainWindow::add() { if (multiple){ + for (int i = 0; i < count; i++){ + auto M = std::vector(masses.begin(), masses.begin() + segments); + auto L = std::vector(lengths.begin(), lengths.begin() + segments); + double angle = startingAngle; + double changeAmount = changeAmountPercentage / 100; + double progress = double(i) / count - 0.5; + QColor c = color; + switch (changeProperty) { + case Angle: + angle += progress * 360 * changeAmount; + break; + case Mass: + M[changeIndex] += progress * M[changeIndex] * changeAmount; + break; + case Length: + L[changeIndex] += progress * L[changeIndex] * changeAmount; + break; + } + if (rainbow){ + auto hue = progress + 0.5; + c = QColor::fromHsvF(hue, 1, 1); + } + simulation->pendula.push_back(new Pendulum(M, L, c, angle)); + } } else { auto M = std::vector(masses.begin(), masses.begin() + segments); auto L = std::vector(lengths.begin(), lengths.begin() + segments); @@ -381,7 +405,7 @@ void MainWindow::add() { } void MainWindow::remove() { - + simulation->clearPendula(); } void MainWindow::resetSimulationControl() { diff --git a/src/Pendulum.cpp b/src/Pendulum.cpp index 3ebf50d..f2393a5 100644 --- a/src/Pendulum.cpp +++ b/src/Pendulum.cpp @@ -32,3 +32,42 @@ void Pendulum::draw(QPainter *p, double scale) const { p->drawEllipse(QPointF(x.x, x.y), r * 2, r * 2); } } + +void Pendulum::update(double h, double g) { + Vector p1(0, 0); + + for (int i = 0; i < X.size(); i++){ + V[i] = V[i] + Vector(0, g * h); + + Vector p2 = X[i] + V[i] * h; + + // solve distance constraint + double w1 = i == 0 ? 0 : 1 / M[i - 1]; + double w2 = 1 / M[i]; + + Vector s = p1 - p2; + Vector n = s; + n.normalize(); + double l = s.length(); + + Vector deltaP1 = n * -w1 / (w1 + w2) * (l - L[i]); + Vector deltaP2 = n * w2 / (w1 + w2) * (l - L[i]); + + p1 = p1 + deltaP1; + p2 = p2 + deltaP2; + + // integrate + if (i > 0){ + V[i - 1] = (p1 - X[i - 1]) / h; + X[i - 1] = p1; + } + + p1 = p2; + } + + // integrate last segment + int i = X.size() - 1; + V[i] = (p1 - X[i]) / h; + X[i] = p1; + +} diff --git a/src/Pendulum.h b/src/Pendulum.h index 6dd6766..f748371 100644 --- a/src/Pendulum.h +++ b/src/Pendulum.h @@ -12,6 +12,7 @@ public: QColor color, double startAngle); void draw(QPainter*, double) const; + void update(double, double); private: std::vector X, V; diff --git a/src/Simulation.cpp b/src/Simulation.cpp index 9a9e273..eb17304 100644 --- a/src/Simulation.cpp +++ b/src/Simulation.cpp @@ -1,12 +1,37 @@ #include "Simulation.h" #include "Pendulum.h" #include +#include -Simulation::Simulation() = default; +Simulation::Simulation() { + timer = new QTimer(this); + QTimer::connect(timer, &QTimer::timeout, this, &Simulation::update); + timer->setInterval(updateInterval); + timer->start(); +}; void Simulation::draw(QPainter *p, int screenSize) const { - double scale = screenSize / size; + double scale = screenSize * 0.95 / size; for (const auto pendulum : pendula) pendulum->draw(p, scale); } + +void Simulation::update() { + if (!isPlaying) + return; + + double h = (timescale * updateInterval) / 1000; + + h /= substeps; + + for (int i = 0; i < substeps; i++) + for (const auto pendulum : pendula) + pendulum->update(h, gravity); +} + +void Simulation::clearPendula() { + for (auto p : pendula) + delete p; + pendula.clear(); +} diff --git a/src/Simulation.h b/src/Simulation.h index 7cd37e3..a31a608 100644 --- a/src/Simulation.h +++ b/src/Simulation.h @@ -1,10 +1,12 @@ #include #include +#include class Pendulum; class QPainter; +class QTimer; -class Simulation { +class Simulation : public QObject { public: explicit Simulation(); @@ -14,9 +16,16 @@ public: double timescale; int substeps; + int updateInterval = 17; + bool isPlaying = false; std::vector pendula; + void clearPendula(); + + QTimer * timer; void draw(QPainter*, int) const; +private slots: + void update(); }; \ No newline at end of file