From d0b4a4a87da65ba079456863092a335f192bf6dd Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 4 May 2022 17:28:57 +0200 Subject: [PATCH 01/25] Preferences Dialog: Revert values, when "Cancel" button is clicked ([SPE-1230|https://dev.prusa3d.com/browse/SPE-1230]) + Fixed bug: If change "dark mode" checkbox and "Settings layout mode", than dark mode wouldn't processed. + Code refactoring for create_settings_mode_widget() --- src/slic3r/GUI/Preferences.cpp | 243 ++++++++++++++++++++++----------- src/slic3r/GUI/Preferences.hpp | 9 ++ 2 files changed, 171 insertions(+), 81 deletions(-) diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 75c5c116fd..c92909a8d1 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -173,6 +173,10 @@ void PreferencesDialog::build() // Add "General" tab m_optgroup_general = create_options_tab(L("General"), tabs); m_optgroup_general->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + if (auto it = m_values.find(opt_key); it != m_values.end()) { + m_values.erase(it); // we shouldn't change value, if some of those parameters were selected, and then deselected + return; + } if (opt_key == "default_action_on_close_application" || opt_key == "default_action_on_select_preset" || opt_key == "default_action_on_new_project") m_values[opt_key] = boost::any_cast(value) ? "none" : "discard"; else if (opt_key == "default_action_on_dirty_project") @@ -335,6 +339,10 @@ void PreferencesDialog::build() // Add "Camera" tab m_optgroup_camera = create_options_tab(L("Camera"), tabs); m_optgroup_camera->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + if (auto it = m_values.find(opt_key);it != m_values.end()) { + m_values.erase(it); // we shouldn't change value, if some of those parameters were selected, and then deselected + return; + } m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; }; @@ -358,25 +366,38 @@ void PreferencesDialog::build() // Add "GUI" tab m_optgroup_gui = create_options_tab(L("GUI"), tabs); m_optgroup_gui->m_on_change = [this](t_config_option_key opt_key, boost::any value) { - if (opt_key == "suppress_hyperlinks") - m_values[opt_key] = boost::any_cast(value) ? "1" : ""; - else if (opt_key == "notify_release") { + if (opt_key == "notify_release") { int val_int = boost::any_cast(value); for (const auto& item : s_keys_map_NotifyReleaseMode) { if (item.second == val_int) { m_values[opt_key] = item.first; - break; + return; } } - } else - m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; - + } if (opt_key == "use_custom_toolbar_size") { m_icon_size_sizer->ShowItems(boost::any_cast(value)); - m_optgroup_gui->parent()->Layout(); - tabs->Layout(); - this->layout(); + refresh_og(m_optgroup_gui); } + if (opt_key == "tabs_as_menu") { + bool disable_new_layout = boost::any_cast(value); + m_rb_new_settings_layout_mode->Show(!disable_new_layout); + if (disable_new_layout && m_rb_new_settings_layout_mode->GetValue()) { + m_rb_new_settings_layout_mode->SetValue(false); + m_rb_old_settings_layout_mode->SetValue(true); + } + refresh_og(m_optgroup_gui); + } + + if (auto it = m_values.find(opt_key); it != m_values.end()) { + m_values.erase(it); // we shouldn't change value, if some of those parameters were selected, and then deselected + return; + } + + if (opt_key == "suppress_hyperlinks") + m_values[opt_key] = boost::any_cast(value) ? "1" : ""; + else + m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; }; append_bool_option(m_optgroup_gui, "seq_top_layer_only", @@ -464,6 +485,10 @@ void PreferencesDialog::build() // Add "Render" tab m_optgroup_render = create_options_tab(L("Render"), tabs); m_optgroup_render->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + if (auto it = m_values.find(opt_key); it != m_values.end()) { + m_values.erase(it); // we shouldn't change value, if some of those parameters were selected, and then deselected + return; + } m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; }; @@ -479,6 +504,10 @@ void PreferencesDialog::build() // Add "Dark Mode" tab m_optgroup_dark_mode = create_options_tab(_L("Dark mode (experimental)"), tabs); m_optgroup_dark_mode->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + if (auto it = m_values.find(opt_key); it != m_values.end()) { + m_values.erase(it); // we shouldn't change value, if some of those parameters were selected, and then deselected + return; + } m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; }; @@ -509,6 +538,7 @@ void PreferencesDialog::build() auto buttons = CreateStdDialogButtonSizer(wxOK | wxCANCEL); this->Bind(wxEVT_BUTTON, &PreferencesDialog::accept, this, wxID_OK); + this->Bind(wxEVT_BUTTON, &PreferencesDialog::revert, this, wxID_CANCEL); for (int id : {wxID_OK, wxID_CANCEL}) wxGetApp().UpdateDarkUI(static_cast(FindWindowById(id, this))); @@ -592,19 +622,6 @@ void PreferencesDialog::accept(wxEvent&) } } - for (const std::string& key : { "default_action_on_close_application", - "default_action_on_select_preset", - "default_action_on_new_project" }) { - auto it = m_values.find(key); - if (it != m_values.end() && it->second != "none" && app_config->get(key) != "none") - m_values.erase(it); // we shouldn't change value, if some of those parameters were selected, and then deselected - } - { - auto it = m_values.find("default_action_on_dirty_project"); - if (it != m_values.end() && !it->second.empty() && !app_config->get("default_action_on_dirty_project").empty()) - m_values.erase(it); // we shouldn't change value, if this parameter was selected, and then deselected - } - #if 0 //#ifdef _WIN32 // #ysDarkMSW - Allow it when we deside to support the sustem colors for application if (m_values.find("always_dark_color_mode") != m_values.end()) wxGetApp().force_sys_colors_update(); @@ -629,11 +646,85 @@ void PreferencesDialog::accept(wxEvent&) wxGetApp().force_menu_update(); #endif //_MSW_DARK_MODE #endif // _WIN32 - if (m_settings_layout_changed) - ;// application will be recreated after Preference dialog will be destroyed - else - // Nothify the UI to update itself from the ini file. - wxGetApp().update_ui_from_settings(); + + wxGetApp().update_ui_from_settings(); + m_values.clear(); +} + +void PreferencesDialog::revert(wxEvent&) +{ + auto app_config = get_app_config(); + + for (auto value : m_values) { + bool reverted = false; + const std::string& key = value.first; + + if (key == "default_action_on_dirty_project") { + m_optgroup_general->set_value(key, app_config->get(key).empty()); + continue; + } + if (key == "default_action_on_close_application" || key == "default_action_on_select_preset" || key == "default_action_on_new_project") { + m_optgroup_general->set_value(key, app_config->get(key) == "none"); + continue; + } + if (key == "notify_release") { + m_optgroup_gui->set_value(key, s_keys_map_NotifyReleaseMode.at(app_config->get(key))); + continue; + } + if (key == "custom_toolbar_size") { + m_icon_size_slider->SetValue(atoi(app_config->get("custom_toolbar_size").c_str())); + continue; + } + if (key == "old_settings_layout_mode") { + m_rb_old_settings_layout_mode->SetValue(app_config->get(key) == "1"); + continue; + } + if (key == "new_settings_layout_mode") { + m_rb_new_settings_layout_mode->SetValue(app_config->get(key) == "1"); + continue; + } + if (key == "dlg_settings_layout_mode") { + m_rb_dlg_settings_layout_mode->SetValue(app_config->get(key) == "1"); + continue; + } + + for (auto opt_group : { m_optgroup_general, m_optgroup_camera, m_optgroup_gui +#ifdef _WIN32 + , m_optgroup_dark_mode +#endif // _WIN32 +#if ENABLE_ENVIRONMENT_MAP + , m_optgroup_render +#endif // ENABLE_ENVIRONMENT_MAP + }) { + if (reverted = opt_group->set_value(key, app_config->get(key) == "1")) + break; + } + if (!reverted) + int i=0; + if (key == "tabs_as_menu") { + m_rb_new_settings_layout_mode->Show(app_config->get(key) != "1"); + refresh_og(m_optgroup_gui); + continue; + } + + if (key == "use_custom_toolbar_size") { + m_icon_size_sizer->ShowItems(app_config->get(key) == "1"); + refresh_og(m_optgroup_gui); + } + } + + m_values.clear(); + + auto revert_colors = [](wxColourPickerCtrl* color_pckr, const wxColour& color) { + if (color_pckr->GetColour() != color) { + color_pckr->SetColour(color); + wxPostEvent(color_pckr, wxCommandEvent(wxEVT_COLOURPICKER_CHANGED)); + } + }; + revert_colors(m_sys_colour, wxGetApp().get_label_clr_sys()); + revert_colors(m_mod_colour, wxGetApp().get_label_clr_modified()); + + EndModal(wxID_CANCEL); } void PreferencesDialog::msw_rescale() @@ -669,6 +760,13 @@ void PreferencesDialog::layout() Refresh(); } +void PreferencesDialog::refresh_og(std::shared_ptr og) +{ + og->parent()->Layout(); + tabs->Layout(); + this->layout(); +} + void PreferencesDialog::create_icon_size_slider() { const auto app_config = get_app_config(); @@ -695,14 +793,14 @@ void PreferencesDialog::create_icon_size_slider() if (!isOSX) style |= wxSL_LABELS | wxSL_AUTOTICKS; - auto slider = new wxSlider(parent, wxID_ANY, def_val, 30, 100, + m_icon_size_slider = new wxSlider(parent, wxID_ANY, def_val, 30, 100, wxDefaultPosition, wxDefaultSize, style); - slider->SetTickFreq(10); - slider->SetPageSize(10); - slider->SetToolTip(_L("Select toolbar icon size in respect to the default one.")); + m_icon_size_slider->SetTickFreq(10); + m_icon_size_slider->SetPageSize(10); + m_icon_size_slider->SetToolTip(_L("Select toolbar icon size in respect to the default one.")); - m_icon_size_sizer->Add(slider, 1, wxEXPAND); + m_icon_size_sizer->Add(m_icon_size_slider, 1, wxEXPAND); wxStaticText* val_label{ nullptr }; if (isOSX) { @@ -710,15 +808,15 @@ void PreferencesDialog::create_icon_size_slider() m_icon_size_sizer->Add(val_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, em); } - slider->Bind(wxEVT_SLIDER, ([this, slider, val_label](wxCommandEvent e) { - auto val = slider->GetValue(); + m_icon_size_slider->Bind(wxEVT_SLIDER, ([this, val_label](wxCommandEvent e) { + auto val = m_icon_size_slider->GetValue(); m_values["custom_toolbar_size"] = (boost::format("%d") % val).str(); if (val_label) val_label->SetLabelText(wxString::Format("%d", val)); - }), slider->GetId()); + }), m_icon_size_slider->GetId()); - for (wxWindow* win : std::vector{ slider, label, val_label }) { + for (wxWindow* win : std::vector{ m_icon_size_slider, label, val_label }) { if (!win) continue; win->SetFont(wxGetApp().normal_font()); @@ -731,26 +829,6 @@ void PreferencesDialog::create_icon_size_slider() void PreferencesDialog::create_settings_mode_widget() { -#ifdef _MSW_DARK_MODE - bool disable_new_layout = wxGetApp().tabs_as_menu(); -#endif - std::vector choices = { _L("Old regular layout with the tab bar"), - _L("New layout, access via settings button in the top menu"), - _L("Settings in non-modal window") }; - - auto app_config = get_app_config(); - int selection = app_config->get("old_settings_layout_mode") == "1" ? 0 : - app_config->get("new_settings_layout_mode") == "1" ? 1 : - app_config->get("dlg_settings_layout_mode") == "1" ? 2 : 0; - -#ifdef _MSW_DARK_MODE - if (disable_new_layout) { - choices = { _L("Old regular layout with the tab bar"), - _L("Settings in non-modal window") }; - selection = app_config->get("dlg_settings_layout_mode") == "1" ? 1 : 0; - } -#endif - wxWindow* parent = m_optgroup_gui->parent(); wxGetApp().UpdateDarkUI(parent); @@ -762,32 +840,35 @@ void PreferencesDialog::create_settings_mode_widget() wxSizer* stb_sizer = new wxStaticBoxSizer(stb, wxVERTICAL); - int id = 0; - for (const wxString& label : choices) { - wxRadioButton* btn = new wxRadioButton(parent, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, id==0 ? wxRB_GROUP : 0); - stb_sizer->Add(btn); - btn->SetValue(id == selection); - - int dlg_id = 2; -#ifdef _MSW_DARK_MODE - if (disable_new_layout) - dlg_id = 1; -#endif - - btn->Bind(wxEVT_RADIOBUTTON, [this, id, dlg_id -#ifdef _MSW_DARK_MODE - , disable_new_layout -#endif - ](wxCommandEvent& ) { - m_values["old_settings_layout_mode"] = (id == 0) ? "1" : "0"; -#ifdef _MSW_DARK_MODE - if (!disable_new_layout) -#endif - m_values["new_settings_layout_mode"] = (id == 1) ? "1" : "0"; - m_values["dlg_settings_layout_mode"] = (id == dlg_id) ? "1" : "0"; + auto app_config = get_app_config(); + std::vector choices = { _L("Old regular layout with the tab bar"), + _L("New layout, access via settings button in the top menu"), + _L("Settings in non-modal window") }; + int id = -1; + auto add_radio = [this, parent, stb_sizer, choices](wxRadioButton** rb, int id, bool select) { + *rb = new wxRadioButton(parent, wxID_ANY, choices[id], wxDefaultPosition, wxDefaultSize, id == 0 ? wxRB_GROUP : 0); + stb_sizer->Add(*rb); + (*rb)->SetValue(select); + (*rb)->Bind(wxEVT_RADIOBUTTON, [this, id](wxCommandEvent&) { + m_values["old_settings_layout_mode"] = (id == 0) ? "1" : "0"; + m_values["new_settings_layout_mode"] = (id == 1) ? "1" : "0"; + m_values["dlg_settings_layout_mode"] = (id == 2) ? "1" : "0"; }); - id++; + }; + + add_radio(&m_rb_old_settings_layout_mode, ++id, app_config->get("old_settings_layout_mode") == "1"); + add_radio(&m_rb_new_settings_layout_mode, ++id, app_config->get("new_settings_layout_mode") == "1"); + add_radio(&m_rb_dlg_settings_layout_mode, ++id, app_config->get("dlg_settings_layout_mode") == "1"); + +#ifdef _MSW_DARK_MODE + if (app_config->get("tabs_as_menu") == "1") { + m_rb_new_settings_layout_mode->Hide(); + if (m_rb_new_settings_layout_mode->GetValue()) { + m_rb_new_settings_layout_mode->SetValue(false); + m_rb_old_settings_layout_mode->SetValue(true); + } } +#endif std::string opt_key = "settings_layout_mode"; m_blinkers[opt_key] = new BlinkingBitmap(parent); diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index f8b1d1237a..2f8cafeb28 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -12,6 +12,8 @@ class wxColourPickerCtrl; class wxBookCtrlBase; +class wxSlider; +class wxRadioButton; namespace Slic3r { @@ -39,6 +41,11 @@ class PreferencesDialog : public DPIDialog std::shared_ptr m_optgroup_render; #endif // ENABLE_ENVIRONMENT_MAP wxSizer* m_icon_size_sizer; + wxSlider* m_icon_size_slider {nullptr}; + wxRadioButton* m_rb_old_settings_layout_mode {nullptr}; + wxRadioButton* m_rb_new_settings_layout_mode {nullptr}; + wxRadioButton* m_rb_dlg_settings_layout_mode {nullptr}; + wxColourPickerCtrl* m_sys_colour {nullptr}; wxColourPickerCtrl* m_mod_colour {nullptr}; wxBookCtrlBase* tabs {nullptr}; @@ -58,6 +65,7 @@ public: void build(); void update_ctrls_alignment(); void accept(wxEvent&); + void revert(wxEvent&); void show(const std::string& highlight_option = std::string(), const std::string& tab_name = std::string()); protected: @@ -65,6 +73,7 @@ protected: void on_dpi_changed(const wxRect& suggested_rect) override { msw_rescale(); } void on_sys_color_changed() override; void layout(); + void refresh_og(std::shared_ptr og); void create_icon_size_slider(); void create_settings_mode_widget(); void create_settings_text_color_widget(); From 8d1a2a8fb3d6210b41fcd032f38165eed42955d1 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 5 May 2022 11:38:48 +0200 Subject: [PATCH 02/25] Implemented FR: Update toolbars "on fly", when custom toolbar size is editing from Preferences dialog (https://dev.prusa3d.com/browse/SPE-1232) + Fixed update of the color pickers --- src/slic3r/GUI/Preferences.cpp | 75 +++++++++++++++++++++++----------- src/slic3r/GUI/Preferences.hpp | 4 ++ 2 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index c92909a8d1..8ad387367a 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -9,6 +9,7 @@ #include "Notebook.hpp" #include "ButtonsDescription.hpp" #include "OG_CustomCtrl.hpp" +#include "GLCanvas3D.hpp" namespace Slic3r { @@ -54,6 +55,14 @@ PreferencesDialog::PreferencesDialog(wxWindow* parent) : m_highlighter.set_timer_owner(this, 0); } +static void update_color(wxColourPickerCtrl* color_pckr, const wxColour& color) +{ + if (color_pckr->GetColour() != color) { + color_pckr->SetColour(color); + wxPostEvent(color_pckr, wxCommandEvent(wxEVT_COLOURPICKER_CHANGED)); + } +} + void PreferencesDialog::show(const std::string& highlight_opt_key /*= std::string()*/, const std::string& tab_name/*= std::string()*/) { int selected_tab = 0; @@ -66,6 +75,14 @@ void PreferencesDialog::show(const std::string& highlight_opt_key /*= std::strin if (!highlight_opt_key.empty()) init_highlighter(highlight_opt_key); + // cache input values for custom toolbar size + m_custom_toolbar_size = atoi(get_app_config()->get("custom_toolbar_size").c_str()); + m_use_custom_toolbar_size = get_app_config()->get("use_custom_toolbar_size") == "1"; + + // update colors for color pickers + update_color(m_sys_colour, wxGetApp().get_label_clr_sys()); + update_color(m_mod_colour, wxGetApp().get_label_clr_modified()); + this->ShowModal(); } @@ -378,6 +395,10 @@ void PreferencesDialog::build() if (opt_key == "use_custom_toolbar_size") { m_icon_size_sizer->ShowItems(boost::any_cast(value)); refresh_og(m_optgroup_gui); + get_app_config()->set("use_custom_toolbar_size", boost::any_cast(value) ? "1" : "0"); + get_app_config()->save(); + wxGetApp().plater()->get_current_canvas3D()->render(); + return; } if (opt_key == "tabs_as_menu") { bool disable_new_layout = boost::any_cast(value); @@ -648,13 +669,31 @@ void PreferencesDialog::accept(wxEvent&) #endif // _WIN32 wxGetApp().update_ui_from_settings(); - m_values.clear(); + clear_cache(); } void PreferencesDialog::revert(wxEvent&) { auto app_config = get_app_config(); + bool save_app_config = false; + if (m_custom_toolbar_size != atoi(app_config->get("custom_toolbar_size").c_str())) { + app_config->set("custom_toolbar_size", (boost::format("%d") % m_custom_toolbar_size).str()); + m_icon_size_slider->SetValue(m_custom_toolbar_size); + save_app_config |= true; + } + if (m_use_custom_toolbar_size != (get_app_config()->get("use_custom_toolbar_size") == "1")) { + app_config->set("use_custom_toolbar_size", m_use_custom_toolbar_size ? "1" : "0"); + save_app_config |= true; + + m_optgroup_gui->set_value("use_custom_toolbar_size", m_use_custom_toolbar_size); + m_icon_size_sizer->ShowItems(m_use_custom_toolbar_size); + refresh_og(m_optgroup_gui); + } + if (save_app_config) + app_config->save(); + + for (auto value : m_values) { bool reverted = false; const std::string& key = value.first; @@ -671,10 +710,6 @@ void PreferencesDialog::revert(wxEvent&) m_optgroup_gui->set_value(key, s_keys_map_NotifyReleaseMode.at(app_config->get(key))); continue; } - if (key == "custom_toolbar_size") { - m_icon_size_slider->SetValue(atoi(app_config->get("custom_toolbar_size").c_str())); - continue; - } if (key == "old_settings_layout_mode") { m_rb_old_settings_layout_mode->SetValue(app_config->get(key) == "1"); continue; @@ -706,24 +741,9 @@ void PreferencesDialog::revert(wxEvent&) refresh_og(m_optgroup_gui); continue; } - - if (key == "use_custom_toolbar_size") { - m_icon_size_sizer->ShowItems(app_config->get(key) == "1"); - refresh_og(m_optgroup_gui); - } } - m_values.clear(); - - auto revert_colors = [](wxColourPickerCtrl* color_pckr, const wxColour& color) { - if (color_pckr->GetColour() != color) { - color_pckr->SetColour(color); - wxPostEvent(color_pckr, wxCommandEvent(wxEVT_COLOURPICKER_CHANGED)); - } - }; - revert_colors(m_sys_colour, wxGetApp().get_label_clr_sys()); - revert_colors(m_mod_colour, wxGetApp().get_label_clr_modified()); - + clear_cache(); EndModal(wxID_CANCEL); } @@ -760,6 +780,12 @@ void PreferencesDialog::layout() Refresh(); } +void PreferencesDialog::clear_cache() +{ + m_values.clear(); + m_custom_toolbar_size = -1; +} + void PreferencesDialog::refresh_og(std::shared_ptr og) { og->parent()->Layout(); @@ -808,9 +834,12 @@ void PreferencesDialog::create_icon_size_slider() m_icon_size_sizer->Add(val_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, em); } - m_icon_size_slider->Bind(wxEVT_SLIDER, ([this, val_label](wxCommandEvent e) { + m_icon_size_slider->Bind(wxEVT_SLIDER, ([this, val_label, app_config](wxCommandEvent e) { auto val = m_icon_size_slider->GetValue(); - m_values["custom_toolbar_size"] = (boost::format("%d") % val).str(); + + app_config->set("custom_toolbar_size", (boost::format("%d") % val).str()); + app_config->save(); + wxGetApp().plater()->get_current_canvas3D()->render(); if (val_label) val_label->SetLabelText(wxString::Format("%d", val)); diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index 2f8cafeb28..4a82cee003 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -55,6 +55,9 @@ class PreferencesDialog : public DPIDialog bool m_seq_top_layer_only_changed{ false }; bool m_recreate_GUI{false}; + int m_custom_toolbar_size{-1}; + bool m_use_custom_toolbar_size{false}; + public: explicit PreferencesDialog(wxWindow* paren); ~PreferencesDialog() = default; @@ -73,6 +76,7 @@ protected: void on_dpi_changed(const wxRect& suggested_rect) override { msw_rescale(); } void on_sys_color_changed() override; void layout(); + void clear_cache(); void refresh_og(std::shared_ptr og); void create_icon_size_slider(); void create_settings_mode_widget(); From bd644df2f75a7203fe543cc109a8564a43008610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 29 Apr 2022 08:05:52 +0200 Subject: [PATCH 03/25] Suppressed reports of memory leaks from AMD driver and D-Bus library. --- src/PrusaSlicer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 4483d60102..c79d088435 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -837,6 +837,9 @@ extern "C" { "leak:libnvidia-tls.so\n" // For NVidia driver. "leak:terminator_CreateDevice\n" // For Intel Vulkan drivers. "leak:swrast_dri.so\n" // For Mesa 3D software driver. + "leak:amdgpu_dri.so\n" // For AMD driver. + "leak:libdrm_amdgpu.so\n" // For AMD driver. + "leak:libdbus-1.so\n" // For D-Bus library. Unsure if it is a leak or not. ; } } From 356bec6e5f10b8062c17cad3bb9210daf50256cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 29 Apr 2022 08:06:24 +0200 Subject: [PATCH 04/25] Added deallocation of wxBoxSizer into OptionsGroup::activate_line() when is not used. --- src/slic3r/GUI/OptionsGroup.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index a861f478f3..257fe2532c 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -338,10 +338,12 @@ void OptionsGroup::activate_line(Line& line) wxBOTTOM | wxTOP | (option.opt.full_width ? int(wxEXPAND) : int(wxALIGN_CENTER_VERTICAL)), (wxOSX || !staticbox) ? 0 : 2); if (is_sizer_field(field)) sizer->Add(field->getSizer(), 1, (option.opt.full_width ? int(wxEXPAND) : int(wxALIGN_CENTER_VERTICAL)), 0); - } + } else + delete sizer; return; } + bool sizer_is_used = false; bool is_multioption_line = option_set.size() > 1; for (auto opt : option_set) { ConfigOptionDef option = opt.opt; @@ -356,8 +358,9 @@ void OptionsGroup::activate_line(Line& line) wxSize(sublabel_width != -1 ? sublabel_width * wxGetApp().em_unit() : -1, -1), wxALIGN_RIGHT); label->SetBackgroundStyle(wxBG_STYLE_PAINT); label->SetFont(wxGetApp().normal_font()); - sizer_tmp->Add(label, 0, wxALIGN_CENTER_VERTICAL, 0); - } + sizer_tmp->Add(label, 0, wxALIGN_CENTER_VERTICAL, 0); + sizer_is_used = true; + } // add field const Option& opt_ref = opt; @@ -412,6 +415,9 @@ void OptionsGroup::activate_line(Line& line) if (!custom_ctrl) sizer->Add(line.extra_widget_sizer, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); //! requires verification } + + if (custom_ctrl && !sizer_is_used) + delete sizer; } // create all controls for the option group from the m_lines From 17e74141ceaf6e14b8279665f31e58031ef67c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 29 Apr 2022 08:07:30 +0200 Subject: [PATCH 05/25] Fixed a crash in Lightning infill. --- src/libslic3r/Fill/Lightning/Generator.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Fill/Lightning/Generator.cpp b/src/libslic3r/Fill/Lightning/Generator.cpp index 6a4a675cbe..e0cf9680ac 100644 --- a/src/libslic3r/Fill/Lightning/Generator.cpp +++ b/src/libslic3r/Fill/Lightning/Generator.cpp @@ -116,8 +116,12 @@ void Generator::generateTrees(const PrintObject &print_object) if (layer_id == 0) return; - const Polygons& below_outlines = infill_outlines[layer_id - 1]; - outlines_locator.set_bbox(get_extents(below_outlines).inflated(SCALED_EPSILON)); + const Polygons &below_outlines = infill_outlines[layer_id - 1]; + BoundingBox below_outlines_bbox = get_extents(below_outlines).inflated(SCALED_EPSILON); + if (const BoundingBox &outlines_locator_bbox = outlines_locator.bbox(); outlines_locator_bbox.defined) + below_outlines_bbox.merge(outlines_locator_bbox); + + outlines_locator.set_bbox(below_outlines_bbox); outlines_locator.create(below_outlines, locator_cell_size); std::vector& lower_trees = m_lightning_layers[layer_id - 1].tree_roots; From d069befa1fe0cdad32ded2cbd67bfa5f47224881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 29 Apr 2022 08:08:10 +0200 Subject: [PATCH 06/25] Fixed missing layers of Lightning infill. --- src/libslic3r/Fill/Lightning/Layer.cpp | 31 +++++------------------ src/libslic3r/Fill/Lightning/TreeNode.cpp | 12 ++++----- src/libslic3r/Fill/Lightning/TreeNode.hpp | 6 ++--- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/libslic3r/Fill/Lightning/Layer.cpp b/src/libslic3r/Fill/Lightning/Layer.cpp index 1e1127a792..c996b9b7b4 100644 --- a/src/libslic3r/Fill/Lightning/Layer.cpp +++ b/src/libslic3r/Fill/Lightning/Layer.cpp @@ -6,6 +6,7 @@ #include "DistanceField.hpp" #include "TreeNode.hpp" +#include "../../ClipperUtils.hpp" #include "../../Geometry.hpp" #include "Utils.hpp" @@ -271,6 +272,7 @@ void Layer::reconnectRoots } } +#if 0 /*! * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within the root of \p max_dist2 distance. * Given a \p distance more than zero, the point will end up inside, and conversely outside. @@ -398,6 +400,7 @@ static unsigned int moveInside(const Polygons& polygons, Point& from, int distan } return static_cast(-1); } +#endif // Returns 'added someting'. Polylines Layer::convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const @@ -405,31 +408,11 @@ Polylines Layer::convertToLines(const Polygons& limit_to_outline, const coord_t if (tree_roots.empty()) return {}; - Polygons result_lines; - for (const auto& tree : tree_roots) { - // If even the furthest location in the tree is inside the polygon, the entire tree must be inside of the polygon. - // (Don't take the root as that may be on the edge and cause rounding errors to register as 'outside'.) - constexpr coord_t epsilon = 5; - Point should_be_inside = tree->getLocation(); - moveInside(limit_to_outline, should_be_inside, epsilon, epsilon * epsilon); - if (inside(limit_to_outline, should_be_inside)) - tree->convertToPolylines(result_lines, line_width); - } + Polylines result_lines; + for (const auto &tree : tree_roots) + tree->convertToPolylines(result_lines, line_width); - // TODO: allow for polylines! - Polylines split_lines; - for (Polygon &line : result_lines) { - if (line.size() <= 1) - continue; - Point last = line[0]; - for (size_t point_idx = 1; point_idx < line.size(); point_idx++) { - Point here = line[point_idx]; - split_lines.push_back({ last, here }); - last = here; - } - } - - return split_lines; + return intersection_pl(result_lines, limit_to_outline); } } // namespace Slic3r::Lightning diff --git a/src/libslic3r/Fill/Lightning/TreeNode.cpp b/src/libslic3r/Fill/Lightning/TreeNode.cpp index d1820410ee..822550fc49 100644 --- a/src/libslic3r/Fill/Lightning/TreeNode.cpp +++ b/src/libslic3r/Fill/Lightning/TreeNode.cpp @@ -343,16 +343,16 @@ coord_t Node::prune(const coord_t& pruning_distance) return max_distance_pruned; } -void Node::convertToPolylines(Polygons& output, const coord_t line_width) const +void Node::convertToPolylines(Polylines &output, const coord_t line_width) const { - Polygons result; + Polylines result; result.emplace_back(); convertToPolylines(0, result); removeJunctionOverlap(result, line_width); append(output, std::move(result)); } -void Node::convertToPolylines(size_t long_line_idx, Polygons& output) const +void Node::convertToPolylines(size_t long_line_idx, Polylines &output) const { if (m_children.empty()) { output[long_line_idx].points.push_back(m_p); @@ -372,12 +372,12 @@ void Node::convertToPolylines(size_t long_line_idx, Polygons& output) const } } -void Node::removeJunctionOverlap(Polygons& result_lines, const coord_t line_width) const +void Node::removeJunctionOverlap(Polylines &result_lines, const coord_t line_width) const { const coord_t reduction = line_width / 2; // TODO make configurable? size_t res_line_idx = 0; while (res_line_idx < result_lines.size()) { - Polygon &polyline = result_lines[res_line_idx]; + Polyline &polyline = result_lines[res_line_idx]; if (polyline.size() <= 1) { polyline = std::move(result_lines.back()); result_lines.pop_back(); @@ -387,7 +387,7 @@ void Node::removeJunctionOverlap(Polygons& result_lines, const coord_t line_widt coord_t to_be_reduced = reduction; Point a = polyline.back(); for (int point_idx = int(polyline.size()) - 2; point_idx >= 0; point_idx--) { - const Point b = polyline[point_idx]; + const Point b = polyline.points[point_idx]; const Point ab = b - a; const auto ab_len = coord_t(ab.cast().norm()); if (ab_len >= to_be_reduced) { diff --git a/src/libslic3r/Fill/Lightning/TreeNode.hpp b/src/libslic3r/Fill/Lightning/TreeNode.hpp index 55ef35e0a8..fdb80d2e6f 100644 --- a/src/libslic3r/Fill/Lightning/TreeNode.hpp +++ b/src/libslic3r/Fill/Lightning/TreeNode.hpp @@ -239,7 +239,7 @@ public: * * \param output all branches in this tree connected into polylines */ - void convertToPolylines(Polygons& output, coord_t line_width) const; + void convertToPolylines(Polylines &output, coord_t line_width) const; /*! If this was ever a direct child of the root, it'll have a previous grounding location. * @@ -258,9 +258,9 @@ protected: * \param long_line a reference to a polyline in \p output which to continue building on in the recursion * \param output all branches in this tree connected into polylines */ - void convertToPolylines(size_t long_line_idx, Polygons& output) const; + void convertToPolylines(size_t long_line_idx, Polylines &output) const; - void removeJunctionOverlap(Polygons& polylines, coord_t line_width) const; + void removeJunctionOverlap(Polylines &polylines, coord_t line_width) const; bool m_is_root; Point m_p; From 09a9d79e993baa55975e853affd25c22414c45f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 29 Apr 2022 08:09:58 +0200 Subject: [PATCH 07/25] Fix of #8227 (Lightning infill wasn't working when "Combine infill every X layers" was set to a different value than one.) --- src/libslic3r/Fill/Lightning/Generator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Fill/Lightning/Generator.cpp b/src/libslic3r/Fill/Lightning/Generator.cpp index e0cf9680ac..0bdd1c7e88 100644 --- a/src/libslic3r/Fill/Lightning/Generator.cpp +++ b/src/libslic3r/Fill/Lightning/Generator.cpp @@ -63,7 +63,7 @@ void Generator::generateInitialInternalOverhangs(const PrintObject &print_object Polygons infill_area_here; for (const LayerRegion* layerm : print_object.get_layer(layer_nr)->regions()) for (const Surface& surface : layerm->fill_surfaces.surfaces) - if (surface.surface_type == stInternal) + if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) append(infill_area_here, infill_wall_offset == 0 ? surface.expolygon : offset(surface.expolygon, infill_wall_offset)); //Remove the part of the infill area that is already supported by the walls. @@ -92,7 +92,7 @@ void Generator::generateTrees(const PrintObject &print_object) for (int layer_id = int(print_object.layers().size()) - 1; layer_id >= 0; layer_id--) for (const LayerRegion *layerm : print_object.get_layer(layer_id)->regions()) for (const Surface &surface : layerm->fill_surfaces.surfaces) - if (surface.surface_type == stInternal) + if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) append(infill_outlines[layer_id], infill_wall_offset == 0 ? surface.expolygon : offset(surface.expolygon, infill_wall_offset)); // For various operations its beneficial to quickly locate nearby features on the polygon: From 5a67d0e183d1342a4bebf0780365dd172dea9a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 5 May 2022 13:52:52 +0200 Subject: [PATCH 08/25] Fixed build on Linux (GCC 11.2). --- src/libslic3r/Geometry/ConvexHull.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libslic3r/Geometry/ConvexHull.hpp b/src/libslic3r/Geometry/ConvexHull.hpp index 9ba957824e..9e9088f1ee 100644 --- a/src/libslic3r/Geometry/ConvexHull.hpp +++ b/src/libslic3r/Geometry/ConvexHull.hpp @@ -4,6 +4,10 @@ #include "../Polygon.hpp" namespace Slic3r { + +class ExPolygon; +using ExPolygons = std::vector; + namespace Geometry { Pointf3s convex_hull(Pointf3s points); From d4b8d4d0f3abc6be73dfd9aa9b79a035a62229d2 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 5 May 2022 17:57:48 +0200 Subject: [PATCH 09/25] Further Perl unit test porting to C++ and Perl interface reduction: Ported cooling, gap fill, thin walls and polyline unit tests. --- src/libslic3r/Config.cpp | 36 ++++ src/libslic3r/Config.hpp | 74 ++++--- src/libslic3r/ExPolygon.hpp | 2 + src/libslic3r/GCode/CoolingBuffer.hpp | 2 + src/libslic3r/Geometry/ConvexHull.hpp | 2 + t/clean_polylines.t | 83 -------- t/combineinfill.t | 56 ------ t/config.t | 20 -- t/cooling.t | 214 -------------------- t/flow.t | 83 -------- t/gaps.t | 59 ------ t/gcode.t | 9 +- t/loops.t | 57 ------ t/thin.t | 185 ----------------- tests/fff_print/CMakeLists.txt | 4 + tests/fff_print/test_cooling.cpp | 274 ++++++++++++++++++++++++++ tests/fff_print/test_custom_gcode.cpp | 220 +++++++++++++++++++++ tests/fff_print/test_data.cpp | 4 + tests/fff_print/test_data.hpp | 1 + tests/fff_print/test_fill.cpp | 2 +- tests/fff_print/test_flow.cpp | 141 +++++++++---- tests/fff_print/test_gaps.cpp | 60 ++++++ tests/fff_print/test_thin_walls.cpp | 191 ++++++++++++++++++ tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_config.cpp | 22 ++- tests/libslic3r/test_geometry.cpp | 32 ++- tests/libslic3r/test_polygon.cpp | 62 ++++++ tests/libslic3r/test_polyline.cpp | 28 +++ xs/CMakeLists.txt | 1 - xs/lib/Slic3r/XS.pm | 1 - xs/src/perlglue.cpp | 1 - xs/t/01_trianglemesh.t | 30 --- xs/t/03_point.t | 6 +- xs/t/04_expolygon.t | 17 +- xs/t/05_surface.t | 7 +- xs/t/06_polygon.t | 21 -- xs/t/07_extrusionpath.t | 4 +- xs/t/08_extrusionloop.t | 3 +- xs/t/09_polyline.t | 44 +---- xs/t/10_line.t | 17 +- xs/t/12_extrusionpathcollection.t | 8 +- xs/t/17_boundingbox.t | 27 --- xs/xsp/ExPolygon.xsp | 2 - xs/xsp/GCode.xsp | 53 ----- xs/xsp/my.map | 9 - xs/xsp/typemap.xspt | 18 -- 46 files changed, 1080 insertions(+), 1113 deletions(-) delete mode 100644 t/clean_polylines.t delete mode 100644 t/config.t delete mode 100644 t/cooling.t delete mode 100644 t/flow.t delete mode 100644 t/gaps.t delete mode 100644 t/loops.t delete mode 100644 t/thin.t create mode 100644 tests/fff_print/test_cooling.cpp create mode 100644 tests/fff_print/test_custom_gcode.cpp create mode 100644 tests/fff_print/test_gaps.cpp create mode 100644 tests/fff_print/test_thin_walls.cpp create mode 100644 tests/libslic3r/test_polyline.cpp delete mode 100644 xs/t/01_trianglemesh.t delete mode 100644 xs/t/06_polygon.t delete mode 100644 xs/t/17_boundingbox.t delete mode 100644 xs/xsp/GCode.xsp diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 4b8dfa2343..2cfb0740ca 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -402,6 +402,42 @@ std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, s return out; } +std::string ConfigBase::SetDeserializeItem::format(std::initializer_list values) +{ + std::string out; + int i = 0; + for (int v : values) { + if (i ++ > 0) + out += ", "; + out += std::to_string(v); + } + return out; +} + +std::string ConfigBase::SetDeserializeItem::format(std::initializer_list values) +{ + std::string out; + int i = 0; + for (float v : values) { + if (i ++ > 0) + out += ", "; + out += float_to_string_decimal_point(double(v)); + } + return out; +} + +std::string ConfigBase::SetDeserializeItem::format(std::initializer_list values) +{ + std::string out; + int i = 0; + for (float v : values) { + if (i ++ > 0) + out += ", "; + out += float_to_string_decimal_point(v); + } + return out; +} + void ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent) { // loop through options and apply them diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index bfd307de3d..b8c046ceba 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -1950,6 +1950,11 @@ public: throw BadOptionTypeException("Conversion to a wrong type"); return static_cast(opt); } + + template T* opt(const t_config_option_key &opt_key, bool create = false) + { return dynamic_cast(this->optptr(opt_key, create)); } + template const T* opt(const t_config_option_key &opt_key) const + { return dynamic_cast(this->optptr(opt_key)); } // Apply all keys of other ConfigBase defined by this->def() to this ConfigBase. // An UnknownOptionException is thrown in case some option keys of other are not defined by this->def(), @@ -1995,11 +2000,23 @@ public: SetDeserializeItem(const std::string &opt_key, const bool value, bool append = false) : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) {} SetDeserializeItem(const char *opt_key, const int value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {} SetDeserializeItem(const std::string &opt_key, const int value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {} + SetDeserializeItem(const char *opt_key, const std::initializer_list values, bool append = false) : opt_key(opt_key), opt_value(format(values)), append(append) {} + SetDeserializeItem(const std::string &opt_key, const std::initializer_list values, bool append = false) : opt_key(opt_key), opt_value(format(values)), append(append) {} SetDeserializeItem(const char *opt_key, const float value, bool append = false) : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) {} SetDeserializeItem(const std::string &opt_key, const float value, bool append = false) : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) {} SetDeserializeItem(const char *opt_key, const double value, bool append = false) : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) {} SetDeserializeItem(const std::string &opt_key, const double value, bool append = false) : opt_key(opt_key), opt_value(float_to_string_decimal_point(value)), append(append) {} + SetDeserializeItem(const char *opt_key, const std::initializer_list values, bool append = false) : opt_key(opt_key), opt_value(format(values)), append(append) {} + SetDeserializeItem(const std::string &opt_key, const std::initializer_list values, bool append = false) : opt_key(opt_key), opt_value(format(values)), append(append) {} + SetDeserializeItem(const char *opt_key, const std::initializer_list values, bool append = false) : opt_key(opt_key), opt_value(format(values)), append(append) {} + SetDeserializeItem(const std::string &opt_key, const std::initializer_list values, bool append = false) : opt_key(opt_key), opt_value(format(values)), append(append) {} + std::string opt_key; std::string opt_value; bool append = false; + + private: + static std::string format(std::initializer_list values); + static std::string format(std::initializer_list values); + static std::string format(std::initializer_list values); }; // May throw BadOptionTypeException() if the operation fails. void set_deserialize(std::initializer_list items, ConfigSubstitutionContext& substitutions); @@ -2008,7 +2025,31 @@ public: double get_abs_value(const t_config_option_key &opt_key) const; double get_abs_value(const t_config_option_key &opt_key, double ratio_over) const; - void setenv_() const; + + std::string& opt_string(const t_config_option_key &opt_key, bool create = false) { return this->option(opt_key, create)->value; } + const std::string& opt_string(const t_config_option_key &opt_key) const { return const_cast(this)->opt_string(opt_key); } + std::string& opt_string(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } + const std::string& opt_string(const t_config_option_key &opt_key, unsigned int idx) const { return const_cast(this)->opt_string(opt_key, idx); } + + double& opt_float(const t_config_option_key &opt_key) { return this->option(opt_key)->value; } + const double& opt_float(const t_config_option_key &opt_key) const { return dynamic_cast(this->option(opt_key))->value; } + double& opt_float(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } + const double& opt_float(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } + + int& opt_int(const t_config_option_key &opt_key) { return this->option(opt_key)->value; } + int opt_int(const t_config_option_key &opt_key) const { return dynamic_cast(this->option(opt_key))->value; } + int& opt_int(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } + int opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } + + // In ConfigManipulation::toggle_print_fff_options, it is called on option with type ConfigOptionEnumGeneric* and also ConfigOptionEnum*. + // Thus the virtual method getInt() is used to retrieve the enum value. + template + ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast(this->option(opt_key)->getInt()); } + + bool opt_bool(const t_config_option_key &opt_key) const { return this->option(opt_key)->value != 0; } + bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option(opt_key)->get_at(idx) != 0; } + + void setenv_() const; ConfigSubstitutions load(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule); ConfigSubstitutions load_from_ini(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule); ConfigSubstitutions load_from_ini_string(const std::string &data, ForwardCompatibilitySubstitutionRule compatibility_rule); @@ -2017,10 +2058,10 @@ public: ConfigSubstitutions load_from_ini_string_commented(std::string &&data, ForwardCompatibilitySubstitutionRule compatibility_rule); ConfigSubstitutions load_from_gcode_file(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule); ConfigSubstitutions load(const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule); - void save(const std::string &file) const; + void save(const std::string &file) const; // Set all the nullable values to nils. - void null_nullables(); + void null_nullables(); static size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions); @@ -2129,10 +2170,6 @@ public: // Allow DynamicConfig to be instantiated on ints own without a definition. // If the definition is not defined, the method requiring the definition will throw NoDefinitionException. const ConfigDef* def() const override { return nullptr; } - template T* opt(const t_config_option_key &opt_key, bool create = false) - { return dynamic_cast(this->option(opt_key, create)); } - template const T* opt(const t_config_option_key &opt_key) const - { return dynamic_cast(this->option(opt_key)); } // Overrides ConfigResolver::optptr(). const ConfigOption* optptr(const t_config_option_key &opt_key) const override; // Overrides ConfigBase::optptr(). Find ando/or create a ConfigOption instance for a given name. @@ -2163,29 +2200,6 @@ public: // Returns options being equal in the two configs, ignoring options not present in both configs. t_config_option_keys equal(const DynamicConfig &other) const; - std::string& opt_string(const t_config_option_key &opt_key, bool create = false) { return this->option(opt_key, create)->value; } - const std::string& opt_string(const t_config_option_key &opt_key) const { return const_cast(this)->opt_string(opt_key); } - std::string& opt_string(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } - const std::string& opt_string(const t_config_option_key &opt_key, unsigned int idx) const { return const_cast(this)->opt_string(opt_key, idx); } - - double& opt_float(const t_config_option_key &opt_key) { return this->option(opt_key)->value; } - const double& opt_float(const t_config_option_key &opt_key) const { return dynamic_cast(this->option(opt_key))->value; } - double& opt_float(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } - const double& opt_float(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } - - int& opt_int(const t_config_option_key &opt_key) { return this->option(opt_key)->value; } - int opt_int(const t_config_option_key &opt_key) const { return dynamic_cast(this->option(opt_key))->value; } - int& opt_int(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } - int opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } - - // In ConfigManipulation::toggle_print_fff_options, it is called on option with type ConfigOptionEnumGeneric* and also ConfigOptionEnum*. - // Thus the virtual method getInt() is used to retrieve the enum value. - template - ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast(this->option(opt_key)->getInt()); } - - bool opt_bool(const t_config_option_key &opt_key) const { return this->option(opt_key)->value != 0; } - bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option(opt_key)->get_at(idx) != 0; } - // Command line processing bool read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys = nullptr); diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 344450c4a9..7eccf2ec82 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -67,6 +67,8 @@ public: void simplify(double tolerance, ExPolygons* expolygons) const; void medial_axis(double max_width, double min_width, ThickPolylines* polylines) const; void medial_axis(double max_width, double min_width, Polylines* polylines) const; + Polylines medial_axis(double max_width, double min_width) const + { Polylines out; this->medial_axis(max_width, min_width, &out); return out; } Lines lines() const; // Number of contours (outer contour with holes). diff --git a/src/libslic3r/GCode/CoolingBuffer.hpp b/src/libslic3r/GCode/CoolingBuffer.hpp index 1fe0405184..91a81c7f31 100644 --- a/src/libslic3r/GCode/CoolingBuffer.hpp +++ b/src/libslic3r/GCode/CoolingBuffer.hpp @@ -26,6 +26,8 @@ public: void reset(const Vec3d &position); void set_current_extruder(unsigned int extruder_id) { m_current_extruder = extruder_id; } std::string process_layer(std::string &&gcode, size_t layer_id, bool flush); + std::string process_layer(const std::string &gcode, size_t layer_id, bool flush) + { return this->process_layer(std::string(gcode), layer_id, flush); } private: CoolingBuffer& operator=(const CoolingBuffer&) = delete; diff --git a/src/libslic3r/Geometry/ConvexHull.hpp b/src/libslic3r/Geometry/ConvexHull.hpp index 9e9088f1ee..94f4e4cf21 100644 --- a/src/libslic3r/Geometry/ConvexHull.hpp +++ b/src/libslic3r/Geometry/ConvexHull.hpp @@ -1,6 +1,8 @@ #ifndef slic3r_Geometry_ConvexHull_hpp_ #define slic3r_Geometry_ConvexHull_hpp_ +#include + #include "../Polygon.hpp" namespace Slic3r { diff --git a/t/clean_polylines.t b/t/clean_polylines.t deleted file mode 100644 index 50c6f5bbdb..0000000000 --- a/t/clean_polylines.t +++ /dev/null @@ -1,83 +0,0 @@ -use Test::More; -use strict; -use warnings; - -plan tests => 6; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use Slic3r; - -{ - my $polyline = Slic3r::Polyline->new( - [0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[0,0], - ); - $polyline->simplify(1); - is_deeply $polyline->pp, [ [0, 0], [2, 0], [2, 2], [0, 2], [0, 0] ], 'Douglas-Peucker'; -} - -{ - my $polyline = Slic3r::Polyline->new( - [0,0], [50,50], [100,0], [125,-25], [150,50], - ); - $polyline->simplify(25); - is_deeply $polyline->pp, [ [0, 0], [50, 50], [125, -25], [150, 50] ], 'Douglas-Peucker'; -} - -{ - my $gear = Slic3r::Polygon->new_scale( - [144.9694,317.1543], [145.4181,301.5633], [146.3466,296.921], [131.8436,294.1643], [131.7467,294.1464], - [121.7238,291.5082], [117.1631,290.2776], [107.9198,308.2068], [100.1735,304.5101], [104.9896,290.3672], - [106.6511,286.2133], [93.453,279.2327], [81.0065,271.4171], [67.7886,286.5055], [60.7927,280.1127], - [69.3928,268.2566], [72.7271,264.9224], [61.8152,253.9959], [52.2273,242.8494], [47.5799,245.7224], - [34.6577,252.6559], [30.3369,245.2236], [42.1712,236.3251], [46.1122,233.9605], [43.2099,228.4876], - [35.0862,211.5672], [33.1441,207.0856], [13.3923,212.1895], [10.6572,203.3273], [6.0707,204.8561], - [7.2775,204.4259], [29.6713,196.3631], [25.9815,172.1277], [25.4589,167.2745], [19.8337,167.0129], - [5.0625,166.3346], [5.0625,156.9425], [5.3701,156.9282], [21.8636,156.1628], [25.3713,156.4613], - [25.4243,155.9976], [29.3432,155.8157], [30.3838,149.3549], [26.3596,147.8137], [27.1085,141.2604], - [29.8466,126.8337], [24.5841,124.9201], [10.6664,119.8989], [13.4454,110.9264], [33.1886,116.0691], - [38.817,103.1819], [45.8311,89.8133], [30.4286,76.81], [35.7686,70.0812], [48.0879,77.6873], - [51.564,81.1635], [61.9006,69.1791], [72.3019,58.7916], [60.5509,42.5416], [68.3369,37.1532], - [77.9524,48.1338], [80.405,52.2215], [92.5632,44.5992], [93.0123,44.3223], [106.3561,37.2056], - [100.8631,17.4679], [108.759,14.3778], [107.3148,11.1283], [117.0002,32.8627], [140.9109,27.3974], - [145.7004,26.4994], [145.1346,6.1011], [154.502,5.4063], [156.9398,25.6501], [171.0557,26.2017], - [181.3139,27.323], [186.2377,27.8532], [191.6031,8.5474], [200.6724,11.2756], [197.2362,30.2334], - [220.0789,39.1906], [224.3261,41.031], [236.3506,24.4291], [243.6897,28.6723], [234.2956,46.7747], - [245.6562,55.1643], [257.2523,65.0901], [261.4374,61.5679], [273.1709,52.8031], [278.555,59.5164], - [268.4334,69.8001], [264.1615,72.3633], [268.2763,77.9442], [278.8488,93.5305], [281.4596,97.6332], - [286.4487,95.5191], [300.2821,90.5903], [303.4456,98.5849], [286.4523,107.7253], [293.7063,131.1779], - [294.9748,135.8787], [314.918,133.8172], [315.6941,143.2589], [300.9234,146.1746], [296.6419,147.0309], - [297.1839,161.7052], [296.6136,176.3942], [302.1147,177.4857], [316.603,180.3608], [317.1658,176.7341], - [315.215,189.6589], [315.1749,189.6548], [294.9411,187.5222], [291.13,201.7233], [286.2615,215.5916], - [291.1944,218.2545], [303.9158,225.1271], [299.2384,233.3694], [285.7165,227.6001], [281.7091,225.1956], - [273.8981,237.6457], [268.3486,245.2248], [267.4538,246.4414], [264.8496,250.0221], [268.6392,253.896], - [278.5017,265.2131], [272.721,271.4403], [257.2776,258.3579], [234.4345,276.5687], [242.6222,294.8315], - [234.9061,298.5798], [227.0321,286.2841], [225.2505,281.8301], [211.5387,287.8187], [202.3025,291.0935], - [197.307,292.831], [199.808,313.1906], [191.5298,315.0787], [187.3082,299.8172], [186.4201,295.3766], - [180.595,296.0487], [161.7854,297.4248], [156.8058,297.6214], [154.3395,317.8592], - ); - - my $num_points = scalar @$gear; - my $simplified = $gear->simplify(1000); - ok @$simplified == 1, 'gear simplified to a single polygon'; - ###note sprintf "original points: %d\nnew points: %d", $num_points, scalar(@{$simplified->[0]}); - ok @{$simplified->[0]} < $num_points, 'gear was further simplified using Douglas-Peucker'; -} - -{ - - my $hole_in_square = Slic3r::Polygon->new( # cw - [140, 140], - [140, 160], - [160, 160], - [160, 140], - ); - my $simplified = $hole_in_square->simplify(2); - is scalar(@$simplified), 1, 'hole simplification returns one polygon'; - ok $simplified->[0]->is_counter_clockwise, 'hole simplification turns cw polygon into ccw polygon'; -} - diff --git a/t/combineinfill.t b/t/combineinfill.t index a19e817a14..ebb4304196 100644 --- a/t/combineinfill.t +++ b/t/combineinfill.t @@ -107,60 +107,4 @@ plan tests => 8; 'infill combination is idempotent'; } -# the following needs to be adapted to the new API -if (0) { - my $config = Slic3r::Config::new_from_defaults; - $config->set('skirts', 0); - $config->set('solid_layers', 0); - $config->set('bottom_solid_layers', 0); - $config->set('top_solid_layers', 0); - $config->set('infill_every_layers', 6); - $config->set('layer_height', 0.06); - $config->set('perimeters', 1); - - my $test = sub { - my ($shift) = @_; - - my $self = Slic3r::Test::init_print('20mm_cube', config => $config); - - $shift /= &Slic3r::SCALING_FACTOR; - my $scale = 4; # make room for fat infill lines with low layer height - - # Put a slope on the box's sides by shifting x and y coords by $tilt * (z / boxheight). - # The test here is to put such a slight slope on the walls that it should - # not trigger any extra fill on fill layers that should be empty when - # combine infill is enabled. - $_->[0] += $shift * ($_->[2] / (20 / &Slic3r::SCALING_FACTOR)) for @{$self->objects->[0]->meshes->[0]->vertices}; - $_->[1] += $shift * ($_->[2] / (20 / &Slic3r::SCALING_FACTOR)) for @{$self->objects->[0]->meshes->[0]->vertices}; - $_ = [$_->[0]*$scale, $_->[1]*$scale, $_->[2]] for @{$self->objects->[0]->meshes->[0]->vertices}; - - # copy of Print::export_gcode() up to the point - # after fill surfaces are combined - $_->slice for @{$self->objects}; - $_->make_perimeters for @{$self->objects}; - $_->detect_surfaces_type for @{$self->objects}; - $_->prepare_fill_surfaces for map @{$_->regions}, map @{$_->layers}, @{$self->objects}; - $_->process_external_surfaces for map @{$_->regions}, map @{$_->layers}, @{$self->objects}; - $_->discover_horizontal_shells for @{$self->objects}; - $_->combine_infill for @{$self->objects}; - - # Only layers with id % 6 == 0 should have fill. - my $spurious_infill = 0; - foreach my $layer (map @{$_->layers}, @{$self->objects}) { - ++$spurious_infill if ($layer->id % 6 && grep @{$_->fill_surfaces} > 0, @{$layer->regions}); - } - - $spurious_infill -= scalar(@{$self->objects->[0]->layers} - 1) % 6; - - fail "spurious fill surfaces found on layers that should have none (walls " . sprintf("%.4f", Slic3r::Geometry::rad2deg(atan2($shift, 20/&Slic3r::SCALING_FACTOR))) . " degrees off vertical)" - unless $spurious_infill == 0; - 1; - }; - - # Test with mm skew offsets for the top of the 20mm-high box - for my $shift (0, 0.0001, 1) { - ok $test->($shift), "no spurious fill surfaces with box walls " . sprintf("%.4f",Slic3r::Geometry::rad2deg(atan2($shift, 20))) . " degrees off of vertical"; - } -} - __END__ diff --git a/t/config.t b/t/config.t deleted file mode 100644 index f4a1867de6..0000000000 --- a/t/config.t +++ /dev/null @@ -1,20 +0,0 @@ -use Test::More tests => 1; -use strict; -use warnings; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use Slic3r; -use Slic3r::Test; - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('perimeter_extrusion_width', '250%'); - ok $config->validate, 'percent extrusion width is validated'; -} - -__END__ diff --git a/t/cooling.t b/t/cooling.t deleted file mode 100644 index e46cfa2f77..0000000000 --- a/t/cooling.t +++ /dev/null @@ -1,214 +0,0 @@ -use Test::More; -use strict; -use warnings; - -plan tests => 14; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use List::Util qw(none all); -use Slic3r; -use Slic3r::Test; - -my $gcodegen; -sub buffer { - my $config = shift; - if (defined($config)) { - $config = $config->clone(); - } else { - $config = Slic3r::Config->new; - } - my $config_override = shift; - foreach my $key (keys %{$config_override}) { - $config->set($key, ${$config_override}{$key}); - } - - my $print_config = Slic3r::Config::Print->new; - $print_config->apply_dynamic($config); - - $gcodegen = Slic3r::GCode->new; - $gcodegen->apply_print_config($print_config); - $gcodegen->set_layer_count(10); - - my $extruders_ref = shift; - $extruders_ref = [ 0 ] if !defined $extruders_ref; - $gcodegen->set_extruders($extruders_ref); - return Slic3r::GCode::CoolingBuffer->new($gcodegen); -} - -my $gcode1 = "G1 X100 E1 F3000\n"; -my $print_time1 = 100 / (3000 / 60); # 2 sec -my $gcode2 = $gcode1 . "G1 X0 E1 F3000\n"; -my $print_time2 = 2 * $print_time1; # 4 sec - -my $config = Slic3r::Config::new_from_defaults; -# Default cooling settings. -$config->set('bridge_fan_speed', [ 100 ]); -$config->set('cooling', [ 1 ]); -$config->set('fan_always_on', [ 0 ]); -$config->set('fan_below_layer_time', [ 60 ]); -$config->set('max_fan_speed', [ 100 ]); -$config->set('min_print_speed', [ 10 ]); -$config->set('slowdown_below_layer_time', [ 5 ]); -# Default print speeds. -$config->set('bridge_speed', 60); -$config->set('external_perimeter_speed', '50%'); -$config->set('first_layer_speed', 30); -$config->set('gap_fill_speed', 20); -$config->set('infill_speed', 80); -$config->set('perimeter_speed', 60); -$config->set('small_perimeter_speed', 15); -$config->set('solid_infill_speed', 20); -$config->set('top_solid_infill_speed', 15); -$config->set('max_print_speed', 80); -# Override for tests. -$config->set('disable_fan_first_layers', [ 0 ]); - -{ - my $gcode_src = "G1 F3000;_EXTRUDE_SET_SPEED\nG1 X100 E1"; - # Print time of $gcode. - my $print_time = 100 / (3000 / 60); - my $buffer = buffer($config, { 'slowdown_below_layer_time' => [ $print_time * 0.999 ] }); - my $gcode = $buffer->process_layer($gcode_src, 0); - like $gcode, qr/F3000/, 'speed is not altered when elapsed time is greater than slowdown threshold'; -} - -{ - my $gcode_src = - "G1 X50 F2500\n" . - "G1 F3000;_EXTRUDE_SET_SPEED\n" . - "G1 X100 E1\n" . - ";_EXTRUDE_END\n" . - "G1 E4 F400", - # Print time of $gcode. - my $print_time = 50 / (2500 / 60) + 100 / (3000 / 60) + 4 / (400 / 60); - my $buffer = buffer($config, { 'slowdown_below_layer_time' => [ $print_time * 1.001 ] }); - my $gcode = $buffer->process_layer($gcode_src, 0); - unlike $gcode, qr/F3000/, 'speed is altered when elapsed time is lower than slowdown threshold'; - like $gcode, qr/F2500/, 'speed is not altered for travel moves'; - like $gcode, qr/F400/, 'speed is not altered for extruder-only moves'; -} - -{ - my $buffer = buffer($config, { - 'fan_below_layer_time' => [ $print_time1 * 0.88 ], - 'slowdown_below_layer_time' => [ $print_time1 * 0.99 ] - }); - my $gcode = $buffer->process_layer($gcode1, 0); - unlike $gcode, qr/M106/, 'fan is not activated when elapsed time is greater than fan threshold'; -} - -{ - my $gcode .= buffer($config, { 'slowdown_below_layer_time', [ $print_time2 * 0.99 ] })->process_layer($gcode2, 0); - like $gcode, qr/F3000/, 'slowdown is computed on all objects printing at the same Z'; -} - -{ - # use an elapsed time which is < the threshold but greater than it when summed twice - my $buffer = buffer($config, { - 'fan_below_layer_time' => [ $print_time2 * 0.65], - 'slowdown_below_layer_time' => [ $print_time2 * 0.7 ] - }); - my $gcode = $buffer->process_layer($gcode2, 0) . - $buffer->process_layer($gcode2, 1); - unlike $gcode, qr/M106/, 'fan is not activated on all objects printing at different Z'; -} - -{ - # use an elapsed time which is < the threshold even when summed twice - my $buffer = buffer($config, { - 'fan_below_layer_time' => [ $print_time2 + 1 ], - 'slowdown_below_layer_time' => [ $print_time2 + 2 ] - }); - my $gcode = $buffer->process_layer($gcode2, 0) . - $buffer->process_layer($gcode2, 1); - like $gcode, qr/M106/, 'fan is activated on all objects printing at different Z'; -} - -{ - my $buffer = buffer($config, { - 'cooling' => [ 1 , 0 ], - 'fan_below_layer_time' => [ $print_time2 + 1, $print_time2 + 1 ], - 'slowdown_below_layer_time' => [ $print_time2 + 2, $print_time2 + 2 ] - }, - [ 0, 1]); - my $gcode = $buffer->process_layer($gcode1 . "T1\nG1 X0 E1 F3000\n", 0); - like $gcode, qr/^M106/, 'fan is activated for the 1st tool'; - like $gcode, qr/.*M107/, 'fan is disabled for the 2nd tool'; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('cooling', [ 1 ]); - $config->set('bridge_fan_speed', [ 100 ]); - $config->set('fan_below_layer_time', [ 0 ]); - $config->set('slowdown_below_layer_time', [ 0 ]); - $config->set('bridge_speed', 99); - $config->set('top_solid_layers', 1); # internal bridges use solid_infil speed - $config->set('bottom_solid_layers', 1); # internal bridges use solid_infil speed - - my $print = Slic3r::Test::init_print('overhang', config => $config); - my $fan = 0; - my $fan_with_incorrect_speeds = my $fan_with_incorrect_print_speeds = 0; - my $bridge_with_no_fan = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($cmd eq 'M106') { - $fan = $args->{S}; - $fan_with_incorrect_speeds++ if $fan != 255; - } elsif ($cmd eq 'M107') { - $fan = 0; - } elsif ($info->{extruding} && $info->{dist_XY} > 0) { - $fan_with_incorrect_print_speeds++ - if ($fan > 0) && ($args->{F} // $self->F) != 60*$config->bridge_speed; - $bridge_with_no_fan++ - if !$fan && ($args->{F} // $self->F) == 60*$config->bridge_speed; - } - }); - ok !$fan_with_incorrect_speeds, 'bridge fan speed is applied correctly'; - ok !$fan_with_incorrect_print_speeds, 'bridge fan is only turned on for bridges'; - ok !$bridge_with_no_fan, 'bridge fan is turned on for all bridges'; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('cooling', [ 1 ]); - $config->set('fan_below_layer_time', [ 0 ]); - $config->set('slowdown_below_layer_time', [ 10 ]); - $config->set('min_print_speed', [ 0 ]); - $config->set('start_gcode', ''); - $config->set('first_layer_speed', '100%'); - $config->set('external_perimeter_speed', 99); - - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my @layer_times = (0); # in seconds - my %layer_external = (); # z => 1 - Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($cmd eq 'G1') { - if ($info->{dist_Z}) { - push @layer_times, 0; - $layer_external{ $args->{Z} } = 0; - } - $layer_times[-1] += abs($info->{dist_XY} || $info->{dist_E} || $info->{dist_Z} || 0) / ($args->{F} // $self->F) * 60; - if ($args->{F} && $args->{F} == $config->external_perimeter_speed*60) { - $layer_external{ $self->Z }++; - } - } - }); - @layer_times = grep $_, @layer_times; - my $all_below = none { $_ < $config->slowdown_below_layer_time->[0] } @layer_times; - ok $all_below, 'slowdown_below_layer_time is honored'; - - # check that all layers have at least one unaltered external perimeter speed -# my $external = all { $_ > 0 } values %layer_external; -# ok $external, 'slowdown_below_layer_time does not alter external perimeters'; -} - -__END__ diff --git a/t/flow.t b/t/flow.t deleted file mode 100644 index 50c4916049..0000000000 --- a/t/flow.t +++ /dev/null @@ -1,83 +0,0 @@ -use Test::More tests => 6; -use strict; -use warnings; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use List::Util qw(first sum); -use Slic3r; -use Slic3r::Geometry qw(scale PI); -use Slic3r::Test; - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('skirts', 1); - $config->set('brim_width', 2); - $config->set('perimeters', 3); - $config->set('fill_density', 0.4); - $config->set('bottom_solid_layers', 1); - $config->set('first_layer_extrusion_width', 2); - $config->set('first_layer_height', $config->layer_height); - $config->set('filament_diameter', [ 3.0 ]); - $config->set('nozzle_diameter', [ 0.5 ]); - - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my @E_per_mm = (); - Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($self->Z == $config->layer_height) { # only consider first layer - if ($info->{extruding} && $info->{dist_XY} > 0) { - push @E_per_mm, $info->{dist_E} / $info->{dist_XY}; - } - } - }); - my $E_per_mm_avg = sum(@E_per_mm) / @E_per_mm; - # allow some tolerance because solid rectilinear infill might be adjusted/stretched - ok !(defined first { abs($_ - $E_per_mm_avg) > 0.015 } @E_per_mm), - 'first_layer_extrusion_width applies to everything on first layer'; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('bridge_speed', 99); - $config->set('bridge_flow_ratio', 1); - $config->set('cooling', [ 0 ]); # to prevent speeds from being altered - $config->set('first_layer_speed', '100%'); # to prevent speeds from being altered - - my $test = sub { - my $print = Slic3r::Test::init_print('overhang', config => $config); - my @E_per_mm = (); - Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($info->{extruding} && $info->{dist_XY} > 0) { - if (($args->{F} // $self->F) == $config->bridge_speed*60) { - push @E_per_mm, $info->{dist_E} / $info->{dist_XY}; - } - } - }); - my $expected_mm3_per_mm = ($config->nozzle_diameter->[0]**2) * PI/4 * $config->bridge_flow_ratio; - my $expected_E_per_mm = $expected_mm3_per_mm / ((($config->filament_diameter->[0]/2)**2)*PI); - ok !(defined first { abs($_ - $expected_E_per_mm) > 0.01 } @E_per_mm), - 'expected flow when using bridge_flow_ratio = ' . $config->bridge_flow_ratio; - }; - - $config->set('bridge_flow_ratio', 0.5); - $test->(); - $config->set('bridge_flow_ratio', 2); - $test->(); - $config->set('extrusion_width', 0.4); - $config->set('bridge_flow_ratio', 1); - $test->(); - $config->set('bridge_flow_ratio', 0.5); - $test->(); - $config->set('bridge_flow_ratio', 2); - $test->(); -} - -__END__ diff --git a/t/gaps.t b/t/gaps.t deleted file mode 100644 index 2594ac0870..0000000000 --- a/t/gaps.t +++ /dev/null @@ -1,59 +0,0 @@ -use Test::More tests => 1; -use strict; -use warnings; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use List::Util qw(first); -use Slic3r; -use Slic3r::Geometry qw(PI scale unscale convex_hull); -use Slic3r::Surface ':types'; -use Slic3r::Test; - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('skirts', 0); - $config->set('perimeter_speed', 66); - $config->set('external_perimeter_speed', 66); - $config->set('small_perimeter_speed', 66); - $config->set('gap_fill_speed', 99); - $config->set('perimeters', 1); - $config->set('cooling', [ 0 ]); # to prevent speeds from being altered - $config->set('first_layer_speed', '100%'); # to prevent speeds from being altered - $config->set('perimeter_extrusion_width', 0.35); - $config->set('first_layer_extrusion_width', 0.35); - - my $print = Slic3r::Test::init_print('two_hollow_squares', config => $config); - my @perimeter_points = (); - my $last = ''; # perimeter | gap - my $gap_fills_outside_last_perimeters = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($info->{extruding} && $info->{dist_XY} > 0) { - my $F = $args->{F} // $self->F; - my $point = Slic3r::Point->new_scale($info->{new_X}, $info->{new_Y}); - if ($F == $config->perimeter_speed*60) { - if ($last eq 'gap') { - @perimeter_points = (); - } - push @perimeter_points, $point; - $last = 'perimeter'; - } elsif ($F == $config->gap_fill_speed*60) { - my $convex_hull = convex_hull(\@perimeter_points); - if (!$convex_hull->contains_point($point)) { - $gap_fills_outside_last_perimeters++; - } - - $last = 'gap'; - } - } - }); - is $gap_fills_outside_last_perimeters, 0, 'gap fills are printed before leaving islands'; -} - -__END__ diff --git a/t/gcode.t b/t/gcode.t index b95505e436..902c40b834 100644 --- a/t/gcode.t +++ b/t/gcode.t @@ -1,4 +1,4 @@ -use Test::More tests => 24; +use Test::More tests => 23; use strict; use warnings; @@ -13,13 +13,6 @@ use Slic3r; use Slic3r::Geometry qw(scale convex_hull); use Slic3r::Test; -{ - my $gcodegen = Slic3r::GCode->new(); - $gcodegen->set_layer_count(1); - $gcodegen->set_origin(Slic3r::Pointf->new(10, 10)); - is_deeply $gcodegen->last_pos->arrayref, [scale -10, scale -10], 'last_pos is shifted correctly'; -} - { my $config = Slic3r::Config::new_from_defaults; $config->set('wipe', [1]); diff --git a/t/loops.t b/t/loops.t deleted file mode 100644 index e662469cad..0000000000 --- a/t/loops.t +++ /dev/null @@ -1,57 +0,0 @@ -use Test::More; -use strict; -use warnings; - -plan skip_all => 'temporarily disabled'; -plan tests => 4; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use Slic3r; -use Slic3r::Test; - -{ - # We only need to slice at one height, so we'll build a non-manifold mesh - # that still produces complete loops at that height. Triangular walls are - # enough for this purpose. - # Basically we want to check what happens when three concentric loops happen - # to be at the same height, the two external ones being ccw and the other being - # a hole, thus cw. - my (@vertices, @facets) = (); - Slic3r::Test::add_facet($_, \@vertices, \@facets) for - # external surface below the slicing Z - [ [0,0,0], [20,0,10], [0,0,10] ], - [ [20,0,0], [20,20,10], [20,0,10] ], - [ [20,20,0], [0,20,10], [20,20,10] ], - [ [0,20,0], [0,0,10], [0,20,10] ], - - # external insetted surface above the slicing Z - [ [2,2,10], [18,2,10], [2,2,20] ], - [ [18,2,10], [18,18,10], [18,2,20] ], - [ [18,18,10], [2,18,10], [18,18,20] ], - [ [2,18,10], [2,2,10], [2,18,20] ], - - # insetted hole below the slicing Z - [ [15,5,0], [5,5,10], [15,5,10] ], - [ [15,15,0], [15,5,10], [15,15,10] ], - [ [5,15,0], [15,15,10], [5,15,10] ], - [ [5,5,0], [5,15,10], [5,5,10] ]; - - my $mesh = Slic3r::TriangleMesh->new; - $mesh->ReadFromPerl(\@vertices, \@facets); - $mesh->analyze; - my @lines = map $mesh->intersect_facet($_, 10), 0..$#facets; - my $loops = Slic3r::TriangleMesh::make_loops(\@lines); - is scalar(@$loops), 3, 'correct number of loops detected'; - is scalar(grep $_->is_counter_clockwise, @$loops), 2, 'correct number of ccw loops detected'; - - my @surfaces = Slic3r::Layer::Region::_merge_loops($loops, 0); - is scalar(@surfaces), 1, 'one surface detected'; - is scalar(@{$surfaces[0]->expolygon})-1, 1, 'surface has one hole'; -} - -__END__ diff --git a/t/thin.t b/t/thin.t deleted file mode 100644 index 50e7abc950..0000000000 --- a/t/thin.t +++ /dev/null @@ -1,185 +0,0 @@ -use Test::More tests => 23; -use strict; -use warnings; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use Slic3r; -use List::Util qw(first sum none); -use Slic3r::Geometry qw(epsilon scale unscale scaled_epsilon Y); -use Slic3r::Test; - -# Disable this until a more robust implementation is provided. It currently -# fails on Linux 32bit because some spurious extrudates are generated. -if (0) { - my $config = Slic3r::Config::new_from_defaults; - $config->set('layer_height', 0.2); - $config->set('first_layer_height', $config->layer_height); - $config->set('extrusion_width', 0.5); - $config->set('first_layer_extrusion_width', '200%'); # check this one too - $config->set('skirts', 0); - $config->set('thin_walls', 1); - - my $print = Slic3r::Test::init_print('gt2_teeth', config => $config); - - my %extrusion_paths = (); # Z => count of continuous extrusions - my $extruding = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($cmd eq 'G1') { - if ($info->{extruding} && $info->{dist_XY}) { - if (!$extruding) { - $extrusion_paths{$self->Z} //= 0; - $extrusion_paths{$self->Z}++; - } - $extruding = 1; - } else { - $extruding = 0; - } - } - }); - - ok !(first { $_ != 3 } values %extrusion_paths), - 'no superfluous thin walls are generated for toothed profile'; -} - -{ - my $square = Slic3r::Polygon->new_scale( # ccw - [100, 100], - [200, 100], - [200, 200], - [100, 200], - ); - my $hole_in_square = Slic3r::Polygon->new_scale( # cw - [140, 140], - [140, 160], - [160, 160], - [160, 140], - ); - my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square); - my $res = $expolygon->medial_axis(scale 40, scale 0.5); - is scalar(@$res), 1, 'medial axis of a square shape is a single path'; - isa_ok $res->[0], 'Slic3r::Polyline', 'medial axis result is a polyline'; - ok $res->[0]->first_point->coincides_with($res->[0]->last_point), 'polyline forms a closed loop'; - ok $res->[0]->length > $hole_in_square->length && $res->[0]->length < $square->length, - 'medial axis loop has reasonable length'; -} - -{ - my $expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new_scale( - [100, 100], - [120, 100], - [120, 200], - [100, 200], - )); - my $res = $expolygon->medial_axis(scale 20, scale 0.5); - is scalar(@$res), 1, 'medial axis of a narrow rectangle is a single line'; - ok unscale($res->[0]->length) >= (200-100 - (120-100)) - epsilon, 'medial axis has reasonable length'; - - $expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new_scale( - [100, 100], - [120, 100], - [120, 200], - [105, 200], # extra point in the short side - [100, 200], - )); - my $res2 = $expolygon->medial_axis(scale 1, scale 0.5); - is scalar(@$res), 1, 'medial axis of a narrow rectangle with an extra vertex is still a single line'; - ok unscale($res->[0]->length) >= (200-100 - (120-100)) - epsilon, 'medial axis has still a reasonable length'; - ok !(grep { abs($_ - scale 150) < scaled_epsilon } map $_->[Y], map @$_, @$res2), "extra vertices don't influence medial axis"; -} - -{ - my $expolygon = Slic3r::ExPolygon->new( - Slic3r::Polygon->new([1185881,829367],[1421988,1578184],[1722442,2303558],[2084981,2999998],[2506843,3662186],[2984809,4285086],[3515250,4863959],[4094122,5394400],[4717018,5872368],[5379210,6294226],[6075653,6656769],[6801033,6957229],[7549842,7193328],[8316383,7363266],[9094809,7465751],[9879211,7500000],[10663611,7465750],[11442038,7363265],[12208580,7193327],[12957389,6957228],[13682769,6656768],[14379209,6294227],[15041405,5872366],[15664297,5394401],[16243171,4863960],[16758641,4301424],[17251579,3662185],[17673439,3000000],[18035980,2303556],[18336441,1578177],[18572539,829368],[18750748,0],[19758422,0],[19727293,236479],[19538467,1088188],[19276136,1920196],[18942292,2726179],[18539460,3499999],[18070731,4235755],[17539650,4927877],[16950279,5571067],[16307090,6160437],[15614974,6691519],[14879209,7160248],[14105392,7563079],[13299407,7896927],[12467399,8159255],[11615691,8348082],[10750769,8461952],[9879211,8500000],[9007652,8461952],[8142729,8348082],[7291022,8159255],[6459015,7896927],[5653029,7563079],[4879210,7160247],[4143447,6691519],[3451331,6160437],[2808141,5571066],[2218773,4927878],[1687689,4235755],[1218962,3499999],[827499,2748020],[482284,1920196],[219954,1088186],[31126,236479],[0,0],[1005754,0]), - ); - my $res = $expolygon->medial_axis(scale 1.324888, scale 0.25); - is scalar(@$res), 1, 'medial axis of a semicircumference is a single line'; - - # check whether turns are all CCW or all CW - my @lines = @{$res->[0]->lines}; - my @angles = map { $lines[$_-1]->ccw($lines[$_]->b) } 1..$#lines; - ok !!(none { $_ < 0 } @angles) || (none { $_ > 0 } @angles), - 'all medial axis segments of a semicircumference have the same orientation'; -} - -{ - my $expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new_scale( - [100, 100], - [120, 100], - [112, 200], - [108, 200], - )); - my $res = $expolygon->medial_axis(scale 20, scale 0.5); - is scalar(@$res), 1, 'medial axis of a narrow trapezoid is a single line'; - ok unscale($res->[0]->length) >= (200-100 - (120-100)) - epsilon, 'medial axis has reasonable length'; -} - -{ - my $expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new_scale( - [100, 100], - [120, 100], - [120, 180], - [200, 180], - [200, 200], - [100, 200], - )); - my $res = $expolygon->medial_axis(scale 20, scale 0.5); - is scalar(@$res), 1, 'medial axis of a L shape is a single polyline'; - my $len = unscale($res->[0]->length) + 20; # 20 is the thickness of the expolygon, which is subtracted from the ends - ok $len > 80*2 && $len < 100*2, 'medial axis has reasonable length'; -} - -{ - my $expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new( - [-203064906,-51459966],[-219312231,-51459966],[-219335477,-51459962],[-219376095,-51459962],[-219412047,-51459966], - [-219572094,-51459966],[-219624814,-51459962],[-219642183,-51459962],[-219656665,-51459966],[-220815482,-51459966], - [-220815482,-37738966],[-221117540,-37738966],[-221117540,-51762024],[-203064906,-51762024], - )); - my $polylines = $expolygon->medial_axis(819998, 102499.75); - - my $perimeter = $expolygon->contour->split_at_first_point->length; - ok sum(map $_->length, @$polylines) > $perimeter/2/4*3, 'medial axis has a reasonable length'; -} - -{ - my $expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new_scale( - [50, 100], - [1000, 102], - [50, 104], - )); - my $res = $expolygon->medial_axis(scale 4, scale 0.5); - is scalar(@$res), 1, 'medial axis of a narrow triangle is a single line'; - ok unscale($res->[0]->length) >= (200-100 - (120-100)) - epsilon, 'medial axis has reasonable length'; -} - -{ - # GH #2474 - my $expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new( - [91294454,31032190],[11294481,31032190],[11294481,29967810],[44969182,29967810],[89909960,29967808],[91294454,29967808] - )); - my $polylines = $expolygon->medial_axis(1871238, 500000); - is scalar(@$polylines), 1, 'medial axis is a single polyline'; - my $polyline = $polylines->[0]; - - my $expected_y = $expolygon->bounding_box->center->y; #;; - ok abs(sum(map $_->y, @$polyline) / @$polyline - $expected_y) < scaled_epsilon, #,, - 'medial axis is horizontal and is centered'; - - # order polyline from left to right - $polyline->reverse if $polyline->first_point->x > $polyline->last_point->x; - - my $polyline_bb = $polyline->bounding_box; - is $polyline->first_point->x, $polyline_bb->x_min, 'expected x_min'; - is $polyline->last_point->x, $polyline_bb->x_max, 'expected x_max'; - - is_deeply [ map $_->x, @$polyline ], [ sort map $_->x, @$polyline ], - 'medial axis is not self-overlapping'; -} - -__END__ diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index 9e039c913b..4e8821287f 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -3,11 +3,14 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests.cpp test_avoid_crossing_perimeters.cpp test_bridges.cpp + test_cooling.cpp + test_custom_gcode.cpp test_data.cpp test_data.hpp test_extrusion_entity.cpp test_fill.cpp test_flow.cpp + test_gaps.cpp test_gcode.cpp test_gcodefindreplace.cpp test_gcodewriter.cpp @@ -19,6 +22,7 @@ add_executable(${_TEST_NAME}_tests test_printobject.cpp test_skirt_brim.cpp test_support_material.cpp + test_thin_walls.cpp test_trianglemesh.cpp ) target_link_libraries(${_TEST_NAME}_tests test_common libslic3r) diff --git a/tests/fff_print/test_cooling.cpp b/tests/fff_print/test_cooling.cpp new file mode 100644 index 0000000000..f743783b11 --- /dev/null +++ b/tests/fff_print/test_cooling.cpp @@ -0,0 +1,274 @@ +#include + +#include +#include + +#include "test_data.hpp" // get access to init_print, etc + +#include "libslic3r/Config.hpp" +#include "libslic3r/GCode.hpp" +#include "libslic3r/GCodeReader.hpp" +#include "libslic3r/GCode/CoolingBuffer.hpp" +#include "libslic3r/libslic3r.h" + +using namespace Slic3r; + +std::unique_ptr make_cooling_buffer( + GCode &gcode, + const DynamicPrintConfig &config = DynamicPrintConfig{}, + const std::vector &extruder_ids = { 0 }) +{ + PrintConfig print_config; + print_config.apply(config, true); // ignore_nonexistent + gcode.apply_print_config(print_config); + gcode.set_layer_count(10); + gcode.writer().set_extruders(extruder_ids); + gcode.writer().set_extruder(0); + return std::make_unique(gcode); +} + +SCENARIO("Cooling unit tests", "[Cooling]") { + const std::string gcode1 = "G1 X100 E1 F3000\n"; + // 2 sec + const double print_time1 = 100. / (3000. / 60.); + const std::string gcode2 = gcode1 + "G1 X0 E1 F3000\n"; + // 4 sec + const double print_time2 = 2. * print_time1; + + auto config = DynamicPrintConfig::full_print_config_with({ + // Default cooling settings. + { "bridge_fan_speed", "100" }, + { "cooling", "1" }, + { "fan_always_on", "0" }, + { "fan_below_layer_time", "60" }, + { "max_fan_speed", "100" }, + { "min_print_speed", "10" }, + { "slowdown_below_layer_time", "5" }, + // Default print speeds. + { "bridge_speed", 60 }, + { "external_perimeter_speed", "50%" }, + { "first_layer_speed", 30 }, + { "gap_fill_speed", 20 }, + { "infill_speed", 80 }, + { "perimeter_speed", 60 }, + { "small_perimeter_speed", 15 }, + { "solid_infill_speed", 20 }, + { "top_solid_infill_speed", 15 }, + { "max_print_speed", 80 }, + // Override for tests. + { "disable_fan_first_layers", "0" } + }); + + WHEN("G-code block 3") { + THEN("speed is not altered when elapsed time is greater than slowdown threshold") { + // Print time of gcode. + const double print_time = 100. / (3000. / 60.); + //FIXME slowdown_below_layer_time is rounded down significantly from 1.8s to 1s. + config.set_deserialize_strict({ { "slowdown_below_layer_time", { int(print_time * 0.999) } } }); + GCode gcodegen; + auto buffer = make_cooling_buffer(gcodegen, config); + std::string gcode = buffer->process_layer("G1 F3000;_EXTRUDE_SET_SPEED\nG1 X100 E1", 0, true); + bool speed_not_altered = gcode.find("F3000") != gcode.npos; + REQUIRE(speed_not_altered); + } + } + + WHEN("G-code block 4") { + const std::string gcode_src = + "G1 X50 F2500\n" + "G1 F3000;_EXTRUDE_SET_SPEED\n" + "G1 X100 E1\n" + ";_EXTRUDE_END\n" + "G1 E4 F400"; + // Print time of gcode. + const double print_time = 50. / (2500. / 60.) + 100. / (3000. / 60.) + 4. / (400. / 60.); + config.set_deserialize_strict({ { "slowdown_below_layer_time", { int(print_time * 1.001) } } }); + GCode gcodegen; + auto buffer = make_cooling_buffer(gcodegen, config); + std::string gcode = buffer->process_layer(gcode_src, 0, true); + THEN("speed is altered when elapsed time is lower than slowdown threshold") { + bool speed_is_altered = gcode.find("F3000") == gcode.npos; + REQUIRE(speed_is_altered); + } + THEN("speed is not altered for travel moves") { + bool speed_not_altered = gcode.find("F2500") != gcode.npos; + REQUIRE(speed_not_altered); + } + THEN("speed is not altered for extruder-only moves") { + bool speed_not_altered = gcode.find("F400") != gcode.npos; + REQUIRE(speed_not_altered); + } + } + + WHEN("G-code block 1") { + THEN("fan is not activated when elapsed time is greater than fan threshold") { + config.set_deserialize_strict({ + { "fan_below_layer_time" , int(print_time1 * 0.88) }, + { "slowdown_below_layer_time" , int(print_time1 * 0.99) } + }); + GCode gcodegen; + auto buffer = make_cooling_buffer(gcodegen, config); + std::string gcode = buffer->process_layer(gcode1, 0, true); + bool fan_not_activated = gcode.find("M106") == gcode.npos; + REQUIRE(fan_not_activated); + } + } + WHEN("G-code block 1 with two extruders") { + config.set_deserialize_strict({ + { "cooling", "1, 0" }, + { "fan_below_layer_time", { int(print_time2 + 1.), int(print_time2 + 1.) } }, + { "slowdown_below_layer_time", { int(print_time2 + 2.), int(print_time2 + 2.) } } + }); + GCode gcodegen; + auto buffer = make_cooling_buffer(gcodegen, config, { 0, 1 }); + std::string gcode = buffer->process_layer(gcode1 + "T1\nG1 X0 E1 F3000\n", 0, true); + THEN("fan is activated for the 1st tool") { + bool ok = gcode.find("M106") == 0; + REQUIRE(ok); + } + THEN("fan is disabled for the 2nd tool") { + bool ok = gcode.find("\nM107") > 0; + REQUIRE(ok); + } + } + WHEN("G-code block 2") { + THEN("slowdown is computed on all objects printing at the same Z") { + config.set_deserialize_strict({ { "slowdown_below_layer_time", int(print_time2 * 0.99) } }); + GCode gcodegen; + auto buffer = make_cooling_buffer(gcodegen, config); + std::string gcode = buffer->process_layer(gcode2, 0, true); + bool ok = gcode.find("F3000") != gcode.npos; + REQUIRE(ok); + } + THEN("fan is not activated on all objects printing at different Z") { + config.set_deserialize_strict({ + { "fan_below_layer_time", int(print_time2 * 0.65) }, + { "slowdown_below_layer_time", int(print_time2 * 0.7) } + }); + GCode gcodegen; + auto buffer = make_cooling_buffer(gcodegen, config); + // use an elapsed time which is < the threshold but greater than it when summed twice + std::string gcode = buffer->process_layer(gcode2, 0, true) + buffer->process_layer(gcode2, 1, true); + bool fan_not_activated = gcode.find("M106") == gcode.npos; + REQUIRE(fan_not_activated); + } + THEN("fan is activated on all objects printing at different Z") { + // use an elapsed time which is < the threshold even when summed twice + config.set_deserialize_strict({ + { "fan_below_layer_time", int(print_time2 + 1) }, + { "slowdown_below_layer_time", int(print_time2 + 1) } + }); + GCode gcodegen; + auto buffer = make_cooling_buffer(gcodegen, config); + // use an elapsed time which is < the threshold but greater than it when summed twice + std::string gcode = buffer->process_layer(gcode2, 0, true) + buffer->process_layer(gcode2, 1, true); + bool fan_activated = gcode.find("M106") != gcode.npos; + REQUIRE(fan_activated); + } + } +} + +SCENARIO("Cooling integration tests", "[Cooling]") { + GIVEN("overhang") { + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "cooling", { 1 } }, + { "bridge_fan_speed", { 100 } }, + { "fan_below_layer_time", { 0 } }, + { "slowdown_below_layer_time", { 0 } }, + { "bridge_speed", 99 }, + // internal bridges use solid_infil speed + { "bottom_solid_layers", 1 }, + // internal bridges use solid_infil speed + }); + + GCodeReader parser; + int fan = 0; + int fan_with_incorrect_speeds = 0; + int fan_with_incorrect_print_speeds = 0; + int bridge_with_no_fan = 0; + const double bridge_speed = config.opt_float("bridge_speed") * 60; + parser.parse_buffer( + Slic3r::Test::slice({ Slic3r::Test::TestMesh::overhang }, config), + [&fan, &fan_with_incorrect_speeds, &fan_with_incorrect_print_speeds, &bridge_with_no_fan, bridge_speed] + (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) + { + if (line.cmd_is("M106")) { + line.has_value('S', fan); + if (fan != 255) + ++ fan_with_incorrect_speeds; + } else if (line.cmd_is("M107")) { + fan = 0; + } else if (line.extruding(self) && line.dist_XY(self) > 0) { + if (is_approx(line.new_F(self), bridge_speed)) { + if (fan != 255) + ++ bridge_with_no_fan; + } else { + if (fan != 0) + ++ fan_with_incorrect_print_speeds; + } + } + }); + THEN("bridge fan speed is applied correctly") { + REQUIRE(fan_with_incorrect_speeds == 0); + } + THEN("bridge fan is only turned on for bridges") { + REQUIRE(fan_with_incorrect_print_speeds == 0); + } + THEN("bridge fan is turned on for all bridges") { + REQUIRE(bridge_with_no_fan == 0); + } + } + GIVEN("20mm cube") { + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "cooling", { 1 } }, + { "fan_below_layer_time", { 0 } }, + { "slowdown_below_layer_time", { 10 } }, + { "min_print_speed", { 0 } }, + { "start_gcode", "" }, + { "first_layer_speed", "100%" }, + { "external_perimeter_speed", 99 } + }); + GCodeReader parser; + const double external_perimeter_speed = config.opt("external_perimeter_speed")->value * 60; + std::vector layer_times; + // z => 1 + std::map layer_external; + parser.parse_buffer( + Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config), + [&layer_times, &layer_external, external_perimeter_speed] + (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) + { + if (line.cmd_is("G1")) { + if (line.dist_Z(self) != 0) { + layer_times.emplace_back(0.); + layer_external[scaled(line.new_Z(self))] = 0; + } + double l = line.dist_XY(self); + if (l == 0) + l = line.dist_E(self); + if (l == 0) + l = line.dist_Z(self); + if (l > 0.) { + if (layer_times.empty()) + layer_times.emplace_back(0.); + layer_times.back() += 60. * std::abs(l) / line.new_F(self); + } + if (line.has('F') && line.f() == external_perimeter_speed) + ++ layer_external[scaled(self.z())]; + } + }); + THEN("slowdown_below_layer_time is honored") { + // Account for some inaccuracies. + const double slowdown_below_layer_time = config.opt("slowdown_below_layer_time")->values.front() - 0.2; + size_t minimum_time_honored = std::count_if(layer_times.begin(), layer_times.end(), + [slowdown_below_layer_time](double t){ return t > slowdown_below_layer_time; }); + REQUIRE(minimum_time_honored == layer_times.size()); + } + THEN("slowdown_below_layer_time does not alter external perimeters") { + // Broken by Vojtech + // check that all layers have at least one unaltered external perimeter speed + // my $external = all { $_ > 0 } values %layer_external; + // ok $external, ''; + } + } +} diff --git a/tests/fff_print/test_custom_gcode.cpp b/tests/fff_print/test_custom_gcode.cpp new file mode 100644 index 0000000000..0368b9604f --- /dev/null +++ b/tests/fff_print/test_custom_gcode.cpp @@ -0,0 +1,220 @@ +#include + +#include +#include + +#include "libslic3r/Config.hpp" +#include "libslic3r/Print.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/libslic3r.h" + +#include "test_data.hpp" + +using namespace Slic3r; + +#if 0 +SCENARIO("Output file format", "[CustomGCode]") +{ + WHEN("output_file_format set") { + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "output_filename_format", "ts_[travel_speed]_lh_[layer_height].gcode" }, + { "start_gcode", "TRAVEL:[travel_speed] HEIGHT:[layer_height]\n" } + }); + + Print print; + Model model; + Test::init_print({ Test::TestMesh::cube_2x20x10 }, print, model, config); + + std::string output_file = print.output_filepath(); + THEN("print config options are replaced in output filename") { + output_file.find(std::string("ts_") + ) + } + my ($t, $h) = map $config->$_, qw(travel_speed layer_height); + ok $output_file =~ /ts_${t}_/, ''; + ok $output_file =~ /lh_$h\./, 'region config options are replaced in output filename'; + + std::string gcode = print.gcode(print); + THEN("print config options are replaced in custom G-code") { + ok $gcode =~ /TRAVEL:$t/, ''; + } + THEN("region config options are replaced in custom G-code") { + ok $gcode =~ /HEIGHT:$h/, ''; + } + } +} + +SCENARIO("Custom G-code", "[CustomGCode]") +{ + WHEN("start_gcode and layer_gcode set") { + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "start_gcode", "_MY_CUSTOM_START_GCODE_" }, // to avoid dealing with the nozzle lift in start G-code + { "layer_gcode", "_MY_CUSTOM_LAYER_GCODE_" } + }); + GCodeReader parser; + bool last_move_was_z_change = false; + int num_layer_changes_not_applied = 0; + parser.parse_buffer(Slic3r::Test::slice({ Test::TestMesh::cube_2x20x10 }, config), + [&last_move_was_z_change, &num_layer_changes_not_applied](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) + { + if (line.extruding(self)) { + if (! was_extruding) + seam_points.emplace_back(self.xy_scaled()); + was_extruding = true; + } else if (! line.cmd_is("M73")) { + // skips remaining time lines (M73) + was_extruding = false; + } + if (last_move_was_z_change != line.cmd_is("_MY_CUSTOM_LAYER_GCODE_")) + ++ num_layer_changes_not_applied; + last_move_was_z_change = line.dist_Z(self) > 0; + }); + THEN("custom layer G-code is applied after Z move and before other moves"); + }; + +{ + my $config = Slic3r::Config->new; + $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]); + $config->set('extruder', 2); + $config->set('first_layer_temperature', [200,205]); + + { + my $print = Slic3r::Test::init_print('20mm_cube', config => $config); + my $gcode = Slic3r::Test::gcode($print); + ok $gcode =~ /M104 S205 T1/, 'temperature set correctly for non-zero yet single extruder'; + ok $gcode !~ /M104 S\d+ T0/, 'unused extruder correctly ignored'; + } + + $config->set('infill_extruder', 1); + { + my $print = Slic3r::Test::init_print('20mm_cube', config => $config); + my $gcode = Slic3r::Test::gcode($print); + ok $gcode =~ /M104 S200 T0/, 'temperature set correctly for first extruder'; + ok $gcode =~ /M104 S205 T1/, 'temperature set correctly for second extruder'; + } + + my @start_gcode = (qq! +;__temp0:[first_layer_temperature_0]__ +;__temp1:[first_layer_temperature_1]__ +;__temp2:[first_layer_temperature_2]__ + !, qq! +;__temp0:{first_layer_temperature[0]}__ +;__temp1:{first_layer_temperature[1]}__ +;__temp2:{first_layer_temperature[2]}__ + !); + my @syntax_description = (' (legacy syntax)', ' (new syntax)'); + for my $i (0, 1) { + $config->set('start_gcode', $start_gcode[$i]); + { + my $print = Slic3r::Test::init_print('20mm_cube', config => $config); + my $gcode = Slic3r::Test::gcode($print); + # we use the [infill_extruder] placeholder to make sure this test doesn't + # catch a false positive caused by the unparsed start G-code option itself + # being embedded in the G-code + ok $gcode =~ /temp0:200/, 'temperature placeholder for first extruder correctly populated' . $syntax_description[$i]; + ok $gcode =~ /temp1:205/, 'temperature placeholder for second extruder correctly populated' . $syntax_description[$i]; + ok $gcode =~ /temp2:200/, 'temperature placeholder for unused extruder populated with first value' . $syntax_description[$i]; + } + } + + $config->set('start_gcode', qq! +;substitution:{if infill_extruder==1}extruder1 + {elsif infill_extruder==2}extruder2 + {else}extruder3{endif} + !); + { + my $print = Slic3r::Test::init_print('20mm_cube', config => $config); + my $gcode = Slic3r::Test::gcode($print); + ok $gcode =~ /substitution:extruder1/, 'if / else / endif - first block returned'; + } +} + +{ + my $config = Slic3r::Config::new_from_defaults; + $config->set('before_layer_gcode', ';BEFORE [layer_num]'); + $config->set('layer_gcode', ';CHANGE [layer_num]'); + $config->set('support_material', 1); + $config->set('layer_height', 0.2); + my $print = Slic3r::Test::init_print('overhang', config => $config); + my $gcode = Slic3r::Test::gcode($print); + + my @before = (); + my @change = (); + foreach my $line (split /\R+/, $gcode) { + if ($line =~ /;BEFORE (\d+)/) { + push @before, $1; + } elsif ($line =~ /;CHANGE (\d+)/) { + push @change, $1; + fail 'inconsistent layer_num before and after layer change' + if $1 != $before[-1]; + } + } + is_deeply \@before, \@change, 'layer_num is consistent before and after layer changes'; + ok !defined(first { $change[$_] != $change[$_-1]+1 } 1..$#change), + 'layer_num grows continously'; # i.e. no duplicates or regressions +} + +{ + my $config = Slic3r::Config->new; + $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6,0.6]); + $config->set('start_gcode', qq! +;substitution:{if infill_extruder==1}if block + {elsif infill_extruder==2}elsif block 1 + {elsif infill_extruder==3}elsif block 2 + {elsif infill_extruder==4}elsif block 3 + {else}endif block{endif} + !); + my @returned = ('', 'if block', 'elsif block 1', 'elsif block 2', 'elsif block 3', 'endif block'); + for my $i (1,2,3,4,5) { + $config->set('infill_extruder', $i); + my $print = Slic3r::Test::init_print('20mm_cube', config => $config); + my $gcode = Slic3r::Test::gcode($print); + my $found_other = 0; + for my $j (1,2,3,4,5) { + next if $i == $j; + $found_other = 1 if $gcode =~ /substitution:$returned[$j]/; + } + ok $gcode =~ /substitution:$returned[$i]/, 'if / else / endif - ' . $returned[$i] . ' returned'; + ok !$found_other, 'if / else / endif - only ' . $returned[$i] . ' returned'; + } +} + +{ + my $config = Slic3r::Config->new; + $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]); + $config->set('start_gcode', + ';substitution:{if infill_extruder==1}{if perimeter_extruder==1}block11{else}block12{endif}' . + '{elsif infill_extruder==2}{if perimeter_extruder==1}block21{else}block22{endif}' . + '{else}{if perimeter_extruder==1}block31{else}block32{endif}{endif}:end'); + for my $i (1,2,3) { + $config->set('infill_extruder', $i); + for my $j (1,2) { + $config->set('perimeter_extruder', $j); + my $print = Slic3r::Test::init_print('20mm_cube', config => $config); + my $gcode = Slic3r::Test::gcode($print); + ok $gcode =~ /substitution:block$i$j:end/, "two level if / else / endif - block$i$j returned"; + } + } +} + +{ + my $config = Slic3r::Config->new; + $config->set('start_gcode', + ';substitution:{if notes=="MK2"}MK2{elsif notes=="MK3"}MK3{else}MK1{endif}:end'); + for my $printer_name ("MK2", "MK3", "MK1") { + $config->set('notes', $printer_name); + my $print = Slic3r::Test::init_print('20mm_cube', config => $config); + my $gcode = Slic3r::Test::gcode($print); + ok $gcode =~ /substitution:$printer_name:end/, "printer name $printer_name matched"; + } +} + +{ + my $config = Slic3r::Config::new_from_defaults; + $config->set('complete_objects', 1); + $config->set('between_objects_gcode', '_MY_CUSTOM_GCODE_'); + my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 3); + my $gcode = Slic3r::Test::gcode($print); + is scalar(() = $gcode =~ /^_MY_CUSTOM_GCODE_/gm), 2, 'between_objects_gcode is applied correctly'; +} + +#endif \ No newline at end of file diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp index 6be45d2380..a52583cfca 100644 --- a/tests/fff_print/test_data.cpp +++ b/tests/fff_print/test_data.cpp @@ -26,6 +26,7 @@ const std::unordered_map mesh_names { std::pair(TestMesh::V, "V"), std::pair(TestMesh::_40x10, "40x10"), std::pair(TestMesh::cube_20x20x20, "cube_20x20x20"), + std::pair(TestMesh::cube_2x20x10, "cube_2x20x10"), std::pair(TestMesh::sphere_50mm, "sphere_50mm"), std::pair(TestMesh::bridge, "bridge"), std::pair(TestMesh::bridge_with_hole, "bridge_with_hole"), @@ -49,6 +50,9 @@ TriangleMesh mesh(TestMesh m) case TestMesh::cube_20x20x20: mesh = Slic3r::make_cube(20, 20, 20); break; + case TestMesh::cube_2x20x10: + mesh = Slic3r::make_cube(2, 20, 10); + break; case TestMesh::sphere_50mm: mesh = Slic3r::make_sphere(50, PI / 243.0); break; diff --git a/tests/fff_print/test_data.hpp b/tests/fff_print/test_data.hpp index 573ae58a5c..b699e5e4e6 100644 --- a/tests/fff_print/test_data.hpp +++ b/tests/fff_print/test_data.hpp @@ -21,6 +21,7 @@ enum class TestMesh { V, _40x10, cube_20x20x20, + cube_2x20x10, sphere_50mm, bridge, bridge_with_hole, diff --git a/tests/fff_print/test_fill.cpp b/tests/fff_print/test_fill.cpp index c3af6e8fc5..0ccb27d9ab 100644 --- a/tests/fff_print/test_fill.cpp +++ b/tests/fff_print/test_fill.cpp @@ -197,7 +197,7 @@ TEST_CASE("Fill: Pattern Path Length", "[Fill]") { SCENARIO("Infill does not exceed perimeters", "[Fill]") { auto test = [](const std::string_view pattern) { - DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config_with({ + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ { "nozzle_diameter", "0.4, 0.4, 0.4, 0.4" }, { "fill_pattern", pattern }, { "top_fill_pattern", pattern }, diff --git a/tests/fff_print/test_flow.cpp b/tests/fff_print/test_flow.cpp index 81f748e19a..b24b59cc61 100644 --- a/tests/fff_print/test_flow.cpp +++ b/tests/fff_print/test_flow.cpp @@ -5,8 +5,6 @@ #include "test_data.hpp" // get access to init_print, etc -#include "libslic3r/Config.hpp" -#include "libslic3r/Model.hpp" #include "libslic3r/Config.hpp" #include "libslic3r/GCodeReader.hpp" #include "libslic3r/Flow.hpp" @@ -16,61 +14,118 @@ using namespace Slic3r::Test; using namespace Slic3r; SCENARIO("Extrusion width specifics", "[Flow]") { - GIVEN("A config with a skirt, brim, some fill density, 3 perimeters, and 1 bottom solid layer and a 20mm cube mesh") { - // this is a sharedptr - DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); - config.set_deserialize_strict({ - { "brim_width", 2 }, - { "skirts", 1 }, - { "perimeters", 3 }, - { "fill_density", "40%" }, - { "first_layer_height", 0.3 } - }); - WHEN("first layer width set to 2mm") { - Slic3r::Model model; - config.set("first_layer_extrusion_width", 2); - Slic3r::Print print; - Slic3r::Test::init_print({TestMesh::cube_20x20x20}, print, model, config); - - std::vector E_per_mm_bottom; - std::string gcode = Test::gcode(print); - Slic3r::GCodeReader parser; - const double layer_height = config.opt_float("layer_height"); - parser.parse_buffer(gcode, [&E_per_mm_bottom, layer_height] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) - { - if (self.z() == Approx(layer_height).margin(0.01)) { // only consider first layer - if (line.extruding(self) && line.dist_XY(self) > 0) { - E_per_mm_bottom.emplace_back(line.dist_E(self) / line.dist_XY(self)); - } - } - }); - THEN(" First layer width applies to everything on first layer.") { - bool pass = false; - double avg_E = std::accumulate(E_per_mm_bottom.cbegin(), E_per_mm_bottom.cend(), 0.0) / static_cast(E_per_mm_bottom.size()); - - pass = (std::count_if(E_per_mm_bottom.cbegin(), E_per_mm_bottom.cend(), [avg_E] (const double& v) { return v == Approx(avg_E); }) == 0); - REQUIRE(pass == true); - REQUIRE(E_per_mm_bottom.size() > 0); // make sure it actually passed because of extrusion - } - THEN(" First layer width does not apply to upper layer.") { + auto test = [](const DynamicPrintConfig &config) { + Slic3r::GCodeReader parser; + const double layer_height = config.opt_float("layer_height"); + std::vector E_per_mm_bottom; + parser.parse_buffer(Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config), + [&E_per_mm_bottom, layer_height] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line) + { + if (self.z() == Approx(layer_height).margin(0.01)) { // only consider first layer + if (line.extruding(self) && line.dist_XY(self) > 0) + E_per_mm_bottom.emplace_back(line.dist_E(self) / line.dist_XY(self)); } + }); + THEN("First layer width applies to everything on first layer.") { + REQUIRE(E_per_mm_bottom.size() > 0); + const double E_per_mm_avg = std::accumulate(E_per_mm_bottom.cbegin(), E_per_mm_bottom.cend(), 0.0) / static_cast(E_per_mm_bottom.size()); + bool pass = (std::count_if(E_per_mm_bottom.cbegin(), E_per_mm_bottom.cend(), [E_per_mm_avg] (const double& v) { return v == Approx(E_per_mm_avg); }) == 0); + REQUIRE(pass); + } + THEN("First layer width does not apply to upper layer.") { + } + }; + GIVEN("A config with a skirt, brim, some fill density, 3 perimeters, and 1 bottom solid layer") { + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "skirts", 1 }, + { "brim_width", 2 }, + { "perimeters", 3 }, + { "fill_density", "40%" }, + { "first_layer_height", 0.3 }, + { "first_layer_extrusion_width", "2" }, + }); + WHEN("Slicing a 20mm cube") { + test(config); + } + } + GIVEN("A config with more options and a 20mm cube ") { + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "skirts", 1 }, + { "brim_width", 2 }, + { "perimeters", 3 }, + { "fill_density", "40%" }, + { "layer_height", "0.35" }, + { "first_layer_height", "0.35" }, + { "bottom_solid_layers", 1 }, + { "first_layer_extrusion_width", "2" }, + { "filament_diameter", "3" }, + { "nozzle_diameter", "0.5" } + }); + WHEN("Slicing a 20mm cube") { + test(config); } } } -// needs gcode export + SCENARIO(" Bridge flow specifics.", "[Flow]") { + auto config = DynamicPrintConfig::full_print_config_with({ + { "bridge_speed", 99 }, + { "bridge_flow_ratio", 1 }, + // to prevent speeds from being altered + { "cooling", "0" }, + // to prevent speeds from being altered + { "first_layer_speed", "100%" } + }); + + auto test = [](const DynamicPrintConfig &config) { + GCodeReader parser; + const double bridge_speed = config.opt_float("bridge_speed") * 60.; + std::vector E_per_mm; + parser.parse_buffer(Slic3r::Test::slice({ Slic3r::Test::TestMesh::overhang }, config), + [&E_per_mm, bridge_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + if (line.extruding(self) && line.dist_XY(self) > 0) { + if (is_approx(line.new_F(self), bridge_speed)) + E_per_mm.emplace_back(line.dist_E(self) / line.dist_XY(self)); + } + }); + const double nozzle_dmr = config.opt("nozzle_diameter")->get_at(0); + const double filament_dmr = config.opt("filament_diameter")->get_at(0); + const double bridge_mm_per_mm = sqr(nozzle_dmr / filament_dmr) * config.opt_float("bridge_flow_ratio"); + size_t num_errors = std::count_if(E_per_mm.begin(), E_per_mm.end(), + [bridge_mm_per_mm](double v){ return std::abs(v - bridge_mm_per_mm) > 0.01; }); + return num_errors == 0; + }; + GIVEN("A default config with no cooling and a fixed bridge speed, flow ratio and an overhang mesh.") { - WHEN("bridge_flow_ratio is set to 1.0") { + WHEN("bridge_flow_ratio is set to 0.5 and extrusion width to default") { + config.set_deserialize_strict({ { "bridge_flow_ratio", 0.5}, { "extrusion_width", "0" } }); THEN("Output flow is as expected.") { + REQUIRE(test(config)); } } - WHEN("bridge_flow_ratio is set to 0.5") { + WHEN("bridge_flow_ratio is set to 2.0 and extrusion width to default") { + config.set_deserialize_strict({ { "bridge_flow_ratio", 2.0}, { "extrusion_width", "0" } }); THEN("Output flow is as expected.") { + REQUIRE(test(config)); } } - WHEN("bridge_flow_ratio is set to 2.0") { + WHEN("bridge_flow_ratio is set to 0.5 and extrusion_width to 0.4") { + config.set_deserialize_strict({ { "bridge_flow_ratio", 0.5}, { "extrusion_width", 0.4 } }); THEN("Output flow is as expected.") { + REQUIRE(test(config)); + } + } + WHEN("bridge_flow_ratio is set to 1.0 and extrusion_width to 0.4") { + config.set_deserialize_strict({ { "bridge_flow_ratio", 1.0}, { "extrusion_width", 0.4 } }); + THEN("Output flow is as expected.") { + REQUIRE(test(config)); + } + } + WHEN("bridge_flow_ratio is set to 2 and extrusion_width to 0.4") { + config.set_deserialize_strict({ { "bridge_flow_ratio", 2.}, { "extrusion_width", 0.4 } }); + THEN("Output flow is as expected.") { + REQUIRE(test(config)); } } } diff --git a/tests/fff_print/test_gaps.cpp b/tests/fff_print/test_gaps.cpp new file mode 100644 index 0000000000..a096087ce6 --- /dev/null +++ b/tests/fff_print/test_gaps.cpp @@ -0,0 +1,60 @@ +#include + +#include "libslic3r/GCodeReader.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/Layer.hpp" + +#include "test_data.hpp" // get access to init_print, etc + +using namespace Slic3r::Test; +using namespace Slic3r; + +SCENARIO("Gaps", "[Gaps]") { + GIVEN("Two hollow squares") { + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "skirts", 0 }, + { "perimeter_speed", 66 }, + { "external_perimeter_speed", 66 }, + { "small_perimeter_speed", 66 }, + { "gap_fill_speed", 99 }, + { "perimeters", 1 }, + // to prevent speeds from being altered + { "cooling", 0 }, + // to prevent speeds from being altered + { "first_layer_speed", "100%" }, + { "perimeter_extrusion_width", 0.35 }, + { "first_layer_extrusion_width", 0.35 } + }); + + GCodeReader parser; + const double perimeter_speed = config.opt_float("perimeter_speed") * 60; + const double gap_fill_speed = config.opt_float("gap_fill_speed") * 60; + std::string last; // perimeter or gap + Points perimeter_points; + int gap_fills_outside_last_perimeters = 0; + parser.parse_buffer( + Slic3r::Test::slice({ Slic3r::Test::TestMesh::two_hollow_squares }, config), + [&perimeter_points, &gap_fills_outside_last_perimeters, &last, perimeter_speed, gap_fill_speed] + (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) + { + if (line.extruding(self) && line.dist_XY(self) > 0) { + double f = line.new_F(self); + Point point = line.new_XY_scaled(self); + if (is_approx(f, perimeter_speed)) { + if (last == "gap") + perimeter_points.clear(); + perimeter_points.emplace_back(point); + last = "perimeter"; + } else if (is_approx(f, gap_fill_speed)) { + Polygon convex_hull = Geometry::convex_hull(perimeter_points); + if (! convex_hull.contains(point)) + ++ gap_fills_outside_last_perimeters; + last = "gap"; + } + } + }); + THEN("gap fills are printed before leaving islands") { + REQUIRE(gap_fills_outside_last_perimeters == 0); + } + } +} diff --git a/tests/fff_print/test_thin_walls.cpp b/tests/fff_print/test_thin_walls.cpp new file mode 100644 index 0000000000..cd80f3bd66 --- /dev/null +++ b/tests/fff_print/test_thin_walls.cpp @@ -0,0 +1,191 @@ +#include + +#include +#include + +#include "test_data.hpp" // get access to init_print, etc + +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/libslic3r.h" + +using namespace Slic3r; + +SCENARIO("Medial Axis", "[ThinWalls]") { + GIVEN("Square with hole") { + auto square = Polygon::new_scale({ {100, 100}, {200, 100}, {200, 200}, {100, 200} }); + auto hole_in_square = Polygon::new_scale({ {140, 140}, {140, 160}, {160, 160}, {160, 140} }); + ExPolygon expolygon{ square, hole_in_square }; + WHEN("Medial axis is extracted") { + Polylines res = expolygon.medial_axis(scaled(40.), scaled(0.5)); + THEN("medial axis of a square shape is a single path") { + REQUIRE(res.size() == 1); + } + THEN("polyline forms a closed loop") { + REQUIRE(res.front().first_point() == res.front().last_point()); + } + THEN("medial axis loop has reasonable length") { + REQUIRE(res.front().length() > hole_in_square.length()); + REQUIRE(res.front().length() < square.length()); + } + } + } + GIVEN("narrow rectangle") { + ExPolygon expolygon{ Polygon::new_scale({ {100, 100}, {120, 100}, {120, 200}, {100, 200} }) }; + WHEN("Medial axis is extracted") { + Polylines res = expolygon.medial_axis(scaled(20.), scaled(0.5)); + THEN("medial axis of a narrow rectangle is a single line") { + REQUIRE(res.size() == 1); + } + THEN("medial axis has reasonable length") { + REQUIRE(res.front().length() >= scaled(200.-100. - (120.-100.)) - SCALED_EPSILON); + } + } + } +#if 0 + //FIXME this test never worked + GIVEN("narrow rectangle with an extra vertex") { + ExPolygon expolygon{ Polygon::new_scale({ + {100, 100}, {120, 100}, {120, 200}, + {105, 200} /* extra point in the short side*/, + {100, 200} + })}; + WHEN("Medial axis is extracted") { + Polylines res = expolygon.medial_axis(scaled(1.), scaled(0.5)); + THEN("medial axis of a narrow rectangle with an extra vertex is still a single line") { + REQUIRE(res.size() == 1); + } + THEN("medial axis has still a reasonable length") { + REQUIRE(res.front().length() >= scaled(200.-100. - (120.-100.)) - SCALED_EPSILON); + } + THEN("extra vertices don't influence medial axis") { + size_t invalid = 0; + for (const Polyline &pl : res) + for (const Point &p : pl.points) + if (std::abs(p.y() - scaled(150.)) < SCALED_EPSILON) + ++ invalid; + REQUIRE(invalid == 0); + } + } + } +#endif + GIVEN("semicircumference") { + ExPolygon expolygon{{ + {1185881,829367},{1421988,1578184},{1722442,2303558},{2084981,2999998},{2506843,3662186},{2984809,4285086},{3515250,4863959},{4094122,5394400}, + {4717018,5872368},{5379210,6294226},{6075653,6656769},{6801033,6957229},{7549842,7193328},{8316383,7363266},{9094809,7465751},{9879211,7500000}, + {10663611,7465750},{11442038,7363265},{12208580,7193327},{12957389,6957228},{13682769,6656768},{14379209,6294227},{15041405,5872366}, + {15664297,5394401},{16243171,4863960},{16758641,4301424},{17251579,3662185},{17673439,3000000},{18035980,2303556},{18336441,1578177}, + {18572539,829368},{18750748,0},{19758422,0},{19727293,236479},{19538467,1088188},{19276136,1920196},{18942292,2726179},{18539460,3499999}, + {18070731,4235755},{17539650,4927877},{16950279,5571067},{16307090,6160437},{15614974,6691519},{14879209,7160248},{14105392,7563079}, + {13299407,7896927},{12467399,8159255},{11615691,8348082},{10750769,8461952},{9879211,8500000},{9007652,8461952},{8142729,8348082}, + {7291022,8159255},{6459015,7896927},{5653029,7563079},{4879210,7160247},{4143447,6691519},{3451331,6160437},{2808141,5571066},{2218773,4927878}, + {1687689,4235755},{1218962,3499999},{827499,2748020},{482284,1920196},{219954,1088186},{31126,236479},{0,0},{1005754,0} + }}; + WHEN("Medial axis is extracted") { + Polylines res = expolygon.medial_axis(scaled(1.324888), scaled(0.25)); + THEN("medial axis of a semicircumference is a single line") { + REQUIRE(res.size() == 1); + } + THEN("all medial axis segments of a semicircumference have the same orientation") { + int nccw = 0; + int ncw = 0; + for (const Polyline &pl : res) + for (size_t i = 1; i + 1 < pl.size(); ++ i) { + double cross = cross2((pl.points[i] - pl.points[i - 1]).cast(), (pl.points[i + 1] - pl.points[i]).cast()); + if (cross > 0.) + ++ nccw; + else if (cross < 0.) + ++ ncw; + } + REQUIRE((ncw == 0 || nccw == 0)); + } + } + } + GIVEN("narrow trapezoid") { + ExPolygon expolygon{ Polygon::new_scale({ {100, 100}, {120, 100}, {112, 200}, {108, 200} }) }; + WHEN("Medial axis is extracted") { + Polylines res = expolygon.medial_axis(scaled(20.), scaled(0.5)); + THEN("medial axis of a narrow trapezoid is a single line") { + REQUIRE(res.size() == 1); + } + THEN("medial axis has reasonable length") { + REQUIRE(res.front().length() >= scaled(200.-100. - (120.-100.)) - SCALED_EPSILON); + } + } + } + GIVEN("L shape") { + ExPolygon expolygon{ Polygon::new_scale({ {100, 100}, {120, 100}, {120, 180}, {200, 180}, {200, 200}, {100, 200}, }) }; + WHEN("Medial axis is extracted") { + Polylines res = expolygon.medial_axis(scaled(20.), scaled(0.5)); + THEN("medial axis of an L shape is a single line") { + REQUIRE(res.size() == 1); + } + THEN("medial axis has reasonable length") { + // 20 is the thickness of the expolygon, which is subtracted from the ends + auto len = unscale(res.front().length()) + 20; + REQUIRE(len > 80. * 2.); + REQUIRE(len < 100. * 2.); + } + } + } + GIVEN("whatever shape") { + ExPolygon expolygon{{ + {-203064906,-51459966},{-219312231,-51459966},{-219335477,-51459962},{-219376095,-51459962},{-219412047,-51459966}, + {-219572094,-51459966},{-219624814,-51459962},{-219642183,-51459962},{-219656665,-51459966},{-220815482,-51459966}, + {-220815482,-37738966},{-221117540,-37738966},{-221117540,-51762024},{-203064906,-51762024}, + }}; + WHEN("Medial axis is extracted") { + Polylines res = expolygon.medial_axis(819998., 102499.75); + THEN("medial axis is a single line") { + REQUIRE(res.size() == 1); + } + THEN("medial axis has reasonable length") { + double perimeter = expolygon.contour.split_at_first_point().length(); + REQUIRE(total_length(res) > perimeter / 2. / 4. * 3.); + } + } + } + GIVEN("narrow triangle") { + ExPolygon expolygon{ Polygon::new_scale({ {50, 100}, {1000, 102}, {50, 104} }) }; + WHEN("Medial axis is extracted") { + Polylines res = expolygon.medial_axis(scaled(4.), scaled(0.5)); + THEN("medial axis of a narrow triangle is a single line") { + REQUIRE(res.size() == 1); + } + THEN("medial axis has reasonable length") { + REQUIRE(res.front().length() >= scaled(200.-100. - (120.-100.)) - SCALED_EPSILON); + } + } + } + GIVEN("GH #2474") { + ExPolygon expolygon{{ {91294454,31032190},{11294481,31032190},{11294481,29967810},{44969182,29967810},{89909960,29967808},{91294454,29967808} }}; + WHEN("Medial axis is extracted") { + Polylines res = expolygon.medial_axis(1871238, 500000); + THEN("medial axis is a single line") { + REQUIRE(res.size() == 1); + } + Polyline &polyline = res.front(); + THEN("medial axis is horizontal and is centered") { + double expected_y = expolygon.contour.bounding_box().center().y(); + double center_y = 0.; + for (auto &p : polyline.points) + center_y += double(p.y()); + REQUIRE(std::abs(center_y / polyline.size() - expected_y) < SCALED_EPSILON); + } + // order polyline from left to right + if (polyline.first_point().x() > polyline.last_point().x()) + polyline.reverse(); + BoundingBox polyline_bb = polyline.bounding_box(); + THEN("expected x_min") { + REQUIRE(polyline.first_point().x() == polyline_bb.min.x()); + } + THEN("expected x_max") { + REQUIRE(polyline.last_point().x() == polyline_bb.max.x()); + } + THEN("medial axis is monotonous in x (not self intersecting)") { + Polyline sorted { polyline }; + std::sort(sorted.begin(), sorted.end()); + REQUIRE(polyline == sorted); + } + } + } +} diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index 2482451829..a3984b34b1 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(${_TEST_NAME}_tests test_geometry.cpp test_placeholder_parser.cpp test_polygon.cpp + test_polyline.cpp test_mutable_polygon.cpp test_mutable_priority_queue.cpp test_stl.cpp diff --git a/tests/libslic3r/test_config.cpp b/tests/libslic3r/test_config.cpp index 025459d689..50e61b3b04 100644 --- a/tests/libslic3r/test_config.cpp +++ b/tests/libslic3r/test_config.cpp @@ -1,5 +1,6 @@ #include +#include "libslic3r/Config.hpp" #include "libslic3r/PrintConfig.hpp" #include "libslic3r/LocalesUtils.hpp" @@ -13,20 +14,20 @@ using namespace Slic3r; SCENARIO("Generic config validation performs as expected.", "[Config]") { GIVEN("A config generated from default options") { Slic3r::DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); - WHEN( "perimeter_extrusion_width is set to 250%, a valid value") { + WHEN("perimeter_extrusion_width is set to 250%, a valid value") { config.set_deserialize_strict("perimeter_extrusion_width", "250%"); THEN( "The config is read as valid.") { REQUIRE(config.validate().empty()); } } - WHEN( "perimeter_extrusion_width is set to -10, an invalid value") { + WHEN("perimeter_extrusion_width is set to -10, an invalid value") { config.set("perimeter_extrusion_width", -10); THEN( "Validate returns error") { REQUIRE(! config.validate().empty()); } } - WHEN( "perimeters is set to -10, an invalid value") { + WHEN("perimeters is set to -10, an invalid value") { config.set("perimeters", -10); THEN( "Validate returns error") { REQUIRE(! config.validate().empty()); @@ -36,8 +37,7 @@ SCENARIO("Generic config validation performs as expected.", "[Config]") { } SCENARIO("Config accessor functions perform as expected.", "[Config]") { - GIVEN("A config generated from default options") { - Slic3r::DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + auto test = [](ConfigBase &config) { WHEN("A boolean option is set to a boolean value") { REQUIRE_NOTHROW(config.set("gcode_comments", true)); THEN("The underlying value is set correctly.") { @@ -70,8 +70,8 @@ SCENARIO("Config accessor functions perform as expected.", "[Config]") { } } #if 0 - //FIXME better design accessors for vector elements. - WHEN("An integer-based option is set through the integer interface") { + //FIXME better design accessors for vector elements. + WHEN("An integer-based option is set through the integer interface") { config.set("bed_temperature", 100); THEN("The underlying value is set correctly.") { REQUIRE(config.opt("bed_temperature")->get_at(0) == 100); @@ -193,6 +193,14 @@ SCENARIO("Config accessor functions perform as expected.", "[Config]") { REQUIRE(config.opt_float("layer_height") == 0.5); } } + }; + GIVEN("DynamicPrintConfig generated from default options") { + auto config = Slic3r::DynamicPrintConfig::full_print_config(); + test(config); + } + GIVEN("FullPrintConfig generated from default options") { + Slic3r::FullPrintConfig config; + test(config); } } diff --git a/tests/libslic3r/test_geometry.cpp b/tests/libslic3r/test_geometry.cpp index 34e625e6db..41ef69aaaf 100644 --- a/tests/libslic3r/test_geometry.cpp +++ b/tests/libslic3r/test_geometry.cpp @@ -162,14 +162,34 @@ TEST_CASE("Splitting a Polygon generates a polyline correctly", "[Geometry]"){ } -TEST_CASE("Bounding boxes are scaled appropriately", "[Geometry]"){ - BoundingBox bb(std::vector({Point(0, 1), Point(10, 2), Point(20, 2)})); - bb.scale(2); - REQUIRE(bb.min == Point(0,2)); - REQUIRE(bb.max == Point(40,4)); +SCENARIO("BoundingBox", "[Geometry]") { + WHEN("Bounding boxes are scaled") { + BoundingBox bb(std::vector({Point(0, 1), Point(10, 2), Point(20, 2)})); + bb.scale(2); + REQUIRE(bb.min == Point(0,2)); + REQUIRE(bb.max == Point(40,4)); + } + WHEN("BoundingBox constructed from points") { + BoundingBox bb(Points{ {100,200}, {100, 200}, {500, -600} }); + THEN("minimum is correct") { + REQUIRE(bb.min == Point{100,-600}); + } + THEN("maximum is correct") { + REQUIRE(bb.max == Point{500,200}); + } + } + WHEN("BoundingBox constructed from a single point") { + BoundingBox bb; + bb.merge({10, 10}); + THEN("minimum equals to the only defined point") { + REQUIRE(bb.min == Point{10,10}); + } + THEN("maximum equals to the only defined point") { + REQUIRE(bb.max == Point{10,10}); + } + } } - TEST_CASE("Offseting a line generates a polygon correctly", "[Geometry]"){ Slic3r::Polyline tmp = { Point(10,10), Point(20,10) }; Slic3r::Polygon area = offset(tmp,5).at(0); diff --git a/tests/libslic3r/test_polygon.cpp b/tests/libslic3r/test_polygon.cpp index f2c78cacec..7774b44a6a 100644 --- a/tests/libslic3r/test_polygon.cpp +++ b/tests/libslic3r/test_polygon.cpp @@ -148,3 +148,65 @@ SCENARIO("Remove collinear points from Polygon", "[Polygon]") { } } } + +SCENARIO("Simplify polygon", "[Polygon]") +{ + GIVEN("gear") { + auto gear = Polygon::new_scale({ + {144.9694,317.1543}, {145.4181,301.5633}, {146.3466,296.921}, {131.8436,294.1643}, {131.7467,294.1464}, + {121.7238,291.5082}, {117.1631,290.2776}, {107.9198,308.2068}, {100.1735,304.5101}, {104.9896,290.3672}, + {106.6511,286.2133}, {93.453,279.2327}, {81.0065,271.4171}, {67.7886,286.5055}, {60.7927,280.1127}, + {69.3928,268.2566}, {72.7271,264.9224}, {61.8152,253.9959}, {52.2273,242.8494}, {47.5799,245.7224}, + {34.6577,252.6559}, {30.3369,245.2236}, {42.1712,236.3251}, {46.1122,233.9605}, {43.2099,228.4876}, + {35.0862,211.5672}, {33.1441,207.0856}, {13.3923,212.1895}, {10.6572,203.3273}, {6.0707,204.8561}, + {7.2775,204.4259}, {29.6713,196.3631}, {25.9815,172.1277}, {25.4589,167.2745}, {19.8337,167.0129}, + {5.0625,166.3346}, {5.0625,156.9425}, {5.3701,156.9282}, {21.8636,156.1628}, {25.3713,156.4613}, + {25.4243,155.9976}, {29.3432,155.8157}, {30.3838,149.3549}, {26.3596,147.8137}, {27.1085,141.2604}, + {29.8466,126.8337}, {24.5841,124.9201}, {10.6664,119.8989}, {13.4454,110.9264}, {33.1886,116.0691}, + {38.817,103.1819}, {45.8311,89.8133}, {30.4286,76.81}, {35.7686,70.0812}, {48.0879,77.6873}, + {51.564,81.1635}, {61.9006,69.1791}, {72.3019,58.7916}, {60.5509,42.5416}, {68.3369,37.1532}, + {77.9524,48.1338}, {80.405,52.2215}, {92.5632,44.5992}, {93.0123,44.3223}, {106.3561,37.2056}, + {100.8631,17.4679}, {108.759,14.3778}, {107.3148,11.1283}, {117.0002,32.8627}, {140.9109,27.3974}, + {145.7004,26.4994}, {145.1346,6.1011}, {154.502,5.4063}, {156.9398,25.6501}, {171.0557,26.2017}, + {181.3139,27.323}, {186.2377,27.8532}, {191.6031,8.5474}, {200.6724,11.2756}, {197.2362,30.2334}, + {220.0789,39.1906}, {224.3261,41.031}, {236.3506,24.4291}, {243.6897,28.6723}, {234.2956,46.7747}, + {245.6562,55.1643}, {257.2523,65.0901}, {261.4374,61.5679}, {273.1709,52.8031}, {278.555,59.5164}, + {268.4334,69.8001}, {264.1615,72.3633}, {268.2763,77.9442}, {278.8488,93.5305}, {281.4596,97.6332}, + {286.4487,95.5191}, {300.2821,90.5903}, {303.4456,98.5849}, {286.4523,107.7253}, {293.7063,131.1779}, + {294.9748,135.8787}, {314.918,133.8172}, {315.6941,143.2589}, {300.9234,146.1746}, {296.6419,147.0309}, + {297.1839,161.7052}, {296.6136,176.3942}, {302.1147,177.4857}, {316.603,180.3608}, {317.1658,176.7341}, + {315.215,189.6589}, {315.1749,189.6548}, {294.9411,187.5222}, {291.13,201.7233}, {286.2615,215.5916}, + {291.1944,218.2545}, {303.9158,225.1271}, {299.2384,233.3694}, {285.7165,227.6001}, {281.7091,225.1956}, + {273.8981,237.6457}, {268.3486,245.2248}, {267.4538,246.4414}, {264.8496,250.0221}, {268.6392,253.896}, + {278.5017,265.2131}, {272.721,271.4403}, {257.2776,258.3579}, {234.4345,276.5687}, {242.6222,294.8315}, + {234.9061,298.5798}, {227.0321,286.2841}, {225.2505,281.8301}, {211.5387,287.8187}, {202.3025,291.0935}, + {197.307,292.831}, {199.808,313.1906}, {191.5298,315.0787}, {187.3082,299.8172}, {186.4201,295.3766}, + {180.595,296.0487}, {161.7854,297.4248}, {156.8058,297.6214}, {154.3395,317.8592} + }); + + WHEN("simplified") { + size_t num_points = gear.size(); + Polygons simplified = gear.simplify(1000.); + THEN("gear simplified to a single polygon") { + REQUIRE(simplified.size() == 1); + } + THEN("gear was reduced using Douglas-Peucker") { + //note printf "original points: %d\nnew points: %d", $num_points, scalar(@{$simplified->[0]}); + REQUIRE(simplified.front().size() < num_points); + } + } + } + GIVEN("hole in square") { + // CW oriented + auto hole_in_square = Polygon{ {140, 140}, {140, 160}, {160, 160}, {160, 140} }; + WHEN("simplified") { + Polygons simplified = hole_in_square.simplify(2.); + THEN("hole simplification returns one polygon") { + REQUIRE(simplified.size() == 1); + } + THEN("hole simplification turns cw polygon into ccw polygon") { + REQUIRE(simplified.front().is_counter_clockwise()); + } + } + } +} diff --git a/tests/libslic3r/test_polyline.cpp b/tests/libslic3r/test_polyline.cpp new file mode 100644 index 0000000000..8271554041 --- /dev/null +++ b/tests/libslic3r/test_polyline.cpp @@ -0,0 +1,28 @@ +#include + +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" + +using namespace Slic3r; + +SCENARIO("Simplify polyline", "[Polyline]") +{ + GIVEN("polyline 1") { + auto polyline = Polyline{ {0,0},{1,0},{2,0},{2,1},{2,2},{1,2},{0,2},{0,1},{0,0} }; + WHEN("simplified with Douglas-Peucker") { + polyline.simplify(1.); + THEN("simplified correctly") { + REQUIRE(polyline == Polyline{ {0,0}, {2,0}, {2,2}, {0,2}, {0,0} }); + } + } + } + GIVEN("polyline 2") { + auto polyline = Polyline{ {0,0}, {50,50}, {100,0}, {125,-25}, {150,50} }; + WHEN("simplified with Douglas-Peucker") { + polyline.simplify(25.); + THEN("not simplified") { + REQUIRE(polyline == Polyline{ {0,0}, {50,50}, {125,-25}, {150,50} }); + } + } + } +} diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index 1a58aab122..c2343b032c 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -49,7 +49,6 @@ set(XS_XSP_FILES ${XSP_DIR}/ExtrusionEntityCollection.xsp ${XSP_DIR}/ExtrusionLoop.xsp ${XSP_DIR}/ExtrusionPath.xsp - ${XSP_DIR}/GCode.xsp ${XSP_DIR}/Geometry.xsp ${XSP_DIR}/Layer.xsp ${XSP_DIR}/Line.xsp diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 1675ac1935..87fb267c51 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -158,7 +158,6 @@ for my $class (qw( Slic3r::ExtrusionLoop Slic3r::ExtrusionPath Slic3r::ExtrusionPath::Collection - Slic3r::GCode Slic3r::Geometry::BoundingBox Slic3r::Layer Slic3r::Layer::Region diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index 4e293a2f9f..8484b1d64f 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -7,7 +7,6 @@ REGISTER_CLASS(ExPolygon, "ExPolygon"); REGISTER_CLASS(ExtrusionPath, "ExtrusionPath"); REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop"); REGISTER_CLASS(ExtrusionEntityCollection, "ExtrusionPath::Collection"); -REGISTER_CLASS(CoolingBuffer, "GCode::CoolingBuffer"); REGISTER_CLASS(GCode, "GCode"); REGISTER_CLASS(Layer, "Layer"); REGISTER_CLASS(LayerRegion, "Layer::Region"); diff --git a/xs/t/01_trianglemesh.t b/xs/t/01_trianglemesh.t deleted file mode 100644 index a071a75a28..0000000000 --- a/xs/t/01_trianglemesh.t +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use Slic3r::XS; -use Test::More tests => 4; - -my $cube = { - vertices => [ [20,20,0], [20,0,0], [0,0,0], [0,20,0], [20,20,20], [0,20,20], [0,0,20], [20,0,20] ], - facets => [ [0,1,2], [0,2,3], [4,5,6], [4,6,7], [0,4,7], [0,7,1], [1,7,6], [1,6,2], [2,6,5], [2,5,3], [4,0,3], [4,3,5] ], -}; - -{ - my $m = Slic3r::TriangleMesh->new; - $m->ReadFromPerl($cube->{vertices}, $cube->{facets}); - my ($vertices, $facets) = ($m->vertices, $m->facets); - - is_deeply $vertices, $cube->{vertices}, 'vertices arrayref roundtrip'; - is_deeply $facets, $cube->{facets}, 'facets arrayref roundtrip'; - - { - my $m2 = $m->clone; - is_deeply $m2->vertices, $cube->{vertices}, 'cloned vertices arrayref roundtrip'; - is_deeply $m2->facets, $cube->{facets}, 'cloned facets arrayref roundtrip'; - $m2->scale(3); # check that it does not affect $m - } -} - -__END__ diff --git a/xs/t/03_point.t b/xs/t/03_point.t index c950998fbb..f888349b3d 100644 --- a/xs/t/03_point.t +++ b/xs/t/03_point.t @@ -4,10 +4,9 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 24; +use Test::More tests => 21; my $point = Slic3r::Point->new(10, 15); -is_deeply [ @$point ], [10, 15], 'point roundtrip'; my $point2 = $point->clone; $point2->scale(2); @@ -16,9 +15,6 @@ is_deeply [ @$point2 ], [20, 30], 'scale'; $point2->translate(10, -15); is_deeply [ @$point2 ], [30, 15], 'translate'; -ok $point->coincides_with($point->clone), 'coincides_with'; -ok !$point->coincides_with($point2), 'coincides_with'; - { my $point3 = Slic3r::Point->new(4300000, -9880845); is $point->[0], $point->x, 'x accessor'; diff --git a/xs/t/04_expolygon.t b/xs/t/04_expolygon.t index 48eaed551a..9132c44b96 100644 --- a/xs/t/04_expolygon.t +++ b/xs/t/04_expolygon.t @@ -5,7 +5,7 @@ use warnings; use List::Util qw(first sum); use Slic3r::XS; -use Test::More tests => 15; +use Test::More tests => 7; use constant PI => 4 * atan2(1, 1); @@ -25,21 +25,6 @@ my $hole_in_square = [ # cw my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square); ok $expolygon->is_valid, 'is_valid'; -is ref($expolygon->pp), 'ARRAY', 'expolygon pp is unblessed'; -is_deeply $expolygon->pp, [$square, $hole_in_square], 'expolygon roundtrip'; - -is ref($expolygon->arrayref), 'ARRAY', 'expolygon arrayref is unblessed'; -isa_ok $expolygon->[0], 'Slic3r::Polygon::Ref', 'expolygon polygon is blessed'; -isa_ok $expolygon->contour, 'Slic3r::Polygon::Ref', 'expolygon contour is blessed'; -isa_ok $expolygon->holes->[0], 'Slic3r::Polygon::Ref', 'expolygon hole is blessed'; -isa_ok $expolygon->[0][0], 'Slic3r::Point::Ref', 'expolygon point is blessed'; - -{ - my $expolygon2 = $expolygon->clone; - my $polygon = $expolygon2->[0]; - $polygon->scale(2); - is $expolygon2->[0][0][0], $polygon->[0][0], 'polygons are returned by reference'; -} is_deeply $expolygon->clone->pp, [$square, $hole_in_square], 'clone'; diff --git a/xs/t/05_surface.t b/xs/t/05_surface.t index 34feb47346..4d9eb5b891 100644 --- a/xs/t/05_surface.t +++ b/xs/t/05_surface.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 15; +use Test::More tests => 11; my $square = [ # ccw [100, 100], @@ -27,10 +27,6 @@ my $surface = Slic3r::Surface->new( $surface = $surface->clone; -isa_ok $surface->expolygon, 'Slic3r::ExPolygon::Ref', 'expolygon'; -is_deeply [ @{$surface->expolygon->pp} ], [$square, $hole_in_square], 'expolygon roundtrip'; -is scalar(@{$surface->polygons}), 2, 'polygons roundtrip'; - is $surface->surface_type, Slic3r::Surface::S_TYPE_INTERNAL, 'surface_type'; $surface->surface_type(Slic3r::Surface::S_TYPE_BOTTOM); is $surface->surface_type, Slic3r::Surface::S_TYPE_BOTTOM, 'modify surface_type'; @@ -59,7 +55,6 @@ is $surface->extra_perimeters, 2, 'extra_perimeters'; is scalar(@$collection), 1, 'append to collection'; my $item = $collection->[0]; - isa_ok $item, 'Slic3r::Surface::Ref'; $item->surface_type(Slic3r::Surface::S_TYPE_INTERNAL); is $item->surface_type, $collection->[0]->surface_type, 'collection returns items by reference'; } diff --git a/xs/t/06_polygon.t b/xs/t/06_polygon.t deleted file mode 100644 index 7bbcd5356b..0000000000 --- a/xs/t/06_polygon.t +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use Slic3r::XS; -use Test::More tests => 3; - -my $square = [ # ccw - [100, 100], - [200, 100], - [200, 200], - [100, 200], -]; - -my $polygon = Slic3r::Polygon->new(@$square); -is ref($polygon->arrayref), 'ARRAY', 'polygon arrayref is unblessed'; -isa_ok $polygon->[0], 'Slic3r::Point::Ref', 'polygon point is blessed'; -ok ref($polygon->first_point) eq 'Slic3r::Point', 'first_point'; - -__END__ diff --git a/xs/t/07_extrusionpath.t b/xs/t/07_extrusionpath.t index 008b51b001..084b4f03ea 100644 --- a/xs/t/07_extrusionpath.t +++ b/xs/t/07_extrusionpath.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 7; +use Test::More tests => 5; my $points = [ [100, 100], @@ -17,8 +17,6 @@ my $path = Slic3r::ExtrusionPath->new( role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, mm3_per_mm => 1, ); -isa_ok $path->polyline, 'Slic3r::Polyline::Ref', 'path polyline'; -is_deeply $path->polyline->pp, $points, 'path points roundtrip'; $path->reverse; is_deeply $path->polyline->pp, [ reverse @$points ], 'reverse path'; diff --git a/xs/t/08_extrusionloop.t b/xs/t/08_extrusionloop.t index e0660a9fd9..3abfbd728a 100644 --- a/xs/t/08_extrusionloop.t +++ b/xs/t/08_extrusionloop.t @@ -5,7 +5,7 @@ use warnings; use List::Util qw(sum); use Slic3r::XS; -use Test::More tests => 47; +use Test::More tests => 46; { my $square = [ @@ -33,7 +33,6 @@ use Test::More tests => 47; is scalar(@$loop), 1, 'loop contains one path'; { my $path = $loop->[0]; - isa_ok $path, 'Slic3r::ExtrusionPath::Ref'; is $path->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'role'; } diff --git a/xs/t/09_polyline.t b/xs/t/09_polyline.t index 5203ec5ef4..7da74b93da 100644 --- a/xs/t/09_polyline.t +++ b/xs/t/09_polyline.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 18; +use Test::More tests => 15; my $points = [ [100, 100], @@ -14,11 +14,6 @@ my $points = [ my $polyline = Slic3r::Polyline->new(@$points); -is_deeply $polyline->pp, $points, 'polyline roundtrip'; - -is ref($polyline->arrayref), 'ARRAY', 'polyline arrayref is unblessed'; -isa_ok $polyline->[0], 'Slic3r::Point::Ref', 'polyline point is blessed'; - my $lines = $polyline->lines; is_deeply [ map $_->pp, @$lines ], [ [ [100, 100], [200, 100] ], @@ -88,41 +83,4 @@ is_deeply $polyline->pp, [ @$points, @$points ], 'append_polyline'; is scalar(@$p2), 4, 'split_at'; } -# disabled because we now use a more efficient but incomplete algorithm -#if (0) { -# my $polyline = Slic3r::Polyline->new( -# map [$_,10], (0,10,20,30,40,50,60) -# ); -# { -# my $expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new( -# [25,0], [55,0], [55,30], [25,30], -# )); -# my $p = $polyline->clone; -# $p->simplify_by_visibility($expolygon); -# is_deeply $p->pp, [ -# map [$_,10], (0,10,20,30,50,60) -# ], 'simplify_by_visibility()'; -# } -# { -# my $expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new( -# [-15,0], [75,0], [75,30], [-15,30], -# )); -# my $p = $polyline->clone; -# $p->simplify_by_visibility($expolygon); -# is_deeply $p->pp, [ -# map [$_,10], (0,60) -# ], 'simplify_by_visibility()'; -# } -# { -# my $expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new( -# [-15,0], [25,0], [25,30], [-15,30], -# )); -# my $p = $polyline->clone; -# $p->simplify_by_visibility($expolygon); -# is_deeply $p->pp, [ -# map [$_,10], (0,20,30,40,50,60) -# ], 'simplify_by_visibility()'; -# } -#} - __END__ diff --git a/xs/t/10_line.t b/xs/t/10_line.t index 8f82e988c6..886573f7b6 100644 --- a/xs/t/10_line.t +++ b/xs/t/10_line.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 40; +use Test::More tests => 35; use constant PI => 4 * atan2(1, 1); use constant EPSILON => 1E-4; @@ -15,21 +15,6 @@ my $points = [ ]; my $line = Slic3r::Line->new(@$points); -is_deeply $line->pp, $points, 'line roundtrip'; - -is ref($line->arrayref), 'ARRAY', 'line arrayref is unblessed'; -isa_ok $line->[0], 'Slic3r::Point::Ref', 'line point is blessed'; - -{ - my $clone = $line->clone; - $clone->reverse; - is_deeply $clone->pp, [ reverse @$points ], 'reverse'; -} - -{ - my $line2 = Slic3r::Line->new($line->a->clone, $line->b->clone); - is_deeply $line2->pp, $points, 'line roundtrip with cloned points'; -} { my $clone = $line->clone; diff --git a/xs/t/12_extrusionpathcollection.t b/xs/t/12_extrusionpathcollection.t index e7e0b1316a..e028542451 100644 --- a/xs/t/12_extrusionpathcollection.t +++ b/xs/t/12_extrusionpathcollection.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 18; +use Test::More tests => 13; my $points = [ [100, 100], @@ -41,12 +41,6 @@ is scalar(@$collection), 3, 'append ExtrusionPath'; $collection->append($loop); is scalar(@$collection), 4, 'append ExtrusionLoop'; -isa_ok $collection->[1], 'Slic3r::ExtrusionPath::Collection::Ref', 'correct object returned for collection'; -isa_ok $collection->[2], 'Slic3r::ExtrusionPath::Ref', 'correct object returned for path'; -isa_ok $collection->[3], 'Slic3r::ExtrusionLoop::Ref', 'correct object returned for loop'; -is ref($collection->[2]->clone), 'Slic3r::ExtrusionPath', 'correct object returned for cloned path'; -is ref($collection->[3]->clone), 'Slic3r::ExtrusionLoop', 'correct object returned for cloned loop'; - is scalar(@{$collection->[1]}), 1, 'appended collection was duplicated'; { diff --git a/xs/t/17_boundingbox.t b/xs/t/17_boundingbox.t deleted file mode 100644 index 349e0024de..0000000000 --- a/xs/t/17_boundingbox.t +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use Slic3r::XS; -use Test::More tests => 5; - -{ - my @points = ( - Slic3r::Point->new(100, 200), - Slic3r::Point->new(500, -600), - ); - my $bb = Slic3r::Geometry::BoundingBox->new_from_points(\@points); - isa_ok $bb, 'Slic3r::Geometry::BoundingBox', 'new_from_points'; - is_deeply $bb->min_point->pp, [100,-600], 'min_point'; - is_deeply $bb->max_point->pp, [500,200], 'max_point'; -} - -{ - my $bb = Slic3r::Geometry::BoundingBox->new; - $bb->merge_point(Slic3r::Point->new(10, 10)); - is_deeply $bb->min_point->pp, [10,10], 'min_point equals to the only defined point'; - is_deeply $bb->max_point->pp, [10,10], 'max_point equals to the only defined point'; -} - -__END__ diff --git a/xs/xsp/ExPolygon.xsp b/xs/xsp/ExPolygon.xsp index a57bcfbcb8..50b32544ee 100644 --- a/xs/xsp/ExPolygon.xsp +++ b/xs/xsp/ExPolygon.xsp @@ -29,8 +29,6 @@ %code{% RETVAL = THIS->contains(*point); %}; ExPolygons simplify(double tolerance); Polygons simplify_p(double tolerance); - Polylines medial_axis(double max_width, double min_width) - %code{% THIS->medial_axis(max_width, min_width, &RETVAL); %}; %{ ExPolygon* diff --git a/xs/xsp/GCode.xsp b/xs/xsp/GCode.xsp deleted file mode 100644 index 4c25838946..0000000000 --- a/xs/xsp/GCode.xsp +++ /dev/null @@ -1,53 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "libslic3r/GCode.hpp" -#include "libslic3r/GCode/CoolingBuffer.hpp" -%} - -%name{Slic3r::GCode::CoolingBuffer} class CoolingBuffer { - CoolingBuffer(GCode* gcode) - %code{% RETVAL = new CoolingBuffer(*gcode); %}; - ~CoolingBuffer(); - std::string process_layer(std::string gcode, size_t layer_id) - %code{% RETVAL = THIS->process_layer(std::move(gcode), layer_id, true); %}; - -}; - -%name{Slic3r::GCode} class GCode { - GCode(); - ~GCode(); - void do_export(Print *print, const char *path) - %code%{ - try { - THIS->do_export(print, path); - } catch (std::exception& e) { - croak("%s\n", e.what()); - } - %}; - - Ref origin() - %code{% RETVAL = &(THIS->origin()); %}; - void set_origin(Vec2d* pointf) - %code{% THIS->set_origin(*pointf); %}; - Ref last_pos() - %code{% RETVAL = &(THIS->last_pos()); %}; - - unsigned int layer_count() const; - void set_layer_count(unsigned int value); - void set_extruders(std::vector extruders) - %code{% THIS->writer().set_extruders(extruders); THIS->writer().set_extruder(0); %}; - - void apply_print_config(StaticPrintConfig* print_config) - %code{% - if (const PrintConfig* config = dynamic_cast(print_config)) { - THIS->apply_print_config(*config); - } else { - CONFESS("A PrintConfig object was not supplied to apply_print_config()"); - } - %}; - - Ref config() - %code{% RETVAL = const_cast(static_cast(static_cast(&THIS->config()))); %}; -}; diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 5174bdfa95..42ca74292c 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -125,18 +125,9 @@ Ref O_OBJECT_SLIC3R_T Layer* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T -CoolingBuffer* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -GCode* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - Axis T_UV ExtrusionLoopRole T_UV ExtrusionRole T_UV -FlowRole T_UV SurfaceType T_UV # we return these types whenever we want the items to be cloned diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index 243e80dbcd..bf1e8e2acc 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -92,18 +92,6 @@ %typemap{Layer*}; %typemap{Ref}{simple}; -%typemap{CoolingBuffer*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; - -%typemap{GCode*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; - -//%typemap{GCodePreviewData*}; -//%typemap{Ref}{simple}; -//%typemap{Clone}{simple}; - %typemap{Points}; %typemap{Pointfs}; %typemap{Lines}; @@ -167,9 +155,3 @@ $CVar = (ExtrusionRole)SvUV($PerlVar); %}; }; -%typemap{FlowRole}{parsed}{ - %cpp_type{FlowRole}; - %precall_code{% - $CVar = (FlowRole)SvUV($PerlVar); - %}; -}; From ff20ad1052987b79196430ab61928c2bbdc3fa44 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 6 May 2022 07:30:03 +0200 Subject: [PATCH 10/25] Fixed warning --- src/slic3r/GUI/GCodeViewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index afcc3f9541..652410589f 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -3942,7 +3942,7 @@ void GCodeViewer::render_legend(float& legend_height) std::vector custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes : m_custom_gcode_per_print_z; std::vector last_color(m_extruders_count); - for (int i = 0; i < m_extruders_count; ++i) { + for (size_t i = 0; i < m_extruders_count; ++i) { last_color[i] = m_tool_colors[i]; } int last_extruder_id = 1; From 9d2b6d5bda282423161ffc545d37a0a352950218 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 6 May 2022 09:14:39 +0200 Subject: [PATCH 11/25] Follow-up to https://github.com/prusa3d/PrusaSlicer/commit/d0b4a4a87da65ba079456863092a335f192bf6dd - Fix for build warnings --- src/slic3r/GUI/Preferences.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 8ad387367a..660cfc7f0c 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -731,11 +731,9 @@ void PreferencesDialog::revert(wxEvent&) , m_optgroup_render #endif // ENABLE_ENVIRONMENT_MAP }) { - if (reverted = opt_group->set_value(key, app_config->get(key) == "1")) + if (opt_group->set_value(key, app_config->get(key) == "1")) break; } - if (!reverted) - int i=0; if (key == "tabs_as_menu") { m_rb_new_settings_layout_mode->Show(app_config->get(key) != "1"); refresh_og(m_optgroup_gui); From 6ab517187fa5f3a8e2b87a59b6a50f26b3a49da6 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Fri, 6 May 2022 13:37:35 +0200 Subject: [PATCH 12/25] Fix mismatch of data types. Separate checks. --- tests/libslic3r/test_mutable_priority_queue.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/libslic3r/test_mutable_priority_queue.cpp b/tests/libslic3r/test_mutable_priority_queue.cpp index 40ed5a1586..3e99eef08a 100644 --- a/tests/libslic3r/test_mutable_priority_queue.cpp +++ b/tests/libslic3r/test_mutable_priority_queue.cpp @@ -343,7 +343,7 @@ TEST_CASE("Mutable priority queue - reshedule first", "[MutableSkipHeapPriorityQ TEST_CASE("Mutable priority queue - first pop", "[MutableSkipHeapPriorityQueue]") { struct MyValue{ - int id; + size_t id; float val; }; size_t count = 50000; @@ -356,15 +356,15 @@ TEST_CASE("Mutable priority queue - first pop", "[MutableSkipHeapPriorityQueue]" [](MyValue &l, MyValue &r) { return l.val < r.val; }); q.reserve(count); for (size_t id = 0; id < count; id++) { - MyValue mv; - mv.id = id; - mv.val = rand(); + MyValue mv{ id, rand()}; q.push(mv); } MyValue it = q.top(); // copy q.pop(); - bool valid = (it.id != 0) && (idxs[0] < 3 * count); - CHECK(valid); + // is valid id (no initial value default value) + CHECK(it.id != 0); + // is first item in queue valid value + CHECK(idxs[0] != std::numeric_limits::max()); } TEST_CASE("Mutable priority queue complex", "[MutableSkipHeapPriorityQueue]") From 6173896024ba14047c0b07e55bb969f3485f6b36 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 6 May 2022 17:04:10 +0200 Subject: [PATCH 13/25] Revert utf8 for wx on mac --- deps/wxWidgets/wxWidgets.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/wxWidgets/wxWidgets.cmake b/deps/wxWidgets/wxWidgets.cmake index 2939425682..bf5fd62894 100644 --- a/deps/wxWidgets/wxWidgets.cmake +++ b/deps/wxWidgets/wxWidgets.cmake @@ -10,7 +10,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") endif() set(_unicode_utf8 OFF) -if (UNIX) # wxWidgets will not use char as the underlying type for wxString unless its forced to. +if (UNIX AND NOT APPLE) # wxWidgets will not use char as the underlying type for wxString unless its forced to. set (_unicode_utf8 ON) endif() From e687db9eb018097a5e81fb6dfd3637c9e8a2d257 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 6 May 2022 18:30:10 +0200 Subject: [PATCH 14/25] Ported custom_gcode and print unit tests from Perl to C++. --- lib/Slic3r/Layer.pm | 16 -- src/libslic3r/PrintConfig.hpp | 12 + t/custom_gcode.t | 210 --------------- t/print.t | 65 ----- tests/fff_print/test_custom_gcode.cpp | 361 ++++++++++++++------------ tests/fff_print/test_data.cpp | 13 + tests/fff_print/test_data.hpp | 3 + tests/fff_print/test_print.cpp | 59 +++++ tests/fff_print/test_skirt_brim.cpp | 1 + xs/xsp/Print.xsp | 2 - 10 files changed, 289 insertions(+), 453 deletions(-) delete mode 100644 t/custom_gcode.t delete mode 100644 t/print.t diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index 7f7b589d0d..a4146f169a 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -15,20 +15,4 @@ sub config { return $self->object->config; } -sub region { - my $self = shift; - my ($region_id) = @_; - - while ($self->region_count <= $region_id) { - $self->add_region($self->object->print->get_region($self->region_count)); - } - - return $self->get_region($region_id); -} - -sub regions { - my ($self) = @_; - return [ map $self->get_region($_), 0..($self->region_count-1) ]; -} - 1; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index ab12bc8ce2..0c1060b7de 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -220,6 +220,16 @@ public: config.set_deserialize_strict(items); return config; } + static DynamicPrintConfig new_with(const t_config_option_key &opt_key, const std::string &str, bool append = false) { + DynamicPrintConfig config; + config.set_deserialize_strict(opt_key, str, append); + return config; + } + static DynamicPrintConfig new_with(std::initializer_list items) { + DynamicPrintConfig config; + config.set_deserialize_strict(items); + return config; + } static DynamicPrintConfig* new_from_defaults_keys(const std::vector &keys); // Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here. @@ -1131,6 +1141,8 @@ public: void set(const std::string &opt_key, T value) { m_data.set(opt_key, value, true); this->touch(); } void set_deserialize(const t_config_option_key &opt_key, const std::string &str, ConfigSubstitutionContext &substitution_context, bool append = false) { m_data.set_deserialize(opt_key, str, substitution_context, append); this->touch(); } + void set_deserialize_strict(const t_config_option_key &opt_key, const std::string &str, bool append = false) + { m_data.set_deserialize_strict(opt_key, str, append); this->touch(); } bool erase(const t_config_option_key &opt_key) { bool out = m_data.erase(opt_key); if (out) this->touch(); return out; } // Getters are thread safe. diff --git a/t/custom_gcode.t b/t/custom_gcode.t deleted file mode 100644 index 1bb52b618e..0000000000 --- a/t/custom_gcode.t +++ /dev/null @@ -1,210 +0,0 @@ -use Test::More tests => 38; -use strict; -use warnings; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use List::Util qw(first); -use Slic3r; -use Slic3r::Test; - -{ - my $config = Slic3r::Config::new_from_defaults; - - my $test = sub { - my ($conf) = @_; - $conf ||= $config; - - my $print = Slic3r::Test::init_print('2x20x10', config => $conf); - - my $last_move_was_z_change = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($last_move_was_z_change && $cmd ne $config->layer_gcode) { - fail 'custom layer G-code was not applied after Z change'; - } - if (!$last_move_was_z_change && $cmd eq $config->layer_gcode) { - fail 'custom layer G-code was not applied after Z change'; - } - - $last_move_was_z_change = (defined $info->{dist_Z} && $info->{dist_Z} > 0); - }); - - 1; - }; - - $config->set('start_gcode', '_MY_CUSTOM_START_GCODE_'); # to avoid dealing with the nozzle lift in start G-code - $config->set('layer_gcode', '_MY_CUSTOM_LAYER_GCODE_'); - ok $test->(), "custom layer G-code is applied after Z move and before other moves"; -} - -#========================================================== - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('output_filename_format', 'ts_[travel_speed]_lh_[layer_height].gcode'); - $config->set('start_gcode', "TRAVEL:[travel_speed] HEIGHT:[layer_height]\n"); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - - my $output_file = $print->print->output_filepath; - my ($t, $h) = map $config->$_, qw(travel_speed layer_height); - ok $output_file =~ /ts_${t}_/, 'print config options are replaced in output filename'; - ok $output_file =~ /lh_$h\./, 'region config options are replaced in output filename'; - - my $gcode = Slic3r::Test::gcode($print); - ok $gcode =~ /TRAVEL:$t/, 'print config options are replaced in custom G-code'; - ok $gcode =~ /HEIGHT:$h/, 'region config options are replaced in custom G-code'; -} - -{ - my $config = Slic3r::Config->new; - $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]); - $config->set('extruder', 2); - $config->set('first_layer_temperature', [200,205]); - - { - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - ok $gcode =~ /M104 S205 T1/, 'temperature set correctly for non-zero yet single extruder'; - ok $gcode !~ /M104 S\d+ T0/, 'unused extruder correctly ignored'; - } - - $config->set('infill_extruder', 1); - { - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - ok $gcode =~ /M104 S200 T0/, 'temperature set correctly for first extruder'; - ok $gcode =~ /M104 S205 T1/, 'temperature set correctly for second extruder'; - } - - my @start_gcode = (qq! -;__temp0:[first_layer_temperature_0]__ -;__temp1:[first_layer_temperature_1]__ -;__temp2:[first_layer_temperature_2]__ - !, qq! -;__temp0:{first_layer_temperature[0]}__ -;__temp1:{first_layer_temperature[1]}__ -;__temp2:{first_layer_temperature[2]}__ - !); - my @syntax_description = (' (legacy syntax)', ' (new syntax)'); - for my $i (0, 1) { - $config->set('start_gcode', $start_gcode[$i]); - { - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - # we use the [infill_extruder] placeholder to make sure this test doesn't - # catch a false positive caused by the unparsed start G-code option itself - # being embedded in the G-code - ok $gcode =~ /temp0:200/, 'temperature placeholder for first extruder correctly populated' . $syntax_description[$i]; - ok $gcode =~ /temp1:205/, 'temperature placeholder for second extruder correctly populated' . $syntax_description[$i]; - ok $gcode =~ /temp2:200/, 'temperature placeholder for unused extruder populated with first value' . $syntax_description[$i]; - } - } - - $config->set('start_gcode', qq! -;substitution:{if infill_extruder==1}extruder1 - {elsif infill_extruder==2}extruder2 - {else}extruder3{endif} - !); - { - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - ok $gcode =~ /substitution:extruder1/, 'if / else / endif - first block returned'; - } -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('before_layer_gcode', ';BEFORE [layer_num]'); - $config->set('layer_gcode', ';CHANGE [layer_num]'); - $config->set('support_material', 1); - $config->set('layer_height', 0.2); - my $print = Slic3r::Test::init_print('overhang', config => $config); - my $gcode = Slic3r::Test::gcode($print); - - my @before = (); - my @change = (); - foreach my $line (split /\R+/, $gcode) { - if ($line =~ /;BEFORE (\d+)/) { - push @before, $1; - } elsif ($line =~ /;CHANGE (\d+)/) { - push @change, $1; - fail 'inconsistent layer_num before and after layer change' - if $1 != $before[-1]; - } - } - is_deeply \@before, \@change, 'layer_num is consistent before and after layer changes'; - ok !defined(first { $change[$_] != $change[$_-1]+1 } 1..$#change), - 'layer_num grows continously'; # i.e. no duplicates or regressions -} - -{ - my $config = Slic3r::Config->new; - $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6,0.6]); - $config->set('start_gcode', qq! -;substitution:{if infill_extruder==1}if block - {elsif infill_extruder==2}elsif block 1 - {elsif infill_extruder==3}elsif block 2 - {elsif infill_extruder==4}elsif block 3 - {else}endif block{endif} - !); - my @returned = ('', 'if block', 'elsif block 1', 'elsif block 2', 'elsif block 3', 'endif block'); - for my $i (1,2,3,4,5) { - $config->set('infill_extruder', $i); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - my $found_other = 0; - for my $j (1,2,3,4,5) { - next if $i == $j; - $found_other = 1 if $gcode =~ /substitution:$returned[$j]/; - } - ok $gcode =~ /substitution:$returned[$i]/, 'if / else / endif - ' . $returned[$i] . ' returned'; - ok !$found_other, 'if / else / endif - only ' . $returned[$i] . ' returned'; - } -} - -{ - my $config = Slic3r::Config->new; - $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]); - $config->set('start_gcode', - ';substitution:{if infill_extruder==1}{if perimeter_extruder==1}block11{else}block12{endif}' . - '{elsif infill_extruder==2}{if perimeter_extruder==1}block21{else}block22{endif}' . - '{else}{if perimeter_extruder==1}block31{else}block32{endif}{endif}:end'); - for my $i (1,2,3) { - $config->set('infill_extruder', $i); - for my $j (1,2) { - $config->set('perimeter_extruder', $j); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - ok $gcode =~ /substitution:block$i$j:end/, "two level if / else / endif - block$i$j returned"; - } - } -} - -{ - my $config = Slic3r::Config->new; - $config->set('start_gcode', - ';substitution:{if notes=="MK2"}MK2{elsif notes=="MK3"}MK3{else}MK1{endif}:end'); - for my $printer_name ("MK2", "MK3", "MK1") { - $config->set('notes', $printer_name); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - ok $gcode =~ /substitution:$printer_name:end/, "printer name $printer_name matched"; - } -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('complete_objects', 1); - $config->set('between_objects_gcode', '_MY_CUSTOM_GCODE_'); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 3); - my $gcode = Slic3r::Test::gcode($print); - is scalar(() = $gcode =~ /^_MY_CUSTOM_GCODE_/gm), 2, 'between_objects_gcode is applied correctly'; -} - -__END__ diff --git a/t/print.t b/t/print.t deleted file mode 100644 index 2144e80c1e..0000000000 --- a/t/print.t +++ /dev/null @@ -1,65 +0,0 @@ -use Test::More tests => 6; -use strict; -use warnings; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use List::Util qw(first); -use Slic3r; -use Slic3r::Geometry qw(unscale X Y); -use Slic3r::Test; - -{ - my $config = Slic3r::Config::new_from_defaults; - my $print_center = [100,100]; - my $print = Slic3r::Test::init_print('20mm_cube', config => $config, print_center => $print_center); - my @extrusion_points = (); - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) { - push @extrusion_points, my $point = Slic3r::Point->new_scale($args->{X}, $args->{Y}); - } - }); - my $bb = Slic3r::Geometry::BoundingBox->new_from_points(\@extrusion_points); - my $center = $bb->center; - ok abs(unscale($center->[X]) - $print_center->[X]) < 0.005, 'print is centered around print_center (X)'; - ok abs(unscale($center->[Y]) - $print_center->[Y]) < 0.005, 'print is centered around print_center (Y)'; -} - -{ - # this represents the aggregate config from presets - my $config = Slic3r::Config::new_from_defaults; - # Define 4 extruders. - $config->set('nozzle_diameter', [0.4, 0.4, 0.4, 0.4]); - - # user adds one object to the plater - my $print = Slic3r::Test::init_print(my $model = Slic3r::Test::model('20mm_cube'), config => $config); - - # user sets a per-region option - my $model2 = $model->clone; - $model2->get_object(0)->config->set('fill_density', 100); - $print->apply($model2, $config); - - is $print->print->regions->[0]->config->fill_density, 100, 'region config inherits model object config'; - - # user exports G-code, thus the default config is reapplied - $model2->get_object(0)->config->erase('fill_density'); - $print->apply($model2, $config); - - is $print->print->regions->[0]->config->fill_density, 20, 'region config is resetted'; - - # user assigns object extruders - $model2->get_object(0)->config->set('extruder', 3); - $model2->get_object(0)->config->set('perimeter_extruder', 2); - $print->apply($model2, $config); - - is $print->print->regions->[0]->config->infill_extruder, 3, 'extruder setting is correctly expanded'; - is $print->print->regions->[0]->config->perimeter_extruder, 2, 'extruder setting does not override explicitely specified extruders'; -} - -__END__ diff --git a/tests/fff_print/test_custom_gcode.cpp b/tests/fff_print/test_custom_gcode.cpp index 0368b9604f..37103b316d 100644 --- a/tests/fff_print/test_custom_gcode.cpp +++ b/tests/fff_print/test_custom_gcode.cpp @@ -1,8 +1,11 @@ #include +#include #include #include +#include + #include "libslic3r/Config.hpp" #include "libslic3r/Print.hpp" #include "libslic3r/PrintConfig.hpp" @@ -12,11 +15,12 @@ using namespace Slic3r; -#if 0 SCENARIO("Output file format", "[CustomGCode]") { WHEN("output_file_format set") { auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "travel_speed", "130"}, + { "layer_height", "0.4"}, { "output_filename_format", "ts_[travel_speed]_lh_[layer_height].gcode" }, { "start_gcode", "TRAVEL:[travel_speed] HEIGHT:[layer_height]\n" } }); @@ -25,20 +29,9 @@ SCENARIO("Output file format", "[CustomGCode]") Model model; Test::init_print({ Test::TestMesh::cube_2x20x10 }, print, model, config); - std::string output_file = print.output_filepath(); + std::string output_file = print.output_filepath({}, {}); THEN("print config options are replaced in output filename") { - output_file.find(std::string("ts_") + ) - } - my ($t, $h) = map $config->$_, qw(travel_speed layer_height); - ok $output_file =~ /ts_${t}_/, ''; - ok $output_file =~ /lh_$h\./, 'region config options are replaced in output filename'; - - std::string gcode = print.gcode(print); - THEN("print config options are replaced in custom G-code") { - ok $gcode =~ /TRAVEL:$t/, ''; - } - THEN("region config options are replaced in custom G-code") { - ok $gcode =~ /HEIGHT:$h/, ''; + REQUIRE(output_file == "ts_130_lh_0.4.gcode"); } } } @@ -56,165 +49,213 @@ SCENARIO("Custom G-code", "[CustomGCode]") parser.parse_buffer(Slic3r::Test::slice({ Test::TestMesh::cube_2x20x10 }, config), [&last_move_was_z_change, &num_layer_changes_not_applied](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { - if (line.extruding(self)) { - if (! was_extruding) - seam_points.emplace_back(self.xy_scaled()); - was_extruding = true; - } else if (! line.cmd_is("M73")) { - // skips remaining time lines (M73) - was_extruding = false; - } if (last_move_was_z_change != line.cmd_is("_MY_CUSTOM_LAYER_GCODE_")) ++ num_layer_changes_not_applied; last_move_was_z_change = line.dist_Z(self) > 0; }); - THEN("custom layer G-code is applied after Z move and before other moves"); + THEN("custom layer G-code is applied after Z move and before other moves") { + REQUIRE(num_layer_changes_not_applied == 0); + } }; -{ - my $config = Slic3r::Config->new; - $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]); - $config->set('extruder', 2); - $config->set('first_layer_temperature', [200,205]); + auto config = Slic3r::DynamicPrintConfig::new_with({ + { "nozzle_diameter", { 0.6,0.6,0.6,0.6 } }, + { "extruder", 2 }, + { "first_layer_temperature", { 200, 205 } } + }); + config.normalize_fdm(); + WHEN("Printing with single but non-zero extruder") { + std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config); + THEN("temperature set correctly for non-zero yet single extruder") { + REQUIRE(Slic3r::Test::contains(gcode, "\nM104 S205 T1 ;")); + } + THEN("unused extruder correctly ignored") { + REQUIRE(! Slic3r::Test::contains_regex(gcode, "M104 S\\d+ T0")); + } + } + WHEN("Printing with two extruders") { + config.opt_int("infill_extruder") = 1; + std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config); + THEN("temperature set correctly for first extruder") { + REQUIRE(Slic3r::Test::contains(gcode, "\nM104 S200 T0 ;")); + }; + THEN("temperature set correctly for second extruder") { + REQUIRE(Slic3r::Test::contains(gcode, "\nM104 S205 T1 ;")); + }; + } + auto test = [](DynamicPrintConfig &config) { + // we use the [infill_extruder] placeholder to make sure this test doesn't + // catch a false positive caused by the unparsed start G-code option itself + // being embedded in the G-code + config.opt_int("infill_extruder") = 1; + std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config); + THEN("temperature placeholder for first extruder correctly populated") { + REQUIRE(Slic3r::Test::contains(gcode, "temp0:200")); + } + THEN("temperature placeholder for second extruder correctly populated") { + REQUIRE(Slic3r::Test::contains(gcode, "temp1:205")); + } + THEN("temperature placeholder for unused extruder populated with first value") { + REQUIRE(Slic3r::Test::contains(gcode, "temp2:200")); + } + }; + WHEN("legacy syntax") { + config.set_deserialize_strict("start_gcode", + ";__temp0:[first_layer_temperature_0]__\n" + ";__temp1:[first_layer_temperature_1]__\n" + ";__temp2:[first_layer_temperature_2]__\n"); + test(config); + } + WHEN("new syntax") { + config.set_deserialize_strict("start_gcode", + ";__temp0:{first_layer_temperature[0]}__\n" + ";__temp1:{first_layer_temperature[1]}__\n" + ";__temp2:{first_layer_temperature[2]}__\n"); + test(config); + } + WHEN("Vojtech's syntax") { + config.set_deserialize_strict({ + { "infill_extruder", 1 }, + { "start_gcode", + ";substitution:{if infill_extruder==1}extruder1" + "{elsif infill_extruder==2}extruder2" + "{else}extruder3{endif}" + } + }); + std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config); + THEN("if / else / endif - first block returned") { + REQUIRE(Test::contains(gcode, "\n;substitution:extruder1\n")); + } + } + GIVEN("Layer change G-codes") { - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - ok $gcode =~ /M104 S205 T1/, 'temperature set correctly for non-zero yet single extruder'; - ok $gcode !~ /M104 S\d+ T0/, 'unused extruder correctly ignored'; + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "before_layer_gcode", ";BEFORE [layer_num]" }, + { "layer_gcode", ";CHANGE [layer_num]" }, + { "support_material", 1 }, + { "layer_height", 0.2 } + }); + WHEN("before and after layer change G-codes set") { + std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::overhang }, config); + GCodeReader parser; + std::vector before; + std::vector change; + parser.parse_buffer(gcode, [&before, &change](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line){ + int d; + if (sscanf(line.raw().c_str(), ";BEFORE %d", &d) == 1) + before.emplace_back(d); + else if (sscanf(line.raw().c_str(), ";CHANGE %d", &d) == 1) { + change.emplace_back(d); + if (d != before.back()) + throw std::runtime_error("inconsistent layer_num before and after layer change"); + } + }); + THEN("layer_num is consistent before and after layer changes") { + REQUIRE(before == change); + } + THEN("layer_num grows continously") { + // i.e. no duplicates or regressions + bool successive = true; + for (size_t i = 1; i < change.size(); ++ i) + if (change[i - 1] + 1 != change[i]) + successive = false; + REQUIRE(successive); + } + } } - - $config->set('infill_extruder', 1); + GIVEN("if / elsif / elsif / elsif / else / endif") { - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - ok $gcode =~ /M104 S200 T0/, 'temperature set correctly for first extruder'; - ok $gcode =~ /M104 S205 T1/, 'temperature set correctly for second extruder'; + auto config = Slic3r::DynamicPrintConfig::new_with({ + { "nozzle_diameter", { 0.6,0.6,0.6,0.6,0.6 } }, + { "start_gcode", + ";substitution:{if infill_extruder==1}if block" + "{elsif infill_extruder==2}elsif block 1" + "{elsif infill_extruder==3}elsif block 2" + "{elsif infill_extruder==4}elsif block 3" + "{else}endif block{endif}" + ":end" + } + }); + std::string returned[] = { "" /* indexed by one based extruder ID */, "if block", "elsif block 1", "elsif block 2", "elsif block 3", "endif block" }; + auto test = [&config, &returned](int i) { + config.set_deserialize_strict({ { "infill_extruder", i } }); + std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config); + int found_error = 0; + for (int j = 1; j <= 5; ++ j) + if (i != j && Slic3r::Test::contains(gcode, std::string("substitution:") + returned[j] + ":end")) + // failure + ++ found_error; + THEN(std::string("if / else / endif returned ") + returned[i]) { + REQUIRE(Slic3r::Test::contains(gcode, std::string("substitution:") + returned[i] + ":end")); + } + THEN(std::string("if / else / endif - only ") + returned[i] + "returned") { + REQUIRE(found_error == 0); + } + }; + WHEN("infill_extruder == 1") { test(1); } + WHEN("infill_extruder == 2") { test(2); } + WHEN("infill_extruder == 3") { test(3); } + WHEN("infill_extruder == 4") { test(4); } + WHEN("infill_extruder == 5") { test(5); } } - - my @start_gcode = (qq! -;__temp0:[first_layer_temperature_0]__ -;__temp1:[first_layer_temperature_1]__ -;__temp2:[first_layer_temperature_2]__ - !, qq! -;__temp0:{first_layer_temperature[0]}__ -;__temp1:{first_layer_temperature[1]}__ -;__temp2:{first_layer_temperature[2]}__ - !); - my @syntax_description = (' (legacy syntax)', ' (new syntax)'); - for my $i (0, 1) { - $config->set('start_gcode', $start_gcode[$i]); - { - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - # we use the [infill_extruder] placeholder to make sure this test doesn't - # catch a false positive caused by the unparsed start G-code option itself - # being embedded in the G-code - ok $gcode =~ /temp0:200/, 'temperature placeholder for first extruder correctly populated' . $syntax_description[$i]; - ok $gcode =~ /temp1:205/, 'temperature placeholder for second extruder correctly populated' . $syntax_description[$i]; - ok $gcode =~ /temp2:200/, 'temperature placeholder for unused extruder populated with first value' . $syntax_description[$i]; - } + GIVEN("nested if / if / else / endif") { + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "nozzle_diameter", { 0.6,0.6,0.6,0.6,0.6 } }, + { "start_gcode", + ";substitution:{if infill_extruder==1}{if perimeter_extruder==1}block11{else}block12{endif}" + "{elsif infill_extruder==2}{if perimeter_extruder==1}block21{else}block22{endif}" + "{else}{if perimeter_extruder==1}block31{else}block32{endif}{endif}:end" + } + }); + auto test = [&config](int i) { + config.opt_int("infill_extruder") = i; + int failed = 0; + for (int j = 1; j <= 2; ++ j) { + config.opt_int("perimeter_extruder") = j; + std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config); + if (! Slic3r::Test::contains(gcode, std::string("substitution:block") + std::to_string(i) + std::to_string(j) + ":end")) + ++ failed; + } + THEN(std::string("two level if / else / endif - block for infill_extruder ") + std::to_string(i) + "succeeded") { + REQUIRE(failed == 0); + } + }; + WHEN("infill_extruder == 1") { test(1); } + WHEN("infill_extruder == 2") { test(2); } + WHEN("infill_extruder == 3") { test(3); } } - - $config->set('start_gcode', qq! -;substitution:{if infill_extruder==1}extruder1 - {elsif infill_extruder==2}extruder2 - {else}extruder3{endif} - !); - { - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - ok $gcode =~ /substitution:extruder1/, 'if / else / endif - first block returned'; + GIVEN("printer type in notes") { + auto config = Slic3r::DynamicPrintConfig::new_with({ + { "start_gcode", + ";substitution:{if notes==\"MK2\"}MK2{elsif notes==\"MK3\"}MK3{else}MK1{endif}:end" + } + }); + auto test = [&config](const std::string &printer_name) { + config.set_deserialize_strict("notes", printer_name); + std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config); + THEN(std::string("printer name ") + printer_name + " matched") { + REQUIRE(Slic3r::Test::contains(gcode, std::string("substitution:") + printer_name + ":end")); + } + }; + WHEN("printer MK2") { test("MK2"); } + WHEN("printer MK3") { test("MK3"); } + WHEN("printer MK1") { test("MK1"); } } -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('before_layer_gcode', ';BEFORE [layer_num]'); - $config->set('layer_gcode', ';CHANGE [layer_num]'); - $config->set('support_material', 1); - $config->set('layer_height', 0.2); - my $print = Slic3r::Test::init_print('overhang', config => $config); - my $gcode = Slic3r::Test::gcode($print); - - my @before = (); - my @change = (); - foreach my $line (split /\R+/, $gcode) { - if ($line =~ /;BEFORE (\d+)/) { - push @before, $1; - } elsif ($line =~ /;CHANGE (\d+)/) { - push @change, $1; - fail 'inconsistent layer_num before and after layer change' - if $1 != $before[-1]; - } - } - is_deeply \@before, \@change, 'layer_num is consistent before and after layer changes'; - ok !defined(first { $change[$_] != $change[$_-1]+1 } 1..$#change), - 'layer_num grows continously'; # i.e. no duplicates or regressions -} - -{ - my $config = Slic3r::Config->new; - $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6,0.6]); - $config->set('start_gcode', qq! -;substitution:{if infill_extruder==1}if block - {elsif infill_extruder==2}elsif block 1 - {elsif infill_extruder==3}elsif block 2 - {elsif infill_extruder==4}elsif block 3 - {else}endif block{endif} - !); - my @returned = ('', 'if block', 'elsif block 1', 'elsif block 2', 'elsif block 3', 'endif block'); - for my $i (1,2,3,4,5) { - $config->set('infill_extruder', $i); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - my $found_other = 0; - for my $j (1,2,3,4,5) { - next if $i == $j; - $found_other = 1 if $gcode =~ /substitution:$returned[$j]/; - } - ok $gcode =~ /substitution:$returned[$i]/, 'if / else / endif - ' . $returned[$i] . ' returned'; - ok !$found_other, 'if / else / endif - only ' . $returned[$i] . ' returned'; - } -} - -{ - my $config = Slic3r::Config->new; - $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]); - $config->set('start_gcode', - ';substitution:{if infill_extruder==1}{if perimeter_extruder==1}block11{else}block12{endif}' . - '{elsif infill_extruder==2}{if perimeter_extruder==1}block21{else}block22{endif}' . - '{else}{if perimeter_extruder==1}block31{else}block32{endif}{endif}:end'); - for my $i (1,2,3) { - $config->set('infill_extruder', $i); - for my $j (1,2) { - $config->set('perimeter_extruder', $j); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - ok $gcode =~ /substitution:block$i$j:end/, "two level if / else / endif - block$i$j returned"; + GIVEN("sequential print with between_objects_gcode") { + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "complete_objects", 1 }, + { "between_objects_gcode", "_MY_CUSTOM_GCODE_" } + }); + std::string gcode = Slic3r::Test::slice( + // 3x 20mm box + { Slic3r::Test::TestMesh::cube_20x20x20, Slic3r::Test::TestMesh::cube_20x20x20, Slic3r::Test::TestMesh::cube_20x20x20 }, + config); + THEN("between_objects_gcode is applied correctly") { + const boost::regex expression("^_MY_CUSTOM_GCODE_"); + const std::ptrdiff_t match_count = + std::distance(boost::sregex_iterator(gcode.begin(), gcode.end(), expression), boost::sregex_iterator()); + REQUIRE(match_count == 2); } } } - -{ - my $config = Slic3r::Config->new; - $config->set('start_gcode', - ';substitution:{if notes=="MK2"}MK2{elsif notes=="MK3"}MK3{else}MK1{endif}:end'); - for my $printer_name ("MK2", "MK3", "MK1") { - $config->set('notes', $printer_name); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $gcode = Slic3r::Test::gcode($print); - ok $gcode =~ /substitution:$printer_name:end/, "printer name $printer_name matched"; - } -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('complete_objects', 1); - $config->set('between_objects_gcode', '_MY_CUSTOM_GCODE_'); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 3); - my $gcode = Slic3r::Test::gcode($print); - is scalar(() = $gcode =~ /^_MY_CUSTOM_GCODE_/gm), 2, 'between_objects_gcode is applied correctly'; -} - -#endif \ No newline at end of file diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp index a52583cfca..6d87560579 100644 --- a/tests/fff_print/test_data.cpp +++ b/tests/fff_print/test_data.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include using namespace std; @@ -228,6 +229,7 @@ void init_print(std::vector &&meshes, Slic3r::Print &print, Slic3r object->add_instance(); } arrange_objects(model, InfiniteBed{}, ArrangeParams{ scaled(min_object_distance(config))}); + model.center_instances_around_point({100, 100}); for (ModelObject *mo : model.objects) { mo->ensure_on_bed(); print.auto_assign_extruders(mo); @@ -352,6 +354,17 @@ std::string slice(std::initializer_list meshes, std::initializer_l return gcode(print); } +bool contains(const std::string &data, const std::string &pattern) +{ + return data.find(pattern) != data.npos; +} + +bool contains_regex(const std::string &data, const std::string &pattern) +{ + boost::regex re(pattern); + return boost::regex_match(data, re); +} + } } // namespace Slic3r::Test #include diff --git a/tests/fff_print/test_data.hpp b/tests/fff_print/test_data.hpp index b699e5e4e6..fd110caf1b 100644 --- a/tests/fff_print/test_data.hpp +++ b/tests/fff_print/test_data.hpp @@ -81,6 +81,9 @@ std::string slice(std::initializer_list meshes, const DynamicPrint std::string slice(std::initializer_list meshes, std::initializer_list config_items, bool comments = false); std::string slice(std::initializer_list meshes, std::initializer_list config_items, bool comments = false); +bool contains(const std::string &data, const std::string &pattern); +bool contains_regex(const std::string &data, const std::string &pattern); + } } // namespace Slic3r::Test diff --git a/tests/fff_print/test_print.cpp b/tests/fff_print/test_print.cpp index a139e4c2be..395f758410 100644 --- a/tests/fff_print/test_print.cpp +++ b/tests/fff_print/test_print.cpp @@ -126,3 +126,62 @@ SCENARIO("Print: Brim generation", "[Print]") { } } } + +SCENARIO("Ported from Perl", "[Print]") { + GIVEN("20mm cube") { + WHEN("Print center is set to 100x100 (test framework default)") { + auto config = Slic3r::DynamicPrintConfig::full_print_config(); + std::string gcode = Slic3r::Test::slice({ TestMesh::cube_20x20x20 }, config); + GCodeReader parser; + Points extrusion_points; + parser.parse_buffer(gcode, [&extrusion_points](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) + { + if (line.cmd_is("G1") && line.extruding(self) && line.dist_XY(self) > 0) + extrusion_points.emplace_back(line.new_XY_scaled(self)); + }); + Vec2d center = unscaled(BoundingBox(extrusion_points).center()); + THEN("print is centered around print_center") { + REQUIRE(is_approx(center.x(), 100.)); + REQUIRE(is_approx(center.y(), 100.)); + } + } + } + GIVEN("Model with multiple objects") { + auto config = Slic3r::DynamicPrintConfig::full_print_config_with({ + { "nozzle_diameter", { 0.4, 0.4, 0.4, 0.4 } } + }); + Print print; + Model model; + Slic3r::Test::init_print({ TestMesh::cube_20x20x20 }, print, model, config); + + // User sets a per-region option, also testing a deep copy of Model. + Model model2(model); + model2.objects.front()->config.set_deserialize_strict("fill_density", "100%"); + WHEN("fill_density overridden") { + print.apply(model2, config); + THEN("region config inherits model object config") { + REQUIRE(print.get_print_region(0).config().fill_density == 100); + } + } + + model2.objects.front()->config.erase("fill_density"); + WHEN("fill_density resetted") { + print.apply(model2, config); + THEN("region config is resetted") { + REQUIRE(print.get_print_region(0).config().fill_density == 20); + } + } + + WHEN("extruder is assigned") { + model2.objects.front()->config.set("extruder", 3); + model2.objects.front()->config.set("perimeter_extruder", 2); + print.apply(model2, config); + THEN("extruder setting is correctly expanded") { + REQUIRE(print.get_print_region(0).config().infill_extruder == 3); + } + THEN("extruder setting does not override explicitely specified extruders") { + REQUIRE(print.get_print_region(0).config().perimeter_extruder == 2); + } + } + } +} diff --git a/tests/fff_print/test_skirt_brim.cpp b/tests/fff_print/test_skirt_brim.cpp index 8f508f3233..655517220a 100644 --- a/tests/fff_print/test_skirt_brim.cpp +++ b/tests/fff_print/test_skirt_brim.cpp @@ -38,6 +38,7 @@ TEST_CASE("Skirt height is honored", "[Skirt]") { { "support_material_speed", 99 }, // avoid altering speeds unexpectedly { "cooling", false }, + // avoid altering speeds unexpectedly { "first_layer_speed", "100%" } }); diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index 97cbdafe32..6b6f6e9be2 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -60,8 +60,6 @@ size_t object_count() %code%{ RETVAL = THIS->objects().size(); %}; - PrintRegionPtrs* regions() - %code%{ RETVAL = const_cast(&THIS->print_regions_mutable()); %}; void auto_assign_extruders(ModelObject* model_object); std::string output_filepath(std::string path = "") From 436a454b2e5dc823c6a878b836f82f56922e8834 Mon Sep 17 00:00:00 2001 From: KARBOWSKI Piotr Date: Mon, 9 May 2022 10:35:50 +0200 Subject: [PATCH 15/25] Fix building with new Boost 1.79.0. Fixes #8302 --- src/slic3r/GUI/DesktopIntegrationDialog.cpp | 3 ++- src/slic3r/GUI/GUI_App.cpp | 1 + src/slic3r/Utils/AppUpdater.cpp | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/DesktopIntegrationDialog.cpp b/src/slic3r/GUI/DesktopIntegrationDialog.cpp index 81c681bc3a..7f99a505c6 100644 --- a/src/slic3r/GUI/DesktopIntegrationDialog.cpp +++ b/src/slic3r/GUI/DesktopIntegrationDialog.cpp @@ -10,6 +10,7 @@ #include "libslic3r/Platform.hpp" #include "libslic3r/Config.hpp" +#include #include #include #include @@ -503,4 +504,4 @@ DesktopIntegrationDialog::~DesktopIntegrationDialog() } // namespace GUI } // namespace Slic3r -#endif // __linux__ \ No newline at end of file +#endif // __linux__ diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 8533854f4d..4435f836b3 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/src/slic3r/Utils/AppUpdater.cpp b/src/slic3r/Utils/AppUpdater.cpp index 60739ccb39..80f31f69f7 100644 --- a/src/slic3r/Utils/AppUpdater.cpp +++ b/src/slic3r/Utils/AppUpdater.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -242,7 +243,7 @@ boost::filesystem::path AppUpdater::priv::download_file(const DownloadAppData& d tmp_path += format(".%1%%2%", get_current_pid(), ".download"); try { - boost::filesystem::fstream file(tmp_path, std::ios::out | std::ios::binary | std::ios::trunc); + boost::nowide::fstream file(tmp_path, std::ios::out | std::ios::binary | std::ios::trunc); file.write(body.c_str(), body.size()); file.close(); boost::filesystem::rename(tmp_path, dest_path); From effad3a6f8a176ac7c45f6e0abc38a3524ad011b Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Mon, 9 May 2022 17:02:55 +0200 Subject: [PATCH 16/25] fix initialization type --- tests/libslic3r/test_mutable_priority_queue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libslic3r/test_mutable_priority_queue.cpp b/tests/libslic3r/test_mutable_priority_queue.cpp index 3e99eef08a..78c97bc7e1 100644 --- a/tests/libslic3r/test_mutable_priority_queue.cpp +++ b/tests/libslic3r/test_mutable_priority_queue.cpp @@ -356,7 +356,7 @@ TEST_CASE("Mutable priority queue - first pop", "[MutableSkipHeapPriorityQueue]" [](MyValue &l, MyValue &r) { return l.val < r.val; }); q.reserve(count); for (size_t id = 0; id < count; id++) { - MyValue mv{ id, rand()}; + MyValue mv{ id, rand() / 100.f }; q.push(mv); } MyValue it = q.top(); // copy From 0869f491245827857ce2bcc85a2648ceda0fcb00 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 9 May 2022 17:04:10 +0200 Subject: [PATCH 17/25] Localization: Update for list.txt --- resources/localization/list.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/resources/localization/list.txt b/resources/localization/list.txt index d68f99bff8..bc8c9f2727 100644 --- a/resources/localization/list.txt +++ b/resources/localization/list.txt @@ -17,15 +17,20 @@ src/slic3r/GUI/GalleryDialog.cpp src/slic3r/GUI/GCodeViewer.cpp src/slic3r/GUI/GLCanvas3D.cpp src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +src/slic3r/GUI/Gizmos/GLGizmoCut.hpp src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp src/slic3r/GUI/Gizmos/GLGizmoMove.cpp src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp src/slic3r/GUI/Gizmos/GLGizmoScale.cpp src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp src/slic3r/GUI/Gizmos/GLGizmosManager.cpp src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp From 6be84d529d740c44c1e9bf533e70e167b3442063 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 10 May 2022 08:40:49 +0200 Subject: [PATCH 18/25] #8202 - Fixed detection of layers in vase mode --- src/libslic3r/GCode/GCodeProcessor.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 92e0a698e3..1611b23254 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1991,14 +1991,15 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers if (comment == reserved_tag(ETags::Layer_Change)) { ++m_layer_id; if (m_spiral_vase_active) { - if (m_result.moves.empty()) - m_result.spiral_vase_layers.push_back({ m_first_layer_height, { 0, 0 } }); + if (m_result.moves.empty() || m_result.spiral_vase_layers.empty()) + // add a placeholder for layer height. the actual value will be set inside process_G1() method + m_result.spiral_vase_layers.push_back({ FLT_MAX, { 0, 0 } }); else { const size_t move_id = m_result.moves.size() - 1; - if (!m_result.spiral_vase_layers.empty() && m_end_position[Z] == m_result.spiral_vase_layers.back().first) + if (!m_result.spiral_vase_layers.empty()) m_result.spiral_vase_layers.back().second.second = move_id; - else - m_result.spiral_vase_layers.push_back({ static_cast(m_end_position[Z]), { move_id, move_id } }); + // add a placeholder for layer height. the actual value will be set inside process_G1() method + m_result.spiral_vase_layers.push_back({ FLT_MAX, { move_id, move_id } }); } } return; @@ -2828,8 +2829,13 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]); } - if (m_spiral_vase_active && !m_result.spiral_vase_layers.empty() && !m_result.moves.empty()) - m_result.spiral_vase_layers.back().second.second = m_result.moves.size() - 1; + if (m_spiral_vase_active && !m_result.spiral_vase_layers.empty()) { + if (m_result.spiral_vase_layers.back().first == FLT_MAX && delta_pos[Z] > 0.0) + // replace layer height placeholder with correct value + m_result.spiral_vase_layers.back().first = static_cast(m_end_position[Z]); + if (!m_result.moves.empty()) + m_result.spiral_vase_layers.back().second.second = m_result.moves.size() - 1; + } // store move #if ENABLE_PROCESS_G2_G3_LINES From 8c133c01ee21258a701897ef71c1faccb4db4793 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 10 May 2022 09:07:12 +0200 Subject: [PATCH 19/25] Follow-up of 436a454b2e5dc823c6a878b836f82f56922e8834 - Fixed syntax error --- src/slic3r/Utils/AppUpdater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/Utils/AppUpdater.cpp b/src/slic3r/Utils/AppUpdater.cpp index 80f31f69f7..27f2e34bc8 100644 --- a/src/slic3r/Utils/AppUpdater.cpp +++ b/src/slic3r/Utils/AppUpdater.cpp @@ -243,7 +243,7 @@ boost::filesystem::path AppUpdater::priv::download_file(const DownloadAppData& d tmp_path += format(".%1%%2%", get_current_pid(), ".download"); try { - boost::nowide::fstream file(tmp_path, std::ios::out | std::ios::binary | std::ios::trunc); + boost::nowide::fstream file(tmp_path.string(), std::ios::out | std::ios::binary | std::ios::trunc); file.write(body.c_str(), body.size()); file.close(); boost::filesystem::rename(tmp_path, dest_path); From d7857e75bc69f9adb9581cd8aaefa850e7bd8409 Mon Sep 17 00:00:00 2001 From: rtyr <36745189+rtyr@users.noreply.github.com> Date: Tue, 10 May 2022 13:18:44 +0200 Subject: [PATCH 20/25] Updated Voron v1 thumbnails. --- .../Voron_v1_250_afterburner_thumbnail.png | Bin 64932 -> 39990 bytes .../Voron_v1_300_afterburner_thumbnail.png | Bin 64932 -> 39990 bytes .../Voron_v1_350_afterburner_thumbnail.png | Bin 64932 -> 39990 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/profiles/Voron/Voron_v1_250_afterburner_thumbnail.png b/resources/profiles/Voron/Voron_v1_250_afterburner_thumbnail.png index 07c3202cac80a383e4a6539a0763325ab43258b3..2b933909755680716b75387e46af97b002f5a763 100644 GIT binary patch literal 39990 zcmd2?Wm}Y8+Z}MgA*F<&8$r4|hVGJb zi#Bx}&MoTyZEjcn2>w9^dJW*=5>>8AyAh^6#=?SLwCi0rGXsAqUEWr6r0*7m=VMg`ln#Fh&((% zNx77+(~Hyf)9#nA^QRjh)Lfmibh_||VdsKqEGH!nd&9mS#5(+8FC+(PZD#-g1^d5m zI6!7L7yuvx$cRJKJeH5UtjleeTxo7&dG~d!d+wI@9SvNM^r*+^cBNT|2gM6^4D4DV zX=ZOoZ+EiBw5uz)s;^| zcb&IFPxboFQ;DQk^$Y73dEV32PVOsf-neC_o~I)^CULyO+}#&wh8-=||G%Fj;RA^k zx$`@J--ii<(z|u<_*?-`coS5==Mn#GH+OeBg)jeH_(Va0U0s3=m7k5x=XAd0?!O33zdd~ry5H;(6cA`K(-xJbD^4*q z*RoD5rF(o4IypH}czSt#bMW$d^nZRmd+S~zxONkCW@Y!i%GxM?|A8c;v5}pZBwk%R zjbhqaeK)k~pR84NNj(kYr6{yrajAh#vP``M+dK=N%$l({MHECAL6)k@CX<8{BTn}R zSGB1)MbG3{ygW_v+vVgrb7X(tahxjHQsP`-&P0ruhR>gKifny)%X zOaWZ%DE`DUvUDkGSU|cEWzh(6_0ZJR6!+I^sPIEQ z=~I2J@1dN5*EMMsMA++E+UIFy16TOI@5AoH!%qPoo*9G3x%5i^FU+T~f|Bd;d|%JQ z$EP|nGBRddKiUMfQo+etvPrY7<{!?`P*?8~nEnb~4s34GTyWh0vy&A<^cKWS(?v>(yrfLk3KAABL?)y6Q0(W_g|?T;`d3}pM5=Q&iMgkAptm3`Jp(%;)W|guN z<5xryDl^9Q`5X#8x0J${lyCFawOw5G&?pWCY&tXJn6VgETZ-|j=A1%W9i1a`b_;cN zv{+U_^L4tY!m{S|Rw#OeWxPmHWle~%)0mE&IFPP{T{O&)1&KUFHL9wa|ZddF-2tA*RrI_Kz zGg~wA<)EjiD$5$NfEU-+*7#(wz_#0o2VL;hdJa14??rdQfdLu#LBPN??n+OwLg&Ii zSwAoNl~^On@W-WC&wmI^&7(dxoEhBmaliP@^Vc#@xb2v5DuwTv$dbbaQB&lU9vWL% z?B_MFoV?lAYpwG0@OWHi^*m%<^|&LxJWTuNhG1+cChfw4>Hsq?E{-KfQDuSiQa~z+ z%H!o`p}wOdnnQuS1PB0|XfUlm4z(YLRU4e|Z2;{btFn6he1vNuZ?^bXS3*!J)`LAx z?R60yG;M;d$mZLM+6vFf%q2zF(Rug($fl-AG zxECj4c>JbN&EE>gsO67H_J775|Ham&OIh3vkc#r{ zhnO7`V?sqm`Pd5CX&YB=^zows2@lDoW*6+ISmUH;s&o3vK zcm8M^NVKj<=qflY>aEGwELU z7JM}QQC{+%sOr0o?d7%7Rq2oQ$u2JV;ISY^Lx_^#W3BOwKVjMEJZe@1nY6$>IR<8N z5(br1#cr2knRAlaQXbaqS-ROnpz8SR>DepOTMnD0^~qW*Y?-&PWwC%!&zG%hw>CEc z!F>P#OWt(fuQvZTAy~a|c)GPcK07mLQ_ezdumYreUds)jqW9fidNf;~ZGI-n)QGWg zrkUlKo4~40y^{n6kdu>bqaak7X`!(Aa@c#PieG#7f1ePA+;#me^;zDLI#cNH3sp^1 z9jBORIFq4!t4O)b`y}Jk-qX`_Kd#wb_?AO(t@QF+DUo$=i~p?CdFOPkgNy<-T&(kQ zoPKd*L#k)NowboOL3R7!0Hl;F0QvE!e|?=qry3enrrXmCUADx@LfvUNHlDKPDLcdD12m$x$eH9` z>3R$@KqMp?V8YcDxtGNqBTKcHicG(^YzJ}@OMY=ktp37_E@+FyB6vTY%rc&cgWEu$ z5396C5nmdGpBhbLJg;HRcjwW8XRz6N!NJ2LqNs?{XB#`O*N{a- zZ{fg&k5wB-luY4^fX_X~2U4LyLzZ4k4$(9-R-@J3kGb6BSmM$m(jfqB!%d;8X3%CT z0)Oqvj?GrQ@&qb9!B&)6v1(tCQ7_XH&}VeUBl~_89vNthh6*kWX3 zRVdQ&N3sx$;SwQ+waxR2rhSd+biFJ3>F#W2x!L-_tz(woe|6|rfCHXtK(;rcs#=|vMxk~*n_wmNGqaT$zD54jK@b~!^h07Itt zmFxD{s=ra)bMa=85Z4af3}YZFI2Sm2;df~tytRYA^&Jbm@S%5CX*7hpAW5hMMA%`^ z+5+;jCe00agoK11h76vEgb#1LdbsnZH!RHO4_%DWiq`C4Wm85r^1?&+^yEan=k=(^ zE^k82|03Fes`_T9=RUfp?KV=$2Y#VOFWP>4cNYlDjlL}VZln^mT~t^H*?hb?lAgzr zrBhQ6g`uI%vE)zSSVXH2e}A*a>BPH*dsODEnerU64{}*ZR~;poHTG^qVR1s!z%Kc{W2NojqS-V!pvvtAjoScHn&;J#Y zQ)xM@&c}a0!06#^-gitS0v-W`+;;hYzS#;;)E*aP;YGvMg&LxCI9+A$?}GK~dJ>4x zSOhQ{*-eo%>aQlI&Le$!$e%ar`Oyp$IXYE+Y+5ijGdhEoKGp8FQdEP>I}qK9{Fi(@ zxrVBm_R@nin;ibUPHu_Je|@4tXH13=##UAtH3inkVGQAMB_s6KLGx>@?PuU+scVEV z)+t$2l7vPQlvN?0kt%SoN)o8(<~SshiW~lX8*5`5#=42^EkVo*+_ zMhu4QetS9F8TcSPI5mZ?@A>!RYNsRiXO&q(7%=xa?|V->!4^iQI-a_FJ}$+=u8JjH z96%9-psbBXtc-lLK8e+Mi)b4>;-J5>wJ@>E0^W-9#0(y#&W8uK9E%Z#ojbBW+4c{z zawMv@^%w=9v4jSq??FYFb+Ou)^0|$CaL#2dIA32POTx|j*%Zt%=+Za2k~GaF)68J! zLZ6%S9Lh5MqNrz`Viww7sr*N7IT(fX8_URdx?fK0ca+|)l`g97eNjAfM+O^^s6rN0)IYBKTuqJ%KZn1a z|7f*adpz^|tLbOIDrmDsoMv7JVwI9WYG4%_HSWF!qR`o-6{0`TSaKm!2KoqL)RXf6ev*R$6u>r#A*!`?X>Nw9R3XXQj(m8 z@*{$FXu0bN+W0_qopegS|4aNEtKasgSCnFzs3GIPN;aV?7lC7eJTYsF=jAq{5uNBl z+EsjGwDCewZH*b7osNwcrtXJH`)$}ijn`jZ$GUc<2CI&+$K!9R=JD(6tDM2hKTT3y z0;dqOm@NzSh7A0^U=;H6^DQy32@IJxl=1lZ zSeLgHRR(c|M%9QMVwvb-g@JhGo-OCSStu|OYfchJ~;hS0=N^!+CD8M7p{wsUtW!jvWqDeVC6YTD*nM+xcY z9l4ty5>V(u9CEK_i$-Xp=EC`*gdZWYL8?e8s$>*YGC}&a;b%Vk{5<^pp*YB{Cp?R; zdQu_ynp8O(djYbZPVZA@B9WNl5)vU>LDX8Uw`Z4CzehC0r=qrLA= zA#|Zf3$-IL-fLgE?V|~F0}dMB8wqDOE-riaOW$q4O6`eT-H1* zf|-EbEsY6dBZyF!#WJ=$+!vs>;5!eIvUy0yT4a5f8H%-y{Cy^(tCv^Q{Cx6XtKqop zJ>!4MBJ5~3E0R9T4G3TLWdyi2C*`eF?p^UVFbsSWevonL(4&f6dDt=rQc(#QcsvVC z6BmjCSP#sGSRNrP{IWmL^k>B^;aX6J37NmmKh?hx>>kH6#x!5J8~e_N zQx;HxJ2@I}jAHIsSn>nP2Nk5rAhB58I}9C1b*nDWhHzm`PqnSHrJaKyptP#I#*YS3 zZ5)>2Vbghhf~QII9Xd=!ib4!yK!ARvnb?Tj{lXIbkir5(5uphoYkMekS)Jrv@u9s@ z0D6`rks=lyH4HyQfL!%zar^|}oj8LvWK#iCv8+$&iLS*dFd$+6-2UfV!OF?@`8mcg zxbu2W&f{_yX=-{JHu%7Hpt3SZ6}h(Ol@G=lIC^-rUH4i~H)=7ke3w^N|5#ZG4?1x5 zPEhRycWvGOJs4Z$qZ%YYJBsHdyksOj3Nxi8;NV1CZsyW9(R)e;<=#_l_g)|}c9q%^ z2w=qPrb?r}7bA_jpBWAp5Vsthh7uOU*3Pbp`}2vv(;*N*+TX6`WR+!ICO(<6g!0mr z_93Dowuk&(tT`ny`Gp|wgPm$bN&V+ahbiGFK}y7V>*TbUeK7__5YprwM&}(nTKoK= zTJ(@{Ve|UNU@nRQeaUuoimGJp_0w4oY3$?mHHVjlxn$XVAMC9EgHjiZ>X2qAo?;-) z2%o^K1CI->?2Z-!01I9f)JBuKH)PwyS)GpLle7~v)5=}{L5*R17;x3#7^tDb(IUqr zy_*q2NE}RfM+DVTh9ppEKjdKS)THMxaK~{W%2vwBXej{A9(a}0KEg((f9?8gMvXzWo6JXXG&nau+CY&} zE}OqPvvx-EHsMbc(eY?xU} zALf9s(Bio&9NX9(=U98Sw$NqUn<_RSa-X28e-G+>y2&YBKYDM`6FrCBRTU*aYa1 z&$S)M5cC;B{6%B@b5-QCuFX=fch<3W+#f^t#7gx0SAI^0wIFAJ`!F`a~;&|=#z!X@hK_Fh5Vglg+@NRg)aMdPG8j;+I*^MoKlZf6rKi zrhsffTe*ytZkbh$uq4aBo3yHENiYe$>3-tp&jKq-7+OifWY3)2b-ZbRu;GJ4P0BFK z0+PzFh#KdSU?{zT3c|~*^5;+L=tKI8z&TrS3i?MKG0F%Kx7}(lp?xQ2@`HKg1KYKc z;7^nTcy=+mP)!5hk1|RB;i~$&IRTZ0fzTi4TilLK+>1GX(LS`y=6|hDqba0FQO=r! zBMr?bWy)pU3&P_b9?anNNOO=EV#HkPTv@Q^6HeWDYKpt~JB0d;6;~X~suITTT{Z+5 zM(h0%ofyt6Vm`OT0Do6gRt;FpZ|Lok2*ko|tz8@R{MoA_B(-d7@<}d{_U2dCb5nBt znq3jY#3IFlKuwlDqsL0w(2f#&?`C%Y{>ICxJMnPmu0 zm7#Z5j_zJDm4?UYlA~N0eVJ#~W7_LY7qCWa!}Ya*G~{UU=%#S?qbFP{t*N%#;mzW2 zLkzB9C_(fPMR(1TO;`g1WH;hD@ZDSe&$HKutWeyyM)!`jQ-5a zRG5?`3M{tQ90kDXhkm>hSoi9hZL+%GD*f&1OJ2I}qAE>ia@$3>hn#EmQod?Bn#DI+ z-8_0lBrCh?8K|R~@zJ>xCSu$Z7Aw#2Ir8=c?v5=Y2(i6H!oEv*eFI zQR)j0g7)j3Ka)Z@F_U3`$nzR>|!+h(15uRE1pa3=Y| zmwtvEDw!Ky#Fqi#=Yh2EM?GkQ5qr^>vI0tH@>WFb3JjOp{@79PCrw4IiND6yV8t7N z96{yQu}e0A4>oZy=-JmRN*h=&IAYLsMQn;(H#5^LX%zWzWm-Vjr!10yok)#-_E0*4l_OJVa6 zFd*Wv)@1VO>FNHuOgL7t>>WkF4OjF6y$c~LJ54guy8oN+e}iQm)L4K7RtDTU(5i1_ zoi=R3TA;=}L=-Yf``aD%hFyQc z^ zu8*~=A#<5hm&WxGLlp`cCq6$gS}>V zH)s7Kfc~$6WyXJT%i;bR(KgnW!(#>kAcP^-KYP=3-?C;W#XNK9!W3(iHJrQ88^c=v zlZ%Qkt3RB^v1DvP{{wv{>#al-rEN%7zjL@L56`eqL{i zp%b7+#ThyY5odw+W>U|yfUT47R_t0${x;J_d5}VtzPqAFLJ2%`DHXoNNK%5xDUwuh zBs#mH?K7XLEXbJ*${bo&PPEYdPns9%T3hd0lk7vm?J{V3$!;*IWJI79l1xSzqfK4e z2cDy8$a$BnUccgNeg;1QKM>N)b7L+Alse-s%T;7apd!9u~Bt`{eCb+b*6FbEwApb-uz$2Wx_gQ!uRcG%^-b@;NWI{d(Ti zPK+s(powy9a$iAW;_1{T<;o&H8JBe{6EM{rDFG|Z&$ED)kljV*rlmh9ft{ZYz z|DXxd*HTlrSN?SssM?7=PZ|ZnhiE0;W!099@oucFh;^*Rk@tmKOG7$7fZEOBzI>4V zqOLA+aAHMXLIy`8Rgo%GF|EVs(oP)XMtlcMxBRG|dUe&5U?TYQ=5D6@VwiBRXmEzT z+Lft9z8T88hkOZ~Bz|ckZuRTq!c@vM2*)MIny?GMp%A-**H>HFrud&1AWR#P8EWP-cv}k5pUaFF6wq>F)$b?G~7~B+WrM}&*FCqm;fKmsE2XQx|OUj_A0{VZ~mwa}! zdCC=~17%)^&Qpbe&bptNVpu(3vJ`R{(Q=(A)d0jGWJ{-~P!gm84(v1Hc;J#d1c`WY z8S^^_Wk0=t4?c+{dj7}fuGulm>}ZvOAB7D>h(D^Xa3l zS+A0YL-GX^feO=I9TZ~_bTp(NMH{h!6Wtcg+FBaWMb(%4ZAa%vD1%B(GcszC>#;8? zG3zfJVT1VnG5d8GnLe_+JOqs$Rza@sD%vi!LS`{uwNJ-PlyX1?DFWGh1Dk7#G~E>h z;*{1-+oB3kNb!yB@lG^Wye~y?zH)Wfd~%;S@@Cz#Cb;Dra(&^`vd;6u(Y2e=Zo!~J zwq}&(Yw#$W55rJ&7{uI2{#b;*>9dK=;W*#x-c7~S{(FL-HwdvrnT*R(bzp}>Eb@o( zWY*{OtZuvWhiqk8iUf@OkOf)_6u8(md2+eO#b#iUwKTjcT_SR%8wEMz<{%yjcbSq3 zhqDwRJKrOTT3<7aJoJl$Q)CHtIsPfCkG*MreB`1Up>`GdF%tR!+c!P2g<lxL={AgP5a~u>m;QU$%=THqFqWS&-PY*5>|5KXZ$l>Uz3ZSn>NG8<&72g} zSg0nP#s-wkoDc%mTPb!+y1&_dLk;+|g*9@Y)F=W9M-!o!S{l5Ak1JG~fYg47`FK?54E5t~=B&hvv zUxcZ!8xnr zgqvwc9M#0KO>S~ZOiy%}1Bua+IA_JWs{iEpr^UhI;Xy!$4WaGtmUis=Gf>ChYsw{| zGMQr@;Yi?tlNtjON2UrGw*(+!A-_vBEJZM{2q5RF_~M3TT=R9!I&xO^)quqqB85S) zfDyn+=Je>5q&vVQaYI|C#~1>b`)yAW#>MH@;oEsLrXupmof6 z|4yR=>k*~Z-iYlx#WYF?3EJ7;w=dN!fD+iAzIT% z?+5YeV{^sifMdHI?Xi@&eKHXx;@~lyE)A5z6^K5wp;K9=IF$1v2oH}};R9rSbZt)t zl)y`E6feV*(*V}V)~>oOT9C$F%EN}@Bb z_Fk9(5jFtVzDAP704c|E6>2r2aWJ0%KF1X!} zW;Wu>Avf5aCFdQYMzO92%=D=iTz*4b`_?RLB5ziGBj|wtd79I*RcCQ!ZD45$IDAkx z&aEeKq*t4loZglFqjUWhJHQQ-Up(_{M9k(_-7!v@w6ru!2wr$3qnfD47I>#0$dFY! z3PHyh_A2cDB8HV_7@>?!$%)$l^^7Ij-% z6WMnW2EbQHqDVZPzzsNyf^~uQ}`mG?f zWHvN>gohOoH}TtoZOKAKGHIk!Q1BVPs+l3^K^0%MkWH)8=1FI9 zbqM2cF}~S4xZDHHs`cE+Mh6-wocN;(6aG_<6sJErp&|ya>U<4-6)JN}Df}e|a-yDo zc@Yd(V0Kb-{c9|7ros(z6Bp65`n8V&F7m~)s#jyxA<#1n_}PQ)C@d+6i~dg>%_)|$ zpbZ1^8^aV5TP&IYKtlII4A7(Cu=8Pj*I)4xemVb#XL>4=&Q^PQF=ES&(zkkXh zLh(l|hhxygi{A%XS+GeW9>S$@U?Hsv5}6!(ITa+y)Uajr3SN@%mpOaWa&-o!m2G~C zr3U>^ZQkxA$lcRRQp7)LyD=2l@dSY84}VjV(=DIi&Z$Z0X5!OEVWkTeaK;&QULVNO z(s{XSfxl29nVD=L&}0-+2*V{9({a*o8cUPw#?XN^maIt?C}&hByi72ILIMp^vD1Yq zZ8>B835qDsZArTR_CDLe%gc)_Nag+SJ}qp1a13j%(u!1)bg_1n8-MhrhPs}K4_9Q) zy4;Ry8l@#~k%?a6IQ2849yNv>t2r=X)mxD^MpR=nydmIh-(itoJQ|qZu+UMYe zaTzb9NHPZddW!qQ@q<8$Oj&8`0uC`e>bBnr@a15hCPZgCqY5`C&~U$2KBCdLX3Dd# z?3{I3ZLmfp#P|y3)=7|@(B@s&`CY>Og9}<#KK)ZW$C?1is z)~rS*{3k$#*@-BZ)SGD4)*lO*ty~{F`xgOc;Tu`<2%5DF(YFui%MX9ekJf<2qq2O28V6KOqXs4)%OqFWa8Vw`A zAAADsTG0X$n{;4uDwIv9nyXluhnM$qyztolduR&s%PYpGPb2ie94%@#f&ht1K54<3 zBb&BFrUVStAPMC$Jj@Onx_sBzWvy}z6j7Nnl5c3mTL-BO?5Mg#7NK8q zxrYmxI4YNYQ<@`_>%cMCP#!M6FkS|LG<=iWNQL7v$y~B~lR1u#SV<(dMU#k>xn(n- zbZl1Wwh@Vn#NiD)nt)^kD z`;mtk8Rr2y(B_GSZA+eT zCsD(R;o9gPP?3qK{xlIV6cGgsTb!zrTQ{$EUN?wJ#xPhzJ|h(1R3(%@KjT@W{%a3v zW-@9Kl9_`k9f<1M5^zqRLXRe{RAzp^)HDkbT{-9^2w{un|2dU{le>GRResSGMHWe_ zJ;$0kZJL?l1D~7~{joD@^CwQe;DwPhEWBQ*DtiaTA=X_?Zt^Jeo`GY9k}9}7KTv7r zu@=gReZ1PDzm|w_<`wb?N~x&Rx<*#k7?C-sG6mSZkFFF~|APh?z<15v&zQ8xnBF6o z+S#{Q!MvFE*|K0@=KNP=wC{SREHl?0gN3ZvdcpY%Qn z_)wL^n51SUX~X@Y{YNm;NT+Jt)EpWRIP-ClE$WIEym^pmLvbxhf@tWpJb{6p{LsOJv5~1T7);lDoqyekxRv zr=GSz961$hie{fjKtSA{4tT$NxqNcf!u+`BeHn!Lf zTc{hJedh(DNUy2Duqj)g4cDD?Jf(`6b`;@){U)?JON(I-Lli>8)}N&c(&gvrT|Z?S zUO;#7x(4kOb<}yrxg~AqFATA~+mi^j(l6@j2o?k#iyAMUZLQe%#PZ(>1(-|r4a-n2 z;3l_=><v^j=K1+7r&rznvQ`JV-XWGA>GTxlIk3uMt!jJYANAfF6! zFv(UF%g3j2!sH-o;ezq7K4JaE2{w7#P6(kUPQCv9EO=U>g{4_iot*)n+dqK{i1K?T zKYQlSvWoba0*1pknPW#IDftTeSn;3mQYDO^ZMUH~Mg(vJVlKeCh!~+;iI2BV zJ@n!%XWzejB4mGTvT1-BnP8-8WLFv_h)m6?V~q($W+j@@MNx#SA{EP$6~jN61K(+q zf@9rgPh44+HwI>tDYJ=5ML$yWAsN-u&ragBQP2Ls7xs8sx!0#~Y|k(mrfxz&1ue75 zni$IDFC2+Asjl92C8l#~J;ldc&IH*cc-sgOG)5ZE#MAeuI(K&5EZbd2zklvm=97WWOh8FZiyLT&$;Z3 zBprrdmfIn)FISBH{Si54!N29Td=Dcl%=8x<&Vbok62Qb4v`cLjEKuQsh`rau&|J2J z2hlxdlb5(uw&^oJ`s2W}D*YYp@kF#; zfLgY^dMQv9-%WC1<|NkPWH_3Kmv3-vrz62E&@IWx>lWBNs{9G5R6Q`X+OR~t8dOqW z9;xyeIPW36}I8^Fhx?whblNt)rs~4cbOW9Ji*KF+JVD&IE0tBLtsVk-p8Y)#za zEq&6MuGztEKh6Ao8Y8Y`;3XE-r_+v~O8BsbDr$|062jE0_;0UMLBo=@)=e|8e%6R?E!r7gpEU zi~m~ne>?z8oTS5<17=J+!Kev)BQwcHT`qs4wcf2U87O0xBnWfHIdQAmOw~URANhg@r=pq2s#M#;le7Ny# z_2g-JydS+`26PIR7}gwFf4=MX-rP}&C&Zwt}63O-_$rPZmGY& zhic~$;{G7nt+n5vN>Cvp1+H~rh7}1ZevrI>{m}ichNGBjF*A`cHrXfa@__YoOC8jC z74Fv_%5QZ9Ylgim1R!rfpDPk|U@waxAK&9Y`xmJF+M6_q4#*Kvn&W_>+V3Zw9+!Pz`&SmT43-P(-0OR zC1o2gvZn$XDZMl54))I%OvF2_9pftzgD&MlgIiRcmU_m?8&(}HsD2W+he3xbBbrob zJz{f<1& zim!(*?QG2F&(Etn<6W`YIUZ4U13M7-6a5cXKM=ID`I%aq%X>4FKJjEL88MKN`5gZG zD=tgTvi$h%lE~^`c`*}*Da*=$rh)g3e-}(~fJK3Ywp-f%Pnts0uE~vMvpxEd0hzM- z|1PP-%)*>TH+*O@0`6lb$~>0?zciUVU}iT|#94OnVDkR_wITW?xw>B-Y?BurtPlw( zwLq*-MmcM0R#s?aGw$(l!PHUFZ05kyXlfw>C&H|T1%sSF6*3P`1MMX!2SJA|9G?ML zYz0qF4MJ?a<+IeYFDL;npZtnd!446Zp_QrWkU*BkN7R0Nq4yE112mBfvjGMMq?K?0rzttrNYt z@|#hQ9zGfIrH2N8+Nl^QV8PiVX6lr8h~${eh@dfedtCTL8u{TwERenJVo3odVpX&M zl9qi~e73vKFyQLSIc8*sRtW2!Y!ZEM4{>R2Z3yP0i(!R{ez96poa{3YPtG7j@ZwFtL71PN;szTpYnMiI)xaHFnu>T_CdB!y` z2>i6PQh{#VbI2r?3Y8^^@$5- z=txKj1r!SbL0Cy;cNYO*#u8)iDI ztjtEw4v!dy&6ZPB+X)KczEe!)Nr*3P4?ZNRjKP0p+8*fk4U27zN(N)A-e*DEG^Yf7 zK51an-PYG$qqX*byi5ULk&}gnV#SEd_?zh6Fvw7)08+?6NeR1)wq;ky(W($?c#U^v zW@Hixa_&ayskqHGIgqeR=U{`JQaZkzIBQ|bpb&{PP`UW<&*k3%B$yp40eb)yLM(kZ zS`0Yp2(o!(?mIx|Qs2M;@Pm?53KWtVl*Z>mzB+M5lspEMl9GZMoMbwg`?f+Lf-q$h z<`5e5?vDDL8MzebyHBvr3~-M^+_}Hd@;!A=D5R1?`x8`CHqQmH9a}YySO& zVO9`XA5ee*@BVz2h%6d8pnQ$Unmi40aeS2sn+{mT8YiW|1Sj9+5RC(`IQs_@)YvIv zgav9)d81OJ&GEOD?}&}@6Gn39jeT`l2| z30HGn?GHTs`!O}3mW=fGz(He+#bH8kn77WQn8b(ze(U^;dvcEZ?f4@mM62Hr%6I%- zVBO;THrT`Vo7(WupGcQV$s|Ape6jci7YJf$L8qflU{%e;>aq|Q`-R$70^>cghK?8^ znv8jg!{4cFj4M9oPZVlW-P(q(h`bM42B7|Ylk>d^#+cg==dWD^A4sP2t@jJ2X)L-a zhr7aEc|%;k?^ISYMXU+T=U0cOz<1ewC}hyhFk%#8dLYcp-afwmH6g%YQL|D9vErn< zY#CA=zZl^>z-P}=ST-RaMtWxjrRN*Y0NcR?wEsNYP)?d;8K1F)|Gk`INYLQtV--xz&f_+j+H)pG&k)Hk1&VPCD#l!Z0Fw zHI7qV>abIqU{W+r`_)t?>ML_kOsGC!f4|;7A{HUMU&~~V@9Xqo7|I<~itH)=DxTO0 zL>@~vJ8G;M`;%^NO)UnMtu}dV@R0ZT3|5DIB<9G8n=9NFCo0r26?&5ZYBS zB|rVIg?H7`;?;yrIPmS24o)s1Uzt~jEjjuR53NGZf=aL2Yb37{o_)SD*_(+oFL0LgI0HN#9sOQ_~(p*qT5ozCL!UdwVCvxwCW&YQNbWe9`V-A3UTMv7XItwDe8V` z?3nEVI-JMO!OlMM?&hgxkj*}BT)f`V{o_HhZSbZ!hv8Cb1 zE(kbz8GP}_&T#NJAk~Kl4$%P919z8Cv7mxThtct6uqp;z6jg}pFBl%O*;;PS^7wlT z|2EwkcYa%hY}-d-oQxT45U!E;Da@|_C1(q;Abdl!n@n==5dbr$Ect}3tqG!riBVZa zy#&8ICMDYJ;&*3~-$yPBZcdA|e5^@Bg)y$z@uLG-{&{{QjjCtQIq{YG> z(u;tkX~YPP+G$NFe-3QGl~CEdzvqc_L}_>KbBHdCP#<(X?>_94DuQvb24a<;UHGtF z*ffnA6sW)YU(iYa9E5z24cc&$ZQ#Zcep{Zb6OwI$L=pB!bjNH%&nj=&LG=!HPAC1H|aDdtbL z2(%rHd?}?4KH{fydrM}r>zW%f@I4YjC)KEHe`m{hSt&XmV2aqsr^xGx%*3ctOHXGA zS0BL6D=cM;syIEoxX}}qGds%34&Ff!(X2pY)7#d+az|;3Aa4WkS;+;Ht9B7%< zLpvMV`q>ZVz6hN~QXp|@oLj`9v7yO4VyG{4VDF);m>tJz(gC&@^CG2fT2{T5j`Kj= zDyHyJd6%U)4$Q52q38}_MuA!0Nc!Fd;XW!wHH-ixa=jHHnO=v#+wSI7=XdZ*iC!TEEwoj{0wicJQ#nsxL z|NY{*u5 zUMVVKQ%T5m?oOCgR4Ep3X^qd6ElyLlzp=s$ zX1$Uo*bYE6W&=f9ev|i`KYbGdQ>@l)s`MM_J`%1g>Z1|Gpwj!jXSDy_kHZ$xM~3?z zlkB6P$L?D*{hT05z{j&jO<*v1DL_CSXq@Tx$N9b6Y%yCW4JPD>0Q60;-_3e@0gZdt z<)y-!$O@o9a{owo=mOoiU!I$M$G3$=xj3zYl%(OB1$8Iw6hn5fN#6BIjxGzGJAY)> z`Ks=w@3igv=55_8TGeiN#=0RViP^Nfv5|c@AV*EP$d(y>azWf$HnY9=g$&Hm~0UWdqCZvI$18mimbn z7dhtjv<4T?>qH;ZD=Ib+d6H0m_?u-+Tb*rrrfv|2$Qa0g=oHLVH#}X&c;)9trkzlX z1n_a>ktWUQZ>#^JtTnc~y|{vwn9vERDU9Rqm_Drc`=MX;rx1tAEn7Mq%PpM|v~ED7 zNYYTxdlVYiJfm`qdJ9Hs%!EPSRtFn4eb;=d(@8e-gSY5|x7fC=8(d;aIOZ7p()Z^2 z6q$MSXc+MIh^c(AKPdXGLT?W0Z7+;BZN&KdC*|hac%5m^aLV?|_lFtEwK!wl-63L; zuX&WH-yD3|XOm#<6L9|@mDWVn19nMkft?h8=*o@NP- zHHNstQeMQA{hduq8k_(I*?+V{pmO>r>Gzq;Wl}dEHTWbirt6UW?nf0^OZlS=oFSe7 zpRAR&6=?!D#MZ!fhzAM#3ZmVedFI$#W7L65!hA@y9u0}Y)U|Z$4u!Ll-9oW48Iob8 zqo=3mqtE^gzRSHKSQ73H$@4rYh#_~s3Hn_iwGy=E&-PVtC%|e#A|M2iHRx<^4g+9f z^h$evW)S4&+D{Eq{QrKr<;3&*w?-^p7#(4xM%j5;8AANHH#v6s6>LL4CeAEUH8{ugtB2Rk^?$V-K z-z&$JWNmygI$~jKH9!=cz-T3r<_m?-M9wnIk$v0er1I5~4wrSqF5;sTs&8np3<{#$ zaTO%b=+=qh!r&EmCqEL%a>41n{hXq0X)Z=)*Cnhg)!5L0q|DOM)&>@)ClqdH7xiIk zgojmVO+=4q<$ECK!KW-Q(2e+lYKgYm##w*D=CMNM-0~aTNmBe z0;kW!y}^8uwsDb$1snoRa4w-X{uof<9RnZdX1K!aOH4Jf2)Gm5i>|*A7<6QOX9m-{ zy1dcqrIY5Cp6HnwObnzqlf{<#+IWVov>gUvLzyj&eLc{v@}*V`>ZMnu2^OFrLdTep zJ))`U(^0Zb?UC)j?e!$~RgNodg=Ylw#3*FcSztMwtZQ%m+~?u`=O09h6N$d*_g^RM z_Oy{-kFDJ1Fi`4lJMgzfWbH0skiL_7h(%{7*)+Z%Bp8a`$Plm5-r5s@XrvKO-)hxNk2Rahk`@QP;<5MXjch&|>hD@AJyC)4HhQ>I=<5T>96R`s|PnXJ>a$&b-;Wob; zj$z(`+%cuz9rZjTkHdq{OUZ5ylk=57mqO^FsfEMe*r}^8g(`@M;K=^ zYiP3w3A)sgbZY3YAgQcI+<}2;U=hL`-4FO55$gxVH6utPB7*Xo2#`^We7VP}RvtJ7_X5~3nzKs!HUe0d zWpeLJ!jA@~rt&%TLY|Kp^nNIf!DuBQd0&I^VLdoTs6;HGL$fI^n{;kV&zG)m$;HIN zieMXwNRjvy!YC>WluZT`Rw?If%l6|a+uLH(e=TGSM`)929WC?H!-q zVs!DV;b00DTrIRAIhg(5<}xI)+}LqzuvAjGXLvXYBWp)~uY&Sr{ZJO^60L7w8f6j! z`abGVra(pEGL|v-I>F9#vTR)fr4O9Qy{D5}ExR=(%vz#orwXMhr2(7rYkaD$`=ONH zcIrmWS|5!A)>z9?w_jAfR-1OTrE$;0Ei_Tf%-8XHSlVWE`ZtF9jD|MPSr_@nv+t53 z#KJ>XzU;dTU>E8&^AW>u!)uF?!`m4P9#<j6cO-h?B3q6aF^Xu(|GylQpLb=xs7dqm=foua)7y& z-j1j{b4a)ia=RuUH_s*X(+g*zRqS^|W2ROmBmsX1=DwN)wlQPWm!)eLbgKAckg4~o z^diQlrT#f^W6AUmwhwl=7;8l0*5GrU&o#kp@$*X)qw_p^TLA-Gjm_J|T`+g{puSDnr2-aU=&` zFv{BBxWZNZjauoIlD`pX;#qOcyJcgpGsh*5ar?hXj7VoWSSqsMD!2<6oow?iqK`g7 z4&mYmMx-ODQKaOu3JWKoPz+9!uFx6P{)wKDf5Df#gYRlOC0db^+V;B{Su+5MifzA*AQH`4yh3)#bm zS8ub1Bkl=PNky2cz&iG+MN}Aq93!RjjsNk?qpX(Pmf|MDLx;*J+Y_;sRh#7_krWqzqEY#1uAT&Ibk7{r8)5up^*jpHt=bp0t z?K)=nfXdJ^J$L2e{;4ItaAjmg?I>nt941__GH$fEoO?K5ddwk$J3;C0+PndQLbix5 zcr2#wn^g_NK|qfpbgHcIJ`GZ80z{6xt?D z?d*KEczX1Uo0)OJce7on5)1Z>6xwOIynm4jD+LuRgK~->Qscq+Y24E6Uxaw7YHC9x z${2^*|47jaQ40y(N#mG9BXA1BQ23K_z+TisrZ-q65(MMPElI=FBSRP@);ZMIPemgn ztm&unG%rdCT#2|7kW%`U^HLEZem2!fosWn^ExRZ<7$&~5pNKI0E-7+QzZG?_%>L@7 z>ltl9Wwct|mvXejN`+B!Yqy0& zbU!1w%l^6lVfFR8`-Dojqvv{rw}EG_>I7|W$Hbk&%EhJMjY%ZX5kgJluI2DsNAh7P z>Z?L&>?2fV)nsM{YVK*JZHEMD8feDKt`KSugd5nqZ3t$KF@-}D3T%vCwpRFcZa&~1 zNsFC8+7*iqLKR&SsYYQT=xRzPk*xtwR^Vw>#FQF*?)wUlfh2zKZ+wdVqG%b*oX}1< zT9ib;Ae~3w!>C%0kb)r3eXe3&u^>}MFEB!dm)z{QWVm=2SU)>Qh+wr@l6?<}+oPz~ zQUsYIdX{Z@m?i+{~F}=Y8vStX^&$uj}1_|d56ESFue3j9MDJa z!D&+1BG9s^5`~vH)HoZI5aVLZDx*Q4KodyAcW=(DXiHL_$7*xYAATMzQb9ZH=E?7y zEpx1cP@~ffu7&zUMh#@q%`5UepW8@WM|tnW_}}!_?l+t)W#4Ssq=$v)#1OBN$FY7~ z3I*;C1a+O))N+Z6=8_K(98O?5&)o_5FciU#U1LxEld-PJKZNTE4f?@cWg{5F6G6yE zHwvYe_H@v0+jLpJ@UGG+d56Wd{ZcNQHG@O) zYHWTnLOo9?WioCC3O#CR;n0oaYSvzKy*82}ZgsnE^0;9i(fMQWMMS4hli5>+f4-0c zZ$la*-&H@p#I5%0akdhnO)lR^U$HmQ-tcF!n8S%AJJ}K;;0DKTFfDs=@5I;#AQy0O zakZYD|ZCsnygXGOLIQQ7MJ+wkU@KJCw&#FwCho@Y$ z3!)0=ag{Llm(QR140U0#ve;zI)FWFf#OeAy2L%UXWl{>m?P3q{r(sH)_If<@h_ka4R#f9cFfrRT?jZs3q|QP_;rmmwS&WRlWX&g_KdZ-Vm} zBKN7{OkWTBs_rg1g{VK^GjP>4)|a-nmm_Z5pjGot_?^O6^UHea2{6H(WaSzUrA%|K zZPF?Wk7*%gPt~c+|FRn?;&xUns#%BUIOOSd7Rha%_MOvZSEZFHT{uOMZo0#uj4rN& zRuEOT|FPoVadab{bl6rcs(bFj6;n#3r`wUmT@;!m(}uI5qV>726BK#=cK42PfMzgU z6df%gpj!e)_=hH33gkoy7cc$vQiWu)Y}IzgpT|hvy|#TAdYV(jQkHEgIgCIcxM4=L z7;AH_Gx=tQNdur0%K~q0shu`0%t5*8k3cSFy8BH%f&Tb zYMd4--5uL1gH1h|fP%6mF+j@r~PJ&TK=J}gjnnZJ(B?!O)R8RACVp>iwJM!gb zWoJw8y#jw1yh~WD0 zqh4>C4?TX(cM(%Fut9fn8cVMRhwo0j-?X~8v!g@NO?n)fhJ73u+WSe{n~#H&^H_j5 zPF3zFNcn&Si2o?z)M;DZ7tNQm`Z;^_^#aJkWyG?Xl$zuVXd;&OQ%KHrU5FJ4f!wmgLQ?+aC+1$Sl}cZwyNj<|tZ(k%);bVN4P{<%M)^8D=hCnxlkarlRUlg`5RZj5{U4 zG|73sOOB&wL{`s?pU@A?1H0_U-2Dxs#RX>FV_qUN~%TRZbd0o|sHE{rR@}61$2T!;&u4_?1oBKm0v);2a&8$#W{B70 ziP7h(bVnPlvkjj#a{p@EY`?fLwrDVdOgc4#LzBzYB|H0q9T$nU9F=}>SDjZ@BoP7k zP6^n31NZabM23g%r_TITNPS`a;Fb%TsabM>a-_w#Prp(#_r!1f=71{rDJWH|0bWQa zFk%XlPB_2YL=Q8)fHd7>B{)jFdo=Zu%#DyxJTC6Lx2IwQUFNZIa^q}IZV-DkXD zDH%)nHIDyzkiyVP6U#7^g$GWcv!c?uf1r6V%)c_`j4=sfoWimR9k&|r@O0Vf z*ti5p1qwo4DaC|xRp{8>5(G3~IOwBmBV-L>k53VfyVz_GOYL0*Q}i^LXCVFmIJaC< zX+w1Vn$j*lAzp2+ner!amuD(3d7Y?Qw64ez$maqXhyf8n@9_b?_pZ*9s?Wc<^yB*Q z-{wf@db^-x#|umIZ_K>e*$Gm}g6O@dp;$_hw(zF1ff(M5T+>2<3?TVzsX}!q?oXMOSC+=*yp^t&oIl<$R$=arN2V>ttQd!$@beMg(xTLAr)sF zU;U%P4(W)F_O@tB4{{k1hRR-?fD)N+twnC<3QVD!Wxq1vbN$?c4%&AAoI8-`QOc4hOmG66Uy1UZEIC=-P)3Av z6&P0j_*$tt0wn12k#b0}`4Bq-Ss5rnXbG8%_syD*HF&E$_5$FIO}-|&&@G~y_8=nfNF=E2D)5_*>$4)uz?hbdRU;7GC)jlsZZ);d*=(!o&rX@Z-RXJPjIVr$Nh zZaa0QsO3s$JvOxJfK^$aUg_86`zR#jl0(+x+j@DlkK|$~tcA2gG&rzee<@ZJw97Q> z_eJZgiH>&7U$Uh(_h^TPExso6)u3#oWc+DFOhNkyYYcI%(@GxCMmS_KL@3WY)rJ&I z9BH^yHyK5k=HiwhsUZq6gkz`Zj4VBTu_Vu*{>+{8Y3{eAM#hC7CuPSs(Xjr{!|N9lCmDUwe8S;J&b0=dSb zSb%I2=G>zTI9`7^^kEKF=AX#rr$I1XFiy zh=UHoy*4FhZt@*EzP#iL;m9DCPc{1aN@8{M{Qc(bd*_b(1my*=Rz~$m>Mr@@``oFWZ3_yLg;4&ugm*O3nJMH8L!@qly8YZ|zA1$*>&-Kc|Z6^d36M z`B?xyCHkkoQuy+7tASUEDh1}XP0trJsU((rlH{yoHJ&1cAqwnybBNw7&w2DquNAyE z-V}HBActqCw4W2jjGU6?zWqD9EafH_5B~pzRJqheU!uW01$T1VJ3;q=2BcSt*ct5 zJZ@&&hMRWgblo{1zg9KXAiMP}#TTfbR>{-F)&{^HTvsaxMthy02xj6AMC&w2u5CgHRo9y+0?_Nu)V0tAjc`cS8*$JsHkLXmsd$55Q z#uK1}-gXAI-DtO6=PxyUQx8RXQ1;H`ECxhw)FuK977`X0GV5$lxpfsfjD!#Ilu*8G zsa(INUomi-wB5CqR{1K_jQi3Svv&)(eRY|{+_P2GpDnEVt;+yhAP5?h`-G)g&*h!T)AZzx-8NpvVT$-uV_KdI-Hr83Lv9L zGs4^^2cebmdT<`s8|T{Z2F8i3MMm0^otb%MmK-0Qb2!hHCEEH2sUs}oiuz$ghcK&< zi+QQavP%}gdxP*x8a5;rXA2D7IE_wHH>OUEL~RI3>q z8kODpDBN;CO!Y9U7Gypae+-KAIHS6B40|jmZbvwrH(sA7jkA=?*P%2X$zx%1XbO2_ zu2qjW?2MBzssq(F?2LmyE;)A+{PabJ#FvB58f@($B;6X*axpQj&1uYEFnV?-^>t?o zK;2hWxx>26&>fjKZkc2itv}SfS z$Z{XGqZoz4p;PGX~bacRF4V{ajIjB^mjl8>QYP(qIBhO%dhmp9Q1+h)Tsp{i-I`6O@fFgcm- zJG-%&7ZJY0to_`UkkuyIoi7bh+aKJKvD_Zi=lGU5JcU2oy}go3hXO|^uPGHody@t)qJZ8feM}*>XpR8k%jF^0o7Si+V!5tc&nf;-+T7Ke z&;qU(^}t>AFM>sHQfM?HFpgWkTM$Pj@JLa?3ysmKAHQzv6!w4bR9=zGIV5DQg7)uZh?(Je~1GcfeedOTH?r`hnYKz z)WSo~ZtRdiSVnSM3pe-Nu>KSdLS0wtAzlJA9+veo(qM5~>+>7t`LI}+BvF?~raEr> zsBAh5d=ZvKmYx#+#0Gy-JM`KoM*#}#*Bk{jA7|xsolRY4Vogf3TLc;G>|g=d4M(}u zwyY|?;71(Mk-FRYgUwiVt`t>7L^?NyVIdw#8Lav^IqC^2KVLXzt3uliPYk$bt#w81 zI=0yP=Nw;%YnJhM6#Ea^9m*d|m0<@BCe(7yRePU=>%XZGDqH4`)Xb1T3`9glYkl~O zPL7Wc9v&WAmn=cTg?6mS_b#`N@Z?kHW)LnOGEQT>nKe_g>v+;p2gPNAQ8*IYY%Ka= zb|s}S+2U)%D)n<`CxehFN6iTMY{mj@WiGgHih9k(#CbL`WpOz87P^e<%G!z+_jQCe zlFXvqjIe@)jh)J`pD9GNi25?_`TaB?6=;j@$=|z*6Tx^|lZ$JXmU62X4?7&fWT0s4 zg!<1XY6#?#G>cX6QuM;NaNI5)4O3v7 zzL=I!);Li$GAP(=nq?tgX=zAF)k617R?frK)%6@>rjlKlp3Cp9*UOZuu0+C8nEwyO zzc821t=SP=69+S1SQ4(0IAwPQh)^NpdNQ8rfg%lGk2D;Dgj^!&()XzD!Wflp%@8$D z@kq;CaKm5#&v>?V=w0%uNB9AhBwla1`*(oV<*RW0{c4%!^Z0G%g#3M3&=@Q8BBniY zA!mfk%qh5u&S+%T+Cl<8BDPwkX%a3hB|p6PiP564 zPam#GW6ZSSnM@0|GbGiar~`{5<1cTW7gVAFS$jRq{lrfF7UChl`Ua)i4Tdp?=<35- z4~UW%4}OS|$+-yu_Ao0G&hu8IlLDmaTJX4uBwI!xpc4-K{4jx{&OD58s~AumC)K9dKmuH`$fv4+L^<1T zl`-A~YRU8rqcwKT3GH8xpEi+7At6A;AV^LgAsRQ(5wQxOl1+9YI2Zp0MzDnAEaMhf zBvD4WqQNrE!#=*Ly4fpL)~W-9d7CGw00kWg05Nvh>E9Wmd~&lvt05AYs=_>u-h2yf zSi1mMIB2D#5?a`^@aeX+|6Q(|Uj~LZRnDs+DGsjdUd%4Qo&VY~>Ss+&LLjDt zHC^r7bTVUz9xM$VI7*NsUyK0zkmsp8tVzH($_(Sp|`EQK1j?2g- zIyjtiG;yL*RX7e`6eY`eExA0>j_>m(OrtZ^m)@=MjodzG+}B<2?6}(S@s`)03X^1# z^$6SR1oV~5d#UE@_2N_MQ?fMhu;PC!#l{J@bFdA^*k{6b8HDIhC!b-uM#rFV!x}@s zMRT)p+xEDziruAz+NM9>;uEs#qI~Nzl&a?Uh86sdzM%3x|+@CmJGu>QOA zlwd4ORZ9ie9Otyt7Vdr7d@x3mY^SDn^qH+BGkT7L`=_YF8(k-M==v1yN`A}+`;;#`G08q#7*$|l z1To~MGlk9=3b6V(WZ8h)gFsh4CA_xrx~_9)lR+{yK8U>eWM%WDXMx>($B73}0zV|3JR z8uYA_`PYR0J=Y)XDU1o`#*pR9ovE=ah)q<_^{W%Xwj!B~88@%-D9aa+{X9X|m2fA1 z&VuPCuy)|NQ+#FVDcbn7(>uI>lCf z%6kPJ8wxL7q9)xBo*SBK=&s{=Qqz?e)k=Eo14P+pVZ-#?D?2WHo)6hWA~o44n~iMG(g0~h1TA_u<$Dbh)eNZ{dB> zP`Z!{6y<;k{K*-n?_30zL^3HTBO&TL!6N$jQWaFZ%kgmck1>*T(<`hvFK_9A5Y?Fb zc3cSxQ1SMgeP+cLWldCDxBogfR1B75>@e`S*Eh|g#cTop)*sepZvDiGbYEuc+9_C8 zcsk)moJPHbpu)l@2Ac%4N*?-3MGZ49c8@GhZ-M_{3tvV+aw06A;-KEm>hOIbTZ&54 zDnSWi&~^c9+PJ2Rg8)zKxPe!C8LJ|Q!rju5XOkd$BHnNrT$}h-GNxnbV)O_Bjp|Rh z80eU`Sw3!{vNjpp=;>Nb0geZ7fWwm&wT-<00ro3rKf*&d zshe+fgH${ubS668E6~qyj=0xc>a5T9{B!lMSJB;cqoy%0(&C8YMZx`6fwd!7 z9B>X7I5#@HA)v^@TzfiNq0iN>VeZ~JzbU=-w8%LvkgMu8i;ECOU$TRJs#nVZSXER4 z?enw><~U$R+?nb3t&MQwpl)_qK-{=Qi<@_YrwEE1VDgybbK^pmHs{c~*F_$v#mGi? zDu%1QXhC~mK2}UZBd|J)hDSw09mbWgfGJy5&%q91Ip6Sc=U?uov|m;}gWF`Ww6(3E zw#Cj9aY460Gu*DicnzAg|CxMq|$FgAt{&5KpB!NIKG#yl-;cC786=zfr?CKCJd zG<#`!8CUQ*^F|}RKF)sFCtr^VQmd%)u&Ix zrAZRuu7gQJ>9YA%s5b%4|9%FAl%1q#jXb@vv-PftDy2@Bf!}WfHyE%r8*twriNd}y z-1G!=B`iHX@uh*9LhN}U320O8K6$_MRRCQRg!Ah4Fz9ptv|? zO$emyRG!i}VlHd&WH7FP<;RUH2P`F$tkd90%5x63G~KUIrD z1zvzL`PzDbX&x*PA_KPx;1DDw|2^H^-Bq>^cw#H1Qe(*8zrJDA6>=_R6Ouz_+T31- z*m!eEzx*MFf3vjD7WE?_^|4W|={2=Y2&iwsPaoeo6q*g{f=IU;iN9`Aqi{(|0!9^K zX-w(|&p!`QM%^ywC&f|4=B6JIU2ln|lMe#T*O;PU+Lw4^x{(cv$0y>i`d2mklBke-dj z#}B}>42<1@FCIr5S?u#3J`^BB9E_okxhG7&AEc<)tK}C7Fl&sq>HC1(Q7q~nzwJ_Bo&{PK_{_-)a?QbRrDJW>f9SVKX0+1cC*fLQobwq6NP zBSfCSs$i>kxm)~zDcdnG{$);4sV0nh&W*L1dsHPdHVula=J=)bgP54a0})ZsyX{9! z6>W7KbLHY-K6SqBA92@H9#B<Po}0b z8Hm8CrI_df+-BVOhQhZ06tSKqM0|oR+HqaNCz@wc%X_|Njw9N-5&#fHtE+n4lA`h5 zw)j^?(R{Jg!tnSM6bQSAMPQx-8a8R_aO(BPxRo*%oegl4v)}>;Ay4j6ia-WM6YlRp zau%fg8N!6TniQ;nUkCG#7SoBgt*ErX|K7_3e5ew@LPYOYX9q`TGU%0BUdUkt1O%mwmqV^QQ(z;jauv1s>W87bya(!@Z9Hd zpVrE{si0Tk0;b#=Kdw9zbzW_Qb-6IiRWe03>=bzaH?T8yxjZJ^GBUlLpW@VqZ~vR3 z*e!eP=~zld&p=`cbHHDR9DuV-jZ$J%|2V83^0M>^h!1~yGV! zB6$fj&tH`mMp_Jea0wMt5QZo3DF)>e~Mh!O|k%1L6#;s0{b!2joUk& z$b9td3`hY90^7G*bbNp(PulA?wOGVDUprN+w9)-+0pH7h8sC@EGWn^Q^ntLrwI$AK zBC%NWvtzaeWFHlT6UOc==uG0Gv4t1y$r(W{bQj4NwfhVa#3~T+KL121>f`LgMUt!) zXXpluAKCZf^?4cm-OO*Bnd+QJYIbc#R-~u80 z9b#-?@IWUZBIrKjV5r1c@ca~>+aO`+B3#1LOi2)_%h+ELKXY^#zU3${`X_e#mm{fW ztsD;HYY#Qbydr_EAB?gV#xqPfLMpQi!Fbi0(@PL-xXzgnrK4l#))_wD{G2a@cc8ti z>)A7*c})^@z3Es4TYlJ2 zXjMW_vu`6KaGO^GBKc~oO1%?#Cw@TH(Jk`X#3f6RtAqw4)1gF^Zjd`Ca2!NlLozb| z?dgm$E8$pCZKZVRG8dxiLna&unu_4zO?eiG9@qhr z9*odVl8D|r)#S6alcuIuGU-XT4mp8BRsKXG+}D~t)Q}7@L6Kqh0NciapUc(Sh5x1g zSbckl?}q@AIAHmAYOx!{p0V1*}p46~2_?*>N%8 zi2!S%j5c{dBsU3CN>S7Py*AOCr$4wjT$ywcSJ4i!@V;0lB37|DulvTh<`nIK2)SP0 zd{R%4+9@OSg>}-!Z*&-AhHzLDiwZ~J!vf%Hj!WNR-QL1u@5R*?hC@uq9a1yGVf9Y) zJPVwk9!%Qy?>r0c^1cForIL%z0?hz_W~ov=0(QOg^E+F+lX=GuSO^#I5=5mJbGMPy z$ufiPm*=czY zHXY4JOKxk`l(%XdS~lHH$}K-|N^pe(fhpAoU0bT%UK}v3mrk56A)PG(6-1-fSVI$I z62jui`?dv<=y|4|V`e?Ss zKD<0nXIIw}z1p*duG=E8gc&%s0&0FMmLfbwCGJn)kW;dBcI4Z^iCo02#&c%retKo? zN@+{#@v&Rrl;0;W^Uj7b;y7LR>dO3wZ#{+EfPls5djVXDd-A!QkG8FRl|A;k0GzKT8yOs}!!4rliMk^K)M0HdITBn!10Gd>( z;zqa4FcstZBzE60gE{97(|v-FE3g$55Y2X2Fe>yfoyQE*3TXxg*$&RMnxiTJgM=Q> z9Zai&cfUw-qOaf7+`Mm)mJnBuES(&@rHlph9QN)x?EVaR@4f<0@}~IHc0^L}eJPNT zj~*X0W@Kjalh5JPA%^@l&{a50JQ=9ia0Zg-#lz*)$q8C2wR;UEP#r*Hnw1z`siWDH(Vyb)`BI_Ijl(@kK0b8K#En! zQn3z*>8)EU%=*KdGhm56y;_bSV<0j9{_pQoh$WCQVasXC0Sqblv$eG~+zD=5J3CJb zlP|g-*UIp;7;t1VX<;k?Wr+`o6vM!UWe6#CtmMwj|F~U&;up(CEK@cz5fdp)o;cAi zTzSZ>76sw@0)K(-?D^pHqi>3AnCYSdv)O{j!WNw|l?4xu;E6i$9YQo$98V?RleaMA zQ$4TU?4N6w&K;k(PW~cNtMmWX>Yc|dzCIQkhU|amal;unl7LC!e;>VC;hnbGdF4qJ zqqW)RQ7&lCNX<$@=*jG{kV9=euS6HqM5~~Pj_8#@b}Ec z;7`!!KNJi1P?7=i_kBCA|CR{#P26vQW`Ul*ehR&kz}!im6|g)2v<*;QyKl{8%h0-DfsYcM3ep2wYDYfnasC0u8UV(y1EL%>&cZv@eb zSZDUxON0Q2I6FgB*>W2=4=r0h2tx)W$YW}#FAG)$uy$gI@7VdV!)h0Ppty}?UtuW2 ztn!}0>T-*G9_AKsMg1kyyA%8l#{abVYw{Gq>*E#RObWmY>P&o8%K3&%iYOTTr_tTM zEL>i1`C6AA{Bvmg;1wp2E6)KcoXW|^Tk`Wzj{ivrU1^>ZzF(B%blY#7Zf!FkV z1hz!X@85oxTb=4(nzW>A5b#3ZBM8~;h0|fYDyESD7*OJAwS>!f4$ghGbP#kb*~98H z*tv|0$+*?If9lxm$1=weHLLtVs;R9Vopa@grPMeM-5PW5Vhu^#^}n#pP8xwlk%68r#x4OS^w6w~M0I15Mq?%2wcL#1)7Q{jkS-;*o# zhUtuNFqabPAYOMBamduzTpK?!dTU~4CfMc%y|x00ckN2ajlI;r;dg(AWhL){PZBXe zV)6iLtG~c*|2!>CvIP89u6)pI-pMFpu54URh+_w9z!S57sZ%{bOA=K`Pa}L#PDhno z%jmSix^Ytd6`;fyJGV1FA9RnMp zupcMN@Zis+9*lY=+YF-;|6==VcCv=gGWygsINfv7;#|3iS9c63vj7uYB{xETMQ2n! zhPE_%C0iKlk9eI3*?Y@IWQy_y(bJrDJOZo&`PTv=3tZKThTfm8zc!G4wRon2tW)m( z43+RW`qo+Sn8i51=Mk`^bJC=> zXh8UMd#NXknWmAJ9D=H(d#hMJ{K~~VoD+LYbkH);2dcbN@4VcMYC^f5H6h3*Ue3-5Br+h*UW(^5q-m6;5n!lFjBxM0|X_mdC@Q z#z)*ZqXSvW#nVLY?QKWw!KF?wss-dY=()SF%Cf5bs576~^uKf^#;H+!8O;fZ$+hc@ zZgor#C_sE>Ca+|RT3&{FdU~!8hDeryfrw$xM@B49>5Yq|58GiN+gtK;oW)x6pqO2B zE0mKBHojcTFjmJI?dt3RX)wr4DHSM0_Zu36uAFkWK>bYgMX*3uA`i%yoc{f~?!Ec@ z@MZ9I2PX8!?*+8p`x#qnb|GGtS-#4TLVB-s!+8jwHlpnp$&Gwmb`pZ^PtPc|Kc+IDC?clpoI#YW$G zVIbB9@9efX`#rc;53z}2d_=c1mbMtrAzAg zfh_=-@d#*R8W4-do~1P#HcmxB8_XHyIb#DizHd1qxm?R!1eS`f*bAoJ*HmTDIaQQsFuX|=<>GIVRyf+k(iRR=8L7i}3BhW1B&$1n=T{xq$RK=a^nB-l=JyXf# ztn}U{KEvu9kJ9(z;>ndPAy|)R_gsh_cRR>fe=A(gg5hxZ+{$Q$aaYQDkMR=ebj_P+ zdncQY9A*KtZ&8uJPTd%@ZG+kVx4gUz1Eb`0KrphnEIYcmaQ6jqB$H}Mh<;F#|7qYfF3T)Vqve!S{{B;CdtiJ8RgmXwsJo}!lo%gJy zvVh6sprry~=!mMyAMa|zqLlB7Wzr|?dOzQI0=InKEpu*Spqb@+{gt~TykiT_J_*Vu zT+B=W!g$RprcogPT{5iSs9*1PuE z&1*ZfaUamx``D1*{yGP=1ziTG8A_+oZ{=^-x$4OjNnp3D4=?WMt9L)L!>H@!sxtsn$oR}T-5LObA6>-uivfPyC-w93(1Q=$FfLD8&h zXbA7X(0VZ4xQ6+w+rn%{K01Z7_rN9Dc&qpxM$Wuq!pS12XA^o>+T zd@6!Q7`+-kMb49m5v~Eg&IpFkbz?LHVh3vDeGDZGLy>|U9{uzOI-9RkpMmmZTpC<# z*gLV8luY0OG;lew>Ff)Uscm$yNyXg@KHlEnB%Hx%Nu_nC(uM)5+9iS)4gvHJ7b8hQ zjR3YL(g!@}Mt56RY1Q!0l-)b%B)6}!nrneEHOW=Z$GDFp-Eiju#r+g5C#L`NkJ-yI z;V3{(F^L_4H%@;<4)Ed6tcP>voXmjm9*?@+{m2Cj&$Uh)89~o#G|JZK2_px$d2ZNE zAnMPwh~9Z9Mz0xEi*Q)lA3by7jaUnqwDR2^wq%eHv@Qf~8epuqyTG_vownn{`0))# zbeHF)QCzi&R*a=HsP0+I^-*kO(Dcr@4_=^a!(wXZNA>w|f&hM(4KfiynG8cL1V=8I z94@Uyd<2WSBO(scz{*P^p~`x7A{$SehpB-m?hmL_x!l~`jy>`M@S5*Rnc;ArU0OB2 ziCJYj*vDa-f_r4DY5lG`j*7j<{GU$2IbL)n6=gdACiK6%F7P0(}>#=_XL=$~|8FZgq zoj@sxs9i_h9mlYy-43}#>*A4}2n>txktpEdRkbliX`)Dw0Kt&a34hEu3_mEwp;5Rc zpW{!!pOfh0C5Qu}ZbNx_tNH>URao;5b+2H_f*C*v2?>jWanh|&?eDTi2167rQVd8f zhM?Z|0nTZfCdJ($#SdeUewhga5?3rv!I{LAt5m%<@3DSmbS<&C!YA2M2Z3 z?!&!-U-Oy*B5f^E<4ZhB_a7Q6v1ER}H7Hi!yrU+UeGlFuGSOcjbLy}4F#Uw)18KiA zE8?O5sKQ5|+?K2elrh~mxa;`1bRw(Tv!x|&Y(lX;w^_2FGR^?QDxY%0?s_)IWPI## z;pdPQ8ofZ99ip?L${0p0w#1*J{Y24z#-|ABHW{)hkPqv03Sv_Nv55zE4I`lNO2h9T zUKX;EB+5TUE@H`8bppXSK&9O~3=YpfPd^KC__=>T|9HM-T=?qGPk2uil2-WcItk?F zU7HNM&?UzHSF?y^RxC;vyW&xCWaZ{^@ecTlh$SV|UhhZ{VP#yr=O7!imrVnbimv}c zZZN$I#2aC@!>9XVqUd3ImoUrgmA3+;#s`rpH8XZKQsp6V-+xlsbv%iHGZl* zOM+U%znHW5j|%_zR+KKo&HUV3i(|CPv#Qs{8mCyZ_?~D=iiM7LkF%%wczNl)Zhc&w zqCqJ=$NB0FnrH)63*9@X<~Lczc!8tE@5rudKU?1DLL3Ou=@ph%C@)|wDx?#RAyF;0 zHoGs%V99<%lf6~FwY8HAE+uapnc|?F3Y|Jz-z*!Ky$}aD#Hx^X=+<1SE`7Hi^g660 z1XW%ahyal(xDdHH!Wpr69j5VY{e9@bF=a@@R)JjOY;UF#f&!A=;WQ$;cAlS2q_nOs z@r;D2)6G1U!F;!@kWi$askch$FOtf;$I;0VgkRjAlMorr<;k%jmh|kat5Gc}D7pF- zML?ViY6hJEdLg+a2-B6v>wWQ2zSS7Q60Ws!5@=eAZVAQ3GOM%J>~XDc2)-+6>EPkPfv;f*07*gJ8(6#&t%`<i)(4ov%~XwtE#n zuvq12g8~_LVvz_*rS)@c9$_Uj)vwoTB~6G{RHX;+g|s{zeTztq6KHU`r)Gc zZ%9-MyGTl*TV0;mZO-OIq+g?5NicZyJR7I`u4;z9LhYIT7M;(MML7tPnc)33C)T!oIN$(Xl#Y}}QWc*j|KrKWQ3y?2IYtkX6>>_kv2#X)~ zRKXM=HLAICu+XqdjhrNFx!^xp z7rU7CKQh{@YO!BmlW?|pDkMbx+qD+fsg$?D*ZDWFr>AG;&xh*;PCOhq}e5C(oF_XQkT)f(YuVv&kd*0W`e$ErD)zWRD(p-Ar1!()^mY70jT zhNArG??_aJ7pTpq07A?AGVCq@qi<$hf}Ga>2NaH4iGig6zkNx-Lng4 zmd&8d>Ud7$f07!%x%=5f41VN~61U$YTbm-N`^685C4)Utq7|@?HCIJ>= zxE4Ru+&lC|#e`B|3;8&sA&D|I_|l!w|Vx-b)E@Cj86W z{b;s?plHF%!J`s3J0N`_Y}ukjn*xj!5%#GEz+43kW(rQ!mY0`HE0mU(e}p`Stgo3C zlGkueJ5_ylC0)pSo^Y%KEk!rf@B{=Hz>?nb{O}hFo`84RVnatNnub<`5(YpJUFvTbtpj#~>7Oxd z|8(TGCE{w$N_kJDn}-MSLv_QP3}ca{Vy`waA;DiKI=*S~hFl#D^kT@3j*YeA83zoq z51yPy$qDaIva6&YmROg3B8WCVI^g&zfjD4a+t{%!-lI}6CGL&&RbX0G@v9PU78ZPO zc={}*e}_4|h3VL>%K;HDkFuVM0O^#hiU(MGS9*xJ1z+n8nFz#LuIGj}5N%1zBz`Sg zZYY=PWWb=NDN5(yOp@J!4c2b0_(*{%Bl~7x{(^O;t13B{Ra^`!GZ&}+PNhAWNiz!=ZCTeb~hfe8*kPK z8WW8*bAQil5V~Atd|GeVve)~mhc4uAeq6p=dB0-9K~x`UuqYL0SM(3ggr`86uliyQ zgP}UqAJt8LtWW~Ok&~pkTThzAAQ(IVaL^ScFM*O)$-YsI{gSAln(se31VJ^DfYSxw zd`p)$&1s{8W1Uf>qd<#ABDH{`t0@x{RhJZat-T$zRBE3le%CY2VK5ye9UCnXx+Sc|B`vO za3WLH^H-j1w=1elZq4wHmvs^NG@FztTO$6Sp4_UVmLjh->Pm8MwCxh|YW>&L8UDZj z%v%(i9@slM&1OTcdE=WVwbj)}@x#M&&J|X?LPCYfWo!la!BnJumUx+07#S>7x^hKJ z{h}i8yvvL$Z(?F6`d4bz0J)|SlLlm^rY!mR)4Aws6snIk*8*WdNe zmQ^EMDy)*RLfO zMygH~qkW^EJJd60&cs_=TPKiEXGEBL7Rax|b%go@b2}UqP77vodEezm2c$o^q?eBs zy0cc~)H^+<#kcp;K-8>TKL#GMSBEd{Ag$NEGYDPfpdxe>!*LHax4ODVD_jkOSI4%C zL1%$BLtmj()Qe>#=>5<35jb<2VU*;eP4-DpX1wvwTc@QfefvDMYp za&9_K9{8uq`;P_;AG#S6w*LDn8T*bo3T}|I!>QxLCbAQUu`zc#m&e81d&dYTdc~Zb z`lrX)*!i!L=gNgp&!+oh?2x^MzW0_L2Fu{&H@xYY+lRtay~d4?zYT3{Lb`!n@Sko= zg2sopUoEB1DWABW+C@MG3A#pree!n)D}SC8PyvIggFtU+v@U)Kd!yi`u9pNoGUvzV zP{u3Y*<60*U(Qj-6Ce8*9a*??(EJH*pAa#}v1Avn4RH~tchEO_?WaXYpk*f@WQaXe zlp}Aa>PQI;p~3$j`eYu*?6W%Gx0!RHu0>}@+2Su}giSJpj^xhMu4!N9M5 zJHIa}FE78YXJ&?lsV$%`#*y@w7)u1`5IyOLPo`W>UK_@cgWuf|=wzx*L+nBvFe*^?V zP9dlz)IcCwr(f38p*ecW^L&HAJ`@v!BBtiC(iE%2EGML^IxM92XYsVrZgZfmes?rV za0Ak;-;NNSxr!ydh8hUBzom`GIT(@yYgM`TKlpUS;>D=v0pAa zTxV1Gt&Ul%Tay==eWJ`?d?YG9!Tjs}3-#s*gzn{-$V8C89}RMC9&|F)3$g86_t@YVy7A0`VIQr#_(v_UZYF5o&>jx#NIj5eAM7dXr5~=n)-*_ z@I=2`OvDL&UrL+HVebo{mh&GWrR&$PcLFe#3U1>G9n+X^O13ywpnmw~S6B1Q%}_Ph zQ6Q2=o`>8^E+ZwUq+|i%33)H;Npc#aT98@M*S8d2-+HtZFn03AkW|{Q!6qyG z^>#V^_l!HGWS3j-hyEygy}K7`I9OS^5OVBy$ZfU_D3^Z@Inmk5#JtEZWp%li>83Di3gMbY zE**u?HMj%+t=-9cF6rLYRR0uxHk-jpgnTEugRnt~gI0WY8$%OEluf=@RaPp$`6-6+ zn`4)~_rEq4f2*tCu6sf2neQ4PnNaU;OjY~9 zh(kj|4~&-X1MIL3y4QiGzL|eYwCLtr zdO-0*W8jHlDm>#=6`uHD?m9{{80`pPJcY70NtEPHx|4q7C;RabHRNq>26W-bwVN`z z4#Rv~#WvLq*2VK6my~)@%XYp!KYDJl?o^IHCxk!t6^ctAeNgT8D3JlHblsbuoSYOF znf1bwBdtns@!DA9Gy1<`p;(;UGeAfgE!i3^g@G>>;R-%c*G(n+WK}@o1A#dRL~V2J zHILzxP)G>)f0WR~pws$e0k+j+h;zor Uh|lYE0tCEn-!L^m>)S{F56q%YMF0Q* literal 64932 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

>BkWU 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 YsJ>ZkHKKuFay{g|jFNPb zi#Bx}&MoTyZEjcn2>w9^dJW*=5>>8AyAh^6#=?SLwCi0rGXsAqUEWr6r0*7m=VMg`ln#Fh&((% zNx77+(~Hyf)9#nA^QRjh)Lfmibh_||VdsKqEGH!nd&9mS#5(+8FC+(PZD#-g1^d5m zI6!7L7yuvx$cRJKJeH5UtjleeTxo7&dG~d!d+wI@9SvNM^r*+^cBNT|2gM6^4D4DV zX=ZOoZ+EiBw5uz)s;^| zcb&IFPxboFQ;DQk^$Y73dEV32PVOsf-neC_o~I)^CULyO+}#&wh8-=||G%Fj;RA^k zx$`@J--ii<(z|u<_*?-`coS5==Mn#GH+OeBg)jeH_(Va0U0s3=m7k5x=XAd0?!O33zdd~ry5H;(6cA`K(-xJbD^4*q z*RoD5rF(o4IypH}czSt#bMW$d^nZRmd+S~zxONkCW@Y!i%GxM?|A8c;v5}pZBwk%R zjbhqaeK)k~pR84NNj(kYr6{yrajAh#vP``M+dK=N%$l({MHECAL6)k@CX<8{BTn}R zSGB1)MbG3{ygW_v+vVgrb7X(tahxjHQsP`-&P0ruhR>gKifny)%X zOaWZ%DE`DUvUDkGSU|cEWzh(6_0ZJR6!+I^sPIEQ z=~I2J@1dN5*EMMsMA++E+UIFy16TOI@5AoH!%qPoo*9G3x%5i^FU+T~f|Bd;d|%JQ z$EP|nGBRddKiUMfQo+etvPrY7<{!?`P*?8~nEnb~4s34GTyWh0vy&A<^cKWS(?v>(yrfLk3KAABL?)y6Q0(W_g|?T;`d3}pM5=Q&iMgkAptm3`Jp(%;)W|guN z<5xryDl^9Q`5X#8x0J${lyCFawOw5G&?pWCY&tXJn6VgETZ-|j=A1%W9i1a`b_;cN zv{+U_^L4tY!m{S|Rw#OeWxPmHWle~%)0mE&IFPP{T{O&)1&KUFHL9wa|ZddF-2tA*RrI_Kz zGg~wA<)EjiD$5$NfEU-+*7#(wz_#0o2VL;hdJa14??rdQfdLu#LBPN??n+OwLg&Ii zSwAoNl~^On@W-WC&wmI^&7(dxoEhBmaliP@^Vc#@xb2v5DuwTv$dbbaQB&lU9vWL% z?B_MFoV?lAYpwG0@OWHi^*m%<^|&LxJWTuNhG1+cChfw4>Hsq?E{-KfQDuSiQa~z+ z%H!o`p}wOdnnQuS1PB0|XfUlm4z(YLRU4e|Z2;{btFn6he1vNuZ?^bXS3*!J)`LAx z?R60yG;M;d$mZLM+6vFf%q2zF(Rug($fl-AG zxECj4c>JbN&EE>gsO67H_J775|Ham&OIh3vkc#r{ zhnO7`V?sqm`Pd5CX&YB=^zows2@lDoW*6+ISmUH;s&o3vK zcm8M^NVKj<=qflY>aEGwELU z7JM}QQC{+%sOr0o?d7%7Rq2oQ$u2JV;ISY^Lx_^#W3BOwKVjMEJZe@1nY6$>IR<8N z5(br1#cr2knRAlaQXbaqS-ROnpz8SR>DepOTMnD0^~qW*Y?-&PWwC%!&zG%hw>CEc z!F>P#OWt(fuQvZTAy~a|c)GPcK07mLQ_ezdumYreUds)jqW9fidNf;~ZGI-n)QGWg zrkUlKo4~40y^{n6kdu>bqaak7X`!(Aa@c#PieG#7f1ePA+;#me^;zDLI#cNH3sp^1 z9jBORIFq4!t4O)b`y}Jk-qX`_Kd#wb_?AO(t@QF+DUo$=i~p?CdFOPkgNy<-T&(kQ zoPKd*L#k)NowboOL3R7!0Hl;F0QvE!e|?=qry3enrrXmCUADx@LfvUNHlDKPDLcdD12m$x$eH9` z>3R$@KqMp?V8YcDxtGNqBTKcHicG(^YzJ}@OMY=ktp37_E@+FyB6vTY%rc&cgWEu$ z5396C5nmdGpBhbLJg;HRcjwW8XRz6N!NJ2LqNs?{XB#`O*N{a- zZ{fg&k5wB-luY4^fX_X~2U4LyLzZ4k4$(9-R-@J3kGb6BSmM$m(jfqB!%d;8X3%CT z0)Oqvj?GrQ@&qb9!B&)6v1(tCQ7_XH&}VeUBl~_89vNthh6*kWX3 zRVdQ&N3sx$;SwQ+waxR2rhSd+biFJ3>F#W2x!L-_tz(woe|6|rfCHXtK(;rcs#=|vMxk~*n_wmNGqaT$zD54jK@b~!^h07Itt zmFxD{s=ra)bMa=85Z4af3}YZFI2Sm2;df~tytRYA^&Jbm@S%5CX*7hpAW5hMMA%`^ z+5+;jCe00agoK11h76vEgb#1LdbsnZH!RHO4_%DWiq`C4Wm85r^1?&+^yEan=k=(^ zE^k82|03Fes`_T9=RUfp?KV=$2Y#VOFWP>4cNYlDjlL}VZln^mT~t^H*?hb?lAgzr zrBhQ6g`uI%vE)zSSVXH2e}A*a>BPH*dsODEnerU64{}*ZR~;poHTG^qVR1s!z%Kc{W2NojqS-V!pvvtAjoScHn&;J#Y zQ)xM@&c}a0!06#^-gitS0v-W`+;;hYzS#;;)E*aP;YGvMg&LxCI9+A$?}GK~dJ>4x zSOhQ{*-eo%>aQlI&Le$!$e%ar`Oyp$IXYE+Y+5ijGdhEoKGp8FQdEP>I}qK9{Fi(@ zxrVBm_R@nin;ibUPHu_Je|@4tXH13=##UAtH3inkVGQAMB_s6KLGx>@?PuU+scVEV z)+t$2l7vPQlvN?0kt%SoN)o8(<~SshiW~lX8*5`5#=42^EkVo*+_ zMhu4QetS9F8TcSPI5mZ?@A>!RYNsRiXO&q(7%=xa?|V->!4^iQI-a_FJ}$+=u8JjH z96%9-psbBXtc-lLK8e+Mi)b4>;-J5>wJ@>E0^W-9#0(y#&W8uK9E%Z#ojbBW+4c{z zawMv@^%w=9v4jSq??FYFb+Ou)^0|$CaL#2dIA32POTx|j*%Zt%=+Za2k~GaF)68J! zLZ6%S9Lh5MqNrz`Viww7sr*N7IT(fX8_URdx?fK0ca+|)l`g97eNjAfM+O^^s6rN0)IYBKTuqJ%KZn1a z|7f*adpz^|tLbOIDrmDsoMv7JVwI9WYG4%_HSWF!qR`o-6{0`TSaKm!2KoqL)RXf6ev*R$6u>r#A*!`?X>Nw9R3XXQj(m8 z@*{$FXu0bN+W0_qopegS|4aNEtKasgSCnFzs3GIPN;aV?7lC7eJTYsF=jAq{5uNBl z+EsjGwDCewZH*b7osNwcrtXJH`)$}ijn`jZ$GUc<2CI&+$K!9R=JD(6tDM2hKTT3y z0;dqOm@NzSh7A0^U=;H6^DQy32@IJxl=1lZ zSeLgHRR(c|M%9QMVwvb-g@JhGo-OCSStu|OYfchJ~;hS0=N^!+CD8M7p{wsUtW!jvWqDeVC6YTD*nM+xcY z9l4ty5>V(u9CEK_i$-Xp=EC`*gdZWYL8?e8s$>*YGC}&a;b%Vk{5<^pp*YB{Cp?R; zdQu_ynp8O(djYbZPVZA@B9WNl5)vU>LDX8Uw`Z4CzehC0r=qrLA= zA#|Zf3$-IL-fLgE?V|~F0}dMB8wqDOE-riaOW$q4O6`eT-H1* zf|-EbEsY6dBZyF!#WJ=$+!vs>;5!eIvUy0yT4a5f8H%-y{Cy^(tCv^Q{Cx6XtKqop zJ>!4MBJ5~3E0R9T4G3TLWdyi2C*`eF?p^UVFbsSWevonL(4&f6dDt=rQc(#QcsvVC z6BmjCSP#sGSRNrP{IWmL^k>B^;aX6J37NmmKh?hx>>kH6#x!5J8~e_N zQx;HxJ2@I}jAHIsSn>nP2Nk5rAhB58I}9C1b*nDWhHzm`PqnSHrJaKyptP#I#*YS3 zZ5)>2Vbghhf~QII9Xd=!ib4!yK!ARvnb?Tj{lXIbkir5(5uphoYkMekS)Jrv@u9s@ z0D6`rks=lyH4HyQfL!%zar^|}oj8LvWK#iCv8+$&iLS*dFd$+6-2UfV!OF?@`8mcg zxbu2W&f{_yX=-{JHu%7Hpt3SZ6}h(Ol@G=lIC^-rUH4i~H)=7ke3w^N|5#ZG4?1x5 zPEhRycWvGOJs4Z$qZ%YYJBsHdyksOj3Nxi8;NV1CZsyW9(R)e;<=#_l_g)|}c9q%^ z2w=qPrb?r}7bA_jpBWAp5Vsthh7uOU*3Pbp`}2vv(;*N*+TX6`WR+!ICO(<6g!0mr z_93Dowuk&(tT`ny`Gp|wgPm$bN&V+ahbiGFK}y7V>*TbUeK7__5YprwM&}(nTKoK= zTJ(@{Ve|UNU@nRQeaUuoimGJp_0w4oY3$?mHHVjlxn$XVAMC9EgHjiZ>X2qAo?;-) z2%o^K1CI->?2Z-!01I9f)JBuKH)PwyS)GpLle7~v)5=}{L5*R17;x3#7^tDb(IUqr zy_*q2NE}RfM+DVTh9ppEKjdKS)THMxaK~{W%2vwBXej{A9(a}0KEg((f9?8gMvXzWo6JXXG&nau+CY&} zE}OqPvvx-EHsMbc(eY?xU} zALf9s(Bio&9NX9(=U98Sw$NqUn<_RSa-X28e-G+>y2&YBKYDM`6FrCBRTU*aYa1 z&$S)M5cC;B{6%B@b5-QCuFX=fch<3W+#f^t#7gx0SAI^0wIFAJ`!F`a~;&|=#z!X@hK_Fh5Vglg+@NRg)aMdPG8j;+I*^MoKlZf6rKi zrhsffTe*ytZkbh$uq4aBo3yHENiYe$>3-tp&jKq-7+OifWY3)2b-ZbRu;GJ4P0BFK z0+PzFh#KdSU?{zT3c|~*^5;+L=tKI8z&TrS3i?MKG0F%Kx7}(lp?xQ2@`HKg1KYKc z;7^nTcy=+mP)!5hk1|RB;i~$&IRTZ0fzTi4TilLK+>1GX(LS`y=6|hDqba0FQO=r! zBMr?bWy)pU3&P_b9?anNNOO=EV#HkPTv@Q^6HeWDYKpt~JB0d;6;~X~suITTT{Z+5 zM(h0%ofyt6Vm`OT0Do6gRt;FpZ|Lok2*ko|tz8@R{MoA_B(-d7@<}d{_U2dCb5nBt znq3jY#3IFlKuwlDqsL0w(2f#&?`C%Y{>ICxJMnPmu0 zm7#Z5j_zJDm4?UYlA~N0eVJ#~W7_LY7qCWa!}Ya*G~{UU=%#S?qbFP{t*N%#;mzW2 zLkzB9C_(fPMR(1TO;`g1WH;hD@ZDSe&$HKutWeyyM)!`jQ-5a zRG5?`3M{tQ90kDXhkm>hSoi9hZL+%GD*f&1OJ2I}qAE>ia@$3>hn#EmQod?Bn#DI+ z-8_0lBrCh?8K|R~@zJ>xCSu$Z7Aw#2Ir8=c?v5=Y2(i6H!oEv*eFI zQR)j0g7)j3Ka)Z@F_U3`$nzR>|!+h(15uRE1pa3=Y| zmwtvEDw!Ky#Fqi#=Yh2EM?GkQ5qr^>vI0tH@>WFb3JjOp{@79PCrw4IiND6yV8t7N z96{yQu}e0A4>oZy=-JmRN*h=&IAYLsMQn;(H#5^LX%zWzWm-Vjr!10yok)#-_E0*4l_OJVa6 zFd*Wv)@1VO>FNHuOgL7t>>WkF4OjF6y$c~LJ54guy8oN+e}iQm)L4K7RtDTU(5i1_ zoi=R3TA;=}L=-Yf``aD%hFyQc z^ zu8*~=A#<5hm&WxGLlp`cCq6$gS}>V zH)s7Kfc~$6WyXJT%i;bR(KgnW!(#>kAcP^-KYP=3-?C;W#XNK9!W3(iHJrQ88^c=v zlZ%Qkt3RB^v1DvP{{wv{>#al-rEN%7zjL@L56`eqL{i zp%b7+#ThyY5odw+W>U|yfUT47R_t0${x;J_d5}VtzPqAFLJ2%`DHXoNNK%5xDUwuh zBs#mH?K7XLEXbJ*${bo&PPEYdPns9%T3hd0lk7vm?J{V3$!;*IWJI79l1xSzqfK4e z2cDy8$a$BnUccgNeg;1QKM>N)b7L+Alse-s%T;7apd!9u~Bt`{eCb+b*6FbEwApb-uz$2Wx_gQ!uRcG%^-b@;NWI{d(Ti zPK+s(powy9a$iAW;_1{T<;o&H8JBe{6EM{rDFG|Z&$ED)kljV*rlmh9ft{ZYz z|DXxd*HTlrSN?SssM?7=PZ|ZnhiE0;W!099@oucFh;^*Rk@tmKOG7$7fZEOBzI>4V zqOLA+aAHMXLIy`8Rgo%GF|EVs(oP)XMtlcMxBRG|dUe&5U?TYQ=5D6@VwiBRXmEzT z+Lft9z8T88hkOZ~Bz|ckZuRTq!c@vM2*)MIny?GMp%A-**H>HFrud&1AWR#P8EWP-cv}k5pUaFF6wq>F)$b?G~7~B+WrM}&*FCqm;fKmsE2XQx|OUj_A0{VZ~mwa}! zdCC=~17%)^&Qpbe&bptNVpu(3vJ`R{(Q=(A)d0jGWJ{-~P!gm84(v1Hc;J#d1c`WY z8S^^_Wk0=t4?c+{dj7}fuGulm>}ZvOAB7D>h(D^Xa3l zS+A0YL-GX^feO=I9TZ~_bTp(NMH{h!6Wtcg+FBaWMb(%4ZAa%vD1%B(GcszC>#;8? zG3zfJVT1VnG5d8GnLe_+JOqs$Rza@sD%vi!LS`{uwNJ-PlyX1?DFWGh1Dk7#G~E>h z;*{1-+oB3kNb!yB@lG^Wye~y?zH)Wfd~%;S@@Cz#Cb;Dra(&^`vd;6u(Y2e=Zo!~J zwq}&(Yw#$W55rJ&7{uI2{#b;*>9dK=;W*#x-c7~S{(FL-HwdvrnT*R(bzp}>Eb@o( zWY*{OtZuvWhiqk8iUf@OkOf)_6u8(md2+eO#b#iUwKTjcT_SR%8wEMz<{%yjcbSq3 zhqDwRJKrOTT3<7aJoJl$Q)CHtIsPfCkG*MreB`1Up>`GdF%tR!+c!P2g<lxL={AgP5a~u>m;QU$%=THqFqWS&-PY*5>|5KXZ$l>Uz3ZSn>NG8<&72g} zSg0nP#s-wkoDc%mTPb!+y1&_dLk;+|g*9@Y)F=W9M-!o!S{l5Ak1JG~fYg47`FK?54E5t~=B&hvv zUxcZ!8xnr zgqvwc9M#0KO>S~ZOiy%}1Bua+IA_JWs{iEpr^UhI;Xy!$4WaGtmUis=Gf>ChYsw{| zGMQr@;Yi?tlNtjON2UrGw*(+!A-_vBEJZM{2q5RF_~M3TT=R9!I&xO^)quqqB85S) zfDyn+=Je>5q&vVQaYI|C#~1>b`)yAW#>MH@;oEsLrXupmof6 z|4yR=>k*~Z-iYlx#WYF?3EJ7;w=dN!fD+iAzIT% z?+5YeV{^sifMdHI?Xi@&eKHXx;@~lyE)A5z6^K5wp;K9=IF$1v2oH}};R9rSbZt)t zl)y`E6feV*(*V}V)~>oOT9C$F%EN}@Bb z_Fk9(5jFtVzDAP704c|E6>2r2aWJ0%KF1X!} zW;Wu>Avf5aCFdQYMzO92%=D=iTz*4b`_?RLB5ziGBj|wtd79I*RcCQ!ZD45$IDAkx z&aEeKq*t4loZglFqjUWhJHQQ-Up(_{M9k(_-7!v@w6ru!2wr$3qnfD47I>#0$dFY! z3PHyh_A2cDB8HV_7@>?!$%)$l^^7Ij-% z6WMnW2EbQHqDVZPzzsNyf^~uQ}`mG?f zWHvN>gohOoH}TtoZOKAKGHIk!Q1BVPs+l3^K^0%MkWH)8=1FI9 zbqM2cF}~S4xZDHHs`cE+Mh6-wocN;(6aG_<6sJErp&|ya>U<4-6)JN}Df}e|a-yDo zc@Yd(V0Kb-{c9|7ros(z6Bp65`n8V&F7m~)s#jyxA<#1n_}PQ)C@d+6i~dg>%_)|$ zpbZ1^8^aV5TP&IYKtlII4A7(Cu=8Pj*I)4xemVb#XL>4=&Q^PQF=ES&(zkkXh zLh(l|hhxygi{A%XS+GeW9>S$@U?Hsv5}6!(ITa+y)Uajr3SN@%mpOaWa&-o!m2G~C zr3U>^ZQkxA$lcRRQp7)LyD=2l@dSY84}VjV(=DIi&Z$Z0X5!OEVWkTeaK;&QULVNO z(s{XSfxl29nVD=L&}0-+2*V{9({a*o8cUPw#?XN^maIt?C}&hByi72ILIMp^vD1Yq zZ8>B835qDsZArTR_CDLe%gc)_Nag+SJ}qp1a13j%(u!1)bg_1n8-MhrhPs}K4_9Q) zy4;Ry8l@#~k%?a6IQ2849yNv>t2r=X)mxD^MpR=nydmIh-(itoJQ|qZu+UMYe zaTzb9NHPZddW!qQ@q<8$Oj&8`0uC`e>bBnr@a15hCPZgCqY5`C&~U$2KBCdLX3Dd# z?3{I3ZLmfp#P|y3)=7|@(B@s&`CY>Og9}<#KK)ZW$C?1is z)~rS*{3k$#*@-BZ)SGD4)*lO*ty~{F`xgOc;Tu`<2%5DF(YFui%MX9ekJf<2qq2O28V6KOqXs4)%OqFWa8Vw`A zAAADsTG0X$n{;4uDwIv9nyXluhnM$qyztolduR&s%PYpGPb2ie94%@#f&ht1K54<3 zBb&BFrUVStAPMC$Jj@Onx_sBzWvy}z6j7Nnl5c3mTL-BO?5Mg#7NK8q zxrYmxI4YNYQ<@`_>%cMCP#!M6FkS|LG<=iWNQL7v$y~B~lR1u#SV<(dMU#k>xn(n- zbZl1Wwh@Vn#NiD)nt)^kD z`;mtk8Rr2y(B_GSZA+eT zCsD(R;o9gPP?3qK{xlIV6cGgsTb!zrTQ{$EUN?wJ#xPhzJ|h(1R3(%@KjT@W{%a3v zW-@9Kl9_`k9f<1M5^zqRLXRe{RAzp^)HDkbT{-9^2w{un|2dU{le>GRResSGMHWe_ zJ;$0kZJL?l1D~7~{joD@^CwQe;DwPhEWBQ*DtiaTA=X_?Zt^Jeo`GY9k}9}7KTv7r zu@=gReZ1PDzm|w_<`wb?N~x&Rx<*#k7?C-sG6mSZkFFF~|APh?z<15v&zQ8xnBF6o z+S#{Q!MvFE*|K0@=KNP=wC{SREHl?0gN3ZvdcpY%Qn z_)wL^n51SUX~X@Y{YNm;NT+Jt)EpWRIP-ClE$WIEym^pmLvbxhf@tWpJb{6p{LsOJv5~1T7);lDoqyekxRv zr=GSz961$hie{fjKtSA{4tT$NxqNcf!u+`BeHn!Lf zTc{hJedh(DNUy2Duqj)g4cDD?Jf(`6b`;@){U)?JON(I-Lli>8)}N&c(&gvrT|Z?S zUO;#7x(4kOb<}yrxg~AqFATA~+mi^j(l6@j2o?k#iyAMUZLQe%#PZ(>1(-|r4a-n2 z;3l_=><v^j=K1+7r&rznvQ`JV-XWGA>GTxlIk3uMt!jJYANAfF6! zFv(UF%g3j2!sH-o;ezq7K4JaE2{w7#P6(kUPQCv9EO=U>g{4_iot*)n+dqK{i1K?T zKYQlSvWoba0*1pknPW#IDftTeSn;3mQYDO^ZMUH~Mg(vJVlKeCh!~+;iI2BV zJ@n!%XWzejB4mGTvT1-BnP8-8WLFv_h)m6?V~q($W+j@@MNx#SA{EP$6~jN61K(+q zf@9rgPh44+HwI>tDYJ=5ML$yWAsN-u&ragBQP2Ls7xs8sx!0#~Y|k(mrfxz&1ue75 zni$IDFC2+Asjl92C8l#~J;ldc&IH*cc-sgOG)5ZE#MAeuI(K&5EZbd2zklvm=97WWOh8FZiyLT&$;Z3 zBprrdmfIn)FISBH{Si54!N29Td=Dcl%=8x<&Vbok62Qb4v`cLjEKuQsh`rau&|J2J z2hlxdlb5(uw&^oJ`s2W}D*YYp@kF#; zfLgY^dMQv9-%WC1<|NkPWH_3Kmv3-vrz62E&@IWx>lWBNs{9G5R6Q`X+OR~t8dOqW z9;xyeIPW36}I8^Fhx?whblNt)rs~4cbOW9Ji*KF+JVD&IE0tBLtsVk-p8Y)#za zEq&6MuGztEKh6Ao8Y8Y`;3XE-r_+v~O8BsbDr$|062jE0_;0UMLBo=@)=e|8e%6R?E!r7gpEU zi~m~ne>?z8oTS5<17=J+!Kev)BQwcHT`qs4wcf2U87O0xBnWfHIdQAmOw~URANhg@r=pq2s#M#;le7Ny# z_2g-JydS+`26PIR7}gwFf4=MX-rP}&C&Zwt}63O-_$rPZmGY& zhic~$;{G7nt+n5vN>Cvp1+H~rh7}1ZevrI>{m}ichNGBjF*A`cHrXfa@__YoOC8jC z74Fv_%5QZ9Ylgim1R!rfpDPk|U@waxAK&9Y`xmJF+M6_q4#*Kvn&W_>+V3Zw9+!Pz`&SmT43-P(-0OR zC1o2gvZn$XDZMl54))I%OvF2_9pftzgD&MlgIiRcmU_m?8&(}HsD2W+he3xbBbrob zJz{f<1& zim!(*?QG2F&(Etn<6W`YIUZ4U13M7-6a5cXKM=ID`I%aq%X>4FKJjEL88MKN`5gZG zD=tgTvi$h%lE~^`c`*}*Da*=$rh)g3e-}(~fJK3Ywp-f%Pnts0uE~vMvpxEd0hzM- z|1PP-%)*>TH+*O@0`6lb$~>0?zciUVU}iT|#94OnVDkR_wITW?xw>B-Y?BurtPlw( zwLq*-MmcM0R#s?aGw$(l!PHUFZ05kyXlfw>C&H|T1%sSF6*3P`1MMX!2SJA|9G?ML zYz0qF4MJ?a<+IeYFDL;npZtnd!446Zp_QrWkU*BkN7R0Nq4yE112mBfvjGMMq?K?0rzttrNYt z@|#hQ9zGfIrH2N8+Nl^QV8PiVX6lr8h~${eh@dfedtCTL8u{TwERenJVo3odVpX&M zl9qi~e73vKFyQLSIc8*sRtW2!Y!ZEM4{>R2Z3yP0i(!R{ez96poa{3YPtG7j@ZwFtL71PN;szTpYnMiI)xaHFnu>T_CdB!y` z2>i6PQh{#VbI2r?3Y8^^@$5- z=txKj1r!SbL0Cy;cNYO*#u8)iDI ztjtEw4v!dy&6ZPB+X)KczEe!)Nr*3P4?ZNRjKP0p+8*fk4U27zN(N)A-e*DEG^Yf7 zK51an-PYG$qqX*byi5ULk&}gnV#SEd_?zh6Fvw7)08+?6NeR1)wq;ky(W($?c#U^v zW@Hixa_&ayskqHGIgqeR=U{`JQaZkzIBQ|bpb&{PP`UW<&*k3%B$yp40eb)yLM(kZ zS`0Yp2(o!(?mIx|Qs2M;@Pm?53KWtVl*Z>mzB+M5lspEMl9GZMoMbwg`?f+Lf-q$h z<`5e5?vDDL8MzebyHBvr3~-M^+_}Hd@;!A=D5R1?`x8`CHqQmH9a}YySO& zVO9`XA5ee*@BVz2h%6d8pnQ$Unmi40aeS2sn+{mT8YiW|1Sj9+5RC(`IQs_@)YvIv zgav9)d81OJ&GEOD?}&}@6Gn39jeT`l2| z30HGn?GHTs`!O}3mW=fGz(He+#bH8kn77WQn8b(ze(U^;dvcEZ?f4@mM62Hr%6I%- zVBO;THrT`Vo7(WupGcQV$s|Ape6jci7YJf$L8qflU{%e;>aq|Q`-R$70^>cghK?8^ znv8jg!{4cFj4M9oPZVlW-P(q(h`bM42B7|Ylk>d^#+cg==dWD^A4sP2t@jJ2X)L-a zhr7aEc|%;k?^ISYMXU+T=U0cOz<1ewC}hyhFk%#8dLYcp-afwmH6g%YQL|D9vErn< zY#CA=zZl^>z-P}=ST-RaMtWxjrRN*Y0NcR?wEsNYP)?d;8K1F)|Gk`INYLQtV--xz&f_+j+H)pG&k)Hk1&VPCD#l!Z0Fw zHI7qV>abIqU{W+r`_)t?>ML_kOsGC!f4|;7A{HUMU&~~V@9Xqo7|I<~itH)=DxTO0 zL>@~vJ8G;M`;%^NO)UnMtu}dV@R0ZT3|5DIB<9G8n=9NFCo0r26?&5ZYBS zB|rVIg?H7`;?;yrIPmS24o)s1Uzt~jEjjuR53NGZf=aL2Yb37{o_)SD*_(+oFL0LgI0HN#9sOQ_~(p*qT5ozCL!UdwVCvxwCW&YQNbWe9`V-A3UTMv7XItwDe8V` z?3nEVI-JMO!OlMM?&hgxkj*}BT)f`V{o_HhZSbZ!hv8Cb1 zE(kbz8GP}_&T#NJAk~Kl4$%P919z8Cv7mxThtct6uqp;z6jg}pFBl%O*;;PS^7wlT z|2EwkcYa%hY}-d-oQxT45U!E;Da@|_C1(q;Abdl!n@n==5dbr$Ect}3tqG!riBVZa zy#&8ICMDYJ;&*3~-$yPBZcdA|e5^@Bg)y$z@uLG-{&{{QjjCtQIq{YG> z(u;tkX~YPP+G$NFe-3QGl~CEdzvqc_L}_>KbBHdCP#<(X?>_94DuQvb24a<;UHGtF z*ffnA6sW)YU(iYa9E5z24cc&$ZQ#Zcep{Zb6OwI$L=pB!bjNH%&nj=&LG=!HPAC1H|aDdtbL z2(%rHd?}?4KH{fydrM}r>zW%f@I4YjC)KEHe`m{hSt&XmV2aqsr^xGx%*3ctOHXGA zS0BL6D=cM;syIEoxX}}qGds%34&Ff!(X2pY)7#d+az|;3Aa4WkS;+;Ht9B7%< zLpvMV`q>ZVz6hN~QXp|@oLj`9v7yO4VyG{4VDF);m>tJz(gC&@^CG2fT2{T5j`Kj= zDyHyJd6%U)4$Q52q38}_MuA!0Nc!Fd;XW!wHH-ixa=jHHnO=v#+wSI7=XdZ*iC!TEEwoj{0wicJQ#nsxL z|NY{*u5 zUMVVKQ%T5m?oOCgR4Ep3X^qd6ElyLlzp=s$ zX1$Uo*bYE6W&=f9ev|i`KYbGdQ>@l)s`MM_J`%1g>Z1|Gpwj!jXSDy_kHZ$xM~3?z zlkB6P$L?D*{hT05z{j&jO<*v1DL_CSXq@Tx$N9b6Y%yCW4JPD>0Q60;-_3e@0gZdt z<)y-!$O@o9a{owo=mOoiU!I$M$G3$=xj3zYl%(OB1$8Iw6hn5fN#6BIjxGzGJAY)> z`Ks=w@3igv=55_8TGeiN#=0RViP^Nfv5|c@AV*EP$d(y>azWf$HnY9=g$&Hm~0UWdqCZvI$18mimbn z7dhtjv<4T?>qH;ZD=Ib+d6H0m_?u-+Tb*rrrfv|2$Qa0g=oHLVH#}X&c;)9trkzlX z1n_a>ktWUQZ>#^JtTnc~y|{vwn9vERDU9Rqm_Drc`=MX;rx1tAEn7Mq%PpM|v~ED7 zNYYTxdlVYiJfm`qdJ9Hs%!EPSRtFn4eb;=d(@8e-gSY5|x7fC=8(d;aIOZ7p()Z^2 z6q$MSXc+MIh^c(AKPdXGLT?W0Z7+;BZN&KdC*|hac%5m^aLV?|_lFtEwK!wl-63L; zuX&WH-yD3|XOm#<6L9|@mDWVn19nMkft?h8=*o@NP- zHHNstQeMQA{hduq8k_(I*?+V{pmO>r>Gzq;Wl}dEHTWbirt6UW?nf0^OZlS=oFSe7 zpRAR&6=?!D#MZ!fhzAM#3ZmVedFI$#W7L65!hA@y9u0}Y)U|Z$4u!Ll-9oW48Iob8 zqo=3mqtE^gzRSHKSQ73H$@4rYh#_~s3Hn_iwGy=E&-PVtC%|e#A|M2iHRx<^4g+9f z^h$evW)S4&+D{Eq{QrKr<;3&*w?-^p7#(4xM%j5;8AANHH#v6s6>LL4CeAEUH8{ugtB2Rk^?$V-K z-z&$JWNmygI$~jKH9!=cz-T3r<_m?-M9wnIk$v0er1I5~4wrSqF5;sTs&8np3<{#$ zaTO%b=+=qh!r&EmCqEL%a>41n{hXq0X)Z=)*Cnhg)!5L0q|DOM)&>@)ClqdH7xiIk zgojmVO+=4q<$ECK!KW-Q(2e+lYKgYm##w*D=CMNM-0~aTNmBe z0;kW!y}^8uwsDb$1snoRa4w-X{uof<9RnZdX1K!aOH4Jf2)Gm5i>|*A7<6QOX9m-{ zy1dcqrIY5Cp6HnwObnzqlf{<#+IWVov>gUvLzyj&eLc{v@}*V`>ZMnu2^OFrLdTep zJ))`U(^0Zb?UC)j?e!$~RgNodg=Ylw#3*FcSztMwtZQ%m+~?u`=O09h6N$d*_g^RM z_Oy{-kFDJ1Fi`4lJMgzfWbH0skiL_7h(%{7*)+Z%Bp8a`$Plm5-r5s@XrvKO-)hxNk2Rahk`@QP;<5MXjch&|>hD@AJyC)4HhQ>I=<5T>96R`s|PnXJ>a$&b-;Wob; zj$z(`+%cuz9rZjTkHdq{OUZ5ylk=57mqO^FsfEMe*r}^8g(`@M;K=^ zYiP3w3A)sgbZY3YAgQcI+<}2;U=hL`-4FO55$gxVH6utPB7*Xo2#`^We7VP}RvtJ7_X5~3nzKs!HUe0d zWpeLJ!jA@~rt&%TLY|Kp^nNIf!DuBQd0&I^VLdoTs6;HGL$fI^n{;kV&zG)m$;HIN zieMXwNRjvy!YC>WluZT`Rw?If%l6|a+uLH(e=TGSM`)929WC?H!-q zVs!DV;b00DTrIRAIhg(5<}xI)+}LqzuvAjGXLvXYBWp)~uY&Sr{ZJO^60L7w8f6j! z`abGVra(pEGL|v-I>F9#vTR)fr4O9Qy{D5}ExR=(%vz#orwXMhr2(7rYkaD$`=ONH zcIrmWS|5!A)>z9?w_jAfR-1OTrE$;0Ei_Tf%-8XHSlVWE`ZtF9jD|MPSr_@nv+t53 z#KJ>XzU;dTU>E8&^AW>u!)uF?!`m4P9#<j6cO-h?B3q6aF^Xu(|GylQpLb=xs7dqm=foua)7y& z-j1j{b4a)ia=RuUH_s*X(+g*zRqS^|W2ROmBmsX1=DwN)wlQPWm!)eLbgKAckg4~o z^diQlrT#f^W6AUmwhwl=7;8l0*5GrU&o#kp@$*X)qw_p^TLA-Gjm_J|T`+g{puSDnr2-aU=&` zFv{BBxWZNZjauoIlD`pX;#qOcyJcgpGsh*5ar?hXj7VoWSSqsMD!2<6oow?iqK`g7 z4&mYmMx-ODQKaOu3JWKoPz+9!uFx6P{)wKDf5Df#gYRlOC0db^+V;B{Su+5MifzA*AQH`4yh3)#bm zS8ub1Bkl=PNky2cz&iG+MN}Aq93!RjjsNk?qpX(Pmf|MDLx;*J+Y_;sRh#7_krWqzqEY#1uAT&Ibk7{r8)5up^*jpHt=bp0t z?K)=nfXdJ^J$L2e{;4ItaAjmg?I>nt941__GH$fEoO?K5ddwk$J3;C0+PndQLbix5 zcr2#wn^g_NK|qfpbgHcIJ`GZ80z{6xt?D z?d*KEczX1Uo0)OJce7on5)1Z>6xwOIynm4jD+LuRgK~->Qscq+Y24E6Uxaw7YHC9x z${2^*|47jaQ40y(N#mG9BXA1BQ23K_z+TisrZ-q65(MMPElI=FBSRP@);ZMIPemgn ztm&unG%rdCT#2|7kW%`U^HLEZem2!fosWn^ExRZ<7$&~5pNKI0E-7+QzZG?_%>L@7 z>ltl9Wwct|mvXejN`+B!Yqy0& zbU!1w%l^6lVfFR8`-Dojqvv{rw}EG_>I7|W$Hbk&%EhJMjY%ZX5kgJluI2DsNAh7P z>Z?L&>?2fV)nsM{YVK*JZHEMD8feDKt`KSugd5nqZ3t$KF@-}D3T%vCwpRFcZa&~1 zNsFC8+7*iqLKR&SsYYQT=xRzPk*xtwR^Vw>#FQF*?)wUlfh2zKZ+wdVqG%b*oX}1< zT9ib;Ae~3w!>C%0kb)r3eXe3&u^>}MFEB!dm)z{QWVm=2SU)>Qh+wr@l6?<}+oPz~ zQUsYIdX{Z@m?i+{~F}=Y8vStX^&$uj}1_|d56ESFue3j9MDJa z!D&+1BG9s^5`~vH)HoZI5aVLZDx*Q4KodyAcW=(DXiHL_$7*xYAATMzQb9ZH=E?7y zEpx1cP@~ffu7&zUMh#@q%`5UepW8@WM|tnW_}}!_?l+t)W#4Ssq=$v)#1OBN$FY7~ z3I*;C1a+O))N+Z6=8_K(98O?5&)o_5FciU#U1LxEld-PJKZNTE4f?@cWg{5F6G6yE zHwvYe_H@v0+jLpJ@UGG+d56Wd{ZcNQHG@O) zYHWTnLOo9?WioCC3O#CR;n0oaYSvzKy*82}ZgsnE^0;9i(fMQWMMS4hli5>+f4-0c zZ$la*-&H@p#I5%0akdhnO)lR^U$HmQ-tcF!n8S%AJJ}K;;0DKTFfDs=@5I;#AQy0O zakZYD|ZCsnygXGOLIQQ7MJ+wkU@KJCw&#FwCho@Y$ z3!)0=ag{Llm(QR140U0#ve;zI)FWFf#OeAy2L%UXWl{>m?P3q{r(sH)_If<@h_ka4R#f9cFfrRT?jZs3q|QP_;rmmwS&WRlWX&g_KdZ-Vm} zBKN7{OkWTBs_rg1g{VK^GjP>4)|a-nmm_Z5pjGot_?^O6^UHea2{6H(WaSzUrA%|K zZPF?Wk7*%gPt~c+|FRn?;&xUns#%BUIOOSd7Rha%_MOvZSEZFHT{uOMZo0#uj4rN& zRuEOT|FPoVadab{bl6rcs(bFj6;n#3r`wUmT@;!m(}uI5qV>726BK#=cK42PfMzgU z6df%gpj!e)_=hH33gkoy7cc$vQiWu)Y}IzgpT|hvy|#TAdYV(jQkHEgIgCIcxM4=L z7;AH_Gx=tQNdur0%K~q0shu`0%t5*8k3cSFy8BH%f&Tb zYMd4--5uL1gH1h|fP%6mF+j@r~PJ&TK=J}gjnnZJ(B?!O)R8RACVp>iwJM!gb zWoJw8y#jw1yh~WD0 zqh4>C4?TX(cM(%Fut9fn8cVMRhwo0j-?X~8v!g@NO?n)fhJ73u+WSe{n~#H&^H_j5 zPF3zFNcn&Si2o?z)M;DZ7tNQm`Z;^_^#aJkWyG?Xl$zuVXd;&OQ%KHrU5FJ4f!wmgLQ?+aC+1$Sl}cZwyNj<|tZ(k%);bVN4P{<%M)^8D=hCnxlkarlRUlg`5RZj5{U4 zG|73sOOB&wL{`s?pU@A?1H0_U-2Dxs#RX>FV_qUN~%TRZbd0o|sHE{rR@}61$2T!;&u4_?1oBKm0v);2a&8$#W{B70 ziP7h(bVnPlvkjj#a{p@EY`?fLwrDVdOgc4#LzBzYB|H0q9T$nU9F=}>SDjZ@BoP7k zP6^n31NZabM23g%r_TITNPS`a;Fb%TsabM>a-_w#Prp(#_r!1f=71{rDJWH|0bWQa zFk%XlPB_2YL=Q8)fHd7>B{)jFdo=Zu%#DyxJTC6Lx2IwQUFNZIa^q}IZV-DkXD zDH%)nHIDyzkiyVP6U#7^g$GWcv!c?uf1r6V%)c_`j4=sfoWimR9k&|r@O0Vf z*ti5p1qwo4DaC|xRp{8>5(G3~IOwBmBV-L>k53VfyVz_GOYL0*Q}i^LXCVFmIJaC< zX+w1Vn$j*lAzp2+ner!amuD(3d7Y?Qw64ez$maqXhyf8n@9_b?_pZ*9s?Wc<^yB*Q z-{wf@db^-x#|umIZ_K>e*$Gm}g6O@dp;$_hw(zF1ff(M5T+>2<3?TVzsX}!q?oXMOSC+=*yp^t&oIl<$R$=arN2V>ttQd!$@beMg(xTLAr)sF zU;U%P4(W)F_O@tB4{{k1hRR-?fD)N+twnC<3QVD!Wxq1vbN$?c4%&AAoI8-`QOc4hOmG66Uy1UZEIC=-P)3Av z6&P0j_*$tt0wn12k#b0}`4Bq-Ss5rnXbG8%_syD*HF&E$_5$FIO}-|&&@G~y_8=nfNF=E2D)5_*>$4)uz?hbdRU;7GC)jlsZZ);d*=(!o&rX@Z-RXJPjIVr$Nh zZaa0QsO3s$JvOxJfK^$aUg_86`zR#jl0(+x+j@DlkK|$~tcA2gG&rzee<@ZJw97Q> z_eJZgiH>&7U$Uh(_h^TPExso6)u3#oWc+DFOhNkyYYcI%(@GxCMmS_KL@3WY)rJ&I z9BH^yHyK5k=HiwhsUZq6gkz`Zj4VBTu_Vu*{>+{8Y3{eAM#hC7CuPSs(Xjr{!|N9lCmDUwe8S;J&b0=dSb zSb%I2=G>zTI9`7^^kEKF=AX#rr$I1XFiy zh=UHoy*4FhZt@*EzP#iL;m9DCPc{1aN@8{M{Qc(bd*_b(1my*=Rz~$m>Mr@@``oFWZ3_yLg;4&ugm*O3nJMH8L!@qly8YZ|zA1$*>&-Kc|Z6^d36M z`B?xyCHkkoQuy+7tASUEDh1}XP0trJsU((rlH{yoHJ&1cAqwnybBNw7&w2DquNAyE z-V}HBActqCw4W2jjGU6?zWqD9EafH_5B~pzRJqheU!uW01$T1VJ3;q=2BcSt*ct5 zJZ@&&hMRWgblo{1zg9KXAiMP}#TTfbR>{-F)&{^HTvsaxMthy02xj6AMC&w2u5CgHRo9y+0?_Nu)V0tAjc`cS8*$JsHkLXmsd$55Q z#uK1}-gXAI-DtO6=PxyUQx8RXQ1;H`ECxhw)FuK977`X0GV5$lxpfsfjD!#Ilu*8G zsa(INUomi-wB5CqR{1K_jQi3Svv&)(eRY|{+_P2GpDnEVt;+yhAP5?h`-G)g&*h!T)AZzx-8NpvVT$-uV_KdI-Hr83Lv9L zGs4^^2cebmdT<`s8|T{Z2F8i3MMm0^otb%MmK-0Qb2!hHCEEH2sUs}oiuz$ghcK&< zi+QQavP%}gdxP*x8a5;rXA2D7IE_wHH>OUEL~RI3>q z8kODpDBN;CO!Y9U7Gypae+-KAIHS6B40|jmZbvwrH(sA7jkA=?*P%2X$zx%1XbO2_ zu2qjW?2MBzssq(F?2LmyE;)A+{PabJ#FvB58f@($B;6X*axpQj&1uYEFnV?-^>t?o zK;2hWxx>26&>fjKZkc2itv}SfS z$Z{XGqZoz4p;PGX~bacRF4V{ajIjB^mjl8>QYP(qIBhO%dhmp9Q1+h)Tsp{i-I`6O@fFgcm- zJG-%&7ZJY0to_`UkkuyIoi7bh+aKJKvD_Zi=lGU5JcU2oy}go3hXO|^uPGHody@t)qJZ8feM}*>XpR8k%jF^0o7Si+V!5tc&nf;-+T7Ke z&;qU(^}t>AFM>sHQfM?HFpgWkTM$Pj@JLa?3ysmKAHQzv6!w4bR9=zGIV5DQg7)uZh?(Je~1GcfeedOTH?r`hnYKz z)WSo~ZtRdiSVnSM3pe-Nu>KSdLS0wtAzlJA9+veo(qM5~>+>7t`LI}+BvF?~raEr> zsBAh5d=ZvKmYx#+#0Gy-JM`KoM*#}#*Bk{jA7|xsolRY4Vogf3TLc;G>|g=d4M(}u zwyY|?;71(Mk-FRYgUwiVt`t>7L^?NyVIdw#8Lav^IqC^2KVLXzt3uliPYk$bt#w81 zI=0yP=Nw;%YnJhM6#Ea^9m*d|m0<@BCe(7yRePU=>%XZGDqH4`)Xb1T3`9glYkl~O zPL7Wc9v&WAmn=cTg?6mS_b#`N@Z?kHW)LnOGEQT>nKe_g>v+;p2gPNAQ8*IYY%Ka= zb|s}S+2U)%D)n<`CxehFN6iTMY{mj@WiGgHih9k(#CbL`WpOz87P^e<%G!z+_jQCe zlFXvqjIe@)jh)J`pD9GNi25?_`TaB?6=;j@$=|z*6Tx^|lZ$JXmU62X4?7&fWT0s4 zg!<1XY6#?#G>cX6QuM;NaNI5)4O3v7 zzL=I!);Li$GAP(=nq?tgX=zAF)k617R?frK)%6@>rjlKlp3Cp9*UOZuu0+C8nEwyO zzc821t=SP=69+S1SQ4(0IAwPQh)^NpdNQ8rfg%lGk2D;Dgj^!&()XzD!Wflp%@8$D z@kq;CaKm5#&v>?V=w0%uNB9AhBwla1`*(oV<*RW0{c4%!^Z0G%g#3M3&=@Q8BBniY zA!mfk%qh5u&S+%T+Cl<8BDPwkX%a3hB|p6PiP564 zPam#GW6ZSSnM@0|GbGiar~`{5<1cTW7gVAFS$jRq{lrfF7UChl`Ua)i4Tdp?=<35- z4~UW%4}OS|$+-yu_Ao0G&hu8IlLDmaTJX4uBwI!xpc4-K{4jx{&OD58s~AumC)K9dKmuH`$fv4+L^<1T zl`-A~YRU8rqcwKT3GH8xpEi+7At6A;AV^LgAsRQ(5wQxOl1+9YI2Zp0MzDnAEaMhf zBvD4WqQNrE!#=*Ly4fpL)~W-9d7CGw00kWg05Nvh>E9Wmd~&lvt05AYs=_>u-h2yf zSi1mMIB2D#5?a`^@aeX+|6Q(|Uj~LZRnDs+DGsjdUd%4Qo&VY~>Ss+&LLjDt zHC^r7bTVUz9xM$VI7*NsUyK0zkmsp8tVzH($_(Sp|`EQK1j?2g- zIyjtiG;yL*RX7e`6eY`eExA0>j_>m(OrtZ^m)@=MjodzG+}B<2?6}(S@s`)03X^1# z^$6SR1oV~5d#UE@_2N_MQ?fMhu;PC!#l{J@bFdA^*k{6b8HDIhC!b-uM#rFV!x}@s zMRT)p+xEDziruAz+NM9>;uEs#qI~Nzl&a?Uh86sdzM%3x|+@CmJGu>QOA zlwd4ORZ9ie9Otyt7Vdr7d@x3mY^SDn^qH+BGkT7L`=_YF8(k-M==v1yN`A}+`;;#`G08q#7*$|l z1To~MGlk9=3b6V(WZ8h)gFsh4CA_xrx~_9)lR+{yK8U>eWM%WDXMx>($B73}0zV|3JR z8uYA_`PYR0J=Y)XDU1o`#*pR9ovE=ah)q<_^{W%Xwj!B~88@%-D9aa+{X9X|m2fA1 z&VuPCuy)|NQ+#FVDcbn7(>uI>lCf z%6kPJ8wxL7q9)xBo*SBK=&s{=Qqz?e)k=Eo14P+pVZ-#?D?2WHo)6hWA~o44n~iMG(g0~h1TA_u<$Dbh)eNZ{dB> zP`Z!{6y<;k{K*-n?_30zL^3HTBO&TL!6N$jQWaFZ%kgmck1>*T(<`hvFK_9A5Y?Fb zc3cSxQ1SMgeP+cLWldCDxBogfR1B75>@e`S*Eh|g#cTop)*sepZvDiGbYEuc+9_C8 zcsk)moJPHbpu)l@2Ac%4N*?-3MGZ49c8@GhZ-M_{3tvV+aw06A;-KEm>hOIbTZ&54 zDnSWi&~^c9+PJ2Rg8)zKxPe!C8LJ|Q!rju5XOkd$BHnNrT$}h-GNxnbV)O_Bjp|Rh z80eU`Sw3!{vNjpp=;>Nb0geZ7fWwm&wT-<00ro3rKf*&d zshe+fgH${ubS668E6~qyj=0xc>a5T9{B!lMSJB;cqoy%0(&C8YMZx`6fwd!7 z9B>X7I5#@HA)v^@TzfiNq0iN>VeZ~JzbU=-w8%LvkgMu8i;ECOU$TRJs#nVZSXER4 z?enw><~U$R+?nb3t&MQwpl)_qK-{=Qi<@_YrwEE1VDgybbK^pmHs{c~*F_$v#mGi? zDu%1QXhC~mK2}UZBd|J)hDSw09mbWgfGJy5&%q91Ip6Sc=U?uov|m;}gWF`Ww6(3E zw#Cj9aY460Gu*DicnzAg|CxMq|$FgAt{&5KpB!NIKG#yl-;cC786=zfr?CKCJd zG<#`!8CUQ*^F|}RKF)sFCtr^VQmd%)u&Ix zrAZRuu7gQJ>9YA%s5b%4|9%FAl%1q#jXb@vv-PftDy2@Bf!}WfHyE%r8*twriNd}y z-1G!=B`iHX@uh*9LhN}U320O8K6$_MRRCQRg!Ah4Fz9ptv|? zO$emyRG!i}VlHd&WH7FP<;RUH2P`F$tkd90%5x63G~KUIrD z1zvzL`PzDbX&x*PA_KPx;1DDw|2^H^-Bq>^cw#H1Qe(*8zrJDA6>=_R6Ouz_+T31- z*m!eEzx*MFf3vjD7WE?_^|4W|={2=Y2&iwsPaoeo6q*g{f=IU;iN9`Aqi{(|0!9^K zX-w(|&p!`QM%^ywC&f|4=B6JIU2ln|lMe#T*O;PU+Lw4^x{(cv$0y>i`d2mklBke-dj z#}B}>42<1@FCIr5S?u#3J`^BB9E_okxhG7&AEc<)tK}C7Fl&sq>HC1(Q7q~nzwJ_Bo&{PK_{_-)a?QbRrDJW>f9SVKX0+1cC*fLQobwq6NP zBSfCSs$i>kxm)~zDcdnG{$);4sV0nh&W*L1dsHPdHVula=J=)bgP54a0})ZsyX{9! z6>W7KbLHY-K6SqBA92@H9#B<Po}0b z8Hm8CrI_df+-BVOhQhZ06tSKqM0|oR+HqaNCz@wc%X_|Njw9N-5&#fHtE+n4lA`h5 zw)j^?(R{Jg!tnSM6bQSAMPQx-8a8R_aO(BPxRo*%oegl4v)}>;Ay4j6ia-WM6YlRp zau%fg8N!6TniQ;nUkCG#7SoBgt*ErX|K7_3e5ew@LPYOYX9q`TGU%0BUdUkt1O%mwmqV^QQ(z;jauv1s>W87bya(!@Z9Hd zpVrE{si0Tk0;b#=Kdw9zbzW_Qb-6IiRWe03>=bzaH?T8yxjZJ^GBUlLpW@VqZ~vR3 z*e!eP=~zld&p=`cbHHDR9DuV-jZ$J%|2V83^0M>^h!1~yGV! zB6$fj&tH`mMp_Jea0wMt5QZo3DF)>e~Mh!O|k%1L6#;s0{b!2joUk& z$b9td3`hY90^7G*bbNp(PulA?wOGVDUprN+w9)-+0pH7h8sC@EGWn^Q^ntLrwI$AK zBC%NWvtzaeWFHlT6UOc==uG0Gv4t1y$r(W{bQj4NwfhVa#3~T+KL121>f`LgMUt!) zXXpluAKCZf^?4cm-OO*Bnd+QJYIbc#R-~u80 z9b#-?@IWUZBIrKjV5r1c@ca~>+aO`+B3#1LOi2)_%h+ELKXY^#zU3${`X_e#mm{fW ztsD;HYY#Qbydr_EAB?gV#xqPfLMpQi!Fbi0(@PL-xXzgnrK4l#))_wD{G2a@cc8ti z>)A7*c})^@z3Es4TYlJ2 zXjMW_vu`6KaGO^GBKc~oO1%?#Cw@TH(Jk`X#3f6RtAqw4)1gF^Zjd`Ca2!NlLozb| z?dgm$E8$pCZKZVRG8dxiLna&unu_4zO?eiG9@qhr z9*odVl8D|r)#S6alcuIuGU-XT4mp8BRsKXG+}D~t)Q}7@L6Kqh0NciapUc(Sh5x1g zSbckl?}q@AIAHmAYOx!{p0V1*}p46~2_?*>N%8 zi2!S%j5c{dBsU3CN>S7Py*AOCr$4wjT$ywcSJ4i!@V;0lB37|DulvTh<`nIK2)SP0 zd{R%4+9@OSg>}-!Z*&-AhHzLDiwZ~J!vf%Hj!WNR-QL1u@5R*?hC@uq9a1yGVf9Y) zJPVwk9!%Qy?>r0c^1cForIL%z0?hz_W~ov=0(QOg^E+F+lX=GuSO^#I5=5mJbGMPy z$ufiPm*=czY zHXY4JOKxk`l(%XdS~lHH$}K-|N^pe(fhpAoU0bT%UK}v3mrk56A)PG(6-1-fSVI$I z62jui`?dv<=y|4|V`e?Ss zKD<0nXIIw}z1p*duG=E8gc&%s0&0FMmLfbwCGJn)kW;dBcI4Z^iCo02#&c%retKo? zN@+{#@v&Rrl;0;W^Uj7b;y7LR>dO3wZ#{+EfPls5djVXDd-A!QkG8FRl|A;k0GzKT8yOs}!!4rliMk^K)M0HdITBn!10Gd>( z;zqa4FcstZBzE60gE{97(|v-FE3g$55Y2X2Fe>yfoyQE*3TXxg*$&RMnxiTJgM=Q> z9Zai&cfUw-qOaf7+`Mm)mJnBuES(&@rHlph9QN)x?EVaR@4f<0@}~IHc0^L}eJPNT zj~*X0W@Kjalh5JPA%^@l&{a50JQ=9ia0Zg-#lz*)$q8C2wR;UEP#r*Hnw1z`siWDH(Vyb)`BI_Ijl(@kK0b8K#En! zQn3z*>8)EU%=*KdGhm56y;_bSV<0j9{_pQoh$WCQVasXC0Sqblv$eG~+zD=5J3CJb zlP|g-*UIp;7;t1VX<;k?Wr+`o6vM!UWe6#CtmMwj|F~U&;up(CEK@cz5fdp)o;cAi zTzSZ>76sw@0)K(-?D^pHqi>3AnCYSdv)O{j!WNw|l?4xu;E6i$9YQo$98V?RleaMA zQ$4TU?4N6w&K;k(PW~cNtMmWX>Yc|dzCIQkhU|amal;unl7LC!e;>VC;hnbGdF4qJ zqqW)RQ7&lCNX<$@=*jG{kV9=euS6HqM5~~Pj_8#@b}Ec z;7`!!KNJi1P?7=i_kBCA|CR{#P26vQW`Ul*ehR&kz}!im6|g)2v<*;QyKl{8%h0-DfsYcM3ep2wYDYfnasC0u8UV(y1EL%>&cZv@eb zSZDUxON0Q2I6FgB*>W2=4=r0h2tx)W$YW}#FAG)$uy$gI@7VdV!)h0Ppty}?UtuW2 ztn!}0>T-*G9_AKsMg1kyyA%8l#{abVYw{Gq>*E#RObWmY>P&o8%K3&%iYOTTr_tTM zEL>i1`C6AA{Bvmg;1wp2E6)KcoXW|^Tk`Wzj{ivrU1^>ZzF(B%blY#7Zf!FkV z1hz!X@85oxTb=4(nzW>A5b#3ZBM8~;h0|fYDyESD7*OJAwS>!f4$ghGbP#kb*~98H z*tv|0$+*?If9lxm$1=weHLLtVs;R9Vopa@grPMeM-5PW5Vhu^#^}n#pP8xwlk%68r#x4OS^w6w~M0I15Mq?%2wcL#1)7Q{jkS-;*o# zhUtuNFqabPAYOMBamduzTpK?!dTU~4CfMc%y|x00ckN2ajlI;r;dg(AWhL){PZBXe zV)6iLtG~c*|2!>CvIP89u6)pI-pMFpu54URh+_w9z!S57sZ%{bOA=K`Pa}L#PDhno z%jmSix^Ytd6`;fyJGV1FA9RnMp zupcMN@Zis+9*lY=+YF-;|6==VcCv=gGWygsINfv7;#|3iS9c63vj7uYB{xETMQ2n! zhPE_%C0iKlk9eI3*?Y@IWQy_y(bJrDJOZo&`PTv=3tZKThTfm8zc!G4wRon2tW)m( z43+RW`qo+Sn8i51=Mk`^bJC=> zXh8UMd#NXknWmAJ9D=H(d#hMJ{K~~VoD+LYbkH);2dcbN@4VcMYC^f5H6h3*Ue3-5Br+h*UW(^5q-m6;5n!lFjBxM0|X_mdC@Q z#z)*ZqXSvW#nVLY?QKWw!KF?wss-dY=()SF%Cf5bs576~^uKf^#;H+!8O;fZ$+hc@ zZgor#C_sE>Ca+|RT3&{FdU~!8hDeryfrw$xM@B49>5Yq|58GiN+gtK;oW)x6pqO2B zE0mKBHojcTFjmJI?dt3RX)wr4DHSM0_Zu36uAFkWK>bYgMX*3uA`i%yoc{f~?!Ec@ z@MZ9I2PX8!?*+8p`x#qnb|GGtS-#4TLVB-s!+8jwHlpnp$&Gwmb`pZ^PtPc|Kc+IDC?clpoI#YW$G zVIbB9@9efX`#rc;53z}2d_=c1mbMtrAzAg zfh_=-@d#*R8W4-do~1P#HcmxB8_XHyIb#DizHd1qxm?R!1eS`f*bAoJ*HmTDIaQQsFuX|=<>GIVRyf+k(iRR=8L7i}3BhW1B&$1n=T{xq$RK=a^nB-l=JyXf# ztn}U{KEvu9kJ9(z;>ndPAy|)R_gsh_cRR>fe=A(gg5hxZ+{$Q$aaYQDkMR=ebj_P+ zdncQY9A*KtZ&8uJPTd%@ZG+kVx4gUz1Eb`0KrphnEIYcmaQ6jqB$H}Mh<;F#|7qYfF3T)Vqve!S{{B;CdtiJ8RgmXwsJo}!lo%gJy zvVh6sprry~=!mMyAMa|zqLlB7Wzr|?dOzQI0=InKEpu*Spqb@+{gt~TykiT_J_*Vu zT+B=W!g$RprcogPT{5iSs9*1PuE z&1*ZfaUamx``D1*{yGP=1ziTG8A_+oZ{=^-x$4OjNnp3D4=?WMt9L)L!>H@!sxtsn$oR}T-5LObA6>-uivfPyC-w93(1Q=$FfLD8&h zXbA7X(0VZ4xQ6+w+rn%{K01Z7_rN9Dc&qpxM$Wuq!pS12XA^o>+T zd@6!Q7`+-kMb49m5v~Eg&IpFkbz?LHVh3vDeGDZGLy>|U9{uzOI-9RkpMmmZTpC<# z*gLV8luY0OG;lew>Ff)Uscm$yNyXg@KHlEnB%Hx%Nu_nC(uM)5+9iS)4gvHJ7b8hQ zjR3YL(g!@}Mt56RY1Q!0l-)b%B)6}!nrneEHOW=Z$GDFp-Eiju#r+g5C#L`NkJ-yI z;V3{(F^L_4H%@;<4)Ed6tcP>voXmjm9*?@+{m2Cj&$Uh)89~o#G|JZK2_px$d2ZNE zAnMPwh~9Z9Mz0xEi*Q)lA3by7jaUnqwDR2^wq%eHv@Qf~8epuqyTG_vownn{`0))# zbeHF)QCzi&R*a=HsP0+I^-*kO(Dcr@4_=^a!(wXZNA>w|f&hM(4KfiynG8cL1V=8I z94@Uyd<2WSBO(scz{*P^p~`x7A{$SehpB-m?hmL_x!l~`jy>`M@S5*Rnc;ArU0OB2 ziCJYj*vDa-f_r4DY5lG`j*7j<{GU$2IbL)n6=gdACiK6%F7P0(}>#=_XL=$~|8FZgq zoj@sxs9i_h9mlYy-43}#>*A4}2n>txktpEdRkbliX`)Dw0Kt&a34hEu3_mEwp;5Rc zpW{!!pOfh0C5Qu}ZbNx_tNH>URao;5b+2H_f*C*v2?>jWanh|&?eDTi2167rQVd8f zhM?Z|0nTZfCdJ($#SdeUewhga5?3rv!I{LAt5m%<@3DSmbS<&C!YA2M2Z3 z?!&!-U-Oy*B5f^E<4ZhB_a7Q6v1ER}H7Hi!yrU+UeGlFuGSOcjbLy}4F#Uw)18KiA zE8?O5sKQ5|+?K2elrh~mxa;`1bRw(Tv!x|&Y(lX;w^_2FGR^?QDxY%0?s_)IWPI## z;pdPQ8ofZ99ip?L${0p0w#1*J{Y24z#-|ABHW{)hkPqv03Sv_Nv55zE4I`lNO2h9T zUKX;EB+5TUE@H`8bppXSK&9O~3=YpfPd^KC__=>T|9HM-T=?qGPk2uil2-WcItk?F zU7HNM&?UzHSF?y^RxC;vyW&xCWaZ{^@ecTlh$SV|UhhZ{VP#yr=O7!imrVnbimv}c zZZN$I#2aC@!>9XVqUd3ImoUrgmA3+;#s`rpH8XZKQsp6V-+xlsbv%iHGZl* zOM+U%znHW5j|%_zR+KKo&HUV3i(|CPv#Qs{8mCyZ_?~D=iiM7LkF%%wczNl)Zhc&w zqCqJ=$NB0FnrH)63*9@X<~Lczc!8tE@5rudKU?1DLL3Ou=@ph%C@)|wDx?#RAyF;0 zHoGs%V99<%lf6~FwY8HAE+uapnc|?F3Y|Jz-z*!Ky$}aD#Hx^X=+<1SE`7Hi^g660 z1XW%ahyal(xDdHH!Wpr69j5VY{e9@bF=a@@R)JjOY;UF#f&!A=;WQ$;cAlS2q_nOs z@r;D2)6G1U!F;!@kWi$askch$FOtf;$I;0VgkRjAlMorr<;k%jmh|kat5Gc}D7pF- zML?ViY6hJEdLg+a2-B6v>wWQ2zSS7Q60Ws!5@=eAZVAQ3GOM%J>~XDc2)-+6>EPkPfv;f*07*gJ8(6#&t%`<i)(4ov%~XwtE#n zuvq12g8~_LVvz_*rS)@c9$_Uj)vwoTB~6G{RHX;+g|s{zeTztq6KHU`r)Gc zZ%9-MyGTl*TV0;mZO-OIq+g?5NicZyJR7I`u4;z9LhYIT7M;(MML7tPnc)33C)T!oIN$(Xl#Y}}QWc*j|KrKWQ3y?2IYtkX6>>_kv2#X)~ zRKXM=HLAICu+XqdjhrNFx!^xp z7rU7CKQh{@YO!BmlW?|pDkMbx+qD+fsg$?D*ZDWFr>AG;&xh*;PCOhq}e5C(oF_XQkT)f(YuVv&kd*0W`e$ErD)zWRD(p-Ar1!()^mY70jT zhNArG??_aJ7pTpq07A?AGVCq@qi<$hf}Ga>2NaH4iGig6zkNx-Lng4 zmd&8d>Ud7$f07!%x%=5f41VN~61U$YTbm-N`^685C4)Utq7|@?HCIJ>= zxE4Ru+&lC|#e`B|3;8&sA&D|I_|l!w|Vx-b)E@Cj86W z{b;s?plHF%!J`s3J0N`_Y}ukjn*xj!5%#GEz+43kW(rQ!mY0`HE0mU(e}p`Stgo3C zlGkueJ5_ylC0)pSo^Y%KEk!rf@B{=Hz>?nb{O}hFo`84RVnatNnub<`5(YpJUFvTbtpj#~>7Oxd z|8(TGCE{w$N_kJDn}-MSLv_QP3}ca{Vy`waA;DiKI=*S~hFl#D^kT@3j*YeA83zoq z51yPy$qDaIva6&YmROg3B8WCVI^g&zfjD4a+t{%!-lI}6CGL&&RbX0G@v9PU78ZPO zc={}*e}_4|h3VL>%K;HDkFuVM0O^#hiU(MGS9*xJ1z+n8nFz#LuIGj}5N%1zBz`Sg zZYY=PWWb=NDN5(yOp@J!4c2b0_(*{%Bl~7x{(^O;t13B{Ra^`!GZ&}+PNhAWNiz!=ZCTeb~hfe8*kPK z8WW8*bAQil5V~Atd|GeVve)~mhc4uAeq6p=dB0-9K~x`UuqYL0SM(3ggr`86uliyQ zgP}UqAJt8LtWW~Ok&~pkTThzAAQ(IVaL^ScFM*O)$-YsI{gSAln(se31VJ^DfYSxw zd`p)$&1s{8W1Uf>qd<#ABDH{`t0@x{RhJZat-T$zRBE3le%CY2VK5ye9UCnXx+Sc|B`vO za3WLH^H-j1w=1elZq4wHmvs^NG@FztTO$6Sp4_UVmLjh->Pm8MwCxh|YW>&L8UDZj z%v%(i9@slM&1OTcdE=WVwbj)}@x#M&&J|X?LPCYfWo!la!BnJumUx+07#S>7x^hKJ z{h}i8yvvL$Z(?F6`d4bz0J)|SlLlm^rY!mR)4Aws6snIk*8*WdNe zmQ^EMDy)*RLfO zMygH~qkW^EJJd60&cs_=TPKiEXGEBL7Rax|b%go@b2}UqP77vodEezm2c$o^q?eBs zy0cc~)H^+<#kcp;K-8>TKL#GMSBEd{Ag$NEGYDPfpdxe>!*LHax4ODVD_jkOSI4%C zL1%$BLtmj()Qe>#=>5<35jb<2VU*;eP4-DpX1wvwTc@QfefvDMYp za&9_K9{8uq`;P_;AG#S6w*LDn8T*bo3T}|I!>QxLCbAQUu`zc#m&e81d&dYTdc~Zb z`lrX)*!i!L=gNgp&!+oh?2x^MzW0_L2Fu{&H@xYY+lRtay~d4?zYT3{Lb`!n@Sko= zg2sopUoEB1DWABW+C@MG3A#pree!n)D}SC8PyvIggFtU+v@U)Kd!yi`u9pNoGUvzV zP{u3Y*<60*U(Qj-6Ce8*9a*??(EJH*pAa#}v1Avn4RH~tchEO_?WaXYpk*f@WQaXe zlp}Aa>PQI;p~3$j`eYu*?6W%Gx0!RHu0>}@+2Su}giSJpj^xhMu4!N9M5 zJHIa}FE78YXJ&?lsV$%`#*y@w7)u1`5IyOLPo`W>UK_@cgWuf|=wzx*L+nBvFe*^?V zP9dlz)IcCwr(f38p*ecW^L&HAJ`@v!BBtiC(iE%2EGML^IxM92XYsVrZgZfmes?rV za0Ak;-;NNSxr!ydh8hUBzom`GIT(@yYgM`TKlpUS;>D=v0pAa zTxV1Gt&Ul%Tay==eWJ`?d?YG9!Tjs}3-#s*gzn{-$V8C89}RMC9&|F)3$g86_t@YVy7A0`VIQr#_(v_UZYF5o&>jx#NIj5eAM7dXr5~=n)-*_ z@I=2`OvDL&UrL+HVebo{mh&GWrR&$PcLFe#3U1>G9n+X^O13ywpnmw~S6B1Q%}_Ph zQ6Q2=o`>8^E+ZwUq+|i%33)H;Npc#aT98@M*S8d2-+HtZFn03AkW|{Q!6qyG z^>#V^_l!HGWS3j-hyEygy}K7`I9OS^5OVBy$ZfU_D3^Z@Inmk5#JtEZWp%li>83Di3gMbY zE**u?HMj%+t=-9cF6rLYRR0uxHk-jpgnTEugRnt~gI0WY8$%OEluf=@RaPp$`6-6+ zn`4)~_rEq4f2*tCu6sf2neQ4PnNaU;OjY~9 zh(kj|4~&-X1MIL3y4QiGzL|eYwCLtr zdO-0*W8jHlDm>#=6`uHD?m9{{80`pPJcY70NtEPHx|4q7C;RabHRNq>26W-bwVN`z z4#Rv~#WvLq*2VK6my~)@%XYp!KYDJl?o^IHCxk!t6^ctAeNgT8D3JlHblsbuoSYOF znf1bwBdtns@!DA9Gy1<`p;(;UGeAfgE!i3^g@G>>;R-%c*G(n+WK}@o1A#dRL~V2J zHILzxP)G>)f0WR~pws$e0k+j+h;zor Uh|lYE0tCEn-!L^m>)S{F56q%YMF0Q* literal 64932 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

>BkWU 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 YsJ>ZkHKKuFay{g|jFNPb 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 Uh|lYE0tCEn-!L^m>)S{F56q%YMF0Q* literal 64932 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

>BkWU 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 YsJ>ZkHKKuFay{g|jFNP Date: Tue, 10 May 2022 13:19:18 +0200 Subject: [PATCH 21/25] Sync with PrusaSlicer-settings. --- resources/profiles/Voron.idx | 2 ++ resources/profiles/Voron.ini | 54 +++++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/resources/profiles/Voron.idx b/resources/profiles/Voron.idx index a593d2fb4b..a169eb751e 100644 --- a/resources/profiles/Voron.idx +++ b/resources/profiles/Voron.idx @@ -1,2 +1,4 @@ +min_slic3r_version = 2.4.2 +1.0.1 Added 350mm Voron v1 variant. Updated max print heights. Removed redundant v1 volcano nozzle variants. min_slic3r_version = 2.4.0-beta0 1.0.0 Initial version diff --git a/resources/profiles/Voron.ini b/resources/profiles/Voron.ini index cd0fbd2d9a..e34da50100 100644 --- a/resources/profiles/Voron.ini +++ b/resources/profiles/Voron.ini @@ -7,7 +7,7 @@ name = Voron # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the PrusaSlicer configuration to be downgraded. -config_version = 1.0.0 +config_version = 1.0.1 # Where to get the updates from? config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Voron/ @@ -72,21 +72,30 @@ default_materials = Basic PLA @VORON; Basic PLA VOLCANO @VORON; Basic PET @VORON [printer_model:Voron_v1_250_afterburner] name = Voron v1 250mm3 -variants = 0.4; 0.25; 0.3; 0.5; 0.6; 0.8; volcano 0.6; volcano 0.8; volcano 1.0; volcano 1.2 +variants = 0.4; 0.25; 0.3; 0.5; 0.6; 0.8 technology = FFF family = Voron v1 Afterburner bed_model = printbed-v1-250.stl bed_texture = bedtexture-v1-250.png -default_materials = Basic PLA @VORON; Basic PLA VOLCANO @VORON; Basic PET @VORON; Basic PET VOLCANO @VORON; Basic ABS @VORON; Basic ABS VOLCANO @VORON +default_materials = Basic PLA @VORON; Basic PET @VORON; Basic ABS @VORON [printer_model:Voron_v1_300_afterburner] name = Voron v1 300mm3 -variants = 0.4; 0.25; 0.3; 0.5; 0.6; 0.8; volcano 0.6; volcano 0.8; volcano 1.0; volcano 1.2 +variants = 0.4; 0.25; 0.3; 0.5; 0.6; 0.8 technology = FFF family = Voron v1 Afterburner bed_model = printbed-v1-300.stl bed_texture = bedtexture-v1-300.png -default_materials = Basic PLA @VORON; Basic PLA VOLCANO @VORON; Basic PET @VORON; Basic PET VOLCANO @VORON; Basic ABS @VORON; Basic ABS VOLCANO @VORON +default_materials = Basic PLA @VORON; Basic PET @VORON; Basic ABS @VORON + +[printer_model:Voron_v1_350_afterburner] +name = Voron v1 350mm3 +variants = 0.4; 0.25; 0.3; 0.5; 0.6; 0.8 +technology = FFF +family = Voron v1 Afterburner +bed_model = printbed-v1-350.stl +bed_texture = bedtexture-v2-350.png +default_materials = Basic PLA @VORON; Basic PET @VORON; Basic ABS @VORON [printer_model:Voron_v0_120] name = Voron Zero 120mm3 @@ -239,21 +248,21 @@ retract_speed = 50 [printer:*Voron_v2_250*] inherits = *common* bed_shape = 0x0,250x0,250x250,0x250 -max_print_height = 250 +max_print_height = 230 printer_model = Voron_v2_250 printer_notes = Unoffical profile.\nPRINTER_HAS_BOWDEN\nE3DV6 [printer:*Voron_v2_300*] inherits = *common* bed_shape = 0x0,300x0,300x300,0x300 -max_print_height = 300 +max_print_height = 280 printer_model = Voron_v2_300 printer_notes = Unoffical profile.\nPRINTER_HAS_BOWDEN\nE3DV6 [printer:*Voron_v2_350*] inherits = *common* bed_shape = 0x0,350x0,350x350,0x350 -max_print_height = 350 +max_print_height = 330 printer_model = Voron_v2_350 printer_notes = Unoffical profile.\nPRINTER_HAS_BOWDEN\nE3DV6 @@ -282,10 +291,17 @@ printer_notes = Unoffical profile.\nE3DV6 [printer:*Voron_v1_300_afterburner*] inherits = *common*; *afterburner* bed_shape = 0x0,300x0,300x300,0x300 -max_print_height = 230 +max_print_height = 280 printer_model = Voron_v1_300_afterburner printer_notes = Unoffical profile.\nE3DV6 +[printer:*Voron_v1_350_afterburner*] +inherits = *common*; *afterburner* +bed_shape = 0x0,350x0,350x350,0x350 +max_print_height = 330 +printer_model = Voron_v1_350_afterburner +printer_notes = Unoffical profile.\nE3DV6 + [printer:*Voron_v0_120*] inherits = *common* bed_shape = 0x0,120x0,120x120,0x120 @@ -455,6 +471,24 @@ inherits = *Voron_v1_300_afterburner*; *0.6nozzle* [printer:Voron_v1_300_afterburner 0.8 nozzle] inherits = *Voron_v1_300_afterburner*; *0.8nozzle* +[printer:Voron_v1_350_afterburner 0.25 nozzle] +inherits = *Voron_v1_350_afterburner*; *0.25nozzle* + +[printer:Voron_v1_350_afterburner 0.3 nozzle] +inherits = *Voron_v1_350_afterburner*; *0.3nozzle* + +[printer:Voron_v1_350_afterburner 0.4 nozzle] +inherits = *Voron_v1_350_afterburner*; *0.4nozzle* + +[printer:Voron_v1_350_afterburner 0.5 nozzle] +inherits = *Voron_v1_350_afterburner*; *0.5nozzle* + +[printer:Voron_v1_350_afterburner 0.6 nozzle] +inherits = *Voron_v1_350_afterburner*; *0.6nozzle* + +[printer:Voron_v1_350_afterburner 0.8 nozzle] +inherits = *Voron_v1_350_afterburner*; *0.8nozzle* + [printer:Voron_v2_250_afterburner 0.25 nozzle] inherits = *Voron_v2_250_afterburner*; *0.25nozzle* @@ -652,7 +686,7 @@ fill_angle = 45 fill_density = 15% fill_pattern = gyroid first_layer_acceleration = 1000 -first_layer_height = 75% +first_layer_height = 0.2 first_layer_speed = 30 gap_fill_speed = 40 gcode_comments = 0 From 12a54251c9534162cdb90d46982daa943f4f9372 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 9 May 2022 12:51:58 +0200 Subject: [PATCH 22/25] Extend kdtree with k-nearest and bounding box queries Also add test to verify it --- src/libslic3r/CMakeLists.txt | 1 + src/libslic3r/KDTreeIndirect.hpp | 463 ++++++++++++++---------- src/libslic3r/PointGrid.hpp | 74 ++++ tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_kdtreeindirect.cpp | 142 ++++++++ 5 files changed, 495 insertions(+), 186 deletions(-) create mode 100644 src/libslic3r/PointGrid.hpp create mode 100644 tests/libslic3r/test_kdtreeindirect.cpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index d2ecefb9c7..242378d6db 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -212,6 +212,7 @@ set(SLIC3R_SOURCES PrintObject.cpp PrintObjectSlice.cpp PrintRegion.cpp + PointGrid.hpp PNGReadWrite.hpp PNGReadWrite.cpp QuadricEdgeCollapse.cpp diff --git a/src/libslic3r/KDTreeIndirect.hpp b/src/libslic3r/KDTreeIndirect.hpp index 36a157456f..37c10827b1 100644 --- a/src/libslic3r/KDTreeIndirect.hpp +++ b/src/libslic3r/KDTreeIndirect.hpp @@ -11,231 +11,276 @@ namespace Slic3r { +enum class VisitorReturnMask : unsigned int { + CONTINUE_LEFT = 1, + CONTINUE_RIGHT = 2, + STOP = 4, +}; + // KD tree for N-dimensional closest point search. template class KDTreeIndirect { public: - static constexpr size_t NumDimensions = ANumDimensions; - using CoordinateFn = ACoordinateFn; - using CoordType = ACoordType; + static constexpr size_t NumDimensions = ANumDimensions; + using CoordinateFn = ACoordinateFn; + using CoordType = ACoordType; // Following could be static constexpr size_t, but that would not link in C++11 enum : size_t { npos = size_t(-1) }; - KDTreeIndirect(CoordinateFn coordinate) : coordinate(coordinate) {} - KDTreeIndirect(CoordinateFn coordinate, std::vector indices) : coordinate(coordinate) { this->build(std::move(indices)); } - KDTreeIndirect(CoordinateFn coordinate, std::vector &&indices) : coordinate(coordinate) { this->build(std::move(indices)); } - KDTreeIndirect(CoordinateFn coordinate, size_t num_indices) : coordinate(coordinate) { this->build(num_indices); } - KDTreeIndirect(KDTreeIndirect &&rhs) : m_nodes(std::move(rhs.m_nodes)), coordinate(std::move(rhs.coordinate)) {} - KDTreeIndirect& operator=(KDTreeIndirect &&rhs) { m_nodes = std::move(rhs.m_nodes); coordinate = std::move(rhs.coordinate); return *this; } - void clear() { m_nodes.clear(); } + KDTreeIndirect(CoordinateFn coordinate) : coordinate(coordinate) {} + KDTreeIndirect(CoordinateFn coordinate, std::vector indices) : coordinate(coordinate) { this->build(indices); } + KDTreeIndirect(CoordinateFn coordinate, size_t num_indices) : coordinate(coordinate) { this->build(num_indices); } + KDTreeIndirect(KDTreeIndirect &&rhs) : m_nodes(std::move(rhs.m_nodes)), coordinate(std::move(rhs.coordinate)) {} + KDTreeIndirect& operator=(KDTreeIndirect &&rhs) { m_nodes = std::move(rhs.m_nodes); coordinate = std::move(rhs.coordinate); return *this; } + void clear() { m_nodes.clear(); } - void build(size_t num_indices) - { - std::vector indices; - indices.reserve(num_indices); - for (size_t i = 0; i < num_indices; ++ i) - indices.emplace_back(i); - this->build(std::move(indices)); - } + void build(size_t num_indices) + { + std::vector indices; + indices.reserve(num_indices); + for (size_t i = 0; i < num_indices; ++ i) + indices.emplace_back(i); + this->build(indices); + } - void build(std::vector &&indices) - { - if (indices.empty()) - clear(); - else { - // Allocate enough memory for a full binary tree. - m_nodes.assign(next_highest_power_of_2(indices.size() + 1), npos); - build_recursive(indices, 0, 0, 0, indices.size() - 1); - } - indices.clear(); - } + void build(std::vector &indices) + { + if (indices.empty()) + clear(); + else { + // Allocate enough memory for a full binary tree. + m_nodes.assign(next_highest_power_of_2(indices.size() + 1), npos); + build_recursive(indices, 0, 0, 0, indices.size() - 1); + } + indices.clear(); + } - enum class VisitorReturnMask : unsigned int - { - CONTINUE_LEFT = 1, - CONTINUE_RIGHT = 2, - STOP = 4, - }; - template - unsigned int descent_mask(const CoordType &point_coord, const CoordType &search_radius, size_t idx, size_t dimension) const - { - CoordType dist = point_coord - this->coordinate(idx, dimension); - return (dist * dist < search_radius + CoordType(EPSILON)) ? - // The plane intersects a hypersphere centered at point_coord of search_radius. - ((unsigned int)(VisitorReturnMask::CONTINUE_LEFT) | (unsigned int)(VisitorReturnMask::CONTINUE_RIGHT)) : - // The plane does not intersect the hypersphere. - (dist > CoordType(0)) ? (unsigned int)(VisitorReturnMask::CONTINUE_RIGHT) : (unsigned int)(VisitorReturnMask::CONTINUE_LEFT); - } + template + unsigned int descent_mask(const CoordType &point_coord, const CoordType &search_radius, size_t idx, size_t dimension) const + { + CoordType dist = point_coord - this->coordinate(idx, dimension); + return (dist * dist < search_radius + CoordType(EPSILON)) ? + // The plane intersects a hypersphere centered at point_coord of search_radius. + ((unsigned int)(VisitorReturnMask::CONTINUE_LEFT) | (unsigned int)(VisitorReturnMask::CONTINUE_RIGHT)) : + // The plane does not intersect the hypersphere. + (dist > CoordType(0)) ? (unsigned int)(VisitorReturnMask::CONTINUE_RIGHT) : (unsigned int)(VisitorReturnMask::CONTINUE_LEFT); + } - // Visitor is supposed to return a bit mask of VisitorReturnMask. - template - void visit(Visitor &visitor) const - { + // Visitor is supposed to return a bit mask of VisitorReturnMask. + template + void visit(Visitor &visitor) const + { visit_recursive(0, 0, visitor); - } + } - CoordinateFn coordinate; + CoordinateFn coordinate; private: - // Build a balanced tree by splitting the input sequence by an axis aligned plane at a dimension. - void build_recursive(std::vector &input, size_t node, const size_t dimension, const size_t left, const size_t right) - { - if (left > right) - return; + // Build a balanced tree by splitting the input sequence by an axis aligned plane at a dimension. + void build_recursive(std::vector &input, size_t node, const size_t dimension, const size_t left, const size_t right) + { + if (left > right) + return; - assert(node < m_nodes.size()); + assert(node < m_nodes.size()); - if (left == right) { - // Insert a node into the balanced tree. - m_nodes[node] = input[left]; - return; - } + if (left == right) { + // Insert a node into the balanced tree. + m_nodes[node] = input[left]; + return; + } - // Partition the input to left / right pieces of the same length to produce a balanced tree. - size_t center = (left + right) / 2; - partition_input(input, dimension, left, right, center); - // Insert a node into the tree. - m_nodes[node] = input[center]; - // Build up the left / right subtrees. - size_t next_dimension = dimension; - if (++ next_dimension == NumDimensions) - next_dimension = 0; - if (center > left) - build_recursive(input, node * 2 + 1, next_dimension, left, center - 1); - build_recursive(input, node * 2 + 2, next_dimension, center + 1, right); - } + // Partition the input to left / right pieces of the same length to produce a balanced tree. + size_t center = (left + right) / 2; + partition_input(input, dimension, left, right, center); + // Insert a node into the tree. + m_nodes[node] = input[center]; + // Build up the left / right subtrees. + size_t next_dimension = dimension; + if (++ next_dimension == NumDimensions) + next_dimension = 0; + if (center > left) + build_recursive(input, node * 2 + 1, next_dimension, left, center - 1); + build_recursive(input, node * 2 + 2, next_dimension, center + 1, right); + } - // Partition the input m_nodes at "k" and "dimension" using the QuickSelect method: - // https://en.wikipedia.org/wiki/Quickselect - // Items left of the k'th item are lower than the k'th item in the "dimension", - // items right of the k'th item are higher than the k'th item in the "dimension", - void partition_input(std::vector &input, const size_t dimension, size_t left, size_t right, const size_t k) const - { - while (left < right) { - size_t center = (left + right) / 2; - CoordType pivot; - { - // Bubble sort the input[left], input[center], input[right], so that a median of the three values - // will end up in input[center]. - CoordType left_value = this->coordinate(input[left], dimension); - CoordType center_value = this->coordinate(input[center], dimension); - CoordType right_value = this->coordinate(input[right], dimension); - if (left_value > center_value) { - std::swap(input[left], input[center]); - std::swap(left_value, center_value); - } - if (left_value > right_value) { - std::swap(input[left], input[right]); - right_value = left_value; - } - if (center_value > right_value) { - std::swap(input[center], input[right]); - center_value = right_value; - } - pivot = center_value; - } - if (right <= left + 2) - // The interval is already sorted. - break; - size_t i = left; - size_t j = right - 1; - std::swap(input[center], input[j]); - // Partition the set based on the pivot. - for (;;) { - // Skip left points that are already at correct positions. - // Search will certainly stop at position (right - 1), which stores the pivot. - while (this->coordinate(input[++ i], dimension) < pivot) ; - // Skip right points that are already at correct positions. - while (this->coordinate(input[-- j], dimension) > pivot && i < j) ; - if (i >= j) - break; - std::swap(input[i], input[j]); - } - // Restore pivot to the center of the sequence. - std::swap(input[i], input[right - 1]); - // Which side the kth element is in? - if (k < i) - right = i - 1; - else if (k == i) - // Sequence is partitioned, kth element is at its place. - break; - else - left = i + 1; - } - } + // Partition the input m_nodes at "k" and "dimension" using the QuickSelect method: + // https://en.wikipedia.org/wiki/Quickselect + // Items left of the k'th item are lower than the k'th item in the "dimension", + // items right of the k'th item are higher than the k'th item in the "dimension", + void partition_input(std::vector &input, const size_t dimension, size_t left, size_t right, const size_t k) const + { + while (left < right) { + size_t center = (left + right) / 2; + CoordType pivot; + { + // Bubble sort the input[left], input[center], input[right], so that a median of the three values + // will end up in input[center]. + CoordType left_value = this->coordinate(input[left], dimension); + CoordType center_value = this->coordinate(input[center], dimension); + CoordType right_value = this->coordinate(input[right], dimension); + if (left_value > center_value) { + std::swap(input[left], input[center]); + std::swap(left_value, center_value); + } + if (left_value > right_value) { + std::swap(input[left], input[right]); + right_value = left_value; + } + if (center_value > right_value) { + std::swap(input[center], input[right]); + center_value = right_value; + } + pivot = center_value; + } + if (right <= left + 2) + // The interval is already sorted. + break; + size_t i = left; + size_t j = right - 1; + std::swap(input[center], input[j]); + // Partition the set based on the pivot. + for (;;) { + // Skip left points that are already at correct positions. + // Search will certainly stop at position (right - 1), which stores the pivot. + while (this->coordinate(input[++ i], dimension) < pivot) ; + // Skip right points that are already at correct positions. + while (this->coordinate(input[-- j], dimension) > pivot && i < j) ; + if (i >= j) + break; + std::swap(input[i], input[j]); + } + // Restore pivot to the center of the sequence. + std::swap(input[i], input[right - 1]); + // Which side the kth element is in? + if (k < i) + right = i - 1; + else if (k == i) + // Sequence is partitioned, kth element is at its place. + break; + else + left = i + 1; + } + } - template - void visit_recursive(size_t node, size_t dimension, Visitor &visitor) const - { - assert(! m_nodes.empty()); - if (node >= m_nodes.size() || m_nodes[node] == npos) - return; + template + void visit_recursive(size_t node, size_t dimension, Visitor &visitor) const + { + assert(! m_nodes.empty()); + if (node >= m_nodes.size() || m_nodes[node] == npos) + return; - // Left / right child node index. - size_t left = node * 2 + 1; - size_t right = left + 1; - unsigned int mask = visitor(m_nodes[node], dimension); - if ((mask & (unsigned int)VisitorReturnMask::STOP) == 0) { - size_t next_dimension = (++ dimension == NumDimensions) ? 0 : dimension; - if (mask & (unsigned int)VisitorReturnMask::CONTINUE_LEFT) - visit_recursive(left, next_dimension, visitor); - if (mask & (unsigned int)VisitorReturnMask::CONTINUE_RIGHT) - visit_recursive(right, next_dimension, visitor); - } - } + // Left / right child node index. + size_t left = node * 2 + 1; + size_t right = left + 1; + unsigned int mask = visitor(m_nodes[node], dimension); + if ((mask & (unsigned int)VisitorReturnMask::STOP) == 0) { + size_t next_dimension = (++ dimension == NumDimensions) ? 0 : dimension; + if (mask & (unsigned int)VisitorReturnMask::CONTINUE_LEFT) + visit_recursive(left, next_dimension, visitor); + if (mask & (unsigned int)VisitorReturnMask::CONTINUE_RIGHT) + visit_recursive(right, next_dimension, visitor); + } + } - std::vector m_nodes; + std::vector m_nodes; }; // Find a closest point using Euclidian metrics. // Returns npos if not found. -template -size_t find_closest_point(const KDTreeIndirectType &kdtree, const PointType &point, FilterFn filter) +template +std::array find_closest_points( + const KDTreeIndirect &kdtree, + const PointType &point, + FilterFn filter) { - using CoordType = typename KDTreeIndirectType::CoordType; + using Tree = KDTreeIndirect; - struct Visitor { - const KDTreeIndirectType &kdtree; - const PointType &point; - const FilterFn filter; - size_t min_idx = KDTreeIndirectType::npos; - CoordType min_dist = std::numeric_limits::max(); + struct Visitor + { + const Tree &kdtree; + const PointType &point; + const FilterFn filter; - Visitor(const KDTreeIndirectType &kdtree, const PointType &point, FilterFn filter) : kdtree(kdtree), point(point), filter(filter) {} - unsigned int operator()(size_t idx, size_t dimension) { - if (this->filter(idx)) { - auto dist = CoordType(0); - for (size_t i = 0; i < KDTreeIndirectType::NumDimensions; ++ i) { - CoordType d = point[i] - kdtree.coordinate(idx, i); - dist += d * d; - } - if (dist < min_dist) { - min_dist = dist; - min_idx = idx; - } - } - return kdtree.descent_mask(point[dimension], min_dist, idx, dimension); - } - } visitor(kdtree, point, filter); + std::array, K> results; - kdtree.visit(visitor); - return visitor.min_idx; + Visitor(const Tree &kdtree, const PointType &point, FilterFn filter) + : kdtree(kdtree), point(point), filter(filter) + { + results.fill(std::make_pair(Tree::npos, + std::numeric_limits::max())); + } + unsigned int operator()(size_t idx, size_t dimension) + { + if (this->filter(idx)) { + auto dist = CoordT(0); + for (size_t i = 0; i < D; ++i) { + CoordT d = point[i] - kdtree.coordinate(idx, i); + dist += d * d; + } + + auto res = std::make_pair(idx, dist); + auto it = std::lower_bound(results.begin(), results.end(), + res, [](auto &r1, auto &r2) { + return r1.second < r2.second; + }); + + if (it != results.end()) { + std::rotate(it, std::prev(results.end()), results.end()); + *it = res; + } + } + return kdtree.descent_mask(point[dimension], + results.front().second, idx, + dimension); + } + } visitor(kdtree, point, filter); + + kdtree.visit(visitor); + std::array ret; + for (size_t i = 0; i < K; i++) ret[i] = visitor.results[i].first; + + return ret; +} + +template +std::array find_closest_points( + const KDTreeIndirect &kdtree, const PointType &point) +{ + return find_closest_points(kdtree, point, [](size_t) { return true; }); +} + +template +size_t find_closest_point(const KDTreeIndirect &kdtree, + const PointType &point, + FilterFn filter) +{ + return find_closest_points<1>(kdtree, point, filter)[0]; } template size_t find_closest_point(const KDTreeIndirectType& kdtree, const PointType& point) { - return find_closest_point(kdtree, point, [](size_t) { return true; }); + return find_closest_point(kdtree, point, [](size_t) { return true; }); } // Find nearby points (spherical neighbourhood) using Euclidian metrics. template std::vector find_nearby_points(const KDTreeIndirectType &kdtree, const PointType ¢er, - const typename KDTreeIndirectType::CoordType& max_distance, FilterFn filter) - { + const typename KDTreeIndirectType::CoordType& max_distance, FilterFn filter) +{ using CoordType = typename KDTreeIndirectType::CoordType; struct Visitor { @@ -247,7 +292,7 @@ std::vector find_nearby_points(const KDTreeIndirectType &kdtree, const P Visitor(const KDTreeIndirectType &kdtree, const PointType& center, const CoordType &max_distance, FilterFn filter) : - kdtree(kdtree), center(center), max_distance_squared(max_distance*max_distance), filter(filter) { + kdtree(kdtree), center(center), max_distance_squared(max_distance*max_distance), filter(filter) { } unsigned int operator()(size_t idx, size_t dimension) { if (this->filter(idx)) { @@ -260,7 +305,7 @@ std::vector find_nearby_points(const KDTreeIndirectType &kdtree, const P result.push_back(idx); } } - return kdtree.descent_mask(center[dimension], max_distance_squared, idx, dimension); + return kdtree.descent_mask(center[dimension], max_distance_squared, idx, dimension); } } visitor(kdtree, center, max_distance, filter); @@ -270,13 +315,59 @@ std::vector find_nearby_points(const KDTreeIndirectType &kdtree, const P template std::vector find_nearby_points(const KDTreeIndirectType &kdtree, const PointType ¢er, - const typename KDTreeIndirectType::CoordType& max_distance) - { + const typename KDTreeIndirectType::CoordType& max_distance) +{ return find_nearby_points(kdtree, center, max_distance, [](size_t) { return true; }); } +// Find nearby points (spherical neighbourhood) using Euclidian metrics. +template +std::vector find_nearby_points(const KDTreeIndirectType &kdtree, + const PointType &bb_min, + const PointType &bb_max, + FilterFn filter) +{ + struct Visitor { + const KDTreeIndirectType &kdtree; + const PointType &bb_min, &bb_max; + const FilterFn filter; + std::vector result; + + Visitor(const KDTreeIndirectType &kdtree, const PointType& bbmin, const PointType& bbmax, + FilterFn filter) : + kdtree(kdtree), bb_min{bbmin}, bb_max{bbmax}, filter(filter) { + } + unsigned int operator()(size_t idx, size_t dimension) { + unsigned int ret = + static_cast(VisitorReturnMask::CONTINUE_LEFT) | + static_cast(VisitorReturnMask::CONTINUE_RIGHT); + + if (this->filter(idx)) { + PointType p; + bool contains = true; + for (size_t i = 0; i < KDTreeIndirectType::NumDimensions; ++i) { + p(i) = kdtree.coordinate(idx, i); + contains = contains && bb_min(i) <= p(i) && p(i) <= bb_max(i); + } + + if (p(dimension) < bb_min(dimension)) + ret = static_cast(VisitorReturnMask::CONTINUE_RIGHT); + if (p(dimension) > bb_max(dimension)) + ret = static_cast(VisitorReturnMask::CONTINUE_LEFT); + + if (contains) + result.emplace_back(idx); + } + + return ret; + } + } visitor(kdtree, bb_min, bb_max, filter); + + kdtree.visit(visitor); + return visitor.result; +} } // namespace Slic3r diff --git a/src/libslic3r/PointGrid.hpp b/src/libslic3r/PointGrid.hpp new file mode 100644 index 0000000000..acffd2b871 --- /dev/null +++ b/src/libslic3r/PointGrid.hpp @@ -0,0 +1,74 @@ +#ifndef POINTGRID_HPP +#define POINTGRID_HPP + +#include +#include +#include + +namespace Slic3r { + +template +class PointGrid { + Vec3i m_size; + std::vector> m_data; + const int XY; + +public: + explicit PointGrid(std::vector> data, const Vec3i &size) + : m_data(std::move(data)), m_size{size}, XY{m_size.x() * m_size.y()} + {} + + const Vec<3, T> & get(size_t idx) const { return m_data[idx]; } + const Vec<3, T> & get(const Vec3i &coord) const + { + return m_data[get_idx(coord)]; + } + + size_t get_idx(const Vec3i &coord) const + { + size_t ret = coord.z() * XY + coord.y() * m_size.x() + coord.x(); + + return ret; + } + + Vec3i get_coord(size_t idx) const { + size_t iz = idx / XY; + size_t iy = (idx / m_size.x()) % m_size.y(); + size_t ix = idx % m_size.x(); + + return {ix, iy, iz}; + } + + const std::vector> & data() const { return m_data; } + size_t point_count() const { return m_data.size(); } + bool empty() const { return m_data.empty(); } +}; + +template +PointGrid point_grid(Ex policy, + const BoundingBox3Base> &bounds, + const Vec<3, CoordT> &stride) +{ + Vec3i numpts = Vec3i::Zero(); + + for (int n = 0; n < 3; ++n) + numpts(n) = (bounds.max(n) - bounds.min(n)) / stride(n); + + std::vector> out(numpts.x() * numpts.y() * numpts.z()); + + size_t XY = numpts[X] * numpts[Y]; + + execution::for_each(policy, size_t(0), out.size(), [&](size_t i) { + size_t iz = i / XY; + size_t iy = (i / numpts[X]) % numpts[Y]; + size_t ix = i % numpts[X]; + + out[i] = Vec<3, CoordT>(ix * stride.x(), iy * stride.y(), iz * stride.z()); + }); + + return PointGrid{std::move(out), numpts}; +} + +} // namespace Slic3r + +#endif // POINTGRID_HPP diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index a3984b34b1..57e4736474 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests.cpp test_3mf.cpp test_aabbindirect.cpp + test_kdtreeindirect.cpp test_clipper_offset.cpp test_clipper_utils.cpp test_color.cpp diff --git a/tests/libslic3r/test_kdtreeindirect.cpp b/tests/libslic3r/test_kdtreeindirect.cpp new file mode 100644 index 0000000000..28d409bbbf --- /dev/null +++ b/tests/libslic3r/test_kdtreeindirect.cpp @@ -0,0 +1,142 @@ +#include + +#include "libslic3r/KDTreeIndirect.hpp" +#include "libslic3r/Execution/ExecutionSeq.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/PointGrid.hpp" + +using namespace Slic3r; + +//template +//struct Within { // Wrapper for the `within` predicate that counts calls. + +// kdtree::Within pred; + +// Within(G box): pred{box} {} + +// // Number of times the predicate was called +// mutable size_t call_count = 0; + +// std::pair operator() (const Vec3f &p, size_t dim) +// { +// ++call_count; + +// return pred(p, dim); +// } +//}; + +static double volume(const BoundingBox3Base &box) +{ + auto sz = box.size(); + return sz.x() * sz.y() * sz.z(); +} + +static double volume(const Eigen::AlignedBox &box) +{ + return box.volume(); +} + +TEST_CASE("Test kdtree query for a Box", "[KDTreeIndirect]") +{ + auto vol = BoundingBox3Base{{0.f, 0.f, 0.f}, {10.f, 10.f, 10.f}}; + + auto pgrid = point_grid(ex_seq, vol, Vec3f{0.1f, 0.1f, 0.1f}); + + REQUIRE(!pgrid.empty()); + + auto coordfn = [&pgrid] (size_t i, size_t D) { return pgrid.get(i)(int(D)); }; + KDTreeIndirect<3, float, decltype(coordfn)> tree{coordfn, pgrid.point_count()}; + + std::vector out; + + auto qbox = BoundingBox3Base{Vec3f{0.f, 0.f, 0.f}, Vec3f{.5f, .5f, .5f}}; + + size_t call_count = 0; + out = find_nearby_points(tree, qbox.min, qbox.max, [&call_count](size_t) { + call_count++; + return true; + }); + + // Output shall be non-empty + REQUIRE(!out.empty()); + + std::sort(out.begin(), out.end()); + + // No duplicates allowed in the output + auto it = std::unique(out.begin(), out.end()); + REQUIRE(it == out.end()); + + // Test if inside points are in the output and outside points are not. + bool succ = true; + for (size_t i = 0; i < pgrid.point_count(); ++i) { + auto foundit = std::find(out.begin(), out.end(), i); + bool contains = qbox.contains(pgrid.get(i)); + succ = succ && contains ? foundit != out.end() : foundit == out.end(); + + if (!succ) { + std::cout << "invalid point: " << i << " " << pgrid.get(i).transpose() + << std::endl; + break; + } + } + + REQUIRE(succ); + + // Test for the expected cost of the query. + double gridvolume = volume(vol); + double queryvolume = volume(qbox); + double volratio = (queryvolume / gridvolume); + REQUIRE(call_count < 3 * volratio * pgrid.point_count()); + REQUIRE(call_count < pgrid.point_count()); +} + +//TEST_CASE("Test kdtree query for a Sphere", "[KDTreeIndirect]") { +// auto vol = BoundingBox3Base{{0.f, 0.f, 0.f}, {10.f, 10.f, 10.f}}; + +// auto pgrid = point_grid(ex_seq, vol, Vec3f{0.1f, 0.1f, 0.1f}); + +// REQUIRE(!pgrid.empty()); + +// auto coordfn = [&pgrid] (size_t i, size_t D) { return pgrid.get(i)(int(D)); }; +// kdtree::KDTreeIndirect<3, float, decltype(coordfn)> tree{coordfn, pgrid.point_count()}; + +// std::vector out; + +// auto querysphere = kdtree::Sphere{Vec3f{5.f, 5.f, 5.f}, 2.f}; + +// auto pred = Within(querysphere); + +// kdtree::query(tree, pred, std::back_inserter(out)); + +// // Output shall be non-empty +// REQUIRE(!out.empty()); + +// std::sort(out.begin(), out.end()); + +// // No duplicates allowed in the output +// auto it = std::unique(out.begin(), out.end()); +// REQUIRE(it == out.end()); + +// // Test if inside points are in the output and outside points are not. +// bool succ = true; +// for (size_t i = 0; i < pgrid.point_count(); ++i) { +// auto foundit = std::find(out.begin(), out.end(), i); +// bool contains = (querysphere.center - pgrid.get(i)).squaredNorm() < pred.pred.r2; +// succ = succ && contains ? foundit != out.end() : foundit == out.end(); + +// if (!succ) { +// std::cout << "invalid point: " << i << " " << pgrid.get(i).transpose() +// << std::endl; +// break; +// } +// } + +// REQUIRE(succ); + +// // Test for the expected cost of the query. +// double gridvolume = volume(vol); +// double queryvolume = volume(querysphere); +// double volratio = (queryvolume / gridvolume); +// REQUIRE(pred.call_count < 3 * volratio * pgrid.point_count()); +// REQUIRE(pred.call_count < pgrid.point_count()); +//} From fed317f27b5b78e34bdde1ec70a330665027ec88 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 9 May 2022 13:11:01 +0200 Subject: [PATCH 23/25] Change std::nan("") to proper nan constants --- src/libslic3r/AABBTreeIndirect.hpp | 4 ++-- src/libslic3r/Arrange.hpp | 2 +- src/libslic3r/Optimize/Optimizer.hpp | 6 +++--- src/libslic3r/SLA/Rotfinder.cpp | 10 +++++----- src/libslic3r/SLA/SupportTreeBuildsteps.cpp | 2 +- src/libslic3r/SLAPrintSteps.cpp | 2 +- src/libslic3r/libslic3r.h | 6 ++++++ src/slic3r/GUI/DoubleSlider.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- tests/sla_print/sla_test_utils.cpp | 2 +- 10 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/libslic3r/AABBTreeIndirect.hpp b/src/libslic3r/AABBTreeIndirect.hpp index 3ea18de8dc..31101697f2 100644 --- a/src/libslic3r/AABBTreeIndirect.hpp +++ b/src/libslic3r/AABBTreeIndirect.hpp @@ -771,8 +771,8 @@ inline bool is_any_triangle_in_radius( auto distancer = detail::IndexedTriangleSetDistancer { vertices, faces, tree, point }; - size_t hit_idx; - VectorType hit_point = VectorType::Ones() * (std::nan("")); + size_t hit_idx; + VectorType hit_point = VectorType::Ones() * (NaN); if(tree.empty()) { diff --git a/src/libslic3r/Arrange.hpp b/src/libslic3r/Arrange.hpp index 0ff87c88d5..47171007ac 100644 --- a/src/libslic3r/Arrange.hpp +++ b/src/libslic3r/Arrange.hpp @@ -15,7 +15,7 @@ class CircleBed { double radius_; public: - inline CircleBed(): center_(0, 0), radius_(std::nan("")) {} + inline CircleBed(): center_(0, 0), radius_(NaNd) {} explicit inline CircleBed(const Point& c, double r): center_(c), radius_(r) {} inline double radius() const { return radius_; } diff --git a/src/libslic3r/Optimize/Optimizer.hpp b/src/libslic3r/Optimize/Optimizer.hpp index 8ae55c61c5..bf95d9ee07 100644 --- a/src/libslic3r/Optimize/Optimizer.hpp +++ b/src/libslic3r/Optimize/Optimizer.hpp @@ -41,13 +41,13 @@ template using Bounds = std::array; class StopCriteria { // If the absolute value difference between two scores. - double m_abs_score_diff = std::nan(""); + double m_abs_score_diff = NaNd; // If the relative value difference between two scores. - double m_rel_score_diff = std::nan(""); + double m_rel_score_diff = NaNd; // Stop if this value or better is found. - double m_stop_score = std::nan(""); + double m_stop_score = NaNd; // A predicate that if evaluates to true, the optimization should terminate // and the best result found prior to termination should be returned. diff --git a/src/libslic3r/SLA/Rotfinder.cpp b/src/libslic3r/SLA/Rotfinder.cpp index 196646dc9e..847e638e6f 100644 --- a/src/libslic3r/SLA/Rotfinder.cpp +++ b/src/libslic3r/SLA/Rotfinder.cpp @@ -76,7 +76,7 @@ struct Facestats { // Try to guess the number of support points needed to support a mesh double get_misalginment_score(const TriangleMesh &mesh, const Transform3f &tr) { - if (mesh.its.vertices.empty()) return std::nan(""); + if (mesh.its.vertices.empty()) return NaNd; auto accessfn = [&mesh, &tr](size_t fi) { Facestats fc{get_transformed_triangle(mesh, tr, fi)}; @@ -117,7 +117,7 @@ inline double get_supportedness_score(const Facestats &fc) // Try to guess the number of support points needed to support a mesh double get_supportedness_score(const TriangleMesh &mesh, const Transform3f &tr) { - if (mesh.its.vertices.empty()) return std::nan(""); + if (mesh.its.vertices.empty()) return NaNd; auto accessfn = [&mesh, &tr](size_t fi) { Facestats fc{get_transformed_triangle(mesh, tr, fi)}; @@ -149,10 +149,10 @@ float find_ground_level(const TriangleMesh &mesh, return execution::reduce(ex_tbb, size_t(0), vsize, zmin, minfn, accessfn, granularity); } -float get_supportedness_onfloor_score(const TriangleMesh &mesh, - const Transform3f & tr) +double get_supportedness_onfloor_score(const TriangleMesh &mesh, + const Transform3f &tr) { - if (mesh.its.vertices.empty()) return std::nan(""); + if (mesh.its.vertices.empty()) return NaNd; size_t Nthreads = std::thread::hardware_concurrency(); diff --git a/src/libslic3r/SLA/SupportTreeBuildsteps.cpp b/src/libslic3r/SLA/SupportTreeBuildsteps.cpp index aa69fdc777..e4ca3f59cd 100644 --- a/src/libslic3r/SLA/SupportTreeBuildsteps.cpp +++ b/src/libslic3r/SLA/SupportTreeBuildsteps.cpp @@ -654,7 +654,7 @@ void SupportTreeBuildsteps::filter() for (const SupportPoint &sp : m_support_pts) { m_thr(); heads.emplace_back( - std::nan(""), + NaNd, sp.head_front_radius, 0., m_cfg.head_penetration_mm, diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index de3e3ae96d..fc73aa0786 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -1036,7 +1036,7 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() { // Estimated printing time // A layers count o the highest object if (printer_input.size() == 0) - print_statistics.estimated_print_time = std::nan(""); + print_statistics.estimated_print_time = NaNd; else { print_statistics.estimated_print_time = estim_time; print_statistics.layers_times = layers_times; diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index 2131a9233a..06cad840e5 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -331,6 +331,12 @@ public: inline bool empty() const { return size() == 0; } }; +template> +constexpr T NaN = std::numeric_limits::quiet_NaN(); + +constexpr float NaNf = NaN; +constexpr double NaNd = NaN; + } // namespace Slic3r #endif diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 20a3d83960..dda50ec053 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -1163,7 +1163,7 @@ void Control::draw_ruler(wxDC& dc) } }; - double short_tick = std::nan(""); + double short_tick = NaNd; int tick = 0; double value = 0.0; size_t sequence = 0; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 09659faea1..1876500e23 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -822,7 +822,7 @@ public: class WipeTowerInfo { protected: - Vec2d m_pos = {std::nan(""), std::nan("")}; + Vec2d m_pos = {NaNd, NaNd}; double m_rotation = 0.; BoundingBoxf m_bb; friend class GLCanvas3D; diff --git a/tests/sla_print/sla_test_utils.cpp b/tests/sla_print/sla_test_utils.cpp index d98a920372..a58b33ca0f 100644 --- a/tests/sla_print/sla_test_utils.cpp +++ b/tests/sla_print/sla_test_utils.cpp @@ -386,7 +386,7 @@ long raster_pxsum(const sla::RasterGrayscaleAA &raster) double raster_white_area(const sla::RasterGrayscaleAA &raster) { - if (raster.resolution().pixels() == 0) return std::nan(""); + if (raster.resolution().pixels() == 0) return NaNd; auto res = raster.resolution(); double a = 0; From bbf398f2dc93d4789a05b2eeda93406e1305fa17 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 9 May 2022 14:13:12 +0200 Subject: [PATCH 24/25] Fix AABB query in hollowing print step --- src/libslic3r/AABBTreeIndirect.hpp | 12 ++++++------ src/libslic3r/SLAPrintSteps.cpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/AABBTreeIndirect.hpp b/src/libslic3r/AABBTreeIndirect.hpp index 31101697f2..014b49af11 100644 --- a/src/libslic3r/AABBTreeIndirect.hpp +++ b/src/libslic3r/AABBTreeIndirect.hpp @@ -828,22 +828,22 @@ struct Intersecting> { template auto intersecting(const G &g) { return Intersecting{g}; } -template struct Containing {}; +template struct Within {}; // Intersection predicate specialization for box-box intersections template -struct Containing> { +struct Within> { Eigen::AlignedBox box; - Containing(const Eigen::AlignedBox &bb): box{bb} {} + Within(const Eigen::AlignedBox &bb): box{bb} {} bool operator() (const typename Tree::Node &node) const { - return box.contains(node.bbox); + return node.is_leaf() ? box.contains(node.bbox) : box.intersects(node.bbox); } }; -template auto containing(const G &g) { return Containing{g}; } +template auto within(const G &g) { return Within{g}; } namespace detail { @@ -858,7 +858,7 @@ void traverse_recurse(const Tree &tree, if (!pred(tree.node(idx))) return; if (tree.node(idx).is_leaf()) { - callback(tree.node(idx).idx); + callback(tree.node(idx)); } else { // call this with left and right node idx: diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index fc73aa0786..c3ec3e3997 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -408,9 +408,9 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po) AABBTreeIndirect::traverse( tree, AABBTreeIndirect::intersecting(ebb), - [&part_to_drill, &hollowed_mesh](size_t faceid) + [&part_to_drill, &hollowed_mesh](const auto& node) { - part_to_drill.indices.emplace_back(hollowed_mesh.its.indices[faceid]); + part_to_drill.indices.emplace_back(hollowed_mesh.its.indices[node.idx]); }); auto cgal_meshpart = MeshBoolean::cgal::triangle_mesh_to_cgal( From 34ba45dde404f85fb9a647e5ef0e16f691e8b37f Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 9 May 2022 14:20:29 +0200 Subject: [PATCH 25/25] Small fix in Execution.hpp --- src/libslic3r/Execution/Execution.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Execution/Execution.hpp b/src/libslic3r/Execution/Execution.hpp index dcfd86bde8..57ad4b41b9 100644 --- a/src/libslic3r/Execution/Execution.hpp +++ b/src/libslic3r/Execution/Execution.hpp @@ -30,8 +30,8 @@ template using AsTraits = Traits>; // Each execution policy should declare two types of mutexes. A a spin lock and // a blocking mutex. These types should satisfy the BasicLockable concept. -template using SpinningMutex = typename Traits::SpinningMutex; -template using BlockingMutex = typename Traits::BlockingMutex; +template using SpinningMutex = typename AsTraits::SpinningMutex; +template using BlockingMutex = typename AsTraits::BlockingMutex; // Query the available threads for concurrency. template >