Rewrite ear-clipping triangulation to output dcel

This commit is contained in:
Nikita Lisitsa 2022-09-17 00:40:00 +03:00
parent 34d9e67960
commit 51e6f8ad9c
2 changed files with 75 additions and 61 deletions

View file

@ -8,6 +8,7 @@
#include <psemek/cg/bbox.hpp>
#include <psemek/cg/triangulation/ear_clipping.hpp>
#include <psemek/cg/triangulation/monotone.hpp>
#include <psemek/cg/triangulation/delaunay.hpp>
#include <psemek/log/log.hpp>
#include <psemek/prof/profiler.hpp>
#include <psemek/util/clock.hpp>
@ -62,12 +63,15 @@ struct triangulation_app
{
prof::profiler prof("triangulate");
indices_ = cg::ear_clipping<std::uint16_t>(points_.begin(), points_.end());
auto dcel = cg::ear_clipping<std::uint16_t>(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<std::uint8_t>(rng, {0, 255});
c[1] = random::uniform<std::uint8_t>(rng, {0, 255});
c[2] = random::uniform<std::uint8_t>(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<geom::point<float, 2>> points_;
std::vector<std::uint16_t> indices_;
std::vector<geom::segment<std::uint16_t>> edges_;
std::vector<geom::triangle<std::uint16_t>> triangles_;
geom::box<float, 2> bbox_;
geom::point<float, 2> camera_center_;
float camera_size_;

View file

@ -3,44 +3,68 @@
#include <psemek/geom/point.hpp>
#include <psemek/geom/orientation.hpp>
#include <psemek/geom/contains.hpp>
#include <psemek/cg/dcel.hpp>
#include <vector>
namespace psemek::cg
{
template <typename IndexType = std::size_t, typename RobustTag, typename Iterator, typename OutputIterator>
OutputIterator ear_clipping(RobustTag robust_tag, Iterator begin, Iterator end, OutputIterator out)
template <typename IndexType = std::size_t, typename RobustTag, typename Iterator>
auto ear_clipping(RobustTag robust_tag, Iterator begin, Iterator end)
{
IndexType const count = std::distance(begin, end);
std::vector<IndexType> next(count, 0);
auto at = [begin](IndexType i){ return *(begin + i); };
using dcel_type = dcel<util::empty, util::empty, util::empty, IndexType>;
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 <typename IndexType = std::size_t, typename Iterator, typename OutputIterator>
OutputIterator ear_clipping(Iterator begin, Iterator end, OutputIterator out)
{
return ear_clipping<IndexType>(geom::default_robust_tag, begin, end, out);
}
template <typename IndexType, typename RobustTag, typename Iterator>
std::vector<IndexType> ear_clipping(RobustTag robust_tag, Iterator begin, Iterator end)
{
std::vector<IndexType> result;
ear_clipping<IndexType>(robust_tag, begin, end, std::back_inserter(result));
return result;
}
template <typename IndexType, typename Iterator>
template <typename IndexType = std::size_t, typename Iterator>
auto ear_clipping(Iterator begin, Iterator end)
{
return ear_clipping<IndexType>(geom::default_robust_tag, begin, end);