Calculate extrusion width %s as a function of nozzle width, not layer height (#1578)

* Calculate extrusion width %s as a function of nozzle width, not layer height

* handled more width conversions

* more missing percent handling

* even more missed percent handling

* even more more extrusion % handling

* some fixes

---------

Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
Jason M-H 2023-07-27 11:37:47 -04:00 committed by GitHub
parent 71ddef9724
commit be54f6bc99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 187 additions and 121 deletions

View file

@ -653,22 +653,52 @@ double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const
{ {
// Get stored option value. // Get stored option value.
const ConfigOption *raw_opt = this->option(opt_key); const ConfigOption *raw_opt = this->option(opt_key);
if (raw_opt == nullptr) {
std::stringstream ss;
ss << "You can't define an option that need " << opt_key << " without defining it!";
throw std::runtime_error(ss.str());
}
assert(raw_opt != nullptr); assert(raw_opt != nullptr);
if (raw_opt->type() == coFloat) if (raw_opt->type() == coFloat)
return static_cast<const ConfigOptionFloat*>(raw_opt)->value; return static_cast<const ConfigOptionFloat*>(raw_opt)->value;
if (raw_opt->type() == coInt)
return static_cast<const ConfigOptionInt *>(raw_opt)->value;
if (raw_opt->type() == coBool)
return static_cast<const ConfigOptionBool *>(raw_opt)->value ? 1 : 0;
const ConfigOptionPercent *cast_opt = nullptr;
if (raw_opt->type() == coFloatOrPercent) { if (raw_opt->type() == coFloatOrPercent) {
auto cofop = static_cast<const ConfigOptionFloatOrPercent*>(raw_opt);
if (cofop->value == 0 && boost::ends_with(opt_key, "_line_width")) {
return this->get_abs_value("line_width");
}
if (!cofop->percent)
return cofop->value;
cast_opt = cofop;
}
if (raw_opt->type() == coPercent) {
cast_opt = static_cast<const ConfigOptionPercent *>(raw_opt);
}
// Get option definition. // Get option definition.
const ConfigDef *def = this->def(); const ConfigDef *def = this->def();
if (def == nullptr) if (def == nullptr)
throw NoDefinitionException(opt_key); throw NoDefinitionException(opt_key);
const ConfigOptionDef *opt_def = def->get(opt_key); const ConfigOptionDef *opt_def = def->get(opt_key);
assert(opt_def != nullptr); assert(opt_def != nullptr);
if (opt_def->ratio_over == "")
return cast_opt->get_abs_value(1);
// Compute absolute value over the absolute value of the base option. // Compute absolute value over the absolute value of the base option.
//FIXME there are some ratio_over chains, which end with empty ratio_with. //FIXME there are some ratio_over chains, which end with empty ratio_with.
// For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly. // For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
return opt_def->ratio_over.empty() ? 0. : return opt_def->ratio_over.empty() ? 0. :
static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->get_abs_value(this->get_abs_value(opt_def->ratio_over)); static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->get_abs_value(this->get_abs_value(opt_def->ratio_over));
}
throw ConfigurationError("ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()"); throw ConfigurationError("ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()");
} }

View file

@ -301,7 +301,7 @@ std::pair<double, double> adaptive_fill_line_spacing(const PrintObject &print_ob
bool nonempty = config.sparse_infill_density > 0; bool nonempty = config.sparse_infill_density > 0;
bool has_adaptive_infill = nonempty && config.sparse_infill_pattern == ipAdaptiveCubic; bool has_adaptive_infill = nonempty && config.sparse_infill_pattern == ipAdaptiveCubic;
bool has_support_infill = nonempty && config.sparse_infill_pattern == ipSupportCubic; bool has_support_infill = nonempty && config.sparse_infill_pattern == ipSupportCubic;
double sparse_infill_line_width = config.sparse_infill_line_width; double sparse_infill_line_width = config.sparse_infill_line_width.get_abs_value(max_nozzle_diameter);
region_fill_data.push_back(RegionFillData({ region_fill_data.push_back(RegionFillData({
has_adaptive_infill ? Tristate::Maybe : Tristate::No, has_adaptive_infill ? Tristate::Maybe : Tristate::No,
has_support_infill ? Tristate::Maybe : Tristate::No, has_support_infill ? Tristate::Maybe : Tristate::No,

View file

@ -75,9 +75,7 @@ Generator::Generator(const PrintObject &print_object, const std::function<void()
// Note: There's not going to be a layer below the first one, so the 'initial layer height' doesn't have to be taken into account. // Note: There's not going to be a layer below the first one, so the 'initial layer height' doesn't have to be taken into account.
const double layer_thickness = scaled<double>(object_config.layer_height.value); const double layer_thickness = scaled<double>(object_config.layer_height.value);
//m_infill_extrusion_width = scaled<float>(region_config.infill_extrusion_width.percent ? default_infill_extrusion_width * 0.01 * region_config.infill_extrusion_width : region_config.infill_extrusion_width); m_infill_extrusion_width = scaled<float>(region_config.sparse_infill_line_width.get_abs_value(max_nozzle_diameter));
//m_supporting_radius = coord_t(m_infill_extrusion_width) * 100 / coord_t(region_config.fill_density.value);
m_infill_extrusion_width = scaled<float>(region_config.sparse_infill_line_width.value);
m_supporting_radius = coord_t(m_infill_extrusion_width) * 100 / region_config.sparse_infill_density; m_supporting_radius = coord_t(m_infill_extrusion_width) * 100 / region_config.sparse_infill_density;
const double lightning_infill_overhang_angle = M_PI / 4; // 45 degrees const double lightning_infill_overhang_angle = M_PI / 4; // 45 degrees
@ -103,7 +101,7 @@ Generator::Generator(PrintObject* m_object, std::vector<Polygons>& contours, std
// Note: There's not going to be a layer below the first one, so the 'initial layer height' doesn't have to be taken into account. // Note: There's not going to be a layer below the first one, so the 'initial layer height' doesn't have to be taken into account.
const double layer_thickness = scaled<double>(object_config.layer_height.value); const double layer_thickness = scaled<double>(object_config.layer_height.value);
m_infill_extrusion_width = scaled<float>(region_config.sparse_infill_line_width.value); m_infill_extrusion_width = scaled<float>(region_config.sparse_infill_line_width.get_abs_value(max_nozzle_diameter));
//m_supporting_radius: against to the density of lightning, failures may happen if set to high density //m_supporting_radius: against to the density of lightning, failures may happen if set to high density
//higher density lightning makes support harder, more time-consuming on computing and printing, but more reliable on supporting overhangs //higher density lightning makes support harder, more time-consuming on computing and printing, but more reliable on supporting overhangs
//lower density lightning performs opposite //lower density lightning performs opposite

View file

@ -67,8 +67,6 @@ double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionFloat
{ {
assert(opt != nullptr); assert(opt != nullptr);
bool first_layer = boost::starts_with(opt_key, "initial_layer_");
#if 0 #if 0
// This is the logic used for skit / brim, but not for the rest of the 1st layer. // This is the logic used for skit / brim, but not for the rest of the 1st layer.
if (opt->value == 0. && first_layer) { if (opt->value == 0. && first_layer) {
@ -84,24 +82,18 @@ double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionFloat
opt = config.option<ConfigOptionFloatOrPercent>("line_width"); opt = config.option<ConfigOptionFloatOrPercent>("line_width");
if (opt == nullptr) if (opt == nullptr)
throw_on_missing_variable(opt_key, "line_width"); throw_on_missing_variable(opt_key, "line_width");
// Use the "layer_height" instead of "initial_layer_print_height".
first_layer = false;
} }
auto opt_nozzle_diameters = config.option<ConfigOptionFloats>("nozzle_diameter");
if (opt_nozzle_diameters == nullptr)
throw_on_missing_variable(opt_key, "nozzle_diameter");
if (opt->percent) { if (opt->percent) {
auto opt_key_layer_height = first_layer ? "initial_layer_print_height" : "layer_height"; return opt->get_abs_value(float(opt_nozzle_diameters->get_at(first_printing_extruder)));
auto opt_layer_height = config.option(opt_key_layer_height);
if (opt_layer_height == nullptr)
throw_on_missing_variable(opt_key, opt_key_layer_height);
assert(! first_layer || ! static_cast<const ConfigOptionFloatOrPercent*>(opt_layer_height)->percent);
return opt->get_abs_value(opt_layer_height->getFloat());
} }
if (opt->value == 0.) { if (opt->value == 0.) {
// If user left option to 0, calculate a sane default width. // If user left option to 0, calculate a sane default width.
auto opt_nozzle_diameters = config.option<ConfigOptionFloats>("nozzle_diameter");
if (opt_nozzle_diameters == nullptr)
throw_on_missing_variable(opt_key, "nozzle_diameter");
return auto_extrusion_width(opt_key_to_flow_role(opt_key), float(opt_nozzle_diameters->get_at(first_printing_extruder))); return auto_extrusion_width(opt_key_to_flow_role(opt_key), float(opt_nozzle_diameters->get_at(first_printing_extruder)));
} }
@ -116,18 +108,18 @@ double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionResol
// This constructor builds a Flow object from an extrusion width config setting // This constructor builds a Flow object from an extrusion width config setting
// and other context properties. // and other context properties.
Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloat &width, float nozzle_diameter, float height) Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height)
{ {
if (height <= 0) if (height <= 0)
throw Slic3r::InvalidArgument("Invalid flow height supplied to new_from_config_width()"); throw Slic3r::InvalidArgument("Invalid flow height supplied to new_from_config_width()");
float w; float w;
if (width.value == 0.) { if (!width.percent && width.value <= 0.) {
// If user left option to 0, calculate a sane default width. // If user left option to 0, calculate a sane default width.
w = auto_extrusion_width(role, nozzle_diameter); w = auto_extrusion_width(role, nozzle_diameter);
} else { } else {
// If user set a manual value, use it. // If user set a manual value, use it.
w = float(width.value); w = float(width.get_abs_value(nozzle_diameter));
} }
return Flow(w, height, rounded_rectangle_extrusion_spacing(w, height), nozzle_diameter, false); return Flow(w, height, rounded_rectangle_extrusion_spacing(w, height), nozzle_diameter, false);

View file

@ -98,7 +98,7 @@ public:
static Flow bridging_flow(float dmr, float nozzle_diameter) { return Flow { dmr, dmr, bridge_extrusion_spacing(dmr), nozzle_diameter, true }; } static Flow bridging_flow(float dmr, float nozzle_diameter) { return Flow { dmr, dmr, bridge_extrusion_spacing(dmr), nozzle_diameter, true }; }
static Flow new_from_config_width(FlowRole role, const ConfigOptionFloat &width, float nozzle_diameter, float height); static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height);
// Spacing of extrusions with rounded extrusion model. // Spacing of extrusions with rounded extrusion model.
static float rounded_rectangle_extrusion_spacing(float width, float height); static float rounded_rectangle_extrusion_spacing(float width, float height);

View file

@ -1783,11 +1783,13 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
//BBS: calculate the volumetric speed of outer wall. Ignore pre-object setting and multi-filament, and just use the default setting //BBS: calculate the volumetric speed of outer wall. Ignore pre-object setting and multi-filament, and just use the default setting
{ {
float filament_max_volumetric_speed = m_config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->get_at(initial_non_support_extruder_id); float filament_max_volumetric_speed = m_config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->get_at(initial_non_support_extruder_id);
float outer_wall_line_width = print.default_region_config().outer_wall_line_width.value; const double nozzle_diameter = m_config.nozzle_diameter.get_at(initial_non_support_extruder_id);
float outer_wall_line_width = this->config().get_abs_value("outer_wall_line_width", nozzle_diameter);
if (outer_wall_line_width == 0.0) { if (outer_wall_line_width == 0.0) {
float default_line_width = print.default_object_config().line_width.value; float default_line_width = this->config().get_abs_value("line_width", nozzle_diameter);
outer_wall_line_width = default_line_width == 0.0 ? m_config.nozzle_diameter.get_at(initial_non_support_extruder_id) : default_line_width; outer_wall_line_width = default_line_width == 0.0 ? nozzle_diameter : default_line_width;
} }
Flow outer_wall_flow = Flow(outer_wall_line_width, m_config.layer_height, m_config.nozzle_diameter.get_at(initial_non_support_extruder_id)); Flow outer_wall_flow = Flow(outer_wall_line_width, m_config.layer_height, m_config.nozzle_diameter.get_at(initial_non_support_extruder_id));
float outer_wall_speed = print.default_region_config().outer_wall_speed.value; float outer_wall_speed = print.default_region_config().outer_wall_speed.value;

View file

@ -239,7 +239,10 @@ std::vector<unsigned int> ToolOrdering::generate_first_layer_tool_order(const Pr
int extruder_id = layerm->region().config().option("wall_filament")->getInt(); int extruder_id = layerm->region().config().option("wall_filament")->getInt();
for (auto expoly : layerm->raw_slices) { for (auto expoly : layerm->raw_slices) {
if (offset_ex(expoly, -0.2 * scale_(print.config().initial_layer_line_width)).empty()) const double nozzle_diameter = print.config().nozzle_diameter.get_at(0);
const coordf_t initial_layer_line_width = print.config().get_abs_value("initial_layer_line_width", nozzle_diameter);
if (offset_ex(expoly, -0.2 * scale_(initial_layer_line_width)).empty())
continue; continue;
double contour_area = expoly.contour.area(); double contour_area = expoly.contour.area();
@ -279,7 +282,10 @@ std::vector<unsigned int> ToolOrdering::generate_first_layer_tool_order(const Pr
for (auto layerm : first_layer->regions()) { for (auto layerm : first_layer->regions()) {
int extruder_id = layerm->region().config().option("wall_filament")->getInt(); int extruder_id = layerm->region().config().option("wall_filament")->getInt();
for (auto expoly : layerm->raw_slices) { for (auto expoly : layerm->raw_slices) {
if (offset_ex(expoly, -0.2 * scale_(object.config().line_width)).empty()) const double nozzle_diameter = object.print()->config().nozzle_diameter.get_at(0);
const coordf_t line_width = object.config().get_abs_value("line_width", nozzle_diameter);
if (offset_ex(expoly, -0.2 * scale_(line_width)).empty())
continue; continue;
double contour_area = expoly.contour.area(); double contour_area = expoly.contour.area();

View file

@ -175,6 +175,7 @@ void Layer::make_perimeters()
&& config.filter_out_gap_fill.value == other_config.filter_out_gap_fill.value && config.filter_out_gap_fill.value == other_config.filter_out_gap_fill.value
&& config.detect_overhang_wall == other_config.detect_overhang_wall && config.detect_overhang_wall == other_config.detect_overhang_wall
&& config.opt_serialize("inner_wall_line_width") == other_config.opt_serialize("inner_wall_line_width") && config.opt_serialize("inner_wall_line_width") == other_config.opt_serialize("inner_wall_line_width")
&& config.opt_serialize("outer_wall_line_width") == other_config.opt_serialize("outer_wall_line_width")
&& config.detect_thin_wall == other_config.detect_thin_wall && config.detect_thin_wall == other_config.detect_thin_wall
//&& config.wall_infill_order == other_config.wall_infill_order //&& config.wall_infill_order == other_config.wall_infill_order
&& config.infill_wall_overlap == other_config.infill_wall_overlap && config.infill_wall_overlap == other_config.infill_wall_overlap

View file

@ -1545,7 +1545,7 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
//BBS: spacing according to width and layer height //BBS: spacing according to width and layer height
float extrusion_spacing{ 0.f }; float extrusion_spacing{ 0.f };
}; };
auto layer_color_stat = [&layers = std::as_const(layers)](const size_t layer_idx, const size_t color_idx) -> LayerColorStat { auto layer_color_stat = [&layers = std::as_const(layers), &print_object](const size_t layer_idx, const size_t color_idx) -> LayerColorStat {
LayerColorStat out; LayerColorStat out;
const Layer &layer = *layers[layer_idx]; const Layer &layer = *layers[layer_idx];
for (const LayerRegion *region : layer.regions()) for (const LayerRegion *region : layer.regions())
@ -1554,16 +1554,18 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
// As this region may split existing regions, we collect statistics over all regions for color_idx == 0. // As this region may split existing regions, we collect statistics over all regions for color_idx == 0.
color_idx == 0 || config.wall_filament == int(color_idx)) { color_idx == 0 || config.wall_filament == int(color_idx)) {
//BBS: the extrusion line width is outer wall rather than inner wall //BBS: the extrusion line width is outer wall rather than inner wall
out.extrusion_width = std::max<float>(out.extrusion_width, float(config.outer_wall_line_width)); const double nozzle_diameter = print_object.print()->config().nozzle_diameter.get_at(0);
double outer_wall_line_width = config.get_abs_value("outer_wall_line_width", nozzle_diameter);
out.extrusion_width = std::max<float>(out.extrusion_width, outer_wall_line_width);
out.top_shell_layers = std::max<int>(out.top_shell_layers, config.top_shell_layers); out.top_shell_layers = std::max<int>(out.top_shell_layers, config.top_shell_layers);
out.bottom_shell_layers = std::max<int>(out.bottom_shell_layers, config.bottom_shell_layers); out.bottom_shell_layers = std::max<int>(out.bottom_shell_layers, config.bottom_shell_layers);
out.small_region_threshold = config.gap_infill_speed.value > 0 ? out.small_region_threshold = config.gap_infill_speed.value > 0 ?
// Gap fill enabled. Enable a single line of 1/2 extrusion width. // Gap fill enabled. Enable a single line of 1/2 extrusion width.
0.5f * float(config.outer_wall_line_width) : 0.5f * outer_wall_line_width :
// Gap fill disabled. Enable two lines slightly overlapping. // Gap fill disabled. Enable two lines slightly overlapping.
float(config.outer_wall_line_width) + 0.7f * Flow::rounded_rectangle_extrusion_spacing(float(config.outer_wall_line_width), float(layer.height)); outer_wall_line_width + 0.7f * Flow::rounded_rectangle_extrusion_spacing(outer_wall_line_width, float(layer.height));
out.small_region_threshold = scaled<float>(out.small_region_threshold * 0.5f); out.small_region_threshold = scaled<float>(out.small_region_threshold * 0.5f);
out.extrusion_spacing = Flow::rounded_rectangle_extrusion_spacing(float(config.outer_wall_line_width), float(layer.height)); out.extrusion_spacing = Flow::rounded_rectangle_extrusion_spacing(float(outer_wall_line_width), float(layer.height));
++ out.num_regions; ++ out.num_regions;
} }
assert(out.num_regions > 0); assert(out.num_regions > 0);

View file

@ -1019,15 +1019,13 @@ void PerimeterGenerator::process_classic()
// get the real top surface // get the real top surface
ExPolygons grown_lower_slices; ExPolygons grown_lower_slices;
ExPolygons bridge_checker; ExPolygons bridge_checker;
// BBS: check whether surface be bridge or not auto nozzle_diameter = this->print_config->nozzle_diameter.get_at(this->config->wall_filament - 1);
// Check whether surface be bridge or not
if (this->lower_slices != NULL) { if (this->lower_slices != NULL) {
// BBS: get the Polygons below the polygon this layer // BBS: get the Polygons below the polygon this layer
Polygons lower_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*this->lower_slices, last_box); Polygons lower_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*this->lower_slices, last_box);
double bridge_offset = std::max(double(ext_perimeter_spacing), (double(perimeter_width))); double bridge_offset = std::max(double(ext_perimeter_spacing), (double(perimeter_width)));
// SoftFever: improve bridging // SoftFever: improve bridging
auto nozzle_diameter =
this->print_config->nozzle_diameter.get_at(this->config->wall_filament - 1);
const float bridge_margin = const float bridge_margin =
std::min(float(scale_(BRIDGE_INFILL_MARGIN)), std::min(float(scale_(BRIDGE_INFILL_MARGIN)),
float(scale_(nozzle_diameter * BRIDGE_INFILL_MARGIN / 0.4))); float(scale_(nozzle_diameter * BRIDGE_INFILL_MARGIN / 0.4)));
@ -1047,7 +1045,8 @@ void PerimeterGenerator::process_classic()
// increase by half peri the inner space to fill the frontier between last and stored. // increase by half peri the inner space to fill the frontier between last and stored.
top_fills = union_ex(top_fills, top_polygons); top_fills = union_ex(top_fills, top_polygons);
//set the clip to the external wall but go back inside by infill_extrusion_width/2 to be sure the extrusion won't go outside even with a 100% overlap. //set the clip to the external wall but go back inside by infill_extrusion_width/2 to be sure the extrusion won't go outside even with a 100% overlap.
double infill_spacing_unscaled = this->config->sparse_infill_line_width.value; double infill_spacing_unscaled = this->config->sparse_infill_line_width.get_abs_value(nozzle_diameter);
if (infill_spacing_unscaled == 0) infill_spacing_unscaled = Flow::auto_extrusion_width(frInfill, nozzle_diameter);
fill_clip = offset_ex(last, double(ext_perimeter_spacing / 2) - scale_(infill_spacing_unscaled / 2)); fill_clip = offset_ex(last, double(ext_perimeter_spacing / 2) - scale_(infill_spacing_unscaled / 2));
//ExPolygons oldLast = last; //ExPolygons oldLast = last;

View file

@ -1099,13 +1099,9 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
return ("One or more object were assigned an extruder that the printer does not have."); return ("One or more object were assigned an extruder that the printer does not have.");
#endif #endif
auto validate_extrusion_width = [/*min_nozzle_diameter,*/ max_nozzle_diameter](const ConfigBase &config, const char *opt_key, double layer_height, std::string &err_msg) -> bool { auto validate_extrusion_width = [min_nozzle_diameter, max_nozzle_diameter](const ConfigBase &config, const char *opt_key, double layer_height, std::string &err_msg) -> bool {
// This may change in the future, if we switch to "extrusion width wrt. nozzle diameter" double extrusion_width_min = config.get_abs_value(opt_key, min_nozzle_diameter);
// instead of currently used logic "extrusion width wrt. layer height", see GH issues #1923 #2829. double extrusion_width_max = config.get_abs_value(opt_key, max_nozzle_diameter);
// double extrusion_width_min = config.get_abs_value(opt_key, min_nozzle_diameter);
// double extrusion_width_max = config.get_abs_value(opt_key, max_nozzle_diameter);
double extrusion_width_min = config.get_abs_value(opt_key);
double extrusion_width_max = config.get_abs_value(opt_key);
if (extrusion_width_min == 0) { if (extrusion_width_min == 0) {
// Default "auto-generated" extrusion width is always valid. // Default "auto-generated" extrusion width is always valid.
} else if (extrusion_width_min <= layer_height) { } else if (extrusion_width_min <= layer_height) {
@ -1297,10 +1293,10 @@ double Print::skirt_first_layer_height() const
Flow Print::brim_flow() const Flow Print::brim_flow() const
{ {
ConfigOptionFloat width = m_config.initial_layer_line_width; ConfigOptionFloatOrPercent width = m_config.initial_layer_line_width;
if (width.value == 0) if (width.value <= 0)
width = m_print_regions.front()->config().inner_wall_line_width; width = m_print_regions.front()->config().inner_wall_line_width;
if (width.value == 0) if (width.value <= 0)
width = m_objects.front()->config().line_width; width = m_objects.front()->config().line_width;
/* We currently use a random region's perimeter extruder. /* We currently use a random region's perimeter extruder.
@ -1310,6 +1306,7 @@ Flow Print::brim_flow() const
generation as well. */ generation as well. */
return Flow::new_from_config_width( return Flow::new_from_config_width(
frPerimeter, frPerimeter,
// Flow::new_from_config_width takes care of the percent to value substitution
width, width,
(float)m_config.nozzle_diameter.get_at(m_print_regions.front()->config().wall_filament-1), (float)m_config.nozzle_diameter.get_at(m_print_regions.front()->config().wall_filament-1),
(float)this->skirt_first_layer_height()); (float)this->skirt_first_layer_height());
@ -1317,8 +1314,8 @@ Flow Print::brim_flow() const
Flow Print::skirt_flow() const Flow Print::skirt_flow() const
{ {
ConfigOptionFloat width = m_config.initial_layer_line_width; ConfigOptionFloatOrPercent width = m_config.initial_layer_line_width;
if (width.value == 0) if (width.value <= 0)
width = m_objects.front()->config().line_width; width = m_objects.front()->config().line_width;
/* We currently use a random object's support material extruder. /* We currently use a random object's support material extruder.
@ -1328,6 +1325,7 @@ Flow Print::skirt_flow() const
generation as well. */ generation as well. */
return Flow::new_from_config_width( return Flow::new_from_config_width(
frPerimeter, frPerimeter,
// Flow::new_from_config_width takes care of the percent to value substitution
width, width,
(float)m_config.nozzle_diameter.get_at(m_objects.front()->config().support_filament-1), (float)m_config.nozzle_diameter.get_at(m_objects.front()->config().support_filament-1),
(float)this->skirt_first_layer_height()); (float)this->skirt_first_layer_height());

View file

@ -1057,14 +1057,17 @@ void PrintConfigDef::init_fff_params()
def->enum_labels = def_top_fill_pattern->enum_labels; def->enum_labels = def_top_fill_pattern->enum_labels;
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipRectilinear)); def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipRectilinear));
def = this->add("outer_wall_line_width", coFloat); def = this->add("outer_wall_line_width", coFloatOrPercent);
def->label = L("Outer wall"); def->label = L("Outer wall");
def->category = L("Quality"); def->category = L("Quality");
def->tooltip = L("Line width of outer wall"); def->tooltip = L("Line width of outer wall. If expressed as a %, it will be computed over the nozzle diameter.");
def->sidetext = L("mm"); def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0; def->min = 0;
def->max = 1000;
def->max_literal = 10;
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0)); def->set_default_value(new ConfigOptionFloatOrPercent(0., false));
def = this->add("outer_wall_speed", coFloat); def = this->add("outer_wall_speed", coFloat);
def->label = L("Outer wall"); def->label = L("Outer wall");
@ -1208,15 +1211,17 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats { 0.02 }); def->set_default_value(new ConfigOptionFloats { 0.02 });
def = this->add("line_width", coFloat); def = this->add("line_width", coFloatOrPercent);
def->label = L("Default"); def->label = L("Default");
def->category = L("Quality"); def->category = L("Quality");
def->tooltip = L("Default line width if some line width is set to be zero"); def->tooltip = L("Default line width if other line widths are set to 0. If expressed as a %, it will be computed over the nozzle diameter.");
def->sidetext = L("mm"); def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0; def->min = 0;
def->max = 10; def->max = 1000;
def->max_literal = 10;
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.4)); def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
def = this->add("reduce_fan_stop_start_freq", coBools); def = this->add("reduce_fan_stop_start_freq", coBools);
def->label = L("Keep fan always on"); def->label = L("Keep fan always on");
@ -1637,14 +1642,18 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(12)); def->set_default_value(new ConfigOptionFloat(12));
def = this->add("initial_layer_line_width", coFloat); def = this->add("initial_layer_line_width", coFloatOrPercent);
def->label = L("Initial layer"); def->label = L("Initial layer");
def->category = L("Quality"); def->category = L("Quality");
def->tooltip = L("Line width of initial layer"); def->tooltip = L("Line width of initial layer. If expressed as a %, it will be computed over the nozzle diameter.");
def->sidetext = L("mm"); def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0; def->min = 0;
def->max = 1000;
def->max_literal = 10;
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.4)); def->set_default_value(new ConfigOptionFloatOrPercent(0., false));
def = this->add("initial_layer_print_height", coFloat); def = this->add("initial_layer_print_height", coFloat);
def->label = L("Initial layer height"); def->label = L("Initial layer height");
@ -1942,14 +1951,17 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(1)); def->set_default_value(new ConfigOptionInt(1));
def = this->add("sparse_infill_line_width", coFloat); def = this->add("sparse_infill_line_width", coFloatOrPercent);
def->label = L("Sparse infill"); def->label = L("Sparse infill");
def->category = L("Quality"); def->category = L("Quality");
def->tooltip = L("Line width of internal sparse infill"); def->tooltip = L("Line width of internal sparse infill. If expressed as a %, it will be computed over the nozzle diameter.");
def->sidetext = L("mm"); def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0; def->min = 0;
def->max = 1000;
def->max_literal = 10;
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.4)); def->set_default_value(new ConfigOptionFloatOrPercent(0., false));
def = this->add("infill_wall_overlap", coPercent); def = this->add("infill_wall_overlap", coPercent);
def->label = L("Infill/Wall overlap"); def->label = L("Infill/Wall overlap");
@ -2374,14 +2386,17 @@ void PrintConfigDef::init_fff_params()
def->mode = comDevelop; def->mode = comDevelop;
def->set_default_value(new ConfigOptionInt(1)); def->set_default_value(new ConfigOptionInt(1));
def = this->add("inner_wall_line_width", coFloat); def = this->add("inner_wall_line_width", coFloatOrPercent);
def->label = L("Inner wall"); def->label = L("Inner wall");
def->category = L("Quality"); def->category = L("Quality");
def->tooltip = L("Line width of inner wall"); def->tooltip = L("Line width of inner wall. If expressed as a %, it will be computed over the nozzle diameter.");
def->sidetext = L("mm"); def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0; def->min = 0;
def->max = 1000;
def->max_literal = 10;
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.4)); def->set_default_value(new ConfigOptionFloatOrPercent(0., false));
def = this->add("inner_wall_speed", coFloat); def = this->add("inner_wall_speed", coFloat);
def->label = L("Inner wall"); def->label = L("Inner wall");
@ -2773,14 +2788,17 @@ void PrintConfigDef::init_fff_params()
def->mode = comDevelop; def->mode = comDevelop;
def->set_default_value(new ConfigOptionInt(1)); def->set_default_value(new ConfigOptionInt(1));
def = this->add("internal_solid_infill_line_width", coFloat); def = this->add("internal_solid_infill_line_width", coFloatOrPercent);
def->label = L("Internal solid infill"); def->label = L("Internal solid infill");
def->category = L("Quality"); def->category = L("Quality");
def->tooltip = L("Line width of internal solid infill"); def->tooltip = L("Line width of internal solid infill. If expressed as a %, it will be computed over the nozzle diameter.");
def->sidetext = L("mm"); def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0; def->min = 0;
def->max = 1000;
def->max_literal = 10;
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.4)); def->set_default_value(new ConfigOptionFloatOrPercent(0., false));
def = this->add("internal_solid_infill_speed", coFloat); def = this->add("internal_solid_infill_speed", coFloat);
def->label = L("Internal solid infill"); def->label = L("Internal solid infill");
@ -2995,14 +3013,17 @@ void PrintConfigDef::init_fff_params()
def->mode = comSimple; def->mode = comSimple;
def->set_default_value(new ConfigOptionInt(1)); def->set_default_value(new ConfigOptionInt(1));
def = this->add("support_line_width", coFloat); def = this->add("support_line_width", coFloatOrPercent);
def->label = L("Support"); def->label = L("Support");
def->category = L("Quality"); def->category = L("Quality");
def->tooltip = L("Line width of support"); def->tooltip = L("Line width of support. If expressed as a %, it will be computed over the nozzle diameter.");
def->sidetext = L("mm"); def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0; def->min = 0;
def->max = 1000;
def->max_literal = 10;
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.4)); def->set_default_value(new ConfigOptionFloatOrPercent(0., false));
def = this->add("support_interface_loop_pattern", coBool); def = this->add("support_interface_loop_pattern", coBool);
def->label = L("Interface use loop pattern"); def->label = L("Interface use loop pattern");
@ -3318,14 +3339,17 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString("")); def->set_default_value(new ConfigOptionString(""));
def = this->add("top_surface_line_width", coFloat); def = this->add("top_surface_line_width", coFloatOrPercent);
def->label = L("Top surface"); def->label = L("Top surface");
def->category = L("Quality"); def->category = L("Quality");
def->tooltip = L("Line width for top surfaces"); def->tooltip = L("Line width for top surfaces. If expressed as a %, it will be computed over the nozzle diameter.");
def->sidetext = L("mm"); def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0; def->min = 0;
def->max = 1000;
def->max_literal = 10;
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.4)); def->set_default_value(new ConfigOptionFloatOrPercent(0., false));
def = this->add("top_surface_speed", coFloat); def = this->add("top_surface_speed", coFloat);
def->label = L("Top surface"); def->label = L("Top surface");
@ -4993,7 +5017,7 @@ std::map<std::string, std::string> validate(const FullPrintConfig &cfg, bool und
"initial_layer_line_width" }; "initial_layer_line_width" };
for (size_t i = 0; i < sizeof(widths) / sizeof(widths[i]); ++ i) { for (size_t i = 0; i < sizeof(widths) / sizeof(widths[i]); ++ i) {
std::string key(widths[i]); std::string key(widths[i]);
if (cfg.get_abs_value(key) > 2.5 * max_nozzle_diameter) { if (cfg.get_abs_value(key, max_nozzle_diameter) > 2.5 * max_nozzle_diameter) {
error_message.emplace(key, L("too large line width ") + std::to_string(cfg.get_abs_value(key))); error_message.emplace(key, L("too large line width ") + std::to_string(cfg.get_abs_value(key)));
//return std::string("Too Large line width: ") + key; //return std::string("Too Large line width: ") + key;
} }

View file

@ -643,7 +643,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, bridge_no_support)) ((ConfigOptionBool, bridge_no_support))
((ConfigOptionFloat, elefant_foot_compensation)) ((ConfigOptionFloat, elefant_foot_compensation))
((ConfigOptionFloat, max_bridge_length)) ((ConfigOptionFloat, max_bridge_length))
((ConfigOptionFloat, line_width)) ((ConfigOptionFloatOrPercent, line_width))
// Force the generation of solid shells between adjacent materials/volumes. // Force the generation of solid shells between adjacent materials/volumes.
((ConfigOptionBool, interface_shells)) ((ConfigOptionBool, interface_shells))
((ConfigOptionFloat, layer_height)) ((ConfigOptionFloat, layer_height))
@ -667,7 +667,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, support_bottom_z_distance)) ((ConfigOptionFloat, support_bottom_z_distance))
((ConfigOptionInt, enforce_support_layers)) ((ConfigOptionInt, enforce_support_layers))
((ConfigOptionInt, support_filament)) ((ConfigOptionInt, support_filament))
((ConfigOptionFloat, support_line_width)) ((ConfigOptionFloatOrPercent, support_line_width))
((ConfigOptionBool, support_interface_loop_pattern)) ((ConfigOptionBool, support_interface_loop_pattern))
((ConfigOptionInt, support_interface_filament)) ((ConfigOptionInt, support_interface_filament))
((ConfigOptionInt, support_interface_top_layers)) ((ConfigOptionInt, support_interface_top_layers))
@ -727,7 +727,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, ensure_vertical_shell_thickness)) ((ConfigOptionBool, ensure_vertical_shell_thickness))
((ConfigOptionEnum<InfillPattern>, top_surface_pattern)) ((ConfigOptionEnum<InfillPattern>, top_surface_pattern))
((ConfigOptionEnum<InfillPattern>, bottom_surface_pattern)) ((ConfigOptionEnum<InfillPattern>, bottom_surface_pattern))
((ConfigOptionFloat, outer_wall_line_width)) ((ConfigOptionFloatOrPercent, outer_wall_line_width))
((ConfigOptionFloat, outer_wall_speed)) ((ConfigOptionFloat, outer_wall_speed))
((ConfigOptionFloat, infill_direction)) ((ConfigOptionFloat, infill_direction))
((ConfigOptionPercent, sparse_infill_density)) ((ConfigOptionPercent, sparse_infill_density))
@ -737,7 +737,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, fuzzy_skin_point_distance)) ((ConfigOptionFloat, fuzzy_skin_point_distance))
((ConfigOptionFloat, gap_infill_speed)) ((ConfigOptionFloat, gap_infill_speed))
((ConfigOptionInt, sparse_infill_filament)) ((ConfigOptionInt, sparse_infill_filament))
((ConfigOptionFloat, sparse_infill_line_width)) ((ConfigOptionFloatOrPercent, sparse_infill_line_width))
((ConfigOptionPercent, infill_wall_overlap)) ((ConfigOptionPercent, infill_wall_overlap))
((ConfigOptionFloat, sparse_infill_speed)) ((ConfigOptionFloat, sparse_infill_speed))
//BBS //BBS
@ -750,17 +750,17 @@ PRINT_CONFIG_CLASS_DEFINE(
// Detect bridging perimeters // Detect bridging perimeters
((ConfigOptionBool, detect_overhang_wall)) ((ConfigOptionBool, detect_overhang_wall))
((ConfigOptionInt, wall_filament)) ((ConfigOptionInt, wall_filament))
((ConfigOptionFloat, inner_wall_line_width)) ((ConfigOptionFloatOrPercent, inner_wall_line_width))
((ConfigOptionFloat, inner_wall_speed)) ((ConfigOptionFloat, inner_wall_speed))
// Total number of perimeters. // Total number of perimeters.
((ConfigOptionInt, wall_loops)) ((ConfigOptionInt, wall_loops))
((ConfigOptionFloat, minimum_sparse_infill_area)) ((ConfigOptionFloat, minimum_sparse_infill_area))
((ConfigOptionInt, solid_infill_filament)) ((ConfigOptionInt, solid_infill_filament))
((ConfigOptionFloat, internal_solid_infill_line_width)) ((ConfigOptionFloatOrPercent, internal_solid_infill_line_width))
((ConfigOptionFloat, internal_solid_infill_speed)) ((ConfigOptionFloat, internal_solid_infill_speed))
// Detect thin walls. // Detect thin walls.
((ConfigOptionBool, detect_thin_wall)) ((ConfigOptionBool, detect_thin_wall))
((ConfigOptionFloat, top_surface_line_width)) ((ConfigOptionFloatOrPercent, top_surface_line_width))
((ConfigOptionInt, top_shell_layers)) ((ConfigOptionInt, top_shell_layers))
((ConfigOptionFloat, top_shell_thickness)) ((ConfigOptionFloat, top_shell_thickness))
((ConfigOptionFloat, top_surface_speed)) ((ConfigOptionFloat, top_surface_speed))
@ -946,7 +946,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionFloat, travel_acceleration)) ((ConfigOptionFloat, travel_acceleration))
((ConfigOptionFloatOrPercent, sparse_infill_acceleration)) ((ConfigOptionFloatOrPercent, sparse_infill_acceleration))
((ConfigOptionFloatOrPercent, internal_solid_infill_acceleration)) ((ConfigOptionFloatOrPercent, internal_solid_infill_acceleration))
((ConfigOptionFloat, initial_layer_line_width)) ((ConfigOptionFloatOrPercent, initial_layer_line_width))
((ConfigOptionFloat, initial_layer_print_height)) ((ConfigOptionFloat, initial_layer_print_height))
((ConfigOptionFloat, initial_layer_speed)) ((ConfigOptionFloat, initial_layer_speed))
((ConfigOptionFloat, default_jerk)) ((ConfigOptionFloat, default_jerk))

View file

@ -423,7 +423,10 @@ static const float g_min_overhang_percent_for_lift = 0.3f;
void PrintObject::detect_overhangs_for_lift() void PrintObject::detect_overhangs_for_lift()
{ {
if (this->set_started(posDetectOverhangsForLift)) { if (this->set_started(posDetectOverhangsForLift)) {
const float min_overlap = m_config.line_width * g_min_overhang_percent_for_lift; const double nozzle_diameter = m_print->config().nozzle_diameter.get_at(0);
const coordf_t line_width = this->config().get_abs_value("line_width", nozzle_diameter);
const float min_overlap = line_width * g_min_overhang_percent_for_lift;
size_t num_layers = this->layer_count(); size_t num_layers = this->layer_count();
size_t num_raft_layers = m_slicing_params.raft_layers(); size_t num_raft_layers = m_slicing_params.raft_layers();
@ -433,14 +436,14 @@ void PrintObject::detect_overhangs_for_lift()
tbb::spin_mutex layer_storage_mutex; tbb::spin_mutex layer_storage_mutex;
tbb::parallel_for(tbb::blocked_range<size_t>(num_raft_layers + 1, num_layers), tbb::parallel_for(tbb::blocked_range<size_t>(num_raft_layers + 1, num_layers),
[this, min_overlap](const tbb::blocked_range<size_t>& range) [this, min_overlap, line_width](const tbb::blocked_range<size_t>& range)
{ {
for (size_t layer_id = range.begin(); layer_id < range.end(); ++layer_id) { for (size_t layer_id = range.begin(); layer_id < range.end(); ++layer_id) {
Layer& layer = *m_layers[layer_id]; Layer& layer = *m_layers[layer_id];
Layer& lower_layer = *layer.lower_layer; Layer& lower_layer = *layer.lower_layer;
ExPolygons overhangs = diff_ex(layer.lslices, offset_ex(lower_layer.lslices, scale_(min_overlap))); ExPolygons overhangs = diff_ex(layer.lslices, offset_ex(lower_layer.lslices, scale_(min_overlap)));
layer.loverhangs = std::move(offset2_ex(overhangs, -0.1f * scale_(m_config.line_width), 0.1f * scale_(m_config.line_width))); layer.loverhangs = std::move(offset2_ex(overhangs, -0.1f * scale_(line_width), 0.1f * scale_(line_width)));
} }
}); });
@ -2591,6 +2594,7 @@ SupportNecessaryType PrintObject::is_support_necessary()
#if 0 #if 0
double threshold_rad = (m_config.support_threshold_angle.value < EPSILON ? 30 : m_config.support_threshold_angle.value + 1) * M_PI / 180.; double threshold_rad = (m_config.support_threshold_angle.value < EPSILON ? 30 : m_config.support_threshold_angle.value + 1) * M_PI / 180.;
int enforce_support_layers = m_config.enforce_support_layers; int enforce_support_layers = m_config.enforce_support_layers;
// not fixing in extrusion width % PR b/c never called
const coordf_t extrusion_width = m_config.line_width.value; const coordf_t extrusion_width = m_config.line_width.value;
const coordf_t extrusion_width_scaled = scale_(extrusion_width); const coordf_t extrusion_width_scaled = scale_(extrusion_width);
float max_bridge_length = scale_(m_config.max_bridge_length.value); float max_bridge_length = scale_(m_config.max_bridge_length.value);

View file

@ -21,7 +21,7 @@ unsigned int PrintRegion::extruder(FlowRole role) const
Flow PrintRegion::flow(const PrintObject &object, FlowRole role, double layer_height, bool first_layer) const Flow PrintRegion::flow(const PrintObject &object, FlowRole role, double layer_height, bool first_layer) const
{ {
const PrintConfig &print_config = object.print()->config(); const PrintConfig &print_config = object.print()->config();
ConfigOptionFloat config_width; ConfigOptionFloatOrPercent config_width;
// Get extrusion width from configuration. // Get extrusion width from configuration.
// (might be an absolute value, or a percent value, or zero for auto) // (might be an absolute value, or a percent value, or zero for auto)
if (first_layer && print_config.initial_layer_line_width.value > 0) { if (first_layer && print_config.initial_layer_line_width.value > 0) {

View file

@ -2252,7 +2252,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
// check if the sharp tails should be extended higher // check if the sharp tails should be extended higher
bool detect_first_sharp_tail_only = false; bool detect_first_sharp_tail_only = false;
const coordf_t extrusion_width = m_object_config->line_width.value; const coordf_t extrusion_width = m_object_config->line_width.get_abs_value(object.print()->config().nozzle_diameter.get_at(object.config().support_interface_filament-1));
const coordf_t extrusion_width_scaled = scale_(extrusion_width); const coordf_t extrusion_width_scaled = scale_(extrusion_width);
if (is_auto(m_object_config->support_type.value) && g_config_support_sharp_tails && !detect_first_sharp_tail_only) { if (is_auto(m_object_config->support_type.value) && g_config_support_sharp_tails && !detect_first_sharp_tail_only) {
for (size_t layer_nr = 0; layer_nr < object.layer_count(); layer_nr++) { for (size_t layer_nr = 0; layer_nr < object.layer_count(); layer_nr++) {
@ -2345,7 +2345,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
// BBS group overhang clusters // BBS group overhang clusters
if (g_config_remove_small_overhangs) { if (g_config_remove_small_overhangs) {
std::vector<OverhangCluster> clusters; std::vector<OverhangCluster> clusters;
double fw_scaled = scale_(m_object_config->line_width); double fw_scaled = scale_(extrusion_width);
std::set<ExPolygon*> removed_overhang; std::set<ExPolygon*> removed_overhang;
for (size_t layer_id = layer_id_start; layer_id < num_layers; layer_id++) { for (size_t layer_id = layer_id_start; layer_id < num_layers; layer_id++) {

View file

@ -689,7 +689,12 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p
m_object_config->support_interface_pattern == smipConcentric ? m_object_config->support_interface_pattern == smipConcentric ?
ipConcentric : ipConcentric :
(m_support_params.interface_density > 0.95 ? ipRectilinear : ipSupportBase); (m_support_params.interface_density > 0.95 ? ipRectilinear : ipSupportBase);
m_support_params.support_extrusion_width = m_object_config->support_line_width.value > 0 ? m_object_config->support_line_width : m_object_config->line_width;
const auto nozzle_diameter = object.print()->config().nozzle_diameter.get_at(object.config().support_interface_filament-1);
const coordf_t extrusion_width = m_object_config->line_width.get_abs_value(nozzle_diameter);
const coordf_t support_extrusion_width = m_object_config->support_line_width.get_abs_value(nozzle_diameter);
m_support_params.support_extrusion_width = support_extrusion_width > 0 ? support_extrusion_width : extrusion_width;
is_slim = is_tree_slim(support_type, support_style); is_slim = is_tree_slim(support_type, support_style);
is_strong = is_tree(support_type) && support_style == smsTreeStrong; is_strong = is_tree(support_type) && support_style == smsTreeStrong;
MAX_BRANCH_RADIUS = 10.0; MAX_BRANCH_RADIUS = 10.0;
@ -723,7 +728,8 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only)
const PrintObjectConfig& config = m_object->config(); const PrintObjectConfig& config = m_object->config();
SupportType stype = support_type; SupportType stype = support_type;
const coordf_t radius_sample_resolution = g_config_tree_support_collision_resolution; const coordf_t radius_sample_resolution = g_config_tree_support_collision_resolution;
const coordf_t extrusion_width = config.line_width.value; const double nozzle_diameter = m_object->print()->config().nozzle_diameter.get_at(0);
const coordf_t extrusion_width = config.get_abs_value("line_width", nozzle_diameter);
const coordf_t extrusion_width_scaled = scale_(extrusion_width); const coordf_t extrusion_width_scaled = scale_(extrusion_width);
const coordf_t max_bridge_length = scale_(config.max_bridge_length.value); const coordf_t max_bridge_length = scale_(config.max_bridge_length.value);
const bool bridge_no_support = max_bridge_length > 0; const bool bridge_no_support = max_bridge_length > 0;
@ -2011,7 +2017,8 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
const size_t top_interface_layers = config.support_interface_top_layers.value; const size_t top_interface_layers = config.support_interface_top_layers.value;
const size_t bottom_interface_layers = config.support_interface_bottom_layers.value; const size_t bottom_interface_layers = config.support_interface_bottom_layers.value;
const double diameter_angle_scale_factor = tan(tree_support_branch_diameter_angle * M_PI / 180.);// * layer_height / branch_radius; //Scale factor per layer to produce the desired angle. const double diameter_angle_scale_factor = tan(tree_support_branch_diameter_angle * M_PI / 180.);// * layer_height / branch_radius; //Scale factor per layer to produce the desired angle.
const coordf_t line_width = config.support_line_width; const double nozzle_diameter = m_object->print()->config().nozzle_diameter.get_at(0);
const coordf_t line_width = config.get_abs_value("support_line_width", nozzle_diameter);
const coordf_t line_width_scaled = scale_(line_width); const coordf_t line_width_scaled = scale_(line_width);
const bool with_lightning_infill = m_support_params.base_fill_pattern == ipLightning; const bool with_lightning_infill = m_support_params.base_fill_pattern == ipLightning;
@ -2472,12 +2479,14 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
const size_t bottom_interface_layers = config.support_interface_bottom_layers.value; const size_t bottom_interface_layers = config.support_interface_bottom_layers.value;
const size_t top_interface_layers = config.support_interface_top_layers.value; const size_t top_interface_layers = config.support_interface_top_layers.value;
float DO_NOT_MOVER_UNDER_MM = is_slim ? 0 : 5; // do not move contact points under 5mm float DO_NOT_MOVER_UNDER_MM = is_slim ? 0 : 5; // do not move contact points under 5mm
const auto nozzle_diameter = m_object->print()->config().nozzle_diameter.get_at(m_object->config().support_interface_filament-1);
const auto support_line_width = config.support_line_width.get_abs_value(nozzle_diameter);
auto get_branch_angle = [this,&config](coordf_t radius) { auto get_branch_angle = [this,&config](coordf_t radius) {
if (config.tree_support_branch_angle.value < 30.0) return config.tree_support_branch_angle.value; if (config.tree_support_branch_angle.value < 30.0) return config.tree_support_branch_angle.value;
return (radius - MIN_BRANCH_RADIUS) / (MAX_BRANCH_RADIUS - MIN_BRANCH_RADIUS) * (config.tree_support_branch_angle.value - 30.0) + 30.0; return (radius - MIN_BRANCH_RADIUS) / (MAX_BRANCH_RADIUS - MIN_BRANCH_RADIUS) * (config.tree_support_branch_angle.value - 30.0) + 30.0;
}; };
auto get_max_move_dist = [this, &config, branch_radius, tip_layers, diameter_angle_scale_factor, wall_count, support_extrusion_width](const Node *node, int power = 1) { auto get_max_move_dist = [this, &config, branch_radius, tip_layers, diameter_angle_scale_factor, wall_count, support_extrusion_width, support_line_width](const Node *node, int power = 1) {
double move_dist = node->max_move_dist; double move_dist = node->max_move_dist;
if (node->max_move_dist == 0) { if (node->max_move_dist == 0) {
if (node->radius == 0) node->radius = calc_branch_radius(branch_radius, node->dist_mm_to_top, diameter_angle_scale_factor); if (node->radius == 0) node->radius = calc_branch_radius(branch_radius, node->dist_mm_to_top, diameter_angle_scale_factor);
@ -2485,7 +2494,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes)
if (angle > 30.0 && node->radius > MIN_BRANCH_RADIUS) if (angle > 30.0 && node->radius > MIN_BRANCH_RADIUS)
angle = (node->radius - MIN_BRANCH_RADIUS) / (MAX_BRANCH_RADIUS - MIN_BRANCH_RADIUS) * (config.tree_support_branch_angle.value - 30.0) + 30.0; angle = (node->radius - MIN_BRANCH_RADIUS) / (MAX_BRANCH_RADIUS - MIN_BRANCH_RADIUS) * (config.tree_support_branch_angle.value - 30.0) + 30.0;
double tan_angle = tan(angle * M_PI / 180); double tan_angle = tan(angle * M_PI / 180);
int wall_count_ = node->radius > 2 * config.support_line_width ? wall_count : 1; int wall_count_ = node->radius > 2 * support_line_width ? wall_count : 1;
node->max_move_dist = (angle < 90) ? (coordf_t) (tan_angle * node->height) * wall_count_ : std::numeric_limits<coordf_t>::max(); node->max_move_dist = (angle < 90) ? (coordf_t) (tan_angle * node->height) * wall_count_ : std::numeric_limits<coordf_t>::max();
node->max_move_dist = std::min(node->max_move_dist, support_extrusion_width); node->max_move_dist = std::min(node->max_move_dist, support_extrusion_width);
move_dist = node->max_move_dist; move_dist = node->max_move_dist;

View file

@ -166,8 +166,8 @@ public:
protected: protected:
double speed_first_layer() const { return m_config.option<ConfigOptionFloat>("initial_layer_speed")->value; }; double speed_first_layer() const { return m_config.option<ConfigOptionFloat>("initial_layer_speed")->value; };
double speed_perimeter() const { return m_config.option<ConfigOptionFloat>("outer_wall_speed")->value; }; double speed_perimeter() const { return m_config.option<ConfigOptionFloat>("outer_wall_speed")->value; };
double line_width_first_layer() const { return m_config.option<ConfigOptionFloat>("initial_layer_line_width")->value; }; double line_width_first_layer() const { return m_config.get_abs_value("initial_layer_line_width"); };
double line_width() const { return m_config.option<ConfigOptionFloat>("line_width")->value; }; double line_width() const { return m_config.get_abs_value("line_width"); };
int wall_count() const { return m_config.option<ConfigOptionInt>("wall_loops")->value; }; int wall_count() const { return m_config.option<ConfigOptionInt>("wall_loops")->value; };
private: private:

View file

@ -1390,7 +1390,7 @@ void PageDiameters::apply_custom_config(DynamicPrintConfig &config)
auto set_extrusion_width = [&config, opt_nozzle](const char *key, double dmr) { auto set_extrusion_width = [&config, opt_nozzle](const char *key, double dmr) {
char buf[64]; // locales don't matter here (sprintf/atof) char buf[64]; // locales don't matter here (sprintf/atof)
sprintf(buf, "%.2lf", dmr * opt_nozzle->values.front() / 0.4); sprintf(buf, "%.2lf", dmr * opt_nozzle->values.front() / 0.4);
config.set_key_value(key, new ConfigOptionFloat(atof(buf))); config.set_key_value(key, new ConfigOptionFloatOrPercent(atof(buf),false));
}; };
set_extrusion_width("support_line_width", 0.35); set_extrusion_width("support_line_width", 0.35);

View file

@ -1,4 +1,5 @@
#include "Plater.hpp" #include "Plater.hpp"
#include "libslic3r/Config.hpp"
#include <cstddef> #include <cstddef>
#include <algorithm> #include <algorithm>
@ -8155,7 +8156,7 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
double nozzle_diameter = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->get_at(0); double nozzle_diameter = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->get_at(0);
print_config.set_key_value( print_config.set_key_value(
opt.first, opt.first,
new ConfigOptionFloat(nozzle_diameter * opt.second / 100) new ConfigOptionFloatOrPercent(nozzle_diameter * opt.second / 100, false)
); );
} }
@ -8333,8 +8334,8 @@ void Plater::calib_flowrate(int pass) {
_obj->config.set_key_value("detect_thin_wall", new ConfigOptionBool(true)); _obj->config.set_key_value("detect_thin_wall", new ConfigOptionBool(true));
_obj->config.set_key_value("filter_out_gap_fill", new ConfigOptionFloat(0)); _obj->config.set_key_value("filter_out_gap_fill", new ConfigOptionFloat(0));
_obj->config.set_key_value("sparse_infill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear)); _obj->config.set_key_value("sparse_infill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear));
_obj->config.set_key_value("top_surface_line_width", new ConfigOptionFloat(nozzle_diameter * 1.2f)); _obj->config.set_key_value("top_surface_line_width", new ConfigOptionFloatOrPercent(nozzle_diameter * 1.2f, false));
_obj->config.set_key_value("internal_solid_infill_line_width", new ConfigOptionFloat(nozzle_diameter * 1.2f)); _obj->config.set_key_value("internal_solid_infill_line_width", new ConfigOptionFloatOrPercent(nozzle_diameter * 1.2f, false));
_obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum<InfillPattern>(ipMonotonic)); _obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum<InfillPattern>(ipMonotonic));
_obj->config.set_key_value("top_solid_infill_flow_ratio", new ConfigOptionFloat(1.0f)); _obj->config.set_key_value("top_solid_infill_flow_ratio", new ConfigOptionFloat(1.0f));
_obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum<InfillPattern>(ipMonotonic)); _obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum<InfillPattern>(ipMonotonic));
@ -8455,7 +8456,7 @@ void Plater::calib_max_vol_speed(const Calib_Params& params)
print_config->set_key_value("bottom_shell_layers", new ConfigOptionInt(1)); print_config->set_key_value("bottom_shell_layers", new ConfigOptionInt(1));
print_config->set_key_value("sparse_infill_density", new ConfigOptionPercent(0)); print_config->set_key_value("sparse_infill_density", new ConfigOptionPercent(0));
print_config->set_key_value("spiral_mode", new ConfigOptionBool(true)); print_config->set_key_value("spiral_mode", new ConfigOptionBool(true));
print_config->set_key_value("outer_wall_line_width", new ConfigOptionFloat(line_width)); print_config->set_key_value("outer_wall_line_width", new ConfigOptionFloatOrPercent(line_width, false));
print_config->set_key_value("initial_layer_print_height", new ConfigOptionFloat(layer_height)); print_config->set_key_value("initial_layer_print_height", new ConfigOptionFloat(layer_height));
print_config->set_key_value("layer_height", new ConfigOptionFloat(layer_height)); print_config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
obj->config.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterAndInner)); obj->config.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterAndInner));