Refactor TriangleSelector to allow returning indexed triangle set with information about the color of each facet.

This commit is contained in:
Lukáš Hejl 2024-07-09 12:41:59 +02:00 committed by Lukas Matena
parent 225d52b084
commit 2fa92a96a4
5 changed files with 178 additions and 57 deletions

View File

@ -2043,35 +2043,46 @@ void ModelInstance::transform_polygon(Polygon* polygon) const
polygon->scale(get_scaling_factor(X), get_scaling_factor(Y)); // scale around polygon origin polygon->scale(get_scaling_factor(X), get_scaling_factor(Y)); // scale around polygon origin
} }
indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, TriangleStateType type) const indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume &mv, TriangleStateType type) const {
{
TriangleSelector selector(mv.mesh()); TriangleSelector selector(mv.mesh());
// Reset of TriangleSelector is done inside TriangleSelector's constructor, so we don't need it to perform it again in deserialize(). // Reset of TriangleSelector is done inside TriangleSelector's constructor, so we don't need it to perform it again in deserialize().
selector.deserialize(m_data, false); selector.deserialize(m_data, false);
return selector.get_facets(type); return selector.get_facets(type);
} }
indexed_triangle_set FacetsAnnotation::get_facets_strict(const ModelVolume& mv, TriangleStateType type) const indexed_triangle_set FacetsAnnotation::get_facets_strict(const ModelVolume &mv, TriangleStateType type) const {
{
TriangleSelector selector(mv.mesh()); TriangleSelector selector(mv.mesh());
// Reset of TriangleSelector is done inside TriangleSelector's constructor, so we don't need it to perform it again in deserialize(). // Reset of TriangleSelector is done inside TriangleSelector's constructor, so we don't need it to perform it again in deserialize().
selector.deserialize(m_data, false); selector.deserialize(m_data, false);
return selector.get_facets_strict(type); return selector.get_facets_strict(type);
} }
bool FacetsAnnotation::has_facets(const ModelVolume& mv, TriangleStateType type) const indexed_triangle_set_with_color FacetsAnnotation::get_all_facets_with_colors(const ModelVolume &mv) const {
{ TriangleSelector selector(mv.mesh());
// Reset of TriangleSelector is done inside TriangleSelector's constructor, so we don't need it to perform it again in deserialize().
selector.deserialize(m_data, false);
return selector.get_all_facets_with_colors();
}
indexed_triangle_set_with_color FacetsAnnotation::get_all_facets_strict_with_colors(const ModelVolume &mv) const {
TriangleSelector selector(mv.mesh());
// Reset of TriangleSelector is done inside TriangleSelector's constructor, so we don't need it to perform it again in deserialize().
selector.deserialize(m_data, false);
return selector.get_all_facets_strict_with_colors();
}
bool FacetsAnnotation::has_facets(const ModelVolume &mv, TriangleStateType type) const {
return TriangleSelector::has_facets(m_data, type); return TriangleSelector::has_facets(m_data, type);
} }
bool FacetsAnnotation::set(const TriangleSelector& selector) bool FacetsAnnotation::set(const TriangleSelector &selector) {
{
TriangleSelector::TriangleSplittingData sel_map = selector.serialize(); TriangleSelector::TriangleSplittingData sel_map = selector.serialize();
if (sel_map != m_data) { if (sel_map != m_data) {
m_data = std::move(sel_map); m_data = std::move(sel_map);
this->touch(); this->touch();
return true; return true;
} }
return false; return false;
} }

View File

