Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 77 additions & 7 deletions src/libslic3r/GCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,68 @@ Vec2d travel_point_1;
Vec2d travel_point_2;
Vec2d travel_point_3;

// Calculate pressure advance value based on nozzle diameter from string format:
// "nozzle_diameter,pa_value\n..." or single value for legacy compatibility
static double calculate_pressure_advance_for_nozzle(const std::string& pa_string, double nozzle_diameter)
{
if (pa_string.empty()) return 0.0;

// Remove all whitespace characters for simpler parsing
std::string clean_string = pa_string;
clean_string.erase(std::remove_if(clean_string.begin(), clean_string.end(),
[](char c) { return std::isspace(c); }), clean_string.end());

// Legacy format: single value without comma
if (clean_string.find(',') == std::string::npos) {
try { return std::stod(clean_string); } catch (...) { return 0.0; }
}

// Parse nozzle,pa pairs
std::vector<std::pair<double, double>> pa_values;

for (size_t start = 0, end; start < clean_string.length(); start = end + 1) {
end = clean_string.find('\n', start);
if (end == std::string::npos) end = clean_string.length();
if (end <= start) continue;

size_t comma = clean_string.find(',', start);
if (comma != std::string::npos && comma < end) {
try {
pa_values.emplace_back(std::stod(clean_string.substr(start, comma - start)),
std::stod(clean_string.substr(comma + 1, end - comma - 1)));
} catch (...) { /* Skip invalid lines */ }
}
if (end == clean_string.length()) break;
}

if (pa_values.empty()) return 0.0;
std::sort(pa_values.begin(), pa_values.end());

// Handle all cases in one pass: exact match, boundaries, and interpolation
for (size_t i = 0; i < pa_values.size(); ++i) {
auto& [nozzle, pa] = pa_values[i];

// Exact match
if (std::abs(nozzle - nozzle_diameter) < 0.001) return pa;

// Below first value
if (i == 0 && nozzle_diameter < nozzle) return pa;

// Above last value
if (i == pa_values.size() - 1 && nozzle_diameter > nozzle) return pa;

// Interpolation range found
if (i < pa_values.size() - 1 && nozzle_diameter > nozzle) {
auto& [next_nozzle, next_pa] = pa_values[i + 1];
if (nozzle_diameter <= next_nozzle) {
return pa + (next_pa - pa) * (nozzle_diameter - nozzle) / (next_nozzle - nozzle);
}
}
}

return 0.0;
}

static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
{
// give safe value in case there is no start_end_points in config
Expand Down Expand Up @@ -665,10 +727,10 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)

// SoftFever: set new PA for new filament
if (gcodegen.config().enable_pressure_advance.get_at(new_extruder_id)) {
gcode += gcodegen.writer().set_pressure_advance(gcodegen.config().pressure_advance.get_at(new_extruder_id));
gcode += gcodegen.writer().set_pressure_advance(gcodegen.get_pressure_advance_for_extruder(new_extruder_id));
// Orca: Adaptive PA
// Reset Adaptive PA processor last PA value
gcodegen.m_pa_processor->resetPreviousPA(gcodegen.config().pressure_advance.get_at(new_extruder_id));
gcodegen.m_pa_processor->resetPreviousPA(gcodegen.get_pressure_advance_for_extruder(new_extruder_id));
}

// A phony move to the end position at the wipe tower.
Expand Down Expand Up @@ -794,10 +856,10 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)

// SoftFever: set new PA for new filament
if (new_extruder_id != -1 && gcodegen.config().enable_pressure_advance.get_at(new_extruder_id)) {
gcode += gcodegen.writer().set_pressure_advance(gcodegen.config().pressure_advance.get_at(new_extruder_id));
gcode += gcodegen.writer().set_pressure_advance(gcodegen.get_pressure_advance_for_extruder(new_extruder_id));
// Orca: Adaptive PA
// Reset Adaptive PA processor last PA value
gcodegen.m_pa_processor->resetPreviousPA(gcodegen.config().pressure_advance.get_at(new_extruder_id));
gcodegen.m_pa_processor->resetPreviousPA(gcodegen.get_pressure_advance_for_extruder(new_extruder_id));
}

// A phony move to the end position at the wipe tower.
Expand Down Expand Up @@ -6010,6 +6072,14 @@ std::string GCode::extrusion_role_to_string_for_parser(const ExtrusionRole & rol
}
}

