refactoring overhang speed
This commit is contained in:
parent
3714943b49
commit
f730fd21d4
@ -851,7 +851,6 @@ namespace DoExport {
|
|||||||
if (region.config().get_abs_value("perimeter_speed") == 0 ||
|
if (region.config().get_abs_value("perimeter_speed") == 0 ||
|
||||||
region.config().get_abs_value("small_perimeter_speed") == 0 ||
|
region.config().get_abs_value("small_perimeter_speed") == 0 ||
|
||||||
region.config().get_abs_value("external_perimeter_speed") == 0 ||
|
region.config().get_abs_value("external_perimeter_speed") == 0 ||
|
||||||
region.config().get_abs_value("overhang_speed") == 0 ||
|
|
||||||
region.config().get_abs_value("bridge_speed") == 0)
|
region.config().get_abs_value("bridge_speed") == 0)
|
||||||
mm3_per_mm.push_back(layerm->perimeters().min_mm3_per_mm());
|
mm3_per_mm.push_back(layerm->perimeters().min_mm3_per_mm());
|
||||||
if (region.config().get_abs_value("infill_speed") == 0 ||
|
if (region.config().get_abs_value("infill_speed") == 0 ||
|
||||||
@ -2877,9 +2876,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
|||||||
speed = m_config.get_abs_value("perimeter_speed");
|
speed = m_config.get_abs_value("perimeter_speed");
|
||||||
} else if (path.role() == erExternalPerimeter) {
|
} else if (path.role() == erExternalPerimeter) {
|
||||||
speed = m_config.get_abs_value("external_perimeter_speed");
|
speed = m_config.get_abs_value("external_perimeter_speed");
|
||||||
}else if (path.role() == erOverhangPerimeter){
|
} else if (path.role() == erOverhangPerimeter || path.role() == erBridgeInfill) {
|
||||||
speed = m_config.get_abs_value("overhang_speed");
|
|
||||||
} else if (path.role() == erBridgeInfill) {
|
|
||||||
speed = m_config.get_abs_value("bridge_speed");
|
speed = m_config.get_abs_value("bridge_speed");
|
||||||
} else if (path.role() == erInternalInfill) {
|
} else if (path.role() == erInternalInfill) {
|
||||||
speed = m_config.get_abs_value("infill_speed");
|
speed = m_config.get_abs_value("infill_speed");
|
||||||
@ -2918,9 +2915,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
|||||||
|
|
||||||
bool variable_speed = false;
|
bool variable_speed = false;
|
||||||
std::vector<ProcessedPoint> new_points{};
|
std::vector<ProcessedPoint> new_points{};
|
||||||
if (this->m_config.overhangs && !this->on_first_layer() && is_perimeter(path.role())) {
|
if (this->m_config.enable_dynamic_overhang_speeds && !this->on_first_layer() && is_perimeter(path.role())) {
|
||||||
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path);
|
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, m_config.overhang_overlaps,
|
||||||
variable_speed = std::any_of(new_points.begin(), new_points.end(), [](const ProcessedPoint &p) { return p.speed_factor != 1.0; });
|
m_config.dynamic_overhang_speeds,
|
||||||
|
m_config.get_abs_value("external_perimeter_speed"), speed);
|
||||||
|
variable_speed = std::any_of(new_points.begin(), new_points.end(), [speed](const ProcessedPoint &p) { return p.speed != speed; });
|
||||||
}
|
}
|
||||||
|
|
||||||
double F = speed * 60; // convert mm/sec to mm/min
|
double F = speed * 60; // convert mm/sec to mm/min
|
||||||
@ -2987,7 +2986,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
|||||||
if (!variable_speed) {
|
if (!variable_speed) {
|
||||||
// F is mm per minute.
|
// F is mm per minute.
|
||||||
gcode += m_writer.set_speed(F, "", comment);
|
gcode += m_writer.set_speed(F, "", comment);
|
||||||
double path_length = 0.;
|
double path_length = 0.;
|
||||||
std::string comment;
|
std::string comment;
|
||||||
if (m_config.gcode_comments) {
|
if (m_config.gcode_comments) {
|
||||||
comment = description;
|
comment = description;
|
||||||
@ -2996,30 +2995,29 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
|||||||
Vec2d prev = this->point_to_gcode_quantized(path.polyline.points.front());
|
Vec2d prev = this->point_to_gcode_quantized(path.polyline.points.front());
|
||||||
auto it = path.polyline.points.begin();
|
auto it = path.polyline.points.begin();
|
||||||
auto end = path.polyline.points.end();
|
auto end = path.polyline.points.end();
|
||||||
for (++it; it != end; ++it) {
|
for (++ it; it != end; ++ it) {
|
||||||
Vec2d p = this->point_to_gcode_quantized(*it);
|
Vec2d p = this->point_to_gcode_quantized(*it);
|
||||||
const double line_length = (p - prev).norm();
|
const double line_length = (p - prev).norm();
|
||||||
path_length += line_length;
|
path_length += line_length;
|
||||||
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
|
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
|
||||||
prev = p;
|
prev = p;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
double overhang_speed = m_config.get_abs_value("overhang_speed");
|
|
||||||
std::string comment;
|
std::string comment;
|
||||||
if (m_config.gcode_comments) {
|
if (m_config.gcode_comments) {
|
||||||
comment = description;
|
comment = description;
|
||||||
comment += description_bridge;
|
comment += description_bridge;
|
||||||
}
|
}
|
||||||
double last_set_speed = std::max(overhang_speed, new_points[0].speed_factor * speed) * 60.0;
|
double last_set_speed = new_points[0].speed * 60.0;
|
||||||
gcode += m_writer.set_speed(last_set_speed, "", comment);
|
gcode += m_writer.set_speed(last_set_speed, "", comment);
|
||||||
Vec2d prev = this->point_to_gcode_quantized(new_points[0].p);
|
Vec2d prev = this->point_to_gcode_quantized(new_points[0].p);
|
||||||
for (size_t i = 1; i < new_points.size(); i++) {
|
for (size_t i = 1; i < new_points.size(); i++) {
|
||||||
const ProcessedPoint& procesed_point = new_points[i];
|
const ProcessedPoint& processed_point = new_points[i];
|
||||||
Vec2d p = this->point_to_gcode_quantized(procesed_point.p);
|
Vec2d p = this->point_to_gcode_quantized(processed_point.p);
|
||||||
const double line_length = (p - prev).norm();
|
const double line_length = (p - prev).norm();
|
||||||
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
|
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment);
|
||||||
prev = p;
|
prev = p;
|
||||||
double new_speed = std::max(overhang_speed, procesed_point.speed_factor * speed) * 60.0;
|
double new_speed = processed_point.speed * 60.0;
|
||||||
if (last_set_speed != new_speed) {
|
if (last_set_speed != new_speed) {
|
||||||
gcode += m_writer.set_speed(new_speed, "", comment);
|
gcode += m_writer.set_speed(new_speed, "", comment);
|
||||||
last_set_speed = new_speed;
|
last_set_speed = new_speed;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "../Polygon.hpp"
|
#include "../Polygon.hpp"
|
||||||
#include "../ClipperUtils.hpp"
|
#include "../ClipperUtils.hpp"
|
||||||
#include "../Flow.hpp"
|
#include "../Flow.hpp"
|
||||||
|
#include "../Config.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@ -19,6 +20,7 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
@ -67,8 +69,8 @@ public:
|
|||||||
|
|
||||||
class CurvatureEstimator
|
class CurvatureEstimator
|
||||||
{
|
{
|
||||||
static const size_t sliders_count = 3;
|
static const size_t sliders_count = 2;
|
||||||
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{2.0}, {4.0}, {8.0}};
|
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{1.5}, {3.0}};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void add_point(float distance, float angle)
|
void add_point(float distance, float angle)
|
||||||
@ -189,7 +191,7 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
|
|||||||
struct ProcessedPoint
|
struct ProcessedPoint
|
||||||
{
|
{
|
||||||
Point p;
|
Point p;
|
||||||
float speed_factor = 1.0f;
|
float speed = 1.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExtrusionQualityEstimator
|
class ExtrusionQualityEstimator
|
||||||
@ -209,33 +211,53 @@ public:
|
|||||||
next_layer_boundaries[object] = AABBTreeLines::LinesDistancer<Linef>{to_unscaled_linesf(layer->lslices)};
|
next_layer_boundaries[object] = AABBTreeLines::LinesDistancer<Linef>{to_unscaled_linesf(layer->lslices)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ProcessedPoint> estimate_extrusion_quality(const ExtrusionPath &path)
|
std::vector<ProcessedPoint> estimate_extrusion_quality(const ExtrusionPath &path,
|
||||||
|
const ConfigOptionPercents &overlaps,
|
||||||
|
const ConfigOptionFloatsOrPercents &speeds,
|
||||||
|
float ext_perimeter_speed,
|
||||||
|
float original_speed)
|
||||||
{
|
{
|
||||||
|
size_t speed_sections_count = std::min(overlaps.values.size(), speeds.values.size());
|
||||||
|
std::vector<std::pair<float, float>> speed_sections;
|
||||||
|
for (size_t i = 0; i < speed_sections_count; i++) {
|
||||||
|
float distance = path.width * (1.0 - (overlaps.get_at(i) / 100.0));
|
||||||
|
float speed = speeds.get_at(i).percent ? (ext_perimeter_speed * speeds.get_at(i).value / 100.0) : speeds.get_at(i).value;
|
||||||
|
speed_sections.push_back({distance, speed});
|
||||||
|
}
|
||||||
|
std::sort(speed_sections.begin(), speed_sections.end(),
|
||||||
|
[](const std::pair<float, float> &a, const std::pair<float, float> &b) { return a.first < b.first; });
|
||||||
|
|
||||||
std::vector<ExtendedPoint> extended_points =
|
std::vector<ExtendedPoint> extended_points =
|
||||||
estimate_points_properties<true, true, true, false>(path.polyline.points, prev_layer_boundaries[current_object], path.width);
|
estimate_points_properties<true, true, true, false>(path.polyline.points, prev_layer_boundaries[current_object], path.width);
|
||||||
|
|
||||||
float min_malformation_dist = 0.55 * path.width;
|
|
||||||
float peak_malformation_dist = path.width;
|
|
||||||
|
|
||||||
std::vector<ProcessedPoint> processed_points;
|
std::vector<ProcessedPoint> processed_points;
|
||||||
processed_points.reserve(extended_points.size());
|
processed_points.reserve(extended_points.size());
|
||||||
for (size_t i = 0; i < extended_points.size(); i++) {
|
for (size_t i = 0; i < extended_points.size(); i++) {
|
||||||
const ExtendedPoint &curr = extended_points[i];
|
const ExtendedPoint &curr = extended_points[i];
|
||||||
const ExtendedPoint &next = extended_points[i + 1 < extended_points.size() ? i + 1 : i];
|
const ExtendedPoint &next = extended_points[i + 1 < extended_points.size() ? i + 1 : i];
|
||||||
|
|
||||||
float extrusion_speed_factor = 1.0f;
|
auto calculate_speed = [&speed_sections, &original_speed](float distance) {
|
||||||
if (std::max(curr.distance, next.distance) < min_malformation_dist) {
|
float final_speed;
|
||||||
extrusion_speed_factor = 1.0f;
|
if (distance <= speed_sections.front().first) {
|
||||||
} else {
|
final_speed = original_speed;
|
||||||
float curvature_penalty = std::min(1.0f, next.curvature);
|
} else if (distance >= speed_sections.back().first) {
|
||||||
float distance_penalty = (std::max(curr.distance, next.distance) - min_malformation_dist) /
|
final_speed = speed_sections.back().second;
|
||||||
(peak_malformation_dist - min_malformation_dist);
|
} else {
|
||||||
distance_penalty = std::min(1.0f, distance_penalty);
|
size_t section_idx = 0;
|
||||||
|
while (distance > speed_sections[section_idx + 1].first) {
|
||||||
|
section_idx++;
|
||||||
|
}
|
||||||
|
float t = (distance - speed_sections[section_idx].first) /
|
||||||
|
(speed_sections[section_idx + 1].first - speed_sections[section_idx].first);
|
||||||
|
t = std::clamp(t, 0.0f, 1.0f);
|
||||||
|
final_speed = (1.0f - t) * speed_sections[section_idx].second + t * speed_sections[section_idx + 1].second;
|
||||||
|
}
|
||||||
|
return final_speed;
|
||||||
|
};
|
||||||
|
|
||||||
extrusion_speed_factor = std::clamp(1.0f - distance_penalty - curvature_penalty, 0.0f, 1.0f);
|
float extrusion_speed = (calculate_speed(curr.distance) + calculate_speed(next.distance)) / 2.0f;
|
||||||
}
|
|
||||||
|
|
||||||
processed_points.push_back({scaled(curr.position), extrusion_speed_factor});
|
processed_points.push_back({scaled(curr.position), extrusion_speed});
|
||||||
}
|
}
|
||||||
return processed_points;
|
return processed_points;
|
||||||
}
|
}
|
||||||
|
@ -474,7 +474,6 @@ void Layer::make_perimeters()
|
|||||||
&& config.perimeters == other_config.perimeters
|
&& config.perimeters == other_config.perimeters
|
||||||
&& config.perimeter_speed == other_config.perimeter_speed
|
&& config.perimeter_speed == other_config.perimeter_speed
|
||||||
&& config.external_perimeter_speed == other_config.external_perimeter_speed
|
&& config.external_perimeter_speed == other_config.external_perimeter_speed
|
||||||
&& config.overhang_speed == other_config.overhang_speed
|
|
||||||
&& (config.gap_fill_enabled ? config.gap_fill_speed.value : 0.) ==
|
&& (config.gap_fill_enabled ? config.gap_fill_speed.value : 0.) ==
|
||||||
(other_config.gap_fill_enabled ? other_config.gap_fill_speed.value : 0.)
|
(other_config.gap_fill_enabled ? other_config.gap_fill_speed.value : 0.)
|
||||||
&& config.overhangs == other_config.overhangs
|
&& config.overhangs == other_config.overhangs
|
||||||
|
@ -428,7 +428,8 @@ static std::vector<std::string> s_Preset_print_options {
|
|||||||
"max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour",
|
"max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour",
|
||||||
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist",
|
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist",
|
||||||
"max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
|
"max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
|
||||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "overhang_speed", "infill_speed", "solid_infill_speed",
|
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed",
|
||||||
|
"enable_dynamic_overhang_speeds", "dynamic_overhang_speeds", "overhang_overlaps",
|
||||||
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
|
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
|
||||||
"bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration",
|
"bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration",
|
||||||
"bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
|
"bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
|
||||||
|
@ -528,6 +528,36 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionFloat(60));
|
def->set_default_value(new ConfigOptionFloat(60));
|
||||||
|
|
||||||
|
def = this->add("enable_dynamic_overhang_speeds", coBool);
|
||||||
|
def->label = L("Enable dynamic overhang speeds (Experimental)");
|
||||||
|
def->category = L("Speed");
|
||||||
|
def->tooltip = L("This setting enables dynamic speed control on overhangs.");
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionBool(true));
|
||||||
|
|
||||||
|
def = this->add("overhang_overlaps", coPercents);
|
||||||
|
def->label = L("Overhang overlap percentage");
|
||||||
|
def->category = L("Speed");
|
||||||
|
def->tooltip = L("Controls percentage of overhang extrusion overlap with the previous layer."
|
||||||
|
"Each overlap size then corresponds with the overhang speed set below.");
|
||||||
|
def->sidetext = L("%");
|
||||||
|
def->min = 0;
|
||||||
|
def->max = 100;
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionPercents({60, 40, 20, 0}));
|
||||||
|
|
||||||
|
def = this->add("dynamic_overhang_speeds", coFloatsOrPercents);
|
||||||
|
def->label = L("Dynamic speed on overhangs");
|
||||||
|
def->category = L("Speed");
|
||||||
|
def->tooltip = L("This setting controls the speed of the overhangs for overlap values set above."
|
||||||
|
"The final speed is calculated as an interpolation of the set speed values."
|
||||||
|
"If set as percentage, the speeds are calculated over the external perimeter speed."
|
||||||
|
);
|
||||||
|
def->sidetext = L("mm/s or %");
|
||||||
|
def->min = 0;
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionFloatsOrPercents({{25, false}, {20, false}, {15, false}, {15, false}}));
|
||||||
|
|
||||||
def = this->add("brim_width", coFloat);
|
def = this->add("brim_width", coFloat);
|
||||||
def->label = L("Brim width");
|
def->label = L("Brim width");
|
||||||
def->category = L("Skirt and brim");
|
def->category = L("Skirt and brim");
|
||||||
@ -2358,18 +2388,6 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionFloatOrPercent(15, false));
|
def->set_default_value(new ConfigOptionFloatOrPercent(15, false));
|
||||||
|
|
||||||
def = this->add("overhang_speed", coFloatOrPercent);
|
|
||||||
def->label = L("Overhangs");
|
|
||||||
def->category = L("Speed");
|
|
||||||
def->tooltip = L("This setting controls the speed of overhangs."
|
|
||||||
"If expressed as percentage (for example: 80%) it will be calculated "
|
|
||||||
"on the external perimeters speed setting. Set to zero for auto.");
|
|
||||||
def->sidetext = L("mm/s or %");
|
|
||||||
def->ratio_over = "external_perimeter_speed";
|
|
||||||
def->min = 0;
|
|
||||||
def->mode = comAdvanced;
|
|
||||||
def->set_default_value(new ConfigOptionFloatOrPercent(15, false));
|
|
||||||
|
|
||||||
def = this->add("solid_infill_below_area", coFloat);
|
def = this->add("solid_infill_below_area", coFloat);
|
||||||
def->label = L("Solid infill threshold area");
|
def->label = L("Solid infill threshold area");
|
||||||
def->category = L("Infill");
|
def->category = L("Infill");
|
||||||
|
@ -564,7 +564,9 @@ PRINT_CONFIG_CLASS_DEFINE(
|
|||||||
((ConfigOptionEnum<InfillPattern>, bottom_fill_pattern))
|
((ConfigOptionEnum<InfillPattern>, bottom_fill_pattern))
|
||||||
((ConfigOptionFloatOrPercent, external_perimeter_extrusion_width))
|
((ConfigOptionFloatOrPercent, external_perimeter_extrusion_width))
|
||||||
((ConfigOptionFloatOrPercent, external_perimeter_speed))
|
((ConfigOptionFloatOrPercent, external_perimeter_speed))
|
||||||
((ConfigOptionFloatOrPercent, overhang_speed))
|
((ConfigOptionBool, enable_dynamic_overhang_speeds))
|
||||||
|
((ConfigOptionPercents, overhang_overlaps))
|
||||||
|
((ConfigOptionFloatsOrPercents, dynamic_overhang_speeds))
|
||||||
((ConfigOptionBool, external_perimeters_first))
|
((ConfigOptionBool, external_perimeters_first))
|
||||||
((ConfigOptionBool, extra_perimeters))
|
((ConfigOptionBool, extra_perimeters))
|
||||||
((ConfigOptionBool, extra_perimeters_on_overhangs))
|
((ConfigOptionBool, extra_perimeters_on_overhangs))
|
||||||
|
@ -748,7 +748,9 @@ bool PrintObject::invalidate_state_by_config_options(
|
|||||||
|| opt_key == "support_material_speed"
|
|| opt_key == "support_material_speed"
|
||||||
|| opt_key == "support_material_interface_speed"
|
|| opt_key == "support_material_interface_speed"
|
||||||
|| opt_key == "bridge_speed"
|
|| opt_key == "bridge_speed"
|
||||||
|| opt_key == "overhang_speed"
|
|| opt_key == "enable_dynamic_overhang_speeds"
|
||||||
|
|| opt_key == "overhang_overlaps"
|
||||||
|
|| opt_key == "dynamic_overhang_speeds"
|
||||||
|| opt_key == "external_perimeter_speed"
|
|| opt_key == "external_perimeter_speed"
|
||||||
|| opt_key == "infill_speed"
|
|| opt_key == "infill_speed"
|
||||||
|| opt_key == "perimeter_speed"
|
|| opt_key == "perimeter_speed"
|
||||||
|
@ -220,9 +220,12 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
|||||||
bool have_perimeters = config->opt_int("perimeters") > 0;
|
bool have_perimeters = config->opt_int("perimeters") > 0;
|
||||||
for (auto el : { "extra_perimeters","extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
|
for (auto el : { "extra_perimeters","extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
|
||||||
"seam_position","staggered_inner_seams", "external_perimeters_first", "external_perimeter_extrusion_width",
|
"seam_position","staggered_inner_seams", "external_perimeters_first", "external_perimeter_extrusion_width",
|
||||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "overhang_speed" })
|
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "enable_dynamic_overhang_speeds", "overhang_overlaps", "dynamic_overhang_speeds" })
|
||||||
toggle_field(el, have_perimeters);
|
toggle_field(el, have_perimeters);
|
||||||
|
|
||||||
|
toggle_field("overhang_overlaps", config->opt_bool("enable_dynamic_overhang_speeds"));
|
||||||
|
toggle_field("dynamic_overhang_speeds", config->opt_bool("enable_dynamic_overhang_speeds"));
|
||||||
|
|
||||||
bool have_infill = config->option<ConfigOptionPercent>("fill_density")->value > 0;
|
bool have_infill = config->option<ConfigOptionPercent>("fill_density")->value > 0;
|
||||||
// infill_extruder uses the same logic as in Print::extruders()
|
// infill_extruder uses the same logic as in Print::extruders()
|
||||||
for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed",
|
for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed",
|
||||||
|
@ -100,7 +100,6 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
|
|||||||
double bridge_flow_ratio = print_config.opt_float("bridge_flow_ratio");
|
double bridge_flow_ratio = print_config.opt_float("bridge_flow_ratio");
|
||||||
double perimeter_speed = print_config.opt_float("perimeter_speed");
|
double perimeter_speed = print_config.opt_float("perimeter_speed");
|
||||||
double external_perimeter_speed = print_config.get_abs_value("external_perimeter_speed", perimeter_speed);
|
double external_perimeter_speed = print_config.get_abs_value("external_perimeter_speed", perimeter_speed);
|
||||||
// double overhang_seed = print_config.get_abs_value("overhang_speed", external_perimeter_speed);
|
|
||||||
// double gap_fill_speed = print_config.opt_bool("gap_fill_enabled") ? print_config.opt_float("gap_fill_speed") : 0.;
|
// double gap_fill_speed = print_config.opt_bool("gap_fill_enabled") ? print_config.opt_float("gap_fill_speed") : 0.;
|
||||||
double infill_speed = print_config.opt_float("infill_speed");
|
double infill_speed = print_config.opt_float("infill_speed");
|
||||||
double small_perimeter_speed = print_config.get_abs_value("small_perimeter_speed", perimeter_speed);
|
double small_perimeter_speed = print_config.get_abs_value("small_perimeter_speed", perimeter_speed);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// #include "libslic3r/GCodeSender.hpp"
|
// #include "libslic3r/GCodeSender.hpp"
|
||||||
|
#include "slic3r/GUI/BedShapeDialog.hpp"
|
||||||
#include "slic3r/Utils/Serial.hpp"
|
#include "slic3r/Utils/Serial.hpp"
|
||||||
#include "Tab.hpp"
|
#include "Tab.hpp"
|
||||||
#include "PresetHints.hpp"
|
#include "PresetHints.hpp"
|
||||||
@ -1541,7 +1542,6 @@ void TabPrint::build()
|
|||||||
optgroup->append_single_option_line("perimeter_speed");
|
optgroup->append_single_option_line("perimeter_speed");
|
||||||
optgroup->append_single_option_line("small_perimeter_speed");
|
optgroup->append_single_option_line("small_perimeter_speed");
|
||||||
optgroup->append_single_option_line("external_perimeter_speed");
|
optgroup->append_single_option_line("external_perimeter_speed");
|
||||||
optgroup->append_single_option_line("overhang_speed");
|
|
||||||
optgroup->append_single_option_line("infill_speed");
|
optgroup->append_single_option_line("infill_speed");
|
||||||
optgroup->append_single_option_line("solid_infill_speed");
|
optgroup->append_single_option_line("solid_infill_speed");
|
||||||
optgroup->append_single_option_line("top_solid_infill_speed");
|
optgroup->append_single_option_line("top_solid_infill_speed");
|
||||||
@ -1551,6 +1551,20 @@ void TabPrint::build()
|
|||||||
optgroup->append_single_option_line("gap_fill_speed");
|
optgroup->append_single_option_line("gap_fill_speed");
|
||||||
optgroup->append_single_option_line("ironing_speed");
|
optgroup->append_single_option_line("ironing_speed");
|
||||||
|
|
||||||
|
optgroup = page->new_optgroup(L("Dynamic overhang speed"));
|
||||||
|
auto append_option_line = [](ConfigOptionsGroupShp optgroup, std::string opt_key) {
|
||||||
|
auto option = optgroup->get_option(opt_key, 0);
|
||||||
|
auto line = Line{option.opt.full_label, ""};
|
||||||
|
line.append_option(option);
|
||||||
|
line.append_option(optgroup->get_option(opt_key, 1));
|
||||||
|
line.append_option(optgroup->get_option(opt_key, 2));
|
||||||
|
line.append_option(optgroup->get_option(opt_key, 3));
|
||||||
|
optgroup->append_line(line);
|
||||||
|
};
|
||||||
|
optgroup->append_single_option_line("enable_dynamic_overhang_speeds");
|
||||||
|
append_option_line(optgroup,"overhang_overlaps");
|
||||||
|
append_option_line(optgroup,"dynamic_overhang_speeds");
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Speed for non-print moves"));
|
optgroup = page->new_optgroup(L("Speed for non-print moves"));
|
||||||
optgroup->append_single_option_line("travel_speed");
|
optgroup->append_single_option_line("travel_speed");
|
||||||
optgroup->append_single_option_line("travel_speed_z");
|
optgroup->append_single_option_line("travel_speed_z");
|
||||||
|
@ -176,7 +176,7 @@ SCENARIO("Cooling integration tests", "[Cooling]") {
|
|||||||
{ "fan_below_layer_time", { 0 } },
|
{ "fan_below_layer_time", { 0 } },
|
||||||
{ "slowdown_below_layer_time", { 0 } },
|
{ "slowdown_below_layer_time", { 0 } },
|
||||||
{ "bridge_speed", 99 },
|
{ "bridge_speed", 99 },
|
||||||
{ "overhangs", false },
|
{ "enable_dynamic_overhang_speeds", false },
|
||||||
// internal bridges use solid_infil speed
|
// internal bridges use solid_infil speed
|
||||||
{ "bottom_solid_layers", 1 },
|
{ "bottom_solid_layers", 1 },
|
||||||
// internal bridges use solid_infil speed
|
// internal bridges use solid_infil speed
|
||||||
|
@ -309,7 +309,7 @@ SCENARIO("Perimeters", "[Perimeters]")
|
|||||||
{ "perimeters", 1 },
|
{ "perimeters", 1 },
|
||||||
{ "perimeter_speed", 77 },
|
{ "perimeter_speed", 77 },
|
||||||
{ "external_perimeter_speed", 66 },
|
{ "external_perimeter_speed", 66 },
|
||||||
{ "overhang_speed", 60 },
|
{ "enable_dynamic_overhang_speeds", false },
|
||||||
{ "bridge_speed", 99 },
|
{ "bridge_speed", 99 },
|
||||||
{ "cooling", "1" },
|
{ "cooling", "1" },
|
||||||
{ "fan_below_layer_time", "0" },
|
{ "fan_below_layer_time", "0" },
|
||||||
@ -330,11 +330,10 @@ SCENARIO("Perimeters", "[Perimeters]")
|
|||||||
const double perimeter_speed = config.opt_float("perimeter_speed") * 60.;
|
const double perimeter_speed = config.opt_float("perimeter_speed") * 60.;
|
||||||
const double external_perimeter_speed = config.get_abs_value("external_perimeter_speed") * 60.;
|
const double external_perimeter_speed = config.get_abs_value("external_perimeter_speed") * 60.;
|
||||||
const double bridge_speed = config.opt_float("bridge_speed") * 60.;
|
const double bridge_speed = config.opt_float("bridge_speed") * 60.;
|
||||||
const double overhang_speed = config.opt<ConfigOptionFloatOrPercent>("overhang_speed")->value * 60.;
|
|
||||||
const double nozzle_dmr = config.opt<ConfigOptionFloats>("nozzle_diameter")->get_at(0);
|
const double nozzle_dmr = config.opt<ConfigOptionFloats>("nozzle_diameter")->get_at(0);
|
||||||
const double filament_dmr = config.opt<ConfigOptionFloats>("filament_diameter")->get_at(0);
|
const double filament_dmr = config.opt<ConfigOptionFloats>("filament_diameter")->get_at(0);
|
||||||
const double bridge_mm_per_mm = sqr(nozzle_dmr / filament_dmr) * config.opt_float("bridge_flow_ratio");
|
const double bridge_mm_per_mm = sqr(nozzle_dmr / filament_dmr) * config.opt_float("bridge_flow_ratio");
|
||||||
parser.parse_buffer(gcode, [&layer_speeds, &fan_speed, perimeter_speed, external_perimeter_speed, bridge_speed, overhang_speed, nozzle_dmr, filament_dmr, bridge_mm_per_mm]
|
parser.parse_buffer(gcode, [&layer_speeds, &fan_speed, perimeter_speed, external_perimeter_speed, bridge_speed, nozzle_dmr, filament_dmr, bridge_mm_per_mm]
|
||||||
(Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
|
(Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
|
||||||
{
|
{
|
||||||
if (line.cmd_is("M107"))
|
if (line.cmd_is("M107"))
|
||||||
@ -343,14 +342,13 @@ SCENARIO("Perimeters", "[Perimeters]")
|
|||||||
line.has_value('S', fan_speed);
|
line.has_value('S', fan_speed);
|
||||||
else if (line.extruding(self) && line.dist_XY(self) > 0) {
|
else if (line.extruding(self) && line.dist_XY(self) > 0) {
|
||||||
double feedrate = line.new_F(self);
|
double feedrate = line.new_F(self);
|
||||||
REQUIRE((is_approx(feedrate, perimeter_speed) || is_approx(feedrate, bridge_speed) ||
|
REQUIRE((is_approx(feedrate, perimeter_speed) || is_approx(feedrate, external_perimeter_speed) || is_approx(feedrate, bridge_speed)));
|
||||||
(feedrate >= overhang_speed && feedrate <= external_perimeter_speed)));
|
|
||||||
layer_speeds[self.z()].insert(feedrate);
|
layer_speeds[self.z()].insert(feedrate);
|
||||||
bool bridging = is_approx(feedrate, bridge_speed);
|
bool bridging = is_approx(feedrate, bridge_speed);
|
||||||
double mm_per_mm = line.dist_E(self) / line.dist_XY(self);
|
double mm_per_mm = line.dist_E(self) / line.dist_XY(self);
|
||||||
// Fan enabled at full speed when bridging, disabled when not bridging.
|
// Fan enabled at full speed when bridging, disabled when not bridging.
|
||||||
REQUIRE((! bridging || fan_speed == 255));
|
REQUIRE((! bridging || fan_speed == 255));
|
||||||
// REQUIRE((bridging || fan_speed == 0)); not true. with dynamic overhangs slowdown, the fan is used as well (and the speed is anywhere between external perimeter speed and overhang speed)
|
REQUIRE((bridging || fan_speed == 0));
|
||||||
// When bridging, bridge flow is applied.
|
// When bridging, bridge flow is applied.
|
||||||
REQUIRE((! bridging || std::abs(mm_per_mm - bridge_mm_per_mm) <= 0.01));
|
REQUIRE((! bridging || std::abs(mm_per_mm - bridge_mm_per_mm) <= 0.01));
|
||||||
}
|
}
|
||||||
@ -377,7 +375,6 @@ SCENARIO("Perimeters", "[Perimeters]")
|
|||||||
{ "external_perimeter_speed", 99 },
|
{ "external_perimeter_speed", 99 },
|
||||||
{ "small_perimeter_speed", 99 },
|
{ "small_perimeter_speed", 99 },
|
||||||
{ "thin_walls", 0 },
|
{ "thin_walls", 0 },
|
||||||
{ "overhangs", false },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::ipadstand }, config);
|
std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::ipadstand }, config);
|
||||||
@ -533,7 +530,7 @@ SCENARIO("Perimeters3", "[Perimeters]")
|
|||||||
{ "skirts", 0 },
|
{ "skirts", 0 },
|
||||||
{ "perimeters", 3 },
|
{ "perimeters", 3 },
|
||||||
{ "layer_height", 0.4 },
|
{ "layer_height", 0.4 },
|
||||||
{ "overhang_speed", 5 },
|
{ "enable_dynamic_overhang_speeds", false },
|
||||||
// to prevent bridging over sparse infill
|
// to prevent bridging over sparse infill
|
||||||
{ "fill_density", 0 },
|
{ "fill_density", 0 },
|
||||||
{ "overhangs", true },
|
{ "overhangs", true },
|
||||||
@ -547,25 +544,26 @@ SCENARIO("Perimeters3", "[Perimeters]")
|
|||||||
std::string gcode = Slic3r::Test::slice({ mesh(Slic3r::Test::TestMesh::V, Vec3d::Zero(), scale) }, config);
|
std::string gcode = Slic3r::Test::slice({ mesh(Slic3r::Test::TestMesh::V, Vec3d::Zero(), scale) }, config);
|
||||||
GCodeReader parser;
|
GCodeReader parser;
|
||||||
std::set<coord_t> z_with_bridges;
|
std::set<coord_t> z_with_bridges;
|
||||||
const double overhang_speed = config.opt<ConfigOptionFloatOrPercent>("overhang_speed")->value * 60.;
|
const double bridge_speed = config.opt_float("bridge_speed") * 60.;
|
||||||
parser.parse_buffer(gcode, [&z_with_bridges, overhang_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
|
parser.parse_buffer(gcode, [&z_with_bridges, bridge_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
|
||||||
{
|
{
|
||||||
if (line.extruding(self) && line.dist_XY(self) > 0 &&
|
if (line.extruding(self) && line.dist_XY(self) > 0 && is_approx<double>(line.new_F(self), bridge_speed))
|
||||||
(is_approx<double>(line.new_F(self), overhang_speed)))
|
|
||||||
z_with_bridges.insert(scaled<coord_t>(self.z()));
|
z_with_bridges.insert(scaled<coord_t>(self.z()));
|
||||||
});
|
});
|
||||||
return z_with_bridges.size();
|
return z_with_bridges.size();
|
||||||
};
|
};
|
||||||
|
|
||||||
GIVEN("V shape, scaled 0.5x in X") {
|
GIVEN("V shape, unscaled") {
|
||||||
int n = test(Vec3d(0.5, 1., 1.));
|
int n = test(Vec3d(1., 1., 1.));
|
||||||
THEN("no overhangs printed with overhangs speed") {
|
// except for the two internal solid layers above void
|
||||||
REQUIRE(n == 0);
|
THEN("no overhangs printed with bridge speed") {
|
||||||
|
REQUIRE(n == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GIVEN("V shape, scaled 3x in X") {
|
GIVEN("V shape, scaled 3x in X") {
|
||||||
int n = test(Vec3d(3., 1., 1.));
|
int n = test(Vec3d(3., 1., 1.));
|
||||||
THEN("overhangs printed with overhangs speed") {
|
// except for the two internal solid layers above void
|
||||||
|
THEN("overhangs printed with bridge speed") {
|
||||||
REQUIRE(n > 2);
|
REQUIRE(n > 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user