@ -667,10 +667,12 @@ public:
void assign(const FacetsAnnotation &rhs) { if (! this->timestamp_matches(rhs)) { m_data = rhs.m_data; this->copy_timestamp(rhs); } } void assign(const FacetsAnnotation &rhs) { if (! this->timestamp_matches(rhs)) { m_data = rhs.m_data; this->copy_timestamp(rhs); } }
void assign(FacetsAnnotation &&rhs) { if (! this->timestamp_matches(rhs)) { m_data = std::move(rhs.m_data); this->copy_timestamp(rhs); } } void assign(FacetsAnnotation &&rhs) { if (! this->timestamp_matches(rhs)) { m_data = std::move(rhs.m_data); this->copy_timestamp(rhs); } }
const TriangleSelector::TriangleSplittingData &get_data() const noexcept { return m_data; } const TriangleSelector::TriangleSplittingData &get_data() const noexcept { return m_data; }
bool set(const TriangleSelector& selector); bool set(const TriangleSelector &selector);
indexed_triangle_set get_facets(const ModelVolume& mv, TriangleStateType type) const; indexed_triangle_set get_facets(const ModelVolume &mv, TriangleStateType type) const;
indexed_triangle_set get_facets_strict(const ModelVolume& mv, TriangleStateType type) const; indexed_triangle_set get_facets_strict(const ModelVolume &mv, TriangleStateType type) const;
bool has_facets(const ModelVolume& mv, TriangleStateType type) const; indexed_triangle_set_with_color get_all_facets_with_colors(const ModelVolume &mv) const;
indexed_triangle_set_with_color get_all_facets_strict_with_colors(const ModelVolume &mv) const;
bool has_facets(const ModelVolume &mv, TriangleStateType type) const;
bool empty() const { return m_data.triangles_to_split.empty(); } bool empty() const { return m_data.triangles_to_split.empty(); }
// Following method clears the config and increases its timestamp, so the deleted // Following method clears the config and increases its timestamp, so the deleted

View File

@ -39,6 +39,30 @@ namespace Slic3r {
class TriangleMesh; class TriangleMesh;
class TriangleMeshSlicer; class TriangleMeshSlicer;
struct indexed_triangle_set_with_color
{
std::vector<stl_triangle_vertex_indices> indices;
std::vector<stl_vertex> vertices;
std::vector<uint8_t> colors;
};
enum class AdditionalMeshInfo {
None,
Color
};
template<AdditionalMeshInfo mesh_info> struct IndexedTriangleSetType;
template<> struct IndexedTriangleSetType<AdditionalMeshInfo::None>
{
using type = indexed_triangle_set;
};
template<> struct IndexedTriangleSetType<AdditionalMeshInfo::Color>
{
using type = indexed_triangle_set_with_color;
};
struct RepairedMeshErrors { struct RepairedMeshErrors {
// How many edges were united by merging their end points with some other end points in epsilon neighborhood? // How many edges were united by merging their end points with some other end points in epsilon neighborhood?
int edges_fixed = 0; int edges_fixed = 0;
@ -394,7 +418,7 @@ inline BoundingBoxf3 bounding_box(const indexed_triangle_set& its, const Transfo
return {bmin.cast<double>(), bmax.cast<double>()}; return {bmin.cast<double>(), bmax.cast<double>()};
} }
} } // namespace Slic3r
// Serialization through the Cereal library // Serialization through the Cereal library
#include <cereal/access.hpp> #include <cereal/access.hpp>

View File

