Re-implement monotone chain triangulation to output a DCEL
This commit is contained in:
parent
92ad22f656
commit
7a57c1c1d8
2 changed files with 202 additions and 137 deletions
|
|
@ -64,14 +64,20 @@ struct triangulation_app
|
||||||
{
|
{
|
||||||
prof::profiler prof("triangulate");
|
prof::profiler prof("triangulate");
|
||||||
|
|
||||||
auto dcel = cg::ear_clipping<std::uint16_t>(geom::fast, points_.begin(), points_.end());
|
// auto dcel = cg::ear_clipping<std::uint16_t>(geom::fast, points_.begin(), points_.end());
|
||||||
|
auto dcel = cg::monotone_triangulation<std::uint16_t>(geom::fast, points_.begin(), points_.end());
|
||||||
edges_ = cg::edge_mesh(dcel);
|
edges_ = cg::edge_mesh(dcel);
|
||||||
triangles_ = cg::triangle_mesh(dcel);
|
triangles_ = cg::triangle_mesh(dcel);
|
||||||
}
|
}
|
||||||
|
|
||||||
prof::dump();
|
prof::dump();
|
||||||
|
|
||||||
log::info() << (triangles_.size() / 3) << " triangles";
|
log::info() << edges_.size() << " edges";
|
||||||
|
log::info() << triangles_.size() << " triangles";
|
||||||
|
log::info() << "Euler chi: " << (points_.size() - edges_.size() + triangles_.size());
|
||||||
|
|
||||||
|
closest_points_.resize(points_.size());
|
||||||
|
std::iota(closest_points_.begin(), closest_points_.end(), std::uint16_t{0});
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_left_button_down() override
|
void on_left_button_down() override
|
||||||
|
|
@ -125,8 +131,7 @@ struct triangulation_app
|
||||||
};
|
};
|
||||||
|
|
||||||
random::generator rng;
|
random::generator rng;
|
||||||
for (auto const & e : edges_)
|
|
||||||
edge(e[0], e[1], gfx::black);
|
|
||||||
for (auto const & t : triangles_)
|
for (auto const & t : triangles_)
|
||||||
{
|
{
|
||||||
gfx::color_rgba c;
|
gfx::color_rgba c;
|
||||||
|
|
@ -138,14 +143,52 @@ struct triangulation_app
|
||||||
painter_.triangle(points_[t[0]], points_[t[1]], points_[t[2]], c);
|
painter_.triangle(points_[t[0]], points_[t[1]], points_[t[2]], c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for (auto const & e : edges_)
|
||||||
|
// edge(e[0], e[1], gfx::black);
|
||||||
|
|
||||||
for (std::size_t i = 0; i < points_.size(); ++i)
|
for (std::size_t i = 0; i < points_.size(); ++i)
|
||||||
{
|
|
||||||
edge(i, (i + 1) % points_.size(), gfx::black);
|
edge(i, (i + 1) % points_.size(), gfx::black);
|
||||||
}
|
|
||||||
|
|
||||||
auto camera_transform = geom::orthographic_camera{view_bbox}.transform();
|
auto camera_transform = geom::orthographic_camera{view_bbox}.transform();
|
||||||
|
|
||||||
painter_.render(camera_transform);
|
painter_.render(camera_transform);
|
||||||
|
|
||||||
|
if (auto m = mouse(); m)
|
||||||
|
{
|
||||||
|
geom::point<float, 2> m_world;
|
||||||
|
m_world[0] = geom::lerp(view_bbox[0], (*m)[0] * 1.f / width());
|
||||||
|
m_world[1] = geom::lerp(view_bbox[1], 1.f - (*m)[1] * 1.f / height());
|
||||||
|
|
||||||
|
auto compare = [&](auto i, auto j){
|
||||||
|
return geom::distance(points_[i], m_world) < geom::distance(points_[j], m_world);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t const n_closest = 8;
|
||||||
|
|
||||||
|
std::partial_sort(closest_points_.begin(), closest_points_.begin() + n_closest, closest_points_.end(), compare);
|
||||||
|
|
||||||
|
float max_distance = camera_size_ / 32.f;
|
||||||
|
|
||||||
|
for (std::size_t j = 0; j < n_closest; ++j)
|
||||||
|
{
|
||||||
|
auto i = closest_points_[j];
|
||||||
|
|
||||||
|
if (geom::distance(points_[i], m_world) > max_distance)
|
||||||
|
break;
|
||||||
|
|
||||||
|
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:
|
private:
|
||||||
|
|
@ -158,6 +201,7 @@ private:
|
||||||
float camera_size_tgt_;
|
float camera_size_tgt_;
|
||||||
|
|
||||||
std::optional<geom::point<int, 2>> drag_start_;
|
std::optional<geom::point<int, 2>> drag_start_;
|
||||||
|
std::vector<std::uint16_t> closest_points_;
|
||||||
|
|
||||||
gfx::painter painter_;
|
gfx::painter painter_;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <psemek/geom/point.hpp>
|
#include <psemek/geom/point.hpp>
|
||||||
#include <psemek/geom/orientation.hpp>
|
#include <psemek/geom/orientation.hpp>
|
||||||
#include <psemek/geom/contains.hpp>
|
#include <psemek/geom/contains.hpp>
|
||||||
|
#include <psemek/cg/dcel.hpp>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
@ -10,39 +11,43 @@
|
||||||
namespace psemek::cg
|
namespace psemek::cg
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename IndexType = std::size_t, typename RobustTag, typename Iterator, typename OutputIterator>
|
template <typename IndexType = std::size_t, typename RobustTag, typename Iterator>
|
||||||
OutputIterator monotone_triangulation(RobustTag robust_tag, Iterator begin, Iterator end, OutputIterator out)
|
auto monotone_triangulation(RobustTag robust_tag, Iterator begin, Iterator end)
|
||||||
{
|
{
|
||||||
IndexType const count = std::distance(begin, end);
|
IndexType const count = std::distance(begin, end);
|
||||||
IndexType const null = IndexType(-1);
|
|
||||||
|
|
||||||
auto at = [begin](auto i){ return *(begin + i); };
|
auto at = [begin](IndexType i){ return *(begin + i); };
|
||||||
|
|
||||||
// Initialize dcel
|
// Initialize dcel
|
||||||
|
|
||||||
std::vector<IndexType> start(count, 0);
|
using dcel_type = dcel<util::empty, util::empty, util::empty, IndexType>;
|
||||||
std::vector<IndexType> next(count, 0);
|
using point_handle = typename dcel_type::point_handle;
|
||||||
std::vector<IndexType> prev(count, 0);
|
|
||||||
std::vector<IndexType> twin(count, 0);
|
dcel_type result;
|
||||||
|
|
||||||
|
result.push_face();
|
||||||
|
result.faces[0].edge = count;
|
||||||
|
|
||||||
|
result.points.resize(count);
|
||||||
|
result.edges.resize(2 * count);
|
||||||
|
|
||||||
for (IndexType i = 0; i < count; ++i)
|
for (IndexType i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
start[i] = i;
|
result.points[i].edge = i;
|
||||||
next[i] = (i + 1) % count;
|
|
||||||
prev[i] = (i + count - 1) % count;
|
result.edges[i].face = result.null;
|
||||||
twin[i] = null;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto finish = [&](auto i)
|
|
||||||
{
|
|
||||||
return start[next[i]];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct vertex_id
|
|
||||||
{
|
|
||||||
IndexType index;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sweepline_compare
|
struct sweepline_compare
|
||||||
{
|
{
|
||||||
struct is_transparent{};
|
struct is_transparent{};
|
||||||
|
|
@ -71,14 +76,14 @@ namespace psemek::cg
|
||||||
return geom::orientation(RobustTag{}, j0, j1, i0) == geom::sign_t::negative;
|
return geom::orientation(RobustTag{}, j0, j1, i0) == geom::sign_t::negative;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator()(IndexType e, vertex_id const & v) const
|
bool operator()(IndexType e, point_handle v) const
|
||||||
{
|
{
|
||||||
return geom::orientation(RobustTag{}, at(e), at((e + 1) % count), at(v.index)) == geom::sign_t::positive;
|
return geom::orientation(RobustTag{}, at(e), at((e + 1) % count), at(v.index())) == geom::sign_t::positive;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator()(vertex_id const & v, IndexType e) const
|
bool operator()(point_handle v, IndexType e) const
|
||||||
{
|
{
|
||||||
return geom::orientation(RobustTag{}, at(e), at((e + 1) % count), at(v.index)) == geom::sign_t::negative;
|
return geom::orientation(RobustTag{}, at(e), at((e + 1) % count), at(v.index())) == geom::sign_t::negative;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -129,11 +134,11 @@ namespace psemek::cg
|
||||||
auto const vi = at(i);
|
auto const vi = at(i);
|
||||||
auto const vj = at(j);
|
auto const vj = at(j);
|
||||||
|
|
||||||
auto ni = i;
|
auto ni = result.edge(i);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
auto f = at(finish(ni));
|
auto f = at(ni.next().origin().index());
|
||||||
auto p = at(start[prev[ni]]);
|
auto p = at(ni.prev().origin().index());
|
||||||
bool contains;
|
bool contains;
|
||||||
if (geom::orientation(robust_tag, f, vi, p) == geom::sign_t::negative)
|
if (geom::orientation(robust_tag, f, vi, p) == geom::sign_t::negative)
|
||||||
contains = geom::orientation(robust_tag, f, vi, vj) == geom::sign_t::negative && geom::orientation(robust_tag, vj, vi, p) == geom::sign_t::negative;
|
contains = geom::orientation(robust_tag, f, vi, vj) == geom::sign_t::negative && geom::orientation(robust_tag, vj, vi, p) == geom::sign_t::negative;
|
||||||
|
|
@ -141,15 +146,15 @@ namespace psemek::cg
|
||||||
contains = geom::orientation(robust_tag, f, vi, vj) == geom::sign_t::negative || geom::orientation(robust_tag, vj, vi, p) == geom::sign_t::negative;
|
contains = geom::orientation(robust_tag, f, vi, vj) == geom::sign_t::negative || geom::orientation(robust_tag, vj, vi, p) == geom::sign_t::negative;
|
||||||
if (contains)
|
if (contains)
|
||||||
break;
|
break;
|
||||||
ni = twin[prev[ni]];
|
ni = ni.prev().twin();
|
||||||
}
|
}
|
||||||
auto pi = prev[ni];
|
auto pi = ni.prev();
|
||||||
|
|
||||||
auto nj = j;
|
auto nj = result.edge(j);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
auto f = at(finish(nj));
|
auto f = at(nj.next().origin().index());
|
||||||
auto p = at(start[prev[nj]]);
|
auto p = at(nj.prev().origin().index());
|
||||||
bool contains;
|
bool contains;
|
||||||
if (geom::orientation(robust_tag, f, vj, p) == geom::sign_t::negative)
|
if (geom::orientation(robust_tag, f, vj, p) == geom::sign_t::negative)
|
||||||
contains = geom::orientation(robust_tag, f, vj, vi) == geom::sign_t::negative && geom::orientation(robust_tag, vi, vj, p) == geom::sign_t::negative;
|
contains = geom::orientation(robust_tag, f, vj, vi) == geom::sign_t::negative && geom::orientation(robust_tag, vi, vj, p) == geom::sign_t::negative;
|
||||||
|
|
@ -157,37 +162,22 @@ namespace psemek::cg
|
||||||
contains = geom::orientation(robust_tag, f, vj, vi) == geom::sign_t::negative || geom::orientation(robust_tag, vi, vj, p) == geom::sign_t::negative;
|
contains = geom::orientation(robust_tag, f, vj, vi) == geom::sign_t::negative || geom::orientation(robust_tag, vi, vj, p) == geom::sign_t::negative;
|
||||||
if (contains)
|
if (contains)
|
||||||
break;
|
break;
|
||||||
nj = twin[prev[nj]];
|
nj = nj.prev().twin();
|
||||||
}
|
}
|
||||||
auto pj = prev[nj];
|
auto pj = nj.prev();
|
||||||
|
|
||||||
IndexType eij = start.size();
|
auto eij = result.push_edge();
|
||||||
IndexType eji = eij + 1;
|
auto eji = result.push_edge();
|
||||||
|
|
||||||
start.emplace_back();
|
eij.origin(result.point(i));
|
||||||
start.emplace_back();
|
eij.next(nj); nj.prev(eij);
|
||||||
next.emplace_back();
|
eij.prev(pi); pi.next(eij);
|
||||||
next.emplace_back();
|
eij.twin(eji);
|
||||||
prev.emplace_back();
|
|
||||||
prev.emplace_back();
|
|
||||||
twin.emplace_back();
|
|
||||||
twin.emplace_back();
|
|
||||||
|
|
||||||
start[eij] = i;
|
eji.origin(result.point(j));
|
||||||
next[eij] = nj;
|
eji.next(ni); ni.prev(eji);
|
||||||
prev[eij] = pi;
|
eji.prev(pj); pj.next(eji);
|
||||||
twin[eij] = eji;
|
eji.twin(eij);
|
||||||
|
|
||||||
start[eji] = j;
|
|
||||||
next[eji] = ni;
|
|
||||||
prev[eji] = pj;
|
|
||||||
twin[eji] = eij;
|
|
||||||
|
|
||||||
next[pi] = eij;
|
|
||||||
prev[nj] = eij;
|
|
||||||
|
|
||||||
next[pj] = eji;
|
|
||||||
prev[ni] = eji;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Partition into monotone parts
|
// Partition into monotone parts
|
||||||
|
|
@ -208,7 +198,7 @@ namespace psemek::cg
|
||||||
break;
|
break;
|
||||||
case event_type::split:
|
case event_type::split:
|
||||||
{
|
{
|
||||||
auto l = *std::prev(sweepline.upper_bound(vertex_id{e}));
|
auto l = *std::prev(sweepline.upper_bound(result.point(e)));
|
||||||
connect(e, helper[l]);
|
connect(e, helper[l]);
|
||||||
helper[l] = e;
|
helper[l] = e;
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +210,7 @@ namespace psemek::cg
|
||||||
connect(e, h);
|
connect(e, h);
|
||||||
sweepline.erase(p);
|
sweepline.erase(p);
|
||||||
{
|
{
|
||||||
auto l = *std::prev(sweepline.upper_bound(vertex_id{e}));
|
auto l = *std::prev(sweepline.upper_bound(result.point(e)));
|
||||||
if (auto h = helper[l]; classify(h) == event_type::merge)
|
if (auto h = helper[l]; classify(h) == event_type::merge)
|
||||||
connect(e, h);
|
connect(e, h);
|
||||||
helper[l] = e;
|
helper[l] = e;
|
||||||
|
|
@ -237,7 +227,7 @@ namespace psemek::cg
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto l = *std::prev(sweepline.upper_bound(vertex_id{e}));
|
auto l = *std::prev(sweepline.upper_bound(result.point(e)));
|
||||||
if (auto h = helper[l]; classify(h) == event_type::merge)
|
if (auto h = helper[l]; classify(h) == event_type::merge)
|
||||||
connect(e, h);
|
connect(e, h);
|
||||||
helper[l] = e;
|
helper[l] = e;
|
||||||
|
|
@ -246,125 +236,156 @@ namespace psemek::cg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Triangulate monotone parts
|
fill_missing_faces(result);
|
||||||
std::vector<bool> used(start.size(), false);
|
|
||||||
std::vector<IndexType> stack;
|
|
||||||
for (IndexType e = 0; e < start.size(); ++e)
|
|
||||||
{
|
|
||||||
if (used[e]) continue;
|
|
||||||
|
|
||||||
auto le = e;
|
IndexType face_count = result.faces.size();
|
||||||
used[e] = true;
|
|
||||||
// Mark the whole part as used and find leftmost point
|
// Triangulate monotone parts
|
||||||
for (auto ee = next[e]; ee != e; ee = next[ee])
|
std::vector<IndexType> stack;
|
||||||
|
for (IndexType f = 1; f < face_count; ++f)
|
||||||
{
|
{
|
||||||
used[ee] = true;
|
auto e = result.face(f).edge();
|
||||||
if (at(start[ee]) < at(start[le]))
|
|
||||||
|
// Find leftmost point
|
||||||
|
auto le = e;
|
||||||
|
for (auto ee = e.next(); ee != e; ee = ee.next())
|
||||||
|
{
|
||||||
|
if (at(ee.origin().index()) < at(le.origin().index()))
|
||||||
le = ee;
|
le = ee;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stack_left = true;
|
bool stack_left = true;
|
||||||
|
|
||||||
auto re = prev[le];
|
auto re = le.prev();
|
||||||
stack.push_back(start[le]);
|
stack.push_back(le.index());
|
||||||
le = next[le];
|
le = le.next();
|
||||||
|
|
||||||
|
auto emit_triangle = [&](auto e0_id, auto e1_id)
|
||||||
|
{
|
||||||
|
auto e0 = result.edge(e0_id);
|
||||||
|
auto e1 = result.edge(e1_id);
|
||||||
|
|
||||||
|
auto p = e0.prev();
|
||||||
|
auto n = e1.next();
|
||||||
|
|
||||||
|
auto face_out = e0.face();
|
||||||
|
auto face_in = result.push_face();
|
||||||
|
|
||||||
|
auto e_in = result.push_edge();
|
||||||
|
auto e_out = result.push_edge();
|
||||||
|
|
||||||
|
face_in.edge(e_in);
|
||||||
|
face_out.edge(e_out);
|
||||||
|
|
||||||
|
e_in.origin(n.origin());
|
||||||
|
e_out.origin(e0.origin());
|
||||||
|
|
||||||
|
e_in.twin(e_out);
|
||||||
|
e_out.twin(e_in);
|
||||||
|
|
||||||
|
e0.face(face_in);
|
||||||
|
e1.face(face_in);
|
||||||
|
e_in.face(face_in);
|
||||||
|
e_out.face(face_out);
|
||||||
|
|
||||||
|
e0.prev(e_in); e_in.next(e0);
|
||||||
|
e1.next(e_in); e_in.prev(e1);
|
||||||
|
|
||||||
|
p.next(e_out); e_out.prev(p);
|
||||||
|
n.prev(e_out); e_out.next(n);
|
||||||
|
|
||||||
|
return e_out.index();
|
||||||
|
};
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
bool last = (le == re);
|
auto ve = le;
|
||||||
|
|
||||||
IndexType v;
|
|
||||||
bool left;
|
bool left;
|
||||||
if (at(start[le]) < at(start[re]))
|
if (at(le.origin().index()) < at(re.origin().index()))
|
||||||
{
|
{
|
||||||
v = start[le];
|
ve = le;
|
||||||
le = next[le];
|
le = le.next();
|
||||||
left = true;
|
left = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
v = start[re];
|
ve = re;
|
||||||
re = prev[re];
|
re = re.prev();
|
||||||
left = false;
|
left = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto orientation = [&](auto e0, auto e1, auto e2)
|
||||||
|
{
|
||||||
|
auto point = [&](auto e){ return at(result.edge(e).origin().index()); };
|
||||||
|
return geom::orientation(robust_tag, point(e0), point(e1), point(e2));
|
||||||
|
};
|
||||||
|
|
||||||
if (left && stack_left)
|
if (left && stack_left)
|
||||||
{
|
{
|
||||||
while (stack.size() >= 2 && geom::orientation(robust_tag, at(v), at(stack.back()), at(stack[stack.size() - 2])) == geom::sign_t::negative)
|
while (stack.size() >= 2 && orientation(ve.index(), stack.back(), stack[stack.size() - 2]) == geom::sign_t::negative)
|
||||||
{
|
{
|
||||||
*out++ = v;
|
auto new_edge = emit_triangle(stack[stack.size() - 2], stack.back());
|
||||||
*out++ = stack[stack.size() - 2];
|
|
||||||
*out++ = stack.back();
|
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
|
stack.pop_back();
|
||||||
|
stack.push_back(new_edge);
|
||||||
}
|
}
|
||||||
stack.push_back(v);
|
stack.push_back(ve.index());
|
||||||
}
|
}
|
||||||
else if (!left && !stack_left)
|
else if (!left && !stack_left)
|
||||||
{
|
{
|
||||||
while (stack.size() >= 2 && geom::orientation(robust_tag, at(v), at(stack.back()), at(stack[stack.size() - 2])) == geom::sign_t::positive)
|
auto e = ve.index();
|
||||||
|
while (stack.size() >= 2 && orientation(ve.index(), stack.back(), stack[stack.size() - 2]) == geom::sign_t::positive)
|
||||||
{
|
{
|
||||||
*out++ = v;
|
e = emit_triangle(e, stack.back());
|
||||||
*out++ = stack.back();
|
|
||||||
*out++ = stack[stack.size() - 2];
|
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
}
|
}
|
||||||
stack.push_back(v);
|
stack.push_back(e);
|
||||||
}
|
}
|
||||||
else if (left && !stack_left)
|
else if (left && !stack_left)
|
||||||
{
|
{
|
||||||
auto last = stack.back();
|
auto e = stack.front();
|
||||||
while (stack.size() >= 2)
|
for (auto it = std::next(stack.begin()); it != stack.end(); ++it)
|
||||||
{
|
e = emit_triangle(*it, e);
|
||||||
*out++ = v;
|
stack.clear();
|
||||||
*out++ = stack.back();
|
stack.push_back(e);
|
||||||
*out++ = stack[stack.size() - 2];
|
stack.push_back(ve.index());
|
||||||
stack.pop_back();
|
|
||||||
}
|
|
||||||
stack.pop_back();
|
|
||||||
stack.push_back(last);
|
|
||||||
stack.push_back(v);
|
|
||||||
}
|
}
|
||||||
else if (!left && stack_left)
|
else if (!left && stack_left)
|
||||||
{
|
{
|
||||||
|
auto e = ve.index();
|
||||||
auto last = stack.back();
|
auto last = stack.back();
|
||||||
while (stack.size() >= 2)
|
for (auto it = stack.begin(); it != std::prev(stack.end()); ++it)
|
||||||
{
|
e = emit_triangle(e, *it);
|
||||||
*out++ = v;
|
stack.clear();
|
||||||
*out++ = stack[stack.size() - 2];
|
|
||||||
*out++ = stack.back();
|
|
||||||
stack.pop_back();
|
|
||||||
}
|
|
||||||
stack.pop_back();
|
|
||||||
stack.push_back(last);
|
stack.push_back(last);
|
||||||
stack.push_back(v);
|
stack.push_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
stack_left = left;
|
stack_left = left;
|
||||||
|
|
||||||
if (last)
|
if (le == re)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto de = le.index();
|
||||||
|
if (stack_left)
|
||||||
|
{
|
||||||
|
for (IndexType i = 0; i + 2 < stack.size(); ++i)
|
||||||
|
de = emit_triangle(de, stack[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (IndexType i = stack.size() - 1; i > 1; --i)
|
||||||
|
de = emit_triangle(de, stack[i]);
|
||||||
|
}
|
||||||
|
|
||||||
stack.clear();
|
stack.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename IndexType = std::size_t, typename Iterator, typename OutputIterator>
|
|
||||||
auto monotone_triangulation(Iterator begin, Iterator end, OutputIterator out)
|
|
||||||
{
|
|
||||||
return monotone_triangulation<IndexType>(geom::default_robust_tag, begin, end, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename IndexType, typename RobustTag, typename Iterator>
|
|
||||||
std::vector<IndexType> monotone_triangulation(RobustTag robust_tag, Iterator begin, Iterator end)
|
|
||||||
{
|
|
||||||
std::vector<IndexType> result;
|
|
||||||
monotone_triangulation<IndexType>(robust_tag, begin, end, std::back_inserter(result));
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename IndexType, typename Iterator>
|
template <typename IndexType, typename Iterator>
|
||||||
auto monotone_triangulation(Iterator begin, Iterator end)
|
auto monotone_triangulation(Iterator begin, Iterator end)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue