diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index cf3d2022dc0..1bc140789ac 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3108,6 +3108,24 @@ double cap_speed( return speed; } +// https://arachnoid.com/polysolve/ +double GCodeGenerator::_regress(double x) { + double terms[3]; + + int extr_id = this->m_writer.extruder()->id(); + terms[0] = m_writer.config.extrusion_regression_c.get_at(extr_id); + terms[1] = m_writer.config.extrusion_regression_b.get_at(extr_id); + terms[2] = m_writer.config.extrusion_regression_a.get_at(extr_id); + + double t = 1; + double r = 0; + for (double c : terms) { + r += c * t; + t *= x; + } + return r; +} + std::string GCodeGenerator::_extrude( const ExtrusionAttributes &path_attr, const Geometry::ArcWelder::Path &path, @@ -3332,15 +3350,37 @@ std::string GCodeGenerator::_extrude( } if (radius == 0) { // Extrude line segment. - if (const double line_length = (p - prev).norm(); line_length > 0) - gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); + if (const double line_length = (p - prev).norm(); line_length > 0) { + + double dE = e_per_mm * line_length; + double tm = line_length/speed; + double k = _regress(dE / tm); + std::string ln = m_writer.extrude_to_xy(p, dE * k, comment); + + if (k > 1) { + std::string ee = (!this->config().extrusion_regression_show ? ";_K_" : ";K:") + std::to_string(std::round(k * 1000000) / 1000000) + "\n"; + int i = ln.find("\n"); + ln = ln.replace(i, strlen("\n"),ee); + } + gcode += ln; + } } else { double angle = Geometry::ArcWelder::arc_angle(prev.cast(), p.cast(), double(radius)); assert(angle > 0); const double line_length = angle * std::abs(radius); const double dE = e_per_mm * line_length; assert(dE > 0); - gcode += m_writer.extrude_to_xy_G2G3IJ(p, ij, it->ccw(), dE, comment); + + double tm = line_length/speed; + double k = _regress(dE / (line_length/speed)); + std::string ln = m_writer.extrude_to_xy_G2G3IJ(p, ij, it->ccw(), dE * k, comment); + + if (k > 1 && !this->config().extrusion_regression_show) { + std::string ee = (!this->config().extrusion_regression_show ? ";_K_" : ";K:") + std::to_string(std::round(k * 1000000) / 1000000) + "\n"; + int i = ln.find("\n"); + ln = ln.replace(i, strlen("\n"),ee); + } + gcode += ln; } prev = p; prev_exact = p_exact; diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 97b36958593..925d4275a6b 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -454,6 +454,7 @@ class GCodeGenerator { // Back-pointer to Print (const). const Print* m_print; + double _regress(double x); std::string _extrude( const ExtrusionAttributes &attribs, const Geometry::ArcWelder::Path &path, const std::string_view description, double speed = -1); void print_machine_envelope(GCodeOutputStream &file, const Print &print); diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index a602a77de4a..67362f66ab8 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -2551,14 +2551,26 @@ void GCodeProcessor::process_G0(const GCodeReader::GCodeLine& line) { process_G1(line); } - +#pragma optimize("",off) void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) { std::array, 4> g1_axes = { std::nullopt, std::nullopt, std::nullopt, std::nullopt }; if (line.has_x()) g1_axes[X] = (double)line.x(); if (line.has_y()) g1_axes[Y] = (double)line.y(); if (line.has_z()) g1_axes[Z] = (double)line.z(); - if (line.has_e()) g1_axes[E] = (double)line.e(); + if (line.has_e()){ + + std::string_view cmnt = line.comment(); + g1_axes[E] = (double)line.e(); + int st = cmnt.find("_K_"); + if (st >= 0) { + st += 3; + int eol = cmnt.find("\n"); + std::string es(cmnt.substr(st, eol)); + double k = atof(es.c_str()); + g1_axes[E] = g1_axes[E].value() / k ; + } + } std::optional g1_feedrate = std::nullopt; if (line.has_f()) g1_feedrate = (double)line.f(); process_G1(g1_axes, g1_feedrate); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 8be5a3f45f6..ef426ec580d 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -481,6 +481,7 @@ static std::vector s_Preset_filament_options { "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower", "filament_multitool_ramming", "filament_multitool_ramming_volume", "filament_multitool_ramming_flow", + "extrusion_regression_a", "extrusion_regression_b", "extrusion_regression_c", "extrusion_regression_show", "temperature", "idle_temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", "start_filament_gcode", "end_filament_gcode", "enable_dynamic_fan_speeds", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index f69720d6d6a..3e864c40e41 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -109,6 +109,10 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "extruder_colour", "extruder_offset", "extrusion_multiplier", + "extrusion_regression_a", + "extrusion_regression_b", + "extrusion_regression_c", + "extrusion_regression_show", "fan_always_on", "fan_below_layer_time", "full_fan_speed_layer", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 4404aea7beb..cda96e2be59 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -995,6 +995,34 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloats { 1. }); + def = this->add("extrusion_regression_a", coFloats); + def->label = L("A factor"); + def->tooltip = L("A factor (X^2) of quadratic polynomial"); + def->sidetext = L("*X^2"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 0. }); + + def = this->add("extrusion_regression_b", coFloats); + def->label = L("B factor"); + def->tooltip = L("B factor (X) of quadratic polynomial"); + def->sidetext = L("*X+"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 0. }); + + def = this->add("extrusion_regression_c", coFloats); + def->label = L("C factor"); + def->tooltip = L("C factor (constant) of quadratic polynomial"); + def->sidetext = L("+"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats { 1. }); + + def = this->add("extrusion_regression_show", coBool); + def->label = L("Show commanded extrusion"); + def->tooltip = L("Show extrusion amount that was sent to extruder motor. " + "It exceeds expected amount to compensate underextrusion caused by gear slippage."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool { false }); + def = this->add("extrusion_width", coFloatOrPercent); def->label = L("Default extrusion width"); def->category = L("Extrusion Width"); @@ -3515,6 +3543,7 @@ void PrintConfigDef::init_extruder_option_keys() // ConfigOptionFloats, ConfigOptionPercents, ConfigOptionBools, ConfigOptionStrings m_extruder_option_keys = { "nozzle_diameter", "min_layer_height", "max_layer_height", "extruder_offset", + "extrusion_regression_a", "extrusion_regression_b", "extrusion_regression_c","extrusion_regression_show", "retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_before_wipe", "retract_restart_extra", "retract_before_travel", "wipe", "travel_slope", "travel_max_lift", "travel_ramping_lift", "travel_lift_before_obstacle", diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index f1dc6b96a43..97fb8cde51c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -749,6 +749,10 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloats, travel_max_lift)) ((ConfigOptionFloats, travel_slope)) ((ConfigOptionBools, travel_lift_before_obstacle)) + ((ConfigOptionFloats, extrusion_regression_a))//x^2 + ((ConfigOptionFloats, extrusion_regression_b))//x + ((ConfigOptionFloats, extrusion_regression_c))//c + ((ConfigOptionBool, extrusion_regression_show)) ((ConfigOptionPercents, retract_before_wipe)) ((ConfigOptionFloats, retract_length)) ((ConfigOptionFloats, retract_length_toolchange)) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c0a232e85da..50fb4cf877a 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2255,6 +2255,12 @@ void TabFilament::build() }; optgroup->append_line(line); + optgroup = page->new_optgroup(L("Non-linear extrusion")); + optgroup->append_single_option_line("extrusion_regression_c"); + optgroup->append_single_option_line("extrusion_regression_b"); + optgroup->append_single_option_line("extrusion_regression_a"); + optgroup->append_single_option_line("extrusion_regression_show"); + optgroup = page->new_optgroup(L("Wipe tower parameters")); optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower");