Fix small area flow comp regression and some other small tweaks (#5844)

* Fix regression, always create SmallAreaInfillFlowCompensator model
small_area_infill_flow_compensation is per-region parameter, it's not necessary to iterate though all regions to check whether to create a model.

* Make SmallAreaInfillFlowCompensator robus.
1. handle spaces/tabs/new lines etc
2. don't throw expection, fall back to no-op instead if parsing failed

* Fixing an issue that changing small_area_infill_flow_compensation per modifier didn't take effect
This commit is contained in:
SoftFever 2024-06-25 00:20:20 +08:00 committed by GitHub
parent 5c9b82d6ec
commit 34ad17bcd2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 56 additions and 40 deletions

View file

@ -1977,7 +1977,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
} else } else
m_enable_extrusion_role_markers = false; m_enable_extrusion_role_markers = false;
if (m_config.small_area_infill_flow_compensation.value && !print.config().small_area_infill_flow_compensation_model.empty()) if (!print.config().small_area_infill_flow_compensation_model.empty())
m_small_area_infill_flow_compensator = make_unique<SmallAreaInfillFlowCompensator>(print.config()); m_small_area_infill_flow_compensator = make_unique<SmallAreaInfillFlowCompensator>(print.config());
file.write_format("; HEADER_BLOCK_START\n"); file.write_format("; HEADER_BLOCK_START\n");

View file

