Merge branch 'main' into feature/filament_id

This commit is contained in:
SoftFever
2026-09-02 15:34:20 +08:00
49 changed files with 3625 additions and 134 deletions

View File

@@ -10,6 +10,7 @@
#include <string>
#include <boost/log/trivial.hpp>
#include <boost/nowide/fstream.hpp>
#ifdef _WIN32
#define DIR_SEPARATOR '\\'

View File

@@ -8197,9 +8197,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
}
variable_speed = std::any_of(new_points.begin(), new_points.end(),
[speed](const ProcessedPoint &p) { return fabs(double(p.speed) - speed) > 1; }); // Ignore small speed variations (under 1mm/sec)
if (!NOZZLE_CONFIG(enable_overhang_speed) && FILAMENT_CONFIG(enable_overhang_bridge_fan) && m_enable_cooling_markers) {
for (ProcessedPoint &point : new_points)
point.speed = speed;
if (FILAMENT_CONFIG(enable_overhang_bridge_fan) && m_enable_cooling_markers) {
if (!NOZZLE_CONFIG(enable_overhang_speed))
for (ProcessedPoint &point : new_points)
point.speed = speed;
variable_speed = new_points.size() > 1;
}
}

View File

@@ -1024,28 +1024,29 @@ std::string CoolingBuffer::apply_layer_cooldown(
}
if (need_set_fan) {
const auto set_fan = [&](int speed) {
if (m_current_fan_speed != speed) {
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, speed, part_cooling_fan_min_pwm);
m_current_fan_speed = speed;
}
};
if (fan_speed_change_requests[CoolingLine::TYPE_OVERHANG_FAN_START]){
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, overhang_fan_speed, part_cooling_fan_min_pwm);
m_current_fan_speed = overhang_fan_speed;
set_fan(overhang_fan_speed);
} else if (fan_speed_change_requests[CoolingLine::TYPE_INTERNAL_BRIDGE_FAN_START]){ // ORCA: Add support for separate internal bridge fan speed control
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, internal_bridge_fan_speed, part_cooling_fan_min_pwm);
m_current_fan_speed = internal_bridge_fan_speed;
set_fan(internal_bridge_fan_speed);
}
else if (fan_speed_change_requests[CoolingLine::TYPE_SUPPORT_INTERFACE_FAN_START]){
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, supp_interface_fan_speed, part_cooling_fan_min_pwm);
m_current_fan_speed = supp_interface_fan_speed;
set_fan(supp_interface_fan_speed);
}
else if (fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]){
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, ironing_fan_speed, part_cooling_fan_min_pwm);
m_current_fan_speed = ironing_fan_speed;
set_fan(ironing_fan_speed);
}
else if(fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] && m_current_fan_speed != -1){
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_current_fan_speed, part_cooling_fan_min_pwm);
fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] = false;
}
else {
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_fan_speed, part_cooling_fan_min_pwm);
m_current_fan_speed = m_fan_speed;
set_fan(m_fan_speed);
}
need_set_fan = false;
}

View File

@@ -170,14 +170,13 @@ void FanMover::_put_in_middle_G1(std::list<BufferData>::iterator item_to_split,
void FanMover::_print_in_middle_G1(BufferData& line_to_split, float nb_sec, const std::string &line_to_write) {
if (nb_sec < line_to_split.time * 0.1) {
// doesn't really need to be split, print it after
m_process_output += line_to_split.raw + "\n";
// Doesn't need to be split: the insertion point is at the start.
m_process_output += line_to_write + (line_to_write.back() == '\n'?"":"\n");
} else if (nb_sec > line_to_split.time * 0.9) {
// doesn't really need to be split, print it before
//will also print before if line_to_split.time == 0
m_process_output += line_to_write + (line_to_write.back() == '\n' ? "" : "\n");
m_process_output += line_to_split.raw + "\n";
} else if (nb_sec > line_to_split.time * 0.9) {
// Doesn't need to be split: the insertion point is at the end.
m_process_output += line_to_split.raw + "\n";
m_process_output += line_to_write + (line_to_write.back() == '\n' ? "" : "\n");
}else if(line_to_split.raw.size() > 2
&& line_to_split.raw[0] == 'G' && line_to_split.raw[1] == '1' && line_to_split.raw[2] == ' ') {
float percent = nb_sec / line_to_split.time;

View File

@@ -532,7 +532,7 @@ void GCodeProcessor::TimeMachine::calculate_time(GCodeProcessorResult& result, P
const float height = interpolate ? lerp(prev_move.height, curr_move.height, t) : curr_move.height;
// ORCA: Fix issue with flow rate changes being visualized incorrectly
const float mm3_per_mm = curr_move.mm3_per_mm;
const float fan_speed = interpolate ? lerp(prev_move.fan_speed, curr_move.fan_speed, t) : curr_move.fan_speed;
const float fan_speed = curr_move.fan_speed;
const float temperature = interpolate ? lerp(prev_move.temperature, curr_move.temperature, t) : curr_move.temperature;
actual_speed_moves.push_back({
block.move_id,
@@ -563,7 +563,7 @@ void GCodeProcessor::TimeMachine::calculate_time(GCodeProcessorResult& result, P
const float height = interpolate ? lerp(prev_move.height, curr_move.height, t) : curr_move.height;
// ORCA: Fix issue with flow rate changes being visualized incorrectly
const float mm3_per_mm = curr_move.mm3_per_mm;
const float fan_speed = interpolate ? lerp(prev_move.fan_speed, curr_move.fan_speed, t) : curr_move.fan_speed;
const float fan_speed = curr_move.fan_speed;
const float temperature = interpolate ? lerp(prev_move.temperature, curr_move.temperature, t) : curr_move.temperature;
actual_speed_moves.push_back({
block.move_id,

View File

@@ -10091,6 +10091,10 @@ int DynamicPrintConfig::update_values_from_single_to_multi(DynamicPrintConfig& m
for (int index = 0; index < variant_count; index++)
{
//variant_count is the variant column width, src_opt the value array;
//they disagree when the source was authored at a different width
if (index >= (int)src_opt->values.size())
break;
if (opt->values[index] > src_opt->values[index])
opt->values[index] = src_opt->values[index];
}
@@ -10108,6 +10112,8 @@ int DynamicPrintConfig::update_values_from_single_to_multi(DynamicPrintConfig& m
for (int index = 0; index < variant_count; index++)
{
if (index >= (int)src_opt->values.size())
break;
if (opt->values[index].value > src_opt->values[index].value)
opt->values[index] = src_opt->values[index];
}
@@ -10302,6 +10308,10 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne
for(auto idx : variant_indices){
assert(idx < old_count);
//the counts come from the variant columns, the arrays from the options;
//they disagree when a config was authored at a different variant width
if (idx >= old_count || new_variant_index >= (int)opt->values.size())
continue;
if (old_values[idx] < opt->values[new_variant_index])
opt->values[new_variant_index] = old_values[idx];
}
@@ -10332,6 +10342,10 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne
for(auto idx : variant_indices){
assert(idx < old_count);
//the counts come from the variant columns, the arrays from the options;
//they disagree when a config was authored at a different variant width
if (idx >= old_count || new_variant_index >= (int)opt->values.size())
continue;
if (old_values[idx] < opt->values[new_variant_index])
opt->values[new_variant_index] = old_values[idx];
}
@@ -10362,6 +10376,8 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne
for(auto idx : variant_indices){
assert(idx < old_count);
if (idx >= old_count || new_variant_index >= (int)opt->values.size())
continue;
if (old_values[idx]) //enabled
opt->values[new_variant_index] = old_values[idx];
}
@@ -10402,6 +10418,15 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
same_variant_indices.emplace_back(indices);
}
//dst_values below is the destination PRINT preset's per-variant row, sized to its own
//print_extruder_variant; dst_extruder_variants is the PRINTER's list. They disagree until
//the print preset is re-selected, so size the row to the variant count before indexing it.
const size_t dst_variant_count = dst_extruder_variants.size();
if (dst_variant_count == 0) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", Line %1%: empty destination variant list")%__LINE__;
return -1;
}
t_config_option_keys keys = this->keys();
for(auto& key : keys){
if(key_sets.find(key) == key_sets.end())
@@ -10417,7 +10442,13 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
{
ConfigOptionFloatsNullable* opt = this->option<ConfigOptionFloatsNullable>(key);
auto src_values = opt->values;
auto dst_values = dst_config.option<ConfigOptionFloatsNullable>(key) ->values;
const auto* dst_opt = dst_config.option<ConfigOptionFloatsNullable>(key);
if(!dst_opt){
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key;
break;
}
auto dst_values = dst_opt->values;
dst_values.resize(dst_variant_count, ConfigOptionFloatsNullable::nil_value());
for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){
auto& indices = same_variant_indices[dst_idx];
if(indices.empty())
@@ -10425,7 +10456,7 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
bool has_value = false;
double target_value = std::numeric_limits<double>::max();
for(auto idx : indices){
if(opt && idx < opt->values.size() && !opt->is_nil(idx)){
if(idx < (int)opt->values.size() && !opt->is_nil(idx)){
has_value = true;
target_value = std::min(target_value, src_values[idx]);
}
@@ -10441,7 +10472,13 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
{
ConfigOptionFloatsOrPercentsNullable* opt = this->option<ConfigOptionFloatsOrPercentsNullable>(key);
auto src_values = opt->values;
auto dst_values = dst_config.option<ConfigOptionFloatsOrPercentsNullable>(key) ->values;
const auto* dst_opt = dst_config.option<ConfigOptionFloatsOrPercentsNullable>(key);
if(!dst_opt){
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key;
break;
}
auto dst_values = dst_opt->values;
dst_values.resize(dst_variant_count, ConfigOptionFloatsOrPercentsNullable::nil_value());
for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){
auto& indices = same_variant_indices[dst_idx];
if(indices.empty())
@@ -10449,7 +10486,7 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
bool has_value = false;
FloatOrPercent target_value{9999.f, true};
for(auto idx : indices){
if(opt && !opt->is_nil(idx)){
if(idx < (int)opt->values.size() && !opt->is_nil(idx)){
has_value = true;
target_value = src_values[idx].value < target_value.value ? src_values[idx] : target_value;
}
@@ -10465,15 +10502,21 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
{
ConfigOptionBoolsNullable* opt = this->option<ConfigOptionBoolsNullable>(key);
auto src_values = opt->values;
auto dst_values = dst_config.option<ConfigOptionBoolsNullable>(key) ->values;
const auto* dst_opt = dst_config.option<ConfigOptionBoolsNullable>(key);
if(!dst_opt){
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key;
break;
}
auto dst_values = dst_opt->values;
dst_values.resize(dst_variant_count, ConfigOptionBoolsNullable::nil_value());
for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){
auto indices = same_variant_indices[dst_idx];
if(indices.empty())
continue;
bool has_value = false;
bool target_value;
bool target_value = false;
for(auto idx : indices){
if(opt && !opt->is_nil(idx)){
if(idx < (int)opt->values.size() && !opt->is_nil(idx)){
has_value = true;
target_value = src_values[idx];
break;

View File

@@ -453,7 +453,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
if (config->opt_bool("alternate_extra_wall") &&
(config->opt_enum<EnsureVerticalShellThickness>("ensure_vertical_shell_thickness") == evstAll)) {
wxString msg_text = _(L("Alternate extra wall does't work well when ensure vertical shell thickness is set to All."));
wxString msg_text = _(L("Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All."));
if (is_global_config)
msg_text += "\n\n" + _(L("Change these settings automatically?\n"
@@ -642,7 +642,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
if (config->opt_enum<SeamScarfType>("seam_slope_type") != SeamScarfType::None &&
config->get_abs_value("seam_slope_start_height") >= layer_height) {
const wxString msg_text = _(L("seam_slope_start_height need to be smaller than layer_height.\nReset to 0."));
const wxString msg_text = _(L("seam_slope_start_height needs to be smaller than layer_height.\nReset to 0."));
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
@@ -656,7 +656,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
float skin_depth = config->opt_float("skin_infill_depth");
if (config->opt_float("infill_lock_depth") > skin_depth) {
// xgettext:no-c-format, no-boost-format
const wxString msg_text = _(L("Lock depth should smaller than skin depth.\nReset to 50% of skin depth."));
const wxString msg_text = _(L("Lock depth should be smaller than skin depth.\nReset to 50% of skin depth."));
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;

View File

@@ -12,6 +12,7 @@
#include "libslic3r/MeshBoolean.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/Format/bbs_3mf.hpp"
#include "libslic3r/format.hpp"
#include "libslic3r/Thread.hpp"
#include "../GUI/I18N.hpp"
@@ -69,6 +70,9 @@ public:
// Returns false if fixing was canceled. fix_result contains error message if failed.
bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::ProgressDialog &progress_dialog, const wxString &msg_header, std::string &fix_result, bool keep_painting)
{
// Hold SaveObjectGaurd to prevent backup manager from racing concurrent mesh mutations (use-after-free).
SaveObjectGaurd backup_gaurd(model_object);
// Orca: Synchronization primitives for progress updates between worker thread and GUI.
std::mutex mtx;
std::condition_variable condition;