// Calculate the correct pressure advance value based on nozzle diameter
double GCode::get_pressure_advance_for_extruder(unsigned int extruder_id) const
{
const std::string& pa_string = m_config.pressure_advance.get_at(extruder_id);
const double nozzle_diameter = m_config.nozzle_diameter.get_at(extruder_id);
return calculate_pressure_advance_for_nozzle(pa_string, nozzle_diameter);
}

std::string encodeBase64(uint64_t value)
{
//Always use big endian mode
Expand Down Expand Up @@ -6401,10 +6471,10 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b
check_add_eol(gcode);
}
if (m_config.enable_pressure_advance.get_at(extruder_id)) {
gcode += m_writer.set_pressure_advance(m_config.pressure_advance.get_at(extruder_id));
gcode += m_writer.set_pressure_advance(get_pressure_advance_for_extruder(extruder_id));
// Orca: Adaptive PA
// Reset Adaptive PA processor last PA value
m_pa_processor->resetPreviousPA(m_config.pressure_advance.get_at(extruder_id));
m_pa_processor->resetPreviousPA(get_pressure_advance_for_extruder(extruder_id));
}

gcode += m_writer.toolchange(extruder_id);
Expand Down Expand Up @@ -6610,7 +6680,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b
gcode += m_ooze_prevention.post_toolchange(*this);

if (m_config.enable_pressure_advance.get_at(extruder_id)) {
gcode += m_writer.set_pressure_advance(m_config.pressure_advance.get_at(extruder_id));
gcode += m_writer.set_pressure_advance(get_pressure_advance_for_extruder(extruder_id));
}

