Reworked the "new" bridging to respect the bridge_flow_ratio

by maintaining extrusion spacing, but modifying the extrusion width
and / or height.
This commit is contained in:
Vojtech Bubnik 2021-03-09 12:30:31 +01:00
parent 8e27e355c2
commit f01f02154c
12 changed files with 173 additions and 134 deletions

View File

@ -28,6 +28,8 @@ struct SurfaceFillParams
// coordf_t overlap = 0.; // coordf_t overlap = 0.;
// Angle as provided by the region config, in radians. // Angle as provided by the region config, in radians.
float angle = 0.f; float angle = 0.f;
// Is bridging used for this fill? Bridging parameters may be used even if this->flow.bridge() is not set.
bool bridge;
// Non-negative for a bridge. // Non-negative for a bridge.
float bridge_angle = 0.f; float bridge_angle = 0.f;
@ -73,18 +75,19 @@ struct SurfaceFillParams
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());
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, flow.bridge()); RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, bridge);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, extrusion_role); RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, extrusion_role);
return false; return false;
} }
bool operator==(const SurfaceFillParams &rhs) const { bool operator==(const SurfaceFillParams &rhs) const {
return this->extruder == rhs.extruder && return this->extruder == rhs.extruder &&
this->pattern == rhs.pattern &&
this->pattern == rhs.pattern && this->pattern == rhs.pattern &&
this->spacing == rhs.spacing && this->spacing == rhs.spacing &&
// this->overlap == rhs.overlap && // this->overlap == rhs.overlap &&
this->angle == rhs.angle && this->angle == rhs.angle &&
this->bridge == rhs.bridge &&
// this->bridge_angle == rhs.bridge_angle &&
this->density == rhs.density && this->density == rhs.density &&
// this->dont_adjust == rhs.dont_adjust && // this->dont_adjust == rhs.dont_adjust &&
this->anchor_length == rhs.anchor_length && this->anchor_length == rhs.anchor_length &&
@ -128,6 +131,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
if (surface.is_solid()) { if (surface.is_solid()) {
params.density = 100.f; params.density = 100.f;
//FIXME for non-thick bridges, shall we allow a bottom surface pattern?
params.pattern = (surface.is_external() && ! is_bridge) ? params.pattern = (surface.is_external() && ! is_bridge) ?
(surface.is_top() ? region_config.top_fill_pattern.value : region_config.bottom_fill_pattern.value) : (surface.is_top() ? region_config.top_fill_pattern.value : region_config.bottom_fill_pattern.value) :
region_config.top_fill_pattern == ipMonotonic ? ipMonotonic : ipRectilinear; region_config.top_fill_pattern == ipMonotonic ? ipMonotonic : ipRectilinear;
@ -144,9 +148,10 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.angle = float(Geometry::deg2rad(region_config.fill_angle.value)); params.angle = float(Geometry::deg2rad(region_config.fill_angle.value));
// Calculate the actual flow we'll be using for this infill. // Calculate the actual flow we'll be using for this infill.
params.flow = is_bridge || Fill::use_bridge_flow(params.pattern) ? params.bridge = is_bridge || Fill::use_bridge_flow(params.pattern);
params.flow = params.bridge ?
layerm.bridging_flow(extrusion_role) : layerm.bridging_flow(extrusion_role) :
layerm.region()->flow(*layer.object(), extrusion_role, (surface.thickness == -1) ? layer.height : surface.thickness, layer.id() == 0); 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.
if (surface.is_solid() || is_bridge) { if (surface.is_solid() || is_bridge) {
@ -159,7 +164,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
// for all layers, for avoiding the ugly effect of // for all layers, for avoiding the ugly effect of
// misaligned infill on first layer because of different extrusion width and // misaligned infill on first layer because of different extrusion width and
// layer height // layer height
params.spacing = layerm.region()->flow(*layer.object(), frInfill, layer.object()->config().layer_height).spacing(); params.spacing = layerm.flow(frInfill, layer.object()->config().layer_height).spacing();
// Anchor a sparse infill to inner perimeters with the following anchor length: // Anchor a sparse infill to inner perimeters with the following anchor length:
params.anchor_length = float(region_config.infill_anchor); params.anchor_length = float(region_config.infill_anchor);
if (region_config.infill_anchor.percent) if (region_config.infill_anchor.percent)
@ -278,7 +283,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
params.extrusion_role = erInternalInfill; params.extrusion_role = erInternalInfill;
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value)); params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
// calculate the actual flow we'll be using for this infill // calculate the actual flow we'll be using for this infill
params.flow = layerm.region()->flow(*layer.object(), frSolidInfill, layer.height, layer.id() == 0); params.flow = layerm.flow(frSolidInfill);
params.spacing = params.flow.spacing(); params.spacing = params.flow.spacing();
surface_fills.emplace_back(params); surface_fills.emplace_back(params);
surface_fills.back().surface.surface_type = stInternalSolid; surface_fills.back().surface.surface_type = stInternalSolid;
@ -346,9 +351,9 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
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;
// calculate flow spacing for infill pattern generation // calculate flow spacing for infill pattern generation
bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.flow.bridge(); bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.bridge;
double link_max_length = 0.; double link_max_length = 0.;
if (! surface_fill.params.flow.bridge()) { if (! surface_fill.params.bridge) {
#if 0 #if 0
link_max_length = layerm.region()->config().get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing()); link_max_length = layerm.region()->config().get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing());
// printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length); // printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length);
@ -389,9 +394,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
// so we can safely ignore the slight variation that might have // so we can safely ignore the slight variation that might have
// been applied to f->spacing // been applied to f->spacing
} else { } else {
Flow new_flow = surface_fill.params.flow.bridge() ? Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing));
Flow::bridging_flow_from_spacing(float(f->spacing), surface_fill.params.flow.nozzle_diameter()) :
Flow::new_from_spacing(float(f->spacing), surface_fill.params.flow.nozzle_diameter(), surface_fill.params.flow.height());
flow_mm3_per_mm = new_flow.mm3_per_mm(); flow_mm3_per_mm = new_flow.mm3_per_mm();
flow_width = new_flow.width(); flow_width = new_flow.width();
} }
@ -601,9 +604,9 @@ void Layer::make_ironing()
fill.spacing = ironing_params.line_spacing; fill.spacing = ironing_params.line_spacing;
fill.angle = float(ironing_params.angle + 0.25 * M_PI); fill.angle = float(ironing_params.angle + 0.25 * M_PI);
fill.link_max_length = (coord_t)scale_(3. * fill.spacing); fill.link_max_length = (coord_t)scale_(3. * fill.spacing);
double height = ironing_params.height * fill.spacing / nozzle_dmr; double extrusion_height = ironing_params.height * fill.spacing / nozzle_dmr;
Flow flow = Flow::new_from_spacing(float(nozzle_dmr), 0., float(height)); float extrusion_width = Flow::rounded_rectangle_extrusion_width_from_spacing(float(nozzle_dmr), float(extrusion_height));
double flow_mm3_per_mm = flow.mm3_per_mm(); double flow_mm3_per_mm = nozzle_dmr * extrusion_height;
Surface surface_fill(stTop, ExPolygon()); Surface surface_fill(stTop, ExPolygon());
for (ExPolygon &expoly : ironing_areas) { for (ExPolygon &expoly : ironing_areas) {
surface_fill.expolygon = std::move(expoly); surface_fill.expolygon = std::move(expoly);
@ -621,7 +624,7 @@ void Layer::make_ironing()
extrusion_entities_append_paths( extrusion_entities_append_paths(
eec->entities, std::move(polylines), eec->entities, std::move(polylines),
erIroning, erIroning,
flow_mm3_per_mm, float(flow.width()), float(height)); flow_mm3_per_mm, extrusion_width, float(extrusion_height));
} }
} }
} }

