Top/bottom surface pattern density (#9783)

* Create top surface density option

* Update tooltip

* Specify what 0% top infill means

* Add density for bottom layers

* Discourage users from using top/bottom density incorrectly

* Fix percent don't need translation

* Fix incorrect indentation

---------

Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
This commit is contained in:
Jonathan Dyrekilde Sommerlund
2025-06-23 04:28:21 +02:00
committed by GitHub
parent 88fb8187d9
commit 51d844af2c
7 changed files with 93 additions and 63 deletions

View File

@@ -657,30 +657,30 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
if (params.pattern == ipCrossZag || params.pattern == ipLockedZag) {
params.symmetric_infill_y_axis = region_config.symmetric_infill_y_axis;
} else if (params.pattern == ipZigZag) {
params.symmetric_infill_y_axis = region_config.symmetric_infill_y_axis;
}
if (surface.is_solid()) {
params.density = 100.f;
//FIXME for non-thick bridges, shall we allow a bottom surface pattern?
if (surface.is_solid_infill())
params.pattern = region_config.internal_solid_infill_pattern.value;
else if (surface.is_external() && ! is_bridge) {
if(surface.is_top())
if (surface.is_external() && !is_bridge) {
if (surface.is_top()) {
params.pattern = region_config.top_surface_pattern.value;
else
params.density = float(region_config.top_surface_density);
} else { // Surface is bottom
params.pattern = region_config.bottom_surface_pattern.value;
}
else {
if(region_config.top_surface_pattern == ipMonotonic || region_config.top_surface_pattern == ipMonotonicLine)
params.density = float(region_config.bottom_surface_density);
}
} else if (surface.is_solid_infill()) {
params.pattern = region_config.internal_solid_infill_pattern.value;
params.density = 100.f;
} else {
if (region_config.top_surface_pattern == ipMonotonic || region_config.top_surface_pattern == ipMonotonicLine)
params.pattern = ipMonotonic;
else
params.pattern = ipRectilinear;
params.density = 100.f;
}
} else if (params.density <= 0)
continue;
} else if (params.density <= 0)
continue;
params.extrusion_role = erInternalInfill;
if (is_bridge) {
@@ -1029,7 +1029,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.resolution = resolution;
params.use_arachne = surface_fill.params.pattern == ipConcentric || surface_fill.params.pattern == ipConcentricInternal;
params.layer_height = layerm->layer()->height;
params.lattice_angle_1 = surface_fill.params.lattice_angle_1;
params.lattice_angle_1 = surface_fill.params.lattice_angle_1;
params.lattice_angle_2 = surface_fill.params.lattice_angle_2;
params.infill_overhang_angle = surface_fill.params.infill_overhang_angle;
@@ -1041,7 +1041,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
auto &region_config = layerm->region().config();
ConfigOptionFloats rotate_angles;
rotate_angles.deserialize( surface_fill.params.extrusion_role == erInternalInfill ? region_config.sparse_infill_rotate_template.value : region_config.solid_infill_rotate_template.value);
rotate_angles.deserialize( surface_fill.params.extrusion_role == erInternalInfill ? region_config.sparse_infill_rotate_template.value : region_config.solid_infill_rotate_template.value);
auto rotate_angle_idx = f->layer_id % rotate_angles.size();
f->rotate_angle = Geometry::deg2rad(rotate_angles.values[rotate_angle_idx]);
@@ -1149,7 +1149,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
case ipTpmsD:
case ipHilbertCurve:
case ipArchimedeanChords:
case ipOctagramSpiral:
case ipOctagramSpiral:
case ipZigZag:
case ipCrossZag:
case ipLockedZag: break;
@@ -1196,8 +1196,8 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
params.resolution = resolution;
params.use_arachne = false;
params.layer_height = layerm.layer()->height;
params.lattice_angle_1 = surface_fill.params.lattice_angle_1;
params.lattice_angle_2 = surface_fill.params.lattice_angle_2;
params.lattice_angle_1 = surface_fill.params.lattice_angle_1;
params.lattice_angle_2 = surface_fill.params.lattice_angle_2;
params.infill_overhang_angle = surface_fill.params.infill_overhang_angle;
for (ExPolygon &expoly : surface_fill.expolygons) {

View File

@@ -783,7 +783,7 @@ bool Preset::has_cali_lines(PresetBundle* preset_bundle)
static std::vector<std::string> s_Preset_print_options {
"layer_height", "initial_layer_print_height", "wall_loops", "alternate_extra_wall", "slice_closing_radius", "spiral_mode", "spiral_mode_smooth", "spiral_mode_max_xy_smoothing", "spiral_starting_flow_ratio", "spiral_finishing_flow_ratio", "slicing_mode",
"top_shell_layers", "top_shell_thickness", "bottom_shell_layers", "bottom_shell_thickness",
"top_shell_layers", "top_shell_thickness", "top_surface_density", "bottom_surface_density", "bottom_shell_layers", "bottom_shell_thickness",
"extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", "overhang_reverse", "overhang_reverse_threshold","overhang_reverse_internal_only", "wall_direction",
"seam_position", "staggered_inner_seams", "wall_sequence", "is_infill_first", "sparse_infill_density", "sparse_infill_pattern", "lattice_angle_1", "lattice_angle_2", "infill_overhang_angle", "top_surface_pattern", "bottom_surface_pattern",
"infill_direction", "solid_infill_direction", "counterbore_hole_bridging","infill_shift_step", "sparse_infill_rotate_template", "solid_infill_rotate_template", "symmetric_infill_y_axis","skeleton_infill_density", "infill_lock_depth", "skin_infill_depth", "skin_infill_density",

View File

@@ -5466,6 +5466,30 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->set_default_value(new ConfigOptionFloat(0.6));
def = this->add("top_surface_density", coPercent);
def->label = L("Top surface density");
def->category = L("Strength");
def->tooltip = L("Density of top surface layer. A value of 100% creates a fully solid, smooth top layer. "
"Reducing this value results in a textured top surface, according to the chosen top surface pattern. "
"A value of 0% will result in only the walls on the top layer being created. "
"Intended for aesthetic or functional purposes, not to fix issues such as over-extrusion.");
def->sidetext = ("%");
def->min = 0;
def->max = 100;
def->set_default_value(new ConfigOptionPercent(100));
def = this->add("bottom_surface_density", coPercent);
def->label = L("Bottom surface density");
def->category = L("Strength");
def->tooltip = L("Density of the bottom surface layer. "
"Intended for aesthetic or functional purposes, not to fix issues such as over-extrusion.\n"
"WARNING: Lowering this value may negatively affect bed adhesion.");
def->sidetext = ("%");
def->min = 10;
def->max = 100;
def->set_default_value(new ConfigOptionPercent(100));
def = this->add("travel_speed", coFloat);
def->label = L("Travel");
def->tooltip = L("Speed of travel which is faster and without extrusion.");

View File

@@ -939,6 +939,8 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, bridge_speed))
((ConfigOptionFloatOrPercent, internal_bridge_speed))
((ConfigOptionEnum<EnsureVerticalShellThickness>, ensure_vertical_shell_thickness))
((ConfigOptionPercent, top_surface_density))
((ConfigOptionPercent, bottom_surface_density))
((ConfigOptionEnum<InfillPattern>, top_surface_pattern))
((ConfigOptionEnum<InfillPattern>, bottom_surface_pattern))
((ConfigOptionEnum<InfillPattern>, internal_solid_infill_pattern))

View File

@@ -1092,6 +1092,8 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "infill_anchor"
|| opt_key == "infill_anchor_max"
|| opt_key == "top_surface_line_width"
|| opt_key == "top_surface_density"
|| opt_key == "bottom_surface_density"
|| opt_key == "initial_layer_line_width"
|| opt_key == "small_area_infill_flow_compensation"
|| opt_key == "lattice_angle_1"