From ef5c94f90adec4f77ec56e3dd5f32b564dde8bc7 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Fri, 6 Aug 2021 15:11:20 +0200 Subject: [PATCH 01/86] Fix: prevent degeneration of model during simplification --- src/libslic3r/QuadricEdgeCollapse.cpp | 27 ++++++++++- tests/data/simplification.obj | 46 +++++++++++++++++++ tests/libslic3r/test_indexed_triangle_set.cpp | 12 ++++- 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 tests/data/simplification.obj diff --git a/src/libslic3r/QuadricEdgeCollapse.cpp b/src/libslic3r/QuadricEdgeCollapse.cpp index e42ed5deb..ffe1e5ca7 100644 --- a/src/libslic3r/QuadricEdgeCollapse.cpp +++ b/src/libslic3r/QuadricEdgeCollapse.cpp @@ -77,7 +77,8 @@ namespace QuadricEdgeCollapse { uint32_t ti, const EdgeInfos& e_infos, const Indices& indices); bool is_flipped(const Vec3f &new_vertex, uint32_t ti0, uint32_t ti1, const VertexInfo& v_info, const TriangleInfos &t_infos, const EdgeInfos &e_infos, const indexed_triangle_set &its); - + bool degenerate(uint32_t vi, uint32_t ti0, uint32_t ti1, const VertexInfo &v_info, + const EdgeInfos &e_infos, const Indices &indices); // find edge with smallest error in triangle Vec3d calculate_3errors(const Triangle &t, const Vertices &vertices, const VertexInfos &v_infos); Error calculate_error(uint32_t ti, const Triangle& t,const Vertices &vertices, const VertexInfos& v_infos, unsigned char& min_index); @@ -179,6 +180,8 @@ void Slic3r::its_quadric_edge_collapse( find_triangle_index1(vi1, v_info0, ti0, e_infos, its.indices) : find_triangle_index1(vi0, v_info1, ti0, e_infos, its.indices) ; if (!ti1_opt.has_value() || // edge has only one triangle + degenerate(vi0, ti0, *ti1_opt, v_info1, e_infos, its.indices) || + degenerate(vi1, ti0, *ti1_opt, v_info0, e_infos, its.indices) || is_flipped(new_vertex0, ti0, *ti1_opt, v_info0, t_infos, e_infos, its) || is_flipped(new_vertex0, ti0, *ti1_opt, v_info1, t_infos, e_infos, its)) { // try other triangle's edge @@ -487,6 +490,28 @@ bool QuadricEdgeCollapse::is_flipped(const Vec3f & new_vertex, return false; } +bool QuadricEdgeCollapse::degenerate(uint32_t vi, + uint32_t ti0, + uint32_t ti1, + const VertexInfo &v_info, + const EdgeInfos & e_infos, + const Indices & indices) +{ + // check surround triangle do not contain vertex index + // protect from creation of triangle with two same vertices inside + size_t v_info_end = v_info.start + v_info.count; + for (size_t ei = v_info.start; ei < v_info_end; ++ei) { + assert(ei < e_infos.size()); + const EdgeInfo &e_info = e_infos[ei]; + if (e_info.t_index == ti0) continue; // ti0 will be deleted + if (e_info.t_index == ti1) continue; // ti1 will be deleted + const Triangle &t = indices[e_info.t_index]; + for (size_t i = 0; i < 3; ++i) + if (t[i] == vi) return true; + } + return false; +} + Vec3d QuadricEdgeCollapse::calculate_3errors(const Triangle & t, const Vertices & vertices, const VertexInfos &v_infos) diff --git a/tests/data/simplification.obj b/tests/data/simplification.obj new file mode 100644 index 000000000..f509e695c --- /dev/null +++ b/tests/data/simplification.obj @@ -0,0 +1,46 @@ +v 39.349007 -54.069000 -199.819000 +v 39.489006 -54.029007 -199.815002 +v 39.419006 -53.993011 -199.769012 +v 39.629005 -53.975006 -199.815002 +v 39.639008 -53.947006 -199.805023 +v 39.651001 -53.919006 -199.795013 +v 39.807007 -53.863007 -199.796997 +v 39.729004 -53.891006 -199.796997 +v 39.727005 -53.935013 -199.813019 +v 39.767006 -53.899002 -199.805023 +v 39.871002 -53.835007 -199.801025 +v 39.443001 -53.829010 -199.878998 +v 39.523003 -53.965012 -199.827026 +v 39.807007 -53.863007 -199.796997 +v 39.833008 -53.723007 -199.723022 +v 39.759003 -53.822998 -199.822998 +v 39.867004 -53.845001 -199.805023 +v 39.937004 -53.805008 -199.805023 +f 1 2 3 +f 4 5 2 +f 2 6 3 +f 7 8 4 +f 9 10 4 +f 10 9 11 +f 12 2 1 +f 13 6 4 +f 13 4 2 +f 8 7 9 +f 6 9 4 +f 6 14 15 +f 16 14 6 +f 17 18 9 +f 3 6 15 +f 12 16 6 +f 12 6 13 +f 12 13 2 +f 5 4 8 +f 6 8 9 +f 5 6 2 +f 6 5 8 +f 17 9 7 +f 7 11 17 +f 18 11 9 +f 11 18 17 +f 10 7 4 +f 7 10 11 diff --git a/tests/libslic3r/test_indexed_triangle_set.cpp b/tests/libslic3r/test_indexed_triangle_set.cpp index b640d8410..0e08749bf 100644 --- a/tests/libslic3r/test_indexed_triangle_set.cpp +++ b/tests/libslic3r/test_indexed_triangle_set.cpp @@ -246,4 +246,14 @@ TEST_CASE("Simplify mesh by Quadric edge collapse to 5%", "[its]") CHECK(fabs(original_volume - volume) < 33.); float avg_distance = compare(mesh.its, its, 10); CHECK(avg_distance < 0.022f); // 0.02022 | 0.0199614074 -} \ No newline at end of file +} + +TEST_CASE("Simplify trouble case", "[its]") +{ + TriangleMesh tm = load_model("simplification.obj"); + REQUIRE_FALSE(tm.empty()); + float max_error = std::numeric_limits::max(); + uint32_t wanted_count = 8; + its_quadric_edge_collapse(tm.its, wanted_count, &max_error); + CHECK(tm.its.indices.size() <= 8); +} From 62f8ab1cbe500b20a2a0ca5957d101d27a98be9c Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Mon, 16 Aug 2021 11:53:37 +0200 Subject: [PATCH 02/86] Add check of neighbors Add store triangle for debug purpose --- src/libslic3r/QuadricEdgeCollapse.cpp | 120 +++++++++++++++++++++++++- src/libslic3r/TriangleMesh.cpp | 42 +++++++++ src/libslic3r/TriangleMesh.hpp | 4 + 3 files changed, 164 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/QuadricEdgeCollapse.cpp b/src/libslic3r/QuadricEdgeCollapse.cpp index ffe1e5ca7..52f68ee8d 100644 --- a/src/libslic3r/QuadricEdgeCollapse.cpp +++ b/src/libslic3r/QuadricEdgeCollapse.cpp @@ -91,6 +91,119 @@ namespace QuadricEdgeCollapse { using namespace QuadricEdgeCollapse; +// store triangle surrounding to file +void store_surround(const char * obj_filename, + size_t triangle_index, + int depth, + const indexed_triangle_set &its, + const VertexInfos & v_infos, + const EdgeInfos & e_infos) +{ + std::set triangles; + // triangle index, depth + using Item = std::pair; + std::queue process; + process.push({triangle_index, depth}); + + while (!process.empty()) { + Item item = process.front(); + process.pop(); + size_t ti = item.first; + auto it = triangles.find(ti); + if (it != triangles.end()) continue; + triangles.insert(ti); + if (item.second == 0) continue; + + const Vec3i &t = its.indices[ti]; + for (size_t i = 0; i < 3; ++i) { + const auto &v_info = v_infos[t[i]]; + for (size_t d = 0; d < v_info.count; ++d) { + size_t ei = v_info.start + d; + const auto & e_info = e_infos[ei]; + auto it = triangles.find(e_info.t_index); + if (it != triangles.end()) continue; + process.push({e_info.t_index, item.second - 1}); + } + } + } + + std::vector trs; + trs.reserve(triangles.size()); + for (size_t ti : triangles) trs.push_back(ti); + its_store_triangles(its, obj_filename, trs); + //its_write_obj(its,"original.obj"); +} + +bool check_neighbors(const indexed_triangle_set &its, + const TriangleInfos & t_infos, + const VertexInfos & v_infos, + const EdgeInfos & e_infos) +{ + VertexInfos v_infos2(v_infos.size()); + size_t count_indices = 0; + + for (size_t ti = 0; ti < its.indices.size(); ti++) { + if (t_infos[ti].is_deleted()) continue; + ++count_indices; + const Triangle &t = its.indices[ti]; + for (size_t e = 0; e < 3; e++) { + VertexInfo &v_info = v_infos2[t[e]]; + ++v_info.count; // triangle count + } + } + + uint32_t triangle_start = 0; + for (VertexInfo &v_info : v_infos2) { + v_info.start = triangle_start; + triangle_start += v_info.count; + // set filled vertex to zero + v_info.count = 0; + } + + // create reference + EdgeInfos e_infos2(count_indices * 3); + for (size_t ti = 0; ti < its.indices.size(); ti++) { + if (t_infos[ti].is_deleted()) continue; + const Triangle &t = its.indices[ti]; + for (size_t j = 0; j < 3; ++j) { + VertexInfo &v_info = v_infos2[t[j]]; + size_t ei = v_info.start + v_info.count; + assert(ei < e_infos2.size()); + EdgeInfo &e_info = e_infos2[ei]; + e_info.t_index = ti; + e_info.edge = j; + ++v_info.count; + } + } + + for (size_t vi = 0; vi < its.vertices.size(); vi++) { + const VertexInfo &v_info = v_infos[vi]; + if (v_info.is_deleted()) continue; + const VertexInfo &v_info2 = v_infos2[vi]; + if (v_info.count != v_info2.count) { + return false; + } + EdgeInfos eis; + eis.reserve(v_info.count); + std::copy(e_infos.begin() + v_info.start, + e_infos.begin() + v_info.start + v_info.count, + std::back_inserter(eis)); + auto compare = [](const EdgeInfo &ei1, const EdgeInfo &ei2) { + return ei1.t_index < ei2.t_index; + }; + std::sort(eis.begin(), eis.end(), compare); + std::sort(e_infos2.begin() + v_info2.start, + e_infos2.begin() + v_info2.start + v_info2.count, + compare); + for (size_t ei = 0; ei < v_info.count; ++ei) { + if (eis[ei].t_index != e_infos2[ei + v_info2.start].t_index) { + return false; + } + } + } + return true; +} + void Slic3r::its_quadric_edge_collapse( indexed_triangle_set & its, uint32_t triangle_count, @@ -117,6 +230,9 @@ void Slic3r::its_quadric_edge_collapse( throw_on_cancel(); statusfn(status_init_size); + //its_store_triangle(its, "triangle.obj", 1182); + //store_surround("triangle_surround1.obj", 1182, 1, its, v_infos, e_infos); + // convert from triangle index to mutable priority queue index std::vector ti_2_mpqi(its.indices.size(), {0}); auto setter = [&ti_2_mpqi](const Error &e, size_t index) { ti_2_mpqi[e.triangle_index] = index; }; @@ -237,8 +353,7 @@ void Slic3r::its_quadric_edge_collapse( } v_info0.q = q; - // fix neighbors - + // fix neighbors // vertex index of triangle 0 which is not vi0 nor vi1 uint32_t vi_top0 = t0[(t_info0.min_index + 2) % 3]; const Triangle &t1 = its.indices[ti1]; @@ -264,6 +379,7 @@ void Slic3r::its_quadric_edge_collapse( t_info1.set_deleted(); // triangle counter decrementation actual_triangle_count-=2; + assert(check_neighbors(its, t_infos, v_infos, e_infos)); } // compact triangle diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 360a8b14e..d4baabc97 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -957,6 +957,48 @@ int its_compactify_vertices(indexed_triangle_set &its, bool shrink_to_fit) return removed; } +bool its_store_triangle(const indexed_triangle_set &its, + const char * obj_filename, + size_t triangle_index) +{ + if (its.indices.size() <= triangle_index) return false; + Vec3i t = its.indices[triangle_index]; + indexed_triangle_set its2; + its2.indices = {{0, 1, 2}}; + its2.vertices = {its.vertices[t[0]], its.vertices[t[1]], + its.vertices[t[2]]}; + return its_write_obj(its2, obj_filename); +} + +bool its_store_triangles(const indexed_triangle_set &its, + const char * obj_filename, + const std::vector & triangles) +{ + indexed_triangle_set its2; + its2.vertices.reserve(triangles.size() * 3); + its2.indices.reserve(triangles.size()); + std::map vertex_map; + for (auto ti : triangles) { + if (its.indices.size() <= ti) return false; + Vec3i t = its.indices[ti]; + Vec3i new_t; + for (size_t i = 0; i < 3; ++i) { + size_t vi = t[i]; + auto it = vertex_map.find(vi); + if (it != vertex_map.end()) { + new_t[i] = it->second; + continue; + } + size_t new_vi = its2.vertices.size(); + its2.vertices.push_back(its.vertices[vi]); + vertex_map[vi] = new_vi; + new_t[i] = new_vi; + } + its2.indices.push_back(new_t); + } + return its_write_obj(its2, obj_filename); +} + void its_shrink_to_fit(indexed_triangle_set &its) { its.indices.shrink_to_fit(); diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index c8c7e0dd7..b7a1bebb1 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -140,6 +140,10 @@ int its_remove_degenerate_faces(indexed_triangle_set &its, bool shrink_to_fit = // Remove vertices, which none of the faces references. Return number of freed vertices. int its_compactify_vertices(indexed_triangle_set &its, bool shrink_to_fit = true); +// store part of index triangle set +bool its_store_triangle(const indexed_triangle_set &its, const char *obj_filename, size_t triangle_index); +bool its_store_triangles(const indexed_triangle_set &its, const char *obj_filename, const std::vector& triangles); + std::vector its_split(const indexed_triangle_set &its); bool its_is_splittable(const indexed_triangle_set &its); From 21fd35d243ebb91e3c2a632b5d14d8e5cd521a36 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Mon, 16 Aug 2021 13:04:39 +0200 Subject: [PATCH 03/86] Fix: Do not close dialog after preview --- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 694eeadd4..cdcf9ce1f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -194,19 +194,15 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi need_reload = false; // Reload visualization of mesh - change VBO, FBO on GPU - m_parent.reload_scene(true); // deactivate gizmo?? - GLGizmosManager &gizmos_mgr = m_parent.get_gizmos_manager(); - gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify); - + m_parent.reload_scene(true); if (state == State::close_on_end) { // fix hollowing, sla support points, modifiers, ... auto plater = wxGetApp().plater(); - plater->changed_mesh(obj_index); // deactivate gizmo?? - // changed_mesh cause close(); - //close(); + plater->changed_mesh(obj_index); + close(); } - // change from simplifying | aply + // change from simplifying | apply state = State::settings; // Fix warning icon in object list From 268b06bdbb7eaa433c663413d9c9387c7fb15d67 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Mon, 16 Aug 2021 15:30:33 +0200 Subject: [PATCH 04/86] fix position of window --- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 47 +++++++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 2 + 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index cdcf9ce1f..fa0b94200 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -53,10 +53,6 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi const int max_char_in_name = 25; create_gui_cfg(); - int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | - ImGuiWindowFlags_NoCollapse; - m_imgui->begin(on_get_name(), flag); - const Selection &selection = m_parent.get_selection(); int object_idx = selection.get_object_idx(); ModelObject *obj = wxGetApp().plater()->model().objects[object_idx]; @@ -65,6 +61,12 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi // Check selection of new volume // Do not reselect object when processing if (act_volume != volume && state == State::settings) { + bool change_window_position = (volume == nullptr); + // select different model + if (volume != nullptr && original_its.has_value()) { + set_its(*original_its); + } + obj_index = object_idx; // to remember correct object volume = act_volume; original_its = {}; @@ -72,13 +74,30 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi c.wanted_percent = 50.; // default value c.update_percent(tm.its.indices.size()); is_valid_result = false; - // set window position - ImVec2 pos = ImGui::GetMousePos(); - pos.x -= gui_cfg->window_offset; - pos.y -= gui_cfg->window_offset; - ImGui::SetWindowPos(pos, ImGuiCond_Always); + + if (change_window_position) { + ImVec2 pos = ImGui::GetMousePos(); + pos.x -= gui_cfg->window_offset; + pos.y -= gui_cfg->window_offset; + // minimal top left value + ImVec2 tl(gui_cfg->window_padding, gui_cfg->window_padding); + if (pos.x < tl.x) pos.x = tl.x; + if (pos.y < tl.y) pos.y = tl.y; + // maximal bottom right value + auto parent_size = m_parent.get_canvas_size(); + ImVec2 br( + parent_size.get_width() - (2 * gui_cfg->window_offset + gui_cfg->window_padding), + parent_size.get_height() - (2 * gui_cfg->window_offset + gui_cfg->window_padding)); + if (pos.x > br.x) pos.x = br.x; + if (pos.y > br.y) pos.y = br.y; + ImGui::SetNextWindowPos(pos, ImGuiCond_Always); + } } + int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoCollapse; + m_imgui->begin(on_get_name(), flag); + size_t triangle_count = volume->mesh().its.indices.size(); // already reduced mesh if (original_its.has_value()) @@ -211,8 +230,6 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi } void GLGizmoSimplify::close() { - volume = nullptr; - // close gizmo == open it again GLGizmosManager &gizmos_mgr = m_parent.get_gizmos_manager(); gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify); @@ -293,6 +310,14 @@ bool GLGizmoSimplify::on_is_activable() const return !m_parent.get_selection().is_empty(); } +void GLGizmoSimplify::on_set_state() +{ + // Closing gizmo. e.g. selecting another one + if (m_state == GLGizmoBase::Off) { + volume = nullptr; + } +} + void GLGizmoSimplify::create_gui_cfg() { if (gui_cfg.has_value()) return; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index bd3637360..cefd1abf0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -41,6 +41,7 @@ protected: virtual void on_render_input_window(float x, float y, float bottom_limit) override; virtual bool on_is_activable() const override; virtual bool on_is_selectable() const override { return false; } + virtual void on_set_state() override; private: void close(); @@ -78,6 +79,7 @@ private: int input_width = 100; int input_small_width = 80; int window_offset = 100; + int window_padding = 0; }; std::optional gui_cfg; void create_gui_cfg(); From c04856e049221312a87761df0e194488ba95b5c6 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Mon, 16 Aug 2021 18:04:38 +0200 Subject: [PATCH 05/86] Extend simplify test to chack distance of each triangle center and each vertices. Both simplify to origin and vice versa --- tests/libslic3r/test_indexed_triangle_set.cpp | 71 +++++++++++++------ 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/tests/libslic3r/test_indexed_triangle_set.cpp b/tests/libslic3r/test_indexed_triangle_set.cpp index 0e08749bf..a3996e651 100644 --- a/tests/libslic3r/test_indexed_triangle_set.cpp +++ b/tests/libslic3r/test_indexed_triangle_set.cpp @@ -165,29 +165,51 @@ std::vector its_sample_surface(const indexed_triangle_set &its, #include "libslic3r/AABBTreeIndirect.hpp" -// return Average abs distance to original -float compare(const indexed_triangle_set &original, - const indexed_triangle_set &simplified, - double sample_per_mm2) +struct CompareConfig +{ + float max_distance = 3.f; + float max_average_distance = 2.f; +}; + +bool is_similar(const indexed_triangle_set &from, + const indexed_triangle_set &to, + const CompareConfig &cfg) { // create ABBTree auto tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set( - original.vertices, original.indices); + from.vertices, from.indices); + float sum_distance = 0.f; + float max_distance = 0.f; - unsigned int init = 0; - std::mt19937 rnd(init); - auto samples = its_sample_surface(simplified, sample_per_mm2, rnd); - - float sumDistance = 0; - for (const Vec3f &sample : samples) { + auto collect_distances = [&](const Vec3f &surface_point) { size_t hit_idx; Vec3f hit_point; - float distance2 = AABBTreeIndirect::squared_distance_to_indexed_triangle_set( - original.vertices, original.indices, tree, sample, hit_idx, - hit_point); - sumDistance += sqrt(distance2); + float distance2 = + AABBTreeIndirect::squared_distance_to_indexed_triangle_set( + from.vertices, from.indices, tree, surface_point, hit_idx, hit_point); + float distance = sqrt(distance2); + if (max_distance < distance) max_distance = distance; + sum_distance += distance; + }; + + for (const Vec3f &vertex : to.vertices) { + collect_distances(vertex); } - return sumDistance / samples.size(); + + for (const Vec3i &t : to.indices) { + Vec3f center(0,0,0); + for (size_t i = 0; i < 3; ++i) { + center += to.vertices[t[i]] / 3; + } + collect_distances(center); + } + + size_t count = to.vertices.size() + to.indices.size(); + float avg_distance = sum_distance / count; + if (avg_distance > cfg.max_average_distance || + max_distance > cfg.max_distance) + return false; + return true; } TEST_CASE("Reduce one edge by Quadric Edge Collapse", "[its]") @@ -226,8 +248,12 @@ TEST_CASE("Reduce one edge by Quadric Edge Collapse", "[its]") (v[i] > v4[i] && v[i] < v2[i]); CHECK(is_between); } - float avg_distance = compare(its_, its, 10); - CHECK(avg_distance < 8e-3f); + CompareConfig cfg; + cfg.max_average_distance = 0.014f; + cfg.max_distance = 0.75f; + + CHECK(is_similar(its, its_, cfg)); + CHECK(is_similar(its_, its, cfg)); } #include "test_utils.hpp" @@ -244,8 +270,13 @@ TEST_CASE("Simplify mesh by Quadric edge collapse to 5%", "[its]") CHECK(its.indices.size() <= wanted_count); double volume = its_volume(its); CHECK(fabs(original_volume - volume) < 33.); - float avg_distance = compare(mesh.its, its, 10); - CHECK(avg_distance < 0.022f); // 0.02022 | 0.0199614074 + + CompareConfig cfg; + cfg.max_average_distance = 0.043f; + cfg.max_distance = 0.32f; + + CHECK(is_similar(mesh.its, its, cfg)); + CHECK(is_similar(its, mesh.its, cfg)); } TEST_CASE("Simplify trouble case", "[its]") From 090728b9d5c1279650bc585f9be7c1b5fb4608fd Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Tue, 17 Aug 2021 08:58:45 +0200 Subject: [PATCH 06/86] Add private member prefix m_ --- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 230 +++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 48 ++--- 2 files changed, 142 insertions(+), 136 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index fa0b94200..23ab4ef13 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -18,17 +18,17 @@ GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D & parent, const std::string &icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, -1) - , state(State::settings) - , is_valid_result(false) - , progress(0) - , volume(nullptr) - , obj_index(0) - , need_reload(false) + , m_state(State::settings) + , m_is_valid_result(false) + , m_progress(0) + , m_volume(nullptr) + , m_obj_index(0) + , m_need_reload(false) {} GLGizmoSimplify::~GLGizmoSimplify() { - state = State::canceling; - if (worker.joinable()) worker.join(); + m_state = State::canceling; + if (m_worker.joinable()) m_worker.join(); } bool GLGizmoSimplify::on_init() @@ -60,34 +60,34 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi // Check selection of new volume // Do not reselect object when processing - if (act_volume != volume && state == State::settings) { - bool change_window_position = (volume == nullptr); + if (act_volume != m_volume && m_state == State::settings) { + bool change_window_position = (m_volume == nullptr); // select different model - if (volume != nullptr && original_its.has_value()) { - set_its(*original_its); + if (m_volume != nullptr && m_original_its.has_value()) { + set_its(*m_original_its); } - obj_index = object_idx; // to remember correct object - volume = act_volume; - original_its = {}; - const TriangleMesh &tm = volume->mesh(); - c.wanted_percent = 50.; // default value - c.update_percent(tm.its.indices.size()); - is_valid_result = false; + m_obj_index = object_idx; // to remember correct object + m_volume = act_volume; + m_original_its = {}; + const TriangleMesh &tm = m_volume->mesh(); + m_configuration.wanted_percent = 50.; // default value + m_configuration.update_percent(tm.its.indices.size()); + m_is_valid_result = false; if (change_window_position) { ImVec2 pos = ImGui::GetMousePos(); - pos.x -= gui_cfg->window_offset; - pos.y -= gui_cfg->window_offset; + pos.x -= m_gui_cfg->window_offset; + pos.y -= m_gui_cfg->window_offset; // minimal top left value - ImVec2 tl(gui_cfg->window_padding, gui_cfg->window_padding); + ImVec2 tl(m_gui_cfg->window_padding, m_gui_cfg->window_padding); if (pos.x < tl.x) pos.x = tl.x; if (pos.y < tl.y) pos.y = tl.y; // maximal bottom right value auto parent_size = m_parent.get_canvas_size(); ImVec2 br( - parent_size.get_width() - (2 * gui_cfg->window_offset + gui_cfg->window_padding), - parent_size.get_height() - (2 * gui_cfg->window_offset + gui_cfg->window_padding)); + parent_size.get_width() - (2 * m_gui_cfg->window_offset + m_gui_cfg->window_padding), + parent_size.get_height() - (2 * m_gui_cfg->window_offset + m_gui_cfg->window_padding)); if (pos.x > br.x) pos.x = br.x; if (pos.y > br.y) pos.y = br.y; ImGui::SetNextWindowPos(pos, ImGuiCond_Always); @@ -98,98 +98,100 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi ImGuiWindowFlags_NoCollapse; m_imgui->begin(on_get_name(), flag); - size_t triangle_count = volume->mesh().its.indices.size(); + size_t triangle_count = m_volume->mesh().its.indices.size(); // already reduced mesh - if (original_its.has_value()) - triangle_count = original_its->indices.size(); + if (m_original_its.has_value()) + triangle_count = m_original_its->indices.size(); m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Mesh name") + ":"); - ImGui::SameLine(gui_cfg->top_left_width); - std::string name = volume->name; + ImGui::SameLine(m_gui_cfg->top_left_width); + std::string name = m_volume->name; if (name.length() > max_char_in_name) name = name.substr(0, max_char_in_name-3) + "..."; m_imgui->text(name); m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Triangles") + ":"); - ImGui::SameLine(gui_cfg->top_left_width); + ImGui::SameLine(m_gui_cfg->top_left_width); m_imgui->text(std::to_string(triangle_count)); ImGui::Separator(); ImGui::Text(_L("Limit by triangles").c_str()); - ImGui::SameLine(gui_cfg->bottom_left_width); + ImGui::SameLine(m_gui_cfg->bottom_left_width); // First initialization + fix triangle count - if (m_imgui->checkbox("##UseCount", c.use_count)) { - if (!c.use_count) c.use_error = true; - is_valid_result = false; + if (m_imgui->checkbox("##UseCount", m_configuration.use_count)) { + if (!m_configuration.use_count) m_configuration.use_error = true; + m_is_valid_result = false; } - m_imgui->disabled_begin(!c.use_count); + m_imgui->disabled_begin(!m_configuration.use_count); ImGui::Text(_L("Triangle count").c_str()); - ImGui::SameLine(gui_cfg->bottom_left_width); - int wanted_count = c.wanted_count; - ImGui::SetNextItemWidth(gui_cfg->input_width); + ImGui::SameLine(m_gui_cfg->bottom_left_width); + int wanted_count = m_configuration.wanted_count; + ImGui::SetNextItemWidth(m_gui_cfg->input_width); if (ImGui::SliderInt("##triangle_count", &wanted_count, min_triangle_count, triangle_count, "%d")) { - c.wanted_count = static_cast(wanted_count); - if (c.wanted_count < min_triangle_count) - c.wanted_count = min_triangle_count; - if (c.wanted_count > triangle_count) - c.wanted_count = triangle_count; - c.update_count(triangle_count); - is_valid_result = false; + m_configuration.wanted_count = static_cast(wanted_count); + if (m_configuration.wanted_count < min_triangle_count) + m_configuration.wanted_count = min_triangle_count; + if (m_configuration.wanted_count > triangle_count) + m_configuration.wanted_count = triangle_count; + m_configuration.update_count(triangle_count); + m_is_valid_result = false; } ImGui::Text(_L("Ratio").c_str()); - ImGui::SameLine(gui_cfg->bottom_left_width); - ImGui::SetNextItemWidth(gui_cfg->input_small_width); - const char * precision = (c.wanted_percent > 10)? "%.0f": ((c.wanted_percent > 1)? "%.1f":"%.2f"); - float step = (c.wanted_percent > 10)? 1.f: ((c.wanted_percent > 1)? 0.1f : 0.01f); - if (ImGui::InputFloat("%", &c.wanted_percent, step, 10*step, precision)) { - if (c.wanted_percent > 100.f) c.wanted_percent = 100.f; - c.update_percent(triangle_count); - if (c.wanted_count < min_triangle_count) { - c.wanted_count = min_triangle_count; - c.update_count(triangle_count); + ImGui::SameLine(m_gui_cfg->bottom_left_width); + ImGui::SetNextItemWidth(m_gui_cfg->input_small_width); + const char * precision = (m_configuration.wanted_percent > 10)? "%.0f": + ((m_configuration.wanted_percent > 1)? "%.1f":"%.2f"); + float step = (m_configuration.wanted_percent > 10)? 1.f: + ((m_configuration.wanted_percent > 1)? 0.1f : 0.01f); + if (ImGui::InputFloat("%", &m_configuration.wanted_percent, step, 10*step, precision)) { + if (m_configuration.wanted_percent > 100.f) m_configuration.wanted_percent = 100.f; + m_configuration.update_percent(triangle_count); + if (m_configuration.wanted_count < min_triangle_count) { + m_configuration.wanted_count = min_triangle_count; + m_configuration.update_count(triangle_count); } - is_valid_result = false; + m_is_valid_result = false; } m_imgui->disabled_end(); // use_count ImGui::NewLine(); ImGui::Text(_L("Limit by error").c_str()); - ImGui::SameLine(gui_cfg->bottom_left_width); - if (m_imgui->checkbox("##UseError", c.use_error)) { - if (!c.use_error) c.use_count = true; - is_valid_result = false; + ImGui::SameLine(m_gui_cfg->bottom_left_width); + if (m_imgui->checkbox("##UseError", m_configuration.use_error)) { + if (!m_configuration.use_error) m_configuration.use_count = true; + m_is_valid_result = false; } - m_imgui->disabled_begin(!c.use_error); + m_imgui->disabled_begin(!m_configuration.use_error); ImGui::Text(_L("Max. error").c_str()); - ImGui::SameLine(gui_cfg->bottom_left_width); - ImGui::SetNextItemWidth(gui_cfg->input_small_width); - if (ImGui::InputFloat("##maxError", &c.max_error, 0.01f, .1f, "%.2f")) { - if (c.max_error < 0.f) c.max_error = 0.f; - is_valid_result = false; + ImGui::SameLine(m_gui_cfg->bottom_left_width); + ImGui::SetNextItemWidth(m_gui_cfg->input_small_width); + if (ImGui::InputFloat("##maxError", &m_configuration.max_error, 0.01f, .1f, "%.2f")) { + if (m_configuration.max_error < 0.f) m_configuration.max_error = 0.f; + m_is_valid_result = false; } m_imgui->disabled_end(); // use_error - if (state == State::settings) { + if (m_state == State::settings) { if (m_imgui->button(_L("Cancel"))) { - if (original_its.has_value()) { - set_its(*original_its); - state = State::close_on_end; + if (m_original_its.has_value()) { + set_its(*m_original_its); + m_state = State::close_on_end; } else { close(); } } - ImGui::SameLine(gui_cfg->bottom_left_width); + ImGui::SameLine(m_gui_cfg->bottom_left_width); if (m_imgui->button(_L("Preview"))) { - state = State::simplifying; + m_state = State::simplifying; // simplify but not aply on mesh process(); } ImGui::SameLine(); if (m_imgui->button(_L("Apply"))) { - if (!is_valid_result) { - state = State::close_on_end; + if (!m_is_valid_result) { + m_state = State::close_on_end; process(); } else { // use preview and close @@ -197,35 +199,35 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi } } } else { - m_imgui->disabled_begin(state == State::canceling); - if (m_imgui->button(_L("Cancel"))) state = State::canceling; + m_imgui->disabled_begin(m_state == State::canceling); + if (m_imgui->button(_L("Cancel"))) m_state = State::canceling; m_imgui->disabled_end(); - ImGui::SameLine(gui_cfg->bottom_left_width); + ImGui::SameLine(m_gui_cfg->bottom_left_width); // draw progress bar char buf[32]; - sprintf(buf, L("Process %d / 100"), progress); - ImGui::ProgressBar(progress / 100., ImVec2(gui_cfg->input_width, 0.f), buf); + sprintf(buf, L("Process %d / 100"), m_progress); + ImGui::ProgressBar(m_progress / 100., ImVec2(m_gui_cfg->input_width, 0.f), buf); } m_imgui->end(); - if (need_reload) { - need_reload = false; + if (m_need_reload) { + m_need_reload = false; // Reload visualization of mesh - change VBO, FBO on GPU m_parent.reload_scene(true); - if (state == State::close_on_end) { + if (m_state == State::close_on_end) { // fix hollowing, sla support points, modifiers, ... auto plater = wxGetApp().plater(); - plater->changed_mesh(obj_index); + plater->changed_mesh(m_obj_index); close(); } // change from simplifying | apply - state = State::settings; + m_state = State::settings; // Fix warning icon in object list - wxGetApp().obj_list()->update_item_error_icon(obj_index, -1); + wxGetApp().obj_list()->update_item_error_icon(m_obj_index, -1); } } @@ -243,51 +245,53 @@ void GLGizmoSimplify::process() const char* what() const throw() { return L("Model simplification has been canceled"); } }; - if (!original_its.has_value()) - original_its = volume->mesh().its; // copy + if (!m_original_its.has_value()) + m_original_its = m_volume->mesh().its; // copy auto plater = wxGetApp().plater(); - plater->take_snapshot(_L("Simplify ") + volume->name); - plater->clear_before_change_mesh(obj_index); - progress = 0; - if (worker.joinable()) worker.join(); - worker = std::thread([&]() { + plater->take_snapshot(_L("Simplify ") + m_volume->name); + plater->clear_before_change_mesh(m_obj_index); + m_progress = 0; + if (m_worker.joinable()) m_worker.join(); + m_worker = std::thread([&]() { // store original triangles - uint32_t triangle_count = (c.use_count) ? c.wanted_count : 0; - float max_error = (c.use_error) ? c.max_error : std::numeric_limits::max(); + uint32_t triangle_count = (m_configuration.use_count) ? m_configuration.wanted_count : 0; + float max_error = (m_configuration.use_error) ? + m_configuration.max_error : std::numeric_limits::max(); std::function throw_on_cancel = [&]() { - if (state == State::canceling) { + if (m_state == State::canceling) { throw SimplifyCanceledException(); } }; std::function statusfn = [&](int percent) { - progress = percent; + m_progress = percent; m_parent.schedule_extra_frame(0); }; indexed_triangle_set collapsed; - if (last_error.has_value()) { + if (m_last_error.has_value()) { // is chance to continue with last reduction - const indexed_triangle_set &its = volume->mesh().its; + const indexed_triangle_set &its = m_volume->mesh().its; uint32_t last_triangle_count = static_cast(its.indices.size()); - if ((!c.use_count || triangle_count <= last_triangle_count) && - (!c.use_error || c.max_error <= *last_error)) { + if ((!m_configuration.use_count || triangle_count <= last_triangle_count) && + (!m_configuration.use_error || m_configuration.max_error <= *m_last_error)) { collapsed = its; // small copy } else { - collapsed = *original_its; // copy + collapsed = *m_original_its; // copy } } else { - collapsed = *original_its; // copy + collapsed = *m_original_its; // copy } try { its_quadric_edge_collapse(collapsed, triangle_count, &max_error, throw_on_cancel, statusfn); set_its(collapsed); - is_valid_result = true; - last_error = max_error; + m_is_valid_result = true; + m_last_error = max_error; } catch (SimplifyCanceledException &) { - state = State::settings; + // set state out of main thread + m_state = State::settings; } // need to render last status fn // without sleep it freezes until mouse move @@ -299,10 +303,10 @@ void GLGizmoSimplify::process() void GLGizmoSimplify::set_its(indexed_triangle_set &its) { auto tm = std::make_unique(its); tm->repair(); - volume->set_mesh(std::move(tm)); - volume->set_new_unique_id(); - volume->get_object()->invalidate_bounding_box(); - need_reload = true; + m_volume->set_mesh(std::move(tm)); + m_volume->set_new_unique_id(); + m_volume->get_object()->invalidate_bounding_box(); + m_need_reload = true; } bool GLGizmoSimplify::on_is_activable() const @@ -313,13 +317,13 @@ bool GLGizmoSimplify::on_is_activable() const void GLGizmoSimplify::on_set_state() { // Closing gizmo. e.g. selecting another one - if (m_state == GLGizmoBase::Off) { - volume = nullptr; + if (GLGizmoBase::m_state == GLGizmoBase::Off) { + m_volume = nullptr; } } void GLGizmoSimplify::create_gui_cfg() { - if (gui_cfg.has_value()) return; + if (m_gui_cfg.has_value()) return; int space_size = m_imgui->calc_text_size(":MM").x; GuiCfg cfg; @@ -337,7 +341,7 @@ void GLGizmoSimplify::create_gui_cfg() { cfg.input_width = cfg.bottom_left_width; cfg.input_small_width = cfg.input_width * 0.8; cfg.window_offset = cfg.input_width; - gui_cfg = cfg; + m_gui_cfg = cfg; } } // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index cefd1abf0..57174b7c1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -10,26 +10,7 @@ namespace Slic3r { namespace GUI { class GLGizmoSimplify : public GLGizmoBase -{ - enum class State { - settings, - simplifying, // start processing - canceling, // canceled - successfull, // successful simplified - close_on_end - } state; - - bool is_valid_result; // differ what to do in apply - int progress; - - ModelVolume *volume; - size_t obj_index; - std::optional original_its; - - std::optional last_error; // for use previous reduction - - bool need_reload; // after simplify, glReload must be on main thread - std::thread worker; +{ public: GLGizmoSimplify(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); virtual ~GLGizmoSimplify(); @@ -47,6 +28,28 @@ private: void close(); void process(); void set_its(indexed_triangle_set &its); + void create_gui_cfg(); + + bool m_is_valid_result; // differ what to do in apply + volatile int m_progress; // percent of done work + ModelVolume *m_volume; // + size_t m_obj_index; + + std::optional m_original_its; + std::optional m_last_error; // for use previous reduction + + volatile bool m_need_reload; // after simplify, glReload must be on main thread + std::thread m_worker; + + enum class State { + settings, + simplifying, // start processing + canceling, // canceled + successfull, // successful simplified + close_on_end + }; + volatile State m_state; + struct Configuration { bool use_count = true; @@ -67,7 +70,7 @@ private: wanted_count = static_cast( std::round(triangle_count * wanted_percent / 100.f)); } - } c; + } m_configuration; // This configs holds GUI layout size given by translated texts. // etc. When language changes, GUI is recreated and this class constructed again, @@ -81,8 +84,7 @@ private: int window_offset = 100; int window_padding = 0; }; - std::optional gui_cfg; - void create_gui_cfg(); + std::optional m_gui_cfg; }; } // namespace GUI From 11c91d781e4c56c5047a692f743d5f65a938c561 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Tue, 17 Aug 2021 15:28:08 +0200 Subject: [PATCH 07/86] FIX: extra frame request Do not freeze bargraph in Siplify dialog when no mouse move. --- src/slic3r/GUI/GLCanvas3D.cpp | 19 ++++++----------- src/slic3r/GUI/GLCanvas3D.hpp | 4 +--- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 25 +++++++++-------------- src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 9 ++++---- 4 files changed, 22 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 529056e99..96cf015ea 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2780,11 +2780,10 @@ void GLCanvas3D::on_timer(wxTimerEvent& evt) void GLCanvas3D::on_render_timer(wxTimerEvent& evt) { - // no need to do anything here - // right after this event is recieved, idle event is fired - - //m_dirty = true; - //wxWakeUpIdle(); + m_dirty = true; + // wxWakeUpIdle(); + // no need to wake up idle + // right after this event, idle event is fired } @@ -2802,21 +2801,15 @@ void GLCanvas3D::schedule_extra_frame(int miliseconds) return; } } - // Start timer - int64_t now = timestamp_now(); + int remaining_time = m_render_timer.GetInterval(); // Timer is not running - if (! m_render_timer.IsRunning()) { - m_extra_frame_requested_delayed = miliseconds; + if (!m_render_timer.IsRunning()) { m_render_timer.StartOnce(miliseconds); - m_render_timer_start = now; // Timer is running - restart only if new period is shorter than remaning period } else { - const int64_t remaining_time = (m_render_timer_start + m_extra_frame_requested_delayed) - now; if (miliseconds + 20 < remaining_time) { m_render_timer.Stop(); - m_extra_frame_requested_delayed = miliseconds; m_render_timer.StartOnce(miliseconds); - m_render_timer_start = now; } } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index d9cd55e35..ba8430c07 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -463,15 +463,13 @@ private: std::string m_sidebar_field; // when true renders an extra frame by not resetting m_dirty to false // see request_extra_frame() - bool m_extra_frame_requested; - int m_extra_frame_requested_delayed { std::numeric_limits::max() }; + bool m_extra_frame_requested; bool m_event_handlers_bound{ false }; GLVolumeCollection m_volumes; GCodeViewer m_gcode_viewer; RenderTimer m_render_timer; - int64_t m_render_timer_start; Selection m_selection; const DynamicPrintConfig* m_config; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 23ab4ef13..06a999cad 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -184,7 +184,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi } ImGui::SameLine(m_gui_cfg->bottom_left_width); if (m_imgui->button(_L("Preview"))) { - m_state = State::simplifying; + m_state = State::preview; // simplify but not aply on mesh process(); } @@ -263,23 +263,18 @@ void GLGizmoSimplify::process() if (m_state == State::canceling) { throw SimplifyCanceledException(); } - }; + }; std::function statusfn = [&](int percent) { m_progress = percent; m_parent.schedule_extra_frame(0); }; indexed_triangle_set collapsed; - if (m_last_error.has_value()) { - // is chance to continue with last reduction - const indexed_triangle_set &its = m_volume->mesh().its; - uint32_t last_triangle_count = static_cast(its.indices.size()); - if ((!m_configuration.use_count || triangle_count <= last_triangle_count) && - (!m_configuration.use_error || m_configuration.max_error <= *m_last_error)) { - collapsed = its; // small copy - } else { - collapsed = *m_original_its; // copy - } + if (m_last_error.has_value() && m_last_count.has_value() && + (!m_configuration.use_count || triangle_count <= *m_last_count) && + (!m_configuration.use_error || m_configuration.max_error <= *m_last_error)) { + // continue from last reduction - speed up + collapsed = m_volume->mesh().its; // small copy } else { collapsed = *m_original_its; // copy } @@ -288,14 +283,14 @@ void GLGizmoSimplify::process() its_quadric_edge_collapse(collapsed, triangle_count, &max_error, throw_on_cancel, statusfn); set_its(collapsed); m_is_valid_result = true; + m_last_count = triangle_count; // need to store last requirement, collapsed count could be count-1 m_last_error = max_error; } catch (SimplifyCanceledException &) { // set state out of main thread + m_last_error = {}; m_state = State::settings; } - // need to render last status fn - // without sleep it freezes until mouse move - std::this_thread::sleep_for(std::chrono::milliseconds(50)); + // need to render last status fn to change bar graph to buttons m_parent.schedule_extra_frame(0); }); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index 57174b7c1..5a84cabad 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -36,17 +36,18 @@ private: size_t m_obj_index; std::optional m_original_its; + std::optional m_last_error; // for use previous reduction + std::optional m_last_count; volatile bool m_need_reload; // after simplify, glReload must be on main thread std::thread m_worker; enum class State { settings, - simplifying, // start processing - canceling, // canceled - successfull, // successful simplified - close_on_end + preview, // simplify to show preview + close_on_end, // simplify with close on end + canceling // after button click, before canceled }; volatile State m_state; From 1e863cc03181aeff0989c3c9974d0850a0ad7600 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 18 Aug 2021 10:37:08 +0200 Subject: [PATCH 08/86] Add restriction for simplification Refuse outgoing during simlification. Refuse start simplification when other Gizmo is active Fix close after preview to revert changes Allow change model for simplification --- src/slic3r/GUI/GUI_ObjectList.cpp | 18 ++++++++- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 47 ++++++++++++++++------- src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 8 +++- src/slic3r/GUI/Plater.cpp | 6 +++ 4 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 07119b8de..decd55dd2 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -3961,7 +3961,23 @@ void ObjectList::fix_through_netfabb() void ObjectList::simplify() { - GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager(); + auto plater = wxGetApp().plater(); + GLGizmosManager& gizmos_mgr = plater->canvas3D()->get_gizmos_manager(); + + // Do not simplify when a gizmo is open. There might be issues with updates + // and what is worse, the snapshot time would refer to the internal stack. + auto current_type = gizmos_mgr.get_current_type(); + if (current_type == GLGizmosManager::Simplify) { + // close first + gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify); + }else if (current_type != GLGizmosManager::Undefined) { + plater->get_notification_manager()->push_notification( + NotificationType::CustomSupportsAndSeamRemovedAfterRepair, + NotificationManager::NotificationLevel::RegularNotification, + _u8L("ERROR: Please close all manipulators available from " + "the left toolbar before start simplify the mesh.")); + return; + } gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 06a999cad..a921a121e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -1,17 +1,14 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoSimplify.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/GUI_ObjectManipulation.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp" +#include "slic3r/GUI/NotificationManager.hpp" +#include "slic3r/GUI/Plater.hpp" #include "libslic3r/AppConfig.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/QuadricEdgeCollapse.hpp" -#include -#include - namespace Slic3r::GUI { GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D & parent, @@ -38,7 +35,6 @@ bool GLGizmoSimplify::on_init() return true; } - std::string GLGizmoSimplify::on_get_name() const { return (_L("Simplify")).ToUTF8().data(); @@ -195,6 +191,11 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi process(); } else { // use preview and close + if (m_original_its.has_value()) { + // fix hollowing, sla support points, modifiers, ... + auto plater = wxGetApp().plater(); + plater->changed_mesh(m_obj_index); + } close(); } } @@ -213,18 +214,17 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi if (m_need_reload) { m_need_reload = false; - + bool close_on_end = (m_state == State::close_on_end); // Reload visualization of mesh - change VBO, FBO on GPU m_parent.reload_scene(true); - if (m_state == State::close_on_end) { + // set m_state must be before close() !!! + m_state = State::settings; + if (close_on_end) { // fix hollowing, sla support points, modifiers, ... auto plater = wxGetApp().plater(); plater->changed_mesh(m_obj_index); close(); } - - // change from simplifying | apply - m_state = State::settings; // Fix warning icon in object list wxGetApp().obj_list()->update_item_error_icon(m_obj_index, -1); @@ -287,7 +287,6 @@ void GLGizmoSimplify::process() m_last_error = max_error; } catch (SimplifyCanceledException &) { // set state out of main thread - m_last_error = {}; m_state = State::settings; } // need to render last status fn to change bar graph to buttons @@ -310,10 +309,30 @@ bool GLGizmoSimplify::on_is_activable() const } void GLGizmoSimplify::on_set_state() -{ +{ // Closing gizmo. e.g. selecting another one if (GLGizmoBase::m_state == GLGizmoBase::Off) { - m_volume = nullptr; + + // refuse outgoing during simlification + if (m_state != State::settings) { + GLGizmoBase::m_state = GLGizmoBase::On; + auto notification_manager = wxGetApp().plater()->get_notification_manager(); + notification_manager->push_notification( + NotificationType::CustomNotification, + NotificationManager::NotificationLevel::RegularNotification, + _u8L("ERROR: Wait until Simplification ends or Cancel process.")); + return; + } + + // revert preview + if (m_original_its.has_value()) { + set_its(*m_original_its); + m_parent.reload_scene(true); + m_need_reload = false; + } + + // invalidate selected model + m_volume = nullptr; } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index 5a84cabad..4539fef01 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -1,14 +1,20 @@ #ifndef slic3r_GLGizmoSimplify_hpp_ #define slic3r_GLGizmoSimplify_hpp_ +// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, +// which overrides our localization "L" macro. #include "GLGizmoBase.hpp" -#include "libslic3r/Model.hpp" +#include "admesh/stl.h" // indexed_triangle_set #include #include namespace Slic3r { + +class ModelVolume; + namespace GUI { + class GLGizmoSimplify : public GLGizmoBase { public: diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 22a1b36ae..e037a0ac8 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4283,6 +4283,12 @@ bool Plater::priv::can_fix_through_netfabb() const bool Plater::priv::can_simplify() const { + // is object for simplification selected + if (get_selected_object_idx() < 0) return false; + // is already opened? + if (q->canvas3D()->get_gizmos_manager().get_current_type() == + GLGizmosManager::EType::Simplify) + return false; return true; } From 27fcf55eaa61dd9b7fa793801099ce110e7f08f0 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 18 Aug 2021 12:07:46 +0200 Subject: [PATCH 09/86] Add cancel and statusFn into init phase of simplification Move debug functions into NDEBUG macro --- src/libslic3r/QuadricEdgeCollapse.cpp | 293 +++++++++++++++----------- 1 file changed, 171 insertions(+), 122 deletions(-) diff --git a/src/libslic3r/QuadricEdgeCollapse.cpp b/src/libslic3r/QuadricEdgeCollapse.cpp index b5568a171..c4e874c65 100644 --- a/src/libslic3r/QuadricEdgeCollapse.cpp +++ b/src/libslic3r/QuadricEdgeCollapse.cpp @@ -7,13 +7,14 @@ using namespace Slic3r; -// only private namespace not neccessary be in hpp +// only private namespace not neccessary be in .hpp namespace QuadricEdgeCollapse { using Vertices = std::vector; using Triangle = stl_triangle_vertex_indices; using Indices = std::vector; using SymMat = SimplifyMesh::implementation::SymetricMatrix; - + using ThrowOnCancel = std::function; + using StatusFn = std::function; // smallest error caused by edges, identify smallest edge in triangle struct Error { @@ -74,7 +75,8 @@ namespace QuadricEdgeCollapse { // calculate error for vertex and quadrics, triangle quadrics and triangle vertex give zero, only pozitive number double vertex_error(const SymMat &q, const Vec3d &vertex); SymMat create_quadric(const Triangle &t, const Vec3d& n, const Vertices &vertices); - std::tuple init(const indexed_triangle_set &its); + std::tuple + init(const indexed_triangle_set &its, ThrowOnCancel& throw_on_cancel, StatusFn& status_fn); std::optional find_triangle_index1(uint32_t vi, const VertexInfo& v_info, uint32_t ti, const EdgeInfos& e_infos, const Indices& indices); bool is_flipped(const Vec3f &new_vertex, uint32_t ti0, uint32_t ti1, const VertexInfo& v_info, @@ -89,129 +91,24 @@ namespace QuadricEdgeCollapse { uint32_t vi0, uint32_t vi1, uint32_t vi_top0, const Triangle &t1, CopyEdgeInfos& infos, EdgeInfos &e_infos1); void compact(const VertexInfos &v_infos, const TriangleInfos &t_infos, const EdgeInfos &e_infos, indexed_triangle_set &its); + +#ifndef NDEBUG + void store_surround(const char *obj_filename, size_t triangle_index, int depth, const indexed_triangle_set &its, + const VertexInfos &v_infos, const EdgeInfos &e_infos); + bool check_neighbors(const indexed_triangle_set &its, const TriangleInfos &t_infos, + const VertexInfos &v_infos, const EdgeInfos &e_infos); +#endif /* NDEBUG */ + } // namespace QuadricEdgeCollapse using namespace QuadricEdgeCollapse; -// store triangle surrounding to file -void store_surround(const char * obj_filename, - size_t triangle_index, - int depth, - const indexed_triangle_set &its, - const VertexInfos & v_infos, - const EdgeInfos & e_infos) -{ - std::set triangles; - // triangle index, depth - using Item = std::pair; - std::queue process; - process.push({triangle_index, depth}); - - while (!process.empty()) { - Item item = process.front(); - process.pop(); - size_t ti = item.first; - auto it = triangles.find(ti); - if (it != triangles.end()) continue; - triangles.insert(ti); - if (item.second == 0) continue; - - const Vec3i &t = its.indices[ti]; - for (size_t i = 0; i < 3; ++i) { - const auto &v_info = v_infos[t[i]]; - for (size_t d = 0; d < v_info.count; ++d) { - size_t ei = v_info.start + d; - const auto & e_info = e_infos[ei]; - auto it = triangles.find(e_info.t_index); - if (it != triangles.end()) continue; - process.push({e_info.t_index, item.second - 1}); - } - } - } - - std::vector trs; - trs.reserve(triangles.size()); - for (size_t ti : triangles) trs.push_back(ti); - its_store_triangles(its, obj_filename, trs); - //its_write_obj(its,"original.obj"); -} - -bool check_neighbors(const indexed_triangle_set &its, - const TriangleInfos & t_infos, - const VertexInfos & v_infos, - const EdgeInfos & e_infos) -{ - VertexInfos v_infos2(v_infos.size()); - size_t count_indices = 0; - - for (size_t ti = 0; ti < its.indices.size(); ti++) { - if (t_infos[ti].is_deleted()) continue; - ++count_indices; - const Triangle &t = its.indices[ti]; - for (size_t e = 0; e < 3; e++) { - VertexInfo &v_info = v_infos2[t[e]]; - ++v_info.count; // triangle count - } - } - - uint32_t triangle_start = 0; - for (VertexInfo &v_info : v_infos2) { - v_info.start = triangle_start; - triangle_start += v_info.count; - // set filled vertex to zero - v_info.count = 0; - } - - // create reference - EdgeInfos e_infos2(count_indices * 3); - for (size_t ti = 0; ti < its.indices.size(); ti++) { - if (t_infos[ti].is_deleted()) continue; - const Triangle &t = its.indices[ti]; - for (size_t j = 0; j < 3; ++j) { - VertexInfo &v_info = v_infos2[t[j]]; - size_t ei = v_info.start + v_info.count; - assert(ei < e_infos2.size()); - EdgeInfo &e_info = e_infos2[ei]; - e_info.t_index = ti; - e_info.edge = j; - ++v_info.count; - } - } - - for (size_t vi = 0; vi < its.vertices.size(); vi++) { - const VertexInfo &v_info = v_infos[vi]; - if (v_info.is_deleted()) continue; - const VertexInfo &v_info2 = v_infos2[vi]; - if (v_info.count != v_info2.count) { - return false; - } - EdgeInfos eis; - eis.reserve(v_info.count); - std::copy(e_infos.begin() + v_info.start, - e_infos.begin() + v_info.start + v_info.count, - std::back_inserter(eis)); - auto compare = [](const EdgeInfo &ei1, const EdgeInfo &ei2) { - return ei1.t_index < ei2.t_index; - }; - std::sort(eis.begin(), eis.end(), compare); - std::sort(e_infos2.begin() + v_info2.start, - e_infos2.begin() + v_info2.start + v_info2.count, - compare); - for (size_t ei = 0; ei < v_info.count; ++ei) { - if (eis[ei].t_index != e_infos2[ei + v_info2.start].t_index) { - return false; - } - } - } - return true; -} - void Slic3r::its_quadric_edge_collapse( indexed_triangle_set & its, uint32_t triangle_count, float * max_error, std::function throw_on_cancel, - std::function statusfn) + std::function status_fn) { // constants --> may be move to config const int status_init_size = 10; // in percents @@ -222,15 +119,19 @@ void Slic3r::its_quadric_edge_collapse( float maximal_error = (max_error == nullptr)? std::numeric_limits::max() : *max_error; if (maximal_error <= 0.f) return; if (throw_on_cancel == nullptr) throw_on_cancel = []() {}; - if (statusfn == nullptr) statusfn = [](int) {}; + if (status_fn == nullptr) status_fn = [](int) {}; + + StatusFn init_status_fn = [&](int percent) { + status_fn(std::round((percent * status_init_size) / 100.)); + }; TriangleInfos t_infos; // only normals with information about deleted triangle VertexInfos v_infos; EdgeInfos e_infos; Errors errors; - std::tie(t_infos, v_infos, e_infos, errors) = init(its); + std::tie(t_infos, v_infos, e_infos, errors) = init(its, throw_on_cancel, init_status_fn); throw_on_cancel(); - statusfn(status_init_size); + status_fn(status_init_size); //its_store_triangle(its, "triangle.obj", 1182); //store_surround("triangle_surround1.obj", 1182, 1, its, v_infos, e_infos); @@ -259,7 +160,7 @@ void Slic3r::its_quadric_edge_collapse( (double) count_triangle_to_reduce; double status = status_init_size + (100 - status_init_size) * (1. - reduced); - statusfn(static_cast(std::round(status))); + status_fn(static_cast(std::round(status))); }; // modulo for update status uint32_t status_mod = std::max(uint32_t(16), count_triangle_to_reduce / 100); @@ -481,8 +382,16 @@ SymMat QuadricEdgeCollapse::create_quadric(const Triangle &t, } std::tuple -QuadricEdgeCollapse::init(const indexed_triangle_set &its) +QuadricEdgeCollapse::init(const indexed_triangle_set &its, ThrowOnCancel& throw_on_cancel, StatusFn& status_fn) { + // change speed of progress bargraph + const int status_normal_size = 25; + const int status_sum_quadric = 25; + const int status_set_offsets = 10; + const int status_calc_errors = 30; + const int status_create_refs = 10; + + int status_offset = 0; TriangleInfos t_infos(its.indices.size()); VertexInfos v_infos(its.vertices.size()); { @@ -496,8 +405,13 @@ QuadricEdgeCollapse::init(const indexed_triangle_set &its) Vec3d normal = create_normal(t, its.vertices); t_info.n = normal.cast(); triangle_quadrics[i] = create_quadric(t, normal, its.vertices); + if (i % 1000000 == 0) { + throw_on_cancel(); + status_fn(status_offset + (i * status_normal_size) / its.indices.size()); + } } }); // END parallel for + status_offset += status_normal_size; // sum quadrics for (size_t i = 0; i < its.indices.size(); i++) { @@ -508,7 +422,12 @@ QuadricEdgeCollapse::init(const indexed_triangle_set &its) v_info.q += q; ++v_info.count; // triangle count } + if (i % 1000000 == 0) { + throw_on_cancel(); + status_fn(status_offset + (i * status_sum_quadric) / its.indices.size()); + } } + status_offset += status_sum_quadric; } // remove triangle quadrics // set offseted starts @@ -521,6 +440,10 @@ QuadricEdgeCollapse::init(const indexed_triangle_set &its) } assert(its.indices.size() * 3 == triangle_start); + status_offset += status_set_offsets; + throw_on_cancel(); + status_fn(status_offset); + // calc error Errors errors(its.indices.size()); tbb::parallel_for(tbb::blocked_range(0, its.indices.size()), @@ -529,8 +452,15 @@ QuadricEdgeCollapse::init(const indexed_triangle_set &its) const Triangle &t = its.indices[i]; TriangleInfo & t_info = t_infos[i]; errors[i] = calculate_error(i, t, its.vertices, v_infos, t_info.min_index); + if (i % 1000000 == 0) { + throw_on_cancel(); + status_fn(status_offset + (i * status_calc_errors) / its.indices.size()); + } + if (i % 1000000 == 0) throw_on_cancel(); } }); // END parallel for + + status_offset += status_calc_errors; // create reference EdgeInfos e_infos(its.indices.size() * 3); @@ -545,7 +475,14 @@ QuadricEdgeCollapse::init(const indexed_triangle_set &its) e_info.edge = j; ++v_info.count; } + if (i % 1000000 == 0) { + throw_on_cancel(); + status_fn(status_offset + (i * status_create_refs) / its.indices.size()); + } } + + throw_on_cancel(); + status_fn(100); return {t_infos, v_infos, e_infos, errors}; } @@ -794,3 +731,115 @@ void QuadricEdgeCollapse::compact(const VertexInfos & v_infos, } its.indices.erase(its.indices.begin() + ti_new, its.indices.end()); } + +#ifndef NDEBUG +// store triangle surrounding to file +void QuadricEdgeCollapse::store_surround(const char *obj_filename, + size_t triangle_index, + int depth, + const indexed_triangle_set &its, + const VertexInfos & v_infos, + const EdgeInfos & e_infos) +{ + std::set triangles; + // triangle index, depth + using Item = std::pair; + std::queue process; + process.push({triangle_index, depth}); + + while (!process.empty()) { + Item item = process.front(); + process.pop(); + size_t ti = item.first; + auto it = triangles.find(ti); + if (it != triangles.end()) continue; + triangles.insert(ti); + if (item.second == 0) continue; + + const Vec3i &t = its.indices[ti]; + for (size_t i = 0; i < 3; ++i) { + const auto &v_info = v_infos[t[i]]; + for (size_t d = 0; d < v_info.count; ++d) { + size_t ei = v_info.start + d; + const auto &e_info = e_infos[ei]; + auto it = triangles.find(e_info.t_index); + if (it != triangles.end()) continue; + process.push({e_info.t_index, item.second - 1}); + } + } + } + + std::vector trs; + trs.reserve(triangles.size()); + for (size_t ti : triangles) trs.push_back(ti); + its_store_triangles(its, obj_filename, trs); + // its_write_obj(its,"original.obj"); +} + +bool QuadricEdgeCollapse::check_neighbors(const indexed_triangle_set &its, + const TriangleInfos & t_infos, + const VertexInfos & v_infos, + const EdgeInfos & e_infos) +{ + VertexInfos v_infos2(v_infos.size()); + size_t count_indices = 0; + + for (size_t ti = 0; ti < its.indices.size(); ti++) { + if (t_infos[ti].is_deleted()) continue; + ++count_indices; + const Triangle &t = its.indices[ti]; + for (size_t e = 0; e < 3; e++) { + VertexInfo &v_info = v_infos2[t[e]]; + ++v_info.count; // triangle count + } + } + + uint32_t triangle_start = 0; + for (VertexInfo &v_info : v_infos2) { + v_info.start = triangle_start; + triangle_start += v_info.count; + // set filled vertex to zero + v_info.count = 0; + } + + // create reference + EdgeInfos e_infos2(count_indices * 3); + for (size_t ti = 0; ti < its.indices.size(); ti++) { + if (t_infos[ti].is_deleted()) continue; + const Triangle &t = its.indices[ti]; + for (size_t j = 0; j < 3; ++j) { + VertexInfo &v_info = v_infos2[t[j]]; + size_t ei = v_info.start + v_info.count; + assert(ei < e_infos2.size()); + EdgeInfo &e_info = e_infos2[ei]; + e_info.t_index = ti; + e_info.edge = j; + ++v_info.count; + } + } + + for (size_t vi = 0; vi < its.vertices.size(); vi++) { + const VertexInfo &v_info = v_infos[vi]; + if (v_info.is_deleted()) continue; + const VertexInfo &v_info2 = v_infos2[vi]; + if (v_info.count != v_info2.count) { return false; } + EdgeInfos eis; + eis.reserve(v_info.count); + std::copy(e_infos.begin() + v_info.start, + e_infos.begin() + v_info.start + v_info.count, + std::back_inserter(eis)); + auto compare = [](const EdgeInfo &ei1, const EdgeInfo &ei2) { + return ei1.t_index < ei2.t_index; + }; + std::sort(eis.begin(), eis.end(), compare); + std::sort(e_infos2.begin() + v_info2.start, + e_infos2.begin() + v_info2.start + v_info2.count, compare); + for (size_t ei = 0; ei < v_info.count; ++ei) { + if (eis[ei].t_index != e_infos2[ei + v_info2.start].t_index) { + return false; + } + } + } + return true; +} +#endif /* NDEBUG */ From 12328a74f70fdd1b11153dcb8f1787bfe5330143 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Aug 2021 10:15:42 +0200 Subject: [PATCH 10/86] Desktop integration changes empty catch block fix internal namespace fix wrong app config var Desktop integration for regular executables cmake option SLIC3R_DESKTOP_INTEGRATION cmake dependent option escape executable path in desktop file by adding /' Error messages instead of notifications. --- CMakeLists.txt | 7 ++ src/slic3r/GUI/DesktopIntegrationDialog.cpp | 94 ++++++++++----------- src/slic3r/GUI/GUI_App.cpp | 8 +- 3 files changed, 58 insertions(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a69d3bbf..a7d3dbf92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ project(PrusaSlicer) include("version.inc") include(GNUInstallDirs) +include(CMakeDependentOption) set(SLIC3R_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources") file(TO_NATIVE_PATH "${SLIC3R_RESOURCES_DIR}" SLIC3R_RESOURCES_DIR_WIN) @@ -32,6 +33,8 @@ option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1) option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1) option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0) option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0) +# If SLIC3R_FHS is 1 -> SLIC3R_DESKTOP_INTEGRATION is always 0, othrewise variable. +CMAKE_DEPENDENT_OPTION(SLIC3R_DESKTOP_INTEGRATION "Allow perfoming desktop integration during runtime" 0 "NOT SLIC3R_FHS" 0) set(OPENVDB_FIND_MODULE_PATH "" CACHE PATH "Path to OpenVDB installation's find modules.") @@ -71,6 +74,10 @@ if (SLIC3R_GUI) add_definitions(-DSLIC3R_GUI) endif () +if(SLIC3R_DESKTOP_INTEGRATION) + add_definitions(-DSLIC3R_DESKTOP_INTEGRATION) +endif () + if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) set(IS_CLANG_CL TRUE) diff --git a/src/slic3r/GUI/DesktopIntegrationDialog.cpp b/src/slic3r/GUI/DesktopIntegrationDialog.cpp index a2f7c8933..1ec008bd5 100644 --- a/src/slic3r/GUI/DesktopIntegrationDialog.cpp +++ b/src/slic3r/GUI/DesktopIntegrationDialog.cpp @@ -1,15 +1,18 @@ #ifdef __linux__ #include "DesktopIntegrationDialog.hpp" #include "GUI_App.hpp" +#include "GUI.hpp" #include "format.hpp" #include "I18N.hpp" #include "NotificationManager.hpp" #include "libslic3r/AppConfig.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/Platform.hpp" +#include "libslic3r/Config.hpp" #include #include +#include #include #include @@ -17,9 +20,9 @@ namespace Slic3r { namespace GUI { -namespace integrate_desktop_internal{ +namespace { // Disects path strings stored in system variable divided by ':' and adds into vector -static void resolve_path_from_var(const std::string& var, std::vector& paths) +void resolve_path_from_var(const std::string& var, std::vector& paths) { wxString wxdirs; if (! wxGetEnv(boost::nowide::widen(var), &wxdirs) || wxdirs.empty() ) @@ -34,7 +37,7 @@ static void resolve_path_from_var(const std::string& var, std::vectorget("desktop_integration_app_path")); BOOST_LOG_TRIVIAL(debug) << "Desktop integration desktop file path: " << path; @@ -126,10 +125,6 @@ bool DesktopIntegrationDialog::is_integrated() } bool DesktopIntegrationDialog::integration_possible() { - - const char *appimage_env = std::getenv("APPIMAGE"); - if (!appimage_env) - return false; return true; } void DesktopIntegrationDialog::perform_desktop_integration() @@ -143,14 +138,26 @@ void DesktopIntegrationDialog::perform_desktop_integration() try { appimage_path = boost::filesystem::canonical(boost::filesystem::path(appimage_env)).string(); } catch (std::exception &) { + BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - boost::filesystem::canonical did not return appimage path."; + show_error(nullptr, _L("Performing desktop integration failed - boost::filesystem::canonical did not return appimage path.")); + return; } } else { - // not appimage - not performing - BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - not Appimage executable."; - wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationFail); - return; + // not appimage - find executable + appimage_path = boost::dll::program_location().string(); + //appimage_path = wxStandardPaths::Get().GetExecutablePath().string(); + BOOST_LOG_TRIVIAL(debug) << "non-appimage path to executable: " << appimage_path; + if (appimage_path.empty()) + { + BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - no executable found."; + show_error(nullptr, _L("Performing desktop integration failed - Could not find executable.")); + return; + } } + // Escape ' characters in appimage, other special symbols will be esacaped in desktop file by 'appimage_path' + //appimage_path = std::regex_replace(appimage_path, std::regex("\'"), "\\\'"); + // Find directories icons and applications // $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored. // If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used. @@ -158,8 +165,8 @@ void DesktopIntegrationDialog::perform_desktop_integration() // The directories in $XDG_DATA_DIRS should be seperated with a colon ':'. // If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used. std::vectortarget_candidates; - integrate_desktop_internal::resolve_path_from_var("XDG_DATA_HOME", target_candidates); - integrate_desktop_internal::resolve_path_from_var("XDG_DATA_DIRS", target_candidates); + resolve_path_from_var("XDG_DATA_HOME", target_candidates); + resolve_path_from_var("XDG_DATA_DIRS", target_candidates); AppConfig *app_config = wxGetApp().app_config; // suffix string to create different desktop file for alpha, beta. @@ -186,7 +193,6 @@ void DesktopIntegrationDialog::perform_desktop_integration() icon_theme_dirs = "/hicolor/96x96/apps"; } - std::string target_dir_icons; std::string target_dir_desktop; @@ -194,24 +200,24 @@ void DesktopIntegrationDialog::perform_desktop_integration() // iterate thru target_candidates to find icons folder for (size_t i = 0; i < target_candidates.size(); ++i) { // Copy icon PrusaSlicer.png from resources_dir()/icons to target_dir_icons/icons/ - if (integrate_desktop_internal::contains_path_dir(target_candidates[i], "icons")) { + if (contains_path_dir(target_candidates[i], "icons")) { target_dir_icons = target_candidates[i]; std::string icon_path = GUI::format("%1%/icons/PrusaSlicer.png",resources_dir()); std::string dest_path = GUI::format("%1%/icons/%2%PrusaSlicer%3%.png", target_dir_icons, icon_theme_path, version_suffix); - if (integrate_desktop_internal::copy_icon(icon_path, dest_path)) + if (copy_icon(icon_path, dest_path)) break; // success else target_dir_icons.clear(); // copying failed // if all failed - try creating default home folder if (i == target_candidates.size() - 1) { // create $HOME/.local/share - integrate_desktop_internal::create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/icons" + icon_theme_dirs); + create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/icons" + icon_theme_dirs); // copy icon target_dir_icons = GUI::format("%1%/.local/share",wxFileName::GetHomeDir()); std::string icon_path = GUI::format("%1%/icons/PrusaSlicer.png",resources_dir()); std::string dest_path = GUI::format("%1%/icons/%2%PrusaSlicer%3%.png", target_dir_icons, icon_theme_path, version_suffix); - if (!integrate_desktop_internal::contains_path_dir(target_dir_icons, "icons") - || !integrate_desktop_internal::copy_icon(icon_path, dest_path)) { + if (!contains_path_dir(target_dir_icons, "icons") + || !copy_icon(icon_path, dest_path)) { // every attempt failed - icon wont be present target_dir_icons.clear(); } @@ -228,7 +234,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() // iterate thru target_candidates to find applications folder for (size_t i = 0; i < target_candidates.size(); ++i) { - if (integrate_desktop_internal::contains_path_dir(target_candidates[i], "applications")) { + if (contains_path_dir(target_candidates[i], "applications")) { target_dir_desktop = target_candidates[i]; // Write slicer desktop file std::string desktop_file = GUI::format( @@ -236,7 +242,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() "Name=PrusaSlicer%1%\n" "GenericName=3D Printing Software\n" "Icon=PrusaSlicer%2%\n" - "Exec=%3% %%F\n" + "Exec=\'%3%\' %%F\n" "Terminal=false\n" "Type=Application\n" "MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;\n" @@ -246,23 +252,23 @@ void DesktopIntegrationDialog::perform_desktop_integration() "StartupWMClass=prusa-slicer", name_suffix, version_suffix, appimage_path); std::string path = GUI::format("%1%/applications/PrusaSlicer%2%.desktop", target_dir_desktop, version_suffix); - if (integrate_desktop_internal::create_desktop_file(path, desktop_file)){ + if (create_desktop_file(path, desktop_file)){ BOOST_LOG_TRIVIAL(debug) << "PrusaSlicer.desktop file installation success."; break; } else { // write failed - try another path - BOOST_LOG_TRIVIAL(error) << "PrusaSlicer.desktop file installation failed."; + BOOST_LOG_TRIVIAL(debug) << "Attempt to PrusaSlicer.desktop file installation failed. failed path: " << target_candidates[i]; target_dir_desktop.clear(); } // if all failed - try creating default home folder if (i == target_candidates.size() - 1) { // create $HOME/.local/share - integrate_desktop_internal::create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/applications"); + create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/applications"); // create desktop file target_dir_desktop = GUI::format("%1%/.local/share",wxFileName::GetHomeDir()); std::string path = GUI::format("%1%/applications/PrusaSlicer%2%.desktop", target_dir_desktop, version_suffix); - if (integrate_desktop_internal::contains_path_dir(target_dir_desktop, "applications")) { - if (!integrate_desktop_internal::create_desktop_file(path, desktop_file)) { + if (contains_path_dir(target_dir_desktop, "applications")) { + if (!create_desktop_file(path, desktop_file)) { // Desktop file not written - end desktop integration BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could not create desktop file"; return; @@ -278,7 +284,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() if(target_dir_desktop.empty()) { // Desktop file not written - end desktop integration BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could not find applications directory"; - wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationFail); + show_error(nullptr, _L("Performing desktop integration failed - could not find applications directory.")); return; } // save path to desktop file @@ -290,7 +296,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() { std::string icon_path = GUI::format("%1%/icons/PrusaSlicer-gcodeviewer_192px.png",resources_dir()); std::string dest_path = GUI::format("%1%/icons/%2%PrusaSlicer-gcodeviewer%3%.png", target_dir_icons, icon_theme_path, version_suffix); - if (integrate_desktop_internal::copy_icon(icon_path, dest_path)) + if (copy_icon(icon_path, dest_path)) // save path to icon app_config->set("desktop_integration_icon_viewer_path", dest_path); else @@ -303,7 +309,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() "Name=Prusa Gcode Viewer%1%\n" "GenericName=3D Printing Software\n" "Icon=PrusaSlicer-gcodeviewer%2%\n" - "Exec=%3% --gcodeviwer %%F\n" + "Exec=\'%3%\' --gcodeviwer %%F\n" "Terminal=false\n" "Type=Application\n" "MimeType=text/x.gcode;\n" @@ -312,23 +318,17 @@ void DesktopIntegrationDialog::perform_desktop_integration() "StartupNotify=false", name_suffix, version_suffix, appimage_path); std::string desktop_path = GUI::format("%1%/applications/PrusaSlicerGcodeViewer%2%.desktop", target_dir_desktop, version_suffix); - if (integrate_desktop_internal::create_desktop_file(desktop_path, desktop_file)) + if (create_desktop_file(desktop_path, desktop_file)) // save path to desktop file app_config->set("desktop_integration_app_viewer_path", desktop_path); else { - BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could create gcode viewer desktop file"; - wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationFail); + BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could not create Gcodeviewer desktop file"; + show_error(nullptr, _L("Performing desktop integration failed - could not create Gcodeviewer desktop file. PrusaSlicer desktop file was probably created successfully.")); } wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationSuccess); } void DesktopIntegrationDialog::undo_desktop_intgration() { - const char *appimage_env = std::getenv("APPIMAGE"); - if (!appimage_env) { - BOOST_LOG_TRIVIAL(error) << "Undo desktop integration failed - not Appimage executable."; - wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::UndoDesktopIntegrationFail); - return; - } const AppConfig *app_config = wxGetApp().app_config; // slicer .desktop std::string path = std::string(app_config->get("desktop_integration_app_path")); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 91d16c602..06d805eeb 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1806,10 +1806,10 @@ void GUI_App::add_config_menu(wxMenuBar *menu) local_menu->Append(config_id_base + ConfigMenuSnapshots, _L("&Configuration Snapshots") + dots, _L("Inspect / activate configuration snapshots")); local_menu->Append(config_id_base + ConfigMenuTakeSnapshot, _L("Take Configuration &Snapshot"), _L("Capture a configuration snapshot")); local_menu->Append(config_id_base + ConfigMenuUpdate, _L("Check for updates"), _L("Check for configuration updates")); -#ifdef __linux__ - if (DesktopIntegrationDialog::integration_possible()) - local_menu->Append(config_id_base + ConfigMenuDesktopIntegration, _L("Desktop Integration"), _L("Desktop Integration")); -#endif +#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) + //if (DesktopIntegrationDialog::integration_possible()) + local_menu->Append(config_id_base + ConfigMenuDesktopIntegration, _L("Desktop Integration"), _L("Desktop Integration")); +#endif //(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) local_menu->AppendSeparator(); } local_menu->Append(config_id_base + ConfigMenuPreferences, _L("&Preferences") + dots + From b686b5764efbc49ab4bc6f5ccabb496bddd893d1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 19 Aug 2021 10:22:26 +0200 Subject: [PATCH 11/86] Fix opening of gizmos after clicking on info lines in object list when object has instances --- src/slic3r/GUI/GUI_ObjectList.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 318705e09..0c555454d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -3404,6 +3404,18 @@ void ObjectList::update_selections_on_canvas() std::vector idxs = selection.get_volume_idxs_from_instance(obj_idx, inst_idx); volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end()); } + else if (type == itInfo) { + // When selecting an info item, select one instance of the + // respective object - a gizmo may want to be opened. + int inst_idx = selection.get_instance_idx(); + int scene_obj_idx = selection.get_object_idx(); + mode = Selection::Instance; + // select first instance, unless an instance of the object is already selected + if (scene_obj_idx == -1 || inst_idx == -1 || scene_obj_idx != obj_idx) + inst_idx = 0; + std::vector idxs = selection.get_volume_idxs_from_instance(obj_idx, inst_idx); + volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end()); + } else { mode = Selection::Instance; @@ -3418,7 +3430,7 @@ void ObjectList::update_selections_on_canvas() if (sel_cnt == 1) { wxDataViewItem item = GetSelection(); - if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer | itInfo)) + if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer)) add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, mode); else add_to_selection(item, selection, instance_idx, mode); From 97418cf9f59e1f78f554975473b02eb50980b975 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Aug 2021 10:27:23 +0200 Subject: [PATCH 12/86] Desktop integration in config wizard ifdef --- src/slic3r/GUI/ConfigWizard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index f64bdecba..bc56fe97e 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -494,7 +494,7 @@ PageWelcome::PageWelcome(ConfigWizard *parent) { welcome_text->Hide(); cbox_reset->Hide(); -#ifdef __linux__ +#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) if (!DesktopIntegrationDialog::is_integrated()) cbox_integrate->Show(true); else From c08b4be0e650fd47e073daea9fb1bb3971fc9829 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Aug 2021 11:00:36 +0200 Subject: [PATCH 13/86] Fix of missplaced checkbox Perform desktop integration in config wizard. --- src/slic3r/GUI/ConfigWizard.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index bc56fe97e..3f388f485 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -494,15 +494,7 @@ PageWelcome::PageWelcome(ConfigWizard *parent) { welcome_text->Hide(); cbox_reset->Hide(); -#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) - if (!DesktopIntegrationDialog::is_integrated()) - cbox_integrate->Show(true); - else - cbox_integrate->Hide(); -#else - cbox_integrate->Hide(); -#endif - + cbox_integrate->Hide(); } void PageWelcome::set_run_reason(ConfigWizard::RunReason run_reason) @@ -510,7 +502,7 @@ void PageWelcome::set_run_reason(ConfigWizard::RunReason run_reason) const bool data_empty = run_reason == ConfigWizard::RR_DATA_EMPTY; welcome_text->Show(data_empty); cbox_reset->Show(!data_empty); -#ifdef __linux__ +#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) if (!DesktopIntegrationDialog::is_integrated()) cbox_integrate->Show(true); else From 316d38807d64e377c4b1d3a71f8c9587dcc82066 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 19 Aug 2021 11:54:41 +0200 Subject: [PATCH 14/86] Simplified shader printbed.vs --- resources/shaders/printbed.vs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/shaders/printbed.vs b/resources/shaders/printbed.vs index ac4763782..ee19098c1 100644 --- a/resources/shaders/printbed.vs +++ b/resources/shaders/printbed.vs @@ -1,12 +1,12 @@ #version 110 -attribute vec4 v_position; +attribute vec3 v_position; attribute vec2 v_tex_coords; varying vec2 tex_coords; void main() { - gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * v_position; + gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position, 1.0); tex_coords = v_tex_coords; } From adfb5b6b4960224c23fec9531765f8d9fdf7ff45 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 19 Aug 2021 12:12:25 +0200 Subject: [PATCH 15/86] Small refactoring into GLModel::render() --- src/slic3r/GUI/GLModel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 6d54ec20e..a9550bc04 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -169,6 +169,8 @@ void GLModel::reset() void GLModel::render() const { + GLShaderProgram* shader = wxGetApp().get_current_shader(); + for (const RenderData& data : m_render_data) { if (data.vbo_id == 0 || data.ibo_id == 0) continue; @@ -190,7 +192,6 @@ void GLModel::render() const glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - GLShaderProgram* shader = wxGetApp().get_current_shader(); if (shader != nullptr) shader->set_uniform("uniform_color", data.color); else From 6d44bde96d6e11e22d34beaa85a9d480ec7c2590 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Aug 2021 12:36:18 +0200 Subject: [PATCH 16/86] Progress notification: fix of wrong method call. --- src/slic3r/GUI/NotificationManager.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index b347c9dfe..2bc9aaaab 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -391,7 +391,7 @@ private: { public: - ProgressBarNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage) : PopNotification(n, id_provider, evt_handler) { set_percentage(percentage); } + ProgressBarNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage) : PopNotification(n, id_provider, evt_handler) { } virtual void set_percentage(float percent) { m_percentage = percent; } protected: virtual void init() override; @@ -434,6 +434,7 @@ private: , m_file_size(filesize) { m_has_cancel_button = true; + set_percentage(percentage); } static std::string get_upload_job_text(int id, const std::string& filename, const std::string& host) { return /*"[" + std::to_string(id) + "] " + */filename + " -> " + host; } void set_percentage(float percent) override; From 8f58b11b085925774fd3172bca339b4f15d1412a Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Aug 2021 14:01:54 +0200 Subject: [PATCH 17/86] Rotated arrow asset. --- resources/icons/toolbar_arrow.png | Bin 3996 -> 3996 bytes resources/icons/toolbar_arrow.svg | 83 ++++++++++++++++++---- src/slic3r/GUI/GLToolbar.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- 4 files changed, 71 insertions(+), 16 deletions(-) diff --git a/resources/icons/toolbar_arrow.png b/resources/icons/toolbar_arrow.png index 90ddce38f0c0dfa71dc4d6abdf07fd8a74b43a01..a370442ff0e933b85d436f3abac584b2e5ac3f37 100644 GIT binary patch literal 3996 zcmeHK_cI&-)4qrn9EskEe$hM8+i6j94yQ&ZN{F5l5vPR^33Ac7aD;G3^p+e)ln}ig z=afW?UZcLg-@gCheP?#(+1+_|W@mqRb~e%6R3AviP6Yq}fQAOTkZTMF0B(>|l3zy{ zm4}npa3ct!uMNNqa;{w`q@G$PS^z*zD)qTD*>!#^z`!O50HE#sKfm$A|C8Hwku6vc z7Hr|~5gg_m=ne=A3zK;K#3#trIlx`QKhQI0OO^ea{nJoa3mWdYnRhF|u8ZwQSb^Az zda&S)G#G>=dPLhUUVDv9ycUht)FFw^Xo-c@-{p)0O*U?7uDvw`;AMbh@f`G&XmPbw zt&-qE9aJrixsz{yC?tCdnE^1gH-_W=58H=0m1@xM4-S5x0T(x;ZoWa!N1PqCHMFE5 zq#_Sx&5mG%P?15zhxb)uBGMva|5`PaBHDc&k8ez*#TGl&nI{{^bySIhiXtLnc07%y zC-yWWR^(xNw1EiA{auFii@6I(PYtXt40>5m8ncUAgXtt)Dcb28&>jS*z%b;YPeEOe z*GhVTFdZt0{*LCwY-4TUA*+4@ec#{=MV!^)IfajbCO9A}(knkF#q_6XQ*<<*p}PwXzHA>u1a6ACDonU{#b5_<{5XMZu<4WZ`;Jx z(h^cMuHk1Qctiw^6rY+1fBi zjs1Hlnh1@8&1al6ryC_h6ie7YmO7Q+FW=(K^?j8~nlsPc`W;@B*DJoBqXyosl*Y zFcRh9fO4To4qx@{Vj~o@pzE-x6qL;JDQ*15+$b?^6(mA?b%s3RY?ZaKD^J(1oZFCU zVV|VlY7v813zuG!cY#a?q%zE^OUz*TMI_=}98xXJ){4U$Rhi1P%b55@!f#~3;~}1K zZTSJNnCZGk+np2CjFPYVn!x1K2YvP1-@o`gtt3Llo`Y&zSe$}E>mzQi%Puq+-1`+` zu*I?go>@}+X|9DVNnZplAxjIr%o4LJF=rOQg<;5bWX|{YToyG?zAw*T9EgzL@Ij5r zm!XSzzWM}MG63Hc=hbY*Ev_zG<=g0l9!ZZse-8ARB;LcW!47PP&i#@tOgcPZFl#y*50p3YCwH0Ds4Z7BB zx8dlVJZQSC=T2@Tud0>dt^ngek9-^>NGz)Z(gzO@y7-&qFlnv3vz)kRipD);O(`s1 z$GJ$Kb2v(>=((N*B0V=-jA=Pjn<_FK0?MV~v~r~%oaDOBAc-3__DWPo>Fm$QYmZ9& zmAP#;xV}>LyQ3=*7RD>j?Li@mU<;AEzvFhcxqs>{d@K6QGUKhL2wEA-ywObYnu47V z$l4E{Cf#6r+2^{UqFRzu&J;Z%5vi^SuCCljt)67%*`ZCdF3IM5^c}|BCp5+1Fh`No znd?R=c)3oO@{KnAA&H+uLx)F7dh&v0Jxr}S_>Wemv8fH|k^zp)R0dq|MV8t~-iG6i z!h4G)NyJDF%sq*1WXYi@n@+Mfw|oxNM0AThf!%$t&i=rqb2#G34hGmfX(v}OS@$X z)XjF@mltL$n#?Ivd!(Sl;NU@meG-{hDcqLjR^dKv*50uEme*q`L-$%G4n&8@v$p0u zh+{2Yd*xx|QXiPwEXKz?n00FU%cQ{$B|`gNWkT5;EV;=8S%PsRD-K29s-b~4g_ZiL zwH2%uR!g`ibutlq%|FH!2i|9^+5H}*f&arDkU}&f8jNByz>`%_d zkn2lRfX?v3U5i{t-vHg*+0j|1gAOl4Bj+jGFITxP0Z?UWnn{qbs{}hg;*8^C!uPJS z-BQ7TN*IsVntY^iFJ<7kXjZPdr}nNxX*cV>+h98nq2=8IwI20EKRc|$ky_6+B9DA9 zs1jR`i(z%>tqng0qblOe<=`!hm?kqbc`&8}#;8Y);o_vr<9ViZJ@ImS{^y#%-Xyz& zESkM_tOF=qWiM>`b0$@Z2(}C+N4_$*FO|)=`R<5sdSv&}PmJ);M5K!ER#=*}>X3oP zm!=vCL=!I+v+C{F+yHGatburM*+YndTKK#`bcLT;S` zg1rV_7!Buy-|+BkG=3T+sL#vXS@E8uUT4MN(GQ_Kc3I6w%N7jrtr}fQ-e7Uq@s@9Y z5f6c7Joqo|--}=W6a`Ai9CIkq!0j1!4~~MlEw7gmlT_)V_7Zko@5ux7s_vX!T#qfJeTA_Qr`6g_IQ8TE)r#Y~hYw zy4+Epwro!TCRKjQS~f?vZTIf{Np*u^;p9#!&{Un_zYjt{TeP*IYa6Q<NcO!uj)j5QMu3gu)-?NqKv+nkp6bI@=5(`%IfE%YPXe^o$D3r^aaI~XCo z9NN42D^fC@L?7eT$HgU+^#@ds=Zl2-U~BD!xWdlWLS?0f^FEeszC*o!wD$b#UuC-i zHsueh{GNHu4#Rz`4C&=Vw^T1)yLudHz4+K99&)v!c0F0&{eB39Gi8`GrruAy z;%Ixek`#4>!y9Gid12-{?o=d4TINE%Z9cVGNSgI9YF5{st&DhiTE_)5_<7tbhNdn$ zu$NFiAEj5sqCCCb)~u-6V;iIx-!N8rc0W;UgU`K4%=g-QINfE$YLmSyZVcNCW2O2X zsUpn$6W0D%)T6{8n5Wwnq_$GlNFfVR_qk<9xY?yuTEg4@S%nhjL4%^u6%jGPjLZ^YIMLs*r;LnkX-Y-tn2a zSPf{{`^yUHHyOf1WkHg*1ydK1iF!^Z^9uM$dcA;Wg0>`VSI^ZL$u=_SQ5s9c54i7=H=JT-0BQ2IlWpN}{F8m)dh!-wVU|X;ab~K3G&TNQITJ-qEkyf2`)}I- z8`j8HS&TU*#ZKn!9s8vk2uv(q;7PA0cqc}e}5b~E!C+u%q znU@S$Ax1BLOpff|^MHIeHKwaG4~L+7LX46&7JzTC>#2)es0!+v*QZ=6J*Jq*MI)B? z>}^F^o32QR46c(Xf6I}hI89OqU)Rl&+h(g!)xUm)6w*GY>-ooGU>LoCzkYrJhI*#D z7;Ps+6=7j~FS^c&1a3MjoIcZN)f7O|jt_g$#yOV-zq{hGqIm2NpZ&ZT54ob~>jBv( LTMD)O|Nj2~#I)V2 literal 3996 zcmeH~_fr$l(uPBkUM@x=0)nE1B2@^80#bqq1}s!5p@+~>S`1QyXy{6nKqw+D^cp~- zp$k%l&1qMW`UIEH8%AeM15E&+GM@d|?!tM`>izJ!4*@QJl%X8?7W?1yk0uvHdOfm0B#OFsHQOrzMjeMZDn$$ zv%dky>G7&&+~66LexkwM&~JrZ4vbDrzEGa5n=39XI9FeafNVH)L=Vq}L1CVj@$VWl)<-AP!f9WQ9LIh~qq=TTVc7q{{1<=Ak= zH+f4_4*z;V?8~q5?Je^cvz-yous8#IhI?dG_ej~QRQoKn93dD=QdIeRBA#ge&2Z~? zUl%J;h4N^wW6;nuN1{43)7Gr0|D*j=M-X)JX)YCr)RIqxhlU;+4~a5P8=H-lR|yiGiyFw zwN;Ta`r125F*cvg2!bZ_Iz!j9T;f#Uo$W@|uXbq6vHKNZKGqKS*k=|2yBXK#j!7Ls zaWAAABDA@_i>mBNCivcd3Gp=i^fHHbD+rt@NbH5?z#Kmac;y6n*ym&*G9<;QgTenf z4R_lfnOpo|tUE7g1d_s};>J-NHi%i`wSsxdQ?Az+b{Nai$Fw&=%eDbM@4;*-5BuT; z!*QGFB5`nnr7m5DyJVD;ecuQ{xj*Z)4^;nzzT8UQ&r2*@h&)Sz8@wlO=`}J5uY8^* zBLV{rN7c6ezOfdMrQv|74sHi5z-V29wqDm1T#|>gfP)13m!hZj-tn%5Y)jnI6>v)T z%}XVT;3N+JgmOc_+F&x&E@L2;W8jbrD4m_iN+ouOE~57rs3XI#S^(c~v^M6$AtMGh|2GiFw}#-GIkJg#7udW+3JV<*6Py+}um+ z`vbzBk`eNJYsjXmcepD}bQFllthhIPVj^X z!H*_F-I@0$SpwrcQT&(8Q^Rz(a*fT7I$@WlbgEXf83fl$TI|0ODjAjhwVMS_HQF;z zC>^9WYm`a;uU`8VSFvr`yNqHeblERLK{A+uh45Es546&D#)8&q4Lhsi1}Pv z3~m*&poae+gV!Dhk3cQmN6XTwzMDSfxD4mZJic4Mt!NX{>+i+NS&%IA|@%GP@P-33?IKy3;E%&3* z(n;e2>x!xgm#u<0j4`c_JJ}@YM?7|;Mu!I(3>i}j1pY%@x6x=aBMk0+xn!4q+ zCj2u~W>PAfk|$9us!;B6o7mTCUZeER*8JD7z}b6=_-@Y&z?msV&WB@o+k#3+gUHB; z#dZY4*AHJW3r8dqGwq7k04qgLjCxGKv3i=}tcPzHoM(i8?OGHSu(jXwzapaeia);eACH@i8y^ z-iii-C_POzv^{r!IdCQvKE@Zzt0rHScORj@sUaAffo(s2rW2ik+i;h5H86x^S8fR2 z;kF-KS>Y-jImtnmt;jY4^Xl_N9CdRCvC3KD(vZGs) zj+|PH*d4(u~o`UMuHHuV0?L4{T1oMiKijdN;T&Uv6ZmyE3vV%>$R0@A#4Ar<{WPQ}$D z8ybh64+}(WI?YaNuyuTegns<_wnQSTk$$?eTH{itkRMR34S* zn5q+0)b)jy4s@<9Q3pfFjmZ=5+88B`qf8_|pO$iEl(rgrQ>da-KFFvF(~9 zqpa+87+3Lr+6g^Fu!Qh}^h->Fpn=Iv=}}+dC6zDmdzuz>$iUpw8#Bl?eP z8R~AX|FFB%1RSY;i#l!^N#VlStk0YU<+w!n+vH4 zUp30~5LO;!TP{;tp)+qLM7WQtIQ#qfQU$=NnNe(D{-fC-@sCU$9v8m>SBigp_V90% zv#1phJ=zwHMwZI{kiA)WjrTH)!)ZGGEzVlV%32bc%Nl9N3DQrYzZ*gr*|72`O?iuU zP`px}YpkA z6q+tzlq3~F2(SLUKfPB+1}@hJP1ap2ZgkLYW{967eW5_(XyfpZ28);2VqujT(n0+n z+wpbD1`9@w>5D7T&#j^N;l(n13*p_aXxA^v5|SjkVc?9T)S3B->uj`}4f44=`(NL} zL6gc;yN|D2?iBW+k8qERv9gT78PeXWw>Eok5!R@Oq8(N;&I# zSczUmw4aA|$ZP=E^r{UjxTW`JIT>@H45siM4n`t>nDq<&$+WdV!Z(KpBa~Km61!nP zSQ{4?1!C1(0>ZIDsU?qRiy8%g26eY{bv{*CE`oxOm~7a<+qYI~_C&8cX);Km_EWVE zFHEz6zjW>_HyP|opmoI4x7MeZ+{n=v_$WZ^;I(F|JSy>a% z7e%pT;GNcZ8;|?^5V15Nw*<`bjksGuM&x$?Q7c#OG%Mh6hHW_heMz#qK(v$PPlbyI z2%_xiEud>;`X$)BvpzDY8N2X%F(*G_-AjzX0=bpO(#(H@yr5ou(Qj|OVZn;d+|boR zt~ZT^*r0;)5ZtN!D=HUpLaizXNQptD)4J}r4w@)#J8lMw{;-w;_^JF2I6>oTuDQbH zG;LTuYfhd#06yV{JeY%=d3Z>jn;+@UD}+uFipxDqG)gS|YQ0mz1B*xp!?ADSzuH9T zM*Zv%qGo^;plP^EP6O^uJZ-sl$wh%ip;Cv1>rWnb6qEJkG^cOPFd9FdJ_A^Y3LK3d zp - - - and for imgui markers std::string marker_s(1, ImGui::ColorMarkerStart); std::string marker_e(1, ImGui::ColorMarkerEnd); @@ -319,6 +338,8 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) } } } + if (create_pot) + write_pot(pot_elements); } HintData* HintDatabase::get_hint(bool up) { From 0be2e3bc716ae997d156c1faf01b0e1f3ae7aed5 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 23 Aug 2021 21:16:58 +0200 Subject: [PATCH 52/86] Fixup of e5f0099 --- src/slic3r/GUI/Plater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 29368312a..97ffc6cb7 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4878,7 +4878,7 @@ ProjectDropDialog::ProjectDropDialog(const std::string& filename) _L("Select an action to apply to the file") + ": " + from_u8(filename)), 0, wxEXPAND | wxALL, 10); m_action = std::clamp(std::stoi(wxGetApp().app_config->get("drop_project_action")), - static_cast(LoadType::OpenProject) - 1, static_cast(LoadType::LoadConfig)) - 1; + static_cast(LoadType::OpenProject), static_cast(LoadType::LoadConfig)) - 1; wxStaticBox* action_stb = new wxStaticBox(this, wxID_ANY, _L("Action")); if (!wxOSX) action_stb->SetBackgroundStyle(wxBG_STYLE_PAINT); From b3010a817bdc8e63b2ad2f9d281be3ba89216ba7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 24 Aug 2021 07:46:59 +0200 Subject: [PATCH 53/86] Do not allow objects to be placed fully below bed --- src/libslic3r/Model.hpp | 1 + src/slic3r/GUI/3DScene.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 2 +- src/slic3r/GUI/Selection.cpp | 33 ++++++++++++++++++++++++++++++--- src/slic3r/GUI/Selection.hpp | 1 + 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 11dcfa775..1dd16ee91 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1177,6 +1177,7 @@ void check_model_ids_equal(const Model &model1, const Model &model2); #endif /* NDEBUG */ static const float SINKING_Z_THRESHOLD = -0.001f; +static const double SINKING_MIN_Z_THRESHOLD = 0.05; } // namespace Slic3r diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 9c0341ff4..7a9fdc388 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -595,7 +595,7 @@ bool GLVolume::is_sinking() const bool GLVolume::is_below_printbed() const { - return transformed_convex_hull_bounding_box().max(2) < 0.0; + return transformed_convex_hull_bounding_box().max.z() < 0.0; } #if ENABLE_SINKING_CONTOURS diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index b9aefcc76..498b02605 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -621,7 +621,7 @@ void MainFrame::update_title() if (!dirty_marker.empty() || !project.empty()) { if (!dirty_marker.empty() && project.empty()) project = _("Untitled"); - title = dirty_marker + project + " - "; + title = dirty_marker + project + " - "; } } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index dbc259444..acb1f1113 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -683,7 +683,8 @@ void Selection::translate(const Vec3d& displacement, bool local) synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH - this->set_bounding_boxes_dirty(); + ensure_not_below_bed(); + set_bounding_boxes_dirty(); } // Rotate an object around one of the axes. Only one rotation component is expected to be changing. @@ -1712,7 +1713,7 @@ void Selection::calc_unscaled_instance_bounding_box() const if (volume.is_modifier) continue; Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, true, false) * volume.get_volume_transformation().get_matrix(); - trafo.translation()(2) += volume.get_sla_shift_z(); + trafo.translation().z() += volume.get_sla_shift_z(); unscaled_instance_bounding_box->merge(volume.transformed_convex_hull_bounding_box(trafo)); } } @@ -1729,7 +1730,7 @@ void Selection::calc_scaled_instance_bounding_box() const if (volume.is_modifier) continue; Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, false, false) * volume.get_volume_transformation().get_matrix(); - trafo.translation()(2) += volume.get_sla_shift_z(); + trafo.translation().z() += volume.get_sla_shift_z(); scaled_instance_bounding_box->merge(volume.transformed_convex_hull_bounding_box(trafo)); } } @@ -2134,6 +2135,32 @@ void Selection::ensure_on_bed() } } +void Selection::ensure_not_below_bed() +{ + typedef std::map, double> InstancesToZMap; + InstancesToZMap instances_max_z; + + for (size_t i = 0; i < m_volumes->size(); ++i) { + GLVolume* volume = (*m_volumes)[i]; + if (!volume->is_wipe_tower && !volume->is_modifier) { + const double max_z = volume->transformed_convex_hull_bounding_box().max.z(); + std::pair instance = std::make_pair(volume->object_idx(), volume->instance_idx()); + InstancesToZMap::iterator it = instances_max_z.find(instance); + if (it == instances_max_z.end()) + it = instances_max_z.insert(InstancesToZMap::value_type(instance, -DBL_MAX)).first; + + it->second = std::max(it->second, max_z); + } + } + + for (GLVolume* volume : *m_volumes) { + std::pair instance = std::make_pair(volume->object_idx(), volume->instance_idx()); + InstancesToZMap::iterator it = instances_max_z.find(instance); + if (it != instances_max_z.end() && it->second < SINKING_MIN_Z_THRESHOLD) + volume->set_instance_offset(Z, volume->get_instance_offset(Z) + SINKING_MIN_Z_THRESHOLD - it->second); + } +} + bool Selection::is_from_fully_selected_instance(unsigned int volume_idx) const { struct SameInstance diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 0e0e869ef..b3304571f 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -385,6 +385,7 @@ public: private: void ensure_on_bed(); + void ensure_not_below_bed(); bool is_from_fully_selected_instance(unsigned int volume_idx) const; void paste_volumes_from_clipboard(); From d7d4d528439d03c43ec4b4fe90721a01b122b2c5 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Tue, 24 Aug 2021 08:21:14 +0200 Subject: [PATCH 54/86] Fix ../src/libslic3r/QuadricEdgeCollapse.cpp:565:22: warning: comparison of integer expressions of different signedness: 'const int' and 'uint32_t' {aka 'unsigned int'} [-Wsign-compare] ../src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp:48:15: warning: unused variable 'min_triangle_count' [-Wunused-variable] ../src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp:160:9: warning: unused variable 'wanted_count' [-Wunused-variable] ..\src\slic3r\GUI\Gizmos\GLGizmoSimplify.cpp(167): warning C4305: '=': truncation from 'double' to 'float' --- src/libslic3r/QuadricEdgeCollapse.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/QuadricEdgeCollapse.cpp b/src/libslic3r/QuadricEdgeCollapse.cpp index c4e874c65..6efc5f4a9 100644 --- a/src/libslic3r/QuadricEdgeCollapse.cpp +++ b/src/libslic3r/QuadricEdgeCollapse.cpp @@ -562,7 +562,7 @@ bool QuadricEdgeCollapse::degenerate(uint32_t vi, if (e_info.t_index == ti1) continue; // ti1 will be deleted const Triangle &t = indices[e_info.t_index]; for (size_t i = 0; i < 3; ++i) - if (t[i] == vi) return true; + if (static_cast(t[i]) == vi) return true; } return false; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index a6f4f97a6..f0336f729 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -45,7 +45,6 @@ void GLGizmoSimplify::on_render_for_picking() {} void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limit) { - const int min_triangle_count = 4; // tetrahedron const int max_char_in_name = 20; create_gui_cfg(); @@ -119,11 +118,11 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi m_imgui->disabled_begin(m_configuration.use_count); ImGui::Text(_L("Detail level").c_str()); std::vector reduce_captions = { - _u8L("Extra high"), - _u8L("High"), - _u8L("Medium"), - _u8L("Low"), - _u8L("Extra low") + static_cast(_u8L("Extra high")), + static_cast(_u8L("High")), + static_cast(_u8L("Medium")), + static_cast(_u8L("Low")), + static_cast(_u8L("Extra low")) }; ImGui::SameLine(m_gui_cfg->bottom_left_width); ImGui::SetNextItemWidth(m_gui_cfg->input_width); @@ -157,14 +156,13 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi m_imgui->disabled_begin(!m_configuration.use_count); ImGui::Text(_L("Ratio").c_str()); ImGui::SameLine(m_gui_cfg->bottom_left_width); - int wanted_count = m_configuration.wanted_count; ImGui::SetNextItemWidth(m_gui_cfg->input_width); const char * format = (m_configuration.wanted_percent > 10)? "%.0f %%": ((m_configuration.wanted_percent > 1)? "%.1f %%":"%.2f %%"); if (ImGui::SliderFloat("##triangle_ratio", &m_configuration.wanted_percent, 0.f, 100.f, format)) { m_is_valid_result = false; if (m_configuration.wanted_percent < 0.f) - m_configuration.wanted_percent = 0.01; + m_configuration.wanted_percent = 0.01f; if (m_configuration.wanted_percent > 100.f) m_configuration.wanted_percent = 100.f; m_configuration.update_percent(triangle_count); From 19f88d015d6e7ad78f3709b5eb6173ca01c7002c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 24 Aug 2021 08:25:04 +0200 Subject: [PATCH 55/86] Follow-up of ab6c638e44915138ee0e0500931aefd63bba16ed -> Fixed logic to center objects loaded from 3mf files produced by 3rd part softwares --- src/slic3r/GUI/Plater.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 97ffc6cb7..5f1563526 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1643,7 +1643,7 @@ struct Plater::priv BoundingBox scaled_bed_shape_bb() const; std::vector load_files(const std::vector& input_files, bool load_model, bool load_config, bool used_inches = false); - std::vector load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool force_center_on_bed = false); + std::vector load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false); wxString get_export_file(GUI::FileType file_type); @@ -2426,7 +2426,9 @@ std::vector Plater::priv::load_files(const std::vector& input_ } if (one_by_one) { - auto loaded_idxs = load_model_objects(model.objects, is_project_file, !is_project_file); + if (type_3mf && !is_project_file) + model.center_instances_around_point(bed_shape_bb().center()); + auto loaded_idxs = load_model_objects(model.objects, is_project_file); obj_idxs.insert(obj_idxs.end(), loaded_idxs.begin(), loaded_idxs.end()); } else { // This must be an .stl or .obj file, which may contain a maximum of one volume. @@ -2479,7 +2481,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ // #define AUTOPLACEMENT_ON_LOAD -std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z, bool force_center_on_bed) +std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z) { const BoundingBoxf bed_shape = bed_shape_bb(); const Vec3d bed_size = Slic3r::to_3d(bed_shape.size().cast(), 1.0) - 2.0 * Vec3d::Ones(); @@ -2539,9 +2541,6 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& mode object->ensure_on_bed(allow_negative_z); } - if (force_center_on_bed) - model.center_instances_around_point(bed_shape.center()); - #ifdef AUTOPLACEMENT_ON_LOAD // FIXME distance should be a config value ///////////////////////////////// auto min_obj_distance = static_cast(6/SCALING_FACTOR); From fefc20dbbb7919e8717be43c53202ae9addcdd68 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 24 Aug 2021 09:34:25 +0200 Subject: [PATCH 56/86] Slight refactoring of the project state. --- src/libslic3r/Preset.hpp | 4 ++-- src/slic3r/GUI/Plater.cpp | 9 +++------ src/slic3r/GUI/ProjectDirtyStateManager.cpp | 9 ++++----- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index d0e7561db..d19cb0aac 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -371,7 +371,7 @@ public: const Preset& get_edited_preset() const { return m_edited_preset; } // Return the last saved preset. - const Preset& get_saved_preset() const { return m_saved_preset; } +// const Preset& get_saved_preset() const { return m_saved_preset; } // Return vendor of the first parent profile, for which the vendor is defined, or null if such profile does not exist. PresetWithVendorProfile get_preset_with_vendor_profile(const Preset &preset) const; @@ -474,7 +474,7 @@ public: // Compare the content of get_saved_preset() with get_edited_preset() configs, return true if they differ. bool saved_is_dirty() const - { return is_dirty(&this->get_edited_preset(), &this->get_saved_preset()); } + { return is_dirty(&this->get_edited_preset(), &m_saved_preset); } // Compare the content of get_saved_preset() with get_edited_preset() configs, return the list of keys where they differ. // std::vector saved_dirty_options() const // { return dirty_options(&this->get_edited_preset(), &this->get_saved_preset(), /* deep_compare */ false); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5f1563526..fa53522d1 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4703,10 +4703,8 @@ void Plater::load_project(const wxString& filename) std::vector input_paths; input_paths.push_back(into_path(filename)); - std::vector res = load_files(input_paths); - - // if res is empty no data has been loaded - if (!res.empty()) { + if (! load_files(input_paths).empty()) { + // At least one file was loaded. p->set_project_filename(filename); reset_project_dirty_initial_presets(); update_project_dirty_from_presets(); @@ -4741,8 +4739,7 @@ void Plater::add_model(bool imperial_units/* = false*/) } Plater::TakeSnapshot snapshot(this, snapshot_label); - std::vector res = load_files(paths, true, false, imperial_units); - if (!res.empty()) + if (! load_files(paths, true, false, imperial_units).empty()) wxGetApp().mainframe->update_title(); } diff --git a/src/slic3r/GUI/ProjectDirtyStateManager.cpp b/src/slic3r/GUI/ProjectDirtyStateManager.cpp index 9efc1dd90..3ca764e91 100644 --- a/src/slic3r/GUI/ProjectDirtyStateManager.cpp +++ b/src/slic3r/GUI/ProjectDirtyStateManager.cpp @@ -28,7 +28,7 @@ static const UndoRedo::Snapshot* get_active_snapshot(const UndoRedo::Stack& stac const size_t active_snapshot_time = stack.active_snapshot_time(); const auto it = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(active_snapshot_time)); const int idx = it - snapshots.begin() - 1; - const Slic3r::UndoRedo::Snapshot* ret = (0 <= idx && (size_t)idx < snapshots.size() - 1) ? + const Slic3r::UndoRedo::Snapshot* ret = (0 <= idx && idx < int(snapshots.size()) - 1) ? &snapshots[idx] : nullptr; assert(ret != nullptr); @@ -195,8 +195,7 @@ void ProjectDirtyStateManager::update_from_undo_redo_stack(UpdateType type) void ProjectDirtyStateManager::update_from_presets() { m_state.presets = false; - std::vector> selected_presets = wxGetApp().get_selected_presets(); - for (const auto& [type, name] : selected_presets) { + for (const auto& [type, name] : wxGetApp().get_selected_presets()) { m_state.presets |= !m_initial_presets[type].empty() && m_initial_presets[type] != name; } m_state.presets |= wxGetApp().has_unsaved_preset_changes(); @@ -214,6 +213,7 @@ void ProjectDirtyStateManager::reset_after_save() m_last_save.main = (saveable_snapshot != nullptr) ? saveable_snapshot->timestamp : 0; } else { + // Gizmo is active with its own Undo / Redo stack (for example the SLA support point editing gizmo). const UndoRedo::Snapshot* main_active_snapshot = get_active_snapshot(main_stack); if (boost::starts_with(main_active_snapshot->name, _utf8("Entering"))) { if (m_state.gizmos.current) @@ -231,8 +231,7 @@ void ProjectDirtyStateManager::reset_after_save() void ProjectDirtyStateManager::reset_initial_presets() { m_initial_presets = std::array(); - std::vector> selected_presets = wxGetApp().get_selected_presets(); - for (const auto& [type, name] : selected_presets) { + for (const auto& [type, name] : wxGetApp().get_selected_presets()) { m_initial_presets[type] = name; } } From 326fb51316f7a4311d46dd5c32f0e7245d0316bb Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 24 Aug 2021 09:44:32 +0200 Subject: [PATCH 57/86] Force enable menu icons under GTK GTK specific: Fixed missing icons for wxMenuItem on GTK2 and GTK3 for skins that haven't enabled showing an icon for gtk_image_menu_item by forcing showing icons for every skin. --- src/slic3r/GUI/GUI_App.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 06d805eeb..58ce12ae4 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -87,6 +87,11 @@ #include #endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG +// Needed for forcing menu icons back under gtk2 and gtk3 +#if defined(__WXGTK20__) || defined(__WXGTK3__) + #include +#endif + namespace Slic3r { namespace GUI { @@ -799,6 +804,14 @@ bool GUI_App::OnInit() bool GUI_App::on_init_inner() { + // Forcing back menu icons under gtk2 and gtk3. Solution is based on: + // https://docs.gtk.org/gtk3/class.Settings.html + // see also https://docs.wxwidgets.org/3.0/classwx_menu_item.html#a2b5d6bcb820b992b1e4709facbf6d4fb + // TODO: Find workaround for GTK4 +#if defined(__WXGTK20__) || defined(__WXGTK3__) + g_object_set (gtk_settings_get_default (), "gtk-menu-images", TRUE, NULL); +#endif + // Verify resources path const wxString resources_dir = from_u8(Slic3r::resources_dir()); wxCHECK_MSG(wxDirExists(resources_dir), false, From 0b654e151852e049461d2da5a68056989c7d4835 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 24 Aug 2021 11:23:33 +0200 Subject: [PATCH 58/86] Follow-up of 316d38807d64e377c4b1d3a71f8c9587dcc82066 -> Modified shader to work on (buggy) Intel graphics card --- resources/shaders/printbed.vs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/shaders/printbed.vs b/resources/shaders/printbed.vs index ee19098c1..7633017f1 100644 --- a/resources/shaders/printbed.vs +++ b/resources/shaders/printbed.vs @@ -7,6 +7,8 @@ varying vec2 tex_coords; void main() { - gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position, 1.0); + gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position.x, v_position.y, v_position.z, 1.0); + // the following line leads to crash on some Intel graphics card + //gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position, 1.0); tex_coords = v_tex_coords; } From 6b03b66167dd17bc6c804f58b9af124082e80287 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 24 Aug 2021 11:24:48 +0200 Subject: [PATCH 59/86] OctoPrint upload: ignore certificate revocation checks Fixes Hostname incorrect While test is positive (Bonjour discovery not supported for the address field) #1781 (partial fix of #1781) --- src/libslic3r/Preset.cpp | 3 ++- src/libslic3r/PrintConfig.cpp | 6 ++++++ src/slic3r/GUI/PhysicalPrinterDialog.cpp | 9 ++++++++- src/slic3r/Utils/Http.cpp | 8 ++++++++ src/slic3r/Utils/Http.hpp | 2 ++ src/slic3r/Utils/OctoPrint.cpp | 9 ++++++++- src/slic3r/Utils/OctoPrint.hpp | 1 + 7 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index c0a956154..26359b866 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1442,7 +1442,8 @@ const std::vector& PhysicalPrinter::printer_options() "printhost_authorization_type", // HTTP digest authentization (RFC 2617) "printhost_user", - "printhost_password" + "printhost_password", + "printhost_ignore_check" }; } return s_opts; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index e64824d0d..dffb8ac0c 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -310,6 +310,12 @@ void PrintConfigDef::init_common_params() // def->tooltip = L(""); def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("")); + + def = this->add("printhost_ignore_check", coBool); + def->label = L("Ignore certificate revocation checks"); + // def->tooltip = L(""); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); def = this->add("preset_names", coStrings); def->label = L("Printer preset names"); diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index f189378a6..9c570172c 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -396,6 +396,7 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr m_optgroup->append_line(cafile_hint); } else { + Line line{ "", "" }; line.full_width = 1; @@ -411,8 +412,14 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr sizer->Add(txt, 1, wxEXPAND); return sizer; }; - m_optgroup->append_line(line); + +#ifdef WIN32 + option = m_optgroup->get_option("printhost_ignore_check"); + option.opt.width = Field::def_width_wider(); + m_optgroup->append_single_option_line(option); +#endif + } for (const std::string& opt_key : std::vector{ "printhost_user", "printhost_password" }) { diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 2afb7ed50..69093988a 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -491,6 +491,14 @@ Http& Http::form_add_file(const std::string &name, const fs::path &path, const s return *this; } +Http& Http::revoke_best_effort(bool set) +{ + if(p && set){ + ::curl_easy_setopt(p->curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_REVOKE_BEST_EFFORT); + } + return *this; +} + Http& Http::set_post_body(const fs::path &path) { if (p) { p->set_post_body(path);} diff --git a/src/slic3r/Utils/Http.hpp b/src/slic3r/Utils/Http.hpp index f34a27fbc..3cce25086 100644 --- a/src/slic3r/Utils/Http.hpp +++ b/src/slic3r/Utils/Http.hpp @@ -80,6 +80,8 @@ public: // Same as above except also override the file's filename with a custom one Http& form_add_file(const std::string &name, const boost::filesystem::path &path, const std::string &filename); + Http& revoke_best_effort(bool set); + // Set the file contents as a POST request body. // The data is used verbatim, it is not additionally encoded in any way. // This can be used for hosts which do not support multipart requests. diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index ee669c36f..3a2335b1e 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -25,7 +25,8 @@ namespace Slic3r { OctoPrint::OctoPrint(DynamicPrintConfig *config) : host(config->opt_string("print_host")), apikey(config->opt_string("printhost_apikey")), - cafile(config->opt_string("printhost_cafile")) + cafile(config->opt_string("printhost_cafile")), + ignore_checks(config->opt_bool("printhost_ignore_check")) {} const char* OctoPrint::get_name() const { return "OctoPrint"; } @@ -73,6 +74,9 @@ bool OctoPrint::test(wxString &msg) const msg = "Could not parse server response"; } }) +#ifdef WIN32 + .revoke_best_effort(ignore_checks) +#endif .perform_sync(); return res; @@ -137,6 +141,9 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro res = false; } }) +#ifdef WIN32 + .revoke_best_effort(ignore_checks) +#endif .perform_sync(); return res; diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index 62bdfb6fa..42683dc62 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -40,6 +40,7 @@ private: std::string host; std::string apikey; std::string cafile; + bool ignore_checks; virtual void set_auth(Http &http) const; std::string make_url(const std::string &path) const; From c5cc4ce2215846feaadec605e9052e8a0b10a660 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 24 Aug 2021 11:31:04 +0200 Subject: [PATCH 60/86] Fixed sequential print clearance contours not disappearing after undo --- src/slic3r/GUI/Plater.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index fa53522d1..3884fbca4 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2944,6 +2944,9 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool if (view3D->is_layers_editing_enabled()) view3D->get_wxglcanvas()->Refresh(); + if (background_process.empty()) + view3D->get_canvas3d()->reset_sequential_print_clearance(); + if (invalidated == Print::APPLY_STATUS_INVALIDATED) { // Some previously calculated data on the Print was invalidated. // Hide the slicing results, as the current slicing status is no more valid. From d4584b11581295f26f7a83e3c71e700c70a1d6a9 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 24 Aug 2021 12:09:30 +0200 Subject: [PATCH 61/86] Removed confirmation dialog for command Delete All --- src/slic3r/GUI/Plater.cpp | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 3884fbca4..60215484b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1658,6 +1658,7 @@ struct Plater::priv void deselect_all(); void remove(size_t obj_idx); void delete_object_from_model(size_t obj_idx); + void delete_all_objects_from_model(); void reset(); void mirror(Axis axis); void split_object(); @@ -1944,7 +1945,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) // 3DScene/Toolbar: view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this); view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE, [q](SimpleEvent&) { q->remove_selected(); }); - view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE_ALL, [q](SimpleEvent&) { q->reset_with_confirm(); }); + view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE_ALL, [this](SimpleEvent&) { delete_all_objects_from_model(); }); +// view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE_ALL, [q](SimpleEvent&) { q->reset_with_confirm(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_ARRANGE, [this](SimpleEvent&) { this->q->arrange(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_COPY, [q](SimpleEvent&) { q->copy_selection_to_clipboard(); }); view3D_canvas->Bind(EVT_GLTOOLBAR_PASTE, [q](SimpleEvent&) { q->paste_from_clipboard(); }); @@ -2753,6 +2755,32 @@ void Plater::priv::delete_object_from_model(size_t obj_idx) object_list_changed(); } +void Plater::priv::delete_all_objects_from_model() +{ + Plater::TakeSnapshot snapshot(q, _L("Delete All Objects")); + + if (view3D->is_layers_editing_enabled()) + view3D->enable_layers_editing(false); + + reset_gcode_toolpaths(); + gcode_result.reset(); + + view3D->get_canvas3d()->reset_sequential_print_clearance(); + + // Stop and reset the Print content. + background_process.reset(); + model.clear_objects(); + update(); + // Delete object from Sidebar list. Do it after update, so that the GLScene selection is updated with the modified model. + sidebar->obj_list()->delete_all_objects_from_list(); + object_list_changed(); + + // The hiding of the slicing results, if shown, is not taken care by the background process, so we do it here + sidebar->show_sliced_info_sizer(false); + + model.custom_gcode_per_print_z.gcodes.clear(); +} + void Plater::priv::reset() { Plater::TakeSnapshot snapshot(q, _L("Reset Project")); From dfdfb32648d3d6b71c2e5032e68d3e57356a29dc Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 24 Aug 2021 12:17:47 +0200 Subject: [PATCH 62/86] Fixed update of project dirty state after discarding config changes --- src/libslic3r/Preset.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index d19cb0aac..849dd7b80 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -395,7 +395,7 @@ public: void discard_current_changes() { m_presets[m_idx_selected].reset_dirty(); m_edited_preset = m_presets[m_idx_selected]; - update_saved_preset_from_current_preset(); +// update_saved_preset_from_current_preset(); } // Return a preset by its name. If the preset is active, a temporary copy is returned. From b6deda3477a17e27200432dd0a277d118835292f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 24 Aug 2021 12:39:21 +0200 Subject: [PATCH 63/86] Fixed object below bed after deleting part --- src/slic3r/GUI/Selection.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index acb1f1113..ba4577bfb 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1149,6 +1149,7 @@ void Selection::erase() } wxGetApp().obj_list()->delete_from_model_and_list(items); + ensure_not_below_bed(); } } From 16562a2e77ad74c44e8b143ae3e45deafa0912ee Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 23 Aug 2021 15:51:06 +0200 Subject: [PATCH 64/86] Do not print brim when object has raft, it is not supported and makes no sense --- src/libslic3r/Brim.cpp | 6 +++++- src/libslic3r/Print.hpp | 8 ++++++-- src/libslic3r/PrintConfig.cpp | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index e73bed2c9..f4455fdd5 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -71,12 +71,16 @@ static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print, Polygons islands; ConstPrintObjectPtrs island_to_object; for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) { + const PrintObject *object = print.objects()[print_object_idx]; + + if (! object->has_brim()) + continue; + Polygons islands_object; islands_object.reserve(bottom_layers_expolygons[print_object_idx].size()); for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx]) islands_object.emplace_back(ex_poly.contour); - const PrintObject *object = print.objects()[print_object_idx]; islands.reserve(islands.size() + object->instances().size() * islands_object.size()); for (const PrintInstance &instance : object->instances()) for (Polygon &poly : islands_object) { diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 491960705..0056aee33 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -271,7 +271,11 @@ public: // Centering offset of the sliced mesh from the scaled and rotated mesh of the model. const Point& center_offset() const { return m_center_offset; } - bool has_brim() const { return this->config().brim_type != btNoBrim && this->config().brim_width.value > 0.; } + bool has_brim() const { + return this->config().brim_type != btNoBrim + && this->config().brim_width.value > 0. + && ! this->has_raft(); + } // This is the *total* layer count (including support layers) // this value is not supposed to be compared with Layer::id @@ -321,7 +325,7 @@ public: bool has_raft() const { return m_config.raft_layers > 0; } bool has_support_material() const { return this->has_support() || this->has_raft(); } // Checks if the model object is painted using the multi-material painting gizmo. - bool is_mm_painted() const { return this->model_object()->is_mm_painted(); }; + bool is_mm_painted() const { return this->model_object()->is_mm_painted(); } // returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions) std::vector object_extruders() const; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index dffb8ac0c..c46ac04d6 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -471,7 +471,8 @@ void PrintConfigDef::init_fff_params() def = this->add("brim_width", coFloat); def->label = L("Brim width"); def->category = L("Skirt and brim"); - def->tooltip = L("Horizontal width of the brim that will be printed around each object on the first layer."); + def->tooltip = L("Horizontal width of the brim that will be printed around each object on the first layer." + "When raft is used, no brim is generated (use raft_first_layer_expansion)."); def->sidetext = L("mm"); def->min = 0; def->max = 200; From c029cd44a489f4f4a1abd822623fd0725c9a88b4 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 24 Aug 2021 13:10:35 +0200 Subject: [PATCH 65/86] Initialization of various Preset list of config options was made thread safe. --- src/libslic3r/Preset.cpp | 403 ++++++++++++++++++--------------------- 1 file changed, 185 insertions(+), 218 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 26359b866..bb083e03c 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -413,212 +413,181 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config) } } -const std::vector& Preset::print_options() -{ - static std::vector s_opts { - "layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "slicing_mode", - "top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness", - "extra_perimeters", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs", - "seam_position", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern", - "infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle", - "solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first", - "ironing", "ironing_type", "ironing_flowrate", "ironing_speed", "ironing_spacing", - "max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour", - "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist", +static std::vector s_Preset_print_options { + "layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "slicing_mode", + "top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness", + "extra_perimeters", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs", + "seam_position", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern", + "infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle", + "solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first", + "ironing", "ironing_type", "ironing_flowrate", "ironing_speed", "ironing_spacing", + "max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour", + "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist", #ifdef HAS_PRESSURE_EQUALIZER - "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative", + "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative", #endif /* HAS_PRESSURE_EQUALIZER */ - "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed", - "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed", - "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "perimeter_acceleration", "infill_acceleration", - "bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield", - "min_skirt_length", "brim_width", "brim_offset", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", - "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", - "support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_closing_radius", "support_material_style", - "support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers", - "support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops", - "support_material_contact_distance", "support_material_bottom_contact_distance", - "support_material_buildplate_only", "dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius", - "extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder", - "infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder", - "ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width", - "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", - "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio", "clip_multipart_objects", - "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", - "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width", - "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits" - }; - return s_opts; -} + "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed", + "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed", + "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "perimeter_acceleration", "infill_acceleration", + "bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield", + "min_skirt_length", "brim_width", "brim_offset", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", + "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", + "support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_closing_radius", "support_material_style", + "support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers", + "support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops", + "support_material_contact_distance", "support_material_bottom_contact_distance", + "support_material_buildplate_only", "dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius", + "extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder", + "infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder", + "ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width", + "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", + "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio", "clip_multipart_objects", + "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", + "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width", + "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits" +}; -const std::vector& Preset::filament_options() -{ - static std::vector s_opts { - "filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed", - "extrusion_multiplier", "filament_density", "filament_cost", "filament_spool_weight", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time", - "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", - "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower", - "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", - "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", - "start_filament_gcode", "end_filament_gcode", - // Retract overrides - "filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel", - "filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe", - // Profile compatibility - "filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits" - }; - return s_opts; -} +static std::vector s_Preset_filament_options { + "filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed", + "extrusion_multiplier", "filament_density", "filament_cost", "filament_spool_weight", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time", + "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", + "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower", + "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", + "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", + "start_filament_gcode", "end_filament_gcode", + // Retract overrides + "filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel", + "filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe", + // Profile compatibility + "filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits" +}; -const std::vector& Preset::machine_limits_options() -{ - static std::vector s_opts; - if (s_opts.empty()) { - s_opts = { - "machine_max_acceleration_extruding", "machine_max_acceleration_retracting", "machine_max_acceleration_travel", - "machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e", - "machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e", - "machine_min_extruding_rate", "machine_min_travel_rate", - "machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e", - }; - } - return s_opts; -} +static std::vector s_Preset_machine_limits_options { + "machine_max_acceleration_extruding", "machine_max_acceleration_retracting", "machine_max_acceleration_travel", + "machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e", + "machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e", + "machine_min_extruding_rate", "machine_min_travel_rate", + "machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e", +}; + +static std::vector s_Preset_printer_options { + "printer_technology", + "bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances", + "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", + //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset. + "host_type", "print_host", "printhost_apikey", "printhost_cafile", + "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode", + "color_change_gcode", "pause_print_gcode", "template_custom_gcode", + "between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction", + "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "max_print_height", + "default_print_profile", "inherits", + "remaining_times", "silent_mode", + "machine_limits_usage", "thumbnails" +}; + +static std::vector s_Preset_sla_print_options { + "layer_height", + "faded_layers", + "supports_enable", + "support_head_front_diameter", + "support_head_penetration", + "support_head_width", + "support_pillar_diameter", + "support_small_pillar_diameter_percent", + "support_max_bridges_on_pillar", + "support_pillar_connection_mode", + "support_buildplate_only", + "support_pillar_widening_factor", + "support_base_diameter", + "support_base_height", + "support_base_safety_distance", + "support_critical_angle", + "support_max_bridge_length", + "support_max_pillar_link_distance", + "support_object_elevation", + "support_points_density_relative", + "support_points_minimal_distance", + "slice_closing_radius", + "slicing_mode", + "pad_enable", + "pad_wall_thickness", + "pad_wall_height", + "pad_brim_size", + "pad_max_merge_distance", + // "pad_edge_radius", + "pad_wall_slope", + "pad_object_gap", + "pad_around_object", + "pad_around_object_everywhere", + "pad_object_connector_stride", + "pad_object_connector_width", + "pad_object_connector_penetration", + "hollowing_enable", + "hollowing_min_thickness", + "hollowing_quality", + "hollowing_closing_distance", + "output_filename_format", + "default_sla_print_profile", + "compatible_printers", + "compatible_printers_condition", + "inherits" +}; + +static std::vector s_Preset_sla_material_options { + "material_type", + "initial_layer_height", + "bottle_cost", + "bottle_volume", + "bottle_weight", + "material_density", + "exposure_time", + "initial_exposure_time", + "material_correction", + "material_notes", + "material_vendor", + "default_sla_material_profile", + "compatible_prints", "compatible_prints_condition", + "compatible_printers", "compatible_printers_condition", "inherits" +}; + +static std::vector s_Preset_sla_printer_options { + "printer_technology", + "bed_shape", "bed_custom_texture", "bed_custom_model", "max_print_height", + "display_width", "display_height", "display_pixels_x", "display_pixels_y", + "display_mirror_x", "display_mirror_y", + "display_orientation", + "fast_tilt_time", "slow_tilt_time", "area_fill", + "relative_correction", + "absolute_correction", + "elefant_foot_compensation", + "elefant_foot_min_width", + "gamma_correction", + "min_exposure_time", "max_exposure_time", + "min_initial_exposure_time", "max_initial_exposure_time", + //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset. + "print_host", "printhost_apikey", "printhost_cafile", + "printer_notes", + "inherits" +}; + +const std::vector& Preset::print_options() { return s_Preset_print_options; } +const std::vector& Preset::filament_options() { return s_Preset_filament_options; } +const std::vector& Preset::machine_limits_options() { return s_Preset_machine_limits_options; } +// The following nozzle options of a printer profile will be adjusted to match the size +// of the nozzle_diameter vector. +const std::vector& Preset::nozzle_options() { return print_config_def.extruder_option_keys(); } +const std::vector& Preset::sla_print_options() { return s_Preset_sla_print_options; } +const std::vector& Preset::sla_material_options() { return s_Preset_sla_material_options; } +const std::vector& Preset::sla_printer_options() { return s_Preset_sla_printer_options; } const std::vector& Preset::printer_options() { - static std::vector s_opts; - if (s_opts.empty()) { - s_opts = { - "printer_technology", - "bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances", - "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", - //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset. - "host_type", "print_host", "printhost_apikey", "printhost_cafile", - "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode", - "color_change_gcode", "pause_print_gcode", "template_custom_gcode", - "between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction", - "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "max_print_height", - "default_print_profile", "inherits", - "remaining_times", "silent_mode", - "machine_limits_usage", "thumbnails" - }; - s_opts.insert(s_opts.end(), Preset::machine_limits_options().begin(), Preset::machine_limits_options().end()); - s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end()); - } - return s_opts; -} - -// The following nozzle options of a printer profile will be adjusted to match the size -// of the nozzle_diameter vector. -const std::vector& Preset::nozzle_options() -{ - return print_config_def.extruder_option_keys(); -} - -const std::vector& Preset::sla_print_options() -{ - static std::vector s_opts; - if (s_opts.empty()) { - s_opts = { - "layer_height", - "faded_layers", - "supports_enable", - "support_head_front_diameter", - "support_head_penetration", - "support_head_width", - "support_pillar_diameter", - "support_small_pillar_diameter_percent", - "support_max_bridges_on_pillar", - "support_pillar_connection_mode", - "support_buildplate_only", - "support_pillar_widening_factor", - "support_base_diameter", - "support_base_height", - "support_base_safety_distance", - "support_critical_angle", - "support_max_bridge_length", - "support_max_pillar_link_distance", - "support_object_elevation", - "support_points_density_relative", - "support_points_minimal_distance", - "slice_closing_radius", - "slicing_mode", - "pad_enable", - "pad_wall_thickness", - "pad_wall_height", - "pad_brim_size", - "pad_max_merge_distance", - // "pad_edge_radius", - "pad_wall_slope", - "pad_object_gap", - "pad_around_object", - "pad_around_object_everywhere", - "pad_object_connector_stride", - "pad_object_connector_width", - "pad_object_connector_penetration", - "hollowing_enable", - "hollowing_min_thickness", - "hollowing_quality", - "hollowing_closing_distance", - "output_filename_format", - "default_sla_print_profile", - "compatible_printers", - "compatible_printers_condition", - "inherits" - }; - } - return s_opts; -} - -const std::vector& Preset::sla_material_options() -{ - static std::vector s_opts; - if (s_opts.empty()) { - s_opts = { - "material_type", - "initial_layer_height", - "bottle_cost", - "bottle_volume", - "bottle_weight", - "material_density", - "exposure_time", - "initial_exposure_time", - "material_correction", - "material_notes", - "material_vendor", - "default_sla_material_profile", - "compatible_prints", "compatible_prints_condition", - "compatible_printers", "compatible_printers_condition", "inherits" - }; - } - return s_opts; -} - -const std::vector& Preset::sla_printer_options() -{ - static std::vector s_opts; - if (s_opts.empty()) { - s_opts = { - "printer_technology", - "bed_shape", "bed_custom_texture", "bed_custom_model", "max_print_height", - "display_width", "display_height", "display_pixels_x", "display_pixels_y", - "display_mirror_x", "display_mirror_y", - "display_orientation", - "fast_tilt_time", "slow_tilt_time", "area_fill", - "relative_correction", - "absolute_correction", - "elefant_foot_compensation", - "elefant_foot_min_width", - "gamma_correction", - "min_exposure_time", "max_exposure_time", - "min_initial_exposure_time", "max_initial_exposure_time", - //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset. - "print_host", "printhost_apikey", "printhost_cafile", - "printer_notes", - "inherits" - }; - } + static std::vector s_opts = [](){ + std::vector opts = s_Preset_printer_options; + append(opts, s_Preset_machine_limits_options); + append(opts, Preset::nozzle_options()); + return opts; + }(); return s_opts; } @@ -1426,27 +1395,25 @@ std::string PhysicalPrinter::separator() return " * "; } +static std::vector s_PhysicalPrinter_opts { + "preset_name", // temporary option to compatibility with older Slicer + "preset_names", + "printer_technology", + "host_type", + "print_host", + "printhost_apikey", + "printhost_cafile", + "printhost_port", + "printhost_authorization_type", + // HTTP digest authentization (RFC 2617) + "printhost_user", + "printhost_password", + "printhost_ignore_check" +}; + const std::vector& PhysicalPrinter::printer_options() { - static std::vector s_opts; - if (s_opts.empty()) { - s_opts = { - "preset_name", // temporary option to compatibility with older Slicer - "preset_names", - "printer_technology", - "host_type", - "print_host", - "printhost_apikey", - "printhost_cafile", - "printhost_port", - "printhost_authorization_type", - // HTTP digest authentization (RFC 2617) - "printhost_user", - "printhost_password", - "printhost_ignore_check" - }; - } - return s_opts; + return s_PhysicalPrinter_opts; } static constexpr auto legacy_print_host_options = { From d3f11a6ab7a7c350439929e9ebf2b03ef4989477 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 24 Aug 2021 13:57:52 +0200 Subject: [PATCH 66/86] Follow-up to OctoPrint upload: ignore certificate revocation checks 6b03b66167dd17bc6c804f58b9af124082e80287 Renamed the new "printhost_ignore_check" option to "printhost_ssl_ignore_revoke" Improved the Physical Printers dialog in regard to the new option checkbox (added tooltip to the checkbox, moved it to the end of options). Disabled the host_xxx options at the command line interface, they no more work after these options were separated to Physical Printers profiles. Little refactoring of Http.cpp/hpp, OctoPrint.cpp/hpp Private local variables prefixed with m_, some renaming for clarity. --- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 49 +++++++++++++++--------- src/slic3r/GUI/PhysicalPrinterDialog.cpp | 13 +++---- src/slic3r/Utils/Http.cpp | 4 +- src/slic3r/Utils/Http.hpp | 6 ++- src/slic3r/Utils/OctoPrint.cpp | 48 +++++++++++------------ src/slic3r/Utils/OctoPrint.hpp | 26 ++++++------- 7 files changed, 82 insertions(+), 66 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index bb083e03c..3883c4980 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1408,7 +1408,7 @@ static std::vector s_PhysicalPrinter_opts { // HTTP digest authentization (RFC 2617) "printhost_user", "printhost_password", - "printhost_ignore_check" + "printhost_ssl_ignore_revoke" }; const std::vector& PhysicalPrinter::printer_options() diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index c46ac04d6..f010bad39 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -232,6 +232,16 @@ void PrintConfigDef::init_common_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("")); + def = this->add("elefant_foot_compensation", coFloat); + def->label = L("Elephant foot compensation"); + def->category = L("Advanced"); + def->tooltip = L("The first layer will be shrunk in the XY plane by the configured value " + "to compensate for the 1st layer squish aka an Elephant Foot effect."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.)); + def = this->add("thumbnails", coPoints); def->label = L("G-code thumbnails"); def->tooltip = L("Picture sizes to be stored into a .gcode and .sl1 / .sl1s files, in the following format: \"XxY, XxY, ...\""); @@ -264,6 +274,7 @@ void PrintConfigDef::init_common_params() "Print host behind HAProxy with basic auth enabled can be accessed by putting the user name and password into the URL " "in the following format: https://username:password@your-octopi-address/"); def->mode = comAdvanced; + def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionString("")); def = this->add("printhost_apikey", coString); @@ -271,6 +282,7 @@ void PrintConfigDef::init_common_params() def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain " "the API Key or the password required for authentication."); def->mode = comAdvanced; + def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionString("")); def = this->add("printhost_port", coString); @@ -278,6 +290,7 @@ void PrintConfigDef::init_common_params() def->tooltip = L("Name of the printer"); def->gui_type = ConfigOptionDef::GUIType::select_open; def->mode = comAdvanced; + def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionString("")); def = this->add("printhost_cafile", coString); @@ -285,36 +298,32 @@ void PrintConfigDef::init_common_params() def->tooltip = L("Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. " "If left blank, the default OS CA certificate repository is used."); def->mode = comAdvanced; + def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionString("")); - def = this->add("elefant_foot_compensation", coFloat); - def->label = L("Elephant foot compensation"); - def->category = L("Advanced"); - def->tooltip = L("The first layer will be shrunk in the XY plane by the configured value " - "to compensate for the 1st layer squish aka an Elephant Foot effect."); - def->sidetext = L("mm"); - def->min = 0; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.)); - // Options used by physical printers def = this->add("printhost_user", coString); def->label = L("User"); // def->tooltip = L(""); def->mode = comAdvanced; + def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionString("")); def = this->add("printhost_password", coString); def->label = L("Password"); // def->tooltip = L(""); def->mode = comAdvanced; + def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionString("")); - def = this->add("printhost_ignore_check", coBool); - def->label = L("Ignore certificate revocation checks"); - // def->tooltip = L(""); + // Only available on Windows. + def = this->add("printhost_ssl_ignore_revoke", coBool); + def->label = L("Ignore HTTPS certificate revocation checks"); + def->tooltip = L("Ignore HTTPS certificate revocation checks in case of missing or offline distribution points. " + "One may want to enable this option for self signed certificates if connection fails."); def->mode = comAdvanced; + def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionBool(false)); def = this->add("preset_names", coStrings); @@ -323,12 +332,6 @@ void PrintConfigDef::init_common_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionStrings()); - // temporary workaround for compatibility with older Slicer - { - def = this->add("preset_name", coString); - def->set_default_value(new ConfigOptionString()); - } - def = this->add("printhost_authorization_type", coEnum); def->label = L("Authorization Type"); // def->tooltip = L(""); @@ -338,7 +341,14 @@ void PrintConfigDef::init_common_params() def->enum_labels.push_back(L("API key")); def->enum_labels.push_back(L("HTTP digest")); def->mode = comAdvanced; + def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionEnum(atKeyPassword)); + + // temporary workaround for compatibility with older Slicer + { + def = this->add("preset_name", coString); + def->set_default_value(new ConfigOptionString()); + } } void PrintConfigDef::init_fff_params() @@ -1816,6 +1826,7 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back("AstroBox"); def->enum_labels.push_back("Repetier"); def->mode = comAdvanced; + def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionEnum(htOctoPrint)); def = this->add("only_retract_when_crossing_perimeters", coBool); diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index 9c570172c..519abab43 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -413,13 +413,6 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr return sizer; }; m_optgroup->append_line(line); - -#ifdef WIN32 - option = m_optgroup->get_option("printhost_ignore_check"); - option.opt.width = Field::def_width_wider(); - m_optgroup->append_single_option_line(option); -#endif - } for (const std::string& opt_key : std::vector{ "printhost_user", "printhost_password" }) { @@ -428,6 +421,12 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr m_optgroup->append_single_option_line(option); } +#ifdef WIN32 + option = m_optgroup->get_option("printhost_ssl_ignore_revoke"); + option.opt.width = Field::def_width_wider(); + m_optgroup->append_single_option_line(option); +#endif + m_optgroup->activate(); Field* printhost_field = m_optgroup->get_field("print_host"); diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 69093988a..06598f8f5 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -491,7 +491,9 @@ Http& Http::form_add_file(const std::string &name, const fs::path &path, const s return *this; } -Http& Http::revoke_best_effort(bool set) +// Tells libcurl to ignore certificate revocation checks in case of missing or offline distribution points for those SSL backends where such behavior is present. +// This option is only supported for Schannel (the native Windows SSL library). +Http& Http::ssl_revoke_best_effort(bool set) { if(p && set){ ::curl_easy_setopt(p->curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_REVOKE_BEST_EFFORT); diff --git a/src/slic3r/Utils/Http.hpp b/src/slic3r/Utils/Http.hpp index 3cce25086..52e48a394 100644 --- a/src/slic3r/Utils/Http.hpp +++ b/src/slic3r/Utils/Http.hpp @@ -80,7 +80,11 @@ public: // Same as above except also override the file's filename with a custom one Http& form_add_file(const std::string &name, const boost::filesystem::path &path, const std::string &filename); - Http& revoke_best_effort(bool set); +#ifdef WIN32 + // Tells libcurl to ignore certificate revocation checks in case of missing or offline distribution points for those SSL backends where such behavior is present. + // This option is only supported for Schannel (the native Windows SSL library). + Http& ssl_revoke_best_effort(bool set); +#endif // WIN32 // Set the file contents as a POST request body. // The data is used verbatim, it is not additionally encoded in any way. diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index 3a2335b1e..f9ae4af5a 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -23,10 +23,10 @@ namespace pt = boost::property_tree; namespace Slic3r { OctoPrint::OctoPrint(DynamicPrintConfig *config) : - host(config->opt_string("print_host")), - apikey(config->opt_string("printhost_apikey")), - cafile(config->opt_string("printhost_cafile")), - ignore_checks(config->opt_bool("printhost_ignore_check")) + m_host(config->opt_string("print_host")), + m_apikey(config->opt_string("printhost_apikey")), + m_cafile(config->opt_string("printhost_cafile")), + m_ssl_revoke_best_effort(config->opt_bool("printhost_ssl_ignore_revoke")) {} const char* OctoPrint::get_name() const { return "OctoPrint"; } @@ -75,7 +75,7 @@ bool OctoPrint::test(wxString &msg) const } }) #ifdef WIN32 - .revoke_best_effort(ignore_checks) + .ssl_revoke_best_effort(m_ssl_revoke_best_effort) #endif .perform_sync(); @@ -142,7 +142,7 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro } }) #ifdef WIN32 - .revoke_best_effort(ignore_checks) + .ssl_revoke_best_effort(m_ssl_revoke_best_effort) #endif .perform_sync(); @@ -156,31 +156,31 @@ bool OctoPrint::validate_version_text(const boost::optional &versio void OctoPrint::set_auth(Http &http) const { - http.header("X-Api-Key", apikey); + http.header("X-Api-Key", m_apikey); - if (! cafile.empty()) { - http.ca_file(cafile); + if (!m_cafile.empty()) { + http.ca_file(m_cafile); } } std::string OctoPrint::make_url(const std::string &path) const { - if (host.find("http://") == 0 || host.find("https://") == 0) { - if (host.back() == '/') { - return (boost::format("%1%%2%") % host % path).str(); + if (m_host.find("http://") == 0 || m_host.find("https://") == 0) { + if (m_host.back() == '/') { + return (boost::format("%1%%2%") % m_host % path).str(); } else { - return (boost::format("%1%/%2%") % host % path).str(); + return (boost::format("%1%/%2%") % m_host % path).str(); } } else { - return (boost::format("http://%1%/%2%") % host % path).str(); + return (boost::format("http://%1%/%2%") % m_host % path).str(); } } SL1Host::SL1Host(DynamicPrintConfig *config) : OctoPrint(config), - authorization_type(dynamic_cast*>(config->option("printhost_authorization_type"))->value), - username(config->opt_string("printhost_user")), - password(config->opt_string("printhost_password")) + m_authorization_type(dynamic_cast*>(config->option("printhost_authorization_type"))->value), + m_username(config->opt_string("printhost_user")), + m_password(config->opt_string("printhost_password")) { } @@ -206,12 +206,12 @@ bool SL1Host::validate_version_text(const boost::optional &version_ void SL1Host::set_auth(Http &http) const { - switch (authorization_type) { + switch (m_authorization_type) { case atKeyPassword: http.header("X-Api-Key", get_apikey()); break; case atUserPassword: - http.auth_digest(username, password); + http.auth_digest(m_username, m_password); break; } @@ -223,9 +223,9 @@ void SL1Host::set_auth(Http &http) const // PrusaLink PrusaLink::PrusaLink(DynamicPrintConfig* config) : OctoPrint(config), - authorization_type(dynamic_cast*>(config->option("printhost_authorization_type"))->value), - username(config->opt_string("printhost_user")), - password(config->opt_string("printhost_password")) + m_authorization_type(dynamic_cast*>(config->option("printhost_authorization_type"))->value), + m_username(config->opt_string("printhost_user")), + m_password(config->opt_string("printhost_password")) { } @@ -250,12 +250,12 @@ bool PrusaLink::validate_version_text(const boost::optional& versio void PrusaLink::set_auth(Http& http) const { - switch (authorization_type) { + switch (m_authorization_type) { case atKeyPassword: http.header("X-Api-Key", get_apikey()); break; case atUserPassword: - http.auth_digest(username, password); + http.auth_digest(m_username, m_password); break; } diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index 42683dc62..48035b795 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -29,18 +29,18 @@ public: bool has_auto_discovery() const override { return true; } bool can_test() const override { return true; } bool can_start_print() const override { return true; } - std::string get_host() const override { return host; } - const std::string& get_apikey() const { return apikey; } - const std::string& get_cafile() const { return cafile; } + std::string get_host() const override { return m_host; } + const std::string& get_apikey() const { return m_apikey; } + const std::string& get_cafile() const { return m_cafile; } protected: virtual bool validate_version_text(const boost::optional &version_text) const; private: - std::string host; - std::string apikey; - std::string cafile; - bool ignore_checks; + std::string m_host; + std::string m_apikey; + std::string m_cafile; + bool m_ssl_revoke_best_effort; virtual void set_auth(Http &http) const; std::string make_url(const std::string &path) const; @@ -65,10 +65,10 @@ private: void set_auth(Http &http) const override; // Host authorization type. - AuthorizationType authorization_type; + AuthorizationType m_authorization_type; // username and password for HTTP Digest Authentization (RFC RFC2617) - std::string username; - std::string password; + std::string m_username; + std::string m_password; }; class PrusaLink : public OctoPrint @@ -90,10 +90,10 @@ private: void set_auth(Http& http) const override; // Host authorization type. - AuthorizationType authorization_type; + AuthorizationType m_authorization_type; // username and password for HTTP Digest Authentization (RFC RFC2617) - std::string username; - std::string password; + std::string m_username; + std::string m_password; }; } From cfcfbc38d239e79d09b27f74a82bc254da249040 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 24 Aug 2021 16:48:05 +0200 Subject: [PATCH 67/86] Hints notification random weighted order with saving used hints to cache/hints.cereal --- src/libslic3r/AppConfig.cpp | 3 - src/slic3r/GUI/HintNotification.cpp | 224 ++++++++++++++++++++-------- src/slic3r/GUI/HintNotification.hpp | 21 ++- 3 files changed, 180 insertions(+), 68 deletions(-) diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 4166658f5..177d8d708 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -167,9 +167,6 @@ void AppConfig::set_defaults() if (get("show_splash_screen").empty()) set("show_splash_screen", "1"); - if (get("last_hint").empty()) - set("last_hint", "0"); - if (get("show_hints").empty()) set("show_hints", "1"); diff --git a/src/slic3r/GUI/HintNotification.cpp b/src/slic3r/GUI/HintNotification.cpp index 42039fa70..cd92cf480 100644 --- a/src/slic3r/GUI/HintNotification.cpp +++ b/src/slic3r/GUI/HintNotification.cpp @@ -14,6 +14,31 @@ #include #include #include +#include +#include +#include + +#define HINTS_CEREAL_VERSION 1 +// structure for writing used hints into binary file with version +struct CerealData +{ + std::vector my_data; + // cereal will supply the version automatically when loading or saving + // The version number comes from the CEREAL_CLASS_VERSION macro + template + void serialize(Archive& ar, std::uint32_t const version) + { + // You can choose different behaviors depending on the version + // This is useful if you need to support older variants of your codebase + // interacting with newer ones + if (version > HINTS_CEREAL_VERSION) + throw Slic3r::IOError("Version of hints.cereal is higher than current version."); + else + ar(my_data); + } +}; +// version of used hints binary file +CEREAL_CLASS_VERSION(CerealData, HINTS_CEREAL_VERSION); namespace Slic3r { namespace GUI { @@ -31,6 +56,41 @@ inline void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, f else ImGui::PushStyleColor(idx, col); } + + + + + +void write_used_binary(const std::vector& ids) +{ + boost::filesystem::ofstream file((boost::filesystem::path(data_dir()) / "cache" / "hints.cereal"), std::ios::binary); + cereal::BinaryOutputArchive archive(file); + CerealData cd { ids }; + try + { + archive(cd); + } + catch (const std::exception& ex) + { + BOOST_LOG_TRIVIAL(error) << "Failed to write to hints.cereal. " << ex.what(); + } +} +void read_used_binary(std::vector& ids) +{ + boost::filesystem::ifstream file((boost::filesystem::path(data_dir()) / "cache" / "hints.cereal")); + cereal::BinaryInputArchive archive(file); + CerealData cd; + try + { + archive(cd); + } + catch (const std::exception& ex) + { + BOOST_LOG_TRIVIAL(error) << "Failed to load to hints.cereal. " << ex.what(); + return; + } + ids = cd.my_data; +} enum TagCheckResult { TagCheckAffirmative, @@ -179,30 +239,19 @@ void launch_browser_if_allowed(const std::string& url) if (wxGetApp().app_config->get("suppress_hyperlinks") != "1") wxLaunchDefaultBrowser(url); } -bool pot_exists() -{ - return true; -// return boost::filesystem::exists(std::move(boost::filesystem::path(resources_dir()) / "data" / "hints.pot")); -} -void write_pot(const std::vector& elements) -{ - boost::filesystem::ofstream file(std::move(boost::filesystem::path(resources_dir()) / "data" / "hints.pot")); - - for ( const auto &element : elements) - { - file << "msgid \"" << escape_string_cstyle(element) << "\"\nmsgstr \"\"\n\n"; - } - file.close(); -} } //namespace - +HintDatabase::~HintDatabase() +{ + if (m_initialized) { + write_used_binary(m_used_ids); + } +} void HintDatabase::init() { load_hints_from_file(std::move(boost::filesystem::path(resources_dir()) / "data" / "hints.ini")); const AppConfig* app_config = wxGetApp().app_config; - m_hint_id = std::atoi(app_config->get("last_hint").c_str()); m_initialized = true; } @@ -210,8 +259,6 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) { namespace pt = boost::property_tree; pt::ptree tree; - bool create_pot = !pot_exists(); - std::vector pot_elements; boost::nowide::ifstream ifs(path.string()); try { pt::read_ini(ifs, tree); @@ -227,19 +274,24 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) for (const auto& data : section.second) { dict.emplace(data.first, data.second.data()); } - - //unescaping and translating all texts and saving all data common for all hint types + // unique id string [hint:id] (trim "hint:") + std::string id_string = section.first.substr(5); + id_string = std::to_string(std::hash{}(id_string)); + // unescaping and translating all texts and saving all data common for all hint types std::string fulltext; std::string text1; std::string hypertext_text; std::string follow_text; + // tags std::string disabled_tags; std::string enabled_tags; + // optional link to documentation (accessed from button) std::string documentation_link; + // randomized weighted order variables + size_t weight = 1; + bool was_displayed = is_used(id_string); //unescape text1 unescape_string_cstyle(_utf8(dict["text"]), fulltext); - if (create_pot) - pot_elements.emplace_back(fulltext); // replace and for imgui markers std::string marker_s(1, ImGui::ColorMarkerStart); std::string marker_e(1, ImGui::ColorMarkerEnd); @@ -295,37 +347,41 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) documentation_link = dict["documentation_link"]; } + if (dict.find("weight") != dict.end()) { + weight = (size_t)std::max(1, std::atoi(dict["weight"].c_str())); + } + // create HintData if (dict.find("hypertext_type") != dict.end()) { //link to internet if(dict["hypertext_type"] == "link") { std::string hypertext_link = dict["hypertext_link"]; - HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [hypertext_link]() { launch_browser_if_allowed(hypertext_link); } }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [hypertext_link]() { launch_browser_if_allowed(hypertext_link); } }; m_loaded_hints.emplace_back(hint_data); // highlight settings } else if (dict["hypertext_type"] == "settings") { std::string opt = dict["hypertext_settings_opt"]; Preset::Type type = static_cast(std::atoi(dict["hypertext_settings_type"].c_str())); std::wstring category = boost::nowide::widen(dict["hypertext_settings_category"]); - HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [opt, type, category]() { GUI::wxGetApp().sidebar().jump_to_option(opt, type, category); } }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [opt, type, category]() { GUI::wxGetApp().sidebar().jump_to_option(opt, type, category); } }; m_loaded_hints.emplace_back(hint_data); // open preferences } else if(dict["hypertext_type"] == "preferences") { int page = static_cast(std::atoi(dict["hypertext_preferences_page"].c_str())); - HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [page]() { wxGetApp().open_preferences(page); } }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [page]() { wxGetApp().open_preferences(page); } }; m_loaded_hints.emplace_back(hint_data); } else if (dict["hypertext_type"] == "plater") { std::string item = dict["hypertext_plater_item"]; - HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [item]() { wxGetApp().plater()->canvas3D()->highlight_toolbar_item(item); } }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [item]() { wxGetApp().plater()->canvas3D()->highlight_toolbar_item(item); } }; m_loaded_hints.emplace_back(hint_data); } else if (dict["hypertext_type"] == "gizmo") { std::string item = dict["hypertext_gizmo_item"]; - HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [item]() { wxGetApp().plater()->canvas3D()->highlight_gizmo(item); } }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [item]() { wxGetApp().plater()->canvas3D()->highlight_gizmo(item); } }; m_loaded_hints.emplace_back(hint_data); } else if (dict["hypertext_type"] == "gallery") { - HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, []() { + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, []() { // Deselect all objects, otherwise gallery wont show. wxGetApp().plater()->canvas3D()->deselect_all(); wxGetApp().obj_list()->load_shape_object_from_gallery(); } }; @@ -333,19 +389,17 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) } } else { // plain text without hypertext - HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link }; m_loaded_hints.emplace_back(hint_data); } } } - if (create_pot) - write_pot(pot_elements); } -HintData* HintDatabase::get_hint(bool up) +HintData* HintDatabase::get_hint(bool new_hint/* = true*/) { if (! m_initialized) { init(); - //return false; + new_hint = true; } if (m_loaded_hints.empty()) { @@ -353,23 +407,84 @@ HintData* HintDatabase::get_hint(bool up) return nullptr; } - // shift id - m_hint_id = (up ? m_hint_id + 1 : m_hint_id ); - m_hint_id %= m_loaded_hints.size(); + if (new_hint) + m_hint_id = get_next(); - AppConfig* app_config = wxGetApp().app_config; - app_config->set("last_hint", std::to_string(m_hint_id)); - - //data = &m_loaded_hints[m_hint_id]; - /* - data.text = m_loaded_hints[m_hint_id].text; - data.hypertext = m_loaded_hints[m_hint_id].hypertext; - data.follow_text = m_loaded_hints[m_hint_id].follow_text; - data.callback = m_loaded_hints[m_hint_id].callback; - */ return &m_loaded_hints[m_hint_id]; } +size_t HintDatabase::get_next() +{ + if (!m_sorted_hints) + { + auto compare_wieght = [](const HintData& a, const HintData& b){ return a.weight < b.weight; }; + std::sort(m_loaded_hints.begin(), m_loaded_hints.end(), compare_wieght); + m_sorted_hints = true; + srand(time(NULL)); + } + std::vector candidates; // index in m_loaded_hints + // total weight + size_t total_weight = 0; + for (size_t i = 0; i < m_loaded_hints.size(); i++) { + if (!m_loaded_hints[i].was_displayed && tags_check(m_loaded_hints[i].disabled_tags, m_loaded_hints[i].enabled_tags)) { + candidates.emplace_back(i); + total_weight += m_loaded_hints[i].weight; + } + } + // all were shown + if (total_weight == 0) { + clear_used(); + for (size_t i = 0; i < m_loaded_hints.size(); i++) { + m_loaded_hints[i].was_displayed = false; + if (tags_check(m_loaded_hints[i].disabled_tags, m_loaded_hints[i].enabled_tags)) { + candidates.emplace_back(i); + total_weight += m_loaded_hints[i].weight; + } + } + } + size_t random_number = rand() % total_weight + 1; + size_t current_weight = 0; + for (size_t i = 0; i < candidates.size(); i++) { + current_weight += m_loaded_hints[candidates[i]].weight; + if (random_number <= current_weight) { + set_used(m_loaded_hints[candidates[i]].id_string); + m_loaded_hints[candidates[i]].was_displayed = true; + return candidates[i]; + } + } + BOOST_LOG_TRIVIAL(error) << "Hint notification random number generator failed."; + return 0; +} + +bool HintDatabase::is_used(const std::string& id) +{ + // load used ids from file + if (!m_used_ids_loaded) { + read_used_binary(m_used_ids); + m_used_ids_loaded = true; + } + // check if id is in used + for (const std::string& used_id : m_used_ids) { + if (used_id == id) + { + return true; + } + } + return false; +} +void HintDatabase::set_used(const std::string& id) +{ + // check needed? + if (!is_used(id)) + { + m_used_ids.emplace_back(id); + } +} +void HintDatabase::clear_used() +{ + m_used_ids.clear(); +} + void NotificationManager::HintNotification::count_spaces() { //determine line width @@ -865,23 +980,12 @@ void NotificationManager::HintNotification::open_documentation() launch_browser_if_allowed(m_documentation_link); } } -void NotificationManager::HintNotification::retrieve_data(int recursion_counter) +void NotificationManager::HintNotification::retrieve_data(bool new_hint/* = true*/) { - HintData* hint_data = HintDatabase::get_instance().get_hint(recursion_counter >= 0 ? true : false); + HintData* hint_data = HintDatabase::get_instance().get_hint(new_hint); if (hint_data == nullptr) close(); - if (hint_data != nullptr && !tags_check(hint_data->disabled_tags, hint_data->enabled_tags)) - { - // Content for different user - retrieve another - size_t count = HintDatabase::get_instance().get_count(); - if ((int)count < recursion_counter) { - BOOST_LOG_TRIVIAL(error) << "Hint notification failed to load data due to recursion counter."; - } else { - retrieve_data(recursion_counter + 1); - } - return; - } if(hint_data != nullptr) { NotificationData nd { NotificationType::DidYouKnowHint, diff --git a/src/slic3r/GUI/HintNotification.hpp b/src/slic3r/GUI/HintNotification.hpp index 78e02a848..c1e7c0ed3 100644 --- a/src/slic3r/GUI/HintNotification.hpp +++ b/src/slic3r/GUI/HintNotification.hpp @@ -9,7 +9,10 @@ namespace GUI { // Database of hints updatable struct HintData { + std::string id_string; std::string text; + size_t weight; + bool was_displayed; std::string hypertext; std::string follow_text; std::string disabled_tags; @@ -33,11 +36,12 @@ private: : m_hint_id(0) {} public: + ~HintDatabase(); HintDatabase(HintDatabase const&) = delete; void operator=(HintDatabase const&) = delete; // return true if HintData filled; - HintData* get_hint(bool up = true); + HintData* get_hint(bool new_hint = true); size_t get_count() { if (!m_initialized) return 0; @@ -46,10 +50,17 @@ public: private: void init(); void load_hints_from_file(const boost::filesystem::path& path); + bool is_used(const std::string& id); + void set_used(const std::string& id); + void clear_used(); + // Returns position in m_loaded_hints with next hint chosed randomly with weights + size_t get_next(); size_t m_hint_id; bool m_initialized { false }; std::vector m_loaded_hints; - + bool m_sorted_hints { false }; + std::vector m_used_ids; + bool m_used_ids_loaded { false }; }; // Notification class - shows current Hint ("Did you know") class NotificationManager::HintNotification : public NotificationManager::PopNotification @@ -58,10 +69,10 @@ public: HintNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool new_hint) : PopNotification(n, id_provider, evt_handler) { - retrieve_data(new_hint ? 0 : -1); + retrieve_data(new_hint); } virtual void init() override; - void open_next() { retrieve_data(0); } + void open_next() { retrieve_data(); } protected: virtual void set_next_window_size(ImGuiWrapper& imgui) override; virtual void count_spaces() override; @@ -87,7 +98,7 @@ protected: const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y); // recursion counter -1 tells to retrieve same hint as last time - void retrieve_data(int recursion_counter = 0); + void retrieve_data(bool new_hint = true); void open_documentation(); bool m_has_hint_data { false }; From 2680d420558d312a361164345e691f45d9e8d82a Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 24 Aug 2021 17:09:49 +0200 Subject: [PATCH 68/86] comments in hints.ini --- resources/data/hints.ini | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/data/hints.ini b/resources/data/hints.ini index 28a13236d..95060f9ec 100644 --- a/resources/data/hints.ini +++ b/resources/data/hints.ini @@ -49,7 +49,13 @@ # Algorithm shows hint only if ALL enabled tags are affirmative. (so never do enabled_tags = FFF; SLA;) # Algorithm shows hint only if not in all disabled tags. # if there are both disabled and preferred, only preferred that are not in disabled are valid. - +# +# +# Notifications shows in random order, already shown notifications are saved at cache/hints.cereal (as binary - human non-readable) +# You can affect random ordering by seting weigh +# weight = 5 +# Weight must be larger or equal to 1. Default weight is 1. +# Weight defines probability as weight : sum_of_all_weights. [hint:Fuzzy skin] text = Fuzzy skin\nDid you know that you can create rough fibre-like texture on the sides of your models using theFuzzy skinfeature? You can also use modifiers to apply fuzzy-skin only to a portion of your model. From e65dc37401b29f06fa571de63ce4d47c450c26f1 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 24 Aug 2021 17:23:58 +0200 Subject: [PATCH 69/86] Refactoring + throwing exception from random generator in hints --- src/slic3r/GUI/HintNotification.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/HintNotification.cpp b/src/slic3r/GUI/HintNotification.cpp index cd92cf480..990e4d37a 100644 --- a/src/slic3r/GUI/HintNotification.cpp +++ b/src/slic3r/GUI/HintNotification.cpp @@ -20,7 +20,7 @@ #define HINTS_CEREAL_VERSION 1 // structure for writing used hints into binary file with version -struct CerealData +struct HintsCerealData { std::vector my_data; // cereal will supply the version automatically when loading or saving @@ -38,7 +38,7 @@ struct CerealData } }; // version of used hints binary file -CEREAL_CLASS_VERSION(CerealData, HINTS_CEREAL_VERSION); +CEREAL_CLASS_VERSION(HintsCerealData, HINTS_CEREAL_VERSION); namespace Slic3r { namespace GUI { @@ -65,7 +65,7 @@ void write_used_binary(const std::vector& ids) { boost::filesystem::ofstream file((boost::filesystem::path(data_dir()) / "cache" / "hints.cereal"), std::ios::binary); cereal::BinaryOutputArchive archive(file); - CerealData cd { ids }; + HintsCerealData cd { ids }; try { archive(cd); @@ -79,7 +79,7 @@ void read_used_binary(std::vector& ids) { boost::filesystem::ifstream file((boost::filesystem::path(data_dir()) / "cache" / "hints.cereal")); cereal::BinaryInputArchive archive(file); - CerealData cd; + HintsCerealData cd; try { archive(cd); @@ -407,8 +407,17 @@ HintData* HintDatabase::get_hint(bool new_hint/* = true*/) return nullptr; } - if (new_hint) - m_hint_id = get_next(); + try + { + if (new_hint) + m_hint_id = get_next(); + } + catch (const std::exception&) + { + return nullptr; + } + + return &m_loaded_hints[m_hint_id]; } @@ -442,6 +451,10 @@ size_t HintDatabase::get_next() } } } + if (total_weight == 0) { + BOOST_LOG_TRIVIAL(error) << "Hint notification random number generator failed. No suitable hint was found."; + throw std::exception(); + } size_t random_number = rand() % total_weight + 1; size_t current_weight = 0; for (size_t i = 0; i < candidates.size(); i++) { @@ -453,7 +466,7 @@ size_t HintDatabase::get_next() } } BOOST_LOG_TRIVIAL(error) << "Hint notification random number generator failed."; - return 0; + throw std::exception(); } bool HintDatabase::is_used(const std::string& id) From 1c72351ba0aaf78dba86e5aeefe6bae65cdeb324 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 24 Aug 2021 17:31:34 +0200 Subject: [PATCH 70/86] Erase updatedItemsInfo type from multiple-showing notifications list. --- src/slic3r/GUI/NotificationManager.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 2bc9aaaab..2be8ba26b 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -538,7 +538,7 @@ private: // Timestamp of last rendering int64_t m_last_render { 0LL }; // Notification types that can be shown multiple types at once (compared by text) - const std::vector m_multiple_types = { NotificationType::CustomNotification, NotificationType::PlaterWarning, NotificationType::ProgressBar, NotificationType::PrintHostUpload, NotificationType::UpdatedItemsInfo }; + const std::vector m_multiple_types = { NotificationType::CustomNotification, NotificationType::PlaterWarning, NotificationType::ProgressBar, NotificationType::PrintHostUpload }; //prepared (basic) notifications static const NotificationData basic_notifications[]; }; From d701dfe436b353f4847b7a78605847f85e50e4eb Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 25 Aug 2021 09:11:20 +0200 Subject: [PATCH 71/86] Fixed deletion of objects/volumes by pressing Del key while the mouse cursor is hovering the objects list in sidebar --- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 0c555454d..1e290beae 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1049,7 +1049,7 @@ void ObjectList::key_event(wxKeyEvent& event) || event.GetKeyCode() == WXK_BACK #endif //__WXOSX__ ) { - remove(); + wxGetApp().plater()->remove_selected(); } else if (event.GetKeyCode() == WXK_F5) wxGetApp().plater()->reload_all_from_disk(); From 783c9cf2028e994608100ba598fd206ceccec93b Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 25 Aug 2021 09:34:32 +0200 Subject: [PATCH 72/86] Fix of d3f11a6ab7a7c350439929e9ebf2b03ef4989477 --- src/slic3r/Utils/Http.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 06598f8f5..f1614017f 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -491,6 +491,7 @@ Http& Http::form_add_file(const std::string &name, const fs::path &path, const s return *this; } +#ifdef WIN32 // Tells libcurl to ignore certificate revocation checks in case of missing or offline distribution points for those SSL backends where such behavior is present. // This option is only supported for Schannel (the native Windows SSL library). Http& Http::ssl_revoke_best_effort(bool set) @@ -500,6 +501,7 @@ Http& Http::ssl_revoke_best_effort(bool set) } return *this; } +#endif // WIN32 Http& Http::set_post_body(const fs::path &path) { From debf4981a6a20f67545c399b3144014fe40c2a10 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 25 Aug 2021 09:44:50 +0200 Subject: [PATCH 73/86] Fix clang for VisualStudio usage --- .clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 6b68254ec..440c89ec5 100644 --- a/.clang-format +++ b/.clang-format @@ -77,7 +77,7 @@ IndentWidth: 4 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true -KeepLineBreaksForNonEmptyLines: false +#KeepLineBreaksForNonEmptyLines: false KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: '' MacroBlockEnd: '' From 369f325f4ed396271401ea267e8327cd73c4a0cc Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 25 Aug 2021 09:52:27 +0200 Subject: [PATCH 74/86] Delete unused variable --- src/slic3r/GUI/HintNotification.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/slic3r/GUI/HintNotification.cpp b/src/slic3r/GUI/HintNotification.cpp index 990e4d37a..1d5931c48 100644 --- a/src/slic3r/GUI/HintNotification.cpp +++ b/src/slic3r/GUI/HintNotification.cpp @@ -248,12 +248,8 @@ HintDatabase::~HintDatabase() } void HintDatabase::init() { - load_hints_from_file(std::move(boost::filesystem::path(resources_dir()) / "data" / "hints.ini")); - - const AppConfig* app_config = wxGetApp().app_config; m_initialized = true; - } void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) { From beb38d09ae16c7d8308806be59893a7d0413548c Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 25 Aug 2021 10:51:11 +0200 Subject: [PATCH 75/86] Add reserve to mesh boolean operation --- src/libslic3r/MeshBoolean.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libslic3r/MeshBoolean.cpp b/src/libslic3r/MeshBoolean.cpp index 3dd5da307..a59165946 100644 --- a/src/libslic3r/MeshBoolean.cpp +++ b/src/libslic3r/MeshBoolean.cpp @@ -118,6 +118,11 @@ void triangle_mesh_to_cgal(const std::vector & V, { if (F.empty()) return; + size_t vertices_count = V.size(); + size_t edges_count = (F.size()* 3) / 2; + size_t faces_count = F.size(); + out.reserve(vertices_count, edges_count, faces_count); + for (auto &v : V) out.add_vertex(typename _Mesh::Point{v.x(), v.y(), v.z()}); From 3fc4cc84a7b0a3a86b5162039e04d4cce079367c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 25 Aug 2021 12:01:41 +0200 Subject: [PATCH 76/86] Fixed invalidation when first_layer_height is changed --- src/libslic3r/Print.cpp | 3 ++- src/libslic3r/PrintObject.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index b3a1bc993..48737f830 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -159,7 +159,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "wipe_tower_rotation_angle") { steps.emplace_back(psSkirtBrim); } else if ( - opt_key == "nozzle_diameter" + opt_key == "first_layer_height" + || opt_key == "nozzle_diameter" || opt_key == "resolution" // Spiral Vase forces different kind of slicing than the normal model: // In Spiral Vase mode, holes are closed and only the largest area contour is kept at each layer. diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index ae9816531..ee09e0f5b 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -535,7 +535,6 @@ bool PrintObject::invalidate_state_by_config_options( steps.emplace_back(posPerimeters); } else if ( opt_key == "layer_height" - || opt_key == "first_layer_height" || opt_key == "mmu_segmented_region_max_width" || opt_key == "raft_layers" || opt_key == "raft_contact_distance" From 38cd7fea6540ecf41cd0773f859861ef7924757e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 25 Aug 2021 12:39:46 +0200 Subject: [PATCH 77/86] Fixed update of backend after the changes introduced with b3010a817bdc8e63b2ad2f9d281be3ba89216ba7 (Do not allow objects to be placed fully below bed) and pop object on the bed when only one part is left --- src/libslic3r/Model.cpp | 53 +++++++++++++++++++++++++++++-- src/libslic3r/Model.hpp | 2 ++ src/slic3r/GUI/GUI_ObjectList.cpp | 11 +++---- src/slic3r/GUI/Plater.cpp | 3 +- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 235c35797..8eb5bb389 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -956,9 +956,22 @@ void ModelObject::center_around_origin(bool include_modifiers) void ModelObject::ensure_on_bed(bool allow_negative_z) { - const double min_z = get_min_z(); - if (!allow_negative_z || min_z > SINKING_Z_THRESHOLD) - translate_instances({ 0.0, 0.0, -min_z }); + double z_offset = 0.0; + + if (allow_negative_z) { + if (volumes.size() == 1) + z_offset = -get_min_z(); + else { + const double max_z = get_max_z(); + if (max_z < SINKING_MIN_Z_THRESHOLD) + z_offset = SINKING_MIN_Z_THRESHOLD - max_z; + } + } + else + z_offset = -get_min_z(); + + if (z_offset != 0.0) + translate_instances(z_offset * Vec3d::UnitZ()); } void ModelObject::translate_instances(const Vec3d& vector) @@ -1429,6 +1442,19 @@ double ModelObject::get_min_z() const } } +double ModelObject::get_max_z() const +{ + if (instances.empty()) + return 0.0; + else { + double max_z = -DBL_MAX; + for (size_t i = 0; i < instances.size(); ++i) { + max_z = std::max(max_z, get_instance_max_z(i)); + } + return max_z; + } +} + double ModelObject::get_instance_min_z(size_t instance_idx) const { double min_z = DBL_MAX; @@ -1450,6 +1476,27 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const return min_z + inst->get_offset(Z); } +double ModelObject::get_instance_max_z(size_t instance_idx) const +{ + double max_z = -DBL_MAX; + + const ModelInstance* inst = instances[instance_idx]; + const Transform3d& mi = inst->get_matrix(true); + + for (const ModelVolume* v : volumes) { + if (!v->is_model_part()) + continue; + + const Transform3d mv = mi * v->get_matrix(); + const TriangleMesh& hull = v->get_convex_hull(); + for (const stl_facet& facet : hull.stl.facet_start) + for (int i = 0; i < 3; ++i) + max_z = std::max(max_z, (mv * facet.vertex[i].cast()).z()); + } + + return max_z + inst->get_offset(Z); +} + unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume) { unsigned int num_printable = 0; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 1dd16ee91..25f19e792 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -358,7 +358,9 @@ public: void bake_xy_rotation_into_meshes(size_t instance_idx); double get_min_z() const; + double get_max_z() const; double get_instance_min_z(size_t instance_idx) const; + double get_instance_max_z(size_t instance_idx) const; // Called by Print::validate() from the UI thread. unsigned int check_instances_print_volume_state(const BoundingBoxf3& print_volume); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 1e290beae..23ce819dd 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1920,16 +1920,15 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con if (vol->is_model_part()) ++solid_cnt; if (volume->is_model_part() && solid_cnt == 1) { - Slic3r::GUI::show_error(nullptr, _(L("From Object List You can't delete the last solid part from object."))); + Slic3r::GUI::show_error(nullptr, _L("From Object List You can't delete the last solid part from object.")); return false; } - take_snapshot(_(L("Delete Subobject"))); + take_snapshot(_L("Delete Subobject")); object->delete_volume(idx); - if (object->volumes.size() == 1) - { + if (object->volumes.size() == 1) { const auto last_volume = object->volumes[0]; if (!last_volume->config.empty()) { object->config.apply(last_volume->config); @@ -1948,11 +1947,11 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con } else if (type == itInstance) { if (object->instances.size() == 1) { - Slic3r::GUI::show_error(nullptr, _(L("Last instance of an object cannot be deleted."))); + Slic3r::GUI::show_error(nullptr, _L("Last instance of an object cannot be deleted.")); return false; } - take_snapshot(_(L("Delete Instance"))); + take_snapshot(_L("Delete Instance")); object->delete_instance(idx); } else diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 60215484b..72b2c5909 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6200,8 +6200,7 @@ void Plater::changed_object(int obj_idx) if (obj_idx < 0) return; // recenter and re - align to Z = 0 - auto model_object = p->model.objects[obj_idx]; - model_object->ensure_on_bed(this->p->printer_technology != ptSLA); + p->model.objects[obj_idx]->ensure_on_bed(p->printer_technology != ptSLA); if (this->p->printer_technology == ptSLA) { // Update the SLAPrint from the current Model, so that the reload_scene() // pulls the correct data, update the 3D scene. From a918314aab574075e256ce30e1a1e1b29f287a54 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 25 Aug 2021 13:01:08 +0200 Subject: [PATCH 78/86] Fix UI glitches when "fill bed" fails to add any additional instances --- src/slic3r/GUI/Jobs/FillBedJob.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/Jobs/FillBedJob.cpp b/src/slic3r/GUI/Jobs/FillBedJob.cpp index 1948c8fbb..870f31f2f 100644 --- a/src/slic3r/GUI/Jobs/FillBedJob.cpp +++ b/src/slic3r/GUI/Jobs/FillBedJob.cpp @@ -147,26 +147,28 @@ void FillBedJob::finalize() size_t inst_cnt = model_object->instances.size(); - for (ArrangePolygon &ap : m_selected) { - if (ap.bed_idx != arrangement::UNARRANGED && (ap.priority != 0 || ap.bed_idx == 0)) - ap.apply(); - } + int added_cnt = std::accumulate(m_selected.begin(), m_selected.end(), 0, [](int s, auto &ap) { + return s + int(ap.priority == 0 && ap.bed_idx == 0); + }); - model_object->ensure_on_bed(); + if (added_cnt > 0) { + for (ArrangePolygon &ap : m_selected) { + if (ap.bed_idx != arrangement::UNARRANGED && (ap.priority != 0 || ap.bed_idx == 0)) + ap.apply(); + } - m_plater->update(); + model_object->ensure_on_bed(); - int added_cnt = std::accumulate(m_selected.begin(), m_selected.end(), 0, - [](int s, auto &ap) { - return s + int(ap.priority == 0 && ap.bed_idx == 0); - }); + m_plater->update(); - // FIXME: somebody explain why this is needed for increase_object_instances - if (inst_cnt == 1) added_cnt++; + // FIXME: somebody explain why this is needed for increase_object_instances + if (inst_cnt == 1) added_cnt++; - if (added_cnt > 0) m_plater->sidebar() .obj_list()->increase_object_instances(m_object_idx, size_t(added_cnt)); + } + + Job::finalize(); } }} // namespace Slic3r::GUI From 9896a2190466d1c0d6a4c76e7ec0541f6bef3072 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 25 Aug 2021 13:09:37 +0200 Subject: [PATCH 79/86] @Vojta request --> change ratio to decimation ratio --- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 80 ++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 27 +++++--- 2 files changed, 66 insertions(+), 41 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index f0336f729..3530b4240 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -17,10 +17,17 @@ GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D & parent, : GLGizmoBase(parent, icon_filename, -1) , m_state(State::settings) , m_is_valid_result(false) + , m_exist_preview(false) , m_progress(0) , m_volume(nullptr) , m_obj_index(0) , m_need_reload(false) + + , tr_mesh_name(_u8L("Mesh name")) + , tr_triangles(_u8L("Triangles")) + , tr_preview(_u8L("Preview")) + , tr_detail_level(_u8L("Detail level")) + , tr_decimate_ratio(_u8L("Decimate ratio")) {} GLGizmoSimplify::~GLGizmoSimplify() { @@ -45,9 +52,7 @@ void GLGizmoSimplify::on_render_for_picking() {} void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limit) { - const int max_char_in_name = 20; create_gui_cfg(); - const Selection &selection = m_parent.get_selection(); int object_idx = selection.get_object_idx(); ModelObject *obj = wxGetApp().plater()->model().objects[object_idx]; @@ -65,15 +70,15 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi m_obj_index = object_idx; // to remember correct object m_volume = act_volume; m_original_its = {}; - const TriangleMesh &tm = m_volume->mesh(); - m_configuration.wanted_percent = 50.; // default value - m_configuration.update_percent(tm.its.indices.size()); + m_configuration.decimate_ratio = 50.; // default value + m_configuration.fix_count_by_ratio(m_volume->mesh().its.indices.size()); m_is_valid_result = false; + m_exist_preview = false; if (change_window_position) { ImVec2 pos = ImGui::GetMousePos(); - pos.x -= m_gui_cfg->window_offset; - pos.y -= m_gui_cfg->window_offset; + pos.x -= m_gui_cfg->window_offset_x; + pos.y -= m_gui_cfg->window_offset_y; // minimal top left value ImVec2 tl(m_gui_cfg->window_padding, m_gui_cfg->window_padding); if (pos.x < tl.x) pos.x = tl.x; @@ -81,8 +86,8 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi // maximal bottom right value auto parent_size = m_parent.get_canvas_size(); ImVec2 br( - parent_size.get_width() - (2 * m_gui_cfg->window_offset + m_gui_cfg->window_padding), - parent_size.get_height() - (2 * m_gui_cfg->window_offset + m_gui_cfg->window_padding)); + parent_size.get_width() - (2 * m_gui_cfg->window_offset_x + m_gui_cfg->window_padding), + parent_size.get_height() - (2 * m_gui_cfg->window_offset_y + m_gui_cfg->window_padding)); if (pos.x > br.x) pos.x = br.x; if (pos.y > br.y) pos.y = br.y; ImGui::SetNextWindowPos(pos, ImGuiCond_Always); @@ -98,15 +103,23 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi if (m_original_its.has_value()) triangle_count = m_original_its->indices.size(); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Mesh name") + ":"); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, tr_mesh_name + ":"); ImGui::SameLine(m_gui_cfg->top_left_width); std::string name = m_volume->name; - if (name.length() > max_char_in_name) - name = name.substr(0, max_char_in_name-3) + "..."; + if (name.length() > m_gui_cfg->max_char_in_name) + name = name.substr(0, m_gui_cfg->max_char_in_name - 3) + "..."; m_imgui->text(name); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Triangles") + ":"); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, tr_triangles + ":"); ImGui::SameLine(m_gui_cfg->top_left_width); m_imgui->text(std::to_string(triangle_count)); + /* + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, tr_preview + ":"); + ImGui::SameLine(m_gui_cfg->top_left_width); + if (m_exist_preview) { + m_imgui->text(std::to_string(m_volume->mesh().its.indices.size())); + } else { + m_imgui->text("---"); + }*/ ImGui::Separator(); @@ -116,7 +129,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi } ImGui::SameLine(); m_imgui->disabled_begin(m_configuration.use_count); - ImGui::Text(_L("Detail level").c_str()); + ImGui::Text(tr_detail_level.c_str()); std::vector reduce_captions = { static_cast(_u8L("Extra high")), static_cast(_u8L("High")), @@ -150,22 +163,23 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi // show preview result triangle count (percent) if (m_need_reload && !m_configuration.use_count) { m_configuration.wanted_count = static_cast(m_volume->mesh().its.indices.size()); - m_configuration.update_count(triangle_count); + m_configuration.decimate_ratio = + (1.0f - (m_configuration.wanted_count / (float) triangle_count)) * 100.f; } m_imgui->disabled_begin(!m_configuration.use_count); - ImGui::Text(_L("Ratio").c_str()); + ImGui::Text(tr_decimate_ratio.c_str()); ImGui::SameLine(m_gui_cfg->bottom_left_width); ImGui::SetNextItemWidth(m_gui_cfg->input_width); - const char * format = (m_configuration.wanted_percent > 10)? "%.0f %%": - ((m_configuration.wanted_percent > 1)? "%.1f %%":"%.2f %%"); - if (ImGui::SliderFloat("##triangle_ratio", &m_configuration.wanted_percent, 0.f, 100.f, format)) { + const char * format = (m_configuration.decimate_ratio > 10)? "%.0f %%": + ((m_configuration.decimate_ratio > 1)? "%.1f %%":"%.2f %%"); + if (ImGui::SliderFloat("##decimate_ratio", &m_configuration.decimate_ratio, 0.f, 100.f, format)) { m_is_valid_result = false; - if (m_configuration.wanted_percent < 0.f) - m_configuration.wanted_percent = 0.01f; - if (m_configuration.wanted_percent > 100.f) - m_configuration.wanted_percent = 100.f; - m_configuration.update_percent(triangle_count); + if (m_configuration.decimate_ratio < 0.f) + m_configuration.decimate_ratio = 0.01f; + if (m_configuration.decimate_ratio > 100.f) + m_configuration.decimate_ratio = 100.f; + m_configuration.fix_count_by_ratio(triangle_count); } ImGui::NewLine(); @@ -195,7 +209,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi process(); } else { // use preview and close - if (m_original_its.has_value()) { + if (m_exist_preview) { // fix hollowing, sla support points, modifiers, ... auto plater = wxGetApp().plater(); plater->changed_mesh(m_obj_index); @@ -286,6 +300,7 @@ void GLGizmoSimplify::process() its_quadric_edge_collapse(collapsed, triangle_count, &max_error, throw_on_cancel, statusfn); set_its(collapsed); m_is_valid_result = true; + m_exist_preview = true; } catch (SimplifyCanceledException &) { // set state out of main thread m_state = State::settings; @@ -326,7 +341,7 @@ void GLGizmoSimplify::on_set_state() } // revert preview - if (m_original_its.has_value()) { + if (m_exist_preview) { set_its(*m_original_its); m_parent.reload_scene(true); m_need_reload = false; @@ -344,18 +359,19 @@ void GLGizmoSimplify::create_gui_cfg() { if (m_gui_cfg.has_value()) return; int space_size = m_imgui->calc_text_size(":MM").x; GuiCfg cfg; - cfg.top_left_width = std::max(m_imgui->calc_text_size(_L("Mesh name")).x, - m_imgui->calc_text_size(_L("Triangles")).x) + cfg.top_left_width = std::max(m_imgui->calc_text_size(tr_mesh_name).x, + m_imgui->calc_text_size(tr_triangles).x) + space_size; const float radio_size = ImGui::GetFrameHeight(); cfg.bottom_left_width = - std::max(m_imgui->calc_text_size(_L("Detail level")).x, - m_imgui->calc_text_size(_L("Ratio")).x) + + std::max(m_imgui->calc_text_size(tr_detail_level).x, + m_imgui->calc_text_size(tr_decimate_ratio).x) + space_size + radio_size; - cfg.input_width = cfg.bottom_left_width; - cfg.window_offset = cfg.input_width; + cfg.input_width = cfg.bottom_left_width * 1.5; + cfg.window_offset_x = (cfg.bottom_left_width + cfg.input_width)/2; + cfg.window_offset_y = ImGui::GetTextLineHeightWithSpacing() * 5; m_gui_cfg = cfg; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index 3d667d691..9af6686bd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -37,7 +37,9 @@ private: void create_gui_cfg(); void request_rerender(); - bool m_is_valid_result; // differ what to do in apply + std::atomic_bool m_is_valid_result; // differ what to do in apply + std::atomic_bool m_exist_preview; // set when process end + volatile int m_progress; // percent of done work ModelVolume *m_volume; // size_t m_obj_index; @@ -59,20 +61,16 @@ private: { bool use_count = false; // minimal triangle count - float wanted_percent = 50.f; + float decimate_ratio = 50.f; // in percent uint32_t wanted_count = 0; // initialize by percents // maximal quadric error float max_error = 1.; - void update_count(size_t triangle_count) - { - wanted_percent = (float) wanted_count / triangle_count * 100.f; - } - void update_percent(size_t triangle_count) + void fix_count_by_ratio(size_t triangle_count) { wanted_count = static_cast( - std::round(triangle_count * wanted_percent / 100.f)); + std::round(triangle_count * (100.f-decimate_ratio) / 100.f)); } } m_configuration; @@ -84,10 +82,21 @@ private: int top_left_width = 100; int bottom_left_width = 100; int input_width = 100; - int window_offset = 100; + int window_offset_x = 100; + int window_offset_y = 100; int window_padding = 0; + + // trunc model name when longer + int max_char_in_name = 30; }; std::optional m_gui_cfg; + + // translations used for calc window size + const std::string tr_mesh_name; + const std::string tr_triangles; + const std::string tr_preview; + const std::string tr_detail_level; + const std::string tr_decimate_ratio; }; } // namespace GUI From 0e4a987bed809a6933b89bfc400316440051580d Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 25 Aug 2021 13:17:36 +0200 Subject: [PATCH 80/86] extend git ignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index efeaa91b5..63004bab2 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ MANIFEST.bak xs/MANIFEST.bak xs/assertlib* .init_bundle.ini +.vs/* local-lib /src/TAGS /.vscode/ +build-linux/* +deps/build-linux/* From ca098d576313d0c20169d543ab1338e6150ddcac Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 25 Aug 2021 15:01:15 +0200 Subject: [PATCH 81/86] Fixed manipulation of sinking multipart objects resulting in wrong object/parts positioning --- src/libslic3r/Model.cpp | 11 ++++++++++- src/libslic3r/Model.hpp | 1 + src/slic3r/GUI/Selection.cpp | 22 +++++++++++++++++----- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 8eb5bb389..e32285106 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -959,7 +959,7 @@ void ModelObject::ensure_on_bed(bool allow_negative_z) double z_offset = 0.0; if (allow_negative_z) { - if (volumes.size() == 1) + if (parts_count() == 1) z_offset = -get_min_z(); else { const double max_z = get_max_z(); @@ -1127,6 +1127,15 @@ size_t ModelObject::facets_count() const return num; } +size_t ModelObject::parts_count() const +{ + size_t num = 0; + for (const ModelVolume* v : this->volumes) + if (v->is_model_part()) + ++num; + return num; +} + bool ModelObject::needed_repair() const { for (const ModelVolume *v : this->volumes) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 25f19e792..b89dd5aa1 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -347,6 +347,7 @@ public: size_t materials_count() const; size_t facets_count() const; + size_t parts_count() const; bool needed_repair() const; ModelObjectPtrs cut(size_t instance, coordf_t z, ModelObjectCutAttributes attributes); void split(ModelObjectPtrs* new_objects); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index ba4577bfb..3409c531d 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -2154,11 +2154,23 @@ void Selection::ensure_not_below_bed() } } - for (GLVolume* volume : *m_volumes) { - std::pair instance = std::make_pair(volume->object_idx(), volume->instance_idx()); - InstancesToZMap::iterator it = instances_max_z.find(instance); - if (it != instances_max_z.end() && it->second < SINKING_MIN_Z_THRESHOLD) - volume->set_instance_offset(Z, volume->get_instance_offset(Z) + SINKING_MIN_Z_THRESHOLD - it->second); + if (is_any_volume()) { + for (unsigned int i : m_list) { + GLVolume& volume = *(*m_volumes)[i]; + std::pair instance = std::make_pair(volume.object_idx(), volume.instance_idx()); + InstancesToZMap::iterator it = instances_max_z.find(instance); + double z_shift = SINKING_MIN_Z_THRESHOLD - it->second; + if (it != instances_max_z.end() && z_shift > 0.0) + volume.set_volume_offset(Z, volume.get_volume_offset(Z) + z_shift); + } + } + else { + for (GLVolume* volume : *m_volumes) { + std::pair instance = std::make_pair(volume->object_idx(), volume->instance_idx()); + InstancesToZMap::iterator it = instances_max_z.find(instance); + if (it != instances_max_z.end() && it->second < SINKING_MIN_Z_THRESHOLD) + volume->set_instance_offset(Z, volume->get_instance_offset(Z) + SINKING_MIN_Z_THRESHOLD - it->second); + } } } From e6bae065571c0d8c95ec7ba6100a50fb094f7f80 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 25 Aug 2021 15:07:30 +0200 Subject: [PATCH 82/86] Notice dialog when opening any link outside PrusaSlicer --- src/slic3r/GUI/AboutDialog.cpp | 4 ++-- src/slic3r/GUI/GUI_App.cpp | 19 ++++++++++++++++++- src/slic3r/GUI/GUI_App.hpp | 3 ++- src/slic3r/GUI/HintNotification.cpp | 3 +-- src/slic3r/GUI/MainFrame.cpp | 6 +++--- src/slic3r/GUI/NotificationManager.cpp | 2 +- 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index fdbc1a6d3..72f1421f6 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -195,7 +195,7 @@ void CopyrightsDialog::on_dpi_changed(const wxRect &suggested_rect) void CopyrightsDialog::onLinkClicked(wxHtmlLinkEvent &event) { - wxLaunchDefaultBrowser(event.GetLinkInfo().GetHref()); + wxGetApp().open_browser_with_warning_dialog(event.GetLinkInfo().GetHref()); event.Skip(false); } @@ -344,7 +344,7 @@ void AboutDialog::on_dpi_changed(const wxRect &suggested_rect) void AboutDialog::onLinkClicked(wxHtmlLinkEvent &event) { - wxLaunchDefaultBrowser(event.GetLinkInfo().GetHref()); + wxGetApp().open_browser_with_warning_dialog(event.GetLinkInfo().GetHref()); event.Skip(false); } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 58ce12ae4..102026a0c 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2327,7 +2327,7 @@ wxString GUI_App::current_language_code_safe() const void GUI_App::open_web_page_localized(const std::string &http_address) { - wxLaunchDefaultBrowser(http_address + "&lng=" + this->current_language_code_safe()); + open_browser_with_warning_dialog(http_address + "&lng=" + this->current_language_code_safe()); } bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage start_page) @@ -2525,6 +2525,23 @@ void GUI_App::check_updates(const bool verbose) } } +bool GUI_App::open_browser_with_warning_dialog(const wxString& url, int flags/* = 0*/) +{ + bool launch = true; + + if (get_app_config()->get("suppress_hyperlinks").empty()) { + wxRichMessageDialog dialog(nullptr, _L("Should we open this hyperlink in your default browser?"), _L("PrusaSlicer: Open hyperlink"), wxICON_QUESTION | wxYES_NO); + dialog.ShowCheckBox(_L("Remember my choice")); + int answer = dialog.ShowModal(); + launch = answer == wxID_YES; + get_app_config()->set("suppress_hyperlinks", dialog.IsCheckBoxChecked() ? (answer == wxID_NO ? "1" : "0") : ""); + } + if (launch) + launch = get_app_config()->get("suppress_hyperlinks") != "1"; + + return launch && wxLaunchDefaultBrowser(url, flags); +} + // static method accepting a wxWindow object as first parameter // void warning_catcher{ // my($self, $message_dialog) = @_; diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index a140247e0..1d8c2fcf7 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -261,7 +261,8 @@ public: void open_preferences(size_t open_on_tab = 0); virtual bool OnExceptionInMainLoop() override; - + // Calls wxLaunchDefaultBrowser if user confirms in dialog. + bool open_browser_with_warning_dialog(const wxString& url, int flags = 0); #ifdef __APPLE__ void OSXStoreOpenFiles(const wxArrayString &files) override; // wxWidgets override to get an event on open files. diff --git a/src/slic3r/GUI/HintNotification.cpp b/src/slic3r/GUI/HintNotification.cpp index 1d5931c48..ead7a8f29 100644 --- a/src/slic3r/GUI/HintNotification.cpp +++ b/src/slic3r/GUI/HintNotification.cpp @@ -236,8 +236,7 @@ bool tags_check(const std::string& disabled_tags, const std::string& enabled_tag } void launch_browser_if_allowed(const std::string& url) { - if (wxGetApp().app_config->get("suppress_hyperlinks") != "1") - wxLaunchDefaultBrowser(url); + wxGetApp().open_browser_with_warning_dialog(url); } } //namespace HintDatabase::~HintDatabase() diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 498b02605..329a9a62a 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1057,7 +1057,7 @@ static wxMenu* generate_help_menu() append_menu_item(helpMenu, wxID_ANY, _L("Prusa 3D &Drivers"), _L("Open the Prusa3D drivers download page in your browser"), [](wxCommandEvent&) { wxGetApp().open_web_page_localized("https://www.prusa3d.com/downloads"); }); append_menu_item(helpMenu, wxID_ANY, _L("Software &Releases"), _L("Open the software releases page in your browser"), - [](wxCommandEvent&) { wxLaunchDefaultBrowser("https://github.com/prusa3d/PrusaSlicer/releases"); }); + [](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases"); }); //# my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", "Check for new Slic3r versions", sub{ //# wxTheApp->check_version(1); //# }); @@ -1067,14 +1067,14 @@ static wxMenu* generate_help_menu() [](wxCommandEvent&) { wxGetApp().open_web_page_localized("https://www.prusa3d.com/slicerweb"); }); // append_menu_item(helpMenu, wxID_ANY, wxString::Format(_L("%s &Manual"), SLIC3R_APP_NAME), // wxString::Format(_L("Open the %s manual in your browser"), SLIC3R_APP_NAME), -// [this](wxCommandEvent&) { wxLaunchDefaultBrowser("http://manual.slic3r.org/"); }); +// [this](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("http://manual.slic3r.org/"); }); helpMenu->AppendSeparator(); append_menu_item(helpMenu, wxID_ANY, _L("System &Info"), _L("Show system information"), [](wxCommandEvent&) { wxGetApp().system_info(); }); append_menu_item(helpMenu, wxID_ANY, _L("Show &Configuration Folder"), _L("Show user configuration folder (datadir)"), [](wxCommandEvent&) { Slic3r::GUI::desktop_open_datadir_folder(); }); append_menu_item(helpMenu, wxID_ANY, _L("Report an I&ssue"), wxString::Format(_L("Report an issue on %s"), SLIC3R_APP_NAME), - [](wxCommandEvent&) { wxLaunchDefaultBrowser("https://github.com/prusa3d/slic3r/issues/new"); }); + [](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/slic3r/issues/new"); }); if (wxGetApp().is_editor()) append_menu_item(helpMenu, wxID_ANY, wxString::Format(_L("&About %s"), SLIC3R_APP_NAME), _L("Show about dialog"), [](wxCommandEvent&) { Slic3r::GUI::about(); }); diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 4c1c404da..3278a5a6e 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -42,7 +42,7 @@ const NotificationManager::NotificationData NotificationManager::basic_notificat } }, {NotificationType::NewAppAvailable, NotificationLevel::ImportantNotification, 20, _u8L("New version is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr) { - wxLaunchDefaultBrowser("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }}, + wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }}, {NotificationType::EmptyColorChangeCode, NotificationLevel::RegularNotification, 10, _u8L("You have just added a G-code for color change, but its value is empty.\n" "To export the G-code correctly, check the \"Color Change G-code\" in \"Printer Settings > Custom G-code\"") }, From 02dd1b5f7d5cca8a9aafde182409261dc06f5cc3 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 25 Aug 2021 16:31:23 +0200 Subject: [PATCH 83/86] rendering highlight arrow from svg --- resources/icons/toolbar_arrow.png | Bin 3996 -> 0 bytes resources/icons/toolbar_arrow.svg | 94 +++++----------------- src/slic3r/GUI/GLCanvas3D.cpp | 8 +- src/slic3r/GUI/GLToolbar.cpp | 24 +++--- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 5 +- 5 files changed, 36 insertions(+), 95 deletions(-) delete mode 100644 resources/icons/toolbar_arrow.png diff --git a/resources/icons/toolbar_arrow.png b/resources/icons/toolbar_arrow.png deleted file mode 100644 index a370442ff0e933b85d436f3abac584b2e5ac3f37..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3996 zcmeHK_cI&-)4qrn9EskEe$hM8+i6j94yQ&ZN{F5l5vPR^33Ac7aD;G3^p+e)ln}ig z=afW?UZcLg-@gCheP?#(+1+_|W@mqRb~e%6R3AviP6Yq}fQAOTkZTMF0B(>|l3zy{ zm4}npa3ct!uMNNqa;{w`q@G$PS^z*zD)qTD*>!#^z`!O50HE#sKfm$A|C8Hwku6vc z7Hr|~5gg_m=ne=A3zK;K#3#trIlx`QKhQI0OO^ea{nJoa3mWdYnRhF|u8ZwQSb^Az zda&S)G#G>=dPLhUUVDv9ycUht)FFw^Xo-c@-{p)0O*U?7uDvw`;AMbh@f`G&XmPbw zt&-qE9aJrixsz{yC?tCdnE^1gH-_W=58H=0m1@xM4-S5x0T(x;ZoWa!N1PqCHMFE5 zq#_Sx&5mG%P?15zhxb)uBGMva|5`PaBHDc&k8ez*#TGl&nI{{^bySIhiXtLnc07%y zC-yWWR^(xNw1EiA{auFii@6I(PYtXt40>5m8ncUAgXtt)Dcb28&>jS*z%b;YPeEOe z*GhVTFdZt0{*LCwY-4TUA*+4@ec#{=MV!^)IfajbCO9A}(knkF#q_6XQ*<<*p}PwXzHA>u1a6ACDonU{#b5_<{5XMZu<4WZ`;Jx z(h^cMuHk1Qctiw^6rY+1fBi zjs1Hlnh1@8&1al6ryC_h6ie7YmO7Q+FW=(K^?j8~nlsPc`W;@B*DJoBqXyosl*Y zFcRh9fO4To4qx@{Vj~o@pzE-x6qL;JDQ*15+$b?^6(mA?b%s3RY?ZaKD^J(1oZFCU zVV|VlY7v813zuG!cY#a?q%zE^OUz*TMI_=}98xXJ){4U$Rhi1P%b55@!f#~3;~}1K zZTSJNnCZGk+np2CjFPYVn!x1K2YvP1-@o`gtt3Llo`Y&zSe$}E>mzQi%Puq+-1`+` zu*I?go>@}+X|9DVNnZplAxjIr%o4LJF=rOQg<;5bWX|{YToyG?zAw*T9EgzL@Ij5r zm!XSzzWM}MG63Hc=hbY*Ev_zG<=g0l9!ZZse-8ARB;LcW!47PP&i#@tOgcPZFl#y*50p3YCwH0Ds4Z7BB zx8dlVJZQSC=T2@Tud0>dt^ngek9-^>NGz)Z(gzO@y7-&qFlnv3vz)kRipD);O(`s1 z$GJ$Kb2v(>=((N*B0V=-jA=Pjn<_FK0?MV~v~r~%oaDOBAc-3__DWPo>Fm$QYmZ9& zmAP#;xV}>LyQ3=*7RD>j?Li@mU<;AEzvFhcxqs>{d@K6QGUKhL2wEA-ywObYnu47V z$l4E{Cf#6r+2^{UqFRzu&J;Z%5vi^SuCCljt)67%*`ZCdF3IM5^c}|BCp5+1Fh`No znd?R=c)3oO@{KnAA&H+uLx)F7dh&v0Jxr}S_>Wemv8fH|k^zp)R0dq|MV8t~-iG6i z!h4G)NyJDF%sq*1WXYi@n@+Mfw|oxNM0AThf!%$t&i=rqb2#G34hGmfX(v}OS@$X z)XjF@mltL$n#?Ivd!(Sl;NU@meG-{hDcqLjR^dKv*50uEme*q`L-$%G4n&8@v$p0u zh+{2Yd*xx|QXiPwEXKz?n00FU%cQ{$B|`gNWkT5;EV;=8S%PsRD-K29s-b~4g_ZiL zwH2%uR!g`ibutlq%|FH!2i|9^+5H}*f&arDkU}&f8jNByz>`%_d zkn2lRfX?v3U5i{t-vHg*+0j|1gAOl4Bj+jGFITxP0Z?UWnn{qbs{}hg;*8^C!uPJS z-BQ7TN*IsVntY^iFJ<7kXjZPdr}nNxX*cV>+h98nq2=8IwI20EKRc|$ky_6+B9DA9 zs1jR`i(z%>tqng0qblOe<=`!hm?kqbc`&8}#;8Y);o_vr<9ViZJ@ImS{^y#%-Xyz& zESkM_tOF=qWiM>`b0$@Z2(}C+N4_$*FO|)=`R<5sdSv&}PmJ);M5K!ER#=*}>X3oP zm!=vCL=!I+v+C{F+yHGatburM*+YndTKK#`bcLT;S` zg1rV_7!Buy-|+BkG=3T+sL#vXS@E8uUT4MN(GQ_Kc3I6w%N7jrtr}fQ-e7Uq@s@9Y z5f6c7Joqo|--}=W6a`Ai9CIkq!0j1!4~~MlEw7gmlT_)V_7Zko@5ux7s_vX!T#qfJeTA_Qr`6g_IQ8TE)r#Y~hYw zy4+Epwro!TCRKjQS~f?vZTIf{Np*u^;p9#!&{Un_zYjt{TeP*IYa6Q<NcO!uj)j5QMu3gu)-?NqKv+nkp6bI@=5(`%IfE%YPXe^o$D3r^aaI~XCo z9NN42D^fC@L?7eT$HgU+^#@ds=Zl2-U~BD!xWdlWLS?0f^FEeszC*o!wD$b#UuC-i zHsueh{GNHu4#Rz`4C&=Vw^T1)yLudHz4+K99&)v!c0F0&{eB39Gi8`GrruAy z;%Ixek`#4>!y9Gid12-{?o=d4TINE%Z9cVGNSgI9YF5{st&DhiTE_)5_<7tbhNdn$ zu$NFiAEj5sqCCCb)~u-6V;iIx-!N8rc0W;UgU`K4%=g-QINfE$YLmSyZVcNCW2O2X zsUpn$6W0D%)T6{8n5Wwnq_$GlNFfVR_qk<9xY?yuTEg4@S%nhjL4%^u6%jGPjLZ^YIMLs*r;LnkX-Y-tn2a zSPf{{`^yUHHyOf1WkHg*1ydK1iF!^Z^9uM$dcA;Wg0>`VSI^ZL$u=_SQ5s9c54i7=H=JT-0BQ2IlWpN}{F8m)dh!-wVU|X;ab~K3G&TNQITJ-qEkyf2`)}I- z8`j8HS&TU*#ZKn!9s8vk2uv(q;7PA0cqc}e}5b~E!C+u%q znU@S$Ax1BLOpff|^MHIeHKwaG4~L+7LX46&7JzTC>#2)es0!+v*QZ=6J*Jq*MI)B? z>}^F^o32QR46c(Xf6I}hI89OqU)Rl&+h(g!)xUm)6w*GY>-ooGU>LoCzkYrJhI*#D z7;Ps+6=7j~FS^c&1a3MjoIcZN)f7O|jt_g$#yOV-zq{hGqIm2NpZ&ZT54ob~>jBv( LTMD)O|Nj2~#I)V2 diff --git a/resources/icons/toolbar_arrow.svg b/resources/icons/toolbar_arrow.svg index 998646a24..b49645190 100644 --- a/resources/icons/toolbar_arrow.svg +++ b/resources/icons/toolbar_arrow.svg @@ -1,76 +1,22 @@ - -image/svg+xml - \ No newline at end of file diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 227e5ae4e..1dd9f1d23 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4438,13 +4438,7 @@ bool GLCanvas3D::_init_main_toolbar() } // init arrow BackgroundTexture::Metadata arrow_data; - arrow_data.filename = "toolbar_arrow.png"; -// arrow_data.filename = "toolbar_arrow.svg"; - //arrow_data.left = 16; - //arrow_data.top = 16; - //arrow_data.right = 16; - //arrow_data.bottom = 16; - + arrow_data.filename = "toolbar_arrow.svg"; arrow_data.left = 0; arrow_data.top = 0; arrow_data.right = 0; diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 243031847..515b6ed3a 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -193,10 +193,9 @@ bool GLToolbar::init_arrow(const BackgroundTexture::Metadata& arrow_texture) std::string path = resources_dir() + "/icons/"; bool res = false; - if (!arrow_texture.filename.empty()) - res = m_arrow_texture.texture.load_from_file(path + arrow_texture.filename, false, GLTexture::SingleThreaded, false); -// res = m_arrow_texture.texture.load_from_svg_file(path + arrow_texture.filename, false, true, false, 100); - + if (!arrow_texture.filename.empty()) { + res = m_arrow_texture.texture.load_from_svg_file(path + arrow_texture.filename, false, false, false, 1000); + } if (res) m_arrow_texture.metadata = arrow_texture; @@ -1176,19 +1175,22 @@ void GLToolbar::render_arrow(const GLCanvas3D& parent, GLToolbarItem* highlighte float right = left + scaled_icons_size; unsigned int tex_id = m_arrow_texture.texture.get_id(); + // width and height of icon arrow is pointing to float tex_width = (float)m_icons_texture.get_width(); float tex_height = (float)m_icons_texture.get_height(); + // arrow width and height + float arr_tex_width = (float)m_arrow_texture.texture.get_width(); + float arr_tex_height = (float)m_arrow_texture.texture.get_height(); + if ((tex_id != 0) && (arr_tex_width > 0) && (arr_tex_height > 0)) { + float inv_tex_width = (arr_tex_width != 0.0f) ? 1.0f / arr_tex_width : 0.0f; + float inv_tex_height = (arr_tex_height != 0.0f) ? 1.0f / arr_tex_height : 0.0f; - if ((tex_id != 0) && (tex_width > 0) && (tex_height > 0)) { - float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f; - float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f; - - float internal_left = left + border - scaled_icons_size / 2; // add half scaled_icons_size for huge arrow - float internal_right = right - border + scaled_icons_size / 2; + float internal_left = left + border - scaled_icons_size * 1.5f; // add scaled_icons_size for huge arrow + float internal_right = right - border + scaled_icons_size * 1.5f; float internal_top = top - border; // bottom is not moving and should be calculated from arrow texture sides ratio float arrow_sides_ratio = (float)m_arrow_texture.texture.get_height() / (float)m_arrow_texture.texture.get_width(); - float internal_bottom = internal_top - (internal_right - internal_left) * arrow_sides_ratio; + float internal_bottom = internal_top - (internal_right - internal_left) * arrow_sides_ratio ; float internal_left_uv = (float)m_arrow_texture.metadata.left * inv_tex_width; float internal_right_uv = 1.0f - (float)m_arrow_texture.metadata.right * inv_tex_width; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 5617b5ed8..6d9a03977 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -132,8 +132,7 @@ bool GLGizmosManager::init_arrow(const BackgroundTexture::Metadata& arrow_textur bool res = false; if (!arrow_texture.filename.empty()) - res = m_arrow_texture.texture.load_from_file(path + arrow_texture.filename, false, GLTexture::SingleThreaded, false); -// res = m_arrow_texture.texture.load_from_svg_file(path + arrow_texture.filename, false, true, false, 100); + res = m_arrow_texture.texture.load_from_svg_file(path + arrow_texture.filename, false, false, false, 1000); if (res) m_arrow_texture.metadata = arrow_texture; @@ -1019,7 +1018,7 @@ void GLGizmosManager::render_arrow(const GLCanvas3D& parent, EType highlighted_t float arrow_sides_ratio = (float)m_arrow_texture.texture.get_height() / (float)m_arrow_texture.texture.get_width(); - GLTexture::render_sub_texture(tex_id, zoomed_top_x + zoomed_icons_size * 1.2f, zoomed_top_x + zoomed_icons_size * 1.2f + zoomed_icons_size * arrow_sides_ratio, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { internal_left_uv, internal_bottom_uv }, { internal_left_uv, internal_top_uv }, { internal_right_uv, internal_top_uv }, { internal_right_uv, internal_bottom_uv } }); + GLTexture::render_sub_texture(tex_id, zoomed_top_x + zoomed_icons_size * 1.2f, zoomed_top_x + zoomed_icons_size * 1.2f + zoomed_icons_size * 2.2f * arrow_sides_ratio, zoomed_top_y - zoomed_icons_size * 1.6f , zoomed_top_y + zoomed_icons_size * 0.6f, { { internal_left_uv, internal_bottom_uv }, { internal_left_uv, internal_top_uv }, { internal_right_uv, internal_top_uv }, { internal_right_uv, internal_bottom_uv } }); break; } zoomed_top_y -= zoomed_stride_y; From 673a2bdac8e9874f3fbec15d2568b5cf69018c45 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 25 Aug 2021 18:25:37 +0200 Subject: [PATCH 84/86] Fix: ../src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp:109:23: warning: comparison of integer expressions of different signedness: 'std::basic_string::size_type' {aka 'long unsigned int'} and 'int' [-Wsign-compare] ../src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp:132:17: warning: format string is not a string literal (potentially insecure) [-Wformat-security] ../src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp:171:17: warning: format string is not a string literal (potentially insecure) [-Wformat-security] Severity Code Description Project File Line Suppression State Warning C26451 Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator '-' to avoid overflow (io.2). libslic3r_gui C:\GIT\slic3r\src\slic3r\GUI\Gizmos\GLGizmoSimplify.cpp 143 --- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 22 +++++++++++----------- src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 3530b4240..5ce0064db 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -129,7 +129,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi } ImGui::SameLine(); m_imgui->disabled_begin(m_configuration.use_count); - ImGui::Text(tr_detail_level.c_str()); + ImGui::Text("%s", tr_detail_level.c_str()); std::vector reduce_captions = { static_cast(_u8L("Extra high")), static_cast(_u8L("High")), @@ -139,17 +139,17 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi }; ImGui::SameLine(m_gui_cfg->bottom_left_width); ImGui::SetNextItemWidth(m_gui_cfg->input_width); - static int reduction = 3; - if(ImGui::SliderInt("##ReductionLevel", &reduction, 1, 5, reduce_captions[reduction-1].c_str())) { + static int reduction = 2; + if(ImGui::SliderInt("##ReductionLevel", &reduction, 0, 4, reduce_captions[reduction].c_str())) { m_is_valid_result = false; - if (reduction < 1) reduction = 1; - if (reduction > 5) reduction = 5; + if (reduction < 0) reduction = 0; + if (reduction > 4) reduction = 4; switch (reduction) { - case 1: m_configuration.max_error = 1e-3f; break; - case 2: m_configuration.max_error = 1e-2f; break; - case 3: m_configuration.max_error = 0.1f; break; - case 4: m_configuration.max_error = 0.5f; break; - case 5: m_configuration.max_error = 1.f; break; + case 0: m_configuration.max_error = 1e-3f; break; + case 1: m_configuration.max_error = 1e-2f; break; + case 2: m_configuration.max_error = 0.1f; break; + case 3: m_configuration.max_error = 0.5f; break; + case 4: m_configuration.max_error = 1.f; break; } } m_imgui->disabled_end(); // !use_count @@ -168,7 +168,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi } m_imgui->disabled_begin(!m_configuration.use_count); - ImGui::Text(tr_decimate_ratio.c_str()); + ImGui::Text("%s", tr_decimate_ratio.c_str()); ImGui::SameLine(m_gui_cfg->bottom_left_width); ImGui::SetNextItemWidth(m_gui_cfg->input_width); const char * format = (m_configuration.decimate_ratio > 10)? "%.0f %%": diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index 9af6686bd..04d4b99ab 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -87,7 +87,7 @@ private: int window_padding = 0; // trunc model name when longer - int max_char_in_name = 30; + size_t max_char_in_name = 30; }; std::optional m_gui_cfg; From 08b91d33e9eb49c3412095e5877be715be0e6845 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 26 Aug 2021 08:06:37 +0200 Subject: [PATCH 85/86] Fixed update of objects list in sidebar after deleting a part from a sinking object --- src/slic3r/GUI/GUI_ObjectList.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 23ce819dd..39676e2d7 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2730,8 +2730,9 @@ void ObjectList::delete_from_model_and_list(const std::vector& it return; m_prevent_list_events = true; - for (std::vector::const_reverse_iterator item = items_for_delete.rbegin(); item != items_for_delete.rend(); ++item) - { + + std::set modified_objects_ids; + for (std::vector::const_reverse_iterator item = items_for_delete.rbegin(); item != items_for_delete.rend(); ++item) { if (!(item->type&(itObject | itVolume | itInstance))) continue; if (item->type&itObject) { @@ -2741,8 +2742,7 @@ void ObjectList::delete_from_model_and_list(const std::vector& it else { if (!del_subobject_from_object(item->obj_idx, item->sub_obj_idx, item->type)) continue; - if (item->type&itVolume) - { + if (item->type&itVolume) { m_objects_model->Delete(m_objects_model->GetItemByVolumeId(item->obj_idx, item->sub_obj_idx)); ModelObject* obj = object(item->obj_idx); if (obj->volumes.size() == 1) { @@ -2760,7 +2760,14 @@ void ObjectList::delete_from_model_and_list(const std::vector& it else m_objects_model->Delete(m_objects_model->GetItemByInstanceId(item->obj_idx, item->sub_obj_idx)); } + + modified_objects_ids.insert(static_cast(item->obj_idx)); } + + for (size_t id : modified_objects_ids) { + update_info_items(id); + } + m_prevent_list_events = true; part_selection_changed(); } From 67bc29299ae023578473eea43f0ea846be165940 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 26 Aug 2021 08:34:43 +0200 Subject: [PATCH 86/86] Fixed sinking object popping up on bed when adding a modifier --- src/libslic3r/Model.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index e32285106..6654d3a13 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -959,8 +959,12 @@ void ModelObject::ensure_on_bed(bool allow_negative_z) double z_offset = 0.0; if (allow_negative_z) { - if (parts_count() == 1) - z_offset = -get_min_z(); + if (parts_count() == 1) { + const double min_z = get_min_z(); + const double max_z = get_max_z(); + if (min_z >= SINKING_Z_THRESHOLD || max_z < 0.0) + z_offset = -min_z; + } else { const double max_z = get_max_z(); if (max_z < SINKING_MIN_Z_THRESHOLD)