View File

@ -6,12 +6,6 @@
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
// Overlap factor of perimeter lines. Currently no overlap.
// #define HAS_PERIMETER_LINE_OVERLAP
#ifdef HAS_PERIMETER_LINE_OVERLAP
#define PERIMETER_LINE_OVERLAP_FACTOR 1.0
#endif
// Mark string for localization and translate. // Mark string for localization and translate.
#define L(s) Slic3r::I18N::translate(s) #define L(s) Slic3r::I18N::translate(s)
@ -142,62 +136,82 @@ Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent
w = float(width.get_abs_value(height)); w = float(width.get_abs_value(height));
} }
return Flow(w, height, nozzle_diameter, false); return Flow(w, height, rounded_rectangle_extrusion_spacing(w, height), nozzle_diameter, false);
} }
// This constructor builds a Flow object from a given centerline spacing. // Adjust extrusion flow for new extrusion line spacing, maintaining the old spacing between extrusions.
Flow Flow::new_from_spacing(float spacing, float nozzle_diameter, float height) Flow Flow::with_spacing(float new_spacing) const
{ {
if (height <= 0) Flow out = *this;
throw Slic3r::InvalidArgument("Invalid flow height supplied to new_from_spacing()"); if (m_bridge) {
// Calculate width from spacing. // Diameter of the rounded extrusion.
// For normal extrusons, extrusion width is wider than the spacing due to the rounding and squishing of the extrusions. assert(m_width == m_height);
float width = float( float gap = m_spacing - m_width;
#ifdef HAS_PERIMETER_LINE_OVERLAP auto new_diameter = new_spacing - gap;
(spacing + PERIMETER_LINE_OVERLAP_FACTOR * height * (1. - 0.25 * PI)); out.m_width = out.m_height = new_diameter;
#else } else {
(spacing + height * (1. - 0.25 * PI))); out.m_width += new_spacing - m_spacing;
#endif if (out.m_width < out.m_height)
return Flow(width, height, nozzle_diameter); throw Slic3r::InvalidArgument("Invalid spacing supplied to Flow::with_spacing()");
}
out.m_spacing = new_spacing;
return out;
} }
// This method returns the centerline spacing between two adjacent extrusions // Adjust the width / height of a rounded extrusion model to reach the prescribed cross section area while maintaining extrusion spacing.
// having the same extrusion width (and other properties). Flow Flow::with_cross_section(float area_new) const
float Flow::spacing() const
{ {
#ifdef HAS_PERIMETER_LINE_OVERLAP assert(! m_bridge);
if (m_bridge) assert(flow.width() >= flow.height());
return m_width + BRIDGE_EXTRA_SPACING;
// rectangle with semicircles at the ends // Adjust for bridge_flow_ratio, maintain the extrusion spacing.
float min_flow_spacing = m_width - m_height * (1. - 0.25 * PI); float area = this->mm3_per_mm();
float res = m_width - PERIMETER_LINE_OVERLAP_FACTOR * (m_width - min_flow_spacing); if (area_new > area + EPSILON) {
#else // Increasing the flow rate.
float res = float(m_bridge ? (m_width + BRIDGE_EXTRA_SPACING) : (m_width - m_height * (1. - 0.25 * PI))); float new_full_spacing = area_new / m_height;
#endif if (new_full_spacing > m_spacing) {
// assert(res > 0.f); // Filling up the spacing without an air gap. Grow the extrusion in height.
if (res <= 0.f) float height = area_new / m_spacing;
throw FlowErrorNegativeSpacing(); return Flow(rounded_rectangle_extrusion_width_from_spacing(m_spacing, height), height, m_spacing, m_nozzle_diameter, false);
return res; } else {
return this->with_width(rounded_rectangle_extrusion_width_from_spacing(area / m_height, m_height));
}
} else if (area_new < area - EPSILON) {
// Decreasing the flow rate.
float width_new = m_width - (area - area_new) / m_height;
assert(width_dif > 0);
if (width_new > m_height) {
// Shrink the extrusion width.
return this->with_width(width_new);
} else {
// Create a rounded extrusion.
auto dmr = float(sqrt(area_new / M_PI));
return Flow(dmr, dmr, m_spacing, m_nozzle_diameter, false);
}
} else
return *this;
} }
// This method returns the centerline spacing between an extrusion using this float Flow::rounded_rectangle_extrusion_spacing(float width, float height)
// flow and another one using another flow.
// this->spacing(other) shall return the same value as other.spacing(*this)
float Flow::spacing(const Flow &other) const
{ {
assert(m_height == other.m_height); auto out = width - height * float(1. - 0.25 * PI);
assert(m_bridge == other.m_bridge); if (out <= 0.f)
float res = float(m_bridge ? throw FlowErrorNegativeSpacing();
0.5 * m_width + 0.5 * other.m_width + BRIDGE_EXTRA_SPACING : return out;
0.5 * this->spacing() + 0.5 * other.spacing()); }
// assert(res > 0.f);
if (res <= 0.f) float Flow::rounded_rectangle_extrusion_width_from_spacing(float spacing, float height)
throw FlowErrorNegativeSpacing(); {
return res; return float(spacing + height * (1. - 0.25 * PI));
}
float Flow::bridge_extrusion_spacing(float dmr)
{
return dmr + BRIDGE_EXTRA_SPACING;
} }
// This method returns extrusion volume per head move unit. // This method returns extrusion volume per head move unit.
double Flow::mm3_per_mm() const double Flow::mm3_per_mm() const
{ {
float res = m_bridge ? float res = m_bridge ?
// Area of a circle with dmr of this->width. // Area of a circle with dmr of this->width.

View File

@ -51,26 +51,26 @@ public:
class Flow class Flow
{ {
public: public:
Flow() = default;
Flow(float width, float height, float nozzle_diameter) :
Flow(width, height, rounded_rectangle_extrusion_spacing(width, height), nozzle_diameter, false) {}
// Non bridging flow: Maximum width of an extrusion with semicircles at the ends. // Non bridging flow: Maximum width of an extrusion with semicircles at the ends.
// Bridging flow: Bridge thread diameter. // Bridging flow: Bridge thread diameter.
float width() const { return m_width; } float width() const { return m_width; }
coord_t scaled_width() const { return coord_t(scale_(m_width)); }
// Non bridging flow: Layer height. // Non bridging flow: Layer height.
// Bridging flow: Bridge thread diameter = layer height. // Bridging flow: Bridge thread diameter = layer height.
float height() const { return m_height; } float height() const { return m_height; }
// Spacing between the extrusion centerlines.
float spacing() const { return m_spacing; }
coord_t scaled_spacing() const { return coord_t(scale_(m_spacing)); }
// Nozzle diameter. // Nozzle diameter.
float nozzle_diameter() const { return m_nozzle_diameter; } float nozzle_diameter() const { return m_nozzle_diameter; }
// Is it a bridge? // Is it a bridge?
bool bridge() const { return m_bridge; } bool bridge() const { return m_bridge; }
// Cross section area of the extrusion.
Flow() = default; double mm3_per_mm() const;
Flow(float w, float h, float nozzle_diameter) : Flow(w, h, nozzle_diameter, false) {}
float spacing() const;
float spacing(const Flow &other) const;
double mm3_per_mm() const;
coord_t scaled_width() const { return coord_t(scale_(m_width)); }
coord_t scaled_spacing() const { return coord_t(scale_(this->spacing())); }
coord_t scaled_spacing(const Flow &other) const { return coord_t(scale_(this->spacing(other))); }
// Elephant foot compensation spacing to be used to detect narrow parts, where the elephant foot compensation cannot be applied. // Elephant foot compensation spacing to be used to detect narrow parts, where the elephant foot compensation cannot be applied.
// To be used on frExternalPerimeter only. // To be used on frExternalPerimeter only.
@ -80,18 +80,30 @@ public:
bool operator==(const Flow &rhs) const { return m_width == rhs.m_width && m_height == rhs.m_height && m_nozzle_diameter == rhs.m_nozzle_diameter && m_bridge == rhs.m_bridge; } bool operator==(const Flow &rhs) const { return m_width == rhs.m_width && m_height == rhs.m_height && m_nozzle_diameter == rhs.m_nozzle_diameter && m_bridge == rhs.m_bridge; }
Flow with_width (float width) const { assert(! m_bridge); return Flow(width, m_height, m_nozzle_diameter, m_bridge); } Flow with_width (float width) const {
Flow with_height(float height) const { assert(! m_bridge); return Flow(m_width, height, m_nozzle_diameter, m_bridge); } assert(! m_bridge);
return Flow(width, m_height, rounded_rectangle_extrusion_spacing(width, m_height), m_nozzle_diameter, m_bridge);
}
Flow with_height(float height) const {
assert(! m_bridge);
return Flow(m_width, height, rounded_rectangle_extrusion_spacing(m_width, height), m_nozzle_diameter, m_bridge);
}
// Adjust extrusion flow for new extrusion line spacing, maintaining the old spacing between extrusions.
Flow with_spacing(float spacing) const;
// Adjust the width / height of a rounded extrusion model to reach the prescribed cross section area while maintaining extrusion spacing.
Flow with_cross_section(float area) const;
Flow with_flow_ratio(double ratio) const { return this->with_cross_section(this->mm3_per_mm() * ratio); }
static Flow bridging_flow(float dmr, float nozzle_diameter) { return Flow { dmr, dmr, bridge_extrusion_spacing(dmr), nozzle_diameter, true }; }
static Flow bridging_flow(float dmr, float nozzle_diameter) { return Flow { dmr, dmr, nozzle_diameter, true }; }
static Flow bridging_flow_from_spacing(float spacing, float nozzle_diameter)
{ auto dmr = spacing - float(BRIDGE_EXTRA_SPACING); return Flow { dmr, dmr, nozzle_diameter, true }; }
static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height); static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height);
// Create a flow from the spacing of extrusion lines.
// This method is used exclusively to calculate new flow of 100% infill, where the extrusion width was allowed to scale // Spacing of extrusions with rounded extrusion model.
// to fit a region with integer number of lines. static float rounded_rectangle_extrusion_spacing(float width, float height);
static Flow new_from_spacing(float spacing, float nozzle_diameter, float height); // Width of extrusions with rounded extrusion model.
static float rounded_rectangle_extrusion_width_from_spacing(float spacing, float height);
// Spacing of round thread extrusions.
static float bridge_extrusion_spacing(float dmr);
// Sane extrusion width defautl based on nozzle diameter. // Sane extrusion width defautl based on nozzle diameter.
// The defaults were derived from manual Prusa MK3 profiles. // The defaults were derived from manual Prusa MK3 profiles.
@ -104,10 +116,12 @@ public:
static double extrusion_width(const std::string &opt_key, const ConfigOptionResolver &config, const unsigned int first_printing_extruder = 0); static double extrusion_width(const std::string &opt_key, const ConfigOptionResolver &config, const unsigned int first_printing_extruder = 0);
private: private:
Flow(float w, float h, float nozzle_diameter, bool bridge) : m_width(w), m_height(h), m_nozzle_diameter(nozzle_diameter), m_bridge(bridge) {} Flow(float width, float height, float spacing, float nozzle_diameter, bool bridge) :
m_width(width), m_height(height), m_spacing(spacing), m_nozzle_diameter(nozzle_diameter), m_bridge(bridge) {}
float m_width { 0 }; float m_width { 0 };
float m_height { 0 }; float m_height { 0 };
float m_spacing { 0 };
float m_nozzle_diameter { 0 }; float m_nozzle_diameter { 0 };
bool m_bridge { false }; bool m_bridge { false };
}; };

