Merge branch 'main' into enh-port-edit-gcode-dlg

This commit is contained in:
Ocraftyone 2024-01-20 19:43:17 -05:00 committed by GitHub
commit 9f44e151ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 423 additions and 196 deletions

View file

@ -67,7 +67,8 @@ Fill* Fill::new_from_type(const InfillPattern type)
// BBS: for internal solid infill only
case ipConcentricInternal: return new FillConcentricInternal();
// BBS: for bottom and top surface only
case ipMonotonicLine: return new FillMonotonicLineWGapFill();
// Orca: Replace BBS implementation with Prusa implementation
case ipMonotonicLine: return new FillMonotonicLines();
default: throw Slic3r::InvalidArgument("unknown type");
}
}
@ -173,6 +174,66 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para
for (size_t i = idx; i < eec->entities.size(); i++)
eec->entities[i]->set_reverse();
}
// Orca: run gap fill
this->_create_gap_fill(surface, params, eec);
}
}
// Orca: Dedicated function to calculate gap fill lines for the provided surface, according to the print object parameters
// and append them to the out ExtrusionEntityCollection.
void Fill::_create_gap_fill(const Surface* surface, const FillParams& params, ExtrusionEntityCollection* out){
//Orca: just to be safe, check against null pointer for the print object config and if NULL return.
if (this->print_object_config == nullptr) return;
// Orca: Enable gap fill as per the user preference. Return early if gap fill is to not be applied.
if ((this->print_object_config->gap_fill_target.value == gftNowhere) ||
(surface->surface_type == stInternalSolid && this->print_object_config->gap_fill_target.value != gftEverywhere))
return;
Flow new_flow = params.flow;
ExPolygons unextruded_areas;
unextruded_areas = diff_ex(this->no_overlap_expolygons, union_ex(out->polygons_covered_by_spacing(10)));
ExPolygons gapfill_areas = union_ex(unextruded_areas);
if (!this->no_overlap_expolygons.empty())
gapfill_areas = intersection_ex(gapfill_areas, this->no_overlap_expolygons);
if (gapfill_areas.size() > 0 && params.density >= 1) {
double min = 0.2 * new_flow.scaled_spacing() * (1 - INSET_OVERLAP_TOLERANCE);
double max = 2. * new_flow.scaled_spacing();
ExPolygons gaps_ex = diff_ex(
opening_ex(gapfill_areas, float(min / 2.)),
offset2_ex(gapfill_areas, -float(max / 2.), float(max / 2. + ClipperSafetyOffset)));
//BBS: sort the gap_ex to avoid mess travel
Points ordering_points;
ordering_points.reserve(gaps_ex.size());
ExPolygons gaps_ex_sorted;
gaps_ex_sorted.reserve(gaps_ex.size());
for (const ExPolygon &ex : gaps_ex)
ordering_points.push_back(ex.contour.first_point());
std::vector<Points::size_type> order2 = chain_points(ordering_points);
for (size_t i : order2)
gaps_ex_sorted.emplace_back(std::move(gaps_ex[i]));
ThickPolylines polylines;
for (ExPolygon& ex : gaps_ex_sorted) {
//BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
ex.douglas_peucker(SCALED_RESOLUTION * 0.1);
ex.medial_axis(min, max, &polylines);
}
if (!polylines.empty() && !is_bridge(params.extrusion_role)) {
polylines.erase(std::remove_if(polylines.begin(), polylines.end(),
[&](const ThickPolyline& p) {
return p.length() < scale_(params.config->filter_out_gap_fill.value);
}), polylines.end());
ExtrusionEntityCollection gap_fill;
variable_width(polylines, erGapFill, params.flow, gap_fill.entities);
auto gap = std::move(gap_fill.entities);
out->append(gap);
}
}
}

View file

