[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:
Ioannis Giannakas 2024-01-18 14:43:23 +00:00 committed by GitHub
parent c0c05c715b
commit fe148515ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 143 additions and 7 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);