From 5fe90599fcbba6e4160677b0abbe4e88ba792e3e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 31 Aug 2021 13:58:20 +0200 Subject: [PATCH 1/2] Painting gizmos no longer use a separate undo/redo stack --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 2 -- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 36 -------------------- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 2 +- 3 files changed, 1 insertion(+), 39 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 01eeebe10..ea164ed2f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -298,8 +298,6 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block) } } - activate_internal_undo_redo_stack(true); - Plater::TakeSnapshot snapshot(wxGetApp().plater(), block ? _L("Block supports by angle") : _L("Add supports by angle")); update_model_object(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index be8fc331d..09dad81aa 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -26,35 +26,6 @@ GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& ic m_vbo_sphere.finalize_geometry(true); } -// port of 948bc382655993721d93d3b9fce9b0186fcfb211 -void GLGizmoPainterBase::activate_internal_undo_redo_stack(bool activate) -{ - Plater* plater = wxGetApp().plater(); - - // Following is needed to prevent taking an extra snapshot when the activation of - // the internal stack happens when the gizmo is already active (such as open gizmo, - // close gizmo, undo, start painting). The internal stack does not activate on the - // undo, because that would obliterate all future of the main stack (user would - // have to close the gizmo himself, he has no access to main undo/redo after the - // internal stack opens). We don't want the "entering" snapshot taken in this case, - // because there already is one. - std::string last_snapshot_name; - plater->undo_redo_topmost_string_getter(plater->can_undo(), last_snapshot_name); - - if (activate && !m_internal_stack_active) { - if (std::string str = this->get_gizmo_entering_text(); last_snapshot_name != str) - Plater::TakeSnapshot(plater, str, UndoRedo::SnapshotType::EnteringGizmo); - plater->enter_gizmos_stack(); - m_internal_stack_active = true; - } - if (!activate && m_internal_stack_active) { - plater->leave_gizmos_stack(); - if (std::string str = this->get_gizmo_leaving_text(); last_snapshot_name != str) - Plater::TakeSnapshot(plater, str, UndoRedo::SnapshotType::LeavingGizmoWithAction); - m_internal_stack_active = false; - } -} - void GLGizmoPainterBase::set_painter_gizmo_data(const Selection& selection) { if (m_state != On) @@ -450,7 +421,6 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous && m_button_down != Button::None) { // Take snapshot and update ModelVolume data. wxString action_name = this->handle_snapshot_action_name(shift_down, m_button_down); - activate_internal_undo_redo_stack(true); Plater::TakeSnapshot snapshot(wxGetApp().plater(), action_name); update_model_object(); @@ -548,16 +518,10 @@ void GLGizmoPainterBase::on_set_state() if (m_state == On && m_old_state != On) { // the gizmo was just turned on on_opening(); - if (! m_parent.get_gizmos_manager().is_serializing()) { - wxGetApp().CallAfter([this]() { - activate_internal_undo_redo_stack(true); - }); - } } if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off // we are actually shutting down on_shutdown(); - activate_internal_undo_redo_stack(false); m_old_mo_id = -1; //m_iva.release_geometry(); m_triangle_selectors.clear(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 6a15ab2a5..016f604c3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -88,7 +88,6 @@ protected: void render_cursor_sphere(const Transform3d& trafo) const; virtual void update_model_object() const = 0; virtual void update_from_model_object() = 0; - void activate_internal_undo_redo_stack(bool activate); virtual std::array get_cursor_sphere_left_button_color() const { return {0.f, 0.f, 1.f, 0.25f}; } virtual std::array get_cursor_sphere_right_button_color() const { return {1.f, 0.f, 0.f, 0.25f}; } @@ -170,6 +169,7 @@ protected: void on_load(cereal::BinaryInputArchive& ar) override; void on_save(cereal::BinaryOutputArchive& ar) const override {} CommonGizmosDataID on_get_requirements() const override; + bool wants_enter_leave_snapshots() const override { return true; } virtual wxString handle_snapshot_action_name(bool shift_down, Button button_down) const = 0; From b76f66d2d23f3e6e0c6fc6eaab875082a6d52a46 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 30 Sep 2021 12:18:36 +0200 Subject: [PATCH 2/2] Follow-up to 3ee259b602947b10f1b225124c67c4b750a3c391 1) Added parsing of 3MF PrusaSlicer generator semantic version 2) For 3MFs generated by >= "2.4.0-alpha1" and < "2.4.0-alpha3", remove unreferenced vertices on loading. This should shrink the incorrectly generated 3MFs back. 3) Added check for an empty mesh, which could have crashed PrusaSlicer on 3MF parsing. --- src/libslic3r/Format/3mf.cpp | 73 +++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 1ca20bcba..eca057a5b 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -6,6 +6,7 @@ #include "../GCode.hpp" #include "../Geometry.hpp" #include "../GCode/ThumbnailData.hpp" +#include "../Semver.hpp" #include "../Time.hpp" #include "../I18N.hpp" @@ -411,6 +412,8 @@ namespace Slic3r { unsigned int m_version; bool m_check_version; + // Semantic version of PrusaSlicer, that generated this 3MF. + boost::optional m_prusaslicer_generator_version; unsigned int m_fdm_supports_painting_version = 0; unsigned int m_seam_painting_version = 0; unsigned int m_mm_painting_version = 0; @@ -1712,21 +1715,20 @@ namespace Slic3r { const std::string msg = (boost::format(_(L("The selected 3mf file has been saved with a newer version of %1% and is not compatible."))) % std::string(SLIC3R_APP_NAME)).str(); throw version_error(msg); } - } - - if (m_curr_metadata_name == SLIC3RPE_FDM_SUPPORTS_PAINTING_VERSION) { + } else if (m_curr_metadata_name == "Application") { + // Generator application of the 3MF. + // SLIC3R_APP_KEY - SLIC3R_VERSION + if (boost::starts_with(m_curr_characters, "PrusaSlicer-")) + m_prusaslicer_generator_version = Semver::parse(m_curr_characters.substr(12)); + } else if (m_curr_metadata_name == SLIC3RPE_FDM_SUPPORTS_PAINTING_VERSION) { m_fdm_supports_painting_version = (unsigned int) atoi(m_curr_characters.c_str()); check_painting_version(m_fdm_supports_painting_version, FDM_SUPPORTS_PAINTING_VERSION, _(L("The selected 3MF contains FDM supports painted object using a newer version of PrusaSlicer and is not compatible."))); - } - - if (m_curr_metadata_name == SLIC3RPE_SEAM_PAINTING_VERSION) { + } else if (m_curr_metadata_name == SLIC3RPE_SEAM_PAINTING_VERSION) { m_seam_painting_version = (unsigned int) atoi(m_curr_characters.c_str()); check_painting_version(m_seam_painting_version, SEAM_PAINTING_VERSION, _(L("The selected 3MF contains seam painted object using a newer version of PrusaSlicer and is not compatible."))); - } - - if (m_curr_metadata_name == SLIC3RPE_MM_PAINTING_VERSION) { + } else if (m_curr_metadata_name == SLIC3RPE_MM_PAINTING_VERSION) { m_mm_painting_version = (unsigned int) atoi(m_curr_characters.c_str()); check_painting_version(m_mm_painting_version, MM_PAINTING_VERSION, _(L("The selected 3MF contains multi-material painted object using a newer version of PrusaSlicer and is not compatible."))); @@ -1890,7 +1892,6 @@ namespace Slic3r { unsigned int geo_tri_count = (unsigned int)geometry.triangles.size(); unsigned int renamed_volumes_count = 0; - int processed_vertices_max_id = 0; for (const ObjectMetadata::VolumeMetadata& volume_data : volumes) { if (geo_tri_count <= volume_data.first_triangle_id || geo_tri_count <= volume_data.last_triangle_id || volume_data.last_triangle_id < volume_data.first_triangle_id) { @@ -1910,33 +1911,43 @@ namespace Slic3r { } // splits volume out of imported geometry - std::vector faces(geometry.triangles.begin() + volume_data.first_triangle_id, geometry.triangles.begin() + volume_data.last_triangle_id + 1); - const size_t triangles_count = faces.size(); + indexed_triangle_set its; + its.indices.assign(geometry.triangles.begin() + volume_data.first_triangle_id, geometry.triangles.begin() + volume_data.last_triangle_id + 1); + const size_t triangles_count = its.indices.size(); + if (triangles_count == 0) { + add_error("An empty triangle mesh found"); + return false; + } - int min_id = faces.front()[0]; - int max_id = faces.front()[0]; - for (const Vec3i& face : faces) { - for (const int tri_id : face) { - if (tri_id < 0 || tri_id >= int(geometry.vertices.size())) { - add_error("Found invalid vertex id"); - return false; + { + int min_id = its.indices.front()[0]; + int max_id = min_id; + for (const Vec3i& face : its.indices) { + for (const int tri_id : face) { + if (tri_id < 0 || tri_id >= int(geometry.vertices.size())) { + add_error("Found invalid vertex id"); + return false; + } + min_id = std::min(min_id, tri_id); + max_id = std::max(max_id, tri_id); } - min_id = std::min(min_id, tri_id); - max_id = std::max(max_id, tri_id); } + its.vertices.assign(geometry.vertices.begin() + min_id, geometry.vertices.begin() + max_id + 1); + + // rebase indices to the current vertices list + for (Vec3i& face : its.indices) + for (int& tri_id : face) + tri_id -= min_id; } - // rebase indices to the current vertices list - for (Vec3i& face : faces) { - for (int& tri_id : face) { - tri_id -= min_id; - } - } + if (m_prusaslicer_generator_version && + *m_prusaslicer_generator_version >= *Semver::parse("2.4.0-alpha1") && + *m_prusaslicer_generator_version < *Semver::parse("2.4.0-alpha3")) + // PrusaSlicer 2.4.0-alpha2 contained a bug, where all vertices of a single object were saved for each volume the object contained. + // Remove the vertices, that are not referenced by any face. + its_compactify_vertices(its, true); - processed_vertices_max_id = 1 + std::max(processed_vertices_max_id, max_id); - - std::vector vertices(geometry.vertices.begin() + min_id, geometry.vertices.begin() + max_id + 1); - TriangleMesh triangle_mesh(std::move(vertices), std::move(faces)); + TriangleMesh triangle_mesh(std::move(its)); if (m_version == 0) { // if the 3mf was not produced by PrusaSlicer and there is only one instance,