@ -1333,13 +1333,16 @@ int TriangleSelector::num_facets(TriangleStateType state) const {
return cnt; return cnt;
} }
indexed_triangle_set TriangleSelector::get_facets(TriangleStateType state) const { template<AdditionalMeshInfo facet_info>
indexed_triangle_set out; typename IndexedTriangleSetType<facet_info>::type TriangleSelector::get_facets(const std::function<bool(const Triangle &)> &facet_filter) const {
using IndexedTriangleSetType = typename IndexedTriangleSetType<facet_info>::type;
IndexedTriangleSetType out;
std::vector<int> vertex_map(m_vertices.size(), -1); std::vector<int> vertex_map(m_vertices.size(), -1);
for (const Triangle& tr : m_triangles) { for (const Triangle &tr : m_triangles) {
if (tr.valid() && ! tr.is_split() && tr.get_state() == state) { if (tr.valid() && !tr.is_split() && facet_filter(tr)) {
stl_triangle_vertex_indices indices; stl_triangle_vertex_indices indices;
for (int i=0; i<3; ++i) { for (int i = 0; i < 3; ++i) {
int j = tr.verts_idxs[i]; int j = tr.verts_idxs[i];
if (vertex_map[j] == -1) { if (vertex_map[j] == -1) {
vertex_map[j] = int(out.vertices.size()); vertex_map[j] = int(out.vertices.size());
@ -1348,55 +1351,105 @@ indexed_triangle_set TriangleSelector::get_facets(TriangleStateType state) const
indices[i] = vertex_map[j]; indices[i] = vertex_map[j];
} }
out.indices.emplace_back(indices); out.indices.emplace_back(indices);
if constexpr (facet_info == AdditionalMeshInfo::Color) {
out.colors.emplace_back(static_cast<uint8_t>(tr.get_state()));
} }
} }
}
return out; return out;
} }
indexed_triangle_set TriangleSelector::get_facets_strict(TriangleStateType state) const { indexed_triangle_set TriangleSelector::get_facets(TriangleStateType state) const {
indexed_triangle_set out; return this->get_facets([state](const Triangle &tr) { return tr.get_state() == state; });
}
size_t num_vertices = 0; indexed_triangle_set TriangleSelector::get_all_facets() const {
for (const Vertex &v : m_vertices) return this->get_facets([](const Triangle &tr) { return true; });
}
indexed_triangle_set_with_color TriangleSelector::get_all_facets_with_colors() const {
return this->get_facets<AdditionalMeshInfo::Color>([](const Triangle &tr) { return true; });
}
template<AdditionalMeshInfo facet_info>
typename IndexedTriangleSetType<facet_info>::type TriangleSelector::get_facets_strict(const std::function<bool(const Triangle &)> &facet_filter) const {
using IndexedTriangleSetType = typename IndexedTriangleSetType<facet_info>::type;
auto get_vertices_count = [&vertices = std::as_const(m_vertices)]() -> size_t {
size_t vertices_cnt = 0;
for (const Vertex &v : vertices) {
if (v.ref_cnt > 0) if (v.ref_cnt > 0)
++ num_vertices; ++vertices_cnt;
out.vertices.reserve(num_vertices); }
return vertices_cnt;
};
IndexedTriangleSetType out;
out.vertices.reserve(get_vertices_count());
std::vector<int> vertex_map(m_vertices.size(), -1); std::vector<int> vertex_map(m_vertices.size(), -1);
for (size_t i = 0; i < m_vertices.size(); ++ i) for (size_t i = 0; i < m_vertices.size(); ++i) {
if (const Vertex &v = m_vertices[i]; v.ref_cnt > 0) { if (const Vertex &v = m_vertices[i]; v.ref_cnt > 0) {
vertex_map[i] = int(out.vertices.size()); vertex_map[i] = int(out.vertices.size());
out.vertices.emplace_back(v.v); out.vertices.emplace_back(v.v);
} }
}
std::vector<uint8_t> out_colors;
for (int itriangle = 0; itriangle < m_orig_size_indices; ++ itriangle) for (int itriangle = 0; itriangle < m_orig_size_indices; ++ itriangle)
this->get_facets_strict_recursive(m_triangles[itriangle], m_neighbors[itriangle], state, out.indices); this->get_facets_strict_recursive<facet_info>(m_triangles[itriangle], m_neighbors[itriangle], facet_filter, out.indices, out_colors);
for (auto &triangle : out.indices) if constexpr (facet_info == AdditionalMeshInfo::Color) {
for (int i = 0; i < 3; ++ i) out.colors = std::move(out_colors);
}
for (auto &triangle : out.indices) {
for (int i = 0; i < 3; ++i) {
triangle(i) = vertex_map[triangle(i)]; triangle(i) = vertex_map[triangle(i)];
}
}
return out; return out;
} }
indexed_triangle_set TriangleSelector::get_facets_strict(TriangleStateType state) const {
return this->get_facets_strict([state](const Triangle &tr) { return tr.get_state() == state; });
}
indexed_triangle_set TriangleSelector::get_all_facets_strict() const {
return this->get_facets_strict([](const Triangle &tr) { return true; });
}
indexed_triangle_set_with_color TriangleSelector::get_all_facets_strict_with_colors() const {
return this->get_facets_strict<AdditionalMeshInfo::Color>([](const Triangle &tr) { return true; });
}
template<AdditionalMeshInfo facet_info>
void TriangleSelector::get_facets_strict_recursive( void TriangleSelector::get_facets_strict_recursive(
const Triangle &tr, const Triangle &tr,
const Vec3i &neighbors, const Vec3i &neighbors,
TriangleStateType state, const std::function<bool(const Triangle &)> &facet_filter,
std::vector<stl_triangle_vertex_indices> &out_triangles) const std::vector<stl_triangle_vertex_indices> &out_triangles,
std::vector<uint8_t> &out_colors) const
{ {
if (tr.is_split()) { if (tr.is_split()) {
for (int i = 0; i <= tr.number_of_split_sides(); ++ i) for (int i = 0; i <= tr.number_of_split_sides(); ++ i)
this->get_facets_strict_recursive( this->get_facets_strict_recursive<facet_info>(
m_triangles[tr.children[i]], m_triangles[tr.children[i]],
this->child_neighbors(tr, neighbors, i), this->child_neighbors(tr, neighbors, i),
state, out_triangles); facet_filter, out_triangles, out_colors);
} else if (tr.get_state() == state) } else if (facet_filter(tr)) {
this->get_facets_split_by_tjoints({tr.verts_idxs[0], tr.verts_idxs[1], tr.verts_idxs[2]}, neighbors, out_triangles); const uint8_t facet_color = static_cast<uint8_t>(tr.get_state());
this->get_facets_split_by_tjoints<facet_info>({tr.verts_idxs[0], tr.verts_idxs[1], tr.verts_idxs[2]}, neighbors, facet_color, out_triangles, out_colors);
}
} }
void TriangleSelector::get_facets_split_by_tjoints(const Vec3i &vertices, const Vec3i &neighbors, std::vector<stl_triangle_vertex_indices> &out_triangles) const template<AdditionalMeshInfo facet_info>
{ void TriangleSelector::get_facets_split_by_tjoints(const Vec3i &vertices, const Vec3i &neighbors, const uint8_t color, std::vector<stl_triangle_vertex_indices> &out_triangles, std::vector<uint8_t> &out_colors) const {
// Export this triangle, but first collect the T-joint vertices along its edges. // Export this triangle, but first collect the T-joint vertices along its edges.
Vec3i midpoints( Vec3i midpoints(
this->triangle_midpoint(neighbors(0), vertices(1), vertices(0)), this->triangle_midpoint(neighbors(0), vertices(1), vertices(0)),
this->triangle_midpoint(neighbors(1), vertices(2), vertices(1)), this->triangle_midpoint(neighbors(1), vertices(2), vertices(1)),
@ -1406,6 +1459,11 @@ void TriangleSelector::get_facets_split_by_tjoints(const Vec3i &vertices, const
case 0: case 0:
// Just emit this triangle. // Just emit this triangle.
out_triangles.emplace_back(vertices(0), vertices(1), vertices(2)); out_triangles.emplace_back(vertices(0), vertices(1), vertices(2));
if constexpr (facet_info == AdditionalMeshInfo::Color) {
out_colors.emplace_back(color);
}
break; break;
case 1: case 1:
{ {
@ -1413,18 +1471,18 @@ void TriangleSelector::get_facets_split_by_tjoints(const Vec3i &vertices, const
int i = midpoints(0) != -1 ? 2 : midpoints(1) != -1 ? 0 : 1; int i = midpoints(0) != -1 ? 2 : midpoints(1) != -1 ? 0 : 1;
int j = next_idx_modulo(i, 3); int j = next_idx_modulo(i, 3);
int k = next_idx_modulo(j, 3); int k = next_idx_modulo(j, 3);
this->get_facets_split_by_tjoints( this->get_facets_split_by_tjoints<facet_info>(
{ vertices(i), vertices(j), midpoints(j) }, { vertices(i), vertices(j), midpoints(j) },
{ neighbors(i), { neighbors(i),
this->neighbor_child(neighbors(j), vertices(k), vertices(j), Partition::Second), this->neighbor_child(neighbors(j), vertices(k), vertices(j), Partition::Second),
-1 }, -1 },
out_triangles); color, out_triangles, out_colors);
this->get_facets_split_by_tjoints( this->get_facets_split_by_tjoints<facet_info>(
{ midpoints(j), vertices(k), vertices(i) }, { midpoints(j), vertices(k), vertices(i) },
{ this->neighbor_child(neighbors(j), vertices(k), vertices(j), Partition::First), { this->neighbor_child(neighbors(j), vertices(k), vertices(j), Partition::First),
neighbors(k), neighbors(k),
-1 }, -1 },
out_triangles); color, out_triangles, out_colors);
break; break;
} }
case 2: case 2:
@ -1433,47 +1491,53 @@ void TriangleSelector::get_facets_split_by_tjoints(const Vec3i &vertices, const
int i = midpoints(0) == -1 ? 2 : midpoints(1) == -1 ? 0 : 1; int i = midpoints(0) == -1 ? 2 : midpoints(1) == -1 ? 0 : 1;
int j = next_idx_modulo(i, 3); int j = next_idx_modulo(i, 3);
int k = next_idx_modulo(j, 3); int k = next_idx_modulo(j, 3);
this->get_facets_split_by_tjoints( this->get_facets_split_by_tjoints<facet_info>(
{ vertices(i), midpoints(i), midpoints(k) }, { vertices(i), midpoints(i), midpoints(k) },
{ this->neighbor_child(neighbors(i), vertices(j), vertices(i), Partition::Second), { this->neighbor_child(neighbors(i), vertices(j), vertices(i), Partition::Second),
-1, -1,
this->neighbor_child(neighbors(k), vertices(i), vertices(k), Partition::First) }, this->neighbor_child(neighbors(k), vertices(i), vertices(k), Partition::First) },
out_triangles); color, out_triangles, out_colors);
this->get_facets_split_by_tjoints( this->get_facets_split_by_tjoints<facet_info>(
{ midpoints(i), vertices(j), midpoints(k) }, { midpoints(i), vertices(j), midpoints(k) },
{ this->neighbor_child(neighbors(i), vertices(j), vertices(i), Partition::First), { this->neighbor_child(neighbors(i), vertices(j), vertices(i), Partition::First),
-1, -1 }, -1, -1 },
out_triangles); color, out_triangles, out_colors);
this->get_facets_split_by_tjoints( this->get_facets_split_by_tjoints<facet_info>(
{ vertices(j), vertices(k), midpoints(k) }, { vertices(j), vertices(k), midpoints(k) },
{ neighbors(j), { neighbors(j),
this->neighbor_child(neighbors(k), vertices(i), vertices(k), Partition::Second), this->neighbor_child(neighbors(k), vertices(i), vertices(k), Partition::Second),
-1 }, -1 },
out_triangles); color, out_triangles, out_colors);
break; break;
} }
default: default:
assert(splits == 3); assert(splits == 3);
// Split to 4 triangles. // Split to 4 triangles.
this->get_facets_split_by_tjoints( this->get_facets_split_by_tjoints<facet_info>(
{ vertices(0), midpoints(0), midpoints(2) }, { vertices(0), midpoints(0), midpoints(2) },
{ this->neighbor_child(neighbors(0), vertices(1), vertices(0), Partition::Second), { this->neighbor_child(neighbors(0), vertices(1), vertices(0), Partition::Second),
-1, -1,
this->neighbor_child(neighbors(2), vertices(0), vertices(2), Partition::First) }, this->neighbor_child(neighbors(2), vertices(0), vertices(2), Partition::First) },
out_triangles); color, out_triangles, out_colors);
this->get_facets_split_by_tjoints( this->get_facets_split_by_tjoints<facet_info>(
{ midpoints(0), vertices(1), midpoints(1) }, { midpoints(0), vertices(1), midpoints(1) },
{ this->neighbor_child(neighbors(0), vertices(1), vertices(0), Partition::First), { this->neighbor_child(neighbors(0), vertices(1), vertices(0), Partition::First),
this->neighbor_child(neighbors(1), vertices(2), vertices(1), Partition::Second), this->neighbor_child(neighbors(1), vertices(2), vertices(1), Partition::Second),
-1 }, -1 },
out_triangles); color, out_triangles, out_colors);
this->get_facets_split_by_tjoints( this->get_facets_split_by_tjoints<facet_info>(
{ midpoints(1), vertices(2), midpoints(2) }, { midpoints(1), vertices(2), midpoints(2) },
{ this->neighbor_child(neighbors(1), vertices(2), vertices(1), Partition::First), { this->neighbor_child(neighbors(1), vertices(2), vertices(1), Partition::First),
this->neighbor_child(neighbors(2), vertices(0), vertices(2), Partition::Second), this->neighbor_child(neighbors(2), vertices(0), vertices(2), Partition::Second),
-1 }, -1 },
out_triangles); color, out_triangles, out_colors);
out_triangles.emplace_back(midpoints); out_triangles.emplace_back(midpoints);
if constexpr (facet_info == AdditionalMeshInfo::Color) {
out_colors.emplace_back(color);
}
break; break;
} }
} }

View File

@ -313,10 +313,26 @@ public:
bool has_facets(TriangleStateType state) const; bool has_facets(TriangleStateType state) const;
static bool has_facets(const TriangleSplittingData &data, TriangleStateType test_state); static bool has_facets(const TriangleSplittingData &data, TriangleStateType test_state);
int num_facets(TriangleStateType state) const; int num_facets(TriangleStateType state) const;
// Get facets that pass the filter. Don't triangulate T-joints.
template<AdditionalMeshInfo facet_info = AdditionalMeshInfo::None>
typename IndexedTriangleSetType<facet_info>::type get_facets(const std::function<bool(const Triangle &)> &facet_filter) const;
// Get facets at a given state. Don't triangulate T-joints. // Get facets at a given state. Don't triangulate T-joints.
indexed_triangle_set get_facets(TriangleStateType state) const; indexed_triangle_set get_facets(TriangleStateType state) const;
// Get all facets. Don't triangulate T-joints.
indexed_triangle_set get_all_facets() const;
// Get all facets with information about the colors of the facets. Don't triangulate T-joints.
indexed_triangle_set_with_color get_all_facets_with_colors() const;
// Get facets that pass the filter. Triangulate T-joints.
template<AdditionalMeshInfo facet_info = AdditionalMeshInfo::None>
typename IndexedTriangleSetType<facet_info>::type get_facets_strict(const std::function<bool(const Triangle &)> &facet_filter) const;
// Get facets at a given state. Triangulate T-joints. // Get facets at a given state. Triangulate T-joints.
indexed_triangle_set get_facets_strict(TriangleStateType state) const; indexed_triangle_set get_facets_strict(TriangleStateType state) const;
// Get all facets. Triangulate T-joints.
indexed_triangle_set get_all_facets_strict() const;
// Get all facets with information about the colord of the facetd. Triangulate T-joints.
indexed_triangle_set_with_color get_all_facets_strict_with_colors() const;
// Get edges around the selected area by seed fill. // Get edges around the selected area by seed fill.
std::vector<Vec2i> get_seed_fill_contour() const; std::vector<Vec2i> get_seed_fill_contour() const;
@ -470,12 +486,16 @@ private:
bool verify_triangle_midpoints(const Triangle& tr) const; bool verify_triangle_midpoints(const Triangle& tr) const;
#endif // NDEBUG #endif // NDEBUG
template<AdditionalMeshInfo facet_info>
void get_facets_strict_recursive( void get_facets_strict_recursive(
const Triangle &tr, const Triangle &tr,
const Vec3i &neighbors, const Vec3i &neighbors,
TriangleStateType state, const std::function<bool(const Triangle &)> &facet_filter,
std::vector<stl_triangle_vertex_indices> &out_triangles) const; std::vector<stl_triangle_vertex_indices> &out_triangles,
void get_facets_split_by_tjoints(const Vec3i &vertices, const Vec3i &neighbors, std::vector<stl_triangle_vertex_indices> &out_triangles) const; std::vector<uint8_t> &out_colors) const;
template<AdditionalMeshInfo facet_info>
void get_facets_split_by_tjoints(const Vec3i &vertices, const Vec3i &neighbors, uint8_t color, std::vector<stl_triangle_vertex_indices> &out_triangles, std::vector<uint8_t> &out_colors) const;
void get_seed_fill_contour_recursive(int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector<Vec2i> &edges_out) const; void get_seed_fill_contour_recursive(int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector<Vec2i> &edges_out) const;