ENH: get symmetric pattern

Jira: none

Signed-off-by: qing.zhang <qing.zhang@bambulab.com>
Change-Id: If428ead5f938ba4735786604468b1540d307142d
This commit is contained in:
qing.zhang 2025-02-17 14:24:38 +08:00 committed by lane.wei
parent 7cf078094c
commit f3c7411351
16 changed files with 82 additions and 19 deletions

View File

@ -1,7 +1,7 @@
{
"name": "Bambulab",
"url": "http://www.bambulab.com/Parameters/vendor/BBL.json",
"version": "02.00.00.52",
"version": "02.00.00.53",
"force_update": "0",
"description": "the initial version of BBL configurations",
"machine_model_list": [

View File

@ -139,5 +139,6 @@
"circle_compensation_manual_offset": "0",
"infill_shift_step": "0.4",
"infill_rotate_step": "0",
"prime_tower_enable_framework": "0"
"prime_tower_enable_framework": "0",
"symmetric_infill_y_axis": "false"
}

View File

@ -146,6 +146,13 @@ Point ExPolygon::point_projection(const Point &point) const
}
}
void ExPolygon::symmetric_y(const coord_t &y_axis)
{
this->contour.symmetric_y(y_axis);
for (Polygon &hole : holes)
hole.symmetric_y(y_axis);
}
bool ExPolygon::overlaps(const ExPolygon &other) const
{
if (this->empty() || other.empty())

View File

@ -56,7 +56,7 @@ public:
bool on_boundary(const Point &point, double eps) const;
// Projection of a point onto the polygon.
Point point_projection(const Point &point) const;
void symmetric_y(const coord_t &y_axis);
// Does this expolygon overlap another expolygon?
// Either the ExPolygons intersect, or one is fully inside the other,
// and it is not inside a hole of the other expolygon.

View File

@ -65,6 +65,8 @@ struct SurfaceFillParams
float infill_shift_step = 0;// param for cross zag
float infill_rotate_step = 0; // param for zig zag to get cross texture
bool symmetric_infill_y_axis = false;
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;
#define RETURN_COMPARE_NON_EQUAL_TYPED(TYPE, KEY) if (TYPE(this->KEY) < TYPE(rhs.KEY)) return true; if (TYPE(this->KEY) > TYPE(rhs.KEY)) return false;
@ -90,8 +92,9 @@ 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(infill_shift_step);
RETURN_COMPARE_NON_EQUAL(infill_rotate_step);
RETURN_COMPARE_NON_EQUAL(infill_shift_step);
RETURN_COMPARE_NON_EQUAL(infill_rotate_step);
RETURN_COMPARE_NON_EQUAL(symmetric_infill_y_axis);
return false;
}
@ -114,7 +117,8 @@ struct SurfaceFillParams
this->top_surface_speed == rhs.top_surface_speed &&
this->solid_infill_speed == rhs.solid_infill_speed &&
this->infill_shift_step == rhs.infill_shift_step &&
this->infill_rotate_step == rhs.infill_rotate_step;
this->infill_rotate_step == rhs.infill_rotate_step &&
this->symmetric_infill_y_axis == rhs.symmetric_infill_y_axis;
}
};
@ -163,8 +167,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.infill_shift_step = scale_(region_config.infill_shift_step);
if (params.pattern == ipCrossZag){
params.infill_shift_step = scale_(region_config.infill_shift_step);
params.symmetric_infill_y_axis = region_config.symmetric_infill_y_axis;
}
if (params.pattern == ipZigZag)
params.infill_rotate_step = region_config.infill_rotate_step * M_PI / 360;
@ -507,16 +513,26 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
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)
if (f->layer_id % 2 == 0) {
params.horiz_move -= surface_fill.params.infill_shift_step * (f->layer_id / 2);
else
} else {
params.horiz_move += surface_fill.params.infill_shift_step * (f->layer_id / 2);
}
params.symmetric_infill_y_axis = surface_fill.params.symmetric_infill_y_axis;
}
if (surface_fill.params.pattern == ipGrid)
params.can_reverse = false;
LayerRegion* layerm = this->m_regions[surface_fill.region_id];
for (ExPolygon& expoly : surface_fill.expolygons) {
f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}, ApplySafetyOffset::Yes);
f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}, ApplySafetyOffset::Yes);
if (params.symmetric_infill_y_axis) {
params.symmetric_y_axis = f->extended_object_bounding_box().center().x();
expoly.symmetric_y(params.symmetric_y_axis);
}
// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
f->spacing = surface_fill.params.spacing;
surface_fill.surface.expolygon = std::move(expoly);

View File

