diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 1ad0c92f8a1..e25068572d7 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -1404,7 +1404,7 @@ void PerimeterGenerator::apply_extra_perimeters(ExPolygons &infill_area) } // Reorient loop direction -static void reorient_perimeters(ExtrusionEntityCollection &entities, bool steep_overhang_contour, bool steep_overhang_hole) +static void reorient_perimeters(ExtrusionEntityCollection &entities, bool steep_overhang_contour, bool steep_overhang_hole, bool reverse_internal_only) { if (steep_overhang_hole || steep_overhang_contour) { for (auto entity : entities) { @@ -1412,7 +1412,18 @@ static void reorient_perimeters(ExtrusionEntityCollection &entities, bool steep_ ExtrusionLoop *eloop = static_cast(entity); // Only reverse when needed bool need_reverse = ((eloop->loop_role() & elrHole) == elrHole) ? steep_overhang_hole : steep_overhang_contour; - if (need_reverse) { + + bool isExternal = false; + if(reverse_internal_only){ + for(auto path : eloop->paths){ + if(path.role() == erExternalPerimeter){ + isExternal = true; + break; + } + } + } + + if (need_reverse && !isExternal) { eloop->make_clockwise(); } } @@ -1710,7 +1721,7 @@ void PerimeterGenerator::process_classic() bool steep_overhang_contour = false; bool steep_overhang_hole = false; ExtrusionEntityCollection entities = traverse_loops(*this, contours.front(), thin_walls, steep_overhang_contour, steep_overhang_hole); - reorient_perimeters(entities, steep_overhang_contour, steep_overhang_hole); + reorient_perimeters(entities, steep_overhang_contour, steep_overhang_hole, this->config->overhang_reverse_internal_only); // if brim will be printed, reverse the order of perimeters so that // we continue inwards after having finished the brim @@ -2232,7 +2243,7 @@ void PerimeterGenerator::process_arachne() bool steep_overhang_contour = false; bool steep_overhang_hole = false; if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(*this, ordered_extrusions, steep_overhang_contour, steep_overhang_hole); !extrusion_coll.empty()) { - reorient_perimeters(extrusion_coll, steep_overhang_contour, steep_overhang_hole); + reorient_perimeters(extrusion_coll, steep_overhang_contour, steep_overhang_hole, this->config->overhang_reverse_internal_only); this->loops->append(extrusion_coll); } diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index c8c158f9308..c9777b3c381 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -726,7 +726,7 @@ bool Preset::has_cali_lines(PresetBundle* preset_bundle) static std::vector s_Preset_print_options { "layer_height", "initial_layer_print_height", "wall_loops", "slice_closing_radius", "spiral_mode", "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", + "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", "seam_position", "staggered_inner_seams", "wall_infill_order", "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern", "infill_direction", "minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 723398f751e..cefc09347c9 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -840,7 +840,15 @@ void PrintConfigDef::init_fff_params() def->label = L("Reverse on odd"); def->full_label = L("Overhang reversal"); def->category = L("Quality"); - def->tooltip = L("Extrude perimeters that have a part over an overhang in the reverse direction on odd layers. This alternating pattern can drastically improve steep overhang."); + def->tooltip = L("Extrude perimeters that have a part over an overhang in the reverse direction on odd layers. This alternating pattern can drastically improve steep overhangs.\n\nThis setting can also help reduce part warping due to the reduction of stresses in the part walls."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("overhang_reverse_internal_only", coBool); + def->label = L("Reverse only internal perimeters"); + def->full_label = L("Reverse only internal perimeters"); + def->category = L("Quality"); + def->tooltip = L("Apply the reverse perimeters logic only on internal perimeters. \n\nThis setting greatly reduces part stresses as they are now distributed in alternating directions. This should reduce part warping while also maintaining external wall quality. This feature can be very useful for warp prone material, like ABS/ASA, and also for elastic filaments, like TPU and Silk PLA. It can also help reduce warping on floating regions over supports.\n\nFor this setting to be the most effective, it is recomended to set the Reverse Threshold to 0 so that all internal walls print in alternating directions on odd layers irrespective of their overhang degree."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 6404b367ae1..40cc7a6d628 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -877,6 +877,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloatOrPercent, hole_to_polyhole_threshold)) ((ConfigOptionBool, hole_to_polyhole_twisted)) ((ConfigOptionBool, overhang_reverse)) + ((ConfigOptionBool, overhang_reverse_internal_only)) ((ConfigOptionFloatOrPercent, overhang_reverse_threshold)) ) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 8d6175cc0a9..48da72f5f3f 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1097,6 +1097,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "fuzzy_skin_point_distance" || opt_key == "detect_overhang_wall" || opt_key == "overhang_reverse" + || opt_key == "overhang_reverse_internal_only" || opt_key == "overhang_reverse_threshold" //BBS || opt_key == "enable_overhang_speed" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 934ddb10191..b26e3e8ca6e 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -511,7 +511,7 @@ void ConfigManipulation::apply_null_fff_config(DynamicPrintConfig *config, std:: void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, const bool is_global_config) { PresetBundle *preset_bundle = wxGetApp().preset_bundle; - + auto gcflavor = preset_bundle->printers.get_edited_preset().config.option>("gcode_flavor")->value; bool have_volumetric_extrusion_rate_slope = config->option("max_volumetric_extrusion_rate_slope")->value > 0; @@ -520,27 +520,27 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_line("max_volumetric_extrusion_rate_slope_segment_length", have_volumetric_extrusion_rate_slope); if(have_volumetric_extrusion_rate_slope) config->set_key_value("enable_arc_fitting", new ConfigOptionBool(false)); if(have_volumetric_extrusion_rate_slope_segment_length==0) { - DynamicPrintConfig new_conf = *config; + DynamicPrintConfig new_conf = *config; new_conf.set_key_value("max_volumetric_extrusion_rate_slope_segment_length", new ConfigOptionInt(1)); - apply(config, &new_conf); + apply(config, &new_conf); } bool have_perimeters = config->opt_int("wall_loops") > 0; for (auto el : { "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "detect_thin_wall", "detect_overhang_wall", - "seam_position", "staggered_inner_seams", "wall_infill_order", "outer_wall_line_width", - "inner_wall_speed", "outer_wall_speed", "small_perimeter_speed", "small_perimeter_threshold" }) + "seam_position", "staggered_inner_seams", "wall_infill_order", "outer_wall_line_width", + "inner_wall_speed", "outer_wall_speed", "small_perimeter_speed", "small_perimeter_threshold" }) toggle_field(el, have_perimeters); - + 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", "infill_combination", - "minimum_sparse_infill_area", "sparse_infill_filament", "infill_anchor_max"}) + "minimum_sparse_infill_area", "sparse_infill_filament", "infill_anchor_max"}) toggle_line(el, have_infill); // Only allow configuration of open anchors if the anchoring is enabled. bool has_infill_anchors = have_infill && config->option("infill_anchor_max")->value > 0; toggle_field("infill_anchor", has_infill_anchors); - + bool has_spiral_vase = config->opt_bool("spiral_mode"); bool has_top_solid_infill = config->opt_int("top_shell_layers") > 0; bool has_bottom_solid_infill = config->opt_int("bottom_shell_layers") > 0; @@ -548,43 +548,43 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co // solid_infill_filament uses the same logic as in Print::extruders() for (auto el : { "top_surface_pattern", "bottom_surface_pattern", "internal_solid_infill_pattern", "solid_infill_filament"}) toggle_field(el, has_solid_infill); - + for (auto el : { "infill_direction", "sparse_infill_line_width", - "sparse_infill_speed", "bridge_speed", "internal_bridge_speed", "bridge_angle" }) + "sparse_infill_speed", "bridge_speed", "internal_bridge_speed", "bridge_angle" }) toggle_field(el, have_infill || has_solid_infill); - + toggle_field("top_shell_thickness", ! has_spiral_vase && has_top_solid_infill); toggle_field("bottom_shell_thickness", ! has_spiral_vase && has_bottom_solid_infill); - + // Gap fill is newly allowed in between perimeter lines even for empty infill (see GH #1476). toggle_field("gap_infill_speed", have_perimeters); - + for (auto el : { "top_surface_line_width", "top_surface_speed" }) toggle_field(el, has_top_solid_infill || (has_spiral_vase && has_bottom_solid_infill)); - + bool have_default_acceleration = config->opt_float("default_acceleration") > 0; - + for (auto el : {"outer_wall_acceleration", "inner_wall_acceleration", "initial_layer_acceleration", - "top_surface_acceleration", "travel_acceleration", "bridge_acceleration", "sparse_infill_acceleration", "internal_solid_infill_acceleration"}) + "top_surface_acceleration", "travel_acceleration", "bridge_acceleration", "sparse_infill_acceleration", "internal_solid_infill_acceleration"}) toggle_field(el, have_default_acceleration); - + bool have_default_jerk = config->opt_float("default_jerk") > 0; - + for (auto el : { "outer_wall_jerk", "inner_wall_jerk", "initial_layer_jerk", "top_surface_jerk","travel_jerk", "infill_jerk"}) toggle_field(el, have_default_jerk); - + bool have_skirt = config->opt_int("skirt_loops") > 0; toggle_field("skirt_height", have_skirt && config->opt_enum("draft_shield") != dsEnabled); for (auto el : { "skirt_distance", "draft_shield"}) toggle_field(el, have_skirt); - + bool have_brim = (config->opt_enum("brim_type") != btNoBrim); toggle_field("brim_object_gap", have_brim); bool have_brim_width = (config->opt_enum("brim_type") != btNoBrim) && config->opt_enum("brim_type") != btAutoBrim; toggle_field("brim_width", have_brim_width); // wall_filament uses the same logic as in Print::extruders() toggle_field("wall_filament", have_perimeters || have_brim); - + bool have_brim_ear = (config->opt_enum("brim_type") == btEar); const auto brim_width = config->opt_float("brim_width"); // disable brim_ears_max_angle and brim_ears_detection_length if brim_width is 0 @@ -593,32 +593,32 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co // hide brim_ears_max_angle and brim_ears_detection_length if brim_ear is not selected toggle_line("brim_ears_max_angle", have_brim_ear); toggle_line("brim_ears_detection_length", have_brim_ear); - + // Hide Elephant foot compensation layers if elefant_foot_compensation is not enabled toggle_line("elefant_foot_compensation_layers", config->opt_float("elefant_foot_compensation") > 0); - + bool have_raft = config->opt_int("raft_layers") > 0; bool have_support_material = config->opt_bool("enable_support") || have_raft; - + SupportType support_type = config->opt_enum("support_type"); bool have_support_interface = config->opt_int("support_interface_top_layers") > 0 || config->opt_int("support_interface_bottom_layers") > 0; bool have_support_soluble = have_support_material && config->opt_float("support_top_z_distance") == 0; auto support_style = config->opt_enum("support_style"); for (auto el : { "support_style", "support_base_pattern", - "support_base_pattern_spacing", "support_expansion", "support_angle", - "support_interface_pattern", "support_interface_top_layers", "support_interface_bottom_layers", - "bridge_no_support", "max_bridge_length", "support_top_z_distance", "support_bottom_z_distance", - //BBS: add more support params to dependent of enable_support - "support_type", "support_on_build_plate_only", "support_critical_regions_only", - "support_object_xy_distance"/*, "independent_support_layer_height"*/}) + "support_base_pattern_spacing", "support_expansion", "support_angle", + "support_interface_pattern", "support_interface_top_layers", "support_interface_bottom_layers", + "bridge_no_support", "max_bridge_length", "support_top_z_distance", "support_bottom_z_distance", + //BBS: add more support params to dependent of enable_support + "support_type", "support_on_build_plate_only", "support_critical_regions_only", + "support_object_xy_distance"/*, "independent_support_layer_height"*/}) toggle_field(el, have_support_material); toggle_field("support_threshold_angle", have_support_material && is_auto(support_type)); //toggle_field("support_closing_radius", have_support_material && support_style == smsSnug); - + bool support_is_tree = config->opt_bool("enable_support") && is_tree(support_type); bool support_is_normal_tree = support_is_tree && support_style != smsOrganic && - // Orca: use organic as default - support_style != smsDefault; + // Orca: use organic as default + support_style != smsDefault; bool support_is_organic = support_is_tree && !support_is_normal_tree; // settings shared by normal and organic trees for (auto el : {"tree_support_branch_angle", "tree_support_branch_distance", "tree_support_branch_diameter" }) @@ -629,85 +629,85 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co // settings specific to organic trees for (auto el : {"tree_support_branch_angle_organic", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic","tree_support_angle_slow","tree_support_tip_diameter", "tree_support_top_rate", "tree_support_branch_diameter_angle", "tree_support_branch_diameter_double_wall"}) toggle_line(el, support_is_organic); - + toggle_field("tree_support_brim_width", support_is_tree && !config->opt_bool("tree_support_auto_brim")); // non-organic tree support use max_bridge_length instead of bridge_no_support toggle_line("max_bridge_length", support_is_normal_tree); toggle_line("bridge_no_support", !support_is_normal_tree); - + // This is only supported for auto normal tree toggle_line("support_critical_regions_only", is_auto(support_type) && support_is_normal_tree); - + for (auto el : { "support_interface_spacing", "support_interface_filament", - "support_interface_loop_pattern", "support_bottom_interface_spacing" }) + "support_interface_loop_pattern", "support_bottom_interface_spacing" }) toggle_field(el, have_support_material && have_support_interface); - + bool have_skirt_height = have_skirt && - (config->opt_int("skirt_height") > 1 || config->opt_enum("draft_shield") != dsEnabled); + (config->opt_int("skirt_height") > 1 || config->opt_enum("draft_shield") != dsEnabled); toggle_line("support_speed", have_support_material || have_skirt_height); toggle_line("support_interface_speed", have_support_material && have_support_interface); - + // BBS //toggle_field("support_material_synchronize_layers", have_support_soluble); - + toggle_field("inner_wall_line_width", have_perimeters || have_skirt || have_brim); toggle_field("support_filament", have_support_material || have_skirt); - + toggle_line("raft_contact_distance", have_raft && !have_support_soluble); - + // Orca: Raft, grid, snug and organic supports use these two parameters to control the size & density of the "brim"/flange for (auto el : { "raft_first_layer_expansion", "raft_first_layer_density"}) toggle_field(el, have_support_material && !(support_is_normal_tree && !have_raft)); - + bool has_ironing = (config->opt_enum("ironing_type") != IroningType::NoIroning); for (auto el : { "ironing_pattern", "ironing_flow", "ironing_spacing", "ironing_speed", "ironing_angle" }) toggle_line(el, has_ironing); - + // bool have_sequential_printing = (config->opt_enum("print_sequence") == PrintSequence::ByObject); // for (auto el : { "extruder_clearance_radius", "extruder_clearance_height_to_rod", "extruder_clearance_height_to_lid" }) // toggle_field(el, have_sequential_printing); - + bool have_ooze_prevention = config->opt_bool("ooze_prevention"); toggle_field("standby_temperature_delta", have_ooze_prevention); - + bool have_prime_tower = config->opt_bool("enable_prime_tower"); for (auto el : { "prime_tower_width", "prime_tower_brim_width"}) toggle_line(el, have_prime_tower); - + bool purge_in_primetower = preset_bundle->printers.get_edited_preset().config.opt_bool("purge_in_prime_tower"); - + for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_bridging", "wipe_tower_no_sparse_layers"}) toggle_line(el, have_prime_tower && purge_in_primetower); - + toggle_line("prime_volume",have_prime_tower && !purge_in_primetower); - + for (auto el : {"flush_into_infill", "flush_into_support", "flush_into_objects"}) toggle_field(el, have_prime_tower); - - // BBS: MusangKing - Hide "Independent support layer height" option + + // BBS: MusangKing - Hide "Independent support layer height" option toggle_line("independent_support_layer_height", have_support_material && !have_prime_tower); - + bool have_avoid_crossing_perimeters = config->opt_bool("reduce_crossing_wall"); toggle_line("max_travel_detour_distance", have_avoid_crossing_perimeters); - + bool has_overhang_speed = config->opt_bool("enable_overhang_speed"); for (auto el : {"overhang_speed_classic", "overhang_1_4_speed", - "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed"}) + "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed"}) toggle_line(el, has_overhang_speed); bool has_overhang_speed_classic = config->opt_bool("overhang_speed_classic"); toggle_line("slowdown_for_curled_perimeters",!has_overhang_speed_classic && has_overhang_speed); - + toggle_line("flush_into_objects", !is_global_config); - + bool has_fuzzy_skin = (config->opt_enum("fuzzy_skin") != FuzzySkinType::None); for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_distance"}) toggle_line(el, has_fuzzy_skin); - + bool have_arachne = config->opt_enum("wall_generator") == PerimeterGeneratorType::Arachne; for (auto el : { "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", - "min_feature_size", "min_bead_width", "wall_distribution_count", "initial_layer_min_bead_width"}) + "min_feature_size", "min_bead_width", "wall_distribution_count", "initial_layer_min_bead_width"}) toggle_line(el, have_arachne); toggle_field("detect_thin_wall", !have_arachne); @@ -719,23 +719,30 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_line(el, gcflavor == gcfKlipper); if(gcflavor == gcfKlipper) toggle_field("accel_to_decel_factor", config->opt_bool("accel_to_decel_enable")); - + bool have_make_overhang_printable = config->opt_bool("make_overhang_printable"); toggle_line("make_overhang_printable_angle", have_make_overhang_printable); toggle_line("make_overhang_printable_hole_size", have_make_overhang_printable); - + toggle_line("exclude_object", gcflavor == gcfKlipper); - + toggle_line("min_width_top_surface",config->opt_bool("only_one_wall_top")); - + for (auto el : { "hole_to_polyhole_threshold", "hole_to_polyhole_twisted" }) toggle_line(el, config->opt_bool("hole_to_polyhole")); - + bool has_detect_overhang_wall = config->opt_bool("detect_overhang_wall"); bool has_overhang_reverse = config->opt_bool("overhang_reverse"); bool allow_overhang_reverse = has_detect_overhang_wall && !has_spiral_vase; toggle_field("overhang_reverse", allow_overhang_reverse); toggle_line("overhang_reverse_threshold", allow_overhang_reverse && has_overhang_reverse); + toggle_line("overhang_reverse_internal_only", allow_overhang_reverse && has_overhang_reverse); + bool has_overhang_reverse_internal_only = config->opt_bool("overhang_reverse_internal_only"); + if (has_overhang_reverse_internal_only){ + DynamicPrintConfig new_conf = *config; + new_conf.set_key_value("overhang_reverse_threshold", new ConfigOptionFloatOrPercent(0,true)); + apply(config, &new_conf); + } toggle_line("timelapse_type", is_BBL_Printer); } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 2a55597425d..68a0990436c 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1911,6 +1911,7 @@ void TabPrint::build() optgroup->append_single_option_line("max_travel_detour_distance"); optgroup->append_single_option_line("extra_perimeters_on_overhangs"); optgroup->append_single_option_line("overhang_reverse"); + optgroup->append_single_option_line("overhang_reverse_internal_only"); optgroup->append_single_option_line("overhang_reverse_threshold"); page = add_options_page(L("Strength"), "empty");