diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index c9f253d88..ad823c55d 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -228,7 +228,7 @@ void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_st } } -void TriangleSelector::precompute_all_level_neighbors_recursive(const int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector<Vec3i> &neighbors_out) const +void TriangleSelector::precompute_all_neighbors_recursive(const int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector<Vec3i> &neighbors_out, std::vector<Vec3i> &neighbors_propagated_out) const { assert(facet_idx < int(m_triangles.size())); @@ -236,7 +236,8 @@ void TriangleSelector::precompute_all_level_neighbors_recursive(const int facet_ if (!tr->valid()) return; - neighbors_out[facet_idx] = neighbors_propagated; + neighbors_out[facet_idx] = neighbors; + neighbors_propagated_out[facet_idx] = neighbors_propagated; if (tr->is_split()) { assert(this->verify_triangle_neighbors(*tr, neighbors)); @@ -247,67 +248,51 @@ void TriangleSelector::precompute_all_level_neighbors_recursive(const int facet_ assert(tr->children[i] < int(m_triangles.size())); // Recursion, deep first search over the children of this triangle. // All children of this triangle were created by splitting a single source triangle of the original mesh. - this->precompute_all_level_neighbors_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), this->child_neighbors_propagated(*tr, neighbors_propagated, i), neighbors_out); + this->precompute_all_neighbors_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), + this->child_neighbors_propagated(*tr, neighbors_propagated, i), neighbors_out, + neighbors_propagated_out); } } } } -std::vector<Vec3i> TriangleSelector::precompute_all_level_neighbors() const +std::pair<std::vector<Vec3i>, std::vector<Vec3i>> TriangleSelector::precompute_all_neighbors() const { std::vector<Vec3i> neighbors(m_triangles.size(), Vec3i(-1, -1, -1)); + std::vector<Vec3i> neighbors_propagated(m_triangles.size(), Vec3i(-1, -1, -1)); for (int facet_idx = 0; facet_idx < this->m_orig_size_indices; ++facet_idx) { - neighbors[facet_idx] = root_neighbors(*m_mesh, facet_idx); + neighbors[facet_idx] = root_neighbors(*m_mesh, facet_idx); + neighbors_propagated[facet_idx] = neighbors[facet_idx]; assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors[facet_idx])); if (m_triangles[facet_idx].is_split()) - this->precompute_all_level_neighbors_recursive(facet_idx, neighbors[facet_idx], neighbors[facet_idx], neighbors); + this->precompute_all_neighbors_recursive(facet_idx, neighbors[facet_idx], neighbors_propagated[facet_idx], neighbors, neighbors_propagated); } - return neighbors; + return std::make_pair(std::move(neighbors), std::move(neighbors_propagated)); } -bool TriangleSelector::are_triangles_touching(const int first_facet_idx, const int second_facet_idx) const +// It appends all triangles that are touching the edge (vertexi, vertexj) of the triangle. +// It doesn't append the triangles that are touching the triangle only by part of the edge that means the triangles are from lower depth. +void TriangleSelector::append_touching_subtriangles(int itriangle, int vertexi, int vertexj, std::vector<int> &touching_subtriangles_out) const { - std::array<Linef3, 3> sides_facet = {Linef3(m_vertices[m_triangles[first_facet_idx].verts_idxs[0]].v.cast<double>(), m_vertices[m_triangles[first_facet_idx].verts_idxs[1]].v.cast<double>()), - Linef3(m_vertices[m_triangles[first_facet_idx].verts_idxs[1]].v.cast<double>(), m_vertices[m_triangles[first_facet_idx].verts_idxs[2]].v.cast<double>()), - Linef3(m_vertices[m_triangles[first_facet_idx].verts_idxs[2]].v.cast<double>(), m_vertices[m_triangles[first_facet_idx].verts_idxs[0]].v.cast<double>())}; + if (itriangle == -1) + return; - const Vec3d p0 = m_vertices[m_triangles[second_facet_idx].verts_idxs[0]].v.cast<double>(); - const Vec3d p1 = m_vertices[m_triangles[second_facet_idx].verts_idxs[1]].v.cast<double>(); - const Vec3d p2 = m_vertices[m_triangles[second_facet_idx].verts_idxs[2]].v.cast<double>(); + auto process_subtriangle = [this, &itriangle, &vertexi, &vertexj, &touching_subtriangles_out](const int subtriangle_idx) -> void { + assert(subtriangle_idx == -1); + if (!m_triangles[subtriangle_idx].is_split()) + touching_subtriangles_out.emplace_back(subtriangle_idx); + else if (int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj); midpoint != -1) + append_touching_subtriangles(subtriangle_idx, vertexi, midpoint, touching_subtriangles_out); + else + append_touching_subtriangles(subtriangle_idx, vertexi, vertexj, touching_subtriangles_out); + }; - for (size_t idx = 0; idx < 3; ++idx) - if (line_alg::distance_to_squared(sides_facet[idx], p0) <= EPSILON && (line_alg::distance_to_squared(sides_facet[idx], p1) <= EPSILON || line_alg::distance_to_squared(sides_facet[idx], p2) <= EPSILON)) - return true; - else if (line_alg::distance_to_squared(sides_facet[idx], p1) <= EPSILON && line_alg::distance_to_squared(sides_facet[idx], p2) <= EPSILON) - return true; + std::pair<int, int> touching = this->triangle_subtriangles(itriangle, vertexi, vertexj); + if (touching.first != -1) + process_subtriangle(touching.first); - return false; -} - -std::vector<int> TriangleSelector::neighboring_triangles(const int first_facet_idx, const int second_facet_idx, EnforcerBlockerType second_facet_state) const -{ - assert(first_facet_idx < int(m_triangles.size())); - - const Triangle *tr = &m_triangles[first_facet_idx]; - if (!tr->valid()) - return {}; - - if (!tr->is_split() && tr->get_state() == second_facet_state && (are_triangles_touching(second_facet_idx, first_facet_idx) || are_triangles_touching(first_facet_idx, second_facet_idx))) - return {first_facet_idx}; - - std::vector<int> neighbor_facets_out; - int num_of_children = tr->number_of_split_sides() + 1; - if (num_of_children != 1) { - for (int i = 0; i < num_of_children; ++i) { - assert(i < int(tr->children.size())); - assert(tr->children[i] < int(m_triangles.size())); - - if (std::vector<int> neighbor_facets = neighboring_triangles(tr->children[i], second_facet_idx, second_facet_state); !neighbor_facets.empty()) - Slic3r::append(neighbor_facets_out, std::move(neighbor_facets)); - } - } - - return neighbor_facets_out; + if (touching.second != -1) + process_subtriangle(touching.second); } void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_start, bool propagate) @@ -326,7 +311,23 @@ void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_ return; } - std::vector<Vec3i> all_level_neighbors = this->precompute_all_level_neighbors(); + auto get_all_touching_triangles = [this](int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated) -> std::vector<int> { + assert(facet_idx != -1 && facet_idx < m_triangles.size()); + assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors)); + std::vector<int> touching_triangles; + Vec3i vertices = {m_triangles[facet_idx].verts_idxs[0], m_triangles[facet_idx].verts_idxs[1], m_triangles[facet_idx].verts_idxs[2]}; + append_touching_subtriangles(neighbors(0), vertices(1), vertices(0), touching_triangles); + append_touching_subtriangles(neighbors(1), vertices(2), vertices(1), touching_triangles); + append_touching_subtriangles(neighbors(2), vertices(0), vertices(2), touching_triangles); + + for (int neighbor_idx : neighbors_propagated) + if (neighbor_idx != -1 && !m_triangles[neighbor_idx].is_split()) + touching_triangles.emplace_back(neighbor_idx); + + return touching_triangles; + }; + + auto [neighbors, neighbors_propagated] = this->precompute_all_neighbors(); std::vector<bool> visited(m_triangles.size(), false); std::queue<int> facet_queue; @@ -338,17 +339,14 @@ void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_ if (!visited[current_facet]) { m_triangles[current_facet].select_by_seed_fill(); - for (int neighbor_idx : all_level_neighbors[current_facet]) { - if (neighbor_idx < 0 || visited[neighbor_idx]) + + std::vector<int> touching_triangles = get_all_touching_triangles(current_facet, neighbors[current_facet], neighbors_propagated[current_facet]); + for(const int tr_idx : touching_triangles) { + if (tr_idx < 0 || visited[tr_idx] || m_triangles[tr_idx].get_state() != start_facet_state) continue; - if (!m_triangles[neighbor_idx].is_split()) { - if (m_triangles[neighbor_idx].get_state() == start_facet_state) - facet_queue.push(neighbor_idx); - } else { - for (int neighbor_facet_idx : neighboring_triangles(neighbor_idx, current_facet, start_facet_state)) - facet_queue.push(neighbor_facet_idx); - } + assert(!m_triangles[tr_idx].is_split()); + facet_queue.push(tr_idx); } } @@ -437,6 +435,40 @@ int TriangleSelector::neighbor_child(int itriangle, int vertexi, int vertexj, Pa return itriangle == -1 ? -1 : this->neighbor_child(m_triangles[itriangle], vertexi, vertexj, partition); } +std::pair<int, int> TriangleSelector::triangle_subtriangles(int itriangle, int vertexi, int vertexj) const +{ + return itriangle == -1 ? std::make_pair(-1, -1) : this->triangle_subtriangles(m_triangles[itriangle], vertexi, vertexj); +} + +std::pair<int, int> TriangleSelector::triangle_subtriangles(const Triangle &tr, int vertexi, int vertexj) +{ + if (tr.number_of_split_sides() == 0) + // If this triangle is not split, then there is no subtriangles touching the edge. + return std::make_pair(-1, -1); + + // Find the triangle edge. + int edge = tr.verts_idxs[0] == vertexi ? 0 : tr.verts_idxs[1] == vertexi ? 1 : 2; + assert(tr.verts_idxs[edge] == vertexi); + assert(tr.verts_idxs[next_idx_modulo(edge, 3)] == vertexj); + + if (tr.number_of_split_sides() == 1) { + return edge == next_idx_modulo(tr.special_side(), 3) ? std::make_pair(tr.children[0], tr.children[1]) : + std::make_pair(tr.children[edge == tr.special_side() ? 0 : 1], -1); + } else if (tr.number_of_split_sides() == 2) { + return edge == next_idx_modulo(tr.special_side(), 3) ? std::make_pair(tr.children[2], -1) : + edge == tr.special_side() ? std::make_pair(tr.children[0], tr.children[1]) : + std::make_pair(tr.children[2], tr.children[0]); + } else { + assert(tr.number_of_split_sides() == 3); + assert(tr.special_side() == 0); + return edge == 0 ? std::make_pair(tr.children[0], tr.children[1]) : + edge == 1 ? std::make_pair(tr.children[1], tr.children[2]) : + std::make_pair(tr.children[2], tr.children[0]); + } + + return std::make_pair(-1, -1); +} + // Return existing midpoint of CCW oriented side (vertexi, vertexj). // If itriangle == -1 or if the side sharing (vertexi, vertexj) is not split, return -1. int TriangleSelector::triangle_midpoint(const Triangle &tr, int vertexi, int vertexj) const @@ -524,12 +556,8 @@ Vec3i TriangleSelector::child_neighbors(const Triangle &tr, const Vec3i &neighbo assert(child_idx >= 0 && child_idx <= tr.number_of_split_sides()); int i = tr.special_side(); - int j = i + 1; - if (j >= 3) - j = 0; - int k = j + 1; - if (k >= 3) - k = 0; + int j = next_idx_modulo(i, 3); + int k = next_idx_modulo(j, 3); Vec3i out; switch (tr.number_of_split_sides()) { @@ -612,23 +640,28 @@ Vec3i TriangleSelector::child_neighbors(const Triangle &tr, const Vec3i &neighbo Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors, int child_idx) const { int i = tr.special_side(); - int j = i + 1; - if (j >= 3) j = 0; - int k = j + 1; - if (k >= 3) k = 0; + int j = next_idx_modulo(i, 3); + int k = next_idx_modulo(j, 3); Vec3i out; + auto replace_if_not_exists = [&out](int index_to_replace, int neighbor) { + if (out(index_to_replace) == -1) + out(index_to_replace) = neighbor; + }; + switch (tr.number_of_split_sides()) { case 1: switch (child_idx) { case 0: out(0) = neighbors(i); - out(1) = neighbors(j); + out(1) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::Second); + replace_if_not_exists(1, neighbors(j)); out(2) = tr.children[1]; break; default: assert(child_idx == 1); - out(0) = neighbors(j); + out(0) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::First); + replace_if_not_exists(0, neighbors(j)); out(1) = neighbors(k); out(2) = tr.children[0]; break; @@ -638,20 +671,24 @@ Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec case 2: switch (child_idx) { case 0: - out(0) = neighbors(i); + out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::Second); + replace_if_not_exists(0, neighbors(i)); out(1) = tr.children[1]; - out(2) = neighbors(k); + out(2) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::First); + replace_if_not_exists(2, neighbors(k)); break; case 1: assert(child_idx == 1); - out(0) = neighbors(i); + out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::First); + replace_if_not_exists(0, neighbors(i)); out(1) = tr.children[2]; out(2) = tr.children[0]; break; default: assert(child_idx == 2); out(0) = neighbors(j); - out(1) = neighbors(k); + out(1) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::Second); + replace_if_not_exists(1, neighbors(k)); out(2) = tr.children[1]; break; } @@ -661,18 +698,24 @@ Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec assert(tr.special_side() == 0); switch (child_idx) { case 0: - out(0) = neighbors(0); + out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::Second); + replace_if_not_exists(0, neighbors(0)); out(1) = tr.children[3]; - out(2) = neighbors(2); + out(2) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::First); + replace_if_not_exists(2, neighbors(2)); break; case 1: - out(0) = neighbors(0); - out(1) = neighbors(1); + out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::First); + replace_if_not_exists(0, neighbors(0)); + out(1) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::Second); + replace_if_not_exists(1, neighbors(1)); out(2) = tr.children[3]; break; case 2: - out(0) = neighbors(1); - out(1) = neighbors(2); + out(0) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::First); + replace_if_not_exists(0, neighbors(1)); + out(1) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::Second); + replace_if_not_exists(1, neighbors(2)); out(2) = tr.children[3]; break; default: @@ -886,13 +929,13 @@ void TriangleSelector::undivide_triangle(int facet_idx) Triangle& tr = m_triangles[facet_idx]; 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) { int child = tr.children[i]; Triangle &child_tr = m_triangles[child]; assert(child_tr.valid()); undivide_triangle(child); - for (int i = 0; i < 3; ++ i) { - int iv = child_tr.verts_idxs[i]; + for (int j = 0; j < 3; ++j) { + int iv = child_tr.verts_idxs[j]; Vertex &v = m_vertices[iv]; assert(v.ref_cnt > 0); if (-- v.ref_cnt == 0) { @@ -1231,7 +1274,7 @@ void TriangleSelector::get_facets_strict_recursive( 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 +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( diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index b0fbabaed..eeb479dee 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -22,8 +22,8 @@ public: POINTER }; - [[nodiscard]] std::vector<Vec3i> precompute_all_level_neighbors() const; - void precompute_all_level_neighbors_recursive(const int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector<Vec3i> &neighbors_out) const; + std::pair<std::vector<Vec3i>, std::vector<Vec3i>> precompute_all_neighbors() const; + void precompute_all_neighbors_recursive(int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector<Vec3i> &neighbors_out, std::vector<Vec3i> &neighbors_normal_out) const; // Set a limit to the edge length, below which the edge will not be split by select_patch(). // Called by select_patch() internally. Made public for debugging purposes, see TriangleSelectorGUI::render_debug(). @@ -37,10 +37,6 @@ public: [[nodiscard]] int select_unsplit_triangle(const Vec3f &hit, int facet_idx) const; [[nodiscard]] int select_unsplit_triangle(const Vec3f &hit, int facet_idx, const Vec3i &neighbors) const; - [[nodiscard]] bool are_triangles_touching(int first_facet_idx, int second_facet_idx) const; - - [[nodiscard]] std::vector<int> neighboring_triangles(int first_facet_idx, int second_facet_idx, EnforcerBlockerType second_facet_state) const; - // Select all triangles fully inside the circle, subdivide where needed. void select_patch(const Vec3f &hit, // point where to start int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to @@ -60,7 +56,7 @@ public: bool propagate); // if bucket fill is propagated to neighbor faces or if it fills the only facet of the modified mesh that the hit point belongs to. 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); + static bool has_facets(const std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> &data, 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; @@ -128,11 +124,11 @@ protected: bool is_selected_by_seed_fill() const { assert(! is_split()); return m_selected_by_seed_fill; } // Is this triangle valid or marked to be removed? - bool valid() const throw() { return m_valid; } + bool valid() const noexcept { return m_valid; } // Get info on how it's split. - bool is_split() const throw() { return number_of_split_sides() != 0; } - int number_of_split_sides() const throw() { return number_of_splits; } - int special_side() const throw() { assert(is_split()); return special_side_idx; } + bool is_split() const noexcept { return number_of_split_sides() != 0; } + int number_of_split_sides() const noexcept { return number_of_splits; } + int special_side() const noexcept { assert(is_split()); return special_side_idx; } private: friend TriangleSelector; @@ -205,7 +201,7 @@ private: void remove_useless_children(int facet_idx); // No hidden meaning. Triangles are meant. bool is_pointer_in_triangle(int facet_idx) const; bool is_edge_inside_cursor(int facet_idx) const; - int push_triangle(int a, int b, int c, int source_triangle, const EnforcerBlockerType state = EnforcerBlockerType{0}); + int push_triangle(int a, int b, int c, int source_triangle, EnforcerBlockerType state = EnforcerBlockerType{0}); void perform_split(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType old_state); Vec3i child_neighbors(const Triangle &tr, const Vec3i &neighbors, int child_idx) const; Vec3i child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors, int child_idx) const; @@ -221,6 +217,11 @@ private: int triangle_midpoint(int itriangle, int vertexi, int vertexj) const; int triangle_midpoint_or_allocate(int itriangle, int vertexi, int vertexj); + static std::pair<int, int> triangle_subtriangles(const Triangle &tr, int vertexi, int vertexj); + std::pair<int, int> triangle_subtriangles(int itriangle, int vertexi, int vertexj) const; + + void append_touching_subtriangles(int itriangle, int vertexi, int vertexj, std::vector<int> &touching_subtriangles_out) const; + #ifndef NDEBUG bool verify_triangle_neighbors(const Triangle& tr, const Vec3i& neighbors) const; bool verify_triangle_midpoints(const Triangle& tr) const; @@ -231,7 +232,7 @@ private: 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; + 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 };