From 70fdb48c12aa9c3207c1162747f5176b129da642 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 12 Nov 2018 15:35:58 +0100 Subject: [PATCH 1/4] Manipulation with colorprint ticks now calls Plater::schedule_background_process() --- src/slic3r/GUI/GUI_Preview.cpp | 11 ++++++++--- src/slic3r/GUI/GUI_Preview.hpp | 5 ++++- src/slic3r/GUI/Plater.cpp | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 78f8b7462..b7f85d1ad 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -24,7 +24,7 @@ namespace Slic3r { namespace GUI { -Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data) +Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data, std::function schedule_background_process_func) : m_canvas(nullptr) , m_double_slider_sizer(nullptr) , m_label_view_type(nullptr) @@ -43,6 +43,7 @@ Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, , m_loaded(false) , m_enabled(false) , m_force_sliders_full_range(false) + , m_schedule_background_process(schedule_background_process_func) { if (init(notebook, config, print, gcode_preview_data)) { @@ -488,6 +489,7 @@ void Preview::create_double_slider() Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) { auto& config = wxGetApp().preset_bundle->project_config; ((config.option("colorprint_heights"))->values) = (m_slider->GetTicksValues()); + m_schedule_background_process(); }); } @@ -529,13 +531,16 @@ void Preview::fill_slider_values(std::vector> &values, } // All ticks that would end up outside the slider range should be erased. - // TODO: this should probably be placed into more appropriate part of code, - // this way it relies on the Preview tab being active. + // TODO: this should be placed into more appropriate part of code, + // this function is e.g. not called when the last object is deleted auto& config = wxGetApp().preset_bundle->project_config; std::vector &ticks_from_config = (config.option("colorprint_heights"))->values; + unsigned int old_size = ticks_from_config.size(); ticks_from_config.erase(std::remove_if(ticks_from_config.begin(), ticks_from_config.end(), [values](double val) { return values.back().second < val; }), ticks_from_config.end()); + if (ticks_from_config.size() != old_size) + m_schedule_background_process(); } void Preview::set_double_slider_thumbs(const bool force_sliders_full_range, diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index ab7544ed8..bafcba1ba 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -40,6 +40,9 @@ class Preview : public wxPanel Print* m_print; GCodePreviewData* m_gcode_preview_data; + // Calling this function object forces Plater::schedule_background_process. + std::function m_schedule_background_process; + unsigned int m_number_extruders; std::string m_preferred_color_mode; @@ -50,7 +53,7 @@ class Preview : public wxPanel PrusaDoubleSlider* m_slider {nullptr}; public: - Preview(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data); + Preview(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data, std::function schedule_background_process = [](){}); virtual ~Preview(); wxGLCanvas* get_wxglcanvas() { return m_canvas; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 6b29e72f3..5a742c07b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1002,7 +1002,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : _3DScene::add_canvas(canvas3D); _3DScene::allow_multisample(canvas3D, GLCanvas3DManager::can_multisample()); notebook->AddPage(canvas3D, _(L("3D"))); - preview = new GUI::Preview(notebook, config, &print, &gcode_preview_data); + preview = new GUI::Preview(notebook, config, &print, &gcode_preview_data, [this](){ schedule_background_process(); }); // XXX: If have OpenGL _3DScene::enable_picking(canvas3D, true); From df658713bf0a1bda2aa05b3612168c3349b1cd29 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 12 Nov 2018 15:36:40 +0100 Subject: [PATCH 2/4] Wipe tower preview not shown in SLA mode --- src/slic3r/GUI/GLCanvas3D.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9293adf5a..707359f3e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3658,7 +3658,6 @@ void GLCanvas3D::reload_scene(bool force) { if ((m_canvas == nullptr) || (m_config == nullptr) || (m_model == nullptr)) return; - #if !ENABLE_USE_UNIQUE_GLCONTEXT // ensures this canvas is current if (!set_current()) @@ -3695,7 +3694,7 @@ void GLCanvas3D::reload_scene(bool force) if (m_regenerate_volumes) { - if (m_config->has("nozzle_diameter")) + if (m_config->has("nozzle_diameter") && wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF) { // Should the wipe tower be visualized ? unsigned int extruders_count = (unsigned int)dynamic_cast(m_config->option("nozzle_diameter"))->values.size(); @@ -3717,7 +3716,6 @@ void GLCanvas3D::reload_scene(bool force) float depth = m_print->get_wipe_tower_depth(); if (!m_print->is_step_done(psWipeTower)) depth = (900.f/w) * (float)(extruders_count - 1) ; - m_volumes.load_wipe_tower_preview(1000, x, y, w, depth, (float)height, a, m_use_VBOs && m_initialized, !m_print->is_step_done(psWipeTower), m_print->config().nozzle_diameter.values[0] * 1.25f * 4.5f); } @@ -6207,16 +6205,18 @@ void GLCanvas3D::_load_shells() ++object_id; } - // adds wipe tower's volume - double max_z = m_print->objects()[0]->model_object()->get_model()->bounding_box().max(2); - const PrintConfig& config = m_print->config(); - unsigned int extruders_count = config.nozzle_diameter.size(); - if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects) { - float depth = m_print->get_wipe_tower_depth(); - if (!m_print->is_step_done(psWipeTower)) - depth = (900.f/config.wipe_tower_width) * (float)(extruders_count - 1) ; - m_volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle, - m_use_VBOs && m_initialized, !m_print->is_step_done(psWipeTower), m_print->config().nozzle_diameter.values[0] * 1.25f * 4.5f); + if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF) { + // adds wipe tower's volume + double max_z = m_print->objects()[0]->model_object()->get_model()->bounding_box().max(2); + const PrintConfig& config = m_print->config(); + unsigned int extruders_count = config.nozzle_diameter.size(); + if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects) { + float depth = m_print->get_wipe_tower_depth(); + if (!m_print->is_step_done(psWipeTower)) + depth = (900.f/config.wipe_tower_width) * (float)(extruders_count - 1) ; + m_volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle, + m_use_VBOs && m_initialized, !m_print->is_step_done(psWipeTower), m_print->config().nozzle_diameter.values[0] * 1.25f * 4.5f); + } } } From d20bac70391cd9edc3d3ba84489fc5fe5e4a2817 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 12 Nov 2018 16:03:29 +0100 Subject: [PATCH 3/4] Added a modifier selection in the object list + set box-subobject's center to the objects center + fixed bug in PrusaObjectDataViewModel.Delete(), when deleting last volume_idx --- src/slic3r/GUI/GUI_ObjectList.cpp | 10 +++++++--- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 4 +++- src/slic3r/GUI/wxExtensions.cpp | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 106ea2d16..a088e13e5 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -704,7 +704,7 @@ void ObjectList::load_subobject(int type) parts_changed(obj_idx); for (int i = 0; i < part_names.size(); ++i) { - const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i), /**m_bmp_vector[*/type/*]*/); + const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i), type); if (i == part_names.size() - 1) select_item(sel_item); @@ -786,8 +786,11 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int const auto& sz = BoundingBoxf(bed_shape).size(); const auto side = 0.1 * std::max(sz(0), sz(1)); - if (type_name == _("Box")) + if (type_name == _("Box")) { mesh = make_cube(side, side, side); + // box sets the base coordinate at 0, 0, move to center of plate + mesh.translate(-side * 0.5, -side * 0.5, 0); + } else if (type_name == _("Cylinder")) mesh = make_cylinder(0.5*side, side); else if (type_name == _("Sphere")) @@ -1251,7 +1254,8 @@ void ObjectList::update_selections() { sels.Add(m_objects_model->GetItemById(selection.get_object_idx())); } - else if (selection.is_single_volume() || selection.is_multiple_volume() || selection.is_multiple_full_object()) { + else if (selection.is_single_volume() || selection.is_modifier() || + selection.is_multiple_volume() || selection.is_multiple_full_object()) { for (auto idx : selection.get_volume_idxs()) { const auto gl_vol = selection.get_volume(idx); if (selection.is_multiple_full_object()) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 870ed2226..ee35af642 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -86,6 +86,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent): if (option_name == "Rotation") def.min = -360; + else + def.min == -1000; const std::string lower_name = boost::algorithm::to_lower_copy(option_name); @@ -164,7 +166,7 @@ int ObjectManipulation::ol_selection() void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection) { #if ENABLE_MODELVOLUME_TRANSFORM - if (selection.is_single_full_instance()) + if (selection.is_single_full_instance() || selection.is_single_full_object()) #else if (selection.is_single_full_object()) { diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 6d68d4f02..5d0b44d47 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -641,6 +641,7 @@ wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item) PrusaObjectDataViewModelNode *last_child_node = node_parent->GetNthChild(vol_idx); DeleteSettings(wxDataViewItem(last_child_node)); node_parent->GetChildren().Remove(last_child_node); + node_parent->m_volumes_cnt = 0; delete last_child_node; #ifndef __WXGTK__ From 48173e2a5511a8a8a9c99453ac412aaf17d0ecee Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 12 Nov 2018 16:28:27 +0100 Subject: [PATCH 4/4] Fixed synchronization of background processing with the front end. --- src/libslic3r/Model.hpp | 2 +- src/libslic3r/Print.cpp | 87 ++++++++++++++++++++++------------- src/libslic3r/Print.hpp | 2 + src/libslic3r/PrintObject.cpp | 7 +++ 4 files changed, 66 insertions(+), 32 deletions(-) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 3e52e7623..354d71dc4 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -370,7 +370,7 @@ protected: friend class Print; friend class ModelObject; - explicit ModelVolume(ModelVolume &rhs) = default; + explicit ModelVolume(const ModelVolume &rhs) = default; void set_model_object(ModelObject *model_object) { object = model_object; } private: diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index f0538fda0..c661da5ca 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -260,6 +260,8 @@ bool Print::invalidate_step(PrintStep step) //FIXME Why should skirt invalidate brim? Shouldn't it be vice versa? if (step == psSkirt) invalidated |= Inherited::invalidate_step(psBrim); + if (step != psGCodeExport) + invalidated |= Inherited::invalidate_step(psGCodeExport); return invalidated; } @@ -612,27 +614,45 @@ static inline bool model_volume_list_changed(const ModelObject &model_object_old return false; } -void Print::model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_src) +// Add or remove support modifier ModelVolumes from model_object_dst to match the ModelVolumes of model_object_new +// in the exact order and with the same IDs. +// It is expected, that the model_object_dst already contains the non-support volumes of model_object_new in the correct order. +void Print::model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_new) { - // 1) Delete the support volumes from model_object_dst. - { - std::vector dst; - dst.reserve(model_object_dst.volumes.size()); - for (ModelVolume *vol : model_object_dst.volumes) { - if (vol->is_support_modifier()) - dst.emplace_back(vol); - else - delete vol; + typedef std::pair ModelVolumeWithStatus; + std::vector old_volumes; + old_volumes.reserve(model_object_dst.volumes.size()); + for (const ModelVolume *model_volume : model_object_dst.volumes) + old_volumes.emplace_back(ModelVolumeWithStatus(model_volume, false)); + auto model_volume_lower = [](const ModelVolumeWithStatus &mv1, const ModelVolumeWithStatus &mv2){ return mv1.first->id() < mv2.first->id(); }; + auto model_volume_equal = [](const ModelVolumeWithStatus &mv1, const ModelVolumeWithStatus &mv2){ return mv1.first->id() == mv2.first->id(); }; + std::sort(old_volumes.begin(), old_volumes.end(), model_volume_lower); + model_object_dst.volumes.clear(); + model_object_dst.volumes.reserve(model_object_new.volumes.size()); + for (const ModelVolume *model_volume_src : model_object_new.volumes) { + ModelVolumeWithStatus key(model_volume_src, false); + auto it = std::lower_bound(old_volumes.begin(), old_volumes.end(), key, model_volume_lower); + if (it != old_volumes.end() && model_volume_equal(*it, key)) { + // The volume was found in the old list. Just copy it. + assert(! it->second); // not consumed yet + it->second = true; + ModelVolume *model_volume_dst = const_cast(it->first); + assert(model_volume_dst->type() == model_volume_src->type()); + model_object_dst.volumes.emplace_back(model_volume_dst); + if (model_volume_dst->is_support_modifier()) + model_volume_dst->set_transformation(model_volume_src->get_transformation()); + assert(model_volume_dst->get_matrix().isApprox(model_volume_src->get_matrix())); + } else { + // The volume was not found in the old list. Create a new copy. + assert(model_volume_src->is_support_modifier()); + model_object_dst.volumes.emplace_back(new ModelVolume(*model_volume_src)); + model_object_dst.volumes.back()->set_model_object(&model_object_dst); } - model_object_dst.volumes = std::move(dst); - } - // 2) Copy the support volumes from model_object_src to the end of model_object_dst. - for (ModelVolume *vol : model_object_src.volumes) { - if (vol->is_support_modifier()) { - model_object_dst.volumes.emplace_back(new ModelVolume(*vol)); - model_object_dst.volumes.back()->set_model_object(&model_object_dst); - } } + // Release the non-consumed old volumes (those were deleted from the new list). + for (ModelVolumeWithStatus &mv_with_status : old_volumes) + if (! mv_with_status.second) + delete mv_with_status.first; } static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, const ModelObject &model_object_src, const ModelVolume::Type type) @@ -852,7 +872,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co // Reorder the objects, add new objects. // First stop background processing before shuffling or deleting the PrintObjects in the object list. this->call_cancell_callback(); - this->invalidate_step(psGCodeExport); + update_apply_status(this->invalidate_step(psGCodeExport)); // Second create a new list of objects. std::vector model_objects_old(std::move(m_model.objects)); m_model.objects.clear(); @@ -962,6 +982,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } else if (support_blockers_differ || support_enforcers_differ) { // First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list. this->call_cancell_callback(); + update_apply_status(false); // Invalidate just the supports step. auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); for (auto it = range.first; it != range.second; ++ it) @@ -1067,6 +1088,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } if (m_objects != print_objects_new) { this->call_cancell_callback(); + update_apply_status(this->invalidate_all_steps()); m_objects = print_objects_new; // Delete the PrintObjects marked as Unknown or Deleted. bool deleted_objects = false; @@ -1131,7 +1153,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co int ireg = 0; for (const std::vector &volumes : print_object->region_volumes) { if (! volumes.empty()) - -- m_regions[ireg]; + -- m_regions[ireg]->m_refcnt; ++ ireg; } print_object->region_volumes.clear(); @@ -1164,21 +1186,24 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co // Get the config applied to this volume. PrintRegionConfig config = region_config_from_model_volume(m_default_region_config, *volume); // Find an existing print region with the same config. - for (int i = 0; i < (int)m_regions.size(); ++ i) - if (config.equals(m_regions[i]->config())) { + int idx_empty_slot = -1; + for (int i = 0; i < (int)m_regions.size(); ++ i) { + if (m_regions[i]->m_refcnt == 0) + idx_empty_slot = i; + else if (config.equals(m_regions[i]->config())) { region_id = i; break; } + } // If no region exists with the same config, create a new one. - if (region_id == size_t(-1)) { - for (region_id = 0; region_id < m_regions.size(); ++ region_id) - if (m_regions[region_id]->m_refcnt == 0) { - // An empty slot was found. - m_regions[region_id]->set_config(std::move(config)); - break; - } - if (region_id == m_regions.size()) - this->add_region(config); + if (region_id == -1) { + if (idx_empty_slot == -1) { + region_id = (int)m_regions.size(); + this->add_region(config); + } else { + region_id = idx_empty_slot; + m_regions[region_id]->set_config(std::move(config)); + } } map_volume_to_region[volume_id] = region_id; } else diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index ea34ef23a..b2f9f9501 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -174,6 +174,8 @@ protected: bool set_copies(const Points &points); // Invalidates the step, and its depending steps in PrintObject and Print. bool invalidate_step(PrintObjectStep step); + // Invalidates all PrintObject and Print steps. + bool invalidate_all_steps(); private: void make_perimeters(); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index f0361ba01..a71fa194f 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -570,9 +570,16 @@ bool PrintObject::invalidate_step(PrintObjectStep step) // It also decides about what the wipe_into_infill / wipe_into_object features will do, // and that too depends on many of the settings. invalidated |= m_print->invalidate_step(psWipeTower); + // Invalidate G-code export in any case. + invalidated |= m_print->invalidate_step(psGCodeExport); return invalidated; } +bool PrintObject::invalidate_all_steps() +{ + return Inherited::invalidate_all_steps() | m_print->invalidate_all_steps(); +} + bool PrintObject::has_support_material() const { return m_config.support_material