WIP: Refactored bridging flow from normal flow, new config value
'thick_bridges' to switch between the Slic3r vs. S3D/Cura/Ideamaker way of printing 1st object layer over supports. Simplified the PresetHints.
This commit is contained in:
parent
1569dad5de
commit
ceea9de8b8
@ -320,7 +320,7 @@ static void make_inner_brim(const Print &print, const ConstPrintObjectPtrs &top_
|
||||
loops = union_pt_chained_outside_in(loops, false);
|
||||
std::reverse(loops.begin(), loops.end());
|
||||
extrusion_entities_append_loops(brim.entities, std::move(loops), erSkirt, float(flow.mm3_per_mm()),
|
||||
float(flow.width), float(print.skirt_first_layer_height()));
|
||||
float(flow.width()), float(print.skirt_first_layer_height()));
|
||||
}
|
||||
|
||||
// Produce brim lines around those objects, that have the brim enabled.
|
||||
@ -495,7 +495,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
|
||||
if (i + 1 == j && first_path.size() > 3 && first_path.front().X == first_path.back().X && first_path.front().Y == first_path.back().Y) {
|
||||
auto *loop = new ExtrusionLoop();
|
||||
brim.entities.emplace_back(loop);
|
||||
loop->paths.emplace_back(erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(print.skirt_first_layer_height()));
|
||||
loop->paths.emplace_back(erSkirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height()));
|
||||
Points &points = loop->paths.front().polyline.points;
|
||||
points.reserve(first_path.size());
|
||||
for (const ClipperLib_Z::IntPoint &pt : first_path)
|
||||
@ -506,7 +506,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
|
||||
ExtrusionEntityCollection this_loop_trimmed;
|
||||
this_loop_trimmed.entities.reserve(j - i);
|
||||
for (; i < j; ++ i) {
|
||||
this_loop_trimmed.entities.emplace_back(new ExtrusionPath(erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(print.skirt_first_layer_height())));
|
||||
this_loop_trimmed.entities.emplace_back(new ExtrusionPath(erSkirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height())));
|
||||
const ClipperLib_Z::Path &path = *loops_trimmed_order[i].first;
|
||||
Points &points = static_cast<ExtrusionPath*>(this_loop_trimmed.entities.back())->polyline.points;
|
||||
points.reserve(path.size());
|
||||
@ -522,7 +522,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
|
||||
}
|
||||
}
|
||||
} else {
|
||||
extrusion_entities_append_loops_and_paths(brim.entities, std::move(all_loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width), float(print.skirt_first_layer_height()));
|
||||
extrusion_entities_append_loops_and_paths(brim.entities, std::move(all_loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height()));
|
||||
}
|
||||
|
||||
make_inner_brim(print, top_level_objects_with_brim, brim);
|
||||
|
@ -621,7 +621,7 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, double min_c
|
||||
ExPolygon elephant_foot_compensation(const ExPolygon &input, const Flow &external_perimeter_flow, const double compensation)
|
||||
{
|
||||
// The contour shall be wide enough to apply the external perimeter plus compensation on both sides.
|
||||
double min_contour_width = double(external_perimeter_flow.width + external_perimeter_flow.spacing());
|
||||
double min_contour_width = double(external_perimeter_flow.width() + external_perimeter_flow.spacing());
|
||||
return elephant_foot_compensation(input, min_contour_width, compensation);
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,9 @@ void ExtrusionPath::polygons_covered_by_spacing(Polygons &out, const float scale
|
||||
{
|
||||
// Instantiating the Flow class to get the line spacing.
|
||||
// Don't know the nozzle diameter, setting to zero. It shall not matter it shall be optimized out by the compiler.
|
||||
Flow flow(this->width, this->height, 0.f, is_bridge(this->role()));
|
||||
bool bridge = is_bridge(this->role());
|
||||
assert(! bridge || this->width == this->height);
|
||||
auto flow = bridge ? Flow::bridging_flow(this->width, 0.f) : Flow(this->width, this->height, 0.f);
|
||||
polygons_append(out, offset(this->polyline, 0.5f * float(flow.scaled_spacing()) + scaled_epsilon));
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ struct SurfaceFillParams
|
||||
|
||||
// width, height of extrusion, nozzle diameter, is bridge
|
||||
// For the output, for fill generator.
|
||||
Flow flow = Flow(0.f, 0.f, 0.f, false);
|
||||
Flow flow;
|
||||
|
||||
// For the output
|
||||
ExtrusionRole extrusion_role = ExtrusionRole(0);
|
||||
@ -70,10 +70,10 @@ struct SurfaceFillParams
|
||||
// RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
|
||||
RETURN_COMPARE_NON_EQUAL(anchor_length);
|
||||
RETURN_COMPARE_NON_EQUAL(anchor_length_max);
|
||||
RETURN_COMPARE_NON_EQUAL(flow.width);
|
||||
RETURN_COMPARE_NON_EQUAL(flow.height);
|
||||
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter);
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, flow.bridge);
|
||||
RETURN_COMPARE_NON_EQUAL(flow.width());
|
||||
RETURN_COMPARE_NON_EQUAL(flow.height());
|
||||
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter());
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, flow.bridge());
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, extrusion_role);
|
||||
return false;
|
||||
}
|
||||
@ -143,17 +143,12 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
params.bridge_angle = float(surface.bridge_angle);
|
||||
params.angle = float(Geometry::deg2rad(region_config.fill_angle.value));
|
||||
|
||||
// calculate the actual flow we'll be using for this infill
|
||||
params.flow = layerm.region()->flow(
|
||||
extrusion_role,
|
||||
(surface.thickness == -1) ? layer.height : surface.thickness, // extrusion height
|
||||
is_bridge || Fill::use_bridge_flow(params.pattern), // bridge flow?
|
||||
layer.id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*layer.object()
|
||||
);
|
||||
|
||||
// Calculate flow spacing for infill pattern generation.
|
||||
// Calculate the actual flow we'll be using for this infill.
|
||||
params.flow = is_bridge || Fill::use_bridge_flow(params.pattern) ?
|
||||
layerm.bridging_flow(extrusion_role) :
|
||||
layerm.region()->flow(*layer.object(), extrusion_role, (surface.thickness == -1) ? layer.height : surface.thickness, layer.id() == 0);
|
||||
|
||||
// Calculate flow spacing for infill pattern generation.
|
||||
if (surface.is_solid() || is_bridge) {
|
||||
params.spacing = params.flow.spacing();
|
||||
// Don't limit anchor length for solid or bridging infill.
|
||||
@ -164,14 +159,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
// for all layers, for avoiding the ugly effect of
|
||||
// misaligned infill on first layer because of different extrusion width and
|
||||
// layer height
|
||||
params.spacing = layerm.region()->flow(
|
||||
frInfill,
|
||||
layer.object()->config().layer_height.value, // TODO: handle infill_every_layers?
|
||||
false, // no bridge
|
||||
false, // no first layer
|
||||
-1, // auto width
|
||||
*layer.object()
|
||||
).spacing();
|
||||
params.spacing = layerm.region()->flow(*layer.object(), frInfill, layer.object()->config().layer_height).spacing();
|
||||
// Anchor a sparse infill to inner perimeters with the following anchor length:
|
||||
params.anchor_length = float(region_config.infill_anchor);
|
||||
if (region_config.infill_anchor.percent)
|
||||
@ -278,7 +266,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
region_id = region_some_infill;
|
||||
const LayerRegion& layerm = *layer.regions()[region_id];
|
||||
for (SurfaceFill &surface_fill : surface_fills)
|
||||
if (surface_fill.surface.surface_type == stInternalSolid && std::abs(layer.height - surface_fill.params.flow.height) < EPSILON) {
|
||||
if (surface_fill.surface.surface_type == stInternalSolid && std::abs(layer.height - surface_fill.params.flow.height()) < EPSILON) {
|
||||
internal_solid_fill = &surface_fill;
|
||||
break;
|
||||
}
|
||||
@ -290,14 +278,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
params.extrusion_role = erInternalInfill;
|
||||
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
|
||||
// calculate the actual flow we'll be using for this infill
|
||||
params.flow = layerm.region()->flow(
|
||||
frSolidInfill,
|
||||
layer.height, // extrusion height
|
||||
false, // bridge flow?
|
||||
layer.id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*layer.object()
|
||||
);
|
||||
params.flow = layerm.region()->flow(*layer.object(), frSolidInfill, layer.height, layer.id() == 0);
|
||||
params.spacing = params.flow.spacing();
|
||||
surface_fills.emplace_back(params);
|
||||
surface_fills.back().surface.surface_type = stInternalSolid;
|
||||
@ -365,9 +346,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;
|
||||
|
||||
// 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.flow.bridge();
|
||||
double link_max_length = 0.;
|
||||
if (! surface_fill.params.flow.bridge) {
|
||||
if (! surface_fill.params.flow.bridge()) {
|
||||
#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());
|
||||
// printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length);
|
||||
@ -380,7 +361,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
// Maximum length of the perimeter segment linking two infill lines.
|
||||
f->link_max_length = (coord_t)scale_(link_max_length);
|
||||
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
|
||||
f->loop_clipping = coord_t(scale_(surface_fill.params.flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
|
||||
f->loop_clipping = coord_t(scale_(surface_fill.params.flow.nozzle_diameter()) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
|
||||
|
||||
// apply half spacing using this flow's own spacing and generate infill
|
||||
FillParams params;
|
||||
@ -402,15 +383,17 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
// calculate actual flow from spacing (which might have been adjusted by the infill
|
||||
// pattern generator)
|
||||
double flow_mm3_per_mm = surface_fill.params.flow.mm3_per_mm();
|
||||
double flow_width = surface_fill.params.flow.width;
|
||||
double flow_width = surface_fill.params.flow.width();
|
||||
if (using_internal_flow) {
|
||||
// if we used the internal flow we're not doing a solid infill
|
||||
// so we can safely ignore the slight variation that might have
|
||||
// been applied to f->spacing
|
||||
} else {
|
||||
Flow new_flow = Flow::new_from_spacing(float(f->spacing), surface_fill.params.flow.nozzle_diameter, surface_fill.params.flow.height, surface_fill.params.flow.bridge);
|
||||
Flow new_flow = surface_fill.params.flow.bridge() ?
|
||||
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_width = new_flow.width;
|
||||
flow_width = new_flow.width();
|
||||
}
|
||||
// Save into layer.
|
||||
ExtrusionEntityCollection* eec = nullptr;
|
||||
@ -420,7 +403,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, std::move(polylines),
|
||||
surface_fill.params.extrusion_role,
|
||||
flow_mm3_per_mm, float(flow_width), surface_fill.params.flow.height);
|
||||
flow_mm3_per_mm, float(flow_width), surface_fill.params.flow.height());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -619,7 +602,7 @@ void Layer::make_ironing()
|
||||
fill.angle = float(ironing_params.angle + 0.25 * M_PI);
|
||||
fill.link_max_length = (coord_t)scale_(3. * fill.spacing);
|
||||
double height = ironing_params.height * fill.spacing / nozzle_dmr;
|
||||
Flow flow = Flow::new_from_spacing(float(nozzle_dmr), 0., float(height), false);
|
||||
Flow flow = Flow::new_from_spacing(float(nozzle_dmr), 0., float(height));
|
||||
double flow_mm3_per_mm = flow.mm3_per_mm();
|
||||
Surface surface_fill(stTop, ExPolygon());
|
||||
for (ExPolygon &expoly : ironing_areas) {
|
||||
@ -638,7 +621,7 @@ void Layer::make_ironing()
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, std::move(polylines),
|
||||
erIroning,
|
||||
flow_mm3_per_mm, float(flow.width), float(height));
|
||||
flow_mm3_per_mm, float(flow.width()), float(height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,12 @@
|
||||
|
||||
#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.
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
@ -122,20 +128,13 @@ double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionResol
|
||||
|
||||
// This constructor builds a Flow object from an extrusion width config setting
|
||||
// and other context properties.
|
||||
Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio)
|
||||
Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height)
|
||||
{
|
||||
// we need layer height unless it's a bridge
|
||||
if (height <= 0 && bridge_flow_ratio == 0)
|
||||
if (height <= 0)
|
||||
throw Slic3r::InvalidArgument("Invalid flow height supplied to new_from_config_width()");
|
||||
|
||||
float w;
|
||||
if (bridge_flow_ratio > 0) {
|
||||
// If bridge flow was requested, calculate the bridge width.
|
||||
height = w = (bridge_flow_ratio == 1.) ?
|
||||
// optimization to avoid sqrt()
|
||||
nozzle_diameter :
|
||||
sqrt(bridge_flow_ratio) * nozzle_diameter;
|
||||
} else if (! width.percent && width.value == 0.) {
|
||||
if (! width.percent && width.value == 0.) {
|
||||
// If user left option to 0, calculate a sane default width.
|
||||
w = auto_extrusion_width(role, nozzle_diameter);
|
||||
} else {
|
||||
@ -143,26 +142,23 @@ Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent
|
||||
w = float(width.get_abs_value(height));
|
||||
}
|
||||
|
||||
return Flow(w, height, nozzle_diameter, bridge_flow_ratio > 0);
|
||||
return Flow(w, height, nozzle_diameter, false);
|
||||
}
|
||||
|
||||
// This constructor builds a Flow object from a given centerline spacing.
|
||||
Flow Flow::new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge)
|
||||
Flow Flow::new_from_spacing(float spacing, float nozzle_diameter, float height)
|
||||
{
|
||||
// we need layer height unless it's a bridge
|
||||
if (height <= 0 && !bridge)
|
||||
if (height <= 0)
|
||||
throw Slic3r::InvalidArgument("Invalid flow height supplied to new_from_spacing()");
|
||||
// Calculate width from spacing.
|
||||
// For normal extrusons, extrusion width is wider than the spacing due to the rounding and squishing of the extrusions.
|
||||
// For bridge extrusions, the extrusions are placed with a tiny BRIDGE_EXTRA_SPACING gaps between the threads.
|
||||
float width = float(bridge ?
|
||||
(spacing - BRIDGE_EXTRA_SPACING) :
|
||||
float width = float(
|
||||
#ifdef HAS_PERIMETER_LINE_OVERLAP
|
||||
(spacing + PERIMETER_LINE_OVERLAP_FACTOR * height * (1. - 0.25 * PI));
|
||||
#else
|
||||
(spacing + height * (1. - 0.25 * PI)));
|
||||
#endif
|
||||
return Flow(width, bridge ? width : height, nozzle_diameter, bridge);
|
||||
return Flow(width, height, nozzle_diameter);
|
||||
}
|
||||
|
||||
// This method returns the centerline spacing between two adjacent extrusions
|
||||
@ -170,13 +166,13 @@ Flow Flow::new_from_spacing(float spacing, float nozzle_diameter, float height,
|
||||
float Flow::spacing() const
|
||||
{
|
||||
#ifdef HAS_PERIMETER_LINE_OVERLAP
|
||||
if (this->bridge)
|
||||
return this->width + BRIDGE_EXTRA_SPACING;
|
||||
if (m_bridge)
|
||||
return m_width + BRIDGE_EXTRA_SPACING;
|
||||
// rectangle with semicircles at the ends
|
||||
float min_flow_spacing = this->width - this->height * (1. - 0.25 * PI);
|
||||
float res = this->width - PERIMETER_LINE_OVERLAP_FACTOR * (this->width - min_flow_spacing);
|
||||
float min_flow_spacing = m_width - m_height * (1. - 0.25 * PI);
|
||||
float res = m_width - PERIMETER_LINE_OVERLAP_FACTOR * (m_width - min_flow_spacing);
|
||||
#else
|
||||
float res = float(this->bridge ? (this->width + BRIDGE_EXTRA_SPACING) : (this->width - this->height * (1. - 0.25 * PI)));
|
||||
float res = float(m_bridge ? (m_width + BRIDGE_EXTRA_SPACING) : (m_width - m_height * (1. - 0.25 * PI)));
|
||||
#endif
|
||||
// assert(res > 0.f);
|
||||
if (res <= 0.f)
|
||||
@ -189,10 +185,10 @@ float Flow::spacing() const
|
||||
// this->spacing(other) shall return the same value as other.spacing(*this)
|
||||
float Flow::spacing(const Flow &other) const
|
||||
{
|
||||
assert(this->height == other.height);
|
||||
assert(this->bridge == other.bridge);
|
||||
float res = float(this->bridge ?
|
||||
0.5 * this->width + 0.5 * other.width + BRIDGE_EXTRA_SPACING :
|
||||
assert(m_height == other.m_height);
|
||||
assert(m_bridge == other.m_bridge);
|
||||
float res = float(m_bridge ?
|
||||
0.5 * m_width + 0.5 * other.m_width + BRIDGE_EXTRA_SPACING :
|
||||
0.5 * this->spacing() + 0.5 * other.spacing());
|
||||
// assert(res > 0.f);
|
||||
if (res <= 0.f)
|
||||
@ -203,11 +199,11 @@ float Flow::spacing(const Flow &other) const
|
||||
// This method returns extrusion volume per head move unit.
|
||||
double Flow::mm3_per_mm() const
|
||||
{
|
||||
float res = this->bridge ?
|
||||
float res = m_bridge ?
|
||||
// Area of a circle with dmr of this->width.
|
||||
float((this->width * this->width) * 0.25 * PI) :
|
||||
float((m_width * m_width) * 0.25 * PI) :
|
||||
// Rectangle with semicircles at the ends. ~ h (w - 0.215 h)
|
||||
float(this->height * (this->width - this->height * (1. - 0.25 * PI)));
|
||||
float(m_height * (m_width - m_height * (1. - 0.25 * PI)));
|
||||
//assert(res > 0.);
|
||||
if (res <= 0.)
|
||||
throw FlowErrorNegativeFlow();
|
||||
@ -222,9 +218,7 @@ Flow support_material_flow(const PrintObject *object, float layer_height)
|
||||
(object->config().support_material_extrusion_width.value > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
|
||||
// if object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
|
||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)),
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value),
|
||||
// bridge_flow_ratio
|
||||
0.f);
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
|
||||
}
|
||||
|
||||
Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height)
|
||||
@ -235,9 +229,7 @@ Flow support_material_1st_layer_flow(const PrintObject *object, float layer_heig
|
||||
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
||||
(width.value > 0) ? width : object->config().extrusion_width,
|
||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)),
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().first_layer_height.get_abs_value(object->config().layer_height.value)),
|
||||
// bridge_flow_ratio
|
||||
0.f);
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().first_layer_height.get_abs_value(object->config().layer_height.value)));
|
||||
}
|
||||
|
||||
Flow support_material_interface_flow(const PrintObject *object, float layer_height)
|
||||
@ -248,9 +240,7 @@ Flow support_material_interface_flow(const PrintObject *object, float layer_heig
|
||||
(object->config().support_material_extrusion_width > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
|
||||
// if object->config().support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
|
||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_interface_extruder-1)),
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value),
|
||||
// bridge_flow_ratio
|
||||
0.f);
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,11 +13,6 @@ class PrintObject;
|
||||
// Extra spacing of bridge threads, in mm.
|
||||
#define BRIDGE_EXTRA_SPACING 0.05
|
||||
|
||||
// Overlap factor of perimeter lines. Currently no overlap.
|
||||
#ifdef HAS_PERIMETER_LINE_OVERLAP
|
||||
#define PERIMETER_LINE_OVERLAP_FACTOR 1.0
|
||||
#endif
|
||||
|
||||
enum FlowRole {
|
||||
frExternalPerimeter,
|
||||
frPerimeter,
|
||||
@ -58,22 +53,22 @@ class Flow
|
||||
public:
|
||||
// Non bridging flow: Maximum width of an extrusion with semicircles at the ends.
|
||||
// Bridging flow: Bridge thread diameter.
|
||||
float width;
|
||||
float width() const { return m_width; }
|
||||
// Non bridging flow: Layer height.
|
||||
// Bridging flow: Bridge thread diameter = layer height.
|
||||
float height;
|
||||
float height() const { return m_height; }
|
||||
// Nozzle diameter.
|
||||
float nozzle_diameter;
|
||||
float nozzle_diameter() const { return m_nozzle_diameter; }
|
||||
// Is it a bridge?
|
||||
bool bridge;
|
||||
bool bridge() const { return m_bridge; }
|
||||
|
||||
Flow(float _w, float _h, float _nd, bool _bridge = false) :
|
||||
width(_w), height(_h), nozzle_diameter(_nd), bridge(_bridge) {}
|
||||
Flow() = default;
|
||||
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_(this->width)); }
|
||||
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))); }
|
||||
|
||||
@ -83,13 +78,20 @@ public:
|
||||
// Here an overlap of 0.2x external perimeter spacing is allowed for by the elephant foot compensation.
|
||||
coord_t scaled_elephant_foot_spacing() const { return coord_t(0.5f * float(this->scaled_width() + 0.6f * this->scaled_spacing())); }
|
||||
|
||||
bool operator==(const Flow &rhs) const { return this->width == rhs.width && this->height == rhs.height && this->nozzle_diameter == rhs.nozzle_diameter && this->bridge == rhs.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_height(float height) const { assert(! m_bridge); return Flow(m_width, height, m_nozzle_diameter, m_bridge); }
|
||||
|
||||
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, float bridge_flow_ratio);
|
||||
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
|
||||
// to fit a region with integer number of lines.
|
||||
static Flow new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge);
|
||||
static Flow new_from_spacing(float spacing, float nozzle_diameter, float height);
|
||||
|
||||
// Sane extrusion width defautl based on nozzle diameter.
|
||||
// The defaults were derived from manual Prusa MK3 profiles.
|
||||
@ -100,6 +102,14 @@ public:
|
||||
// on active extruder etc. Therefore the value calculated by this function shall be used as a hint only.
|
||||
static double extrusion_width(const std::string &opt_key, const ConfigOptionFloatOrPercent *opt, 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:
|
||||
Flow(float w, float h, float nozzle_diameter, bool bridge) : m_width(w), m_height(h), m_nozzle_diameter(nozzle_diameter), m_bridge(bridge) {}
|
||||
|
||||
float m_width { 0 };
|
||||
float m_height { 0 };
|
||||
float m_nozzle_diameter { 0 };
|
||||
bool m_bridge { false };
|
||||
};
|
||||
|
||||
extern Flow support_material_flow(const PrintObject *object, float layer_height = 0.f);
|
||||
|
@ -1105,15 +1105,15 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
||||
const double layer_height = first_object->config().layer_height.value;
|
||||
const double first_layer_height = first_object->config().first_layer_height.get_abs_value(layer_height);
|
||||
for (const PrintRegion* region : print.regions()) {
|
||||
_write_format(file, "; external perimeters extrusion width = %.2fmm\n", region->flow(frExternalPerimeter, layer_height, false, false, -1., *first_object).width);
|
||||
_write_format(file, "; perimeters extrusion width = %.2fmm\n", region->flow(frPerimeter, layer_height, false, false, -1., *first_object).width);
|
||||
_write_format(file, "; infill extrusion width = %.2fmm\n", region->flow(frInfill, layer_height, false, false, -1., *first_object).width);
|
||||
_write_format(file, "; solid infill extrusion width = %.2fmm\n", region->flow(frSolidInfill, layer_height, false, false, -1., *first_object).width);
|
||||
_write_format(file, "; top infill extrusion width = %.2fmm\n", region->flow(frTopSolidInfill, layer_height, false, false, -1., *first_object).width);
|
||||
_write_format(file, "; external perimeters extrusion width = %.2fmm\n", region->flow(*first_object, frExternalPerimeter, layer_height).width());
|
||||
_write_format(file, "; perimeters extrusion width = %.2fmm\n", region->flow(*first_object, frPerimeter, layer_height).width());
|
||||
_write_format(file, "; infill extrusion width = %.2fmm\n", region->flow(*first_object, frInfill, layer_height).width());
|
||||
_write_format(file, "; solid infill extrusion width = %.2fmm\n", region->flow(*first_object, frSolidInfill, layer_height).width());
|
||||
_write_format(file, "; top infill extrusion width = %.2fmm\n", region->flow(*first_object, frTopSolidInfill, layer_height).width());
|
||||
if (print.has_support_material())
|
||||
_write_format(file, "; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width);
|
||||
_write_format(file, "; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width());
|
||||
if (print.config().first_layer_extrusion_width.value > 0)
|
||||
_write_format(file, "; first layer extrusion width = %.2fmm\n", region->flow(frPerimeter, first_layer_height, false, true, -1., *first_object).width);
|
||||
_write_format(file, "; first layer extrusion width = %.2fmm\n", region->flow(*first_object, frPerimeter, first_layer_height, true).width());
|
||||
_write_format(file, "\n");
|
||||
}
|
||||
print.throw_if_canceled();
|
||||
@ -2170,14 +2170,13 @@ void GCode::process_layer(
|
||||
const std::pair<size_t, size_t> loops = loops_it->second;
|
||||
this->set_origin(0., 0.);
|
||||
m_avoid_crossing_perimeters.use_external_mp();
|
||||
Flow layer_skirt_flow(print.skirt_flow());
|
||||
layer_skirt_flow.height = float(m_skirt_done.back() - (m_skirt_done.size() == 1 ? 0. : m_skirt_done[m_skirt_done.size() - 2]));
|
||||
Flow layer_skirt_flow = print.skirt_flow().with_height(float(m_skirt_done.back() - (m_skirt_done.size() == 1 ? 0. : m_skirt_done[m_skirt_done.size() - 2])));
|
||||
double mm3_per_mm = layer_skirt_flow.mm3_per_mm();
|
||||
for (size_t i = loops.first; i < loops.second; ++i) {
|
||||
// Adjust flow according to this layer's layer height.
|
||||
ExtrusionLoop loop = *dynamic_cast<const ExtrusionLoop*>(print.skirt().entities[i]);
|
||||
for (ExtrusionPath &path : loop.paths) {
|
||||
path.height = layer_skirt_flow.height;
|
||||
path.height = layer_skirt_flow.height();
|
||||
path.mm3_per_mm = mm3_per_mm;
|
||||
}
|
||||
//FIXME using the support_material_speed of the 1st object printed.
|
||||
|
@ -59,7 +59,9 @@ public:
|
||||
// (this collection contains only ExtrusionEntityCollection objects)
|
||||
ExtrusionEntityCollection fills;
|
||||
|
||||
Flow flow(FlowRole role, bool bridge = false, double width = -1) const;
|
||||
Flow flow(FlowRole role) const;
|
||||
Flow bridging_flow(FlowRole role) const;
|
||||
|
||||
void slices_to_fill_surfaces_clipped();
|
||||
void prepare_fill_surfaces();
|
||||
void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces);
|
||||
|
@ -15,16 +15,14 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
Flow LayerRegion::flow(FlowRole role, bool bridge, double width) const
|
||||
Flow LayerRegion::flow(FlowRole role) const
|
||||
{
|
||||
return m_region->flow(
|
||||
role,
|
||||
m_layer->height,
|
||||
bridge,
|
||||
m_layer->id() == 0,
|
||||
width,
|
||||
*m_layer->object()
|
||||
);
|
||||
return m_region->flow(*m_layer->object(), role, m_layer->height, m_layer->id() == 0);
|
||||
}
|
||||
|
||||
Flow LayerRegion::bridging_flow(FlowRole role) const
|
||||
{
|
||||
return this->layer()->object()->config().thick_bridges ? m_region->bridging_flow(role) : this->flow(role);
|
||||
}
|
||||
|
||||
// Fill in layerm->fill_surfaces by trimming the layerm->slices by the cummulative layerm->fill_surfaces.
|
||||
@ -84,7 +82,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
|
||||
|
||||
g.layer_id = (int)this->layer()->id();
|
||||
g.ext_perimeter_flow = this->flow(frExternalPerimeter);
|
||||
g.overhang_flow = this->region()->flow(frPerimeter, -1, true, false, -1, *this->layer()->object());
|
||||
g.overhang_flow = this->bridging_flow(frPerimeter);
|
||||
g.solid_infill_flow = this->flow(frSolidInfill);
|
||||
|
||||
g.process();
|
||||
@ -266,11 +264,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
|
||||
// would get merged into a single one while they need different directions
|
||||
// also, supply the original expolygon instead of the grown one, because in case
|
||||
// of very thin (but still working) anchors, the grown expolygon would go beyond them
|
||||
BridgeDetector bd(
|
||||
initial,
|
||||
lower_layer->lslices,
|
||||
this->flow(frInfill, true).scaled_width()
|
||||
);
|
||||
BridgeDetector bd(initial, lower_layer->lslices, this->bridging_flow(frInfill).scaled_width());
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf("Processing bridge at layer %zu:\n", this->layer()->id());
|
||||
#endif
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
static ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_polyline, ExtrusionRole role, Flow &flow, const float tolerance)
|
||||
static ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, const float tolerance)
|
||||
{
|
||||
ExtrusionPaths paths;
|
||||
ExtrusionPath path(role);
|
||||
@ -62,15 +62,15 @@ static ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thi
|
||||
path.polyline.append(line.b);
|
||||
// Convert from spacing to extrusion width based on the extrusion model
|
||||
// of a square extrusion ended with semi circles.
|
||||
flow.width = unscale<float>(w) + flow.height * float(1. - 0.25 * PI);
|
||||
Flow new_flow = flow.with_width(unscale<float>(w) + flow.height() * float(1. - 0.25 * PI));
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf(" filling %f gap\n", flow.width);
|
||||
#endif
|
||||
path.mm3_per_mm = flow.mm3_per_mm();
|
||||
path.width = flow.width;
|
||||
path.height = flow.height;
|
||||
path.mm3_per_mm = new_flow.mm3_per_mm();
|
||||
path.width = new_flow.width();
|
||||
path.height = new_flow.height();
|
||||
} else {
|
||||
thickness_delta = fabs(scale_(flow.width) - w);
|
||||
thickness_delta = fabs(scale_(flow.width()) - w);
|
||||
if (thickness_delta <= tolerance) {
|
||||
// the width difference between this line and the current flow width is
|
||||
// within the accepted tolerance
|
||||
@ -88,7 +88,7 @@ static ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thi
|
||||
return paths;
|
||||
}
|
||||
|
||||
static void variable_width(const ThickPolylines& polylines, ExtrusionRole role, Flow flow, std::vector<ExtrusionEntity*> &out)
|
||||
static void variable_width(const ThickPolylines& polylines, ExtrusionRole role, const Flow &flow, std::vector<ExtrusionEntity*> &out)
|
||||
{
|
||||
// This value determines granularity of adaptive width, as G-code does not allow
|
||||
// variable extrusion within a single move; this value shall only affect the amount
|
||||
@ -205,8 +205,8 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
||||
paths,
|
||||
intersection_pl({ polygon }, perimeter_generator.lower_slices_polygons()),
|
||||
role,
|
||||
is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm(),
|
||||
is_external ? perimeter_generator.ext_perimeter_flow.width : perimeter_generator.perimeter_flow.width,
|
||||
is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm(),
|
||||
is_external ? perimeter_generator.ext_perimeter_flow.width() : perimeter_generator.perimeter_flow.width(),
|
||||
(float)perimeter_generator.layer_height);
|
||||
|
||||
// get overhang paths by checking what parts of this loop fall
|
||||
@ -217,8 +217,8 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
||||
diff_pl({ polygon }, perimeter_generator.lower_slices_polygons()),
|
||||
erOverhangPerimeter,
|
||||
perimeter_generator.mm3_per_mm_overhang(),
|
||||
perimeter_generator.overhang_flow.width,
|
||||
perimeter_generator.overhang_flow.height);
|
||||
perimeter_generator.overhang_flow.width(),
|
||||
perimeter_generator.overhang_flow.height());
|
||||
|
||||
// Reapply the nearest point search for starting point.
|
||||
// We allow polyline reversal because Clipper may have randomly reversed polylines during clipping.
|
||||
@ -226,8 +226,8 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
||||
} else {
|
||||
ExtrusionPath path(role);
|
||||
path.polyline = polygon.split_at_first_point();
|
||||
path.mm3_per_mm = is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm();
|
||||
path.width = is_external ? perimeter_generator.ext_perimeter_flow.width : perimeter_generator.perimeter_flow.width;
|
||||
path.mm3_per_mm = is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm();
|
||||
path.width = is_external ? perimeter_generator.ext_perimeter_flow.width() : perimeter_generator.perimeter_flow.width();
|
||||
path.height = (float)perimeter_generator.layer_height;
|
||||
paths.push_back(path);
|
||||
}
|
||||
@ -346,7 +346,7 @@ void PerimeterGenerator::process()
|
||||
if (this->config->thin_walls) {
|
||||
// the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width
|
||||
// (actually, something larger than that still may exist due to mitering or other causes)
|
||||
coord_t min_width = coord_t(scale_(this->ext_perimeter_flow.nozzle_diameter / 3));
|
||||
coord_t min_width = coord_t(scale_(this->ext_perimeter_flow.nozzle_diameter() / 3));
|
||||
ExPolygons expp = offset2_ex(
|
||||
// medial axis requires non-overlapping geometry
|
||||
diff_ex(to_polygons(last),
|
||||
|
@ -430,7 +430,7 @@ const std::vector<std::string>& Preset::print_options()
|
||||
"support_material_pattern", "support_material_with_sheath", "support_material_spacing",
|
||||
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers",
|
||||
"support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_contact_distance",
|
||||
"support_material_buildplate_only", "dont_support_bridges", "notes", "complete_objects", "extruder_clearance_radius",
|
||||
"support_material_buildplate_only", "dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius",
|
||||
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder",
|
||||
"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",
|
||||
|
@ -1577,9 +1577,7 @@ Flow Print::brim_flow() const
|
||||
frPerimeter,
|
||||
width,
|
||||
(float)m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1),
|
||||
(float)this->skirt_first_layer_height(),
|
||||
0
|
||||
);
|
||||
(float)this->skirt_first_layer_height());
|
||||
}
|
||||
|
||||
Flow Print::skirt_flow() const
|
||||
@ -1599,9 +1597,7 @@ Flow Print::skirt_flow() const
|
||||
frPerimeter,
|
||||
width,
|
||||
(float)m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1),
|
||||
(float)this->skirt_first_layer_height(),
|
||||
0
|
||||
);
|
||||
(float)this->skirt_first_layer_height());
|
||||
}
|
||||
|
||||
bool Print::has_support_material() const
|
||||
@ -1818,7 +1814,7 @@ void Print::_make_skirt()
|
||||
ExtrusionPath(
|
||||
erSkirt,
|
||||
(float)mm3_per_mm, // this will be overridden at G-code export time
|
||||
flow.width,
|
||||
flow.width(),
|
||||
(float)first_layer_height // this will be overridden at G-code export time
|
||||
)));
|
||||
eloop.paths.back().polyline = loop.split_at_first_point();
|
||||
|
@ -65,7 +65,8 @@ public:
|
||||
const PrintRegionConfig& config() const { return m_config; }
|
||||
// 1-based extruder identifier for this region and role.
|
||||
unsigned int extruder(FlowRole role) const;
|
||||
Flow flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) 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.
|
||||
coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const;
|
||||
// Average diameter of nozzles participating on extruding this region.
|
||||
|
@ -2415,6 +2415,13 @@ void PrintConfigDef::init_fff_params()
|
||||
def->max = max_temp;
|
||||
def->set_default_value(new ConfigOptionInts { 200 });
|
||||
|
||||
def = this->add("thick_bridges", coBool);
|
||||
def->label = L("Thick bridges");
|
||||
def->category = L("Layers and Perimeters");
|
||||
def->tooltip = L("Print bridges with round extrusions.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
def = this->add("thin_walls", coBool);
|
||||
def->label = L("Detect thin walls");
|
||||
def->category = L("Layers and Perimeters");
|
||||
|
@ -522,6 +522,7 @@ public:
|
||||
ConfigOptionInt support_material_threshold;
|
||||
ConfigOptionBool support_material_with_sheath;
|
||||
ConfigOptionFloatOrPercent support_material_xy_spacing;
|
||||
ConfigOptionBool thick_bridges;
|
||||
ConfigOptionFloat xy_size_compensation;
|
||||
ConfigOptionBool wipe_into_objects;
|
||||
|
||||
@ -569,6 +570,7 @@ protected:
|
||||
OPT_PTR(support_material_xy_spacing);
|
||||
OPT_PTR(support_material_threshold);
|
||||
OPT_PTR(support_material_with_sheath);
|
||||
OPT_PTR(thick_bridges);
|
||||
OPT_PTR(xy_size_compensation);
|
||||
OPT_PTR(wipe_into_objects);
|
||||
}
|
||||
|
@ -554,6 +554,7 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||
|| opt_key == "perimeter_extrusion_width"
|
||||
|| opt_key == "infill_overlap"
|
||||
|| opt_key == "thin_walls"
|
||||
|| opt_key == "thick_bridges"
|
||||
|| opt_key == "external_perimeters_first") {
|
||||
steps.emplace_back(posPerimeters);
|
||||
} else if (
|
||||
@ -1459,14 +1460,7 @@ void PrintObject::bridge_over_infill()
|
||||
if (region.config().fill_density.value == 100) continue;
|
||||
|
||||
// get bridge flow
|
||||
Flow bridge_flow = region.flow(
|
||||
frSolidInfill,
|
||||
-1, // layer height, not relevant for bridge flow
|
||||
true, // bridge
|
||||
false, // first layer
|
||||
-1, // custom width, not relevant for bridge flow
|
||||
*this
|
||||
);
|
||||
Flow bridge_flow = region.bridging_flow(frSolidInfill);
|
||||
|
||||
for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++ layer_it) {
|
||||
// skip first layer
|
||||
@ -1488,7 +1482,7 @@ void PrintObject::bridge_over_infill()
|
||||
Polygons to_bridge_pp = internal_solid;
|
||||
|
||||
// iterate through lower layers spanned by bridge_flow
|
||||
double bottom_z = layer->print_z - bridge_flow.height;
|
||||
double bottom_z = layer->print_z - bridge_flow.height();
|
||||
for (int i = int(layer_it - m_layers.begin()) - 1; i >= 0; --i) {
|
||||
const Layer* lower_layer = m_layers[i];
|
||||
|
||||
|
@ -18,31 +18,25 @@ unsigned int PrintRegion::extruder(FlowRole role) const
|
||||
return extruder;
|
||||
}
|
||||
|
||||
Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const
|
||||
Flow PrintRegion::flow(const PrintObject &object, FlowRole role, double layer_height, bool first_layer) const
|
||||
{
|
||||
ConfigOptionFloatOrPercent config_width;
|
||||
if (width != -1) {
|
||||
// use the supplied custom width, if any
|
||||
config_width.value = width;
|
||||
config_width.percent = false;
|
||||
// Get extrusion width from configuration.
|
||||
// (might be an absolute value, or a percent value, or zero for auto)
|
||||
if (first_layer && m_print->config().first_layer_extrusion_width.value > 0) {
|
||||
config_width = m_print->config().first_layer_extrusion_width;
|
||||
} else if (role == frExternalPerimeter) {
|
||||
config_width = m_config.external_perimeter_extrusion_width;
|
||||
} else if (role == frPerimeter) {
|
||||
config_width = m_config.perimeter_extrusion_width;
|
||||
} else if (role == frInfill) {
|
||||
config_width = m_config.infill_extrusion_width;
|
||||
} else if (role == frSolidInfill) {
|
||||
config_width = m_config.solid_infill_extrusion_width;
|
||||
} else if (role == frTopSolidInfill) {
|
||||
config_width = m_config.top_infill_extrusion_width;
|
||||
} else {
|
||||
// otherwise, get extrusion width from configuration
|
||||
// (might be an absolute value, or a percent value, or zero for auto)
|
||||
if (first_layer && m_print->config().first_layer_extrusion_width.value > 0) {
|
||||
config_width = m_print->config().first_layer_extrusion_width;
|
||||
} else if (role == frExternalPerimeter) {
|
||||
config_width = m_config.external_perimeter_extrusion_width;
|
||||
} else if (role == frPerimeter) {
|
||||
config_width = m_config.perimeter_extrusion_width;
|
||||
} else if (role == frInfill) {
|
||||
config_width = m_config.infill_extrusion_width;
|
||||
} else if (role == frSolidInfill) {
|
||||
config_width = m_config.solid_infill_extrusion_width;
|
||||
} else if (role == frTopSolidInfill) {
|
||||
config_width = m_config.top_infill_extrusion_width;
|
||||
} else {
|
||||
throw Slic3r::InvalidArgument("Unknown role");
|
||||
}
|
||||
throw Slic3r::InvalidArgument("Unknown role");
|
||||
}
|
||||
|
||||
if (config_width.value == 0)
|
||||
@ -50,8 +44,19 @@ Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool fir
|
||||
|
||||
// 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.
|
||||
double nozzle_diameter = m_print->config().nozzle_diameter.get_at(this->extruder(role) - 1);
|
||||
return Flow::new_from_config_width(role, config_width, (float)nozzle_diameter, (float)layer_height, bridge ? (float)m_config.bridge_flow_ratio : 0.0f);
|
||||
auto nozzle_diameter = float(m_print->config().nozzle_diameter.get_at(this->extruder(role) - 1));
|
||||
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
|
||||
|
@ -345,7 +345,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object
|
||||
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id)
|
||||
if (! object->region_volumes[region_id].empty())
|
||||
external_perimeter_width = std::max(external_perimeter_width,
|
||||
(coordf_t)object->print()->get_region(region_id)->flow(frExternalPerimeter, slicing_params.layer_height, false, false, -1, *object).width);
|
||||
(coordf_t)object->print()->get_region(region_id)->flow(*object, frExternalPerimeter, slicing_params.layer_height).width());
|
||||
m_gap_xy = m_object_config->support_material_xy_spacing.get_abs_value(external_perimeter_width);
|
||||
|
||||
m_can_merge_support_regions = m_object_config->support_material_extruder.value == m_object_config->support_material_interface_extruder.value;
|
||||
@ -1231,7 +1231,7 @@ namespace SupportMaterialInternal {
|
||||
// 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
|
||||
// are left in between
|
||||
Flow bridge_flow = layerm->flow(frPerimeter, true);
|
||||
Flow bridge_flow = layerm->bridging_flow(frPerimeter);
|
||||
float w = float(std::max(bridge_flow.scaled_width(), bridge_flow.scaled_spacing()));
|
||||
for (Polyline &polyline : overhang_perimeters)
|
||||
if (polyline.is_straight()) {
|
||||
@ -1542,16 +1542,20 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
||||
}
|
||||
}
|
||||
// Offset the contact polygons outside.
|
||||
#if 0
|
||||
for (size_t i = 0; i < NUM_MARGIN_STEPS; ++ i) {
|
||||
diff_polygons = diff(
|
||||
offset(
|
||||
diff_polygons,
|
||||
SUPPORT_MATERIAL_MARGIN / NUM_MARGIN_STEPS,
|
||||
scaled<float>(SUPPORT_MATERIAL_MARGIN / NUM_MARGIN_STEPS),
|
||||
ClipperLib::jtRound,
|
||||
// round mitter limit
|
||||
scale_(0.05)),
|
||||
slices_margin_cached);
|
||||
}
|
||||
#else
|
||||
diff_polygons = diff(diff_polygons, slices_margin_cached);
|
||||
#endif
|
||||
}
|
||||
polygons_append(contact_polygons, diff_polygons);
|
||||
} // for each layer.region
|
||||
@ -1597,7 +1601,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
||||
|
||||
// Contact layer will be printed with a normal flow, but
|
||||
// it will support layers printed with a bridging flow.
|
||||
if (SupportMaterialInternal::has_bridging_extrusions(layer)) {
|
||||
if (m_object_config->thick_bridges && SupportMaterialInternal::has_bridging_extrusions(layer)) {
|
||||
coordf_t bridging_height = 0.;
|
||||
for (const LayerRegion *region : layer.regions())
|
||||
bridging_height += region->region()->bridging_height_avg(*m_print_config);
|
||||
@ -1879,12 +1883,14 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
|
||||
//FIXME Check whether the bottom bridging surfaces are extruded correctly (no bridging flow correction applied?)
|
||||
// According to Jindrich the bottom surfaces work well.
|
||||
//FIXME test the bridging flow instead?
|
||||
m_support_material_interface_flow.nozzle_diameter;
|
||||
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.print_z + layer_new.height + m_object_config->support_material_contact_distance.value;
|
||||
layer_new.bottom_z = layer.print_z;
|
||||
layer_new.idx_object_layer_below = layer_id;
|
||||
layer_new.bridging = ! m_slicing_params.soluble_interface;
|
||||
layer_new.bridging = ! m_slicing_params.soluble_interface && m_object_config->thick_bridges;
|
||||
//FIXME how much to inflate the bottom surface, as it is being extruded with a bridging flow? The following line uses a normal flow.
|
||||
//FIXME why is the offset positive? It will be trimmed by the object later on anyway, but then it just wastes CPU clocks.
|
||||
layer_new.polygons = offset(touching, float(m_support_material_flow.scaled_width()), SUPPORT_SURFACES_OFFSET_PARAMETERS);
|
||||
@ -2512,7 +2518,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
|
||||
break;
|
||||
polygons_append(polygons_trimming, offset(object_layer.lslices, gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||
}
|
||||
if (! m_slicing_params.soluble_interface) {
|
||||
if (! m_slicing_params.soluble_interface && m_object_config->thick_bridges) {
|
||||
// Collect all bottom surfaces, which will be extruded with a bridging flow.
|
||||
for (; i < object.layers().size(); ++ i) {
|
||||
const Layer &object_layer = *object.layers()[i];
|
||||
@ -2810,7 +2816,7 @@ std::pair<PrintObjectSupportMaterial::MyLayersPtr, PrintObjectSupportMaterial::M
|
||||
// Compress contact_out, remove the nullptr items.
|
||||
remove_nulls(interface_layers);
|
||||
remove_nulls(base_interface_layers);
|
||||
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - start";
|
||||
BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_interface_layers() in parallel - end";
|
||||
}
|
||||
|
||||
return base_and_interface_layers;
|
||||
@ -2835,7 +2841,7 @@ static inline void fill_expolygon_generate_paths(
|
||||
dst,
|
||||
std::move(polylines),
|
||||
role,
|
||||
flow.mm3_per_mm(), flow.width, flow.height);
|
||||
flow.mm3_per_mm(), flow.width(), flow.height());
|
||||
}
|
||||
|
||||
static inline void fill_expolygons_generate_paths(
|
||||
@ -2903,7 +2909,7 @@ static inline void fill_expolygons_with_sheath_generate_paths(
|
||||
pl.clip_end(clip_length);
|
||||
polylines.emplace_back(std::move(pl));
|
||||
}
|
||||
extrusion_entities_append_paths(eec->entities, polylines, erSupportMaterial, flow.mm3_per_mm(), flow.width, flow.height);
|
||||
extrusion_entities_append_paths(eec->entities, polylines, erSupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height());
|
||||
// Fill in the rest.
|
||||
fill_expolygons_generate_paths(eec->entities, offset_ex(expoly, float(-0.4 * spacing)), filler, fill_params, density, role, flow);
|
||||
dst.emplace_back(eec.release());
|
||||
@ -3011,8 +3017,7 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const
|
||||
if (n_contact_loops == 0 || top_contact_layer.empty())
|
||||
return;
|
||||
|
||||
Flow flow = interface_flow_src;
|
||||
flow.height = float(top_contact_layer.layer->height);
|
||||
Flow flow = interface_flow_src.with_height(top_contact_layer.layer->height);
|
||||
|
||||
Polygons overhang_polygons;
|
||||
if (top_contact_layer.layer->overhang_polygons != nullptr)
|
||||
@ -3209,7 +3214,7 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const
|
||||
extrusion_entities_append_paths(
|
||||
top_contact_layer.extrusions,
|
||||
std::move(loop_lines),
|
||||
erSupportMaterialInterface, flow.mm3_per_mm(), flow.width, flow.height);
|
||||
erSupportMaterialInterface, flow.mm3_per_mm(), flow.width(), flow.height());
|
||||
}
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
@ -3342,7 +3347,7 @@ void modulate_extrusion_by_overlapping_layers(
|
||||
// Adjust the extrusion parameters for a reduced layer height and a non-bridging flow (nozzle_dmr = -1, does not matter).
|
||||
assert(this_layer.print_z > overlapping_layer.print_z);
|
||||
frag.height = float(this_layer.print_z - overlapping_layer.print_z);
|
||||
frag.mm3_per_mm = Flow(frag.width, frag.height, -1.f, false).mm3_per_mm();
|
||||
frag.mm3_per_mm = Flow(frag.width, frag.height, -1.f).mm3_per_mm();
|
||||
#ifdef SLIC3R_DEBUG
|
||||
svg.draw(frag.polylines, dbg_index_to_color(i_overlapping_layer), scale_(0.1));
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
@ -3565,7 +3570,8 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
||||
//FIXME misusing contact_polygons for support columns.
|
||||
((raft_layer.contact_polygons == nullptr) ? Polygons() : *raft_layer.contact_polygons);
|
||||
if (! to_infill_polygons.empty()) {
|
||||
Flow flow(float(m_support_material_flow.width), float(raft_layer.height), m_support_material_flow.nozzle_diameter, raft_layer.bridging);
|
||||
assert(! raft_layer.bridging);
|
||||
Flow flow(float(m_support_material_flow.width()), float(raft_layer.height), m_support_material_flow.nozzle_diameter());
|
||||
Fill * filler = filler_support.get();
|
||||
filler->angle = raft_angle_base;
|
||||
filler->spacing = m_support_material_flow.spacing();
|
||||
@ -3596,7 +3602,8 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
||||
// We don't use $base_flow->spacing because we need a constant spacing
|
||||
// value that guarantees that all layers are correctly aligned.
|
||||
filler->spacing = m_support_material_flow.spacing();
|
||||
flow = Flow(float(m_support_material_interface_flow.width), float(raft_layer.height), m_support_material_flow.nozzle_diameter, raft_layer.bridging);
|
||||
assert(! raft_layer.bridging);
|
||||
flow = Flow(float(m_support_material_interface_flow.width()), float(raft_layer.height), m_support_material_flow.nozzle_diameter());
|
||||
density = float(interface_density);
|
||||
} else
|
||||
continue;
|
||||
@ -3734,11 +3741,10 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
||||
bool interface_as_base = (&layer_ex == &interface_layer) && m_object_config->support_material_interface_layers.value == 0;
|
||||
//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)
|
||||
Flow interface_flow(
|
||||
float(layer_ex.layer->bridging ? layer_ex.layer->height : (interface_as_base ? m_support_material_flow.width : m_support_material_interface_flow.width)),
|
||||
float(layer_ex.layer->height),
|
||||
m_support_material_interface_flow.nozzle_diameter,
|
||||
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(interface_as_base ? m_support_material_flow.width() : m_support_material_interface_flow.width(),
|
||||
float(layer_ex.layer->height), m_support_material_interface_flow.nozzle_diameter());
|
||||
filler_interface->angle = interface_as_base ?
|
||||
// If zero interface layers are configured, use the same angle as for the base layers.
|
||||
angles[support_layer_id % angles.size()] :
|
||||
@ -3762,11 +3768,8 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
||||
Fill *filler = filler_base_interface.get();
|
||||
//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)
|
||||
Flow interface_flow(
|
||||
float(base_interface_layer.layer->bridging ? base_interface_layer.layer->height : m_support_material_flow.width), // m_support_material_interface_flow.width)),
|
||||
float(base_interface_layer.layer->height),
|
||||
m_support_material_flow.nozzle_diameter,
|
||||
base_interface_layer.layer->bridging);
|
||||
assert(! base_interface_layer.layer->bridging);
|
||||
Flow interface_flow = m_support_material_flow.with_height(float(base_interface_layer.layer->height));
|
||||
filler->angle = interface_angle;
|
||||
filler->spacing = m_support_material_interface_flow.spacing();
|
||||
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / interface_density));
|
||||
@ -3788,11 +3791,8 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
||||
filler->angle = angles[support_layer_id % angles.size()];
|
||||
// We don't use $base_flow->spacing because we need a constant spacing
|
||||
// value that guarantees that all layers are correctly aligned.
|
||||
Flow flow(
|
||||
float(base_layer.layer->bridging ? base_layer.layer->height : m_support_material_flow.width),
|
||||
float(base_layer.layer->height),
|
||||
m_support_material_flow.nozzle_diameter,
|
||||
base_layer.layer->bridging);
|
||||
assert(! base_layer.layer->bridging);
|
||||
auto flow = m_support_material_flow.with_height(float(base_layer.layer->height));
|
||||
filler->spacing = m_support_material_flow.spacing();
|
||||
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_density));
|
||||
float density = float(support_density);
|
||||
|
@ -148,74 +148,33 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
|
||||
speed_normal = first_layer_speed.get_abs_value(speed_normal);
|
||||
return (speed_normal > 0.) ? speed_normal : speed_max;
|
||||
};
|
||||
auto test_flow =
|
||||
[first_layer_extrusion_width_ptr, extrusion_width, nozzle_diameter, lh, bridging, bridge_speed, bridge_flow_ratio, limit_by_first_layer_speed, max_print_speed, &max_flow, &max_flow_extrusion_type]
|
||||
(FlowRole flow_role, const ConfigOptionFloatOrPercent &this_extrusion_width, double speed, const char *err_msg) {
|
||||
Flow flow = bridging ?
|
||||
Flow::new_from_config_width(flow_role, first_positive(first_layer_extrusion_width_ptr, this_extrusion_width, extrusion_width), nozzle_diameter, lh) :
|
||||
Flow::bridging_flow(nozzle_diameter * bridge_flow_ratio, nozzle_diameter);
|
||||
double volumetric_flow = flow.mm3_per_mm() * (bridging ? bridge_speed : limit_by_first_layer_speed(speed, max_print_speed));
|
||||
if (max_flow < volumetric_flow) {
|
||||
max_flow = volumetric_flow;
|
||||
max_flow_extrusion_type = _utf8(err_msg);
|
||||
}
|
||||
};
|
||||
if (perimeter_extruder_active) {
|
||||
double external_perimeter_rate = Flow::new_from_config_width(frExternalPerimeter,
|
||||
first_positive(first_layer_extrusion_width_ptr, external_perimeter_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() *
|
||||
(bridging ? bridge_speed :
|
||||
limit_by_first_layer_speed(std::max(external_perimeter_speed, small_perimeter_speed), max_print_speed));
|
||||
if (max_flow < external_perimeter_rate) {
|
||||
max_flow = external_perimeter_rate;
|
||||
max_flow_extrusion_type = _utf8(L("external perimeters"));
|
||||
}
|
||||
double perimeter_rate = Flow::new_from_config_width(frPerimeter,
|
||||
first_positive(first_layer_extrusion_width_ptr, perimeter_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() *
|
||||
(bridging ? bridge_speed :
|
||||
limit_by_first_layer_speed(std::max(perimeter_speed, small_perimeter_speed), max_print_speed));
|
||||
if (max_flow < perimeter_rate) {
|
||||
max_flow = perimeter_rate;
|
||||
max_flow_extrusion_type = _utf8(L("perimeters"));
|
||||
}
|
||||
}
|
||||
if (! bridging && infill_extruder_active) {
|
||||
double infill_rate = Flow::new_from_config_width(frInfill,
|
||||
first_positive(first_layer_extrusion_width_ptr, infill_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() * limit_by_first_layer_speed(infill_speed, max_print_speed);
|
||||
if (max_flow < infill_rate) {
|
||||
max_flow = infill_rate;
|
||||
max_flow_extrusion_type = _utf8(L("infill"));
|
||||
}
|
||||
test_flow(frExternalPerimeter, external_perimeter_extrusion_width, std::max(external_perimeter_speed, small_perimeter_speed), L("external perimeters"));
|
||||
test_flow(frPerimeter, perimeter_extrusion_width, std::max(perimeter_speed, small_perimeter_speed), L("perimeters"));
|
||||
}
|
||||
if (! bridging && infill_extruder_active)
|
||||
test_flow(frInfill, infill_extrusion_width, infill_speed, L("infill"));
|
||||
if (solid_infill_extruder_active) {
|
||||
double solid_infill_rate = Flow::new_from_config_width(frInfill,
|
||||
first_positive(first_layer_extrusion_width_ptr, solid_infill_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, 0).mm3_per_mm() *
|
||||
(bridging ? bridge_speed : limit_by_first_layer_speed(solid_infill_speed, max_print_speed));
|
||||
if (max_flow < solid_infill_rate) {
|
||||
max_flow = solid_infill_rate;
|
||||
max_flow_extrusion_type = _utf8(L("solid infill"));
|
||||
}
|
||||
if (! bridging) {
|
||||
double top_solid_infill_rate = Flow::new_from_config_width(frInfill,
|
||||
first_positive(first_layer_extrusion_width_ptr, top_infill_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() * limit_by_first_layer_speed(top_solid_infill_speed, max_print_speed);
|
||||
if (max_flow < top_solid_infill_rate) {
|
||||
max_flow = top_solid_infill_rate;
|
||||
max_flow_extrusion_type = _utf8(L("top solid infill"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (support_material_extruder_active) {
|
||||
double support_material_rate = Flow::new_from_config_width(frSupportMaterial,
|
||||
first_positive(first_layer_extrusion_width_ptr, support_material_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() *
|
||||
(bridging ? bridge_speed : limit_by_first_layer_speed(support_material_speed, max_print_speed));
|
||||
if (max_flow < support_material_rate) {
|
||||
max_flow = support_material_rate;
|
||||
max_flow_extrusion_type = _utf8(L("support"));
|
||||
}
|
||||
}
|
||||
if (support_material_interface_extruder_active) {
|
||||
double support_material_interface_rate = Flow::new_from_config_width(frSupportMaterialInterface,
|
||||
first_positive(first_layer_extrusion_width_ptr, support_material_extrusion_width, extrusion_width),
|
||||
nozzle_diameter, lh, bfr).mm3_per_mm() *
|
||||
(bridging ? bridge_speed : limit_by_first_layer_speed(support_material_interface_speed, max_print_speed));
|
||||
if (max_flow < support_material_interface_rate) {
|
||||
max_flow = support_material_interface_rate;
|
||||
max_flow_extrusion_type = _utf8(L("support interface"));
|
||||
}
|
||||
test_flow(frInfill, solid_infill_extrusion_width, solid_infill_speed, L("solid infill"));
|
||||
if (! bridging)
|
||||
test_flow(frInfill, top_infill_extrusion_width, top_solid_infill_speed, L("top solid infill"));
|
||||
}
|
||||
if (! bridging && support_material_extruder_active)
|
||||
test_flow(frSupportMaterial, support_material_extrusion_width, support_material_speed, L("support"));
|
||||
if (support_material_interface_extruder_active)
|
||||
test_flow(frSupportMaterialInterface, support_material_extrusion_width, support_material_interface_speed, L("support interface"));
|
||||
//FIXME handle gap_fill_speed
|
||||
if (! out.empty())
|
||||
out += "\n";
|
||||
@ -254,11 +213,11 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre
|
||||
Flow external_perimeter_flow = Flow::new_from_config_width(
|
||||
frExternalPerimeter,
|
||||
*print_config.opt<ConfigOptionFloatOrPercent>("external_perimeter_extrusion_width"),
|
||||
nozzle_diameter, layer_height, false);
|
||||
nozzle_diameter, layer_height);
|
||||
Flow perimeter_flow = Flow::new_from_config_width(
|
||||
frPerimeter,
|
||||
*print_config.opt<ConfigOptionFloatOrPercent>("perimeter_extrusion_width"),
|
||||
nozzle_diameter, layer_height, false);
|
||||
nozzle_diameter, layer_height);
|
||||
|
||||
|
||||
if (num_perimeters > 0) {
|
||||
@ -266,7 +225,7 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre
|
||||
out += (boost::format(_utf8(L("Recommended object thin wall thickness for layer height %.2f and"))) % layer_height).str() + " ";
|
||||
// Start with the width of two closely spaced
|
||||
try {
|
||||
double width = external_perimeter_flow.width + external_perimeter_flow.spacing();
|
||||
double width = external_perimeter_flow.width() + external_perimeter_flow.spacing();
|
||||
for (int i = 2; i <= num_lines; thin_walls ? ++ i : i += 2) {
|
||||
if (i > 2)
|
||||
out += ", ";
|
||||
|
@ -1433,6 +1433,7 @@ void TabPrint::build()
|
||||
optgroup->append_single_option_line("avoid_crossing_perimeters", category_path + "avoid-crossing-perimeters");
|
||||
optgroup->append_single_option_line("avoid_crossing_perimeters_max_detour", category_path + "avoid_crossing_perimeters_max_detour");
|
||||
optgroup->append_single_option_line("thin_walls", category_path + "detect-thin-walls");
|
||||
optgroup->append_single_option_line("thick_bridges", category_path + "thick_bridges");
|
||||
optgroup->append_single_option_line("overhangs", category_path + "detect-bridging-perimeters");
|
||||
|
||||
optgroup = page->new_optgroup(L("Advanced"));
|
||||
|
@ -143,7 +143,7 @@ SCENARIO("Flow: Flow math for non-bridges", "[Flow]") {
|
||||
GIVEN("Input spacing of 0.414159 and a total width of 2") {
|
||||
double in_spacing = 0.414159;
|
||||
double total_width = 2.0;
|
||||
auto flow = Flow::new_from_spacing(1.0, 0.4, 0.3, false);
|
||||
auto flow = Flow::new_from_spacing(1.0, 0.4, 0.3);
|
||||
WHEN("solid_spacing() is called") {
|
||||
double result = flow.solid_spacing(total_width, in_spacing);
|
||||
THEN("Yielded spacing is greater than 0") {
|
||||
|
Loading…
Reference in New Issue
Block a user