mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-07 15:07:31 -06:00
[Feature] Enabled gap fill algorithm for all solid fill types (#3412)
* ENH: Enabled gap fill algorithm for all solid fill types * Made gap fill an option & refactored code into its own method * Code comment updates * Converted gap fill to enum and control filter out gap fill in the UI * Update label for consistency * Spelling mistake
This commit is contained in:
parent
c0c05c715b
commit
fe148515ce
9 changed files with 143 additions and 7 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -173,6 +175,10 @@ protected:
|
|||
|
||||
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 ¶ms);
|
||||
static void connect_infill(Polylines &&infill_ordered, const Polygons &boundary, const BoundingBox& bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ¶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 @@ 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);
|
||||
|
|
|
@ -771,7 +771,7 @@ static std::vector<std::string> 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",
|
||||
|
|
|
@ -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}
|
||||
|
@ -753,6 +762,26 @@ void PrintConfigDef::init_fff_params()
|
|||
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");
|
||||
def->tooltip = L("Enable this option to optimize part cooling fan speed for overhang and bridge to get better cooling");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<GapFillTarget>("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;
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue