From 5ae2f8a467ccd41f0debd675ee38eee1edea6c62 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 29 Jan 2020 10:07:10 +0100 Subject: [PATCH 01/27] Function sla_trafo made accessible from outside SLAPrint.cpp unit --- src/libslic3r/SLAPrint.cpp | 8 ++++---- src/libslic3r/SLAPrint.hpp | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 4c10a44fae..23b4a8046e 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -122,10 +122,10 @@ void SLAPrint::clear() } // Transformation without rotation around Z and without a shift by X and Y. -static Transform3d sla_trafo(const SLAPrint& p, const ModelObject &model_object) +Transform3d SLAPrint::sla_trafo(const ModelObject &model_object) const { - Vec3d corr = p.relative_correction(); + Vec3d corr = this->relative_correction(); ModelInstance &model_instance = *model_object.instances.front(); Vec3d offset = model_instance.get_offset(); @@ -376,7 +376,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con bool sla_trafo_differs = model_object.instances.empty() != model_object_new.instances.empty() || (! model_object.instances.empty() && - (! sla_trafo(*this, model_object).isApprox(sla_trafo(*this, model_object_new)) || + (! sla_trafo(model_object).isApprox(sla_trafo(model_object_new)) || model_object.instances.front()->is_left_handed() != model_object_new.instances.front()->is_left_handed())); if (model_parts_differ || sla_trafo_differs) { // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects. @@ -453,7 +453,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con // FIXME: this invalidates the transformed mesh in SLAPrintObject // which is expensive to calculate (especially the raw_mesh() call) - print_object->set_trafo(sla_trafo(*this, model_object), model_object.instances.front()->is_left_handed()); + print_object->set_trafo(sla_trafo(model_object), model_object.instances.front()->is_left_handed()); print_object->set_instances(std::move(new_instances)); diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 771ca0bcd6..871fb3de43 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -421,6 +421,9 @@ public: // Extracted value from the configuration objects Vec3d relative_correction() const; + // Return sla tansformation for a given model_object + Transform3d sla_trafo(const ModelObject &model_object) const; + std::string output_filename(const std::string &filename_base = std::string()) const override; const SLAPrintStatistics& print_statistics() const { return m_print_statistics; } From 76927ce3995c94b28d45b07c32926c867134453d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 29 Jan 2020 10:07:59 +0100 Subject: [PATCH 02/27] REVERT LATER: TEMPORARILY MANGLED reload_scene FUNCTION This commit horribly cripples reload_scene function just to update volumes in scene so that Hollowing and SLASupport gizmos can be updated to the new logic It should be later reverted and the same be achieved in a better way --- src/slic3r/GUI/GLCanvas3D.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8805dc92c8..32d359429b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1930,6 +1930,8 @@ void GLCanvas3D::mirror_selection(Axis axis) // 5) Out of bed collision status & message overlay (texture) void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_refresh) { + force_full_scene_refresh = true; + if ((m_canvas == nullptr) || (m_config == nullptr) || (m_model == nullptr)) return; @@ -2189,9 +2191,28 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed - for (GLVolume* volume : m_volumes.volumes) + for (GLVolume* volume : m_volumes.volumes) { if (volume->object_idx() < (int)m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable()) volume->set_sla_shift_z(shift_zs[volume->object_idx()]); + + // Just an experiment for now - replace the mesh with a hollowed one. + for (size_t po_idx=0; po_idxobjects().size(); ++po_idx) { + const SLAPrintObject* po = sla_print->objects()[po_idx]; + if (po_idx != volume->composite_id.object_id || volume->composite_id.volume_id < 0) + continue; + if (po->is_step_done(slaposHollowing)) { + TriangleMesh mesh = po->get_mesh(slaposHollowing); + if (mesh.empty()) + continue; + Transform3d t = sla_print->sla_trafo(*m_model->objects[volume->object_idx()]); + mesh.transform(t.inverse()); + GLIndexedVertexArray iva; + iva.load_mesh(mesh); + volume->indexed_vertex_array = iva; + volume->finalize_geometry(true); + } + } + } } if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) From 46fdce116922368613ff01786fc21f0c650ef1f1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 28 Jan 2020 10:20:37 +0100 Subject: [PATCH 03/27] SLA gizmos can now fetch hollowed and drilled mesh from the backend --- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 51 +++++++++++ src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 12 ++- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 96 ++++++-------------- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 2 - src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 20 ++-- 5 files changed, 99 insertions(+), 82 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 7dce249f28..bde54a0d21 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -4,6 +4,9 @@ #include #include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/GLCanvas3D.hpp" +#include "libslic3r/SLAPrint.hpp" +#include "slic3r/GUI/MeshUtils.hpp" @@ -302,5 +305,53 @@ unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char gr return b; } + + +bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas) +{ + if (! m_model_object) + return false; + + int old_po_idx = m_print_object_idx; + + // First we need a pointer to the respective SLAPrintObject. The index into objects vector is + // cached so we don't have todo it on each render. We only search for the po if needed: + if (m_print_object_idx < 0 || (int)canvas.sla_print()->objects().size() != m_print_objects_count) { + m_print_objects_count = canvas.sla_print()->objects().size(); + m_print_object_idx = -1; + for (const SLAPrintObject* po : canvas.sla_print()->objects()) { + ++m_print_object_idx; + if (po->model_object()->id() == m_model_object->id()) + break; + } + } + + if (m_print_object_idx < 0) + return old_po_idx != m_print_object_idx; + + m_mesh = nullptr; + // Load either the model_object mesh, or one provided by the backend + // This mesh does not account for the possible Z up SLA offset. + const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx]; + + if (po->is_step_done(slaposHollowing)) + m_mesh = &po->get_mesh_to_print(); + else + m_mesh = &m_model_object->volumes.front()->mesh(); + + m_model_object_id = m_model_object->id(); + + if (m_mesh != m_old_mesh) { + m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh)); + m_object_clipper.reset(); + m_supports_clipper.reset(); + m_old_mesh = m_mesh; + return true; + } + return false; +} + + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 9479174fbd..0ff00a1697 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -31,6 +31,7 @@ static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; class ImGuiWrapper; class CommonGizmosData; +class GLCanvas3D; class GLGizmoBase { @@ -189,9 +190,11 @@ class MeshClipper; class CommonGizmosData { public: const TriangleMesh* mesh() const { - return (! m_mesh ? nullptr : (m_cavity_mesh ? m_cavity_mesh.get() : m_mesh)); + return (! m_mesh ? nullptr : m_mesh); //(m_cavity_mesh ? m_cavity_mesh.get() : m_mesh)); } + bool update_from_backend(GLCanvas3D& canvas); + ModelObject* m_model_object = nullptr; @@ -200,8 +203,8 @@ public: std::unique_ptr m_object_clipper; std::unique_ptr m_supports_clipper; - std::unique_ptr m_cavity_mesh; - std::unique_ptr m_volume_with_cavity; + //std::unique_ptr m_cavity_mesh; + //std::unique_ptr m_volume_with_cavity; int m_active_instance = -1; float m_active_instance_bb_radius = 0; @@ -209,6 +212,9 @@ public: int m_print_object_idx = -1; int m_print_objects_count = -1; int m_old_timestamp = -1; + +private: + const TriangleMesh* m_old_mesh; }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 0422982745..51bc1b34f4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -69,24 +69,24 @@ void GLGizmoHollow::set_sla_support_data(ModelObject* model_object, const Select || m_c->m_active_instance != selection.get_instance_idx()) { m_c->m_model_object = model_object; m_c->m_print_object_idx = -1; + m_c->m_mesh_raycaster.reset(); m_c->m_active_instance = selection.get_instance_idx(); something_changed = true; } - if (model_object && something_changed && selection.is_from_single_instance()) + if (model_object + && selection.is_from_single_instance() + && (m_c->update_from_backend(m_parent) || something_changed)) { // Cache the bb - it's needed for dealing with the clipping plane quite often // It could be done inside update_mesh but one has to account for scaling of the instance. m_c->m_active_instance_bb_radius = m_c->m_model_object->instance_bounding_box(m_c->m_active_instance).radius(); - if (is_mesh_update_necessary()) { - update_mesh(); - reload_cache(); - } + reload_cache(); if (m_state == On) { m_parent.toggle_model_objects_visibility(false); - m_parent.toggle_model_objects_visibility(! m_c->m_cavity_mesh, m_c->m_model_object, m_c->m_active_instance); + m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance); } else @@ -109,8 +109,8 @@ void GLGizmoHollow::on_render() const return; } - if (! m_c->m_mesh) - const_cast(this)->update_mesh(); + // !!! is it necessary? + const_cast(this)->m_c->update_from_backend(m_parent); glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); @@ -132,7 +132,7 @@ void GLGizmoHollow::on_render() const void GLGizmoHollow::render_hollowed_mesh() const { - if (m_c->m_volume_with_cavity) { + /*if (m_c->m_volume_with_cavity) { m_c->m_volume_with_cavity->set_sla_shift_z(m_z_shift); m_parent.get_shader().start_using(); @@ -148,14 +148,13 @@ void GLGizmoHollow::render_hollowed_mesh() const m_c->m_volume_with_cavity->set_instance_transformation(m_c->m_model_object->instances[size_t(m_c->m_active_instance)]->get_transformation()); m_c->m_volume_with_cavity->render(color_id, print_box_detection_id, print_box_worldmatrix_id); m_parent.get_shader().stop_using(); - } + }*/ } - void GLGizmoHollow::render_clipping_plane(const Selection& selection) const { - if (m_clipping_plane_distance == 0.f || m_c->mesh()->empty()) + if (m_clipping_plane_distance == 0.f) return; // Get transformation of the instance @@ -182,17 +181,9 @@ void GLGizmoHollow::render_clipping_plane(const Selection& selection) const // Next, ask the backend if supports are already calculated. If so, we are gonna cut them too. - // First we need a pointer to the respective SLAPrintObject. The index into objects vector is - // cached so we don't have todo it on each render. We only search for the po if needed: - if (m_c->m_print_object_idx < 0 || (int)m_parent.sla_print()->objects().size() != m_c->m_print_objects_count) { - m_c->m_print_objects_count = m_parent.sla_print()->objects().size(); - m_c->m_print_object_idx = -1; - for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { - ++m_c->m_print_object_idx; - if (po->model_object()->id() == m_c->m_model_object->id()) - break; - } - } + if (m_c->m_print_object_idx < 0) + m_c->update_from_backend(m_parent); + if (m_c->m_print_object_idx >= 0) { const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_c->m_print_object_idx]; @@ -355,47 +346,13 @@ bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const -bool GLGizmoHollow::is_mesh_update_necessary() const -{ - return ((m_state == On) && (m_c->m_model_object != nullptr) && !m_c->m_model_object->instances.empty()) - && ((m_c->m_model_object->id() != m_c->m_model_object_id) || ! m_c->m_mesh); -} - - - -void GLGizmoHollow::update_mesh() -{ - if (! m_c->m_model_object) - return; - - wxBusyCursor wait; - // this way we can use that mesh directly. - // This mesh does not account for the possible Z up SLA offset. - m_c->m_mesh = &m_c->m_model_object->volumes.front()->mesh(); - - // If this is different mesh than last time - if (m_c->m_model_object_id != m_c->m_model_object->id()) { - m_c->m_cavity_mesh.reset(); // dump the cavity - m_c->m_volume_with_cavity.reset(); - m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); - m_c->m_mesh_raycaster.reset(); - } - - if (! m_c->m_mesh_raycaster) - m_c->m_mesh_raycaster.reset(new MeshRaycaster(*m_c->mesh())); - - m_c->m_model_object_id = m_c->m_model_object->id(); -} - - - // Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal // Return false if no intersection was found, true otherwise. bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) { // if the gizmo doesn't have the V, F structures for igl, calculate them first: - if (! m_c->m_mesh_raycaster) - update_mesh(); + // !!! is it really necessary? + m_c->update_from_backend(m_parent); const Camera& camera = m_parent.get_camera(); const Selection& selection = m_parent.get_selection(); @@ -605,7 +562,7 @@ void GLGizmoHollow::update_mesh_raycaster(std::unique_ptr &&rc) { m_c->m_mesh_raycaster = std::move(rc); m_c->m_object_clipper.reset(); - m_c->m_volume_with_cavity.reset(); + //m_c->m_volume_with_cavity.reset(); } void GLGizmoHollow::hollow_mesh(bool postpone_error_messages) @@ -622,7 +579,7 @@ void GLGizmoHollow::hollow_mesh(bool postpone_error_messages) void GLGizmoHollow::update_hollowed_mesh(std::unique_ptr &&mesh) { // Called from Plater when the UI job finishes - m_c->m_cavity_mesh = std::move(mesh); + /*m_c->m_cavity_mesh = std::move(mesh); if(m_c->m_cavity_mesh) { // First subtract the holes: @@ -668,7 +625,7 @@ void GLGizmoHollow::update_hollowed_mesh(std::unique_ptr &&mesh) if (m_clipping_plane_distance == 0.f) { m_clipping_plane_distance = 0.5f; update_clipping_plane(); - } + }*/ } std::vector> GLGizmoHollow::get_config_options(const std::vector& keys) const @@ -745,12 +702,13 @@ RENDER_AGAIN: wxGetApp().obj_list()->update_and_show_object_settings_item(); } } - m_imgui->disabled_begin(! m_enable_hollowing); ImGui::SameLine(); if (m_imgui->button(m_desc["preview"])) hollow_mesh(); + m_imgui->disabled_begin(! m_enable_hollowing); + std::vector opts_keys = {"hollowing_min_thickness", "hollowing_quality", "hollowing_closing_distance"}; auto opts = get_config_options(opts_keys); auto* offset_cfg = static_cast(opts[0].first); @@ -995,17 +953,17 @@ void GLGizmoHollow::on_set_state() if (m_state == On && m_old_state != On) { // the gizmo was just turned on //Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); - if (is_mesh_update_necessary()) - update_mesh(); + m_c->update_from_backend(m_parent); // we'll now reload support points: if (m_c->m_model_object) reload_cache(); m_parent.toggle_model_objects_visibility(false); - if (m_c->m_model_object) - m_parent.toggle_model_objects_visibility(! m_c->m_cavity_mesh, m_c->m_model_object, m_c->m_active_instance); - m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance); + if (m_c->m_model_object) { + m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); + m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance); + } // Set default head diameter from config. //const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; @@ -1128,6 +1086,8 @@ void GLGizmoHollow::reload_cache() void GLGizmoHollow::update_clipping_plane(bool keep_normal) const { + if (! m_c->m_model_object) + return; Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ? m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 79b0a69297..617d0b2e6f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -53,8 +53,6 @@ private: void render_points(const Selection& selection, bool picking = false) const; void render_clipping_plane(const Selection& selection) const; void render_hollowed_mesh() const; - bool is_mesh_update_necessary() const; - void update_mesh(); void hollow_mesh(bool postpone_error_messages = false); bool unsaved_changes() const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index c6e0d9007b..f63980d938 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -63,6 +63,8 @@ bool GLGizmoSlaSupports::on_init() void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const Selection& selection) { + return; + if (! model_object || selection.is_empty()) { m_c->m_model_object = nullptr; return; @@ -87,7 +89,7 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S m_c->m_active_instance_bb_radius = m_c->m_model_object->instance_bounding_box(m_c->m_active_instance).radius(); if (m_state == On) { m_parent.toggle_model_objects_visibility(false); - m_parent.toggle_model_objects_visibility(! m_c->m_cavity_mesh, m_c->m_model_object, m_c->m_active_instance); + m_parent.toggle_model_objects_visibility(/*! m_c->m_cavity_mesh*/ true, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance); } else @@ -143,7 +145,7 @@ void GLGizmoSlaSupports::on_render() const void GLGizmoSlaSupports::render_hollowed_mesh() const { - if (m_c->m_volume_with_cavity) { + /*if (m_c->m_volume_with_cavity) { m_c->m_volume_with_cavity->set_sla_shift_z(m_z_shift); m_parent.get_shader().start_using(); @@ -159,7 +161,7 @@ void GLGizmoSlaSupports::render_hollowed_mesh() const m_c->m_volume_with_cavity->set_instance_transformation(m_c->m_model_object->instances[size_t(m_c->m_active_instance)]->get_transformation()); m_c->m_volume_with_cavity->render(color_id, print_box_detection_id, print_box_worldmatrix_id); m_parent.get_shader().stop_using(); - } + }*/ } @@ -359,7 +361,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) } // Now render the drain holes: - if (! m_c->m_cavity_mesh) { + /*if (! m_c->m_cavity_mesh) { render_color[0] = 0.7f; render_color[1] = 0.7f; render_color[2] = 0.7f; @@ -394,7 +396,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) glFrontFace(GL_CCW); glsafe(::glPopMatrix()); } - } + }*/ if (!picking) glsafe(::glDisable(GL_LIGHTING)); @@ -467,14 +469,14 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pairm_cavity_mesh) { + /*if (! m_c->m_cavity_mesh) { for (const sla::DrainHole& hole : m_c->m_model_object->sla_drain_holes) { if (hole.is_inside(hit)) { in_hole = true; break; } } - } + }*/ if (! in_hole) { // Return both the point and the facet normal. pos_and_normal = std::make_pair(hit, normal); @@ -1051,7 +1053,7 @@ void GLGizmoSlaSupports::on_set_state() reload_cache(); m_parent.toggle_model_objects_visibility(false); - if (m_c->m_model_object && ! m_c->m_cavity_mesh) + if (m_c->m_model_object /*&& ! m_c->m_cavity_mesh*/) m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance); @@ -1087,7 +1089,7 @@ void GLGizmoSlaSupports::on_set_state() m_its = nullptr; m_c->m_object_clipper.reset(); m_c->m_supports_clipper.reset(); - m_c->m_mesh_raycaster.reset(); + //m_c->m_mesh_raycaster.reset(); } } m_old_state = m_state; From 3f73261fdb2653ca304210dc3e4766f46fa568e0 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 28 Jan 2020 12:41:48 +0100 Subject: [PATCH 04/27] Fixed transformation of the hollowed mesh to be used at frontend Common gizmos data update is called from GLGizmoManager --- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 23 +++++++++++++------- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 6 +++-- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 3 +++ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 3 +++ 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index bde54a0d21..e753157448 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -326,18 +326,24 @@ bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas) } } - if (m_print_object_idx < 0) - return old_po_idx != m_print_object_idx; - m_mesh = nullptr; // Load either the model_object mesh, or one provided by the backend // This mesh does not account for the possible Z up SLA offset. - const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx]; + // The backend mesh needs to be transformed and because a pointer to it is + // saved, a copy is stored as a member (FIXME) + if (m_print_object_idx >=0) { + const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx]; + if (po->is_step_done(slaposHollowing)) { + m_backend_mesh_transformed = po->get_mesh_to_print(); + m_backend_mesh_transformed.transform(canvas.sla_print()->sla_trafo(*m_model_object).inverse()); + m_mesh = &m_backend_mesh_transformed; + } + } - if (po->is_step_done(slaposHollowing)) - m_mesh = &po->get_mesh_to_print(); - else + if (! m_mesh) { m_mesh = &m_model_object->volumes.front()->mesh(); + m_backend_mesh_transformed.clear(); + } m_model_object_id = m_model_object->id(); @@ -348,7 +354,8 @@ bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas) m_old_mesh = m_mesh; return true; } - return false; + + return m_print_object_idx < 0 ? old_po_idx >=0 : false; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 0ff00a1697..c5a6d36aa3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -215,6 +215,7 @@ public: private: const TriangleMesh* m_old_mesh; + TriangleMesh m_backend_mesh_transformed; }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 51bc1b34f4..80695b4681 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -76,8 +76,10 @@ void GLGizmoHollow::set_sla_support_data(ModelObject* model_object, const Select if (model_object && selection.is_from_single_instance() - && (m_c->update_from_backend(m_parent) || something_changed)) + && (something_changed)) { + m_c->update_from_backend(m_parent); + // Cache the bb - it's needed for dealing with the clipping plane quite often // It could be done inside update_mesh but one has to account for scaling of the instance. m_c->m_active_instance_bb_radius = m_c->m_model_object->instance_bounding_box(m_c->m_active_instance).radius(); @@ -580,7 +582,7 @@ void GLGizmoHollow::update_hollowed_mesh(std::unique_ptr &&mesh) { // Called from Plater when the UI job finishes /*m_c->m_cavity_mesh = std::move(mesh); - + if(m_c->m_cavity_mesh) { // First subtract the holes: if (! m_c->m_model_object->sla_drain_holes.empty()) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index f63980d938..db514c6e25 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -1246,6 +1246,9 @@ void GLGizmoSlaSupports::reload_cache() bool GLGizmoSlaSupports::has_backend_supports() const { + if (! m_c->m_model_object) + return false; + // find SlaPrintObject with this ID for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { if (po->model_object()->id() == m_c->m_model_object->id()) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index ccc6369e46..acb74fffc1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -348,6 +348,9 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object) if (!m_enabled || m_gizmos.empty()) return; + // Update common data for hollowing and sla support gizmos. + m_common_gizmos_data->update_from_backend(m_parent); + dynamic_cast(m_gizmos[SlaSupports].get())->set_sla_support_data(model_object, m_parent.get_selection()); dynamic_cast(m_gizmos[Hollow].get())->set_sla_support_data(model_object, m_parent.get_selection()); } From b41c6d7d64440e9a419441a179c3234081d3a7eb Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 29 Jan 2020 14:07:12 +0100 Subject: [PATCH 05/27] Refuse to drill a broken mesh Hole parameters defaults and limits changed a bit --- src/libslic3r/SLAPrintSteps.cpp | 11 +++++++++-- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index f781814ae6..44ef5fe45c 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -80,6 +80,13 @@ SLAPrint::Steps::Steps(SLAPrint *print) void SLAPrint::Steps::hollow_model(SLAPrintObject &po) { po.m_hollowing_data.reset(); + bool drilling_needed = ! po.m_model_object->sla_drain_holes.empty(); + + // If the mesh is broken, stop immediately, even before hollowing. + if (drilling_needed && po.transformed_mesh().needed_repair()) + throw std::runtime_error(L("The mesh appears to be too broken " + "to drill holes into it reliably.")); + if (! po.m_config.hollowing_enable.getBool()) BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!"; else { @@ -104,7 +111,7 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po) } // Drill holes into the hollowed/original mesh. - if (po.m_model_object->sla_drain_holes.empty()) + if (! drilling_needed) BOOST_LOG_TRIVIAL(info) << "Drilling skipped (no holes)."; else { BOOST_LOG_TRIVIAL(info) << "Drilling drainage holes."; @@ -116,7 +123,7 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po) holes_mesh.merge(sla::to_triangle_mesh(holept.to_mesh())); holes_mesh.require_shared_vertices(); - MeshBoolean::self_union(holes_mesh); //FIXME-fix and use the cgal version + MeshBoolean::self_union(holes_mesh); // If there is no hollowed mesh yet, copy the original mesh. if (! po.m_hollowing_data) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 80695b4681..078eda4935 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -794,7 +794,7 @@ RENDER_AGAIN: // m_imgui->text(" "); // vertical gap ImGui::Separator(); - float diameter_upper_cap = 5.f; + float diameter_upper_cap = 15.; if (m_new_hole_radius > diameter_upper_cap) m_new_hole_radius = diameter_upper_cap; m_imgui->text(m_desc.at("hole_diameter")); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 617d0b2e6f..5745b93934 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -58,7 +58,7 @@ private: bool m_show_supports = true; float m_new_hole_radius = 2.f; // Size of a new hole. - float m_new_hole_height = 5.f; + float m_new_hole_height = 6.f; mutable std::vector m_selected; // which holes are currently selected bool m_enable_hollowing = true; From b0aa937215ba44161b06d19b7c0db774760c7e60 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 29 Jan 2020 15:57:49 +0100 Subject: [PATCH 06/27] Trying to improve drilling stability by handling CGAL exceptions --- src/libslic3r/MeshBoolean.cpp | 13 +++++++++++-- src/libslic3r/SLAPrintSteps.cpp | 14 ++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/MeshBoolean.cpp b/src/libslic3r/MeshBoolean.cpp index 69db96d3fc..734bfaca89 100644 --- a/src/libslic3r/MeshBoolean.cpp +++ b/src/libslic3r/MeshBoolean.cpp @@ -150,8 +150,17 @@ void minus(TriangleMesh &A, const TriangleMesh &B) triangle_mesh_to_cgal(B, meshB.m); CGALMesh meshResult; - CGALProc::corefine_and_compute_difference(meshA.m, meshB.m, meshResult.m); - + bool success = false; + try { + success = CGALProc::corefine_and_compute_difference(meshA.m, meshB.m, meshResult.m, + CGALParams::throw_on_self_intersection(true), CGALParams::throw_on_self_intersection(true)); + } + catch (const CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception&) { + success = false; + } + if (! success) + throw std::runtime_error("CGAL corefine_and_compute_difference failed"); + A = cgal_to_triangle_mesh(meshResult.m); } diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index 44ef5fe45c..8c0aac6fa7 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -83,9 +83,9 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po) bool drilling_needed = ! po.m_model_object->sla_drain_holes.empty(); // If the mesh is broken, stop immediately, even before hollowing. - if (drilling_needed && po.transformed_mesh().needed_repair()) - throw std::runtime_error(L("The mesh appears to be too broken " - "to drill holes into it reliably.")); + //if (drilling_needed && po.transformed_mesh().needed_repair()) + // throw std::runtime_error(L("The mesh appears to be too broken " + // "to drill holes into it reliably.")); if (! po.m_config.hollowing_enable.getBool()) BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!"; @@ -133,7 +133,13 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po) TriangleMesh &hollowed_mesh = po.m_hollowing_data->hollow_mesh_with_holes; hollowed_mesh = po.get_mesh_to_print(); - MeshBoolean::cgal::minus(hollowed_mesh, holes_mesh); + try { + MeshBoolean::cgal::minus(hollowed_mesh, holes_mesh); + } + catch (const std::runtime_error& ex) { + throw std::runtime_error(L("Drilling holes into the mesh failed. " + "This is usually caused by broken model. Try to fix it first.")); + } hollowed_mesh.require_shared_vertices(); } } From 08dcbd027172492f27ed2103e2cba67d65e1d446 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 30 Jan 2020 14:12:52 +0100 Subject: [PATCH 07/27] Hollowing gizmo - most of updating now assumes that common data struct is updated properly --- src/slic3r/GUI/GLCanvas3D.cpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 25 +++++++++++-- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 4 ++- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 44 ++++++----------------- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 32d359429b..c605c29280 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2208,6 +2208,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re mesh.transform(t.inverse()); GLIndexedVertexArray iva; iva.load_mesh(mesh); + volume->indexed_vertex_array.release_geometry(); volume->indexed_vertex_array = iva; volume->finalize_geometry(true); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index e753157448..0fc0cc94a8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -307,9 +307,27 @@ unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char gr -bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas) +bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* model_object) { - if (! m_model_object) + recent_update = false; + + if (m_model_object != model_object + || (model_object && m_model_object_id != model_object->id())) { + m_model_object = model_object; + m_print_object_idx = -1; + m_mesh_raycaster.reset(); + m_object_clipper.reset(); + m_supports_clipper.reset(); + if (m_model_object) { + m_active_instance = canvas.get_selection().get_instance_idx(); + m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius(); + } + + recent_update = true; + } + + + if (! m_model_object || ! canvas.get_selection().is_from_single_instance()) return false; int old_po_idx = m_print_object_idx; @@ -352,8 +370,11 @@ bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas) m_object_clipper.reset(); m_supports_clipper.reset(); m_old_mesh = m_mesh; + recent_update = true; return true; } + if (! recent_update) + recent_update = m_print_object_idx < 0 && old_po_idx >= 0; return m_print_object_idx < 0 ? old_po_idx >=0 : false; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index c5a6d36aa3..85f87c8f53 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -193,7 +193,9 @@ public: return (! m_mesh ? nullptr : m_mesh); //(m_cavity_mesh ? m_cavity_mesh.get() : m_mesh)); } - bool update_from_backend(GLCanvas3D& canvas); + bool update_from_backend(GLCanvas3D& canvas, ModelObject* model_object); + + bool recent_update = false; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 078eda4935..1bb18a7557 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -55,36 +55,12 @@ bool GLGizmoHollow::on_init() return true; } -void GLGizmoHollow::set_sla_support_data(ModelObject* model_object, const Selection& selection) +void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&) { - if (! model_object || selection.is_empty()) { - m_c->m_model_object = nullptr; - return; - } + if (m_c->recent_update) { - bool something_changed = false; - - if (m_c->m_model_object != model_object - || m_c->m_model_object_id != model_object->id() - || m_c->m_active_instance != selection.get_instance_idx()) { - m_c->m_model_object = model_object; - m_c->m_print_object_idx = -1; - m_c->m_mesh_raycaster.reset(); - m_c->m_active_instance = selection.get_instance_idx(); - something_changed = true; - } - - if (model_object - && selection.is_from_single_instance() - && (something_changed)) - { - m_c->update_from_backend(m_parent); - - // Cache the bb - it's needed for dealing with the clipping plane quite often - // It could be done inside update_mesh but one has to account for scaling of the instance. - m_c->m_active_instance_bb_radius = m_c->m_model_object->instance_bounding_box(m_c->m_active_instance).radius(); - - reload_cache(); + if (m_c->m_model_object) + reload_cache(); if (m_state == On) { m_parent.toggle_model_objects_visibility(false); @@ -112,7 +88,7 @@ void GLGizmoHollow::on_render() const } // !!! is it necessary? - const_cast(this)->m_c->update_from_backend(m_parent); + //const_cast(this)->m_c->update_from_backend(m_parent, m_c->m_model_object); glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); @@ -183,8 +159,8 @@ void GLGizmoHollow::render_clipping_plane(const Selection& selection) const // Next, ask the backend if supports are already calculated. If so, we are gonna cut them too. - if (m_c->m_print_object_idx < 0) - m_c->update_from_backend(m_parent); + //if (m_c->m_print_object_idx < 0) + // m_c->update_from_backend(m_parent, m_c->m_model_object); if (m_c->m_print_object_idx >= 0) { const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_c->m_print_object_idx]; @@ -352,9 +328,11 @@ bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const // Return false if no intersection was found, true otherwise. bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) { + if (! m_c->m_mesh_raycaster) + return false; // if the gizmo doesn't have the V, F structures for igl, calculate them first: // !!! is it really necessary? - m_c->update_from_backend(m_parent); + //m_c->update_from_backend(m_parent, m_c->m_model_object); const Camera& camera = m_parent.get_camera(); const Selection& selection = m_parent.get_selection(); @@ -955,7 +933,7 @@ void GLGizmoHollow::on_set_state() if (m_state == On && m_old_state != On) { // the gizmo was just turned on //Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); - m_c->update_from_backend(m_parent); + //m_c->update_from_backend(m_parent, m_c->m_model_object); // we'll now reload support points: if (m_c->m_model_object) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index acb74fffc1..db459dd7d4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -349,7 +349,7 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object) return; // Update common data for hollowing and sla support gizmos. - m_common_gizmos_data->update_from_backend(m_parent); + m_common_gizmos_data->update_from_backend(m_parent, model_object); dynamic_cast(m_gizmos[SlaSupports].get())->set_sla_support_data(model_object, m_parent.get_selection()); dynamic_cast(m_gizmos[Hollow].get())->set_sla_support_data(model_object, m_parent.get_selection()); From 4f43c6d3f804fecbcf6ba09d5b25d41e3eeff5ca Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 30 Jan 2020 14:31:22 +0100 Subject: [PATCH 08/27] SlaSupports gizmo - most of updating now assumes that common data struct is updated properly --- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 1 + src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 83 +++----------------- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 2 - 3 files changed, 14 insertions(+), 72 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 0fc0cc94a8..92b9901479 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -366,6 +366,7 @@ bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* mode m_model_object_id = m_model_object->id(); if (m_mesh != m_old_mesh) { + wxBusyCursor wait; m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh)); m_object_clipper.reset(); m_supports_clipper.reset(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index db514c6e25..c1c3c6d1ce 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -63,45 +63,22 @@ bool GLGizmoSlaSupports::on_init() void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const Selection& selection) { - return; - - if (! model_object || selection.is_empty()) { - m_c->m_model_object = nullptr; - return; - } - - bool something_changed = false; - - if (m_c->m_model_object != model_object - || m_c->m_model_object_id != model_object->id() - || m_c->m_active_instance != selection.get_instance_idx()) { - m_c->m_model_object = model_object; - m_c->m_print_object_idx = -1; - m_c->m_active_instance = selection.get_instance_idx(); - something_changed = true; - } - - if (model_object && selection.is_from_single_instance()) - { - // Cache the bb - it's needed for dealing with the clipping plane quite often - // It could be done inside update_mesh but one has to account for scaling of the instance. - if (something_changed) { - m_c->m_active_instance_bb_radius = m_c->m_model_object->instance_bounding_box(m_c->m_active_instance).radius(); - if (m_state == On) { - m_parent.toggle_model_objects_visibility(false); - m_parent.toggle_model_objects_visibility(/*! m_c->m_cavity_mesh*/ true, m_c->m_model_object, m_c->m_active_instance); - m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance); - } - else - m_parent.toggle_model_objects_visibility(true, nullptr, -1); + if (m_c->recent_update) { + if (m_state == On) { + m_parent.toggle_model_objects_visibility(false); + m_parent.toggle_model_objects_visibility(/*! m_c->m_cavity_mesh*/ true, m_c->m_model_object, m_c->m_active_instance); + m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance); } + else + m_parent.toggle_model_objects_visibility(true, nullptr, -1); - if (is_mesh_update_necessary()) { - update_mesh(); + disable_editing_mode(); + if (m_c->m_model_object) reload_cache(); - } + } - // If we triggered autogeneration before, check backend and fetch results if they are there + // If we triggered autogeneration before, check backend and fetch results if they are there + if (m_c->m_model_object) { if (m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating) get_data_from_backend(); } @@ -122,9 +99,6 @@ void GLGizmoSlaSupports::on_render() const return; } - if (! m_its || ! m_c->m_mesh) - const_cast(this)->update_mesh(); - glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); @@ -418,41 +392,12 @@ bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const -bool GLGizmoSlaSupports::is_mesh_update_necessary() const -{ - return ((m_state == On) && (m_c->m_model_object != nullptr) && !m_c->m_model_object->instances.empty()) - && ((m_c->m_model_object->id() != m_c->m_model_object_id) || m_its == nullptr); -} - - - -void GLGizmoSlaSupports::update_mesh() -{ - if (! m_c->m_model_object) - return; - - wxBusyCursor wait; - // this way we can use that mesh directly. - // This mesh does not account for the possible Z up SLA offset. - m_c->m_mesh = &m_c->m_model_object->volumes.front()->mesh(); - m_its = &m_c->m_mesh->its; - - // If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it. - if (m_c->m_model_object_id != m_c->m_model_object->id() || ! m_c->m_mesh_raycaster) - m_c->m_mesh_raycaster.reset(new MeshRaycaster(*m_c->mesh())); - - m_c->m_model_object_id = m_c->m_model_object->id(); - disable_editing_mode(); -} - - // Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal // Return false if no intersection was found, true otherwise. bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) { - // if the gizmo doesn't have the V, F structures for igl, calculate them first: if (! m_c->m_mesh_raycaster) - update_mesh(); + return false; const Camera& camera = m_parent.get_camera(); const Selection& selection = m_parent.get_selection(); @@ -1045,8 +990,6 @@ void GLGizmoSlaSupports::on_set_state() if (m_state == On && m_old_state != On) { // the gizmo was just turned on Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); - if (is_mesh_update_necessary()) - update_mesh(); // we'll now reload support points: if (m_c->m_model_object) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 3697e7af69..152979f83d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -91,8 +91,6 @@ private: void render_points(const Selection& selection, bool picking = false) const; void render_clipping_plane(const Selection& selection) const; void render_hollowed_mesh() const; - bool is_mesh_update_necessary() const; - void update_mesh(); bool unsaved_changes() const; bool m_lock_unique_islands = false; From a6f7fc93f411c4a773810ca5ab56ab88ec54aa18 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 30 Jan 2020 15:25:15 +0100 Subject: [PATCH 09/27] Gizmo updates - forget everything about the loaded mesh when an object is deselected --- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 92b9901479..463c681a69 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -318,6 +318,9 @@ bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* mode m_mesh_raycaster.reset(); m_object_clipper.reset(); m_supports_clipper.reset(); + m_old_mesh = nullptr; + m_mesh = nullptr; + m_backend_mesh_transformed.clear(); if (m_model_object) { m_active_instance = canvas.get_selection().get_instance_idx(); m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius(); From 9ef65b23d8627aa5d76140bf4829afad343adf96 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 30 Jan 2020 17:58:40 +0100 Subject: [PATCH 10/27] Implemented loading of hollowed SLA mesh into the scene in place of the normal mesh. WIP: The code is inefficient (it does not store the timestamp of the hollowed mesh, therefore it refreshes the hollowed mesh on each scene update) and if the hollowing gets invalidated, the original mesh is currently not being reloaded and the hollowed mesh is still visible. --- src/libslic3r/SLAPrint.cpp | 2 + src/slic3r/GUI/GLCanvas3D.cpp | 85 +++++++++++++++++------------------ 2 files changed, 42 insertions(+), 45 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 23b4a8046e..1935e5e319 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1103,6 +1103,8 @@ const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const bool SLAPrintObject::has_mesh(SLAPrintObjectStep step) const { switch (step) { + case slaposHollowing: + return m_hollowing_data && !m_hollowing_data->hollow_mesh_with_holes.empty(); case slaposSupportTree: return ! this->support_mesh().empty(); case slaposPad: diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c605c29280..fa3a25b79d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1930,8 +1930,6 @@ void GLCanvas3D::mirror_selection(Axis axis) // 5) Out of bed collision status & message overlay (texture) void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_refresh) { - force_full_scene_refresh = true; - if ((m_canvas == nullptr) || (m_config == nullptr) || (m_model == nullptr)) return; @@ -1971,8 +1969,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re }; // SLA steps to pull the preview meshes for. - typedef std::array SLASteps; - SLASteps sla_steps = { slaposSupportTree, slaposPad }; + typedef std::array SLASteps; + SLASteps sla_steps = { slaposHollowing, slaposSupportTree, slaposPad }; struct SLASupportState { std::array::value> step; }; @@ -2019,7 +2017,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // Consider the DONE step without a valid mesh as invalid for the purpose // of mesh visualization. state.step[istep].state = PrintStateBase::INVALID; - else + else if (sla_steps[istep] != slaposHollowing) for (const ModelInstance* model_instance : print_object->model_object()->instances) // Only the instances, which are currently printable, will have the SLA support structures kept. // The instances outside the print bed will have the GLVolumes of their support structures released. @@ -2032,7 +2030,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } std::sort(model_volume_state.begin(), model_volume_state.end(), model_volume_state_lower); std::sort(aux_volume_state.begin(), aux_volume_state.end(), model_volume_state_lower); - // Release all ModelVolume based GLVolumes not found in the current Model. + // Release all ModelVolume based GLVolumes not found in the current Model. Find the GLVolume of a hollowed mesh. for (size_t volume_id = 0; volume_id < m_volumes.volumes.size(); ++volume_id) { GLVolume* volume = m_volumes.volumes[volume_id]; ModelVolumeState key(volume); @@ -2114,6 +2112,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (it_old_volume != deleted_volumes.end() && it_old_volume->composite_id == it->composite_id) // If a volume changed its ObjectID, but it reuses a GLVolume's CompositeID, maintain its selection. map_glvolume_old_to_new[it_old_volume->volume_idx] = m_volumes.volumes.size(); + // Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh + // later in this function. + it->volume_idx = m_volumes.volumes.size(); m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized); m_volumes.volumes.back()->geometry_id = key.geometry_id; update_object_list = true; @@ -2163,57 +2164,51 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re int instance_idx = it - model_object->instances.begin(); for (size_t istep = 0; istep < sla_steps.size(); ++ istep) if (state.step[istep].state == PrintStateBase::DONE) { - ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); - auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); - assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id); - if (it->new_geometry()) { - // This can be an SLA support structure that should not be rendered (in case someone used undo - // to revert to before it was generated). If that's the case, we should not generate anything. - if (model_object->sla_points_status != sla::PointsStatus::NoPoints) - instances[istep].emplace_back(std::pair(instance_idx, print_instance_idx)); - else - shift_zs[object_idx] = 0.; + if (sla_steps[istep] == slaposHollowing) { + // Check whether there is a main object mesh, which we may update with the hollowed mesh. + ModelVolumeState key(model_object->volumes.front()->id(), instance.instance_id); + auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); + assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); + assert(!it->new_geometry()); + GLVolume& volume = *m_volumes.volumes[it->volume_idx]; + TriangleMesh mesh = print_object->get_mesh(slaposHollowing); + if (!mesh.empty()) { + Transform3d t = sla_print->sla_trafo(*m_model->objects[volume.object_idx()]); + mesh.transform(t.inverse()); + volume.indexed_vertex_array.release_geometry(); + volume.indexed_vertex_array.load_mesh(mesh); + volume.finalize_geometry(true); + } + } else { + // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created. + ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); + auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); + assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id); + if (it->new_geometry()) { + // This can be an SLA support structure that should not be rendered (in case someone used undo + // to revert to before it was generated). If that's the case, we should not generate anything. + if (model_object->sla_points_status != sla::PointsStatus::NoPoints) + instances[istep].emplace_back(std::pair(instance_idx, print_instance_idx)); + else + shift_zs[object_idx] = 0.; + } else { + // Recycling an old GLVolume. Update the Object/Instance indices into the current Model. + m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); + m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); + } } - else { - // Recycling an old GLVolume. Update the Object/Instance indices into the current Model. - m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); - m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); - } } } -// // stores the current volumes count -// size_t volumes_count = m_volumes.volumes.size(); - for (size_t istep = 0; istep < sla_steps.size(); ++istep) if (!instances[istep].empty()) m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized); } // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed - for (GLVolume* volume : m_volumes.volumes) { + for (GLVolume* volume : m_volumes.volumes) if (volume->object_idx() < (int)m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable()) volume->set_sla_shift_z(shift_zs[volume->object_idx()]); - - // Just an experiment for now - replace the mesh with a hollowed one. - for (size_t po_idx=0; po_idxobjects().size(); ++po_idx) { - const SLAPrintObject* po = sla_print->objects()[po_idx]; - if (po_idx != volume->composite_id.object_id || volume->composite_id.volume_id < 0) - continue; - if (po->is_step_done(slaposHollowing)) { - TriangleMesh mesh = po->get_mesh(slaposHollowing); - if (mesh.empty()) - continue; - Transform3d t = sla_print->sla_trafo(*m_model->objects[volume->object_idx()]); - mesh.transform(t.inverse()); - GLIndexedVertexArray iva; - iva.load_mesh(mesh); - volume->indexed_vertex_array.release_geometry(); - volume->indexed_vertex_array = iva; - volume->finalize_geometry(true); - } - } - } } if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) From 73f69f3387e6ea9d35360fa6e0483d7e2bc68d94 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 3 Feb 2020 14:01:35 +0100 Subject: [PATCH 11/27] Speed up of libigl SelfIntersectMesh: The test for intersection of two triangles sharing a common edge has been optimized to reject non-overlaping triangles with the least amount of exact arithmetics predicates. Cherry pick of https://github.com/bubnikv/libigl/commit/d367762468ce3e663a62f155ee118fb6aa3657c4 --- .../igl/copyleft/cgal/SelfIntersectMesh.h | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/libigl/igl/copyleft/cgal/SelfIntersectMesh.h b/src/libigl/igl/copyleft/cgal/SelfIntersectMesh.h index 5a70fc39e7..39a4e1a7e3 100644 --- a/src/libigl/igl/copyleft/cgal/SelfIntersectMesh.h +++ b/src/libigl/igl/copyleft/cgal/SelfIntersectMesh.h @@ -635,13 +635,30 @@ inline bool igl::copyleft::cgal::SelfIntersectMesh< { using namespace std; + auto opposite_vertex = [](const Index a0, const Index a1) { + // get opposite index of A + int a2=-1; + for(int c=0;c<3;++c) + if(c!=a0 && c!=a1) { + a2 = c; + break; + } + assert(a2 != -1); + return a2; + }; + // must be co-planar - if( - A.supporting_plane() != B.supporting_plane() && - A.supporting_plane() != B.supporting_plane().opposite()) - { + Index a2 = opposite_vertex(shared[0].first, shared[1].first); + if (! B.supporting_plane().has_on(A.vertex(a2))) return false; - } + + Index b2 = opposite_vertex(shared[0].second, shared[1].second); + + if (int(CGAL::coplanar_orientation(A.vertex(shared[0].first), A.vertex(shared[1].first), A.vertex(a2))) * + int(CGAL::coplanar_orientation(B.vertex(shared[0].second), B.vertex(shared[1].second), B.vertex(b2))) < 0) + // There is certainly no self intersection as the non-shared triangle vertices lie on opposite sides of the shared edge. + return false; + // Since A and B are non-degenerate the intersection must be a polygon // (triangle). Either // - the vertex of A (B) opposite the shared edge of lies on B (A), or @@ -650,22 +667,10 @@ inline bool igl::copyleft::cgal::SelfIntersectMesh< // Determine if the vertex opposite edge (a0,a1) in triangle A lies in // (intersects) triangle B const auto & opposite_point_inside = []( - const Triangle_3 & A, const Index a0, const Index a1, const Triangle_3 & B) + const Triangle_3 & A, const Index a2, const Triangle_3 & B) -> bool { - // get opposite index - Index a2 = -1; - for(int c = 0;c<3;c++) - { - if(c != a0 && c != a1) - { - a2 = c; - break; - } - } - assert(a2 != -1); - bool ret = CGAL::do_intersect(A.vertex(a2),B); - return ret; + return CGAL::do_intersect(A.vertex(a2),B); }; // Determine if edge opposite vertex va in triangle A intersects edge @@ -681,8 +686,8 @@ inline bool igl::copyleft::cgal::SelfIntersectMesh< }; if( - !opposite_point_inside(A,shared[0].first,shared[1].first,B) && - !opposite_point_inside(B,shared[0].second,shared[1].second,A) && + !opposite_point_inside(A,a2,B) && + !opposite_point_inside(B,b2,A) && !opposite_edges_intersect(A,shared[0].first,B,shared[1].second) && !opposite_edges_intersect(A,shared[1].first,B,shared[0].second)) { @@ -936,4 +941,4 @@ inline void igl::copyleft::cgal::SelfIntersectMesh< //process_chunk(0, candidate_triangle_pairs.size()); } -#endif +#endif \ No newline at end of file From 9d55121695126c113cb2eb4b65115320840dca39 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 3 Feb 2020 14:39:16 +0100 Subject: [PATCH 12/27] Move Gizmo -> added movements using arrow keys: Left arrow = decrease X by 1mm Right arrow = increase X by 1mm Up arrow = increase Y by 1mm Down arrow = decrease Y by 1mm --- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 32 ++++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index ccc6369e46..beca637987 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -497,7 +497,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) processed = true; } else if (evt.Dragging() && (m_parent.get_move_volume_id() != -1) && (m_current == SlaSupports || m_current == Hollow)) - // don't allow dragging objects with the Sla gizmo on + // don't allow dragging objects with the Sla gizmo on processed = true; else if (evt.Dragging() && (m_current == SlaSupports || m_current == Hollow) && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown())) { @@ -554,12 +554,9 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) else if (evt.LeftUp() && is_dragging()) { switch (m_current) { - case Move : m_parent.do_move(L("Gizmo-Move")); - break; - case Scale : m_parent.do_scale(L("Gizmo-Scale")); - break; - case Rotate : m_parent.do_rotate(L("Gizmo-Rotate")); - break; + case Move : m_parent.do_move(L("Gizmo-Move")); break; + case Scale : m_parent.do_scale(L("Gizmo-Scale")); break; + case Rotate : m_parent.do_rotate(L("Gizmo-Rotate")); break; default : break; } @@ -776,6 +773,27 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) processed = true; } } + else if (m_current == Move) + { + auto do_move = [this, &processed](const Vec3d& displacement) { + Selection& selection = m_parent.get_selection(); + selection.start_dragging(); + selection.translate(displacement); + wxGetApp().obj_manipul()->set_dirty(); + m_parent.do_move(L("Gizmo-Move")); + m_parent.set_as_dirty(); + processed = true; + }; + + switch (keyCode) + { + case WXK_NUMPAD_LEFT: case WXK_LEFT: { do_move(-Vec3d::UnitX()); break; } + case WXK_NUMPAD_RIGHT: case WXK_RIGHT: { do_move(Vec3d::UnitX()); break; } + case WXK_NUMPAD_UP: case WXK_UP: { do_move(Vec3d::UnitY()); break; } + case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_move(-Vec3d::UnitY()); break; } + default: { break; } + } + } // if (processed) // m_parent.set_cursor(GLCanvas3D::Standard); From c09091c40703bdfae84e4bee3094bf6db23d8487 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 3 Feb 2020 14:51:25 +0100 Subject: [PATCH 13/27] Rotate Gizmo -> added rotations using arrow keys: Left arrow = 90 degrees around Z axis CCW Right arrow = 90 degrees around Z axis CW Up arrow = 45 degrees around Z axis CCW Down arrow = 45 degrees around Z axis CW --- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index beca637987..d830e4f3a1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -794,6 +794,27 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) default: { break; } } } + else if (m_current == Rotate) + { + auto do_rotate = [this, &processed](const Vec3d& rotation) { + Selection& selection = m_parent.get_selection(); + selection.start_dragging(); + selection.rotate(rotation, TransformationType(TransformationType::World_Relative_Joint)); + wxGetApp().obj_manipul()->set_dirty(); + m_parent.do_rotate(L("Gizmo-Rotate")); + m_parent.set_as_dirty(); + processed = true; + }; + + switch (keyCode) + { + case WXK_NUMPAD_LEFT: case WXK_LEFT: { do_rotate(Vec3d(0.0, 0.0, 0.5 * M_PI)); break; } + case WXK_NUMPAD_RIGHT: case WXK_RIGHT: { do_rotate(-Vec3d(0.0, 0.0, 0.5 * M_PI)); break; } + case WXK_NUMPAD_UP: case WXK_UP: { do_rotate(Vec3d(0.0, 0.0, 0.25 * M_PI)); break; } + case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_rotate(-Vec3d(0.0, 0.0, 0.25 * M_PI)); break; } + default: { break; } + } + } // if (processed) // m_parent.set_cursor(GLCanvas3D::Standard); From 8453c8848238c1bb20bc7dc85cad4763203534c9 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 3 Feb 2020 15:00:49 +0100 Subject: [PATCH 14/27] Cut Gizmo -> added movements using arrow keys: Up arrow = increase Z by 1mm Down arrow = decrease Z by 1mm --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 4 +++- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 4 +++- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index e98446749f..52d710249b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include "slic3r/GUI/GUI_App.hpp" @@ -189,7 +191,7 @@ void GLGizmoCut::update_max_z(const Selection& selection) const void GLGizmoCut::set_cut_z(double cut_z) const { // Clamp the plane to the object's bounding box - m_cut_z = std::max(0.0, std::min(m_max_z, cut_z)); + m_cut_z = std::clamp(cut_z, 0.0, m_max_z); } void GLGizmoCut::perform_cut(const Selection& selection) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 6e5738a422..b6e10861fc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -25,6 +25,9 @@ class GLGizmoCut : public GLGizmoBase public: GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); + double get_cut_z() const { return m_cut_z; } + void set_cut_z(double cut_z) const; + protected: virtual bool on_init(); virtual void on_load(cereal::BinaryInputArchive& ar) { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); } @@ -40,7 +43,6 @@ protected: private: void update_max_z(const Selection& selection) const; - void set_cut_z(double cut_z) const; void perform_cut(const Selection& selection); double calc_projection(const Linef3& mouse_ray) const; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index d830e4f3a1..e1b4a97e80 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -815,6 +815,22 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) default: { break; } } } + else if (m_current == Cut) + { + auto do_move = [this, &processed](double delta_z) { + GLGizmoCut* cut = dynamic_cast(get_current()); + cut->set_cut_z(delta_z + cut->get_cut_z()); + m_parent.set_as_dirty(); + processed = true; + }; + + switch (keyCode) + { + case WXK_NUMPAD_UP: case WXK_UP: { do_move(1.0); break; } + case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_move(-1.0); break; } + default: { break; } + } + } // if (processed) // m_parent.set_cursor(GLCanvas3D::Standard); From f28d0ebc1871e8fc3687e897a06a3cc10c0b87cf Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 3 Feb 2020 12:55:38 +0100 Subject: [PATCH 15/27] Implemented reload of original mesh volume in case the SLA hollowing step is no more valid. --- src/slic3r/GUI/3DScene.hpp | 57 +++++++++++++++------------ src/slic3r/GUI/GLCanvas3D.cpp | 74 +++++++++++++++++++---------------- 2 files changed, 72 insertions(+), 59 deletions(-) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 5d559c246d..aed907004f 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -313,33 +313,38 @@ public: // Valid geometry_id should always be positive. std::pair geometry_id; // An ID containing the extruder ID (used to select color). - int extruder_id; - // Is this object selected? - bool selected; - // Is this object disabled from selection? - bool disabled; - // Is this object printable? - bool printable; - // Whether or not this volume is active for rendering - bool is_active; - // Whether or not to use this volume when applying zoom_to_volumes() - bool zoom_to_volumes; - // Wheter or not this volume is enabled for outside print volume detection in shader. - bool shader_outside_printer_detection_enabled; - // Wheter or not this volume is outside print volume. - bool is_outside; + int extruder_id; + + // Various boolean flags. + struct { + // Is this object selected? + bool selected : 1; + // Is this object disabled from selection? + bool disabled : 1; + // Is this object printable? + bool printable : 1; + // Whether or not this volume is active for rendering + bool is_active : 1; + // Whether or not to use this volume when applying zoom_to_volumes() + bool zoom_to_volumes : 1; + // Wheter or not this volume is enabled for outside print volume detection in shader. + bool shader_outside_printer_detection_enabled : 1; + // Wheter or not this volume is outside print volume. + bool is_outside : 1; + // Wheter or not this volume has been generated from a modifier + bool is_modifier : 1; + // Wheter or not this volume has been generated from the wipe tower + bool is_wipe_tower : 1; + // Wheter or not this volume has been generated from an extrusion path + bool is_extrusion_path : 1; + // Wheter or not to always render this volume using its own alpha + bool force_transparent : 1; + // Whether or not always use the volume's own color (not using SELECTED/HOVER/DISABLED/OUTSIDE) + bool force_native_color : 1; + }; + // Is mouse or rectangle selection over this object to select/deselect it ? - EHoverState hover; - // Wheter or not this volume has been generated from a modifier - bool is_modifier; - // Wheter or not this volume has been generated from the wipe tower - bool is_wipe_tower; - // Wheter or not this volume has been generated from an extrusion path - bool is_extrusion_path; - // Wheter or not to always render this volume using its own alpha - bool force_transparent; - // Whether or not always use the volume's own color (not using SELECTED/HOVER/DISABLED/OUTSIDE) - bool force_native_color; + EHoverState hover; // Interleaved triangles & normals with indexed triangles & quads. GLIndexedVertexArray indexed_vertex_array; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index fa3a25b79d..e0c7a77a0d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2143,8 +2143,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re const ModelObject *model_object = print_object->model_object(); // Find an index of the ModelObject int object_idx; - if (std::all_of(state.step.begin(), state.step.end(), [](const PrintStateBase::StateWithTimeStamp &state){ return state.state != PrintStateBase::DONE; })) - continue; // There may be new SLA volumes added to the scene for this print_object. // Find the object index of this print_object in the Model::objects list. auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object); @@ -2163,39 +2161,49 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re assert(it != model_object->instances.end()); int instance_idx = it - model_object->instances.begin(); for (size_t istep = 0; istep < sla_steps.size(); ++ istep) - if (state.step[istep].state == PrintStateBase::DONE) { - if (sla_steps[istep] == slaposHollowing) { - // Check whether there is a main object mesh, which we may update with the hollowed mesh. - ModelVolumeState key(model_object->volumes.front()->id(), instance.instance_id); - auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); - assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); - assert(!it->new_geometry()); - GLVolume& volume = *m_volumes.volumes[it->volume_idx]; - TriangleMesh mesh = print_object->get_mesh(slaposHollowing); - if (!mesh.empty()) { - Transform3d t = sla_print->sla_trafo(*m_model->objects[volume.object_idx()]); - mesh.transform(t.inverse()); - volume.indexed_vertex_array.release_geometry(); + if (sla_steps[istep] == slaposHollowing) { + // Hollowing is a special case, where the mesh from the backend is being loaded into the 1st volume of an instance, + // not into its own GLVolume. + // There shall always be such a GLVolume allocated. + ModelVolumeState key(model_object->volumes.front()->id(), instance.instance_id); + auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); + assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); + assert(!it->new_geometry()); + GLVolume &volume = *m_volumes.volumes[it->volume_idx]; + if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) { + // The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen. + volume.indexed_vertex_array.release_geometry(); + if (state.step[istep].state == PrintStateBase::DONE) { + TriangleMesh mesh = print_object->get_mesh(slaposHollowing); + assert(! mesh.empty()); + mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse()); volume.indexed_vertex_array.load_mesh(mesh); - volume.finalize_geometry(true); - } + } else { + // Reload the original volume. + volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); + } + volume.finalize_geometry(true); + } + //FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable + // to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables + // of various concenrs (model vs. 3D print path). + volume.offsets = { state.step[istep].timestamp }; + } else if (state.step[istep].state == PrintStateBase::DONE) { + // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created. + ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); + auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); + assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id); + if (it->new_geometry()) { + // This can be an SLA support structure that should not be rendered (in case someone used undo + // to revert to before it was generated). If that's the case, we should not generate anything. + if (model_object->sla_points_status != sla::PointsStatus::NoPoints) + instances[istep].emplace_back(std::pair(instance_idx, print_instance_idx)); + else + shift_zs[object_idx] = 0.; } else { - // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created. - ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); - auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); - assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id); - if (it->new_geometry()) { - // This can be an SLA support structure that should not be rendered (in case someone used undo - // to revert to before it was generated). If that's the case, we should not generate anything. - if (model_object->sla_points_status != sla::PointsStatus::NoPoints) - instances[istep].emplace_back(std::pair(instance_idx, print_instance_idx)); - else - shift_zs[object_idx] = 0.; - } else { - // Recycling an old GLVolume. Update the Object/Instance indices into the current Model. - m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); - m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); - } + // Recycling an old GLVolume. Update the Object/Instance indices into the current Model. + m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); + m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); } } } From 79da3a95e18bef9a3484737a818659191d577b98 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 31 Jan 2020 15:54:16 +0100 Subject: [PATCH 16/27] Clipping plane is now common for Hollowing and SLA supports gizmos --- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 13 +++++ src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 53 +++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 6 +-- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 51 ++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 3 +- 6 files changed, 73 insertions(+), 55 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 463c681a69..653bfefb5b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -374,6 +374,8 @@ bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* mode m_object_clipper.reset(); m_supports_clipper.reset(); m_old_mesh = m_mesh; + m_clipping_plane_distance = 0.f; + m_clipping_plane_distance_stash = 0.f; recent_update = true; return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 85f87c8f53..5cd3d9d84c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -32,6 +32,7 @@ static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; class ImGuiWrapper; class CommonGizmosData; class GLCanvas3D; +class ClippingPlane; class GLGizmoBase { @@ -215,9 +216,21 @@ public: int m_print_objects_count = -1; int m_old_timestamp = -1; + float m_clipping_plane_distance = 0.f; + std::unique_ptr m_clipping_plane; + + void stash_clipping_plane() { + m_clipping_plane_distance_stash = m_clipping_plane_distance; + } + + void unstash_clipping_plane() { + m_clipping_plane_distance = m_clipping_plane_distance_stash; + } + private: const TriangleMesh* m_old_mesh; TriangleMesh m_backend_mesh_transformed; + float m_clipping_plane_distance_stash = 0.f; }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 1bb18a7557..3db5e1e132 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -22,7 +22,7 @@ GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filenam : GLGizmoBase(parent, icon_filename, sprite_id, cd) , m_quadric(nullptr) { - m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); + m_c->m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); m_quadric = ::gluNewQuadric(); if (m_quadric != nullptr) // using GLU_FILL does not work when the instance's transformation @@ -132,7 +132,7 @@ void GLGizmoHollow::render_hollowed_mesh() const void GLGizmoHollow::render_clipping_plane(const Selection& selection) const { - if (m_clipping_plane_distance == 0.f) + if (m_c->m_clipping_plane_distance == 0.f) return; // Get transformation of the instance @@ -154,7 +154,7 @@ void GLGizmoHollow::render_clipping_plane(const Selection& selection) const m_c->m_object_clipper.reset(new MeshClipper); m_c->m_object_clipper->set_mesh(*m_c->mesh()); } - m_c->m_object_clipper->set_plane(*m_clipping_plane); + m_c->m_object_clipper->set_plane(*m_c->m_clipping_plane); m_c->m_object_clipper->set_transformation(trafo); @@ -177,7 +177,7 @@ void GLGizmoHollow::render_clipping_plane(const Selection& selection) const m_c->m_supports_clipper->set_mesh(print_object->support_mesh()); m_c->m_old_timestamp = timestamp; } - m_c->m_supports_clipper->set_plane(*m_clipping_plane); + m_c->m_supports_clipper->set_plane(*m_c->m_clipping_plane); m_c->m_supports_clipper->set_transformation(supports_trafo); } else @@ -314,12 +314,12 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const { - if (m_clipping_plane_distance == 0.f) + if (m_c->m_clipping_plane_distance == 0.f) return false; Vec3d transformed_point = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation().get_matrix() * point; transformed_point(2) += m_z_shift; - return m_clipping_plane->is_point_clipped(transformed_point); + return m_c->m_clipping_plane->is_point_clipped(transformed_point); } @@ -343,7 +343,7 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pairm_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) { + if (m_c->m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_c->m_clipping_plane.get())) { // Return both the point and the facet normal. pos_and_normal = std::make_pair(hit, normal); return true; @@ -429,7 +429,7 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos points_inside.push_back(points[idx].cast()); // Only select/deselect points that are actually visible - for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_clipping_plane.get())) + for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_c->m_clipping_plane.get())) { if (rectangle_status == GLSelectionRectangle::Deselect) unselect_point(points_idxs[idx]); @@ -483,13 +483,13 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos } if (action == SLAGizmoEventType::MouseWheelUp && control_down) { - m_clipping_plane_distance = std::min(1.f, m_clipping_plane_distance + 0.01f); + m_c->m_clipping_plane_distance = std::min(1.f, m_c->m_clipping_plane_distance + 0.01f); update_clipping_plane(true); return true; } if (action == SLAGizmoEventType::MouseWheelDown && control_down) { - m_clipping_plane_distance = std::max(0.f, m_clipping_plane_distance - 0.01f); + m_c->m_clipping_plane_distance = std::max(0.f, m_c->m_clipping_plane_distance - 0.01f); update_clipping_plane(true); return true; } @@ -602,8 +602,8 @@ void GLGizmoHollow::update_hollowed_mesh(std::unique_ptr &&mesh) m_c->m_mesh_raycaster.reset(new MeshRaycaster(*m_c->mesh())); } - if (m_clipping_plane_distance == 0.f) { - m_clipping_plane_distance = 0.5f; + if (m_c->m_clipping_plane_distance == 0.f) { + m_c->m_clipping_plane_distance = 0.5f; update_clipping_plane(); }*/ } @@ -638,10 +638,10 @@ std::vector> GLGizmoHollo ClippingPlane GLGizmoHollow::get_sla_clipping_plane() const { - if (!m_c->m_model_object || m_state == Off || m_clipping_plane_distance == 0.f) + if (!m_c->m_model_object || m_state == Off || m_c->m_clipping_plane_distance == 0.f) return ClippingPlane::ClipsNothing(); else - return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]); + return ClippingPlane(-m_c->m_clipping_plane->get_normal(), m_c->m_clipping_plane->get_data()[3]); } @@ -842,7 +842,7 @@ RENDER_AGAIN: // Following is rendered in both editing and non-editing mode: // m_imgui->text(""); ImGui::Separator(); - if (m_clipping_plane_distance == 0.f) + if (m_c->m_clipping_plane_distance == 0.f) m_imgui->text(m_desc.at("clipping_of_view")); else { if (m_imgui->button(m_desc.at("reset_direction"))) { @@ -854,7 +854,7 @@ RENDER_AGAIN: ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); - if (ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f")) + if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f")) update_clipping_plane(true); // make sure supports are shown/hidden as appropriate @@ -934,6 +934,8 @@ void GLGizmoHollow::on_set_state() if (m_state == On && m_old_state != On) { // the gizmo was just turned on //Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); //m_c->update_from_backend(m_parent, m_c->m_model_object); + m_c->unstash_clipping_plane(); + update_clipping_plane(m_c->m_clipping_plane_distance != 0.f); // we'll now reload support points: if (m_c->m_model_object) @@ -952,8 +954,9 @@ void GLGizmoHollow::on_set_state() if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off //Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off"))); m_parent.toggle_model_objects_visibility(true); - m_clipping_plane_distance = 0.f; - update_clipping_plane(); + m_c->stash_clipping_plane(); + m_c->m_clipping_plane_distance = 0.f; + update_clipping_plane(true); // Release clippers and the AABB raycaster. m_c->m_object_clipper.reset(); m_c->m_supports_clipper.reset(); @@ -998,8 +1001,8 @@ void GLGizmoHollow::on_stop_dragging() void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar) { - ar(m_clipping_plane_distance, - *m_clipping_plane, + ar(m_c->m_clipping_plane_distance, + *m_c->m_clipping_plane, m_c->m_model_object_id, m_new_hole_radius, m_new_hole_height, @@ -1012,8 +1015,8 @@ void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar) void GLGizmoHollow::on_save(cereal::BinaryOutputArchive& ar) const { - ar(m_clipping_plane_distance, - *m_clipping_plane, + ar(m_c->m_clipping_plane_distance, + *m_c->m_clipping_plane, m_c->m_model_object_id, m_new_hole_radius, m_new_hole_height, @@ -1068,12 +1071,12 @@ void GLGizmoHollow::update_clipping_plane(bool keep_normal) const { if (! m_c->m_model_object) return; - Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ? - m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); + Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ? + m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift); float dist = normal.dot(center); - *m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius)); + *m_c->m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_c->m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius)); m_parent.set_as_dirty(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 5745b93934..6264304b73 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -70,13 +70,9 @@ private: float m_closing_d_stash = 2.f; Vec3f m_hole_before_drag = Vec3f::Zero(); - sla::DrainHoles m_holes_stash; - - - float m_clipping_plane_distance = 0.f; - std::unique_ptr m_clipping_plane; + //std::unique_ptr m_clipping_plane; // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index c1c3c6d1ce..879a09da2e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -27,7 +27,7 @@ GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& ic , m_quadric(nullptr) , m_its(nullptr) { - m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); + m_c->m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); m_quadric = ::gluNewQuadric(); if (m_quadric != nullptr) // using GLU_FILL does not work when the instance's transformation @@ -142,7 +142,7 @@ void GLGizmoSlaSupports::render_hollowed_mesh() const void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const { - if (m_clipping_plane_distance == 0.f || m_c->m_mesh->empty()) + if (m_c->m_clipping_plane_distance == 0.f || m_c->m_mesh->empty()) return; // Get transformation of the instance @@ -164,7 +164,7 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const m_c->m_object_clipper.reset(new MeshClipper); m_c->m_object_clipper->set_mesh(*m_c->mesh()); } - m_c->m_object_clipper->set_plane(*m_clipping_plane); + m_c->m_object_clipper->set_plane(*m_c->m_clipping_plane); m_c->m_object_clipper->set_transformation(trafo); @@ -195,7 +195,7 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const m_c->m_supports_clipper->set_mesh(print_object->support_mesh()); m_c->m_old_timestamp = timestamp; } - m_c->m_supports_clipper->set_plane(*m_clipping_plane); + m_c->m_supports_clipper->set_plane(*m_c->m_clipping_plane); m_c->m_supports_clipper->set_transformation(supports_trafo); } else @@ -382,12 +382,12 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const { - if (m_clipping_plane_distance == 0.f) + if (m_c->m_clipping_plane_distance == 0.f) return false; Vec3d transformed_point = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation().get_matrix() * point; transformed_point(2) += m_z_shift; - return m_clipping_plane->is_point_clipped(transformed_point); + return m_c->m_clipping_plane->is_point_clipped(transformed_point); } @@ -408,7 +408,7 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pairm_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) { + if (m_c->m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_c->m_clipping_plane.get())) { // Check whether the hit is in a hole bool in_hole = false; // In case the hollowed and drilled mesh is available, we can allow @@ -502,7 +502,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous points_inside.push_back(points[idx].cast()); // Only select/deselect points that are actually visible - for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_clipping_plane.get())) + for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_c->m_clipping_plane.get())) { if (rectangle_status == GLSelectionRectangle::Deselect) unselect_point(points_idxs[idx]); @@ -579,13 +579,13 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } if (action == SLAGizmoEventType::MouseWheelUp && control_down) { - m_clipping_plane_distance = std::min(1.f, m_clipping_plane_distance + 0.01f); + m_c->m_clipping_plane_distance = std::min(1.f, m_c->m_clipping_plane_distance + 0.01f); update_clipping_plane(true); return true; } if (action == SLAGizmoEventType::MouseWheelDown && control_down) { - m_clipping_plane_distance = std::max(0.f, m_clipping_plane_distance - 0.01f); + m_c->m_clipping_plane_distance = std::max(0.f, m_c->m_clipping_plane_distance - 0.01f); update_clipping_plane(true); return true; } @@ -666,10 +666,10 @@ std::vector GLGizmoSlaSupports::get_config_options(const st ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const { - if (!m_c->m_model_object || m_state == Off || m_clipping_plane_distance == 0.f) + if (!m_c->m_model_object || m_state == Off || m_c->m_clipping_plane_distance == 0.f) return ClippingPlane::ClipsNothing(); else - return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]); + return ClippingPlane(-m_c->m_clipping_plane->get_normal(), m_c->m_clipping_plane->get_data()[3]); } @@ -891,7 +891,7 @@ RENDER_AGAIN: // Following is rendered in both editing and non-editing mode: ImGui::Separator(); - if (m_clipping_plane_distance == 0.f) + if (m_c->m_clipping_plane_distance == 0.f) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("clipping_of_view")); @@ -906,7 +906,7 @@ RENDER_AGAIN: ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); - if (ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f")) + if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f")) update_clipping_plane(true); @@ -991,6 +991,10 @@ void GLGizmoSlaSupports::on_set_state() if (m_state == On && m_old_state != On) { // the gizmo was just turned on Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); + m_c->unstash_clipping_plane(); + update_clipping_plane(m_c->m_clipping_plane_distance != 0.f); + + // we'll now reload support points: if (m_c->m_model_object) reload_cache(); @@ -1026,8 +1030,9 @@ void GLGizmoSlaSupports::on_set_state() Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off"))); m_parent.toggle_model_objects_visibility(true); m_normal_cache.clear(); - m_clipping_plane_distance = 0.f; - update_clipping_plane(); + m_c->stash_clipping_plane(); + m_c->m_clipping_plane_distance = 0.f; + update_clipping_plane(true); // Release clippers and the AABB raycaster. m_its = nullptr; m_c->m_object_clipper.reset(); @@ -1072,8 +1077,8 @@ void GLGizmoSlaSupports::on_stop_dragging() void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar) { - ar(m_clipping_plane_distance, - *m_clipping_plane, + ar(m_c->m_clipping_plane_distance, + *m_c->m_clipping_plane, m_c->m_model_object_id, m_new_point_head_diameter, m_normal_cache, @@ -1086,8 +1091,8 @@ void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar) void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const { - ar(m_clipping_plane_distance, - *m_clipping_plane, + ar(m_c->m_clipping_plane_distance, + *m_c->m_clipping_plane, m_c->m_model_object_id, m_new_point_head_diameter, m_normal_cache, @@ -1286,12 +1291,12 @@ bool GLGizmoSlaSupports::unsaved_changes() const void GLGizmoSlaSupports::update_clipping_plane(bool keep_normal) const { - Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ? - m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); + Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ? + m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift); float dist = normal.dot(center); - *m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius)); + *m_c->m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_c->m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius)); m_parent.set_as_dirty(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 152979f83d..7ded6aadb4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -103,8 +103,7 @@ private: mutable std::vector m_editing_cache; // a support point and whether it is currently selected std::vector m_normal_cache; // to restore after discarding changes or undo/redo - float m_clipping_plane_distance = 0.f; - std::unique_ptr m_clipping_plane; + //std::unique_ptr m_clipping_plane; // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. From d407fda43326f4a767c85b6b7a4c900fe70a4e5b Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 3 Feb 2020 14:45:26 +0100 Subject: [PATCH 17/27] Hollowing gizmo - controls layout improvements --- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 30 +++++++++++++------------ 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 3db5e1e132..b585a8e4f2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -40,7 +40,7 @@ bool GLGizmoHollow::on_init() { m_shortcut_key = WXK_CONTROL_H; m_desc["enable"] = _(L("Hollow this object")); - m_desc["preview"] = _(L("Preview")); + m_desc["preview"] = _(L("Preview hollowed and drilled model")); m_desc["offset"] = _(L("Offset")) + ": "; m_desc["quality"] = _(L("Quality")) + ": "; m_desc["closing_distance"] = _(L("Closing distance")) + ": "; @@ -661,18 +661,24 @@ RENDER_AGAIN: // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: const float settings_sliders_left = - std::max(std::max(m_imgui->calc_text_size(m_desc.at("offset")).x, - m_imgui->calc_text_size(m_desc.at("quality")).x), - m_imgui->calc_text_size(m_desc.at("closing_distance")).x) - + m_imgui->scaled(1.f); + std::max({m_imgui->calc_text_size(m_desc.at("offset")).x, + m_imgui->calc_text_size(m_desc.at("quality")).x, + m_imgui->calc_text_size(m_desc.at("closing_distance")).x, + m_imgui->calc_text_size(m_desc.at("hole_diameter")).x, + m_imgui->calc_text_size(m_desc.at("hole_depth")).x}) + + m_imgui->scaled(1.f); const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); - const float diameter_slider_left = m_imgui->calc_text_size(m_desc.at("hole_diameter")).x + m_imgui->scaled(1.f); + const float diameter_slider_left = settings_sliders_left; //m_imgui->calc_text_size(m_desc.at("hole_diameter")).x + m_imgui->scaled(1.f); const float minimal_slider_width = m_imgui->scaled(4.f); - //const float buttons_width_approx = m_imgui->calc_text_size(m_desc.at("apply_changes")).x + m_imgui->calc_text_size(m_desc.at("discard_changes")).x + m_imgui->scaled(1.5f); - float window_width = minimal_slider_width + std::max(std::max(settings_sliders_left, clipping_slider_left), diameter_slider_left); - window_width = std::max(std::max(window_width, /*buttons_width_approx*/0.f), 0.f); + float window_width = minimal_slider_width + std::max({settings_sliders_left, clipping_slider_left, diameter_slider_left}); + window_width = std::max(window_width, m_imgui->calc_text_size(m_desc.at("preview")).x); + + if (m_imgui->button(m_desc["preview"])) + hollow_mesh(); + + ImGui::Separator(); { auto opts = get_config_options({"hollowing_enable"}); @@ -683,10 +689,6 @@ RENDER_AGAIN: } } - ImGui::SameLine(); - if (m_imgui->button(m_desc["preview"])) - hollow_mesh(); - m_imgui->disabled_begin(! m_enable_hollowing); std::vector opts_keys = {"hollowing_min_thickness", "hollowing_quality", "hollowing_closing_distance"}; @@ -911,7 +913,7 @@ bool GLGizmoHollow::on_is_selectable() const std::string GLGizmoHollow::on_get_name() const { - return (_(L("Hollowing")) + " [H]").ToUTF8().data(); + return (_(L("Hollowing and drilling")) + " [H]").ToUTF8().data(); } From 227cc4dc3378c1350618f12f2f1b61437666f92b Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 3 Feb 2020 15:42:54 +0100 Subject: [PATCH 18/27] Fixed conflicts after merge slaposHollowing was divided into slaposHollowing and slaposDrillHoles on master This commit takes this into account on the code that was merged from lm_drilling_backend_rebased --- src/libslic3r/SLAPrint.cpp | 6 +++--- src/libslic3r/SLAPrint.hpp | 2 +- src/libslic3r/SLAPrintSteps.cpp | 4 ++-- src/slic3r/GUI/GLCanvas3D.cpp | 10 ++++------ src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 2 +- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index e98e0edc41..06c4f687b9 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -419,7 +419,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con if (model_object.sla_drain_holes != model_object_new.sla_drain_holes) { model_object.sla_drain_holes = model_object_new.sla_drain_holes; - update_apply_status(it_print_object_status->print_object->invalidate_step(slaposHollowing)); + update_apply_status(it_print_object_status->print_object->invalidate_step(slaposDrillHoles)); } // Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step. @@ -1101,7 +1101,7 @@ const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const bool SLAPrintObject::has_mesh(SLAPrintObjectStep step) const { switch (step) { - case slaposHollowing: + case slaposDrillHoles: return m_hollowing_data && !m_hollowing_data->hollow_mesh_with_holes.empty(); case slaposSupportTree: return ! this->support_mesh().empty(); @@ -1119,7 +1119,7 @@ TriangleMesh SLAPrintObject::get_mesh(SLAPrintObjectStep step) const return this->support_mesh(); case slaposPad: return this->pad_mesh(); - case slaposHollowing: + case slaposDrillHoles: if (m_hollowing_data) return m_hollowing_data->hollow_mesh_with_holes; [[fallthrough]]; diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index d2f1212776..df052a9c75 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -78,7 +78,7 @@ public: // Support mesh is only valid if this->is_step_done(slaposPad) is true. const TriangleMesh& pad_mesh() const; - // Ready after this->is_step_done(slaposHollowing) is true + // Ready after this->is_step_done(slaposDrillHoles) is true const TriangleMesh& hollowed_interior_mesh() const; // Get the mesh that is going to be printed with all the modifications diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index 4bb6be7b02..4e19abd587 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -27,7 +27,7 @@ namespace { const std::array OBJ_STEP_LEVELS = { 10, // slaposHollowing, - 10, // slaposDrillHolesIfHollowed + 10, // slaposDrillHoles 10, // slaposObjectSlice, 20, // slaposSupportPoints, 10, // slaposSupportTree, @@ -39,7 +39,7 @@ std::string OBJ_STEP_LABELS(size_t idx) { switch (idx) { case slaposHollowing: return L("Hollowing model"); - case slaposDrillHoles: return L("Drilling holes into hollowed model."); + case slaposDrillHoles: return L("Drilling holes into model."); case slaposObjectSlice: return L("Slicing model"); case slaposSupportPoints: return L("Generating support points"); case slaposSupportTree: return L("Generating support tree"); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1e90b85c5d..3d0730198b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1978,7 +1978,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // SLA steps to pull the preview meshes for. typedef std::array SLASteps; - SLASteps sla_steps = { slaposHollowing, slaposSupportTree, slaposPad }; + SLASteps sla_steps = { slaposDrillHoles, slaposSupportTree, slaposPad }; struct SLASupportState { std::array::value> step; }; @@ -2025,7 +2025,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // Consider the DONE step without a valid mesh as invalid for the purpose // of mesh visualization. state.step[istep].state = PrintStateBase::INVALID; - else if (sla_steps[istep] != slaposHollowing) + else if (sla_steps[istep] != slaposDrillHoles) for (const ModelInstance* model_instance : print_object->model_object()->instances) // Only the instances, which are currently printable, will have the SLA support structures kept. // The instances outside the print bed will have the GLVolumes of their support structures released. @@ -2169,7 +2169,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re assert(it != model_object->instances.end()); int instance_idx = it - model_object->instances.begin(); for (size_t istep = 0; istep < sla_steps.size(); ++ istep) - if (sla_steps[istep] == slaposHollowing) { + if (sla_steps[istep] == slaposDrillHoles) { // Hollowing is a special case, where the mesh from the backend is being loaded into the 1st volume of an instance, // not into its own GLVolume. // There shall always be such a GLVolume allocated. @@ -2182,7 +2182,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen. volume.indexed_vertex_array.release_geometry(); if (state.step[istep].state == PrintStateBase::DONE) { - TriangleMesh mesh = print_object->get_mesh(slaposHollowing); + TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles); assert(! mesh.empty()); mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse()); volume.indexed_vertex_array.load_mesh(mesh); @@ -6106,8 +6106,6 @@ void GLCanvas3D::_load_sla_shells() unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); for (const SLAPrintObject::Instance& instance : obj->instances()) { add_volume(*obj, 0, instance, obj->get_mesh_to_print(), GLVolume::MODEL_COLOR[0], true); -// if (! obj->hollowed_interior_mesh().empty()) -// add_volume(*obj, -int(slaposHollowing), instance, obj->hollowed_interior_mesh(), GLVolume::MODEL_COLOR[0], false); // Set the extruder_id and volume_id to achieve the same color as in the 3D scene when // through the update_volumes_colors_by_extruder() call. m_volumes.volumes.back()->extruder_id = obj->model_object()->volumes.front()->extruder_id(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 653bfefb5b..af022352e0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -354,7 +354,7 @@ bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* mode // saved, a copy is stored as a member (FIXME) if (m_print_object_idx >=0) { const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx]; - if (po->is_step_done(slaposHollowing)) { + if (po->is_step_done(slaposDrillHoles)) { m_backend_mesh_transformed = po->get_mesh_to_print(); m_backend_mesh_transformed.transform(canvas.sla_print()->sla_trafo(*m_model_object).inverse()); m_mesh = &m_backend_mesh_transformed; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8afd98d11e..57e0c787c9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5130,7 +5130,7 @@ void Plater::reslice_SLA_supports(const ModelObject &object, bool postpone_error void Plater::reslice_SLA_hollowing(const ModelObject &object, bool postpone_error_messages) { - reslice_SLA_until_step(slaposHollowing, object, postpone_error_messages); + reslice_SLA_until_step(slaposDrillHoles, object, postpone_error_messages); } void Plater::reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &object, bool postpone_error_messages) From 03680bb01442855ed93bcbdde8305e99eb420ed1 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 3 Feb 2020 15:47:09 +0100 Subject: [PATCH 19/27] Follow-up of 3a99b23ec762cd1ad9b4c5cbb4373d386bfe4b66 -> F5 accelerator added also to objects list --- src/slic3r/GUI/GUI_ObjectList.cpp | 2 ++ src/slic3r/GUI/Plater.cpp | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 33ddd475cd..d630f152f1 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -978,6 +978,8 @@ void ObjectList::key_event(wxKeyEvent& event) ) { remove(); } + else if (event.GetKeyCode() == WXK_F5) + wxGetApp().plater()->reload_all_from_disk(); else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/)) select_item_all_children(); else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL)) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8afd98d11e..f0ca1aa392 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2076,7 +2076,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, [this](SimpleEvent&) { this->view3D->get_canvas3d()->reset_layer_height_profile(); }); view3D_canvas->Bind(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, [this](Event& evt) { this->view3D->get_canvas3d()->adaptive_layer_height_profile(evt.data); }); view3D_canvas->Bind(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, [this](HeightProfileSmoothEvent& evt) { this->view3D->get_canvas3d()->smooth_layer_height_profile(evt.data); }); - view3D_canvas->Bind(EVT_GLCANVAS_RELOAD_FROM_DISK, [this](SimpleEvent&) { if (!this->model.objects.empty()) this->reload_all_from_disk(); }); + view3D_canvas->Bind(EVT_GLCANVAS_RELOAD_FROM_DISK, [this](SimpleEvent&) { this->reload_all_from_disk(); }); // 3DScene/Toolbar: view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this); @@ -3451,6 +3451,9 @@ void Plater::priv::reload_from_disk() void Plater::priv::reload_all_from_disk() { + if (model.objects.empty()) + return; + Plater::TakeSnapshot snapshot(q, _(L("Reload all from disk"))); Plater::SuppressSnapshots suppress(q); From 0c4797e92ed0581fddb23949dce3c0dea9c9b577 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 3 Feb 2020 11:18:33 +0100 Subject: [PATCH 20/27] use vsnprintf instead of snprintf in string_printf function Also, revert to old location: Utils.hpp and utils.cpp --- src/libslic3r/Utils.hpp | 2 ++ src/libslic3r/libslic3r.h | 17 ----------------- src/libslic3r/utils.cpp | 21 +++++++++++++++++++++ tests/libslic3r/libslic3r_tests.cpp | 2 +- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index bc6aa20fc5..06c4358099 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -93,6 +93,8 @@ namespace PerlUtils { extern std::string path_to_parent_path(const char *src); }; +std::string string_printf(const char *format, ...); + // Standard "generated by Slic3r version xxx timestamp xxx" header string, // to be placed at the top of Slic3r generated files. std::string header_slic3r_generated(); diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index 7d9558f1e5..d3e4992ce8 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -230,23 +230,6 @@ static inline bool is_approx(Number value, Number test_value) return std::fabs(double(value) - double(test_value)) < double(EPSILON); } -template -std::string string_printf(const char *const _fmt, Args &&...args) -{ - static const size_t INITIAL_LEN = 1024; - std::vector buffer(INITIAL_LEN, '\0'); - - auto fmt = std::string("%s") + _fmt; - int bufflen = snprintf(buffer.data(), INITIAL_LEN - 1, fmt.c_str(), "", std::forward(args)...); - - if (bufflen >= int(INITIAL_LEN)) { - buffer.resize(size_t(bufflen) + 1); - snprintf(buffer.data(), buffer.size(), fmt.c_str(), "", std::forward(args)...); - } - - return std::string(buffer.begin(), buffer.begin() + bufflen); -} - } // namespace Slic3r #endif diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 9f0afa0614..f78a2b54d5 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -577,6 +577,27 @@ namespace PerlUtils { std::string path_to_parent_path(const char *src) { return boost::filesystem::path(src).parent_path().string(); } }; + +std::string string_printf(const char *format, ...) +{ + va_list args1; + va_start(args1, format); + va_list args2; + va_copy(args2, args1); + + static const size_t INITIAL_LEN = 1024; + std::vector buffer(INITIAL_LEN, '\0'); + + int bufflen = ::vsnprintf(buffer.data(), INITIAL_LEN - 1, format, args1); + + if (bufflen >= int(INITIAL_LEN)) { + buffer.resize(size_t(bufflen) + 1); + ::vsnprintf(buffer.data(), buffer.size(), format, args2); + } + + return std::string(buffer.begin(), buffer.begin() + bufflen); +} + std::string header_slic3r_generated() { return std::string("generated by " SLIC3R_APP_NAME " " SLIC3R_VERSION " on " ) + Utils::utc_timestamp(); diff --git a/tests/libslic3r/libslic3r_tests.cpp b/tests/libslic3r/libslic3r_tests.cpp index b9c615d90a..f4dcab42a0 100644 --- a/tests/libslic3r/libslic3r_tests.cpp +++ b/tests/libslic3r/libslic3r_tests.cpp @@ -1,6 +1,6 @@ #include -#include "libslic3r/libslic3r.h" +#include "libslic3r/Utils.hpp" namespace { From e042cab8faaeb47da363314839236071003c6083 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 3 Feb 2020 16:05:13 +0100 Subject: [PATCH 21/27] Follow-up of 8453c8848238c1bb20bc7dc85cad4763203534c9, c09091c40703bdfae84e4bee3094bf6db23d8487 and 9d55121695126c113cb2eb4b65115320840dca39 -> Use key down event in place of key up event --- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 33 ++++++++++------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index ae47fcfc8e..4e4f716f49 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -776,6 +776,18 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) processed = true; } } + +// if (processed) +// m_parent.set_cursor(GLCanvas3D::Standard); + } + else if (evt.GetEventType() == wxEVT_KEY_DOWN) + { + if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) + && dynamic_cast(get_current())->is_in_editing_mode()) + { +// m_parent.set_cursor(GLCanvas3D::Cross); + processed = true; + } else if (m_current == Move) { auto do_move = [this, &processed](const Vec3d& displacement) { @@ -784,7 +796,6 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) selection.translate(displacement); wxGetApp().obj_manipul()->set_dirty(); m_parent.do_move(L("Gizmo-Move")); - m_parent.set_as_dirty(); processed = true; }; @@ -805,16 +816,13 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) selection.rotate(rotation, TransformationType(TransformationType::World_Relative_Joint)); wxGetApp().obj_manipul()->set_dirty(); m_parent.do_rotate(L("Gizmo-Rotate")); - m_parent.set_as_dirty(); processed = true; }; switch (keyCode) { - case WXK_NUMPAD_LEFT: case WXK_LEFT: { do_rotate(Vec3d(0.0, 0.0, 0.5 * M_PI)); break; } - case WXK_NUMPAD_RIGHT: case WXK_RIGHT: { do_rotate(-Vec3d(0.0, 0.0, 0.5 * M_PI)); break; } - case WXK_NUMPAD_UP: case WXK_UP: { do_rotate(Vec3d(0.0, 0.0, 0.25 * M_PI)); break; } - case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_rotate(-Vec3d(0.0, 0.0, 0.25 * M_PI)); break; } + case WXK_NUMPAD_LEFT: case WXK_LEFT: { do_rotate(Vec3d(0.0, 0.0, 0.25 * M_PI)); break; } + case WXK_NUMPAD_RIGHT: case WXK_RIGHT: { do_rotate(-Vec3d(0.0, 0.0, 0.25 * M_PI)); break; } default: { break; } } } @@ -823,7 +831,6 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) auto do_move = [this, &processed](double delta_z) { GLGizmoCut* cut = dynamic_cast(get_current()); cut->set_cut_z(delta_z + cut->get_cut_z()); - m_parent.set_as_dirty(); processed = true; }; @@ -834,18 +841,6 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) default: { break; } } } - -// if (processed) -// m_parent.set_cursor(GLCanvas3D::Standard); - } - else if (evt.GetEventType() == wxEVT_KEY_DOWN) - { - if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) - && dynamic_cast(get_current())->is_in_editing_mode()) - { -// m_parent.set_cursor(GLCanvas3D::Cross); - processed = true; - } } if (processed) From ad3e3be3bc6a643405abc7e6cf3c90e8bd67539e Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 3 Feb 2020 17:11:24 +0100 Subject: [PATCH 22/27] optimize string_printf --- src/libslic3r/utils.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index f78a2b54d5..c451507779 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -585,8 +585,8 @@ std::string string_printf(const char *format, ...) va_list args2; va_copy(args2, args1); - static const size_t INITIAL_LEN = 1024; - std::vector buffer(INITIAL_LEN, '\0'); + static const size_t INITIAL_LEN = 200; + std::string buffer(INITIAL_LEN, '\0'); int bufflen = ::vsnprintf(buffer.data(), INITIAL_LEN - 1, format, args1); @@ -595,7 +595,9 @@ std::string string_printf(const char *format, ...) ::vsnprintf(buffer.data(), buffer.size(), format, args2); } - return std::string(buffer.begin(), buffer.begin() + bufflen); + buffer.resize(bufflen); + + return buffer; } std::string header_slic3r_generated() From d0f21dda4aad7e956e50a3dfb194b45c08c177b0 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 3 Feb 2020 17:29:15 +0100 Subject: [PATCH 23/27] Make sure that when drill holes are manipulated with, all data are invalidated properly It is needed to regenerate hollow_mesh_with_holes completely, it may contain holes that were deleted by the user in the meantime --- src/libslic3r/SLAPrint.hpp | 2 +- src/libslic3r/SLAPrintSteps.cpp | 42 +++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index df052a9c75..c9f5198db8 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -84,7 +84,7 @@ public: // Get the mesh that is going to be printed with all the modifications // like hollowing and drilled holes. const TriangleMesh & get_mesh_to_print() const { - return m_hollowing_data ? m_hollowing_data->hollow_mesh_with_holes : transformed_mesh(); + return (m_hollowing_data && is_step_done(slaposDrillHoles)) ? m_hollowing_data->hollow_mesh_with_holes : transformed_mesh(); } // This will return the transformed mesh which is cached diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index 4e19abd587..b7d1cfa1d8 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -99,17 +99,37 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po) else { po.m_hollowing_data.reset(new SLAPrintObject::HollowingData()); po.m_hollowing_data->interior = *meshptr; - auto &hollowed_mesh = po.m_hollowing_data->hollow_mesh_with_holes; - hollowed_mesh = po.transformed_mesh(); - hollowed_mesh.merge(po.m_hollowing_data->interior); - hollowed_mesh.require_shared_vertices(); } } +// Drill holes into the hollowed/original mesh. void SLAPrint::Steps::drill_holes(SLAPrintObject &po) { - // Drill holes into the hollowed/original mesh. - if (po.m_model_object->sla_drain_holes.empty()) { + bool needs_drilling = ! po.m_model_object->sla_drain_holes.empty(); + bool is_hollowed = (po.m_hollowing_data && ! po.m_hollowing_data->interior.empty()); + + if (! is_hollowed && ! needs_drilling) { + // In this case we can dump any data that might have been + // generated on previous runs. + po.m_hollowing_data.reset(); + return; + } + + if (! po.m_hollowing_data) + po.m_hollowing_data.reset(new SLAPrintObject::HollowingData()); + + // Hollowing and/or drilling is active, m_hollowing_data is valid. + + // Regenerate hollowed mesh, even if it was there already. It may contain + // holes that are no longer on the frontend. + TriangleMesh &hollowed_mesh = po.m_hollowing_data->hollow_mesh_with_holes; + hollowed_mesh = po.transformed_mesh(); + if (! po.m_hollowing_data->interior.empty()) { + hollowed_mesh.merge(po.m_hollowing_data->interior); + hollowed_mesh.require_shared_vertices(); + } + + if (! needs_drilling) { BOOST_LOG_TRIVIAL(info) << "Drilling skipped (no holes)."; return; } @@ -125,17 +145,9 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po) holes_mesh.require_shared_vertices(); MeshBoolean::cgal::self_union(holes_mesh); //FIXME-fix and use the cgal version - // If there is no hollowed mesh yet, copy the original mesh. - if (! po.m_hollowing_data) { - po.m_hollowing_data.reset(new SLAPrintObject::HollowingData()); - po.m_hollowing_data->hollow_mesh_with_holes = po.transformed_mesh(); - } - - TriangleMesh &hollowed_mesh = po.m_hollowing_data->hollow_mesh_with_holes; - try { MeshBoolean::cgal::minus(hollowed_mesh, holes_mesh); - } catch (const std::runtime_error &ex) { + } catch (const std::runtime_error&) { throw std::runtime_error(L( "Drilling holes into the mesh failed. " "This is usually caused by broken model. Try to fix it first.")); From d320a03c545de70a24d2ced024334934f5823a44 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 3 Feb 2020 21:27:53 +0100 Subject: [PATCH 24/27] DoubleSlider: Added using of default colors for color changes in SingleExtruder Mode (#3449) + added missed input parameter to the BitmapCache::mksolid() which was cause a wrong drawing of the Extruder selector under OSX --- src/slic3r/GUI/BitmapCache.hpp | 2 +- src/slic3r/GUI/DoubleSlider.cpp | 41 +++++++++++++++++++++++++-------- src/slic3r/GUI/DoubleSlider.hpp | 14 ++++++++--- src/slic3r/GUI/GUI_Preview.cpp | 7 ++++++ 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp index dd3e6ffc0d..e12beb5c72 100644 --- a/src/slic3r/GUI/BitmapCache.hpp +++ b/src/slic3r/GUI/BitmapCache.hpp @@ -35,7 +35,7 @@ public: wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false, const bool dark_mode = false); /*static */wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, bool suppress_scaling = false); - /*static */wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3], bool suppress_scaling = false) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); } + /*static */wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3], bool suppress_scaling = false) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE, suppress_scaling); } /*static */wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); } static bool parse_color(const std::string& scolor, unsigned char* rgb_out); diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 4a5bea9a10..5990984b02 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -1,4 +1,5 @@ #include "wxExtensions.hpp" +#include "libslic3r/GCode/PreviewData.hpp" #include "GUI.hpp" #include "GUI_App.hpp" #include "I18N.hpp" @@ -322,7 +323,8 @@ void Control::SetTicksValues(const CustomGCode::Info& custom_gcode_per_print_z) // Switch to the "Feature type"/"Tool" from the very beginning of a new object slicing after deleting of the old one post_ticks_changed_event(); - m_ticks.mode = custom_gcode_per_print_z.mode; + if (custom_gcode_per_print_z.mode) + m_ticks.mode = custom_gcode_per_print_z.mode; Refresh(); Update(); @@ -1169,6 +1171,8 @@ void Control::OnKeyDown(wxKeyEvent &event) m_ticks.suppress_minus(true); delete_current_tick(); } + else if (event.GetKeyCode() == WXK_SHIFT) + UseDefaultColors(false); else if (is_horizontal()) { if (key == WXK_LEFT || key == WXK_RIGHT) @@ -1194,6 +1198,9 @@ void Control::OnKeyUp(wxKeyEvent &event) { if (event.GetKeyCode() == WXK_CONTROL) m_is_one_layer = false; + else if (event.GetKeyCode() == WXK_SHIFT) + UseDefaultColors(true); + Refresh(); Update(); event.Skip(); @@ -1278,9 +1285,11 @@ std::array Control::get_active_extruders_for_tick(int tick) const // Get used extruders for tick. // Means all extruders(tools) which will be used during printing from current tick to the end -std::set TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extruder, double print_z) const +std::set TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extruder, double print_z, t_mode force_mode/* = t_mode::Undef*/) const { - if (mode == t_mode::MultiExtruder) + t_mode e_mode = !force_mode ? mode : force_mode; + + if (e_mode == t_mode::MultiExtruder) { // #ys_FIXME: get tool ordering from _correct_ place const ToolOrdering& tool_ordering = GUI::wxGetApp().plater()->fff_print().get_tool_ordering(); @@ -1301,8 +1310,8 @@ std::set TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extru return used_extruders; } - const int default_initial_extruder = mode == t_mode::MultiAsSingle ? std::max(only_extruder, 1) : 1; - if (ticks.empty()) + const int default_initial_extruder = e_mode == t_mode::MultiAsSingle ? std::max(only_extruder, 1) : 1; + if (ticks.empty() || e_mode == t_mode::SingleExtruder) return {default_initial_extruder}; std::set used_extruders; @@ -1346,10 +1355,13 @@ void Control::OnRightUp(wxMouseEvent& event) if (m_show_context_menu) { wxMenu menu; - if (m_mode == t_mode::SingleExtruder) + if (m_mode == t_mode::SingleExtruder) { append_menu_item(&menu, wxID_ANY, _(L("Add color change")) + " (M600)", "", [this](wxCommandEvent&) { add_code_as_tick(ColorChangeCode); }, "colorchange_add_m", &menu, [](){return true;}, this); + + UseDefaultColors(false); + } else { append_change_extruder_menu_item(&menu); @@ -1688,9 +1700,18 @@ bool Control::check_ticks_changed_event(const std::string& gcode) return true; } - std::string TickCodeInfo::get_color_for_tick(TickCode tick, const std::string& code, const int extruder) { + if (mode == t_mode::SingleExtruder && code == ColorChangeCode && m_use_default_colors) + { + const std::vector& colors = GCodePreviewData::ColorPrintColors(); + if (ticks.empty()) + return colors[0]; + m_default_color_idx++; + + return colors[m_default_color_idx % colors.size()]; + } + std::vector colors = GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); std::string color = colors[extruder - 1]; @@ -1740,6 +1761,9 @@ bool TickCodeInfo::add_tick(const int tick, std::string& code, const int extrude return false; } + if (mode == t_mode::SingleExtruder) + m_use_default_colors = true; + ticks.emplace(TickCode{ tick, code, extruder, color }); return true; } @@ -1840,7 +1864,7 @@ ConflictType TickCodeInfo::is_conflict_tick(const TickCode& tick, t_mode out_mod { // We should mark a tick as a "MeaninglessColorChange", // if it has a ColorChange for unused extruder from current print to end of the print - std::set used_extruders_for_tick = get_used_extruders_for_tick(tick.tick, only_extruder, print_z); + std::set used_extruders_for_tick = get_used_extruders_for_tick(tick.tick, only_extruder, print_z, out_mode); if (used_extruders_for_tick.find(tick.extruder) == used_extruders_for_tick.end()) return ctMeaninglessColorChange; @@ -1868,7 +1892,6 @@ ConflictType TickCodeInfo::is_conflict_tick(const TickCode& tick, t_mode out_mod { // We should mark a tick as a "MeaninglessToolChange", // if it has a ToolChange to the same extruder - auto it = ticks.find(tick); if (it == ticks.begin()) return tick.extruder == std::max(only_extruder, 1) ? ctMeaninglessToolChange : ctNone; diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp index f14af621f9..01181fc2f5 100644 --- a/src/slic3r/GUI/DoubleSlider.hpp +++ b/src/slic3r/GUI/DoubleSlider.hpp @@ -67,12 +67,14 @@ class TickCodeInfo std::string pause_print_msg; bool m_suppress_plus = false; bool m_suppress_minus = false; + bool m_use_default_colors= false; + int m_default_color_idx = 0; std::string get_color_for_tick(TickCode tick, const std::string& code, const int extruder); public: - std::set ticks {}; - t_mode mode = t_mode::SingleExtruder; + std::set ticks {}; + t_mode mode = t_mode::Undef; bool empty() const { return ticks.empty(); } void set_pause_print_msg(const std::string& message) { pause_print_msg = message; } @@ -88,12 +90,13 @@ public: // Get used extruders for tick. // Means all extruders(tools) which will be used during printing from current tick to the end - std::set get_used_extruders_for_tick(int tick, int only_extruder, double print_z) const; + std::set get_used_extruders_for_tick(int tick, int only_extruder, double print_z, t_mode force_mode = t_mode::Undef) const; void suppress_plus (bool suppress) { m_suppress_plus = suppress; } void suppress_minus(bool suppress) { m_suppress_minus = suppress; } bool suppressed_plus () { return m_suppress_plus; } bool suppressed_minus() { return m_suppress_minus; } + void set_default_colors(bool default_colors_on) { m_use_default_colors = default_colors_on; } }; @@ -186,7 +189,11 @@ public: m_mode = !is_one_extruder_printed_model ? t_mode::MultiExtruder : only_extruder < 0 ? t_mode::SingleExtruder : t_mode::MultiAsSingle; + if (!m_ticks.mode) + m_ticks.mode = m_mode; m_only_extruder = only_extruder; + + UseDefaultColors(m_mode == t_mode::SingleExtruder); } bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; } @@ -201,6 +208,7 @@ public: void OnLeftUp(wxMouseEvent& event); void OnEnterWin(wxMouseEvent& event) { enter_window(event, true); } void OnLeaveWin(wxMouseEvent& event) { enter_window(event, false); } + void UseDefaultColors(bool def_colors_on) { m_ticks.set_default_colors(def_colors_on); } void OnWheel(wxMouseEvent& event); void OnKeyDown(wxKeyEvent &event); void OnKeyUp(wxKeyEvent &event); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index e42f8ed216..25862b72d7 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -591,6 +591,11 @@ void Preview::create_double_slider() // sizer, m_canvas_widget m_canvas_widget->Bind(wxEVT_KEY_DOWN, &Preview::update_double_slider_from_canvas, this); + m_canvas_widget->Bind(wxEVT_KEY_UP, [this](wxKeyEvent& event) { + if (event.GetKeyCode() == WXK_SHIFT) + m_slider->UseDefaultColors(true); + event.Skip(); + }); m_slider->Bind(wxEVT_SCROLL_CHANGED, &Preview::on_sliders_scroll_changed, this); @@ -776,6 +781,8 @@ void Preview::update_double_slider_from_canvas(wxKeyEvent& event) } else if (key == 'S') m_slider->ChangeOneLayerLock(); + else if (key == WXK_SHIFT) + m_slider->UseDefaultColors(false); else event.Skip(); } From 3371fa42daae024e15ccb31bec84f0fae1431618 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 4 Feb 2020 09:32:09 +0100 Subject: [PATCH 25/27] Follow-up of e042cab8faaeb47da363314839236071003c6083 -> Avoid polluting undo/redo stack --- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 54 ++++++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 4e4f716f49..8e2923cacf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -776,6 +776,56 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) processed = true; } } + else if (m_current == Move) + { + switch (keyCode) + { + case WXK_NUMPAD_LEFT: case WXK_LEFT: + case WXK_NUMPAD_RIGHT: case WXK_RIGHT: + case WXK_NUMPAD_UP: case WXK_UP: + case WXK_NUMPAD_DOWN: case WXK_DOWN: + { + m_parent.do_move(L("Gizmo-Move")); + stop_dragging(); + update_data(); + + wxGetApp().obj_manipul()->set_dirty(); + // Let the plater know that the dragging finished, so a delayed refresh + // of the scene with the background processing data should be performed. + m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); + // updates camera target constraints + m_parent.refresh_camera_scene_box(); + processed = true; + + break; + } + default: { break; } + } + } + else if (m_current == Rotate) + { + switch (keyCode) + { + case WXK_NUMPAD_LEFT: case WXK_LEFT: + case WXK_NUMPAD_RIGHT: case WXK_RIGHT: + { + m_parent.do_rotate(L("Gizmo-Rotate")); + stop_dragging(); + update_data(); + + wxGetApp().obj_manipul()->set_dirty(); + // Let the plater know that the dragging finished, so a delayed refresh + // of the scene with the background processing data should be performed. + m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); + // updates camera target constraints + m_parent.refresh_camera_scene_box(); + processed = true; + + break; + } + default: { break; } + } + } // if (processed) // m_parent.set_cursor(GLCanvas3D::Standard); @@ -793,9 +843,9 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) auto do_move = [this, &processed](const Vec3d& displacement) { Selection& selection = m_parent.get_selection(); selection.start_dragging(); + start_dragging(); selection.translate(displacement); wxGetApp().obj_manipul()->set_dirty(); - m_parent.do_move(L("Gizmo-Move")); processed = true; }; @@ -813,9 +863,9 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) auto do_rotate = [this, &processed](const Vec3d& rotation) { Selection& selection = m_parent.get_selection(); selection.start_dragging(); + start_dragging(); selection.rotate(rotation, TransformationType(TransformationType::World_Relative_Joint)); wxGetApp().obj_manipul()->set_dirty(); - m_parent.do_rotate(L("Gizmo-Rotate")); processed = true; }; From 648060f4ec8225425183714477e2c8eca360f7a9 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 4 Feb 2020 10:31:50 +0100 Subject: [PATCH 26/27] Smoother movements/rotations when using arrow keys --- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 8e2923cacf..b992fd7aef 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -845,7 +845,7 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) selection.start_dragging(); start_dragging(); selection.translate(displacement); - wxGetApp().obj_manipul()->set_dirty(); +// wxGetApp().obj_manipul()->set_dirty(); processed = true; }; @@ -860,19 +860,19 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) } else if (m_current == Rotate) { - auto do_rotate = [this, &processed](const Vec3d& rotation) { + auto do_rotate = [this, &processed](double angle_z_rad) { Selection& selection = m_parent.get_selection(); selection.start_dragging(); start_dragging(); - selection.rotate(rotation, TransformationType(TransformationType::World_Relative_Joint)); - wxGetApp().obj_manipul()->set_dirty(); + selection.rotate(Vec3d(0.0, 0.0, angle_z_rad), TransformationType(TransformationType::World_Relative_Joint)); +// wxGetApp().obj_manipul()->set_dirty(); processed = true; }; switch (keyCode) { - case WXK_NUMPAD_LEFT: case WXK_LEFT: { do_rotate(Vec3d(0.0, 0.0, 0.25 * M_PI)); break; } - case WXK_NUMPAD_RIGHT: case WXK_RIGHT: { do_rotate(-Vec3d(0.0, 0.0, 0.25 * M_PI)); break; } + case WXK_NUMPAD_LEFT: case WXK_LEFT: { do_rotate(0.25 * M_PI); break; } + case WXK_NUMPAD_RIGHT: case WXK_RIGHT: { do_rotate(-0.25 * M_PI); break; } default: { break; } } } From 87daba9288a8c00b08471af10cad09a09feffa89 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 4 Feb 2020 11:42:58 +0100 Subject: [PATCH 27/27] Movements and rotations by keyboard indipendent from gizmos: Left arrow = Decrease X by 1mm Right arrow = Increase X by 1mm Up arrow = Decrease Y by 1mm Down arrow = Increase Y by 1mm PgUp = Rotate 45 degrees CCW PgDown = Rotate 45 degrees CW --- src/slic3r/GUI/GLCanvas3D.cpp | 83 +++++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 88 ----------------------- 2 files changed, 76 insertions(+), 95 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 3d0730198b..e12e8c6612 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2743,6 +2743,46 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) } else if (keyCode == WXK_CONTROL) m_dirty = true; + else if (m_gizmos.is_enabled() && !m_selection.is_empty()) { + switch (keyCode) + { + case WXK_NUMPAD_LEFT: case WXK_LEFT: + case WXK_NUMPAD_RIGHT: case WXK_RIGHT: + case WXK_NUMPAD_UP: case WXK_UP: + case WXK_NUMPAD_DOWN: case WXK_DOWN: + { + do_move(L("Gizmo-Move")); + m_gizmos.update_data(); + + wxGetApp().obj_manipul()->set_dirty(); + // Let the plater know that the dragging finished, so a delayed refresh + // of the scene with the background processing data should be performed. + post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); + // updates camera target constraints + refresh_camera_scene_box(); + m_dirty = true; + + break; + } + case WXK_NUMPAD_PAGEUP: case WXK_PAGEUP: + case WXK_NUMPAD_PAGEDOWN: case WXK_PAGEDOWN: + { + do_rotate(L("Gizmo-Rotate")); + m_gizmos.update_data(); + + wxGetApp().obj_manipul()->set_dirty(); + // Let the plater know that the dragging finished, so a delayed refresh + // of the scene with the background processing data should be performed. + post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); + // updates camera target constraints + refresh_camera_scene_box(); + m_dirty = true; + + break; + } + default: { break; } + } + } } else if (evt.GetEventType() == wxEVT_KEY_DOWN) { m_tab_down = keyCode == WXK_TAB && !evt.HasAnyModifiers(); @@ -2764,14 +2804,43 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) } else if (keyCode == WXK_CONTROL) m_dirty = true; - // DoubleSlider navigation in Preview - else if (keyCode == WXK_LEFT || - keyCode == WXK_RIGHT || - keyCode == WXK_UP || - keyCode == WXK_DOWN ) + else if (m_gizmos.is_enabled() && !m_selection.is_empty()) { - if (dynamic_cast(m_canvas->GetParent()) != nullptr) - post_event(wxKeyEvent(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, evt)); + auto do_move = [this](const Vec3d& displacement) { + m_selection.start_dragging(); + m_selection.translate(displacement); + m_dirty = true; +// wxGetApp().obj_manipul()->set_dirty(); + }; + auto do_rotate = [this](double angle_z_rad) { + m_selection.start_dragging(); + m_selection.rotate(Vec3d(0.0, 0.0, angle_z_rad), TransformationType(TransformationType::World_Relative_Joint)); + m_dirty = true; +// wxGetApp().obj_manipul()->set_dirty(); + }; + + switch (keyCode) + { + case WXK_NUMPAD_LEFT: case WXK_LEFT: { do_move(-Vec3d::UnitX()); break; } + case WXK_NUMPAD_RIGHT: case WXK_RIGHT: { do_move(Vec3d::UnitX()); break; } + case WXK_NUMPAD_UP: case WXK_UP: { do_move(Vec3d::UnitY()); break; } + case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_move(-Vec3d::UnitY()); break; } + case WXK_NUMPAD_PAGEUP: case WXK_PAGEUP: { do_rotate(0.25 * M_PI); break; } + case WXK_NUMPAD_PAGEDOWN: case WXK_PAGEDOWN: { do_rotate(-0.25 * M_PI); break; } + default: { break; } + } + } + else if (!m_gizmos.is_enabled()) + { + // DoubleSlider navigation in Preview + if (keyCode == WXK_LEFT || + keyCode == WXK_RIGHT || + keyCode == WXK_UP || + keyCode == WXK_DOWN) + { + if (dynamic_cast(m_canvas->GetParent()) != nullptr) + post_event(wxKeyEvent(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, evt)); + } } } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index b992fd7aef..be0f480071 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -776,56 +776,6 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) processed = true; } } - else if (m_current == Move) - { - switch (keyCode) - { - case WXK_NUMPAD_LEFT: case WXK_LEFT: - case WXK_NUMPAD_RIGHT: case WXK_RIGHT: - case WXK_NUMPAD_UP: case WXK_UP: - case WXK_NUMPAD_DOWN: case WXK_DOWN: - { - m_parent.do_move(L("Gizmo-Move")); - stop_dragging(); - update_data(); - - wxGetApp().obj_manipul()->set_dirty(); - // Let the plater know that the dragging finished, so a delayed refresh - // of the scene with the background processing data should be performed. - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); - // updates camera target constraints - m_parent.refresh_camera_scene_box(); - processed = true; - - break; - } - default: { break; } - } - } - else if (m_current == Rotate) - { - switch (keyCode) - { - case WXK_NUMPAD_LEFT: case WXK_LEFT: - case WXK_NUMPAD_RIGHT: case WXK_RIGHT: - { - m_parent.do_rotate(L("Gizmo-Rotate")); - stop_dragging(); - update_data(); - - wxGetApp().obj_manipul()->set_dirty(); - // Let the plater know that the dragging finished, so a delayed refresh - // of the scene with the background processing data should be performed. - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); - // updates camera target constraints - m_parent.refresh_camera_scene_box(); - processed = true; - - break; - } - default: { break; } - } - } // if (processed) // m_parent.set_cursor(GLCanvas3D::Standard); @@ -838,44 +788,6 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt) // m_parent.set_cursor(GLCanvas3D::Cross); processed = true; } - else if (m_current == Move) - { - auto do_move = [this, &processed](const Vec3d& displacement) { - Selection& selection = m_parent.get_selection(); - selection.start_dragging(); - start_dragging(); - selection.translate(displacement); -// wxGetApp().obj_manipul()->set_dirty(); - processed = true; - }; - - switch (keyCode) - { - case WXK_NUMPAD_LEFT: case WXK_LEFT: { do_move(-Vec3d::UnitX()); break; } - case WXK_NUMPAD_RIGHT: case WXK_RIGHT: { do_move(Vec3d::UnitX()); break; } - case WXK_NUMPAD_UP: case WXK_UP: { do_move(Vec3d::UnitY()); break; } - case WXK_NUMPAD_DOWN: case WXK_DOWN: { do_move(-Vec3d::UnitY()); break; } - default: { break; } - } - } - else if (m_current == Rotate) - { - auto do_rotate = [this, &processed](double angle_z_rad) { - Selection& selection = m_parent.get_selection(); - selection.start_dragging(); - start_dragging(); - selection.rotate(Vec3d(0.0, 0.0, angle_z_rad), TransformationType(TransformationType::World_Relative_Joint)); -// wxGetApp().obj_manipul()->set_dirty(); - processed = true; - }; - - switch (keyCode) - { - case WXK_NUMPAD_LEFT: case WXK_LEFT: { do_rotate(0.25 * M_PI); break; } - case WXK_NUMPAD_RIGHT: case WXK_RIGHT: { do_rotate(-0.25 * M_PI); break; } - default: { break; } - } - } else if (m_current == Cut) { auto do_move = [this, &processed](double delta_z) {