Skip to content

Instantly share code, notes, and snippets.

@sknjpn
Created July 9, 2017 12:21
Show Gist options
  • Save sknjpn/27c0ec14726650368b4bba84cc010777 to your computer and use it in GitHub Desktop.
Save sknjpn/27c0ec14726650368b4bba84cc010777 to your computer and use it in GitHub Desktop.
# include <Siv3D.hpp> // OpenSiv3D v0.1.5
struct Glass
{
Glass(const Vec2& _pos, const double& _n, const double& _r)
: pos(_pos), n(_n), r(_r) {}
Vec2 pos;
double n;
double r;
Circle circle() const { return Circle(pos, r); }
};
struct Lazer
{
Lazer(const Vec2& _pos, const Vec2& _ang)
: pos(_pos), ang(_ang) {}
Vec2 pos;
Vec2 ang;
};
void Main()
{
Graphics::SetBackground(Color(11, 22, 33));
Window::SetTitle(L"ガラス球の光学特性");
Window::Resize(1280, 720);
const Font font(24);
Array<Glass> glass;
Array<Lazer> lazer;
double n = 1;
Mat3x2 transform(Mat3x2::Identity());
for (int i = 0; i < 100; i++)
glass.emplace_back(Vec2(0, i * 33), 1.5, 16);
for (int x = 0; x < 10; x++)
for (int y = 0; y < 10; y++)
glass.emplace_back(Vec2(0, -700) + Vec2(x*1.73*0.5, y + (x % 2)*0.5) * 64, 1.5, 31);
for (int i = 0; i < 10; i++)
lazer.emplace_back(Vec2(64, 0 + i * 8), Vec2(1.0, 0.0));
for (int i = 0; i < 30; i++)
lazer.emplace_back(Vec2(64, 512 + i * 4), Vec2(1.0, 0.0));
for (int i = 0; i < 100; i++)
lazer.emplace_back(Vec2(64, 1024 + i * 8), Vec2(1.0, 0.0));
Glass* selectedGlass = NULL;
Lazer* rSelectedLazer = NULL;
Lazer* lSelectedLazer = NULL;
while (System::Update())
{
if (!KeyControl.pressed() && !KeyShift.pressed()) transform = transform.scale((10 - Mouse::Wheel()) / 10.0, Cursor::PosF());
else
{
const Transformer2D t1(transform, true);
for (auto& g : glass)
{
if (g.circle().mouseOver())
{
if (KeyShift.pressed()) g.n = Max(1.0, Min(5.0, g.n + Mouse::Wheel() / 10.0));
else g.r *= (10 - Mouse::Wheel()) / 10.0;
}
}
}
{
const Transformer2D t1(transform, true);
if (MouseL.up()) selectedGlass = NULL;
if (selectedGlass != NULL) selectedGlass->pos = Cursor::PosF();
if (MouseL.up()) lSelectedLazer = NULL;
if (lSelectedLazer != NULL) lSelectedLazer->pos = Cursor::PosF();
if (MouseR.up()) rSelectedLazer = NULL;
if (rSelectedLazer != NULL && !(Cursor::PosF() - rSelectedLazer->pos).isZero()) rSelectedLazer->ang = (Cursor::PosF() - rSelectedLazer->pos).normalized();
}
for (;;)
{
bool flag = false;
for (auto& g1 : glass)
{
for (auto& g2 : glass)
{
if (&g1 != &g2 && g1.circle().intersects(g2.circle()))
{
if (&g1 != selectedGlass) g1.pos += (g1.pos - g2.pos).normalized();
if (&g2 != selectedGlass) g2.pos += (g2.pos - g1.pos).normalized();
flag = true;
}
}
}
if (!flag) break;
}
for (auto& l : lazer)
{
const Transformer2D t1(transform, true);
double len = 4096;
Vec2 pos = l.pos;
Vec2 ang = l.ang;
Glass* nowGlass = NULL;
for (auto& g : glass) if (g.circle().intersects(l.pos)) nowGlass = &g;
for (;;)
{
Vec2 nearPos;
Glass* nearGlass = NULL;
const auto ray = Line(pos, pos + ang * len);
for (auto& g : glass)
{
auto list = g.circle().intersectsAt(ray);
if (list)
{
for (auto& i : list.value())
{
if (!(i - ray.begin).isZero() && (nearGlass == NULL || (i - ray.begin).length() < (nearPos - ray.begin).length()))
{
nearGlass = &g;
nearPos = i;
}
}
}
}
if (nowGlass == NULL)
{
if (nearGlass != NULL)
{
Circle(nearPos, 4).draw(ColorF(Palette::Red, 1.0));
Line(pos, nearPos).draw(2, ColorF(Palette::Red, 1.0));
auto a = n / nearGlass->n* (nearGlass->pos - nearPos).normalized().cross(ang);
ang = Vec2::Right().rotated(atan2(nearGlass->pos.y - nearPos.y, nearGlass->pos.x - nearPos.x) + asin(a));
len -= (nearPos - pos).length();
pos = nearPos + ang*0.01;
nowGlass = nearGlass;
}
else
{
ray.draw(2, ColorF(Palette::Red, 1.0));
break;
}
}
else
{
if (nearGlass != NULL)
{
Circle(nearPos, 4).draw(ColorF(Palette::Red, 1.0));
Line(pos, nearPos).draw(2, ColorF(Palette::Red, 1.0));
auto a = nowGlass->n / n* (nearGlass->pos - nearPos).normalized().cross(ang);
if (abs(a) <= 1)
{
ang = Vec2::Right().rotated(atan2(nearPos.y - nearGlass->pos.y, nearPos.x - nearGlass->pos.x) - asin(a));
nowGlass = NULL;
}
else
{
ang.rotate(-(atan2(ang.y, ang.x) - atan2(nearPos.y - nearGlass->pos.y, nearPos.x - nearGlass->pos.x)) * 2);
ang = -ang;
}
len -= (nearPos - pos).length();
pos = nearPos + ang*0.01;
}
else
{
ray.draw(2, ColorF(Palette::Red, 1.0));
break;
}
}
}
}
for (auto& g : glass)
{
const Transformer2D t1(transform, true);
g.circle().draw(ColorF(Palette::Skyblue, (g.n - 1) / 8.0)).drawFrame(2.0, ColorF(Palette::Skyblue, g.circle().mouseOver() ? 1.0 : 0.5));
font(g.n).drawAt(g.pos);
if (g.circle().leftClicked()) selectedGlass = &g;
}
for (auto& l : lazer)
{
const Transformer2D t(transform, true);
Circle(l.pos + l.ang * 8, 4).draw(ColorF(Palette::Red, 1.0));
auto r = Rect(-8, -3, 16, 6).rotated(atan2(l.ang.y, l.ang.x)).movedBy(l.pos);
r.draw(Palette::White).drawFrame(1, 0, Palette::Gray);
if (r.rightClicked()) rSelectedLazer = &l;
if (r.leftClicked() && selectedGlass == NULL) lSelectedLazer = &l;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment