Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port OrcaSlicer's Small Area Infill Flow Compensation #4329

Closed
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
3 changes: 3 additions & 0 deletions resources/ui_layout/default/print.ui
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ group:Advanced Infill options
setting:label_width$8:width$5:fill_smooth_distribution
setting:label_width$26:label$Spacing between ironing lines:width$5:sidetext_width$7:fill_smooth_width
end_line
group:Small Area Infill Flow Compensation (beta)
setting:small_area_infill_flow_compensation
setting:height$15:small_area_infill_flow_compensation_model
group:title_width$19:Ironing post-process (This will go on top of infills and perimeters)
line:Enable ironing post-process
setting:label$_:sidetext_width$0:ironing
Expand Down
3 changes: 3 additions & 0 deletions resources/ui_layout/example/print.ui
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ group:Advanced Infill options
setting:label_width$8:width$5:fill_smooth_distribution
setting:label_width$26:label$Spacing between ironing lines:width$5:sidetext_width$7:fill_smooth_width
end_line
group:Small Area Infill Flow Compensation (beta)
setting:small_area_infill_flow_compensation
setting:height$15:small_area_infill_flow_compensation_model
group:title_width$19:Ironing post-process (This will go on top of infills and perimeters)
line:Enable ironing post-process
setting:label$_:sidetext_width$0:ironing
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ add_library(libslic3r STATIC
GCode/GCodeProcessor.hpp
GCode/AvoidCrossingPerimeters.cpp
GCode/AvoidCrossingPerimeters.hpp
GCode/SmallAreaInfillFlowCompensator.cpp
GCode/SmallAreaInfillFlowCompensator.hpp
GCode.cpp
GCode.hpp
GCodeReader.cpp
Expand Down
29 changes: 24 additions & 5 deletions src/libslic3r/GCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "GCode/PrintExtents.hpp"
#include "GCode/Thumbnails.hpp"
#include "GCode/WipeTower.hpp"
#include "GCode/SmallAreaInfillFlowCompensator.hpp"
#include "ShortestPath.hpp"
#include "PrintConfig.hpp"
#include "Utils.hpp"
Expand Down Expand Up @@ -5496,15 +5497,28 @@ std::vector<double> cut_corner_cache = {
0.381436735764648,0.398363940736199,0.416256777189962,0.435193636891737,0.455261618934834 };


void GCode::_extrude_line(std::string& gcode_str, const Line& line, const double e_per_mm, const std::string& comment) {
void GCode::_extrude_line(std::string& gcode_str, const Line& line, const double e_per_mm, const std::string& comment,
ExtrusionRole role) {
if (line.a.coincides_with_epsilon(line.b)) {
assert(false); // todo: investigate if it happens (it happens in perimeters)
return;
}
std::string comment_copy = comment;
double unscaled_line_length = unscaled(line.length());
double extrusion_value = e_per_mm * unscaled_line_length;
if (!this->on_first_layer() && m_small_area_infill_flow_compensator && m_config.small_area_infill_flow_compensation.value) {
double new_extrusion_value = m_small_area_infill_flow_compensator ->modify_flow(unscaled_line_length, extrusion_value, role);
if (new_extrusion_value > 0.0 && new_extrusion_value != extrusion_value) {
extrusion_value = new_extrusion_value;
if (m_config.gcode_comments) {
comment_copy += Slic3r::format(_(L(" | Old Flow Value: %0.5f Length: %0.5f")), extrusion_value, unscaled_line_length);
}
}
}
gcode_str += m_writer.extrude_to_xy(
this->point_to_gcode(line.b),
e_per_mm * unscaled(line.length()),
comment);
extrusion_value,
comment_copy);
}

void GCode::_extrude_line_cut_corner(std::string& gcode_str, const Line& line, const double e_per_mm, const std::string& comment, Point& last_pos, const double path_width) {
Expand Down Expand Up @@ -5604,6 +5618,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string &descri
comment);
};

if (m_config.small_area_infill_flow_compensation.value &&
!m_config.small_area_infill_flow_compensation_model.empty()) {
m_small_area_infill_flow_compensator = std::make_unique<SmallAreaInfillFlowCompensator>(m_config);
}

// calculate extrusion length per distance unit
double e_per_mm = path.mm3_per_mm
* m_writer.tool()->e_per_mm3()
Expand All @@ -5623,7 +5642,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string &descri
for (const Line& line : path.polyline.lines()) {
if (path.role() != erExternalPerimeter || config().external_perimeter_cut_corners.value == 0) {
// normal & legacy pathcode
_extrude_line(gcode, line, e_per_mm, comment);
_extrude_line(gcode, line, e_per_mm, comment, path.role());
} else {
_extrude_line_cut_corner(gcode, line, e_per_mm, comment, last_pos, path.width);
}
Expand All @@ -5641,7 +5660,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string &descri
const Line line = Line(path.polyline.get_points()[point_index - 1], path.polyline.get_points()[point_index]);
if (path.role() != erExternalPerimeter || config().external_perimeter_cut_corners.value == 0) {
// normal & legacy pathcode
_extrude_line(gcode, line, e_per_mm, comment);
_extrude_line(gcode, line, e_per_mm, comment, path.role());
} else {
_extrude_line_cut_corner(gcode, line, e_per_mm, comment, last_pos, path.width);
}
Expand Down
4 changes: 3 additions & 1 deletion src/libslic3r/GCode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "GCode/SeamPlacer.hpp"
#include "GCode/GCodeProcessor.hpp"
#include "GCode/ThumbnailData.hpp"
#include "GCode/SmallAreaInfillFlowCompensator.hpp"

#include <memory>
#include <map>
Expand Down Expand Up @@ -485,6 +486,7 @@ class GCode : ExtrusionVisitorConst {
std::unique_ptr<GCodeFindReplace> m_find_replace;
std::unique_ptr<PressureEqualizer> m_pressure_equalizer;
std::unique_ptr<WipeTowerIntegration> m_wipe_tower;
std::unique_ptr<SmallAreaInfillFlowCompensator> m_small_area_infill_flow_compensator;

// Heights (print_z) at which the skirt has already been extruded.
std::vector<coordf_t> m_skirt_done;
Expand Down Expand Up @@ -515,7 +517,7 @@ class GCode : ExtrusionVisitorConst {
std::function<void()> m_throw_if_canceled = [](){};

std::string _extrude(const ExtrusionPath &path, const std::string &description, double speed = -1);
void _extrude_line(std::string& gcode_str, const Line& line, const double e_per_mm, const std::string& comment);
void _extrude_line(std::string& gcode_str, const Line& line, const double e_per_mm, const std::string& comment, ExtrusionRole role);
void _extrude_line_cut_corner(std::string& gcode_str, const Line& line, const double e_per_mm, const std::string& comment, Point& last_pos, const double path_width);
std::string _before_extrude(const ExtrusionPath &path, const std::string &description, double speed = -1);
double_t _compute_speed_mm_per_sec(const ExtrusionPath& path, double speed = -1);
Expand Down
103 changes: 103 additions & 0 deletions src/libslic3r/GCode/SmallAreaInfillFlowCompensator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#include "SmallAreaInfillFlowCompensator.hpp"

#include "../libslic3r.h"

namespace Slic3r{

bool nearly_equal_floating_point(double a, double b) {
return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b &&
std::nextafter(a, std::numeric_limits<double>::max()) >= b;
}

void SmallAreaInfillFlowCompensator::check_model_parameter_correctness() {
if (extrusionLengths.empty()) {
throw Slic3r::InvalidArgument(
"Small area infill compensation model is misconfigured: no lengths have been set"
);
}
if (flowCompensationFactors.empty()) {
throw Slic3r::InvalidArgument(
"Small area infill compensation model is misconfigured: no compensation factors have been set"
);
}

if (extrusionLengths.size() != flowCompensationFactors.size()) {
throw Slic3r::InvalidArgument("Small area infill compensation model is misconfigured: "
"Different size of lengths and compensation factors");
}

if (!nearly_equal_floating_point(extrusionLengths[0], 0.0)) {
throw Slic3r::InvalidArgument(
"First extrusion length for small area infill compensation model must be 0"
);
}

for (int i = 1; i < extrusionLengths.size(); i++) {
if (nearly_equal_floating_point(extrusionLengths[i], 0.0)) {
throw Slic3r::InvalidArgument("Only the first extrusion length for small area "
"infill compensation model can be 0");
}
if (extrusionLengths[i] <= extrusionLengths[i - 1]) {
throw Slic3r::InvalidArgument(
"Extrusion lengths for subsequent points must be in increasing order"
);
}
}

if (!nearly_equal_floating_point(flowCompensationFactors.back(), 1.0)) {
throw Slic3r::InvalidArgument(
"Final compensation factor for small area infill flow compensation model must be 1.0"
);
}
}

void SmallAreaInfillFlowCompensator::read_config_parameters(const Slic3r::FullPrintConfig& config) {
for (auto &line : config.small_area_infill_flow_compensation_model.values) {
std::istringstream iss(line);
std::string value_str;
double extrusion_length = 0.0;

if (std::getline(iss, value_str, ',')) {
try {
extrusion_length = std::stod(value_str);
if (std::getline(iss, value_str, ',')) {
extrusionLengths.push_back(extrusion_length);
flowCompensationFactors.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());
}
}
}
}


SmallAreaInfillFlowCompensator::SmallAreaInfillFlowCompensator(const Slic3r::FullPrintConfig& config) {
read_config_parameters(config);
check_model_parameter_correctness();
flowModel.set_points(extrusionLengths, flowCompensationFactors);
}

double SmallAreaInfillFlowCompensator::flow_comp_model(const double line_length) {
if (line_length == 0 || line_length > max_modified_length()) {
return 1.0;
}

return flowModel(line_length);
}

double SmallAreaInfillFlowCompensator::modify_flow(
const double line_length, const double dE, const ExtrusionRole role
) {
if (role == ExtrusionRole::erSolidInfill || role == ExtrusionRole::erTopSolidInfill) {
return dE * flow_comp_model(line_length);
}

return dE;
}

} // namespace Slic3r
38 changes: 38 additions & 0 deletions src/libslic3r/GCode/SmallAreaInfillFlowCompensator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#ifndef slic3r_SmallAreaInfillFlowCompensator_hpp_
#define slic3r_SmallAreaInfillFlowCompensator_hpp_

#include "../libslic3r.h"
#include "../PrintConfig.hpp"
#include "../ExtrusionEntity.hpp"
#include "spline/spline.h"

namespace Slic3r {


class SmallAreaInfillFlowCompensator
{
private:
// Model points
std::vector<double> extrusionLengths;
std::vector<double> flowCompensationFactors;

tk::spline flowModel;

private:
double flow_comp_model(const double line_length);

double max_modified_length() { return extrusionLengths.back(); }

void check_model_parameter_correctness();

void read_config_parameters(const Slic3r::FullPrintConfig& config);

public:
explicit SmallAreaInfillFlowCompensator(const Slic3r::FullPrintConfig& config);

double modify_flow(const double line_length, const double dE, const ExtrusionRole role);
};

} // namespace Slic3r

#endif /* slic3r_SmallAreaInfillFlowCompensator_hpp_ */
3 changes: 2 additions & 1 deletion src/libslic3r/Preset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,8 @@ static std::vector<std::string> s_Preset_print_options {
"milling_speed",
//Arachne
"perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
"wall_distribution_count", "min_feature_size", "min_bead_width"
"wall_distribution_count", "min_feature_size", "min_bead_width",
"small_area_infill_flow_compensation", "small_area_infill_flow_compensation_model"
};

static std::vector<std::string> s_Preset_filament_options {
Expand Down
26 changes: 26 additions & 0 deletions src/libslic3r/PrintConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2504,6 +2504,30 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("%");
def->set_default_value(new ConfigOptionPercent(10));

def = this->add("small_area_infill_flow_compensation", coBool);
def->label = L("Enable small area flow compensation");
def->category = OptionCategory::infill;
def->tooltip = L("Enable flow compensation for small infill areas");
def->mode = comExpert | comSuSi;
def->set_default_value(new ConfigOptionBool(false));

def = this->add("small_area_infill_flow_compensation_model", coStrings);
def->label = L("Flow Compensation Model");
def->category = OptionCategory::infill;
def->tooltip = L("Flow Compensation Model, used to adjust the flow for small infill "
"areas. The model is expressed as a comma separated pair of values for "
"extrusion length and flow correction factors, one per line, in the "
"following format: \"1.234,5.678\"");
def->mode = comExpert | comSuSi;
def->gui_flags = "serialized";
def->multiline = true;
def->full_width = false;
def->height = 15;
def->set_default_value(new ConfigOptionStrings{
"0,0", "0.2,0.4444", "0.4,0.6145", "0.6,0.7059", "0.8,0.7619", "1.5,0.8571",
"2,0.8889", "3,0.9231", "5,0.9520", "10,1"
});

def = this->add("first_layer_acceleration", coFloatOrPercent);
def->label = L("Max");
def->full_label = L("First layer acceleration");
Expand Down Expand Up @@ -8249,6 +8273,8 @@ std::unordered_set<std::string> prusa_export_to_remove_keys = {
"skirt_brim",
"skirt_distance_from_brim",
"skirt_extrusion_width",
"small_area_infill_flow_compensation"
"small_area_infill_flow_compensation_model"
"small_perimeter_max_length",
"small_perimeter_min_length",
"solid_fill_pattern",
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/PrintConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, xy_size_compensation))
((ConfigOptionFloat, xy_inner_size_compensation))
((ConfigOptionBool, wipe_into_objects))
((ConfigOptionBool, small_area_infill_flow_compensation))
)

// This object is mapped to Perl as Slic3r::Config::PrintRegion.
Expand Down Expand Up @@ -1287,6 +1288,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionFloats, wiping_volumes_extruders))
((ConfigOptionFloat, z_offset))
((ConfigOptionFloat, init_z_rotate))
((ConfigOptionStrings, small_area_infill_flow_compensation_model))

)

Expand Down
3 changes: 3 additions & 0 deletions src/libslic3r/PrintObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,9 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "perimeter_loop"
|| opt_key == "perimeter_loop_seam") {
steps.emplace_back(posPerimeters);
} else if (opt_key == "small_area_infill_flow_compensation"
|| opt_key == "small_area_infill_flow_compensation_model") {
steps.emplace_back(posSlice);
} else if (
opt_key == "gap_fill_enabled"
|| opt_key == "gap_fill_speed") {
Expand Down
3 changes: 3 additions & 0 deletions src/slic3r/GUI/ConfigManipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)

toggle_field("perimeter_loop_seam", config->opt_bool("perimeter_loop"));

bool have_small_area_infill_flow_compensation = config->opt_bool("small_area_infill_flow_compensation");
toggle_field("small_area_infill_flow_compensation_model", have_small_area_infill_flow_compensation);

bool have_notch = have_perimeters && (config->option("seam_notch_all")->get_float() != 0 ||
config->option("seam_notch_inner")->get_float() != 0 ||
config->option("seam_notch_outer")->get_float() != 0);
Expand Down
Loading