From 9f393e6b9ba1463467e242daebda6ff0124cd1e5 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 1 Aug 2019 15:25:35 +0200 Subject: [PATCH 01/14] Not taking the snapshot with non-empty Redo stack will likely be more confusing than losing the Redo stack. Let's wait for user feedback. --- src/slic3r/GUI/Selection.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 211863627f..2488947bc3 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -402,8 +402,10 @@ void Selection::remove_all() if (is_empty()) return; - - if (!wxGetApp().plater()->can_redo()) + +// Not taking the snapshot with non-empty Redo stack will likely be more confusing than losing the Redo stack. +// Let's wait for user feedback. +// if (!wxGetApp().plater()->can_redo()) wxGetApp().plater()->take_snapshot(_(L("Selection-Remove All"))); m_mode = Instance; From 170bd8b064d55cd580b19c597acb08d45ac35164 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 1 Aug 2019 15:28:21 +0200 Subject: [PATCH 02/14] Wipetower fix: temperature-changing command was sometimes missing after the toolchange Cause: variable holding last issued temperature was not reset where it should have been This should fix issue #2685 --- src/libslic3r/GCode/WipeTower.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 55a6c4437e..e1b34fdeae 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -1242,6 +1242,8 @@ void WipeTower::generate(std::vector> & for (auto& used : m_used_filament_length) // reset used filament stats used = 0.f; + m_old_temperature = -1; // reset last temperature written in the gcode + std::vector layer_result; for (auto layer : m_plan) { From ec9117cc06e5b268d5c5b1170312c922fe3e892b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 1 Aug 2019 15:38:00 +0200 Subject: [PATCH 03/14] Split snapshot text for separated fazes (in ObjectList) --- src/slic3r/GUI/GUI_ObjectList.cpp | 44 ++++++++++++------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 70632a3377..fede48166c 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -490,7 +490,7 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const if (obj_idx < 0) return; const int volume_id = m_objects_model->GetVolumeIdByItem(item); - take_snapshot(wxString::Format(_(L("Rename %s")), volume_id < 0 ? _(L("Object")) : _(L("Sub-object")))); + take_snapshot(volume_id < 0 ? _(L("Rename Object")) : _(L("Rename Sub-object"))); if (m_objects_model->GetItemType(item) & itObject) { (*m_objects)[obj_idx]->name = m_objects_model->GetName(item).ToUTF8().data(); @@ -1043,8 +1043,10 @@ void ObjectList::get_settings_choice(const wxString& category_name) wxArrayInt selections; wxDataViewItem item = GetSelection(); + const ItemType item_type = m_objects_model->GetItemType(item); + settings_menu_hierarchy settings_menu; - const bool is_part = m_objects_model->GetItemType(item) & (itVolume | itLayer); + const bool is_part = item_type & (itVolume | itLayer); get_options_menu(settings_menu, is_part); std::vector< std::pair > *settings_list = nullptr; @@ -1121,7 +1123,10 @@ void ObjectList::get_settings_choice(const wxString& category_name) } #endif - take_snapshot(wxString::Format(_(L("Add Settings for %s")), is_part ? _(L("Sub-object")) : _(L("Object")))); + const wxString snapshot_text = item_type & itLayer ? _(L("Add Settings for Layers")) : + item_type & itVolume ? _(L("Add Settings for Sub-object")) : + _(L("Add Settings for Object")); + take_snapshot(snapshot_text); std::vector selected_options; selected_options.reserve(selection_cnt); @@ -1153,7 +1158,7 @@ void ObjectList::get_settings_choice(const wxString& category_name) // Add settings item for object/sub-object and show them - if (!(m_objects_model->GetItemType(item) & (itObject | itVolume | itLayer))) + if (!(item_type & (itObject | itVolume | itLayer))) item = m_objects_model->GetTopParent(item); show_settings(add_settings_item(item, m_config)); } @@ -1163,11 +1168,13 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name) std::vector options = get_options_for_bundle(bundle_name); wxDataViewItem item = GetSelection(); + ItemType item_type = m_objects_model->GetItemType(item); + /* Because of we couldn't edited layer_height for ItVolume from settings list, * correct options according to the selected item type : * remove "layer_height" option */ - if ((m_objects_model->GetItemType(item) & itVolume) && bundle_name == _("Layers and Perimeters")) { + if ((item_type & itVolume) && bundle_name == _("Layers and Perimeters")) { const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height"); if (layer_height_it != options.end()) options.erase(layer_height_it); @@ -1179,7 +1186,10 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name) assert(m_config); auto opt_keys = m_config->keys(); - take_snapshot(wxString::Format(_(L("Add Settings Bundle for %s")), m_objects_model->GetItemType(item) & (itVolume|itLayer) ? _(L("Sub-object")) : _(L("Object")))); + const wxString snapshot_text = item_type & itLayer ? _(L("Add Settings Bundle for Layers")) : + item_type & itVolume ? _(L("Add Settings Bundle for Sub-object")) : + _(L("Add Settings Bundle for Object")); + take_snapshot(snapshot_text); const DynamicPrintConfig& from_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; for (auto& opt_key : options) @@ -1196,7 +1206,7 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name) } // Add settings item for object/sub-object and show them - if (!(m_objects_model->GetItemType(item) & (itObject | itVolume | itLayer))) + if (!(item_type & (itObject | itVolume | itLayer))) item = m_objects_model->GetTopParent(item); show_settings(add_settings_item(item, m_config)); } @@ -1211,26 +1221,6 @@ void ObjectList::show_settings(const wxDataViewItem settings_item) // update object selection on Plater if (!m_prevent_canvas_selection_update) update_selections_on_canvas(); -/* auto item = GetSelection(); - if (item) { - if (m_objects_model->GetItemType(item) == itInstance) - item = m_objects_model->GetTopParent(item); - const auto settings_item = m_objects_model->IsSettingsItem(item) ? item : m_objects_model->GetSettingsItem(item); - select_item(settings_item ? settings_item : - m_objects_model->AddSettingsChild(item)); - - // update object selection on Plater - if (!m_prevent_canvas_selection_update) - update_selections_on_canvas(); - } - else { - //# ys_FIXME ??? use case ??? - auto panel = wxGetApp().sidebar().scrolled_panel(); - panel->Freeze(); - wxGetApp().obj_settings()->UpdateAndShow(true); - panel->Thaw(); - } - */ } wxMenu* ObjectList::append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type) { From 9471c9cd17b19e3d96155a4413dd7a7a84009960 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 1 Aug 2019 16:20:46 +0200 Subject: [PATCH 04/14] Implemented FR #2633 --- src/slic3r/GUI/MainFrame.cpp | 19 ++++++++++++++++++- src/slic3r/GUI/MainFrame.hpp | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index d3da148a05..f5da43aee9 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -279,6 +279,18 @@ bool MainFrame::can_export_gcode() const return true; } +bool MainFrame::can_send_gcode() const +{ + if (m_plater == nullptr) + return false; + + if (m_plater->model().objects.empty()) + return false; + + const auto prin_host_opt =wxGetApp().preset_bundle->printers.get_edited_preset().config.option("print_host"); + return prin_host_opt != nullptr && !prin_host_opt->value.empty(); +} + bool MainFrame::can_slice() const { bool bg_proc = wxGetApp().app_config->get("background_processing") == "1"; @@ -451,6 +463,10 @@ void MainFrame::init_menubar() [this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, menu_icon("export_gcode"), nullptr, [this](){return can_export_gcode(); }, this); m_changeable_menu_items.push_back(item_export_gcode); + wxMenuItem* item_send_gcode = append_menu_item(export_menu, wxID_ANY, _(L("S&end G-code")) + dots +"\tCtrl+Shift+G", _(L("Send to print current plate as G-code")), + [this](wxCommandEvent&) { if (m_plater) m_plater->send_gcode(); }, menu_icon("export_gcode"), nullptr, + [this](){return can_send_gcode(); }, this); + m_changeable_menu_items.push_back(item_send_gcode); export_menu->AppendSeparator(); append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")), [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, menu_icon("export_plater"), nullptr, @@ -689,7 +705,8 @@ void MainFrame::update_menubar() { const bool is_fff = plater()->printer_technology() == ptFFF; - m_changeable_menu_items[miExport] ->SetItemLabel((is_fff ? _(L("Export &G-code")) : _(L("Export")) ) + dots + "\tCtrl+G"); + m_changeable_menu_items[miExport] ->SetItemLabel((is_fff ? _(L("Export &G-code")) : _(L("E&xport")) ) + dots + "\tCtrl+G"); + m_changeable_menu_items[miSend] ->SetItemLabel((is_fff ? _(L("S&end G-code")) : _(L("S&end to print"))) + dots + "\tCtrl+Shift+G"); m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3"); m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, menu_icon(is_fff ? "spool": "resin"))); diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index a41f33824d..5d34be48ef 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -67,6 +67,7 @@ class MainFrame : public DPIFrame bool can_export_model() const; bool can_export_supports() const; bool can_export_gcode() const; + bool can_send_gcode() const; bool can_slice() const; bool can_change_view() const; bool can_select() const; @@ -79,6 +80,7 @@ class MainFrame : public DPIFrame enum MenuItems { // FFF SLA miExport = 0, // Export G-code Export + miSend, // Send G-code Send to print miMaterialTab, // Filament Settings Material Settings }; From 28cc5953506b8dab6b3ee2e386148cd1d2d1239b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 2 Aug 2019 09:43:41 +0200 Subject: [PATCH 05/14] #2593 - Fixed loading of .zip.amf files when running from command line --- src/libslic3r/Model.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 858ae52b29..76ef9eccab 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -99,8 +99,7 @@ Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *c result = load_stl(input_file.c_str(), &model); else if (boost::algorithm::iends_with(input_file, ".obj")) result = load_obj(input_file.c_str(), &model); - else if (!boost::algorithm::iends_with(input_file, ".zip.amf") && (boost::algorithm::iends_with(input_file, ".amf") || - boost::algorithm::iends_with(input_file, ".amf.xml"))) + else if (boost::algorithm::iends_with(input_file, ".amf") || boost::algorithm::iends_with(input_file, ".amf.xml")) result = load_amf(input_file.c_str(), config, &model); else if (boost::algorithm::iends_with(input_file, ".3mf")) result = load_3mf(input_file.c_str(), config, &model); From c791ba776f96c8fa18c435c12dad2c726af46c3b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 2 Aug 2019 12:05:02 +0200 Subject: [PATCH 06/14] Added absolute time to estimated time for color print and fixed a bug in showing estimated times for print color for silent mode --- src/libslic3r/GCode.cpp | 4 ++-- src/libslic3r/GCodeTimeEstimator.cpp | 24 ++++++++++++++++++++---- src/libslic3r/GCodeTimeEstimator.hpp | 8 +++++--- src/slic3r/GUI/Plater.cpp | 4 ++-- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index bc37300269..011bf3fc42 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1138,9 +1138,9 @@ void GCode::_do_export(Print &print, FILE *file) print.m_print_statistics.clear(); print.m_print_statistics.estimated_normal_print_time = m_normal_time_estimator.get_time_dhms(); print.m_print_statistics.estimated_silent_print_time = m_silent_time_estimator_enabled ? m_silent_time_estimator.get_time_dhms() : "N/A"; - print.m_print_statistics.estimated_normal_color_print_times = m_normal_time_estimator.get_color_times_dhms(); + print.m_print_statistics.estimated_normal_color_print_times = m_normal_time_estimator.get_color_times_dhms(true); if (m_silent_time_estimator_enabled) - print.m_print_statistics.estimated_silent_color_print_times = m_silent_time_estimator.get_color_times_dhms(); + print.m_print_statistics.estimated_silent_color_print_times = m_silent_time_estimator.get_color_times_dhms(true); std::vector extruders = m_writer.extruders(); if (! extruders.empty()) { diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 33dc9f4b7d..87f8bca65d 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -694,22 +694,38 @@ namespace Slic3r { return m_color_times; } - std::vector GCodeTimeEstimator::get_color_times_dhms() const + std::vector GCodeTimeEstimator::get_color_times_dhms(bool include_absolute) const { std::vector ret; + float total_time = 0.0f; for (float t : m_color_times) { - ret.push_back(_get_time_dhms(t)); + total_time += t; + std::string time = ""; + if (include_absolute) + time += _get_time_dhms(total_time) + " ("; + time += _get_time_dhms(t); + if (include_absolute) + time += ")"; + ret.push_back(time); } return ret; } - std::vector GCodeTimeEstimator::get_color_times_minutes() const + std::vector GCodeTimeEstimator::get_color_times_minutes(bool include_absolute) const { std::vector ret; + float total_time = 0.0f; for (float t : m_color_times) { - ret.push_back(_get_time_minutes(t)); + total_time += t; + std::string time = ""; + if (include_absolute) + time += _get_time_minutes(total_time) + " ("; + time += _get_time_minutes(t); + if (include_absolute) + time += ")"; + ret.push_back(time); } return ret; } diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index 840d587784..792fb72a51 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -346,14 +346,16 @@ namespace Slic3r { // Returns the estimated time, in minutes (integer) std::string get_time_minutes() const; - // Returns the estimated time, in seconds, for each color + // Returns the estimated time, in seconds, for each color std::vector get_color_times() const; // Returns the estimated time, in format DDd HHh MMm SSs, for each color - std::vector get_color_times_dhms() const; + // If include_absolute==true the strings will be formatted as: "absolute time (relative time)" + std::vector get_color_times_dhms(bool include_absolute) const; // Returns the estimated time, in minutes (integer), for each color - std::vector get_color_times_minutes() const; + // If include_absolute==true the strings will be formatted as: "absolute time (relative time)" + std::vector get_color_times_minutes(bool include_absolute) const; // Return an estimate of the memory consumed by the time estimator. size_t memory_used() const; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7c494b4dcd..23beb09627 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1175,10 +1175,10 @@ void Sidebar::show_sliced_info_sizer(const bool show) if (ps.estimated_silent_print_time != "N/A") { new_label += wxString::Format("\n - %s", _(L("stealth mode"))); info_text += wxString::Format("\n%s", ps.estimated_silent_print_time); - for (int i = (int)ps.estimated_normal_color_print_times.size() - 1; i >= 0; --i) + for (int i = (int)ps.estimated_silent_color_print_times.size() - 1; i >= 0; --i) { new_label += wxString::Format("\n - %s%d", _(L("Color ")), i + 1); - info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]); + info_text += wxString::Format("\n%s", ps.estimated_silent_color_print_times[i]); } } p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label); From bfb135bcc3ac3f7d5cd65365a2f5944a78c7a250 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 2 Aug 2019 15:11:50 +0200 Subject: [PATCH 07/14] Comment out stale implementation in Serial, fix #2150 --- src/slic3r/GUI/FirmwareDialog.cpp | 2 +- src/slic3r/Utils/Serial.cpp | 3 +++ src/slic3r/Utils/Serial.hpp | 14 +++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp index 7865aecf2e..d1f2da040c 100644 --- a/src/slic3r/GUI/FirmwareDialog.cpp +++ b/src/slic3r/GUI/FirmwareDialog.cpp @@ -354,7 +354,7 @@ bool FirmwareDialog::priv::check_model_id() // Therefore, regretably, so far the check cannot be used and we just return true here. // TODO: Rewrite Serial using more platform-native code. return true; - + // if (hex_file.model_id.empty()) { // // No data to check against, assume it's ok // return true; diff --git a/src/slic3r/Utils/Serial.cpp b/src/slic3r/Utils/Serial.cpp index cd2a01cbfd..acfd5fafd0 100644 --- a/src/slic3r/Utils/Serial.cpp +++ b/src/slic3r/Utils/Serial.cpp @@ -353,6 +353,8 @@ void Serial::set_baud_rate(unsigned baud_rate) } } + +/* void Serial::set_DTR(bool on) { auto handle = native_handle(); @@ -495,6 +497,7 @@ std::string Serial::printer_format_line(const std::string &line, unsigned line_n return (boost::format("N%1% %2%*%3%\n") % line_num_str % line % checksum).str(); } +*/ } // namespace Utils diff --git a/src/slic3r/Utils/Serial.hpp b/src/slic3r/Utils/Serial.hpp index 67d64b4ec1..8bad75b315 100644 --- a/src/slic3r/Utils/Serial.hpp +++ b/src/slic3r/Utils/Serial.hpp @@ -46,6 +46,17 @@ public: ~Serial(); void set_baud_rate(unsigned baud_rate); + + // The Serial implementation is currently in disarray and therefore commented out. + // The boost implementation seems to have several problems, such as lack of support + // for custom baud rates, few weird implementation bugs and a history of API breakages. + // It's questionable whether it solves more problems than causes. Probably not. + // TODO: Custom implementation not based on asio. + // + // As of now, this class is only kept for the purpose of rebooting AVR109, + // see FirmwareDialog::priv::avr109_reboot() + +/* void set_DTR(bool on); // Resets the line number both internally as well as with the firmware using M110 @@ -68,7 +79,7 @@ public: // Same as above, but with internally-managed line number size_t printer_write_line(const std::string &line); - + // Toggles DTR to reset the printer void printer_reset(); @@ -76,6 +87,7 @@ public: static std::string printer_format_line(const std::string &line, unsigned line_num); private: unsigned m_line_num = 0; +*/ }; From 1cdc3e0493099b93cc41c11be68fa27e640c94df Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 2 Aug 2019 15:30:37 +0200 Subject: [PATCH 08/14] Workaround for gizmos being clipped by the perspective camera --- src/slic3r/GUI/GLCanvas3D.cpp | 17 ++++++++++++++--- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 5e505bb416..c74207123d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1529,7 +1529,7 @@ void GLCanvas3D::render() } m_camera.apply_view_matrix(); - m_camera.apply_projection(_max_bounding_box(true)); + m_camera.apply_projection(_max_bounding_box(true, true)); GLfloat position_cam[4] = { 1.0f, 0.0f, 1.0f, 0.0f }; glsafe(::glLightfv(GL_LIGHT1, GL_POSITION, position_cam)); @@ -3273,7 +3273,7 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type) void GLCanvas3D::set_camera_zoom(double zoom) { const Size& cnv_size = get_canvas_size(); - m_camera.set_zoom(zoom, _max_bounding_box(false), cnv_size.get_width(), cnv_size.get_height()); + m_camera.set_zoom(zoom, _max_bounding_box(false, false), cnv_size.get_width(), cnv_size.get_height()); m_dirty = true; } @@ -3699,9 +3699,20 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) m_dirty = false; } -BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_bed_model) const +BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_bed_model) const { BoundingBoxf3 bb = volumes_bounding_box(); + + // The following is a workaround for gizmos not being taken in account when calculating the tight camera frustrum + // A better solution would ask the gizmo manager for the bounding box of the current active gizmo, if any + if (include_gizmos && m_gizmos.is_running()) + { + BoundingBoxf3 sel_bb = m_selection.get_bounding_box(); + Vec3d sel_bb_center = sel_bb.center(); + Vec3d extend_by = sel_bb.max_size() * Vec3d::Ones(); + bb.merge(BoundingBoxf3(sel_bb_center - extend_by, sel_bb_center + extend_by)); + } + bb.merge(m_bed.get_bounding_box(include_bed_model)); return bb; } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index c9803f9db8..bd33dbef78 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -652,7 +652,7 @@ private: bool _set_current(); void _resize(unsigned int w, unsigned int h); - BoundingBoxf3 _max_bounding_box(bool include_bed_model) const; + BoundingBoxf3 _max_bounding_box(bool include_gizmos, bool include_bed_model) const; void _zoom_to_box(const BoundingBoxf3& box); From 3b24565411d3b4e477a6393e27196707be9eb2df Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 2 Aug 2019 16:15:49 +0200 Subject: [PATCH 09/14] Fixed wrong naming of bottom infill pattern --- src/libslic3r/PrintConfig.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 304f6f749f..e49c81f460 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -422,6 +422,7 @@ void PrintConfigDef::init_fff_params() def->cli = "bottom-fill-pattern|external-fill-pattern|solid-fill-pattern"; def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values = def_top_fill_pattern->enum_values; + def->enum_labels = def_top_fill_pattern->enum_labels; def->aliases = def_top_fill_pattern->aliases; def->set_default_value(new ConfigOptionEnum(ipRectilinear)); From 6ab1cec48c037a4f4a132a06e83f2a12fcacd9ff Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 2 Aug 2019 16:49:22 +0200 Subject: [PATCH 10/14] Empty layers detection added to GCode.cpp Added detection of empty layers so the wipe tower doesn't trip on them (it is not printable anyway). This should improve wipe tower reliability with supports, objects standing on edges, etc. I also turned an assert into exception throw to prevent hard crashes and nonsense output. --- src/libslic3r/GCode.cpp | 18 +++++++++++++++++- src/libslic3r/GCode/ToolOrdering.cpp | 10 ++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 011bf3fc42..6ae703a20f 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1,4 +1,5 @@ #include "libslic3r.h" +#include "I18N.hpp" #include "GCode.hpp" #include "ExtrusionEntity.hpp" #include "EdgeGrid.hpp" @@ -36,6 +37,11 @@ namespace Slic3r { +//! macro used to mark string used at localization, +//! return same string +#define L(s) (s) +#define _(s) Slic3r::I18N::translate(s) + // Only add a newline in case the current G-code does not end with a newline. static inline void check_add_eol(std::string &gcode) { @@ -405,7 +411,8 @@ std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, assert(m_layer_idx >= 0 && size_t(m_layer_idx) <= m_tool_changes.size()); if (! m_brim_done || gcodegen.writer().need_toolchange(extruder_id) || finish_layer) { if (m_layer_idx < (int)m_tool_changes.size()) { - assert(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()); + if (! (size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size())) + throw std::runtime_error("Wipe tower generation failed, possibly due to empty first layer."); gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id); } m_brim_done = true; @@ -436,6 +443,14 @@ std::vector GCode::collect_layers_to_print(const PrintObjec size_t idx_object_layer = 0; size_t idx_support_layer = 0; while (idx_object_layer < object.layers().size() || idx_support_layer < object.support_layers().size()) { + // Let's make sure that the last layer is not empty, so we don't build on top of it. + if (! layers_to_print.empty() + && (! layers_to_print.back().object_layer || ! layers_to_print.back().object_layer->has_extrusions()) + && (! layers_to_print.back().support_layer || ! layers_to_print.back().support_layer->has_extrusions())) + throw std::runtime_error(_(L("Empty layers detected, the output would not be printable.")) + "\n\n" + + _(L("Object name: ")) + object.model_object()->name + "\n" + _(L("Print z: ")) + + std::to_string(layers_to_print.back().print_z())); + LayerToPrint layer_to_print; layer_to_print.object_layer = (idx_object_layer < object.layers().size()) ? object.layers()[idx_object_layer ++] : nullptr; layer_to_print.support_layer = (idx_support_layer < object.support_layers().size()) ? object.support_layers()[idx_support_layer ++] : nullptr; @@ -448,6 +463,7 @@ std::vector GCode::collect_layers_to_print(const PrintObjec -- idx_object_layer; } } + layers_to_print.emplace_back(layer_to_print); } diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index f10b45723a..18437c8e16 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -78,8 +78,13 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool zs.emplace_back(layer->print_z); for (auto layer : object->support_layers()) zs.emplace_back(layer->print_z); - if (! object->layers().empty()) - object_bottom_z = object->layers().front()->print_z - object->layers().front()->height; + + // Find first object layer that is not empty and save its print_z + for (const Layer* layer : object->layers()) + if (layer->has_extrusions()) { + object_bottom_z = layer->print_z - layer->height; + break; + } } this->initialize_layers(zs); } @@ -324,6 +329,7 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_ m_layer_tools[j].has_wipe_tower = true; } else { LayerTools <_extra = *m_layer_tools.insert(m_layer_tools.begin() + j, lt_new); + //LayerTools <_prev = m_layer_tools[j]; LayerTools <_next = m_layer_tools[j + 1]; assert(! m_layer_tools[j - 1].extruders.empty() && ! lt_next.extruders.empty()); // FIXME: Following assert tripped when running combine_infill.t. I decided to comment it out for now. From eaccd737567f239ee2fdea0384b2b0050ec60e2e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 2 Aug 2019 17:53:12 +0200 Subject: [PATCH 11/14] Added InvalidItem() to ObjectDataViewModel to controling if item till exist during multiple deleting + some code cleaning --- src/slic3r/GUI/GUI_ObjectList.cpp | 45 +++++++++++-------------------- src/slic3r/GUI/wxExtensions.cpp | 12 +++++++++ src/slic3r/GUI/wxExtensions.hpp | 2 ++ 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index fede48166c..279a439eda 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1755,7 +1755,19 @@ void ObjectList::del_subobject_item(wxDataViewItem& item) if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0) m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item)); + // If last two Instances of object is selected, show the message about impossible action + bool show_msg = false; + if (type & itInstance) { + wxDataViewItemArray instances; + m_objects_model->GetChildren(m_objects_model->GetParent(item), instances); + if (instances.Count() == 2 && IsSelected(instances[0]) && IsSelected(instances[1])) + show_msg = true; + } + m_objects_model->Delete(item); + + if (show_msg) + Slic3r::GUI::show_error(nullptr, _(L("From Object List You can't delete the last intance from object."))); } void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item) @@ -1838,7 +1850,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con if (vol->is_model_part()) ++solid_cnt; if (volume->is_model_part() && solid_cnt == 1) { - Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last solid part from object."))); + Slic3r::GUI::show_error(nullptr, _(L("From Object List You can't delete the last solid part from object."))); return false; } @@ -1857,7 +1869,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con } else if (type == itInstance) { if (object->instances.size() == 1) { - Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last intance from object."))); + Slic3r::GUI::show_error(nullptr, _(L("From Object List You can't delete the last intance from object."))); return false; } @@ -2404,6 +2416,8 @@ void ObjectList::remove() for (auto& item : sels) { + if (m_objects_model->InvalidItem(item)) // item can be deleted for this moment (like last 2 Instances or Volumes) + continue; if (m_objects_model->GetParent(item) == wxDataViewItem(0)) delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1); else { @@ -3150,33 +3164,6 @@ void ObjectList::last_volume_is_deleted(const int obj_idx) volume->config.set_key_value("extruder", new ConfigOptionInt(0)); } -/* #lm_FIXME_delete_after_testing -void ObjectList::update_settings_items() -{ - m_prevent_canvas_selection_update = true; - wxDataViewItemArray sel; - GetSelections(sel); // stash selection - - wxDataViewItemArray items; - m_objects_model->GetChildren(wxDataViewItem(0), items); - - for (auto& item : items) { - const wxDataViewItem& settings_item = m_objects_model->GetSettingsItem(item); - select_item(settings_item ? settings_item : m_objects_model->AddSettingsChild(item)); - - // If settings item was deleted from the list, - // it's need to be deleted from selection array, if it was there - if (settings_item != m_objects_model->GetSettingsItem(item) && - sel.Index(settings_item) != wxNOT_FOUND) { - sel.Remove(settings_item); - } - } - - // restore selection: - SetSelections(sel); - m_prevent_canvas_selection_update = false; -} -*/ void ObjectList::update_and_show_object_settings_item() { const wxDataViewItem item = GetSelection(); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index a33b7248c3..01acb78534 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -1325,6 +1325,18 @@ int ObjectDataViewModel::GetRowByItem(const wxDataViewItem& item) const return -1; } +bool ObjectDataViewModel::InvalidItem(const wxDataViewItem& item) +{ + if (!item) + return true; + + ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID(); + if (!node || node->invalid()) + return true; + + return false; +} + wxString ObjectDataViewModel::GetName(const wxDataViewItem &item) const { ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 2a8d8fccf5..5bc81b82d4 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -355,6 +355,7 @@ public: #ifndef NDEBUG bool valid(); #endif /* NDEBUG */ + bool invalid() const { return m_idx < -1; } private: friend class ObjectDataViewModel; @@ -417,6 +418,7 @@ public: void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx); int GetRowByItem(const wxDataViewItem& item) const; bool IsEmpty() { return m_objects.empty(); } + bool InvalidItem(const wxDataViewItem& item); // helper method for wxLog From 77df54947bb4a7eed2055f15faf08f075cc1330c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Sat, 3 Aug 2019 08:51:03 +0200 Subject: [PATCH 12/14] Follow-up of c791ba776f96c8fa18c435c12dad2c726af46c3b -> Estimated times for color print layed-out as 'time for color (remaining time at color start)' --- src/libslic3r/GCodeTimeEstimator.cpp | 31 ++++++++++++++-------------- src/libslic3r/GCodeTimeEstimator.hpp | 8 +++---- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 87f8bca65d..8a2e1266a8 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -694,38 +694,39 @@ namespace Slic3r { return m_color_times; } - std::vector GCodeTimeEstimator::get_color_times_dhms(bool include_absolute) const + std::vector GCodeTimeEstimator::get_color_times_dhms(bool include_remaining) const { std::vector ret; float total_time = 0.0f; for (float t : m_color_times) { - total_time += t; - std::string time = ""; - if (include_absolute) - time += _get_time_dhms(total_time) + " ("; - time += _get_time_dhms(t); - if (include_absolute) + std::string time = _get_time_dhms(t); + if (include_remaining) + { + time += " ("; + time += _get_time_dhms(m_time - total_time); time += ")"; + } + total_time += t; ret.push_back(time); } return ret; } - std::vector GCodeTimeEstimator::get_color_times_minutes(bool include_absolute) const + std::vector GCodeTimeEstimator::get_color_times_minutes(bool include_remaining) const { std::vector ret; float total_time = 0.0f; for (float t : m_color_times) { - total_time += t; - std::string time = ""; - if (include_absolute) - time += _get_time_minutes(total_time) + " ("; - time += _get_time_minutes(t); - if (include_absolute) + std::string time = _get_time_minutes(t); + if (include_remaining) + { + time += " ("; + time += _get_time_minutes(m_time - total_time); time += ")"; - ret.push_back(time); + } + total_time += t; } return ret; } diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index 792fb72a51..8d794af1e4 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -350,12 +350,12 @@ namespace Slic3r { std::vector get_color_times() const; // Returns the estimated time, in format DDd HHh MMm SSs, for each color - // If include_absolute==true the strings will be formatted as: "absolute time (relative time)" - std::vector get_color_times_dhms(bool include_absolute) const; + // If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)" + std::vector get_color_times_dhms(bool include_remaining) const; // Returns the estimated time, in minutes (integer), for each color - // If include_absolute==true the strings will be formatted as: "absolute time (relative time)" - std::vector get_color_times_minutes(bool include_absolute) const; + // If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)" + std::vector get_color_times_minutes(bool include_remaining) const; // Return an estimate of the memory consumed by the time estimator. size_t memory_used() const; From 8078e00c1315a120860a359a6e5c0b415699e485 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Sat, 3 Aug 2019 09:07:38 +0200 Subject: [PATCH 13/14] Fixed automatic update of perspective camera --- src/slic3r/GUI/Camera.cpp | 137 ++++++++++++++++++++------------------ src/slic3r/GUI/Camera.hpp | 7 +- 2 files changed, 76 insertions(+), 68 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 242d00a071..8e3a6d1f12 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -22,10 +22,10 @@ namespace Slic3r { namespace GUI { const double Camera::DefaultDistance = 1000.0; -double Camera::FrustrumMinZSize = 50.0; +double Camera::FrustrumMinZRange = 50.0; +double Camera::FrustrumMinNearZ = 100.0; double Camera::FrustrumZMargin = 10.0; -double Camera::FovMinDeg = 0.5; -double Camera::FovMaxDeg = 75.0; +double Camera::MaxFovDeg = 60.0; Camera::Camera() : phi(45.0f) @@ -186,7 +186,8 @@ void Camera::apply_view_matrix() const void Camera::apply_projection(const BoundingBoxf3& box) const { - m_distance = DefaultDistance; + set_distance(DefaultDistance); + double w = 0.0; double h = 0.0; @@ -194,15 +195,14 @@ void Camera::apply_projection(const BoundingBoxf3& box) const { m_frustrum_zs = calc_tight_frustrum_zs_around(box); - w = (double)m_viewport[2]; - h = (double)m_viewport[3]; + w = 0.5 * (double)m_viewport[2]; + h = 0.5 * (double)m_viewport[3]; - double two_zoom = 2.0 * m_zoom; - if (two_zoom != 0.0) + if (m_zoom != 0.0) { - double inv_two_zoom = 1.0 / two_zoom; - w *= inv_two_zoom; - h *= inv_two_zoom; + double inv_zoom = 1.0 / m_zoom; + w *= inv_zoom; + h *= inv_zoom; } switch (m_type) @@ -226,21 +226,16 @@ void Camera::apply_projection(const BoundingBoxf3& box) const if (m_type == Perspective) { - double fov_rad = 2.0 * std::atan(h / m_frustrum_zs.first); - double fov_deg = Geometry::rad2deg(fov_rad); + double fov_deg = Geometry::rad2deg(2.0 * std::atan(h / m_frustrum_zs.first)); // adjust camera distance to keep fov in a limited range - if (fov_deg > FovMaxDeg + 0.001) + if (fov_deg > MaxFovDeg) { - double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMaxDeg)); - m_distance += (new_near_z - m_frustrum_zs.first); - apply_view_matrix(); - } - else if (fov_deg < FovMinDeg - 0.001) - { - double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMinDeg)); - m_distance += (new_near_z - m_frustrum_zs.first); - apply_view_matrix(); + double delta_z = h / ::tan(0.5 * Geometry::deg2rad(MaxFovDeg)) - m_frustrum_zs.first; + if (delta_z > 0.001) + set_distance(m_distance + delta_z); + else + break; } else break; @@ -328,42 +323,50 @@ void Camera::debug_render() const std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const { - std::pair ret = std::make_pair(DBL_MAX, -DBL_MAX); + std::pair ret; - Vec3d bb_min = box.min; - Vec3d bb_max = box.max; - - // box vertices in world space - std::vector vertices; - vertices.reserve(8); - vertices.push_back(bb_min); - vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2)); - vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2)); - vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2)); - vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2)); - vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2)); - vertices.push_back(bb_max); - vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2)); - - // set the Z range in eye coordinates (negative Zs are in front of the camera) - for (const Vec3d& v : vertices) + while (true) { - double z = -(m_view_matrix * v)(2); - ret.first = std::min(ret.first, z); - ret.second = std::max(ret.second, z); - } + ret = std::make_pair(DBL_MAX, -DBL_MAX); - // apply margin - ret.first -= FrustrumZMargin; - ret.second += FrustrumZMargin; + // box vertices in world space + std::vector vertices; + vertices.reserve(8); + vertices.push_back(box.min); + vertices.emplace_back(box.max(0), box.min(1), box.min(2)); + vertices.emplace_back(box.max(0), box.max(1), box.min(2)); + vertices.emplace_back(box.min(0), box.max(1), box.min(2)); + vertices.emplace_back(box.min(0), box.min(1), box.max(2)); + vertices.emplace_back(box.max(0), box.min(1), box.max(2)); + vertices.push_back(box.max); + vertices.emplace_back(box.min(0), box.max(1), box.max(2)); - // ensure min size - if (ret.second - ret.first < FrustrumMinZSize) - { - double mid_z = 0.5 * (ret.first + ret.second); - double half_size = 0.5 * FrustrumMinZSize; - ret.first = mid_z - half_size; - ret.second = mid_z + half_size; + // set the Z range in eye coordinates (negative Zs are in front of the camera) + for (const Vec3d& v : vertices) + { + double z = -(m_view_matrix * v)(2); + ret.first = std::min(ret.first, z); + ret.second = std::max(ret.second, z); + } + + // apply margin + ret.first -= FrustrumZMargin; + ret.second += FrustrumZMargin; + + // ensure min size + if (ret.second - ret.first < FrustrumMinZRange) + { + double mid_z = 0.5 * (ret.first + ret.second); + double half_size = 0.5 * FrustrumMinZRange; + ret.first = mid_z - half_size; + ret.second = mid_z + half_size; + } + + if (ret.first >= FrustrumMinNearZ) + break; + + // ensure min Near Z + set_distance(m_distance + FrustrumMinNearZ - ret.first); } return ret; @@ -385,21 +388,19 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca Vec3d up = get_dir_up(); Vec3d forward = get_dir_forward(); - Vec3d bb_min = box.min; - Vec3d bb_max = box.max; Vec3d bb_center = box.center(); // box vertices in world space std::vector vertices; vertices.reserve(8); - vertices.push_back(bb_min); - vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2)); - vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2)); - vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2)); - vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2)); - vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2)); - vertices.push_back(bb_max); - vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2)); + vertices.push_back(box.min); + vertices.emplace_back(box.max(0), box.min(1), box.min(2)); + vertices.emplace_back(box.max(0), box.max(1), box.min(2)); + vertices.emplace_back(box.min(0), box.max(1), box.min(2)); + vertices.emplace_back(box.min(0), box.min(1), box.max(2)); + vertices.emplace_back(box.max(0), box.min(1), box.max(2)); + vertices.push_back(box.max); + vertices.emplace_back(box.min(0), box.max(1), box.max(2)); double max_x = 0.0; double max_y = 0.0; @@ -430,6 +431,12 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca return std::min((double)canvas_w / (2.0 * max_x), (double)canvas_h / (2.0 * max_y)); } +void Camera::set_distance(double distance) const +{ + m_distance = distance; + apply_view_matrix(); +} + } // GUI } // Slic3r diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 79e87c7264..839d0d6cf1 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -10,10 +10,10 @@ namespace GUI { struct Camera { static const double DefaultDistance; - static double FrustrumMinZSize; + static double FrustrumMinZRange; + static double FrustrumMinNearZ; static double FrustrumZMargin; - static double FovMinDeg; - static double FovMaxDeg; + static double MaxFovDeg; enum EType : unsigned char { @@ -101,6 +101,7 @@ private: // the camera MUST be outside of the bounding box in eye coordinate of the given box std::pair calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const; double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const; + void set_distance(double distance) const; }; } // GUI From 0de6e532197bbfda4665e4b5441651e5e740afd1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 2 Aug 2019 19:45:13 +0200 Subject: [PATCH 14/14] Followup of 6ab1cec - empty layers are ok if there are only other empty layers on top of them Also fixed a possible crash in Print.cpp when preparing the wipe tower layers --- src/libslic3r/GCode.cpp | 18 ++++++++++-------- src/libslic3r/Print.cpp | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 6ae703a20f..9e5d5c4fab 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -443,14 +443,6 @@ std::vector GCode::collect_layers_to_print(const PrintObjec size_t idx_object_layer = 0; size_t idx_support_layer = 0; while (idx_object_layer < object.layers().size() || idx_support_layer < object.support_layers().size()) { - // Let's make sure that the last layer is not empty, so we don't build on top of it. - if (! layers_to_print.empty() - && (! layers_to_print.back().object_layer || ! layers_to_print.back().object_layer->has_extrusions()) - && (! layers_to_print.back().support_layer || ! layers_to_print.back().support_layer->has_extrusions())) - throw std::runtime_error(_(L("Empty layers detected, the output would not be printable.")) + "\n\n" + - _(L("Object name: ")) + object.model_object()->name + "\n" + _(L("Print z: ")) + - std::to_string(layers_to_print.back().print_z())); - LayerToPrint layer_to_print; layer_to_print.object_layer = (idx_object_layer < object.layers().size()) ? object.layers()[idx_object_layer ++] : nullptr; layer_to_print.support_layer = (idx_support_layer < object.support_layers().size()) ? object.support_layers()[idx_support_layer ++] : nullptr; @@ -464,6 +456,16 @@ std::vector GCode::collect_layers_to_print(const PrintObjec } } + // Let's make sure that the last layer is not empty, so we don't build on top of it. + if (! layers_to_print.empty() + && ((layer_to_print.object_layer && layer_to_print.object_layer->has_extrusions()) + || (layer_to_print.support_layer && layer_to_print.support_layer->has_extrusions())) + && (! layers_to_print.back().object_layer || ! layers_to_print.back().object_layer->has_extrusions()) + && (! layers_to_print.back().support_layer || ! layers_to_print.back().support_layer->has_extrusions())) + throw std::runtime_error(_(L("Empty layers detected, the output would not be printable.")) + "\n\n" + + _(L("Object name: ")) + object.model_object()->name + "\n" + _(L("Print z: ")) + + std::to_string(layers_to_print.back().print_z())); + layers_to_print.emplace_back(layer_to_print); } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index c423afeb94..e53f498106 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1723,7 +1723,7 @@ void Print::_make_wipe_tower() break; lt.has_support = true; // Insert the new support layer. - double height = lt.print_z - m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z; + double height = lt.print_z - (i == 0 ? 0. : m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z); //FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway. it_layer = m_objects.front()->insert_support_layer(it_layer, -1, height, lt.print_z, lt.print_z - 0.5 * height); ++ it_layer;