View File

@ -60,6 +60,7 @@ public:
ExtrusionEntityCollection fills; ExtrusionEntityCollection fills;
Flow flow(FlowRole role) const; Flow flow(FlowRole role) const;
Flow flow(FlowRole role, double layer_height) const;
Flow bridging_flow(FlowRole role) const; Flow bridging_flow(FlowRole role) const;
void slices_to_fill_surfaces_clipped(); void slices_to_fill_surfaces_clipped();

View File

@ -17,12 +17,29 @@ namespace Slic3r {
Flow LayerRegion::flow(FlowRole role) const Flow LayerRegion::flow(FlowRole role) const
{ {
return m_region->flow(*m_layer->object(), role, m_layer->height, m_layer->id() == 0); return this->flow(role, m_layer->height);
}
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) const
{ {
return this->layer()->object()->config().thick_bridges ? m_region->bridging_flow(role) : this->flow(role); const PrintRegion &region = *this->region();
const PrintRegionConfig &region_config = region.config();
if (this->layer()->object()->config().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.
auto nozzle_diameter = float(region.print()->config().nozzle_diameter.get_at(region.extruder(role) - 1));
// Applies default bridge spacing.
return Flow::bridging_flow(float(sqrt(region_config.bridge_flow_ratio)) * nozzle_diameter, nozzle_diameter);
} else {
// The same way as other slicers: Use normal extrusions. Apply bridge_flow_ratio while maintaining the original spacing.
return this->flow(role).with_flow_ratio(region_config.bridge_flow_ratio);
}
} }
// Fill in layerm->fill_surfaces by trimming the layerm->slices by the cummulative layerm->fill_surfaces. // Fill in layerm->fill_surfaces by trimming the layerm->slices by the cummulative layerm->fill_surfaces.

View File

@ -286,7 +286,7 @@ void PerimeterGenerator::process()
m_ext_mm3_per_mm = this->ext_perimeter_flow.mm3_per_mm(); m_ext_mm3_per_mm = this->ext_perimeter_flow.mm3_per_mm();
coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width(); coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width();
coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing(); coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing();
coord_t ext_perimeter_spacing2 = this->ext_perimeter_flow.scaled_spacing(this->perimeter_flow); coord_t ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (this->ext_perimeter_flow.spacing() + this->perimeter_flow.spacing()));
// overhang perimeters // overhang perimeters
m_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm(); m_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm();

