mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-29 03:41:31 +00:00
Clamp Ironing Line Spacing to a Usable Minimum
An ironing line spacing of 0 reached the fillers from a 3MF, the CLI or the per-filament override, which has no GUI guard. Concentric ironing then never finished slicing, because a zero inset never shrinks the region, and rectilinear ironing was silently dropped. Tiny positive values produced an unprintable number of lines. Top surface and support ironing now clamp the spacing to the 0.05 mm floor the process GUI guard already enforces, so these configurations iron at that spacing. Spacings at or above the floor, including every shipped profile, are unchanged. The concentric filler also returns early on a non-positive step so no other caller can hang it, and the filament settings page now resets a too-small override the same way the process page does.
This commit is contained in:
@@ -1692,9 +1692,9 @@ void Layer::make_ironing()
|
|||||||
ironing_params.just_infill = false;
|
ironing_params.just_infill = false;
|
||||||
// ORCA: Get filament-specific overrides if configured, otherwise use process values
|
// ORCA: Get filament-specific overrides if configured, otherwise use process values
|
||||||
size_t extruder_idx = ironing_params.extruder - 1;
|
size_t extruder_idx = ironing_params.extruder - 1;
|
||||||
ironing_params.line_spacing = (!config.filament_ironing_spacing.is_nil(extruder_idx)
|
ironing_params.line_spacing = std::max(IRONING_SPACING_MIN, !config.filament_ironing_spacing.is_nil(extruder_idx)
|
||||||
? config.filament_ironing_spacing.get_at(extruder_idx)
|
? config.filament_ironing_spacing.get_at(extruder_idx)
|
||||||
: config.ironing_spacing);
|
: config.ironing_spacing.value);
|
||||||
ironing_params.inset = (!config.filament_ironing_inset.is_nil(extruder_idx)
|
ironing_params.inset = (!config.filament_ironing_inset.is_nil(extruder_idx)
|
||||||
? config.filament_ironing_inset.get_at(extruder_idx)
|
? config.filament_ironing_inset.get_at(extruder_idx)
|
||||||
: config.ironing_inset);
|
: config.ironing_inset);
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ void FillConcentric::_fill_surface_single(
|
|||||||
|
|
||||||
coord_t min_spacing = scale_(this->spacing) * params.multiline;
|
coord_t min_spacing = scale_(this->spacing) * params.multiline;
|
||||||
coord_t distance = coord_t(min_spacing / params.density);
|
coord_t distance = coord_t(min_spacing / params.density);
|
||||||
|
// A non-positive step never shrinks the region, so the inset loop below would not end.
|
||||||
|
if (min_spacing <= 0 || distance <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (params.density > 0.9999f && !params.dont_adjust) {
|
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||||
distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
|
distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
|
||||||
@@ -108,6 +111,8 @@ void FillConcentric::_fill_surface_single(const FillParams& params,
|
|||||||
// no rotation is supported for this infill pattern
|
// no rotation is supported for this infill pattern
|
||||||
Point bbox_size = expolygon.contour.bounding_box().size();
|
Point bbox_size = expolygon.contour.bounding_box().size();
|
||||||
coord_t min_spacing = scaled<coord_t>(this->spacing);
|
coord_t min_spacing = scaled<coord_t>(this->spacing);
|
||||||
|
if (min_spacing <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (params.density > 0.9999f && !params.dont_adjust) {
|
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||||
coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / min_spacing + 1;
|
coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / min_spacing + 1;
|
||||||
|
|||||||
@@ -178,6 +178,10 @@ enum class IroningType {
|
|||||||
Count,
|
Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Smallest usable ironing line spacing. Anything tighter yields an unprintable number of lines,
|
||||||
|
// and zero stops the fillers from making progress.
|
||||||
|
constexpr double IRONING_SPACING_MIN = 0.05;
|
||||||
|
|
||||||
//BBS
|
//BBS
|
||||||
enum class WallInfillOrder {
|
enum class WallInfillOrder {
|
||||||
InnerOuterInfill,
|
InnerOuterInfill,
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ struct SupportParameters {
|
|||||||
|
|
||||||
this->ironing = object_config.support_ironing;
|
this->ironing = object_config.support_ironing;
|
||||||
this->ironing_flow = support_material_interface_flow.with_height(support_material_interface_flow.height() * 0.01 * object_config.support_ironing_flow.value);
|
this->ironing_flow = support_material_interface_flow.with_height(support_material_interface_flow.height() * 0.01 * object_config.support_ironing_flow.value);
|
||||||
this->ironing_spacing = object_config.support_ironing_spacing;
|
this->ironing_spacing = std::max(IRONING_SPACING_MIN, object_config.support_ironing_spacing.value);
|
||||||
this->ironing_pattern = object_config.support_ironing_pattern;
|
this->ironing_pattern = object_config.support_ironing_pattern;
|
||||||
|
|
||||||
// Calculate a minimum support layer height as a minimum over all extruders, but not smaller than 10um.
|
// Calculate a minimum support layer height as a minimum over all extruders, but not smaller than 10um.
|
||||||
|
|||||||
@@ -210,6 +210,30 @@ void ConfigManipulation::check_filament_max_volumetric_speed(DynamicPrintConfig
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigManipulation::check_filament_ironing_spacing(DynamicPrintConfig *config)
|
||||||
|
{
|
||||||
|
const auto *opt = config->option<ConfigOptionFloatsNullable>("filament_ironing_spacing");
|
||||||
|
if (opt == nullptr)
|
||||||
|
return;
|
||||||
|
std::vector<double> values = opt->values;
|
||||||
|
bool reset = false;
|
||||||
|
for (size_t i = 0; i < values.size(); ++i)
|
||||||
|
if (!opt->is_nil(i) && values[i] < IRONING_SPACING_MIN) {
|
||||||
|
values[i] = 0.1;
|
||||||
|
reset = true;
|
||||||
|
}
|
||||||
|
if (!reset)
|
||||||
|
return;
|
||||||
|
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
||||||
|
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
||||||
|
DynamicPrintConfig new_conf = *config;
|
||||||
|
is_msg_dlg_already_exist = true;
|
||||||
|
dialog.ShowModal();
|
||||||
|
new_conf.set_key_value("filament_ironing_spacing", new ConfigOptionFloatsNullable(values));
|
||||||
|
apply(config, &new_conf);
|
||||||
|
is_msg_dlg_already_exist = false;
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigManipulation::check_chamber_temperature(DynamicPrintConfig* config)
|
void ConfigManipulation::check_chamber_temperature(DynamicPrintConfig* config)
|
||||||
{
|
{
|
||||||
bool support_chamber_temp_control=GUI::wxGetApp().preset_bundle->printers.get_selected_preset().config.opt_bool("support_chamber_temp_control");
|
bool support_chamber_temp_control=GUI::wxGetApp().preset_bundle->printers.get_selected_preset().config.opt_bool("support_chamber_temp_control");
|
||||||
@@ -332,7 +356,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
//BBS: ironing_spacing shouldn't be too small or equal to zero
|
//BBS: ironing_spacing shouldn't be too small or equal to zero
|
||||||
if (config->opt_float("ironing_spacing") < 0.05)
|
if (config->opt_float("ironing_spacing") < IRONING_SPACING_MIN)
|
||||||
{
|
{
|
||||||
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
||||||
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
||||||
@@ -343,7 +367,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
apply(config, &new_conf);
|
apply(config, &new_conf);
|
||||||
is_msg_dlg_already_exist = false;
|
is_msg_dlg_already_exist = false;
|
||||||
}
|
}
|
||||||
if (config->opt_float("support_ironing_spacing") < 0.05)
|
if (config->opt_float("support_ironing_spacing") < IRONING_SPACING_MIN)
|
||||||
{
|
{
|
||||||
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
||||||
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ public:
|
|||||||
void check_nozzle_temperature_initial_layer_range(DynamicPrintConfig* config);
|
void check_nozzle_temperature_initial_layer_range(DynamicPrintConfig* config);
|
||||||
void check_adaptive_pressure_advance_model(DynamicPrintConfig* config);
|
void check_adaptive_pressure_advance_model(DynamicPrintConfig* config);
|
||||||
void check_filament_max_volumetric_speed(DynamicPrintConfig *config);
|
void check_filament_max_volumetric_speed(DynamicPrintConfig *config);
|
||||||
|
void check_filament_ironing_spacing(DynamicPrintConfig *config);
|
||||||
void check_chamber_temperature(DynamicPrintConfig* config);
|
void check_chamber_temperature(DynamicPrintConfig* config);
|
||||||
void check_chamber_minimal_temperature(DynamicPrintConfig* config);
|
void check_chamber_minimal_temperature(DynamicPrintConfig* config);
|
||||||
bool check_layer_height(DynamicPrintConfig* config);
|
bool check_layer_height(DynamicPrintConfig* config);
|
||||||
|
|||||||
@@ -4905,6 +4905,7 @@ void TabFilament::update()
|
|||||||
return; // ys_FIXME
|
return; // ys_FIXME
|
||||||
|
|
||||||
m_config_manipulation.check_filament_max_volumetric_speed(m_config);
|
m_config_manipulation.check_filament_max_volumetric_speed(m_config);
|
||||||
|
m_config_manipulation.check_filament_ironing_spacing(m_config);
|
||||||
|
|
||||||
m_update_cnt++;
|
m_update_cnt++;
|
||||||
|
|
||||||
|
|||||||
@@ -747,6 +747,61 @@ TEST_CASE("A region with ironing turned off is never ironed", "[Fill]")
|
|||||||
REQUIRE(Layer::choose_ironing_extruder(cfg, spiral_mode, /*is_topmost_layer=*/true) == -1);
|
REQUIRE(Layer::choose_ironing_extruder(cfg, spiral_mode, /*is_topmost_layer=*/true) == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ironing path count and total length in mm, over the whole object.
|
||||||
|
static std::pair<size_t, double> ironing_extent(const Print &print)
|
||||||
|
{
|
||||||
|
size_t paths = 0;
|
||||||
|
double length = 0.;
|
||||||
|
for (const Layer *layer : print.objects().front()->layers())
|
||||||
|
for (const LayerRegion *region : layer->regions())
|
||||||
|
for (const ExtrusionEntity *entity : region->fills.flatten().entities)
|
||||||
|
if (ironing_role(entity->role())) {
|
||||||
|
++paths;
|
||||||
|
length += unscale<double>(entity->length());
|
||||||
|
}
|
||||||
|
return {paths, length};
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Ironing spacing below the minimum irons at the minimum spacing", "[Fill]")
|
||||||
|
{
|
||||||
|
const std::string pattern = GENERATE("rectilinear", "concentric");
|
||||||
|
const bool via_filament = GENERATE(false, true);
|
||||||
|
const double spacing = GENERATE(0., 0.001);
|
||||||
|
CAPTURE(pattern, via_filament, spacing);
|
||||||
|
|
||||||
|
auto ironing_for = [&pattern, via_filament](double spacing) {
|
||||||
|
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||||
|
config.set_deserialize_strict({{"ironing_type", "top"},
|
||||||
|
{"ironing_pattern", pattern},
|
||||||
|
{"layer_height", 0.2}});
|
||||||
|
// The filament override replaces the process spacing, which stays at a usable value.
|
||||||
|
if (via_filament)
|
||||||
|
config.set_deserialize_strict({{"ironing_spacing", 0.1}, {"filament_ironing_spacing", spacing}});
|
||||||
|
else
|
||||||
|
config.set_deserialize_strict({{"ironing_spacing", spacing}});
|
||||||
|
Print print;
|
||||||
|
Slic3r::Test::init_and_process_print({Slic3r::Test::cube(20)}, print, config);
|
||||||
|
return ironing_extent(print);
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::pair<size_t, double> clamped = ironing_for(spacing);
|
||||||
|
const std::pair<size_t, double> minimum = ironing_for(IRONING_SPACING_MIN);
|
||||||
|
REQUIRE(minimum.first > 0);
|
||||||
|
CHECK(clamped.first == minimum.first);
|
||||||
|
CHECK_THAT(clamped.second, Catch::Matchers::WithinRel(minimum.second, 1e-9));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Concentric fill at zero spacing returns without paths", "[Fill]")
|
||||||
|
{
|
||||||
|
std::unique_ptr<Fill> filler(Fill::new_from_type(ipConcentric));
|
||||||
|
filler->spacing = 0.;
|
||||||
|
filler->bounding_box = BoundingBox(Point(0, 0), Point::new_scale(10, 10));
|
||||||
|
FillParams params;
|
||||||
|
params.density = 1.f;
|
||||||
|
Surface surface(stTop, ExPolygon({Point(0, 0), Point::new_scale(10, 0), Point::new_scale(10, 10), Point::new_scale(0, 10)}));
|
||||||
|
CHECK(filler->fill_surface(&surface, params).empty());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Solid infill direction offsets every layer when no template is set", "[Fill]")
|
TEST_CASE("Solid infill direction offsets every layer when no template is set", "[Fill]")
|
||||||
{
|
{
|
||||||
auto angles_for = [](int direction) {
|
auto angles_for = [](int direction) {
|
||||||
|
|||||||
Reference in New Issue
Block a user