Skip to content

Instantly share code, notes, and snippets.

@sknjpn
Created July 9, 2017 14:13
Show Gist options
  • Save sknjpn/5e9d7053c171b3bae673c71f0cdfbdf4 to your computer and use it in GitHub Desktop.
Save sknjpn/5e9d7053c171b3bae673c71f0cdfbdf4 to your computer and use it in GitHub Desktop.
# include <Siv3D.hpp>
# include <HamFramework.hpp>
struct Compass
{
Compass(const Vec2& _pos) : pos(_pos), ang(Vec2::Up), v(0.0) {}
Vec2 pos;
Vec2 ang;
double v;
};
struct Monopole
{
Monopole(const Vec2& _pos, const bool& _isNPole) : pos(_pos), isNPole(_isNPole), strength(1.0) {}
bool isNPole; //true:N極 false:S極
Vec2 pos;
double strength;
};
void Main()
{
Camera2D camera;
Window::SetTitle(L"CompassSimulator");
Window::Resize(1280, 720);
Array<Compass> compass;
Array<Monopole> monopole;
Monopole* selectedMonopole = NULL;
monopole.push_back(Monopole(Vec2(160, 240), true));
monopole.push_back(Monopole(Vec2(480, 240), false));
bool f = false;
for (double x = -2000.0; x < 2000; x += 32 * 1.73)
{
for (double y = -2000.0; y < 2000.0; y += 64)
{
if (f) compass.push_back(Compass(Vec2(x, y)));
else compass.push_back(Compass(Vec2(x, y + 32)));
}
f = !f;
}
const Font mFont(32, Typeface::Black);
Window::SetStyle(WindowStyle::Sizeable);
while (System::Update())
{
Window::SetBaseSize(Window::Size());
for (auto& c : compass)
{
double force = 0.0; //力のモーメント
for (auto& m : monopole)
{
double len = (m.pos - c.pos).length();
if (len == 0.0) continue;
if (m.isNPole)
force -= c.ang.cross(m.pos - c.pos) / len / (len*len + 32.0*32.0)*1000.0;
else
force += c.ang.cross(m.pos - c.pos) / len / (len*len + 32.0*32.0)*1000.0;
}
c.v += force;
c.v *= 0.98;
c.ang.rotate(c.v);
}
camera.update();
{
auto t1 = camera.createTransformer();
for (auto& c : compass)
{
const double theta = Atan2(c.ang.y, c.ang.x);
//Circle(c.pos, 28).draw(Palette::Lightsteelblue).drawFrame(1.0, 1.0, Palette::Gray);
Triangle(0, -4, 24, 0, 0, 4).rotatedAt(Vec2::Zero, theta).movedBy(c.pos).draw(Palette::Red);
Triangle(0, -4, -24, 0, 0, 4).rotatedAt(Vec2::Zero, theta).movedBy(c.pos).draw(Palette::White);
Circle(c.pos, 3).draw(Palette::Gray);
}
for (auto& m : monopole)
{
double accuracy = 4.0;
for (int i = 0; i < 32; i++)
{
Vec2 p = m.pos.movedBy(Vec2::Right.rotated(i*Pi / 16.0));
for (int j = 0; j < 500; j++)
{
bool breakFlag = false;
Vec2 v(0, 0);
for (auto& n : monopole)
{
double len = (n.pos - p).length();
if (j > 1 && len <= 1.0) { breakFlag = true; break; }
if (n.isNPole) v -= (n.pos - p) / (len*(len*len + 32.0*32.0));
else v += (n.pos - p) / (len*(len*len + 32.0*32.0));
}
const double width = (Log2(v.length()) + 20.0) / 4.0;
const Color color = Palette::White;
if (width < 0) break;
if (j % 20 == 0) Triangle(-width*3, -width*3, width*3, 0, -width*3, width*3).rotated(Atan2(v.y, v.x)).movedBy(p).draw(color);
if (m.isNPole)
{
Line(p, p + v.normalized()*accuracy).draw(width, color);
p += v.normalized()*accuracy;
}
else
{
Line(p, p - v.normalized()*accuracy).draw(width, color);
p -= v.normalized()*accuracy;
}
if (breakFlag) break;
}
}
}
for (auto& m : monopole)
{
if (m.isNPole)
{
Circle(m.pos, 24).draw(Palette::Red);
mFont(L"N").drawCenter(m.pos, Palette::Darkred);
}
else
{
Circle(m.pos, 24).draw(Palette::Blue);
mFont(L"S").drawCenter(m.pos, Palette::Darkblue);
}
}
if (Input::MouseL.released && selectedMonopole != NULL)
{
Monopole& m = *selectedMonopole;
if (Graphics2D::GetTransform().transform(m.pos).y > Window::Size().y - 64)
{
Erase_if(monopole, [=](Monopole& t) { return &t == selectedMonopole; });
}
selectedMonopole = NULL;
}
if (Input::MouseL.clicked)
{
if (Graphics2D::GetTransform().inverse().transform(Vec2(0, Window::Size().y - 64)).y < Mouse::PosF().y)
{
const Vec2 p1(48, Window::Size().y - 32);
const Vec2 p2(112, Window::Size().y - 32);
if (p1.distanceFrom(Graphics2D::GetTransform().transform(Mouse::PosF())) < 24)
{
monopole.push_back(Monopole(Mouse::PosF(), true));
selectedMonopole = &monopole.back();
}
if (p2.distanceFrom(Graphics2D::GetTransform().transform(Mouse::PosF())) < 24)
{
monopole.push_back(Monopole(Mouse::PosF(), false));
selectedMonopole = &monopole.back();
}
}
else
{
for (auto& m : monopole)
{
if (m.pos.distanceFrom(Mouse::PosF()) < 24.0)
{
selectedMonopole = &m;
}
}
}
}
if (Input::MouseL.pressed && selectedMonopole != NULL)
{
Monopole& m = *selectedMonopole;
m.pos = Mouse::PosF();
}
}
Rect(0, Window::Size().y - 64, Window::Size().x, 64).draw(Palette::Lightgrey).drawFrame(4, 0, Palette::Gray);
const Vec2 p1(48, Window::Size().y - 32);
const Vec2 p2(112, Window::Size().y - 32);
Circle(p1, 24).draw(Palette::Red);
mFont(L"N").drawCenter(p1, Palette::Darkred);
Circle(p2, 24).draw(Palette::Blue);
mFont(L"S").drawCenter(p2, Palette::Darkblue);
{
auto t1 = camera.createTransformer();
if (Input::MouseL.pressed && selectedMonopole != NULL)
{
Monopole& m = *selectedMonopole;
Circle(m.pos, 32).draw(Palette::White);
if (m.isNPole)
{
Circle(m.pos, 24).draw(Palette::Red);
mFont(L"N").drawCenter(m.pos, Palette::Darkred);
}
else
{
Circle(m.pos, 24).draw(Palette::Blue);
mFont(L"S").drawCenter(m.pos, Palette::Darkblue);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment