mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-23 17:02:39 +00:00
Merge branch '2.3.0' into dev_2.3.0_alves
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include "libslic3r.h"
|
||||
#include "clonable_ptr.hpp"
|
||||
@@ -39,6 +40,12 @@ namespace Slic3r {
|
||||
inline bool operator==(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value == r.value && l.percent == r.percent; }
|
||||
inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return !(l == r); }
|
||||
inline bool operator< (const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value < r.value || (l.value == r.value && int(l.percent) < int(r.percent)); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const FloatOrPercent& v) {
|
||||
os << v.value;
|
||||
if (v.percent)
|
||||
os << "%";
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
||||
namespace std {
|
||||
@@ -415,22 +422,63 @@ public:
|
||||
// This function is useful to split values from multiple extrder / filament settings into separate configurations.
|
||||
void set_at(const ConfigOption *rhs, size_t i, size_t j) override
|
||||
{
|
||||
// SM Orca: Debug logging
|
||||
BOOST_LOG_TRIVIAL(error) << "ConfigOptionVector::set_at: START - this->values.size()=" << this->values.size()
|
||||
<< ", i=" << i << ", j=" << j;
|
||||
|
||||
// It is expected that the vector value has at least one value, which is the default, if not overwritten.
|
||||
assert(! this->values.empty());
|
||||
if (this->values.size() <= i) {
|
||||
// Resize this vector, fill in the new vector fields with the copy of the first field.
|
||||
T v = this->values.front();
|
||||
this->values.resize(i + 1, v);
|
||||
BOOST_LOG_TRIVIAL(error) << "ConfigOptionVector::set_at: resized to " << this->values.size();
|
||||
}
|
||||
|
||||
if (rhs->type() == this->type()) {
|
||||
// Assign the first value of the rhs vector.
|
||||
auto other = static_cast<const ConfigOptionVector<T>*>(rhs);
|
||||
if (other->values.empty())
|
||||
throw ConfigurationError("ConfigOptionVector::set_at(): Assigning from an empty vector");
|
||||
|
||||
// Log before assignment
|
||||
std::stringstream before_ss;
|
||||
before_ss << "[";
|
||||
for (size_t k = 0; k < this->values.size(); ++k) {
|
||||
if (k > 0) before_ss << ", ";
|
||||
before_ss << this->values[k];
|
||||
}
|
||||
before_ss << "]";
|
||||
BOOST_LOG_TRIVIAL(error) << "ConfigOptionVector::set_at: before this->values=" << before_ss.str();
|
||||
|
||||
// Log other vector
|
||||
std::stringstream other_ss;
|
||||
other_ss << "[";
|
||||
for (size_t k = 0; k < other->values.size(); ++k) {
|
||||
if (k > 0) other_ss << ", ";
|
||||
other_ss << other->values[k];
|
||||
}
|
||||
other_ss << "]";
|
||||
BOOST_LOG_TRIVIAL(error) << "ConfigOptionVector::set_at: other->values=" << other_ss.str()
|
||||
<< ", other->get_at(" << j << ")=" << other->get_at(j);
|
||||
|
||||
this->values[i] = other->get_at(j);
|
||||
} else if (rhs->type() == this->scalar_type())
|
||||
|
||||
// Log after assignment
|
||||
std::stringstream after_ss;
|
||||
after_ss << "[";
|
||||
for (size_t k = 0; k < this->values.size(); ++k) {
|
||||
if (k > 0) after_ss << ", ";
|
||||
after_ss << this->values[k];
|
||||
}
|
||||
after_ss << "]";
|
||||
BOOST_LOG_TRIVIAL(error) << "ConfigOptionVector::set_at: after this->values[" << i << "]=" << this->values[i]
|
||||
<< ", full=" << after_ss.str();
|
||||
|
||||
} else if (rhs->type() == this->scalar_type()) {
|
||||
this->values[i] = static_cast<const ConfigOptionSingle<T>*>(rhs)->value;
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(error) << "ConfigOptionVector::set_at: assigned scalar value=" << this->values[i];
|
||||
} else
|
||||
throw ConfigurationError("ConfigOptionVector::set_at(): Assigning an incompatible type");
|
||||
}
|
||||
|
||||
|
||||
+50
-105
@@ -225,7 +225,6 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
gcode += '\n';
|
||||
}
|
||||
|
||||
|
||||
// Return true if tch_prefix is found in custom_gcode
|
||||
static bool custom_gcode_changes_tool(const std::string& custom_gcode, const std::string& tch_prefix, unsigned next_extruder)
|
||||
{
|
||||
@@ -362,7 +361,6 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
if(_wipe_speed < 10)
|
||||
_wipe_speed = 10;
|
||||
|
||||
|
||||
//SoftFever: allow 100% retract before wipe
|
||||
if (length >= 0)
|
||||
{
|
||||
@@ -523,23 +521,19 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
{
|
||||
GCodeWriter &gcode_writer = gcodegen.m_writer;
|
||||
FullPrintConfig &full_config = gcodegen.m_config;
|
||||
// SM Orca: 计算物理挤出机ID用于参数查询
|
||||
int previous_physical_extruder = (previous_extruder_id >= 0) ? gcode_writer.get_physical_extruder(previous_extruder_id) : -1;
|
||||
int new_physical_extruder = gcode_writer.get_physical_extruder(new_extruder_id);
|
||||
// SM Orca: 回抽和温度是挤出机属性,使用 physical_extruder
|
||||
float old_retract_length = (gcode_writer.extruder() != nullptr && previous_physical_extruder >= 0) ?
|
||||
full_config.retraction_length.get_at(previous_physical_extruder) : 0;
|
||||
float new_retract_length = full_config.retraction_length.get_at(new_physical_extruder);
|
||||
float old_retract_length_toolchange = (gcode_writer.extruder() != nullptr && previous_physical_extruder >= 0) ?
|
||||
full_config.retract_length_toolchange.get_at(previous_physical_extruder) : 0;
|
||||
float new_retract_length_toolchange = full_config.retract_length_toolchange.get_at(new_physical_extruder);
|
||||
int old_filament_temp = (gcode_writer.extruder() != nullptr && previous_physical_extruder >= 0) ?
|
||||
float old_retract_length = (gcode_writer.extruder() != nullptr && previous_extruder_id >= 0) ?
|
||||
full_config.retraction_length.get_at(previous_extruder_id) : 0;
|
||||
float new_retract_length = full_config.retraction_length.get_at(new_extruder_id);
|
||||
float old_retract_length_toolchange = (gcode_writer.extruder() != nullptr && previous_extruder_id >= 0) ?
|
||||
full_config.retract_length_toolchange.get_at(previous_extruder_id) : 0;
|
||||
float new_retract_length_toolchange = full_config.retract_length_toolchange.get_at(new_extruder_id);
|
||||
int old_filament_temp = (gcode_writer.extruder() != nullptr && previous_extruder_id >= 0) ?
|
||||
(gcodegen.on_first_layer() ?
|
||||
full_config.nozzle_temperature_initial_layer.get_at(previous_physical_extruder) :
|
||||
full_config.nozzle_temperature.get_at(previous_physical_extruder)) :
|
||||
full_config.nozzle_temperature_initial_layer.get_at(previous_extruder_id) :
|
||||
full_config.nozzle_temperature.get_at(previous_extruder_id)) :
|
||||
210;
|
||||
int new_filament_temp = gcodegen.on_first_layer() ? full_config.nozzle_temperature_initial_layer.get_at(new_physical_extruder) :
|
||||
full_config.nozzle_temperature.get_at(new_physical_extruder);
|
||||
int new_filament_temp = gcodegen.on_first_layer() ? full_config.nozzle_temperature_initial_layer.get_at(new_extruder_id) :
|
||||
full_config.nozzle_temperature.get_at(new_extruder_id);
|
||||
Vec3d nozzle_pos = gcode_writer.get_position();
|
||||
|
||||
float purge_volume = tcr.purge_volume < EPSILON ? 0 : std::max(tcr.purge_volume, g_min_purge_volume);
|
||||
@@ -740,7 +734,6 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
|
||||
double current_z = gcodegen.writer().get_position().z();
|
||||
|
||||
|
||||
if (z == -1.) // in case no specific z was provided, print at current_z pos
|
||||
z = current_z;
|
||||
|
||||
@@ -847,7 +840,6 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
if (m_single_extruder_multi_material)
|
||||
extruder_offset = m_extruder_offsets[0].cast<float>();
|
||||
else {
|
||||
// SM Orca: 使用物理挤出机ID,不是耗材ID
|
||||
int physical_extruder = gcodegen.writer().get_physical_extruder(tcr.initial_tool);
|
||||
extruder_offset = m_extruder_offsets[physical_extruder].cast<float>();
|
||||
}
|
||||
@@ -910,7 +902,6 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
if (line == "[change_filament_gcode]") {
|
||||
// BBS
|
||||
if (!m_single_extruder_multi_material) {
|
||||
// SM Orca: 使用物理挤出机ID,不是耗材ID
|
||||
int physical_extruder_new = gcodegen.writer().get_physical_extruder(tcr.new_tool);
|
||||
int physical_extruder_initial = gcodegen.writer().get_physical_extruder(tcr.initial_tool);
|
||||
Vec2f new_extruder_offset = m_extruder_offsets[physical_extruder_new].cast<float>();
|
||||
@@ -1051,6 +1042,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
const std::vector<std::string> ColorPrintColors::Colors = { "#C0392B", "#E67E22", "#F1C40F", "#27AE60", "#1ABC9C", "#2980B9", "#9B59B6" };
|
||||
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id())
|
||||
#define PHYSICAL_EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.get_physical_extruder(m_writer.extruder()->id()))
|
||||
|
||||
void GCode::PlaceholderParserIntegration::reset()
|
||||
{
|
||||
@@ -1600,20 +1592,9 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
// DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
|
||||
DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics, print->config());
|
||||
if (result != nullptr) {
|
||||
// SM Orca: 记录移动赋值前的状态
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: Before move assignment - result=" << result
|
||||
<< ", result->extruders_count=" << result->extruders_count
|
||||
<< ", result->filament_diameters.size()=" << result->filament_diameters.size()
|
||||
<< ", processor.result().extruders_count=" << m_processor.result().extruders_count
|
||||
<< ", processor.result().filament_diameters.size()=" << m_processor.result().filament_diameters.size();
|
||||
|
||||
*result = std::move(m_processor.extract_result());
|
||||
|
||||
// SM Orca: 记录移动赋值后的状态
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: After move assignment - result=" << result
|
||||
<< ", result->extruders_count=" << result->extruders_count
|
||||
<< ", result->filament_diameters.size()=" << result->filament_diameters.size();
|
||||
|
||||
// set the filename to the correct value
|
||||
result->filename = path;
|
||||
}
|
||||
@@ -1870,21 +1851,15 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
|
||||
// SM Orca: 确保GCodeWriter有正确的映射表(从Print获取并设置到writer)
|
||||
const auto& print_mapping = print.get_filament_extruder_map();
|
||||
if (!print_mapping.empty()) {
|
||||
m_writer.set_filament_extruder_map(print_mapping);
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: GCode::_do_export - Set filament_extruder_map from Print to writer, size: " << print_mapping.size();
|
||||
for (const auto& pair : print_mapping) {
|
||||
BOOST_LOG_TRIVIAL(info) << " SM Orca: Print mapping: filament " << pair.first << " -> extruder " << pair.second;
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: GCode::_do_export - No filament_extruder_map from Print (using default 1:1 mapping)";
|
||||
}
|
||||
|
||||
// SM Orca: 从GCodeWriter获取映射表并传递给GCodeProcessor
|
||||
const auto& writer_mapping = m_writer.get_filament_extruder_map();
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: GCode::_do_export - Setting filament_extruder_map to processor, mapping size: " << writer_mapping.size();
|
||||
m_processor.set_filament_extruder_map(writer_mapping);
|
||||
|
||||
// modifies m_silent_time_estimator_enabled
|
||||
@@ -2066,7 +2041,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write some terse information on the slicing parameters.
|
||||
const PrintObject *first_object = print.objects().front();
|
||||
const double layer_height = first_object->config().layer_height.value;
|
||||
@@ -2249,7 +2223,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
this->placeholder_parser().set("long_retraction_when_cut", m_config.long_retractions_when_cut.get_at(initial_extruder_id));
|
||||
this->placeholder_parser().set("temperature", new ConfigOptionInts(print.config().nozzle_temperature));
|
||||
|
||||
|
||||
this->placeholder_parser().set("retraction_distances_when_cut", new ConfigOptionFloats(m_config.retraction_distances_when_cut));
|
||||
this->placeholder_parser().set("long_retractions_when_cut",new ConfigOptionBools(m_config.long_retractions_when_cut));
|
||||
//Set variable for total layer count so it can be used in custom gcode.
|
||||
@@ -2403,10 +2376,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
|
||||
// calculate the volumetric speed of outer wall. Ignore per-object setting and multi-filament, and just use the default setting
|
||||
{
|
||||
// SM Orca: 使用物理挤出机的喷嘴直径
|
||||
int physical_extruder_id = m_writer.get_physical_extruder(initial_non_support_extruder_id);
|
||||
|
||||
// SM Orca: 日志 - 配置数组访问边界检查
|
||||
size_t nozzle_array_size = m_config.nozzle_diameter.values.size();
|
||||
BOOST_LOG_TRIVIAL(info) << "GCode::process_layer: volumetric_speed_calc - filament_id=" << initial_non_support_extruder_id
|
||||
<< " physical_extruder_id=" << physical_extruder_id
|
||||
@@ -2853,12 +2824,12 @@ void GCode::process_layers(
|
||||
}
|
||||
});
|
||||
if (m_spiral_vase) {
|
||||
float nozzle_diameter = EXTRUDER_CONFIG(nozzle_diameter);
|
||||
float nozzle_diameter = PHYSICAL_EXTRUDER_CONFIG(nozzle_diameter);
|
||||
float max_xy_smoothing = m_config.get_abs_value("spiral_mode_max_xy_smoothing", nozzle_diameter);
|
||||
this->m_spiral_vase->set_max_xy_smoothing(max_xy_smoothing);
|
||||
}
|
||||
const auto spiral_mode = tbb::make_filter<LayerResult, LayerResult>(slic3r_tbb_filtermode::serial_in_order,
|
||||
[&spiral_mode = *this->m_spiral_vase.get(), &layers_to_print](LayerResult in) -> LayerResult {
|
||||
[&spiral_mode = *this->m_spiral_vase.get(), &layers_to_print](LayerResult in)->LayerResult {
|
||||
if (in.nop_layer_result)
|
||||
return in;
|
||||
|
||||
@@ -2953,7 +2924,7 @@ void GCode::process_layers(
|
||||
}
|
||||
});
|
||||
if (m_spiral_vase) {
|
||||
float nozzle_diameter = EXTRUDER_CONFIG(nozzle_diameter);
|
||||
float nozzle_diameter = PHYSICAL_EXTRUDER_CONFIG(nozzle_diameter);
|
||||
float max_xy_smoothing = m_config.get_abs_value("spiral_mode_max_xy_smoothing", nozzle_diameter);
|
||||
this->m_spiral_vase->set_max_xy_smoothing(max_xy_smoothing);
|
||||
}
|
||||
@@ -3221,7 +3192,6 @@ int GCode::get_bed_temperature(const int extruder_id, const bool is_first_layer,
|
||||
return bed_temp_opt->get_at(extruder_id);
|
||||
}
|
||||
|
||||
|
||||
// Write 1st layer bed temperatures into the G-code.
|
||||
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
|
||||
// M140 - Set Extruder Temperature
|
||||
@@ -4710,8 +4680,6 @@ std::string GCode::change_layer(coordf_t print_z)
|
||||
return gcode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static std::unique_ptr<EdgeGrid::Grid> calculate_layer_edge_grid(const Layer& layer)
|
||||
{
|
||||
auto out = make_unique<EdgeGrid::Grid>();
|
||||
@@ -4765,7 +4733,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
!m_config.spiral_mode &&
|
||||
(loop.role() == erExternalPerimeter || (loop.role() == erPerimeter && m_config.seam_slope_inner_walls)) &&
|
||||
layer_id() > 0;
|
||||
const auto nozzle_diameter = EXTRUDER_CONFIG(nozzle_diameter);
|
||||
const auto nozzle_diameter = PHYSICAL_EXTRUDER_CONFIG(nozzle_diameter);
|
||||
if (enable_seam_slope && m_config.seam_slope_conditional.value) {
|
||||
enable_seam_slope = loop.is_smooth(m_config.scarf_angle_threshold.value * M_PI / 180., nozzle_diameter);
|
||||
}
|
||||
@@ -4871,7 +4839,6 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const auto speed_for_path = [&speed, &small_peri_speed](const ExtrusionPath& path) {
|
||||
// don't apply small perimeter setting for overhangs/bridges/non-perimeters
|
||||
const bool is_small_peri = is_perimeter(path.role()) && !is_bridge(path.role()) && small_peri_speed > 0;
|
||||
@@ -4988,7 +4955,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
||||
Vec2d p1 = paths.front().polyline.points.front().cast<double>();
|
||||
Vec2d p2 = paths.front().polyline.points[1].cast<double>();
|
||||
Vec2d v = p2 - p1;
|
||||
double nd = scale_(EXTRUDER_CONFIG(nozzle_diameter));
|
||||
double nd = scale_(PHYSICAL_EXTRUDER_CONFIG(nozzle_diameter));
|
||||
double l2 = v.squaredNorm();
|
||||
// Shift by no more than a nozzle diameter.
|
||||
//FIXME Hiding the seams will not work nicely for very densely discretized contours!
|
||||
@@ -5309,7 +5276,6 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if needed, write the gcode_label_objects_end then gcode_label_objects_start
|
||||
// should be already done by travel_to, but just in case
|
||||
m_writer.add_object_change_labels(gcode);
|
||||
@@ -5392,8 +5358,6 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
double e_per_mm = m_writer.extruder()->e_per_mm3() * _mm3_per_mm;
|
||||
e_per_mm /= filament_flow_ratio;
|
||||
|
||||
|
||||
|
||||
// set speed
|
||||
if (speed == -1) {
|
||||
if (path.role() == erPerimeter) {
|
||||
@@ -5577,10 +5541,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
// If adaptive PA is enabled, by default evaluate PA on all extrusion moves
|
||||
bool is_pa_calib = m_curr_print->calib_mode() == CalibMode::Calib_PA_Line ||
|
||||
m_curr_print->calib_mode() == CalibMode::Calib_PA_Pattern ||
|
||||
m_curr_print->calib_mode() == CalibMode::Calib_PA_Tower;
|
||||
m_curr_print->calib_mode() == CalibMode::Calib_PA_Tower;
|
||||
bool evaluate_adaptive_pa = false;
|
||||
bool role_change = (m_last_extrusion_role != path.role());
|
||||
if (!is_pa_calib && EXTRUDER_CONFIG(adaptive_pressure_advance) && EXTRUDER_CONFIG(enable_pressure_advance)) {
|
||||
if (!is_pa_calib && PHYSICAL_EXTRUDER_CONFIG(adaptive_pressure_advance) && PHYSICAL_EXTRUDER_CONFIG(enable_pressure_advance)) {
|
||||
evaluate_adaptive_pa = true;
|
||||
// If we have already emmited a PA change because the m_multi_flow_segment_path_pa_set is set
|
||||
// skip re-issuing the PA change tag.
|
||||
@@ -5691,9 +5655,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto overhang_fan_threshold = EXTRUDER_CONFIG(overhang_fan_threshold);
|
||||
auto enable_overhang_bridge_fan = EXTRUDER_CONFIG(enable_overhang_bridge_fan);
|
||||
auto overhang_fan_threshold = PHYSICAL_EXTRUDER_CONFIG(overhang_fan_threshold);
|
||||
auto enable_overhang_bridge_fan = PHYSICAL_EXTRUDER_CONFIG(enable_overhang_bridge_fan);
|
||||
|
||||
// { "0%", Overhang_threshold_none },
|
||||
// { "10%", Overhang_threshold_1_4 },
|
||||
@@ -5758,8 +5721,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
};
|
||||
auto apply_role_based_fan_speed = [
|
||||
&path, &append_role_based_fan_marker,
|
||||
supp_interface_fan_speed = EXTRUDER_CONFIG(support_material_interface_fan_speed),
|
||||
ironing_fan_speed = EXTRUDER_CONFIG(ironing_fan_speed)
|
||||
supp_interface_fan_speed = PHYSICAL_EXTRUDER_CONFIG(support_material_interface_fan_speed),
|
||||
ironing_fan_speed = PHYSICAL_EXTRUDER_CONFIG(ironing_fan_speed)
|
||||
] {
|
||||
append_role_based_fan_marker(erSupportMaterialInterface, "_SUPP_INTERFACE"sv,
|
||||
supp_interface_fan_speed >= 0 && path.role() == erSupportMaterialInterface);
|
||||
@@ -5776,9 +5739,9 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
// Emit tag before new speed is set so the post processor reads the next speed immediately and uses it.
|
||||
// Dont emit tag if it has just already been emitted from a role change above
|
||||
if(_mm3_per_mm >0 &&
|
||||
EXTRUDER_CONFIG(adaptive_pressure_advance) &&
|
||||
EXTRUDER_CONFIG(enable_pressure_advance) &&
|
||||
EXTRUDER_CONFIG(adaptive_pressure_advance_overhangs) &&
|
||||
PHYSICAL_EXTRUDER_CONFIG(adaptive_pressure_advance) &&
|
||||
PHYSICAL_EXTRUDER_CONFIG(enable_pressure_advance) &&
|
||||
PHYSICAL_EXTRUDER_CONFIG(adaptive_pressure_advance_overhangs) &&
|
||||
!evaluate_adaptive_pa){
|
||||
if(writer().get_current_speed() > F){ // Ramping down speed - use overhang logic where the minimum speed is used between current and upcoming extrusion
|
||||
if(m_config.gcode_comments){
|
||||
@@ -5985,9 +5948,9 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
// There is a speed change or flow change so emit the flag to evaluate PA for the upcomming extrusion
|
||||
// Emit tag before new speed is set so the post processor reads the next speed immediately and uses it.
|
||||
if(_mm3_per_mm >0 &&
|
||||
EXTRUDER_CONFIG(adaptive_pressure_advance) &&
|
||||
EXTRUDER_CONFIG(enable_pressure_advance) &&
|
||||
EXTRUDER_CONFIG(adaptive_pressure_advance_overhangs) ){
|
||||
PHYSICAL_EXTRUDER_CONFIG(adaptive_pressure_advance) &&
|
||||
PHYSICAL_EXTRUDER_CONFIG(enable_pressure_advance) &&
|
||||
PHYSICAL_EXTRUDER_CONFIG(adaptive_pressure_advance_overhangs) ){
|
||||
if(last_set_speed > new_speed){ // Ramping down speed - use overhang logic where the minimum speed is used between current and upcoming extrusion
|
||||
if(m_config.gcode_comments) {
|
||||
sprintf(buf, "; Ramp up-variable\n");
|
||||
@@ -6435,7 +6398,6 @@ std::string GCode::retract(bool toolchange, bool is_last_retraction, LiftType li
|
||||
gcode += toolchange ? m_writer.retract_for_toolchange() : m_writer.retract();
|
||||
}
|
||||
|
||||
|
||||
gcode += m_writer.reset_e();
|
||||
// Orca: check if should + can lift (roughly from SuperSlicer)
|
||||
RetractLiftEnforceType retract_lift_type = RetractLiftEnforceType(EXTRUDER_CONFIG(retract_lift_enforce));
|
||||
@@ -6495,11 +6457,12 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b
|
||||
gcode += this->placeholder_parser_process("filament_start_gcode", filament_start_gcode, extruder_id, &config);
|
||||
check_add_eol(gcode);
|
||||
}
|
||||
if (m_config.enable_pressure_advance.get_at(extruder_id)) {
|
||||
gcode += m_writer.set_pressure_advance(m_config.pressure_advance.get_at(extruder_id));
|
||||
int physical_extruder_id = m_writer.get_physical_extruder(extruder_id);
|
||||
if (m_config.enable_pressure_advance.get_at(physical_extruder_id)) {
|
||||
gcode += m_writer.set_pressure_advance(m_config.pressure_advance.get_at(physical_extruder_id));
|
||||
// Orca: Adaptive PA
|
||||
// Reset Adaptive PA processor last PA value
|
||||
m_pa_processor->resetPreviousPA(m_config.pressure_advance.get_at(extruder_id));
|
||||
m_pa_processor->resetPreviousPA(m_config.pressure_advance.get_at(physical_extruder_id));
|
||||
}
|
||||
|
||||
gcode += m_writer.toolchange(extruder_id);
|
||||
@@ -6535,17 +6498,14 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If ooze prevention is enabled, park current extruder in the nearest
|
||||
// standby point and set it to the standby temperature.
|
||||
if (m_ooze_prevention.enable && m_writer.extruder() != nullptr)
|
||||
gcode += m_ooze_prevention.pre_toolchange(*this);
|
||||
|
||||
// SM Orca: 计算物理挤出机ID,用于耗材-挤出机映射
|
||||
// 需要在参数查询之前计算,因为挤出机属性(温度、回抽等)应该从物理挤出机获取
|
||||
int next_physical_extruder = m_writer.get_physical_extruder(extruder_id);
|
||||
|
||||
// SM Orca: 日志 - 工具切换开始
|
||||
BOOST_LOG_TRIVIAL(info) << "GCode::set_extruder: Tool change START - filament_id=" << extruder_id
|
||||
<< " -> physical_extruder_id=" << next_physical_extruder
|
||||
<< " print_z=" << print_z
|
||||
@@ -6554,31 +6514,30 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b
|
||||
// BBS
|
||||
// 回抽和温度是挤出机属性,使用 physical_extruder
|
||||
|
||||
// SM Orca: 日志 - 配置数组访问边界检查
|
||||
size_t retract_array_size = m_config.retraction_length.values.size();
|
||||
size_t temp_array_size = m_config.nozzle_temperature.values.size();
|
||||
BOOST_LOG_TRIVIAL(info) << "GCode::set_extruder: Config access check -"
|
||||
<< " retraction_length array_size=" << retract_array_size
|
||||
<< " nozzle_temperature array_size=" << temp_array_size
|
||||
<< " access_index=" << next_physical_extruder
|
||||
<< (next_physical_extruder >= (int)retract_array_size ? " [RETRACT_OUT_OF_BOUNDS!]" : "")
|
||||
<< (next_physical_extruder >= (int)temp_array_size ? " [TEMP_OUT_OF_BOUNDS!]" : "");
|
||||
<< " extruder_id=" << extruder_id
|
||||
<< (extruder_id >= (int)retract_array_size ? " [RETRACT_OUT_OF_BOUNDS!]" : "")
|
||||
<< (extruder_id >= (int)temp_array_size ? " [TEMP_OUT_OF_BOUNDS!]" : "");
|
||||
|
||||
float new_retract_length = m_config.retraction_length.get_at(next_physical_extruder);
|
||||
float new_retract_length_toolchange = m_config.retract_length_toolchange.get_at(next_physical_extruder);
|
||||
int new_filament_temp = this->on_first_layer() ? m_config.nozzle_temperature_initial_layer.get_at(next_physical_extruder): m_config.nozzle_temperature.get_at(next_physical_extruder);
|
||||
float new_retract_length = m_config.retraction_length.get_at(extruder_id);
|
||||
float new_retract_length_toolchange = m_config.retract_length_toolchange.get_at(extruder_id);
|
||||
int new_filament_temp = this->on_first_layer() ? m_config.nozzle_temperature_initial_layer.get_at(extruder_id): m_config.nozzle_temperature.get_at(extruder_id);
|
||||
// BBS: if print_z == 0 use first layer temperature
|
||||
if (abs(print_z) < EPSILON)
|
||||
new_filament_temp = m_config.nozzle_temperature_initial_layer.get_at(next_physical_extruder);
|
||||
new_filament_temp = m_config.nozzle_temperature_initial_layer.get_at(extruder_id);
|
||||
|
||||
Vec3d nozzle_pos = m_writer.get_position();
|
||||
float old_retract_length, old_retract_length_toolchange, wipe_volume;
|
||||
int old_filament_temp, old_filament_e_feedrate;
|
||||
int previous_physical_extruder = -1;
|
||||
|
||||
float filament_area = float((M_PI / 4.f) * pow(m_config.filament_diameter.get_at(extruder_id), 2));
|
||||
//BBS: add handling for filament change in start gcode
|
||||
int previous_extruder_id = -1;
|
||||
int previous_physical_extruder = -1; // SM Orca: 前一个物理挤出机ID
|
||||
if (m_writer.extruder() != nullptr || m_start_gcode_filament != -1) {
|
||||
std::vector<float> flush_matrix(cast<float>(m_config.flush_volumes_matrix.values));
|
||||
const unsigned int number_of_extruders = (unsigned int)(sqrt(flush_matrix.size()) + EPSILON);
|
||||
@@ -6588,18 +6547,16 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b
|
||||
assert(m_start_gcode_filament < number_of_extruders);
|
||||
|
||||
previous_extruder_id = m_writer.extruder() != nullptr ? m_writer.extruder()->id() : m_start_gcode_filament;
|
||||
previous_physical_extruder = m_writer.get_physical_extruder(previous_extruder_id); // SM Orca: 计算前一个物理挤出机
|
||||
|
||||
// SM Orca: 日志 - 前一个挤出机配置访问
|
||||
BOOST_LOG_TRIVIAL(info) << "GCode::set_extruder: Previous extruder config - filament_id=" << previous_extruder_id
|
||||
<< " physical_extruder_id=" << previous_physical_extruder
|
||||
<< " (array_size=" << m_config.retraction_length.values.size() << ")"
|
||||
<< (previous_physical_extruder >= (int)m_config.retraction_length.values.size() ? " [PREV_OUT_OF_BOUNDS!]" : " [OK]");
|
||||
<< (previous_extruder_id >= (int)m_config.retraction_length.values.size() ? " [PREV_OUT_OF_BOUNDS!]" : " [OK]");
|
||||
|
||||
// SM Orca: 回抽和温度是挤出机属性,使用 physical_extruder
|
||||
old_retract_length = m_config.retraction_length.get_at(previous_physical_extruder);
|
||||
old_retract_length_toolchange = m_config.retract_length_toolchange.get_at(previous_physical_extruder);
|
||||
old_filament_temp = this->on_first_layer()? m_config.nozzle_temperature_initial_layer.get_at(previous_physical_extruder) : m_config.nozzle_temperature.get_at(previous_physical_extruder);
|
||||
old_retract_length = m_config.retraction_length.get_at(previous_extruder_id);
|
||||
old_retract_length_toolchange = m_config.retract_length_toolchange.get_at(previous_extruder_id);
|
||||
previous_physical_extruder = m_writer.get_physical_extruder(previous_extruder_id);
|
||||
|
||||
old_filament_temp = this->on_first_layer()? m_config.nozzle_temperature_initial_layer.get_at(previous_extruder_id) : m_config.nozzle_temperature.get_at(previous_extruder_id);
|
||||
//Orca: always calculate wipe volume and hence provide correct flush_length, so that MMU devices with cutter and purge bin (e.g. ERCF_v2 with a filament cutter or Filametrix can take advantage of it)
|
||||
wipe_volume = flush_matrix[previous_extruder_id * number_of_extruders + extruder_id];
|
||||
wipe_volume *= m_config.flush_multiplier;
|
||||
@@ -6622,7 +6579,6 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b
|
||||
DynamicConfig dyn_config;
|
||||
dyn_config.set_key_value("previous_extruder", new ConfigOptionInt(previous_extruder_id));
|
||||
dyn_config.set_key_value("next_extruder", new ConfigOptionInt((int)extruder_id));
|
||||
// SM Orca: 物理挤出机ID在前面已经计算过了
|
||||
dyn_config.set_key_value("next_physical_extruder", new ConfigOptionInt(next_physical_extruder));
|
||||
dyn_config.set_key_value("previous_physical_extruder", new ConfigOptionInt(previous_physical_extruder));
|
||||
dyn_config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
@@ -6743,8 +6699,9 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b
|
||||
if (m_ooze_prevention.enable)
|
||||
gcode += m_ooze_prevention.post_toolchange(*this);
|
||||
|
||||
if (m_config.enable_pressure_advance.get_at(extruder_id)) {
|
||||
gcode += m_writer.set_pressure_advance(m_config.pressure_advance.get_at(extruder_id));
|
||||
int physical_extruder_id = m_writer.get_physical_extruder(extruder_id);
|
||||
if (m_config.enable_pressure_advance.get_at(physical_extruder_id)) {
|
||||
gcode += m_writer.set_pressure_advance(m_config.pressure_advance.get_at(physical_extruder_id));
|
||||
}
|
||||
//Orca: tool changer or IDEX's firmware may change Z position, so we set it to unknown/undefined
|
||||
m_last_pos_defined = false;
|
||||
@@ -6819,16 +6776,9 @@ std::string GCode::set_object_info(Print *print) {
|
||||
// convert a model-space scaled point into G-code coordinates
|
||||
Vec2d GCode::point_to_gcode(const Point &point) const
|
||||
{
|
||||
// SM Orca: 无条件诊断 - 检查是否被调用
|
||||
static std::atomic<int> call_count{0};
|
||||
int this_call = ++call_count;
|
||||
if (this_call <= 5 || (m_writer.extruder() && m_writer.extruder()->id() >= 12)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: point_to_gcode called #" << this_call
|
||||
<< " extruder=" << (m_writer.extruder() ? m_writer.extruder()->id() : -1)
|
||||
<< " point=(" << point.x() << ", " << point.y() << ")";
|
||||
}
|
||||
|
||||
// SM Orca: 使用物理挤出机ID获取offset,与gcode_to_point保持一致
|
||||
Vec2d extruder_offset = Vec2d::Zero();
|
||||
if (const Extruder *extruder = m_writer.extruder(); extruder) {
|
||||
extruder_offset = m_config.extruder_offset.get_at(m_writer.get_physical_extruder(extruder->id()));
|
||||
@@ -6836,7 +6786,6 @@ Vec2d GCode::point_to_gcode(const Point &point) const
|
||||
|
||||
Vec2d result = unscale(point) + m_origin - extruder_offset;
|
||||
|
||||
// SM Orca: 诊断NaN问题
|
||||
if (std::isnan(result.x()) || std::isinf(result.x()) || std::isnan(result.y()) || std::isinf(result.y())) {
|
||||
Vec2d unscaled_val = unscale(point);
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: point_to_gcode produced NaN/inf"
|
||||
@@ -6858,7 +6807,6 @@ Point GCode::gcode_to_point(const Vec2d &point) const
|
||||
Vec2d pt = point - m_origin;
|
||||
if (const Extruder *extruder = m_writer.extruder(); extruder)
|
||||
// This function may be called at the very start from toolchange G-code when the extruder is not assigned yet.
|
||||
// SM Orca: 使用物理挤出机的偏移
|
||||
pt += m_config.extruder_offset.get_at(m_writer.get_physical_extruder(extruder->id()));
|
||||
return scaled<coord_t>(pt);
|
||||
|
||||
@@ -6870,7 +6818,6 @@ Vec2d GCode::point_to_gcode_quantized(const Point& point) const
|
||||
return { GCodeFormatter::quantize_xyzf(p.x()), GCodeFormatter::quantize_xyzf(p.y()) };
|
||||
}
|
||||
|
||||
|
||||
// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
|
||||
// during infill/perimeter wiping, or normally (depends on wiping_entities parameter)
|
||||
// Fills in by_region_per_copy_cache and returns its reference.
|
||||
@@ -6971,9 +6918,7 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Index into std::vector<LayerToPrint>, which contains Object and Support layers for the current print_z, collected for
|
||||
// a single object, or for possibly multiple objects with multiple instances.
|
||||
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -198,7 +198,11 @@ public:
|
||||
void set_gcode_offset(double x, double y) { m_writer.set_xy_offset(x, y); m_processor.set_xy_offset(x, y);}
|
||||
|
||||
// SM Orca: Set filament-extruder mapping
|
||||
void set_filament_extruder_map(const std::unordered_map<int, int>& map) { m_writer.set_filament_extruder_map(map); m_processor.set_filament_extruder_map(map); }
|
||||
void set_filament_extruder_map(const std::unordered_map<int, int>& map) {
|
||||
m_writer.set_filament_extruder_map(map);
|
||||
m_processor.set_filament_extruder_map(map);
|
||||
if (m_cooling_buffer) m_cooling_buffer->set_filament_extruder_map(map);
|
||||
}
|
||||
|
||||
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
||||
const Vec2d& origin() const { return m_origin; }
|
||||
|
||||
@@ -482,8 +482,11 @@ static inline float get_default_perimeter_spacing(const PrintObject &print_objec
|
||||
std::vector<unsigned int> printing_extruders = print_object.object_extruders();
|
||||
assert(!printing_extruders.empty());
|
||||
float avg_extruder = 0;
|
||||
for(unsigned int extruder_id : printing_extruders)
|
||||
avg_extruder += float(scale_(print_object.print()->config().nozzle_diameter.get_at(extruder_id)));
|
||||
for(unsigned int extruder_id : printing_extruders) {
|
||||
// SM Orca: nozzle_diameter是物理挤出机参数,使用physical_extruder_id访问
|
||||
int physical_extruder_id = print_object.print()->get_physical_extruder(extruder_id);
|
||||
avg_extruder += float(scale_(print_object.print()->config().nozzle_diameter.get_at(physical_extruder_id)));
|
||||
}
|
||||
avg_extruder /= printing_extruders.size();
|
||||
return avg_extruder;
|
||||
}
|
||||
|
||||
@@ -340,12 +340,14 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
||||
for (size_t i = 0; i < m_extruder_ids.size(); ++ i) {
|
||||
PerExtruderAdjustments &adj = per_extruder_adjustments[i];
|
||||
unsigned int extruder_id = m_extruder_ids[i];
|
||||
// SM Orca: 冷却参数都是物理挤出机参数(无耗材覆盖),使用physical_extruder_id访问
|
||||
int physical_extruder_id = get_physical_extruder(extruder_id);
|
||||
adj.extruder_id = extruder_id;
|
||||
adj.cooling_slow_down_enabled = m_config.slow_down_for_layer_cooling.get_at(extruder_id);
|
||||
adj.slow_down_layer_time = float(m_config.slow_down_layer_time.get_at(extruder_id));
|
||||
adj.slow_down_min_speed = float(m_config.slow_down_min_speed.get_at(extruder_id));
|
||||
adj.cooling_slow_down_enabled = m_config.slow_down_for_layer_cooling.get_at(physical_extruder_id);
|
||||
adj.slow_down_layer_time = float(m_config.slow_down_layer_time.get_at(physical_extruder_id));
|
||||
adj.slow_down_min_speed = float(m_config.slow_down_min_speed.get_at(physical_extruder_id));
|
||||
// ORCA: To enable dont slow down external perimeters feature per filament (extruder)
|
||||
adj.dont_slow_down_outer_wall = m_config.dont_slow_down_outer_wall.get_at(extruder_id);
|
||||
adj.dont_slow_down_outer_wall = m_config.dont_slow_down_outer_wall.get_at(physical_extruder_id);
|
||||
map_extruder_to_per_extruder_adjustment[extruder_id] = i;
|
||||
}
|
||||
|
||||
@@ -731,7 +733,8 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
&supp_interface_fan_control, &supp_interface_fan_speed,
|
||||
&ironing_fan_control, &ironing_fan_speed
|
||||
](bool immediately_apply) {
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_current_extruder)
|
||||
// SM Orca: 风扇参数都是物理挤出机参数(无耗材覆盖),使用physical_extruder_id访问
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(get_physical_extruder(m_current_extruder))
|
||||
float fan_min_speed = EXTRUDER_CONFIG(fan_min_speed);
|
||||
float fan_speed_new = EXTRUDER_CONFIG(reduce_fan_stop_start_freq) ? fan_min_speed : 0;
|
||||
//BBS
|
||||
|
||||
@@ -27,6 +27,13 @@ public:
|
||||
void reset(const Vec3d &position);
|
||||
void set_current_extruder(unsigned int extruder_id) { m_current_extruder = extruder_id; }
|
||||
std::string process_layer(std::string &&gcode, size_t layer_id, bool flush);
|
||||
// SM Orca: Set filament to physical extruder mapping for correct parameter access
|
||||
void set_filament_extruder_map(const std::unordered_map<int, int>& map) { m_filament_extruder_map = map; }
|
||||
// SM Orca: Get physical extruder ID from filament ID
|
||||
int get_physical_extruder(int filament_idx) const {
|
||||
auto it = m_filament_extruder_map.find(filament_idx);
|
||||
return (it != m_filament_extruder_map.end()) ? it->second : filament_idx;
|
||||
}
|
||||
|
||||
private:
|
||||
CoolingBuffer& operator=(const CoolingBuffer&) = delete;
|
||||
@@ -55,6 +62,8 @@ private:
|
||||
// the PrintConfig slice of FullPrintConfig is constant, thus no thread synchronization is required.
|
||||
const PrintConfig &m_config;
|
||||
unsigned int m_current_extruder;
|
||||
// SM Orca: Filament to physical extruder mapping for correct parameter access
|
||||
std::unordered_map<int, int> m_filament_extruder_map;
|
||||
//BBS: current fan speed
|
||||
int m_current_fan_speed;
|
||||
};
|
||||
|
||||
@@ -94,7 +94,6 @@ const std::vector<std::string> GCodeProcessor::Reserved_Tags_compatible = {
|
||||
" PA_CHANGE:"
|
||||
};
|
||||
|
||||
|
||||
const std::string GCodeProcessor::Flush_Start_Tag = " FLUSH_START";
|
||||
const std::string GCodeProcessor::Flush_End_Tag = " FLUSH_END";
|
||||
|
||||
@@ -397,7 +396,6 @@ void GCodeProcessor::TimeProcessor::reset()
|
||||
filament_unload_times = 0.0f;
|
||||
machine_tool_change_time = 0.0f;
|
||||
|
||||
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
machines[i].reset();
|
||||
}
|
||||
@@ -457,7 +455,6 @@ void GCodeProcessor::UsedFilaments::process_color_change_cache()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GCodeProcessor::UsedFilaments::process_total_volume_cache(GCodeProcessor* processor)
|
||||
{
|
||||
size_t active_extruder_id = processor->m_extruder_id;
|
||||
@@ -526,7 +523,6 @@ void GCodeProcessor::UsedFilaments::process_role_cache(GCodeProcessor* processor
|
||||
if (role_cache != 0.0f) {
|
||||
std::pair<double, double> filament = { 0.0f, 0.0f };
|
||||
|
||||
// SM Orca: 添加边界检查,与其他地方保持一致
|
||||
float diameter = (static_cast<size_t>(processor->m_extruder_id) < processor->m_result.filament_diameters.size())
|
||||
? processor->m_result.filament_diameters[processor->m_extruder_id]
|
||||
: processor->m_result.filament_diameters.back();
|
||||
@@ -565,21 +561,16 @@ void GCodeProcessorResult::reset() {
|
||||
//BBS: add mutex for protection of gcode result
|
||||
lock();
|
||||
|
||||
// SM Orca: 保存当前的extruders_count并尝试从已有数组推断
|
||||
size_t saved_count = extruders_count;
|
||||
|
||||
// SM Orca: 如果extruders_count不合理,尝试从已有数组大小推断
|
||||
if (saved_count == 0 || saved_count > 256) {
|
||||
// 尝试从已有数组大小推断(优先使用filament_diameters的大小)
|
||||
if (!filament_diameters.empty() && filament_diameters.size() <= 256) {
|
||||
saved_count = filament_diameters.size();
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: GCodeProcessorResult::reset() - Inferred extruders_count from existing array: "
|
||||
<< saved_count;
|
||||
} else {
|
||||
// SM Orca: 使用16作为默认值(覆盖U1等多耗材机型)
|
||||
// 对于只有少量耗材的用户,稍微多分配一些内存影响很小
|
||||
saved_count = 16;
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: GCodeProcessorResult::reset() - Using default extruders_count: "
|
||||
<< saved_count << " (was " << extruders_count << ", array size was " << filament_diameters.size() << ")";
|
||||
}
|
||||
}
|
||||
@@ -596,18 +587,15 @@ void GCodeProcessorResult::reset() {
|
||||
printable_height = 0.0f;
|
||||
settings_ids.reset();
|
||||
|
||||
// SM Orca: 恢复extruders_count为合理的值
|
||||
extruders_count = saved_count;
|
||||
extruder_colors = std::vector<std::string>();
|
||||
|
||||
// SM Orca: 使用推断的大小初始化所有耗材相关数组
|
||||
filament_diameters = std::vector<float>(saved_count, DEFAULT_FILAMENT_DIAMETER);
|
||||
filament_densities = std::vector<float>(saved_count, DEFAULT_FILAMENT_DENSITY);
|
||||
filament_costs = std::vector<float>(saved_count, DEFAULT_FILAMENT_COST);
|
||||
required_nozzle_HRC = std::vector<int>(saved_count, DEFAULT_FILAMENT_HRC);
|
||||
filament_vitrification_temperature = std::vector<int>(saved_count, DEFAULT_FILAMENT_VITRIFICATION_TEMPERATURE);
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: GCodeProcessorResult::reset() - Resized arrays to " << saved_count
|
||||
<< " (original extruders_count=" << (saved_count == extruders_count ? "preserved" : "inferred")
|
||||
<< ", this=" << this << ")";
|
||||
|
||||
@@ -623,22 +611,15 @@ void GCodeProcessorResult::reset() {
|
||||
//BBS: add mutex for protection of gcode result
|
||||
lock();
|
||||
|
||||
// SM Orca: 保存当前的extruders_count并尝试从已有数组推断
|
||||
size_t saved_count = extruders_count;
|
||||
|
||||
// SM Orca: 如果extruders_count不合理,尝试从已有数组大小推断
|
||||
if (saved_count == 0 || saved_count > 256) {
|
||||
// 尝试从已有数组大小推断(优先使用filament_diameters的大小)
|
||||
if (!filament_diameters.empty() && filament_diameters.size() <= 256) {
|
||||
saved_count = filament_diameters.size();
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: GCodeProcessorResult::reset() - Inferred extruders_count from existing array: "
|
||||
<< saved_count;
|
||||
} else {
|
||||
// SM Orca: 使用16作为默认值(覆盖U1等多耗材机型)
|
||||
// 对于只有少量耗材的用户,稍微多分配一些内存影响很小
|
||||
saved_count = 16;
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: GCodeProcessorResult::reset() - Using default extruders_count: "
|
||||
<< saved_count << " (was " << extruders_count << ", array size was " << filament_diameters.size() << ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,20 +639,14 @@ void GCodeProcessorResult::reset() {
|
||||
backtrace_enabled = false;
|
||||
extruder_colors = std::vector<std::string>();
|
||||
|
||||
// SM Orca: 恢复extruders_count为合理的值
|
||||
extruders_count = saved_count;
|
||||
|
||||
// SM Orca: 使用推断的大小初始化所有耗材相关数组
|
||||
filament_diameters = std::vector<float>(saved_count, DEFAULT_FILAMENT_DIAMETER);
|
||||
required_nozzle_HRC = std::vector<int>(saved_count, DEFAULT_FILAMENT_HRC);
|
||||
filament_densities = std::vector<float>(saved_count, DEFAULT_FILAMENT_DENSITY);
|
||||
filament_costs = std::vector<float>(saved_count, DEFAULT_FILAMENT_COST);
|
||||
filament_vitrification_temperature = std::vector<int>(saved_count, DEFAULT_FILAMENT_VITRIFICATION_TEMPERATURE);
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: GCodeProcessorResult::reset() - Resized arrays to " << saved_count
|
||||
<< " (original extruders_count=" << (saved_count == extruders_count ? "preserved" : "inferred")
|
||||
<< ", this=" << this << ")";
|
||||
|
||||
custom_gcode_per_print_z = std::vector<CustomGCode::Item>();
|
||||
spiral_vase_layers = std::vector<std::pair<float, std::pair<size_t, size_t>>>();
|
||||
bed_match_result = BedMatchResult(true);
|
||||
@@ -788,12 +763,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_preheat_steps = 1;
|
||||
m_result.backtrace_enabled = m_preheat_time > 0 && (m_is_XL_printer || (!m_single_extruder_multi_material && extruders_count > 1));
|
||||
|
||||
// SM Orca: 配置验证 - 在resize之前检查配置完整性
|
||||
size_t physical_extruder_count = config.extruder_offset.values.size();
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: Configuration validation:"
|
||||
<< " filaments=" << extruders_count
|
||||
<< ", physical_extruders=" << physical_extruder_count
|
||||
<< ", mappings=" << m_filament_extruder_map.size();
|
||||
|
||||
// 验证各配置数组大小
|
||||
if (config.filament_density.values.size() < extruders_count) {
|
||||
@@ -840,7 +810,6 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_result.nozzle_hrc = static_cast<int>(config.nozzle_hrc.getInt());
|
||||
m_result.nozzle_type = config.nozzle_type;
|
||||
|
||||
// SM Orca: 获取各配置数组的大小,用于边界检查
|
||||
size_t diameter_count = config.filament_diameter.values.size();
|
||||
size_t density_count = config.filament_density.values.size();
|
||||
size_t cost_count = config.filament_cost.values.size();
|
||||
@@ -850,10 +819,8 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
size_t vitrification_count = config.temperature_vitrification.values.size();
|
||||
|
||||
for (size_t i = 0; i < extruders_count; ++ i) {
|
||||
// SM Orca: 使用物理挤出机ID来访问offset,并确保不越界
|
||||
int physical_extruder = get_physical_extruder(i);
|
||||
|
||||
// SM Orca: 边界检查 - 如果映射的物理挤出机超出范围,回退到1:1映射
|
||||
if (physical_extruder < 0 || physical_extruder >= static_cast<int>(physical_extruder_count)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: Filament " << i
|
||||
<< " maps to invalid physical extruder " << physical_extruder
|
||||
@@ -866,7 +833,6 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_extruder_offsets[i] = to_3d(config.extruder_offset.get_at(physical_extruder).cast<float>().eval(), 0.f);
|
||||
m_extruder_colors[i] = static_cast<unsigned char>(i);
|
||||
|
||||
// SM Orca: 安全读取温度配置(使用最后有效值作为回退)
|
||||
// 温度是挤出机属性,使用 physical_extruder 而不是 filament index
|
||||
if (physical_extruder < static_cast<int>(temp_initial_count)) {
|
||||
m_extruder_temps_first_layer_config[i] = static_cast<int>(config.nozzle_temperature_initial_layer.get_at(physical_extruder));
|
||||
@@ -891,7 +857,6 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_extruder_temps_config[i] = m_extruder_temps_first_layer_config[i];
|
||||
}
|
||||
|
||||
// SM Orca: 安全读取直径(使用最后有效值作为回退)
|
||||
if (i < diameter_count) {
|
||||
m_result.filament_diameters[i] = static_cast<float>(config.filament_diameter.get_at(i));
|
||||
} else {
|
||||
@@ -901,7 +866,6 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: Filament " << i << " diameter not configured, using " << fallback << "mm";
|
||||
}
|
||||
|
||||
// SM Orca: 安全读取HRC
|
||||
if (i < hrc_count) {
|
||||
m_result.required_nozzle_HRC[i] = static_cast<int>(config.required_nozzle_HRC.get_at(i));
|
||||
} else {
|
||||
@@ -910,7 +874,6 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_result.required_nozzle_HRC[i] = fallback;
|
||||
}
|
||||
|
||||
// SM Orca: 安全读取密度(使用最后有效值作为回退)
|
||||
if (i < density_count) {
|
||||
m_result.filament_densities[i] = static_cast<float>(config.filament_density.get_at(i));
|
||||
} else {
|
||||
@@ -920,7 +883,6 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: Filament " << i << " density not configured, using " << fallback << " g/cm³";
|
||||
}
|
||||
|
||||
// SM Orca: 安全读取玻璃化温度
|
||||
if (i < vitrification_count) {
|
||||
m_result.filament_vitrification_temperature[i] = static_cast<int>(config.temperature_vitrification.get_at(i));
|
||||
} else {
|
||||
@@ -929,7 +891,6 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_result.filament_vitrification_temperature[i] = fallback;
|
||||
}
|
||||
|
||||
// SM Orca: 安全读取成本(使用0作为默认值)
|
||||
if (i < cost_count) {
|
||||
m_result.filament_costs[i] = static_cast<float>(config.filament_cost.get_at(i));
|
||||
} else {
|
||||
@@ -1051,17 +1012,14 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (filament_diameters != nullptr) {
|
||||
size_t config_size = filament_diameters->values.size();
|
||||
|
||||
// SM Orca: 确保数组大小等于extruders_count,不要clear()
|
||||
if (m_result.filament_diameters.size() < m_result.extruders_count) {
|
||||
m_result.filament_diameters.resize(m_result.extruders_count, DEFAULT_FILAMENT_DIAMETER);
|
||||
}
|
||||
|
||||
// SM Orca: 只更新配置中有的值
|
||||
for (size_t i = 0; i < config_size && i < m_result.extruders_count; ++i) {
|
||||
m_result.filament_diameters[i] = static_cast<float>(filament_diameters->values[i]);
|
||||
}
|
||||
|
||||
// SM Orca: 对于配置中没有的值,使用最后一个有效值
|
||||
if (config_size > 0 && config_size < m_result.extruders_count) {
|
||||
float last_value = static_cast<float>(filament_diameters->values[config_size - 1]);
|
||||
for (size_t i = config_size; i < m_result.extruders_count; ++i) {
|
||||
@@ -1072,7 +1030,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
}
|
||||
}
|
||||
|
||||
// SM Orca: 确保数组大小正确(移除原有的回退逻辑,因为已经在上面处理了)
|
||||
if (m_result.filament_diameters.size() < m_result.extruders_count) {
|
||||
m_result.filament_diameters.resize(m_result.extruders_count, DEFAULT_FILAMENT_DIAMETER);
|
||||
}
|
||||
@@ -1093,17 +1050,14 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (filament_densities != nullptr) {
|
||||
size_t config_size = filament_densities->values.size();
|
||||
|
||||
// SM Orca: 确保数组大小等于extruders_count,不要clear()
|
||||
if (m_result.filament_densities.size() < m_result.extruders_count) {
|
||||
m_result.filament_densities.resize(m_result.extruders_count, DEFAULT_FILAMENT_DENSITY);
|
||||
}
|
||||
|
||||
// SM Orca: 只更新配置中有的值
|
||||
for (size_t i = 0; i < config_size && i < m_result.extruders_count; ++i) {
|
||||
m_result.filament_densities[i] = static_cast<float>(filament_densities->values[i]);
|
||||
}
|
||||
|
||||
// SM Orca: 对于配置中没有的值,使用最后一个有效值
|
||||
if (config_size > 0 && config_size < m_result.extruders_count) {
|
||||
float last_value = static_cast<float>(filament_densities->values[config_size - 1]);
|
||||
for (size_t i = config_size; i < m_result.extruders_count; ++i) {
|
||||
@@ -1114,7 +1068,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
}
|
||||
}
|
||||
|
||||
// SM Orca: 确保数组大小正确
|
||||
if (m_result.filament_densities.size() < m_result.extruders_count) {
|
||||
m_result.filament_densities.resize(m_result.extruders_count, DEFAULT_FILAMENT_DENSITY);
|
||||
}
|
||||
@@ -1124,16 +1077,13 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (filament_costs != nullptr) {
|
||||
size_t config_size = filament_costs->values.size();
|
||||
|
||||
// SM Orca: 确保数组大小等于extruders_count,不要clear()
|
||||
if (m_result.filament_costs.size() < m_result.extruders_count) {
|
||||
m_result.filament_costs.resize(m_result.extruders_count, DEFAULT_FILAMENT_COST);
|
||||
}
|
||||
|
||||
// SM Orca: 只更新配置中有的值
|
||||
for (size_t i = 0; i < config_size && i < m_result.extruders_count; ++i)
|
||||
m_result.filament_costs[i] = static_cast<float>(filament_costs->values[i]);
|
||||
|
||||
// SM Orca: 对于配置中没有的值,使用0(成本默认值)
|
||||
if (config_size < m_result.extruders_count) {
|
||||
for (size_t i = config_size; i < m_result.extruders_count; ++i) {
|
||||
m_result.filament_costs[i] = DEFAULT_FILAMENT_COST;
|
||||
@@ -1143,7 +1093,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
}
|
||||
}
|
||||
|
||||
// SM Orca: 确保数组大小正确
|
||||
if (m_result.filament_costs.size() < m_result.extruders_count) {
|
||||
m_result.filament_costs.resize(m_result.extruders_count, DEFAULT_FILAMENT_COST);
|
||||
}
|
||||
@@ -1153,17 +1102,14 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (filament_vitrification_temperature != nullptr) {
|
||||
size_t config_size = filament_vitrification_temperature->values.size();
|
||||
|
||||
// SM Orca: 确保数组大小等于extruders_count,不要clear()
|
||||
if (m_result.filament_vitrification_temperature.size() < m_result.extruders_count) {
|
||||
m_result.filament_vitrification_temperature.resize(m_result.extruders_count, DEFAULT_FILAMENT_VITRIFICATION_TEMPERATURE);
|
||||
}
|
||||
|
||||
// SM Orca: 只更新配置中有的值
|
||||
for (size_t i = 0; i < config_size && i < m_result.extruders_count; ++i) {
|
||||
m_result.filament_vitrification_temperature[i] = static_cast<int>(filament_vitrification_temperature->values[i]);
|
||||
}
|
||||
|
||||
// SM Orca: 对于配置中没有的值,使用最后一个有效值
|
||||
if (config_size > 0 && config_size < m_result.extruders_count) {
|
||||
int last_value = static_cast<int>(filament_vitrification_temperature->values[config_size - 1]);
|
||||
for (size_t i = config_size; i < m_result.extruders_count; ++i) {
|
||||
@@ -1186,7 +1132,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
}
|
||||
}
|
||||
else {
|
||||
// SM Orca: 先确保数组足够大,不要缩小已有的数组
|
||||
size_t physical_count = extruder_offset->values.size();
|
||||
if (m_extruder_offsets.size() < m_result.extruders_count) {
|
||||
m_extruder_offsets.resize(m_result.extruders_count, DEFAULT_EXTRUDER_OFFSET);
|
||||
@@ -1201,7 +1146,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
}
|
||||
|
||||
if (m_extruder_offsets.size() < m_result.extruders_count) {
|
||||
// SM Orca: 使用映射来填充剩余耗材的offset,而不是使用默认值
|
||||
size_t physical_count = m_extruder_offsets.size();
|
||||
for (size_t i = m_extruder_offsets.size(); i < m_result.extruders_count; ++i) {
|
||||
int physical_extruder = get_physical_extruder(i);
|
||||
@@ -1257,7 +1201,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (machine_tool_change_time != nullptr)
|
||||
m_time_processor.machine_tool_change_time = static_cast<float>(machine_tool_change_time->value);
|
||||
|
||||
|
||||
if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfKlipper) {
|
||||
const ConfigOptionFloats* machine_max_acceleration_x = config.option<ConfigOptionFloats>("machine_max_acceleration_x");
|
||||
if (machine_max_acceleration_x != nullptr)
|
||||
@@ -1319,7 +1262,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (machine_max_acceleration_retracting != nullptr)
|
||||
m_time_processor.machine_limits.machine_max_acceleration_retracting.values = machine_max_acceleration_retracting->values;
|
||||
|
||||
|
||||
// Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead.
|
||||
const ConfigOptionFloats* machine_max_acceleration_travel = config.option<ConfigOptionFloats>(m_flavor == gcfMarlinLegacy || m_flavor == gcfKlipper
|
||||
? "machine_max_acceleration_extruding"
|
||||
@@ -1327,7 +1269,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (machine_max_acceleration_travel != nullptr)
|
||||
m_time_processor.machine_limits.machine_max_acceleration_travel.values = machine_max_acceleration_travel->values;
|
||||
|
||||
|
||||
const ConfigOptionFloats* machine_min_extruding_rate = config.option<ConfigOptionFloats>("machine_min_extruding_rate");
|
||||
if (machine_min_extruding_rate != nullptr)
|
||||
m_time_processor.machine_limits.machine_min_extruding_rate.values = machine_min_extruding_rate->values;
|
||||
@@ -1379,12 +1320,10 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (bed_type != nullptr)
|
||||
m_result.bed_type = (BedType)bed_type->value;
|
||||
|
||||
|
||||
const ConfigOptionFloat* z_offset = config.option<ConfigOptionFloat>("z_offset");
|
||||
if (z_offset != nullptr)
|
||||
m_z_offset = z_offset->value;
|
||||
|
||||
// SM Orca: 验证所有数组大小是否正确
|
||||
bool arrays_valid = true;
|
||||
if (m_result.filament_diameters.size() != m_result.extruders_count) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: CRITICAL - filament_diameters size mismatch: "
|
||||
@@ -1407,10 +1346,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
arrays_valid = false;
|
||||
}
|
||||
|
||||
if (arrays_valid) {
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: DynamicPrintConfig array validation passed - all arrays correctly sized to "
|
||||
<< m_result.extruders_count;
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeProcessor::enable_stealth_time_estimator(bool enabled)
|
||||
@@ -1850,7 +1785,6 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line, bool
|
||||
// update start position
|
||||
m_start_position = m_end_position;
|
||||
|
||||
// SM Orca: 防止NaN/inf从m_end_position传播到m_start_position
|
||||
if (std::isnan(m_start_position[X]) || std::isinf(m_start_position[X]) ||
|
||||
std::isnan(m_start_position[Y]) || std::isinf(m_start_position[Y]) ||
|
||||
std::isnan(m_start_position[Z]) || std::isinf(m_start_position[Z])) {
|
||||
@@ -2946,7 +2880,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
|
||||
m_end_position[a] = absolute_position((Axis)a, line);
|
||||
}
|
||||
|
||||
// SM Orca: 验证position更新,捕获NaN/inf的源头
|
||||
if (std::isnan(m_end_position[X]) || std::isinf(m_end_position[X]) ||
|
||||
std::isnan(m_end_position[Y]) || std::isinf(m_end_position[Y]) ||
|
||||
std::isnan(m_end_position[Z]) || std::isinf(m_end_position[Z])) {
|
||||
@@ -3026,12 +2959,10 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
|
||||
// cross section: rectangle
|
||||
m_width = delta_pos[E] * static_cast<float>(M_PI * sqr(1.05f * filament_radius)) / (delta_xyz * m_height);
|
||||
else if (m_extrusion_role == erBridgeInfill || m_extrusion_role == erInternalBridgeInfill || m_extrusion_role == erNone) {
|
||||
// SM Orca: 添加边界检查
|
||||
float diameter = (static_cast<size_t>(m_extruder_id) < m_result.filament_diameters.size())
|
||||
? m_result.filament_diameters[m_extruder_id]
|
||||
: m_result.filament_diameters.back();
|
||||
|
||||
// SM Orca: 防止sqrt(负数)产生NaN
|
||||
float ratio = delta_pos[E] / delta_xyz;
|
||||
if (ratio < 0.0f) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: Negative E/XYZ ratio (" << ratio
|
||||
@@ -3046,7 +2977,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
|
||||
// cross section: rectangle + 2 semicircles
|
||||
m_width = delta_pos[E] * static_cast<float>(M_PI * sqr(filament_radius)) / (delta_xyz * m_height) + static_cast<float>(1.0 - 0.25 * M_PI) * m_height;
|
||||
|
||||
// SM Orca: 验证宽度计算结果,防止NaN/inf传播
|
||||
if (std::isnan(m_width) || std::isinf(m_width)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: Invalid width calculated: " << m_width
|
||||
<< " for extruder " << m_extruder_id
|
||||
@@ -3262,7 +3192,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
|
||||
// axis reversal
|
||||
std::max(-v_exit, v_entry));
|
||||
|
||||
|
||||
float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (jerk > axis_max_jerk) {
|
||||
v_factor *= axis_max_jerk / jerk;
|
||||
@@ -3309,7 +3238,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
|
||||
// check for seam starting vertex
|
||||
if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) {
|
||||
//BBS: m_result.moves.back().position has plate offset, must minus plate offset before calculate the real seam position
|
||||
// SM Orca: m_extruder_offsets[i] 已经在 apply_config 中映射过了,这里直接使用 m_extruder_id 作为索引
|
||||
const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset;
|
||||
if (!m_seams_detector.has_first_vertex()) {
|
||||
m_seams_detector.set_first_vertex(new_pos);
|
||||
@@ -3329,7 +3257,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
|
||||
|
||||
const Vec3f curr_pos(m_end_position[X], m_end_position[Y], m_end_position[Z]);
|
||||
//BBS: m_result.moves.back().position has plate offset, must minus plate offset before calculate the real seam position
|
||||
// SM Orca: m_extruder_offsets[i] 已经在 apply_config 中映射过了,这里直接使用 m_extruder_id 作为索引
|
||||
const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset;
|
||||
const std::optional<Vec3f> first_vertex = m_seams_detector.get_first_vertex();
|
||||
// the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later
|
||||
@@ -3345,7 +3272,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line, const std::o
|
||||
}
|
||||
else if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) {
|
||||
m_seams_detector.activate(true);
|
||||
// SM Orca: m_extruder_offsets[i] 已经在 apply_config 中映射过了,这里直接使用 m_extruder_id 作为索引
|
||||
m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset);
|
||||
}
|
||||
|
||||
@@ -3439,7 +3365,6 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
m_end_position[a] = absolute_position((Axis)a, line);
|
||||
}
|
||||
|
||||
// SM Orca: 验证position更新,捕获NaN/inf的源头
|
||||
if (std::isnan(m_end_position[X]) || std::isinf(m_end_position[X]) ||
|
||||
std::isnan(m_end_position[Y]) || std::isinf(m_end_position[Y]) ||
|
||||
std::isnan(m_end_position[Z]) || std::isinf(m_end_position[Z])) {
|
||||
@@ -3499,7 +3424,6 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
|
||||
EMoveType type = move_type(delta_pos[E]);
|
||||
|
||||
|
||||
const float delta_xyz = std::sqrt(sqr(arc_length) + sqr(delta_pos[Z]));
|
||||
m_travel_dist = delta_xyz;
|
||||
if (type == EMoveType::Extrude) {
|
||||
@@ -3548,12 +3472,10 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
//BBS: cross section: rectangle
|
||||
m_width = delta_pos[E] * static_cast<float>(M_PI * sqr(1.05f * filament_radius)) / (delta_xyz * m_height);
|
||||
else if (m_extrusion_role == erBridgeInfill || m_extrusion_role == erInternalBridgeInfill || m_extrusion_role == erNone) {
|
||||
// SM Orca: 添加边界检查
|
||||
float diameter = (static_cast<size_t>(m_extruder_id) < m_result.filament_diameters.size())
|
||||
? m_result.filament_diameters[m_extruder_id]
|
||||
: m_result.filament_diameters.back();
|
||||
|
||||
// SM Orca: 防止sqrt(负数)产生NaN
|
||||
float ratio = delta_pos[E] / delta_xyz;
|
||||
if (ratio < 0.0f) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: Negative E/XYZ ratio (" << ratio
|
||||
@@ -3568,7 +3490,6 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
//BBS: cross section: rectangle + 2 semicircles
|
||||
m_width = delta_pos[E] * static_cast<float>(M_PI * sqr(filament_radius)) / (delta_xyz * m_height) + static_cast<float>(1.0 - 0.25 * M_PI) * m_height;
|
||||
|
||||
// SM Orca: 验证宽度计算结果,防止NaN/inf传播
|
||||
if (std::isnan(m_width) || std::isinf(m_width)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: Invalid width calculated: " << m_width
|
||||
<< " for extruder " << m_extruder_id
|
||||
@@ -3739,7 +3660,6 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
//BBS: axis reversal
|
||||
std::max(-v_exit, v_entry));
|
||||
|
||||
|
||||
float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (jerk > axis_max_jerk) {
|
||||
v_factor *= axis_max_jerk / jerk;
|
||||
@@ -3786,7 +3706,6 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
if (m_seams_detector.is_active()) {
|
||||
//BBS: check for seam starting vertex
|
||||
if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) {
|
||||
// SM Orca: m_extruder_offsets[i] 已经在 apply_config 中映射过了,这里直接使用 m_extruder_id 作为索引
|
||||
const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset;
|
||||
if (!m_seams_detector.has_first_vertex()) {
|
||||
m_seams_detector.set_first_vertex(new_pos);
|
||||
@@ -3804,7 +3723,6 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
m_end_position[X] = pos.x(); m_end_position[Y] = pos.y(); m_end_position[Z] = pos.z();
|
||||
};
|
||||
const Vec3f curr_pos(m_end_position[X], m_end_position[Y], m_end_position[Z]);
|
||||
// SM Orca: m_extruder_offsets[i] 已经在 apply_config 中映射过了,这里直接使用 m_extruder_id 作为索引
|
||||
const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset;
|
||||
const std::optional<Vec3f> first_vertex = m_seams_detector.get_first_vertex();
|
||||
//BBS: the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later
|
||||
@@ -3820,7 +3738,6 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line)
|
||||
}
|
||||
else if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) {
|
||||
m_seams_detector.activate(true);
|
||||
// SM Orca: m_extruder_offsets[i] 已经在 apply_config 中映射过了,这里直接使用 m_extruder_id 作为索引
|
||||
m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset);
|
||||
}
|
||||
|
||||
@@ -3866,21 +3783,17 @@ void GCodeProcessor::process_G29(const GCodeReader::GCodeLine& line)
|
||||
|
||||
void GCodeProcessor::process_G10(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// SM Orca: 回抽参数是挤出机属性,使用 physical_extruder
|
||||
int physical_extruder = get_physical_extruder(m_extruder_id);
|
||||
GCodeReader::GCodeLine g10;
|
||||
g10.set(Axis::E, -this->m_parser.config().retraction_length.get_at(physical_extruder));
|
||||
g10.set(Axis::F, this->m_parser.config().retraction_speed.get_at(physical_extruder) * 60);
|
||||
g10.set(Axis::E, -this->m_parser.config().retraction_length.get_at(m_extruder_id));
|
||||
g10.set(Axis::F, this->m_parser.config().retraction_speed.get_at(m_extruder_id) * 60);
|
||||
process_G1(g10);
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_G11(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// SM Orca: 回抽参数是挤出机属性,使用 physical_extruder
|
||||
int physical_extruder = get_physical_extruder(m_extruder_id);
|
||||
GCodeReader::GCodeLine g11;
|
||||
g11.set(Axis::E, this->m_parser.config().retraction_length.get_at(physical_extruder) + this->m_parser.config().retract_restart_extra.get_at(physical_extruder));
|
||||
g11.set(Axis::F, this->m_parser.config().deretraction_speed.get_at(physical_extruder) * 60);
|
||||
g11.set(Axis::E, this->m_parser.config().retraction_length.get_at(m_extruder_id) + this->m_parser.config().retract_restart_extra.get_at(m_extruder_id));
|
||||
g11.set(Axis::F, this->m_parser.config().deretraction_speed.get_at(m_extruder_id) * 60);
|
||||
process_G1(g11);
|
||||
}
|
||||
|
||||
@@ -3979,7 +3892,6 @@ void GCodeProcessor::process_G92(const GCodeReader::GCodeLine& line)
|
||||
}
|
||||
}
|
||||
|
||||
// SM Orca: 验证m_origin,防止NaN/inf传播
|
||||
if (std::isnan(m_origin[X]) || std::isinf(m_origin[X]) ||
|
||||
std::isnan(m_origin[Y]) || std::isinf(m_origin[Y]) ||
|
||||
std::isnan(m_origin[Z]) || std::isinf(m_origin[Z])) {
|
||||
@@ -4121,7 +4033,6 @@ void GCodeProcessor::process_M191(const GCodeReader::GCodeLine& line)
|
||||
simulate_st_synchronize(wait_chamber_temp_time);
|
||||
}
|
||||
|
||||
|
||||
void GCodeProcessor::process_M201(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
|
||||
@@ -4457,7 +4368,6 @@ void GCodeProcessor::run_post_process()
|
||||
double filament_total_cost = 0.0;
|
||||
|
||||
for (const auto& [id, volume] : m_result.print_statistics.total_volumes_per_extruder) {
|
||||
// SM Orca: 边界检查 - 确保id在有效范围内
|
||||
if (id >= m_result.filament_diameters.size() ||
|
||||
id >= m_result.filament_densities.size() ||
|
||||
id >= m_result.filament_costs.size()) {
|
||||
@@ -4468,12 +4378,10 @@ void GCodeProcessor::run_post_process()
|
||||
continue;
|
||||
}
|
||||
|
||||
// SM Orca: 读取并验证配置值
|
||||
double diameter = m_result.filament_diameters[id];
|
||||
double density = m_result.filament_densities[id];
|
||||
double cost = m_result.filament_costs[id];
|
||||
|
||||
// SM Orca: 防止除零和NaN传播
|
||||
if (diameter <= 0.0 || std::isnan(diameter)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "SM Orca: Invalid filament diameter " << diameter
|
||||
<< " for filament " << id << ", using default 1.75mm";
|
||||
@@ -4492,7 +4400,6 @@ void GCodeProcessor::run_post_process()
|
||||
cost = 0.0;
|
||||
}
|
||||
|
||||
// SM Orca: 执行成本计算
|
||||
double cross_section = M_PI * sqr(0.5 * diameter);
|
||||
filament_mm[id] = volume / cross_section;
|
||||
filament_cm3[id] = volume * 0.001;
|
||||
@@ -4509,7 +4416,6 @@ void GCodeProcessor::run_post_process()
|
||||
|
||||
double total_g_wipe_tower = m_print->print_statistics().total_wipe_tower_filament;
|
||||
|
||||
|
||||
auto time_in_minutes = [](float time_in_seconds) {
|
||||
assert(time_in_seconds >= 0.f);
|
||||
return int((time_in_seconds + 0.5f) / 60.0f);
|
||||
@@ -4637,7 +4543,6 @@ void GCodeProcessor::run_post_process()
|
||||
size_t m_times_cache_id{ 0 };
|
||||
size_t m_out_file_pos{ 0 };
|
||||
|
||||
|
||||
public:
|
||||
ExportLines(EWriteType type,
|
||||
const std::array<TimeMachine, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)>& machines)
|
||||
@@ -5207,7 +5112,6 @@ void GCodeProcessor::run_post_process()
|
||||
|
||||
export_lines.flush(out, m_result, out_path);
|
||||
|
||||
|
||||
out.close();
|
||||
in.close();
|
||||
|
||||
@@ -5225,7 +5129,6 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type)
|
||||
m_line_id + 1 :
|
||||
((type == EMoveType::Seam) ? m_last_line_id : m_line_id);
|
||||
|
||||
// SM Orca: 添加边界检查,防止访问越界
|
||||
Vec3f extruder_offset = (static_cast<size_t>(m_extruder_id) < m_extruder_offsets.size())
|
||||
? m_extruder_offsets[m_extruder_id]
|
||||
: Vec3f(0.0f, 0.0f, 0.0f);
|
||||
@@ -5241,7 +5144,6 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type)
|
||||
extruder_offset;
|
||||
}
|
||||
|
||||
// SM Orca: 最后一道防线,防止无效值进入result
|
||||
if (std::isnan(m_width) || std::isinf(m_width)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: Blocking invalid width: " << m_width
|
||||
<< " (extruder " << m_extruder_id << ")";
|
||||
@@ -5254,7 +5156,6 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type)
|
||||
m_height = DEFAULT_TOOLPATH_HEIGHT;
|
||||
}
|
||||
|
||||
// SM Orca: 验证position,防止NaN/inf进入moves
|
||||
Vec3f final_position = Vec3f(m_end_position[X] + m_x_offset,
|
||||
m_end_position[Y] + m_y_offset,
|
||||
m_processing_start_custom_gcode ? m_first_layer_height : m_end_position[Z] - m_z_offset)
|
||||
@@ -5281,7 +5182,6 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type)
|
||||
m_extruder_id,
|
||||
m_cp_color.current,
|
||||
//BBS: add plate's offset to the rendering vertices
|
||||
// SM Orca: 使用验证过的final_position
|
||||
final_position,
|
||||
static_cast<float>(m_end_position[E] - m_start_position[E]),
|
||||
m_feedrate,
|
||||
@@ -5295,7 +5195,6 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type)
|
||||
static_cast<float>(m_layer_id), //layer_duration: set later
|
||||
//BBS: add arc move related data
|
||||
path_type,
|
||||
// SM Orca: m_extruder_offsets[i] 已经在 apply_config 中映射过了,这里直接使用 m_extruder_id 作为索引
|
||||
Vec3f(m_arc_center(0, 0) + m_x_offset, m_arc_center(1, 0) + m_y_offset, m_arc_center(2, 0)) + m_extruder_offsets[m_extruder_id],
|
||||
m_interpolation_points,
|
||||
});
|
||||
|
||||
@@ -1410,9 +1410,9 @@ void WipeTower2::set_extruder(size_t idx, int physical_extruder, const PrintConf
|
||||
|
||||
m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later
|
||||
|
||||
// SM Orca: 回抽参数是挤出机属性,使用 physical_extruder
|
||||
m_filpar[idx].retract_length = config.retraction_length.get_at(physical_extruder);
|
||||
m_filpar[idx].retract_speed = config.retraction_speed.get_at(physical_extruder);
|
||||
// SM Orca: 回抽参数支持耗材覆盖,继承后存储在耗材位置,使用 filament_id (idx)
|
||||
m_filpar[idx].retract_length = config.retraction_length.get_at(idx);
|
||||
m_filpar[idx].retract_speed = config.retraction_speed.get_at(idx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||
{
|
||||
this->config.apply(print_config, true);
|
||||
m_single_extruder_multi_material = print_config.single_extruder_multi_material.value;
|
||||
m_physical_extruder_count = print_config.nozzle_diameter.values.size();
|
||||
if (m_physical_extruder_count == 0) {
|
||||
m_physical_extruder_count = 1; // 防止除零,默认为1
|
||||
BOOST_LOG_TRIVIAL(warning) << "GCodeWriter::apply_print_config: nozzle_diameter is empty, using default physical_extruder_count=1";
|
||||
}
|
||||
bool use_mach_limits = print_config.gcode_flavor.value == gcfMarlinLegacy || print_config.gcode_flavor.value == gcfMarlinFirmware ||
|
||||
print_config.gcode_flavor.value == gcfKlipper || print_config.gcode_flavor.value == gcfRepRapFirmware;
|
||||
m_max_acceleration = std::lrint(use_mach_limits ? print_config.machine_max_acceleration_extruding.values.front() : 0);
|
||||
@@ -46,13 +51,11 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||
void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "GCodeWriter::set_extruders: START - Creating Extruder objects for " << extruder_ids.size() << " extruders";
|
||||
BOOST_LOG_TRIVIAL(info) << "GCodeWriter::set_extruders: filament_extruder_map size=" << m_filament_extruder_map.size();
|
||||
|
||||
std::sort(extruder_ids.begin(), extruder_ids.end());
|
||||
m_extruder = nullptr; // this points to object inside `m_extruders`, so should be cleared too
|
||||
m_extruders.clear();
|
||||
m_extruders.reserve(extruder_ids.size());
|
||||
// SM Orca: 创建 Extruder 对象时传递物理挤出机ID
|
||||
for (unsigned int extruder_id : extruder_ids) {
|
||||
int physical_extruder_id = get_physical_extruder(extruder_id);
|
||||
BOOST_LOG_TRIVIAL(info) << "GCodeWriter::set_extruders: Creating Extruder - filament_id=" << extruder_id
|
||||
@@ -408,7 +411,6 @@ std::string GCodeWriter::set_input_shaping(char axis, float damp, float freq) co
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
|
||||
std::string GCodeWriter::reset_e(bool force)
|
||||
{
|
||||
if (FLAVOR_IS(gcfMach3)
|
||||
@@ -463,11 +465,8 @@ std::string GCodeWriter::toolchange_prefix() const
|
||||
|
||||
std::string GCodeWriter::toolchange(unsigned int extruder_id)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: GCodeWriter::toolchange(" << extruder_id << ") called";
|
||||
|
||||
// SM Orca: 记录映射信息
|
||||
int physical_extruder = get_physical_extruder(extruder_id);
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: Toolchange - filament " << extruder_id << " maps to physical extruder " << physical_extruder << " (mapping table size: " << m_filament_extruder_map.size() << ")";
|
||||
|
||||
// set the new extruder
|
||||
auto it_extruder = Slic3r::lower_bound_by_predicate(m_extruders.begin(), m_extruders.end(), [extruder_id](const Extruder &e) { return e.id() < extruder_id; });
|
||||
@@ -478,8 +477,6 @@ std::string GCodeWriter::toolchange(unsigned int extruder_id)
|
||||
// if we are running a single-extruder setup, just set the extruder and return nothing
|
||||
std::ostringstream gcode;
|
||||
if (this->multiple_extruders || (this->config.filament_diameter.values.size() > 1 && !is_bbl_printers())) {
|
||||
// SM Orca: T命令使用耗材序号(extruder_id),物理换头由固件处理
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: Generating T command: T" << extruder_id;
|
||||
gcode << this->toolchange_prefix() << extruder_id;
|
||||
//BBS
|
||||
if (GCodeWriter::full_gcode_comment)
|
||||
@@ -487,7 +484,6 @@ std::string GCodeWriter::toolchange(unsigned int extruder_id)
|
||||
gcode << "\n";
|
||||
gcode << this->reset_e(true);
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: Toolchange - Single extruder mode, no T command generated";
|
||||
}
|
||||
return gcode.str();
|
||||
}
|
||||
@@ -508,7 +504,6 @@ std::string GCodeWriter::set_speed(double F, const std::string &comment, const s
|
||||
|
||||
std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string &comment)
|
||||
{
|
||||
// SM Orca: 诊断NaN输入
|
||||
if (std::isnan(point(0)) || std::isinf(point(0)) || std::isnan(point(1)) || std::isinf(point(1))) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: travel_to_xy received NaN/inf point"
|
||||
<< " extruder=" << (m_extruder ? m_extruder->id() : -1)
|
||||
@@ -736,7 +731,6 @@ bool GCodeWriter::will_move_z(double z) const
|
||||
|
||||
std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std::string &comment, bool force_no_extrusion)
|
||||
{
|
||||
// SM Orca: 诊断NaN输入
|
||||
if (std::isnan(point(0)) || std::isinf(point(0)) || std::isnan(point(1)) || std::isinf(point(1))) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SM Orca: extrude_to_xy received NaN/inf point"
|
||||
<< " extruder=" << (m_extruder ? m_extruder->id() : -1)
|
||||
|
||||
@@ -123,10 +123,24 @@ public:
|
||||
// SM Orca: 设置耗材-挤出机映射
|
||||
void set_filament_extruder_map(const std::unordered_map<int, int>& map) { m_filament_extruder_map = map; }
|
||||
const std::unordered_map<int, int>& get_filament_extruder_map() const { return m_filament_extruder_map; }
|
||||
// SM Orca: 获取物理挤出机ID(如果没有映射,返回耗材ID本身)
|
||||
// SM Orca: 获取物理挤出机ID
|
||||
// 关键修复:当映射表为空时,使用模运算而不是直接返回耗材ID,避免越界
|
||||
// 例如:4个物理挤出机时,耗材0-7分别映射到0,1,2,3,0,1,2,3
|
||||
int get_physical_extruder(int filament_idx) const {
|
||||
auto it = m_filament_extruder_map.find(filament_idx);
|
||||
int physical_extruder_id = (it != m_filament_extruder_map.end()) ? it->second : filament_idx;
|
||||
int physical_extruder_id;
|
||||
if (it != m_filament_extruder_map.end()) {
|
||||
// 从映射表获取
|
||||
physical_extruder_id = it->second;
|
||||
} else {
|
||||
// 映射表为空或没有该耗材的映射,使用默认模运算映射
|
||||
physical_extruder_id = filament_idx % m_physical_extruder_count;
|
||||
}
|
||||
// SM Orca: 日志 - 映射查询
|
||||
BOOST_LOG_TRIVIAL(info) << "GCodeWriter::get_physical_extruder: filament_id=" << filament_idx
|
||||
<< " -> physical_extruder_id=" << physical_extruder_id
|
||||
<< " (map_size=" << m_filament_extruder_map.size() << ", physical_count=" << m_physical_extruder_count << ")"
|
||||
<< (it != m_filament_extruder_map.end() ? " [from_map]" : " [default_mod]");
|
||||
return physical_extruder_id;
|
||||
}
|
||||
|
||||
@@ -183,6 +197,8 @@ public:
|
||||
|
||||
// SM Orca: 耗材到物理挤出机的映射表(filament_idx -> physical_extruder_id)
|
||||
std::unordered_map<int, int> m_filament_extruder_map;
|
||||
// SM Orca: 物理挤出机数量(用于默认模运算映射)
|
||||
size_t m_physical_extruder_count = 1; // 默认为1,防止除零
|
||||
|
||||
enum class Acceleration {
|
||||
Travel,
|
||||
|
||||
+53
-39
@@ -493,7 +493,6 @@ std::vector<unsigned int> Print::extruders(bool conside_custom_gcode) const
|
||||
return extruders;
|
||||
}
|
||||
|
||||
// SM Orca: Initialize filament-to-physical-extruder mapping
|
||||
// This must be called before the mapping is used (e.g., before export_gcode)
|
||||
void Print::initialize_filament_extruder_map()
|
||||
{
|
||||
@@ -503,16 +502,35 @@ void Print::initialize_filament_extruder_map()
|
||||
size_t physical_extruder_count = m_config.nozzle_diameter.values.size();
|
||||
|
||||
if (physical_extruder_count == 0) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Print::initialize_filament_extruder_map: No physical extruders configured!";
|
||||
BOOST_LOG_TRIVIAL(error) << "Print::initialize_filament_extruder_map: ERROR - No physical extruders configured!";
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all filament indices that will be used
|
||||
std::vector<unsigned int> filament_extruders = this->extruders();
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Print::initialize_filament_extruder_map: Initializing with "
|
||||
<< physical_extruder_count << " physical extruders and "
|
||||
<< filament_extruders.size() << " filaments to map";
|
||||
// IMPORTANT: Always create mappings for ALL configured filaments, not just those used by objects.
|
||||
// This is critical because filament override parameters need to access the mapping for all filaments.
|
||||
// For example, if a user has 8 filaments configured but only uses 4 in their model,
|
||||
// the mapping table must still contain entries for all 8 filaments to correctly
|
||||
// inherit parameters from the corresponding physical extruders.
|
||||
// extruders() returns empty. In this case, use filament_diameter.size() to determine filament count.
|
||||
// This ensures the mapping is created for all configured filaments, not just those used by objects.
|
||||
if (filament_extruders.empty()) {
|
||||
size_t filament_count = m_config.filament_diameter.size();
|
||||
for (size_t i = 0; i < filament_count; ++i) {
|
||||
filament_extruders.push_back((unsigned int)i);
|
||||
}
|
||||
} else {
|
||||
// Even if extruders() returns some values, we need to ensure ALL configured filaments are in the map.
|
||||
// Add any missing filament indices that are configured but not used by objects.
|
||||
size_t configured_filament_count = m_config.filament_diameter.size();
|
||||
for (size_t i = 0; i < configured_filament_count; ++i) {
|
||||
if (std::find(filament_extruders.begin(), filament_extruders.end(), (unsigned int)i) == filament_extruders.end()) {
|
||||
filament_extruders.push_back((unsigned int)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create mapping: filament_id -> physical_extruder_id
|
||||
// Mapping formula: physical_extruder = filament_id % physical_extruder_count
|
||||
@@ -522,13 +540,7 @@ void Print::initialize_filament_extruder_map()
|
||||
for (unsigned int filament_idx : filament_extruders) {
|
||||
int physical_extruder = filament_idx % physical_extruder_count;
|
||||
m_filament_extruder_map[filament_idx] = physical_extruder;
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Print::initialize_filament_extruder_map: filament "
|
||||
<< filament_idx << " -> physical_extruder " << physical_extruder;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Print::initialize_filament_extruder_map: Map initialized with "
|
||||
<< m_filament_extruder_map.size() << " entries";
|
||||
}
|
||||
|
||||
unsigned int Print::num_object_instances() const
|
||||
@@ -543,7 +555,6 @@ double Print::max_allowed_layer_height() const
|
||||
{
|
||||
double nozzle_diameter_max = 0.;
|
||||
for (unsigned int extruder_id : this->extruders()) {
|
||||
// SM Orca: 使用物理挤出机的喷嘴直径
|
||||
int physical_extruder = get_physical_extruder(extruder_id);
|
||||
nozzle_diameter_max = std::max(nozzle_diameter_max, m_config.nozzle_diameter.get_at(physical_extruder));
|
||||
}
|
||||
@@ -1224,7 +1235,6 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||
if (this->has_wipe_tower() && ! m_objects.empty()) {
|
||||
// Make sure all extruders use same diameter filament and have the same nozzle diameter
|
||||
// EPSILON comparison is used for nozzles and 10 % tolerance is used for filaments
|
||||
// SM Orca: 使用物理挤出机的喷嘴直径
|
||||
int first_physical = get_physical_extruder(extruders.front());
|
||||
double first_nozzle_diam = m_config.nozzle_diameter.get_at(first_physical);
|
||||
double first_filament_diam = m_config.filament_diameter.get_at(extruders.front());
|
||||
@@ -1336,7 +1346,6 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||
double min_nozzle_diameter = std::numeric_limits<double>::max();
|
||||
double max_nozzle_diameter = 0;
|
||||
for (unsigned int extruder_id : extruders) {
|
||||
// SM Orca: 使用物理挤出机的喷嘴直径
|
||||
int physical_extruder = get_physical_extruder(extruder_id);
|
||||
double dmr = m_config.nozzle_diameter.get_at(physical_extruder);
|
||||
min_nozzle_diameter = std::min(min_nozzle_diameter, dmr);
|
||||
@@ -1426,7 +1435,6 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||
size_t first_layer_extruder = object->config().raft_layers == 1
|
||||
? object->config().support_interface_filament-1
|
||||
: object->config().support_filament-1;
|
||||
// SM Orca: 使用物理挤出机的喷嘴直径
|
||||
int physical_extruder = get_physical_extruder(first_layer_extruder);
|
||||
first_layer_min_nozzle_diameter = (first_layer_extruder == size_t(-1)) ?
|
||||
min_nozzle_diameter :
|
||||
@@ -1748,7 +1756,6 @@ Flow Print::brim_flow() const
|
||||
extruders and take the one with, say, the smallest index.
|
||||
The same logic should be applied to the code that selects the extruder during G-code
|
||||
generation as well. */
|
||||
// SM Orca: 使用物理挤出机的喷嘴直径
|
||||
int filament_idx = m_print_regions.front()->config().wall_filament - 1;
|
||||
int physical_extruder = get_physical_extruder(filament_idx);
|
||||
return Flow::new_from_config_width(
|
||||
@@ -1770,7 +1777,6 @@ Flow Print::skirt_flow() const
|
||||
extruders and take the one with, say, the smallest index;
|
||||
The same logic should be applied to the code that selects the extruder during G-code
|
||||
generation as well. */
|
||||
// SM Orca: 使用物理挤出机的喷嘴直径
|
||||
int filament_idx = m_objects.front()->config().support_filament - 1;
|
||||
int physical_extruder = get_physical_extruder(filament_idx);
|
||||
return Flow::new_from_config_width(
|
||||
@@ -1856,7 +1862,6 @@ void PrintObject::copy_layers_overhang_from_shared_object()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// BBS
|
||||
BoundingBox PrintObject::get_first_layer_bbox(float& a, float& layer_height, std::string& name)
|
||||
{
|
||||
@@ -2207,7 +2212,6 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
append(m_first_layer_convex_hull.points, std::move(poly.points));
|
||||
}
|
||||
|
||||
|
||||
if (has_skirt() && ! draft_shield) {
|
||||
// In case that draft shield is NOT active, generate skirt now.
|
||||
// It will be placed around the brim, so brim has to be ready.
|
||||
@@ -2296,21 +2300,41 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor
|
||||
const Vec3d origin = this->get_plate_origin();
|
||||
gcode.set_gcode_offset(origin(0), origin(1));
|
||||
|
||||
// SM Orca: Initialize filament-to-extruder mapping before it's used
|
||||
this->initialize_filament_extruder_map();
|
||||
|
||||
// SM Orca: 设置耗材-挤出机映射
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: Print::export_gcode - Setting filament_extruder_map to GCode, mapping size: " << m_filament_extruder_map.size();
|
||||
for (const auto& pair : m_filament_extruder_map) {
|
||||
BOOST_LOG_TRIVIAL(info) << " SM Orca: Print mapping: filament " << pair.first << " -> extruder " << pair.second;
|
||||
}
|
||||
gcode.set_filament_extruder_map(m_filament_extruder_map);
|
||||
BOOST_LOG_TRIVIAL(info) << "SM Orca: Print::export_gcode - Mapping set to GCode object, calling do_export";
|
||||
gcode.do_export(this, path.c_str(), result, thumbnail_cb);
|
||||
|
||||
//BBS
|
||||
result->conflict_result = m_conflict_result;
|
||||
return path.c_str();
|
||||
|
||||
// After G-code export is complete, finalize the output path by replacing placeholders with actual values
|
||||
// This ensures that placeholders like {print_time} are replaced with calculated values
|
||||
// Note: This is needed for direct export (not through BackgroundSlicingProcess) where
|
||||
// finalize_output_path() might not be called automatically
|
||||
std::string final_path = this->print_statistics().finalize_output_path(path);
|
||||
|
||||
// Rename the file from the placeholder path to the finalized path
|
||||
if (final_path != path) {
|
||||
std::error_code ret = rename_file(path, final_path);
|
||||
if (ret) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Failed to rename G-code file from '" << path
|
||||
<< "' to '" << final_path << "': " << ret.message();
|
||||
// If rename fails, return the original path
|
||||
return path;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << "Renamed G-code file from '" << path
|
||||
<< "' to '" << final_path << "'";
|
||||
// Update result filename to reflect the new path
|
||||
if (result) {
|
||||
result->filename = final_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return final_path;
|
||||
}
|
||||
|
||||
void Print::_make_skirt()
|
||||
@@ -2396,7 +2420,6 @@ void Print::_make_skirt()
|
||||
extruders_e_per_mm.reserve(set_extruders.size());
|
||||
for (auto &extruder_id : set_extruders) {
|
||||
extruders.push_back(extruder_id);
|
||||
// SM Orca: 创建 Extruder 对象时传递物理挤出机ID
|
||||
int physical_extruder_id = get_physical_extruder(extruder_id);
|
||||
extruders_e_per_mm.push_back(Extruder((unsigned int)extruder_id, physical_extruder_id, &m_config, m_config.single_extruder_multi_material).e_per_mm(mm3_per_mm));
|
||||
}
|
||||
@@ -2798,7 +2821,6 @@ void Print::_make_wipe_tower()
|
||||
// wipe_tower.set_zhop();
|
||||
|
||||
// Set the extruder & material properties at the wipe tower object.
|
||||
// SM Orca: 传递物理挤出机ID以支持耗材-挤出机映射
|
||||
for (size_t i = 0; i < number_of_extruders; ++i) {
|
||||
int physical_extruder = get_physical_extruder(i);
|
||||
wipe_tower.set_extruder(i, physical_extruder, m_config);
|
||||
@@ -2897,7 +2919,6 @@ void Print::_make_wipe_tower()
|
||||
// wipe_tower.set_zhop();
|
||||
|
||||
// Set the extruder & material properties at the wipe tower object.
|
||||
// SM Orca: 传递物理挤出机ID以支持耗材-挤出机映射
|
||||
for (size_t i = 0; i < number_of_extruders; ++i) {
|
||||
int physical_extruder = get_physical_extruder(i);
|
||||
wipe_tower.set_extruder(i, physical_extruder, m_config);
|
||||
@@ -2991,7 +3012,10 @@ std::string Print::output_filename(const std::string &filename_base) const
|
||||
{
|
||||
// Set the placeholders for the data know first after the G-code export is finished.
|
||||
// These values will be just propagated into the output file name.
|
||||
DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders();
|
||||
// Use cached statistics if available (even if not finished) to avoid placeholders like {print_time}
|
||||
const PrintStatistics& stats = this->print_statistics();
|
||||
bool has_valid_stats = stats.total_used_filament > 0 || !stats.estimated_normal_print_time.empty();
|
||||
DynamicConfig config = (this->finished() || has_valid_stats) ? stats.config() : stats.placeholders();
|
||||
config.set_key_value("num_filaments", new ConfigOptionInt((int)m_config.nozzle_diameter.size()));
|
||||
config.set_key_value("num_extruders", new ConfigOptionInt((int) m_config.nozzle_diameter.size()));
|
||||
config.set_key_value("plate_name", new ConfigOptionString(get_plate_name()));
|
||||
@@ -3041,7 +3065,6 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces
|
||||
GCodeProcessor::s_IsBBLPrinter = is_BBL_printer();
|
||||
const Vec3d origin = this->get_plate_origin();
|
||||
processor.set_xy_offset(origin(0), origin(1));
|
||||
// SM Orca: 设置耗材到物理挤出机的映射
|
||||
processor.set_filament_extruder_map(m_filament_extruder_map);
|
||||
//processor.enable_producers(true);
|
||||
processor.process_file(file);
|
||||
@@ -3186,7 +3209,6 @@ const std::string PrintStatistics::TotalFilamentCostValueMask = "; total filamen
|
||||
const std::string PrintStatistics::TotalFilamentUsedWipeTower = "total filament used for wipe tower [g]";
|
||||
const std::string PrintStatistics::TotalFilamentUsedWipeTowerValueMask = "; total filament used for wipe tower [g] = %.2lf\n";
|
||||
|
||||
|
||||
/*add json export/import related functions */
|
||||
#define JSON_POLYGON_CONTOUR "contour"
|
||||
#define JSON_POLYGON_HOLES "holes"
|
||||
@@ -3196,7 +3218,6 @@ const std::string PrintStatistics::TotalFilamentUsedWipeTowerValueMask = "; tota
|
||||
#define JSON_OBJECT_NAME "name"
|
||||
#define JSON_IDENTIFY_ID "identify_id"
|
||||
|
||||
|
||||
#define JSON_LAYERS "layers"
|
||||
#define JSON_SUPPORT_LAYERS "support_layers"
|
||||
#define JSON_TREE_SUPPORT_LAYERS "tree_support_layers"
|
||||
@@ -3233,8 +3254,6 @@ const std::string PrintStatistics::TotalFilamentUsedWipeTowerValueMask = "; tota
|
||||
#define JSON_LAYER_REGION_PERIMETERS "perimeters"
|
||||
#define JSON_LAYER_REGION_FILLS "fills"
|
||||
|
||||
|
||||
|
||||
#define JSON_SURF_TYPE "surface_type"
|
||||
#define JSON_SURF_THICKNESS "thickness"
|
||||
#define JSON_SURF_THICKNESS_LAYER "thickness_layers"
|
||||
@@ -3274,7 +3293,6 @@ const std::string PrintStatistics::TotalFilamentUsedWipeTowerValueMask = "; tota
|
||||
#define JSON_EXTRUSION_NO_EXTRUSION "no_extrusion"
|
||||
#define JSON_EXTRUSION_LOOP_ROLE "loop_role"
|
||||
|
||||
|
||||
static void to_json(json& j, const Points& p_s) {
|
||||
for (const Point& p : p_s)
|
||||
{
|
||||
@@ -3338,7 +3356,6 @@ static void to_json(json& j, const ArcSegment& arc_seg) {
|
||||
j[JSON_ARC_CENTER] = std::move(center_point_json);
|
||||
}
|
||||
|
||||
|
||||
static void to_json(json& j, const Polyline& poly_line) {
|
||||
json points_json = json::array(), fittings_json = json::array();
|
||||
points_json = poly_line.points;
|
||||
@@ -3612,7 +3629,6 @@ static void from_json(const json& j, ArcSegment& arc_seg) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void from_json(const json& j, Polyline& poly_line) {
|
||||
poly_line.points = j[JSON_POINTS];
|
||||
|
||||
@@ -3823,7 +3839,6 @@ static void convert_layer_region_from_json(const json& j, LayerRegion& layer_reg
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void extract_layer(const json& layer_json, Layer& layer) {
|
||||
//slice_polygons
|
||||
int slice_polygons_count = layer_json[JSON_LAYER_SLICED_POLYGONS].size();
|
||||
@@ -4194,7 +4209,6 @@ int Print::export_cached_data(const std::string& directory, bool with_space)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int Print::load_cached_data(const std::string& directory)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
+21
-2
@@ -894,10 +894,29 @@ public:
|
||||
// SM Orca: 获取耗材-挤出机映射表
|
||||
const std::unordered_map<int, int>& get_filament_extruder_map() const { return m_filament_extruder_map; }
|
||||
// SM Orca: 获取物理挤出机ID(根据耗材索引)
|
||||
// 关键修复:当映射表为空时,使用模运算而不是直接返回耗材ID,避免越界
|
||||
int get_physical_extruder(int filament_idx) const {
|
||||
auto it = m_filament_extruder_map.find(filament_idx);
|
||||
int physical_extruder_id = (it != m_filament_extruder_map.end()) ? it->second : filament_idx;
|
||||
|
||||
int physical_extruder_id;
|
||||
if (it != m_filament_extruder_map.end()) {
|
||||
// 从映射表获取
|
||||
physical_extruder_id = it->second;
|
||||
} else {
|
||||
// 映射表为空或没有该耗材的映射,使用默认模运算映射
|
||||
size_t physical_count = m_config.nozzle_diameter.values.size();
|
||||
if (physical_count == 0) {
|
||||
// 防止除零,使用安全的默认值
|
||||
physical_extruder_id = 0;
|
||||
BOOST_LOG_TRIVIAL(warning) << "Print::get_physical_extruder: nozzle_diameter is empty! Using default physical_extruder=0";
|
||||
} else {
|
||||
physical_extruder_id = filament_idx % physical_count;
|
||||
}
|
||||
}
|
||||
// SM Orca: 日志 - 映射查询
|
||||
BOOST_LOG_TRIVIAL(info) << "Print::get_physical_extruder: filament_id=" << filament_idx
|
||||
<< " -> physical_extruder_id=" << physical_extruder_id
|
||||
<< " (map_size=" << m_filament_extruder_map.size() << ")"
|
||||
<< (it != m_filament_extruder_map.end() ? " [from_map]" : " [default_mod]");
|
||||
return physical_extruder_id;
|
||||
}
|
||||
// SM Orca: Initialize filament-to-physical-extruder mapping table
|
||||
|
||||
+190
-45
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <cfloat>
|
||||
#include <sstream>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -216,50 +217,127 @@ static bool custom_per_printz_gcodes_tool_changes_differ(const std::vector<Custo
|
||||
return false;
|
||||
}
|
||||
|
||||
// SM Orca: Apply physical extruder mapping to filament parameters without overrides
|
||||
// For each filament slot, if no override is provided, inherit from the mapped physical extruder
|
||||
static void apply_physical_extruder_defaults(
|
||||
ConfigOption* target,
|
||||
// IMPORTANT: This function creates a NEW target array with filament_count elements
|
||||
static ConfigOption* apply_physical_extruder_defaults(
|
||||
const ConfigOption* filament_overrides,
|
||||
const ConfigOption* extruder_defaults,
|
||||
size_t filament_count,
|
||||
const std::unordered_map<int, int>& filament_extruder_map)
|
||||
{
|
||||
if (!target->is_vector() || !extruder_defaults->is_vector())
|
||||
return;
|
||||
if (!extruder_defaults->is_vector())
|
||||
return nullptr;
|
||||
|
||||
auto* target_vec = dynamic_cast<ConfigOptionVectorBase*>(target);
|
||||
auto* extruder_vec = dynamic_cast<const ConfigOptionVectorBase*>(extruder_defaults);
|
||||
const ConfigOptionVectorBase* override_vec = filament_overrides ?
|
||||
dynamic_cast<const ConfigOptionVectorBase*>(filament_overrides) : nullptr;
|
||||
|
||||
if (!target_vec || !extruder_vec)
|
||||
return;
|
||||
if (!extruder_vec)
|
||||
return nullptr;
|
||||
|
||||
size_t num_filaments = target_vec->size();
|
||||
// Clone the extruder defaults to create the target
|
||||
auto* target = extruder_defaults->clone();
|
||||
auto* target_vec = dynamic_cast<ConfigOptionVectorBase*>(target);
|
||||
if (!target_vec) {
|
||||
delete target;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (size_t filament_idx = 0; filament_idx < num_filaments; ++filament_idx) {
|
||||
// Check if this filament has an override
|
||||
// Resize target to filament_count
|
||||
target_vec->resize(filament_count);
|
||||
|
||||
for (size_t filament_idx = 0; filament_idx < filament_count; ++filament_idx) {
|
||||
bool has_override = false;
|
||||
if (override_vec && filament_idx < override_vec->size()) {
|
||||
has_override = override_vec->nullable() ? !override_vec->is_nil(filament_idx) : true;
|
||||
}
|
||||
if (override_vec->nullable()) {
|
||||
// Nullable type: use override only if not nil (checkbox is checked)
|
||||
has_override = !override_vec->is_nil(filament_idx);
|
||||
} else {
|
||||
// Non-nullable type: check if the value differs from the default (printer config)
|
||||
// Only if it's different do we consider it a user override
|
||||
// Get the default value from the mapped physical extruder
|
||||
auto map_it = filament_extruder_map.find(filament_idx);
|
||||
int physical_extruder_idx;
|
||||
if (map_it != filament_extruder_map.end()) {
|
||||
physical_extruder_idx = map_it->second;
|
||||
} else {
|
||||
// Fallback: use modulo to map filament to physical extruder
|
||||
// This handles edge cases where the map is incomplete or filament_idx is out of range
|
||||
size_t physical_extruder_count = extruder_vec->size();
|
||||
if (physical_extruder_count == 0) {
|
||||
// Should not happen, but safety check
|
||||
physical_extruder_idx = 0;
|
||||
} else {
|
||||
physical_extruder_idx = (int)filament_idx % (int)physical_extruder_count;
|
||||
}
|
||||
}
|
||||
|
||||
// If no override, inherit from the mapped physical extruder
|
||||
if (!has_override) {
|
||||
auto map_it = filament_extruder_map.find(filament_idx);
|
||||
int physical_extruder_idx = (map_it != filament_extruder_map.end()) ?
|
||||
map_it->second : filament_idx;
|
||||
if (physical_extruder_idx < extruder_vec->size()) {
|
||||
// Try different types: double, int, bool
|
||||
auto* override_dbl = dynamic_cast<const ConfigOptionVector<double>*>(override_vec);
|
||||
auto* extruder_dbl = dynamic_cast<const ConfigOptionVector<double>*>(extruder_vec);
|
||||
if (override_dbl && extruder_dbl) {
|
||||
// Compare with the value from the mapped physical extruder
|
||||
double override_value = override_dbl->get_at(filament_idx);
|
||||
double default_value = extruder_dbl->get_at(physical_extruder_idx);
|
||||
// Use override only if value differs from default
|
||||
has_override = (override_value != default_value);
|
||||
|
||||
if (physical_extruder_idx < extruder_vec->size()) {
|
||||
target_vec->set_at(extruder_vec, filament_idx, physical_extruder_idx);
|
||||
} else {
|
||||
// Try int type
|
||||
auto* override_int = dynamic_cast<const ConfigOptionVector<int>*>(override_vec);
|
||||
auto* extruder_int = dynamic_cast<const ConfigOptionVector<int>*>(extruder_vec);
|
||||
if (override_int && extruder_int) {
|
||||
int override_value = override_int->get_at(filament_idx);
|
||||
int default_value = extruder_int->get_at(physical_extruder_idx);
|
||||
has_override = (override_value != default_value);
|
||||
} else {
|
||||
// Try bool type
|
||||
auto* override_bool = dynamic_cast<const ConfigOptionVector<unsigned char>*>(override_vec);
|
||||
auto* extruder_bool = dynamic_cast<const ConfigOptionVector<unsigned char>*>(extruder_vec);
|
||||
if (override_bool && extruder_bool) {
|
||||
unsigned char override_value = override_bool->get_at(filament_idx);
|
||||
unsigned char default_value = extruder_bool->get_at(physical_extruder_idx);
|
||||
has_override = (override_value != default_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_override) {
|
||||
// No override: inherit from the mapped physical extruder
|
||||
auto map_it = filament_extruder_map.find(filament_idx);
|
||||
int physical_extruder_idx;
|
||||
if (map_it != filament_extruder_map.end()) {
|
||||
physical_extruder_idx = map_it->second;
|
||||
} else {
|
||||
// Fallback: use modulo to map filament to physical extruder
|
||||
// This handles edge cases where the map is incomplete or filament_idx is out of range
|
||||
size_t physical_extruder_count = extruder_vec->size();
|
||||
if (physical_extruder_count == 0) {
|
||||
// Should not happen, but safety check
|
||||
physical_extruder_idx = 0;
|
||||
} else {
|
||||
physical_extruder_idx = (int)filament_idx % (int)physical_extruder_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (physical_extruder_idx < extruder_vec->size() && filament_idx < target_vec->size()) {
|
||||
target_vec->set_at(extruder_vec, filament_idx, physical_extruder_idx);
|
||||
}
|
||||
} else if (override_vec && filament_idx < override_vec->size()) {
|
||||
// Has override: use the value from filament config
|
||||
target_vec->set_at(override_vec, filament_idx, filament_idx);
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
// Collect changes to print config, account for overrides of extruder retract values by filament presets.
|
||||
//BBS: add plate index
|
||||
// SM Orca: add filament_extruder_map for physical extruder mapping
|
||||
static t_config_option_keys print_config_diffs(
|
||||
const PrintConfig ¤t_config,
|
||||
const DynamicPrintConfig &new_full_config,
|
||||
@@ -284,45 +362,81 @@ static t_config_option_keys print_config_diffs(
|
||||
// const ConfigOption *opt_new_filament = std::binary_search(extruder_retract_keys.begin(), extruder_retract_keys.end(), opt_key) ? new_full_config.option(filament_prefix + opt_key) : nullptr;
|
||||
const ConfigOption* opt_new_filament = (iter == extruder_retract_keys.end()) ? nullptr :
|
||||
new_full_config.option(filament_prefix + opt_key);
|
||||
if (opt_new_filament != nullptr && ! opt_new_filament->is_nil()) {
|
||||
|
||||
bool is_extruder_retract_param = (iter != extruder_retract_keys.end());
|
||||
|
||||
// 1. This is an extruder retract parameter AND
|
||||
// 2. Filament overrides exist AND
|
||||
// 3. Filament-extruder map is not empty (meaning objects are loaded and mapping is initialized)
|
||||
// When user edits printer config directly (without objects loaded or without filament overrides),
|
||||
// we should treat it as a regular config change to ensure UI updates work correctly.
|
||||
bool has_filament_overrides = (opt_new_filament != nullptr && !opt_new_filament->is_nil());
|
||||
bool needs_physical_mapping = is_extruder_retract_param && has_filament_overrides && !filament_extruder_map.empty();
|
||||
|
||||
if (needs_physical_mapping) {
|
||||
|
||||
// This is safe because both opt_old and opt_new should have the same number of physical extruders
|
||||
bool printer_config_changed = (*opt_old != *opt_new);
|
||||
|
||||
auto* override_vec = dynamic_cast<const ConfigOptionVectorBase*>(opt_new_filament);
|
||||
if (override_vec) {
|
||||
BOOST_LOG_TRIVIAL(info) << "print_config_diffs: " << opt_key
|
||||
<< " - filament_override size=" << override_vec->size()
|
||||
<< ", nullable=" << override_vec->nullable();
|
||||
}
|
||||
|
||||
// since we know has_filament_overrides is true at this point
|
||||
if ((opt_key == "long_retractions_when_cut" || opt_key == "retraction_distances_when_cut")
|
||||
&& new_full_config.option<ConfigOptionInt>("enable_long_retraction_when_cut")->value != LongRectrationLevel::EnableFilament)
|
||||
continue;
|
||||
|
||||
// - Check if printer config or filament override changed the effective value
|
||||
// - Only add to print_diff (not filament_overrides) to avoid array size mismatch
|
||||
// The actual filament->extruder mapping is applied later during config usage
|
||||
//
|
||||
// 关键修复:只要打印机配置变化了,就应该添加到 print_diff
|
||||
// 这确保了用户在UI中修改打印机配置时,修改能被正确保存
|
||||
auto opt_copy = opt_new->clone();
|
||||
opt_copy->apply_override(opt_new_filament);
|
||||
if (printer_config_changed || *opt_old != *opt_copy) {
|
||||
print_diff.emplace_back(opt_key);
|
||||
BOOST_LOG_TRIVIAL(info) << "print_config_diffs: " << opt_key
|
||||
<< " - adding to print_diff (printer_changed=" << (printer_config_changed ? "Y" : "N")
|
||||
<< ", effective_changed=" << (*opt_old != *opt_copy ? "Y" : "N") << ")";
|
||||
}
|
||||
delete opt_copy;
|
||||
} else if (opt_new_filament != nullptr && ! opt_new_filament->is_nil()) {
|
||||
// An extruder retract override is available at some of the filament presets.
|
||||
bool overriden = opt_new->overriden_by(opt_new_filament);
|
||||
if (overriden || *opt_old != *opt_new) {
|
||||
|
||||
bool printer_config_changed = (*opt_old != *opt_new);
|
||||
|
||||
if (overriden || printer_config_changed) {
|
||||
auto opt_copy = opt_new->clone();
|
||||
if (!((opt_key == "long_retractions_when_cut" || opt_key == "retraction_distances_when_cut")
|
||||
&& new_full_config.option<ConfigOptionInt>("enable_long_retraction_when_cut")->value != LongRectrationLevel::EnableFilament)) // ugly code, remove it later if firmware supports
|
||||
opt_copy->apply_override(opt_new_filament);
|
||||
|
||||
// SM Orca: Apply physical extruder mapping for slots without overrides
|
||||
bool is_extruder_retract_param = (iter != extruder_retract_keys.end());
|
||||
if (is_extruder_retract_param && !filament_extruder_map.empty()) {
|
||||
apply_physical_extruder_defaults(opt_copy, opt_new_filament, opt_new, filament_extruder_map);
|
||||
}
|
||||
|
||||
bool changed = *opt_old != *opt_copy;
|
||||
if (changed)
|
||||
print_diff.emplace_back(opt_key);
|
||||
if (changed || overriden) {
|
||||
|
||||
// If user directly edited printer config, don't override it with filament values
|
||||
if ((changed || overriden) && !printer_config_changed) {
|
||||
if ((opt_key == "long_retractions_when_cut" || opt_key == "retraction_distances_when_cut")
|
||||
&& new_full_config.option<ConfigOptionInt>("enable_long_retraction_when_cut")->value != LongRectrationLevel::EnableFilament)
|
||||
continue;
|
||||
// filament_overrides will be applied to the placeholder parser, which layers these parameters over full_print_config.
|
||||
filament_overrides.set_key_value(opt_key, opt_copy);
|
||||
} else
|
||||
} else if (changed && printer_config_changed) {
|
||||
// Only add to print_diff, not to filament_overrides
|
||||
// This preserves user's printer config edit
|
||||
BOOST_LOG_TRIVIAL(info) << "print_config_diffs: " << opt_key
|
||||
<< " - printer config changed, not adding to filament_overrides to preserve user edit";
|
||||
delete opt_copy;
|
||||
}
|
||||
} else if (iter != extruder_retract_keys.end() && !filament_extruder_map.empty()) {
|
||||
// SM Orca: No filament override exists, but this is an extruder retract parameter
|
||||
// Apply physical extruder mapping to inherit from correct extruders
|
||||
auto opt_copy = opt_new->clone();
|
||||
apply_physical_extruder_defaults(opt_copy, nullptr, opt_new, filament_extruder_map);
|
||||
|
||||
bool changed = *opt_old != *opt_copy;
|
||||
if (changed) {
|
||||
print_diff.emplace_back(opt_key);
|
||||
filament_overrides.set_key_value(opt_key, opt_copy);
|
||||
} else {
|
||||
delete opt_copy;
|
||||
} else {
|
||||
delete opt_copy;
|
||||
}
|
||||
}
|
||||
} else if (*opt_new != *opt_old) {
|
||||
//BBS: add plate_index logic for wipe_tower_x/wipe_tower_y
|
||||
@@ -1157,6 +1271,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
// BBS
|
||||
int used_filaments = this->extruders(true).size();
|
||||
|
||||
// 此时 m_objects 和 m_config 是稳定的,可以安全地计算映射
|
||||
// 这确保了 print_config_diffs 中的参数继承机制能正常工作
|
||||
this->initialize_filament_extruder_map();
|
||||
|
||||
//new_full_config.normalize_fdm(used_filaments);
|
||||
new_full_config.normalize_fdm_1();
|
||||
t_config_option_keys changed_keys = new_full_config.normalize_fdm_2(objects().size(), used_filaments);
|
||||
@@ -1194,13 +1312,36 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
// Find modified keys of the various configs. Resolve overrides extruder retract values by filament profiles.
|
||||
DynamicPrintConfig filament_overrides;
|
||||
//BBS: add plate index
|
||||
// SM Orca: Pass filament_extruder_map to apply physical extruder mapping
|
||||
t_config_option_keys print_diff = print_config_diffs(m_config, new_full_config, filament_overrides, this->m_plate_index, m_filament_extruder_map);
|
||||
t_config_option_keys full_config_diff = full_print_config_diffs(m_full_print_config, new_full_config, this->m_plate_index);
|
||||
// Collect changes to object and region configs.
|
||||
t_config_option_keys object_diff = m_default_object_config.diff(new_full_config);
|
||||
t_config_option_keys region_diff = m_default_region_config.diff(new_full_config);
|
||||
|
||||
//
|
||||
// 问题根源:
|
||||
// 1. 回抽参数(如retraction_length)既存在于打印机配置,也可能被耗材覆盖
|
||||
// 2. 当耗材-挤出机映射激活时(m_filament_extruder_map不为空),
|
||||
// filament_overrides中的回抽值会覆盖用户对打印机配置的直接修改
|
||||
//
|
||||
// 修复策略:
|
||||
// - 当存在耗材-挤出机映射时(说明已加载项目),移除filament_overrides中的所有回抽参数
|
||||
// - 这样用户的打印机配置修改就不会被耗材覆盖值覆盖
|
||||
// - 保留filament_overrides中其他参数的功能不受影响
|
||||
//
|
||||
// 注意:此修复确保用户对打印机挤出机回抽参数的直接编辑拥有最高优先级
|
||||
const std::vector<std::string> &extruder_retract_keys = print_config_def.extruder_retract_keys();
|
||||
bool has_mapping = !m_filament_extruder_map.empty();
|
||||
if (has_mapping) {
|
||||
// 当有映射时,移除所有回抽参数的耗材覆盖,让打印机配置生效
|
||||
for (const std::string &key : extruder_retract_keys) {
|
||||
if (filament_overrides.erase(key)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Print::apply - Clearing filament override for '" << key
|
||||
<< "' to allow printer config to take effect (filament-extruder mapping active)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do not use the ApplyStatus as we will use the max function when updating apply_status.
|
||||
unsigned int apply_status = APPLY_STATUS_UNCHANGED;
|
||||
auto update_apply_status = [&apply_status](bool invalidated)
|
||||
@@ -1614,6 +1755,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
m_full_print_config = std::move(new_full_config);
|
||||
}
|
||||
|
||||
// 在对象同步后,m_objects 可能已经被重建,需要重新计算映射以反映最新状态
|
||||
// 这确保了后续使用映射表时(如 export_gcode)能获得正确的映射关系
|
||||
this->initialize_filament_extruder_map();
|
||||
|
||||
// All regions now have distinct settings.
|
||||
// Check whether applying the new region config defaults we would get different regions,
|
||||
// update regions or create regions from scratch.
|
||||
|
||||
@@ -136,12 +136,12 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
|
||||
}
|
||||
case coPercents:{
|
||||
ConfigOptionPercents* vec_new = new ConfigOptionPercents{ boost::any_cast<double>(value) };
|
||||
config.option<ConfigOptionPercents>(opt_key)->set_at(vec_new, opt_index, opt_index);
|
||||
config.option<ConfigOptionPercents>(opt_key)->set_at(vec_new, opt_index, 0); // SM Orca: Fix - use src_idx=0 for single-element vectors
|
||||
break;
|
||||
}
|
||||
case coFloats:{
|
||||
ConfigOptionFloats* vec_new = new ConfigOptionFloats{ boost::any_cast<double>(value) };
|
||||
config.option<ConfigOptionFloats>(opt_key)->set_at(vec_new, opt_index, opt_index);
|
||||
config.option<ConfigOptionFloats>(opt_key)->set_at(vec_new, opt_index, 0); // SM Orca: Fix - use src_idx=0 for single-element vectors
|
||||
break;
|
||||
}
|
||||
case coString:
|
||||
|
||||
@@ -645,6 +645,10 @@ void ConfigOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const b
|
||||
const std::string &opt_key = itOption.first;
|
||||
int opt_index = itOption.second;
|
||||
|
||||
// SM Orca: Debug logging - track parameter changes from UI
|
||||
BOOST_LOG_TRIVIAL(error) << "ConfigOptionsGroup::on_change_OG: opt_id=" << opt_id
|
||||
<< ", opt_key=" << opt_key << ", opt_index=" << opt_index;
|
||||
|
||||
this->change_opt_value(opt_key, value, opt_index == -1 ? 0 : opt_index);
|
||||
}
|
||||
|
||||
@@ -1227,18 +1231,12 @@ void ExtruderOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const
|
||||
|
||||
auto itOption = it->second;
|
||||
const std::string& opt_key = itOption.first;
|
||||
int opt_index = itOption.second;
|
||||
|
||||
auto opt = m_config->option(opt_key);
|
||||
const ConfigOptionVectorBase* opt_vec = dynamic_cast<const ConfigOptionVectorBase*>(opt);
|
||||
if (opt_vec != nullptr) {
|
||||
for (int opt_index = 0; opt_index < opt_vec->size(); opt_index++) {
|
||||
this->change_opt_value(opt_key, value, opt_index);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int opt_index = itOption.second;
|
||||
this->change_opt_value(opt_key, value, opt_index == -1 ? 0 : opt_index);
|
||||
}
|
||||
// SM Orca: FIX - Only modify the specific extruder's value, not all extruders
|
||||
// The original code iterated through all indices and set them to the same value,
|
||||
// which caused all extruders to have identical values when editing one extruder
|
||||
this->change_opt_value(opt_key, value, opt_index == -1 ? 0 : opt_index);
|
||||
}
|
||||
|
||||
OptionsGroup::on_change_OG(opt_id, value);
|
||||
|
||||
+40
-4
@@ -3286,7 +3286,24 @@ void TabFilament::add_filament_overrides_page()
|
||||
else {
|
||||
const std::string printer_opt_key = opt_key.substr(strlen("filament_"));
|
||||
const auto printer_config = m_preset_bundle->printers.get_edited_preset().config;
|
||||
const boost::any printer_config_value = optgroup_sh->get_config_value(printer_config, printer_opt_key, opt_index);
|
||||
// SM Orca: Map filament slot to physical extruder index for inheritance
|
||||
auto& filament_extruder_map = wxGetApp().app_config->get_filament_extruder_map_ref();
|
||||
// SM Orca: First calculate num_extruders to use modulo for default mapping
|
||||
const ConfigOptionFloats* nozzle_diameter = printer_config.option<ConfigOptionFloats>("nozzle_diameter");
|
||||
int num_extruders = nozzle_diameter ? (int)nozzle_diameter->values.size() : 1;
|
||||
// SM Orca: Use modulo arithmetic for default mapping when no explicit mapping exists
|
||||
int physical_extruder_idx = opt_index % num_extruders; // default: filament N maps to extruder N % num_extruders
|
||||
auto map_it = filament_extruder_map.find(opt_index);
|
||||
if (map_it != filament_extruder_map.end()) {
|
||||
physical_extruder_idx = map_it->second;
|
||||
}
|
||||
// SM Orca: Bounds check to prevent crash from misconfigured map
|
||||
if (physical_extruder_idx < 0 || physical_extruder_idx >= num_extruders) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Invalid physical_extruder_idx " << physical_extruder_idx
|
||||
<< " for filament slot " << opt_index << ", using default";
|
||||
physical_extruder_idx = std::clamp(physical_extruder_idx, 0, num_extruders - 1);
|
||||
}
|
||||
const boost::any printer_config_value = optgroup_sh->get_config_value(printer_config, printer_opt_key, physical_extruder_idx);
|
||||
field->update_na_value(printer_config_value);
|
||||
field->set_na_value();
|
||||
}
|
||||
@@ -3301,7 +3318,7 @@ void TabFilament::add_filament_overrides_page()
|
||||
optgroup->append_line(line);
|
||||
};
|
||||
|
||||
const int extruder_idx = 0; // #ys_FIXME
|
||||
const int extruder_idx = (m_presets_choice && m_presets_choice->get_filament_idx() >= 0) ? m_presets_choice->get_filament_idx() : 0; // SM Orca: Get actual filament slot index
|
||||
|
||||
for (const std::string opt_key : { "filament_retraction_length",
|
||||
"filament_z_hop",
|
||||
@@ -3367,7 +3384,7 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print
|
||||
// "filament_seam_gap"
|
||||
};
|
||||
|
||||
const int extruder_idx = 0; // #ys_FIXME
|
||||
const int extruder_idx = (m_presets_choice && m_presets_choice->get_filament_idx() >= 0) ? m_presets_choice->get_filament_idx() : 0; // SM Orca: Get actual filament slot index
|
||||
|
||||
const bool have_retract_length = m_config->option("filament_retraction_length")->is_nil() ||
|
||||
m_config->opt_float("filament_retraction_length", extruder_idx) > 0;
|
||||
@@ -3399,7 +3416,26 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print
|
||||
} else {
|
||||
if (!is_checked) {
|
||||
const std::string printer_opt_key = opt_key.substr(strlen("filament_"));
|
||||
boost::any printer_config_value = optgroup->get_config_value(*printers_config, printer_opt_key, extruder_idx);
|
||||
// SM Orca: Map filament slot to physical extruder index for inheritance
|
||||
auto& filament_extruder_map = wxGetApp().app_config->get_filament_extruder_map_ref();
|
||||
// SM Orca: Determine extruder count first for proper modulo calculation
|
||||
const ConfigOptionFloats* nozzle_diameter = printers_config->option<ConfigOptionFloats>("nozzle_diameter");
|
||||
int num_extruders = nozzle_diameter ? (int)nozzle_diameter->values.size() : 1;
|
||||
int physical_extruder_idx = extruder_idx; // default: filament N uses extruder N
|
||||
auto map_it = filament_extruder_map.find(extruder_idx);
|
||||
if (map_it != filament_extruder_map.end()) {
|
||||
physical_extruder_idx = map_it->second;
|
||||
} else {
|
||||
// SM Orca: Use modulo arithmetic when map entry doesn't exist
|
||||
physical_extruder_idx = extruder_idx % num_extruders;
|
||||
}
|
||||
// SM Orca: Bounds check to prevent crash from misconfigured map
|
||||
if (physical_extruder_idx < 0 || physical_extruder_idx >= num_extruders) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Invalid physical_extruder_idx " << physical_extruder_idx
|
||||
<< " for filament slot " << extruder_idx << ", using default";
|
||||
physical_extruder_idx = std::clamp(physical_extruder_idx, 0, num_extruders - 1);
|
||||
}
|
||||
boost::any printer_config_value = optgroup->get_config_value(*printers_config, printer_opt_key, physical_extruder_idx);
|
||||
field->update_na_value(printer_config_value);
|
||||
field->set_value(printer_config_value, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user