diff --git a/resources/images/param_2dhoneycomb.svg b/resources/images/param_2dhoneycomb.svg new file mode 100644 index 0000000000..5c9112b38a --- /dev/null +++ b/resources/images/param_2dhoneycomb.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index ec4afe9e9d..a3d8b45323 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -69,6 +69,9 @@ struct SurfaceFillParams float lattice_angle_1 = 0.f; float lattice_angle_2 = 0.f; + // Params for 2D honeycomb + float infill_overhang_angle = 60.f; + 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; @@ -97,31 +100,33 @@ struct SurfaceFillParams RETURN_COMPARE_NON_EQUAL(solid_infill_speed); RETURN_COMPARE_NON_EQUAL(lattice_angle_1); RETURN_COMPARE_NON_EQUAL(lattice_angle_2); + RETURN_COMPARE_NON_EQUAL(infill_overhang_angle); return false; } - bool operator==(const SurfaceFillParams &rhs) const { - return this->extruder == rhs.extruder && - this->pattern == rhs.pattern && - this->spacing == rhs.spacing && - this->overlap == rhs.overlap && - this->angle == rhs.angle && - this->rotate_angle == rhs.rotate_angle && - this->bridge == rhs.bridge && - this->bridge_angle == rhs.bridge_angle && - this->density == rhs.density && -// this->dont_adjust == rhs.dont_adjust && - this->anchor_length == rhs.anchor_length && - this->anchor_length_max == rhs.anchor_length_max && - this->flow == rhs.flow && - 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->lattice_angle_1 == rhs.lattice_angle_1 && - this->lattice_angle_2 == rhs.lattice_angle_2; - } + bool operator==(const SurfaceFillParams &rhs) const { + return this->extruder == rhs.extruder && + this->pattern == rhs.pattern && + this->spacing == rhs.spacing && + this->overlap == rhs.overlap && + this->angle == rhs.angle && + this->rotate_angle == rhs.rotate_angle && + this->bridge == rhs.bridge && + this->bridge_angle == rhs.bridge_angle && + this->density == rhs.density && +// this->dont_adjust == rhs.dont_adjust && + this->anchor_length == rhs.anchor_length && + this->anchor_length_max == rhs.anchor_length_max && + this->flow == rhs.flow && + 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->lattice_angle_1 == rhs.lattice_angle_1 && + this->lattice_angle_2 == rhs.lattice_angle_2 && + this->infill_overhang_angle == rhs.infill_overhang_angle; + } }; struct SurfaceFill { @@ -622,6 +627,7 @@ std::vector group_fills(const Layer &layer) params.density = float(region_config.sparse_infill_density); params.lattice_angle_1 = region_config.lattice_angle_1; params.lattice_angle_2 = region_config.lattice_angle_2; + params.infill_overhang_angle = region_config.infill_overhang_angle; if (surface.is_solid()) { params.density = 100.f; @@ -966,6 +972,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: 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.infill_overhang_angle = surface_fill.params.infill_overhang_angle; // BBS params.flow = surface_fill.params.flow; @@ -1046,6 +1053,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc case ipLine: case ipConcentric: case ipHoneycomb: + case ip2DHoneycomb: case ip3DHoneycomb: case ipGyroid: case ipTpmsD: @@ -1097,6 +1105,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc 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.infill_overhang_angle = surface_fill.params.infill_overhang_angle; for (ExPolygon &expoly : surface_fill.expolygons) { // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 619f67036c..3b2f5bcc5c 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -40,6 +40,7 @@ Fill* Fill::new_from_type(const InfillPattern type) switch (type) { case ipConcentric: return new FillConcentric(); case ipHoneycomb: return new FillHoneycomb(); + case ip2DHoneycomb: return new Fill2DHoneycomb(); case ip3DHoneycomb: return new Fill3DHoneycomb(); case ipGyroid: return new FillGyroid(); case ipTpmsD: return new FillTpmsD();//from creality print diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index 01aaf38d28..62eeb9000e 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -73,6 +73,9 @@ struct FillParams coordf_t lattice_angle_1 { 0.f }; coordf_t lattice_angle_2 { 0.f }; + // For 2D Honeycomb + float infill_overhang_angle { 60 }; + // BBS Flow flow; ExtrusionRole extrusion_role{ ExtrusionRole(0) }; diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index 7fe310e14b..6948cfd799 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -3093,6 +3093,66 @@ Polylines FillQuarterCubic::fill_surface(const Surface* surface, const FillParam return polylines_out; } +Polylines Fill2DHoneycomb::fill_surface(const Surface *surface, const FillParams ¶ms) +{ + // the 2D honeycomb is generated based on a base pattern of an inverted Y with its junction at height zero + // | + // | + // 0 --+-- + // / \ + // why inverted? + // it makes determining some of the properties easier + // and the two angled legs provide additional horizontal stiffness + // the additional horizontal stiffness is not required close to the bed (unless you don't have any kind of bottom or flange) + + using namespace boost::math::float_constants; + + // lets begin calculating some base properties of the honeycomb pattern + const float half_horizontal_period = .5f * (1*(2/3.f) + 2*(1/3.f)) * float(spacing) / params.density; + const float vertical_period = 3 * half_horizontal_period / tanf(degree * float(params.infill_overhang_angle)); + + // we want to align the base pattern with its knot on height 0 + // therefore the double line part is 1/3 below and the single line is 2/3 above 0 + const float vertical_thirds_float = 3 * float(z) / vertical_period; + const int vertical_thirds_int = vertical_thirds_float; // converstion to int does implicit floor wich is desired here + const bool single_line = (vertical_thirds_int + 1) % 3; + + // the base pattern needs to be horizontally shifted by half every odd pattern layer + const bool odd_layer = ((vertical_thirds_int + 1) / 3) % 2; + const float horizontal_offset = odd_layer ? half_horizontal_period : 0; + + Polylines polylines_out; + + if (single_line) + { + FillParams multiline_params = params; + multiline_params.density *= 1 / (1*(2/3.) + 2*(1/3.)); + + if (!fill_surface_by_multilines( + surface, multiline_params, + { { half_pi, horizontal_offset } }, + polylines_out)) + BOOST_LOG_TRIVIAL(error) << "Fill2DHoneycomb::fill_surface() failed to fill a region."; + } else { + FillParams multiline_params = params; + multiline_params.density *= 2 / (1*(2/3.) + 2*(1/3.)); + + const float horizontal_position = (1 - (vertical_thirds_float - vertical_thirds_int)) * half_horizontal_period; + + if (!fill_surface_by_multilines( + surface, multiline_params, + { { half_pi, -horizontal_position + horizontal_offset }, { half_pi, horizontal_position + horizontal_offset } }, + polylines_out)) + BOOST_LOG_TRIVIAL(error) << "Fill2DHoneycomb::fill_surface() failed to fill a region."; + } + + if (this->layer_id % 2 == 1) + for (int i = 0; i < polylines_out.size(); i++) + std::reverse(polylines_out[i].begin(), polylines_out[i].end()); + + return polylines_out; +} + Polylines FillSupportBase::fill_surface(const Surface *surface, const FillParams ¶ms) { assert(! params.full_infill()); diff --git a/src/libslic3r/Fill/FillRectilinear.hpp b/src/libslic3r/Fill/FillRectilinear.hpp index 58f9afb1df..2dbcad3e90 100644 --- a/src/libslic3r/Fill/FillRectilinear.hpp +++ b/src/libslic3r/Fill/FillRectilinear.hpp @@ -132,6 +132,14 @@ protected: float _layer_angle(size_t idx) const override { return 0.f; } }; +class Fill2DHoneycomb : public FillAlignedRectilinear +{ +public: + Fill* clone() const override { return new Fill2DHoneycomb(*this); } + ~Fill2DHoneycomb() override = default; + Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override; +}; + class FillSupportBase : public FillRectilinear { diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index f6047fbbb1..e419b5497b 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -387,6 +387,7 @@ coordf_t Layer::get_sparse_infill_max_void_area() case ipAlignedRectilinear: case ipOctagramSpiral: case ipHilbertCurve: + case ip2DHoneycomb: case ip3DHoneycomb: case ipArchimedeanChords: max_void_area = std::max(max_void_area, spacing * spacing); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 2b9119ad5c..5586c4fcff 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -785,7 +785,7 @@ static std::vector 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", "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", "top_surface_pattern", "bottom_surface_pattern", + "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", "rotate_solid_infill_direction", "counterbore_hole_bridging", "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", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 650018208b..f134902819 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -152,6 +152,7 @@ static t_config_enum_values s_keys_map_InfillPattern { { "monotonic", ipMonotonic }, { "monotonicline", ipMonotonicLine }, { "alignedrectilinear", ipAlignedRectilinear }, + { "2dhoneycomb", ip2DHoneycomb }, { "3dhoneycomb", ip3DHoneycomb }, { "hilbertcurve", ipHilbertCurve }, { "archimedeanchords", ipArchimedeanChords }, @@ -2390,6 +2391,7 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("honeycomb"); def->enum_values.push_back("adaptivecubic"); def->enum_values.push_back("alignedrectilinear"); + def->enum_values.push_back("2dhoneycomb"); def->enum_values.push_back("3dhoneycomb"); def->enum_values.push_back("hilbertcurve"); def->enum_values.push_back("archimedeanchords"); @@ -2411,6 +2413,7 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Honeycomb")); def->enum_labels.push_back(L("Adaptive Cubic")); def->enum_labels.push_back(L("Aligned Rectilinear")); + def->enum_labels.push_back(L("2D Honeycomb")); def->enum_labels.push_back(L("3D Honeycomb")); def->enum_labels.push_back(L("Hilbert Curve")); def->enum_labels.push_back(L("Archimedean Chords")); @@ -2441,6 +2444,16 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(45)); + def = this->add("infill_overhang_angle", coFloat); + def->label = L("Infill overhang angle"); + def->category = L("Strength"); + def->tooltip = L("The angle of the infill angled lines. 60° will result in a pure honeycomb."); + def->sidetext = L("°"); + def->min = 15; + def->max = 75; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(60)); + auto def_infill_anchor_min = def = this->add("infill_anchor", coFloatOrPercent); def->label = L("Sparse infill anchor length"); def->category = L("Strength"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index fade4a9e3f..92f96761cd 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -58,7 +58,7 @@ enum AuthorizationType { }; enum InfillPattern : int { - ipConcentric, ipRectilinear, ipGrid, ip2DLattice, ipLine, ipCubic, ipTriangles, ipStars, ipGyroid, ipTpmsD, ipHoneycomb, ipAdaptiveCubic, ipMonotonic, ipMonotonicLine, ipAlignedRectilinear, ip3DHoneycomb, + ipConcentric, ipRectilinear, ipGrid, ip2DLattice, ipLine, ipCubic, ipTriangles, ipStars, ipGyroid, ipTpmsD, ipHoneycomb, ipAdaptiveCubic, ipMonotonic, ipMonotonicLine, ipAlignedRectilinear, ip2DHoneycomb, ip3DHoneycomb, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSupportCubic, ipSupportBase, ipConcentricInternal, ipLightning, ipCrossHatch, ipQuarterCubic, ipCount, @@ -947,6 +947,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionEnum, sparse_infill_pattern)) ((ConfigOptionFloat, lattice_angle_1)) ((ConfigOptionFloat, lattice_angle_2)) + ((ConfigOptionFloat, infill_overhang_angle)) ((ConfigOptionEnum, fuzzy_skin)) ((ConfigOptionFloat, fuzzy_skin_thickness)) ((ConfigOptionFloat, fuzzy_skin_point_distance)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 9d12806122..f7f9bca8ce 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1090,7 +1090,8 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "initial_layer_line_width" || opt_key == "small_area_infill_flow_compensation" || opt_key == "lattice_angle_1" - || opt_key == "lattice_angle_2") { + || opt_key == "lattice_angle_2" + || opt_key == "infill_overhang_angle") { steps.emplace_back(posInfill); } else if (opt_key == "sparse_infill_pattern") { steps.emplace_back(posPrepareInfill); @@ -3769,7 +3770,8 @@ void PrintObject::combine_infill() infill_pattern == ipGrid || infill_pattern == ip2DLattice || infill_pattern == ipLine || - infill_pattern == ipHoneycomb) ? 1.5f : 0.5f) * + infill_pattern == ipHoneycomb || + infill_pattern == ip2DHoneycomb) ? 1.5f : 0.5f) * layerms.back()->flow(frSolidInfill).scaled_width(); for (ExPolygon &expoly : intersection) polygons_append(intersection_with_clearance, offset(expoly, clearance_offset)); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 048cb065fe..78d8aaeff0 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -804,6 +804,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool lattice_options = config->opt_enum("sparse_infill_pattern") == InfillPattern::ip2DLattice; for (auto el : { "lattice_angle_1", "lattice_angle_2"}) toggle_line(el, lattice_options); + + toggle_line("infill_overhang_angle", config->opt_enum("sparse_infill_pattern") == InfillPattern::ip2DHoneycomb); } void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/) diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 15c0023cc4..ad32fc6d6c 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -106,7 +106,7 @@ std::map> SettingsFactory::PART_CAT }}, { L("Strength"), {{"wall_loops", "",1},{"top_shell_layers", L("Top Solid Layers"),1},{"top_shell_thickness", L("Top Minimum Shell Thickness"),1}, {"bottom_shell_layers", L("Bottom Solid Layers"),1}, {"bottom_shell_thickness", L("Bottom Minimum Shell Thickness"),1}, - {"sparse_infill_density", "",1},{"sparse_infill_pattern", "",1},{"lattice_angle_1", "",1},{"lattice_angle_2", "",1},{"infill_anchor", "",1},{"infill_anchor_max", "",1},{"top_surface_pattern", "",1},{"bottom_surface_pattern", "",1}, {"internal_solid_infill_pattern", "",1}, + {"sparse_infill_density", "",1},{"sparse_infill_pattern", "",1},{"lattice_angle_1", "",1},{"lattice_angle_2", "",1},{"infill_overhang_angle", "",1},{"infill_anchor", "",1},{"infill_anchor_max", "",1},{"top_surface_pattern", "",1},{"bottom_surface_pattern", "",1}, {"internal_solid_infill_pattern", "",1}, {"infill_combination", "",1}, {"infill_combination_max_layer_height", "",1}, {"infill_wall_overlap", "",1},{"top_bottom_infill_wall_overlap", "",1}, {"solid_infill_direction", "",1}, {"rotate_solid_infill_direction", "",1}, {"infill_direction", "",1}, {"bridge_angle", "",1}, {"internal_bridge_angle", "",1}, {"minimum_sparse_infill_area", "",1} }}, { L("Speed"), {{"outer_wall_speed", "",1},{"inner_wall_speed", "",2},{"sparse_infill_speed", "",3},{"top_surface_speed", "",4}, {"internal_solid_infill_speed", "",5}, diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 3ba87e3c40..8ee8b60c77 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2168,6 +2168,7 @@ void TabPrint::build() optgroup->append_single_option_line("sparse_infill_pattern", "fill-patterns#infill types and their properties of sparse"); optgroup->append_single_option_line("lattice_angle_1"); optgroup->append_single_option_line("lattice_angle_2"); + optgroup->append_single_option_line("infill_overhang_angle"); optgroup->append_single_option_line("infill_anchor_max"); optgroup->append_single_option_line("infill_anchor"); optgroup->append_single_option_line("internal_solid_infill_pattern");