@ -19,6 +19,7 @@
#include "../Flow.hpp"
#include "../ExtrusionEntity.hpp"
#include "../ExtrusionEntityCollection.hpp"
#include "../ShortestPath.hpp"
namespace Slic3r {
@ -106,6 +107,7 @@ public:
FillAdaptive::Octree* adapt_fill_octree = nullptr;
// PrintConfig and PrintObjectConfig are used by infills that use Arachne (Concentric and FillEnsuring).
// Orca: also used by gap fill function.
const PrintConfig *print_config = nullptr;
const PrintObjectConfig *print_object_config = nullptr;
@ -134,7 +136,7 @@ public:
// Perform the fill.
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
virtual ThickPolylines fill_surface_arachne(const Surface* surface, const FillParams& params);
// BBS: this method is used to fill the ExtrusionEntityCollection.
// It call fill_surface by default
virtual void fill_surface_extrusion(const Surface* surface, const FillParams& params, ExtrusionEntitiesPtr& out);
@ -172,6 +174,10 @@ protected:
virtual float _layer_angle(size_t idx) const { return (idx & 1) ? float(M_PI/2.) : 0; }
virtual std::pair<float, Point> _infill_direction(const Surface *surface) const;
// Orca: Dedicated function to calculate gap fill lines for the provided surface, according to the print object parameters
// and append them to the out ExtrusionEntityCollection.
void _create_gap_fill(const Surface* surface, const FillParams& params, ExtrusionEntityCollection* out);
public:
static void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams &params);

View file

@ -3099,7 +3099,22 @@ Points sample_grid_pattern(const Polygons& polygons, coord_t spacing, const Boun
return sample_grid_pattern(union_ex(polygons), spacing, global_bounding_box);
}
void FillMonotonicLineWGapFill::fill_surface_extrusion(const Surface* surface, const FillParams& params, ExtrusionEntitiesPtr& out)
// Orca: Introduced FillMonotonicLines from Prusa slicer, inhereting from FillRectilinear
// This replaces the FillMonotonicLineWGapFill from BBS
Polylines FillMonotonicLines::fill_surface(const Surface *surface, const FillParams &params)
{
FillParams params2 = params;
params2.monotonic = true;
params2.anchor_length_max = 0.0f;
Polylines polylines_out;
if (! fill_surface_by_lines(surface, params2, 0.f, 0.f, polylines_out))
BOOST_LOG_TRIVIAL(error) << "FillMonotonicLines::fill_surface() failed to fill a region.";
return polylines_out;
}
// Orca: Replaced with FillMonotonicLines from Prusa slicer. Moved gap fill algorithm to
// FillBase to perform gap fill for all fill types.
/*void FillMonotonicLineWGapFill::fill_surface_extrusion(const Surface* surface, const FillParams& params, ExtrusionEntitiesPtr& out)
{
ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection();
coll_nosort->no_sort = this->no_sort();
@ -3274,7 +3289,7 @@ void FillMonotonicLineWGapFill::fill_surface_by_lines(const Surface* surface, co
//assert(! it->has_duplicate_points());
it->remove_duplicate_points();
}
}
}*/
} // namespace Slic3r

View file

@ -119,7 +119,19 @@ protected:
float _layer_angle(size_t idx) const override { return 0.f; }
};
class FillMonotonicLineWGapFill : public Fill
// Orca: Introduced FillMonotonicLines from Prusa slicer, inhereting from FillRectilinear
// This replaces the FillMonotonicLineWGapFill from BBS
class FillMonotonicLines : public FillRectilinear
{
public:
Fill* clone() const override { return new FillMonotonicLines(*this); }
~FillMonotonicLines() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
bool no_sort() const override { return true; }
};
//Orca: Replaced with FillMonotonicLines, inheriting from FillRectilinear
/*class FillMonotonicLineWGapFill : public Fill
{
public:
~FillMonotonicLineWGapFill() override = default;
@ -131,7 +143,7 @@ protected:
private:
void fill_surface_by_lines(const Surface* surface, const FillParams& params, Polylines& polylines_out);
};
};*/
Points sample_grid_pattern(const ExPolygon& expolygon, coord_t spacing, const BoundingBox& global_bounding_box);
Points sample_grid_pattern(const ExPolygons& expolygons, coord_t spacing, const BoundingBox& global_bounding_box);

View file

@ -4473,7 +4473,7 @@ static std::unique_ptr<EdgeGrid::Grid> calculate_layer_edge_grid(const Layer& la
}
std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, double speed)
std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, double speed, const ExtrusionEntitiesPtr& region_perimeters)
{
// get a copy; don't modify the orientation of the original loop object otherwise
// next copies (if any) would not detect the correct orientation
@ -4518,8 +4518,12 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
// extrude along the path
std::string gcode;
// Orca:
// Port of "wipe inside before extruding an external perimeter" feature from super slicer
if (m_config.wipe_before_external_loop.value && !paths.empty() && paths.front().size() > 1 && paths.back().size() > 1 && paths.front().role() == erExternalPerimeter) {
// If region perimeters size not greater than or equal to 2, then skip the wipe inside move as we will extrude in mid air
// as no neighbouring perimeter exists. If an internal perimeter exists, we should find 2 perimeters touching the de-retraction point
// 1 - the currently printed external perimeter and 2 - the neighbouring internal perimeter.
if (m_config.wipe_before_external_loop.value && !paths.empty() && paths.front().size() > 1 && paths.back().size() > 1 && paths.front().role() == erExternalPerimeter && region_perimeters.size() > 1) {
const bool is_full_loop_ccw = loop.polygon().is_counter_clockwise();
bool is_hole_loop = (loop.loop_role() & ExtrusionLoopRole::elrHole) != 0; // loop.make_counter_clockwise();
const double nozzle_diam = EXTRUDER_CONFIG(nozzle_diameter);
@ -4560,11 +4564,28 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
pt.rotate(angle, current_point);
pt = (current_pos + vec_dist * (2 * dist / vec_norm)).cast<coord_t>();
pt.rotate(angle, current_point);
// use extrude instead of travel_to_xy to trigger the unretract
ExtrusionPath fake_path_wipe(Polyline{pt, current_point}, paths.front());
fake_path_wipe.mm3_per_mm = 0;
gcode += extrude_path(fake_path_wipe, "move inwards before retraction/seam", speed);
// Search region perimeters for lines that are touching the de-retraction point.
// If an internal perimeter exists, we should find 2 perimeters touching the de-retraction point
// 1: the currently printed external perimeter and 2: the neighbouring internal perimeter.
int discoveredTouchingLines = 0;
for (const ExtrusionEntity* ee : region_perimeters){
auto potential_touching_line = ee->as_polyline();
AABBTreeLines::LinesDistancer<Line> potential_touching_line_distancer{potential_touching_line.lines()};
auto touching_line = potential_touching_line_distancer.all_lines_in_radius(pt, scale_(nozzle_diam));
if(touching_line.size()){
discoveredTouchingLines ++;
if(discoveredTouchingLines > 1) break; // found 2 touching lines. End the search early.
}
}
// found 2 perimeters touching the de-retraction point. Its safe to deretract as the point will be
// inside the model
if(discoveredTouchingLines > 1){
// use extrude instead of travel_to_xy to trigger the unretract
ExtrusionPath fake_path_wipe(Polyline{pt, current_point}, paths.front());
fake_path_wipe.mm3_per_mm = 0;
gcode += extrude_path(fake_path_wipe, "move inwards before retraction/seam", speed);
}
}
@ -4657,14 +4678,14 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string
return gcode;
}
std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string description, double speed)
std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string description, double speed, const ExtrusionEntitiesPtr& region_perimeters)
{
if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity))
return this->extrude_path(*path, description, speed);
else if (const ExtrusionMultiPath* multipath = dynamic_cast<const ExtrusionMultiPath*>(&entity))
return this->extrude_multi_path(*multipath, description, speed);
else if (const ExtrusionLoop* loop = dynamic_cast<const ExtrusionLoop*>(&entity))
return this->extrude_loop(*loop, description, speed);
return this->extrude_loop(*loop, description, speed, region_perimeters);
else
throw Slic3r::InvalidArgument("Invalid argument supplied to extrude()");
return "";
@ -4691,7 +4712,7 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje
m_config.apply(print.get_print_region(&region - &by_region.front()).config());
for (const ExtrusionEntity* ee : region.perimeters)
gcode += this->extrude_entity(*ee, "perimeter", -1.);
gcode += this->extrude_entity(*ee, "perimeter", -1., region.perimeters);
}
return gcode;
}

