Created
May 1, 2019 01:30
-
-
Save G4rryS1ngh/e5e20d5b0830859dcb63455710accce0 to your computer and use it in GitHub Desktop.
こくばん(*'▽')
This file contains hidden or 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.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