diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 0a159d5d881..772395f9bc4 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -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 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); + } } } diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index f4eaa20fb68..38f8c722b5d 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -19,6 +19,7 @@ #include "../Flow.hpp" #include "../ExtrusionEntity.hpp" #include "../ExtrusionEntityCollection.hpp" +#include "../ShortestPath.hpp" namespace Slic3r { @@ -106,6 +107,7 @@ class Fill 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 @@ class Fill // Perform the fill. virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms); 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 @@ class Fill virtual float _layer_angle(size_t idx) const { return (idx & 1) ? float(M_PI/2.) : 0; } virtual std::pair _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 ¶ms); diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index c97de62aa39..dc9595eac4f 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -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 ¶ms) +{ + 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 diff --git a/src/libslic3r/Fill/FillRectilinear.hpp b/src/libslic3r/Fill/FillRectilinear.hpp index c1b1680431c..f85dce07e85 100644 --- a/src/libslic3r/Fill/FillRectilinear.hpp +++ b/src/libslic3r/Fill/FillRectilinear.hpp @@ -119,7 +119,19 @@ class FillSupportBase : public FillRectilinear 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 ¶ms) 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 @@ class FillMonotonicLineWGapFill : public Fill 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); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index d4be5c2b76a..db675a51931 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -771,7 +771,7 @@ static std::vector s_Preset_print_options { "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", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index b18ea365bd5..980e1b63db1 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -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::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(gftEverywhere)); + def = this->add("enable_overhang_bridge_fan", coBools); def->label = L("Force cooling for overhang and bridge"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 432e517746b..c665cee6e9a 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -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,gap_fill_target)) ((ConfigOptionFloat, min_length_factor)) // Move all acceleration and jerk settings to object diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 95bdae6aedc..f6bbcecf09f 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -510,6 +510,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co apply(config, &new_conf); } + // Orca: Hide the filter out tiny gaps field when gap fill target is nowhere as no gap fill will be applied. + bool have_gap_fill = config->opt_enum("gap_fill_target") != gftNowhere; + toggle_line("filter_out_gap_fill", have_gap_fill); + bool have_ensure_vertical_thickness = config->opt_bool("ensure_vertical_shell_thickness"); if(have_ensure_vertical_thickness) { DynamicPrintConfig new_conf = *config; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 7e62e1f8453..5a67afa5146 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2009,6 +2009,7 @@ void TabPrint::build() optgroup->append_single_option_line("infill_anchor"); optgroup->append_single_option_line("infill_anchor_max"); optgroup->append_single_option_line("internal_solid_infill_pattern"); + optgroup->append_single_option_line("gap_fill_target"); optgroup->append_single_option_line("filter_out_gap_fill"); optgroup = page->new_optgroup(L("Advanced"), L"param_advanced");