Added gravitation
This commit is contained in:
parent
61afefa6b5
commit
64419997dd
|
@ -7,7 +7,7 @@ cmake_minimum_required (VERSION 3.8)
|
|||
add_executable (GraviSim
|
||||
"main.cpp"
|
||||
"MainWindow.cpp"
|
||||
"Screen.hpp" "Screen.cpp" "Planet.hpp" "Planet.cpp" "PlanetConfig.cpp" )
|
||||
"Screen.hpp" "Screen.cpp" "Planet.hpp" "Planet.cpp" "PlanetConfig.cpp" "PlanetManager.hpp" "PlanetManager.cpp")
|
||||
|
||||
target_link_libraries(GraviSim
|
||||
Qt5::Widgets
|
||||
|
|
|
@ -33,6 +33,7 @@ void MainWindow::OpenPlanetDialog(Planet* planet)
|
|||
ui.config->Enable();
|
||||
ui.config->SetTitle(planet->name);
|
||||
ui.config->SetRadius(planet->radius);
|
||||
ui.config->SetMass(planet->mass);
|
||||
ui.config->SetColor(planet->GetColor());
|
||||
ui.config->SetX(planet->position.rx());
|
||||
ui.config->SetY(planet->position.ry());
|
||||
|
@ -48,10 +49,17 @@ void MainWindow::ClosePlanetDialog()
|
|||
ui.config->Disable();
|
||||
ui.config->SetColor(QColor(0, 0, 0, 0));
|
||||
ui.config->SetRadius(0.f);
|
||||
ui.config->SetMass(0.f);
|
||||
ui.config->SetX(0.f);
|
||||
ui.config->SetY(0.f);
|
||||
}
|
||||
|
||||
void MainWindow::UpdatePlanetPositionInDialog(const QPointF& position)
|
||||
{
|
||||
ui.config->SetX(position.x());
|
||||
ui.config->SetY(position.y());
|
||||
}
|
||||
|
||||
void MainWindow::OnNameChanged(const QString& name)
|
||||
{
|
||||
if (activePlanet != nullptr)
|
||||
|
@ -64,6 +72,12 @@ void MainWindow::OnRadiusChanged(double radius)
|
|||
activePlanet->radius = radius;
|
||||
}
|
||||
|
||||
void MainWindow::OnMassChanged(double mass)
|
||||
{
|
||||
if (activePlanet != nullptr)
|
||||
activePlanet->mass = mass;
|
||||
}
|
||||
|
||||
void MainWindow::OnColourChanged(const QColor& color)
|
||||
{
|
||||
if (activePlanet != nullptr)
|
||||
|
@ -92,4 +106,5 @@ void MainWindow::OnToggle()
|
|||
{
|
||||
isSimulating = !isSimulating;
|
||||
ui.config->SetButtonLabel((isSimulating) ? "Stop Simulation" : "Start Simulation");
|
||||
ui.screen->simulate = isSimulating;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,12 @@ public:
|
|||
void OpenPlanetDialog(Planet* planet);
|
||||
void ClosePlanetDialog();
|
||||
|
||||
void UpdatePlanetPositionInDialog(const QPointF& position);
|
||||
|
||||
public slots:
|
||||
void OnNameChanged(const QString& name);
|
||||
void OnRadiusChanged(double radius);
|
||||
void OnMassChanged(double mass);
|
||||
void OnColourChanged(const QColor& color);
|
||||
void OnXChanged(double x);
|
||||
void OnYChanged(double y);
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
#include "Planet.hpp"
|
||||
|
||||
Planet::Planet(float xPos, float yPos, float radius, QColor color) :
|
||||
position{ xPos, yPos }, radius(radius)
|
||||
#define LENGTH(v) (sqrtf(v.x()*v.x() + v.y()*v.y()))
|
||||
|
||||
QPen Planet::arrowColor = QPen(Qt::white);
|
||||
QLine Planet::arrow = QLine();
|
||||
|
||||
Planet::Planet(uint32_t id, float xPos, float yPos, float radius, QColor color) :
|
||||
position{ xPos, yPos }, radius(radius), id(id)
|
||||
{
|
||||
Initialize(color);
|
||||
}
|
||||
|
||||
Planet::Planet(QPointF pos, float radius, QColor color) :
|
||||
position(pos), radius(radius)
|
||||
Planet::Planet(uint32_t id, QPointF pos, float radius, QColor color) :
|
||||
position(pos), radius(radius), id(id)
|
||||
{
|
||||
Initialize(color);
|
||||
}
|
||||
|
@ -31,11 +36,33 @@ void Planet::SetColor(const QColor& color)
|
|||
selectionColor = QColor::fromHsv((h + 180) % 360, s, v, a);
|
||||
}
|
||||
|
||||
void Planet::Draw(QPainter* painter)
|
||||
void Planet::Update()
|
||||
{
|
||||
painter->setBrush(circle);
|
||||
painter->setPen(outline);
|
||||
painter->drawEllipse(position, radius, radius);
|
||||
velocity += acceleration * (1.f / 60.f);
|
||||
position += velocity * (1.f / 60.f);
|
||||
}
|
||||
|
||||
void Planet::Draw(QPainter & painter)
|
||||
{
|
||||
painter.setBrush(circle);
|
||||
painter.setPen(outline);
|
||||
painter.drawEllipse(position, radius, radius);
|
||||
|
||||
// Draw velocity arrow
|
||||
if (!velocity.isNull())
|
||||
{
|
||||
painter.save();
|
||||
qreal angle = QPointF::dotProduct(velocity, QPointF(1.0f, 0.0f)) / LENGTH(velocity);
|
||||
painter.rotate(angle);
|
||||
|
||||
arrow.setP1(position.toPoint());
|
||||
arrow.setP2((position + velocity).toPoint());
|
||||
|
||||
painter.setPen(arrowColor);
|
||||
painter.drawLine(arrow);
|
||||
|
||||
painter.restore();
|
||||
}
|
||||
}
|
||||
|
||||
bool Planet::IsInside(QPointF point) const
|
||||
|
@ -48,4 +75,6 @@ void Planet::Initialize(QColor color)
|
|||
{
|
||||
name = "Unnamed";
|
||||
SetColor(color);
|
||||
arrowColor.setWidthF(2.0f);
|
||||
acceleration = QPointF(0.f, 0.f);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
class Planet
|
||||
{
|
||||
public:
|
||||
Planet(float xPos, float yPos, float radius, QColor color);
|
||||
Planet(QPointF pos, float radius, QColor color);
|
||||
Planet(uint32_t id, float xPos, float yPos, float radius, QColor color);
|
||||
Planet(uint32_t id, QPointF pos, float radius, QColor color);
|
||||
|
||||
void Resize(float newRadius) { radius = newRadius; }
|
||||
void Select(bool select);
|
||||
|
@ -16,7 +16,8 @@ public:
|
|||
void SetColor(const QColor& color);
|
||||
const QColor& GetColor() { return circle.color(); }
|
||||
|
||||
void Draw(QPainter* painter);
|
||||
void Update();
|
||||
void Draw(QPainter & painter);
|
||||
|
||||
bool IsInside(QPointF point) const;
|
||||
|
||||
|
@ -24,9 +25,14 @@ private:
|
|||
void Initialize(QColor color);
|
||||
|
||||
public:
|
||||
const uint32_t id;
|
||||
|
||||
QPointF position;
|
||||
QPointF velocity;
|
||||
QPointF acceleration;
|
||||
QString name;
|
||||
float radius;
|
||||
float mass;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -34,4 +40,7 @@ private:
|
|||
|
||||
QBrush circle;
|
||||
QPen outline;
|
||||
|
||||
static QPen arrowColor;
|
||||
static QLine arrow;
|
||||
};
|
|
@ -18,6 +18,9 @@ PlanetConfig::PlanetConfig(QWidget* parent) :
|
|||
connect(ui.radius, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
||||
instance, [instance](double d) { instance->OnRadiusChanged(d); });
|
||||
|
||||
connect(ui.mass, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
||||
instance, [instance](double d) { instance->OnMassChanged(d); });
|
||||
|
||||
connect(ui.colour, SIGNAL(returnPressed()),
|
||||
this, SLOT(ColourTBSlot()));
|
||||
|
||||
|
@ -38,6 +41,7 @@ PlanetConfig::PlanetConfig(QWidget* parent) :
|
|||
void PlanetConfig::Disable()
|
||||
{
|
||||
ui.radius->setDisabled(true);
|
||||
ui.mass->setDisabled(true);
|
||||
ui.colour->setDisabled(true);
|
||||
ui.xPos->setDisabled(true);
|
||||
ui.yPos->setDisabled(true);
|
||||
|
@ -47,6 +51,7 @@ void PlanetConfig::Disable()
|
|||
void PlanetConfig::Enable()
|
||||
{
|
||||
ui.radius->setDisabled(false);
|
||||
ui.mass->setDisabled(false);
|
||||
ui.colour->setDisabled(false);
|
||||
ui.xPos->setDisabled(false);
|
||||
ui.yPos->setDisabled(false);
|
||||
|
@ -78,6 +83,11 @@ void PlanetConfig::SetY(double y)
|
|||
ui.yPos->setValue(y);
|
||||
}
|
||||
|
||||
void PlanetConfig::SetMass(double mass)
|
||||
{
|
||||
ui.mass->setValue(mass);
|
||||
}
|
||||
|
||||
void PlanetConfig::SetButtonLabel(const QString& label)
|
||||
{
|
||||
ui.toggle->setText(label);
|
||||
|
|
|
@ -19,6 +19,7 @@ public:
|
|||
void SetColor(const QColor& color);
|
||||
void SetX(double x);
|
||||
void SetY(double y);
|
||||
void SetMass(double mass);
|
||||
|
||||
void SetButtonLabel(const QString& label);
|
||||
|
||||
|
|
99
src/PlanetManager.cpp
Normal file
99
src/PlanetManager.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
#include "PlanetManager.hpp"
|
||||
|
||||
std::map<uint32_t, Planet*> PlanetManager::planets;
|
||||
uint32_t PlanetManager::planetCounter = 0;
|
||||
|
||||
Planet* PlanetManager::AddPlanet(const QPointF& position, float radius, const QColor& color, const QString& name)
|
||||
{
|
||||
Planet* planet = new Planet(planetCounter, position, radius, color);
|
||||
planet->mass = rand() % 100;
|
||||
|
||||
planets.insert(
|
||||
std::make_pair(
|
||||
planetCounter++,
|
||||
planet
|
||||
)
|
||||
);
|
||||
|
||||
return planet;
|
||||
}
|
||||
|
||||
void PlanetManager::RemovePlanet(uint32_t id)
|
||||
{
|
||||
auto it = planets.find(id);
|
||||
if (it == planets.end())
|
||||
return;
|
||||
|
||||
delete it->second;
|
||||
planets.erase(it);
|
||||
}
|
||||
|
||||
Planet* PlanetManager::GetPlanet(uint32_t id)
|
||||
{
|
||||
auto it = planets.find(id);
|
||||
if (it == planets.end())
|
||||
return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
Planet* PlanetManager::GetLastPlanet()
|
||||
{
|
||||
return planets.rbegin()->second;
|
||||
}
|
||||
|
||||
void PlanetManager::RemoveLastPlanet()
|
||||
{
|
||||
auto it = planets.cbegin();
|
||||
delete it->second;
|
||||
|
||||
planets.erase(it);
|
||||
}
|
||||
|
||||
Planet* PlanetManager::IsInPlanet(const QPointF& position)
|
||||
{
|
||||
for (auto it : planets)
|
||||
if (it.second->IsInside(position))
|
||||
return it.second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PlanetManager::Update()
|
||||
{
|
||||
for (auto planet : planets)
|
||||
planet.second->Update();
|
||||
|
||||
// Collision detection && Gravitation
|
||||
for (auto planet : planets)
|
||||
{
|
||||
planet.second->acceleration = QPointF(0.f, 0.f);
|
||||
for (auto otherPlanet : planets)
|
||||
{
|
||||
if (planet == otherPlanet)
|
||||
continue;
|
||||
|
||||
QPointF distance = planet.second->position - otherPlanet.second->position;
|
||||
float radiusSum = (planet.second->radius + otherPlanet.second->radius);
|
||||
float dist = distance.x() * distance.x() + distance.y() * distance.y();
|
||||
if (dist < radiusSum * radiusSum)
|
||||
{
|
||||
// Collision
|
||||
Planet* lighter = ((planet.second->mass > otherPlanet.second->mass) ? otherPlanet.second : planet.second);
|
||||
lighter->position += (radiusSum - sqrt(dist) + 1) * distance / sqrt(dist);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Gravitation
|
||||
planet.second->acceleration -= 1000000 * (planet.second->mass * otherPlanet.second->mass) / pow(dist, 3.f / 2.f) * distance / sqrt(dist);
|
||||
}
|
||||
}
|
||||
|
||||
planet.second->acceleration /= planet.second->mass;
|
||||
}
|
||||
}
|
||||
|
||||
void PlanetManager::Render(QPainter& painter)
|
||||
{
|
||||
for (auto it : planets)
|
||||
it.second->Draw(painter);
|
||||
}
|
30
src/PlanetManager.hpp
Normal file
30
src/PlanetManager.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <QPointF>
|
||||
|
||||
#include "Planet.hpp"
|
||||
|
||||
class PlanetManager
|
||||
{
|
||||
public:
|
||||
PlanetManager() = delete;
|
||||
|
||||
static Planet* AddPlanet(const QPointF& position, float radius, const QColor& color,
|
||||
const QString& name = "Unnamed");
|
||||
static void RemovePlanet(uint32_t id);
|
||||
|
||||
static Planet* GetPlanet(uint32_t id);
|
||||
static Planet* GetLastPlanet();
|
||||
static void RemoveLastPlanet();
|
||||
|
||||
static Planet* IsInPlanet(const QPointF& position);
|
||||
|
||||
static void Update();
|
||||
static void Render(QPainter& painter);
|
||||
|
||||
private:
|
||||
static std::map<uint32_t, Planet*> planets;
|
||||
static uint32_t planetCounter;
|
||||
};
|
|
@ -9,6 +9,7 @@
|
|||
#include <QtMath>
|
||||
|
||||
#include "MainWindow.hpp"
|
||||
#include "PlanetManager.hpp"
|
||||
|
||||
#define BIND_LMB(f) (lmbAction = std::bind(&Screen::f, this, std::placeholders::_1))
|
||||
|
||||
|
@ -32,32 +33,30 @@ Screen::Screen(QWidget* parent) :
|
|||
|
||||
void Screen::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
if (mouseDown && hovered == nullptr)
|
||||
if (mouseDown && selected == nullptr && hovered == nullptr)
|
||||
{
|
||||
Planet* planet = planets.back();
|
||||
Planet* planet = PlanetManager::GetLastPlanet();
|
||||
QPointF distance = event->localPos() - mouseClickPos;
|
||||
planet->Resize(qSqrt(distance.x()*distance.x() + distance.y() *distance.y()));
|
||||
}
|
||||
else if (mouseDown && selected != nullptr)
|
||||
{
|
||||
selected->velocity = event->localPos() - selected->position;
|
||||
}
|
||||
else
|
||||
{
|
||||
hovered = nullptr;
|
||||
for (unsigned i = planets.size(); i-- > 0; )
|
||||
{
|
||||
if (planets[i]->IsInside(event->localPos()))
|
||||
{
|
||||
setCursor(Qt::PointingHandCursor);
|
||||
BIND_LMB(lmb_SelectPlanet);
|
||||
hovered = planets[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hovered = PlanetManager::IsInPlanet(event->localPos());
|
||||
if (hovered == nullptr)
|
||||
{
|
||||
setCursor(Qt::ArrowCursor);
|
||||
if(selected == nullptr)
|
||||
BIND_LMB(lmb_MakePlanet);
|
||||
}
|
||||
else
|
||||
{
|
||||
BIND_LMB(lmb_SelectPlanet);
|
||||
setCursor(Qt::PointingHandCursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +71,7 @@ void Screen::mousePressEvent(QMouseEvent* event)
|
|||
{
|
||||
if (mouseDown)
|
||||
{
|
||||
planets.pop_back();
|
||||
PlanetManager::RemoveLastPlanet();
|
||||
mouseDown = false;
|
||||
}
|
||||
}
|
||||
|
@ -86,17 +85,9 @@ void Screen::mouseReleaseEvent(QMouseEvent* event)
|
|||
|
||||
void Screen::DeletePlanet(Planet* planet)
|
||||
{
|
||||
for (std::vector<Planet*>::iterator it = planets.begin(); it != planets.end(); it++)
|
||||
{
|
||||
if ((*it) == planet)
|
||||
{
|
||||
planets.erase(it);
|
||||
delete planet;
|
||||
hovered = nullptr;
|
||||
selected = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PlanetManager::RemovePlanet(planet->id);
|
||||
hovered = nullptr;
|
||||
selected = nullptr;
|
||||
}
|
||||
|
||||
void Screen::Render()
|
||||
|
@ -106,9 +97,12 @@ void Screen::Render()
|
|||
|
||||
void Screen::lmb_MakePlanet(QMouseEvent* event)
|
||||
{
|
||||
planets.push_back(new Planet(event->localPos(), 0,
|
||||
QColor(rand() % 256, rand() % 256, rand() % 256)
|
||||
));
|
||||
Planet* newPlanet = PlanetManager::AddPlanet(event->localPos(), 0,
|
||||
QColor(rand() % 200, rand() % 200, rand() % 200)
|
||||
);
|
||||
|
||||
newPlanet->velocity = QPointF(rand() % 400 - 200, rand() % 400 - 200);
|
||||
|
||||
mouseClickPos = event->localPos();
|
||||
mouseDown = true;
|
||||
}
|
||||
|
@ -117,12 +111,19 @@ void Screen::lmb_SelectPlanet(QMouseEvent* event)
|
|||
{
|
||||
if (hovered != nullptr)
|
||||
{
|
||||
if (selected != nullptr)
|
||||
selected->Select(false);
|
||||
if (selected != hovered)
|
||||
{
|
||||
if (selected != nullptr)
|
||||
selected->Select(false);
|
||||
|
||||
hovered->Select(true);
|
||||
selected = hovered;
|
||||
MainWindow::Instance()->OpenPlanetDialog(selected);
|
||||
hovered->Select(true);
|
||||
selected = hovered;
|
||||
MainWindow::Instance()->OpenPlanetDialog(selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseDown = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -136,12 +137,20 @@ void Screen::lmb_SelectPlanet(QMouseEvent* event)
|
|||
|
||||
void Screen::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
if (simulate)
|
||||
{
|
||||
PlanetManager::Update();
|
||||
if (selected != nullptr)
|
||||
{
|
||||
MainWindow::Instance()->UpdatePlanetPositionInDialog(selected->position);
|
||||
}
|
||||
}
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(this);
|
||||
painter.fillRect(rect(), background);
|
||||
|
||||
for (Planet* planet : planets)
|
||||
planet->Draw(&painter);
|
||||
PlanetManager::Render(painter);
|
||||
|
||||
painter.end();
|
||||
}
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
#include <QOpenGLWidget>
|
||||
|
||||
#include "Planet.hpp"
|
||||
|
||||
class Planet;
|
||||
class MainWindow;
|
||||
|
||||
class Screen : public QOpenGLWidget
|
||||
|
@ -30,6 +30,9 @@ private:
|
|||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
public:
|
||||
bool simulate = false;
|
||||
|
||||
private:
|
||||
bool mouseDown = false;
|
||||
|
||||
|
@ -40,7 +43,6 @@ private:
|
|||
QBrush background;
|
||||
QTimer* renderTimer;
|
||||
|
||||
std::vector<Planet*> planets;
|
||||
Planet* selected = nullptr;
|
||||
Planet* hovered = nullptr;
|
||||
};
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>308</width>
|
||||
<height>380</height>
|
||||
<height>454</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -82,6 +82,42 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Courier New</family>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Mass</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="mass">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="stepType">
|
||||
<enum>QAbstractSpinBox::AdaptiveDecimalStepType</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
|
|
Loading…
Reference in a new issue