ENH: add cross zag pattern

Jira: none

Signed-off-by: qing.zhang <qing.zhang@bambulab.com>
Change-Id: If11f423db443b3f31f2181d4b0c56eaeb9a7ca5d
This commit is contained in:
qing.zhang 2025-02-12 17:39:38 +08:00 committed by lane.wei
parent d69fce58cb
commit 872726abed
12 changed files with 87 additions and 9 deletions

View File

@ -134,5 +134,7 @@
"xy_hole_compensation": "0",
"z_direction_outwall_speed_continuous": "0",
"enable_circle_compensation": "0",
"circle_compensation_manual_offset": "0"
"circle_compensation_manual_offset": "0",
"crosszag_move_step": "0.4",
"zigzag_angle_step": "0"
}

View File

@ -62,6 +62,8 @@ struct SurfaceFillParams
float sparse_infill_speed = 0;
float top_surface_speed = 0;
float solid_infill_speed = 0;
float crosszag_move_step = 0;// param for cross zag
float zigzag_angle_step = 0; // param for zig zag to get cross texture
bool operator<(const SurfaceFillParams &rhs) const {
#define RETURN_COMPARE_NON_EQUAL(KEY) if (this->KEY < rhs.KEY) return true; if (this->KEY > rhs.KEY) return false;
@ -88,6 +90,8 @@ struct SurfaceFillParams
RETURN_COMPARE_NON_EQUAL(sparse_infill_speed);
RETURN_COMPARE_NON_EQUAL(top_surface_speed);
RETURN_COMPARE_NON_EQUAL(solid_infill_speed);
RETURN_COMPARE_NON_EQUAL(crosszag_move_step);
RETURN_COMPARE_NON_EQUAL(zigzag_angle_step);
return false;
}
@ -108,7 +112,9 @@ struct SurfaceFillParams
this->extrusion_role == rhs.extrusion_role &&
this->sparse_infill_speed == rhs.sparse_infill_speed &&
this->top_surface_speed == rhs.top_surface_speed &&
this->solid_infill_speed == rhs.solid_infill_speed;
this->solid_infill_speed == rhs.solid_infill_speed &&
this->crosszag_move_step == rhs.crosszag_move_step &&
this->zigzag_angle_step == rhs.zigzag_angle_step;
}
};
@ -157,6 +163,10 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.extruder = layerm.region().extruder(extrusion_role);
params.pattern = region_config.sparse_infill_pattern.value;
params.density = float(region_config.sparse_infill_density);
if (params.pattern == ipCrossZag)
params.crosszag_move_step = scale_(region_config.crosszag_move_step);
if (params.pattern == ipZigZag)
params.zigzag_angle_step = region_config.zigzag_angle_step * M_PI / 360;
if (surface.is_solid()) {
params.density = 100.f;
@ -444,7 +454,12 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
f->z = this->print_z;
f->angle = surface_fill.params.angle;
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
if (surface_fill.params.pattern == ipZigZag) {
if (f->layer_id % 2 == 0)
f->angle -= surface_fill.params.zigzag_angle_step * (f->layer_id / 2);
else
f->angle += surface_fill.params.zigzag_angle_step * (f->layer_id / 2);
}
if (surface_fill.params.pattern == ipConcentricInternal) {
FillConcentricInternal *fill_concentric = dynamic_cast<FillConcentricInternal *>(f.get());
assert(fill_concentric != nullptr);
@ -491,6 +506,12 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.extrusion_role = surface_fill.params.extrusion_role;
params.using_internal_flow = using_internal_flow;
params.no_extrusion_overlap = surface_fill.params.overlap;
if (surface_fill.params.pattern == ipCrossZag) {
if (f->layer_id % 2 == 0)
params.horiz_move -= surface_fill.params.crosszag_move_step * (f->layer_id / 2);
else
params.horiz_move += surface_fill.params.crosszag_move_step * (f->layer_id / 2);
}
if (surface_fill.params.pattern == ipGrid)
params.can_reverse = false;
LayerRegion* layerm = this->m_regions[surface_fill.region_id];
@ -559,7 +580,8 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
case ipHilbertCurve:
case ipArchimedeanChords:
case ipOctagramSpiral:
case ipZigZag: break;
case ipZigZag:
case ipCrossZag: break;
}
// Create the filler object.

View File

@ -57,6 +57,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
// BBS: for bottom and top surface only
case ipMonotonicLine: return new FillMonotonicLineWGapFill();
case ipZigZag: return new FillZigZag();
case ipCrossZag: return new FillCrossZag();
default: throw Slic3r::InvalidArgument("unknown type");
}
}

