ENH: improve archor of internal bridge

Add loop inside sparse infill of lower layer
to provide archor for internal bridge.

This option controls how many lower layers generate
loop path.

Signed-off-by: salt.wei <salt.wei@bambulab.com>
Change-Id: Ifdb6db9090115732aa2cacf5d155b587a10e18fc
(cherry picked from commit 4fdb87ecd5c2e680f6bad2d018ba39cd05f787ce)
This commit is contained in:
salt.wei 2022-11-15 20:20:48 +08:00 committed by Lane.Wei
parent 08494b5f6f
commit 588f18ac58
18 changed files with 141 additions and 15 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "Bambulab", "name": "Bambulab",
"url": "http://www.bambulab.com/Parameters/vendor/BBL.json", "url": "http://www.bambulab.com/Parameters/vendor/BBL.json",
"version": "01.04.00.06", "version": "01.04.00.07",
"force_update": "0", "force_update": "0",
"description": "the initial version of BBL configurations", "description": "the initial version of BBL configurations",
"machine_model_list": [ "machine_model_list": [

View file

@ -5,6 +5,7 @@
"instantiation": "false", "instantiation": "false",
"inherits": "fdm_process_bbl_common", "inherits": "fdm_process_bbl_common",
"layer_height": "0.08", "layer_height": "0.08",
"elefant_foot_compensation": "0.15",
"bottom_shell_layers": "7", "bottom_shell_layers": "7",
"top_shell_layers": "9", "top_shell_layers": "9",
"bridge_flow": "1", "bridge_flow": "1",

View file

@ -6,7 +6,9 @@
"inherits": "fdm_process_bbl_common", "inherits": "fdm_process_bbl_common",
"layer_height": "0.12", "layer_height": "0.12",
"bottom_shell_layers": "5", "bottom_shell_layers": "5",
"top_shell_layers": "6", "elefant_foot_compensation": "0.15",
"top_shell_layers": "5",
"top_shell_thickness": "0.6",
"bridge_flow": "1", "bridge_flow": "1",
"initial_layer_speed": "50", "initial_layer_speed": "50",
"initial_layer_infill_speed": "105", "initial_layer_infill_speed": "105",

View file

@ -5,8 +5,10 @@
"instantiation": "false", "instantiation": "false",
"inherits": "fdm_process_bbl_common", "inherits": "fdm_process_bbl_common",
"layer_height": "0.16", "layer_height": "0.16",
"elefant_foot_compensation": "0.15",
"bottom_shell_layers": "4", "bottom_shell_layers": "4",
"top_shell_layers": "5", "top_shell_layers": "4",
"top_shell_thickness": "0.6",
"bridge_flow": "1", "bridge_flow": "1",
"initial_layer_speed": "50", "initial_layer_speed": "50",
"initial_layer_infill_speed": "105", "initial_layer_infill_speed": "105",

View file

@ -5,8 +5,10 @@
"instantiation": "false", "instantiation": "false",
"inherits": "fdm_process_bbl_common", "inherits": "fdm_process_bbl_common",
"layer_height": "0.2", "layer_height": "0.2",
"elefant_foot_compensation": "0.15",
"bottom_shell_layers": "3", "bottom_shell_layers": "3",
"top_shell_layers": "4", "top_shell_layers": "3",
"top_shell_thickness": "0.6",
"bridge_flow": "1", "bridge_flow": "1",
"initial_layer_speed": "50", "initial_layer_speed": "50",
"initial_layer_infill_speed": "105", "initial_layer_infill_speed": "105",

View file

@ -5,9 +5,11 @@
"instantiation": "false", "instantiation": "false",
"inherits": "fdm_process_bbl_common", "inherits": "fdm_process_bbl_common",
"layer_height": "0.24", "layer_height": "0.24",
"elefant_foot_compensation": "0.15",
"top_surface_line_width": "0.45", "top_surface_line_width": "0.45",
"bottom_shell_layers": "3", "bottom_shell_layers": "3",
"top_shell_layers": "4", "top_shell_layers": "3",
"top_shell_thickness": "0.6",
"bridge_flow": "1", "bridge_flow": "1",
"initial_layer_speed": "50", "initial_layer_speed": "50",
"initial_layer_infill_speed": "105", "initial_layer_infill_speed": "105",

View file

@ -5,9 +5,11 @@
"instantiation": "false", "instantiation": "false",
"inherits": "fdm_process_bbl_common", "inherits": "fdm_process_bbl_common",
"layer_height": "0.28", "layer_height": "0.28",
"elefant_foot_compensation": "0.15",
"top_surface_line_width": "0.45", "top_surface_line_width": "0.45",
"bottom_shell_layers": "3", "bottom_shell_layers": "3",
"top_shell_layers": "4", "top_shell_layers": "3",
"top_shell_thickness": "0.6",
"bridge_flow": "1", "bridge_flow": "1",
"initial_layer_speed": "50", "initial_layer_speed": "50",
"initial_layer_infill_speed": "105", "initial_layer_infill_speed": "105",

View file

@ -30,6 +30,7 @@
"infill_direction": "45", "infill_direction": "45",
"sparse_infill_density": "15%", "sparse_infill_density": "15%",
"sparse_infill_pattern": "grid", "sparse_infill_pattern": "grid",
"internal_bridge_support_thickness": "0.8",
"initial_layer_acceleration": "500", "initial_layer_acceleration": "500",
"initial_layer_line_width": "0.5", "initial_layer_line_width": "0.5",
"initial_layer_print_height": "0.2", "initial_layer_print_height": "0.2",

View file

@ -46,6 +46,8 @@ struct SurfaceFillParams
// 1000mm is roughly the maximum length line that fits into a 32bit coord_t. // 1000mm is roughly the maximum length line that fits into a 32bit coord_t.
float anchor_length = 1000.f; float anchor_length = 1000.f;
float anchor_length_max = 1000.f; float anchor_length_max = 1000.f;
//BBS
bool with_loop = false;
// width, height of extrusion, nozzle diameter, is bridge // width, height of extrusion, nozzle diameter, is bridge
// For the output, for fill generator. // For the output, for fill generator.
@ -77,6 +79,7 @@ struct SurfaceFillParams
// RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust); // RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
RETURN_COMPARE_NON_EQUAL(anchor_length); RETURN_COMPARE_NON_EQUAL(anchor_length);
RETURN_COMPARE_NON_EQUAL(anchor_length_max); RETURN_COMPARE_NON_EQUAL(anchor_length_max);
RETURN_COMPARE_NON_EQUAL(with_loop);
RETURN_COMPARE_NON_EQUAL(flow.width()); RETURN_COMPARE_NON_EQUAL(flow.width());
RETURN_COMPARE_NON_EQUAL(flow.height()); RETURN_COMPARE_NON_EQUAL(flow.height());
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter()); RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter());
@ -97,6 +100,7 @@ struct SurfaceFillParams
// this->dont_adjust == rhs.dont_adjust && // this->dont_adjust == rhs.dont_adjust &&
this->anchor_length == rhs.anchor_length && this->anchor_length == rhs.anchor_length &&
this->anchor_length_max == rhs.anchor_length_max && this->anchor_length_max == rhs.anchor_length_max &&
this->with_loop == rhs.with_loop &&
this->flow == rhs.flow && this->flow == rhs.flow &&
this->extrusion_role == rhs.extrusion_role; this->extrusion_role == rhs.extrusion_role;
} }
@ -147,6 +151,8 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.extruder = layerm.region().extruder(extrusion_role); params.extruder = layerm.region().extruder(extrusion_role);
params.pattern = region_config.sparse_infill_pattern.value; params.pattern = region_config.sparse_infill_pattern.value;
params.density = float(region_config.sparse_infill_density); params.density = float(region_config.sparse_infill_density);
//BBS
params.with_loop = surface.surface_type == stInternalWithLoop;
if (surface.is_solid()) { if (surface.is_solid()) {
params.density = 100.f; params.density = 100.f;
@ -465,6 +471,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.extrusion_role = surface_fill.params.extrusion_role; params.extrusion_role = surface_fill.params.extrusion_role;
params.using_internal_flow = using_internal_flow; params.using_internal_flow = using_internal_flow;
params.no_extrusion_overlap = surface_fill.params.overlap; params.no_extrusion_overlap = surface_fill.params.overlap;
params.with_loop = surface_fill.params.with_loop;
LayerRegion* layerm = this->m_regions[surface_fill.region_id]; LayerRegion* layerm = this->m_regions[surface_fill.region_id];
for (ExPolygon& expoly : surface_fill.expolygons) { for (ExPolygon& expoly : surface_fill.expolygons) {

View file

@ -29,7 +29,7 @@
namespace Slic3r { namespace Slic3r {
//BBS: 0% of sparse_infill_line_width, no anchor at the start of sparse infill //BBS: 0% of sparse_infill_line_width, no anchor at the start of sparse infill
float Fill::infill_anchor = 0; float Fill::infill_anchor = 400;
//BBS: 20mm //BBS: 20mm
float Fill::infill_anchor_max = 20; float Fill::infill_anchor_max = 20;
@ -122,13 +122,57 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para
{ {
Polylines polylines; Polylines polylines;
ThickPolylines thick_polylines; ThickPolylines thick_polylines;
try { if (!params.with_loop) {
if (params.use_arachne) try {
thick_polylines = this->fill_surface_arachne(surface, params); if (params.use_arachne)
else thick_polylines = this->fill_surface_arachne(surface, params);
polylines = this->fill_surface(surface, params); else
polylines = this->fill_surface(surface, params);
}
catch (InfillFailedException&) {}
}
//BBS: add handling for infill pattern with loop
else {
Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(this->overlap - 0.5 * this->spacing)));
Polylines loop_polylines = to_polylines(expp);
{
//BBS: clip the loop
size_t j = 0;
for (size_t i = 0; i < loop_polylines.size(); ++i) {
loop_polylines[i].clip_end(this->loop_clipping);
if (loop_polylines[i].is_valid()) {
if (j < i)
loop_polylines[j] = std::move(loop_polylines[i]);
++j;
}
}
if (j < loop_polylines.size())
loop_polylines.erase(loop_polylines.begin() + int(j), loop_polylines.end());
}
if (!loop_polylines.empty()) {
if (params.use_arachne)
append(thick_polylines, to_thick_polylines(std::move(loop_polylines), scaled<coord_t>(this->spacing)));
else
append(polylines, std::move(loop_polylines));
expp = offset_ex(expp, float(scale_(0 - 0.5 * this->spacing)));
} else {
//BBS: the area is too narrow to place a loop, return to original expolygon
expp = { surface->expolygon };
}
Surface temp_surface = *surface;
for (ExPolygon& ex : expp) {
temp_surface.expolygon = ex;
try {
if (params.use_arachne)
append(thick_polylines, std::move(this->fill_surface_arachne(&temp_surface, params)));
else
append(polylines, std::move(this->fill_surface(&temp_surface, params)));
}
catch (InfillFailedException&) {}
}
} }
catch (InfillFailedException&) {}
if (!polylines.empty() || !thick_polylines.empty()) { if (!polylines.empty() || !thick_polylines.empty()) {
// calculate actual flow from spacing (which might have been adjusted by the infill // calculate actual flow from spacing (which might have been adjusted by the infill

View file

@ -67,6 +67,8 @@ struct FillParams
bool use_arachne{ false }; bool use_arachne{ false };
// Layer height for Concentric infill with Arachne. // Layer height for Concentric infill with Arachne.
coordf_t layer_height { 0.f }; coordf_t layer_height { 0.f };
//BBS
bool with_loop { false };
// BBS // BBS
Flow flow; Flow flow;

View file

@ -730,7 +730,7 @@ static std::vector<std::string> s_Preset_print_options {
"gcode_add_line_number", "enable_arc_fitting", "infill_combination", /*"adaptive_layer_height",*/ "gcode_add_line_number", "enable_arc_fitting", "infill_combination", /*"adaptive_layer_height",*/
"support_bottom_interface_spacing", "enable_overhang_speed", "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed", "support_bottom_interface_spacing", "enable_overhang_speed", "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed",
"initial_layer_infill_speed", "only_one_wall_top", "initial_layer_infill_speed", "only_one_wall_top",
"timelapse_type" "timelapse_type", "internal_bridge_support_thickness"
}; };
static std::vector<std::string> s_Preset_filament_options { static std::vector<std::string> s_Preset_filament_options {

View file

@ -916,6 +916,19 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(true)); def->set_default_value(new ConfigOptionBool(true));
def = this->add("internal_bridge_support_thickness", coFloat);
def->label = L("Internal bridge support thickness");
def->category = L("Strength");
def->tooltip = L("When sparse infill density is low, the internal solid infill or internal bridge may have no archor at the end of line. "
"This cause falling and bad quality when printing internal solid infill. "
"When enable this feature, loop paths will be added to the sparse fill of the lower layers for specific thickness, so that better archor can be provided for internal bridge. "
"0 means disable this feature");
def->sidetext = L("mm");
def->min = 0;
def->max = 2;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
auto def_top_fill_pattern = def = this->add("top_surface_pattern", coEnum); auto def_top_fill_pattern = def = this->add("top_surface_pattern", coEnum);
def->label = L("Top surface pattern"); def->label = L("Top surface pattern");
def->category = L("Strength"); def->category = L("Strength");

View file

@ -655,6 +655,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, detect_narrow_internal_solid_infill)) ((ConfigOptionBool, detect_narrow_internal_solid_infill))
// ((ConfigOptionBool, adaptive_layer_height)) // ((ConfigOptionBool, adaptive_layer_height))
((ConfigOptionFloat, support_bottom_interface_spacing)) ((ConfigOptionFloat, support_bottom_interface_spacing))
((ConfigOptionFloat, internal_bridge_support_thickness))
) )
// This object is mapped to Perl as Slic3r::Config::PrintRegion. // This object is mapped to Perl as Slic3r::Config::PrintRegion.

View file

@ -770,7 +770,9 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "solid_infill_filament" || opt_key == "solid_infill_filament"
|| opt_key == "sparse_infill_line_width" || opt_key == "sparse_infill_line_width"
|| opt_key == "ensure_vertical_shell_thickness" || opt_key == "ensure_vertical_shell_thickness"
|| opt_key == "bridge_angle") { || opt_key == "bridge_angle"
//BBS
|| opt_key == "internal_bridge_support_thickness") {
steps.emplace_back(posPrepareInfill); steps.emplace_back(posPrepareInfill);
} else if ( } else if (
opt_key == "top_surface_pattern" opt_key == "top_surface_pattern"
@ -1611,6 +1613,7 @@ void PrintObject::bridge_over_infill()
Layer *layer = *layer_it; Layer *layer = *layer_it;
LayerRegion *layerm = layer->m_regions[region_id]; LayerRegion *layerm = layer->m_regions[region_id];
const PrintObjectConfig& object_config = layer->object()->config();
//BBS: enable thick bridge for internal bridge only //BBS: enable thick bridge for internal bridge only
Flow bridge_flow = layerm->bridging_flow(frSolidInfill, true); Flow bridge_flow = layerm->bridging_flow(frSolidInfill, true);
@ -1678,8 +1681,43 @@ void PrintObject::bridge_over_infill()
(layerm->fill_surfaces.surfaces.end() - 1)->bridge_angle = ibd.angle; (layerm->fill_surfaces.surfaces.end() - 1)->bridge_angle = ibd.angle;
} }
} }
for (ExPolygon &ex : not_to_bridge) for (ExPolygon &ex : not_to_bridge)
layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, ex)); layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, ex));
//BBS: modify stInternal to be stInternalWithLoop to give better support to internal bridge
if (!to_bridge.empty()){
float internal_loop_thickness = object_config.internal_bridge_support_thickness.value;
double bottom_z = layer->print_z - layer->height - internal_loop_thickness + EPSILON;
//BBS: lighting infill doesn't support this feature. Don't need to add loop when infill density is high than 50%
if (region.config().sparse_infill_pattern != InfillPattern::ipLightning && region.config().sparse_infill_density.value < 50)
for (int i = int(layer_it - m_layers.begin()) - 1; i >= 0; --i) {
const Layer* lower_layer = m_layers[i];
if (lower_layer->print_z < bottom_z) break;
for (LayerRegion* lower_layerm : lower_layer->m_regions) {
Polygons lower_internal;
lower_layerm->fill_surfaces.filter_by_type(stInternal, &lower_internal);
ExPolygons internal_with_loop = intersection_ex(lower_internal, to_bridge);
ExPolygons internal = diff_ex(lower_internal, to_bridge);
if (internal_with_loop.empty()) {
//BBS: don't need to do anything
}
else if (internal.empty()) {
lower_layerm->fill_surfaces.change_to_new_type(stInternal, stInternalWithLoop);
}
else {
lower_layerm->fill_surfaces.remove_type(stInternal);
for (ExPolygon& ex : internal_with_loop)
lower_layerm->fill_surfaces.surfaces.push_back(Surface(stInternalWithLoop, ex));
for (ExPolygon& ex : internal)
lower_layerm->fill_surfaces.surfaces.push_back(Surface(stInternal, ex));
}
}
}
}
/* /*
# exclude infill from the layers below if needed # exclude infill from the layers below if needed
# see discussion at https://github.com/alexrj/Slic3r/issues/240 # see discussion at https://github.com/alexrj/Slic3r/issues/240

View file

@ -15,6 +15,8 @@ enum SurfaceType {
stBottomBridge, stBottomBridge,
// Normal sparse infill. // Normal sparse infill.
stInternal, stInternal,
// Normal sparse infill.
stInternalWithLoop,
// Full infill, supporting the top surfaces and/or defining the verticall wall thickness. // Full infill, supporting the top surfaces and/or defining the verticall wall thickness.
stInternalSolid, stInternalSolid,
// 1st layer of dense infill over sparse infill, printed with a bridging extrusion flow. // 1st layer of dense infill over sparse infill, printed with a bridging extrusion flow.

View file

@ -37,6 +37,12 @@ public:
for (Surface &surface : this->surfaces) for (Surface &surface : this->surfaces)
surface.surface_type = type; surface.surface_type = type;
} }
//BBS
void change_to_new_type(SurfaceType old_type, SurfaceType new_type) {
for (Surface& surface : this->surfaces)
if (surface.surface_type == old_type)
surface.surface_type = new_type;
}
void clear() { surfaces.clear(); } void clear() { surfaces.clear(); }
bool empty() const { return surfaces.empty(); } bool empty() const { return surfaces.empty(); }

View file

@ -1815,6 +1815,7 @@ void TabPrint::build()
optgroup->append_single_option_line("infill_combination"); optgroup->append_single_option_line("infill_combination");
optgroup->append_single_option_line("detect_narrow_internal_solid_infill"); optgroup->append_single_option_line("detect_narrow_internal_solid_infill");
optgroup->append_single_option_line("ensure_vertical_shell_thickness"); optgroup->append_single_option_line("ensure_vertical_shell_thickness");
optgroup->append_single_option_line("internal_bridge_support_thickness");
page = add_options_page(L("Speed"), "empty"); page = add_options_page(L("Speed"), "empty");
optgroup = page->new_optgroup(L("Initial layer speed"), L"param_speed_first", 15); optgroup = page->new_optgroup(L("Initial layer speed"), L"param_speed_first", 15);