TriangleSelector:
1) Fixing yesterday's regression in deserialization of older painted 3MFs (order of triangle children is now reversed, thus the serialization / deserialization has to take it into account). 2) WIP extraction into facets to triangulate T-joints.
This commit is contained in:
parent
ccb53f71b6
commit
d0411223be
2 changed files with 218 additions and 18 deletions
|
@ -3,12 +3,22 @@
|
|||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifndef _NDEBUG
|
||||
#define EXPENSIVE_DEBUG_CHECKS
|
||||
#endif // DEBUG
|
||||
#endif // _NDEBUG
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
static inline Vec3i root_neighbors(const TriangleMesh &mesh, int triangle_id)
|
||||
{
|
||||
Vec3i neighbors;
|
||||
const stl_neighbors& neighbors_src = mesh.stl.neighbors_start[triangle_id];
|
||||
for (int i = 0; i < 3; ++i)
|
||||
// Refuse a neighbor with a flipped normal.
|
||||
neighbors(i) = neighbors_src.neighbor[i];
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
#ifndef _NDEBUG
|
||||
bool TriangleSelector::verify_triangle_midpoints(const Triangle &tr) const
|
||||
{
|
||||
|
@ -137,7 +147,7 @@ void TriangleSelector::seed_fill_select_triangles(const Vec3f& hit, int facet_st
|
|||
if (current_facet < m_orig_size_indices)
|
||||
// Propagate over the original triangles.
|
||||
for (int neighbor_idx : m_mesh->stl.neighbors_start[current_facet].neighbor) {
|
||||
assert(neighbor_idx >= 0);
|
||||
assert(neighbor_idx >= -1);
|
||||
if (neighbor_idx >= 0 && !visited[neighbor_idx]) {
|
||||
// Check if neighbour_facet_idx is satisfies angle in seed_fill_angle and append it to facet_queue if it do.
|
||||
const Vec3f &n1 = m_mesh->stl.facet_start[m_triangles[neighbor_idx].source_triangle].normal;
|
||||
|
@ -163,10 +173,7 @@ bool TriangleSelector::select_triangle(int facet_idx, EnforcerBlockerType type,
|
|||
if (! m_triangles[facet_idx].valid())
|
||||
return false;
|
||||
|
||||
Vec3i neighbors;
|
||||
const stl_neighbors &neighbors_src = m_mesh->stl.neighbors_start[facet_idx];
|
||||
for (int i = 0; i < 3; ++ i)
|
||||
neighbors(i) = neighbors_src.neighbor[i];
|
||||
Vec3i neighbors = root_neighbors(*m_mesh, facet_idx);
|
||||
assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
|
||||
|
||||
if (! select_triangle_recursive(facet_idx, neighbors, type, triangle_splitting))
|
||||
|
@ -863,6 +870,23 @@ void TriangleSelector::perform_split(int facet_idx, const Vec3i &neighbors, Enfo
|
|||
#endif // _NDEBUG
|
||||
}
|
||||
|
||||
bool TriangleSelector::has_facets(EnforcerBlockerType state) const
|
||||
{
|
||||
for (const Triangle& tr : m_triangles)
|
||||
if (tr.valid() && ! tr.is_split() && tr.get_state() == state)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int TriangleSelector::num_facets(EnforcerBlockerType state) const
|
||||
{
|
||||
int cnt = 0;
|
||||
for (const Triangle& tr : m_triangles)
|
||||
if (tr.valid() && ! tr.is_split() && tr.get_state() == state)
|
||||
++ cnt;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
indexed_triangle_set TriangleSelector::get_facets(EnforcerBlockerType state) const
|
||||
{
|
||||
indexed_triangle_set out;
|
||||
|
@ -884,7 +908,121 @@ indexed_triangle_set TriangleSelector::get_facets(EnforcerBlockerType state) con
|
|||
return out;
|
||||
}
|
||||
|
||||
indexed_triangle_set TriangleSelector::get_facets_strict(EnforcerBlockerType state) const
|
||||
{
|
||||
indexed_triangle_set out;
|
||||
|
||||
size_t num_vertices = 0;
|
||||
for (const Vertex &v : m_vertices)
|
||||
if (v.ref_cnt > 0)
|
||||
++ num_vertices;
|
||||
out.vertices.reserve(num_vertices);
|
||||
std::vector<int> vertex_map(m_vertices.size(), -1);
|
||||
for (int i = 0; i < m_vertices.size(); ++ i)
|
||||
if (const Vertex &v = m_vertices[i]; v.ref_cnt > 0) {
|
||||
vertex_map[i] = int(out.vertices.size());
|
||||
out.vertices.emplace_back(v.v);
|
||||
}
|
||||
|
||||
for (int itriangle = 0; itriangle < m_orig_size_indices; ++ itriangle)
|
||||
this->get_facets_strict_recursive(m_triangles[itriangle], root_neighbors(*m_mesh, itriangle), state, out.indices);
|
||||
|
||||
for (auto &triangle : out.indices)
|
||||
for (int i = 0; i < 3; ++ i)
|
||||
triangle(i) = vertex_map[triangle(i)];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void TriangleSelector::get_facets_strict_recursive(
|
||||
const Triangle &tr,
|
||||
const Vec3i &neighbors,
|
||||
EnforcerBlockerType state,
|
||||
std::vector<stl_triangle_vertex_indices> &out_triangles) const
|
||||
{
|
||||
if (tr.is_split()) {
|
||||
for (int i = 0; i <= tr.number_of_split_sides(); ++ i)
|
||||
this->get_facets_strict_recursive(
|
||||
m_triangles[tr.children[i]],
|
||||
this->child_neighbors(tr, neighbors, i),
|
||||
state, out_triangles);
|
||||
} else if (tr.get_state() == state)
|
||||
this->get_facets_split_by_tjoints({tr.verts_idxs[0], tr.verts_idxs[1], tr.verts_idxs[2]}, neighbors, out_triangles);
|
||||
}
|
||||
|
||||
void TriangleSelector::get_facets_split_by_tjoints(const Vec3i vertices, const Vec3i neighbors, std::vector<stl_triangle_vertex_indices> &out_triangles) const
|
||||
{
|
||||
// Export this triangle, but first collect the T-joint vertices along its edges.
|
||||
Vec3i midpoints(
|
||||
this->triangle_midpoint(neighbors(0), vertices(1), vertices(0)),
|
||||
this->triangle_midpoint(neighbors(1), vertices(2), vertices(1)),
|
||||
this->triangle_midpoint(neighbors(2), vertices(0), vertices(2)));
|
||||
int splits = (midpoints(0) != -1) + (midpoints(1) != -1) + (midpoints(2) != -1);
|
||||
if (splits == 0) {
|
||||
// Just emit this triangle.
|
||||
out_triangles.emplace_back(vertices(0), midpoints(0), midpoints(2));
|
||||
} else if (splits == 1) {
|
||||
// Split to two triangles
|
||||
int i = midpoints(0) != -1 ? 2 : midpoints(1) != -1 ? 0 : 1;
|
||||
int j = next_idx_modulo(i, 3);
|
||||
int k = next_idx_modulo(j, 3);
|
||||
this->get_facets_split_by_tjoints(
|
||||
{ vertices(i), vertices(j), midpoints(j) },
|
||||
{ neighbors(i),
|
||||
this->neighbor_child(neighbors(j), vertices(j), vertices(k), Partition::Second),
|
||||
-1 },
|
||||
out_triangles);
|
||||
this->get_facets_split_by_tjoints(
|
||||
{ midpoints(j), vertices(j), vertices(k) },
|
||||
{ this->neighbor_child(neighbors(j), vertices(j), vertices(k), Partition::First),
|
||||
neighbors(k),
|
||||
-1 },
|
||||
out_triangles);
|
||||
} else if (splits == 2) {
|
||||
// Split to three triangles.
|
||||
int i = midpoints(0) == -1 ? 2 : midpoints(1) == -1 ? 0 : 1;
|
||||
int j = next_idx_modulo(i, 3);
|
||||
int k = next_idx_modulo(j, 3);
|
||||
this->get_facets_split_by_tjoints(
|
||||
{ vertices(i), midpoints(i), midpoints(k) },
|
||||
{ this->neighbor_child(neighbors(i), vertices(j), vertices(i), Partition::Second),
|
||||
-1,
|
||||
this->neighbor_child(neighbors(k), vertices(i), vertices(k), Partition::First) },
|
||||
out_triangles);
|
||||
this->get_facets_split_by_tjoints(
|
||||
{ midpoints(i), vertices(j), midpoints(k) },
|
||||
{ this->neighbor_child(neighbors(i), vertices(j), vertices(i), Partition::First),
|
||||
-1, -1 },
|
||||
out_triangles);
|
||||
this->get_facets_split_by_tjoints(
|
||||
{ vertices(j), vertices(k), midpoints(k) },
|
||||
{ neighbors(j),
|
||||
this->neighbor_child(neighbors(k), vertices(i), vertices(k), Partition::Second),
|
||||
-1 },
|
||||
out_triangles);
|
||||
} else if (splits == 4) {
|
||||
// Split to 4 triangles.
|
||||
this->get_facets_split_by_tjoints(
|
||||
{ vertices(0), midpoints(0), midpoints(2) },
|
||||
{ this->neighbor_child(neighbors(0), vertices(1), vertices(0), Partition::Second),
|
||||
-1,
|
||||
this->neighbor_child(neighbors(2), vertices(0), vertices(2), Partition::First) },
|
||||
out_triangles);
|
||||
this->get_facets_split_by_tjoints(
|
||||
{ midpoints(0), vertices(1), midpoints(1) },
|
||||
{ this->neighbor_child(neighbors(0), vertices(1), vertices(0), Partition::First),
|
||||
this->neighbor_child(neighbors(1), vertices(2), vertices(1), Partition::Second),
|
||||
-1 },
|
||||
out_triangles);
|
||||
this->get_facets_split_by_tjoints(
|
||||
{ midpoints(1), vertices(2), midpoints(2) },
|
||||
{ this->neighbor_child(neighbors(1), vertices(2), vertices(1), Partition::First),
|
||||
this->neighbor_child(neighbors(2), vertices(0), vertices(2), Partition::Second),
|
||||
-1 },
|
||||
out_triangles);
|
||||
out_triangles.emplace_back(midpoints);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> TriangleSelector::serialize() const
|
||||
{
|
||||
|
@ -924,7 +1062,8 @@ std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> TriangleSelector:
|
|||
data.second.push_back(tr.special_side() & 0b01);
|
||||
data.second.push_back(tr.special_side() & 0b10);
|
||||
// Now save all children.
|
||||
for (int child_idx = 0; child_idx <= split_sides; ++child_idx)
|
||||
// Serialized in reverse order for compatibility with PrusaSlicer 2.3.1.
|
||||
for (int child_idx = split_sides; child_idx >= 0; -- child_idx)
|
||||
this->serialize(tr.children[child_idx]);
|
||||
} else {
|
||||
// In case this is leaf, we better save information about its state.
|
||||
|
@ -1005,10 +1144,7 @@ void TriangleSelector::deserialize(const std::pair<std::vector<std::pair<int, in
|
|||
if (is_split) {
|
||||
// root is split, add it into list of parents and split it.
|
||||
// then go to the next.
|
||||
Vec3i neighbors;
|
||||
const stl_neighbors& neighbors_src = m_mesh->stl.neighbors_start[triangle_id];
|
||||
for (int i = 0; i < 3; ++i)
|
||||
neighbors(i) = neighbors_src.neighbor[i];
|
||||
Vec3i neighbors = root_neighbors(*m_mesh, triangle_id);
|
||||
parents.push_back({triangle_id, neighbors, 0, num_of_children});
|
||||
m_triangles[triangle_id].set_division(num_of_split_sides, special_side);
|
||||
perform_split(triangle_id, neighbors, EnforcerBlockerType::NONE);
|
||||
|
@ -1024,18 +1160,19 @@ void TriangleSelector::deserialize(const std::pair<std::vector<std::pair<int, in
|
|||
assert(! parents.empty());
|
||||
assert(parents.back().processed_children < parents.back().total_children);
|
||||
|
||||
if (ProcessingInfo& last = parents.back(); is_split) {
|
||||
if (ProcessingInfo& last = parents.back(); is_split) {
|
||||
// split the triangle and save it as parent of the next ones.
|
||||
const Triangle &tr = m_triangles[last.facet_id];
|
||||
//FIXME calculate neighbor triangles from last.neighbors and last.processed_children.
|
||||
Vec3i neighbors = this->child_neighbors(tr, last.neighbors, last.processed_children);
|
||||
int this_idx = tr.children[last.processed_children];
|
||||
int child_idx = last.total_children - last.processed_children - 1;
|
||||
Vec3i neighbors = this->child_neighbors(tr, last.neighbors, child_idx);
|
||||
int this_idx = tr.children[child_idx];
|
||||
m_triangles[this_idx].set_division(num_of_split_sides, special_side);
|
||||
perform_split(this_idx, neighbors, EnforcerBlockerType::NONE);
|
||||
parents.push_back({this_idx, neighbors, 0, num_of_children});
|
||||
} else {
|
||||
// this triangle belongs to last split one
|
||||
m_triangles[m_triangles[last.facet_id].children[last.processed_children]].set_state(state);
|
||||
int child_idx = last.total_children - last.processed_children - 1;
|
||||
m_triangles[m_triangles[last.facet_id].children[child_idx]].set_state(state);
|
||||
++last.processed_children;
|
||||
}
|
||||
|
||||
|
@ -1058,6 +1195,57 @@ void TriangleSelector::deserialize(const std::pair<std::vector<std::pair<int, in
|
|||
}
|
||||
}
|
||||
|
||||
// Lightweight variant of deserialization, which only tests whether a face of test_state exists.
|
||||
bool TriangleSelector::has_facets(const std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> &data, const EnforcerBlockerType test_state)
|
||||
{
|
||||
// Depth-first queue of a number of unvisited children.
|
||||
// Kept outside of the loop to avoid re-allocating inside the loop.
|
||||
std::vector<int> parents_children;
|
||||
parents_children.reserve(64);
|
||||
|
||||
for (auto [triangle_id, ibit] : data.first) {
|
||||
assert(ibit < data.second.size());
|
||||
auto next_nibble = [&data, &ibit = ibit]() {
|
||||
int n = 0;
|
||||
for (int i = 0; i < 4; ++ i)
|
||||
n |= data.second[ibit ++] << i;
|
||||
return n;
|
||||
};
|
||||
// < 0 -> negative of a number of children
|
||||
// >= 0 -> state
|
||||
auto num_children_or_state = [&next_nibble]() -> int {
|
||||
int code = next_nibble();
|
||||
int num_of_split_sides = code & 0b11;
|
||||
return num_of_split_sides == 0 ?
|
||||
((code & 0b1100) == 0b1100 ? next_nibble() + 3 : code >> 2) :
|
||||
- num_of_split_sides - 1;
|
||||
};
|
||||
|
||||
int state = num_children_or_state();
|
||||
if (state < 0) {
|
||||
// Root is split.
|
||||
parents_children.clear();
|
||||
parents_children.emplace_back(- state);
|
||||
do {
|
||||
if (-- parents_children.back() >= 0) {
|
||||
int state = num_children_or_state();
|
||||
if (state < 0)
|
||||
// Child is split.
|
||||
parents_children.emplace_back(- state);
|
||||
else if (state == int(test_state))
|
||||
// Child is not split and a face of test_state was found.
|
||||
return true;
|
||||
} else
|
||||
parents_children.pop_back();
|
||||
} while (! parents_children.empty());
|
||||
} else if (state == int(test_state))
|
||||
// Root is not split and a face of test_state was found.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TriangleSelector::seed_fill_unselect_all_triangles()
|
||||
{
|
||||
for (Triangle &triangle : m_triangles)
|
||||
|
|
|
@ -43,8 +43,13 @@ public:
|
|||
int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to
|
||||
float seed_fill_angle); // the maximal angle between two facets to be painted by the same color
|
||||
|
||||
// Get facets currently in the given state.
|
||||
bool has_facets(EnforcerBlockerType state) const;
|
||||
static bool has_facets(const std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> &data, const EnforcerBlockerType test_state);
|
||||
int num_facets(EnforcerBlockerType state) const;
|
||||
// Get facets at a given state. Don't triangulate T-joints.
|
||||
indexed_triangle_set get_facets(EnforcerBlockerType state) const;
|
||||
// Get facets at a given state. Triangulate T-joints.
|
||||
indexed_triangle_set get_facets_strict(EnforcerBlockerType state) const;
|
||||
|
||||
// Set facet of the mesh to a given state. Only works for original triangles.
|
||||
void set_facet(int facet_idx, EnforcerBlockerType state);
|
||||
|
@ -204,6 +209,13 @@ private:
|
|||
bool verify_triangle_midpoints(const Triangle& tr) const;
|
||||
#endif // _NDEBUG
|
||||
|
||||
void get_facets_strict_recursive(
|
||||
const Triangle &tr,
|
||||
const Vec3i &neighbors,
|
||||
EnforcerBlockerType state,
|
||||
std::vector<stl_triangle_vertex_indices> &out_triangles) const;
|
||||
void get_facets_split_by_tjoints(const Vec3i vertices, const Vec3i neighbors, std::vector<stl_triangle_vertex_indices> &out_triangles) const;
|
||||
|
||||
int m_free_triangles_head { -1 };
|
||||
int m_free_vertices_head { -1 };
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue