mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-01 02:21:58 +08:00
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:
parent
398222a49f
commit
60f6766aab
@ -16,9 +16,10 @@
|
|||||||
#include "FillLightning.hpp"
|
#include "FillLightning.hpp"
|
||||||
#include "FillConcentric.hpp"
|
#include "FillConcentric.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
static constexpr const float NarrowInfillAreaThresholdMM = 3.f;
|
||||||
|
|
||||||
struct SurfaceFillParams
|
struct SurfaceFillParams
|
||||||
{
|
{
|
||||||
// Zero based extruder ID.
|
// Zero based extruder ID.
|
||||||
@ -148,6 +149,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||||||
erBridgeInfill :
|
erBridgeInfill :
|
||||||
(surface.is_solid() ?
|
(surface.is_solid() ?
|
||||||
(surface.is_top() ? erTopSolidInfill : erSolidInfill) :
|
(surface.is_top() ? erTopSolidInfill : erSolidInfill) :
|
||||||
|
//(surface.is_top() ? erTopSolidInfill : (surface.is_bottom()? erBottomSurface : erSolidInfill)) :
|
||||||
erInternalInfill);
|
erInternalInfill);
|
||||||
params.bridge_angle = float(surface.bridge_angle);
|
params.bridge_angle = float(surface.bridge_angle);
|
||||||
params.angle = float(Geometry::deg2rad(region_config.fill_angle.value));
|
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.
|
// Calculate the actual flow we'll be using for this infill.
|
||||||
params.bridge = is_bridge || Fill::use_bridge_flow(params.pattern);
|
params.bridge = is_bridge || Fill::use_bridge_flow(params.pattern);
|
||||||
params.flow = params.bridge ?
|
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);
|
layerm.flow(extrusion_role, (surface.thickness == -1) ? layer.height : surface.thickness);
|
||||||
|
|
||||||
// Calculate flow spacing for infill pattern generation.
|
// 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;
|
return surface_fills;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,16 +487,17 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
|||||||
f->layer_id = this->id();
|
f->layer_id = this->id();
|
||||||
f->z = this->print_z;
|
f->z = this->print_z;
|
||||||
f->angle = surface_fill.params.angle;
|
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)
|
if (surface_fill.params.pattern == ipLightning)
|
||||||
dynamic_cast<FillLightning::Filler*>(f.get())->generator = lightning_generator;
|
dynamic_cast<FillLightning::Filler*>(f.get())->generator = lightning_generator;
|
||||||
|
|
||||||
if (perimeter_generator.value == PerimeterGeneratorType::Arachne && surface_fill.params.pattern == ipConcentric) {
|
if (surface_fill.params.pattern == ipBoundedRectilinear) {
|
||||||
FillConcentric *fill_concentric = dynamic_cast<FillConcentric *>(f.get());
|
auto *fill_bounded_rectilinear = dynamic_cast<FillBoundedRectilinear *>(f.get());
|
||||||
assert(fill_concentric != nullptr);
|
assert(fill_bounded_rectilinear != nullptr);
|
||||||
fill_concentric->print_config = &this->object()->print()->config();
|
fill_bounded_rectilinear->print_region_config = &m_regions[surface_fill.region_id]->region().config();
|
||||||
fill_concentric->print_object_config = &this->object()->config();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate flow spacing for infill pattern generation
|
// 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 = surface_fill.params.anchor_length;
|
||||||
params.anchor_length_max = surface_fill.params.anchor_length_max;
|
params.anchor_length_max = surface_fill.params.anchor_length_max;
|
||||||
params.resolution = resolution;
|
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;
|
params.layer_height = layerm.layer()->height;
|
||||||
|
|
||||||
for (ExPolygon &expoly : surface_fill.expolygons) {
|
for (ExPolygon &expoly : surface_fill.expolygons) {
|
||||||
|
@ -134,7 +134,7 @@ public:
|
|||||||
|
|
||||||
Flow flow(FlowRole role) const;
|
Flow flow(FlowRole role) const;
|
||||||
Flow flow(FlowRole role, double layer_height) 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 slices_to_fill_surfaces_clipped();
|
||||||
void prepare_fill_surfaces();
|
void prepare_fill_surfaces();
|
||||||
|
@ -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);
|
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 ®ion = this->region();
|
const PrintRegion ®ion = this->region();
|
||||||
const PrintRegionConfig ®ion_config = region.config();
|
const PrintRegionConfig ®ion_config = region.config();
|
||||||
const PrintObject &print_object = *this->layer()->object();
|
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.
|
// 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.
|
// 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.
|
// 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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user