From 51e6f8ad9cfcfd1801e73660d728e95a0248d166 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sat, 17 Sep 2022 00:40:00 +0300 Subject: [PATCH] Rewrite ear-clipping triangulation to output dcel --- examples/triangulation.cpp | 40 +++----- .../psemek/cg/triangulation/ear_clipping.hpp | 96 ++++++++++++------- 2 files changed, 75 insertions(+), 61 deletions(-) diff --git a/examples/triangulation.cpp b/examples/triangulation.cpp index c24a32e4..86a7bfb9 100644 --- a/examples/triangulation.cpp +++ b/examples/triangulation.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -62,12 +63,15 @@ struct triangulation_app { prof::profiler prof("triangulate"); - indices_ = cg::ear_clipping(points_.begin(), points_.end()); + + auto dcel = cg::ear_clipping(geom::fast, points_.begin(), points_.end()); + edges_ = cg::edge_mesh(dcel); + triangles_ = cg::triangle_mesh(dcel); } prof::dump(); - log::info() << (indices_.size() / 3) << " triangles"; + log::info() << (triangles_.size() / 3) << " triangles"; } void on_left_button_down() override @@ -117,23 +121,21 @@ struct triangulation_app auto edge = [this, line_width](auto i0, auto i1, gfx::color_rgba const & color) { - painter_.line(points_[i0], points_[i1], line_width, color, false); + painter_.line(points_[i0], points_[i1], line_width, color, true); }; random::generator rng; - for (std::size_t i = 0; i < indices_.size(); i += 3) + for (auto const & e : edges_) + edge(e[0], e[1], gfx::black); + for (auto const & t : triangles_) { -// 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); + painter_.triangle(points_[t[0]], points_[t[1]], points_[t[2]], c); } for (std::size_t i = 0; i < points_.size(); ++i) @@ -144,28 +146,12 @@ struct triangulation_app 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_; + std::vector> edges_; + std::vector> triangles_; geom::box bbox_; geom::point camera_center_; float camera_size_; diff --git a/libs/cg/include/psemek/cg/triangulation/ear_clipping.hpp b/libs/cg/include/psemek/cg/triangulation/ear_clipping.hpp index 12eada8c..3490e7d8 100644 --- a/libs/cg/include/psemek/cg/triangulation/ear_clipping.hpp +++ b/libs/cg/include/psemek/cg/triangulation/ear_clipping.hpp @@ -3,44 +3,68 @@ #include #include #include +#include #include namespace psemek::cg { - template - OutputIterator ear_clipping(RobustTag robust_tag, Iterator begin, Iterator end, OutputIterator out) + template + auto ear_clipping(RobustTag robust_tag, Iterator begin, Iterator end) { IndexType const count = std::distance(begin, end); - std::vector next(count, 0); + auto at = [begin](IndexType i){ return *(begin + i); }; + + using dcel_type = dcel; + + dcel_type result; + + auto outer_face = result.push_face(); + auto inner_face = result.push_face(); + + result.faces[inner_face.index()].edge = 0; + result.faces[outer_face.index()].edge = count; + + result.points.resize(count); + result.edges.resize(2 * count); for (IndexType i = 0; i < count; ++i) { - next[i] = (i + 1) % count; + result.points[i].edge = i; + + result.edges[i].face = 1; + result.edges[i].origin = i; + result.edges[i].prev = (i + count - 1) % count; + result.edges[i].next = (i + 1) % count; + result.edges[i].twin = i + count; + + result.edges[i + count].face = 0; + result.edges[i + count].origin = (i + 1) % count; + result.edges[i + count].prev = count + (i + 1) % count; + result.edges[i + count].next = count + (i + count - 1) % count; + result.edges[i + count].twin = i; } - IndexType j = 0; - for (IndexType i = 0; i + 2 < count; ++i) + auto edge = result.edge(0); + for (IndexType i = 0; i + 3 < count; ++i) { - for (;; j = (j + 1) % count) + for (;; edge = edge.next()) { - if (next[j] == j) continue; - bool ear = true; - auto l = next[j]; - auto h = next[l]; + auto next = edge.next(); + auto nnext = next.next(); - geom::simplex triangle{*(begin + j), *(begin + l), *(begin + h)}; + geom::simplex triangle{at(edge.origin().index()), at(next.origin().index()), at(nnext.origin().index())}; if (geom::orientation(robust_tag, triangle[0], triangle[1], triangle[2]) == geom::sign_t::negative) continue; - for (IndexType k = next[h]; k != j; k = next[k]) + for (auto k = nnext.next(); k != edge; k = k.next()) { - if (geom::contains(triangle, *(begin + k))) + if (geom::contains(triangle, at(k.origin().index()))) { ear = false; break; @@ -50,36 +74,40 @@ namespace psemek::cg if (!ear) continue; - *out++ = j; - *out++ = l; - *out++ = h; + auto ein = result.push_edge(); + auto eout = result.push_edge(); + auto prev = edge.prev(); - next[l] = l; + auto face = result.push_face(); - next[j] = h; + face.edge(ein); + ein.face(face); + edge.face(face); + next.face(face); + + ein.origin(nnext.origin()); + ein.prev(next); next.next(ein); + ein.next(edge); edge.prev(ein); + ein.twin(eout); + + eout.origin(edge.origin()); + eout.prev(prev); prev.next(eout); + eout.next(nnext); nnext.prev(eout); + eout.twin(ein); + + inner_face.edge(eout); + eout.face(inner_face); + + edge = eout; break; } } - return out; - } - - template - OutputIterator ear_clipping(Iterator begin, Iterator end, OutputIterator out) - { - return ear_clipping(geom::default_robust_tag, begin, end, out); - } - - template - std::vector ear_clipping(RobustTag robust_tag, Iterator begin, Iterator end) - { - std::vector result; - ear_clipping(robust_tag, begin, end, std::back_inserter(result)); return result; } - template + template auto ear_clipping(Iterator begin, Iterator end) { return ear_clipping(geom::default_robust_tag, begin, end);