#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace psemek; struct triangulation_app : app::app { triangulation_app() : app("Triangulation example", 16) { std::ifstream in(PSEMEK_EXAMPLES_DIR "/turkey"); while (true) { geom::point p; in >> p[0] >> p[1]; if (!in) break; points_.push_back(p); } std::reverse(points_.begin(), points_.end()); for (std::size_t i = 0; i < points_.size();) { std::size_t j = (i + 1) % points_.size(); if (points_[i] == points_[j]) { points_.erase(points_.begin() + i); } else { ++i; } } log::info() << points_.size() << " input points"; bbox_ = cg::bbox(points_.begin(), points_.end()); camera_center_ = bbox_.center(); camera_size_ = std::max(bbox_[0].length(), bbox_[1].length()) * 1.125f; camera_size_tgt_ = camera_size_; { prof::profiler prof("triangulate"); indices_ = cg::ear_clipping(points_.begin(), points_.end()); } prof::dump(); log::info() << (indices_.size() / 3) << " triangles"; } void on_left_button_down() override { app::on_left_button_down(); if (mouse()) drag_start_ = mouse(); } void on_left_button_up() override { app::on_left_button_up(); drag_start_ = std::nullopt; } void on_mouse_wheel(int delta) override { camera_size_tgt_ *= std::pow(0.8f, delta); } void update() override { float const dt = clock_.restart().count(); if (drag_start_ && mouse()) { auto delta = *mouse() - *drag_start_; delta[1] *= -1; camera_center_ -= geom::cast(delta) * camera_size_ / (1.f * height()); drag_start_ = mouse(); } camera_size_ += (camera_size_tgt_ - camera_size_) * (1.f - std::exp(- 20.f * dt)); } void present() override { gl::ClearColor(1.f, 1.f, 1.f, 1.f); gl::Clear(gl::COLOR_BUFFER_BIT); float aspect_ratio = (width() * 1.f) / height(); geom::box view_bbox = geom::expand(geom::box::singleton(camera_center_), geom::vector{camera_size_ * 0.5f * aspect_ratio, camera_size_ * 0.5f}); float line_width = 4.f * camera_size_ / height(); auto edge = [this, line_width](auto i0, auto i1, gfx::color_rgba const & color) { painter_.line(points_[i0], points_[i1], line_width, color, false); }; random::generator rng; for (std::size_t i = 0; i < indices_.size(); i += 3) { // edge(indices_[i + 0], indices_[i + 1], gfx::blue); // edge(indices_[i + 1], indices_[i + 2], gfx::blue); // edge(indices_[i + 2], indices_[i + 0], gfx::blue); gfx::color_rgba c; c[0] = random::uniform(rng, {0, 255}); c[1] = random::uniform(rng, {0, 255}); c[2] = random::uniform(rng, {0, 255}); c[3] = 255; painter_.triangle(points_[indices_[i + 0]], points_[indices_[i + 1]], points_[indices_[i + 2]], c); } for (std::size_t i = 0; i < points_.size(); ++i) { edge(i, (i + 1) % points_.size(), gfx::black); } auto camera_transform = geom::orthographic_camera{view_bbox}.transform(); painter_.render(camera_transform); if(false) for (std::size_t i = 0; i < points_.size(); ++i) // for (std::size_t i : {2993, 2087, 2089, 2088}) { gfx::painter::text_options opts; opts.c = {0, 0, 0, 255}; opts.x = gfx::painter::x_align::left; opts.y = gfx::painter::y_align::bottom; opts.scale = 2.f; auto p = geom::swizzle<0, 1>(geom::as_point(camera_transform * geom::homogeneous(geom::swizzle<0, 1, -1>(points_[i])))); p[0] = std::round((p[0] * 0.5f + 0.5f) * width()); p[1] = std::round((0.5f - p[1] * 0.5f) * height()); painter_.text(p, util::to_string(i), opts); } painter_.render(geom::window_camera{width(), height()}.transform()); } private: std::vector> points_; std::vector indices_; geom::box bbox_; geom::point camera_center_; float camera_size_; float camera_size_tgt_; std::optional> drag_start_; gfx::painter painter_; util::clock, std::chrono::high_resolution_clock> clock_; }; int main() { return app::main(); }