Adaptive Pressure Advance Validation (#14198)
Co-authored-by: Wegerich <23041237+Wegerich@users.noreply.github.com>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <cctype>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -282,4 +283,81 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {
|
||||
return output.str();
|
||||
}
|
||||
|
||||
std::string AdaptivePAProcessor::validate_adaptive_pa_model(const std::string& model_str)
|
||||
{
|
||||
if (model_str.empty())
|
||||
return {}; // Empty model is valid
|
||||
|
||||
std::istringstream model_stream(model_str);
|
||||
std::string line;
|
||||
int line_number = 0;
|
||||
|
||||
while (std::getline(model_stream, line)) {
|
||||
++line_number;
|
||||
|
||||
// Trim whitespace
|
||||
const auto first = line.find_first_not_of(" \t\r\n");
|
||||
if (first == std::string::npos)
|
||||
continue; // Skip empty lines
|
||||
|
||||
const auto last = line.find_last_not_of(" \t\r\n");
|
||||
line = line.substr(first, last - first + 1);
|
||||
|
||||
// Only numbers, commas and dots are allowed (no letters or other characters)
|
||||
for (char c : line) {
|
||||
if (!std::isdigit(static_cast<unsigned char>(c)) && c != ',' && c != '.') {
|
||||
return "Line " + std::to_string(line_number) +
|
||||
": only numbers, commas and dots are allowed";
|
||||
}
|
||||
}
|
||||
|
||||
// Count commas to validate format (should be exactly 2 for 3 values)
|
||||
int comma_count = 0;
|
||||
for (char c : line) {
|
||||
if (c == ',') comma_count++;
|
||||
}
|
||||
|
||||
if (comma_count != 2) {
|
||||
return "Line " + std::to_string(line_number) +
|
||||
": must contain exactly 3 comma-separated values (PA, flow, acceleration)";
|
||||
}
|
||||
|
||||
// Parse and validate the values
|
||||
try {
|
||||
std::istringstream line_stream(line);
|
||||
std::string value;
|
||||
|
||||
// Parse PA
|
||||
if (!std::getline(line_stream, value, ','))
|
||||
return "Line " + std::to_string(line_number) + ": missing PA value";
|
||||
double pa = std::stod(value);
|
||||
|
||||
// Parse flow
|
||||
if (!std::getline(line_stream, value, ','))
|
||||
return "Line " + std::to_string(line_number) + ": missing flow value";
|
||||
double flow = std::stod(value);
|
||||
|
||||
// Parse acceleration
|
||||
if (!std::getline(line_stream, value, ','))
|
||||
return "Line " + std::to_string(line_number) + ": missing acceleration value";
|
||||
double accel = std::stod(value);
|
||||
|
||||
// Validate constraints
|
||||
if (pa >= 2.0) {
|
||||
return "Line " + std::to_string(line_number) + ": PA value must be less than 2";
|
||||
}
|
||||
if (flow <= pa) {
|
||||
return "Line " + std::to_string(line_number) + ": flow value must be greater than PA value";
|
||||
}
|
||||
if (accel <= flow) {
|
||||
return "Line " + std::to_string(line_number) + ": acceleration value must be greater than flow value";
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
return "Line " + std::to_string(line_number) + ": invalid numeric value";
|
||||
}
|
||||
}
|
||||
|
||||
return {}; // All validations passed
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -54,6 +54,20 @@ public:
|
||||
*/
|
||||
void resetPreviousPA(double PA){ m_last_predicted_pa = PA; };
|
||||
|
||||
/**
|
||||
* @brief Validates an adaptive pressure advance model string.
|
||||
*
|
||||
* Checks that:
|
||||
* - Each non-empty line has exactly 3 comma-separated values (PA, flow, accel)
|
||||
* - PA value is less than 2
|
||||
* - Flow value is greater than PA value
|
||||
* - Accel value is greater than flow value
|
||||
*
|
||||
* @param model_str The model string to validate (typically from config)
|
||||
* @return Empty string if valid, or an error message describing the first issue found
|
||||
*/
|
||||
static std::string validate_adaptive_pa_model(const std::string& model_str);
|
||||
|
||||
private:
|
||||
GCode &m_gcodegen; ///< Reference to the GCode object.
|
||||
std::unordered_map<unsigned int, std::unique_ptr<AdaptivePAInterpolator>> m_AdaptivePAInterpolators; ///< Map between Interpolator objects and tool ID's
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <unordered_set>
|
||||
#include <sstream>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
@@ -1925,6 +1926,23 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin
|
||||
if (m_default_region_config.precise_outer_wall && m_default_region_config.wall_sequence != WallSequence::InnerOuter)
|
||||
warn(L("The precise wall option will be ignored for outer-inner or inner-outer-inner wall sequences."), "precise_outer_wall");
|
||||
|
||||
// check adaptive pressure advance model
|
||||
for (unsigned int extruder_id : extruders) {
|
||||
if (m_config.adaptive_pressure_advance.get_at(extruder_id) &&
|
||||
m_config.enable_pressure_advance.get_at(extruder_id)) {
|
||||
|
||||
const std::string pa_model = m_config.adaptive_pressure_advance_model.get_at(extruder_id);
|
||||
if (!pa_model.empty()) {
|
||||
std::string validation_error = AdaptivePAProcessor::validate_adaptive_pa_model(pa_model);
|
||||
if (!validation_error.empty()) {
|
||||
warn(L("The Adaptive Pressure Advance model for one or more extruders may contain invalid values."),
|
||||
"adaptive_pressure_advance_model");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca: validate motion ability failed: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
@@ -9,13 +9,29 @@
|
||||
#include "libslic3r/MaterialType.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/GCode/AdaptivePAProcessor.hpp"
|
||||
#include "Plater.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <wx/msgdlg.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string trim_copy(const std::string& text)
|
||||
{
|
||||
const auto first = text.find_first_not_of(" \t\r\n");
|
||||
if (first == std::string::npos)
|
||||
return {};
|
||||
|
||||
const auto last = text.find_last_not_of(" \t\r\n");
|
||||
return text.substr(first, last - first + 1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ConfigManipulation::apply(DynamicPrintConfig* config, DynamicPrintConfig* new_config)
|
||||
{
|
||||
bool modified = false;
|
||||
@@ -141,6 +157,30 @@ void ConfigManipulation::check_nozzle_temperature_initial_layer_range(DynamicPri
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigManipulation::check_adaptive_pressure_advance_model(DynamicPrintConfig* config)
|
||||
{
|
||||
if (is_msg_dlg_already_exist || !config->has("adaptive_pressure_advance_model"))
|
||||
return;
|
||||
|
||||
const auto* model = config->option<ConfigOptionStrings>("adaptive_pressure_advance_model");
|
||||
if (model == nullptr || model->values.empty())
|
||||
return;
|
||||
|
||||
std::string raw_model;
|
||||
for (const std::string& chunk : model->values)
|
||||
raw_model += chunk;
|
||||
|
||||
std::string error = AdaptivePAProcessor::validate_adaptive_pa_model(raw_model);
|
||||
if (!error.empty()) {
|
||||
wxString msg_text = _L("Adaptive Pressure Advance model validation failed:\n");
|
||||
msg_text += from_u8(error);
|
||||
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
|
||||
is_msg_dlg_already_exist = true;
|
||||
dialog.ShowModal();
|
||||
is_msg_dlg_already_exist = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ConfigManipulation::check_filament_max_volumetric_speed(DynamicPrintConfig *config)
|
||||
{
|
||||
|
||||
@@ -77,6 +77,7 @@ public:
|
||||
void check_nozzle_recommended_temperature_range(DynamicPrintConfig *config);
|
||||
void check_nozzle_temperature_range(DynamicPrintConfig* config);
|
||||
void check_nozzle_temperature_initial_layer_range(DynamicPrintConfig* config);
|
||||
void check_adaptive_pressure_advance_model(DynamicPrintConfig* config);
|
||||
void check_filament_max_volumetric_speed(DynamicPrintConfig *config);
|
||||
void check_chamber_temperature(DynamicPrintConfig* config);
|
||||
void set_is_BBL_Printer(bool is_bbl_printer) { is_BBL_Printer = is_bbl_printer; };
|
||||
|
||||
@@ -3946,6 +3946,15 @@ void TabFilament::build()
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = 15;
|
||||
optgroup->append_single_option_line(option);
|
||||
optgroup->m_on_change = [this](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
DynamicPrintConfig& filament_config = m_preset_bundle->filaments.get_edited_preset().config;
|
||||
|
||||
update_dirty();
|
||||
if (opt_key == "adaptive_pressure_advance_model")
|
||||
m_config_manipulation.check_adaptive_pressure_advance_model(&filament_config);
|
||||
|
||||
on_value_change(opt_key, value);
|
||||
};
|
||||
//
|
||||
|
||||
optgroup = page->new_optgroup(L("Print chamber temperature"), L"param_chamber_temp");
|
||||
|
||||
Reference in New Issue
Block a user