diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index 786a99b95ef..9921887b76d 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -43,10 +43,13 @@ enum ExtrusionRole : uint8_t { }; // Special flags describing loop -enum ExtrusionLoopRole { - elrDefault, - elrContourInternalPerimeter, - elrSkirt, +enum ExtrusionLoopRole : uint8_t { + elrDefault=0x0, + // Loop for the hole, not for the contour + elrHole=0x1, + // Loop that is the most closest to infill + elrInternal = 0x2, + elrSkirt=0x4, }; diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index cd8f71501a3..261d3f0488c 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -4152,8 +4152,12 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // get a copy; don't modify the orientation of the original loop object otherwise // next copies (if any) would not detect the correct orientation - // extrude all loops ccw - bool was_clockwise = loop.make_counter_clockwise(); + bool is_hole = (loop.loop_role() & elrHole) == elrHole; + + if (m_config.spiral_mode && !is_hole) { + // if spiral vase, we have to ensure that all contour are in the same orientation. + loop.make_counter_clockwise(); + } // find the point of the loop that is closest to the current extruder position // or randomize if requested @@ -4210,26 +4214,20 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // make a little move inwards before leaving loop if (m_config.wipe_on_loops.value && paths.back().role() == erExternalPerimeter && m_layer != NULL && m_config.wall_loops.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) { // detect angle between last and first segment - // the side depends on the original winding order of the polygon (left for contours, right for holes) + // the side depends on the original winding order of the polygon (inwards for contours, outwards for holes) //FIXME improve the algorithm in case the loop is tiny. //FIXME improve the algorithm in case the loop is split into segments with a low number of points (see the Point b query). Point a = paths.front().polyline.points[1]; // second point Point b = *(paths.back().polyline.points.end()-3); // second to last point - if (was_clockwise) { + if (is_hole == loop.is_counter_clockwise()) { // swap points Point c = a; a = b; b = c; - - // double angle = paths.front().first_point().ccw_angle(a, b) / 3; - - // // turn left if contour, turn right if hole - // if (was_clockwise) angle *= -1; - } double angle = paths.front().first_point().ccw_angle(a, b) / 3; - // turn left if contour, turn right if hole - if (was_clockwise) angle *= -1; + // turn inwards if contour, turn outwards if hole + if (is_hole == loop.is_counter_clockwise()) angle *= -1; // create the destination point along the first segment and rotate it // we make sure we don't exceed the segment length because we don't know diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 6a0cf9cfbf1..c120103ae7c 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -174,6 +174,8 @@ void Layer::make_perimeters() && config.gap_infill_speed.value == other_config.gap_infill_speed.value && config.filter_out_gap_fill.value == other_config.filter_out_gap_fill.value && config.detect_overhang_wall == other_config.detect_overhang_wall + && config.overhang_reverse == other_config.overhang_reverse + && config.overhang_reverse_threshold == other_config.overhang_reverse_threshold && config.opt_serialize("inner_wall_line_width") == other_config.opt_serialize("inner_wall_line_width") && config.opt_serialize("outer_wall_line_width") == other_config.opt_serialize("outer_wall_line_width") && config.detect_thin_wall == other_config.detect_thin_wall diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 4dd89fd80d4..8a293d71106 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -223,12 +223,61 @@ static void lowpass_filter_by_paths_overhang_degree(ExtrusionPaths& paths) { } } -static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perimeter_generator, const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) +template +static bool detect_steep_overhang(const PrintRegionConfig *config, + bool is_contour, + const BoundingBox &extrusion_bboxs, + double extrusion_width, + const _T extrusion, + const ExPolygons *lower_slices, + bool &steep_overhang_contour, + bool &steep_overhang_hole) +{ + double threshold = config->overhang_reverse_threshold.get_abs_value(extrusion_width); + // Special case: reverse on every odd layer + if (threshold < EPSILON) { + if (is_contour) { + steep_overhang_contour = true; + } else { + steep_overhang_hole = true; + } + + return true; + } + + Polygons lower_slcier_chopped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*lower_slices, extrusion_bboxs, true); + + // All we need to check is whether we have lines outside `threshold` + double off = threshold - 0.5 * extrusion_width; + + auto limiton_polygons = offset(lower_slcier_chopped, float(scale_(off))); + + auto remain_polylines = diff_pl(extrusion, limiton_polygons); + if (!remain_polylines.empty()) { + if (is_contour) { + steep_overhang_contour = true; + } else { + steep_overhang_hole = true; + } + + return true; + } + + return false; +} + +static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perimeter_generator, const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls, + bool &steep_overhang_contour, bool &steep_overhang_hole) { // loops is an arrayref of ::Loop objects // turn each one into an ExtrusionLoop object ExtrusionEntityCollection coll; Polygon fuzzified; + + // Detect steep overhangs + bool overhangs_reverse = perimeter_generator.config->overhang_reverse && + perimeter_generator.layer_id % 2 == 1; // Only calculate overhang degree on odd layers + for (const PerimeterGeneratorLoop &loop : loops) { bool is_external = loop.is_external(); bool is_small_width = loop.is_smaller_width_perimeter; @@ -240,9 +289,9 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime // Note that we set loop role to ContourInternalPerimeter // also when loop is both internal and external (i.e. // there's only one contour loop). - loop_role = elrContourInternalPerimeter; + loop_role = elrInternal; } else { - loop_role = elrDefault; + loop_role = loop.is_contour? elrDefault : elrHole; } // detect overhanging/bridging perimeters @@ -283,6 +332,22 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime BoundingBox bbox(polygon.points); bbox.offset(SCALED_EPSILON); + // Always reverse extrusion if use fuzzy skin: https://github.com/SoftFever/OrcaSlicer/pull/2413#issuecomment-1769735357 + if (overhangs_reverse && perimeter_generator.config->fuzzy_skin != FuzzySkinType::None) { + if (loop.is_contour) { + steep_overhang_contour = true; + } else if (perimeter_generator.config->fuzzy_skin != FuzzySkinType::External) { + steep_overhang_hole = true; + } + } + // Detect steep overhang + // Skip the check if we already found steep overhangs + bool found_steep_overhang = (loop.is_contour && steep_overhang_contour) || (!loop.is_contour && steep_overhang_hole); + if (overhangs_reverse && !found_steep_overhang) { + detect_steep_overhang(perimeter_generator.config, loop.is_contour, bbox, extrusion_width, Polygons{polygon}, perimeter_generator.lower_slices, + steep_overhang_contour, steep_overhang_hole); + } + Polylines remain_polines; //BBS: don't calculate overhang degree when enable fuzzy skin. It's unmeaning @@ -382,16 +447,16 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime } else { const PerimeterGeneratorLoop &loop = loops[idx.first]; assert(thin_walls.empty()); - ExtrusionEntityCollection children = traverse_loops(perimeter_generator, loop.children, thin_walls); + ExtrusionEntityCollection children = traverse_loops(perimeter_generator, loop.children, thin_walls, steep_overhang_contour, steep_overhang_hole); out.entities.reserve(out.entities.size() + children.entities.size() + 1); ExtrusionLoop *eloop = static_cast(coll.entities[idx.first]); coll.entities[idx.first] = nullptr; + + eloop->make_counter_clockwise(); if (loop.is_contour) { - eloop->make_counter_clockwise(); out.append(std::move(children.entities)); out.entities.emplace_back(eloop); } else { - eloop->make_clockwise(); out.entities.emplace_back(eloop); out.append(std::move(children.entities)); } @@ -573,8 +638,13 @@ static void smooth_overhang_level(ExtrusionPaths &paths) } } -static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& perimeter_generator, std::vector& pg_extrusions) +static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& perimeter_generator, std::vector& pg_extrusions, + bool &steep_overhang_contour, bool &steep_overhang_hole) { + // Detect steep overhangs + bool overhangs_reverse = perimeter_generator.config->overhang_reverse && + perimeter_generator.layer_id % 2 == 1; // Only calculate overhang degree on odd layers + ExtrusionEntityCollection extrusion_coll; for (PerimeterGeneratorArachneExtrusion& pg_extrusion : pg_extrusions) { Arachne::ExtrusionLine* extrusion = pg_extrusion.extrusion; @@ -621,6 +691,41 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p extrusion_paths_append(temp_paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctIntersection), role, is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow); + // Always reverse extrusion if use fuzzy skin: https://github.com/SoftFever/OrcaSlicer/pull/2413#issuecomment-1769735357 + if (overhangs_reverse && perimeter_generator.config->fuzzy_skin != FuzzySkinType::None) { + if (pg_extrusion.is_contour) { + steep_overhang_contour = true; + } else if (perimeter_generator.config->fuzzy_skin != FuzzySkinType::External) { + steep_overhang_hole = true; + } + } + // Detect steep overhang + // Skip the check if we already found steep overhangs + bool found_steep_overhang = (pg_extrusion.is_contour && steep_overhang_contour) || (!pg_extrusion.is_contour && steep_overhang_hole); + if (overhangs_reverse && !found_steep_overhang) { + std::map recognization_paths; + for (const ExtrusionPath &path : temp_paths) { + if (recognization_paths.count(path.width)) + recognization_paths[path.width].emplace_back(std::move(path)); + else + recognization_paths.insert(std::pair(path.width, {std::move(path)})); + } + for (const auto &it : recognization_paths) { + Polylines be_clipped; + + for (const ExtrusionPath &p : it.second) { + be_clipped.emplace_back(std::move(p.polyline)); + } + + BoundingBox extrusion_bboxs = get_extents(be_clipped); + + if (detect_steep_overhang(perimeter_generator.config, pg_extrusion.is_contour, extrusion_bboxs, it.first, be_clipped, perimeter_generator.lower_slices, + steep_overhang_contour, steep_overhang_hole)) { + break; + } + } + } + if (perimeter_generator.config->overhang_speed_classic && perimeter_generator.config->enable_overhang_speed && perimeter_generator.config->fuzzy_skin == FuzzySkinType::None) { Flow flow = is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow; @@ -728,13 +833,8 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p // Append paths to collection. if (!paths.empty()) { if (extrusion->is_closed) { - ExtrusionLoop extrusion_loop(std::move(paths)); - // Restore the orientation of the extrusion loop. - if (pg_extrusion.is_contour) - extrusion_loop.make_counter_clockwise(); - else - extrusion_loop.make_clockwise(); - + ExtrusionLoop extrusion_loop(std::move(paths), pg_extrusion.is_contour ? elrDefault : elrHole); + extrusion_loop.make_counter_clockwise(); for (auto it = std::next(extrusion_loop.paths.begin()); it != extrusion_loop.paths.end(); ++it) { assert(it->polyline.points.size() >= 2); assert(std::prev(it)->polyline.last_point() == it->polyline.first_point()); @@ -1303,6 +1403,23 @@ 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) +{ + if (steep_overhang_hole || steep_overhang_contour) { + for (auto entity : entities) { + if (entity->is_loop()) { + 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) { + eloop->make_clockwise(); + } + } + } + } +} + void PerimeterGenerator::process_classic() { // other perimeters @@ -1590,7 +1707,10 @@ void PerimeterGenerator::process_classic() } } // at this point, all loops should be in contours[0] - ExtrusionEntityCollection entities = traverse_loops(*this, contours.front(), thin_walls); + 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); // if brim will be printed, reverse the order of perimeters so that // we continue inwards after having finished the brim @@ -2108,11 +2228,13 @@ void PerimeterGenerator::process_arachne() } } } - - - if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(*this, ordered_extrusions); !extrusion_coll.empty()) + 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); this->loops->append(extrusion_coll); + } ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour()); const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing; diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 184f14c8366..9847f606f75 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", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", + "extra_perimeters_on_overhangs", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", "overhang_reverse", "overhang_reverse_threshold", "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 d492471c4b8..2a8f43cf9a3 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -836,6 +836,27 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); + def = this->add("overhang_reverse", coBool); + 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->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("overhang_reverse_threshold", coFloatOrPercent); + def->label = L("Reverse threshold"); + def->full_label = L("Overhang reversal threshold"); + def->category = L("Quality"); + def->tooltip = L("Number of mm the overhang need to be for the reversal to be considered useful. Can be a % of the perimeter width." + "\nValue 0 enables reversal on every odd layers regardless."); + def->sidetext = L("mm or %"); + def->ratio_over = "line_width"; + def->min = 0; + def->max_literal = 20; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloatOrPercent(50, true)); + def = this->add("overhang_speed_classic", coBool); def->label = L("Classic mode"); def->category = L("Speed"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index f96f16afddf..ad5fdfb5ea2 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -848,6 +848,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, hole_to_polyhole)) ((ConfigOptionFloatOrPercent, hole_to_polyhole_threshold)) ((ConfigOptionBool, hole_to_polyhole_twisted)) + ((ConfigOptionBool, overhang_reverse)) + ((ConfigOptionFloatOrPercent, overhang_reverse_threshold)) ) PRINT_CONFIG_CLASS_DEFINE( diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 8c21a0ee37b..f38a32ce1b8 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1095,6 +1095,8 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "fuzzy_skin_thickness" || opt_key == "fuzzy_skin_point_distance" || opt_key == "detect_overhang_wall" + || opt_key == "overhang_reverse" + || opt_key == "overhang_reverse_threshold" //BBS || opt_key == "enable_overhang_speed" || opt_key == "detect_thin_wall" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index f6ca7f5dfa3..3e18c511387 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -278,6 +278,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con ! config->opt_bool("enable_support") && config->opt_int("enforce_support_layers") == 0 && ! config->opt_bool("detect_thin_wall") && + ! config->opt_bool("overhang_reverse") && config->opt_enum("timelapse_type") == TimelapseType::tlTraditional)) { wxString msg_text = _(L("Spiral mode only works when wall loops is 1, support is disabled, top shell layers is 0, sparse infill density is 0 and timelapse type is traditional.")); @@ -304,6 +305,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con new_conf.set_key_value("enable_support", new ConfigOptionBool(false)); new_conf.set_key_value("enforce_support_layers", new ConfigOptionInt(0)); new_conf.set_key_value("detect_thin_wall", new ConfigOptionBool(false)); + new_conf.set_key_value("overhang_reverse", new ConfigOptionBool(false)); new_conf.set_key_value("timelapse_type", new ConfigOptionEnum(tlTraditional)); sparse_infill_density = 0; timelapse_type = TimelapseType::tlTraditional; @@ -726,6 +728,12 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co 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); } void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 126623e40a0..e700b08244f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -8639,6 +8639,7 @@ void Plater::calib_max_vol_speed(const Calib_Params& params) print_config->set_key_value("top_shell_layers", new ConfigOptionInt(0)); print_config->set_key_value("bottom_shell_layers", new ConfigOptionInt(1)); print_config->set_key_value("sparse_infill_density", new ConfigOptionPercent(0)); + print_config->set_key_value("overhang_reverse", new ConfigOptionBool(false)); print_config->set_key_value("spiral_mode", new ConfigOptionBool(true)); print_config->set_key_value("outer_wall_line_width", new ConfigOptionFloatOrPercent(line_width, false)); print_config->set_key_value("initial_layer_print_height", new ConfigOptionFloat(layer_height)); @@ -8734,6 +8735,7 @@ void Plater::calib_VFA(const Calib_Params& params) print_config->set_key_value("top_shell_layers", new ConfigOptionInt(0)); print_config->set_key_value("bottom_shell_layers", new ConfigOptionInt(1)); print_config->set_key_value("sparse_infill_density", new ConfigOptionPercent(0)); + print_config->set_key_value("overhang_reverse", new ConfigOptionBool(false)); print_config->set_key_value("spiral_mode", new ConfigOptionBool(true)); model().objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum(btOuterOnly)); model().objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(3.0)); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 58b1c88aa5d..43c39922ae5 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1910,6 +1910,8 @@ void TabPrint::build() optgroup->append_single_option_line("reduce_crossing_wall"); 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_threshold"); page = add_options_page(L("Strength"), "empty"); optgroup = page->new_optgroup(L("Walls"), L"param_wall"); diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 55e37dce6a3..d711bac6add 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -656,6 +656,7 @@ void CalibUtils::calib_max_vol_speed(const CalibInfo &calib_info, wxString &erro print_config.set_key_value("top_shell_layers", new ConfigOptionInt(0)); print_config.set_key_value("bottom_shell_layers", new ConfigOptionInt(1)); print_config.set_key_value("sparse_infill_density", new ConfigOptionPercent(0)); + print_config.set_key_value("overhang_reverse", new ConfigOptionBool(false)); print_config.set_key_value("spiral_mode", new ConfigOptionBool(true)); print_config.set_key_value("outer_wall_line_width", new ConfigOptionFloat(line_width)); print_config.set_key_value("initial_layer_print_height", new ConfigOptionFloat(layer_height)); @@ -719,6 +720,7 @@ void CalibUtils::calib_VFA(const CalibInfo &calib_info, wxString &error_message) print_config.set_key_value("top_shell_layers", new ConfigOptionInt(0)); print_config.set_key_value("bottom_shell_layers", new ConfigOptionInt(1)); print_config.set_key_value("sparse_infill_density", new ConfigOptionPercent(0)); + print_config.set_key_value("overhang_reverse", new ConfigOptionBool(false)); print_config.set_key_value("spiral_mode", new ConfigOptionBool(true)); model.objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum(btOuterOnly)); model.objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(3.0));