diff --git a/resources/profiles/Basic.ini b/resources/profiles/Basic.ini index dcb379cd0..291e47aeb 100644 --- a/resources/profiles/Basic.ini +++ b/resources/profiles/Basic.ini @@ -266,7 +266,7 @@ infill_dense_algo = autosmall infill_every_layers = 1 infill_extruder = 1 infill_first = 0 -infill_not_connected = 0 +infill_connection = connected infill_only_where_needed = 0 infill_overlap = 20% interface_shells = 0 diff --git a/resources/ui_layout/print.ui b/resources/ui_layout/print.ui index 66961f27a..4379ea320 100644 --- a/resources/ui_layout/print.ui +++ b/resources/ui_layout/print.ui @@ -104,7 +104,7 @@ group:Infill end_line line:Pattern setting:label_width$5:label$_:fill_pattern - setting:label$Don't connect:infill_not_connected + setting:width$19:label$_:infill_connection end_line line:External patterns setting:label_width$5:top_fill_pattern diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index c12a51dcf..f17e5fcfb 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -241,7 +241,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) params.density = float(0.01 * density); params.dont_adjust = false; params.fill_exactly = layerm.region()->config().enforce_full_fill_volume.getBool(); - params.dont_connect = layerm.region()->config().infill_not_connected.getBool(); + params.connection = layerm.region()->config().infill_connection.value; //adjust flow (to over-extrude when needed) float flow_percent = 1; if (surface.has_pos_top()) flow_percent *= layerm.region()->config().fill_top_flow_ratio.get_abs_value(1); diff --git a/src/libslic3r/Fill/Fill3DHoneycomb.cpp b/src/libslic3r/Fill/Fill3DHoneycomb.cpp index d2529b208..e33ac4b69 100644 --- a/src/libslic3r/Fill/Fill3DHoneycomb.cpp +++ b/src/libslic3r/Fill/Fill3DHoneycomb.cpp @@ -168,7 +168,7 @@ void Fill3DHoneycomb::_fill_surface_single( // connect lines if needed if (! polylines_chained.empty()) { - if (params.dont_connect) + if (params.connection == icNotConnected) append(polylines_out, std::move(polylines_chained)); else this->connect_infill(std::move(polylines_chained), expolygon, polylines_out, this->spacing, params); diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 55bf5a613..7ead8d135 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -1011,6 +1011,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_ [&boundary](const std::pair &contour_point) { return contour_point.first < boundary.size() && contour_point.second < boundary[contour_point.first].size(); })); + assert(boundary_data.size() == boundary_src.holes.size() + 1); #endif /* NDEBUG */ } @@ -1065,6 +1066,20 @@ void Fill::connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary_ } std::sort(connections_sorted.begin(), connections_sorted.end(), [](const ConnectionCost& l, const ConnectionCost& r) { return l.cost < r.cost; }); + //mark point as used depends of connection parameter + if (params.connection == icOuterShell) { + for (auto it = boundary_data.begin() + 1; it != boundary_data.end(); ++it) { + for (ContourPointData& pt : *it) { + pt.point_consumed = true; + } + } + } else if (params.connection == icHoles) { + for (ContourPointData& pt : boundary_data[0]) { + pt.point_consumed = true; + } + } + assert(boundary_data.size() == boundary_src.holes.size() + 1); + size_t idx_chain_last = 0; for (ConnectionCost &connection_cost : connections_sorted) { const std::pair *cp1 = &map_infill_end_point_to_boundary[connection_cost.idx_first * 2 + 1]; diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index bef34595d..621f361a6 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -38,7 +38,7 @@ struct FillParams float flow_mult { 1.0f }; // Don't connect the fill lines around the inner perimeter. - bool dont_connect{ false }; + InfillConnection connection{ icConnected }; // Don't adjust spacing to fill the space evenly. bool dont_adjust { true }; diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index 4eae6090f..6b167166a 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -193,15 +193,16 @@ void FillGyroid::_fill_surface_single( polylines = chain_polylines(polylines); // connect lines size_t polylines_out_first_idx = polylines_out.size(); - if (params.dont_connect) - append(polylines_out, std::move(polylines)); - else + if (params.connection == icNotConnected){ + append(polylines_out, std::move(polylines)); + } else { this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params); - // new paths must be rotated back - if (abs(infill_angle) >= EPSILON) { - for (auto it = polylines_out.begin() + polylines_out_first_idx; it != polylines_out.end(); ++ it) - it->rotate(infill_angle); - } + } + // new paths must be rotated back + if (abs(infill_angle) >= EPSILON) { + for (auto it = polylines_out.begin() + polylines_out_first_idx; it != polylines_out.end(); ++ it) + it->rotate(infill_angle); + } } } diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index ceb5cecd9..fbd91b117 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -89,16 +89,31 @@ void FillRectilinear::_fill_surface_single( // offset the expolygon by max(min_spacing/2, extra) ExPolygon expolygon_off; { - ExPolygons expolygons_off = offset_ex(expolygon, this->_min_spacing/2); - if (! expolygons_off.empty()) { - // When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island. - assert(expolygons_off.size() == 1); - std::swap(expolygon_off, expolygons_off.front()); + if (params.connection == icConnected || params.connection == icHoles) { + ExPolygons expolygons_off = offset_ex(expolygon, this->_min_spacing / 2); + if (!expolygons_off.empty()) { + // When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island. + assert(expolygons_off.size() == 1); + std::swap(expolygon_off, expolygons_off.front()); + } + //restore contour for hole-only. + if (params.connection == icHoles) { + expolygon_off.contour = expolygon.contour; + } + } else if (params.connection == icOuterShell) { + // shrink only the contour + expolygon_off = expolygon; + Polygons bigcontour = offset(expolygon_off.contour, this->_min_spacing / 2); + if (!bigcontour.empty()) { + // When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island. + assert(bigcontour.size() == 1); + std::swap(expolygon_off.contour, bigcontour.front()); + } } } bool first = true; for (Polyline &polyline : chain_polylines(std::move(polylines))) { - if (!params.dont_connect && !first) { + if (params.connection != icNotConnected && !first) { // Try to connect the lines. Points &pts_end = polylines_out.back().points; const Point &first_point = polyline.points.front(); diff --git a/src/libslic3r/Fill/FillRectilinear2.cpp b/src/libslic3r/Fill/FillRectilinear2.cpp index 3ed3a9429..35852af7f 100644 --- a/src/libslic3r/Fill/FillRectilinear2.cpp +++ b/src/libslic3r/Fill/FillRectilinear2.cpp @@ -123,6 +123,8 @@ struct SegmentIntersection int64_t pos_p{ 0 }; uint32_t pos_q{ 1 }; + bool is_hole{ false }; + coord_t pos() const { // Division rounds both positive and negative down to zero. // Add half of q for an arithmetic rounding effect. @@ -591,8 +593,8 @@ static inline void emit_perimeter_prev_next_segment( } static inline coordf_t measure_perimeter_segment_on_vertical_line_length( - const ExPolygonWithOffset &poly_with_offset, - const std::vector &segs, + const ExPolygonWithOffset& poly_with_offset, + const std::vector& segs, size_t iVerticalLine, size_t iIntersection, size_t iIntersection2, @@ -759,6 +761,7 @@ std::vector FillRectilinear2::_vert_lines_for_polygon } for (size_t iContour = 0; iContour < poly_with_offset.n_contours; ++ iContour) { const Points &contour = poly_with_offset.contour(iContour).points; + bool is_hole = poly_with_offset.contour(iContour).is_clockwise(); if (contour.size() < 2) continue; // For each segment @@ -791,6 +794,7 @@ std::vector FillRectilinear2::_vert_lines_for_polygon SegmentIntersection is; is.iContour = iContour; is.iSegment = iSegment; + is.is_hole = is_hole; assert(l <= this_x); assert(r >= this_x); // Calculate the intersection position in y axis. x is known. @@ -1064,8 +1068,10 @@ static void connect_segment_intersections_by_contours( itsct.next_on_contour_quality = SegmentIntersection::LinkQuality::Invalid; } } - - if (params.dont_connect) { + if (params.connection == icNotConnected + || (params.connection == icOuterShell && itsct.is_hole) // not: don't work as expected because the algo only start from top and go bottom. + || (params.connection == icHoles && !itsct.is_hole) + ) { if (itsct.prev_on_contour_quality == SegmentIntersection::LinkQuality::Valid) itsct.prev_on_contour_quality = SegmentIntersection::LinkQuality::TooLong; if (itsct.next_on_contour_quality == SegmentIntersection::LinkQuality::Valid) @@ -1082,8 +1088,8 @@ static void connect_segment_intersections_by_contours( measure_perimeter_segment_on_vertical_line_length(poly_with_offset, segs, i_vline, i_intersection, inext, forward) : measure_perimeter_horizontal_segment_length(poly_with_offset, segs, i_vline, i_intersection, inext)) > link_max_length) itsct.next_on_contour_quality = SegmentIntersection::LinkQuality::TooLong; + } } - } // Make the LinkQuality::Invalid symmetric on vertical connections. for (size_t i_intersection = 0; i_intersection < il.intersections.size(); ++i_intersection) { @@ -1092,7 +1098,7 @@ static void connect_segment_intersections_by_contours( SegmentIntersection& it2 = il.intersections[it.left_vertical()]; assert(it2.left_vertical() == i_intersection); it2.prev_on_contour_quality = SegmentIntersection::LinkQuality::Invalid; - } + } if (it.has_right_vertical() && it.next_on_contour_quality == SegmentIntersection::LinkQuality::Invalid) { SegmentIntersection& it2 = il.intersections[it.right_vertical()]; assert(it2.right_vertical() == i_intersection); @@ -2704,7 +2710,7 @@ Polylines FillTriangles::fill_surface(const Surface *surface, const FillParams & FillParams params2 = params; params2.density *= 0.333333333f; FillParams params3 = params2; - params3.dont_connect = true; + params3.connection = icNotConnected; Polylines polylines_out; if (! fill_surface_by_lines(surface, params2, 0.f, 0., polylines_out) || ! fill_surface_by_lines(surface, params2, float(M_PI / 3.), 0., polylines_out) || @@ -2720,7 +2726,7 @@ Polylines FillStars::fill_surface(const Surface *surface, const FillParams ¶ FillParams params2 = params; params2.density *= 0.333333333f; FillParams params3 = params2; - params3.dont_connect = true; + params3.connection = icNotConnected; Polylines polylines_out; if (! fill_surface_by_lines(surface, params2, 0.f, 0.f, polylines_out) || ! fill_surface_by_lines(surface, params2, float(M_PI / 3.), 0.f, polylines_out) || @@ -2736,7 +2742,7 @@ Polylines FillCubic::fill_surface(const Surface *surface, const FillParams ¶ FillParams params2 = params; params2.density *= 0.333333333f; FillParams params3 = params2; - params3.dont_connect = true; + params3.connection = icNotConnected; Polylines polylines_out; coordf_t dx = sqrt(0.5) * z; if (! fill_surface_by_lines(surface, params2, 0.f, float(dx), polylines_out) || diff --git a/src/libslic3r/Fill/FillRectilinear3.cpp b/src/libslic3r/Fill/FillRectilinear3.cpp index df10ef8e8..cd50daf3a 100644 --- a/src/libslic3r/Fill/FillRectilinear3.cpp +++ b/src/libslic3r/Fill/FillRectilinear3.cpp @@ -1361,7 +1361,7 @@ static bool fill_hatching_segments_legacy( (distNext < distPrev) : intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK; assert(intrsctn->is_inner()); - bool skip = params.dont_connect || (link_max_length > 0 && (take_next ? distNext : distPrev) > link_max_length); + bool skip = params.connection == icNotConnected || (link_max_length > 0 && (take_next ? distNext : distPrev) > link_max_length); if (skip) { // Just skip the connecting contour and start a new path. goto dont_connect; @@ -1423,7 +1423,7 @@ static bool fill_hatching_segments_legacy( distance_of_segmens(poly, intrsctn->iSegment, iSegNext, false)) : (vert_seg_dir_valid_mask == DIR_FORWARD); // Skip this perimeter line? - bool skip = params.dont_connect; + bool skip = params.connection == icNotConnected; if (! skip && link_max_length > 0) { coordf_t link_length = measure_perimeter_segment_on_vertical_line_length( poly_with_offset, segs, i_vline, intrsctn->iContour, i_intersection, iNext, dir_forward); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 034a21185..904f23945 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1763,12 +1763,23 @@ void PrintConfigDef::init_fff_params() def->mode = comSimple; def->set_default_value(new ConfigOptionBool(false)); - def = this->add("infill_not_connected", coBool); + def = this->add("infill_connection", coEnum); def->label = L("Do not connect infill lines to each other"); def->category = OptionCategory::infill; - def->tooltip = L("If checked, the infill algorithm will try to not connect the lines near the infill. Can be useful for art or with high infill/perimeter overlap."); + def->tooltip = L("Give to the infill algorithm if the infill needs to be connected, and on which periemters" + " Can be useful for art or with high infill/perimeter overlap." + " The result amy varies between infill typers."); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("connected"); + def->enum_values.push_back("holes"); + def->enum_values.push_back("outershell"); + def->enum_values.push_back("notconnected"); + def->enum_labels.push_back(L("Connected")); + def->enum_labels.push_back(L("Connected to hole perimeters")); + def->enum_labels.push_back(L("Connected to outer perimeters")); + def->enum_labels.push_back(L("Not connected")); def->mode = comExpert; - def->set_default_value(new ConfigOptionBool(false)); + def->set_default_value(new ConfigOptionEnum(icConnected)); def = this->add("infill_dense_algo", coEnum); def->label = L("Algorithm"); @@ -4566,6 +4577,12 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va opt_key = "z_step"; float v = boost::lexical_cast(value); value = boost::lexical_cast(1/v); + } else if (opt_key == "infill_not_connected") { + opt_key = "infill_connection"; + if (value == "1") + value = "notconnected"; + else + value = "connected"; } // Ignore the following obsolete configuration keys: @@ -4575,10 +4592,11 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va "standby_temperature", "scale", "rotate", "duplicate", "duplicate_grid", "start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start", "seal_position", "vibration_limit", "bed_size", - "print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe" + "print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe", #ifndef HAS_PRESSURE_EQUALIZER - , "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative" + "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative", #endif /* HAS_PRESSURE_EQUALIZER */ + "cooling" }; if (ignore.find(opt_key) != ignore.end()) { diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 645adb694..a1bf65183 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -98,6 +98,10 @@ enum NoPerimeterUnsupportedAlgo { npuaNone, npuaNoPeri, npuaBridges, npuaBridgesOverhangs, npuaFilled, }; +enum InfillConnection { + icConnected, icHoles, icOuterShell, icNotConnected, +}; + enum SupportZDistanceType { zdFilament, zdPlane, zdNone, }; @@ -247,6 +251,16 @@ template<> inline const t_config_enum_values& ConfigOptionEnum inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { + static const t_config_enum_values keys_map = { + { "connected", icConnected }, + { "holes", icHoles }, + { "outershell", icOuterShell }, + { "notconnected", icNotConnected } + }; + return keys_map; +} + template<> inline const t_config_enum_values& ConfigOptionEnum::get_enum_values() { static const t_config_enum_values keys_map = { { "filament", zdFilament }, @@ -672,7 +686,7 @@ public: ConfigOptionInt infill_every_layers; ConfigOptionFloatOrPercent infill_overlap; ConfigOptionFloat infill_speed; - ConfigOptionBool infill_not_connected; + ConfigOptionEnum infill_connection; ConfigOptionBool infill_dense; ConfigOptionEnum infill_dense_algo; ConfigOptionBool infill_first; @@ -763,7 +777,7 @@ protected: OPT_PTR(infill_overlap); OPT_PTR(infill_speed); OPT_PTR(infill_dense); - OPT_PTR(infill_not_connected); + OPT_PTR(infill_connection); OPT_PTR(infill_dense_algo); OPT_PTR(infill_first); OPT_PTR(milling_after_z); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 9ab1a68dc..21452b762 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -1004,6 +1004,8 @@ void Choice::set_value(const boost::any& value, bool change_event) val = idx_from_enum_value(val); else if (m_opt_id.compare("no_perimeter_unsupported_algo") == 0) val = idx_from_enum_value(val); + else if (m_opt_id.compare("infill_connection") == 0) + val = idx_from_enum_value(val); else if (m_opt_id.compare("wipe_advanced_algo") == 0) val = idx_from_enum_value(val); else if (m_opt_id.compare("support_material_contact_distance_type") == 0) @@ -1089,6 +1091,8 @@ boost::any& Choice::get_value() convert_to_enum_value(ret_enum); else if (m_opt_id.compare("no_perimeter_unsupported_algo") == 0) convert_to_enum_value(ret_enum); + else if (m_opt_id.compare("infill_connection") == 0) + convert_to_enum_value(ret_enum); else if (m_opt_id.compare("wipe_advanced_algo") == 0) convert_to_enum_value(ret_enum); else if (m_opt_id.compare("support_material_contact_distance_type") == 0) diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index d3449b835..54be1e4ad 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -200,18 +200,20 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("seam_position") == 0 || opt_key.compare("perimeter_loop_seam") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); - else if (opt_key.compare("host_type") == 0) + else if (opt_key.compare("host_type") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("infill_dense_algo") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("no_perimeter_unsupported_algo") == 0) - config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); + config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); + else if (opt_key.compare("infill_connection") == 0) + config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("wipe_advanced_algo") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if (opt_key.compare("support_material_contact_distance_type") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); - else if (opt_key.compare("display_orientation") == 0) - config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); + else if (opt_key.compare("display_orientation") == 0) + config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); else if(opt_key.compare("support_pillar_connection_mode") == 0) config.set_key_value(opt_key, new ConfigOptionEnum(boost::any_cast(value))); } diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 7d61d343c..c6cd23b3a 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -774,6 +774,9 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config else if (opt_key.compare("no_perimeter_unsupported_algo") == 0){ ret = static_cast(config.option>(opt_key)->value); } + else if (opt_key.compare("infill_connection") == 0) { + ret = static_cast(config.option>(opt_key)->value); + } else if (opt_key.compare("wipe_advanced_algo") == 0){ ret = static_cast(config.option>(opt_key)->value); } diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index b2d8f3371..220e6e4fb 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -523,15 +523,15 @@ const std::vector& Preset::print_options() "compatible_printers", "compatible_printers_condition", "inherits", "infill_dense", "infill_dense_algo", "no_perimeter_unsupported_algo", - "support_material_solid_first_layer" - , "exact_last_layer_height" - , "perimeter_loop" - , "perimeter_loop_seam" - , "seam_travel" - , "infill_not_connected" - , "first_layer_infill_speed" - , "thin_walls_min_width" - , "thin_walls_overlap", + "support_material_solid_first_layer", + "exact_last_layer_height", + "perimeter_loop", + "perimeter_loop_seam", + "seam_travel", + "infill_connection", + "first_layer_infill_speed", + "thin_walls_min_width", + "thin_walls_overlap", "thin_walls_speed" , "model_precision" , "curve_smoothing_precision"