From 5b67fafb75f6cc20c9e3b738756bb032ba0c1b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Mon, 19 Jul 2021 10:24:38 +0200 Subject: [PATCH 1/2] Fixed a crash in the multi-material gizmo when bucket fill is selected. --- src/libslic3r/TriangleSelector.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index b64bef17a..e7be260f6 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -333,6 +333,9 @@ 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]) + continue; + if(!m_triangles[neighbor_idx].is_split()) { if(m_triangles[neighbor_idx].get_state() == start_facet_state) facet_queue.push(neighbor_idx); From 5405ab19866114c7159fb7c47033af48b44cc357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Mon, 19 Jul 2021 11:15:04 +0200 Subject: [PATCH 2/2] Optimized seed fill and bucket fill selection to recompute selection only in case the cursor is pointing on a non-selected triangle. --- src/libslic3r/TriangleSelector.cpp | 63 ++++++++++++++++-------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index e7be260f6..a349fe35a 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -65,8 +65,8 @@ void TriangleSelector::Triangle::set_division(int sides_to_split, int special_si assert(sides_to_split >= 0 && sides_to_split <= 3); assert(special_side_idx >= 0 && special_side_idx < 3); assert(sides_to_split == 1 || sides_to_split == 2 || special_side_idx == 0); - this->number_of_splits = sides_to_split; - this->special_side_idx = special_side_idx; + this->number_of_splits = char(sides_to_split); + this->special_side_idx = char(special_side_idx); } inline bool is_point_inside_triangle(const Vec3f &pt, const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) @@ -167,8 +167,7 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, if (! visited[facet]) { if (select_triangle(facet, new_state, triangle_splitting)) { // add neighboring facets to list to be proccessed later - for (int n=0; n<3; ++n) { - int neighbor_idx = m_mesh->stl.neighbors_start[facet].neighbor[n]; + for (int neighbor_idx : m_mesh->stl.neighbors_start[facet].neighbor) { if (neighbor_idx >=0 && (m_cursor.type == SPHERE || faces_camera(neighbor_idx))) facets_to_check.push_back(neighbor_idx); } @@ -182,6 +181,11 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start, void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_start, float seed_fill_angle) { assert(facet_start < m_orig_size_indices); + + // Recompute seed fill only if the cursor is pointing on facet unselected by seed fill. + if (int start_facet_idx = select_unsplit_triangle(hit, facet_start); start_facet_idx >= 0 && m_triangles[start_facet_idx].is_selected_by_seed_fill()) + return; + this->seed_fill_unselect_all_triangles(); std::vector visited(m_triangles.size(), false); @@ -308,13 +312,15 @@ std::vector TriangleSelector::neighboring_triangles(const int first_facet_i void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_start, bool propagate) { - this->seed_fill_unselect_all_triangles(); - - int start_facet_idx = select_unsplit_triangle(hit, facet_start); - EnforcerBlockerType start_facet_state = m_triangles[start_facet_idx].get_state(); - if (start_facet_idx == -1) + int start_facet_idx = select_unsplit_triangle(hit, facet_start); + // Recompute bucket fill only if the cursor is pointing on facet unselected by bucket fill. + if (start_facet_idx == -1 || m_triangles[start_facet_idx].is_selected_by_seed_fill()) return; + assert(!m_triangles[start_facet_idx].is_split()); + EnforcerBlockerType start_facet_state = m_triangles[start_facet_idx].get_state(); + this->seed_fill_unselect_all_triangles(); + if (!propagate) { m_triangles[start_facet_idx].select_by_seed_fill(); return; @@ -332,15 +338,15 @@ 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]) + for (int neighbor_idx : all_level_neighbors[current_facet]) { + if (neighbor_idx < 0 || visited[neighbor_idx]) continue; - if(!m_triangles[neighbor_idx].is_split()) { - if(m_triangles[neighbor_idx].get_state() == start_facet_state) + 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)) + for (int neighbor_facet_idx : neighboring_triangles(neighbor_idx, current_facet, start_facet_state)) facet_queue.push(neighbor_facet_idx); } } @@ -478,7 +484,7 @@ int TriangleSelector::triangle_midpoint_or_allocate(int itriangle, int vertexi, Vec3f c = 0.5f * (m_vertices[vertexi].v + m_vertices[vertexj].v); #ifdef EXPENSIVE_DEBUG_CHECKS // Verify that the vertex is really a new one. - auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [this, c](const Vertex &v) { + auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [c](const Vertex &v) { return v.ref_cnt > 0 && (v.v - c).norm() < EPSILON; }); assert(it == m_vertices.end()); #endif // EXPENSIVE_DEBUG_CHECKS @@ -777,10 +783,9 @@ void TriangleSelector::split_triangle(int facet_idx, const Vec3i &neighbors) } } - std::array sides; - sides = { (*pts[2]-*pts[1]).squaredNorm(), - (*pts[0]-*pts[2]).squaredNorm(), - (*pts[1]-*pts[0]).squaredNorm() }; + std::array sides = {(*pts[2] - *pts[1]).squaredNorm(), + (*pts[0] - *pts[2]).squaredNorm(), + (*pts[1] - *pts[0]).squaredNorm()}; boost::container::small_vector sides_to_split; int side_to_keep = -1; @@ -798,7 +803,7 @@ void TriangleSelector::split_triangle(int facet_idx, const Vec3i &neighbors) // Save how the triangle will be split. Second argument makes sense only for one // or two split sides, otherwise the value is ignored. - tr->set_division(sides_to_split.size(), + tr->set_division(int(sides_to_split.size()), sides_to_split.size() == 2 ? side_to_keep : sides_to_split[0]); perform_split(facet_idx, neighbors, old_type); @@ -1026,12 +1031,12 @@ void TriangleSelector::reset() for (const stl_vertex& vert : m_mesh->its.vertices) m_vertices.emplace_back(vert); m_triangles.reserve(m_mesh->its.indices.size()); - for (size_t i=0; iits.indices.size(); ++i) { - const stl_triangle_vertex_indices& ind = m_mesh->its.indices[i]; - push_triangle(ind[0], ind[1], ind[2], i); + for (size_t i = 0; i < m_mesh->its.indices.size(); ++i) { + const stl_triangle_vertex_indices &ind = m_mesh->its.indices[i]; + push_triangle(ind[0], ind[1], ind[2], int(i)); } - m_orig_size_vertices = m_vertices.size(); - m_orig_size_indices = m_triangles.size(); + m_orig_size_vertices = int(m_vertices.size()); + m_orig_size_indices = int(m_triangles.size()); } @@ -1412,7 +1417,7 @@ void TriangleSelector::deserialize(const std::pair &triangle_id_and_ibit : data.first) { int ibit = triangle_id_and_ibit.second; - assert(ibit < data.second.size()); + assert(ibit < int(data.second.size())); auto next_nibble = [&data, &ibit = ibit]() { int n = 0; for (int i = 0; i < 4; ++ i) @@ -1556,7 +1561,7 @@ void TriangleSelector::seed_fill_apply_on_triangles(EnforcerBlockerType new_stat for (Triangle &triangle : m_triangles) if (triangle.is_split() && triangle.valid()) { size_t facet_idx = &triangle - &m_triangles.front(); - remove_useless_children(facet_idx); + remove_useless_children(int(facet_idx)); } } @@ -1570,7 +1575,7 @@ TriangleSelector::Cursor::Cursor( { Vec3d sf = Geometry::Transformation(trafo_).get_scaling_factor(); if (is_approx(sf(0), sf(1)) && is_approx(sf(1), sf(2))) { - radius_sqr = std::pow(radius_world / sf(0), 2); + radius_sqr = float(std::pow(radius_world / sf(0), 2)); uniform_scaling = true; } else {