View file

@ -348,8 +348,12 @@ private:
std::string preamble();
// BBS
std::string change_layer(coordf_t print_z);
std::string extrude_entity(const ExtrusionEntity &entity, std::string description = "", double speed = -1.);
std::string extrude_loop(ExtrusionLoop loop, std::string description, double speed = -1.);
// Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop
// should be executed
std::string extrude_entity(const ExtrusionEntity &entity, std::string description = "", double speed = -1., const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr());
// Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop
// should be executed
std::string extrude_loop(ExtrusionLoop loop, std::string description, double speed = -1., const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr());
std::string extrude_multi_path(ExtrusionMultiPath multipath, std::string description = "", double speed = -1.);
std::string extrude_path(ExtrusionPath path, std::string description = "", double speed = -1.);

View file

@ -768,10 +768,10 @@ bool Preset::has_cali_lines(PresetBundle* preset_bundle)
static std::vector<std::string> s_Preset_print_options {
"layer_height", "initial_layer_print_height", "wall_loops", "alternate_extra_wall", "slice_closing_radius", "spiral_mode", "spiral_mode_smooth", "spiral_mode_max_xy_smoothing", "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","overhang_reverse_internal_only",
"extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness","reduce_wall_solid_infill", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", "overhang_reverse", "overhang_reverse_threshold","overhang_reverse_internal_only",
"seam_position", "staggered_inner_seams", "wall_sequence", "is_infill_first", "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",
"minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern","gap_fill_target",
"ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle",
"max_travel_detour_distance",
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer",
@ -1125,11 +1125,6 @@ void PresetCollection::load_presets(
std::string version_str = key_values[BBL_JSON_KEY_VERSION];
boost::optional<Semver> version = Semver::parse(version_str);
if (!version) continue;
Semver app_version = *(Semver::parse(SLIC3R_VERSION));
if ( version->maj() != app_version.maj()) {
BOOST_LOG_TRIVIAL(warning) << "Preset incompatibla, not loading: " << name;
continue;
}
preset.version = *version;
if (key_values.find(BBL_JSON_KEY_FILAMENT_ID) != key_values.end())
@ -1574,11 +1569,6 @@ bool PresetCollection::load_user_preset(std::string name, std::map<std::string,
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("invalid version %1%, not loading for user preset %2%")%version_str %name;
return false;
}
Semver app_version = *(Semver::parse(SLIC3R_VERSION));
if ( cloud_version->maj() != app_version.maj()) {
BOOST_LOG_TRIVIAL(warning)<< __FUNCTION__ << boost::format("version %1% mismatch with app version %2%, not loading for user preset %3%")%version_str %SLIC3R_VERSION %name;
return false;
}
//setting_id
if (preset_values.find(BBL_JSON_KEY_SETTING_ID) == preset_values.end()) {

View file

@ -768,11 +768,6 @@ bool PresetBundle::import_json_presets(PresetsConfigSubstitutions & s
std::string version_str = key_values[BBL_JSON_KEY_VERSION];
boost::optional<Semver> version = Semver::parse(version_str);
if (!version) return false;
Semver app_version = *(Semver::parse(SoftFever_VERSION));
if (version->maj() != app_version.maj()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset incompatibla, not loading: " << name;
return false;
}
PresetCollection *collection = nullptr;
if (config.has("printer_settings_id"))

View file

@ -248,6 +248,7 @@ static t_config_enum_values s_keys_map_SeamPosition {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SeamPosition)
// Orca
static t_config_enum_values s_keys_map_InternalBridgeFilter {
{ "disabled", ibfDisabled },
{ "limited", ibfLimited },
@ -255,6 +256,14 @@ static t_config_enum_values s_keys_map_InternalBridgeFilter {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InternalBridgeFilter)
// Orca
static t_config_enum_values s_keys_map_GapFillTarget {
{ "everywhere", gftEverywhere },
{ "topbottom", gftTopBottom },
{ "nowhere", gftNowhere },
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(GapFillTarget)
static const t_config_enum_values s_keys_map_SLADisplayOrientation = {
{ "landscape", sladoLandscape},
{ "portrait", sladoPortrait}
@ -752,6 +761,26 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm");
def->min = 0;
def->set_default_value(new ConfigOptionFloat(0.));
def = this->add("gap_fill_target", coEnum);
def->label = L("Apply gap fill");
def->category = L("Strength");
def->tooltip = L("Enables gap fill for the selected surfaces. The minimum gap length that will be filled can be controlled "
"from the filter out tiny gaps option below.\n\n"
"Options:\n"
"1. Everywhere: Applies gap fill to top, bottom and internal solid surfaces\n"
"2. Top and Bottom surfaces: Applies gap fill to top and bottom surfaces only\n"
"3. Nowhere: Disables gap fill\n");
def->enum_keys_map = &ConfigOptionEnum<GapFillTarget>::get_enum_values();
def->enum_values.push_back("everywhere");
def->enum_values.push_back("topbottom");
def->enum_values.push_back("nowhere");
def->enum_labels.push_back(L("Everywhere"));
def->enum_labels.push_back(L("Top and bottom surfaces"));
def->enum_labels.push_back(L("Nowhere"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<GapFillTarget>(gftEverywhere));
def = this->add("enable_overhang_bridge_fan", coBools);
def->label = L("Force cooling for overhang and bridge");
@ -1297,6 +1326,16 @@ void PrintConfigDef::init_fff_params()
"(top+bottom solid layers)");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true));
def = this->add("reduce_wall_solid_infill", coBool);
def->label = L("Further reduce solid infill on walls (experimental)");
def->category = L("Strength");
def->tooltip = L("Further reduces any solid infill applied to walls. As there will be very limited infill supporting"
" solid surfaces, make sure that you are using adequate number of walls to support the part on sloping surfaces.\n\n"
"For heavily sloped surfaces this option is not suitable as it will generate too thin of a top layer "
"and should be disabled.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
auto def_top_fill_pattern = def = this->add("top_surface_pattern", coEnum);
def->label = L("Top surface pattern");

View file

@ -152,10 +152,17 @@ enum SeamPosition {
spNearest, spAligned, spRear, spRandom
};
//Orca
enum InternalBridgeFilter {
ibfDisabled, ibfLimited, ibfNofilter
};
//Orca
enum GapFillTarget {
gftEverywhere, gftTopBottom, gftNowhere
};
enum LiftType {
NormalLift,
SpiralLift,
@ -789,6 +796,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionPercent, tree_support_top_rate))
((ConfigOptionFloat, tree_support_branch_diameter_organic))
((ConfigOptionFloat, tree_support_branch_angle_organic))
((ConfigOptionEnum<GapFillTarget>,gap_fill_target))
((ConfigOptionFloat, min_length_factor))
// Move all acceleration and jerk settings to object
@ -824,6 +832,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, bridge_speed))
((ConfigOptionFloatOrPercent, internal_bridge_speed))
((ConfigOptionBool, ensure_vertical_shell_thickness))
((ConfigOptionBool, reduce_wall_solid_infill))
((ConfigOptionEnum<InfillPattern>, top_surface_pattern))
((ConfigOptionEnum<InfillPattern>, bottom_surface_pattern))
((ConfigOptionEnum<InfillPattern>, internal_solid_infill_pattern))

View file

@ -449,17 +449,6 @@ void PrintObject::prepare_infill()
} // for each region
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
// this will detect bridges and reverse bridges
// and rearrange top/bottom/internal surfaces
// It produces enlarged overlapping bridging areas.
//
// 1) stBottomBridge / stBottom infill is grown by 3mm and clipped by the total infill area. Bridges are detected. The areas may overlap.
// 2) stTop is grown by 3mm and clipped by the grown bottom areas. The areas may overlap.
// 3) Clip the internal surfaces by the grown top/bottom surfaces.
// 4) Merge surfaces with the same style. This will mostly get rid of the overlaps.
//FIXME This does not likely merge surfaces, which are supported by a material with different colors, but same properties.
this->process_external_surfaces();
m_print->throw_if_canceled();
// Debugging output.
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
@ -478,9 +467,23 @@ void PrintObject::prepare_infill()
// and to add a configurable number of solid layers above the BOTTOM / BOTTOMBRIDGE surfaces
// to close these surfaces reliably.
//FIXME Vojtech: Is this a good place to add supporting infills below sloping perimeters?
// Orca: Brought this function call before the process_external_surfaces, to allow bridges over holes to expand more than
// one perimeter. Example of this is the bridge over the benchy lettering.
this->discover_horizontal_shells();
m_print->throw_if_canceled();
// this will detect bridges and reverse bridges
// and rearrange top/bottom/internal surfaces
// It produces enlarged overlapping bridging areas.
//
// 1) stBottomBridge / stBottom infill is grown by 3mm and clipped by the total infill area. Bridges are detected. The areas may overlap.
// 2) stTop is grown by 3mm and clipped by the grown bottom areas. The areas may overlap.
// 3) Clip the internal surfaces by the grown top/bottom surfaces.
// 4) Merge surfaces with the same style. This will mostly get rid of the overlaps.
//FIXME This does not likely merge surfaces, which are supported by a material with different colors, but same properties.
this->process_external_surfaces();
m_print->throw_if_canceled();
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
for (const Layer *layer : m_layers) {
@ -3224,7 +3227,10 @@ void PrintObject::discover_horizontal_shells()
// 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.sparse_infill_density.value == 0) {
// Orca: Also use the same strategy if the user has selected to further reduce
// the amount of solid infill on walls.
if (region_config.sparse_infill_density.value == 0 || region_config.reduce_wall_solid_infill) {
// 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
@ -3237,12 +3243,19 @@ void PrintObject::discover_horizontal_shells()
}
}
if (region_config.sparse_infill_density.value == 0) {
if (region_config.sparse_infill_density.value == 0 || region_config.reduce_wall_solid_infill) {
// 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());
// Orca: Also use the same strategy if the user has selected to reduce
// the amount of solid infill on walls. However reduce the margin to 20% overhang
// as we want to generate infill on sloped vertical surfaces but still keep a small amount of
// filtering. This is an arbitrary value to make this option safe
// by ensuring that top surfaces, especially slanted ones dont go **completely** unsupported
// especially when using single perimeter top layers.
float margin = region_config.reduce_wall_solid_infill? float(neighbor_layerm->flow(frExternalPerimeter).scaled_width()) * 0.2f : float(neighbor_layerm->flow(frExternalPerimeter).scaled_width());
Polygons too_narrow = diff(
new_internal_solid,
opening(new_internal_solid, margin, margin + ClipperSafetyOffset, jtMiter, 5));