From 415877d79e7edf26868e71afdbc3277948dec765 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 18 Jun 2019 18:02:40 +0200 Subject: [PATCH 01/48] Experiments with msw_rescale fixing --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 33 +++++++++++++++------ src/slic3r/GUI/GUI_Utils.hpp | 36 ++++++++++++++++++++--- src/slic3r/GUI/wxExtensions.cpp | 2 ++ 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 5bf25f3fc0..925ba65bcd 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -130,8 +130,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : auto manifold_warning_icon = [this](wxWindow* parent) { m_fix_throught_netfab_bitmap = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap); - auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(m_fix_throught_netfab_bitmap); +// auto sizer = new wxBoxSizer(wxHORIZONTAL); +// sizer->Add(m_fix_throught_netfab_bitmap); if (is_windows10()) m_fix_throught_netfab_bitmap->Bind(wxEVT_CONTEXT_MENU, [this](wxCommandEvent &e) @@ -144,17 +144,19 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors_list()); }); - return sizer; +// return sizer; + return m_fix_throught_netfab_bitmap; }; - line.append_widget(manifold_warning_icon); + // line.append_widget(manifold_warning_icon); + line.near_label_widget = manifold_warning_icon; def.label = ""; def.gui_type = "legend"; def.tooltip = L("Object name"); #ifdef __APPLE__ - def.width = 19; + def.width = 20; #else - def.width = 21; + def.width = 22; #endif def.set_default_value(new ConfigOptionString{ " " }); line.append_option(Option(def, "object_name")); @@ -233,10 +235,19 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // call back for a rescale of button "Set uniform scale" m_og->rescale_near_label_widget = [this](wxWindow* win) { + // rescale lock icon auto *ctrl = dynamic_cast(win); - if (ctrl == nullptr) + if (ctrl != nullptr) { + ctrl->msw_rescale(); return; - ctrl->msw_rescale(); + } + + if (win == m_fix_throught_netfab_bitmap) + return; + + // rescale "place" of the empty icon (to correct layout of the "Size" and "Scale") + if (dynamic_cast(win) != nullptr) + win->SetMinSize(create_scaled_bitmap(m_parent, "one_layer_lock_on.png").GetSize()); }; } @@ -431,6 +442,7 @@ void ObjectManipulation::emulate_kill_focus() void ObjectManipulation::update_warning_icon_state(const wxString& tooltip) { m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp()); + m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0,0) : m_manifold_warning_bmp.bmp().GetSize()); m_fix_throught_netfab_bitmap->SetToolTip(tooltip); } @@ -664,7 +676,10 @@ void ObjectManipulation::msw_rescale() { msw_rescale_word_local_combo(m_word_local_combo); m_manifold_warning_bmp.msw_rescale(); - m_fix_throught_netfab_bitmap->SetBitmap(m_manifold_warning_bmp.bmp()); + + const wxString& tooltip = m_fix_throught_netfab_bitmap->GetToolTipText(); + m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp()); + m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0, 0) : m_manifold_warning_bmp.bmp().GetSize()); get_og()->msw_rescale(); } diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index a17bbf6d33..39b68ea7a0 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -72,6 +72,8 @@ public: this->Bind(EVT_DPI_CHANGED, [this](const DpiChangedEvent &evt) { m_scale_factor = (float)evt.dpi / (float)DPI_DEFAULT; + m_new_font_point_size = get_default_font_for_dpi(evt.dpi).GetPointSize(); + if (!m_can_rescale) return; @@ -124,6 +126,8 @@ private: float m_prev_scale_factor; bool m_can_rescale{ true }; + int m_new_font_point_size; + // void recalc_font() // { // wxClientDC dc(this); @@ -148,18 +152,42 @@ private: window->Layout(); } + void scale_win_font(wxWindow *window, const int font_point_size) + { + wxFont new_font(window->GetFont()); + new_font.SetPointSize(font_point_size); + window->SetFont(new_font); + } + + // recursive function for scaling fonts for all controls in Window + void scale_controls_fonts(wxWindow *window, const int font_point_size) + { + auto children = window->GetChildren(); + + for (auto child : children) { + scale_controls_fonts(child, font_point_size); + scale_win_font(child, font_point_size); + } + + window->Layout(); + } + void rescale(const wxRect &suggested_rect) { this->Freeze(); - const float relative_scale_factor = m_scale_factor / m_prev_scale_factor; +// const float relative_scale_factor = m_scale_factor / m_prev_scale_factor; // rescale fonts of all controls - scale_controls_fonts(this, relative_scale_factor); - this->SetFont(this->GetFont().Scaled(relative_scale_factor)); +// scale_controls_fonts(this, relative_scale_factor); + scale_controls_fonts(this, m_new_font_point_size); + +// this->SetFont(this->GetFont().Scaled(relative_scale_factor)); + scale_win_font(this, m_new_font_point_size); // rescale normal_font value - m_normal_font = m_normal_font.Scaled(relative_scale_factor); +// m_normal_font = m_normal_font.Scaled(relative_scale_factor); + m_normal_font = this->GetFont(); // An analog of em_unit value from GUI_App. m_em_unit = std::max(10, 10 * m_scale_factor); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 76ba853dc3..546e4889f7 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2478,6 +2478,8 @@ void LockButton::msw_rescale() m_bmp_lock_off .msw_rescale(); m_bmp_unlock_on .msw_rescale(); m_bmp_unlock_off.msw_rescale(); + + enter_button(false); } void LockButton::enter_button(const bool enter) From 12133f95993ba33064b059e971f27e02fcc046d8 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 19 Jun 2019 11:38:42 +0200 Subject: [PATCH 02/48] Code cleaning and last msw_rescale() improvements --- src/slic3r/GUI/GUI_Utils.hpp | 32 +++++++++++--------------------- src/slic3r/GUI/MainFrame.cpp | 4 +++- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index 39b68ea7a0..c47714e464 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -64,6 +64,12 @@ public: m_prev_scale_factor = m_scale_factor; m_normal_font = get_default_font_for_dpi(dpi); + /* Because of default window font is a primary display font, + * We should set correct font for window before getting em_unit value. + */ +#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList + this->SetFont(m_normal_font); +#endif // initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window. m_em_unit = std::max(10, this->GetTextExtent("m").x - 1); @@ -139,19 +145,7 @@ private: // check if new scale is differ from previous bool is_new_scale_factor() const { return fabs(m_scale_factor - m_prev_scale_factor) > 0.001; } - // recursive function for scaling fonts for all controls in Window - void scale_controls_fonts(wxWindow *window, const float scale_f) - { - auto children = window->GetChildren(); - - for (auto child : children) { - scale_controls_fonts(child, scale_f); - child->SetFont(child->GetFont().Scaled(scale_f)); - } - - window->Layout(); - } - + // function for a font scaling of the window void scale_win_font(wxWindow *window, const int font_point_size) { wxFont new_font(window->GetFont()); @@ -175,22 +169,18 @@ private: void rescale(const wxRect &suggested_rect) { this->Freeze(); -// const float relative_scale_factor = m_scale_factor / m_prev_scale_factor; // rescale fonts of all controls -// scale_controls_fonts(this, relative_scale_factor); scale_controls_fonts(this, m_new_font_point_size); - -// this->SetFont(this->GetFont().Scaled(relative_scale_factor)); + // rescale current window font scale_win_font(this, m_new_font_point_size); - // rescale normal_font value -// m_normal_font = m_normal_font.Scaled(relative_scale_factor); + // set normal application font as a current window font m_normal_font = this->GetFont(); - // An analog of em_unit value from GUI_App. - m_em_unit = std::max(10, 10 * m_scale_factor); + // update em_unit value for new window font + m_em_unit = std::max(10, this->GetTextExtent("m").x - 1); // rescale missed controls sizes and images on_dpi_changed(suggested_rect); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 7e5b3ec05a..47d012fdf5 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -38,10 +38,12 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S { // Fonts were created by the DPIFrame constructor for the monitor, on which the window opened. wxGetApp().update_fonts(this); +/* #ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList this->SetFont(this->normal_font()); #endif - + // Font is already set in DPIFrame constructor +*/ // Load the icon either from the exe, or from the ico file. #if _WIN32 { From 7d25d8c677cc0edbba469e2a54658ed9468efa60 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 1 Aug 2019 16:03:52 +0200 Subject: [PATCH 03/48] Can build with (original llvm) clang-cl on windows --- CMakeLists.txt | 11 ++++++++--- cmake/modules/PrecompiledHeader.cmake | 9 ++++++--- deps/deps-windows.cmake | 4 ++++ src/avrdude/windows/unistd.h | 8 +++++++- src/libnest2d/tests/test.cpp | 4 ++++ src/libslic3r/Arrange.cpp | 5 +++++ src/libslic3r/MinAreaBoundingBox.cpp | 5 +++++ src/slic3r/GUI/GUI_Utils.cpp | 2 +- 8 files changed, 40 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbb0e2ec49..a29a144fe3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,8 +52,14 @@ if (SLIC3R_GUI) add_definitions(-DSLIC3R_GUI) endif () +if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(IS_CLANG_CL TRUE) +else () + set(IS_CLANG_CL FALSE) +endif () + if (MSVC) - if (SLIC3R_MSVC_COMPILE_PARALLEL) + if (SLIC3R_MSVC_COMPILE_PARALLEL AND NOT IS_CLANG_CL) add_compile_options(/MP) endif () # /bigobj (Increase Number of Sections in .Obj file) @@ -148,7 +154,7 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals" ) endif() -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") +if (NOT MSVC AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder" ) @@ -168,7 +174,6 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATC add_compile_options(-Wno-unknown-pragmas) endif() - if (SLIC3R_ASAN) add_compile_options(-fsanitize=address -fno-omit-frame-pointer) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") diff --git a/cmake/modules/PrecompiledHeader.cmake b/cmake/modules/PrecompiledHeader.cmake index e463021441..2f62a7dbeb 100644 --- a/cmake/modules/PrecompiledHeader.cmake +++ b/cmake/modules/PrecompiledHeader.cmake @@ -105,6 +105,9 @@ function(add_precompiled_header _target _input) cmake_parse_arguments(_PCH "FORCEINCLUDE" "SOURCE_CXX;SOURCE_C" "" ${ARGN}) get_filename_component(_input_we ${_input} NAME_WE) + get_filename_component(_input_full ${_input} ABSOLUTE) + file(TO_NATIVE_PATH "${_input_full}" _input_fullpath) + if(NOT _PCH_SOURCE_CXX) set(_PCH_SOURCE_CXX "${_input_we}.cpp") endif() @@ -138,16 +141,16 @@ function(add_precompiled_header _target _input) set_source_files_properties("${_source}" PROPERTIES OBJECT_OUTPUTS "${_pch_c_pch}") else() if(_source MATCHES \\.\(cpp|cxx|cc\)$) - set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_cxx_pch}\" \"/Yu${_input}\"") + set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_cxx_pch}\" \"/Yu${_input_fullpath}\"") set(_pch_source_cxx_needed TRUE) set_source_files_properties("${_source}" PROPERTIES OBJECT_DEPENDS "${_pch_cxx_pch}") else() - set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_c_pch}\" \"/Yu${_input}\"") + set(_pch_compile_flags "${_pch_compile_flags} \"/Fp${_pch_c_pch}\" \"/Yu${_input_fullpath}\"") set(_pch_source_c_needed TRUE) set_source_files_properties("${_source}" PROPERTIES OBJECT_DEPENDS "${_pch_c_pch}") endif() if(_PCH_FORCEINCLUDE) - set(_pch_compile_flags "${_pch_compile_flags} /FI${_input}") + set(_pch_compile_flags "${_pch_compile_flags} /FI${_input_fullpath}") endif(_PCH_FORCEINCLUDE) endif() diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake index 9092f330bc..85013fbddd 100644 --- a/deps/deps-windows.cmake +++ b/deps/deps-windows.cmake @@ -19,6 +19,10 @@ else () message(FATAL_ERROR "Unsupported MSVC version") endif () +if (CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(DEP_BOOST_TOOLSET "clang-win") +endif () + if (${DEPS_BITS} EQUAL 32) set(DEP_MSVC_GEN "Visual Studio ${DEP_VS_VER}") set(DEP_PLATFORM "Win32") diff --git a/src/avrdude/windows/unistd.h b/src/avrdude/windows/unistd.h index 95ba79a346..fe6a8fb871 100644 --- a/src/avrdude/windows/unistd.h +++ b/src/avrdude/windows/unistd.h @@ -63,10 +63,15 @@ extern "C" { #define STDOUT_FILENO 1 #define STDERR_FILENO 2 +#ifdef _MSC_VER +#include +struct timezone; +struct timeval; +#else #ifndef __cplusplus /* should be in some equivalent to */ typedef __int8 int8_t; -typedef __int16 int16_t; +typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; @@ -74,6 +79,7 @@ typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; #endif +#endif int usleep(unsigned usec); diff --git a/src/libnest2d/tests/test.cpp b/src/libnest2d/tests/test.cpp index 29577344d1..4a6691415f 100644 --- a/src/libnest2d/tests/test.cpp +++ b/src/libnest2d/tests/test.cpp @@ -7,6 +7,10 @@ #include "../tools/svgtools.hpp" #include +#if defined(_MSC_VER) && defined(__clang__) +#define BOOST_NO_CXX17_HDR_STRING_VIEW +#endif + #include "boost/multiprecision/integer.hpp" #include "boost/rational.hpp" diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index b4cfac9546..ed599d11da 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -12,6 +12,11 @@ #include #include + +#if defined(_MSC_VER) && defined(__clang__) +#define BOOST_NO_CXX17_HDR_STRING_VIEW +#endif + #include #include diff --git a/src/libslic3r/MinAreaBoundingBox.cpp b/src/libslic3r/MinAreaBoundingBox.cpp index fafb54a585..15c04517d0 100644 --- a/src/libslic3r/MinAreaBoundingBox.cpp +++ b/src/libslic3r/MinAreaBoundingBox.cpp @@ -1,6 +1,11 @@ #include "MinAreaBoundingBox.hpp" #include + +#if defined(_MSC_VER) && defined(__clang__) +#define BOOST_NO_CXX17_HDR_STRING_VIEW +#endif + #include #include diff --git a/src/slic3r/GUI/GUI_Utils.cpp b/src/slic3r/GUI/GUI_Utils.cpp index 74e70c5546..d5753f2ccf 100644 --- a/src/slic3r/GUI/GUI_Utils.cpp +++ b/src/slic3r/GUI/GUI_Utils.cpp @@ -62,7 +62,7 @@ template typename F::FN winapi_get_function(const wchar_t *dll, const c static HINSTANCE dll_handle = LoadLibraryExW(dll, nullptr, 0); if (dll_handle == nullptr) { return nullptr; } - return (F::FN)GetProcAddress(dll_handle, fn_name); + return (typename F::FN)GetProcAddress(dll_handle, fn_name); } #endif From 1b5d561b7cdf9c546e1b9b0355a55928c2de462d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 8 Aug 2019 15:17:17 +0200 Subject: [PATCH 04/48] Added handling of std::bad_alloc so the user gets more comprehensible error message Call to boost::nowide::nowide_filesystem() was made Windows only --- src/PrusaSlicer.cpp | 15 ++++++++++++++- src/libslic3r/PrintObject.cpp | 4 ++-- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 7 ++++++- src/slic3r/GUI/GUI_App.cpp | 11 ++++++++++- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 45a3336304..9bef4b4192 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -60,8 +60,21 @@ PrinterTechnology get_printer_technology(const DynamicConfig &config) int CLI::run(int argc, char **argv) { +#ifdef _WIN32 // Switch boost::filesystem to utf8. - boost::nowide::nowide_filesystem(); + try { + boost::nowide::nowide_filesystem(); + } catch (const std::runtime_error& ex) { + std::string caption = std::string(SLIC3R_APP_NAME) + " Error"; + std::string text = std::string("An error occured while setting up locale.\n") + SLIC3R_APP_NAME + " will now terminate.\n\n" + ex.what(); + #ifdef SLIC3R_GUI + if (m_actions.empty()) + MessageBoxA(NULL, text.c_str(), caption.c_str(), MB_OK | MB_ICONERROR); + #endif + boost::nowide::cerr << text.c_str() << std::endl; + return 1; + } +#endif if (! this->setup(argc, argv)) return 1; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 37cf0cccc7..e19bceeb76 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -161,7 +161,7 @@ void PrintObject::make_perimeters() const PrintRegion ®ion = *m_print->regions()[region_id]; if (! region.config().extra_perimeters || region.config().perimeters == 0 || region.config().fill_density == 0 || this->layer_count() < 2) continue; - + BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - start"; tbb::parallel_for( tbb::blocked_range(0, m_layers.size() - 1), @@ -2379,7 +2379,7 @@ void PrintObject::discover_horizontal_shells() if (new_internal_solid.empty()) { // No internal solid needed on this layer. In order to decide whether to continue // searching on the next neighbor (thus enforcing the configured number of solid - // layers, use different strategies according to configured infill density: + // layers, use different strategies according to configured infill density: if (region_config.fill_density.value == 0) { // If user expects the object to be void (for example a hollow sloping vase), // don't continue the search. In this case, we only generate the external solid diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index b77a272e2e..94ddb1e5ef 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -151,7 +151,12 @@ void BackgroundSlicingProcess::thread_proc() } catch (CanceledException & /* ex */) { // Canceled, this is all right. assert(m_print->canceled()); - } catch (std::exception &ex) { + } catch (const std::bad_alloc& ex) { + wxString errmsg = wxString::Format(_(L("%s has encountered an error. It was likely caused by running out of memory. " + "If you are sure you have enough RAM on your system, this may also be a bug and we would " + "be glad if you reported it.")), SLIC3R_APP_NAME); + error = errmsg.ToStdString() + "\n\n" + std::string(ex.what()); + } catch (std::exception &ex) { error = ex.what(); } catch (...) { error = "Unknown C++ exception."; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 066dab90fd..9b4522356a 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -126,7 +126,16 @@ static void generic_exception_handle() try { throw; - } catch (const std::exception &ex) { + } catch (const std::bad_alloc& ex) { + // bad_alloc in main thread is most likely fatal. Report immediately to the user (wxLogError would be delayed) + // and terminate the app so it is at least certain to happen now. + wxString errmsg = wxString::Format(_(L("%s has encountered an error. It was likely caused by running out of memory. " + "If you are sure you have enough RAM on your system, this may also be a bug and we would " + "be glad if you reported it.\n\nThe application will now terminate.")), SLIC3R_APP_NAME); + wxMessageBox(errmsg + "\n\n" + wxString(ex.what()), _(L("Fatal error")), wxOK | wxICON_ERROR); + BOOST_LOG_TRIVIAL(error) << boost::format("std::bad_alloc exception: %1%") % ex.what(); + std::terminate(); + } catch (const std::exception& ex) { wxLogError("Internal error: %s", ex.what()); BOOST_LOG_TRIVIAL(error) << boost::format("Uncaught exception: %1%") % ex.what(); throw; From c84b1ca34b86e4f35b6caac1a8e51897951f14de Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 15 Aug 2019 01:20:38 +0200 Subject: [PATCH 05/48] Multimaterial initial priming for non-Prusa printers (https://github.com/prusa3d/PrusaSlicer/issues/1121) The initial priming now does not assume anything about bed width and always uses the space it has In case of circular beds it places the priming lines along the diameter Custom beds are not supported (they are treated as circular with no extra checks whether it is sane) Slight refactoring of the WipeTower class (constructor now gets reference to PrintConfig and not the individual values, same with set_extruder). This was legacy from times when the wipe tower was meant to be abstract and independent on the rest) --- src/libslic3r/GCode/WipeTower.cpp | 86 +++++++++++++++++++++++++++++-- src/libslic3r/GCode/WipeTower.hpp | 83 ++++------------------------- src/libslic3r/Print.cpp | 27 +--------- 3 files changed, 94 insertions(+), 102 deletions(-) diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index e1b34fdeae..8385f579c8 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -22,6 +22,7 @@ TODO LIST #include #include "Analyzer.hpp" +#include "BoundingBox.hpp" #if defined(__linux) || defined(__GNUC__ ) #include @@ -470,6 +471,83 @@ private: +WipeTower::WipeTower(const PrintConfig& config, const std::vector>& wiping_matrix, size_t initial_tool) : + m_semm(config.single_extruder_multi_material.value), + m_wipe_tower_pos(config.wipe_tower_x, config.wipe_tower_y), + m_wipe_tower_width(config.wipe_tower_width), + m_wipe_tower_rotation_angle(config.wipe_tower_rotation_angle), + m_y_shift(0.f), + m_z_pos(0.f), + m_is_first_layer(false), + m_bridging(config.wipe_tower_bridging), + m_gcode_flavor(config.gcode_flavor), + m_current_tool(initial_tool), + wipe_volumes(wiping_matrix) +{ + // If this is a single extruder MM printer, we will use all the SE-specific config values. + // Otherwise, the defaults will be used to turn off the SE stuff. + if (m_semm) { + m_cooling_tube_retraction = config.cooling_tube_retraction; + m_cooling_tube_length = config.cooling_tube_length; + m_parking_pos_retraction = config.parking_pos_retraction; + m_extra_loading_move = config.extra_loading_move; + m_set_extruder_trimpot = config.high_current_on_filament_swap; + } + // Calculate where the priming lines should be - very naive test not detecting parallelograms or custom shapes + const std::vector& bed_points = config.bed_shape.values; + m_bed_shape = (bed_points.size() == 4 ? RectangularBed : CircularBed); + m_bed_width = BoundingBoxf(bed_points).size().x(); +} + + + +void WipeTower::set_extruder(size_t idx, const PrintConfig& config) +{ + //while (m_filpar.size() < idx+1) // makes sure the required element is in the vector + m_filpar.push_back(FilamentParameters()); + + m_filpar[idx].material = config.filament_type.get_at(idx); + m_filpar[idx].temperature = config.temperature.get_at(idx); + m_filpar[idx].first_layer_temperature = config.first_layer_temperature.get_at(idx); + + // If this is a single extruder MM printer, we will use all the SE-specific config values. + // Otherwise, the defaults will be used to turn off the SE stuff. + if (m_semm) { + m_filpar[idx].loading_speed = config.filament_loading_speed.get_at(idx); + m_filpar[idx].loading_speed_start = config.filament_loading_speed_start.get_at(idx); + m_filpar[idx].unloading_speed = config.filament_unloading_speed.get_at(idx); + m_filpar[idx].unloading_speed_start = config.filament_unloading_speed_start.get_at(idx); + m_filpar[idx].delay = config.filament_toolchange_delay.get_at(idx); + m_filpar[idx].cooling_moves = config.filament_cooling_moves.get_at(idx); + m_filpar[idx].cooling_initial_speed = config.filament_cooling_initial_speed.get_at(idx); + m_filpar[idx].cooling_final_speed = config.filament_cooling_final_speed.get_at(idx); + } + + m_filpar[idx].filament_area = float((M_PI/4.f) * pow(config.filament_diameter.get_at(idx), 2)); // all extruders are assumed to have the same filament diameter at this point + float nozzle_diameter = config.nozzle_diameter.get_at(idx); + m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM + + float max_vol_speed = config.filament_max_volumetric_speed.get_at(idx); + if (max_vol_speed!= 0.f) + m_filpar[idx].max_e_speed = (max_vol_speed / filament_area()); + + m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter + + if (m_semm) { + std::istringstream stream{config.filament_ramming_parameters.get_at(idx)}; + float speed = 0.f; + stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator; + m_filpar[idx].ramming_line_width_multiplicator /= 100; + m_filpar[idx].ramming_step_multiplicator /= 100; + while (stream >> speed) + m_filpar[idx].ramming_speed.push_back(speed); + } + + m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later +} + + + // Returns gcode to prime the nozzles at the front edge of the print bed. std::vector WipeTower::prime( // print_z of the first layer. @@ -488,9 +566,11 @@ std::vector WipeTower::prime( // therefore the homing position is shifted inside the bed by 0.2 in the firmware to [0.2, -2.0]. // box_coordinates cleaning_box(xy(0.5f, - 1.5f), m_wipe_tower_width, wipe_area); - const float prime_section_width = std::min(240.f / tools.size(), 60.f); - box_coordinates cleaning_box(Vec2f(5.f, 0.01f + m_perimeter_width/2.f), prime_section_width, 100.f); - + float prime_section_width = std::min(0.9f * m_bed_width / tools.size(), 60.f); + box_coordinates cleaning_box(Vec2f(0.02f * m_bed_width, 0.01f + m_perimeter_width/2.f), prime_section_width, 100.f); + // In case of a circular bed, place it so it goes across the diameter and hope it will fit + if (m_bed_shape == CircularBed) + cleaning_box.translate(-m_bed_width/2 + m_bed_width * 0.03f, -m_bed_width * 0.12f); std::vector results; diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 3c6b4afca2..fab75c5e60 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -78,83 +78,12 @@ public: // y -- y coordinates of wipe tower in mm ( left bottom corner ) // width -- width of wipe tower in mm ( default 60 mm - leave as it is ) // wipe_area -- space available for one toolchange in mm - WipeTower(bool semm, float x, float y, float width, float rotation_angle, float cooling_tube_retraction, - float cooling_tube_length, float parking_pos_retraction, float extra_loading_move, - float bridging, bool set_extruder_trimpot, GCodeFlavor flavor, - const std::vector>& wiping_matrix, unsigned int initial_tool) : - m_semm(semm), - m_wipe_tower_pos(x, y), - m_wipe_tower_width(width), - m_wipe_tower_rotation_angle(rotation_angle), - m_y_shift(0.f), - m_z_pos(0.f), - m_is_first_layer(false), - m_gcode_flavor(flavor), - m_bridging(bridging), - m_current_tool(initial_tool), - wipe_volumes(wiping_matrix) - { - // If this is a single extruder MM printer, we will use all the SE-specific config values. - // Otherwise, the defaults will be used to turn off the SE stuff. - if (m_semm) { - m_cooling_tube_retraction = cooling_tube_retraction; - m_cooling_tube_length = cooling_tube_length; - m_parking_pos_retraction = parking_pos_retraction; - m_extra_loading_move = extra_loading_move; - m_set_extruder_trimpot = set_extruder_trimpot; - } - } - + WipeTower(const PrintConfig& config, const std::vector>& wiping_matrix, size_t initial_tool); virtual ~WipeTower() {} // Set the extruder properties. - void set_extruder(size_t idx, std::string material, int temp, int first_layer_temp, float loading_speed, float loading_speed_start, - float unloading_speed, float unloading_speed_start, float delay, int cooling_moves, - float cooling_initial_speed, float cooling_final_speed, std::string ramming_parameters, float max_volumetric_speed, - float nozzle_diameter, float filament_diameter) - { - //while (m_filpar.size() < idx+1) // makes sure the required element is in the vector - m_filpar.push_back(FilamentParameters()); - - m_filpar[idx].material = material; - m_filpar[idx].temperature = temp; - m_filpar[idx].first_layer_temperature = first_layer_temp; - - // If this is a single extruder MM printer, we will use all the SE-specific config values. - // Otherwise, the defaults will be used to turn off the SE stuff. - if (m_semm) { - m_filpar[idx].loading_speed = loading_speed; - m_filpar[idx].loading_speed_start = loading_speed_start; - m_filpar[idx].unloading_speed = unloading_speed; - m_filpar[idx].unloading_speed_start = unloading_speed_start; - m_filpar[idx].delay = delay; - m_filpar[idx].cooling_moves = cooling_moves; - m_filpar[idx].cooling_initial_speed = cooling_initial_speed; - m_filpar[idx].cooling_final_speed = cooling_final_speed; - } - - m_filpar[idx].filament_area = float((M_PI/4.f) * pow(filament_diameter, 2)); // all extruders are assumed to have the same filament diameter at this point - m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM - - if (max_volumetric_speed != 0.f) - m_filpar[idx].max_e_speed = (max_volumetric_speed / filament_area()); - - m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter - - if (m_semm) { - std::stringstream stream{ramming_parameters}; - float speed = 0.f; - stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator; - m_filpar[idx].ramming_line_width_multiplicator /= 100; - m_filpar[idx].ramming_step_multiplicator /= 100; - while (stream >> speed) - m_filpar[idx].ramming_speed.push_back(speed); - } - - m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later - } - + void set_extruder(size_t idx, const PrintConfig& config); // Appends into internal structure m_plan containing info about the future wipe tower // to be used before building begins. The entries must be added ordered in z. @@ -263,7 +192,6 @@ private: SHAPE_REVERSED = -1 }; - const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust const float WT_EPSILON = 1e-3f; @@ -295,6 +223,13 @@ private: bool m_adhesion = true; GCodeFlavor m_gcode_flavor; + // Bed properties + enum { + RectangularBed, + CircularBed + } m_bed_shape; + float m_bed_width; // width of the bed bounding box + float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill. float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter. diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index d8a094b20b..0ea07e9a40 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1760,15 +1760,7 @@ void Print::_make_wipe_tower() this->throw_if_canceled(); // Initialize the wipe tower. - WipeTower wipe_tower( - m_config.single_extruder_multi_material.value, - float(m_config.wipe_tower_x.value), float(m_config.wipe_tower_y.value), - float(m_config.wipe_tower_width.value), - float(m_config.wipe_tower_rotation_angle.value), float(m_config.cooling_tube_retraction.value), - float(m_config.cooling_tube_length.value), float(m_config.parking_pos_retraction.value), - float(m_config.extra_loading_move.value), float(m_config.wipe_tower_bridging), - m_config.high_current_on_filament_swap.value, m_config.gcode_flavor, wipe_volumes, - m_wipe_tower_data.tool_ordering.first_extruder()); + WipeTower wipe_tower(m_config, wipe_volumes, m_wipe_tower_data.tool_ordering.first_extruder()); //wipe_tower.set_retract(); //wipe_tower.set_zhop(); @@ -1777,22 +1769,7 @@ void Print::_make_wipe_tower() for (size_t i = 0; i < number_of_extruders; ++ i) wipe_tower.set_extruder( - i, - m_config.filament_type.get_at(i), - m_config.temperature.get_at(i), - m_config.first_layer_temperature.get_at(i), - (float)m_config.filament_loading_speed.get_at(i), - (float)m_config.filament_loading_speed_start.get_at(i), - (float)m_config.filament_unloading_speed.get_at(i), - (float)m_config.filament_unloading_speed_start.get_at(i), - (float)m_config.filament_toolchange_delay.get_at(i), - m_config.filament_cooling_moves.get_at(i), - (float)m_config.filament_cooling_initial_speed.get_at(i), - (float)m_config.filament_cooling_final_speed.get_at(i), - m_config.filament_ramming_parameters.get_at(i), - (float)m_config.filament_max_volumetric_speed.get_at(i), - (float)m_config.nozzle_diameter.get_at(i), - (float)m_config.filament_diameter.get_at(i)); + i, m_config); m_wipe_tower_data.priming = Slic3r::make_unique>( wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); From c8ac46df43f0ae467edc02f7587094f7facfe16f Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 15 Aug 2019 12:52:56 +0200 Subject: [PATCH 06/48] Fixed some memory leaks related to heap-allocated wxDialogs Some correctly destroyed dialogs were also converted to stack-allocated --- src/slic3r/GUI/Field.cpp | 4 +- src/slic3r/GUI/MainFrame.cpp | 85 ++++++++++++++---------------------- src/slic3r/GUI/Plater.cpp | 16 +++---- src/slic3r/GUI/Tab.cpp | 76 ++++++++++++++++---------------- 4 files changed, 79 insertions(+), 102 deletions(-) diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 39924e44c5..3e3026a4cd 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -206,8 +206,8 @@ void Field::get_value_by_opt_type(wxString& str) const wxString msg_text = wxString::Format(_(L("Do you mean %s%% instead of %s %s?\n" "Select YES if you want to change this value to %s%%, \n" "or NO if you are sure that %s %s is a correct value.")), stVal, stVal, sidetext, stVal, stVal, sidetext); - auto dialog = new wxMessageDialog(m_parent, msg_text, _(L("Parameter validation")), wxICON_WARNING | wxYES | wxNO); - if (dialog->ShowModal() == wxID_YES) { + wxMessageDialog dialog(m_parent, msg_text, _(L("Parameter validation")), wxICON_WARNING | wxYES | wxNO); + if (dialog.ShowModal() == wxID_YES) { set_value(wxString::Format("%s%%", stVal), false/*true*/); str += "%%"; } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index b0945aea83..f10a106c18 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -729,29 +729,26 @@ void MainFrame::quick_slice(const int qs) // select input file if (!(qs & qsReslice)) { - auto dlg = new wxFileDialog(this, _(L("Choose a file to slice (STL/OBJ/AMF/3MF/PRUSA):")), + wxFileDialog dlg(this, _(L("Choose a file to slice (STL/OBJ/AMF/3MF/PRUSA):")), wxGetApp().app_config->get_last_dir(), "", file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) return; - } - input_file = dlg->GetPath(); - dlg->Destroy(); + input_file = dlg.GetPath(); if (!(qs & qsExportSVG)) m_qs_last_input_file = input_file; } else { if (m_qs_last_input_file.IsEmpty()) { - auto dlg = new wxMessageDialog(this, _(L("No previously sliced file.")), + wxMessageDialog dlg(this, _(L("No previously sliced file.")), _(L("Error")), wxICON_ERROR | wxOK); - dlg->ShowModal(); + dlg.ShowModal(); return; } if (std::ifstream(m_qs_last_input_file.ToUTF8().data())) { - auto dlg = new wxMessageDialog(this, _(L("Previously sliced file ("))+m_qs_last_input_file+_(L(") not found.")), + wxMessageDialog dlg(this, _(L("Previously sliced file ("))+m_qs_last_input_file+_(L(") not found.")), _(L("File Not Found")), wxICON_ERROR | wxOK); - dlg->ShowModal(); + dlg.ShowModal(); return; } input_file = m_qs_last_input_file; @@ -785,30 +782,24 @@ void MainFrame::quick_slice(const int qs) } else if (qs & qsSaveAs) { // The following line may die if the output_filename_format template substitution fails. - auto dlg = new wxFileDialog(this, wxString::Format(_(L("Save %s file as:")) , qs & qsExportSVG ? _(L("SVG")) : _(L("G-code")) ), + wxFileDialog dlg(this, wxString::Format(_(L("Save %s file as:")) , qs & qsExportSVG ? _(L("SVG")) : _(L("G-code")) ), wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)), get_base_name(input_file), qs & qsExportSVG ? file_wildcards(FT_SVG) : file_wildcards(FT_GCODE), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) return; - } - output_file = dlg->GetPath(); - dlg->Destroy(); + output_file = dlg.GetPath(); if (!(qs & qsExportSVG)) m_qs_last_output_file = output_file; wxGetApp().app_config->update_last_output_dir(get_dir_name(output_file)); } else if (qs & qsExportPNG) { - auto dlg = new wxFileDialog(this, _(L("Save zip file as:")), + wxFileDialog dlg(this, _(L("Save zip file as:")), wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)), get_base_name(output_file), "*.sl1", wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) return; - } - output_file = dlg->GetPath(); - dlg->Destroy(); + output_file = dlg.GetPath(); } // show processbar dialog @@ -854,28 +845,22 @@ void MainFrame::repair_stl() { wxString input_file; { - auto dlg = new wxFileDialog(this, _(L("Select the STL file to repair:")), + wxFileDialog dlg(this, _(L("Select the STL file to repair:")), wxGetApp().app_config->get_last_dir(), "", file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) return; - } - input_file = dlg->GetPath(); - dlg->Destroy(); + input_file = dlg.GetPath(); } wxString output_file = input_file; { - auto dlg = new wxFileDialog( this, L("Save OBJ file (less prone to coordinate errors than STL) as:"), + wxFileDialog dlg( this, L("Save OBJ file (less prone to coordinate errors than STL) as:"), get_dir_name(output_file), get_base_name(output_file, ".obj"), file_wildcards(FT_OBJ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) return; - } - output_file = dlg->GetPath(); - dlg->Destroy(); + output_file = dlg.GetPath(); } auto tmesh = new Slic3r::TriangleMesh(); @@ -896,14 +881,13 @@ void MainFrame::export_config() return; } // Ask user for the file name for the config file. - auto dlg = new wxFileDialog(this, _(L("Save configuration as:")), + wxFileDialog dlg(this, _(L("Save configuration as:")), !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(), !m_last_config.IsEmpty() ? get_base_name(m_last_config) : "config.ini", file_wildcards(FT_INI), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); wxString file; - if (dlg->ShowModal() == wxID_OK) - file = dlg->GetPath(); - dlg->Destroy(); + if (dlg.ShowModal() == wxID_OK) + file = dlg.GetPath(); if (!file.IsEmpty()) { wxGetApp().app_config->update_config_dir(get_dir_name(file)); m_last_config = file; @@ -916,13 +900,12 @@ void MainFrame::load_config_file() { if (!wxGetApp().check_unsaved_changes()) return; - auto dlg = new wxFileDialog(this, _(L("Select configuration to load:")), + wxFileDialog dlg(this, _(L("Select configuration to load:")), !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(), "config.ini", "INI files (*.ini, *.gcode)|*.ini;*.INI;*.gcode;*.g", wxFD_OPEN | wxFD_FILE_MUST_EXIST); wxString file; - if (dlg->ShowModal() == wxID_OK) - file = dlg->GetPath(); - dlg->Destroy(); + if (dlg.ShowModal() == wxID_OK) + file = dlg.GetPath(); if (! file.IsEmpty() && this->load_config_file(file.ToUTF8().data())) { wxGetApp().app_config->update_config_dir(get_dir_name(file)); m_last_config = file; @@ -953,14 +936,13 @@ void MainFrame::export_configbundle() return; } // Ask user for a file name. - auto dlg = new wxFileDialog(this, _(L("Save presets bundle as:")), + wxFileDialog dlg(this, _(L("Save presets bundle as:")), !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(), SLIC3R_APP_KEY "_config_bundle.ini", file_wildcards(FT_INI), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); wxString file; - if (dlg->ShowModal() == wxID_OK) - file = dlg->GetPath(); - dlg->Destroy(); + if (dlg.ShowModal() == wxID_OK) + file = dlg.GetPath(); if (!file.IsEmpty()) { // Export the config bundle. wxGetApp().app_config->update_config_dir(get_dir_name(file)); @@ -980,15 +962,12 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re if (!wxGetApp().check_unsaved_changes()) return; if (file.IsEmpty()) { - auto dlg = new wxFileDialog(this, _(L("Select configuration to load:")), + wxFileDialog dlg(this, _(L("Select configuration to load:")), !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(), "config.ini", file_wildcards(FT_INI), wxFD_OPEN | wxFD_FILE_MUST_EXIST); - if (dlg->ShowModal() != wxID_OK) { - dlg->Destroy(); - return; - } - file = dlg->GetPath(); - dlg->Destroy(); + if (dlg.ShowModal() != wxID_OK) + return; + file = dlg.GetPath(); } wxGetApp().app_config->update_config_dir(get_dir_name(file)); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 99f63da8a1..97a1da2728 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -296,11 +296,11 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * data->SetChooseFull(1); data->SetColour(clr); - auto dialog = new wxColourDialog(this, data); - dialog->CenterOnParent(); - if (dialog->ShowModal() == wxID_OK) + wxColourDialog dialog(this, data); + dialog.CenterOnParent(); + if (dialog.ShowModal() == wxID_OK) { - colors->values[extruder_idx] = dialog->GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX); + colors->values[extruder_idx] = dialog.GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX); DynamicPrintConfig cfg_new = *cfg; cfg_new.set_key_value("extruder_colour", colors); @@ -309,7 +309,6 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * wxGetApp().preset_bundle->update_platter_filament_ui(extruder_idx, this); wxGetApp().plater()->on_config_change(cfg_new); } - dialog->Destroy(); }); } @@ -2511,15 +2510,14 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type) default: break; } - wxFileDialog* dlg = new wxFileDialog(q, dlg_title, + wxFileDialog dlg(q, dlg_title, from_path(output_file.parent_path()), from_path(output_file.filename()), wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if (dlg->ShowModal() != wxID_OK) { + if (dlg.ShowModal() != wxID_OK) return wxEmptyString; - } - wxString out_path = dlg->GetPath(); + wxString out_path = dlg.GetPath(); fs::path path(into_path(out_path)); wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index d643aa4a86..a7d178e724 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -159,8 +159,8 @@ void Tab::create_preset_tab() m_undo_to_sys_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { on_roll_back_value(true); })); m_question_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { - auto dlg = new ButtonsDescription(this, m_icon_descriptions); - if (dlg->ShowModal() == wxID_OK) { + ButtonsDescription dlg(this, m_icon_descriptions); + if (dlg.ShowModal() == wxID_OK) { // Colors for ui "decoration" for (Tab *tab : wxGetApp().tabs_list) { tab->m_sys_label_clr = wxGetApp().get_label_clr_sys(); @@ -1266,10 +1266,10 @@ void TabPrint::update() if (m_config->opt_float("layer_height") < EPSILON) { const wxString msg_text = _(L("Zero layer height is not valid.\n\nThe layer height will be reset to 0.01.")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Layer height")), wxICON_WARNING | wxOK); + wxMessageDialog dialog(parent(), msg_text, _(L("Layer height")), wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *m_config; is_msg_dlg_already_exist = true; - dialog->ShowModal(); + dialog.ShowModal(); new_conf.set_key_value("layer_height", new ConfigOptionFloat(0.01)); load_config(new_conf); is_msg_dlg_already_exist = false; @@ -1278,10 +1278,10 @@ void TabPrint::update() if (fabs(m_config->option("first_layer_height")->value - 0) < EPSILON) { const wxString msg_text = _(L("Zero first layer height is not valid.\n\nThe first layer height will be reset to 0.01.")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("First layer height")), wxICON_WARNING | wxOK); + wxMessageDialog dialog(parent(), msg_text, _(L("First layer height")), wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *m_config; is_msg_dlg_already_exist = true; - dialog->ShowModal(); + dialog.ShowModal(); new_conf.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.01, false)); load_config(new_conf); is_msg_dlg_already_exist = false; @@ -1299,9 +1299,9 @@ void TabPrint::update() "- no support material\n" "- no ensure_vertical_shell_thickness\n" "\nShall I adjust those settings in order to enable Spiral Vase?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Spiral Vase")), wxICON_WARNING | wxYES | wxNO); + wxMessageDialog dialog(parent(), msg_text, _(L("Spiral Vase")), wxICON_WARNING | wxYES | wxNO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { new_conf.set_key_value("perimeters", new ConfigOptionInt(1)); new_conf.set_key_value("top_solid_layers", new ConfigOptionInt(0)); new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); @@ -1324,9 +1324,9 @@ void TabPrint::update() "if they are printed with the current extruder without triggering a tool change.\n" "(both support_material_extruder and support_material_interface_extruder need to be set to 0).\n" "\nShall I adjust those settings in order to enable the Wipe Tower?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); + wxMessageDialog dialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0)); new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0)); } @@ -1341,9 +1341,9 @@ void TabPrint::update() wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n" "need to be synchronized with the object layers.\n" "\nShall I synchronize support layers in order to enable the Wipe Tower?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); + wxMessageDialog dialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true)); } else @@ -1359,9 +1359,9 @@ void TabPrint::update() wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" "- Detect bridging perimeters\n" "\nShall I adjust those settings for supports?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Support Generator")), wxICON_WARNING | wxYES | wxNO | wxCANCEL); + wxMessageDialog dialog(parent(), msg_text, _(L("Support Generator")), wxICON_WARNING | wxYES | wxNO | wxCANCEL); DynamicPrintConfig new_conf = *m_config; - auto answer = dialog->ShowModal(); + auto answer = dialog.ShowModal(); if (answer == wxID_YES) { // Enable "detect bridging perimeters". new_conf.set_key_value("overhangs", new ConfigOptionBool(true)); @@ -1403,9 +1403,9 @@ void TabPrint::update() if (!correct_100p_fill) { wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density.\n\n" "Shall I switch to rectilinear fill pattern?"))) % str_fill_pattern).str()); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Infill")), wxICON_WARNING | wxYES | wxNO); + wxMessageDialog dialog(parent(), msg_text, _(L("Infill")), wxICON_WARNING | wxYES | wxNO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { new_conf.set_key_value("fill_pattern", new ConfigOptionEnum(ipRectilinear)); fill_density = 100; } @@ -2045,10 +2045,10 @@ void TabPrinter::build_fff() const wxString msg_text = _(L("Single Extruder Multi Material is selected, \n" "and all extruders must have the same diameter.\n" "Do you want to change the diameter for all extruders to first extruder nozzle diameter value?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); + wxMessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { for (size_t i = 1; i < nozzle_diameters.size(); i++) nozzle_diameters[i] = frst_diam; @@ -2507,10 +2507,10 @@ void TabPrinter::build_unregular_pages() { const wxString msg_text = _(L("This is a single extruder multimaterial printer, diameters of all extruders " "will be set to the new value. Do you want to proceed?")); - auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); + wxMessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { for (size_t i = 0; i < nozzle_diameters.size(); i++) { if (i==extruder_idx) continue; @@ -2715,13 +2715,13 @@ void TabPrinter::update_fff() get_field("retract_before_wipe", i)->toggle(wipe); if (use_firmware_retraction && wipe) { - auto dialog = new wxMessageDialog(parent(), + wxMessageDialog dialog(parent(), _(L("The Wipe option is not available when using the Firmware Retraction mode.\n" "\nShall I disable it in order to enable Firmware Retraction?")), _(L("Firmware Retraction")), wxICON_WARNING | wxYES | wxNO); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_YES) { + if (dialog.ShowModal() == wxID_YES) { auto wipe = static_cast(m_config->option("wipe")->clone()); for (int w = 0; w < wipe->values.size(); w++) wipe->values[w] = false; @@ -3073,10 +3073,10 @@ bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr message += wxString("\n") + tab + from_u8(new_printer_name) + "\n\n"; message += _(L("and it has the following unsaved changes:")); } - auto confirm = new wxMessageDialog(parent(), + wxMessageDialog confirm(parent(), message + "\n" + changes + "\n\n" + _(L("Discard changes and continue anyway?")), _(L("Unsaved Changes")), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); - return confirm->ShowModal() == wxID_YES; + return confirm.ShowModal() == wxID_YES; } // If we are switching from the FFF-preset to the SLA, we should to control the printed objects if they have a part(s). @@ -3183,11 +3183,11 @@ void Tab::save_preset(std::string name /*= ""*/) values.push_back(preset.name); } - auto dlg = new SavePresetWindow(parent()); - dlg->build(title(), default_name, values); - if (dlg->ShowModal() != wxID_OK) + SavePresetWindow dlg(parent()); + dlg.build(title(), default_name, values); + if (dlg.ShowModal() != wxID_OK) return; - name = dlg->get_name(); + name = dlg.get_name(); if (name == "") { show_error(this, _(L("The supplied name is empty. It can't be saved."))); return; @@ -3799,13 +3799,13 @@ void TabSLAPrint::update() wxString msg_text = _( L("Head penetration should not be greater than the head width.")); - auto dialog = new wxMessageDialog(parent(), - msg_text, - _(L("Invalid Head penetration")), - wxICON_WARNING | wxOK); + wxMessageDialog dialog(parent(), + msg_text, + _(L("Invalid Head penetration")), + wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_OK) { + if (dialog.ShowModal() == wxID_OK) { new_conf.set_key_value("support_head_penetration", new ConfigOptionFloat(head_width)); } @@ -3819,13 +3819,13 @@ void TabSLAPrint::update() wxString msg_text = _(L( "Pinhead diameter should be smaller than the pillar diameter.")); - auto dialog = new wxMessageDialog(parent(), - msg_text, - _(L("Invalid pinhead diameter")), - wxICON_WARNING | wxOK); + wxMessageDialog dialog (parent(), + msg_text, + _(L("Invalid pinhead diameter")), + wxICON_WARNING | wxOK); DynamicPrintConfig new_conf = *m_config; - if (dialog->ShowModal() == wxID_OK) { + if (dialog.ShowModal() == wxID_OK) { new_conf.set_key_value("support_head_front_diameter", new ConfigOptionFloat(pillar_d / 2.0)); } From 0f32223ba0ec19b1e85141d0ccb997574532ad91 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 16 Aug 2019 00:20:51 +0200 Subject: [PATCH 07/48] WipeTower: linear advance is disabled immediately before ramming, not before moving to the wipe tower Linear advance is reset by filament start gcode after a toolchange. However, not all moves to the wipe tower end with a toolchange (brim, empty grid) and it would therefore disable linear advance until the next toolchange This should solve https://github.com/prusa3d/PrusaSlicer/issues/2770 --- src/libslic3r/GCode.cpp | 3 --- src/libslic3r/GCode/WipeTower.cpp | 7 +++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index b691203c97..1e67f02445 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -197,9 +197,6 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T std::string tcr_rotated_gcode = post_process_wipe_tower_moves(tcr, wipe_tower_offset, wipe_tower_rotation); - // Disable linear advance for the wipe tower operations. - gcode += (gcodegen.config().gcode_flavor == gcfRepRap ? std::string("M572 D0 S0\n") : std::string("M900 K0\n")); - if (!tcr.priming) { // Move over the wipe tower. // Retract for a tool change, using the toolchange retract value and setting the priming extra length. diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index e1b34fdeae..7a764d0f6e 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -113,6 +113,11 @@ public: return (*this); } + WipeTowerWriter& disable_linear_advance() { + m_gcode += (m_gcode_flavor == gcfRepRap ? std::string("M572 D0 S0\n") : std::string("M900 K0\n")); + return *this; + } + // Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various // filament loading and cooling moves from normal extrusion moves. Therefore the writer // is asked to suppres output of some lines, which look like extrusions. @@ -818,6 +823,8 @@ void WipeTower::toolchange_Unload( } } + writer.disable_linear_advance(); + // now the ramming itself: while (i < m_filpar[m_current_tool].ramming_speed.size()) { From eba8c39846c7ada22f68001ac484c56241e417bd Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 16 Aug 2019 13:55:39 +0200 Subject: [PATCH 08/48] Fix performance bottleneck in IGL --- src/libigl/igl/ray_box_intersect.cpp | 28 +++++++++++++-------------- src/libigl/igl/ray_mesh_intersect.cpp | 4 +++- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/libigl/igl/ray_box_intersect.cpp b/src/libigl/igl/ray_box_intersect.cpp index 8c6346d86d..088273f255 100644 --- a/src/libigl/igl/ray_box_intersect.cpp +++ b/src/libigl/igl/ray_box_intersect.cpp @@ -1,12 +1,12 @@ // This file is part of libigl, a simple c++ geometry processing library. -// +// // Copyright (C) 2016 Alec Jacobson -// -// This Source Code Form is subject to the terms of the Mozilla Public License -// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can // obtain one at http://mozilla.org/MPL/2.0/. #include "ray_box_intersect.h" -#include +#include template < typename Derivedsource, @@ -27,7 +27,7 @@ IGL_INLINE bool igl::ray_box_intersect( const Eigen::Vector3f& rayo, const Eigen::Vector3f& rayd, const Eigen::Vector3f& bmin, - const Eigen::Vector3f& bmax, + const Eigen::Vector3f& bmax, float & tnear, float & tfar )->bool @@ -35,12 +35,12 @@ IGL_INLINE bool igl::ray_box_intersect( Eigen::Vector3f bnear; Eigen::Vector3f bfar; // Checks for intersection testing on each direction coordinate - // Computes + // Computes float t1, t2; tnear = -1e+6f, tfar = 1e+6f; //, tCube; bool intersectFlag = true; for (int i = 0; i < 3; ++i) { - // std::cout << "coordinate " << i << ": bmin " << bmin(i) << ", bmax " << bmax(i) << std::endl; + // std::cout << "coordinate " << i << ": bmin " << bmin(i) << ", bmax " << bmax(i) << std::endl; assert(bmin(i) <= bmax(i)); if (::fabs(rayd(i)) < 1e-6) { // Ray parallel to axis i-th if (rayo(i) < bmin(i) || rayo(i) > bmax(i)) { @@ -59,12 +59,12 @@ IGL_INLINE bool igl::ray_box_intersect( } // std::cout << " bnear " << bnear(i) << ", bfar " << bfar(i) << std::endl; // Finds the distance parameters t1 and t2 of the two ray-box intersections: - // t1 must be the closest to the ray origin rayo. + // t1 must be the closest to the ray origin rayo. t1 = (bnear(i) - rayo(i)) / rayd(i); t2 = (bfar(i) - rayo(i)) / rayd(i); if (t1 > t2) { std::swap(t1,t2); - } + } // The two intersection values are used to saturate tnear and tfar if (t1 > tnear) { tnear = t1; @@ -72,7 +72,7 @@ IGL_INLINE bool igl::ray_box_intersect( if (t2 < tfar) { tfar = t2; } - // std::cout << " t1 " << t1 << ", t2 " << t2 << ", tnear " << tnear << ", tfar " << tfar + // std::cout << " t1 " << t1 << ", t2 " << t2 << ", tnear " << tnear << ", tfar " << tfar // << " tnear > tfar? " << (tnear > tfar) << ", tfar < 0? " << (tfar < 0) << std::endl; if(tnear > tfar) { intersectFlag = false; @@ -101,11 +101,11 @@ IGL_INLINE bool igl::ray_box_intersect( // This should be precomputed and provided as input typedef Matrix RowVector3S; const RowVector3S inv_dir( 1./dir(0),1./dir(1),1./dir(2)); - const std::vector sign = { inv_dir(0)<0, inv_dir(1)<0, inv_dir(2)<0}; + const std::array sign = { inv_dir(0)<0, inv_dir(1)<0, inv_dir(2)<0}; // http://people.csail.mit.edu/amy/papers/box-jgt.pdf // "An Efficient and Robust Ray–Box Intersection Algorithm" Scalar tymin, tymax, tzmin, tzmax; - std::vector bounds = {box.min(),box.max()}; + std::array bounds = {box.min(),box.max()}; tmin = ( bounds[sign[0]](0) - origin(0)) * inv_dir(0); tmax = ( bounds[1-sign[0]](0) - origin(0)) * inv_dir(0); tymin = (bounds[sign[1]](1) - origin(1)) * inv_dir(1); @@ -146,4 +146,4 @@ IGL_INLINE bool igl::ray_box_intersect( #ifdef IGL_STATIC_LIBRARY template bool igl::ray_box_intersect, Eigen::Matrix, double>(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::AlignedBox const&, double const&, double const&, double&, double&); -#endif \ No newline at end of file +#endif diff --git a/src/libigl/igl/ray_mesh_intersect.cpp b/src/libigl/igl/ray_mesh_intersect.cpp index 512a35c461..18060fbadb 100644 --- a/src/libigl/igl/ray_mesh_intersect.cpp +++ b/src/libigl/igl/ray_mesh_intersect.cpp @@ -29,7 +29,9 @@ IGL_INLINE bool igl::ray_mesh_intersect( // Should be but can't be const Vector3d s_d = s.template cast(); Vector3d dir_d = dir.template cast(); - hits.clear(); + hits.clear(); + hits.reserve(F.rows()); + // loop over all triangles for(int f = 0;f Date: Fri, 16 Aug 2019 16:17:37 +0200 Subject: [PATCH 09/48] more clang warnings enabled, performance measuring Succesfull build on mingw-w64 fix sandboxes Mingw fixes and full parallel support tree gen. --- CMakeLists.txt | 63 ++- deps/CMakeLists.txt | 5 +- deps/deps-mingw.cmake | 76 +++ deps/deps-unix-common.cmake | 7 + sandboxes/CMakeLists.txt | 1 + sandboxes/slabasebed/slabasebed.cpp | 17 +- sandboxes/slasupporttree/CMakeLists.txt | 2 + sandboxes/slasupporttree/slasupporttree.cpp | 42 ++ src/CMakeLists.txt | 36 +- src/PrusaSlicer.cpp | 238 ++++----- src/PrusaSlicer_app_msvc.cpp | 381 +++++++-------- src/avrdude/CMakeLists.txt | 8 +- src/avrdude/lexer.c | 2 +- src/avrdude/main-standalone.cpp | 4 + src/avrdude/windows/unistd.h | 2 +- src/libigl/igl/SortableRow.h | 84 ++-- .../libnest2d/backends/clipper/geometries.hpp | 8 + src/libslic3r/Arrange.cpp | 10 + src/libslic3r/CMakeLists.txt | 6 +- src/libslic3r/GCode/ToolOrdering.hpp | 73 +-- src/libslic3r/PrintConfig.cpp | 402 ++++++++-------- src/libslic3r/SLA/SLAAutoSupports.cpp | 88 ++-- src/libslic3r/SLA/SLASupportTree.cpp | 328 ++++++------- src/libslic3r/SLA/SLASupportTreeIGL.cpp | 13 +- src/libslic3r/SLAPrint.cpp | 192 ++++---- src/slic3r/GUI/wxExtensions.hpp | 451 +++++++++--------- src/slic3r/Utils/Time.hpp | 2 +- 27 files changed, 1393 insertions(+), 1148 deletions(-) create mode 100644 deps/deps-mingw.cmake create mode 100644 sandboxes/slasupporttree/CMakeLists.txt create mode 100644 sandboxes/slasupporttree/slasupporttree.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a29a144fe3..9b8a1c8480 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,13 +13,13 @@ if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) endif() if(DEFINED ENV{SLIC3R_STATIC}) - set(SLIC3R_STATIC_INITIAL $ENV{SLIC3R_STATIC}) + set(SLIC3R_STATIC_INITIAL $ENV{SLIC3R_STATIC}) else() - if (MSVC OR MINGW OR APPLE) - set(SLIC3R_STATIC_INITIAL 1) - else() - set(SLIC3R_STATIC_INITIAL 0) - endif() + if (MSVC OR MINGW OR APPLE) + set(SLIC3R_STATIC_INITIAL 1) + else() + set(SLIC3R_STATIC_INITIAL 0) + endif() endif() option(SLIC3R_STATIC "Compile PrusaSlicer with static libraries (Boost, TBB, glew)" ${SLIC3R_STATIC_INITIAL}) @@ -54,13 +54,19 @@ endif () if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) set(IS_CLANG_CL TRUE) + + # clang-cl can interpret SYSTEM header paths if -imsvc is used + set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-imsvc") + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall \ + -Wno-old-style-cast -Wno-reserved-id-macro -Wno-c++98-compat-pedantic") else () set(IS_CLANG_CL FALSE) endif () if (MSVC) if (SLIC3R_MSVC_COMPILE_PARALLEL AND NOT IS_CLANG_CL) - add_compile_options(/MP) + add_compile_options(/MP) endif () # /bigobj (Increase Number of Sections in .Obj file) # error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater @@ -68,6 +74,10 @@ if (MSVC) add_compile_options(-bigobj -Zm520 /Zi) endif () +if (MINGW) + add_compile_options(-Wa,-mbig-obj) +endif () + # Display and check CMAKE_PREFIX_PATH message(STATUS "SLIC3R_STATIC: ${SLIC3R_STATIC}") if (NOT "${CMAKE_PREFIX_PATH}" STREQUAL "") @@ -107,17 +117,17 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) # WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory. # We pick it from environment if it is not defined in another way if(WIN32) - if(NOT DEFINED WIN10SDK_PATH) - if(DEFINED ENV{WIN10SDK_PATH}) - set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}") - endif() - endif() - if(DEFINED WIN10SDK_PATH AND NOT EXISTS "${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h") - message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}") - message("${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h was not found") - message("STL fixing by the Netfabb service will not be compiled") - unset(WIN10SDK_PATH) - endif() + if(NOT DEFINED WIN10SDK_PATH) + if(DEFINED ENV{WIN10SDK_PATH}) + set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}") + endif() + endif() + if(DEFINED WIN10SDK_PATH AND NOT EXISTS "${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h") + message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}") + message("${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h was not found") + message("STL fixing by the Netfabb service will not be compiled") + unset(WIN10SDK_PATH) + endif() if(WIN10SDK_PATH) message("Building with Win10 Netfabb STL fixing service support") add_definitions(-DHAS_WIN10SDK) @@ -155,7 +165,9 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX) endif() if (NOT MSVC AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" ) + if (NOT MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" ) + endif () set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder" ) # On GCC and Clang, no return from a non-void function is a warning only. Here, we make it an error. @@ -201,9 +213,12 @@ include_directories(${LIBDIR_BIN}/platform) include_directories(${LIBDIR}/clipper ${LIBDIR}/polypartition) if(WIN32) - # BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking. - add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x601 -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) -endif() + add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) + if(MSVC) + # BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking. + add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x601 ) + endif(MSVC) +endif(WIN32) add_definitions(-DwxUSE_UNICODE -D_UNICODE -DUNICODE -DWXINTL_NO_GETTEXT_MACRO) @@ -234,7 +249,7 @@ if(SLIC3R_STATIC) # set(Boost_USE_STATIC_RUNTIME ON) endif() #set(Boost_DEBUG ON) -# set(Boost_COMPILER "-vc120") +# set(Boost_COMPILER "-mgw81") if(NOT WIN32) # boost::process was introduced first in version 1.64.0 set(MINIMUM_BOOST_VERSION "1.64.0") @@ -256,7 +271,7 @@ endif() if(TARGET Boost::system) message(STATUS "Boost::boost exists") target_link_libraries(boost_headeronly INTERFACE Boost::boost) - target_link_libraries(boost_libs INTERFACE + target_link_libraries(boost_libs INTERFACE boost_headeronly # includes the custom compile definitions as well Boost::system Boost::filesystem diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index f6a80f3ca0..90ad6f0fa7 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -76,7 +76,10 @@ elseif (APPLE) endif () include("deps-macos.cmake") -else () +elseif (MINGW) + message(STATUS "Building for MinGW...") + include("deps-mingw.cmake") +else() include("deps-linux.cmake") endif() diff --git a/deps/deps-mingw.cmake b/deps/deps-mingw.cmake new file mode 100644 index 0000000000..bfe5f9fe43 --- /dev/null +++ b/deps/deps-mingw.cmake @@ -0,0 +1,76 @@ +set(DEP_CMAKE_OPTS "-DCMAKE_POSITION_INDEPENDENT_CODE=ON") +set(DEP_BOOST_TOOLSET "gcc") +set(DEP_BITS 64) + +find_package(Git REQUIRED) + +# TODO make sure to build tbb with -flifetime-dse=1 +include("deps-unix-common.cmake") + +ExternalProject_Add(dep_boost + EXCLUDE_FROM_ALL 1 + URL "https://dl.bintray.com/boostorg/release/1.70.0/source/boost_1_70_0.tar.gz" + URL_HASH SHA256=882b48708d211a5f48e60b0124cf5863c1534cd544ecd0664bb534a4b5d506e9 + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND bootstrap.bat + BUILD_COMMAND b2.exe + -j "${NPROC}" + --with-system + --with-filesystem + --with-thread + --with-log + --with-locale + --with-regex + "--prefix=${DESTDIR}/usr/local" + "address-model=${DEPS_BITS}" + "toolset=${DEP_BOOST_TOOLSET}" + link=static + define=BOOST_USE_WINAPI_VERSION=0x0502 + variant=release + threading=multi + boost.locale.icu=off + "${DEP_BOOST_DEBUG}" release install + INSTALL_COMMAND "" # b2 does that already +) + +ExternalProject_Add(dep_libcurl + EXCLUDE_FROM_ALL 1 + URL "https://curl.haxx.se/download/curl-7.58.0.tar.gz" + URL_HASH SHA256=cc245bf9a1a42a45df491501d97d5593392a03f7b4f07b952793518d97666115 + CMAKE_ARGS + -DBUILD_SHARED_LIBS=OFF + -DBUILD_TESTING=OFF + -DCURL_STATICLIB=ON + -DCURL_STATIC_CRT=ON + -DENABLE_THREADED_RESOLVER=ON + -DCURL_DISABLE_FTP=ON + -DCURL_DISABLE_LDAP=ON + -DCURL_DISABLE_LDAPS=ON + -DCURL_DISABLE_TELNET=ON + -DCURL_DISABLE_DICT=ON + -DCURL_DISABLE_FILE=ON + -DCURL_DISABLE_TFTP=ON + -DCURL_DISABLE_RTSP=ON + -DCURL_DISABLE_POP3=ON + -DCURL_DISABLE_IMAP=ON + -DCURL_DISABLE_SMTP=ON + -DCURL_DISABLE_GOPHER=ON + -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local + ${DEP_CMAKE_OPTS} +) + +ExternalProject_Add(dep_wxwidgets + EXCLUDE_FROM_ALL 1 + GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets" + GIT_TAG v3.1.1-patched +# URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.1/wxWidgets-3.1.1.tar.bz2" +# URL_HASH SHA256=c925dfe17e8f8b09eb7ea9bfdcfcc13696a3e14e92750effd839f5e10726159e +# PATCH_COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}\\wxwidgets-pngprefix.h" src\\png\\pngprefix.h + CMAKE_ARGS + -DBUILD_SHARED_LIBS=OFF + -DwxUSE_LIBPNG=builtin + -DwxUSE_ZLIB=builtin + -DwxUSE_OPENGL=ON + -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local + ${DEP_CMAKE_OPTS} +) \ No newline at end of file diff --git a/deps/deps-unix-common.cmake b/deps/deps-unix-common.cmake index e323460a6d..6e559d05a3 100644 --- a/deps/deps-unix-common.cmake +++ b/deps/deps-unix-common.cmake @@ -1,6 +1,12 @@ # The unix common part expects DEP_CMAKE_OPTS to be set +if (MINGW) + set(TBB_MINGW_WORKAROUND "-flifetime-dse=1") +else () + set(TBB_MINGW_WORKAROUND "") +endif () + ExternalProject_Add(dep_tbb EXCLUDE_FROM_ALL 1 URL "https://github.com/wjakob/tbb/archive/a0dc9bf76d0120f917b641ed095360448cabc85b.tar.gz" @@ -8,6 +14,7 @@ ExternalProject_Add(dep_tbb CMAKE_ARGS -DTBB_BUILD_SHARED=OFF -DTBB_BUILD_TESTS=OFF + -DCMAKE_CXX_FLAGS=${TBB_MINGW_WORKAROUND} -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local ${DEP_CMAKE_OPTS} ) diff --git a/sandboxes/CMakeLists.txt b/sandboxes/CMakeLists.txt index 0e1f52d6cf..5905c438e9 100644 --- a/sandboxes/CMakeLists.txt +++ b/sandboxes/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(slabasebed) +add_subdirectory(slasupporttree) diff --git a/sandboxes/slabasebed/slabasebed.cpp b/sandboxes/slabasebed/slabasebed.cpp index 5393f61fd7..b8b94d86f3 100644 --- a/sandboxes/slabasebed/slabasebed.cpp +++ b/sandboxes/slabasebed/slabasebed.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -15,8 +16,8 @@ const std::string USAGE_STR = { namespace Slic3r { namespace sla { -Contour3D create_base_pool(const Polygons &ground_layer, - const Polygons &holes = {}, +Contour3D create_base_pool(const Polygons &ground_layer, + const ExPolygons &holes = {}, const PoolConfig& cfg = PoolConfig()); Contour3D walls(const Polygon& floor_plate, const Polygon& ceiling, @@ -43,22 +44,22 @@ int main(const int argc, const char *argv[]) { model.ReadSTLFile(argv[1]); model.align_to_origin(); - Polygons ground_slice; + ExPolygons ground_slice; sla::base_plate(model, ground_slice, 0.1f); if(ground_slice.empty()) return EXIT_FAILURE; - Polygon gndfirst; gndfirst = ground_slice.front(); - sla::offset_with_breakstick_holes(gndfirst, 0.5, 10, 0.3); + ground_slice = offset_ex(ground_slice, 0.5); + ExPolygon gndfirst; gndfirst = ground_slice.front(); + sla::breakstick_holes(gndfirst, 0.5, 10, 0.3); sla::Contour3D mesh; - bench.start(); sla::PoolConfig cfg; cfg.min_wall_height_mm = 0; cfg.edge_radius_mm = 0; - mesh = sla::create_base_pool(ground_slice, {}, cfg); + mesh = sla::create_base_pool(to_polygons(ground_slice), {}, cfg); bench.stop(); @@ -75,7 +76,7 @@ int main(const int argc, const char *argv[]) { if(std::abs(a) < 1e-6) std::cout << "degenerate triangle" << std::endl; } -// basepool.write_ascii("out.stl"); + // basepool.write_ascii("out.stl"); std::fstream outstream("out.obj", std::fstream::out); mesh.to_obj(outstream); diff --git a/sandboxes/slasupporttree/CMakeLists.txt b/sandboxes/slasupporttree/CMakeLists.txt new file mode 100644 index 0000000000..79adb842b9 --- /dev/null +++ b/sandboxes/slasupporttree/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(slasupporttree slasupporttree.cpp) +target_link_libraries(slasupporttree libslic3r ${Boost_LIBRARIES} ${TBB_LIBRARIES} ${Boost_LIBRARIES} ${CMAKE_DL_LIBS}) diff --git a/sandboxes/slasupporttree/slasupporttree.cpp b/sandboxes/slasupporttree/slasupporttree.cpp new file mode 100644 index 0000000000..dcaddf6d3f --- /dev/null +++ b/sandboxes/slasupporttree/slasupporttree.cpp @@ -0,0 +1,42 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +const std::string USAGE_STR = { + "Usage: slasupporttree stlfilename.stl" +}; + +int main(const int argc, const char *argv[]) { + using namespace Slic3r; + using std::cout; using std::endl; + + if(argc < 2) { + cout << USAGE_STR << endl; + return EXIT_SUCCESS; + } + + DynamicPrintConfig config; + + Model model = Model::read_from_file(argv[1], &config); + + SLAPrint print; + + print.apply(model, config); + print.process(); + + + return EXIT_SUCCESS; +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3ee46289ad..9f3dbcec89 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,7 +47,7 @@ if (SLIC3R_GUI) endif () endif () else () - find_package(wxWidgets 3.1 REQUIRED COMPONENTS base core adv html gl) + find_package(wxWidgets 3.1 REQUIRED COMPONENTS html adv gl core base) endif () if(UNIX) @@ -56,6 +56,9 @@ if (SLIC3R_GUI) include(${wxWidgets_USE_FILE}) +# list(REMOVE_ITEM wxWidgets_LIBRARIES oleacc) + message(STATUS "wx libs: ${wxWidgets_LIBRARIES}") + add_subdirectory(slic3r) endif() @@ -65,12 +68,18 @@ endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/PrusaSlicer.rc.in ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.rc @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/PrusaSlicer.manifest.in ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.manifest @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/osx/Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/Info.plist @ONLY) -if (MSVC) +if (WIN32) add_library(PrusaSlicer SHARED PrusaSlicer.cpp PrusaSlicer.hpp) else () add_executable(PrusaSlicer PrusaSlicer.cpp PrusaSlicer.hpp) endif () -if (NOT MSVC) + +if (MINGW) + target_link_options(PrusaSlicer PUBLIC "-Wl,-allow-multiple-definition") + set_target_properties(PrusaSlicer PROPERTIES PREFIX "") +endif (MINGW) + +if (NOT WIN32) # Binary name on unix like systems (OSX, Linux) set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer") endif () @@ -91,11 +100,12 @@ endif () # Add the Slic3r GUI library, libcurl, OpenGL and GLU libraries. if (SLIC3R_GUI) - target_link_libraries(PrusaSlicer libslic3r_gui ${wxWidgets_LIBRARIES}) +# target_link_libraries(PrusaSlicer ws2_32 uxtheme setupapi libslic3r_gui ${wxWidgets_LIBRARIES}) +target_link_libraries(PrusaSlicer libslic3r_gui ${wxWidgets_LIBRARIES}) # Configure libcurl and its dependencies OpenSSL & zlib find_package(CURL REQUIRED) - if (NOT MSVC) + if (NOT WIN32) # Required by libcurl find_package(ZLIB REQUIRED) endif() @@ -123,7 +133,7 @@ if (SLIC3R_GUI) target_link_options(PrusaSlicer PUBLIC "$<$:/DEBUG>") target_link_libraries(PrusaSlicer user32.lib Setupapi.lib OpenGL32.Lib GlU32.Lib) elseif (MINGW) - target_link_libraries(PrusaSlicer -lopengl32) + target_link_libraries(PrusaSlicer opengl32 ws2_32 uxtheme setupapi) elseif (APPLE) target_link_libraries(PrusaSlicer "-framework OpenGL") else () @@ -133,10 +143,16 @@ endif () # On Windows, a shim application is required to produce a console / non console version of the Slic3r application. # Also the shim may load the Mesa software OpenGL renderer if the default renderer does not support OpenGL 2.0 and higher. -if (MSVC) +if (WIN32) + if (MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode") + endif() + add_executable(PrusaSlicer_app_gui WIN32 PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.rc) # Generate debug symbols even in release mode. - target_link_options(PrusaSlicer_app_gui PUBLIC "$<$:/DEBUG>") + if(MSVC) + target_link_options(PrusaSlicer_app_gui PUBLIC "$<$:/DEBUG>") + endif() target_compile_definitions(PrusaSlicer_app_gui PRIVATE -DSLIC3R_WRAPPER_NOCONSOLE) add_dependencies(PrusaSlicer_app_gui PrusaSlicer) set_target_properties(PrusaSlicer_app_gui PROPERTIES OUTPUT_NAME "prusa-slicer") @@ -144,7 +160,9 @@ if (MSVC) add_executable(PrusaSlicer_app_console PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.rc) # Generate debug symbols even in release mode. + if (MSVC) target_link_options(PrusaSlicer_app_console PUBLIC "$<$:/DEBUG>") + endif () target_compile_definitions(PrusaSlicer_app_console PRIVATE -DSLIC3R_WRAPPER_CONSOLE) add_dependencies(PrusaSlicer_app_console PrusaSlicer) set_target_properties(PrusaSlicer_app_console PROPERTIES OUTPUT_NAME "prusa-slicer-console") @@ -152,7 +170,7 @@ if (MSVC) endif () # Link the resources dir to where Slic3r GUI expects it -if (MSVC) +if (WIN32) if (CMAKE_CONFIGURATION_TYPES) foreach (CONF ${CMAKE_CONFIGURATION_TYPES}) file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CONF}" WIN_CONF_OUTPUT_DIR) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index b1ba30553e..c8cf9b42d8 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -7,8 +7,8 @@ #include #include #ifdef SLIC3R_GUI - extern "C" - { + extern "C" + { // Let the NVIDIA and AMD know we want to use their graphics card // on a dual graphics card system. __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; @@ -53,28 +53,28 @@ using namespace Slic3r; PrinterTechnology get_printer_technology(const DynamicConfig &config) { - const ConfigOptionEnum *opt = config.option>("printer_technology"); + const ConfigOptionEnum *opt = config.option>("printer_technology"); return (opt == nullptr) ? ptUnknown : opt->value; } -int CLI::run(int argc, char **argv) +int CLI::run(int argc, char **argv) { - if (! this->setup(argc, argv)) - return 1; + if (! this->setup(argc, argv)) + return 1; m_extra_config.apply(m_config, true); m_extra_config.normalize(); bool start_gui = m_actions.empty() && // cutting transformations are setting an "export" action. - std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() && - std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() && - std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end(); + std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() && + std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() && + std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end(); PrinterTechnology printer_technology = get_printer_technology(m_extra_config); - const std::vector &load_configs = m_config.option("load", true)->values; - + const std::vector &load_configs = m_config.option("load", true)->values; + // load config files supplied via --load - for (auto const &file : load_configs) { + for (auto const &file : load_configs) { if (! boost::filesystem::exists(file)) { if (m_config.opt_bool("ignore_nonexistent_config")) { continue; @@ -100,7 +100,7 @@ int CLI::run(int argc, char **argv) } m_print_config.apply(config); } - + // Read input file(s) if any. for (const std::string &file : m_input_files) { if (! boost::filesystem::exists(file)) { @@ -136,21 +136,21 @@ int CLI::run(int argc, char **argv) m_print_config.normalize(); if (printer_technology == ptUnknown) - printer_technology = std::find(m_actions.begin(), m_actions.end(), "export_sla") == m_actions.end() ? ptFFF : ptSLA; + printer_technology = std::find(m_actions.begin(), m_actions.end(), "export_sla") == m_actions.end() ? ptFFF : ptSLA; // Initialize full print configs for both the FFF and SLA technologies. FullPrintConfig fff_print_config; // SLAFullPrintConfig sla_print_config; fff_print_config.apply(m_print_config, true); // sla_print_config.apply(m_print_config, true); - + // Loop through transform options. for (auto const &opt_key : m_transforms) { if (opt_key == "merge") { Model m; for (auto &model : m_models) - for (ModelObject *o : model.objects) - m.add_object(*o); + for (ModelObject *o : model.objects) + m.add_object(*o); // Rearrange instances unless --dont-arrange is supplied if (! m_config.opt_bool("dont_arrange")) { m.add_default_instances(); @@ -162,8 +162,8 @@ int CLI::run(int argc, char **argv) this->has_print_action() ? &bb : nullptr ); } - m_models.clear(); - m_models.emplace_back(std::move(m)); + m_models.clear(); + m_models.emplace_back(std::move(m)); } else if (opt_key == "duplicate") { const BoundingBoxf &bb = fff_print_config.bed_shape.values; for (auto &model : m_models) { @@ -192,11 +192,11 @@ int CLI::run(int argc, char **argv) // this affects instances: model.center_instances_around_point(m_config.option("center")->value); // this affects volumes: - //FIXME Vojtech: Who knows why the complete model should be aligned with Z as a single rigid body? + //FIXME Vojtech: Who knows why the complete model should be aligned with Z as a single rigid body? //model.align_to_ground(); BoundingBoxf3 bbox; for (ModelObject *model_object : model.objects) - // We are interested into the Z span only, therefore it is sufficient to measure the bounding box of the 1st instance only. + // We are interested into the Z span only, therefore it is sufficient to measure the bounding box of the 1st instance only. bbox.merge(model_object->instance_bounding_box(0, false)); for (ModelObject *model_object : model.objects) for (ModelInstance *model_instance : model_object->instances) @@ -207,7 +207,7 @@ int CLI::run(int argc, char **argv) for (auto &model : m_models) { BoundingBoxf3 bb = model.bounding_box(); // this affects volumes: - model.translate(-(bb.min.x() - p.x()), -(bb.min.y() - p.y()), -bb.min.z()); + model.translate(-(bb.min.x() - p.x()), -(bb.min.y() - p.y()), -bb.min.z()); } } else if (opt_key == "dont_arrange") { // do nothing - this option alters other transform options @@ -245,8 +245,8 @@ int CLI::run(int argc, char **argv) std::vector new_models; for (auto &model : m_models) { model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0 - size_t num_objects = model.objects.size(); - for (size_t i = 0; i < num_objects; ++ i) { + size_t num_objects = model.objects.size(); + for (size_t i = 0; i < num_objects; ++ i) { #if 0 if (opt_key == "cut_x") { @@ -257,15 +257,15 @@ int CLI::run(int argc, char **argv) o->cut(Z, m_config.opt_float("cut"), &out); } #else - model.objects.front()->cut(0, m_config.opt_float("cut"), true, true, true); + model.objects.front()->cut(0, m_config.opt_float("cut"), true, true, true); #endif - model.delete_object(size_t(0)); + model.delete_object(size_t(0)); } } - + // TODO: copy less stuff around using pointers m_models = new_models; - + if (m_actions.empty()) m_actions.push_back("export_stl"); } @@ -275,7 +275,7 @@ int CLI::run(int argc, char **argv) for (auto &model : m_models) { TriangleMesh mesh = model.mesh(); mesh.repair(); - + TriangleMeshPtrs meshes = mesh.cut_by_grid(m_config.option("cut_grid")->value); size_t i = 0; for (TriangleMesh* m : meshes) { @@ -286,10 +286,10 @@ int CLI::run(int argc, char **argv) delete m; } } - + // TODO: copy less stuff around using pointers m_models = new_models; - + if (m_actions.empty()) m_actions.push_back("export_stl"); } @@ -303,7 +303,7 @@ int CLI::run(int argc, char **argv) } } } else if (opt_key == "repair") { - // Models are repaired by default. + // Models are repaired by default. //for (auto &model : m_models) // model.repair(); } else { @@ -311,7 +311,7 @@ int CLI::run(int argc, char **argv) return 1; } } - + // loop through action options for (auto const &opt_key : m_actions) { if (opt_key == "help") { @@ -354,14 +354,14 @@ int CLI::run(int argc, char **argv) boost::nowide::cerr << "error: cannot export SLA slices for a SLA configuration" << std::endl; return 1; } - // Make a copy of the model if the current action is not the last action, as the model may be - // modified by the centering and such. - Model model_copy; - bool make_copy = &opt_key != &m_actions.back(); + // Make a copy of the model if the current action is not the last action, as the model may be + // modified by the centering and such. + Model model_copy; + bool make_copy = &opt_key != &m_actions.back(); for (Model &model_in : m_models) { - if (make_copy) - model_copy = model_in; - Model &model = make_copy ? model_copy : model_in; + if (make_copy) + model_copy = model_in; + Model &model = make_copy ? model_copy : model_in; // If all objects have defined instances, their relative positions will be // honored when printing (they will be only centered, unless --dont-arrange // is supplied); if any object has no instances, it will get a default one @@ -381,7 +381,7 @@ int CLI::run(int argc, char **argv) if (! m_config.opt_bool("dont_arrange")) { //FIXME make the min_object_distance configurable. model.arrange_objects(fff_print.config().min_object_distance()); - model.center_instances_around_point(m_config.option("center")->value); + model.center_instances_around_point(m_config.option("center")->value); } if (printer_technology == ptFFF) { for (auto* mo : model.objects) @@ -395,40 +395,40 @@ int CLI::run(int argc, char **argv) } if (print->empty()) boost::nowide::cout << "Nothing to print for " << outfile << " . Either the print is empty or no object is fully inside the print volume." << std::endl; - else + else try { std::string outfile_final; - print->process(); + print->process(); if (printer_technology == ptFFF) { // The outfile is processed by a PlaceholderParser. outfile = fff_print.export_gcode(outfile, nullptr); outfile_final = fff_print.print_statistics().finalize_output_path(outfile); } else { - outfile = sla_print.output_filepath(outfile); + outfile = sla_print.output_filepath(outfile); // We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata outfile_final = sla_print.print_statistics().finalize_output_path(outfile); - sla_print.export_raster(outfile_final); + sla_print.export_raster(outfile_final); } if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final) != 0) { - boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; + boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; return 1; } boost::nowide::cout << "Slicing result exported to " << outfile << std::endl; } catch (const std::exception &ex) { - boost::nowide::cerr << ex.what() << std::endl; - return 1; + boost::nowide::cerr << ex.what() << std::endl; + return 1; } /* print.center = ! m_config.has("center") && ! m_config.has("align_xy") && ! m_config.opt_bool("dont_arrange"); print.set_model(model); - + // start chronometer typedef std::chrono::high_resolution_clock clock_; typedef std::chrono::duration > second_; std::chrono::time_point t0{ clock_::now() }; - + const std::string outfile = this->output_filepath(model, IO::Gcode); try { print.export_gcode(outfile); @@ -437,7 +437,7 @@ int CLI::run(int argc, char **argv) return 1; } boost::nowide::cout << "G-code exported to " << outfile << std::endl; - + // output some statistics double duration { std::chrono::duration_cast(clock_::now() - t0).count() }; boost::nowide::cout << std::fixed << std::setprecision(0) @@ -454,45 +454,45 @@ int CLI::run(int argc, char **argv) return 1; } } - - if (start_gui) { + + if (start_gui) { #ifdef SLIC3R_GUI // #ifdef USE_WX - GUI::GUI_App *gui = new GUI::GUI_App(); + GUI::GUI_App *gui = new GUI::GUI_App(); // gui->autosave = m_config.opt_string("autosave"); - GUI::GUI_App::SetInstance(gui); - gui->CallAfter([gui, this, &load_configs] { - if (!gui->initialized()) { - return; - } + GUI::GUI_App::SetInstance(gui); + gui->CallAfter([gui, this, &load_configs] { + if (!gui->initialized()) { + return; + } #if 0 - // Load the cummulative config over the currently active profiles. - //FIXME if multiple configs are loaded, only the last one will have an effect. - // We need to decide what to do about loading of separate presets (just print preset, just filament preset etc). - // As of now only the full configs are supported here. - if (!m_print_config.empty()) - gui->mainframe->load_config(m_print_config); + // Load the cummulative config over the currently active profiles. + //FIXME if multiple configs are loaded, only the last one will have an effect. + // We need to decide what to do about loading of separate presets (just print preset, just filament preset etc). + // As of now only the full configs are supported here. + if (!m_print_config.empty()) + gui->mainframe->load_config(m_print_config); #endif - if (! load_configs.empty()) - // Load the last config to give it a name at the UI. The name of the preset may be later - // changed by loading an AMF or 3MF. - //FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config. - gui->mainframe->load_config_file(load_configs.back()); - // If loading a 3MF file, the config is loaded from the last one. - if (! m_input_files.empty()) - gui->plater()->load_files(m_input_files, true, true); - if (! m_extra_config.empty()) - gui->mainframe->load_config(m_extra_config); - }); - return wxEntry(argc, argv); + if (! load_configs.empty()) + // Load the last config to give it a name at the UI. The name of the preset may be later + // changed by loading an AMF or 3MF. + //FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config. + gui->mainframe->load_config_file(load_configs.back()); + // If loading a 3MF file, the config is loaded from the last one. + if (! m_input_files.empty()) + gui->plater()->load_files(m_input_files, true, true); + if (! m_extra_config.empty()) + gui->mainframe->load_config(m_extra_config); + }); + return wxEntry(argc, argv); #else /* SLIC3R_GUI */ - // No GUI support. Just print out a help. - this->print_help(false); - // If started without a parameter, consider it to be OK, otherwise report an error code (no action etc). - return (argc == 0) ? 0 : 1; + // No GUI support. Just print out a help. + this->print_help(false); + // If started without a parameter, consider it to be OK, otherwise report an error code (no action etc). + return (argc == 0) ? 0 : 1; #endif /* SLIC3R_GUI */ } - + return 0; } @@ -539,18 +539,18 @@ bool CLI::setup(int argc, char **argv) // If any option is unsupported, print usage and abort immediately. t_config_option_keys opt_order; if (! m_config.read_cli(argc, argv, &m_input_files, &opt_order)) { - // Separate error message reported by the CLI parser from the help. - boost::nowide::cerr << std::endl; + // Separate error message reported by the CLI parser from the help. + boost::nowide::cerr << std::endl; this->print_help(); - return false; + return false; + } + // Parse actions and transform options. + for (auto const &opt_key : opt_order) { + if (cli_actions_config_def.has(opt_key)) + m_actions.emplace_back(opt_key); + else if (cli_transform_config_def.has(opt_key)) + m_transforms.emplace_back(opt_key); } - // Parse actions and transform options. - for (auto const &opt_key : opt_order) { - if (cli_actions_config_def.has(opt_key)) - m_actions.emplace_back(opt_key); - else if (cli_transform_config_def.has(opt_key)) - m_transforms.emplace_back(opt_key); - } { const ConfigOptionInt *opt_loglevel = m_config.opt("loglevel"); @@ -563,15 +563,15 @@ bool CLI::setup(int argc, char **argv) for (const std::pair &optdef : *options) m_config.optptr(optdef.first, true); - set_data_dir(m_config.opt_string("datadir")); + set_data_dir(m_config.opt_string("datadir")); - return true; + return true; } -void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const +void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const { boost::nowide::cout - << SLIC3R_BUILD_ID << " " << "based on Slic3r" + << SLIC3R_BUILD_ID << " " << "based on Slic3r" #ifdef SLIC3R_GUI << " (with GUI support)" #else /* SLIC3R_GUI */ @@ -583,20 +583,20 @@ void CLI::print_help(bool include_print_options, PrinterTechnology printer_techn << std::endl << "Actions:" << std::endl; cli_actions_config_def.print_cli_help(boost::nowide::cout, false); - + boost::nowide::cout << std::endl << "Transform options:" << std::endl; cli_transform_config_def.print_cli_help(boost::nowide::cout, false); - + boost::nowide::cout << std::endl << "Other options:" << std::endl; cli_misc_config_def.print_cli_help(boost::nowide::cout, false); - + if (include_print_options) { boost::nowide::cout << std::endl; - print_config_def.print_cli_help(boost::nowide::cout, true, [printer_technology](const ConfigOptionDef &def) + print_config_def.print_cli_help(boost::nowide::cout, true, [printer_technology](const ConfigOptionDef &def) { return printer_technology == ptAny || def.printer_technology == ptAny || printer_technology == def.printer_technology; }); } else { boost::nowide::cout @@ -613,14 +613,14 @@ bool CLI::export_models(IO::ExportFormat format) switch (format) { case IO::AMF: success = Slic3r::store_amf(path.c_str(), &model, nullptr); break; case IO::OBJ: success = Slic3r::store_obj(path.c_str(), &model); break; - case IO::STL: success = Slic3r::store_stl(path.c_str(), &model, true); break; - case IO::TMF: success = Slic3r::store_3mf(path.c_str(), &model, nullptr); break; + case IO::STL: success = Slic3r::store_stl(path.c_str(), &model, true); break; + case IO::TMF: success = Slic3r::store_3mf(path.c_str(), &model, nullptr); break; default: assert(false); break; } if (success) - std::cout << "File exported to " << path << std::endl; + std::cout << "File exported to " << path << std::endl; else { - std::cerr << "File export to " << path << " failed" << std::endl; + std::cerr << "File export to " << path << " failed" << std::endl; return false; } } @@ -634,12 +634,12 @@ std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) co case IO::AMF: ext = ".zip.amf"; break; case IO::OBJ: ext = ".obj"; break; case IO::STL: ext = ".stl"; break; - case IO::TMF: ext = ".3mf"; break; + case IO::TMF: ext = ".3mf"; break; default: assert(false); break; }; auto proposed_path = boost::filesystem::path(model.propose_export_file_name_and_path(ext)); // use --output when available - std::string cmdline_param = m_config.opt_string("output"); + std::string cmdline_param = m_config.opt_string("output"); if (! cmdline_param.empty()) { // if we were supplied a directory, use it and append our automatically generated filename boost::filesystem::path cmdline_path(cmdline_param); @@ -651,20 +651,20 @@ std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) co return proposed_path.string(); } -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__MINGW32__) extern "C" { - __declspec(dllexport) int __stdcall slic3r_main(int argc, wchar_t **argv) - { - // Convert wchar_t arguments to UTF8. - std::vector argv_narrow; - std::vector argv_ptrs(argc + 1, nullptr); - for (size_t i = 0; i < argc; ++ i) - argv_narrow.emplace_back(boost::nowide::narrow(argv[i])); - for (size_t i = 0; i < argc; ++ i) - argv_ptrs[i] = const_cast(argv_narrow[i].data()); - // Call the UTF8 main. - return CLI().run(argc, argv_ptrs.data()); - } + __declspec(dllexport) int __stdcall slic3r_main(int argc, wchar_t **argv) + { + // Convert wchar_t arguments to UTF8. + std::vector argv_narrow; + std::vector argv_ptrs(argc + 1, nullptr); + for (size_t i = 0; i < argc; ++ i) + argv_narrow.emplace_back(boost::nowide::narrow(argv[i])); + for (size_t i = 0; i < argc; ++ i) + argv_ptrs[i] = const_cast(argv_narrow[i].data()); + // Call the UTF8 main. + return CLI().run(argc, argv_ptrs.data()); + } } #else /* _MSC_VER */ int main(int argc, char **argv) diff --git a/src/PrusaSlicer_app_msvc.cpp b/src/PrusaSlicer_app_msvc.cpp index 95dd4fb075..b3d1e8bb47 100644 --- a/src/PrusaSlicer_app_msvc.cpp +++ b/src/PrusaSlicer_app_msvc.cpp @@ -8,12 +8,12 @@ #include #ifdef SLIC3R_GUI -extern "C" -{ - // Let the NVIDIA and AMD know we want to use their graphics card - // on a dual graphics card system. - __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; - __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; +extern "C" +{ + // Let the NVIDIA and AMD know we want to use their graphics card + // on a dual graphics card system. + __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; + __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; } #endif /* SLIC3R_GUI */ @@ -21,7 +21,7 @@ extern "C" #include #ifdef SLIC3R_GUI - #include + #include #endif /* SLIC3R_GUI */ #include @@ -36,97 +36,97 @@ extern "C" class OpenGLVersionCheck { public: - std::string version; - std::string glsl_version; - std::string vendor; - std::string renderer; + std::string version; + std::string glsl_version; + std::string vendor; + std::string renderer; - HINSTANCE hOpenGL = nullptr; - bool success = false; + HINSTANCE hOpenGL = nullptr; + bool success = false; - bool load_opengl_dll() - { - MSG msg = {0}; - WNDCLASS wc = {0}; - wc.lpfnWndProc = OpenGLVersionCheck::supports_opengl2_wndproc; - wc.hInstance = (HINSTANCE)GetModuleHandle(nullptr); - wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND); - wc.lpszClassName = L"PrusaSlicer_opengl_version_check"; - wc.style = CS_OWNDC; - if (RegisterClass(&wc)) { - HWND hwnd = CreateWindowW(wc.lpszClassName, L"PrusaSlicer_opengl_version_check", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, wc.hInstance, (LPVOID)this); - if (hwnd) { - message_pump_exit = false; - while (GetMessage(&msg, NULL, 0, 0 ) > 0 && ! message_pump_exit) - DispatchMessage(&msg); - } - } - return this->success; - } + bool load_opengl_dll() + { + MSG msg = {0}; + WNDCLASS wc = {0}; + wc.lpfnWndProc = OpenGLVersionCheck::supports_opengl2_wndproc; + wc.hInstance = (HINSTANCE)GetModuleHandle(nullptr); + wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND); + wc.lpszClassName = L"PrusaSlicer_opengl_version_check"; + wc.style = CS_OWNDC; + if (RegisterClass(&wc)) { + HWND hwnd = CreateWindowW(wc.lpszClassName, L"PrusaSlicer_opengl_version_check", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, wc.hInstance, (LPVOID)this); + if (hwnd) { + message_pump_exit = false; + while (GetMessage(&msg, NULL, 0, 0 ) > 0 && ! message_pump_exit) + DispatchMessage(&msg); + } + } + return this->success; + } - void unload_opengl_dll() - { - if (this->hOpenGL) { - BOOL released = FreeLibrary(this->hOpenGL); - if (released) - printf("System OpenGL library released\n"); - else - printf("System OpenGL library NOT released\n"); - this->hOpenGL = nullptr; - } - } + void unload_opengl_dll() + { + if (this->hOpenGL) { + BOOL released = FreeLibrary(this->hOpenGL); + if (released) + printf("System OpenGL library released\n"); + else + printf("System OpenGL library NOT released\n"); + this->hOpenGL = nullptr; + } + } - bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const - { - // printf("is_version_greater_or_equal_to, version: %s\n", version.c_str()); - std::vector tokens; - boost::split(tokens, version, boost::is_any_of(" "), boost::token_compress_on); - if (tokens.empty()) - return false; + bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const + { + // printf("is_version_greater_or_equal_to, version: %s\n", version.c_str()); + std::vector tokens; + boost::split(tokens, version, boost::is_any_of(" "), boost::token_compress_on); + if (tokens.empty()) + return false; - std::vector numbers; - boost::split(numbers, tokens[0], boost::is_any_of("."), boost::token_compress_on); + std::vector numbers; + boost::split(numbers, tokens[0], boost::is_any_of("."), boost::token_compress_on); - unsigned int gl_major = 0; - unsigned int gl_minor = 0; - if (numbers.size() > 0) - gl_major = ::atoi(numbers[0].c_str()); - if (numbers.size() > 1) - gl_minor = ::atoi(numbers[1].c_str()); - // printf("Major: %d, minor: %d\n", gl_major, gl_minor); - if (gl_major < major) - return false; - else if (gl_major > major) - return true; - else - return gl_minor >= minor; - } + unsigned int gl_major = 0; + unsigned int gl_minor = 0; + if (numbers.size() > 0) + gl_major = ::atoi(numbers[0].c_str()); + if (numbers.size() > 1) + gl_minor = ::atoi(numbers[1].c_str()); + // printf("Major: %d, minor: %d\n", gl_major, gl_minor); + if (gl_major < major) + return false; + else if (gl_major > major) + return true; + else + return gl_minor >= minor; + } protected: - static bool message_pump_exit; + static bool message_pump_exit; - void check(HWND hWnd) - { - hOpenGL = LoadLibraryExW(L"opengl32.dll", nullptr, 0); - if (hOpenGL == nullptr) { - printf("Failed loading the system opengl32.dll\n"); - return; - } + void check(HWND hWnd) + { + hOpenGL = LoadLibraryExW(L"opengl32.dll", nullptr, 0); + if (hOpenGL == nullptr) { + printf("Failed loading the system opengl32.dll\n"); + return; + } - typedef HGLRC (WINAPI *Func_wglCreateContext)(HDC); - typedef BOOL (WINAPI *Func_wglMakeCurrent )(HDC, HGLRC); - typedef BOOL (WINAPI *Func_wglDeleteContext)(HGLRC); - typedef GLubyte* (WINAPI *Func_glGetString )(GLenum); + typedef HGLRC (WINAPI *Func_wglCreateContext)(HDC); + typedef BOOL (WINAPI *Func_wglMakeCurrent )(HDC, HGLRC); + typedef BOOL (WINAPI *Func_wglDeleteContext)(HGLRC); + typedef GLubyte* (WINAPI *Func_glGetString )(GLenum); - Func_wglCreateContext wglCreateContext = (Func_wglCreateContext)GetProcAddress(hOpenGL, "wglCreateContext"); - Func_wglMakeCurrent wglMakeCurrent = (Func_wglMakeCurrent) GetProcAddress(hOpenGL, "wglMakeCurrent"); - Func_wglDeleteContext wglDeleteContext = (Func_wglDeleteContext)GetProcAddress(hOpenGL, "wglDeleteContext"); - Func_glGetString glGetString = (Func_glGetString) GetProcAddress(hOpenGL, "glGetString"); + Func_wglCreateContext wglCreateContext = (Func_wglCreateContext)GetProcAddress(hOpenGL, "wglCreateContext"); + Func_wglMakeCurrent wglMakeCurrent = (Func_wglMakeCurrent) GetProcAddress(hOpenGL, "wglMakeCurrent"); + Func_wglDeleteContext wglDeleteContext = (Func_wglDeleteContext)GetProcAddress(hOpenGL, "wglDeleteContext"); + Func_glGetString glGetString = (Func_glGetString) GetProcAddress(hOpenGL, "glGetString"); - if (wglCreateContext == nullptr || wglMakeCurrent == nullptr || wglDeleteContext == nullptr || glGetString == nullptr) { - printf("Failed loading the system opengl32.dll: The library is invalid.\n"); - return; - } + if (wglCreateContext == nullptr || wglMakeCurrent == nullptr || wglDeleteContext == nullptr || glGetString == nullptr) { + printf("Failed loading the system opengl32.dll: The library is invalid.\n"); + return; + } PIXELFORMATDESCRIPTOR pfd = { @@ -149,152 +149,155 @@ protected: }; HDC ourWindowHandleToDeviceContext = ::GetDC(hWnd); - // Gdi32.dll - int letWindowsChooseThisPixelFormat = ::ChoosePixelFormat(ourWindowHandleToDeviceContext, &pfd); - // Gdi32.dll + // Gdi32.dll + int letWindowsChooseThisPixelFormat = ::ChoosePixelFormat(ourWindowHandleToDeviceContext, &pfd); + // Gdi32.dll SetPixelFormat(ourWindowHandleToDeviceContext, letWindowsChooseThisPixelFormat, &pfd); - // Opengl32.dll + // Opengl32.dll HGLRC glcontext = wglCreateContext(ourWindowHandleToDeviceContext); wglMakeCurrent(ourWindowHandleToDeviceContext, glcontext); // Opengl32.dll - const char *data = (const char*)glGetString(GL_VERSION); - if (data != nullptr) - this->version = data; - // printf("check -version: %s\n", version.c_str()); - data = (const char*)glGetString(0x8B8C); // GL_SHADING_LANGUAGE_VERSION - if (data != nullptr) - this->glsl_version = data; - data = (const char*)glGetString(GL_VENDOR); - if (data != nullptr) - this->vendor = data; - data = (const char*)glGetString(GL_RENDERER); - if (data != nullptr) - this->renderer = data; + const char *data = (const char*)glGetString(GL_VERSION); + if (data != nullptr) + this->version = data; + // printf("check -version: %s\n", version.c_str()); + data = (const char*)glGetString(0x8B8C); // GL_SHADING_LANGUAGE_VERSION + if (data != nullptr) + this->glsl_version = data; + data = (const char*)glGetString(GL_VENDOR); + if (data != nullptr) + this->vendor = data; + data = (const char*)glGetString(GL_RENDERER); + if (data != nullptr) + this->renderer = data; // Opengl32.dll wglDeleteContext(glcontext); - ::ReleaseDC(hWnd, ourWindowHandleToDeviceContext); + ::ReleaseDC(hWnd, ourWindowHandleToDeviceContext); this->success = true; - } + } - static LRESULT CALLBACK supports_opengl2_wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) - { - switch(message) - { - case WM_CREATE: - { - CREATESTRUCT *pCreate = reinterpret_cast(lParam); - OpenGLVersionCheck *ogl_data = reinterpret_cast(pCreate->lpCreateParams); - ogl_data->check(hWnd); - DestroyWindow(hWnd); - return 0; - } - case WM_NCDESTROY: - message_pump_exit = true; - return 0; - default: - return DefWindowProc(hWnd, message, wParam, lParam); - } - } + static LRESULT CALLBACK supports_opengl2_wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) + { + switch(message) + { + case WM_CREATE: + { + CREATESTRUCT *pCreate = reinterpret_cast(lParam); + OpenGLVersionCheck *ogl_data = reinterpret_cast(pCreate->lpCreateParams); + ogl_data->check(hWnd); + DestroyWindow(hWnd); + return 0; + } + case WM_NCDESTROY: + message_pump_exit = true; + return 0; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + } }; bool OpenGLVersionCheck::message_pump_exit = false; #endif /* SLIC3R_GUI */ extern "C" { - typedef int (__stdcall *Slic3rMainFunc)(int argc, wchar_t **argv); - Slic3rMainFunc slic3r_main = nullptr; + typedef int (__stdcall *Slic3rMainFunc)(int argc, wchar_t **argv); + Slic3rMainFunc slic3r_main = nullptr; } +extern "C" { + #ifdef SLIC3R_WRAPPER_NOCONSOLE int APIENTRY wWinMain(HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */, PWSTR /* lpCmdLine */, int /* nCmdShow */) { - int argc; - wchar_t **argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + int argc; + wchar_t **argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); #else int wmain(int argc, wchar_t **argv) { #endif - std::vector argv_extended; - argv_extended.emplace_back(argv[0]); + std::vector argv_extended; + argv_extended.emplace_back(argv[0]); #ifdef SLIC3R_GUI - // Here one may push some additional parameters based on the wrapper type. - bool force_mesa = false; + // Here one may push some additional parameters based on the wrapper type. + bool force_mesa = false; #endif /* SLIC3R_GUI */ - for (int i = 1; i < argc; ++ i) { + for (int i = 1; i < argc; ++ i) { #ifdef SLIC3R_GUI - if (wcscmp(argv[i], L"--sw-renderer") == 0) - force_mesa = true; - else if (wcscmp(argv[i], L"--no-sw-renderer") == 0) - force_mesa = false; + if (wcscmp(argv[i], L"--sw-renderer") == 0) + force_mesa = true; + else if (wcscmp(argv[i], L"--no-sw-renderer") == 0) + force_mesa = false; #endif /* SLIC3R_GUI */ - argv_extended.emplace_back(argv[i]); - } - argv_extended.emplace_back(nullptr); + argv_extended.emplace_back(argv[i]); + } + argv_extended.emplace_back(nullptr); #ifdef SLIC3R_GUI - OpenGLVersionCheck opengl_version_check; - bool load_mesa = - // Forced from the command line. - force_mesa || - // Running over a rempote desktop, and the RemoteFX is not enabled, therefore Windows will only provide SW OpenGL 1.1 context. - // In that case, use Mesa. - ::GetSystemMetrics(SM_REMOTESESSION) || - // Try to load the default OpenGL driver and test its context version. - ! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0); + OpenGLVersionCheck opengl_version_check; + bool load_mesa = + // Forced from the command line. + force_mesa || + // Running over a rempote desktop, and the RemoteFX is not enabled, therefore Windows will only provide SW OpenGL 1.1 context. + // In that case, use Mesa. + ::GetSystemMetrics(SM_REMOTESESSION) || + // Try to load the default OpenGL driver and test its context version. + ! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0); #endif /* SLIC3R_GUI */ - wchar_t path_to_exe[MAX_PATH + 1] = { 0 }; - ::GetModuleFileNameW(nullptr, path_to_exe, MAX_PATH); - wchar_t drive[_MAX_DRIVE]; - wchar_t dir[_MAX_DIR]; - wchar_t fname[_MAX_FNAME]; - wchar_t ext[_MAX_EXT]; - _wsplitpath(path_to_exe, drive, dir, fname, ext); - _wmakepath(path_to_exe, drive, dir, nullptr, nullptr); + wchar_t path_to_exe[MAX_PATH + 1] = { 0 }; + ::GetModuleFileNameW(nullptr, path_to_exe, MAX_PATH); + wchar_t drive[_MAX_DRIVE]; + wchar_t dir[_MAX_DIR]; + wchar_t fname[_MAX_FNAME]; + wchar_t ext[_MAX_EXT]; + _wsplitpath(path_to_exe, drive, dir, fname, ext); + _wmakepath(path_to_exe, drive, dir, nullptr, nullptr); #ifdef SLIC3R_GUI // https://wiki.qt.io/Cross_compiling_Mesa_for_Windows // http://download.qt.io/development_releases/prebuilt/llvmpipe/windows/ - if (load_mesa) { - opengl_version_check.unload_opengl_dll(); - wchar_t path_to_mesa[MAX_PATH + 1] = { 0 }; - wcscpy(path_to_mesa, path_to_exe); - wcscat(path_to_mesa, L"mesa\\opengl32.dll"); - printf("Loading MESA OpenGL library: %S\n", path_to_mesa); - HINSTANCE hInstance_OpenGL = LoadLibraryExW(path_to_mesa, nullptr, 0); - if (hInstance_OpenGL == nullptr) { - printf("MESA OpenGL library was not loaded\n"); - } else - printf("MESA OpenGL library was loaded sucessfully\n"); - } + if (load_mesa) { + opengl_version_check.unload_opengl_dll(); + wchar_t path_to_mesa[MAX_PATH + 1] = { 0 }; + wcscpy(path_to_mesa, path_to_exe); + wcscat(path_to_mesa, L"mesa\\opengl32.dll"); + printf("Loading MESA OpenGL library: %S\n", path_to_mesa); + HINSTANCE hInstance_OpenGL = LoadLibraryExW(path_to_mesa, nullptr, 0); + if (hInstance_OpenGL == nullptr) { + printf("MESA OpenGL library was not loaded\n"); + } else + printf("MESA OpenGL library was loaded sucessfully\n"); + } #endif /* SLIC3R_GUI */ - wchar_t path_to_slic3r[MAX_PATH + 1] = { 0 }; - wcscpy(path_to_slic3r, path_to_exe); - wcscat(path_to_slic3r, L"PrusaSlicer.dll"); + wchar_t path_to_slic3r[MAX_PATH + 1] = { 0 }; + wcscpy(path_to_slic3r, path_to_exe); + wcscat(path_to_slic3r, L"PrusaSlicer.dll"); // printf("Loading Slic3r library: %S\n", path_to_slic3r); - HINSTANCE hInstance_Slic3r = LoadLibraryExW(path_to_slic3r, nullptr, 0); - if (hInstance_Slic3r == nullptr) { - printf("PrusaSlicer.dll was not loaded\n"); - return -1; - } + HINSTANCE hInstance_Slic3r = LoadLibraryExW(path_to_slic3r, nullptr, 0); + if (hInstance_Slic3r == nullptr) { + printf("PrusaSlicer.dll was not loaded\n"); + return -1; + } - // resolve function address here - slic3r_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r, + // resolve function address here + slic3r_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r, #ifdef _WIN64 - // there is just a single calling conversion, therefore no mangling of the function name. - "slic3r_main" + // there is just a single calling conversion, therefore no mangling of the function name. + "slic3r_main" #else // stdcall calling convention declaration - "_slic3r_main@8" + "_slic3r_main@8" #endif - ); - if (slic3r_main == nullptr) { - printf("could not locate the function slic3r_main in PrusaSlicer.dll\n"); - return -1; - } - // argc minus the trailing nullptr of the argv - return slic3r_main((int)argv_extended.size() - 1, argv_extended.data()); + ); + if (slic3r_main == nullptr) { + printf("could not locate the function slic3r_main in PrusaSlicer.dll\n"); + return -1; + } + // argc minus the trailing nullptr of the argv + return slic3r_main((int)argv_extended.size() - 1, argv_extended.data()); +} } diff --git a/src/avrdude/CMakeLists.txt b/src/avrdude/CMakeLists.txt index 0e9b9e6d4d..a1930ad5f9 100644 --- a/src/avrdude/CMakeLists.txt +++ b/src/avrdude/CMakeLists.txt @@ -74,6 +74,10 @@ if (MSVC) windows/unistd.cpp windows/getopt.c ) +elseif (MINGW) + set(AVRDUDE_SOURCES ${AVRDUDE_SOURCES} + windows/utf8.c + ) endif() add_executable(avrdude-conf-gen conf-generate.cpp) @@ -98,5 +102,7 @@ target_link_libraries(avrdude-slic3r avrdude) if (WIN32) target_compile_definitions(avrdude PRIVATE WIN32NATIVE=1) - target_include_directories(avrdude SYSTEM PRIVATE windows) # So that sources find the getopt.h windows drop-in + if(MSVC) + target_include_directories(avrdude SYSTEM PRIVATE windows) # So that sources find the getopt.h windows drop-in + endif(MSVC) endif() diff --git a/src/avrdude/lexer.c b/src/avrdude/lexer.c index f2d8adb4bc..46d88170f5 100644 --- a/src/avrdude/lexer.c +++ b/src/avrdude/lexer.c @@ -30,7 +30,7 @@ /* C99 systems have . Non-C99 systems may or may not. */ -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER) /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. diff --git a/src/avrdude/main-standalone.cpp b/src/avrdude/main-standalone.cpp index df6d79e136..f7cd6d1d4a 100644 --- a/src/avrdude/main-standalone.cpp +++ b/src/avrdude/main-standalone.cpp @@ -38,6 +38,10 @@ struct ArgvUtf8 : std::vector } }; +#endif + +#ifdef _MSC_VER + int wmain(int argc_w, wchar_t *argv_w[]) { ArgvUtf8 argv_utf8(argc_w, argv_w); diff --git a/src/avrdude/windows/unistd.h b/src/avrdude/windows/unistd.h index fe6a8fb871..c88b780bfa 100644 --- a/src/avrdude/windows/unistd.h +++ b/src/avrdude/windows/unistd.h @@ -63,7 +63,7 @@ extern "C" { #define STDOUT_FILENO 1 #define STDERR_FILENO 2 -#ifdef _MSC_VER +#if defined(_MSC_VER) && defined(__clang__) #include struct timezone; struct timeval; diff --git a/src/libigl/igl/SortableRow.h b/src/libigl/igl/SortableRow.h index 5f172987bf..182bf81343 100644 --- a/src/libigl/igl/SortableRow.h +++ b/src/libigl/igl/SortableRow.h @@ -1,9 +1,9 @@ // This file is part of libigl, a simple c++ geometry processing library. -// +// // Copyright (C) 2013 Alec Jacobson -// -// This Source Code Form is subject to the terms of the Mozilla Public License -// v. 2.0. If a copy of the MPL was not distributed with this file, You can +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.0. If a copy of the MPL was not distributed with this file, You can // obtain one at http://mozilla.org/MPL/2.0/. #ifndef IGL_SORTABLE_ROW_H #define IGL_SORTABLE_ROW_H @@ -14,57 +14,53 @@ namespace igl { - // Templates: - // T should be a matrix that implements .size(), and operator(int i) - template - class SortableRow - { - public: - T data; - public: - SortableRow():data(){}; - SortableRow(const T & data):data(data){}; - bool operator<(const SortableRow & that) const - { - // Get reference so that I can use parenthesis - const SortableRow & THIS = *this; +// Templates: +// T should be a matrix that implements .size(), and operator(int i) +template +class SortableRow +{ +public: + T data; +public: + SortableRow():data(){}; + SortableRow(const T & data):data(data){}; + bool operator<(const SortableRow & that) const + { // Lexicographical - int minc = (THIS.data.size() < that.data.size()? - THIS.data.size() : that.data.size()); + int minc = (this->data.size() < that.data.size()? + this->data.size() : that.data.size()); // loop over columns for(int i = 0;idata(i) == that.data(i)) + { + continue; + } + return this->data(i) < that.data(i); } // All characters the same, comes done to length - return THIS.data.size() & THIS = *this; - if(THIS.data.size() != that.data.size()) + return this->data.size()data.size() != that.data.size()) { - return false; - } - for(int i = 0;idata.size();i++) + { + if(this->data(i) != that.data(i)) + { + return false; + } } return true; - }; - bool operator!=(const SortableRow & that) const - { + }; + bool operator!=(const SortableRow & that) const + { return !(*this == that); - }; - }; + }; +}; } #endif diff --git a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp index 06afbd1872..56330e15e7 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -337,7 +337,15 @@ merge(const TMultiShape& shapes) //#define DISABLE_BOOST_SERIALIZE //#define DISABLE_BOOST_UNSERIALIZE +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4244) +#pragma warning(disable: 4267) +#endif // All other operators and algorithms are implemented with boost #include +#ifdef _MSC_VER +#pragma warning(pop) +#endif #endif // CLIPPER_BACKEND_HPP diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index ed599d11da..1b7451f8f3 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -133,8 +133,18 @@ protected: PConfig m_pconf; // Placement configuration TBin m_bin; double m_bin_area; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4244) +#pragma warning(disable: 4267) +#endif SpatIndex m_rtree; // spatial index for the normal (bigger) objects SpatIndex m_smallsrtree; // spatial index for only the smaller items +#ifdef _MSC_VER +#pragma warning(pop) +#endif + double m_norm; // A coefficient to scale distances MultiPolygon m_merged_pile; // The already merged pile (vector of items) Box m_pilebb; // The bounding box of the merged pile. diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 4842b51239..1ebd922e20 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -5,6 +5,10 @@ include(PrecompiledHeader) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libslic3r_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/libslic3r_version.h @ONLY) +if (MINGW) + add_compile_options(-Wa,-mbig-obj) +endif () + add_library(libslic3r STATIC pchheader.cpp pchheader.hpp @@ -70,7 +74,7 @@ add_library(libslic3r STATIC GCode/CoolingBuffer.cpp GCode/CoolingBuffer.hpp GCode/PostProcessor.cpp - GCode/PostProcessor.hpp + GCode/PostProcessor.hpp # GCode/PressureEqualizer.cpp # GCode/PressureEqualizer.hpp GCode/PreviewData.cpp diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 538127810d..d4006120d2 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -102,45 +102,60 @@ private: class ToolOrdering { public: - ToolOrdering() {} + ToolOrdering() {} - // For the use case when each object is printed separately - // (print.config.complete_objects is true). - ToolOrdering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); + // For the use case when each object is printed separately + // (print.config.complete_objects is true). + ToolOrdering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); - // For the use case when all objects are printed at once. - // (print.config.complete_objects is false). - ToolOrdering(const Print &print, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); + // For the use case when all objects are printed at once. + // (print.config.complete_objects is false). + ToolOrdering(const Print &print, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false); - void clear() { m_layer_tools.clear(); } + void clear() { m_layer_tools.clear(); } - // Get the first extruder printing, including the extruder priming areas, returns -1 if there is no layer printed. - unsigned int first_extruder() const { return m_first_printing_extruder; } + // Get the first extruder printing, including the extruder priming areas, returns -1 if there is no layer printed. + unsigned int first_extruder() const { return m_first_printing_extruder; } - // Get the first extruder printing the layer_tools, returns -1 if there is no layer printed. - unsigned int last_extruder() const { return m_last_printing_extruder; } + // Get the first extruder printing the layer_tools, returns -1 if there is no layer printed. + unsigned int last_extruder() const { return m_last_printing_extruder; } - // For a multi-material print, the printing extruders are ordered in the order they shall be primed. - const std::vector& all_extruders() const { return m_all_printing_extruders; } + // For a multi-material print, the printing extruders are ordered in the order they shall be primed. + const std::vector& all_extruders() const { return m_all_printing_extruders; } - // Find LayerTools with the closest print_z. - LayerTools& tools_for_layer(coordf_t print_z); - const LayerTools& tools_for_layer(coordf_t print_z) const - { return *const_cast(&const_cast(this)->tools_for_layer(print_z)); } + template static auto tools_for_layer(Self& self, coordf_t print_z) -> decltype (*self.m_layer_tools.begin()) + { + auto it_layer_tools = std::lower_bound(self.m_layer_tools.begin(), self.m_layer_tools.end(), LayerTools(print_z - EPSILON)); + assert(it_layer_tools != self.m_layer_tools.end()); + coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z); + for (++ it_layer_tools; it_layer_tools != self.m_layer_tools.end(); ++it_layer_tools) { + coordf_t d = std::abs(it_layer_tools->print_z - print_z); + if (d >= dist_min) + break; + dist_min = d; + } + -- it_layer_tools; + assert(dist_min < EPSILON); + return *it_layer_tools; + } - const LayerTools& front() const { return m_layer_tools.front(); } - const LayerTools& back() const { return m_layer_tools.back(); } - std::vector::const_iterator begin() const { return m_layer_tools.begin(); } - std::vector::const_iterator end() const { return m_layer_tools.end(); } - bool empty() const { return m_layer_tools.empty(); } - std::vector& layer_tools() { return m_layer_tools; } - bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().wipe_tower_partitions > 0; } + // Find LayerTools with the closest print_z. + LayerTools& tools_for_layer(coordf_t print_z) { return tools_for_layer(*this, print_z); } + const LayerTools& tools_for_layer(coordf_t print_z) const { return tools_for_layer(*this, print_z); } + + const LayerTools& front() const { return m_layer_tools.front(); } + const LayerTools& back() const { return m_layer_tools.back(); } + std::vector::const_iterator begin() const { return m_layer_tools.begin(); } + std::vector::const_iterator end() const { return m_layer_tools.end(); } + bool empty() const { return m_layer_tools.empty(); } + std::vector& layer_tools() { return m_layer_tools; } + bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().wipe_tower_partitions > 0; } private: - void initialize_layers(std::vector &zs); - void collect_extruders(const PrintObject &object); - void reorder_extruders(unsigned int last_extruder_id); - void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z); + void initialize_layers(std::vector &zs); + void collect_extruders(const PrintObject &object); + void reorder_extruders(unsigned int last_extruder_id); + void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z); void collect_extruder_statistics(bool prime_multi_material); std::vector m_layer_tools; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 304f6f749f..f38ef662d2 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -12,7 +12,7 @@ namespace Slic3r { -//! macro used to mark string used at localization, +//! macro used to mark string used at localization, //! return same string #define L(s) (s) #define _(s) Slic3r::I18N::translate(s) @@ -51,7 +51,7 @@ void PrintConfigDef::init_common_params() def->label = L("Bed shape"); def->mode = comAdvanced; def->set_default_value(new ConfigOptionPoints{ Vec2d(0, 0), Vec2d(200, 0), Vec2d(200, 200), Vec2d(0, 200) }); - + def = this->add("bed_custom_texture", coString); def->label = L("Bed custom texture"); def->mode = comAdvanced; @@ -85,8 +85,8 @@ void PrintConfigDef::init_common_params() "The gap closing operation may reduce the final print resolution, therefore it is advisable to keep the value reasonably low."); def->sidetext = L("mm"); def->min = 0; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.049)); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.049)); def = this->add("print_host", coString); def->label = L("Hostname, IP or URL"); @@ -101,7 +101,7 @@ void PrintConfigDef::init_common_params() "the API Key or the password required for authentication."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("")); - + def = this->add("printhost_cafile", coString); def->label = L("HTTPS CA File"); def->tooltip = L("Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. " @@ -117,9 +117,9 @@ void PrintConfigDef::init_fff_params() // Maximum extruder temperature, bumped to 1500 to support printing of glass. const int max_temp = 1500; - def = this->add("avoid_crossing_perimeters", coBool); + def = this->add("avoid_crossing_perimeters", coBool); def->label = L("Avoid crossing perimeters"); - def->tooltip = L("Optimize travel moves in order to minimize the crossing of perimeters. " + def->tooltip = L("Optimize travel moves in order to minimize the crossing of perimeters. " "This is mostly useful with Bowden extruders which suffer from oozing. " "This feature slows down both the print and the G-code generation."); def->mode = comExpert; @@ -178,7 +178,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Bridging angle override. If left to zero, the bridging angle will be calculated " "automatically. Otherwise the provided angle will be used for all bridges. " "Use 180° for zero angle."); - def->sidetext = L("°"); + def->sidetext = L("°"); def->min = 0; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.)); @@ -200,9 +200,9 @@ void PrintConfigDef::init_fff_params() "although default settings are usually good and you should experiment " "with cooling (use a fan) before tweaking this."); def->min = 0; - def->max = 2; + def->max = 2; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(1)); + def->set_default_value(new ConfigOptionFloat(1)); def = this->add("bridge_speed", coFloat); def->label = L("Bridges"); @@ -531,7 +531,7 @@ void PrintConfigDef::init_fff_params() "check filament diameter and your firmware E steps."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloats { 1. }); - + def = this->add("extrusion_width", coFloatOrPercent); def->label = L("Default extrusion width"); def->category = L("Extrusion Width"); @@ -677,7 +677,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("This string is edited by RammingDialog and contains ramming specific parameters."); def->mode = comExpert; def->set_default_value(new ConfigOptionStrings { "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0|" - " 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" }); + " 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" }); def = this->add("filament_unload_time", coFloats); def->label = L("Filament unload time"); @@ -743,7 +743,7 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("money/kg"); def->min = 0; def->set_default_value(new ConfigOptionFloats { 0. }); - + def = this->add("filament_settings_id", coStrings); def->set_default_value(new ConfigOptionStrings { "" }); def->cli = ConfigOptionDef::nocli; @@ -889,7 +889,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->max = max_temp; def->set_default_value(new ConfigOptionInts { 200 }); - + def = this->add("gap_fill_speed", coFloat); def->label = L("Gap fill"); def->category = L("Speed"); @@ -1072,85 +1072,85 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionBool(false)); - def = this->add("silent_mode", coBool); - def->label = L("Supports stealth mode"); - def->tooltip = L("The firmware supports stealth mode"); + def = this->add("silent_mode", coBool); + def->label = L("Supports stealth mode"); + def->tooltip = L("The firmware supports stealth mode"); def->mode = comExpert; - def->set_default_value(new ConfigOptionBool(true)); + def->set_default_value(new ConfigOptionBool(true)); - const int machine_limits_opt_width = 7; - { - struct AxisDefault { - std::string name; - std::vector max_feedrate; - std::vector max_acceleration; - std::vector max_jerk; - }; - std::vector axes { - // name, max_feedrate, max_acceleration, max_jerk - { "x", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } }, - { "y", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } }, - { "z", { 12., 12. }, { 500., 200. }, { 0.2, 0.4 } }, - { "e", { 120., 120. }, { 10000., 5000. }, { 2.5, 2.5 } } - }; - for (const AxisDefault &axis : axes) { - std::string axis_upper = boost::to_upper_copy(axis.name); - // Add the machine feedrate limits for XYZE axes. (M203) - def = this->add("machine_max_feedrate_" + axis.name, coFloats); - def->full_label = (boost::format("Maximum feedrate %1%") % axis_upper).str(); - (void)L("Maximum feedrate X"); - (void)L("Maximum feedrate Y"); - (void)L("Maximum feedrate Z"); - (void)L("Maximum feedrate E"); - def->category = L("Machine limits"); - def->tooltip = (boost::format("Maximum feedrate of the %1% axis") % axis_upper).str(); - (void)L("Maximum feedrate of the X axis"); - (void)L("Maximum feedrate of the Y axis"); - (void)L("Maximum feedrate of the Z axis"); - (void)L("Maximum feedrate of the E axis"); - def->sidetext = L("mm/s"); - def->min = 0; - def->width = machine_limits_opt_width; + const int machine_limits_opt_width = 7; + { + struct AxisDefault { + std::string name; + std::vector max_feedrate; + std::vector max_acceleration; + std::vector max_jerk; + }; + std::vector axes { + // name, max_feedrate, max_acceleration, max_jerk + { "x", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } }, + { "y", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } }, + { "z", { 12., 12. }, { 500., 200. }, { 0.2, 0.4 } }, + { "e", { 120., 120. }, { 10000., 5000. }, { 2.5, 2.5 } } + }; + for (const AxisDefault &axis : axes) { + std::string axis_upper = boost::to_upper_copy(axis.name); + // Add the machine feedrate limits for XYZE axes. (M203) + def = this->add("machine_max_feedrate_" + axis.name, coFloats); + def->full_label = (boost::format("Maximum feedrate %1%") % axis_upper).str(); + (void)L("Maximum feedrate X"); + (void)L("Maximum feedrate Y"); + (void)L("Maximum feedrate Z"); + (void)L("Maximum feedrate E"); + def->category = L("Machine limits"); + def->tooltip = (boost::format("Maximum feedrate of the %1% axis") % axis_upper).str(); + (void)L("Maximum feedrate of the X axis"); + (void)L("Maximum feedrate of the Y axis"); + (void)L("Maximum feedrate of the Z axis"); + (void)L("Maximum feedrate of the E axis"); + def->sidetext = L("mm/s"); + def->min = 0; + def->width = machine_limits_opt_width; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats(axis.max_feedrate)); - // Add the machine acceleration limits for XYZE axes (M201) - def = this->add("machine_max_acceleration_" + axis.name, coFloats); - def->full_label = (boost::format("Maximum acceleration %1%") % axis_upper).str(); - (void)L("Maximum acceleration X"); - (void)L("Maximum acceleration Y"); - (void)L("Maximum acceleration Z"); - (void)L("Maximum acceleration E"); - def->category = L("Machine limits"); - def->tooltip = (boost::format("Maximum acceleration of the %1% axis") % axis_upper).str(); - (void)L("Maximum acceleration of the X axis"); - (void)L("Maximum acceleration of the Y axis"); - (void)L("Maximum acceleration of the Z axis"); - (void)L("Maximum acceleration of the E axis"); - def->sidetext = L("mm/s²"); - def->min = 0; - def->width = machine_limits_opt_width; + def->set_default_value(new ConfigOptionFloats(axis.max_feedrate)); + // Add the machine acceleration limits for XYZE axes (M201) + def = this->add("machine_max_acceleration_" + axis.name, coFloats); + def->full_label = (boost::format("Maximum acceleration %1%") % axis_upper).str(); + (void)L("Maximum acceleration X"); + (void)L("Maximum acceleration Y"); + (void)L("Maximum acceleration Z"); + (void)L("Maximum acceleration E"); + def->category = L("Machine limits"); + def->tooltip = (boost::format("Maximum acceleration of the %1% axis") % axis_upper).str(); + (void)L("Maximum acceleration of the X axis"); + (void)L("Maximum acceleration of the Y axis"); + (void)L("Maximum acceleration of the Z axis"); + (void)L("Maximum acceleration of the E axis"); + def->sidetext = L("mm/s²"); + def->min = 0; + def->width = machine_limits_opt_width; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats(axis.max_acceleration)); - // Add the machine jerk limits for XYZE axes (M205) - def = this->add("machine_max_jerk_" + axis.name, coFloats); - def->full_label = (boost::format("Maximum jerk %1%") % axis_upper).str(); - (void)L("Maximum jerk X"); - (void)L("Maximum jerk Y"); - (void)L("Maximum jerk Z"); - (void)L("Maximum jerk E"); - def->category = L("Machine limits"); - def->tooltip = (boost::format("Maximum jerk of the %1% axis") % axis_upper).str(); - (void)L("Maximum jerk of the X axis"); - (void)L("Maximum jerk of the Y axis"); - (void)L("Maximum jerk of the Z axis"); - (void)L("Maximum jerk of the E axis"); - def->sidetext = L("mm/s"); - def->min = 0; - def->width = machine_limits_opt_width; + def->set_default_value(new ConfigOptionFloats(axis.max_acceleration)); + // Add the machine jerk limits for XYZE axes (M205) + def = this->add("machine_max_jerk_" + axis.name, coFloats); + def->full_label = (boost::format("Maximum jerk %1%") % axis_upper).str(); + (void)L("Maximum jerk X"); + (void)L("Maximum jerk Y"); + (void)L("Maximum jerk Z"); + (void)L("Maximum jerk E"); + def->category = L("Machine limits"); + def->tooltip = (boost::format("Maximum jerk of the %1% axis") % axis_upper).str(); + (void)L("Maximum jerk of the X axis"); + (void)L("Maximum jerk of the Y axis"); + (void)L("Maximum jerk of the Z axis"); + (void)L("Maximum jerk of the E axis"); + def->sidetext = L("mm/s"); + def->min = 0; + def->width = machine_limits_opt_width; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats(axis.max_jerk)); - } - } + def->set_default_value(new ConfigOptionFloats(axis.max_jerk)); + } + } // M205 S... [mm/sec] def = this->add("machine_min_extruding_rate", coFloats); @@ -1159,9 +1159,9 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Minimum feedrate when extruding (M205 S)"); def->sidetext = L("mm/s"); def->min = 0; - def->width = machine_limits_opt_width; + def->width = machine_limits_opt_width; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats{ 0., 0. }); + def->set_default_value(new ConfigOptionFloats{ 0., 0. }); // M205 T... [mm/sec] def = this->add("machine_min_travel_rate", coFloats); @@ -1170,9 +1170,9 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Minimum travel feedrate (M205 T)"); def->sidetext = L("mm/s"); def->min = 0; - def->width = machine_limits_opt_width; + def->width = machine_limits_opt_width; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats{ 0., 0. }); + def->set_default_value(new ConfigOptionFloats{ 0., 0. }); // M204 S... [mm/sec^2] def = this->add("machine_max_acceleration_extruding", coFloats); @@ -1181,7 +1181,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Maximum acceleration when extruding (M204 S)"); def->sidetext = L("mm/s²"); def->min = 0; - def->width = machine_limits_opt_width; + def->width = machine_limits_opt_width; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloats{ 1500., 1250. }); @@ -1192,7 +1192,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Maximum acceleration when retracting (M204 T)"); def->sidetext = L("mm/s²"); def->min = 0; - def->width = machine_limits_opt_width; + def->width = machine_limits_opt_width; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloats{ 1500., 1250. }); @@ -1436,9 +1436,9 @@ void PrintConfigDef::init_fff_params() def->gui_flags = "serialized"; def->multiline = true; def->full_width = true; - def->height = 6; + def->height = 6; def->mode = comExpert; - def->set_default_value(new ConfigOptionStrings()); + def->set_default_value(new ConfigOptionStrings()); def = this->add("printer_model", coString); def->label = L("Printer type"); @@ -1470,7 +1470,7 @@ void PrintConfigDef::init_fff_params() def = this->add("print_settings_id", coString); def->set_default_value(new ConfigOptionString("")); def->cli = ConfigOptionDef::nocli; - + def = this->add("printer_settings_id", coString); def->set_default_value(new ConfigOptionString("")); def->cli = ConfigOptionDef::nocli; @@ -1510,7 +1510,7 @@ void PrintConfigDef::init_fff_params() def->sidetext = L("%"); def->mode = comAdvanced; def->set_default_value(new ConfigOptionPercents { 0. }); - + def = this->add("retract_layer_change", coBools); def->label = L("Retract on layer change"); def->tooltip = L("This flag enforces a retraction whenever a Z move is done."); @@ -1607,7 +1607,7 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Random")); def->enum_labels.push_back(L("Nearest")); def->enum_labels.push_back(L("Aligned")); - def->enum_labels.push_back(L("Rear")); + def->enum_labels.push_back(L("Rear")); def->mode = comSimple; def->set_default_value(new ConfigOptionEnum(spAligned)); @@ -1678,7 +1678,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(1)); - + def = this->add("slowdown_below_layer_time", coInts); def->label = L("Slow down if layer print time is below"); def->tooltip = L("If layer print time is estimated below this number of seconds, print moves " @@ -1774,7 +1774,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Temperature variation"); def->tooltip = L("Temperature difference to be applied when an extruder is not active. " "Enables a full-height \"sacrificial\" skirt on which the nozzles are periodically wiped."); - def->sidetext = "∆°C"; + def->sidetext = "∆°C"; def->min = -max_temp; def->max = max_temp; def->mode = comExpert; @@ -1816,7 +1816,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Single Extruder Multi Material"); def->tooltip = L("The printer multiplexes filaments into a single hot end."); def->mode = comExpert; - def->set_default_value(new ConfigOptionBool(false)); + def->set_default_value(new ConfigOptionBool(false)); def = this->add("single_extruder_multi_material_priming", coBool); def->label = L("Prime all printing extruders"); @@ -1878,8 +1878,8 @@ void PrintConfigDef::init_fff_params() // def->min = 0; def->enum_values.push_back("0"); def->enum_values.push_back("0.2"); - def->enum_labels.push_back(L("0 (soluble)")); - def->enum_labels.push_back(L("0.2 (detachable)")); + def->enum_labels.push_back(L("0 (soluble)")); + def->enum_labels.push_back(L("0.2 (detachable)")); def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.2)); @@ -1968,7 +1968,7 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("rectilinear"); def->enum_values.push_back("rectilinear-grid"); def->enum_values.push_back("honeycomb"); - def->enum_labels.push_back(L("Rectilinear")); + def->enum_labels.push_back(L("Rectilinear")); def->enum_labels.push_back(L("Rectilinear grid")); def->enum_labels.push_back(L("Honeycomb")); def->mode = comAdvanced; @@ -2030,7 +2030,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->max = max_temp; def->set_default_value(new ConfigOptionInts { 200 }); - + def = this->add("thin_walls", coBool); def->label = L("Detect thin walls"); def->category = L("Layers and Perimeters"); @@ -2050,7 +2050,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionInt(threads > 0 ? threads : 2)); def->cli == ConfigOptionDef::nocli; } - + def = this->add("toolchange_gcode", coString); def->label = L("Tool change G-code"); def->tooltip = L("This custom code is inserted at every extruder change. If you don't leave this empty, you are " @@ -2242,45 +2242,45 @@ void PrintConfigDef::init_fff_params() // Declare retract values for filament profile, overriding the printer's extruder profile. for (const char *opt_key : { - // floats - "retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel", - // bools - "retract_layer_change", "wipe", - // percents - "retract_before_wipe"}) { - auto it_opt = options.find(opt_key); - assert(it_opt != options.end()); - def = this->add_nullable(std::string("filament_") + opt_key, it_opt->second.type); - def->label = it_opt->second.label; - def->full_label = it_opt->second.full_label; - def->tooltip = it_opt->second.tooltip; - def->sidetext = it_opt->second.sidetext; - def->mode = it_opt->second.mode; - switch (def->type) { - case coFloats : def->set_default_value(new ConfigOptionFloatsNullable (static_cast(it_opt->second.default_value.get())->values)); break; - case coPercents : def->set_default_value(new ConfigOptionPercentsNullable(static_cast(it_opt->second.default_value.get())->values)); break; - case coBools : def->set_default_value(new ConfigOptionBoolsNullable (static_cast(it_opt->second.default_value.get())->values)); break; - default: assert(false); - } + // floats + "retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel", + // bools + "retract_layer_change", "wipe", + // percents + "retract_before_wipe"}) { + auto it_opt = options.find(opt_key); + assert(it_opt != options.end()); + def = this->add_nullable(std::string("filament_") + opt_key, it_opt->second.type); + def->label = it_opt->second.label; + def->full_label = it_opt->second.full_label; + def->tooltip = it_opt->second.tooltip; + def->sidetext = it_opt->second.sidetext; + def->mode = it_opt->second.mode; + switch (def->type) { + case coFloats : def->set_default_value(new ConfigOptionFloatsNullable (static_cast(it_opt->second.default_value.get())->values)); break; + case coPercents : def->set_default_value(new ConfigOptionPercentsNullable(static_cast(it_opt->second.default_value.get())->values)); break; + case coBools : def->set_default_value(new ConfigOptionBoolsNullable (static_cast(it_opt->second.default_value.get())->values)); break; + default: assert(false); + } } } void PrintConfigDef::init_extruder_retract_keys() { - m_extruder_retract_keys = { - "deretract_speed", - "retract_before_travel", - "retract_before_wipe", - "retract_layer_change", - "retract_length", - "retract_lift", - "retract_lift_above", - "retract_lift_below", - "retract_restart_extra", - "retract_speed", - "wipe" - }; - assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end())); + m_extruder_retract_keys = { + "deretract_speed", + "retract_before_travel", + "retract_before_wipe", + "retract_layer_change", + "retract_length", + "retract_lift", + "retract_lift_above", + "retract_lift_below", + "retract_restart_extra", + "retract_speed", + "wipe" + }; + assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end())); } void PrintConfigDef::init_sla_params() @@ -2374,7 +2374,7 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloats( { 1., 1. } )); - + def = this->add("absolute_correction", coFloat); def->label = L("Printer absolute correction"); def->full_label = L("Printer absolute correction"); @@ -2382,7 +2382,7 @@ void PrintConfigDef::init_sla_params() "to the sign of the correction."); def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.0)); - + def = this->add("gamma_correction", coFloat); def->label = L("Printer gamma correction"); def->full_label = L("Printer gamma correction"); @@ -2393,7 +2393,7 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(1.0)); - + // SLA Material settings. def = this->add("initial_layer_height", coFloat); @@ -2560,7 +2560,7 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(1.0)); - + def = this->add("support_base_safety_distance", coFloat); def->label = L("Support base safety distance"); def->category = L("Supports"); @@ -2694,7 +2694,7 @@ void PrintConfigDef::init_sla_params() def->max = 90; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(45.0)); - + def = this->add("pad_object_gap", coFloat); def->label = L("Pad object gap"); def->category = L("Pad"); @@ -2705,7 +2705,7 @@ void PrintConfigDef::init_sla_params() def->max = 10; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(1)); - + def = this->add("pad_object_connector_stride", coFloat); def->label = L("Pad object connector stride"); def->category = L("Pad"); @@ -2715,7 +2715,7 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(10)); - + def = this->add("pad_object_connector_width", coFloat); def->label = L("Pad object connector width"); def->category = L("Pad"); @@ -2725,7 +2725,7 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.5)); - + def = this->add("pad_object_connector_penetration", coFloat); def->label = L("Pad object connector penetration"); def->category = L("Pad"); @@ -2746,7 +2746,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va if (opt_key == "bottom_layer_speed") opt_key = "first_layer_speed"; try { float v = boost::lexical_cast(value); - if (v != 0) + if (v != 0) value = boost::lexical_cast(v*100) + "%"; } catch (boost::bad_lexical_cast &) { value = "0"; @@ -2786,14 +2786,14 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va } else if (opt_key == "octoprint_apikey") { opt_key = "printhost_apikey"; } - + // Ignore the following obsolete configuration keys: static std::set ignore = { "duplicate_x", "duplicate_y", "gcode_arcs", "multiply_x", "multiply_y", - "support_material_tool", "acceleration", "adjust_overhang_flow", + "support_material_tool", "acceleration", "adjust_overhang_flow", "standby_temperature", "scale", "rotate", "duplicate", "duplicate_grid", - "start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start", - "seal_position", "vibration_limit", "bed_size", + "start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start", + "seal_position", "vibration_limit", "bed_size", "print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe" #ifndef HAS_PRESSURE_EQUALIZER , "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative" @@ -2804,7 +2804,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va opt_key = ""; return; } - + if (! print_config_def.has(opt_key)) { opt_key = ""; return; @@ -2844,10 +2844,10 @@ void DynamicPrintConfig::normalize() // this->option("support_material_interface_extruder", true)->setInt(extruder); } } - + if (!this->has("solid_infill_extruder") && this->has("infill_extruder")) this->option("solid_infill_extruder", true)->setInt(this->option("infill_extruder")->getInt()); - + if (this->has("spiral_vase") && this->opt("spiral_vase", true)->value) { { // this should be actually done only on the spiral layers instead of all @@ -2865,8 +2865,8 @@ void DynamicPrintConfig::normalize() std::string DynamicPrintConfig::validate() { // Full print config is initialized from the defaults. - const ConfigOption *opt = this->option("printer_technology", false); - auto printer_technology = (opt == nullptr) ? ptFFF : static_cast(dynamic_cast(opt)->value); + const ConfigOption *opt = this->option("printer_technology", false); + auto printer_technology = (opt == nullptr) ? ptFFF : static_cast(dynamic_cast(opt)->value); switch (printer_technology) { case ptFFF: { @@ -2890,7 +2890,7 @@ double PrintConfig::min_object_distance(const ConfigBase *config) { double extruder_clearance_radius = config->option("extruder_clearance_radius")->getFloat(); double duplicate_distance = config->option("duplicate_distance")->getFloat(); - + // min object distance is max(duplicate_distance, clearance_radius) return (config->option("complete_objects")->getBool() && extruder_clearance_radius > duplicate_distance) ? extruder_clearance_radius @@ -2919,7 +2919,7 @@ std::string FullPrintConfig::validate() for (double nd : this->nozzle_diameter.values) if (nd < 0.005) return "Invalid value for --nozzle-diameter"; - + // --perimeters if (this->perimeters.value < 0) return "Invalid value for --perimeters"; @@ -2929,8 +2929,8 @@ std::string FullPrintConfig::validate() return "Invalid value for --top-solid-layers"; if (this->bottom_solid_layers < 0) return "Invalid value for --bottom-solid-layers"; - - if (this->use_firmware_retraction.value && + + if (this->use_firmware_retraction.value && this->gcode_flavor.value != gcfSmoothie && this->gcode_flavor.value != gcfRepRap && this->gcode_flavor.value != gcfMarlin && @@ -2942,15 +2942,15 @@ std::string FullPrintConfig::validate() for (unsigned char wipe : this->wipe.values) if (wipe) return "--use-firmware-retraction is not compatible with --wipe"; - + // --gcode-flavor if (! print_config_def.get("gcode_flavor")->has_enum_value(this->gcode_flavor.serialize())) return "Invalid value for --gcode-flavor"; - + // --fill-pattern if (! print_config_def.get("fill_pattern")->has_enum_value(this->fill_pattern.serialize())) return "Invalid value for --fill-pattern"; - + // --top-fill-pattern if (! print_config_def.get("top_fill_pattern")->has_enum_value(this->top_fill_pattern.serialize())) return "Invalid value for --top-fill-pattern"; @@ -2963,7 +2963,7 @@ std::string FullPrintConfig::validate() if (fabs(this->fill_density.value - 100.) < EPSILON && ! print_config_def.get("top_fill_pattern")->has_enum_value(this->fill_pattern.serialize())) return "The selected fill pattern is not supposed to work at 100% density"; - + // --infill-every-layers if (this->infill_every_layers < 1) return "Invalid value for --infill-every-layers"; @@ -2971,11 +2971,11 @@ std::string FullPrintConfig::validate() // --skirt-height if (this->skirt_height < -1) // -1 means as tall as the object return "Invalid value for --skirt-height"; - + // --bridge-flow-ratio if (this->bridge_flow_ratio <= 0) return "Invalid value for --bridge-flow-ratio"; - + // extruder clearance if (this->extruder_clearance_radius <= 0) return "Invalid value for --extruder-clearance-radius"; @@ -3007,7 +3007,7 @@ std::string FullPrintConfig::validate() if (this->support_material || this->support_material_enforce_layers > 0) return "Spiral vase mode is not compatible with support material"; } - + // extrusion widths { double max_nozzle_diameter = 0.; @@ -3064,7 +3064,7 @@ std::string FullPrintConfig::validate() if (out_of_range) return std::string("Value out of range: " + opt_key); } - + // The configuration is valid. return ""; } @@ -3087,20 +3087,20 @@ StaticPrintConfig::StaticCache SLAFullPrint CLIActionsConfigDef::CLIActionsConfigDef() { ConfigOptionDef* def; - + // Actions: def = this->add("export_obj", coBool); def->label = L("Export OBJ"); def->tooltip = L("Export the model(s) as OBJ."); def->set_default_value(new ConfigOptionBool(false)); - + /* def = this->add("export_svg", coBool); def->label = L("Export SVG"); def->tooltip = L("Slice the model and export solid slices as SVG."); def->set_default_value(new ConfigOptionBool(false)); */ - + def = this->add("export_sla", coBool); def->label = L("Export SLA"); def->tooltip = L("Slice the model and export SLA printing layers as PNG."); @@ -3149,12 +3149,12 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->label = L("Help (SLA options)"); def->tooltip = L("Show the full list of SLA print configuration options."); def->set_default_value(new ConfigOptionBool(false)); - + def = this->add("info", coBool); def->label = L("Output Model Info"); def->tooltip = L("Write information about the model to the console."); def->set_default_value(new ConfigOptionBool(false)); - + def = this->add("save", coString); def->label = L("Save config file"); def->tooltip = L("Save configuration to the specified file."); @@ -3164,35 +3164,35 @@ CLIActionsConfigDef::CLIActionsConfigDef() CLITransformConfigDef::CLITransformConfigDef() { ConfigOptionDef* def; - + // Transform options: def = this->add("align_xy", coPoint); def->label = L("Align XY"); def->tooltip = L("Align the model to the given point."); def->set_default_value(new ConfigOptionPoint(Vec2d(100,100))); - + def = this->add("cut", coFloat); def->label = L("Cut"); def->tooltip = L("Cut model at the given Z."); def->set_default_value(new ConfigOptionFloat(0)); - + /* def = this->add("cut_grid", coFloat); def->label = L("Cut"); def->tooltip = L("Cut model in the XY plane into tiles of the specified max size."); def->set_default_value(new ConfigOptionPoint()); - + def = this->add("cut_x", coFloat); def->label = L("Cut"); def->tooltip = L("Cut model at the given X."); def->set_default_value(new ConfigOptionFloat(0)); - + def = this->add("cut_y", coFloat); def->label = L("Cut"); def->tooltip = L("Cut model at the given Y."); def->set_default_value(new ConfigOptionFloat(0)); */ - + def = this->add("center", coPoint); def->label = L("Center"); def->tooltip = L("Center the print around the given center."); @@ -3201,12 +3201,12 @@ CLITransformConfigDef::CLITransformConfigDef() def = this->add("dont_arrange", coBool); def->label = L("Don't arrange"); def->tooltip = L("Do not rearrange the given models before merging and keep their original XY coordinates."); - + def = this->add("duplicate", coInt); def->label = L("Duplicate"); def->tooltip =L("Multiply copies by this factor."); def->min = 1; - + def = this->add("duplicate_grid", coPoint); def->label = L("Duplicate by grid"); def->tooltip = L("Multiply copies by creating a grid."); @@ -3219,22 +3219,22 @@ CLITransformConfigDef::CLITransformConfigDef() def = this->add("repair", coBool); def->label = L("Repair"); def->tooltip = L("Try to repair any non-manifold meshes (this option is implicitly added whenever we need to slice the model to perform the requested action)."); - + def = this->add("rotate", coFloat); def->label = L("Rotate"); def->tooltip = L("Rotation angle around the Z axis in degrees."); def->set_default_value(new ConfigOptionFloat(0)); - + def = this->add("rotate_x", coFloat); def->label = L("Rotate around X"); def->tooltip = L("Rotation angle around the X axis in degrees."); def->set_default_value(new ConfigOptionFloat(0)); - + def = this->add("rotate_y", coFloat); def->label = L("Rotate around Y"); def->tooltip = L("Rotation angle around the Y axis in degrees."); def->set_default_value(new ConfigOptionFloat(0)); - + def = this->add("scale", coFloatOrPercent); def->label = L("Scale"); def->tooltip = L("Scaling factor or percentage."); @@ -3243,7 +3243,7 @@ CLITransformConfigDef::CLITransformConfigDef() def = this->add("split", coBool); def->label = L("Split"); def->tooltip = L("Detect unconnected parts in the given model(s) and split them into separate objects."); - + def = this->add("scale_to_fit", coPoint3); def->label = L("Scale to Fit"); def->tooltip = L("Scale to fit the given volume."); @@ -3253,26 +3253,26 @@ CLITransformConfigDef::CLITransformConfigDef() CLIMiscConfigDef::CLIMiscConfigDef() { ConfigOptionDef* def; - + def = this->add("ignore_nonexistent_config", coBool); def->label = L("Ignore non-existent config files"); def->tooltip = L("Do not fail if a file supplied to --load does not exist."); - + def = this->add("load", coStrings); def->label = L("Load config file"); def->tooltip = L("Load configuration from the specified file. It can be used more than once to load options from multiple files."); - + def = this->add("output", coString); def->label = L("Output File"); def->tooltip = L("The file where the output will be written (if not specified, it will be based on the input file)."); def->cli = "output|o"; -/* +/* def = this->add("autosave", coString); def->label = L("Autosave"); def->tooltip = L("Automatically export current configuration to the specified file."); */ - + def = this->add("datadir", coString); def->label = L("Data directory"); def->tooltip = L("Load and store settings at the given directory. This is useful for maintaining different profiles or including configurations from a network storage."); @@ -3282,7 +3282,7 @@ CLIMiscConfigDef::CLIMiscConfigDef() def->tooltip = L("Messages with severity lower or eqal to the loglevel will be printed out. 0:trace, 1:debug, 2:info, 3:warning, 4:error, 5:fatal"); def->min = 0; -#if defined(_MSC_VER) && defined(SLIC3R_GUI) +#if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(SLIC3R_GUI) def = this->add("sw_renderer", coBool); def->label = L("Render with a software renderer"); def->tooltip = L("Render with a software renderer. The bundled MESA software renderer is loaded instead of the default OpenGL driver."); @@ -3298,15 +3298,15 @@ DynamicPrintAndCLIConfig::PrintAndCLIConfigDef DynamicPrintAndCLIConfig::s_def; void DynamicPrintAndCLIConfig::handle_legacy(t_config_option_key &opt_key, std::string &value) const { - if (cli_actions_config_def .options.find(opt_key) == cli_actions_config_def .options.end() && - cli_transform_config_def.options.find(opt_key) == cli_transform_config_def.options.end() && - cli_misc_config_def .options.find(opt_key) == cli_misc_config_def .options.end()) { - PrintConfigDef::handle_legacy(opt_key, value); - } + if (cli_actions_config_def .options.find(opt_key) == cli_actions_config_def .options.end() && + cli_transform_config_def.options.find(opt_key) == cli_transform_config_def.options.end() && + cli_misc_config_def .options.find(opt_key) == cli_misc_config_def .options.end()) { + PrintConfigDef::handle_legacy(opt_key, value); + } } } #include CEREAL_REGISTER_TYPE(Slic3r::DynamicPrintConfig) -CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::DynamicConfig, Slic3r::DynamicPrintConfig) +CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::DynamicConfig, Slic3r::DynamicPrintConfig) diff --git a/src/libslic3r/SLA/SLAAutoSupports.cpp b/src/libslic3r/SLA/SLAAutoSupports.cpp index 78efd08067..36378df395 100644 --- a/src/libslic3r/SLA/SLAAutoSupports.cpp +++ b/src/libslic3r/SLA/SLAAutoSupports.cpp @@ -1,5 +1,5 @@ -#include "igl/random_points_on_mesh.h" -#include "igl/AABB.h" +//#include "igl/random_points_on_mesh.h" +//#include "igl/AABB.h" #include @@ -101,7 +101,7 @@ static std::vector make_layers( std::vector layers; layers.reserve(slices.size()); for (size_t i = 0; i < slices.size(); ++ i) - layers.emplace_back(i, heights[i]); + layers.emplace_back(i, heights[i]); // FIXME: calculate actual pixel area from printer config: //const float pixel_area = pow(wxGetApp().preset_bundle->project_config.option("display_width") / wxGetApp().preset_bundle->project_config.option("display_pixels_x"), 2.f); // @@ -114,47 +114,47 @@ static std::vector make_layers( if ((layer_id % 8) == 0) // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves. throw_on_cancel(); - SLAAutoSupports::MyLayer &layer = layers[layer_id]; + SLAAutoSupports::MyLayer &layer = layers[layer_id]; const ExPolygons &islands = slices[layer_id]; //FIXME WTF? const float height = (layer_id>2 ? heights[layer_id-3] : heights[0]-(heights[1]-heights[0])); - layer.islands.reserve(islands.size()); + layer.islands.reserve(islands.size()); for (const ExPolygon &island : islands) { float area = float(island.area() * SCALING_FACTOR * SCALING_FACTOR); if (area >= pixel_area) //FIXME this is not a correct centroid of a polygon with holes. - layer.islands.emplace_back(layer, island, get_extents(island.contour), Slic3r::unscale(island.contour.centroid()).cast(), area, height); + layer.islands.emplace_back(layer, island, get_extents(island.contour), Slic3r::unscale(island.contour.centroid()).cast(), area, height); } } }); - // Calculate overlap of successive layers. Link overlapping islands. - tbb::parallel_for(tbb::blocked_range(1, layers.size(), 8), - [&layers, &heights, throw_on_cancel](const tbb::blocked_range& range) { - for (size_t layer_id = range.begin(); layer_id < range.end(); ++layer_id) { - if ((layer_id % 2) == 0) - // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves. - throw_on_cancel(); - SLAAutoSupports::MyLayer &layer_above = layers[layer_id]; - SLAAutoSupports::MyLayer &layer_below = layers[layer_id - 1]; + // Calculate overlap of successive layers. Link overlapping islands. + tbb::parallel_for(tbb::blocked_range(1, layers.size(), 8), + [&layers, &heights, throw_on_cancel](const tbb::blocked_range& range) { + for (size_t layer_id = range.begin(); layer_id < range.end(); ++layer_id) { + if ((layer_id % 2) == 0) + // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves. + throw_on_cancel(); + SLAAutoSupports::MyLayer &layer_above = layers[layer_id]; + SLAAutoSupports::MyLayer &layer_below = layers[layer_id - 1]; //FIXME WTF? const float layer_height = (layer_id!=0 ? heights[layer_id]-heights[layer_id-1] : heights[0]); const float safe_angle = 5.f * (float(M_PI)/180.f); // smaller number - less supports const float between_layers_offset = float(scale_(layer_height / std::tan(safe_angle))); const float slope_angle = 75.f * (float(M_PI)/180.f); // smaller number - less supports const float slope_offset = float(scale_(layer_height / std::tan(slope_angle))); - //FIXME This has a quadratic time complexity, it will be excessively slow for many tiny islands. - for (SLAAutoSupports::Structure &top : layer_above.islands) { - for (SLAAutoSupports::Structure &bottom : layer_below.islands) { + //FIXME This has a quadratic time complexity, it will be excessively slow for many tiny islands. + for (SLAAutoSupports::Structure &top : layer_above.islands) { + for (SLAAutoSupports::Structure &bottom : layer_below.islands) { float overlap_area = top.overlap_area(bottom); if (overlap_area > 0) { - top.islands_below.emplace_back(&bottom, overlap_area); + top.islands_below.emplace_back(&bottom, overlap_area); bottom.islands_above.emplace_back(&top, overlap_area); } } if (! top.islands_below.empty()) { Polygons top_polygons = to_polygons(*top.polygon); - Polygons bottom_polygons = top.polygons_below(); + Polygons bottom_polygons = top.polygons_below(); top.overhangs = diff_ex(top_polygons, bottom_polygons); if (! top.overhangs.empty()) { top.overhangs_area = 0.f; @@ -164,21 +164,21 @@ static std::vector make_layers( expolys_with_areas.emplace_back(&ex, area); top.overhangs_area += area; } - std::sort(expolys_with_areas.begin(), expolys_with_areas.end(), + std::sort(expolys_with_areas.begin(), expolys_with_areas.end(), [](const std::pair &p1, const std::pair &p2) { return p1.second > p2.second; }); ExPolygons overhangs_sorted; for (auto &p : expolys_with_areas) overhangs_sorted.emplace_back(std::move(*p.first)); - top.overhangs = std::move(overhangs_sorted); + top.overhangs = std::move(overhangs_sorted); top.overhangs_area *= float(SCALING_FACTOR * SCALING_FACTOR); top.overhangs_slopes = diff_ex(top_polygons, offset(bottom_polygons, slope_offset)); top.dangling_areas = diff_ex(top_polygons, offset(bottom_polygons, between_layers_offset)); } } - } - } - }); + } + } + }); return layers; } @@ -207,14 +207,14 @@ void SLAAutoSupports::process(const std::vector& slices, const std:: support_force_bottom[i] = layer_bottom->islands[i].supports_force_total(); } for (Structure &top : layer_top->islands) - for (Structure::Link &bottom_link : top.islands_below) { + for (Structure::Link &bottom_link : top.islands_below) { Structure &bottom = *bottom_link.island; //float centroids_dist = (bottom.centroid - top.centroid).norm(); // Penalization resulting from centroid offset: // bottom.supports_force *= std::min(1.f, 1.f - std::min(1.f, (1600.f * layer_height) * centroids_dist * centroids_dist / bottom.area)); float &support_force = support_force_bottom[&bottom - layer_bottom->islands.data()]; //FIXME this condition does not reflect a bifurcation into a one large island and one tiny island well, it incorrectly resets the support force to zero. -// One should rather work with the overlap area vs overhang area. +// One should rather work with the overlap area vs overhang area. // support_force *= std::min(1.f, 1.f - std::min(1.f, 0.1f * centroids_dist * centroids_dist / bottom.area)); // Penalization resulting from increasing polygon area: support_force *= std::min(1.f, 20.f * bottom.area / top.area); @@ -224,10 +224,10 @@ void SLAAutoSupports::process(const std::vector& slices, const std:: for (Structure &below : layer_bottom->islands) { float below_support_force = support_force_bottom[&below - layer_bottom->islands.data()]; float above_overlap_area = 0.f; - for (Structure::Link &above_link : below.islands_above) - above_overlap_area += above_link.overlap_area; - for (Structure::Link &above_link : below.islands_above) - above_link.island->supports_force_inherited += below_support_force * above_link.overlap_area / above_overlap_area; + for (Structure::Link &above_link : below.islands_above) + above_overlap_area += above_link.overlap_area; + for (Structure::Link &above_link : below.islands_above) + above_link.island->supports_force_inherited += below_support_force * above_link.overlap_area / above_overlap_area; } } // Now iterate over all polygons and append new points if needed. @@ -266,7 +266,7 @@ void SLAAutoSupports::process(const std::vector& slices, const std:: } std::vector sample_expolygon(const ExPolygon &expoly, float samples_per_mm2, std::mt19937 &rng) -{ +{ // Triangulate the polygon with holes into triplets of 3D points. std::vector triangles = Slic3r::triangulate_expolygon_2f(expoly); @@ -347,7 +347,7 @@ static inline std::vector poisson_disk_from_samples(const std::vector(); raw_samples_sorted.emplace_back(sample); } - std::sort(raw_samples_sorted.begin(), raw_samples_sorted.end(), [](const RawSample &lhs, const RawSample &rhs) + std::sort(raw_samples_sorted.begin(), raw_samples_sorted.end(), [](const RawSample &lhs, const RawSample &rhs) { return lhs.cell_id.x() < rhs.cell_id.x() || (lhs.cell_id.x() == rhs.cell_id.x() && lhs.cell_id.y() < rhs.cell_id.y()); }); struct PoissonDiskGridEntry { @@ -464,10 +464,10 @@ void SLAAutoSupports::uniformly_cover(const ExPolygons& islands, Structure& stru //FIXME share the random generator. The random generator may be not so cheap to initialize, also we don't want the random generator to be restarted for each polygon. std::random_device rd; std::mt19937 rng(rd()); - std::vector raw_samples = sample_expolygon_with_boundary(islands, samples_per_mm2, 5.f / poisson_radius, rng); + std::vector raw_samples = sample_expolygon_with_boundary(islands, samples_per_mm2, 5.f / poisson_radius, rng); std::vector poisson_samples; for (size_t iter = 0; iter < 4; ++ iter) { - poisson_samples = poisson_disk_from_samples(raw_samples, poisson_radius, + poisson_samples = poisson_disk_from_samples(raw_samples, poisson_radius, [&structure, &grid3d, min_spacing](const Vec2f &pos) { return grid3d.collides_with(pos, &structure, min_spacing); }); @@ -481,21 +481,21 @@ void SLAAutoSupports::uniformly_cover(const ExPolygons& islands, Structure& stru } #ifdef SLA_AUTOSUPPORTS_DEBUG - { - static int irun = 0; - Slic3r::SVG svg(debug_out_path("SLA_supports-uniformly_cover-%d.svg", irun ++), get_extents(islands)); + { + static int irun = 0; + Slic3r::SVG svg(debug_out_path("SLA_supports-uniformly_cover-%d.svg", irun ++), get_extents(islands)); for (const ExPolygon &island : islands) svg.draw(island); - for (const Vec2f &pt : raw_samples) - svg.draw(Point(scale_(pt.x()), scale_(pt.y())), "red"); - for (const Vec2f &pt : poisson_samples) - svg.draw(Point(scale_(pt.x()), scale_(pt.y())), "blue"); - } + for (const Vec2f &pt : raw_samples) + svg.draw(Point(scale_(pt.x()), scale_(pt.y())), "red"); + for (const Vec2f &pt : poisson_samples) + svg.draw(Point(scale_(pt.x()), scale_(pt.y())), "blue"); + } #endif /* NDEBUG */ // assert(! poisson_samples.empty()); if (poisson_samples_target < poisson_samples.size()) { - std::shuffle(poisson_samples.begin(), poisson_samples.end(), rng); + std::shuffle(poisson_samples.begin(), poisson_samples.end(), rng); poisson_samples.erase(poisson_samples.begin() + poisson_samples_target, poisson_samples.end()); } for (const Vec2f &pt : poisson_samples) { diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index 6f4ac6c21a..5e4820988e 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -85,7 +85,7 @@ using Portion = std::tuple; // Set this to true to enable full parallelism in this module. // Only the well tested parts will be concurrent if this is set to false. -const constexpr bool USE_FULL_CONCURRENCY = false; +const constexpr bool USE_FULL_CONCURRENCY = true; template struct _ccr {}; @@ -580,13 +580,13 @@ struct CompactBridge { double fa = 2*PI/steps; auto upperball = sphere(r, Portion{PI / 2 - fa, PI}, fa); for(auto& p : upperball.points) p += startp; - + if(endball) { auto lowerball = sphere(r, Portion{0, PI/2 + 2*fa}, fa); for(auto& p : lowerball.points) p += endp; mesh.merge(lowerball); } - + mesh.merge(upperball); } }; @@ -604,15 +604,15 @@ struct Pad { double ground_level, const PoolConfig& pcfg) : cfg(pcfg), - zlevel(ground_level + + zlevel(ground_level + sla::get_pad_fullheight(pcfg) - sla::get_pad_elevation(pcfg)) { Polygons basep; auto &thr = cfg.throw_on_cancel; - + thr(); - + // Get a sample for the pad from the support mesh { ExPolygons platetmp; @@ -626,20 +626,20 @@ struct Pad { for (const ExPolygon &bp : platetmp) basep.emplace_back(std::move(bp.contour)); } - + if(pcfg.embed_object) { - + // If the zero elevation mode is ON, we need to process the model // base silhouette. Create the offsetted version and punch the // breaksticks across its perimeter. - + ExPolygons modelbase_offs = modelbase; - + if (pcfg.embed_object.object_gap_mm > 0.0) modelbase_offs = offset_ex(modelbase_offs, float(scaled(pcfg.embed_object.object_gap_mm))); - + // Create a spatial index of the support silhouette polygons. // This will be used to check for intersections with the model // silhouette polygons. If there is no intersection, then a certain @@ -653,35 +653,35 @@ struct Pad { bindex.insert(bb, idx++); } } - + ExPolygons concaveh = offset_ex( concave_hull(basep, pcfg.max_merge_distance_mm, thr), scaled(pcfg.min_wall_thickness_mm)); - + // Punching the breaksticks across the offsetted polygon perimeters auto pad_stickholes = reserve_vector(modelbase.size()); for(auto& poly : modelbase_offs) { - + bool overlap = false; for (const ExPolygon &p : concaveh) overlap = overlap || poly.overlaps(p); - + auto bb = poly.contour.bounding_box(); bb.offset(scaled(pcfg.min_wall_thickness_mm)); - + std::vector qres = bindex.query(bb, BoxIndex::qtIntersects); - + if (!qres.empty() || overlap) { - + // The model silhouette polygon 'poly' HAS an intersection // with the support silhouettes. Include this polygon // in the pad holes with the breaksticks and merge the // original (offsetted) version with the rest of the pad // base plate. - + basep.emplace_back(poly.contour); - + // The holes of 'poly' will become positive parts of the // pad, so they has to be checked for intersections as well // and erased if there is no intersection with the supports @@ -693,7 +693,7 @@ struct Pad { else ++it; } - + // Punch the breaksticks sla::breakstick_holes( poly, @@ -701,11 +701,11 @@ struct Pad { pcfg.embed_object.stick_stride_mm, pcfg.embed_object.stick_width_mm, pcfg.embed_object.stick_penetration_mm); - + pad_stickholes.emplace_back(poly); } } - + create_base_pool(basep, tmesh, pad_stickholes, cfg); } else { for (const ExPolygon &bp : modelbase) basep.emplace_back(bp.contour); @@ -775,78 +775,78 @@ class SLASupportTree::Impl { // For heads it is beneficial to use the same IDs as for the support points. std::vector m_heads; std::vector m_head_indices; - + std::vector m_pillars; std::vector m_junctions; std::vector m_bridges; std::vector m_compact_bridges; Controller m_ctl; - + Pad m_pad; - + using Mutex = ccr::Mutex; - + mutable Mutex m_mutex; mutable TriangleMesh meshcache; mutable bool meshcache_valid = false; mutable double model_height = 0; // the full height of the model - + public: double ground_level = 0; - + Impl() = default; inline Impl(const Controller& ctl): m_ctl(ctl) {} - + const Controller& ctl() const { return m_ctl; } - + template Head& add_head(unsigned id, Args&&... args) { std::lock_guard lk(m_mutex); m_heads.emplace_back(std::forward(args)...); m_heads.back().id = id; - + if (id >= m_head_indices.size()) m_head_indices.resize(id + 1); m_head_indices[id] = m_heads.size() - 1; - + meshcache_valid = false; return m_heads.back(); } - + template Pillar& add_pillar(unsigned headid, Args&&... args) { std::lock_guard lk(m_mutex); - + assert(headid < m_head_indices.size()); Head &head = m_heads[m_head_indices[headid]]; - + m_pillars.emplace_back(head, std::forward(args)...); Pillar& pillar = m_pillars.back(); pillar.id = long(m_pillars.size() - 1); head.pillar_id = pillar.id; pillar.start_junction_id = head.id; pillar.starts_from_head = true; - + meshcache_valid = false; return m_pillars.back(); } - + void increment_bridges(const Pillar& pillar) { std::lock_guard lk(m_mutex); assert(pillar.id >= 0 && size_t(pillar.id) < m_pillars.size()); - - if(pillar.id >= 0 && size_t(pillar.id) < m_pillars.size()) + + if(pillar.id >= 0 && size_t(pillar.id) < m_pillars.size()) m_pillars[size_t(pillar.id)].bridges++; } - + void increment_links(const Pillar& pillar) { std::lock_guard lk(m_mutex); assert(pillar.id >= 0 && size_t(pillar.id) < m_pillars.size()); - + if(pillar.id >= 0 && size_t(pillar.id) < m_pillars.size()) - m_pillars[size_t(pillar.id)].links++; + m_pillars[size_t(pillar.id)].links++; } - + template Pillar& add_pillar(Args&&...args) { std::lock_guard lk(m_mutex); @@ -857,30 +857,30 @@ public: meshcache_valid = false; return m_pillars.back(); } - + const Head& pillar_head(long pillar_id) const { std::lock_guard lk(m_mutex); assert(pillar_id >= 0 && pillar_id < long(m_pillars.size())); - + const Pillar& p = m_pillars[size_t(pillar_id)]; assert(p.starts_from_head && p.start_junction_id >= 0); assert(size_t(p.start_junction_id) < m_head_indices.size()); - + return m_heads[m_head_indices[p.start_junction_id]]; } - + const Pillar& head_pillar(unsigned headid) const { std::lock_guard lk(m_mutex); assert(headid < m_head_indices.size()); - + const Head& h = m_heads[m_head_indices[headid]]; assert(h.pillar_id >= 0 && h.pillar_id < long(m_pillars.size())); - + return m_pillars[size_t(h.pillar_id)]; } - + template const Junction& add_junction(Args&&... args) { std::lock_guard lk(m_mutex); @@ -889,7 +889,7 @@ public: meshcache_valid = false; return m_junctions.back(); } - + template const Bridge& add_bridge(Args&&... args) { std::lock_guard lk(m_mutex); @@ -898,7 +898,7 @@ public: meshcache_valid = false; return m_bridges.back(); } - + template const CompactBridge& add_compact_bridge(Args&&...args) { std::lock_guard lk(m_mutex); @@ -907,30 +907,30 @@ public: meshcache_valid = false; return m_compact_bridges.back(); } - + Head &head(unsigned id) { std::lock_guard lk(m_mutex); assert(id < m_head_indices.size()); - + meshcache_valid = false; return m_heads[m_head_indices[id]]; } - + inline size_t pillarcount() const { std::lock_guard lk(m_mutex); return m_pillars.size(); } - + template inline IntegerOnly pillar(T id) const { std::lock_guard lk(m_mutex); assert(id >= 0 && size_t(id) < m_pillars.size() && size_t(id) < std::numeric_limits::max()); - + return m_pillars[size_t(id)]; } - + const Pad &create_pad(const TriangleMesh &object_supports, const ExPolygons & modelbase, const PoolConfig & cfg) @@ -938,86 +938,88 @@ public: m_pad = Pad(object_supports, modelbase, ground_level, cfg); return m_pad; } - + void remove_pad() { m_pad = Pad(); } - + const Pad& pad() const { return m_pad; } - + // WITHOUT THE PAD!!! const TriangleMesh &merged_mesh() const { if (meshcache_valid) return meshcache; - + + std::cout << "merging mesh" << std::endl; + Contour3D merged; - + for (auto &head : m_heads) { if (m_ctl.stopcondition()) break; if (head.is_valid()) merged.merge(head.mesh); } - + for (auto &stick : m_pillars) { if (m_ctl.stopcondition()) break; merged.merge(stick.mesh); merged.merge(stick.base); } - + for (auto &j : m_junctions) { if (m_ctl.stopcondition()) break; merged.merge(j.mesh); } - + for (auto &cb : m_compact_bridges) { if (m_ctl.stopcondition()) break; merged.merge(cb.mesh); } - + for (auto &bs : m_bridges) { if (m_ctl.stopcondition()) break; merged.merge(bs.mesh); } - + if (m_ctl.stopcondition()) { // In case of failure we have to return an empty mesh meshcache = TriangleMesh(); return meshcache; } - + meshcache = mesh(merged); - + // The mesh will be passed by const-pointer to TriangleMeshSlicer, // which will need this. if (!meshcache.empty()) meshcache.require_shared_vertices(); - + BoundingBoxf3 &&bb = meshcache.bounding_box(); model_height = bb.max(Z) - bb.min(Z); - + meshcache_valid = true; return meshcache; } - + // WITH THE PAD double full_height() const { if (merged_mesh().empty() && !pad().empty()) return get_pad_fullheight(pad().cfg); - + double h = mesh_height(); if (!pad().empty()) h += sla::get_pad_elevation(pad().cfg); return h; } - + // WITHOUT THE PAD!!! double mesh_height() const { if (!meshcache_valid) merged_mesh(); return model_height; } - + // Intended to be called after the generation is fully complete void merge_and_cleanup() { merged_mesh(); // in case the mesh is not generated, it should be... - + // Doing clear() does not garantee to release the memory. m_heads = {}; m_head_indices = {}; @@ -1194,7 +1196,7 @@ class SLASupportTree::Algorithm { // Now a and b vectors are perpendicular to v and to each other. // Together they define the plane where we have to iterate with the // given angles in the 'phis' vector - ccr_par::enumerate(phis.begin(), phis.end(), + ccr_seq::enumerate(phis.begin(), phis.end(), [&hits, &m, sd, r_pin, r_back, s, a, b, c] (double phi, size_t i) { @@ -1296,8 +1298,8 @@ class SLASupportTree::Algorithm { // Hit results std::array hits; - - ccr_par::enumerate(phis.begin(), phis.end(), + + ccr_seq::enumerate(phis.begin(), phis.end(), [&m, a, b, sd, dir, r, s, ins_check, &hits] (double phi, size_t i) { @@ -1431,11 +1433,11 @@ class SLASupportTree::Algorithm { // For connecting a head to a nearby pillar. bool connect_to_nearpillar(const Head& head, long nearpillar_id) { - + auto nearpillar = [this, nearpillar_id]() { return m_result.pillar(nearpillar_id); }; - + if (nearpillar().bridges > m_cfg.max_bridges_on_pillar) return false; Vec3d headjp = head.junction_point(); @@ -1539,7 +1541,7 @@ class SLASupportTree::Algorithm { return nearest_id >= 0; } - + // This is a proxy function for pillar creation which will mind the gap // between the pad and the model bottom in zero elevation mode. void create_ground_pillar(const Vec3d &jp, @@ -1594,7 +1596,7 @@ class SLASupportTree::Algorithm { endp = jp + SQR2 * mv * dir; Vec3d pgnd = {endp(X), endp(Y), gndlvl}; can_add_base = result.score > min_dist; - + double gnd_offs = m_mesh.ground_level_offset(); auto abort_in_shame = [gnd_offs, &normal_mode, &can_add_base, &endp, jp, gndlvl]() @@ -1612,7 +1614,7 @@ class SLASupportTree::Algorithm { if (endp(Z) < gndlvl) endp = endp - SQR2 * (gndlvl - endp(Z)) * dir; // back off else { - + auto hit = bridge_mesh_intersect(endp, DOWN, radius); if (!std::isinf(hit.distance())) abort_in_shame(); @@ -1636,7 +1638,7 @@ class SLASupportTree::Algorithm { m_result.add_pillar(unsigned(head_id), jp, radius); } } - + if (normal_mode) { Pillar &plr = head_id >= 0 ? m_result.add_pillar(unsigned(head_id), @@ -1648,8 +1650,8 @@ class SLASupportTree::Algorithm { plr.add_base(m_cfg.base_height_mm, m_cfg.base_radius_mm); pillar_id = plr.id; - } - + } + if(pillar_id >= 0) // Save the pillar endpoint in the spatial index m_pillar_index.insert(endp, pillar_id); } @@ -1716,52 +1718,52 @@ public: using libnest2d::opt::initvals; using libnest2d::opt::GeneticOptimizer; using libnest2d::opt::StopCriteria; - + ccr::Mutex mutex; auto addfn = [&mutex](PtIndices &container, unsigned val) { std::lock_guard lk(mutex); container.emplace_back(val); }; - + ccr::enumerate(filtered_indices.begin(), filtered_indices.end(), [this, &nmls, addfn](unsigned fidx, size_t i) { m_thr(); - + auto n = nmls.row(i); - + // for all normals we generate the spherical coordinates and // saturate the polar angle to 45 degrees from the bottom then // convert back to standard coordinates to get the new normal. // Then we just create a quaternion from the two normals // (Quaternion::FromTwoVectors) and apply the rotation to the // arrow head. - + double z = n(2); double r = 1.0; // for normalized vector double polar = std::acos(z / r); double azimuth = std::atan2(n(1), n(0)); - + // skip if the tilt is not sane if(polar >= PI - m_cfg.normal_cutoff_angle) { - + // We saturate the polar angle to 3pi/4 polar = std::max(polar, 3*PI / 4); - + // save the head (pinpoint) position Vec3d hp = m_points.row(fidx); - + double w = m_cfg.head_width_mm + m_cfg.head_back_radius_mm + 2*m_cfg.head_front_radius_mm; - + double pin_r = double(m_support_pts[fidx].head_front_radius); - + // Reassemble the now corrected normal auto nn = Vec3d(std::cos(azimuth) * std::sin(polar), std::sin(azimuth) * std::sin(polar), std::cos(polar)).normalized(); - + // check available distance EigenMesh3D::hit_result t = pinhead_mesh_intersect(hp, // touching point @@ -1769,20 +1771,20 @@ public: pin_r, m_cfg.head_back_radius_mm, w); - + if(t.distance() <= w) { - + // Let's try to optimize this angle, there might be a // viable normal that doesn't collide with the model // geometry and its very close to the default. - + StopCriteria stc; stc.max_iterations = m_cfg.optimizer_max_iterations; stc.relative_score_difference = m_cfg.optimizer_rel_score_diff; stc.stop_score = w; // space greater than w is enough GeneticOptimizer solver(stc); solver.seed(0); // we want deterministic behavior - + auto oresult = solver.optimize_max( [this, pin_r, w, hp](double plr, double azm) { @@ -1799,7 +1801,7 @@ public: bound(3*PI/4, PI), // Must not exceed the tilt limit bound(-PI, PI) // azimuth can be a full search ); - + if(oresult.score > w) { polar = std::get<0>(oresult.optimum); azimuth = std::get<1>(oresult.optimum); @@ -1809,10 +1811,10 @@ public: t = oresult.score; } } - + // save the verified and corrected normal m_support_nmls.row(fidx) = nn; - + if (t.distance() > w) { // Check distance from ground, we might have zero elevation. if (hp(Z) + w * nn(Z) < m_result.ground_level) { @@ -1889,7 +1891,7 @@ public: // from each other in the XY plane to not cross their pillar bases // These clusters of support points will join in one pillar, // possibly in their centroid support point. - + auto pointfn = [this](unsigned i) { return m_result.head(i).junction_point(); }; @@ -2178,7 +2180,7 @@ public: m_pillar_index.insert(pillar.endpoint(), pillid); } } - + // Helper function for interconnect_pillars where pairs of already connected // pillars should be checked for not to be processed again. This can be done // in O(log) or even constant time with a set or an unordered set of hash @@ -2187,17 +2189,17 @@ public: template static I pairhash(I a, I b) { using std::ceil; using std::log2; using std::max; using std::min; - + static_assert(std::is_integral::value, "This function works only for integral types."); I g = min(a, b), l = max(a, b); - + auto bits_g = g ? int(ceil(log2(g))) : 0; // Assume the hash will fit into the output variable assert((l ? (ceil(log2(l))) : 0) + bits_g < int(sizeof(I) * CHAR_BIT)); - + return (l << bits_g) + g; } @@ -2217,7 +2219,7 @@ public: double min_height_ratio = 0.5; std::set pairs; - + // A function to connect one pillar with its neighbors. THe number of // neighbors is given in the configuration. This function if called // for every pillar in the pillar index. A pair of pillar will not @@ -2229,7 +2231,7 @@ public: Vec3d qp = el.first; // endpoint of the pillar const Pillar& pillar = m_result.pillar(el.second); // actual pillar - + // Get the max number of neighbors a pillar should connect to unsigned neighbors = m_cfg.pillar_cascade_neighbors; @@ -2255,10 +2257,10 @@ public: // Get unique hash for the given pair (order doesn't matter) auto hashval = pairhash(a, b); - + // Search for the pair amongst the remembered pairs if(pairs.find(hashval) != pairs.end()) continue; - + const Pillar& neighborpillar = m_result.pillar(re.second); // this neighbor is occupied, skip @@ -2283,10 +2285,10 @@ public: if(pillar.links >= neighbors) break; } }; - + // Run the cascade for the pillars in the index m_pillar_index.foreach(cascadefn); - + // We would be done here if we could allow some pillars to not be // connected with any neighbors. But this might leave the support tree // unprintable. @@ -2294,16 +2296,16 @@ public: // The current solution is to insert additional pillars next to these // lonely pillars. One or even two additional pillar might get inserted // depending on the length of the lonely pillar. - + size_t pillarcount = m_result.pillarcount(); - + // Again, go through all pillars, this time in the whole support tree // not just the index. for(size_t pid = 0; pid < pillarcount; pid++) { auto pillar = [this, pid]() { return m_result.pillar(pid); }; - + // Decide how many additional pillars will be needed: - + unsigned needpillars = 0; if (pillar().bridges > m_cfg.max_bridges_on_pillar) needpillars = 3; @@ -2332,7 +2334,7 @@ public: double gnd = m_result.ground_level; double min_dist = m_cfg.pillar_base_safety_distance_mm + m_cfg.base_radius_mm + EPSILON; - + while(!found && alpha < 2*PI) { for (unsigned n = 0; n < needpillars && (!n || canplace[n - 1]); @@ -2343,11 +2345,11 @@ public: s(X) += std::cos(a) * r; s(Y) += std::sin(a) * r; spts[n] = s; - - // Check the path vertically down + + // Check the path vertically down auto hr = bridge_mesh_intersect(s, {0, 0, -1}, pillar().r); Vec3d gndsp{s(X), s(Y), gnd}; - + // If the path is clear, check for pillar base collisions canplace[n] = std::isinf(hr.distance()) && std::sqrt(m_mesh.squared_distance(gndsp)) > @@ -2365,7 +2367,7 @@ public: newpills.reserve(needpillars); if(found) for(unsigned n = 0; n < needpillars; n++) { - Vec3d s = spts[n]; + Vec3d s = spts[n]; Pillar p(s, Vec3d(s(X), s(Y), gnd), pillar().r); p.add_base(m_cfg.base_height_mm, m_cfg.base_radius_mm); @@ -2447,8 +2449,8 @@ public: m_result.add_compact_bridge(sp, ej, n, R, !std::isinf(dist)); } } - - void merge_result() { m_result.merge_and_cleanup(); } + + void merge_result() { /*m_result.merge_and_cleanup();*/ } }; bool SLASupportTree::generate(const std::vector &support_points, @@ -2457,9 +2459,9 @@ bool SLASupportTree::generate(const std::vector &support_points, const Controller &ctl) { if(support_points.empty()) return false; - + Algorithm alg(cfg, mesh, support_points, *m_impl, ctl.cancelfn); - + // Let's define the individual steps of the processing. We can experiment // later with the ordering and the dependencies between them. enum Steps { @@ -2477,41 +2479,41 @@ bool SLASupportTree::generate(const std::vector &support_points, NUM_STEPS //... }; - + // Collect the algorithm steps into a nice sequence std::array, NUM_STEPS> program = { [] () { // Begin... // Potentially clear up the shared data (not needed for now) }, - + std::bind(&Algorithm::filter, &alg), - + std::bind(&Algorithm::add_pinheads, &alg), - + std::bind(&Algorithm::classify, &alg), - + std::bind(&Algorithm::routing_to_ground, &alg), - + std::bind(&Algorithm::routing_to_model, &alg), - + std::bind(&Algorithm::interconnect_pillars, &alg), - + std::bind(&Algorithm::routing_headless, &alg), - + std::bind(&Algorithm::merge_result, &alg), - + [] () { // Done }, - + [] () { // Abort } }; - + Steps pc = BEGIN; - + if(cfg.ground_facing_only) { program[ROUTING_NONGROUND] = []() { BOOST_LOG_TRIVIAL(info) @@ -2522,7 +2524,7 @@ bool SLASupportTree::generate(const std::vector &support_points, " requested."; }; } - + // Let's define a simple automaton that will run our program. auto progress = [&ctl, &pc] () { static const std::array stepstr { @@ -2538,7 +2540,7 @@ bool SLASupportTree::generate(const std::vector &support_points, "Done", "Abort" }; - + static const std::array stepstate { 0, 10, @@ -2552,9 +2554,9 @@ bool SLASupportTree::generate(const std::vector &support_points, 100, 0 }; - + if(ctl.stopcondition()) pc = ABORT; - + switch(pc) { case BEGIN: pc = FILTER; break; case FILTER: pc = PINHEADS; break; @@ -2569,16 +2571,16 @@ bool SLASupportTree::generate(const std::vector &support_points, case ABORT: break; default: ; } - + ctl.statuscb(stepstate[pc], stepstr[pc]); }; - + // Just here we run the computation... while(pc < DONE) { progress(); program[pc](); } - + return pc == ABORT; } @@ -2588,7 +2590,7 @@ SLASupportTree::SLASupportTree(double gnd_lvl): m_impl(new Impl()) { const TriangleMesh &SLASupportTree::merged_mesh() const { - return get().merged_mesh(); + return m_impl->merged_mesh(); } void SLASupportTree::merged_mesh_with_pad(TriangleMesh &outmesh) const { @@ -2601,34 +2603,34 @@ std::vector SLASupportTree::slice( { const TriangleMesh &sup_mesh = m_impl->merged_mesh(); const TriangleMesh &pad_mesh = get_pad(); - + std::vector sup_slices; - if (!sup_mesh.empty()) { + if (!sup_mesh.empty()) { TriangleMeshSlicer sup_slicer(&sup_mesh); sup_slicer.slice(heights, cr, &sup_slices, m_impl->ctl().cancelfn); } - + auto bb = pad_mesh.bounding_box(); auto maxzit = std::upper_bound(heights.begin(), heights.end(), bb.max.z()); - + auto padgrid = reserve_vector(heights.end() - maxzit); std::copy(heights.begin(), maxzit, std::back_inserter(padgrid)); - + std::vector pad_slices; - if (!pad_mesh.empty()) { + if (!pad_mesh.empty()) { TriangleMeshSlicer pad_slicer(&pad_mesh); pad_slicer.slice(padgrid, cr, &pad_slices, m_impl->ctl().cancelfn); } - + size_t len = std::min(heights.size(), pad_slices.size()); len = std::min(len, sup_slices.size()); - + for (size_t i = 0; i < len; ++i) { std::copy(pad_slices[i].begin(), pad_slices[i].end(), std::back_inserter(sup_slices[i])); - pad_slices[i] = {}; + pad_slices[i] = {}; } - + return sup_slices; } diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp index d48b5bf739..95d4512710 100644 --- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp +++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp @@ -148,9 +148,9 @@ std::vector BoxIndex::query(const BoundingBox &qrbb, BoxIndex::QueryType qt) { namespace bgi = boost::geometry::index; - + std::vector ret; ret.reserve(m_impl->m_store.size()); - + switch (qt) { case qtIntersects: m_impl->m_store.query(bgi::intersects(qrbb), std::back_inserter(ret)); @@ -158,7 +158,7 @@ std::vector BoxIndex::query(const BoundingBox &qrbb, case qtWithin: m_impl->m_store.query(bgi::within(qrbb), std::back_inserter(ret)); } - + return ret; } @@ -198,9 +198,9 @@ EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) { F.resize(stl.stats.number_of_facets, 3); for (unsigned int i = 0; i < stl.stats.number_of_facets; ++i) { const stl_facet &facet = stl.facet_start[i]; - V.block<1, 3>(3 * i + 0, 0) = facet.vertex[0].cast(); - V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1].cast(); - V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2].cast(); + V.block<1, 3>(3 * i + 0, 0) = facet.vertex[0].cast(); + V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1].cast(); + V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2].cast(); F(i, 0) = int(3*i+0); F(i, 1) = int(3*i+1); F(i, 2) = int(3*i+2); @@ -306,6 +306,7 @@ PointSet normals(const PointSet& points, PointSet ret(range.size(), 3); +// for (size_t ridx = 0; ridx < range.size(); ++ridx) tbb::parallel_for(size_t(0), range.size(), [&ret, &range, &mesh, &points, thr, eps](size_t ridx) { diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 45f8a0c83a..fa85d497f9 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -16,6 +16,12 @@ // For geometry algorithms with native Clipper types (no copies and conversions) #include +#define SLAPRINT_DO_BENCHMARK + +#ifdef SLAPRINT_DO_BENCHMARK +#include +#endif + //#include //#include "tbb/mutex.h" #include "I18N.hpp" @@ -52,7 +58,7 @@ const std::array OBJ_STEP_LEVELS = }; // Object step to status label. The labels are localized at the time of calling, thus supporting language switching. -std::string OBJ_STEP_LABELS(size_t idx) +std::string OBJ_STEP_LABELS(size_t idx) { switch (idx) { case slaposObjectSlice: return L("Slicing model"); @@ -365,7 +371,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con // Synchronize Object's config. bool object_config_changed = model_object.config != model_object_new.config; if (object_config_changed) - static_cast(model_object.config) = static_cast(model_object_new.config); + static_cast(model_object.config) = static_cast(model_object_new.config); if (! object_diff.empty() || object_config_changed) { SLAPrintObjectConfig new_config = m_default_object_config; normalize_and_apply_config(new_config, model_object.config); @@ -424,10 +430,10 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con print_object->set_trafo(sla_trafo(*this, model_object), model_object.instances.front()->is_left_handed()); print_object->set_instances(std::move(new_instances)); - - SLAPrintObjectConfig new_config = m_default_object_config; - normalize_and_apply_config(new_config, model_object.config); - print_object->config_apply(new_config, true); + + SLAPrintObjectConfig new_config = m_default_object_config; + normalize_and_apply_config(new_config, model_object.config); + print_object->config_apply(new_config, true); print_objects_new.emplace_back(print_object); new_objects = true; } @@ -446,7 +452,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con if (new_objects) update_apply_status(false); } - + if(m_objects.empty()) { m_printer.release(); m_printer_input.clear(); @@ -596,16 +602,16 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { scfg.pillar_base_safety_distance_mm = c.support_base_safety_distance.getFloat() < EPSILON ? scfg.safety_distance_mm : c.support_base_safety_distance.getFloat(); - + return scfg; } sla::PoolConfig::EmbedObject builtin_pad_cfg(const SLAPrintObjectConfig& c) { sla::PoolConfig::EmbedObject ret; - + ret.enabled = c.support_object_elevation.getFloat() <= EPSILON && c.pad_enable.getBool() && c.supports_enable.getBool(); - + if(ret.enabled) { ret.object_gap_mm = c.pad_object_gap.getFloat(); ret.stick_width_mm = c.pad_object_connector_width.getFloat(); @@ -613,7 +619,7 @@ sla::PoolConfig::EmbedObject builtin_pad_cfg(const SLAPrintObjectConfig& c) { ret.stick_penetration_mm = c.pad_object_connector_penetration .getFloat(); } - + return ret; } @@ -622,16 +628,16 @@ sla::PoolConfig make_pool_config(const SLAPrintObjectConfig& c) { pcfg.min_wall_thickness_mm = c.pad_wall_thickness.getFloat(); pcfg.wall_slope = c.pad_wall_slope.getFloat() * PI / 180.0; - + // We do not support radius for now pcfg.edge_radius_mm = 0.0; //c.pad_edge_radius.getFloat(); - + pcfg.max_merge_distance_mm = c.pad_max_merge_distance.getFloat(); pcfg.min_wall_height_mm = c.pad_wall_height.getFloat(); // set builtin pad implicitly ON pcfg.embed_object = builtin_pad_cfg(c); - + return pcfg; } @@ -657,12 +663,12 @@ std::string SLAPrint::validate() const cfg.head_width_mm + 2 * cfg.head_back_radius_mm - cfg.head_penetration_mm; - + double elv = cfg.object_elevation_mm; if(supports_en && elv > EPSILON && elv < pinhead_width ) return L("Elevation is too low for object."); - + sla::PoolConfig::EmbedObject builtinpad = builtin_pad_cfg(po->config()); if(supports_en && builtinpad.enabled && cfg.pillar_base_safety_distance_mm < builtinpad.object_gap_mm) { @@ -740,15 +746,15 @@ void SLAPrint::process() coord_t maxZs = scaled(maxZ); po.m_slice_index.clear(); - + size_t cap = size_t(1 + (maxZs - minZs - ilhs) / lhs); po.m_slice_index.reserve(cap); - + po.m_slice_index.emplace_back(minZs + ilhs, minZf + ilh / 2.f, ilh); for(coord_t h = minZs + ilhs + lhs; h <= maxZs; h += lhs) po.m_slice_index.emplace_back(h, unscaled(h) - lh / 2.f, lh); - + // Just get the first record that is form the model: auto slindex_it = po.closest_slice_record(po.m_slice_index, float(bb3d.min(Z))); @@ -781,9 +787,9 @@ void SLAPrint::process() { // We apply the printer correction offset here. if(clpr_offs != 0) - po.m_model_slices[id] = + po.m_model_slices[id] = offset_ex(po.m_model_slices[id], float(clpr_offs)); - + mit->set_model_slice_idx(po, id); ++mit; } @@ -876,7 +882,7 @@ void SLAPrint::process() // removed them on purpose. No calculation will be done. po.m_supportdata->support_points = po.transformed_support_points(); } - + // If the zero elevation mode is engaged, we have to filter out all the // points that are on the bottom of the object if (po.config().support_object_elevation.getFloat() <= EPSILON) { @@ -894,7 +900,7 @@ void SLAPrint::process() double diff = std::abs(gnd - double(sp.pos(Z))); return diff <= tolerance; }); - + // erase all elements after the new end pts.erase(endit, pts.end()); } @@ -904,7 +910,7 @@ void SLAPrint::process() auto support_tree = [this, ostepd](SLAPrintObject& po) { if(!po.m_supportdata) return; - + sla::PoolConfig pcfg = make_pool_config(po.m_config); if (pcfg.embed_object) @@ -912,11 +918,11 @@ void SLAPrint::process() pcfg.min_wall_thickness_mm); if(!po.m_config.supports_enable.getBool()) { - + // Generate empty support tree. It can still host a pad po.m_supportdata->support_tree_ptr.reset( new SLASupportTree(po.m_supportdata->emesh.ground_level())); - + return; } @@ -940,7 +946,7 @@ void SLAPrint::process() ctl.stopcondition = [this](){ return canceled(); }; ctl.cancelfn = [this]() { throw_if_canceled(); }; - + po.m_supportdata->support_tree_ptr.reset( new SLASupportTree(po.m_supportdata->support_points, po.m_supportdata->emesh, scfg, ctl)); @@ -948,20 +954,20 @@ void SLAPrint::process() throw_if_canceled(); // Create the unified mesh - auto rc = SlicingStatus::RELOAD_SCENE; + // auto rc = SlicingStatus::RELOAD_SCENE; // This is to prevent "Done." being displayed during merged_mesh() - m_report_status(*this, -1, L("Visualizing supports")); - po.m_supportdata->support_tree_ptr->merged_mesh(); + // m_report_status(*this, -1, L("Visualizing supports")); + // po.m_supportdata->support_tree_ptr->merged_mesh(); BOOST_LOG_TRIVIAL(debug) << "Processed support point count " << po.m_supportdata->support_points.size(); // Check the mesh for later troubleshooting. - if(po.support_mesh().empty()) - BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty"; +// if(po.support_mesh().empty()) +// BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty"; - m_report_status(*this, -1, L("Visualizing supports"), rc); +// m_report_status(*this, -1, L("Visualizing supports"), rc); }; // This step generates the sla base pad @@ -970,6 +976,10 @@ void SLAPrint::process() // and before the supports had been sliced. (or the slicing has to be // repeated) + std::cout << "Should only merge mesh after this" << std::endl; + po.m_supportdata->support_tree_ptr->merged_mesh(); + m_report_status(*this, -1, L("Visualizing supports"), SlicingStatus::RELOAD_SCENE); + if(po.m_config.pad_enable.getBool()) { // Get the distilled pad configuration from the config @@ -1040,7 +1050,7 @@ void SLAPrint::process() if(clpr_offs != 0) sd->support_slices[i] = offset_ex(sd->support_slices[i], float(clpr_offs)); - + po.m_slice_index[i].set_support_slice_idx(po, i); } @@ -1268,7 +1278,7 @@ void SLAPrint::process() const SLAPrintObject *po = record.print_obj(); const ExPolygons &modelslices = record.get_slice(soModel); - + bool is_lefth = record.print_obj()->is_left_handed(); if (!modelslices.empty()) { ClipperPolygons v = get_all_polygons(modelslices, po->instances(), is_lefth); @@ -1276,7 +1286,7 @@ void SLAPrint::process() } const ExPolygons &supportslices = record.get_slice(soSupport); - + if (!supportslices.empty()) { ClipperPolygons v = get_all_polygons(supportslices, po->instances(), is_lefth); for(ClipperPolygon& p_tmp : v) supports_polygons.emplace_back(std::move(p_tmp)); @@ -1369,8 +1379,8 @@ void SLAPrint::process() { // create a raster printer for the current print parameters double layerh = m_default_object_config.layer_height.getFloat(); - m_printer.reset(new SLAPrinter(m_printer_config, - m_material_config, + m_printer.reset(new SLAPrinter(m_printer_config, + m_material_config, layerh)); } @@ -1429,7 +1439,7 @@ void SLAPrint::process() if(canceled()) return; // Sequential version (for testing) - // for(unsigned l = 0; l < lvlcnt; ++l) process_level(l); + // for(unsigned l = 0; l < lvlcnt; ++l) lvlfn(l); // Print all the layers in parallel tbb::parallel_for(0, lvlcnt, lvlfn); @@ -1446,44 +1456,48 @@ void SLAPrint::process() using slaposFn = std::function; using slapsFn = std::function; - std::array pobj_program = + slaposFn pobj_program[] = { - slice_model, - support_points, - support_tree, - base_pool, - slice_supports + slice_model, support_points, support_tree, base_pool, slice_supports }; - std::array print_program = - { - merge_slices_and_eval_stats, - rasterize + // We want to first process all objects... + std::vector level1_obj_steps = { + slaposObjectSlice, slaposSupportPoints, slaposSupportTree, slaposBasePool }; + // and then slice all supports to allow preview to be displayed ASAP + std::vector level2_obj_steps = { + slaposSliceSupports + }; + + slapsFn print_program[] = { merge_slices_and_eval_stats, rasterize }; + SLAPrintStep print_steps[] = { slapsMergeSlicesAndEval, slapsRasterize }; + double st = min_objstatus; - unsigned incr = 0; BOOST_LOG_TRIVIAL(info) << "Start slicing process."; - // TODO: this loop could run in parallel but should not exhaust all the CPU - // power available - // Calculate the support structures first before slicing the supports, - // so that the preview will get displayed ASAP for all objects. - std::vector step_ranges = {slaposObjectSlice, - slaposSliceSupports, - slaposCount}; +#ifdef SLAPRINT_DO_BENCHMARK + Benchmark bench; +#else + struct { + void start() {} void stop() {} double getElapsedSec() { return .0; } + } bench; +#endif - for (size_t idx_range = 0; idx_range + 1 < step_ranges.size(); ++idx_range) { + std::array step_times {}; + + auto apply_steps_on_objects = + [this, &st, ostepd, &pobj_program, &step_times, &bench] + (const std::vector &steps) + { + unsigned incr = 0; for (SLAPrintObject *po : m_objects) { - BOOST_LOG_TRIVIAL(info) - << "Slicing object " << po->model_object()->name; + for (SLAPrintObjectStep currentstep : steps) { - for (int s = int(step_ranges[idx_range]); - s < int(step_ranges[idx_range + 1]); - ++s) { - auto currentstep = static_cast(s); + Benchmark bench; // Cancellation checking. Each step will check for // cancellation on its own and return earlier gracefully. @@ -1493,12 +1507,12 @@ void SLAPrint::process() st += incr * ostepd; - if (po->m_stepmask[currentstep] - && po->set_started(currentstep)) { - m_report_status(*this, - st, - OBJ_STEP_LABELS(currentstep)); + if (po->m_stepmask[currentstep] && po->set_started(currentstep)) { + m_report_status(*this, st, OBJ_STEP_LABELS(currentstep)); + bench.start(); pobj_program[currentstep](*po); + bench.stop(); + step_times[currentstep] += bench.getElapsedSec(); throw_if_canceled(); po->set_done(currentstep); } @@ -1506,26 +1520,27 @@ void SLAPrint::process() incr = OBJ_STEP_LEVELS[currentstep]; } } - } - - std::array printsteps = { - slapsMergeSlicesAndEval, slapsRasterize }; + apply_steps_on_objects(level1_obj_steps); + apply_steps_on_objects(level2_obj_steps); + + SLAPrintStep printsteps[] = { slapsMergeSlicesAndEval, slapsRasterize }; + // this would disable the rasterization step - // m_stepmask[slapsRasterize] = false; + // std::fill(m_stepmask.begin(), m_stepmask.end(), false); double pstd = (100 - max_objstatus) / 100.0; st = max_objstatus; - for(size_t s = 0; s < print_program.size(); ++s) { - auto currentstep = printsteps[s]; - + for(SLAPrintStep currentstep : printsteps) { throw_if_canceled(); - if(m_stepmask[currentstep] && set_started(currentstep)) - { + if (m_stepmask[currentstep] && set_started(currentstep)) { m_report_status(*this, st, PRINT_STEP_LABELS(currentstep)); + bench.start(); print_program[currentstep](); + bench.stop(); + step_times[slaposCount + currentstep] += bench.getElapsedSec(); throw_if_canceled(); set_done(currentstep); } @@ -1535,6 +1550,21 @@ void SLAPrint::process() // If everything vent well m_report_status(*this, 100, L("Slicing done")); + +#ifdef SLAPRINT_DO_BENCHMARK + std::string csvbenchstr; + for (size_t i = 0; i < size_t(slaposCount); ++i) + csvbenchstr += OBJ_STEP_LABELS(i) + ";"; + + for (size_t i = 0; i < size_t(slapsCount); ++i) + csvbenchstr += PRINT_STEP_LABELS(i) + ";"; + + csvbenchstr += "\n"; + for (double t : step_times) csvbenchstr += std::to_string(t) + ";"; + + std::cout << "Performance stats: \n" << csvbenchstr << std::endl; +#endif + } bool SLAPrint::invalidate_state_by_config_options(const std::vector &opt_keys, bool &invalidate_all_model_objects) @@ -1756,7 +1786,7 @@ Vec3d SLAPrint::relative_correction() const corr(X) = printer_config().relative_correction.values[0]; corr(Y) = printer_config().relative_correction.values[0]; corr(Z) = printer_config().relative_correction.values.back(); - } + } if(material_config().material_correction.values.size() >= 2) { corr(X) *= material_config().material_correction.values[0]; @@ -1925,7 +1955,7 @@ void SLAPrint::StatusReporter::operator()(SLAPrint & p, BOOST_LOG_TRIVIAL(info) << st << "% " << msg << (logmsg.empty() ? "" : ": ") << logmsg << log_memory_info(); - + p.set_status(int(std::round(st)), msg, flags); } diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 2a8d8fccf5..aef0896346 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -11,13 +11,14 @@ #include #include #include +#include #include #include #include namespace Slic3r { - enum class ModelVolumeType : int; + enum class ModelVolumeType : int; }; typedef double coordf_t; @@ -36,11 +37,11 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const std::function cb, const std::string& icon = "", wxEvtHandler* event_handler = nullptr, std::function const cb_condition = []() { return true; }, wxWindow* parent = nullptr); -wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description, +wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description, const std::string& icon = "", std::function const cb_condition = []() { return true; }, wxWindow* parent = nullptr); -wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description, +wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description, std::function cb, wxEvtHandler* event_handler); class wxDialog; @@ -48,7 +49,7 @@ void edit_tooltip(wxString& tooltip); void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector& btn_ids); int em_unit(wxWindow* win); -wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name, +wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name, const int px_cnt = 16, const bool is_horizontal = false, const bool grayscale = false); class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup @@ -92,23 +93,23 @@ public: class wxDataViewTreeCtrlComboPopup: public wxDataViewTreeCtrl, public wxComboPopup { - static const unsigned int DefaultWidth; - static const unsigned int DefaultHeight; - static const unsigned int DefaultItemHeight; + static const unsigned int DefaultWidth; + static const unsigned int DefaultHeight; + static const unsigned int DefaultItemHeight; - wxString m_text; - int m_cnt_open_items{0}; + wxString m_text; + int m_cnt_open_items{0}; public: - virtual bool Create(wxWindow* parent); - virtual wxWindow* GetControl() { return this; } - virtual void SetStringValue(const wxString& value) { m_text = value; } - virtual wxString GetStringValue() const { return m_text; } + virtual bool Create(wxWindow* parent); + virtual wxWindow* GetControl() { return this; } + virtual void SetStringValue(const wxString& value) { m_text = value; } + virtual wxString GetStringValue() const { return m_text; } // virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight); - virtual void OnKeyEvent(wxKeyEvent& evt); - void OnDataViewTreeCtrlSelection(wxCommandEvent& evt); - void SetItemsCnt(int cnt) { m_cnt_open_items = cnt; } + virtual void OnKeyEvent(wxKeyEvent& evt); + void OnDataViewTreeCtrlSelection(wxCommandEvent& evt); + void SetItemsCnt(int cnt) { m_cnt_open_items = cnt; } }; @@ -121,7 +122,7 @@ class DataViewBitmapText : public wxObject public: DataViewBitmapText( const wxString &text = wxEmptyString, const wxBitmap& bmp = wxNullBitmap) : - m_text(text), + m_text(text), m_bmp(bmp) { } @@ -177,8 +178,8 @@ WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray); class ObjectDataViewModelNode { - ObjectDataViewModelNode* m_parent; - MyObjectTreeModelNodePtrArray m_children; + ObjectDataViewModelNode* m_parent; + MyObjectTreeModelNodePtrArray m_children; wxBitmap m_empty_bmp; size_t m_volumes_cnt = 0; std::vector< std::string > m_opt_categories; @@ -196,7 +197,7 @@ class ObjectDataViewModelNode Slic3r::ModelVolumeType m_volume_type; public: - ObjectDataViewModelNode(const wxString &name, + ObjectDataViewModelNode(const wxString &name, const wxString& extruder): m_parent(NULL), m_name(name), @@ -211,20 +212,20 @@ public: #endif //__WXGTK__ set_action_icon(); - } + } - ObjectDataViewModelNode(ObjectDataViewModelNode* parent, - const wxString& sub_obj_name, - const wxBitmap& bmp, - const wxString& extruder, + ObjectDataViewModelNode(ObjectDataViewModelNode* parent, + const wxString& sub_obj_name, + const wxBitmap& bmp, + const wxString& extruder, const int idx = -1 ) : m_parent (parent), - m_name (sub_obj_name), - m_type (itVolume), + m_name (sub_obj_name), + m_type (itVolume), m_idx (idx), m_extruder (extruder) { - m_bmp = bmp; + m_bmp = bmp; #ifdef __WXGTK__ // it's necessary on GTK because of control have to know if this item will be container // in another case you couldn't to add subitem for this item @@ -235,125 +236,125 @@ public: set_action_icon(); } - ObjectDataViewModelNode(ObjectDataViewModelNode* parent, - const t_layer_height_range& layer_range, + ObjectDataViewModelNode(ObjectDataViewModelNode* parent, + const t_layer_height_range& layer_range, const int idx = -1, const wxString& extruder = wxEmptyString ); ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type); - ~ObjectDataViewModelNode() - { - // free all our children nodes - size_t count = m_children.GetCount(); - for (size_t i = 0; i < count; i++) - { - ObjectDataViewModelNode *child = m_children[i]; - delete child; - } + ~ObjectDataViewModelNode() + { + // free all our children nodes + size_t count = m_children.GetCount(); + for (size_t i = 0; i < count; i++) + { + ObjectDataViewModelNode *child = m_children[i]; + delete child; + } #ifndef NDEBUG - // Indicate that the object was deleted. - m_idx = -2; + // Indicate that the object was deleted. + m_idx = -2; #endif /* NDEBUG */ - } + } - bool IsContainer() const - { - return m_container; - } + bool IsContainer() const + { + return m_container; + } - ObjectDataViewModelNode* GetParent() - { - assert(m_parent == nullptr || m_parent->valid()); - return m_parent; - } - MyObjectTreeModelNodePtrArray& GetChildren() - { - return m_children; - } - ObjectDataViewModelNode* GetNthChild(unsigned int n) - { - return m_children.Item(n); - } - void Insert(ObjectDataViewModelNode* child, unsigned int n) - { - if (!m_container) - m_container = true; - m_children.Insert(child, n); - } - void Append(ObjectDataViewModelNode* child) - { - if (!m_container) - m_container = true; - m_children.Add(child); - } - void RemoveAllChildren() - { - if (GetChildCount() == 0) - return; - for (int id = int(GetChildCount()) - 1; id >= 0; --id) - { - if (m_children.Item(id)->GetChildCount() > 0) - m_children[id]->RemoveAllChildren(); - auto node = m_children[id]; - m_children.RemoveAt(id); - delete node; - } - } + ObjectDataViewModelNode* GetParent() + { + assert(m_parent == nullptr || m_parent->valid()); + return m_parent; + } + MyObjectTreeModelNodePtrArray& GetChildren() + { + return m_children; + } + ObjectDataViewModelNode* GetNthChild(unsigned int n) + { + return m_children.Item(n); + } + void Insert(ObjectDataViewModelNode* child, unsigned int n) + { + if (!m_container) + m_container = true; + m_children.Insert(child, n); + } + void Append(ObjectDataViewModelNode* child) + { + if (!m_container) + m_container = true; + m_children.Add(child); + } + void RemoveAllChildren() + { + if (GetChildCount() == 0) + return; + for (int id = int(GetChildCount()) - 1; id >= 0; --id) + { + if (m_children.Item(id)->GetChildCount() > 0) + m_children[id]->RemoveAllChildren(); + auto node = m_children[id]; + m_children.RemoveAt(id); + delete node; + } + } - size_t GetChildCount() const - { - return m_children.GetCount(); - } + size_t GetChildCount() const + { + return m_children.GetCount(); + } - bool SetValue(const wxVariant &variant, unsigned int col); + bool SetValue(const wxVariant &variant, unsigned int col); - void SetBitmap(const wxBitmap &icon) { m_bmp = icon; } + void SetBitmap(const wxBitmap &icon) { m_bmp = icon; } const wxBitmap& GetBitmap() const { return m_bmp; } const wxString& GetName() const { return m_name; } ItemType GetType() const { return m_type; } - void SetIdx(const int& idx); - int GetIdx() const { return m_idx; } - t_layer_height_range GetLayerRange() const { return m_layer_range; } + void SetIdx(const int& idx); + int GetIdx() const { return m_idx; } + t_layer_height_range GetLayerRange() const { return m_layer_range; } - // use this function only for childrens - void AssignAllVal(ObjectDataViewModelNode& from_node) - { - // ! Don't overwrite other values because of equality of this values for all children -- - m_name = from_node.m_name; + // use this function only for childrens + void AssignAllVal(ObjectDataViewModelNode& from_node) + { + // ! Don't overwrite other values because of equality of this values for all children -- + m_name = from_node.m_name; m_bmp = from_node.m_bmp; m_idx = from_node.m_idx; m_extruder = from_node.m_extruder; m_type = from_node.m_type; - } + } - bool SwapChildrens(int frst_id, int scnd_id) { - if (GetChildCount() < 2 || - frst_id < 0 || (size_t)frst_id >= GetChildCount() || - scnd_id < 0 || (size_t)scnd_id >= GetChildCount()) - return false; + bool SwapChildrens(int frst_id, int scnd_id) { + if (GetChildCount() < 2 || + frst_id < 0 || (size_t)frst_id >= GetChildCount() || + scnd_id < 0 || (size_t)scnd_id >= GetChildCount()) + return false; - ObjectDataViewModelNode new_scnd = *GetNthChild(frst_id); - ObjectDataViewModelNode new_frst = *GetNthChild(scnd_id); + ObjectDataViewModelNode new_scnd = *GetNthChild(frst_id); + ObjectDataViewModelNode new_frst = *GetNthChild(scnd_id); new_scnd.m_idx = m_children.Item(scnd_id)->m_idx; new_frst.m_idx = m_children.Item(frst_id)->m_idx; - m_children.Item(frst_id)->AssignAllVal(new_frst); - m_children.Item(scnd_id)->AssignAllVal(new_scnd); - return true; - } + m_children.Item(frst_id)->AssignAllVal(new_frst); + m_children.Item(scnd_id)->AssignAllVal(new_scnd); + return true; + } - // Set action icons for node + // Set action icons for node void set_action_icon(); void update_settings_digest_bitmaps(); - bool update_settings_digest(const std::vector& categories); + bool update_settings_digest(const std::vector& categories); int volume_type() const { return int(m_volume_type); } void msw_rescale(); #ifndef NDEBUG - bool valid(); + bool valid(); #endif /* NDEBUG */ private: @@ -369,7 +370,7 @@ wxDECLARE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent); class ObjectDataViewModel :public wxDataViewModel { - std::vector m_objects; + std::vector m_objects; std::vector m_volume_bmps; wxBitmap* m_warning_bmp; @@ -379,7 +380,7 @@ public: ObjectDataViewModel(); ~ObjectDataViewModel(); - wxDataViewItem Add( const wxString &name, + wxDataViewItem Add( const wxString &name, const int extruder, const bool has_errors = false); wxDataViewItem AddVolumeChild( const wxDataViewItem &parent_item, @@ -391,24 +392,24 @@ public: wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num); wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item); - wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item, + wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item, const t_layer_height_range& layer_range, - const int extruder = 0, + const int extruder = 0, const int index = -1); - wxDataViewItem Delete(const wxDataViewItem &item); - wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num); - void DeleteAll(); + wxDataViewItem Delete(const wxDataViewItem &item); + wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num); + void DeleteAll(); void DeleteChildren(wxDataViewItem& parent); void DeleteVolumeChildren(wxDataViewItem& parent); void DeleteSettings(const wxDataViewItem& parent); - wxDataViewItem GetItemById(int obj_idx); + wxDataViewItem GetItemById(int obj_idx); wxDataViewItem GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type); - wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx); - wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx); + wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx); + wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx); wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx); wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range); int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range); - int GetIdByItem(const wxDataViewItem& item) const; + int GetIdByItem(const wxDataViewItem& item) const; int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const; int GetObjectIdByItem(const wxDataViewItem& item) const; int GetVolumeIdByItem(const wxDataViewItem& item) const; @@ -418,53 +419,53 @@ public: int GetRowByItem(const wxDataViewItem& item) const; bool IsEmpty() { return m_objects.empty(); } - // helper method for wxLog + // helper method for wxLog - wxString GetName(const wxDataViewItem &item) const; + wxString GetName(const wxDataViewItem &item) const; wxBitmap& GetBitmap(const wxDataViewItem &item) const; - // helper methods to change the model + // helper methods to change the model - virtual unsigned int GetColumnCount() const override { return 3;} - virtual wxString GetColumnType(unsigned int col) const override{ return wxT("string"); } + virtual unsigned int GetColumnCount() const override { return 3;} + virtual wxString GetColumnType(unsigned int col) const override{ return wxT("string"); } - virtual void GetValue( wxVariant &variant, - const wxDataViewItem &item, + virtual void GetValue( wxVariant &variant, + const wxDataViewItem &item, unsigned int col) const override; - virtual bool SetValue( const wxVariant &variant, - const wxDataViewItem &item, + virtual bool SetValue( const wxVariant &variant, + const wxDataViewItem &item, unsigned int col) override; - bool SetValue( const wxVariant &variant, - const int item_idx, + bool SetValue( const wxVariant &variant, + const int item_idx, unsigned int col); - // For parent move child from cur_volume_id place to new_volume_id + // For parent move child from cur_volume_id place to new_volume_id // Remaining items will moved up/down accordingly - wxDataViewItem ReorganizeChildren( const int cur_volume_id, + wxDataViewItem ReorganizeChildren( const int cur_volume_id, const int new_volume_id, const wxDataViewItem &parent); - virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override; + virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override; - virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override; + virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override; // get object item wxDataViewItem GetTopParent(const wxDataViewItem &item) const; - virtual bool IsContainer(const wxDataViewItem &item) const override; - virtual unsigned int GetChildren(const wxDataViewItem &parent, - wxDataViewItemArray &array) const override; + virtual bool IsContainer(const wxDataViewItem &item) const override; + virtual unsigned int GetChildren(const wxDataViewItem &parent, + wxDataViewItemArray &array) const override; void GetAllChildren(const wxDataViewItem &parent,wxDataViewItemArray &array) const; - // Is the container just a header or an item with all columns - // In our case it is an item with all columns - virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; } + // Is the container just a header or an item with all columns + // In our case it is an item with all columns + virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; } ItemType GetItemType(const wxDataViewItem &item) const ; - wxDataViewItem GetItemByType( const wxDataViewItem &parent_item, + wxDataViewItem GetItemByType( const wxDataViewItem &parent_item, ItemType type) const; wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const; wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const; wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const; bool IsSettingsItem(const wxDataViewItem &item) const; - void UpdateSettingsDigest( const wxDataViewItem &item, + void UpdateSettingsDigest( const wxDataViewItem &item, const std::vector& categories); void SetVolumeBitmaps(const std::vector& volume_bmps) { m_volume_bmps = volume_bmps; } @@ -475,7 +476,7 @@ public: // Rescale bitmaps for existing Items void Rescale(); - wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, + wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, const bool is_marked = false); void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false); t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const; @@ -520,12 +521,12 @@ public: return false; #else return true; -#endif +#endif } - wxWindow* CreateEditorCtrl(wxWindow* parent, - wxRect labelRect, + wxWindow* CreateEditorCtrl(wxWindow* parent, + wxRect labelRect, const wxVariant& value) override; - bool GetValueFromEditorCtrl( wxWindow* ctrl, + bool GetValueFromEditorCtrl( wxWindow* ctrl, wxVariant& value) override; bool WasCanceled() const { return m_was_unusable_symbol; } @@ -542,88 +543,88 @@ private: class MyCustomRenderer : public wxDataViewCustomRenderer { public: - // This renderer can be either activatable or editable, for demonstration - // purposes. In real programs, you should select whether the user should be - // able to activate or edit the cell and it doesn't make sense to switch - // between the two -- but this is just an example, so it doesn't stop us. - explicit MyCustomRenderer(wxDataViewCellMode mode) - : wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER) - { } + // This renderer can be either activatable or editable, for demonstration + // purposes. In real programs, you should select whether the user should be + // able to activate or edit the cell and it doesn't make sense to switch + // between the two -- but this is just an example, so it doesn't stop us. + explicit MyCustomRenderer(wxDataViewCellMode mode) + : wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER) + { } - virtual bool Render(wxRect rect, wxDC *dc, int state) override/*wxOVERRIDE*/ - { - dc->SetBrush(*wxLIGHT_GREY_BRUSH); - dc->SetPen(*wxTRANSPARENT_PEN); + virtual bool Render(wxRect rect, wxDC *dc, int state) override/*wxOVERRIDE*/ + { + dc->SetBrush(*wxLIGHT_GREY_BRUSH); + dc->SetPen(*wxTRANSPARENT_PEN); - rect.Deflate(2); - dc->DrawRoundedRectangle(rect, 5); + rect.Deflate(2); + dc->DrawRoundedRectangle(rect, 5); - RenderText(m_value, - 0, // no offset - wxRect(dc->GetTextExtent(m_value)).CentreIn(rect), - dc, - state); - return true; - } + RenderText(m_value, + 0, // no offset + wxRect(dc->GetTextExtent(m_value)).CentreIn(rect), + dc, + state); + return true; + } - virtual bool ActivateCell(const wxRect& WXUNUSED(cell), - wxDataViewModel *WXUNUSED(model), - const wxDataViewItem &WXUNUSED(item), - unsigned int WXUNUSED(col), - const wxMouseEvent *mouseEvent) override/*wxOVERRIDE*/ - { - wxString position; - if (mouseEvent) - position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y); - else - position = "from keyboard"; + virtual bool ActivateCell(const wxRect& WXUNUSED(cell), + wxDataViewModel *WXUNUSED(model), + const wxDataViewItem &WXUNUSED(item), + unsigned int WXUNUSED(col), + const wxMouseEvent *mouseEvent) override/*wxOVERRIDE*/ + { + wxString position; + if (mouseEvent) + position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y); + else + position = "from keyboard"; // wxLogMessage("MyCustomRenderer ActivateCell() %s", position); - return false; - } + return false; + } - virtual wxSize GetSize() const override/*wxOVERRIDE*/ - { - return wxSize(60, 20); - } + virtual wxSize GetSize() const override/*wxOVERRIDE*/ + { + return wxSize(60, 20); + } - virtual bool SetValue(const wxVariant &value) override/*wxOVERRIDE*/ - { - m_value = value.GetString(); - return true; - } + virtual bool SetValue(const wxVariant &value) override/*wxOVERRIDE*/ + { + m_value = value.GetString(); + return true; + } - virtual bool GetValue(wxVariant &WXUNUSED(value)) const override/*wxOVERRIDE*/{ return true; } + virtual bool GetValue(wxVariant &WXUNUSED(value)) const override/*wxOVERRIDE*/{ return true; } - virtual bool HasEditorCtrl() const override/*wxOVERRIDE*/{ return true; } + virtual bool HasEditorCtrl() const override/*wxOVERRIDE*/{ return true; } - virtual wxWindow* - CreateEditorCtrl(wxWindow* parent, - wxRect labelRect, - const wxVariant& value) override/*wxOVERRIDE*/ - { - wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value, - labelRect.GetPosition(), - labelRect.GetSize(), - wxTE_PROCESS_ENTER); - text->SetInsertionPointEnd(); + virtual wxWindow* + CreateEditorCtrl(wxWindow* parent, + wxRect labelRect, + const wxVariant& value) override/*wxOVERRIDE*/ + { + wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value, + labelRect.GetPosition(), + labelRect.GetSize(), + wxTE_PROCESS_ENTER); + text->SetInsertionPointEnd(); - return text; - } + return text; + } - virtual bool - GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) override/*wxOVERRIDE*/ - { - wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl); - if (!text) - return false; + virtual bool + GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) override/*wxOVERRIDE*/ + { + wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl); + if (!text) + return false; - value = text->GetValue(); + value = text->GetValue(); - return true; - } + return true; + } private: - wxString m_value; + wxString m_value; }; @@ -635,7 +636,7 @@ class ScalableBitmap { public: ScalableBitmap() {}; - ScalableBitmap( wxWindow *parent, + ScalableBitmap( wxWindow *parent, const std::string& icon_name = "", const int px_cnt = 16, const bool is_horizontal = false); @@ -681,9 +682,9 @@ public: DoubleSlider( wxWindow *parent, wxWindowID id, - int lowerValue, - int higherValue, - int minValue, + int lowerValue, + int higherValue, + int minValue, int maxValue, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, @@ -726,8 +727,8 @@ public: EnableTickManipulation(false); } - bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; } - bool is_one_layer() const { return m_is_one_layer; } + bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; } + bool is_one_layer() const { return m_is_one_layer; } bool is_lower_at_min() const { return m_lower_value == m_min_value; } bool is_higher_at_max() const { return m_higher_value == m_max_value; } bool is_full_span() const { return this->is_lower_at_min() && this->is_higher_at_max(); } @@ -746,7 +747,7 @@ public: void OnRightUp(wxMouseEvent& event); protected: - + void render(); void draw_focus_rect(); void draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_end); diff --git a/src/slic3r/Utils/Time.hpp b/src/slic3r/Utils/Time.hpp index 7b670bd3ee..6a1aefa188 100644 --- a/src/slic3r/Utils/Time.hpp +++ b/src/slic3r/Utils/Time.hpp @@ -2,7 +2,7 @@ #define slic3r_Utils_Time_hpp_ #include -#include +#include namespace Slic3r { namespace Utils { From c187a5fb695b59402ccbbb24eb17266226236b67 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 16 Aug 2019 16:31:05 +0200 Subject: [PATCH 10/48] Fix up build and clear dev output --- src/libslic3r/GCode/ToolOrdering.cpp | 37 +++++++------------------- src/libslic3r/SLA/SLASupportTree.cpp | 4 +-- src/libslic3r/SLAPrint.cpp | 39 +++++++++++----------------- 3 files changed, 26 insertions(+), 54 deletions(-) diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index f10b45723a..2d7b90442b 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -96,23 +96,6 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool this->collect_extruder_statistics(prime_multi_material); } - -LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) -{ - auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), LayerTools(print_z - EPSILON)); - assert(it_layer_tools != m_layer_tools.end()); - coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z); - for (++ it_layer_tools; it_layer_tools != m_layer_tools.end(); ++it_layer_tools) { - coordf_t d = std::abs(it_layer_tools->print_z - print_z); - if (d >= dist_min) - break; - dist_min = d; - } - -- it_layer_tools; - assert(dist_min < EPSILON); - return *it_layer_tools; -} - void ToolOrdering::initialize_layers(std::vector &zs) { sort_remove_duplicates(zs); @@ -151,7 +134,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object) LayerTools &layer_tools = this->tools_for_layer(layer->print_z); // What extruders are required to print this object layer? for (size_t region_id = 0; region_id < object.region_volumes.size(); ++ region_id) { - const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr; + const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr; if (layerm == nullptr) continue; const PrintRegion ®ion = *object.print()->regions()[region_id]; @@ -320,20 +303,20 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_ LayerTools lt_new(0.5f * (lt.print_z + lt_object.print_z)); // Find the 1st layer above lt_new. for (j = i + 1; j < m_layer_tools.size() && m_layer_tools[j].print_z < lt_new.print_z - EPSILON; ++ j); - if (std::abs(m_layer_tools[j].print_z - lt_new.print_z) < EPSILON) { - m_layer_tools[j].has_wipe_tower = true; - } else { - LayerTools <_extra = *m_layer_tools.insert(m_layer_tools.begin() + j, lt_new); + if (std::abs(m_layer_tools[j].print_z - lt_new.print_z) < EPSILON) { + m_layer_tools[j].has_wipe_tower = true; + } else { + LayerTools <_extra = *m_layer_tools.insert(m_layer_tools.begin() + j, lt_new); LayerTools <_next = m_layer_tools[j + 1]; assert(! m_layer_tools[j - 1].extruders.empty() && ! lt_next.extruders.empty()); // FIXME: Following assert tripped when running combine_infill.t. I decided to comment it out for now. // If it is a bug, it's likely not critical, because this code is unchanged for a long time. It might // still be worth looking into it more and decide if it is a bug or an obsolete assert. //assert(lt_prev.extruders.back() == lt_next.extruders.front()); - lt_extra.has_wipe_tower = true; + lt_extra.has_wipe_tower = true; lt_extra.extruders.push_back(lt_next.extruders.front()); - lt_extra.wipe_tower_partitions = lt_next.wipe_tower_partitions; - } + lt_extra.wipe_tower_partitions = lt_next.wipe_tower_partitions; + } } } break; @@ -375,7 +358,7 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material) // Reorder m_all_printing_extruders in the sequence they will be primed, the last one will be m_first_printing_extruder. // Then set m_first_printing_extruder to the 1st extruder primed. m_all_printing_extruders.erase( - std::remove_if(m_all_printing_extruders.begin(), m_all_printing_extruders.end(), + std::remove_if(m_all_printing_extruders.begin(), m_all_printing_extruders.end(), [ this ](const unsigned int eid) { return eid == m_first_printing_extruder; }), m_all_printing_extruders.end()); m_all_printing_extruders.emplace_back(m_first_printing_extruder); @@ -623,6 +606,6 @@ const std::vector* WipingExtrusions::get_extruder_overrides(const Extrusion return &(entity_map_it->second); } - + } // namespace Slic3r diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index 5e4820988e..1838514f31 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -948,8 +948,6 @@ public: { if (meshcache_valid) return meshcache; - std::cout << "merging mesh" << std::endl; - Contour3D merged; for (auto &head : m_heads) { @@ -2450,7 +2448,7 @@ public: } } - void merge_result() { /*m_result.merge_and_cleanup();*/ } + void merge_result() { m_result.merge_and_cleanup(); } }; bool SLASupportTree::generate(const std::vector &support_points, diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index fa85d497f9..46fa281b5e 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -16,7 +16,7 @@ // For geometry algorithms with native Clipper types (no copies and conversions) #include -#define SLAPRINT_DO_BENCHMARK +// #define SLAPRINT_DO_BENCHMARK #ifdef SLAPRINT_DO_BENCHMARK #include @@ -954,20 +954,20 @@ void SLAPrint::process() throw_if_canceled(); // Create the unified mesh - // auto rc = SlicingStatus::RELOAD_SCENE; + auto rc = SlicingStatus::RELOAD_SCENE; // This is to prevent "Done." being displayed during merged_mesh() - // m_report_status(*this, -1, L("Visualizing supports")); - // po.m_supportdata->support_tree_ptr->merged_mesh(); + m_report_status(*this, -1, L("Visualizing supports")); + po.m_supportdata->support_tree_ptr->merged_mesh(); BOOST_LOG_TRIVIAL(debug) << "Processed support point count " << po.m_supportdata->support_points.size(); // Check the mesh for later troubleshooting. -// if(po.support_mesh().empty()) -// BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty"; + if(po.support_mesh().empty()) + BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty"; -// m_report_status(*this, -1, L("Visualizing supports"), rc); + m_report_status(*this, -1, L("Visualizing supports"), rc); }; // This step generates the sla base pad @@ -976,10 +976,6 @@ void SLAPrint::process() // and before the supports had been sliced. (or the slicing has to be // repeated) - std::cout << "Should only merge mesh after this" << std::endl; - po.m_supportdata->support_tree_ptr->merged_mesh(); - m_report_status(*this, -1, L("Visualizing supports"), SlicingStatus::RELOAD_SCENE); - if(po.m_config.pad_enable.getBool()) { // Get the distilled pad configuration from the config @@ -1494,10 +1490,7 @@ void SLAPrint::process() { unsigned incr = 0; for (SLAPrintObject *po : m_objects) { - - for (SLAPrintObjectStep currentstep : steps) { - - Benchmark bench; + for (SLAPrintObjectStep step : steps) { // Cancellation checking. Each step will check for // cancellation on its own and return earlier gracefully. @@ -1507,17 +1500,17 @@ void SLAPrint::process() st += incr * ostepd; - if (po->m_stepmask[currentstep] && po->set_started(currentstep)) { - m_report_status(*this, st, OBJ_STEP_LABELS(currentstep)); + if (po->m_stepmask[step] && po->set_started(step)) { + m_report_status(*this, st, OBJ_STEP_LABELS(step)); bench.start(); - pobj_program[currentstep](*po); + pobj_program[step](*po); bench.stop(); - step_times[currentstep] += bench.getElapsedSec(); + step_times[step] += bench.getElapsedSec(); throw_if_canceled(); - po->set_done(currentstep); + po->set_done(step); } - incr = OBJ_STEP_LEVELS[currentstep]; + incr = OBJ_STEP_LEVELS[step]; } } }; @@ -1525,14 +1518,12 @@ void SLAPrint::process() apply_steps_on_objects(level1_obj_steps); apply_steps_on_objects(level2_obj_steps); - SLAPrintStep printsteps[] = { slapsMergeSlicesAndEval, slapsRasterize }; - // this would disable the rasterization step // std::fill(m_stepmask.begin(), m_stepmask.end(), false); double pstd = (100 - max_objstatus) / 100.0; st = max_objstatus; - for(SLAPrintStep currentstep : printsteps) { + for(SLAPrintStep currentstep : print_steps) { throw_if_canceled(); if (m_stepmask[currentstep] && set_started(currentstep)) { From eddf9321612e0cde71f466ccbc9e1cc4f6ab4442 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 19 Aug 2019 10:58:44 +0200 Subject: [PATCH 11/48] Set min SLA display resolution to 1x1 (see SPE-1000) --- src/libslic3r/PrintConfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 31de80e8be..fd5b699ac5 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2306,13 +2306,13 @@ void PrintConfigDef::init_sla_params() def->full_label = L("Number of pixels in"); def->label = ("X"); def->tooltip = L("Number of pixels in X"); - def->min = 100; + def->min = 1; def->set_default_value(new ConfigOptionInt(2560)); def = this->add("display_pixels_y", coInt); def->label = ("Y"); def->tooltip = L("Number of pixels in Y"); - def->min = 100; + def->min = 1; def->set_default_value(new ConfigOptionInt(1440)); def = this->add("display_mirror_x", coBool); From a66c59941d1ef7e9b18d7a3d3935781c491416f1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 19 Aug 2019 12:55:57 +0200 Subject: [PATCH 12/48] Better error message in case of corrupted PrusaSlicer.ini --- src/slic3r/GUI/AppConfig.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index dfdc79677d..7ca8c3e5eb 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -15,9 +15,13 @@ #include #include #include +#include #include #include +#include +#include "I18N.hpp" + namespace Slic3r { static const std::string VENDOR_PREFIX = "vendor:"; @@ -58,7 +62,7 @@ void AppConfig::set_defaults() if (!get("use_legacy_opengl").empty()) erase("", "use_legacy_opengl"); -#if __APPLE__ +#ifdef __APPLE__ if (get("use_retina_opengl").empty()) set("use_retina_opengl", "1"); #endif @@ -90,7 +94,14 @@ void AppConfig::load() namespace pt = boost::property_tree; pt::ptree tree; boost::nowide::ifstream ifs(AppConfig::config_path()); - pt::read_ini(ifs, tree); + try { + pt::read_ini(ifs, tree); + } catch (pt::ptree_error& ex) { + // Error while parsing config file. We'll customize the error message and rethrow to be displayed. + throw std::runtime_error(wxString::Format(_(L("Error parsing config file, it is probably corrupted. " + "Try to manualy delete the file. Your user profiles will not be affected.\n\n%s\n\n%s")), + AppConfig::config_path(), ex.what()).ToStdString()); + } // 2) Parse the property_tree, extract the sections and key / value pairs. for (const auto §ion : tree) { From 283cee3f27156231a84a278c8ba29d52a0795d4d Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 19 Aug 2019 12:58:59 +0200 Subject: [PATCH 13/48] Fixed SPE-1000. Since the value inserted from the keyboard or clipboard is not updated under OSX, we forcibly set the input value for SpinControl every time during editing. Thus we can't set min control value bigger then 0. Otherwise, it couldn't be possible to input from keyboard value less then min_val. --- src/libslic3r/PrintConfig.cpp | 4 ++-- src/slic3r/GUI/Field.cpp | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index fd5b699ac5..31de80e8be 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2306,13 +2306,13 @@ void PrintConfigDef::init_sla_params() def->full_label = L("Number of pixels in"); def->label = ("X"); def->tooltip = L("Number of pixels in X"); - def->min = 1; + def->min = 100; def->set_default_value(new ConfigOptionInt(2560)); def = this->add("display_pixels_y", coInt); def->label = ("Y"); def->tooltip = L("Number of pixels in Y"); - def->min = 1; + def->min = 100; def->set_default_value(new ConfigOptionInt(1440)); def = this->add("display_mirror_x", coBool); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 39924e44c5..252b9d6c5b 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -559,7 +559,16 @@ void SpinCtrl::BUILD() { break; } - const int min_val = m_opt.min == INT_MIN ? 0: m_opt.min; + const int min_val = m_opt.min == INT_MIN +#ifdef __WXOSX__ + // We will forcibly set the input value for SpinControl, since the value + // inserted from the keyboard is not updated under OSX. + // So, we can't set min control value bigger then 0. + // Otherwise, it couldn't be possible to input from keyboard value + // less then min_val. + || m_opt.min > 0 +#endif + ? 0 : m_opt.min; const int max_val = m_opt.max < 2147483647 ? m_opt.max : 2147483647; auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, @@ -631,6 +640,14 @@ void SpinCtrl::propagate_value() if (tmp_value == UNDEF_VALUE) { on_kill_focus(); } else { +#ifdef __WXOSX__ + // check input value for minimum + if (m_opt.min > 0 && tmp_value < m_opt.min) { + wxSpinCtrl* spin = static_cast(window); + spin->SetValue(m_opt.min); + spin->GetText()->SetInsertionPointEnd(); + } +#endif on_change_field(); } } From 7008853f0861201971fc21cf4da1d2cd8a8b401b Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 19 Aug 2019 14:34:12 +0200 Subject: [PATCH 14/48] Add AppImage credits #2747 --- src/slic3r/GUI/AboutDialog.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index d2c76366b7..ca7c2c22d3 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -110,7 +110,9 @@ void CopyrightsDialog::fill_entries() , "Based on original by fabian \"ryg\" giesen v1.04. " "Custom version, modified by Yann Collet" , "https://github.com/Cyan4973/RygsDXTc" }, { "Icons for STL and GCODE files." - , "Akira Yasuda" , "http://3dp0.com/icons-for-stl-and-gcode/" } + , "Akira Yasuda" , "http://3dp0.com/icons-for-stl-and-gcode/" }, + { "AppImage packaging for Linux using AppImageKit" + , "2004-2019 Simon Peter and contributors" , "https://appimage.org/" } }; } From 0becfa0a0486daed4509f6688e7458b868b19d0a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 19 Aug 2019 15:44:22 +0200 Subject: [PATCH 15/48] Fix of #2739 --- src/slic3r/GUI/3DBed.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 97e200b38e..5b7473980f 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -609,10 +609,12 @@ void Bed3D::render_default(bool bottom) const if (!has_model && !bottom) { // draw background + glsafe(::glDepthMask(GL_FALSE)); glsafe(::glColor4f(0.35f, 0.35f, 0.35f, 0.4f)); glsafe(::glNormal3d(0.0f, 0.0f, 1.0f)); glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_vertices_data())); glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount)); + glsafe(::glDepthMask(GL_TRUE)); } // draw grid From 92bdb68e1126a1e6dc4001f50e02f30ce252ea74 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 19 Aug 2019 15:50:49 +0200 Subject: [PATCH 16/48] Extended the error message when empty layers are detected --- src/libslic3r/GCode.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index b691203c97..24be7fd605 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -474,8 +474,10 @@ std::vector GCode::collect_layers_to_print(const PrintObjec if (layer_to_print.print_z() > maximal_print_z + EPSILON) throw std::runtime_error(_(L("Empty layers detected, the output would not be printable.")) + "\n\n" + - _(L("Object name: ")) + object.model_object()->name + "\n" + _(L("Print z: ")) + - std::to_string(layers_to_print.back().print_z())); + _(L("Object name: ")) + object.model_object()->name + "\n" + _(L("Print z: ")) + + std::to_string(layers_to_print.back().print_z()) + "\n\n" + _(L("This is " + "usually caused by negligibly small extrusions or by a faulty model. Try to repair " + " the model or change its orientation on the bed."))); // Remember last layer with extrusions. last_extrusion_layer = &layers_to_print.back(); } From e30a17beb3c2d1d9faf64fc7c73b40ed853cdedc Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 19 Aug 2019 17:01:39 +0200 Subject: [PATCH 17/48] Fixed memory issues of BedShapeHintwhen using unions of non-trivial objects --- src/libslic3r/Arrange.cpp | 4 +--- src/libslic3r/Arrange.hpp | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index f04e051624..99645f29d8 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -507,9 +507,7 @@ BedShapeHint::BedShapeHint(const Polyline &bed) { m_type = BedShapes::bsCircle; m_bed.circ = c; } else { - if (m_type == BedShapes::bsIrregular) - m_bed.polygon.Slic3r::Polyline::~Polyline(); - + assert(m_type != BedShapes::bsIrregular); m_type = BedShapes::bsIrregular; ::new (&m_bed.polygon) Polyline(bed); } diff --git a/src/libslic3r/Arrange.hpp b/src/libslic3r/Arrange.hpp index 3d405145e6..a0e4c043f0 100644 --- a/src/libslic3r/Arrange.hpp +++ b/src/libslic3r/Arrange.hpp @@ -39,6 +39,9 @@ enum BedShapes { class BedShapeHint { BedShapes m_type = BedShapes::bsInfinite; + // The union neither calls constructors nor destructors of its members. + // The only member with non-trivial constructor / destructor is the polygon, + // a placement new / delete needs to be called over it. union BedShape_u { // TODO: use variant from cpp17? CircleBed circ; BoundingBox box; @@ -80,6 +83,12 @@ public: BedShapeHint &operator=(const BedShapeHint &cpy) { + if (m_type != cpy.m_type) { + if (m_type == bsIrregular) + m_bed.polygon.Slic3r::Polyline::~Polyline(); + else if (cpy.m_type == bsIrregular) + ::new (&m_bed.polygon) Polyline(); + } m_type = cpy.m_type; switch(m_type) { case bsBox: m_bed.box = cpy.m_bed.box; break; @@ -94,6 +103,12 @@ public: BedShapeHint& operator=(BedShapeHint &&cpy) { + if (m_type != cpy.m_type) { + if (m_type == bsIrregular) + m_bed.polygon.Slic3r::Polyline::~Polyline(); + else if (cpy.m_type == bsIrregular) + ::new (&m_bed.polygon) Polyline(); + } m_type = cpy.m_type; switch(m_type) { case bsBox: m_bed.box = std::move(cpy.m_bed.box); break; From b5dd13b9879eb1d149ed1c4f3f15fb10abd112a5 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 5 Aug 2019 17:28:02 +0200 Subject: [PATCH 18/48] PresetUpdater: Fix index installation having broken incompatibility check This fixes a problem where old slicer having found newer incompatible bundle would not report an incompatibility. The installed index check was performed too early before bundle compatibility check. This fix moves the installed index check to the point where a bundle would've been update (as it should be). --- src/slic3r/Utils/PresetUpdater.cpp | 56 ++++++++++++++++++------------ 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index bc600fcad9..3f3139cadf 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -101,6 +101,17 @@ struct Incompat , vendor(std::move(vendor)) {} + void remove() { + // Remove the bundle file + fs::remove(bundle); + + // Look for an installed index and remove it too if any + const fs::path installed_idx = bundle.replace_extension("idx"); + if (fs::exists(installed_idx)) { + fs::remove(installed_idx); + } + } + friend std::ostream& operator<<(std::ostream& os , const Incompat &self) { os << "Incompat(" << self.bundle.string() << ')'; return os; @@ -383,25 +394,6 @@ Updates PresetUpdater::priv::get_config_updates() const continue; } - // Load 'installed' idx, if any. - // 'Installed' indices are kept alongside the bundle in the `vendor` subdir - // for bookkeeping to remember a cancelled update and not offer it again. - if (fs::exists(bundle_path_idx)) { - Index existing_idx; - try { - existing_idx.load(bundle_path_idx); - - const auto existing_recommended = existing_idx.recommended(); - if (existing_recommended != existing_idx.end() && recommended->config_version == existing_recommended->config_version) { - // The user has already seen (and presumably rejected) this update - BOOST_LOG_TRIVIAL(info) << boost::format("Downloaded index for `%1%` is the same as installed one, not offering an update.") % idx.vendor(); - continue; - } - } catch (const std::exception & /* err */) { - BOOST_LOG_TRIVIAL(error) << boost::format("Could nto load installed index %1%") % bundle_path_idx; - } - } - const auto ver_current = idx.find(vp.config_version); const bool ver_current_found = ver_current != idx.end(); @@ -424,6 +416,25 @@ Updates PresetUpdater::priv::get_config_updates() const } else if (recommended->config_version > vp.config_version) { // Config bundle update situation + // Load 'installed' idx, if any. + // 'Installed' indices are kept alongside the bundle in the `vendor` subdir + // for bookkeeping to remember a cancelled update and not offer it again. + if (fs::exists(bundle_path_idx)) { + Index existing_idx; + try { + existing_idx.load(bundle_path_idx); + + const auto existing_recommended = existing_idx.recommended(); + if (existing_recommended != existing_idx.end() && recommended->config_version == existing_recommended->config_version) { + // The user has already seen (and presumably rejected) this update + BOOST_LOG_TRIVIAL(info) << boost::format("Downloaded index for `%1%` is the same as installed one, not offering an update.") % idx.vendor(); + continue; + } + } catch (const std::exception &err) { + BOOST_LOG_TRIVIAL(error) << boost::format("Could not load installed index at `%1%`: %2%") % bundle_path_idx % err.what(); + } + } + // Check if the update is already present in a snapshot const auto recommended_snap = SnapshotDB::singleton().snapshot_with_vendor_preset(vp.name, recommended->config_version); if (recommended_snap != SnapshotDB::singleton().end()) { @@ -485,12 +496,11 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons BOOST_LOG_TRIVIAL(info) << boost::format("Deleting %1% incompatible bundles") % updates.incompats.size(); - for (const auto &incompat : updates.incompats) { + for (auto &incompat : updates.incompats) { BOOST_LOG_TRIVIAL(info) << '\t' << incompat; - fs::remove(incompat.bundle); + incompat.remove(); } - } - else if (updates.updates.size() > 0) { + } else if (updates.updates.size() > 0) { if (snapshot) { BOOST_LOG_TRIVIAL(info) << "Taking a snapshot..."; SnapshotDB::singleton().take_snapshot(*GUI::wxGetApp().app_config, Snapshot::SNAPSHOT_UPGRADE); From 745182988d5edc06ef3d9c0ea1a2265a04d79a88 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 9 Aug 2019 17:01:37 +0200 Subject: [PATCH 19/48] Refactor: Move Semver from slice3r to libslic3r A static symbol Slic3r::SEMVER is introduced, which holds the running slicer's Semver object. This is mainly done to make testing updater behaviour _much_ easier. Additionaly to cleanup some questionable code (Semver was being parsed multiple times / in multiple places in the frontend.) --- src/libslic3r/CMakeLists.txt | 1 + src/libslic3r/Semver.cpp | 7 +++++++ src/{slic3r/Utils => libslic3r}/Semver.hpp | 0 src/libslic3r/libslic3r.h | 3 +++ src/slic3r/Config/Snapshot.cpp | 2 +- src/slic3r/Config/Snapshot.hpp | 2 +- src/slic3r/Config/Version.cpp | 3 +-- src/slic3r/Config/Version.hpp | 2 +- src/slic3r/GUI/AppConfig.hpp | 2 +- src/slic3r/GUI/MsgDialog.hpp | 2 -- src/slic3r/GUI/Preset.hpp | 2 +- src/slic3r/GUI/UpdateDialogs.hpp | 2 +- src/slic3r/Utils/PresetUpdater.cpp | 20 +++----------------- 13 files changed, 21 insertions(+), 27 deletions(-) create mode 100644 src/libslic3r/Semver.cpp rename src/{slic3r/Utils => libslic3r}/Semver.hpp (100%) diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 1ebd922e20..a5abf43eca 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -139,6 +139,7 @@ add_library(libslic3r STATIC PrintConfig.hpp PrintObject.cpp PrintRegion.cpp + Semver.cpp SLAPrint.cpp SLAPrint.hpp SLA/SLAAutoSupports.hpp diff --git a/src/libslic3r/Semver.cpp b/src/libslic3r/Semver.cpp new file mode 100644 index 0000000000..5d36b39f72 --- /dev/null +++ b/src/libslic3r/Semver.cpp @@ -0,0 +1,7 @@ +#include "libslic3r.h" + +namespace Slic3r { + +Semver SEMVER { SLIC3R_VERSION }; + +} diff --git a/src/slic3r/Utils/Semver.hpp b/src/libslic3r/Semver.hpp similarity index 100% rename from src/slic3r/Utils/Semver.hpp rename to src/libslic3r/Semver.hpp diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index dc2b6a4ec0..afbf94fa39 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -19,6 +19,7 @@ #include #include "Technologies.hpp" +#include "Semver.hpp" typedef int32_t coord_t; typedef double coordf_t; @@ -92,6 +93,8 @@ inline std::string debug_out_path(const char *name, ...) namespace Slic3r { +extern Semver SEMVER; + template inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); } diff --git a/src/slic3r/Config/Snapshot.cpp b/src/slic3r/Config/Snapshot.cpp index b208554b50..3757ec25b3 100644 --- a/src/slic3r/Config/Snapshot.cpp +++ b/src/slic3r/Config/Snapshot.cpp @@ -366,7 +366,7 @@ const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot: // Snapshot header. snapshot.time_captured = Slic3r::Utils::get_current_time_utc(); snapshot.id = Slic3r::Utils::format_time_ISO8601Z(snapshot.time_captured); - snapshot.slic3r_version_captured = *Semver::parse(SLIC3R_VERSION); // XXX: have Semver Slic3r version + snapshot.slic3r_version_captured = Slic3r::SEMVER; snapshot.comment = comment; snapshot.reason = reason; // Active presets at the time of the snapshot. diff --git a/src/slic3r/Config/Snapshot.hpp b/src/slic3r/Config/Snapshot.hpp index a916dfe92a..9a73916916 100644 --- a/src/slic3r/Config/Snapshot.hpp +++ b/src/slic3r/Config/Snapshot.hpp @@ -8,8 +8,8 @@ #include +#include "libslic3r/Semver.hpp" #include "Version.hpp" -#include "../Utils/Semver.hpp" namespace Slic3r { diff --git a/src/slic3r/Config/Version.cpp b/src/slic3r/Config/Version.cpp index 865884c6fe..175abff69a 100644 --- a/src/slic3r/Config/Version.cpp +++ b/src/slic3r/Config/Version.cpp @@ -15,7 +15,6 @@ namespace Slic3r { namespace GUI { namespace Config { -static const Semver s_current_slic3r_semver(SLIC3R_VERSION); // Optimized lexicographic compare of two pre-release versions, ignoring the numeric suffix. static int compare_prerelease(const char *p1, const char *p2) @@ -64,7 +63,7 @@ bool Version::is_slic3r_supported(const Semver &slic3r_version) const bool Version::is_current_slic3r_supported() const { - return this->is_slic3r_supported(s_current_slic3r_semver); + return this->is_slic3r_supported(Slic3r::SEMVER); } #if 0 diff --git a/src/slic3r/Config/Version.hpp b/src/slic3r/Config/Version.hpp index 560bc29c21..19c565ffb4 100644 --- a/src/slic3r/Config/Version.hpp +++ b/src/slic3r/Config/Version.hpp @@ -7,7 +7,7 @@ #include #include "libslic3r/FileParserError.hpp" -#include "../Utils/Semver.hpp" +#include "libslic3r/Semver.hpp" namespace Slic3r { namespace GUI { diff --git a/src/slic3r/GUI/AppConfig.hpp b/src/slic3r/GUI/AppConfig.hpp index 230a922940..8ad17b9db8 100644 --- a/src/slic3r/GUI/AppConfig.hpp +++ b/src/slic3r/GUI/AppConfig.hpp @@ -6,7 +6,7 @@ #include #include "libslic3r/Config.hpp" -#include "slic3r/Utils/Semver.hpp" +#include "libslic3r/Semver.hpp" namespace Slic3r { diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp index ad4bbcc971..5a49298495 100644 --- a/src/slic3r/GUI/MsgDialog.hpp +++ b/src/slic3r/GUI/MsgDialog.hpp @@ -8,8 +8,6 @@ #include #include -#include "slic3r/Utils/Semver.hpp" - class wxBoxSizer; class wxCheckBox; class wxStaticBitmap; diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 8fd1652a83..e1efdc1ef0 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -8,7 +8,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/PrintConfig.hpp" -#include "slic3r/Utils/Semver.hpp" +#include "libslic3r/Semver.hpp" class wxBitmap; class wxBitmapComboBox; diff --git a/src/slic3r/GUI/UpdateDialogs.hpp b/src/slic3r/GUI/UpdateDialogs.hpp index 2a580e2513..4b61b84c23 100644 --- a/src/slic3r/GUI/UpdateDialogs.hpp +++ b/src/slic3r/GUI/UpdateDialogs.hpp @@ -5,7 +5,7 @@ #include #include -#include "slic3r/Utils/Semver.hpp" +#include "libslic3r/Semver.hpp" #include "MsgDialog.hpp" class wxBoxSizer; diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 3f3139cadf..589db36dce 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -124,25 +124,12 @@ struct Updates std::vector updates; }; -static Semver get_slic3r_version() -{ - auto res = Semver::parse(SLIC3R_VERSION); - - if (! res) { - const char *error = "Could not parse Slic3r version string: " SLIC3R_VERSION; - BOOST_LOG_TRIVIAL(error) << error; - throw std::runtime_error(error); - } - - return *res; -} wxDEFINE_EVENT(EVT_SLIC3R_VERSION_ONLINE, wxCommandEvent); struct PresetUpdater::priv { - const Semver ver_slic3r; std::vector index_db; bool enabled_version_check; @@ -170,8 +157,7 @@ struct PresetUpdater::priv }; PresetUpdater::priv::priv() - : ver_slic3r(get_slic3r_version()) - , cache_path(fs::path(Slic3r::data_dir()) / "cache") + : cache_path(fs::path(Slic3r::data_dir()) / "cache") , rsrc_path(fs::path(resources_dir()) / "profiles") , vendor_path(fs::path(Slic3r::data_dir()) / "vendor") , cancel(false) @@ -594,8 +580,8 @@ void PresetUpdater::slic3r_update_notify() if (ver_online) { // Only display the notification if the version available online is newer AND if we haven't seen it before - if (*ver_online > p->ver_slic3r && (! ver_online_seen || *ver_online_seen < *ver_online)) { - GUI::MsgUpdateSlic3r notification(p->ver_slic3r, *ver_online); + if (*ver_online > Slic3r::SEMVER && (! ver_online_seen || *ver_online_seen < *ver_online)) { + GUI::MsgUpdateSlic3r notification(Slic3r::SEMVER, *ver_online); notification.ShowModal(); if (notification.disable_version_check()) { app_config->set("version_check", "0"); From baaf66d138f3be357bbc4beb12c804c84b743c48 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 19 Aug 2019 10:35:18 +0200 Subject: [PATCH 20/48] avrdude: conf-generate: Fix line endings - always generate LF endings avrdude configuration embedding tool was generating platform specific line endings in avrdude-slic3r.conf.h --- src/avrdude/CMakeLists.txt | 2 +- src/avrdude/conf-generate.cpp | 36 ++++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/avrdude/CMakeLists.txt b/src/avrdude/CMakeLists.txt index a1930ad5f9..f2204db0c8 100644 --- a/src/avrdude/CMakeLists.txt +++ b/src/avrdude/CMakeLists.txt @@ -86,7 +86,7 @@ add_executable(avrdude-conf-gen conf-generate.cpp) add_custom_command( DEPENDS avrdude-conf-gen ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf.h - COMMAND $ avrdude-slic3r.conf avrdude_slic3r_conf > avrdude-slic3r.conf.h + COMMAND $ avrdude-slic3r.conf avrdude_slic3r_conf avrdude-slic3r.conf.h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/src/avrdude/conf-generate.cpp b/src/avrdude/conf-generate.cpp index 4aa80ae0af..1e05db5cea 100644 --- a/src/avrdude/conf-generate.cpp +++ b/src/avrdude/conf-generate.cpp @@ -6,36 +6,42 @@ int main(int argc, char const *argv[]) { - if (argc != 3) { - std::cerr << "Usage: " << argv[0] << " " << std::endl; + if (argc != 4) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; return -1; } - const char* filename = argv[1]; + const char* filename_in = argv[1]; const char* symbol = argv[2]; + const char* filename_out = argv[3]; size_t size = 0; - std::fstream file(filename); + std::fstream file(filename_in, std::ios::in | std::ios::binary); if (!file.good()) { - std::cerr << "Cannot read file: " << filename << std::endl; + std::cerr << "Cannot read file: " << filename_in << std::endl; } - std::cout << "/* WARN: This file is auto-generated from `" << filename << "` */" << std::endl; - std::cout << "const unsigned char " << symbol << "[] = {"; + std::fstream output(filename_out, std::ios::out | std::ios::trunc | std::ios::binary); + if (!output.good()) { + std::cerr << "Cannot open output file: " << filename_out << std::endl; + } + + output << "/* WARN: This file is auto-generated from `" << filename_in << "` */" << std::endl; + output << "const unsigned char " << symbol << "[] = {"; char c; - std::cout << std::hex; - std::cout.fill('0'); + output << std::hex; + output.fill('0'); for (file.get(c); !file.eof(); size++, file.get(c)) { - if (size % 12 == 0) { std::cout << "\n "; } - std::cout << "0x" << std::setw(2) << (unsigned)c << ", "; + if (size % 12 == 0) { output << "\n "; } + output << "0x" << std::setw(2) << (unsigned)c << ", "; } - std::cout << "\n 0, 0\n};\n"; + output << "\n 0, 0\n};\n"; - std::cout << std::dec; - std::cout << "const size_t " << symbol << "_size = " << size << ";" << std::endl; - std::cout << "const size_t " << symbol << "_size_yy = " << size + 2 << ";" << std::endl; + output << std::dec; + output << "const size_t " << symbol << "_size = " << size << ";" << std::endl; + output << "const size_t " << symbol << "_size_yy = " << size + 2 << ";" << std::endl; return 0; } From f937209619e7a32ba4f3a5571d647aa4e695b5e5 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 19 Aug 2019 10:55:11 +0200 Subject: [PATCH 21/48] Refactor catch(...) handlers in Http, OctoPrint, PrintHost, and Serial --- src/slic3r/Utils/Http.cpp | 3 ++- src/slic3r/Utils/OctoPrint.cpp | 3 ++- src/slic3r/Utils/PrintHost.cpp | 2 -- src/slic3r/Utils/Serial.cpp | 12 +++++------- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 79c4ecfa91..69301547c3 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -165,7 +166,7 @@ size_t Http::priv::form_file_read_cb(char *buffer, size_t size, size_t nitems, v try { stream->read(buffer, size * nitems); - } catch (...) { + } catch (const std::exception &) { return CURL_READFUNC_ABORT; } diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index cafa69c554..09ca02071a 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -69,7 +70,7 @@ bool OctoPrint::test(wxString &msg) const msg = wxString::Format(_(L("Mismatched type of print host: %s")), text ? *text : "OctoPrint"); } } - catch (...) { + catch (const std::exception &) { res = false; msg = "Could not parse server response"; } diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index e9e39e6957..ab52b23443 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -170,8 +170,6 @@ void PrintHostJobQueue::priv::bg_thread_main() } } catch (const std::exception &e) { emit_error(e.what()); - } catch (...) { - emit_error("Unknown exception"); } // Cleanup leftover files, if any diff --git a/src/slic3r/Utils/Serial.cpp b/src/slic3r/Utils/Serial.cpp index acfd5fafd0..5944646926 100644 --- a/src/slic3r/Utils/Serial.cpp +++ b/src/slic3r/Utils/Serial.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -71,13 +72,10 @@ void parse_hardware_id(const std::string &hardware_id, SerialPortInfo &spi) std::regex pattern("USB\\\\.*VID_([[:xdigit:]]+)&PID_([[:xdigit:]]+).*"); std::smatch matches; if (std::regex_match(hardware_id, matches, pattern)) { - try { - vid = std::stoul(matches[1].str(), 0, 16); - pid = std::stoul(matches[2].str(), 0, 16); - spi.id_vendor = vid; - spi.id_product = pid; - } - catch (...) {} + vid = std::stoul(matches[1].str(), 0, 16); + pid = std::stoul(matches[2].str(), 0, 16); + spi.id_vendor = vid; + spi.id_product = pid; } } #endif From 0ded335488b1bc84f808cf335ef9751edcd9276f Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 19 Aug 2019 12:25:18 +0200 Subject: [PATCH 22/48] build: Add source file encoding check Source files are checked using a small utility in src/build-utils This is done to prevent bugs in build and localization caused by weird non-UTF-8 encodings interpreted by MSVC in terms of local codepages rather than UTF-8. --- src/CMakeLists.txt | 1 + src/avrdude/CMakeLists.txt | 3 + src/build-utils/CMakeLists.txt | 39 ++++++++++ src/build-utils/encoding-check.cpp | 119 +++++++++++++++++++++++++++++ src/libslic3r/CMakeLists.txt | 2 + src/semver/CMakeLists.txt | 2 + src/slic3r/CMakeLists.txt | 2 + 7 files changed, 168 insertions(+) create mode 100644 src/build-utils/CMakeLists.txt create mode 100644 src/build-utils/encoding-check.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9f3dbcec89..31cb24f24a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,6 @@ project(PrusaSlicer-native) +add_subdirectory(build-utils) add_subdirectory(admesh) add_subdirectory(avrdude) # boost/nowide diff --git a/src/avrdude/CMakeLists.txt b/src/avrdude/CMakeLists.txt index f2204db0c8..e6748a5aa2 100644 --- a/src/avrdude/CMakeLists.txt +++ b/src/avrdude/CMakeLists.txt @@ -100,6 +100,9 @@ add_dependencies(avrdude gen_conf_h) add_executable(avrdude-slic3r main-standalone.cpp) target_link_libraries(avrdude-slic3r avrdude) +encoding_check(avrdude) +encoding_check(avrdude-slic3r) + if (WIN32) target_compile_definitions(avrdude PRIVATE WIN32NATIVE=1) if(MSVC) diff --git a/src/build-utils/CMakeLists.txt b/src/build-utils/CMakeLists.txt new file mode 100644 index 0000000000..3b3961b562 --- /dev/null +++ b/src/build-utils/CMakeLists.txt @@ -0,0 +1,39 @@ + +add_executable(encoding-check encoding-check.cpp) + +# A global no-op target which depends on all encodings checks, +# and on which in turn all checked targets depend. +# This is done to make encoding checks the first thing to be +# performed before actually compiling any sources of the checked targets +# to make the check fail as early as possible. +add_custom_target(global-encoding-check + ALL + DEPENDS encoding-check +) + +# Function that adds source file encoding check to a target +# using the above encoding-check binary + +function(encoding_check TARGET) + # Obtain target source files + get_target_property(T_SOURCES ${TARGET} SOURCES) + + # Define top-level encoding check target for this ${TARGET} + add_custom_target(encoding-check-${TARGET} + DEPENDS encoding-check ${T_SOURCES} + COMMENT "Checking source files encodings for target ${TARGET}" + ) + + # Add checking of each source file as a subcommand of encoding-check-${TARGET} + foreach(file ${T_SOURCES}) + add_custom_command(TARGET encoding-check-${TARGET} + COMMAND $ ${TARGET} ${file} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + endforeach() + + # This adds dependency on encoding-check-${TARGET} to ${TARET} + # via the global-encoding-check + add_dependencies(global-encoding-check encoding-check-${TARGET}) + add_dependencies(${TARGET} global-encoding-check) +endfunction() diff --git a/src/build-utils/encoding-check.cpp b/src/build-utils/encoding-check.cpp new file mode 100644 index 0000000000..89f225572b --- /dev/null +++ b/src/build-utils/encoding-check.cpp @@ -0,0 +1,119 @@ +#include +#include +#include +#include + + +/* + * The utf8_check() function scans the '\0'-terminated string starting + * at s. It returns a pointer to the first byte of the first malformed + * or overlong UTF-8 sequence found, or NULL if the string contains + * only correct UTF-8. It also spots UTF-8 sequences that could cause + * trouble if converted to UTF-16, namely surrogate characters + * (U+D800..U+DFFF) and non-Unicode positions (U+FFFE..U+FFFF). This + * routine is very likely to find a malformed sequence if the input + * uses any other encoding than UTF-8. It therefore can be used as a + * very effective heuristic for distinguishing between UTF-8 and other + * encodings. + * + * I wrote this code mainly as a specification of functionality; there + * are no doubt performance optimizations possible for certain CPUs. + * + * Markus Kuhn -- 2005-03-30 + * License: http://www.cl.cam.ac.uk/~mgk25/short-license.html + */ + +unsigned char *utf8_check(unsigned char *s) +{ + while (*s) { + if (*s < 0x80) { + // 0xxxxxxx + s++; + } else if ((s[0] & 0xe0) == 0xc0) { + // 110xxxxx 10xxxxxx + if ((s[1] & 0xc0) != 0x80 || + (s[0] & 0xfe) == 0xc0) { // overlong? + return s; + } else { + s += 2; + } + } else if ((s[0] & 0xf0) == 0xe0) { + // 1110xxxx 10xxxxxx 10xxxxxx + if ((s[1] & 0xc0) != 0x80 || + (s[2] & 0xc0) != 0x80 || + (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || // overlong? + (s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || // surrogate? + (s[0] == 0xef && s[1] == 0xbf && + (s[2] & 0xfe) == 0xbe)) { // U+FFFE or U+FFFF? + return s; + } else { + s += 3; + } + } else if ((s[0] & 0xf8) == 0xf0) { + // 11110xxX 10xxxxxx 10xxxxxx 10xxxxxx + if ((s[1] & 0xc0) != 0x80 || + (s[2] & 0xc0) != 0x80 || + (s[3] & 0xc0) != 0x80 || + (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || // overlong? + (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) { // > U+10FFFF? + return s; + } else { + s += 4; + } + } else { + return s; + } + } + + return NULL; +} + + +int main(int argc, char const *argv[]) +{ + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return -1; + } + + const char* target = argv[1]; + const char* filename = argv[2]; + + const auto error_exit = [=](const char* error) { + std::cerr << "\n\tError: " << error << ": " << filename << "\n" + << "\tTarget: " << target << "\n" + << std::endl; + std::exit(-2); + }; + + std::ifstream file(filename, std::ios::binary | std::ios::ate); + const auto size = file.tellg(); + + if (size == 0) { + return 0; + } + + file.seekg(0, std::ios::beg); + std::vector buffer(size); + + if (file.read(buffer.data(), size)) { + buffer.push_back('\0'); + + // Check UTF-8 validity + if (utf8_check(reinterpret_cast(buffer.data())) != nullptr) { + error_exit("Source file does not contain (valid) UTF-8"); + } + + // Check against a BOM mark + if (buffer.size() >= 3 + && buffer[0] == '\xef' + && buffer[1] == '\xbb' + && buffer[2] == '\xbf') { + error_exit("Source file is valid UTF-8 but contains a BOM mark"); + } + } else { + error_exit("Could not read source file"); + } + + return 0; +} diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index a5abf43eca..1a9a153b94 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -187,6 +187,8 @@ add_library(libslic3r STATIC SLA/SLARasterWriter.cpp ) +encoding_check(libslic3r) + if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) add_precompiled_header(libslic3r pchheader.hpp FORCEINCLUDE) endif () diff --git a/src/semver/CMakeLists.txt b/src/semver/CMakeLists.txt index e3457bf291..c273121d49 100644 --- a/src/semver/CMakeLists.txt +++ b/src/semver/CMakeLists.txt @@ -5,3 +5,5 @@ add_library(semver STATIC semver.c semver.h ) + +encoding_check(semver) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index e3a910d6d2..b3e2990f91 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -163,6 +163,8 @@ endif () add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES}) +encoding_check(libslic3r_gui) + target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui ${GLEW_LIBRARIES}) if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE) From ef4ff55e55b5384be04e12b7dfcbf223f0f71ae8 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 19 Aug 2019 12:28:25 +0200 Subject: [PATCH 23/48] Fix encoding of a few files in GUI GUI/AboutDialog.cpp GUI/MainFrame.hpp GUI/OptionsGroup.cpp --- src/slic3r/GUI/AboutDialog.cpp | 4 ++-- src/slic3r/GUI/MainFrame.hpp | 2 +- src/slic3r/GUI/OptionsGroup.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index ca7c2c22d3..a4453c73ea 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -76,9 +76,9 @@ void CopyrightsDialog::fill_entries() { m_entries = { { "wxWidgets" , "2019 wxWidgets" , "https://www.wxwidgets.org/" }, - { "OpenGL" , "1997-2019 The Khronos™ Group Inc" , "https://www.opengl.org/" }, + { "OpenGL" , "1997-2019 The Khronosâ„¢ Group Inc" , "https://www.opengl.org/" }, { "GNU gettext" , "1998, 2019 Free Software Foundation, Inc." , "https://www.gnu.org/software/gettext/" }, - { "PoEdit" , "2019 Václav Slavík" , "https://poedit.net/" }, + { "PoEdit" , "2019 Václav Slavík" , "https://poedit.net/" }, { "ImGUI" , "2014-2019 Omar Cornut" , "https://github.com/ocornut/imgui" }, { "Eigen" , "" , "http://eigen.tuxfamily.org" }, { "ADMesh" , "1995, 1996 Anthony D. Martin; " diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 5d34be48ef..0e8a053e0f 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -1,4 +1,4 @@ -#ifndef slic3r_MainFrame_hpp_ +#ifndef slic3r_MainFrame_hpp_ #define slic3r_MainFrame_hpp_ #include "libslic3r/PrintConfig.hpp" diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 656e07a0e3..656df86ff2 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -1,4 +1,4 @@ -#include "OptionsGroup.hpp" +#include "OptionsGroup.hpp" #include "ConfigExceptions.hpp" #include From 4fbee3216b9a5067e83e3ae1d90cfc397ab2604e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 19 Aug 2019 19:48:07 +0200 Subject: [PATCH 24/48] Fix of Zoom by trackpad does not update until click #2750 For an unknown reason, if the scrolling is performed on Windows with the two finger gesture on touch pad, there is no Idle event generated on some computers. The Idle is not generated on Vojtech's laptop, it is generated on Enrico's laptop. evt.Skip() solves the issue on Vojtech's laptop. --- src/slic3r/GUI/GLCanvas3D.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a5906f619b..981cb38a93 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2474,6 +2474,13 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) evt.SetY(evt.GetY() * scale); #endif +#ifdef __WXMSW__ + // For some reason the Idle event is not being generated after the mouse scroll event in case of scrolling with the two fingers on the touch pad, + // if the event is not allowed to be passed further. + // https://github.com/prusa3d/PrusaSlicer/issues/2750 + evt.Skip(); +#endif /* __WXMSW__ */ + // Performs layers editing updates, if enabled if (is_layers_editing_enabled()) { From 3e62d7ae64f1f09f08a21708f5b21794ce2b12b5 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 13 Aug 2019 09:37:44 +0200 Subject: [PATCH 25/48] Implemented button "Reset to Filament Color" --- src/slic3r/GUI/Field.cpp | 55 +++++++++++++++++++++++++++++++++++----- src/slic3r/GUI/Field.hpp | 10 +++----- src/slic3r/GUI/Tab.cpp | 28 +++++++++++++++++++- src/slic3r/GUI/Tab.hpp | 1 + 4 files changed, 81 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 19a54016e5..2bee0018c9 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -1033,11 +1033,12 @@ void ColourPicker::BUILD() // Validate the color wxString clr_str(m_opt.get_default_value()->get_at(m_opt_idx)); wxColour clr(clr_str); - if (! clr.IsOk()) { + if (clr_str.IsEmpty() || !clr.IsOk()) { clr = wxTransparentColour; } auto temp = new wxColourPickerCtrl(m_parent, wxID_ANY, clr, wxDefaultPosition, size); + temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); temp->SetBackgroundStyle(wxBG_STYLE_PAINT); // // recast as a wxWindow to fit the calling convention @@ -1048,17 +1049,59 @@ void ColourPicker::BUILD() temp->SetToolTip(get_tooltip_text(clr_str)); } +void ColourPicker::set_undef_value(wxColourPickerCtrl* field) +{ + field->SetColour(wxTransparentColour); + + wxButton* btn = dynamic_cast(field->GetPickerCtrl()); + wxBitmap bmp = btn->GetBitmap(); + wxMemoryDC dc(bmp); + dc.SetTextForeground(*wxWHITE); + dc.SetFont(wxGetApp().normal_font()); + + const wxRect rect = wxRect(0, 0, bmp.GetWidth(), bmp.GetHeight()); + dc.DrawLabel("undef", rect, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL); + + dc.SelectObject(wxNullBitmap); + btn->SetBitmapLabel(bmp); +} + +void ColourPicker::set_value(const boost::any& value, bool change_event) +{ + m_disable_change_event = !change_event; + const wxString clr_str(boost::any_cast(value)); + auto field = dynamic_cast(window); + + wxColour clr(clr_str); + if (clr_str.IsEmpty() || !clr.IsOk()) + set_undef_value(field); + else + field->SetColour(clr); + + m_disable_change_event = false; +} + boost::any& ColourPicker::get_value() { -// boost::any m_value; - auto colour = static_cast(window)->GetColour(); - auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), colour.Red(), colour.Green(), colour.Blue()); - m_value = clr_str.ToStdString(); - + if (colour == wxTransparentColour) + m_value = std::string(""); + else { + auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), colour.Red(), colour.Green(), colour.Blue()); + m_value = clr_str.ToStdString(); + } return m_value; } +void ColourPicker::msw_rescale() +{ + Field::msw_rescale(); + + wxColourPickerCtrl* field = dynamic_cast(window); + if (field->GetColour() == wxTransparentColour) + set_undef_value(field); +} + void PointCtrl::BUILD() { auto temp = new wxBoxSizer(wxHORIZONTAL); diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 6c16f90f27..761b99ed83 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -404,6 +404,8 @@ public: class ColourPicker : public Field { using Field::Field; + + void set_undef_value(wxColourPickerCtrl* field); public: ColourPicker(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} ColourPicker(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} @@ -417,13 +419,9 @@ public: dynamic_cast(window)->SetColour(value); m_disable_change_event = false; } - void set_value(const boost::any& value, bool change_event = false) { - m_disable_change_event = !change_event; - dynamic_cast(window)->SetColour(boost::any_cast(value)); - m_disable_change_event = false; - } - + void set_value(const boost::any& value, bool change_event = false) override; boost::any& get_value() override; + void msw_rescale() override; void enable() override { dynamic_cast(window)->Enable(); }; void disable() override{ dynamic_cast(window)->Disable(); }; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index a7d178e724..4afd3a1163 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2558,7 +2558,33 @@ void TabPrinter::build_unregular_pages() optgroup->append_single_option_line("retract_restart_extra_toolchange", extruder_idx); optgroup = page->new_optgroup(_(L("Preview"))); - optgroup->append_single_option_line("extruder_colour", extruder_idx); + + auto reset_to_filament_color = [this, extruder_idx](wxWindow* parent) { + add_scaled_button(parent, &m_reset_to_filament_color, "undo", + _(L("Reset to Filament Color")), wxBU_LEFT | wxBU_EXACTFIT); + ScalableButton* btn = m_reset_to_filament_color; + btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(btn); + + btn->Bind(wxEVT_BUTTON, [this, extruder_idx](wxCommandEvent& e) + { + std::vector colors = static_cast(m_config->option("extruder_colour"))->values; + colors[extruder_idx] = ""; + + DynamicPrintConfig new_conf = *m_config; + new_conf.set_key_value("extruder_colour", new ConfigOptionStrings(colors)); + load_config(new_conf); + + update_dirty(); + update(); + }); + + return sizer; + }; + line = optgroup->create_single_option_line("extruder_colour", extruder_idx); + line.append_widget(reset_to_filament_color); + optgroup->append_line(line); #ifdef __WXMSW__ layout_page(page); diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index efefc47c56..0a90707005 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -371,6 +371,7 @@ public: wxButton* m_serial_test_btn = nullptr; ScalableButton* m_print_host_test_btn = nullptr; ScalableButton* m_printhost_browse_btn = nullptr; + ScalableButton* m_reset_to_filament_color = nullptr; size_t m_extruders_count; size_t m_extruders_count_old = 0; From 6780e74521111e4e08d8f3fdefab684f3e3e445b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 13 Aug 2019 14:56:02 +0200 Subject: [PATCH 26/48] Update 3D-scene after filament's color change --- src/slic3r/GUI/Tab.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 4afd3a1163..22c5a548a5 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1621,6 +1621,24 @@ void TabFilament::build() optgroup->append_single_option_line("filament_density"); optgroup->append_single_option_line("filament_cost"); + optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + this->update_dirty(); + this->on_value_change(opt_key, value); + + if (opt_key == "filament_colour") + { + const Preset& printer_preset = m_preset_bundle->printers.get_edited_preset(); + const std::vector& colors = static_cast( + printer_preset.config.option("extruder_colour"))->values; + for (const std::string& color : colors) + if (color.empty()) { + // update scene + wxGetApp().plater()->update(); + break; + } + } + }; + optgroup = page->new_optgroup(_(L("Temperature")) + wxString(" °C", wxConvUTF8)); Line line = { _(L("Extruder")), "" }; line.append_option(optgroup->get_option("first_layer_temperature")); From 7706a5be3e596a8271f7fb69e76f4aacfbcaf292 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 19 Aug 2019 17:19:21 +0200 Subject: [PATCH 27/48] Fixed #2738 + Added update for plater config option "filament_colour", when we have multiple extruder print. --- src/slic3r/GUI/Plater.cpp | 24 ++++++++++++++++++++++++ src/slic3r/GUI/Tab.cpp | 18 ------------------ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 97a1da2728..71d8e39102 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4602,6 +4602,30 @@ void Plater::on_config_change(const DynamicPrintConfig &config) bool update_scheduled = false; bool bed_shape_changed = false; for (auto opt_key : p->config->diff(config)) { + if (opt_key == "filament_colour") + { + update_scheduled = true; // update should be scheduled (for update 3DScene) #2738 + + /* There is a case, when we use filament_color instead of extruder_color (when extruder_color == ""). + * Thus plater config option "filament_colour" should be filled with filament_presets values. + * Otherwise, on 3dScene will be used last edited filament color for all volumes with extruder_color == "". + */ + const std::vector filament_presets = wxGetApp().preset_bundle->filament_presets; + if (filament_presets.size() > 1 && + p->config->option(opt_key)->values.size() != config.option(opt_key)->values.size()) + { + const PresetCollection& filaments = wxGetApp().preset_bundle->filaments; + std::vector filament_colors; + filament_colors.reserve(filament_presets.size()); + + for (const std::string& filament_preset : filament_presets) + filament_colors.push_back(filaments.find_preset(filament_preset, true)->config.opt_string("filament_colour", (unsigned)0)); + + p->config->option(opt_key)->values = filament_colors; + continue; + } + } + p->config->set_key_value(opt_key, config.option(opt_key)->clone()); if (opt_key == "printer_technology") this->set_printer_technology(config.opt_enum(opt_key)); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 22c5a548a5..4afd3a1163 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1621,24 +1621,6 @@ void TabFilament::build() optgroup->append_single_option_line("filament_density"); optgroup->append_single_option_line("filament_cost"); - optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { - this->update_dirty(); - this->on_value_change(opt_key, value); - - if (opt_key == "filament_colour") - { - const Preset& printer_preset = m_preset_bundle->printers.get_edited_preset(); - const std::vector& colors = static_cast( - printer_preset.config.option("extruder_colour"))->values; - for (const std::string& color : colors) - if (color.empty()) { - // update scene - wxGetApp().plater()->update(); - break; - } - } - }; - optgroup = page->new_optgroup(_(L("Temperature")) + wxString(" °C", wxConvUTF8)); Line line = { _(L("Extruder")), "" }; line.append_option(optgroup->get_option("first_layer_temperature")); From 1fc05bbf00c8c5574f4ba06b9ec735a9954c9869 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Sun, 11 Aug 2019 18:57:33 +0200 Subject: [PATCH 28/48] ConfigWizard: Fix: Snapshot not being taken on user-requested Wizard run If the user launched Wizard from the menu and checked the reset checkbox, snapshot was not taken in case no new bundles were to be installed from resources (ie. most of the time). Snapshot is now taken as appropriate. --- src/slic3r/GUI/ConfigWizard.cpp | 33 +++++++++++++++++++++++++----- src/slic3r/Utils/PresetUpdater.cpp | 10 +++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 6a70cb9fdb..0115ff5f9c 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -25,6 +25,7 @@ #include "PresetBundle.hpp" #include "GUI.hpp" #include "GUI_Utils.hpp" +#include "slic3r/Config/Snapshot.hpp" #include "slic3r/Utils/PresetUpdater.hpp" @@ -32,6 +33,10 @@ namespace Slic3r { namespace GUI { +using Config::Snapshot; +using Config::SnapshotDB; + + // Printer model picker GUI control struct PrinterPickerEvent : public wxEvent @@ -1025,15 +1030,33 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese // Decide whether to create snapshot based on run_reason and the reset profile checkbox bool snapshot = true; + Snapshot::Reason snapshot_reason = Snapshot::SNAPSHOT_UPGRADE; switch (run_reason) { - case ConfigWizard::RR_DATA_EMPTY: snapshot = false; break; - case ConfigWizard::RR_DATA_LEGACY: snapshot = true; break; - case ConfigWizard::RR_DATA_INCOMPAT: snapshot = false; break; // In this case snapshot is done by PresetUpdater with the appropriate reason - case ConfigWizard::RR_USER: snapshot = page_welcome->reset_user_profile(); break; + case ConfigWizard::RR_DATA_EMPTY: + snapshot = false; + break; + case ConfigWizard::RR_DATA_LEGACY: + snapshot = true; + break; + case ConfigWizard::RR_DATA_INCOMPAT: + // In this case snapshot has already been taken by + // PresetUpdater with the appropriate reason + snapshot = false; + break; + case ConfigWizard::RR_USER: + snapshot = page_welcome->reset_user_profile(); + snapshot_reason = Snapshot::SNAPSHOT_USER; + break; } + + if (snapshot) { + SnapshotDB::singleton().take_snapshot(*app_config, snapshot_reason); + } + if (install_bundles.size() > 0) { // Install bundles from resources. - updater->install_bundles_rsrc(std::move(install_bundles), snapshot); + // Don't create snapshot - we've already done that above if applicable. + updater->install_bundles_rsrc(std::move(install_bundles), false); } else { BOOST_LOG_TRIVIAL(info) << "No bundles need to be installed from resources"; } diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 589db36dce..d55063c7b5 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -35,6 +35,10 @@ using Slic3r::GUI::Config::Snapshot; using Slic3r::GUI::Config::SnapshotDB; + +// FIXME: Incompat bundle resolution doesn't deal with inherited user presets + + namespace Slic3r { @@ -624,11 +628,17 @@ PresetUpdater::UpdateResult PresetUpdater::config_update() const const auto res = dlg.ShowModal(); if (res == wxID_REPLACE) { BOOST_LOG_TRIVIAL(info) << "User wants to re-configure..."; + + // This effectively removes the incompatible bundles: + // (snapshot is taken beforehand) p->perform_updates(std::move(updates)); + GUI::ConfigWizard wizard(nullptr, GUI::ConfigWizard::RR_DATA_INCOMPAT); + if (! wizard.run(GUI::wxGetApp().preset_bundle, this)) { return R_INCOMPAT_EXIT; } + GUI::wxGetApp().load_current_presets(); return R_INCOMPAT_CONFIGURED; } else { From 52c24a16624dc93d10fc01bcbb9abcb3630bbadb Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 20 Aug 2019 13:01:01 +0200 Subject: [PATCH 29/48] Set list manipulation action on LeftButton too Note: Doesn't work under OSX --- src/slic3r/GUI/GUI_ObjectList.cpp | 45 ++++++++++++++++++++----------- src/slic3r/GUI/GUI_ObjectList.hpp | 1 + 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 3d5efe63fc..0f1861550f 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -134,7 +134,11 @@ ObjectList::ObjectList(wxWindow* parent) : selection_changed(); #ifndef __WXMSW__ set_tooltip_for_item(get_mouse_position_in_control()); -#endif //__WXMSW__ +#endif //__WXMSW__ + +#ifndef __WXOSX__ + list_manipulation(); +#endif //__WXOSX__ }); #ifdef __WXOSX__ @@ -169,7 +173,7 @@ ObjectList::ObjectList(wxWindow* parent) : #ifdef __WXMSW__ GetMainWindow()->Bind(wxEVT_MOTION, [this](wxMouseEvent& event) { - set_tooltip_for_item(/*event.GetPosition()*/get_mouse_position_in_control()); + set_tooltip_for_item(get_mouse_position_in_control()); event.Skip(); }); #endif //__WXMSW__ @@ -330,28 +334,34 @@ void ObjectList::set_tooltip_for_item(const wxPoint& pt) * Just this->SetToolTip(tooltip) => has no effect. */ - if (!item) + if (!item || GetSelectedItemsCount() > 1) { GetMainWindow()->SetToolTip(""); // hide tooltip return; } - if (col->GetTitle() == _(L("Editing")) && GetSelectedItemsCount()<2) - GetMainWindow()->SetToolTip(_(L("Right button click the icon to change the object settings"))); - else if (col->GetTitle() == _("Name")) - { -#ifdef __WXMSW__ - if (pt.x < 2 * wxGetApp().em_unit() || pt.x > 4 * wxGetApp().em_unit()) { - GetMainWindow()->SetToolTip(""); // hide tooltip - return; - } + wxString tooltip = ""; + + if (col->GetTitle() == _(L("Editing"))) +#ifdef __WXOSX__ + tooltip = _(L("Right button click the icon to change the object settings")); +#else + tooltip = _(L("Click the icon to change the object settings")); #endif //__WXMSW__ + else if (col->GetTitle() == " ") +#ifdef __WXOSX__ + tooltip = _(L("Right button click the icon to change the object printable property")); +#else + tooltip = _(L("Click the icon to change the object printable property")); +#endif //__WXMSW__ + else if (col->GetTitle() == _("Name") && (pt.x >= 2 * wxGetApp().em_unit() && pt.x <= 4 * wxGetApp().em_unit())) + { int obj_idx, vol_idx; get_selected_item_indexes(obj_idx, vol_idx, item); - GetMainWindow()->SetToolTip(get_mesh_errors_list(obj_idx, vol_idx)); + tooltip = get_mesh_errors_list(obj_idx, vol_idx); } - else - GetMainWindow()->SetToolTip(""); // hide tooltip + + GetMainWindow()->SetToolTip(tooltip); } wxPoint ObjectList::get_mouse_position_in_control() @@ -744,6 +754,11 @@ void ObjectList::OnChar(wxKeyEvent& event) #endif /* __WXOSX__ */ void ObjectList::OnContextMenu(wxDataViewEvent&) +{ + list_manipulation(); +} + +void ObjectList::list_manipulation() { wxDataViewItem item; wxDataViewColumn* col; diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index bdec060818..62003e5571 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -358,6 +358,7 @@ private: // void OnChar(wxKeyEvent& event); #endif /* __WXOSX__ */ void OnContextMenu(wxDataViewEvent &event); + void list_manipulation(); void OnBeginDrag(wxDataViewEvent &event); void OnDropPossible(wxDataViewEvent &event); From 53939796a653d99961fff05f32be275ef05e01ce Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 20 Aug 2019 14:22:31 +0200 Subject: [PATCH 30/48] GCode.cpp: Fix of temperature change before print Function set_extruder can be called before moving to the first layer, m_layer_index is then -1. We definitely don't want to set temperature for second layer in that case. --- src/libslic3r/GCode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 7a6f686dfc..433167e895 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2887,7 +2887,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z) // Set the temperature if the wipe tower didn't (not needed for non-single extruder MM) if (m_config.single_extruder_multi_material && !m_config.wipe_tower) { - int temp = (m_layer_index == 0 ? m_config.first_layer_temperature.get_at(extruder_id) : + int temp = (m_layer_index <= 0 ? m_config.first_layer_temperature.get_at(extruder_id) : m_config.temperature.get_at(extruder_id)); gcode += m_writer.set_temperature(temp, false); From 03079d49282fa9328ec78862372ec1cba855f8f2 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 20 Aug 2019 15:12:32 +0200 Subject: [PATCH 31/48] avrdude: Fix: Generate the embedded conf in the bin dir, remove from repo The generated file avrdude-slic3r.conf.h is not kept in repo any longer - it was causing trouble for git diffing. It's now generated in $CMAKE_CURRENT_BINARY_DIR and included from there. The file embeds avrdude-slic3r.conf so that the conf doesn't need to be loaded from disk. --- src/avrdude/CMakeLists.txt | 9 +- src/avrdude/avrdude-slic3r.conf.h | 1188 ----------------------------- src/avrdude/conf-generate.cpp | 2 +- 3 files changed, 7 insertions(+), 1192 deletions(-) delete mode 100644 src/avrdude/avrdude-slic3r.conf.h diff --git a/src/avrdude/CMakeLists.txt b/src/avrdude/CMakeLists.txt index e6748a5aa2..8897200211 100644 --- a/src/avrdude/CMakeLists.txt +++ b/src/avrdude/CMakeLists.txt @@ -85,13 +85,13 @@ add_executable(avrdude-conf-gen conf-generate.cpp) # Config file embedding add_custom_command( DEPENDS avrdude-conf-gen ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf - OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf.h - COMMAND $ avrdude-slic3r.conf avrdude_slic3r_conf avrdude-slic3r.conf.h + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h + COMMAND $ avrdude-slic3r.conf avrdude_slic3r_conf ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) add_custom_target(gen_conf_h - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf.h + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h ) add_library(avrdude STATIC ${AVRDUDE_SOURCES}) @@ -103,6 +103,9 @@ target_link_libraries(avrdude-slic3r avrdude) encoding_check(avrdude) encoding_check(avrdude-slic3r) +# Make avrdude-slic3r.conf.h includable: +target_include_directories(avrdude SYSTEM PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + if (WIN32) target_compile_definitions(avrdude PRIVATE WIN32NATIVE=1) if(MSVC) diff --git a/src/avrdude/avrdude-slic3r.conf.h b/src/avrdude/avrdude-slic3r.conf.h deleted file mode 100644 index 905b14ee8c..0000000000 --- a/src/avrdude/avrdude-slic3r.conf.h +++ /dev/null @@ -1,1188 +0,0 @@ -/* WARN: This file is auto-generated from `avrdude-slic3r.conf` */ -const unsigned char avrdude_slic3r_conf[] = { - 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, - 0x20, 0x61, 0x20, 0x62, 0x61, 0x73, 0x69, 0x63, 0x20, 0x6d, 0x69, 0x6e, - 0x69, 0x6d, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, - 0x66, 0x69, 0x6c, 0x65, 0x20, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, - 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, - 0x76, 0x72, 0x64, 0x75, 0x64, 0x65, 0x2d, 0x73, 0x6c, 0x69, 0x63, 0x33, - 0x72, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x0a, 0x23, 0x20, 0x73, - 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x63, 0x61, - 0x6e, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, - 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x20, 0x6d, - 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x4f, - 0x6e, 0x6c, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x74, 0x73, - 0x20, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x20, 0x66, 0x6f, 0x72, 0x20, - 0x50, 0x72, 0x75, 0x73, 0x61, 0x33, 0x44, 0x20, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x63, 0x6f, 0x70, - 0x69, 0x65, 0x64, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x66, 0x72, 0x6f, - 0x6d, 0x20, 0x61, 0x76, 0x72, 0x64, 0x75, 0x64, 0x65, 0x2e, 0x63, 0x6f, - 0x6e, 0x66, 0x0a, 0x23, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x65, 0x65, 0x64, - 0x65, 0x64, 0x2c, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, - 0x61, 0x6e, 0x20, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, - 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, - 0x61, 0x76, 0x72, 0x64, 0x75, 0x64, 0x65, 0x2d, 0x73, 0x6c, 0x69, 0x63, - 0x33, 0x72, 0x0a, 0x23, 0x20, 0x76, 0x69, 0x61, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x2d, 0x43, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2d, - 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x0a, 0x23, 0x0a, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, - 0x6d, 0x65, 0x72, 0x0a, 0x20, 0x20, 0x69, 0x64, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x77, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x3b, 0x0a, - 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x57, - 0x69, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x79, - 0x70, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x77, 0x69, 0x72, 0x69, 0x6e, - 0x67, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, - 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x3b, 0x0a, 0x3b, 0x0a, 0x0a, 0x70, - 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x0a, 0x20, 0x20, - 0x69, 0x64, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x61, 0x72, 0x64, - 0x75, 0x69, 0x6e, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, 0x73, - 0x63, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x41, 0x72, 0x64, 0x75, 0x69, 0x6e, - 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x22, 0x3b, - 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x72, - 0x69, 0x61, 0x6c, 0x3b, 0x0a, 0x3b, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x0a, 0x20, 0x20, 0x69, 0x64, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x61, 0x76, 0x72, 0x31, 0x30, 0x39, - 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, 0x20, 0x3d, - 0x20, 0x22, 0x41, 0x74, 0x6d, 0x65, 0x6c, 0x20, 0x41, 0x70, 0x70, 0x4e, - 0x6f, 0x74, 0x65, 0x20, 0x41, 0x56, 0x52, 0x31, 0x30, 0x39, 0x20, 0x42, - 0x6f, 0x6f, 0x74, 0x20, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x22, 0x3b, - 0x0a, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x22, - 0x62, 0x75, 0x74, 0x74, 0x65, 0x72, 0x66, 0x6c, 0x79, 0x22, 0x3b, 0x0a, - 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x72, 0x69, - 0x61, 0x6c, 0x3b, 0x0a, 0x3b, 0x0a, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, - 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x32, 0x35, 0x36, 0x30, 0x0a, 0x23, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x6d, 0x32, 0x35, 0x36, 0x30, - 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x32, 0x35, 0x36, - 0x30, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x30, 0x78, 0x31, 0x65, 0x20, 0x30, 0x78, 0x39, 0x38, - 0x20, 0x30, 0x78, 0x30, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, - 0x61, 0x73, 0x5f, 0x6a, 0x74, 0x61, 0x67, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x79, 0x65, 0x73, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x73, 0x74, 0x6b, 0x35, 0x30, 0x30, 0x5f, 0x64, 0x65, - 0x76, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, - 0x42, 0x32, 0x3b, 0x0a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x61, 0x76, 0x72, - 0x39, 0x31, 0x30, 0x5f, 0x64, 0x65, 0x76, 0x63, 0x6f, 0x64, 0x65, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x33, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x5f, 0x65, 0x72, 0x61, 0x73, 0x65, - 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x6c, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x30, 0x78, 0x44, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x62, 0x73, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x41, 0x30, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x64, 0x65, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x70, 0x67, 0x6d, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, - 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, - 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x22, - 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, - 0x69, 0x70, 0x5f, 0x65, 0x72, 0x61, 0x73, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x3b, 0x0a, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x63, 0x6d, 0x64, 0x65, 0x78, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x6c, 0x6f, 0x6f, 0x70, 0x73, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x62, 0x79, 0x74, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, - 0x6c, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, - 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x65, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x73, 0x74, 0x64, 0x65, 0x6c, 0x61, - 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, - 0x74, 0x61, 0x63, 0x6b, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x30, 0x45, 0x2c, - 0x20, 0x30, 0x78, 0x31, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x46, 0x2c, - 0x20, 0x30, 0x78, 0x31, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x45, 0x2c, - 0x20, 0x30, 0x78, 0x33, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x46, 0x2c, - 0x20, 0x30, 0x78, 0x33, 0x46, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x78, 0x34, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x35, - 0x45, 0x2c, 0x20, 0x30, 0x78, 0x34, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x35, - 0x46, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x37, - 0x45, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x37, - 0x46, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, - 0x78, 0x36, 0x36, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x36, 0x2c, 0x20, 0x30, - 0x78, 0x36, 0x37, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x37, 0x2c, 0x20, 0x30, - 0x78, 0x36, 0x41, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x41, 0x2c, 0x20, 0x30, - 0x78, 0x36, 0x42, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x42, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x42, 0x45, 0x2c, - 0x20, 0x30, 0x78, 0x46, 0x44, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, - 0x20, 0x30, 0x78, 0x30, 0x31, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, - 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, - 0x20, 0x30, 0x78, 0x30, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, - 0x76, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x6d, 0x6f, - 0x64, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, - 0x61, 0x74, 0x63, 0x68, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x73, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x76, 0x74, - 0x67, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x77, - 0x65, 0x72, 0x6f, 0x66, 0x66, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x35, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x64, 0x65, 0x6c, 0x61, - 0x79, 0x6d, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, - 0x74, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x75, 0x73, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x68, 0x76, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x74, 0x61, 0x62, - 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, - 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x65, - 0x72, 0x61, 0x73, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, 0x64, - 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x63, 0x68, 0x69, 0x70, 0x65, 0x72, 0x61, 0x73, 0x65, 0x70, 0x6f, 0x6c, - 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x31, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x66, 0x75, 0x73, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, - 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x66, 0x75, 0x73, - 0x65, 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, - 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6c, 0x6f, 0x63, 0x6b, 0x70, 0x75, 0x6c, - 0x73, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, - 0x6c, 0x6f, 0x63, 0x6b, 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x69, 0x64, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x30, 0x78, 0x33, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, - 0x6d, 0x63, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, 0x37, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x61, 0x6d, 0x70, 0x7a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x33, 0x62, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x66, 0x75, 0x6c, 0x6c, 0x70, - 0x61, 0x67, 0x65, 0x62, 0x69, 0x74, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x6f, 0x63, 0x64, 0x72, 0x65, 0x76, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x34, 0x3b, - 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, - 0x20, 0x22, 0x65, 0x65, 0x70, 0x72, 0x6f, 0x6d, 0x22, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x6e, 0x6f, 0x3b, 0x20, 0x2f, 0x2a, 0x20, 0x6c, 0x65, 0x61, 0x76, 0x65, - 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x22, 0x6e, 0x6f, 0x22, 0x20, 0x2a, - 0x2f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, - 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x38, 0x3b, 0x20, 0x20, 0x2f, 0x2a, 0x20, 0x66, - 0x6f, 0x72, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x20, - 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x69, 0x6e, 0x67, 0x20, - 0x2a, 0x2f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x34, 0x30, 0x39, 0x36, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, - 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, - 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, - 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, - 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x31, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, - 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, - 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, - 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, - 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, - 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, - 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, - 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, - 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, - 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, - 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, - 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x20, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, - 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, - 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x6f, 0x20, 0x3d, 0x20, 0x22, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, - 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, - 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x77, 0x72, 0x69, - 0x74, 0x65, 0x70, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, - 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, - 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x65, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, 0x3b, 0x0a, - 0x20, 0x20, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x31, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x72, - 0x65, 0x61, 0x64, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x32, - 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, - 0x22, 0x66, 0x6c, 0x61, 0x73, 0x68, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x79, 0x65, - 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x36, 0x32, 0x31, 0x34, 0x34, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, - 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x6e, 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x67, 0x65, - 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, - 0x32, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x34, 0x35, 0x30, 0x30, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, - 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, - 0x3d, 0x20, 0x34, 0x35, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, - 0x5f, 0x70, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, - 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x32, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, - 0x5f, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x31, 0x35, 0x20, 0x61, - 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, - 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, - 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, - 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, - 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, - 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, - 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, - 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x68, 0x69, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x61, 0x31, 0x35, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, - 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, - 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, - 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, - 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, - 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, - 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, - 0x67, 0x65, 0x5f, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, - 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, - 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, - 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, - 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, - 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x68, 0x69, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, - 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, - 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, - 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, - 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x70, 0x61, 0x67, - 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x61, 0x31, 0x35, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, - 0x31, 0x33, 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, - 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, - 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x3b, 0x0a, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, - 0x64, 0x5f, 0x65, 0x78, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, 0x36, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x65, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, 0x3b, 0x0a, - 0x20, 0x20, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x31, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, - 0x20, 0x72, 0x65, 0x61, 0x64, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x3d, - 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, - 0x79, 0x20, 0x22, 0x6c, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, - 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, - 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, - 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, - 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, - 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x68, 0x66, 0x75, - 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, - 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x69, 0x20, - 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, - 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, - 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, - 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, - 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, - 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, - 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, - 0x79, 0x20, 0x22, 0x65, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, - 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, - 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, - 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, - 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x6c, 0x6f, 0x63, - 0x6b, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, - 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, - 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x31, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x31, 0x20, - 0x31, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, - 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, - 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, - 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, - 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x63, 0x61, 0x6c, 0x69, 0x62, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x20, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, - 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x78, 0x20, 0x61, 0x31, 0x20, 0x61, 0x30, 0x20, 0x20, - 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, - 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, - 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x20, - 0x20, 0x3b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x23, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x23, 0x20, - 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x33, 0x32, 0x75, 0x34, 0x0a, 0x23, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x6d, 0x33, 0x32, 0x75, 0x34, - 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x22, 0x41, 0x54, 0x6d, 0x65, 0x67, 0x61, 0x33, 0x32, 0x55, - 0x34, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x30, 0x78, 0x31, 0x65, 0x20, 0x30, 0x78, 0x39, 0x35, - 0x20, 0x30, 0x78, 0x38, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, - 0x73, 0x62, 0x70, 0x69, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x32, 0x66, 0x66, 0x34, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x61, 0x73, 0x5f, 0x6a, 0x74, - 0x61, 0x67, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x79, 0x65, 0x73, 0x3b, 0x0a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x73, - 0x74, 0x6b, 0x35, 0x30, 0x30, 0x5f, 0x64, 0x65, 0x76, 0x63, 0x6f, 0x64, - 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x42, 0x32, 0x3b, 0x0a, - 0x23, 0x20, 0x20, 0x20, 0x20, 0x61, 0x76, 0x72, 0x39, 0x31, 0x30, 0x5f, - 0x64, 0x65, 0x76, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x30, 0x78, 0x34, 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, - 0x69, 0x70, 0x5f, 0x65, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x64, 0x65, 0x6c, - 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x6c, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, - 0x44, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x73, 0x32, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x30, 0x78, 0x41, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x64, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x64, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, - 0x67, 0x6d, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x3b, - 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x5f, 0x65, - 0x72, 0x61, 0x73, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x32, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, - 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x31, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6d, 0x64, - 0x65, 0x78, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x32, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x79, 0x6e, - 0x63, 0x68, 0x6c, 0x6f, 0x6f, 0x70, 0x73, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x33, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x79, 0x74, - 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, 0x6c, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, 0x33, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x70, 0x72, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x70, 0x6f, 0x73, 0x74, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6c, - 0x6c, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x31, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x70, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x73, 0x74, 0x61, 0x63, 0x6b, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x78, 0x30, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x31, - 0x45, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x31, - 0x46, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x33, - 0x45, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x33, - 0x46, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, - 0x78, 0x34, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x35, 0x45, 0x2c, 0x20, 0x30, - 0x78, 0x34, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x35, 0x46, 0x2c, 0x20, 0x30, - 0x78, 0x36, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x45, 0x2c, 0x20, 0x30, - 0x78, 0x36, 0x46, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x46, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x78, 0x36, 0x36, 0x2c, - 0x20, 0x30, 0x78, 0x37, 0x36, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x37, 0x2c, - 0x20, 0x30, 0x78, 0x37, 0x37, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x41, 0x2c, - 0x20, 0x30, 0x78, 0x37, 0x41, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x42, 0x2c, - 0x20, 0x30, 0x78, 0x37, 0x42, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x78, 0x42, 0x45, 0x2c, 0x20, 0x30, 0x78, 0x46, - 0x44, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, - 0x31, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, - 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x76, 0x65, 0x6e, 0x74, - 0x65, 0x72, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x6d, 0x6f, 0x64, 0x65, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x61, 0x74, 0x63, 0x68, - 0x63, 0x79, 0x63, 0x6c, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x76, 0x74, 0x67, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x6f, 0x66, - 0x66, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x31, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, - 0x65, 0x73, 0x65, 0x74, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x6d, 0x73, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x64, 0x65, 0x6c, - 0x61, 0x79, 0x75, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x76, 0x6c, - 0x65, 0x61, 0x76, 0x65, 0x73, 0x74, 0x61, 0x62, 0x64, 0x65, 0x6c, 0x61, - 0x79, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x35, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, 0x65, 0x72, 0x61, 0x73, 0x65, - 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, - 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x70, - 0x65, 0x72, 0x61, 0x73, 0x65, 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, - 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x66, 0x75, - 0x73, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, - 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, - 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x66, 0x75, 0x73, 0x65, 0x70, 0x6f, 0x6c, - 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x35, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, - 0x6d, 0x6c, 0x6f, 0x63, 0x6b, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x77, 0x69, - 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6c, 0x6f, 0x63, 0x6b, - 0x70, 0x6f, 0x6c, 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, - 0x3d, 0x20, 0x35, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x64, - 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x33, 0x31, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, 0x6d, 0x63, 0x72, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x35, 0x37, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x61, 0x6d, 0x70, 0x7a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x30, 0x78, 0x33, 0x62, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x6c, - 0x6c, 0x6f, 0x77, 0x66, 0x75, 0x6c, 0x6c, 0x70, 0x61, 0x67, 0x65, 0x62, - 0x69, 0x74, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x20, 0x3d, 0x20, 0x6e, - 0x6f, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x63, 0x64, 0x72, - 0x65, 0x76, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x65, 0x65, - 0x70, 0x72, 0x6f, 0x6d, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6e, 0x6f, 0x3b, 0x20, - 0x2f, 0x2a, 0x20, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, 0x69, - 0x73, 0x20, 0x22, 0x6e, 0x6f, 0x22, 0x20, 0x2a, 0x2f, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x34, 0x3b, 0x20, 0x20, 0x2f, 0x2a, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, - 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x20, 0x70, 0x72, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x2a, 0x2f, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x31, 0x30, 0x32, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, - 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, - 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, - 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, - 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, - 0x70, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, - 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, - 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x61, 0x31, 0x30, - 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, - 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, - 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, - 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, - 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, - 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, - 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x20, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, - 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, - 0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, 0x65, - 0x5f, 0x6c, 0x6f, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x31, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, - 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, - 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x70, 0x61, - 0x67, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, - 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, - 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, - 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x3b, - 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x30, 0x3b, 0x0a, - 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x69, 0x7a, 0x65, 0x20, - 0x3d, 0x20, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x66, 0x6c, 0x61, - 0x73, 0x68, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x70, 0x61, 0x67, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x79, 0x65, 0x73, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x33, 0x32, 0x37, 0x36, 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, - 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x32, - 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, - 0x75, 0x6d, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, - 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, - 0x34, 0x35, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, - 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x34, 0x35, 0x30, 0x30, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, - 0x61, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x31, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x62, 0x61, - 0x63, 0x6b, 0x5f, 0x70, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x30, 0x78, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6c, 0x6f, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, - 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, - 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, - 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, - 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, - 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, - 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, - 0x68, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, - 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, 0x61, 0x31, 0x32, 0x20, 0x20, 0x20, - 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, 0x20, 0x20, 0x61, 0x39, - 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, - 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, - 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, - 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, - 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x20, 0x6f, - 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x6f, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, - 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, 0x61, 0x31, 0x20, 0x20, 0x61, - 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x69, 0x20, 0x20, - 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, - 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x70, 0x61, 0x67, - 0x65, 0x5f, 0x68, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x61, 0x35, 0x20, 0x20, 0x61, 0x34, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x61, 0x33, 0x20, 0x20, 0x61, 0x32, 0x20, 0x20, - 0x61, 0x31, 0x20, 0x20, 0x61, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, - 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, - 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x20, 0x20, 0x20, 0x69, 0x22, 0x3b, - 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, - 0x69, 0x74, 0x65, 0x70, 0x61, 0x67, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x22, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, - 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, - 0x20, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x61, 0x31, - 0x35, 0x20, 0x61, 0x31, 0x34, 0x20, 0x61, 0x31, 0x33, 0x20, 0x61, 0x31, - 0x32, 0x20, 0x20, 0x20, 0x20, 0x61, 0x31, 0x31, 0x20, 0x61, 0x31, 0x30, - 0x20, 0x20, 0x61, 0x39, 0x20, 0x20, 0x61, 0x38, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x20, 0x61, 0x37, 0x20, 0x20, 0x61, 0x36, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, - 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x20, 0x78, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x6f, - 0x64, 0x65, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x30, 0x78, 0x34, 0x31, - 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x20, 0x20, - 0x3d, 0x20, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x31, 0x32, 0x38, 0x3b, 0x0a, - 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, - 0x3d, 0x20, 0x32, 0x35, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, - 0x72, 0x79, 0x20, 0x22, 0x6c, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, - 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, - 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, - 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, - 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, - 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x68, 0x66, - 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, - 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, - 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x69, - 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, - 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, - 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, - 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, - 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, - 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, - 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, - 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, - 0x72, 0x79, 0x20, 0x22, 0x65, 0x66, 0x75, 0x73, 0x65, 0x22, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, - 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x20, 0x30, 0x20, 0x31, - 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, - 0x31, 0x20, 0x30, 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, - 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, - 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, - 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, - 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x6c, 0x6f, - 0x63, 0x6b, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, - 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x31, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x22, - 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, - 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x22, 0x31, - 0x20, 0x30, 0x20, 0x31, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x31, 0x20, - 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x22, 0x2c, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x20, 0x31, - 0x20, 0x31, 0x20, 0x69, 0x20, 0x69, 0x20, 0x20, 0x69, 0x20, 0x69, 0x20, - 0x69, 0x20, 0x69, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x69, 0x6e, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, - 0x64, 0x65, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, - 0x78, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, - 0x79, 0x20, 0x3d, 0x20, 0x39, 0x30, 0x30, 0x30, 0x3b, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, - 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x63, 0x61, 0x6c, 0x69, 0x62, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x61, - 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x20, - 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, - 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x78, - 0x20, 0x78, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x30, 0x20, - 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, - 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, - 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x20, 0x6f, 0x22, 0x3b, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x20, 0x22, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x33, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, - 0x61, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x3d, 0x20, 0x22, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, - 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, - 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, - 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x20, - 0x20, 0x78, 0x20, 0x20, 0x78, 0x20, 0x61, 0x31, 0x20, 0x61, 0x30, 0x20, - 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, - 0x20, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, 0x6f, 0x20, 0x20, - 0x6f, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x0a, - 0x20, 0x20, 0x3b, 0x0a, 0x0a, 0x0a, - 0, 0 -}; -const size_t avrdude_slic3r_conf_size = 14178; -const size_t avrdude_slic3r_conf_size_yy = 14180; diff --git a/src/avrdude/conf-generate.cpp b/src/avrdude/conf-generate.cpp index 1e05db5cea..e61f42eb4b 100644 --- a/src/avrdude/conf-generate.cpp +++ b/src/avrdude/conf-generate.cpp @@ -21,7 +21,7 @@ int main(int argc, char const *argv[]) std::cerr << "Cannot read file: " << filename_in << std::endl; } - std::fstream output(filename_out, std::ios::out | std::ios::trunc | std::ios::binary); + std::fstream output(filename_out, std::ios::out | std::ios::trunc); if (!output.good()) { std::cerr << "Cannot open output file: " << filename_out << std::endl; } From 448d773da0e6d9ee31448d8a8817971269f59d7f Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 20 Aug 2019 15:26:57 +0200 Subject: [PATCH 32/48] Fixed default transparency for ColorPicker from sidebar (was appeared under OSX for empty extruder color). + Fixed wrong getting of instance printable value inside add_object_to_list() --- src/slic3r/GUI/GUI_ObjectList.cpp | 4 ++-- src/slic3r/GUI/Plater.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 0f1861550f..e0bdd26df9 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2306,14 +2306,14 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed) { std::vector print_idicator(model_object->instances.size()); for (int i = 0; i < model_object->instances.size(); ++i) - print_idicator[i] = model_object->instances[i]->is_printable(); + print_idicator[i] = model_object->instances[i]->printable; const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx); m_objects_model->AddInstanceChild(object_item, print_idicator); Expand(m_objects_model->GetInstanceRootItem(object_item)); } else - m_objects_model->SetPrintableState(model_object->instances[0]->is_printable() ? piPrintable : piUnprintable, obj_idx); + m_objects_model->SetPrintableState(model_object->instances[0]->printable ? piPrintable : piUnprintable, obj_idx); // add settings to the object, if it has those add_settings_item(item, &model_object->config); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 71d8e39102..476caead14 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -290,7 +290,7 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * auto colors = static_cast(cfg->option("extruder_colour")->clone()); wxColour clr(colors->values[extruder_idx]); if (!clr.IsOk()) - clr = wxTransparentColour; + clr = wxColour(0,0,0); // Don't set alfa to transparence auto data = new wxColourData(); data->SetChooseFull(1); From 7c94db063488092607877a54ed3e4f0cdac02745 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 20 Aug 2019 15:49:32 +0200 Subject: [PATCH 33/48] Adding new sla material parameters: (initial) exposition min/max --- src/libslic3r/PrintConfig.cpp | 32 ++++++++++++++++++++++ src/libslic3r/PrintConfig.hpp | 8 ++++++ src/libslic3r/SLAPrint.cpp | 18 +++++++++++++ src/slic3r/GUI/Preset.cpp | 3 ++- src/slic3r/GUI/Tab.cpp | 51 +++++++++++++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 31de80e8be..037b248007 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2412,6 +2412,22 @@ void PrintConfigDef::init_sla_params() def->mode = comExpert; def->set_default_value(new ConfigOptionInt(10)); + def = this->add("exposure_time_min", coFloat); + def->label = L("Minimum exposure time"); + def->tooltip = L("Minimum exposure time"); + def->sidetext = L("s"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0)); + + def = this->add("exposure_time_max", coFloat); + def->label = L("Maximum exposure time"); + def->tooltip = L("Maximum exposure time"); + def->sidetext = L("s"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(100)); + def = this->add("exposure_time", coFloat); def->label = L("Exposure time"); def->tooltip = L("Exposure time"); @@ -2419,6 +2435,22 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->set_default_value(new ConfigOptionFloat(10)); + def = this->add("initial_exposure_time_min", coFloat); + def->label = L("Minimum initial exposure time"); + def->tooltip = L("Minimum initial exposure time"); + def->sidetext = L("s"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0)); + + def = this->add("initial_exposure_time_max", coFloat); + def->label = L("Maximum initial exposure time"); + def->tooltip = L("Maximum initial exposure time"); + def->sidetext = L("s"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(150)); + def = this->add("initial_exposure_time", coFloat); def->label = L("Initial exposure time"); def->tooltip = L("Initial exposure time"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 081f670e15..ca2a210f26 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1098,14 +1098,22 @@ class SLAMaterialConfig : public StaticPrintConfig STATIC_PRINT_CONFIG_CACHE(SLAMaterialConfig) public: ConfigOptionFloat initial_layer_height; + ConfigOptionFloat exposure_time_min; + ConfigOptionFloat exposure_time_max; ConfigOptionFloat exposure_time; + ConfigOptionFloat initial_exposure_time_min; + ConfigOptionFloat initial_exposure_time_max; ConfigOptionFloat initial_exposure_time; ConfigOptionFloats material_correction; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) { OPT_PTR(initial_layer_height); + OPT_PTR(exposure_time_min); + OPT_PTR(exposure_time_max); OPT_PTR(exposure_time); + OPT_PTR(initial_exposure_time_min); + OPT_PTR(initial_exposure_time_max); OPT_PTR(initial_exposure_time); OPT_PTR(material_correction); } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 1529f4bafc..8e99d6ddc5 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -692,6 +692,20 @@ std::string SLAPrint::validate() const } } + double expt_max = m_material_config.exposure_time_max.getFloat(); + double expt_min = m_material_config.exposure_time_min.getFloat(); + double expt_cur = m_material_config.exposure_time.getFloat(); + + if (expt_cur < expt_min || expt_cur > expt_max) + return L("Exposition time is out of predefined bounds."); + + double iexpt_max = m_material_config.initial_exposure_time_max.getFloat(); + double iexpt_min = m_material_config.initial_exposure_time_min.getFloat(); + double iexpt_cur = m_material_config.initial_exposure_time.getFloat(); + + if (iexpt_cur < iexpt_min || iexpt_cur > iexpt_max) + return L("Initial exposition time is out of predefined bounds."); + return ""; } @@ -1586,7 +1600,11 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector steps_rasterize = { + "exposure_time_min", + "exposure_time_max", "exposure_time", + "initial_exposure_time_min", + "initial_exposure_time_max", "initial_exposure_time", "display_width", "display_height", diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 833da238a5..82124761a5 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -500,7 +500,8 @@ const std::vector& Preset::sla_material_options() if (s_opts.empty()) { s_opts = { "initial_layer_height", - "exposure_time", "initial_exposure_time", + "exposure_time_min", "exposure_time_max", "exposure_time", + "initial_exposure_time_min", "initial_exposure_time_max", "initial_exposure_time", "material_correction", "material_notes", "default_sla_material_profile", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 4afd3a1163..188bb50cf0 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3614,7 +3614,11 @@ void TabSLAMaterial::build() optgroup->append_single_option_line("initial_layer_height"); optgroup = page->new_optgroup(_(L("Exposure"))); + optgroup->append_single_option_line("exposure_time_min"); + optgroup->append_single_option_line("exposure_time_max"); optgroup->append_single_option_line("exposure_time"); + optgroup->append_single_option_line("initial_exposure_time_min"); + optgroup->append_single_option_line("initial_exposure_time_max"); optgroup->append_single_option_line("initial_exposure_time"); optgroup = page->new_optgroup(_(L("Corrections"))); @@ -3679,11 +3683,58 @@ void TabSLAMaterial::reload_config() Tab::reload_config(); } + +namespace { + +enum e_cmp {EQUAL = 1, SMALLER = 2, GREATER = 4, SMALLER_EQ = 3, GREATER_EQ = 5}; + +void bound_check(Tab &tb, e_cmp cmp, const char *id, const char *boundid) +{ + double bound = tb.m_config->opt_float(boundid); + double value = tb.m_config->opt_float(id); + + auto boundlabel = tb.m_config->def()->get(boundid)->label; + auto valuelabel = tb.m_config->def()->get(id)->label; + + double ddiff = value - bound; + int diff = ddiff < 0 ? SMALLER : (std::abs(ddiff) < EPSILON ? EQUAL : GREATER); + + wxString fmt; + switch (cmp) { + case EQUAL: fmt = _(L("%s should be equal to %s")); break; + case SMALLER: fmt = _(L("%s should be smaller than %s")); break; + case GREATER: fmt = _(L("%s should be greater than %s")); break; + case SMALLER_EQ: fmt = _(L("%s should be smaller or equal to %s")); break; + case GREATER_EQ: fmt = _(L("%s should be greater or equal to %s")); break; + } + + if ((cmp | diff) != cmp) { + wxString msg_text = wxString::Format(fmt, valuelabel, boundlabel); + + wxMessageDialog dialog(tb.parent(), msg_text, + _(L("Value outside bounds")), + wxICON_WARNING | wxOK); + + DynamicPrintConfig new_conf = *tb.m_config; + if (dialog.ShowModal() == wxID_OK) + new_conf.set_key_value(id, new ConfigOptionFloat(bound)); + + tb.load_config(new_conf); + } +}; + +} + void TabSLAMaterial::update() { if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) return; + bound_check(*this, e_cmp::GREATER_EQ, "exposure_time", "exposure_time_min"); + bound_check(*this, e_cmp::SMALLER_EQ, "exposure_time", "exposure_time_max"); + bound_check(*this, e_cmp::GREATER_EQ, "initial_exposure_time", "initial_exposure_time_min"); + bound_check(*this, e_cmp::SMALLER_EQ, "initial_exposure_time", "initial_exposure_time_max"); + // #ys_FIXME. Just a template for this function // m_update_cnt++; // ! something to update From bafa4d6d1909c3e9541b349129e6929ee962368b Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 20 Aug 2019 16:00:26 +0200 Subject: [PATCH 34/48] Follow up: Adding new sla material parameters... Small fix for redundant operations. --- src/slic3r/GUI/Tab.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 188bb50cf0..0301653371 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3699,16 +3699,17 @@ void bound_check(Tab &tb, e_cmp cmp, const char *id, const char *boundid) double ddiff = value - bound; int diff = ddiff < 0 ? SMALLER : (std::abs(ddiff) < EPSILON ? EQUAL : GREATER); - wxString fmt; - switch (cmp) { - case EQUAL: fmt = _(L("%s should be equal to %s")); break; - case SMALLER: fmt = _(L("%s should be smaller than %s")); break; - case GREATER: fmt = _(L("%s should be greater than %s")); break; - case SMALLER_EQ: fmt = _(L("%s should be smaller or equal to %s")); break; - case GREATER_EQ: fmt = _(L("%s should be greater or equal to %s")); break; - } - if ((cmp | diff) != cmp) { + wxString fmt; + + switch (cmp) { + case EQUAL: fmt = _(L("%s should be equal to %s")); break; + case SMALLER: fmt = _(L("%s should be smaller than %s")); break; + case GREATER: fmt = _(L("%s should be greater than %s")); break; + case SMALLER_EQ: fmt = _(L("%s should be smaller or equal to %s")); break; + case GREATER_EQ: fmt = _(L("%s should be greater or equal to %s")); break; + } + wxString msg_text = wxString::Format(fmt, valuelabel, boundlabel); wxMessageDialog dialog(tb.parent(), msg_text, From fd3fe75d1ca4ddf1a36eb89d7210a4ec0e8f4afa Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 20 Aug 2019 16:19:30 +0200 Subject: [PATCH 35/48] Reworked the rename_file() function on Windows to work reliably and atomically. The code was taken from the llvm project, it is complex and hopefully it covers all the Windows file system quirks. Vojtech has highest hopes, that this will fix the various PrusaSlicer.ini file corruptions. Enabled the locales switching and error handling on Linux as well, where now the missing locales are reported and running the locale-gen tool is recommended. --- src/PrusaSlicer.cpp | 9 +- src/libslic3r/GCode.cpp | 2 +- src/libslic3r/GCodeTimeEstimator.cpp | 2 +- src/libslic3r/Utils.hpp | 2 +- src/libslic3r/utils.cpp | 288 ++++++++++++++++++++++----- src/slic3r/GUI/AppConfig.cpp | 7 +- 6 files changed, 248 insertions(+), 62 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 72cbe150fc..92ff65a843 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -66,7 +66,12 @@ int CLI::run(int argc, char **argv) boost::nowide::nowide_filesystem(); } catch (const std::runtime_error& ex) { std::string caption = std::string(SLIC3R_APP_NAME) + " Error"; - std::string text = std::string("An error occured while setting up locale.\n") + SLIC3R_APP_NAME + " will now terminate.\n\n" + ex.what(); + std::string text = std::string("An error occured while setting up locale.\n") + ( +#if !defined(_WIN32) && !defined(__APPLE__) + // likely some linux system + "You may need to reconfigure the missing locales, likely by running the \"locale-gen\"" and \"dpkg-reconfigure locales\" commands.\n" +#endif + SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what(); #ifdef SLIC3R_GUI if (m_actions.empty()) MessageBoxA(NULL, text.c_str(), caption.c_str(), MB_OK | MB_ICONERROR); @@ -426,7 +431,7 @@ int CLI::run(int argc, char **argv) outfile_final = sla_print.print_statistics().finalize_output_path(outfile); sla_print.export_raster(outfile_final); } - if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final) != 0) { + if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final)) { boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; return 1; } diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 7a6f686dfc..8a007023bb 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -607,7 +607,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ m_analyzer.reset(); } - if (rename_file(path_tmp, path) != 0) + if (rename_file(path_tmp, path)) throw std::runtime_error( std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' + "Is " + path_tmp + " locked?" + '\n'); diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 8a2e1266a8..a03d3c7c85 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -390,7 +390,7 @@ namespace Slic3r { fclose(out); in.close(); - if (rename_file(path_tmp, filename) != 0) + if (rename_file(path_tmp, filename)) throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' + "Is " + path_tmp + " locked?" + '\n'); diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index b19027826b..2b1fdb2417 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -61,7 +61,7 @@ extern std::string normalize_utf8_nfc(const char *src); // Safely rename a file even if the target exists. // On Windows, the file explorer (or anti-virus or whatever else) often locks the file // for a short while, so the file may not be movable. Retry while we see recoverable errors. -extern int rename_file(const std::string &from, const std::string &to); +extern std::error_code rename_file(const std::string &from, const std::string &to); // Copy a file, adjust the access attributes, so that the target is writable. extern int copy_file(const std::string &from, const std::string &to); diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 8fcd611acc..e26ed38394 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -173,67 +173,247 @@ const std::string& data_dir() return g_data_dir; } +#ifdef _WIN32 +// The following helpers are borrowed from the LLVM project https://github.com/llvm +namespace WindowsSupport +{ + template + class ScopedHandle { + typedef typename HandleTraits::handle_type handle_type; + handle_type Handle; + ScopedHandle(const ScopedHandle &other) = delete; + void operator=(const ScopedHandle &other) = delete; + public: + ScopedHandle() : Handle(HandleTraits::GetInvalid()) {} + explicit ScopedHandle(handle_type h) : Handle(h) {} + ~ScopedHandle() { if (HandleTraits::IsValid(Handle)) HandleTraits::Close(Handle); } + handle_type take() { + handle_type t = Handle; + Handle = HandleTraits::GetInvalid(); + return t; + } + ScopedHandle &operator=(handle_type h) { + if (HandleTraits::IsValid(Handle)) + HandleTraits::Close(Handle); + Handle = h; + return *this; + } + // True if Handle is valid. + explicit operator bool() const { return HandleTraits::IsValid(Handle) ? true : false; } + operator handle_type() const { return Handle; } + }; + + struct CommonHandleTraits { + typedef HANDLE handle_type; + static handle_type GetInvalid() { return INVALID_HANDLE_VALUE; } + static void Close(handle_type h) { ::CloseHandle(h); } + static bool IsValid(handle_type h) { return h != GetInvalid(); } + }; + + typedef ScopedHandle ScopedFileHandle; + + std::error_code map_windows_error(unsigned windows_error_code) + { + #define MAP_ERR_TO_COND(x, y) case x: return std::make_error_code(std::errc::y) + switch (windows_error_code) { + MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied); + MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists); + MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device); + MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long); + MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied); + MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error); + MAP_ERR_TO_COND(ERROR_CANTREAD, io_error); + MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error); + MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied); + MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device); + MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty); + MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument); + MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device); + MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists); + MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device); + MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied); + MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device); + MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported); + MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument); + MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument); + MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available); + MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available); + MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument); + MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied); + MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory); + MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again); + MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error); + MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory); + MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error); + MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again); + MAP_ERR_TO_COND(ERROR_SEEK, io_error); + MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied); + MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open); + MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error); + MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied); + MAP_ERR_TO_COND(WSAEACCES, permission_denied); + MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor); + MAP_ERR_TO_COND(WSAEFAULT, bad_address); + MAP_ERR_TO_COND(WSAEINTR, interrupted); + MAP_ERR_TO_COND(WSAEINVAL, invalid_argument); + MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open); + MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long); + default: + return std::error_code(windows_error_code, std::system_category()); + } + #undef MAP_ERR_TO_COND + } + + static std::error_code rename_internal(HANDLE from_handle, const std::wstring &wide_to, bool replace_if_exists) + { + std::vector rename_info_buf(sizeof(FILE_RENAME_INFO) - sizeof(wchar_t) + (wide_to.size() * sizeof(wchar_t))); + FILE_RENAME_INFO &rename_info = *reinterpret_cast(rename_info_buf.data()); + rename_info.ReplaceIfExists = replace_if_exists; + rename_info.RootDirectory = 0; + rename_info.FileNameLength = DWORD(wide_to.size() * sizeof(wchar_t)); + std::copy(wide_to.begin(), wide_to.end(), &rename_info.FileName[0]); + + ::SetLastError(ERROR_SUCCESS); + if (! ::SetFileInformationByHandle(from_handle, FileRenameInfo, &rename_info, (DWORD)rename_info_buf.size())) { + unsigned Error = GetLastError(); + if (Error == ERROR_SUCCESS) + Error = ERROR_CALL_NOT_IMPLEMENTED; // Wine doesn't always set error code. + return map_windows_error(Error); + } + + return std::error_code(); + } + + static std::error_code real_path_from_handle(HANDLE H, std::wstring &buffer) + { + buffer.resize(MAX_PATH + 1); + DWORD CountChars = ::GetFinalPathNameByHandleW(H, (LPWSTR)buffer.data(), (DWORD)buffer.size() - 1, FILE_NAME_NORMALIZED); + if (CountChars > buffer.size()) { + // The buffer wasn't big enough, try again. In this case the return value *does* indicate the size of the null terminator. + buffer.resize((size_t)CountChars); + CountChars = ::GetFinalPathNameByHandleW(H, (LPWSTR)buffer.data(), (DWORD)buffer.size() - 1, FILE_NAME_NORMALIZED); + } + if (CountChars == 0) + return map_windows_error(GetLastError()); + buffer.resize(CountChars); + return std::error_code(); + } + + std::error_code rename(const std::string &from, const std::string &to) + { + // Convert to utf-16. + std::wstring wide_from = boost::nowide::widen(from); + std::wstring wide_to = boost::nowide::widen(to); + + ScopedFileHandle from_handle; + // Retry this a few times to defeat badly behaved file system scanners. + for (unsigned retry = 0; retry != 200; ++ retry) { + if (retry != 0) + ::Sleep(10); + from_handle = ::CreateFileW((LPWSTR)wide_from.data(), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (from_handle) + break; + } + if (! from_handle) + return map_windows_error(GetLastError()); + + // We normally expect this loop to succeed after a few iterations. If it + // requires more than 200 tries, it's more likely that the failures are due to + // a true error, so stop trying. + for (unsigned retry = 0; retry != 200; ++ retry) { + auto errcode = rename_internal(from_handle, wide_to, true); + + if (errcode == std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category())) { + // Wine doesn't support SetFileInformationByHandle in rename_internal. + // Fall back to MoveFileEx. + if (std::error_code errcode2 = real_path_from_handle(from_handle, wide_from)) + return errcode2; + if (::MoveFileExW((LPCWSTR)wide_from.data(), (LPCWSTR)wide_to.data(), MOVEFILE_REPLACE_EXISTING)) + return std::error_code(); + return map_windows_error(GetLastError()); + } + + if (! errcode || errcode != std::errc::permission_denied) + return errcode; + + // The destination file probably exists and is currently open in another + // process, either because the file was opened without FILE_SHARE_DELETE or + // it is mapped into memory (e.g. using MemoryBuffer). Rename it in order to + // move it out of the way of the source file. Use FILE_FLAG_DELETE_ON_CLOSE + // to arrange for the destination file to be deleted when the other process + // closes it. + ScopedFileHandle to_handle(::CreateFileW((LPCWSTR)wide_to.data(), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)); + if (! to_handle) { + auto errcode = map_windows_error(GetLastError()); + // Another process might have raced with us and moved the existing file + // out of the way before we had a chance to open it. If that happens, try + // to rename the source file again. + if (errcode == std::errc::no_such_file_or_directory) + continue; + return errcode; + } + + BY_HANDLE_FILE_INFORMATION FI; + if (! ::GetFileInformationByHandle(to_handle, &FI)) + return map_windows_error(GetLastError()); + + // Try to find a unique new name for the destination file. + for (unsigned unique_id = 0; unique_id != 200; ++ unique_id) { + std::wstring tmp_filename = wide_to + L".tmp" + std::to_wstring(unique_id); + std::error_code errcode = rename_internal(to_handle, tmp_filename, false); + if (errcode) { + if (errcode == std::make_error_code(std::errc::file_exists) || errcode == std::make_error_code(std::errc::permission_denied)) { + // Again, another process might have raced with us and moved the file + // before we could move it. Check whether this is the case, as it + // might have caused the permission denied error. If that was the + // case, we don't need to move it ourselves. + ScopedFileHandle to_handle2(::CreateFileW((LPCWSTR)wide_to.data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); + if (! to_handle2) { + auto errcode = map_windows_error(GetLastError()); + if (errcode == std::errc::no_such_file_or_directory) + break; + return errcode; + } + BY_HANDLE_FILE_INFORMATION FI2; + if (! ::GetFileInformationByHandle(to_handle2, &FI2)) + return map_windows_error(GetLastError()); + if (FI.nFileIndexHigh != FI2.nFileIndexHigh || FI.nFileIndexLow != FI2.nFileIndexLow || FI.dwVolumeSerialNumber != FI2.dwVolumeSerialNumber) + break; + continue; + } + return errcode; + } + break; + } + + // Okay, the old destination file has probably been moved out of the way at + // this point, so try to rename the source file again. Still, another + // process might have raced with us to create and open the destination + // file, so we need to keep doing this until we succeed. + } + + // The most likely root cause. + return std::make_error_code(std::errc::permission_denied); + } +} // namespace WindowsSupport +#endif /* _WIN32 */ // borrowed from LVVM lib/Support/Windows/Path.inc -int rename_file(const std::string &from, const std::string &to) +std::error_code rename_file(const std::string &from, const std::string &to) { - int ec = 0; - #ifdef _WIN32 - - // Convert to utf-16. - std::wstring wide_from = boost::nowide::widen(from); - std::wstring wide_to = boost::nowide::widen(to); - - // Retry while we see recoverable errors. - // System scanners (eg. indexer) might open the source file when it is written - // and closed. - bool TryReplace = true; - - // This loop may take more than 2000 x 1ms to finish. - for (int i = 0; i < 2000; ++ i) { - if (i > 0) - // Sleep 1ms - ::Sleep(1); - if (TryReplace) { - // Try ReplaceFile first, as it is able to associate a new data stream - // with the destination even if the destination file is currently open. - if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL)) - return 0; - DWORD ReplaceError = ::GetLastError(); - ec = -1; // ReplaceError - // If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or - // ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW(). - if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT || - ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) { - TryReplace = false; - continue; - } - // If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry - // using ReplaceFileW(). - if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED) - continue; - // We get ERROR_FILE_NOT_FOUND if the destination file is missing. - // MoveFileEx can handle this case. - if (ReplaceError != ERROR_ACCESS_DENIED && ReplaceError != ERROR_FILE_NOT_FOUND && ReplaceError != ERROR_SHARING_VIOLATION) - break; - } - if (::MoveFileExW(wide_from.c_str(), wide_to.c_str(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) - return 0; - DWORD MoveError = ::GetLastError(); - ec = -1; // MoveError - if (MoveError != ERROR_ACCESS_DENIED && MoveError != ERROR_SHARING_VIOLATION) - break; - } - + return WindowsSupport::rename(from, to); #else - boost::nowide::remove(to.c_str()); - ec = boost::nowide::rename(from.c_str(), to.c_str()); - + return std::make_error_code(static_cast(boost::nowide::rename(from.c_str(), to.c_str()))); #endif - - return ec; } int copy_file(const std::string &from, const std::string &to) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 7ca8c3e5eb..96213447cf 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -98,9 +98,10 @@ void AppConfig::load() pt::read_ini(ifs, tree); } catch (pt::ptree_error& ex) { // Error while parsing config file. We'll customize the error message and rethrow to be displayed. - throw std::runtime_error(wxString::Format(_(L("Error parsing config file, it is probably corrupted. " - "Try to manualy delete the file. Your user profiles will not be affected.\n\n%s\n\n%s")), - AppConfig::config_path(), ex.what()).ToStdString()); + throw std::runtime_error( + _utf8(L("Error parsing PrusaSlicer config file, it is probably corrupted. " + "Try to manualy delete the file to recover from the error. Your user profiles will not be affected.")) + + "\n\n" + AppConfig::config_path() + "\n\n" + ex.what()); } // 2) Parse the property_tree, extract the sections and key / value pairs. From 88dcb7f366324225e715a67fa231fff0bda584a4 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 20 Aug 2019 16:38:03 +0200 Subject: [PATCH 36/48] Checking for OpenGL driver version in the GUI slicer and giving some reasonable advice to the user in case OpenGL < 2.0 was detected. --- src/PrusaSlicer.cpp | 3 +-- src/slic3r/GUI/GUI_App.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 92ff65a843..81422f4a88 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -60,7 +60,6 @@ PrinterTechnology get_printer_technology(const DynamicConfig &config) int CLI::run(int argc, char **argv) { -#ifdef _WIN32 // Switch boost::filesystem to utf8. try { boost::nowide::nowide_filesystem(); @@ -74,12 +73,12 @@ int CLI::run(int argc, char **argv) SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what(); #ifdef SLIC3R_GUI if (m_actions.empty()) + // Empty actions means Slicer is executed in the GUI mode. Show a GUI message. MessageBoxA(NULL, text.c_str(), caption.c_str(), MB_OK | MB_ICONERROR); #endif boost::nowide::cerr << text.c_str() << std::endl; return 1; } -#endif if (! this->setup(argc, argv)) return 1; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 9b4522356a..dff9fc1a97 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -293,6 +293,20 @@ bool GUI_App::on_init_inner() config_wizard_startup(app_conf_exists); preset_updater->slic3r_update_notify(); preset_updater->sync(preset_bundle); + const GLCanvas3DManager::GLInfo &glinfo = GLCanvas3DManager::get_gl_info(); + if (! glinfo.is_version_greater_or_equal_to(2, 0)) { + // Complain about the OpenGL version. + wxString message = wxString::Format( + _(L("PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n" + "while OpenGL version %s, render %s, vendor %s was detected.")), wxString(glinfo.get_version()), wxString(glinfo.get_renderer()), wxString(glinfo.get_vendor())); + message += "\n"; + message += _(L("You may need to update your graphics card driver.")); +#ifdef _WIN32 + message += "\n"; + message += _(L("As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw_renderer parameter.")); +#endif + wxMessageBox(message, wxString("PrusaSlicer - ") + _(L("Unsupported OpenGL version")), wxOK | wxICON_ERROR); + } }); } }); From b58713c06ff154b8d421343496a64d29ffb9b1db Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 20 Aug 2019 17:24:48 +0200 Subject: [PATCH 37/48] SLA exposure bounds to printer params. --- src/libslic3r/PrintConfig.cpp | 8 +-- src/libslic3r/PrintConfig.hpp | 16 +++--- src/libslic3r/SLAPrint.cpp | 20 ++++---- src/slic3r/GUI/Preset.cpp | 6 ++- src/slic3r/GUI/Tab.cpp | 94 +++++++++-------------------------- 5 files changed, 50 insertions(+), 94 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 037b248007..8f56c1b83d 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2412,7 +2412,7 @@ void PrintConfigDef::init_sla_params() def->mode = comExpert; def->set_default_value(new ConfigOptionInt(10)); - def = this->add("exposure_time_min", coFloat); + def = this->add("min_exposure_time", coFloat); def->label = L("Minimum exposure time"); def->tooltip = L("Minimum exposure time"); def->sidetext = L("s"); @@ -2420,7 +2420,7 @@ void PrintConfigDef::init_sla_params() def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0)); - def = this->add("exposure_time_max", coFloat); + def = this->add("max_exposure_time", coFloat); def->label = L("Maximum exposure time"); def->tooltip = L("Maximum exposure time"); def->sidetext = L("s"); @@ -2435,7 +2435,7 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->set_default_value(new ConfigOptionFloat(10)); - def = this->add("initial_exposure_time_min", coFloat); + def = this->add("min_initial_exposure_time", coFloat); def->label = L("Minimum initial exposure time"); def->tooltip = L("Minimum initial exposure time"); def->sidetext = L("s"); @@ -2443,7 +2443,7 @@ void PrintConfigDef::init_sla_params() def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0)); - def = this->add("initial_exposure_time_max", coFloat); + def = this->add("max_initial_exposure_time", coFloat); def->label = L("Maximum initial exposure time"); def->tooltip = L("Maximum initial exposure time"); def->sidetext = L("s"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index ca2a210f26..35025fcd10 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1098,22 +1098,14 @@ class SLAMaterialConfig : public StaticPrintConfig STATIC_PRINT_CONFIG_CACHE(SLAMaterialConfig) public: ConfigOptionFloat initial_layer_height; - ConfigOptionFloat exposure_time_min; - ConfigOptionFloat exposure_time_max; ConfigOptionFloat exposure_time; - ConfigOptionFloat initial_exposure_time_min; - ConfigOptionFloat initial_exposure_time_max; ConfigOptionFloat initial_exposure_time; ConfigOptionFloats material_correction; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) { OPT_PTR(initial_layer_height); - OPT_PTR(exposure_time_min); - OPT_PTR(exposure_time_max); OPT_PTR(exposure_time); - OPT_PTR(initial_exposure_time_min); - OPT_PTR(initial_exposure_time_max); OPT_PTR(initial_exposure_time); OPT_PTR(material_correction); } @@ -1139,6 +1131,10 @@ public: ConfigOptionFloat fast_tilt_time; ConfigOptionFloat slow_tilt_time; ConfigOptionFloat area_fill; + ConfigOptionFloat min_exposure_time; + ConfigOptionFloat max_exposure_time; + ConfigOptionFloat min_initial_exposure_time; + ConfigOptionFloat max_initial_exposure_time; protected: void initialize(StaticCacheBase &cache, const char *base_ptr) { @@ -1158,6 +1154,10 @@ protected: OPT_PTR(fast_tilt_time); OPT_PTR(slow_tilt_time); OPT_PTR(area_fill); + OPT_PTR(min_exposure_time); + OPT_PTR(max_exposure_time); + OPT_PTR(min_initial_exposure_time); + OPT_PTR(max_initial_exposure_time); } }; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 8e99d6ddc5..21aec83842 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -692,19 +692,19 @@ std::string SLAPrint::validate() const } } - double expt_max = m_material_config.exposure_time_max.getFloat(); - double expt_min = m_material_config.exposure_time_min.getFloat(); + double expt_max = m_printer_config.max_exposure_time.getFloat(); + double expt_min = m_printer_config.min_exposure_time.getFloat(); double expt_cur = m_material_config.exposure_time.getFloat(); if (expt_cur < expt_min || expt_cur > expt_max) - return L("Exposition time is out of predefined bounds."); + return L("Exposition time is out of printer profile bounds."); - double iexpt_max = m_material_config.initial_exposure_time_max.getFloat(); - double iexpt_min = m_material_config.initial_exposure_time_min.getFloat(); + double iexpt_max = m_printer_config.max_initial_exposure_time.getFloat(); + double iexpt_min = m_printer_config.min_initial_exposure_time.getFloat(); double iexpt_cur = m_material_config.initial_exposure_time.getFloat(); if (iexpt_cur < iexpt_min || iexpt_cur > iexpt_max) - return L("Initial exposition time is out of predefined bounds."); + return L("Initial exposition time is out of printer profile bounds."); return ""; } @@ -1600,11 +1600,11 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector steps_rasterize = { - "exposure_time_min", - "exposure_time_max", + "min_exposure_time", + "max_exposure_time", "exposure_time", - "initial_exposure_time_min", - "initial_exposure_time_max", + "min_initial_exposure_time", + "max_initial_exposure_time", "initial_exposure_time", "display_width", "display_height", diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 82124761a5..64793630ca 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -500,8 +500,8 @@ const std::vector& Preset::sla_material_options() if (s_opts.empty()) { s_opts = { "initial_layer_height", - "exposure_time_min", "exposure_time_max", "exposure_time", - "initial_exposure_time_min", "initial_exposure_time_max", "initial_exposure_time", + "exposure_time", + "initial_exposure_time", "material_correction", "material_notes", "default_sla_material_profile", @@ -527,6 +527,8 @@ const std::vector& Preset::sla_printer_options() "relative_correction", "absolute_correction", "gamma_correction", + "min_exposure_time", "max_exposure_time", + "min_initial_exposure_time", "max_initial_exposure_time", "print_host", "printhost_apikey", "printhost_cafile", "printer_notes", "inherits" diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0301653371..3688542224 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -838,7 +838,7 @@ static wxString support_combo_value_for_config(const DynamicPrintConfig &config, static wxString pad_combo_value_for_config(const DynamicPrintConfig &config) { - return config.opt_bool("pad_enable") ? (config.opt_bool("pad_zero_elevation") ? _("Around object") : _("Below object")) : _("None"); + return config.opt_bool("pad_enable") ? (config.opt_bool("pad_zero_elevation") ? _("Around object") : _("Below object")) : _("None"); } void Tab::on_value_change(const std::string& opt_key, const boost::any& value) @@ -860,8 +860,8 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) (opt_key == "supports_enable" || opt_key == "support_buildplate_only")) og_freq_chng_params->set_value("support", support_combo_value_for_config(*m_config, is_fff)); - if (! is_fff && (opt_key == "pad_enable" || opt_key == "pad_zero_elevation")) - og_freq_chng_params->set_value("pad", pad_combo_value_for_config(*m_config)); + if (! is_fff && (opt_key == "pad_enable" || opt_key == "pad_zero_elevation")) + og_freq_chng_params->set_value("pad", pad_combo_value_for_config(*m_config)); if (opt_key == "brim_width") { @@ -998,7 +998,7 @@ void Tab::update_frequently_changed_parameters() og_freq_chng_params->set_value("support", support_combo_value_for_config(*m_config, is_fff)); if (! is_fff) - og_freq_chng_params->set_value("pad", pad_combo_value_for_config(*m_config)); + og_freq_chng_params->set_value("pad", pad_combo_value_for_config(*m_config)); const std::string updated_value_key = is_fff ? "fill_density" : "pad_enable"; @@ -1772,13 +1772,13 @@ void TabFilament::reload_config() void TabFilament::update_volumetric_flow_preset_hints() { - wxString text; - try { - text = from_u8(PresetHints::maximum_volumetric_flow_description(*m_preset_bundle)); - } catch (std::exception &ex) { - text = _(L("Volumetric flow hints not available\n\n")) + from_u8(ex.what()); - } - m_volumetric_speed_description_line->SetText(text); + wxString text; + try { + text = from_u8(PresetHints::maximum_volumetric_flow_description(*m_preset_bundle)); + } catch (std::exception &ex) { + text = _(L("Volumetric flow hints not available\n\n")) + from_u8(ex.what()); + } + m_volumetric_speed_description_line->SetText(text); } void TabFilament::update() @@ -1788,9 +1788,9 @@ void TabFilament::update() m_update_cnt++; - wxString text = from_u8(PresetHints::cooling_description(m_presets->get_edited_preset())); - m_cooling_description_line->SetText(text); - this->update_volumetric_flow_preset_hints(); + wxString text = from_u8(PresetHints::cooling_description(m_presets->get_edited_preset())); + m_cooling_description_line->SetText(text); + this->update_volumetric_flow_preset_hints(); Layout(); bool cooling = m_config->opt_bool("cooling", 0); @@ -1812,8 +1812,8 @@ void TabFilament::update() void TabFilament::OnActivate() { - this->update_volumetric_flow_preset_hints(); - Tab::OnActivate(); + this->update_volumetric_flow_preset_hints(); + Tab::OnActivate(); } wxSizer* Tab::description_line_widget(wxWindow* parent, ogStaticText* *StaticText) @@ -2290,6 +2290,12 @@ void TabPrinter::build_sla() optgroup->append_single_option_line("absolute_correction"); optgroup->append_single_option_line("gamma_correction"); + optgroup = page->new_optgroup(_(L("Exposure"))); + optgroup->append_single_option_line("min_exposure_time"); + optgroup->append_single_option_line("max_exposure_time"); + optgroup->append_single_option_line("min_initial_exposure_time"); + optgroup->append_single_option_line("max_initial_exposure_time"); + optgroup = page->new_optgroup(_(L("Print Host upload"))); build_printhost(optgroup.get()); @@ -2560,7 +2566,7 @@ void TabPrinter::build_unregular_pages() optgroup = page->new_optgroup(_(L("Preview"))); auto reset_to_filament_color = [this, extruder_idx](wxWindow* parent) { - add_scaled_button(parent, &m_reset_to_filament_color, "undo", + add_scaled_button(parent, &m_reset_to_filament_color, "undo", _(L("Reset to Filament Color")), wxBU_LEFT | wxBU_EXACTFIT); ScalableButton* btn = m_reset_to_filament_color; btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); @@ -2571,7 +2577,7 @@ void TabPrinter::build_unregular_pages() { std::vector colors = static_cast(m_config->option("extruder_colour"))->values; colors[extruder_idx] = ""; - + DynamicPrintConfig new_conf = *m_config; new_conf.set_key_value("extruder_colour", new ConfigOptionStrings(colors)); load_config(new_conf); @@ -3614,11 +3620,7 @@ void TabSLAMaterial::build() optgroup->append_single_option_line("initial_layer_height"); optgroup = page->new_optgroup(_(L("Exposure"))); - optgroup->append_single_option_line("exposure_time_min"); - optgroup->append_single_option_line("exposure_time_max"); optgroup->append_single_option_line("exposure_time"); - optgroup->append_single_option_line("initial_exposure_time_min"); - optgroup->append_single_option_line("initial_exposure_time_max"); optgroup->append_single_option_line("initial_exposure_time"); optgroup = page->new_optgroup(_(L("Corrections"))); @@ -3683,59 +3685,11 @@ void TabSLAMaterial::reload_config() Tab::reload_config(); } - -namespace { - -enum e_cmp {EQUAL = 1, SMALLER = 2, GREATER = 4, SMALLER_EQ = 3, GREATER_EQ = 5}; - -void bound_check(Tab &tb, e_cmp cmp, const char *id, const char *boundid) -{ - double bound = tb.m_config->opt_float(boundid); - double value = tb.m_config->opt_float(id); - - auto boundlabel = tb.m_config->def()->get(boundid)->label; - auto valuelabel = tb.m_config->def()->get(id)->label; - - double ddiff = value - bound; - int diff = ddiff < 0 ? SMALLER : (std::abs(ddiff) < EPSILON ? EQUAL : GREATER); - - if ((cmp | diff) != cmp) { - wxString fmt; - - switch (cmp) { - case EQUAL: fmt = _(L("%s should be equal to %s")); break; - case SMALLER: fmt = _(L("%s should be smaller than %s")); break; - case GREATER: fmt = _(L("%s should be greater than %s")); break; - case SMALLER_EQ: fmt = _(L("%s should be smaller or equal to %s")); break; - case GREATER_EQ: fmt = _(L("%s should be greater or equal to %s")); break; - } - - wxString msg_text = wxString::Format(fmt, valuelabel, boundlabel); - - wxMessageDialog dialog(tb.parent(), msg_text, - _(L("Value outside bounds")), - wxICON_WARNING | wxOK); - - DynamicPrintConfig new_conf = *tb.m_config; - if (dialog.ShowModal() == wxID_OK) - new_conf.set_key_value(id, new ConfigOptionFloat(bound)); - - tb.load_config(new_conf); - } -}; - -} - void TabSLAMaterial::update() { if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) return; - bound_check(*this, e_cmp::GREATER_EQ, "exposure_time", "exposure_time_min"); - bound_check(*this, e_cmp::SMALLER_EQ, "exposure_time", "exposure_time_max"); - bound_check(*this, e_cmp::GREATER_EQ, "initial_exposure_time", "initial_exposure_time_min"); - bound_check(*this, e_cmp::SMALLER_EQ, "initial_exposure_time", "initial_exposure_time_max"); - // #ys_FIXME. Just a template for this function // m_update_cnt++; // ! something to update From 775a54846fc01ec9e977bad7cfa810ac1789d5b0 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 20 Aug 2019 17:46:19 +0200 Subject: [PATCH 38/48] Fixed compilation of Win32 message boxes on unix systems. --- src/PrusaSlicer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 81422f4a88..a75635ae60 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -71,7 +71,7 @@ int CLI::run(int argc, char **argv) "You may need to reconfigure the missing locales, likely by running the \"locale-gen\"" and \"dpkg-reconfigure locales\" commands.\n" #endif SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what(); - #ifdef SLIC3R_GUI + #if defined(_WIN32) && defined(SLIC3R_GUI) if (m_actions.empty()) // Empty actions means Slicer is executed in the GUI mode. Show a GUI message. MessageBoxA(NULL, text.c_str(), caption.c_str(), MB_OK | MB_ICONERROR); From 18d3792d3759f7a72a60530bafcb22154b25857b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 20 Aug 2019 18:45:12 +0200 Subject: [PATCH 39/48] Fixed a slack bug with wrong filament preset selection after importing of config --- src/slic3r/GUI/PresetBundle.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 7c9f7af4e9..3aee71c4c7 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -763,8 +763,11 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool } } // Load the configs into this->filaments and make them active. - this->filament_presets.clear(); - for (size_t i = 0; i < configs.size(); ++ i) { + this->filament_presets = std::vector(configs.size()); + // To avoid incorrect selection of the first filament preset (means a value of Preset->m_idx_selected) + // in a case when next added preset take a place of previosly selected preset, + // we should add presets from last to first + for (int i = (int)configs.size()-1; i >= 0; i--) { DynamicPrintConfig &cfg = configs[i]; // Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets. cfg.opt_string("compatible_printers_condition", true) = compatible_printers_condition_values[i + 1]; @@ -789,7 +792,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool new_name, std::move(cfg), i == 0); loaded->save(); } - this->filament_presets.emplace_back(loaded->name); + this->filament_presets[i] = loaded->name; } } // 4) Load the project config values (the per extruder wipe matrix etc). From 6a2265150196a791e493ee16456ecc5ecdd85f6c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 20 Aug 2019 20:24:37 +0200 Subject: [PATCH 40/48] Fixed a typo preventing compilation on Linux --- src/PrusaSlicer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index a75635ae60..3c0f27f4d8 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -68,7 +68,7 @@ int CLI::run(int argc, char **argv) std::string text = std::string("An error occured while setting up locale.\n") + ( #if !defined(_WIN32) && !defined(__APPLE__) // likely some linux system - "You may need to reconfigure the missing locales, likely by running the \"locale-gen\"" and \"dpkg-reconfigure locales\" commands.\n" + "You may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n" #endif SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what(); #if defined(_WIN32) && defined(SLIC3R_GUI) From e403118d7d518c52b0bf8129a1c650d1f7c04e23 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 21 Aug 2019 08:50:38 +0200 Subject: [PATCH 41/48] Fixed a typo in an error message. --- src/PrusaSlicer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index a75635ae60..ccbe0ab542 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -68,7 +68,7 @@ int CLI::run(int argc, char **argv) std::string text = std::string("An error occured while setting up locale.\n") + ( #if !defined(_WIN32) && !defined(__APPLE__) // likely some linux system - "You may need to reconfigure the missing locales, likely by running the \"locale-gen\"" and \"dpkg-reconfigure locales\" commands.\n" + "You may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n" #endif SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what(); #if defined(_WIN32) && defined(SLIC3R_GUI) From 7c0c5705df1b6d7739c0d20b713e99741d91cc88 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 21 Aug 2019 09:28:32 +0200 Subject: [PATCH 42/48] Fix of Excessive external_perimeter_extrusion_width error #2784 Increased the perimeter_extrusion_width check limit to 3x nozzle diameter. --- src/libslic3r/Print.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index e875db1dca..c5b619891d 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1258,7 +1258,7 @@ std::string Print::validate() const } else if (extrusion_width_min <= layer_height) { err_msg = (boost::format(L("%1%=%2% mm is too low to be printable at a layer height %3% mm")) % opt_key % extrusion_width_min % layer_height).str(); return false; - } else if (extrusion_width_max >= max_nozzle_diameter * 2.) { + } else if (extrusion_width_max >= max_nozzle_diameter * 3.) { err_msg = (boost::format(L("Excessive %1%=%2% mm to be printable with a nozzle diameter %3% mm")) % opt_key % extrusion_width_max % max_nozzle_diameter).str(); return false; } From ded2019765643d6a0acfe1c296eb1f2d2e860eb9 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 21 Aug 2019 13:08:26 +0200 Subject: [PATCH 43/48] Fix of "spiral vase printable for a single region object only" check. --- src/libslic3r/Print.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index c5b619891d..fdac4d8981 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1144,7 +1144,12 @@ std::string Print::validate() const // #4043 if (total_copies_count > 1 && ! m_config.complete_objects.value) return L("The Spiral Vase option can only be used when printing a single object."); - if (m_regions.size() > 1) + assert(m_objects.size() == 1); + size_t num_regions = 0; + for (const std::vector> &volumes_per_region : m_objects.front()->region_volumes) + if (! volumes_per_region.empty()) + ++ num_regions; + if (num_regions > 1) return L("The Spiral Vase option can only be used when printing single material objects."); } From 40d313961e474fce91e0e94858254f149e877d91 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 21 Aug 2019 13:49:37 +0200 Subject: [PATCH 44/48] Fixing issues in Print / PrintObject / PrintRegion reporting a list of printing extruders. --- src/libslic3r/Print.cpp | 25 +++++++++++++++++++------ src/libslic3r/PrintRegion.cpp | 19 +++++++++++++++---- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index fdac4d8981..6437302c30 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -262,8 +262,14 @@ std::vector Print::object_extruders() const { std::vector extruders; extruders.reserve(m_regions.size() * 3); - for (const PrintRegion *region : m_regions) - region->collect_object_printing_extruders(extruders); + std::vector region_used(m_regions.size(), false); + for (const PrintObject *object : m_objects) + for (const std::vector> &volumes_per_region : object->region_volumes) + if (! volumes_per_region.empty()) + region_used[&volumes_per_region - &object->region_volumes.front()] = true; + for (size_t idx_region = 0; idx_region < m_regions.size(); ++ idx_region) + if (region_used[idx_region]) + m_regions[idx_region]->collect_object_printing_extruders(extruders); sort_remove_duplicates(extruders); return extruders; } @@ -273,17 +279,24 @@ std::vector Print::support_material_extruders() const { std::vector extruders; bool support_uses_current_extruder = false; + auto num_extruders = (unsigned int)m_config.nozzle_diameter.size(); for (PrintObject *object : m_objects) { if (object->has_support_material()) { + assert(object->config().support_material_extruder >= 0); if (object->config().support_material_extruder == 0) support_uses_current_extruder = true; - else - extruders.push_back(object->config().support_material_extruder - 1); + else { + unsigned int i = (unsigned int)object->config().support_material_extruder - 1; + extruders.emplace_back((i >= num_extruders) ? 0 : i); + } + assert(object->config().support_material_interface_extruder >= 0); if (object->config().support_material_interface_extruder == 0) support_uses_current_extruder = true; - else - extruders.push_back(object->config().support_material_interface_extruder - 1); + else { + unsigned int i = (unsigned int)object->config().support_material_interface_extruder - 1; + extruders.emplace_back((i >= num_extruders) ? 0 : i); + } } } diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp index 73b40487bc..fc2bdfa7d1 100644 --- a/src/libslic3r/PrintRegion.cpp +++ b/src/libslic3r/PrintRegion.cpp @@ -46,7 +46,7 @@ Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool fir } double nozzle_diameter = m_print->config().nozzle_diameter.get_at(extruder-1); - return Flow::new_from_config_width(role, config_width, nozzle_diameter, layer_height, bridge ? (float)m_config.bridge_flow_ratio : 0.0); + return Flow::new_from_config_width(role, config_width, (float)nozzle_diameter, (float)layer_height, bridge ? (float)m_config.bridge_flow_ratio : 0.0f); } coordf_t PrintRegion::nozzle_dmr_avg(const PrintConfig &print_config) const @@ -64,16 +64,27 @@ coordf_t PrintRegion::bridging_height_avg(const PrintConfig &print_config) const void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig ®ion_config, std::vector &object_extruders) { // These checks reflect the same logic used in the GUI for enabling/disabling extruder selection fields. + auto num_extruders = (int)print_config.nozzle_diameter.size(); + auto emplace_extruder = [num_extruders, &object_extruders](int extruder_id) { + int i = std::max(0, extruder_id - 1); + object_extruders.emplace_back((i >= num_extruders) ? 0 : i); + }; if (region_config.perimeters.value > 0 || print_config.brim_width.value > 0) - object_extruders.emplace_back(region_config.perimeter_extruder - 1); + emplace_extruder(region_config.perimeter_extruder); if (region_config.fill_density.value > 0) - object_extruders.emplace_back(region_config.infill_extruder - 1); + emplace_extruder(region_config.infill_extruder); if (region_config.top_solid_layers.value > 0 || region_config.bottom_solid_layers.value > 0) - object_extruders.emplace_back(region_config.solid_infill_extruder - 1); + emplace_extruder(region_config.solid_infill_extruder); } void PrintRegion::collect_object_printing_extruders(std::vector &object_extruders) const { + auto num_extruders = (int)print()->config().nozzle_diameter.size(); + // PrintRegion, if used by some PrintObject, shall have all the extruders set to an existing printer extruder. + // If not, then there must be something wrong with the Print::apply() function. + assert(this->config().perimeter_extruder <= num_extruders); + assert(this->config().infill_extruder <= num_extruders); + assert(this->config().solid_infill_extruder <= num_extruders); collect_object_printing_extruders(print()->config(), this->config(), object_extruders); } From 668a8cd2eaaf4d3c06cc7053f071afddb70d3583 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 21 Aug 2019 14:05:32 +0200 Subject: [PATCH 45/48] Fix of an update of support extruders when changing number of printer extruders. --- src/libslic3r/Print.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 6437302c30..71529cff15 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -590,6 +590,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // Apply variables to placeholder parser. The placeholder parser is used by G-code export, // which should be stopped if print_diff is not empty. + size_t num_extruders = m_config.nozzle_diameter.size(); + bool num_extruders_changed = false; if (! full_config_diff.empty() || ! placeholder_parser_overrides.empty()) { update_apply_status(this->invalidate_step(psGCodeExport)); m_placeholder_parser.apply_config(std::move(placeholder_parser_overrides)); @@ -605,6 +607,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // Handle changes to regions config defaults m_default_region_config.apply_only(new_full_config, region_diff, true); m_full_print_config = std::move(new_full_config); + if (num_extruders != m_config.nozzle_diameter.size()) { + num_extruders = m_config.nozzle_diameter.size(); + num_extruders_changed = true; + } } class LayerRanges @@ -781,7 +787,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ print_object_status.emplace(PrintObjectStatus(print_object)); // 3) Synchronize ModelObjects & PrintObjects. - size_t num_extruders = m_config.nozzle_diameter.size(); for (size_t idx_model_object = 0; idx_model_object < model.objects.size(); ++ idx_model_object) { ModelObject &model_object = *m_model.objects[idx_model_object]; auto it_status = model_object_status.find(ModelObjectStatus(model_object.id())); @@ -828,7 +833,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ bool object_config_changed = model_object.config != model_object_new.config; if (object_config_changed) static_cast(model_object.config) = static_cast(model_object_new.config); - if (! object_diff.empty() || object_config_changed) { + if (! object_diff.empty() || object_config_changed || num_extruders_changed) { PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_extruders); auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); for (auto it = range.first; it != range.second; ++ it) { From 67a677577339d88663fb35f8f5720d0799914761 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 21 Aug 2019 14:07:56 +0200 Subject: [PATCH 46/48] Making arrange a little bit smarter: fix for issue #2787 --- src/libslic3r/Arrange.cpp | 42 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 99645f29d8..a70c208bc8 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -148,8 +148,9 @@ protected: double m_norm; // A coefficient to scale distances MultiPolygon m_merged_pile; // The already merged pile (vector of items) Box m_pilebb; // The bounding box of the merged pile. - ItemGroup m_remaining; // Remaining items (m_items at the beginning) - ItemGroup m_items; // The items to be packed + ItemGroup m_remaining; // Remaining items + ItemGroup m_items; // allready packed items + size_t m_item_count = 0; // Number of all items to be packed template ArithmeticOnly norm(T val) { @@ -167,7 +168,6 @@ protected: const double bin_area = m_bin_area; const SpatIndex& spatindex = m_rtree; const SpatIndex& smalls_spatindex = m_smallsrtree; - const ItemGroup& remaining = m_remaining; // We will treat big items (compared to the print bed) differently auto isBig = [bin_area](double a) { @@ -209,8 +209,8 @@ protected: } compute_case; bool bigitems = isBig(item.area()) || spatindex.empty(); - if(bigitems && !remaining.empty()) compute_case = BIG_ITEM; - else if (bigitems && remaining.empty()) compute_case = LAST_BIG_ITEM; + if(bigitems && !m_remaining.empty()) compute_case = BIG_ITEM; + else if (bigitems && m_remaining.empty()) compute_case = LAST_BIG_ITEM; else compute_case = SMALL_ITEM; switch (compute_case) { @@ -235,7 +235,7 @@ protected: // The smalles distance from the arranged pile center: double dist = norm(*(std::min_element(dists.begin(), dists.end()))); double bindist = norm(pl::distance(ibb.center(), bincenter)); - dist = 0.8 * dist + 0.2*bindist; + dist = 0.8 * dist + 0.2 * bindist; // Prepare a variable for the alignment score. // This will indicate: how well is the candidate item @@ -267,29 +267,24 @@ protected: if(ascore < alignment_score) alignment_score = ascore; } } - + density = std::sqrt(norm(fullbb.width()) * norm(fullbb.height())); - + double R = double(m_remaining.size()) / m_item_count; + // The final mix of the score is the balance between the // distance from the full pile center, the pack density and // the alignment with the neighbors if (result.empty()) - score = 0.5 * dist + 0.5 * density; + score = 0.50 * dist + 0.50 * density; else - score = 0.40 * dist + 0.40 * density + 0.2 * alignment_score; + score = R * 0.60 * dist + + (1.0 - R) * 0.20 * density + + 0.20 * alignment_score; break; } case LAST_BIG_ITEM: { - auto mp = m_merged_pile; - mp.emplace_back(item.transformedShape()); - auto chull = sl::convexHull(mp); - - placers::EdgeCache ec(chull); - - double circ = norm(ec.circumference()); - double bcirc = 2.0 * norm(fullbb.width() + fullbb.height()); - score = 0.5 * circ + 0.5 * bcirc; + score = norm(pl::distance(ibb.center(), m_pilebb.center())); break; } case SMALL_ITEM: { @@ -355,9 +350,11 @@ public: m_pck.configure(m_pconf); } - template inline void operator()(Args&&...args) { - m_rtree.clear(); /*m_preload_idx.clear();*/ - m_pck.execute(std::forward(args)...); + template inline void operator()(It from, It to) { + m_rtree.clear(); + m_item_count += size_t(to - from); + m_pck.execute(from, to); + m_item_count = 0; } inline void preload(std::vector& fixeditems) { @@ -376,6 +373,7 @@ public: } m_pck.configure(m_pconf); + m_item_count += fixeditems.size(); } }; From dc3a0a0ab34af1ac0e0139cbde2a75f820e17f1f Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 21 Aug 2019 14:52:22 +0200 Subject: [PATCH 47/48] Refactoring of EdgeGrid to accept an segment to segment visitor. WIP: PolygonTrimmer to trim skirt & brim with polygons stored in EdgeGrid. --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/EdgeGrid.cpp | 173 ++++--------------------------- src/libslic3r/EdgeGrid.hpp | 139 +++++++++++++++++++++++++ src/libslic3r/Geometry.hpp | 23 ++++ src/libslic3r/PolygonTrimmer.cpp | 56 ++++++++++ src/libslic3r/PolygonTrimmer.hpp | 31 ++++++ 6 files changed, 272 insertions(+), 152 deletions(-) create mode 100644 src/libslic3r/PolygonTrimmer.cpp create mode 100644 src/libslic3r/PolygonTrimmer.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 1a9a153b94..85e11eded3 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -127,6 +127,8 @@ add_library(libslic3r STATIC Point.hpp Polygon.cpp Polygon.hpp + PolygonTrimmer.cpp + PolygonTrimmer.hpp Polyline.cpp Polyline.hpp PolylineCollection.cpp diff --git a/src/libslic3r/EdgeGrid.cpp b/src/libslic3r/EdgeGrid.cpp index 9d02ef09b7..f40d499de1 100644 --- a/src/libslic3r/EdgeGrid.cpp +++ b/src/libslic3r/EdgeGrid.cpp @@ -11,6 +11,7 @@ #include "libslic3r.h" #include "ClipperUtils.hpp" #include "EdgeGrid.hpp" +#include "Geometry.hpp" #include "SVG.hpp" #if 0 @@ -275,134 +276,24 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) // 6) Finally fill in m_cell_data by rasterizing the lines once again. for (size_t i = 0; i < m_cells.size(); ++i) m_cells[i].end = m_cells[i].begin; - for (size_t i = 0; i < m_contours.size(); ++i) { - const Slic3r::Points &pts = *m_contours[i]; - for (size_t j = 0; j < pts.size(); ++j) { - // End points of the line segment. - Slic3r::Point p1(pts[j]); - Slic3r::Point p2 = pts[(j + 1 == pts.size()) ? 0 : j + 1]; - p1(0) -= m_bbox.min(0); - p1(1) -= m_bbox.min(1); - p2(0) -= m_bbox.min(0); - p2(1) -= m_bbox.min(1); - // Get the cells of the end points. - coord_t ix = p1(0) / m_resolution; - coord_t iy = p1(1) / m_resolution; - coord_t ixb = p2(0) / m_resolution; - coord_t iyb = p2(1) / m_resolution; - assert(ix >= 0 && size_t(ix) < m_cols); - assert(iy >= 0 && size_t(iy) < m_rows); - assert(ixb >= 0 && size_t(ixb) < m_cols); - assert(iyb >= 0 && size_t(iyb) < m_rows); - // Account for the end points. - m_cell_data[m_cells[iy*m_cols + ix].end++] = std::pair(i, j); - if (ix == ixb && iy == iyb) - // Both ends fall into the same cell. - continue; - // Raster the centeral part of the line. - coord_t dx = std::abs(p2(0) - p1(0)); - coord_t dy = std::abs(p2(1) - p1(1)); - if (p1(0) < p2(0)) { - int64_t ex = int64_t((ix + 1)*m_resolution - p1(0)) * int64_t(dy); - if (p1(1) < p2(1)) { - // x positive, y positive - int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); - do { - assert(ix <= ixb && iy <= iyb); - if (ex < ey) { - ey -= ex; - ex = int64_t(dy) * m_resolution; - ix += 1; - } - else if (ex == ey) { - ex = int64_t(dy) * m_resolution; - ey = int64_t(dx) * m_resolution; - ix += 1; - iy += 1; - } - else { - assert(ex > ey); - ex -= ey; - ey = int64_t(dx) * m_resolution; - iy += 1; - } - m_cell_data[m_cells[iy*m_cols + ix].end++] = std::pair(i, j); - } while (ix != ixb || iy != iyb); - } - else { - // x positive, y non positive - int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); - do { - assert(ix <= ixb && iy >= iyb); - if (ex <= ey) { - ey -= ex; - ex = int64_t(dy) * m_resolution; - ix += 1; - } - else { - ex -= ey; - ey = int64_t(dx) * m_resolution; - iy -= 1; - } - m_cell_data[m_cells[iy*m_cols + ix].end++] = std::pair(i, j); - } while (ix != ixb || iy != iyb); - } - } - else { - int64_t ex = int64_t(p1(0) - ix*m_resolution) * int64_t(dy); - if (p1(1) < p2(1)) { - // x non positive, y positive - int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); - do { - assert(ix >= ixb && iy <= iyb); - if (ex < ey) { - ey -= ex; - ex = int64_t(dy) * m_resolution; - ix -= 1; - } - else { - assert(ex >= ey); - ex -= ey; - ey = int64_t(dx) * m_resolution; - iy += 1; - } - m_cell_data[m_cells[iy*m_cols + ix].end++] = std::pair(i, j); - } while (ix != ixb || iy != iyb); - } - else { - // x non positive, y non positive - int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); - do { - assert(ix >= ixb && iy >= iyb); - if (ex < ey) { - ey -= ex; - ex = int64_t(dy) * m_resolution; - ix -= 1; - } - else if (ex == ey) { - // The lower edge of a grid cell belongs to the cell. - // Handle the case where the ray may cross the lower left corner of a cell in a general case, - // or a left or lower edge in a degenerate case (horizontal or vertical line). - if (dx > 0) { - ex = int64_t(dy) * m_resolution; - ix -= 1; - } - if (dy > 0) { - ey = int64_t(dx) * m_resolution; - iy -= 1; - } - } - else { - assert(ex > ey); - ex -= ey; - ey = int64_t(dx) * m_resolution; - iy -= 1; - } - m_cell_data[m_cells[iy*m_cols + ix].end++] = std::pair(i, j); - } while (ix != ixb || iy != iyb); - } - } - } + + struct Visitor { + Visitor(std::vector> &cell_data, std::vector &cells, size_t cols) : + cell_data(cell_data), cells(cells), cols(cols), i(0), j(0) {} + + void operator()(coord_t iy, coord_t ix) { cell_data[cells[iy*cols + ix].end++] = std::pair(i, j); } + + std::vector> &cell_data; + std::vector &cells; + size_t cols; + size_t i; + size_t j; + } visitor(m_cell_data, m_cells, m_cols); + + for (; visitor.i < m_contours.size(); ++ visitor.i) { + const Slic3r::Points &pts = *m_contours[visitor.i]; + for (; visitor.j < pts.size(); ++ visitor.j) + this->visit_cells_intersecting_line(pts[visitor.j], pts[(visitor.j + 1 == pts.size()) ? 0 : visitor.j + 1], visitor); } } @@ -1360,28 +1251,6 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset, bool fill_holes) co return out; } -inline int segments_could_intersect( - const Slic3r::Point &ip1, const Slic3r::Point &ip2, - const Slic3r::Point &jp1, const Slic3r::Point &jp2) -{ - Vec2i64 iv = (ip2 - ip1).cast(); - Vec2i64 vij1 = (jp1 - ip1).cast(); - Vec2i64 vij2 = (jp2 - ip1).cast(); - int64_t tij1 = cross2(iv, vij1); - int64_t tij2 = cross2(iv, vij2); - int sij1 = (tij1 > 0) ? 1 : ((tij1 < 0) ? -1 : 0); // signum - int sij2 = (tij2 > 0) ? 1 : ((tij2 < 0) ? -1 : 0); - return sij1 * sij2; -} - -inline bool segments_intersect( - const Slic3r::Point &ip1, const Slic3r::Point &ip2, - const Slic3r::Point &jp1, const Slic3r::Point &jp2) -{ - return segments_could_intersect(ip1, ip2, jp1, jp2) <= 0 && - segments_could_intersect(jp1, jp2, ip1, ip2) <= 0; -} - std::vector> EdgeGrid::Grid::intersecting_edges() const { std::vector> out; @@ -1405,7 +1274,7 @@ std::vector> if (&ipts == &jpts && (&ip1 == &jp2 || &jp1 == &ip2)) // Segments of the same contour share a common vertex. continue; - if (segments_intersect(ip1, ip2, jp1, jp2)) { + if (Geometry::segments_intersect(ip1, ip2, jp1, jp2)) { // The two segments intersect. Add them to the output. int jfirst = (&jpts < &ipts) || (&jpts == &ipts && jpt < ipt); out.emplace_back(jfirst ? @@ -1440,7 +1309,7 @@ bool EdgeGrid::Grid::has_intersecting_edges() const const Slic3r::Point &jp1 = jpts[jpt]; const Slic3r::Point &jp2 = jpts[(jpt + 1 == jpts.size()) ? 0 : jpt + 1]; if (! (&ipts == &jpts && (&ip1 == &jp2 || &jp1 == &ip2)) && - segments_intersect(ip1, ip2, jp1, jp2)) + Geometry::segments_intersect(ip1, ip2, jp1, jp2)) return true; } } diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp index 7faafdb3e1..cad20e07bb 100644 --- a/src/libslic3r/EdgeGrid.hpp +++ b/src/libslic3r/EdgeGrid.hpp @@ -65,6 +65,145 @@ public: std::vector> intersecting_edges() const; bool has_intersecting_edges() const; + template void visit_cells_intersecting_line(Slic3r::Point p1, Slic3r::Point p2, FUNCTION func) const + { + // End points of the line segment. + p1(0) -= m_bbox.min(0); + p1(1) -= m_bbox.min(1); + p2(0) -= m_bbox.min(0); + p2(1) -= m_bbox.min(1); + // Get the cells of the end points. + coord_t ix = p1(0) / m_resolution; + coord_t iy = p1(1) / m_resolution; + coord_t ixb = p2(0) / m_resolution; + coord_t iyb = p2(1) / m_resolution; + assert(ix >= 0 && size_t(ix) < m_cols); + assert(iy >= 0 && size_t(iy) < m_rows); + assert(ixb >= 0 && size_t(ixb) < m_cols); + assert(iyb >= 0 && size_t(iyb) < m_rows); + // Account for the end points. + func(iy, ix); + if (ix == ixb && iy == iyb) + // Both ends fall into the same cell. + return; + // Raster the centeral part of the line. + coord_t dx = std::abs(p2(0) - p1(0)); + coord_t dy = std::abs(p2(1) - p1(1)); + if (p1(0) < p2(0)) { + int64_t ex = int64_t((ix + 1)*m_resolution - p1(0)) * int64_t(dy); + if (p1(1) < p2(1)) { + // x positive, y positive + int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); + do { + assert(ix <= ixb && iy <= iyb); + if (ex < ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix += 1; + } + else if (ex == ey) { + ex = int64_t(dy) * m_resolution; + ey = int64_t(dx) * m_resolution; + ix += 1; + iy += 1; + } + else { + assert(ex > ey); + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy += 1; + } + func(iy, ix); + } while (ix != ixb || iy != iyb); + } + else { + // x positive, y non positive + int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); + do { + assert(ix <= ixb && iy >= iyb); + if (ex <= ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix += 1; + } + else { + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy -= 1; + } + func(iy, ix); + } while (ix != ixb || iy != iyb); + } + } + else { + int64_t ex = int64_t(p1(0) - ix*m_resolution) * int64_t(dy); + if (p1(1) < p2(1)) { + // x non positive, y positive + int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); + do { + assert(ix >= ixb && iy <= iyb); + if (ex < ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix -= 1; + } + else { + assert(ex >= ey); + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy += 1; + } + func(iy, ix); + } while (ix != ixb || iy != iyb); + } + else { + // x non positive, y non positive + int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); + do { + assert(ix >= ixb && iy >= iyb); + if (ex < ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix -= 1; + } + else if (ex == ey) { + // The lower edge of a grid cell belongs to the cell. + // Handle the case where the ray may cross the lower left corner of a cell in a general case, + // or a left or lower edge in a degenerate case (horizontal or vertical line). + if (dx > 0) { + ex = int64_t(dy) * m_resolution; + ix -= 1; + } + if (dy > 0) { + ey = int64_t(dx) * m_resolution; + iy -= 1; + } + } + else { + assert(ex > ey); + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy -= 1; + } + func(iy, ix); + } while (ix != ixb || iy != iyb); + } + } + } + + std::pair>::const_iterator, std::vector>::const_iterator> cell_data_range(coord_t row, coord_t col) const + { + const EdgeGrid::Grid::Cell &cell = m_cells[row * m_cols + col]; + return std::make_pair(m_cell_data.begin() + cell.begin, m_cell_data.begin() + cell.end); + } + + std::pair segment(const std::pair &contour_and_segment_idx) const + { + const Slic3r::Points &ipts = *m_contours[contour_and_segment_idx.first]; + size_t ipt = contour_and_segment_idx.second; + return std::pair(ipts[ipt], ipts[(ipt + 1 == ipts.size()) ? 0 : ipt + 1]); + } + protected: struct Cell { Cell() : begin(0), end(0) {} diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index dca1872d82..eec2673227 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -111,6 +111,29 @@ inline bool segment_segment_intersection(const Vec2d &p1, const Vec2d &v1, const return true; } + +inline int segments_could_intersect( + const Slic3r::Point &ip1, const Slic3r::Point &ip2, + const Slic3r::Point &jp1, const Slic3r::Point &jp2) +{ + Vec2i64 iv = (ip2 - ip1).cast(); + Vec2i64 vij1 = (jp1 - ip1).cast(); + Vec2i64 vij2 = (jp2 - ip1).cast(); + int64_t tij1 = cross2(iv, vij1); + int64_t tij2 = cross2(iv, vij2); + int sij1 = (tij1 > 0) ? 1 : ((tij1 < 0) ? -1 : 0); // signum + int sij2 = (tij2 > 0) ? 1 : ((tij2 < 0) ? -1 : 0); + return sij1 * sij2; +} + +inline bool segments_intersect( + const Slic3r::Point &ip1, const Slic3r::Point &ip2, + const Slic3r::Point &jp1, const Slic3r::Point &jp2) +{ + return segments_could_intersect(ip1, ip2, jp1, jp2) <= 0 && + segments_could_intersect(jp1, jp2, ip1, ip2) <= 0; +} + Pointf3s convex_hull(Pointf3s points); Polygon convex_hull(Points points); Polygon convex_hull(const Polygons &polygons); diff --git a/src/libslic3r/PolygonTrimmer.cpp b/src/libslic3r/PolygonTrimmer.cpp new file mode 100644 index 0000000000..3e3c9b4982 --- /dev/null +++ b/src/libslic3r/PolygonTrimmer.cpp @@ -0,0 +1,56 @@ +#include "PolygonTrimmer.hpp" +#include "EdgeGrid.hpp" +#include "Geometry.hpp" + +namespace Slic3r { + +TrimmedLoop trim_loop(const Polygon &loop, const EdgeGrid::Grid &grid) +{ + assert(! loop.empty()); + assert(loop.size() >= 2); + + TrimmedLoop out; + + if (loop.size() >= 2) { + size_t cnt = loop.points.size(); + + struct Visitor { + Visitor(const EdgeGrid::Grid &grid, const Slic3r::Point *pt_prev, const Slic3r::Point *pt_this) : grid(grid), pt_prev(pt_prev), pt_this(pt_this) {} + + void operator()(coord_t iy, coord_t ix) { + // Called with a row and colum of the grid cell, which is intersected by a line. + auto cell_data_range = grid.cell_data_range(iy, ix); + for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++ it_contour_and_segment) { + // End points of the line segment and their vector. + auto segment = grid.segment(*it_contour_and_segment); + if (Geometry::segments_intersect(segment.first, segment.second, *pt_prev, *pt_this)) { + // The two segments intersect. Add them to the output. + } + } + } + + const EdgeGrid::Grid &grid; + const Slic3r::Point *pt_this; + const Slic3r::Point *pt_prev; + } visitor(grid, &loop.points.back(), nullptr); + + for (const Point &pt_this : loop.points) { + visitor.pt_this = &pt_this; + grid.visit_cells_intersecting_line(*visitor.pt_prev, pt_this, visitor); + visitor.pt_prev = &pt_this; + } + } + + return out; +} + +std::vector trim_loops(const Polygons &loops, const EdgeGrid::Grid &grid) +{ + std::vector out; + out.reserve(loops.size()); + for (const Polygon &loop : loops) + out.emplace_back(trim_loop(loop, grid)); + return out; +} + +} diff --git a/src/libslic3r/PolygonTrimmer.hpp b/src/libslic3r/PolygonTrimmer.hpp new file mode 100644 index 0000000000..b2a780be91 --- /dev/null +++ b/src/libslic3r/PolygonTrimmer.hpp @@ -0,0 +1,31 @@ +#ifndef slic3r_PolygonTrimmer_hpp_ +#define slic3r_PolygonTrimmer_hpp_ + +#include "libslic3r.h" +#include +#include +#include "Line.hpp" +#include "MultiPoint.hpp" +#include "Polyline.hpp" + +namespace Slic3r { + +namespace EdgeGrid { + class Grid; +} + +struct TrimmedLoop +{ + std::vector points; + // Number of points per segment. Empty if the loop is + std::vector segments; + + bool is_trimmed() const { return ! segments.empty(); } +}; + +TrimmedLoop trim_loop(const Polygon &loop, const EdgeGrid::Grid &grid); +std::vector trim_loops(const Polygons &loops, const EdgeGrid::Grid &grid); + +} // namespace Slic3r + +#endif /* slic3r_PolygonTrimmer_hpp_ */ From 1b00932a01a03dd9894f63abdff1c4cbb9697bf9 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 21 Aug 2019 15:39:20 +0200 Subject: [PATCH 48/48] Small refactor for BedShapeHint --- src/libslic3r/Arrange.cpp | 54 ++++++++++++++++++++++++++++++++++----- src/libslic3r/Arrange.hpp | 44 ++++--------------------------- 2 files changed, 53 insertions(+), 45 deletions(-) diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index a70c208bc8..34e07302a0 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -437,6 +437,18 @@ inline Circle to_lnCircle(const CircleBed& circ) { } // Get the type of bed geometry from a simple vector of points. +void BedShapeHint::reset(BedShapes type) +{ + if (m_type != type) { + if (m_type == bsIrregular) + m_bed.polygon.Slic3r::Polyline::~Polyline(); + else if (type == bsIrregular) + ::new (&m_bed.polygon) Polyline(); + } + + m_type = type; +} + BedShapeHint::BedShapeHint(const Polyline &bed) { auto x = [](const Point& p) { return p(X); }; auto y = [](const Point& p) { return p(Y); }; @@ -511,14 +523,44 @@ BedShapeHint::BedShapeHint(const Polyline &bed) { } } +BedShapeHint &BedShapeHint::operator=(BedShapeHint &&cpy) +{ + reset(cpy.m_type); + + switch(m_type) { + case bsBox: m_bed.box = std::move(cpy.m_bed.box); break; + case bsCircle: m_bed.circ = std::move(cpy.m_bed.circ); break; + case bsIrregular: m_bed.polygon = std::move(cpy.m_bed.polygon); break; + case bsInfinite: m_bed.infbed = std::move(cpy.m_bed.infbed); break; + case bsUnknown: break; + } + + return *this; +} + +BedShapeHint &BedShapeHint::operator=(const BedShapeHint &cpy) +{ + reset(cpy.m_type); + + switch(m_type) { + case bsBox: m_bed.box = cpy.m_bed.box; break; + case bsCircle: m_bed.circ = cpy.m_bed.circ; break; + case bsIrregular: m_bed.polygon = cpy.m_bed.polygon; break; + case bsInfinite: m_bed.infbed = cpy.m_bed.infbed; break; + case bsUnknown: break; + } + + return *this; +} + template // Arrange for arbitrary bin type void _arrange( - std::vector & shapes, - std::vector & excludes, - const BinT & bin, - coord_t minobjd, - std::function prind, - std::function stopfn) + std::vector & shapes, + std::vector & excludes, + const BinT & bin, + coord_t minobjd, + std::function prind, + std::function stopfn) { // Integer ceiling the min distance from the bed perimeters coord_t md = minobjd - 2 * scaled(0.1 + EPSILON); diff --git a/src/libslic3r/Arrange.hpp b/src/libslic3r/Arrange.hpp index a0e4c043f0..1cfe1c907d 100644 --- a/src/libslic3r/Arrange.hpp +++ b/src/libslic3r/Arrange.hpp @@ -51,6 +51,9 @@ class BedShapeHint { BedShape_u() {} } m_bed; + // Reset the type, allocate m_bed properly + void reset(BedShapes type); + public: BedShapeHint(){} @@ -81,45 +84,8 @@ public: BedShapeHint(const BedShapeHint &cpy) { *this = cpy; } BedShapeHint(BedShapeHint &&cpy) { *this = std::move(cpy); } - BedShapeHint &operator=(const BedShapeHint &cpy) - { - if (m_type != cpy.m_type) { - if (m_type == bsIrregular) - m_bed.polygon.Slic3r::Polyline::~Polyline(); - else if (cpy.m_type == bsIrregular) - ::new (&m_bed.polygon) Polyline(); - } - m_type = cpy.m_type; - switch(m_type) { - case bsBox: m_bed.box = cpy.m_bed.box; break; - case bsCircle: m_bed.circ = cpy.m_bed.circ; break; - case bsIrregular: m_bed.polygon = cpy.m_bed.polygon; break; - case bsInfinite: m_bed.infbed = cpy.m_bed.infbed; break; - case bsUnknown: break; - } - - return *this; - } - - BedShapeHint& operator=(BedShapeHint &&cpy) - { - if (m_type != cpy.m_type) { - if (m_type == bsIrregular) - m_bed.polygon.Slic3r::Polyline::~Polyline(); - else if (cpy.m_type == bsIrregular) - ::new (&m_bed.polygon) Polyline(); - } - m_type = cpy.m_type; - switch(m_type) { - case bsBox: m_bed.box = std::move(cpy.m_bed.box); break; - case bsCircle: m_bed.circ = std::move(cpy.m_bed.circ); break; - case bsIrregular: m_bed.polygon = std::move(cpy.m_bed.polygon); break; - case bsInfinite: m_bed.infbed = std::move(cpy.m_bed.infbed); break; - case bsUnknown: break; - } - - return *this; - } + BedShapeHint &operator=(const BedShapeHint &cpy); + BedShapeHint& operator=(BedShapeHint &&cpy); BedShapes get_type() const { return m_type; }