Merge remote-tracking branch 'origin/master' into pm_anchor_bridges_on_sparse_infill
This commit is contained in:
commit
92f8ed6d6b
@ -484,6 +484,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
}
|
||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||
|
||||
size_t first_object_layer_id = this->object()->get_layer(0)->id();
|
||||
for (SurfaceFill &surface_fill : surface_fills) {
|
||||
//skip patterns for which additional input is nullptr
|
||||
switch (surface_fill.params.pattern) {
|
||||
@ -496,7 +497,10 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
// Create the filler object.
|
||||
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
|
||||
f->set_bounding_box(bbox);
|
||||
f->layer_id = this->id();
|
||||
// Layer ID is used for orienting the infill in alternating directions.
|
||||
// Layer::id() returns layer ID including raft layers, subtract them to make the infill direction independent
|
||||
// from raft.
|
||||
f->layer_id = this->id() - first_object_layer_id;
|
||||
f->z = this->print_z;
|
||||
f->angle = surface_fill.params.angle;
|
||||
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
|
||||
@ -838,7 +842,11 @@ void Layer::make_ironing()
|
||||
FillRectilinear fill;
|
||||
FillParams fill_params;
|
||||
fill.set_bounding_box(this->object()->bounding_box());
|
||||
fill.layer_id = this->id();
|
||||
// Layer ID is used for orienting the infill in alternating directions.
|
||||
// Layer::id() returns layer ID including raft layers, subtract them to make the infill direction independent
|
||||
// from raft.
|
||||
//FIXME ironing does not take fill angle into account. Shall it? Does it matter?
|
||||
fill.layer_id = this->id() - this->object()->get_layer(0)->id();
|
||||
fill.z = this->print_z;
|
||||
fill.overlap = 0;
|
||||
fill_params.density = 1.;
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "Config.hpp"
|
||||
#include "libslic3r.h"
|
||||
#include "GCode/ExtrusionProcessor.hpp"
|
||||
#include "I18N.hpp"
|
||||
@ -24,6 +25,7 @@
|
||||
#include <cstdlib>
|
||||
#include <chrono>
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
@ -2867,16 +2869,36 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
||||
);
|
||||
}
|
||||
|
||||
bool variable_speed = false;
|
||||
bool variable_speed_or_fan_speed = false;
|
||||
std::vector<ProcessedPoint> new_points{};
|
||||
if (this->m_config.enable_dynamic_overhang_speeds && !this->on_first_layer() && path.role().is_perimeter()) {
|
||||
if ((this->m_config.enable_dynamic_overhang_speeds || this->config().enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) &&
|
||||
!this->on_first_layer() && path.role().is_perimeter()) {
|
||||
std::vector<std::pair<int, ConfigOptionFloatOrPercent>> overhangs_with_speeds = {{100, ConfigOptionFloatOrPercent{speed, false}}};
|
||||
if (this->m_config.enable_dynamic_overhang_speeds) {
|
||||
overhangs_with_speeds = {{0, m_config.overhang_speed_0},
|
||||
{25, m_config.overhang_speed_1},
|
||||
{50, m_config.overhang_speed_2},
|
||||
{75, m_config.overhang_speed_3},
|
||||
{100, ConfigOptionFloatOrPercent{speed, false}}};
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, ConfigOptionInts>> overhang_w_fan_speeds = {{100, ConfigOptionInts{0}}};
|
||||
if (this->m_config.enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) {
|
||||
overhang_w_fan_speeds = {{0, m_config.overhang_fan_speed_0},
|
||||
{25, m_config.overhang_fan_speed_1},
|
||||
{50, m_config.overhang_fan_speed_2},
|
||||
{75, m_config.overhang_fan_speed_3},
|
||||
{100, ConfigOptionInts{0}}};
|
||||
}
|
||||
|
||||
double external_perim_reference_speed = std::min(m_config.get_abs_value("external_perimeter_speed"),
|
||||
std::min(EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm,
|
||||
m_config.max_volumetric_speed.value / path.mm3_per_mm));
|
||||
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, m_config.overhang_overlap_levels,
|
||||
m_config.dynamic_overhang_speeds,
|
||||
external_perim_reference_speed, speed);
|
||||
variable_speed = std::any_of(new_points.begin(), new_points.end(), [speed](const ProcessedPoint &p) { return p.speed != speed; });
|
||||
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, overhangs_with_speeds, overhang_w_fan_speeds,
|
||||
m_writer.extruder()->id(), external_perim_reference_speed,
|
||||
speed);
|
||||
variable_speed_or_fan_speed = std::any_of(new_points.begin(), new_points.end(),
|
||||
[speed](const ProcessedPoint &p) { return p.speed != speed || p.fan_speed != 0; });
|
||||
}
|
||||
|
||||
double F = speed * 60; // convert mm/sec to mm/min
|
||||
@ -2932,7 +2954,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
||||
|
||||
std::string cooling_marker_setspeed_comments;
|
||||
if (m_enable_cooling_markers) {
|
||||
if (path.role().is_bridge())
|
||||
if (path.role().is_bridge() &&
|
||||
(!path.role().is_perimeter() || !this->config().enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())))
|
||||
gcode += ";_BRIDGE_FAN_START\n";
|
||||
else
|
||||
cooling_marker_setspeed_comments = ";_EXTRUDE_SET_SPEED";
|
||||
@ -2940,7 +2963,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
||||
cooling_marker_setspeed_comments += ";_EXTERNAL_PERIMETER";
|
||||
}
|
||||
|
||||
if (!variable_speed) {
|
||||
if (!variable_speed_or_fan_speed) {
|
||||
// F is mm per minute.
|
||||
gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments);
|
||||
double path_length = 0.;
|
||||
@ -2965,21 +2988,28 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
||||
marked_comment = description;
|
||||
marked_comment += description_bridge;
|
||||
}
|
||||
double last_set_speed = new_points[0].speed * 60.0;
|
||||
double last_set_speed = new_points[0].speed * 60.0;
|
||||
double last_set_fan_speed = new_points[0].fan_speed;
|
||||
gcode += m_writer.set_speed(last_set_speed, "", cooling_marker_setspeed_comments);
|
||||
gcode += ";_SET_FAN_SPEED" + std::to_string(int(last_set_fan_speed)) + "\n";
|
||||
Vec2d prev = this->point_to_gcode_quantized(new_points[0].p);
|
||||
for (size_t i = 1; i < new_points.size(); i++) {
|
||||
const ProcessedPoint& processed_point = new_points[i];
|
||||
Vec2d p = this->point_to_gcode_quantized(processed_point.p);
|
||||
const double line_length = (p - prev).norm();
|
||||
const ProcessedPoint &processed_point = new_points[i];
|
||||
Vec2d p = this->point_to_gcode_quantized(processed_point.p);
|
||||
const double line_length = (p - prev).norm();
|
||||
gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, marked_comment);
|
||||
prev = p;
|
||||
prev = p;
|
||||
double new_speed = processed_point.speed * 60.0;
|
||||
if (last_set_speed != new_speed) {
|
||||
gcode += m_writer.set_speed(new_speed, "", cooling_marker_setspeed_comments);
|
||||
last_set_speed = new_speed;
|
||||
}
|
||||
if (last_set_fan_speed != processed_point.fan_speed) {
|
||||
last_set_fan_speed = processed_point.fan_speed;
|
||||
gcode += ";_SET_FAN_SPEED" + std::to_string(int(last_set_fan_speed)) + "\n";
|
||||
}
|
||||
}
|
||||
gcode += ";_RESET_FAN_SPEED\n";
|
||||
}
|
||||
|
||||
if (m_enable_cooling_markers)
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "../GCode.hpp"
|
||||
#include "CoolingBuffer.hpp"
|
||||
#include <algorithm>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
@ -59,6 +60,9 @@ struct CoolingLine
|
||||
// Would be TYPE_ADJUSTABLE, but the block of G-code lines has zero extrusion length, thus the block
|
||||
// cannot have its speed adjusted. This should not happen (sic!).
|
||||
TYPE_ADJUSTABLE_EMPTY = 1 << 12,
|
||||
// Custom fan speed (introduced for overhang fan speed)
|
||||
TYPE_SET_FAN_SPEED = 1 << 13,
|
||||
TYPE_RESET_FAN_SPEED = 1 << 14,
|
||||
};
|
||||
|
||||
CoolingLine(unsigned int type, size_t line_start, size_t line_end) :
|
||||
@ -88,6 +92,8 @@ struct CoolingLine
|
||||
float time;
|
||||
// Maximum duration of this segment.
|
||||
float time_max;
|
||||
// Requested fan speed
|
||||
int fan_speed;
|
||||
// If marked with the "slowdown" flag, the line has been slowed down.
|
||||
bool slowdown;
|
||||
};
|
||||
@ -499,7 +505,18 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
||||
} else
|
||||
line.time = 0;
|
||||
line.time_max = line.time;
|
||||
} else if (boost::contains(sline, ";_SET_FAN_SPEED")) {
|
||||
auto speed_start = sline.find_last_of('D');
|
||||
int speed = 0;
|
||||
for (char num : sline.substr(speed_start + 1)) {
|
||||
speed = speed * 10 + (num - '0');
|
||||
}
|
||||
line.type = CoolingLine::TYPE_SET_FAN_SPEED;
|
||||
line.fan_speed = speed;
|
||||
} else if (boost::contains(sline, ";_RESET_FAN_SPEED")) {
|
||||
line.type = CoolingLine::TYPE_RESET_FAN_SPEED;
|
||||
}
|
||||
|
||||
if (line.type != 0)
|
||||
adjustment->lines.emplace_back(std::move(line));
|
||||
}
|
||||
@ -732,10 +749,11 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
new_gcode.reserve(gcode.size() * 2);
|
||||
bool bridge_fan_control = false;
|
||||
int bridge_fan_speed = 0;
|
||||
auto change_extruder_set_fan = [ this, layer_id, layer_time, &new_gcode, &bridge_fan_control, &bridge_fan_speed ]() {
|
||||
auto change_extruder_set_fan = [this, layer_id, layer_time, &new_gcode, &bridge_fan_control, &bridge_fan_speed]() {
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_current_extruder)
|
||||
int min_fan_speed = EXTRUDER_CONFIG(min_fan_speed);
|
||||
int fan_speed_new = EXTRUDER_CONFIG(fan_always_on) ? min_fan_speed : 0;
|
||||
std::pair<int, int> custom_fan_speed_limits{fan_speed_new, 100 };
|
||||
int disable_fan_first_layers = EXTRUDER_CONFIG(disable_fan_first_layers);
|
||||
// Is the fan speed ramp enabled?
|
||||
int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer);
|
||||
@ -752,11 +770,13 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
if (layer_time < slowdown_below_layer_time) {
|
||||
// Layer time very short. Enable the fan to a full throttle.
|
||||
fan_speed_new = max_fan_speed;
|
||||
custom_fan_speed_limits.first = fan_speed_new;
|
||||
} else if (layer_time < fan_below_layer_time) {
|
||||
// Layer time quite short. Enable the fan proportionally according to the current layer time.
|
||||
assert(layer_time >= slowdown_below_layer_time);
|
||||
double t = (layer_time - slowdown_below_layer_time) / (fan_below_layer_time - slowdown_below_layer_time);
|
||||
fan_speed_new = int(floor(t * min_fan_speed + (1. - t) * max_fan_speed) + 0.5);
|
||||
custom_fan_speed_limits.first = fan_speed_new;
|
||||
}
|
||||
}
|
||||
bridge_fan_speed = EXTRUDER_CONFIG(bridge_fan_speed);
|
||||
@ -765,6 +785,7 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
float factor = float(int(layer_id + 1) - disable_fan_first_layers) / float(full_fan_speed_layer - disable_fan_first_layers);
|
||||
fan_speed_new = std::clamp(int(float(fan_speed_new) * factor + 0.5f), 0, 255);
|
||||
bridge_fan_speed = std::clamp(int(float(bridge_fan_speed) * factor + 0.5f), 0, 255);
|
||||
custom_fan_speed_limits.second = fan_speed_new;
|
||||
}
|
||||
#undef EXTRUDER_CONFIG
|
||||
bridge_fan_control = bridge_fan_speed > fan_speed_new;
|
||||
@ -777,11 +798,12 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
m_fan_speed = fan_speed_new;
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, m_fan_speed);
|
||||
}
|
||||
return custom_fan_speed_limits;
|
||||
};
|
||||
|
||||
const char *pos = gcode.c_str();
|
||||
int current_feedrate = 0;
|
||||
change_extruder_set_fan();
|
||||
std::pair<int,int> fan_speed_limits = change_extruder_set_fan();
|
||||
for (const CoolingLine *line : lines) {
|
||||
const char *line_start = gcode.c_str() + line->line_start;
|
||||
const char *line_end = gcode.c_str() + line->line_end;
|
||||
@ -792,9 +814,17 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
auto res = std::from_chars(line_start + m_toolchange_prefix.size(), line_end, new_extruder);
|
||||
if (res.ec != std::errc::invalid_argument && new_extruder != m_current_extruder) {
|
||||
m_current_extruder = new_extruder;
|
||||
change_extruder_set_fan();
|
||||
fan_speed_limits = change_extruder_set_fan();
|
||||
}
|
||||
new_gcode.append(line_start, line_end - line_start);
|
||||
} else if (line->type & CoolingLine::TYPE_SET_FAN_SPEED) {
|
||||
int new_speed = std::clamp(line->fan_speed, fan_speed_limits.first, fan_speed_limits.second);
|
||||
if (m_fan_speed != new_speed) {
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, new_speed);
|
||||
m_fan_speed = new_speed;
|
||||
}
|
||||
} else if (line->type & CoolingLine::TYPE_RESET_FAN_SPEED){
|
||||
fan_speed_limits = change_extruder_set_fan();
|
||||
} else if (line->type & CoolingLine::TYPE_BRIDGE_FAN_START) {
|
||||
if (bridge_fan_control)
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, bridge_fan_speed);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <unordered_map>
|
||||
@ -238,6 +239,7 @@ struct ProcessedPoint
|
||||
{
|
||||
Point p;
|
||||
float speed = 1.0f;
|
||||
int fan_speed = 0;
|
||||
};
|
||||
|
||||
class ExtrusionQualityEstimator
|
||||
@ -257,34 +259,27 @@ public:
|
||||
next_layer_boundaries[object] = AABBTreeLines::LinesDistancer<Linef>{to_unscaled_linesf(layer->lslices)};
|
||||
}
|
||||
|
||||
std::vector<ProcessedPoint> estimate_extrusion_quality(const ExtrusionPath &path,
|
||||
const ConfigOptionPercents &overlaps,
|
||||
const ConfigOptionFloatsOrPercents &speeds,
|
||||
float ext_perimeter_speed,
|
||||
float original_speed)
|
||||
std::vector<ProcessedPoint> estimate_extrusion_quality(const ExtrusionPath &path,
|
||||
const std::vector<std::pair<int, ConfigOptionFloatOrPercent>> overhangs_w_speeds,
|
||||
const std::vector<std::pair<int, ConfigOptionInts>> overhangs_w_fan_speeds,
|
||||
size_t extruder_id,
|
||||
float ext_perimeter_speed,
|
||||
float original_speed)
|
||||
{
|
||||
size_t speed_sections_count = std::min(overlaps.values.size(), speeds.values.size());
|
||||
float speed_base = ext_perimeter_speed > 0 ? ext_perimeter_speed : original_speed;
|
||||
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 ? (speed_base * speeds.get_at(i).value / 100.0) : speeds.get_at(i).value;
|
||||
speed_sections.push_back({distance, speed});
|
||||
float speed_base = ext_perimeter_speed > 0 ? ext_perimeter_speed : original_speed;
|
||||
std::map<float, float> speed_sections;
|
||||
for (size_t i = 0; i < overhangs_w_speeds.size(); i++) {
|
||||
float distance = path.width * (1.0 - (overhangs_w_speeds[i].first / 100.0));
|
||||
float speed = overhangs_w_speeds[i].second.percent ? (speed_base * overhangs_w_speeds[i].second.value / 100.0) :
|
||||
overhangs_w_speeds[i].second.value;
|
||||
speed_sections[distance] = speed;
|
||||
}
|
||||
std::sort(speed_sections.begin(), speed_sections.end(),
|
||||
[](const std::pair<float, float> &a, const std::pair<float, float> &b) {
|
||||
if (a.first == b.first) {
|
||||
return a.second > b.second;
|
||||
}
|
||||
return a.first < b.first; });
|
||||
|
||||
std::pair<float, float> last_section{INFINITY, 0};
|
||||
for (auto §ion : speed_sections) {
|
||||
if (section.first == last_section.first) {
|
||||
section.second = last_section.second;
|
||||
} else {
|
||||
last_section = section;
|
||||
}
|
||||
std::map<float, float> fan_speed_sections;
|
||||
for (size_t i = 0; i < overhangs_w_fan_speeds.size(); i++) {
|
||||
float distance = path.width * (1.0 - (overhangs_w_fan_speeds[i].first / 100.0));
|
||||
float fan_speed = overhangs_w_fan_speeds[i].second.get_at(extruder_id);
|
||||
fan_speed_sections[distance] = fan_speed;
|
||||
}
|
||||
|
||||
std::vector<ExtendedPoint> extended_points =
|
||||
@ -296,28 +291,26 @@ public:
|
||||
const ExtendedPoint &curr = extended_points[i];
|
||||
const ExtendedPoint &next = extended_points[i + 1 < extended_points.size() ? i + 1 : i];
|
||||
|
||||
auto calculate_speed = [&speed_sections, &original_speed](float distance) {
|
||||
float final_speed;
|
||||
if (distance <= speed_sections.front().first) {
|
||||
final_speed = original_speed;
|
||||
} else if (distance >= speed_sections.back().first) {
|
||||
final_speed = speed_sections.back().second;
|
||||
} else {
|
||||
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;
|
||||
auto interpolate_speed = [](const std::map<float, float> &values, float distance) {
|
||||
auto upper_dist = values.lower_bound(distance);
|
||||
if (upper_dist == values.end()) {
|
||||
return values.rbegin()->second;
|
||||
}
|
||||
return final_speed;
|
||||
if (upper_dist == values.begin()) {
|
||||
return upper_dist->second;
|
||||
}
|
||||
|
||||
auto lower_dist = std::prev(upper_dist);
|
||||
float t = (distance - lower_dist->first) / (upper_dist->first - lower_dist->first);
|
||||
return (1.0f - t) * lower_dist->second + t * upper_dist->second;
|
||||
};
|
||||
|
||||
float extrusion_speed = std::min(calculate_speed(curr.distance), calculate_speed(next.distance));
|
||||
float extrusion_speed = std::min(interpolate_speed(speed_sections, curr.distance),
|
||||
interpolate_speed(speed_sections, next.distance));
|
||||
float fan_speed = std::min(interpolate_speed(fan_speed_sections, curr.distance),
|
||||
interpolate_speed(fan_speed_sections, next.distance));
|
||||
|
||||
processed_points.push_back({scaled(curr.position), extrusion_speed});
|
||||
processed_points.push_back({scaled(curr.position), extrusion_speed, int(fan_speed)});
|
||||
}
|
||||
return processed_points;
|
||||
}
|
||||
|
@ -440,7 +440,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist",
|
||||
"max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed",
|
||||
"enable_dynamic_overhang_speeds", "dynamic_overhang_speeds", "overhang_overlap_levels",
|
||||
"enable_dynamic_overhang_speeds", "overhang_speed_0", "overhang_speed_1", "overhang_speed_2", "overhang_speed_3",
|
||||
"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",
|
||||
"external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration",
|
||||
@ -473,7 +473,8 @@ static std::vector<std::string> s_Preset_filament_options {
|
||||
"filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower",
|
||||
"temperature", "idle_temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed",
|
||||
"max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed",
|
||||
"start_filament_gcode", "end_filament_gcode",
|
||||
"start_filament_gcode", "end_filament_gcode", "enable_dynamic_fan_speeds",
|
||||
"overhang_fan_speed_0", "overhang_fan_speed_1", "overhang_fan_speed_2", "overhang_fan_speed_3",
|
||||
// Retract overrides
|
||||
"filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel",
|
||||
"filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe",
|
||||
|
@ -66,6 +66,11 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
"between_objects_gcode",
|
||||
"bridge_acceleration",
|
||||
"bridge_fan_speed",
|
||||
"enable_dynamic_fan_speeds",
|
||||
"overhang_fan_speed_0",
|
||||
"overhang_fan_speed_1",
|
||||
"overhang_fan_speed_2",
|
||||
"overhang_fan_speed_3",
|
||||
"colorprint_heights",
|
||||
"cooling",
|
||||
"default_acceleration",
|
||||
|
@ -535,35 +535,96 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Enable dynamic overhang speeds");
|
||||
def->category = L("Speed");
|
||||
def->tooltip = L("This setting enables dynamic speed control on overhangs.");
|
||||
def->mode = comAdvanced;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("overhang_overlap_levels", coPercents);
|
||||
def->full_label = L("Overhang overlap levels");
|
||||
def->category = L("Speed");
|
||||
def->tooltip = L("Controls overhang levels, expressed as a percentage of overlap of the extrusion with the previous layer - "
|
||||
"100% represents full overlap - no overhang is present, while 0% represents full overhang (floating extrusion). "
|
||||
"Each overhang level then corresponds with the overhang speed below. Speeds for overhang levels in between are "
|
||||
"calculated via linear interpolation."
|
||||
"If you set multiple different speeds for the same overhang level, only the largest speed is used. "
|
||||
);
|
||||
def->sidetext = L("%");
|
||||
def->min = 0;
|
||||
def->max = 100;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionPercents({60, 40, 20, 0}));
|
||||
auto overhang_speed_setting_description = L("Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: "
|
||||
"100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). "
|
||||
"Speeds for overhang sizes in between are calculated via linear interpolation. "
|
||||
"If set as percentage, the speed is calculated over the external perimeter speed.");
|
||||
|
||||
def = this->add("dynamic_overhang_speeds", coFloatsOrPercents);
|
||||
def->full_label = L("Dynamic speed on overhangs");
|
||||
def = this->add("overhang_speed_0", coFloatOrPercent);
|
||||
def->label = L("speed for 0\% overlap (bridge)");
|
||||
def->category = L("Speed");
|
||||
def->tooltip = L("This setting controls the speed on the overhang with the overlap value set above. "
|
||||
"The speed of the extrusion is calculated as a linear interpolation of the speeds for higher and lower overlap. "
|
||||
"If set as percentage, the speed is calculated over the external perimeter speed."
|
||||
);
|
||||
def->tooltip = overhang_speed_setting_description;
|
||||
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->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent(15, false));
|
||||
|
||||
def = this->add("overhang_speed_1", coFloatOrPercent);
|
||||
def->label = L("speed for 25\% overlap");
|
||||
def->category = L("Speed");
|
||||
def->tooltip = overhang_speed_setting_description;
|
||||
def->sidetext = L("mm/s or %");
|
||||
def->min = 0;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent(15, false));
|
||||
|
||||
def = this->add("overhang_speed_2", coFloatOrPercent);
|
||||
def->label = L("speed for 50\% overlap");
|
||||
def->category = L("Speed");
|
||||
def->tooltip = overhang_speed_setting_description;
|
||||
def->sidetext = L("mm/s or %");
|
||||
def->min = 0;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent(20, false));
|
||||
|
||||
def = this->add("overhang_speed_3", coFloatOrPercent);
|
||||
def->label = L("speed for 75\% overlap");
|
||||
def->category = L("Speed");
|
||||
def->tooltip = overhang_speed_setting_description;
|
||||
def->sidetext = L("mm/s or %");
|
||||
def->min = 0;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent(25, false));
|
||||
|
||||
def = this->add("enable_dynamic_fan_speeds", coBools);
|
||||
def->label = L("Enable dynamic fan speeds");
|
||||
def->tooltip = L("This setting enables dynamic fan speed control on overhangs.");
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionBools{false});
|
||||
|
||||
auto fan_speed_setting_description = L(
|
||||
"Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: "
|
||||
"100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). "
|
||||
"Fan speeds for overhang sizes in between are calculated via linear interpolation. ");
|
||||
|
||||
def = this->add("overhang_fan_speed_0", coInts);
|
||||
def->label = L("speed for 0\% overlap (bridge)");
|
||||
def->tooltip = fan_speed_setting_description;
|
||||
def->sidetext = L("%");
|
||||
def->min = 0;
|
||||
def->max = 100;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionInts{0});
|
||||
|
||||
def = this->add("overhang_fan_speed_1", coInts);
|
||||
def->label = L("speed for 25\% overlap");
|
||||
def->tooltip = fan_speed_setting_description;
|
||||
def->sidetext = L("%");
|
||||
def->min = 0;
|
||||
def->max = 100;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionInts{0});
|
||||
|
||||
def = this->add("overhang_fan_speed_2", coInts);
|
||||
def->label = L("speed for 50\% overlap");
|
||||
def->tooltip = fan_speed_setting_description;
|
||||
def->sidetext = L("%");
|
||||
def->min = 0;
|
||||
def->max = 100;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionInts{0});
|
||||
|
||||
def = this->add("overhang_fan_speed_3", coInts);
|
||||
def->label = L("speed for 75\% overlap");
|
||||
def->tooltip = fan_speed_setting_description;
|
||||
def->sidetext = L("%");
|
||||
def->min = 0;
|
||||
def->max = 100;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionInts{0});
|
||||
|
||||
def = this->add("brim_width", coFloat);
|
||||
def->label = L("Brim width");
|
||||
|
@ -575,8 +575,10 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionFloatOrPercent, external_perimeter_extrusion_width))
|
||||
((ConfigOptionFloatOrPercent, external_perimeter_speed))
|
||||
((ConfigOptionBool, enable_dynamic_overhang_speeds))
|
||||
((ConfigOptionPercents, overhang_overlap_levels))
|
||||
((ConfigOptionFloatsOrPercents, dynamic_overhang_speeds))
|
||||
((ConfigOptionFloatOrPercent, overhang_speed_0))
|
||||
((ConfigOptionFloatOrPercent, overhang_speed_1))
|
||||
((ConfigOptionFloatOrPercent, overhang_speed_2))
|
||||
((ConfigOptionFloatOrPercent, overhang_speed_3))
|
||||
((ConfigOptionBool, external_perimeters_first))
|
||||
((ConfigOptionBool, extra_perimeters))
|
||||
((ConfigOptionBool, extra_perimeters_on_overhangs))
|
||||
@ -749,6 +751,11 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
((ConfigOptionInts, bed_temperature))
|
||||
((ConfigOptionFloat, bridge_acceleration))
|
||||
((ConfigOptionInts, bridge_fan_speed))
|
||||
((ConfigOptionBools, enable_dynamic_fan_speeds))
|
||||
((ConfigOptionInts, overhang_fan_speed_0))
|
||||
((ConfigOptionInts, overhang_fan_speed_1))
|
||||
((ConfigOptionInts, overhang_fan_speed_2))
|
||||
((ConfigOptionInts, overhang_fan_speed_3))
|
||||
((ConfigOptionBool, complete_objects))
|
||||
((ConfigOptionFloats, colorprint_heights))
|
||||
((ConfigOptionBools, cooling))
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "Fill/FillAdaptive.hpp"
|
||||
#include "Fill/FillLightning.hpp"
|
||||
#include "Format/STL.hpp"
|
||||
#include "SupportMaterial.hpp"
|
||||
#include "SupportSpotsGenerator.hpp"
|
||||
#include "TriangleSelectorWrapper.hpp"
|
||||
#include "format.hpp"
|
||||
@ -784,8 +785,10 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||
|| opt_key == "support_material_interface_speed"
|
||||
|| opt_key == "bridge_speed"
|
||||
|| opt_key == "enable_dynamic_overhang_speeds"
|
||||
|| opt_key == "overhang_overlap_levels"
|
||||
|| opt_key == "dynamic_overhang_speeds"
|
||||
|| opt_key == "overhang_speed_0"
|
||||
|| opt_key == "overhang_speed_1"
|
||||
|| opt_key == "overhang_speed_2"
|
||||
|| opt_key == "overhang_speed_3"
|
||||
|| opt_key == "external_perimeter_speed"
|
||||
|| opt_key == "infill_speed"
|
||||
|| opt_key == "perimeter_speed"
|
||||
@ -1152,6 +1155,15 @@ void PrintObject::process_external_surfaces()
|
||||
m_print->throw_if_canceled();
|
||||
BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - end";
|
||||
}
|
||||
|
||||
if (this->has_raft() && ! m_layers.empty()) {
|
||||
// Adjust bridge direction of 1st object layer over raft to be perpendicular to the raft contact layer direction.
|
||||
Layer &layer = *m_layers.front();
|
||||
assert(layer.id() > 0);
|
||||
for (LayerRegion *layerm : layer.regions())
|
||||
for (Surface &fill : layerm->m_fill_surfaces)
|
||||
fill.bridge_angle = -1;
|
||||
}
|
||||
} // void PrintObject::process_external_surfaces()
|
||||
|
||||
void PrintObject::discover_vertical_shells()
|
||||
|
@ -376,8 +376,6 @@ SupportParameters::SupportParameters(const PrintObject &object)
|
||||
}
|
||||
|
||||
|
||||
this->base_angle = Geometry::deg2rad(float(object_config.support_material_angle.value));
|
||||
this->interface_angle = Geometry::deg2rad(float(object_config.support_material_angle.value + 90.));
|
||||
double interface_spacing = object_config.support_material_interface_spacing.value + this->support_material_interface_flow.spacing();
|
||||
this->interface_density = std::min(1., this->support_material_interface_flow.spacing() / interface_spacing);
|
||||
double raft_interface_spacing = object_config.support_material_interface_spacing.value + this->raft_interface_flow.spacing();
|
||||
@ -401,6 +399,39 @@ SupportParameters::SupportParameters(const PrintObject &object)
|
||||
object_config.support_material_interface_pattern == smipConcentric ?
|
||||
ipConcentric :
|
||||
(this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
|
||||
|
||||
this->base_angle = Geometry::deg2rad(float(object_config.support_material_angle.value));
|
||||
this->interface_angle = Geometry::deg2rad(float(object_config.support_material_angle.value + 90.));
|
||||
this->raft_angle_1st_layer = 0.f;
|
||||
this->raft_angle_base = 0.f;
|
||||
this->raft_angle_interface = 0.f;
|
||||
if (slicing_params.base_raft_layers > 1) {
|
||||
assert(slicing_params.raft_layers() >= 4);
|
||||
// There are all raft layer types (1st layer, base, interface & contact layers) available.
|
||||
this->raft_angle_1st_layer = this->interface_angle;
|
||||
this->raft_angle_base = this->base_angle;
|
||||
this->raft_angle_interface = this->interface_angle;
|
||||
if ((slicing_params.interface_raft_layers & 1) == 0)
|
||||
// Allign the 1st raft interface layer so that the object 1st layer is hatched perpendicularly to the raft contact interface.
|
||||
this->raft_angle_interface += float(0.5 * M_PI);
|
||||
} else if (slicing_params.base_raft_layers == 1 || slicing_params.interface_raft_layers > 1) {
|
||||
assert(slicing_params.raft_layers() == 2 || slicing_params.raft_layers() == 3);
|
||||
// 1st layer, interface & contact layers available.
|
||||
this->raft_angle_1st_layer = this->base_angle;
|
||||
this->raft_angle_interface = this->interface_angle + 0.5 * M_PI;
|
||||
} else if (slicing_params.interface_raft_layers == 1) {
|
||||
// Only the contact raft layer is non-empty, which will be printed as the 1st layer.
|
||||
assert(slicing_params.base_raft_layers == 0);
|
||||
assert(slicing_params.interface_raft_layers == 1);
|
||||
assert(slicing_params.raft_layers() == 1);
|
||||
this->raft_angle_1st_layer = float(0.5 * M_PI);
|
||||
this->raft_angle_interface = this->raft_angle_1st_layer;
|
||||
} else {
|
||||
// No raft.
|
||||
assert(slicing_params.base_raft_layers == 0);
|
||||
assert(slicing_params.interface_raft_layers == 0);
|
||||
assert(slicing_params.raft_layers() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object, const SlicingParameters &slicing_params) :
|
||||
@ -4207,38 +4238,12 @@ void generate_support_toolpaths(
|
||||
// const coordf_t link_max_length_factor = 3.;
|
||||
const coordf_t link_max_length_factor = 0.;
|
||||
|
||||
float raft_angle_1st_layer = 0.f;
|
||||
float raft_angle_base = 0.f;
|
||||
float raft_angle_interface = 0.f;
|
||||
if (slicing_params.base_raft_layers > 1) {
|
||||
// There are all raft layer types (1st layer, base, interface & contact layers) available.
|
||||
raft_angle_1st_layer = support_params.interface_angle;
|
||||
raft_angle_base = support_params.base_angle;
|
||||
raft_angle_interface = support_params.interface_angle;
|
||||
} else if (slicing_params.base_raft_layers == 1 || slicing_params.interface_raft_layers > 1) {
|
||||
// 1st layer, interface & contact layers available.
|
||||
raft_angle_1st_layer = support_params.base_angle;
|
||||
if (config.support_material || config.support_material_enforce_layers > 0)
|
||||
// Print 1st layer at 45 degrees from both the interface and base angles as both can land on the 1st layer.
|
||||
raft_angle_1st_layer += 0.7854f;
|
||||
raft_angle_interface = support_params.interface_angle;
|
||||
} else if (slicing_params.interface_raft_layers == 1) {
|
||||
// Only the contact raft layer is non-empty, which will be printed as the 1st layer.
|
||||
assert(slicing_params.base_raft_layers == 0);
|
||||
assert(slicing_params.interface_raft_layers == 1);
|
||||
assert(slicing_params.raft_layers() == 1 && raft_layers.size() == 0);
|
||||
} else {
|
||||
// No raft.
|
||||
assert(slicing_params.base_raft_layers == 0);
|
||||
assert(slicing_params.interface_raft_layers == 0);
|
||||
assert(slicing_params.raft_layers() == 0 && raft_layers.size() == 0);
|
||||
}
|
||||
|
||||
// Insert the raft base layers.
|
||||
auto n_raft_layers = std::min<size_t>(support_layers.size(), std::max(0, int(slicing_params.raft_layers()) - 1));
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, n_raft_layers),
|
||||
[&support_layers, &raft_layers, &intermediate_layers, &config, &support_params, &slicing_params,
|
||||
&bbox_object, raft_angle_1st_layer, raft_angle_base, raft_angle_interface, link_max_length_factor]
|
||||
&bbox_object, link_max_length_factor]
|
||||
(const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id)
|
||||
{
|
||||
@ -4270,7 +4275,7 @@ void generate_support_toolpaths(
|
||||
assert(!raft_layer.bridging);
|
||||
if (! to_infill_polygons.empty()) {
|
||||
Fill *filler = filler_support.get();
|
||||
filler->angle = raft_angle_base;
|
||||
filler->angle = support_params.raft_angle_base;
|
||||
filler->spacing = support_params.support_material_flow.spacing();
|
||||
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.support_density));
|
||||
fill_expolygons_with_sheath_generate_paths(
|
||||
@ -4293,11 +4298,11 @@ void generate_support_toolpaths(
|
||||
float density = 0.f;
|
||||
if (support_layer_id == 0) {
|
||||
// Base flange.
|
||||
filler->angle = raft_angle_1st_layer;
|
||||
filler->angle = support_params.raft_angle_1st_layer;
|
||||
filler->spacing = support_params.first_layer_flow.spacing();
|
||||
density = float(config.raft_first_layer_density.value * 0.01);
|
||||
} else if (support_layer_id >= slicing_params.base_raft_layers) {
|
||||
filler->angle = raft_angle_interface;
|
||||
filler->angle = support_params.raft_interface_angle(support_layer.interface_id());
|
||||
// We don't use $base_flow->spacing because we need a constant spacing
|
||||
// value that guarantees that all layers are correctly aligned.
|
||||
filler->spacing = support_params.support_material_flow.spacing();
|
||||
@ -4345,7 +4350,7 @@ void generate_support_toolpaths(
|
||||
std::vector<LayerCache> layer_caches(support_layers.size());
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, support_layers.size()),
|
||||
[&config, &support_params, &support_layers, &bottom_contacts, &top_contacts, &intermediate_layers, &interface_layers, &base_interface_layers, &layer_caches, &loop_interface_processor,
|
||||
[&config, &slicing_params, &support_params, &support_layers, &bottom_contacts, &top_contacts, &intermediate_layers, &interface_layers, &base_interface_layers, &layer_caches, &loop_interface_processor,
|
||||
&bbox_object, &angles, n_raft_layers, link_max_length_factor]
|
||||
(const tbb::blocked_range<size_t>& range) {
|
||||
// Indices of the 1st layer in their respective container at the support layer height.
|
||||
@ -4381,9 +4386,8 @@ void generate_support_toolpaths(
|
||||
{
|
||||
SupportLayer &support_layer = *support_layers[support_layer_id];
|
||||
LayerCache &layer_cache = layer_caches[support_layer_id];
|
||||
float interface_angle_delta = config.support_material_style.value != smsGrid ?
|
||||
(support_layer.interface_id() & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.) :
|
||||
0;
|
||||
const float support_interface_angle = config.support_material_style.value == smsGrid ?
|
||||
support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id());
|
||||
|
||||
// Find polygons with the same print_z.
|
||||
SupportGeneratorLayerExtruded &bottom_contact_layer = layer_cache.bottom_contact_layer;
|
||||
@ -4412,7 +4416,8 @@ void generate_support_toolpaths(
|
||||
if (idx_layer_intermediate < intermediate_layers.size() && intermediate_layers[idx_layer_intermediate]->print_z < support_layer.print_z + EPSILON)
|
||||
base_layer.layer = intermediate_layers[idx_layer_intermediate];
|
||||
|
||||
bool raft_layer = support_layer_id == n_raft_layers;
|
||||
// This layer is a raft contact layer. Any contact polygons at this layer are raft contacts.
|
||||
bool raft_layer = slicing_params.interface_raft_layers && top_contact_layer.layer && is_approx(top_contact_layer.layer->print_z, slicing_params.raft_contact_top_z);
|
||||
if (config.support_material_interface_layers == 0) {
|
||||
// If no top interface layers were requested, we treat the contact layer exactly as a generic base layer.
|
||||
// Don't merge the raft contact layer though.
|
||||
@ -4470,7 +4475,9 @@ void generate_support_toolpaths(
|
||||
// If zero interface layers are configured, use the same angle as for the base layers.
|
||||
angles[support_layer_id % angles.size()] :
|
||||
// Use interface angle for the interface layers.
|
||||
support_params.interface_angle + interface_angle_delta;
|
||||
raft_contact ?
|
||||
support_params.raft_interface_angle(support_layer.interface_id()) :
|
||||
support_interface_angle;
|
||||
double density = raft_contact ? support_params.raft_interface_density : interface_as_base ? support_params.support_density : support_params.interface_density;
|
||||
filler->spacing = raft_contact ? support_params.raft_interface_flow.spacing() :
|
||||
interface_as_base ? support_params.support_material_flow.spacing() : support_params.support_material_interface_flow.spacing();
|
||||
@ -4499,7 +4506,7 @@ void generate_support_toolpaths(
|
||||
// the bridging flow does not quite apply. Reduce the flow to area of an ellipse? (A = pi * a * b)
|
||||
assert(! base_interface_layer.layer->bridging);
|
||||
Flow interface_flow = support_params.support_material_flow.with_height(float(base_interface_layer.layer->height));
|
||||
filler->angle = support_params.interface_angle + interface_angle_delta;
|
||||
filler->angle = support_interface_angle;
|
||||
filler->spacing = support_params.support_material_interface_flow.spacing();
|
||||
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.interface_density));
|
||||
fill_expolygons_generate_paths(
|
||||
|
@ -161,6 +161,14 @@ struct SupportParameters {
|
||||
InfillPattern contact_fill_pattern;
|
||||
// Shall the sparse (base) layers be printed with a single perimeter line (sheath) for robustness?
|
||||
bool with_sheath;
|
||||
|
||||
float raft_angle_1st_layer;
|
||||
float raft_angle_base;
|
||||
float raft_angle_interface;
|
||||
|
||||
// Produce a raft interface angle for a given SupportLayer::interface_id()
|
||||
float raft_interface_angle(size_t interface_id) const
|
||||
{ return this->raft_angle_interface + ((interface_id & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.)); }
|
||||
};
|
||||
|
||||
// Remove bridges from support contact areas.
|
||||
|
@ -491,9 +491,8 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex
|
||||
if (const std::vector<Polygons> &outlines = m_layer_outlines[outline_idx].second; ! outlines.empty()) {
|
||||
const TreeSupportMeshGroupSettings &settings = m_layer_outlines[outline_idx].first;
|
||||
const coord_t layer_height = settings.layer_height;
|
||||
const coord_t z_distance_bottom = settings.support_bottom_distance;
|
||||
const int z_distance_bottom_layers = round_up_divide<int>(z_distance_bottom, layer_height);
|
||||
const int z_distance_top_layers = round_up_divide<int>(settings.support_top_distance, layer_height);
|
||||
const int z_distance_bottom_layers = int(round(double(settings.support_bottom_distance) / double(layer_height)));
|
||||
const int z_distance_top_layers = int(round(double(settings.support_top_distance) / double(layer_height)));
|
||||
const LayerIndex max_required_layer = std::min<LayerIndex>(outlines.size(), max_layer_idx + std::max(coord_t(1), z_distance_top_layers));
|
||||
const LayerIndex min_layer_bottom = std::max<LayerIndex>(0, min_layer_last - int(z_distance_bottom_layers));
|
||||
const coord_t xy_distance = outline_idx == m_current_outline_idx ? m_current_min_xy_dist :
|
||||
|
@ -80,8 +80,8 @@ TreeSupportSettings::TreeSupportSettings(const TreeSupportMeshGroupSettings& mes
|
||||
xy_min_distance(std::min(mesh_group_settings.support_xy_distance, mesh_group_settings.support_xy_distance_overhang)),
|
||||
bp_radius(mesh_group_settings.support_tree_bp_diameter / 2),
|
||||
diameter_scale_bp_radius(std::min(sin(0.7) * layer_height / branch_radius, 1.0 / (branch_radius / (support_line_width / 2.0)))), // Either 40? or as much as possible so that 2 lines will overlap by at least 50%, whichever is smaller.
|
||||
z_distance_top_layers(round_up_divide(mesh_group_settings.support_top_distance, layer_height)),
|
||||
z_distance_bottom_layers(round_up_divide(mesh_group_settings.support_bottom_distance, layer_height)),
|
||||
z_distance_bottom_layers(size_t(round(double(mesh_group_settings.support_bottom_distance) / double(layer_height)))),
|
||||
z_distance_top_layers(size_t(round(double(mesh_group_settings.support_top_distance) / double(layer_height)))),
|
||||
performance_interface_skip_layers(round_up_divide(mesh_group_settings.support_interface_skip_height, layer_height)),
|
||||
// support_infill_angles(mesh_group_settings.support_infill_angles),
|
||||
support_roof_angles(mesh_group_settings.support_roof_angles),
|
||||
|
@ -221,12 +221,11 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
||||
bool have_perimeters = config->opt_int("perimeters") > 0;
|
||||
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",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "enable_dynamic_overhang_speeds", "overhang_overlap_levels", "dynamic_overhang_speeds" })
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "enable_dynamic_overhang_speeds"})
|
||||
toggle_field(el, have_perimeters);
|
||||
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
toggle_field("overhang_overlap_levels#" + std::to_string(i), config->opt_bool("enable_dynamic_overhang_speeds"));
|
||||
toggle_field("dynamic_overhang_speeds#" + std::to_string(i), config->opt_bool("enable_dynamic_overhang_speeds"));
|
||||
toggle_field("overhang_speed_" + std::to_string(i), config->opt_bool("enable_dynamic_overhang_speeds"));
|
||||
}
|
||||
|
||||
bool have_infill = config->option<ConfigOptionPercent>("fill_density")->value > 0;
|
||||
|
@ -1549,18 +1549,11 @@ void TabPrint::build()
|
||||
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_overlap_levels");
|
||||
append_option_line(optgroup,"dynamic_overhang_speeds");
|
||||
optgroup->append_single_option_line("overhang_speed_0");
|
||||
optgroup->append_single_option_line("overhang_speed_1");
|
||||
optgroup->append_single_option_line("overhang_speed_2");
|
||||
optgroup->append_single_option_line("overhang_speed_3");
|
||||
|
||||
optgroup = page->new_optgroup(L("Speed for non-print moves"));
|
||||
optgroup->append_single_option_line("travel_speed");
|
||||
@ -1994,6 +1987,13 @@ void TabFilament::build()
|
||||
optgroup->append_single_option_line("disable_fan_first_layers", category_path + "fan-settings");
|
||||
optgroup->append_single_option_line("full_fan_speed_layer", category_path + "fan-settings");
|
||||
|
||||
optgroup = page->new_optgroup(L("Dynamic fan speeds"), 25);
|
||||
optgroup->append_single_option_line("enable_dynamic_fan_speeds", category_path + "dynamic-fan-speeds");
|
||||
optgroup->append_single_option_line("overhang_fan_speed_0", category_path + "dynamic-fan-speeds");
|
||||
optgroup->append_single_option_line("overhang_fan_speed_1", category_path + "dynamic-fan-speeds");
|
||||
optgroup->append_single_option_line("overhang_fan_speed_2", category_path + "dynamic-fan-speeds");
|
||||
optgroup->append_single_option_line("overhang_fan_speed_3", category_path + "dynamic-fan-speeds");
|
||||
|
||||
optgroup = page->new_optgroup(L("Cooling thresholds"), 25);
|
||||
optgroup->append_single_option_line("fan_below_layer_time", category_path + "cooling-thresholds");
|
||||
optgroup->append_single_option_line("slowdown_below_layer_time", category_path + "cooling-thresholds");
|
||||
@ -2146,6 +2146,11 @@ void TabFilament::toggle_options()
|
||||
|
||||
for (auto el : { "min_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer" })
|
||||
toggle_option(el, fan_always_on);
|
||||
|
||||
bool dynamic_fan_speeds = m_config->opt_bool("enable_dynamic_fan_speeds", 0);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
toggle_option("overhang_fan_speed_"+std::to_string(i),dynamic_fan_speeds);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_active_page->title() == "Filament Overrides")
|
||||
|
Loading…
Reference in New Issue
Block a user