From 95698410913e35d0e3f548c2602116840aa7b161 Mon Sep 17 00:00:00 2001 From: yw4z Date: Sat, 14 Jun 2025 10:19:25 +0300 Subject: [PATCH 1/7] Ramming dialog improvements & add step control for SpinInput class (#9651) * init * update dialog buttons * Fix color on Linux & macOS * Fix dark mode dialog title color on Windows --------- Co-authored-by: Noisyfox --- src/slic3r/GUI/RammingChart.cpp | 58 +++++++------- src/slic3r/GUI/RammingChart.hpp | 7 +- src/slic3r/GUI/Widgets/SpinInput.cpp | 23 +++--- src/slic3r/GUI/Widgets/SpinInput.hpp | 10 ++- src/slic3r/GUI/WipeTowerDialog.cpp | 110 ++++++++++++++------------- src/slic3r/GUI/WipeTowerDialog.hpp | 10 ++- 6 files changed, 119 insertions(+), 99 deletions(-) diff --git a/src/slic3r/GUI/RammingChart.cpp b/src/slic3r/GUI/RammingChart.cpp index 5bf75bbc74..265c4aa4e0 100644 --- a/src/slic3r/GUI/RammingChart.cpp +++ b/src/slic3r/GUI/RammingChart.cpp @@ -14,20 +14,22 @@ wxDEFINE_EVENT(EVT_WIPE_TOWER_CHART_CHANGED, wxCommandEvent); void Chart::draw() { wxAutoBufferedPaintDC dc(this); // unbuffered DC caused flickering on win + // scaling button and tick line from text size gives better result compared to dc.GetContentScale + int text_width, text_height; + dc.GetTextExtent("m",&text_width,&text_height); + side = text_width; + int tick_w = text_width / 2; + dc.SetBrush(GetBackgroundColour()); dc.SetPen(GetBackgroundColour()); dc.DrawRectangle(GetClientRect()); // otherwise the background would end up black on windows -#ifdef _WIN32 - dc.SetPen(wxPen(GetForegroundColour())); - dc.SetBrush(wxBrush(Slic3r::GUI::wxGetApp().get_highlight_default_clr())); -#else - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxWHITE_BRUSH); -#endif + dc.SetPen( wxPen(StateColor::darkModeColorFor(wxColour("#DBDBDB")), 1)); // input box border color + dc.SetBrush(wxBrush(StateColor::darkModeColorFor(wxColour("#F1F1F1")))); // sidebar titlebar bg color dc.DrawRectangle(m_rect); if (visible_area.m_width < 0.499) { + dc.SetTextForeground(StateColor::darkModeColorFor(wxColour("#FF6F00"))); // Use orange color for warning dc.DrawText(_(L("NO RAMMING AT ALL")),wxPoint(m_rect.GetLeft()+m_rect.GetWidth()/2-legend_side,m_rect.GetBottom()-m_rect.GetHeight()/2)); return; } @@ -35,15 +37,11 @@ void Chart::draw() { if (!m_line_to_draw.empty()) { for (unsigned int i=0;iDisableFocusFromKeyboard(); btn->Bind(wxEVT_LEFT_DOWN, [=](auto &e) { delta = inc ? 1 : -1; - SetValue(val + delta); + SetValue(val + delta * step); text_ctrl->SetFocus(); if (!btn->HasCapture()) btn->CaptureMouse(); @@ -241,7 +242,7 @@ Button *SpinInput::createButton(bool inc) delta = inc ? 1 : -1; if (!btn->HasCapture()) btn->CaptureMouse(); - SetValue(val + delta); + SetValue(val + delta * step); sendSpinEvent(); }); btn->Bind(wxEVT_LEFT_UP, [=](auto &e) { @@ -259,7 +260,7 @@ void SpinInput::onTimer(wxTimerEvent &evnet) { delta /= 2; return; } - SetValue(val + delta); + SetValue(val + delta * step); sendSpinEvent(); } @@ -293,7 +294,7 @@ void SpinInput::onTextEnter(wxCommandEvent &event) void SpinInput::mouseWheelMoved(wxMouseEvent &event) { auto delta = event.GetWheelRotation() < 0 ? 1 : -1; - SetValue(val + delta); + SetValue(val + delta * step); sendSpinEvent(); text_ctrl->SetFocus(); } @@ -305,10 +306,10 @@ void SpinInput::keyPressed(wxKeyEvent &event) case WXK_DOWN: long value; if (!text_ctrl->GetValue().ToLong(&value)) { value = val; } - if (event.GetKeyCode() == WXK_DOWN && value > min) { - --value; - } else if (event.GetKeyCode() == WXK_UP && value + 1 < max) { - ++value; + if (event.GetKeyCode() == WXK_DOWN && value - step >= min) { + value = value - step; + } else if (event.GetKeyCode() == WXK_UP && value + step <= max) { + value = value + step; } if (value != val) { SetValue(value); diff --git a/src/slic3r/GUI/Widgets/SpinInput.hpp b/src/slic3r/GUI/Widgets/SpinInput.hpp index cc342276f9..030eb56942 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.hpp +++ b/src/slic3r/GUI/Widgets/SpinInput.hpp @@ -23,6 +23,7 @@ class SpinInput : public wxNavigationEnabled int min; int max; int delta; + int step; static const int SpinInputWidth = 200; static const int SpinInputHeight = 50; @@ -36,7 +37,7 @@ public: const wxPoint &pos = wxDefaultPosition, const wxSize & size = wxDefaultSize, long style = 0, - int min = 0, int max = 100, int initial = 0); + int min = 0, int max = 100, int initial = 0, const int& step = 1); void Create(wxWindow * parent, wxString text, @@ -46,7 +47,8 @@ public: long style = 0, int min = 0, int max = 100, - int initial = 0); + int initial = 0, + int step = 1); void SetCornerRadius(double radius); @@ -70,6 +72,10 @@ public: int GetValue () const; + void SetStep(int value) { step = value; }; + + int GetStep() { return step; }; + void SetRange(int min, int max); protected: diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index babad123d6..de93b3c5ac 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -9,6 +9,7 @@ #include "MsgDialog.hpp" #include "libslic3r/Color.hpp" #include "Widgets/Button.hpp" +#include "Widgets/StaticLine.hpp" #include "Widgets/DialogButtons.hpp" #include "slic3r/Utils/ColorSpaceConvert.hpp" #include "MainFrame.hpp" @@ -49,37 +50,27 @@ static void update_ui(wxWindow* window) RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters) : wxDialog(parent, wxID_ANY, _(L("Ramming customization")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/) { - update_ui(this); + SetBackgroundColour(*wxWHITE); m_panel_ramming = new RammingPanel(this,parameters); - - // Not found another way of getting the background colours of RammingDialog, RammingPanel and Chart correct than setting - // them all explicitely. Reading the parent colour yielded colour that didn't really match it, no wxSYS_COLOUR_... matched - // colour used for the dialog. Same issue (and "solution") here : https://forums.wxwidgets.org/viewtopic.php?f=1&t=39608 - // Whoever can fix this, feel free to do so. -#ifndef _WIN32 - this-> SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK)); - m_panel_ramming->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK)); -#endif m_panel_ramming->Show(true); - this->Show(); auto main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(m_panel_ramming, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5); - main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxBOTTOM, 10); + auto dlg_btns = new DialogButtons(this, {"OK", "Cancel"}); + main_sizer->Add(dlg_btns, 0, wxEXPAND); SetSizer(main_sizer); main_sizer->SetSizeHints(this); - update_ui(static_cast(this->FindWindowById(wxID_OK, this))); - update_ui(static_cast(this->FindWindowById(wxID_CANCEL, this))); - this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { EndModal(wxCANCEL); }); this->Bind(wxEVT_BUTTON,[this](wxCommandEvent&) { m_output_data = m_panel_ramming->get_parameters(); EndModal(wxID_OK); },wxID_OK); + + wxGetApp().UpdateDlgDarkUI(this); this->Show(); -// wxMessageDialog dlg(this, _(L("Ramming denotes the rapid extrusion just before a tool change in a single-extruder MM printer. Its purpose is to " + Slic3r::GUI::MessageDialog dlg(this, _(L("Ramming denotes the rapid extrusion just before a tool change in a single-extruder MM printer. Its purpose is to " "properly shape the end of the unloaded filament so it does not prevent insertion of the new filament and can itself " "be reinserted later. This phase is important and different materials can require different extrusion speeds to get " @@ -100,6 +91,7 @@ RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters) RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxPoint(50,50), wxSize(800,350),wxBORDER_RAISED*/) { + SetBackgroundColour(*wxWHITE); update_ui(this); auto sizer_chart = new wxBoxSizer(wxVERTICAL); auto sizer_param = new wxBoxSizer(wxVERTICAL); @@ -120,48 +112,59 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) buttons.push_back(std::make_pair(x, y)); m_chart = new Chart(this, wxRect(scale(10),scale(10),scale(480),scale(360)), buttons, ramming_speed_size, 0.25f, scale(10)); -#ifdef _WIN32 update_ui(m_chart); -#else - m_chart->SetBackgroundColour(parent->GetBackgroundColour()); // see comment in RammingDialog constructor -#endif sizer_chart->Add(m_chart, 0, wxALL, 5); - m_widget_time = new wxSpinCtrlDouble(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH()*2.5, -1),style,0.,5.0,3.,0.5); - m_widget_volume = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH()*2.5, -1),style,0,10000,0); - m_widget_ramming_line_width_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH()*2.5, -1),style,10,200,100); - m_widget_ramming_step_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH()*2.5, -1),style,10,200,100); + m_widget_time = new SpinInput(this, wxEmptyString, _L("ms") , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 0 , 5000 , 3000, 500); + m_widget_volume = new SpinInput(this, wxEmptyString, _L("mm³"), wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 0 , 10000, 0 ); + m_widget_ramming_line_width_multiplicator = new SpinInput(this, wxEmptyString, _L("%") , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 10, 200 , 100 ); + m_widget_ramming_step_multiplicator = new SpinInput(this, wxEmptyString, _L("%") , wxDefaultPosition, wxSize(scale(120), -1), wxSP_ARROW_KEYS, 10, 200 , 100 ); -#ifdef _WIN32 - update_ui(m_widget_time->GetText()); - update_ui(m_widget_volume); - update_ui(m_widget_ramming_line_width_multiplicator); - update_ui(m_widget_ramming_step_multiplicator); -#endif + auto add_title = [this, sizer_param](wxString label){ + auto title = new StaticLine(this, 0, label); + title->SetFont(Label::Head_14); + title->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#363636"))); + sizer_param->Add(title, 0, wxEXPAND | wxBOTTOM, scale(8)); + }; - auto gsizer_param = new wxFlexGridSizer(2, 5, 15); - gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total ramming time")) + " (" + _(L("s")) + "):")), 0, wxALIGN_CENTER_VERTICAL); - gsizer_param->Add(m_widget_time); - gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total rammed volume")) + " (" + _(L("mm")) + wxString("³):", wxConvUTF8))), 0, wxALIGN_CENTER_VERTICAL); - gsizer_param->Add(m_widget_volume); - gsizer_param->AddSpacer(20); - gsizer_param->AddSpacer(20); - gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Ramming line width")) + " (%):")), 0, wxALIGN_CENTER_VERTICAL); - gsizer_param->Add(m_widget_ramming_line_width_multiplicator); - gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Ramming line spacing")) + " (%):")), 0, wxALIGN_CENTER_VERTICAL); - gsizer_param->Add(m_widget_ramming_step_multiplicator); + SetFont(Label::Body_14); + wxSize col_size; + for(auto label : {"Time", "Volume", "Width", "Spacing"}) + col_size.IncTo(GetTextExtent(_L(label))); + col_size = wxSize(col_size.x + scale(30) ,-1); - sizer_param->Add(gsizer_param, 0, wxTOP, scale(10)); + auto add_spin = [this, sizer_param, col_size](wxString label, SpinInput* spin){ + spin->Bind(wxEVT_KILL_FOCUS, [this](auto &e) { + e.SetId(GetId()); + ProcessEventLocally(e); + e.Skip(); + }); + auto h_sizer = new wxBoxSizer(wxHORIZONTAL); + auto text = new wxStaticText(this, wxID_ANY, label, wxDefaultPosition, col_size); + text->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#363636"))); + h_sizer->Add(text, 0, wxALIGN_CENTER_VERTICAL); + h_sizer->Add(spin); + sizer_param->Add(h_sizer, 0, wxEXPAND | wxBOTTOM, scale(2)); + }; - m_widget_time->SetValue(m_chart->get_time()); - m_widget_time->SetDigits(2); + add_title(_L("Total ramming")); + add_spin( _L("Time") , m_widget_time ); + add_spin( _L("Volume"), m_widget_volume); + + sizer_param->AddSpacer(10); + + add_title(_L("Ramming line")); + add_spin( _L("Width") , m_widget_ramming_line_width_multiplicator); + add_spin( _L("Spacing"), m_widget_ramming_step_multiplicator ); + + m_widget_time->SetValue(int(m_chart->get_time() * 1000)); m_widget_volume->SetValue(m_chart->get_volume()); m_widget_volume->Disable(); m_widget_ramming_line_width_multiplicator->SetValue(m_ramming_line_width_multiplicator); - m_widget_ramming_step_multiplicator->SetValue(m_ramming_step_multiplicator); - - m_widget_ramming_step_multiplicator->Bind(wxEVT_TEXT,[this](wxCommandEvent&) { line_parameters_changed(); }); - m_widget_ramming_line_width_multiplicator->Bind(wxEVT_TEXT,[this](wxCommandEvent&) { line_parameters_changed(); }); + m_widget_ramming_step_multiplicator->SetValue(m_ramming_step_multiplicator); + + m_widget_ramming_step_multiplicator->Bind(wxEVT_SPINCTRL,[this](wxCommandEvent&) { line_parameters_changed(); }); + m_widget_ramming_line_width_multiplicator->Bind(wxEVT_SPINCTRL,[this](wxCommandEvent&) { line_parameters_changed(); }); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(sizer_chart, 0, wxALL, 5); @@ -170,10 +173,15 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) sizer->SetSizeHints(this); SetSizer(sizer); - m_widget_time->Bind(wxEVT_TEXT,[this](wxCommandEvent&) {m_chart->set_xy_range(m_widget_time->GetValue(),-1);}); + m_widget_time->Bind(wxEVT_SPINCTRL,[this](wxCommandEvent&) { + m_chart->set_xy_range(m_widget_time->GetValue() * 0.001,-1); + }); m_widget_time->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value m_widget_volume->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value - Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) {m_widget_volume->SetValue(m_chart->get_volume()); m_widget_time->SetValue(m_chart->get_time());} ); + Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) { + m_widget_volume->SetValue(m_chart->get_volume()); + m_widget_time->SetValue(m_chart->get_time() * 1000); + }); Refresh(true); // erase background } @@ -340,7 +348,7 @@ void WipingDialog::on_dpi_changed(const wxRect &suggested_rect) // Parent dialog for purging volume adjustments - it fathers WipingPanel widget (that contains all controls) and a button to toggle simple/advanced mode: WipingDialog::WipingDialog(wxWindow* parent, const std::vector& matrix, const std::vector& extruders, const std::vector& extruder_colours, const std::vector&extra_flush_volume, float flush_multiplier) - : DPIDialog(parent ? parent : static_cast(wxGetApp().mainframe), + : GUI::DPIDialog(parent ? parent : static_cast(wxGetApp().mainframe), wxID_ANY, _(L("Flushing volumes for filament change")), wxDefaultPosition, diff --git a/src/slic3r/GUI/WipeTowerDialog.hpp b/src/slic3r/GUI/WipeTowerDialog.hpp index 4a1abfaad2..31ffe2f080 100644 --- a/src/slic3r/GUI/WipeTowerDialog.hpp +++ b/src/slic3r/GUI/WipeTowerDialog.hpp @@ -10,6 +10,8 @@ #include #include +#include "Widgets/SpinInput.hpp" + #include "RammingChart.hpp" class Button; class Label; @@ -23,10 +25,10 @@ public: private: Chart* m_chart = nullptr; - wxSpinCtrl* m_widget_volume = nullptr; - wxSpinCtrl* m_widget_ramming_line_width_multiplicator = nullptr; - wxSpinCtrl* m_widget_ramming_step_multiplicator = nullptr; - wxSpinCtrlDouble* m_widget_time = nullptr; + SpinInput* m_widget_volume = nullptr; + SpinInput* m_widget_ramming_line_width_multiplicator = nullptr; + SpinInput* m_widget_ramming_step_multiplicator = nullptr; + SpinInput* m_widget_time = nullptr; int m_ramming_step_multiplicator; int m_ramming_line_width_multiplicator; From 3ecca6116dfa5729051ace53fb486a761e1b5453 Mon Sep 17 00:00:00 2001 From: "Dipl.-Ing. Raoul Rubien, BSc" Date: Sat, 14 Jun 2025 15:05:25 +0200 Subject: [PATCH 2/7] fixes compiler warnings (#9619) * compiler warnings: adds SYSTEM to [target_]include_directories to skip warnings originating from dependencies * compiler warnings: uninitialized/unused variables, missing parenthesis, pragma * compiler warnings: redundant template type, missing curly braces, pass 0 instead of NULL as int argument * compiler warnings: removes fclose(fp) where fp==nullptr since fclose() has attribute __nonnull((1)) * compiler warnings: uninitialized variables, missing parentheses, missing curly braces * compiler warnings: ? as lower precedence than << * compiler warnings: unused variable * compiler warnings: unused result * compiler warnings: undefined/unused variable * compiler warnings: uninitialized variable --- CMakeLists.txt | 16 ++++++++-------- src/admesh/stlinit.cpp | 11 +++++------ .../Clipper2Lib/include/clipper2/clipper.core.h | 2 +- src/imgui/imgui_widgets.cpp | 5 ++--- src/libslic3r/Algorithm/LineSplit.cpp | 2 +- src/libslic3r/Brim.cpp | 10 ++++++---- src/libslic3r/CMakeLists.txt | 2 +- src/libslic3r/ClipperUtils.cpp | 8 ++++---- src/libslic3r/Color.cpp | 4 ++-- src/libslic3r/Fill/FillConcentric.cpp | 4 ++-- src/libslic3r/GCode/FanMover.cpp | 3 ++- src/libslic3r/Model.cpp | 3 ++- src/libslic3r/TriangleMeshSlicer.cpp | 2 +- src/mcut/source/shewchuk.c | 4 ++-- src/nanosvg/nanosvg.h | 4 ++-- src/qhull/CMakeLists.txt | 2 +- src/slic3r/CMakeLists.txt | 2 +- src/slic3r/GUI/CalibrationWizardPresetPage.cpp | 2 +- src/slic3r/GUI/ConnectPrinter.cpp | 4 ++-- src/slic3r/GUI/CreatePresetsDialog.cpp | 12 ++++++------ src/slic3r/GUI/EditGCodeDialog.cpp | 11 ++++------- src/slic3r/GUI/GLCanvas3D.cpp | 14 +++++++------- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- src/slic3r/GUI/MediaFilePanel.cpp | 2 +- src/slic3r/GUI/ObjColorDialog.cpp | 2 +- src/slic3r/GUI/PartPlate.cpp | 2 +- src/slic3r/GUI/PlateSettingsDialog.cpp | 6 +++--- src/slic3r/GUI/Plater.cpp | 4 ++-- src/slic3r/GUI/ReleaseNote.cpp | 2 +- src/slic3r/GUI/SelectMachine.cpp | 2 +- src/slic3r/GUI/StatusPanel.cpp | 2 +- src/slic3r/GUI/Widgets/Scrollbar.cpp | 3 +-- src/slic3r/GUI/Widgets/StateColor.cpp | 2 +- src/slic3r/GUI/Widgets/StateHandler.cpp | 6 +++--- src/slic3r/GUI/calib_dlg.cpp | 8 ++++---- src/slic3r/Utils/NetworkAgent.cpp | 6 +++--- 38 files changed, 90 insertions(+), 92 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ff06e0c25..dc145b5f5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -264,7 +264,7 @@ if(WIN32) if(WIN10SDK_INCLUDE_PATH) message("Building with Win10 Netfabb STL fixing service support") add_definitions(-DHAS_WIN10SDK) - include_directories("${WIN10SDK_INCLUDE_PATH}") + include_directories(SYSTEM "${WIN10SDK_INCLUDE_PATH}") else() message("Building without Win10 Netfabb STL fixing service support") endif() @@ -292,7 +292,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux") find_package(Threads REQUIRED) find_package(DBus REQUIRED) - include_directories(${DBUS_INCLUDE_DIRS}) + include_directories(SYSTEM ${DBUS_INCLUDE_DIRS}) endif() if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX) @@ -401,11 +401,11 @@ message(STATUS "LIBDIR: ${LIBDIR}") message(STATUS "LIBDIR_BIN: ${LIBDIR_BIN}") # For the bundled boost libraries (boost::nowide) -include_directories(${LIBDIR}) +include_directories(SYSTEM ${LIBDIR}) # For generated header files -include_directories(${LIBDIR_BIN}/platform) +include_directories(SYSTEM ${LIBDIR_BIN}/platform) # For ligigl -include_directories(${LIBDIR}/libigl) +include_directories(SYSTEM ${LIBDIR}/libigl) if(WIN32) add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) @@ -501,7 +501,7 @@ function(slic3r_remap_configs targets from_Cfg to_Cfg) endif() endfunction() -target_include_directories(boost_headeronly INTERFACE ${Boost_INCLUDE_DIRS}) +target_include_directories(boost_headeronly SYSTEM INTERFACE ${Boost_INCLUDE_DIRS}) target_link_libraries(boost_libs INTERFACE boost_headeronly ${Boost_LIBRARIES}) # Find and configure intel-tbb @@ -511,7 +511,7 @@ endif() set(TBB_DEBUG 1) set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO RelWithDebInfo Release "") find_package(TBB REQUIRED) -# include_directories(${TBB_INCLUDE_DIRS}) +# include_directories(SYSTEM ${TBB_INCLUDE_DIRS}) # add_definitions(${TBB_DEFINITIONS}) # if(MSVC) # # Suppress implicit linking of the TBB libraries by the Visual Studio compiler. @@ -553,7 +553,7 @@ if (SLIC3R_STATIC AND NOT SLIC3R_STATIC_EXCLUDE_CURL) find_package(OpenSSL REQUIRED) message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}") message("OpenSSL libraries: ${OPENSSL_LIBRARIES}") - target_include_directories(libcurl INTERFACE ${OPENSSL_INCLUDE_DIR}) + target_include_directories(libcurl SYSTEM INTERFACE ${OPENSSL_INCLUDE_DIR}) target_link_libraries(libcurl INTERFACE ${OPENSSL_LIBRARIES}) endif() endif() diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index 8196bf10cb..a69bd5497a 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -115,7 +115,6 @@ static FILE *stl_open_count_facets(stl_file *stl, const char *file, unsigned int // do another null check to be safe if (fp == nullptr) { BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading"; - fclose(fp); return nullptr; } @@ -228,8 +227,8 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first, Impor // Read a single facet from an ASCII .STL file // skip solid/endsolid // (in this order, otherwise it won't work when they are paired in the middle of a file) - fscanf(fp, " endsolid%*[^\n]\n"); - fscanf(fp, " solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid") + [[maybe_unused]] auto unused_result = fscanf(fp, " endsolid%*[^\n]\n"); + unused_result = fscanf(fp, " solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid") // Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs. int res_normal = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]); assert(res_normal == 3); @@ -244,12 +243,12 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first, Impor assert(res_vertex3 == 3); // Some G-code generators tend to produce text after "endloop" and "endfacet". Just ignore it. char buf[2048]; - fgets(buf, 2047, fp); + [[maybe_unused]] auto unused_result2 = fgets(buf, 2047, fp); bool endloop_ok = strncmp(buf, "endloop", 7) == 0 && (buf[7] == '\r' || buf[7] == '\n' || buf[7] == ' ' || buf[7] == '\t'); assert(endloop_ok); // Skip the trailing whitespaces and empty lines. - fscanf(fp, " "); - fgets(buf, 2047, fp); + unused_result = fscanf(fp, " "); + unused_result2 = fgets(buf, 2047, fp); bool endfacet_ok = strncmp(buf, "endfacet", 8) == 0 && (buf[8] == '\r' || buf[8] == '\n' || buf[8] == ' ' || buf[8] == '\t'); assert(endfacet_ok); if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || ! endloop_ok || ! endfacet_ok) { diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h b/src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h index f8d6b42b78..a02ba63e3d 100644 --- a/src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h +++ b/src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h @@ -114,7 +114,7 @@ struct Point { Point(const T2 x_, const T2 y_) { Init(x_, y_); } template - explicit Point(const Point& p) { Init(p.x, p.y); } + explicit Point(const Point& p) { Init(p.x, p.y); } Point operator * (const double scale) const { diff --git a/src/imgui/imgui_widgets.cpp b/src/imgui/imgui_widgets.cpp index 819a76cdc8..65f0bc5260 100644 --- a/src/imgui/imgui_widgets.cpp +++ b/src/imgui/imgui_widgets.cpp @@ -43,7 +43,6 @@ Index of this file: #include #include // System includes -#include // toupper #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier #include // intptr_t #else @@ -6298,9 +6297,9 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl RenderFrameBorder(bb.Min, bb.Max, rounding); else #ifdef __APPLE__ - window->DrawList->AddRect(bb.Min - ImVec2(3, 3), bb.Max + ImVec2(3, 3), GetColorU32(ImGuiCol_FrameBg), rounding * 2,NULL,4.0f);; // Color button are often in need of some sort of border + window->DrawList->AddRect(bb.Min - ImVec2(3, 3), bb.Max + ImVec2(3, 3), GetColorU32(ImGuiCol_FrameBg), rounding * 2, 0, 4.0f); // Color button are often in need of some sort of border #else - window->DrawList->AddRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2), GetColorU32(ImGuiCol_FrameBg), rounding * 2,NULL,3.0f); // Color button are often in need of some sort of border + window->DrawList->AddRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2), GetColorU32(ImGuiCol_FrameBg), rounding * 2, 0, 3.0f); // Color button are often in need of some sort of border #endif } diff --git a/src/libslic3r/Algorithm/LineSplit.cpp b/src/libslic3r/Algorithm/LineSplit.cpp index 53ef00e0a5..d2e2ff53fd 100644 --- a/src/libslic3r/Algorithm/LineSplit.cpp +++ b/src/libslic3r/Algorithm/LineSplit.cpp @@ -200,7 +200,7 @@ SplittedLine do_split_line(const ClipperZUtils::ZPath& path, const ExPolygons& c // Chain segment back to the original path ClipperZUtils::ZPoint& front = segment.front(); - const ClipperZUtils::ZPoint* previous_src_point; + const ClipperZUtils::ZPoint* previous_src_point = nullptr; if (is_src(front)) { // The segment starts with a point from src path, which means apart from the last point, // all other points on this segment should come from the src path or the clip polygon diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index 06e7b75ea3..e865efc781 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -587,9 +587,9 @@ double getadhesionCoeff(const PrintObject* printObject) } double adhesionCoeff = 1; for (const ModelVolume* modelVolume : objectVolumes) { - for (auto iter = extrudersFirstLayer.begin(); iter != extrudersFirstLayer.end(); iter++) + for (auto iter = extrudersFirstLayer.begin(); iter != extrudersFirstLayer.end(); iter++) { if (modelVolume->extruder_id() == *iter) { - if (Model::extruderParamsMap.find(modelVolume->extruder_id()) != Model::extruderParamsMap.end()) + if (Model::extruderParamsMap.find(modelVolume->extruder_id()) != Model::extruderParamsMap.end()) { if (Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "PETG" || Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "PCTG") { adhesionCoeff = 2; @@ -597,11 +597,13 @@ double getadhesionCoeff(const PrintObject* printObject) else if (Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "TPU") { adhesionCoeff = 0.5; } + } } + } } return adhesionCoeff; - /* + /* def->enum_values.push_back("PLA"); def->enum_values.push_back("PET"); def->enum_values.push_back("ABS"); @@ -1653,7 +1655,7 @@ ExtrusionEntityCollection makeBrimInfill(const ExPolygons& singleBrimArea, const Polylines loops_pl = to_polylines(loops); loops_pl_by_levels.assign(loops_pl.size(), Polylines()); tbb::parallel_for(tbb::blocked_range(0, loops_pl.size()), - [&loops_pl_by_levels, &loops_pl, &islands_area](const tbb::blocked_range& range) { + [&loops_pl_by_levels, &loops_pl /*, &islands_area*/](const tbb::blocked_range& range) { for (size_t i = range.begin(); i < range.end(); ++i) { loops_pl_by_levels[i] = chain_polylines({ std::move(loops_pl[i]) }); //loops_pl_by_levels[i] = chain_polylines(intersection_pl({ std::move(loops_pl[i]) }, islands_area)); diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 41adb363f9..b93f025e73 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -513,7 +513,7 @@ encoding_check(libslic3r) target_compile_definitions(libslic3r PUBLIC -DUSE_TBB -DTBB_USE_CAPTURED_EXCEPTION=0) target_include_directories(libslic3r PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) -target_include_directories(libslic3r PUBLIC ${EXPAT_INCLUDE_DIRS}) +target_include_directories(libslic3r SYSTEM PUBLIC ${EXPAT_INCLUDE_DIRS}) # Find the OCCT and related libraries set(OpenCASCADE_DIR "${CMAKE_PREFIX_PATH}/lib/cmake/occt") diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 1918145c4c..7a871cea90 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -94,10 +94,10 @@ template inline void clip_clipper_polygon_with_subject_bbox_ } // Never produce just a single point output polygon. - if (!out.empty()) - if(get_entire_polygons){ + if (!out.empty()) { + if (get_entire_polygons) { out=src; - }else{ + } else { if (int sides_next = sides(out.front()); // The last point is inside. Take it. sides_this == 0 || @@ -106,7 +106,7 @@ template inline void clip_clipper_polygon_with_subject_bbox_ (sides_prev & sides_this & sides_next) == 0) out.emplace_back(src.back()); } - + } } void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out, const bool get_entire_polygons) { clip_clipper_polygon_with_subject_bbox_templ(src, bbox, out, get_entire_polygons); } diff --git a/src/libslic3r/Color.cpp b/src/libslic3r/Color.cpp index 2f593538ac..d7208d40fc 100644 --- a/src/libslic3r/Color.cpp +++ b/src/libslic3r/Color.cpp @@ -257,7 +257,7 @@ ColorRGBA complementary(const ColorRGBA& color) ColorRGB saturate(const ColorRGB& color, float factor) { - float h, s, v; + float h = 0.0, s = 0.0, v = 0.0; RGBtoHSV(color.r(), color.g(), color.b(), h, s, v); s = std::clamp(s * factor, 0.0f, 1.0f); float r, g, b; @@ -272,7 +272,7 @@ ColorRGBA saturate(const ColorRGBA& color, float factor) ColorRGB opposite(const ColorRGB& color) { - float h, s, v; + float h = 0.0, s = 0.0, v = 0.0; RGBtoHSV(color.r(), color.g(), color.b(), h, s, v); h += 65.0f; // 65 instead 60 to avoid circle values diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp index b5a0c738c9..33863d4575 100644 --- a/src/libslic3r/Fill/FillConcentric.cpp +++ b/src/libslic3r/Fill/FillConcentric.cpp @@ -61,8 +61,8 @@ void FillConcentric::_fill_surface_single( size_t iPathFirst = polylines_out.size(); Point last_pos(0, 0); - double min_nozzle_diameter; - bool dir; + double min_nozzle_diameter = 0.0; + bool dir = false; if (this->print_config != nullptr && params.density >= STAGGER_SEAM_THRESHOLD) { min_nozzle_diameter = *std::min_element(print_config->nozzle_diameter.values.begin(), print_config->nozzle_diameter.values.end()); dir = rand() % 2; diff --git a/src/libslic3r/GCode/FanMover.cpp b/src/libslic3r/GCode/FanMover.cpp index b21711b5a7..10ecfd8827 100644 --- a/src/libslic3r/GCode/FanMover.cpp +++ b/src/libslic3r/GCode/FanMover.cpp @@ -421,11 +421,12 @@ void FanMover::_process_gcode_line(GCodeReader& reader, const GCodeReader::GCode current_role = ExtrusionEntity::string_to_role(extrusion_string); } if (line.raw().size() > 16) { - if (line.raw().rfind("; custom gcode", 0) != std::string::npos) + if (line.raw().rfind("; custom gcode", 0) != std::string::npos) { if (line.raw().rfind("; custom gcode end", 0) != std::string::npos) m_is_custom_gcode = false; else m_is_custom_gcode = true; + } } } } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index a6b4f2bb87..b9d3b7db3e 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -3200,7 +3200,7 @@ double getadhesionCoeff(const ModelVolumePtrs objectVolumes) { double adhesionCoeff = 1; for (const ModelVolume* modelVolume : objectVolumes) { - if (Model::extruderParamsMap.find(modelVolume->extruder_id()) != Model::extruderParamsMap.end()) + if (Model::extruderParamsMap.find(modelVolume->extruder_id()) != Model::extruderParamsMap.end()) { if (Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "PETG" || Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "PCTG") { adhesionCoeff = 2; @@ -3208,6 +3208,7 @@ double getadhesionCoeff(const ModelVolumePtrs objectVolumes) else if (Model::extruderParamsMap.at(modelVolume->extruder_id()).materialName == "TPU") { adhesionCoeff = 0.5; } + } } return adhesionCoeff; } diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index c9a59e5b2f..00b37ebdd5 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -2474,7 +2474,7 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u // intersect v0-v1 and v2-v0 with cutting plane and make new vertices auto new_vertex = [upper, lower, &upper_slice_vertices, &lower_slice_vertices](const Vec3f &a, const int ia, const Vec3f &b, const int ib, const Vec3f &c, const int ic, const Vec3f &new_pt, bool &is_new_vertex) { - int iupper, ilower; + int iupper = 0, ilower = 0; is_new_vertex = false; if (is_equal(new_pt, a)) iupper = ilower = ia; diff --git a/src/mcut/source/shewchuk.c b/src/mcut/source/shewchuk.c index 3143e40234..b23c3bea9d 100644 --- a/src/mcut/source/shewchuk.c +++ b/src/mcut/source/shewchuk.c @@ -2770,7 +2770,7 @@ REAL permanent; REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; int cxtaalen, cxtbblen, cytaalen, cytbblen; REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; - int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen; + int axtbclen = 0, aytbclen = 0, bxtcalen = 0, bytcalen = 0, cxtablen = 0, cytablen = 0; REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; REAL axtbctt[8], aytbctt[8], bxtcatt[8]; @@ -8679,4 +8679,4 @@ REAL* pe; } #endif -#endif \ No newline at end of file +#endif diff --git a/src/nanosvg/nanosvg.h b/src/nanosvg/nanosvg.h index 32b6bbbe9a..b3aa8b7858 100644 --- a/src/nanosvg/nanosvg.h +++ b/src/nanosvg/nanosvg.h @@ -1661,8 +1661,8 @@ static int nsvg__parseRotate(float* xform, const char* str) static void nsvg__parseTransform(float* xform, const char* str) { - float t[6]; - int len; + float t[6] = {0.0}; + int len; nsvg__xformIdentity(xform); while (*str) { diff --git a/src/qhull/CMakeLists.txt b/src/qhull/CMakeLists.txt index 06e430f6f0..573eafc7eb 100644 --- a/src/qhull/CMakeLists.txt +++ b/src/qhull/CMakeLists.txt @@ -145,7 +145,7 @@ endif(UNIX) ################################################## # LIBDIR is defined in the main xs CMake file: -target_include_directories(${qhull_STATIC} BEFORE PUBLIC ${LIBDIR}/qhull/src) +target_include_directories(${qhull_STATIC} SYSTEM BEFORE PUBLIC ${LIBDIR}/qhull/src) target_link_libraries(qhull INTERFACE ${qhull_STATIC}) endif() diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index baf7b56e89..b3a28a1c6b 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -623,7 +623,7 @@ add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES}) target_include_directories(libslic3r_gui PRIVATE Utils) if (WIN32) - target_include_directories(libslic3r_gui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../deps/WebView2/include) + target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../deps/WebView2/include) endif() source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SLIC3R_GUI_SOURCES}) diff --git a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp index f4b268347f..17aca8df5c 100644 --- a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp @@ -320,7 +320,7 @@ void CaliPresetCustomRangePanel::create_panel(wxWindow* parent) std::string decimal_point; std::string expression = "^[-+]?[0-9]+([,.][0-9]+)?$"; std::regex decimalRegex(expression); - int decimal_number; + int decimal_number = 0; if (std::regex_match(number, decimalRegex)) { std::smatch match; if (std::regex_search(number, match, decimalRegex)) { diff --git a/src/slic3r/GUI/ConnectPrinter.cpp b/src/slic3r/GUI/ConnectPrinter.cpp index 9ea5d9de89..6564c01dfd 100644 --- a/src/slic3r/GUI/ConnectPrinter.cpp +++ b/src/slic3r/GUI/ConnectPrinter.cpp @@ -160,7 +160,7 @@ void ConnectPrinterDialog::on_button_confirm(wxCommandEvent &event) { wxString code = m_textCtrl_code->GetTextCtrl()->GetValue(); for (char c : code) { - if (!('0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z')) { + if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))) { show_error(this, _L("Invalid input.")); return; } @@ -187,4 +187,4 @@ void ConnectPrinterDialog::on_dpi_changed(const wxRect &suggested_rect) Layout(); this->Refresh(); } -}} // namespace Slic3r::GUI \ No newline at end of file +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/CreatePresetsDialog.cpp b/src/slic3r/GUI/CreatePresetsDialog.cpp index b42defb346..6827b28c3d 100644 --- a/src/slic3r/GUI/CreatePresetsDialog.cpp +++ b/src/slic3r/GUI/CreatePresetsDialog.cpp @@ -778,7 +778,7 @@ wxBoxSizer *CreateFilamentPresetDialog::create_vendor_item() m_filament_custom_vendor_input->SetSize(NAME_OPTION_COMBOBOX_SIZE); textInputSizer->Add(m_filament_custom_vendor_input, 0, wxEXPAND | wxALL, 0); m_filament_custom_vendor_input->GetTextCtrl()->SetHint(_L("Input Custom Vendor")); - m_filament_custom_vendor_input->GetTextCtrl()->Bind(wxEVT_CHAR, [this](wxKeyEvent &event) { + m_filament_custom_vendor_input->GetTextCtrl()->Bind(wxEVT_CHAR, [](wxKeyEvent &event) { int key = event.GetKeyCode(); if (cannot_input_key.find(key) != cannot_input_key.end()) { event.Skip(false); @@ -888,7 +888,7 @@ wxBoxSizer *CreateFilamentPresetDialog::create_serial_item() m_filament_serial_input = new TextInput(this, "", "", "", wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE, wxTE_PROCESS_ENTER); m_filament_serial_input->GetTextCtrl()->SetMaxLength(50); comboBoxSizer->Add(m_filament_serial_input, 0, wxEXPAND | wxALL, 0); - m_filament_serial_input->GetTextCtrl()->Bind(wxEVT_CHAR, [this](wxKeyEvent &event) { + m_filament_serial_input->GetTextCtrl()->Bind(wxEVT_CHAR, [](wxKeyEvent &event) { int key = event.GetKeyCode(); if (cannot_input_key.find(key) != cannot_input_key.end()) { event.Skip(false); @@ -1750,7 +1750,7 @@ wxBoxSizer *CreatePrinterPresetDialog::create_printer_item(wxWindow *parent) m_custom_vendor_text_ctrl = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE); m_custom_vendor_text_ctrl->SetHint(_L("Input Custom Vendor")); - m_custom_vendor_text_ctrl->Bind(wxEVT_CHAR, [this](wxKeyEvent &event) { + m_custom_vendor_text_ctrl->Bind(wxEVT_CHAR, [](wxKeyEvent &event) { int key = event.GetKeyCode(); if (cannot_input_key.find(key) != cannot_input_key.end()) { // "@" can not be inputed event.Skip(false); @@ -1762,7 +1762,7 @@ wxBoxSizer *CreatePrinterPresetDialog::create_printer_item(wxWindow *parent) m_custom_vendor_text_ctrl->Hide(); m_custom_model_text_ctrl = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE); m_custom_model_text_ctrl->SetHint(_L("Input Custom Model")); - m_custom_model_text_ctrl->Bind(wxEVT_CHAR, [this](wxKeyEvent &event) { + m_custom_model_text_ctrl->Bind(wxEVT_CHAR, [](wxKeyEvent &event) { int key = event.GetKeyCode(); if (cannot_input_key.find(key) != cannot_input_key.end()) { // "@" can not be inputed event.Skip(false); @@ -3242,8 +3242,8 @@ CreatePresetSuccessfulDialog::CreatePresetSuccessfulDialog(wxWindow *parent, con horizontal_sizer->Add(success_bitmap_sizer, 0, wxEXPAND | wxALL, FromDIP(5)); wxBoxSizer *success_text_sizer = new wxBoxSizer(wxVERTICAL); - wxStaticText *success_text; - wxStaticText *next_step_text; + wxStaticText *success_text = nullptr; + wxStaticText *next_step_text = nullptr; bool sync_user_preset_need_enabled = wxGetApp().getAgent() && wxGetApp().app_config->get("sync_user_preset") == "false"; switch (create_success_type) { case PRINTER: diff --git a/src/slic3r/GUI/EditGCodeDialog.cpp b/src/slic3r/GUI/EditGCodeDialog.cpp index c50b86d32a..0afbb18a1e 100644 --- a/src/slic3r/GUI/EditGCodeDialog.cpp +++ b/src/slic3r/GUI/EditGCodeDialog.cpp @@ -15,16 +15,13 @@ #include "format.hpp" #include "Tab.hpp" #include "wxExtensions.hpp" -#include "BitmapCache.hpp" #include "ExtraRenderers.hpp" #include "MsgDialog.hpp" #include "Plater.hpp" #include "Widgets/DialogButtons.hpp" -#include "libslic3r/PlaceholderParser.hpp" #include "libslic3r/Preset.hpp" -#include "libslic3r/Print.hpp" #define BTN_GAP FromDIP(20) #define BTN_SIZE wxSize(FromDIP(58), FromDIP(24)) @@ -61,7 +58,7 @@ EditGCodeDialog::EditGCodeDialog(wxWindow* parent, const std::string& key, const m_search_bar->SetForegroundColour(*wxBLACK); wxGetApp().UpdateDarkUI(m_search_bar); - m_search_bar->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent&) { + m_search_bar->Bind(wxEVT_SET_FOCUS, [](wxFocusEvent&) { // this->on_search_update(); }); m_search_bar->Bind(wxEVT_COMMAND_TEXT_UPDATED, [this](wxCommandEvent&) { @@ -256,9 +253,9 @@ wxDataViewItem EditGCodeDialog::add_presets_placeholders() const auto& full_config = wxGetApp().preset_bundle->full_config(); const auto& tab_list = wxGetApp().tabs_list; - Tab* tab_print; - Tab* tab_filament; - Tab* tab_printer; + Tab* tab_print = nullptr; + Tab* tab_filament = nullptr; + Tab* tab_printer = nullptr; for (const auto tab : tab_list) { if (tab->m_type == Preset::TYPE_PRINT) tab_print = tab; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a1e7f55b9c..e02919d9e0 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3511,7 +3511,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) m_dirty = true; #endif } else if ((evt.ShiftDown() && evt.ControlDown() && keyCode == WXK_RETURN) || - evt.ShiftDown() && evt.AltDown() && keyCode == WXK_RETURN) { + (evt.ShiftDown() && evt.AltDown() && keyCode == WXK_RETURN)) { wxGetApp().plater()->toggle_show_wireframe(); m_dirty = true; } @@ -6640,8 +6640,8 @@ bool GLCanvas3D::_init_assemble_view_toolbar() item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLVIEWTOOLBAR_ASSEMBLE)); }; item.left.render_callback = GLToolbarItem::Default_Render_Callback; item.visible = true; - item.visibility_callback = [this]()->bool { return true; }; - item.enabling_callback = [this]()->bool { + item.visibility_callback = []()->bool { return true; }; + item.enabling_callback = []()->bool { return wxGetApp().plater()->has_assmeble_view(); }; if (!m_assemble_view_toolbar.add_item(item)) @@ -6690,7 +6690,7 @@ bool GLCanvas3D::_init_separator_toolbar() sperate_item.name = "start_seperator"; sperate_item.icon_filename = "seperator.svg"; sperate_item.sprite_id = 0; - sperate_item.left.action_callback = [this]() {}; + sperate_item.left.action_callback = []() {}; sperate_item.visibility_callback = []()->bool { return true; }; sperate_item.enabling_callback = []()->bool { return false; }; if (!m_separator_toolbar.add_item(sperate_item)) @@ -7407,7 +7407,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with }*/ const Camera& camera = wxGetApp().plater()->get_camera(); //BBS:add assemble view related logic - m_volumes.render(type, false, camera.get_view_matrix(), camera.get_projection_matrix(), cvn_size, [this, canvas_type](const GLVolume& volume) { + m_volumes.render(type, false, camera.get_view_matrix(), camera.get_projection_matrix(), cvn_size, [canvas_type](const GLVolume& volume) { if (canvas_type == ECanvasType::CanvasAssembleView) { return !volume.is_modifier; } @@ -7783,7 +7783,7 @@ void GLCanvas3D::_render_gizmos_overlay() // m_gizmos.set_overlay_scale(wxGetApp().em_unit()*0.1f); const float size = int(GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale()); m_gizmos.set_overlay_icon_size(size); //! #ys_FIXME_experiment -#endif /* __WXMSW__ */ +#endif */ /* __WXMSW__ */ m_gizmos.render_overlay(); if (m_gizmo_highlighter.m_render_arrow) @@ -8474,7 +8474,7 @@ float GLCanvas3D::_show_assembly_tooltip_information(float caption_max, float x, if (ImGui::IsItemHovered()) { ImGui::BeginTooltip2(ImVec2(x, y)); - auto draw_text_with_caption = [this, &imgui, & caption_max](const wxString &caption, const wxString &text) { + auto draw_text_with_caption = [&imgui, & caption_max](const wxString &caption, const wxString &text) { imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption); ImGui::SameLine(caption_max); imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index da94634318..e264f27c93 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1975,7 +1975,7 @@ void GUI_App::init_app_config() } // Change current dirtory of application - chdir(encode_path((Slic3r::data_dir() + "/log").c_str()).c_str()); + [[maybe_unused]] auto unused_result = chdir(encode_path((Slic3r::data_dir() + "/log").c_str()).c_str()); } else { m_datadir_redefined = true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp index 8e15214e2d..2b7e7bc9fe 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp @@ -204,8 +204,8 @@ bool GLGizmoBrimEars::unproject_on_mesh2(const Vec2d &mouse_pos, std::pairobject_clipper()->get_position(); const ClippingPlane *clp = m_c->object_clipper()->get_clipping_plane(); bool mouse_on_object = false; - Vec3f position_on_model; - Vec3f normal_on_model; + Vec3f position_on_model {}; + Vec3f normal_on_model {}; double closest_hit_distance = std::numeric_limits::max(); for (auto item : m_mesh_raycaster_map) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 9645926d7e..139b21edcc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1817,7 +1817,7 @@ void GLGizmoMeasure::show_selection_ui() return text; }; - float selection_cap_length; + float selection_cap_length = 0; if (m_measure_mode == EMeasureMode::ONLY_ASSEMBLY) { if (m_assembly_mode == AssemblyMode::FACE_FACE) { selection_cap_length = ImGui::CalcTextSize((_u8L("Selection") + " 1" + _u8L(" (Moving)")).c_str()).x * 1.2; diff --git a/src/slic3r/GUI/MediaFilePanel.cpp b/src/slic3r/GUI/MediaFilePanel.cpp index c62307dbb5..d915307aba 100644 --- a/src/slic3r/GUI/MediaFilePanel.cpp +++ b/src/slic3r/GUI/MediaFilePanel.cpp @@ -395,7 +395,7 @@ void MediaFilePanel::SetSelecting(bool selecting) m_image_grid->SetSelecting(selecting); m_button_management->SetLabel(selecting ? _L("Cancel") : _L("Select")); auto fs = m_image_grid->GetFileSystem(); - bool download_support = fs && fs->GetFileType() < PrinterFileSystem::F_MODEL || m_model_download_support; + bool download_support = (fs && fs->GetFileType() < PrinterFileSystem::F_MODEL) || m_model_download_support; m_manage_panel->GetSizer()->Show(m_button_download, selecting && download_support); m_manage_panel->GetSizer()->Show(m_button_delete, selecting); m_manage_panel->GetSizer()->Show(m_button_refresh, !selecting); diff --git a/src/slic3r/GUI/ObjColorDialog.cpp b/src/slic3r/GUI/ObjColorDialog.cpp index d0200ce8b9..116625e7cc 100644 --- a/src/slic3r/GUI/ObjColorDialog.cpp +++ b/src/slic3r/GUI/ObjColorDialog.cpp @@ -640,7 +640,7 @@ void ObjColorPanel::draw_table() m_color_cluster_icon_list.clear(); m_extruder_icon_list.clear(); - float row_height ; + float row_height = 0; for (size_t ii = 0; ii < row; ii++) { wxPanel *row_panel = new wxPanel(m_scrolledWindow); row_panel->SetBackgroundColour(ii % 2 == 0 ? *wxWHITE : wxColour(238, 238, 238)); diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 0c79b38e38..2a8987bdc0 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -576,7 +576,7 @@ void PartPlate::calc_vertex_for_plate_name_edit_icon(GLTexture *texture, int ind float height = icon_sz; float offset_y = factor * PARTPLATE_TEXT_OFFSET_Y; - float name_width; + float name_width = 0.0; if (texture && texture->get_width() > 0 && texture->get_height()) // original width give correct ratio in here since rendering width can be much higher because of next_highest_power_of_2 for rendering name_width = icon_sz * texture->m_original_width / texture->get_height(); diff --git a/src/slic3r/GUI/PlateSettingsDialog.cpp b/src/slic3r/GUI/PlateSettingsDialog.cpp index 7c15f08fe1..80e17f8fa5 100644 --- a/src/slic3r/GUI/PlateSettingsDialog.cpp +++ b/src/slic3r/GUI/PlateSettingsDialog.cpp @@ -55,8 +55,8 @@ LayerNumberTextInput::LayerNumberTextInput(wxWindow* parent, int layer_number, w // value should not be less than MIN_LAYER_VALUE, and should not be greater than MAX_LAYER_VALUE gui_value = std::clamp(gui_value, MIN_LAYER_VALUE, MAX_LAYER_VALUE); - int begin_value; - int end_value; + int begin_value = 0; + int end_value = 0; LayerNumberTextInput* end_layer_input = nullptr; if (this->m_type == Type::Begin) { begin_value = gui_value; @@ -688,4 +688,4 @@ void PlateNameEditDialog::set_plate_name(const wxString &name) { } -} // namespace Slic3r::GUI \ No newline at end of file +} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0993d1635a..9760237e83 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3668,7 +3668,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ bool dlg_cont = true; bool is_user_cancel = false; bool translate_old = false; - int current_width, current_depth, current_height; + int current_width = 0, current_depth = 0, current_height = 0; if (input_files.empty()) { return std::vector(); } @@ -9081,7 +9081,7 @@ void Plater::load_project(wxString const& filename2, // if res is empty no data has been loaded if (!res.empty() && (load_restore || !(strategy & LoadStrategy::Silence))) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " call set_project_filename: " << load_restore ? originfile : filename; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " call set_project_filename: " << (load_restore ? originfile : filename); p->set_project_filename(load_restore ? originfile : filename); if (load_restore && originfile.IsEmpty()) { p->set_project_name(_L("Untitled")); diff --git a/src/slic3r/GUI/ReleaseNote.cpp b/src/slic3r/GUI/ReleaseNote.cpp index fa72f7cd4f..abade15b26 100644 --- a/src/slic3r/GUI/ReleaseNote.cpp +++ b/src/slic3r/GUI/ReleaseNote.cpp @@ -2091,7 +2091,7 @@ void InputIpAddressDialog::on_text(wxCommandEvent &evt) bool invalid_access_code = true; for (char c : str_access_code) { - if (!('0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z')) { + if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))) { invalid_access_code = false; return; } diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index fd93b42e90..a9624772b6 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -2285,7 +2285,7 @@ bool SelectMachineDialog::is_same_nozzle_diameters(std::string& tag_nozzle_type, { bool is_same_nozzle_diameters = true; - float preset_nozzle_diameters; + float preset_nozzle_diameters = 0.0; std::string preset_nozzle_type; DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index a73bcbea8f..fb3f721905 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -2523,7 +2523,7 @@ void StatusPanel::update_misc_ctrl(MachineObject *obj) } bool light_on = obj->chamber_light != MachineObject::LIGHT_EFFECT::LIGHT_EFFECT_OFF; - BOOST_LOG_TRIVIAL(trace) << "light: " << light_on ? "on" : "off"; + BOOST_LOG_TRIVIAL(trace) << "light: " << (light_on ? "on" : "off"); if (m_switch_lamp_timeout > 0) m_switch_lamp_timeout--; else { diff --git a/src/slic3r/GUI/Widgets/Scrollbar.cpp b/src/slic3r/GUI/Widgets/Scrollbar.cpp index b71390b833..5b2140c658 100644 --- a/src/slic3r/GUI/Widgets/Scrollbar.cpp +++ b/src/slic3r/GUI/Widgets/Scrollbar.cpp @@ -1,4 +1,3 @@ -#pragma once #include #ifndef WX_PRECOMP #include @@ -311,4 +310,4 @@ void MyScrollbar::OnMouseWheel(wxMouseEvent &event) } Refresh(); Update(); -} \ No newline at end of file +} diff --git a/src/slic3r/GUI/Widgets/StateColor.cpp b/src/slic3r/GUI/Widgets/StateColor.cpp index 95cea1882f..f2881b9fa5 100644 --- a/src/slic3r/GUI/Widgets/StateColor.cpp +++ b/src/slic3r/GUI/Widgets/StateColor.cpp @@ -234,7 +234,7 @@ void StateColor::append(unsigned long color, int states) { if ((color & 0xff000000) == 0) color |= 0xff000000; - wxColour cl; cl.SetRGBA(color & 0xff00ff00 | ((color & 0xff) << 16) | ((color >> 16) & 0xff)); + wxColour cl; cl.SetRGBA((color & 0xff00ff00) | ((color & 0xff) << 16) | ((color >> 16) & 0xff)); append(cl, states); } diff --git a/src/slic3r/GUI/Widgets/StateHandler.cpp b/src/slic3r/GUI/Widgets/StateHandler.cpp index 7b2e4cf6e8..75936796ef 100644 --- a/src/slic3r/GUI/Widgets/StateHandler.cpp +++ b/src/slic3r/GUI/Widgets/StateHandler.cpp @@ -51,7 +51,7 @@ void StateHandler::update_binds() int diff = bind_states ^ bind_states_; State states[] = {Enabled, Checked, Focused, Hovered, Pressed}; wxEventType events[] = {EVT_ENABLE_CHANGED, wxEVT_CHECKBOX, wxEVT_SET_FOCUS, wxEVT_ENTER_WINDOW, wxEVT_LEFT_DOWN}; - wxEventType events2[] = {{0}, {0}, wxEVT_KILL_FOCUS, wxEVT_LEAVE_WINDOW, wxEVT_LEFT_UP}; + wxEventType events2[] = {0, 0, wxEVT_KILL_FOCUS, wxEVT_LEAVE_WINDOW, wxEVT_LEFT_UP}; for (int i = 0; i < 5; ++i) { int s = states[i]; if (diff & s) { @@ -74,7 +74,7 @@ void StateHandler::set_state(int state, int mask) { if ((states_ & mask) == (state & mask)) return; int old = states_; - states_ = states_ & ~mask | state & mask; + states_ = (states_ & ~mask) | (state & mask); if (old != states_ && (old | states2_) != (states_ | states2_)) { if (parent_) parent_->changed(states_ | states2_); @@ -94,7 +94,7 @@ void StateHandler::changed(wxEvent &event) { event.Skip(); wxEventType events[] = {EVT_ENABLE_CHANGED, wxEVT_CHECKBOX, wxEVT_SET_FOCUS, wxEVT_ENTER_WINDOW, wxEVT_LEFT_DOWN}; - wxEventType events2[] = {{0}, {0}, wxEVT_KILL_FOCUS, wxEVT_LEAVE_WINDOW, wxEVT_LEFT_UP}; + wxEventType events2[] = {0, 0, wxEVT_KILL_FOCUS, wxEVT_LEAVE_WINDOW, wxEVT_LEFT_UP}; int old = states_; // some events are from another window (ex: text_ctrl of TextInput), save state in states2_ to avoid conflicts for (int i = 0; i < 5; ++i) { diff --git a/src/slic3r/GUI/calib_dlg.cpp b/src/slic3r/GUI/calib_dlg.cpp index ee1ce3e23c..92455ec5de 100644 --- a/src/slic3r/GUI/calib_dlg.cpp +++ b/src/slic3r/GUI/calib_dlg.cpp @@ -348,7 +348,7 @@ Temp_Calibration_Dlg::Temp_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plat Layout(); Fit(); - auto validate_text = [this](TextInput* ti){ + auto validate_text = [](TextInput* ti){ unsigned long t = 0; if(!ti->GetTextCtrl()->GetValue().ToULong(&t)) return; @@ -395,7 +395,7 @@ void Temp_Calibration_Dlg::on_start(wxCommandEvent& event) { } m_params.start = start; m_params.end = end; - m_params.mode =CalibMode::Calib_Temp_Tower; + m_params.mode = CalibMode::Calib_Temp_Tower; m_plater->calib_temp(m_params); EndModal(wxID_OK); @@ -403,7 +403,7 @@ void Temp_Calibration_Dlg::on_start(wxCommandEvent& event) { void Temp_Calibration_Dlg::on_filament_type_changed(wxCommandEvent& event) { int selection = event.GetSelection(); - unsigned long start,end; + unsigned long start = 0, end = 0; switch(selection) { case tABS_ASA: @@ -1112,4 +1112,4 @@ void Junction_Deviation_Test_Dlg::on_dpi_changed(const wxRect& suggested_rect) { Fit(); } -}} // namespace Slic3r::GUI \ No newline at end of file +}} // namespace Slic3r::GUI diff --git a/src/slic3r/Utils/NetworkAgent.cpp b/src/slic3r/Utils/NetworkAgent.cpp index 47c3a7068e..ddeba01c37 100644 --- a/src/slic3r/Utils/NetworkAgent.cpp +++ b/src/slic3r/Utils/NetworkAgent.cpp @@ -1181,7 +1181,7 @@ std::string NetworkAgent::request_setting_id(std::string name, std::map* values_map, unsigned int* http_code) { - int ret; + int ret = 0; if (network_agent && put_setting_ptr) { ret = put_setting_ptr(network_agent, setting_id, name, values_map, http_code); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, setting_id=%2%, name=%3%, http_code=%4%, ret=%5%") @@ -1341,7 +1341,7 @@ int NetworkAgent::get_subtask_info(std::string subtask_id, std::string* task_jso int NetworkAgent::get_slice_info(std::string project_id, std::string profile_id, int plate_index, std::string* slice_json) { - int ret; + int ret = 0; if (network_agent && get_slice_info_ptr) { ret = get_slice_info_ptr(network_agent, project_id, profile_id, plate_index, slice_json); BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" : network_agent=%1%, project_id=%2%, profile_id=%3%, plate_index=%4%, slice_json=%5%") @@ -1352,7 +1352,7 @@ int NetworkAgent::get_slice_info(std::string project_id, std::string profile_id, int NetworkAgent::query_bind_status(std::vector query_list, unsigned int* http_code, std::string* http_body) { - int ret; + int ret = 0; if (network_agent && query_bind_status_ptr) { ret = query_bind_status_ptr(network_agent, query_list, http_code, http_body); if (ret) From 153c478c35b52c79f6227ed650b513a65c38658c Mon Sep 17 00:00:00 2001 From: _mightyMax147 <63765227+MaxShih147@users.noreply.github.com> Date: Sat, 14 Jun 2025 21:26:07 +0800 Subject: [PATCH 3/7] Add Phrozen Arco machine profiles and bed plate assets (#9486) * feat: add Phrozen Arco machine profiles and bed plate assets - Upload JSON profiles for the Phrozen Arco printer series - Include 3D bed plate model and corresponding texture files - Enables accurate slicing configuration and scene rendering for Arco * fix: add missing "instantiation" attribute --------- Co-authored-by: SoftFever Co-authored-by: Noisyfox --- resources/profiles/Phrozen.json | 70 +++++ .../Phrozen/Phrozen Arco_buildplate_model.stl | Bin 0 -> 24684 bytes .../Phrozen Arco_buildplate_texture.png | Bin 0 -> 291904 bytes .../Phrozen Arco_buildplate_texture.svg | 1 + .../profiles/Phrozen/Phrozen Arco_cover.png | Bin 0 -> 25246 bytes .../Phrozen PLA @Phrozen Arco 0.4 nozzle.json | 258 ++++++++++++++++ .../Phrozen/filament/fdm_filament_abs.json | 82 +++++ .../Phrozen/filament/fdm_filament_asa.json | 82 +++++ .../Phrozen/filament/fdm_filament_common.json | 138 +++++++++ .../Phrozen/filament/fdm_filament_pa.json | 79 +++++ .../Phrozen/filament/fdm_filament_pc.json | 82 +++++ .../Phrozen/filament/fdm_filament_pet.json | 76 +++++ .../Phrozen/filament/fdm_filament_pla.json | 88 ++++++ .../Phrozen/filament/fdm_filament_pva.json | 94 ++++++ .../Phrozen/filament/fdm_filament_tpu.json | 82 +++++ .../machine/Phrozen Arco 0.4 nozzle.json | 232 ++++++++++++++ .../Phrozen/machine/Phrozen Arco.json | 12 + .../Phrozen/machine/_fdm_machine_common.json | 139 +++++++++ .../Phrozen/machine/fdm_machine_common.json | 7 + ...0mm Standard @Phrozen Arco 0.4 nozzle.json | 292 ++++++++++++++++++ .../Phrozen/process/fdm_process_common.json | 107 +++++++ 21 files changed, 1921 insertions(+) create mode 100644 resources/profiles/Phrozen.json create mode 100644 resources/profiles/Phrozen/Phrozen Arco_buildplate_model.stl create mode 100644 resources/profiles/Phrozen/Phrozen Arco_buildplate_texture.png create mode 100644 resources/profiles/Phrozen/Phrozen Arco_buildplate_texture.svg create mode 100644 resources/profiles/Phrozen/Phrozen Arco_cover.png create mode 100644 resources/profiles/Phrozen/filament/Phrozen PLA @Phrozen Arco 0.4 nozzle.json create mode 100644 resources/profiles/Phrozen/filament/fdm_filament_abs.json create mode 100644 resources/profiles/Phrozen/filament/fdm_filament_asa.json create mode 100644 resources/profiles/Phrozen/filament/fdm_filament_common.json create mode 100644 resources/profiles/Phrozen/filament/fdm_filament_pa.json create mode 100644 resources/profiles/Phrozen/filament/fdm_filament_pc.json create mode 100644 resources/profiles/Phrozen/filament/fdm_filament_pet.json create mode 100644 resources/profiles/Phrozen/filament/fdm_filament_pla.json create mode 100644 resources/profiles/Phrozen/filament/fdm_filament_pva.json create mode 100644 resources/profiles/Phrozen/filament/fdm_filament_tpu.json create mode 100644 resources/profiles/Phrozen/machine/Phrozen Arco 0.4 nozzle.json create mode 100644 resources/profiles/Phrozen/machine/Phrozen Arco.json create mode 100644 resources/profiles/Phrozen/machine/_fdm_machine_common.json create mode 100644 resources/profiles/Phrozen/machine/fdm_machine_common.json create mode 100644 resources/profiles/Phrozen/process/0.20mm Standard @Phrozen Arco 0.4 nozzle.json create mode 100644 resources/profiles/Phrozen/process/fdm_process_common.json diff --git a/resources/profiles/Phrozen.json b/resources/profiles/Phrozen.json new file mode 100644 index 0000000000..e5eae56b69 --- /dev/null +++ b/resources/profiles/Phrozen.json @@ -0,0 +1,70 @@ +{ + "name": "Phrozen", + "version": "00.00.00.01", + "force_update": "0", + "description": "Phrozen configurations", + "machine_model_list": [ + { + "name": "Phrozen Arco", + "sub_path": "machine/Phrozen Arco.json" + } + ], + "process_list": [ + { + "name": "fdm_process_common", + "sub_path": "process/fdm_process_common.json" + }, + { + "name": "0.20mm Standard @Phrozen Arco", + "sub_path": "process/0.20mm Standard @Phrozen Arco 0.4 nozzle.json" + } + ], + "filament_list": [ + { + "name": "fdm_filament_common", + "sub_path": "filament/fdm_filament_common.json" + }, + { + "name": "fdm_filament_pla", + "sub_path": "filament/fdm_filament_pla.json" + }, + { + "name": "fdm_filament_tpu", + "sub_path": "filament/fdm_filament_tpu.json" + }, + { + "name": "fdm_filament_pet", + "sub_path": "filament/fdm_filament_pet.json" + }, + { + "name": "fdm_filament_abs", + "sub_path": "filament/fdm_filament_abs.json" + }, + { + "name": "fdm_filament_pc", + "sub_path": "filament/fdm_filament_pc.json" + }, + { + "name": "fdm_filament_asa", + "sub_path": "filament/fdm_filament_asa.json" + }, + { + "name": "fdm_filament_pva", + "sub_path": "filament/fdm_filament_pva.json" + }, + { + "name": "fdm_filament_pa", + "sub_path": "filament/fdm_filament_pa.json" + } + ], + "machine_list": [ + { + "name": "fdm_machine_common", + "sub_path": "machine/fdm_machine_common.json" + }, + { + "name": "Phrozen Arco 0.4 nozzle", + "sub_path": "machine/Phrozen Arco 0.4 nozzle.json" + } + ] +} diff --git a/resources/profiles/Phrozen/Phrozen Arco_buildplate_model.stl b/resources/profiles/Phrozen/Phrozen Arco_buildplate_model.stl new file mode 100644 index 0000000000000000000000000000000000000000..d3c6b8107af6c30bb5b2f9c31f0ae87737ba98cb GIT binary patch literal 24684 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

9>vSu{`!SpS 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 literal 0 HcmV?d00001 diff --git a/resources/profiles/Phrozen/Phrozen Arco_buildplate_texture.svg b/resources/profiles/Phrozen/Phrozen Arco_buildplate_texture.svg new file mode 100644 index 0000000000..1ae1e92edf --- /dev/null +++ b/resources/profiles/Phrozen/Phrozen Arco_buildplate_texture.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/profiles/Phrozen/Phrozen Arco_cover.png b/resources/profiles/Phrozen/Phrozen Arco_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..f0ffbf6680a014c90593d92a1c40dd2cf26e58c8 GIT binary patch literal 25246 zcmbrl1z1~4_b;3Thazo}LUCFgf=jSKOKI^!aW4cZ4#6#ywoshnP~2S#6xZSwiWPTv zcev>}ublV2=YPNNxfh;fPiC+6o0&Ch*6dkp?a#`JGWfU@xBvhE|JBRqDyVD4?+-R6 z>RYTIlLvJHI;zM>0g4AGH&8#8VVbW@6%+uhs4_MH6Zimt_L~It4**gCF#ae50P4WU z|0?SPxd9+lJq_w(3gr2tOpGdj^0xq>|ARgOb^Too|NZsPtE7qTTNtgfxh>q*(cIRK zmPde-mzG(>!p6kb#gPR7;Njxohj8&hxVdS$Q3ZYoKQ{n?9*+L67LcjHfA=mG^sm+` zQqlfh{@w0>A@M=@xByj5chsm`ICd|!98se9@cRQCEi8cp09XzdZ#3bW3i1$RTWe0E z-`(VNwYK|>1Q2zFpo-QoxDllZ##)mzI`R)WO6QqVoL3KiE;f#OTf8a61SX?Be3W>B7rt>tF`v78Vu;bMb(A zcsNiL9FA@_a3fa^8%KseLH>#J9Oh{3U||Qhu(hH6jcfGQ)(I{~Pyf52fBpU0PZQ&R zwPWYxVD(2UCdOcx70eoD19t>-b8>_Kjt@23e=*uP{zDolxqw}b>`+Wx{}Ypf!vC4g z+WK!f9pTc>s1f`_B7fVU;~O_S7+3}7XzS!)43l<7b)VtydJeZR{kLrY1L^mj|FQ3O z|5V7o@5R4v{|WHNoc<|lQ4?c`sjY*x5nSBD+QJ9-;*MW5-LQ&*2Kcp z?YR*gCjMJLIk@;ZxVhi_Q`6bFgdkj8qTv6c{4b1W4lpCQt-~8zTPyMZ^K$wV>96#E z2L=1P?)+XZf9=j6Ab(Q+7lr~#|4oeGMt_I$d-?tqWmNEapJ zKbDRv%>F-X|9Qj8;*TX@XXM}r`>i2j^#4?mf32B+Es5Vee`p%S(bg31V&njmG()M; z|ECQ9j_2Qf{}=o}uwBeyHvc`he--ARXn#=s&ma~yj&LIzW7w(P9XW`G<|D2pZbnb5_^Y;Qk-B5C{Fte~RvU+Z7?DX3T{bP(K z|G&rhKf?UG)BkAd|FMa`u>Wt+ul{dm=+EB&h5awkzfII{`Jkj?^vC3&X7qon`)_*9 z-x_b_^anlPZ|m^~$6sszn?vhwIsRJv7mk0KKFBj$D_aMY0fUM2ih}>H`X5|>YQ)|;<#*y8X^Dy6!7Y~4@}P?6Ujm=n--IBZaYD!-ias%4Z#4cJXQjZiy|m<$QidnZo@p04Pt%Wsd&58J(C| z8H!GK*J#LJ%gqSgj5Mqy z_<%R*-XIRzr#iNj@gPJ*p;xl>?)Hk%djZeD{M2R2byyf0reW-OtblJA zfgz=f)vWvaqO?CzFa;tcbpDe=r)nF_<)gPU_b^=JO~I(Ft?izggRpm_{Zhw6cX#(< z?NY;*aRSl(<{*iEUqY))iDvJ1Hhpfc`z|H~NOK3yU=1`i-;%SdxjS#oiMgAZIj%TU+jAsGo~M5Cs9 zO}W>V^P*xio8>e^^B0T?$r5pXUuxPt?J6rRX?0yrc!N?JJ;HX@I85wzFxg|*?G{Vo zyv2hef7gh;Jrqp41`xyg8Oo1XsTdW#SdP5Q0bGm&v|bBQJ&ID>)u}LltvQQ1ED01a zpv5f3unSj|=sG7?Zd4+zr%&B`bGuli^S$vdaqfDxl4w5g+zMKww{9^mG%k<>v}`uK z9sAxm>T!2-<|7?*&R#@P0tk7k@ranP&=rgY_Cz$_zeK z5`F!!Sy23HV(_*k<@PwIiPPP4tIFF+oQkU%h2D&fKhL{l%Dh7oR}!vcPmG9i(!&PW zQ&B*Jy)hY`gr)rNthfs9aaor4G~|2CmvvH4ogSs!QTFOZf81UA)YlWuHdlNUA^Ny8Fz&Zp=#Kd&EBf zNy*ACk`&Ep+ta*&fURC`#=R0vB_i=K=UtrvKwKTGZGI_Cf*_SGP|f<{q-*Eb$r8=o zBf%9CrX=`JFTol3@Y#Oe%4t+BjU#Do?nRA*DwQeV_5zYq(2t{>Umq{e8w+M>I!G&StMtFnXNIa|OHoy|Y+b*!yWCT?j?b=B+beT)N6$MQ~m7A#2cQPcr1?y-4T38B*1V2eZ3p){kEybm$4ublH zSSg$lBIv0T78ajgW7}5s!IG;eG$r6U#kV~gjfZ?mm*d7sE5o;EpQJFoufF?SJ-Vpf zdvK1qO#eX*BjEgprfG98CuU5HXc=%!AHk`da#|kSu$|F#-VRpGC~WjPW}+AY*+~mp zvsTkm(k`}B#bvq7d7W*5jJ*8_X?nmL!o zrM2ZTi1^a2C{;zbkY;%9p&!T?e+vgm3E=c4-U_ONQY(L9eeeAAB&lwvN+)UN9s%|l z-N&)!u}2DQAz9;^_E(<6*$Pc8G?(P`bJ0b|l&M4Wy5{fZi|clA<*~Z}WQKZadLdhM zt}|Qu-=QlHG4d0mr8)(40F~XT5iPYpQ(jUV<{$=V{6|T0jRnytpz=?UN;~$Fuc)xF zV3%DEtJJ zl?;iW;Oy5qtZQu>iear6F66k~o-c(F&MmAa+OB@;1_ERe_3iKOBlP`(=-9f4U%t@* za=?WFcFhGGH9gM=#fWJ!egPhlrMm*wLk+Wq~hJ9UQQzyS%lWi`yp^O_zL zu-F}Z+lygG#EbimMw)0Kr8w=RpM+>!_(TmB=DOA(-LBlBpjiqJjoK=<+( ziGbdpG5`&DBNU;FpKIGz0zKa#uIOUks3(fJHy|G3?HY!wm>H0>1*vtYpveMWneT^+ zo`6g>oenAQoi_QU9xUBzx;B?ItGa1klf>H)AhjMV?TMOl5ivFIi~-D3nmdx3zoGvu z0;r^hCNeAo<9+4H5k{}e2ENaEdmtQVYMty=GmU%;rny+Oom~N*2rF@P9zx#8a?!^vjH$d>w5@Ebl{?yz?I+fboF*RlM3dlL%3k-i}D+KkQE3mcw zKvRfDpFBkLr~tyei3G}G0pt*ZhKzP;I8?@ut`V9$eiR-=G*r}GX}1igXlno})~{FH z6htpUFhoG13N>MovGiw6EuF#XFi5fmW*pL@#8sJv5NtitzM$HpG11WcvvsNk>RiL^ ziIh}QrV?S}-)J$Og*L`wK3%Z&@?nHZz}2*o^iZDwBF| ze&g&tSv|tKQNPE%a+7k0tx3-CQ_R%NP!4bmP)2y~h#q4k(}Ckx^49B%*9TV{A%e56 zAsv%Yn(pHaltI|T!5{Q}R6eldP)gxQ$2Xq@(wci*v;M$t6(<$&G}&d~9jFjNc?J|j zqeYWKC?qE`Xc%}oY1-G|s*PgNxc&ky*&yd&ImkyN$7uDqu|5~Q2D9f_KKod`)yU;$ zB=D4mkC`u}IuY$STq^roBS_8bq`-hG=lGhdzXgkilF_E5;WU41L{yeQOTqJ}`|a`= zbNZ|N{g2VQfjStOY)-Gg%hF2d&M!2yEXZu~Q6t(;=2vkzfyDum)`o}cIfv5$lC5;A zv*9EZ)1+wMUyIQL_X8Ik*8BF|C{7rA9pL~fr~wsUJ&t}vXhQ8{ZtM_8qeK4G_Tk$0 zaX-e^`uwTE2Bu`!#Z-de2n~~m3y^ZK>%5$FWiPnt8V|G{Wb*m!4OPnH0KfYV&Dcah z*0G0VA2>t`1x~U*%P)1FvdR4hwN zY85-`t$S57zUB8xaO29J@F`9rUfd?*)85`3QG1tZ`_2YE^|P77$nQbibJ>=)m~OOy z?hP8t;4NS-%dS8h{a+@UE4U^?bh72+Q3aqRD0F3i#+PO*b4H; z5e*lYIUP$KT{$+@3!j>Zh+<`{7MU6nlENRBzD?_{3l;%|f8I8kk93s#x+CH&wLHKF z#K*s(WDatMUT&)0P$A;0uxLE@!Ec&gDy`fs1~7!4V|l{6drl2`?>Snii&^v9FB}!S zG_W;_hLM(+Y~e9p#UHu=RYN&Q&NO^ZG{B?pef(UGu-W6Fspw}8NO9BY9*iFV^injC zn0KBPp&)Uq!RSXMX#=QoZcY5GMrK9iut>OX+63+Kv+r{1m!b{hXKRoE*BYk}2gU^G z1kc$y054tuOF5D1zmIdjFpQ|HepEAQT3p+BwbBw8x;FPBKG9(DV*yiRQ#?n0pTr)A zik<#?2qWfvCRkL+Tc3@KTosuJe6d>gzO$H^gOLhf{t&?nbX;#_!(X~brU!pL=rpeP z9ePzFno*~jv$>-EV@2hbRcq#=_KSq%3U9?rUEPEAry4gv-K>5pboPoudFV!29<|2&vkwN>i)3Ut;Xx}+9MNxM<%W8r z7T1bL-hOD>dgH_v)k&kDef=OyF6xl-dHt8Y_D(5_p{+%JsW}^&mxoAlWE2o@OjeWu zmkUu>J1BnTDU~x5gmQXZbxPbGT&){mZ@(PLJgZ$y9ebyXRj__xvYR^nRm|sdIAwMK znC~VVywDT|RVRQhTWzb4sI9hKag-0>Va!t?Rtqy5F|Ckj-u-l&;ZsLT&B~9Kvp<{P zrieS)F_P30)jv1uja+dd6yMSsgvd_02wLd(gVUszxTIQ&w`sEsbml!5AEvDL`iKCO zLOpM}Ish1PnxvirQsr?ELD{6n$%;xrnO*JWkL21DFtoA*2z#-H>9g2j#qTQ6`m*x< zyvsJ-d|G@FOtI|Nz1lntaH&*ux|&g|y^u?r!%|Xo1OjUD9pu`YkFk zSMrmZXf)~QNM)*Xx9R(-m zMm90>w9dlJvzdcx-?}=%731duR&!Yts8_FNF7sHVJbZj(#Jg8U{4hc$Xen>{XJ9Wa zA4i3FlT(f}Y0Tyu8e4Nq-NB{}R=QZ|AOU7N4yKrz=er>R$>3?kms~WiO)l#RMdL1)g6QA?z=!`y7wldZSwPDBl z@sLhBGCmbpZC@2A+{bWzfInAH)>w!$Z}X!QeV2yCn~bg4x-^lqdj5Ugh|7luKXMp* z$BhLQIj4(Jt}GAmMX|(KBN#KCfXFHQQI}D41dy`pDKv(tm(>@iKm!|r3(sGU+LSVSe*<(YxG*uO;O3()Mwa0JGtyhq8U=3k&+Eiwr zc2cAHF0#V*s`Dfv^e_lMa={e$Y|@C&MzJXa5%{J;)c+Nt?=tjgEe zJU{ThF5|HJJGV1LVa~mM^j7$dT&!+(Rbg>g#_(bI%Qi>LQ9{VDRHO+{X`BY3;p^u# zKs#T*@hEpbpWq*5<%^vHh3ASjUM}Km!hKZA>V^{(13#5Jh`m^M|IUZT7(>_LS@aMOWBFow3 zf;-i!z>3ETRj&6RPQESmY`?VWmG;(}Rdj1@qg&Hkt7y@AqLwTXBN;p_A{)dTIf+%~ zUVg4yN}bIQkte+-1pHF+K8(aVetnP#tgh-VU6w#<9PRnsUCsGyqfYG67==vk)|n#u zhhJiK!847TWIjg#hLgk3Tj@sr^oY;i5wDEfpWT4GJhh@KBdp#9*5yc|g;%~1wdLsA zUIb>lK?1156A$JZFGoxC^M&n@tNoZt9&aF=&^kdGhKC0h==(4C0j0$OOU#+_<^Y-Y zbCo&`CQpfB=y;sy1a_1oLSS52Neowb9)Y&lLoO&2^iXz{pSC!=61wo+$ik*(B_@!R zMSpe~VM!KfEH!1J7XiM}w1R)kvLcBiyYKF=?)E)Ve3*Z-^j*u#EfQL?QqXd~+2hju zlg*(Cc*x{9_H+}@eAHZ_Ew}ARp0@#M;z;M z%GE6R+B){s!-Y%gvIAL@8V0O$)uCxbUB)iYju&2ReyfVp2qn7LsahLx7-b$iZ@lC^ zU$+#RoAj+kpu6GK<(wbCvUi=icbeFh6UZA}5h5N|a7T6=w}Hi3zu!7lk;q*vfp@4Y zlRj8!oLOGmho65x;Q0miFIJ=(yCG6=c*WDkk8sJJ^#`t_oZ9zyY?Hfr>pJ)(de8YJ zj{WIt%ok4CWn-NV;*Fzn+YescCtmK|fjRoo_zD~%Aj2e`8T}O%!mWPw&j#vH-tE{G zxy{x<%f8i!>=P>V@Smy*B4ld!fM)u-f?5l#1|wwW?j?Q9%1$bF`o-tTQ_I!bwHMDFM-I|i5v?a|hn0Q8Sv0T?(?*-N=%rM9J1@lC;$Uhko~&ocuc}8U?^OlDr!mFc&Pz3!spX__n|Tab>XJvS_dA(JSoolz-2OSwS5zA^ zU9d|>+G-B$pM({w@%apL4O4M6SR8XcOJikKuZ<~}F%Z)qhNSgG9s3+RN9amcWIlO9 zc@S%_l4~B2`*+Pq5YS@v8pXfd7#wy4anJ3p4{7@35i%c2u#0IB+-V5jmQK83eD^Ui zSe8c*I2rTudfPp!lp6F9Q2xF!Tz)z~RGJaFD+&VxoR+l=&F?91e$5H#de4A`hjQPN z2_j21D<-7VlgkU`MJGNDVuuUA%wyt-fjKwEY1{buor+>j_P)PZ6>uf$L)$7aGh(fM zO;S$Ba2Q!0(!m+#JNOm&6gtka{4!qR2(T{x5?FJQAu$=Sp9Xekjl{2si`5O$1M#F_ zT~%;)-D!``=kwCwF-AVB1;HsKo-+0???ryQ=;f!KBHqEn&-m? z>JF$fmOsMGYuSPvbvdNkk#>yv6T7_<<{18j(MAUI)q-j@0re(y2813xN)%tk2zzUy zyXnw#PR=#-tA+3;u%4M$1`u4|g|0mD5dc311|X7$C1{yI4r0F^9u9XxJ4xs-X^q<`y3c<#_;&oXRLHBMUU1r#I^bxdS_lVOA9`SD?F}`h`^I+9PDce z-KH$8T1HSIk4y!;HaaP}p@sN1LC&mibqN3v^K~6D=#9CA=9ueKcN=uO;P+=L;=*CQB z#Dmnd*^4gtg|RqX(C6D*%J-^=NOSx}2JVn5*RdDwEArim!_xoot)c$GM|)Dn-gf2ejc!&oaWfk}^6~ch z2j=pK!)qv@5y)C7oEoNcly8|`F(tLuF2gw)7~u}85GEKUxcm8H?(0ukJ?^Mc5)0-; zGPkqtyvg`)*~9gK6Dpm#Cr0~3sY6QLNXoJ?O*6zR6ZYfo_=n!>Y92p~-oPUR?--V& zD{u#!OUG?{IlZTQin}-Gd=9&rXxRKtewj&JO`PK{MYoap$s1|6Wui@vkxQqEQq2_b zGXVOnl}~-CZGVVFhvIGu8W46A{U|CjcEBbNS30cL( zNrYU!1t zK&9?Y@ho`IYPEFjRG~HK2>s{l)a^KXp_Q=B(z^J1(7 zDIMlt)3`Per&8%AjO>Wc=Z_z6GpF_h<+_`c<=aZ|k!g|L2a297RbE^@KEQ&xUxeMA zhh^0=RBNlllz>8o^?(|1vqo(!py|cNJ73R_KPhgLuIs5!E!8?ZK}+wWhS?8)h8ld% zlCrs4M%-^!#q5Is7Nv&BBKwqR1LBT~89vhFbpUrV`kg1x@toiv!$6Qlx-=iv`WJ`$ zNF-yWSk^I1cd4}F6#b?37yE)k&x6QLvG0~X?sd&IdSQOM#9mi9<$M9>O}e7vte=8> z+1|@7qEW_oS=x+#Z`iTMn?(g6t%u@;^zT8D@wg}(OIn<^98>-+T;;HI;z8D>va{Yn z?y6WTMTxn^k(he;8R^O(MuQ>@=-vRV*AfkQOe}-JQm2tZsG0YzZ5Omf(eAa9u+6El zCe(0Zm#>n{o9p2Jy5#(acd>4o5Fn^8j^PMN?&oq*#cK0~f2!E+W0oofsUn}!XHqt- zYS)IuYXRR4Nv+CpIn3Gm05DO@L+CP;%GW);H~z)R^yh+CF-n^awI!=noQL;>_|}zs zw(PF)Vm{>&nkRpKZM;i4vdlmJvYR2pZ@;;=FAzzR8uVoi=L^$=ucRAOQ5Wx&%=7zK zJBeh9Nfl#4I~lG}4rlQhKG)89J<3FEV%k{_k$uj0`W5LxoUOI4tlQgPAxy?v}J#x%l=cw zFoexDISBCMs~5#oNZFLH2e3K*8#{y9#~yOCuLn`-Eq%|aEJ8n*7&Ik|+A=z(ja&lF zb7ese+Bxl}zU%{5<(DGI08hCyy2lvgf%J)?JzaoY9K~*iIV*H$4TPx_f!4-yO)7{e z1c?i`NeP4#&p)0A(JGK(Y2jqD6E~(4zUe9c4oe?U*NZ8UQ76*pG78ODWues=BlM-v z$837(54vW;#Rj^YKQM(zvy?+t=@^X(;^$13neMH#qvQQ(WPJEksGpBF9_woiOAaDh z04-i1y*IP3f1IFv6SH)fC53cJ$F!F_+K(rBZEmv=uipxca_LySYH~TM3@rfkOamw~z+IjdO(Sr$X znuk%z={g(qq0_;N9>SnJc*z3`o=FCo2BI$t(~R@@3V6dM8*$>%OU>jI)VL_PcKgp}52I{6fX zDpa*j;}nlHW5DD6@J2Q$179RdVkXma_a?~n=e6R|u0V8shDq7ir2Rg!=SfJj1ohfY z6VG9xe$O1%uzD?10@Dr`y#b}@do%kx6iDj6hnc#4N^2m^u^SJNtsHy}JbB2W zL^9VMg-1TMVVZ8NV0u>!*zsCd4_fH{{w}2tM?Om9b;sL@YcZzS9JZu9`=FylYj>8O zH3toZ^O|}dlY|awM)X(M2``5ubyM8n3eQANIi~>;ga6W-&u(D??WcZQu3uK z2n~iI{D?_KyDyK)ry>r%-HWmO;{TPa?$tLW>X3Qmu*SrXroAU~RPn-lg?OM4o%;L6Bn{ z&<%Gngxwj#ywO0CS<&Xn7IXi=k;>;(Rjtuo@^Aw9FJgQ=G3raxPEH;Q8BKg5!8@iI zD~c0ddpoTUF%}w#)yJd+Ma0wjvp1%4J&WgW6qD!S9qruc>vPKYxOh5+aS`e>k~;Z!gK;wMY}w_+buuzI4XIazM*y}bBr_lwA|cf zQ?5|%m=KMSP3&tDUFB%t5=n2cp1KC(@S8C@KL$wIN1LpayeODxeH{pXp!!DML4dv0 zmC;69m*72Fi50bWAFGS#36`)wcAtOGs4JEk^>K5H!W$|dOZyDOjn&Ql6_QJ~;PHZ+ zsYMq`AJ@!Azn-wmQfH>xXW5GDqB(glBYfAxkBSrVQR=~oJNwR|Xfx=>tUNe4REwb3 zhW0>$?Q;L(7Idb1Nl12kXPa1PQ=)R~P|V8KXQ0B~_8`cVgjC@e?_9Ii4R$-=GHD9Q z*_DW9F?JJOT`J$A*x>5PQHdjPbHOmLqhuFo3DOr>wVJE?)~Ekubun&pQRx$3teOK; z=nw6nY$e0l<2IUGyQc@FUxDv+Hrd0)0PD0P6K(dsLWnzui(&&b84p(VRIB;Z z9G)8?RvExO_;zrmrlMQW6y~v>bLTeUJnxIOOWY510E_4OtY1E-UdoJA)Xot1&rd43 z4Fgnk_8$u?)xr8sh9k_9VTaM93jU%=!9ygeTCwTrW=BtYiH+P|CHbQgth6gxZ|OAw zr+3Bsg9U0@lM0ieQ-wR#VsOb{Om`mSW0%n-o-1mXA}db?=RA+tjz5kuovcaw+|KNI zyHx(d?{Sy#K4>S~`$WTGc!^WR6Oqo@`}2!A1qFb&K&4AmS;%G;9t}DhV|FFWh%Q*4@mG0i5)vG!cJCTK=b7#J9l_AoL zi-eZ4xB zccyaNJPE5`k$T3}Z*+|7!U9b;iDl2O*C{YlF5dE*qa8Vz+Tcv!I?Vv0|K1kolN7*OR0a@qxibBrsN@}-iCGKirx44g1 zs;&#>%gZ>xcrOfr)?O2hZF`v2?8Tn#rO4$Ctn)ON525a8<9w@0ojD=i!qxJ!9t1YM zPI{|tDQhJeC8%^^ZSS|?o|i|LtB=`GnTa|tvKW|#vXmo7i`bwZbWCyq2m8S4OUp&p zyRIy;1x+W8=QpUtEnAS=&E?5;r}HTv1WlGtPWyJ5C;2SCTcxJ^>>Cr(40eyqU zW_mR?l*UTJC{y-=m8~Y}gZv|?ylFTIb(c?%&1{MHNrA-SydNR;ll=yDL+{e2CZCq0 zLwX z?#E8_I9{1>);e(tFVQje$DTZf(K$gi0)#1@e;GM-Yn=G{oXxm^&zB@_mozLwgZRD| z)ha#;2aD1gSE^#|hW2vSSv|F6y7?e2qtw^VeUz+lQ4ADQjTBn@>X=-Kiv1T)*f!me zuG3pjpi;?JH;VOk{AjM{A1^Nrh@jNKz-POx^LFWv@Uwu`FQT`b1A3bD9O{H-WFH}b zC#4>ePfE?v%>jaqV7KJa=1q_ay^i|`kPFNOpSBzFC03{QnW}p%tsEPTKlb+Vq4HW8 zbFaV8`!_D^Zf=He=I5WrV2D{BD$WSG&uEz?RVwgM2cn`c%|g@#+%(kn`71Z)_qKU% zdG*FgQoS~9vaa*KMv)#Ez&;YzuEgkoxVjwn8qU;<8%`%BlXkyb_|ASC*Y~*T{(YKK z(~1+TZBB2miv(~?`VR}8EHWS$6u^e+dt#qGQD2WgLJuwp`zuJ z-AQsa1R_pEyI=ZF$QstA34KtJav^>9b+fJ4V{Xbz_yU~TZ4Z`s=$c#)F5VMiQl+t( z&^~qL%>3i%NScV0y|8%SKN>No19l`aM7yb3OV(*P8Pj0^Bh+f3Y02Lu_TxtdTvy}G z)SY_PPI*!%IcZO@g`8%R3UD(U%Ej@}*Y&jby?!jQ7rkO9@KhFcu$0^^w^KXR)N-af zo|bk@EB#S1L}n@9Bidk>iIBh|jSsN3wrevkpW*0!J$${Hu(g5m+2we!_kNNGP{#|4 zoX=+v#M{tDu`t7cPdKh`b3QU~J0eMiF66<<#(&>?hpeKb*+#o!O;2Cc{V*EUnObvxzOpH`O4 z;3)ryWtwrHpcsy{0a7E1KW>qfVmh@5HPhqnAFMO!SZfC)^zf5D-zhuSq+#dWK@d?_ zOwo+Jm!UF**;D|ZoW^!P{Q4ya{~}dJz!jn?xSplPT=jb327N5wgj!jQZgNBsn>NUH zTT$2RWHfrprmo-6v8U9Y59I{xmU7;;5pX>Kkn*V|0T%)DbAB*p*1J>NyBA_)K|}rr z6lu3?_BlitQ6F_nM9ECTpl6XO*Ct&S9PkI>WL=w!1ndu7W6aB9aEW@eN>@O0xW2Gx zg4Afxq^wq-8tAMxzF>k_}MEcJA*n+N)Iq=8wC<1i6%q%%)wkxsh4x4}WY5|Ozt9}!LoTGc2+Zp4?r{3lkdRbK6x1LccG*PQ6q&A z7_gMD9rl9nj($4?Tc<<(sy_loATEo-LbJ&Ah5$A6( z;K_MJb??se5drO>W+dAAlx>q(v$US^YX(@E-lwJ++{+e1@%;=dTB$Z^>gHA2R<*KV z{YUG1osXiJDEj<}C$KZgJ+ti-2{QLT3MwQ9Z(RCclT6Xf)~ zifxAO<3jR1o|xw1x9H+DcJ=Hd4_Jh$dp|Id-fu^P6Ayq4Yb;bt0+zKrNhf`Iyc$wN z%HGPL&8rZC6>HeV>+=M`hwSAu#2x8joh=YF+++-++Yk4e%N>ZKuaShenF9>A$tf3f z1)YvGD)1k^IGPK-R$W_h{_QJ^^6l+{<0R)l`w|-oV%k?G!chmM&_x0eV?Jy9bV*S~ zZ)QC;iy|bi%xR3R;QLF@RhA}bpcZWbLZ=Msbc9ikk)Bi{Fxlq779!p34v50+YD)mf zl4^KuX{rLjeHoiui_c7k_~aWH#k+>kF@v6?Qu3z+?KFN=Ga`OUU5JCv9jY0)Tg(* zK70-y9FjbQCCdGBIgb}V57y_<_uHZ1LSGT3v9hTpJEMAgu-C1W>@S7G{9ZJVJiPI^0~V~ z>+0cf|sH91L=Qv>1><`g^o5?*5>6yz> zUBlH%jI4mE#nR|TZ>eaNh`jTsba*L!^(~qqREWNi;zXCLWt=;VML)~e@BPbC?{F+? zn6LZriug#4(!jGN_j4W>`tk^nY@wjYeRP0qDs}jS4J@VRz+TCuPA=Qa>d?0)%L3~(`v!mF_zcZXpp%~{Dc$Z6fQF%}-a|S~ znw1!B^X6)4@gkrnEMV6ti!d@jN9(+kqRB3YU=#!!v@tM?#JiJ6$S0-)MGXULaTv=?9Jz8p}CRZU}>hj2RD$NMX z_iW+$pw6IghyZ7hqhIm`55ZA8Zp;SerTR(HWU7q%uGK0U1{t~rqN>AFXuefUmFBQ? zxzpt?U5e-ZES)qm_m-e932hDej4)619GQ`j!TF_fSEtH~6bEAE>=>&R;f%4a_;mak z*bmZw=SO;}$Z^=F^6OcTM833-F5dnRAQolm1q00mc8tq;{V4g7-LvNu+9ZZGNF3_& zp6Q6b>rI=7%Kl%^TOVP9MiHNaSoEVXuyu*bn2J;{5bN$y`i$ad)2RGMGwd$E-%emP zv1LrjIe^kO(fXusxrUDvHk9*d%=OWS>Q;5J<`wAS*h5D`GJK@mSarYc#Phmm2S!xr zY$H{gTlbs&vF`T{gkr{Ar1}v&NcAZ?T#li6qh747H9;5DVB9Gn?Hu^&O|b4a7I|!> zx?Qqz2B)G0YC{+CSrYVKDq2f&(HE7E-1vI8E+Ziu)6O{g{Kq27!z^Bb@v_E=lO}}c zemGxCym)Bt=4lJh+DK3yMyPaq>w`QjihdP8pVS8*^JMe_qdnn`;|dLygx0b+UXDfwws5WMkF z5U=`d!?0fFLgwVjOj0M6%e22!noE_rb3Wm&s_19tWGD7UkYj$n!OG=UabDqgNc3#7 zz8)n(Qe~V0Tl|Kos*x08pvTl9>N5f0c}%dsdGdMD+-1>4tt>U*YXuYACP8M~*=MzC z9x?8*MPVXMCzAR{na=@zYM#d2eoR5#t#scCuSJ22z;-N)C>pOY#on8DVYXu{ZfJZ5 z!861s9?JC-^?ED`LdcDj4VKuC^!PW@ojV);=#x`Xb4rcJm|3DxPG1sS%=cVpXFc|A zVzyAPx1=ZuuSEI5WA_v*!>}*=TCc%g8**U7S?vtBOmqT6lTK@TF09Jl!D4mN&9{*P z$C9O1Q9c{CUcB5&T^4=i%QD}Cmh60Pk5ZacNvkZ>SI&aPd(=nh6&gP8>y=D6wVXq0J!0Y z2%EK>J)VY_!tgdb(T9cx};6^#Z- zUMX-im3=Yn`FM$E9BgG`YDMbxiy}ex+`|@1?{<6UHG2nr(L}mo78 zW)J1DgqwA>{!k7c{4?++(}U&UptjrF+ed!(I0%Tpx`Sy#d>6|9h0dXvtC{?{JJ?Jf zOl&bgILI*eZ6e04S4t4bQPALf3t8zLmI26J+~@o>xfHx=&r`B+;IOkU3NJF}Uv&Ur z`REd4l@%Wz$WUixOjH%J^k}mW5Aj$dzcGA!3ddic;PLGa_xlJ8_)z{aqY<02!He2< ze!X?Gx3+oGz>LGjkewt&y1Y*f=oK`{X}NF0^u)Dd$$-+YkqR?~r(Ik(qgrJ1=8V8C zn4Yc2Y9i<)12SMJt%2AbSuxa4-ojK7nDGmG1^pkbp4;w-)L+!9n`m)+{(LmloQKDn7~aODL7wZW-+(DJ z0Qf;}p|ifaatQ~dSIQn0(Ru9VIN`vYq!u)dI*L}9;&U6(hml_%Crz2jHQsw!h{F@< z?$qURe@0!vwja;nqnCUkmzyRa6X=DPVG*xJ{l5Ys9Nyy*G7fTn1ko4;J)RrlYVUXt zc-W6tK7h>L^F)H@4G+s`o#eWSj4|1L#|3B|@y+o)L03>Fax=o9acY{`kXml1ESiBD zb((_%Ww)D#Hd(;2EMG9;?RE1SPiooRr&xBqw&jAq^!zxwmaI{h#g5&TiTKb4GhGp2K9PT{&AUu9Q|P3-t!FCtXT74VCP*azjTqOPD9$u4vBJvT>^BCJJd@ zM2qM4#+>8IQ5S@R;>)7eVH<^>rCl1UspcH6|WJ7!()4lVv7DUjrCcib6GnZ zPc&#^%T0abLn0H|+X$@oyz|+)@=!vDwjzrnJ6Hwi<{jSkjV?Tj>Z-Mt@zOtle6nG*n_H6a=RGe+N-OY0lJT}T}Ogv==xB-ZEiVG)4yFU({yAIq%2dE+x-bpbB!=y?vsbS%9IJn@Ffx4!kQebje}z`RVUSpVXF-ptk~y{e2W z-NdbLxkFnU&utWk8c{Bz(H!F29n6o|*hLuuXuzz{JQzkWouNY47P>K+5Ig6&^{P8* zqo#uuKyk7F;n#A(#8*La4^+qb%x_kdeO`hX6QZ5$NYYK9_Sl{Akm>dN{+p zH(EdO>LberVQFTUiGOLzfx9xjv)?srJulVuEc=n+>L? zllbwz<&%2GdyA~}Q#xR`O1E3}RVqFo5f3&=?s#&~`T)?#U|B4yQ_o|j)2;zsrf}DJ zl1jN_7Gp^1q&phmjd|;$Dbn<_>g6wg`CfW;zF$B+P>McS3v+-LlIMQc>Xg5XvjbKY z@BmhT+X$c|EIH$g4y5r7yRbC)nOHBtt^*(}j-H7R00VCNuvl1S@-8Rk+N#G<`I;$i(q>ux zg9UyL;Fu7);~>rf85M>moEv5^-$cWBWI#!T;?YVS)|tg5Xo2gpit#BhS!ZiwnLaVK zR@S*+7V7{h>OfhL1LeE+3$%L)aI5(ign$shYdo8ff#UDF;pbJQWE9F9;_>pWWnz2- z2%xdJEGql}H7WCe#wmS?$WOgN3CO93hYt#Px-WI+!MM=UhcT4KhaoAuEi&l`KJ+OD z>T|H(<<`{op~X7SZ?hMzk1*nD)E?2hhU{$U4I3Vg;=!qqK|I8M=qw|*top(izAz4S z>4P_L7AjpR@|DaF(DFVZ7GDRzfZV8foeTE~>km)QJVQ`+N=PVJa_s*~Qg@%3v+KCFWK6xyzFEB3Xinn&~)!{+P97#=2J$aX5I9tMm z0PRVXO^iDHO#yV56s6*jrPV@*bx|4A@qOZozLOEaHQ)gQme3198GZnXJ>iurmg_C# z-NM>naTY9?FE?W7pQ+~0pV!ROX7I9*jK#sg)*L|N%T8V#gPByHVU}pamY;btJ`p}F zI(Y(lPSeyQCt--k&;dp}Z5}5G(vSJ1s!>@uF&cB>fYOV{@o^k@V@93z;Y*&Bh+>J*Vs&s=SO^xCGLbL* z=r2NI0pZW0_4f7%_>1F05{nNgs1xjBp#}%Bv_l6B_0@{LUayy@IcO>Z_NGmnV@wtw zOGtn>XAR_I49ln8+vZ&6XM4Le;ry5W@z~@Mh*lAw*S`YjEX*y*K0sKW!IU0wxtsWblHShWG?FTa%j9* zNg2fh0s_jy`syXp06j{FhG^hIhw`W+ups2=3ojOj06>ZQf{O4rd|*INf2X>FtmvWS zsN=35VQ8_2#-XgwZd7^~4DDWQ->wfp$}({pW=wzyP_SO`#A-R_asauHQ~f|#Q@}zy z`tV#BYdpcAf)6eS-^*YR9XEr$b>xFL1_OUrZd|w|=!HFSWZ(i)x92O`J{&PL?j9eE zCtw_iSab(;NI(V$gSye?OBp2aA!F6^;5q zv4ER4EDQjqjy@b1@MRJ6!H~;XUfKxSY>CuALl$|+r(`Ywg~(W*!w%JxcNzI2~G7tbXRuoGMs2S(pd+!Y(Lc`ctUI2_GcED=$5p;k~ zKws$8a-stQ<1x=1a$Rn-Y?*c@^IZYDOkgI7e@DQo5tuAWBPF7|tN<(2b*2MkSQPv@ zzO76@-AD7J$23(Qw|JH*Y<&hv<$_%wfdax zPJtf36#)6*LbmY+c;~sHXYNSaLgPbYg#jiO8+{Qt=m9=5+KQudT%a60hg`>a1ja4~ zw^6VBXo6ygX)I3~pqV7rH&1q~c>r91iL&#ep4j|oaTdpzFuhPv+T4H=ILNrx_nt>$>O08q{ASC)252UQVhK#T(*W>_^ppWR z2M9ohuU!Kcgg%rV+@I8uwp?%83_dIsyoj8Rp(n)x+M=2tDRua;r1U8UWJRvrm+#x@ z250!U)O-A5-*#n#5E&Rl`@y0NIw7Qqr?4ROzJqjvcRN{t_Pq7sb%pZ zk=l(RpWDg14mki*uA_}Wom109g?@_Qcl~%$k3%2w%+DdWxvo_@9@@-_ zWl=dD61>1}%Zkixuzs@-%ml@6m}k|f9q0&HBo z0czuAzVG(cx1Ffqzp_2V9( zD7MIa^n2papfJGXK2E6z$n+s4QU@;ptv-Rw;<)DBX-a>)0q}3dkNPtCI~gbQECWrE zN2V{f<+9~%M-Ppo=a2zR-t&TPtk7<(vHDI&`-A}9YI0T#iXsmHv9^ zGc74&B0G8`lFxH#)xTXmeA|sl`%Hzdd}t|2^BL)f<_UN~p>f`zMVYq9?o%vNPhSI? z)HL*OSZH^T)Z>h(?4STY7Mk%0nUCcs%^=8Zp{Ko7|4a)FJ~XMvahmBm$$LDfxeq)Y zbA1_YZvR!tcLitxO!^x3wa7cP%X5K;8-ikq(2@f799$2O$#7OKBwlL>pX5THBDI`x8>Ay@Nqu3lc(O}6x(J? zd0c?zeKiEvq%^m3f2-A`sRuk>U2iI}L*oOC{v5czeaNhv!0QqpmFE`IhCW^Z4}7`7(ZGb*=i8)msKq^kJP8X^Z8uac8P-(gEFS zB32f_V8Ly*vht`WxDFbWN{SNci_4M$O+Ar5V=3A)SVrhGps6ndF8!b@<4+rrenfzb zRp!8hKHsMHxUJHne68qQ5C2wu%4E&`oX;tJT7fvz&F1{10=kuQQ2=k0@Wu#>UIdX9 zX+T?H02yEy9JB*wKuz$XwHw#GGQI2QkN=!OY+g>GHCWv*r@0M_%mpif{+UPaQ_Mp* z-nkTcP=-e*W10r~B7iMNC;Z#dmi3>Gx=96enZPJ)%aeL9Z{gC)0$xqhU+V%)B7g-D z&=66yQ+Uyi#mj(ZUz>-YpaYBqFQgZW)cGK2^OJc%Mn5l<^T_CYrlF4hq{s!B$!D4< z6n;!osE(q?E^Bk0=j$?Q?w9kKCexw6TrSeJDi?WcF69?ftr$#keOG`6XbyRCii&od zzA06CytiK2i@&4Rg7Zq0L1I4U=|0pO(4^1<7+#LmhgIUV4lQG{IJV@_QYO;o1%TGP zJvLvG+roZ0W}t#NI#Q4*Fl%_E@xWu&@_NIir!;6E%Hk|0W04HmKh4;0yHmsrmudEDKd%z3=8!cf!-dSws-284goJ)NGlWNJ8#C+VfjeCVB~oX zi9lVB@C9VNcEl@6ECh8P5B>nzz=t<9_Q^eNF|~!x^^6N&0{!7_88aPu*E`Ma#X9)F zH|rwjb6@A-fnEsE=Dcaj(h|P-OH67|dg+s{q^jQdMu$Iy$&0x~R5F0(TrxvK59>D0}e?GEx9Wu*LKMwBeUxWdRgv?w|R&p79tf2g_g@ zj}1>h18o}mK}Xs2qz1I>po5QTeL%R~DRh}PtFD#-zC~c>n}fS)sMVrdqBmx~qt7Lr|GM?-FFpSCuOIrJ#4G?ax){0o z)U*kjNL=wq0mHY@+R(RKFhBw*SP1A)Fp)X}b%0o(e2s5=;A(i`=tJI-egvl;mlS@a zt_wo_82F~4uj$MOTKW@no$E=F!4?`C@}2{77T>U@&twMcpi`b{9`W66tpnc-3=m^L z6mQmU&A&?T|Edo*-jex>jt|ezmqiW`fA+JVr5Oy(8b5kmfYv8g1365L#aEDihQLIb zJgM`!EZR7gDUFUSx|GT1c6+oa!H2~$c;G>vSMk}^@C^&6v=zsqzrmhUZp!cXUA0Y1IJW3zmj2sh1qnhXjV_;eHC+i7UbpMiE6#5$;J=vJ=R z2Blxo$7?RS^wLYONjz~Qi1g$3FbV?9J?q!6uPXBI39|;wlB+ulEk*GEC0tN(s)A1- zLHW?I+WcK+zFN<}sMgd6;D)0IaLB@=(I0+wfsk)0(;c4t#DOEL$A`nCu0h`fB)n|x zNs0Ky1{w73<1tAy;AziRmVq36;51|knHhsVSTuHA-t(UKRP<&4xWL5n^I|MMJa2oS zfByNgGsBqlbFfS-W9;1~BbT)Bq@;;+eIT%dnBxI(~e z-p5KX zJU*MHi-#WWoarNif3C&;nc9C%eAbA5Z_%xh(hn7wma^c!NMj)kq?Dpu*2U&bWJ5uG z1N>RJkmU#;BA{}LtdtFI_a7c&_*T6}a&z>D2Qm}*_@n;zB6x9gg|9(z(M0~FlTNC< z{q1kByyPV>83E`fGi5Sw>Wk$fZI&;$Ip65NOLREKeUh`rnM9GV^tJI-rI+AOOgKvH7TXz$ve@%ecQ(gC! z68Dk*h` zz9lx#;DHBVQhgIx_>&2=5wQNyAQNA7 z!YUKjtsDBw39L0T@+HuVFTOawqd}enh>-cajEJ;j2OC# zd|;#N^p8wEvg|efw1+xbF#dBT0BD+=YSF9u7pvtub+6LXYkLSpYt_ED7MrsI)_pG> zOly<|=(UjZyzl_V5pd+Zc#N|2YFAhJJW7dK4t7ESuzAA|;K36&2)BYdB5nrOo=h{Dh`@fwJ zlo-tB?1;r1kD!2Br>B~}blKz~i;Uk@1Zkg6W&8BR$lG;YlooB&?50lH4)`O`oB z(`EXa(Q5hLdnjVrM}S`Cu=Gk-Xz>>qm#W>Kp&GU0vpbS8hT29jxQe@MxA$KqSKOokDbEiQ3 zC4u-N?NEF_^{L7)?$ux64M^X=av)CgY@U{L-9+>8N0=~?@&Lz>SsEYLxERzHQI&s! zE4pe?DL$0xW;}3%&r) z?gn{wU<4**1N@|(EAmFvSXCWpSWJK)e22+~tu^CuuoPVm#w`T=Vs?iN;sSwMkGzMtK^riP}&C=2>{g*@Dczs2Z1egR5pGx zu&DyjxE#g$)CW-VmmQDGrMX<=|MT;n_q&s7e6{B?6GR)3*NiZ?&E~8PHer|4|pVrwG8@l<>uC@E1tKy#lbd&;XxuBdA+_Ky8Ea z$LH~d{{H^{XJ2;NWjE>CWPuJy{w5ju=7KcP)Y_aj#?(O872vOA|K0~cnX7Z!X{WtI z*7sea3BMdS1Z%9wO(!DTER?Ib97+SAswN*dLUCP|BXHRRWfDf-ig zATQF>XV%j+Q?@GcWp!g^t^OL~L$b2_3#6+B(p9p;O93&~SmlW9hVah?>~H&K4>xB7 z;_C$F3uT%A<-GIGyJwoj|D_ye4$xD-Z0NY@5@>Ioe{Nl=i_P5yX7<+cz4sM}xd`1? zk7x3J*%K;n(Z%1rx&!&ekA3W8c?*vH=5hJ_qMr+M8kjr{$UUiHttY~f=PTed5gt#6 zzH=6OdRMu5;mNREeCooEosB9tlp1$WvF0`E31i(+4WhZ9rUw2$^B^4|t>k!600000 LNkvXXu0mjfkN{h; literal 0 HcmV?d00001 diff --git a/resources/profiles/Phrozen/filament/Phrozen PLA @Phrozen Arco 0.4 nozzle.json b/resources/profiles/Phrozen/filament/Phrozen PLA @Phrozen Arco 0.4 nozzle.json new file mode 100644 index 0000000000..b36382bbc3 --- /dev/null +++ b/resources/profiles/Phrozen/filament/Phrozen PLA @Phrozen Arco 0.4 nozzle.json @@ -0,0 +1,258 @@ +{ + "type": "filament", + "filament_id": "GFL99", + "setting_id": "GFSA04", + "from": "system", + "instantiation": "true", + "name": "Phrozen PLA @Phrozen Arco 0.4 nozzle", + "inherits": "fdm_filament_pla", + "filament_settings_id": [ + "Phrozen PLA @Phrozen Arco 0.4 nozzle" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "nozzle_temperature": [ + "205" + ], + "compatible_printers": [ + "Phrozen Arco 0.4 nozzle" + ], + "activate_air_filtration": [ + "1" + ], + "activate_chamber_temp_control": [ + "0" + ], + "adaptive_pressure_advance_model": [ + "0.042,0.72,5000\n0.044,1.44,5000\n0.045,2.16,5000\n0.045,2.88,5000\n0.045,3.58,5000\n0.044,4.3,5000\n0.045,5.02,5000\n0.043,5.73,5000\n0.045,6.45,5000\n0.041,7.17,5000\n0.039,7.89,5000\n0.038,8.61,5000\n0.036,9.33,5000\n0.033,10.05,5000\n0.032,10.77,5000\n0.034,11.49,5000\n0.033,12.21,5000" + ], + "additional_cooling_fan_speed": [ + "60" + ], + "bed_type": [ + "Cool Plate" + ], + "chamber_temperature": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "compatible_printers_condition": "", + "compatible_prints": [], + "compatible_prints_condition": "", + "complete_print_exhaust_fan_speed": [ + "80" + ], + "cool_plate_temp": [ + "35" + ], + "cool_plate_temp_initial_layer": [ + "35" + ], + "default_filament_colour": [ + "" + ], + "during_print_exhaust_fan_speed": [ + "60" + ], + "enable_overhang_bridge_fan": [ + "1" + ], + "enable_pressure_advance": [ + "1" + ], + "eng_plate_temp": [ + "0" + ], + "eng_plate_temp_initial_layer": [ + "0" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cooling_final_speed": [ + "0" + ], + "filament_cooling_initial_speed": [ + "0" + ], + "filament_cooling_moves": [ + "0" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.24" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_end_gcode": [ + "; filament end gcode\n" + ], + "filament_is_support": [ + "0" + ], + "filament_load_time": [ + "31.925" + ], + "filament_loading_speed": [ + "0" + ], + "filament_loading_speed_start": [ + "0" + ], + "filament_long_retractions_when_cut": [ + "nil" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_multitool_ramming": [ + "0" + ], + "filament_multitool_ramming_flow": [ + "0" + ], + "filament_multitool_ramming_volume": [ + "0" + ], + "filament_notes": [ + "" + ], + "filament_ramming_parameters": [ + "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" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_lift_above": [ + "nil" + ], + "filament_retract_lift_below": [ + "nil" + ], + "filament_retract_lift_enforce": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_distances_when_cut": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_shrink": [ + "100%" + ], + "filament_soluble": [ + "0" + ], + "filament_start_gcode": [ + "; filament start gcode" + ], + "filament_toolchange_delay": [ + "0" + ], + "filament_unload_time": [ + "24.75" + ], + "filament_unloading_speed": [ + "0" + ], + "filament_unloading_speed_start": [ + "0" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "55" + ], + "hot_plate_temp_initial_layer": [ + "55" + ], + "nozzle_temperature_initial_layer": [ + "215" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "pressure_advance": [ + "0.035" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "8" + ], + "slow_down_min_speed": [ + "20" + ], + "support_material_interface_fan_speed": [ + "-1" + ], + "temperature_vitrification": [ + "55" + ], + "textured_plate_temp": [ + "55" + ], + "textured_plate_temp_initial_layer": [ + "55" + ] +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/filament/fdm_filament_abs.json b/resources/profiles/Phrozen/filament/fdm_filament_abs.json new file mode 100644 index 0000000000..55f18c5ee9 --- /dev/null +++ b/resources/profiles/Phrozen/filament/fdm_filament_abs.json @@ -0,0 +1,82 @@ +{ + "type": "filament", + "name": "fdm_filament_abs", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_common", + "filament_type": [ + "ABS" + ], + "cool_plate_temp": [ + "105" + ], + "eng_plate_temp": [ + "105" + ], + "hot_plate_temp": [ + "105" + ], + "cool_plate_temp_initial_layer": [ + "105" + ], + "eng_plate_temp_initial_layer": [ + "105" + ], + "hot_plate_temp_initial_layer": [ + "105" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "fan_cooling_layer_time": [ + "30" + ], + "filament_max_volumetric_speed": [ + "28.6" + ], + "filament_density": [ + "1.04" + ], + "filament_cost": [ + "20" + ], + "nozzle_temperature_initial_layer": [ + "260" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "10" + ], + "overhang_fan_threshold": [ + "25%" + ], + "overhang_fan_speed": [ + "80" + ], + "nozzle_temperature": [ + "260" + ], + "temperature_vitrification": [ + "110" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "3" + ] +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/filament/fdm_filament_asa.json b/resources/profiles/Phrozen/filament/fdm_filament_asa.json new file mode 100644 index 0000000000..9495d85477 --- /dev/null +++ b/resources/profiles/Phrozen/filament/fdm_filament_asa.json @@ -0,0 +1,82 @@ +{ + "type": "filament", + "name": "fdm_filament_asa", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_common", + "filament_type": [ + "ASA" + ], + "cool_plate_temp": [ + "105" + ], + "eng_plate_temp": [ + "105" + ], + "hot_plate_temp": [ + "105" + ], + "cool_plate_temp_initial_layer": [ + "105" + ], + "eng_plate_temp_initial_layer": [ + "105" + ], + "hot_plate_temp_initial_layer": [ + "105" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "fan_cooling_layer_time": [ + "35" + ], + "filament_max_volumetric_speed": [ + "28.6" + ], + "filament_density": [ + "1.04" + ], + "filament_cost": [ + "20" + ], + "nozzle_temperature_initial_layer": [ + "260" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "10" + ], + "overhang_fan_threshold": [ + "25%" + ], + "overhang_fan_speed": [ + "80" + ], + "nozzle_temperature": [ + "260" + ], + "temperature_vitrification": [ + "110" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "3" + ] +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/filament/fdm_filament_common.json b/resources/profiles/Phrozen/filament/fdm_filament_common.json new file mode 100644 index 0000000000..457f288c63 --- /dev/null +++ b/resources/profiles/Phrozen/filament/fdm_filament_common.json @@ -0,0 +1,138 @@ +{ + "type": "filament", + "name": "fdm_filament_common", + "from": "system", + "instantiation": "false", + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp": [ + "60" + ], + "hot_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "60" + ], + "hot_plate_temp_initial_layer": [ + "60" + ], + "overhang_fan_threshold": [ + "95%" + ], + "overhang_fan_speed": [ + "100" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "filament_end_gcode": [ + "; filament end gcode \n" + ], + "filament_flow_ratio": [ + "1" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "fan_cooling_layer_time": [ + "60" + ], + "filament_cost": [ + "0" + ], + "filament_density": [ + "0" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_max_volumetric_speed": [ + "0" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "bed_type": [ + "Cool Plate" + ], + "nozzle_temperature_initial_layer": [ + "200" + ], + "full_fan_speed_layer": [ + "0" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "35" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "8" + ], + "filament_start_gcode": [ + "; Filament gcode\n" + ], + "nozzle_temperature": [ + "200" + ], + "temperature_vitrification": [ + "100" + ] +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/filament/fdm_filament_pa.json b/resources/profiles/Phrozen/filament/fdm_filament_pa.json new file mode 100644 index 0000000000..e8c8dea0e8 --- /dev/null +++ b/resources/profiles/Phrozen/filament/fdm_filament_pa.json @@ -0,0 +1,79 @@ +{ + "type": "filament", + "name": "fdm_filament_pa", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_common", + "filament_type": [ + "PA" + ], + "cool_plate_temp": [ + "0" + ], + "eng_plate_temp": [ + "100" + ], + "hot_plate_temp": [ + "100" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "eng_plate_temp_initial_layer": [ + "100" + ], + "hot_plate_temp_initial_layer": [ + "100" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "fan_cooling_layer_time": [ + "4" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_density": [ + "1.04" + ], + "filament_cost": [ + "20" + ], + "nozzle_temperature_initial_layer": [ + "290" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "0" + ], + "overhang_fan_speed": [ + "30" + ], + "nozzle_temperature": [ + "290" + ], + "temperature_vitrification": [ + "108" + ], + "nozzle_temperature_range_low": [ + "270" + ], + "nozzle_temperature_range_high": [ + "300" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "2" + ] +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/filament/fdm_filament_pc.json b/resources/profiles/Phrozen/filament/fdm_filament_pc.json new file mode 100644 index 0000000000..3192f802c5 --- /dev/null +++ b/resources/profiles/Phrozen/filament/fdm_filament_pc.json @@ -0,0 +1,82 @@ +{ + "type": "filament", + "name": "fdm_filament_pc", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_common", + "filament_type": [ + "PC" + ], + "cool_plate_temp": [ + "0" + ], + "eng_plate_temp": [ + "110" + ], + "hot_plate_temp": [ + "110" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "eng_plate_temp_initial_layer": [ + "110" + ], + "hot_plate_temp_initial_layer": [ + "110" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "fan_cooling_layer_time": [ + "30" + ], + "filament_max_volumetric_speed": [ + "23.2" + ], + "filament_density": [ + "1.04" + ], + "filament_cost": [ + "20" + ], + "nozzle_temperature_initial_layer": [ + "270" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "10" + ], + "overhang_fan_threshold": [ + "25%" + ], + "overhang_fan_speed": [ + "60" + ], + "nozzle_temperature": [ + "280" + ], + "temperature_vitrification": [ + "140" + ], + "nozzle_temperature_range_low": [ + "260" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "2" + ] +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/filament/fdm_filament_pet.json b/resources/profiles/Phrozen/filament/fdm_filament_pet.json new file mode 100644 index 0000000000..4d7ba4ada0 --- /dev/null +++ b/resources/profiles/Phrozen/filament/fdm_filament_pet.json @@ -0,0 +1,76 @@ +{ + "type": "filament", + "name": "fdm_filament_pet", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_common", + "filament_type": [ + "PETG" + ], + "cool_plate_temp": [ + "60" + ], + "eng_plate_temp": [ + "0" + ], + "hot_plate_temp": [ + "80" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "eng_plate_temp_initial_layer": [ + "0" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "fan_cooling_layer_time": [ + "20" + ], + "filament_max_volumetric_speed": [ + "25" + ], + "filament_density": [ + "1.27" + ], + "filament_cost": [ + "30" + ], + "nozzle_temperature_initial_layer": [ + "255" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "20" + ], + "overhang_fan_speed": [ + "100" + ], + "nozzle_temperature": [ + "255" + ], + "temperature_vitrification": [ + "80" + ], + "nozzle_temperature_range_low": [ + "220" + ], + "nozzle_temperature_range_high": [ + "260" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/filament/fdm_filament_pla.json b/resources/profiles/Phrozen/filament/fdm_filament_pla.json new file mode 100644 index 0000000000..5426679f33 --- /dev/null +++ b/resources/profiles/Phrozen/filament/fdm_filament_pla.json @@ -0,0 +1,88 @@ +{ + "type": "filament", + "name": "fdm_filament_pla", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_common", + "filament_type": [ + "PLA" + ], + "fan_cooling_layer_time": [ + "100" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_density": [ + "1.24" + ], + "filament_cost": [ + "20" + ], + "cool_plate_temp": [ + "35" + ], + "eng_plate_temp": [ + "0" + ], + "hot_plate_temp": [ + "45" + ], + "cool_plate_temp_initial_layer": [ + "35" + ], + "eng_plate_temp_initial_layer": [ + "0" + ], + "hot_plate_temp_initial_layer": [ + "45" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "nozzle_temperature": [ + "220" + ], + "temperature_vitrification": [ + "60" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_range_high": [ + "230" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "4" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/filament/fdm_filament_pva.json b/resources/profiles/Phrozen/filament/fdm_filament_pva.json new file mode 100644 index 0000000000..eee5675ea8 --- /dev/null +++ b/resources/profiles/Phrozen/filament/fdm_filament_pva.json @@ -0,0 +1,94 @@ +{ + "type": "filament", + "name": "fdm_filament_pva", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_common", + "filament_type": [ + "PVA" + ], + "cool_plate_temp": [ + "35" + ], + "eng_plate_temp": [ + "0" + ], + "hot_plate_temp": [ + "45" + ], + "cool_plate_temp_initial_layer": [ + "35" + ], + "eng_plate_temp_initial_layer": [ + "0" + ], + "hot_plate_temp_initial_layer": [ + "45" + ], + "fan_cooling_layer_time": [ + "100" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "filament_soluble": [ + "1" + ], + "filament_is_support": [ + "1" + ], + "filament_density": [ + "1.24" + ], + "filament_cost": [ + "20" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "nozzle_temperature": [ + "220" + ], + "temperature_vitrification": [ + "50" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "slow_down_min_speed": [ + "10" + ], + "slow_down_layer_time": [ + "4" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/filament/fdm_filament_tpu.json b/resources/profiles/Phrozen/filament/fdm_filament_tpu.json new file mode 100644 index 0000000000..3d14ece169 --- /dev/null +++ b/resources/profiles/Phrozen/filament/fdm_filament_tpu.json @@ -0,0 +1,82 @@ +{ + "type": "filament", + "name": "fdm_filament_tpu", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_common", + "filament_type": [ + "TPU" + ], + "cool_plate_temp": [ + "30" + ], + "eng_plate_temp": [ + "30" + ], + "hot_plate_temp": [ + "35" + ], + "cool_plate_temp_initial_layer": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "30" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "fan_cooling_layer_time": [ + "100" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "filament_density": [ + "1.24" + ], + "filament_cost": [ + "20" + ], + "filament_retraction_length": [ + "0.4" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "overhang_fan_speed": [ + "100" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "nozzle_temperature": [ + "240" + ], + "temperature_vitrification": [ + "60" + ], + "nozzle_temperature_range_low": [ + "200" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "filament_start_gcode": [ + "; filament start gcode\n" + ] +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/machine/Phrozen Arco 0.4 nozzle.json b/resources/profiles/Phrozen/machine/Phrozen Arco 0.4 nozzle.json new file mode 100644 index 0000000000..d0d4866090 --- /dev/null +++ b/resources/profiles/Phrozen/machine/Phrozen Arco 0.4 nozzle.json @@ -0,0 +1,232 @@ +{ + "from": "User", + "inherits": "fdm_machine_common", + "instantiation": "true", + "printer_technology": "FFF", + "version": "0.0.0.1", + "printer_settings_id": "Phrozen Arco 0.4 nozzle", + "printer_model": "Phrozen Arco", + "printer_variant": "0.4", + "name": "Phrozen Arco 0.4 nozzle", + "nozzle_diameter": [ + "0.4" + ], + "default_print_profile": "0.20mm Standard @Phrozen Arco 0.4 nozzle", + "default_filament_profile": [ + "Phrozen PLA @Phrozen Arco 0.4 nozzle" + ], + "disable_m73": "1", + "gcode_flavor": "klipper", + "printable_area": [ + "0x0", + "300x0", + "300x300", + "0x300" + ], + "printable_height": "300", + "thumbnails": "240x224/PNG", + "thumbnails_format": "PNG", + "adaptive_bed_mesh_margin": "0", + "auxiliary_fan": "1", + "bbl_use_printhost": "0", + "bed_custom_model": "", + "bed_custom_texture": "", + "bed_exclude_area": [], + "bed_mesh_max": "0,0", + "bed_mesh_min": "0,0", + "bed_mesh_probe_distance": "0,0", + "before_layer_change_gcode": "; BEFORE_LAYER_CHANGE [layer_num] @ [layer_z]mm", + "best_object_pos": "0.5,0.5", + "change_extrusion_role_gcode": "", + "change_filament_gcode": "G1 E-1 F3600", + "cooling_tube_length": "0", + "cooling_tube_retraction": "0", + "deretraction_speed": [ + "0" + ], + "emit_machine_limits_to_gcode": "1", + "enable_filament_ramming": "0", + "enable_long_retraction_when_cut": "0", + "extra_loading_move": "0", + "extruder_clearance_height_to_lid": "240", + "extruder_clearance_height_to_rod": "48", + "extruder_clearance_radius": "60", + "extruder_colour": [ + "#FF4D4F" + ], + "extruder_offset": [ + "0x0" + ], + "fan_kickstart": "0", + "fan_speedup_overhangs": "1", + "fan_speedup_time": "0", + "head_wrap_detect_zone": [], + "high_current_on_filament_swap": "0", + "host_type": "octoprint", + "is_custom_defined": "0", + "layer_change_gcode": "; AFTER_LAYER_CHANGE [layer_num] @ [layer_z]mm", + "long_retractions_when_cut": [ + "0" + ], + "machine_end_gcode": "PRINT_END", + "machine_load_filament_time": "126.423", + "machine_max_acceleration_e": [ + "5000", + "5000" + ], + "machine_max_acceleration_extruding": [ + "20000", + "20000" + ], + "machine_max_acceleration_retracting": [ + "5000", + "5000" + ], + "machine_max_acceleration_travel": [ + "20000", + "20000" + ], + "machine_max_acceleration_x": [ + "10000", + "10000" + ], + "machine_max_acceleration_y": [ + "10000", + "10000" + ], + "machine_max_acceleration_z": [ + "500", + "500" + ], + "machine_max_jerk_e": [ + "2.5", + "2.5" + ], + "machine_max_jerk_x": [ + "9", + "9" + ], + "machine_max_jerk_y": [ + "9", + "9" + ], + "machine_max_jerk_z": [ + "3", + "3" + ], + "machine_max_speed_e": [ + "80", + "80" + ], + "machine_max_speed_x": [ + "600", + "600" + ], + "machine_max_speed_y": [ + "600", + "600" + ], + "machine_max_speed_z": [ + "15", + "15" + ], + "machine_min_extruding_rate": [ + "0", + "0" + ], + "machine_min_travel_rate": [ + "0", + "0" + ], + "machine_pause_gcode": "M601", + "machine_start_gcode": "M107\nG90\nM140 S65 ; set bed temperature\nM104 S140 ; set temperature\nM190 S65 ; set bed temperature\nM109 S140 ; set temperature\nPG28\nM106 S255 \nG30\n;AUTO_LEVELING_2\nM106 S0\nG21\nM83\nM109 S220\nP0 M1\nP28\nP2 A1", + "machine_tool_change_time": "0", + "machine_unload_filament_time": "0", + "manual_filament_change": "0", + "max_layer_height": [ + "0.28" + ], + "min_layer_height": [ + "0.08" + ], + "nozzle_height": "4", + "nozzle_hrc": "0", + "nozzle_type": "brass", + "nozzle_volume": "71.6", + "parking_pos_retraction": "0", + "pellet_modded_printer": "0", + "preferred_orientation": "0", + "printer_notes": "", + "printer_structure": "corexy", + "printhost_authorization_type": "key", + "printhost_ssl_ignore_revoke": "0", + "printing_by_object_gcode": "", + "purge_in_prime_tower": "0", + "retract_before_wipe": [ + "0%" + ], + "retract_length_toolchange": [ + "0" + ], + "retract_lift_above": [ + "0.3" + ], + "retract_lift_below": [ + "249" + ], + "retract_lift_enforce": [ + "All Surfaces" + ], + "retract_on_top_layer": [ + "1" + ], + "retract_restart_extra": [ + "0" + ], + "retract_restart_extra_toolchange": [ + "0" + ], + "retract_when_changing_layer": [ + "1" + ], + "retraction_distances_when_cut": [ + "18" + ], + "retraction_length": [ + "2" + ], + "retraction_minimum_travel": [ + "1" + ], + "retraction_speed": [ + "45" + ], + "scan_first_layer": "0", + "silent_mode": "0", + "single_extruder_multi_material": "1", + "support_air_filtration": "1", + "support_chamber_temp_control": "0", + "support_multi_bed_types": "0", + "template_custom_gcode": "", + "time_cost": "0", + "time_lapse_gcode": "", + "travel_slope": [ + "3" + ], + "upward_compatible_machine": [], + "use_firmware_retraction": "0", + "use_relative_e_distances": "1", + "wipe": [ + "1" + ], + "wipe_distance": [ + "2" + ], + "z_hop": [ + "0.4" + ], + "z_hop_types": [ + "Spiral Lift" + ], + "z_offset": "0" +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/machine/Phrozen Arco.json b/resources/profiles/Phrozen/machine/Phrozen Arco.json new file mode 100644 index 0000000000..b60155d2cd --- /dev/null +++ b/resources/profiles/Phrozen/machine/Phrozen Arco.json @@ -0,0 +1,12 @@ +{ + "type": "machine_model", + "machine_tech": "FFF", + "family": "Phrozen", + "name": "Phrozen Arco", + "model_id": "Phrozen Arco", + "nozzle_diameter": "0.4", + "bed_model": "Phrozen Arco_buildplate_model.stl", + "bed_texture": "Phrozen Arco_buildplate_texture.png", + "hotend_model": "", + "default_materials": "Phrozen PLA @Phrozen Arco 0.4 nozzle" +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/machine/_fdm_machine_common.json b/resources/profiles/Phrozen/machine/_fdm_machine_common.json new file mode 100644 index 0000000000..e11bc7c234 --- /dev/null +++ b/resources/profiles/Phrozen/machine/_fdm_machine_common.json @@ -0,0 +1,139 @@ +{ + "type": "machine", + "name": "fdm_machine_common", + "from": "system", + "instantiation": "false", + "gcode_flavor": "marlin", + "machine_start_gcode": "", + "machine_end_gcode": "", + "extruder_colour": [ + "#018001" + ], + "extruder_offset": [ + "0x0" + ], + "machine_max_acceleration_e": [ + "5000", + "5000" + ], + "machine_max_acceleration_extruding": [ + "2000", + "2000" + ], + "machine_max_acceleration_retracting": [ + "5000", + "5000" + ], + "machine_max_acceleration_travel": [ + "3000", + "3000" + ], + "machine_max_acceleration_x": [ + "2000", + "2000" + ], + "machine_max_acceleration_y": [ + "2000", + "2000" + ], + "machine_max_acceleration_z": [ + "300", + "200" + ], + "machine_max_speed_e": [ + "25", + "25" + ], + "machine_max_speed_x": [ + "300", + "200" + ], + "machine_max_speed_y": [ + "300", + "200" + ], + "machine_max_speed_z": [ + "12", + "12" + ], + "machine_max_jerk_e": [ + "2.5", + "2.5" + ], + "machine_max_jerk_x": [ + "9", + "9" + ], + "machine_max_jerk_y": [ + "9", + "9" + ], + "machine_max_jerk_z": [ + "0.2", + "0.4" + ], + "machine_min_extruding_rate": [ + "0", + "0" + ], + "machine_min_travel_rate": [ + "0", + "0" + ], + "max_layer_height": [ + "0.3" + ], + "min_layer_height": [ + "0.08" + ], + "printable_height": "300", + "extruder_clearance_radius": "65", + "extruder_clearance_height_to_rod": "36", + "extruder_clearance_height_to_lid": "140", + "nozzle_diameter": [ + "0.4" + ], + "printer_settings_id": "", + "printer_technology": "FFF", + "printer_variant": "0.4", + "retraction_minimum_travel": [ + "1" + ], + "retract_before_wipe": [ + "70%" + ], + "retract_when_changing_layer": [ + "1" + ], + "retraction_length": [ + "0.8" + ], + "retract_length_toolchange": [ + "2" + ], + "z_hop": [ + "0.4" + ], + "retract_restart_extra": [ + "0" + ], + "retract_restart_extra_toolchange": [ + "0" + ], + "retraction_speed": [ + "30" + ], + "deretraction_speed": [ + "30" + ], + "silent_mode": "0", + "single_extruder_multi_material": "1", + "change_filament_gcode": "", + "before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n", + "layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]", + "machine_pause_gcode": "M400 U1\n", + "wipe": [ + "1" + ], + "z_hop_types": "Normal Lift" +} diff --git a/resources/profiles/Phrozen/machine/fdm_machine_common.json b/resources/profiles/Phrozen/machine/fdm_machine_common.json new file mode 100644 index 0000000000..5316314092 --- /dev/null +++ b/resources/profiles/Phrozen/machine/fdm_machine_common.json @@ -0,0 +1,7 @@ +{ + "type": "machine", + "name": "fdm_machine_common", + "from": "system", + "instantiation": "false", + "gcode_flavor": "marlin" +} diff --git a/resources/profiles/Phrozen/process/0.20mm Standard @Phrozen Arco 0.4 nozzle.json b/resources/profiles/Phrozen/process/0.20mm Standard @Phrozen Arco 0.4 nozzle.json new file mode 100644 index 0000000000..58904f9912 --- /dev/null +++ b/resources/profiles/Phrozen/process/0.20mm Standard @Phrozen Arco 0.4 nozzle.json @@ -0,0 +1,292 @@ +{ + "type": "process", + "from": "system", + "setting_id": "GP004", + "name": "0.20mm Standard @Phrozen Arco 0.4 nozzle", + "inherits": "fdm_process_common", + "instantiation": "true", + "is_custom_defined": "0", + "version": "1.3.2412.13", + "print_settings_id": "0.20mm Standard @Phrozen Arco 0.4 nozzle", + "layer_height": "0.2", + "filename_format": "{input_filename_base}_{filament_type[0]}_{layer_height}_{print_time}.gcode", + "compatible_printers": [ + "Phrozen Arco 0.4 nozzle" + ], + "accel_to_decel_enable": "1", + "accel_to_decel_factor": "50%", + "alternate_extra_wall": "0", + "bottom_shell_layers": "3", + "bottom_shell_thickness": "0", + "bottom_solid_infill_flow_ratio": "1", + "bottom_surface_pattern": "monotonic", + "bridge_acceleration": "50%", + "bridge_angle": "0", + "bridge_density": "100%", + "bridge_flow": "0.9", + "bridge_no_support": "0", + "bridge_speed": "30", + "brim_ears_detection_length": "1", + "brim_ears_max_angle": "125", + "brim_object_gap": "0.1", + "brim_type": "auto_brim", + "brim_width": "5", + "compatible_printers_condition": "", + "counterbore_hole_bridging": "none", + "default_acceleration": "10000", + "default_jerk": "9", + "detect_narrow_internal_solid_infill": "1", + "detect_overhang_wall": "1", + "detect_thin_wall": "1", + "dont_filter_internal_bridges": "disabled", + "draft_shield": "disabled", + "elefant_foot_compensation": "0.075", + "elefant_foot_compensation_layers": "1", + "enable_arc_fitting": "0", + "enable_overhang_speed": "1", + "enable_prime_tower": "1", + "enable_support": "0", + "enforce_support_layers": "0", + "ensure_vertical_shell_thickness": "ensure_all", + "exclude_object": "1", + "extra_perimeters_on_overhangs": "1", + "filter_out_gap_fill": "0", + "flush_into_infill": "0", + "flush_into_objects": "0", + "flush_into_support": "1", + "fuzzy_skin": "none", + "fuzzy_skin_first_layer": "0", + "fuzzy_skin_point_distance": "0.8", + "fuzzy_skin_thickness": "0.3", + "gap_fill_target": "topbottom", + "gap_infill_speed": "250", + "gcode_add_line_number": "0", + "gcode_comments": "0", + "gcode_label_objects": "1", + "hole_to_polyhole": "0", + "hole_to_polyhole_threshold": "0.01", + "hole_to_polyhole_twisted": "1", + "independent_support_layer_height": "1", + "infill_anchor": "400%", + "infill_anchor_max": "20", + "infill_combination": "0", + "infill_direction": "45", + "infill_jerk": "9", + "infill_wall_overlap": "15%", + "initial_layer_acceleration": "500", + "initial_layer_infill_speed": "80", + "initial_layer_jerk": "9", + "initial_layer_line_width": "0.5", + "initial_layer_min_bead_width": "85%", + "initial_layer_print_height": "0.2", + "initial_layer_speed": "50", + "initial_layer_travel_speed": "100%", + "inner_wall_acceleration": "5000", + "inner_wall_jerk": "9", + "inner_wall_line_width": "0.45", + "inner_wall_speed": "300", + "interface_shells": "0", + "internal_bridge_flow": "1", + "internal_bridge_speed": "150%", + "internal_solid_infill_acceleration": "5000", + "internal_solid_infill_line_width": "0.42", + "internal_solid_infill_pattern": "monotonic", + "internal_solid_infill_speed": "250", + "ironing_angle": "-1", + "ironing_flow": "10%", + "ironing_pattern": "zig-zag", + "ironing_spacing": "0.15", + "ironing_speed": "30", + "ironing_type": "no ironing", + "is_infill_first": "0", + "line_width": "0.42", + "make_overhang_printable": "0", + "make_overhang_printable_angle": "55", + "make_overhang_printable_hole_size": "0", + "max_bridge_length": "10", + "max_travel_detour_distance": "0", + "max_volumetric_extrusion_rate_slope": "0", + "max_volumetric_extrusion_rate_slope_segment_length": "3", + "min_bead_width": "85%", + "min_feature_size": "25%", + "min_length_factor": "0.5", + "min_width_top_surface": "300%", + "minimum_sparse_infill_area": "15", + "mmu_segmented_region_interlocking_depth": "0", + "mmu_segmented_region_max_width": "0", + "notes": "", + "only_one_wall_first_layer": "0", + "only_one_wall_top": "1", + "ooze_prevention": "0", + "outer_wall_acceleration": "5000", + "outer_wall_jerk": "9", + "outer_wall_line_width": "0.42", + "outer_wall_speed": "200", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "10", + "overhang_reverse": "0", + "overhang_reverse_internal_only": "0", + "overhang_reverse_threshold": "50%", + "overhang_speed_classic": "1", + "overhang_totally_speed": "10", + "post_process": [], + "precise_outer_wall": "1", + "precise_z_height": "0", + "prime_tower_brim_width": "5", + "prime_tower_width": "35", + "prime_volume": "20", + "print_flow_ratio": "1", + "print_order": "default", + "print_sequence": "by layer", + "raft_contact_distance": "0.1", + "raft_expansion": "1.5", + "raft_first_layer_density": "90%", + "raft_first_layer_expansion": "5", + "raft_layers": "0", + "reduce_crossing_wall": "0", + "reduce_infill_retraction": "1", + "resolution": "0.012", + "role_based_wipe_speed": "1", + "rotate_solid_infill_direction": "1", + "scarf_angle_threshold": "155", + "scarf_joint_flow_ratio": "1", + "scarf_joint_speed": "35", + "scarf_overhang_threshold": "40%", + "seam_gap": "10%", + "seam_position": "aligned", + "seam_slope_conditional": "1", + "seam_slope_entire_loop": "0", + "seam_slope_inner_walls": "0", + "seam_slope_min_length": "10", + "seam_slope_start_height": "0", + "seam_slope_steps": "10", + "seam_slope_type": "none", + "single_extruder_multi_material_priming": "0", + "skirt_distance": "2", + "skirt_height": "1", + "skirt_loops": "0", + "skirt_speed": "50", + "slice_closing_radius": "0.049", + "slicing_mode": "regular", + "slow_down_layers": "0", + "slowdown_for_curled_perimeters": "0", + "small_area_infill_flow_compensation": "0", + "small_area_infill_flow_compensation_model": [ + "0,0", + "\n0.2,0.4444", + "\n0.4,0.6145", + "\n0.6,0.7059", + "\n0.8,0.7619", + "\n1.5,0.8571", + "\n2,0.8889", + "\n3,0.9231", + "\n5,0.9520", + "\n10,1" + ], + "small_perimeter_speed": "50%", + "small_perimeter_threshold": "0", + "solid_infill_direction": "45", + "solid_infill_filament": "1", + "sparse_infill_acceleration": "100%", + "sparse_infill_density": "15%", + "sparse_infill_filament": "1", + "sparse_infill_line_width": "0.45", + "sparse_infill_pattern": "crosshatch", + "sparse_infill_speed": "270", + "spiral_mode": "0", + "spiral_mode_max_xy_smoothing": "200%", + "spiral_mode_smooth": "0", + "staggered_inner_seams": "0", + "standby_temperature_delta": "-5", + "support_angle": "0", + "support_base_pattern": "default", + "support_base_pattern_spacing": "2.5", + "support_bottom_interface_spacing": "0.5", + "support_bottom_z_distance": "0.2", + "support_critical_regions_only": "0", + "support_expansion": "0", + "support_filament": "0", + "support_interface_bottom_layers": "2", + "support_interface_filament": "0", + "support_interface_loop_pattern": "0", + "support_interface_not_for_body": "1", + "support_interface_pattern": "auto", + "support_interface_spacing": "0.5", + "support_interface_speed": "80", + "support_interface_top_layers": "2", + "support_line_width": "0.42", + "support_object_xy_distance": "0.35", + "support_on_build_plate_only": "1", + "support_remove_small_overhang": "1", + "support_speed": "150", + "support_style": "default", + "support_threshold_angle": "30", + "support_top_z_distance": "0.18", + "support_type": "tree(auto)", + "thick_bridges": "0", + "thick_internal_bridges": "1", + "timelapse_type": "0", + "top_bottom_infill_wall_overlap": "25%", + "top_shell_layers": "5", + "top_shell_thickness": "1", + "top_solid_infill_flow_ratio": "0.97", + "top_surface_acceleration": "2000", + "top_surface_jerk": "9", + "top_surface_line_width": "0.42", + "top_surface_pattern": "monotonicline", + "top_surface_speed": "200", + "travel_acceleration": "10000", + "travel_jerk": "9", + "travel_speed": "300", + "travel_speed_z": "0", + "tree_support_adaptive_layer_height": "1", + "tree_support_angle_slow": "25", + "tree_support_auto_brim": "1", + "tree_support_branch_angle": "45", + "tree_support_branch_angle_organic": "40", + "tree_support_branch_diameter": "2", + "tree_support_branch_diameter_angle": "5", + "tree_support_branch_diameter_double_wall": "3", + "tree_support_branch_diameter_organic": "2", + "tree_support_branch_distance": "5", + "tree_support_branch_distance_organic": "1", + "tree_support_brim_width": "3", + "tree_support_tip_diameter": "0.8", + "tree_support_top_rate": "30%", + "tree_support_wall_count": "0", + "wall_direction": "auto", + "wall_distribution_count": "1", + "wall_filament": "1", + "wall_generator": "classic", + "wall_loops": "2", + "wall_sequence": "outer wall/inner wall", + "wall_transition_angle": "10", + "wall_transition_filter_deviation": "25%", + "wall_transition_length": "100%", + "wipe_before_external_loop": "0", + "wipe_on_loops": "0", + "wipe_speed": "80%", + "wipe_tower_bridging": "10", + "wipe_tower_cone_angle": "15", + "wipe_tower_extra_spacing": "120%", + "wipe_tower_extruder": "0", + "wipe_tower_max_purge_speed": "90", + "wipe_tower_no_sparse_layers": "0", + "wipe_tower_rotation_angle": "0", + "wiping_volumes_extruders": [ + "70", + "70", + "70", + "70", + "70", + "70", + "70", + "70", + "70", + "70" + ], + "xy_contour_compensation": "0", + "xy_hole_compensation": "0" +} \ No newline at end of file diff --git a/resources/profiles/Phrozen/process/fdm_process_common.json b/resources/profiles/Phrozen/process/fdm_process_common.json new file mode 100644 index 0000000000..489a8ca472 --- /dev/null +++ b/resources/profiles/Phrozen/process/fdm_process_common.json @@ -0,0 +1,107 @@ +{ + "type": "process", + "name": "fdm_process_common", + "from": "system", + "instantiation": "false", + "adaptive_layer_height": "0", + "reduce_crossing_wall": "0", + "max_travel_detour_distance": "0", + "bottom_surface_pattern": "monotonic", + "bottom_shell_thickness": "0", + "bridge_speed": "50", + "brim_width": "5", + "brim_object_gap": "0.1", + "compatible_printers": [], + "compatible_printers_condition": "", + "print_sequence": "by layer", + "default_acceleration": "1000", + "initial_layer_acceleration": "500", + "top_surface_acceleration": "800", + "travel_acceleration": "1000", + "inner_wall_acceleration": "900", + "outer_wall_acceleration": "700", + "bridge_no_support": "0", + "draft_shield": "disabled", + "elefant_foot_compensation": "0", + + "outer_wall_line_width": "0.4", + "wall_infill_order": "inner wall/outer wall/infill", + "line_width": "0.4", + "infill_direction": "45", + "sparse_infill_density": "15%", + "sparse_infill_pattern": "crosshatch", + "initial_layer_line_width": "0.5", + "initial_layer_print_height": "0.2", + "infill_combination": "0", + "sparse_infill_line_width": "0.45", + "infill_wall_overlap": "25%", + "interface_shells": "0", + "ironing_flow": "10%", + "ironing_spacing": "0.15", + "ironing_speed": "30", + "ironing_type": "no ironing", + "reduce_infill_retraction": "1", + "filename_format": "{input_filename_base}_{filament_type[initial_tool]}_{print_time}.gcode", + "detect_overhang_wall": "1", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "10", + "inner_wall_line_width": "0.45", + "wall_loops": "3", + "print_settings_id": "", + "raft_layers": "0", + "seam_position": "aligned", + "skirt_distance": "2", + "skirt_height": "1", + "skirt_loops": "0", + "minimum_sparse_infill_area": "15", + "internal_solid_infill_line_width": "0.4", + "spiral_mode": "0", + "standby_temperature_delta": "-5", + "enable_support": "0", + "resolution": "0.012", + "support_type": "normal(auto)", + "support_on_build_plate_only": "0", + "support_top_z_distance": "0.2", + "support_filament": "0", + "support_line_width": "0.4", + "support_interface_loop_pattern": "0", + "support_interface_filament": "0", + "support_interface_top_layers": "2", + "support_interface_bottom_layers": "2", + "support_interface_spacing": "0.5", + "support_interface_speed": "80", + "support_base_pattern": "rectilinear", + "support_base_pattern_spacing": "2.5", + "support_speed": "150", + "support_threshold_angle": "30", + "support_object_xy_distance": "0.35", + "tree_support_branch_angle": "30", + "tree_support_wall_count": "0", + "tree_support_with_infill": "0", + "detect_thin_wall": "0", + "top_surface_pattern": "monotonicline", + "top_surface_line_width": "0.4", + "top_shell_thickness": "0.8", + "enable_prime_tower": "0", + "wipe_tower_no_sparse_layers": "0", + "prime_tower_width": "60", + "xy_hole_compensation": "0", + "xy_contour_compensation": "0", + "layer_height": "0.2", + "bottom_shell_layers": "3", + "top_shell_layers": "4", + "bridge_flow": "1", + "initial_layer_speed": "45", + "initial_layer_infill_speed": "45", + "outer_wall_speed": "45", + "inner_wall_speed": "80", + "sparse_infill_speed": "150", + "internal_solid_infill_speed": "150", + "top_surface_speed": "50", + "gap_infill_speed": "30", + "travel_speed": "200", + "enable_arc_fitting": "0" + +} From 6da7fe62a2a56cd9a7537e93dc451bb9cba96413 Mon Sep 17 00:00:00 2001 From: "Dipl.-Ing. Raoul Rubien, BSc" Date: Sat, 14 Jun 2025 18:41:20 +0200 Subject: [PATCH 4/7] Fixes, refactors and enhances Linux build-scripts (#8269) * fixes and refactors linux build scripts - build_linux.sh: fixes wrong AppImage build folder; refactors script; enhances help text - harmonizes names: BuildLinux.sh and BuildLinuxImage.sh - fixes file permissions: cmake inherits .in-file permission; removes chmod 755 in scripts - linux.d/debian: removes false positive error message - updates documentation * enables ANSI-colored output for GNU or Clang * build_linux.sh: adds -p flag to disable PCH for boosting ccache hit rate * Allow compilation on distributions based on Ubuntu/Debian (#8625) * build_linux.sh: takes over changes from BuildLinux.sh * CMakeLists.txt: removes leftovers, enables ANSI-colored output * CMakeLists.txt: fixes issue where FORCE_COLORED_OUTPUT was not respected form environment (introduces -C cli arg) * merges 5df4275: Make it easy to pass extra build args to deps and orca in BuildLinux.sh (#9648) --- .devcontainer/postCreate.sh | 7 +- .github/workflows/build_all.yml | 2 +- .github/workflows/build_deps.yml | 4 +- .github/workflows/build_orca.yml | 6 +- BuildLinux.sh | 207 ----------------- CMakeLists.txt | 11 +- Dockerfile | 8 +- README.md | 1 - build_linux.sh | 217 ++++++++++++++++++ doc/How-to-build.md | 4 +- linux.d/README.md | 2 +- linux.d/debian | 2 +- src/CMakeLists.txt | 2 +- ...nuxImage.sh.in => build_linux_image.sh.in} | 12 +- 14 files changed, 252 insertions(+), 233 deletions(-) delete mode 100755 BuildLinux.sh create mode 100755 build_linux.sh rename src/platform/unix/{BuildLinuxImage.sh.in => build_linux_image.sh.in} (93%) mode change 100644 => 100755 diff --git a/.devcontainer/postCreate.sh b/.devcontainer/postCreate.sh index ea76f8e22c..b805c08b8b 100755 --- a/.devcontainer/postCreate.sh +++ b/.devcontainer/postCreate.sh @@ -3,12 +3,13 @@ apt update apt upgrade -y +build_linux="./build_linux.sh -u" echo "-----------------------------------------" -echo "Running BuildLinux.sh with update flag..." +echo "Running ${build_linux}..." echo "-----------------------------------------" -./BuildLinux.sh -u +${build_linux} echo "------------------------------" echo "Installing missing packages..." echo "------------------------------" -apt install -y libgl1-mesa-dev m4 autoconf libtool \ No newline at end of file +apt install -y libgl1-mesa-dev m4 autoconf libtool diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index c0990561e1..51caa6e3e9 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -25,7 +25,7 @@ on: - '**/CMakeLists.txt' - 'version.inc' - ".github/workflows/build_*.yml" - - 'BuildLinux.sh' + - 'build_linux.sh' - 'build_release_vs2022.bat' - 'build_release_macos.sh' - 'flatpak/**' diff --git a/.github/workflows/build_deps.yml b/.github/workflows/build_deps.yml index b9dd05f647..f45394adf1 100644 --- a/.github/workflows/build_deps.yml +++ b/.github/workflows/build_deps.yml @@ -105,9 +105,9 @@ jobs: run: | mkdir -p ${{ github.workspace }}/deps/build mkdir -p ${{ github.workspace }}/deps/build/destdir - sudo ./BuildLinux.sh -ur + sudo ./build_linux.sh -ur sudo chown $USER -R ./ - ./BuildLinux.sh -dr + ./build_linux.sh -dr cd deps/build tar -czvf OrcaSlicer_dep_ubuntu_$(date +"%Y%m%d").tar.gz destdir diff --git a/.github/workflows/build_orca.yml b/.github/workflows/build_orca.yml index 75e78e344a..1102895cc0 100644 --- a/.github/workflows/build_orca.yml +++ b/.github/workflows/build_orca.yml @@ -246,10 +246,10 @@ jobs: libgtk-3-dev libgtk-3-dev libmspack-dev libosmesa6-dev libsecret-1-dev libsoup2.4-dev libssl-dev libudev-dev libwayland-dev \ libwebkit2gtk-${{ env.webkit-ver }}-dev libxkbcommon-dev locales locales-all m4 pkgconf sudo wayland-protocols wget ${{ env.libfuse2-pkg }} - - name: Install dependencies from BuildLinux.sh + - name: Install dependencies from build_linux.sh if: inputs.os == 'ubuntu-20.04' || inputs.os == 'ubuntu-24.04' shell: bash - run: sudo ./BuildLinux.sh -ur + run: sudo ./build_linux.sh -ur - name: Fix permissions if: inputs.os == 'ubuntu-20.04' || inputs.os == 'ubuntu-24.04' @@ -262,7 +262,7 @@ jobs: env: ubuntu-ver-str: ${{ (inputs.os == 'ubuntu-24.04' && '_Ubuntu2404') || '' }} run: | - ./BuildLinux.sh -isr + ./build_linux.sh -isr mv -n ./build/OrcaSlicer_Linux_V${{ env.ver_pure }}.AppImage ./build/OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}_${{ env.ver }}.AppImage chmod +x ./build/OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}_${{ env.ver }}.AppImage diff --git a/BuildLinux.sh b/BuildLinux.sh deleted file mode 100755 index d0ff7348a0..0000000000 --- a/BuildLinux.sh +++ /dev/null @@ -1,207 +0,0 @@ -#!/bin/bash - -export ROOT=$(dirname $(readlink -f ${0})) - -set -e # exit on first error - -function check_available_memory_and_disk() { - FREE_MEM_GB=$(free -g -t | grep 'Mem' | rev | cut -d" " -f1 | rev) - MIN_MEM_GB=10 - - FREE_DISK_KB=$(df -k . | tail -1 | awk '{print $4}') - MIN_DISK_KB=$((10 * 1024 * 1024)) - - if [ ${FREE_MEM_GB} -le ${MIN_MEM_GB} ]; then - echo -e "\nERROR: Orca Slicer Builder requires at least ${MIN_MEM_GB}G of 'available' mem (system has only ${FREE_MEM_GB}G available)" - echo && free -h && echo - echo "Invoke with -r to skip ram and disk checks." - exit 2 - fi - - if [[ ${FREE_DISK_KB} -le ${MIN_DISK_KB} ]]; then - echo -e "\nERROR: Orca Slicer Builder requires at least $(echo ${MIN_DISK_KB} |awk '{ printf "%.1fG\n", $1/1024/1024; }') (system has only $(echo ${FREE_DISK_KB} | awk '{ printf "%.1fG\n", $1/1024/1024; }') disk free)" - echo && df -h . && echo - echo "Invoke with -r to skip ram and disk checks." - exit 1 - fi -} - -function usage() { - echo "Usage: ./BuildLinux.sh [-1][-b][-c][-d][-i][-r][-s][-u] [-j N]" - echo " -1: limit builds to 1 core (where possible)" - echo " -j N: limit builds to N cores (where possible)" - echo " -b: build in debug mode" - echo " -c: force a clean build" - echo " -d: build deps (optional)" - echo " -h: this help output" - echo " -i: Generate appimage (optional)" - echo " -r: skip ram and disk checks (low ram compiling)" - echo " -s: build orca-slicer (optional)" - echo " -u: update and build dependencies (optional and need sudo)" - echo "For a first use, you want to 'sudo ./BuildLinux.sh -u'" - echo " and then './BuildLinux.sh -dsi'" -} - -unset name -while getopts ":1j:bcdghirsu" opt; do - case ${opt} in - 1 ) - export CMAKE_BUILD_PARALLEL_LEVEL=1 - ;; - j ) - export CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG - ;; - b ) - BUILD_DEBUG="1" - ;; - c ) - CLEAN_BUILD=1 - ;; - d ) - BUILD_DEPS="1" - ;; - h ) usage - exit 0 - ;; - i ) - BUILD_IMAGE="1" - ;; - r ) - SKIP_RAM_CHECK="1" - ;; - s ) - BUILD_ORCA="1" - ;; - u ) - UPDATE_LIB="1" - ;; - esac -done - -if [ ${OPTIND} -eq 1 ] -then - usage - exit 0 -fi - - -# cmake 4.x compatibility workaround -export CMAKE_POLICY_VERSION_MINIMUM=3.5 - -DISTRIBUTION=$(awk -F= '/^ID=/ {print $2}' /etc/os-release | tr -d '"') -DISTRIBUTION_LIKE=$(awk -F= '/^ID_LIKE=/ {print $2}' /etc/os-release | tr -d '"') -# Check for direct distribution match to Ubuntu/Debian -if [ "${DISTRIBUTION}" == "ubuntu" ] || [ "${DISTRIBUTION}" == "linuxmint" ]; then - DISTRIBUTION="debian" -# Check if distribution is Debian/Ubuntu-like based on ID_LIKE -elif [[ "${DISTRIBUTION_LIKE}" == *"debian"* ]] || [[ "${DISTRIBUTION_LIKE}" == *"ubuntu"* ]]; then - DISTRIBUTION="debian" -elif [[ "${DISTRIBUTION_LIKE}" == *"arch"* ]]; then - DISTRIBUTION="arch" -fi -if [ ! -f ./linux.d/${DISTRIBUTION} ] -then - echo "Your distribution does not appear to be currently supported by these build scripts" - exit 1 -fi -source ./linux.d/${DISTRIBUTION} - -echo "FOUND_GTK3=${FOUND_GTK3}" -if [[ -z "${FOUND_GTK3_DEV}" ]] -then - echo "Error, you must install the dependencies before." - echo "Use option -u with sudo" - exit 1 -fi - -echo "Changing date in version..." -{ - # change date in version - sed -i "s/+UNKNOWN/_$(date '+%F')/" version.inc -} -echo "done" - - -if ! [[ -n "${SKIP_RAM_CHECK}" ]] -then - check_available_memory_and_disk -fi - -if [[ -n "${BUILD_DEPS}" ]] -then - echo "Configuring dependencies..." - BUILD_ARGS="${DEPS_EXTRA_BUILD_ARGS} -DDEP_WX_GTK3=ON" - if [[ -n "${CLEAN_BUILD}" ]] - then - rm -fr deps/build - fi - if [ ! -d "deps/build" ] - then - mkdir deps/build - fi - if [[ -n "${BUILD_DEBUG}" ]] - then - # have to build deps with debug & release or the cmake won't find everything it needs - if [ ! -d "deps/build/release" ] - then - mkdir deps/build/release - fi - cmake -S deps -B deps/build/release -G Ninja -DDESTDIR="${PWD}/deps/build/destdir" -DDEP_DOWNLOAD_DIR="${PWD}/deps/DL_CACHE" ${BUILD_ARGS} - cmake --build deps/build/release - BUILD_ARGS="${BUILD_ARGS} -DCMAKE_BUILD_TYPE=Debug" - fi - - echo "cmake -S deps -B deps/build -G Ninja ${BUILD_ARGS}" - cmake -S deps -B deps/build -G Ninja ${BUILD_ARGS} - cmake --build deps/build -fi - - -if [[ -n "${BUILD_ORCA}" ]] -then - echo "Configuring OrcaSlicer..." - if [[ -n "${CLEAN_BUILD}" ]] - then - rm -fr build - fi - BUILD_ARGS="${ORCA_EXTRA_BUILD_ARGS}" - if [[ -n "${FOUND_GTK3_DEV}" ]] - then - BUILD_ARGS="${BUILD_ARGS} -DSLIC3R_GTK=3" - fi - if [[ -n "${BUILD_DEBUG}" ]] - then - BUILD_ARGS="${BUILD_ARGS} -DCMAKE_BUILD_TYPE=Debug -DBBL_INTERNAL_TESTING=1" - else - BUILD_ARGS="${BUILD_ARGS} -DBBL_RELEASE_TO_PUBLIC=1 -DBBL_INTERNAL_TESTING=0" - fi - echo -e "cmake -S . -B build -G Ninja -DCMAKE_PREFIX_PATH="${PWD}/deps/build/destdir/usr/local" -DSLIC3R_STATIC=1 -DORCA_TOOLS=ON ${BUILD_ARGS}" - cmake -S . -B build -G Ninja \ - -DCMAKE_PREFIX_PATH="${PWD}/deps/build/destdir/usr/local" \ - -DSLIC3R_STATIC=1 \ - -DORCA_TOOLS=ON \ - ${BUILD_ARGS} - echo "done" - echo "Building OrcaSlicer ..." - cmake --build build --target OrcaSlicer - echo "Building OrcaSlicer_profile_validator .." - cmake --build build --target OrcaSlicer_profile_validator - ./run_gettext.sh - echo "done" -fi - -if [[ -e ${ROOT}/build/src/BuildLinuxImage.sh ]]; then -# Give proper permissions to script -chmod 755 ${ROOT}/build/src/BuildLinuxImage.sh - -echo "[9/9] Generating Linux app..." - pushd build - if [[ -n "${BUILD_IMAGE}" ]] - then - ${ROOT}/build/src/BuildLinuxImage.sh -i - else - ${ROOT}/build/src/BuildLinuxImage.sh - fi - popd -echo "done" -fi diff --git a/CMakeLists.txt b/CMakeLists.txt index dc145b5f5d..9b0263226d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,6 +108,15 @@ set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux") set(IS_CROSS_COMPILE FALSE) +option (COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." OFF) +if (${COLORED_OUTPUT}) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + add_compile_options (-fdiagnostics-color=always) + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + add_compile_options (-fcolor-diagnostics) + endif () +endif () + if (APPLE) set(CMAKE_FIND_FRAMEWORK LAST) set(CMAKE_FIND_APPBUNDLE LAST) @@ -806,7 +815,7 @@ endif() if (NOT WIN32 AND NOT APPLE) set(SLIC3R_APP_CMD "orca-slicer") - configure_file(${LIBDIR}/platform/unix/build_appimage.sh.in ${CMAKE_CURRENT_BINARY_DIR}/build_appimage.sh @ONLY) + configure_file(${LIBDIR}/platform/unix/build_appimage.sh.in ${CMAKE_CURRENT_BINARY_DIR}/build_appimage.sh USE_SOURCE_PERMISSIONS @ONLY) endif() option(BUILD_BBS_TEST_TOOLS "Build bbs test tools" OFF) diff --git a/Dockerfile b/Dockerfile index f244d20acb..db9bf705e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -65,17 +65,17 @@ WORKDIR OrcaSlicer # These can run together, but we run them seperate for podman caching # Update System dependencies -RUN ./BuildLinux.sh -u +RUN ./build_linux.sh -u # Build dependencies in ./deps -RUN ./BuildLinux.sh -dr +RUN ./build_linux.sh -dr # Build slic3r -RUN ./BuildLinux.sh -sr +RUN ./build_linux.sh -sr # Build AppImage ENV container podman -RUN ./BuildLinux.sh -ir +RUN ./build_linux.sh -ir # It's easier to run Orca Slicer as the same username, # UID and GID as your workstation. Since we bind mount diff --git a/README.md b/README.md index 3802af7a9e..eff7c96317 100644 --- a/README.md +++ b/README.md @@ -183,4 +183,3 @@ The GNU Affero General Public License, version 3 ensures that if you use any par Orca Slicer includes a pressure advance calibration pattern test adapted from Andrew Ellis' generator, which is licensed under GNU General Public License, version 3. Ellis' generator is itself adapted from a generator developed by Sineos for Marlin, which is licensed under GNU General Public License, version 3. The Bambu networking plugin is based on non-free libraries from BambuLab. It is optional to the Orca Slicer and provides extended functionalities for Bambulab printer users. - diff --git a/build_linux.sh b/build_linux.sh new file mode 100755 index 0000000000..eb3c1bc920 --- /dev/null +++ b/build_linux.sh @@ -0,0 +1,217 @@ +#!/usr/bin/env bash + +SCRIPT_NAME=$(basename "$0") +SCRIPT_PATH=$(dirname $(readlink -f ${0})) + +pushd ${SCRIPT_PATH} > /dev/null + +set -e # Exit immediately if a command exits with a non-zero status. + +function check_available_memory_and_disk() { + FREE_MEM_GB=$(free --gibi --total | grep 'Mem' | rev | cut --delimiter=" " --fields=1 | rev) + MIN_MEM_GB=10 + + FREE_DISK_KB=$(df --block-size=1K . | tail -1 | awk '{print $4}') + MIN_DISK_KB=$((10 * 1024 * 1024)) + + if [[ ${FREE_MEM_GB} -le ${MIN_MEM_GB} ]] ; then + echo -e "\nERROR: Orca Slicer Builder requires at least ${MIN_MEM_GB}G of 'available' mem (system has only ${FREE_MEM_GB}G available)" + echo && free --human && echo + echo "Invoke with -r to skip RAM and disk checks." + exit 2 + fi + + if [[ ${FREE_DISK_KB} -le ${MIN_DISK_KB} ]] ; then + echo -e "\nERROR: Orca Slicer Builder requires at least $(echo ${MIN_DISK_KB} |awk '{ printf "%.1fG\n", $1/1024/1024; }') (system has only $(echo ${FREE_DISK_KB} | awk '{ printf "%.1fG\n", $1/1024/1024; }') disk free)" + echo && df --human-readable . && echo + echo "Invoke with -r to skip ram and disk checks." + exit 1 + fi +} + +function usage() { + echo "Usage: ./${SCRIPT_NAME} [-1][-b][-c][-d][-h][-i][-j N][-p][-r][-s][-u]" + echo " -1: limit builds to one core (where possible)" + echo " -j N: limit builds to N cores (where possible)" + echo " -b: build in debug mode" + echo " -c: force a clean build" + echo " -C: enable ANSI-colored compile output (GNU/Clang only)" + echo " -d: download and build dependencies in ./deps/ (build prerequisite)" + echo " -h: prints this help text" + echo " -i: build the Orca Slicer AppImage (optional)" + echo " -p: boost ccache hit rate by disabling precompiled headers (default: ON)" + echo " -r: skip RAM and disk checks (low RAM compiling)" + echo " -s: build the Orca Slicer (optional)" + echo " -u: install system dependencies (asks for sudo password; build prerequisite)" + echo "For a first use, you want to './${SCRIPT_NAME} -u'" + echo " and then './${SCRIPT_NAME} -dsi'" +} + +SLIC3R_PRECOMPILED_HEADERS="ON" + +unset name +while getopts ":1j:bcCdhiprsu" opt ; do + case ${opt} in + 1 ) + export CMAKE_BUILD_PARALLEL_LEVEL=1 + ;; + j ) + export CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG + ;; + b ) + BUILD_DEBUG="1" + ;; + c ) + CLEAN_BUILD=1 + ;; + C ) + COLORED_OUTPUT="-DCOLORED_OUTPUT=ON" + ;; + d ) + BUILD_DEPS="1" + ;; + h ) usage + exit 0 + ;; + i ) + BUILD_IMAGE="1" + ;; + p ) + SLIC3R_PRECOMPILED_HEADERS="OFF" + ;; + r ) + SKIP_RAM_CHECK="1" + ;; + s ) + BUILD_ORCA="1" + ;; + u ) + UPDATE_LIB="1" + ;; + esac +done + +if [ ${OPTIND} -eq 1 ] ; then + usage + exit 0 +fi + +# cmake 4.x compatibility workaround +export CMAKE_POLICY_VERSION_MINIMUM=3.5 + +DISTRIBUTION=$(awk -F= '/^ID=/ {print $2}' /etc/os-release | tr -d '"') +DISTRIBUTION_LIKE=$(awk -F= '/^ID_LIKE=/ {print $2}' /etc/os-release | tr -d '"') +# Check for direct distribution match to Ubuntu/Debian +if [ "${DISTRIBUTION}" == "ubuntu" ] || [ "${DISTRIBUTION}" == "linuxmint" ] ; then + DISTRIBUTION="debian" +# Check if distribution is Debian/Ubuntu-like based on ID_LIKE +elif [[ "${DISTRIBUTION_LIKE}" == *"debian"* ]] || [[ "${DISTRIBUTION_LIKE}" == *"ubuntu"* ]] ; then + DISTRIBUTION="debian" +elif [[ "${DISTRIBUTION_LIKE}" == *"arch"* ]] ; then + DISTRIBUTION="arch" +fi + +if [ ! -f ./linux.d/${DISTRIBUTION} ] ; then + echo "Your distribution \"${DISTRIBUTION}\" is not supported by system-dependency scripts in ./linux.d/" + echo "Please resolve dependencies manually and contribute a script for your distribution to upstream." + exit 1 +else + echo "resolving system dependencies for distribution \"${DISTRIBUTION}\" ..." + source ./linux.d/${DISTRIBUTION} +fi + +echo "FOUND_GTK3=${FOUND_GTK3}" +if [[ -z "${FOUND_GTK3_DEV}" ]] ; then + echo "Error, you must install the dependencies before." + echo "Use option -u with sudo" + exit 1 +fi + +echo "Changing date in version..." +{ + # change date in version + sed --in-place "s/+UNKNOWN/_$(date '+%F')/" version.inc +} +echo "done" + + +if ! [[ -n "${SKIP_RAM_CHECK}" ]] ; then + check_available_memory_and_disk +fi + +if [[ -n "${BUILD_DEPS}" ]] ; then + echo "Configuring dependencies..." + BUILD_ARGS="${DEPS_EXTRA_BUILD_ARGS} -DDEP_WX_GTK3=ON" + if [[ -n "${CLEAN_BUILD}" ]] + then + rm -fr deps/build + fi + if [ ! -d "deps/build" ] + then + mkdir deps/build + fi + if [[ -n "${BUILD_DEBUG}" ]] ; then + # build deps with debug and release else cmake will not find required sources + if [ ! -d "deps/build/release" ] ; then + mkdir deps/build/release + fi + cmake -S deps -B deps/build/release -DSLIC3R_PCH=${SLIC3R_PRECOMPILED_HEADERS} -G Ninja -DDESTDIR="${SCRIPT_PATH}/deps/build/destdir" -DDEP_DOWNLOAD_DIR="${SCRIPT_PATH}/deps/DL_CACHE" ${COLORED_OUTPUT} ${BUILD_ARGS} + cmake --build deps/build/release + BUILD_ARGS="${BUILD_ARGS} -DCMAKE_BUILD_TYPE=Debug" + fi + + echo "cmake -S deps -B deps/build -G Ninja ${BUILD_ARGS}" + cmake -S deps -B deps/build -G Ninja ${COLORED_OUTPUT} ${BUILD_ARGS} + cmake --build deps/build +fi + +if [[ -n "${BUILD_ORCA}" ]] ; then + echo "Configuring OrcaSlicer..." + if [[ -n "${CLEAN_BUILD}" ]] ; then + rm --force --recursive build + fi + BUILD_ARGS="${ORCA_EXTRA_BUILD_ARGS}" + if [[ -n "${FOUND_GTK3_DEV}" ]] ; then + BUILD_ARGS="${BUILD_ARGS} -DSLIC3R_GTK=3" + fi + if [[ -n "${BUILD_DEBUG}" ]] ; then + BUILD_ARGS="${BUILD_ARGS} -DCMAKE_BUILD_TYPE=Debug -DBBL_INTERNAL_TESTING=1" + else + BUILD_ARGS="${BUILD_ARGS} -DBBL_RELEASE_TO_PUBLIC=1 -DBBL_INTERNAL_TESTING=0" + fi + + CMAKE_CMD="cmake -S . -B build -G Ninja \ +-DSLIC3R_PCH=${SLIC3R_PRECOMPILED_HEADERS} \ +-DCMAKE_PREFIX_PATH="${SCRIPT_PATH}/deps/build/destdir/usr/local" \ +-DSLIC3R_STATIC=1 \ +-DORCA_TOOLS=ON \ +${COLORED_OUTPUT} \ +${BUILD_ARGS}" + echo -e "${CMAKE_CMD}" + ${CMAKE_CMD} + echo "done" + echo "Building OrcaSlicer ..." + cmake --build build --target OrcaSlicer + echo "Building OrcaSlicer_profile_validator .." + cmake --build build --target OrcaSlicer_profile_validator + ./run_gettext.sh + echo "done" +fi + +if [[ -n "${BUILD_IMAGE}" || -n "${BUILD_ORCA}" ]] ; then + pushd build > /dev/null + echo "[9/9] Generating Linux app..." + build_linux_image="./src/build_linux_image.sh" + if [[ -e ${build_linux_image} ]] ; then + extra_script_args="" + if [[ -n "${BUILD_IMAGE}" ]] ; then + extra_script_args="-i" + fi + ${build_linux_image} ${extra_script_args} + + echo "done" + fi + popd > /dev/null # build +fi + +popd > /dev/null # ${SCRIPT_PATH} diff --git a/doc/How-to-build.md b/doc/How-to-build.md index 49553c039e..c414bad3be 100644 --- a/doc/How-to-build.md +++ b/doc/How-to-build.md @@ -188,6 +188,6 @@ All required dependencies will be installed automatically by the provided shell ### Instructions ```shell -sudo ./BuildLinux.sh -u # Install dependencies -./BuildLinux.sh -dsi # Build OrcaSlicer +`./build_linux.sh -u` # install dependencies +`./build_linux.sh -disr` # build OrcaSlicer ``` diff --git a/linux.d/README.md b/linux.d/README.md index 7f05a77cd4..4cfc11b045 100644 --- a/linux.d/README.md +++ b/linux.d/README.md @@ -1,3 +1,3 @@ Files in this directory are named for the **exact** output of `awk -F= '/^ID=/ {print $2}' /etc/os-release` for their respective distribution. -When `BuildLinux.sh` is executed, the respective file for the distribution will be sourced so the distribution specific instructions/logic are used. +When `build_linux.sh` is executed, the respective file for the distribution will be sourced so the distribution specific instructions/logic are used. diff --git a/linux.d/debian b/linux.d/debian index 10d866fcb5..121e53a3a7 100644 --- a/linux.d/debian +++ b/linux.d/debian @@ -44,7 +44,7 @@ then fi # check which version of libwebkit2gtk is available - if [ "$(apt show --quiet libwebkit2gtk-4.0-dev)" != "" ] + if [ "$(apt show --quiet libwebkit2gtk-4.0-dev 2>/dev/null)" != "" ] then REQUIRED_DEV_PACKAGES+=(libwebkit2gtk-4.0-dev) else diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a541e7c548..91eaee8465 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,7 +123,7 @@ if (NOT WIN32 AND NOT APPLE) # Binary name on unix like systems (Linux, Unix) set_target_properties(OrcaSlicer PROPERTIES OUTPUT_NAME "orca-slicer") set(SLIC3R_APP_CMD "orca-slicer") - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/unix/BuildLinuxImage.sh.in ${CMAKE_CURRENT_BINARY_DIR}/BuildLinuxImage.sh @ONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/unix/build_linux_image.sh.in ${CMAKE_CURRENT_BINARY_DIR}/build_linux_image.sh USE_SOURCE_PERMISSIONS @ONLY) endif () target_link_libraries(OrcaSlicer libslic3r cereal::cereal) diff --git a/src/platform/unix/BuildLinuxImage.sh.in b/src/platform/unix/build_linux_image.sh.in old mode 100644 new mode 100755 similarity index 93% rename from src/platform/unix/BuildLinuxImage.sh.in rename to src/platform/unix/build_linux_image.sh.in index 77ab1431a7..738f6528eb --- a/src/platform/unix/BuildLinuxImage.sh.in +++ b/src/platform/unix/build_linux_image.sh.in @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash export ROOT=$(echo $ROOT | grep . || pwd) export NCORES=`nproc --all` @@ -8,7 +8,7 @@ while getopts ":ih" opt; do i ) export BUILD_IMAGE="1" ;; - h ) echo "Usage: ./BuildLinuxImage.sh [-i]" + h ) echo "Usage: ./build_linux_image.sh [-i]" echo " -i: Generate Appimage (optional)" exit 0 ;; @@ -67,9 +67,9 @@ EOF chmod ug+x @SLIC3R_APP_CMD@ cp -f @SLIC3R_APP_CMD@ package/@SLIC3R_APP_CMD@ - pushd package + pushd package > /dev/null tar -cvf ../@SLIC3R_APP_KEY@.tar . &>/dev/null - popd + popd > /dev/null #} &> $ROOT/Build.log # Capture all command output echo "done" @@ -77,10 +77,10 @@ if [[ -n "$BUILD_IMAGE" ]] then echo -n "Creating Appimage for distribution..." #{ - pushd package + pushd package > /dev/null chmod +x ../build_appimage.sh ../build_appimage.sh - popd + popd > /dev/null mv package/"@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage" "@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage" #} &> $ROOT/Build.log # Capture all command output echo "done" From b72e28c1163113cf4ba9696678d815b469cdbb69 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Sat, 14 Jun 2025 21:10:51 -0700 Subject: [PATCH 5/7] Various flatpak fixes and improvements (#9527) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Revert 98be94a729ff39cd21442547d10e988422f58310 We carry a wxgtk patch [1] that detects dark theme automatically. If it doesn't work, it means that either selected Gtk theme is not installed in flatpak environment, or appropriate xdg-desktop-portal for the DE is not installed. Plasma users may need to install org.gtk.Gtk3theme.Adapta Also see https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html [1] 0001-Enable-using-a-dark-theme-when-Gnome-dark-style-is-s.patch * flatpak: introduce ORCA_SLICER_DARK_THEME to force dark theme If ORCA_SLICER_DARK_THEME is set, dark theme will be applied regardless of system settings. * FIX: occt build failure Pick up build error fix from upstream: https://github.com/Open-Cascade-SAS/OCCT/commit/7236e83dcc1e7284e66dc61e612154617ef715d6 /run/build/BambuStudio/deps/build/dep_OCCT-prefix/src/dep_OCCT/src/StdPrs/StdPrs_BRepFont.cxx: In member function ‘Standard_Boolean StdPrs_BRepFont::renderGlyph(Standard_Utf32Char, TopoDS_Shape&)’: /run/build/BambuStudio/deps/build/dep_OCCT-prefix/src/dep_OCCT/src/StdPrs/StdPrs_BRepFont.cxx:465:30: error: invalid conversion from ‘unsigned char*’ to ‘const char*’ [-fpermissive] 465 | const char* aTags = &anOutline->tags[aStartIndex]; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | unsigned char* * Set policy CMP0167 to NEW Newer cmake switched to using BoostConfig.cmake shipped with boost-1.70 or later for detecting boost, to preserve old behavior policy CMP0167 was introduced. Set it to "NEW" to indicate that we want to use .cmake shipped with boost * Add OpenSSL tarball link to the manifest * Add curl zip to the manifest * flatpak: bump runtime version to 47 Gnome 47 has been released a while ago --------- Co-authored-by: Bastien Nocera --- .github/workflows/build_all.yml | 2 +- CMakeLists.txt | 3 + deps/OCCT/0001-OCCT-fix.patch | 24 ++++++ flatpak/entrypoint | 9 +- flatpak/io.github.softfever.OrcaSlicer.yml | 52 +++--------- ...ark-theme-when-Gnome-dark-style-is-s.patch | 22 +++-- flatpak/set-dark-theme-variant.py | 85 ------------------- flatpak/uses-dark-theme.py | 18 ---- 8 files changed, 57 insertions(+), 158 deletions(-) delete mode 100644 flatpak/set-dark-theme-variant.py delete mode 100644 flatpak/uses-dark-theme.py diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index 51caa6e3e9..9b44b5639c 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -64,7 +64,7 @@ jobs: flatpak: name: "Flatpak" container: - image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-46 + image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-47 options: --privileged volumes: - /usr/local/lib/android:/usr/local/lib/android diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b0263226d..5524e3a1e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -484,6 +484,9 @@ endif() # set(Boost_COMPILER "-mgw81") # boost::process was introduced first in version 1.64.0, # boost::beast::detail::base64 was introduced first in version 1.66.0 +if(POLICY CMP0167) + cmake_policy(SET CMP0167 NEW) +endif() find_package(Boost 1.83.0 REQUIRED COMPONENTS system filesystem thread log log_setup locale regex chrono atomic date_time iostreams program_options nowide) add_library(boost_libs INTERFACE) diff --git a/deps/OCCT/0001-OCCT-fix.patch b/deps/OCCT/0001-OCCT-fix.patch index d0de170d5a..27f5db7e0f 100644 --- a/deps/OCCT/0001-OCCT-fix.patch +++ b/deps/OCCT/0001-OCCT-fix.patch @@ -195,3 +195,27 @@ index 5ae9899f..0a17372b 100644 if (!myFTLib->IsValid()) { +From 7236e83dcc1e7284e66dc61e612154617ef715d6 Mon Sep 17 00:00:00 2001 +From: dpasukhi +Date: Tue, 27 Aug 2024 11:33:29 +0100 +Subject: [PATCH] 0033808: Coding - FreeType Use unsigned point and contour + indexing in `FT_Outline` + +Changes to auto instead of specific type +--- + src/StdPrs/StdPrs_BRepFont.cxx | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/StdPrs/StdPrs_BRepFont.cxx b/src/StdPrs/StdPrs_BRepFont.cxx +index ab2d9b3c9f..cd701879b1 100644 +--- a/src/StdPrs/StdPrs_BRepFont.cxx ++++ b/src/StdPrs/StdPrs_BRepFont.cxx +@@ -457,7 +457,7 @@ Standard_Boolean StdPrs_BRepFont::renderGlyph (const Standard_Utf32Char theChar, + for (short aContour = 0, aStartIndex = 0; aContour < anOutline->n_contours; ++aContour) + { + const FT_Vector* aPntList = &anOutline->points[aStartIndex]; +- const char* aTags = &anOutline->tags[aStartIndex]; ++ const auto* aTags = &anOutline->tags[aStartIndex]; + const short anEndIndex = anOutline->contours[aContour]; + const short aPntsNb = (anEndIndex - aStartIndex) + 1; + aStartIndex = anEndIndex + 1; diff --git a/flatpak/entrypoint b/flatpak/entrypoint index 0c8e163fdc..38fd86f451 100644 --- a/flatpak/entrypoint +++ b/flatpak/entrypoint @@ -6,11 +6,4 @@ grep -q org.freedesktop.Platform.GL.nvidia /.flatpak-info && export WEBKIT_DISAB # Work-around https://github.com/bambulab/BambuStudio/issues/3440 export LC_ALL=C.UTF-8 -if XDG_CONFIG_HOME=$HOME/.config /app/bin/uses-dark-theme.py; then - export GTK_THEME='Adwaita:dark' - export ORCA_SLICER_DARK_THEME='true' - echo "Message: $(date +%T): INFO: using dark theme variant" -fi - -exec /app/bin/orca-slicer "$@" & -$(/app/bin/set-dark-theme-variant.py) & +exec /app/bin/orca-slicer "$@" diff --git a/flatpak/io.github.softfever.OrcaSlicer.yml b/flatpak/io.github.softfever.OrcaSlicer.yml index f40e2cba4f..2f588045d3 100755 --- a/flatpak/io.github.softfever.OrcaSlicer.yml +++ b/flatpak/io.github.softfever.OrcaSlicer.yml @@ -1,6 +1,6 @@ app-id: io.github.softfever.OrcaSlicer runtime: org.gnome.Platform -runtime-version: "46" +runtime-version: "47" sdk: org.gnome.Sdk command: entrypoint separate-locales: true @@ -19,34 +19,8 @@ finish-args: - --talk-name=io.github.softfever.OrcaSlicer.InstanceCheck.* - --system-talk-name=org.freedesktop.UDisks2 - --env=SPNAV_SOCKET=/run/spnav.sock - # set dark theme - - --env=ORCA_SLICER_DARK_THEME=false modules: - # xprop, xlib is needed to manipulate the X11 window and set _GTK_THEME_VARIANT dark on X11 - # and paint the window dark when ORCA_SLICER_DARK_THEME is true - # see: entrypoint & set-dark-theme-variant.py (originated from Pursa Slicer flatpak which originated from spotify client flatpak) - - name: xprop - sources: - - type: archive - url: https://xorg.freedesktop.org/archive/individual/app/xprop-1.2.5.tar.gz - sha256: b7bf6b6be6cf23e7966a153fc84d5901c14f01ee952fbd9d930aa48e2385d670 - - name: python-setuptools_scm - buildsystem: simple - build-commands: - - pip3 install --no-deps --no-build-isolation --verbose --prefix=${FLATPAK_DEST} . - sources: - - type: archive - url: https://files.pythonhosted.org/packages/57/38/930b1241372a9f266a7df2b184fb9d4f497c2cef2e016b014f82f541fe7c/setuptools_scm-6.0.1.tar.gz - sha256: d1925a69cb07e9b29416a275b9fadb009a23c148ace905b2fb220649a6c18e92 - - name: python-xlib - buildsystem: simple - build-commands: - - pip3 install --no-deps --no-build-isolation --verbose --prefix=${FLATPAK_DEST} . - sources: - - type: archive - url: https://files.pythonhosted.org/packages/86/f5/8c0653e5bb54e0cbdfe27bf32d41f27bc4e12faa8742778c17f2a71be2c0/python-xlib-0.33.tar.gz - sha256: 55af7906a2c75ce6cb280a584776080602444f75815a7aff4d287bb2d7018b32 # JPEG codec for the liveview - name: gst-plugins-good @@ -112,7 +86,7 @@ modules: - type: archive url: https://github.com/FreeSpacenav/libspnav/releases/download/v1.2/libspnav-1.2.tar.gz sha256: 093747e7e03b232e08ff77f1ad7f48552c06ac5236316a5012db4269951c39db - + - name: orca_wxwidgets buildsystem: simple build-commands: @@ -221,6 +195,12 @@ modules: dest: external-packages/GMP sha256: eae9326beb4158c386e39a356818031bd28f3124cf915f8c5b1dc4c7a36b4d7c + # curl + - type: file + url: https://github.com/curl/curl/archive/refs/tags/curl-7_75_0.zip + dest: external-packages/CURL + sha256: a63ae025bb0a14f119e73250f2c923f4bf89aa93b8d4fafa4a9f5353a96a765a + # MPFR - type: file url: https://www.mpfr.org/mpfr-4.2.2/mpfr-4.2.2.tar.bz2 @@ -257,6 +237,12 @@ modules: dest: external-packages/OpenEXR sha256: 0307a3d7e1fa1e77e9d84d7e9a8694583fbbbfd50bdc6884e2c96b8ef6b902de + # OpenSSL + - type: file + url: https://github.com/openssl/openssl/archive/OpenSSL_1_1_1w.tar.gz + dest: external-packages/OpenSSL + sha256: 2130e8c2fb3b79d1086186f78e59e8bc8d1a6aedf17ab3907f4cb9ae20918c41 + # OpenVDB - type: file url: https://github.com/tamasmeszaros/openvdb/archive/a68fd58d0e2b85f01adeb8b13d7555183ab10aa5.zip @@ -325,8 +311,6 @@ modules: desktop-file-edit --set-key=Exec --set-value="entrypoint %U" /app/share/applications/${FLATPAK_ID}.desktop install -Dm755 entrypoint /app/bin install -Dm755 umount /app/bin - install set-dark-theme-variant.py /app/bin - install uses-dark-theme.py /app/bin sources: # - @@ -344,14 +328,6 @@ modules: - type: file path: io.github.softfever.OrcaSlicer.metainfo.xml - # script to set dark theme variant - - type: file - path: set-dark-theme-variant.py - - # script to detect if host uses dark theme - - type: file - path: uses-dark-theme.py - # start-up script - type: file path: entrypoint diff --git a/flatpak/patches/0001-Enable-using-a-dark-theme-when-Gnome-dark-style-is-s.patch b/flatpak/patches/0001-Enable-using-a-dark-theme-when-Gnome-dark-style-is-s.patch index 7f8bd07d44..877b69b459 100644 --- a/flatpak/patches/0001-Enable-using-a-dark-theme-when-Gnome-dark-style-is-s.patch +++ b/flatpak/patches/0001-Enable-using-a-dark-theme-when-Gnome-dark-style-is-s.patch @@ -1,4 +1,4 @@ -From 221be0af1a0b5bcf05c59b3403f969643b42dbaf Mon Sep 17 00:00:00 2001 +From f0135d9c3faf0207f7100991ccf512f228b90570 Mon Sep 17 00:00:00 2001 From: Paul Cornett Date: Sat, 30 Sep 2023 16:42:58 -0700 Subject: [PATCH] Enable using a dark theme when Gnome "dark style" is set @@ -8,11 +8,11 @@ automatically, so request it explicitly. Co-authored-by: Colin Kinloch --- - src/gtk/settings.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 111 insertions(+), 1 deletion(-) + src/gtk/settings.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/src/gtk/settings.cpp b/src/gtk/settings.cpp -index 304724773711..74898d9bb953 100644 +index 3047247737..f13ea2ef24 100644 --- a/src/gtk/settings.cpp +++ b/src/gtk/settings.cpp @@ -183,6 +183,64 @@ static void notify_gtk_font_name(GObject*, GParamSpec*, void*) @@ -80,7 +80,7 @@ index 304724773711..74898d9bb953 100644 // Some notes on using GtkStyleContext. Style information from a context // attached to a non-visible GtkWidget is not accurate. The context has an // internal visibility state, controlled by the widget, which it presumably -@@ -1124,12 +1182,62 @@ bool wxSystemSettingsNative::HasFeature(wxSystemFeature index) +@@ -1124,12 +1182,68 @@ bool wxSystemSettingsNative::HasFeature(wxSystemFeature index) class wxSystemSettingsModule: public wxModule { public: @@ -109,8 +109,14 @@ index 304724773711..74898d9bb953 100644 + + m_proxy = nullptr; + ++ if (getenv("ORCA_SLICER_DARK_THEME") != nullptr) { ++ /* 1 for prefer dark */ ++ GVariant *value = g_variant_new_uint32(1); ++ UpdatePreferDark(value); ++ g_variant_unref(value); ++ } + // GTK_THEME environment variable overrides other settings -+ if (getenv("GTK_THEME") == nullptr) ++ else if (getenv("GTK_THEME") == nullptr) + { + m_proxy = g_dbus_proxy_new_for_bus_sync( + G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, nullptr, @@ -144,7 +150,7 @@ index 304724773711..74898d9bb953 100644 void wxSystemSettingsModule::OnExit() { #ifdef __WXGTK3__ -@@ -1141,6 +1249,8 @@ void wxSystemSettingsModule::OnExit() +@@ -1141,6 +1255,8 @@ void wxSystemSettingsModule::OnExit() g_signal_handlers_disconnect_by_func(settings, (void*)notify_gtk_font_name, NULL); } @@ -154,5 +160,5 @@ index 304724773711..74898d9bb953 100644 if (gs_tlw_parent) { -- -2.46.2 +2.49.0 diff --git a/flatpak/set-dark-theme-variant.py b/flatpak/set-dark-theme-variant.py deleted file mode 100644 index 2f05be0fe5..0000000000 --- a/flatpak/set-dark-theme-variant.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python3 - -import Xlib -import Xlib.display -import time -import subprocess -import os -import sys - - -disp = Xlib.display.Display() -root = disp.screen().root - -NET_CLIENT_LIST = disp.intern_atom('_NET_CLIENT_LIST') - - -def set_theme_variant_by_window_id(id, variant): - # Use subprocess to call - # xprop and set the variant from id. - try: - s = subprocess.call(['xprop', '-f', '_GTK_THEME_VARIANT', '8u', '-set', '_GTK_THEME_VARIANT', variant, '-id', str(id)], - stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - if s == 0: - return True - return False - except Exception as ex: - return False - - -def set_theme_variant_from_win_id_collection(win_id_collection, variant): - # Loop though all of the collected - # window ids and set theme variant - for win_id in win_id_collection: - set_theme_variant_by_window_id(win_id, variant) - - -def collection_win_id_from_wm_class_name(win_class_name): - - collect = [] - - # Loop though all of the windows - # and collect id's those that match - # win_class: prusa-slicer - for win_id in root.get_full_property(NET_CLIENT_LIST, Xlib.X.AnyPropertyType).value: - try: - win = disp.create_resource_object('window', win_id) - if not win.get_wm_transient_for(): - win_class = win.get_wm_class() - if win_id and win_class_name in win_class: - collect.append( - win_id) if win_id not in collect else collect - except Xlib.error.BadWindow: - pass - - return collect - - -if __name__ == '__main__': - - if os.environ.get('ORCA_SLICER_DARK_THEME', 'false') != 'true': - sys.exit(0) - - # Listen for X Property Change events. - root.change_attributes(event_mask=Xlib.X.PropertyChangeMask) - # the class name of the slicer window - win_class_name = 'orcaslicer' - # the variant to set - variant = 'dark' - - start = time.time() - - while True: - # collect all of the window ids - collect = collection_win_id_from_wm_class_name(win_class_name) - # give Orca Slicer window 2 secs to - # collect the wanted window ids - # set the theme variant and exit - if time.time() - start <= 2: - # disp.next_event() blocks if no events are - # queued. In combination with while True - # it creates a very simple event loop. - disp.next_event() - set_theme_variant_from_win_id_collection(collect, variant) - else: - break diff --git a/flatpak/uses-dark-theme.py b/flatpak/uses-dark-theme.py deleted file mode 100644 index 4d7ebbc87a..0000000000 --- a/flatpak/uses-dark-theme.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -import gi -gi.require_version("Gtk", "3.0") -from gi.repository import Gtk as gtk - - -if __name__ == '__main__': - forced = os.environ.get('ORCA_SLICER_DARK_THEME', 'false') == 'true' - settings = gtk.Settings.get_default() - prefer_dark = settings.get_property('gtk-application-prefer-dark-theme') - - if not forced and not prefer_dark: - sys.exit(1) - else: - sys.exit(0) From ecfe53e488e8455f2238f54446880deb269491bc Mon Sep 17 00:00:00 2001 From: anjis Date: Sun, 15 Jun 2025 14:53:35 +0800 Subject: [PATCH 6/7] The multi-color printing wipe tower now includes the Bambu RIB wall feature (#9881) * Add new Bambu RIB wall feature, including only the rib wall generation algorithm. * Fix Linux compilation errors. * Attempt to fix flatpak build --------- Co-authored-by: Noisyfox --- src/libslic3r/GCode.cpp | 13 +- src/libslic3r/GCode/WipeTower2.cpp | 1036 ++++++++++++++++++++++--- src/libslic3r/GCode/WipeTower2.hpp | 32 +- src/libslic3r/Preset.cpp | 4 +- src/libslic3r/Print.cpp | 4 + src/libslic3r/PrintConfig.cpp | 49 +- src/libslic3r/PrintConfig.hpp | 12 + src/slic3r/GUI/ConfigManipulation.cpp | 9 + src/slic3r/GUI/Plater.cpp | 4 +- src/slic3r/GUI/Tab.cpp | 6 +- 10 files changed, 1034 insertions(+), 135 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 08b3ebac52..d56a971ad0 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -845,9 +845,10 @@ static std::vector get_path_of_change_filament(const Print& print) // All G1 commands should be translated and rotated. X and Y coords are // only pushed to the output when they differ from last time. // WT generator can override this by appending the never_skip_tag - if (line.find("G1 ") == 0) { - bool never_skip = false; - auto it = line.find(WipeTower::never_skip_tag()); + if (line.find("G1 ") == 0 || line.find("G2 ") == 0 || line.find("G3 ") == 0) { + std::string cur_gcode_start = line.find("G1 ") == 0 ? "G1 " : (line.find("G2 ") == 0 ? "G2 " : "G3 "); + bool never_skip = false; + auto it = line.find(WipeTower::never_skip_tag()); if (it != std::string::npos) { // remove the tag and remember we saw it never_skip = true; @@ -855,7 +856,7 @@ static std::vector get_path_of_change_filament(const Print& print) } std::ostringstream line_out; std::istringstream line_str(line); - line_str >> std::noskipws; // don't skip whitespace + line_str >> std::noskipws; // don't skip whitespace char ch = 0; while (line_str >> ch) { if (ch == 'X' || ch == 'Y') @@ -869,13 +870,13 @@ static std::vector get_path_of_change_filament(const Print& print) if (transformed_pos != old_pos || never_skip) { line = line_out.str(); std::ostringstream oss; - oss << std::fixed << std::setprecision(3) << "G1 "; + oss << std::fixed << std::setprecision(3) << cur_gcode_start; if (transformed_pos.x() != old_pos.x() || never_skip) oss << " X" << transformed_pos.x() - extruder_offset.x(); if (transformed_pos.y() != old_pos.y() || never_skip) oss << " Y" << transformed_pos.y() - extruder_offset.y(); oss << " "; - line.replace(line.find("G1 "), 3, oss.str()); + line.replace(line.find(cur_gcode_start), 3, oss.str()); old_pos = transformed_pos; } } diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp index d9a4a9c0f0..9decfc4c96 100644 --- a/src/libslic3r/GCode/WipeTower2.cpp +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -24,6 +24,526 @@ namespace Slic3r { + float flat_iron_area = 4.f; +constexpr float flat_iron_speed = 10.f * 60.f; +static const double wipe_tower_wall_infill_overlap = 0.0; +static constexpr double WIPE_TOWER_RESOLUTION = 0.1; +static constexpr double WT_SIMPLIFY_TOLERANCE_SCALED = 0.001f / SCALING_FACTOR_INTERNAL; +static constexpr int arc_fit_size = 20; +#define SCALED_WIPE_TOWER_RESOLUTION (WIPE_TOWER_RESOLUTION / SCALING_FACTOR_INTERNAL) +enum class LimitFlow { None, LimitPrintFlow, LimitRammingFlow }; +static const std::map nozzle_diameter_to_nozzle_change_width{{0.2f, 0.5f}, {0.4f, 1.0f}, {0.6f, 1.2f}, {0.8f, 1.4f}}; + +inline float align_round(float value, float base) { return std::round(value / base) * base; } + +inline float align_ceil(float value, float base) { return std::ceil(value / base) * base; } + +inline float align_floor(float value, float base) { return std::floor((value) / base) * base; } + +static bool is_valid_gcode(const std::string& gcode) +{ + int str_size = gcode.size(); + int start_index = 0; + int end_index = 0; + bool is_valid = false; + while (end_index < str_size) { + if (gcode[end_index] != '\n') { + end_index++; + continue; + } + + if (end_index > start_index) { + std::string line_str = gcode.substr(start_index, end_index - start_index); + line_str.erase(0, line_str.find_first_not_of(" ")); + line_str.erase(line_str.find_last_not_of(" ") + 1); + if (!line_str.empty() && line_str[0] != ';') { + is_valid = true; + break; + } + } + + start_index = end_index + 1; + end_index = start_index; + } + + return is_valid; +} + +Polygon chamfer_polygon(Polygon& polygon, double chamfer_dis = 2., double angle_tol = 30. / 180. * PI) +{ + if (polygon.points.size() < 3) + return polygon; + Polygon res; + res.points.reserve(polygon.points.size() * 2); + int mod = polygon.points.size(); + double cos_angle_tol = abs(std::cos(angle_tol)); + + for (int i = 0; i < polygon.points.size(); i++) { + Vec2d a = unscaled(polygon.points[(i - 1 + mod) % mod]); + Vec2d b = unscaled(polygon.points[i]); + Vec2d c = unscaled(polygon.points[(i + 1) % mod]); + double ab_len = (a - b).norm(); + double bc_len = (b - c).norm(); + Vec2d ab = (b - a) / ab_len; + Vec2d bc = (c - b) / bc_len; + assert(ab_len != 0); + assert(bc_len != 0); + float cosangle = ab.dot(bc); + // std::cout << " angle " << acos(cosangle) << " cosangle " << cosangle << std::endl; + // std::cout << " ab_len " << ab_len << " bc_len " << bc_len << std::endl; + if (abs(cosangle) < cos_angle_tol) { + float real_chamfer_dis = std::min({chamfer_dis, ab_len / 2.1, bc_len / 2.1}); // 2.1 to ensure the points do not coincide + Vec2d left = b - ab * real_chamfer_dis; + Vec2d right = b + bc * real_chamfer_dis; + res.points.push_back(scaled(left)); + res.points.push_back(scaled(right)); + } else + res.points.push_back(polygon.points[i]); + } + res.points.shrink_to_fit(); + return res; +} + +Polygon rounding_polygon(Polygon& polygon, double rounding = 2., double angle_tol = 30. / 180. * PI) +{ + if (polygon.points.size() < 3) + return polygon; + Polygon res; + res.points.reserve(polygon.points.size() * 2); + int mod = polygon.points.size(); + double cos_angle_tol = abs(std::cos(angle_tol)); + + for (int i = 0; i < polygon.points.size(); i++) { + Vec2d a = unscaled(polygon.points[(i - 1 + mod) % mod]); + Vec2d b = unscaled(polygon.points[i]); + Vec2d c = unscaled(polygon.points[(i + 1) % mod]); + double ab_len = (a - b).norm(); + double bc_len = (b - c).norm(); + Vec2d ab = (b - a) / ab_len; + Vec2d bc = (c - b) / bc_len; + assert(ab_len != 0); + assert(bc_len != 0); + float cosangle = ab.dot(bc); + cosangle = std::clamp(cosangle, -1.f, 1.f); + bool is_ccw = cross2(ab, bc) > 0; + if (abs(cosangle) < cos_angle_tol) { + float real_rounding_dis = std::min({rounding, ab_len / 2.1, bc_len / 2.1}); // 2.1 to ensure the points do not coincide + Vec2d left = b - ab * real_rounding_dis; + Vec2d right = b + bc * real_rounding_dis; + // Point r_left = scaled(left); + // Point r_right = scaled(right); + // std::cout << " r_left " << r_left[0] << " " << r_left[1] << std::endl; + // std::cout << " r_right " << r_right[0] << " " << r_right[1] << std::endl; + { + float half_angle = std::acos(cosangle) / 2.f; + // std::cout << " half_angle " << cos(half_angle) << std::endl; + + Vec2d dir = (right - left).normalized(); + dir = Vec2d{-dir[1], dir[0]}; + dir = is_ccw ? dir : -dir; + double dis = real_rounding_dis / sin(half_angle); + // std::cout << " dis " << dis << std::endl; + + Vec2d center = b + dir * dis; + double radius = (left - center).norm(); + ArcSegment arc(scaled(center), scaled(radius), scaled(left), scaled(right), + is_ccw ? ArcDirection::Arc_Dir_CCW : ArcDirection::Arc_Dir_CW); + int n = arc_fit_size; + // std::cout << "start " << arc.start_point[0] << " " << arc.start_point[1] << std::endl; + // std::cout << "end " << arc.end_point[0] << " " << arc.end_point[1] << std::endl; + // std::cout << "start angle " << arc.polar_start_theta << " end angle " << arc.polar_end_theta << std::endl; + for (int j = 0; j < n; j++) { + float cur_angle = arc.polar_start_theta + (float) j / n * arc.angle_radians; + // std::cout << " cur_angle " << cur_angle << std::endl; + if (cur_angle > 2 * PI) + cur_angle -= 2 * PI; + else if (cur_angle < 0) + cur_angle += 2 * PI; + Point tmp = arc.center + Point{arc.radius * std::cos(cur_angle), arc.radius * std::sin(cur_angle)}; + // std::cout << "j = " << j << std::endl; + // std::cout << "tmp = " << tmp[0]<<" "< 0; + if (abs(cosangle) < cos_angle_tol) { + float real_rounding_dis = std::min({rounding, ab_len / 2.1, bc_len / 2.1}); // 2.1 to ensure the points do not coincide + Vec2d left = b - ab * real_rounding_dis; + Vec2d right = b + bc * real_rounding_dis; + // Point r_left = scaled(left); + // Point r_right = scaled(right); + // std::cout << " r_left " << r_left[0] << " " << r_left[1] << std::endl; + // std::cout << " r_right " << r_right[0] << " " << r_right[1] << std::endl; + { + Vec2d center = b; + double radius = real_rounding_dis; + ArcSegment arc(scaled(center), scaled(radius), scaled(left), scaled(right), + is_ccw ? ArcDirection::Arc_Dir_CCW : ArcDirection::Arc_Dir_CW); + int n = arc_fit_size; + // std::cout << "start " << arc.start_point[0] << " " << arc.start_point[1] << std::endl; + // std::cout << "end " << arc.end_point[0] << " " << arc.end_point[1] << std::endl; + // std::cout << "start angle " << arc.polar_start_theta << " end angle " << arc.polar_end_theta << std::endl; + for (int j = 0; j < n; j++) { + float cur_angle = arc.polar_start_theta + (float) j / n * arc.angle_radians; + // std::cout << " cur_angle " << cur_angle << std::endl; + if (cur_angle > 2 * PI) + cur_angle -= 2 * PI; + else if (cur_angle < 0) + cur_angle += 2 * PI; + Point tmp = arc.center + Point{arc.radius * std::cos(cur_angle), arc.radius * std::sin(cur_angle)}; + // std::cout << "j = " << j << std::endl; + // std::cout << "tmp = " << tmp[0]<<" "< ray_intersetion_line(const Vec2f& a, const Vec2f& v1, const Vec2f& b, const Vec2f& c) +{ + const Vec2f v2 = c - b; + double denom = cross2(v1, v2); + if (fabs(denom) < EPSILON) + return {false, Vec2f(0, 0)}; + const Vec2f v12 = (a - b); + double nume_a = cross2(v2, v12); + double nume_b = cross2(v1, v12); + double t1 = nume_a / denom; + double t2 = nume_b / denom; + if (t1 >= 0 && t2 >= 0 && t2 <= 1.) { + // Get the intersection point. + Vec2f res = a + t1 * v1; + return std::pair(true, res); + } + return std::pair(false, Vec2f{0, 0}); +} +Polygon scale_polygon(const std::vector& points) +{ + Polygon res; + for (const auto& p : points) + res.points.push_back(scaled(p)); + return res; +} +std::vector unscale_polygon(const Polygon& polygon) +{ + std::vector res; + for (const auto& p : polygon.points) + res.push_back(unscaled(p)); + return res; +} + +Polygon generate_rectange(const Line& line, coord_t offset) +{ + Point p1 = line.a; + Point p2 = line.b; + + double dx = p2.x() - p1.x(); + double dy = p2.y() - p1.y(); + + double length = std::sqrt(dx * dx + dy * dy); + + double ux = dx / length; + double uy = dy / length; + + double vx = -uy; + double vy = ux; + + double ox = vx * offset; + double oy = vy * offset; + + Points rect; + rect.resize(4); + rect[0] = {p1.x() + ox, p1.y() + oy}; + rect[1] = {p1.x() - ox, p1.y() - oy}; + rect[2] = {p2.x() - ox, p2.y() - oy}; + rect[3] = {p2.x() + ox, p2.y() + oy}; + Polygon poly(rect); + return poly; +}; + +struct Segment +{ + Vec2f start; + Vec2f end; + bool is_arc = false; + ArcSegment arcsegment; + Segment(const Vec2f& s, const Vec2f& e) : start(s), end(e) {} + bool is_valid() const { return start.y() < end.y(); } +}; + +std::vector remove_points_from_segment(const Segment& segment, const std::vector& skip_points, double range) +{ + std::vector result; + result.push_back(segment); + float x = segment.start.x(); + + for (const Vec2f& point : skip_points) { + std::vector newResult; + for (const auto& seg : result) { + if (point.y() + range <= seg.start.y() || point.y() - range >= seg.end.y()) { + newResult.push_back(seg); + } else { + if (point.y() - range > seg.start.y()) { + newResult.push_back(Segment(Vec2f(x, seg.start.y()), Vec2f(x, point.y() - range))); + } + if (point.y() + range < seg.end.y()) { + newResult.push_back(Segment(Vec2f(x, point.y() + range), Vec2f(x, seg.end.y()))); + } + } + } + + result = newResult; + } + + result.erase(std::remove_if(result.begin(), result.end(), [](const Segment& seg) { return !seg.is_valid(); }), result.end()); + return result; +} + +struct IntersectionInfo +{ + Vec2f pos; + int idx; + int pair_idx; // gap_pair idx + float dis_from_idx; + bool is_forward; +}; + +struct PointWithFlag +{ + Vec2f pos; + int pair_idx; // gap_pair idx + bool is_forward; +}; +IntersectionInfo move_point_along_polygon( + const std::vector& points, const Vec2f& startPoint, int startIdx, float offset, bool forward, int pair_idx) +{ + float remainingDistance = offset; + IntersectionInfo res; + int mod = points.size(); + if (forward) { + int next = (startIdx + 1) % mod; + remainingDistance -= (points[next] - startPoint).norm(); + if (remainingDistance <= 0) { + res.idx = startIdx; + res.pos = startPoint + (points[next] - startPoint).normalized() * offset; + res.pair_idx = pair_idx; + res.dis_from_idx = (points[startIdx] - res.pos).norm(); + return res; + } else { + for (int i = (startIdx + 1) % mod; i != startIdx; i = (i + 1) % mod) { + float segmentLength = (points[(i + 1) % mod] - points[i]).norm(); + if (remainingDistance <= segmentLength) { + float ratio = remainingDistance / segmentLength; + res.idx = i; + res.pos = points[i] + ratio * (points[(i + 1) % mod] - points[i]); + res.dis_from_idx = remainingDistance; + res.pair_idx = pair_idx; + return res; + } + remainingDistance -= segmentLength; + } + res.idx = (startIdx - 1 + mod) % mod; + res.pos = points[startIdx]; + res.pair_idx = pair_idx; + res.dis_from_idx = (res.pos - points[res.idx]).norm(); + } + } else { + int next = (startIdx + 1) % mod; + remainingDistance -= (points[startIdx] - startPoint).norm(); + if (remainingDistance <= 0) { + res.idx = startIdx; + res.pos = startPoint - (points[next] - points[startIdx]).normalized() * offset; + res.dis_from_idx = (res.pos - points[startIdx]).norm(); + res.pair_idx = pair_idx; + return res; + } + for (int i = (startIdx - 1 + mod) % mod; i != startIdx; i = (i - 1 + mod) % mod) { + float segmentLength = (points[(i + 1) % mod] - points[i]).norm(); + if (remainingDistance <= segmentLength) { + float ratio = remainingDistance / segmentLength; + res.idx = i; + res.pos = points[(i + 1) % mod] - ratio * (points[(i + 1) % mod] - points[i]); + res.dis_from_idx = segmentLength - remainingDistance; + res.pair_idx = pair_idx; + return res; + } + remainingDistance -= segmentLength; + } + res.idx = startIdx; + res.pos = points[res.idx]; + res.pair_idx = pair_idx; + res.dis_from_idx = 0; + } + return res; +}; + +void insert_points(std::vector& pl, int idx, Vec2f pos, int pair_idx, bool is_forward) +{ + int next = (idx + 1) % pl.size(); + Vec2f pos1 = pl[idx].pos; + Vec2f pos2 = pl[next].pos; + if ((pos - pos1).squaredNorm() < EPSILON) { + pl[idx].pair_idx = pair_idx; + pl[idx].is_forward = is_forward; + } else if ((pos - pos2).squaredNorm() < EPSILON) { + pl[next].pair_idx = pair_idx; + pl[next].is_forward = is_forward; + } else { + pl.insert(pl.begin() + idx + 1, PointWithFlag{pos, pair_idx, is_forward}); + } +} + +Polylines remove_points_from_polygon( + const Polygon& polygon, const std::vector& skip_points, double range, bool is_left, Polygon& insert_skip_pg) +{ + assert(polygon.size() > 2); + Polylines result; + std::vector new_pl; // add intersection points for gaps, where bool indicates whether it's a gap point. + std::vector inter_info; + Vec2f ray = is_left ? Vec2f(-1, 0) : Vec2f(1, 0); + auto polygon_box = get_extents(polygon); + Point anchor_point = is_left ? Point{polygon_box.max[0], polygon_box.min[1]} : polygon_box.min; // rd:ld + std::vector points; + { + points.reserve(polygon.points.size()); + int idx = polygon.closest_point_index(anchor_point); + Polyline tmp_poly = polygon.split_at_index(idx); + for (auto& p : tmp_poly) + points.push_back(unscale(p).cast()); + points.pop_back(); + } + + for (int i = 0; i < skip_points.size(); i++) { + for (int j = 0; j < points.size(); j++) { + Vec2f& p1 = points[j]; + Vec2f& p2 = points[(j + 1) % points.size()]; + auto [is_inter, inter_pos] = ray_intersetion_line(skip_points[i], ray, p1, p2); + if (is_inter) { + IntersectionInfo forward = move_point_along_polygon(points, inter_pos, j, range, true, i); + IntersectionInfo backward = move_point_along_polygon(points, inter_pos, j, range, false, i); + backward.is_forward = false; + forward.is_forward = true; + inter_info.push_back(backward); + inter_info.push_back(forward); + break; + } + } + } + + // insert point to new_pl + for (const auto& p : points) + new_pl.push_back({p, -1}); + std::sort(inter_info.begin(), inter_info.end(), [](const IntersectionInfo& lhs, const IntersectionInfo& rhs) { + if (rhs.idx == lhs.idx) + return lhs.dis_from_idx < rhs.dis_from_idx; + return lhs.idx < rhs.idx; + }); + for (int i = inter_info.size() - 1; i >= 0; i--) { + insert_points(new_pl, inter_info[i].idx, inter_info[i].pos, inter_info[i].pair_idx, inter_info[i].is_forward); + } + + { + // set insert_pg for wipe_path + for (auto& p : new_pl) + insert_skip_pg.points.push_back(scaled(p.pos)); + } + + int beg = 0; + bool skip = true; + int i = beg; + Polyline pl; + + do { + if (skip || new_pl[i].pair_idx == -1) { + pl.points.push_back(scaled(new_pl[i].pos)); + i = (i + 1) % new_pl.size(); + skip = false; + } else { + if (!pl.points.empty()) { + pl.points.push_back(scaled(new_pl[i].pos)); + result.push_back(pl); + pl.points.clear(); + } + int left = new_pl[i].pair_idx; + int j = (i + 1) % new_pl.size(); + while (j != beg && new_pl[j].pair_idx != left) { + if (new_pl[j].pair_idx != -1 && !new_pl[j].is_forward) + left = new_pl[j].pair_idx; + j = (j + 1) % new_pl.size(); + } + i = j; + skip = true; + } + } while (i != beg); + + if (!pl.points.empty()) { + if (new_pl[i].pair_idx == -1) + pl.points.push_back(scaled(new_pl[i].pos)); + result.push_back(pl); + } + return result; +} + +Polylines contrust_gap_for_skip_points( + const Polygon& polygon, const std::vector& skip_points, float wt_width, float gap_length, Polygon& insert_skip_polygon) +{ + if (skip_points.empty()) { + insert_skip_polygon = polygon; + return Polylines{to_polyline(polygon)}; + } + bool is_left = false; + const auto& pt = skip_points.front(); + if (abs(pt.x()) < wt_width / 2.f) { + is_left = true; + } + return remove_points_from_polygon(polygon, skip_points, gap_length, is_left, insert_skip_polygon); +}; + +Polygon generate_rectange_polygon(const Vec2f& wt_box_min, const Vec2f& wt_box_max) +{ + Polygon res; + res.points.push_back(scaled(wt_box_min)); + res.points.push_back(scaled(Vec2f{wt_box_max[0], wt_box_min[1]})); + res.points.push_back(scaled(wt_box_max)); + res.points.push_back(scaled(Vec2f{wt_box_min[0], wt_box_max[1]})); + return res; +} + // Calculates length of extrusion line to extrude given volume static float volume_to_length(float volume, float line_width, float layer_height) { @@ -41,7 +561,12 @@ static float length_to_volume(float length, float line_width, float layer_height class WipeTowerWriter2 { public: - WipeTowerWriter2(float layer_height, float line_width, GCodeFlavor flavor, const std::vector& filament_parameters) : + WipeTowerWriter2(float layer_height, + float line_width, + GCodeFlavor flavor, + const std::vector& filament_parameters, + bool enable_arc_fitting) + : m_current_pos(std::numeric_limits::max(), std::numeric_limits::max()), m_current_z(0.f), m_current_feedrate(0.f), @@ -49,8 +574,8 @@ public: m_extrusion_flow(0.f), m_preview_suppressed(false), m_elapsed_time(0.f), - m_gcode_flavor(flavor), - m_filpar(filament_parameters) + m_gcode_flavor(flavor), m_filpar(filament_parameters) + //m_enable_arc_fitting(enable_arc_fitting) { // ORCA: This class is only used by non BBL printers, so set the parameter appropriately. // This fixes an issue where the wipe tower was using BBL tags resulting in statistics for purging in the purge tower not being displayed. @@ -447,6 +972,162 @@ public: return add_wipe_point(Vec2f(x, y)); } + // Extrude with an explicitely provided amount of extrusion. + WipeTowerWriter2& extrude_arc_explicit(ArcSegment& arc, + float f = 0.f, + bool record_length = false, + LimitFlow limit_flow = LimitFlow::LimitPrintFlow) + { + float x = (float) unscale(arc.end_point).x(); + float y = (float) unscale(arc.end_point).y(); + float len = unscaled(arc.length); + float e = len * m_extrusion_flow; + if (len < (float) EPSILON && e == 0.f && (f == 0.f || f == m_current_feedrate)) + // Neither extrusion nor a travel move. + return *this; + if (record_length) + m_used_filament_length += e; + + // Now do the "internal rotation" with respect to the wipe tower center + Vec2f rotated_current_pos(this->pos_rotated()); + Vec2f rot(this->rotate(Vec2f(x, y))); // this is where we want to go + + if (!m_preview_suppressed && e > 0.f && len > 0.f) { +#if ENABLE_GCODE_VIEWER_DATA_CHECKING + change_analyzer_mm3_per_mm(len, e); +#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + // Width of a squished extrusion, corrected for the roundings of the squished extrusions. + // This is left zero if it is a travel move. + float width = e * m_filpar[0].filament_area / (len * m_layer_height); + // Correct for the roundings of a squished extrusion. + width += m_layer_height * float(1. - M_PI / 4.); + if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos) + m_extrusions.emplace_back(WipeTower::Extrusion(rotated_current_pos, 0, m_current_tool)); + { + int n = arc_fit_size; + for (int j = 0; j < n; j++) { + float cur_angle = arc.polar_start_theta + (float) j / n * arc.angle_radians; + if (cur_angle > 2 * PI) + cur_angle -= 2 * PI; + else if (cur_angle < 0) + cur_angle += 2 * PI; + Point tmp = arc.center + Point{arc.radius * std::cos(cur_angle), arc.radius * std::sin(cur_angle)}; + m_extrusions.emplace_back(WipeTower::Extrusion(this->rotate(unscaled(tmp)), width, m_current_tool)); + } + m_extrusions.emplace_back(WipeTower::Extrusion(rot, width, m_current_tool)); + } + } + + //if (e == 0.f) { + // m_gcode += set_travel_acceleration(); + //} else { + // m_gcode += set_normal_acceleration(); + //} + + m_gcode += arc.direction == ArcDirection::Arc_Dir_CCW ? "G3" : "G2"; + const Vec2f center_offset = this->rotate(unscaled(arc.center)) - rotated_current_pos; + m_gcode += set_format_X(rot.x()); + m_gcode += set_format_Y(rot.y()); + m_gcode += set_format_I(center_offset.x()); + m_gcode += set_format_J(center_offset.y()); + + if (e != 0.f) + m_gcode += set_format_E(e); + + if (f != 0.f && f != m_current_feedrate) { + if (limit_flow != LimitFlow::None) { + float e_speed = e / (((len == 0.f) ? std::abs(e) : len) / f * 60.f); + float tmp = m_filpar[m_current_tool].max_e_speed; + //if (limit_flow == LimitFlow::LimitRammingFlow) + // tmp = m_filpar[m_current_tool].max_e_ramming_speed; + f /= std::max(1.f, e_speed / tmp); + } + m_gcode += set_format_F(f); + } + + m_current_pos.x() = x; + m_current_pos.y() = y; + + // Update the elapsed time with a rough estimate. + m_elapsed_time += ((len == 0.f) ? std::abs(e) : len) / m_current_feedrate * 60.f; + m_gcode += "\n"; + return *this; + } + + WipeTowerWriter2& extrude_arc(ArcSegment& arc, float f = 0.f, LimitFlow limit_flow = LimitFlow::LimitPrintFlow) + { + return extrude_arc_explicit(arc, f, false, limit_flow); + } + + void generate_path(Polylines& pls, float feedrate, float retract_length, float retract_speed, bool used_fillet) + { + auto get_closet_idx = [this](std::vector& corners) -> int { + Vec2f anchor{this->m_current_pos.x(), this->m_current_pos.y()}; + int closestIndex = -1; + float minDistance = std::numeric_limits::max(); + for (int i = 0; i < corners.size(); ++i) { + float distance = (corners[i].start - anchor).squaredNorm(); + if (distance < minDistance) { + minDistance = distance; + closestIndex = i; + } + } + return closestIndex; + }; + std::vector segments; + if (m_enable_arc_fitting) { + for (auto& pl : pls) + pl.simplify_by_fitting_arc(SCALED_WIPE_TOWER_RESOLUTION); + + for (const auto& pl : pls) { + if (pl.points.size() < 2) + continue; + for (int i = 0; i < pl.fitting_result.size(); i++) { + if (pl.fitting_result[i].path_type == EMovePathType::Linear_move) { + for (int j = pl.fitting_result[i].start_point_index; j < pl.fitting_result[i].end_point_index; j++) + segments.push_back({unscaled(pl.points[j]), unscaled(pl.points[j + 1])}); + } else { + int beg = pl.fitting_result[i].start_point_index; + int end = pl.fitting_result[i].end_point_index; + segments.push_back({unscaled(pl.points[beg]), unscaled(pl.points[end])}); + segments.back().is_arc = true; + segments.back().arcsegment = pl.fitting_result[i].arc_data; + } + } + } + for (auto& pl : pls) + pl.simplify(SCALED_WIPE_TOWER_RESOLUTION); + + } else { + for (const auto& pl : pls) { + if (pl.points.size() < 2) + continue; + for (int i = 0; i < pl.size() - 1; i++) { + segments.push_back({unscaled(pl.points[i]), unscaled(pl.points[i + 1])}); + } + } + } + + int index_of_closest = get_closet_idx(segments); + int i = index_of_closest; + travel(segments[i].start); // travel to the closest points + segments[i].is_arc ? extrude_arc(segments[i].arcsegment, feedrate) : extrude(segments[i].end, feedrate); + do { + i = (i + 1) % segments.size(); + if (i == index_of_closest) + break; + float dx = segments[i].start.x() - m_current_pos.x(); + float dy = segments[i].start.y() - m_current_pos.y(); + float len = std::sqrt(dx * dx + dy * dy); + if (len > EPSILON) { + retract(retract_length, retract_speed); + travel(segments[i].start, 600.); + retract(-retract_length, retract_speed); + } + segments[i].is_arc ? extrude_arc(segments[i].arcsegment, feedrate) : extrude(segments[i].end, feedrate); + } while (1); + } + private: Vec2f m_start_pos; Vec2f m_current_pos; @@ -468,6 +1149,7 @@ private: int current_temp = -1; float m_used_filament_length = 0.f; GCodeFlavor m_gcode_flavor; + bool m_enable_arc_fitting = false; const std::vector& m_filpar; std::string set_format_X(float x) @@ -495,6 +1177,8 @@ private: m_current_feedrate = f; return buf; } + std::string set_format_I(float i) { return " I" + Slic3r::float_to_string_decimal_point(i, 3); } + std::string set_format_J(float j) { return " J" + Slic3r::float_to_string_decimal_point(j, 3); } WipeTowerWriter2& operator=(const WipeTowerWriter2 &rhs); @@ -556,8 +1240,12 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau m_infill_speed(default_region_config.sparse_infill_speed), m_perimeter_speed(default_region_config.inner_wall_speed), m_current_tool(initial_tool), - wipe_volumes(wiping_matrix), - m_wipe_tower_max_purge_speed(float(config.wipe_tower_max_purge_speed)) + wipe_volumes(wiping_matrix), m_wipe_tower_max_purge_speed(float(config.wipe_tower_max_purge_speed)), + m_enable_arc_fitting(config.enable_arc_fitting), + m_used_fillet(config.wipe_tower_fillet_wall), + m_rib_width(config.wipe_tower_rib_width), + m_extra_rib_length(config.wipe_tower_extra_rib_length), + m_wall_type((int)config.wipe_tower_wall_type) { // Read absolute value of first layer speed, if given as percentage, // it is taken over following default. Speeds from config are not @@ -676,6 +1364,9 @@ void WipeTower2::set_extruder(size_t idx, const PrintConfig& config) } 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 + + m_filpar[idx].retract_length = config.retraction_length.get_at(idx); + m_filpar[idx].retract_speed = config.retraction_speed.get_at(idx); } @@ -714,7 +1405,7 @@ std::vector WipeTower2::prime( for (size_t idx_tool = 0; idx_tool < tools.size(); ++ idx_tool) { size_t old_tool = m_current_tool; - WipeTowerWriter2 writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter2 writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool); @@ -809,7 +1500,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool) (tool != (unsigned int)(-1) ? wipe_area+m_depth_traversed-0.5f*m_perimeter_width : m_wipe_tower_depth-m_perimeter_width)); - WipeTowerWriter2 writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter2 writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool) @@ -1237,7 +1928,7 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer() size_t old_tool = m_current_tool; - WipeTowerWriter2 writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar); + WipeTowerWriter2 writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar, m_enable_arc_fitting); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) .set_initial_tool(m_current_tool) @@ -1257,8 +1948,6 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer() m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation); bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON; - WipeTower::box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)), - m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); // inner perimeter of the sparse section, if there is space for it: if (fill_box.ru.y() - fill_box.rd.y() > m_perimeter_width - WT_EPSILON) @@ -1275,9 +1964,9 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer() if (dy > m_perimeter_width) { writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f)) - .append(";--------------------\n" - "; CP EMPTY GRID START\n") - .comment_with_value(" layer #", m_num_layer_changes + 1); + .append(";--------------------\n" + "; CP EMPTY GRID START\n") + .comment_with_value(" layer #", m_num_layer_changes + 1); // Is there a soluble filament wiped/rammed at the next layer? // If so, the infill should not be sparse. @@ -1285,10 +1974,10 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer() ? false : std::any_of((m_layer_info+1)->tool_changes.begin(), (m_layer_info+1)->tool_changes.end(), - [this](const WipeTowerInfo::ToolChange& tch) { + [this](const WipeTowerInfo::ToolChange& tch) { return m_filpar[tch.new_tool].is_soluble || m_filpar[tch.old_tool].is_soluble; - }); + }); solid_infill |= first_layer && m_adhesion; if (solid_infill) { @@ -1326,118 +2015,23 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer() } const float spacing = m_perimeter_width - m_layer_height*float(1.-M_PI_4); - - // This block creates the stabilization cone. - // First define a lambda to draw the rectangle with stabilization. - auto supported_rectangle = [this, &writer, spacing](const WipeTower::box_coordinates& wt_box, double feedrate, bool infill_cone) -> Polygon { - const auto [R, support_scale] = get_wipe_tower_cone_base(m_wipe_tower_width, m_wipe_tower_height, m_wipe_tower_depth, m_wipe_tower_cone_angle); - - double z = m_no_sparse_layers ? (m_current_height + m_layer_info->height) : m_layer_info->z; // the former should actually work in both cases, but let's stay on the safe side (the 2.6.0 is close) - - double r = std::tan(Geometry::deg2rad(m_wipe_tower_cone_angle/2.f)) * (m_wipe_tower_height - z); - Vec2f center = (wt_box.lu + wt_box.rd) / 2.; - double w = wt_box.lu.y() - wt_box.ld.y(); - enum Type { - Arc, - Corner, - ArcStart, - ArcEnd - }; - - // First generate vector of annotated point which form the boundary. - std::vector> pts = {{wt_box.ru, Corner}}; - if (double alpha_start = std::asin((0.5*w)/r); ! std::isnan(alpha_start) && r > 0.5*w+0.01) { - for (double alpha = alpha_start; alpha < M_PI-alpha_start+0.001; alpha+=(M_PI-2*alpha_start) / 40.) - pts.emplace_back(Vec2f(center.x() + r*std::cos(alpha)/support_scale, center.y() + r*std::sin(alpha)), alpha == alpha_start ? ArcStart : Arc); - pts.back().second = ArcEnd; - } - pts.emplace_back(wt_box.lu, Corner); - pts.emplace_back(wt_box.ld, Corner); - for (int i=int(pts.size())-3; i>0; --i) - pts.emplace_back(Vec2f(pts[i].first.x(), 2*center.y()-pts[i].first.y()), i == int(pts.size())-3 ? ArcStart : i == 1 ? ArcEnd : Arc); - pts.emplace_back(wt_box.rd, Corner); - - // Create a Polygon from the points. - Polygon poly; - for (const auto& [pt, tag] : pts) - poly.points.push_back(Point::new_scale(pt)); - - // Prepare polygons to be filled by infill. - Polylines polylines; - if (infill_cone && m_wipe_tower_width > 2*spacing && m_wipe_tower_depth > 2*spacing) { - ExPolygons infill_areas; - ExPolygon wt_contour(poly); - Polygon wt_rectangle(Points{Point::new_scale(wt_box.ld), Point::new_scale(wt_box.rd), Point::new_scale(wt_box.ru), Point::new_scale(wt_box.lu)}); - wt_rectangle = offset(wt_rectangle, scale_(-spacing/2.)).front(); - wt_contour = offset_ex(wt_contour, scale_(-spacing/2.)).front(); - infill_areas = diff_ex(wt_contour, wt_rectangle); - if (infill_areas.size() == 2) { - ExPolygon& bottom_expoly = infill_areas.front().contour.points.front().y() < infill_areas.back().contour.points.front().y() ? infill_areas[0] : infill_areas[1]; - std::unique_ptr filler(Fill::new_from_type(ipMonotonicLine)); - filler->angle = Geometry::deg2rad(45.f); - filler->spacing = spacing; - FillParams params; - params.density = 1.f; - Surface surface(stBottom, bottom_expoly); - filler->bounding_box = get_extents(bottom_expoly); - polylines = filler->fill_surface(&surface, params); - if (! polylines.empty()) { - if (polylines.front().points.front().x() > polylines.back().points.back().x()) { - std::reverse(polylines.begin(), polylines.end()); - for (Polyline& p : polylines) - p.reverse(); - } - } - } - } - - // Find the closest corner and travel to it. - int start_i = 0; - double min_dist = std::numeric_limits::max(); - for (int i=0; i() - center)); - for (size_t i=0; i() - center)); - } - writer.travel(pts[i].first); - } - } - if (++i == int(pts.size())) - i = 0; - } - writer.extrude(pts[start_i].first, feedrate); - return poly; - }; - feedrate = first_layer ? m_first_layer_speed * 60.f : std::min(m_wipe_tower_max_purge_speed * 60.f, m_perimeter_speed * 60.f); - // outer contour (always) - bool infill_cone = first_layer && m_wipe_tower_width > 2*spacing && m_wipe_tower_depth > 2*spacing; - Polygon poly = supported_rectangle(wt_box, feedrate, infill_cone); - + Polygon poly; + if (m_wall_type == (int)wtwCone) { + WipeTower::box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)), + m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); + // outer contour (always) + bool infill_cone = first_layer && m_wipe_tower_width > 2 * spacing && m_wipe_tower_depth > 2 * spacing; + poly = generate_support_cone_wall(writer, wt_box, feedrate, infill_cone, spacing); + } else { + WipeTower::box_coordinates wt_box(Vec2f(0.f, 0.f), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); + poly = generate_support_rib_wall(writer, wt_box, feedrate, first_layer, m_wall_type == (int)wtwRib, true, false); + } // brim (first layer only) if (first_layer) { + writer.append("; WIPE_TOWER_BRIM_START\n"); size_t loops_num = (m_wipe_tower_brim_width + spacing/2.f) / spacing; for (size_t i = 0; i < loops_num; ++ i) { @@ -1452,7 +2046,7 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer() break; } } - + writer.append("; WIPE_TOWER_BRIM_END\n"); // Save actual brim width to be later passed to the Print object, which will use it // for skirt calculation and pass it to GLCanvas for precise preview box m_wipe_tower_brim_width_real = loops_num * spacing; @@ -1659,10 +2253,18 @@ void WipeTower2::generate(std::vector> return; plan_tower(); - for (int i = 0; i<5; ++i) { +#if 1 + for (int i=0;i<5;++i) { save_on_last_wipe(); plan_tower(); } +#endif + + m_rib_length = std::max({m_rib_length, sqrt(m_wipe_tower_depth * m_wipe_tower_depth + m_wipe_tower_width * m_wipe_tower_width)}); + m_rib_length += m_extra_rib_length; + m_rib_length = std::max(0.f, m_rib_length); + m_rib_width = std::min(m_rib_width, std::min(m_wipe_tower_depth, m_wipe_tower_width) / + 2.f); // Ensure that the rib wall of the wipetower are attached to the infill. m_layer_info = m_plan.begin(); m_current_height = 0.f; @@ -1742,4 +2344,190 @@ std::vector> WipeTower2::get_z_and_depth_pairs() const return out; } + +Polygon WipeTower2::generate_rib_polygon(const WipeTower::box_coordinates& wt_box) +{ + + auto get_current_layer_rib_len = [](float cur_height, float max_height, float max_len) -> float { + return std::abs(max_height - cur_height) / max_height * max_len; + }; + coord_t diagonal_width = scaled(m_rib_width) / 2; + float a = this->m_wipe_tower_width, b = this->m_wipe_tower_depth; + Line line_1(Point::new_scale(Vec2f{0, 0}), Point::new_scale(Vec2f{a, b})); + Line line_2(Point::new_scale(Vec2f{a, 0}), Point::new_scale(Vec2f{0, b})); + float diagonal_extra_length = std::max(0.f, m_rib_length - (float) unscaled(line_1.length())) / 2.f; + diagonal_extra_length = scaled(get_current_layer_rib_len(this->m_z_pos, this->m_wipe_tower_height, diagonal_extra_length)); + Point y_shift{0, scaled(this->m_y_shift)}; + + line_1.extend(double(diagonal_extra_length)); + line_2.extend(double(diagonal_extra_length)); + line_1.translate(-y_shift); + line_2.translate(-y_shift); + + Polygon poly_1 = generate_rectange(line_1, diagonal_width); + Polygon poly_2 = generate_rectange(line_2, diagonal_width); + Polygon poly; + poly.points.push_back(Point::new_scale(wt_box.ld)); + poly.points.push_back(Point::new_scale(wt_box.rd)); + poly.points.push_back(Point::new_scale(wt_box.ru)); + poly.points.push_back(Point::new_scale(wt_box.lu)); + + Polygons p_1_2 = union_({poly_1, poly_2, poly}); + // Polygon res_poly = p_1_2.front(); + // for (auto &p : res_poly.points) res.push_back(unscale(p).cast()); + /*if (p_1_2.front().points.size() != 16) + std::cout << "error " << std::endl;*/ + return p_1_2.front(); +}; + +Polygon WipeTower2::generate_support_rib_wall(WipeTowerWriter2& writer, + const WipeTower::box_coordinates& wt_box, + double feedrate, + bool first_layer, + bool rib_wall, + bool extrude_perimeter, + bool skip_points) +{ + + float retract_length = m_filpar[m_current_tool].retract_length; + float retract_speed = m_filpar[m_current_tool].retract_speed * 60; + Polygon wall_polygon = rib_wall ? generate_rib_polygon(wt_box) : generate_rectange_polygon(wt_box.ld, wt_box.ru); + Polylines result_wall; + Polygon insert_skip_polygon; + if (m_used_fillet) { + if (!rib_wall && m_y_shift > EPSILON) // do nothing because the fillet will cause it to be suspended. + { + } else { + wall_polygon = rib_wall ? rounding_polygon(wall_polygon) : wall_polygon; // rectangle_wall do nothing + Polygon wt_box_polygon = generate_rectange_polygon(wt_box.ld, wt_box.ru); + wall_polygon = union_({wall_polygon, wt_box_polygon}).front(); + } + } + if (!extrude_perimeter) + return wall_polygon; + + if (skip_points) { + result_wall = contrust_gap_for_skip_points(wall_polygon, std::vector(), m_wipe_tower_width, 2.5 * m_perimeter_width, + insert_skip_polygon); + } else { + result_wall.push_back(to_polyline(wall_polygon)); + insert_skip_polygon = wall_polygon; + } + writer.generate_path(result_wall, feedrate, retract_length, retract_speed, m_used_fillet); + //if (m_cur_layer_id == 0) { + // BoundingBox bbox = get_extents(result_wall); + // m_rib_offset = Vec2f(-unscaled(bbox.min.x()), -unscaled(bbox.min.y())); + //} + + return insert_skip_polygon; +} + + +// This block creates the stabilization cone. +// First define a lambda to draw the rectangle with stabilization. +Polygon WipeTower2::generate_support_cone_wall( + WipeTowerWriter2& writer, const WipeTower::box_coordinates& wt_box, double feedrate, bool infill_cone, float spacing){ + + const auto [R, support_scale] = get_wipe_tower_cone_base(m_wipe_tower_width, m_wipe_tower_height, m_wipe_tower_depth, + m_wipe_tower_cone_angle); + + double z = m_no_sparse_layers ? + (m_current_height + m_layer_info->height) : + m_layer_info->z; // the former should actually work in both cases, but let's stay on the safe side (the 2.6.0 is close) + + double r = std::tan(Geometry::deg2rad(m_wipe_tower_cone_angle / 2.f)) * (m_wipe_tower_height - z); + Vec2f center = (wt_box.lu + wt_box.rd) / 2.; + double w = wt_box.lu.y() - wt_box.ld.y(); + enum Type { Arc, Corner, ArcStart, ArcEnd }; + + // First generate vector of annotated point which form the boundary. + std::vector> pts = {{wt_box.ru, Corner}}; + if (double alpha_start = std::asin((0.5 * w) / r); !std::isnan(alpha_start) && r > 0.5 * w + 0.01) { + for (double alpha = alpha_start; alpha < M_PI - alpha_start + 0.001; alpha += (M_PI - 2 * alpha_start) / 40.) + pts.emplace_back(Vec2f(center.x() + r * std::cos(alpha) / support_scale, center.y() + r * std::sin(alpha)), + alpha == alpha_start ? ArcStart : Arc); + pts.back().second = ArcEnd; + } + pts.emplace_back(wt_box.lu, Corner); + pts.emplace_back(wt_box.ld, Corner); + for (int i = int(pts.size()) - 3; i > 0; --i) + pts.emplace_back(Vec2f(pts[i].first.x(), 2 * center.y() - pts[i].first.y()), i == int(pts.size()) - 3 ? ArcStart : + i == 1 ? ArcEnd : + Arc); + pts.emplace_back(wt_box.rd, Corner); + + // Create a Polygon from the points. + Polygon poly; + for (const auto& [pt, tag] : pts) + poly.points.push_back(Point::new_scale(pt)); + + // Prepare polygons to be filled by infill. + Polylines polylines; + if (infill_cone && m_wipe_tower_width > 2 * spacing && m_wipe_tower_depth > 2 * spacing) { + ExPolygons infill_areas; + ExPolygon wt_contour(poly); + Polygon wt_rectangle( + Points{Point::new_scale(wt_box.ld), Point::new_scale(wt_box.rd), Point::new_scale(wt_box.ru), Point::new_scale(wt_box.lu)}); + wt_rectangle = offset(wt_rectangle, scale_(-spacing / 2.)).front(); + wt_contour = offset_ex(wt_contour, scale_(-spacing / 2.)).front(); + infill_areas = diff_ex(wt_contour, wt_rectangle); + if (infill_areas.size() == 2) { + ExPolygon& bottom_expoly = infill_areas.front().contour.points.front().y() < infill_areas.back().contour.points.front().y() ? + infill_areas[0] : + infill_areas[1]; + std::unique_ptr filler(Fill::new_from_type(ipMonotonicLine)); + filler->angle = Geometry::deg2rad(45.f); + filler->spacing = spacing; + FillParams params; + params.density = 1.f; + Surface surface(stBottom, bottom_expoly); + filler->bounding_box = get_extents(bottom_expoly); + polylines = filler->fill_surface(&surface, params); + if (!polylines.empty()) { + if (polylines.front().points.front().x() > polylines.back().points.back().x()) { + std::reverse(polylines.begin(), polylines.end()); + for (Polyline& p : polylines) + p.reverse(); + } + } + } + } + + // Find the closest corner and travel to it. + int start_i = 0; + double min_dist = std::numeric_limits::max(); + for (int i = 0; i < int(pts.size()); ++i) { + if (pts[i].second == Corner) { + double dist = (pts[i].first - Vec2f(writer.x(), writer.y())).squaredNorm(); + if (dist < min_dist) { + min_dist = dist; + start_i = i; + } + } + } + writer.travel(pts[start_i].first); + + // Now actually extrude the boundary (and possibly infill): + int i = start_i + 1 == int(pts.size()) ? 0 : start_i + 1; + while (i != start_i) { + writer.extrude(pts[i].first, feedrate); + if (pts[i].second == ArcEnd) { + // Extrude the infill. + if (!polylines.empty()) { + // Extrude the infill and travel back to where we were. + bool mirror = ((pts[i].first.y() - center.y()) * (unscale(polylines.front().points.front()).y() - center.y())) < 0.; + for (const Polyline& line : polylines) { + writer.travel(center - (mirror ? 1.f : -1.f) * (unscale(line.points.front()).cast() - center)); + for (size_t i = 0; i < line.points.size(); ++i) + writer.extrude(center - (mirror ? 1.f : -1.f) * (unscale(line.points[i]).cast() - center)); + } + writer.travel(pts[i].first); + } + } + if (++i == int(pts.size())) + i = 0; + } + writer.extrude(pts[start_i].first, feedrate); + return poly; +} } // namespace Slic3r diff --git a/src/libslic3r/GCode/WipeTower2.hpp b/src/libslic3r/GCode/WipeTower2.hpp index 0f377d00f7..3dbc066634 100644 --- a/src/libslic3r/GCode/WipeTower2.hpp +++ b/src/libslic3r/GCode/WipeTower2.hpp @@ -10,6 +10,7 @@ #include #include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" #include "WipeTower.hpp" namespace Slic3r { @@ -85,7 +86,8 @@ public: while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end()) ++m_layer_info; - m_current_shape = (! this->is_first_layer() && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL; + //m_current_shape = (! this->is_first_layer() && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL; + m_current_shape = SHAPE_NORMAL; if (this->is_first_layer()) { m_num_layer_changes = 0; m_num_tool_changes = 0; @@ -156,6 +158,8 @@ public: bool multitool_ramming; float multitool_ramming_time = 0.f; float filament_minimal_purge_on_wipe_tower = 0.f; + float retract_length; + float retract_speed; }; private: @@ -196,6 +200,14 @@ private: float m_first_layer_speed = 0.f; size_t m_first_layer_idx = size_t(-1); + int m_wall_type; + bool m_used_fillet = true; + float m_rib_width = 10; + float m_extra_rib_length = 0; + float m_rib_length = 0; + + bool m_enable_arc_fitting = false; + // G-code generator parameters. float m_cooling_tube_retraction = 0.f; float m_cooling_tube_length = 0.f; @@ -315,6 +327,24 @@ private: WipeTowerWriter2 &writer, const WipeTower::box_coordinates &cleaning_box, float wipe_volume); + + + Polygon generate_support_rib_wall(WipeTowerWriter2& writer, + const WipeTower::box_coordinates& wt_box, + double feedrate, + bool first_layer, + bool rib_wall, + bool extrude_perimeter, + bool skip_points); + + Polygon generate_support_cone_wall( + WipeTowerWriter2& writer, + const WipeTower::box_coordinates& wt_box, + double feedrate, + bool infill_cone, + float spacing); + + Polygon generate_rib_polygon(const WipeTower::box_coordinates& wt_box); }; diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index df54335939..f1c0cf244f 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -830,7 +830,9 @@ static std::vector s_Preset_print_options { "tree_support_brim_width", "gcode_comments", "gcode_label_objects", "initial_layer_travel_speed", "exclude_object", "slow_down_layers", "infill_anchor", "infill_anchor_max","initial_layer_min_bead_width", "make_overhang_printable", "make_overhang_printable_angle", "make_overhang_printable_hole_size" ,"notes", - "wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", "wipe_tower_filament", "wiping_volumes_extruders","wipe_tower_bridging", "wipe_tower_extra_flow","single_extruder_multi_material_priming", + "wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", + "wipe_tower_wall_type", "wipe_tower_extra_rib_length", "wipe_tower_rib_width", "wipe_tower_fillet_wall", + "wipe_tower_filament", "wiping_volumes_extruders","wipe_tower_bridging", "wipe_tower_extra_flow","single_extruder_multi_material_priming", "wipe_tower_rotation_angle", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic", "tree_support_branch_angle_organic", "hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth", "small_area_infill_flow_compensation", "small_area_infill_flow_compensation_model", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 1d73cd1fe7..dfc34a850c 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -304,6 +304,10 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "wipe_tower_cone_angle" || opt_key == "wipe_tower_extra_spacing" || opt_key == "wipe_tower_max_purge_speed" + || opt_key == "wipe_tower_wall_type" + || opt_key == "wipe_tower_extra_rib_length" + || opt_key == "wipe_tower_rib_width" + || opt_key == "wipe_tower_fillet_wall" || opt_key == "wipe_tower_filament" || opt_key == "wiping_volumes_extruders" || opt_key == "enable_filament_ramming" diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 9e9b43c61f..5ed428fcf6 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -445,6 +445,13 @@ static const t_config_enum_values s_keys_map_CounterboreHoleBridgingOption{ }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(CounterboreHoleBridgingOption) +static const t_config_enum_values s_keys_map_WipeTowerWallType{ + {"rectangle", wtwRectangle}, + {"cone", wtwCone}, + {"rib", wtwRib}, +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(WipeTowerWallType) + static void assign_printer_technology_to_unknown(t_optiondef_map &options, PrinterTechnology printer_technology) { for (std::pair &kvp : options) @@ -5394,7 +5401,7 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->min = 0.; def->max = 90.; - def->set_default_value(new ConfigOptionFloat(0.)); + def->set_default_value(new ConfigOptionFloat(30.0)); def = this->add("wipe_tower_max_purge_speed", coFloat); def->label = L("Maximum wipe tower print speed"); @@ -5409,6 +5416,46 @@ void PrintConfigDef::init_fff_params() def->min = 10; def->set_default_value(new ConfigOptionFloat(90.)); + def = this->add("wipe_tower_wall_type", coEnum); + def->label = L("Wall type"); + def->tooltip = L("Wipe tower outer wall type.\n" + "1. Rectangle: The default wall type, a rectangle with fixed width and height.\n" + "2. Cone: A cone with a fillet at the bottom to help stabilize the wipe tower.\n" + "3. Rib: Adds four ribs to the tower wall for enhanced stability."); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.emplace_back("rectangle"); + def->enum_values.emplace_back("cone"); + def->enum_values.emplace_back("rib"); + def->enum_labels.emplace_back("Rectangle"); + def->enum_labels.emplace_back("Cone"); + def->enum_labels.emplace_back("Rib"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionEnum(wtwRectangle)); + + def = this->add("wipe_tower_extra_rib_length", coFloat); + def->label = L("Extra rib length"); + def->tooltip = L("Positive values can increase the size of the rib wall, while negative values can reduce the size." + "However, the size of the rib wall can not be smaller than that determined by the cleaning volume."); + def->sidetext = L("mm"); + def->max = 300; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0)); + + def = this->add("wipe_tower_rib_width", coFloat); + def->label = L("Rib width"); + def->tooltip = L("Rib width"); + def->sidetext = L("mm"); + def->mode = comAdvanced; + def->min = 0; + def->set_default_value(new ConfigOptionFloat(8)); + + def = this->add("wipe_tower_fillet_wall", coBool); + def->label = L("Fillet wall"); + def->tooltip = L("The wall of prime tower will fillet."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(true)); + + def = this->add("wipe_tower_filament", coInt); def->gui_type = ConfigOptionDef::GUIType::i_enum_open; def->label = L("Wipe tower"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 95540005b4..d244e7bab2 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -332,6 +332,12 @@ enum CounterboreHoleBridgingOption { chbNone, chbBridges, chbFilled }; + enum WipeTowerWallType { + wtwRectangle = 0, + wtwCone, + wtwRib + }; + static std::string bed_type_to_gcode_string(const BedType type) { std::string type_str; @@ -439,7 +445,9 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeThumbnailsFormat) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(CounterboreHoleBridgingOption) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PrintHostType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(AuthorizationType) +CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(WipeTowerWallType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PerimeterGeneratorType) + #undef CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS class DynamicPrintConfig; @@ -1327,6 +1335,10 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionFloat, wipe_tower_cone_angle)) ((ConfigOptionPercent, wipe_tower_extra_spacing)) ((ConfigOptionFloat, wipe_tower_max_purge_speed)) + ((ConfigOptionEnum, wipe_tower_wall_type)) + ((ConfigOptionFloat, wipe_tower_extra_rib_length)) + ((ConfigOptionFloat, wipe_tower_rib_width)) + ((ConfigOptionBool, wipe_tower_fillet_wall)) ((ConfigOptionInt, wipe_tower_filament)) ((ConfigOptionFloats, wiping_volumes_extruders)) ((ConfigOptionInts, idle_temperature)) diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index f4248baf65..048cb065fe 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -686,10 +686,19 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_max_purge_speed", + "wipe_tower_wall_type", + "wipe_tower_extra_rib_length","wipe_tower_rib_width","wipe_tower_fillet_wall", "wipe_tower_bridging", "wipe_tower_extra_flow", "wipe_tower_no_sparse_layers"}) toggle_line(el, have_prime_tower && !is_BBL_Printer); + WipeTowerWallType wipe_tower_wall_type = config->opt_enum("wipe_tower_wall_type"); + toggle_line("wipe_tower_cone_angle", have_prime_tower && !is_BBL_Printer && wipe_tower_wall_type == WipeTowerWallType::wtwCone); + toggle_line("wipe_tower_extra_rib_length", have_prime_tower && !is_BBL_Printer && wipe_tower_wall_type == WipeTowerWallType::wtwRib); + toggle_line("wipe_tower_rib_width", have_prime_tower && !is_BBL_Printer && wipe_tower_wall_type == WipeTowerWallType::wtwRib); + toggle_line("wipe_tower_fillet_wall", have_prime_tower && !is_BBL_Printer && wipe_tower_wall_type == WipeTowerWallType::wtwRib); + + toggle_line("single_extruder_multi_material_priming", !bSEMM && have_prime_tower && !is_BBL_Printer); toggle_line("prime_volume",have_prime_tower && (!purge_in_primetower || !bSEMM)); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 9760237e83..08881caa6f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2828,7 +2828,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) "brim_width", "wall_loops", "wall_filament", "sparse_infill_density", "sparse_infill_filament", "top_shell_layers", "enable_support", "support_filament", "support_interface_filament", "support_top_z_distance", "support_bottom_z_distance", "raft_layers", - "wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extra_flow", "wipe_tower_max_purge_speed", "wipe_tower_filament", + "wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extra_flow", "wipe_tower_max_purge_speed", + "wipe_tower_wall_type", "wipe_tower_extra_rib_length","wipe_tower_rib_width","wipe_tower_fillet_wall", + "wipe_tower_filament", "best_object_pos" })) , sidebar(new Sidebar(q)) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index e566b15f00..34b42a8d0a 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2323,10 +2323,14 @@ void TabPrint::build() optgroup->append_single_option_line("prime_tower_brim_width"); optgroup->append_single_option_line("wipe_tower_rotation_angle"); optgroup->append_single_option_line("wipe_tower_bridging"); - optgroup->append_single_option_line("wipe_tower_cone_angle"); optgroup->append_single_option_line("wipe_tower_extra_spacing"); optgroup->append_single_option_line("wipe_tower_extra_flow"); optgroup->append_single_option_line("wipe_tower_max_purge_speed"); + optgroup->append_single_option_line("wipe_tower_wall_type"); + optgroup->append_single_option_line("wipe_tower_cone_angle"); + optgroup->append_single_option_line("wipe_tower_extra_rib_length"); + optgroup->append_single_option_line("wipe_tower_rib_width"); + optgroup->append_single_option_line("wipe_tower_fillet_wall"); optgroup->append_single_option_line("wipe_tower_no_sparse_layers"); optgroup->append_single_option_line("single_extruder_multi_material_priming"); From be3bbfa39e1eb53e1bd692ea7658038cb80f8604 Mon Sep 17 00:00:00 2001 From: lodriguez Date: Sun, 15 Jun 2025 08:53:42 +0200 Subject: [PATCH 7/7] remove OSMesa (#9708) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove OSMesa OSMesa is depricated for quite a while and got removed with Mesa 25.1.0 * remove OSMesa from all buildfiles, readmes, etc… --------- Co-authored-by: Noisyfox --- .github/workflows/build_deps.yml | 2 +- .github/workflows/build_orca.yml | 2 +- Dockerfile | 1 - deps/GLEW/glew/README.md | 7 ------- doc/How-to-build.md | 1 - flatpak/io.github.softfever.OrcaSlicer.yml | 23 ---------------------- linux.d/debian | 1 - linux.d/fedora | 1 - src/slic3r/CMakeLists.txt | 2 +- 9 files changed, 3 insertions(+), 37 deletions(-) diff --git a/.github/workflows/build_deps.yml b/.github/workflows/build_deps.yml index f45394adf1..4a29a133a1 100644 --- a/.github/workflows/build_deps.yml +++ b/.github/workflows/build_deps.yml @@ -97,7 +97,7 @@ jobs: libwayland-dev libxkbcommon-dev wayland-protocols extra-cmake-modules pkgconf \ libglu1-mesa-dev libcairo2-dev libgtk-3-dev libsoup2.4-dev libwebkit2gtk-${{ env.webkit-ver }}-dev \ libgstreamer1.0-dev libgstreamer-plugins-good1.0-dev libgstreamer-plugins-base1.0-dev \ - gstreamer1.0-plugins-bad libosmesa6-dev wget sudo autoconf curl libunwind-dev texinfo + gstreamer1.0-plugins-bad wget sudo autoconf curl libunwind-dev texinfo - name: Build on Ubuntu if: inputs.os == 'ubuntu-20.04' || inputs.os == 'ubuntu-24.04' diff --git a/.github/workflows/build_orca.yml b/.github/workflows/build_orca.yml index 1102895cc0..1ae30f7b3b 100644 --- a/.github/workflows/build_orca.yml +++ b/.github/workflows/build_orca.yml @@ -243,7 +243,7 @@ jobs: ${{ env.apt-cmd }} install -y autoconf build-essential cmake curl eglexternalplatform-dev \ extra-cmake-modules file git libcairo2-dev libcurl4-openssl-dev libdbus-1-dev libglew-dev libglu1-mesa-dev \ libglu1-mesa-dev libgstreamer1.0-dev libgstreamerd-3-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev \ - libgtk-3-dev libgtk-3-dev libmspack-dev libosmesa6-dev libsecret-1-dev libsoup2.4-dev libssl-dev libudev-dev libwayland-dev \ + libgtk-3-dev libgtk-3-dev libmspack-dev libsecret-1-dev libsoup2.4-dev libssl-dev libudev-dev libwayland-dev \ libwebkit2gtk-${{ env.webkit-ver }}-dev libxkbcommon-dev locales locales-all m4 pkgconf sudo wayland-protocols wget ${{ env.libfuse2-pkg }} - name: Install dependencies from build_linux.sh diff --git a/Dockerfile b/Dockerfile index db9bf705e1..0cc12ac2aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,7 +32,6 @@ RUN apt-get update && apt-get install -y \ libgstreamer-plugins-good1.0-dev \ libgtk-3-dev \ libgtk-3-dev \ - libosmesa6-dev \ libsecret-1-dev \ libsoup2.4-dev \ libssl3 \ diff --git a/deps/GLEW/glew/README.md b/deps/GLEW/glew/README.md index bfec3064de..475c69afc8 100644 --- a/deps/GLEW/glew/README.md +++ b/deps/GLEW/glew/README.md @@ -22,7 +22,6 @@ https://github.com/nigels-com/glew * [Install build tools](#install-build-tools) * [Build](#build-1) * [Linux EGL](#linux-egl) - * [Linux OSMesa](#linux-osmesa) * [Linux mingw-w64](#linux-mingw-w64) * [Using cmake](#using-cmake) * [Install build tools](#install-build-tools-1) @@ -95,11 +94,6 @@ _Note: you may need to call `make` in the **auto** folder first_ $ sudo apt install libegl1-mesa-dev $ make SYSTEM=linux-egl -##### Linux OSMesa - - $ sudo apt install libosmesa-dev - $ make SYSTEM=linux-osmesa - ##### Linux mingw-w64 $ sudo apt install mingw-w64 @@ -140,7 +134,6 @@ RedHat/CentOS/Fedora: `$ sudo yum install libXmu-devel libXi-devel libGL-devel c | --------------- | ----------- | | BUILD_UTILS | Build the `glewinfo` and `visualinfo` executables. | | GLEW_REGAL | Build in Regal mode. | -| GLEW_OSMESA | Build in off-screen Mesa mode. | | BUILD_FRAMEWORK | Build as MacOSX Framework. Setting `CMAKE_INSTALL_PREFIX` to `/Library/Frameworks` is recommended. | ### Windows diff --git a/doc/How-to-build.md b/doc/How-to-build.md index c414bad3be..2377656e08 100644 --- a/doc/How-to-build.md +++ b/doc/How-to-build.md @@ -172,7 +172,6 @@ All required dependencies will be installed automatically by the provided shell - libgstreamerd-3-dev - libsecret-1-dev - libwebkit2gtk-4.0-dev -- libosmesa6-dev - libssl-dev - libcurl4-openssl-dev - eglexternalplatform-dev diff --git a/flatpak/io.github.softfever.OrcaSlicer.yml b/flatpak/io.github.softfever.OrcaSlicer.yml index 2f588045d3..3dde299a64 100755 --- a/flatpak/io.github.softfever.OrcaSlicer.yml +++ b/flatpak/io.github.softfever.OrcaSlicer.yml @@ -36,29 +36,6 @@ modules: url: https://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.22.8.tar.xz sha256: e305b9f07f52743ca481da0a4e0c76c35efd60adaf1b0694eb3bb021e2137e39 - # For libOSMesa - - name: mesa - buildsystem: meson - config-opts: - - -Dosmesa=classic - - -Ddri-drivers=[] - - -Dgallium-drivers=[] - - -Dvulkan-drivers=[] - - -Dplatforms=[] - build-options: - arch: - aarch64: - config-opts: - - -Dlibunwind=disabled - cleanup: - - /share/drirc.d - - /include - - "*.a" - sources: - - type: archive - url: https://archive.mesa3d.org/older-versions/20.x/mesa-20.2.6.tar.xz - sha256: f12ca3c6c622f11cd79ad66b4220f04514fa96f795062fe92a37339ab19885db - - name: glu config-opts: - --disable-static diff --git a/linux.d/debian b/linux.d/debian index 121e53a3a7..cce41d74ce 100644 --- a/linux.d/debian +++ b/linux.d/debian @@ -15,7 +15,6 @@ REQUIRED_DEV_PACKAGES=( libgstreamerd-3-dev libgtk-3-dev libmspack-dev - libosmesa6-dev libsecret-1-dev libspnav-dev libssl-dev diff --git a/linux.d/fedora b/linux.d/fedora index bdfe05d567..ed91883dd9 100644 --- a/linux.d/fedora +++ b/linux.d/fedora @@ -22,7 +22,6 @@ REQUIRED_DEV_PACKAGES=( libtool m4 mesa-libGLU-devel - mesa-libOSMesa-devel ninja-build openssl-devel perl-FindBin diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index b3a28a1c6b..903b66368b 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -640,9 +640,9 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux") FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl) FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client) find_package(CURL REQUIRED) - target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES} OSMesa) target_link_libraries(libslic3r_gui OpenGL::EGL + ${DBUS_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CLIENT_LIBRARIES}