diff --git a/resources/profiles/BBL.json b/resources/profiles/BBL.json index 08eac536a..a1c596665 100644 --- a/resources/profiles/BBL.json +++ b/resources/profiles/BBL.json @@ -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": [ diff --git a/resources/profiles/BBL/process/fdm_process_common.json b/resources/profiles/BBL/process/fdm_process_common.json index 1817ee635..50561639c 100644 --- a/resources/profiles/BBL/process/fdm_process_common.json +++ b/resources/profiles/BBL/process/fdm_process_common.json @@ -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" } \ No newline at end of file diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 6b8761520..635a2c1fd 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -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()) diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 2f28792e8..9c69580c4 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -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. diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index bec54fc7c..bd7523f66 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -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 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); diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index a8278e346..0cc6e288c 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -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 &boundary_src, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms) { assert(! infill_ordered.empty()); diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index 647738bd6..103710cfb 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -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::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; } diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index 64c0ce44d..860114530 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -996,7 +996,6 @@ static std::vector 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 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; } diff --git a/src/libslic3r/MultiPoint.cpp b/src/libslic3r/MultiPoint.cpp index 6a5f309fe..b0362f5b1 100644 --- a/src/libslic3r/MultiPoint.cpp +++ b/src/libslic3r/MultiPoint.cpp @@ -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); + } +} + } diff --git a/src/libslic3r/MultiPoint.hpp b/src/libslic3r/MultiPoint.hpp index cefce6f7d..605ce5512 100644 --- a/src/libslic3r/MultiPoint.hpp +++ b/src/libslic3r/MultiPoint.hpp @@ -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); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 7add4a0ce..217934ef8 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -849,7 +849,7 @@ static std::vector 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", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 62013be38..d8be72c96 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -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"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 0bcd910fe..246510f45 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -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)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 5ebd1cb82..49ba27ef8 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -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); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 0ea5dd61b..61c526eb8 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -557,15 +557,16 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in bool have_infill = config->option("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("sparse_infill_anchor_max")->value > 0; toggle_line("sparse_infill_anchor", has_infill_anchors); //cross zag - toggle_line("infill_shift_step", config->option>("sparse_infill_pattern")->value == InfillPattern::ipCrossZag); + bool is_cross_zag = config->option>("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>("sparse_infill_pattern")->value == InfillPattern::ipZigZag); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index e09939232..de30a1cd0 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -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");