Add fixed Ironing Angle setting for uniform surface finish (#11195)

* Initial working fixed ironing angle implemented with new Fixed ironing angle setting

* update documentation

* Combine Fill.is_using_template_angle and Fill.alternate_fill_direction into Fill.fixed_angle

* Rename SurfaceFillParams.is_using_template_angle to SurfaceFillParam.fixed_angle.
This commit is contained in:
Anson Liu
2025-11-03 01:21:01 -08:00
committed by GitHub
parent c105d42d09
commit c6e4ac1c4d
8 changed files with 43 additions and 24 deletions

View File

@@ -52,7 +52,17 @@ If this value is set to 0, the ironing toolpath will start directly at the perim
## Angle Offset
The angle of ironing lines offset relative to the top surface solid infill direction. Commonly used ironing angle offsets are 0°, 45°, and 90° each producing a [different surface finish](https://github.com/SoftFever/OrcaSlicer/issues/10834#issuecomment-3322628589) which will depend on your printer nozzle.
The angle of ironing lines offset relative to the top surface solid infill direction.
Commonly used ironing angle offsets are 0°, 45°, and 90° each producing a [different surface finish](https://github.com/SoftFever/OrcaSlicer/issues/10834#issuecomment-3322628589) which will depend on your printer nozzle.
## Fixed Angle
Use a fixed absolute angle for ironing that is not offset from the top surface infill direction. This results in an ironing finish that does not have alternating line directions and may result in a more uniform surface finish and reduced tiger striping effect when reflecting light.
Set the Ironing Angle Offset to an angle with optimal ironing angle offsets from all affected top surface solid infill directions.
Suggested fixed ironing angles are 0° and 90° if you are using the default solid infill direction of 45°.
## Speed

View File

@@ -227,8 +227,8 @@ struct SurfaceFillParams
coordf_t overlap = 0.;
// Angle as provided by the region config, in radians.
float angle = 0.f;
// Orca: is_using_template_angle
bool is_using_template_angle = false;
// Orca: fixed_angle
bool fixed_angle = false;
// Is bridging used for this fill? Bridging parameters may be used even if this->flow.bridge() is not set.
bool bridge;
// Non-negative for a bridge.
@@ -284,7 +284,7 @@ struct SurfaceFillParams
RETURN_COMPARE_NON_EQUAL(spacing);
RETURN_COMPARE_NON_EQUAL(overlap);
RETURN_COMPARE_NON_EQUAL(angle);
RETURN_COMPARE_NON_EQUAL(is_using_template_angle);
RETURN_COMPARE_NON_EQUAL(fixed_angle);
RETURN_COMPARE_NON_EQUAL(density);
RETURN_COMPARE_NON_EQUAL(multiline);
// RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
@@ -313,7 +313,7 @@ struct SurfaceFillParams
this->spacing == rhs.spacing &&
this->overlap == rhs.overlap &&
this->angle == rhs.angle &&
this->is_using_template_angle == rhs.is_using_template_angle &&
this->fixed_angle == rhs.fixed_angle &&
this->bridge == rhs.bridge &&
this->bridge_angle == rhs.bridge_angle &&
this->density == rhs.density &&
@@ -902,11 +902,11 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
if (params.extrusion_role == erInternalInfill) {
params.angle = calculate_infill_rotation_angle(layer.object(), layer.id(), region_config.infill_direction.value,
region_config.sparse_infill_rotate_template.value);
params.is_using_template_angle = !region_config.sparse_infill_rotate_template.value.empty();
params.fixed_angle = !region_config.sparse_infill_rotate_template.value.empty();
} else {
params.angle = calculate_infill_rotation_angle(layer.object(), layer.id(), region_config.solid_infill_direction.value,
region_config.solid_infill_rotate_template.value);
params.is_using_template_angle = !region_config.solid_infill_rotate_template.value.empty();
params.fixed_angle = !region_config.solid_infill_rotate_template.value.empty();
}
params.bridge_angle = float(surface.bridge_angle);
@@ -1094,7 +1094,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
const PrintRegionConfig &region_config = layerm.region().config();
params.angle = calculate_infill_rotation_angle(layer.object(), layer.id(), region_config.solid_infill_direction.value,
region_config.solid_infill_rotate_template.value);
params.is_using_template_angle = !region_config.solid_infill_rotate_template.value.empty();
params.fixed_angle = !region_config.solid_infill_rotate_template.value.empty();
// calculate the actual flow we'll be using for this infill
params.flow = layerm.flow(frSolidInfill);
@@ -1199,7 +1199,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
f->layer_id = this->id();
f->z = this->print_z;
f->angle = surface_fill.params.angle;
f->is_using_template_angle = surface_fill.params.is_using_template_angle;
f->fixed_angle = surface_fill.params.fixed_angle;
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
f->print_config = &this->object()->print()->config();
f->print_object_config = &this->object()->config();
@@ -1389,7 +1389,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
f->layer_id = this->id() - this->object()->get_layer(0)->id(); // We need to subtract raft layers.
f->z = this->print_z;
f->angle = surface_fill.params.angle;
f->is_using_template_angle = surface_fill.params.is_using_template_angle;
f->fixed_angle = surface_fill.params.fixed_angle;
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
f->print_config = &this->object()->print()->config();
f->print_object_config = &this->object()->config();
@@ -1462,7 +1462,7 @@ void Layer::make_ironing()
double height;
double speed;
double angle;
bool is_using_template_angle;
bool fixed_angle;
double inset;
bool operator<(const IroningParams &rhs) const {
@@ -1472,7 +1472,7 @@ void Layer::make_ironing()
RETURN_COMPARE_NON_EQUAL(height);
RETURN_COMPARE_NON_EQUAL(speed);
RETURN_COMPARE_NON_EQUAL(angle);
RETURN_COMPARE_NON_EQUAL(is_using_template_angle);
RETURN_COMPARE_NON_EQUAL(fixed_angle);
RETURN_COMPARE_NON_EQUAL(inset);
return false;
}
@@ -1484,7 +1484,7 @@ void Layer::make_ironing()
this->height == rhs.height &&
this->speed == rhs.speed &&
this->angle == rhs.angle &&
this->is_using_template_angle == rhs.is_using_template_angle &&
this->fixed_angle == rhs.fixed_angle &&
this->pattern == rhs.pattern &&
this->inset == rhs.inset;
}
@@ -1533,8 +1533,8 @@ void Layer::make_ironing()
ironing_params.inset = config.ironing_inset;
ironing_params.height = default_layer_height * 0.01 * config.ironing_flow;
ironing_params.speed = config.ironing_speed;
ironing_params.angle = calculate_infill_rotation_angle(this->object(), this->id(), config.solid_infill_direction.value, config.solid_infill_rotate_template.value) + config.ironing_angle * M_PI / 180.;
ironing_params.is_using_template_angle = !config.solid_infill_rotate_template.value.empty();
ironing_params.angle = (config.ironing_angle_fixed ? 0 : calculate_infill_rotation_angle(this->object(), this->id(), config.solid_infill_direction.value, config.solid_infill_rotate_template.value)) + config.ironing_angle * M_PI / 180.;
ironing_params.fixed_angle = config.ironing_angle_fixed || !config.solid_infill_rotate_template.value.empty();
ironing_params.pattern = config.ironing_pattern;
ironing_params.layerm = layerm;
by_extruder.emplace_back(ironing_params);
@@ -1630,7 +1630,7 @@ void Layer::make_ironing()
// Create the filler object.
f->spacing = ironing_params.line_spacing;
f->angle = float(ironing_params.angle);
f->is_using_template_angle = ironing_params.is_using_template_angle;
f->fixed_angle = ironing_params.fixed_angle;
f->link_max_length = (coord_t) scale_(3. * f->spacing);
double extrusion_height = ironing_params.height * f->spacing / nozzle_dmr;
float extrusion_width = Flow::rounded_rectangle_extrusion_width_from_spacing(float(nozzle_dmr), float(extrusion_height));

View File

@@ -304,10 +304,9 @@ std::pair<float, Point> Fill::_infill_direction(const Surface *surface) const
printf("Filling bridge with angle %f\n", surface->bridge_angle);
#endif /* SLIC3R_DEBUG */
out_angle = float(surface->bridge_angle);
} else if (this->layer_id != size_t(-1)) {
} else if (this->layer_id != size_t(-1) && !fixed_angle) {
// alternate fill direction
//Orca: if template angle is not empty, don't apply layer angle
if(!is_using_template_angle)
//Orca: Do not alternate direction if Fill.fixed_angle is true
out_angle += this->_layer_angle(this->layer_id / surface->thickness_layers);
} else {
// printf("Layer_ID undefined!\n");

View File

@@ -119,8 +119,9 @@ public:
coordf_t overlap;
// in radians, ccw, 0 = East
float angle;
// Orca: is_using_template_angle
bool is_using_template_angle{false};
// Orca: Fill direction is fixed absolute angle if SurfaceFillParams.fixed_angle or config.ironing_angle_fixed
bool fixed_angle{false};
// In scaled coordinates. Maximum lenght of a perimeter segment connecting two infill lines.
// Used by the FillRectilinear2, FillGrid2, FillTriangles, FillStars and FillCubic.
// If left to zero, the links will not be limited.
@@ -203,7 +204,7 @@ protected:
ExPolygon expolygon,
ThickPolylines& thick_polylines_out) {}
virtual float _layer_angle(size_t idx) const { return is_using_template_angle ? 0.f : (idx & 1) ? float(M_PI/2.) : 0.f; }
virtual float _layer_angle(size_t idx) const { return fixed_angle ? 0.f : (idx & 1) ? float(M_PI/2.) : 0.f; }
virtual std::pair<float, Point> _infill_direction(const Surface *surface) const;

View File

@@ -888,7 +888,7 @@ static std::vector<std::string> s_Preset_print_options {
"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",
"align_infill_direction_to_model", "extra_solid_infills",
"minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern","gap_fill_target",
"ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "ironing_inset",
"ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "ironing_angle_fixed", "ironing_inset",
"support_ironing", "support_ironing_pattern", "support_ironing_flow", "support_ironing_spacing",
"max_travel_detour_distance",
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_mode", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence",

View File

@@ -3887,6 +3887,13 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("ironing_angle_fixed", coBool);
def->label = L("Fixed ironing angle");
def->category = L("Quality");
def->tooltip = L("Use a fixed absolute angle for ironing.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("layer_change_gcode", coString);
def->label = L("Layer change G-code");
def->tooltip = L("This G-code is inserted at every layer change after the Z lift.");

View File

@@ -1084,6 +1084,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, ironing_direction))
((ConfigOptionFloat, ironing_speed))
((ConfigOptionFloat, ironing_angle))
((ConfigOptionBool, ironing_angle_fixed))
// Detect bridging perimeters
((ConfigOptionBool, detect_overhang_wall))
((ConfigOptionInt, wall_filament))

View File

@@ -2339,6 +2339,7 @@ void TabPrint::build()
optgroup->append_single_option_line("ironing_spacing", "quality_settings_ironing#line-spacing");
optgroup->append_single_option_line("ironing_inset", "quality_settings_ironing#inset");
optgroup->append_single_option_line("ironing_angle", "quality_settings_ironing#angle-offset");
optgroup->append_single_option_line("ironing_angle_fixed", "quality_settings_ironing#fixed-angle");
optgroup = page->new_optgroup(L("Wall generator"), L"param_wall_generator");
optgroup->append_single_option_line("wall_generator", "quality_settings_wall_generator");