View File

@ -66,7 +66,6 @@ public:
// 1-based extruder identifier for this region and role. // 1-based extruder identifier for this region and role.
unsigned int extruder(FlowRole role) const; unsigned int extruder(FlowRole role) const;
Flow flow(const PrintObject &object, FlowRole role, double layer_height, bool first_layer = false) const; Flow flow(const PrintObject &object, FlowRole role, double layer_height, bool first_layer = false) const;
Flow bridging_flow(FlowRole role) const;
// Average diameter of nozzles participating on extruding this region. // Average diameter of nozzles participating on extruding this region.
coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const; coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const;
// Average diameter of nozzles participating on extruding this region. // Average diameter of nozzles participating on extruding this region.

View File

@ -1457,19 +1457,18 @@ void PrintObject::bridge_over_infill()
const PrintRegion &region = *m_print->regions()[region_id]; const PrintRegion &region = *m_print->regions()[region_id];
// skip bridging in case there are no voids // skip bridging in case there are no voids
if (region.config().fill_density.value == 100) continue; if (region.config().fill_density.value == 100)
continue;
// get bridge flow
Flow bridge_flow = region.bridging_flow(frSolidInfill);
for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++ layer_it) { for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++ layer_it) {
// skip first layer // skip first layer
if (layer_it == m_layers.begin()) if (layer_it == m_layers.begin())
continue; continue;
Layer* layer = *layer_it; Layer *layer = *layer_it;
LayerRegion* layerm = layer->m_regions[region_id]; LayerRegion *layerm = layer->m_regions[region_id];
Flow bridge_flow = layerm->bridging_flow(frSolidInfill);
// extract the stInternalSolid surfaces that might be transformed into bridges // extract the stInternalSolid surfaces that might be transformed into bridges
Polygons internal_solid; Polygons internal_solid;
layerm->fill_surfaces.filter_by_type(stInternalSolid, &internal_solid); layerm->fill_surfaces.filter_by_type(stInternalSolid, &internal_solid);

View File

@ -48,17 +48,6 @@ Flow PrintRegion::flow(const PrintObject &object, FlowRole role, double layer_he
return Flow::new_from_config_width(role, config_width, nozzle_diameter, float(layer_height)); return Flow::new_from_config_width(role, config_width, nozzle_diameter, float(layer_height));
} }
Flow PrintRegion::bridging_flow(FlowRole role) const
{
// 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.
auto nozzle_diameter = float(m_print->config().nozzle_diameter.get_at(this->extruder(role) - 1));
double bfr = m_config.bridge_flow_ratio;
if (bfr != 1.)
bfr = sqrt(bfr);
return Flow::bridging_flow(float(bfr) * nozzle_diameter, nozzle_diameter);
}
coordf_t PrintRegion::nozzle_dmr_avg(const PrintConfig &print_config) const coordf_t PrintRegion::nozzle_dmr_avg(const PrintConfig &print_config) const
{ {
return (print_config.nozzle_diameter.get_at(m_config.perimeter_extruder.value - 1) + return (print_config.nozzle_diameter.get_at(m_config.perimeter_extruder.value - 1) +

View File

@ -334,7 +334,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object
for (auto lh : m_print_config->min_layer_height.values) for (auto lh : m_print_config->min_layer_height.values)
m_support_layer_height_min = std::min(m_support_layer_height_min, std::max(0.01, lh)); m_support_layer_height_min = std::min(m_support_layer_height_min, std::max(0.01, lh));
if (m_object_config->support_material_interface_layers.value == 0) { if (m_slicing_params.soluble_interface) {
// No interface layers allowed, print everything with the base support pattern. // No interface layers allowed, print everything with the base support pattern.
m_support_material_interface_flow = m_support_material_flow; m_support_material_interface_flow = m_support_material_flow;
} }
@ -342,11 +342,21 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object
// Evaluate the XY gap between the object outer perimeters and the support structures. // Evaluate the XY gap between the object outer perimeters and the support structures.
// Evaluate the XY gap between the object outer perimeters and the support structures. // Evaluate the XY gap between the object outer perimeters and the support structures.
coordf_t external_perimeter_width = 0.; coordf_t external_perimeter_width = 0.;
size_t num_nonempty_regions = 0;
coordf_t bridge_flow_ratio = 0;
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id)
if (! object->region_volumes[region_id].empty()) if (! object->region_volumes[region_id].empty()) {
external_perimeter_width = std::max(external_perimeter_width, ++ num_nonempty_regions;
(coordf_t)object->print()->get_region(region_id)->flow(*object, frExternalPerimeter, slicing_params.layer_height).width()); const PrintRegion &region = *object->print()->get_region(region_id);
external_perimeter_width = std::max(external_perimeter_width, coordf_t(region.flow(*object, frExternalPerimeter, slicing_params.layer_height).width()));
bridge_flow_ratio += region.config().bridge_flow_ratio;
}
m_gap_xy = m_object_config->support_material_xy_spacing.get_abs_value(external_perimeter_width); m_gap_xy = m_object_config->support_material_xy_spacing.get_abs_value(external_perimeter_width);
bridge_flow_ratio /= num_nonempty_regions;
m_support_material_bottom_interface_flow = m_slicing_params.soluble_interface || ! m_object_config->thick_bridges ?
m_support_material_interface_flow.with_flow_ratio(bridge_flow_ratio) :
Flow::bridging_flow(bridge_flow_ratio * m_support_material_interface_flow.nozzle_diameter(), m_support_material_interface_flow.nozzle_diameter());
m_can_merge_support_regions = m_object_config->support_material_extruder.value == m_object_config->support_material_interface_extruder.value; m_can_merge_support_regions = m_object_config->support_material_extruder.value == m_object_config->support_material_interface_extruder.value;
if (! m_can_merge_support_regions && (m_object_config->support_material_extruder.value == 0 || m_object_config->support_material_interface_extruder.value == 0)) { if (! m_can_merge_support_regions && (m_object_config->support_material_extruder.value == 0 || m_object_config->support_material_interface_extruder.value == 0)) {
@ -1231,8 +1241,8 @@ namespace SupportMaterialInternal {
// since we're dealing with bridges, we can't assume width is larger than spacing, // since we're dealing with bridges, we can't assume width is larger than spacing,
// so we take the largest value and also apply safety offset to be ensure no gaps // so we take the largest value and also apply safety offset to be ensure no gaps
// are left in between // are left in between
Flow bridge_flow = layerm->bridging_flow(frPerimeter); Flow perimeter_bridge_flow = layerm->bridging_flow(frPerimeter);
float w = float(std::max(bridge_flow.scaled_width(), bridge_flow.scaled_spacing())); float w = float(std::max(perimeter_bridge_flow.scaled_width(), perimeter_bridge_flow.scaled_spacing()));
for (Polyline &polyline : overhang_perimeters) for (Polyline &polyline : overhang_perimeters)
if (polyline.is_straight()) { if (polyline.is_straight()) {
// This is a bridge // This is a bridge
@ -1879,13 +1889,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
layer_new.height = m_slicing_params.soluble_interface ? layer_new.height = m_slicing_params.soluble_interface ?
// Align the interface layer with the object's layer height. // Align the interface layer with the object's layer height.
object.layers()[layer_id + 1]->height : object.layers()[layer_id + 1]->height :
// Place a bridge flow interface layer over the top surface. // Place a bridge flow interface layer or the normal flow interface layer over the top surface.
//FIXME Check whether the bottom bridging surfaces are extruded correctly (no bridging flow correction applied?) m_support_material_bottom_interface_flow.height();
// According to Jindrich the bottom surfaces work well.
//FIXME test the bridging flow instead?
m_object_config->thick_bridges.value ? m_support_material_interface_flow.nozzle_diameter() :
// Take the default layer height.
m_object_config->layer_height;
layer_new.print_z = m_slicing_params.soluble_interface ? object.layers()[layer_id + 1]->print_z : layer_new.print_z = m_slicing_params.soluble_interface ? object.layers()[layer_id + 1]->print_z :
layer.print_z + layer_new.height + m_object_config->support_material_contact_distance.value; layer.print_z + layer_new.height + m_object_config->support_material_contact_distance.value;
layer_new.bottom_z = layer.print_z; layer_new.bottom_z = layer.print_z;
@ -3497,7 +3502,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
coordf_t interface_density = std::min(1., m_support_material_interface_flow.spacing() / interface_spacing); coordf_t interface_density = std::min(1., m_support_material_interface_flow.spacing() / interface_spacing);
coordf_t support_spacing = m_object_config->support_material_spacing.value + m_support_material_flow.spacing(); coordf_t support_spacing = m_object_config->support_material_spacing.value + m_support_material_flow.spacing();
coordf_t support_density = std::min(1., m_support_material_flow.spacing() / support_spacing); coordf_t support_density = std::min(1., m_support_material_flow.spacing() / support_spacing);
if (m_object_config->support_material_interface_layers.value == 0) { if (m_slicing_params.soluble_interface) {
// No interface layers allowed, print everything with the base support pattern. // No interface layers allowed, print everything with the base support pattern.
interface_spacing = support_spacing; interface_spacing = support_spacing;
interface_density = support_density; interface_density = support_density;
@ -3738,13 +3743,12 @@ void PrintObjectSupportMaterial::generate_toolpaths(
MyLayerExtruded &layer_ex = (i == 0) ? top_contact_layer : (i == 1 ? bottom_contact_layer : interface_layer); MyLayerExtruded &layer_ex = (i == 0) ? top_contact_layer : (i == 1 ? bottom_contact_layer : interface_layer);
if (layer_ex.empty() || layer_ex.polygons_to_extrude().empty()) if (layer_ex.empty() || layer_ex.polygons_to_extrude().empty())
continue; continue;
bool interface_as_base = (&layer_ex == &interface_layer) && m_object_config->support_material_interface_layers.value == 0; bool interface_as_base = (&layer_ex == &interface_layer) && m_slicing_params.soluble_interface;
//FIXME Bottom interfaces are extruded with the briding flow. Some bridging layers have its height slightly reduced, therefore //FIXME Bottom interfaces are extruded with the briding flow. Some bridging layers have its height slightly reduced, therefore
// the bridging flow does not quite apply. Reduce the flow to area of an ellipse? (A = pi * a * b) // the bridging flow does not quite apply. Reduce the flow to area of an ellipse? (A = pi * a * b)
auto interface_flow = layer_ex.layer->bridging ? auto interface_flow = layer_ex.layer->bridging ?
Flow::bridging_flow(layer_ex.layer->height, m_support_material_interface_flow.nozzle_diameter()) : Flow::bridging_flow(layer_ex.layer->height, m_support_material_bottom_interface_flow.nozzle_diameter()) :
Flow(interface_as_base ? m_support_material_flow.width() : m_support_material_interface_flow.width(), (interface_as_base ? &m_support_material_flow : &m_support_material_interface_flow)->with_height(float(layer_ex.layer->height));
float(layer_ex.layer->height), m_support_material_interface_flow.nozzle_diameter());
filler_interface->angle = interface_as_base ? filler_interface->angle = interface_as_base ?
// If zero interface layers are configured, use the same angle as for the base layers. // If zero interface layers are configured, use the same angle as for the base layers.
angles[support_layer_id % angles.size()] : angles[support_layer_id % angles.size()] :

View File

@ -244,6 +244,7 @@ private:
Flow m_first_layer_flow; Flow m_first_layer_flow;
Flow m_support_material_flow; Flow m_support_material_flow;
Flow m_support_material_interface_flow; Flow m_support_material_interface_flow;
Flow m_support_material_bottom_interface_flow;
// Is merging of regions allowed? Could the interface & base support regions be printed with the same extruder? // Is merging of regions allowed? Could the interface & base support regions be printed with the same extruder?
bool m_can_merge_support_regions; bool m_can_merge_support_regions;

View File

@ -16,8 +16,6 @@
float nozzle_diameter(); float nozzle_diameter();
bool bridge(); bool bridge();
float spacing(); float spacing();
float spacing_to(Flow* other)
%code{% RETVAL = THIS->spacing(*other); %};
int scaled_width(); int scaled_width();
int scaled_spacing(); int scaled_spacing();
double mm3_per_mm(); double mm3_per_mm();