Created
June 26, 2017 13:40
-
-
Save sknjpn/b2a9b9b6a9df0523bddee41b94cf9f91 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# include <Siv3D.hpp> //OpenSiv3D v0.1.5 | |
# include <HamFramework.hpp> | |
struct Node | |
{ | |
Vec2 pos; | |
double mass; | |
bool isFixed; | |
Vec2 v; | |
Array<Node*> spring; | |
Vec2 f; | |
}; | |
void Main() | |
{ | |
Window::SetTitle(L"SpringSimulator"); | |
Window::Resize(1280, 720); | |
Window::SetBaseSize(Window::Size()); | |
Array<Node> nodes; | |
const double interval = 32.0; | |
const double naturalLength = 24.0; | |
const double springConstant = 0.01; | |
for (double x = 0; x < Window::Size().x; x += interval*1.73) | |
for (double y = 0; y < Window::Size().y; y += interval) | |
nodes.push_back({ Vec2(x,y), 10.0, true }); | |
for (double x = interval*1.73 / 2.0; x < Window::Size().x; x += interval*1.73) | |
for (double y = interval / 2.0; y < Window::Size().y; y += interval) | |
nodes.push_back({ Vec2(x,y), 10.0, true }); | |
nodes.push_back({ Vec2(-100,-100), 10.0, true }); | |
nodes.push_back({ Vec2(-124,-100), 10.0, false }); | |
nodes.push_back({ Vec2(-148,-100), 10.0, true }); | |
nodes.push_back({ Vec2(-80,-160), 10.0, false }); | |
nodes.push_back({ Vec2(-60,-160), 10.0, true }); | |
for (auto& n1 : nodes) | |
for (auto& n2 : nodes) | |
if ((n1.pos - n2.pos).length() <= interval && &n1 != &n2) n1.spring.push_back(&n2); | |
for (auto& n : nodes) if (n.spring.size() == 6) n.isFixed = false; | |
Node* selectedNode = NULL; | |
Camera2D camera; | |
Array<double> forceLog; | |
Array<double> speedLog; | |
Node* observedNode = &nodes[0]; | |
Font font(14); | |
while (System::Update()) | |
{ | |
//運動の計算 | |
for (auto& n : nodes) n.f = Vec2::Zero(); | |
for (auto& n : nodes) | |
{ | |
for (auto& s : n.spring) | |
{ | |
const double length = (s->pos - n.pos).length(); | |
if (length != 0) n.f -= springConstant*(s->pos - n.pos).normalized()*(naturalLength - length); | |
} | |
} | |
for (auto& n : nodes) | |
{ | |
if (!n.isFixed) | |
{ | |
n.v += n.f / n.mass; | |
n.pos += n.v; | |
} | |
} | |
camera.update(); | |
{ | |
auto t = camera.createTransformer(); | |
//マウス操作 | |
if (!MouseL.pressed()) selectedNode = NULL; | |
if (MouseL.down()) | |
{ | |
for (auto& n : nodes) if (Circle(n.pos, 4).mouseOver()) selectedNode = &n; | |
observedNode = selectedNode; | |
forceLog.clear(); | |
speedLog.clear(); | |
} | |
if (selectedNode != NULL) | |
{ | |
selectedNode->pos = Cursor::PosF(); | |
selectedNode->v = Vec2::Zero(); | |
} | |
if (observedNode != NULL) | |
{ | |
forceLog.push_front(observedNode->f.length()); | |
if (forceLog.size() > 512) forceLog.pop_back(); | |
speedLog.push_front(observedNode->v.length()); | |
if (speedLog.size() > 512) speedLog.pop_back(); | |
} | |
//バネの描画 | |
for (auto& n : nodes) | |
{ | |
for (auto& s : n.spring) | |
{ | |
const double x = abs((n.pos - s->pos).length() - naturalLength)*0.05; | |
Line(n.pos, s->pos).draw(Palette::White.lerp(Palette::Red, Min(1.0, x))); | |
} | |
} | |
//おもりの描画 | |
for (auto& n : nodes) | |
{ | |
if (selectedNode != NULL && &n == selectedNode) Circle(n.pos, 4).draw(Palette::Pink); | |
else if (observedNode != NULL && &n == observedNode) Circle(n.pos, 4).draw(Palette::Lightgreen); | |
else if (Circle(n.pos, 4).mouseOver()) Circle(n.pos, 4).draw(Palette::Red); | |
else Circle(n.pos, 4).draw(n.isFixed ? Palette::Orange : Palette::White); | |
if (observedNode != NULL && &n == observedNode) Circle(n.pos, 6).drawFrame(2, Palette::Lightgreen); | |
} | |
} | |
camera.draw(); | |
//グラフの描画 | |
Rect(0, 0, 512, 160).draw(Palette::Black).drawFrame(2, Palette::Skyblue); | |
double flMax = 0.01; | |
for (auto& fl : forceLog) flMax = Max(flMax, fl); | |
if (forceLog.size() >= 2) | |
{ | |
for (int i = 0; i < forceLog.size() - 1; i++) | |
Line(i, 130.0 - 128.0*forceLog[i] / flMax, i + 1, 128.0 - 128.0*forceLog[i + 1] / flMax).movedBy(0, 32).draw(2.0, Palette::Red); | |
} | |
double slMax = 0.01; | |
for (auto& sl : speedLog) slMax = Max(slMax, sl); | |
if (speedLog.size() >= 2) | |
{ | |
for (int i = 0; i < speedLog.size() - 1; i++) | |
Line(i, 130.0 - 128.0*speedLog[i] / slMax, i + 1, 128.0 - 128.0*speedLog[i + 1] / slMax).movedBy(0, 32).draw(2.0, Palette::Blue); | |
} | |
font(L"ForceMax ", flMax).draw(Vec2(0, 0), Palette::Red); | |
font(L"SpeedMax ", slMax).draw(Vec2(0, 16), Palette::Blue); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment