Various infill improvements (#2716)

* Fix issue that sparse infill threshold no longer working

* Turn all internal sparse infill into solid infill if infill density is 100%

* Allow combining solid infill when sparse infill density is 100%
This commit is contained in:
Noisyfox 2023-11-29 21:28:23 +08:00 committed by GitHub
parent d48c279762
commit 0fa884d9ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 41 additions and 61 deletions

View file

@ -446,6 +446,24 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
RegionExpansionParameters::build(expansion_top, expansion_step, max_nr_expansion_steps), RegionExpansionParameters::build(expansion_top, expansion_step, max_nr_expansion_steps),
sparse, expansion_params_into_sparse_infill, closing_radius); sparse, expansion_params_into_sparse_infill, closing_radius);
// turn too small internal regions into solid regions according to the user setting
if (!this->layer()->object()->print()->config().spiral_mode && this->region().config().sparse_infill_density.value > 0) {
// scaling an area requires two calls!
double min_area = scale_(scale_(this->region().config().minimum_sparse_infill_area.value));
ExPolygons small_regions{};
sparse.erase(std::remove_if(sparse.begin(), sparse.end(), [min_area, &small_regions](ExPolygon& ex_polygon) {
if (ex_polygon.area() <= min_area) {
small_regions.push_back(ex_polygon);
return true;
}
return false;
}), sparse.end());
if (!small_regions.empty()) {
shells = union_ex(shells, small_regions);
}
}
// m_fill_surfaces.remove_types({ stBottomBridge, stBottom, stTop, stInternal, stInternalSolid }); // m_fill_surfaces.remove_types({ stBottomBridge, stBottom, stTop, stInternal, stInternalSolid });
this->fill_surfaces.clear(); this->fill_surfaces.clear();
reserve_more(this->fill_surfaces.surfaces, shells.size() + sparse.size() + bridges.size() + bottoms.size() + tops.size()); reserve_more(this->fill_surfaces.surfaces, shells.size() + sparse.size() + bridges.size() + bottoms.size() + tops.size());
@ -792,12 +810,10 @@ void LayerRegion::prepare_fill_surfaces()
surface.surface_type = stInternal; surface.surface_type = stInternal;
} }
// turn too small internal regions into solid regions according to the user setting if (!spiral_mode && fabs(this->region().config().sparse_infill_density.value - 100.) < EPSILON) {
if (! spiral_mode && this->region().config().sparse_infill_density.value > 0) { // Turn all internal sparse infill into solid infill, if sparse_infill_density is 100%
// scaling an area requires two calls!
double min_area = scale_(scale_(this->region().config().minimum_sparse_infill_area.value));
for (Surface &surface : this->fill_surfaces.surfaces) for (Surface &surface : this->fill_surfaces.surfaces)
if (surface.surface_type == stInternal && surface.area() <= min_area) if (surface.surface_type == stInternal)
surface.surface_type = stInternalSolid; surface.surface_type = stInternalSolid;
} }

View file

