From 990d235415c87fdf3be2d5bad13315375b634d03 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Tue, 27 Dec 2022 23:51:53 +0800 Subject: [PATCH] pressure advance tower --- .../pressure_advance_test.stl | Bin .../calib/PresureAdvnace/tower_with_seam.stl | Bin 0 -> 30284 bytes src/libslic3r/GCode.cpp | 10 ++++- src/libslic3r/Print.hpp | 8 ++-- src/slic3r/GUI/MainFrame.cpp | 32 ++++++++++--- src/slic3r/GUI/Plater.cpp | 42 ++++++++++++++++-- src/slic3r/GUI/Plater.hpp | 2 +- 7 files changed, 79 insertions(+), 15 deletions(-) rename resources/calib/{ => PresureAdvnace}/pressure_advance_test.stl (100%) create mode 100644 resources/calib/PresureAdvnace/tower_with_seam.stl diff --git a/resources/calib/pressure_advance_test.stl b/resources/calib/PresureAdvnace/pressure_advance_test.stl similarity index 100% rename from resources/calib/pressure_advance_test.stl rename to resources/calib/PresureAdvnace/pressure_advance_test.stl diff --git a/resources/calib/PresureAdvnace/tower_with_seam.stl b/resources/calib/PresureAdvnace/tower_with_seam.stl new file mode 100644 index 0000000000000000000000000000000000000000..325ffb1d70bfb844b501de354404901a2ddc6272 GIT binary patch literal 30284 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.insert(iter->first); } if (this->m_objsWithBrim.empty() && this->m_objSupportsWithBrim.empty()) m_brim_done = true; - if (print.is_calib_mode() == Calib_PA_DDE || print.is_calib_mode() == Calib_PA_Bowden) { + if (print.calib_mode() == Calib_PA_DDE || print.calib_mode() == Calib_PA_Bowden) { std::string gcode; auto s = m_config.inner_wall_speed.value; gcode += m_writer.set_acceleration((unsigned int)floor(m_config.outer_wall_acceleration.value + 0.5)); @@ -1645,7 +1645,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato m_config.outer_wall_speed = print.default_region_config().outer_wall_speed; m_config.inner_wall_speed = print.default_region_config().inner_wall_speed; calib_pressure_advance pa_test(this); - if(print.is_calib_mode() == Calib_PA_DDE) + if(print.calib_mode() == Calib_PA_DDE) gcode += pa_test.generate_test(); else gcode +=pa_test.generate_test(0.0,0.02); @@ -2589,6 +2589,12 @@ GCode::LayerResult GCode::process_layer( config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); } + if (print.calib_mode() == Calib_PA_Tower_DDE) { + gcode += writer().set_pressure_advance(static_cast(print_z) * 0.002); + } + else if(print.calib_mode() == Calib_PA_Tower_Bowden) { + gcode += writer().set_pressure_advance(static_cast(print_z) * 0.02); + } //BBS if (first_layer) { //BBS: set first layer global acceleration diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index a7e3d4807a..337981df2c 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -91,7 +91,9 @@ enum PrintObjectStep { enum CalibMode { Calib_None = 0, Calib_PA_DDE, - Calib_PA_Bowden + Calib_PA_Bowden, + Calib_PA_Tower_DDE, + Calib_PA_Tower_Bowden }; // A PrintRegion object represents a group of volumes to print @@ -741,8 +743,8 @@ public: //SoftFever bool &is_BBL_printer() { return m_isBBLPrinter; } const bool is_BBL_printer() const { return m_isBBLPrinter; } - CalibMode& is_calib_mode() { return m_calib_mode; } - const CalibMode is_calib_mode() const { return m_calib_mode; } + CalibMode& calib_mode() { return m_calib_mode; } + const CalibMode calib_mode() const { return m_calib_mode; } protected: // Invalidates the step, and its depending steps in Print. bool invalidate_step(PrintStep step); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 0d96f63762..f5fe4941b9 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -12,6 +12,7 @@ //#include #include #include +#include #include #include @@ -2460,18 +2461,37 @@ void MainFrame::init_menubar_as_editor() m_topbar->AddDropDownSubMenu(helpMenu, _L("Help")); // SoftFever calibrations - append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("PA - DDE"), _L("Calibrate PA - DDE"), - [this](wxCommandEvent&) { if (m_plater) m_plater->calib_pa(false); }, "", nullptr, + auto pa_menu = new wxMenu(); + // PA + append_menu_item(pa_menu, wxID_ANY, _L("Line method - DDE"), _L(""), + [this](wxCommandEvent&) { if (m_plater) m_plater->calib_pa(true, false); }, "", nullptr, [this]() {return m_plater->is_view3D_shown();; }, this); - append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("PA - Bowden"), _L("Calibrate PA - Bowden"), - [this](wxCommandEvent&) { if (m_plater) m_plater->calib_pa(true); }, "", nullptr, + append_menu_item(pa_menu, wxID_ANY, _L("Line method - Bowden"), _L(""), + [this](wxCommandEvent&) { if (m_plater) m_plater->calib_pa(true, true); }, "", nullptr, [this]() {return m_plater->is_view3D_shown();; }, this); - append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Flowrate - Pass 1"), _L("Flowrate - Pass 1"), + append_menu_item(pa_menu, wxID_ANY, _L("Tower method - DDE"), _L(""), + [this](wxCommandEvent&) { if (m_plater) m_plater->calib_pa(false, false); }, "", nullptr, + [this]() {return m_plater->is_view3D_shown();; }, this); + append_menu_item(pa_menu, wxID_ANY, _L("Tower method - Bowden"), _L(""), + [this](wxCommandEvent&) { if (m_plater) m_plater->calib_pa(false, true); }, "", nullptr, + [this]() {return m_plater->is_view3D_shown();; }, this); + m_topbar->GetCalibMenu()->AppendSubMenu(pa_menu, _L("Presure/Linear Advance")); + + // Flowrate + auto flowrate_menu = new wxMenu(); + append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 1"), _L("Flow rate test - Pass 1"), [this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(1); }, "", nullptr, [this]() {return m_plater->is_view3D_shown();; }, this); - append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Flowrate - Pass 2"), _L("Flowrate - Pass 2"), + append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 2"), _L("Flow rate test - Pass 2"), [this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(2); }, "", nullptr, [this]() {return m_plater->is_view3D_shown();; }, this); + m_topbar->GetCalibMenu()->AppendSubMenu(flowrate_menu, _L("Flow rate")); + + // help + auto calib_help_menu = append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Tutorial"), _L("Calibration help"), + [this](wxCommandEvent&) { wxLaunchDefaultBrowser("https://github.com/SoftFever/BambuStudio-SoftFever/wiki/Calibration", wxBROWSER_NEW_WINDOW); }, "", nullptr, + [this]() {return m_plater->is_view3D_shown();; }, this); + #else m_menubar->Append(fileMenu, wxString::Format("&%s", _L("File"))); if (editMenu) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5351ce08a2..9ef895094f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -7865,13 +7865,49 @@ void Plater::add_model(bool imperial_units/* = false*/, std::string fname/* = " } } -void Plater::calib_pa(bool bowden) { +void Plater::calib_pa(bool line_method, bool bowden) { const auto calib_pa_name = "Pressure Advance Test"; new_project(false, false, calib_pa_name); - add_model(false, Slic3r::resources_dir() + "/calib/pressure_advance_test.stl"); wxGetApp().mainframe->select_tab(size_t(MainFrame::tp3DEditor)); + if (line_method) { + add_model(false, Slic3r::resources_dir() + "/calib/PresureAdvnace/pressure_advance_test.stl"); + p->background_process.fff_print()->calib_mode() = bowden ? Calib_PA_Bowden : Calib_PA_DDE; + } + else { + add_model(false, Slic3r::resources_dir() + "/calib/PresureAdvnace/tower_with_seam.stl"); + p->background_process.fff_print()->calib_mode() = bowden ? Calib_PA_Tower_Bowden: Calib_PA_Tower_DDE; + auto print_config = &wxGetApp().preset_bundle->prints.get_edited_preset().config; + auto printer_config = &wxGetApp().preset_bundle->printers.get_edited_preset().config; + auto filament_config = &wxGetApp().preset_bundle->filaments.get_edited_preset().config; + filament_config->set_key_value("slow_down_layer_time", new ConfigOptionFloats{ 1.0f }); + print_config->set_key_value("default_jerk", new ConfigOptionFloat(1.0f)); + print_config->set_key_value("outer_wall_jerk", new ConfigOptionFloat(1.0f)); + print_config->set_key_value("inner_wall_jerk", new ConfigOptionFloat(1.0f)); + print_config->set_key_value("top_surface_jerk", new ConfigOptionFloat(1.0f)); + model().objects[0]->config.set_key_value("seam_position", new ConfigOptionEnum(spRear)); + + changed_objects({ 0 }); + wxGetApp().get_tab(Preset::TYPE_PRINT)->update_dirty(); + wxGetApp().get_tab(Preset::TYPE_FILAMENT)->update_dirty(); + + + // automatic selection of added objects + // update printable state for new volumes on canvas3D + wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects({0}); + + Selection& selection = p->view3D->get_canvas3d()->get_selection(); + selection.clear(); + selection.add_object(0, false); + + // BBS: update object list selection + p->sidebar->obj_list()->update_selections(); + selection.notify_instance_update(-1, -1); + if (p->view3D->get_canvas3d()->get_gizmos_manager().is_enabled()) + // this is required because the selected object changed and the flatten on face an sla support gizmos need to be updated accordingly + p->view3D->get_canvas3d()->update_gizmos_on_off_state(); + + } - p->background_process.fff_print()->is_calib_mode() = bowden ? Calib_PA_Bowden : Calib_PA_DDE; } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index d604237621..aef8479e3c 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -226,7 +226,7 @@ public: void refresh_print(); // SoftFever - void calib_pa(bool bowden = false); + void calib_pa(bool line_method = true, bool bowden = false); void calib_flowrate(int pass); ModelObject* add_part(ModelObject* model_object, std::string input_file, Vec3d move, Vec3d scale);