mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-29 01:52:03 +08:00
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 */
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
|
|
||||||
|
size_t first_object_layer_id = this->object()->get_layer(0)->id();
|
||||||
for (SurfaceFill &surface_fill : surface_fills) {
|
for (SurfaceFill &surface_fill : surface_fills) {
|
||||||
//skip patterns for which additional input is nullptr
|
//skip patterns for which additional input is nullptr
|
||||||
switch (surface_fill.params.pattern) {
|
switch (surface_fill.params.pattern) {
|
||||||
@ -496,7 +497,10 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
|||||||
// Create the filler object.
|
// Create the filler object.
|
||||||
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
|
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
|
||||||
f->set_bounding_box(bbox);
|
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->z = this->print_z;
|
||||||
f->angle = surface_fill.params.angle;
|
f->angle = surface_fill.params.angle;
|
||||||
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
|
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
|
||||||
@ -838,7 +842,11 @@ void Layer::make_ironing()
|
|||||||
FillRectilinear fill;
|
FillRectilinear fill;
|
||||||
FillParams fill_params;
|
FillParams fill_params;
|
||||||
fill.set_bounding_box(this->object()->bounding_box());
|
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.z = this->print_z;
|
||||||
fill.overlap = 0;
|
fill.overlap = 0;
|
||||||
fill_params.density = 1.;
|
fill_params.density = 1.;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "Config.hpp"
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include "GCode/ExtrusionProcessor.hpp"
|
#include "GCode/ExtrusionProcessor.hpp"
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
@ -24,6 +25,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#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{};
|
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"),
|
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,
|
std::min(EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm,
|
||||||
m_config.max_volumetric_speed.value / 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,
|
new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, overhangs_with_speeds, overhang_w_fan_speeds,
|
||||||
m_config.dynamic_overhang_speeds,
|
m_writer.extruder()->id(), external_perim_reference_speed,
|
||||||
external_perim_reference_speed, speed);
|
speed);
|
||||||
variable_speed = std::any_of(new_points.begin(), new_points.end(), [speed](const ProcessedPoint &p) { return p.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
|
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;
|
std::string cooling_marker_setspeed_comments;
|
||||||
if (m_enable_cooling_markers) {
|
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";
|
gcode += ";_BRIDGE_FAN_START\n";
|
||||||
else
|
else
|
||||||
cooling_marker_setspeed_comments = ";_EXTRUDE_SET_SPEED";
|
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";
|
cooling_marker_setspeed_comments += ";_EXTERNAL_PERIMETER";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!variable_speed) {
|
if (!variable_speed_or_fan_speed) {
|
||||||
// F is mm per minute.
|
// F is mm per minute.
|
||||||
gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments);
|
gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments);
|
||||||
double path_length = 0.;
|
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;
|
||||||
marked_comment += description_bridge;
|
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 += 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);
|
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& processed_point = new_points[i];
|
const ProcessedPoint &processed_point = new_points[i];
|
||||||
Vec2d p = this->point_to_gcode_quantized(processed_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, marked_comment);
|
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;
|
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, "", cooling_marker_setspeed_comments);
|
gcode += m_writer.set_speed(new_speed, "", cooling_marker_setspeed_comments);
|
||||||
last_set_speed = new_speed;
|
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)
|
if (m_enable_cooling_markers)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "../GCode.hpp"
|
#include "../GCode.hpp"
|
||||||
#include "CoolingBuffer.hpp"
|
#include "CoolingBuffer.hpp"
|
||||||
|
#include <algorithm>
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
#include <boost/log/trivial.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
|
// 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!).
|
// cannot have its speed adjusted. This should not happen (sic!).
|
||||||
TYPE_ADJUSTABLE_EMPTY = 1 << 12,
|
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) :
|
CoolingLine(unsigned int type, size_t line_start, size_t line_end) :
|
||||||
@ -88,6 +92,8 @@ struct CoolingLine
|
|||||||
float time;
|
float time;
|
||||||
// Maximum duration of this segment.
|
// Maximum duration of this segment.
|
||||||
float time_max;
|
float time_max;
|
||||||
|
// Requested fan speed
|
||||||
|
int fan_speed;
|
||||||
// If marked with the "slowdown" flag, the line has been slowed down.
|
// If marked with the "slowdown" flag, the line has been slowed down.
|
||||||
bool slowdown;
|
bool slowdown;
|
||||||
};
|
};
|
||||||
@ -499,7 +505,18 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
|||||||
} else
|
} else
|
||||||
line.time = 0;
|
line.time = 0;
|
||||||
line.time_max = line.time;
|
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)
|
if (line.type != 0)
|
||||||
adjustment->lines.emplace_back(std::move(line));
|
adjustment->lines.emplace_back(std::move(line));
|
||||||
}
|
}
|
||||||
@ -732,10 +749,11 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
|||||||
new_gcode.reserve(gcode.size() * 2);
|
new_gcode.reserve(gcode.size() * 2);
|
||||||
bool bridge_fan_control = false;
|
bool bridge_fan_control = false;
|
||||||
int bridge_fan_speed = 0;
|
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)
|
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_current_extruder)
|
||||||
int min_fan_speed = EXTRUDER_CONFIG(min_fan_speed);
|
int min_fan_speed = EXTRUDER_CONFIG(min_fan_speed);
|
||||||
int fan_speed_new = EXTRUDER_CONFIG(fan_always_on) ? min_fan_speed : 0;
|
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);
|
int disable_fan_first_layers = EXTRUDER_CONFIG(disable_fan_first_layers);
|
||||||
// Is the fan speed ramp enabled?
|
// Is the fan speed ramp enabled?
|
||||||
int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer);
|
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) {
|
if (layer_time < slowdown_below_layer_time) {
|
||||||
// Layer time very short. Enable the fan to a full throttle.
|
// Layer time very short. Enable the fan to a full throttle.
|
||||||
fan_speed_new = max_fan_speed;
|
fan_speed_new = max_fan_speed;
|
||||||
|
custom_fan_speed_limits.first = fan_speed_new;
|
||||||
} else if (layer_time < fan_below_layer_time) {
|
} else if (layer_time < fan_below_layer_time) {
|
||||||
// Layer time quite short. Enable the fan proportionally according to the current layer time.
|
// Layer time quite short. Enable the fan proportionally according to the current layer time.
|
||||||
assert(layer_time >= slowdown_below_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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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
|
#undef EXTRUDER_CONFIG
|
||||||
bridge_fan_control = bridge_fan_speed > fan_speed_new;
|
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;
|
m_fan_speed = fan_speed_new;
|
||||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, m_fan_speed);
|
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();
|
const char *pos = gcode.c_str();
|
||||||
int current_feedrate = 0;
|
int current_feedrate = 0;
|
||||||
change_extruder_set_fan();
|
std::pair<int,int> fan_speed_limits = change_extruder_set_fan();
|
||||||
for (const CoolingLine *line : lines) {
|
for (const CoolingLine *line : lines) {
|
||||||
const char *line_start = gcode.c_str() + line->line_start;
|
const char *line_start = gcode.c_str() + line->line_start;
|
||||||
const char *line_end = gcode.c_str() + line->line_end;
|
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);
|
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) {
|
if (res.ec != std::errc::invalid_argument && new_extruder != m_current_extruder) {
|
||||||
m_current_extruder = new_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);
|
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) {
|
} else if (line->type & CoolingLine::TYPE_BRIDGE_FAN_START) {
|
||||||
if (bridge_fan_control)
|
if (bridge_fan_control)
|
||||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, bridge_fan_speed);
|
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, bridge_fan_speed);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <iterator>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -238,6 +239,7 @@ struct ProcessedPoint
|
|||||||
{
|
{
|
||||||
Point p;
|
Point p;
|
||||||
float speed = 1.0f;
|
float speed = 1.0f;
|
||||||
|
int fan_speed = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExtrusionQualityEstimator
|
class ExtrusionQualityEstimator
|
||||||
@ -257,34 +259,27 @@ 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 std::vector<std::pair<int, ConfigOptionFloatOrPercent>> overhangs_w_speeds,
|
||||||
const ConfigOptionFloatsOrPercents &speeds,
|
const std::vector<std::pair<int, ConfigOptionInts>> overhangs_w_fan_speeds,
|
||||||
float ext_perimeter_speed,
|
size_t extruder_id,
|
||||||
float original_speed)
|
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;
|
||||||
float speed_base = ext_perimeter_speed > 0 ? ext_perimeter_speed : original_speed;
|
std::map<float, float> speed_sections;
|
||||||
std::vector<std::pair<float, float>> speed_sections;
|
for (size_t i = 0; i < overhangs_w_speeds.size(); i++) {
|
||||||
for (size_t i = 0; i < speed_sections_count; i++) {
|
float distance = path.width * (1.0 - (overhangs_w_speeds[i].first / 100.0));
|
||||||
float distance = path.width * (1.0 - (overlaps.get_at(i) / 100.0));
|
float speed = overhangs_w_speeds[i].second.percent ? (speed_base * overhangs_w_speeds[i].second.value / 100.0) :
|
||||||
float speed = speeds.get_at(i).percent ? (speed_base * speeds.get_at(i).value / 100.0) : speeds.get_at(i).value;
|
overhangs_w_speeds[i].second.value;
|
||||||
speed_sections.push_back({distance, speed});
|
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};
|
std::map<float, float> fan_speed_sections;
|
||||||
for (auto §ion : speed_sections) {
|
for (size_t i = 0; i < overhangs_w_fan_speeds.size(); i++) {
|
||||||
if (section.first == last_section.first) {
|
float distance = path.width * (1.0 - (overhangs_w_fan_speeds[i].first / 100.0));
|
||||||
section.second = last_section.second;
|
float fan_speed = overhangs_w_fan_speeds[i].second.get_at(extruder_id);
|
||||||
} else {
|
fan_speed_sections[distance] = fan_speed;
|
||||||
last_section = section;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ExtendedPoint> extended_points =
|
std::vector<ExtendedPoint> extended_points =
|
||||||
@ -296,28 +291,26 @@ public:
|
|||||||
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];
|
||||||
|
|
||||||
auto calculate_speed = [&speed_sections, &original_speed](float distance) {
|
auto interpolate_speed = [](const std::map<float, float> &values, float distance) {
|
||||||
float final_speed;
|
auto upper_dist = values.lower_bound(distance);
|
||||||
if (distance <= speed_sections.front().first) {
|
if (upper_dist == values.end()) {
|
||||||
final_speed = original_speed;
|
return values.rbegin()->second;
|
||||||
} 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;
|
|
||||||
}
|
}
|
||||||
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;
|
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",
|
"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", "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_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",
|
"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",
|
||||||
"external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_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",
|
"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",
|
"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",
|
"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
|
// 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_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",
|
"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",
|
"between_objects_gcode",
|
||||||
"bridge_acceleration",
|
"bridge_acceleration",
|
||||||
"bridge_fan_speed",
|
"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",
|
"colorprint_heights",
|
||||||
"cooling",
|
"cooling",
|
||||||
"default_acceleration",
|
"default_acceleration",
|
||||||
|
@ -535,35 +535,96 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->label = L("Enable dynamic overhang speeds");
|
def->label = L("Enable dynamic overhang speeds");
|
||||||
def->category = L("Speed");
|
def->category = L("Speed");
|
||||||
def->tooltip = L("This setting enables dynamic speed control on overhangs.");
|
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->set_default_value(new ConfigOptionBool(false));
|
||||||
|
|
||||||
def = this->add("overhang_overlap_levels", coPercents);
|
auto overhang_speed_setting_description = L("Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: "
|
||||||
def->full_label = L("Overhang overlap levels");
|
"100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). "
|
||||||
def->category = L("Speed");
|
"Speeds for overhang sizes in between are calculated via linear interpolation. "
|
||||||
def->tooltip = L("Controls overhang levels, expressed as a percentage of overlap of the extrusion with the previous layer - "
|
"If set as percentage, the speed is calculated over the external perimeter speed.");
|
||||||
"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}));
|
|
||||||
|
|
||||||
def = this->add("dynamic_overhang_speeds", coFloatsOrPercents);
|
def = this->add("overhang_speed_0", coFloatOrPercent);
|
||||||
def->full_label = L("Dynamic speed on overhangs");
|
def->label = L("speed for 0\% overlap (bridge)");
|
||||||
def->category = L("Speed");
|
def->category = L("Speed");
|
||||||
def->tooltip = L("This setting controls the speed on the overhang with the overlap value set above. "
|
def->tooltip = overhang_speed_setting_description;
|
||||||
"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->sidetext = L("mm/s or %");
|
def->sidetext = L("mm/s or %");
|
||||||
def->min = 0;
|
def->min = 0;
|
||||||
def->mode = comAdvanced;
|
def->mode = comExpert;
|
||||||
def->set_default_value(new ConfigOptionFloatsOrPercents({{25, false}, {20, false}, {15, false}, {15, false}}));
|
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 = this->add("brim_width", coFloat);
|
||||||
def->label = L("Brim width");
|
def->label = L("Brim width");
|
||||||
|
@ -575,8 +575,10 @@ PRINT_CONFIG_CLASS_DEFINE(
|
|||||||
((ConfigOptionFloatOrPercent, external_perimeter_extrusion_width))
|
((ConfigOptionFloatOrPercent, external_perimeter_extrusion_width))
|
||||||
((ConfigOptionFloatOrPercent, external_perimeter_speed))
|
((ConfigOptionFloatOrPercent, external_perimeter_speed))
|
||||||
((ConfigOptionBool, enable_dynamic_overhang_speeds))
|
((ConfigOptionBool, enable_dynamic_overhang_speeds))
|
||||||
((ConfigOptionPercents, overhang_overlap_levels))
|
((ConfigOptionFloatOrPercent, overhang_speed_0))
|
||||||
((ConfigOptionFloatsOrPercents, dynamic_overhang_speeds))
|
((ConfigOptionFloatOrPercent, overhang_speed_1))
|
||||||
|
((ConfigOptionFloatOrPercent, overhang_speed_2))
|
||||||
|
((ConfigOptionFloatOrPercent, overhang_speed_3))
|
||||||
((ConfigOptionBool, external_perimeters_first))
|
((ConfigOptionBool, external_perimeters_first))
|
||||||
((ConfigOptionBool, extra_perimeters))
|
((ConfigOptionBool, extra_perimeters))
|
||||||
((ConfigOptionBool, extra_perimeters_on_overhangs))
|
((ConfigOptionBool, extra_perimeters_on_overhangs))
|
||||||
@ -749,6 +751,11 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
|||||||
((ConfigOptionInts, bed_temperature))
|
((ConfigOptionInts, bed_temperature))
|
||||||
((ConfigOptionFloat, bridge_acceleration))
|
((ConfigOptionFloat, bridge_acceleration))
|
||||||
((ConfigOptionInts, bridge_fan_speed))
|
((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))
|
((ConfigOptionBool, complete_objects))
|
||||||
((ConfigOptionFloats, colorprint_heights))
|
((ConfigOptionFloats, colorprint_heights))
|
||||||
((ConfigOptionBools, cooling))
|
((ConfigOptionBools, cooling))
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "Fill/FillAdaptive.hpp"
|
#include "Fill/FillAdaptive.hpp"
|
||||||
#include "Fill/FillLightning.hpp"
|
#include "Fill/FillLightning.hpp"
|
||||||
#include "Format/STL.hpp"
|
#include "Format/STL.hpp"
|
||||||
|
#include "SupportMaterial.hpp"
|
||||||
#include "SupportSpotsGenerator.hpp"
|
#include "SupportSpotsGenerator.hpp"
|
||||||
#include "TriangleSelectorWrapper.hpp"
|
#include "TriangleSelectorWrapper.hpp"
|
||||||
#include "format.hpp"
|
#include "format.hpp"
|
||||||
@ -784,8 +785,10 @@ bool PrintObject::invalidate_state_by_config_options(
|
|||||||
|| opt_key == "support_material_interface_speed"
|
|| opt_key == "support_material_interface_speed"
|
||||||
|| opt_key == "bridge_speed"
|
|| opt_key == "bridge_speed"
|
||||||
|| opt_key == "enable_dynamic_overhang_speeds"
|
|| opt_key == "enable_dynamic_overhang_speeds"
|
||||||
|| opt_key == "overhang_overlap_levels"
|
|| opt_key == "overhang_speed_0"
|
||||||
|| opt_key == "dynamic_overhang_speeds"
|
|| opt_key == "overhang_speed_1"
|
||||||
|
|| opt_key == "overhang_speed_2"
|
||||||
|
|| opt_key == "overhang_speed_3"
|
||||||
|| 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"
|
||||||
@ -1152,6 +1155,15 @@ void PrintObject::process_external_surfaces()
|
|||||||
m_print->throw_if_canceled();
|
m_print->throw_if_canceled();
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - end";
|
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::process_external_surfaces()
|
||||||
|
|
||||||
void PrintObject::discover_vertical_shells()
|
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();
|
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);
|
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();
|
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 ?
|
object_config.support_material_interface_pattern == smipConcentric ?
|
||||||
ipConcentric :
|
ipConcentric :
|
||||||
(this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
|
(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) :
|
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 = 3.;
|
||||||
const coordf_t link_max_length_factor = 0.;
|
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.
|
// 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));
|
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),
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, n_raft_layers),
|
||||||
[&support_layers, &raft_layers, &intermediate_layers, &config, &support_params, &slicing_params,
|
[&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) {
|
(const tbb::blocked_range<size_t>& range) {
|
||||||
for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id)
|
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);
|
assert(!raft_layer.bridging);
|
||||||
if (! to_infill_polygons.empty()) {
|
if (! to_infill_polygons.empty()) {
|
||||||
Fill *filler = filler_support.get();
|
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->spacing = support_params.support_material_flow.spacing();
|
||||||
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.support_density));
|
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.support_density));
|
||||||
fill_expolygons_with_sheath_generate_paths(
|
fill_expolygons_with_sheath_generate_paths(
|
||||||
@ -4293,11 +4298,11 @@ void generate_support_toolpaths(
|
|||||||
float density = 0.f;
|
float density = 0.f;
|
||||||
if (support_layer_id == 0) {
|
if (support_layer_id == 0) {
|
||||||
// Base flange.
|
// Base flange.
|
||||||
filler->angle = raft_angle_1st_layer;
|
filler->angle = support_params.raft_angle_1st_layer;
|
||||||
filler->spacing = support_params.first_layer_flow.spacing();
|
filler->spacing = support_params.first_layer_flow.spacing();
|
||||||
density = float(config.raft_first_layer_density.value * 0.01);
|
density = float(config.raft_first_layer_density.value * 0.01);
|
||||||
} else if (support_layer_id >= slicing_params.base_raft_layers) {
|
} 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
|
// We don't use $base_flow->spacing because we need a constant spacing
|
||||||
// value that guarantees that all layers are correctly aligned.
|
// value that guarantees that all layers are correctly aligned.
|
||||||
filler->spacing = support_params.support_material_flow.spacing();
|
filler->spacing = support_params.support_material_flow.spacing();
|
||||||
@ -4345,7 +4350,7 @@ void generate_support_toolpaths(
|
|||||||
std::vector<LayerCache> layer_caches(support_layers.size());
|
std::vector<LayerCache> layer_caches(support_layers.size());
|
||||||
|
|
||||||
tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, 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]
|
&bbox_object, &angles, n_raft_layers, link_max_length_factor]
|
||||||
(const tbb::blocked_range<size_t>& range) {
|
(const tbb::blocked_range<size_t>& range) {
|
||||||
// Indices of the 1st layer in their respective container at the support layer height.
|
// 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];
|
SupportLayer &support_layer = *support_layers[support_layer_id];
|
||||||
LayerCache &layer_cache = layer_caches[support_layer_id];
|
LayerCache &layer_cache = layer_caches[support_layer_id];
|
||||||
float interface_angle_delta = config.support_material_style.value != smsGrid ?
|
const float support_interface_angle = config.support_material_style.value == smsGrid ?
|
||||||
(support_layer.interface_id() & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.) :
|
support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id());
|
||||||
0;
|
|
||||||
|
|
||||||
// Find polygons with the same print_z.
|
// Find polygons with the same print_z.
|
||||||
SupportGeneratorLayerExtruded &bottom_contact_layer = layer_cache.bottom_contact_layer;
|
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)
|
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];
|
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 (config.support_material_interface_layers == 0) {
|
||||||
// If no top interface layers were requested, we treat the contact layer exactly as a generic base layer.
|
// 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.
|
// 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.
|
// If zero interface layers are configured, use the same angle as for the base layers.
|
||||||
angles[support_layer_id % angles.size()] :
|
angles[support_layer_id % angles.size()] :
|
||||||
// Use interface angle for the interface layers.
|
// 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;
|
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() :
|
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();
|
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)
|
// 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);
|
assert(! base_interface_layer.layer->bridging);
|
||||||
Flow interface_flow = support_params.support_material_flow.with_height(float(base_interface_layer.layer->height));
|
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->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));
|
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.interface_density));
|
||||||
fill_expolygons_generate_paths(
|
fill_expolygons_generate_paths(
|
||||||
|
@ -161,6 +161,14 @@ struct SupportParameters {
|
|||||||
InfillPattern contact_fill_pattern;
|
InfillPattern contact_fill_pattern;
|
||||||
// Shall the sparse (base) layers be printed with a single perimeter line (sheath) for robustness?
|
// Shall the sparse (base) layers be printed with a single perimeter line (sheath) for robustness?
|
||||||
bool with_sheath;
|
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.
|
// 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()) {
|
if (const std::vector<Polygons> &outlines = m_layer_outlines[outline_idx].second; ! outlines.empty()) {
|
||||||
const TreeSupportMeshGroupSettings &settings = m_layer_outlines[outline_idx].first;
|
const TreeSupportMeshGroupSettings &settings = m_layer_outlines[outline_idx].first;
|
||||||
const coord_t layer_height = settings.layer_height;
|
const coord_t layer_height = settings.layer_height;
|
||||||
const coord_t z_distance_bottom = settings.support_bottom_distance;
|
const int z_distance_bottom_layers = int(round(double(settings.support_bottom_distance) / double(layer_height)));
|
||||||
const int z_distance_bottom_layers = round_up_divide<int>(z_distance_bottom, layer_height);
|
const int z_distance_top_layers = int(round(double(settings.support_top_distance) / double(layer_height)));
|
||||||
const int z_distance_top_layers = round_up_divide<int>(settings.support_top_distance, 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 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 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 :
|
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)),
|
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),
|
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.
|
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(size_t(round(double(mesh_group_settings.support_bottom_distance) / double(layer_height)))),
|
||||||
z_distance_bottom_layers(round_up_divide(mesh_group_settings.support_bottom_distance, 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)),
|
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_infill_angles(mesh_group_settings.support_infill_angles),
|
||||||
support_roof_angles(mesh_group_settings.support_roof_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;
|
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", "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);
|
toggle_field(el, have_perimeters);
|
||||||
|
|
||||||
for (size_t i = 0; i < 4; i++) {
|
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("overhang_speed_" + 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"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool have_infill = config->option<ConfigOptionPercent>("fill_density")->value > 0;
|
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->append_single_option_line("ironing_speed");
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Dynamic overhang 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");
|
optgroup->append_single_option_line("enable_dynamic_overhang_speeds");
|
||||||
append_option_line(optgroup,"overhang_overlap_levels");
|
optgroup->append_single_option_line("overhang_speed_0");
|
||||||
append_option_line(optgroup,"dynamic_overhang_speeds");
|
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 = page->new_optgroup(L("Speed for non-print moves"));
|
||||||
optgroup->append_single_option_line("travel_speed");
|
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("disable_fan_first_layers", category_path + "fan-settings");
|
||||||
optgroup->append_single_option_line("full_fan_speed_layer", 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 = 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("fan_below_layer_time", category_path + "cooling-thresholds");
|
||||||
optgroup->append_single_option_line("slowdown_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" })
|
for (auto el : { "min_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer" })
|
||||||
toggle_option(el, fan_always_on);
|
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")
|
if (m_active_page->title() == "Filament Overrides")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user