mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-15 14:05:59 +08:00
overextruding a bit on top of bridge to come back to a correct height
This commit is contained in:
parent
f22db7efbe
commit
2749c63b10
@ -34,6 +34,7 @@ avoid_crossing_perimeters = 0
|
||||
bridge_acceleration = 1000
|
||||
bridge_angle = 0
|
||||
bridge_flow_ratio = 0.8
|
||||
over_bridge_flow_ratio = 1.2
|
||||
bridge_speed = 20
|
||||
brim_width = 0
|
||||
clip_multipart_objects = 1
|
||||
|
@ -531,6 +531,7 @@ Usage: slic3r.pl [ OPTIONS ] [ file.stl ] [ file2.stl ] ...
|
||||
Set a different extrusion width for support material
|
||||
--infill-overlap Overlap between infill and perimeters (default: $config->{infill_overlap})
|
||||
--bridge-flow-ratio Multiplier for extrusion when bridging (> 0, default: $config->{bridge_flow_ratio})
|
||||
--over-bridge-flow-ratio Multiplier for extrusion when solid-filling over a bridge (> 0, default: $config->{over_bridge_flow_ratio})
|
||||
|
||||
Multiple extruder options:
|
||||
--extruder-offset Offset of each extruder, if firmware doesn't handle the displacement
|
||||
|
1
t/flow.t
1
t/flow.t
@ -44,6 +44,7 @@ use Slic3r::Test;
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('bridge_speed', 99);
|
||||
$config->set('bridge_flow_ratio', 1);
|
||||
$config->set('over_bridge_flow_ratio', 1);
|
||||
$config->set('cooling', [ 0 ]); # to prevent speeds from being altered
|
||||
$config->set('first_layer_speed', '100%'); # to prevent speeds from being altered
|
||||
|
||||
|
@ -248,6 +248,7 @@ use Slic3r::Test;
|
||||
$config->set('slowdown_below_layer_time', [ 0 ]);
|
||||
$config->set('bridge_fan_speed', [ 100 ]);
|
||||
$config->set('bridge_flow_ratio', 33); # arbitrary value
|
||||
$config->set('over_bridge_flow_ratio', 110); # arbitrary value
|
||||
$config->set('overhangs', 1);
|
||||
my $print = Slic3r::Test::init_print('overhang', config => $config);
|
||||
my %layer_speeds = (); # print Z => [ speeds ]
|
||||
|
@ -63,14 +63,14 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
// (we'll use them for comparing compatible groups)
|
||||
std::vector<SurfaceGroupAttrib> group_attrib(groups.size());
|
||||
for (size_t i = 0; i < groups.size(); ++ i) {
|
||||
// we can only merge solid non-bridge surfaces, so discard
|
||||
// we can only merge solid non-bridge non-overextruded surfaces, so discard
|
||||
// non-solid surfaces
|
||||
const Surface &surface = *groups[i].front();
|
||||
if (surface.is_solid() && (!surface.is_bridge() || layerm.layer()->id() == 0)) {
|
||||
if (surface.is_solid() && (!surface.is_bridge() || layerm.layer()->id() == 0) && !surface.is_overBridge()) {
|
||||
group_attrib[i].is_solid = true;
|
||||
group_attrib[i].flow_width = (surface.surface_type == stTop) ? top_solid_infill_flow.width : solid_infill_flow.width;
|
||||
group_attrib[i].pattern = (surface.surface_type == stTop && surface.is_external()) ? layerm.region()->config.top_fill_pattern.value : ipRectilinear;
|
||||
group_attrib[i].pattern = (surface.surface_type == stBottom && surface.is_external()) ? layerm.region()->config.bottom_fill_pattern.value : ipRectilinear;
|
||||
group_attrib[i].flow_width = (surface.is_top()) ? top_solid_infill_flow.width : solid_infill_flow.width;
|
||||
group_attrib[i].pattern = (surface.is_top() && surface.is_external()) ? layerm.region()->config.top_fill_pattern.value : ipRectilinear;
|
||||
group_attrib[i].pattern = (surface.is_bottom() && surface.is_external()) ? layerm.region()->config.bottom_fill_pattern.value : ipRectilinear;
|
||||
}
|
||||
}
|
||||
// Loop through solid groups, find compatible groups and append them to this one.
|
||||
@ -155,14 +155,14 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
continue;
|
||||
InfillPattern fill_pattern = layerm.region()->config.fill_pattern.value;
|
||||
double density = fill_density;
|
||||
FlowRole role = (surface.surface_type == stTop) ? frTopSolidInfill :
|
||||
FlowRole role = (surface.is_top()) ? frTopSolidInfill :
|
||||
(surface.is_solid() ? frSolidInfill : frInfill);
|
||||
bool is_bridge = layerm.layer()->id() > 0 && surface.is_bridge();
|
||||
|
||||
if (surface.is_solid()) {
|
||||
density = 100.;
|
||||
fill_pattern = (surface.is_external() && ! is_bridge) ?
|
||||
(surface.surface_type == stTop ? layerm.region()->config.top_fill_pattern.value : layerm.region()->config.bottom_fill_pattern.value) :
|
||||
(surface.is_top() ? layerm.region()->config.top_fill_pattern.value : layerm.region()->config.bottom_fill_pattern.value) :
|
||||
ipRectilinear;
|
||||
} else if (density <= 0)
|
||||
continue;
|
||||
@ -241,6 +241,11 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
} else {
|
||||
flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, h, is_bridge || f->use_bridge_flow());
|
||||
}
|
||||
|
||||
float flow_percent = 1;
|
||||
if(surface.is_overBridge()){
|
||||
flow_percent = layerm.region()->config.over_bridge_flow_ratio;
|
||||
}
|
||||
|
||||
// Save into layer.
|
||||
auto *eec = new ExtrusionEntityCollection();
|
||||
@ -254,7 +259,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
(surface.is_solid() ?
|
||||
((surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill) :
|
||||
erInternalInfill),
|
||||
flow.mm3_per_mm(), flow.width, flow.height);
|
||||
flow.mm3_per_mm()*flow_percent, flow.width*flow_percent, flow.height);
|
||||
}
|
||||
|
||||
// add thin fill regions
|
||||
|
@ -121,7 +121,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
|
||||
fill_boundaries.reserve(number_polygons(surfaces));
|
||||
bool has_infill = this->region()->config.fill_density.value > 0.;
|
||||
for (const Surface &surface : this->fill_surfaces.surfaces) {
|
||||
if (surface.surface_type == stTop) {
|
||||
if (surface.is_top()) {
|
||||
// Collect the top surfaces, inflate them and trim them by the bottom surfaces.
|
||||
// This gives the priority to bottom surfaces.
|
||||
surfaces_append(top, offset_ex(surface.expolygon, float(margin), EXTERNAL_SURFACES_OFFSET_PARAMETERS), surface);
|
||||
@ -132,13 +132,12 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
|
||||
if (! surface.empty())
|
||||
bridges.push_back(surface);
|
||||
}
|
||||
bool internal_surface = surface.surface_type != stTop && ! surface.is_bottom();
|
||||
if (has_infill || surface.surface_type != stInternal) {
|
||||
if (internal_surface)
|
||||
if (!surface.is_external())
|
||||
// Make a copy as the following line uses the move semantics.
|
||||
internal.push_back(surface);
|
||||
polygons_append(fill_boundaries, STDMOVE(surface.expolygon));
|
||||
} else if (internal_surface)
|
||||
} else if (!surface.is_external())
|
||||
internal.push_back(STDMOVE(surface));
|
||||
}
|
||||
}
|
||||
@ -304,7 +303,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
|
||||
s2.clear();
|
||||
}
|
||||
}
|
||||
if (s1.surface_type == stTop)
|
||||
if (s1.is_top())
|
||||
// Trim the top surfaces by the bottom surfaces. This gives the priority to the bottom surfaces.
|
||||
polys = diff(polys, bottom_polygons);
|
||||
surfaces_append(
|
||||
@ -357,13 +356,13 @@ LayerRegion::prepare_fill_surfaces()
|
||||
// if no solid layers are requested, turn top/bottom surfaces to internal
|
||||
if (this->region()->config.top_solid_layers == 0) {
|
||||
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface)
|
||||
if (surface->surface_type == stTop)
|
||||
if (surface->is_top())
|
||||
surface->surface_type = (this->layer()->object()->config.infill_only_where_needed) ?
|
||||
stInternalVoid : stInternal;
|
||||
}
|
||||
if (this->region()->config.bottom_solid_layers == 0) {
|
||||
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) {
|
||||
if (surface->surface_type == stBottom || surface->surface_type == stBottomBridge)
|
||||
if (surface->is_bottom())
|
||||
surface->surface_type = stInternal;
|
||||
}
|
||||
}
|
||||
|
@ -199,6 +199,7 @@ public:
|
||||
void process_external_surfaces();
|
||||
void discover_vertical_shells();
|
||||
void bridge_over_infill();
|
||||
void replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_replacement, SurfaceType st_under_it);
|
||||
void _make_perimeters();
|
||||
void _infill();
|
||||
void clip_fill_surfaces();
|
||||
|
@ -113,6 +113,17 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(1);
|
||||
|
||||
def = this->add("over_bridge_flow_ratio", coFloat);
|
||||
def->label = L("Over-bridge flow ratio");
|
||||
def->category = L("Advanced");
|
||||
def->tooltip = L("This factor affects the amount of plastic to overextrude "
|
||||
"when we are filling on top of a bridge surface."
|
||||
"With a number >1, we can retreive the correct z-height "
|
||||
"even if the bridged layer has fallen a bit.");
|
||||
def->cli = "over-bridge-flow-ratio=f";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(1);
|
||||
|
||||
def = this->add("bridge_speed", coFloat);
|
||||
def->label = L("Bridges");
|
||||
def->category = L("Speed");
|
||||
@ -2013,6 +2024,10 @@ std::string FullPrintConfig::validate()
|
||||
if (this->bridge_flow_ratio <= 0)
|
||||
return "Invalid value for --bridge-flow-ratio";
|
||||
|
||||
// --over-bridge-flow-ratio
|
||||
if (this->over_bridge_flow_ratio <= 0)
|
||||
return "Invalid value for --over-bridge-flow-ratio";
|
||||
|
||||
// extruder clearance
|
||||
if (this->extruder_clearance_radius <= 0)
|
||||
return "Invalid value for --extruder-clearance-radius";
|
||||
|
@ -376,6 +376,7 @@ public:
|
||||
ConfigOptionFloat bridge_angle;
|
||||
ConfigOptionInt bottom_solid_layers;
|
||||
ConfigOptionFloat bridge_flow_ratio;
|
||||
ConfigOptionFloat over_bridge_flow_ratio;
|
||||
ConfigOptionFloat bridge_speed;
|
||||
ConfigOptionBool ensure_vertical_shell_thickness;
|
||||
ConfigOptionEnum<InfillPattern> top_fill_pattern;
|
||||
@ -416,6 +417,7 @@ protected:
|
||||
OPT_PTR(bridge_angle);
|
||||
OPT_PTR(bottom_solid_layers);
|
||||
OPT_PTR(bridge_flow_ratio);
|
||||
OPT_PTR(over_bridge_flow_ratio);
|
||||
OPT_PTR(bridge_speed);
|
||||
OPT_PTR(ensure_vertical_shell_thickness);
|
||||
OPT_PTR(top_fill_pattern);
|
||||
|
@ -363,10 +363,18 @@ void PrintObject::_prepare_infill()
|
||||
// the following step needs to be done before combination because it may need
|
||||
// to remove only half of the combined infill
|
||||
this->bridge_over_infill();
|
||||
std::cout<<"INTERNAL BRIDGE ===========================================\n";
|
||||
this->replaceSurfaceType( stInternalSolid, stInternalOverBridge, stInternalBridge);
|
||||
std::cout<<"BOTTOM BRIDGE ===========================================\n";
|
||||
this->replaceSurfaceType( stInternalSolid, stInternalOverBridge, stBottomBridge);
|
||||
std::cout<<"TOP BRIDGE ===========================================\n";
|
||||
this->replaceSurfaceType( stTop, stTopOverBridge, stInternalBridge);
|
||||
this->replaceSurfaceType( stTop, stTopOverBridge, stBottomBridge);
|
||||
|
||||
// combine fill surfaces to honor the "infill every N layers" option
|
||||
this->combine_infill();
|
||||
|
||||
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
for (size_t region_id = 0; region_id < this->print()->regions.size(); ++ region_id) {
|
||||
for (const Layer *layer : this->layers) {
|
||||
@ -435,6 +443,7 @@ void PrintObject::detect_surfaces_type()
|
||||
// unless internal shells are requested
|
||||
Layer *upper_layer = (idx_layer + 1 < this->layer_count()) ? this->layers[idx_layer + 1] : nullptr;
|
||||
Layer *lower_layer = (idx_layer > 0) ? this->layers[idx_layer - 1] : nullptr;
|
||||
Layer *under_lower_layer = (idx_layer > 1) ? this->layers[idx_layer - 2] : nullptr;
|
||||
// collapse very narrow parts (using the safety offset in the diff is not enough)
|
||||
float offset = layerm->flow(frExternalPerimeter).scaled_width() / 10.f;
|
||||
|
||||
@ -478,6 +487,7 @@ void PrintObject::detect_surfaces_type()
|
||||
diff(layerm_slices_surfaces, to_polygons(lower_layer->slices), true),
|
||||
-offset, offset),
|
||||
surface_type_bottom_other);
|
||||
|
||||
// if user requested internal shells, we need to identify surfaces
|
||||
// lying on other slices not belonging to this region
|
||||
if (interface_shells) {
|
||||
@ -494,6 +504,7 @@ void PrintObject::detect_surfaces_type()
|
||||
stBottom);
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
// if no lower layer, all surfaces of this one are solid
|
||||
// we clone surfaces because we're going to clear the slices collection
|
||||
@ -501,6 +512,22 @@ void PrintObject::detect_surfaces_type()
|
||||
for (Surface &surface : bottom)
|
||||
surface.surface_type = surface_type_bottom_1st;
|
||||
}
|
||||
|
||||
// Any surface lying on the void is a true bottom bridge (an overhang)
|
||||
// and we have to conpensate if we are over that
|
||||
// Surfaces bottomOverBridge;
|
||||
// if(under_lower_layer){
|
||||
// surfaces_append(
|
||||
// bottomOverBridge,
|
||||
// offset2_ex(
|
||||
// diff(layerm_slices_surfaces, to_polygons(under_lower_layer->slices), true),
|
||||
// -offset, offset),
|
||||
// stInternalOverBridge);
|
||||
// std::cout<<idx_layer<<" under_lower_layer "<<under_lower_layer->slices.expolygons.size()<<" > "<<bottomOverBridge.size()<<", bot="<<bottom.size()<<"\n";
|
||||
// for(int i=0;i<under_lower_layer->slices.expolygons.size();i++) std::cout<<" area of under_lower_layer "<<under_lower_layer->slices.expolygons[i].area()<<"\n";
|
||||
// for(int i=0;i<bottom.size();i++) std::cout<<" area of bottom "<<bottom[i].area()<<"\n";
|
||||
// for(int i=0;i<bottomOverBridge.size();i++) std::cout<<" area of overbridge "<<bottomOverBridge[i].area()<<"\n";
|
||||
// }
|
||||
|
||||
// now, if the object contained a thin membrane, we could have overlapping bottom
|
||||
// and top surfaces; let's do an intersection to discover them and consider them
|
||||
@ -522,6 +549,7 @@ void PrintObject::detect_surfaces_type()
|
||||
std::vector<std::pair<Slic3r::ExPolygons, SVG::ExPolygonAttributes>> expolygons_with_attributes;
|
||||
expolygons_with_attributes.emplace_back(std::make_pair(union_ex(top), SVG::ExPolygonAttributes("green")));
|
||||
expolygons_with_attributes.emplace_back(std::make_pair(union_ex(bottom), SVG::ExPolygonAttributes("brown")));
|
||||
expolygons_with_attributes.emplace_back(std::make_pair(union_ex(bottomOverBridge), SVG::ExPolygonAttributes("grey")));
|
||||
expolygons_with_attributes.emplace_back(std::make_pair(to_expolygons(layerm->slices.surfaces), SVG::ExPolygonAttributes("black")));
|
||||
SVG::export_expolygons(debug_out_path("1_detect_surfaces_type_%d_region%d-layer_%f.svg", iRun ++, idx_region, layer->print_z).c_str(), expolygons_with_attributes);
|
||||
}
|
||||
@ -535,6 +563,12 @@ void PrintObject::detect_surfaces_type()
|
||||
{
|
||||
Polygons topbottom = to_polygons(top);
|
||||
polygons_append(topbottom, to_polygons(bottom));
|
||||
// ExPolygons overExPolygons = diff_ex(to_polygons(bottomOverBridge), topbottom, false);
|
||||
// surfaces_append(surfaces_out,
|
||||
// overExPolygons,
|
||||
// stInternalOverBridge);
|
||||
// for(int i=0;i<overExPolygons.size();i++) std::cout<<" area of overExPolygons "<<overExPolygons[i].area()<<"\n";
|
||||
// polygons_append(topbottom, to_polygons(bottomOverBridge));
|
||||
surfaces_append(surfaces_out,
|
||||
diff_ex(layerm_slices_surfaces, topbottom, false),
|
||||
stInternal);
|
||||
@ -1106,6 +1140,178 @@ void PrintObject::bridge_over_infill()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This method applies overextrude flow to the first internal solid layer above
|
||||
bridge (which is over sparse infill) note: it's almost complete copy/paste from the method behind,
|
||||
i think it should be merged before gitpull that.
|
||||
*/
|
||||
void PrintObject::replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_replacement, SurfaceType st_under_it)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "overextrude over Bridge...";
|
||||
|
||||
FOREACH_REGION(this->_print, region) {
|
||||
size_t region_id = region - this->_print->regions.begin();
|
||||
|
||||
FOREACH_LAYER(this, layer_it) {
|
||||
// skip first layer
|
||||
if (layer_it == this->layers.begin()) continue;
|
||||
|
||||
Layer* layer = *layer_it;
|
||||
LayerRegion* layerm = layer->regions[region_id];
|
||||
|
||||
// extract the stInternalSolid surfaces that might be transformed into bridges
|
||||
Polygons internal_solid;
|
||||
layerm->fill_surfaces.filter_by_type(st_to_replace, &internal_solid);
|
||||
|
||||
double internsolidareainit=0;
|
||||
for (ExPolygon &ex : union_ex(internal_solid)) internsolidareainit+=ex.area();
|
||||
|
||||
Polygons internal_over_tot_init;
|
||||
layerm->fill_surfaces.filter_by_type(st_replacement, &internal_over_tot_init);
|
||||
double totoverareaInit=0;
|
||||
for (ExPolygon &ex : union_ex(internal_over_tot_init)) totoverareaInit+=ex.area();
|
||||
|
||||
Polygons stBottom_init;
|
||||
layerm->fill_surfaces.filter_by_type(stBottom, &stBottom_init);
|
||||
double bottomeareainit=0;
|
||||
for (ExPolygon &ex : union_ex(stBottom_init)) bottomeareainit+=ex.area();
|
||||
|
||||
Polygons stBottomBridge_init;
|
||||
layerm->fill_surfaces.filter_by_type(stBottomBridge, &stBottomBridge_init);
|
||||
double bottombridgearea=0;
|
||||
for (ExPolygon &ex : union_ex(stBottomBridge_init)) bottombridgearea+=ex.area();
|
||||
|
||||
Polygons stIntBridge_init;
|
||||
layerm->fill_surfaces.filter_by_type(st_under_it, &stIntBridge_init);
|
||||
double intbridgeareainit=0;
|
||||
for (ExPolygon &ex : union_ex(stIntBridge_init)) intbridgeareainit+=ex.area();
|
||||
|
||||
std::cout<<"init st_replacement="<<totoverareaInit<<", bottombridgearea="<<bottombridgearea
|
||||
<<", st_to_replace="<<internsolidareainit<<", bottomeareainit="<<bottomeareainit
|
||||
<<", st_under_it="<<intbridgeareainit<<"\n";
|
||||
|
||||
// check whether the lower area is deep enough for absorbing the extra flow
|
||||
// (for obvious physical reasons but also for preventing the bridge extrudates
|
||||
// from overflowing in 3D preview)
|
||||
ExPolygons to_overextrude;
|
||||
{
|
||||
Polygons to_overextrude_pp = internal_solid;
|
||||
|
||||
// get previous layer
|
||||
if (int(layer_it - this->layers.begin()) - 1 >= 0) {
|
||||
const Layer* lower_layer = this->layers[int(layer_it - this->layers.begin()) - 1];
|
||||
|
||||
// iterate through regions and collect internal surfaces
|
||||
Polygons lower_internal;
|
||||
FOREACH_LAYERREGION(lower_layer, lower_layerm_it){
|
||||
Polygons lower_internal_OK;
|
||||
Polygons lower_internal_Bridge;
|
||||
Polygons lower_internal_Over;
|
||||
(*lower_layerm_it)->fill_surfaces.filter_by_type(st_replacement, &lower_internal_OK);
|
||||
(*lower_layerm_it)->fill_surfaces.filter_by_type(st_under_it, &lower_internal_Bridge);
|
||||
(*lower_layerm_it)->fill_surfaces.filter_by_type(st_to_replace, &lower_internal_Over);
|
||||
double okarea =0, bridgearea=0, overarea=0;
|
||||
for (ExPolygon &ex : union_ex(lower_internal_OK)) okarea+=ex.area();
|
||||
for (ExPolygon &ex : union_ex(lower_internal_Bridge)) bridgearea+=ex.area();
|
||||
for (ExPolygon &ex : union_ex(lower_internal_Over)) overarea+=ex.area();
|
||||
std::cout<<"@layer "<<int(layer_it - this->layers.begin())
|
||||
<<" region under has "<<lower_internal_OK.size()<<" st_replacement : "<<okarea
|
||||
<<" , has "<<lower_internal_Bridge.size()<<" st_under_it: "<<bridgearea
|
||||
<<" , has "<<lower_internal_Over.size()<<" st_to_replace: "<<overarea<<"\n";
|
||||
(*lower_layerm_it)->fill_surfaces.filter_by_type(st_under_it, &lower_internal);
|
||||
}
|
||||
double sumarea=0;
|
||||
for (ExPolygon &ex : union_ex(lower_internal)) sumarea+=ex.area();
|
||||
std::cout<<"@layer "<<int(layer_it - this->layers.begin())<<" region under has "<<union_ex(lower_internal).size()<<" sum bridge : "<<sumarea<<"\n";
|
||||
|
||||
// intersect such lower internal surfaces with the candidate solid surfaces
|
||||
to_overextrude_pp = intersection(to_overextrude_pp, lower_internal);
|
||||
}
|
||||
|
||||
// there's no point in overextruding too thin/short regions
|
||||
//FIXME Vojtech: The offset2 function is not a geometric offset,
|
||||
// therefore it may create 1) gaps, and 2) sharp corners, which are outside the original contour.
|
||||
// The gaps will be filled by a separate region, which makes the infill less stable and it takes longer.
|
||||
// {
|
||||
// float min_width = float(bridge_flow.scaled_width()) * 3.f;
|
||||
// to_overextrude_pp = offset2(to_overextrude_pp, -min_width, +min_width);
|
||||
// }
|
||||
|
||||
if (to_overextrude_pp.empty()) continue;
|
||||
|
||||
// convert into ExPolygons
|
||||
to_overextrude = union_ex(to_overextrude_pp);
|
||||
double finalarea = 0;
|
||||
for (ExPolygon &ex : to_overextrude) finalarea+=ex.area();
|
||||
std::cout<<"find an overextruding area of "<<finalarea<<" on layer "<<int(layer_it - this->layers.begin())<<"\n";
|
||||
}
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf("Bridging " PRINTF_ZU " internal areas at layer " PRINTF_ZU "\n", to_overextrude.size(), layer->id());
|
||||
#endif
|
||||
|
||||
// compute the remaning internal solid surfaces as difference
|
||||
ExPolygons not_to_overextrude = diff_ex(internal_solid, to_polygons(to_overextrude), true);
|
||||
to_overextrude = intersection_ex(to_polygons(to_overextrude), internal_solid, true);
|
||||
// build the new collection of fill_surfaces
|
||||
layerm->fill_surfaces.remove_type(st_to_replace);
|
||||
double overareafinal = 0, solidareafinal=0;
|
||||
for (ExPolygon &ex : to_overextrude){
|
||||
overareafinal += ex.area();
|
||||
layerm->fill_surfaces.surfaces.push_back(Surface(st_replacement, ex));
|
||||
}
|
||||
for (ExPolygon &ex : not_to_overextrude){
|
||||
solidareafinal += ex.area();
|
||||
layerm->fill_surfaces.surfaces.push_back(Surface(st_to_replace, ex));
|
||||
}
|
||||
Polygons internal_over_tot;
|
||||
layerm->fill_surfaces.filter_by_type(stInternalOverBridge, &internal_over_tot);
|
||||
double totoverarea=0;
|
||||
for (ExPolygon &ex : union_ex(internal_over_tot)) totoverarea+=ex.area();
|
||||
std::cout<<"final: st_to_replace="<<solidareafinal<<", st_replacement="<<overareafinal<<", totstInternalOverBridge="<<totoverarea<<"\n";
|
||||
/*
|
||||
# exclude infill from the layers below if needed
|
||||
# see discussion at https://github.com/alexrj/Slic3r/issues/240
|
||||
# Update: do not exclude any infill. Sparse infill is able to absorb the excess material.
|
||||
if (0) {
|
||||
my $excess = $layerm->extruders->{infill}->bridge_flow->width - $layerm->height;
|
||||
for (my $i = $layer_id-1; $excess >= $self->get_layer($i)->height; $i--) {
|
||||
Slic3r::debugf " skipping infill below those areas at layer %d\n", $i;
|
||||
foreach my $lower_layerm (@{$self->get_layer($i)->regions}) {
|
||||
my @new_surfaces = ();
|
||||
# subtract the area from all types of surfaces
|
||||
foreach my $group (@{$lower_layerm->fill_surfaces->group}) {
|
||||
push @new_surfaces, map $group->[0]->clone(expolygon => $_),
|
||||
@{diff_ex(
|
||||
[ map $_->p, @$group ],
|
||||
[ map @$_, @$to_overextrude ],
|
||||
)};
|
||||
push @new_surfaces, map Slic3r::Surface->new(
|
||||
expolygon => $_,
|
||||
surface_type => S_TYPE_INTERNALVOID,
|
||||
), @{intersection_ex(
|
||||
[ map $_->p, @$group ],
|
||||
[ map @$_, @$to_overextrude ],
|
||||
)};
|
||||
}
|
||||
$lower_layerm->fill_surfaces->clear;
|
||||
$lower_layerm->fill_surfaces->append($_) for @new_surfaces;
|
||||
}
|
||||
|
||||
$excess -= $self->get_layer($i)->height;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
layerm->export_region_slices_to_svg_debug("7_overextrude_over_bridge");
|
||||
layerm->export_region_fill_surfaces_to_svg_debug("7_overextrude_over_bridge");
|
||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SlicingParameters PrintObject::slicing_parameters() const
|
||||
{
|
||||
return SlicingParameters::create_from_config(
|
||||
@ -1699,8 +1905,8 @@ void PrintObject::discover_horizontal_shells()
|
||||
continue;
|
||||
// Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == S_TYPE_TOP) ? 'top' : 'bottom';
|
||||
|
||||
size_t solid_layers = (type == stTop) ? region_config.top_solid_layers.value : region_config.bottom_solid_layers.value;
|
||||
for (int n = (type == stTop) ? i-1 : i+1; std::abs(n - i) < solid_layers; (type == stTop) ? -- n : ++ n) {
|
||||
size_t solid_layers = (type == stTop || type == stTopOverBridge) ? region_config.top_solid_layers.value : region_config.bottom_solid_layers.value;
|
||||
for (int n = (type == stTop || type == stTopOverBridge) ? i-1 : i+1; std::abs(n - i) < solid_layers; (type == stTop || type == stTopOverBridge) ? -- n : ++ n) {
|
||||
if (n < 0 || n >= int(this->layers.size()))
|
||||
continue;
|
||||
// Slic3r::debugf " looking for neighbors on layer %d...\n", $n;
|
||||
|
@ -22,7 +22,9 @@ Surface::is_solid() const
|
||||
|| this->surface_type == stBottom
|
||||
|| this->surface_type == stBottomBridge
|
||||
|| this->surface_type == stInternalSolid
|
||||
|| this->surface_type == stInternalBridge;
|
||||
|| this->surface_type == stInternalBridge
|
||||
|| this->surface_type == stInternalOverBridge
|
||||
|| this->surface_type == stTopOverBridge;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -30,7 +32,15 @@ Surface::is_external() const
|
||||
{
|
||||
return this->surface_type == stTop
|
||||
|| this->surface_type == stBottom
|
||||
|| this->surface_type == stBottomBridge;
|
||||
|| this->surface_type == stBottomBridge
|
||||
|| this->surface_type == stTopOverBridge;
|
||||
}
|
||||
|
||||
bool
|
||||
Surface::is_top() const
|
||||
{
|
||||
return this->surface_type == stTop
|
||||
|| this->surface_type == stTopOverBridge;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -38,6 +48,7 @@ Surface::is_internal() const
|
||||
{
|
||||
return this->surface_type == stInternal
|
||||
|| this->surface_type == stInternalBridge
|
||||
|| this->surface_type == stInternalOverBridge
|
||||
|| this->surface_type == stInternalSolid
|
||||
|| this->surface_type == stInternalVoid;
|
||||
}
|
||||
@ -55,6 +66,12 @@ Surface::is_bridge() const
|
||||
return this->surface_type == stBottomBridge
|
||||
|| this->surface_type == stInternalBridge;
|
||||
}
|
||||
bool
|
||||
Surface::is_overBridge() const
|
||||
{
|
||||
return this->surface_type == stInternalOverBridge
|
||||
|| this->surface_type == stTopOverBridge;
|
||||
}
|
||||
|
||||
BoundingBox get_extents(const Surface &surface)
|
||||
{
|
||||
@ -91,7 +108,8 @@ const char* surface_type_to_color_name(const SurfaceType surface_type)
|
||||
case stBottomBridge: return "rgb(0,0,255)"; // "blue";
|
||||
case stInternal: return "rgb(255,255,128)"; // yellow
|
||||
case stInternalSolid: return "rgb(255,0,255)"; // magenta
|
||||
case stInternalBridge: return "rgb(0,255,255)";
|
||||
case stInternalBridge: return "rgb(0,255,255)"; // cyan
|
||||
case stInternalOverBridge: return "rgb(0,255,128)"; // green-cyan
|
||||
case stInternalVoid: return "rgb(128,128,128)";
|
||||
case stPerimeter: return "rgb(128,0,0)"; // maroon
|
||||
default: return "rgb(64,64,64)";
|
||||
@ -128,6 +146,8 @@ void export_surface_type_legend_to_svg(SVG &svg, const Point &pos)
|
||||
pos_x += step_x;
|
||||
svg.draw_legend(Point(pos_x, pos_y), "internal bridge", surface_type_to_color_name(stInternalBridge));
|
||||
pos_x += step_x;
|
||||
svg.draw_legend(Point(pos_x, pos_y), "internal over bridge", surface_type_to_color_name(stInternalOverBridge));
|
||||
pos_x += step_x;
|
||||
svg.draw_legend(Point(pos_x, pos_y), "internal void" , surface_type_to_color_name(stInternalVoid));
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,9 @@ enum SurfaceType {
|
||||
stInternalSolid,
|
||||
// 1st layer of dense infill over sparse infill, printed with a bridging extrusion flow.
|
||||
stInternalBridge,
|
||||
// 2nd layer of dense infill over sparse infill/nothing, printed with an over-extruding flow.
|
||||
stInternalOverBridge,
|
||||
stTopOverBridge,
|
||||
// stInternal turns into void surfaces if the sparse infill is used for supports only,
|
||||
// or if sparse infill layers get combined into a single layer.
|
||||
stInternalVoid,
|
||||
@ -97,9 +100,11 @@ public:
|
||||
void clear() { expolygon.clear(); }
|
||||
bool is_solid() const;
|
||||
bool is_external() const;
|
||||
bool is_top() const;
|
||||
bool is_internal() const;
|
||||
bool is_bottom() const;
|
||||
bool is_bridge() const;
|
||||
bool is_overBridge() const;
|
||||
};
|
||||
|
||||
typedef std::vector<Surface> Surfaces;
|
||||
|
@ -197,7 +197,8 @@ const std::vector<std::string>& Preset::print_options()
|
||||
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
|
||||
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
|
||||
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
||||
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects",
|
||||
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio",
|
||||
"over_bridge_flow_ratio", "clip_multipart_objects",
|
||||
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
|
||||
"wipe_tower_width", "wipe_tower_per_color_wipe", "only_one_perimeter_top",
|
||||
"compatible_printers", "compatible_printers_condition"
|
||||
|
@ -84,6 +84,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
|
||||
double support_material_interface_speed = print_config.get_abs_value("support_material_interface_speed", support_material_speed);
|
||||
double bridge_speed = print_config.opt_float("bridge_speed");
|
||||
double bridge_flow_ratio = print_config.opt_float("bridge_flow_ratio");
|
||||
double over_bridge_flow_ratio = print_config.opt_float("over_bridge_flow_ratio");
|
||||
double perimeter_speed = print_config.opt_float("perimeter_speed");
|
||||
double external_perimeter_speed = print_config.get_abs_value("external_perimeter_speed", perimeter_speed);
|
||||
double gap_fill_speed = print_config.opt_float("gap_fill_speed");
|
||||
|
@ -538,6 +538,7 @@ void TabPrint::build()
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Flow")));
|
||||
optgroup->append_single_option_line("bridge_flow_ratio");
|
||||
optgroup->append_single_option_line("over_bridge_flow_ratio");
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Other")));
|
||||
optgroup->append_single_option_line("clip_multipart_objects");
|
||||
|
Loading…
x
Reference in New Issue
Block a user