View File

@ -76,6 +76,8 @@ struct FillParams
float no_extrusion_overlap{ 0.0 };
bool dont_sort{ false }; // do not sort the lines, just simply connect them
bool can_reverse{true};
float horiz_move{0.0}; //move infill to get cross zag pattern
};
static_assert(IsTriviallyCopyable<FillParams>::value, "FillParams class is not POD (and it should be - see constructor).");

View File

@ -2806,6 +2806,13 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
if (params.full_infill())
x0 += (line_spacing + coord_t(SCALED_EPSILON)) / 2;
int gap_line = params.horiz_move / line_spacing;
if (gap_line % 2 == 0) {
x0 += params.horiz_move - gap_line * line_spacing;
} else {
x0 += params.horiz_move - (gap_line - 1) * line_spacing;
n_vlines += 1;
}
#ifdef SLIC3R_DEBUG
static int iRun = 0;
BoundingBox bbox_svg = poly_with_offset.bounding_box_outer();

View File

@ -150,6 +150,16 @@ public:
bool has_consistent_pattern() const override { return true; }
};
class FillCrossZag : public FillRectilinear
{
public:
Fill *clone() const override { return new FillCrossZag(*this); }
~FillCrossZag() override = default;
bool has_consistent_pattern() const override { return true; }
};
Points sample_grid_pattern(const ExPolygon &expolygon, coord_t spacing, const BoundingBox &global_bounding_box);
Points sample_grid_pattern(const ExPolygons &expolygons, coord_t spacing, const BoundingBox &global_bounding_box);
Points sample_grid_pattern(const Polygons &polygons, coord_t spacing, const BoundingBox &global_bounding_box);

View File

@ -849,7 +849,7 @@ static std::vector<std::string> s_Preset_print_options {
"detect_overhang_wall",
"smooth_speed_discontinuity_area","smooth_coefficient",
"seam_position", "wall_sequence", "is_infill_first", "sparse_infill_density", "sparse_infill_pattern", "sparse_infill_anchor", "sparse_infill_anchor_max",
"top_surface_pattern", "bottom_surface_pattern", "internal_solid_infill_pattern", "infill_direction", "bridge_angle",
"top_surface_pattern", "bottom_surface_pattern", "internal_solid_infill_pattern", "infill_direction", "bridge_angle","crosszag_move_step", "zigzag_angle_step",
"minimum_sparse_infill_area", "reduce_infill_retraction", "ironing_pattern", "ironing_type",
"ironing_flow", "ironing_speed", "ironing_spacing","ironing_direction", "ironing_inset",
"max_travel_detour_distance",

View File

@ -149,7 +149,8 @@ static t_config_enum_values s_keys_map_InfillPattern {
{ "supportcubic", ipSupportCubic },
{ "lightning", ipLightning },
{ "crosshatch", ipCrossHatch},
{ "zigzag", ipZigZag }
{ "zigzag", ipZigZag },
{ "crosszag", ipCrossZag }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InfillPattern)
@ -1965,6 +1966,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("lightning");
def->enum_values.push_back("crosshatch");
def->enum_values.push_back("zigzag");
def->enum_values.push_back("crosszag");
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Grid"));
@ -1984,6 +1986,7 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back(L("Lightning"));
def->enum_labels.push_back(L("Cross Hatch"));
def->enum_labels.push_back(L("Zig Zag"));
def->enum_labels.push_back(L("Cross Zag"));
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipCubic));
def = this->add("top_surface_acceleration", coFloats);
@ -2374,6 +2377,26 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("crosszag_move_step", coFloat);
def->label = L("Cross Zag Move Step");
def->category = L("Strength");
def->tooltip = L("move infill a bit to get cross texture.");
def->sidetext = L("mm");
def->min = 0;
def->max = 10;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.4));
def = this->add("zigzag_angle_step", coFloat);
def->label = L("Zig Zag Angle Step");
def->category = L("Strength");
def->tooltip = L("rotate infill of each layer to get cross texture.");
def->sidetext = L("°");
def->min = 0;
def->max = 360;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
auto def_infill_anchor_min = def = this->add("sparse_infill_anchor", coFloatOrPercent);
def->label = L("Length of sparse infill anchor");
def->category = L("Strength");

