mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-23 02:42:08 +00:00
Merge branch 'main' into zaa
This commit is contained in:
@@ -879,8 +879,8 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START] = true;
|
||||
need_set_fan = true;
|
||||
}
|
||||
} else if (line->type & CoolingLine::TYPE_IRONING_FAN_END && fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]) {
|
||||
if (ironing_fan_control) {
|
||||
} else if (line->type & CoolingLine::TYPE_IRONING_FAN_END) {
|
||||
if (ironing_fan_control && fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]) {
|
||||
fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START] = false;
|
||||
}
|
||||
need_set_fan = true;
|
||||
|
||||
@@ -124,7 +124,7 @@ static void set_option_value(ConfigOptionFloats& option, size_t id, float value)
|
||||
static float get_option_value(const ConfigOptionFloats& option, size_t id)
|
||||
{
|
||||
return option.values.empty() ? 0.0f :
|
||||
((id < option.values.size()) ? static_cast<float>(option.values[id]) : static_cast<float>(option.values.back()));
|
||||
((id < option.values.size()) ? static_cast<float>(option.values[id]) : static_cast<float>(option.values.front()));
|
||||
}
|
||||
|
||||
static float estimated_acceleration_distance(float initial_rate, float target_rate, float acceleration)
|
||||
@@ -1259,7 +1259,7 @@ void GCodeProcessor::run_post_process()
|
||||
// line inserter
|
||||
[tool_number, this](unsigned int id, const std::vector<float>& time_diffs) {
|
||||
const int temperature = int(m_layer_id != 1 ? m_filament_nozzle_temp[tool_number] :
|
||||
m_filament_nozzle_temp_first_layer[tool_number]);
|
||||
m_filament_nozzle_temp_first_layer[tool_number]);
|
||||
// Orca: M104.1 for XL printers, I can't find the documentation for this so I copied the C++ comments from
|
||||
// Prusa-Firmware-Buddy here
|
||||
/**
|
||||
@@ -1731,6 +1731,10 @@ void GCodeProcessor::register_commands()
|
||||
{"M702", [this](const GCodeReader::GCodeLine& line) { process_M702(line); }}, // Unload the current filament into the MK3 MMU2 unit at the end of print.
|
||||
{"M1020", [this](const GCodeReader::GCodeLine& line) { process_M1020(line); }}, // Select Tool
|
||||
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
{"M900", [this](const GCodeReader::GCodeLine& line) { process_M900(line); }}, // Marlin: Set pressure advance
|
||||
{"M572", [this](const GCodeReader::GCodeLine& line) { process_M572(line); }}, // RepRapFirmware/Duet: Set pressure advance
|
||||
|
||||
{"T", [this](const GCodeReader::GCodeLine& line) { process_T(line); }}, // Select Tool
|
||||
{"SYNC", [this](const GCodeReader::GCodeLine& line) { process_SYNC(line); }}, // SYNC TIME
|
||||
|
||||
@@ -2792,6 +2796,12 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line, bool
|
||||
process_SET_VELOCITY_LIMIT(line);
|
||||
return;
|
||||
}
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
if (boost::iequals(cmd, "SET_PRESSURE_ADVANCE"))
|
||||
{
|
||||
process_SET_PRESSURE_ADVANCE(line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd.length() > 1) {
|
||||
@@ -3931,7 +3941,7 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
|
||||
|
||||
curr.abs_axis_feedrate[a] = std::abs(curr.axis_feedrate[a]);
|
||||
if (curr.abs_axis_feedrate[a] != 0.0f) {
|
||||
float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_extruder_id);
|
||||
float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (axis_max_feedrate != 0.0f) min_feedrate_factor = std::min<float>(min_feedrate_factor, axis_max_feedrate / curr.abs_axis_feedrate[a]);
|
||||
}
|
||||
}
|
||||
@@ -3955,7 +3965,7 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
|
||||
|
||||
//BBS
|
||||
for (unsigned char a = X; a <= E; ++a) {
|
||||
float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_extruder_id);
|
||||
float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (acceleration * std::abs(delta_pos[a]) * inv_distance > axis_max_acceleration)
|
||||
acceleration = axis_max_acceleration / (std::abs(delta_pos[a]) * inv_distance);
|
||||
}
|
||||
@@ -4289,7 +4299,7 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line)
|
||||
|
||||
curr.abs_axis_feedrate[a] = std::abs(curr.axis_feedrate[a]);
|
||||
if (curr.abs_axis_feedrate[a] != 0.0f) {
|
||||
float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_extruder_id);
|
||||
float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (axis_max_feedrate != 0.0f) min_feedrate_factor = std::min<float>(min_feedrate_factor, axis_max_feedrate / curr.abs_axis_feedrate[a]);
|
||||
}
|
||||
}
|
||||
@@ -4313,7 +4323,7 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line)
|
||||
|
||||
//BBS
|
||||
for (unsigned char a = X; a <= E; ++a) {
|
||||
float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_extruder_id);
|
||||
float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (acceleration * std::abs(delta_pos[a]) * inv_distance > axis_max_acceleration)
|
||||
acceleration = axis_max_acceleration / (std::abs(delta_pos[a]) * inv_distance);
|
||||
}
|
||||
@@ -4914,6 +4924,37 @@ void GCodeProcessor::process_M106(const GCodeReader::GCodeLine& line)
|
||||
}
|
||||
}
|
||||
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
void GCodeProcessor::process_M900(const GCodeReader::GCodeLine &line)
|
||||
{
|
||||
float pa_value = m_pressure_advance;
|
||||
line.has_value('K', pa_value);
|
||||
m_pressure_advance = std::max(0.0f, pa_value);
|
||||
// BOOST_LOG_TRIVIAL(debug) << "M900 command: PA set to " << m_pressure_advance;
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M572(const GCodeReader::GCodeLine &line)
|
||||
{
|
||||
float pa_value = m_pressure_advance;
|
||||
line.has_value('S', pa_value);
|
||||
m_pressure_advance = std::max(0.0f, pa_value);
|
||||
// BOOST_LOG_TRIVIAL(debug) << "M572 command: PA set to " << m_pressure_advance;
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_SET_PRESSURE_ADVANCE(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
std::regex regex(R"(SET_PRESSURE_ADVANCE\s+(?:.*\s+)?ADVANCE\s*=\s*([\d.]+))");
|
||||
std::smatch matches;
|
||||
|
||||
if (std::regex_search(line.raw(), matches, regex) && matches.size() > 1) {
|
||||
float pa_value = 0;
|
||||
try {
|
||||
pa_value = std::stof(matches[1].str());
|
||||
} catch (...) {}
|
||||
m_pressure_advance = std::max(0.0f, pa_value);
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M107(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
m_fan_speed = 0.0f;
|
||||
@@ -5016,18 +5057,17 @@ void GCodeProcessor::process_M201(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
|
||||
float factor = ((m_flavor != gcfRepRapSprinter && m_flavor != gcfRepRapFirmware) && m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
|
||||
int indx_limit = m_time_processor.machine_limits.machine_max_acceleration_x.size() / 2;
|
||||
for (size_t index = 0; index < indx_limit; index += 2) {
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
if (static_cast<PrintEstimatedStatistics::ETimeMode>(i) == PrintEstimatedStatistics::ETimeMode::Normal || m_time_processor.machine_envelope_processing_enabled) {
|
||||
if (line.has_x()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_x, index + i, line.x() * factor);
|
||||
|
||||
if (line.has_y()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_y, index + i, line.y() * factor);
|
||||
// Write to index i (0=Normal, 1=Stealth) — matches get_axis_max_acceleration's read pattern.
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
if (static_cast<PrintEstimatedStatistics::ETimeMode>(i) == PrintEstimatedStatistics::ETimeMode::Normal || m_time_processor.machine_envelope_processing_enabled) {
|
||||
if (line.has_x()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_x, i, line.x() * factor);
|
||||
|
||||
if (line.has_z()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_z, index + i, line.z() * factor);
|
||||
if (line.has_y()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_y, i, line.y() * factor);
|
||||
|
||||
if (line.has_e()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_e, index + i, line.e() * factor);
|
||||
}
|
||||
if (line.has_z()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_z, i, line.z() * factor);
|
||||
|
||||
if (line.has_e()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_e, i, line.e() * factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5042,23 +5082,20 @@ void GCodeProcessor::process_M203(const GCodeReader::GCodeLine& line)
|
||||
// http://smoothieware.org/supported-g-codes
|
||||
float factor = (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfSmoothie || m_flavor == gcfKlipper) ? 1.0f : MMMIN_TO_MMSEC;
|
||||
|
||||
//BBS:
|
||||
int indx_limit = m_time_processor.machine_limits.machine_max_speed_x.size() / 2;
|
||||
for (size_t index = 0; index < indx_limit; index += 2) {
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
if (static_cast<PrintEstimatedStatistics::ETimeMode>(i) == PrintEstimatedStatistics::ETimeMode::Normal || m_time_processor.machine_envelope_processing_enabled) {
|
||||
if (line.has_x())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_x, index + i, line.x() * factor);
|
||||
// Write to index i (0=Normal, 1=Stealth) — matches get_axis_max_feedrate's read pattern.
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
if (static_cast<PrintEstimatedStatistics::ETimeMode>(i) == PrintEstimatedStatistics::ETimeMode::Normal || m_time_processor.machine_envelope_processing_enabled) {
|
||||
if (line.has_x())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_x, i, line.x() * factor);
|
||||
|
||||
if (line.has_y())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_y, index + i, line.y() * factor);
|
||||
if (line.has_y())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_y, i, line.y() * factor);
|
||||
|
||||
if (line.has_z())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_z, index + i, line.z() * factor);
|
||||
if (line.has_z())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_z, i, line.z() * factor);
|
||||
|
||||
if (line.has_e())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_e, index + i, line.e() * factor);
|
||||
}
|
||||
if (line.has_e())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_e, i, line.e() * factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5118,6 +5155,9 @@ void GCodeProcessor::process_M205(const GCodeReader::GCodeLine& line)
|
||||
|
||||
if (line.has_value('T', value))
|
||||
set_option_value(m_time_processor.machine_limits.machine_min_travel_rate, i, value);
|
||||
|
||||
if (line.has_value('J', value))
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, i, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5453,6 +5493,8 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type,
|
||||
m_travel_dist,
|
||||
m_fan_speed,
|
||||
m_extruder_temps[filament_id],
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
m_pressure_advance,
|
||||
{ 0.0f, 0.0f }, // time
|
||||
static_cast<float>(m_layer_id), //layer_duration: set later
|
||||
std::max<unsigned int>(1, m_layer_id) - 1,
|
||||
@@ -5499,49 +5541,94 @@ float GCodeProcessor::minimum_travel_feedrate(PrintEstimatedStatistics::ETimeMod
|
||||
return std::max(feedrate, get_option_value(m_time_processor.machine_limits.machine_min_travel_rate, static_cast<size_t>(mode)));
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_axis_max_feedrate(PrintEstimatedStatistics::ETimeMode mode, Axis axis, int extruder_id) const
|
||||
// Machine limit arrays hold 2 values: [0]=Normal, [1]=Stealth. Index by mode only.
|
||||
// BambuStudio used extruder_id*2+mode to support per-nozzle limits, but OrcaSlicer
|
||||
// never ported that system (filament_map_2 / get_config_idx_for_filament), so the
|
||||
// extruder_id offset was always wrong: uninitialized extruder (255) or extruder > 0
|
||||
// would overshoot the array and fall back to values.back() (stealth limits).
|
||||
float GCodeProcessor::get_axis_max_feedrate(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
|
||||
{
|
||||
int matched_pos = extruder_id * 2;
|
||||
switch (axis)
|
||||
{
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_x, matched_pos + static_cast<size_t>(mode)); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_y, matched_pos + static_cast<size_t>(mode)); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_z, matched_pos + static_cast<size_t>(mode)); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_e, matched_pos + static_cast<size_t>(mode)); }
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_x, static_cast<size_t>(mode)); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_y, static_cast<size_t>(mode)); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_z, static_cast<size_t>(mode)); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_e, static_cast<size_t>(mode)); }
|
||||
default: { return 0.0f; }
|
||||
}
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis, int extruder_id) const
|
||||
float GCodeProcessor::get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
|
||||
{
|
||||
int matched_pos = extruder_id * 2;
|
||||
switch (axis)
|
||||
{
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_x, matched_pos + static_cast<size_t>(mode)); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_y, matched_pos + static_cast<size_t>(mode)); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_z, matched_pos + static_cast<size_t>(mode)); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_e, matched_pos + static_cast<size_t>(mode)); }
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_x, static_cast<size_t>(mode)); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_y, static_cast<size_t>(mode)); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_z, static_cast<size_t>(mode)); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_e, static_cast<size_t>(mode)); }
|
||||
default: { return 0.0f; }
|
||||
}
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
|
||||
{
|
||||
if (axis != X && axis != Y && axis != Z && axis != E)
|
||||
return 0.0f;
|
||||
|
||||
const size_t id = static_cast<size_t>(mode);
|
||||
const float jd = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, id);
|
||||
if (jd <= 0.0f)
|
||||
return 0.0f;
|
||||
|
||||
const float axis_max_acc = get_axis_max_acceleration(mode, axis);
|
||||
const float generic_acc = get_acceleration(mode);
|
||||
const float effective_acc = axis_max_acc > 0.0f ? axis_max_acc : generic_acc;
|
||||
|
||||
return std::sqrt(jd * effective_acc * 2.5f);
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
|
||||
{
|
||||
const size_t id = static_cast<size_t>(mode);
|
||||
const float jd = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, id);
|
||||
if (m_flavor == gcfMarlinFirmware && jd > 0.0f) {
|
||||
return get_axis_max_jerk_with_jd(mode, axis);
|
||||
}
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, static_cast<size_t>(mode)); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_y, static_cast<size_t>(mode)); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_z, static_cast<size_t>(mode)); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_e, static_cast<size_t>(mode)); }
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, id); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_y, id); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_z, id); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_e, id); }
|
||||
default: { return 0.0f; }
|
||||
}
|
||||
}
|
||||
|
||||
Vec3f GCodeProcessor::get_xyz_max_jerk(PrintEstimatedStatistics::ETimeMode mode) const
|
||||
{
|
||||
return Vec3f(get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, static_cast<size_t>(mode)),
|
||||
get_option_value(m_time_processor.machine_limits.machine_max_jerk_y, static_cast<size_t>(mode)),
|
||||
get_option_value(m_time_processor.machine_limits.machine_max_jerk_z, static_cast<size_t>(mode)));
|
||||
// Default values from config
|
||||
const size_t id = static_cast<size_t>(mode);
|
||||
float jx = 0.0f;
|
||||
float jy = 0.0f;
|
||||
float jz = 0.0f;
|
||||
const float jd = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, id);
|
||||
|
||||
// Classic Jerk: Junction Deviation is only supported by Marlin firmware when using a JD value grater than 0.
|
||||
if (m_flavor != gcfMarlinFirmware || jd <= 0.0f)
|
||||
{
|
||||
jx = get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, id);
|
||||
jy = get_option_value(m_time_processor.machine_limits.machine_max_jerk_y, id);
|
||||
jz = get_option_value(m_time_processor.machine_limits.machine_max_jerk_z, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
jx = get_axis_max_jerk_with_jd(mode, X);
|
||||
jy = get_axis_max_jerk_with_jd(mode, Y);
|
||||
jz = get_axis_max_jerk_with_jd(mode, Z);
|
||||
}
|
||||
|
||||
return Vec3f(jx, jy, jz);
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const
|
||||
@@ -5897,4 +5984,3 @@ int GCodeProcessor::get_extruder_id(bool force_initialize)const
|
||||
}
|
||||
|
||||
} /* namespace Slic3r */
|
||||
|
||||
|
||||
@@ -184,6 +184,8 @@ class Print;
|
||||
float travel_dist{ 0.0f }; // mm
|
||||
float fan_speed{ 0.0f }; // percentage
|
||||
float temperature{ 0.0f }; // Celsius degrees
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
float pressure_advance{ 0.0f };
|
||||
std::array<float, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)> time{ 0.0f, 0.0f }; // s
|
||||
float layer_duration{ 0.0f }; // s
|
||||
unsigned int layer_id{ 0 };
|
||||
@@ -777,6 +779,8 @@ class Print;
|
||||
float m_travel_dist; // mm
|
||||
float m_fan_speed; // percentage
|
||||
float m_z_offset; // mm
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
float m_pressure_advance;
|
||||
ExtrusionRole m_extrusion_role;
|
||||
std::vector<int> m_filament_maps;
|
||||
std::vector<unsigned char> m_last_filament_id;
|
||||
@@ -981,6 +985,12 @@ class Print;
|
||||
// Disable fan
|
||||
void process_M107(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
// Set pressure advance
|
||||
void process_M900(const GCodeReader::GCodeLine& line);
|
||||
void process_M572(const GCodeReader::GCodeLine &line);
|
||||
void process_SET_PRESSURE_ADVANCE(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set tool (Sailfish)
|
||||
void process_M108(const GCodeReader::GCodeLine& line);
|
||||
|
||||
@@ -1059,8 +1069,12 @@ class Print;
|
||||
|
||||
float minimum_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const;
|
||||
float minimum_travel_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const;
|
||||
float get_axis_max_feedrate(PrintEstimatedStatistics::ETimeMode mode, Axis axis, int extruder_id) const;
|
||||
float get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis, int extruder_id) const;
|
||||
// Machine limit arrays are indexed by time mode only: [0]=Normal, [1]=Stealth.
|
||||
// Do NOT add an extruder_id parameter — OrcaSlicer does not use BambuStudio's
|
||||
// per-nozzle machine limits (filament_map_2 / get_config_idx_for_filament).
|
||||
float get_axis_max_feedrate(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
Vec3f get_xyz_max_jerk(PrintEstimatedStatistics::ETimeMode mode) const;
|
||||
float get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const;
|
||||
|
||||
@@ -541,10 +541,17 @@ void PressureEqualizer::output_gcode_line(const size_t line_idx)
|
||||
// We don't have enough time to accel to max possible extrusion rate
|
||||
// now we calculate the actual possible value
|
||||
target_max_extrusion_rate = std::sqrt((2 * max_sloped_extrusion * sp * sn + sn * e0_2 + sp * e1_2) / (sp + sn));
|
||||
|
||||
// Worst case: we don't have enough time to do an accl-steady-decel movement at all, fallback to the old fashion
|
||||
// single slope mode
|
||||
if (target_max_extrusion_rate <= line.volumetric_extrusion_rate_start ||
|
||||
target_max_extrusion_rate <= line.volumetric_extrusion_rate_end) {
|
||||
goto single_slope_fallback; // TODO: FIXIT: better way than a goto?
|
||||
}
|
||||
}
|
||||
assert(target_max_extrusion_rate > line.volumetric_extrusion_rate_start);
|
||||
assert(target_max_extrusion_rate > line.volumetric_extrusion_rate_end);
|
||||
assert(target_max_extrusion_rate >= line.volumetric_extrusion_rate);
|
||||
assert(target_max_extrusion_rate <= line.volumetric_extrusion_rate);
|
||||
|
||||
// if the extrusion rate change is trivial, then ignore this algorithm and use the single sloped version instead
|
||||
delta_volumetric_rate = std::round(std::min({ // important! it's MIN here not max!
|
||||
@@ -626,7 +633,7 @@ void PressureEqualizer::output_gcode_line(const size_t line_idx)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
single_slope_fallback:
|
||||
bool accelerating = line.volumetric_extrusion_rate_start < line.volumetric_extrusion_rate_end;
|
||||
float feed_avg = 0.5f * (line.pos_start[4] + line.pos_end[4]);
|
||||
// Limiting volumetric extrusion rate slope for this segment.
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
static constexpr float flat_iron_area = 4.f;
|
||||
constexpr float flat_iron_speed = 10.f * 60.f;
|
||||
static const double wipe_tower_wall_infill_overlap = 0.0;
|
||||
static constexpr double WIPE_TOWER_RESOLUTION = 0.1;
|
||||
@@ -1243,7 +1242,8 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer,
|
||||
size_t old_tool,
|
||||
bool is_finish,
|
||||
bool is_tool_change,
|
||||
float purge_volume) const
|
||||
float purge_volume,
|
||||
bool is_contact) const
|
||||
{
|
||||
ToolChangeResult result;
|
||||
result.priming = priming;
|
||||
@@ -1260,6 +1260,7 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer,
|
||||
result.is_finish_first = is_finish;
|
||||
result.nozzle_change_result = m_nozzle_change_result;
|
||||
result.is_tool_change = is_tool_change;
|
||||
result.is_contact = is_contact;
|
||||
result.tool_change_start_pos = is_tool_change ? result.start_pos : Vec2f(0, 0);
|
||||
|
||||
// BBS
|
||||
@@ -1283,6 +1284,7 @@ WipeTower::ToolChangeResult WipeTower::construct_block_tcr(WipeTowerWriter &writ
|
||||
result.wipe_path = std::move(writer.wipe_path());
|
||||
result.is_finish_first = is_finish;
|
||||
result.is_tool_change = false;
|
||||
result.is_contact = false;
|
||||
result.tool_change_start_pos = Vec2f(0, 0);
|
||||
// BBS
|
||||
result.purge_volume = purge_volume;
|
||||
@@ -1486,7 +1488,9 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi
|
||||
m_used_fillet(config.wipe_tower_fillet_wall.value),
|
||||
m_extra_spacing((float)config.prime_tower_infill_gap.value/100.f),
|
||||
m_tower_framework(config.prime_tower_enable_framework.value),
|
||||
m_flat_ironing(config.prime_tower_flat_ironing.value)
|
||||
m_flat_ironing(config.prime_tower_flat_ironing.value),
|
||||
m_enable_tower_interface_features(config.enable_tower_interface_features.value),
|
||||
m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value)
|
||||
{
|
||||
m_flat_ironing = (m_flat_ironing && m_use_gap_wall);
|
||||
// Read absolute value of first layer speed, if given as percentage,
|
||||
@@ -1546,6 +1550,16 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config)
|
||||
m_filpar[idx].nozzle_temperature = config.nozzle_temperature.get_at(idx);
|
||||
m_filpar[idx].nozzle_temperature_initial_layer = config.nozzle_temperature_initial_layer.get_at(idx);
|
||||
m_filpar[idx].category = config.filament_adhesiveness_category.get_at(idx);
|
||||
{
|
||||
int interface_temp = config.filament_tower_interface_print_temp.get_at(idx);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = config.nozzle_temperature_range_high.get_at(idx);
|
||||
m_filpar[idx].interface_print_temperature = interface_temp;
|
||||
}
|
||||
m_filpar[idx].tower_interface_pre_extrusion_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx);
|
||||
m_filpar[idx].tower_interface_pre_extrusion_length = config.filament_tower_interface_pre_extrusion_length.get_at(idx);
|
||||
m_filpar[idx].tower_ironing_area = config.filament_tower_ironing_area.get_at(idx);
|
||||
m_filpar[idx].tower_interface_purge_length = config.filament_tower_interface_purge_volume.get_at(idx);
|
||||
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
@@ -1608,7 +1622,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
|
||||
return std::vector<ToolChangeResult>();
|
||||
}
|
||||
|
||||
Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length)
|
||||
Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool interface_layer, size_t interface_tool)
|
||||
{
|
||||
const float &xl = cleaning_box.ld.x();
|
||||
const float &xr = cleaning_box.rd.x();
|
||||
@@ -1740,7 +1754,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||
}
|
||||
}
|
||||
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length);
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length, false, tool);
|
||||
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||
|
||||
if (extrude_perimeter) {
|
||||
@@ -1796,7 +1810,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume);
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume, false);
|
||||
}
|
||||
|
||||
WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int new_filament_id)
|
||||
@@ -2284,6 +2298,8 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||
bool first_layer = is_first_layer();
|
||||
// BBS: speed up perimeter speed to 90mm/s for non-first layer
|
||||
float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f);
|
||||
if (m_enable_tower_interface_features && m_prev_layer_had_interface)
|
||||
feedrate = std::min(feedrate, 20.f * 60.f);
|
||||
float fill_box_y = m_layer_info->toolchanges_depth() + m_perimeter_width;
|
||||
box_coordinates fill_box(Vec2f(m_perimeter_width, fill_box_y),
|
||||
m_wipe_tower_width - 2 * m_perimeter_width, m_layer_info->depth - fill_box_y);
|
||||
@@ -2426,7 +2442,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f);
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f, false);
|
||||
}
|
||||
|
||||
// Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box
|
||||
@@ -2646,6 +2662,7 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first,
|
||||
{
|
||||
assert(first.new_tool == second.initial_tool);
|
||||
WipeTower::ToolChangeResult out = first;
|
||||
out.is_contact = first.is_contact || second.is_contact;
|
||||
if ((first.end_pos - second.start_pos).norm() > (float)EPSILON) {
|
||||
std::string travel_gcode = "G1 X" + Slic3r::float_to_string_decimal_point(second.start_pos.x(), 3) + " Y" +
|
||||
Slic3r::float_to_string_decimal_point(second.start_pos.y(), 3) + " F5400" + "\n";
|
||||
@@ -2769,6 +2786,15 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
}
|
||||
}
|
||||
|
||||
bool interface_layer = solid_toolchange && m_enable_tower_interface_features;
|
||||
if (interface_layer && new_tool < m_filpar.size()) {
|
||||
float extra_purge_length = m_filpar[new_tool].tower_interface_purge_length;
|
||||
if (extra_purge_length > 0.f) {
|
||||
purge_volume += extra_purge_length * m_filpar[new_tool].filament_area;
|
||||
wipe_length += extra_purge_length;
|
||||
}
|
||||
}
|
||||
|
||||
WipeTowerBlock* block = get_block_by_category(m_filpar[new_tool].category, false);
|
||||
if (!block) {
|
||||
assert(block != nullptr);
|
||||
@@ -2795,7 +2821,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
|
||||
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
||||
if (new_tool != (unsigned int) -1) { // This is not the last change.
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length);
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length, interface_layer, new_tool);
|
||||
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n");
|
||||
@@ -2804,6 +2830,23 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
toolchange_Change(writer, new_tool, m_filpar[new_tool].material); // Change the tool, set a speed override for soluble and flex materials.
|
||||
toolchange_Load(writer, cleaning_box);
|
||||
|
||||
int base_temp = is_first_layer() ? m_filpar[new_tool].nozzle_temperature_initial_layer : m_filpar[new_tool].nozzle_temperature;
|
||||
if (interface_layer) {
|
||||
int interface_temp = m_filpar[new_tool].interface_print_temperature;
|
||||
if (interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(interface_temp, true);
|
||||
if (m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
float pre_dist = m_filpar[new_tool].tower_interface_pre_extrusion_dist;
|
||||
float pre_len = m_filpar[new_tool].tower_interface_pre_extrusion_length;
|
||||
if (pre_dist > 0.f && pre_len > 0.f) {
|
||||
bool start_left = (m_cur_layer_id % 4 == 0 || m_cur_layer_id % 4 == 3);
|
||||
float target_x = writer.x() + (start_left ? pre_dist : -pre_dist);
|
||||
target_x = std::max(cleaning_box.ld.x(), std::min(cleaning_box.rd.x(), target_x));
|
||||
writer.extrude_explicit(target_x, writer.y(), pre_len, 600.f);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_is_multi_extruder && is_tpu_filament(new_tool)) {
|
||||
float dy = m_layer_info->extra_spacing * m_nozzle_change_perimeter_width;
|
||||
if (m_layer_info->extra_spacing < m_tpu_fixed_spacing) {
|
||||
@@ -2838,6 +2881,13 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
|
||||
toolchange_wipe_new(writer, cleaning_box, wipe_length, solid_toolchange);
|
||||
|
||||
if (interface_layer) {
|
||||
int base_temp = is_first_layer() ? m_filpar[new_tool].nozzle_temperature_initial_layer : m_filpar[new_tool].nozzle_temperature;
|
||||
int interface_temp = m_filpar[new_tool].interface_print_temperature;
|
||||
if (!m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
}
|
||||
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n");
|
||||
++m_num_tool_changes;
|
||||
} else
|
||||
@@ -2859,7 +2909,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume);
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume, interface_layer);
|
||||
}
|
||||
|
||||
WipeTower::NozzleChangeResult WipeTower::nozzle_change_new(int old_filament_id, int new_filament_id, bool solid_infill)
|
||||
@@ -3157,7 +3207,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer_new(bool extrude_perimeter,
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
m_nozzle_change_result.gcode.clear();
|
||||
return construct_tcr(writer, false, m_current_tool, true, false, 0.f);
|
||||
return construct_tcr(writer, false, m_current_tool, true, false, 0.f, false);
|
||||
}
|
||||
|
||||
WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_fill)
|
||||
@@ -3350,6 +3400,8 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat
|
||||
}
|
||||
float retract_length = m_filpar[m_current_tool].retract_length;
|
||||
float retract_speed = m_filpar[m_current_tool].retract_speed * 60;
|
||||
const float ironing_area = m_filpar[m_current_tool].tower_ironing_area;
|
||||
const bool do_ironing = m_flat_ironing && (!solid_tool_toolchange || !m_enable_tower_interface_features);
|
||||
|
||||
const float &xl = cleaning_box.ld.x();
|
||||
const float &xr = cleaning_box.rd.x();
|
||||
@@ -3393,10 +3445,10 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat
|
||||
writer.extrude(writer.x() + ironing_length, writer.y(), wipe_speed);
|
||||
writer.retract(retract_length, retract_speed);
|
||||
writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 600.);
|
||||
if (m_flat_ironing) {
|
||||
if (do_ironing && ironing_area > 0.f) {
|
||||
writer.travel(writer.x() + 0.5f * ironing_length, writer.y(), 240.);
|
||||
Vec2f pos{writer.x() + 1.f * ironing_length, writer.y()};
|
||||
writer.spiral_flat_ironing(writer.pos(), flat_iron_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.travel(pos, wipe_speed);
|
||||
} else
|
||||
writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 240.);
|
||||
@@ -3408,10 +3460,10 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat
|
||||
writer.extrude(writer.x() - ironing_length, writer.y(), wipe_speed);
|
||||
writer.retract(retract_length, retract_speed);
|
||||
writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 600.);
|
||||
if (m_flat_ironing) {
|
||||
if (do_ironing && ironing_area > 0.f) {
|
||||
writer.travel(writer.x() - 0.5f * ironing_length, writer.y(), 240.);
|
||||
Vec2f pos{writer.x() - 1.0f * ironing_length, writer.y()};
|
||||
writer.spiral_flat_ironing(writer.pos(), flat_iron_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.travel(pos, wipe_speed);
|
||||
}else
|
||||
writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 240.);
|
||||
@@ -3837,6 +3889,8 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
|
||||
for (auto layer : m_plan) {
|
||||
reset_block_status();
|
||||
m_cur_layer_id = index++;
|
||||
m_prev_layer_had_interface = m_current_layer_has_interface;
|
||||
m_current_layer_has_interface = !solid_blocks_id.empty();
|
||||
set_layer(layer.z, layer.height, 0, false, layer.z == m_plan.back().z);
|
||||
|
||||
if (m_layer_info->depth < m_perimeter_width) continue;
|
||||
@@ -4188,7 +4242,7 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall(bool is_new_mode)
|
||||
if (!m_no_sparse_layers || toolchanges_on_layer)
|
||||
if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f);
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f, false);
|
||||
}
|
||||
|
||||
Polygon WipeTower::generate_rib_polygon(const box_coordinates &wt_box)
|
||||
|
||||
@@ -83,6 +83,7 @@ public:
|
||||
bool priming;
|
||||
|
||||
bool is_tool_change{false};
|
||||
bool is_contact{false};
|
||||
Vec2f tool_change_start_pos;
|
||||
|
||||
// Pass a polyline so that normal G-code generator can do a wipe for us.
|
||||
@@ -160,8 +161,9 @@ public:
|
||||
bool priming,
|
||||
size_t old_tool,
|
||||
bool is_finish,
|
||||
bool is_tool_change,
|
||||
float purge_volume) const;
|
||||
bool is_tool_change,
|
||||
float purge_volume,
|
||||
bool is_contact = false) const;
|
||||
|
||||
ToolChangeResult construct_block_tcr(WipeTowerWriter& writer,
|
||||
bool priming,
|
||||
@@ -319,6 +321,7 @@ public:
|
||||
bool is_support = false;
|
||||
int nozzle_temperature = 0;
|
||||
int nozzle_temperature_initial_layer = 0;
|
||||
int interface_print_temperature = 0;
|
||||
float loading_speed = 0.f;
|
||||
float loading_speed_start = 0.f;
|
||||
float unloading_speed = 0.f;
|
||||
@@ -336,6 +339,10 @@ public:
|
||||
float retract_length;
|
||||
float retract_speed;
|
||||
float wipe_dist;
|
||||
float tower_interface_pre_extrusion_dist = 0.f;
|
||||
float tower_interface_pre_extrusion_length = 0.f;
|
||||
float tower_ironing_area = 4.f;
|
||||
float tower_interface_purge_length = 0.f;
|
||||
};
|
||||
|
||||
|
||||
@@ -492,6 +499,10 @@ private:
|
||||
std::map<float,Polylines> m_outer_wall;
|
||||
bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; }
|
||||
bool m_flat_ironing=false;
|
||||
bool m_enable_tower_interface_features=false;
|
||||
bool m_enable_tower_interface_cooldown_during_tower=false;
|
||||
bool m_prev_layer_had_interface=false;
|
||||
bool m_current_layer_has_interface=false;
|
||||
// Calculates length of extrusion line to extrude given volume
|
||||
float volume_to_length(float volume, float line_width, float layer_height) const {
|
||||
return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))));
|
||||
@@ -503,7 +514,7 @@ private:
|
||||
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
|
||||
void make_wipe_tower_square();
|
||||
|
||||
Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length);
|
||||
Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool interface_layer, size_t interface_tool);
|
||||
|
||||
// Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe
|
||||
void save_on_last_wipe();
|
||||
|
||||
@@ -972,6 +972,25 @@ public:
|
||||
return add_wipe_point(Vec2f(x, y));
|
||||
}
|
||||
|
||||
void spiral_flat_ironing(const Vec2f ¢er, float area, float step_length, float feedrate)
|
||||
{
|
||||
float edge_length = std::sqrt(area);
|
||||
Vec2f box_max = center + Vec2f{step_length, step_length};
|
||||
Vec2f box_min = center - Vec2f{step_length, step_length};
|
||||
int n = std::ceil(edge_length / step_length / 2.f);
|
||||
if (n <= 0)
|
||||
return;
|
||||
while (n--) {
|
||||
travel(box_max.x(), m_current_pos.y(), feedrate);
|
||||
travel(m_current_pos.x(), box_max.y(), feedrate);
|
||||
travel(box_min.x(), m_current_pos.y(), feedrate);
|
||||
travel(m_current_pos.x(), box_min.y(), feedrate);
|
||||
|
||||
box_max += Vec2f{step_length, step_length};
|
||||
box_min -= Vec2f{step_length, step_length};
|
||||
}
|
||||
}
|
||||
|
||||
// Extrude with an explicitely provided amount of extrusion.
|
||||
WipeTowerWriter2& extrude_arc_explicit(ArcSegment& arc,
|
||||
float f = 0.f,
|
||||
@@ -1200,7 +1219,8 @@ private:
|
||||
WipeTower::ToolChangeResult WipeTower2::construct_tcr(WipeTowerWriter2& writer,
|
||||
bool priming,
|
||||
size_t old_tool,
|
||||
bool is_finish) const
|
||||
bool is_finish,
|
||||
bool is_contact) const
|
||||
{
|
||||
WipeTower::ToolChangeResult result;
|
||||
result.priming = priming;
|
||||
@@ -1215,6 +1235,7 @@ WipeTower::ToolChangeResult WipeTower2::construct_tcr(WipeTowerWriter2& writer,
|
||||
result.extrusions = std::move(writer.extrusions());
|
||||
result.wipe_path = std::move(writer.wipe_path());
|
||||
result.is_finish_first = is_finish;
|
||||
result.is_contact = is_contact;
|
||||
// ORCA: Always initialize the tool_change_start_pos with a valid position
|
||||
// to avoid undefined variable travel on X in Gcode.cpp function std::string WipeTowerIntegration::post_process_wipe_tower_moves
|
||||
result.tool_change_start_pos = result.start_pos; // always valid fallback
|
||||
@@ -1250,7 +1271,10 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau
|
||||
m_used_fillet(config.wipe_tower_fillet_wall),
|
||||
m_rib_width(config.wipe_tower_rib_width),
|
||||
m_extra_rib_length(config.wipe_tower_extra_rib_length),
|
||||
m_wall_type((int)config.wipe_tower_wall_type)
|
||||
m_wall_type((int)config.wipe_tower_wall_type),
|
||||
m_flat_ironing(config.prime_tower_flat_ironing.value),
|
||||
m_enable_tower_interface_features(config.enable_tower_interface_features.value),
|
||||
m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value)
|
||||
{
|
||||
// Read absolute value of first layer speed, if given as percentage,
|
||||
// it is taken over following default. Speeds from config are not
|
||||
@@ -1317,6 +1341,16 @@ void WipeTower2::set_extruder(size_t idx, const PrintConfig& config)
|
||||
m_filpar[idx].temperature = config.nozzle_temperature.get_at(idx);
|
||||
m_filpar[idx].first_layer_temperature = config.nozzle_temperature_initial_layer.get_at(idx);
|
||||
m_filpar[idx].filament_minimal_purge_on_wipe_tower = config.filament_minimal_purge_on_wipe_tower.get_at(idx);
|
||||
{
|
||||
int interface_temp = config.filament_tower_interface_print_temp.get_at(idx);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = config.nozzle_temperature_range_high.get_at(idx);
|
||||
m_filpar[idx].interface_print_temperature = interface_temp;
|
||||
}
|
||||
m_filpar[idx].tower_interface_pre_extrusion_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx);
|
||||
m_filpar[idx].tower_interface_pre_extrusion_length = config.filament_tower_interface_pre_extrusion_length.get_at(idx);
|
||||
m_filpar[idx].tower_ironing_area = config.filament_tower_ironing_area.get_at(idx);
|
||||
m_filpar[idx].tower_interface_purge_length = config.filament_tower_interface_purge_volume.get_at(idx);
|
||||
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
@@ -1440,11 +1474,11 @@ std::vector<WipeTower::ToolChangeResult> WipeTower2::prime(
|
||||
toolchange_Load(writer, cleaning_box); // Prime the tool.
|
||||
if (idx_tool + 1 == tools.size()) {
|
||||
// Last tool should not be unloaded, but it should be wiped enough to become of a pure color.
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volumes[tools[idx_tool-1]][tool]);
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volumes[tools[idx_tool-1]][tool], false);
|
||||
} else {
|
||||
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
||||
//writer.travel(writer.x(), writer.y() + m_perimeter_width, 7200);
|
||||
toolchange_Wipe(writer, cleaning_box , 20.f);
|
||||
toolchange_Wipe(writer, cleaning_box , 20.f, false);
|
||||
WipeTower::box_coordinates box = cleaning_box;
|
||||
box.translate(0.f, writer.y() - cleaning_box.ld.y() + m_perimeter_width);
|
||||
toolchange_Unload(writer, box , m_filpar[m_current_tool].material, m_filpar[m_current_tool].first_layer_temperature, m_filpar[tools[idx_tool + 1]].first_layer_temperature);
|
||||
@@ -1472,7 +1506,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower2::prime(
|
||||
"\n\n");
|
||||
}
|
||||
|
||||
results.emplace_back(construct_tcr(writer, true, old_tool, true));
|
||||
results.emplace_back(construct_tcr(writer, true, old_tool, true, false));
|
||||
}
|
||||
|
||||
m_old_temperature = -1; // If the priming is turned off in config, the temperature changing commands will not actually appear
|
||||
@@ -1487,6 +1521,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
|
||||
float wipe_area = 0.f;
|
||||
float wipe_volume = 0.f;
|
||||
bool interface_layer = m_enable_tower_interface_features && m_current_layer_has_interface;
|
||||
|
||||
// Finds this toolchange info
|
||||
if (tool != (unsigned int)(-1))
|
||||
@@ -1501,6 +1536,12 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
else {
|
||||
// Otherwise we are going to Unload only. And m_layer_info would be invalid.
|
||||
}
|
||||
if (interface_layer && tool != (unsigned int)(-1) && tool < m_filpar.size()) {
|
||||
float extra_purge_length = m_filpar[tool].tower_interface_purge_length;
|
||||
if (extra_purge_length > 0.f) {
|
||||
wipe_volume += extra_purge_length * m_filpar[tool].filament_area;
|
||||
}
|
||||
}
|
||||
|
||||
WipeTower::box_coordinates cleaning_box(
|
||||
Vec2f(m_perimeter_width / 2.f, m_perimeter_width / 2.f),
|
||||
@@ -1542,7 +1583,27 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials.
|
||||
toolchange_Load(writer, cleaning_box);
|
||||
writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volume); // Wipe the newly loaded filament until the end of the assigned wipe area.
|
||||
int base_temp = is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature;
|
||||
if (interface_layer) {
|
||||
int interface_temp = m_filpar[tool].interface_print_temperature;
|
||||
if (interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(interface_temp, true);
|
||||
if (m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
float pre_dist = m_filpar[tool].tower_interface_pre_extrusion_dist;
|
||||
float pre_len = m_filpar[tool].tower_interface_pre_extrusion_length;
|
||||
if (pre_dist > 0.f && pre_len > 0.f) {
|
||||
float target_x = writer.x() + pre_dist;
|
||||
target_x = std::max(cleaning_box.ld.x(), std::min(cleaning_box.rd.x(), target_x));
|
||||
writer.extrude_explicit(target_x, writer.y(), pre_len, 600.f);
|
||||
}
|
||||
}
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volume, interface_layer); // Wipe the newly loaded filament until the end of the assigned wipe area.
|
||||
if (interface_layer) {
|
||||
int interface_temp = m_filpar[tool].interface_print_temperature;
|
||||
if (!m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
}
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n");
|
||||
++ m_num_tool_changes;
|
||||
} else
|
||||
@@ -1564,7 +1625,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, false);
|
||||
return construct_tcr(writer, false, old_tool, false, interface_layer);
|
||||
}
|
||||
|
||||
|
||||
@@ -1854,7 +1915,8 @@ void WipeTower2::toolchange_Load(
|
||||
void WipeTower2::toolchange_Wipe(
|
||||
WipeTowerWriter2 &writer,
|
||||
const WipeTower::box_coordinates &cleaning_box,
|
||||
float wipe_volume)
|
||||
float wipe_volume,
|
||||
bool interface_layer)
|
||||
{
|
||||
// Increase flow on first layer, slow down print.
|
||||
writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? 1.18f : 1.f))
|
||||
@@ -1884,6 +1946,9 @@ void WipeTower2::toolchange_Wipe(
|
||||
m_left_to_right = !m_left_to_right;
|
||||
}
|
||||
|
||||
const bool do_ironing = m_flat_ironing && (!interface_layer || !m_enable_tower_interface_features);
|
||||
const float ironing_area = m_filpar[m_current_tool].tower_ironing_area;
|
||||
|
||||
// now the wiping itself:
|
||||
for (int i = 0; true; ++i) {
|
||||
if (i!=0) {
|
||||
@@ -1899,6 +1964,11 @@ void WipeTower2::toolchange_Wipe(
|
||||
else
|
||||
writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*line_width), writer.y(), wipe_speed);
|
||||
|
||||
if (i == 0 && do_ironing && ironing_area > 0.f) {
|
||||
writer.travel(writer.x(), writer.y(), 600.f);
|
||||
writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, 10.f * 60.f);
|
||||
}
|
||||
|
||||
if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*line_width)
|
||||
break; // in case next line would not fit
|
||||
|
||||
@@ -1943,10 +2013,12 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer()
|
||||
.set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f));
|
||||
|
||||
|
||||
// Slow down on the 1st layer.
|
||||
// Slow down on the 1st layer.
|
||||
// If spare layers are excluded -> if 1 or less toolchange has been done, it must be still the first layer, too. So slow down.
|
||||
bool first_layer = is_first_layer() || (m_num_tool_changes <= 1 && m_no_sparse_layers);
|
||||
float feedrate = first_layer ? m_first_layer_speed * 60.f : std::min(m_wipe_tower_max_purge_speed * 60.f, m_infill_speed * 60.f);
|
||||
if (m_enable_tower_interface_features && m_prev_layer_had_interface)
|
||||
feedrate = std::min(feedrate, 20.f * 60.f);
|
||||
float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth();
|
||||
WipeTower::box_coordinates fill_box(Vec2f(m_perimeter_width, m_layer_info->depth-(current_depth-m_perimeter_width)),
|
||||
m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width);
|
||||
@@ -2062,6 +2134,11 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer()
|
||||
// Save actual brim width to be later passed to the Print object, which will use it
|
||||
// for skirt calculation and pass it to GLCanvas for precise preview box
|
||||
m_wipe_tower_brim_width_real = loops_num * spacing;
|
||||
|
||||
// Compute actual first-layer bounding box from the outermost brim polygon,
|
||||
// matching how WipeTower::get_bbx() uses m_outer_wall extents.
|
||||
BoundingBox first_layer_box = get_extents(poly);
|
||||
m_first_layer_bbx = BoundingBoxf(unscale(first_layer_box.min), unscale(first_layer_box.max));
|
||||
}
|
||||
|
||||
// Now prepare future wipe.
|
||||
@@ -2077,7 +2154,7 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer()
|
||||
m_current_height += m_layer_info->height;
|
||||
}
|
||||
|
||||
return construct_tcr(writer, false, old_tool, true);
|
||||
return construct_tcr(writer, false, old_tool, true, false);
|
||||
}
|
||||
|
||||
// Static method to get the radius and x-scaling of the stabilizing cone base.
|
||||
@@ -2156,7 +2233,18 @@ void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned i
|
||||
float first_wipe_line = - (width*((length_to_extrude / width)-int(length_to_extrude / width)) - width);
|
||||
|
||||
float first_wipe_volume = length_to_volume(first_wipe_line, m_perimeter_width * m_extra_flow, layer_height_par);
|
||||
float wiping_depth = get_wipe_depth(wipe_volume - first_wipe_volume, layer_height_par, m_perimeter_width, m_extra_flow, m_extra_spacing_wipe, width);
|
||||
|
||||
// ORCA: Keep wipe-depth planning consistent with toolchange_Wipe().
|
||||
// ORCA: On the first layer, toolchange_Wipe() advances purge rows using
|
||||
// ORCA: m_extra_flow * m_perimeter_width, while later layers use
|
||||
// ORCA: m_extra_spacing_wipe * m_perimeter_width.
|
||||
// ORCA: float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width;
|
||||
// ORCA: Use the same spacing here so reserved depth matches consumed depth
|
||||
// ORCA: and first-layer purge segments do not leave visible gaps.
|
||||
const bool first_layer_plan = (m_plan.size() - 1) == m_first_layer_idx;
|
||||
const float planning_spacing = first_layer_plan ? m_extra_flow : m_extra_spacing_wipe;
|
||||
|
||||
float wiping_depth = get_wipe_depth(wipe_volume - first_wipe_volume, layer_height_par, m_perimeter_width, m_extra_flow, planning_spacing, width);
|
||||
|
||||
m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, ramming_depth + wiping_depth, ramming_depth, first_wipe_line, wipe_volume));
|
||||
}
|
||||
@@ -2213,7 +2301,18 @@ void WipeTower2::save_on_last_wipe()
|
||||
float volume_to_save = length_to_volume(finish_layer().total_extrusion_length_in_plane(), m_perimeter_width, m_layer_info->height);
|
||||
float volume_left_to_wipe = std::max(m_filpar[toolchange.new_tool].filament_minimal_purge_on_wipe_tower, toolchange.wipe_volume_total - volume_to_save);
|
||||
float volume_we_need_depth_for = std::max(0.f, volume_left_to_wipe - length_to_volume(toolchange.first_wipe_line, m_perimeter_width*m_extra_flow, m_layer_info->height));
|
||||
float depth_to_wipe = get_wipe_depth(volume_we_need_depth_for, m_layer_info->height, m_perimeter_width, m_extra_flow, m_extra_spacing_wipe, width);
|
||||
|
||||
// ORCA: Keep wipe-depth planning consistent with toolchange_Wipe().
|
||||
// ORCA: On the first layer, toolchange_Wipe() advances purge rows using
|
||||
// ORCA: m_extra_flow * m_perimeter_width, while later layers use
|
||||
// ORCA: m_extra_spacing_wipe * m_perimeter_width.
|
||||
// ORCA: float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width;
|
||||
// ORCA: Use the same spacing here so reserved depth matches consumed depth
|
||||
// ORCA: and first-layer purge segments do not leave visible gaps.
|
||||
const bool first_layer_plan = size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx;
|
||||
const float planning_spacing = first_layer_plan ? m_extra_flow : m_extra_spacing_wipe;
|
||||
|
||||
float depth_to_wipe = get_wipe_depth(volume_we_need_depth_for, m_layer_info->height, m_perimeter_width, m_extra_flow, planning_spacing, width);
|
||||
|
||||
toolchange.required_depth = toolchange.ramming_depth + depth_to_wipe;
|
||||
toolchange.wipe_volume = volume_left_to_wipe;
|
||||
@@ -2245,6 +2344,7 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first,
|
||||
{
|
||||
assert(first.new_tool == second.initial_tool);
|
||||
WipeTower::ToolChangeResult out = first;
|
||||
out.is_contact = first.is_contact || second.is_contact;
|
||||
if (first.end_pos != second.start_pos)
|
||||
out.gcode += "G1 X" + Slic3r::float_to_string_decimal_point(second.start_pos.x(), 3)
|
||||
+ " Y" + Slic3r::float_to_string_decimal_point(second.start_pos.y(), 3)
|
||||
|
||||
@@ -31,7 +31,8 @@ public:
|
||||
WipeTower::ToolChangeResult construct_tcr(WipeTowerWriter2& writer,
|
||||
bool priming,
|
||||
size_t old_tool,
|
||||
bool is_finish) const;
|
||||
bool is_finish,
|
||||
bool is_contact = false) const;
|
||||
|
||||
// x -- x coordinates of wipe tower in mm ( left bottom corner )
|
||||
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
||||
@@ -60,16 +61,19 @@ public:
|
||||
float get_wipe_tower_height() const { return m_wipe_tower_height; }
|
||||
// ORCA: Match WipeTower API used by Print skirt/brim planning.
|
||||
// Returned bounding box is in WIPE-TOWER-LOCAL coordinates (before placement on the bed).
|
||||
// Include brim and y-shift to match what WT gcode actually prints.
|
||||
BoundingBoxf get_bbx() const{
|
||||
// Computed from the actual first-layer polygon (including brim), like WipeTower::get_bbx().
|
||||
BoundingBoxf get_bbx() const {
|
||||
if (m_first_layer_bbx.defined)
|
||||
return m_first_layer_bbx;
|
||||
// Fallback: nominal rectangle (used if generate() hasn't run yet)
|
||||
const float brim = m_wipe_tower_brim_width_real;
|
||||
const Vec2d min(-brim, -brim + double(m_y_shift));
|
||||
const Vec2d max(double(m_wipe_tower_width) + brim, double(m_wipe_tower_depth) + brim + double(m_y_shift));
|
||||
return BoundingBoxf(min, max);
|
||||
return BoundingBoxf(Vec2d(-brim, -brim), Vec2d(double(m_wipe_tower_width) + brim, double(m_wipe_tower_depth) + brim));
|
||||
}
|
||||
// WT2 doesn't currently compute a rib-origin compensation like WipeTower (m_rib_offset),
|
||||
// so expose a zero offset for consistency purposes (to maintain API parity).
|
||||
Vec2f get_rib_offset() const { return Vec2f::Zero(); }
|
||||
float get_rib_width() const { return m_rib_width; }
|
||||
float get_rib_length() const { return m_rib_length; }
|
||||
|
||||
// Switch to a next layer.
|
||||
void set_layer(
|
||||
@@ -88,11 +92,13 @@ public:
|
||||
m_layer_height = layer_height;
|
||||
m_depth_traversed = 0.f;
|
||||
m_current_layer_finished = false;
|
||||
m_prev_layer_had_interface = m_current_layer_has_interface;
|
||||
|
||||
|
||||
// Advance m_layer_info iterator, making sure we got it right
|
||||
while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end())
|
||||
++m_layer_info;
|
||||
m_current_layer_has_interface = (m_layer_info != m_plan.end()) && (m_layer_info->toolchanges_depth() > WT_EPSILON);
|
||||
|
||||
//m_current_shape = (! this->is_first_layer() && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
|
||||
m_current_shape = SHAPE_NORMAL;
|
||||
@@ -145,6 +151,7 @@ public:
|
||||
bool is_soluble = false;
|
||||
int temperature = 0;
|
||||
int first_layer_temperature = 0;
|
||||
int interface_print_temperature = 0;
|
||||
float loading_speed = 0.f;
|
||||
float loading_speed_start = 0.f;
|
||||
float unloading_speed = 0.f;
|
||||
@@ -168,6 +175,10 @@ public:
|
||||
float filament_minimal_purge_on_wipe_tower = 0.f;
|
||||
float retract_length;
|
||||
float retract_speed;
|
||||
float tower_interface_pre_extrusion_dist = 0.f;
|
||||
float tower_interface_pre_extrusion_length = 0.f;
|
||||
float tower_ironing_area = 4.f;
|
||||
float tower_interface_purge_length = 0.f;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -195,6 +206,7 @@ private:
|
||||
float m_wipe_tower_cone_angle = 0.f;
|
||||
float m_wipe_tower_brim_width = 0.f; // Width of brim (mm) from config
|
||||
float m_wipe_tower_brim_width_real = 0.f; // Width of brim (mm) after generation
|
||||
BoundingBoxf m_first_layer_bbx; // Actual first-layer bounding box (incl. brim/ribs)
|
||||
float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis)
|
||||
float m_internal_rotation = 0.f;
|
||||
float m_y_shift = 0.f; // y shift passed to writer
|
||||
@@ -208,6 +220,11 @@ private:
|
||||
float m_perimeter_speed = 0.f;
|
||||
float m_first_layer_speed = 0.f;
|
||||
size_t m_first_layer_idx = size_t(-1);
|
||||
bool m_flat_ironing = false;
|
||||
bool m_enable_tower_interface_features = false;
|
||||
bool m_enable_tower_interface_cooldown_during_tower = false;
|
||||
bool m_prev_layer_had_interface = false;
|
||||
bool m_current_layer_has_interface = false;
|
||||
|
||||
int m_wall_type;
|
||||
bool m_used_fillet = true;
|
||||
@@ -335,7 +352,8 @@ private:
|
||||
void toolchange_Wipe(
|
||||
WipeTowerWriter2 &writer,
|
||||
const WipeTower::box_coordinates &cleaning_box,
|
||||
float wipe_volume);
|
||||
float wipe_volume,
|
||||
bool interface_layer);
|
||||
|
||||
|
||||
Polygon generate_support_rib_wall(WipeTowerWriter2& writer,
|
||||
|
||||
Reference in New Issue
Block a user