diff --git a/README.md b/README.md index d9f9f5c9f1..77f8547f08 100644 --- a/README.md +++ b/README.md @@ -86,5 +86,7 @@ Slic3r is licensed under the GNU Affero General Public License, version 3. Slic3 The GNU Affero General Public License, version 3 ensures that if you use any part of this software in any way (even behind a web server), your software must be released under the same license. +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. It is optional to the Orca Slicer and provides extended functionalities for users. diff --git a/doc/Calibration.md b/doc/Calibration.md index 58baa67223..70961b231b 100644 --- a/doc/Calibration.md +++ b/doc/Calibration.md @@ -1,7 +1,8 @@ - [Flow rate](#Flow-rate) - [Pressure Advance](#Pressure-Advance) 1. [Line method](#Line-method) - 2. [Tower method](#Tower-method) + 2. [Pattern method](#Pattern-method) + 3. [Tower method](#Tower-method) - [Temp tower](#Temp-tower) - [Retraction test](#Retraction-test) - [Orca Tolerance Test](#Orca-Tolerance-Test) @@ -32,10 +33,13 @@ Steps ![image](https://user-images.githubusercontent.com/103989404/210139721-919be130-fbba-4e3a-aa58-8a563e8c7792.png) # Pressure Advance -I will present two approaches for calibrating the pressure advance value. Both methods have their own advantages and disadvantages. It is important to note that each method has two versions: one for a direct drive extruder and one for a Bowden extruder. Make sure to select the appropriate version for your test. - ##### *NOTE: For Bambulab X1/X1C users, make sure you do not select the 'Flow calibration' option.* + +Orca Slicer includes three approaches for calibrating the pressure advance value. Each method has its own advantages and disadvantages. It is important to note that each method has two versions: one for a direct drive extruder and one for a Bowden extruder. Make sure to select the appropriate version for your test. + ##### *NOTE: For Bambulab X1/X1C users, make sure you do not select the 'Flow calibration' option when printings.* ![uncheck](https://user-images.githubusercontent.com/103989404/221345187-3c317a46-4d85-4221-99b9-adb5c7f48026.jpeg) + ### Line method + The line method is quick and straightforward to test. However, its accuracy highly depends on your first layer quality. It is suggested to turn on the bed mesh leveling for this test. Steps: 1. Select the printer, filament, and process you would like to use for the test. @@ -48,7 +52,27 @@ Steps: ![line_0 016](https://user-images.githubusercontent.com/103989404/210140046-dc5adf6a-42e8-48cd-950c-5e81558da967.jpg) ![image](https://user-images.githubusercontent.com/103989404/210140079-61a4aba4-ae01-4988-9f8e-2a45a90cdb7d.png) +### Pattern method + +The pattern method is adapted from [Andrew Ellis' pattern method generator](https://ellis3dp.com/Pressure_Linear_Advance_Tool/), which was itself derived from the [Marlin pattern method](https://marlinfw.org/tools/lin_advance/k-factor.html) developed by [Sineos](https://github.com/Sineos/k-factorjs). + +[Instructions for using and reading the pattern method](https://ellis3dp.com/Print-Tuning-Guide/articles/pressure_linear_advance/pattern_method.html) are provided in [Ellis' Print Tuning Guide](https://ellis3dp.com/Print-Tuning-Guide/), with only a few Orca Slicer differences to note. + +First and foremost, when you initiate the test, you'll only see a small rectangular prism on the plate. This object serves a few purposes: + +1. The test pattern itself is added in as custom G-Code at each layer, same as you could do by hand actually. The rectangular prism gives us the layers in which to insert that G-Code. This also means that **you'll see the full test pattern when you move to the Preview pane** +2. The prism acts as a handle, enabling you to move the test pattern wherever you'd like on the plate by moving the prism +3. The filament selected for the prism is also used for the test pattern + +Next, Ellis' generator provided the ability to adjust specific printer, filament, and print profile settings. You can make these same changes in Orca Slicer by adjusting the settings in the Prepare pane as you would with any other print. When you initiate the calibration test, Ellis' default settings are applied. A few things to note about these settings: + +1. Ellis specified line widths as a percent of filament diameter. The Orca pattern method does the same to provide its suggested defaults, making use of Ellis' percentages in combination with your specified nozzle diameter +2. In terms of line width, the pattern only makes use of the `Default` and `First layer` widths +3. In terms of speed, the pattern only uses the `First layer speed -> First layer` and `Other layers speed -> Outer wall` speeds +4. The infill pattern beneath the numbers cannot be changed becuase it's not actually an infill pattern pulled from the settings. All of the pattern G-Code is custom written, so that "infill" is, effectively, hand-drawn and so not processed through the usual channels that would enable Orca to recognize it as infill + ### Tower method + The tower method may take a bit more time to complete, but it does not rely on the quality of the first layer. The PA value for this test will be increased by 0.002 for every 1 mm increase in height. (**NOTE** 0.02 for Bowden) Steps: diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 126112f0d1..ee1a10893b 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -11,7 +11,6 @@ #include "Print.hpp" #include "Utils.hpp" #include "ClipperUtils.hpp" -#include "libslic3r.h" #include "LocalesUtils.hpp" #include "libslic3r/format.hpp" #include "Time.hpp" @@ -1056,7 +1055,6 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu GCodeProcessor::s_IsBBLPrinter = print->is_BBL_printer(); print->set_started(psGCodeExport); - // check if any custom gcode contains keywords used by the gcode processor to // produce time estimation and gcode toolpaths std::vector> validation_res = DoExport::validate_custom_gcode(*print); @@ -1886,14 +1884,18 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato gcode += m_writer.set_jerk_xy(jerk); } - calib_pressure_advance pa_test(this); + auto params = print.calib_params(); + + CalibPressureAdvanceLine pa_test(this); + double filament_max_volumetric_speed = m_config.option("filament_max_volumetric_speed")->get_at(initial_extruder_id); Flow pattern_line = Flow(pa_test.line_width(), 0.2, m_config.nozzle_diameter.get_at(0)); auto fast_speed = std::min(print.default_region_config().outer_wall_speed.value, filament_max_volumetric_speed / pattern_line.mm3_per_mm()); auto slow_speed = std::max(20.0, fast_speed / 10.0); + pa_test.set_speed(fast_speed, slow_speed); pa_test.draw_numbers() = print.calib_params().print_numbers; - auto params = print.calib_params(); + gcode += pa_test.generate_test(params.start, params.step, std::llround(std::ceil((params.end - params.start) / params.step))); file.write(gcode); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 0987e5937e..d20be486fd 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -72,6 +72,12 @@ Model& Model::assign_copy(const Model &rhs) this->plates_custom_gcodes = rhs.plates_custom_gcodes; this->curr_plate_index = rhs.curr_plate_index; + if (rhs.calib_pa_pattern) { + this->calib_pa_pattern = std::make_unique( + CalibPressureAdvancePattern(*rhs.calib_pa_pattern) + ); + } + // BBS: for design info this->design_info = rhs.design_info; this->model_info = rhs.model_info; @@ -100,6 +106,7 @@ Model& Model::assign_copy(Model &&rhs) // BBS this->plates_custom_gcodes = std::move(rhs.plates_custom_gcodes); this->curr_plate_index = rhs.curr_plate_index; + this->calib_pa_pattern = std::move(rhs.calib_pa_pattern); //BBS: add auxiliary path logic // BBS: backup, all in one temp dir @@ -893,6 +900,7 @@ void Model::load_from(Model& model) model.design_info.reset(); model.model_info.reset(); model.profile_info.reset(); + model.calib_pa_pattern.reset(); } // BBS: backup diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index a3002b22df..6e66ce2289 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -12,6 +12,7 @@ #include "SLA/Hollowing.hpp" #include "TriangleMesh.hpp" #include "CustomGCode.hpp" +#include "calib.hpp" #include "enum_bitmask.hpp" //BBS: add bbs 3mf @@ -1608,6 +1609,8 @@ public: // Checks if any of objects is painted using the multi-material painting gizmo. bool is_mm_painted() const; + std::unique_ptr calib_pa_pattern; + private: explicit Model(int) : ObjectBase(-1) { diff --git a/src/libslic3r/calib.cpp b/src/libslic3r/calib.cpp index b6a95ef4fc..321d04945f 100644 --- a/src/libslic3r/calib.cpp +++ b/src/libslic3r/calib.cpp @@ -1,221 +1,906 @@ #include "calib.hpp" -#include "Point.hpp" -#include "PrintConfig.hpp" -#include "GCodeWriter.hpp" -#include "GCode.hpp" -#include +#include "BoundingBox.hpp" +#include "Model.hpp" namespace Slic3r { +std::string CalibPressureAdvance::move_to(Vec2d pt, GCodeWriter& writer, std::string comment) +{ + std::stringstream gcode; - calib_pressure_advance::calib_pressure_advance(GCode* gcodegen) :mp_gcodegen(gcodegen), m_length_short(20.0), m_length_long(40.0), m_space_y(3.5), m_line_width(0.6), m_draw_numbers(true) {} + gcode << writer.retract(); + gcode << writer.travel_to_xy(pt, comment); + gcode << writer.unretract(); - std::string calib_pressure_advance::generate_test(double start_pa /*= 0*/, double step_pa /*= 0.002*/, - int count /*= 10*/) { - BoundingBoxf bed_ext = get_extents(mp_gcodegen->config().printable_area.values); - bool is_delta = false; - if (mp_gcodegen->config().printable_area.values.size() > 4) { - is_delta = true; - bed_ext.scale(1.0f / 1.41421f); - } + m_last_pos = Vec3d(pt.x(), pt.y(), 0); - auto bed_sizes = mp_gcodegen->config().printable_area.values; - const auto &w = bed_ext.size().x(); - const auto &h = bed_ext.size().y(); - count = std::min(count, int((h - 10) / m_space_y)); + return gcode.str(); +} - m_length_long = 40 + std::min(w - 120.0, 0.0); +double CalibPressureAdvance::e_per_mm( + double line_width, + double layer_height, + float nozzle_diameter, + float filament_diameter, + float print_flow_ratio +) const +{ + const Flow line_flow = Flow(line_width, layer_height, nozzle_diameter); + const double filament_area = M_PI * std::pow(filament_diameter / 2, 2); - auto startx = (w - m_length_short * 2 - m_length_long - 20) / 2; - auto starty = (h - count * m_space_y) / 2; - if (is_delta) { - startx = -startx; - starty = -(count * m_space_y) / 2; - } + return line_flow.mm3_per_mm() / filament_area * print_flow_ratio; +} - return print_pa_lines(startx, starty, start_pa, step_pa, count); - } +std::string CalibPressureAdvance::convert_number_to_string(double num) const +{ + auto sNumber = std::to_string(num); + sNumber.erase(sNumber.find_last_not_of('0') + 1, std::string::npos); + sNumber.erase(sNumber.find_last_not_of('.') + 1, std::string::npos); - std::string calib_pressure_advance::move_to(Vec2d pt) { - std::stringstream gcode; - gcode << mp_gcodegen->retract(); - gcode << mp_gcodegen->writer().travel_to_xyz(Vec3d(pt.x(), pt.y(), 0.2)); - gcode << mp_gcodegen->unretract(); - return gcode.str(); - } + return sNumber; +} - std::string calib_pressure_advance::print_pa_lines(double start_x, double start_y, double start_pa, double step_pa, int num) { +std::string CalibPressureAdvance::draw_digit( + double startx, + double starty, + char c, + CalibPressureAdvance::DrawDigitMode mode, + double line_width, + double e_per_mm, + GCodeWriter& writer +) +{ + const double len = m_digit_segment_len; + const double gap = line_width / 2.0; - auto& writer = mp_gcodegen->writer(); - Flow line_flow = Flow(m_line_width, 0.2, mp_gcodegen->config().nozzle_diameter.get_at(0)); - Flow thin_line_flow = Flow(0.44, 0.2, mp_gcodegen->config().nozzle_diameter.get_at(0)); - const double e_calib = line_flow.mm3_per_mm() / 2.40528; // filament_mm/extrusion_mm - const double e = thin_line_flow.mm3_per_mm() / 2.40528; // filament_mm/extrusion_mm + const auto dE = e_per_mm * len; + const auto two_dE = dE * 2; + Vec2d p0, p1, p2, p3, p4, p5; + Vec2d p0_5, p4_5; + Vec2d gap_p0_toward_p3, gap_p2_toward_p3; + Vec2d dot_direction; - const double fast = m_fast_speed * 60.0; - const double slow = m_slow_speed * 60.0; - std::stringstream gcode; - gcode << mp_gcodegen->writer().travel_to_z(0.2); - double y_pos = start_y; + if (mode == CalibPressureAdvance::DrawDigitMode::Bottom_To_Top) { + // 1-------2-------5 + // | | | + // | | | + // 0-------3-------4 + p0 = Vec2d(startx, starty); + p0_5 = Vec2d(startx, starty + len / 2); + p1 = Vec2d(startx, starty + len); + p2 = Vec2d(startx + len, starty + len); + p3 = Vec2d(startx + len, starty); + p4 = Vec2d(startx + len * 2, starty); + p4_5 = Vec2d(startx + len * 2, starty + len / 2); + p5 = Vec2d(startx + len * 2, starty + len); - // prime line - auto prime_x = start_x - 2; - gcode << move_to(Vec2d(prime_x, y_pos + (num - 4) * m_space_y)); - gcode << writer.set_speed(slow); - gcode << writer.extrude_to_xy(Vec2d(prime_x, y_pos + 3 * m_space_y), e_calib * m_space_y * num * 1.1); - - for (int i = 0; i < num; ++i) { - - gcode << writer.set_pressure_advance(start_pa + i * step_pa); - gcode << move_to(Vec2d(start_x, y_pos + i * m_space_y)); - gcode << writer.set_speed(slow); - gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short, y_pos + i * m_space_y), e_calib * m_length_short); - gcode << writer.set_speed(fast); - gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long, y_pos + i * m_space_y), e_calib * m_length_long); - gcode << writer.set_speed(slow); - gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long + m_length_short, y_pos + i * m_space_y), e_calib * m_length_short); - - } - gcode << writer.set_pressure_advance(0.0); - - if (m_draw_numbers) { - // draw indicator lines - gcode << writer.set_speed(fast); - gcode << move_to(Vec2d(start_x + m_length_short, y_pos + (num - 1) * m_space_y + 2)); - gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short, y_pos + (num - 1) * m_space_y + 7), e * 7); - gcode << move_to(Vec2d(start_x + m_length_short + m_length_long, y_pos + (num - 1) * m_space_y + 7)); - gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long, y_pos + (num - 1) * m_space_y + 2), e * 7); - - for (int i = 0; i < num; i += 2) { - gcode << draw_number(start_x + m_length_short + m_length_long + m_length_short + 3, y_pos + i * m_space_y + m_space_y / 2, start_pa + i * step_pa); - } - } - return gcode.str(); - } - - - std::string calib_pressure_advance::draw_digit(double startx, double starty, char c) { - auto& writer = mp_gcodegen->writer(); - std::stringstream gcode; - const double lw = 0.48; - Flow line_flow = Flow(lw, 0.2, mp_gcodegen->config().nozzle_diameter.get_at(0)); - const double len = 2; - const double gap = lw / 2.0; - const double e = line_flow.mm3_per_mm() / 2.40528; // filament_mm/extrusion_mm + gap_p0_toward_p3 = p0 + Vec2d(gap, 0); + gap_p2_toward_p3 = p2 + Vec2d(0, gap); + dot_direction = Vec2d(-len / 2, 0); + } else { // 0-------1 // | | // 3-------2 // | | // 4-------5 - const Vec2d p0(startx, starty); - const Vec2d p1(startx + len, starty); - const Vec2d p2(startx + len, starty - len); - const Vec2d p3(startx, starty - len); - const Vec2d p4(startx, starty - len * 2); - const Vec2d p5(startx + len, starty - len * 2); + p0 = Vec2d(startx, starty); + p0_5 = Vec2d(startx + len / 2, starty); + p1 = Vec2d(startx + len, starty); + p2 = Vec2d(startx + len, starty - len); + p3 = Vec2d(startx, starty - len); + p4 = Vec2d(startx, starty - len * 2); + p4_5 = Vec2d(startx + len / 2, starty - len * 2); + p5 = Vec2d(startx + len, starty - len * 2); - switch (c) - { - case '0': - gcode << move_to(p0); - gcode << writer.extrude_to_xy(p1, e * len); - gcode << writer.extrude_to_xy(p5, e * len * 2); - gcode << writer.extrude_to_xy(p4, e * len); - gcode << writer.extrude_to_xy(p0 - Vec2d(0, gap), e * len * 2); - break; - case '1': - gcode << move_to(p0 + Vec2d(len / 2, 0)); - gcode << writer.extrude_to_xy(p4 + Vec2d(len / 2, 0), e * len * 2); - break; - case '2': - gcode << move_to(p0); - gcode << writer.extrude_to_xy(p1, e * len); - gcode << writer.extrude_to_xy(p2, e * len); - gcode << writer.extrude_to_xy(p3, e * len); - gcode << writer.extrude_to_xy(p4, e * len); - gcode << writer.extrude_to_xy(p5, e * len); - break; - case '3': - gcode << move_to(p0); - gcode << writer.extrude_to_xy(p1, e * len); - gcode << writer.extrude_to_xy(p5, e * len * 2); - gcode << writer.extrude_to_xy(p4, e * len); - gcode << move_to(p2 - Vec2d(gap, 0)); - gcode << writer.extrude_to_xy(p3, e * len); - break; - case '4': - gcode << move_to(p0); - gcode << writer.extrude_to_xy(p3, e * len); - gcode << writer.extrude_to_xy(p2, e * len); - gcode << move_to(p1); - gcode << writer.extrude_to_xy(p5, e * len * 2); - break; - case '5': - gcode << move_to(p1); - gcode << writer.extrude_to_xy(p0, e * len); - gcode << writer.extrude_to_xy(p3, e * len); - gcode << writer.extrude_to_xy(p2, e * len); - gcode << writer.extrude_to_xy(p5, e * len); - gcode << writer.extrude_to_xy(p4, e * len); - break; - case '6': - gcode << move_to(p1); - gcode << writer.extrude_to_xy(p0, e * len); - gcode << writer.extrude_to_xy(p4, e * len * 2); - gcode << writer.extrude_to_xy(p5, e * len); - gcode << writer.extrude_to_xy(p2, e * len); - gcode << writer.extrude_to_xy(p3, e * len); - break; - case '7': - gcode << move_to(p0); - gcode << writer.extrude_to_xy(p1, e * len); - gcode << writer.extrude_to_xy(p5, e * len * 2); - break; - case '8': - gcode << move_to(p2); - gcode << writer.extrude_to_xy(p3, e * len); - gcode << writer.extrude_to_xy(p4, e * len); - gcode << writer.extrude_to_xy(p5, e * len); - gcode << writer.extrude_to_xy(p1, e * len * 2); - gcode << writer.extrude_to_xy(p0, e * len); - gcode << writer.extrude_to_xy(p3, e * len); - break; - case '9': - gcode << move_to(p5); - gcode << writer.extrude_to_xy(p1, e * len * 2); - gcode << writer.extrude_to_xy(p0, e * len); - gcode << writer.extrude_to_xy(p3, e * len); - gcode << writer.extrude_to_xy(p2, e * len); - break; - case '.': - gcode << move_to(p4 + Vec2d(len / 2, 0)); - gcode << writer.extrude_to_xy(p4 + Vec2d(len / 2, len / 2), e * len); - break; - default: + gap_p0_toward_p3 = p0 - Vec2d(0, gap); + gap_p2_toward_p3 = p2 - Vec2d(gap, 0); + + dot_direction = Vec2d(0, len / 2); + } + + std::stringstream gcode; + + switch (c) { + case '0': + gcode << move_to(p0, writer, "Glyph: 0"); + gcode << writer.extrude_to_xy(p1, dE); + gcode << writer.extrude_to_xy(p5, two_dE); + gcode << writer.extrude_to_xy(p4, dE); + gcode << writer.extrude_to_xy(gap_p0_toward_p3, two_dE); + break; + case '1': + gcode << move_to(p0_5, writer, "Glyph: 1"); + gcode << writer.extrude_to_xy(p4_5, two_dE); + break; + case '2': + gcode << move_to(p0, writer, "Glyph: 2"); + gcode << writer.extrude_to_xy(p1, dE); + gcode << writer.extrude_to_xy(p2, dE); + gcode << writer.extrude_to_xy(p3, dE); + gcode << writer.extrude_to_xy(p4, dE); + gcode << writer.extrude_to_xy(p5, dE); + break; + case '3': + gcode << move_to(p0, writer, "Glyph: 3"); + gcode << writer.extrude_to_xy(p1, dE); + gcode << writer.extrude_to_xy(p5, two_dE); + gcode << writer.extrude_to_xy(p4, dE); + gcode << move_to(gap_p2_toward_p3, writer); + gcode << writer.extrude_to_xy(p3, dE); + break; + case '4': + gcode << move_to(p0, writer, "Glyph: 4"); + gcode << writer.extrude_to_xy(p3, dE); + gcode << writer.extrude_to_xy(p2, dE); + gcode << move_to(p1, writer); + gcode << writer.extrude_to_xy(p5, two_dE); + break; + case '5': + gcode << move_to(p1, writer, "Glyph: 5"); + gcode << writer.extrude_to_xy(p0, dE); + gcode << writer.extrude_to_xy(p3, dE); + gcode << writer.extrude_to_xy(p2, dE); + gcode << writer.extrude_to_xy(p5, dE); + gcode << writer.extrude_to_xy(p4, dE); + break; + case '6': + gcode << move_to(p1, writer, "Glyph: 6"); + gcode << writer.extrude_to_xy(p0, dE); + gcode << writer.extrude_to_xy(p4, two_dE); + gcode << writer.extrude_to_xy(p5, dE); + gcode << writer.extrude_to_xy(p2, dE); + gcode << writer.extrude_to_xy(p3, dE); + break; + case '7': + gcode << move_to(p0, writer, "Glyph: 7"); + gcode << writer.extrude_to_xy(p1, dE); + gcode << writer.extrude_to_xy(p5, two_dE); + break; + case '8': + gcode << move_to(p2, writer, "Glyph: 8"); + gcode << writer.extrude_to_xy(p3, dE); + gcode << writer.extrude_to_xy(p4, dE); + gcode << writer.extrude_to_xy(p5, dE); + gcode << writer.extrude_to_xy(p1, two_dE); + gcode << writer.extrude_to_xy(p0, dE); + gcode << writer.extrude_to_xy(p3, dE); + break; + case '9': + gcode << move_to(p5, writer, "Glyph: 9"); + gcode << writer.extrude_to_xy(p1, two_dE); + gcode << writer.extrude_to_xy(p0, dE); + gcode << writer.extrude_to_xy(p3, dE); + gcode << writer.extrude_to_xy(p2, dE); + break; + case '.': + gcode << move_to(p4_5, writer, "Glyph: ."); + gcode << writer.extrude_to_xy(p4_5 + dot_direction, dE); + break; + default: + break; + } + + return gcode.str(); +} + +std::string CalibPressureAdvance::draw_number( + double startx, + double starty, + double value, + CalibPressureAdvance::DrawDigitMode mode, + double line_width, + double e_per_mm, + double speed, + GCodeWriter& writer +) +{ + auto sNumber = convert_number_to_string(value); + std::stringstream gcode; + gcode << writer.set_speed(speed); + + for (std::string::size_type i = 0; i < sNumber.length(); ++i) { + if (i > m_max_number_len) { break; } - - return gcode.str(); - } - // draw number - std::string calib_pressure_advance::draw_number(double startx, double starty, double value) { - double spacing = 3.0; - auto sNumber = std::to_string(value); - sNumber.erase(sNumber.find_last_not_of('0') + 1, std::string::npos); - sNumber.erase(sNumber.find_last_not_of('.') + 1, std::string::npos); - std::stringstream gcode; - gcode << mp_gcodegen->writer().set_speed(3600); - - - for (int i = 0; i < sNumber.length(); ++i) { - if (i > 5) + switch (mode) { + case DrawDigitMode::Bottom_To_Top: + gcode << draw_digit( + startx, + starty + i * number_spacing(), + sNumber[i], + mode, + line_width, + e_per_mm, + writer + ); break; - gcode << draw_digit(startx + i * spacing, starty, sNumber[i]); + default: + gcode << draw_digit( + startx + i * number_spacing(), + starty, + sNumber[i], + mode, + line_width, + e_per_mm, + writer + ); + } + } + return gcode.str(); +} + +std::string CalibPressureAdvanceLine::generate_test(double start_pa /*= 0*/, double step_pa /*= 0.002*/, int count /*= 10*/) +{ + BoundingBoxf bed_ext = get_extents(mp_gcodegen->config().printable_area.values); + if (is_delta()) { + CalibPressureAdvanceLine::delta_scale_bed_ext(bed_ext); + } + + auto bed_sizes = mp_gcodegen->config().printable_area.values; + const auto &w = bed_ext.size().x(); + const auto &h = bed_ext.size().y(); + count = std::min(count, int((h - 10) / m_space_y)); + + m_length_long = 40 + std::min(w - 120.0, 0.0); + + auto startx = (w - m_length_short * 2 - m_length_long - 20) / 2; + auto starty = (h - count * m_space_y) / 2; + if (is_delta()) { + CalibPressureAdvanceLine::delta_modify_start(startx, starty, count); + } + + return print_pa_lines(startx, starty, start_pa, step_pa, count); +} + +bool CalibPressureAdvanceLine::is_delta() const +{ + return mp_gcodegen->config().printable_area.values.size() > 4; +} + +std::string CalibPressureAdvanceLine::print_pa_lines(double start_x, double start_y, double start_pa, double step_pa, int num) +{ + auto& writer = mp_gcodegen->writer(); + const auto& config = mp_gcodegen->config(); + + const auto filament_diameter = config.filament_diameter.get_at(0); + const auto print_flow_ratio = config.print_flow_ratio; + + const double e_per_mm = CalibPressureAdvance::e_per_mm( + m_line_width, + m_height_layer, + m_nozzle_diameter, + filament_diameter, + print_flow_ratio + ); + const double thin_e_per_mm = CalibPressureAdvance::e_per_mm( + m_thin_line_width, + m_height_layer, + m_nozzle_diameter, + filament_diameter, + print_flow_ratio + ); + const double number_e_per_mm = CalibPressureAdvance::e_per_mm( + m_number_line_width, + m_height_layer, + m_nozzle_diameter, + filament_diameter, + print_flow_ratio + ); + + const double fast = CalibPressureAdvance::speed_adjust(m_fast_speed); + const double slow = CalibPressureAdvance::speed_adjust(m_slow_speed); + std::stringstream gcode; + gcode << mp_gcodegen->writer().travel_to_z(m_height_layer); + double y_pos = start_y; + + // prime line + auto prime_x = start_x - 2; + gcode << move_to(Vec2d(prime_x, y_pos + (num - 4) * m_space_y), writer); + gcode << writer.set_speed(slow); + gcode << writer.extrude_to_xy(Vec2d(prime_x, y_pos + 3 * m_space_y), e_per_mm * m_space_y * num * 1.1); + + for (int i = 0; i < num; ++i) { + gcode << writer.set_pressure_advance(start_pa + i * step_pa); + gcode << move_to(Vec2d(start_x, y_pos + i * m_space_y), writer); + gcode << writer.set_speed(slow); + gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short, y_pos + i * m_space_y), e_per_mm * m_length_short); + gcode << writer.set_speed(fast); + gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long, y_pos + i * m_space_y), e_per_mm * m_length_long); + gcode << writer.set_speed(slow); + gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long + m_length_short, y_pos + i * m_space_y), e_per_mm * m_length_short); + } + gcode << writer.set_pressure_advance(0.0); + + if (m_draw_numbers) { + // draw indicator lines + gcode << writer.set_speed(fast); + gcode << move_to(Vec2d(start_x + m_length_short, y_pos + (num - 1) * m_space_y + 2), writer); + gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short, y_pos + (num - 1) * m_space_y + 7), thin_e_per_mm * 7); + gcode << move_to(Vec2d(start_x + m_length_short + m_length_long, y_pos + (num - 1) * m_space_y + 7), writer); + gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long, y_pos + (num - 1) * m_space_y + 2), thin_e_per_mm * 7); + + for (int i = 0; i < num; i += 2) { + gcode << draw_number( + start_x + m_length_short + m_length_long + m_length_short + 3, + y_pos + i * m_space_y + m_space_y / 2, + start_pa + i * step_pa, + m_draw_digit_mode, + m_number_line_width, + number_e_per_mm, + 3600, + writer + ); + } + } + return gcode.str(); +} + +void CalibPressureAdvanceLine::delta_modify_start(double& startx, double& starty, int count) +{ + startx = -startx; + starty = -(count * m_space_y) / 2; +} + +CalibPressureAdvancePattern::CalibPressureAdvancePattern( + const Calib_Params& params, + const DynamicPrintConfig& config, + bool is_bbl_machine, + Model& model, + const Vec3d& origin +) : + m_params(params) +{ + this->m_draw_digit_mode = DrawDigitMode::Bottom_To_Top; + + refresh_setup(config, is_bbl_machine, model, origin); +}; + +void CalibPressureAdvancePattern::generate_custom_gcodes( + const DynamicPrintConfig& config, + bool is_bbl_machine, + Model& model, + const Vec3d& origin +) +{ + std::stringstream gcode; + gcode << "; start pressure advance pattern for layer\n"; + + refresh_setup(config, is_bbl_machine, model, origin); + + gcode << move_to(Vec2d(m_starting_point.x(), m_starting_point.y()), m_writer, "Move to start XY position"); + gcode << m_writer.travel_to_z(height_first_layer(), "Move to start Z position"); + gcode << m_writer.set_pressure_advance(m_params.start); + + const DrawBoxOptArgs default_box_opt_args(*this); + + // create anchoring frame + gcode << draw_box( + m_starting_point.x(), + m_starting_point.y(), + print_size_x(), + frame_size_y(), + default_box_opt_args + ); + + // create tab for numbers + DrawBoxOptArgs draw_box_opt_args = default_box_opt_args; + draw_box_opt_args.is_filled = true; + draw_box_opt_args.num_perimeters = wall_count(); + gcode << draw_box( + m_starting_point.x(), + m_starting_point.y() + frame_size_y() + line_spacing_first_layer(), + glyph_tab_max_x() - m_starting_point.x(), + max_numbering_height() + line_spacing_first_layer() + m_glyph_padding_vertical * 2, + draw_box_opt_args + ); + + std::vector gcode_items; + const DrawLineOptArgs default_line_opt_args(*this); + const int num_patterns = get_num_patterns(); // "cache" for use in loops + + // draw pressure advance pattern + for (int i = 0; i < m_num_layers; ++i) { + if (i > 0) { + gcode << "; end pressure advance pattern for layer\n"; + CustomGCode::Item item; + item.print_z = height_first_layer() + (i - 1) * height_layer(); + item.type = CustomGCode::Type::Custom; + item.extra = gcode.str(); + gcode_items.push_back(item); + + gcode = std::stringstream(); // reset for next layer contents + gcode << "; start pressure advance pattern for layer\n"; + + const double layer_height = height_first_layer() + (i * height_layer()); + gcode << m_writer.travel_to_z(layer_height, "Move to layer height"); } + // line numbering + if (i == 1) { + gcode << m_writer.set_pressure_advance(m_params.start); + + double number_e_per_mm = e_per_mm( + line_width(), + height_layer(), + m_config.option("nozzle_diameter")->get_at(0), + m_config.option("filament_diameter")->get_at(0), + m_config.option("filament_flow_ratio")->get_at(0) + ); + + // glyph on every other line + for (int j = 0; j < num_patterns; j += 2) { + gcode << draw_number( + glyph_start_x(j), + m_starting_point.y() + frame_size_y() + m_glyph_padding_vertical + line_width(), + m_params.start + (j * m_params.step), + m_draw_digit_mode, + line_width(), + number_e_per_mm, + speed_first_layer(), + m_writer + ); + } + } + + DrawLineOptArgs draw_line_opt_args = default_line_opt_args; + + double to_x = m_starting_point.x() + pattern_shift(); + double to_y = m_starting_point.y(); + double side_length = m_wall_side_length; + + // shrink first layer to fit inside frame + if (i == 0) { + double shrink = + ( + line_spacing_first_layer() * (wall_count() - 1) + + (line_width_first_layer() * (1 - m_encroachment)) + ) / std::sin(to_radians(m_corner_angle) / 2) + ; + side_length = m_wall_side_length - shrink; + to_x += shrink * std::sin(to_radians(90) - to_radians(m_corner_angle) / 2); + to_y += + line_spacing_first_layer() * (wall_count() - 1) + + (line_width_first_layer() * (1 - m_encroachment)) + ; + } + + double initial_x = to_x; + double initial_y = to_y; + + gcode << move_to(Vec2d(to_x, to_y), m_writer, "Move to pattern start"); + + for (int j = 0; j < num_patterns; ++j) { + // increment pressure advance + gcode << m_writer.set_pressure_advance(m_params.start + (j * m_params.step)); + + for (int k = 0; k < wall_count(); ++k) { + to_x += std::cos(to_radians(m_corner_angle) / 2) * side_length; + to_y += std::sin(to_radians(m_corner_angle) / 2) * side_length; + + draw_line_opt_args = default_line_opt_args; + draw_line_opt_args.height = i == 0 ? height_first_layer() : height_layer(); + draw_line_opt_args.line_width = line_width(); // don't use line_width_first_layer so results are consistent across all layers + draw_line_opt_args.speed = i == 0 ? speed_adjust(speed_first_layer()) : speed_adjust(speed_perimeter()); + draw_line_opt_args.comment = "Print pattern wall"; + gcode << draw_line(Vec2d(to_x, to_y), draw_line_opt_args); + + to_x -= std::cos(to_radians(m_corner_angle) / 2) * side_length; + to_y += std::sin(to_radians(m_corner_angle) / 2) * side_length; + + gcode << draw_line(Vec2d(to_x, to_y), draw_line_opt_args); + + to_y = initial_y; + if (k != wall_count() - 1) { + // perimeters not done yet. move to next perimeter + to_x += line_spacing_angle(); + gcode << move_to(Vec2d(to_x, to_y), m_writer, "Move to start next pattern wall"); + } else if (j != num_patterns - 1) { + // patterns not done yet. move to next pattern + to_x += m_pattern_spacing + line_width(); + gcode << move_to(Vec2d(to_x, to_y), m_writer, "Move to next pattern"); + } else if (i != m_num_layers - 1) { + // layers not done yet. move back to start + to_x = initial_x; + gcode << move_to(Vec2d(to_x, to_y), m_writer, "Move back to start position"); + } else { + // everything done + } + } + } + } + + gcode << m_writer.set_pressure_advance(m_params.start); + gcode << "; end pressure advance pattern for layer\n"; + + CustomGCode::Item item; + item.print_z = max_layer_z(); + item.type = CustomGCode::Type::Custom; + item.extra = gcode.str(); + gcode_items.push_back(item); + + CustomGCode::Info info; + info.mode = CustomGCode::Mode::SingleExtruder; + info.gcodes = gcode_items; + + model.plates_custom_gcodes[model.curr_plate_index] = info; +} + +void CalibPressureAdvancePattern::refresh_setup( + const DynamicPrintConfig& config, + bool is_bbl_machine, + const Model& model, + const Vec3d& origin +) +{ + m_config = config; + m_config.apply(model.objects.front()->config.get(), true); + m_config.apply(model.objects.front()->volumes.front()->config.get(), true); + + m_is_delta = (m_config.option("printable_area")->values.size() > 4); + + _refresh_starting_point(model); + _refresh_writer(is_bbl_machine, model, origin); +} + +void CalibPressureAdvancePattern::_refresh_starting_point(const Model& model) +{ + ModelObject* obj = model.objects.front(); + BoundingBoxf3 bbox = + obj->instance_bounding_box( + *obj->instances.front(), + false + ) + ; + + m_starting_point = Vec3d(bbox.min.x(), bbox.max.y(), 0); + m_starting_point.y() += m_handle_spacing; + + if (m_is_delta) { + m_starting_point.x() *= -1; + m_starting_point.y() -= (frame_size_y() / 2); + } +} + +void CalibPressureAdvancePattern::_refresh_writer( + bool is_bbl_machine, + const Model& model, + const Vec3d& origin +) +{ + PrintConfig print_config; + print_config.apply(m_config, true); + + m_writer.apply_print_config(print_config); + m_writer.set_xy_offset(origin(0), origin(1)); + m_writer.set_is_bbl_machine(is_bbl_machine); + + const unsigned int extruder_id = model.objects.front()->volumes.front()->extruder_id(); + m_writer.set_extruders({ extruder_id }); + m_writer.set_extruder(extruder_id); +} + +std::string CalibPressureAdvancePattern::draw_line( + Vec2d to_pt, + DrawLineOptArgs opt_args +) +{ + const double e_per_mm = CalibPressureAdvance::e_per_mm( + opt_args.line_width, + opt_args.height, + m_config.option("nozzle_diameter")->get_at(0), + m_config.option("filament_diameter")->get_at(0), + m_config.option("filament_flow_ratio")->get_at(0) + ); + + const double length = get_distance(Vec2d(m_last_pos.x(), m_last_pos.y()), to_pt); + auto dE = e_per_mm * length; + + std::stringstream gcode; + + gcode << m_writer.set_speed(opt_args.speed); + gcode << m_writer.extrude_to_xy(to_pt, dE, opt_args.comment); + + m_last_pos = Vec3d(to_pt.x(), to_pt.y(), 0); + + return gcode.str(); +} + +std::string CalibPressureAdvancePattern::draw_box( + double min_x, + double min_y, + double size_x, + double size_y, + DrawBoxOptArgs opt_args +) +{ + std::stringstream gcode; + + double x = min_x; + double y = min_y; + const double max_x = min_x + size_x; + const double max_y = min_y + size_y; + + const double spacing = opt_args.line_width - opt_args.height * (1 - M_PI / 4); + + // if number of perims exceeds size of box, reduce it to max + const int max_perimeters = + std::min( + // this is the equivalent of number of perims for concentric fill + std::floor(size_x * std::sin(to_radians(45))) / (spacing / std::sin(to_radians(45))), + std::floor(size_y * std::sin(to_radians(45))) / (spacing / std::sin(to_radians(45))) + ) + ; + + opt_args.num_perimeters = std::min(opt_args.num_perimeters, max_perimeters); + + gcode << move_to(Vec2d(min_x, min_y), m_writer, "Move to box start"); + + DrawLineOptArgs line_opt_args(*this); + line_opt_args.height = opt_args.height; + line_opt_args.line_width = opt_args.line_width; + line_opt_args.speed = opt_args.speed; + + for (int i = 0; i < opt_args.num_perimeters; ++i) { + if (i != 0) { // after first perimeter, step inwards to start next perimeter + x += spacing; + y += spacing; + gcode << move_to(Vec2d(x, y), m_writer, "Step inwards to print next perimeter"); + } + + y += size_y - i * spacing * 2; + line_opt_args.comment = "Draw perimeter (up)"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + + x += size_x - i * spacing * 2; + line_opt_args.comment = "Draw perimeter (right)"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + + y -= size_y - i * spacing * 2; + line_opt_args.comment = "Draw perimeter (down)"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + + x -= size_x - i * spacing * 2; + line_opt_args.comment = "Draw perimeter (left)"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + } + + if (!opt_args.is_filled) { return gcode.str(); } - Calib_Params::Calib_Params() : mode(CalibMode::Calib_None) {} + + // create box infill + const double spacing_45 = spacing / std::sin(to_radians(45)); + + const double bound_modifier = + (spacing * (opt_args.num_perimeters - 1)) + + (opt_args.line_width * (1 - m_encroachment)) + ; + const double x_min_bound = min_x + bound_modifier; + const double x_max_bound = max_x - bound_modifier; + const double y_min_bound = min_y + bound_modifier; + const double y_max_bound = max_y - bound_modifier; + const int x_count = std::floor((x_max_bound - x_min_bound) / spacing_45); + const int y_count = std::floor((y_max_bound - y_min_bound) / spacing_45); + + double x_remainder = std::fmod((x_max_bound - x_min_bound), spacing_45); + double y_remainder = std::fmod((y_max_bound - y_min_bound), spacing_45); + + x = x_min_bound; + y = y_min_bound; + + gcode << move_to(Vec2d(x, y), m_writer, "Move to fill start"); + + for (int i = 0; i < x_count + y_count + (x_remainder + y_remainder >= spacing_45 ? 1 : 0); ++i) { // this isn't the most robust way, but less expensive than finding line intersections + if (i < std::min(x_count, y_count)) { + if (i % 2 == 0) { + x += spacing_45; + y = y_min_bound; + gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step right"); + + y += x - x_min_bound; + x = x_min_bound; + line_opt_args.comment = "Fill: Print up/left"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + } else { + y += spacing_45; + x = x_min_bound; + gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step up"); + + x += y - y_min_bound; + y = y_min_bound; + line_opt_args.comment = "Fill: Print down/right"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + } + } else if (i < std::max(x_count, y_count)) { + if (x_count > y_count) { + // box is wider than tall + if (i % 2 == 0) { + x += spacing_45; + y = y_min_bound; + gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step right"); + + x -= y_max_bound - y_min_bound; + y = y_max_bound; + line_opt_args.comment = "Fill: Print up/left"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + } else { + if (i == y_count) { + x += spacing_45 - y_remainder; + y_remainder = 0; + } else { + x += spacing_45; + } + y = y_max_bound; + gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step right"); + + x += y_max_bound - y_min_bound; + y = y_min_bound; + line_opt_args.comment = "Fill: Print down/right"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + } + } else { + // box is taller than wide + if (i % 2 == 0) { + x = x_max_bound; + if (i == x_count) { + y += spacing_45 - x_remainder; + x_remainder = 0; + } else { + y += spacing_45; + } + gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step up"); + + x = x_min_bound; + y += x_max_bound - x_min_bound; + line_opt_args.comment = "Fill: Print up/left"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + } else { + x = x_min_bound; + y += spacing_45; + gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step up"); + + x = x_max_bound; + y -= x_max_bound - x_min_bound; + line_opt_args.comment = "Fill: Print down/right"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + } + } + } else { + if (i % 2 == 0) { + x = x_max_bound; + if (i == x_count) { + y += spacing_45 - x_remainder; + } else { + y += spacing_45; + } + gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step up"); + + x -= y_max_bound - y; + y = y_max_bound; + line_opt_args.comment = "Fill: Print up/left"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + } else { + if (i == y_count) { + x += spacing_45 - y_remainder; + } else { + x += spacing_45; + } + y = y_max_bound; + gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step right"); + + y -= x_max_bound - x; + x = x_max_bound; + line_opt_args.comment = "Fill: Print down/right"; + gcode << draw_line(Vec2d(x, y), line_opt_args); + } + } + } + + return gcode.str(); +} + +double CalibPressureAdvancePattern::get_distance(Vec2d from, Vec2d to) const +{ + return std::hypot((to.x() - from.x()), (to.y() - from.y())); +} + +double CalibPressureAdvancePattern::object_size_x() const +{ + return get_num_patterns() * ((wall_count() - 1) * line_spacing_angle()) + + (get_num_patterns() - 1) * (m_pattern_spacing + line_width()) + + std::cos(to_radians(m_corner_angle) / 2) * m_wall_side_length + + line_spacing_first_layer() * wall_count() + ; +} + +double CalibPressureAdvancePattern::object_size_y() const +{ + return 2 * (std::sin(to_radians(m_corner_angle) / 2) * m_wall_side_length) + + max_numbering_height() + + m_glyph_padding_vertical * 2 + + line_width_first_layer(); +} + +double CalibPressureAdvancePattern::glyph_start_x(int pattern_i) const +{ + // note that pattern_i is zero-based! + // align glyph's start with first perimeter of specified pattern + double x = + // starting offset + m_starting_point.x() + + pattern_shift() + + + // width of pattern extrusions + pattern_i * (wall_count() - 1) * line_spacing_angle() + // center to center distance of extrusions + pattern_i * line_width() + // endcaps. center to end on either side = 1 line width + + // space between each pattern + pattern_i * m_pattern_spacing + ; + + // align to middle of pattern walls + x += wall_count() * line_spacing_angle() / 2; + + // shift so glyph is centered on pattern + // m_digit_segment_len = half of X length of glyph + x -= (glyph_length_x() / 2); + + return x; +} + +double CalibPressureAdvancePattern::glyph_length_x() const +{ + // half of line_width sticks out on each side + return line_width() + (2 * m_digit_segment_len); +} + +double CalibPressureAdvancePattern::glyph_tab_max_x() const +{ + // only every other glyph is shown, starting with 1 + int num = get_num_patterns(); + int max_num = + (num % 2 == 0) + ? num - 1 + : num + ; + + // padding at end should be same as padding at start + double padding = glyph_start_x(0) - m_starting_point.x(); + + return + glyph_start_x(max_num - 1) + // glyph_start_x is zero-based + (glyph_length_x() - line_width() / 2) + + padding + ; +} + +double CalibPressureAdvancePattern::max_numbering_height() const +{ + std::string::size_type most_characters = 0; + const int num_patterns = get_num_patterns(); + + // note: only every other number is printed + for (std::string::size_type i = 0; i < num_patterns; i += 2) { + std::string sNumber = convert_number_to_string(m_params.start + (i * m_params.step)); + + if (sNumber.length() > most_characters) { + most_characters = sNumber.length(); + } + } + + most_characters = std::min(most_characters, m_max_number_len); + + return (most_characters * m_digit_segment_len) + ((most_characters - 1) * m_digit_gap_len); +} + +double CalibPressureAdvancePattern::pattern_shift() const +{ + return + (wall_count() - 1) * line_spacing_first_layer() + + line_width_first_layer() + + m_glyph_padding_horizontal + ; +} } // namespace Slic3r diff --git a/src/libslic3r/calib.hpp b/src/libslic3r/calib.hpp index 18cc583b62..11f797b19a 100644 --- a/src/libslic3r/calib.hpp +++ b/src/libslic3r/calib.hpp @@ -1,55 +1,274 @@ #pragma once #define calib_pressure_advance_dd -#include -#include "Point.hpp" -namespace Slic3r { +#include "GCode.hpp" +#include "GCodeWriter.hpp" +#include "PrintConfig.hpp" -class GCode; +namespace Slic3r { enum class CalibMode : int { Calib_None = 0, Calib_PA_Line, + Calib_PA_Pattern, Calib_PA_Tower, Calib_Temp_Tower, Calib_Vol_speed_Tower, Calib_VFA_Tower, Calib_Retraction_tower - }; -struct Calib_Params -{ - Calib_Params(); + +struct Calib_Params { + Calib_Params() : mode(CalibMode::Calib_None) { }; double start, end, step; bool print_numbers; CalibMode mode; }; -class calib_pressure_advance -{ +class CalibPressureAdvance { +protected: + CalibPressureAdvance() =default; + ~CalibPressureAdvance() =default; + + enum class DrawDigitMode { + Left_To_Right, + Bottom_To_Top + }; + + void delta_scale_bed_ext(BoundingBoxf& bed_ext) const { bed_ext.scale(1.0f / 1.41421f); } + + std::string move_to(Vec2d pt, GCodeWriter& writer, std::string comment = std::string()); + double e_per_mm( + double line_width, + double layer_height, + float nozzle_diameter, + float filament_diameter, + float print_flow_ratio + ) const; + double speed_adjust(int speed) const { return speed * 60; }; + + std::string convert_number_to_string(double num) const; + double number_spacing() const { return m_digit_segment_len + m_digit_gap_len; }; + std::string draw_digit( + double startx, + double starty, + char c, + CalibPressureAdvance::DrawDigitMode mode, + double line_width, + double e_per_mm, + GCodeWriter& writer + ); + std::string draw_number( + double startx, + double starty, + double value, + CalibPressureAdvance::DrawDigitMode mode, + double line_width, + double e_per_mm, + double speed, + GCodeWriter& writer + ); + + Vec3d m_last_pos; + + DrawDigitMode m_draw_digit_mode {DrawDigitMode::Left_To_Right}; + const double m_digit_segment_len {2}; + const double m_digit_gap_len {1}; + const std::string::size_type m_max_number_len {5}; +}; + +class CalibPressureAdvanceLine : public CalibPressureAdvance { public: - calib_pressure_advance(GCode* gcodegen); - ~calib_pressure_advance() {} + CalibPressureAdvanceLine(GCode* gcodegen) : + mp_gcodegen(gcodegen), + m_nozzle_diameter(gcodegen->config().nozzle_diameter.get_at(0)) + { }; + ~CalibPressureAdvanceLine() { }; std::string generate_test(double start_pa = 0, double step_pa = 0.002, int count = 50); - void set_speed(double fast = 100.0,double slow = 20.0) { + + void set_speed(double fast = 100.0, double slow = 20.0) { m_slow_speed = slow; m_fast_speed = fast; } - double& line_width() { return m_line_width; }; - bool& draw_numbers() { return m_draw_numbers; } + + const double& line_width() { return m_line_width; }; + bool is_delta() const; + bool& draw_numbers() { return m_draw_numbers; } private: - std::string move_to(Vec2d pt); std::string print_pa_lines(double start_x, double start_y, double start_pa, double step_pa, int num); - std::string draw_digit(double startx, double starty, char c); - std::string draw_number(double startx, double starty, double value); -private: + + void delta_modify_start(double& startx, double& starty, int count); + GCode* mp_gcodegen; - double m_length_short, m_length_long; - double m_space_y; + + double m_nozzle_diameter; double m_slow_speed, m_fast_speed; - double m_line_width; - bool m_draw_numbers; + + const double m_height_layer {0.2}; + const double m_line_width {0.6}; + const double m_thin_line_width {0.44}; + const double m_number_line_width {0.48}; + const double m_space_y {3.5}; + + double m_length_short {20.0}, m_length_long {40.0}; + bool m_draw_numbers {true}; +}; + +struct SuggestedCalibPressureAdvancePatternConfig { + const std::vector> float_pairs { + {"initial_layer_print_height", 0.25}, + {"layer_height", 0.2}, + {"initial_layer_speed", 30}, + {"outer_wall_speed", 100} + }; + + const std::vector> nozzle_ratio_pairs { + {"line_width", 112.5}, + {"initial_layer_line_width", 140} + }; + + const std::vector> int_pairs { + {"wall_loops", 3} + }; +}; + +class CalibPressureAdvancePattern : public CalibPressureAdvance { +friend struct DrawLineOptArgs; +friend struct DrawBoxOptArgs; + +public: + CalibPressureAdvancePattern( + const Calib_Params& params, + const DynamicPrintConfig& config, + bool is_bbl_machine, + Model& model, + const Vec3d& origin + ); + + double handle_xy_size() const { return m_handle_xy_size; }; + double handle_spacing() const { return m_handle_spacing; }; + double print_size_x() const { return object_size_x() + pattern_shift(); }; + double print_size_y() const { return object_size_y(); }; + double max_layer_z() const { return height_first_layer() + ((m_num_layers - 1) * height_layer()); }; + + void generate_custom_gcodes( + const DynamicPrintConfig& config, + bool is_bbl_machine, + Model& model, + const Vec3d& origin + ); + +protected: + double speed_first_layer() const { return m_config.option("initial_layer_speed")->value; }; + double speed_perimeter() const { return m_config.option("outer_wall_speed")->value; }; + double line_width_first_layer() const { return m_config.option("initial_layer_line_width")->value; }; + double line_width() const { return m_config.option("line_width")->value; }; + int wall_count() const { return m_config.option("wall_loops")->value; }; + +private: + struct DrawLineOptArgs { + DrawLineOptArgs(const CalibPressureAdvancePattern& p) : + height {p.height_layer()}, + line_width {p.line_width()}, + speed {p.speed_adjust(p.speed_perimeter())} + { }; + + double height; + double line_width; + double speed; + std::string comment {"Print line"}; + }; + + struct DrawBoxOptArgs { + DrawBoxOptArgs(const CalibPressureAdvancePattern& p) : + num_perimeters {p.wall_count()}, + height {p.height_first_layer()}, + line_width {p.line_width_first_layer()}, + speed {p.speed_adjust(p.speed_first_layer())} + { }; + + bool is_filled {false}; + int num_perimeters; + double height; + double line_width; + double speed; + }; + + void refresh_setup( + const DynamicPrintConfig& config, + bool is_bbl_machine, + const Model& model, + const Vec3d& origin + ); + void _refresh_starting_point(const Model& model); + void _refresh_writer( + bool is_bbl_machine, + const Model& model, + const Vec3d& origin + ); + + double height_first_layer() const { return m_config.option("initial_layer_print_height")->value; }; + double height_layer() const { return m_config.option("layer_height")->value; }; + const int get_num_patterns() const + { + return std::ceil((m_params.end - m_params.start) / m_params.step + 1); + } + + std::string draw_line( + Vec2d to_pt, + DrawLineOptArgs opt_args + ); + std::string draw_box( + double min_x, + double min_y, + double size_x, + double size_y, + DrawBoxOptArgs opt_args + ); + + double to_radians(double degrees) const { return degrees * M_PI / 180; }; + double get_distance(Vec2d from, Vec2d to) const; + + /* + from slic3r documentation: spacing = extrusion_width - layer_height * (1 - PI/4) + "spacing" = center-to-center distance of adjacent extrusions, which partially overlap + https://manual.slic3r.org/advanced/flow-math + https://ellis3dp.com/Print-Tuning-Guide/articles/misconceptions.html#two-04mm-perimeters--08mm + */ + double line_spacing() const { return line_width() - height_layer() * (1 - M_PI / 4); }; + double line_spacing_first_layer() const { return line_width_first_layer() - height_first_layer() * (1 - M_PI / 4); }; + double line_spacing_angle() const { return line_spacing() / std::sin(to_radians(m_corner_angle) / 2); }; + + double object_size_x() const; + double object_size_y() const; + double frame_size_y() const { return std::sin(to_radians(double(m_corner_angle) / 2)) * m_wall_side_length * 2; }; + + double glyph_start_x(int pattern_i = 0) const; + double glyph_length_x() const; + double glyph_tab_max_x() const; + double max_numbering_height() const; + + double pattern_shift() const; + + const Calib_Params& m_params; + + DynamicPrintConfig m_config; + GCodeWriter m_writer; + bool m_is_delta; + Vec3d m_starting_point; + + const double m_handle_xy_size {5}; + const double m_handle_spacing {2}; + const int m_num_layers {4}; + + const double m_wall_side_length {30.0}; + const int m_corner_angle {90}; + const int m_pattern_spacing {2}; + const double m_encroachment {1. / 3.}; + + const double m_glyph_padding_horizontal {1}; + const double m_glyph_padding_vertical {1}; }; } // namespace Slic3r diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 29c636efbb..49be6b4e34 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -738,7 +738,7 @@ void Preview::load_print_as_fff(bool keep_z_range, bool only_gcode) unsigned int number_extruders = wxGetApp().is_editor() ? (unsigned int)print->extruders().size() : m_canvas->get_gcode_extruders_count(); - std::vector gcodes = wxGetApp().is_editor() ? + std::vector gcodes = wxGetApp().is_editor() ? //BBS wxGetApp().plater()->model().get_curr_plate_custom_gcodes().gcodes : m_canvas->get_custom_gcode_per_print_z(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0801ca19b9..a4b135b0f4 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1,4 +1,5 @@ #include "Plater.hpp" + #include #include #include @@ -100,6 +101,7 @@ #include "MsgDialog.hpp" #include "ProjectDirtyStateManager.hpp" #include "Gizmos/GLGizmoSimplify.hpp" // create suggestion notification +#include "Gizmos/GizmoObjectManipulation.hpp" // BBS #include "Widgets/ProgressDialog.hpp" @@ -8100,60 +8102,165 @@ std::array get_cut_plane(const BoundingBoxf3& bbox, const double& cut_ return plane_pts; } -void Plater::calib_pa(const Calib_Params& params) { - +void Plater::calib_pa(const Calib_Params& params) +{ const auto calib_pa_name = wxString::Format(L"Pressure Advance Test"); new_project(false, false, calib_pa_name); wxGetApp().mainframe->select_tab(size_t(MainFrame::tp3DEditor)); - if (params.mode == CalibMode::Calib_PA_Line) { - add_model(false, Slic3r::resources_dir() + "/calib/PressureAdvance/pressure_advance_test.stl"); + + switch (params.mode) { + case CalibMode::Calib_PA_Line: + add_model(false, Slic3r::resources_dir() + "/calib/PressureAdvance/pressure_advance_test.stl"); + break; + case CalibMode::Calib_PA_Pattern: + _calib_pa_pattern(params); + break; + case CalibMode::Calib_PA_Tower: + _calib_pa_tower(params); + break; + default: break; } - else { - add_model(false, Slic3r::resources_dir() + "/calib/PressureAdvance/tower_with_seam.stl"); - 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)); - if(print_config->option>("wall_generator")->value == PerimeterGeneratorType::Arachne) - print_config->set_key_value("wall_transition_angle", new ConfigOptionFloat(25)); - 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(); - wxGetApp().get_tab(Preset::TYPE_PRINTER)->update_dirty(); - wxGetApp().get_tab(Preset::TYPE_PRINT)->reload_config(); - wxGetApp().get_tab(Preset::TYPE_FILAMENT)->reload_config(); - wxGetApp().get_tab(Preset::TYPE_PRINTER)->reload_config(); - - auto new_height = std::ceil((params.end - params.start) / params.step) + 1; - auto obj_bb = model().objects[0]->bounding_box(); - if (new_height < obj_bb.size().z()) { - std::array plane_pts = get_cut_plane(obj_bb, new_height); - cut(0, 0, plane_pts, ModelObjectCutAttribute::KeepLower); - } - - // 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()->set_calib_params(params); +} +void Plater::_calib_pa_pattern(const Calib_Params& params) +{ + // add "handle" cube + sidebar().obj_list()->load_generic_subobject("Cube", ModelVolumeType::INVALID); + orient(); + changed_objects({ 0 }); + _calib_pa_select_added_objects(); + const DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; + DynamicPrintConfig& print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; + + for (const auto opt : SuggestedCalibPressureAdvancePatternConfig().float_pairs) { + print_config.set_key_value( + opt.first, + new ConfigOptionFloat(opt.second) + ); + } + + for (const auto opt : SuggestedCalibPressureAdvancePatternConfig().nozzle_ratio_pairs) { + double nozzle_diameter = printer_config.option("nozzle_diameter")->get_at(0); + print_config.set_key_value( + opt.first, + new ConfigOptionFloat(nozzle_diameter * opt.second / 100) + ); + } + + for (const auto opt : SuggestedCalibPressureAdvancePatternConfig().int_pairs) { + print_config.set_key_value( + opt.first, + new ConfigOptionInt(opt.second) + ); + } + + wxGetApp().get_tab(Preset::TYPE_PRINT)->update_dirty(); + wxGetApp().get_tab(Preset::TYPE_PRINT)->reload_config(); + + const DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config(); + PresetBundle* preset_bundle = wxGetApp().preset_bundle; + const bool is_bbl_machine = preset_bundle->printers.get_edited_preset().is_bbl_vendor_preset(preset_bundle); + const Vec3d plate_origin = get_partplate_list().get_current_plate_origin(); + CalibPressureAdvancePattern pa_pattern( + params, + full_config, + is_bbl_machine, + model(), + plate_origin + ); + + // scale cube to suit test + GizmoObjectManipulation& giz_obj_manip = p->view3D->get_canvas3d()-> + get_gizmos_manager().get_object_manipulation(); + giz_obj_manip.set_uniform_scaling(true); + giz_obj_manip.on_change( + "size", + 0, + pa_pattern.handle_xy_size() + ); + giz_obj_manip.set_uniform_scaling(false); + giz_obj_manip.on_change( + "size", + 2, + pa_pattern.max_layer_z() + ); + // start with pattern centered on plate + center_selection(); + const Vec3d plate_center = get_partplate_list().get_curr_plate()->get_center_origin(); + giz_obj_manip.on_change( + "position", + 0, + plate_center.x() - (pa_pattern.print_size_x() / 2) + ); + giz_obj_manip.on_change( + "position", + 1, + plate_center.y() - + (pa_pattern.print_size_y() / 2) - + pa_pattern.handle_spacing() + ); + + pa_pattern.generate_custom_gcodes( + full_config, + is_bbl_machine, + model(), + plate_origin + ); + model().calib_pa_pattern = std::make_unique(pa_pattern); + changed_objects({ 0 }); +} + +void Plater::_calib_pa_tower(const Calib_Params& params) { + add_model(false, Slic3r::resources_dir() + "/calib/PressureAdvance/tower_with_seam.stl"); + + 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)); + if(print_config->option>("wall_generator")->value == PerimeterGeneratorType::Arachne) + print_config->set_key_value("wall_transition_angle", new ConfigOptionFloat(25)); + 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(); + wxGetApp().get_tab(Preset::TYPE_PRINTER)->update_dirty(); + wxGetApp().get_tab(Preset::TYPE_PRINT)->reload_config(); + wxGetApp().get_tab(Preset::TYPE_FILAMENT)->reload_config(); + wxGetApp().get_tab(Preset::TYPE_PRINTER)->reload_config(); + + auto new_height = std::ceil((params.end - params.start) / params.step) + 1; + auto obj_bb = model().objects[0]->bounding_box(); + if (new_height < obj_bb.size().z()) { + std::array plane_pts = get_cut_plane(obj_bb, new_height); + cut(0, 0, plane_pts, ModelObjectCutAttribute::KeepLower); + } + + _calib_pa_select_added_objects(); +} + +void Plater::_calib_pa_select_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(); + } } void Plater::calib_flowrate(int pass) { @@ -8243,7 +8350,6 @@ void Plater::calib_flowrate(int pass) { wxGetApp().get_tab(Preset::TYPE_PRINT)->reload_config(); wxGetApp().get_tab(Preset::TYPE_FILAMENT)->reload_config(); wxGetApp().get_tab(Preset::TYPE_PRINTER)->reload_config(); - } void Plater::calib_temp(const Calib_Params& params) { @@ -10260,6 +10366,18 @@ void Plater::reslice() // Stop arrange and (or) optimize rotation tasks. this->stop_jobs(); + // regenerate CalibPressureAdvancePattern custom G-code to apply changes + if (model().calib_pa_pattern) { + PresetBundle* preset_bundle = wxGetApp().preset_bundle; + + model().calib_pa_pattern->generate_custom_gcodes( + wxGetApp().preset_bundle->full_config(), + preset_bundle->printers.get_edited_preset().is_bbl_vendor_preset(preset_bundle), + model(), + get_partplate_list().get_current_plate_origin() + ); + } + if (printer_technology() == ptSLA) { for (auto& object : model().objects) if (object->sla_points_status == sla::PointsStatus::NoPoints) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 33ea0e7b20..a1ba2e827b 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -727,6 +727,10 @@ private: // BBS: add project slice related functions int start_next_slice(); + void _calib_pa_pattern(const Calib_Params& params); + void _calib_pa_tower(const Calib_Params& params); + void _calib_pa_select_added_objects(); + friend class SuppressBackgroundProcessingUpdate; }; diff --git a/src/slic3r/GUI/calib_dlg.cpp b/src/slic3r/GUI/calib_dlg.cpp index d08c8b3a01..2d0b9c1bec 100644 --- a/src/slic3r/GUI/calib_dlg.cpp +++ b/src/slic3r/GUI/calib_dlg.cpp @@ -46,7 +46,7 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater* m_rbExtruderType->SetSelection(0); choice_sizer->Add(m_rbExtruderType, 0, wxALL, 5); choice_sizer->Add(FromDIP(5), 0, 0, wxEXPAND, 5); - wxString m_rbMethodChoices[] = { _L("PA Tower"), _L("PA Line") }; + wxString m_rbMethodChoices[] = { _L("PA Tower"), _L("PA Line"), _L("PA Pattern") }; int m_rbMethodNChoices = sizeof(m_rbMethodChoices) / sizeof(wxString); m_rbMethod = new wxRadioBox(this, wxID_ANY, _L("Method"), wxDefaultPosition, wxDefaultSize, m_rbMethodNChoices, m_rbMethodChoices, 2, wxRA_SPECIFY_COLS); m_rbMethod->SetSelection(0); @@ -70,7 +70,7 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater* // start PA auto start_PA_sizer = new wxBoxSizer(wxHORIZONTAL); auto start_pa_text = new wxStaticText(this, wxID_ANY, start_pa_str, wxDefaultPosition, st_size, wxALIGN_LEFT); - m_tiStartPA = new TextInput(this, wxString::FromDouble(0.0), "", "", wxDefaultPosition, ti_size, wxTE_CENTRE | wxTE_PROCESS_ENTER); + m_tiStartPA = new TextInput(this, "", "", "", wxDefaultPosition, ti_size, wxTE_CENTRE | wxTE_PROCESS_ENTER); m_tiStartPA->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); start_PA_sizer->Add(start_pa_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); @@ -80,7 +80,7 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater* // end PA auto end_PA_sizer = new wxBoxSizer(wxHORIZONTAL); auto end_pa_text = new wxStaticText(this, wxID_ANY, end_pa_str, wxDefaultPosition, st_size, wxALIGN_LEFT); - m_tiEndPA = new TextInput(this, wxString::FromDouble(0.1), "", "", wxDefaultPosition, ti_size, wxTE_CENTRE | wxTE_PROCESS_ENTER); + m_tiEndPA = new TextInput(this, "", "", "", wxDefaultPosition, ti_size, wxTE_CENTRE | wxTE_PROCESS_ENTER); m_tiStartPA->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); end_PA_sizer->Add(end_pa_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); end_PA_sizer->Add(m_tiEndPA, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); @@ -89,7 +89,7 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater* // PA step auto PA_step_sizer = new wxBoxSizer(wxHORIZONTAL); auto PA_step_text = new wxStaticText(this, wxID_ANY, PA_step_str, wxDefaultPosition, st_size, wxALIGN_LEFT); - m_tiPAStep = new TextInput(this, wxString::FromDouble(0.002), "", "", wxDefaultPosition, ti_size, wxTE_CENTRE | wxTE_PROCESS_ENTER); + m_tiPAStep = new TextInput(this, "", "", "", wxDefaultPosition, ti_size, wxTE_CENTRE | wxTE_PROCESS_ENTER); m_tiStartPA->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); PA_step_sizer->Add(PA_step_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); PA_step_sizer->Add(m_tiPAStep, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); @@ -114,6 +114,8 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater* m_btnStart->Bind(wxEVT_BUTTON, &PA_Calibration_Dlg::on_start, this); v_sizer->Add(m_btnStart, 0, wxALL | wxALIGN_RIGHT, FromDIP(5)); + PA_Calibration_Dlg::reset_params(); + // Connect Events m_rbExtruderType->Connect(wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler(PA_Calibration_Dlg::on_extruder_type_changed), NULL, this); m_rbMethod->Connect(wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler(PA_Calibration_Dlg::on_method_changed), NULL, this); @@ -131,6 +133,47 @@ PA_Calibration_Dlg::~PA_Calibration_Dlg() { m_btnStart->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PA_Calibration_Dlg::on_start), NULL, this); } +void PA_Calibration_Dlg::reset_params() { + bool isDDE = m_rbExtruderType->GetSelection() == 0 ? true : false; + int method = m_rbMethod->GetSelection(); + + m_tiStartPA->GetTextCtrl()->SetValue(wxString::FromDouble(0.0)); + + switch (method) { + case 1: + m_params.mode = CalibMode::Calib_PA_Line; + m_tiEndPA->GetTextCtrl()->SetValue(wxString::FromDouble(0.1)); + m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.002)); + m_cbPrintNum->SetValue(true); + m_cbPrintNum->Enable(true); + break; + case 2: + m_params.mode = CalibMode::Calib_PA_Pattern; + m_tiEndPA->GetTextCtrl()->SetValue(wxString::FromDouble(0.08)); + m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.005)); + m_cbPrintNum->SetValue(true); + m_cbPrintNum->Enable(false); + break; + default: + m_params.mode = CalibMode::Calib_PA_Tower; + m_tiEndPA->GetTextCtrl()->SetValue(wxString::FromDouble(0.1)); + m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.002)); + m_cbPrintNum->SetValue(false); + m_cbPrintNum->Enable(false); + break; + } + + if (!isDDE) { + m_tiEndPA->GetTextCtrl()->SetValue(wxString::FromDouble(1.0)); + + if (m_params.mode == CalibMode::Calib_PA_Pattern) { + m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.05)); + } else { + m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.02)); + } + } +} + void PA_Calibration_Dlg::on_start(wxCommandEvent& event) { bool read_double = false; read_double = m_tiStartPA->GetTextCtrl()->GetValue().ToDouble(&m_params.start); @@ -141,7 +184,18 @@ void PA_Calibration_Dlg::on_start(wxCommandEvent& event) { msg_dlg.ShowModal(); return; } - m_params.mode = m_rbMethod->GetSelection() == 0 ? CalibMode::Calib_PA_Tower : CalibMode::Calib_PA_Line; + + switch (m_rbMethod->GetSelection()) { + case 1: + m_params.mode = CalibMode::Calib_PA_Line; + break; + case 2: + m_params.mode = CalibMode::Calib_PA_Pattern; + break; + default: + m_params.mode = CalibMode::Calib_PA_Tower; + } + m_params.print_numbers = m_cbPrintNum->GetValue(); m_plater->calib_pa(m_params); @@ -149,41 +203,21 @@ void PA_Calibration_Dlg::on_start(wxCommandEvent& event) { } void PA_Calibration_Dlg::on_extruder_type_changed(wxCommandEvent& event) { - int selection = event.GetSelection(); - m_bDDE = selection == 0 ? true : false; - m_tiEndPA->GetTextCtrl()->SetValue(wxString::FromDouble(m_bDDE ? 0.1 : 1.0)); - m_tiStartPA->GetTextCtrl()->SetValue(wxString::FromDouble(0.0)); - m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(m_bDDE ? 0.002 : 0.02)); + PA_Calibration_Dlg::reset_params(); event.Skip(); } void PA_Calibration_Dlg::on_method_changed(wxCommandEvent& event) { - int selection = event.GetSelection(); - m_params.mode = selection == 0 ? CalibMode::Calib_PA_Tower : CalibMode::Calib_PA_Line; - if (selection == 0) { - m_cbPrintNum->SetValue(false); - m_cbPrintNum->Enable(false); - } - else { - m_cbPrintNum->SetValue(true); - m_cbPrintNum->Enable(true); - } - + PA_Calibration_Dlg::reset_params(); event.Skip(); } - void PA_Calibration_Dlg::on_dpi_changed(const wxRect& suggested_rect) { this->Refresh(); Fit(); - } void PA_Calibration_Dlg::on_show(wxShowEvent& event) { - - if (m_rbMethod->GetSelection() == 0) - m_cbPrintNum->Enable(false); - else - m_cbPrintNum->Enable(true); + PA_Calibration_Dlg::reset_params(); } // Temp Calib dlg diff --git a/src/slic3r/GUI/calib_dlg.hpp b/src/slic3r/GUI/calib_dlg.hpp index b1bf8d8616..cd2e35b14b 100644 --- a/src/slic3r/GUI/calib_dlg.hpp +++ b/src/slic3r/GUI/calib_dlg.hpp @@ -25,6 +25,7 @@ public: void on_dpi_changed(const wxRect& suggested_rect) override; void on_show(wxShowEvent& event); protected: + void reset_params(); virtual void on_start(wxCommandEvent& event); virtual void on_extruder_type_changed(wxCommandEvent& event); virtual void on_method_changed(wxCommandEvent& event);