Skip to content

Instantly share code, notes, and snippets.

@sknjpn
Created June 26, 2017 13:40
Show Gist options
  • Save sknjpn/b2a9b9b6a9df0523bddee41b94cf9f91 to your computer and use it in GitHub Desktop.
Save sknjpn/b2a9b9b6a9df0523bddee41b94cf9f91 to your computer and use it in GitHub Desktop.
# 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