diff --git a/src/libslic3r/Support/SupportParameters.hpp b/src/libslic3r/Support/SupportParameters.hpp index da615ab1fd..1318925849 100644 --- a/src/libslic3r/Support/SupportParameters.hpp +++ b/src/libslic3r/Support/SupportParameters.hpp @@ -96,10 +96,10 @@ struct SupportParameters { // No interface layers allowed, print everything with the base support pattern. this->interface_density = this->support_density; } - + SupportMaterialPattern support_pattern = object_config.support_base_pattern; - this->with_sheath = false;//object_config.support_material_with_sheath; - this->base_fill_pattern = + this->with_sheath = /*is_tree(object_config.support_type) &&*/ object_config.tree_support_wall_count > 0; + this->base_fill_pattern = support_pattern == smpHoneycomb ? ipHoneycomb : this->support_density > 0.95 || this->with_sheath ? ipRectilinear : ipSupportBase; this->interface_fill_pattern = (this->interface_density > 0.95 ? ipRectilinear : ipSupportBase); diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index 9b199adc45..18c9f8e0e4 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -17,10 +17,6 @@ #include #include -#define _L(s) Slic3r::I18N::translate(s) - -#define USE_PLAN_LAYER_HEIGHTS 1 - #ifndef M_PI #define M_PI 3.1415926535897932384626433832795 #endif @@ -176,7 +172,7 @@ Lines spanning_tree_to_lines(const std::vector& spanning_tr #ifdef SUPPORT_TREE_DEBUG_TO_SVG -static std::string get_svg_filename(std::string layer_nr_or_z, std::string tag = "bbl_ts") +static std::string get_svg_filename(const std::string& tag = "bbl_ts", const std::string& layer_nr_or_z="") { static bool rand_init = false; @@ -186,10 +182,13 @@ static std::string get_svg_filename(std::string layer_nr_or_z, std::string tag } int rand_num = rand() % 1000000; - //makedir("./SVG"); - std::string prefix = "./SVG/"; + std::string prefix = "C:/Users/arthur.tang/AppData/Roaming/BambuStudioInternal/SVG/"; + //makedir(prefix); std::string suffix = ".svg"; - return prefix + tag + "_" + layer_nr_or_z /*+ "_" + std::to_string(rand_num)*/ + suffix; + std::string name = prefix + tag; + if(!layer_nr_or_z.empty()) + name+= "_" + layer_nr_or_z; + return name + suffix; } static void draw_contours_and_nodes_to_svg @@ -217,10 +216,7 @@ static void draw_contours_and_nodes_to_svg bbox.max.y() = std::max(bbox.max.y(), (coord_t)scale_(10)); SVG svg; - if(!layer_nr_or_z.empty()) - svg.open(get_svg_filename(layer_nr_or_z, name_prefix), bbox); - else - svg.open(name_prefix, bbox); + svg.open(get_svg_filename(name_prefix, layer_nr_or_z), bbox); if (!svg.is_opened()) return; // draw grid @@ -276,7 +272,7 @@ static void draw_layer_mst bbox.merge(bb); } - SVG svg(get_svg_filename(layer_nr_or_z, "mstree").c_str(), bbox); + SVG svg(get_svg_filename("mstree",layer_nr_or_z).c_str(), bbox); if (!svg.is_opened()) return; svg.draw(lines, "blue", coord_t(scale_(0.05))); @@ -293,7 +289,7 @@ static void draw_two_overhangs_to_svg(SupportLayer* ts_layer, const ExPolygons& BoundingBox bbox2 = get_extents(overhangs2); bbox1.merge(bbox2); - SVG svg(get_svg_filename(std::to_string(ts_layer->print_z), "two_overhangs"), bbox1); + SVG svg(get_svg_filename("two_overhangs", std::to_string(ts_layer->print_z)), bbox1); if (!svg.is_opened()) return; svg.draw(union_ex(overhangs1), "blue"); @@ -306,7 +302,7 @@ static void draw_polylines(SupportLayer* ts_layer, Polylines& polylines) return; BoundingBox bbox = get_extents(polylines); - SVG svg(get_svg_filename(std::to_string(ts_layer->print_z), "lightnings"), bbox); + SVG svg(get_svg_filename("lightnings", std::to_string(ts_layer->print_z)), bbox); if (!svg.is_opened()) return; int id = 0; @@ -687,7 +683,7 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p // align with the centered object in current plate (may not be the 1st plate, so need to add the plate offset) m_machine_border.translate(Point(scale_(plate_offset(0)), scale_(plate_offset(1))) - m_object->instances().front().shift); #ifdef SUPPORT_TREE_DEBUG_TO_SVG - SVG svg("SVG/machine_boarder.svg", m_object->bounding_box()); + SVG svg(get_svg_filename("machine_boarder"), m_object->bounding_box()); if (svg.is_opened()) svg.draw(m_machine_border, "yellow"); #endif } @@ -889,7 +885,7 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only) if (!overhang.empty()) { has_sharp_tails = true; #ifdef SUPPORT_TREE_DEBUG_TO_SVG - SVG svg(format("SVG/sharp_tail_orig_%.02f.svg", layer->print_z), m_object->bounding_box()); + SVG svg(get_svg_filename(format("sharp_tail_orig_%.02f", layer->print_z)), m_object->bounding_box()); if (svg.is_opened()) svg.draw(overhang, "red"); #endif } @@ -1007,7 +1003,7 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only) if (!overhang.empty()) has_sharp_tails = true; #ifdef SUPPORT_TREE_DEBUG_TO_SVG - SVG svg(format("SVG/sharp_tail_%.02f.svg",layer->print_z), m_object->bounding_box()); + SVG svg(get_svg_filename(format("sharp_tail_%.02f",layer->print_z)), m_object->bounding_box()); if (svg.is_opened()) svg.draw(overhang, "red"); #endif } @@ -1020,6 +1016,8 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only) for (size_t layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) { if (m_object->print()->canceled()) break; + if(layer_nr+m_raft_layers>=m_object->support_layer_count()) + break; SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers); Layer* layer = m_object->get_layer(layer_nr); for (auto& overhang : ts_layer->overhang_areas) { @@ -1060,9 +1058,9 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only) const Layer* layer1 = m_object->get_layer(cluster.min_layer); BoundingBox bbox = cluster.merged_bbox; bbox.merge(get_extents(layer1->lslices)); - SVG svg(format("SVG/overhangCluster_%s-%s_%s-%s_tail=%s_cantilever=%s_small=%s.svg", + SVG svg(get_svg_filename(format("overhangCluster_%s-%s_%s-%s_tail=%s_cantilever=%s_small=%s", cluster.min_layer, cluster.max_layer, layer1->print_z, m_object->get_layer(cluster.max_layer)->print_z, - cluster.is_sharp_tail, cluster.is_cantilever, cluster.is_small_overhang), bbox); + cluster.is_sharp_tail, cluster.is_cantilever, cluster.is_small_overhang)), bbox); if (svg.is_opened()) { svg.draw(layer1->lslices, "red"); svg.draw(cluster.merged_poly, "blue"); @@ -1108,8 +1106,9 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only) } if (max_bridge_length > 0 && ts_layer->overhang_areas.size() > 0 && lower_layer) { - // do not break bridge for normal part in TreeHybrid - bool break_bridge = !(m_support_params.support_style == smsTreeHybrid && area(ts_layer->overhang_areas) > m_support_params.thresh_big_overhang); + // do not break bridge for normal part in TreeHybrid, nor Tree Strong + bool break_bridge = !(m_support_params.support_style == smsTreeHybrid && area(ts_layer->overhang_areas) > m_support_params.thresh_big_overhang) + && !(m_support_params.support_style==smsTreeStrong); m_object->remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &ts_layer->overhang_areas, max_bridge_length, break_bridge); } @@ -1143,7 +1142,7 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only) if (layer->overhang_areas.empty() && (blockers.size()<=layer->id() || blockers[layer->id()].empty())) continue; - SVG svg(format("SVG/overhang_areas_%s.svg", layer->print_z), m_object->bounding_box()); + SVG svg(get_svg_filename("overhang_areas", std::to_string(layer->print_z)), m_object->bounding_box()); if (svg.is_opened()) { svg.draw_outline(m_object->get_layer(layer->id())->lslices, "yellow"); svg.draw(layer->overhang_areas, "orange"); @@ -1186,18 +1185,20 @@ void TreeSupport::create_tree_support_layers() } for (Layer *layer : m_object->layers()) { - SupportLayer* ts_layer = m_object->add_tree_support_layer(layer->id(), layer->height, layer->print_z, layer->slice_z); + SupportLayer* ts_layer = m_object->add_tree_support_layer(layer_id++, layer->height, layer->print_z, layer->slice_z); if (ts_layer->id() > m_raft_layers) { SupportLayer* lower_layer = m_object->get_support_layer(ts_layer->id() - 1); - lower_layer->upper_layer = ts_layer; - ts_layer->lower_layer = lower_layer; + if (lower_layer) { + lower_layer->upper_layer = ts_layer; + ts_layer->lower_layer = lower_layer; + } } } } static inline BoundingBox fill_expolygon_generate_paths( ExtrusionEntitiesPtr &dst, - ExPolygon &&expolygon, + ExPolygon &expolygon, Fill *filler, const FillParams &fill_params, ExtrusionRole role, @@ -1224,7 +1225,7 @@ static inline BoundingBox fill_expolygon_generate_paths( static inline std::vector fill_expolygons_generate_paths( ExtrusionEntitiesPtr &dst, - ExPolygons &&expolygons, + ExPolygons &expolygons, Fill *filler, const FillParams &fill_params, ExtrusionRole role, @@ -1390,16 +1391,9 @@ void TreeSupport::generate_toolpaths() // generate raft tool path if (m_raft_layers > 0) { - ExtrusionRole raft_contour_er = m_slicing_params.base_raft_layers > 0 ? erSupportMaterial : erSupportMaterialInterface; SupportLayer *ts_layer = m_object->support_layers().front(); Flow flow = Flow(support_extrusion_width, ts_layer->height, nozzle_diameter); - - Polygons loops; - for (const ExPolygon& expoly : raft_areas) { - loops.push_back(expoly.contour); - loops.insert(loops.end(), expoly.holes.begin(), expoly.holes.end()); - } - extrusion_entities_append_loops(ts_layer->support_fills.entities, std::move(loops), raft_contour_er, + extrusion_entities_append_loops(ts_layer->support_fills.entities, to_polygons(raft_areas), erSupportMaterial, float(flow.mm3_per_mm()), float(flow.width()), float(flow.height())); raft_areas = offset_ex(raft_areas, -flow.scaled_spacing() / 2.); } @@ -1407,6 +1401,7 @@ void TreeSupport::generate_toolpaths() for (size_t layer_nr = 0; layer_nr < m_slicing_params.base_raft_layers; layer_nr++) { SupportLayer *ts_layer = m_object->get_support_layer(layer_nr); coordf_t expand_offset = (layer_nr == 0 ? 0. : -1.); + raft_areas = offset_ex(raft_areas, scale_(expand_offset)); Flow support_flow = Flow(support_extrusion_width, ts_layer->height, nozzle_diameter); Fill* filler_interface = Fill::new_from_type(ipRectilinear); @@ -1417,16 +1412,25 @@ void TreeSupport::generate_toolpaths() fill_params.density = object_config.raft_first_layer_density * 0.01; fill_params.dont_adjust = true; - fill_expolygons_generate_paths(ts_layer->support_fills.entities, std::move(offset_ex(raft_areas, scale_(expand_offset))), + fill_expolygons_generate_paths(ts_layer->support_fills.entities, raft_areas, filler_interface, fill_params, erSupportMaterial, support_flow); } + // subtract the non-raft support bases, otherwise we'll get support base on top of raft interfaces which is not stable + SupportLayer* first_non_raft_layer = m_object->get_support_layer(m_raft_layers); + ExPolygons first_non_raft_base; + for (auto& area_group : first_non_raft_layer->area_groups) { + if (area_group.type == SupportLayer::BaseType) + first_non_raft_base.emplace_back(*area_group.area); + } + ExPolygons raft_base_areas = intersection_ex(raft_areas, first_non_raft_base); + ExPolygons raft_interface_areas = diff_ex(raft_areas, raft_base_areas); + for (size_t layer_nr = m_slicing_params.base_raft_layers; layer_nr < m_slicing_params.base_raft_layers + m_slicing_params.interface_raft_layers; layer_nr++) { SupportLayer *ts_layer = m_object->get_support_layer(layer_nr); - coordf_t expand_offset = (layer_nr == 0 ? 0. : -1.); Flow support_flow(support_extrusion_width, ts_layer->height, nozzle_diameter); Fill* filler_interface = Fill::new_from_type(ipRectilinear); @@ -1437,8 +1441,12 @@ void TreeSupport::generate_toolpaths() fill_params.density = interface_density; fill_params.dont_adjust = true; - fill_expolygons_generate_paths(ts_layer->support_fills.entities, std::move(offset_ex(raft_areas, scale_(expand_offset))), + fill_expolygons_generate_paths(ts_layer->support_fills.entities, raft_interface_areas, filler_interface, fill_params, erSupportMaterialInterface, support_flow); + + fill_params.density = object_config.raft_first_layer_density * 0.01; + fill_expolygons_generate_paths(ts_layer->support_fills.entities, raft_base_areas, + filler_interface, fill_params, erSupportMaterial, support_flow); } BoundingBox bbox_object(Point(-scale_(1.), -scale_(1.0)), Point(scale_(1.), scale_(1.))); @@ -1459,7 +1467,7 @@ void TreeSupport::generate_toolpaths() if (m_object->print()->canceled()) break; - m_object->print()->set_status(70, (boost::format(_L("Support: generate toolpath at layer %d")) % layer_id).str()); + m_object->print()->set_status(70, (boost::format(_u8L("Support: generate toolpath at layer %d")) % layer_id).str()); SupportLayer* ts_layer = m_object->get_support_layer(layer_id); Flow support_flow(support_extrusion_width, ts_layer->height, nozzle_diameter); @@ -1526,9 +1534,6 @@ void TreeSupport::generate_toolpaths() bool need_infill = with_infill; if(m_object_config->support_base_pattern==smpDefault) need_infill &= area_group.need_infill; - size_t walls = wall_count; - if (layer_id == 0) walls = std::numeric_limits::max(); - else if (area_group.need_extra_wall && walls < 2) walls += 1; std::shared_ptr filler_support = std::shared_ptr(Fill::new_from_type(layer_id == 0 ? ipConcentric : m_support_params.base_fill_pattern)); filler_support->set_bounding_box(bbox_object); filler_support->spacing = object_config.support_base_pattern_spacing.value * support_density;// constant spacing to align support infill lines @@ -1544,11 +1549,14 @@ void TreeSupport::generate_toolpaths() if (need_infill && m_support_params.base_fill_pattern != ipLightning) { // allow infill-only mode if support is thick enough (so min_wall_count is 0); // otherwise must draw 1 wall + // Don't need extra walls if we have infill. Extra walls may overlap with the infills. size_t min_wall_count = offset(poly, -scale_(support_spacing * 1.5)).empty() ? 1 : 0; - make_perimeter_and_infill(ts_layer->support_fills.entities, *m_object->print(), poly, std::max(min_wall_count, walls), flow, + make_perimeter_and_infill(ts_layer->support_fills.entities, *m_object->print(), poly, std::max(min_wall_count, wall_count), flow, erSupportMaterial, filler_support.get(), support_density); } else { + size_t walls = wall_count; + if (area_group.need_extra_wall && walls < 2) walls += 1; for (size_t i = 1; i < walls; i++) { Polygons contour_new = offset(poly.contour, -(i - 0.5f) * flow.scaled_spacing(), jtSquare); loops.insert(loops.end(), contour_new.begin(), contour_new.end()); @@ -1600,7 +1608,7 @@ void TreeSupport::generate_toolpaths() float(flow.mm3_per_mm()), float(flow.width()), float(flow.height())); #ifdef SUPPORT_TREE_DEBUG_TO_SVG - std::string name = "./SVG/trees_polyline_" + std::to_string(ts_layer->print_z) /*+ "_" + std::to_string(rand_num)*/ + ".svg"; + std::string name = get_svg_filename("trees_polyline", std::to_string(ts_layer->print_z)); BoundingBox bbox = get_extents(ts_layer->base_areas); SVG svg(name, bbox); if (svg.is_opened()) { @@ -1631,7 +1639,7 @@ void TreeSupport::generate() // Generate overhang areas profiler.stage_start(STAGE_DETECT_OVERHANGS); - m_object->print()->set_status(55, _L("Support: detect overhangs")); + m_object->print()->set_status(55, _u8L("Support: detect overhangs")); detect_overhangs(); profiler.stage_finish(STAGE_DETECT_OVERHANGS); @@ -1645,14 +1653,14 @@ void TreeSupport::generate() std::vector move_bounds(m_highest_overhang_layer + 1); profiler.stage_start(STAGE_GENERATE_CONTACT_NODES); - m_object->print()->set_status(56, _L("Support: generate contact points")); + m_object->print()->set_status(56, _u8L("Support: generate contact points")); generate_contact_points(contact_nodes, move_bounds); profiler.stage_finish(STAGE_GENERATE_CONTACT_NODES); //Drop nodes to lower layers. profiler.stage_start(STAGE_DROP_DOWN_NODES); - m_object->print()->set_status(60, _L("Support: propagate branches")); + m_object->print()->set_status(60, _u8L("Support: propagate branches")); drop_nodes(contact_nodes); profiler.stage_finish(STAGE_DROP_DOWN_NODES); @@ -1660,7 +1668,7 @@ void TreeSupport::generate() //Generate support areas. profiler.stage_start(STAGE_DRAW_CIRCLES); - m_object->print()->set_status(65, _L("Support: draw polygons")); + m_object->print()->set_status(65, _u8L("Support: draw polygons")); draw_circles(contact_nodes); profiler.stage_finish(STAGE_DRAW_CIRCLES); @@ -1675,7 +1683,7 @@ void TreeSupport::generate() contact_nodes.clear(); profiler.stage_start(STAGE_GENERATE_TOOLPATHS); - m_object->print()->set_status(69, _L("Support: generate toolpath")); + m_object->print()->set_status(69, _u8L("Support: generate toolpath")); generate_toolpaths(); profiler.stage_finish(STAGE_GENERATE_TOOLPATHS); @@ -2063,7 +2071,7 @@ void TreeSupport::draw_circles(const std::vector>& con ts_layer->lslices_bboxes.emplace_back(get_extents(expoly)); ts_layer->backup_untyped_slices(); - m_object->print()->set_status(65, (boost::format( _L("Support: generate polygons at layer %d")) % layer_nr).str()); + m_object->print()->set_status(65, (boost::format( _u8L("Support: generate polygons at layer %d")) % layer_nr).str()); // join roof segments double contact_dist_scaled = scale_(0.5);// scale_(m_slicing_params.gap_support_object); @@ -2248,7 +2256,7 @@ void TreeSupport::draw_circles(const std::vector>& con std::map> holePropagationInfos; for (int layer_nr = m_object->layer_count() - 1; layer_nr > 0; layer_nr--) { if (print->canceled()) break; - m_object->print()->set_status(66, (boost::format(_L("Support: fix holes at layer %d")) % layer_nr).str()); + m_object->print()->set_status(66, (boost::format(_u8L("Support: fix holes at layer %d")) % layer_nr).str()); const std::vector& curr_layer_nodes = contact_nodes[layer_nr]; SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers); @@ -2342,10 +2350,9 @@ void TreeSupport::draw_circles(const std::vector>& con ExPolygons& base_areas = ts_layer->base_areas; ExPolygons& roof_areas = ts_layer->roof_areas; ExPolygons& roof_1st_layer = ts_layer->roof_1st_layer; - ExPolygons& floor_areas = ts_layer->floor_areas; + ExPolygons roofs = roof_areas; append(roofs, roof_1st_layer); if (base_areas.empty() && roof_areas.empty() && roof_1st_layer.empty()) continue; - char fname[10]; sprintf(fname, "%d_%.2f", layer_nr, ts_layer->print_z); - draw_contours_and_nodes_to_svg("", base_areas, roof_areas, roof_1st_layer, {}, {}, get_svg_filename(fname, "circles"), {"base", "roof", "roof1st"}); + draw_contours_and_nodes_to_svg(format("%d_%.2f", layer_nr, ts_layer->print_z), base_areas, roofs, ts_layer->lslices, {}, {}, "circles", {"base", "roof", "lslices"}, {"blue","red","black"}); } #endif // SUPPORT_TREE_DEBUG_TO_SVG @@ -2424,9 +2431,9 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod std::deque> unsupported_branch_leaves; // All nodes that are leaves on this layer that would result in unsupported ('mid-air') branches. const Layer* ts_layer = m_object->get_support_layer(layer_nr); - m_object->print()->set_status(60, (boost::format(_L("Support: propagate branches at layer %d")) % layer_nr).str()); + m_object->print()->set_status(60, (boost::format(_u8L("Support: propagate branches at layer %d")) % layer_nr).str()); - Polygons layer_contours = m_ts_data->get_contours_with_holes(layer_nr); + Polygons layer_contours = std::move(m_ts_data->get_contours_with_holes(layer_nr)); //std::unordered_map& mst_line_x_layer_contour_cache = m_mst_line_x_layer_contour_caches[layer_nr]; std::unordered_map mst_line_x_layer_contour_cache; auto is_line_cut_by_contour = [&mst_line_x_layer_contour_cache,&layer_contours](Point a, Point b) diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index a376aa7f1f..a8e77677d4 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -611,7 +611,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co for (auto el : {"tree_support_branch_angle", "tree_support_branch_distance", "tree_support_branch_diameter" }) toggle_line(el, support_is_normal_tree); // settings specific to normal trees - for (auto el : {"tree_support_wall_count", "tree_support_auto_brim", "tree_support_brim_width", "tree_support_adaptive_layer_height"}) + for (auto el : {"tree_support_auto_brim", "tree_support_brim_width", "tree_support_adaptive_layer_height"}) toggle_line(el, support_is_normal_tree); // 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"}) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index fea8908d75..67863846d2 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2250,6 +2250,7 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Advanced"), L"param_advanced"); optgroup->append_single_option_line("support_top_z_distance", "support#top-z-distance"); optgroup->append_single_option_line("support_bottom_z_distance", "support#bottom-z-distance"); + optgroup->append_single_option_line("tree_support_wall_count"); optgroup->append_single_option_line("support_base_pattern", "support#base-pattern"); optgroup->append_single_option_line("support_base_pattern_spacing", "support#base-pattern"); optgroup->append_single_option_line("support_angle"); @@ -2278,7 +2279,6 @@ void TabPrint::build() optgroup->append_single_option_line("tree_support_branch_angle_organic", "support#tree-support-only-options"); optgroup->append_single_option_line("tree_support_angle_slow"); optgroup->append_single_option_line("tree_support_branch_diameter_double_wall"); - optgroup->append_single_option_line("tree_support_wall_count"); optgroup->append_single_option_line("tree_support_adaptive_layer_height"); optgroup->append_single_option_line("tree_support_auto_brim"); optgroup->append_single_option_line("tree_support_brim_width");