From 4eb4e40746343f665cfc26527fd468a2c74a49b0 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 27 Feb 2019 16:23:10 +0100 Subject: [PATCH] SLA gizmo keeps track of current status of the points, enables the user to erase all points --- src/libslic3r/Model.cpp | 4 +++ src/libslic3r/Model.hpp | 3 +++ src/libslic3r/SLA/SLACommon.hpp | 8 ++++++ src/libslic3r/SLAPrint.cpp | 24 ++++++++++++++---- src/slic3r/GUI/GLGizmo.cpp | 43 +++++++++++++++++++++------------ src/slic3r/GUI/GLGizmo.hpp | 14 +++++------ 6 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 6e291412c..9c5f8c826 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -592,6 +592,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs) this->input_file = rhs.input_file; this->config = rhs.config; this->sla_support_points = rhs.sla_support_points; + this->sla_points_status = rhs.sla_points_status; this->layer_height_ranges = rhs.layer_height_ranges; this->layer_height_profile = rhs.layer_height_profile; this->origin_translation = rhs.origin_translation; @@ -625,6 +626,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs) this->input_file = std::move(rhs.input_file); this->config = std::move(rhs.config); this->sla_support_points = std::move(rhs.sla_support_points); + this->sla_points_status = std::move(rhs.sla_points_status); this->layer_height_ranges = std::move(rhs.layer_height_ranges); this->layer_height_profile = std::move(rhs.layer_height_profile); this->origin_translation = std::move(rhs.origin_translation); @@ -1130,6 +1132,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b if (keep_upper) { upper->set_model(nullptr); upper->sla_support_points.clear(); + upper->sla_points_status = sla::PointsStatus::None; upper->clear_volumes(); upper->input_file = ""; } @@ -1137,6 +1140,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b if (keep_lower) { lower->set_model(nullptr); lower->sla_support_points.clear(); + lower->sla_points_status = sla::PointsStatus::None; lower->clear_volumes(); lower->input_file = ""; } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index a215f9b9f..a4b32d93f 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -180,6 +180,9 @@ public: // saved in mesh coordinates to allow using them for several instances. // The format is (x, y, z, point_size, supports_island) std::vector sla_support_points; + // To keep track of where the points came from (used for synchronization between + // the SLA gizmo and the backend). + sla::PointsStatus sla_points_status = sla::PointsStatus::None; /* This vector accumulates the total translation applied to the object by the center_around_origin() method. Callers might want to apply the same translation diff --git a/src/libslic3r/SLA/SLACommon.hpp b/src/libslic3r/SLA/SLACommon.hpp index f7c0acf33..bdeead9ca 100644 --- a/src/libslic3r/SLA/SLACommon.hpp +++ b/src/libslic3r/SLA/SLACommon.hpp @@ -15,6 +15,14 @@ class TriangleMesh; namespace sla { +// An enum to keep track of where the current points on the ModelObject came from. +enum class PointsStatus { + None, // No points were generated so far. + Generating, // The autogeneration algorithm triggered, but not yet finished. + AutoGenerated, // Points were autogenerated (i.e. copied from the backend). + UserModified // User has done some edits. +}; + struct SupportPoint { Vec3f pos; float head_front_radius; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 827846b71..8ce306869 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -342,6 +342,17 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf if (it_print_object_status != print_object_status.end()) update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); } + if (model_object.sla_points_status != model_object_new.sla_points_status) { + // Change of this status should invalidate support points. The points themselves are not enough, there are none + // in case that nothing was generated OR that points were autogenerated already and not copied to the front-end. + // These cases can only be differentiated by checking the status change. However, changing from 'Generating' should NOT + // invalidate - that would keep stopping the background processing without a reason. + if (model_object.sla_points_status != sla::PointsStatus::Generating) + if (it_print_object_status != print_object_status.end()) + update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); + model_object.sla_points_status = model_object_new.sla_points_status; + } + // Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step. model_object.name = model_object_new.name; model_object.input_file = model_object_new.input_file; @@ -630,10 +641,11 @@ void SLAPrint::process() BOOST_LOG_TRIVIAL(debug) << "Support point count " << mo.sla_support_points.size(); - // If there are no points on the front-end, we will do the - // autoplacement. Otherwise we will just blindly copy the frontend data + // Unless the user modified the points or we already did the calculation, we will do + // the autoplacement. Otherwise we will just blindly copy the frontend data // into the backend cache. - if(mo.sla_support_points.empty()) { + if (mo.sla_points_status != sla::PointsStatus::UserModified) { + // calculate heights of slices (slices are calculated already) double lh = po.m_config.layer_height.getFloat(); @@ -645,7 +657,9 @@ void SLAPrint::process() this->throw_if_canceled(); SLAAutoSupports::Config config; const SLAPrintObjectConfig& cfg = po.config(); - config.density_relative = float(cfg.support_points_density_relative / 100.f); // the config value is in percents + + // the density config value is in percents: + config.density_relative = float(cfg.support_points_density_relative / 100.f); config.minimal_distance = float(cfg.support_points_minimal_distance); // Construction of this object does the calculation. @@ -669,7 +683,7 @@ void SLAPrint::process() report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS); } else { - // There are some points on the front-end, no calculation will be done. + // There are either some points on the front-end, or the user removed them on purpose. No calculation will be done. po.m_supportdata->support_points = po.transformed_support_points(); } }; diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index f1a4589fe..e7f77eb2f 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1789,12 +1789,12 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const G if (is_mesh_update_necessary()) update_mesh(); - // If there are no points, let's ask the backend if it calculated some. - if (m_editing_mode_cache.empty()) - get_data_from_backend(); - if (m_model_object != m_old_model_object) m_editing_mode = false; + + if (m_editing_mode_cache.empty() && m_model_object->sla_points_status != sla::PointsStatus::UserModified) + get_data_from_backend(); + if (m_state == On) { m_parent.toggle_model_objects_visibility(false); m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); @@ -2296,8 +2296,7 @@ RENDER_AGAIN: m_imgui->text(" "); // vertical gap - bool apply_changes = m_imgui->button(_(L("Apply changes"))); - if (apply_changes) { + if (m_imgui->button(_(L("Apply changes")))) { editing_mode_apply_changes(); force_refresh = true; } @@ -2308,24 +2307,28 @@ RENDER_AGAIN: force_refresh = true; } } - else { - /* ImGui::PushItemWidth(50.0f); + else { // not in editing mode: + /*ImGui::PushItemWidth(100.0f); m_imgui->text(_(L("Minimal points distance: "))); ImGui::SameLine(); - bool value_changed = ImGui::InputDouble("mm", &m_minimal_point_distance, 0.0f, 0.0f, "%.2f"); + bool value_changed = ImGui::SliderFloat("", &m_minimal_point_distance, 0.f, 20.f, "%.f mm"); m_imgui->text(_(L("Support points density: "))); ImGui::SameLine(); - value_changed |= ImGui::InputDouble("%", &m_density, 0.0f, 0.0f, "%.f");*/ + value_changed |= ImGui::SliderFloat(" ", &m_density, 0.f, 200.f, "%.f %%");*/ bool generate = m_imgui->button(_(L("Auto-generate points [A]"))); if (generate) auto_generate(); - m_imgui->text(""); m_imgui->text(""); if (m_imgui->button(_(L("Manual editing [M]")))) switch_to_editing_mode(); + + m_imgui->text(m_model_object->sla_points_status == sla::PointsStatus::None ? "No points (will be autogenerated)" : + (m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated ? "Autogenerated points (no modifications)" : + (m_model_object->sla_points_status == sla::PointsStatus::UserModified ? "User-modified points" : + (m_model_object->sla_points_status == sla::PointsStatus::Generating ? "Generation in progress..." : "UNKNOWN STATUS")))); } m_imgui->end(); @@ -2448,16 +2451,18 @@ void GLGizmoSlaSupports::editing_mode_apply_changes() // If there are no changes, don't touch the front-end. The data in the cache could have been // taken from the backend and copying them to ModelObject would needlessly invalidate them. if (m_unsaved_changes) { + m_model_object->sla_points_status = sla::PointsStatus::UserModified; m_model_object->sla_support_points.clear(); for (const std::pair& point_and_selection : m_editing_mode_cache) m_model_object->sla_support_points.push_back(point_and_selection.first); + + // Recalculate support structures once the editing mode is left. + // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + wxGetApp().plater()->reslice_SLA_supports(*m_model_object); } m_editing_mode = false; m_unsaved_changes = false; - - // Recalculate support structures once the editing mode is left. - // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); - wxGetApp().plater()->reslice_SLA_supports(*m_model_object); } @@ -2476,10 +2481,15 @@ void GLGizmoSlaSupports::get_data_from_backend() { for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { if (po->model_object()->id() == m_model_object->id() && po->is_step_done(slaposSupportPoints)) { + m_editing_mode_cache.clear(); const std::vector& points = po->get_support_points(); auto mat = po->trafo().inverse().cast(); for (unsigned int i=0; isla_points_status != sla::PointsStatus::UserModified) + m_model_object->sla_points_status = sla::PointsStatus::AutoGenerated; + break; } } @@ -2497,8 +2507,9 @@ void GLGizmoSlaSupports::auto_generate() "Are you sure you want to do it?\n" )), _(L("Warning")), wxICON_WARNING | wxYES | wxNO); - if (m_model_object->sla_support_points.empty() || dlg.ShowModal() == wxID_YES) { + if (m_model_object->sla_points_status != sla::PointsStatus::UserModified || dlg.ShowModal() == wxID_YES) { m_model_object->sla_support_points.clear(); + m_model_object->sla_points_status = sla::PointsStatus::Generating; m_editing_mode_cache.clear(); wxGetApp().plater()->reslice_SLA_supports(*m_model_object); } diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp index 6996f5576..a5371a3e9 100644 --- a/src/slic3r/GUI/GLGizmo.hpp +++ b/src/slic3r/GUI/GLGizmo.hpp @@ -489,19 +489,19 @@ private: #endif // not ENABLE_IMGUI bool m_lock_unique_islands = false; - bool m_editing_mode = false; - bool m_old_editing_state = false; - float m_new_point_head_diameter = 0.4f; - double m_minimal_point_distance = 20.; - double m_density = 100.; + bool m_editing_mode = false; // Is editing mode active? + bool m_old_editing_state = false; // To keep track of whether the user toggled between the modes (needed for imgui refreshes). + float m_new_point_head_diameter = 0.4f; // Size of a new point. + float m_minimal_point_distance = 20.f; + float m_density = 100.f; std::vector> m_editing_mode_cache; // a support point and whether it is currently selected bool m_selection_rectangle_active = false; Vec2d m_selection_rectangle_start_corner; Vec2d m_selection_rectangle_end_corner; bool m_ignore_up_event = false; - bool m_combo_box_open = false; - bool m_unsaved_changes = false; + bool m_combo_box_open = false; // To ensure proper rendering of the imgui combobox. + bool m_unsaved_changes = false; // Are there unsaved changes in manual mode? bool m_selection_empty = true; EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) int m_canvas_width;