@ -1482,6 +1482,18 @@ BoundaryInfillGraph create_boundary_infill_graph(const Polylines &infill_ordered
return out;
}
// The extended bounding box of the whole object that covers any rotation of every layer.
BoundingBox Fill::extended_object_bounding_box() const
{
BoundingBox out = bounding_box;
out.merge(Point(out.min.y(), out.min.x()));
out.merge(Point(out.max.y(), out.max.x()));
// The bounding box is scaled by sqrt(2.) to ensure that the bounding box
// covers any possible rotations.
return out.scaled(sqrt(2.));
}
void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Polygon*> &boundary_src, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams &params)
{
assert(! infill_ordered.empty());

View File

@ -78,6 +78,8 @@ struct FillParams
bool can_reverse{true};
float horiz_move{0.0}; //move infill to get cross zag pattern
bool symmetric_infill_y_axis{false};
coord_t symmetric_y_axis{0};
};
static_assert(IsTriviallyCopyable<FillParams>::value, "FillParams class is not POD (and it should be - see constructor).");
@ -118,7 +120,7 @@ public:
static bool use_bridge_flow(const InfillPattern type);
void set_bounding_box(const Slic3r::BoundingBox &bbox) { bounding_box = bbox; }
BoundingBox extended_object_bounding_box() const;
// Use bridge flow for the fill?
virtual bool use_bridge_flow() const { return false; }

View File

@ -996,7 +996,6 @@ static std::vector<SegmentedIntersectionLine> slice_region_by_vertical_lines(con
throw;
}
#endif //INFILL_DEBUG_OUTPUT
return segs;
}
@ -2834,7 +2833,6 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
}
iRun ++;
#endif /* SLIC3R_DEBUG */
std::vector<SegmentedIntersectionLine> segs = slice_region_by_vertical_lines(poly_with_offset, n_vlines, x0, line_spacing);
// Connect by horizontal / vertical links, classify the links based on link_max_length as too long.
connect_segment_intersections_by_contours(poly_with_offset, segs, params, link_max_length);
@ -2908,6 +2906,11 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
//FIXME rather simplify the paths to avoid very short edges?
//assert(! it->has_duplicate_points());
it->remove_duplicate_points();
//get origin direction infill
if (params.symmetric_infill_y_axis) {
it->symmetric_y(params.symmetric_y_axis);
}
}
#ifdef SLIC3R_DEBUG
@ -2916,6 +2919,8 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
assert(! polyline.has_duplicate_points());
#endif /* SLIC3R_DEBUG */
return true;
}

View File

@ -469,4 +469,11 @@ BoundingBox get_extents_rotated(const MultiPoint &mp, double angle)
return get_extents_rotated(mp.points, angle);
}
void MultiPoint::symmetric_y(const coord_t &x_axis)
{
for (Point &pt : points) {
pt(0) = 2 * x_axis - pt(0);
}
}
}

View File

@ -95,7 +95,7 @@ public:
bool intersection(const Line& line, Point* intersection) const;
bool first_intersection(const Line& line, Point* intersection) const;
bool intersections(const Line &line, Points *intersections) const;
void symmetric_y(const coord_t &y_axis);
static Points _douglas_peucker(const Points &points, const double tolerance);
static Points visivalingam(const Points& pts, const double tolerance);
static Points concave_hull_2d(const Points& pts, const double tolerence);

View File

@ -849,7 +849,7 @@ static std::vector<std::string> s_Preset_print_options {
"detect_overhang_wall", "top_color_penetration_layers", "bottom_color_penetration_layers",
"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","infill_shift_step", "infill_rotate_step",
"top_surface_pattern", "bottom_surface_pattern", "internal_solid_infill_pattern", "infill_direction", "bridge_angle","infill_shift_step", "infill_rotate_step", "symmetric_infill_y_axis",
"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

@ -2424,6 +2424,14 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("symmetric_infill_y_axis", coBool);
def->label = L("Symmetric infill y axis");
def->category = L("Strength");
def->tooltip = L("If the model has two parts that are symmetric about the y-axis,"
" and you want these parts to have symmetric textures, please click this option on one of the parts.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
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

@ -902,6 +902,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, outer_wall_line_width))
((ConfigOptionFloatsNullable, outer_wall_speed))
((ConfigOptionFloat, infill_direction))
((ConfigOptionBool, symmetric_infill_y_axis))
((ConfigOptionFloat, infill_shift_step))
((ConfigOptionFloat, infill_rotate_step))
((ConfigOptionPercent, sparse_infill_density))

View File

@ -1090,6 +1090,7 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "initial_layer_line_width") {
steps.emplace_back(posInfill);
} else if (opt_key == "sparse_infill_pattern"
|| opt_key == "symmetric_infill_y_axis"
|| opt_key == "infill_shift_step"
|| opt_key == "infill_rotate_step") {
steps.emplace_back(posPrepareInfill);

View File

@ -557,15 +557,16 @@ 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","infill_shift_step","infill_rotate_step"})
for (auto el : { "sparse_infill_pattern", "sparse_infill_anchor_max", "infill_combination", "minimum_sparse_infill_area", "sparse_infill_filament", "infill_shift_step", "infill_rotate_step", "symmetric_infill_y_axis"})
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("infill_shift_step", config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value == InfillPattern::ipCrossZag);
bool is_cross_zag = config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value == InfillPattern::ipCrossZag;
for (auto el : {"infill_shift_step", "symmetric_infill_y_axis"})
toggle_line(el, is_cross_zag);
toggle_line("infill_rotate_step", config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value == InfillPattern::ipZigZag);

View File

@ -2093,6 +2093,8 @@ void TabPrint::build()
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("infill_shift_step");
optgroup->append_single_option_line("symmetric_infill_y_axis");
optgroup->append_single_option_line("infill_rotate_step");
optgroup->append_single_option_line("sparse_infill_anchor");
optgroup->append_single_option_line("sparse_infill_anchor_max");