View File

@ -54,7 +54,7 @@ enum AuthorizationType {
enum InfillPattern : int {
ipConcentric, ipRectilinear, ipGrid, ipLine, ipCubic, ipTriangles, ipStars, ipGyroid, ipHoneycomb, ipAdaptiveCubic, ipMonotonic, ipMonotonicLine, ipAlignedRectilinear, ip3DHoneycomb,
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSupportCubic, ipSupportBase, ipConcentricInternal,
ipLightning, ipCrossHatch, ipZigZag,
ipLightning, ipCrossHatch, ipZigZag, ipCrossZag,
ipCount,
};
@ -896,6 +896,8 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, outer_wall_line_width))
((ConfigOptionFloatsNullable, outer_wall_speed))
((ConfigOptionFloat, infill_direction))
((ConfigOptionFloat, crosszag_move_step))
((ConfigOptionFloat, zigzag_angle_step))
((ConfigOptionPercent, sparse_infill_density))
((ConfigOptionEnum<InfillPattern>, sparse_infill_pattern))
((ConfigOptionEnum<FuzzySkinType>, fuzzy_skin))

View File

@ -1087,7 +1087,9 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "top_surface_line_width"
|| opt_key == "initial_layer_line_width") {
steps.emplace_back(posInfill);
} else if (opt_key == "sparse_infill_pattern") {
} else if (opt_key == "sparse_infill_pattern"
|| opt_key == "crosszag_move_step"
|| opt_key == "zigzag_angle_step") {
steps.emplace_back(posPrepareInfill);
} else if (opt_key == "sparse_infill_density") {
// One likely wants to reslice only when switching between zero infill to simulate boolean difference (subtracting volumes),

View File

@ -558,12 +558,17 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in
bool have_infill = config->option<ConfigOptionPercent>("sparse_infill_density")->value > 0;
// sparse_infill_filament uses the same logic as in Print::extruders()
for (auto el : { "sparse_infill_pattern", "sparse_infill_anchor_max", "infill_combination",
"minimum_sparse_infill_area", "sparse_infill_filament"})
"minimum_sparse_infill_area", "sparse_infill_filament","crosszag_move_step","zigzag_angle_step"})
toggle_line(el, have_infill);
// Only allow configuration of open anchors if the anchoring is enabled.
bool has_infill_anchors = have_infill && config->option<ConfigOptionFloatOrPercent>("sparse_infill_anchor_max")->value > 0;
toggle_line("sparse_infill_anchor", has_infill_anchors);
//cross zag
toggle_line("crosszag_move_step", config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value == InfillPattern::ipCrossZag);
toggle_line("zigzag_angle_step", config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value == InfillPattern::ipZigZag);
bool has_spiral_vase = config->opt_bool("spiral_mode");
toggle_line("spiral_mode_smooth", has_spiral_vase);
toggle_line("spiral_mode_max_xy_smoothing", config->opt_bool("spiral_mode_smooth"));

View File

@ -2094,6 +2094,8 @@ void TabPrint::build()
optgroup = page->new_optgroup(L("Sparse infill"), L"param_infill");
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("crosszag_move_step");
optgroup->append_single_option_line("zigzag_angle_step");
optgroup->append_single_option_line("sparse_infill_anchor");
optgroup->append_single_option_line("sparse_infill_anchor_max");
optgroup->append_single_option_line("filter_out_gap_fill");