diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 9fa3c7430..0e760f3d3 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -431,7 +431,7 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config) static std::vector s_Preset_print_options { "layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "slicing_mode", "top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness", - "extra_perimeters", "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs", + "extra_perimeters", "extra_perimeters_on_overhangs", "avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs", "seam_position","staggered_inner_seams", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern", "infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle", "solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index ba1c7f056..30206a6c6 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -806,14 +806,6 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionStrings { "; Filament-specific end gcode \n;END gcode for filament\n" }); - def = this->add("ensure_vertical_shell_thickness", coBool); - def->label = L("Ensure vertical shell thickness"); - def->category = L("Layers and Perimeters"); - def->tooltip = L("Add solid infill near sloping surfaces to guarantee the vertical shell thickness " - "(top+bottom solid layers)."); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(false)); - auto def_top_fill_pattern = def = this->add("top_fill_pattern", coEnum); def->label = L("Top fill pattern"); def->category = L("Infill"); @@ -4097,6 +4089,8 @@ static std::set PrintConfigDef_ignore = { "fuzzy_skin_perimeter_mode", "fuzzy_skin_shape", // Introduced in PrusaSlicer 2.3.0-alpha2, later replaced by automatic calculation based on extrusion width. "wall_add_middle_threshold", "wall_split_middle_threshold", + // Replaced by new concentric ensuring in 2.6.0-alpha5 + "ensure_vertical_shell_thickness", }; void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index df57ab1da..9e89fcefd 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -569,7 +569,6 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, bottom_solid_min_thickness)) ((ConfigOptionFloat, bridge_flow_ratio)) ((ConfigOptionFloat, bridge_speed)) - ((ConfigOptionBool, ensure_vertical_shell_thickness)) ((ConfigOptionEnum, top_fill_pattern)) ((ConfigOptionEnum, bottom_fill_pattern)) ((ConfigOptionFloatOrPercent, external_perimeter_extrusion_width)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index f87741cfa..3a0444b46 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -719,7 +719,6 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "infill_extruder" || opt_key == "solid_infill_extruder" || opt_key == "infill_extrusion_width" - || opt_key == "ensure_vertical_shell_thickness" || opt_key == "bridge_angle") { steps.emplace_back(posPrepareInfill); } else if ( @@ -1204,7 +1203,7 @@ void PrintObject::discover_vertical_shells() bool has_extra_layers = false; for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) { const PrintRegionConfig &config = this->printing_region(region_id).config(); - if (config.ensure_vertical_shell_thickness.value && has_extra_layers_fn(config)) { + if (has_extra_layers_fn(config)) { has_extra_layers = true; break; } @@ -1282,9 +1281,6 @@ void PrintObject::discover_vertical_shells() for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) { const PrintRegion ®ion = this->printing_region(region_id); - if (! region.config().ensure_vertical_shell_thickness.value) - // This region will be handled by discover_horizontal_shells(). - continue; if (! has_extra_layers_fn(region.config())) // Zero or 1 layer, there is no additional vertical wall thickness enforced. continue; @@ -2440,195 +2436,35 @@ void PrintObject::clip_fill_surfaces() void PrintObject::discover_horizontal_shells() { BOOST_LOG_TRIVIAL(trace) << "discover_horizontal_shells()"; - - for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) { - for (size_t i = 0; i < m_layers.size(); ++ i) { + + for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) { + for (size_t i = 0; i < m_layers.size(); ++i) { m_print->throw_if_canceled(); - Layer *layer = m_layers[i]; - LayerRegion *layerm = layer->regions()[region_id]; + Layer *layer = m_layers[i]; + LayerRegion *layerm = layer->regions()[region_id]; const PrintRegionConfig ®ion_config = layerm->region().config(); if (region_config.solid_infill_every_layers.value > 0 && region_config.fill_density.value > 0 && (i % region_config.solid_infill_every_layers) == 0) { // Insert a solid internal layer. Mark stInternal surfaces as stInternalSolid or stInternalBridge. - SurfaceType type = (region_config.fill_density == 100 || region_config.solid_infill_every_layers == 1) ? stInternalSolid : stInternalBridge; + SurfaceType type = (region_config.fill_density == 100 || region_config.solid_infill_every_layers == 1) ? stInternalSolid : + stInternalBridge; for (Surface &surface : layerm->m_fill_surfaces.surfaces) if (surface.surface_type == stInternal) surface.surface_type = type; } - - // If ensure_vertical_shell_thickness, then the rest has already been performed by discover_vertical_shells(). - if (region_config.ensure_vertical_shell_thickness.value) - continue; - - coordf_t print_z = layer->print_z; - coordf_t bottom_z = layer->bottom_z(); - for (size_t idx_surface_type = 0; idx_surface_type < 3; ++ idx_surface_type) { - m_print->throw_if_canceled(); - SurfaceType type = (idx_surface_type == 0) ? stTop : (idx_surface_type == 1) ? stBottom : stBottomBridge; - int num_solid_layers = (type == stTop) ? region_config.top_solid_layers.value : region_config.bottom_solid_layers.value; - if (num_solid_layers == 0) - continue; - // Find slices of current type for current layer. - // Use slices instead of fill_surfaces, because they also include the perimeter area, - // which needs to be propagated in shells; we need to grow slices like we did for - // fill_surfaces though. Using both ungrown slices and grown fill_surfaces will - // not work in some situations, as there won't be any grown region in the perimeter - // area (this was seen in a model where the top layer had one extra perimeter, thus - // its fill_surfaces were thinner than the lower layer's infill), however it's the best - // solution so far. Growing the external slices by EXTERNAL_INFILL_MARGIN will put - // too much solid infill inside nearly-vertical slopes. - - // Surfaces including the area of perimeters. Everything, that is visible from the top / bottom - // (not covered by a layer above / below). - // This does not contain the areas covered by perimeters! - Polygons solid; - for (const Surface &surface : layerm->slices()) - if (surface.surface_type == type) - polygons_append(solid, to_polygons(surface.expolygon)); - // Infill areas (slices without the perimeters). - for (const Surface &surface : layerm->fill_surfaces()) - if (surface.surface_type == type) - polygons_append(solid, to_polygons(surface.expolygon)); - if (solid.empty()) - continue; -// Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == stTop) ? 'top' : 'bottom'; - - // Scatter top / bottom regions to other layers. Scattering process is inherently serial, it is difficult to parallelize without locking. - for (int n = (type == stTop) ? int(i) - 1 : int(i) + 1; - (type == stTop) ? - (n >= 0 && (int(i) - n < num_solid_layers || - print_z - m_layers[n]->print_z < region_config.top_solid_min_thickness.value - EPSILON)) : - (n < int(m_layers.size()) && (n - int(i) < num_solid_layers || - m_layers[n]->bottom_z() - bottom_z < region_config.bottom_solid_min_thickness.value - EPSILON)); - (type == stTop) ? -- n : ++ n) - { -// Slic3r::debugf " looking for neighbors on layer %d...\n", $n; - // Reference to the lower layer of a TOP surface, or an upper layer of a BOTTOM surface. - LayerRegion *neighbor_layerm = m_layers[n]->regions()[region_id]; - - // find intersection between neighbor and current layer's surfaces - // intersections have contours and holes - // we update $solid so that we limit the next neighbor layer to the areas that were - // found on this one - in other words, solid shells on one layer (for a given external surface) - // are always a subset of the shells found on the previous shell layer - // this approach allows for DWIM in hollow sloping vases, where we want bottom - // shells to be generated in the base but not in the walls (where there are many - // narrow bottom surfaces): reassigning $solid will consider the 'shadow' of the - // upper perimeter as an obstacle and shell will not be propagated to more upper layers - //FIXME How does it work for stInternalBRIDGE? This is set for sparse infill. Likely this does not work. - Polygons new_internal_solid; - { - Polygons internal; - for (const Surface &surface : neighbor_layerm->fill_surfaces()) - if (surface.surface_type == stInternal || surface.surface_type == stInternalSolid) - polygons_append(internal, to_polygons(surface.expolygon)); - new_internal_solid = intersection(solid, internal, ApplySafetyOffset::Yes); - } - if (new_internal_solid.empty()) { - // No internal solid needed on this layer. In order to decide whether to continue - // searching on the next neighbor (thus enforcing the configured number of solid - // layers, use different strategies according to configured infill density: - if (region_config.fill_density.value == 0) { - // If user expects the object to be void (for example a hollow sloping vase), - // don't continue the search. In this case, we only generate the external solid - // shell if the object would otherwise show a hole (gap between perimeters of - // the two layers), and internal solid shells are a subset of the shells found - // on each previous layer. - goto EXTERNAL; - } else { - // If we have internal infill, we can generate internal solid shells freely. - continue; - } - } - - if (region_config.fill_density.value == 0) { - // if we're printing a hollow object we discard any solid shell thinner - // than a perimeter width, since it's probably just crossing a sloping wall - // and it's not wanted in a hollow print even if it would make sense when - // obeying the solid shell count option strictly (DWIM!) - float margin = float(neighbor_layerm->flow(frExternalPerimeter).scaled_width()); - Polygons too_narrow = diff( - new_internal_solid, - opening(new_internal_solid, margin, margin + ClipperSafetyOffset, jtMiter, 5)); - // Trim the regularized region by the original region. - if (! too_narrow.empty()) - new_internal_solid = solid = diff(new_internal_solid, too_narrow); - } - - // make sure the new internal solid is wide enough, as it might get collapsed - // when spacing is added in Fill.pm - { - //FIXME Vojtech: Disable this and you will be sorry. - // https://github.com/prusa3d/PrusaSlicer/issues/26 bottom - float margin = 3.f * layerm->flow(frSolidInfill).scaled_width(); // require at least this size - // we use a higher miterLimit here to handle areas with acute angles - // in those cases, the default miterLimit would cut the corner and we'd - // get a triangle in $too_narrow; if we grow it below then the shell - // would have a different shape from the external surface and we'd still - // have the same angle, so the next shell would be grown even more and so on. - Polygons too_narrow = diff( - new_internal_solid, - opening(new_internal_solid, margin, margin + ClipperSafetyOffset, ClipperLib::jtMiter, 5)); - if (! too_narrow.empty()) { - // grow the collapsing parts and add the extra area to the neighbor layer - // as well as to our original surfaces so that we support this - // additional area in the next shell too - // make sure our grown surfaces don't exceed the fill area - Polygons internal; - for (const Surface &surface : neighbor_layerm->fill_surfaces()) - if (surface.is_internal() && !surface.is_bridge()) - polygons_append(internal, to_polygons(surface.expolygon)); - polygons_append(new_internal_solid, - intersection( - expand(too_narrow, +margin), - // Discard bridges as they are grown for anchoring and we can't - // remove such anchors. (This may happen when a bridge is being - // anchored onto a wall where little space remains after the bridge - // is grown, and that little space is an internal solid shell so - // it triggers this too_narrow logic.) - internal)); - // see https://github.com/prusa3d/PrusaSlicer/pull/3426 - // solid = new_internal_solid; - } - } - - // internal-solid are the union of the existing internal-solid surfaces - // and new ones - SurfaceCollection backup = std::move(neighbor_layerm->m_fill_surfaces); - polygons_append(new_internal_solid, to_polygons(backup.filter_by_type(stInternalSolid))); - ExPolygons internal_solid = union_ex(new_internal_solid); - // assign new internal-solid surfaces to layer - neighbor_layerm->m_fill_surfaces.set(internal_solid, stInternalSolid); - // subtract intersections from layer surfaces to get resulting internal surfaces - Polygons polygons_internal = to_polygons(std::move(internal_solid)); - ExPolygons internal = diff_ex(backup.filter_by_type(stInternal), polygons_internal, ApplySafetyOffset::Yes); - // assign resulting internal surfaces to layer - neighbor_layerm->m_fill_surfaces.append(internal, stInternal); - polygons_append(polygons_internal, to_polygons(std::move(internal))); - // assign top and bottom surfaces to layer - backup.keep_types({ stTop, stBottom, stBottomBridge }); - std::vector top_bottom_groups; - backup.group(&top_bottom_groups); - for (SurfacesPtr &group : top_bottom_groups) - neighbor_layerm->m_fill_surfaces.append( - diff_ex(group, polygons_internal), - // Use an existing surface as a template, it carries the bridge angle etc. - *group.front()); - } - EXTERNAL:; - } // foreach type (stTop, stBottom, stBottomBridge) + // The rest has already been performed by discover_vertical_shells(). } // for each layer - } // for each region + } // for each region #ifdef SLIC3R_DEBUG_SLICE_PROCESSING - for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) { + for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) { for (const Layer *layer : m_layers) { const LayerRegion *layerm = layer->m_regions[region_id]; layerm->export_region_slices_to_svg_debug("5_discover_horizontal_shells"); layerm->export_region_fill_surfaces_to_svg_debug("5_discover_horizontal_shells"); } // for each layer - } // for each region -#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ + } // for each region +#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ } // void PrintObject::discover_horizontal_shells() // combine fill surfaces across layers to honor the "infill every N layers" option diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 9a0cf3881..5129cdc61 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -77,7 +77,6 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con fill_density == 0 && ! config->opt_bool("support_material") && config->opt_int("support_material_enforce_layers") == 0 && - config->opt_bool("ensure_vertical_shell_thickness") && ! config->opt_bool("thin_walls"))) { wxString msg_text = _(L("The Spiral Vase mode requires:\n" @@ -85,7 +84,6 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con "- no top solid layers\n" "- 0% fill density\n" "- no support material\n" - "- Ensure vertical shell thickness enabled\n" "- Detect thin walls disabled")); if (is_global_config) msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable Spiral Vase?")); @@ -100,7 +98,6 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); new_conf.set_key_value("support_material", new ConfigOptionBool(false)); new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0)); - new_conf.set_key_value("ensure_vertical_shell_thickness", new ConfigOptionBool(true)); new_conf.set_key_value("thin_walls", new ConfigOptionBool(false)); fill_density = 0; support = false; @@ -219,7 +216,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) { bool have_perimeters = config->opt_int("perimeters") > 0; - for (auto el : { "extra_perimeters","extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "thin_walls", "overhangs", + for (auto el : { "extra_perimeters","extra_perimeters_on_overhangs", "thin_walls", "overhangs", "seam_position","staggered_inner_seams", "external_perimeters_first", "external_perimeter_extrusion_width", "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "enable_dynamic_overhang_speeds"}) toggle_field(el, have_perimeters); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ae9bb175f..6923aaff4 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1427,7 +1427,6 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Quality (slower slicing)")); optgroup->append_single_option_line("extra_perimeters", category_path + "extra-perimeters-if-needed"); optgroup->append_single_option_line("extra_perimeters_on_overhangs", category_path + "extra-perimeters-on-overhangs"); - optgroup->append_single_option_line("ensure_vertical_shell_thickness", category_path + "ensure-vertical-shell-thickness"); optgroup->append_single_option_line("avoid_crossing_curled_overhangs", category_path + "avoid-crossing-curled-overhangs"); optgroup->append_single_option_line("avoid_crossing_perimeters", category_path + "avoid-crossing-perimeters"); optgroup->append_single_option_line("avoid_crossing_perimeters_max_detour", category_path + "avoid_crossing_perimeters_max_detour");