@ -1726,7 +1726,7 @@ def = this->add("filament_loading_speed", coFloats);
def = this->add("sparse_infill_density", coPercent); def = this->add("sparse_infill_density", coPercent);
def->label = L("Sparse infill density"); def->label = L("Sparse infill density");
def->category = L("Strength"); def->category = L("Strength");
def->tooltip = L("Density of internal sparse infill, 100% means solid throughout"); def->tooltip = L("Density of internal sparse infill, 100% turns all sparse infill into solid infill and internal solid infill pattern will be used");
def->sidetext = L("%"); def->sidetext = L("%");
def->min = 0; def->min = 0;
def->max = 100; def->max = 100;
@ -5711,12 +5711,6 @@ std::map<std::string, std::string> validate(const FullPrintConfig &cfg, bool und
error_message.emplace("internal_solid_infill_pattern", L("invalid value ") + cfg.internal_solid_infill_pattern.serialize()); error_message.emplace("internal_solid_infill_pattern", L("invalid value ") + cfg.internal_solid_infill_pattern.serialize());
} }
// --fill-density
if (fabs(cfg.sparse_infill_density.value - 100.) < EPSILON &&
! print_config_def.get("top_surface_pattern")->has_enum_value(cfg.sparse_infill_pattern.serialize())) {
error_message.emplace("sparse_infill_pattern", cfg.sparse_infill_pattern.serialize() + L(" doesn't work at 100%% density "));
}
// --skirt-height // --skirt-height
if (cfg.skirt_height < 0) { if (cfg.skirt_height < 0) {
error_message.emplace("skirt_height", L("invalid value ") + std::to_string(cfg.skirt_height)); error_message.emplace("skirt_height", L("invalid value ") + std::to_string(cfg.skirt_height));

View file

@ -3315,6 +3315,13 @@ void PrintObject::combine_infill()
const bool enable_combine_infill = region.config().infill_combination.value; const bool enable_combine_infill = region.config().infill_combination.value;
if (enable_combine_infill == false || region.config().sparse_infill_density == 0.) if (enable_combine_infill == false || region.config().sparse_infill_density == 0.)
continue; continue;
// Support internal solid infill when sparse_infill_density is 100%
const bool use_solid_infill = fabs(region.config().sparse_infill_density.value - 100.) < EPSILON;
const SurfaceType surface_type = use_solid_infill ? stInternalSolid : stInternal;
const InfillPattern infill_pattern = use_solid_infill ? region.config().internal_solid_infill_pattern :
region.config().sparse_infill_pattern;
// Limit the number of combined layers to the maximum height allowed by this regions' nozzle. // Limit the number of combined layers to the maximum height allowed by this regions' nozzle.
//FIXME limit the layer height to max_layer_height //FIXME limit the layer height to max_layer_height
double nozzle_diameter = std::min( double nozzle_diameter = std::min(
@ -3361,10 +3368,10 @@ void PrintObject::combine_infill()
layerms.emplace_back(m_layers[i]->regions()[region_id]); layerms.emplace_back(m_layers[i]->regions()[region_id]);
// We need to perform a multi-layer intersection, so let's split it in pairs. // We need to perform a multi-layer intersection, so let's split it in pairs.
// Initialize the intersection with the candidates of the lowest layer. // Initialize the intersection with the candidates of the lowest layer.
ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(stInternal)); ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(surface_type));
// Start looping from the second layer and intersect the current intersection with it. // Start looping from the second layer and intersect the current intersection with it.
for (size_t i = 1; i < layerms.size(); ++ i) for (size_t i = 1; i < layerms.size(); ++ i)
intersection = intersection_ex(layerms[i]->fill_surfaces.filter_by_type(stInternal), intersection); intersection = intersection_ex(layerms[i]->fill_surfaces.filter_by_type(surface_type), intersection);
double area_threshold = layerms.front()->infill_area_threshold(); double area_threshold = layerms.front()->infill_area_threshold();
if (! intersection.empty() && area_threshold > 0.) if (! intersection.empty() && area_threshold > 0.)
intersection.erase(std::remove_if(intersection.begin(), intersection.end(), intersection.erase(std::remove_if(intersection.begin(), intersection.end(),
@ -3384,21 +3391,21 @@ void PrintObject::combine_infill()
0.5f * layerms.back()->flow(frPerimeter).scaled_width() + 0.5f * layerms.back()->flow(frPerimeter).scaled_width() +
// Because fill areas for rectilinear and honeycomb are grown // Because fill areas for rectilinear and honeycomb are grown
// later to overlap perimeters, we need to counteract that too. // later to overlap perimeters, we need to counteract that too.
((region.config().sparse_infill_pattern == ipRectilinear || ((infill_pattern == ipRectilinear ||
region.config().sparse_infill_pattern == ipMonotonic || infill_pattern == ipMonotonic ||
region.config().sparse_infill_pattern == ipGrid || infill_pattern == ipGrid ||
region.config().sparse_infill_pattern == ipLine || infill_pattern == ipLine ||
region.config().sparse_infill_pattern == ipHoneycomb) ? 1.5f : 0.5f) * infill_pattern == ipHoneycomb) ? 1.5f : 0.5f) *
layerms.back()->flow(frSolidInfill).scaled_width(); layerms.back()->flow(frSolidInfill).scaled_width();
for (ExPolygon &expoly : intersection) for (ExPolygon &expoly : intersection)
polygons_append(intersection_with_clearance, offset(expoly, clearance_offset)); polygons_append(intersection_with_clearance, offset(expoly, clearance_offset));
for (LayerRegion *layerm : layerms) { for (LayerRegion *layerm : layerms) {
Polygons internal = to_polygons(std::move(layerm->fill_surfaces.filter_by_type(stInternal))); Polygons internal = to_polygons(std::move(layerm->fill_surfaces.filter_by_type(surface_type)));
layerm->fill_surfaces.remove_type(stInternal); layerm->fill_surfaces.remove_type(surface_type);
layerm->fill_surfaces.append(diff_ex(internal, intersection_with_clearance), stInternal); layerm->fill_surfaces.append(diff_ex(internal, intersection_with_clearance), surface_type);
if (layerm == layerms.back()) { if (layerm == layerms.back()) {
// Apply surfaces back with adjusted depth to the uppermost layer. // Apply surfaces back with adjusted depth to the uppermost layer.
Surface templ(stInternal, ExPolygon()); Surface templ(surface_type, ExPolygon());
templ.thickness = 0.; templ.thickness = 0.;
for (LayerRegion *layerm2 : layerms) for (LayerRegion *layerm2 : layerms)
templ.thickness += layerm2->layer()->height; templ.thickness += layerm2->layer()->height;

View file

@ -419,43 +419,6 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
} }
} }
if (config->option<ConfigOptionPercent>("sparse_infill_density")->value == 100) {
std::string sparse_infill_pattern = config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->serialize();
const auto &top_fill_pattern_values = config->def()->get("top_surface_pattern")->enum_values;
bool correct_100p_fill = std::find(top_fill_pattern_values.begin(), top_fill_pattern_values.end(), sparse_infill_pattern) != top_fill_pattern_values.end();
if (!correct_100p_fill) {
// get sparse_infill_pattern name from enum_labels for using this one at dialog_msg
const ConfigOptionDef *fill_pattern_def = config->def()->get("sparse_infill_pattern");
assert(fill_pattern_def != nullptr);
auto it_pattern = std::find(fill_pattern_def->enum_values.begin(), fill_pattern_def->enum_values.end(), sparse_infill_pattern);
assert(it_pattern != fill_pattern_def->enum_values.end());
if (it_pattern != fill_pattern_def->enum_values.end()) {
wxString msg_text = GUI::format_wxstr(_L("%1% infill pattern doesn't support 100%% density."),
_(fill_pattern_def->enum_labels[it_pattern - fill_pattern_def->enum_values.begin()]));
if (is_global_config)
msg_text += "\n" + _L("Switch to rectilinear pattern?\n"
"Yes - switch to rectilinear pattern automaticlly\n"
"No - reset density to default non 100% value automaticlly") + "\n";
MessageDialog dialog(m_msg_dlg_parent, msg_text, "",
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) );
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
auto answer = dialog.ShowModal();
if (!is_global_config || answer == wxID_YES) {
new_conf.set_key_value("sparse_infill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear));
sparse_infill_density = 100;
}
else
sparse_infill_density = wxGetApp().preset_bundle->prints.get_selected_preset().config.option<ConfigOptionPercent>("sparse_infill_density")->value;
new_conf.set_key_value("sparse_infill_density", new ConfigOptionPercent(sparse_infill_density));
apply(config, &new_conf);
if (cb_value_change)
cb_value_change("sparse_infill_density", sparse_infill_density);
is_msg_dlg_already_exist = false;
}
}
}
// BBS // BBS
static const char* keys[] = { "support_filament", "support_interface_filament"}; static const char* keys[] = { "support_filament", "support_interface_filament"};
for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) { for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {

View file

@ -1927,13 +1927,13 @@ void TabPrint::build()
optgroup->append_single_option_line("bottom_surface_pattern", "fill-patterns#Infill of the top surface and bottom surface"); optgroup->append_single_option_line("bottom_surface_pattern", "fill-patterns#Infill of the top surface and bottom surface");
optgroup->append_single_option_line("bottom_shell_layers"); optgroup->append_single_option_line("bottom_shell_layers");
optgroup->append_single_option_line("bottom_shell_thickness"); optgroup->append_single_option_line("bottom_shell_thickness");
optgroup->append_single_option_line("internal_solid_infill_pattern");
optgroup = page->new_optgroup(L("Infill"), L"param_infill"); optgroup = page->new_optgroup(L("Infill"), L"param_infill");
optgroup->append_single_option_line("sparse_infill_density"); optgroup->append_single_option_line("sparse_infill_density");
optgroup->append_single_option_line("sparse_infill_pattern", "fill-patterns#infill types and their properties of sparse"); optgroup->append_single_option_line("sparse_infill_pattern", "fill-patterns#infill types and their properties of sparse");
optgroup->append_single_option_line("infill_anchor"); optgroup->append_single_option_line("infill_anchor");
optgroup->append_single_option_line("infill_anchor_max"); optgroup->append_single_option_line("infill_anchor_max");
optgroup->append_single_option_line("internal_solid_infill_pattern");
optgroup->append_single_option_line("filter_out_gap_fill"); optgroup->append_single_option_line("filter_out_gap_fill");