Apply FillBoundedRectilinear on narrow internal solid infills

to reduce zig-zag movements of the print head on overhangs.
Always use thick bridges on internal bridges.
Co-authored-by: lane.wei <lane.wei@bambulab.com>
This commit is contained in:
Vojtech Bubnik 2023-01-03 17:42:10 +01:00
parent 398222a49f
commit 60f6766aab
3 changed files with 56 additions and 12 deletions

View file

@ -16,9 +16,10 @@
#include "FillLightning.hpp"
#include "FillConcentric.hpp"
namespace Slic3r {
static constexpr const float NarrowInfillAreaThresholdMM = 3.f;
struct SurfaceFillParams
{
// Zero based extruder ID.
@ -148,6 +149,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
erBridgeInfill :
(surface.is_solid() ?
(surface.is_top() ? erTopSolidInfill : erSolidInfill) :
//(surface.is_top() ? erTopSolidInfill : (surface.is_bottom()? erBottomSurface : erSolidInfill)) :
erInternalInfill);
params.bridge_angle = float(surface.bridge_angle);
params.angle = float(Geometry::deg2rad(region_config.fill_angle.value));
@ -155,7 +157,8 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
// Calculate the actual flow we'll be using for this infill.
params.bridge = is_bridge || Fill::use_bridge_flow(params.pattern);
params.flow = params.bridge ?
layerm.bridging_flow(extrusion_role) :
// Always enable thick bridges for internal bridges.
layerm.bridging_flow(extrusion_role, surface.is_bridge() && ! surface.is_external()) :
layerm.flow(extrusion_role, (surface.thickness == -1) ? layer.height : surface.thickness);
// Calculate flow spacing for infill pattern generation.
@ -298,6 +301,46 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
}
}
// Detect narrow internal solid infill area and use ipBoundedRectilinear pattern instead.
{
std::vector<char> narrow_expolygons;
static constexpr const auto narrow_pattern = ipBoundedRectilinear;
for (size_t surface_fill_id = 0, num_old_fills = surface_fills.size(); surface_fill_id < num_old_fills; ++ surface_fill_id)
if (SurfaceFill &fill = surface_fills[surface_fill_id]; fill.surface.surface_type == stInternalSolid) {
size_t num_expolygons = fill.expolygons.size();
narrow_expolygons.clear();
narrow_expolygons.reserve(num_expolygons);
// Detect narrow expolygons.
int num_narrow = 0;
for (const ExPolygon &ex : fill.expolygons) {
bool narrow = offset_ex(ex, -scaled<float>(NarrowInfillAreaThresholdMM)).empty();
num_narrow += int(narrow);
narrow_expolygons.emplace_back(narrow);
}
if (num_narrow == num_expolygons) {
// All expolygons are narrow, change the fill pattern.
fill.params.pattern = narrow_pattern;
} else if (num_narrow > 0) {
// Some expolygons are narrow, split the fills.
params = fill.params;
params.pattern = narrow_pattern;
surface_fills.emplace_back(params);
SurfaceFill &old_fill = surface_fills[surface_fill_id];
SurfaceFill &new_fill = surface_fills.back();
new_fill.region_id = old_fill.region_id;
new_fill.surface.surface_type = stInternalSolid;
new_fill.surface.thickness = old_fill.surface.thickness;
new_fill.expolygons.reserve(num_narrow);
for (size_t i = 0; i < narrow_expolygons.size(); ++ i)
if (narrow_expolygons[i])
new_fill.expolygons.emplace_back(std::move(old_fill.expolygons[i]));
old_fill.expolygons.erase(std::remove_if(old_fill.expolygons.begin(), old_fill.expolygons.end(),
[&narrow_expolygons, ex_first = old_fill.expolygons.data()](const ExPolygon& ex) { return narrow_expolygons[&ex - ex_first]; }),
old_fill.expolygons.end());
}
}
}
return surface_fills;
}
@ -444,16 +487,17 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
f->layer_id = this->id();
f->z = this->print_z;
f->angle = surface_fill.params.angle;
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
f->print_config = &this->object()->print()->config();
f->print_object_config = &this->object()->config();
if (surface_fill.params.pattern == ipLightning)
dynamic_cast<FillLightning::Filler*>(f.get())->generator = lightning_generator;
if (perimeter_generator.value == PerimeterGeneratorType::Arachne && surface_fill.params.pattern == ipConcentric) {
FillConcentric *fill_concentric = dynamic_cast<FillConcentric *>(f.get());
assert(fill_concentric != nullptr);
fill_concentric->print_config = &this->object()->print()->config();
fill_concentric->print_object_config = &this->object()->config();
if (surface_fill.params.pattern == ipBoundedRectilinear) {
auto *fill_bounded_rectilinear = dynamic_cast<FillBoundedRectilinear *>(f.get());
assert(fill_bounded_rectilinear != nullptr);
fill_bounded_rectilinear->print_region_config = &m_regions[surface_fill.region_id]->region().config();
}
// calculate flow spacing for infill pattern generation
@ -483,7 +527,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.anchor_length = surface_fill.params.anchor_length;
params.anchor_length_max = surface_fill.params.anchor_length_max;
params.resolution = resolution;
params.use_arachne = perimeter_generator == PerimeterGeneratorType::Arachne && surface_fill.params.pattern == ipConcentric;
params.use_arachne = (perimeter_generator == PerimeterGeneratorType::Arachne && surface_fill.params.pattern == ipConcentric) || surface_fill.params.pattern == ipBoundedRectilinear;
params.layer_height = layerm.layer()->height;
for (ExPolygon &expoly : surface_fill.expolygons) {

View file

@ -134,7 +134,7 @@ public:
Flow flow(FlowRole role) const;
Flow flow(FlowRole role, double layer_height) const;
Flow bridging_flow(FlowRole role) const;
Flow bridging_flow(FlowRole role, bool force_thick_bridges = false) const;
void slices_to_fill_surfaces_clipped();
void prepare_fill_surfaces();

View file

@ -27,12 +27,12 @@ Flow LayerRegion::flow(FlowRole role, double layer_height) const
return m_region->flow(*m_layer->object(), role, layer_height, m_layer->id() == 0);
}
Flow LayerRegion::bridging_flow(FlowRole role) const
Flow LayerRegion::bridging_flow(FlowRole role, bool force_thick_bridges) const
{
const PrintRegion &region = this->region();
const PrintRegionConfig &region_config = region.config();
const PrintObject &print_object = *this->layer()->object();
if (print_object.config().thick_bridges) {
if (print_object.config().thick_bridges || force_thick_bridges) {
// The old Slic3r way (different from all other slicers): Use rounded extrusions.
// Get the configured nozzle_diameter for the extruder associated to the flow role requested.
// Here this->extruder(role) - 1 may underflow to MAX_INT, but then the get_at() will follback to zero'th element, so everything is all right.