return gcode;
Expand Down
3 changes: 3 additions & 0 deletions src/libslic3r/GCode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ class GCode {
bool enable_cooling_markers() const { return m_enable_cooling_markers; }
std::string extrusion_role_to_string_for_parser(const ExtrusionRole &);

// Calculate the correct pressure advance value based on nozzle diameter
double get_pressure_advance_for_extruder(unsigned int extruder_id) const;

// For Perl bindings, to be used exclusively by unit tests.
unsigned int layer_count() const { return m_layer_count; }
void set_layer_count(unsigned int value) { m_layer_count = value; }
Expand Down
6 changes: 3 additions & 3 deletions src/libslic3r/GCode/AdaptivePAProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {

if(!interpolator){ // Tool not found in the interpolator map
// Tool not found in the PA interpolator to tool map
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_extruder_id) ? m_config.pressure_advance.get_at(m_last_extruder_id) : 0;
predicted_pa = m_gcodegen.get_pressure_advance_for_extruder(m_last_extruder_id);
if(m_config.gcode_comments) output << "; APA: Tool doesnt have APA enabled\n";
} else if (!interpolator->isInitialised() || (!m_config.adaptive_pressure_advance.get_at(m_last_extruder_id)) )
// Check if the model is not initialised by the constructor for the active extruder
Expand All @@ -227,7 +227,7 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {
// however check for robustness sake.
{
// Model failed or adaptive pressure advance not enabled - use default value from m_config
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_extruder_id) ? m_config.pressure_advance.get_at(m_last_extruder_id) : 0;
predicted_pa = m_gcodegen.get_pressure_advance_for_extruder(m_last_extruder_id);
if(m_config.gcode_comments) output << "; APA: Interpolator setup failed, using default pressure advance\n";
} else { // Model setup succeeded
// Proceed to identify the print speed to use to calculate the adaptive PA value
Expand All @@ -252,7 +252,7 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {
predicted_pa = m_config.adaptive_pressure_advance_bridges.get_at(m_last_extruder_id);

if (predicted_pa < 0) { // If extrapolation fails, fall back to the default PA for the extruder.
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_extruder_id) ? m_config.pressure_advance.get_at(m_last_extruder_id) : 0;
predicted_pa = m_gcodegen.get_pressure_advance_for_extruder(m_last_extruder_id);
if(m_config.gcode_comments) output << "; APA: Interpolation failed, using fallback pressure advance value\n";
}
}
Expand Down
16 changes: 11 additions & 5 deletions src/libslic3r/PrintConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1885,13 +1885,19 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Enable pressure advance, auto calibration result will be overwritten once enabled.");
def->set_default_value(new ConfigOptionBools{ false });

def = this->add("pressure_advance", coFloats);
def = this->add("pressure_advance", coStrings);
def->label = L("Pressure advance");
def->tooltip = L("Pressure advance (Klipper) AKA Linear advance factor (Marlin).");
def->max = 2;
def->tooltip = L("Pressure advance (Klipper) AKA Linear advance factor (Marlin).\n"
"Set as: Nozzle Size, Pressure Advance Value.\n"
"Multiple values can be set. For example\n"
"0.25,0.09 \n0.3,0.065 \n0.35,0.05 \n0.4,0.02 \n0.5,0.018 \n0.6,0.012 \n0.8,0.01 \n"
"Missing values will be calculated with linear interpolation.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats { 0.02 });

def->multiline = true;
def->full_width = true;
def->height = 10;
def->set_default_value(new ConfigOptionStrings{"0.25,0.09\n0.3,0.065\n0.35,0.05\n0.4,0.02\n0.5,0.018\n0.6,0.012\n0.8,0.01"});

// Orca: Adaptive pressure advance option and calibration values
def = this->add("adaptive_pressure_advance", coBools);
def->label = L("Enable adaptive pressure advance (beta)");
Expand Down
2 changes: 1 addition & 1 deletion src/libslic3r/PrintConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionStrings, filament_end_gcode))
((ConfigOptionFloats, filament_flow_ratio))
((ConfigOptionBools, enable_pressure_advance))
((ConfigOptionFloats, pressure_advance))
((ConfigOptionStrings, pressure_advance))
// Orca: adaptive pressure advance and calibration model
((ConfigOptionBools, adaptive_pressure_advance))
((ConfigOptionBools, adaptive_pressure_advance_overhangs))
Expand Down
9 changes: 8 additions & 1 deletion src/slic3r/GUI/Field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,13 @@ void TextCtrl::BUILD() {
const ConfigOptionStrings *vec = m_opt.get_default_value<ConfigOptionStrings>();
if (vec == nullptr || vec->empty()) break; //for the case of empty default value
text_value = vec->get_at(m_opt_idx);
// For multiline fields, unescape newlines and other escape sequences
if (m_opt.multiline) {
std::string unescaped_value;
if (unescape_string_cstyle(text_value.ToStdString(), unescaped_value)) {
text_value = wxString::FromUTF8(unescaped_value);
}
}
break;
}
case coPoint:
Expand All @@ -756,7 +763,7 @@ void TextCtrl::BUILD() {
: builder2.build(m_parent, "", "", "", wxDefaultPosition, size, wxTE_PROCESS_ENTER);
temp->SetLabel(_L(m_opt.sidetext));
auto text_ctrl = m_opt.multiline ? (wxTextCtrl *)temp : ((TextInput *) temp)->GetTextCtrl();
text_ctrl->SetLabel(text_value);
text_ctrl->SetValue(text_value);
temp->SetSize(size);
m_combine_side_text = !m_opt.multiline;
if (parent_is_custom_ctrl && m_opt.height < 0)
Expand Down
8 changes: 6 additions & 2 deletions src/slic3r/GUI/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3446,14 +3446,18 @@ void TabFilament::build()
optgroup->append_single_option_line("filament_flow_ratio");

optgroup->append_single_option_line("enable_pressure_advance", "pressure-advance-calib");
optgroup->append_single_option_line("pressure_advance", "pressure-advance-calib");
Option option = optgroup->get_option("pressure_advance");
option.opt.full_width = true;
option.opt.is_code = true;
option.opt.height = 15;
optgroup->append_single_option_line(option);

// Orca: adaptive pressure advance and calibration model
optgroup->append_single_option_line("adaptive_pressure_advance", "adaptive-pressure-advance-calib");
optgroup->append_single_option_line("adaptive_pressure_advance_overhangs", "adaptive-pressure-advance-calib");
optgroup->append_single_option_line("adaptive_pressure_advance_bridges", "adaptive-pressure-advance-calib");

Option option = optgroup->get_option("adaptive_pressure_advance_model");
option = optgroup->get_option("adaptive_pressure_advance_model");
option.opt.full_width = true;
option.opt.is_code = true;
option.opt.height = 15;
Expand Down
Loading