@ -14,6 +14,7 @@
#include "../PrintConfig.hpp" #include "../PrintConfig.hpp"
#include "SmallAreaInfillFlowCompensator.hpp" #include "SmallAreaInfillFlowCompensator.hpp"
#include <boost/log/trivial.hpp>
namespace Slic3r { namespace Slic3r {
@ -24,61 +25,75 @@ bool nearly_equal(double a, double b)
SmallAreaInfillFlowCompensator::SmallAreaInfillFlowCompensator(const Slic3r::GCodeConfig& config) SmallAreaInfillFlowCompensator::SmallAreaInfillFlowCompensator(const Slic3r::GCodeConfig& config)
{ {
for (auto& line : config.small_area_infill_flow_compensation_model.values) { try {
std::istringstream iss(line); for (auto& line : config.small_area_infill_flow_compensation_model.values) {
std::string value_str; std::istringstream iss(line);
double eLength = 0.0; std::string value_str;
double eLength = 0.0;
if (std::getline(iss, value_str, ',')) { if (std::getline(iss, value_str, ',')) {
try { try {
eLength = std::stod(value_str); // Trim leading and trailing whitespace
if (std::getline(iss, value_str, ',')) { value_str = std::regex_replace(value_str, std::regex("^\\s+|\\s+$"), "");
eLengths.push_back(eLength); if (value_str.empty()) {
flowComps.push_back(std::stod(value_str)); continue;
}
eLength = std::stod(value_str);
if (std::getline(iss, value_str, ',')) {
eLengths.push_back(eLength);
flowComps.push_back(std::stod(value_str));
}
} catch (...) {
std::stringstream ss;
ss << "Error parsing data point in small area infill compensation model:" << line << std::endl;
throw Slic3r::InvalidArgument(ss.str());
} }
} catch (...) {
std::stringstream ss;
ss << "Error parsing data point in small area infill compensation model:" << line << std::endl;
throw Slic3r::InvalidArgument(ss.str());
} }
} }
}
for (int i = 0; i < eLengths.size(); i++) { for (int i = 0; i < eLengths.size(); i++) {
if (i == 0) { if (i == 0) {
if (!nearly_equal(eLengths[i], 0.0)) { if (!nearly_equal(eLengths[i], 0.0)) {
throw Slic3r::InvalidArgument("First extrusion length for small area infill compensation model must be 0"); throw Slic3r::InvalidArgument("First extrusion length for small area infill compensation model must be 0");
} }
} else { } else {
if (nearly_equal(eLengths[i], 0.0)) { if (nearly_equal(eLengths[i], 0.0)) {
throw Slic3r::InvalidArgument("Only the first extrusion length for small area infill compensation model can be 0"); throw Slic3r::InvalidArgument("Only the first extrusion length for small area infill compensation model can be 0");
} }
if (eLengths[i] <= eLengths[i - 1]) { if (eLengths[i] <= eLengths[i - 1]) {
throw Slic3r::InvalidArgument("Extrusion lengths for subsequent points must be increasing"); throw Slic3r::InvalidArgument("Extrusion lengths for subsequent points must be increasing");
}
} }
} }
}
if (!flowComps.empty() && !nearly_equal(flowComps.back(), 1.0)) { if (!flowComps.empty() && !nearly_equal(flowComps.back(), 1.0)) {
throw Slic3r::InvalidArgument("Final compensation factor for small area infill flow compensation model must be 1.0"); throw Slic3r::InvalidArgument("Final compensation factor for small area infill flow compensation model must be 1.0");
} }
flowModel.set_points(eLengths, flowComps); flowModel = std::make_unique<tk::spline>();
flowModel->set_points(eLengths, flowComps);
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Error parsing small area infill compensation model: " << e.what();
}
} }
double SmallAreaInfillFlowCompensator::flow_comp_model(const double line_length) double SmallAreaInfillFlowCompensator::flow_comp_model(const double line_length)
{ {
if(flowModel == nullptr)
return 1.0;
if (line_length == 0 || line_length > max_modified_length()) { if (line_length == 0 || line_length > max_modified_length()) {
return 1.0; return 1.0;
} }
return flowModel(line_length); return (*flowModel)(line_length);
} }
double SmallAreaInfillFlowCompensator::modify_flow(const double line_length, const double dE, const ExtrusionRole role) double SmallAreaInfillFlowCompensator::modify_flow(const double line_length, const double dE, const ExtrusionRole role)
{ {
if (role == ExtrusionRole::erSolidInfill || role == ExtrusionRole::erTopSolidInfill || role == ExtrusionRole::erBottomSurface) { if (flowModel &&
(role == ExtrusionRole::erSolidInfill || role == ExtrusionRole::erTopSolidInfill || role == ExtrusionRole::erBottomSurface)) {
return dE * flow_comp_model(line_length); return dE * flow_comp_model(line_length);
} }

View file

@ -5,6 +5,7 @@
#include "../PrintConfig.hpp" #include "../PrintConfig.hpp"
#include "../ExtrusionEntity.hpp" #include "../ExtrusionEntity.hpp"
#include "spline/spline.h" #include "spline/spline.h"
#include <memory>
namespace Slic3r { namespace Slic3r {
@ -23,7 +24,7 @@ private:
std::vector<double> flowComps; std::vector<double> flowComps;
// TODO: Cubic Spline // TODO: Cubic Spline
tk::spline flowModel; std::unique_ptr<tk::spline> flowModel;
double flow_comp_model(const double line_length); double flow_comp_model(const double line_length);

View file

@ -924,8 +924,7 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "wipe_speed") { || opt_key == "wipe_speed") {
steps.emplace_back(posPerimeters); steps.emplace_back(posPerimeters);
} else if ( } else if (
opt_key == "small_area_infill_flow_compensation" opt_key == "small_area_infill_flow_compensation_model") {
|| opt_key == "small_area_infill_flow_compensation_model") {
steps.emplace_back(posSlice); steps.emplace_back(posSlice);
} else if (opt_key == "gap_infill_speed" } else if (opt_key == "gap_infill_speed"
|| opt_key == "filter_out_gap_fill" ) { || opt_key == "filter_out_gap_fill" ) {
@ -1080,7 +1079,8 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "infill_anchor" || opt_key == "infill_anchor"
|| opt_key == "infill_anchor_max" || opt_key == "infill_anchor_max"
|| opt_key == "top_surface_line_width" || opt_key == "top_surface_line_width"
|| opt_key == "initial_layer_line_width") { || opt_key == "initial_layer_line_width"
|| opt_key == "small_area_infill_flow_compensation") {
steps.emplace_back(posInfill); steps.emplace_back(posInfill);
} else if (opt_key == "sparse_infill_pattern") { } else if (opt_key == "sparse_infill_pattern") {
steps.emplace_back(posPrepareInfill); steps.emplace_back(posPrepareInfill);