Skip to content

Instantly share code, notes, and snippets.

@G4rryS1ngh
Created May 1, 2019 01:30
Show Gist options
  • Select an option

  • Save G4rryS1ngh/e5e20d5b0830859dcb63455710accce0 to your computer and use it in GitHub Desktop.

Select an option

Save G4rryS1ngh/e5e20d5b0830859dcb63455710accce0 to your computer and use it in GitHub Desktop.
こくばん(*'▽')
# include <Siv3D.hpp> // OpenSiv3D v0.3.2
Image CreateNoiseImage(double _density)
{
Grid<double> grid(Window::Size());
const PerlinNoise noise(Random(0, 100000));
for (auto p : step(grid.size()))
{
grid[p] = noise.octaveNoise0_1(p / static_cast<double>(grid.width()) * _density, 2);
}
return Image(grid.size(), Arg::generator = [&](Point p) { return Color(U"#233825").setA((uint32)(255 * grid[p])); });
}
Optional<Polygon> CalculateRegion(Array<Vec2> _trail, const double _thres, const double _finess)
{
// 交差しているか、端点が交差しそうなら領域化する
Optional<Array<Vec2>> outer;
// 交差判定
if (_trail.count() >= 4)
{
for (size_t j = 0; j <= _trail.count() - 4; j++)
{
size_t cnt = _trail.count() - j;
const Line tail(_trail[cnt - 1], _trail[cnt - 2]);
const Array<Vec2> remaining(_trail.take(cnt - 2));
for (size_t i : step(remaining.count() - 2))
{
if (const auto p = Line(remaining[i], remaining[i + 1]).intersectsAt(tail))
{
outer = _trail.take(cnt - 1).dropped(i + 1);
outer->push_back(p.value());
break;
}
}
if (outer)
break;
}
}
// 交差していなければ
const size_t ignore = (uint32)(_thres / _finess) + 1;
if (!outer && _trail.count() > ignore)
{
Optional<size_t> near_pos_index;
// 終点から近い点があるか探す
for (size_t i = 0; i < _trail.count() - ignore; i++)
if (_trail[i].distanceFrom(_trail.back()) <= _thres)
near_pos_index = i;
// 近い点があれば
if (near_pos_index)
{
outer = _trail.dropped(*near_pos_index + 1);
}
else
{
// 始点から近い点があるか探す
for (size_t i = _trail.count() - 1; i >= ignore; i--)
if (_trail[i].distanceFrom(_trail.front()) <= _thres)
near_pos_index = i;
// 近い点があれば
if (near_pos_index)
outer = _trail.take(*near_pos_index);
}
}
Optional<Polygon> ret;
if (outer)
{
Array<Vec2> tmp = *outer;
// 反時計回りなら逆順にしたものをPolygonに渡す
// [ref] https://www.hiramine.com/programming/graphics/2d_polygonloopwise.html
const size_t cnt = tmp.count();
size_t lm = 0; // left most
for (const auto [i, v] : Indexed(tmp))
if (v.x < tmp[lm].x || (v.x == tmp[lm].x && v.y < tmp[lm].y))
lm = i;
const Vec2 a = tmp[(lm - 1 + cnt) % cnt], b = tmp[lm], c = tmp[(lm + 1) % cnt];
if ((b - a).cross(c - b) < 0)
tmp.reverse();
ret = Polygon(tmp);
}
return ret;
}
void Main()
{
const Color color_back(U"#233825");
Graphics::SetBackground(color_back);
Texture kasure(CreateNoiseImage(100.0));
Array<Vec2> trail;
Array<Polygon> regions;
Array<Polygon> inners;
Array<LineString> lines;
while (System::Update())
{
const double finess = 3.0;
if (MouseL.down())
{
trail << Cursor::PosF();
}
else if (MouseL.pressed() && !trail.isEmpty())
{
if (trail.back().distanceFrom(Cursor::PosF()) > finess)
{
trail << Cursor::PosF() + RandomVec2(0.01);
}
}
if (MouseL.up() && !trail.isEmpty())
{
const double threshold = 30.0;
if (const auto r = CalculateRegion(trail, threshold, finess))
{
regions << *r;
inners << r->calculateBuffer(-8.0);
// 既存のPolygonと連結させる
for (int i = regions.count() - 2; i >= 0; i--)
{
Polygon tmp = regions.back();
if (tmp.append(regions.at(i)))
{
regions.remove_at(i);
regions.pop_back();
regions << Polygon(tmp.outer());
inners.remove_at(i);
inners.pop_back();
inners << regions.back().calculateBuffer(-8.0);
}
}
}
else
lines << LineString(trail);
trail.clear();
}
if (KeySpace.down())
{
lines.clear();
regions.clear();
inners.clear();
}
inners.each([](const auto & p) { p.draw(); });
regions.each([](const auto & p) { p.drawFrame(6.0); });
lines.each([](const auto & ls) { ls.draw(LineStyle::RoundCap, 10.0); });
LineString(trail).draw(LineStyle::RoundCap, 10.0);
kasure.draw();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment